STM32MP135平台基于HAL库创建Bare Metal裸机工程并从SD卡启动

4 篇文章 0 订阅
3 篇文章 0 订阅
本文详细介绍了如何在STM32MP135微处理器上使用STM32官方HAL库创建BareMetal裸机工程,并通过SD卡启动。步骤包括使用CubeIDE设置工程、配置硬件、编写并调试代码,以及烧录程序到SD卡以实现从SD启动用户程序。
摘要由CSDN通过智能技术生成

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" "${gnu_tools_for_stm32_compiler_path}"  "${BuildArtifactFileBaseName}"

作者的实际命令为:

"C:\Users\Administrator\STM32Cube\Repository\STM32Cube_FW_MP13_V1.0.0\Utilities\ImageHeader\postbuild_STM32MP13.sh" "${gnu_tools_for_stm32_compiler_path}"  "${BuildArtifactFileBaseName}"

​ 如图:

在这里插入图片描述

  • 重新编译用户程序,可以看到在编译后生成bin文件后执行了脚本文件,添加了header,生成了stm32文件,一会烧写时使用

    在这里插入图片描述

  • 准备好SD_Ext_Loader.bin和STM32PRGFW_UTIL_MP13xx_CP_Serial_Boot.stm32,HAL库中有提供,使用Everything可以快速搜索到

  • 准备好分区表文件FlashLayout_OpenBL_ExtLoaderSDMMC_SerialBoot.tsv,HAL库中同样有提供

  • 准备好的文件如下:

    在这里插入图片描述

  • 修改分区表文件tsv,使用文本编辑工具打开,根据实际情况修改用户程序文件名

    在这里插入图片描述

  • 启动拨码开关拨至在这里插入图片描述
    ,从USB启动,重新连接至计算机

  • 启动CubeProgrammer,使用串口连接目标设备,在弹出的Open File对话框中选择分区表文件在这里插入图片描述

  • 选择好固件所在路径,点击Download烧写固件到SD卡

    在这里插入图片描述

  • 等待烧写完成

    在这里插入图片描述

  • 拨码开关拨至在这里插入图片描述
    ,从SD卡加载,按下复位按键或重新上电,观察运行效果

  • 至此,完成烧写程序至SD卡,并实现从SD加载用户程序运行

  • 21
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值