diff options
| author | Drashna Jaelre <drashna@live.com> | 2020-02-21 02:32:30 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-02-21 21:32:30 +1100 |
| commit | 1751c3cc25ecc1734976d9790598d64133ee306d (patch) | |
| tree | d9e8dea87ccc9379b53718acdde836e43f2ed18f | |
| parent | 67ee050a0e80359b5b58ea1767adfb96b5bdace5 (diff) | |
| download | qmk_firmware-1751c3cc25ecc1734976d9790598d64133ee306d.tar.gz qmk_firmware-1751c3cc25ecc1734976d9790598d64133ee306d.zip | |
uart.c fix from TMK (#7628)
* uart.c fix from TMK
Backport from tmk/tmk_keyboard@c41e48a0ab0712d2667feb6b5dd8a4d5491cfcc5
* Avoid deadlock when uart.c is usind in ISR
Backport from tmk/tmk_keyboard@55443fabb731459e21b45781c6d951edac5d75f4
| -rw-r--r-- | tmk_core/common/uart.c | 54 |
1 files changed, 44 insertions, 10 deletions
diff --git a/tmk_core/common/uart.c b/tmk_core/common/uart.c index f2e4bc4f3..412fcf8e1 100644 --- a/tmk_core/common/uart.c +++ b/tmk_core/common/uart.c | |||
| @@ -31,9 +31,41 @@ | |||
| 31 | 31 | ||
| 32 | #include "uart.h" | 32 | #include "uart.h" |
| 33 | 33 | ||
| 34 | #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__) | ||
| 35 | # define UDRn UDR0 | ||
| 36 | # define UBRRn UBRR0 | ||
| 37 | # define UCSRnA UCSR0A | ||
| 38 | # define UCSRnB UCSR0B | ||
| 39 | # define UCSRnC UCSR0C | ||
| 40 | # define U2Xn U2X0 | ||
| 41 | # define RXENn RXEN0 | ||
| 42 | # define TXENn TXEN0 | ||
| 43 | # define RXCIEn RXCIE0 | ||
| 44 | # define UCSZn1 UCSZ01 | ||
| 45 | # define UCSZn0 UCSZ00 | ||
| 46 | # define UDRIEn UDRIE0 | ||
| 47 | # define UDRE_vect USART_UDRE_vect | ||
| 48 | # define RX_vect USART_RX_vect | ||
| 49 | #elif defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega32U2__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) | ||
| 50 | # define UDRn UDR1 | ||
| 51 | # define UBRRn UBRR1 | ||
| 52 | # define UCSRnA UCSR1A | ||
| 53 | # define UCSRnB UCSR1B | ||
| 54 | # define UCSRnC UCSR1C | ||
| 55 | # define U2Xn U2X1 | ||
| 56 | # define RXENn RXEN1 | ||
| 57 | # define TXENn TXEN1 | ||
| 58 | # define RXCIEn RXCIE1 | ||
| 59 | # define UCSZn1 UCSZ11 | ||
| 60 | # define UCSZn0 UCSZ10 | ||
| 61 | # define UDRIEn UDRIE1 | ||
| 62 | # define UDRE_vect USART1_UDRE_vect | ||
| 63 | # define RX_vect USART1_RX_vect | ||
| 64 | #endif | ||
| 65 | |||
| 34 | // These buffers may be any size from 2 to 256 bytes. | 66 | // These buffers may be any size from 2 to 256 bytes. |
| 35 | #define RX_BUFFER_SIZE 64 | 67 | #define RX_BUFFER_SIZE 64 |
| 36 | #define TX_BUFFER_SIZE 40 | 68 | #define TX_BUFFER_SIZE 256 |
| 37 | 69 | ||
| 38 | static volatile uint8_t tx_buffer[TX_BUFFER_SIZE]; | 70 | static volatile uint8_t tx_buffer[TX_BUFFER_SIZE]; |
| 39 | static volatile uint8_t tx_buffer_head; | 71 | static volatile uint8_t tx_buffer_head; |
| @@ -45,10 +77,10 @@ static volatile uint8_t rx_buffer_tail; | |||
| 45 | // Initialize the UART | 77 | // Initialize the UART |
| 46 | void uart_init(uint32_t baud) { | 78 | void uart_init(uint32_t baud) { |
| 47 | cli(); | 79 | cli(); |
| 48 | UBRR0 = (F_CPU / 4 / baud - 1) / 2; | 80 | UBRRn = (F_CPU / 4 / baud - 1) / 2; |
| 49 | UCSR0A = (1 << U2X0); | 81 | UCSRnA = (1 << U2Xn); |
| 50 | UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0); | 82 | UCSRnB = (1 << RXENn) | (1 << TXENn) | (1 << RXCIEn); |
| 51 | UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); | 83 | UCSRnC = (1 << UCSZn1) | (1 << UCSZn0); |
| 52 | tx_buffer_head = tx_buffer_tail = 0; | 84 | tx_buffer_head = tx_buffer_tail = 0; |
| 53 | rx_buffer_head = rx_buffer_tail = 0; | 85 | rx_buffer_head = rx_buffer_tail = 0; |
| 54 | sei(); | 86 | sei(); |
| @@ -60,12 +92,14 @@ void uart_putchar(uint8_t c) { | |||
| 60 | 92 | ||
| 61 | i = tx_buffer_head + 1; | 93 | i = tx_buffer_head + 1; |
| 62 | if (i >= TX_BUFFER_SIZE) i = 0; | 94 | if (i >= TX_BUFFER_SIZE) i = 0; |
| 95 | // return immediately to avoid deadlock when interrupt is disabled(called from ISR) | ||
| 96 | if (tx_buffer_tail == i && (SREG & (1<<SREG_I)) == 0) return; | ||
| 63 | while (tx_buffer_tail == i) | 97 | while (tx_buffer_tail == i) |
| 64 | ; // wait until space in buffer | 98 | ; // wait until space in buffer |
| 65 | // cli(); | 99 | // cli(); |
| 66 | tx_buffer[i] = c; | 100 | tx_buffer[i] = c; |
| 67 | tx_buffer_head = i; | 101 | tx_buffer_head = i; |
| 68 | UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0) | (1 << UDRIE0); | 102 | UCSRB = (1 << RXENn) | (1 << TXENn) | (1 << RXCIEn) | (1 << UDRIEn); |
| 69 | // sei(); | 103 | // sei(); |
| 70 | } | 104 | } |
| 71 | 105 | ||
| @@ -95,12 +129,12 @@ uint8_t uart_available(void) { | |||
| 95 | } | 129 | } |
| 96 | 130 | ||
| 97 | // Transmit Interrupt | 131 | // Transmit Interrupt |
| 98 | ISR(USART_UDRE_vect) { | 132 | ISR(UDRE_vect) { |
| 99 | uint8_t i; | 133 | uint8_t i; |
| 100 | 134 | ||
| 101 | if (tx_buffer_head == tx_buffer_tail) { | 135 | if (tx_buffer_head == tx_buffer_tail) { |
| 102 | // buffer is empty, disable transmit interrupt | 136 | // buffer is empty, disable transmit interrupt |
| 103 | UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0); | 137 | UCSRnB = (1 << RXENn) | (1 << TXENn) | (1 << RXCIEn); |
| 104 | } else { | 138 | } else { |
| 105 | i = tx_buffer_tail + 1; | 139 | i = tx_buffer_tail + 1; |
| 106 | if (i >= TX_BUFFER_SIZE) i = 0; | 140 | if (i >= TX_BUFFER_SIZE) i = 0; |
| @@ -110,10 +144,10 @@ ISR(USART_UDRE_vect) { | |||
| 110 | } | 144 | } |
| 111 | 145 | ||
| 112 | // Receive Interrupt | 146 | // Receive Interrupt |
| 113 | ISR(USART_RX_vect) { | 147 | ISR(RX_vect) { |
| 114 | uint8_t c, i; | 148 | uint8_t c, i; |
| 115 | 149 | ||
| 116 | c = UDR0; | 150 | c = UDRn; |
| 117 | i = rx_buffer_head + 1; | 151 | i = rx_buffer_head + 1; |
| 118 | if (i >= RX_BUFFER_SIZE) i = 0; | 152 | if (i >= RX_BUFFER_SIZE) i = 0; |
| 119 | if (i != rx_buffer_tail) { | 153 | if (i != rx_buffer_tail) { |
