mirror of
https://github.com/XIVN1987/DAPLink.git
synced 2026-09-27 14:36:22 +00:00
766 lines
21 KiB
C
766 lines
21 KiB
C
/**************************************************************************//**
|
|
* @file retarget.c
|
|
* @version V3.00
|
|
* @brief M480 Series Debug Port and Semihost Setting Source File
|
|
*
|
|
* @copyright (C) 2017 Nuvoton Technology Corp. All rights reserved.
|
|
******************************************************************************/
|
|
|
|
|
|
#include <stdio.h>
|
|
#include "NuMicro.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
|
|
/* Uncomment this line 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
|
|
|
|
#define DEBUG_PORT UART0
|
|
/*---------------------------------------------------------------------------------------------------------*/
|
|
/* 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};
|
|
|
|
/**
|
|
* @brief Helper function to dump register while hard fault occurred
|
|
* @param[in] stack pointer points to the dumped registers in SRAM
|
|
* @return None
|
|
* @details This function is implement to print r0, r1, r2, r3, r12, lr, pc, psr
|
|
*/
|
|
static 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]);
|
|
}
|
|
|
|
/**
|
|
* @brief Hard fault handler
|
|
* @param[in] stack pointer points to the dumped registers in SRAM
|
|
* @return 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[])
|
|
{
|
|
printf("In Hard Fault Handler\n");
|
|
|
|
stackDump(stack);
|
|
/* Replace while(1) with chip reset if WDT is not enabled for end product */
|
|
while(1);
|
|
/* SYS->IPRST0 = SYS_IPRST0_CHIPRST_Msk; */
|
|
}
|
|
|
|
|
|
|
|
/*---------------------------------------------------------------------------------------------------------*/
|
|
/* Routine to write a char */
|
|
/*---------------------------------------------------------------------------------------------------------*/
|
|
|
|
#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;
|
|
|
|
/* Make sure won't goes here only because --gnu is defined , so
|
|
add !__CC_ARM and !__ICCARM__ checking */
|
|
# if defined ( __GNUC__ ) && !(__CC_ARM) && !(__ICCARM__)
|
|
|
|
# elif defined(__ICCARM__) // IAR
|
|
|
|
void SH_End(void)
|
|
{
|
|
asm("MOVS R0,#1 \n" /*; Set return value to 1 */
|
|
"BX lr \n" /*; Return */
|
|
);
|
|
}
|
|
|
|
void SH_ICE(void)
|
|
{
|
|
asm("CMP R2,#0 \n"
|
|
"BEQ SH_End \n"
|
|
"STR R0,[R2] \n" /*; Save the return value to *pn32Out_R0 */
|
|
);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @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 */
|
|
);
|
|
|
|
return 1; /*; Return 1 when it is trap by ICE */
|
|
}
|
|
|
|
/**
|
|
* @brief Get LR value and branch to Hard_Fault_Handler function
|
|
* @param None
|
|
* @return None
|
|
* @details This function is use to get LR value and branch to Hard_Fault_Handler function.
|
|
*/
|
|
void Get_LR_and_Branch(void)
|
|
{
|
|
asm("MOV R1, LR \n" /*; LR current value */
|
|
"B Hard_Fault_Handler \n"
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @brief Get MSP value and branch to Get_LR_and_Branch function
|
|
* @param None
|
|
* @return None
|
|
* @details This function is use to get stack pointer value and branch to Get_LR_and_Branch function.
|
|
*/
|
|
void Stack_Use_MSP(void)
|
|
{
|
|
asm("MRS R0, MSP \n" /*; read MSP */
|
|
"B Get_LR_and_Branch \n"
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @brief Get stack pointer value and branch to Get_LR_and_Branch function
|
|
* @param None
|
|
* @return None
|
|
* @details This function is use to get stack pointer value and branch to Get_LR_and_Branch function.
|
|
*/
|
|
void HardFault_Handler_Ret(void)
|
|
{
|
|
asm("MOVS r0, #4 \n"
|
|
"MOV r1, LR \n"
|
|
"TST r0, r1 \n" /*; check LR bit 2 */
|
|
"BEQ Stack_Use_MSP \n" /*; stack use MSP */
|
|
"MRS R0, PSP \n" /*; stack use PSP, read PSP */
|
|
"B Get_LR_and_Branch \n"
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @brief This function is implemented to support semihost
|
|
* @param None
|
|
* @returns None
|
|
* @details This function is implement to support semihost message print.
|
|
*
|
|
*/
|
|
void SP_Read_Ready(void)
|
|
{
|
|
asm("LDR R1, [R0, #24] \n" /*; Get previous PC */
|
|
"LDRH R3, [R1] \n" /*; Get instruction */
|
|
"LDR R2, [pc, #8] \n" /*; The special 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 */
|
|
"B HardFault_Handler_Ret \n"
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @brief Get stack pointer value and branch to Get_LR_and_Branch function
|
|
* @param None
|
|
* @return None
|
|
* @details This function is use to get stack pointer value and branch to Get_LR_and_Branch function.
|
|
*/
|
|
void SP_is_PSP(void)
|
|
{
|
|
asm(
|
|
"MRS R0, PSP \n" /*; stack use PSP, read PSP */
|
|
"B Get_LR_and_Branch \n"
|
|
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @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"
|
|
);
|
|
|
|
while(1);
|
|
}
|
|
|
|
# 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 special 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 /*; check LR bit 2 */
|
|
BEQ Stack_Use_MSP /*; stack use MSP */
|
|
MRS R0, PSP ;stack use PSP /*; stack use PSP, read PSP */
|
|
B Get_LR_and_Branch
|
|
Stack_Use_MSP
|
|
MRS R0, MSP ; stack use MSP /*; read MSP */
|
|
Get_LR_and_Branch
|
|
MOV R1, LR ; LR current value /*; LR current value */
|
|
LDR R2,=__cpp(Hard_Fault_Handler) /*; branch to 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 // ndef DEBUG_ENABLE_SEMIHOST
|
|
|
|
/* Make sure won't goes here only because --gnu is defined , so
|
|
add !__CC_ARM and !__ICCARM__ checking */
|
|
# if defined ( __GNUC__ ) && !(__CC_ARM) && !(__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" /*; check LR bit 2 */
|
|
"BEQ 1f \n" /*; stack use MSP */
|
|
"MRS R0, PSP \n" /*; stack use PSP, read PSP */
|
|
"MOV R1, LR \n" /*; LR current value */
|
|
"B Hard_Fault_Handler \n"
|
|
"1: \n"
|
|
"MRS R0, MSP \n" /*; LR current value */
|
|
"B Hard_Fault_Handler \n"
|
|
::[Hard_Fault_Handler] "r" (Hard_Fault_Handler) // input
|
|
);
|
|
while(1);
|
|
}
|
|
|
|
# elif defined(__ICCARM__)
|
|
|
|
void Get_LR_and_Branch(void)
|
|
{
|
|
asm("MOV R1, LR \n" /*; LR current value */
|
|
"B Hard_Fault_Handler \n"
|
|
);
|
|
}
|
|
|
|
void Stack_Use_MSP(void)
|
|
{
|
|
asm("MRS R0, MSP \n" /*; read MSP */
|
|
"B Get_LR_and_Branch \n"
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @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" /*; check LR bit 2 */
|
|
"BEQ Stack_Use_MSP \n" /*; stack use MSP */
|
|
"MRS R0, PSP \n" /*; stack use PSP, read PSP */
|
|
"B Get_LR_and_Branch \n"
|
|
);
|
|
|
|
while(1);
|
|
}
|
|
|
|
# else
|
|
|
|
/**
|
|
* @brief This HardFault handler is implemented to show r0, r1, r2, r3, r12, lr, pc, psr
|
|
*
|
|
* @param None
|
|
*
|
|
* @return None
|
|
*
|
|
* @details The function extracts the location of stack frame and passes it to Hard_Fault_Handler function as a pointer
|
|
*
|
|
*/
|
|
__asm int32_t HardFault_Handler(void)
|
|
{
|
|
MOVS r0, #4
|
|
MOV r1, LR
|
|
TST r0, r1 /*; check LR bit 2 */
|
|
BEQ Stack_Use_MSP /*; stack use MSP */
|
|
MRS R0, PSP /*; stack use PSP, read PSP */
|
|
B Get_LR_and_Branch
|
|
Stack_Use_MSP
|
|
MRS R0, MSP /*; read MSP */
|
|
Get_LR_and_Branch
|
|
MOV R1, LR /*; LR current value */
|
|
LDR R2,=__cpp(Hard_Fault_Handler) /*; branch to Hard_Fault_Handler */
|
|
BX R2
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#ifndef DISABLE_UART
|
|
/**
|
|
* @brief Routine to send a char
|
|
*
|
|
* @param[in] ch Character to send to debug port.
|
|
*
|
|
* @returns Send value from UART debug port
|
|
*
|
|
* @details Send a target char to UART debug port .
|
|
*/
|
|
#ifndef NONBLOCK_PRINTF
|
|
static void SendChar_ToUART(int ch)
|
|
{
|
|
while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);
|
|
|
|
DEBUG_PORT->DAT = ch;
|
|
if(ch == '\n')
|
|
{
|
|
while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);
|
|
DEBUG_PORT->DAT = '\r';
|
|
}
|
|
}
|
|
|
|
#else
|
|
/* Non-block implement of send char */
|
|
#define BUF_SIZE 2048
|
|
static void SendChar_ToUART(int ch)
|
|
{
|
|
static uint8_t u8Buf[BUF_SIZE] = {0};
|
|
static int32_t i32Head = 0;
|
|
static int32_t i32Tail = 0;
|
|
int32_t i32Tmp;
|
|
|
|
/* Only flush the data in buffer to UART when ch == 0 */
|
|
if(ch)
|
|
{
|
|
/* Push char */
|
|
i32Tmp = i32Head+1;
|
|
if(i32Tmp > BUF_SIZE) i32Tmp = 0;
|
|
if(i32Tmp != i32Tail)
|
|
{
|
|
u8Buf[i32Head] = ch;
|
|
i32Head = i32Tmp;
|
|
}
|
|
|
|
if(ch == '\n')
|
|
{
|
|
i32Tmp = i32Head+1;
|
|
if(i32Tmp > BUF_SIZE) i32Tmp = 0;
|
|
if(i32Tmp != i32Tail)
|
|
{
|
|
u8Buf[i32Head] = '\r';
|
|
i32Head = i32Tmp;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(i32Tail == i32Head)
|
|
return;
|
|
}
|
|
|
|
/* pop char */
|
|
do
|
|
{
|
|
i32Tmp = i32Tail + 1;
|
|
if(i32Tmp > BUF_SIZE) i32Tmp = 0;
|
|
|
|
if((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk) == 0)
|
|
{
|
|
DEBUG_PORT->DAT = u8Buf[i32Tail];
|
|
i32Tail = i32Tmp;
|
|
}
|
|
else
|
|
break; /* FIFO full */
|
|
}while(i32Tail != i32Head);
|
|
}
|
|
#endif /* else for NONBLOCK_PRINTF */
|
|
|
|
#endif /* if not def DISABLE_UART */
|
|
|
|
/**
|
|
* @brief Routine to send a char
|
|
*
|
|
* @param[in] ch Character to send to debug port.
|
|
*
|
|
* @returns Send value from UART debug port or semihost
|
|
*
|
|
* @details Send a target char to UART debug port or semihost.
|
|
*/
|
|
static 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
|
|
{
|
|
#ifndef DISABLE_UART
|
|
int i;
|
|
|
|
for(i = 0; i < g_buf_len; i++)
|
|
SendChar_ToUART(g_buf[i]);
|
|
g_buf_len = 0;
|
|
#endif
|
|
}
|
|
}
|
|
#else
|
|
#ifndef DISABLE_UART
|
|
SendChar_ToUART(ch);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* @brief Routine to get a char
|
|
*
|
|
* @param None
|
|
*
|
|
* @returns Get value from UART debug port or semihost
|
|
*
|
|
* @details Wait UART debug port or semihost to input a char.
|
|
*/
|
|
static char GetChar(void)
|
|
{
|
|
#ifdef 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
|
|
return (0);
|
|
#else
|
|
#ifndef DISABLE_UART
|
|
while(1)
|
|
{
|
|
if((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk) == 0)
|
|
{
|
|
return (DEBUG_PORT->DAT);
|
|
}
|
|
}
|
|
#else
|
|
return 0;
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* @brief Check any char input from UART
|
|
*
|
|
* @param None
|
|
*
|
|
* @retval 1: No any char input
|
|
* @retval 0: Have some char input
|
|
*
|
|
* @details Check UART RSR RX EMPTY or not to determine if any char input from UART
|
|
*/
|
|
|
|
int kbhit(void)
|
|
{
|
|
#ifndef DISABLE_UART
|
|
return !((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk) == 0);
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
/**
|
|
* @brief Check if debug message finished
|
|
*
|
|
* @param None
|
|
*
|
|
* @retval 1: Message is finished
|
|
* @retval 0: Message is transmitting.
|
|
*
|
|
* @details Check if message finished (FIFO empty of debug port)
|
|
*/
|
|
|
|
int IsDebugFifoEmpty(void)
|
|
{
|
|
#ifndef DISABLE_UART
|
|
return ((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXEMPTYF_Msk) != 0);
|
|
#else
|
|
return 1;
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* @brief C library retargetting
|
|
*
|
|
* @param[in] ch Character to send to debug port.
|
|
*
|
|
* @returns None
|
|
*
|
|
* @details Check if message finished (FIFO empty of debug port)
|
|
*/
|
|
|
|
void _ttywrch(int ch)
|
|
{
|
|
SendChar(ch);
|
|
return;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Write character to stream
|
|
*
|
|
* @param[in] ch Character to be written. The character is passed as its int promotion.
|
|
* @param[in] stream Pointer to a FILE object that identifies the stream where the character is to be written.
|
|
*
|
|
* @returns If there are no errors, the same character that has been written is returned.
|
|
* If an error occurs, EOF is returned and the error indicator is set (see ferror).
|
|
*
|
|
* @details Writes a character to the stream and advances the position indicator.\n
|
|
* The character is written at the current position of the stream as indicated \n
|
|
* by the internal position indicator, which is then advanced one character.
|
|
*
|
|
* @note The above descriptions are copied from http://www.cplusplus.com/reference/clibrary/cstdio/fputc/.
|
|
*
|
|
*
|
|
*/
|
|
|
|
int fputc(int ch, FILE *stream)
|
|
{
|
|
SendChar(ch);
|
|
return ch;
|
|
}
|
|
|
|
#if defined ( __GNUC__ )
|
|
|
|
int _write (int fd, char *ptr, int len)
|
|
{
|
|
int i = len;
|
|
|
|
while(i--)
|
|
{
|
|
while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);
|
|
|
|
DEBUG_PORT->DAT = *ptr++;
|
|
|
|
if(*ptr == '\n')
|
|
{
|
|
while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);
|
|
DEBUG_PORT->DAT = '\r';
|
|
}
|
|
}
|
|
return len;
|
|
}
|
|
|
|
int _read (int fd, char *ptr, int len)
|
|
{
|
|
|
|
while((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk) != 0);
|
|
*ptr = DEBUG_PORT->DAT;
|
|
return 1;
|
|
|
|
|
|
}
|
|
|
|
#else
|
|
/**
|
|
* @brief Get character from UART debug port or semihosting input
|
|
*
|
|
* @param[in] stream Pointer to a FILE object that identifies the stream on which the operation is to be performed.
|
|
*
|
|
* @returns The character read from UART debug port or semihosting
|
|
*
|
|
* @details For get message from debug port or semihosting.
|
|
*
|
|
*/
|
|
|
|
int fgetc(FILE *stream)
|
|
{
|
|
return (GetChar());
|
|
}
|
|
|
|
/**
|
|
* @brief Check error indicator
|
|
*
|
|
* @param[in] stream Pointer to a FILE object that identifies the stream.
|
|
*
|
|
* @returns If the error indicator associated with the stream was set, the function returns a nonzero value.
|
|
* Otherwise, it returns a zero value.
|
|
*
|
|
* @details Checks if the error indicator associated with stream is set, returning a value different
|
|
* from zero if it is. This indicator is generally set by a previous operation on the stream that failed.
|
|
*
|
|
* @note The above descriptions are copied from http://www.cplusplus.com/reference/clibrary/cstdio/ferror/.
|
|
*
|
|
*/
|
|
|
|
int ferror(FILE *stream)
|
|
{
|
|
return EOF;
|
|
}
|
|
#endif
|
|
#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
|