目录
简介
硬件平台及软件版本
CubeMX设置
调试I/O配置
SDRAM配置
LTDC配置
CubeMX生成文件参数配置
程序移植
文件下载百度链接
在正点原子例程中缺少RGBLCD的CubeMX配置,主要提供讲解RGBLCD的CubeMX配置,达到在阿波罗上运行的效果。
阿波罗F7(STM32F767IGT)开发板,4342的480*272像素RGB显示屏。
Keil5、STM32CubeMX5.4。
在将Debug使能后,先对一些可能用到的GPIO进行设置。如下图所示。需要注意的是,仅仅只有PB5在显示屏中作为背光使用,其他I/O作为调试使用。
在使用显示屏时,用到了SRAM,SDRAM通过FMC接口,与STM32相连。关于FMC与SDRAM不做过多解释,在这仅仅讲解如何通过STM32CubeMX进行配置。SDRAM的配置如下图所示。需要特别注意的是Write recovery time选项,在正点原子中的数值是2。
在对SDRAM的参数选项配置完成后需要改变默认的I/O从而与阿波罗的开发板相对应。更改后的I/O如下图。
RGBLCD用的是LTDC,LTDC除了自身外,还需要使能后对时钟进行配置。LTDC的参数配置如下(参数配置跟显示屏有关,可以在正点原子例程中找到对应参数)。
同样的LTDC的IO口也需要改变。
配置完成后对DMA2D使能,设置时钟。
Project Manger中,Project里面设置工程名,保存路径,编译器。并在与Project并列的Code Generator中勾选生成对应的.c和.h文件。之后生成工程。
注意:正点原子的数据类型名与CubeMX生成文件数据类型名不一致,以CubeMX的为准。
关于正点原子变量如无必要建立不在特殊点出。
首先需要将正点原子已经写好的字库文件(font.h),与画笔函数(lcd.c和lcd.h)移植过来。对lcd.c进行更改。主要是初始化函数。其他关于显示屏函数无非就是添加变量,声明定义,不在图书指出。
//初始化lcd
//该初始化函数可以初始化各种型号的LCD(详见本.c文件最前面的描述)
void LCD_Init(void)
{
lcdltdc.pwidth=480; //面板宽度,单位:像素
lcdltdc.pheight=272; //面板高度,单位:像素
lcdltdc.hsw=1; //水平同步宽度
lcdltdc.vsw=1; //垂直同步宽度
lcdltdc.hbp=40; //水平后廊
lcdltdc.vbp=8; //垂直后廊
lcdltdc.hfp=5; //水平前廊
lcdltdc.vfp=8; //垂直前廊
lcdltdc.pixsize=2; //每个像素占2个字节
lcddev.width=lcdltdc.pwidth;
lcddev.height=lcdltdc.pheight;
ltdc_framebuf[0] = (uint32_t *)<dc_lcd_framebuf; //把SDRAM的首地址赋给第一层的地址指针,作为RGBLCD的显存
LTDC_Layer_Parameter_Config(0,(uint32_t)ltdc_framebuf[0],LCD_PIXFORMAT,255,0,6,7,0X000000);//层参数配置
HAL_LTDC_SetWindowPosition(<DC_Handler,0,0,0); //设置窗口的位置
HAL_LTDC_SetWindowSize(<DC_Handler,lcdltdc.pwidth,lcdltdc.pheight,0);//设置窗口大小
LCD_Display_Dir(0); //默认为竖屏
LTDC_Select_Layer(0); //选择第1层
LCD_LED(1); //点亮背光
LCD_Clear(WHITE);
}
特别注意的是需要对SDRAM的部分初始化函数进行移植,主要是需要添加 SDRAM_Initialization_Sequence 函数。关于此方面更改后的代码如下。此段代码来自于正点原子F7的HAL库版本。放在CubeMX生成的fmc.c中。在移植此部分程序时,需要将原来的SDRAM_HandleTypeDef类型的变量替换为hsdram1。
/* USER CODE BEGIN 0 */
//向SDRAM发送命令
//bankx:0,向BANK5上面的SDRAM发送指令
// 1,向BANK6上面的SDRAM发送指令
//cmd:指令(0,正常模式/1,时钟配置使能/2,预充电所有存储区/3,自动刷新/4,加载模式寄存器/5,自刷新/6,掉电)
//refresh:自刷新次数
//regval:模式寄存器的定义
//返回值:0,正常;1,失败.
uint8_t SDRAM_Send_Cmd(uint8_t bankx,uint8_t cmd,uint8_t refresh,uint16_t regval)
{
uint32_t target_bank=0;
FMC_SDRAM_CommandTypeDef Command;
if(bankx==0) target_bank=FMC_SDRAM_CMD_TARGET_BANK1;
else if(bankx==1) target_bank=FMC_SDRAM_CMD_TARGET_BANK2;
Command.CommandMode=cmd; //命令
Command.CommandTarget=target_bank; //目标SDRAM存储区域
Command.AutoRefreshNumber=refresh; //自刷新次数
Command.ModeRegisterDefinition=regval; //要写入模式寄存器的值
if(HAL_SDRAM_SendCommand(&hsdram1,&Command,0X1000)==HAL_OK) //向SDRAM发送命令
{
return 0;
}
else return 1;
}
//在指定地址(WriteAddr+Bank5_SDRAM_ADDR)开始,连续写入n个字节.
//pBuffer:字节指针
//WriteAddr:要写入的地址
//n:要写入的字节数
void FMC_SDRAM_WriteBuffer(uint8_t *pBuffer,uint32_t WriteAddr,uint32_t n)
{
for(;n!=0;n--)
{
*(vuint8_t*)(Bank5_SDRAM_ADDR+WriteAddr)=*pBuffer;
WriteAddr++;
pBuffer++;
}
}
//在指定地址((WriteAddr+Bank5_SDRAM_ADDR))开始,连续读出n个字节.
//pBuffer:字节指针
//ReadAddr:要读出的起始地址
//n:要写入的字节数
void FMC_SDRAM_ReadBuffer(uint8_t *pBuffer,uint32_t ReadAddr,uint32_t n)
{
for(;n!=0;n--)
{
*pBuffer++=*(vuint8_t*)(Bank5_SDRAM_ADDR+ReadAddr);
ReadAddr++;
}
}
//发送SDRAM初始化序列
void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram)
{
uint32_t temp=0;
//SDRAM控制器初始化完成以后还需要按照如下顺序初始化SDRAM
SDRAM_Send_Cmd(0,FMC_SDRAM_CMD_CLK_ENABLE,1,0); //时钟配置使能
//delay_us(500); //至少延时200us
HAL_Delay(1);
SDRAM_Send_Cmd(0,FMC_SDRAM_CMD_PALL,1,0); //对所有存储区预充电
SDRAM_Send_Cmd(0,FMC_SDRAM_CMD_AUTOREFRESH_MODE,8,0);//设置自刷新次数
//配置模式寄存器,SDRAM的bit0~bit2为指定突发访问的长度,
//bit3为指定突发访问的类型,bit4~bit6为CAS值,bit7和bit8为运行模式
//bit9为指定的写突发模式,bit10和bit11位保留位
temp=(uint32_t)SDRAM_MODEREG_BURST_LENGTH_1 | //设置突发长度:1(可以是1/2/4/8)
SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL | //设置突发类型:连续(可以是连续/交错)
SDRAM_MODEREG_CAS_LATENCY_3 | //设置CAS值:3(可以是2/3)
SDRAM_MODEREG_OPERATING_MODE_STANDARD | //设置操作模式:0,标准模式
SDRAM_MODEREG_WRITEBURST_MODE_SINGLE; //设置突发写模式:1,单点访问
SDRAM_Send_Cmd(0,FMC_SDRAM_CMD_LOAD_MODE,1,temp); //设置SDRAM的模式寄存器
//刷新频率计数器(以SDCLK频率计数),计算方法:
//COUNT=SDRAM刷新周期/行数-20=SDRAM刷新周期(us)*SDCLK频率(Mhz)/行数
//我们使用的SDRAM刷新周期为64ms,SDCLK=216/2=108Mhz,行数为8192(2^13).
//所以,COUNT=64*1000*108/8192-20=823
HAL_SDRAM_ProgramRefreshRate(&hsdram1,823);
}
/* USER CODE END 0 */
到此处基本已经完成大多数移植,接下来是对主函数的修改。主函数初始化部分需要进行修改,以及添加测试函数。测试函数与主函数如下。
/* USER CODE BEGIN 0 */
void LTDC_Test(void)
{
static uint32_t i = 0;
HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);
HAL_Delay(1000);
switch(i)
{
case 0:LTDC_Clear(WHITE);break;
case 1:LTDC_Clear(BLACK);break;
case 2:LTDC_Clear(BLUE);break;
case 3:LTDC_Clear(RED);break;
case 4:LTDC_Clear(MAGENTA);break;
case 5:LTDC_Clear(GREEN);break;
case 6:LTDC_Clear(CYAN);break;
case 7:LTDC_Clear(YELLOW);break;
case 8:LTDC_Clear(BRRED);break;
case 9:LTDC_Clear(GRAY);break;
case 10:LTDC_Clear(LGRAY);break;
case 11:LTDC_Clear(BROWN);break;
}
i++;
if(i == 12)
i=0;
POINT_COLOR=RED;
LCD_ShowString(10,40,260,32,32, (uint8_t*)"Apollo STM32F4/F7");
LCD_ShowString(10,80,240,24,24, (uint8_t*)"LTDC TEST");
LCD_ShowString(10,110,240,16,16, (uint8_t*)"ATOM@ALIENTEK");
LCD_ShowString(10,130,240,16,16, (uint8_t*)"1024*800"); //显示LCD ID
LCD_ShowString(10,150,240,12,12, (uint8_t*)"2016/1/6");
}
/* USER CODE END 0 */
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA2D_Init();
/* USER CODE BEGIN 2 */
MX_FMC_Init();
SDRAM_Initialization_Sequence(&hsdram1);//发送SDRAM初始化序列
MX_LTDC_Init();
LCD_Init();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
LTDC_Test();
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
https://pan.baidu.com/s/1AV2ogX98cGV1TmnOE1ILSg