这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 基于ZephyrRTOSMiKroBUS驱动NV3022

共2条 1/1 1 跳转至

基于ZephyrRTOSMiKroBUS驱动NV3022

高工
2026-03-29 19:34:29     打赏

【前言】

MikroBUS™ 是由 MikroElektronika (MIKROE) 公司发明并推广的一种标准化硬件接口规范。它的核心目标是简化嵌入式系统的原型开发,让开发者能够像搭积木一样,快速、便捷地将各种功能模块(被称为“Click板”)连接到主控制器,最近拿到NXP的FRDM_MCX一系列开发板都有这种接口。刚好朋友做好了一块这个接口的的LCD屏。因此决定添加一个基于这个接口的驱动。

【硬件平台】

Zephyr RTOS + NXP MCXA346

LCD屏:

  - 分辨率:70 x 160

  - 像素格式:RGB565

  - 通信接口:SPI 4-wire + DC GPIO

【硬件连接】

LCD 模块到 FRDM-MCXA346 开发板的连接:

  LCD Module    FRDM-MCXA346 Pin

  VCC          3.3V

  GND          GND

  MOSI (SDI)   P1_0 (LPSPI0_SDO)

  SCK          P1_1 (LPSPI0_SCK)

  MISO (SDO)   P1_2 (LPSPI0_SDI)

  CS           P1_3 (LPSPI0_PCS0)

  DC           P1_6 (GPIO1_IO6)

  RST          P1_7 (GPIO1_IO7)

  BL           P2_5 (GPIO2_IO5)

【驱动目录结构

由于我官方没有这款屏的驱动,但是添加到官方驱动有点麻烦,现在采取一个简单的方式,在app下面新建库的目录:


app/modules/nv3022/
├── nv3022.h          # 公共头文件
├── nv3022.c          # 驱动实现
├── CMakeLists.txt      # 构建配置
└── README.md          # 使用文档

【驱动源代码】

nv3022.h

/*
 * NV3022 LCD Driver Library
 * Reusable driver for NV3022 1.28" Round LCD (70x160)
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#ifndef __NV3022_H__
#define __NV3022_H__

#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/spi.h>

/* Display dimensions */
#define NV3022_WIDTH     70
#define NV3022_HEIGHT    160
#define NV3022_X_OFFSET  29
#define NV3022_Y_OFFSET  0

/* RGB565 Color definitions */
#define NV3022_COLOR_WHITE   0xFFFF
#define NV3022_COLOR_BLACK   0x0000
#define NV3022_COLOR_BLUE    0x001F
#define NV3022_COLOR_RED     0xF800
#define NV3022_COLOR_GREEN   0x07E0
#define NV3022_COLOR_YELLOW  0xFFE0
#define NV3022_COLOR_CYAN    0x07FF
#define NV3022_COLOR_MAGENTA 0xF81F

/**
 * @brief NV3022 configuration struct
 *
 * This struct holds all hardware configuration needed to communicate
 * with the NV3022 display.
 */
struct nv3022_config {
    /* Reset GPIO pin (active high) */
    const struct device *rst_gpio;
    uint8_t rst_pin;

    /* Data/Command GPIO pin */
    const struct device *dc_gpio;
    uint8_t dc_pin;

    /* SPI device */
    const struct device *spi_dev;

    /* SPI configuration (frequency, mode, etc.) */
    struct spi_config spi_cfg;
};

/**
 * @brief Initialize the NV3022 LCD.
 *
 * @param cfg  Configuration struct pointer
 * @return 0 on success, negative errno on failure
 */
int nv3022_init(const struct nv3022_config *cfg);

/**
 * @brief Clear the entire screen with a solid color.
 *
 * @param cfg   Configuration struct pointer
 * @param color RGB565 color (e.g., NV3022_COLOR_BLACK)
 */
void nv3022_clear(const struct nv3022_config *cfg, uint16_t color);

/**
 * @brief Fill a rectangle with a solid color.
 *
 * @param cfg   Configuration struct pointer
 * @param x0    Start X coordinate
 * @param y0    Start Y coordinate
 * @param x1    End X coordinate (inclusive)
 * @param y1    End Y coordinate (inclusive)
 * @param color RGB565 color
 */
