HC32F460填坑 - SPI POLLING SEND

文章目录[隐藏]

目前,小一点的系统很流行SPI接口的显示屏,有黑白TN,有彩色TFT,有高对比OLED,显示分辨率从3296到320240不等,这些显示屏成本低,接口少,易于驱动,所以非常受欢迎

硬件连线通常有以下:
复位RESET,片选CS,地址A0,时钟SCK,数据SDI,背光正负,电源正负,可以做到10PIN以内

因为显示屏的SPI在某些TIMING上会有一些要求,所以片选CS通常使用GPIO模拟,另外RESET,A0也是GPIO,SCK,SDI会使用硬件SPI,达到比较高的传输速率(50MHZ)


这是MCU驱动SPI显示屏的时序图,CS选中器件,DC(A0)决定写指令还是写参数,如果当前BYTE传输期间A0是LOW,表示写指令,如果A0是HIGH,表示写参数,传输完成后,CS再拉高

#include "board.h"


#define LCDCODE_REGFLAG_DELAY       0xFFFE
#define LCDCODE_REGFLAG_END         0xFFFF
#define LCDCODE_DATA_LEN            32

typedef struct
{
    uint16_t reg;
    uint16_t len;
    uint8_t  dat[LCDCODE_DATA_LEN];
}lcd_code_t;

static struct rt_semaphore spi3_tx_wait = {0x00};

static void spi3_tx_dma_tc0_irq_cb(void)
{
    DMA_ClearIrqFlag(SPI3_DMA_UNIT, SPI3_DMA_TX_CHANNEL, TrnCpltIrq);
    rt_sem_release(&spi3_tx_wait);
}

static void spi3_dma_config(void)
{
    stc_dma_config_t stcDmaCfg;
    stc_irq_regi_conf_t stcIrqRegiConf;

    /* configuration structure initialization */
    MEM_ZERO_STRUCT(stcDmaCfg);

    /* Configuration peripheral clock */
    PWC_Fcg0PeriphClockCmd(SPI3_DMA_CLOCK_UNIT, Enable);
    PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_AOS, Enable);
    
    /* Configure TX DMA */
    stcDmaCfg.u16BlockSize           = 1u;
    stcDmaCfg.u16TransferCnt         = 128;
    stcDmaCfg.u32SrcAddr             = (uint32_t)(0);
    stcDmaCfg.u32DesAddr             = (uint32_t)(&SPI3_UNIT->DR);
    stcDmaCfg.stcDmaChCfg.enSrcInc   = AddressIncrease;
    stcDmaCfg.stcDmaChCfg.enDesInc   = AddressFix;
    stcDmaCfg.stcDmaChCfg.enTrnWidth = Dma8Bit;
    stcDmaCfg.stcDmaChCfg.enIntEn    = Enable;
    DMA_InitChannel(SPI3_DMA_UNIT, SPI3_DMA_TX_CHANNEL, &stcDmaCfg);
    DMA_SetTriggerSrc(SPI3_DMA_UNIT, SPI3_DMA_TX_CHANNEL, SPI3_DMA_TX_TRIG_SOURCE);

    /* Enable DMA. */
    DMA_Cmd(SPI3_DMA_UNIT, Enable);

   /* Set DMA block transfer complete IRQ */
    stcIrqRegiConf.enIRQn      = IRQ_SPI3_DMA_TX;
    stcIrqRegiConf.pfnCallback = &spi3_tx_dma_tc0_irq_cb;
    stcIrqRegiConf.enIntSrc    = INT_DMA1_TC0;
    enIrqRegistration(&stcIrqRegiConf);
    
    NVIC_SetPriority(stcIrqRegiConf.enIRQn, IRQ_PRIORITY_SPI3_DMA_TX);
    NVIC_ClearPendingIRQ(stcIrqRegiConf.enIRQn);
    NVIC_EnableIRQ(stcIrqRegiConf.enIRQn);
}

