ST77903 QSPI + STM32H743 + RTThread + LVGL

因为之前的H750内部空间太小,无法放入UI资源,所以这次直接买了块NUCLEO-H743ZI2,驱动上做了指令1LANE和4LANE的兼容

驱动文件如下:


#include "board.h"
#include "sram.h"
#include "rtthread.h"
#include "rtdevice.h"
#include "lcdqspi.h"


#define DBG
#define DBG_TAG             "lcdqspi"
#include "log.h"

#define FRAME_BLANKING_TIME (10U)
#define FRAME_MEM_SIZE      (LCD_HBYTE * LCD_Y_SIZE)
#define FRAME_MEM_BASE      SRAM_AXI_BASE

#define QSPI_CLK_MHZ        (25)

#if (FRAME_MEM_SIZE > SRAM_AXI_SIZE)
#error "lcdqspi frame cache size is not enough!"
#endif

static uint8_t frame_cache[LCD_Y_SIZE][LCD_HBYTE] __attribute__ ((at(FRAME_MEM_BASE)));
 

void rt_hw_us_delay(rt_uint32_t us);

static QSPI_HandleTypeDef QSPI_Handler; 
static QSPI_CommandTypeDef QSPI_Cmdhandler;

static struct rt_semaphore  trans_sem  = {0};
static struct rt_completion frame_sync = {0};
static struct rt_timer      te_timer   = {0};

static __IO uint32_t te_offset = LCD_TE_OFT;

void QUADSPI_IRQHandler(void)
{
    IRQ_ENTER();
    HAL_QSPI_IRQHandler(&QSPI_Handler);
    IRQ_LEAVE();
}

void MDMA_IRQHandler(void)
{ 
    IRQ_ENTER();
    HAL_MDMA_IRQHandler(QSPI_Handler.hmdma);
    IRQ_LEAVE();
}

void HAL_QSPI_CmdCpltCallback(QSPI_HandleTypeDef *hqspi)
{
    rt_sem_release(&trans_sem);
}

void HAL_QSPI_TxCpltCallback(QSPI_HandleTypeDef *hqspi)
{
    rt_sem_release(&trans_sem);
}

void HAL_QSPI_MspInit(QSPI_HandleTypeDef *hqspi)
{
    static MDMA_HandleTypeDef hmdma;

    __HAL_RCC_QSPI_CLK_ENABLE();
    __HAL_RCC_QSPI_FORCE_RESET();
    __HAL_RCC_QSPI_RELEASE_RESET();

    __HAL_RCC_MDMA_CLK_ENABLE();
    __HAL_RCC_MDMA_FORCE_RESET();
    __HAL_RCC_MDMA_RELEASE_RESET();

    HAL_NVIC_SetPriority(QUADSPI_IRQn, NVIC_PRIORITY_QSPI, 0);
    HAL_NVIC_EnableIRQ(QUADSPI_IRQn);

    hmdma.Init.Request              = MDMA_REQUEST_QUADSPI_FIFO_TH;
    hmdma.Init.TransferTriggerMode  = MDMA_BUFFER_TRANSFER;
    hmdma.Init.Priority             = MDMA_PRIORITY_HIGH;
    hmdma.Init.Endianness           = MDMA_LITTLE_ENDIANNESS_PRESERVE;

    hmdma.Init.SourceInc            = MDMA_SRC_INC_BYTE;
    hmdma.Init.DestinationInc       = MDMA_DEST_INC_DISABLE;
    hmdma.Init.SourceDataSize       = MDMA_SRC_DATASIZE_BYTE;
    hmdma.Init.DestDataSize         = MDMA_DEST_DATASIZE_BYTE;
    hmdma.Init.DataAlignment        = MDMA_DATAALIGN_PACKENABLE;
    hmdma.Init.BufferTransferLength = 16;
    hmdma.Init.SourceBurst          = MDMA_SOURCE_BURST_SINGLE;
    hmdma.Init.DestBurst            = MDMA_DEST_BURST_SINGLE;

    hmdma.Init.SourceBlockAddressOffset = 0;
    hmdma.Init.DestBlockAddressOffset   = 0;

    hmdma.Instance = MDMA_Channel1;

    __HAL_LINKDMA(hqspi, hmdma, hmdma);
    HAL_MDMA_DeInit(&hmdma);      
    HAL_MDMA_Init(&hmdma);
    HAL_NVIC_SetPriority(MDMA_IRQn, 0x00, 0);
    HAL_NVIC_EnableIRQ(MDMA_IRQn);  
}