void nv3022_fill(const struct nv3022_config *cfg,
                 uint16_t x0, uint16_t y0,
                 uint16_t x1, uint16_t y1,
                 uint16_t color);

/**
 * @brief Draw a single pixel.
 *
 * @param cfg   Configuration struct pointer
 * @param x     X coordinate
 * @param y     Y coordinate
 * @param color RGB565 color
 */
void nv3022_draw_pixel(const struct nv3022_config *cfg,
                       uint16_t x, uint16_t y, uint16_t color);

/**
 * @brief Display a null-terminated string.
 *
 * @param cfg   Configuration struct pointer
 * @param x     Start X coordinate
 * @param y     Start Y coordinate
 * @param str   Null-terminated string
 * @param fc    Foreground color (RGB565)
 * @param bc    Background color (RGB565)
 */
void nv3022_show_string(const struct nv3022_config *cfg,
                        uint16_t x, uint16_t y,
                        const char *str,
                        uint16_t fc, uint16_t bc);

/**
 * @brief Display a single character.
 *
 * @param cfg   Configuration struct pointer
 * @param x     X coordinate
 * @param y     Y coordinate
 * @param ch    Character to display
 * @param fc    Foreground color (RGB565)
 * @param bc    Background color (RGB565)
 */
void nv3022_show_char(const struct nv3022_config *cfg,
                      uint16_t x, uint16_t y,
                      char ch, uint16_t fc, uint16_t bc);

#endif /* __NV3022_H__ */

nv3022.c

/*
 * NV3022 LCD Driver Library Implementation
 * SPDX-License-Identifier: Apache-2.0
 */

#include <stdio.h>
#include <stdint.h>
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/kernel.h>
#include "nv3022.h"

/* ---- Private helpers ---- */

static void delay_ms(uint32_t ms)
{
    k_msleep(ms);
}

static void lcd_write_cmd(const struct nv3022_config *cfg, uint8_t cmd)
{
    int ret;
    uint8_t tx_buf[1] = {cmd};

    gpio_pin_set(cfg->dc_gpio, cfg->dc_pin, 0);

    struct spi_buf buf = {
        .buf = tx_buf,
        .len = 1
    };
    struct spi_buf_set tx = {
        .buffers = &buf,
        .count = 1
    };

    ret = spi_transceive(cfg->spi_dev, &cfg->spi_cfg, &tx, NULL);
    if (ret < 0) {
        printf("NV3022: SPI cmd error: %d\n", ret);
    }
}

static void lcd_write_data(const struct nv3022_config *cfg, uint8_t data)
{
    int ret;
    uint8_t tx_buf[1] = {data};

    gpio_pin_set(cfg->dc_gpio, cfg->dc_pin, 1);

    struct spi_buf buf = {
        .buf = tx_buf,
        .len = 1
    };
    struct spi_buf_set tx = {
        .buffers = &buf,
        .count = 1
    };

    ret = spi_transceive(cfg->spi_dev, &cfg->spi_cfg, &tx, NULL);
    if (ret < 0) {
        printf("NV3022: SPI data error: %d\n", ret);
    }
}

static void lcd_write_data16(const struct nv3022_config *cfg, uint16_t data)
{
    int ret;
    uint8_t tx_buf[2] = {
        (data >> 8) & 0xFF,
        data & 0xFF
    };

    gpio_pin_set(cfg->dc_gpio, cfg->dc_pin, 1);

    struct spi_buf buf = {
        .buf = tx_buf,
        .len = 2
    };
    struct spi_buf_set tx = {
        .buffers = &buf,
        .count = 1
    };

    ret = spi_transceive(cfg->spi_dev, &cfg->spi_cfg, &tx, NULL);
    if (ret < 0) {
        printf("NV3022: SPI data16 error: %d\n", ret);
    }
}

static void lcd_reset(const struct nv3022_config *cfg)
{
    gpio_pin_set(cfg->rst_gpio, cfg->rst_pin, 1);
    delay_ms(10);
    gpio_pin_set(cfg->rst_gpio, cfg->rst_pin, 0);
    delay_ms(200);
    gpio_pin_set(cfg->rst_gpio, cfg->rst_pin, 1);
    delay_ms(120);
}

