Intel® Quark™ Microcontroller Software Interface 1.4.0 Intel® Quark™ Microcontroller BSP

- Main Page
- Modules
- Data Structures
- Files

- File List

newlib-syscalls.c
1 /*
2 * {% copyright %}
3 */
4
5 /**
6 * newlib syscalls implementation
7 *
8 * @defgroup groupSyscalls Syscalls
9 * @{
10 */
11
12 /*
13 * Implement newlib system calls and syscall-related functions.
14 *
15 * Implementation notes:
16 * - file descriptor support is limited to stdout/stderr, both targeting UART
17 */
18
19 #include <sys/stat.h>
20 #include <errno.h>
21 #include <stdio.h>
22 #include <stdarg.h>
23
24 #include "qm_common.h"
25 #include "qm_interrupt.h"
26 #include "qm_pinmux.h"
27 #include "clk.h"
28 #include "qm_uart.h"
29
30 #define ASSERT_STR_HEAD ("\nAssertion failed: file ")
31 #define ASSERT_STR_TRAIL (", expr: ")
32
33 #define PICO_PRINTF_D 1
34 #define PICO_PRINTF_U 1
35 #define PICO_PRINTF_X 1
36 #define PICO_PRINTF_S 1
37 #define PICO_PRINTF_ESC 1
38 #define FORMAT_BUF_SIZE 32
39
40 static __inline__ int pico_putchar(int c)
41 {
42 qm_uart_write(STDOUT_UART, c);
43 return 1;
44 }
45
46 #if (PICO_PRINTF_D || PICO_PRINTF_U || PICO_PRINTF_X)
47 static __inline__ char last_digit_to_char(unsigned int n, int base, bool upcase)
48 {
49 char c;
50
51 c = n % base;
52 if (c <= 9)
53 return c + '0';
54
55 return upcase ? c + ('A' - 10) : c + ('a' - 10);
56 }
57
58 static __inline__ int putuint(unsigned int n, int base, bool upcase)
59 {
60 static char format_buf[FORMAT_BUF_SIZE];
61 char *s = format_buf;
62 int k;
63 int i = 0;
64
65 do {
66 s[i++] = last_digit_to_char(n, base, upcase);
67 n /= base;
68 } while (n > 0);
69
70 for (k = i - 1; k >= 0; k--)
71 pico_putchar(s[k]);
72
73 return i;
74 }
75 #endif
76
77 #if (PICO_PRINTF_S)
78 static __inline__ int pico_putchars(const char *s)
79 {
80 int len = 0;
81
82 for (; *s; s++)
83 len += pico_putchar(*s);
84
85 return len;
86 }
87 #endif
88
89 /**
90 * @brief This is an minimally useful subset of the POSIX printf() function.
91 *
92 * To reduce code size, this pico_printf() implementation only supports a few
93 * conversion specifiers:
94 * - @a 'd', @a 'u': for signed and unsigned decimal numbers, respectively;
95 * - @a 'x', @a 'X': for hexadecimal numbers, downcase and upcase;
96 * - @a 's': for NULL terminated strings.
97 *
98 * Other limitations:
99 * - No flag specifier is implemented;
100 * - No field width specifier is implemented;
101 * - The only supported length modifier is 'l', which is parsed and ignored,
102 * on supported archictetures 'int' and 'long int' are both 32 bits long.
103 * - 32 digits maximum length for formatted numbers.
104 */
105 int pico_printf(const char *format, ...)
106 {
107 const char *s = format;
108 int len = 0;
109 va_list ap;
110 va_start(ap, format);
111
112 while (*s) {
113 char c = *s++;
114 if (c == '%') {
115 c = *s++;
116 /*
117 * Ignore 'l' length sub-specifier.
118 * This has no effect in ILP32 (4/4/4).
119 * In i586, 'int' and 'long int' are both 4 bytes long.
120 */
121 if (c == 'l') {
122 c = *s++;
123 }
124 switch (c) {
125 #if (PICO_PRINTF_D)
126 case 'd': {
127 int n;
128 n = va_arg(ap, int);
129 if (n < 0) {
130 len += pico_putchar('-');
131 n = -n;
132 }
133 len += putuint(n, 10, false);
134 break;
135 }
136 #endif
137 #if (PICO_PRINTF_U)
138 case 'u': {
139 unsigned int u;
140 u = va_arg(ap, unsigned int);
141 len += putuint(u, 10, false);
142 break;
143 }
144 #endif
145 #if (PICO_PRINTF_X)
146 case 'X':
147 case 'x': {
148 unsigned int u;
149 u = va_arg(ap, unsigned int);
150 len += putuint(u, 16, c == 'X');
151 break;
152 }
153 #endif
154 #if (PICO_PRINTF_S)
155 case 's': {
156 const char *str;
157 str = va_arg(ap, const char *);
158 len += pico_putchars(str);
159 break;
160 }
161 #endif
162 #if (PICO_PRINTF_ESC)
163 default:
164 len += pico_putchar('%');
165 case '%':
166 len += pico_putchar(c);
167 break;
168 #endif
169 }
170 continue;
171 }
172
173 len += pico_putchar(c);
174 }
175
176 va_end(ap);
177 return len;
178 }
179
180 static qm_uart_config_t stdout_uart_cfg;
181 #define QM_AON_GPIO ((qm_gpio_reg_t *)QM_AON_GPIO_BASE)
182
183 void stdout_uart_setup(uint32_t baud_divisors)
184 {
185 /* Mux out TX pin */
186
187 #if (QUARK_SE)
188 #if (STDOUT_UART_0)
189 qm_pmux_select(QM_PIN_ID_19, QM_PMUX_FN_0);
190 #else
191 qm_pmux_select(QM_PIN_ID_16, QM_PMUX_FN_2);
192
193 #if (UART1_FTDI)
194 /* Set AON_GPIO 3 to get UART1 routed to USB/FTDI */
195 QM_AON_GPIO->gpio_swporta_dr |= BIT(3);
196 #else
197 QM_AON_GPIO->gpio_swporta_dr &= ~BIT(3);
198 #endif /* UART1_FTDI */
199 QM_AON_GPIO->gpio_swporta_ddr |= BIT(3);
200 #endif /* STDOUT_UART_0 */
201 #else
202 #if (STDOUT_UART_0)
203 qm_pmux_select(QM_PIN_ID_12, QM_PMUX_FN_2);
204 #else
205 qm_pmux_select(QM_PIN_ID_20, QM_PMUX_FN_2);
206 #endif /* STDOUT_UART_0 */
207 #endif /* QUARK_SE */
208
209 stdout_uart_cfg.baud_divisor = baud_divisors;
210 stdout_uart_cfg.line_control = QM_UART_LC_8N1;
211
212 #if (STDOUT_UART_0)
213 clk_periph_enable(CLK_PERIPH_CLK | CLK_PERIPH_UARTA_REGISTER);
214 #else
215 clk_periph_enable(CLK_PERIPH_CLK | CLK_PERIPH_UARTB_REGISTER);
216 #endif
217 qm_uart_set_config(STDOUT_UART, &stdout_uart_cfg);
218 }
219
220 /*
221 * Custom puts implementation providing a lightweight alternative to the
222 * standard stream-compliant newlib implementation.
223 * Transmit a pre-formatted string through UART and append a newline to it.
224 */
225 int puts(const char *s)
226 {
227 for (; *s; s++) {
228 qm_uart_write(STDOUT_UART, *s);
229 }
230
231 qm_uart_write(STDOUT_UART, '\n');
232 return 0;
233 }
234
235 /*
236 * Custom lightweight implementation that avoids the need for
237 * kill/abort/exit/getpid syscalls. It is also optimised for size (no string
238 * formatting, targeting UART directly).
239 */
240 void __assert_func(const char *file, int line, const char *func,
241 const char *failedexpr)
242 {
243 (void)file;
244 (void)line;
245
246 qm_irq_disable();
247
248 #if (PUTS_ENABLE || PRINTF_ENABLE)
249 /* No point in checking for TX outcome at this stage */
250 qm_uart_write_buffer(STDOUT_UART, (uint8_t *)ASSERT_STR_HEAD,
251 sizeof(ASSERT_STR_HEAD));
252 int i;
253 for (i = 0; func[i]; i++) {
254 qm_uart_write(STDOUT_UART, (uint8_t)func[i]);
255 }
256 qm_uart_write_buffer(STDOUT_UART, (uint8_t *)ASSERT_STR_TRAIL,
257 sizeof(ASSERT_STR_TRAIL));
258 for (i = 0; failedexpr[i]; i++) {
259 qm_uart_write(STDOUT_UART, (uint8_t)failedexpr[i]);
260 }
261 #else
262 (void)func;
263 (void)failedexpr;
264 #endif /* PUTS_ENABLED || PRINTF_ENABLED */
265
266 while (1) {
267 #if (ASSERT_ACTION_HALT)
268 #if (QM_SENSOR)
269 __builtin_arc_brk();
270 #else
271 __asm__ __volatile__("hlt");
272 #endif
273 #elif(ASSERT_ACTION_RESET)
274 qm_soc_reset(QM_WARM_RESET);
275 #else
276 #error "Undefined assert action"
277 #endif /* ASSERT_ACTION_* */
278 }
279 }
280
281 /* System call not supported */
282 int close(int file)
283 {
284 (void)file;
285
286 errno = ENOTSUP;
287 return -1;
288 }
289
290 /* System call not supported */
291 int isatty(int file)
292 {
293 (void)file;
294
295 errno = ENOTTY;
296 return 0;
297 }
298
299 /* System call not supported */
300 int read(int file, char *buf, int len)
301 {
302 (void)file;
303 (void)buf;
304 (void)len;
305
306 errno = ENOTSUP;
307 return -1;
308 }
309
310 /*
311 * Back-end of printf. Directs output and error streams to UART.
312 */
313 int write(int file, const char *buf, int len)
314 {
315 int ret = -1;
316
317 switch (file) {
318 case 1:
319 case 2:
320 if (0 ==
321 qm_uart_write_buffer(STDOUT_UART, (uint8_t *)buf, len)) {
322 ret = len;
323 } else {
324 errno = EIO;
325 }
326 break;
327
328 default:
329 errno = ENOTSUP;
330 break;
331 }
332
333 return ret;
334 }
335
336 /* System call not supported */
337 int lseek(int file, int p, int dir)
338 {
339 (void)file;
340 (void)p;
341 (void)dir;
342
343 errno = ENOTSUP;
344 return -1;
345 }
346
347 /* Returns file status. stdout/stderr set to character devices (needed by the
348 * printf family). */
349 int fstat(int file, struct stat *st)
350 {
351 if (file == 0 || file > 2) {
352 errno = ENOTSUP;
353 return -1;
354 }
355
356 /* The stream is a character device (needed by printf functions) */
357 st->st_mode = S_IFCHR;
358 return 0;
359 }
360
361 /*
362 * Expands/shrinks the heap. This is the back-end of malloc/free.
363 */
364 caddr_t sbrk(int incr)
365 {
366 extern char __heap, __heap_end;
367 static char *prog_break = &__heap;
368
369 char *prev_prog_break;
370
371 if (prog_break + incr >= &__heap_end || prog_break + incr < &__heap) {
372 errno = ENOMEM;
373 return (void *)-1;
374 }
375
376 prev_prog_break = prog_break;
377
378 prog_break += incr;
379
380 return prev_prog_break;
381 }
382
383 /**
384 * @}
385 */
CLK_PERIPH_UARTA_REGISTER
UARTA Clock Gate Enable.
Definition: qm_soc_regs.h:1384
QM_PIN_ID_20
Pin id 20.
Definition: qm_pinmux.h:66
clk_periph_enable
int clk_periph_enable(const clk_periph_t clocks)
Enable clocks for peripherals / registers.
Definition: clk.c:319
qm_uart_config_t::line_control
qm_uart_lc_t line_control
Line control (enum).
Definition: qm_uart.h:68
qm_irq_disable
void qm_irq_disable(void)
Unconditionally disable interrupt delivery on the CPU.
Definition: qm_interrupt.c:31
CLK_PERIPH_CLK
Peripheral Clock Enable.
Definition: qm_soc_regs.h:1370
QM_WARM_RESET
Warm reset.
Definition: qm_init.h:22
QM_PMUX_FN_0
Gpio function 0.
Definition: qm_pinmux.h:22
pico_printf
int pico_printf(const char *format,...)
This is an minimally useful subset of the POSIX printf() function.
Definition: newlib-syscalls.c:105
QM_PIN_ID_12
Pin id 12.
Definition: qm_pinmux.h:58
QM_PIN_ID_16
Pin id 16.
Definition: qm_pinmux.h:62
QM_PMUX_FN_2
Gpio function 0.
Definition: qm_pinmux.h:24
qm_pmux_select
int qm_pmux_select(const qm_pin_id_t pin, const qm_pmux_fn_t fn)
Set up pin muxing for a SoC pin.
Definition: qm_pinmux.c:37
qm_uart_set_config
int qm_uart_set_config(const qm_uart_t uart, const qm_uart_config_t *const cfg)
Set UART configuration.
Definition: qm_uart.c:215
CLK_PERIPH_UARTB_REGISTER
UARTB Clock Gate Enable.
Definition: qm_soc_regs.h:1385
QM_PIN_ID_19
Pin id 19.
Definition: qm_pinmux.h:65
qm_uart_config_t::baud_divisor
uint32_t baud_divisor
Baud Divisor.
Definition: qm_uart.h:69
qm_soc_reset
void qm_soc_reset(qm_soc_reset_t reset_type)
Reset the SoC.
Definition: qm_init.c:7
qm_uart_write
int qm_uart_write(const qm_uart_t uart, const uint8_t data)
UART character data write.
Definition: qm_uart.c:280
qm_uart_config_t
UART configuration structure type.
Definition: qm_uart.h:67
qm_uart_write_buffer
int qm_uart_write_buffer(const qm_uart_t uart, const uint8_t *const data, const uint32_t len)
UART multi-byte data write.
Definition: qm_uart.c:342
QM_UART_LC_8N1
8 data bits, no parity, 1 stop bit.
Definition: qm_uart.h:41