static void bsp_spi3_init(void)
{
    stc_spi_init_t stcSpiInit;

    /* configuration structure initialization */
    MEM_ZERO_STRUCT(stcSpiInit);

    /* Configuration peripheral clock */
    PWC_Fcg1PeriphClockCmd(SPI3_UNIT_CLOCK, Enable);
    
    /* Configuration SPI structure */
    stcSpiInit.enClkDiv                 = SpiClkDiv32;
    stcSpiInit.enFrameNumber            = SpiFrameNumber1;
    stcSpiInit.enDataLength             = SpiDataLengthBit8;
    stcSpiInit.enFirstBitPosition       = SpiFirstBitPositionMSB;
    stcSpiInit.enSckPolarity            = SpiSckIdleLevelLow;
    stcSpiInit.enSckPhase               = SpiSckOddSampleEvenChange;
    stcSpiInit.enReadBufferObject       = SpiReadReceiverBuffer;
    stcSpiInit.enWorkMode               = SpiWorkMode3Line;
    stcSpiInit.enTransMode              = SpiTransOnlySend;
    stcSpiInit.enCommAutoSuspendEn      = Disable;
    stcSpiInit.enModeFaultErrorDetectEn = Disable;
    stcSpiInit.enParitySelfDetectEn     = Disable;
    stcSpiInit.enParityEn               = Disable;
    stcSpiInit.enParity                 = SpiParityEven;

    stcSpiInit.enMasterSlaveMode = SpiModeMaster;
    stcSpiInit.stcDelayConfig.enSsSetupDelayOption   = SpiSsSetupDelayCustomValue;
    stcSpiInit.stcDelayConfig.enSsSetupDelayTime     = SpiSsSetupDelaySck1;
    stcSpiInit.stcDelayConfig.enSsHoldDelayOption    = SpiSsHoldDelayCustomValue;
    stcSpiInit.stcDelayConfig.enSsHoldDelayTime      = SpiSsHoldDelaySck1;
    stcSpiInit.stcDelayConfig.enSsIntervalTimeOption = SpiSsIntervalCustomValue;
    stcSpiInit.stcDelayConfig.enSsIntervalTime       = SpiSsIntervalSck1PlusPck2;
    SPI_Init(SPI3_UNIT, &stcSpiInit);

    spi3_dma_config();
    
    SPI_Cmd(SPI3_UNIT, Enable);   

    rt_sem_init(&spi3_tx_wait, "spi3tx", 0, RT_IPC_FLAG_FIFO);
}

static void lcd_spi_send(uint8_t dat)
{ 
    while (Reset == SPI_GetFlag(SPI3_UNIT, SpiFlagSendBufferEmpty)){;}
    SPI_SendData8(SPI3_UNIT, dat);
    while (Reset == SPI_GetFlag(SPI3_UNIT, SpiFlagSpiIdle)){;}
}
/*
static void lcd_spi_trans(uint8_t *dat, uint16_t len)
{
    DMA_SetSrcAddress (SPI3_DMA_UNIT, SPI3_DMA_TX_CHANNEL, (uint32_t)dat);
    DMA_SetTransferCnt(SPI3_DMA_UNIT, SPI3_DMA_TX_CHANNEL, len);

    LCD_CS_L;
    

    DMA_ChannelCmd(SPI3_DMA_UNIT, SPI3_DMA_TX_CHANNEL, Enable);
        

    SPI_Cmd(SPI3_UNIT, Enable);   
    rt_sem_take(&spi3_tx_wait, RT_WAITING_FOREVER);

    LCD_CS_H;
    

    SPI_Cmd(SPI3_UNIT, Disable);
    DMA_ChannelCmd(SPI3_DMA_UNIT, SPI3_DMA_TX_CHANNEL, Disable);
}
*/
static void delayms(uint16_t ms)
{
    rt_thread_delay(ms);
}

