M480 BSP  V3.05.001
The Board Support Package for M480 Series
retarget.c
Go to the documentation of this file.
1 /**************************************************************************/
11 #include <stdio.h>
12 #include "NuMicro.h"
13 
14 #if defined ( __CC_ARM )
15 #if (__ARMCC_VERSION < 400000)
16 #else
17 /* Insist on keeping widthprec, to avoid X propagation by benign code in C-lib */
18 #pragma import _printf_widthprec
19 #endif
20 #endif
21 /* Uncomment this line to disable all printf and getchar. getchar() will always return 0x00*/
22 /* #define DISABLE_UART */
23 
24 #if defined(DEBUG_ENABLE_SEMIHOST)
25  #ifndef DISABLE_UART
26  #define DISABLE_UART
27  #endif
28 #endif
29 
30 #define DEBUG_PORT UART0
31 /*---------------------------------------------------------------------------------------------------------*/
32 /* Global variables */
33 /*---------------------------------------------------------------------------------------------------------*/
34 #if !(defined(__ICCARM__) && (__VER__ >= 6010000))
35 # if (__ARMCC_VERSION < 6040000)
36 struct __FILE
37 {
38  int handle; /* Add whatever you need here */
39 };
40 # endif
41 #elif(__VER__ >= 8000000)
42 struct __FILE
43 {
44  int handle; /* Add whatever you need here */
45 };
46 #endif
47 FILE __stdout;
48 FILE __stdin;
49 
50 
51 enum { r0, r1, r2, r3, r12, lr, pc, psr};
52 
59 static void stackDump(uint32_t stack[])
60 {
61  printf("r0 = 0x%x\n", stack[r0]);
62  printf("r1 = 0x%x\n", stack[r1]);
63  printf("r2 = 0x%x\n", stack[r2]);
64  printf("r3 = 0x%x\n", stack[r3]);
65  printf("r12 = 0x%x\n", stack[r12]);
66  printf("lr = 0x%x\n", stack[lr]);
67  printf("pc = 0x%x\n", stack[pc]);
68  printf("psr = 0x%x\n", stack[psr]);
69 }
70 
77 void Hard_Fault_Handler(uint32_t stack[])
78 {
79  printf("In Hard Fault Handler\n");
80 
81  stackDump(stack);
82  /* Replace while(1) with chip reset if WDT is not enabled for end product */
83  while(1);
84  /* SYS->IPRST0 = SYS_IPRST0_CHIPRST_Msk; */
85 }
86 
87 
88 
89 /*---------------------------------------------------------------------------------------------------------*/
90 /* Routine to write a char */
91 /*---------------------------------------------------------------------------------------------------------*/
92 
93 #if defined(DEBUG_ENABLE_SEMIHOST)
94 /* The static buffer is used to speed up the semihost */
95 static char g_buf[16];
96 static char g_buf_len = 0;
97 
98 /* Make sure won't goes here only because --gnu is defined , so
99  add !__CC_ARM and !__ICCARM__ checking */
100 # if defined ( __GNUC__ ) && !(__CC_ARM) && !(__ICCARM__)
101 
102 # elif defined(__ICCARM__) // IAR
103 
104 void SH_End(void)
105 {
106  asm("MOVS R0,#1 \n" /*; Set return value to 1 */
107  "BX lr \n" /*; Return */
108  );
109 }
110 
111 void SH_ICE(void)
112 {
113  asm("CMP R2,#0 \n"
114  "BEQ SH_End \n"
115  "STR R0,[R2] \n" /*; Save the return value to *pn32Out_R0 */
116  );
117 }
118 
129 int32_t SH_DoCommand(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0)
130 {
131  asm("BKPT 0xAB \n" /*; This instruction will cause ICE trap or system HardFault */
132  "B SH_ICE \n"
133  "SH_HardFault: \n" /*; Captured by HardFault */
134  "MOVS R0,#0 \n" /*; Set return value to 0 */
135  "BX lr \n" /*; Return */
136  );
137 
138  return 1; /*; Return 1 when it is trap by ICE */
139 }
140 
147 void Get_LR_and_Branch(void)
148 {
149  asm("MOV R1, LR \n" /*; LR current value */
150  "B Hard_Fault_Handler \n"
151  );
152 }
153 
160 void Stack_Use_MSP(void)
161 {
162  asm("MRS R0, MSP \n" /*; read MSP */
163  "B Get_LR_and_Branch \n"
164  );
165 }
166 
173 void HardFault_Handler_Ret(void)
174 {
175  asm("MOVS r0, #4 \n"
176  "MOV r1, LR \n"
177  "TST r0, r1 \n" /*; check LR bit 2 */
178  "BEQ Stack_Use_MSP \n" /*; stack use MSP */
179  "MRS R0, PSP \n" /*; stack use PSP, read PSP */
180  "B Get_LR_and_Branch \n"
181  );
182 }
183 
191 void SP_Read_Ready(void)
192 {
193  asm("LDR R1, [R0, #24] \n" /*; Get previous PC */
194  "LDRH R3, [R1] \n" /*; Get instruction */
195  "LDR R2, [pc, #8] \n" /*; The special BKPT instruction */
196  "CMP R3, R2 \n" /*; Test if the instruction at previous PC is BKPT */
197  "BNE HardFault_Handler_Ret \n" /*; Not BKPT */
198  "ADDS R1, #4 \n" /*; Skip BKPT and next line */
199  "STR R1, [R0, #24] \n" /*; Save previous PC */
200  "BX lr \n" /*; Return */
201  "DCD 0xBEAB \n" /*; BKPT instruction code */
202  "B HardFault_Handler_Ret \n"
203  );
204 }
205 
212 void SP_is_PSP(void)
213 {
214  asm(
215  "MRS R0, PSP \n" /*; stack use PSP, read PSP */
216  "B Get_LR_and_Branch \n"
217 
218  );
219 }
220 
231 void HardFault_Handler (void)
232 {
233  asm("MOV R0, lr \n"
234  "LSLS R0, #29 \n" /*; Check bit 2 */
235  "BMI SP_is_PSP \n" /*; previous stack is PSP */
236  "MRS R0, MSP \n" /*; previous stack is MSP, read MSP */
237  "B SP_Read_Ready \n"
238  );
239 
240  while(1);
241 }
242 
243 # else
244 
252 __asm int32_t HardFault_Handler(void)
253 {
254  MOV R0, LR
255  LSLS R0, #29 /*; Check bit 2 */
256  BMI SP_is_PSP /*; previous stack is PSP */
257  MRS R0, MSP /*; previous stack is MSP, read MSP */
258  B SP_Read_Ready
259 SP_is_PSP
260  MRS R0, PSP /*; Read PSP */
261 
262 SP_Read_Ready
263  LDR R1, [R0, #24] /*; Get previous PC */
264  LDRH R3, [R1] /*; Get instruction */
265  LDR R2, =0xBEAB /*; The special BKPT instruction */
266  CMP R3, R2 /*; Test if the instruction at previous PC is BKPT */
267  BNE HardFault_Handler_Ret /*; Not BKPT */
268 
269  ADDS R1, #4 /*; Skip BKPT and next line */
270  STR R1, [R0, #24] /*; Save previous PC */
271 
272  BX LR /*; Return */
273 HardFault_Handler_Ret
274 
275  /* TODO: Implement your own hard fault handler here. */
276  MOVS r0, #4
277  MOV r1, LR
278  TST r0, r1 /*; check LR bit 2 */
279  BEQ Stack_Use_MSP /*; stack use MSP */
280  MRS R0, PSP ;stack use PSP /*; stack use PSP, read PSP */
281  B Get_LR_and_Branch
282 Stack_Use_MSP
283  MRS R0, MSP ; stack use MSP /*; read MSP */
284 Get_LR_and_Branch
285  MOV R1, LR ; LR current value /*; LR current value */
286  LDR R2,=__cpp(Hard_Fault_Handler) /*; branch to Hard_Fault_Handler */
287  BX R2
288 
289  B .
290 
291  ALIGN
292 }
293 
304 __asm int32_t SH_DoCommand(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0)
305 {
306  BKPT 0xAB /*; Wait ICE or HardFault */
307  /*; ICE will step over BKPT directly
308  ; HardFault will step BKPT and the next line */
309  B SH_ICE
310 
311 SH_HardFault /*; Captured by HardFault */
312  MOVS R0, #0 /*; Set return value to 0 */
313  BX lr /*; Return */
314 
315 SH_ICE /*; Captured by ICE */
316  /*; Save return value */
317  CMP R2, #0
318  BEQ SH_End
319  STR R0, [R2] /*; Save the return value to *pn32Out_R0 */
320 
321 SH_End
322  MOVS R0, #1 /*; Set return value to 1 */
323  BX lr /*; Return */
324 }
325 #endif
326 
327 #else // ndef DEBUG_ENABLE_SEMIHOST
328 
329 /* Make sure won't goes here only because --gnu is defined , so
330  add !__CC_ARM and !__ICCARM__ checking */
331 # if defined ( __GNUC__ ) && !(__CC_ARM) && !(__ICCARM__)
332 
343 void HardFault_Handler(void)
344 {
345  asm("MOVS r0, #4 \n"
346  "MOV r1, LR \n"
347  "TST r0, r1 \n" /*; check LR bit 2 */
348  "BEQ 1f \n" /*; stack use MSP */
349  "MRS R0, PSP \n" /*; stack use PSP, read PSP */
350  "MOV R1, LR \n" /*; LR current value */
351  "B Hard_Fault_Handler \n"
352  "1: \n"
353  "MRS R0, MSP \n" /*; LR current value */
354  "B Hard_Fault_Handler \n"
355  ::[Hard_Fault_Handler] "r" (Hard_Fault_Handler) // input
356  );
357  while(1);
358 }
359 
360 # elif defined(__ICCARM__)
361 
362 void Get_LR_and_Branch(void)
363 {
364  asm("MOV R1, LR \n" /*; LR current value */
365  "B Hard_Fault_Handler \n"
366  );
367 }
368 
369 void Stack_Use_MSP(void)
370 {
371  asm("MRS R0, MSP \n" /*; read MSP */
372  "B Get_LR_and_Branch \n"
373  );
374 }
375 
386 void HardFault_Handler(void)
387 {
388  asm("MOVS r0, #4 \n"
389  "MOV r1, LR \n"
390  "TST r0, r1 \n" /*; check LR bit 2 */
391  "BEQ Stack_Use_MSP \n" /*; stack use MSP */
392  "MRS R0, PSP \n" /*; stack use PSP, read PSP */
393  "B Get_LR_and_Branch \n"
394  );
395 
396  while(1);
397 }
398 
399 # else
400 
411 __asm int32_t HardFault_Handler(void)
412 {
413  MOVS r0, #4
414  MOV r1, LR
415  TST r0, r1 /*; check LR bit 2 */
416  BEQ Stack_Use_MSP /*; stack use MSP */
417  MRS R0, PSP /*; stack use PSP, read PSP */
418  B Get_LR_and_Branch
419 Stack_Use_MSP
420  MRS R0, MSP /*; read MSP */
421 Get_LR_and_Branch
422  MOV R1, LR /*; LR current value */
423  LDR R2,=__cpp(Hard_Fault_Handler) /*; branch to Hard_Fault_Handler */
424  BX R2
425 }
426 
427 #endif
428 
429 #endif
430 
431 #ifndef DISABLE_UART
432 
441 #ifndef NONBLOCK_PRINTF
442 static void SendChar_ToUART(int ch)
443 {
444  while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);
445 
446  if(ch == '\n')
447  {
448  DEBUG_PORT->DAT = '\r';
449  while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);
450  }
451  DEBUG_PORT->DAT = ch;
452 }
453 
454 #else
455 /* Non-block implement of send char */
456 #define BUF_SIZE 2048
457 static void SendChar_ToUART(int ch)
458 {
459  static uint8_t u8Buf[BUF_SIZE] = {0};
460  static int32_t i32Head = 0;
461  static int32_t i32Tail = 0;
462  int32_t i32Tmp;
463 
464  /* Only flush the data in buffer to UART when ch == 0 */
465  if(ch)
466  {
467  /* Push char */
468  if(ch == '\n')
469  {
470  i32Tmp = i32Head+1;
471  if(i32Tmp > BUF_SIZE) i32Tmp = 0;
472  if(i32Tmp != i32Tail)
473  {
474  u8Buf[i32Head] = '\r';
475  i32Head = i32Tmp;
476  }
477  }
478 
479  i32Tmp = i32Head+1;
480  if(i32Tmp > BUF_SIZE) i32Tmp = 0;
481  if(i32Tmp != i32Tail)
482  {
483  u8Buf[i32Head] = ch;
484  i32Head = i32Tmp;
485  }
486  }
487  else
488  {
489  if(i32Tail == i32Head)
490  return;
491  }
492 
493  /* pop char */
494  do
495  {
496  i32Tmp = i32Tail + 1;
497  if(i32Tmp > BUF_SIZE) i32Tmp = 0;
498 
499  if((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk) == 0)
500  {
501  DEBUG_PORT->DAT = u8Buf[i32Tail];
502  i32Tail = i32Tmp;
503  }
504  else
505  break; /* FIFO full */
506  }while(i32Tail != i32Head);
507 }
508 #endif /* else for NONBLOCK_PRINTF */
509 
510 #endif /* if not def DISABLE_UART */
511 
521 static void SendChar(int ch)
522 {
523 #if defined(DEBUG_ENABLE_SEMIHOST)
524  g_buf[g_buf_len++] = ch;
525  g_buf[g_buf_len] = '\0';
526  if(g_buf_len + 1 >= sizeof(g_buf) || ch == '\n' || ch == '\0')
527  {
528  /* Send the char */
529  if(SH_DoCommand(0x04, (int)g_buf, NULL) != 0)
530  {
531  g_buf_len = 0;
532  return;
533  }
534  else
535  {
536 #ifndef DISABLE_UART
537  int i;
538 
539  for(i = 0; i < g_buf_len; i++)
540  SendChar_ToUART(g_buf[i]);
541 #endif
542  g_buf_len = 0;
543  }
544  }
545 #else
546 #ifndef DISABLE_UART
547  SendChar_ToUART(ch);
548 #endif
549 #endif
550 }
551 
561 static char GetChar(void)
562 {
563 #ifdef DEBUG_ENABLE_SEMIHOST
564 # if defined (__CC_ARM)
565  int nRet;
566  while(SH_DoCommand(0x101, 0, &nRet) != 0)
567  {
568  if(nRet != 0)
569  {
570  SH_DoCommand(0x07, 0, &nRet);
571  return (char)nRet;
572  }
573  }
574 # else
575  int nRet;
576  while(SH_DoCommand(0x7, 0, &nRet) != 0)
577  {
578  if(nRet != 0)
579  return (char)nRet;
580  }
581 # endif
582  return (0);
583 #else
584 #ifndef DISABLE_UART
585  while(1)
586  {
587  if((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk) == 0)
588  {
589  return (DEBUG_PORT->DAT);
590  }
591  }
592 #else
593  return 0;
594 #endif
595 #endif
596 }
597 
609 int kbhit(void)
610 {
611 #ifndef DISABLE_UART
612  return !((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk) == 0);
613 #else
614  return 0;
615 #endif
616 }
629 {
630 #ifndef DISABLE_UART
631  return ((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXEMPTYF_Msk) != 0);
632 #else
633  return 1;
634 #endif
635 }
636 
647 void _ttywrch(int ch)
648 {
649  SendChar(ch);
650  return;
651 }
652 
653 
672 int fputc(int ch, FILE *stream)
673 {
674  SendChar(ch);
675  return ch;
676 }
677 
678 #if defined (__GNUC__) && !defined(__ARMCC_VERSION)
679 
680 int _write (int fd, char *ptr, int len)
681 {
682  int i = len;
683 
684  while(i--)
685  {
686  while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);
687 
688  if(*ptr == '\n')
689  {
690  DEBUG_PORT->DAT = '\r';
691  while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);
692  }
693 
694  DEBUG_PORT->DAT = *ptr++;
695 
696  }
697  return len;
698 }
699 
700 int _read (int fd, char *ptr, int len)
701 {
702 
703  while((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk) != 0);
704  *ptr = DEBUG_PORT->DAT;
705  return 1;
706 
707 
708 }
709 
710 #else
711 
722 int fgetc(FILE *stream)
723 {
724  return (GetChar());
725 }
726 
742 int ferror(FILE *stream)
743 {
744  return EOF;
745 }
746 #endif
747 #ifdef DEBUG_ENABLE_SEMIHOST
748 # ifdef __ICCARM__
749 void __exit(int return_code)
750 {
751 
752  /* Check if link with ICE */
753  if(SH_DoCommand(0x18, 0x20026, NULL) == 0)
754  {
755  /* Make sure all message is print out */
756  while(IsDebugFifoEmpty() == 0);
757  }
758 label:
759  goto label; /* endless loop */
760 }
761 # else
762 void _sys_exit(int return_code)
763 {
764 
765  /* Check if link with ICE */
766  if(SH_DoCommand(0x18, 0x20026, NULL) == 0)
767  {
768  /* Make sure all message is print out */
769  while(IsDebugFifoEmpty() == 0);
770  }
771 label:
772  goto label; /* endless loop */
773 }
774 # endif
775 #endif
int IsDebugFifoEmpty(void)
Check if debug message finished.
Definition: retarget.c:628
__asm int32_t HardFault_Handler(void)
This HardFault handler is implemented to show r0, r1, r2, r3, r12, lr, pc, psr.
Definition: retarget.c:411
void _ttywrch(int ch)
C library retargetting.
Definition: retarget.c:647
static void SendChar(int ch)
Routine to send a char.
Definition: retarget.c:521
#define DEBUG_PORT
Definition: retarget.c:30
Definition: retarget.c:51
NuMicro peripheral access layer header file.
void Hard_Fault_Handler(uint32_t stack[])
Hard fault handler.
Definition: retarget.c:77
int fputc(int ch, FILE *stream)
Write character to stream.
Definition: retarget.c:672
int ferror(FILE *stream)
Check error indicator.
Definition: retarget.c:742
Definition: retarget.c:51
int kbhit(void)
Check any char input from UART.
Definition: retarget.c:609
Definition: retarget.c:51
Definition: retarget.c:51
int handle
Definition: retarget.c:38
Definition: retarget.c:51
static void stackDump(uint32_t stack[])
Helper function to dump register while hard fault occurred.
Definition: retarget.c:59
static char GetChar(void)
Routine to get a char.
Definition: retarget.c:561
Definition: retarget.c:51
#define UART_FIFOSTS_TXEMPTYF_Msk
Definition: uart_reg.h:2003
FILE __stdout
Definition: retarget.c:47
#define UART_FIFOSTS_RXEMPTY_Msk
Definition: uart_reg.h:1985
Definition: retarget.c:51
static void SendChar_ToUART(int ch)
Routine to send a char.
Definition: retarget.c:442
return value
Definition: semihosting.h:98
#define NULL
NULL pointer.
Definition: M480.h:604
Definition: retarget.c:51
FILE __stdin
Definition: retarget.c:48
int fgetc(FILE *stream)
Get character from UART debug port or semihosting input.
Definition: retarget.c:722
#define UART_FIFOSTS_TXFULL_Msk
Definition: uart_reg.h:1997