[牛人杂谈] M058S重定向

[复制链接]
 楼主| 734774645 发表于 2025-2-14 15:39 | 显示全部楼层 |阅读模式
  1. /**************************************************************************//**
  2. * [url=home.php?mod=space&uid=288409]@file[/url]     retarget.c
  3. * [url=home.php?mod=space&uid=895143]@version[/url]  V3.00
  4. * $Revision: 4 $
  5. * $Date: 15/11/04 9:35a $
  6. * [url=home.php?mod=space&uid=247401]@brief[/url]    Debug Port and Semihost Setting Source File
  7. *
  8. * @note
  9. * SPDX-License-Identifier: Apache-2.0
  10. *
  11. * Copyright (C) 2011 Nuvoton Technology Corp. All rights reserved.
  12. *
  13. ******************************************************************************/


  14. #include <stdio.h>
  15. #include "M058S.h"

  16. #if defined ( __CC_ARM   )
  17. #if (__ARMCC_VERSION < 400000)
  18. #else
  19. /* Insist on keeping widthprec, to avoid X propagation by benign code in C-lib */
  20. #pragma import _printf_widthprec
  21. #endif
  22. #endif

  23. /*---------------------------------------------------------------------------------------------------------*/
  24. /* Global variables                                                                                        */
  25. /*---------------------------------------------------------------------------------------------------------*/
  26. #if !(defined(__ICCARM__) && (__VER__ >= 6010000))
  27. struct __FILE
  28. {
  29.     int handle; /* Add whatever you need here */
  30. };
  31. #endif
  32. FILE __stdout;
  33. FILE __stdin;

  34. enum { r0, r1, r2, r3, r12, lr, pc, psr};

  35. /**
  36. * @brief       Helper function to dump register while hard fault occurred
  37. * @param[in]   stack pointer points to the dumped registers in SRAM
  38. * [url=home.php?mod=space&uid=266161]@return[/url]      None
  39. * [url=home.php?mod=space&uid=1543424]@Details[/url]     This function is implement to print r0, r1, r2, r3, r12, lr, pc, psr
  40. */
  41. static void stackDump(uint32_t stack[])
  42. {   
  43.     printf("r0  = 0x%x\n", stack[r0]);
  44.     printf("r1  = 0x%x\n", stack[r1]);
  45.     printf("r2  = 0x%x\n", stack[r2]);
  46.     printf("r3  = 0x%x\n", stack[r3]);
  47.     printf("r12 = 0x%x\n", stack[r12]);
  48.     printf("lr  = 0x%x\n", stack[lr]);
  49.     printf("pc  = 0x%x\n", stack[pc]);
  50.     printf("psr = 0x%x\n", stack[psr]);
  51. }

  52. /**
  53. * @brief       Hard fault handler
  54. * @param[in]   stack pointer points to the dumped registers in SRAM
  55. * @return      None
  56. * @details     Replace while(1) at the end of this function with chip reset if WDT is not enabled for end product
  57. */
  58. void Hard_Fault_Handler(uint32_t stack[])
  59. {
  60.     printf("In Hard Fault Handler\n");

  61.     stackDump(stack);

  62.     // Replace while(1) with chip reset if WDT is not enabled for end product
  63.     while(1);
  64.     //SYS->IPRSTC1 = SYS_IPRSTC1_CHIP_RST_Msk;
  65. }

  66. /*---------------------------------------------------------------------------------------------------------*/
  67. /* Routine to write a char                                                                                 */
  68. /*---------------------------------------------------------------------------------------------------------*/

  69. #if defined(DEBUG_ENABLE_SEMIHOST)
  70. /* The static buffer is used to speed up the semihost */
  71. static char g_buf[16];
  72. static char g_buf_len = 0;

  73. /* Make sure won't goes here only because --gnu is defined , so
  74.    add !__CC_ARM and !__ICCARM__ checking */
  75. # if defined ( __GNUC__ ) && !(__CC_ARM) && !(__ICCARM__)

  76. # elif defined(__ICCARM__)


  77. void SH_End(void)
  78. {
  79.     asm("MOVS   R0,#1 \n"        //; Set return value to 1
  80.         "BX     lr    \n"            //; Return
  81.        );
  82. }

  83. void SH_ICE(void)
  84. {
  85.   asm("CMP   R2,#0   \n"
  86.       "BEQ   SH_End  \n"
  87.       "STR   R0,[R2] \n"       //; Save the return value to *pn32Out_R0
  88.      );
  89. }

  90. /**
  91. *
  92. * @brief      The function to process semihosted command
  93. * @param[in]  n32In_R0  : semihost register 0
  94. * @param[in]  n32In_R1  : semihost register 1
  95. * @param[out] pn32Out_R0: semihost register 0
  96. * @retval     0: No ICE debug
  97. * @retval     1: ICE debug
  98. *
  99. */
  100. int32_t SH_DoCommand(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0)
  101. {
  102.     asm("BKPT   0xAB   \n"       //; This instruction will cause ICE trap or system HardFault
  103.         "B      SH_ICE \n"
  104.         "SH_HardFault: \n"       //; Captured by HardFault
  105.         "MOVS   R0,#0  \n"       //; Set return value to 0
  106.         "BX     lr     \n"       //; Return
  107.         );

  108.     return 1;                    //; Return 1 when it is trap by ICE
  109. }

  110. /**
  111. * @brief       Get LR value and branch to Hard_Fault_Handler function
  112. * @param       None
  113. * @return      None
  114. * @details     This function is use to get LR value and branch to Hard_Fault_Handler function.
  115. */
  116. void Get_LR_and_Branch(void)
  117. {
  118.     asm("MOV     R1, LR               \n" //; LR current value
  119.         "B       Hard_Fault_Handler   \n"
  120.        );
  121. }

  122. /**
  123. * @brief       Get MSP value and branch to Get_LR_and_Branch function
  124. * @param       None
  125. * @return      None
  126. * @details     This function is use to get stack pointer value and branch to Get_LR_and_Branch function.
  127. */
  128. void Stack_Use_MSP(void)
  129. {
  130.     asm("MRS     R0, MSP           \n" //; read MSP
  131.         "B       Get_LR_and_Branch \n"
  132.        );
  133. }

  134. /**
  135. * @brief       Get stack pointer value and branch to Get_LR_and_Branch function
  136. * @param       None
  137. * @return      None
  138. * @details     This function is use to get stack pointer value and branch to Get_LR_and_Branch function.
  139. */
  140. void HardFault_Handler_Ret(void)
  141. {
  142.     asm("MOVS    r0, #4                        \n"
  143.         "MOV     r1, LR                        \n"
  144.         "TST     r0, r1                        \n" //; check LR bit 2
  145.         "BEQ     Stack_Use_MSP                 \n" //; stack use MSP
  146.         "MRS     R0, PSP                       \n" //; stack use PSP, read PSP
  147.         "B       Get_LR_and_Branch             \n"
  148.        );
  149. }

  150. /**
  151. * @brief    This function is implemented to support semihost
  152. * @param    None
  153. * @returns  None
  154. * @details  This function is implement to support semihost message print.
  155. *
  156. */
  157. void SP_Read_Ready(void)
  158. {
  159.     asm("LDR     R1, [R0, #24] \n"        //; Get previous PC
  160.         "LDRH    R3, [R1]      \n"        //; Get instruction
  161.         "LDR     R2, [pc, #8]  \n"        //; The special BKPT instruction
  162.         "CMP     R3, R2        \n"        //; Test if the instruction at previous PC is BKPT
  163.         "BNE     HardFault_Handler_Ret \n" //; Not BKPT
  164.         "ADDS    R1, #4        \n"        //; Skip BKPT and next line
  165.         "STR     R1, [R0, #24] \n"        //; Save previous PC
  166.         "BX      lr            \n"        //; Return
  167.         "DCD     0xBEAB        \n"        //; BKPT instruction code
  168.         "B       HardFault_Handler_Ret \n"
  169.        );
  170. }

  171. /**
  172. * @brief       Get stack pointer value and branch to Get_LR_and_Branch function
  173. * @param       None
  174. * @return      None
  175. * @details     This function is use to get stack pointer value and branch to Get_LR_and_Branch function.
  176. */
  177. void SP_is_PSP(void)
  178. {
  179.     asm(
  180.         "MRS     R0, PSP       \n"      //; stack use PSP, read PSP
  181.         "B       Get_LR_and_Branch    \n"
  182.    
  183.        );
  184. }

  185. /**
  186. * @brief    This HardFault handler is implemented to support semihost
  187. *
  188. * @param    None
  189. *
  190. * @returns  None
  191. *
  192. * @details  This function is implement to support semihost message print.
  193. *
  194. */
  195. void HardFault_Handler (void)
  196. {
  197.     asm("MOV     R0, lr        \n"
  198.         "LSLS    R0, #29       \n"        //; Check bit 2
  199.         "BMI     SP_is_PSP     \n"        //; previous stack is PSP
  200.         "MRS     R0, MSP       \n"        //; previous stack is MSP, read MSP
  201.         "B       SP_Read_Ready \n"
  202.        );

  203.     while(1);
  204. }


  205. # else

  206. /**
  207. * @brief    This HardFault handler is implemented to support semihost
  208. * @param    None
  209. * @returns  None
  210. * @details  This function is implement to support semihost message print.
  211. *
  212. */
  213. __asm int32_t HardFault_Handler(void)
  214. {
  215.     IMPORT  Hard_Fault_Handler

  216.     MOV     R0, LR
  217.     LSLS    R0, #29               //; Check bit 2
  218.     BMI     SP_is_PSP             //; previous stack is PSP
  219.     MRS     R0, MSP               //; previous stack is MSP, read MSP
  220.     B       SP_Read_Ready
  221. SP_is_PSP
  222.     MRS     R0, PSP               //; Read PSP

  223. SP_Read_Ready
  224.     LDR     R1, [R0, #24]         //; Get previous PC
  225.     LDRH    R3, [R1]              //; Get instruction
  226.     LDR     R2, =0xBEAB           //; The special BKPT instruction
  227.     CMP     R3, R2                //; Test if the instruction at previous PC is BKPT
  228.     BNE     HardFault_Handler_Ret //; Not BKPT

  229.     ADDS    R1, #4                //; Skip BKPT and next line
  230.     STR     R1, [R0, #24]         //; Save previous PC

  231.     BX      LR                    //; Return
  232. HardFault_Handler_Ret

  233.     /* TODO: Implement your own hard fault handler here. */
  234.     MOVS    r0, #4
  235.     MOV     r1, LR
  236.     TST     r0, r1                          //; check LR bit 2  
  237.     BEQ     Stack_Use_MSP                   //; stack use MSP
  238.     MRS     R0, PSP ;stack use PSP          //; stack use PSP, read PSP
  239.     B       Get_LR_and_Branch
  240. Stack_Use_MSP
  241.     MRS     R0, MSP ; stack use MSP         //; read MSP
  242. Get_LR_and_Branch
  243.     MOV     R1, LR ; LR current value       //; LR current value      
  244.     LDR     R2,=__cpp(Hard_Fault_Handler)   //; branch to Hard_Fault_Handler
  245.     BX      R2

  246.     B       .

  247.                  ALIGN
  248. }

  249. /**
  250. *
  251. * @brief      The function to process semihosted command
  252. * @param[in]  n32In_R0  : semihost register 0
  253. * @param[in]  n32In_R1  : semihost register 1
  254. * @param[out] pn32Out_R0: semihost register 0
  255. * @retval     0: No ICE debug
  256. * @retval     1: ICE debug
  257. *
  258. */
  259. __asm int32_t SH_DoCommand(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0)
  260. {
  261.     BKPT   0xAB          //; Wait ICE or HardFault
  262.     //; ICE will step over BKPT directly
  263.     //; HardFault will step BKPT and the next line
  264.     B      SH_ICE

  265. SH_HardFault             //; Captured by HardFault
  266.     MOVS   R0, #0        //; Set return value to 0
  267.     BX     lr            //; Return

  268. SH_ICE                   //; Captured by ICE
  269.     //; Save return value
  270.     CMP    R2, #0
  271.     BEQ    SH_End
  272.     STR    R0, [R2]      //; Save the return value to *pn32Out_R0

  273. SH_End
  274.     MOVS   R0, #1        //; Set return value to 1
  275.     BX     lr            //; Return
  276. }
  277. #endif


  278. #else // Non-semihost

  279. /* Make sure won't goes here only because --gnu is defined , so
  280.    add !__CC_ARM and !__ICCARM__ checking */
  281. # if defined ( __GNUC__ ) && !(__CC_ARM) && !(__ICCARM__)

  282. /**
  283. * @brief    This HardFault handler is implemented to show r0, r1, r2, r3, r12, lr, pc, psr
  284. *
  285. * @param    None
  286. *
  287. * @returns  None
  288. *
  289. * @details  This function is implement to print r0, r1, r2, r3, r12, lr, pc, psr.
  290. *
  291. */
  292. void HardFault_Handler(void)
  293. {
  294.     asm("MOVS    r0, #4                        \n"
  295.         "MOV     r1, LR                        \n"
  296.         "TST     r0, r1                        \n" /*; check LR bit 2 */
  297.         "BEQ     1f                            \n" /*; stack use MSP */
  298.         "MRS     R0, PSP                       \n" /*; stack use PSP, read PSP */
  299.         "MOV     R1, LR                        \n" /*; LR current value */
  300.         "B       Hard_Fault_Handler            \n"
  301.         "1:                                    \n"
  302.         "MRS     R0, MSP                       \n" /*; LR current value */
  303.         "B       Hard_Fault_Handler            \n"
  304.         ::[Hard_Fault_Handler] "r" (Hard_Fault_Handler) // input
  305.     );
  306.     while(1);
  307. }

  308. # elif defined(__ICCARM__)

  309. void Get_LR_and_Branch(void)
  310. {
  311.     asm("MOV     R1, LR                  \n" //; LR current value
  312.         "B       Hard_Fault_Handler      \n"
  313.        );
  314. }

  315. void Stack_Use_MSP(void)
  316. {
  317.     asm("MRS     R0, MSP           \n" //; read MSP
  318.         "B       Get_LR_and_Branch \n"
  319.        );
  320. }

  321. /**
  322. * @brief    This HardFault handler is implemented to show r0, r1, r2, r3, r12, lr, pc, psr
  323. *
  324. * @param    None
  325. *
  326. * @returns  None
  327. *
  328. * @details  This function is implement to print r0, r1, r2, r3, r12, lr, pc, psr.
  329. *
  330. */
  331. void HardFault_Handler(void)
  332. {
  333.     asm("MOVS    r0, #4                        \n"
  334.         "MOV     r1, LR                        \n"
  335.         "TST     r0, r1                        \n" //; check LR bit 2
  336.         "BEQ     Stack_Use_MSP                 \n" //; stack use MSP
  337.         "MRS     R0, PSP                       \n" //; stack use PSP, read PSP
  338.         "B       Get_LR_and_Branch             \n"
  339.        );

  340.     while(1);
  341. }

  342. # else

  343. /**
  344. * @brief    This HardFault handler is implemented to show r0, r1, r2, r3, r12, lr, pc, psr
  345. *
  346. * @param    None
  347. *
  348. * @return   None
  349. *
  350. * @details  The function extracts the location of stack frame and passes it to Hard_Fault_Handler function as a pointer
  351. *
  352. */
  353. __asm int32_t HardFault_Handler(void)
  354. {
  355.     IMPORT  Hard_Fault_Handler

  356.     MOVS    r0, #4
  357.     MOV     r1, LR
  358.     TST     r0, r1          //; check LR bit 2                 
  359.     BEQ     Stack_Use_MSP   //; stack use MSP
  360.     MRS     R0, PSP         //; stack use PSP, read PSP
  361.     B       Get_LR_and_Branch
  362. Stack_Use_MSP
  363.     MRS     R0, MSP         //; read MSP
  364. Get_LR_and_Branch
  365.     MOV     R1, LR          //; LR current value
  366.     LDR     R2,=__cpp(Hard_Fault_Handler) //; branch to Hard_Fault_Handler
  367.     BX      R2
  368. }

  369. #endif

  370. #endif


  371. /**
  372. * @brief    Routine to send a char
  373. *
  374. * @param[in] ch  A character data writes to debug port
  375. *
  376. * @returns  Send value from UART debug port
  377. *
  378. * @details  Send a target char to UART debug port .
  379. */
  380. #ifndef NONBLOCK_PRINTF
  381. void SendChar_ToUART(int ch)
  382. {

  383.     while(DEBUG_PORT->FSR & UART_FSR_TX_FULL_Msk);
  384.     if(ch == '\n')
  385.     {
  386.         DEBUG_PORT->DATA = '\r';
  387.         while(DEBUG_PORT->FSR & UART_FSR_TX_FULL_Msk);
  388.     }

  389.     DEBUG_PORT->DATA = ch;
  390. }

  391. #else
  392. /* Non-block implement of send char */
  393. #define BUF_SIZE    512
  394. void SendChar_ToUART(int ch)
  395. {
  396.     static uint8_t u8Buf[BUF_SIZE] = {0};
  397.     static int32_t i32Head = 0;
  398.     static int32_t i32Tail = 0;
  399.     int32_t i32Tmp;

  400.     /* Only flush the data in buffer to UART when ch == 0 */
  401.     if(ch)
  402.     {
  403.         // Push char
  404.         if(ch == '\n')
  405.         {
  406.             i32Tmp = i32Head + 1;
  407.             if(i32Tmp > BUF_SIZE) i32Tmp = 0;
  408.             if(i32Tmp != i32Tail)
  409.             {
  410.                 u8Buf[i32Head] = '\r';
  411.                 i32Head = i32Tmp;
  412.             }
  413.         }

  414.         i32Tmp = i32Head + 1;
  415.         if(i32Tmp > BUF_SIZE) i32Tmp = 0;
  416.         if(i32Tmp != i32Tail)
  417.         {
  418.             u8Buf[i32Head] = ch;
  419.             i32Head = i32Tmp;
  420.         }
  421.     }
  422.     else
  423.     {
  424.         if(i32Tail == i32Head)
  425.             return;
  426.     }

  427.     // pop char
  428.     do
  429.     {
  430.         i32Tmp = i32Tail + 1;
  431.         if(i32Tmp > BUF_SIZE) i32Tmp = 0;

  432.         if((DEBUG_PORT->FSR & UART_FSR_TX_FULL_Msk) == 0)
  433.         {
  434.             DEBUG_PORT->DATA = u8Buf[i32Tail];
  435.             i32Tail = i32Tmp;
  436.         }
  437.         else
  438.             break; // FIFO full
  439.     }
  440.     while(i32Tail != i32Head);
  441. }
  442. #endif

  443. /**
  444. * @brief    Routine to send a char
  445. *
  446. * @param[in] ch A character data writes to debug port
  447. *
  448. * @returns  Send value from UART debug port or semihost
  449. *
  450. * @details  Send a target char to UART debug port or semihost.
  451. */
  452. void SendChar(int ch)
  453. {
  454. #if defined(DEBUG_ENABLE_SEMIHOST)
  455.     g_buf[g_buf_len++] = ch;
  456.     g_buf[g_buf_len] = '\0';
  457.     if(g_buf_len + 1 >= sizeof(g_buf) || ch == '\n' || ch == '\0')
  458.     {
  459.         /* Send the char */
  460.         if(SH_DoCommand(0x04, (int)g_buf, NULL) != 0)
  461.         {
  462.             g_buf_len = 0;
  463.             return;
  464.         }
  465.         else
  466.         {
  467.             g_buf_len = 0;
  468.         }
  469.     }
  470. #else
  471.     SendChar_ToUART(ch);
  472. #endif
  473. }

  474. /**
  475. * @brief    Routine to get a char
  476. *
  477. * @param    None
  478. *
  479. * @returns  Get value from UART debug port or semihost
  480. *
  481. * @details  Wait UART debug port or semihost to input a char.
  482. */
  483. char GetChar(void)
  484. {
  485. #ifdef DEBUG_ENABLE_SEMIHOST
  486. # if defined (__CC_ARM)
  487.     int nRet;
  488.     while(SH_DoCommand(0x101, 0, &nRet) != 0)
  489.     {
  490.         if(nRet != 0)
  491.         {
  492.             SH_DoCommand(0x07, 0, &nRet);
  493.             return (char)nRet;
  494.         }
  495.     }
  496. # else
  497.     int nRet;
  498.     while(SH_DoCommand(0x7, 0, &nRet) != 0)
  499.     {
  500.         if(nRet != 0)
  501.             return (char)nRet;
  502.     }
  503. # endif
  504.     return (0);
  505. #else

  506.     while(1)
  507.     {
  508.         if((DEBUG_PORT->FSR & UART_FSR_RX_EMPTY_Msk) == 0)
  509.         {
  510.             return (DEBUG_PORT->DATA);
  511.         }
  512.     }

  513. #endif
  514. }

  515. /**
  516. * @brief    Check any char input from UART
  517. *
  518. * @param    None
  519. *
  520. * @retval   1: No any char input
  521. * @retval   0: Have some char input
  522. *
  523. * @details  Check UART RSR RX EMPTY or not to determine if any char input from UART
  524. */

  525. int kbhit(void)
  526. {
  527.     return !((DEBUG_PORT->FSR & UART_FSR_RX_EMPTY_Msk) == 0);
  528. }
  529. /**
  530. * @brief    Check if debug message finished
  531. *
  532. * @param    None
  533. *
  534. * @retval   1: Message is finished
  535. * @retval   0: Message is transmitting.
  536. *
  537. * @details  Check if message finished (FIFO empty of debug port)
  538. */

  539. int IsDebugFifoEmpty(void)
  540. {
  541.     return ((DEBUG_PORT->FSR & UART_FSR_TE_FLAG_Msk) != 0);
  542. }

  543. /**
  544. * @brief    C library retargetting
  545. *
  546. * @param[in]  ch  Write a character data
  547. *
  548. * @returns  None
  549. *
  550. * @details  Check if message finished (FIFO empty of debug port)
  551. */

  552. void _ttywrch(int ch)
  553. {
  554.     SendChar(ch);
  555.     return;
  556. }


  557. /**
  558. * @brief      Write character to stream
  559. *
  560. * @param[in]  ch       Character to be written. The character is passed as its int promotion.
  561. * @param[in]  stream   Pointer to a FILE object that identifies the stream where the character is to be written.
  562. *
  563. * @returns    If there are no errors, the same character that has been written is returned.
  564. *             If an error occurs, EOF is returned and the error indicator is set (see ferror).
  565. *
  566. * @details    Writes a character to the stream and advances the position indicator.\n
  567. *             The character is written at the current position of the stream as indicated \n
  568. *             by the internal position indicator, which is then advanced one character.
  569. *
  570. * [url=home.php?mod=space&uid=536309]@NOTE[/url]       The above descriptions are copied from http://www.cplusplus.com/reference/clibrary/cstdio/fputc/.
  571. *
  572. *
  573. */

  574. int fputc(int ch, FILE *stream)
  575. {
  576.     SendChar(ch);
  577.     return ch;
  578. }

  579. #if defined ( __GNUC__ )

  580. #if !defined (OS_USE_SEMIHOSTING)
  581. int _write (int fd, char *ptr, int len)
  582. {
  583.     int i = len;

  584.     while(i--)
  585.     {
  586.         while(DEBUG_PORT->FSR & UART_FSR_TX_FULL_Msk);

  587.         if(*ptr == '\n')
  588.         {
  589.             DEBUG_PORT->DATA = '\r';
  590.             while(DEBUG_PORT->FSR & UART_FSR_TX_FULL_Msk);
  591.         }

  592.         DEBUG_PORT->DATA = *ptr++;
  593.         }
  594.     return len;
  595. }

  596. int _read (int fd, char *ptr, int len)
  597. {

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


  601. }
  602. #endif

  603. #else
  604. /**
  605. * @brief      Get character from UART debug port or semihosting input
  606. *
  607. * @param[in]  stream   Pointer to a FILE object that identifies the stream on which the operation is to be performed.
  608. *
  609. * @returns    The character read from UART debug port or semihosting
  610. *
  611. * @details    For get message from debug port or semihosting.
  612. *
  613. */

  614. int fgetc(FILE *stream)
  615. {
  616.     return (GetChar());
  617. }

  618. /**
  619. * @brief      Check error indicator
  620. *
  621. * @param[in]  stream   Pointer to a FILE object that identifies the stream.
  622. *
  623. * @returns    If the error indicator associated with the stream was set, the function returns a nonzero value.
  624. *             Otherwise, it returns a zero value.
  625. *
  626. * @details    Checks if the error indicator associated with stream is set, returning a value different
  627. *             from zero if it is. This indicator is generally set by a previous operation on the stream that failed.
  628. *
  629. * @note       The above descriptions are copied from http://www.cplusplus.com/reference/clibrary/cstdio/ferror/.
  630. *
  631. */

  632. // int ferror(FILE *stream)
  633. // {
  634. //     return EOF;
  635. // }
  636. #endif

  637. #ifdef DEBUG_ENABLE_SEMIHOST
  638. # ifdef __ICCARM__
  639. void __exit(int return_code)
  640. {

  641.     /* Check if link with ICE */
  642.     if(SH_DoCommand(0x18, 0x20026, NULL) == 0)
  643.     {
  644.         /* Make sure all message is print out */
  645.         while(IsDebugFifoEmpty() == 0);
  646.     }
  647. label:
  648.     goto label;  /* endless loop */
  649. }
  650. # else
  651. void _sys_exit(int return_code)
  652. {

  653.     /* Check if link with ICE */
  654.     if(SH_DoCommand(0x18, 0x20026, NULL) == 0)
  655.     {
  656.         /* Make sure all message is print out */
  657.         while(IsDebugFifoEmpty() == 0);
  658.     }
  659. label:
  660.     goto label;  /* endless loop */
  661. }
  662. # endif
  663. #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的重定向函数怎么是不同的。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

210

主题

3585

帖子

15

粉丝
快速回复 在线客服 返回列表 返回顶部

210

主题

3585

帖子

15

粉丝
快速回复 在线客服 返回列表 返回顶部