正点原子 发表于 2023-6-28 10:41:33

《ATK-DFPGL22G之FPGA开发指南_V1.0》第二十五章 TFTLCD(MCU屏)实验

本帖最后由 正点原子 于 2023-6-28 10:41 编辑

1)实验平台:正点原子 DFZU2EG_4EV MPSoC开发板
2)购买链接:https://item.taobao.com/item.htm?&id=692368045899
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-340252-1-1.html
4)正点原子官方B站:https://space.bilibili.com/394620890
5)正点原子FPGA交流群:994244016




第二十五章 TFTLCD(MCU屏)实验

本章将介绍使用APM32E103驱动TFTLCD(MCU屏)进行显示。通过本章的学习,读者将学习到EMMC(外部存储器控制器)中SMC(静态存储控制器)的使用。
本章分为如下几个小节:
25.1硬件设计
25.2 程序设计
25.3 下载验证


25.1 硬件设计
25.1.1 例程功能
1. TFTLCD模块显示实验信息和LCD驱动器的ID,同时不停地切换底色
2. LED0闪烁,指示程序正在运行
25.1.2 硬件资源
1. LED
      LED0 - PB5
2. 正点原子 2.8/3.5/4.3/7/10寸TFTLCD模块(仅限MCU屏,16位8080并口驱动)
25.1.3 原理图
本章实验使用了正点原子的TFTLCD模块(兼容正点原子2.8/3.5/4.3/7/10寸的TFTLCD模块),该模块需通过LCD转接板与板载的TFTLCD接口进行连接,该接口与板载MCU的连接原理图,如下图所示:
图25.1.3.1 TFTLCD模块与MCU的连接原理图


从上图中可以看到,TFTLCD模块连接至SMC的存储块1的区域块4,并且使用了地址线A10作为TFTLCD模块命令或数据的选择信号,结合《APM32E103xCxE用户手册》,便可计算出配置好SMC后,TFTLCD模块的命令访问地址被映射到0x6C00007E,TFTLCD模块的数据访问地址被映射到0x6C000080。
25.2 程序设计
25.2.1 Geehy标准库的SMC驱动
本章实验通过SMC驱动8080并口的TFTLCD模块,通过SMC可以将TFTLCD模块的命令和数据寄存器映射为两个地址,往这两个地址写入或读取数据就可直接与TFTLCD模块进行通讯,因此需要对SMC做相应的配置,,具体的步骤如下:
①:配置SMC存储块1的区域块4
②:使能SMC存储块1的区域块4
在Geehy标准库中对应的驱动函数如下:
①:配置SMC存储块1的区域块
该函数用于配置SMC存储块1的区域块,其函数原型如下所示:
void SMC_ConfigNORSRAM(SMC_NORSRAMConfig_T* smcNORSRAMConfig);
该函数的形参描述,如下表所示:
表25.2.1.1 函数SMC_ConfigNORSRAM()形参描述
该函数的返回值描述,如下表所示:
表25.2.1.2 函数SMC_ConfigNORSRAM()返回值描述
该函数使用SMC_NORSRAMConfig_T类型的结构体变量传入SMC存储块1区域块的配置参数,该结构体的定义如下所示:
typedef enum
{
    SMC_BANK1_NORSRAM_1,                                                /* SMC存储块1区域块1 */
    SMC_BANK1_NORSRAM_2,                                                /* SMC存储块1区域块2 */
    SMC_BANK1_NORSRAM_3,                                                /* SMC存储块1区域块3 */
    SMC_BANK1_NORSRAM_4                                                      /* SMC存储块1区域块4 */
} SMC_BANK1_NORSRAM_T;

typedef enum
{
    SMC_DATA_ADDRESS_MUX_DISABLE,                              /* 禁止数据地址总线复用 */
    SMC_DATA_ADDRESS_MUX_ENABLE                                        /* 使能数据地址总线复用 */
} SMC_DATA_ADDRESS_MUX_T;

typedef enum
{
    SMC_MEMORY_TYPE_SRAM,                                                /* SRAM */
    SMC_MEMORY_TYPE_PSRAM,                                                /* PSRAM */
    SMC_MEMORY_TYPE_NOR                                                      /* NORFlash */
} SMC_MEMORY_TYPE_T;

typedef enum
{
    SMC_MEMORY_DATA_WIDTH_8BIT,                                        /* 8位数据宽度 */
    SMC_MEMORY_DATA_WIDTH_16BIT                                        /* 16位数据宽度 */
} SMC_MEMORY_DATA_WIDTH_T;

