STM32MP135平台基于HAL库创建Bare Metal裸机工程并从SD卡启动
1.引言
首先引用ST官方的介绍:
STM32MP135微处理器 (MPU) 基于单Arm® Cortex®-A7内核,运行频率可达1GHz。STM32MP13 MPU专门面向入门级Linux、裸机或RTOS系统设计,并已预先集成Microsoft Azure RTOS。”
STM32MP135处理器(以下简称MP135)本是一块MPU,主频可达1GHz(我看到的手册及时钟配置下最高实际为900MHz),本该运行Linux内核,这次官方支持了Bare Metal,也就是裸机HAL库,可以实现利用MPU丰富外设资源及实际需求的同时,进一步提升程序运行的实时性,当作一块资源丰富的大单片机用。
这次使用手上的ST官方的MP135DK开发板,使用最新的V1.0.0 HAL库,创建基于MP135的裸机工程,并将程序烧录至SD卡运行。
本文参考:【STM32MP13x直播回顾】 直播答疑汇总 (stmicroelectronics.cn)
2.提前了解
-
MP135启动开关决定了上电时的启动方式
-
MP135是一块标准的MPU,没有内部Flash,只有内部的SYSRAM(128KB)
-
前面两项共同决定了MP135的启动流程与运行流程,实际情况如下
-
综上所述,总结一下MP135的裸机玩法:
- 调试时直接在CubeIDE中进入调试模式,程序会自动被写进内部的SYSRAM中运行,并且可以单步调试。如果程序大小超过了SYSRAM的128KB,则需要先在SYSRAM中运行DDR初始化程序,并在用户程序调试时,将程序加载进DDR中,实现用户程序的调试运行,同样支持单步调试。
- 以上是调试模式的方法,但实际情况通常为从外部Flash或SD卡加载程序运行,这里以SD卡为例,结合上图可知:上电时MP135拨码为外部SD卡启动->加载ROM Code->从SD卡加载第一段程序FSBLA->复制用户程序到DDR->跳转至DDR运行用户程序。
-
最后,明确我们接下来要做的工作:
- 使用CubeIDE或CubeMX建立基于Bare Metal的MP135工程
- 编写代码并调试用户程序
- 在DDR中运行并调试用户程序
- 烧写程序至SD卡,并从SD加载用户程序运行
3.使用CubeIDE或CubeMX建立基于Bare Metal的MP135工程
-
确保已安装或更新CubeIDE至最新,目前最新版本为1.14.1
-
按照常规方法新建STM32工程
-
找到正确的MPU型号
-
为工程命名并指定保存位置,注意工程类型要选择BareMetal裸机工程,点击Finish完成创建
-
至此,完成了使用CubeIDE或CubeMX建立基于Bare Metal的MP135工程
4.编写代码并调试用户程序
-
按照常规方法配置时钟树(System Core -> RCC),在这里配置为外部晶振,也可忽略不配置
-
按照常规方法配置调试引脚为SWD(Trace and Debug -> DEBUG)
-
这里以点亮板载的一颗蓝色LED为例,实现LED闪烁,作为用户程序的功能,由电路图可知引脚为PA14
-
完成后生成代码,工程结构如下
-
作者在图形配置界面为PA14创建了别名"LED",但在生成的代码中并没有看到相关的#define,因此暂时手动控制led闪烁
-
在main.c中手动完善GPIO初始化代码
/** * @brief GPIO Initialization Function * @param None * @retval None */ static void MX_GPIO_Init(void) { /* USER CODE BEGIN MX_GPIO_Init_1 */ GPIO_InitTypeDef gpio_init_structure; /* USER CODE END MX_GPIO_Init_1 */ /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOH_CLK_ENABLE(); /* USER CODE BEGIN MX_GPIO_Init_2 */ __HAL_RCC_GPIOA_CLK_ENABLE(); gpio_init_structure.Pin = GPIO_PIN_14; gpio_init_structure.Mode = GPIO_MODE_OUTPUT_PP; gpio_init_structure.Pull = GPIO_PULLUP; gpio_init_structure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(GPIOA, &gpio_init_structure); /* USER CODE END MX_GPIO_Init_2 */ }
-
完善main函数中的led闪烁代码
/** * @brief The application entry point. * @retval int */ 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(); /* USER CODE BEGIN 2 */ /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_14); HAL_Delay(500); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ }
-
此时编译工程,出现一个警告,暂忽略。将板子拨码开关拨至状态,连接至计算机
-
点击调试按钮,确认待调试的elf程序及调试器接口,点击OK进入调试模式
-
此时进入单步调试模式,程序运行在SYSRAM中
-
点击全速运行,观察LED效果
-
至此,完成了基于STM32MP135裸机代码的编写并在SYSRAM中调试用户程序
5.在DDR中运行并调试用户程序
-
刚才我们实现了在SYSRAM中运行并调试用户程序,若程序超过了SYSRAM的128KB大小,就需要将程序运行在DDR中,这就需要在我们的用户程序之前先实现DDR的初始化,再将用户程序运行在DDR中
-
导入HAL库中的实例工程"DDR_Init"
-
编译"DDR_Init"工程并进入调试,点击全速运行后,板载蓝色LED开始闪烁,说明DDR初始化完成。
-
此时退出调试模式,程序终止,蓝色LED停止闪烁,DDR仍然正常
-
保持板子不断电,继续完成接下来的操作
-
在完成DDR的初始化操作之后,我们要将刚才的用户程序运行在DDR上,需要对原工程进行一些修改:
-
去掉不必要的初始化,如系统时钟初始化,用户程序内如果对系统时钟初始化将会导致DDR功能异常,这里ST的诸多示例工程中用一个宏定义"USE_DDR"决定是否在用户程序中执行系统时钟初始化操作
/** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { #ifndef USE_DDR RCC_OscInitTypeDef RCC_OscInitStruct = { 0 }; if (HAL_RCC_DeInit() != HAL_OK) { Error_Handler(); } /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = 16; RCC_OscInitStruct.HSIDivValue = RCC_HSI_DIV1; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; RCC_OscInitStruct.PLL2.PLLState = RCC_PLL_NONE; RCC_OscInitStruct.PLL3.PLLState = RCC_PLL_NONE; RCC_OscInitStruct.PLL4.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } #endif }
-
在工程属性中配置传递给编译器的宏定义"USE_DDR"
-
工程属性中修改链接文件为stm32mp13xx_a7_ddr.ld,该文件可从其他示例工程中获取,并拷贝至自建工程下,与原链接文件同目录,实现调试时程序加载至DDR中运行。
-
确保stm32mp13xx_a7_ddr.ld中的REGION_ALIAS定义到DDR区域
-
修改Debug配置,删掉调试目标程序Startup中的monitor reset,防止DDR跟着复位
-
-
重新编译程序
-
进入调试模式,此时发现用户程序的断点停留在0xc000开头的DDR处
-
点击全速运行,发现用户程序在DDR中可以正常运行
-
至此,完成在DDR中运行并调试用户程序
6.烧写程序至SD卡,并从SD加载用户程序运行
-
根据前面的介绍,若要实现用户程序从SD卡加载至MP135上运行,我们需要准备以下两个程序,并将其写入SD卡中:
- 初级初始化程序FSBL,被芯片的Rom Code加载,实现DDR的初始化与用户程序的拷贝与加载
- 用户程序,被初始化程序FSB拷贝至DDR并加载
-
除此之外还需准备为烧录工具引导使用的两个文件,HAL库中已提供:
STM32PRGFW_UTIL_MP13xx_CP_Serial_Boot.stm32
SD_Ext_Loader.bin
-
还有烧录工具使用到的分区表文件
FlashLayout_OpenBL_ExtLoaderSDMMC_SerialBoot.tsv
-
FSBLA程序和用户程序需要添加header信息。FSBLA工程选项中在编译后已默认调用post脚本添加了header信息,这里保持默认,准备好编译后生成的FSBLA_Sdmmc1_A7_Signed.bin
-
用户程序的工程选项中,同样地在Build Step中添加编译后执行的命令,其中需要引用需要的postbuild_STM32MP13.sh,根据实际位置完善好以下命令:
“(path_to_STM32CubeMP13 Package)/Utilities/ImageHeader/postbuild_STM32MP13.sh"
“ g n u t o o l s f o r s t m 3 2 c o m p i l e r p a t h " " {gnu_tools_for_stm32_compiler_path}" " gnutoolsforstm32compilerpath""{BuildArtifactFileBaseName}”作者的实际命令为:
“C:\Users\Administrator\STM32Cube\Repository\STM32Cube_FW_MP13_V1.0.0\Utilities\ImageHeader\postbuild_STM32MP13.sh” “ g n u t o o l s f o r s t m 3 2 c o m p i l e r p a t h " " {gnu_tools_for_stm32_compiler_path}" " gnutoolsforstm32compilerpath""{BuildArtifactFileBaseName}”
如图:
-
重新编译用户程序,可以看到在编译后生成bin文件后执行了脚本文件,添加了header,生成了stm32文件,一会烧写时使用
-
准备好SD_Ext_Loader.bin和SD_Ext_Loader.bin,HAL库中有提供,使用Everything可以快速搜索到
-
准备好分区表文件FlashLayout_OpenBL_ExtLoaderSDMMC_SerialBoot.tsv,HAL库中同样有提供
-
准备好的文件如下:
-
修改分区表文件tsv,使用文本编辑工具打开,根据实际情况修改用户程序文件名
-
启动拨码开关拨至
,从USB启动,重新连接至计算机 -
启动CubeProgrammer,使用串口连接目标设备,在弹出的Open File对话框中选择分区表文件
-
选择好固件所在路径,点击Download烧写固件到SD卡
-
等待烧写完成
-
拨码开关拨至
,从SD卡加载,按下复位按键或重新上电,观察运行效果文章来源:https://www.toymoban.com/news/detail-827967.html -
至此,完成烧写程序至SD卡,并实现从SD加载用户程序运行文章来源地址https://www.toymoban.com/news/detail-827967.html
到了这里,关于STM32MP135平台基于HAL库创建Bare Metal裸机工程并从SD卡启动的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!