diff --git a/drivers/include/drivers/RawCAN.h b/drivers/include/drivers/RawCAN.h index 158c5c58c4..eac460e802 100644 --- a/drivers/include/drivers/RawCAN.h +++ b/drivers/include/drivers/RawCAN.h @@ -31,6 +31,53 @@ namespace mbed { class RawCAN: public CAN { public: + /** Creates an unlocked CAN interface connected to specific pins. + * + * @param rd read from transmitter + * @param td transmit to transmitter + * + * Example: + * @code + * #include "mbed.h" + * + * + * Ticker ticker; + * DigitalOut led1(LED1); + * DigitalOut led2(LED2); + * //The constructor takes in RX, and TX pin respectively. + * //These pins, for this example, are defined in mbed_app.json + * RawCAN can1(MBED_CONF_APP_CAN1_RD, MBED_CONF_APP_CAN1_TD); + * RawCAN can2(MBED_CONF_APP_CAN2_RD, MBED_CONF_APP_CAN2_TD); + * + * unsigned char counter = 0; + * + * void send() { + * if(can1.write(CANMessage(1337U, &counter, 1))) { + * printf("Message sent: %d\n", counter); + * counter++; + * } + * led1 = !led1; + * } + * + * int main() { + * ticker.attach(&send, 1); + * CANMessage msg; + * while(1) { + * if(can2.read(msg)) { + * printf("Message received: %d\n\n", msg.data[0]); + * led2 = !led2; + * } + * ThisThread::sleep_for(200); + * } + * } + * + * @endcode + */ + + /* Note: The can apis are unlocked hence using this when multiple + * threads are accessing a single instance of CAN will lead to + * race conditions, can be used in single threaded CAN. + */ using CAN::CAN; diff --git a/targets/TARGET_STM/README.md b/targets/TARGET_STM/README.md index 245a93f666..447d0ba675 100644 --- a/targets/TARGET_STM/README.md +++ b/targets/TARGET_STM/README.md @@ -470,6 +470,63 @@ For application that require optimized maximum performance, the recommendation i The SPI DMA transfer support shall be implemented on a case-by-case based on below example https://github.com/ABOSTM/mbed-os/tree/I2C_SPI_DMA_IMPLEMENTATION_FOR_STM32L4 +### CAN receive interrupt problem due to mutex and resolution + +In bxCAN and earlier versions the receive interrupt flags can be cleared only on performing a read operation in ST MCUs +But can_read() cannot be used in interrupt context as it is gaurded by lock operation and mbed does not allow locks in +interrupt context. Hence the Rx interrupt is disabled for a while and read is deferred to thread context, the interrupt is +enabled on a successful read. + +As an other option RawCAN (with unlocked CAN apis) is also available and can be used directly, if only one thread is accessing +the CAN interface. + +While using RxInterrupt with the CAN object the receive ISR callback registered should defer read to thread context. +A simple example is as shown below: + +#include "mbed.h" + +Ticker ticker; +Thread canReadThread; + +DigitalOut led1(LED1); +DigitalOut led2(LED2); +DigitalOut led3(LED3); + +CAN can1(PD_0 ,PD_1); + +EventQueue queue(32 * EVENTS_EVENT_SIZE); + +int counter = 0xABCD; +CANMessage msg; + +void canRead(){ + if(can1.read(msg)) { + if(msg.id==1100) + led2 = !led2; + if(msg.id==1102){ + led3 = !led3; + } + } +} + +void canISR(){ + queue.call(canRead); + led3 = !led3; +} + +int main() { + + can1.frequency(100000); + can1.mode(CAN::Normal); + + can1.attach(canISR, CAN::RxIrq); + + canReadThread.start(callback(&queue, &EventQueue::dispatch_forever)); + + while(1) { + } +} + ## Mbed OS Wiki pages diff --git a/targets/TARGET_STM/can_api.c b/targets/TARGET_STM/can_api.c index 01f27ebede..44995dcc23 100644 --- a/targets/TARGET_STM/can_api.c +++ b/targets/TARGET_STM/can_api.c @@ -1187,6 +1187,7 @@ static void can_irq(CANName name, int id) // In legacy can (bxCAN and earlier), reading is the only way to clear rx interrupt. But can_read has mutex locks // since mutexes cannot be used in ISR context, rx interrupt is masked here to temporary disable it // rx interrupts will be unamsked in read operation. reads must be deffered to thread context. + // refer to the CAN receive interrupt problem due to mutex and resolution section of README doc. __HAL_CAN_DISABLE_IT(&CanHandle, CAN_IT_FMP0); if ((tmp1 != 0) && tmp2) {