/ src / io.c
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  }