void HAL_QSPI_MspDeInit(QSPI_HandleTypeDef *hqspi)
{
    __HAL_RCC_QSPI_FORCE_RESET();
    __HAL_RCC_QSPI_RELEASE_RESET();
    HAL_NVIC_DisableIRQ(QUADSPI_IRQn);

    __HAL_RCC_MDMA_FORCE_RESET();
    __HAL_RCC_MDMA_RELEASE_RESET();
    HAL_NVIC_DisableIRQ(MDMA_IRQn);
} 


/* QSPI initialize */
static void ll_qspi_init(void)
{
    static DMA_HandleTypeDef hdma;

    __HAL_RCC_QSPI_CLK_ENABLE();        

    __HAL_RCC_DMA1_CLK_ENABLE();  
    
    QSPI_Handler.Instance                = QUADSPI;     

    /* D1HCLK(200MHz) / (prescaler + 1) = 200/5 = 40MHZ */
    QSPI_Handler.Init.ClockPrescaler     = 200 / QSPI_CLK_MHZ - 1;                                                                   
    QSPI_Handler.Init.FifoThreshold      = 16;                     
    QSPI_Handler.Init.SampleShifting     = QSPI_SAMPLE_SHIFTING_NONE;
    QSPI_Handler.Init.FlashSize          = POSITION_VAL(0X800000)-1;  
    QSPI_Handler.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_5_CYCLE;
    
    /* clock keep high level in idle time cs inactive */
    QSPI_Handler.Init.ClockMode          = QSPI_CLOCK_MODE_3;        
    QSPI_Handler.Init.FlashID            = QSPI_FLASH_ID_1;              
    QSPI_Handler.Init.DualFlash          = QSPI_DUALFLASH_DISABLE;     
    HAL_QSPI_Init(&QSPI_Handler);

    /* 0xde is the first byte every transmit */
    QSPI_Cmdhandler.Instruction     = 0xde;
    /* qspi 24bit address, lcd command is set in A15~A8 */
    QSPI_Cmdhandler.Address         = 0x000000;
    QSPI_Cmdhandler.DummyCycles     = 0;
    QSPI_Cmdhandler.InstructionMode = QSPI_INSTRUCTION_1_LINE;
    QSPI_Cmdhandler.AddressMode     = QSPI_ADDRESS_1_LINE;
    QSPI_Cmdhandler.AddressSize     = QSPI_ADDRESS_24_BITS;    
    QSPI_Cmdhandler.DataMode        = QSPI_DATA_NONE;    
    QSPI_Cmdhandler.NbData          = 0;

    QSPI_Cmdhandler.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;               
    QSPI_Cmdhandler.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;   
    QSPI_Cmdhandler.DdrMode           = QSPI_DDR_MODE_DISABLE;                  
    QSPI_Cmdhandler.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;
}

/* lcd delay millisecond */
__INLINE static void lcd_dlyms(uint32_t ms)
{
    rt_thread_delay(ms);
}

__INLINE static void lcd_dlyus(uint32_t us)
{
    rt_hw_us_delay(us);
}

