diff --git a/STM32F1/cores/maple/HardwareTimer.cpp b/STM32F1/cores/maple/HardwareTimer.cpp index 48d040037..676ad3743 100644 --- a/STM32F1/cores/maple/HardwareTimer.cpp +++ b/STM32F1/cores/maple/HardwareTimer.cpp @@ -117,6 +117,22 @@ uint16 HardwareTimer::setPeriod(uint32 microseconds) { return overflow; } +uint16 HardwareTimer::setCycles(uint32 Cycles) { + // Not the best way to handle this edge case? + if (!Cycles) { + this->setPrescaleFactor(1); + this->setOverflow(1); + return this->getOverflow(); + } + + uint32 period_cyc = Cycles; + uint16 prescaler = (uint16)(period_cyc / MAX_RELOAD + 1); + uint16 overflow = (uint16)((period_cyc + (prescaler / 2)) / prescaler); + this->setPrescaleFactor(prescaler); + this->setOverflow(overflow); + return overflow; +} + void HardwareTimer::setMode(int channel, timer_mode mode) { timer_set_mode(this->dev, (uint8)channel, (timer_mode)mode); } diff --git a/STM32F1/cores/maple/HardwareTimer.h b/STM32F1/cores/maple/HardwareTimer.h index 45272ec0b..9fa1ca3ff 100644 --- a/STM32F1/cores/maple/HardwareTimer.h +++ b/STM32F1/cores/maple/HardwareTimer.h @@ -131,6 +131,18 @@ class HardwareTimer { */ void setCount(uint16 val); + /** + * @brief Set the timer's period in Cycles. + * + * Configures the prescaler and overflow values to generate a timer + * reload with a period of given number of + * Cycles. + * + * @param Cycles The desired period of the timer. This must be + * greater than zero. + * @return The new overflow value. + */ + uint16 setCycles(uint32 Cycles); /** * @brief Set the timer's period in microseconds. * diff --git a/STM32F1/libraries/HardwareCAN/examples/AstraH_CAN_test/AstraH_CAN_test.ino b/STM32F1/libraries/HardwareCAN/examples/AstraH_CAN_test/AstraH_CAN_test.ino new file mode 100644 index 000000000..a05576bb9 --- /dev/null +++ b/STM32F1/libraries/HardwareCAN/examples/AstraH_CAN_test/AstraH_CAN_test.ino @@ -0,0 +1,145 @@ +#include +/* + * Uses STM32duino with Phono patch. Must add 33 and 95 CAN speeds + */ +#define BPIN 0 +#define SPIN 1 +byte msgD0 ; // variable to be used in the example. + +// Instanciation of CAN interface +HardwareCAN canBus(CAN1_BASE); +CanMsg msg ; + +void CANSetup(void) +{ + CAN_STATUS Stat ; + + // Initialize CAN module + canBus.map(CAN_GPIO_PB8_PB9); // This setting is already wired in the Olimexino-STM32 board + Stat = canBus.begin(CAN_SPEED_95, CAN_MODE_NORMAL); // Other speeds go from 125 kbps to 1000 kbps. CAN allows even more choices. + + canBus.filter(0, 0, 0); + canBus.set_irq_mode(); // Use irq mode (recommended), so the handling of incoming messages + // will be performed at ease in a task or in the loop. The software fifo is 16 cells long, + // allowing at least 15 ms before processing the fifo is needed at 125 kbps + Stat = canBus.status(); + if (Stat != CAN_OK) + /* Your own error processing here */ ; // Initialization failed +} + + +// Send one frame. Parameter is a pointer to a frame structure (above), that has previously been updated with data. +// If no mailbox is available, wait until one becomes empty. There are 3 mailboxes. +CAN_TX_MBX CANsend(CanMsg *pmsg) // Should be moved to the library?! +{ + CAN_TX_MBX mbx; + + do + { + mbx = canBus.send(pmsg) ; +#ifdef USE_MULTITASK + vTaskDelay( 1 ) ; // Infinite loops are not multitasking-friendly +#endif + } + while(mbx == CAN_TX_NO_MBX) ; // Waiting outbound frames will eventually be sent, unless there is a CAN bus failure. + return mbx ; +} + +// Send message +// Prepare and send a frame containing some value +void SendCANmessage(long id=0x001, byte dlength=8, byte d0=0x00, byte d1=0x00, byte d2=0x00, byte d3=0x00, byte d4=0x00, byte d5=0x00, byte d6=0x00, byte d7=0x00) +{ + // Initialize the message structure + // A CAN structure includes the following fields: + msg.IDE = CAN_ID_STD; // Indicates a standard identifier ; CAN_ID_EXT would mean this frame uses an extended identifier + msg.RTR = CAN_RTR_DATA; // Indicated this is a data frame, as opposed to a remote frame (would then be CAN_RTR_REMOTE) + msg.ID = id ; // Identifier of the frame : 0-2047 (0-0x3ff) for standard idenfiers; 0-0x1fffffff for extended identifiers + msg.DLC = dlength; // Number of data bytes to follow + + // Prepare frame : send something + msg.Data[0] = d0 ; + msg.Data[1] = d1 ; + msg.Data[2] = d2 ; + msg.Data[3] = d3 ; + msg.Data[4] = d4 ; + msg.Data[5] = d5 ; + msg.Data[6] = d6 ; + msg.Data[7] = d7 ; + + digitalWrite(PC13, LOW); // turn the onboard LED on + CANsend(&msg) ; // Send this frame + delay(180); + digitalWrite(PC13, HIGH); // turn the LED off + delay(100); +} + +// The application program starts here +int bState = 0; // variable for reading the pushbutton status +int sState = 0; // variable for reading the switch status +byte st = 0x31; // buttot 1 on the CD30MP3 + +void setup() { + // put your setup code here, to run once: + CANSetup() ; // Initialize the CAN module and prepare the message structures. + pinMode(PC13, OUTPUT); + pinMode(BPIN, INPUT); // input for hardware button + pinMode(SPIN, INPUT); // input for hardware switch + Serial1.begin(115200); + Serial1.println("Hello World!"); + msgD0 = 0x01; + delay(500); +} + +void loop() { + bState = digitalRead(BPIN); + sState = digitalRead(SPIN); + // check if the pushbutton is pressed. + // if it is, the buttonState is HIGH: + if (bState == HIGH) { + long msgID = 0x201 ; + SendCANmessage(msgID, 3, 0x01, 0x6f, 0x00) ; + Serial1.println("OK pressed"); + } + + // check if the switch is high. + // if it is: + if (sState == HIGH) { + long msgID = 0x201 ; + SendCANmessage(msgID, 3, 0x01, st, 0x00) ; + Serial1.print("Station changed to "); + Serial1.println(st); + delay(500); + if (st == 0x39){st=0x31;} else {st++;}; + } +// try to read message and output to serial +CanMsg *r_msg; +if ((r_msg = canBus.recv()) != NULL){ + Serial1.print(r_msg->ID); + Serial1.print("#"); + Serial1.print(r_msg->Data[0]); + Serial1.print("."); + Serial1.print(r_msg->Data[1]); + Serial1.print("."); + Serial1.print(r_msg->Data[2]); + Serial1.print("."); + Serial1.print(r_msg->Data[3]); + Serial1.print("."); + Serial1.print(r_msg->Data[4]); + Serial1.print("."); + Serial1.print(r_msg->Data[5]); + Serial1.print("."); + Serial1.print(r_msg->Data[6]); + Serial1.print("."); + Serial1.println(r_msg->Data[7]); +if (r_msg->ID == 0x201 and r_msg->Data[0] == 0x01 and r_msg->Data[1] == 0xFF){ +// SETTINGS is pressed! + Serial1.println("SETTINGS. Pause for 2 seconds."); + digitalWrite(PC13, LOW); // turn the onboard LED on + delay(2000); + digitalWrite(PC13, HIGH); // turn the LED off + } + canBus.free(); + } + + +} diff --git a/STM32F1/libraries/HardwareCAN/examples/HardwareCAN_simplified_send1/HardwareCAN_simplified_send1.ino b/STM32F1/libraries/HardwareCAN/examples/HardwareCAN_simplified_send1/HardwareCAN_simplified_send1.ino new file mode 100644 index 000000000..17fb07f9b --- /dev/null +++ b/STM32F1/libraries/HardwareCAN/examples/HardwareCAN_simplified_send1/HardwareCAN_simplified_send1.ino @@ -0,0 +1,93 @@ +#include +//#include "changes.h" +/* + * Example of use of the HardwareCAN library + * This application sends two times one frame of data and then blinkes 3 times. Then repeats after 2 seconds. + * It also produces data that are sent periodically using another two frames. + * + * Please read the file changes.h to see the changes to be performed to the core in order to use this + */ + +byte msgD0 ; // variable to be used in the example. + +// Instanciation of CAN interface +HardwareCAN canBus(CAN1_BASE); +CanMsg msg ; + +void CANSetup(void) +{ + CAN_STATUS Stat ; + + // Initialize CAN module + canBus.map(CAN_GPIO_PB8_PB9); // This setting is already wired in the Olimexino-STM32 board + Stat = canBus.begin(CAN_SPEED_125, CAN_MODE_NORMAL); // Other speeds go from 125 kbps to 1000 kbps. CAN allows even more choices. + + canBus.filter(0, 0, 0); + canBus.set_irq_mode(); // Use irq mode (recommended), so the handling of incoming messages + // will be performed at ease in a task or in the loop. The software fifo is 16 cells long, + // allowing at least 15 ms before processing the fifo is needed at 125 kbps + Stat = canBus.status(); + if (Stat != CAN_OK) + /* Your own error processing here */ ; // Initialization failed +} + + +// Send one frame. Parameter is a pointer to a frame structure (above), that has previously been updated with data. +// If no mailbox is available, wait until one becomes empty. There are 3 mailboxes. +CAN_TX_MBX CANsend(CanMsg *pmsg) // Should be moved to the library?! +{ + CAN_TX_MBX mbx; + + do + { + mbx = canBus.send(pmsg) ; +#ifdef USE_MULTITASK + vTaskDelay( 1 ) ; // Infinite loops are not multitasking-friendly +#endif + } + while(mbx == CAN_TX_NO_MBX) ; // Waiting outbound frames will eventually be sent, unless there is a CAN bus failure. + return mbx ; +} + +// Send message +// Prepare and send a frame containing some value +void SendCANmessage(long id=0x001, byte d0=0x00, byte d1=0x00, byte d2=0x00, byte d3=0x00, byte d4=0x00, byte d5=0x00, byte d6=0x00, byte d7=0x00) +{ + // Initialize the message structure + // A CAN structure includes the following fields: + msg.IDE = CAN_ID_STD; // Indicates a standard identifier ; CAN_ID_EXT would mean this frame uses an extended identifier + msg.RTR = CAN_RTR_DATA; // Indicated this is a data frame, as opposed to a remote frame (would then be CAN_RTR_REMOTE) + msg.ID = id ; // Identifier of the frame : 0-2047 (0-0x3ff) for standard idenfiers; 0-0x1fffffff for extended identifiers + msg.DLC = 8; // Number of data bytes to follow + + // Prepare frame : send something + msg.Data[0] = d0 ; + msg.Data[1] = d1 ; + msg.Data[2] = d2 ; + msg.Data[3] = d3 ; + msg.Data[4] = d4 ; + msg.Data[5] = d5 ; + msg.Data[6] = d6 ; + msg.Data[7] = d7 ; + + digitalWrite(PC13, LOW); // turn the onboard LED on + CANsend(&msg) ; // Send this frame + delay(180); + digitalWrite(PC13, HIGH); // turn the LED off + delay(100); +} + +// The application program starts here +void setup() { + // put your setup code here, to run once: + CANSetup() ; // Initialize the CAN module and prepare the message structures. + pinMode(PC13, OUTPUT); + msgD0 = 0x01; +} + +void loop() { + delay(1000); + long msgID = 0x101 ; + SendCANmessage(msgID, msgD0) ; + msgD0++; +} diff --git a/STM32F1/libraries/HardwareCAN/examples/STMdualCAN/STMdualCAN.ino b/STM32F1/libraries/HardwareCAN/examples/STMdualCAN/STMdualCAN.ino new file mode 100644 index 000000000..cbeaf8962 --- /dev/null +++ b/STM32F1/libraries/HardwareCAN/examples/STMdualCAN/STMdualCAN.ino @@ -0,0 +1,123 @@ +#include +/* + * + */ + +#define T_DELAY 10 +// Instanciation of CAN interface +HardwareCAN canBus(CAN1_BASE); +CanMsg msg ; + + +void CAN_a_33_Setup(void) +{ + + CAN_STATUS Stat ; + afio_init(); // this will restart subsystem and make it work! + canBus.map(CAN_GPIO_PA11_PA12); + Stat = canBus.begin(CAN_SPEED_33, CAN_MODE_NORMAL); + canBus.filter(0, 0, 0); + canBus.set_irq_mode(); + Stat = canBus.status(); + if (Stat != CAN_OK) + {digitalWrite(PC13, LOW); + } +// /* Your own error processing here */ ; // Initialization failed + } + +void CAN_b_95_Setup(void) +{ + CAN_STATUS Stat ; + canBus.map(CAN_GPIO_PB8_PB9); + Stat = canBus.begin(CAN_SPEED_95, CAN_MODE_NORMAL); + canBus.filter(0, 0, 0); + canBus.set_irq_mode(); + Stat = canBus.status(); + if (Stat != CAN_OK) + {digitalWrite(PC13, LOW); + } +// /* Your own error processing here */ ; // Initialization failed +// delay(T_DELAY); +} + + +CAN_TX_MBX CANsend(CanMsg *pmsg) // Should be moved to the library?! +{ + CAN_TX_MBX mbx; + +// do +// { + mbx = canBus.send(pmsg) ; +#ifdef USE_MULTITASK + vTaskDelay( 1 ) ; // Infinite loops are not multitasking-friendly +#endif +// } +// while(mbx == CAN_TX_NO_MBX) ; // Waiting outbound frames will eventually be sent, unless there is a CAN bus failure. + return mbx ; +} + +// Send message +// Prepare and send a frame containing some value +void SendCANmessage(long id=0x001, byte dlength=8, byte d0=0x00, byte d1=0x00, byte d2=0x00, byte d3=0x00, byte d4=0x00, byte d5=0x00, byte d6=0x00, byte d7=0x00) +{ + // Initialize the message structure + // A CAN structure includes the following fields: + msg.IDE = CAN_ID_STD; // Indicates a standard identifier ; CAN_ID_EXT would mean this frame uses an extended identifier + msg.RTR = CAN_RTR_DATA; // Indicated this is a data frame, as opposed to a remote frame (would then be CAN_RTR_REMOTE) + msg.ID = id ; // Identifier of the frame : 0-2047 (0-0x3ff) for standard idenfiers; 0-0x1fffffff for extended identifiers + msg.DLC = dlength; // Number of data bytes to follow + + // Prepare frame : send something + msg.Data[0] = d0 ; + msg.Data[1] = d1 ; + msg.Data[2] = d2 ; + msg.Data[3] = d3 ; + msg.Data[4] = d4 ; + msg.Data[5] = d5 ; + msg.Data[6] = d6 ; + msg.Data[7] = d7 ; + + digitalWrite(PC13, LOW); // turn the onboard LED on + CANsend(&msg) ; // Send this frame + digitalWrite(PC13, HIGH); // turn the LED off + delay(T_DELAY); +} + + +// The application program starts here +byte msgD0 = 0x00; +void setup() { // Initialize the CAN module and prepare the message structures. + pinMode(PC13, OUTPUT); + digitalWrite(PC13, HIGH); + delay(10); + digitalWrite(PC13, LOW); + delay(200); + digitalWrite(PC13, HIGH); + delay(200); + +} + + +void loop() { +/**/ + CAN_a_33_Setup(); + SendCANmessage(0x108,8,0x03,msgD0,msgD0,0x00,msgD0,msgD0,0x00,0x00); + SendCANmessage(0x5e8,8,0x81,msgD0,msgD0,msgD0); + delay(30); +/**/ + CAN_b_95_Setup(); + for (byte msgD1=1;msgD1<3;msgD1++) + { + delay(T_DELAY); + SendCANmessage(0x201,3,0x01,0xff,msgD0); + delay(T_DELAY); + SendCANmessage(0x201,3,0x00,0xff,msgD0); + delay(T_DELAY); + SendCANmessage(0x201,3,0x01,0xff,msgD1); + delay(T_DELAY); + SendCANmessage(0x201,3,0x00,0xff,msgD1); + delay(T_DELAY); + } +/**/ +msgD0++; +} diff --git a/STM32F1/libraries/HardwareCAN/src/HardwareCAN.cpp b/STM32F1/libraries/HardwareCAN/src/HardwareCAN.cpp index f113c4d85..8a9933215 100644 --- a/STM32F1/libraries/HardwareCAN/src/HardwareCAN.cpp +++ b/STM32F1/libraries/HardwareCAN/src/HardwareCAN.cpp @@ -13,6 +13,8 @@ * - CAN_SPEED_500 * - CAN_SPEED_250 * - CAN_SPEED_125 + * - CAN_SPEED_95 + * - CAN_SPEED_33 */ CAN_STATUS HardwareCAN::begin(CAN_SPEED speed, uint32 mode) { @@ -57,6 +59,11 @@ uint8 HardwareCAN::available(void) return can_rx_available(); } +uint8 HardwareCAN::frame_lost(void) +{ + return can_frame_lost() ; +} + CanMsg* HardwareCAN::recv(void) { return can_rx_queue_get(); diff --git a/STM32F1/libraries/HardwareCAN/src/HardwareCAN.h b/STM32F1/libraries/HardwareCAN/src/HardwareCAN.h index ccc318f5b..944187e14 100644 --- a/STM32F1/libraries/HardwareCAN/src/HardwareCAN.h +++ b/STM32F1/libraries/HardwareCAN/src/HardwareCAN.h @@ -54,6 +54,7 @@ class HardwareCAN void cancel(CAN_TX_MBX mbx); uint8 available(void); + uint8 frame_lost(void); CanMsg* recv(void); diff --git a/STM32F1/libraries/HardwareCAN/src/utility/can.c b/STM32F1/libraries/HardwareCAN/src/utility/can.c index 0120e0eed..c551e27d7 100644 --- a/STM32F1/libraries/HardwareCAN/src/utility/can.c +++ b/STM32F1/libraries/HardwareCAN/src/utility/can.c @@ -1,9 +1,4 @@ -//#include "libmaple.h" #include "can.h" -//#include "rcc.h" -//#include "gpio.h" -//#include "nvic.h" -//#include "usb.h" /** * CAN_interrupts @@ -44,6 +39,18 @@ struct can_speed_info { #define CAN_CLOCK (36000000UL / 18UL) static const struct can_speed_info can_speed_table[] = { + [CAN_SPEED_33] = { .btr = ( + (( 4-1) << CAN_BTR_SJW_POS) | + ((12-1) << CAN_BTR_TS1_POS) | + (( 5-1) << CAN_BTR_TS2_POS) | + (CAN_CLOCK / 33000UL - 1) + )}, + [CAN_SPEED_95] = { .btr = ( + (( 4-1) << CAN_BTR_SJW_POS) | + ((12-1) << CAN_BTR_TS1_POS) | + (( 5-1) << CAN_BTR_TS2_POS) | + (CAN_CLOCK / 95000UL - 1) + )}, [CAN_SPEED_125] = { .btr = ( (( 4-1) << CAN_BTR_SJW_POS) | ((12-1) << CAN_BTR_TS1_POS) | @@ -73,10 +80,10 @@ static const struct can_speed_info can_speed_table[] = { CAN_STATUS status; CanMsg can_rx_queue[CAN_RX_QUEUE_SIZE]; -uint8 can_rx_head; -uint8 can_rx_tail; -uint8 can_rx_count; -uint8 can_rx_lost; +// JMD 2017/07/18 -- added volatile to fix queue problems, removed can_rx_count +volatile uint8 can_rx_head; +volatile uint8 can_rx_tail; +volatile uint8 can_rx_lost; uint8 can_active = 0; /** @@ -137,7 +144,10 @@ CAN_STATUS can_deinit(CAN_Port* CANx) if (CANx == CAN1_BASE) { nvic_irq_disable(NVIC_USB_LP_CAN_RX0); // Disable interrupts + nvic_irq_disable(NVIC_CAN_RX1); nvic_irq_disable(NVIC_USB_HP_CAN_TX); + __asm volatile( "dsb" ); // Synchronization of the pipeline to guarantee + __asm volatile( "isb" ); // that the protection against interrupts is effective rcc_reset_dev(RCC_CAN); rcc_clk_disable(RCC_CAN); can_active = 0; @@ -161,11 +171,10 @@ CAN_STATUS can_init(CAN_Port* CANx, uint32 control, uint8 speed) { status = CAN_INIT_FAILED; // default result status // initialize receive message queue - can_rx_head = can_rx_tail = can_rx_count = can_rx_lost = 0; + can_rx_head = can_rx_tail = can_rx_lost = 0; rcc_reset_dev(RCC_USB); //! X893 rcc_clk_disable(RCC_USB); //! X893 -// line_dtr_rts = 0; //! X893 rcc_clk_enable(RCC_AFIO); // enable clocks for AFIO rcc_clk_enable(RCC_CAN); // and CAN rcc_reset_dev(RCC_CAN); // reset CAN interface @@ -184,6 +193,7 @@ CAN_STATUS can_init(CAN_Port* CANx, uint32 control, uint8 speed) CANx->BTR |= (can_speed_table[speed].btr & CAN_TIMING_MASK); nvic_irq_enable(NVIC_USB_LP_CAN_RX0); // Enable interrupts + nvic_irq_enable(NVIC_CAN_RX1); nvic_irq_enable(NVIC_USB_HP_CAN_TX); @@ -245,6 +255,12 @@ CAN_STATUS can_gpio_map(CAN_Port* CANx, CAN_GPIO_MAP map_mode) gpio_set_mode(GPIOB, 8, GPIO_INPUT_FLOATING); gpio_set_mode(GPIOB, 9, GPIO_AF_OUTPUT_PP); break; + case CAN_GPIO_PA11_PA12: + rcc_clk_enable(RCC_GPIOA); + afio_remap(AFIO_MAPR_CAN_REMAP_NONE); + gpio_set_mode(GPIOA, 11, GPIO_INPUT_FLOATING); + gpio_set_mode(GPIOA, 12, GPIO_AF_OUTPUT_PP); + break; #if NR_GPIO_PORTS >= 4 case CAN_GPIO_PD0_PD1: rcc_clk_enable(RCC_GPIOD); @@ -261,7 +277,7 @@ CAN_STATUS can_gpio_map(CAN_Port* CANx, CAN_GPIO_MAP map_mode) return status; } -CAN_STATUS can_filter(CAN_Port* CANx, uint8 filter_idx, CAN_FIFO fifo, CAN_FILTER_SCALE scale, CAN_FILTER_MODE mode, uint32 fr1, uint32 fr2) +CAN_STATUS can_filter(CAN_Port* CANx, uint8 filter_idx, CAN_FIFO fifo, CAN_FILTER_SCALE scale, CAN_FILTER_MODE mode, uint32 fr1, uint32 fr2, int extID = 0) { uint32 mask = ((uint32)0x00000001) << filter_idx; @@ -273,9 +289,15 @@ CAN_STATUS can_filter(CAN_Port* CANx, uint8 filter_idx, CAN_FIFO fifo, CAN_FILTE CANx->FS1R |= mask; else CANx->FS1R &= ~mask; - - CANx->sFilterRegister[filter_idx].FR1 = fr1; - CANx->sFilterRegister[filter_idx].FR2 = fr2; + if (extID) { + CANx->sFilterRegister[filter_idx].FR1 = (fr1 << 3) | CAN_ID_EXT; + CANx->sFilterRegister[filter_idx].FR2 = (fr2 << 3) | CAN_ID_EXT; + } + else { + CANx->sFilterRegister[filter_idx].FR1 = (fr1 << 21); + CANx->sFilterRegister[filter_idx].FR2 = (fr2 << 21); + } + if (mode == CAN_FILTER_MASK) CANx->FM1R &= ~mask; @@ -430,30 +452,54 @@ void can_cancel(CAN_Port* CANx, uint8 mbx) void can_rx_queue_clear(void) { nvic_irq_disable(NVIC_USB_LP_CAN_RX0); - can_rx_head = can_rx_tail = can_rx_count = can_rx_lost = 0; + nvic_irq_disable(NVIC_CAN_RX1); + __asm volatile( "dsb" ); // Synchronization of the pipeline to guarantee + __asm volatile( "isb" ); // that the protection against interrupts is effective + can_rx_head = can_rx_tail = can_rx_lost = 0; // JMD 2017/07/18 nvic_irq_enable(NVIC_USB_LP_CAN_RX0); + nvic_irq_enable(NVIC_CAN_RX1); } +// JMD 2017/07/18 -- changed uint8 can_rx_available(void) { - return can_rx_count; + if ( can_rx_head >= can_rx_tail ) + return can_rx_head - can_rx_tail ; + else + return CAN_RX_QUEUE_SIZE - ( can_rx_tail - can_rx_head ) ; +} + +// JMD 2017/07/18 -- added +uint8 can_frame_lost(void) +{ + if ( can_rx_lost != 0 ) + { + can_rx_lost = 0 ; + return 1 ; + } + return 0 ; + } CanMsg* can_rx_queue_get(void) { - if (can_rx_count == 0) + if (can_rx_head == can_rx_tail) // JMD 2017/07/18 -- changed return NULL; return &(can_rx_queue[can_rx_tail]); } + void can_rx_queue_free(void) { - if (can_rx_count > 0) + if (can_rx_head != can_rx_tail) // JMD 2017/07/18 -- changed { - nvic_irq_disable(NVIC_USB_LP_CAN_RX0); // JMD problème d'atomicité + nvic_irq_disable(NVIC_USB_LP_CAN_RX0); // JMD atomicity problem + nvic_irq_disable(NVIC_CAN_RX1); + __asm volatile( "dsb" ); // Synchronization of the pipeline to guarantee + __asm volatile( "isb" ); // that the protection against interrupts is effective can_rx_tail = (can_rx_tail == (CAN_RX_QUEUE_SIZE - 1)) ? 0 : (can_rx_tail + 1); - --can_rx_count; nvic_irq_enable(NVIC_USB_LP_CAN_RX0); // fin JMD problème d'atomicité + nvic_irq_enable(NVIC_CAN_RX1); } } @@ -504,12 +550,11 @@ void can_rx_release(CAN_Port* CANx, CAN_FIFO fifo) void can_rx_read(CAN_Port* CANx, CAN_FIFO fifo) { - if (can_rx_count < CAN_RX_QUEUE_SIZE) // read the message + if (can_rx_available() < CAN_RX_QUEUE_SIZE) // read the message { CanMsg* msg = &can_rx_queue[can_rx_head]; can_read(CANx, fifo, msg); can_rx_head = (can_rx_head == (CAN_RX_QUEUE_SIZE - 1)) ? 0 : (can_rx_head + 1); - can_rx_count++; } else can_rx_lost = 1; // no place in queue, ignore package @@ -529,6 +574,12 @@ uint8 CAN_RX0_IRQ_Handler(void) return can_active; // return CAN active flag to USB handler } +// Addition JMD: the messages stored in fifo1 must also trigger an interrupt. +void __irq_can_rx1(void) +{ + CAN_RX0_IRQ_Handler() ; +} + void USB_HP_CAN_TX_IRQHandler (void) { if (can_active) diff --git a/STM32F1/libraries/HardwareCAN/src/utility/can.c.txt b/STM32F1/libraries/HardwareCAN/src/utility/can.c.txt new file mode 100644 index 000000000..64cedac5e --- /dev/null +++ b/STM32F1/libraries/HardwareCAN/src/utility/can.c.txt @@ -0,0 +1,591 @@ +//#include "libmaple.h" +#include "can.h" +//#include "rcc.h" +//#include "gpio.h" +//#include "nvic.h" +//#include "usb.h" + +/** + * CAN_interrupts + */ + +#define CAN_IT_RQCP0 ((uint32)0x00000005) /* Request completed mailbox 0 */ +#define CAN_IT_RQCP1 ((uint32)0x00000006) /* Request completed mailbox 1 */ +#define CAN_IT_RQCP2 ((uint32)0x00000007) /* Request completed mailbox 2 */ +#define CAN_IT_TME ((uint32)0x00000001) /* Transmit mailbox empty */ +#define CAN_IT_FMP0 ((uint32)0x00000002) /* FIFO 0 message pending */ +#define CAN_IT_FF0 ((uint32)0x00000004) /* FIFO 0 full */ +#define CAN_IT_FOV0 ((uint32)0x00000008) /* FIFO 0 overrun */ +#define CAN_IT_FMP1 ((uint32)0x00000010) /* FIFO 1 message pending */ +#define CAN_IT_FF1 ((uint32)0x00000020) /* FIFO 1 full */ +#define CAN_IT_FOV1 ((uint32)0x00000040) /* FIFO 1 overrun */ +#define CAN_IT_EWG ((uint32)0x00000100) /* Error warning */ +#define CAN_IT_EPV ((uint32)0x00000200) /* Error passive */ +#define CAN_IT_BOF ((uint32)0x00000400) /* Bus-off */ +#define CAN_IT_LEC ((uint32)0x00000800) /* Last error code */ +#define CAN_IT_ERR ((uint32)0x00008000) /* Error */ +#define CAN_IT_WKU ((uint32)0x00010000) /* Wake-up */ +#define CAN_IT_SLK ((uint32)0x00020000) /* Sleep */ + +/* Time out for INAK bit */ +#define CAN_INAK_TimeOut ((uint32)0x0000FFFF) + +/* Time out for SLAK bit */ +#define CAN_SLAK_TimeOut ((uint32)0x0000FFFF) + +#define CAN_CONTROL_MASK (CAN_MCR_TTCM | CAN_MCR_ABOM | CAN_MCR_AWUM | CAN_MCR_NART | CAN_MCR_RFLM | CAN_MCR_TXFP) +#define CAN_TIMING_MASK (CAN_BTR_SJW | CAN_BTR_TS2 | CAN_BTR_TS1 | CAN_BTR_BRP) +#define CAN_MODE_MASK (CAN_BTR_LBKM | CAN_BTR_SILM) + +struct can_speed_info { + const uint32 btr; +}; + +#define CAN_CLOCK (36000000UL / 18UL) + +static const struct can_speed_info can_speed_table[] = { + [CAN_SPEED_125] = { .btr = ( + (( 4-1) << CAN_BTR_SJW_POS) | + ((12-1) << CAN_BTR_TS1_POS) | + (( 5-1) << CAN_BTR_TS2_POS) | + (CAN_CLOCK / 125000UL - 1) + )}, + [CAN_SPEED_250] = { .btr = ( + (( 4-1) << CAN_BTR_SJW_POS) | + ((12-1) << CAN_BTR_TS1_POS) | + (( 5-1) << CAN_BTR_TS2_POS) | + (CAN_CLOCK / 250000UL - 1) + )}, + [CAN_SPEED_500] = { .btr = ( + (( 4-1) << CAN_BTR_SJW_POS) | + ((12-1) << CAN_BTR_TS1_POS) | + (( 5-1) << CAN_BTR_TS2_POS) | + (CAN_CLOCK / 500000UL - 1) + )}, + [CAN_SPEED_1000] = { .btr = ( + (( 4-1) << CAN_BTR_SJW_POS) | + ((12-1) << CAN_BTR_TS1_POS) | + (( 5-1) << CAN_BTR_TS2_POS) | + (CAN_CLOCK / 1000000UL - 1) + )} +}; + +CAN_STATUS status; +CanMsg can_rx_queue[CAN_RX_QUEUE_SIZE]; + +// JMD 2017/07/18 -- added volatile to fix queue problems +volatile uint8 can_rx_head; +volatile uint8 can_rx_tail; +//volatile uint8 can_rx_count; // JMD 2017/07/18 -- redundant +volatile uint8 can_rx_lost; +uint8 can_active = 0; + +/** + * @brief Return last operation status + */ +CAN_STATUS can_status(void) +{ + return status; +} + +/** + * @brief Enter initialization mode + */ +CAN_STATUS can_init_enter(CAN_Port* CANx) +{ + volatile uint32 wait_ack = 0 ; + + status = CAN_OK; + if ((CANx->MSR & CAN_MSR_INAK) == 0) // Check for initialization mode already set + { + CANx->MCR |= CAN_MCR_INRQ; // Request initialisation + + wait_ack = 0; // Wait the acknowledge + while ((wait_ack != CAN_INAK_TimeOut) && ((CANx->MSR & CAN_MSR_INAK) == 0)) + wait_ack++; + if ((CANx->MSR & CAN_MSR_INAK) == 0) + status = CAN_INIT_E_FAILED; // Timeout + } + return status; +} + +/** + * @brief Leave initialization mode + */ +CAN_STATUS can_init_leave(CAN_Port* CANx) +{ + volatile uint32 wait_ack = 0 ; + + status = CAN_OK; + if ((CANx->MSR & CAN_MSR_INAK) != 0) // Check for initialization mode already reset + { + CANx->MCR &= ~CAN_MCR_INRQ; // Clear Request initialization + + wait_ack = 0; // Wait the acknowledge + while ((wait_ack != CAN_INAK_TimeOut) && ((CANx->MSR & CAN_MSR_INAK) != 0)) + wait_ack++; + if ((CANx->MSR & CAN_MSR_INAK) != 0) + status = CAN_INIT_L_FAILED; + } + return status; +} + +/** + * @brief Deinitializes the CAN peripheral registers to their default reset values. + */ +CAN_STATUS can_deinit(CAN_Port* CANx) +{ + if (CANx == CAN1_BASE) + { + nvic_irq_disable(NVIC_USB_LP_CAN_RX0); // Disable interrupts + nvic_irq_disable(NVIC_CAN_RX1); + nvic_irq_disable(NVIC_USB_HP_CAN_TX); + __asm volatile( "dsb" ); // Synchronization of the pipeline to guarantee + __asm volatile( "isb" ); // that the protection against interrupts is effective + rcc_reset_dev(RCC_CAN); + rcc_clk_disable(RCC_CAN); + can_active = 0; + } + return (status = CAN_OK); +} + +/** + * @brief Initialize CAN registers + */ +/* + * Bits in control parameter: + * CAN_MCR_TTCM time triggered communication mode + * CAN_MCR_ABOM automatic bus-off management + * CAN_MCR_AWUM automatic wake-up mode + * CAN_MCR_NART no automatic retransmission + * CAN_MCR_RFLM receive FIFO locked mode + * CAN_MCR_TXFP transmit FIFO priority + */ +CAN_STATUS can_init(CAN_Port* CANx, uint32 control, uint8 speed) +{ + status = CAN_INIT_FAILED; // default result status + // initialize receive message queue +// can_rx_head = can_rx_tail = can_rx_count = can_rx_lost = 0; // JMD 2017/07/18 + can_rx_head = can_rx_tail = can_rx_lost = 0; + + rcc_reset_dev(RCC_USB); //! X893 + rcc_clk_disable(RCC_USB); //! X893 +// line_dtr_rts = 0; //! X893 + rcc_clk_enable(RCC_AFIO); // enable clocks for AFIO + rcc_clk_enable(RCC_CAN); // and CAN + rcc_reset_dev(RCC_CAN); // reset CAN interface + + can_active = 1; // set CAN active flag (for interrupt handler + + CANx->MCR &= ~CAN_MCR_SLEEP; // reset CAN sleep mode (default after reset) + + if (can_init_enter(CANx) != CAN_OK) // enter CAN initialization mode + return status; // error, so return + + CANx->MCR &= ~CAN_CONTROL_MASK; // set mode bits + CANx->MCR |= (control & CAN_CONTROL_MASK); + + CANx->BTR &= ~CAN_TIMING_MASK; // Set the bit timing register + CANx->BTR |= (can_speed_table[speed].btr & CAN_TIMING_MASK); + + nvic_irq_enable(NVIC_USB_LP_CAN_RX0); // Enable interrupts + nvic_irq_enable(NVIC_CAN_RX1); + + nvic_irq_enable(NVIC_USB_HP_CAN_TX); + + CANx->IER = (CAN_IER_FMPIE0 | CAN_IER_FMPIE1 | CAN_IER_TMEIE); + + if (can_init_leave(CANx) == CAN_OK) + { + while (!(CANx->TSR & CAN_TSR_TME0)); // Transmit mailbox 0 is empty + while (!(CANx->TSR & CAN_TSR_TME1)); // Transmit mailbox 0 is empty + while (!(CANx->TSR & CAN_TSR_TME2)); // Transmit mailbox 0 is empty + } + return status; +} + +/** + * @brief Set timing calues (CAN_BTR) + */ +CAN_STATUS can_set_timing(CAN_Port* CANx, uint32 timing) +{ + if (can_init_enter(CANx) == CAN_OK) + { + CANx->BTR = ((CANx->BTR & ~CAN_TIMING_MASK) | (timing & CAN_TIMING_MASK)); + can_init_leave(CANx); + } + return status; +} + +/** + * @brief Set CAN mode + * @param CANx pointer to CAN port + * @param mode CAN mode + */ +CAN_STATUS can_set_mode(CAN_Port* CANx, uint32 mode) +{ + if (can_init_enter(CANx) == CAN_OK) + { + CANx->BTR &= ~CAN_MODE_MASK; + CANx->BTR |= (mode & CAN_MODE_MASK); + can_init_leave(CANx); + } + return status; +} + +/** + * @brief Set CAN to GPIO mapping + */ +CAN_STATUS can_gpio_map(CAN_Port* CANx, CAN_GPIO_MAP map_mode) +{ + rcc_clk_enable(RCC_AFIO); + + status = CAN_INIT_FAILED; + if( CANx == CAN1_BASE) + { + switch(map_mode) + { + case CAN_GPIO_PB8_PB9: + rcc_clk_enable(RCC_GPIOB); + afio_remap(AFIO_MAPR_CAN_REMAP_PB8_PB9); + gpio_set_mode(GPIOB, 8, GPIO_INPUT_FLOATING); + gpio_set_mode(GPIOB, 9, GPIO_AF_OUTPUT_PP); + break; +#if NR_GPIO_PORTS >= 4 + case CAN_GPIO_PD0_PD1: + rcc_clk_enable(RCC_GPIOD); + afio_remap(AFIO_MAPR_CAN_REMAP_PD0_PD1); + gpio_set_mode(GPIOD, 0, GPIO_INPUT_FLOATING); + gpio_set_mode(GPIOD, 1, GPIO_AF_OUTPUT_PP); + break; +#endif + default: + return status; + } + status = CAN_OK; + } + return status; +} + +CAN_STATUS can_filter(CAN_Port* CANx, uint8 filter_idx, CAN_FIFO fifo, CAN_FILTER_SCALE scale, CAN_FILTER_MODE mode, uint32 fr1, uint32 fr2) +{ + uint32 mask = ((uint32)0x00000001) << filter_idx; + + CANx->FMR |= CAN_FMR_FINIT; // Initialization mode for the filter + CANx->FA1R &= ~mask; // Deactivation filter + + + if (scale == CAN_FILTER_32BIT) + CANx->FS1R |= mask; + else + CANx->FS1R &= ~mask; + + CANx->sFilterRegister[filter_idx].FR1 = fr1; + CANx->sFilterRegister[filter_idx].FR2 = fr2; + + if (mode == CAN_FILTER_MASK) + CANx->FM1R &= ~mask; + else + CANx->FM1R |= mask; + + if (fifo == CAN_FIFO0) + CANx->FFA1R &= ~mask; + else + CANx->FFA1R |= mask; + + CANx->FA1R |= mask; + CANx->FMR &= ~CAN_FMR_FINIT; + return CAN_OK; +} + + +/** + * @brief Initiates the transmission of a message. + * @param CANx: where x can be 1 to select the CAN peripheral. + * @param msg: pointer to a structure which contains CAN Id, CAN DLC and CAN datas. + * @retval : The number of the mailbox that is used for transmission or CAN_NO_MB if there is no empty mailbox. + */ +CAN_TX_MBX can_transmit(CAN_Port* CANx, CanMsg* msg) +{ + CAN_TX_MBX mbx; + uint32 data; + + /* Select one empty transmit mailbox */ + if (CANx->TSR & CAN_TSR_TME0) + mbx = CAN_TX_MBX0; + else if (CANx->TSR & CAN_TSR_TME1) + mbx = CAN_TX_MBX1; + else if (CANx->TSR & CAN_TSR_TME2) + mbx = CAN_TX_MBX2; + else + { + status = CAN_NO_MB; + return CAN_TX_NO_MBX; + } + + /* Set up the Id */ + if (msg->IDE == CAN_ID_STD) + data = (msg->ID << 21); + else + data = (msg->ID << 3) | CAN_ID_EXT; + + data |= ((uint32)msg->RTR); + + /* Set up the DLC */ + CANx->sTxMailBox[mbx].TDTR = (uint32)(msg->DLC & 0x0F); + + /* Set up the data field */ + CANx->sTxMailBox[mbx].TDLR = ( + ((uint32)msg->Data[3] << 24) | + ((uint32)msg->Data[2] << 16) | + ((uint32)msg->Data[1] << 8) | + ((uint32)msg->Data[0]) + ); + CANx->sTxMailBox[mbx].TDHR = ( + ((uint32)msg->Data[7] << 24) | + ((uint32)msg->Data[6] << 16) | + ((uint32)msg->Data[5] << 8) | + ((uint32)msg->Data[4]) + ); + /* Request transmission */ + CANx->sTxMailBox[mbx].TIR = (data | CAN_TMIDxR_TXRQ); + status = CAN_OK; + + return mbx; +} + +/** + * Checks the transmission of a message. + * @param CANx: where x can be 1 to select the CAN peripheral. + * @param mbx: the number of the mailbox that is used for transmission. + * @retval : CAN_TX_OK if the CAN driver transmits the message, CAN_TX_FAILED in an other case. + */ +CAN_STATUS can_tx_status(CAN_Port* CANx, CAN_TX_MBX mbx) +{ + /* RQCP, TXOK and TME bits */ + uint8 state = 0; + + switch (mbx) + { + case CAN_TX_MBX0: + state |= (uint8)((CANx->TSR & CAN_TSR_RQCP0) << 2); + state |= (uint8)((CANx->TSR & CAN_TSR_TXOK0) >> 0); + state |= (uint8)((CANx->TSR & CAN_TSR_TME0) >> 26); + break; + case CAN_TX_MBX1: + state |= (uint8)((CANx->TSR & CAN_TSR_RQCP1) >> 6); + state |= (uint8)((CANx->TSR & CAN_TSR_TXOK1) >> 8); + state |= (uint8)((CANx->TSR & CAN_TSR_TME1) >> 27); + break; + case CAN_TX_MBX2: + state |= (uint8)((CANx->TSR & CAN_TSR_RQCP2) >> 14); + state |= (uint8)((CANx->TSR & CAN_TSR_TXOK2) >> 16); + state |= (uint8)((CANx->TSR & CAN_TSR_TME2) >> 28); + break; + default: + status = CAN_TX_FAILED; + return status; + } + + // state = RQCP TXOK TME + switch (state) + { + /* transmit pending */ + case 0x0: + status = CAN_TX_PENDING; + break; + /* transmit failed */ + case 0x5: + status = CAN_TX_FAILED; + break; + /* transmit succedeed */ + case 0x7: + status = CAN_OK; + break; + default: + status = CAN_TX_FAILED; + break; + } + return status; +} + +/** + * @brief Cancels a transmit request. + * @param CANx: where x can be 1 to select the CAN peripheral. + * @param mbx: Mailbox number. + * @retval : None. + */ +void can_cancel(CAN_Port* CANx, uint8 mbx) +{ + /* abort transmission */ + switch (mbx) + { + case 0: + CANx->TSR |= CAN_TSR_ABRQ0; + break; + case 1: + CANx->TSR |= CAN_TSR_ABRQ1; + break; + case 2: + CANx->TSR |= CAN_TSR_ABRQ2; + break; + default: + break; + } +} + +void can_rx_queue_clear(void) +{ + nvic_irq_disable(NVIC_USB_LP_CAN_RX0); + nvic_irq_disable(NVIC_CAN_RX1); + __asm volatile( "dsb" ); // Synchronization of the pipeline to guarantee + __asm volatile( "isb" ); // that the protection against interrupts is effective +// can_rx_head = can_rx_tail = can_rx_count = can_rx_lost = 0; // JMD 2017/07/18 + can_rx_head = can_rx_tail = can_rx_lost = 0; // JMD 2017/07/18 + nvic_irq_enable(NVIC_USB_LP_CAN_RX0); + nvic_irq_enable(NVIC_CAN_RX1); +} + +// JMD 2017/07/18 -- removed +/* +uint8 can_rx_available(void) +{ + return can_rx_count; +} +*/ + +// JMD 2017/07/18 -- added +uint8 can_rx_available(void) +{ + if ( can_rx_head >= can_rx_tail ) + return can_rx_head - can_rx_tail ; + else + return CAN_RX_QUEUE_SIZE - ( can_rx_tail - can_rx_head ) ; +} + +// JMD 2017/07/18 -- added +uint8 can_frame_lost(void) +{ + if ( can_rx_lost != 0 ) + { + can_rx_lost = 0 ; + return 1 ; + } + return 0 ; + +} + +CanMsg* can_rx_queue_get(void) +{ + if (can_rx_head == can_rx_tail) // JMD 2017/07/18 -- changed + return NULL; + return &(can_rx_queue[can_rx_tail]); +} + + +void can_rx_queue_free(void) +{ + if (can_rx_head != can_rx_tail) // JMD 2017/07/18 -- changed + { + nvic_irq_disable(NVIC_USB_LP_CAN_RX0); // JMD atomicity problem + nvic_irq_disable(NVIC_CAN_RX1); + __asm volatile( "dsb" ); // Synchronization of the pipeline to guarantee + __asm volatile( "isb" ); // that the protection against interrupts is effective + can_rx_tail = (can_rx_tail == (CAN_RX_QUEUE_SIZE - 1)) ? 0 : (can_rx_tail + 1); +// --can_rx_count; // JMD 2017/07/18 -- removed + nvic_irq_enable(NVIC_USB_LP_CAN_RX0); // fin JMD problème d'atomicité + nvic_irq_enable(NVIC_CAN_RX1); + } +} + +CanMsg* can_read(CAN_Port* CANx, CAN_FIFO fifo, CanMsg* msg) +{ + uint32 data = CANx->sFIFOMailBox[fifo].RIR; + + /* Get the Id */ + if (data & CAN_ID_EXT) + { + msg->ID = 0x1FFFFFFF & (data >> 3); + msg->IDE = (uint8)CAN_ID_EXT; + } + else + { + msg->ID = 0x000007FF & (data >> 21); + msg->IDE = (uint8)CAN_ID_STD; + } + + msg->RTR = (uint8)(CAN_RTR_REMOTE & data); + msg->DLC = (uint8)(0x0F & CANx->sFIFOMailBox[fifo].RDTR); + msg->FMI = (uint8)(0xFF & (CANx->sFIFOMailBox[fifo].RDTR >> 8)); + + /* Get the data field */ + data = CANx->sFIFOMailBox[fifo].RDLR; + uint8* p = msg->Data; + *p++ = (uint8)0xFF & data; + *p++ = (uint8)0xFF & (data >> 8); + *p++ = (uint8)0xFF & (data >> 16); + *p++ = (uint8)0xFF & (data >> 24); + + data = CANx->sFIFOMailBox[fifo].RDHR; + *p++ = (uint8)0xFF & data; + *p++ = (uint8)0xFF & (data >> 8); + *p++ = (uint8)0xFF & (data >> 16); + *p++ = (uint8)0xFF & (data >> 24); + + return msg; +} + +void can_rx_release(CAN_Port* CANx, CAN_FIFO fifo) +{ + if (fifo == CAN_FIFO0) + CANx->RF0R |= (CAN_RF0R_RFOM0); // Release FIFO0 + else + CANx->RF1R |= (CAN_RF1R_RFOM1); // Release FIFO1 +} + +void can_rx_read(CAN_Port* CANx, CAN_FIFO fifo) +{ +// if (can_rx_count < CAN_RX_QUEUE_SIZE) // JMD 2017/07/18 + if (can_rx_available() < CAN_RX_QUEUE_SIZE) // read the message + { + CanMsg* msg = &can_rx_queue[can_rx_head]; + can_read(CANx, fifo, msg); + can_rx_head = (can_rx_head == (CAN_RX_QUEUE_SIZE - 1)) ? 0 : (can_rx_head + 1); +// can_rx_count++; // JMD 2017/07/18 -- removed + } + else + can_rx_lost = 1; // no place in queue, ignore package + + can_rx_release(CANx, fifo); +} + +uint8 CAN_RX0_IRQ_Handler(void) +{ + if (can_active) + { + while ((CAN1_BASE->RF0R & CAN_RF0R_FMP0) != 0) + can_rx_read(CAN1_BASE, CAN_FIFO0); // message pending FIFO0 + while ((CAN1_BASE->RF1R & CAN_RF1R_FMP1) != 0) + can_rx_read(CAN1_BASE, CAN_FIFO1); // message pending FIFO1 + } + return can_active; // return CAN active flag to USB handler +} + +// Addition JMD: the messages stored in fifo1 must also trigger an interrupt. +void __irq_can_rx1(void) +{ + CAN_RX0_IRQ_Handler() ; +} + +void USB_HP_CAN_TX_IRQHandler (void) +{ + if (can_active) + { + if (CAN1_BASE->TSR & CAN_TSR_RQCP0) + CAN1_BASE->TSR |= CAN_TSR_RQCP0; // reset request complete mbx 0 + if (CAN1_BASE->TSR & CAN_TSR_RQCP1) + CAN1_BASE->TSR |= CAN_TSR_RQCP1; // reset request complete mbx 1 + if (CAN1_BASE->TSR & CAN_TSR_RQCP2) + CAN1_BASE->TSR |= CAN_TSR_RQCP2; // reset request complete mbx 2 + } +} diff --git a/STM32F1/libraries/HardwareCAN/src/utility/can.h b/STM32F1/libraries/HardwareCAN/src/utility/can.h index 576ac36fe..1f2966243 100644 --- a/STM32F1/libraries/HardwareCAN/src/utility/can.h +++ b/STM32F1/libraries/HardwareCAN/src/utility/can.h @@ -139,7 +139,8 @@ extern "C" { typedef enum CAN_GPIO_MAP { CAN_GPIO_PB8_PB9, /* RX to PB8, TX to PB9 */ - CAN_GPIO_PD0_PD1 /* RX to PD0, TX to PD1 */ + CAN_GPIO_PD0_PD1, /* RX to PD0, TX to PD1 */ + CAN_GPIO_PA11_PA12 /* RX to PA11, TX to PA12 */ } CAN_GPIO_MAP; typedef enum CAN_STATUS @@ -168,6 +169,8 @@ typedef enum CAN_TX_MBX #define CAN_MODE_SILENT_LOOPBACK (CAN_BTR_LBKM | CAN_BTR_SILM) /* loopback combined with silent mode */ enum CAN_SPEED { + CAN_SPEED_33, + CAN_SPEED_95, CAN_SPEED_125, CAN_SPEED_250, CAN_SPEED_500, @@ -285,6 +288,7 @@ CAN_STATUS can_status(void); void can_cancel(CAN_Port* CANx, uint8 mbx); void can_rx_queue_clear(void); uint8 can_rx_available(void); +uint8 can_frame_lost(void); CanMsg* can_rx_queue_get(void); CanMsg* can_read(CAN_Port* CANx, CAN_FIFO fifo, CanMsg* msg); void can_rx_release(CAN_Port* CANx, CAN_FIFO fifo); diff --git a/STM32F1/libraries/HardwareCAN/src/utility/can.temp.c b/STM32F1/libraries/HardwareCAN/src/utility/can.temp.c new file mode 100644 index 000000000..e9b270c81 --- /dev/null +++ b/STM32F1/libraries/HardwareCAN/src/utility/can.temp.c @@ -0,0 +1,599 @@ +Skip to content +Features +Business +Explore +Marketplace +Pricing +This repository +Search +Sign in or Sign up + Watch 3 Star 2 Fork 363 megadrifter/Arduino_STM32 +forked from Phonog/Arduino_STM32 + Code Pull requests 0 Projects 0 Insights +Branch: megadrifter-GM… Find file Copy pathArduino_STM32/STM32F1/libraries/HardwareCAN/src/utility/can.c +a9807d2 9 days ago +@megadrifter megadrifter CAN filter corrected by tjb12345 +2 contributors @megadrifter @Phonog +RawBlameHistory +567 lines (500 sloc) 14.3 KB +#include "can.h" + +/** + * CAN_interrupts + */ + +#define CAN_IT_RQCP0 ((uint32)0x00000005) /* Request completed mailbox 0 */ +#define CAN_IT_RQCP1 ((uint32)0x00000006) /* Request completed mailbox 1 */ +#define CAN_IT_RQCP2 ((uint32)0x00000007) /* Request completed mailbox 2 */ +#define CAN_IT_TME ((uint32)0x00000001) /* Transmit mailbox empty */ +#define CAN_IT_FMP0 ((uint32)0x00000002) /* FIFO 0 message pending */ +#define CAN_IT_FF0 ((uint32)0x00000004) /* FIFO 0 full */ +#define CAN_IT_FOV0 ((uint32)0x00000008) /* FIFO 0 overrun */ +#define CAN_IT_FMP1 ((uint32)0x00000010) /* FIFO 1 message pending */ +#define CAN_IT_FF1 ((uint32)0x00000020) /* FIFO 1 full */ +#define CAN_IT_FOV1 ((uint32)0x00000040) /* FIFO 1 overrun */ +#define CAN_IT_EWG ((uint32)0x00000100) /* Error warning */ +#define CAN_IT_EPV ((uint32)0x00000200) /* Error passive */ +#define CAN_IT_BOF ((uint32)0x00000400) /* Bus-off */ +#define CAN_IT_LEC ((uint32)0x00000800) /* Last error code */ +#define CAN_IT_ERR ((uint32)0x00008000) /* Error */ +#define CAN_IT_WKU ((uint32)0x00010000) /* Wake-up */ +#define CAN_IT_SLK ((uint32)0x00020000) /* Sleep */ + +/* Time out for INAK bit */ +#define CAN_INAK_TimeOut ((uint32)0x0000FFFF) + +/* Time out for SLAK bit */ +#define CAN_SLAK_TimeOut ((uint32)0x0000FFFF) + +#define CAN_CONTROL_MASK (CAN_MCR_TTCM | CAN_MCR_ABOM | CAN_MCR_AWUM | CAN_MCR_NART | CAN_MCR_RFLM | CAN_MCR_TXFP) +#define CAN_TIMING_MASK (CAN_BTR_SJW | CAN_BTR_TS2 | CAN_BTR_TS1 | CAN_BTR_BRP) +#define CAN_MODE_MASK (CAN_BTR_LBKM | CAN_BTR_SILM) + +struct can_speed_info { + const uint32 btr; +}; + +#define CAN_CLOCK (36000000UL / 18UL) + +static const struct can_speed_info can_speed_table[] = { + [CAN_SPEED_125] = { .btr = ( + (( 4-1) << CAN_BTR_SJW_POS) | + ((12-1) << CAN_BTR_TS1_POS) | + (( 5-1) << CAN_BTR_TS2_POS) | + (CAN_CLOCK / 125000UL - 1) + )}, + [CAN_SPEED_250] = { .btr = ( + (( 4-1) << CAN_BTR_SJW_POS) | + ((12-1) << CAN_BTR_TS1_POS) | + (( 5-1) << CAN_BTR_TS2_POS) | + (CAN_CLOCK / 250000UL - 1) + )}, + [CAN_SPEED_500] = { .btr = ( + (( 4-1) << CAN_BTR_SJW_POS) | + ((12-1) << CAN_BTR_TS1_POS) | + (( 5-1) << CAN_BTR_TS2_POS) | + (CAN_CLOCK / 500000UL - 1) + )}, + [CAN_SPEED_1000] = { .btr = ( + (( 4-1) << CAN_BTR_SJW_POS) | + ((12-1) << CAN_BTR_TS1_POS) | + (( 5-1) << CAN_BTR_TS2_POS) | + (CAN_CLOCK / 1000000UL - 1) + )} +}; + +CAN_STATUS status; +CanMsg can_rx_queue[CAN_RX_QUEUE_SIZE]; + +// JMD 2017/07/18 -- added volatile to fix queue problems, removed can_rx_count +volatile uint8 can_rx_head; +volatile uint8 can_rx_tail; +volatile uint8 can_rx_lost; +uint8 can_active = 0; + +/** + * @brief Return last operation status + */ +CAN_STATUS can_status(void) +{ + return status; +} + +/** + * @brief Enter initialization mode + */ +CAN_STATUS can_init_enter(CAN_Port* CANx) +{ + volatile uint32 wait_ack = 0 ; + + status = CAN_OK; + if ((CANx->MSR & CAN_MSR_INAK) == 0) // Check for initialization mode already set + { + CANx->MCR |= CAN_MCR_INRQ; // Request initialisation + + wait_ack = 0; // Wait the acknowledge + while ((wait_ack != CAN_INAK_TimeOut) && ((CANx->MSR & CAN_MSR_INAK) == 0)) + wait_ack++; + if ((CANx->MSR & CAN_MSR_INAK) == 0) + status = CAN_INIT_E_FAILED; // Timeout + } + return status; +} + +/** + * @brief Leave initialization mode + */ +CAN_STATUS can_init_leave(CAN_Port* CANx) +{ + volatile uint32 wait_ack = 0 ; + + status = CAN_OK; + if ((CANx->MSR & CAN_MSR_INAK) != 0) // Check for initialization mode already reset + { + CANx->MCR &= ~CAN_MCR_INRQ; // Clear Request initialization + + wait_ack = 0; // Wait the acknowledge + while ((wait_ack != CAN_INAK_TimeOut) && ((CANx->MSR & CAN_MSR_INAK) != 0)) + wait_ack++; + if ((CANx->MSR & CAN_MSR_INAK) != 0) + status = CAN_INIT_L_FAILED; + } + return status; +} + +/** + * @brief Deinitializes the CAN peripheral registers to their default reset values. + */ +CAN_STATUS can_deinit(CAN_Port* CANx) +{ + if (CANx == CAN1_BASE) + { + nvic_irq_disable(NVIC_USB_LP_CAN_RX0); // Disable interrupts + nvic_irq_disable(NVIC_CAN_RX1); + nvic_irq_disable(NVIC_USB_HP_CAN_TX); + __asm volatile( "dsb" ); // Synchronization of the pipeline to guarantee + __asm volatile( "isb" ); // that the protection against interrupts is effective + rcc_reset_dev(RCC_CAN); + rcc_clk_disable(RCC_CAN); + can_active = 0; + } + return (status = CAN_OK); +} + +/** + * @brief Initialize CAN registers + */ +/* + * Bits in control parameter: + * CAN_MCR_TTCM time triggered communication mode + * CAN_MCR_ABOM automatic bus-off management + * CAN_MCR_AWUM automatic wake-up mode + * CAN_MCR_NART no automatic retransmission + * CAN_MCR_RFLM receive FIFO locked mode + * CAN_MCR_TXFP transmit FIFO priority + */ +CAN_STATUS can_init(CAN_Port* CANx, uint32 control, uint8 speed) +{ + status = CAN_INIT_FAILED; // default result status + // initialize receive message queue + can_rx_head = can_rx_tail = can_rx_lost = 0; + + rcc_reset_dev(RCC_USB); //! X893 + rcc_clk_disable(RCC_USB); //! X893 + rcc_clk_enable(RCC_AFIO); // enable clocks for AFIO + rcc_clk_enable(RCC_CAN); // and CAN + rcc_reset_dev(RCC_CAN); // reset CAN interface + + can_active = 1; // set CAN active flag (for interrupt handler + + CANx->MCR &= ~CAN_MCR_SLEEP; // reset CAN sleep mode (default after reset) + + if (can_init_enter(CANx) != CAN_OK) // enter CAN initialization mode + return status; // error, so return + + CANx->MCR &= ~CAN_CONTROL_MASK; // set mode bits + CANx->MCR |= (control & CAN_CONTROL_MASK); + + CANx->BTR &= ~CAN_TIMING_MASK; // Set the bit timing register + CANx->BTR |= (can_speed_table[speed].btr & CAN_TIMING_MASK); + + nvic_irq_enable(NVIC_USB_LP_CAN_RX0); // Enable interrupts + nvic_irq_enable(NVIC_CAN_RX1); + + nvic_irq_enable(NVIC_USB_HP_CAN_TX); + + CANx->IER = (CAN_IER_FMPIE0 | CAN_IER_FMPIE1 | CAN_IER_TMEIE); + + if (can_init_leave(CANx) == CAN_OK) + { + while (!(CANx->TSR & CAN_TSR_TME0)); // Transmit mailbox 0 is empty + while (!(CANx->TSR & CAN_TSR_TME1)); // Transmit mailbox 0 is empty + while (!(CANx->TSR & CAN_TSR_TME2)); // Transmit mailbox 0 is empty + } + return status; +} + +/** + * @brief Set timing calues (CAN_BTR) + */ +CAN_STATUS can_set_timing(CAN_Port* CANx, uint32 timing) +{ + if (can_init_enter(CANx) == CAN_OK) + { + CANx->BTR = ((CANx->BTR & ~CAN_TIMING_MASK) | (timing & CAN_TIMING_MASK)); + can_init_leave(CANx); + } + return status; +} + +/** + * @brief Set CAN mode + * @param CANx pointer to CAN port + * @param mode CAN mode + */ +CAN_STATUS can_set_mode(CAN_Port* CANx, uint32 mode) +{ + if (can_init_enter(CANx) == CAN_OK) + { + CANx->BTR &= ~CAN_MODE_MASK; + CANx->BTR |= (mode & CAN_MODE_MASK); + can_init_leave(CANx); + } + return status; +} + +/** + * @brief Set CAN to GPIO mapping + */ +CAN_STATUS can_gpio_map(CAN_Port* CANx, CAN_GPIO_MAP map_mode) +{ + rcc_clk_enable(RCC_AFIO); + + status = CAN_INIT_FAILED; + if( CANx == CAN1_BASE) + { + switch(map_mode) + { + case CAN_GPIO_PB8_PB9: + rcc_clk_enable(RCC_GPIOB); + afio_remap(AFIO_MAPR_CAN_REMAP_PB8_PB9); + gpio_set_mode(GPIOB, 8, GPIO_INPUT_FLOATING); + gpio_set_mode(GPIOB, 9, GPIO_AF_OUTPUT_PP); + break; + case CAN_GPIO_PA11_PA12: + rcc_clk_enable(RCC_GPIOA); + afio_remap(AFIO_MAPR_CAN_REMAP_NONE); + gpio_set_mode(GPIOA, 11, GPIO_INPUT_FLOATING); + gpio_set_mode(GPIOA, 12, GPIO_AF_OUTPUT_PP); + break; +#if NR_GPIO_PORTS >= 4 + case CAN_GPIO_PD0_PD1: + rcc_clk_enable(RCC_GPIOD); + afio_remap(AFIO_MAPR_CAN_REMAP_PD0_PD1); + gpio_set_mode(GPIOD, 0, GPIO_INPUT_FLOATING); + gpio_set_mode(GPIOD, 1, GPIO_AF_OUTPUT_PP); + break; +#endif + default: + return status; + } + status = CAN_OK; + } + return status; +} + +CAN_STATUS can_filter(CAN_Port* CANx, uint8 filter_idx, CAN_FIFO fifo, CAN_FILTER_SCALE scale, CAN_FILTER_MODE mode, uint32 fr1, uint32 fr2, int extID = 0) +{ + uint32 mask = ((uint32)0x00000001) << filter_idx; + + CANx->FMR |= CAN_FMR_FINIT; // Initialization mode for the filter + CANx->FA1R &= ~mask; // Deactivation filter + + + if (scale == CAN_FILTER_32BIT) + CANx->FS1R |= mask; + else + CANx->FS1R &= ~mask; + if (extID) { + CANx->sFilterRegister[filter_idx].FR1 = (fr1 << 3) | CAN_ID_EXT; + CANx->sFilterRegister[filter_idx].FR2 = (fr2 << 3) | CAN_ID_EXT; + } + else { + CANx->sFilterRegister[filter_idx].FR1 = (fr1 << 21); + CANx->sFilterRegister[filter_idx].FR2 = (fr2 << 21); + } + if (mode == CAN_FILTER_MASK) + CANx->FM1R &= ~mask; + else + CANx->FM1R |= mask; + + if (fifo == CAN_FIFO0) + CANx->FFA1R &= ~mask; + else + CANx->FFA1R |= mask; + + CANx->FA1R |= mask; + CANx->FMR &= ~CAN_FMR_FINIT; + return CAN_OK; +} + + +/** + * @brief Initiates the transmission of a message. + * @param CANx: where x can be 1 to select the CAN peripheral. + * @param msg: pointer to a structure which contains CAN Id, CAN DLC and CAN datas. + * @retval : The number of the mailbox that is used for transmission or CAN_NO_MB if there is no empty mailbox. + */ +CAN_TX_MBX can_transmit(CAN_Port* CANx, CanMsg* msg) +{ + CAN_TX_MBX mbx; + uint32 data; + + /* Select one empty transmit mailbox */ + if (CANx->TSR & CAN_TSR_TME0) + mbx = CAN_TX_MBX0; + else if (CANx->TSR & CAN_TSR_TME1) + mbx = CAN_TX_MBX1; + else if (CANx->TSR & CAN_TSR_TME2) + mbx = CAN_TX_MBX2; + else + { + status = CAN_NO_MB; + return CAN_TX_NO_MBX; + } + + /* Set up the Id */ + if (msg->IDE == CAN_ID_STD) + data = (msg->ID << 21); + else + data = (msg->ID << 3) | CAN_ID_EXT; + + data |= ((uint32)msg->RTR); + + /* Set up the DLC */ + CANx->sTxMailBox[mbx].TDTR = (uint32)(msg->DLC & 0x0F); + + /* Set up the data field */ + CANx->sTxMailBox[mbx].TDLR = ( + ((uint32)msg->Data[3] << 24) | + ((uint32)msg->Data[2] << 16) | + ((uint32)msg->Data[1] << 8) | + ((uint32)msg->Data[0]) + ); + CANx->sTxMailBox[mbx].TDHR = ( + ((uint32)msg->Data[7] << 24) | + ((uint32)msg->Data[6] << 16) | + ((uint32)msg->Data[5] << 8) | + ((uint32)msg->Data[4]) + ); + /* Request transmission */ + CANx->sTxMailBox[mbx].TIR = (data | CAN_TMIDxR_TXRQ); + status = CAN_OK; + + return mbx; +} + +/** + * Checks the transmission of a message. + * @param CANx: where x can be 1 to select the CAN peripheral. + * @param mbx: the number of the mailbox that is used for transmission. + * @retval : CAN_TX_OK if the CAN driver transmits the message, CAN_TX_FAILED in an other case. + */ +CAN_STATUS can_tx_status(CAN_Port* CANx, CAN_TX_MBX mbx) +{ + /* RQCP, TXOK and TME bits */ + uint8 state = 0; + + switch (mbx) + { + case CAN_TX_MBX0: + state |= (uint8)((CANx->TSR & CAN_TSR_RQCP0) << 2); + state |= (uint8)((CANx->TSR & CAN_TSR_TXOK0) >> 0); + state |= (uint8)((CANx->TSR & CAN_TSR_TME0) >> 26); + break; + case CAN_TX_MBX1: + state |= (uint8)((CANx->TSR & CAN_TSR_RQCP1) >> 6); + state |= (uint8)((CANx->TSR & CAN_TSR_TXOK1) >> 8); + state |= (uint8)((CANx->TSR & CAN_TSR_TME1) >> 27); + break; + case CAN_TX_MBX2: + state |= (uint8)((CANx->TSR & CAN_TSR_RQCP2) >> 14); + state |= (uint8)((CANx->TSR & CAN_TSR_TXOK2) >> 16); + state |= (uint8)((CANx->TSR & CAN_TSR_TME2) >> 28); + break; + default: + status = CAN_TX_FAILED; + return status; + } + + // state = RQCP TXOK TME + switch (state) + { + /* transmit pending */ + case 0x0: + status = CAN_TX_PENDING; + break; + /* transmit failed */ + case 0x5: + status = CAN_TX_FAILED; + break; + /* transmit succedeed */ + case 0x7: + status = CAN_OK; + break; + default: + status = CAN_TX_FAILED; + break; + } + return status; +} + +/** + * @brief Cancels a transmit request. + * @param CANx: where x can be 1 to select the CAN peripheral. + * @param mbx: Mailbox number. + * @retval : None. + */ +void can_cancel(CAN_Port* CANx, uint8 mbx) +{ + /* abort transmission */ + switch (mbx) + { + case 0: + CANx->TSR |= CAN_TSR_ABRQ0; + break; + case 1: + CANx->TSR |= CAN_TSR_ABRQ1; + break; + case 2: + CANx->TSR |= CAN_TSR_ABRQ2; + break; + default: + break; + } +} + +void can_rx_queue_clear(void) +{ + nvic_irq_disable(NVIC_USB_LP_CAN_RX0); + nvic_irq_disable(NVIC_CAN_RX1); + __asm volatile( "dsb" ); // Synchronization of the pipeline to guarantee + __asm volatile( "isb" ); // that the protection against interrupts is effective + can_rx_head = can_rx_tail = can_rx_lost = 0; // JMD 2017/07/18 + nvic_irq_enable(NVIC_USB_LP_CAN_RX0); + nvic_irq_enable(NVIC_CAN_RX1); +} + +// JMD 2017/07/18 -- changed +uint8 can_rx_available(void) +{ + if ( can_rx_head >= can_rx_tail ) + return can_rx_head - can_rx_tail ; + else + return CAN_RX_QUEUE_SIZE - ( can_rx_tail - can_rx_head ) ; +} + +// JMD 2017/07/18 -- added +uint8 can_frame_lost(void) +{ + if ( can_rx_lost != 0 ) + { + can_rx_lost = 0 ; + return 1 ; + } + return 0 ; + +} + +CanMsg* can_rx_queue_get(void) +{ + if (can_rx_head == can_rx_tail) // JMD 2017/07/18 -- changed + return NULL; + return &(can_rx_queue[can_rx_tail]); +} + + +void can_rx_queue_free(void) +{ + if (can_rx_head != can_rx_tail) // JMD 2017/07/18 -- changed + { + nvic_irq_disable(NVIC_USB_LP_CAN_RX0); // JMD atomicity problem + nvic_irq_disable(NVIC_CAN_RX1); + __asm volatile( "dsb" ); // Synchronization of the pipeline to guarantee + __asm volatile( "isb" ); // that the protection against interrupts is effective + can_rx_tail = (can_rx_tail == (CAN_RX_QUEUE_SIZE - 1)) ? 0 : (can_rx_tail + 1); + nvic_irq_enable(NVIC_USB_LP_CAN_RX0); // fin JMD problème d'atomicité + nvic_irq_enable(NVIC_CAN_RX1); + } +} + +CanMsg* can_read(CAN_Port* CANx, CAN_FIFO fifo, CanMsg* msg) +{ + uint32 data = CANx->sFIFOMailBox[fifo].RIR; + + /* Get the Id */ + if (data & CAN_ID_EXT) + { + msg->ID = 0x1FFFFFFF & (data >> 3); + msg->IDE = (uint8)CAN_ID_EXT; + } + else + { + msg->ID = 0x000007FF & (data >> 21); + msg->IDE = (uint8)CAN_ID_STD; + } + + msg->RTR = (uint8)(CAN_RTR_REMOTE & data); + msg->DLC = (uint8)(0x0F & CANx->sFIFOMailBox[fifo].RDTR); + msg->FMI = (uint8)(0xFF & (CANx->sFIFOMailBox[fifo].RDTR >> 8)); + + /* Get the data field */ + data = CANx->sFIFOMailBox[fifo].RDLR; + uint8* p = msg->Data; + *p++ = (uint8)0xFF & data; + *p++ = (uint8)0xFF & (data >> 8); + *p++ = (uint8)0xFF & (data >> 16); + *p++ = (uint8)0xFF & (data >> 24); + + data = CANx->sFIFOMailBox[fifo].RDHR; + *p++ = (uint8)0xFF & data; + *p++ = (uint8)0xFF & (data >> 8); + *p++ = (uint8)0xFF & (data >> 16); + *p++ = (uint8)0xFF & (data >> 24); + + return msg; +} + +void can_rx_release(CAN_Port* CANx, CAN_FIFO fifo) +{ + if (fifo == CAN_FIFO0) + CANx->RF0R |= (CAN_RF0R_RFOM0); // Release FIFO0 + else + CANx->RF1R |= (CAN_RF1R_RFOM1); // Release FIFO1 +} + +void can_rx_read(CAN_Port* CANx, CAN_FIFO fifo) +{ + if (can_rx_available() < CAN_RX_QUEUE_SIZE) // read the message + { + CanMsg* msg = &can_rx_queue[can_rx_head]; + can_read(CANx, fifo, msg); + can_rx_head = (can_rx_head == (CAN_RX_QUEUE_SIZE - 1)) ? 0 : (can_rx_head + 1); + } + else + can_rx_lost = 1; // no place in queue, ignore package + + can_rx_release(CANx, fifo); +} + +uint8 CAN_RX0_IRQ_Handler(void) +{ + if (can_active) + { + while ((CAN1_BASE->RF0R & CAN_RF0R_FMP0) != 0) + can_rx_read(CAN1_BASE, CAN_FIFO0); // message pending FIFO0 + while ((CAN1_BASE->RF1R & CAN_RF1R_FMP1) != 0) + can_rx_read(CAN1_BASE, CAN_FIFO1); // message pending FIFO1 + } + return can_active; // return CAN active flag to USB handler +} + +// Addition JMD: the messages stored in fifo1 must also trigger an interrupt. +void __irq_can_rx1(void) +{ + CAN_RX0_IRQ_Handler() ; +} + +void USB_HP_CAN_TX_IRQHandler (void) +{ + if (can_active) + { + if (CAN1_BASE->TSR & CAN_TSR_RQCP0) + CAN1_BASE->TSR |= CAN_TSR_RQCP0; // reset request complete mbx 0 + if (CAN1_BASE->TSR & CAN_TSR_RQCP1) + CAN1_BASE->TSR |= CAN_TSR_RQCP1; // reset request complete mbx 1 + if (CAN1_BASE->TSR & CAN_TSR_RQCP2) + CAN1_BASE->TSR |= CAN_TSR_RQCP2; // reset request complete mbx 2 + } +}