Bootloader(三)

五、Bootloader实现实例

1.Flash配置框图


        如果从主机下载flash到SRAM,则该flash将保存在0x20000000-0x200003FF中。
        如果flash驱动器保存在flash中,而不是从主机下载到SRAM, 0x20000000-0x200003FF未被bootloader占用。
 

2.BootLoader完整流程

①系统初始化

static ResultStatus_t SysInit(void)
{
    ResultStatus_t res = SUCC;    // 初始化结果状态为成功
    
    WatchdogInit();          // 初始化看门狗

    if(ERR == ClockInit())    // 初始化时钟,如果失败则设置结果状态为错误
    {
        res = ERR;
    }
    else
    {
        SYSCTRL_EnableModule(SYSCTRL_REGFILE);    // 启用系统控制模块
        
        CrcInit();    // 初始化CRC
#if ((BL_INTERFACE == BL_INTERFACE_CAN_FD)||(BL_INTERFACE == BL_INTERFACE_CAN))
        if(ERR == CanInit())    // 如果接口是CAN或CAN FD,初始化CAN
        {
            res = ERR;
        }
#elif (BL_INTERFACE  == BL_INTERFACE_LIN)
        if(ERR == LinInit())    // 如果接口是LIN,初始化LIN
        {
            res = ERR;
        }
#else
      /*nothing to do*/
#endif         
        PinmuxInit();    // 初始化引脚复用
        
#ifdef BL_FLASH_DRV_FROM_HOST
        // 使闪存驱动标志无效       
        FlashSetFlashDrvFlag(RESET);
        res = FlashInit();    // 初始化闪存
#else
        res = FlashInit();
#endif
        
    }     
    
    return res;    // 返回结果状态
}

②看门狗初始化

static void WatchdogInit(void)
{
#ifdef WATCHDOG_ENABLE    /*如果定义了 WATCHDOG_ENABLE,将执行看门狗初始化逻辑,否则禁用*/
    volatile uint32_t uLoop = 0;  /* 延迟循环变量*/
    
    /* 检查看门狗控制状态寄存器(WDOG_CS)是否已经设置为所需的时钟、模式和中断配置。如果未设                
       置,则执行初始化步骤 */
    if((WDOG_W->WDOG_CS & 0x00070371U) != 0x00040041U)
    {
        /* 解锁看门狗 */
        WDOG->WDOG_CNT.CNT = 0xB0D9A1C4U;
        WDOG->WDOG_CNT.CNT = 0x1A1E3B0FU;
        
        WDOG_W->WDOG_CS = 0x00040041U;  /*设置看门狗控制状态*/
        WDOG->WDOG_TMO.TMO = 9600U;     /*设置超时值*/
    
        while (1U != WDOG->WDOG_CS.CFGUF)/*等待配置更新*/
        {
            if (uLoop > 0xFFFFFU)
            {
                break;
            }

            uLoop++;
        }    
    }
    else
    {
        /* about 300 ms */
        if(SUCC != WDOG_SetTimeoutValue(9600U))
        {
        }
    }
        
    FeedWatchdog();  /*喂狗*/
#else
    WDOG_Disable(); /*失能*/
#endif
}

③系统定时器初始化

static uint32_t SysTickConfigNoInt(uint32_t ticks)
{
    uint32_t res = 0U;
#if (defined(DEV_Z20K118M))|| (defined(DEV_Z20K116M)) || (defined(DEV_Z20K114M)),
/*选择完设备后 检查 ticks 是否超出允许的重装载值。如果超出,设置 res 为 1,表示失败*/
    if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
    {
        res = 1U;                                                   
    }
    else/* 如果未超出,配置 SysTick 寄存器:设置重装载值、优先级、中断和定时器启用状态。*/
    {
        SysTick->LOAD  = (uint32_t)(ticks - 1UL);                         
        NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); 
        SysTick->VAL   = 0UL;                                             
        SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                         SysTick_CTRL_ENABLE_Msk;                         
    }
#else  /* 对于其他设备型号,执行类似的检查和配置,但使用特定设备的 SysTick寄存器和优先级配置*/
    if ((ticks - 1UL) > 0xFFFFFFUL)
    {
        res = 1U;                                                  
    }
    else
    {
        Z20_SYSTICK->LOAD  = (uint32_t)(ticks - 1UL);                         
        INT_SetPriority (SysTick_IRQn, (1UL << 2U) - 1UL);                
        Z20_SYSTICK->VAL   = 0UL;                                             
        Z20_SYSTICK->CTRL  = (1U << 2U) | 1UL;                         
    }
#endif
    return res;                                                     
}

④系统时钟初始化

static ResultStatus_t ClockInit(void)
{
    ResultStatus_t res = SUCC;  /*声明并初始化结果状态变量 res,默认值为成功(SUCC)。*/
#if (defined(DEV_Z20K118M))|| (defined(DEV_Z20K116M)) || (defined(DEV_Z20K114M))
    /* 选择设备型号并选择40MHz作为系统时钟 */
    if(CLK_OSC40MEnable(40U, ENABLE, CLK_OSC_XTAL) != SUCC)
    {
        return ERR;
    }
#else
    if(CLK_OSC40MEnable(CLK_OSC_FREQ_MODE_HIGH, ENABLE, CLK_OSC_XTAL) != SUCC)
    {
        return ERR;
    }
#endif
    if(CLK_SysClkSrc(CLK_SYS_OSC40M) != SUCC)
    {
        res = ERR;
    }
    else
    {
        CLK_SetClkDivider(CLK_CORE, CLK_DIV_1);
        CLK_SetClkDivider(CLK_BUS, CLK_DIV_1);
        CLK_SetClkDivider(CLK_SLOW, CLK_DIV_5);
        /*根据接口类型配置 CAN 或 LIN 的时钟源和分频器。如果是 CAN 接口,将 OSC40M 设置为 CAN 时钟源,并设置分频器为 1;如果是 LIN 接口,将 OSC40M 设置为 LIN 时钟源,并设置分频器为 2。*/
#if ((BL_INTERFACE  == BL_INTERFACE_CAN_FD)||(BL_INTERFACE  == BL_INTERFACE_CAN))
        /* config CAN clock */
        if(ERR == CLK_ModuleSrc(CLK_CAN_ID, CLK_SRC_OSC40M))
        {
            return ERR;
        }
        CLK_SetClkDivider(CLK_CAN_ID, CLK_DIV_1); 
#elif (BL_INTERFACE  == BL_INTERFACE_LIN)
        /* config LIN clock */
        if(ERR == CLK_ModuleSrc(CLK_LIN_ID, CLK_SRC_OSC40M))
        {
            return ERR;
        }
        CLK_SetClkDivider(CLK_LIN_ID, CLK_DIV_2);
#else
        
#endif        
    }     
    
    return res;
}

⑤CRC校验配置

static ResultStatus_t CrcInit(void)
{
    ResultStatus_t res = SUCC;  /*声明并初始化结果变量 res,默认值为 SUCC,表示函数成功执行*/
    SYSCTRL_EnableModule(SYSCTRL_CRC);    /*启用 CRC 模块*/
    
    const CRC_Config_t crcCfg = 
    {
        .seedValue = 0xffffffff,    //CRC 的初始值,设置为 0xffffffff
        .poly = 0x4C11DB7,    //CRC 的多项式,设置为 0x4C11DB7
        .complementRead = CRC_COMPREAD_INVERT_COMP,    //读操作的补码设置
        .dataMode = CRC_MODE_32BIT,    //数据模式
        .readType = CRC_READ_BIT_Y_BYTE_Y,    //读类型
        .writeType = CRC_WRITE_BIT_Y_BYTE_N    //写类型
    };

    CRC_Init(&crcCfg);    /* 初始化结构体内参数*/
    
    return res;
}

⑥引脚复用配置

