2 * This file is part of Cleanflight.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
20 * Dominic Clifton - Serial port abstraction, Separation of common STM32 code for cleanflight, various cleanups.
21 * Hamasaki/Timecop - Initial baseflight code
28 #include "build/build_config.h"
30 #include "common/utils.h"
32 #include "drivers/uart_inverter.h"
35 #include "serial_uart.h"
36 #include "serial_uart_impl.h"
38 static void usartConfigurePinInversion(uartPort_t
*uartPort
) {
39 #if !defined(USE_UART_INVERTER)
42 bool inverted
= uartPort
->port
.options
& SERIAL_INVERTED
;
44 #ifdef USE_UART_INVERTER
45 uartInverterLine_e invertedLines
= UART_INVERTER_LINE_NONE
;
46 if (uartPort
->port
.mode
& MODE_RX
) {
47 invertedLines
|= UART_INVERTER_LINE_RX
;
49 if (uartPort
->port
.mode
& MODE_TX
) {
50 invertedLines
|= UART_INVERTER_LINE_TX
;
52 uartInverterSet(uartPort
->USARTx
, invertedLines
, inverted
);
58 static void uartReconfigure(uartPort_t
*uartPort
)
60 usart_enable(uartPort
->USARTx
, FALSE
);
61 uint32_t baud_rate
= 115200;
62 usart_data_bit_num_type data_bit
= USART_DATA_8BITS
;
63 usart_stop_bit_num_type stop_bit
= USART_STOP_1_BIT
;
64 usart_parity_selection_type parity_type
= USART_PARITY_EVEN
;
66 baud_rate
= uartPort
->port
.baudRate
;
67 stop_bit
= (uartPort
->port
.options
& SERIAL_STOPBITS_2
) ? USART_STOP_2_BIT
: USART_STOP_1_BIT
;
69 // according to the stm32 documentation wordlen has to be 9 for parity bits
70 // this does not seem to matter for rx but will give bad data on tx!
71 if (uartPort
->port
.options
& SERIAL_PARITY_EVEN
) {
72 data_bit
= USART_DATA_9BITS
;
74 data_bit
= USART_DATA_8BITS
;
76 usart_init(uartPort
->USARTx
, baud_rate
, data_bit
, stop_bit
);
78 parity_type
= (uartPort
->port
.options
& SERIAL_PARITY_EVEN
) ? USART_PARITY_EVEN
: USART_PARITY_NONE
;
79 usart_parity_selection_config(uartPort
->USARTx
, parity_type
);
80 usart_hardware_flow_control_set (uartPort
->USARTx
, USART_HARDWARE_FLOW_NONE
);
82 if (uartPort
->port
.mode
& MODE_RX
)
83 usart_receiver_enable(uartPort
->USARTx
, TRUE
);
84 if (uartPort
->port
.mode
& MODE_TX
)
85 usart_transmitter_enable(uartPort
->USARTx
, TRUE
);
87 usartConfigurePinInversion(uartPort
);
88 uartConfigurePinSwap(uartPort
);
90 if (uartPort
->port
.options
& SERIAL_BIDIR
)
91 usart_single_line_halfduplex_select(uartPort
->USARTx
, TRUE
);
93 usart_single_line_halfduplex_select(uartPort
->USARTx
, FALSE
);
95 usart_enable(uartPort
->USARTx
, TRUE
);
98 serialPort_t
*uartOpen(usart_type
*USARTx
, serialReceiveCallbackPtr rxCallback
, void *rxCallbackData
, uint32_t baudRate
, portMode_t mode
, portOptions_t options
)
100 uartPort_t
*s
= NULL
;
104 } else if (USARTx
== USART1
) {
105 s
= serialUART1(baudRate
, mode
, options
);
109 } else if (USARTx
== USART2
) {
110 s
= serialUART2(baudRate
, mode
, options
);
113 } else if (USARTx
== USART3
) {
114 s
= serialUART3(baudRate
, mode
, options
);
117 } else if (USARTx
== UART4
) {
118 s
= serialUART4(baudRate
, mode
, options
);
121 } else if (USARTx
== UART5
) {
122 s
= serialUART5(baudRate
, mode
, options
);
125 } else if (USARTx
== USART6
) {
126 s
= serialUART6(baudRate
, mode
, options
);
129 } else if (USARTx
== UART7
) {
130 s
= serialUART7(baudRate
, mode
, options
);
133 } else if (USARTx
== UART8
) {
134 s
= serialUART8(baudRate
, mode
, options
);
138 return (serialPort_t
*)s
;
141 // common serial initialisation code should move to serialPort::init()
142 s
->port
.rxBufferHead
= s
->port
.rxBufferTail
= 0;
143 s
->port
.txBufferHead
= s
->port
.txBufferTail
= 0;
144 // callback works for IRQ-based RX ONLY
145 s
->port
.rxCallback
= rxCallback
;
146 s
->port
.rxCallbackData
= rxCallbackData
;
148 s
->port
.baudRate
= baudRate
;
149 s
->port
.options
= options
;
153 if (mode
& MODE_RX
) {
154 usart_flag_clear(s
->USARTx
, USART_RDBF_FLAG
);
155 usart_interrupt_enable (s
->USARTx
, USART_RDBF_INT
, TRUE
);
159 if (mode
& MODE_TX
) {
160 usart_interrupt_enable (s
->USARTx
, USART_TDBE_INT
, TRUE
);
163 usart_enable(s
->USARTx
, TRUE
);
165 return (serialPort_t
*)s
;
168 void uartSetBaudRate(serialPort_t
*instance
, uint32_t baudRate
)
170 uartPort_t
*uartPort
= (uartPort_t
*)instance
;
171 uartPort
->port
.baudRate
= baudRate
;
172 uartReconfigure(uartPort
);
175 void uartSetMode(serialPort_t
*instance
, portMode_t mode
)
177 uartPort_t
*uartPort
= (uartPort_t
*)instance
;
178 uartPort
->port
.mode
= mode
;
179 uartReconfigure(uartPort
);
182 void uartSetOptions(serialPort_t
*instance
, portOptions_t options
)
184 uartPort_t
*uartPort
= (uartPort_t
*)instance
;
185 uartPort
->port
.options
= options
;
186 uartReconfigure(uartPort
);
189 uint32_t uartTotalRxBytesWaiting(const serialPort_t
*instance
)
191 const uartPort_t
*s
= (const uartPort_t
*)instance
;
193 if (s
->port
.rxBufferHead
>= s
->port
.rxBufferTail
) {
194 return s
->port
.rxBufferHead
- s
->port
.rxBufferTail
;
196 return s
->port
.rxBufferSize
+ s
->port
.rxBufferHead
- s
->port
.rxBufferTail
;
200 uint32_t uartTotalTxBytesFree(const serialPort_t
*instance
)
202 const uartPort_t
*s
= (const uartPort_t
*)instance
;
206 if (s
->port
.txBufferHead
>= s
->port
.txBufferTail
) {
207 bytesUsed
= s
->port
.txBufferHead
- s
->port
.txBufferTail
;
209 bytesUsed
= s
->port
.txBufferSize
+ s
->port
.txBufferHead
- s
->port
.txBufferTail
;
212 return (s
->port
.txBufferSize
- 1) - bytesUsed
;
215 bool isUartTransmitBufferEmpty(const serialPort_t
*instance
)
217 const uartPort_t
*s
= (const uartPort_t
*)instance
;
218 return s
->port
.txBufferTail
== s
->port
.txBufferHead
;
221 uint8_t uartRead(serialPort_t
*instance
)
224 uartPort_t
*s
= (uartPort_t
*)instance
;
226 ch
= s
->port
.rxBuffer
[s
->port
.rxBufferTail
];
227 if (s
->port
.rxBufferTail
+ 1 >= s
->port
.rxBufferSize
) {
228 s
->port
.rxBufferTail
= 0;
230 s
->port
.rxBufferTail
++;
236 void uartWrite(serialPort_t
*instance
, uint8_t ch
)
238 uartPort_t
*s
= (uartPort_t
*)instance
;
239 s
->port
.txBuffer
[s
->port
.txBufferHead
] = ch
;
240 if (s
->port
.txBufferHead
+ 1 >= s
->port
.txBufferSize
) {
241 s
->port
.txBufferHead
= 0;
243 s
->port
.txBufferHead
++;
246 usart_interrupt_enable (s
->USARTx
, USART_TDBE_INT
, TRUE
);
250 bool isUartIdle(serialPort_t
*instance
)
252 uartPort_t
*s
= (uartPort_t
*)instance
;
253 if(usart_flag_get(s
->USARTx
, USART_IDLEF_FLAG
)) {
255 uartClearIdleFlag(s
);
262 const struct serialPortVTable uartVTable
[] = {
264 .serialWrite
= uartWrite
,
265 .serialTotalRxWaiting
= uartTotalRxBytesWaiting
,
266 .serialTotalTxFree
= uartTotalTxBytesFree
,
267 .serialRead
= uartRead
,
268 .serialSetBaudRate
= uartSetBaudRate
,
269 .isSerialTransmitBufferEmpty
= isUartTransmitBufferEmpty
,
270 .setMode
= uartSetMode
,
271 .setOptions
= uartSetOptions
,
276 .isIdle
= isUartIdle
,