stm32将flash虚拟成U盘来下载程序


经过将stm32的内部flash做成U盘以后,我一直在思考可不可以使我的程序脱离下载器下载呢?也就是说在我没带下载器,也没有带340串口的时候,我写了个程序想立刻玩一玩看看效果。现在用的芯片是103的c8t6,反正,最小的操作空间是1k,也就是一个扇区。我知道这个FAT32文件系统也是从最开始的最开始的指定控件去存放的,那么我只要把程序的开始运行地址给跳转到FAT32文件系统开始操作的地址即可。

基础工程准备

首先准备一个flashU盘的工程,可以直接下载我的链接工程
当然,我也出了制作教程,看我写的文章即可
ykun1

修改进入U盘的条件

首先要确定的一个条件就是,当芯片启动时需要满足何种条件接入电脑的usb芯片会虚拟出U盘,或者说直接运行bin文件。
这时候我想到了一个最简单方法就是通过添加一个引脚的输入,使得在芯片启动后直接读取引脚的高低电平,如果为高就进入U盘模式,如果为低就跳转运行bin文件即可。
进入cubemx随便添加一个PB13作为这个功能的引脚,重新生成代码后展开。
ykun2

添加IAP跳转代码

这里的跳转地址有必要说明一下,(字有点丑请勿介意)芯片内部的flash区域被分成了四个区域,像我们平时用的顶多就是一个芯片厂商提供的bootloader以及用户写程序的部分,但是我想要一个跳转的效果的话就得分区域,其中文件系统部分是由电脑进行初始化的。
ykun3
接下来将跳转部分的代码添加一下;其中跳转地址有必要说明一下,U盘通过电脑格式化以后显示我的U盘的可用空间为25K,而我这块芯片型号stm32f103c8t6的总内存大小为64k;又因为第1k的地址为0x08000000, 所以计算出第前面39k中第39k的地址为0x08009800,所以后面25k的起始地址为0x08009C00;

typedef  void (*pFunction)(void);
#define ApplicationAddress 0x08009C00  //跳转地址
uint32_t JumpAddress;
pFunction Jump_To_Application;

void ProgramIapJump()
{
	__ASM("CPSID  I");
	if(((*(__IO uint32_t *) ApplicationAddress) & 0x2FFE0000) == 0x20000000)
	{
		JumpAddress = *(__IO uint32_t *) (ApplicationAddress + 4);
		Jump_To_Application = (pFunction) JumpAddress;
				
		__set_MSP(*(__IO uint32_t *) ApplicationAddress);
		Jump_To_Application();//
	 }
}

相应的在main函数中做一些条件判断。

/**
  * @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();
//  MX_USB_DEVICE_Init();
  /* USER CODE BEGIN 2 */
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_13))//如果是高就进入U盘
	{
		MX_USB_DEVICE_Init();
	}
	else
	{
		ProgramIapJump();//程序跳转
	}
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  //HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_12);
	  //HAL_Delay(200);
  }
  /* USER CODE END 3 */
}

至此,一个能判断是否跳转运行bin文件的U盘程序就制作完成。

准备一个生成bin文件的例程

接下来就准备写一个bin文件,运行一下看看效果,跑个led试试水(点灯大法)。
同样的用cubemx随便生成一个led的工程后,在main函数中添加闪烁代码;

  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_12);
	  HAL_Delay(200);
  }
  /* USER CODE END 3 */

然后在main函数的开头需要将中断向量进行偏移操作,然后再把中断打开;

  /* USER CODE BEGIN 1 */
	SCB->VTOR=FLASH_BASE|0x9C00;//
	__ASM("CPSIE  I");//汇编,开启中断
  /* USER CODE END 1 */

然后再将target中ROM1的地址重置一下
ykun4

接下来也是最重要的就是让它生成bin文件;生成bin文件主要是通过MDK中的fromelf.exe这个程序来完成的,这个MDK的编译有点类似与Linux里面的makefile,在我们写好程序进行编译的时候就会生成一堆的(.o文件),然后这些文件再链接起来形成hex或者bin文件。
具体操作,在User选项下添加如下代码,并勾选Run #1
其中D:\MDK529是我的MDK安装的地址,下面这段代码的基本意思就是,调用我的MDK自带的fromelf.exe文件,通过依赖./led目录下的led.axf文件生成一个名叫led.bin的文件,并将其放到./led目录下。

D:\MDK529\ARM\ARMCC\bin\fromelf.exe --bin -o ./led/led.bin ./led/led.axf

ykun6

将bin文件放入指定位置运行

通过简单的复制粘贴,或者直接将bin文件拖动到U盘里面即可;
ykun7
最后将PB13引脚置为低电平,复位芯片即可看到led闪起来了。

工程连接

最后附上工程的链接,主要是两个程序,一个U盘跳转的,另外一个则是led应用。
ykun8


版权声明:本文为givemeyouhand原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。