2 * This file is part of Betaflight.
4 * Betaflight is free software. You can redistribute this software
5 * and/or modify this software under the terms of the GNU General
6 * Public License as published by the Free Software Foundation,
7 * either version 3 of the License, or (at your option) any later
10 * Betaflight is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public
17 * License along with this software.
19 * If not, see <http://www.gnu.org/licenses/>.
23 * jflyper - Refactoring, cleanup and made pin-configurable
33 #include "build/debug.h"
35 #include "drivers/system.h"
36 #include "drivers/io.h"
37 #include "drivers/dma.h"
38 #include "drivers/nvic.h"
39 #include "drivers/rcc.h"
41 #include "drivers/serial.h"
42 #include "drivers/serial_uart.h"
43 #include "drivers/serial_uart_impl.h"
45 const uartHardware_t uartHardware
[UARTDEV_COUNT
] = {
48 .identifier
= SERIAL_PORT_USART1
,
50 .rxDMAChannel
= DMA_CHANNEL_4
,
51 .txDMAChannel
= DMA_CHANNEL_4
,
52 #ifdef USE_UART1_RX_DMA
53 .rxDMAResource
= (dmaResource_t
*)DMA2_Stream5
,
55 #ifdef USE_UART1_TX_DMA
56 .txDMAResource
= (dmaResource_t
*)DMA2_Stream7
,
58 .rxPins
= { { DEFIO_TAG_E(PA10
) }, { DEFIO_TAG_E(PB7
) },
60 .txPins
= { { DEFIO_TAG_E(PA9
) }, { DEFIO_TAG_E(PB6
) },
62 .af
= GPIO_AF7_USART1
,
63 .rcc
= RCC_APB2(USART1
),
65 .txPriority
= NVIC_PRIO_SERIALUART1_TXDMA
,
66 .rxPriority
= NVIC_PRIO_SERIALUART1
,
67 .txBuffer
= uart1TxBuffer
,
68 .rxBuffer
= uart1RxBuffer
,
69 .txBufferSize
= sizeof(uart1TxBuffer
),
70 .rxBufferSize
= sizeof(uart1RxBuffer
),
76 .identifier
= SERIAL_PORT_USART2
,
78 .rxDMAChannel
= DMA_CHANNEL_4
,
79 .txDMAChannel
= DMA_CHANNEL_4
,
80 #ifdef USE_UART2_RX_DMA
81 .rxDMAResource
= (dmaResource_t
*)DMA1_Stream5
,
83 #ifdef USE_UART2_TX_DMA
84 .txDMAResource
= (dmaResource_t
*)DMA1_Stream6
,
86 .rxPins
= { { DEFIO_TAG_E(PA3
) }, { DEFIO_TAG_E(PD6
) } },
87 .txPins
= { { DEFIO_TAG_E(PA2
) }, { DEFIO_TAG_E(PD5
) } },
88 .af
= GPIO_AF7_USART2
,
89 .rcc
= RCC_APB1(USART2
),
91 .txPriority
= NVIC_PRIO_SERIALUART2_TXDMA
,
92 .rxPriority
= NVIC_PRIO_SERIALUART2
,
93 .txBuffer
= uart2TxBuffer
,
94 .rxBuffer
= uart2RxBuffer
,
95 .txBufferSize
= sizeof(uart2TxBuffer
),
96 .rxBufferSize
= sizeof(uart2RxBuffer
),
102 .identifier
= SERIAL_PORT_USART3
,
104 .rxDMAChannel
= DMA_CHANNEL_4
,
105 .txDMAChannel
= DMA_CHANNEL_4
,
106 #ifdef USE_UART3_RX_DMA
107 .rxDMAResource
= (dmaResource_t
*)DMA1_Stream1
,
109 #ifdef USE_UART3_TX_DMA
110 .txDMAResource
= (dmaResource_t
*)DMA1_Stream3
,
112 .rxPins
= { { DEFIO_TAG_E(PB11
) }, { DEFIO_TAG_E(PC11
) }, { DEFIO_TAG_E(PD9
) } },
113 .txPins
= { { DEFIO_TAG_E(PB10
) }, { DEFIO_TAG_E(PC10
) }, { DEFIO_TAG_E(PD8
) } },
114 .af
= GPIO_AF7_USART3
,
115 .rcc
= RCC_APB1(USART3
),
117 .txPriority
= NVIC_PRIO_SERIALUART3_TXDMA
,
118 .rxPriority
= NVIC_PRIO_SERIALUART3
,
119 .txBuffer
= uart3TxBuffer
,
120 .rxBuffer
= uart3RxBuffer
,
121 .txBufferSize
= sizeof(uart3TxBuffer
),
122 .rxBufferSize
= sizeof(uart3RxBuffer
),
128 .identifier
= SERIAL_PORT_UART4
,
130 .rxDMAChannel
= DMA_CHANNEL_4
,
131 .txDMAChannel
= DMA_CHANNEL_4
,
132 #ifdef USE_UART4_RX_DMA
133 .rxDMAResource
= (dmaResource_t
*)DMA1_Stream2
,
135 #ifdef USE_UART4_TX_DMA
136 .txDMAResource
= (dmaResource_t
*)DMA1_Stream4
,
138 .rxPins
= { { DEFIO_TAG_E(PA1
) }, { DEFIO_TAG_E(PC11
) } },
139 .txPins
= { { DEFIO_TAG_E(PA0
) }, { DEFIO_TAG_E(PC10
) } },
140 .af
= GPIO_AF8_UART4
,
141 .rcc
= RCC_APB1(UART4
),
143 .txPriority
= NVIC_PRIO_SERIALUART4_TXDMA
,
144 .rxPriority
= NVIC_PRIO_SERIALUART4
,
145 .txBuffer
= uart4TxBuffer
,
146 .rxBuffer
= uart4RxBuffer
,
147 .txBufferSize
= sizeof(uart4TxBuffer
),
148 .rxBufferSize
= sizeof(uart4RxBuffer
),
154 .identifier
= SERIAL_PORT_UART5
,
156 .rxDMAChannel
= DMA_CHANNEL_4
,
157 .txDMAChannel
= DMA_CHANNEL_4
,
158 #ifdef USE_UART5_RX_DMA
159 .rxDMAResource
= (dmaResource_t
*)DMA1_Stream0
,
161 #ifdef USE_UART5_TX_DMA
162 .txDMAResource
= (dmaResource_t
*)DMA1_Stream7
,
164 .rxPins
= { { DEFIO_TAG_E(PD2
) } },
165 .txPins
= { { DEFIO_TAG_E(PC12
) } },
166 .af
= GPIO_AF8_UART5
,
167 .rcc
= RCC_APB1(UART5
),
169 .txPriority
= NVIC_PRIO_SERIALUART5_TXDMA
,
170 .rxPriority
= NVIC_PRIO_SERIALUART5
,
171 .txBuffer
= uart5TxBuffer
,
172 .rxBuffer
= uart5RxBuffer
,
173 .txBufferSize
= sizeof(uart5TxBuffer
),
174 .rxBufferSize
= sizeof(uart5RxBuffer
),
180 .identifier
= SERIAL_PORT_USART6
,
182 .rxDMAChannel
= DMA_CHANNEL_5
,
183 .txDMAChannel
= DMA_CHANNEL_5
,
184 #ifdef USE_UART6_RX_DMA
185 .rxDMAResource
= (dmaResource_t
*)DMA2_Stream1
,
187 #ifdef USE_UART6_TX_DMA
188 .txDMAResource
= (dmaResource_t
*)DMA2_Stream6
,
190 .rxPins
= { { DEFIO_TAG_E(PC7
) }, { DEFIO_TAG_E(PG9
) } },
191 .txPins
= { { DEFIO_TAG_E(PC6
) }, { DEFIO_TAG_E(PG14
) } },
192 .af
= GPIO_AF8_USART6
,
193 .rcc
= RCC_APB2(USART6
),
195 .txPriority
= NVIC_PRIO_SERIALUART6_TXDMA
,
196 .rxPriority
= NVIC_PRIO_SERIALUART6
,
197 .txBuffer
= uart6TxBuffer
,
198 .rxBuffer
= uart6RxBuffer
,
199 .txBufferSize
= sizeof(uart6TxBuffer
),
200 .rxBufferSize
= sizeof(uart6RxBuffer
),
205 bool checkUsartTxOutput(uartPort_t
*s
)
207 uartDevice_t
*uart
= container_of(s
, uartDevice_t
, port
);
208 IO_t txIO
= IOGetByTag(uart
->tx
.pin
);
210 if ((uart
->txPinState
== TX_PIN_MONITOR
) && txIO
) {
212 // TX is high so we're good to transmit
214 // Enable USART TX output
215 uart
->txPinState
= TX_PIN_ACTIVE
;
216 IOConfigGPIOAF(txIO
, IOCFG_AF_PP
, uart
->hardware
->af
);
218 // Enable the UART transmitter
219 SET_BIT(s
->Handle
.Instance
->CTRL1
, USART_CTRL1_TXEN
);
223 // TX line is pulled low so don't enable USART TX
231 void uartTxMonitor(uartPort_t
*s
)
233 uartDevice_t
*uart
= container_of(s
, uartDevice_t
, port
);
235 if (uart
->txPinState
== TX_PIN_ACTIVE
) {
236 IO_t txIO
= IOGetByTag(uart
->tx
.pin
);
238 // Disable the UART transmitter
239 CLEAR_BIT(s
->Handle
.Instance
->CTRL1
, USART_CTRL1_TXEN
);
241 // Switch TX to an input with pullup so it's state can be monitored
242 uart
->txPinState
= TX_PIN_MONITOR
;
243 IOConfigGPIO(txIO
, IOCFG_IPU
);
247 static void handleUsartTxDma(uartPort_t
*s
)
249 uartDevice_t
*uart
= container_of(s
, uartDevice_t
, port
);
251 uartTryStartTxDMA(s
);
253 if (s
->txDMAEmpty
&& (uart
->txPinState
!= TX_PIN_IGNORE
)) {
254 // Switch TX to an input with pullup so it's state can be monitored
259 void uartDmaIrqHandler(dmaChannelDescriptor_t
* descriptor
)
261 uartPort_t
*s
= &(((uartDevice_t
*)(descriptor
->userParam
))->port
);
262 if (DMA_GET_FLAG_STATUS(descriptor
, DMA_IT_TCIF
))
264 DMA_CLEAR_FLAG(descriptor
, DMA_IT_TCIF
);
265 DMA_CLEAR_FLAG(descriptor
, DMA_IT_HTIF
);
266 if (DMA_GET_FLAG_STATUS(descriptor
, DMA_IT_FEIF
))
268 DMA_CLEAR_FLAG(descriptor
, DMA_IT_FEIF
);
272 if (DMA_GET_FLAG_STATUS(descriptor
, DMA_IT_TEIF
))
274 DMA_CLEAR_FLAG(descriptor
, DMA_IT_TEIF
);
276 if (DMA_GET_FLAG_STATUS(descriptor
, DMA_IT_DMEIF
))
278 DMA_CLEAR_FLAG(descriptor
, DMA_IT_DMEIF
);
282 FAST_IRQ_HANDLER
void uartIrqHandler(uartPort_t
*s
)
284 UART_HandleTypeDef
*huart
= &s
->Handle
;
285 uint32_t isrflags
= READ_REG(huart
->Instance
->STS
);
286 uint32_t cr1its
= READ_REG(huart
->Instance
->CTRL1
);
287 uint32_t cr3its
= READ_REG(huart
->Instance
->CTRL3
);
288 /* UART in mode Receiver ---------------------------------------------------*/
289 if (!s
->rxDMAResource
&& (((isrflags
& USART_STS_RXBNEFLG
) != RESET
) && ((cr1its
& USART_CTRL1_RXBNEIEN
) != RESET
))) {
290 if (s
->port
.rxCallback
) {
291 s
->port
.rxCallback(huart
->Instance
->DATA
, s
->port
.rxCallbackData
);
293 s
->port
.rxBuffer
[s
->port
.rxBufferHead
] = huart
->Instance
->DATA
;
294 s
->port
.rxBufferHead
= (s
->port
.rxBufferHead
+ 1) % s
->port
.rxBufferSize
;
298 // Detect completion of transmission
299 if (((isrflags
& USART_STS_TXCFLG
) != RESET
) && ((cr1its
& USART_CTRL1_TXCIEN
) != RESET
)) {
300 // Switch TX to an input with pullup so it's state can be monitored
303 __DAL_UART_CLEAR_FLAG(huart
, UART_IT_TC
);
306 if (!s
->txDMAResource
&& (((isrflags
& USART_STS_TXBEFLG
) != RESET
) && ((cr1its
& USART_CTRL1_TXBEIEN
) != RESET
))) {
307 if (s
->port
.txBufferTail
!= s
->port
.txBufferHead
) {
308 huart
->Instance
->DATA
= (((uint16_t) s
->port
.txBuffer
[s
->port
.txBufferTail
]) & (uint16_t) 0x01FFU
);
309 s
->port
.txBufferTail
= (s
->port
.txBufferTail
+ 1) % s
->port
.txBufferSize
;
311 __DAL_UART_DISABLE_IT(huart
, UART_IT_TXE
);
315 if (((isrflags
& USART_STS_OVREFLG
) != RESET
) && (((cr1its
& USART_CTRL1_RXBNEIEN
) != RESET
)
316 || ((cr3its
& USART_CTRL3_ERRIEN
) != RESET
))) {
317 __DAL_UART_CLEAR_OREFLAG(huart
);
320 if (((isrflags
& USART_STS_IDLEFLG
) != RESET
) && ((cr1its
& USART_STS_IDLEFLG
) != RESET
)) {
321 if (s
->port
.idleCallback
) {
322 s
->port
.idleCallback();
326 (void) huart
->Instance
->STS
;
327 (void) huart
->Instance
->DATA
;