/* lcd transmit, write command, write display data */
static void lcd_transmit(uint32_t cmd, uint32_t len, uint8_t *dat)
{
    if (len == 0)              
    {                           /* write command, no parameter */
#if (CMD_LANE == CMD_LANE_1)
        QSPI_Cmdhandler.Instruction     = 0xd8;
        QSPI_Cmdhandler.InstructionMode = QSPI_INSTRUCTION_1_LINE;     
        QSPI_Cmdhandler.AddressMode     = QSPI_ADDRESS_1_LINE;  
        QSPI_Cmdhandler.DataMode        = QSPI_DATA_NONE;    
#endif
#if (CMD_LANE == CMD_LANE_4)     
        QSPI_Cmdhandler.Instruction     = 0xde;
        QSPI_Cmdhandler.InstructionMode = QSPI_INSTRUCTION_4_LINES;     
        QSPI_Cmdhandler.AddressMode     = QSPI_ADDRESS_4_LINES;  
        QSPI_Cmdhandler.DataMode        = QSPI_DATA_NONE;  
#endif
        QSPI_Cmdhandler.Address = cmd << 8;                                   
        QSPI_Cmdhandler.NbData  = 0;
                                /* interrupt mode */
        HAL_QSPI_Command_IT(&QSPI_Handler, &QSPI_Cmdhandler);
    }
    else if (len <= INIT_DAT_LEN)
    {                           /* write command with parameter */
#if (CMD_LANE == CMD_LANE_1)
        QSPI_Cmdhandler.Instruction     = 0xd8;
        QSPI_Cmdhandler.InstructionMode = QSPI_INSTRUCTION_1_LINE;     
        QSPI_Cmdhandler.AddressMode     = QSPI_ADDRESS_1_LINE;  
        QSPI_Cmdhandler.DataMode        = QSPI_DATA_1_LINE;    
#endif
#if (CMD_LANE == CMD_LANE_4)     
        QSPI_Cmdhandler.Instruction     = 0xde;
        QSPI_Cmdhandler.InstructionMode = QSPI_INSTRUCTION_4_LINES;     
        QSPI_Cmdhandler.AddressMode     = QSPI_ADDRESS_4_LINES;  
        QSPI_Cmdhandler.DataMode        = QSPI_DATA_4_LINES;    
#endif
        QSPI_Cmdhandler.Address = cmd << 8;  
        QSPI_Cmdhandler.NbData  = len;
                                /* interrupt mode */
        HAL_QSPI_Command_IT(&QSPI_Handler, &QSPI_Cmdhandler);        
        HAL_QSPI_Transmit_IT(&QSPI_Handler, dat);
    }
    else
    {                           /* write display data by hbyte length */
#if (CMD_LANE == CMD_LANE_1)
        QSPI_Cmdhandler.Instruction     = 0xde;
        QSPI_Cmdhandler.InstructionMode = QSPI_INSTRUCTION_1_LINE;     
        QSPI_Cmdhandler.AddressMode     = QSPI_ADDRESS_1_LINE;  
        QSPI_Cmdhandler.DataMode        = QSPI_DATA_4_LINES;   
#endif
#if (CMD_LANE == CMD_LANE_4)     
        QSPI_Cmdhandler.Instruction     = 0xde;
        QSPI_Cmdhandler.InstructionMode = QSPI_INSTRUCTION_4_LINES;     
        QSPI_Cmdhandler.AddressMode     = QSPI_ADDRESS_4_LINES;  
        QSPI_Cmdhandler.DataMode        = QSPI_DATA_4_LINES;   
#endif
        QSPI_Cmdhandler.Address = cmd << 8;
        QSPI_Cmdhandler.NbData  = len;
                                /* mdma mode */
        HAL_QSPI_Command(&QSPI_Handler, &QSPI_Cmdhandler, 1000);
        HAL_QSPI_Transmit_DMA(&QSPI_Handler, dat);
    }
                                /* wait trans complete */
    rt_sem_take(&trans_sem, RT_WAITING_FOREVER);
}

/* LCD initialize */
static void lcd_initialize(void)
{
    uint32_t i;
    LCD_RST_H;
    lcd_dlyms(10);
    LCD_RST_L;
    lcd_dlyms(10);
    LCD_RST_H;
    lcd_dlyms(120);

    init_line_t *init = (init_line_t *)&init_table[0];

    for (i = 0; i < sizeof(init_table)/sizeof(init_line_t); i++)
    {                           /* transmit initialize code */
        if (init->cmd == 0xff)
        {                       /* delay */
            lcd_dlyms(init->dat[0]);
        }
        else
        {                       /* command - parameter */
            lcd_transmit(init->cmd, init->len, init->dat);
        }
        init++;
    }
}

/* lcd te signal generate */
static void lcdqspi_timer_entry(void * parameter)
{
    rt_completion_done(&frame_sync);
}

/* lcd display frame thread */
static void lcdqspi_thread_entry(void * parameter)
{
    __IO uint32_t i = 0;

    /* hardware qspi initialize */
    ll_qspi_init();

    /* lcd driver st77903 initialize */
    lcd_initialize();

    /* lcd display frame with cache pixel data */
    while (1)
    {
        /* TE signal */
        rt_timer_start(&te_timer);
    
        /* vs(0x61) packet */
        for (i = 0; i < LCD_VSW; i++)
        {
            lcd_transmit(0x61, 0, NULL); 
            lcd_dlyus(40);
        }
        
        /* hbp(0x60) packet */
        for (i = 0; i < LCD_HBP; i++)
        {
            lcd_transmit(0x60, 0, NULL); 
            lcd_dlyus(40);
        }
        
        /* transmit display cache data to lcd line by line */	
        for (i = 0; i < LCD_Y_SIZE; i++)
        {
            lcd_transmit(0x60, LCD_HBYTE, (uint8_t *)&frame_cache[i][0]);
        }

        /* hfp(0x60) packet */
        for (i = 0; i < LCD_HFP; i++)
        {
            lcd_transmit(0x60, 0, NULL); 
            lcd_dlyus(40);
        }

        /* transmit is complet, can update frame cache in blanking time */
        lcd_dlyms(FRAME_BLANKING_TIME);
    }
}

