nRF52 Notas (26) Pantalla LCD de interfaz QSPI

1 Condiciones de la plataforma

Hardware: nrf52840
Software: sdk17.0

2 Descripción general de QSPI

El periférico QSPI admite la comunicación con dispositivos flash externos mediante SPI

Las características clave del periférico QSPI se enumeran a continuación:
• Entrada/salida SPI simple/doble/cuádruple
• Frecuencia de reloj configurable de 2 a 32 MHz
• Acceso de lectura/escritura de una sola palabra desde/hacia memoria flash externa
• Para lecturas y escrituras en bloque EasyDMA para transferencias
• Velocidades de lectura EasyDMA de hasta 16 MB/seg.
• Ejecución in situ (XIP) para ejecutar programas directamente desde una memoria flash externa.
Insertar descripción de la imagen aquí
En la serie Nordic nRF52/nRF53, QSPI puede admitir dos modos diferentes.

Operación Flash/XIP (debe seguir el protocolo flash)
para enviar instrucciones personalizadas (limitado a usar 1 cable en QSPI para enviar datos).

En el conjunto de instrucciones, admite códigos de operación con dispositivos flash externos.

Insertar descripción de la imagen aquí

1.1 Interfaz QSPI para LCD

Básicamente, la interfaz QSPI tiene 6 pines GPIO.
Insertar descripción de la imagen aquí
Pantalla utilizada: hannstar 360×360 con resolución GalaxyCore Controller para pruebas.

2 configuraciones de código

2.1 Inicialización

Inicialice el módulo QSPI
para configurar los 6 pines GPIO como salidas de unidad alta.

#define LCD_QSPI_RESET_PIN NRF_GPIO_PIN_MAP(0,27)
#define LCD_QSPI_CSN_PIN   NRF_GPIO_PIN_MAP(0,26)
#define LCD_QSPI_SCK_PIN   NRF_GPIO_PIN_MAP(0,02)
#define LCD_QSPI_IO0_PIN   NRF_GPIO_PIN_MAP(1,15)
#define LCD_QSPI_IO1_PIN   NRF_GPIO_PIN_MAP(1,14)
#define LCD_QSPI_IO2_PIN   NRF_GPIO_PIN_MAP(1,13)
#define LCD_QSPI_IO3_PIN   NRF_GPIO_PIN_MAP(1,12)

static void config_qspi_pin_high_drive(void)
{
    
    
        nrf_gpio_cfg(
                LCD_QSPI_SCK_PIN,
                NRF_GPIO_PIN_DIR_INPUT,
                NRF_GPIO_PIN_INPUT_CONNECT,
                NRF_GPIO_PIN_PULLDOWN,
                NRF_GPIO_PIN_H0H1,
                NRF_GPIO_PIN_SENSE_HIGH);
        nrf_gpio_cfg(
                LCD_QSPI_CSN_PIN,
                NRF_GPIO_PIN_DIR_INPUT,
                NRF_GPIO_PIN_INPUT_DISCONNECT,
                NRF_GPIO_PIN_NOPULL,
                NRF_GPIO_PIN_H0H1,
                NRF_GPIO_PIN_NOSENSE);

        nrf_gpio_cfg(
                LCD_QSPI_IO0_PIN,
                NRF_GPIO_PIN_DIR_INPUT,
                NRF_GPIO_PIN_INPUT_DISCONNECT,
                NRF_GPIO_PIN_PULLDOWN,
                NRF_GPIO_PIN_H0H1,
                NRF_GPIO_PIN_NOSENSE);

        nrf_gpio_cfg(
                LCD_QSPI_IO1_PIN,
                NRF_GPIO_PIN_DIR_INPUT,
                NRF_GPIO_PIN_INPUT_DISCONNECT,
                NRF_GPIO_PIN_PULLDOWN,
                NRF_GPIO_PIN_H0H1,
                NRF_GPIO_PIN_NOSENSE);

        nrf_gpio_cfg(
                LCD_QSPI_IO2_PIN,
                NRF_GPIO_PIN_DIR_INPUT,
                NRF_GPIO_PIN_INPUT_DISCONNECT,
                NRF_GPIO_PIN_PULLDOWN,
                NRF_GPIO_PIN_H0H1,
                NRF_GPIO_PIN_NOSENSE);

        nrf_gpio_cfg(
                LCD_QSPI_IO3_PIN,
                NRF_GPIO_PIN_DIR_INPUT,
                NRF_GPIO_PIN_INPUT_DISCONNECT,
                NRF_GPIO_PIN_PULLDOWN,
                NRF_GPIO_PIN_H0H1,
                NRF_GPIO_PIN_NOSENSE);
}