static void write_codetable(lcd_code_t *code, uint32_t count)
{
    lcd_code_t *pcode = code;
    
    //传输指令和参数
    for (uint32_t i = 0; i < count; i++)
    {   
        if (pcode->reg == LCDCODE_REGFLAG_END)
        {                                   //结束跳出
            break;
        }
        else if (pcode->reg == LCDCODE_REGFLAG_DELAY)
        {                                   //延时MS
            delayms(pcode->len);
        }
        else
        {                                   //常规发送指令
            LCD_A0_L;
            LCD_CS_L;
            lcd_spi_send(pcode->reg);
            for (uint32_t j = 0; j < pcode->len; j++)
            {
                LCD_A0_H;
                lcd_spi_send(pcode->dat[j]);
            }
            LCD_CS_H;
        }
        pcode++;                            //下一个寄存器   
    }
}

//初始化指令表
static lcd_code_t st7789v_initcode[] = {
//{0x11,  0, {0x00} },
//{LCDCODE_REGFLAG_DELAY, 120, {0x00}},
//{0xb2,  5, {0x0c, 0x0c, 0x00, 0x33, 0x33} }, 
//{0xb7,  1, {0x35} }, 
//{0xbb,  1, {0x35} }, 
//{0xc0,  1, {0x2c} }, 
//{0xc2,  1, {0x01} },
//{0xc3,  1, {0x0b} },
//{0xc4,  1, {0x20} },
//{0xc6,  1, {0x0f} },
//{0xd0,  2, {0xa4, 0xa1} },
//{0xe0, 14, {0xd0, 0x00, 0x02, 0x07, 0x0b, 0x1a, 0x32, 0x54, 0x40, 0x29, 0x12, 0x12, 0x12, 0x17} },
//{0xe1, 14, {0xd0, 0x00, 0x02, 0x07, 0x05, 0x25, 0x2d, 0x44, 0x45, 0x1c, 0x18, 0x16, 0x1c, 0x1d} },
//{0x36,  1, {0x00} },
{0x3a,  1, {0x05} },
//{0x29,  0, {0x00} },
{LCDCODE_REGFLAG_END, 0x00, {0x00} }
};

/*显示区域设置*/
static lcd_code_t st7789v_blockcode[] = {
{0x2a,  4, {0x00, 0x00, 0x00, 0x00} },
{0x2b,  4, {0x00, 0x00, 0x00, 0x00} },
{0x2c,  0, {0x00} },
{LCDCODE_REGFLAG_END, 0x00, {0x00} }
};