static int lcdqspi_app(void)
{
    rt_thread_t thread;

    rt_sem_init(&trans_sem, "lcdtrans", 0, RT_IPC_FLAG_PRIO);

    rt_timer_init(&te_timer, "lcdte", lcdqspi_timer_entry, RT_NULL, te_offset, RT_TIMER_FLAG_ONE_SHOT);
    
    rt_completion_init(&frame_sync); 

	thread = rt_thread_create("lcdqspi", lcdqspi_thread_entry, RT_NULL, 1024, 5, 10);
	if (thread != RT_NULL)rt_thread_startup(thread);
    return 0;
}

INIT_APP_EXPORT(lcdqspi_app);


void lcdqspi_set_pixel(uint32_t x, uint32_t y, uint32_t color)
{
    if ((x < LCD_X_SIZE)&&(y < LCD_Y_SIZE))
    {
        uint32_t xoft = x * 3;
        frame_cache[y][xoft + 2] = color & 0xff;
        frame_cache[y][xoft + 1] = (color & 0xff00) >> 8;
        frame_cache[y][xoft + 0] = (color & 0xff0000) >> 16;
    }
}

void lcdqspi_fill_block(uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, uint32_t color)
{
    if ((x1 < LCD_X_SIZE)&&(y1 < LCD_Y_SIZE)&&(x1 >= x0)&&(y1 >= y0))
    {
        uint32_t x,y;
        for (y = y0; y <= y1; y++)
        {        
            uint32_t oft = x0 * 3;
            for (x = x0; x <= x1; x++)
            {
                frame_cache[y][oft + 2] = color & 0xff;
                frame_cache[y][oft + 1] = (color & 0xff00) >> 8;
                frame_cache[y][oft + 0] = (color & 0xff0000) >> 16;
                oft += 3;
            }
        }
    }
}

void lcdqspi_clear(uint32_t color)
{
    lcdqspi_fill_block(0, 0, LCD_X_SIZE - 1, LCD_Y_SIZE - 1, color);
}

void lcdqspi_draw_line(uint32_t x0, uint32_t x1, uint32_t y, uint32_t *pixel)
{
    if ((x1 < LCD_X_SIZE)&&(y < LCD_Y_SIZE)&&(x1 >= x0))
    {
        uint32_t  oft = x0 * 3;
        uint32_t *dat = pixel;
        for (uint32_t x = x0; x <= x1; x++)
        {
            frame_cache[y][oft + 2] = *dat & 0xff;
            frame_cache[y][oft + 1] = (*dat & 0xff00) >> 8;
            frame_cache[y][oft + 0] = (*dat & 0xff0000) >> 16;
            oft += 3;
            dat++;
        }
    }
}

void lcdqspi_draw_line_rbg888(uint32_t x0, uint32_t x1, uint32_t y, uint8_t *dat)
{
    if ((x1 < LCD_X_SIZE)&&(y < LCD_Y_SIZE)&&(x1 >= x0))
    {
        uint32_t  oft = x0 * 3;
        for (uint32_t x = x0; x <= x1; x++)
        {
            frame_cache[y][oft + 2] = *dat++;
            frame_cache[y][oft + 1] = *dat++;
            frame_cache[y][oft + 0] = *dat++;
            oft += 3; 
        }
    }
}
void lcdqspi_set_te(uint32_t offset)
{
    te_offset = offset + 1;
    rt_timer_stop(&te_timer);
    rt_timer_control(&te_timer, RT_TIMER_CTRL_SET_TIME, (void *)&te_offset);
}

void lcdqspi_wait_te(void)
{
    /* if already done, clear flag */
    rt_completion_wait(&frame_sync, 0);
    /* wait a new flag for update sync */
    rt_completion_wait(&frame_sync, RT_WAITING_FOREVER);
}


#ifdef FINSH_USING_MSH
#include "stdlib.h"
static void lcdqspi_ctl(int argc, char **argv)
{
    if (argc == 3)
    {    
	    if (rt_strcmp("te", argv[1]) == RT_EOK)
        {
            lcdqspi_set_te(atoi(argv[2]));
        }
    }
}

