经过将stm32的内部flash做成U盘以后,我一直在思考可不可以使我的程序脱离下载器下载呢?也就是说在我没带下载器,也没有带340串口的时候,我写了个程序想立刻玩一玩看看效果。现在用的芯片是103的c8t6,反正,最小的操作空间是1k,也就是一个扇区。我知道这个FAT32文件系统也是从最开始的最开始的指定控件去存放的,那么我只要把程序的开始运行地址给跳转到FAT32文件系统开始操作的地址即可。
基础工程准备
首先准备一个flashU盘的工程,可以直接下载我的链接工程
当然,我也出了制作教程,看我写的文章即可
修改进入U盘的条件
首先要确定的一个条件就是,当芯片启动时需要满足何种条件接入电脑的usb芯片会虚拟出U盘,或者说直接运行bin文件。
这时候我想到了一个最简单方法就是通过添加一个引脚的输入,使得在芯片启动后直接读取引脚的高低电平,如果为高就进入U盘模式,如果为低就跳转运行bin文件即可。
进入cubemx随便添加一个PB13作为这个功能的引脚,重新生成代码后展开。
添加IAP跳转代码
这里的跳转地址有必要说明一下,(字有点丑请勿介意)芯片内部的flash区域被分成了四个区域,像我们平时用的顶多就是一个芯片厂商提供的bootloader以及用户写程序的部分,但是我想要一个跳转的效果的话就得分区域,其中文件系统部分是由电脑进行初始化的。
接下来将跳转部分的代码添加一下;其中跳转地址有必要说明一下,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的地址重置一下
接下来也是最重要的就是让它生成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

将bin文件放入指定位置运行
通过简单的复制粘贴,或者直接将bin文件拖动到U盘里面即可;
最后将PB13引脚置为低电平,复位芯片即可看到led闪起来了。
工程连接
最后附上工程的链接,主要是两个程序,一个U盘跳转的,另外一个则是led应用。