【DigiKey&amp】NXP FRDM-MCXA153 SPI LCD 驱动

使用 FRDM-MCXA153 开发板驱动SPI LCD屏幕

  • 版本说明
    • SDK版本:25_06_00
    • Keil MDK版本:5.42.0
    • Config Tool版本:25.6

硬件条件

这里使用的是一块驱动芯片为 ST7789 的 SPI 接口 1.3 寸小屏幕,分辨率为240*240,通过FRDM-MCXA153 开发板上面的Arduino接口和屏幕底板进行连接,对应引脚如下。

屏幕底板 MCU引脚
SCL P2_12
BL P2_16
SDA P2_13
CS P2_6
DC P3_14
RES P3_15

软件开发

使用 MCUXpresso Config Tool 工具配置好对应的几个管脚,除了 SPI 的 MCLK、MOSI 外均为输出模式

然后根据 ST7789 的芯片手册,编写写命令和写内存的两个函数,代码如下

void LPSPI_WriteCommand(uint8_t command, const uint8_t *params, uint8_t param_len)
{
    lpspi_transfer_t masterXfer;
    uint32_t i;
    /* Set up the transfer data */
    for (i = 0U; i < TRANSFER_SIZE; i++)
    {
        masterTxData[i] = 0U;
    }
    masterTxData[0] = command;
    /*Start master transfer*/
    masterXfer.txData   = masterTxData;
    masterXfer.rxData   = NULL;
    masterXfer.dataSize = 1;
    masterXfer.configFlags =
        EXAMPLE_LPSPI_MASTER_PCS_FOR_TRANSFER | kLPSPI_MasterPcsContinuous | kLPSPI_MasterByteSwap;
    GPIO_PinWrite(BOARD_INITPINS_DC_GPIO, BOARD_INITPINS_DC_GPIO_PIN, 0); /* command */
    GPIO_PinWrite(BOARD_INITPINS_CS_GPIO, BOARD_INITPINS_CS_GPIO_PIN, 0); /* command */
    LPSPI_MasterTransferBlocking(EXAMPLE_LPSPI_MASTER_BASEADDR, &masterXfer);

    for (i = 0U; i < param_len; i++)
    {
        masterTxData[i] = params[i];
    }
    masterXfer.dataSize = param_len;
    GPIO_PinWrite(BOARD_INITPINS_DC_GPIO, BOARD_INITPINS_DC_GPIO_PIN, 1); /* command */
    LPSPI_MasterTransferBlocking(EXAMPLE_LPSPI_MASTER_BASEADDR, &masterXfer);

    GPIO_PinWrite(BOARD_INITPINS_CS_GPIO, BOARD_INITPINS_CS_GPIO_PIN, 1); /* command */
}

void LPSPI_WriteMemory(uint16_t *data, uint32_t len)
{
    lpspi_transfer_t masterXfer;
    uint32_t i;

    masterXfer.txData   = (uint8_t *)data;
    masterXfer.rxData   = NULL;
    masterXfer.dataSize = len * 2;
    masterXfer.configFlags =
        EXAMPLE_LPSPI_MASTER_PCS_FOR_TRANSFER | kLPSPI_MasterPcsContinuous | kLPSPI_MasterByteSwap;
    GPIO_PinWrite(BOARD_INITPINS_DC_GPIO, BOARD_INITPINS_DC_GPIO_PIN, 1); /* command */
    GPIO_PinWrite(BOARD_INITPINS_CS_GPIO, BOARD_INITPINS_CS_GPIO_PIN, 0); /* command */
    LPSPI_MasterTransferBlocking(EXAMPLE_LPSPI_MASTER_BASEADDR, &masterXfer);

    GPIO_PinWrite(BOARD_INITPINS_CS_GPIO, BOARD_INITPINS_CS_GPIO_PIN, 1); /* command */
}

然后从 NXP的另一款 MCU —— N947 的 SDK 中复制出来 ST7796S的驱动代码进行修改,将头文件中原有的句柄结构体改成如下

/*! @brief ST7789 driver handle structure */
typedef struct _st7789_handle
{
    void (*writeCommand)(uint8_t, const uint8_t *, uint8_t);
    void (*writeMemory)(uint16_t *, uint32_t);
    st7789_orientation_mode_t orientationMode; /*!< Current orientation mode */
} st7789_handle_t;

