The Educational BoosterPack MK II, the Texas Instruments kit with loads of goodies. Who hasn't seen it? I have one. And I have plans with it. I want to turn it into the user interface for a safety features test bed for Hercules micro controllers.
I finished the last blog rather abruptly. I ported the essentials of Rei VILO's LCD_screen Library Suite to Hercules. But it wasn't working. My claim then was that the port was correct but the screen wasn't reacting... |
Getting it Working
... and I was almost right. I didn't have a bug in my port. But I didn't configure the SPI module correctly.
There are 4 SPI modes (commonly known as mode 0 -> 3 - you may recognize that from the Arduino SPISetDataMode() method)
In the Energia library for the LCD screen, this mode is set explicitly:
SPI.setDataMode(SPI_MODE0);
When I ported the SPI setup, I mis-mapped the mode 0 in the configuration tool.
In mode 0, the clock is inactive when high. So I had to set the clock parity check box to have the SPI module generate the clock that way.
And that was it. Just checking this box made the firmware work. It sounds easy with hindsight.
But it took me significant time debugging, documenting and analyzing the traffic. The issue doesn't show up when you're sending one word.
Setting up SPI Communication
The configuration of the SPI module happens in HALCoGen, the Hardware Abstraction Layer Code Generator.
You activate the SPI driver (I used MIBSPI, the buffered implementation of SPI - I have plans later ).
Don't forget to also select the multiplex for the MIBSPI3 MOSI, CS2 and SCK signals in the PINMUX form.
Then we set up the SPI3 peripheral. We're going to have 8-bit and 16-bit traffic, so I configured one format for each of them.
This is also the place where you define baud rate and that dreaded clock polarity. Our LCD uses MSB first, so I left the LSB box alone.
These data formats are later used in the SPI transfer groups. These groups say how many bytes we're buffering.
I know it's silly now. I'm buffering one value. This doesn't make sense.
But later on, when we want super fast screen blanking, bitmap loading and buffer swapping, it 'll come to good use.
You can see that it's in the transfer group where you define what CS pin is used, and how all the buffering behaves.
The Data Format selection links the data formats that we have set up in the previous step with our transfer groups.
The transfer groups are core to the mibspi api. Whenever you do buffered spi, you tell the api where the buffer is, and what transfer group should handle the transfer.
You can enable advanced functionality like DMA and interrupts. I may implement them later if it makes sense.
Our last step is to make the relevant SPI pins functional (they can act as GIO pins if you don't use them for SPI)
In our case, we don't need to make Slave Out Master In functional, because the LCD doesn't talk back.
HALCoGen creates the code to set up the SPI registers (the abstraction layer isn't heavy - it takes care that registers are correctly primed, and provides the source for a thin functional api).
I'll only use four of those api functions.
at the start of the program:
mibspiInit(); // sets up the registers according to the settings in HALCoGen
and for each data exchange:
mibspiSetData(); // tell the api where our data sits mibspiTransfer(); // buffered spi transfer mibspiIsTransferComplete(); // polls if the buffered transfer has finished - we could as well use an interrupt approach for that.
It's in those three last functions that the transfer groups are used.
Here's an example where I use transfer group 1 for 16-bit exchange. You see the commented lines from the original Energia library.
void _writeData16(uint16_t data16) { gioSetBit(_portDataCommand, _pinDataCommand, 1); // drive the D/nC signal high to tell the LCD we're sending data mibspiSetData(mibspiREG3, 1, &data16); /* - start the mibspi transfer tg 1 */ mibspiTransfer(mibspiREG3, 1 ); /* ... wait until transfer complete */ while(!(mibspiIsTransferComplete(mibspiREG3, 1))) { } }
The analyzer output below is the output of the function that was giving me issues in the previous blog:
_writeData88(0x0A, 0x14);
The protocol analyzer shows us this:
The screen image below is created with three lines of code.
clear(orangeColour); line(0, screenSizeY()-1, screenSizeX()-1, 0, blueColour); line(0, 0, screenSizeX()-1, screenSizeY()-1, blueColour);
All good - and the LCD listens. My base line is set.
I have the Educational BoosterPack's display running on the Hercules LaunchPad.
I'll now broaden the port exercise. I'll cherry pick the graphical functions that I need (specificly: fonts) and blatantly steal them from the Energia lib.
(edit April 15 2016: fonts are working. )
WIP Source |
---|
While I'm developing the initial port, I've created a GIST repo to have some kind of version control. You can check out the library there: https://gist.github.com/jancumps/4144fbd5a19e827be5d693eeb7a1e5bf
When things mature - and I have a better idea of how to structure the project - I create a proper Github repo and integrate my Code Composer Studio with that. I know GIT is perfectly able of restructuring, but I am not an expert of using the version control system when changing folder structures and file names. That's my old CVS habits kicking in.
The library sources are available from my GitHub repository: https://github.com/jancumps/hercules_libraries/tree/master/lcd_hx8353e/HX8353E |
Related Blog |
---|
Educational BoosterPack and Hercules LaunchPad: LCD Driver - Part 1 |
Part 2: Logic Analyzer and LCD Backlight |
Part 3: SPI Works |
Part 4: Everything Works |
Top Comments