【目的】
使用stm32cubeMAX创建基于MDK工程,驱动LCD屏。
【步骤】
1、打开stm32cubeMAX,创建一个基于STM32H7S7L8H的基础工程。
2、添加App的LTDC,Display Type选择RG888,配置参数如下:
1)水平与垂直参数,我这里直接使用了官方demo的参数。
2)这里我只使用了1个图层,它的配置参数如下:
这里我也是借用了官方示例的一个图像来做演示,创建一个480*272大小的图像,放置于0,100的地方。
3)GPIO的设置,开启LTDC后,会默认给出GPIO的基本配置。经查看原理图中的LCD
再添加PA6为LTDC_B7,同时设置PE15为普通的输出模式,PG15为背光控制。
配置好后,生成MDK工程。
使用MDK打开新建的工程。需要添加用户代码才能成功驱动。
1、添加MPU配置代码,在stm32cubeMAX中,配置是禁用了MPU的配置的,所以在main中先行MPU配置。
MPU配置,首先要选择MDK的sct分散加载文件,在MPU配置中,是从该文件进行读取并配置的。在mdk的link中选择已存在的.\stm32h7rsxx_RAMxspi1_ROMxspi2.sct这个加载文件。
其文件内容如下:
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LOAD_FLASH 0x70000000 0x08000000 { ; load region size_region
ER_ROM 0x70000000 0x08000000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
.ANY (+XO)
}
ER_ITCM 0x00000000 0x00010000 { ;
}
RW_DTCM 0x20000000 0x00010000 { ; RW data
*(STACK)
*(HEAP)
}
RW_SRAMAHB 0x30000000 0x8000 {
}
RW_BKPSRAM 0x38800000 0x1000 {
}
RW_EXTRAM 0x90000000 0x2000000 {
}
RW_RAM 0x24000000 0x00072000-0x400 {
.ANY (+RW +ZI)
}
RW_NONCACHEABLEBUFFER 0x24072000-0x400 0x400 {
*(noncacheable_buffer)
}
}
此文件把代码放到了外置的flash上面执行。
MPU的配置,这个函数我也是直接抄了示例中的代码。他的主要思路就是读取sct文件中的配置,然后对其进行配置:
/**
* @brief This function configures the MPU context of the application.
* @retval None
*/
void MPU_Config(void)
{
MPU_Region_InitTypeDef MPU_InitStruct = {0};
uint32_t index = MPU_REGION_NUMBER0;
uint32_t address;
uint32_t size;
/* Disable the MPU */
HAL_MPU_Disable();
/* Initialize the background region */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.Number = index;
MPU_InitStruct.BaseAddress = 0x0;
MPU_InitStruct.Size = MPU_REGION_SIZE_4GB;
MPU_InitStruct.SubRegionDisable = 0x87;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
index++;
/* Initialize the region corresponding to external RAM */
#if defined ( __ICCARM__ )
extern uint32_t __region_EXTRAM_start__;
extern uint32_t __region_EXTRAM_end__;
address = (uint32_t)&__region_EXTRAM_start__;
size = (uint32_t)&__region_EXTRAM_end__ - (uint32_t)&__region_EXTRAM_start__ + 1;
#elif defined (__CC_ARM) || defined(__ARMCC_VERSION)
extern uint32_t Image$$RW_EXTRAM$$Base;
extern uint32_t Image$$RW_EXTRAM$$ZI$$Length;
extern uint32_t Image$$RW_EXTRAM$$Length;
address = (uint32_t)&Image$$RW_EXTRAM$$Base;
size = (uint32_t)&Image$$RW_EXTRAM$$Length + (uint32_t)&Image$$RW_EXTRAM$$ZI$$Length;
#elif defined ( __GNUC__ )
extern uint32_t __EXTRAM_BEGIN;
extern uint32_t __EXTRAM_SIZE;
address = (uint32_t)&__EXTRAM_BEGIN;
size = (uint32_t)&__EXTRAM_SIZE;
#else
#error "Compiler toolchain is unsupported"
#endif
if (size != 0)
{
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.Number = index;
MPU_InitStruct.SubRegionDisable = 0u;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
MPU_AdjustRegionAddressSize(address, size, &MPU_InitStruct);
HAL_MPU_ConfigRegion(&MPU_InitStruct);
index++;
}
/* Initialize the non cacheable region */
#if defined ( __ICCARM__ )
/* get the region attribute form the icf file */
extern uint32_t NONCACHEABLEBUFFER_start;
extern uint32_t NONCACHEABLEBUFFER_size;
address = (uint32_t)&NONCACHEABLEBUFFER_start;
size = (uint32_t)&NONCACHEABLEBUFFER_size;
#elif defined (__CC_ARM) || defined(__ARMCC_VERSION)
extern uint32_t Image$$RW_NONCACHEABLEBUFFER$$Base;
extern uint32_t Image$$RW_NONCACHEABLEBUFFER$$Length;
extern uint32_t Image$$RW_NONCACHEABLEBUFFER$$ZI$$Length;
address = (uint32_t)&Image$$RW_NONCACHEABLEBUFFER$$Base;
size = (uint32_t)&Image$$RW_NONCACHEABLEBUFFER$$Length + (uint32_t)&Image$$RW_NONCACHEABLEBUFFER$$ZI$$Length;
#elif defined ( __GNUC__ )
extern int __NONCACHEABLEBUFFER_BEGIN;
extern int __NONCACHEABLEBUFFER_END;
address = (uint32_t)&__NONCACHEABLEBUFFER_BEGIN;
size = (uint32_t)&__NONCACHEABLEBUFFER_END - (uint32_t)&__NONCACHEABLEBUFFER_BEGIN;
#else
#error "Compiler toolchain is unsupported"
#endif
if (size != 0)
{
/* Configure the MPU attributes as Normal Non Cacheable */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = index;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
MPU_AdjustRegionAddressSize(address, size, &MPU_InitStruct);
HAL_MPU_ConfigRegion(&MPU_InitStruct);
index++;
}
/* Initialize the region corresponding to the execution area
(external or internal flash or external or internal RAM
depending on scatter file definition) */
#if defined ( __ICCARM__ )
extern uint32_t __ICFEDIT_region_ROM_start__;
extern uint32_t __ICFEDIT_region_ROM_end__;
address = (uint32_t)&__ICFEDIT_region_ROM_start__;
size = (uint32_t)&__ICFEDIT_region_ROM_end__ - (uint32_t)&__ICFEDIT_region_ROM_start__ + 1;
#elif defined (__CC_ARM) || defined(__ARMCC_VERSION)
extern uint32_t Image$$ER_ROM$$Base;
extern uint32_t Image$$ER_ROM$$Limit;
address = (uint32_t)&Image$$ER_ROM$$Base;
size = (uint32_t)&Image$$ER_ROM$$Limit-(uint32_t)&Image$$ER_ROM$$Base;
#elif defined ( __GNUC__ )
extern uint32_t __FLASH_BEGIN;
extern uint32_t __FLASH_SIZE;
address = (uint32_t)&__FLASH_BEGIN;
size = (uint32_t)&__FLASH_SIZE;
#else
#error "Compiler toolchain is unsupported"
#endif
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.Number = index;
MPU_InitStruct.SubRegionDisable = 0u;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
MPU_AdjustRegionAddressSize(address, size, &MPU_InitStruct);
HAL_MPU_ConfigRegion(&MPU_InitStruct);
index++;
/* Reset unused MPU regions */
for(; index < __MPU_REGIONCOUNT ; index++)
{
/* All unused regions disabled */
MPU_InitStruct.Enable = MPU_REGION_DISABLE;
MPU_InitStruct.Number = index;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
}
/* Enable the MPU */
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}
/**
* @brief This function adjusts the MPU region Address and Size within an MPU configuration.
* @param Address memory address
* @param Size memory size
* @param pInit pointer to an MPU initialization structure
* @retval None
*/
void MPU_AdjustRegionAddressSize(uint32_t Address, uint32_t Size, MPU_Region_InitTypeDef* pInit)
{
/* Compute the MPU region size */
pInit->Size = ((31 - __CLZ(Size)) - 1);
if (Size > (1 << (pInit->Size + 1)))
{
pInit->Size++;
}
uint32_t Modulo = Address % (1 << (pInit->Size - 1));
if (0 != Modulo)
{
/* Align address with MPU region size considering there is no need to increase the size */
pInit->BaseAddress = Address - Modulo;
}
else
{
pInit->BaseAddress = Address;
}
}
接下来,要在LTDC_init中添加自定义的函数,他主要是重新配置的LTDC的时钟:
/* Typical PCLK is 25 MHz so the PLL3R is configured to provide this clock */
/* LCD clock configuration */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL1.PLLState = RCC_PLL_NONE;
RCC_OscInitStruct.PLL2.PLLState = RCC_PLL_NONE;
RCC_OscInitStruct.PLL3.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL3.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL3.PLLM = 4;
RCC_OscInitStruct.PLL3.PLLN = 25;
RCC_OscInitStruct.PLL3.PLLP = 2;
RCC_OscInitStruct.PLL3.PLLQ = 20;
RCC_OscInitStruct.PLL3.PLLR = 16;
RCC_OscInitStruct.PLL3.PLLS = 2;
RCC_OscInitStruct.PLL3.PLLT = 2;
RCC_OscInitStruct.PLL3.PLLFractional = 0;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
/* Initialization error */
while(1);
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
PeriphClkInit.LtdcClockSelection = RCC_LTDCCLKSOURCE_PLL3R;
if(HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
while(1);
}
/* USER CODE END LTDC_MspInit 1 */
}
到些配置完成,我们把复例文件复制进工程目录里面,效果如封面所示。
在主程序中,先对MPU进行配置,然后加载LTDC,就可以成功的驱动LCD屏了。
int main(void)
{
/* USER CODE BEGIN 1 */
MPU_Config();
/* USER CODE END 1 */
/* Enable the CPU Cache */
/* Enable I-Cache---------------------------------------------------------*/
SCB_EnableICache();
/* Enable D-Cache---------------------------------------------------------*/
SCB_EnableDCache();
/* MCU Configuration--------------------------------------------------------*/
/* Update SystemCoreClock variable according to RCC registers values. */
SystemCoreClockUpdate();
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_LTDC_Init();
效率高啊
请问你的芯片选的啥型号?Keil的软件包哪里下载的?Keil官网找不到软件包啊
在stm32cube_fw_h7rs_v110.zip的包里面。目录为:\stm32cube_fw_h7rs_v110\STM32Cube_FW_H7RS_V1.1.0\Utilities\PC_Software
可以再详细一些吗?