Ditching default target for `make` in favour of `make all` (#14099)
[betaflight.git] / src / main / drivers / serial_uart_hw.c
blob91e42c005f81e8b211517f55eb10b6ba3e350994
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 * Common UART hardware functions
26 #include <stdbool.h>
27 #include <stdint.h>
29 #include "platform.h"
31 #if defined(USE_UART) && !defined(SIMULATOR_BUILD)
33 #include "build/build_config.h"
35 #include "drivers/nvic.h"
36 #include "drivers/rcc.h"
37 #include "drivers/inverter.h"
38 #include "drivers/serial.h"
39 #include "drivers/serial_impl.h"
40 #include "drivers/serial_uart.h"
41 #include "drivers/serial_uart_impl.h"
43 // TODO: split this function into mcu-specific UART files ?
44 static void enableRxIrq(const uartHardware_t *hardware)
46 #if defined(USE_HAL_DRIVER)
47 HAL_NVIC_SetPriority(hardware->irqn, NVIC_PRIORITY_BASE(hardware->rxPriority), NVIC_PRIORITY_SUB(hardware->rxPriority));
48 HAL_NVIC_EnableIRQ(hardware->irqn);
49 #elif defined(STM32F4)
50 NVIC_InitTypeDef NVIC_InitStructure;
51 NVIC_InitStructure.NVIC_IRQChannel = hardware->irqn;
52 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = NVIC_PRIORITY_BASE(hardware->rxPriority);
53 NVIC_InitStructure.NVIC_IRQChannelSubPriority = NVIC_PRIORITY_SUB(hardware->rxPriority);
54 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
55 NVIC_Init(&NVIC_InitStructure);
56 #elif defined(AT32F4)
57 nvic_irq_enable(hardware->irqn, NVIC_PRIORITY_BASE(hardware->rxPriority), NVIC_PRIORITY_SUB(hardware->rxPriority));
58 #elif defined(APM32F4)
59 DAL_NVIC_SetPriority(hardware->irqn, NVIC_PRIORITY_BASE(hardware->rxPriority), NVIC_PRIORITY_SUB(hardware->rxPriority));
60 DAL_NVIC_EnableIRQ(hardware->irqn);
61 #else
62 # error "Unhandled MCU type"
63 #endif
66 uartPort_t *serialUART(uartDevice_t *uartdev, uint32_t baudRate, portMode_e mode, portOptions_e options)
68 uartPort_t *s = &uartdev->port;
70 const uartHardware_t *hardware = uartdev->hardware;
72 s->port.vTable = uartVTable;
74 s->port.baudRate = baudRate;
76 s->port.rxBuffer = hardware->rxBuffer;
77 s->port.txBuffer = hardware->txBuffer;
78 s->port.rxBufferSize = hardware->rxBufferSize;
79 s->port.txBufferSize = hardware->txBufferSize;
81 s->USARTx = hardware->reg;
83 #ifdef USE_HAL_DRIVER
84 s->Handle.Instance = hardware->reg;
85 #endif
87 s->checkUsartTxOutput = checkUsartTxOutput;
89 if (hardware->rcc) {
90 RCC_ClockCmd(hardware->rcc, ENABLE);
93 #ifdef USE_DMA
94 uartConfigureDma(uartdev);
95 s->txDMAEmpty = true;
96 #endif
98 IO_t txIO = IOGetByTag(uartdev->tx.pin);
99 IO_t rxIO = IOGetByTag(uartdev->rx.pin);
101 uartdev->txPinState = TX_PIN_IGNORE;
103 const serialPortIdentifier_e identifier = s->port.identifier;
105 const int ownerIndex = serialOwnerIndex(identifier);
106 const resourceOwner_e ownerTxRx = serialOwnerTxRx(identifier); // rx is always +1
108 // prepare AF modes
109 #if UART_TRAIT_AF_PORT
110 uint8_t rxAf = hardware->af;
111 uint8_t txAf = hardware->af;
112 #elif UART_TRAIT_AF_PIN
113 uint8_t rxAf = uartdev->rx.af;
114 uint8_t txAf = uartdev->tx.af;
115 #endif
117 // Note: F4 did not check txIO before refactoring
118 if ((options & SERIAL_BIDIR) && txIO) {
119 // pushPull / openDrain
120 const bool pushPull = serialOptions_pushPull(options);
121 // pull direction
122 const serialPullMode_t pull = serialOptions_pull(options);
123 #if defined(STM32F7) || defined(STM32H7) || defined(STM32G4) || defined(APM32F4)
124 // Note: APM32F4 is different from STM32F4 here
125 const ioConfig_t ioCfg = IO_CONFIG(
126 pushPull ? GPIO_MODE_AF_PP : GPIO_MODE_AF_OD,
127 GPIO_SPEED_FREQ_HIGH,
128 ((const unsigned[]){GPIO_NOPULL, GPIO_PULLDOWN, GPIO_PULLUP})[pull]
130 #elif defined(AT32F4)
131 const ioConfig_t ioCfg = IO_CONFIG(
132 GPIO_MODE_MUX,
133 GPIO_DRIVE_STRENGTH_STRONGER,
134 pushPull ? GPIO_OUTPUT_PUSH_PULL : GPIO_OUTPUT_OPEN_DRAIN,
135 ((const gpio_pull_type[]){GPIO_PULL_NONE, GPIO_PULL_DOWN, GPIO_PULL_UP})[pull]
137 #elif defined(STM32F4)
138 // UART inverter is not supproted on F4, but keep it in line with other CPUs
139 // External inverter in bidir mode would be quite problematic anyway
140 const ioConfig_t ioCfg = IO_CONFIG(
141 GPIO_Mode_AF,
142 GPIO_Low_Speed, // TODO: should use stronger drive
143 pushPull ? GPIO_OType_PP : GPIO_OType_OD,
144 ((const unsigned[]){GPIO_PuPd_NOPULL, GPIO_PuPd_DOWN, GPIO_PuPd_UP})[pull]
146 #endif
147 IOInit(txIO, ownerTxRx, ownerIndex);
148 IOConfigGPIOAF(txIO, ioCfg, txAf);
149 } else {
150 if ((mode & MODE_TX) && txIO) {
151 IOInit(txIO, ownerTxRx, ownerIndex);
153 if (options & SERIAL_CHECK_TX) {
154 #if defined(STM32F7)
155 // see https://github.com/betaflight/betaflight/pull/13021
156 // Allow for F7 UART idle preamble to be sent on startup
157 uartdev->txPinState = TX_PIN_MONITOR;
158 // Switch TX to UART output whilst UART sends idle preamble
159 checkUsartTxOutput(s);
160 #else
161 uartdev->txPinState = TX_PIN_ACTIVE;
162 // Switch TX to an input with pullup so it's state can be monitored
163 uartTxMonitor(s);
164 #endif
165 } else {
166 #if defined(STM32F4) || defined(APM32F4)
167 // TODO: no need for pullup on TX only pin
168 const ioConfig_t ioCfg = IOCFG_AF_PP_UP;
169 #else
170 const ioConfig_t ioCfg = IOCFG_AF_PP;
171 #endif
172 IOConfigGPIOAF(txIO, ioCfg, txAf);
176 if ((mode & MODE_RX) && rxIO) {
177 #if defined(STM32F4) || defined(APM32F4)
178 // no inversion possible on F4, always use pullup
179 const ioConfig_t ioCfg = IOCFG_AF_PP_UP;
180 #else
181 // TODO: pullup/pulldown should be enabled for RX (based on inversion)
182 const ioConfig_t ioCfg = IOCFG_AF_PP;
183 #endif
184 IOInit(rxIO, ownerTxRx + 1, ownerIndex);
185 IOConfigGPIOAF(rxIO, ioCfg, rxAf);
189 if (true
190 #ifdef USE_DMA
191 && !s->rxDMAResource // do not enable IRW if using rxDMA
192 #endif
194 enableRxIrq(hardware);
196 return s;
199 // called from platform-specific uartReconfigure
200 void uartConfigureExternalPinInversion(uartPort_t *uartPort)
202 #if !defined(USE_INVERTER)
203 UNUSED(uartPort);
204 #else
205 const bool inverted = uartPort->port.options & SERIAL_INVERTED;
206 enableInverter(uartPort->port.identifier, inverted);
207 #endif
210 #endif /* USE_UART */