Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UART driver refactor #11637

Merged
merged 8 commits into from
Jan 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/_summary.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
90 changes: 90 additions & 0 deletions docs/uart_driver.md
Original file line number Diff line number Diff line change
@@ -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.
42 changes: 20 additions & 22 deletions tmk_core/common/uart.c → drivers/avr/uart.c
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
34 changes: 34 additions & 0 deletions drivers/avr/uart.h
Original file line number Diff line number Diff line change
@@ -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 changes: 59 additions & 0 deletions drivers/chibios/uart.c
Original file line number Diff line number Diff line change
@@ -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 changes: 77 additions & 0 deletions drivers/chibios/uart.h
Original file line number Diff line number Diff line change
@@ -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);
2 changes: 1 addition & 1 deletion keyboards/mschwingen/modelm/rules.mk
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions keyboards/nullbitsco/nibble/remote_kb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand Down
1 change: 0 additions & 1 deletion keyboards/nullbitsco/nibble/remote_kb.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
7 changes: 2 additions & 5 deletions keyboards/nullbitsco/nibble/rules.mk
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
# MCU name
MCU = atmega32u4

# Interrupt driven control endpoint task(+60)
OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT

# Bootloader selection
BOOTLOADER = atmel-dfu

Expand Down Expand Up @@ -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
4 changes: 2 additions & 2 deletions platforms/chibios/QMK_PROTON_C/configs/mcuconf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading