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 <pazi88@users.noreply.github.com>
Co-authored-by: Josh Stewart <josh@noisymime.org>
This commit is contained in:
Pasi Kemppainen 2021-01-22 23:40:39 +02:00 committed by GitHub
parent 941da74154
commit 3b46db4ca2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 95 additions and 39 deletions

View File

@ -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
}
}

View File

@ -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);
};