Всегда работа с CAN была простой, но что-то пошло не так (в устройстве на КДПВ)…
В последнее время мне часто удается использовать микроконтроллер STM32H750VB, и вот в одном устройстве понадобилось задействовать шину CAN, но первая же попытка, которую я предпринялпоказала всю мою самоуверенность дала странный результат. Ниже описана история
Итак, сначала о схемотехнике. На КДПВ зеленым обведен, понятно дело, сам виновник — микроконтроллер, тут ничего сложного с CAN нет — он подключен согласно
В качестве физического уровня применен MAX3051 (ну нравится он мне..), вот примерно так:
Ранее вместо STM32H750VB в такой же системе был STM32F107, но старичок не справился с задачами и было решено заменить его намодный и молодежный более современный.
Но вот незадача — у старого микроконтроллера был bxCAN, а в новом уже FDCAN. Хотя отличия и есть, но с точки зрения кода (да и работы — устойства-то на шине старые): замена — это очень просто. Для желающих можно сравнить:
В общем, косметические различия. И мне казалось, что и заработает все сразу и правильно.
Однако, сразу не заработало…
Контроллер CAN не мог выставить доминантный уровень и переходил в отказ состояние Bus-Off, также никаких данных с шины не принималось (притом, что другое устройство на шине стабильно посылало пакеты два раза в секунду).
Что ж, подумал я, пришла очередь отладки, и припаял проводки на линии 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 вообще, что можно отнести к плюсам. А к минусам… А к ним можно отнести потерянное время (контроллер удалось пристроить в другой проект) и понимание того, что современные контроллеры глючатсо страшной силой тоже по-современному (или это тоже плюс?).
В последнее время мне часто удается использовать микроконтроллер 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 вообще, что можно отнести к плюсам. А к минусам… А к ним можно отнести потерянное время (контроллер удалось пристроить в другой проект) и понимание того, что современные контроллеры глючат