STM32F405 bxCAN не выходит из режима инициализации

#c #arm #embedded #stm32 #can-bus

#c #arm #встроенный #stm32 #can-шина

Вопрос:

Когда я пытаюсь инициализировать bxCAN на микроконтроллере STM32F405, он не устанавливается CAN_MSR_INAK после оставления запроса.

Вот мой код:

 rcc_peripheral_enable_clock(amp;RCC_APB1ENR, RCC_APB1ENR_CAN2EN);
nvic_enable_irq(NVIC_CAN2_RX0_IRQ);
can_reset(CAN2);
if (can_init(CAN2,          // Can
        false,              // Time triggered communication mode
        true,               // Automatic bus-off management
        true,               // Automatic wakeup mode
        false,              // No automatic retransmission
        false,              // Receive FIFO locked mode
        true,               // Transmit FIFO priority
        CAN_BTR_SJW_1TQ,    // Resynchronization time quanta jump width
        CAN_BTR_TS1_11TQ,   // Time segment 1 time quanta width
        CAN_BTR_TS2_2TQ,    // Time segment 2 time quanta width
        3,                  // Baud rate prescaler (1 mbps)
        false,              // Loopback
        false) != 0)        // Silent mode
    _exit(0);
  

И вот can_init функция:

 int can_init(uint32_t canport, bool ttcm, bool abom, bool awum, bool nart,
         bool rflm, bool txfp, uint32_t sjw, uint32_t ts1, uint32_t ts2,
         uint32_t brp, bool loopback, bool silent)
{
    volatile uint32_t wait_ack;
    int ret = 0;

    /* Exit from sleep mode. */
    CAN_MCR(canport) amp;= ~CAN_MCR_SLEEP;

    /* Request initialization "enter". */
    CAN_MCR(canport) |= CAN_MCR_INRQ;

    /* Wait for acknowledge. */
    wait_ack = CAN_MSR_INAK_TIMEOUT;
    while ((--wait_ack) amp;amp;
        ((CAN_MSR(canport) amp; CAN_MSR_INAK) != CAN_MSR_INAK));

    /* Check the acknowledge. */
    if ((CAN_MSR(canport) amp; CAN_MSR_INAK) != CAN_MSR_INAK) {
        return 1;
    }

    /* clear can timing bits */
    CAN_BTR(canport) = 0;

    /* Set the automatic bus-off management. */
    if (ttcm) {
        CAN_MCR(canport) |= CAN_MCR_TTCM;
    } else {
        CAN_MCR(canport) amp;= ~CAN_MCR_TTCM;
    }

    if (abom) {
        CAN_MCR(canport) |= CAN_MCR_ABOM;
    } else {
        CAN_MCR(canport) amp;= ~CAN_MCR_ABOM;
    }

    if (awum) {
        CAN_MCR(canport) |= CAN_MCR_AWUM;
    } else {
        CAN_MCR(canport) amp;= ~CAN_MCR_AWUM;
    }

    if (nart) {
        CAN_MCR(canport) |= CAN_MCR_NART;
    } else {
        CAN_MCR(canport) amp;= ~CAN_MCR_NART;
    }

    if (rflm) {
        CAN_MCR(canport) |= CAN_MCR_RFLM;
    } else {
        CAN_MCR(canport) amp;= ~CAN_MCR_RFLM;
    }

    if (txfp) {
        CAN_MCR(canport) |= CAN_MCR_TXFP;
    } else {
        CAN_MCR(canport) amp;= ~CAN_MCR_TXFP;
    }

    if (silent) {
        CAN_BTR(canport) |= CAN_BTR_SILM;
    } else {
        CAN_BTR(canport) amp;= ~CAN_BTR_SILM;
    }

    if (loopback) {
        CAN_BTR(canport) |= CAN_BTR_LBKM;
    } else {
        CAN_BTR(canport) amp;= ~CAN_BTR_LBKM;
    }

    /* Set bit timings. */
    CAN_BTR(canport) |= sjw | ts2 | ts1 |
        ((brp - 1ul) amp; CAN_BTR_BRP_MASK);

    /* Request initialization "leave". */
    CAN_MCR(canport) amp;= ~CAN_MCR_INRQ;

    /* Wait for acknowledge. */
    wait_ack = CAN_MSR_INAK_TIMEOUT;
    while ((--wait_ack) amp;amp;
           ((CAN_MSR(canport) amp; CAN_MSR_INAK) == CAN_MSR_INAK));

    if ((CAN_MSR(canport) amp; CAN_MSR_INAK) == CAN_MSR_INAK) {
        ret = 1;
    }

    return ret;
}
  