Después de la demostración de LCD 320×240 @ nRF52840, me gustaría describir cómo usar la interfaz QSPI para controlar una pantalla LCD más grande, como una resolución de 360 ​​x 360 @ nRF52840.

Interfaz periférica serie cuádruple QSPI
El periférico QSPI admite la comunicación con dispositivos de memoria flash externos mediante SPI.

Las características clave del periférico QSPI se enumeran a continuación:
• Entrada/salida SPI simple/doble/cuádruple
• Frecuencia de reloj configurable de 2 a 32 MHz
• Acceso de lectura/escritura de una sola palabra desde/hacia memoria flash externa
• Para lecturas y escrituras en bloque EasyDMA para transferencias
• Velocidades de lectura EasyDMA de hasta 16 MB/seg.
• Ejecución in situ (XIP) para ejecutar programas directamente desde una memoria flash externa

En la serie Nordic nRF52/nRF53, QSPI puede admitir dos modos diferentes.

Operación Flash/XIP (debe seguir el protocolo flash)
para enviar instrucciones personalizadas (limitado a usar 1 cable en QSPI para enviar datos).
En el conjunto de instrucciones, admite códigos de operación con dispositivos flash externos.

Interfaz QSPI para LCD
Básicamente, la interfaz QSPI tiene 6 pines GPIO.

En este blog, realizaré pruebas utilizando las resoluciones HannStar 360×360 y GalaxyCore Controller del fabricante de la pantalla.

Inicialice el módulo QSPI
para configurar los 6 pines GPIO como salidas de unidad alta.

#define LCD_QSPI_RESET_PIN NRF_GPIO_PIN_MAP(0,27)
#define LCD_QSPI_CSN_PIN   NRF_GPIO_PIN_MAP(0,26)
#define LCD_QSPI_SCK_PIN   NRF_GPIO_PIN_MAP(0,02)
#define LCD_QSPI_IO0_PIN   NRF_GPIO_PIN_MAP(1,15)
#define LCD_QSPI_IO1_PIN   NRF_GPIO_PIN_MAP(1,14)
#define LCD_QSPI_IO2_PIN   NRF_GPIO_PIN_MAP(1,13)
#define LCD_QSPI_IO3_PIN   NRF_GPIO_PIN_MAP(1,12)

static void config_qspi_pin_high_drive(void)
{
    
    
        nrf_gpio_cfg(
                LCD_QSPI_SCK_PIN,
                NRF_GPIO_PIN_DIR_INPUT,
                NRF_GPIO_PIN_INPUT_CONNECT,
                NRF_GPIO_PIN_PULLDOWN,
                NRF_GPIO_PIN_H0H1,
                NRF_GPIO_PIN_SENSE_HIGH);
        nrf_gpio_cfg(
                LCD_QSPI_CSN_PIN,
                NRF_GPIO_PIN_DIR_INPUT,
                NRF_GPIO_PIN_INPUT_DISCONNECT,
                NRF_GPIO_PIN_NOPULL,
                NRF_GPIO_PIN_H0H1,
                NRF_GPIO_PIN_NOSENSE);

        nrf_gpio_cfg(
                LCD_QSPI_IO0_PIN,
                NRF_GPIO_PIN_DIR_INPUT,
                NRF_GPIO_PIN_INPUT_DISCONNECT,
                NRF_GPIO_PIN_PULLDOWN,
                NRF_GPIO_PIN_H0H1,
                NRF_GPIO_PIN_NOSENSE);

        nrf_gpio_cfg(
                LCD_QSPI_IO1_PIN,
                NRF_GPIO_PIN_DIR_INPUT,
                NRF_GPIO_PIN_INPUT_DISCONNECT,
                NRF_GPIO_PIN_PULLDOWN,
                NRF_GPIO_PIN_H0H1,
                NRF_GPIO_PIN_NOSENSE);

        nrf_gpio_cfg(
                LCD_QSPI_IO2_PIN,
                NRF_GPIO_PIN_DIR_INPUT,
                NRF_GPIO_PIN_INPUT_DISCONNECT,
                NRF_GPIO_PIN_PULLDOWN,
                NRF_GPIO_PIN_H0H1,
                NRF_GPIO_PIN_NOSENSE);

        nrf_gpio_cfg(
                LCD_QSPI_IO3_PIN,
                NRF_GPIO_PIN_DIR_INPUT,
                NRF_GPIO_PIN_INPUT_DISCONNECT,
                NRF_GPIO_PIN_PULLDOWN,
                NRF_GPIO_PIN_H0H1,
                NRF_GPIO_PIN_NOSENSE);
}

