Skip to content

Commit 2d43df4

Browse files
committed
stm32f469: stdio example update
Added a bit of interactivity on the console (serial port) to demonstrate how you might use this feature with libopencm3
1 parent 66f59a2 commit 2d43df4

File tree

8 files changed

+294
-10
lines changed

8 files changed

+294
-10
lines changed

examples/stm32/f4/stm32f469-discovery/console/main.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ int main(void)
4949
while (1) {
5050
console_puts("Enter a string: ");
5151
len = console_gets(buf, 128);
52-
if (len) {
52+
if (len > 1) {
53+
buf[len-1] = 0; /* kill trailing newline */
5354
console_puts("\nYou entered : '");
5455
console_puts(buf);
5556
console_puts("'\n");
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#
2+
# This file is part of the libopencm3 project.
3+
#
4+
# This library is free software: you can redistribute it and/or modify
5+
# it under the terms of the GNU Lesser General Public License as published by
6+
# the Free Software Foundation, either version 3 of the License, or
7+
# (at your option) any later version.
8+
#
9+
# This library is distributed in the hope that it will be useful,
10+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
# GNU Lesser General Public License for more details.
13+
#
14+
# You should have received a copy of the GNU Lesser General Public License
15+
# along with this library. If not, see <http://www.gnu.org/licenses/>.
16+
#
17+
18+
OBJS = ../util/retarget.o ../util/console.o ../util/clock.o
19+
20+
BINARY = main
21+
22+
LDSCRIPT = ../stm32f469-discovery.ld
23+
24+
include ../../Makefile.include
25+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
Standard I/O Example
2+
--------------------
3+
4+
This just shows using the native retargeting capability of
5+
the ARM GCC Embedded compiler. By linking in retarget,
6+
console, and clock. The startup script will call SystemInit
7+
in retarget automatically and set things up before main()
8+
is called, in particular the serial port is set up as the
9+
standard input, output, and error streams for the program
10+
and the clock is setup to be 168Mhz (based on the STM32F469-Discovery's
11+
external (HSE) crystal setup.
12+
13+
Control-C is enabled so when the example is running, if you
14+
hold the control key and C the board will reset and restart.
15+
16+
## Notes ##
17+
18+
Often time people do not use the standard libraries (especially printf!)
19+
because they include a lot of code that usually is not needed. However
20+
since the F4 chip on our board has 2 megabytes of flash, there is space
21+
to have it, and once you pay the price for including it, you can use it
22+
as often as you like without adding additional space requirements.
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* This file is part of the libopencm3 project.
3+
*
4+
* Copyright (C) 2013 Chuck McManis <[email protected]>
5+
*
6+
* This library is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU Lesser General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This library is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public License
17+
* along with this library. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
20+
#include <stdint.h>
21+
#include <stdio.h>
22+
#include <stdlib.h>
23+
#include <string.h>
24+
#include <libopencm3/stm32/rcc.h>
25+
#include <libopencm3/stm32/gpio.h>
26+
#include "../util/clock.h"
27+
28+
int main(void)
29+
{
30+
double flash_rate = 3.14159;
31+
char buf[128];
32+
uint32_t done_time;
33+
34+
/* things printed to standard error stand out */
35+
fprintf(stderr, "\nSTM32F469-Discovery");
36+
printf(" Retarget demo.\n");
37+
38+
/* This is the LED on the board */
39+
rcc_periph_clock_enable(RCC_GPIOK);
40+
gpio_mode_setup(GPIOK, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO3);
41+
42+
/* You can create a running dialog with the console */
43+
printf("We're going to start blinking the LED, between 0 and 300 times per\n");
44+
printf("second.\n");
45+
while (1) {
46+
printf("Please enter a flash rate: ");
47+
fflush(stdout);
48+
fgets(buf, 128, stdin);
49+
buf[strlen(buf) - 1] = '\0';
50+
flash_rate = atof(buf);
51+
if (flash_rate == 0) {
52+
printf("Was expecting a number greater than 0 and less than 300.\n");
53+
printf("but got '%s' instead\n", buf);
54+
} else if (flash_rate > 300.0) {
55+
printf("The number should be less than 300.\n");
56+
} else {
57+
break;
58+
}
59+
}
60+
/* MS per flash */
61+
done_time = (int) (500 / flash_rate);
62+
printf("The closest we can come will be %f flashes per second\n", 500.0 / done_time);
63+
printf("With %d MS between states\n", (int) done_time);
64+
printf("Press ^C to restart this demo.\n");
65+
while (1) {
66+
msleep(done_time);
67+
gpio_toggle(GPIOK, GPIO3);
68+
}
69+
}

examples/stm32/f4/stm32f469-discovery/util/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,13 @@ Utility Functions
44
Not part of the library, these utility functions provide some
55
helper functions for the examples that simplify things.
66

7+
**clock.c** - sets up the clock to 168Mhz and and enables the
8+
SysTick interrupt with 1khz interrupts.
9+
10+
**console.c** - a set of convienience routines for using the debug
11+
serial port (USART3) which is availble as /dev/ttyACM0 on
12+
the linux box, as a console port.
13+
14+
**retarget.c** - implements the minimum set of character I/O functions
15+
and automatically plumbs them so that you can use standard
16+
functions like printf() in your programs.

examples/stm32/f4/stm32f469-discovery/util/console.c

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
*/
2626

2727
#include <stdint.h>
28+
#include <ctype.h>
2829
#include <libopencm3/stm32/gpio.h>
2930
#include <libopencm3/stm32/rcc.h>
3031
#include <libopencm3/stm32/usart.h>
@@ -47,9 +48,9 @@
4748
/* This is a ring buffer to holding characters as they are typed
4849
* it maintains both the place to put the next character received
4950
* from the UART, and the place where the last character was
50-
* read by the program. See the README file for a discussion of
51-
* the failure semantics.
51+
* read by the program.
5252
*/
53+
5354
#define RECV_BUF_SIZE 128 /* Arbitrary buffer size */
5455
char recv_buf[RECV_BUF_SIZE];
5556
volatile int recv_ndx_nxt; /* Next place to store */
@@ -116,9 +117,6 @@ void console_putc(char c)
116117
* Check the console for a character. If the wait flag is
117118
* non-zero. Continue checking until a character is received
118119
* otherwise return 0 if called and no character was available.
119-
*
120-
* The implementation is a bit different however, now it looks
121-
* in the ring buffer to see if a character has arrived.
122120
*/
123121
char console_getc(int wait)
124122
{
@@ -138,6 +136,9 @@ char console_getc(int wait)
138136
* Send a string to the console, one character at a time, return
139137
* after the last character, as indicated by a NUL character, is
140138
* reached.
139+
*
140+
* Translate '\n' in the string (newline) to \n\r (newline +
141+
* carraige return)
141142
*/
142143
void console_puts(char *s)
143144
{
@@ -154,9 +155,11 @@ void console_puts(char *s)
154155
/*
155156
* int console_gets(char *s, int len)
156157
*
157-
* Wait for a string to be entered on the console, limited
158-
* support for editing characters (back space and delete)
159-
* end when a <CR> character is received.
158+
* Wait for a string to be entered on the console, with
159+
* support for editing characters (delete letter, word,
160+
* entire line). It returns when the length is reached
161+
* or a carrige return is entered. <CR> is changed to newline
162+
* before the buffer is returned.
160163
*/
161164
int console_gets(char *s, int len)
162165
{
@@ -165,13 +168,23 @@ int console_gets(char *s, int len)
165168

166169
*t = '\000';
167170
/* read until a <CR> is received */
168-
while ((c = console_getc(1)) != '\r') {
171+
while (((c = console_getc(1)) != '\r') && ((t - s) < len) ) {
169172
if ((c == '\010') || (c == '\127')) {
170173
if (t > s) {
171174
/* send ^H ^H to erase previous character */
172175
console_puts("\010 \010");
173176
t--;
174177
}
178+
} else if (c == 0x17) { // ^W erase a word
179+
while ((t > s) && (!(isspace((int) (*t))))) {
180+
t--;
181+
console_puts("\010 \010");
182+
}
183+
} else if (c == 0x15) { // ^U erase the line
184+
while (t > s) {
185+
t--;
186+
console_puts("\010 \010");
187+
}
175188
} else {
176189
*t = c;
177190
console_putc(c);
@@ -182,6 +195,10 @@ int console_gets(char *s, int len)
182195
/* update end of string with NUL */
183196
*t = '\000';
184197
}
198+
if ((t < s) < len) {
199+
*t++ = '\n';
200+
*t = 0;
201+
}
185202
return t - s;
186203
}
187204

@@ -226,3 +243,11 @@ void console_setup(int baud)
226243
/* Specifically enable recieve interrupts */
227244
usart_enable_rx_interrupt(CONSOLE_UART);
228245
}
246+
247+
/*
248+
* Set a different baud rate for the console.
249+
*/
250+
void console_baud(int baud_rate)
251+
{
252+
usart_set_baudrate(CONSOLE_UART, baud_rate);
253+
}

examples/stm32/f4/stm32f469-discovery/util/console.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ char console_getc(int wait);
77
void console_puts(char *s);
88
int console_gets(char *s, int len);
99
void console_setup(int baud);
10+
void console_baud(int baudrate);
1011

1112
/* this is for fun, if you type ^C to this example it will reset */
1213
#define RESET_ON_CTRLC
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/*
2+
* This file is part of the libopencm3 project.
3+
*
4+
* Copyright (C) 2015 Chuck McManis <[email protected]>
5+
*
6+
* This library is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU Lesser General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This library is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public License
17+
* along with this library. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
20+
/* retarget.c
21+
*
22+
* Stub routines to connect the board's USART3 which is wired into the
23+
* STLink port, into the C library functions for standard I/O.
24+
*/
25+
#include <stdio.h>
26+
#include <stdint.h>
27+
#include <ctype.h>
28+
#include "../util/clock.h"
29+
#include "../util/console.h"
30+
31+
#ifndef NULL
32+
#define NULL 0
33+
#endif
34+
35+
#define BUFLEN 127
36+
37+
static void SystemInit(void);
38+
39+
/*
40+
* These are the functions to define to enable the
41+
* newlib hooks to implement basic character I/O
42+
*/
43+
int _write (int fd, char *ptr, int len);
44+
int _read (int fd, char *ptr, int len);
45+
46+
/*
47+
* A 128 byte buffer for getting a string from the
48+
* console.
49+
*/
50+
static char buf[BUFLEN+1] = {0};
51+
static char *next_char;
52+
53+
/*
54+
* Called by libc stdio functions
55+
*/
56+
int
57+
_write (int fd, char *ptr, int len)
58+
{
59+
int i = 0;
60+
61+
/*
62+
* Write "len" of char from "ptr" to file id "fd"
63+
* Return number of char written.
64+
*/
65+
if (fd > 2) {
66+
return -1; // STDOUT, STDIN, STDERR
67+
}
68+
if (fd == 2) {
69+
/* set the text output YELLOW when sending to stderr */
70+
console_puts("\033[33;40;1m");
71+
}
72+
while (*ptr && (i < len)) {
73+
console_putc(*ptr);
74+
if (*ptr == '\n') {
75+
console_putc('\r');
76+
}
77+
i++;
78+
ptr++;
79+
}
80+
if (fd == 2) {
81+
/* return text out to its default state */
82+
console_puts("\033[0m");
83+
}
84+
return i;
85+
}
86+
87+
88+
/*
89+
* Depending on the implementation, this function can call
90+
* with a buffer length of 1 to 1024. However it does no
91+
* editing on console reading. So, the console_gets code
92+
* implements a simple line editing input style.
93+
*/
94+
int
95+
_read (int fd, char *ptr, int len)
96+
{
97+
int my_len;
98+
99+
if (fd > 2) {
100+
return -1;
101+
}
102+
103+
/* If not null we've got more characters to return */
104+
if (next_char == NULL) {
105+
console_gets(buf, BUFLEN);
106+
next_char = &buf[0];
107+
}
108+
109+
my_len = 0;
110+
while ((*next_char != 0) && (len > 0)) {
111+
*ptr++ = *next_char++;
112+
my_len++;
113+
len--;
114+
}
115+
if (*next_char == 0) {
116+
next_char = NULL;
117+
}
118+
return my_len; // return the length we got
119+
}
120+
121+
/* SystemInit will be called before main
122+
* This works because we tell GCC that it is a constructor
123+
* which means "run this before main is invoked".
124+
*/
125+
__attribute__((constructor))
126+
static void SystemInit()
127+
{
128+
clock_setup();
129+
console_setup(115200);
130+
next_char = NULL;
131+
}

0 commit comments

Comments
 (0)