ARM M3、M4系列单片机bootloader介绍以及编写

6 篇文章 0 订阅
1 篇文章 0 订阅

    BootLoader与正常程序在功能上完全一样,可以理解为两个程序,只不过在BootLoader运行完后会跳转到想要运行的程序中去,BootLoader也是主函数开始运行、也可以调用串口等外设,这也是可以串口下载程序的原理吧。在串口接收到你要下载的程序,然后将其写到flash中,再跳转过去,当然不仅仅可以用串口,还可以用其他任何可以进行数据传输的方式。要完成跳转需要进行以下几个操作:

一、明白程序保存在哪,怎么运行的

    现在基本上都是保存在Flash中。要运行的时候PC去取指令,将Flash中的二进制指令读取到并执行,然后PC+4,继续下一个指令(采用流水线预取指就不多说了,这里的重点不是这个)。

二、BootLoader与app存储关系

    从上面可以知道程序都是从Flash的最前面开始运行,在stm32F103ZET6中也就是0x8000 0000,而在NRF52832就是0x0地址了(如图2-1),在找地址的时候我找了好久,里面有好多地址,究竟哪个地址才是?找的时候记住找到Flash就好了,其他的CodeRAM,SRAM的别管,就找到Flash就好了。可以看到他是0地址开始,长度为0x0008 0000个字节,那我们就可以将这个区域划分为两个小区域,A与B,分别用来保存BootLoader与app程序,大小视程序大小而定。这里测试就设置A(BootLoader)大小0x2 0000个字节,B(app)区域就0x6 0000个字节。

                                                                         图2-1  nrf52832内存地址图

三、将两个程序分别下载到设定的地址中

    知道了上述理论知识后进行实践,首先就是这么把程序下载到固定地址上去。平时的时候就用Keil点一下,根本没有注意这些东西,查了一些网页后得到如下结果。如图3-1,打开设置中的Target,可以看到左下角的IROM1后面有Start和Size。里面Start就是程序下载的起始位置,设置为0,然后将Size设置为刚才说的0x2 0000.右边的RAM就是程序运行时候需要的堆栈,不管是BootLoader还是app都使用整个系统全部的RAM,不用修改。

                               

                                                                               图3-1  设置BootLoader下载地址

    然后在Flash Downloade里面Start和size设置为与上述对应,需要注意两个程序都要选择部分擦除,即Erase Sectors,不能全部擦除,否则下了第一个,然后再下第二个的时候,第一个就会被擦除。

            

                                                                      图3-2  Flash download设置图

    同样,在app程序里面根据start = 0x2 0000,size = 0x6 0000进行上述设置,设置完成后如下图所示。

                        

                                                                           图3-3  app下载地址设置

             

                                                                          图3-4  Flash download设置

    完成这些操作后准备工作做得差不多了,接着就要在程序中完成从BootLoader到app的跳转了。

四、编写跳转程序

    在开始之前要注意,在M3、M4架构中,中断向量表都是在程序的起始位置处。接着编写BootLoader程序,没有什么内容,主要就是初始化串口,然后跳转,跳转方式就是去运行一个APP首地址加4的地址强制转换为函数指针的函数。在跳转之前要关闭中断并设置堆栈指针。之所以跳转到首地址+4是因为程序首地址是程序堆栈指针,指向ram,长度为4字节。其后第二个字为reset中断地址,这样跳转可以直接像复位一样直接运行app程序。

typedef __IO uint32_t  vu32;

//设置栈顶地址
//addr:栈顶地址
__asm void MSR_MSP(uint32_t addr) 
{
    MSR MSP, r0 			//set Main Stack value
    BX r14
}
//声明指针函数
void (*jump2app)();

//跳转到应用程序段
//appxaddr:用户代码起始地址.
void iap_load_app(uint32_t appxaddr)
{
	if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000)	//检查栈顶地址是否合法.
	{ 
		jump2app=(void(*)())*(vu32*)(appxaddr+4);		//用户代码区第二个字为复位中断地址		
		MSR_MSP(*(vu32*)appxaddr);					//初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
		for(int i = 0; i < 8; i++)
		{			
			NVIC->ICER[i] = 0xFFFFFFFF;	/* 关闭中断*/
			NVIC->ICPR[i] = 0xFFFFFFFF;	/* 清除中断标志位 */
		}
		jump2app();									//跳转到APP.
	}
}
int main(void)
{
	int i = 0;
    uint32_t err_code;

//初始化串口配置参数
    const app_uart_comm_params_t comm_params =
      {
          RX_PIN_NUMBER,
          TX_PIN_NUMBER,
          RTS_PIN_NUMBER,
          CTS_PIN_NUMBER,
          UART_HWFC,
          false,
          NRF_UART_BAUDRATE_115200
      };
//初始化串口
    APP_UART_FIFO_INIT(&comm_params,
                         UART_RX_BUF_SIZE,
                         UART_TX_BUF_SIZE,
                         uart_error_handle,
                         APP_IRQ_PRIORITY_LOWEST,
                         err_code);

    APP_ERROR_CHECK(err_code);
//输出提示信息
		printf("This is bootloader\r\n");
		nrf_delay_ms(500);
		printf("Gonna to jump to app!\r\n");
        nrf_delay_ms(500);
//跳转
		iap_load_app(0x20000);
}

    然后就要编写app中的程序,首先就是要设置中断向量表地址了。因为最开始设置的为BootLoader中的中断地址即0,现在要将上述的0x00地址添加偏移量,使其指向app的0x2 0000。然后就是正常操作了,打开串口,输出调试信息。将两个程序下载后运行结果如图4-1所示。

void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset)
{ 
  /* Check the parameters */
   
  SCB->VTOR = NVIC_VectTab | (Offset & (uint32_t)0x1FFFFF80);
}
int main(void)
{
	int i = 0;
    uint32_t err_code;
//设置中断向量地址
    NVIC_SetVectorTable(0x20000,0);
//初始化串口配置参数

    const app_uart_comm_params_t comm_params =
      {
          RX_PIN_NUMBER,
          TX_PIN_NUMBER,
          RTS_PIN_NUMBER,
          CTS_PIN_NUMBER,
          UART_HWFC,
          false,
          NRF_UART_BAUDRATE_115200
      };
//初始化串口
    APP_UART_FIFO_INIT(&comm_params,
                         UART_RX_BUF_SIZE,
                         UART_TX_BUF_SIZE,
                         uart_error_handle,
                         APP_IRQ_PRIORITY_LOWEST,
                         err_code);


		printf("Here is the app region,this is APP 1 \r\n");
      while(1)
      {
		nrf_delay_ms(500);
         printf("App 1 count :%d\r\n",++i);
      }
}

      

                                                                      图4-1  程序运行结果

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值