分享:PSoC4 Uart Bootloader,不使用Bootloader组件,可更新程序并引导Bootloadable。

公告

大中华汽车电子生态圈社区并入开发者社区- 更多资讯点击此

Tip / 登入 to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
idream
Level 3
Level 3
50 sign-ins First comment on blog 10 replies posted

分享:PSoC4 Uart Bootloader,不使用Bootloader组件,可更新程序并引导Bootloadable。

连接:

https://xarm.gitee.io/2022/11/20/PSoC4/PSoC4Bootloader/

 

PSoC4 Bootloader and Bootloadable

参考文档:Infineon-AN68272 - PSoC_4…_UART_Bootloader-ApplicationNotes-v16_00-EN.pdf

参考这篇文档很容易就可以实现PSoC uart的bootloader和bootloadable,So…这不是今天的主角,今天的主角是简单的、能看的懂的自实现的uart bootloader,并且可以引导运行bootloadable APP。

一、先简单过一遍官方的Bootloader和Bootloadable:

  1. 实现: 实现过程很简单,只要分别在各自的工程中加入Bootloader和Bootloadable控件即可。
  2. 共享:Bootloader和Bootloadable共享变量:cyBtldrRunType
  3. 从Btl跳转至App … 这有点复杂,所有相关操作均在Bootloader.c中,2900+行,兼容各种PSoC 3、4、5,读起来晦涩难懂,这就是为什么要自己实现个BTL,稍后再记录它吧。
  4. 从App跳转至Bootloader的实现:调用 Bootloadable_Load 即可。
 
C
void Bootloadable_Load(void) 
{
    /* Schedule Bootloader to start after reset */
    Bootloadable_SET_RUN_TYPE(Bootloadable_SCHEDULE_BTLDR);    //Set cyBtldrRunType

    CySoftwareReset();    //软复位
}

#define Bootloadable_SET_RUN_TYPE(x)        (cyBtldrRunType = (x))

#define Bootloadable_SCHEDULE_BTLDB             (0x80u)
#define Bootloadable_SCHEDULE_BTLDR             (0x40u)
#define Bootloadable_SCHEDULE_MASK              (0xC0u)

// Set cyBtldrRunType = Bootloadable_SCHEDULE_BTLDR;
  1. Bootloadable生成的文件格式说明:参考AN68272 Append B,

    • .elf : 包含各种调试信息的文件。

    • .hex :合并了bootloader、meta区的整个文件,可用于生产。

    • .cyacd:包含一个header line和诸多flash line,

    Header line: [4 Bytes Silicon ID] + [1Byte Silicon rev] + [1Byte checksum type]

    Flash line: [1 Byte Array ID] + [2 Bytes row number] + [2Bytes data length] + [N Bytes data] + [1 Byte checksum]

    checksum type: 0 - 和校验,1 - CRC-16

  2. Metadata: 位于flash最后一行的最后64字节,PSoC4的格式如下:

 
C
//metadata struct
#pragma pack(1)                    //按字节对齐
typedef struct
{
    uint8_t     appCheckSum;    //B0
    uint32_t    appAddress;     //B1~B4
    uint32_t    lastBtlRow;     //B5~B8
    uint32_t    appLength;      //B9~B0C
    uint8_t     NA1;            //B0D
    uint8_t     NA2;            //B0E
    uint8_t     NA3;            //B0F
    uint8_t     appActive;      //B10
    uint8_t     appVerified;    //B11
    uint8_t     btlVersion;     //B12
    uint16_t    appID;          //B13~B14
    uint16_t    appVersion;     //B15~B16
    uint16_t    appCustomID;    //B17~B18
}strMetadata;       //__attribute__((aligned(1))) 
#pragma pack ()     
  1. Bootloadable生成的.cyacd格式中,最后一行的flash data数据,就是如上的mata数据。其中:appLength、appCheckSum、appAddress等是bootloader用于校验app及跳转app的地址。
  2. PSoC工程有如下几种类型,通过CYDEV_PROJ_TYPE定义工程类型。
 