Inicialice el módulo QSPI y configúrelo para una dirección de 24 bits/reloj de 32 MHz.

void qspi_lcd_GC9c01_init(void)
{
    
    
        if (!m_is_qspi_init)
        {
    
    
                uint32_t err_code;
                nrf_drv_qspi_config_t qspi_lcd_config = NRF_DRV_QSPI_DEFAULT_CONFIG;
                //config.phy_if.sck_freq  = NRF_QSPI_FREQ_32MDIV1;        //NRF_QSPI_FREQ_32MDIV8; //32MHz
                qspi_lcd_config.phy_if.sck_freq  = NRF_QSPI_FREQ_32MDIV1;        //NRF_QSPI_FREQ_32MDIV8; //32MHz
                //qspi_lcd_config.phy_if.sck_freq  = NRF_QSPI_FREQ_32MDIV8;//NRF_QSPI_FREQ_32MDIV8; //8MHz

                qspi_lcd_config.pins.csn_pin     = LCD_QSPI_CSN_PIN;
                qspi_lcd_config.pins.sck_pin     = LCD_QSPI_SCK_PIN;
                qspi_lcd_config.pins.io0_pin     = LCD_QSPI_IO0_PIN;
                qspi_lcd_config.pins.io1_pin     = LCD_QSPI_IO1_PIN;
                qspi_lcd_config.pins.io2_pin     = LCD_QSPI_IO2_PIN;
                qspi_lcd_config.pins.io3_pin     = LCD_QSPI_IO3_PIN;

                err_code = nrf_drv_qspi_init(&qspi_lcd_config, qspi_lcd_handler, NULL);
                APP_ERROR_CHECK(err_code);

                NRF_LOG_INFO("QSPI LCD Init");
                NRF_QSPI->IFCONFIG0 |= (QSPI_IFCONFIG0_PPSIZE_512Bytes << QSPI_IFCONFIG0_PPSIZE_Pos);

                m_is_qspi_init = true;
        }
        else
        {
    
    
                NRF_LOG_ERROR("QSPI LCD has already initialized!");
                APP_ERROR_CHECK(-1);
        }
}

2.2 Operaciones de lectura y escritura

Básicamente, hay 2 operaciones en la pantalla LCD.

Código de comando LCD (por ejemplo, código de inicialización LCD).
Escritura de datos LCD (escribir datos en la pantalla LCD).

(1) Modo de comando LCD
Insertar descripción de la imagen aquí
(2) Comando de escritura LCD

static uint32_t drv_GC9c01_bus_writeCmd(const uint8_t cmd)
{
    
    
        return send_qspi_cinstr_w0d(cmd);
}
static uint32_t drv_GC9c01_bus_writeCmdByte(const uint8_t cmd, const uint8_t data)
{
    
    
        uint32_t err_code = NRF_SUCCESS;
        err_code  = send_qspi_cinstr_w1d(cmd, data);
        return err_code;
}

(3)Código de inicialización de LCD