static void lcd_set_window(const struct nv3022_config *cfg,
               uint16_t xStar, uint16_t yStar,
               uint16_t xEnd, uint16_t yEnd)
{
    xStar += NV3022_X_OFFSET;
    xEnd  += NV3022_X_OFFSET;
    yStar += NV3022_Y_OFFSET;
    yEnd  += NV3022_Y_OFFSET;

    lcd_write_cmd(cfg, 0x2A);
    lcd_write_data(cfg, (xStar >> 8));
    lcd_write_data(cfg, (xStar & 0xFF));
    lcd_write_data(cfg, (xEnd >> 8));
    lcd_write_data(cfg, (xEnd & 0xFF));

    lcd_write_cmd(cfg, 0x2B);
    lcd_write_data(cfg, (yStar >> 8));
    lcd_write_data(cfg, (yStar & 0xFF));
    lcd_write_data(cfg, (yEnd >> 8));
    lcd_write_data(cfg, (yEnd & 0xFF));

    lcd_write_cmd(cfg, 0x2C);
}

/* ---- 8x16 ASCII font ---- */

static const unsigned char asc2_1608[95][16] = {
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x00,0x00,0x08,0x08,0x00,0x00},
    {0x00,0x00,0x08,0x08,0x08,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x14,0x14,0x14,0x3E,0x14,0x14,0x3E,0x14,0x14,0x14,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x08,0x1C,0x2A,0x2A,0x0A,0x0C,0x18,0x28,0x2A,0x2A,0x1C,0x08,0x08},
    {0x00,0x00,0x00,0x22,0x25,0x25,0x12,0x08,0x04,0x24,0x52,0x52,0x22,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x0C,0x12,0x12,0x12,0x0A,0x14,0x24,0x22,0x22,0x22,0x1D,0x00,0x00},
    {0x00,0x00,0x00,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x08,0x10,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x10,0x08,0x00,0x00},
    {0x00,0x00,0x00,0x10,0x08,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x10,0x00,0x00},
    {0x00,0x00,0x00,0x00,0x08,0x2A,0x1C,0x08,0x1C,0x2A,0x08,0x00,0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00,0x08,0x08,0x08,0x3E,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x10,0x00},
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x00,0x00},
    {0x00,0x00,0x00,0x02,0x02,0x04,0x04,0x08,0x08,0x10,0x10,0x20,0x20,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x18,0x24,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x24,0x18,0x00,0x00},
    {0x00,0x00,0x00,0x08,0x38,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x3E,0x00,0x00},
    {0x00,0x00,0x00,0x3C,0x42,0x42,0x02,0x04,0x08,0x10,0x20,0x40,0x42,0x7E,0x00,0x00},
    {0x00,0x00,0x00,0x3C,0x42,0x42,0x02,0x1C,0x02,0x02,0x02,0x42,0x42,0x3C,0x00,0x00},
    {0x00,0x00,0x00,0x04,0x0C,0x14,0x24,0x24,0x44,0x44,0x7E,0x04,0x04,0x1E,0x00,0x00},
    {0x00,0x00,0x00,0x7E,0x40,0x40,0x40,0x7C,0x02,0x02,0x02,0x42,0x42,0x3C,0x00,0x00},
    {0x00,0x00,0x00,0x1C,0x24,0x40,0x40,0x5C,0x62,0x42,0x42,0x42,0x22,0x1C,0x00,0x00},
    {0x00,0x00,0x00,0x7E,0x02,0x02,0x04,0x04,0x08,0x08,0x10,0x10,0x10,0x10,0x00,0x00},
    {0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x24,0x18,0x24,0x42,0x42,0x42,0x3C,0x00,0x00},
    {0x00,0x00,0x00,0x38,0x44,0x42,0x42,0x42,0x46,0x3A,0x02,0x02,0x24,0x38,0x00,0x00},
    {0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x00,0x00,0x00,0x00,0x08,0x08,0x00,0x00},
    {0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x00,0x00,0x00,0x00,0x08,0x08,0x10,0x00},
    {0x00,0x00,0x00,0x02,0x04,0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x04,0x02,0x00,0x00},
    {0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x40,0x20,0x10,0x08,0x04,0x02,0x04,0x08,0x10,0x20,0x40,0x00,0x00},
    {0x00,0x00,0x00,0x3C,0x42,0x42,0x02,0x04,0x08,0x08,0x00,0x00,0x08,0x08,0x00,0x00},
    {0x00,0x00,0x00,0x3C,0x42,0x42,0x4E,0x52,0x52,0x52,0x4E,0x40,0x42,0x3C,0x00,0x00},
    {0x00,0x00,0x00,0x08,0x14,0x22,0x22,0x22,0x3E,0x22,0x22,0x22,0x22,0x22,0x00,0x00},
    {0x00,0x00,0x00,0x3C,0x22,0x22,0x22,0x3C,0x22,0x22,0x22,0x22,0x22,0x3C,0x00,0x00},
    {0x00,0x00,0x00,0x1E,0x22,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x22,0x1E,0x00,0x00},
    {0x00,0x00,0x00,0x38,0x24,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x24,0x38,0x00,0x00},
    {0x00,0x00,0x00,0x7E,0x20,0x20,0x20,0x3C,0x20,0x20,0x20,0x20,0x20,0x7E,0x00,0x00},
    {0x00,0x00,0x00,0x7E,0x20,0x20,0x20,0x3C,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00},
    {0x00,0x00,0x00,0x3C,0x22,0x40,0x40,0x40,0x40,0x4E,0x42,0x42,0x22,0x1C,0x00,0x00},
    {0x00,0x00,0x00,0x22,0x22,0x22,0x22,0x3E,0x22,0x22,0x22,0x22,0x22,0x22,0x00,0x00},
    {0x00,0x00,0x00,0x3E,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x3E,0x00,0x00},
    {0x00,0x00,0x00,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x22,0x1C,0x00,0x00},
    {0x00,0x00,0x00,0x20,0x22,0x24,0x28,0x30,0x20,0x30,0x28,0x24,0x22,0x22,0x00,0x00},
    {0x00,0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x7E,0x00,0x00},
    {0x00,0x00,0x00,0x42,0x66,0x5A,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x00,0x00},
    {0x00,0x00,0x00,0x22,0x22,0x32,0x2A,0x26,0x22,0x22,0x22,0x22,0x22,0x22,0x00,0x00},
    {0x00,0x00,0x00,0x1C,0x22,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x22,0x1C,0x00,0x00},
    {0x00,0x00,0x00,0x3C,0x22,0x22,0x22,0x3C,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00},
    {0x00,0x00,0x00,0x1C,0x22,0x41,0x41,0x41,0x41,0x41,0x49,0x45,0x22,0x1D,0x00,0x00},
    {0x00,0x00,0x00,0x3C,0x22,0x22,0x22,0x3C,0x28,0x24,0x22,0x22,0x22,0x22,0x00,0x00},
    {0x00,0x00,0x00,0x1E,0x22,0x40,0x40,0x3E,0x02,0x02,0x02,0x02,0x22,0x1C,0x00,0x00},
    {0x00,0x00,0x00,0x7F,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x00,0x00},
    {0x00,0x00,0x00,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x1C,0x00,0x00},
    {0x00,0x00,0x00,0x22,0x22,0x22,0x22,0x22,0x22,0x14,0x14,0x08,0x08,0x08,0x00,0x00},
    {0x00,0x00,0x00,0x41,0x41,0x41,0x41,0x41,0x49,0x49,0x49,0x49,0x55,0x22,0x00,0x00},
    {0x00,0x00,0x00,0x42,0x24,0x24,0x18,0x18,0x18,0x18,0x24,0x24,0x42,0x42,0x00,0x00},
    {0x00,0x00,0x00,0x41,0x22,0x14,0x14,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x00,0x00},
    {0x00,0x00,0x00,0x7E,0x02,0x04,0x04,0x08,0x08,0x10,0x10,0x20,0x20,0x7E,0x00,0x00},
    {0x00,0x00,0x00,0x18,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x18,0x00},
    {0x00,0x00,0x00,0x20,0x20,0x10,0x10,0x08,0x08,0x04,0x04,0x02,0x02,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x18,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x18,0x00},
    {0x00,0x00,0x00,0x08,0x14,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF},
    {0x00,0x00,0x00,0x10,0x08,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x02,0x02,0x3E,0x42,0x42,0x3E,0x00,0x00},
    {0x00,0x00,0x00,0x20,0x20,0x20,0x20,0x3C,0x22,0x22,0x22,0x22,0x22,0x3C,0x00,0x00},
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x22,0x40,0x40,0x40,0x22,0x1E,0x00,0x00},
    {0x00,0x00,0x00,0x02,0x02,0x02,0x02,0x1E,0x22,0x42,0x42,0x42,0x22,0x1E,0x00,0x00},
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x7E,0x40,0x42,0x3C,0x00,0x00},
    {0x00,0x00,0x00,0x0E,0x11,0x10,0x10,0x3E,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00},
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x42,0x42,0x42,0x3E,0x02,0x42,0x3C,0x00},
    {0x00,0x00,0x00,0x20,0x20,0x20,0x20,0x3A,0x26,0x22,0x22,0x22,0x22,0x22,0x00,0x00},
    {0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x18,0x08,0x08,0x08,0x08,0x08,0x1C,0x00,0x00},
    {0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x0C,0x04,0x04,0x04,0x04,0x04,0x24,0x18,0x00},
    {0x00,0x00,0x00,0x20,0x20,0x20,0x20,0x22,0x24,0x28,0x30,0x28,0x24,0x22,0x00,0x00},
    {0x00,0x00,0x00,0x18,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x1C,0x00,0x00},
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x49,0x49,0x49,0x49,0x49,0x49,0x00,0x00},
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2E,0x32,0x22,0x22,0x22,0x22,0x22,0x00,0x00},
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x22,0x22,0x22,0x22,0x22,0x1C,0x00,0x00},
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3A,0x26,0x22,0x22,0x22,0x3A,0x20,0x20,0x00},
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x22,0x22,0x22,0x22,0x1E,0x02,0x02,0x00},
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2E,0x32,0x20,0x20,0x20,0x20,0x20,0x00,0x00},
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x22,0x30,0x0C,0x02,0x22,0x1C,0x00,0x00},
    {0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x3E,0x10,0x10,0x10,0x10,0x10,0x0C,0x00,0x00},
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x22,0x22,0x22,0x22,0x22,0x22,0x1E,0x00,0x00},
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x22,0x22,0x22,0x14,0x14,0x08,0x08,0x00,0x00},
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x41,0x49,0x49,0x49,0x55,0x22,0x00,0x00},
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x24,0x18,0x18,0x24,0x42,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x22,0x22,0x22,0x12,0x0A,0x04,0x08,0x10,0x00},
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x04,0x08,0x10,0x20,0x40,0x7E,0x00,0x00},
    {0x00,0x00,0x00,0x0E,0x10,0x10,0x10,0x20,0x10,0x10,0x10,0x10,0x10,0x0E,0x00,0x00},
    {0x00,0x00,0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x00},
    {0x00,0x00,0x00,0x38,0x04,0x04,0x04,0x02,0x04,0x04,0x04,0x04,0x04,0x38,0x00,0x00},
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x54,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
};