C
#define CYDEV_PROJ_TYPE_STANDARD 0
#define CYDEV_PROJ_TYPE_BOOTLOADER 1
#define CYDEV_PROJ_TYPE_LOADABLE 2
#define CYDEV_PROJ_TYPE_MULTIAPPBOOTLOADER 3
#define CYDEV_PROJ_TYPE_LOADABLEANDBOOTLOADER 4
#define CYDEV_PROJ_TYPE_LAUNCHER 5

#define CYDEV_PROJ_TYPE 2

二、手写一个 Uart Bootloader:

在之前的UART的工程上,增加协议、flash操作、跳转app前的校验及跳转函数即可。具体的请参考工程源码。下面是几点注意的地方:

  1. 由于是普通工程(未包含Bootloader组件),所以CYDEV_PROJ_TYPE被定义为 CYDEV_PROJ_TYPE_STANDARD = 0。这个影响了cyBtldrRunType:普通工程中未定义该变量。如果CYDEV_PROJ_TYPE不为0,则会在Cm0plusStart.c中定义该变量。

  2. App-Bootloadable的cm0plusgcc.ld连接文件中,将cyBtldrRunType链接至bootloaderruntype段:

     
    C
    // Bootloadable - cm0plusgcc.ld
    __attribute__ ((section(".bootloaderruntype")))
        volatile uint32 cyBtldrRunType;
    
        .ramvectors (NOLOAD) : ALIGN(8)
        {
          __cy_region_start_ram = .;
          KEEP(*(.ramvectors))
        }
        .btldr_run (NOLOAD) : ALIGN(8)
        {
            KEEP(*(.bootloaderruntype))
        }
        .noinit (NOLOAD) : ALIGN(8)
        {
          KEEP(*(.noinit))
        }

    而普通工程中并没有 .btldr_run 段,ramvectors下接着就是noinit段。

     
    C
    // CYDEV_PROJ_TYPE = CYDEV_PROJ_TYPE_STANDARD  - cm0plusgcc.ld   
        .ramvectors (NOLOAD) : ALIGN(8)
        {
          __cy_region_start_ram = .;
          KEEP(*(.ramvectors))
        }
        .noinit (NOLOAD) : ALIGN(8)
        {
          KEEP(*(.noinit))
        }

    尝试过在cm0plusgcc.ld中手动插入btldr_run段,clean & rebuild后又被清掉,此路不通。

    但是:可以定义一个变量cyBtldrRunTypeB放在noinit段中,查看并对比生成的map文件:

     
    C
    // CYDEV_PROJ_TYPE = CYDEV_PROJ_TYPE_STANDARD  - cm0plusgcc.ld   
    CY_NOINIT volatile uint32_t cyBtldrRunTypeB; //CY_NOINIT 段是和Bootloadable段地址一样
    
    .noinit         0x200000b0        0x4
     *(.noinit)
     .noinit        0x200000b0        0x4 .\CortexM0p\ARM_GCC_541\Debug\btl.o
                    0x200000b0                cyBtldrRunTypeB
    
    //Bootloadable    
    .btldr_run      0x200000b0        0x4
     *(.bootloaderruntype)
     .bootloaderruntype
                    0x200000b0        0x4 .\CortexM0p\ARM_GCC_541\Debug\Cm0plusStart.o
                    0x200000b0                cyBtldrRunType    

    cyBtldrRunType 和 cyBtldrRunTypeB都位于0x200000b0地址。

    这样在APP中调用Bootloadable_Load 函数,会设置cyBtldrRunType = Bootloadable_SCHEDULE_BTLDR,软复位后进入自定义的Bootloader,通过访问相同地址的cyBtldrRunTypeB并判断是否为Bootloadable_SCHEDULE_BTLDR即可。

  1. 跳转:跳转参考官方Bootloader中实现:

     
    C
    /* Moves argument appAddr (RO) into PC, moving execution to appAddr */
    #if defined (__ARMCC_VERSION)
        __asm static void CustomBootloader_LaunchBootloadable(uint32 appAddr)
        {
            BX  R0
            ALIGN
        }
    #elif defined(__GNUC__)
        __attribute__((noinline)) /* Workaround for GCC toolchain bug with inlining */
        __attribute__((naked))
        static void CustomBootloader_LaunchBootloadable(uint32 appAddr)
        {
            __asm volatile("    BX  R0\n");
        }
    #elif defined (__ICCARM__)
        static void CustomBootloader_LaunchBootloadable(uint32 appAddr)
        {
            __asm volatile("    BX  R0\n");
        }
    #endif  /* (__ARMCC_VERSION) */
    
    CustomBootloader_LaunchBootloadable(meta->appAddress);     //校验通过 直接跳到APP区

    跳转地址需要注意:

    CustomBootloader_LaunchBootloadable(meta->appAddress); //校验通过 直接跳到APP区

    跳转的地址不是设置的APP起始地址,而是meta区中存储的appAddress,比如在Bootloadable组件中,选择Manual application image placement: 0x00004000 , App从Flash 16KB地址开始,但是存储在meta->appAddress中的值并不是0x00004000 ,而是偏移了0x11个字节 - 0x4011,所以跳转必须要使用meta中存储的该地址。

  2. 跳转时需要使用meta->appAddress的值,但是校验APP的checksum时,需要从Manual application image placement地址开始,比如0x4000,长度为meta->appLength

     
    C
    uint8_t sum = 0;    
    uint8_t * p = (uint8_t *)STARTAPP_ADDR;    
    for(uint32_t i=0;i < meta->appLength; i++)
    {
        sum += p[i];
    }
    sum = ( uint8_t )1u + ( uint8_t )(~sum);
    
    if(sum != meta->appCheckSum)    return 6;