static void configure_lcd()
{
    
    
        drv_GC9c01_bus_writeCmd(0xfe);
        drv_GC9c01_bus_writeCmd(0xef);

        drv_GC9c01_bus_writeCmdByte(0x80, 0x11);
        drv_GC9c01_bus_writeCmdByte(0x81, 0x70);

        drv_GC9c01_bus_writeCmdByte(0x82, 0x09);
        drv_GC9c01_bus_writeCmdByte(0x83, 0x03);
        
        drv_GC9c01_bus_writeCmdByte(0x84, 0x20);
        drv_GC9c01_bus_writeCmdByte(0x85, 0x42);

        drv_GC9c01_bus_writeCmdByte(0x86, 0xfc);
        drv_GC9c01_bus_writeCmdByte(0x87, 0x09);

        drv_GC9c01_bus_writeCmdByte(0x89, 0x10);
        drv_GC9c01_bus_writeCmdByte(0x8a, 0x4f);

        drv_GC9c01_bus_writeCmdByte(0x8c, 0x59);
        drv_GC9c01_bus_writeCmdByte(0x8d, 0x51);
        
        drv_GC9c01_bus_writeCmdByte(0x8e, 0xae);
        drv_GC9c01_bus_writeCmdByte(0x8f, 0xf3);

        drv_GC9c01_bus_writeCmdByte(0x36, 0x00);
        drv_GC9c01_bus_writeCmdByte(0x3a, 0x05);
        drv_GC9c01_bus_writeCmdByte(0xec, 0x77);

        uint8_t parmater1_buffer[] = {
    
    0x01, 0x80, 0x00, 0x00, 0x00, 0x00};
        send_qspi_cinstr_long_frame_word(0x74, parmater1_buffer, 6);
        drv_GC9c01_bus_writeCmdByte(0x98, 0x3e);
        drv_GC9c01_bus_writeCmdByte(0x99, 0x3e);
        drv_GC9c01_bus_writeCmdByte(0xc3, 0x2A);
        drv_GC9c01_bus_writeCmdByte(0xc4, 0x18);
        send_qspi_cinstr_w1d_2data(0xa1,0x01,0x04);
        send_qspi_cinstr_w1d_2data(0xa2,0x01,0x04);
        drv_GC9c01_bus_writeCmdByte(0xa9, 0x1c);

        send_qspi_cinstr_w1d_2data(0xa5,0x11,0x09);
        drv_GC9c01_bus_writeCmdByte(0xb9, 0x8a);
        drv_GC9c01_bus_writeCmdByte(0xa8, 0x5e);
        drv_GC9c01_bus_writeCmdByte(0xa7, 0x40);
        drv_GC9c01_bus_writeCmdByte(0xaf, 0x73);
        drv_GC9c01_bus_writeCmdByte(0xae, 0x44);
        drv_GC9c01_bus_writeCmdByte(0xad, 0x38);

        drv_GC9c01_bus_writeCmdByte(0xa3, 0x5d);

        drv_GC9c01_bus_writeCmdByte(0xc2, 0x02);

        drv_GC9c01_bus_writeCmdByte(0xc5, 0x11);


        drv_GC9c01_bus_writeCmdByte(0xc6, 0x0e);

        drv_GC9c01_bus_writeCmdByte(0xc7, 0x13);
        drv_GC9c01_bus_writeCmdByte(0xc8, 0x0d);
        drv_GC9c01_bus_writeCmdByte(0xcb, 0x02);

        send_qspi_cinstr_w1d_2data(0x7c,0xb6,0x26);
        drv_GC9c01_bus_writeCmdByte(0xac, 0x24);
        drv_GC9c01_bus_writeCmdByte(0xf6, 0x80);



        send_qspi_cinstr_w1d_2data(0xb5,0x09,0x09);
        send_qspi_cinstr_w1d_4data(0x60, 0x38,0x0b,0x5b,0x56);
        send_qspi_cinstr_w1d_4data(0x63, 0x3a,0xe0,0x5b,0x56);

        uint8_t parmater2_buffer[] = {
    
    0x38, 0x0d, 0x72, 0xdd, 0x5b, 0x56};
        send_qspi_cinstr_long_frame_word(0x64, parmater2_buffer, 6);
        uint8_t parmater3_buffer[] = {
    
    0x38, 0x11, 0x72, 0xe1, 0x5b, 0x56};
        send_qspi_cinstr_long_frame_word(0x66, parmater3_buffer, 6);
        uint8_t parmater4_buffer[] = {
    
    0x3b, 0x08, 0x08, 0x00, 0x08, 0x29,0x5b};
        send_qspi_cinstr_long_frame_word(0x68, parmater4_buffer, 7);
        uint8_t parmater5_buffer[] = {
    
    0x00,0x00,0x00,0x07,0x01,0x13,0x11,0x0b, \
                                      0x09,0x16,0x15,0x1d,0x1e,0x00,0x00,0x00, \
                                      0x00,0x00,0x00,0x1e,0x1d,0x15,0x16,0x0a, \
                                      0x0c,0x12,0x14,0x02,0x08,0x00,0x00,0x00};
        send_qspi_cinstr_long_frame_word(0x6e, parmater5_buffer, 32);

        drv_GC9c01_bus_writeCmdByte(0xbe, 0x11);
        uint8_t parmater6_buffer[] = {
    
    0xcc, 0x0c, 0xcc, 0x84, 0xcc, 0x04,0x50};
        send_qspi_cinstr_long_frame_word(0x6c, parmater6_buffer, 7);
        drv_GC9c01_bus_writeCmdByte(0x7d, 0x72);
        drv_GC9c01_bus_writeCmdByte(0x7e, 0x38);
        uint8_t parmater7_buffer[] = {
    
    0x02,0x03,0x09,0x05,0x0c,0x06,0x09,0x05,0x0c,0x06};
        send_qspi_cinstr_long_frame_word(0x70, parmater7_buffer, 10);
        send_qspi_cinstr_w1d_4data(0x90, 0x06,0x06,0x05,0x06);
        send_qspi_cinstr_w1d_3data(0x93, 0x45,0xff,0x00);

        uint8_t parmater8_buffer[] = {
    
    0x45, 0x09, 0x08, 0x08, 0x26, 0x2a};
        send_qspi_cinstr_long_frame_word(0xf0, parmater8_buffer, 6);
        uint8_t parmater9_buffer[] = {
    
    0x43, 0x70, 0x72, 0x36, 0x37, 0x6f};
        send_qspi_cinstr_long_frame_word(0xf1, parmater9_buffer, 6);
        uint8_t parmater10_buffer[] = {
    
    0x45, 0x09, 0x08, 0x08, 0x26, 0x2a};
        send_qspi_cinstr_long_frame_word(0xf2, parmater10_buffer, 6);
        uint8_t parmater11_buffer[] = {
    
    0x43, 0x70, 0x72, 0x36, 0x37, 0x6f};
        send_qspi_cinstr_long_frame_word(0xf3, parmater11_buffer, 6);
        drv_GC9c01_bus_writeCmd(0xfe);
        drv_GC9c01_bus_writeCmd(0xee);


        // User Command Set (UCS = CMD1)------------------------------------------
        //       drv_GC9c01_bus_writeCmdByte(GC9c01_CMD_WRITE_CMD_MODE_PAGE, 0x00);

        //tearing effect line on--------------------------------------------------
        //       drv_GC9c01_bus_writeCmdByte(GC9c01_CMD_TEARING_EFFECT_ON, 0x00);

        // Interface Pixel Format-------------------------------------------------
        //       drv_GC9c01_bus_writeCmdByte(GC9c01_CMD_INTERFACE_PIXEL_FORMAT, 0x55);// 0x55 -> 565

        // Set_DSPI Mode----------------------------------------------------------
        //       drv_GC9c01_bus_writeCmdByte(GC9c01_CMD_SET_DSPI_MODE, 0x80);

        // Write display brightness-----------------------------------------------
        //GC9c01_drv_SetBrightness(0xCC);


        // Sleep-out and Display on-----------------------------------------------
        GC9c01_DRV_SLEEP_OUT();

        nrf_delay_ms(120);

        GC9c01_DRV_DISPLAY_ON();

        nrf_delay_ms(20);

        GC9c01_drv_setColRowPosition(0, 0);

        NRF_LOG_INFO("After %s", __func__);
}