static void write_block(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
{
    st7789v_blockcode[0].dat[0] = 0x00;
    st7789v_blockcode[0].dat[1] = x0;
    st7789v_blockcode[0].dat[2] = 0x00;
    st7789v_blockcode[0].dat[3] = x1;
    st7789v_blockcode[1].dat[0] = y0 >> 8;
    st7789v_blockcode[1].dat[1] = y0 & 0xff;
    st7789v_blockcode[1].dat[2] = y1 >> 8;
    st7789v_blockcode[1].dat[3] = y1 & 0xff;
    write_codetable(st7789v_blockcode, 5);
}

void st7789v_init(void)
{
    stc_port_init_t stcPortInit;

    MEM_ZERO_STRUCT(stcPortInit);

    PWC_Fcg1PeriphClockCmd(SPI3_UNIT_CLOCK, Enable);
    /* Configuration SPI pin */
    PORT_SetFunc(SPI3_NSS_PORT, SPI3_NSS_PIN, Func_Gpio,     Disable);    
    PORT_SetFunc(SPI3_SCK_PORT, SPI3_SCK_PIN, SPI3_SCK_FUNC, Disable);
    PORT_SetFunc(SPI3_SDI_PORT, SPI3_SDI_PIN, SPI3_SDI_FUNC, Disable);
    PORT_SetFunc(LCD_RST_PORT,  LCD_RST_PIN,  Func_Gpio,     Disable);
    PORT_SetFunc(LCD_A0_PORT,   LCD_A0_PIN,   Func_Gpio,     Disable);

    stcPortInit.enPinMode = Pin_Mode_Out;
    stcPortInit.enPinDrv  = Pin_Drv_H;
    PORT_Init(LCD_RST_PORT, LCD_RST_PIN, &stcPortInit);
    PORT_Init(LCD_A0_PORT,  LCD_A0_PIN,  &stcPortInit);
    PORT_Init(LCD_CS_PORT,  LCD_CS_PIN,  &stcPortInit);

    bsp_spi3_init();
    
    LCD_RST_H;
    LCD_A0_H;
    LCD_CS_H;
    delayms(10);
    LCD_RST_L;
    delayms(10);
    LCD_RST_H;
    delayms(120);

    write_codetable(st7789v_initcode, sizeof(st7789v_initcode)/sizeof(lcd_code_t));
}

void st7789v_test(void)
{
    LCD_RST_H;
    LCD_A0_H;
    LCD_CS_H;
    delayms(10);
    LCD_RST_L;
    delayms(10);
    LCD_RST_H;
    delayms(120);

    write_codetable(st7789v_initcode, sizeof(st7789v_initcode)/sizeof(lcd_code_t));
     delayms(10);
 //write_block(1, 1, 128, 300); 
}

以上代码是测试MCU发送指令0x3a, 参数0x05,SPI发送代码参考HC32F460 DDL库hc32f460_ddl_Rev2.2.0.zip

static void lcd_spi_send(uint8_t dat)
{ 
    while (Reset == SPI_GetFlag(SPI3_UNIT, SpiFlagSendBufferEmpty)){;}
    SPI_SendData8(SPI3_UNIT, dat);
}

 LCD_A0_L;
 LCD_CS_L;
 lcd_spi_send(pcode->reg);
 for (uint32_t j = 0; j < pcode->len; j++)
 {
     LCD_A0_H;
     lcd_spi_send(pcode->dat[j]);
 }
 LCD_CS_H;

每次发送BYTE之前判断SPI BUFFER是否为空,如果空,写入数据,实施证明,BUFFER空,仅仅是BUFFER空,数据还在SPI硬件里发送着,根本就没结束,而且参考手册里面,SPI和发送相关的状态位也就这个BUFFER EMPTY,而不像之前STM,还有一个发送结束COMPLETE状态位。

看下面波形,第一个字节8个CLK还没结束,CS,A0就已经变高了,造成实际传输无效
在这里插入图片描述
修改如下:

static void lcd_spi_send(uint8_t dat)
{ 
    while (Reset == SPI_GetFlag(SPI3_UNIT, SpiFlagSendBufferEmpty)){;}
    SPI_SendData8(SPI3_UNIT, dat);
    while (Reset == SPI_GetFlag(SPI3_UNIT, SpiFlagSpiIdle)){;}
}

 LCD_A0_L;
 LCD_CS_L;
 lcd_spi_send(pcode->reg);
 for (uint32_t j = 0; j < pcode->len; j++)
 {
     LCD_A0_H;
     lcd_spi_send(pcode->dat[j]);
 }
 LCD_CS_H;

每次写数据之前判断BUFFER是否空,每次写数据之后,等待SPI传输结束
在这里插入图片描述
波形上已经达到我们时序的要求,所以,直接参考当前库代码,至少对于驱动LCD,是有问题的。

总结

有异常,外设无法工作时候,我们要习惯于分析波形,从时序中排查问题,然后再尝试解决问题。

版权声明:本文为CSDN博主「sainty07」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/sainty07/article/details/122441880

目前,小一点的系统很流行SPI接口的显示屏,有黑白TN,有彩色TFT,有高对比OLED,显示分辨率从3296到320240不等,这些显示屏成本低,接口少,易于驱动,所以非常受欢迎

硬件连线通常有以下:
复位RESET,片选CS,地址A0,时钟SCK,数据SDI,背光正负,电源正负,可以做到10PIN以内

因为显示屏的SPI在某些TIMING上会有一些要求,所以片选CS通常使用GPIO模拟,另外RESET,A0也是GPIO,SCK,SDI会使用硬件SPI,达到比较高的传输速率(50MHZ)


这是MCU驱动SPI显示屏的时序图,CS选中器件,DC(A0)决定写指令还是写参数,如果当前BYTE传输期间A0是LOW,表示写指令,如果A0是HIGH,表示写参数,传输完成后,CS再拉高

#include "board.h"


#define LCDCODE_REGFLAG_DELAY       0xFFFE
#define LCDCODE_REGFLAG_END         0xFFFF
#define LCDCODE_DATA_LEN            32

typedef struct
{
    uint16_t reg;
    uint16_t len;
    uint8_t  dat[LCDCODE_DATA_LEN];
}lcd_code_t;

static struct rt_semaphore spi3_tx_wait = {0x00};

static void spi3_tx_dma_tc0_irq_cb(void)
{
    DMA_ClearIrqFlag(SPI3_DMA_UNIT, SPI3_DMA_TX_CHANNEL, TrnCpltIrq);
    rt_sem_release(&spi3_tx_wait);
}

static void spi3_dma_config(void)
{
    stc_dma_config_t stcDmaCfg;
    stc_irq_regi_conf_t stcIrqRegiConf;

    /* configuration structure initialization */
    MEM_ZERO_STRUCT(stcDmaCfg);

    /* Configuration peripheral clock */
    PWC_Fcg0PeriphClockCmd(SPI3_DMA_CLOCK_UNIT, Enable);
    PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_AOS, Enable);
    
    /* Configure TX DMA */
    stcDmaCfg.u16BlockSize           = 1u;
    stcDmaCfg.u16TransferCnt         = 128;
    stcDmaCfg.u32SrcAddr             = (uint32_t)(0);
    stcDmaCfg.u32DesAddr             = (uint32_t)(&SPI3_UNIT->DR);
    stcDmaCfg.stcDmaChCfg.enSrcInc   = AddressIncrease;
    stcDmaCfg.stcDmaChCfg.enDesInc   = AddressFix;
    stcDmaCfg.stcDmaChCfg.enTrnWidth = Dma8Bit;
    stcDmaCfg.stcDmaChCfg.enIntEn    = Enable;
    DMA_InitChannel(SPI3_DMA_UNIT, SPI3_DMA_TX_CHANNEL, &stcDmaCfg);
    DMA_SetTriggerSrc(SPI3_DMA_UNIT, SPI3_DMA_TX_CHANNEL, SPI3_DMA_TX_TRIG_SOURCE);

    /* Enable DMA. */
    DMA_Cmd(SPI3_DMA_UNIT, Enable);

   /* Set DMA block transfer complete IRQ */
    stcIrqRegiConf.enIRQn      = IRQ_SPI3_DMA_TX;
    stcIrqRegiConf.pfnCallback = &spi3_tx_dma_tc0_irq_cb;
    stcIrqRegiConf.enIntSrc    = INT_DMA1_TC0;
    enIrqRegistration(&stcIrqRegiConf);
    
    NVIC_SetPriority(stcIrqRegiConf.enIRQn, IRQ_PRIORITY_SPI3_DMA_TX);
    NVIC_ClearPendingIRQ(stcIrqRegiConf.enIRQn);
    NVIC_EnableIRQ(stcIrqRegiConf.enIRQn);
}

