Bootloader应用笔记之AN2295分析(添加引导MQX Keil工程)

Document created by Const Yu Employee on Dec 15, 2013
Version 1Show Document
  • View in full screen mode

分享自China-FAE team同事,在此谢过!


有客户需要bootloader功能,于是从网上下到最新版本的AN2295,发现里面添加了很多的内容,包括支持了很多新的器件,比如KM系列,但是真正把它在板子上跑起来,却花了2天时间,为了减少大家工作量,不在重蹈覆辙,我在这里share给大家,目前该代码在FRDM_KL25以及TWR-K60D100M上跑起来了。遇到的问题主要有如下几点:

 

问题1:

 

在工程中使用除法命令:

a =a /100;

会报错:

Error[Li005]: no definition for "__aeabi_uidiv" [referenced from D:\Customer\XinRuiYang\an2295sw_Kl25\src\Kinetis\IAR_6_4\Kinetis L Debug\Obj\bootloader.o]

 

原因是:

Image.png

这里Lib选择的是None,说明没有使用任何库,所以不能使用除法。

 

打开库后,可能会占用比较大的空间,所以不推荐使用。

 

 

问题2:

 

FRDM_KL25使用默认代码频率,波特率有问题,发送data = 0但是实际发送值为0x80,通过更改主频为48M,然后分频解决。附件有参考代码。TWR-K60100DM没有此问题。

 

 

问题3:

 

FRDM_KL25板子,如果不使能BOOTLOADER_AUTO_TRIMMING这个宏,即不调用SlaveFrequencyCalibration();函数时,

代码上电不能直接运行,而使能该函数后,会一直进行校准频率,上位机无法通讯,查找代码发现:

 

上版代码为

        #if BOOTLOADER_AUTO_TRIMMING == 1         
             if(UART_GetChar() != BOOT_CMD_ACK)
             {
               SlaveFrequencyCalibration();
             }
                             
         #endif

本版代码为:

        #if BOOTLOADER_AUTO_TRIMMING == 1         
               SlaveFrequencyCalibration();           
         #endif

修改为上版代码,可以正常运行并跑起来。

 

 

但是不使能BOOTLOADER_AUTO_TRIMMING这个宏,代码依旧跑不起来,现象就是仿真时没有问题,可以正常跑起来,但是如果是上电直接运行,就不能正常通讯:

 

 

这个问题出在了USB插拔瞬间,KL25会收到一个数据,该数据并不是上位机下发的FC码,如果不使能BOOTLOADER_AUTO_TRIMMING这个宏,代码会误认为自己进入

等待上位机下发数据的状态机,导致通讯错误。在SlaveFrequencyCalibration(); 函数中,有软件复位功能,会让插拔稳定后KL25不在接收到异常数据,以此保证状态机的正确。

 

 

问题4:

 

仿真时全速跑起来时,指针经常回到__main,说明波特率有问题,代码进入SlaveFrequencyCalibration中,复位了。

 

 

AN2295引导MQX Keil工程

 

AN2295的文档已经说明如何修改CW IAR的工程以便让Bootlaoder引导,但是没有Keil工程的说明,这个就只能自己动手啦。

首先肯定会想到修改scf文件:

#define USERFLASH_BASE_ADDR    0x00060000

#define INTFLASH_BASE_ADDR     0x00000000

#define INTFLASH_SIZE          (USERFLASH_BASE_ADDR - INTFLASH_BASE_ADDR)

 

 

#define MY_ALIGN(address, alignment) ((address + (alignment-1)) AND ~(alignment-1))

 

 

LOAD_REGION_INTFLASH INTFLASH_BASE_ADDR INTFLASH_SIZE