MSH_CMD_EXPORT_ALIAS(lcdqspi_ctl, lcdctl, lcdqspi control);
#endif

头文件如下


#ifndef __LCD_QSPI_H__
#define __LCD_QSPI_H__

#include "stdint.h"

#define CMD_LANE_4          (4)
#define CMD_LANE_1          (1)

#define INIT_DAT_LEN        (30)

/* ST77903 bist mode, test command is transmit correctly.
if can't see color bar on lcd panel, check the hardware issure */
//#define BIST_MODE

typedef struct
{
    uint8_t cmd;
    uint8_t len;
    uint8_t dat[INIT_DAT_LEN];
}init_line_t;

#include "ST77903-BOE1D3-320X320.H"
//#include "ST77903-IVO1D6-400X400.H"

#ifndef  CMD_LANE
#define  CMD_LANE           CMD_LANE_1
#endif

#define LCD_BPP             (24)

#define LCD_X_SIZE          LCM_X_SIZE                  /* available x pixel size */
#define LCD_Y_SIZE          LCM_Y_SIZE		            /* available y pixle size */
#define LCD_PBYTE           ((LCD_BPP + 7) / 8)         /* bytes in pixel unit */
#define LCD_HBYTE           (LCD_X_SIZE * LCD_PBYTE)    /* bytes in horizontal line */

void     lcdqspi_clear(uint32_t color);
void     lcdqspi_set_pixel(uint32_t x, uint32_t y, uint32_t color);
void     lcdqspi_fill_block(uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, uint32_t color);
void     lcdqspi_draw_line(uint32_t x0, uint32_t x1, uint32_t y, uint32_t *pixel);
void     lcdqspi_set_te(uint32_t offset);
void     lcdqspi_wait_te(void);

#endif

BOE 320X320初始化


#define  CMD_LANE           CMD_LANE_1

#define LCM_X_SIZE          (320)
#define LCM_Y_SIZE          (320)

#define LCD_VSW             (1U)
#define LCD_HFP             (8U)
#define LCD_HBP             (8U)

#define LCD_TE_OFT          (25U)

/* ST77903 LCD Initialize table */
/* command - parameter length - parameter data */
/* if command is 0xff, means a delay time unit millisecond */
static const init_line_t init_table[] = {
{0xf0,  1, 0xc3},
{0xf0,  1, 0x96},
{0xf0,  1, 0xa5},
{0xe7,  4, 0x80, 0x77, 0x1f, 0xcc},
{0xc1,  4, 0x44, 0x06, 0xac, 0x1b},
{0xc2,  4, 0x44, 0x06, 0xac, 0x1b},
{0xc3,  4, 0x42, 0x04, 0x24, 0x03},
{0xc4,  4, 0x42, 0x02, 0x24, 0x03},
{0xc5,  1, 0x5a},
{0xe0, 14, 0xf3, 0x0f, 0x12, 0x05, 0x07, 0x03, 0x32, 0x44, 0x4a, 0x09, 0x14, 0x14, 0x2e, 0x33},
{0xe1, 14, 0xf3, 0x0f, 0x13, 0x05, 0x07, 0x03, 0x32, 0x33, 0x4a, 0x08, 0x14, 0x14, 0x2e, 0x33},
{0xe5, 14, 0x9a, 0xf5, 0x95, 0x34, 0x22, 0x25, 0x10, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25},
{0xe6, 14, 0x9a, 0xf5, 0x95, 0x57, 0x22, 0x25, 0x10, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22},
{0xec,  2, 0x40, 0x07},
{0x36,  1, 0x0c},
{0x3a,  1, 0x07},
{0xb2,  1, 0x00},
{0xb3,  1, 0x01},
{0xb4,  1, 0x00},
{0xb5,  4, 0x00, 0x54, 0x00, 0x54},
{0xa5,  9, 0x00, 0x01, 0x40, 0x00, 0x00, 0x17, 0x2a, 0x0a, 0x02},
{0xa6,  9, 0xa0, 0x12, 0x40, 0x01, 0x00, 0x11, 0x2a, 0x0a, 0x02},
{0xba,  7, 0x59, 0x02, 0x03, 0x00, 0x22, 0x02, 0x00},
{0xbb,  8, 0x00, 0x35, 0x00, 0x33, 0x88, 0x87, 0x07, 0x00},
{0xbc,  8, 0x00, 0x3b, 0x00, 0x33, 0x08, 0x87, 0x07, 0x00},
{0xbd, 11, 0x33, 0xff, 0xff, 0xff, 0x67, 0x76, 0xff, 0xff, 0x14, 0xff, 0x02},
{0xf9,  1, 0x3c},
{0xb6,  2, 0x9f, 0x27},
{0x35,  1, 0x00},
{0x21,  0, 0x00},
{0x11,  0, 0x00},
{0xff,  1, 120},
{0x29,  0, 0x00},
{0xff,  1, 120},
#ifdef BIST_MODE
{0xb0,  1, 0xa5},
{0xcc,  9, 0x40, 0x00, 0x3f, 0x00, 0x14, 0x14, 0x20, 0x20, 0x03},
#endif
};

