Hardware: 430BOOST-SHARP96 BoosterPack
MSP‐EXP432P401R LaunchPad
Software: 430BOOST-SHARP96_GrlibExample_MSP432P401R
In the process of modifying the MSP432 Grlib example code to draw a bar graph on the Sharp 96x96 LCD screen last week I ran into a problem: LCD updates didn't always work as expected. Often the Graphics_flushBuffer() routine would draw what I expected, but occasionally it would draw part of the screen and then stop. Here's what I expected to see at one point, for example -- text and a "black" (reflective) rectangle on a white background:
and here are some snapshot of what actually appeared:
Over the weekend I managed -- with a great deal of assistance from my brother Bruce -- to isolate what was causing all this ugly output. It turned out to be a problem with the Timer_A1 interrupt handler code which was (properly) attempting keep reversing the LCD screen voltage by issuing an SPI NOP+VCOM_Invert command to the Sharp LS013B4DN04 LCD chip. Unfortunately, when it did so, it was (very improperly) forgetting to check whether anyone else was using the SPI bus.
Every time this occurred, the SPI screen update initiated by Graphics_flushBuffer() got cut short, with results like those above. ( At this point all the test runs I made over the weekend to try to isolate the problem are all running together, but I believe that in some cases the problem persisted, that is, subsequent Graphics_flushBuffer() calls had no further effect on the display. I don't know whether this was an SPI bus lockup, an LCD lockup, or the proverbial Something Completely Different. )
Here's the code in that project's main.c file:
//------------------------------------------------------------------------------
// Timer A0 Interrupt Service Routine
//------------------------------------------------------------------------------
void TimerA1_0IsrHandler(void)
{
Sharp96x96_SendToggleVCOMCommand();
...
The problem with this -- as Bruce finally managed to pound into my thick sk... er, politely pointed out to me -- isn't so much that a few screen update bytes get overwritten by the VCOM_Invert command, it's that after the SPI write code invoked by Sharp96x96_SendToggleVCOMCommand() sends its two bytes, it then unilaterally sets CS LOW, which tells the LCD it's no longer needed. Then the interrupt handler exits, at which point the suspended SPI-write-in-progress tries to continue, but the LCD has just been told to cover its ears and stop listening. With -- as they say -- "unpredictable results". <grin>
Here's the latest iteration of my workaround code:
//------------------------------------------------------------------------------
// Timer A0 Interrupt Service Routine
//------------------------------------------------------------------------------
// Must match Sharp96x96.c pins
#define LCD_SPI_CS_PIN_PORT P4OUT // GPIO_PORT_P4
#define LCD_SPI_CS_PIN (1<<3) // GPIO_PIN3
volatile uint32_t spi_collision_count = 0;
void TimerA1_0IsrHandler(void)
{
// See if bus is active so we don't mash on activity in progress
// Note: Testing UCBUSY is NOT sufficient.
if ( !(LCD_SPI_CS_PIN_PORT & LCD_SPI_CS_PIN) ) { // If SPI bus is free
Sharp96x96_SendToggleVCOMCommand(); // issue VCOM_Invert cmd
} else { // else
spi_collision_count++; // log and avoid
}
There is also something a bit odd in the way the Timer_A1 count register gets updated inside the handler -- it feels more appropriate for Continuous Mode rather than Up Mode -- but fixing that doesn't seem to be required to get clean screen updates; it only means that VCOM_Invert gets issued a lot more than necessary.
FYI, this code appears to be a direct port of project 430BOOST-SHARP96_GrlibExample_G2. Based on a quick glance at that project's main.c file, it appears that the G2 version has the same problem.
Oh, and if anyone is curious about why Sharp96x96_SendToggleVCOMCommand() is needed, there is a detailed description of this in the "VCOM Inversion" section of the Sharp LS013B4DN04 Memory LCD Application Note.
I hope this post saves someone else a few hours of head-scratching. <grin>
Now, what was I doing when... Oh. Right. I was trying to draw a bar graph...
Frank McKenney