#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