/* ---- Public API ---- */

int nv3022_init(const struct nv3022_config *cfg)
{
    printf("NV3022: Starting initialization...\n");

    lcd_reset(cfg);

    /* Extended command sequence */
    lcd_write_cmd(cfg, 0xff);
    lcd_write_data(cfg, 0xa5);
    lcd_write_cmd(cfg, 0x3a);
    lcd_write_data(cfg, 0x65);
    lcd_write_cmd(cfg, 0x51);
    lcd_write_data(cfg, 0x14);
    lcd_write_cmd(cfg, 0x53);
    lcd_write_data(cfg, 0x11);
    lcd_write_cmd(cfg, 0x62);
    lcd_write_data(cfg, 0x10);
    lcd_write_cmd(cfg, 0x86);
    lcd_write_data(cfg, 0x01);
    lcd_write_cmd(cfg, 0x87);
    lcd_write_data(cfg, 0x1e);
    lcd_write_cmd(cfg, 0x88);
    lcd_write_data(cfg, 0x2b);
    lcd_write_cmd(cfg, 0x89);
    lcd_write_data(cfg, 0x3c);
    lcd_write_cmd(cfg, 0x61);
    lcd_write_data(cfg, 0x10);
    lcd_write_cmd(cfg, 0x93);
    lcd_write_data(cfg, 0x12);
    lcd_write_cmd(cfg, 0x94);
    lcd_write_data(cfg, 0x10);
    lcd_write_cmd(cfg, 0x95);
    lcd_write_data(cfg, 0x10);
    lcd_write_cmd(cfg, 0x96);
    lcd_write_data(cfg, 0x0e);
    lcd_write_cmd(cfg, 0xb2);
    lcd_write_data(cfg, 0x0F);
    lcd_write_cmd(cfg, 0xb4);
    lcd_write_data(cfg, 0x60);
    lcd_write_cmd(cfg, 0x91);
    lcd_write_data(cfg, 0x10);
    lcd_write_cmd(cfg, 0xC1);
    lcd_write_data(cfg, 0xF1);
    lcd_write_cmd(cfg, 0xC5);
    lcd_write_data(cfg, 0xF8);
    lcd_write_cmd(cfg, 0xb5);
    lcd_write_data(cfg, 0x00);
    lcd_write_cmd(cfg, 0xc3);
    lcd_write_data(cfg, 0x11);
    lcd_write_cmd(cfg, 0x83);
    lcd_write_data(cfg, 0x13);
    lcd_write_cmd(cfg, 0x44);
    lcd_write_data(cfg, 0x00);

    lcd_write_cmd(cfg, 0x2a);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x84);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x84);
    lcd_write_cmd(cfg, 0x2b);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x1f);
    lcd_write_cmd(cfg, 0x2c);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x1c);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x16);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x1f);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x02);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x08);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x09);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x10);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x1f);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x19);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x1c);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x1e);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x03);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x07);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x01);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x03);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x01);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x0f);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x0d);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x11);
    lcd_write_data(cfg, 0x00);
    lcd_write_data(cfg, 0x1d);

    lcd_write_cmd(cfg, 0xff);
    lcd_write_data(cfg, 0x00);

    lcd_write_cmd(cfg, 0x21);

    lcd_write_cmd(cfg, 0x11);
    delay_ms(120);

    lcd_write_cmd(cfg, 0x3a);
    lcd_write_data(cfg, 0x55);

    lcd_write_cmd(cfg, 0x36);
    lcd_write_data(cfg, 0x00);

    lcd_write_cmd(cfg, 0x29);
    delay_ms(10);

    printf("NV3022: Initialization complete!\n");
    return 0;
}

