SPI
I worked a bit on the SPI interface last night between the PI Zero W and the dsPIC33. The PI SPI interface really only supports being the master, so I am using a GPIO from the dsPIC to tell the PI if there is data waiting. In the PI world the default IOCTL interface to the SPI means a kernel call for every byte transfered. Using that method with a 1MHZ SPI clock I was getting an effective transfer rate of around 400Kbit, and even when jumping the SPI clock to 5MHz the effective rate was still less than 1mbit due to the calling overhead. Going direct to the memory mapped peripherals made a big difference, and now I can run as high at 62MHz SPI speed with an effective rate of 8.5mbit, which isn’t bad from a user mode application in a non realtime OS linux platform.
On the dsPIC side I started with a simple interrupt handler doing single byte transfers but that started to have overflow errors once I got above 2MHz. This dsPIC has a 8-byte FIFO in the SPI channel, so I enabled that with an ‘interrupt on FIFO half full’ method. That allowed me to scale up to as fast as I could get the PI to transmit without any overruns. You can see that in the worst case I read 12 bytes from the FIFO during a single interrupt callback, indicating it was filling at close to the draining rate as the interrupt starts when the FIFO is at 4.
I did have one ‘dumb’ moment where I was getting overflows at even moderate rates, but when I logged the fill level of the FIFO it was never over half full. It turns out I had the priority of the UART interrupts higher than the SPI ones, so the printfs to the console for debugging were causing the drops. 😉
An effective 8.5mbit transfer rate will work great for this application as two fully loaded CAN buses will not be over 2mbit, which leaves plenty of overhead space. I plan on doing the bus-to-bus relaying on the dsPIC anyways, so in most cases all of the traffic doesn’t have to be sent to the PI, except in the case of wanting to log both busses at full speed.