stm32: Avoid read+write modify instructions in can.c

Prefer explicitly setting the hardware registers and avoid using C
read and modify instructions where possible.  This avoids race
conditions where an interrupt or hardware change could cause subtle
corruption of the register state.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2021-01-27 21:15:33 -05:00
parent c0371c94c8
commit 95eb00740b
1 changed files with 13 additions and 24 deletions

View File

@ -85,10 +85,6 @@
#error No known CAN device for configured MCU #error No known CAN device for configured MCU
#endif #endif
// TXFP makes packets posted to the TX mboxes transmit in chronologcal order
// ABOM makes the hardware automatically leave bus-off state
#define MCR_FLAGS (CAN_MCR_TXFP | CAN_MCR_ABOM)
static uint16_t MyCanId = 0; static uint16_t MyCanId = 0;
static int static int
@ -108,13 +104,9 @@ static void
can_transmit_mbox(uint32_t id, int mbox, uint32_t dlc, uint8_t *pkt) can_transmit_mbox(uint32_t id, int mbox, uint32_t dlc, uint8_t *pkt)
{ {
CAN_TxMailBox_TypeDef *mb = &SOC_CAN->sTxMailBox[mbox]; CAN_TxMailBox_TypeDef *mb = &SOC_CAN->sTxMailBox[mbox];
/* Set up the Id */
mb->TIR &= CAN_TI0R_TXRQ;
mb->TIR |= (id << CAN_TI0R_STID_Pos);
/* Set up the DLC */ /* Set up the DLC */
mb->TDTR &= 0xFFFFFFF0U; mb->TDTR = (mb->TDTR & 0xFFFFFFF0) | (dlc & 0x0F);
mb->TDTR |= (dlc & 0xFU);
/* Set up the data field */ /* Set up the data field */
if (pkt) { if (pkt) {
@ -129,8 +121,7 @@ can_transmit_mbox(uint32_t id, int mbox, uint32_t dlc, uint8_t *pkt)
} }
/* Request transmission */ /* Request transmission */
__sync_synchronize(); // disable write optimization mb->TIR = (id << CAN_TI0R_STID_Pos) | CAN_TI0R_TXRQ;
mb->TIR |= CAN_TI0R_TXRQ;
} }
// Blocking transmit function, it can race with the IRQ driven TX handler. // Blocking transmit function, it can race with the IRQ driven TX handler.
@ -290,32 +281,32 @@ CAN_IRQHandler(void)
// Mailbox 0 // Mailbox 0
while (SOC_CAN->RF0R & CAN_RF0R_FMP0) { while (SOC_CAN->RF0R & CAN_RF0R_FMP0) {
CAN_RxCpltCallback(0); CAN_RxCpltCallback(0);
SOC_CAN->RF0R |= CAN_RF0R_RFOM0; SOC_CAN->RF0R = CAN_RF0R_RFOM0;
} }
} }
if (SOC_CAN->RF1R & CAN_RF1R_FMP1) { if (SOC_CAN->RF1R & CAN_RF1R_FMP1) {
// Mailbox 1 // Mailbox 1
while (SOC_CAN->RF1R & CAN_RF1R_FMP1) { while (SOC_CAN->RF1R & CAN_RF1R_FMP1) {
CAN_RxCpltCallback(1); CAN_RxCpltCallback(1);
SOC_CAN->RF1R |= CAN_RF1R_RFOM1; SOC_CAN->RF1R = CAN_RF1R_RFOM1;
} }
} }
/* Check Overrun flag for FIFO0 */ /* Check Overrun flag for FIFO0 */
if (SOC_CAN->RF0R & CAN_RF0R_FOVR0) { if (SOC_CAN->RF0R & CAN_RF0R_FOVR0) {
/* Clear FIFO0 Overrun Flag */ /* Clear FIFO0 Overrun Flag */
SOC_CAN->RF0R |= CAN_RF0R_FOVR0; SOC_CAN->RF0R = CAN_RF0R_FOVR0;
} }
/* Check Overrun flag for FIFO1 */ /* Check Overrun flag for FIFO1 */
if (SOC_CAN->RF1R & CAN_RF1R_FOVR1) { if (SOC_CAN->RF1R & CAN_RF1R_FOVR1) {
/* Clear FIFO1 Overrun Flag */ /* Clear FIFO1 Overrun Flag */
SOC_CAN->RF1R |= CAN_RF1R_FOVR1; SOC_CAN->RF1R = CAN_RF1R_FOVR1;
} }
// TX // TX
if (SOC_CAN->IER & CAN_IER_TMEIE) { // TX IRQ enabled if (SOC_CAN->IER & CAN_IER_TMEIE) { // TX IRQ enabled
if (!CAN_TxIrq()) if (!CAN_TxIrq())
SOC_CAN->IER &= ~CAN_IER_TMEIE; // Disable TXIRQ SOC_CAN->IER = CAN_IER_FMPIE0 | CAN_IER_FMPIE1; // Disable TXIRQ
} }
} }
@ -381,19 +372,17 @@ can_init(void)
/*##-1- Configure the CAN #######################################*/ /*##-1- Configure the CAN #######################################*/
/* Exit from sleep mode */
SOC_CAN->MCR &= ~(CAN_MCR_SLEEP);
/* Request initialisation */ /* Request initialisation */
SOC_CAN->MCR |= CAN_MCR_INRQ; SOC_CAN->MCR = CAN_MCR_INRQ;
/* Wait the acknowledge */ /* Wait the acknowledge */
while (!(SOC_CAN->MSR & CAN_MSR_INAK)) while (!(SOC_CAN->MSR & CAN_MSR_INAK))
; ;
SOC_CAN->MCR |= MCR_FLAGS;
SOC_CAN->BTR = btr; SOC_CAN->BTR = btr;
/* Request leave initialisation */ // TXFP makes packets posted to the TX mboxes transmit in chronologcal order
SOC_CAN->MCR &= ~(CAN_MCR_INRQ); // ABOM makes the hardware automatically leave bus-off state
SOC_CAN->MCR = CAN_MCR_TXFP | CAN_MCR_ABOM;
/* Wait the acknowledge */ /* Wait the acknowledge */
while (SOC_CAN->MSR & CAN_MSR_INAK) while (SOC_CAN->MSR & CAN_MSR_INAK)
; ;
@ -403,7 +392,7 @@ can_init(void)
/*##-3- Configure Interrupts #################################*/ /*##-3- Configure Interrupts #################################*/
SOC_CAN->IER |= (CAN_IER_FMPIE0 | CAN_IER_FMPIE1); // RX mailbox IRQ SOC_CAN->IER = CAN_IER_FMPIE0 | CAN_IER_FMPIE1; // RX mailbox IRQ
armcm_enable_irq(CAN_IRQHandler, CAN_RX0_IRQn, 0); armcm_enable_irq(CAN_IRQHandler, CAN_RX0_IRQn, 0);
if (CAN_RX0_IRQn != CAN_RX1_IRQn) if (CAN_RX0_IRQn != CAN_RX1_IRQn)
@ -424,5 +413,5 @@ serial_enable_tx_irq(void)
// Serial port not initialized // Serial port not initialized
return; return;
SOC_CAN->IER |= CAN_IER_TMEIE; // TX mailbox IRQ SOC_CAN->IER = CAN_IER_FMPIE0 | CAN_IER_FMPIE1 | CAN_IER_TMEIE;
} }