В последнее время мне часто удается использовать микроконтроллер STM32H750VB, и вот в одном устройстве понадобилось задействовать шину CAN, но первая же попытка, которую я предпринял
Итак, сначала о схемотехнике. На КДПВ зеленым обведен, понятно дело, сам виновник — микроконтроллер, тут ничего сложного с CAN нет — он подключен согласно
В качестве физического уровня применен MAX3051 (ну нравится он мне..), вот примерно так:
Ранее вместо STM32H750VB в такой же системе был STM32F107, но старичок не справился с задачами и было решено заменить его на
Но вот незадача — у старого микроконтроллера был bxCAN, а в новом уже FDCAN. Хотя отличия и есть, но с точки зрения кода (да и работы — устойства-то на шине старые): замена — это очень просто. Для желающих можно сравнить:
Было | Стало |
---|---|
MX_CAN1_Init(); |
MX_FDCAN1_Init(); |
hcan1.Instance = CAN1; hcan1.Init.Prescaler = 4; hcan1.Init.Mode = CAN_MODE_NORMAL; hcan1.Init.SyncJumpWidth = CAN_SJW_4TQ; hcan1.Init.TimeSeg1 = CAN_BS1_15TQ; hcan1.Init.TimeSeg2 = CAN_BS2_2TQ; hcan1.Init.TimeTriggeredMode = DISABLE; hcan1.Init.AutoBusOff = ENABLE; hcan1.Init.AutoWakeUp = DISABLE; hcan1.Init.AutoRetransmission = DISABLE; hcan1.Init.ReceiveFifoLocked = DISABLE; hcan1.Init.TransmitFifoPriority = DISABLE; |
hfdcan1.Instance = FDCAN1; hfdcan1.Init.FrameFormat = FDCAN_FRAME_FD_NO_BRS; hfdcan1.Init.Mode = FDCAN_MODE_NORMAL; hfdcan1.Init.AutoRetransmission = ENABLE; hfdcan1.Init.TransmitPause = DISABLE; hfdcan1.Init.ProtocolException = ENABLE; hfdcan1.Init.NominalPrescaler = 1; hfdcan1.Init.NominalSyncJumpWidth = 3; hfdcan1.Init.NominalTimeSeg1 = 11; hfdcan1.Init.NominalTimeSeg2 = 4; hfdcan1.Init.DataPrescaler = 1; hfdcan1.Init.DataSyncJumpWidth = 3; hfdcan1.Init.DataTimeSeg1 = 11; hfdcan1.Init.DataTimeSeg2 = 4; hfdcan1.Init.MessageRAMOffset = 64; hfdcan1.Init.StdFiltersNbr = 0; hfdcan1.Init.ExtFiltersNbr = 0; hfdcan1.Init.RxFifo0ElmtsNbr = 4; hfdcan1.Init.RxFifo0ElmtSize = FDCAN_DATA_BYTES_8; hfdcan1.Init.RxFifo1ElmtsNbr = 4; hfdcan1.Init.RxFifo1ElmtSize = FDCAN_DATA_BYTES_8; hfdcan1.Init.RxBuffersNbr = 4; hfdcan1.Init.RxBufferSize = FDCAN_DATA_BYTES_8; hfdcan1.Init.TxEventsNbr = 4; |
if (HAL_CAN_Init(&hcan1) != HAL_OK) { |
if (HAL_FDCAN_Start(&hfdcan1) != HAL_OK) { |
В общем, косметические различия. И мне казалось, что и заработает все сразу и правильно.
Однако, сразу не заработало…
Контроллер CAN не мог выставить доминантный уровень и переходил в
Что ж, подумал я, пришла очередь отладки, и припаял проводки на линии CAN-RX и CAN-TX (собственно просмотр самой шины выглядел логично — устройство молчало, а подключенное другое устройство посылало пакеты
После этого вначале был включен режим FDCAN_MODE_BUS_MONITORING. И, о чудо, сразу увиделись пакеты от шины! (В этом режиме контроллер CAN только слушает данные, но ничего не передает). Так, замечательно…
Далее был включен режим FDCAN_MODE_EXTERNAL_LOOPBACK ( в этом режиме, наоборот, слушаем только себя, но зато все передаем в шину). И на линиях CAN_RX и CAN_TX появились все пакеты данных — как отправляемые самим устройством, так и принимаемые с шины, вот на
рисунке ниже (серым данные TX от микроконтроллера, оранжевым данные линии RX ) они видны как пики:
Итак, после этого эксперимента стало понятно, что схема работает верно, контроллер CAN в микропроцессоре может как принимать, так и передавать данные.
Однако при попытке одновременно как принимать, так и передавать данные все равно система становилась Bus-Off c ошибкой в регистре контроля ошибок (FDCAN protocol status register (FDCAN_PSR)) LEC[2:0] = 5 — а это означает из даташита Bit0Error: During the transmission of a message (or acknowledge bit, or active error
flag, or overload flag), the device wanted to send a dominant level (data or identifier bit
logical value 0), but the monitored bus value was recessive…
После двух дней мучений (понятно, в чем ошибка, но не понятно, как исправить) и вдумчивого исследования даташита, errata и кучи стороннего кода и мануалов пришло
Что же, подумал я, может дело в технике, и… заменил сам микроконтроллер (на другой из той же партии). И… оно заработало! Ну то есть вот вообще без
Краткие итоги
Видимо, попался такой вот хитробракованный экземпляр. Но зато удалось сильно глубже вникнуть в работу FDCAN вообще, что можно отнести к плюсам. А к минусам… А к ним можно отнести потерянное время (контроллер удалось пристроить в другой проект) и понимание того, что современные контроллеры глючат
nixtonixto
Тайминги где-то не соблюдены, и вот одному контроллеру десятка нс не хватило. В абсолютном большинстве случаев, когда программист говорит «бракованный контроллер», после изучения с ним рефмануала, брак уходит. Н750 ещё сырой проц, но если у него есть косяк в кристалле, то он будет для всей ревизии. Вы заменили на контроллер той же самой ревизии?
drWhy
А разве МК не подвержены частичному браку, как процессоры, у которых просто отключают блоки, не прошедшие тестирования?
nixtonixto
Такие контроллеры переводятся производителем в младшие версии, типа ф103 в ф102, у которого якобы нет ЮСБ, но в котором он работает, или ф103С8 с якобы 64 кБ флеши, у которого доступно 128 кБ… Но такого, чтобы какой-то заявленный модуль работал некорректно и в еррате об этом не было сказано, не было ни разу. А мы их ставим тысячами штук, правда преимущественно ф0 и ф1 семейства с флешью до 512к.