Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Redirect std stream to USARTx for STM32F103 device
# toolchain: gcc-arm-none-eabi(Linux), pleas use newlib_stubs.c
OBJS += newlib_stubs.o
CFLAGS += -ffunction-sections -fdata-sections -fno-builtin
LDFLAGS += --specs=nano.specs -lc -lnosys
# toolchain: keil MDK(Windows), please use redirect_file_stream.c
# Please check 'USE MicroLIB'
/*
* newlib_stubs.c
* Created on: 2 Nov 2010 Author: nanoage.co.uk
http://svn.clifford.at/handicraft/2015/c3demo/app_primes/syscalls.c
https://sourceware.org/newlib/libc.html
*/
#include <errno.h>
#include <sys/stat.h>
#include <sys/times.h>
#include <sys/unistd.h>
#include "stm32f10x.h"
#include "stm32f10x_usart.h"
#ifndef STDOUT_USART
#define STDOUT_USART 1
#endif
#ifndef STDERR_USART
#define STDERR_USART 1
#endif
#ifndef STDIN_USART
#define STDIN_USART 1
#endif
#undef errno
extern int errno;
/*
- File management functions
+ open : (v) open file
+ lseek : (v) set position in file
+ read : (v) read from file
+ write : (v) write to file
+ fstat : (z) status of an open file
+ stat : (z) status of a file by name
+ close : (z) close a file
+ link : (z) rename a file
+ unlink : (z) remote file's directory entry
- Process management functions
+ execve : (z) transfer control to new proc
+ fork : (z) create a new process
+ getpid : (v) get process id
+ kill : (z) send signal to child process
+ wait : (z) wait for a child process
- Misc functions
+ isatty : (v) query whether output stream is a terminal
+ times : (z) timing information for current process
+ sbrk : (v) increase program data space
+ _exit : (-) exit program without cleaning up files
*/
/*
environ
A pointer to a list of environment variables and their values.
For a minimal environment, this empty list is adequate:
*/
char *__env[1] = { 0 };
char **environ = __env;
int _write(int file, char *ptr, int len);
void _exit(int status) {
_write(1, "exit", 4);
while (1) {
;
}
}
int _close(int file) {
return -1;
}
/*
execve
Transfer control to a new process. Minimal implementation (for a system without processes):
*/
int _execve(char *name, char **argv, char **env) {
errno = ENOMEM;
return -1;
}
/*
fork
Create a new process. Minimal implementation (for a system without processes):
*/
int _fork() {
errno = EAGAIN;
return -1;
}
/*
fstat
Status of an open file. For consistency with other minimal implementations in these examples,
all files are regarded as character special devices.
The `sys/stat.h' header file required is distributed in the `include' subdirectory for this C library.
*/
int _fstat(int file, struct stat *st) {
st->st_mode = S_IFCHR;
return 0;
}
/*
getpid
Process-ID; this is sometimes used to generate strings unlikely to conflict with other processes. Minimal implementation, for a system without processes:
*/
int _getpid() {
return 1;
}
/*
isatty
Query whether output stream is a terminal. For consistency with the other minimal implementations,
*/
int _isatty(int file) {
switch (file) {
case STDOUT_FILENO:
case STDERR_FILENO:
case STDIN_FILENO:
return 1;
default:
//errno = ENOTTY;
errno = EBADF;
return 0;
}
}
/*
kill
Send a signal. Minimal implementation:
*/
int _kill(int pid, int sig) {
errno = EINVAL;
return (-1);
}
/*
link
Establish a new name for an existing file. Minimal implementation:
*/
int _link(char *old, char *new) {
errno = EMLINK;
return -1;
}
/*
lseek
Set position in a file. Minimal implementation:
*/
int _lseek(int file, int ptr, int dir) {
return 0;
}
/*
sbrk
Increase program data space.
Malloc and related functions depend on this
*/
caddr_t _sbrk(int incr) {
extern char _ebss; // Defined by the linker
static char *heap_end;
char *prev_heap_end;
if (heap_end == 0) {
heap_end = &_ebss;
}
prev_heap_end = heap_end;
char * stack = (char*) __get_MSP();
if (heap_end + incr > stack) {
_write(STDERR_FILENO, "Heap and stack collision\n", 25);
errno = ENOMEM;
return (caddr_t) - 1;
//abort ();
}
heap_end += incr;
return (caddr_t) prev_heap_end;
}
/*
read
Read a character to a file. `libc' subroutines will use this system routine for input from all files, including stdin
Returns -1 on error or blocks until the number of characters have been read.
About function _read():
In this script, you should input ends with '\r\n' !
For linux or Mac, the EOL is LF (Line feed, '\n', 0x0AH)
For Windows, the EOL is CR+LF (Carriage return+Line feed, '\r\n', 0x0D0AH)
Please view it in function void _read()
*/
int _read(int file, char *ptr, int len) {
int n;
char c;
int num = 0;
switch (file) {
case STDIN_FILENO:
for (n = 0; n < len; n++) {
#if STDIN_USART == 1
while ((USART1->SR & USART_FLAG_RXNE) == (uint16_t) RESET) {
}
c = (char) (USART1->DR & (uint16_t) 0x01FF);
#elif STDIN_USART == 2
while ((USART2->SR & USART_FLAG_RXNE) == (uint16_t) RESET) {}
c = (char) (USART2->DR & (uint16_t) 0x01FF);
#elif STDIN_USART == 3
while ((USART3->SR & USART_FLAG_RXNE) == (uint16_t)RESET) {}
c = (char)(USART3->DR & (uint16_t)0x01FF);
#endif
if (c == '\n')
return num;
// LF means newline, CR means had pressed ENTER key,
// CR tells scanf that user has finished input
*ptr++ = c;
num++;
}
break;
default:
errno = EBADF;
return -1;
}
return num;
}
/*
stat
Status of a file (by name). Minimal implementation:
int _EXFUN(stat,( const char *__path, struct stat *__sbuf ));
*/
int _stat(const char *filepath, struct stat *st) {
st->st_mode = S_IFCHR;
return 0;
}
/*
times
Timing information for current process. Minimal implementation:
*/
clock_t _times(struct tms *buf) {
return -1;
}
/*
unlink
Remove a file's directory entry. Minimal implementation:
*/
int _unlink(char *name) {
errno = ENOENT;
return -1;
}
/*
wait
Wait for a child process. Minimal implementation:
*/
int _wait(int *status) {
errno = ECHILD;
return -1;
}
/*
write
Write a character to a file. `libc' subroutines will use this system routine for output to all files, including stdout
Returns -1 on error or number of bytes sent
*/
int _write(int file, char *ptr, int len) {
int n;
switch (file) {
case STDOUT_FILENO: /*stdout*/
for (n = 0; n < len; n++) {
#if STDOUT_USART == 1
while ((USART1->SR & USART_FLAG_TC) == (uint16_t) RESET) {
}
USART1->DR = (*ptr++ & (uint16_t) 0x01FF);
#elif STDOUT_USART == 2
while ((USART2->SR & USART_FLAG_TC) == (uint16_t) RESET) {
}
USART2->DR = (*ptr++ & (uint16_t) 0x01FF);
#elif STDOUT_USART == 3
while ((USART3->SR & USART_FLAG_TC) == (uint16_t)RESET) {}
USART3->DR = (*ptr++ & (uint16_t)0x01FF);
#endif
}
break;
case STDERR_FILENO: /* stderr */
for (n = 0; n < len; n++) {
#if STDERR_USART == 1
while ((USART1->SR & USART_FLAG_TC) == (uint16_t) RESET) {
}
USART1->DR = (*ptr++ & (uint16_t) 0x01FF);
#elif STDERR_USART == 2
while ((USART2->SR & USART_FLAG_TC) == (uint16_t) RESET) {
}
USART2->DR = (*ptr++ & (uint16_t) 0x01FF);
#elif STDERR_USART == 3
while ((USART3->SR & USART_FLAG_TC) == (uint16_t)RESET) {}
USART3->DR = (*ptr++ & (uint16_t)0x01FF);
#endif
}
break;
default:
errno = EBADF;
return -1;
}
return len;
}
/*
* redirect_file_stream.c
*
* Created on: 2016年8月2日
* Author: li
*
* redirect stdout and stderr to USART1 and USART2 seperately
* use Micro Lib
* For Windows Keil only
*/
#include "stdio.h"
#include "stm32f10x_usart.h"
struct __FILE{
int handle;
};
enum{
STDOUT_HANDLE,
STDERR_HANDLE
};
// USART1: stderr
// USART1: stdin
// USART2: stdout
FILE __stdout={STDOUT_HANDLE};
FILE __stderr={STDERR_HANDLE};
int fputc(int ch,FILE *f)
{
int ret = EOF ;
switch( f->handle ){
case STDOUT_HANDLE:
ret = ch ;
USART_SendData(USART2,(uint8_t)ch);
while((USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET));
break ;
case STDERR_HANDLE:
ret = ch ;
USART_SendData(USART1,(uint8_t)ch);
while((USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET));
break ;
default:
break ;
}
return ret;
}
int fgetc(FILE *f){
unsigned short c;
while ((USART1->SR & USART_FLAG_RXNE) == (uint16_t) RESET);
c = (char) (USART1->DR & (uint16_t) 0x01FF);
return c;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment