打印
[DemoCode下载]

多引导启动实现方式

[复制链接]
341|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
wanduzi|  楼主 | 2024-2-28 19:10 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
TI, ge, RT, ST, se, ar
/****************************************************************************//**
* [url=home.php?mod=space&uid=288409]@file[/url]     main.c
* [url=home.php?mod=space&uid=895143]@version[/url]  V0.10
* [url=home.php?mod=space&uid=247401]@brief[/url]    Implement a multi-boot system to boot from different applications in APROM.
*           A LDROM code and 4 APROM code are implemented in this sample code.
*
* SPDX-License-Identifier: Apache-2.0
* [url=home.php?mod=space&uid=17282]@CopyRight[/url] (C) 2018 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include <stdio.h>
#include "NuMicro.h"


#if !defined(__ICCARM__) && !defined(__GNUC__)
extern uint32_t Image$RO$Base;
#endif

void SYS_Init(void)
{
    /*---------------------------------------------------------------------------------------------------------*/
    /* Init System Clock                                                                                       */
    /*---------------------------------------------------------------------------------------------------------*/
    /* Unlock protected registers */
    SYS_UnlockReg();

    /* Enable HIRC clock */
    CLK_EnableXtalRC(CLK_PWRCTL_HIRCEN_Msk);

    /* Wait for HIRC clock ready */
    CLK_WaitClockReady(CLK_STATUS_HIRCSTB_Msk);

    /* Select HCLK clock source as HIRC and and HCLK source divider as 1 */
    CLK_SetHCLK(CLK_CLKSEL0_HCLKSEL_HIRC, CLK_CLKDIV0_HCLK(1));

    /* Set PLL to Power-down mode and PLLSTB bit in CLK_STATUS register will be cleared by hardware.*/
    CLK_DisablePLL();

    /* Enable UART module clock */
    CLK_EnableModuleClock(UART0_MODULE);

    /* Select UART module clock source as HIRC and UART module clock divider as 1 */
    CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL1_UART0SEL_HIRC, CLK_CLKDIV0_UART0(1));

    /*---------------------------------------------------------------------------------------------------------*/
    /* Init I/O Multi-function                                                                                 */
    /*---------------------------------------------------------------------------------------------------------*/
    /* Set PB multi-function pins for UART0 RXD=PB.12 and TXD=PB.13 */
    SYS->GPB_MFPH = (SYS->GPB_MFPH & ~(SYS_GPB_MFPH_PB12MFP_Msk | SYS_GPB_MFPH_PB13MFP_Msk))
                    |(SYS_GPB_MFPH_PB12MFP_UART0_RXD | SYS_GPB_MFPH_PB13MFP_UART0_TXD);

    /* Lock protected registers */
    SYS_LockReg();
}

/**
* @brief    Routine to get a char
* @param    None
* @returns  Get value from UART debug port or semihost
* [url=home.php?mod=space&uid=1543424]@Details[/url]  Wait UART debug port or semihost to input a char.
*/
static char GetChar(void)
{
    while(1)
    {
        if ((UART0->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk) == 0)
        {
            return (UART0->DAT);
        }
    }
}

/*
* @returns     Send value from UART debug port
* @details     Send a target char to UART debug port .
*/
static void SendChar_ToUART(int ch)
{
    while (UART0->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);

    UART0->DAT = ch;
    if(ch == '\n')
    {
        while (UART0->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);
        UART0->DAT = '\r';
    }
}

static void PutString(char *str)
{
    while (*str != '\0')
    {
        SendChar_ToUART(*str++);
    }
}