static void bsp_spi3_init(void)
{
    stc_spi_init_t stcSpiInit;

    /* configuration structure initialization */
    MEM_ZERO_STRUCT(stcSpiInit);

    /* Configuration peripheral clock */
    PWC_Fcg1PeriphClockCmd(SPI3_UNIT_CLOCK, Enable);
    
    /* Configuration SPI structure */
    stcSpiInit.enClkDiv                 = SpiClkDiv32;
    stcSpiInit.enFrameNumber            = SpiFrameNumber1;
    stcSpiInit.enDataLength             = SpiDataLengthBit8;
    stcSpiInit.enFirstBitPosition       = SpiFirstBitPositionMSB;
    stcSpiInit.enSckPolarity            = SpiSckIdleLevelLow;
    stcSpiInit.enSckPhase               = SpiSckOddSampleEvenChange;
    stcSpiInit.enReadBufferObject       = SpiReadReceiverBuffer;
    stcSpiInit.enWorkMode               = SpiWorkMode3Line;
    stcSpiInit.enTransMode              = SpiTransOnlySend;
    stcSpiInit.enCommAutoSuspendEn      = Disable;
    stcSpiInit.enModeFaultErrorDetectEn = Disable;
    stcSpiInit.enParitySelfDetectEn     = Disable;
    stcSpiInit.enParityEn               = Disable;
    stcSpiInit.enParity                 = SpiParityEven;

    stcSpiInit.enMasterSlaveMode = SpiModeMaster;
    stcSpiInit.stcDelayConfig.enSsSetupDelayOption   = SpiSsSetupDelayCustomValue;
    stcSpiInit.stcDelayConfig.enSsSetupDelayTime     = SpiSsSetupDelaySck1;
    stcSpiInit.stcDelayConfig.enSsHoldDelayOption    = SpiSsHoldDelayCustomValue;
    stcSpiInit.stcDelayConfig.enSsHoldDelayTime      = SpiSsHoldDelaySck1;
    stcSpiInit.stcDelayConfig.enSsIntervalTimeOption = SpiSsIntervalCustomValue;
    stcSpiInit.stcDelayConfig.enSsIntervalTime       = SpiSsIntervalSck1PlusPck2;
    SPI_Init(SPI3_UNIT, &stcSpiInit);

    spi3_dma_config();
    
    SPI_Cmd(SPI3_UNIT, Enable);   

    rt_sem_init(&spi3_tx_wait, "spi3tx", 0, RT_IPC_FLAG_FIFO);
}