static void PinmuxInit(void)
{
/*初始化管脚复用配置,根据不同的接口类型(CAN 或 LIN)进行相应的配置*/
    #if ((BL_INTERFACE  == BL_INTERFACE_CAN_FD)||(BL_INTERFACE  == BL_INTERFACE_CAN))
    SYSCTRL_EnableModule(BL_CAN_SYS_PORT);
    SYSCTRL_EnableModule(SYSCTRL_GPIO);

    /*PULL DOWN STB*/
    PORT_PinmuxConfig(BL_CAN_PORT, BL_CAN_STB_IO, BL_CAN_STB_PINMUX);
    GPIO_SetPinDir(BL_CAN_PORT, BL_CAN_STB_IO, GPIO_OUTPUT);
    GPIO_ClearPinOutput(BL_CAN_PORT, BL_CAN_STB_IO);
    
    PORT_PinmuxConfig(BL_CAN_PORT, BL_CAN_TX_IO, BL_CAN_TX_PINMUX);
    PORT_PinmuxConfig(BL_CAN_PORT, BL_CAN_RX_IO, BL_CAN_RX_PINMUX);
    #elif (BL_INTERFACE  == BL_INTERFACE_LIN)
    SYSCTRL_EnableModule(BL_LIN_SYS_PORT);
    SYSCTRL_EnableModule(SYSCTRL_GPIO);
    
    #if (defined(DEV_Z20K118M))|| (defined(DEV_Z20K116M)) || (defined(DEV_Z20K114M))
    /*nothing to do*/
    #else
    SYSCTRL_EnableModule(BL_LIN_SYS_SLB_PORT);
    #endif
    
    PORT_PinmuxConfig(BL_LIN_PORT, BL_LIN_RX_IO, BL_LIN_RX_PINMUX);
    PORT_PinmuxConfig(BL_LIN_PORT, BL_LIN_TX_IO, BL_LIN_TX_PINMUX);
    /* transciever slpeep pin */
    PORT_PinmuxConfig(BL_LIN_SLB_PORT, BL_LIN_SLB_IO, BL_LIN_SLB_PINMUX);
    GPIO_SetPinDir(BL_LIN_SLB_PORT, BL_LIN_SLB_IO, GPIO_OUTPUT);
    /*  pull up  */
    GPIO_SetPinOutput(BL_LIN_SLB_PORT, BL_LIN_SLB_IO);
    
#else
    /* nothing to do */
#endif
}

⑦闪存初始化

ResultStatus_t FlashInit(void)
{
    ResultStatus_t ret = SUCC;
    #ifdef BL_FLASH_DRV_FROM_HOST /*如果定义了 BL_FLASH_DRV_FROM_HOST,则表示 Flash 驱动来自主机,此时只需检查 FLASH_FSTAT 寄存器的 FAIL 标志位是否为 1,如果是,则返回 ERR*/
        if(1U == flsRegPtr->FLASH_FSTAT.FAIL)
        {
            ret = ERR;
        }
    #else  /*如果未定义 BL_FLASH_DRV_FROM_HOST,则需要调用不同的 Flash 初始化函数,根据具体设备型号进行初始化。*/
        #if (defined(DEV_Z20K118M))|| (defined(DEV_Z20K116M)) || (defined(DEV_Z20K114M))
            if(ERR == Flash_Init())
            {
                ret = ERR;
            }
        #else
            if(ERR == FLASH_Init())
            {
                ret = ERR;
            }
        #endif
    #endif
    return ret;
}

⑧APP检查和跳转

/*检查跳转到应用程序的标志*/
FlagStatus_t CheckJumpToAppFlag(void)
{
    uint32_t flag;
#if (defined(DEV_Z20K118M))|| (defined(DEV_Z20K116M)) || (defined(DEV_Z20K114M))
    REGFILE_ReadByRegID(BL_STAY_IN_BOOT_FLAG_REGFILE_ID, &flag);
#else
    REGFILE_ReadByRegId(BL_STAY_IN_BOOT_FLAG_REGFILE_ID, &flag);
#endif
    
       
    if(flag == BL_JUMP_TO_APP_FLAG_VALUE)
    {
        return SET;
    }
    
    return RESET;
}

/*检查应用程序是否可用*/
static FlagStatus_t CheckApp(void)
{
    uint32_t cnt;
    uint8_t *p;
    FlagStatus_t res = SET;
    
    for(cnt = 0U; cnt < APP_AVAILABLE_LEN; cnt++)
    {
        p = (uint8_t *)(uint32_t)(APP_AVAILABLE_ADDR+cnt);
        
        if(*p != appAvailableFlag[cnt])
        {
            res = RESET;
        }        
    }
        
    return res;
}
/*检查无误跳转至APP*/
void JumpToApp(void)
{
    AppEntry appEntryFunc;
    
    /* MISRA 2012 11.1 */
    appEntryFunc = (AppEntry)GetEntryPoint((uint8_t *)APP_ENTRY_ADDR);
    appEntryFunc();
    
    while(true)
    {
    }
}

跳转至APP后开始进行系统程序的执行,以及判断每次传输数据的有效性,完整代码如在资源中,有需要的自取。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值