static void PutHexNumber(uint32_t u32Num)
{
    int32_t i = 28;
    uint32_t Digit;
    PutString("0x");
    do
    {
        Digit = (u32Num >> i) & 0x0F;
        if(Digit != 0)
            break;
        i = i - 4;
    }
    while(i!=0);

    while (i >= 0)
    {
        Digit =  (u32Num >> i) & 0x0F;
        if(Digit < 10)
            SendChar_ToUART('0'+Digit);
        else
            SendChar_ToUART('A'+Digit-10);
        i = i - 4;
    }
}
#ifdef __GNUC__                        /* for GNU C compiler */
/**
* @brief       Hard fault handler
* @param[in]   stack pointer points to the dumped registers in SRAM
* [url=home.php?mod=space&uid=266161]@return[/url]      None
* @details     Replace while(1) at the end of this function with chip reset if WDT is not enabled for end product
*/
void Hard_Fault_Handler(uint32_t stack[])
{
    PutString("In Hard Fault Handler\n");
    while(1);
}
#endif
int32_t main(void)
{
    uint8_t u8Ch;
    uint32_t u32Data;


    /* Init System, IP clock and multi-function I/O. */
    SYS_Init();
   
    /* Unlock protected registers to operate FMC ISP function */
    SYS_UnlockReg();

    /* Configure UART0: 115200, 8-bit word, no parity bit, 1 stop bit. */
    UART_Open(UART0, 115200);

    /* Checking if target device supports the feature */
    if( (GET_CHIP_SERIES_NUM == CHIP_SERIES_NUM_I) || (GET_CHIP_SERIES_NUM == CHIP_SERIES_NUM_G) )
    {
        /* Checking if flash size matches with target device */
        if(FMC_FLASH_PAGE_SIZE != 2048)
        {
            /* FMC_FLASH_PAGE_SIZE is different from target device's */
            printf("Please enable the compiler option - PAGE_SIZE_2048 in fmc.h\n");
            while(SYS->PDID);
        }
    }
    else
    {
        if(FMC_FLASH_PAGE_SIZE != 512)
        {
            /* FMC_FLASH_PAGE_SIZE is different from target device's */
            printf("Please disable the compiler option - PAGE_SIZE_2048 in fmc.h\n");
            while(SYS->PDID);
        }
    }

    /* Enable FMC ISP function */
    FMC_Open();

    /*
        This sample code shows how to boot with different firmware images in APROM.
        In the code, VECMAP is used to implement multi-boot function. Software set VECMAP
        to remap page of VECMAP to 0x0~0x1ff.
        NOTE: VECMAP only valid when CBS = 00'b or 10'b.

        The sample code didn't use stanard C library for UART message due to the size of LDROM.

        To use this sample code, please:
        1. Build all targets and download to device individually. The targets are:
            FMC_MultiBoot, RO=0x0, ICE download algorithm to APROM
            FMC_Boot0, RO=0x4000, ICE download algorithm to APROM
            FMC_Boot1, RO=0x8000, ICE download algorithm to APROM
            FMC_Boot2, RO=0xC000, ICE download algorithm to APROM
            FMC_Boot3, RO=0x10000, ICE download algorithm to APROM
            FMC_BootLD, RO=0x100000. ICE download algorithm to LDROM
        2. Reset MCU to execute FMC_MultiBoot.
    */

    PutString("\n\n");
    PutString("+---------------------------+\n");
    PutString("|   Multi-Boot Sample Code  |\n");
    PutString("+---------------------------+\n");
#if defined(__BASE__)
    PutString("Boot from 0\n");
#endif
#if defined(__BOOT0__)
    PutString("Boot from 0x4000\n");
#endif
#if defined(__BOOT1__)
    PutString("Boot from 0x8000\n");
#endif
#if defined(__BOOT2__)
    PutString("Boot from 0xC000\n");
#endif
#if defined(__BOOT3__)
    PutString("Boot from 0x10000\n");
#endif
#if defined(__LDROM__)
    PutString("Boot from 0x100000\n");
#endif

    u32Data = FMC_GetVECMAP();
    PutString("VECMAP = ");
    PutHexNumber(u32Data);
    PutString("\n");

    PutString("Select one boot image: \n");
#if !defined(__GNUC__)
    PutString("[0] Boot 0, base = 0x4000\n");
#endif
    PutString("[1] Boot 1, base = 0x8000\n");
#if !defined(__GNUC__)
    PutString("[2] Boot 2, base = 0xC000\n");
#endif
    PutString("[3] Boot 3, base = 0x10000\n");
#if !defined(__GNUC__)
    PutString("[4] Boot 4, base = 0x100000\n");
#endif
    PutString("[Others] Boot, base = 0x0\n");

    u8Ch = GetChar();//getchar();

    switch (u8Ch)
    {
#if !defined(__GNUC__)
    case '0':
        FMC_SetVectorPageAddr(0x4000);
        break;
#endif

    case '1':
        FMC_SetVectorPageAddr(0x8000);
        break;

#if !defined(__GNUC__)
    case '2':
        FMC_SetVectorPageAddr(0xC000);
        break;
#endif

    case '3':
        FMC_SetVectorPageAddr(0x10000);
        break;
#if !defined(__GNUC__)

    case '4':
        FMC_SetVectorPageAddr(0x100000);
        break;
#endif

    default:
        FMC_SetVectorPageAddr(0x0);
        break;
    }
    if (g_FMC_i32ErrCode != 0)
    {
        printf("FMC_SetVectorPageAddr failed!\n");
        while (1);
    }

    /* Reset CPU only to reset to new vector page */
    SYS_ResetCPU();

    /* Reset System to reset to new vector page. */
    //NVIC_SystemReset();

    /* Disable ISP function */
    FMC_Close();

    /* Lock protected registers */
    SYS_LockReg();

    PutString("\nDone\n");

    while (SYS->PDID) __WFI();

}