void nv3022_clear(const struct nv3022_config *cfg, uint16_t color)
{
    nv3022_fill(cfg, 0, 0, NV3022_WIDTH - 1, NV3022_HEIGHT - 1, color);
}

void nv3022_fill(const struct nv3022_config *cfg,
                  uint16_t x0, uint16_t y0,
                  uint16_t x1, uint16_t y1,
                  uint16_t color)
{
    uint16_t i, j;

    lcd_set_window(cfg, x0, y0, x1, y1);

    for (i = y0; i <= y1; i++) {
        for (j = x0; j <= x1; j++) {
            lcd_write_data16(cfg, color);
        }
    }
}

void nv3022_draw_pixel(const struct nv3022_config *cfg,
                       uint16_t x, uint16_t y, uint16_t color)
{
    if (x >= NV3022_WIDTH || y >= NV3022_HEIGHT) {
        return;
    }
    lcd_set_window(cfg, x, y, x, y);
    lcd_write_data16(cfg, color);
}

void nv3022_show_char(const struct nv3022_config *cfg,
                      uint16_t x, uint16_t y,
                      char ch, uint16_t fc, uint16_t bc)
{
    uint8_t temp;
    uint8_t c = ch - ' ';

    lcd_set_window(cfg, x, y, x + 7, y + 15);

    for (uint8_t i = 0; i < 16; i++) {
        temp = asc2_1608[c][i];
        for (uint8_t j = 0; j < 8; j++) {
            if (temp & 0x80) {
                lcd_write_data16(cfg, fc);
            } else {
                lcd_write_data16(cfg, bc);
            }
            temp <<= 1;
        }
    }
}