三、 PC APP

  1. 官方提供了Bootloader Host软件,位于D:\Cypress\PSoC Creator\4.4\PSoC Creator\bin目录下,测试使用官方的Bootloader和Bootloadable组件,可以使用该软件测试bootloader.
  2. 同时也提供了相关的参考代码,位于: D:\Cypress\PSoC Creator\4.4\PSoC Creator\cybootloaderutils目录下。参考cybtldr_parse.c实现cyacd格式的解析。
  3. UART协议未使用官方协议,改成我之前用过的简单协议,上位机在之前的串口程序中修改了一个,用于读取并解析.cyacd格式的app文件,并支持将app存储为纯BIN文件,方便使用其他工具升级。
  4. 注:PC APP暂不支持中文路径。

 

 

 

PSoC4 Uart BTL PC APP

 

 

可以看到如下信息:

Silicon ID:0x257C1175,校验和为普通SUM校验。

Flash Line信息:ROW Num64 ~ ROW Num72,为Flash Data。

ROW Num 511 : MetaData。

串口调试信息:

 

 

 

PSoC4 Uart BTL DebugInfor

 

  1. 首次烧录Boot时,运行Bootloader程序。
  2. 通过PC更新过APP后,通过Reboot命令让Bootloader复位重启,运行APP程序。
  3. 可以看出appAddress: 0x4011
  4. 手动按下按键,从App中再跳到bootloader中,此时由于cyBtldrRunTypeB = 0x40,又留在了bootloader中。

欢迎留言交流。 源码下载见附件。

5 回复数
LinglingG_46
Moderator
Moderator
Moderator
500 solutions authored 1000 replies posted 10 questions asked

👍

0 点赞

Hello Lingling.

I'm always interested in Bootloaders.
Can you provide a few sentences in English about the purpose of this thread.
I tried Google Translate and it didn't make much sense.

Thank you.

0 点赞
LinglingG_46
Moderator
Moderator
Moderator
500 solutions authored 1000 replies posted 10 questions asked

This post explains two things.
1:The first thing is that it explains the process of using the components provided by Infineon to implement the bootloader run to bootloable (app). If using the components, we need to comply with our predefined handshake protocol.

LinglingG_46_0-1675150454957.png


2: The second thing is about how to use the customize protocol. Because the essence of boot load is that the MCU receives data through the interface just like i2c,spi,uart,can,lin etc., then write to the corresponding flash, point the PC pointer to the start of the address that needs to be run, then reset the project and you can run a new project.

3: We can check the Flash Memory Usage, then it is easy for us to understand what is boot load.

LinglingG_46_1-1675150892469.png

4: I hope it can be helpful for you.

 

Thank you Lingling for the explanation.

I understand the intent now.

0 点赞
Roy_Liu
Moderator
Moderator
Moderator
5 comments on KBA First comment on KBA 10 questions asked

How do you like the content, @BiBi_1928986 ? Helpful?

Thanks,

Roy Liu
0 点赞