typedef enum
{
    SMC_BURST_ACCESS_MODE_DISABLE,                              /* 禁用突发访问模式 */
    SMC_BURST_ACCESS_MODE_ENABLE                              /* 使能突发访问模式 */
} SMC_BURST_ACCESS_MODE_T;

typedef enum
{
    SMC_ASYNCHRONOUS_WAIT_DISABLE,                              /* 禁用异步等待 */
    SMC_ASYNCHRONOUS_WAIT_ENABLE                              /* 使能异步等待 */
} SMC_ASYNCHRONOUS_WAIT_T;

typedef enum
{
    SMC_WAIT_SIGNAL_POLARITY_LOW,                              /* 低电平有效 */
    SMC_WAIT_SIGNAL_POLARITY_HIGH                              /* 高电平有效 */
} SMC_WAIT_SIGNAL_POLARITY_T;

typedef enum
{
    SMC_WRAP_MODE_DISABLE,                                                /* 禁止非对齐的突发访问 */
    SMC_WRAP_MODE_ENABLE                                                /* 使能非对齐的突发访问 */
} SMC_WRAP_MODE_T;

typedef enum
{
    SMC_WAIT_SIGNAL_ACTIVE_BEFORE_WAIT_STATE,      /* 在等待前有效 */
    SMC_WAIT_SIGNAL_ACTIVE_DURING_WAIT_STATE      /* 在等在阶段有效 */
} SMC_WAIT_SIGNAL_ACTIVE_T;

typedef enum
{
    SMC_WRITE_OPERATION_DISABLE,                              /* 禁止写操作 */
    SMC_WRITE_OPERATION_ENABLE                                        /* 使能写操作*/
} SMC_WRITE_OPERATION_T;

typedef enum
{
    SMC_WAITE_SIGNAL_DISABLE,                                        /* 禁止等待信号 */
    SMC_WAITE_SIGNAL_ENABLE                                                /* 使能等待信号 */
} SMC_WAITE_SIGNAL_T;

typedef enum
{
    SMC_EXTENDEN_MODE_DISABLE,                                        /* 禁止扩展模式 */
    SMC_EXTENDEN_MODE_ENABLE                                        /* 使能扩展模式 */
} SMC_EXTENDEN_MODE_T;

typedef enum
{
    SMC_WRITE_BURST_DISABLE,                                        /* 禁止突发写 */
    SMC_WRITE_BURST_ENABLE                                                /* 使能突发写 */
} SMC_WRITE_BURST_T;

typedef enum
{
    SMC_ACCESS_MODE_A,                                                      /* 访问模式A */
    SMC_ACCESS_MODE_B,                                                      /* 访问模式B */
    SMC_ACCESS_MODE_C,                                                      /* 访问模式C */
    SMC_ACCESS_MODE_D                                                      /* 访问模式D */
} SMC_ACCESS_MODE_T;

typedef struct
{
    uint8_t addressSetupTime;                                        /* 地址建立时间 */
    uint8_t addressHodeTime;                                        /* 地址保持时间 */
    uint8_t dataSetupTime;                                                /* 数据建立时间 */
    uint8_t busTurnaroundTime;                                        /* 总线恢复时间 */
    uint8_t clockDivision;                                                /* 时钟分频系数 */
    uint8_t dataLatency;                                                /* 数据保持时间 */
    SMC_ACCESS_MODE_T accessMode;                              /* 访问模式 */
} SMC_NORSRAMTimingConfig_T;

