Релюшки на CAN-шине
Jul. 24th, 2021 05:18 pm![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)

Закончил с прошивкой для новой железяки.
Как "наследница" USB-CAN переходника, она умеет все то же самое + несколько специфичных вещей (опрос четырех кнопок, измерение двух внешних каналов АЦП с напряжениями до 5В и до 12В, оперирование четырьмя внешними светодиодами, управление тремя ШИМ-каналами с заполнением 0..255, управление двумя релюшками). Вот меню доступа по USB:
'0' - turn relay0 on(1) or off(0) '1' - turn relay1 on(1) or off(0) 'a' - add ID to ignore list (max 10 IDs) 'A' - get ADC values @ all 4 channels 'b' - get buttons' state 'C' - reinit CAN with given baudrate 'd' - delete ignore list 'f' - add/delete filter, format: bank# FIFO# mode(M/I) num0 [num1 [num2 [num3]]] 'F' - send/clear flood message: F ID byte0 ... byteN 'I' - read CAN ID 'l' - list all active filters 'm' - get MCU temp & Vdd 'o' - turn nth LED OFF 'O' - turn nth LED ON 'p' - print ignore buffer 'P' - pause/resume in packets displaying 'R' - software reset 's/S' - send data over CAN: s ID byte0 .. byteN 'T' - get time from start (ms) 'w' - get PWM settings 'W' - set PWM @nth channel (ch: 0..2, PWM: 0..255)
К сожалению, оказалось, что STM32F042 не умеет программный переход в режим DFU: там есть защита, не позволяющая запустить бутлоадер, если в первых 4 байтах флеш-памяти не пусто! А если стереть эту первую страницу, то и МК подыхает... В общем, для прошивки я оставил лишь в режиме DEBUG возможность стереть первую страницу флеш-памяти, чтобы потом, переподключив питание, запустить МК в режиме DFU. Очень уж не хотелось подпаивать временные проводочки для подключения st-link.
При работе с CAN входящий протокол достаточно простой: железяка реагирует на идентификатор, выставленный перемычками на плате. При запуске этот адрес считывается, и нулевой фильтр (пользователю не позволяется его менять или удалять) принимает сообщения с заданным ID. Если получено пустое сообщение, то оно "отпинговывается" обратно, нет — анализируется байт 0 пришедших данных (это — команда). Команда может быть одна из:
typedef enum{ CAN_CMD_PING, // ping (without setter) CAN_CMD_RELAY, // relay get/set CAN_CMD_PWM, // PWM get/set CAN_CMD_ADC, // get ADC (without setter) CAN_CMD_MCU, // MCU T and Vdd CAN_CMD_LED, // LEDs get/set CAN_CMD_BTNS, // get Buttons state (without setter) CAN_CMD_TMS, // get time from start (in ms) CAN_CMD_ERRCMD, // wrong command CAN_CMD_SETFLAG = 0x80 // command is setter } CAN_commands;
Начиная с кода 8 (CAN_CMD_ERRCMD) команда считается ошибочной (обратно отправляется пакет с одним байтом, где кодом команды является этот самый errcmd). Если в команде установлен старший бит (CAN_CMD_SETFLAG), и она имеет не только геттер, но и сеттер, анализируются следующие байты данных и выполняется соответствующий сеттер (а после все равно вызывается геттер).
Обратный пакет имеет идентификатор, равный 0x100 + CANID, поэтому при совместной работе с CANopen устройствами нужно аккуратно выбирать идентификатор железяки, чтобы случайно что-нибудь не поломать. Если ответом является "pong", то посылается пустой блок данных. Если нет, байт 0 содержит полученную команду (с уже очищенным флагом-сеттером).
Большинство команд передает данные в формате little endian, кроме состояния АЦП (там bigendian-подобное смешанное черт знает что).
- CAN_CMD_ADC имеет только геттер, поле данных в байтах 1..6 содержит смешанные по 12бит показания АЦП (каналы 5В, 12В и внутренние - температура МК и Vdd).
- CAN_CMD_BTNS тоже без сеттера, здесь data[1] - номер кнопки, data[2] - ее состояние (значение enum keyevent), data[4..7] (для выравнивания) - время наступления событий в условных мс от запуска МК или переполнения счетчика времени (uint32_t, little endian).
- CAN_CMD_LED имеет сеттер, в этом случае data[1] входящего потока задает состояние соответствующего светодиода (если бит N установлен, светодиод включается, нет - гаснет), в ответе data[1] указывает на текущее состояние светодиодов (аналогично сеттеру).
- CAN_CMD_MCU без геттера, в data[2,3] содержится температура МК (T*10℃, little endian int16_t), в полях data[4,5] - значение Vdd (V*100, little endian uint16_t).
- CAN_CMD_PWM позволяет задавать и читать заполнение соответствующих ШИМ каналов, поля у сеттера и геттера аналогичны: data[1..3] - соответствующее значение заполнения (0..255) ШИМ для каналов 0..2.
- CAN_CMD_RELAY управляет релюшкой, поля сеттеров и геттеров тоже аналогичны: биты 0 и 1 в data[1] отражают состояние соответствующей релюхи (1 - включено, 0 - выключено).
- CAN_CMD_TMS содержит в полях data[4..7] время Tms (little endian uint32_t).
Проверил работу, передавая данные с моего CAN-USB.
Себестоимость изделия получилась недорогой, т.к. использован МК из партии, закупленной около трех лет назад — до выдуманного "крЫзиса". Сейчас же если и удастся урвать STM32F042C6T6 рублей за 600, то стоимость всего остального будет меньше.