IVO 400X400初始化


#define CMD_LANE           CMD_LANE_4

#define LCM_X_SIZE          (400)
#define LCM_Y_SIZE          (400)

#define LCD_VSW             (1U)
#define LCD_HFP             (8U)
#define LCD_HBP             (8U)

#define LCD_TE_OFT          (25U) 

/* ST77903 LCD Initialize table */
/* command - parameter length - parameter data */
/* if command is 0xff, means a delay time unit millisecond */
static const init_line_t init_table[] = {
{0xf0,  1, 0xc3},
{0xf0,  1, 0x96},
{0xf0,  1, 0xa5},
{0xe9,  1, 0x20},
{0xe7,  4, 0x80, 0x77, 0x1f, 0xcc},
{0xc1,  4, 0x77, 0x07, 0xc2, 0x07},
{0xc2,  4, 0x77, 0x07, 0xc2, 0x07},
{0xc3,  4, 0x22, 0x02, 0x22, 0x04},
{0xc4,  4, 0x22, 0x02, 0x22, 0x04},
{0xc5,  1, 0x71},
{0xe0, 14, 0x87, 0x09, 0x0c, 0x06, 0x05, 0x03, 0x29, 0x32, 0x49, 0x0f, 0x1b, 0x17, 0x2a, 0x2f},
{0xe1, 14, 0x87, 0x09, 0x0c, 0x06, 0x05, 0x03, 0x29, 0x32, 0x49, 0x0f, 0x1b, 0x17, 0x2a, 0x2f},
{0xe5, 14, 0xb2, 0xf5, 0xbd, 0x24, 0x22, 0x25, 0x10, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22},
{0xe6, 14, 0xb2, 0xf5, 0xbd, 0x24, 0x22, 0x25, 0x10, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22},
{0xec,  2, 0x40, 0x03},
{0x36,  1, 0x0c},
{0x3a,  1, 0x07},
{0xb2,  1, 0x00},
{0xb3,  1, 0x01},
{0xb4,  1, 0x00},
{0xb5,  4, 0x00, 0x08, 0x00, 0x08},
{0xb6,  2, 0xc7, 0x31},
{0xa5,  9, 0x00, 0x00, 0x00, 0x00, 0x20, 0x15, 0x2a, 0x8a, 0x02},
{0xa6,  9, 0x00, 0x00, 0x00, 0x00, 0x20, 0x15, 0x2a, 0x8a, 0x02},
{0xba,  7, 0x0a, 0x5a, 0x23, 0x10, 0x25, 0x02, 0x00},
{0xbb,  8, 0x00, 0x30, 0x00, 0x29, 0x88, 0x87, 0x18, 0x00},
{0xbc,  8, 0x00, 0x30, 0x00, 0x29, 0x88, 0x87, 0x18, 0x00},
{0xbd, 11, 0xa1, 0xb2, 0x2b, 0x1a, 0x56, 0x43, 0x34, 0x65, 0xff, 0xff, 0x0f},
{0x35,  1, 0x00},
{0x21,  0, 0x00},
{0x11,  0, 0x00},
{0xff,  1, 120},
{0x29,  0, 0x00},
{0xff,  1, 120},
#ifdef BIST_MODE
{0xb0,  1, 0xa5},
{0xcc,  9, 0x40, 0x00, 0x3f, 0x00, 0x14, 0x14, 0x20, 0x20, 0x03},
#endif
};

实际效果
ST77903 QSPI + STM32H743 + RTThread + LVGL
ST77903 QSPI + STM32H743 + RTThread + LVGL

指针表盘资源从以下地址链接,感谢作者提供
https://blog.csdn.net/mygod2008ok/article/details/111143232

上一篇:moectf chall 数独题 z3约束器求解


下一篇:C#上位机与施耐德PLC通讯