typedef struct
{
    SMC_BANK1_NORSRAM_T                        bank;                                        /* SMC存储块1区域块 */
    SMC_DATA_ADDRESS_MUX_T                dataAddressMux;                        /* 数据地址总线复用 */
    SMC_MEMORY_TYPE_T                        memoryType;                              /* 存储器类型 */
    SMC_MEMORY_DATA_WIDTH_T                memoryDataWidth;                /* 数据宽度 */
    SMC_BURST_ACCESS_MODE_T                burstAcceesMode;                /* 突发访问模式 */
    SMC_ASYNCHRONOUS_WAIT_T                asynchronousWait;                /* 异步等待 */
    SMC_WAIT_SIGNAL_POLARITY_T      waitSignalPolarity;                /* 等待信号极性    */
    SMC_WRAP_MODE_T                              wrapMode;                              /* 非对齐的突发访问 */
    SMC_WAIT_SIGNAL_ACTIVE_T      waitSignalActive;                /* 等待时序 */
    SMC_WRITE_OPERATION_T                writeOperation;                        /* 写操作 */
    SMC_WAITE_SIGNAL_T                        waiteSignal;                        /* 等待信号 */
    SMC_EXTENDEN_MODE_T                        extendedMode;                        /* 扩展模式 */
    SMC_WRITE_BURST_T                        writeBurst;                              /* 突发写 */
    SMC_NORSRAMTimingConfig_T      *readWriteTimingStruct;      /* 读写时序 */
    SMC_NORSRAMTimingConfig_T      *writeTimingStruct;                /* 写时序 */
} SMC_NORSRAMConfig_T;
该函数的使用示例,如下所示:
#include "apm32e10x.h"
#include "apm32e10x_smc.h"

void example_fun(void)
{
    SMC_NORSRAMConfig_T smc_norsram_init_struct;
    SMC_NORSRAMTimingConfig_T smc_read_timing_struct;
    SMC_NORSRAMTimingConfig_T smc_write_timing_struct;
   
    /* 配置SMC读时序 */
    smc_read_timing_struct.addressSetupTime      = 0x0F;
    smc_read_timing_struct.addressHodeTime                = 0x00;
    smc_read_timing_struct.dataSetupTime                = 0x3C;
    smc_read_timing_struct.busTurnaroundTime      = 0;
    smc_read_timing_struct.clockDivision                = 0;
    smc_read_timing_struct.dataLatency                        = 0;
    smc_read_timing_struct.accessMode                        = SMC_ACCESS_MODE_A;
   
    /* 配置SMC写时序 */
    smc_write_timing_struct.addressSetupTime      = 0x09;
    smc_write_timing_struct.addressHodeTime      = 0x00;
    smc_write_timing_struct.dataSetupTime                = 0x09;
    smc_write_timing_struct.busTurnaroundTime      = 0;
    smc_write_timing_struct.clockDivision                = 0;
    smc_write_timing_struct.dataLatency                = 0;
    smc_write_timing_struct.accessMode                        = SMC_ACCESS_MODE_A;
   
    /* 配置SMC存储块1区域块1 */
    smc_norsram_init_struct.bank                              = SMC_BANK1_NORSRAM_1;
    smc_norsram_init_struct.dataAddressMux                = SMC_DATA_ADDRESS_MUX_DISABLE;
    smc_norsram_init_struct.memoryType                        = SMC_MEMORY_TYPE_SRAM;
    smc_norsram_init_struct.memoryDataWidth      = SMC_MEMORY_DATA_WIDTH_16BIT;
    smc_norsram_init_struct.burstAcceesMode      = SMC_BURST_ACCESS_MODE_DISABLE;
    smc_norsram_init_struct.asynchronousWait      = SMC_ASYNCHRONOUS_WAIT_DISABLE;
    smc_norsram_init_struct.waitSignalPolarity      = SMC_WAIT_SIGNAL_POLARITY_LOW;
    smc_norsram_init_struct.wrapMode                        = SMC_WRAP_MODE_DISABLE;
    smc_norsram_init_struct.waitSignalActive      =
         SMC_WAIT_SIGNAL_ACTIVE_BEFORE_WAIT_STATE;
    smc_norsram_init_struct.writeOperation                = SMC_WRITE_OPERATION_ENABLE;
    smc_norsram_init_struct.waiteSignal                = SMC_WAITE_SIGNAL_DISABLE;
    smc_norsram_init_struct.extendedMode                = SMC_EXTENDEN_MODE_ENABLE;
    smc_norsram_init_struct.writeBurst                        = SMC_WRITE_BURST_DISABLE;
    smc_norsram_init_struct.readWriteTimingStruct      = &smc_read_timing_struct;
    smc_norsram_init_struct.writeTimingStruct      = &smc_write_timing_struct;
    SMC_ConfigNORSRAM(&smc_norsram_init_struct);
}
②:使能SMC存储块1的区域块
该函数用于使能SMC存储块1的区域块,其函数原型如下所示:
void SMC_EnableNORSRAM(SMC_BANK1_NORSRAM_T bank);
该函数的形参描述,如下表所示:
表25.2.1.3 函数SMC_EnableNORSRAM()形参描述
该函数的返回值描述,如下表所示:
表25.2.1.4 函数SMC_EnableNORSRAM()返回值描述
该函数的使用示例,图下所示:
#include "apm32e10x.h"
#include "apm32e10x_smc.h"

