1
0
Fork 0
mirror of https://github.com/betaflight/betaflight.git synced 2025-07-26 01:35:41 +03:00
betaflight/src/platform/PICO/serial_uart_pico.c
2025-01-04 15:35:15 +11:00

205 lines
5.6 KiB
C

/*
* This file is part of Betaflight.
*
* Betaflight is free software. You can redistribute this software
* and/or modify this software under the terms of the GNU General
* Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later
* version.
*
* Betaflight is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this software.
*
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdbool.h>
#include <stdint.h>
#include "platform.h"
#ifdef USE_UART
#include "drivers/system.h"
#include "drivers/io.h"
#include "drivers/serial.h"
#include "drivers/serial_uart.h"
#include "drivers/serial_impl.h"
#include "serial_uart_impl.h"
#include "hardware/uart.h"
#include "hardware/irq.h"
const uartHardware_t uartHardware[UARTDEV_COUNT] = {
#ifdef USE_UART0
{
.identifier = SERIAL_PORT_UART0,
.reg = uart0,
.rxPins = {
{ DEFIO_TAG_E(P1) },
{ DEFIO_TAG_E(P17) },
},
.txPins = {
{ DEFIO_TAG_E(P0) },
{ DEFIO_TAG_E(P16) },
},
.irqn = UART0_IRQ,
.txBuffer = uart0TxBuffer,
.rxBuffer = uart0RxBuffer,
.txBufferSize = sizeof(uart0TxBuffer),
.rxBufferSize = sizeof(uart0RxBuffer),
},
#endif
#ifdef USE_UART1
{
.identifier = SERIAL_PORT_UART1,
.reg = uart1,
.rxPins = {
{ DEFIO_TAG_E(P5) },
{ DEFIO_TAG_E(P9) },
{ DEFIO_TAG_E(P25) },
},
.txPins = {
{ DEFIO_TAG_E(P4) },
{ DEFIO_TAG_E(P20) },
{ DEFIO_TAG_E(P24) },
},
.irqn = UART1_IRQ,
.txBuffer = uart1TxBuffer,
.rxBuffer = uart1RxBuffer,
.txBufferSize = sizeof(uart1TxBuffer),
.rxBufferSize = sizeof(uart1RxBuffer),
},
#endif
};
static void uartIrqHandler(uartPort_t *s)
{
if ((uart_get_hw(s->USARTx)->imsc & UART_UARTIMSC_RXIM_BITS) != 0) {
while (uart_is_readable(s->USARTx)) {
const uint8_t ch = uart_getc(s->USARTx);
if (s->port.rxCallback) {
s->port.rxCallback(ch, s->port.rxCallbackData);
} else {
s->port.rxBuffer[s->port.rxBufferHead] = ch;
s->port.rxBufferHead = (s->port.rxBufferHead + 1) % s->port.rxBufferSize;
}
}
}
if ((uart_get_hw(s->USARTx)->imsc & UART_UARTIMSC_TXIM_BITS) != 0) {
while (uart_is_writable(s->USARTx)) {
if (s->port.txBufferTail != s->port.txBufferHead) {
uart_putc(s->USARTx, s->port.txBuffer[s->port.txBufferTail]);
s->port.txBufferTail = (s->port.txBufferTail + 1) % s->port.txBufferSize;
} else {
uart_set_irqs_enabled(s->USARTx, true, false);
break;
}
}
}
}
static void on_uart0(void)
{
uartIrqHandler(&uartDevice[UARTDEV_0].port);
}
static void on_uart1(void)
{
uartIrqHandler(&uartDevice[UARTDEV_1].port);
}
uartPort_t *serialUART(uartDevice_t *uartdev, uint32_t baudRate, portMode_e mode, portOptions_e options)
{
UNUSED(options);
uartPort_t *s = &uartdev->port;
const uartHardware_t *hardware = uartdev->hardware;
s->port.vTable = uartVTable;
s->port.baudRate = baudRate;
s->port.rxBuffer = hardware->rxBuffer;
s->port.txBuffer = hardware->txBuffer;
s->port.rxBufferSize = hardware->rxBufferSize;
s->port.txBufferSize = hardware->txBufferSize;
s->USARTx = hardware->reg;
IO_t txIO = IOGetByTag(uartdev->tx.pin);
IO_t rxIO = IOGetByTag(uartdev->rx.pin);
const serialPortIdentifier_e identifier = s->port.identifier;
const int ownerIndex = serialOwnerIndex(identifier);
const resourceOwner_e ownerTxRx = serialOwnerTxRx(identifier); // rx is always +1
IOInit(txIO, ownerTxRx, ownerIndex);
IOInit(txIO, ownerTxRx, ownerIndex);
uart_init(hardware->reg, baudRate);
if ((mode & MODE_TX) && txIO) {
IOInit(txIO, ownerTxRx, ownerIndex);
gpio_set_function(IO_Pin(txIO), GPIO_FUNC_UART);
}
if ((mode & MODE_RX) && rxIO) {
IOInit(rxIO, ownerTxRx + 1, ownerIndex);
gpio_set_function(IO_Pin(rxIO), GPIO_FUNC_UART);
}
uart_set_hw_flow(hardware->reg, false, false);
uart_set_format(hardware->reg, 8, 1, UART_PARITY_NONE);
uart_set_fifo_enabled(hardware->reg, false);
irq_set_exclusive_handler(hardware->irqn, hardware->irqn == UART0_IRQ ? on_uart0 : on_uart1);
irq_set_enabled(hardware->irqn, true);
if ((mode & MODE_RX) && rxIO) {
uart_set_irqs_enabled(hardware->reg, true, false);
}
return s;
}
// called from platform-specific uartReconfigure
void uartConfigureExternalPinInversion(uartPort_t *uartPort)
{
#if !defined(USE_INVERTER)
UNUSED(uartPort);
#else
const bool inverted = uartPort->port.options & SERIAL_INVERTED;
enableInverter(uartPort->port.identifier, inverted);
#endif
}
void uartTryStartTx(uartPort_t *s)
{
if (s->port.txBufferTail == s->port.txBufferHead) {
return;
}
uart_set_irqs_enabled(s->USARTx, uart_get_hw(s->USARTx)->imsc & UART_UARTIMSC_RXIM_BITS, true);
}
void uartReconfigure(uartPort_t *s)
{
uart_deinit(s->USARTx);
uart_init(s->USARTx, s->port.baudRate);
uart_set_format(s->USARTx, 8, 1, UART_PARITY_NONE);
uart_set_fifo_enabled(s->USARTx, false);
uartConfigureExternalPinInversion(s);
}
#endif /* USE_UART */