Last time, I used 10MHz SPI LED driver chip with low end 4MHz microcontroller. Design priority was cost efficiency. Microcontroller cost less than a dollar but it had enough flash to store the firmware and a few display fonts. At first, I used interrupt and circular buffers to send and receive to and from SPI bus. I just wrote to the buffer and let the hardware and interrupt handled all the communication tasks as I usually do with slower long distance buses such as RS232 and CAN bus. It was OK in normal condition. The problem was that I wanted to update big 96x16 dot-matrix LED at the frame rate of 125Hz and the CPU utilization was very high. Consequently, it could not perform fast enough when it was executing some simple graphic manipulation tasks such as scrolling the text. Later, I realized that the most used SPI function where CPU spent most of its time was not efficient. Using hardware interrupt is more efficient normally, but it was different in this case- slow CPU with very fast and heavily used SPI. For each byte to SPI, send and receive interrupt functions which cost a lot of CPU cycles had to be performed. I found polling or emulation is faster than using interrupt to send a byte to SPI. Polling is still limited to the bus speeds supported by the hardware. After I modified the firmware to improve SPI function and it worked well. According to my experience, let me highlight some advantages of emulating SPI .
- It can sometimes be better in performance to emulate SPI in software.
- It is more reliable because it is simpler and it can avoid potential pitfalls of using interrupt.
- It is faster, easier and less error prone to write a simple code rather than reading datasheet for variety of register settings for every new microcontroller you encountered.
- Most importantly, it is portable and it is not dependent on hardware.
//------------------------------------- unsigned char spi(unsigned char d) { unsigned char i; SCLK=1; EN=1; for(i=0;i<8;i++) { MOSI=(d & 0x80)?1:0; //Delay(period/2)-optional for slower SPI bus speed SCLK=0; d<<=1; d|=MISO; //Delay(period/2)-optional for slower SPI bus speed SCLK=1; } EN=0; return d; } //-------------------------------------