NUC472_NUC442_BSP V3.04.000
The Board Support Package for NUC472/NUC442
retarget.c
Go to the documentation of this file.
1/**************************************************************************/
11#include <stdio.h>
12#include "NUC472_442.h"
13
14#ifndef __WEAK
15 #define __WEAK __attribute__((weak))
16#endif
17#ifndef __NO_RETURN
18 #define __NO_RETURN __attribute__((noreturn))
19#endif
20
21#if(defined(__ICCARM__) && (__VER__ >= 9020000))
22#include <LowLevelIOInterface.h>
23#endif
24
25#if defined (__ICCARM__)
26#pragma diag_suppress=Pm150
27#endif
28
29#if defined ( __CC_ARM )
30#if (__ARMCC_VERSION < 400000)
31#else
32/* Insist on keeping widthprec, to avoid X propagation by benign code in C-lib */
33#pragma import _printf_widthprec
34#endif
35#endif
36
37/* Uncomment this line to disable all printf and getchar. getchar() will always return 0x00*/
38/* #define DISABLE_UART */
39
40#if defined(DEBUG_ENABLE_SEMIHOST)
41 #ifndef DISABLE_UART
42 #define DISABLE_UART
43 #endif
44#endif
45
46
47#define DEBUG_PORT UART0
48
49/*---------------------------------------------------------------------------------------------------------*/
50/* Global variables */
51/*---------------------------------------------------------------------------------------------------------*/
52#if (defined(__ARMCC_VERSION) && (__ARMCC_VERSION < 6040000)) || (defined(__ICCARM__) && (__VER__ >= 8000000))
53struct __FILE { int handle; /* Add whatever you need here */ };
54#endif
55
58
59int kbhit(void);
60int IsDebugFifoEmpty(void);
61void _ttywrch(int ch);
62
63char GetChar(void);
64void SendChar_ToUART(int ch);
65void SendChar(int ch);
66
67#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
68# ifdef __MICROLIB
69
71void __aeabi_assert(const char* expr, const char* file, int line)
72{
73 char str[12], * p;
74
75 fputs("*** assertion failed: ", stderr);
76 fputs(expr, stderr);
77 fputs(", file ", stderr);
78 fputs(file, stderr);
79 fputs(", line ", stderr);
80
81 p = str + sizeof(str);
82 *--p = '\0';
83 *--p = '\n';
84 while(line > 0)
85 {
86 *--p = '0' + (line % 10);
87 line /= 10;
88 }
89 fputs(p, stderr);
90
91 for(;;);
92}
93
94
96void abort(void)
97{
98 for(;;);
99}
100
101# else
102__asm(" .global __ARM_use_no_argv\n");
103__asm(" .global __use_no_semihosting\n");
104
105
106FILE __stdout;
107FILE __stdin;
108FILE __stderr;
109
110void _sys_exit(int return_code)__attribute__((noreturn));
111void _sys_exit(int return_code)
112{
113 (void) return_code;
114 while(1);
115}
116
117# endif
118#endif // defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
119
120/*---------------------------------------------------------------------------------------------------------*/
121/* Routine to write a char */
122/*---------------------------------------------------------------------------------------------------------*/
123#if defined(__ICCARM__)
124#ifndef DEBUG_ENABLE_SEMIHOST
125size_t __write(int handle, const unsigned char *buf, size_t bufSize)
126{
127 size_t nChars = 0;
128
129 /* Check for the command to flush all handles */
130 if (handle == -1)
131 {
132 return 0;
133 }
134
135 /* Check for stdout and stderr (only necessary if FILE descriptors are enabled.) */
136
137 if (handle != 1 && handle != 2)
138 {
139 return -1;
140 }
141
142 for (/* Empty */; bufSize > 0; --bufSize)
143 {
144 SendChar(*buf);
145 ++buf;
146 ++nChars;
147 }
148
149 return nChars;
150}
151
152size_t __read(int handle, unsigned char* buf, size_t bufSize)
153{
154 size_t nChars = 0;
155 /* Check for stdin (only necessary if FILE descriptors are enabled) */
156 if(handle != 0)
157 {
158 return -1;
159 }
160
161 for( ; bufSize > 0; --bufSize)
162 {
163 unsigned char c;
164 c = GetChar();
165 if(c == 0)
166 break;
167 *buf++ = c;
168 ++nChars;
169 }
170 return nChars;
171}
172#endif /* ndef DEBUG_ENABLE_SEMIHOST */
173#endif /* defined(__ICCARM__) */
174
175#if (defined(__ARMCC_VERSION) || defined(__ICCARM__))
176extern int32_t SH_DoCommand(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0);
177int fgetc(FILE* stream);
178int fputc(int ch, FILE* stream);
179int ferror(FILE* stream);
180__WEAK
181uint32_t ProcessHardFault(uint32_t lr, uint32_t msp, uint32_t psp);
182#endif
183
184#if defined(DEBUG_ENABLE_SEMIHOST)
185/* The static buffer is used to speed up the semihost */
186static char g_buf[16];
187static char g_buf_len = 0;
188static volatile int32_t g_ICE_Conneced = 1;
189
190void _sys_exit(int return_code)__attribute__((noreturn));
191
192uint32_t ProcessHardFault(uint32_t lr, uint32_t msp, uint32_t psp)
193{
194 uint32_t *sp = NULL;
195 uint32_t inst;
196
197 /* Check the used stack */
198 if(lr & 0x40)
199 {
200 /* Secure stack used */
201 if(lr & 4)
202 sp = (uint32_t *)psp;
203 else
204 sp = (uint32_t *)msp;
205
206 }
207#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
208 else
209 {
210 /* Non-secure stack used */
211 if(lr & 4)
212 sp = (uint32_t *)__TZ_get_PSP_NS();
213 else
214 sp = (uint32_t *)__TZ_get_MSP_NS();
215
216 }
217#endif
218
219 /* Get the instruction caused the hardfault */
220 if( sp != NULL )
221 inst = M16(sp[6]);
222
223
224 if(inst == 0xBEAB)
225 {
226 /*
227 If the instruction is 0xBEAB, it means it is caused by BKPT without ICE connected.
228 We still return for output/input message to UART.
229 */
230 g_ICE_Conneced = 0; // Set a flag for ICE offline
231 sp[6] += 2; // return to next instruction
232 return lr; // Keep lr in R0
233 }
234
235 /* It is casued by hardfault (Not semihost). Just process the hard fault here. */
236 /* TODO: Implement your hardfault handle code here */
237
238
239 printf(" HardFault!\n\n");
240 printf("r0 = 0x%x\n", sp[0]);
241 printf("r1 = 0x%x\n", sp[1]);
242 printf("r2 = 0x%x\n", sp[2]);
243 printf("r3 = 0x%x\n", sp[3]);
244 printf("r12 = 0x%x\n", sp[4]);
245 printf("lr = 0x%x\n", sp[5]);
246 printf("pc = 0x%x\n", sp[6]);
247 printf("psr = 0x%x\n", sp[7]);
248
249
250 while(1) {}
251
252}
253
265int32_t SH_Return(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0)
266{
267 if(g_ICE_Conneced)
268 {
269 if(pn32Out_R0)
270 *pn32Out_R0 = n32In_R0;
271
272 return 1;
273 }
274 return 0;
275}
276
277#else /* ndef (DEBUG_ENABLE_SEMIHOST) */
278
290 int32_t SH_Return(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0);
291
292__WEAK uint32_t ProcessHardFault(uint32_t lr, uint32_t msp, uint32_t psp)
293{
294 uint32_t *sp = NULL;
295 uint32_t inst, addr, taddr, tdata;
296 int32_t secure;
297 uint32_t rm, rn, rt, imm5, imm8;
298
299 /* It is casued by hardfault. Just process the hard fault */
300 /* TODO: Implement your hardfault handle code here */
301
302
303 /* Check the used stack */
304 secure = (lr & 0x40ul) ? 1 : 0;
305 if(secure)
306 {
307 /* Secure stack used */
308 if(lr & 4UL)
309 {
310 sp = (uint32_t *)psp;
311 }
312 else
313 {
314 sp = (uint32_t *)msp;
315 }
316
317 }
318#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3)
319 else
320 {
321 /* Non-secure stack used */
322 if(lr & 4)
323 sp = (uint32_t *)(__TZ_get_PSP_NS());
324 else
325 sp = (uint32_t *)(__TZ_get_MSP_NS());
326
327 }
328#endif
329
330 /*
331 r0 = sp[0]
332 r1 = sp[1]
333 r2 = sp[2]
334 r3 = sp[3]
335 r12 = sp[4]
336 lr = sp[5]
337 pc = sp[6]
338 psr = sp[7]
339 */
340
341 printf("HardFault @ 0x%08x\n", sp[6]);
342 /* Get the instruction caused the hardfault */
343 if( sp != NULL )
344 {
345 addr = sp[6];
346 inst = M16(addr);
347 }
348
349 printf("HardFault Analysis:\n");
350
351 printf("Instruction code = %x\n", inst);
352
353 if(inst == 0xBEAB)
354 {
355 printf("Execute BKPT without ICE connected\n");
356 }
357 else if((inst >> 12) == 5)
358 {
359 /* 0101xx Load/store (register offset) on page C2-327 of armv8m ref */
360 rm = (inst >> 6) & 0x7;
361 rn = (inst >> 3) & 0x7;
362 rt = inst & 0x7;
363
364 printf("LDR/STR rt=%x rm=%x rn=%x\n", rt, rm, rn);
365 taddr = sp[rn] + sp[rm];
366 tdata = sp[rt];
367 printf("[0x%08x] 0x%04x %s 0x%x [0x%x]\n", addr, inst,
368 (inst & BIT11) ? "LDR" : "STR", tdata, taddr);
369
370 }
371 else if((inst >> 13) == 3)
372 {
373 /* 011xxx Load/store word/byte (immediate offset) on page C2-327 of armv8m ref */
374 imm5 = (inst >> 6) & 0x1f;
375 rn = (inst >> 3) & 0x7;
376 rt = inst & 0x7;
377
378 printf("LDR/STR rt=%x rn=%x imm5=%x\n", rt, rn, imm5);
379 taddr = sp[rn] + imm5;
380 tdata = sp[rt];
381 printf("[0x%08x] 0x%04x %s 0x%x [0x%x]\n", addr, inst,
382 (inst & BIT11) ? "LDR" : "STR", tdata, taddr);
383 }
384 else if((inst >> 12) == 8)
385 {
386 /* 1000xx Load/store halfword (immediate offset) on page C2-328 */
387 imm5 = (inst >> 6) & 0x1f;
388 rn = (inst >> 3) & 0x7;
389 rt = inst & 0x7;
390
391 printf("LDRH/STRH rt=%x rn=%x imm5=%x\n", rt, rn, imm5);
392 taddr = sp[rn] + imm5;
393 tdata = sp[rt];
394 printf("[0x%08x] 0x%04x %s 0x%x [0x%x]\n", addr, inst,
395 (inst & BIT11) ? "LDR" : "STR", tdata, taddr);
396
397 }
398 else if((inst >> 12) == 9)
399 {
400 /* 1001xx Load/store (SP-relative) on page C2-328 */
401 imm8 = inst & 0xff;
402 rt = (inst >> 8) & 0x7;
403
404 printf("LDRH/STRH rt=%x imm8=%x\n", rt, imm8);
405 taddr = sp[6] + imm8;
406 tdata = sp[rt];
407 printf("[0x%08x] 0x%04x %s 0x%x [0x%x]\n", addr, inst,
408 (inst & BIT11) ? "LDR" : "STR", tdata, taddr);
409 }
410 else
411 {
412 printf("Unexpected instruction\n");
413 }
414
415 /* Or *sp to remove compiler warning */
416 while(1U | *sp) {}
417
418 return lr;
419}
420
421int32_t SH_Return(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0)
422{
423 return 0;
424}
425
426#endif /* defined(DEBUG_ENABLE_SEMIHOST) */
427
428
429#ifndef DISABLE_UART
439#ifndef NONBLOCK_PRINTF
440void SendChar_ToUART(int ch)
441{
442 while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);
443
444 if(ch == '\n')
445 {
446 DEBUG_PORT->DAT = '\r';
447 while(DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk);
448 }
449 DEBUG_PORT->DAT = ch;
450}
451#else
452/* Non-block implement of send char */
453#define BUF_SIZE 2048
454static void SendChar_ToUART(int ch)
455{
456 static uint8_t u8Buf[BUF_SIZE] = {0};
457 static int32_t i32Head = 0;
458 static int32_t i32Tail = 0;
459 int32_t i32Tmp;
460
461 /* Only flush the data in buffer to UART when ch == 0 */
462 if(ch)
463 {
464 /* Push char */
465 if(ch == '\n')
466 {
467 i32Tmp = i32Head+1;
468 if(i32Tmp > BUF_SIZE) i32Tmp = 0;
469 if(i32Tmp != i32Tail)
470 {
471 u8Buf[i32Head] = '\r';
472 i32Head = i32Tmp;
473 }
474 }
475
476 i32Tmp = i32Head+1;
477 if(i32Tmp > BUF_SIZE) i32Tmp = 0;
478 if(i32Tmp != i32Tail)
479 {
480 u8Buf[i32Head] = ch;
481 i32Head = i32Tmp;
482 }
483 }
484 else
485 {
486 if(i32Tail == i32Head)
487 return;
488 }
489
490 /* pop char */
491 do
492 {
493 i32Tmp = i32Tail + 1;
494 if(i32Tmp > BUF_SIZE) i32Tmp = 0;
495
496 if((DEBUG_PORT->FIFOSTS & UART_FIFOSTS_TXFULL_Msk) == 0)
497 {
498 DEBUG_PORT->DAT = u8Buf[i32Tail];
499 i32Tail = i32Tmp;
500 }
501 else
502 break; /* FIFO full */
503 }while(i32Tail != i32Head);
504}
505#endif /* else for NONBLOCK_PRINTF */
506#endif /* if not def DISABLE_UART */
507
517void SendChar(int ch)
518{
519#if defined(DEBUG_ENABLE_SEMIHOST)
520 g_buf[g_buf_len++] = ch;
521 g_buf[g_buf_len] = '\0';
522 if(g_buf_len + 1 >= sizeof(g_buf) || ch == '\n' || ch == '\0')
523 {
524 /* Send the char */
525 if(g_ICE_Conneced)
526 {
527 if(SH_DoCommand(0x04, (int)g_buf, NULL) != 0)
528 {
529 g_buf_len = 0;
530 return;
531 }
532 }
533 else
534 {
535# if (DEBUG_ENABLE_SEMIHOST == 2) // Re-direct to UART Debug Port only when DEBUG_ENABLE_SEMIHOST=2
536 int i;
537 for(i = 0; i < g_buf_len; i++)
538 SendChar_ToUART(g_buf[i]);
539 g_buf_len = 0;
540# endif
541 }
542 }
543#else
544
545#ifndef DISABLE_UART
546 SendChar_ToUART(ch);
547#endif
548
549#endif
550}
551
561char GetChar(void)
562{
563#ifdef DEBUG_ENABLE_SEMIHOST
564 int nRet;
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#endif
722
723#else
724
736int fgetc(FILE *stream)
737{
738 (void)stream;
739 return ((int)GetChar());
740}
741
757int ferror(FILE *stream)
758{
759 (void)stream;
760 return EOF;
761}
762
763#endif
764
765
766#ifdef DEBUG_ENABLE_SEMIHOST
767
768# ifdef __ICCARM__
769void __exit(int return_code)
770{
771 /* Check if link with ICE */
772 if(SH_DoCommand(0x18, 0x20026, NULL) == 0)
773 {
774 /* Make sure all message is print out */
775 while(IsDebugFifoEmpty() == 0);
776 }
777label:
778 goto label; /* endless loop */
779}
780# else
781void _sys_exit(int return_code)
782{
783 (void)return_code;
784 /* Check if link with ICE */
785 if(SH_DoCommand(0x18, 0x20026, NULL) == 0)
786 {
787 /* Make sure all message is print out */
788 while(IsDebugFifoEmpty() == 0);
789 }
790label:
791 goto label; /* endless loop */
792}
793# endif // ifdef __ICCARM__
794
795#endif /* ifdef DEBUG_ENABLE_SEMIHOST */
void *__dso_handle __attribute__((weak))
Definition: _syscalls.c:35
NUC472/NUC442 peripheral access layer header file. This file contains all the peripheral register's d...
#define UART_FIFOSTS_TXFULL_Msk
Definition: NUC472_442.h:25935
#define UART_FIFOSTS_TXEMPTYF_Msk
Definition: NUC472_442.h:25941
#define UART_FIFOSTS_RXEMPTY_Msk
Definition: NUC472_442.h:25923
#define M16(addr)
Get a 16-bit unsigned value from specified address.
Definition: NUC472_442.h:28898
#define NULL
NULL pointer.
Definition: NUC472_442.h:29018
#define BIT11
Bit 11 mask of an 32 bit integer.
Definition: NUC472_442.h:29039
int32_t SH_Return(int32_t n32In_R0, int32_t n32In_R1, int32_t *pn32Out_R0)
This function is called by Hardfault handler.
Definition: retarget.c:421
#define __NO_RETURN
Definition: retarget.c:18
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:757
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:440
__WEAK uint32_t ProcessHardFault(uint32_t lr, uint32_t msp, uint32_t psp)
Definition: retarget.c:292
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:736
FILE __stdin
Definition: retarget.c:57
void SendChar(int ch)
Routine to send a char.
Definition: retarget.c:517
FILE __stdout
Definition: retarget.c:56
#define __WEAK
Definition: retarget.c:15
char GetChar(void)
Routine to get a char.
Definition: retarget.c:561
#define DEBUG_PORT
Definition: retarget.c:47
@ lr
Definition: retarget_isp.c:41