【前言】
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 示例进行初始化
【移植效果】

我要赚赏金