/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/


使用特权

评论回复
沙发
wanduzi|  楼主 | 2024-2-28 19:10 | 只看该作者
这个程序是为了实现一个多引导系统,可以从存储在APROM(应用程序闪存)中的不同应用程序启动。以下是代码的主要功能和组件的总结:

头文件包含:代码包含了必要的头文件,如 stdio.h 和 "NuMicro.h",这些文件很可能包含了程序所需的定义和声明。

系统初始化 (SYS_Init):该函数初始化系统时钟,启用UART时钟,配置UART引脚,并设置UART模块以进行通信。

UART函数 (GetChar, SendChar_ToUART, PutString, PutHexNumber):这些函数处理UART通信,用于发送和接收字符和字符串。

硬件故障处理器:在发生硬件故障时,将调用此函数来处理故障。在提供的代码中,它仅通过UART发送一条消息,然后进入无限循环。

主函数 (main):

系统初始化: 初始化系统,解锁保护寄存器,配置UART通信,并根据芯片系列和闪存页面大小检查设备是否支持某些功能。

FMC(闪存存储控制器)配置: 设置FMC ISP(系统内编程)功能,该功能允许在设备运行时对闪存进行编程。它根据目标设备的闪存页面大小检查和配置FMC设置。

多引导配置: 根据预处理器定义 (__BASE__, __BOOT0__ 等),显示引导选项,读取用户输入以选择引导映像,并相应地使用 FMC_SetVectorPageAddr 函数设置向量页地址。

重置CPU: 调用 SYS_ResetCPU() 重置CPU,以从所选的引导映像开始执行代码。

清理工作: 关闭FMC ISP功能,锁定保护寄存器,并发送一条指示完成的消息。

注释: 代码包含了对各个部分、函数和指令的注释,这有助于理解代码的功能和目的。

使用特权

评论回复
板凳
wanduzi|  楼主 | 2024-2-28 19:10 | 只看该作者
总的来说,该代码实现了一个灵活的引导系统,允许从存储在APROM内存中的不同应用程序启动,并提供UART通信以供用户交互和反馈。此外,它利用了FMC模块来配置闪存存储器的设置和多引导功能。

使用特权

评论回复
地板
wanduzi|  楼主 | 2024-2-28 19:11 | 只看该作者
允许从存储在APROM中的不同应用程序中引导,并提供了UART通信以进行用户交互和反馈。此外,它利用了FMC模块来配置Flash存储器设置和多重引导功能。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

143

主题

1728

帖子

3

粉丝