然后按如下步骤操作:

  • 修改ST7796S的初始化序列,改为ST7789的初始化序列
  • 按照原本的驱动框架进行注册、初始化
  • 绘制像素、填充整个屏幕

将原本的初始化序列修改,使用ST7789的序列

static const uint8_t s_st7789_driver_preset_pars035[] = {
    0x01, 0x36, 0x00,
    0x01, 0x3a, 0x55,
    //--------------------------------ST7789S Frame rate setting----------------------------------//
    0x05, 0xb2, 0x0c, 0x0c, 0x00, 0x33, 0x33,
    0x01, 0xb7, 0x35,
    //---------------------------------ST7789S Power setting--------------------------------------//
    0x01, 0xbb, 0x28,
    0x01, 0xc0, 0x2c,
    0x01, 0xc2, 0x01,
    0x01, 0xc3, 0x0b,
    0x01, 0xc4, 0x20,
    0x01, 0xc6, 0x0f,
    0x02, 0xd0, 0xa4, 0xa1,
    //--------------------------------ST7789S gamma setting---------------------------------------//
    0x0e, 0xe0, 0xd0, 0x01, 0x08, 0x0f, 0x11, 0x2a, 0x36, 0x55, 0x44, 0x3a, 0x0b, 0x06, 0x11, 0x20,
    0x0e, 0xe1, 0xd0, 0x02, 0x07, 0x0a, 0x0b, 0x18, 0x34, 0x43, 0x4a, 0x2b, 0x1b, 0x1c, 0x22, 0x1f,
    0x00, 0x11,

    0x01, 0x29,
};

然后在main函数中完成对于屏幕的初始化,代码如下,完成屏幕的上电复位、初始化、框选整个屏幕等操作

st7789_handle_t g_st7789_handle = {
    .writeCommand = LPSPI_WriteCommand,
    .writeMemory = LPSPI_WriteMemory,
};
st7789_config_t g_st7789_config = {
    .pixelFormat   = kST7789_PixelFormatRGB565,
    .teConfig      = kST7789_TEDisabled,
    .driverPreset  = kST7789_DriverPresetLCDPARS035,
    .orientationMode = kST7789_Orientation0,
    .invertDisplay = false,
    .flipDisplay   = false,
    .bgrFilter     = false,
};
/* reset lcd */
GPIO_PinWrite(BOARD_INITPINS_RES_GPIO, BOARD_INITPINS_RES_GPIO_PIN, 0);
SDK_DelayAtLeastUs(100000, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
GPIO_PinWrite(BOARD_INITPINS_RES_GPIO, BOARD_INITPINS_RES_GPIO_PIN, 1);

ST7789_Init(&g_st7789_handle, &g_st7789_config);
ST7789_InvertDisplay(&g_st7789_handle, true);
ST7789_EnableDisplay(&g_st7789_handle, true);
ST7789_SelectArea(&g_st7789_handle, 0, 0, 239, 239);
ST7789_StartPaint(&g_st7789_handle);

此时已经框选了整个屏幕,可以直接对整个屏幕进行写 memory 的操作,也就是对整个屏幕全屏刷新,这里代码实现了每隔1s就会变换红、绿、蓝三种颜色

for (size_t i = 0; i < 240; i++) {
    for (size_t j = 0; j < 480; j += 2) {
        masterTxData[j] = 0xf800 >> 8;
        masterTxData[j + 1] = 0xf800 & 0xff;
    }
    ST7789_WritePixels(&g_st7789_handle, (uint16_t *)masterTxData, 240);
}
SDK_DelayAtLeastUs(1000000, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
for (size_t i = 0; i < 240; i++) {
    for (size_t j = 0; j < 480; j += 2) {
        masterTxData[j] = 0x07E0 >> 8;
        masterTxData[j + 1] = 0x07E0 & 0xff;
    }
    ST7789_WritePixels(&g_st7789_handle, (uint16_t *)masterTxData, 240);
}
SDK_DelayAtLeastUs(1000000, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
for (size_t i = 0; i < 240; i++) {
    for (size_t j = 0; j < 480; j += 2) {
        masterTxData[j] = 0x001f >> 8;
        masterTxData[j + 1] = 0x001f & 0xff;
    }
    ST7789_WritePixels(&g_st7789_handle, (uint16_t *)masterTxData, 240);
}
SDK_DelayAtLeastUs(1000000, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);

实现的效果如下视频所示,几种颜色不断的变换,对这块的 SPI LCD 驱动 demo 就完成了

图3:测试屏幕刷新效果