2 * (C) Copyright 2014 - 2017 Leo C. <erbl259-lmu@yahoo.de>
4 * SPDX-License-Identifier: GPL-2.0
12 #include <libopencm3/stm32/rcc.h>
13 #include <libopencm3/stm32/gpio.h>
14 #include <libopencm3/stm32/usart.h>
15 #include <libopencm3/cm3/nvic.h>
17 #if (USART_CONSOLE == 1)
19 #define CON_GPIO GPIOA
20 #elif (USART_CONSOLE == 2)
22 #define CON_GPIO GPIOA
23 #elif (USART_CONSOLE == 3)
25 #define CON_GPIO GPIOB
27 #error USART_CONSOLE undefined or invalid value
30 #define CONCAT2(a,b) a##b
31 #define CONCAT(a,b) CONCAT2(a,b)
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)
43 int _write(int fd
, char *ptr
, int len
) __attribute__((used
));
54 #define BUFFER_SIZE 256
58 uint8_t rx_ring_buffer
[BUFFER_SIZE
];
59 uint8_t tx_ring_buffer
[BUFFER_SIZE
];
62 static void ring_init(struct ring
*ring
, uint8_t *buf
, int size
)
70 static int ring_write_ch(struct ring
*ring
, uint8_t ch
)
72 int ep
= (ring
->end
+ 1) % ring
->size
;
74 if ((ep
) != ring
->begin
) {
75 ring
->data
[ring
->end
] = ch
;
84 static int ring_write(struct ring
*ring
, uint8_t *data
, int size
)
88 for (i
= 0; i
< size
; i
++) {
89 if (ring_write_ch(ring
, data
[i
]) < 0)
97 static int ring_read_ch(struct ring
*ring
)
101 if (ring
->begin
!= ring
->end
) {
102 ret
= ring
->data
[ring
->begin
];
103 ring
->begin
= (ring
->begin
+1) % ring
->size
;
109 void usart_setup(int baud
)
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
);
115 rcc_periph_clock_enable(RCC_USART_CON
);
117 /* Enable the USART_CONSOLE interrupt. */
118 nvic_enable_irq(CON_IRQ
);
119 nvic_set_priority(CON_IRQ
, 6*16);
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
);
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
);
136 /* Enable CONSOLE Receive interrupt. */
137 USART_CR1(CON_USART
) |= USART_CR1_RXNEIE
;
139 /* Finally enable the USART. */
140 usart_enable(CON_USART
);
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)) {
150 /* Retrieve the data from the peripheral. */
151 ring_write_ch(&rx_ring
, USART_DR(CON_USART
) & USART_DR_MASK
);
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)) {
161 data
= ring_read_ch(&tx_ring
);
164 /* Disable the TXE interrupt, it's no longer needed. */
165 USART_CR1(CON_USART
) &= ~USART_CR1_TXEIE
;
167 /* Put data into the transmit register. */
168 usart_send(CON_USART
, data
);
173 /*--------------------------------------------------------------------------*/
175 void serial_setup(int baud
)
180 void serial_setbaudrate(int baud
)
182 usart_set_baudrate(CON_USART
, baud
);
185 /*--------------------------------------------------------------------------*/
188 * Use USART_CONSOLE as a console.
189 * This is a syscall for newlib
195 int _write(int fd
, char *ptr
, int len
)
199 if (fd
== STDOUT_FILENO
|| fd
== STDERR_FILENO
) {
200 for (i
= 0; i
< len
; i
++) {
201 if (ptr
[i
] == '\n') {
212 int serial_getc(void)
214 return ring_read_ch(&rx_ring
);
217 void serial_putc(int data
)
219 while (ring_write_ch(&tx_ring
, data
) < 0)
222 /* Enable the TXE interrupt. */
223 USART_CR1(CON_USART
) |= USART_CR1_TXEIE
;