Not getting stuck

Thread Starter

Ian0

Joined Aug 7, 2020
13,131
I have a routine that writes to an LCD display using the processor's SPI peripheral. It writes a databyte to the SPI transmit register then loops until a flag in the status register is set.
Sometimes the display stops working and I look at the debugger probe and find that it is still waiting for the status register flag.

I learned software in the days when all data i/o routines were bit-banging routines written in assembler. As my processor isn't doing anything useful while the SPI data gets sent, would I be better off with a bit-banging routine? It seemed to me that arranging a counter to detect if the flag was not set in a timely fashion seemed a lot more complicated to implement. Or is there a better way?
 

nsaspook

Joined Aug 27, 2009
16,321
I have a routine that writes to an LCD display using the processor's SPI peripheral. It writes a databyte to the SPI transmit register then loops until a flag in the status register is set.
Sometimes the display stops working and I look at the debugger probe and find that it is still waiting for the status register flag.

I learned software in the days when all data i/o routines were bit-banging routines written in assembler. As my processor isn't doing anything useful while the SPI data gets sent, would I be better off with a bit-banging routine? It seemed to me that arranging a counter to detect if the flag was not set in a timely fashion seemed a lot more complicated to implement. Or is there a better way?
First, fix the status register polling bug. Bit-banging when you have good hardware is IMO a waste of resources.

I generally use DMA with SPI for LCD display updates as it allows (even if there is nothing useful happening) for possible concurrent processing during the update background process. You have an interrupt when the DMA operation is complete to set LCD 'done' flags or other types of display processing functions. A transmit only DMA LCD setup is usually fairly easy and you normally only need to write it once if you abstract the hardware I/O to machine specific routines.
 

Thread Starter

Ian0

Joined Aug 7, 2020
13,131
First, fix the status register polling bug. Bit-banging when you have good hardware is IMO a waste of resources.

I generally use DMA with SPI for LCD display updates as it allows (even if there is nothing useful happening) for possible concurrent processing during the update background process. You have an interrupt when the DMA operation is complete to set LCD 'done' flags or other types of display processing functions. A transmit only DMA LCD setup is usually fairly easy and you normally only need to write it once if you abstract the hardware I/O to machine specific routines.
The LCD is doing text and area fills, rather than images, so isn't needing vast amounts of data.
This is my first micro (in 30+ years of programming) that has DMA. Without this conversation, I would have probably never looked into it - I'll RTFM and see what it can do.
The polling bug refuses to show up to order. When it does raise its ugly head, I should look at some of the other SPI settings to see why it's not responding. Bugs that show up to order don't remain bugs for long!

I thought the same as you about bit-banging, but it crossed my mind that if the processor were executing while(1) as the SPI outputs data, then the processor might as well be outputting data and the SPI could stop consuming power (not that the application is power criticial). But if the processor is executing WFI then the argument doesn't hold.

While the LCD is doing text and area fills it periodically has to have its BUSY flag checked, so DMA might not work.
 

nsaspook

Joined Aug 27, 2009
16,321
The LCD is doing text and area fills, rather than images, so isn't needing vast amounts of data.
This is my first micro (in 30+ years of programming) that has DMA. Without this conversation, I would have probably never looked into it - I'll RTFM and see what it can do.
The polling bug refuses to show up to order. When it does raise its ugly head, I should look at some of the other SPI settings to see why it's not responding. Bugs that show up to order don't remain bugs for long!

I thought the same as you about bit-banging, but it crossed my mind that if the processor were executing while(1) as the SPI outputs data, then the processor might as well be outputting data and the SPI could stop consuming power (not that the application is power criticial). But if the processor is executing WFI then the argument doesn't hold.

While the LCD is doing text and area fills it periodically has to have its BUSY flag checked, so DMA might not work.
I feel your pain. Is there some sort of SPI errata for the chip?


I set and reset a C boolean volatile BUSY variable. The LCD routines set the BUSY and the DMA complete interrupt ISR clears the BUSY. I have routines that check the BUSY flag and wait if needed.

Some example LCD DMA routines for a PIC18f57k42. It's part of a general LCD lib for 8-bit controllers with DMA.

C:
    struct spi_link_type { // internal SPI state table
        uint8_t SPI_LCD : 1;
        uint8_t SPI_AUX : 1;
        uint8_t LCD_TIMER : 1;
        volatile uint8_t LCD_DATA : 1;
        uint16_t delay;
        uint8_t config;
        uint8_t * txbuf;
        volatile int32_t int_count;
    };

struct spi_link_type spi_link;

DMA1_SetSCNTIInterruptHandler(clear_lcd_done);

/*
* Trigger the SPI DMA transfer to the LCD display
*/
void start_lcd(void)
{
#ifdef USE_LCD_DMA
    DMA1_StartTransferWithTrigger();
#endif

}

/*
* in DMA mode this is a ISR that runs when the source count is complete
*/
void clear_lcd_done(void)
{
    spi_link.LCD_DATA = false;
}

/*
* some LCD flag routines
*/

void wait_lcd_set(void)
{
    spi_link.LCD_DATA = true;
}

bool wait_lcd_check(void)
{
    return spi_link.LCD_DATA;
}

void wait_lcd_done(void)
{
#ifdef USE_LCD_DMA
    while (spi_link.LCD_DATA) {
    };

    while (!SPI1STATUSbits.TXBE) {
    };

#endif
}
C:
/*
* send three byte command string via DMA
*/
void send_lcd_pos_dma(const uint8_t strPtr)
{
    wait_lcd_done();
    wait_lcd_set();
    CSB_SetLow(); /* SPI select display */
    spi_link.txbuf[0] = NHD_CMD;
    spi_link.txbuf[1] = NHD_POS;
    spi_link.txbuf[2] = strPtr;
    DMA1CON0bits.EN = 0; /* disable DMA to change source count */
    DMA1_SetSourceSize(3);
    DMA1_SetDestinationSize(1);
    DMA1CON0bits.EN = 1; /* enable DMA */
    start_lcd(); // start DMA transfer
}
 

Thread Starter

Ian0

Joined Aug 7, 2020
13,131
I feel your pain. Is there some sort of SPI errata for the chip?
Another place I didn't check.


Renesas's SPI doesn't handle the CS pin very well. All it can do is assert and negate the pin every byte. If you need CS to stay asserted for the entire transaction, then addressing the pin directly as GPIO is the only way to go.
My suspicion is that somewhere in the CS disabling process rather too much SPI got disabled. Then it wouldn't respond to a poll! But I haven't seen the bug yet.
 
Top