]>
Commit | Line | Data |
---|---|---|
6b81b39f L |
1 | /* |
2 | * serial.c | |
3 | * | |
4 | * Created on: 04.05.2014 | |
5 | * Author: leo | |
6 | */ | |
7 | ||
8 | #include <errno.h> | |
9 | #include <stdio.h> | |
10 | #include <unistd.h> | |
11 | ||
12 | #include <libopencm3/stm32/gpio.h> | |
13 | #include <libopencm3/stm32/usart.h> | |
14 | #include <libopencm3/cm3/nvic.h> | |
15 | #include "serial.h" | |
16 | ||
17 | ||
18 | #define USART_CONSOLE USART1 | |
19 | ||
20 | int _write(int fd, char *ptr, int len) __attribute__((used)); | |
21 | ||
22 | ||
23 | struct ring { | |
24 | uint8_t *data; | |
25 | int size; | |
26 | volatile int begin; | |
27 | volatile int end; | |
28 | }; | |
29 | ||
30 | ||
31 | #define BUFFER_SIZE 256 | |
32 | ||
33 | struct ring rx_ring; | |
34 | struct ring tx_ring; | |
35 | uint8_t rx_ring_buffer[BUFFER_SIZE]; | |
36 | uint8_t tx_ring_buffer[BUFFER_SIZE]; | |
37 | ||
38 | ||
39 | static void ring_init(struct ring *ring, uint8_t *buf, int size) | |
40 | { | |
41 | ring->data = buf; | |
42 | ring->size = size; | |
43 | ring->begin = 0; | |
44 | ring->end = 0; | |
45 | } | |
46 | ||
47 | static int ring_write_ch(struct ring *ring, uint8_t ch) | |
48 | { | |
49 | int ep = (ring->end + 1) % ring->size; | |
50 | ||
51 | if ((ep) != ring->begin) { | |
52 | ring->data[ring->end] = ch; | |
53 | ring->end = ep; | |
54 | return 1; | |
55 | } | |
56 | ||
57 | return -1; | |
58 | } | |
59 | ||
60 | static int ring_write(struct ring *ring, uint8_t *data, int size) | |
61 | { | |
62 | int i; | |
63 | ||
64 | for (i = 0; i < size; i++) { | |
65 | if (ring_write_ch(ring, data[i]) < 0) | |
66 | return -i; | |
67 | } | |
68 | ||
69 | return i; | |
70 | } | |
71 | ||
72 | static int ring_read_ch(struct ring *ring) | |
73 | { | |
74 | int ret = -1; | |
75 | ||
76 | if (ring->begin != ring->end) { | |
77 | ret = ring->data[ring->begin]; | |
78 | ring->begin = (ring->begin +1) % ring->size; | |
79 | } | |
80 | ||
81 | return ret; | |
82 | } | |
83 | ||
84 | void usart_setup(void) | |
85 | { | |
86 | /* Initialize output ring buffer. */ | |
87 | ring_init(&rx_ring, rx_ring_buffer, BUFFER_SIZE); | |
88 | ring_init(&tx_ring, tx_ring_buffer, BUFFER_SIZE); | |
89 | ||
90 | /* Enable the USART1 interrupt. */ | |
91 | nvic_enable_irq(NVIC_USART1_IRQ); | |
92 | ||
93 | /* Setup GPIO pin GPIO_USART1_TX/LED_GREEN_PIN on GPIO port A for transmit. */ | |
94 | /* TODO: USART1 --> USART_CONSOLE */ | |
95 | ||
96 | gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, | |
97 | GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART1_TX); | |
98 | ||
99 | /* Setup GPIO pin GPIO_USART1_RE_RX on GPIO port B for receive. */ | |
100 | gpio_set_mode(GPIOA, GPIO_MODE_INPUT, | |
101 | GPIO_CNF_INPUT_FLOAT, GPIO_USART1_RX); | |
102 | ||
103 | /* Setup UART parameters. */ | |
104 | // usart_set_baudrate(USART_CONSOLE, 38400); | |
105 | usart_set_baudrate(USART_CONSOLE, 115200); | |
106 | usart_set_databits(USART_CONSOLE, 8); | |
107 | usart_set_stopbits(USART_CONSOLE, USART_STOPBITS_1); | |
108 | usart_set_parity(USART_CONSOLE, USART_PARITY_NONE); | |
109 | usart_set_flow_control(USART_CONSOLE, USART_FLOWCONTROL_NONE); | |
110 | usart_set_mode(USART_CONSOLE, USART_MODE_TX_RX); | |
111 | ||
112 | /* Enable USART1 Receive interrupt. */ | |
113 | USART_CR1(USART1) |= USART_CR1_RXNEIE; | |
114 | ||
115 | /* Finally enable the USART. */ | |
116 | usart_enable(USART_CONSOLE); | |
117 | } | |
118 | ||
119 | void usart1_isr(void) | |
120 | { | |
121 | /* Check if we were called because of RXNE. */ | |
122 | if (((USART_CR1(USART1) & USART_CR1_RXNEIE) != 0) && | |
123 | ((USART_SR(USART1) & USART_SR_RXNE) != 0)) { | |
124 | ||
125 | /* Retrieve the data from the peripheral. */ | |
126 | ring_write_ch(&rx_ring, usart_recv(USART1)); | |
127 | ||
128 | } | |
129 | ||
130 | /* Check if we were called because of TXE. */ | |
131 | if (((USART_CR1(USART1) & USART_CR1_TXEIE) != 0) && | |
132 | ((USART_SR(USART1) & USART_SR_TXE) != 0)) { | |
133 | ||
134 | int data; | |
135 | ||
136 | data = ring_read_ch(&tx_ring); | |
137 | ||
138 | if (data == -1) { | |
139 | /* Disable the TXE interrupt, it's no longer needed. */ | |
140 | USART_CR1(USART1) &= ~USART_CR1_TXEIE; | |
141 | } else { | |
142 | /* Put data into the transmit register. */ | |
143 | usart_send(USART1, data); | |
144 | } | |
145 | } | |
146 | } | |
147 | ||
148 | /*--------------------------------------------------------------------------*/ | |
149 | ||
150 | void serial_setup(void) | |
151 | { | |
152 | usart_setup(); | |
153 | } | |
154 | ||
155 | /*--------------------------------------------------------------------------*/ | |
156 | ||
157 | /** | |
158 | * Use USART_CONSOLE as a console. | |
159 | * This is a syscall for newlib | |
160 | * @param fd | |
161 | * @param ptr | |
162 | * @param len | |
163 | * @return | |
164 | */ | |
165 | int _write(int fd, char *ptr, int len) | |
166 | { | |
167 | int i; | |
168 | ||
169 | if (fd == STDOUT_FILENO || fd == STDERR_FILENO) { | |
170 | for (i = 0; i < len; i++) { | |
171 | if (ptr[i] == '\n') { | |
172 | serial_putc('\r'); | |
173 | } | |
174 | serial_putc(ptr[i]); | |
175 | } | |
176 | return i; | |
177 | } | |
178 | errno = EIO; | |
179 | return -1; | |
180 | } | |
181 | ||
182 | int serial_getc(void) | |
183 | { | |
184 | return ring_read_ch(&rx_ring); | |
185 | } | |
186 | ||
187 | void serial_putc(uint8_t data) | |
188 | { | |
189 | while (ring_write_ch(&tx_ring, data) < 0) | |
190 | ; | |
191 | ||
192 | /* Enable the TXE interrupt. */ | |
193 | USART_CR1(USART1) |= USART_CR1_TXEIE; | |
194 | } |