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