static void lcd_spi_send(uint8_t dat)
{ 
    while (Reset == SPI_GetFlag(SPI3_UNIT, SpiFlagSendBufferEmpty)){;}
    SPI_SendData8(SPI3_UNIT, dat);
    while (Reset == SPI_GetFlag(SPI3_UNIT, SpiFlagSpiIdle)){;}
}
/*
static void lcd_spi_trans(uint8_t *dat, uint16_t len)
{
    DMA_SetSrcAddress (SPI3_DMA_UNIT, SPI3_DMA_TX_CHANNEL, (uint32_t)dat);
    DMA_SetTransferCnt(SPI3_DMA_UNIT, SPI3_DMA_TX_CHANNEL, len);

    LCD_CS_L;
    

    DMA_ChannelCmd(SPI3_DMA_UNIT, SPI3_DMA_TX_CHANNEL, Enable);
        

    SPI_Cmd(SPI3_UNIT, Enable);   
    rt_sem_take(&spi3_tx_wait, RT_WAITING_FOREVER);

    LCD_CS_H;
    

    SPI_Cmd(SPI3_UNIT, Disable);
    DMA_ChannelCmd(SPI3_DMA_UNIT, SPI3_DMA_TX_CHANNEL, Disable);
}
*/
static void delayms(uint16_t ms)
{
    rt_thread_delay(ms);
}

static void write_codetable(lcd_code_t *code, uint32_t count)
{
    lcd_code_t *pcode = code;
    
    //传输指令和参数
    for (uint32_t i = 0; i < count; i++)
    {   
        if (pcode->reg == LCDCODE_REGFLAG_END)
        {                                   //结束跳出
            break;
        }
        else if (pcode->reg == LCDCODE_REGFLAG_DELAY)
        {                                   //延时MS
            delayms(pcode->len);
        }
        else
        {                                   //常规发送指令
            LCD_A0_L;
            LCD_CS_L;
            lcd_spi_send(pcode->reg);
            for (uint32_t j = 0; j < pcode->len; j++)
            {
                LCD_A0_H;
                lcd_spi_send(pcode->dat[j]);
            }
            LCD_CS_H;
        }
        pcode++;                            //下一个寄存器   
    }
}