2.3 Escribir datos LCD

Utiliza Opcode = 0x32 PP4O para escribir datos LCD.
Insertar descripción de la imagen aquí

static uint32_t gc9c01_bus_lcd_write_buffer(uint8_t *p_tx_buffer, uint32_t len, uint32_t addr)
{
    
    
        uint32_t err_code = 0;
        m_finished = false;
        err_code = nrf_drv_qspi_write(p_tx_buffer, len, addr);
        if(err_code != NRFX_SUCCESS)
        {
    
    
                // NRF_LOG_INFO("error code= 0x%x",err_code);
        }
        WAIT_FOR_PERIPH();
        return err_code;
}

static void BMP_picture_show(uint32_t delay, const uint16_t *p_data)
{
    
    
        uint32_t err_code;
        uint32_t * p_color;
        uint32_t i,k;
        uint32_t tran_size,now_size=0;
        uint32_t remain_size = GC9c01_DRV_ALL_SIZE;

        //NRF_LOG_INFO("%s block_dx = %d, Color=%04x", __func__, a block_dx, color);
        //static uint8_t __ALIGN(4) bank_buf[QSPI_PAG_SIZE];

        tran_size = QSPI_PAG_SIZE;
        memcpy(&m_buffer_tx[0], (uint8_t *)&p_data[0]+tran_size, tran_size);
        err_code = gc9c01_bus_lcd_write_buffer(m_buffer_tx, QSPI_PAG_SIZE, 0x002C00);

        remain_size -= tran_size;
        now_size=tran_size;
        while (remain_size)
        {
    
    
                if (remain_size > QSPI_PAG_SIZE)
                {
    
    
                        tran_size = QSPI_PAG_SIZE;
                }
                else
                {
    
    
                        tran_size = remain_size;
                }

                memcpy(m_buffer_tx, (uint8_t *)&p_data[0]+now_size, tran_size);

                now_size += tran_size;
                err_code = gc9c01_bus_lcd_write_buffer(&m_buffer_tx[0], tran_size, 0x003C00);

                remain_size -= tran_size;
        }

        nrf_delay_ms(delay);
}

Mostrar resultados
Insertar descripción de la imagen aquí

Dirección de acceso al enlace de referencia

Supongo que te gusta

Origin blog.csdn.net/zhi_Alanwu/article/details/128127421
Recomendado
Clasificación