void example_fun(void)
{
    /* 使能SMC存储块1区域块1 */
    SMC_EnableNORSRAM(SMC_BANK1_NORSRAM_1);
}
25.2.2 TFTLCD驱动
本章实验的TFTLCD驱动主要负责向应用层提供TFTLCD的初始化和各种TFTLCD显示的操作函数。本章实验中,TFTLCD的驱动代码包括lcd.c、lcd_ex.c、lcd.h和字体文件lcdfont.h四个文件。
由于TFTLCD模块需要使用到打量的GPIO引脚,因此对于GPIO的相关定义,请读者自行查看lcd.c和lcd.h这两个文件。
TFTLCD驱动中,TFTLCD的初始化函数,如下所示:
/**
* @brief       初始化LCD
* @param       无
* @retval      无
*/
void lcd_init(void)
{
    GPIO_Config_T gpio_init_struct;
    SMC_NORSRAMConfig_T smc_norsram_init_struct;
    SMC_NORSRAMTimingConfig_T smc_read_timing_struct;
    SMC_NORSRAMTimingConfig_T smc_write_timing_struct;
   
    /* 使能时钟 */
    LCD_WR_GPIO_CLK_ENABLE();                        /* 使能SMC_NWE引脚端口时钟 */
    LCD_RD_GPIO_CLK_ENABLE();                        /* 使能SMC_NOE引脚端口时钟 */
    LCD_BL_GPIO_CLK_ENABLE();                        /* 使能LCD_BL引脚端口时钟 */
    LCD_CS_GPIO_CLK_ENABLE();                        /* 使能SMC_NE4引脚端口时钟 */
    LCD_RS_GPIO_CLK_ENABLE();                        /* 使能SMC_A6引脚端口时钟 */
RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_SMC);    /* 使能EMMC时钟 */
/* 使能SMC_D0/1/2/3/13/14/15引脚端口时钟 */
RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOD);
/* 使能SMC_D4/5/6/7/8/9/10/11/12引脚端口时钟 */
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOD);
   
    /* 配置SMC_NWE引脚 */
    gpio_init_struct.pin = LCD_WR_GPIO_PIN;          /* SMC_NWE引脚 */
    gpio_init_struct.mode = GPIO_MODE_AF_PP;         /* 复用功能模式 */
    gpio_init_struct.speed = GPIO_SPEED_50MHz;       /* 高速 */
    GPIO_Config(LCD_WR_GPIO_PORT, &gpio_init_struct);/* 配置SMC_NWE引脚 */
   
    /* 配置SMC_NOE引脚 */
    gpio_init_struct.pin = LCD_RD_GPIO_PIN;          /* SMC_NOE引脚 */
    GPIO_Config(LCD_RD_GPIO_PORT, &gpio_init_struct);/* 配置SMC_NOE引脚 */
   
    /* 配置SMC_NEx引脚 */
    gpio_init_struct.pin = LCD_CS_GPIO_PIN;          /* SMC_NEx引脚 */
    GPIO_Config(LCD_CS_GPIO_PORT, &gpio_init_struct);/* 配置SMC_NEx引脚 */
   
    /* 配置SMC_Ay引脚 */
    gpio_init_struct.pin = LCD_RS_GPIO_PIN;          /* SMC_Ay引脚 */
    GPIO_Config(LCD_RS_GPIO_PORT, &gpio_init_struct);/* 配置SMC_Ay引脚 */
   
    /* 配置SMC_Dn引脚 */
    gpio_init_struct.pin =GPIO_PIN_14 |            /* SMC_D0 */
                            GPIO_PIN_15 |            /* SMC_D1 */
                            GPIO_PIN_0 |             /* SMC_D2 */
                            GPIO_PIN_1 |             /* SMC_D3 */
                            GPIO_PIN_8 |             /* SMC_D13 */
                            GPIO_PIN_9 |             /* SMC_D14 */
                            GPIO_PIN_10;             /* SMC_D15 */
    GPIO_Config(GPIOD, &gpio_init_struct);                                                /* 配置SMC_Dn引脚 */
    gpio_init_struct.pin =GPIO_PIN_7 |             /* SMC_D4 */
                            GPIO_PIN_8 |             /* SMC_D5 */
                            GPIO_PIN_9 |             /* SMC_D6 */
                            GPIO_PIN_10 |            /* SMC_D7 */
                            GPIO_PIN_11 |            /* SMC_D8 */
                            GPIO_PIN_12 |            /* SMC_D9 */
                            GPIO_PIN_13 |            /* SMC_D10 */
                            GPIO_PIN_14 |            /* SMC_D11 */
                            GPIO_PIN_15;             /* SMC_D12 */
    GPIO_Config(GPIOE, &gpio_init_struct);         /* 配置SMC_Dn引脚 */
   
    /* 配置LCD_BL引脚 */
    gpio_init_struct.pin = LCD_BL_GPIO_PIN;          /* LCD_BL引脚 */
    gpio_init_struct.mode = GPIO_MODE_OUT_PP;      /* 通用输出模式 */
    GPIO_Config(LCD_BL_GPIO_PORT, &gpio_init_struct);/* 配置LCD_BL引脚 */
   
    /* 配置SMC读时序 */
    smc_read_timing_struct.addressSetupTime = 1;   /* 地址建立时间 */
    smc_read_timing_struct.addressHodeTime = 0;      /* 地址保持时间 */