Таким образом, эта функция успешно переходит в режим инициализации, но не может выйти из него.

Я пытался сделать следующие вещи:

  • Инициализация CAN1 вместо CAN2
  • Настройте разные тактовые частоты
  • Настройте различные настройки can
  • Делать и не настраивать контакты can

и ничего не имело никакого эффекта. Он всегда завершается с ошибкой в одной и той же точке.

Кроме того (на всякий случай), я попытался отключить синхронизацию bxCAN, а затем даже не могу войти в режим инициализации (как и ожидалось).

Тот же код отлично работает для STM32F103, поэтому я не знаю, что может быть не так.

Комментарии:

1. Что должен делать «wait_ack»? Как вы можете знать, что цикл не завершится до того, как аппаратное обеспечение получит возможность установить флаг? Если вам нужен тайм-аут, вам следует использовать профессиональное решение с аппаратным таймером. Во время отладки вы, вероятно, захотите ждать «вечно».

2. Я заглянул в руководство: «Программное обеспечение очищает этот бит, чтобы переключить оборудование в обычный режим. После отслеживания 11 последовательных рецессивных битов в сигнале Rx аппаратное обеспечение CAN синхронизируется и готово к передаче и приему.». Так что, в зависимости от вашей скорости передачи данных, это может занять некоторое время. Если ваш процессор работает с высокой тактовой частотой, возможно, он завершил цикл обратного отсчета задолго до этих 11 бит. Что произойдет, если вы просто будете вечно ждать, пока будет установлен флаг?

3. can_init является частью библиотеки libopencm3, поэтому эту функцию я не писал. Обычно он должен завершаться за пару тактов, а не за 65535 (CAN_MSR_INAK_TIMEOUT). Во всяком случае, вместо _exit(0); того, чтобы я пытался поставить while ((CAN_MSR(CAN2) amp; CAN_MSR_INAK) == CAN_MSR_INAK); , и это тоже не имеет никакого эффекта — он просто зацикливается навсегда.

4. Не имеет значения, кто это написал, это неаккуратно написанный, сомнительный код, который не прошел бы ни одного приличного обзора кода. Но тогда, конечно, большинство «open-blabla-download-from-github» — дерьмо. Предположим, вы установили скорость передачи данных на 10 Кбит / с, что является стандартной скоростью передачи данных CAN. 11 * 1/10 Кбит / с = 1,1 мс. Учитывая столько времени, ваш процессор, вероятно, может уменьшить количество с 65535 до 0 тысячу раз.

5. Я согласен, что качество этого кода вызывает сомнения, но дело в том, что это не источник моей проблемы.

Ответ №1:

Проверьте эти параметры: (i) Проверьте, включена ли синхронизация CAN (поскольку вы входите в режим инициализации, это кажется нормальным.) (ii) Проверьте, включена ли синхронизация порта CAN GPIO (перед входом в режим инициализации вы должны включить это) (iii) Проверьте, настроены ли контакты Can GPIO (переддля входа в режим инициализации can необходимо настроить это)

Комментарии:

1. Что ж, спасибо за ваш ответ (хотя проблема уже решена). Оказалось, что проблема была в оборудовании.

Ответ №2:

У меня была такая же проблема при использовании режима беззвучного обратного цикла. Решение состояло в том, чтобы подтянуть вывод RX, чтобы он мог получать 11 рецессивных битов при смене режима с «Режима инициализации» на «Обычный режим».

Ответ №3:

Вы правильно настроили контакты? Я думаю, что F405 нуждается в альтернативном отображении в конфигурации GPIO