/****************************************************************************//**
* [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. ***/
|