]> cloudbase.mooo.com Git - irmp-demo.git/blob - serial.c
Rename TIM_IRMP --> IRMP_TIMER
[irmp-demo.git] / serial.c
1 /*
2 * (C) Copyright 2014 - 2017 Leo C. <erbl259-lmu@yahoo.de>
3 *
4 * SPDX-License-Identifier: GPL-2.0
5 */
6
7 #include "serial.h"
8 #include "config.h"
9 #include <errno.h>
10 #include <stdio.h>
11 #include <unistd.h>
12 #include <libopencm3/stm32/rcc.h>
13 #include <libopencm3/stm32/gpio.h>
14 #include <libopencm3/stm32/usart.h>
15 #include <libopencm3/cm3/nvic.h>
16
17 #if (USART_CONSOLE == 1)
18 #define CON_PORT A
19 #define CON_GPIO GPIOA
20 #elif (USART_CONSOLE == 2)
21 #define CON_PORT A
22 #define CON_GPIO GPIOA
23 #elif (USART_CONSOLE == 3)
24 #define CON_PORT B
25 #define CON_GPIO GPIOB
26 #else
27 #error USART_CONSOLE undefined or invalid value
28 #endif
29
30 #define CONCAT2(a,b) a##b
31 #define CONCAT(a,b) CONCAT2(a,b)
32
33
34 #define CON_USART CONCAT(USART,USART_CONSOLE)
35 #define CON_IRQ CONCAT(CONCAT(NVIC_USART, USART_CONSOLE), _IRQ)
36 #define CON_isr CONCAT(CONCAT(usart, USART_CONSOLE), _isr)
37 #define CON_GPIO_RX CONCAT(CONCAT(GPIO_USART, USART_CONSOLE), _RX)
38 #define CON_GPIO_TX CONCAT(CONCAT(GPIO_USART, USART_CONSOLE), _TX)
39 #define RCC_USART_CON CONCAT(RCC_USART, USART_CONSOLE)
40 #define RCC_GPIO_CON CONCAT(RCC_GPIO, CON_PORT)
41
42
43 int _write(int fd, char *ptr, int len) __attribute__((used));
44
45
46 struct ring {
47 uint8_t *data;
48 int size;
49 volatile int begin;
50 volatile int end;
51 };
52
53
54 #define BUFFER_SIZE 256
55
56 struct ring rx_ring;
57 struct ring tx_ring;
58 uint8_t rx_ring_buffer[BUFFER_SIZE];
59 uint8_t tx_ring_buffer[BUFFER_SIZE];
60
61
62 static void ring_init(struct ring *ring, uint8_t *buf, int size)
63 {
64 ring->data = buf;
65 ring->size = size;
66 ring->begin = 0;
67 ring->end = 0;
68 }
69
70 static int ring_write_ch(struct ring *ring, uint8_t ch)
71 {
72 int ep = (ring->end + 1) % ring->size;
73
74 if ((ep) != ring->begin) {
75 ring->data[ring->end] = ch;
76 ring->end = ep;
77 return 1;
78 }
79
80 return -1;
81 }
82
83 #if 0 /* unused */
84 static int ring_write(struct ring *ring, uint8_t *data, int size)
85 {
86 int i;
87
88 for (i = 0; i < size; i++) {
89 if (ring_write_ch(ring, data[i]) < 0)
90 return -i;
91 }
92
93 return i;
94 }
95 #endif
96
97 static int ring_read_ch(struct ring *ring)
98 {
99 int ret = -1;
100
101 if (ring->begin != ring->end) {
102 ret = ring->data[ring->begin];
103 ring->begin = (ring->begin +1) % ring->size;
104 }
105
106 return ret;
107 }
108
109 void usart_setup(int baud)
110 {
111 /* Initialize output ring buffer. */
112 ring_init(&rx_ring, rx_ring_buffer, BUFFER_SIZE);
113 ring_init(&tx_ring, tx_ring_buffer, BUFFER_SIZE);
114
115 rcc_periph_clock_enable(RCC_USART_CON);
116
117 /* Enable the USART_CONSOLE interrupt. */
118 nvic_enable_irq(CON_IRQ);
119 nvic_set_priority(CON_IRQ, 6*16);
120
121 /* Setup GPIO pins for CONSOLE TX/RX */
122 rcc_periph_clock_enable(RCC_GPIO_CON);
123 gpio_set_mode(CON_GPIO, GPIO_MODE_OUTPUT_2_MHZ,
124 GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, CON_GPIO_TX);
125 gpio_set_mode(CON_GPIO, GPIO_MODE_INPUT,
126 GPIO_CNF_INPUT_FLOAT, CON_GPIO_RX);
127
128 /* Setup UART parameters. */
129 usart_set_baudrate(CON_USART, baud);
130 usart_set_databits(CON_USART, 8);
131 usart_set_stopbits(CON_USART, USART_STOPBITS_1);
132 usart_set_parity(CON_USART, USART_PARITY_NONE);
133 usart_set_flow_control(CON_USART, USART_FLOWCONTROL_NONE);
134 usart_set_mode(CON_USART, USART_MODE_TX_RX);
135
136 /* Enable CONSOLE Receive interrupt. */
137 USART_CR1(CON_USART) |= USART_CR1_RXNEIE;
138
139 /* Finally enable the USART. */
140 usart_enable(CON_USART);
141 }
142
143
144 void CON_isr(void)
145 {
146 /* Check if we were called because of RXNE. */
147 if (((USART_CR1(CON_USART) & USART_CR1_RXNEIE) != 0) &&
148 ((USART_SR(CON_USART) & USART_SR_RXNE) != 0)) {
149
150 /* Retrieve the data from the peripheral. */
151 ring_write_ch(&rx_ring, USART_DR(CON_USART) & USART_DR_MASK);
152
153 }
154
155 /* Check if we were called because of TXE. */
156 if (((USART_CR1(CON_USART) & USART_CR1_TXEIE) != 0) &&
157 ((USART_SR(CON_USART) & USART_SR_TXE) != 0)) {
158
159 int data;
160
161 data = ring_read_ch(&tx_ring);
162
163 if (data == -1) {
164 /* Disable the TXE interrupt, it's no longer needed. */
165 USART_CR1(CON_USART) &= ~USART_CR1_TXEIE;
166 } else {
167 /* Put data into the transmit register. */
168 usart_send(CON_USART, data);
169 }
170 }
171 }
172
173 /*--------------------------------------------------------------------------*/
174
175 void serial_setup(int baud)
176 {
177 usart_setup(baud);
178 }
179
180 void serial_setbaudrate(int baud)
181 {
182 usart_set_baudrate(CON_USART, baud);
183 }
184
185 /*--------------------------------------------------------------------------*/
186
187 /**
188 * Use USART_CONSOLE as a console.
189 * This is a syscall for newlib
190 * @param fd
191 * @param ptr
192 * @param len
193 * @return
194 */
195 int _write(int fd, char *ptr, int len)
196 {
197 int i;
198
199 if (fd == STDOUT_FILENO || fd == STDERR_FILENO) {
200 for (i = 0; i < len; i++) {
201 if (ptr[i] == '\n') {
202 serial_putc('\r');
203 }
204 serial_putc(ptr[i]);
205 }
206 return i;
207 }
208 errno = EIO;
209 return -1;
210 }
211
212 int serial_getc(void)
213 {
214 return ring_read_ch(&rx_ring);
215 }
216
217 void serial_putc(int data)
218 {
219 while (ring_write_ch(&tx_ring, data) < 0)
220 ;
221
222 /* Enable the TXE interrupt. */
223 USART_CR1(CON_USART) |= USART_CR1_TXEIE;
224 }