void nv3022_show_string(const struct nv3022_config *cfg,
                        uint16_t x, uint16_t y,
                        const char *str,
                        uint16_t fc, uint16_t bc)
{
    while (*str != '\0') {
        nv3022_show_char(cfg, x, y, *str, fc, bc);
        x += 8;
        str++;
    }
}

CMakeLists.txt

# NV3022 LCD Driver Library
# SPDX-License-Identifier: Apache-2.0
#
# This CMakeLists.txt is a placeholder.
# The library sources should be added via target_sources() in the application.
# See README.md for usage instructions.
#
# For Zephyr modules, use zephyr_library() instead.

# Empty - sources are added directly by the application

【移植实现方法】

1、在应用工程CMakeLists.txt添加配置:

    cmake_minimum_required(VERSION 3.20.0)
    find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
    project(my_project)

    # 引用 NV3022 驱动库
    target_sources(app PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/../modules/nv3022/nv3022.c
    )
    target_include_directories(app PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/../modules/nv3022
    )

    # NXP SDK 头文件路径(用于 CLOCK 函数)
    zephyr_include_directories(
        ${CMAKE_SOURCE_DIR}/../../modules/hal/nxp/mcux/mcux-sdk-ng/devices/MCX/MCXA/MCXA346/drivers
        ${CMAKE_SOURCE_DIR}/../../modules/hal/nxp/mcux/mcux-sdk-ng/devices/MCX/MCXA
        ${CMAKE_SOURCE_DIR}/../../modules/hal/nxp/mcux/mcux-sdk-ng/devices
    )