smc_read_timing_struct.dataSetupTime = 26;       /* 数据建立时间 */
/* 访问模式 */
    smc_read_timing_struct.accessMode = SMC_ACCESS_MODE_A;
    /* 配置SMC写时序 */
    smc_write_timing_struct.addressSetupTime = 1;    /* 地址建立时间 */
    smc_write_timing_struct.addressHodeTime = 0;   /* 地址保持时间 */
smc_write_timing_struct.dataSetupTime = 3;       /* 数据建立时间 */
/* 访问模式 */
    smc_write_timing_struct.accessMode = SMC_ACCESS_MODE_A;
   
/* 配置SMC */
smc_norsram_init_struct.bank = SMC_BANK1_NORSRAM_4;/* 使用SMC_NE4 */
/* 禁止数据、地址总线复用 */
smc_norsram_init_struct.dataAddressMux   = SMC_DATA_ADDRESS_MUX_DISABLE;
/* SRAM类型 */
smc_norsram_init_struct.memoryType         = SMC_MEMORY_TYPE_SRAM;
/* 16位数据宽度 */
smc_norsram_init_struct.memoryDataWidth    = SMC_MEMORY_DATA_WIDTH_16BIT;
/* 禁止突发访问 */
smc_norsram_init_struct.burstAcceesMode    = SMC_BURST_ACCESS_MODE_DISABLE;
/* 禁止异步传输期间的等待信号 */
smc_norsram_init_struct.asynchronousWait   = SMC_ASYNCHRONOUS_WAIT_DISABLE;
/* 配置等待信号极性,仅在突发访问模式下有效 */
    smc_norsram_init_struct.waitSignalPolarity = SMC_WAIT_SIGNAL_POLARITY_LOW;
   /* 禁止非对齐的突发访问 */
smc_norsram_init_struct.wrapMode = SMC_WRAP_MODE_DISABLE;
/* 配置等待时序 */
    smc_norsram_init_struct.waitSignalActive = SMC_WAIT_SIGNAL_ACTIVE_BEFORE_WAIT_STATE;
