O_K210_ST7789屏幕CSDK驱动移植


O_嵌入式专题目录


本文基于Sipeed MaxiDockM1W开发板,SDK为堪智官方standalone,屏幕驱动改自官方kendryte_lcd-nt35310-standalone-driver。

主要涉及引脚

  • LCD_D0 - LCD_D7 默认接到K210的LCD8位并行接口,无需特殊配置。
  • LCD_WR - IO39 - CLK
  • LCD_DC - IO38 - DCX
  • LCD_RST - IO37 - RST
  • LCD_CS - IO36 - SS3
1
2
3
4
// fpioa_set_function(37, FUNC_GPIOHS0 + RST_GPIONUM);  //HS3
// fpioa_set_function(38, FUNC_GPIOHS0 + DCX_GPIONUM); //HS2
// fpioa_set_function(36, FUNC_SPI0_SS0 + LCD_SPI_SLAVE_SELECT); //SS3
// fpioa_set_function(39, FUNC_SPI0_SCLK);

device-manager.json

1
2
3
4
5
6
7
8
9
10
11
{
"funcPinMap": {
"UART1_RX": "H12",
"UART1_TX": "G11",
"GPIOHS2": "B2",
"GPIOHS3": "A1",
"SPI0_SCLK": "B1",
"SPI0_SS3": "A2"
},
"selectedChip": "Kendryte K210"
}

fpioa-config.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <fpioa.h>
#include "fpioa-config.h"

int ide_config_fpioa() {
int ret = 0;

ret += fpioa_set_function(5, FUNC_UART1_RX);
ret += fpioa_set_function(6, FUNC_UART1_TX);
ret += fpioa_set_function(38, FUNC_GPIOHS2);
ret += fpioa_set_function(37, FUNC_GPIOHS3);
ret += fpioa_set_function(39, FUNC_SPI0_SCLK);
ret += fpioa_set_function(36, FUNC_SPI0_SS3);

return ret;
}

main.c 配置代码

1
2
3
4
5
6
7
8
// 开启IO36-IO41的电源域
sysctl_set_power_mode(SYSCTL_POWER_BANK6, SYSCTL_POWER_V18);
// 开启SPI0的数据功能
sysctl_set_spi0_dvp_data(1);
// 初始化液晶屏
lcd_init();
// 屏幕填充为红色
lcd_clear(RED);