//初始化指令表
static lcd_code_t st7789v_initcode[] = {
//{0x11,  0, {0x00} },
//{LCDCODE_REGFLAG_DELAY, 120, {0x00}},
//{0xb2,  5, {0x0c, 0x0c, 0x00, 0x33, 0x33} }, 
//{0xb7,  1, {0x35} }, 
//{0xbb,  1, {0x35} }, 
//{0xc0,  1, {0x2c} }, 
//{0xc2,  1, {0x01} },
//{0xc3,  1, {0x0b} },
//{0xc4,  1, {0x20} },
//{0xc6,  1, {0x0f} },
//{0xd0,  2, {0xa4, 0xa1} },
//{0xe0, 14, {0xd0, 0x00, 0x02, 0x07, 0x0b, 0x1a, 0x32, 0x54, 0x40, 0x29, 0x12, 0x12, 0x12, 0x17} },
//{0xe1, 14, {0xd0, 0x00, 0x02, 0x07, 0x05, 0x25, 0x2d, 0x44, 0x45, 0x1c, 0x18, 0x16, 0x1c, 0x1d} },
//{0x36,  1, {0x00} },
{0x3a,  1, {0x05} },
//{0x29,  0, {0x00} },
{LCDCODE_REGFLAG_END, 0x00, {0x00} }
};

/*显示区域设置*/
static lcd_code_t st7789v_blockcode[] = {
{0x2a,  4, {0x00, 0x00, 0x00, 0x00} },
{0x2b,  4, {0x00, 0x00, 0x00, 0x00} },
{0x2c,  0, {0x00} },
{LCDCODE_REGFLAG_END, 0x00, {0x00} }
};