/* 使能写存储器 */
smc_norsram_init_struct.writeOperation = SMC_WRITE_OPERATION_ENABLE;
/* 禁止等待信号 */
smc_norsram_init_struct.waiteSignal    = SMC_WAITE_SIGNAL_DISABLE;
/* 使能扩展模式 */
smc_norsram_init_struct.extendedMode   = SMC_EXTENDEN_MODE_ENABLE;
/* 使能突发写 */
smc_norsram_init_struct.writeBurst   = SMC_WRITE_BURST_DISABLE;
/* 读时序 */
smc_norsram_init_struct.readWriteTimingStruct = &smc_read_timing_struct;
/* 写时序 */
smc_norsram_init_struct.writeTimingStruct = &smc_write_timing_struct;
/* 配置SMC */
SMC_ConfigNORSRAM(&smc_norsram_init_struct);
/* 使能存储块1区域块4 */
    SMC_EnableNORSRAM(SMC_BANK1_NORSRAM_4);
    delay_ms(50);
   
    /* 尝试读取ILI9341的ID */
    lcd_wr_regno(0xD3);
    lcddev.id = lcd_rd_data();                  /* 无效数据 */
    lcddev.id = lcd_rd_data();                  /* 读取到0x00 */
    lcddev.id = lcd_rd_data() << 8;               /* 读取到0x93 */
    lcddev.id |= lcd_rd_data();                   /* 读取到0x41 */
    if (lcddev.id != 0x9341)                                                                /* 尝试读取ST7789的ID */
    {
      lcd_wr_regno(0x04);
      lcddev.id = lcd_rd_data();                /* 无效数据 */
      lcddev.id = lcd_rd_data();                /* 读取到0x85 */
      lcddev.id = lcd_rd_data() << 8;         /* 读取到0x85 */
      lcddev.id |= lcd_rd_data();               /* 读取到0x52 */
      if (lcddev.id == 0x8552)                  /* 将ST7789的ID记为0x7789 */
      {
            lcddev.id = 0x7789;
      }
      if (lcddev.id != 0x7789)                  /* 尝试读取NT35310的ID */
      {
            lcd_wr_regno(0xD4);
            lcddev.id = lcd_rd_data();            /* 无效数据 */
            lcddev.id = lcd_rd_data();            /* 读取到0x01 */
            lcddev.id = lcd_rd_data() << 8;       /* 读取到0x53 */
            lcddev.id |= lcd_rd_data();         /* 读取到0x10 */
            if (lcddev.id != 0x5310)            /* 尝试读取NT35510的ID */
            {
                /* 发送密钥(厂家提供) */
                lcd_write_reg(0xF000, 0x0055);
                lcd_write_reg(0xF001, 0x00AA);
                lcd_write_reg(0xF002, 0x0052);
                lcd_write_reg(0xF003, 0x0008);
                lcd_write_reg(0xF004, 0x0001);
               
                lcd_wr_regno(0xC500);
                lcddev.id = lcd_rd_data() << 8;   /* 读取到0x80 */
                lcd_wr_regno(0xC501);
                lcddev.id |= lcd_rd_data();       /* 读取到0x00 */
/* 因为此NT5510的指令恰好为SSD1963的软件复位指令 */
                delay_ms(5);

                if (lcddev.id != 0x5510)          /* 尝试读取SSD1963的ID */
                {
                  lcd_wr_regno(0xA1);
                  lcddev.id = lcd_rd_data();
                  lcddev.id = lcd_rd_data()<<8; /* 读取到0x57 */
                  lcddev.id |= lcd_rd_data();   /* 读取到0x61 */
                  if (lcddev.id == 0x5761)      /* 将SSD1963的ID记为0x1963 */
                  {
                        lcddev.id = 0x1963;
                  }
                }
            }
      }
    }
   
    if (lcddev.id == 0x7789)
    {
      lcd_ex_st7789_reginit();                  /* 执行ST7789初始化 */
    }
    else if (lcddev.id == 0x9341)
    {
      lcd_ex_ili9341_reginit();               /* 执行ILI9341初始化 */
    }
    else if (lcddev.id == 0x5310)
    {
      lcd_ex_nt35310_reginit();               /* 执行NT35310初始化 */
    }
    else if (lcddev.id == 0x5510)
    {
      lcd_ex_nt35510_reginit();               /* 执行NT35510初始化 */
    }
    else if (lcddev.id == 0x1963)
    {
      lcd_ex_ssd1963_reginit();               /* 执行SSD1963初始化 */
      lcd_ssd_backlight_set(100);               /* 背光设置为最亮 */
    }
    lcd_display_dir(0);                           /* 默认设置为竖屏 */
    LCD_BL(1);                                    /* 点亮背光 */
    lcd_clear(WHITE);                           /* 清屏 */
}
从上的代码中可以看出,本章实验的TFTLCD驱动是兼容了正点原子的多款TFTLCD模块的,因此在初始化完SMC后,会与TFTLCD进行通讯,确定TFTLCD的型号,然后根据型号针对性地对TFTLCD模块进行配置。
TFTLCD驱动中与TFTLCD模块通讯的函数,如下所示:
/**
* @brief       LCD写数据
* @param       data: 要写入的数据
* @retval      无
*/
void lcd_wr_data(volatile uint16_t data)
{
    data = data;
    LCD->LCD_RAM = data;
}

/**
* @brief       LCD写寄存器编号或地址
* @param       regno: 寄存器编号或地址
* @retval      无
*/
void lcd_wr_regno(volatile uint16_t regno)
{
    regno = regno;
    LCD->LCD_REG = regno;
}