lcd.c

  • 这里主要是调颜色。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    #define LCD_SWAP_COLOR_BYTES 1

    #define SWAP_16(x) ((x >> 8 & 0xff) | (x << 8))
    #if LCD_SWAP_COLOR_BYTES
    static const uint16_t gray2rgb565[64] = {
    0x0000, 0x0020, 0x0841, 0x0861, 0x1082, 0x10a2, 0x18c3, 0x18e3,
    0x2104, 0x2124, 0x2945, 0x2965, 0x3186, 0x31a6, 0x39c7, 0x39e7,
    0x4208, 0x4228, 0x4a49, 0x4a69, 0x528a, 0x52aa, 0x5acb, 0x5aeb,
    0x630c, 0x632c, 0x6b4d, 0x6b6d, 0x738e, 0x73ae, 0x7bcf, 0x7bef,
    0x8410, 0x8430, 0x8c51, 0x8c71, 0x9492, 0x94b2, 0x9cd3, 0x9cf3,
    0xa514, 0xa534, 0xad55, 0xad75, 0xb596, 0xb5b6, 0xbdd7, 0xbdf7,
    0xc618, 0xc638, 0xce59, 0xce79, 0xd69a, 0xd6ba, 0xdedb, 0xdefb,
    0xe71c, 0xe73c, 0xef5d, 0xef7d, 0xf79e, 0xf7be, 0xffdf, 0xffff,
    };
    #else
    static const uint16_t gray2rgb565[64] = {
    0x0000, 0x2000, 0x4108, 0x6108, 0x8210, 0xa210, 0xc318, 0xe318,
    0x0421, 0x2421, 0x4529, 0x6529, 0x8631, 0xa631, 0xc739, 0xe739,
    0x0842, 0x2842, 0x494a, 0x694a, 0x8a52, 0xaa52, 0xcb5a, 0xeb5a,
    0x0c63, 0x2c63, 0x4d6b, 0x6d6b, 0x8e73, 0xae73, 0xcf7b, 0xef7b,
    0x1084, 0x3084, 0x518c, 0x718c, 0x9294, 0xb294, 0xd39c, 0xf39c,
    0x14a5, 0x34a5, 0x55ad, 0x75ad, 0x96b5, 0xb6b5, 0xd7bd, 0xf7bd,
    0x18c6, 0x38c6, 0x59ce, 0x79ce, 0x9ad6, 0xbad6, 0xdbde, 0xfbde,
    0x1ce7, 0x3ce7, 0x5def, 0x7def, 0x9ef7, 0xbef7, 0xdfff, 0xffff,
    };
    #endif
  • lcd_init
    (貌似不添加这两行也可以。)

    1
    2
    3
    4
    5
    6
    7
    8
    lcd_set_direction(DIR_YX_RLUD);

    tft_write_command(NORMAL_DISPALY_ON);
    usleep(100000);

    /*display on*/
    tft_write_command(DISPALY_ON);
    lcd_polling_enable();
  • lcd_draw_point

    1
    2
    3
    lcd_set_area(x, y, x, y);
    // tft_write_half(&color, 1);
    tft_write_byte((uint8_t *)&color, 2);
  • lcd_draw_string / lcd_clear
    (函数开始处添加。)

    1
    2
    3
    #if LCD_SWAP_COLOR_BYTES
    color = SWAP_16(color);
    #endif
  • lcd_fill_rectangle
    (函数开始处添加。)

    1
    2
    3
    4
    5
    6
    7
        if ((x1 == x2) || (y1 == y2))
    return;
    #if LCD_SWAP_COLOR_BYTES
    color = SWAP_16(color);
    #endif
    uint32_t data = ((uint32_t)color << 16) | (uint32_t)color;
    // uint32_t data = color | (color << 16);
  • lcd_draw_rectangle
    (函数开始处添加。)

    1
    2
    3
    4
    5
    6
    7
    8
        // uint32_t data = color;
    uint32_t data;
    #if LCD_SWAP_COLOR_BYTES
    color = SWAP_16(color);
    #endif

    data = ((uint32_t)color << 16) | color;
    // data = (data << 16) | data;

st7789.h

  • 在本文件添加或在库内kendryte-package.json定义C、C++常量。
    1
    2
    3
    4
    5
    #define DCX_GPIONUM             (2)
    #define RST_GPIONUM (3)
    #define SPI_CHANNEL 0
    #define SPI_DMA_CH DMAC_CHANNEL1
    #define SPI_SLAVE_SELECT 3

st7789.c

  • 本文件内的所有 DMAC_CHANNEL0 替换为 SPI_DMA_CH ,即之前定义的 DMAC_CHANNEL1

  • 添加rst函数。

    1
    2
    3
    4
    5
    6
    7
    static void init_rst(void)
    {
    gpiohs_set_drive_mode(RST_GPIONUM, GPIO_DM_OUTPUT);
    gpiohs_set_pin(RST_GPIONUM, GPIO_PV_HIGH);
    }

    static void set_rst(uint8_t val) { gpiohs_set_pin(RST_GPIONUM, val); }
  • tft_hard_init

    1
    2
    3
    4
    5
    6
    7
    8
    9
    init_dcx();
    init_rst();
    set_rst(0);
    spi_init(SPI_CHANNEL, SPI_WORK_MODE_0, SPI_FF_STANDARD, 8, 0);
    // spi_set_clk_rate(SPI_CHANNEL, 25000000); //速率太高貌似有问题
    spi_set_clk_rate(SPI_CHANNEL, 15000000);
    msleep(50);
    set_rst(1);
    msleep(50);
  • SPI_FF_STANDARD 标准
  • SPI_FF_DUAL 双线
  • SPI_FF_QUAD 四线
  • SPI_FF_OCTAL 八线(SPI3不支持)