io.c
1 // Copyright © 2014 Jeff Epler 2 // 3 // This program is free software; you can redistribute it and/or modify 4 // it under the terms of the GNU General Public License as published by 5 // the Free Software Foundation; either version 2 of the License, or 6 // (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU General Public License for more details. 12 // 13 // You should have received a copy of the GNU General Public License 14 // along with this program; if not, write to the Free Software 15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 16 17 #include "io.h" 18 #include <libopencm3/stm32/usart.h> 19 #include <libopencm3/stm32/rcc.h> 20 #include <libopencm3/stm32/gpio.h> 21 #include <libopencm3/cm3/cortex.h> 22 #include <libopencm3/cm3/nvic.h> 23 24 #define GPIO_USART1_TX_PORT GPIOA 25 #define GPIO_USART1_TX_PIN GPIO9 26 #define GPIO_USART1_TX_AFNO GPIO_AF7 27 #define GPIO_USART1_RX_PORT GPIOA 28 #define GPIO_USART1_RX_PIN GPIO10 29 #define GPIO_USART1_RX_AFNO GPIO_AF7 30 31 struct ring { 32 uint16_t begin, end; 33 char data[508]; 34 }; 35 36 #define RING_DATA(ring) ((ring)->data) 37 #define RING_SIZE(ring) sizeof(RING_DATA(ring)) 38 #define RING_BEGIN(ring) ((ring)->begin) 39 #define RING_END(ring) ((ring)->end) 40 #define RING_EMPTY(ring) (RING_BEGIN(ring) == RING_END(ring)) 41 #define RING_NEXT(ring,i) ((i) == RING_SIZE(ring) - 1 ? 0 : (i) + 1) 42 #define RING_NEXT_END(ring) (RING_NEXT((ring), RING_END(ring))) 43 #define RING_NEXT_BEGIN(ring) (RING_NEXT((ring), RING_BEGIN(ring))) 44 #define RING_ADVANCE_END(ring) (RING_END(ring) = RING_NEXT_END(ring)) 45 #define RING_ADVANCE_BEGIN(ring) (RING_BEGIN(ring) = RING_NEXT_BEGIN(ring)) 46 #define RING_FULL(ring) (RING_NEXT_END(ring) == RING_BEGIN(ring)) 47 48 static int ring_put(struct ring *ring, char ch) { 49 if(RING_FULL(ring)) return -1; 50 RING_DATA(ring)[RING_END(ring)] = ch; 51 RING_ADVANCE_END(ring); 52 return 0; 53 } 54 55 static struct ring output; 56 57 void usart_setup(void) 58 { 59 /* Enable clocks for GPIO port A (for GPIO_USART1_TX) and USART1. */ 60 rcc_periph_clock_enable(RCC_USART1); 61 rcc_periph_clock_enable(RCC_GPIOA); 62 63 /* Setup GPIO pin GPIO_USART1_RE_TX on GPIO port B for transmit. */ 64 gpio_mode_setup(GPIO_USART1_TX_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_USART1_TX_PIN); 65 gpio_set_af(GPIO_USART1_TX_PORT, GPIO_USART1_TX_AFNO, GPIO_USART1_TX_PIN); 66 67 /* Setup GPIO pin GPIO_USART1_RE_RX on GPIO port B for receive. */ 68 gpio_mode_setup(GPIO_USART1_TX_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_USART1_TX_PIN); 69 gpio_set_af(GPIO_USART1_RX_PORT, GPIO_USART1_RX_AFNO, GPIO_USART1_RX_PIN); 70 71 /* Setup UART parameters. */ 72 usart_set_baudrate(USART1, 1000000); 73 usart_set_databits(USART1, 8); 74 usart_set_stopbits(USART1, USART_STOPBITS_1); 75 usart_set_parity(USART1, USART_PARITY_NONE); 76 usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE); 77 usart_set_mode(USART1, USART_MODE_TX_RX); 78 79 /* Enable the USART1 interrupt. */ 80 nvic_enable_irq(NVIC_USART1_EXTI25_IRQ); 81 82 /* Finally enable the USART. */ 83 usart_enable(USART1); 84 } 85 86 void writec(int c) { 87 cm_disable_interrupts(); 88 int r = ring_put(&output, c); 89 if(r != -1) 90 USART_CR1(USART1) |= USART_CR1_TXEIE; 91 cm_enable_interrupts(); 92 } 93 94 void writes(const char *s) { 95 while(*s) writec(*s++); 96 } 97 98 99 void writex(unsigned d, int md) { 100 const char hexdigits[16] = "0123456789abcdef"; 101 char buf[24], *ptr = buf + sizeof(buf); 102 *--ptr = 0; 103 do { 104 *--ptr = hexdigits[d % 16]; 105 d /= 16; 106 } while(--md || d); 107 writes(ptr); 108 } 109 110 void writed(int d) { 111 char buf[24], *ptr = buf + sizeof(buf); 112 *--ptr = 0; 113 if(d < 0) { writec('-'); d = -d; } 114 do { 115 *--ptr = '0' + d % 10; 116 d /= 10; 117 } while(d); 118 writes(ptr); 119 } 120 121 void usart1_exti25_isr(void) { 122 if (((USART_CR1(USART1) & USART_CR1_TXEIE) != 0) && 123 ((USART_ISR(USART1) & USART_ISR_TXE) != 0)) { 124 USART_TDR(USART1) = RING_DATA(&output)[RING_BEGIN(&output)]; 125 RING_ADVANCE_BEGIN(&output); 126 if(RING_EMPTY(&output)) USART_CR1(USART1) &= ~USART_CR1_TXEIE; 127 } 128 } 129 130 typedef int FILEHANDLE; 131 /* Standard IO device handles. */ 132 #define STDIN 0 133 #define STDOUT 1 134 #define STDERR 2 135 136 int _write(FILEHANDLE fh, const uint8_t *buf, uint32_t len, int mode); 137 int _write(FILEHANDLE fh, const uint8_t *buf, uint32_t len, int mode) { 138 if(fh != STDOUT && fh != STDERR) return -1; 139 int result = len; 140 while(len--) writec(*buf++); 141 return result; 142 }