本帖最后由 [鑫森淼焱垚] 于 2024-5-5 16:26 编辑
SPI LCD 简介
此款显示屏是从某宝购买的,型号是 MSP3223,是一款3.2寸IPS彩色液晶显示模块,支持电容触摸。显示模块采用4线制SPI接口,只需要5个IO即可显示显示,240x320标清分辨率,可应用于各种需要屏显功能的产品。
液晶屏参数
引脚确定
开发板上J7接口有 SPI 管脚,查阅原理图 AT_START_F405_V1.0_SCH.pdf,确定其引脚标号。
这里只关注以下3个管脚,将在 AT32 WorkBench 中进行配置。
- PB13, SCK
- PC2, MISO
- PC3, MOSI
对比 SPI LCD 的管脚,最终确定显示屏和开发板的连接关系如下表所示:
WorkBench 创建工程
选择 MCU
双击 AT32_Work_Bench.exe 打开软件,开始一个新设计,按照下图设置 MCU 系列为 AT32F405,MCU 型号为 AT32F405RCT7-7。
SPI2 配置参数
选择 Pin布局和配置,依次点击 外设 --> SPI --> SPI2。
配置 SPI2 功能为 主机双线单向全双工模式,关闭硬件CS信号。
SPI 参数配置如下图所示,Motorola 模式,8bit模式,MSB优先传输;时钟分频系数为3,时钟极性为高电平,时钟相位为第二个边沿进行数据捕获;CRC校验关闭,CS信号类型为软件CS。
SPI2 GPIO配置
按照下图配置 SPI2 的 GPIO,并且修改了用户标签。对应右侧的红框中的3个管脚。
- LCD_SCK 为 PB13
- LCD_MOSI 为 PC3
- LCD_MISO 为 PC2
SPI2 时钟配置
在时钟配置界面找到 apb1 展开即可看到 SPI2 挂在 APB1 上。当前把 apb1div 设置为4分频,即 SPI2 时钟源为 54MHz。
再回到 SPI2 模式和配置中,其时钟参数配置分频系数为3,即SCK时钟只有 54MHz/3=18MHz 对应上了。
LCD的控制管脚
SPI LCD除了SPI收发数据,还需要额外的管脚控制时序,例如
- LCD_CS,用一个管脚用作 SPI 片选 -- PC5 管脚;
- LCD_RST,用一个管脚控制 LCD 复位 -- PB1 管脚;
- LCD_RS,用一个管脚选择 data/cmd -- PB10 管脚;
这三个管脚的配置如下图所示。
USART1 配置参数
为了重定向 printf() 函数,查看打印日志,这里配置 USART1,配置为异步模式,关闭硬件流控。
串口常用配置选项为:926100, 8bit 数据,无奇偶校验,1个停止位。
USART1 配置GPIO
生成代码
配置完成后,选择菜单栏 生成代码,然后配置项目。
设置项目名称为 AT32F405-LCD。
项目位置,根据需要设置到合适的目录。
工具链,这里选择 MDK_V5.
勾选重新生成代码时保留用户代码。
WorkBench 安装固件包
如果是第一次生成代码,可能固件包没有安装。点击右侧的固件包管理
点击从本地安装,浏览固件库,直接选择 zip 文件即可。
等待固件包安装成功,之后就可以愉快地使用 WorkBench 创建初始化代码。
关键代码
主流程
AT32 WorkBench 自动创建的初始化代码以 wk_ 开头,如下图中的 wk_usart1_init() , wk_spi2_init() 和 wk_gpio_config() 等函数。
这个先初始化了时钟,USART1 和 SPI2 外设,并配置了管脚,然后调用 LCD_Init() 初始化 LCD 显示屏。
由于我移植了AT32固件库中的 FreeRTOS,所以在 init_tasks() 中创建 LCD 应用程序。
SPI2 初始化
此代码由 WorkBench 生成,配置了 SCK, MOSI, MISO 三个 GPIO 为复用模式,并配置 SPI2 参数。
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] init spi2 function
* @param none
* @retval none
*/
void wk_spi2_init(void)
{
/* add user code begin spi2_init 0 */
/* add user code end spi2_init 0 */
gpio_init_type gpio_init_struct;
spi_init_type spi_init_struct;
gpio_default_para_init(&gpio_init_struct);
spi_default_para_init(&spi_init_struct);
/* add user code begin spi2_init 1 */
/* add user code end spi2_init 1 */
/* configure the SCK pin */
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
gpio_init_struct.gpio_pins = LCD_SCK_PIN;
gpio_init_struct.gpio_pull = GPIO_PULL_UP;
gpio_init(LCD_SCK_GPIO_PORT, &gpio_init_struct);
gpio_pin_mux_config(LCD_SCK_GPIO_PORT, GPIO_PINS_SOURCE13, GPIO_MUX_5);
/* configure the MISO pin */
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
gpio_init_struct.gpio_pins = LCD_MISO_PIN;
gpio_init_struct.gpio_pull = GPIO_PULL_UP;
gpio_init(LCD_MISO_GPIO_PORT, &gpio_init_struct);
gpio_pin_mux_config(LCD_MISO_GPIO_PORT, GPIO_PINS_SOURCE2, GPIO_MUX_5);
/* configure the MOSI pin */
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
gpio_init_struct.gpio_pins = LCD_MOSI_PIN;
gpio_init_struct.gpio_pull = GPIO_PULL_UP;
gpio_init(LCD_MOSI_GPIO_PORT, &gpio_init_struct);
gpio_pin_mux_config(LCD_MOSI_GPIO_PORT, GPIO_PINS_SOURCE3, GPIO_MUX_5);
/* configure param */
spi_init_struct.transmission_mode = SPI_TRANSMIT_FULL_DUPLEX;
spi_init_struct.master_slave_mode = SPI_MODE_MASTER;
spi_init_struct.frame_bit_num = SPI_FRAME_8BIT;
spi_init_struct.first_bit_transmission = SPI_FIRST_BIT_MSB;
spi_init_struct.mclk_freq_division = SPI_MCLK_DIV_3;
spi_init_struct.clock_polarity = SPI_CLOCK_POLARITY_HIGH;
spi_init_struct.clock_phase = SPI_CLOCK_PHASE_2EDGE;
spi_init_struct.cs_mode_selection = SPI_CS_SOFTWARE_MODE;
spi_init(SPI2, &spi_init_struct);
spi_enable(SPI2, TRUE);
/* add user code begin spi2_init 2 */
/* add user code end spi2_init 2 */
}
GPIO 初始化
由于 LCD 除了 SPI2 的 MOSI, MISO 和 SCK 管脚,还需要 LCD_CS, LCD_RST 和 LCD_RS 三个GPIO管脚用以控制命令时序。
这三个 GPIO 的初始化在 WorkBench 中单独配置,生成的代码见 wk_gpio_config()。
/**
* @brief init gpio_input/gpio_output/gpio_analog/eventout function.
* @param none
* @retval none
*/
void wk_gpio_config(void)
{
/* add user code begin gpio_config 0 */
/* add user code end gpio_config 0 */
gpio_init_type gpio_init_struct;
gpio_default_para_init(&gpio_init_struct);
/* add user code begin gpio_config 1 */
/* add user code end gpio_config 1 */
/* gpio output config */
gpio_bits_set(LCD_CS_GPIO_PORT, LCD_CS_PIN);
gpio_bits_reset(GPIOB, LCD_RST_PIN | LCD_RS_PIN);
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
gpio_init_struct.gpio_pins = LCD_CS_PIN;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init(LCD_CS_GPIO_PORT, &gpio_init_struct);
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
gpio_init_struct.gpio_pins = LCD_RST_PIN | LCD_RS_PIN;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init(GPIOB, &gpio_init_struct);
/* add user code begin gpio_config 2 */
/* add user code end gpio_config 2 */
}
LCD 初始化
调用函数 LCD_Init() 进行初始化。
这个函数有3个步骤:
- 初始化 GPIO,即配置 LCD_CS, LCD_RST 和 LCD_RS 三个管脚初始化。由于已经在 wk_gpio_init() 中初始化了这三个管脚,这里实现为空;
- 调用 LCD_RESET() 函数,操作 LCD_RST 管脚,拉高50毫秒,再拉低100毫秒,再拉高50毫秒,即可以复位 LCD;
- 最后是下发 LCD 初始化参数,这些参数由屏幕产商提供。
移植结果
- 测试程序读取 LCD Driver IC 的 ID,成功读取数值为 0x9341。
- 在屏幕上显示7种颜色,并读取某个点的颜色值并进行比对,比对成功。
|