打印
[牛人杂谈]

M058S重定向

[复制链接]
68|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
734774645|  楼主 | 2025-2-14 15:39 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
/**************************************************************************//**
* [url=home.php?mod=space&uid=288409]@file[/url]     retarget.c
* [url=home.php?mod=space&uid=895143]@version[/url]  V3.00
* $Revision: 4 $
* $Date: 15/11/04 9:35a $
* [url=home.php?mod=space&uid=247401]@brief[/url]    Debug Port and Semihost Setting Source File
*
* @note
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (C) 2011 Nuvoton Technology Corp. All rights reserved.
*
******************************************************************************/


#include <stdio.h>
#include "M058S.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

/*---------------------------------------------------------------------------------------------------------*/
/* 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
* [url=home.php?mod=space&uid=266161]@return[/url]      None
* [url=home.php?mod=space&uid=1543424]@Details[/url]     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->IPRSTC1 = SYS_IPRSTC1_CHIP_RST_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__)


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)
{
    IMPORT  Hard_Fault_Handler

    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 // Non-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)
{
    IMPORT  Hard_Fault_Handler

    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


/**
* @brief    Routine to send a char
*
* @param[in] ch  A character data writes to debug port
*
* @returns  Send value from UART debug port
*
* @details  Send a target char to UART debug port .
*/
#ifndef NONBLOCK_PRINTF
void SendChar_ToUART(int ch)
{

    while(DEBUG_PORT->FSR & UART_FSR_TX_FULL_Msk);
    if(ch == '\n')
    {
        DEBUG_PORT->DATA = '\r';
        while(DEBUG_PORT->FSR & UART_FSR_TX_FULL_Msk);
    }

    DEBUG_PORT->DATA = ch;
}

#else
/* Non-block implement of send char */
#define BUF_SIZE    512
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
        if(ch == '\n')
        {
            i32Tmp = i32Head + 1;
            if(i32Tmp > BUF_SIZE) i32Tmp = 0;
            if(i32Tmp != i32Tail)
            {
                u8Buf[i32Head] = '\r';
                i32Head = i32Tmp;
            }
        }

        i32Tmp = i32Head + 1;
        if(i32Tmp > BUF_SIZE) i32Tmp = 0;
        if(i32Tmp != i32Tail)
        {
            u8Buf[i32Head] = ch;
            i32Head = i32Tmp;
        }
    }
    else
    {
        if(i32Tail == i32Head)
            return;
    }

    // pop char
    do
    {
        i32Tmp = i32Tail + 1;
        if(i32Tmp > BUF_SIZE) i32Tmp = 0;

        if((DEBUG_PORT->FSR & UART_FSR_TX_FULL_Msk) == 0)
        {
            DEBUG_PORT->DATA = u8Buf[i32Tail];
            i32Tail = i32Tmp;
        }
        else
            break; // FIFO full
    }
    while(i32Tail != i32Head);
}
#endif

/**
* @brief    Routine to send a char
*
* @param[in] ch A character data writes to debug port
*
* @returns  Send value from UART debug port or semihost
*
* @details  Send a target char to UART debug port or semihost.
*/
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
        {
            g_buf_len = 0;
        }
    }
#else
    SendChar_ToUART(ch);
#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.
*/
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

    while(1)
    {
        if((DEBUG_PORT->FSR & UART_FSR_RX_EMPTY_Msk) == 0)
        {
            return (DEBUG_PORT->DATA);
        }
    }

