Awesome.
Yup. The code that refreshes the display is quite possibly the best candidate for optimization in the entire system. It will probably run more than a thousand times per second.
Peter Loron:
I would really appreciate it if you could elaborate on your suggestion of using the SPI hardware instead of the current bit-banging I’m doing. [This page on the Arduino site discusses some direct register pokes to more quickly manipulate the pins.[/quote]
Step one is to read the SPI section in the '168 datasheet. It’s section 18 in my copy. You’ll want to use it in master mode. You probably want CPHA=1 and CPOL=0 (SPI Mode 1), but you should verify that. Whether it’s lsb-first or msb-first (DORD) is going to be dictated by how the display maps pixels and columns. One way will likely produce a venetian blind effect when lighting progressive bit positions, and the other way will likely produce the expected linear progression. Short of tracing out which driver chip pin goes to which display grid, one is left with experimentation. Fortunately, there are only two possibilities ffor DORD.
Once it is set up, the SPI hardware behaves a lot like the USART. Write a byte to SPDR to send it out of the interface (to your display). Wait for notification that the byte has finished being sent before sending the next one. Depending on how fast you run the SPI and how much work you have to do to get the next byte to send, you might not even have to wait. Still, it’s good to check; particularly when getting things working. Hopefully, this is all happening fast enough that you don’t have to enable and service the SPI interrupt; you’d just poll the SPIF bit in SPSR.
How fast you run the SPI is going to depend on things like the specs of the display board and the cabling to it. Start slow (f[OSC]/128) to get things working and then crank it up until you start seeing errors in the communication (and then back off). One of the things that the SPI hardware gets you is bit timing (the reason you have two 1us pauses in your code). The hardware does that for you. You just have to wait for 8 bits to be done so you can hand it the next 8, and you can be preparing the next 8 while you’re waiting. Each column refresh is going to consist of around 9 bytes of bitmap data and another 2.5 bytes indicating which column is active.
2.5? Yes. 20 bits. The whole bitstream is 92 bits, which does not yield an integer when divided by 8. The first byte you shift out will contain 4 bits which will be ignored. They will fall off the end of the shift chain. That will yield 96 bits, which is 12 bytes, even. If you want, you can do what I did and use those 4 wasted bits, which still appear in the bitmap data in RAM, for things like character attributes. Though, on this display, they’d probably be more like column attributes. If it helps, you can pretend those other documents say to shift out 4 zero bits before the bitmap data, just like it says to shift out two afterward.
For maximum speed, the writing of 12 bytes of data to the SPI should be done step-by-step instead of in a finite state machine or other loop. There’s nothing wrong with those mechanisms. We’re just optimizing the heck out of the display refresh routine, and the loop tests and branches take time.
Remember, you’ll probably be in interrupt space here (refreshing column in response to timer rollover), so any dawdling (including waiting for SPI transfers to finish) takes time away from the rest of the system. When testing with low SPI speeds, make sure the column refresh timer has a period long enough that the ISR can actually complete. If it is too short, the machine will spend all of its time servicing the interrupt and none of it doing other things, such as updating the bitmap data.
You don’t need to worry about MISO unless you want to read back the ID byte (when the EN line of the display is high). If you want to do that, you have to temporarily change MOSI to an input to keep it from fighting with the data output by the display.
Peter Loron:
Now I just need to cobble together some character maps for a lookup table.
Oh yeah, that’s fun. Well, not really. I usually end up throwing together some sort of Perl script. Such a script tends to take an input file full of # and space characters (graphically laying out the lit and unlit pixels) and make the lists of numbers for me. Choice of language is unimportant, of course. You’re probably going to want to create two character sets. One for the top row and one for the bottom row. That’s an implementation detail, of course, but it will make things go faster at runtime. One set is shifted a certain number of bits from the other one. This is because each character cell takes 35 bits, which is not a multiple of 8. You could use just one character map and do the shifting every time you print a character in the second row, but it is faster to just have the work done ahead of time in a second map
Peter Loron:
Thanks again!
-Pete
You’re welcome.](Arduino Reference - Arduino Reference)