2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
22 * jflyper - Refactoring, cleanup and made pin-configurable
32 #include "drivers/system.h"
33 #include "drivers/io.h"
34 #include "drivers/dma.h"
35 #include "drivers/nvic.h"
36 #include "drivers/rcc.h"
38 #include "drivers/serial.h"
39 #include "drivers/serial_uart.h"
40 #include "drivers/serial_uart_impl.h"
42 const uartHardware_t uartHardware
[UARTDEV_COUNT
] = {
47 .DMAChannel
= DMA_Channel_4
,
48 #ifdef USE_UART1_RX_DMA
49 .rxDMAResource
= (dmaResource_t
*)DMA2_Stream5
,
51 #ifdef USE_UART1_TX_DMA
52 .txDMAResource
= (dmaResource_t
*)DMA2_Stream7
,
54 .rxPins
= { { DEFIO_TAG_E(PA10
) }, { DEFIO_TAG_E(PB7
) },
55 #if defined (STM32F411xE)
59 .txPins
= { { DEFIO_TAG_E(PA9
) }, { DEFIO_TAG_E(PB6
) },
60 #if defined (STM32F411xE)
61 { DEFIO_TAG_E(PA15
) },
65 .rcc
= RCC_APB2(USART1
),
67 .txPriority
= NVIC_PRIO_SERIALUART1_TXDMA
,
68 .rxPriority
= NVIC_PRIO_SERIALUART1
76 .DMAChannel
= DMA_Channel_4
,
77 #ifdef USE_UART2_RX_DMA
78 .rxDMAResource
= (dmaResource_t
*)DMA1_Stream5
,
80 #ifdef USE_UART2_TX_DMA
81 .txDMAResource
= (dmaResource_t
*)DMA1_Stream6
,
83 .rxPins
= { { DEFIO_TAG_E(PA3
) }, { DEFIO_TAG_E(PD6
) } },
84 .txPins
= { { DEFIO_TAG_E(PA2
) }, { DEFIO_TAG_E(PD5
) } },
86 .rcc
= RCC_APB1(USART2
),
88 .txPriority
= NVIC_PRIO_SERIALUART2_TXDMA
,
89 .rxPriority
= NVIC_PRIO_SERIALUART2
97 .DMAChannel
= DMA_Channel_4
,
98 #ifdef USE_UART3_RX_DMA
99 .rxDMAResource
= (dmaResource_t
*)DMA1_Stream1
,
101 #ifdef USE_UART3_TX_DMA
102 .txDMAResource
= (dmaResource_t
*)DMA1_Stream3
,
104 .rxPins
= { { DEFIO_TAG_E(PB11
) }, { DEFIO_TAG_E(PC11
) }, { DEFIO_TAG_E(PD9
) } },
105 .txPins
= { { DEFIO_TAG_E(PB10
) }, { DEFIO_TAG_E(PC10
) }, { DEFIO_TAG_E(PD8
) } },
106 .af
= GPIO_AF_USART3
,
107 .rcc
= RCC_APB1(USART3
),
109 .txPriority
= NVIC_PRIO_SERIALUART3_TXDMA
,
110 .rxPriority
= NVIC_PRIO_SERIALUART3
118 .DMAChannel
= DMA_Channel_4
,
119 #ifdef USE_UART4_RX_DMA
120 .rxDMAResource
= (dmaResource_t
*)DMA1_Stream2
,
122 #ifdef USE_UART4_TX_DMA
123 .txDMAResource
= (dmaResource_t
*)DMA1_Stream4
,
125 .rxPins
= { { DEFIO_TAG_E(PA1
) }, { DEFIO_TAG_E(PC11
) } },
126 .txPins
= { { DEFIO_TAG_E(PA0
) }, { DEFIO_TAG_E(PC10
) } },
128 .rcc
= RCC_APB1(UART4
),
130 .txPriority
= NVIC_PRIO_SERIALUART4_TXDMA
,
131 .rxPriority
= NVIC_PRIO_SERIALUART4
139 .DMAChannel
= DMA_Channel_4
,
140 #ifdef USE_UART5_RX_DMA
141 .rxDMAResource
= (dmaResource_t
*)DMA1_Stream0
,
143 #ifdef USE_UART5_TX_DMA
144 .txDMAResource
= (dmaResource_t
*)DMA1_Stream7
,
146 .rxPins
= { { DEFIO_TAG_E(PD2
) } },
147 .txPins
= { { DEFIO_TAG_E(PC12
) } },
149 .rcc
= RCC_APB1(UART5
),
151 .txPriority
= NVIC_PRIO_SERIALUART5_TXDMA
,
152 .rxPriority
= NVIC_PRIO_SERIALUART5
160 .DMAChannel
= DMA_Channel_5
,
161 #ifdef USE_UART6_RX_DMA
162 .rxDMAResource
= (dmaResource_t
*)DMA2_Stream1
,
164 #ifdef USE_UART6_TX_DMA
165 .txDMAResource
= (dmaResource_t
*)DMA2_Stream6
,
167 .rxPins
= { { DEFIO_TAG_E(PC7
) },
168 #if defined (STM32F411xE)
169 { DEFIO_TAG_E(PA12
) },
171 { DEFIO_TAG_E(PG9
) },
174 .txPins
= { { DEFIO_TAG_E(PC6
) },
175 #if defined (STM32F411xE)
176 { DEFIO_TAG_E(PA11
) },
178 { DEFIO_TAG_E(PG14
) },
181 .af
= GPIO_AF_USART6
,
182 .rcc
= RCC_APB2(USART6
),
184 .txPriority
= NVIC_PRIO_SERIALUART6_TXDMA
,
185 .rxPriority
= NVIC_PRIO_SERIALUART6
190 static void handleUsartTxDma(uartPort_t
*s
)
192 uartTryStartTxDMA(s
);
195 void dmaIRQHandler(dmaChannelDescriptor_t
* descriptor
)
197 uartPort_t
*s
= &(((uartDevice_t
*)(descriptor
->userParam
))->port
);
198 if (DMA_GET_FLAG_STATUS(descriptor
, DMA_IT_TCIF
))
200 DMA_CLEAR_FLAG(descriptor
, DMA_IT_TCIF
);
201 DMA_CLEAR_FLAG(descriptor
, DMA_IT_HTIF
);
202 if (DMA_GET_FLAG_STATUS(descriptor
, DMA_IT_FEIF
))
204 DMA_CLEAR_FLAG(descriptor
, DMA_IT_FEIF
);
208 if (DMA_GET_FLAG_STATUS(descriptor
, DMA_IT_TEIF
))
210 DMA_CLEAR_FLAG(descriptor
, DMA_IT_TEIF
);
212 if (DMA_GET_FLAG_STATUS(descriptor
, DMA_IT_DMEIF
))
214 DMA_CLEAR_FLAG(descriptor
, DMA_IT_DMEIF
);
218 // XXX Should serialUART be consolidated?
220 uartPort_t
*serialUART(UARTDevice_e device
, uint32_t baudRate
, portMode_e mode
, portOptions_e options
)
222 uartDevice_t
*uart
= uartDevmap
[device
];
223 if (!uart
) return NULL
;
225 const uartHardware_t
*hardware
= uart
->hardware
;
227 if (!hardware
) return NULL
; // XXX Can't happen !?
229 uartPort_t
*s
= &(uart
->port
);
230 s
->port
.vTable
= uartVTable
;
232 s
->port
.baudRate
= baudRate
;
234 s
->port
.rxBuffer
= uart
->rxBuffer
;
235 s
->port
.txBuffer
= uart
->txBuffer
;
236 s
->port
.rxBufferSize
= sizeof(uart
->rxBuffer
);
237 s
->port
.txBufferSize
= sizeof(uart
->txBuffer
);
239 s
->USARTx
= hardware
->reg
;
241 if (hardware
->rxDMAResource
) {
242 dmaInit(dmaGetIdentifier(hardware
->rxDMAResource
), OWNER_SERIAL_RX
, RESOURCE_INDEX(device
));
243 s
->rxDMAChannel
= hardware
->DMAChannel
;
244 s
->rxDMAResource
= hardware
->rxDMAResource
;
245 s
->rxDMAPeripheralBaseAddr
= (uint32_t)&s
->USARTx
->DR
;
248 if (hardware
->txDMAResource
) {
249 const dmaIdentifier_e identifier
= dmaGetIdentifier(hardware
->txDMAResource
);
250 dmaInit(identifier
, OWNER_SERIAL_TX
, RESOURCE_INDEX(device
));
251 dmaSetHandler(identifier
, dmaIRQHandler
, hardware
->txPriority
, (uint32_t)uart
);
252 s
->txDMAChannel
= hardware
->DMAChannel
;
253 s
->txDMAResource
= hardware
->txDMAResource
;
254 s
->txDMAPeripheralBaseAddr
= (uint32_t)&s
->USARTx
->DR
;
257 IO_t txIO
= IOGetByTag(uart
->tx
.pin
);
258 IO_t rxIO
= IOGetByTag(uart
->rx
.pin
);
261 RCC_ClockCmd(hardware
->rcc
, ENABLE
);
264 if (options
& SERIAL_BIDIR
) {
265 IOInit(txIO
, OWNER_SERIAL_TX
, RESOURCE_INDEX(device
));
266 IOConfigGPIOAF(txIO
, (options
& SERIAL_BIDIR_PP
) ? IOCFG_AF_PP
: IOCFG_AF_OD
, hardware
->af
);
268 if ((mode
& MODE_TX
) && txIO
) {
269 IOInit(txIO
, OWNER_SERIAL_TX
, RESOURCE_INDEX(device
));
270 IOConfigGPIOAF(txIO
, IOCFG_AF_PP_UP
, hardware
->af
);
273 if ((mode
& MODE_RX
) && rxIO
) {
274 IOInit(rxIO
, OWNER_SERIAL_RX
, RESOURCE_INDEX(device
));
275 IOConfigGPIOAF(rxIO
, IOCFG_AF_PP_UP
, hardware
->af
);
279 if (!(s
->rxDMAChannel
)) {
280 NVIC_InitTypeDef NVIC_InitStructure
;
282 NVIC_InitStructure
.NVIC_IRQChannel
= hardware
->irqn
;
283 NVIC_InitStructure
.NVIC_IRQChannelPreemptionPriority
= NVIC_PRIORITY_BASE(hardware
->rxPriority
);
284 NVIC_InitStructure
.NVIC_IRQChannelSubPriority
= NVIC_PRIORITY_SUB(hardware
->rxPriority
);
285 NVIC_InitStructure
.NVIC_IRQChannelCmd
= ENABLE
;
286 NVIC_Init(&NVIC_InitStructure
);
292 void uartIrqHandler(uartPort_t
*s
)
294 if (!s
->rxDMAResource
&& (USART_GetITStatus(s
->USARTx
, USART_IT_RXNE
) == SET
)) {
295 if (s
->port
.rxCallback
) {
296 s
->port
.rxCallback(s
->USARTx
->DR
, s
->port
.rxCallbackData
);
298 s
->port
.rxBuffer
[s
->port
.rxBufferHead
] = s
->USARTx
->DR
;
299 s
->port
.rxBufferHead
= (s
->port
.rxBufferHead
+ 1) % s
->port
.rxBufferSize
;
303 if (!s
->txDMAResource
&& (USART_GetITStatus(s
->USARTx
, USART_IT_TXE
) == SET
)) {
304 if (s
->port
.txBufferTail
!= s
->port
.txBufferHead
) {
305 USART_SendData(s
->USARTx
, s
->port
.txBuffer
[s
->port
.txBufferTail
]);
306 s
->port
.txBufferTail
= (s
->port
.txBufferTail
+ 1) % s
->port
.txBufferSize
;
308 USART_ITConfig(s
->USARTx
, USART_IT_TXE
, DISABLE
);
312 if (USART_GetITStatus(s
->USARTx
, USART_IT_ORE
) == SET
) {
313 USART_ClearITPendingBit(s
->USARTx
, USART_IT_ORE
);
316 if (USART_GetITStatus(s
->USARTx
, USART_IT_IDLE
) == SET
) {
317 if (s
->port
.idleCallback
) {
318 s
->port
.idleCallback();
322 (void) s
->USARTx
->SR
;
323 (void) s
->USARTx
->DR
;