/**
* @brief       LCD写寄存器
* @param       regno: 寄存器编号
* @param       data : 要写入的数据
* @retval      无
*/
void lcd_write_reg(uint16_t regno, uint16_t data)
{
    LCD->LCD_REG = regno;
    LCD->LCD_RAM = data;
}

/**
* @brief       LCD读数据
* @param       无
* @retval      读取到的数据
*/
static uint16_t lcd_rd_data(void)
{
    volatile uint16_t ram;
    ram = LCD->LCD_RAM;
    return ram;
}
从上面的代码中可以看出,与TFTLCD的通讯都是通过LCD这一结构体对象来完成的,对于LCD结构体的相关定义,如下所示:
#define LCD_SMC_NEX    4
#define LCD_SMC_AX   10

typedef struct
{
    volatile uint16_t LCD_REG;
    volatile uint16_t LCD_RAM;
} LCD_TypeDef;
从LCD结构体的相关定义中可以看出,与TFTLCD模块的通讯地址是与TFTLCD连接的SMC存储块1的区域块和TFTLCD模块命令、数据选择信号所连接的SMC地址线是有关的。通过上面宏定义的计算,可以算出LCD_BASE宏定义的值为0x6C00007E,因此访问LCD->LCD_REG就是访问0x6C00007E这一地址,访问LCD->LCD_RAM就是访问0x6C000080这一地址,这两个地址也就是通过SMC映射的TFTLCD命令和数据寄存器的访问地址。
通过上面介绍的驱动函数就能够与TFTLCD模块进行通讯了,而在TFTLCD模块的显示屏上显示出特定的图案或字符或设置TFTLCD模块的显示方向等等的操作都是能够通过TFTLCD模块规定的特定命令来完成的,想深究的读者可以产看正点原子TFTLCD模块的用户手册或查看实际使用的TFTLCD模块的相关文档。
25.2.3 实验应用代码
本实验的应用代码,如下所示:
int main(void)
{
    uint8_t x = 0;
    uint8_t lcd_id;
   
    NVIC_ConfigPriorityGroup(NVIC_PRIORITY_GROUP_4);/* 设置中断优先级分组为组4 */
    sys_apm32_clock_init(15);                         /* 配置系统时钟 */
    delay_init(120);                                  /* 初始化延时功能 */
    usart_init(115200);                               /* 初始化串口 */
    led_init();                                       /* 初始化LED */
    lcd_init();                                       /* 初始化LCD */
    /* 显示LCD屏ID信息 */
    sprintf((char *)lcd_id, "LCD ID: %04X", lcddev.id);
   
    while (1)
    {
      switch (x)
      {
            case 0:
            {
                lcd_clear(WHITE);
                break;
            }
            case 1:
            {
                lcd_clear(BLACK);
                break;
            }
            case 2:
            {
                lcd_clear(BLUE);
                break;
            }
            case 3:
            {
                lcd_clear(RED);
                break;
            }
            case 4:
            {
                lcd_clear(MAGENTA);
                break;
            }
            case 5:
            {
                lcd_clear(GREEN);
                break;
            }
            case 6:
            {
                lcd_clear(CYAN);
                break;
            }
            case 7:
            {
                lcd_clear(YELLOW);
                break;
            }
            case 8:
            {
                lcd_clear(BRRED);
                break;
            }
            case 9:
            {
                lcd_clear(GRAY);
                break;
            }
            case 10:
            {
                lcd_clear(LGRAY);
                break;
            }
            case 11:
            {
                lcd_clear(BROWN);
                break;
            }
      }
      
      lcd_show_string(10, 40, 240, 32, 32, "APM32", RED);
      lcd_show_string(10, 80, 240, 24, 24, "TFTLCD TEST", RED);
      lcd_show_string(10, 110, 240, 16, 16, "ATOM@ALIENTEK", RED);
      lcd_show_string(10, 130, 240, 16, 16, (char *)lcd_id, RED);
      
      x++;
      
      if (x == 12)
      {
            x = 0;
      }
      LED0_TOGGLE();
      delay_ms(1000);
    }
}
从上面的代码中可以看出,在初始化完LCD后,便在LCD上显示一些本实验的相关信息,随后便每间隔1000毫秒就更换一次LCD屏幕显示的背景色。
页: [1]
查看完整版本: 《ATK-DFPGL22G之FPGA开发指南_V1.0》第二十五章 TFTLCD(MCU屏)实验