static void write_block(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
{
    st7789v_blockcode[0].dat[0] = 0x00;
    st7789v_blockcode[0].dat[1] = x0;
    st7789v_blockcode[0].dat[2] = 0x00;
    st7789v_blockcode[0].dat[3] = x1;
    st7789v_blockcode[1].dat[0] = y0 >> 8;
    st7789v_blockcode[1].dat[1] = y0 & 0xff;
    st7789v_blockcode[1].dat[2] = y1 >> 8;
    st7789v_blockcode[1].dat[3] = y1 & 0xff;
    write_codetable(st7789v_blockcode, 5);
}

void st7789v_init(void)
{
    stc_port_init_t stcPortInit;

    MEM_ZERO_STRUCT(stcPortInit);

    PWC_Fcg1PeriphClockCmd(SPI3_UNIT_CLOCK, Enable);
    /* Configuration SPI pin */
    PORT_SetFunc(SPI3_NSS_PORT, SPI3_NSS_PIN, Func_Gpio,     Disable);    
    PORT_SetFunc(SPI3_SCK_PORT, SPI3_SCK_PIN, SPI3_SCK_FUNC, Disable);
    PORT_SetFunc(SPI3_SDI_PORT, SPI3_SDI_PIN, SPI3_SDI_FUNC, Disable);
    PORT_SetFunc(LCD_RST_PORT,  LCD_RST_PIN,  Func_Gpio,     Disable);
    PORT_SetFunc(LCD_A0_PORT,   LCD_A0_PIN,   Func_Gpio,     Disable);

    stcPortInit.enPinMode = Pin_Mode_Out;
    stcPortInit.enPinDrv  = Pin_Drv_H;
    PORT_Init(LCD_RST_PORT, LCD_RST_PIN, &stcPortInit);
    PORT_Init(LCD_A0_PORT,  LCD_A0_PIN,  &stcPortInit);
    PORT_Init(LCD_CS_PORT,  LCD_CS_PIN,  &stcPortInit);

    bsp_spi3_init();
    
    LCD_RST_H;
    LCD_A0_H;
    LCD_CS_H;
    delayms(10);
    LCD_RST_L;
    delayms(10);
    LCD_RST_H;
    delayms(120);

    write_codetable(st7789v_initcode, sizeof(st7789v_initcode)/sizeof(lcd_code_t));
}

void st7789v_test(void)
{
    LCD_RST_H;
    LCD_A0_H;
    LCD_CS_H;
    delayms(10);
    LCD_RST_L;
    delayms(10);
    LCD_RST_H;
    delayms(120);

    write_codetable(st7789v_initcode, sizeof(st7789v_initcode)/sizeof(lcd_code_t));
     delayms(10);
 //write_block(1, 1, 128, 300); 
}

以上代码是测试MCU发送指令0x3a, 参数0x05,SPI发送代码参考HC32F460 DDL库hc32f460_ddl_Rev2.2.0.zip

static void lcd_spi_send(uint8_t dat)
{ 
    while (Reset == SPI_GetFlag(SPI3_UNIT, SpiFlagSendBufferEmpty)){;}
    SPI_SendData8(SPI3_UNIT, dat);
}

 LCD_A0_L;
 LCD_CS_L;
 lcd_spi_send(pcode->reg);
 for (uint32_t j = 0; j < pcode->len; j++)
 {
     LCD_A0_H;
     lcd_spi_send(pcode->dat[j]);
 }
 LCD_CS_H;

每次发送BYTE之前判断SPI BUFFER是否为空,如果空,写入数据,实施证明,BUFFER空,仅仅是BUFFER空,数据还在SPI硬件里发送着,根本就没结束,而且参考手册里面,SPI和发送相关的状态位也就这个BUFFER EMPTY,而不像之前STM,还有一个发送结束COMPLETE状态位。

看下面波形,第一个字节8个CLK还没结束,CS,A0就已经变高了,造成实际传输无效
在这里插入图片描述
修改如下:

static void lcd_spi_send(uint8_t dat)
{ 
    while (Reset == SPI_GetFlag(SPI3_UNIT, SpiFlagSendBufferEmpty)){;}
    SPI_SendData8(SPI3_UNIT, dat);
    while (Reset == SPI_GetFlag(SPI3_UNIT, SpiFlagSpiIdle)){;}
}

 LCD_A0_L;
 LCD_CS_L;
 lcd_spi_send(pcode->reg);
 for (uint32_t j = 0; j < pcode->len; j++)
 {
     LCD_A0_H;
     lcd_spi_send(pcode->dat[j]);
 }
 LCD_CS_H;

每次写数据之前判断BUFFER是否空,每次写数据之后,等待SPI传输结束
在这里插入图片描述
波形上已经达到我们时序的要求,所以,直接参考当前库代码,至少对于驱动LCD,是有问题的。

总结

有异常,外设无法工作时候,我们要习惯于分析波形,从时序中排查问题,然后再尝试解决问题。

版权声明:本文为CSDN博主「sainty07」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/sainty07/article/details/122441880

生成海报
点赞 0

sainty07

我还没有学会写个人说明!

暂无评论

相关推荐

HC32F460填坑 - SPI POLLING SEND

目前,小一点的系统很流行SPI接口的显示屏,有黑白TN,有彩色TFT,有高对比OLED,显示分辨率从3296到320240不等,这些显示屏成本低,

基于8051单片机实现电子时钟+数字秒表设计

概述 电子时钟是一种利用数字电路来显示秒、分、时的计时装置,与传统的机械钟相比,它具有走时准确、显 示直观、无机械传动装置等优点,因而得到广泛应用。随着人们生活环境的不断改善和美化,在许

CC2530 常用寄存器

一、端口初始化相关寄存器 代码示例:用按键1和按键2分别控制D4和D6灯 点我跳转 二、INT相关寄存器 代码示例:利用key1,key2来产生中断控制D3,D5灯,key1,key2为下降沿触