【应用工程main.c】

/*
 * NV3022 LCD Direct Control Test
 * Using reusable nv3022 library
 * SPDX-License-Identifier: Apache-2.0
 */

#include <stdio.h>
#include <string.h>
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/kernel.h>
#include <fsl_clock.h>
#include "nv3022.h"

/* 硬件引脚定义 */
#define LCD_RST_GPIO  DT_NODELABEL(gpio1)
#define LCD_DC_GPIO   DT_NODELABEL(gpio1)
#define LCD_SPI_DEV  DT_NODELABEL(lpspi0)
#define LCD_RST_PIN  7
#define LCD_DC_PIN   6

/* 背光 GPIO */
#define LCD_BACKLIGHT_GPIO  DT_NODELABEL(gpio2)
#define LCD_BACKLIGHT_PIN   5

int main(void)
{
    struct nv3022_config cfg;
    int ret;

    printf("NV3022 Direct Control Test (using library)\n");

    /* 获取 GPIO 设备 */
    if (!device_is_ready(DEVICE_DT_GET(LCD_RST_GPIO))) {
        printf("Error: RST GPIO not ready\n");
        return -1;
    }
    if (!device_is_ready(DEVICE_DT_GET(LCD_DC_GPIO))) {
        printf("Error: DC GPIO not ready\n");
        return -1;
    }

    /* 配置 GPIO 引脚 */
    printf("Configuring GPIOs...\n");
    ret = gpio_pin_configure(DEVICE_DT_GET(LCD_RST_GPIO), LCD_RST_PIN, GPIO_OUTPUT);
    if (ret < 0) {
        printf("RST GPIO config error: %d\n", ret);
        return -1;
    }

    ret = gpio_pin_configure(DEVICE_DT_GET(LCD_DC_GPIO), LCD_DC_PIN, GPIO_OUTPUT);
    if (ret < 0) {
        printf("DC GPIO config error: %d\n", ret);
        return -1;
    }

    /* 初始化 DC 为高(数据模式) */
    gpio_pin_set(DEVICE_DT_GET(LCD_DC_GPIO), LCD_DC_PIN, 1);

    /* 获取 SPI 设备 */
    if (!device_is_ready(DEVICE_DT_GET(LCD_SPI_DEV))) {
        printf("Error: SPI device not ready\n");
        return -1;
    }

    /*
     * 切换 LPSPI0 时钟源到 FRO_HF_DIV
     * FRO_HF_DIV ÷5 ≈ 20MHz
     */
    CLOCK_AttachClk(kFRO_HF_DIV_to_LPSPI0);
    CLOCK_SetClockDiv(kCLOCK_DivLPSPI0, 4u);  /* MRCC divider = ÷5 */

    /* 配置结构体 */
    memset(&cfg, 0, sizeof(cfg));
    cfg.rst_gpio = DEVICE_DT_GET(LCD_RST_GPIO);
    cfg.rst_pin = LCD_RST_PIN;
    cfg.dc_gpio = DEVICE_DT_GET(LCD_DC_GPIO);
    cfg.dc_pin = LCD_DC_PIN;
    cfg.spi_dev = DEVICE_DT_GET(LCD_SPI_DEV);
    cfg.spi_cfg.operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8) |
                SPI_HOLD_ON_CS | SPI_LOCK_ON;
    cfg.spi_cfg.frequency = 24000000;  /* 24MHz */
    cfg.spi_cfg.slave = 0;

    printf("SPI configured (clock: FRO_HF_DIV/2 = 24MHz)\n");

    /* 初始化 LCD */
    ret = nv3022_init(&cfg);
    if (ret < 0) {
        printf("NV3022 init failed: %d\n", ret);
        return -1;
    }

    /* 启用背光 */
    const struct device *backlight_gpio = DEVICE_DT_GET(LCD_BACKLIGHT_GPIO);
    if (device_is_ready(backlight_gpio)) {
        ret = gpio_pin_configure(backlight_gpio, LCD_BACKLIGHT_PIN, GPIO_OUTPUT_HIGH);
        if (ret < 0) {
            printf("Backlight config error: %d\n", ret);
        } else {
            printf("Backlight enabled\n");
        }
    }

    /* 清屏 - 黑色 */
    printf("Clear screen...\n");
    nv3022_clear(&cfg, NV3022_COLOR_BLACK);
    k_msleep(500);

    /* 填充红色 */
    printf("Filling RED...\n");
    nv3022_fill(&cfg, 0, 0, NV3022_WIDTH - 1, NV3022_HEIGHT - 1, NV3022_COLOR_RED);
    k_msleep(500);

    /* 填充绿色 */
    printf("Filling GREEN...\n");
    nv3022_fill(&cfg, 0, 0, NV3022_WIDTH - 1, NV3022_HEIGHT - 1, NV3022_COLOR_GREEN);
    k_msleep(500);

    /* 填充蓝色 */
    printf("Filling BLUE...\n");
    nv3022_fill(&cfg, 0, 0, NV3022_WIDTH - 1, NV3022_HEIGHT - 1, NV3022_COLOR_BLUE);
    k_msleep(500);

    /* 填充白色 */
    printf("Filling WHITE...\n");
    nv3022_fill(&cfg, 0, 0, NV3022_WIDTH - 1, NV3022_HEIGHT - 1, NV3022_COLOR_WHITE);
    k_msleep(500);

    /* 清屏并显示文字 */
    printf("Clear and show text...\n");
    nv3022_clear(&cfg, NV3022_COLOR_BLACK);
    k_msleep(100);

    /* 显示字符串 */
    nv3022_show_string(&cfg, 10, 20, "HELLO", NV3022_COLOR_WHITE, NV3022_COLOR_BLACK);
    nv3022_show_string(&cfg, 10, 40, "NV3022", NV3022_COLOR_GREEN, NV3022_COLOR_BLACK);
    nv3022_show_string(&cfg, 10, 60, "ZEPHYR", NV3022_COLOR_RED, NV3022_COLOR_BLACK);
    nv3022_show_string(&cfg, 10, 80, "70x160", NV3022_COLOR_BLUE, NV3022_COLOR_BLACK);

    printf("Test complete!\n");

    while (1) {
        k_msleep(500);
    }

    return 0;
}

prj.conf内容:

# NV3022 Display Test Configuration
CONFIG_SPI=y
CONFIG_DISPLAY=y
CONFIG_LOG=y
CONFIG_DISPLAY_LOG_LEVEL_DBG=y
CONFIG_GPIO=y
CONFIG_STD_C99=y


【移植指导】

如需在其他工程中使用,只需:

复制 app/modules/nv3022/ 目录

在应用 CMakeLists.txt 中添加 target_sources() 和 target_include_directories()

参考文档中的 main.c 示例进行初始化

【移植效果】

2974b90db98cf752d7f23cc56e90f8e1.jpg






关键词: Zephyr     MiKro     NV2022     FRDM_    

助工
2026-03-30 09:14:42     打赏
2楼

这效果太棒了!


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]