I’m working with a PIC32 and MCP2515 SPI based CAN controller and trying to come up with an elegant way of dealing with the asynchronous nature of CAN messages that require multi-byte SPI transactions.
The scenario is that the application is in the middle of sending a string of bytes representing a CAN message through the SPI hardware to the MCP2515.
On PIC18’s and non-RTOS environments I disable the MCP interrupt and use the SPI interrupt to transfer the data or even just sit inside the interrupt routine polling and sending bytes.
With FreeRTOS a CANBus task will determine when to send a message. Usually on a timer event or some other event. The message will get placed onto a Q for the SPI task which is pending on the Q waiting for a message. So far easy.
The SPI task selects the correct SPI device and sets up a Tx Q with the string of bytes to transmit. After that the SPI TxBuffer Empty interrupt will empty out the Tx Q and flag a semaphore that the message is done. The SPI task is waiting on that semaphore and once it’s received it will look for another message.
However it’s possible the MCP2515 can assert a hardware interrupt while the SPI task is in the process of starting to send or sending a message. That interrupt could be for bus errors, transmit message complete or a message has arrived.
Inside the interrupt routine I’m faced with the same issue. I can’t just look at a memory location to determine the cause of the interrupt. I have to send a couple of bytes to read the status register. Ideally that should also occur under interrupt and once the second byte has been received pass that to the original MCP2515 interrupt handler.
Confused? That’s just the status byte. It could also be that the MCP2515 interrupt handler has request a read of 13 bytes for a full CAN message. Or it has to send a couple of bytes to disable further transmit empty interrupts.
SPI clock rate can be up to 10Mhz but at the moment I’m running 2Mbps so each byte requires 4 uS. It seems the simple solution is to forget there’s an RTOS and prevent the MCP2515 interrupts while sending to the device.