{

    VECTORS INTFLASH_BASE_ADDR

    {

        vectors.o (.vectors_rom,+FIRST)

        vectors.o (.cfmconfig)

    }

 

 

    CODE +0

    {

        * (InRoot$$Sections)      ; All library sections for example, __main.o,

                                  ; __scatter*.o, __dc*.o, and * Region$$Table

        * (KERNEL)

        * (TEXT)

        * (+RO)

    }

 

 

    RAM_VECTORS 0x1FFF0000 ; For ram vector table. Used when  MQX_ROM_VECTORS is set to zero.

    {

        vectors.o (.vectors_ram)

    }

 

    NOUSER +0

    {

        * (.nouser)

    }

 

 

    ROUSER MY_ALIGN(ImageLimit(NOUSER), 32)

    {

        * (.rouser)

    }

 

 

    RWUSER MY_ALIGN(ImageLimit(ROUSER), 32)

    {

        * (.rwuser)

    }

 

 

    DATA MY_ALIGN(ImageLimit(RWUSER), 32)

    {

        * (+RW)

        * (+ZI)

    }

 

 

    USB_BDT MY_ALIGN(ImageLimit(DATA), 512)

    {

        * (.usb_bdt)

    }

 

 

    KERNEL_DATA_START MY_ALIGN(ImageLimit(USB_BDT), 0x10)

    {

        * (KERNEL_DATA_START)     ; start of kernel data

    }

 

 

    KERNEL_DATA_END 0x2000FFF0      ; RAM_END

    {

        * (KERNEL_DATA_END)     ; end of kernel data

    }

 

 

    ; mem_init writes a storeblock_struct at the end of kernel data,

    ; max size 32 bytes, so use 0x100 offset

    BOOT_STACK_ADDR 0x2000FEF0

    {

        * (BOOT_STACK)

    }

}

 

都是按偏移算的,应该只改INTFLASH_BASE_ADDR     0x00004000就O了,找了个最简单的工程:mqx\examples\hello,编译生成S19文件,通过bootloader下载进片子,

按reset后看屏幕,始终木有出现hello world,没办法,只能上debug了。

 

打开AN2295工程,加载调试环境,然后在JumpToUserApplication函数上下断点,中断后,单步执行到在__asm("mov pc, r1"); 函数,继续在汇编窗口点单步执行,之后就完全跟crack有点类似,一直点,直到芯片复位,说明之前点那一下是key point,然后对照map文件,于是找到了复位点:

 

init_hardware->_bsp_initialize_hardware->_bsp_watchdog_disable();执行后会复位

不管啦,直接把它屏蔽掉,反正之前就已经关闭看门狗了。

重新编译,继续上。

还是没看到期待已久的hello world,肿么办?


重复上面的方法,发现又一个key point:

_sched_start_internal

查看代码发现,这是一个系统call,应该是从vector 11调用的,查看下寄存器:

keil-scb.png

SCB_VTOR 肿么变成0了,bootloader中已经改成0x4000了,什么时候变成0了.......

代码太多了,不知道从哪儿看起,内存断点是个好东西哈,IAR中没找见在哪儿下,算了,换Keil吧。

用Keil打开AN2295工程,加载调试,然后在0xE000ED08(SCB_VTOR )下写断点,直接run,等待中断吧:

 

_time_set_timer_vector函数修改了SCB_VTOR,

大概路径是_bsp_enable_card->BSP_INTERRUPT_VECTOR_TABLE->BSP_TIMER_INTERRUPT_VECTOR

哈哈,找代码看看:

__VECTOR_TABLE_ROM_START 是这个宏搞的鬼。

仔细对比代码,发现__VECTOR_TABLE_ROM_START 这个宏是通过条件编译区分开的,IAR是通过icf文件定义的

而Keil是通过#define 来实现的。好了,修改对应的值为0x4000,重新编译,下载,搞定,可以看到hello world喽。


总结一下,使用AN2295引导MQX Keil工程需要做以下3点修改:

1.scf文件INTFLASH_BASE_ADDR     0x00000000改为0x00004000

2.屏蔽_bsp_watchdog_disable()该函数

3.修改__VECTOR_TABLE_ROM_START为0x00004000.

 

Attachments

    Outcomes