#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)
{
    return !((DEBUG_PORT->FSR & UART_FSR_RX_EMPTY_Msk) == 0);
}
/**
* @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)
{
    return ((DEBUG_PORT->FSR & UART_FSR_TE_FLAG_Msk) != 0);
}

/**
* @brief    C library retargetting
*
* @param[in]  ch  Write a character data
*
* @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.
*
* [url=home.php?mod=space&uid=536309]@NOTE[/url]       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__ )

#if !defined (OS_USE_SEMIHOSTING)
int _write (int fd, char *ptr, int len)
{
    int i = len;

    while(i--)
    {
        while(DEBUG_PORT->FSR & UART_FSR_TX_FULL_Msk);

        if(*ptr == '\n')
        {
            DEBUG_PORT->DATA = '\r';
            while(DEBUG_PORT->FSR & UART_FSR_TX_FULL_Msk);
        }

        DEBUG_PORT->DATA = *ptr++;
        }
    return len;
}

int _read (int fd, char *ptr, int len)
{

    while((DEBUG_PORT->FSR & UART_FSR_RX_EMPTY_Msk) != 0);
    *ptr = DEBUG_PORT->DATA;
    return 1;


}
#endif

#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


文件是新唐M058S单片机库函数中的一个重要文件,主要用于调试端口和半主机(Semihosting)的设置。以下是对该文件的详细解释,帮助你理解其功能和作用。

1. 文件概述
文件名: retarget.c

版本: V3.00

功能: 该文件主要用于配置调试端口和半主机功能,使得开发者可以通过调试端口或半主机进行调试信息的输入输出。

2. 主要功能模块
2.1 全局变量
FILE __stdout 和 FILE __stdin: 这两个全局变量用于标准输入输出的重定向。在嵌入式系统中,通常需要将标准输入输出重定向到调试端口或半主机。

2.2 寄存器转储函数
stackDump(uint32_t stack[]): 该函数用于在发生硬错误(Hard Fault)时,打印出寄存器的值(如 r0, r1, r2, r3, r12, lr, pc, psr),帮助开发者定位错误。

2.3 硬错误处理函数
Hard_Fault_Handler(uint32_t stack[]): 当发生硬错误时,该函数会被调用。它会调用 stackDump 函数打印寄存器值,并进入一个死循环(while(1)),等待开发者处理。

2.4 半主机支持
半主机(Semihosting): 半主机是一种调试技术,允许嵌入式系统通过调试器与主机进行通信,例如打印调试信息到主机的控制台。

SH_DoCommand(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0): 该函数用于处理半主机命令。通过 BKPT 指令触发调试器或硬错误,从而实现与主机的通信。

HardFault_Handler(void): 该函数是硬错误处理程序,支持半主机功能。它会根据堆栈指针(MSP或PSP)的不同,调用相应的处理函数。

2.5 调试端口输出函数
SendChar_ToUART(int ch): 该函数用于将字符发送到调试端口(通常是UART)。如果启用了非阻塞模式(NONBLOCK_PRINTF),则使用缓冲区来存储字符,以避免阻塞。

SendChar(int ch): 该函数根据是否启用了半主机功能,选择将字符发送到调试端口或通过半主机发送。

2.6 调试端口输入函数
GetChar(void): 该函数用于从调试端口或半主机获取一个字符。

kbhit(void): 该函数用于检查是否有字符输入。

IsDebugFifoEmpty(void): 该函数用于检查调试端口的FIFO是否为空。

2.7 C库重定向
_ttywrch(int ch): 该函数用于将字符写入调试端口。

fputc(int ch, FILE *stream): 该函数是C库的标准输出函数 fputc 的重定向实现,将字符发送到调试端口。

fgetc(FILE *stream): 该函数是C库的标准输入函数 fgetc 的重定向实现,从调试端口获取字符。

2.8 其他函数
_write(int fd, char *ptr, int len) 和 _read(int fd, char *ptr, int len): 这些函数是GNU工具链中的系统调用,用于实现标准输入输出的重定向。

__exit(int return_code) 和 _sys_exit(int return_code): 这些函数用于在程序退出时,确保所有调试信息都已输出。

3. 关键点
调试端口: 该文件通过UART或其他调试端口实现调试信息的输入输出。

半主机: 通过半主机功能,开发者可以在调试器中查看调试信息,而不需要实际的硬件调试端口。

硬错误处理: 当系统发生硬错误时,该文件提供了寄存器转储功能,帮助开发者定位错误。

4. 使用场景
调试信息输出: 在开发过程中,开发者可以通过 printf 函数将调试信息输出到调试端口或半主机。

错误处理: 当系统发生硬错误时,可以通过该文件提供的函数查看寄存器状态,帮助定位问题。

输入输出重定向: 在嵌入式系统中,标准输入输出通常需要重定向到调试端口或半主机,该文件提供了相应的实现。

使用特权

评论回复
沙发
598330983| | 2025-2-15 10:47 | 只看该作者
我一直没搞明白arm和51的重定向函数怎么是不同的。

使用特权

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

本版积分规则

201

主题

3490

帖子

14

粉丝