FIX: AT32 not reading ESC (#14220)
[betaflight.git] / src / platform / APM32 / serial_uart_apm32f4xx.c
blob2c5151b62fe37b0060bf5171290dfbb802181657
1 /*
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
8 * version.
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
26 #include <stdbool.h>
27 #include <stdint.h>
29 #include "platform.h"
31 #ifdef USE_UART
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] = {
46 #ifdef USE_UART1
48 .identifier = SERIAL_PORT_USART1,
49 .reg = USART1,
50 .rxDMAChannel = DMA_CHANNEL_4,
51 .txDMAChannel = DMA_CHANNEL_4,
52 #ifdef USE_UART1_RX_DMA
53 .rxDMAResource = (dmaResource_t *)DMA2_Stream5,
54 #endif
55 #ifdef USE_UART1_TX_DMA
56 .txDMAResource = (dmaResource_t *)DMA2_Stream7,
57 #endif
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),
64 .irqn = USART1_IRQn,
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),
72 #endif
74 #ifdef USE_UART2
76 .identifier = SERIAL_PORT_USART2,
77 .reg = USART2,
78 .rxDMAChannel = DMA_CHANNEL_4,
79 .txDMAChannel = DMA_CHANNEL_4,
80 #ifdef USE_UART2_RX_DMA
81 .rxDMAResource = (dmaResource_t *)DMA1_Stream5,
82 #endif
83 #ifdef USE_UART2_TX_DMA
84 .txDMAResource = (dmaResource_t *)DMA1_Stream6,
85 #endif
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),
90 .irqn = USART2_IRQn,
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),
98 #endif
100 #ifdef USE_UART3
102 .identifier = SERIAL_PORT_USART3,
103 .reg = USART3,
104 .rxDMAChannel = DMA_CHANNEL_4,
105 .txDMAChannel = DMA_CHANNEL_4,
106 #ifdef USE_UART3_RX_DMA
107 .rxDMAResource = (dmaResource_t *)DMA1_Stream1,
108 #endif
109 #ifdef USE_UART3_TX_DMA
110 .txDMAResource = (dmaResource_t *)DMA1_Stream3,
111 #endif
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),
116 .irqn = USART3_IRQn,
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),
124 #endif
126 #ifdef USE_UART4
128 .identifier = SERIAL_PORT_UART4,
129 .reg = UART4,
130 .rxDMAChannel = DMA_CHANNEL_4,
131 .txDMAChannel = DMA_CHANNEL_4,
132 #ifdef USE_UART4_RX_DMA
133 .rxDMAResource = (dmaResource_t *)DMA1_Stream2,
134 #endif
135 #ifdef USE_UART4_TX_DMA
136 .txDMAResource = (dmaResource_t *)DMA1_Stream4,
137 #endif
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),
142 .irqn = UART4_IRQn,
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),
150 #endif
152 #ifdef USE_UART5
154 .identifier = SERIAL_PORT_UART5,
155 .reg = UART5,
156 .rxDMAChannel = DMA_CHANNEL_4,
157 .txDMAChannel = DMA_CHANNEL_4,
158 #ifdef USE_UART5_RX_DMA
159 .rxDMAResource = (dmaResource_t *)DMA1_Stream0,
160 #endif
161 #ifdef USE_UART5_TX_DMA
162 .txDMAResource = (dmaResource_t *)DMA1_Stream7,
163 #endif
164 .rxPins = { { DEFIO_TAG_E(PD2) } },
165 .txPins = { { DEFIO_TAG_E(PC12) } },
166 .af = GPIO_AF8_UART5,
167 .rcc = RCC_APB1(UART5),
168 .irqn = UART5_IRQn,
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),
176 #endif
178 #ifdef USE_UART6
180 .identifier = SERIAL_PORT_USART6,
181 .reg = USART6,
182 .rxDMAChannel = DMA_CHANNEL_5,
183 .txDMAChannel = DMA_CHANNEL_5,
184 #ifdef USE_UART6_RX_DMA
185 .rxDMAResource = (dmaResource_t *)DMA2_Stream1,
186 #endif
187 #ifdef USE_UART6_TX_DMA
188 .txDMAResource = (dmaResource_t *)DMA2_Stream6,
189 #endif
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),
194 .irqn = USART6_IRQn,
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),
202 #endif
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) {
211 if (IORead(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);
221 return true;
222 } else {
223 // TX line is pulled low so don't enable USART TX
224 return false;
228 return true;
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
255 uartTxMonitor(s);
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);
270 handleUsartTxDma(s);
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);
292 } else {
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
301 uartTxMonitor(s);
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;
310 } else {
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();
325 // clear
326 (void) huart->Instance->STS;
327 (void) huart->Instance->DATA;
331 #endif // USE_UART