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
29 #include "build/build_config.h"
31 #include "common/utils.h"
32 #include "drivers/io.h"
33 #include "drivers/nvic.h"
36 #include "serial_uart.h"
37 #include "serial_uart_impl.h"
39 static void usartConfigurePinInversion(uartPort_t
*uartPort
) {
40 bool inverted
= uartPort
->port
.options
& SERIAL_INVERTED
;
44 if (uartPort
->port
.mode
& MODE_RX
)
46 uartPort
->Handle
.AdvancedInit
.AdvFeatureInit
|= UART_ADVFEATURE_RXINVERT_INIT
;
47 uartPort
->Handle
.AdvancedInit
.RxPinLevelInvert
= UART_ADVFEATURE_RXINV_ENABLE
;
49 if (uartPort
->port
.mode
& MODE_TX
)
51 uartPort
->Handle
.AdvancedInit
.AdvFeatureInit
|= UART_ADVFEATURE_TXINVERT_INIT
;
52 uartPort
->Handle
.AdvancedInit
.TxPinLevelInvert
= UART_ADVFEATURE_TXINV_ENABLE
;
57 static void uartReconfigure(uartPort_t
*uartPort
)
59 /*RCC_PeriphCLKInitTypeDef RCC_PeriphClkInit;
60 RCC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_USART2|RCC_PERIPHCLK_USART3|
61 RCC_PERIPHCLK_UART4|RCC_PERIPHCLK_UART5|RCC_PERIPHCLK_USART6|RCC_PERIPHCLK_UART7|RCC_PERIPHCLK_UART8;
62 RCC_PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_SYSCLK;
63 RCC_PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_SYSCLK;
64 RCC_PeriphClkInit.Usart3ClockSelection = RCC_USART3CLKSOURCE_SYSCLK;
65 RCC_PeriphClkInit.Uart4ClockSelection = RCC_UART4CLKSOURCE_SYSCLK;
66 RCC_PeriphClkInit.Uart5ClockSelection = RCC_UART5CLKSOURCE_SYSCLK;
67 RCC_PeriphClkInit.Usart6ClockSelection = RCC_USART6CLKSOURCE_SYSCLK;
68 RCC_PeriphClkInit.Uart7ClockSelection = RCC_UART7CLKSOURCE_SYSCLK;
69 RCC_PeriphClkInit.Uart8ClockSelection = RCC_UART8CLKSOURCE_SYSCLK;
70 HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphClkInit);*/
72 HAL_UART_DeInit(&uartPort
->Handle
);
73 uartPort
->Handle
.Init
.BaudRate
= uartPort
->port
.baudRate
;
74 uartPort
->Handle
.Init
.WordLength
= (uartPort
->port
.options
& SERIAL_PARITY_EVEN
) ? UART_WORDLENGTH_9B
: UART_WORDLENGTH_8B
;
75 uartPort
->Handle
.Init
.StopBits
= (uartPort
->port
.options
& SERIAL_STOPBITS_2
) ? USART_STOPBITS_2
: USART_STOPBITS_1
;
76 uartPort
->Handle
.Init
.Parity
= (uartPort
->port
.options
& SERIAL_PARITY_EVEN
) ? USART_PARITY_EVEN
: USART_PARITY_NONE
;
77 uartPort
->Handle
.Init
.HwFlowCtl
= UART_HWCONTROL_NONE
;
78 uartPort
->Handle
.Init
.OneBitSampling
= UART_ONE_BIT_SAMPLE_DISABLE
;
79 uartPort
->Handle
.Init
.Mode
= 0;
81 if (uartPort
->port
.mode
& MODE_RX
)
82 uartPort
->Handle
.Init
.Mode
|= UART_MODE_RX
;
83 if (uartPort
->port
.mode
& MODE_TX
)
84 uartPort
->Handle
.Init
.Mode
|= UART_MODE_TX
;
87 usartConfigurePinInversion(uartPort
);
89 if (uartPort
->port
.options
& SERIAL_BIDIR
)
91 HAL_HalfDuplex_Init(&uartPort
->Handle
);
95 HAL_UART_Init(&uartPort
->Handle
);
98 if (uartPort
->port
.mode
& MODE_RX
) {
99 /* Enable the UART Parity Error Interrupt */
100 SET_BIT(uartPort
->USARTx
->CR1
, USART_CR1_PEIE
);
102 /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
103 SET_BIT(uartPort
->USARTx
->CR3
, USART_CR3_EIE
);
105 /* Enable the UART Data Register not empty Interrupt */
106 SET_BIT(uartPort
->USARTx
->CR1
, USART_CR1_RXNEIE
);
110 if (uartPort
->port
.mode
& MODE_TX
) {
111 /* Enable the UART Transmit Data Register Empty Interrupt */
112 SET_BIT(uartPort
->USARTx
->CR1
, USART_CR1_TXEIE
);
117 serialPort_t
*uartOpen(USART_TypeDef
*USARTx
, serialReceiveCallbackPtr callback
, void *rxCallbackData
, uint32_t baudRate
, portMode_t mode
, portOptions_t options
)
119 uartPort_t
*s
= NULL
;
123 } else if (USARTx
== USART1
) {
124 s
= serialUART1(baudRate
, mode
, options
);
127 } else if (USARTx
== USART2
) {
128 s
= serialUART2(baudRate
, mode
, options
);
131 } else if (USARTx
== USART3
) {
132 s
= serialUART3(baudRate
, mode
, options
);
135 } else if (USARTx
== UART4
) {
136 s
= serialUART4(baudRate
, mode
, options
);
139 } else if (USARTx
== UART5
) {
140 s
= serialUART5(baudRate
, mode
, options
);
143 } else if (USARTx
== USART6
) {
144 s
= serialUART6(baudRate
, mode
, options
);
147 } else if (USARTx
== UART7
) {
148 s
= serialUART7(baudRate
, mode
, options
);
151 } else if (USARTx
== UART8
) {
152 s
= serialUART8(baudRate
, mode
, options
);
155 return (serialPort_t
*)s
;
159 // common serial initialisation code should move to serialPort::init()
160 s
->port
.rxBufferHead
= s
->port
.rxBufferTail
= 0;
161 s
->port
.txBufferHead
= s
->port
.txBufferTail
= 0;
162 // callback works for IRQ-based RX ONLY
163 s
->port
.rxCallback
= callback
;
164 s
->port
.rxCallbackData
= rxCallbackData
;
166 s
->port
.baudRate
= baudRate
;
167 s
->port
.options
= options
;
171 return (serialPort_t
*)s
;
174 void uartSetBaudRate(serialPort_t
*instance
, uint32_t baudRate
)
176 uartPort_t
*uartPort
= (uartPort_t
*)instance
;
177 uartPort
->port
.baudRate
= baudRate
;
178 uartReconfigure(uartPort
);
181 void uartSetMode(serialPort_t
*instance
, portMode_t mode
)
183 uartPort_t
*uartPort
= (uartPort_t
*)instance
;
184 uartPort
->port
.mode
= mode
;
185 uartReconfigure(uartPort
);
188 uint32_t uartTotalRxBytesWaiting(const serialPort_t
*instance
)
190 uartPort_t
*s
= (uartPort_t
*)instance
;
192 if (s
->port
.rxBufferHead
>= s
->port
.rxBufferTail
) {
193 return s
->port
.rxBufferHead
- s
->port
.rxBufferTail
;
195 return s
->port
.rxBufferSize
+ s
->port
.rxBufferHead
- s
->port
.rxBufferTail
;
199 uint32_t uartTotalTxBytesFree(const serialPort_t
*instance
)
201 uartPort_t
*s
= (uartPort_t
*)instance
;
205 if (s
->port
.txBufferHead
>= s
->port
.txBufferTail
) {
206 bytesUsed
= s
->port
.txBufferHead
- s
->port
.txBufferTail
;
208 bytesUsed
= s
->port
.txBufferSize
+ s
->port
.txBufferHead
- s
->port
.txBufferTail
;
211 return (s
->port
.txBufferSize
- 1) - bytesUsed
;
214 bool isUartTransmitBufferEmpty(const serialPort_t
*instance
)
216 uartPort_t
*s
= (uartPort_t
*)instance
;
217 return s
->port
.txBufferTail
== s
->port
.txBufferHead
;
220 uint8_t uartRead(serialPort_t
*instance
)
223 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 __HAL_UART_ENABLE_IT(&s
->Handle
, UART_IT_TXE
);
249 bool isUartIdle(serialPort_t
*instance
)
251 uartPort_t
*s
= (uartPort_t
*)instance
;
252 if(__HAL_UART_GET_FLAG(&s
->Handle
, UART_FLAG_IDLE
)) {
253 __HAL_UART_CLEAR_IDLEFLAG(&s
->Handle
);
260 const struct serialPortVTable uartVTable
[] = {
262 .serialWrite
= uartWrite
,
263 .serialTotalRxWaiting
= uartTotalRxBytesWaiting
,
264 .serialTotalTxFree
= uartTotalTxBytesFree
,
265 .serialRead
= uartRead
,
266 .serialSetBaudRate
= uartSetBaudRate
,
267 .isSerialTransmitBufferEmpty
= isUartTransmitBufferEmpty
,
268 .setMode
= uartSetMode
,
273 .isIdle
= isUartIdle
,