From 3b46db4ca2e892b31b1e4ae567e38254e403f1a3 Mon Sep 17 00:00:00 2001 From: Pasi Kemppainen <48950874+pazi88@users.noreply.github.com> Date: Fri, 22 Jan 2021 23:40:39 +0200 Subject: [PATCH] STM32 CAN library improvement: addition of TX mailboxes (#508) * CAN-bus library for STM32 This adds CAN-bus library for STM32. Mainly for STM32F4, but others can be added later. * CAN2 and F446 support added for STM32 CAN library Adds support for second can interface and F446 bit timings. * Fix STM32 CAN pin selection and STM32F1 support The previous way to select CAN pins wasn't actually working, so this fixes that problem and also the F1 support too. * Fix building for Mega/Teensy * Update cancomms.ino * Update speeduino.ino * STM32 CAN library fixes * TX mailbox addition Co-authored-by: Pasi Kemppainen Co-authored-by: Josh Stewart --- speeduino/src/STM32_CAN/STM32_CAN.cpp | 123 ++++++++++++++++++-------- speeduino/src/STM32_CAN/STM32_CAN.h | 11 ++- 2 files changed, 95 insertions(+), 39 deletions(-) diff --git a/speeduino/src/STM32_CAN/STM32_CAN.cpp b/speeduino/src/STM32_CAN/STM32_CAN.cpp index b2093998..36c64633 100644 --- a/speeduino/src/STM32_CAN/STM32_CAN.cpp +++ b/speeduino/src/STM32_CAN/STM32_CAN.cpp @@ -124,7 +124,7 @@ void STM32_CAN::begin() #endif } -int STM32_CAN::write(CAN_message_t &CAN_tx_msg) +void STM32_CAN::writeTxMailbox(uint8_t mb_num, CAN_message_t &CAN_tx_msg) { uint32_t out = 0; if (CAN_tx_msg.flags.extended == true) { // Extended frame format @@ -140,50 +140,97 @@ int STM32_CAN::write(CAN_message_t &CAN_tx_msg) if (_channel == _CAN1) { - // Check if the mailbox is empty - if (CAN1->sTxMailBox[0].TIR & 0x1UL) { - //Serial.println("transmit Fail"); - return -1; // transmit of the previous message has failed - } - else { // mailbox is empty, so it's ok to send new message - CAN1->sTxMailBox[0].TDTR &= ~(0xF); - CAN1->sTxMailBox[0].TDTR |= CAN_tx_msg.len & 0xFUL; - CAN1->sTxMailBox[0].TDLR = (((uint32_t) CAN_tx_msg.buf[3] << 24) | - ((uint32_t) CAN_tx_msg.buf[2] << 16) | - ((uint32_t) CAN_tx_msg.buf[1] << 8) | - ((uint32_t) CAN_tx_msg.buf[0] )); - CAN1->sTxMailBox[0].TDHR = (((uint32_t) CAN_tx_msg.buf[7] << 24) | - ((uint32_t) CAN_tx_msg.buf[6] << 16) | - ((uint32_t) CAN_tx_msg.buf[5] << 8) | - ((uint32_t) CAN_tx_msg.buf[4] )); + CAN1->sTxMailBox[mb_num].TDTR &= ~(0xF); + CAN1->sTxMailBox[mb_num].TDTR |= CAN_tx_msg.len & 0xFUL; + CAN1->sTxMailBox[mb_num].TDLR = (((uint32_t) CAN_tx_msg.buf[3] << 24) | + ((uint32_t) CAN_tx_msg.buf[2] << 16) | + ((uint32_t) CAN_tx_msg.buf[1] << 8) | + ((uint32_t) CAN_tx_msg.buf[0] )); + CAN1->sTxMailBox[mb_num].TDHR = (((uint32_t) CAN_tx_msg.buf[7] << 24) | + ((uint32_t) CAN_tx_msg.buf[6] << 16) | + ((uint32_t) CAN_tx_msg.buf[5] << 8) | + ((uint32_t) CAN_tx_msg.buf[4] )); - // Send Go - CAN1->sTxMailBox[0].TIR = out | STM32_CAN_TIR_TXRQ; - return 1; // transmit done + // Send Go + CAN1->sTxMailBox[mb_num].TIR = out | STM32_CAN_TIR_TXRQ; + } + #if defined(CAN2) + if (_channel == _CAN2) + { + CAN2->sTxMailBox[mb_num].TDTR &= ~(0xF); + CAN2->sTxMailBox[mb_num].TDTR |= CAN_tx_msg.len & 0xFUL; + CAN2->sTxMailBox[mb_num].TDLR = (((uint32_t) CAN_tx_msg.buf[3] << 24) | + ((uint32_t) CAN_tx_msg.buf[2] << 16) | + ((uint32_t) CAN_tx_msg.buf[1] << 8) | + ((uint32_t) CAN_tx_msg.buf[0] )); + CAN2->sTxMailBox[mb_num].TDHR = (((uint32_t) CAN_tx_msg.buf[7] << 24) | + ((uint32_t) CAN_tx_msg.buf[6] << 16) | + ((uint32_t) CAN_tx_msg.buf[5] << 8) | + ((uint32_t) CAN_tx_msg.buf[4] )); + // Send Go + CAN2->sTxMailBox[mb_num].TIR = out | STM32_CAN_TIR_TXRQ; + } + #endif +} + +int STM32_CAN::write(CAN_message_t &CAN_tx_msg) +{ + volatile int mailbox = 0; + + if (_channel == _CAN1) + { + // Check if one of the three mailboxes is empty + while(CAN1->sTxMailBox[mailbox].TIR & 0x1UL && mailbox++ < 3); + + if (mailbox >= 3) { + //Serial.println("transmit Fail"); + return -1; // transmit failed, no mailboxes available + } + else { // empty mailbox found, so it's ok to send new message + writeTxMailbox(mailbox, CAN_tx_msg); + return 1; // transmit done } } #if defined(CAN2) if (_channel == _CAN2) { - // Check if the mailbox is empty - if (CAN2->sTxMailBox[0].TIR & 0x1UL) { - //Serial.println("transmit Fail"); - return -1; // transmit of the previous message has failed - } - else { // mailbox is empty, so it's ok to send new message - CAN2->sTxMailBox[0].TDTR &= ~(0xF); - CAN2->sTxMailBox[0].TDTR |= CAN_tx_msg.len & 0xFUL; - CAN2->sTxMailBox[0].TDLR = (((uint32_t) CAN_tx_msg.buf[3] << 24) | - ((uint32_t) CAN_tx_msg.buf[2] << 16) | - ((uint32_t) CAN_tx_msg.buf[1] << 8) | - ((uint32_t) CAN_tx_msg.buf[0] )); - CAN2->sTxMailBox[0].TDHR = (((uint32_t) CAN_tx_msg.buf[7] << 24) | - ((uint32_t) CAN_tx_msg.buf[6] << 16) | - ((uint32_t) CAN_tx_msg.buf[5] << 8) | - ((uint32_t) CAN_tx_msg.buf[4] )); + // Check if one of the three mailboxes is empty + while(CAN2->sTxMailBox[mailbox].TIR & 0x1UL && mailbox++ < 3); - // Send Go - CAN2->sTxMailBox[0].TIR = out | STM32_CAN_TIR_TXRQ; + if (mailbox >= 3) { + //Serial.println("transmit Fail"); + return -1; // transmit failed, no mailboxes available + } + else { // empty mailbox found, so it's ok to send new message + writeTxMailbox(mailbox, CAN_tx_msg); + return 1; // transmit done + } + } + #endif +} + +int STM32_CAN::write(CAN_MAILBOX mb_num, CAN_message_t &CAN_tx_msg) +{ + if (_channel == _CAN1) + { + if (CAN1->sTxMailBox[mb_num].TIR & 0x1UL) { + //Serial.println("transmit Fail"); + return -1; // transmit failed, mailbox was not empty + } + else { // mailbox was empty, so it's ok to send new message + writeTxMailbox(mb_num, CAN_tx_msg); + return 1; // transmit done + } + } + #if defined(CAN2) + if (_channel == _CAN2) + { + if (CAN2->sTxMailBox[mb_num].TIR & 0x1UL) { + //Serial.println("transmit Fail"); + return -1; // transmit failed, mailbox was not empty + } + else { // mailbox was empty, so it's ok to send new message + writeTxMailbox(mb_num, CAN_tx_msg); return 1; // transmit done } } diff --git a/speeduino/src/STM32_CAN/STM32_CAN.h b/speeduino/src/STM32_CAN/STM32_CAN.h index 25dfa224..f79dfc60 100644 --- a/speeduino/src/STM32_CAN/STM32_CAN.h +++ b/speeduino/src/STM32_CAN/STM32_CAN.h @@ -50,6 +50,13 @@ typedef const struct typedef enum CAN_PINS {DEF, ALT, ALT2,} CAN_PINS; +//STM32 has only 3 TX mailboxes +typedef enum CAN_MAILBOX { + MB0 = 0, + MB1 = 1, + MB2 = 2 +} CAN_MAILBOX; + #ifndef CAN2 typedef enum CAN_CHANNEL {_CAN1,} CAN_CHANNEL; #elif defined CAN2 @@ -76,6 +83,7 @@ class STM32_CAN { private: void CANSetGpio(GPIO_TypeDef * addr, uint8_t index, uint8_t speed = 3); void CANSetFilter(uint8_t index, uint8_t scale, uint8_t mode, uint8_t fifo, uint32_t bank1, uint32_t bank2); + void writeTxMailbox(uint8_t mb_num, CAN_message_t &CAN_tx_msg); uint8_t CANMsgAvail(); void SetTXRX(); @@ -83,7 +91,8 @@ class STM32_CAN { STM32_CAN(const CAN_CHANNEL channel, CAN_PINS pins) : _channel (channel), _pins (pins) { }; void begin(); void setBaudRate(uint32_t baud); - int write(CAN_message_t &CAN_tx_msg); + int write(CAN_message_t &CAN_tx_msg); // use any available mailbox for transmitting + int write(CAN_MAILBOX mb_num, CAN_message_t &CAN_tx_msg); // use a single mailbox for transmitting int read(CAN_message_t &CAN_rx_msg); void enableFIFO(bool status = 1); };