NANO130_H2Press/User/retarget.c

537 lines
13 KiB
C
Raw Normal View History

2025-04-10 14:54:41 +08:00
/**************************************************************************//**
* @file retarget.c
* @version V1.00
* $Revision: 14 $
* $Date: 15/10/30 3:25p $
* @brief Nano100 series retarget source file
*
* @note
* Copyright (C) 2013 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include <stdio.h>
#include "Nano100Series.h"
#if defined ( __CC_ARM )
#if (__ARMCC_VERSION < 400000)
#else
/* Insist on keeping widthprec, to avoid X propagation by benign code in C-lib */
#pragma import _printf_widthprec
#endif
#endif
#ifndef DEBUG_PORT
#define DEBUG_PORT UART1 /*!< Select Debug Port which is used for retarget.c to output debug message to UART */
//#define DEBUG_PORT SC1 /*!< Select Debug Port which is used for retarget.c to output debug message to SC UART */
//#define DEBUG_SC_PORT /* Use SC UART */
#endif
/* Use this definition to disable all printf and getchar. getchar() will always return 0x00*/
//#define DISABLE_UART
#if defined(DEBUG_ENABLE_SEMIHOST)
#ifndef DISABLE_UART
#define DISABLE_UART
#endif
#endif
/*---------------------------------------------------------------------------------------------------------*/
/* Global variables */
/*---------------------------------------------------------------------------------------------------------*/
#if !(defined(__ICCARM__) && (__VER__ >= 6010000))
struct __FILE {
int handle; /* Add whatever you need here */
};
#endif
FILE __stdout;
FILE __stdin;
enum { r0, r1, r2, r3, r12, lr, pc, psr};
void stackDump(uint32_t stack[])
{
printf("r0 = 0x%x\n", stack[r0]);
printf("r1 = 0x%x\n", stack[r1]);
printf("r2 = 0x%x\n", stack[r2]);
printf("r3 = 0x%x\n", stack[r3]);
printf("r12 = 0x%x\n", stack[r12]);
printf("lr = 0x%x\n", stack[lr]);
printf("pc = 0x%x\n", stack[pc]);
printf("psr = 0x%x\n", stack[psr]);
}
#if 0
__asm void wait()
{
BX lr
}
void Hard_Fault_Handler(uint32_t stack[])
{
wait();
}
#else
void Hard_Fault_Handler(uint32_t stack[])
{
uint32_t loop;
// <20><><EFBFBD>´򿪿<C2B4><F2BFAABF>Ź<EFBFBD><C5B9><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
WDT->CTL |= WDT_CTL_WTE_Msk;
printf("In Hard Fault Handler\n");
stackDump(stack);
//Chip Reset
//SYS_UnlockReg();
//SYS->IPRST_CTL1 |= SYS_IPRST_CTL1_CHIP_RST_Msk;
while(1)
{
for(loop = 0; loop < 12000000ul; loop++);
printf(".");
}
}
#endif
#if defined(DEBUG_ENABLE_SEMIHOST)
/* The static buffer is used to speed up the semihost */
static char g_buf[16];
static char g_buf_len = 0;
# if defined(__ICCARM__)
/**
* @brief This HardFault handler is implemented to support semihost
*
* @param None
*
* @returns None
*
* @details This function is implement to support semihost message print.
*
*/
void HardFault_Handler(void)
{
asm("MOV R0, lr \n"
"LSLS R0, #29 \n" //; Check bit 2
"BMI SP_is_PSP \n" //; previous stack is PSP
"MRS R0, MSP \n" //; previous stack is MSP, read MSP
"B SP_Read_Ready \n"
"SP_is_PSP: \n"
"MRS R0, PSP \n" //; Read PSP
"SP_Read_Ready: \n"
"LDR R1, [R0, #24] \n" //; Get previous PC
"LDRH R3, [R1] \n" //; Get instruction
"LDR R2, [pc, #8] \n" //; The sepcial BKPT instruction
"CMP R3, R2 \n" //; Test if the instruction at previous PC is BKPT
"BNE HardFault_Handler_Ret\n" //; Not BKPT
"ADDS R1, #4 \n" //; Skip BKPT and next line
"STR R1, [R0, #24] \n" //; Save previous PC
"BX lr \n" //; Return
"DCD 0xBEAB \n" //; BKPT instruction code
"HardFault_Handler_Ret:\n"
"MOVS r0, #4 \n"
"MOV r1, LR \n"
"TST r0, r1 \n"
"BEQ Stack_Use_MSP \n"
"MRS R0, PSP \n" //; stack use PSP
"B Get_LR_and_Branch \n"
"Stack_Use_MSP: \n"
"MRS R0, MSP \n" //; stack use MSP
"Get_LR_and_Branch: \n"
"MOV R1, LR \n" //; LR current value
"B Hard_Fault_Handler \n"
);
while(1);
}
/**
*
* @brief The function to process semihosted command
* @param[in] n32In_R0 : semihost register 0
* @param[in] n32In_R1 : semihost register 1
* @param[out] pn32Out_R0: semihost register 0
* @retval 0: No ICE debug
* @retval 1: ICE debug
*
*/
int32_t SH_DoCommand(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0)
{
asm("BKPT 0xAB \n" //; This instruction will cause ICE trap or system HardFault
"B SH_ICE \n"
"SH_HardFault: \n" //; Captured by HardFault
"MOVS R0, #0 \n" //; Set return value to 0
"BX lr \n" //; Return
"SH_ICE: \n" //; Captured by ICE
"CMP R2, #0 \n"
"BEQ SH_End \n"
"STR R0, [R2]\n" //; Save the return value to *pn32Out_R0
"SH_End: \n");
return 1; //; Return 1 when it is trap by ICE
}
# else
/**
* @brief This HardFault handler is implemented to support semihost
*
* @param None
*
* @returns None
*
* @details This function is implement to support semihost message print.
*
*/
__asm int32_t HardFault_Handler(void)
{
MOV R0, LR
LSLS R0, #29 //; Check bit 2
BMI SP_is_PSP //; previous stack is PSP
MRS R0, MSP //; previous stack is MSP, read MSP
B SP_Read_Ready
SP_is_PSP
MRS R0, PSP //; Read PSP
SP_Read_Ready
LDR R1, [R0, #24] //; Get previous PC
LDRH R3, [R1] //; Get instruction
LDR R2, =0xBEAB //; The sepcial BKPT instruction
CMP R3, R2 //; Test if the instruction at previous PC is BKPT
BNE HardFault_Handler_Ret //; Not BKPT
ADDS R1, #4 //; Skip BKPT and next line
STR R1, [R0, #24] //; Save previous PC
BX LR //; Return
HardFault_Handler_Ret
/* TODO: Implement your own hard fault handler here. */
MOVS r0, #4
MOV r1, LR
TST r0, r1
BEQ Stack_Use_MSP
MRS R0, PSP ;stack use PSP
B Get_LR_and_Branch
Stack_Use_MSP
MRS R0, MSP ; stack use MSP
Get_LR_and_Branch
MOV R1, LR ; LR current value
LDR R2,=__cpp(Hard_Fault_Handler)
BX R2
B .
ALIGN
}
/**
*
* @brief The function to process semihosted command
* @param[in] n32In_R0 : semihost register 0
* @param[in] n32In_R1 : semihost register 1
* @param[out] pn32Out_R0: semihost register 0
* @retval 0: No ICE debug
* @retval 1: ICE debug
*
*/
__asm int32_t SH_DoCommand(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0)
{
BKPT 0xAB //; Wait ICE or HardFault
//; ICE will step over BKPT directly
//; HardFault will step BKPT and the next line
B SH_ICE
SH_HardFault //; Captured by HardFault
MOVS R0, #0 //; Set return value to 0
BX lr //; Return
SH_ICE //; Captured by ICE
//; Save return value
CMP R2, #0
BEQ SH_End
STR R0, [R2] //; Save the return value to *pn32Out_R0
SH_End
MOVS R0, #1 //; Set return value to 1
BX lr //; Return
}
#endif
#else
# if defined(__ICCARM__)
/**
* @brief This HardFault handler is implemented to show r0, r1, r2, r3, r12, lr, pc, psr
*
* @param None
*
* @returns None
*
* @details This function is implement to print r0, r1, r2, r3, r12, lr, pc, psr.
*
*/
void HardFault_Handler(void)
{
asm("MOVS r0, #4 \n"
"MOV r1, LR \n"
"TST r0, r1 \n"
"BEQ Stack_Use_MSP \n"
"MRS R0, PSP \n" //; stack use PSP
"B Get_LR_and_Branch \n"
"Stack_Use_MSP: \n"
"MRS R0, MSP \n" //; stack use MSP
"Get_LR_and_Branch: \n"
"MOV R1, LR \n" //; LR current value
"B Hard_Fault_Handler \n"
);
while(1);
}
# else
/**
* @brief This HardFault handler is implemented to show r0, r1, r2, r3, r12, lr, pc, psr
*
* @param None
*
* @returns None
*
* @details This function is implement to print r0, r1, r2, r3, r12, lr, pc, psr
*
*/
__asm int32_t HardFault_Handler(void)
{
MOVS r0, #4
MOV r1, LR
TST r0, r1
BEQ Stack_Use_MSP
MRS R0, PSP ;stack use PSP
B Get_LR_and_Branch
Stack_Use_MSP
MRS R0, MSP ; stack use MSP
Get_LR_and_Branch
MOV R1, LR ; LR current value
LDR R2,=__cpp(Hard_Fault_Handler)
BX R2
}
#endif
#endif
/**
* @brief Write a char to UART.
* @param ch The character sent to UART.
* @return None
*/
void SendChar_ToUART(int ch)
{
#ifndef DISABLE_UART
#ifdef DEBUG_SC_PORT
while(DEBUG_PORT->TRSR & SC_TRSR_TX_FULL_F_Msk);
DEBUG_PORT->THR = ch;
if(ch == '\n') {
while(DEBUG_PORT->TRSR & SC_TRSR_TX_FULL_F_Msk);
DEBUG_PORT->THR = '\r';
}
#else
while(DEBUG_PORT->FSR & UART_FSR_TX_FULL_F_Msk);
DEBUG_PORT->THR = ch;
if(ch == '\n') {
while(DEBUG_PORT->FSR & UART_FSR_TX_FULL_F_Msk);
DEBUG_PORT->THR = '\r';
}
#endif
#endif
}
/**
* @brief Write a char to debug console.
* @param ch The character sent to debug console
* @return None
*/
void SendChar(int ch)
{
#if defined(DEBUG_ENABLE_SEMIHOST)
g_buf[g_buf_len++] = ch;
g_buf[g_buf_len] = '\0';
if(g_buf_len + 1 >= sizeof(g_buf) || ch == '\n' || ch == '\0') {
/* Send the char */
if(SH_DoCommand(0x04, (int)g_buf, NULL) != 0) {
g_buf_len = 0;
return;
} else {
int i;
for(i=0; i<g_buf_len; i++)
SendChar_ToUART(g_buf[i]);
g_buf_len = 0;
}
}
#else
SendChar_ToUART(ch);
#endif
}
/**
* @brief Read a char from debug console.
* @param None
* @return Received character from debug console
* @note This API waits until UART debug port or semihost input a character
*/
char GetChar(void)
{
#if defined(DEBUG_ENABLE_SEMIHOST)
# if defined ( __CC_ARM )
int nRet;
while(SH_DoCommand(0x101, 0, &nRet) != 0) {
if(nRet != 0) {
SH_DoCommand(0x07, 0, &nRet);
return (char)nRet;
}
}
# else
int nRet;
while(SH_DoCommand(0x7, 0, &nRet) != 0) {
if(nRet != 0)
return (char)nRet;
}
# endif
#endif
#ifndef DISABLE_UART
#ifdef DEBUG_SC_PORT
while (1) {
if(!(DEBUG_PORT->TRSR & SC_TRSR_RX_EMPTY_F_Msk)) {
return (DEBUG_PORT->RBR);
}
}
#else
while (1) {
if(!(DEBUG_PORT->FSR & UART_FSR_RX_EMPTY_F_Msk)) {
return (DEBUG_PORT->RBR);
}
}
#endif
#else
return(0);
#endif
}
/**
* @brief Check whether UART receive FIFO is empty or not.
* @param None
* @return UART Rx FIFO empty status
* @retval 1 Indicates at least one character is available in UART Rx FIFO
* @retval 0 UART Rx FIFO is empty
*/
int kbhit(void)
{
#ifndef DISABLE_UART
#ifdef DEBUG_SC_PORT
return !(DEBUG_PORT->TRSR & SC_TRSR_RX_EMPTY_F_Msk);
#else
return !(DEBUG_PORT->FSR & UART_FSR_RX_EMPTY_F_Msk);
#endif
#else
return(0);
#endif
}
/**
* @brief Check whether UART transmit FIFO is empty or not.
* @param None
* @return UART Tx FIFO empty status
* @retval 1 UART Tx FIFO is empty
* @retval 0 UART Tx FIFO is not empty
*/
int IsDebugFifoEmpty(void)
{
#ifndef DISABLE_UART
#ifdef DEBUG_SC_PORT
return (DEBUG_PORT->TRSR & SC_TRSR_TX_EMPTY_F_Msk) ? 1 : 0;
#else
return (DEBUG_PORT->FSR & UART_FSR_TE_F_Msk) ? 1 : 0;
#endif
#else
return(1);
#endif
}
/*---------------------------------------------------------------------------------------------------------*/
/* C library retargetting */
/*---------------------------------------------------------------------------------------------------------*/
void _ttywrch(int ch)
{
SendChar(ch);
return;
}
int fputc(int ch, FILE *f)
{
SendChar(ch);
return ch;
}
int fgetc(FILE *f)
{
return (GetChar());
}
int ferror(FILE *f)
{
return EOF;
}
#ifdef DEBUG_ENABLE_SEMIHOST
# ifdef __ICCARM__
void __exit(int return_code)
{
/* Check if link with ICE */
if(SH_DoCommand(0x18, 0x20026, NULL) == 0) {
/* Make sure all message is print out */
while(IsDebugFifoEmpty() == 0);
}
label:
goto label; /* endless loop */
}
# else
void _sys_exit(int return_code)
{
/* Check if link with ICE */
if(SH_DoCommand(0x18, 0x20026, NULL) == 0) {
/* Make sure all message is print out */
while(IsDebugFifoEmpty() == 0);
}
label:
goto label; /* endless loop */
}
# endif
#endif
/*** (C) COPYRIGHT 2013 Nuvoton Technology Corp. ***/