M480 BSP V3.0.7000
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#ifndef __WEAK
15 #define __WEAK __attribute__((weak))
16#endif
17
18#if(defined(__ICCARM__) && (__VER__ >= 9020000))
19#include <LowLevelIOInterface.h>
20#endif
21
22#if defined (__ICCARM__)
23#pragma diag_suppress=Pm150
24#endif
25
26#if defined ( __CC_ARM )
27#if (__ARMCC_VERSION < 400000)
28#else
29/* Insist on keeping widthprec, to avoid X propagation by benign code in C-lib */
30#pragma import _printf_widthprec
31#endif
32#endif
33
34/* Uncomment this line to disable all printf and getchar. getchar() will always return 0x00*/
35/* #define DISABLE_UART */
36
37#if defined(DEBUG_ENABLE_SEMIHOST)
38 #ifndef DISABLE_UART
39 #define DISABLE_UART
40 #endif
41#endif
42
43
44#define DEBUG_PORT UART0
45
46/*---------------------------------------------------------------------------------------------------------*/
47/* Global variables */
48/*---------------------------------------------------------------------------------------------------------*/
49#if (defined(__ARMCC_VERSION) && (__ARMCC_VERSION < 6040000)) || (defined(__ICCARM__) && (__VER__ >= 8000000))
50struct __FILE { int handle; /* Add whatever you need here */ };
51#endif
52
55
56int kbhit(void);
57int IsDebugFifoEmpty(void);
58void _ttywrch(int ch);
59
60char GetChar(void);
61void SendChar_ToUART(int ch);
62void SendChar(int ch);
63
64#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
65# ifdef __MICROLIB
66
67__WEAK __NO_RETURN
68void __aeabi_assert(const char* expr, const char* file, int line)
69{
70 char str[12], * p;
71
72 fputs("*** assertion failed: ", stderr);
73 fputs(expr, stderr);
74 fputs(", file ", stderr);
75 fputs(file, stderr);
76 fputs(", line ", stderr);
77
78 p = str + sizeof(str);
79 *--p = '\0';
80 *--p = '\n';
81 while(line > 0)
82 {
83 *--p = '0' + (line % 10);
84 line /= 10;
85 }
86 fputs(p, stderr);
87
88 for(;;);
89}
90
91
93void abort(void)
94{
95 for(;;);
96}
97
98# else
99__asm(" .global __ARM_use_no_argv\n");
100__asm(" .global __use_no_semihosting\n");
101
102
103FILE __stdout;
104FILE __stdin;
105FILE __stderr;
106
107void _sys_exit(int return_code)__attribute__((noreturn));
108void _sys_exit(int return_code)
109{
110 (void) return_code;
111 while(1);
112}
113
114# endif
115#endif // defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
116
117/*---------------------------------------------------------------------------------------------------------*/
118/* Routine to write a char */
119/*---------------------------------------------------------------------------------------------------------*/
120#if defined(__ICCARM__)
121#ifndef DEBUG_ENABLE_SEMIHOST
122size_t __write(int handle, const unsigned char *buf, size_t bufSize)
123{
124 size_t nChars = 0;
125
126 /* Check for the command to flush all handles */
127 if (handle == -1)
128 {
129 return 0;
130 }
131
132 /* Check for stdout and stderr (only necessary if FILE descriptors are enabled.) */
133
134 if (handle != 1 && handle != 2)
135 {
136 return -1;
137 }
138
139 for (/* Empty */; bufSize > 0; --bufSize)
140 {
141 SendChar(*buf);
142 ++buf;
143 ++nChars;
144 }
145
146 return nChars;
147}
148
149size_t __read(int handle, unsigned char* buf, size_t bufSize)
150{
151 size_t nChars = 0;
152 /* Check for stdin (only necessary if FILE descriptors are enabled) */
153 if(handle != 0)
154 {
155 return -1;
156 }
157
158 for( ; bufSize > 0; --bufSize)
159 {
160 unsigned char c;
161 c = GetChar();
162 if(c == 0)
163 break;
164 *buf++ = c;
165 ++nChars;
166 }
167 return nChars;
168}
169#endif /* ndef DEBUG_ENABLE_SEMIHOST */
170#endif /* defined(__ICCARM__) */
171
172#if (defined(__ARMCC_VERSION) || defined(__ICCARM__))
173extern int32_t SH_DoCommand(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0);
174
175int fgetc(FILE* stream);
176int fputc(int ch, FILE* stream);
177int ferror(FILE* stream);
178__WEAK
179uint32_t ProcessHardFault(uint32_t lr, uint32_t msp, uint32_t psp);
180#endif
181
182#if defined(DEBUG_ENABLE_SEMIHOST)
183/* The static buffer is used to speed up the semihost */
184static char g_buf[16];
185static char g_buf_len = 0;
186static volatile int32_t g_ICE_Conneced = 1;
187
188void _sys_exit(int return_code)__attribute__((noreturn));
189
190uint32_t ProcessHardFault(uint32_t lr, uint32_t msp, uint32_t psp)
191{
192 uint32_t *sp = NULL;
193 uint32_t inst;
194
195 /* Check the used stack */
196 if(lr & 0x40)
197 {
198 /* Secure stack used */
199 if(lr & 4)
200 sp = (uint32_t *)psp;
201 else
202 sp = (uint32_t *)msp;
203
204 }
205#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
206 else
207 {
208 /* Non-secure stack used */
209 if(lr & 4)
210 sp = (uint32_t *)__TZ_get_PSP_NS();
211 else
212 sp = (uint32_t *)__TZ_get_MSP_NS();
213
214 }
215#endif
216
217 /* Get the instruction caused the hardfault */
218 if( sp != NULL )
219 inst = M16(sp[6]);
220
221
222 if(inst == 0xBEAB)
223 {
224 /*
225 If the instruction is 0xBEAB, it means it is caused by BKPT without ICE connected.
226 We still return for output/input message to UART.
227 */
228 g_ICE_Conneced = 0; // Set a flag for ICE offline
229 sp[6] += 2; // return to next instruction
230 return lr; // Keep lr in R0
231 }
232
233 /* It is casued by hardfault (Not semihost). Just process the hard fault here. */
234 /* TODO: Implement your hardfault handle code here */
235
236 /*
237 printf(" HardFault!\n\n");
238 printf("r0 = 0x%x\n", sp[0]);
239 printf("r1 = 0x%x\n", sp[1]);
240 printf("r2 = 0x%x\n", sp[2]);
241 printf("r3 = 0x%x\n", sp[3]);
242 printf("r12 = 0x%x\n", sp[4]);
243 printf("lr = 0x%x\n", sp[5]);
244 printf("pc = 0x%x\n", sp[6]);
245 printf("psr = 0x%x\n", sp[7]);
246 */
247
248 while(1) {}
249
250}
251
263int32_t SH_Return(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0)
264{
265 if(g_ICE_Conneced)
266 {
267 if(pn32Out_R0)
268 *pn32Out_R0 = n32In_R0;
269
270 return 1;
271 }
272 return 0;
273}
274
275#else /* ndef (DEBUG_ENABLE_SEMIHOST) */
276
277int32_t SH_Return(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0);
278
290__WEAK uint32_t ProcessHardFault(uint32_t lr, uint32_t msp, uint32_t psp)
291{
292 uint32_t *sp = NULL;
293 uint32_t inst, addr, taddr, tdata;
294 int32_t secure;
295 uint32_t rm, rn, rt, imm5, imm8;
296
297 /* It is casued by hardfault. Just process the hard fault */
298 /* TODO: Implement your hardfault handle code here */
299
300
301 /* Check the used stack */
302 secure = (lr & 0x40ul) ? 1 : 0;
303 if(secure)
304 {
305 /* Secure stack used */
306 if(lr & 4UL)
307 {
308 sp = (uint32_t *)psp;
309 }
310 else
311 {
312 sp = (uint32_t *)msp;
313 }
314
315 }
316#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3)
317 else
318 {
319 /* Non-secure stack used */
320 if(lr & 4)
321 sp = (uint32_t *)(__TZ_get_PSP_NS());
322 else
323 sp = (uint32_t *)(__TZ_get_MSP_NS());
324
325 }
326#endif
327
328 /*
329 r0 = sp[0]
330 r1 = sp[1]
331 r2 = sp[2]
332 r3 = sp[3]
333 r12 = sp[4]
334 lr = sp[5]
335 pc = sp[6]
336 psr = sp[7]
337 */
338
339 printf("HardFault @ 0x%08x\n", sp[6]);
340 /* Get the instruction caused the hardfault */
341 if( sp != NULL )
342 {
343 addr = sp[6];
344 inst = M16(addr);
345 }
346
347 printf("HardFault Analysis:\n");
348
349 printf("Instruction code = %x\n", inst);
350
351 if(inst == 0xBEAB)
352 {
353 printf("Execute BKPT without ICE connected\n");
354 }
355 else if((inst >> 12) == 5)
356 {
357 /* 0101xx Load/store (register offset) on page C2-327 of armv8m ref */
358 rm = (inst >> 6) & 0x7;
359 rn = (inst >> 3) & 0x7;
360 rt = inst & 0x7;
361
362 printf("LDR/STR rt=%x rm=%x rn=%x\n", rt, rm, rn);
363 taddr = sp[rn] + sp[rm];
364 tdata = sp[rt];
365 printf("[0x%08x] 0x%04x %s 0x%x [0x%x]\n", addr, inst,
366 (inst & BIT11) ? "LDR" : "STR", tdata, taddr);
367
368 }
369 else if((inst >> 13) == 3)
370 {
371 /* 011xxx Load/store word/byte (immediate offset) on page C2-327 of armv8m ref */
372 imm5 = (inst >> 6) & 0x1f;
373 rn = (inst >> 3) & 0x7;
374 rt = inst & 0x7;
375
376 printf("LDR/STR rt=%x rn=%x imm5=%x\n", rt, rn, imm5);
377 taddr = sp[rn] + imm5;
378 tdata = sp[rt];
379 printf("[0x%08x] 0x%04x %s 0x%x [0x%x]\n", addr, inst,
380 (inst & BIT11) ? "LDR" : "STR", tdata, taddr);
381 }
382 else if((inst >> 12) == 8)
383 {
384 /* 1000xx Load/store halfword (immediate offset) on page C2-328 */
385 imm5 = (inst >> 6) & 0x1f;
386 rn = (inst >> 3) & 0x7;
387 rt = inst & 0x7;
388
389 printf("LDRH/STRH rt=%x rn=%x imm5=%x\n", rt, rn, imm5);
390 taddr = sp[rn] + imm5;
391 tdata = sp[rt];
392 printf("[0x%08x] 0x%04x %s 0x%x [0x%x]\n", addr, inst,
393 (inst & BIT11) ? "LDR" : "STR", tdata, taddr);
394
395 }
396 else if((inst >> 12) == 9)
397 {
398 /* 1001xx Load/store (SP-relative) on page C2-328 */
399 imm8 = inst & 0xff;
400 rt = (inst >> 8) & 0x7;
401
402 printf("LDRH/STRH rt=%x imm8=%x\n", rt, imm8);
403 taddr = sp[6] + imm8;
404 tdata = sp[rt];
405 printf("[0x%08x] 0x%04x %s 0x%x [0x%x]\n", addr, inst,
406 (inst & BIT11) ? "LDR" : "STR", tdata, taddr);
407 }
408 else
409 {
410 printf("Unexpected instruction\n");
411 }
412
413 /* Or *sp to remove compiler warning */
414 while(1U | *sp) {}
415
416 return lr;
417}
418
419int32_t SH_Return(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0)
420{
421 return 0;
422}
423
424#endif /* defined(DEBUG_ENABLE_SEMIHOST) */
425
426
427#ifndef DISABLE_UART
437#ifndef NONBLOCK_PRINTF
438void SendChar_ToUART(int ch)
439{
440 while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);
441
442 if(ch == '\n')
443 {
444 DEBUG_PORT->DAT = '\r';
445 while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);
446 }
447 DEBUG_PORT->DAT = ch;
448}
449#else
450/* Non-block implement of send char */
451#define BUF_SIZE 2048
452static void SendChar_ToUART(int ch)
453{
454 static uint8_t u8Buf[BUF_SIZE] = {0};
455 static int32_t i32Head = 0;
456 static int32_t i32Tail = 0;
457 int32_t i32Tmp;
458
459 /* Only flush the data in buffer to UART when ch == 0 */
460 if(ch)
461 {
462 /* Push char */
463 if(ch == '\n')
464 {
465 i32Tmp = i32Head+1;
466 if(i32Tmp > BUF_SIZE) i32Tmp = 0;
467 if(i32Tmp != i32Tail)
468 {
469 u8Buf[i32Head] = '\r';
470 i32Head = i32Tmp;
471 }
472 }
473
474 i32Tmp = i32Head+1;
475 if(i32Tmp > BUF_SIZE) i32Tmp = 0;
476 if(i32Tmp != i32Tail)
477 {
478 u8Buf[i32Head] = ch;
479 i32Head = i32Tmp;
480 }
481 }
482 else
483 {
484 if(i32Tail == i32Head)
485 return;
486 }
487
488 /* pop char */
489 do
490 {
491 i32Tmp = i32Tail + 1;
492 if(i32Tmp > BUF_SIZE) i32Tmp = 0;
493
494 if((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk) == 0)
495 {
496 DEBUG_PORT->DAT = u8Buf[i32Tail];
497 i32Tail = i32Tmp;
498 }
499 else
500 break; /* FIFO full */
501 }while(i32Tail != i32Head);
502}
503#endif /* else for NONBLOCK_PRINTF */
504#endif /* if not def DISABLE_UART */
505
515void SendChar(int ch)
516{
517#if defined(DEBUG_ENABLE_SEMIHOST)
518 g_buf[g_buf_len++] = ch;
519 g_buf[g_buf_len] = '\0';
520 if(g_buf_len + 1 >= sizeof(g_buf) || ch == '\n' || ch == '\0')
521 {
522 /* Send the char */
523 if(g_ICE_Conneced)
524 {
525 if(SH_DoCommand(0x04, (int)g_buf, NULL) != 0)
526 {
527 g_buf_len = 0;
528 return;
529 }
530 }
531 else
532 {
533# if (DEBUG_ENABLE_SEMIHOST == 2) // Re-direct to UART Debug Port only when DEBUG_ENABLE_SEMIHOST=2
534 int i;
535 for(i = 0; i < g_buf_len; i++)
536 SendChar_ToUART(g_buf[i]);
537 g_buf_len = 0;
538# endif
539 }
540 }
541#else
542
543#ifndef DISABLE_UART
544 SendChar_ToUART(ch);
545#endif
546
547#endif
548}
549
559char GetChar(void)
560{
561#ifdef DEBUG_ENABLE_SEMIHOST
562
563 int nRet;
564
565# if defined (__ICCARM__)
566 while(SH_DoCommand(0x7, 0, &nRet) != 0)
567 {
568 if(nRet != 0)
569 return (char)nRet;
570 }
571# else
572 while(SH_DoCommand(0x101, 0, &nRet) != 0)
573 {
574 if(nRet != 0)
575 {
576 SH_DoCommand(0x07, 0, &nRet);
577 return (char)nRet;
578 }
579 }
580# endif
581
582# if (DEBUG_ENABLE_SEMIHOST == 2) // Re-direct to UART Debug Port only when DEBUG_ENABLE_SEMIHOST=2
583 /* Use debug port when ICE is not connected at semihost mode */
584 while(!g_ICE_Conneced)
585 {
586 if((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk) == 0)
587 {
588 return (DEBUG_PORT->DAT);
589 }
590 }
591# endif
592
593 return (0);
594#else
595
596#ifndef DISABLE_UART
597 while(1)
598 {
599 if((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk) == 0)
600 {
601 return (DEBUG_PORT->DAT);
602 }
603 }
604#else
605 return 0;
606#endif
607
608#endif
609}
610
622int kbhit(void)
623{
624#ifndef DISABLE_UART
625 return !((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk) == 0);
626#else
627 return 1;
628#endif
629}
642{
643#ifndef DISABLE_UART
644 return ((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXEMPTYF_Msk) != 0);
645#else
646 return 1;
647#endif
648}
649
660void _ttywrch(int ch)
661{
662 SendChar(ch);
663 return;
664}
665
666
685int fputc(int ch, FILE *stream)
686{
687 (void)stream;
688 SendChar(ch);
689 return ch;
690}
691
692
693#if defined (__GNUC__) && !defined(__ARMCC_VERSION)
694#if !defined(OS_USE_SEMIHOSTING)
695int _write(int fd, char *ptr, int len)
696{
697 int i = len;
698 while(i--)
699 {
700 if(*ptr == '\n')
701 {
702 while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);
703 DEBUG_PORT->DAT = '\r';
704 }
705
706 while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);
707 DEBUG_PORT->DAT = *ptr++;
708 }
709 return len;
710}
711
712int _read(int fd, char *ptr, int len)
713{
714
715 while((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk) != 0);
716 *ptr = DEBUG_PORT->DAT;
717 return 1;
718
719
720}
721/* Add implementations to fix linker warnings from the newlib-nano C library in VSCode-GCC14.3.1 */
722#include <sys/stat.h>
723int _close(int file)
724{
725 return -1;
726}
727int _lseek(int file, int ptr, int dir)
728{
729 return 0;
730}
731int _fstat(int file, struct stat *st)
732{
733 st->st_mode = S_IFCHR;
734 return 0;
735}
736int _isatty(int file)
737{
738 return 1;
739}
740int _kill(int pid, int sig)
741{
742 return -1;
743}
744int _getpid(void)
745{
746 return 1;
747}
748
749int _open(int file)
750{
751 return -1;
752}
753int _unlink(const char *path)
754{
755 return -1;
756}
757
758#endif
759
760#else
761
773int fgetc(FILE *stream)
774{
775 (void)stream;
776 return ((int)GetChar());
777}
778
794int ferror(FILE *stream)
795{
796 (void)stream;
797 return EOF;
798}
799
800#endif
801
802
803#ifdef DEBUG_ENABLE_SEMIHOST
804
805# ifdef __ICCARM__
806void __exit(int return_code)
807{
808 /* Check if link with ICE */
809 if(SH_DoCommand(0x18, 0x20026, NULL) == 0)
810 {
811 /* Make sure all message is print out */
812 while(IsDebugFifoEmpty() == 0);
813 }
814label:
815 goto label; /* endless loop */
816}
817# else
818void _sys_exit(int return_code)
819{
820 (void)return_code;
821 /* Check if link with ICE */
822 if(SH_DoCommand(0x18, 0x20026, NULL) == 0)
823 {
824 /* Make sure all message is print out */
825 while(IsDebugFifoEmpty() == 0);
826 }
827label:
828 goto label; /* endless loop */
829}
830# endif // ifdef __ICCARM__
831
832#endif /* ifdef DEBUG_ENABLE_SEMIHOST */
void *__dso_handle __attribute__((weak))
Definition: _syscalls.c:35
NuMicro peripheral access layer header file.
#define M16(addr)
Get a 16-bit unsigned value from specified address.
Definition: M480.h:485
#define NULL
NULL pointer.
Definition: M480.h:605
#define BIT11
Bit 11 mask of an 32 bit integer.
Definition: M480.h:626
#define UART_FIFOSTS_TXFULL_Msk
Definition: uart_reg.h:2000
#define UART_FIFOSTS_TXEMPTYF_Msk
Definition: uart_reg.h:2006
#define UART_FIFOSTS_RXEMPTY_Msk
Definition: uart_reg.h:1988
int32_t SH_Return(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0)
Definition: retarget.c:419
void _ttywrch(int ch)
C library retargetting.
Definition: retarget.c:660
int fputc(int ch, FILE *stream)
Write character to stream.
Definition: retarget.c:685
int ferror(FILE *stream)
Check error indicator.
Definition: retarget.c:794
int IsDebugFifoEmpty(void)
Check if debug message finished.
Definition: retarget.c:641
void SendChar_ToUART(int ch)
Routine to send a char.
Definition: retarget.c:438
__WEAK uint32_t ProcessHardFault(uint32_t lr, uint32_t msp, uint32_t psp)
This function is called by Hardfault handler.
Definition: retarget.c:290
int kbhit(void)
Check any char input from UART.
Definition: retarget.c:622
int fgetc(FILE *stream)
Get character from UART debug port or semihosting input.
Definition: retarget.c:773
FILE __stdin
Definition: retarget.c:54
void SendChar(int ch)
Routine to send a char.
Definition: retarget.c:515
FILE __stdout
Definition: retarget.c:53
#define __WEAK
Definition: retarget.c:15
char GetChar(void)
Routine to get a char.
Definition: retarget.c:559
#define DEBUG_PORT
Definition: retarget.c:44
@ lr
Definition: retarget_iap.c:41