|
| 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 | + |
| 21 | +#include <stdio.h> |
| 22 | +#include <stdlib.h> |
| 23 | +#include <ctype.h> |
| 24 | +#include <libopencm3/stm32/rcc.h> |
| 25 | +#include <libopencm3/stm32/gpio.h> |
| 26 | +#include <libopencm3/stm32/usart.h> |
| 27 | + |
| 28 | +/* |
| 29 | + * To implement the STDIO functions you need to create |
| 30 | + * the _read and _write functions and hook them to the |
| 31 | + * USART you are using. This example also has a buffered |
| 32 | + * read function for basic line editing. |
| 33 | + */ |
| 34 | +int _write(int fd, char *ptr, int len); |
| 35 | +int _read(int fd, char *ptr, int len); |
| 36 | +void get_buffered_line(void); |
| 37 | + |
| 38 | +/* |
| 39 | + * This is a pretty classic ring buffer for characters |
| 40 | + */ |
| 41 | +#define BUFLEN 127 |
| 42 | + |
| 43 | +static uint16_t start_ndx; |
| 44 | +static uint16_t end_ndx; |
| 45 | +static char buf[BUFLEN+1]; |
| 46 | +#define buf_len ((end_ndx - start_ndx) % BUFLEN) |
| 47 | +static inline int inc_ndx(int n) { return ((n + 1) % BUFLEN); } |
| 48 | +static inline int dec_ndx(int n) { return (((n + BUFLEN) - 1) % BUFLEN); } |
| 49 | + |
| 50 | + |
| 51 | +static void clock_setup(void) |
| 52 | +{ |
| 53 | + /* Enable GPIOD clock for LED & USARTs. */ |
| 54 | + rcc_periph_clock_enable(RCC_GPIOA); |
| 55 | + |
| 56 | + /* Enable clocks for USART2. */ |
| 57 | + rcc_periph_clock_enable(RCC_USART2); |
| 58 | +} |
| 59 | + |
| 60 | +static void usart_setup(void) |
| 61 | +{ |
| 62 | + /* Setup USART2 parameters. */ |
| 63 | + usart_set_baudrate(USART2, 115200); |
| 64 | + usart_set_databits(USART2, 8); |
| 65 | + usart_set_stopbits(USART2, USART_STOPBITS_1); |
| 66 | + usart_set_mode(USART2, USART_MODE_TX_RX); |
| 67 | + usart_set_parity(USART2, USART_PARITY_NONE); |
| 68 | + usart_set_flow_control(USART2, USART_FLOWCONTROL_NONE); |
| 69 | + |
| 70 | + /* Finally enable the USART. */ |
| 71 | + usart_enable(USART2); |
| 72 | +} |
| 73 | + |
| 74 | +static void gpio_setup(void) |
| 75 | +{ |
| 76 | + /* Setup GPIO pin GPIO5 on GPIO port A for LED. */ |
| 77 | + gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO5); |
| 78 | + |
| 79 | + /* Setup GPIO pins for USART2 transmit and receive. */ |
| 80 | + gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO2 | GPIO3); |
| 81 | + |
| 82 | + /* Setup USART2 TX pin as alternate function. */ |
| 83 | + gpio_set_af(GPIOA, GPIO_AF7, GPIO2 | GPIO3); |
| 84 | +} |
| 85 | + |
| 86 | +int main(void) |
| 87 | +{ |
| 88 | + int i, j; |
| 89 | + |
| 90 | + clock_setup(); |
| 91 | + gpio_setup(); |
| 92 | + usart_setup(); |
| 93 | + printf("\nStandard I/O Example.\n"); |
| 94 | + |
| 95 | + /* Blink the LED (PD12) on the board with every transmitted byte. */ |
| 96 | + while (1) { |
| 97 | + int delay = 0; |
| 98 | + char local_buf[32]; |
| 99 | + |
| 100 | + gpio_toggle(GPIOA, GPIO5); /* LED on/off */ |
| 101 | + do { |
| 102 | + printf("Enter the delay constant for blink : "); |
| 103 | + fflush(stdout); |
| 104 | + fgets(local_buf, 32, stdin); |
| 105 | + delay = atoi(local_buf); |
| 106 | + if (delay <= 0) { |
| 107 | + printf("Error: expected a delay > 0\n"); |
| 108 | + } |
| 109 | + } while (delay <= 0); |
| 110 | + |
| 111 | + printf("Blinking with a delay of %d\n", delay); |
| 112 | + for (j = 0; j < 1000; j++) { |
| 113 | + gpio_toggle(GPIOA, GPIO5); |
| 114 | + for (i = 0; i < delay; i++) { /* Wait a bit. */ |
| 115 | + __asm__("NOP"); |
| 116 | + } |
| 117 | + } |
| 118 | + } |
| 119 | + return 0; |
| 120 | +} |
| 121 | + |
| 122 | +/* back up the cursor one space */ |
| 123 | +static inline void back_up(void) |
| 124 | +{ |
| 125 | + end_ndx = dec_ndx(end_ndx); |
| 126 | + usart_send_blocking(USART2, '\010'); |
| 127 | + usart_send_blocking(USART2, ' '); |
| 128 | + usart_send_blocking(USART2, '\010'); |
| 129 | +} |
| 130 | + |
| 131 | +/* |
| 132 | + * A buffered line editing function. |
| 133 | + */ |
| 134 | +void |
| 135 | +get_buffered_line(void) { |
| 136 | + char c; |
| 137 | + |
| 138 | + if (start_ndx != end_ndx) { |
| 139 | + return; |
| 140 | + } |
| 141 | + while (1) { |
| 142 | + c = usart_recv_blocking(USART2); |
| 143 | + if (c == '\r') { |
| 144 | + buf[end_ndx] = '\n'; |
| 145 | + end_ndx = inc_ndx(end_ndx); |
| 146 | + buf[end_ndx] = '\0'; |
| 147 | + usart_send_blocking(USART2, '\r'); |
| 148 | + usart_send_blocking(USART2, '\n'); |
| 149 | + return; |
| 150 | + } |
| 151 | + /* ^H or DEL erase a character */ |
| 152 | + if ((c == '\010') || (c == '\177')) { |
| 153 | + if (buf_len == 0) { |
| 154 | + usart_send_blocking(USART2, '\a'); |
| 155 | + } else { |
| 156 | + back_up(); |
| 157 | + } |
| 158 | + /* ^W erases a word */ |
| 159 | + } else if (c == 0x17) { |
| 160 | + while ((buf_len > 0) && |
| 161 | + (!(isspace((int) buf[end_ndx])))) { |
| 162 | + back_up(); |
| 163 | + } |
| 164 | + /* ^U erases the line */ |
| 165 | + } else if (c == 0x15) { |
| 166 | + while (buf_len > 0) { |
| 167 | + back_up(); |
| 168 | + } |
| 169 | + /* Non-editing character so insert it */ |
| 170 | + } else { |
| 171 | + if (buf_len == (BUFLEN - 1)) { |
| 172 | + usart_send_blocking(USART2, '\a'); |
| 173 | + } else { |
| 174 | + buf[end_ndx] = c; |
| 175 | + end_ndx = inc_ndx(end_ndx); |
| 176 | + usart_send_blocking(USART2, c); |
| 177 | + } |
| 178 | + } |
| 179 | + } |
| 180 | +} |
| 181 | + |
| 182 | + |
| 183 | +/* |
| 184 | + * Called by libc stdio fwrite functions |
| 185 | + */ |
| 186 | +int |
| 187 | +_write(int fd, char *ptr, int len) |
| 188 | +{ |
| 189 | + int i = 0; |
| 190 | + |
| 191 | + /* |
| 192 | + * Write "len" of char from "ptr" to file id "fd" |
| 193 | + * Return number of char written. |
| 194 | + * |
| 195 | + * Only work for STDOUT, STDIN, and STDERR |
| 196 | + */ |
| 197 | + if (fd > 2) { |
| 198 | + return -1; |
| 199 | + } |
| 200 | + while (*ptr && (i < len)) { |
| 201 | + usart_send_blocking(USART2, *ptr); |
| 202 | + if (*ptr == '\n') { |
| 203 | + usart_send_blocking(USART2, '\r'); |
| 204 | + } |
| 205 | + i++; |
| 206 | + ptr++; |
| 207 | + } |
| 208 | + return i; |
| 209 | +} |
| 210 | + |
| 211 | +/* |
| 212 | + * Called by the libc stdio fread fucntions |
| 213 | + * |
| 214 | + * Implements a buffered read with line editing. |
| 215 | + */ |
| 216 | +int |
| 217 | +_read(int fd, char *ptr, int len) |
| 218 | +{ |
| 219 | + int my_len; |
| 220 | + |
| 221 | + if (fd > 2) { |
| 222 | + return -1; |
| 223 | + } |
| 224 | + |
| 225 | + get_buffered_line(); |
| 226 | + my_len = 0; |
| 227 | + while ((buf_len > 0) && (len > 0)) { |
| 228 | + *ptr++ = buf[start_ndx]; |
| 229 | + start_ndx = inc_ndx(start_ndx); |
| 230 | + my_len++; |
| 231 | + len--; |
| 232 | + } |
| 233 | + return my_len; /* return the length we got */ |
| 234 | +} |
0 commit comments