Ver código fonte

UART driver refactor (#11637)

Ryan 4 anos atrás
pai
commit
30b46fad57

+ 1 - 0
docs/_summary.md

@@ -138,6 +138,7 @@
       * [WS2812 Driver](ws2812_driver.md)
       * [EEPROM Driver](eeprom_driver.md)
       * ['serial' Driver](serial_driver.md)
+      * [UART Driver](uart_driver.md)
     * [GPIO Controls](internals_gpio_control.md)
     * [Keyboard Guidelines](hardware_keyboard_guidelines.md)
 

+ 90 - 0
docs/uart_driver.md

@@ -0,0 +1,90 @@
+# UART Driver
+
+The UART drivers used in QMK have a set of common functions to allow portability between MCUs.
+
+Currently, this driver does not support enabling hardware flow control (the `RTS` and `CTS` pins) if available, but may do so in future.
+
+## AVR Configuration
+
+No special setup is required - just connect the `RX` and `TX` pins of your UART device to the opposite pins on the MCU:
+
+|MCU          |`TX`|`RX`|`CTS`|`RTS`|
+|-------------|----|----|-----|-----|
+|ATmega16/32U2|`D3`|`D2`|`D7` |`D6` |
+|ATmega16/32U4|`D3`|`D2`|`D5` |`B7` |
+|AT90USB64/128|`D3`|`D2`|*n/a*|*n/a*|
+|ATmega32A    |`D1`|`D0`|*n/a*|*n/a*|
+|ATmega328/P  |`D1`|`D0`|*n/a*|*n/a*|
+
+## ChibiOS/ARM Configuration
+
+You'll need to determine which pins can be used for UART -- as an example, STM32 parts generally have multiple UART peripherals, labeled USART1, USART2, USART3 etc.
+
+To enable UART, modify your board's `halconf.h` to enable the serial driver:
+
+```c
+#define HAL_USE_SERIAL TRUE
+```
+
+Then, modify your board's `mcuconf.h` to enable the peripheral you've chosen, for example:
+
+```c
+#undef STM32_SERIAL_USE_USART2
+#define STM32_SERIAL_USE_USART2 TRUE
+```
+
+Configuration-wise, you'll need to set up the peripheral as per your MCU's datasheet -- the defaults match the pins for a Proton-C, i.e. STM32F303.
+
+|`config.h` override       |Description                                                    |Default Value|
+|--------------------------|---------------------------------------------------------------|-------------|
+|`#define SERIAL_DRIVER`   |USART peripheral to use - USART1 -> `SD1`, USART2 -> `SD2` etc.|`SD1`        |
+|`#define SD1_TX_PIN`      |The pin to use for TX                                          |`A9`         |
+|`#define SD1_TX_PAL_MODE` |The alternate function mode for TX                             |`7`          |
+|`#define SD1_RX_PIN`      |The pin to use for RX                                          |`A10`        |
+|`#define SD1_RX_PAL_MODE` |The alternate function mode for RX                             |`7`          |
+|`#define SD1_CTS_PIN`     |The pin to use for CTS                                         |`A11`        |
+|`#define SD1_CTS_PAL_MODE`|The alternate function mode for CTS                            |`7`          |
+|`#define SD1_RTS_PIN`     |The pin to use for RTS                                         |`A12`        |
+|`#define SD1_RTS_PAL_MODE`|The alternate function mode for RTS                            |`7`          |
+
+## Functions
+
+### `void uart_init(uint32_t baud)`
+
+Initialize the UART driver. This function must be called only once, before any of the below functions can be called.
+
+#### Arguments
+
+ - `uint32_t baud`  
+   The baud rate to transmit and receive at. This may depend on the device you are communicating with. Common values are 1200, 2400, 4800, 9600, 19200, 38400, 57600, and 115200.
+
+---
+
+### `void uart_putchar(uint8_t c)`
+
+Transmit a single byte.
+
+#### Arguments
+
+ - `uint8_t c`  
+   The byte (character) to send, from 0 to 255.
+
+---
+
+### `uint8_t uart_getchar(void)`
+
+Receive a single byte.
+
+#### Return Value
+
+The byte read from the receive buffer.
+
+---
+
+### `bool uart_available(void)`
+
+Return whether the receive buffer contains data. Call this function to determine if `uart_getchar()` will return meaningful data.
+
+#### Return Value
+
+`true` if the receive buffer length is non-zero.

+ 20 - 22
tmk_core/common/uart.c → drivers/avr/uart.c

@@ -1,5 +1,3 @@
-// TODO: Teensy support(ATMega32u4/AT90USB128)
-// Fixed for Arduino Duemilanove ATmega168p by Jun Wako
 /* UART Example for Teensy USB Development Board
  * http://www.pjrc.com/teensy/
  * Copyright (c) 2009 PJRC.COM, LLC
@@ -31,22 +29,7 @@
 
 #include "uart.h"
 
-#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__)
-#    define UDRn UDR0
-#    define UBRRnL UBRR0L
-#    define UCSRnA UCSR0A
-#    define UCSRnB UCSR0B
-#    define UCSRnC UCSR0C
-#    define U2Xn U2X0
-#    define RXENn RXEN0
-#    define TXENn TXEN0
-#    define RXCIEn RXCIE0
-#    define UCSZn1 UCSZ01
-#    define UCSZn0 UCSZ00
-#    define UDRIEn UDRIE0
-#    define USARTn_UDRE_vect USART_UDRE_vect
-#    define USARTn_RX_vect USART_RX_vect
-#elif defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega32U2__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__)
+#if defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__)
 #    define UDRn UDR1
 #    define UBRRnL UBRR1L
 #    define UCSRnA UCSR1A
@@ -76,6 +59,21 @@
 #    define UDRIEn UDRIE
 #    define USARTn_UDRE_vect USART_UDRE_vect
 #    define USARTn_RX_vect USART_RX_vect
+#elif defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__)
+#    define UDRn UDR0
+#    define UBRRnL UBRR0L
+#    define UCSRnA UCSR0A
+#    define UCSRnB UCSR0B
+#    define UCSRnC UCSR0C
+#    define U2Xn U2X0
+#    define RXENn RXEN0
+#    define TXENn TXEN0
+#    define RXCIEn RXCIE0
+#    define UCSZn1 UCSZ01
+#    define UCSZn0 UCSZ00
+#    define UDRIEn UDRIE0
+#    define USARTn_UDRE_vect USART_UDRE_vect
+#    define USARTn_RX_vect USART_RX_vect
 #endif
 
 // These buffers may be any size from 2 to 256 bytes.
@@ -131,16 +129,16 @@ uint8_t uart_getchar(void) {
     return c;
 }
 
-// Return the number of bytes waiting in the receive buffer.
+// Return whether the number of bytes waiting in the receive buffer is nonzero.
 // Call this before uart_getchar() to check if it will need
 // to wait for a byte to arrive.
-uint8_t uart_available(void) {
+bool uart_available(void) {
     uint8_t head, tail;
 
     head = rx_buffer_head;
     tail = rx_buffer_tail;
-    if (head >= tail) return head - tail;
-    return RX_BUFFER_SIZE + head - tail;
+    if (head >= tail) return (head - tail) > 0;
+    return (RX_BUFFER_SIZE + head - tail) > 0;
 }
 
 // Transmit Interrupt

+ 34 - 0
drivers/avr/uart.h

@@ -0,0 +1,34 @@
+/* UART Example for Teensy USB Development Board
+ * http://www.pjrc.com/teensy/
+ * Copyright (c) 2009 PJRC.COM, LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+void uart_init(uint32_t baud);
+
+void uart_putchar(uint8_t c);
+
+uint8_t uart_getchar(void);
+
+bool uart_available(void);

+ 59 - 0
drivers/chibios/uart.c

@@ -0,0 +1,59 @@
+/* Copyright 2021
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it 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.
+ *
+ *  This program 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 program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "uart.h"
+
+#include "quantum.h"
+
+static SerialConfig serialConfig = {
+    SERIAL_DEFAULT_BITRATE,
+    SD1_CR1,
+    SD1_CR2,
+    SD1_CR3
+};
+
+void uart_init(uint32_t baud) {
+    static bool is_initialised = false;
+
+    if (!is_initialised) {
+        is_initialised = true;
+
+        serialConfig.speed = baud;
+
+#if defined(USE_GPIOV1)
+        palSetLineMode(SD1_TX_PIN, PAL_MODE_STM32_ALTERNATE_OPENDRAIN);
+        palSetLineMode(SD1_RX_PIN, PAL_MODE_STM32_ALTERNATE_OPENDRAIN);
+#else
+        palSetLineMode(SD1_TX_PIN, PAL_MODE_ALTERNATE(SD1_TX_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN);
+        palSetLineMode(SD1_RX_PIN, PAL_MODE_ALTERNATE(SD1_RX_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN);
+#endif
+        sdStart(&SERIAL_DRIVER, &serialConfig);
+    }
+}
+
+void uart_putchar(uint8_t c) {
+    sdPut(&SERIAL_DRIVER, c);
+}
+
+uint8_t uart_getchar(void) {
+    msg_t res = sdGet(&SERIAL_DRIVER);
+
+    return (uint8_t)res;
+}
+
+bool uart_available(void) {
+    return !sdGetWouldBlock(&SERIAL_DRIVER);
+}

+ 77 - 0
drivers/chibios/uart.h

@@ -0,0 +1,77 @@
+/* Copyright 2021
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it 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.
+ *
+ *  This program 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 program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#include <hal.h>
+
+#ifndef SERIAL_DRIVER
+#    define SERIAL_DRIVER SD1
+#endif
+
+#ifndef SD1_TX_PIN
+#    define SD1_TX_PIN A9
+#endif
+
+#ifndef SD1_TX_PAL_MODE
+#    define SD1_TX_PAL_MODE 7
+#endif
+
+#ifndef SD1_RX_PIN
+#    define SD1_RX_PIN A10
+#endif
+
+#ifndef SD1_RX_PAL_MODE
+#    define SD1_RX_PAL_MODE 7
+#endif
+
+#ifndef SD1_CTS_PIN
+#    define SD1_CTS_PIN A11
+#endif
+
+#ifndef SD1_CTS_PAL_MODE
+#    define SD1_CTS_PAL_MODE 7
+#endif
+
+#ifndef SD1_RTS_PIN
+#    define SD1_RTS_PIN A12
+#endif
+
+#ifndef SD1_RTS_PAL_MODE
+#    define SD1_RTS_PAL_MODE 7
+#endif
+
+#ifndef SD1_CR1
+#    define SD1_CR1 0
+#endif
+
+#ifndef SD1_CR2
+#    define SD1_CR2 0
+#endif
+
+#ifndef SD1_CR3
+#    define SD1_CR3 0
+#endif
+
+void uart_init(uint32_t baud);
+
+void uart_putchar(uint8_t c);
+
+uint8_t uart_getchar(void);
+
+bool uart_available(void);

+ 1 - 1
keyboards/mschwingen/modelm/rules.mk

@@ -29,7 +29,7 @@ DYNAMIC_MACRO_ENABLE = yes
 UART_DEBUG = no
 
 SRC += matrix.c
-QUANTUM_LIB_SRC += $(COMMON_DIR)/uart.c \
+QUANTUM_LIB_SRC += uart.c \
                    spi_master.c
 
 OPT_DEFS += -DSLEEP_LED_ENABLE # we need our own sleep callbacks to turn of WS2812 LEDs

+ 1 - 0
keyboards/nullbitsco/nibble/remote_kb.c

@@ -27,6 +27,7 @@ This will require a new communication protocol, as the current one is limited.
 */
 
 #include "remote_kb.h"
+#include "uart.h"
 
 uint8_t
  msg[UART_MSG_LEN],

+ 0 - 1
keyboards/nullbitsco/nibble/remote_kb.h

@@ -16,7 +16,6 @@
 #pragma once
 
 #include "quantum.h"
-#include "tmk_core/common/uart.h"
 
 #define SERIAL_UART_BAUD 153600 //low error rate for 32u4 @ 16MHz
 

+ 2 - 5
keyboards/nullbitsco/nibble/rules.mk

@@ -1,9 +1,6 @@
 # MCU name
 MCU = atmega32u4
 
-# Interrupt driven control endpoint task(+60)
-OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT
-
 # Bootloader selection
 BOOTLOADER = atmel-dfu
 
@@ -31,5 +28,5 @@ CUSTOM_MATRIX = lite        # Lite custom matrix
 SRC += matrix.c \
        bitc_led.c \
        big_led.c \
-       remote_kb.c \
-       tmk_core/common/uart.c
+       remote_kb.c
+QUANTUM_LIB_SRC += uart.c

+ 2 - 2
platforms/chibios/QMK_PROTON_C/configs/mcuconf.h

@@ -212,8 +212,8 @@
 /*
  * SERIAL driver system settings.
  */
-#define STM32_SERIAL_USE_USART1             FALSE
-#define STM32_SERIAL_USE_USART2             TRUE
+#define STM32_SERIAL_USE_USART1             TRUE
+#define STM32_SERIAL_USE_USART2             FALSE
 #define STM32_SERIAL_USE_USART3             FALSE
 #define STM32_SERIAL_USE_UART4              FALSE
 #define STM32_SERIAL_USE_UART5              FALSE

+ 0 - 8
tmk_core/common/uart.h

@@ -1,8 +0,0 @@
-#pragma once
-
-#include <stdint.h>
-
-void    uart_init(uint32_t baud);
-void    uart_putchar(uint8_t c);
-uint8_t uart_getchar(void);
-uint8_t uart_available(void);