YAHAL
Yet Another Hardware Abstraction Library
Loading...
Searching...
No Matches
uart_rp2040.cpp
1
2// ---------------------------------------------
3// This file is part of
4// _ _ __ _ _ __ __
5// ( \/ ) /__\ ( )_( ) /__\ ( )
6// \ / /(__)\ ) _ ( /(__)\ )(__
7// (__)(__)(__)(_) (_)(__)(__)(____)
8//
9// Yet Another HW Abstraction Library
10// Copyright (C) Andreas Terstegge
11// BSD Licensed (see file LICENSE)
12//
13// ---------------------------------------------
14//
15// UART driver for RP2040.
16//
17#include "uart_rp2040.h"
18#include "gpio_rp2040.h"
19#include "system_rp2040.h"
20#include "task.h"
21#include <cassert>
22
23using namespace _UART0_;
24using namespace _UART1_;
25using namespace _IO_BANK0_;
26using namespace _RESETS_;
27
28function<void(char)> uart_rp2040::_intHandler[2];
29
30int8_t uart_rp2040::_uart_tx_pins[2][4] =
31 { { 0, 12, 16, 28 }, { 4, 8, 20, 24 } };
32
33uart_rp2040::uart_rp2040(gpio_pin_t tx_pin, gpio_pin_t rx_pin,
34 uint32_t baud, uart_mode_t mode)
35: _init(false), _tx(tx_pin), _rx(rx_pin), _baud(baud), _mode(mode) {
36
37 bool tx_found = false;
38 bool rx_found = false;
39 for (_index=0; _index < 2; ++_index) {
40 tx_found = false;
41 rx_found = false;
42 for (size_t i = 0; i < 4; ++i) {
43 if (tx_pin == _uart_tx_pins[_index][i]) {
44 tx_found = true;
45 }
46 if (rx_pin == (_uart_tx_pins[_index][i]+1)) {
47 rx_found = true;
48 }
49 }
50 if (tx_found && rx_found) break;
51 }
52 assert(tx_found && rx_found);
53
54 // Set register pointer
55 _uart = (_index==0) ? &UART0 : &UART1;
56 _uart_set = (_index==0) ? &UART0_SET : &UART1_SET;
57 _uart_clr = (_index==0) ? &UART0_CLR : &UART1_CLR;
58}
59
60void uart_rp2040::init() {
61 // Take UART out of reset state
62 if (_index) RESETS_CLR.RESET.uart1 = 1;
63 else RESETS_CLR.RESET.uart0 = 1;
64 // Configure GPIO pins
65 _tx.setSEL(GPIO_CTRL_FUNCSEL__uart);
66 _rx.setSEL(GPIO_CTRL_FUNCSEL__uart);
67 // Configure UART protocol (default 8N1)
68 uartMode(_mode);
69 // Set baud rate
70 setBaudrate(_baud);
71 // Enable UART & FIFOs
72 _uart_set->UARTCR.UARTEN <<= 1;
73 _uart_set->UARTLCR_H.FEN <<= 1;
74 _init = true;
75}
76
77uart_rp2040::~uart_rp2040() {
78 // Check if we need to de-configure
79 if (!_init) return;
80 // Wait for pending operations
81 while( (_uart->UARTFR.TXFE) == 0) ;
82 // Reset UART
83 if (_index) RESETS_SET.RESET.uart1 = 1;
84 else RESETS_SET.RESET.uart0 = 1;
85 // De-configure the digital RX/TX lines
86 _tx.setSEL( GPIO_CTRL_FUNCSEL__null );
87 _rx.setSEL( GPIO_CTRL_FUNCSEL__null );
88}
89
90bool uart_rp2040::available() {
91 if (!_init) init();
92 return !_uart->UARTFR.RXFE;
93}
94
95char uart_rp2040::getc() {
96 if (!_init) init();
97 // Wait until the RX Buffer is not empty....
98 while(_uart->UARTFR.RXFE) ;
99 // Transfer single char from RX buffer
100 return _uart->UARTDR.DATA;
101}
102
103void uart_rp2040::putc(char c) {
104 if (!_init) init();
105 // Wait until the TX FIFO is not full....
106 while(_uart->UARTFR.TXFF) ;
107 // Transfer single char to TX buffer
108 _uart->UARTDR.DATA = (uint16_t)c;
109}
110
111int uart_rp2040::puts(const char *s) {
112 int len = 0;
113 while(*s) {
114 putc(*s++);
115 len++;
116 }
117 return len;
118}
119
120void uart_rp2040::uartMode(uart_mode_t mode) {
121 _mode = mode;
122 if (mode & UART::BITS_7) {
123 _uart->UARTLCR_H.WLEN = 2;
124 }
125 if (mode & UART::BITS_8) {
126 _uart->UARTLCR_H.WLEN = 3;
127 }
128 if (mode & UART::NO_PARITY) {
129 _uart->UARTLCR_H.PEN = 0;
130 }
131 if (mode & UART::EVEN_PARITY) {
132 _uart->UARTLCR_H.PEN = 1;
133 _uart->UARTLCR_H.EPS = 1;
134 }
135 if (mode & UART::ODD_PARITY) {
136 _uart->UARTLCR_H.PEN = 1;
137 _uart->UARTLCR_H.EPS = 0;
138 }
139 if (mode & UART::STOPBITS_1) {
140 _uart->UARTLCR_H.STP2 = 0;
141 }
142 if (mode & UART::STOPBITS_2) {
143 _uart->UARTLCR_H.STP2 = 1;
144 }
145}
146
147void uart_rp2040::setBaudrate(uint32_t baud) {
148 _baud = baud;
149 uint32_t baud_div = (8 * CLK_PERI) / _baud;
150 _uart->UARTIBRD = (baud_div >> 7);
151 _uart->UARTFBRD = ((baud_div & 0x7f) + 1) / 2;
152 // dummy write
153 _uart_set->UARTLCR_H <<= 0;
154}
155
156void uart_rp2040::sendBreak(uint16_t ms) {
157 if (ms == 0) {
158 _uart_clr->UARTLCR_H.BRK <<= 1;
159 } else if (ms == 0xffff) {
160 _uart_set->UARTLCR_H.BRK <<= 1;
161 } else {
162 _uart_set->UARTLCR_H.BRK <<= 1;
163 task::sleep_ms(ms);
164 _uart_clr->UARTLCR_H.BRK <<= 1;
165 }
166}
167
168void uart_rp2040::setDTR(bool dtr) {
169 _uart->UARTCR.DTR = dtr;
170}
171
172void uart_rp2040::setRTS(bool rts) {
173 _uart->UARTCR.RTS = rts;
174}
175
176void uart_rp2040::uartAttachIrq(function<void(char)> f) {
177 if (!_init) init();
178 _intHandler[_index] = f;
179 // Enable RX interrupt
180 _uart_set->UARTIMSC.RXIM <<= 1;
181 _uart_set->UARTIMSC.RTIM <<= 1;
182 // Enable NVIC interrupt
183 NVIC_EnableIRQ((IRQn_Type)(UART0_IRQ_IRQn + _index));
184}
185
186void uart_rp2040::uartDetachIrq () {
187 if (!_init) init();
188 // Disable NVIC interrupt
189 NVIC_DisableIRQ((IRQn_Type)(UART0_IRQ_IRQn + _index));
190 // Disable RX interrupt
191 _uart_clr->UARTIMSC.RXIM <<= 1;
192 _uart_clr->UARTIMSC.RTIM <<= 1;
193 // Clear pending interrupts
194 _uart_set->UARTICR.RXIC <<= 1;
195 _uart_set->UARTICR.RTIC <<= 1;
196 // Clear handler
197 _intHandler[_index] = nullptr;
198}
199
200void uart_rp2040::uartEnableIrq () {
201 _uart_set->UARTIMSC.RXIM <<= 1;
202 _uart_set->UARTIMSC.RTIM <<= 1;
203}
204
205void uart_rp2040::uartDisableIrq() {
206 _uart_clr->UARTIMSC.RXIM <<= 1;
207 _uart_clr->UARTIMSC.RTIM <<= 1;
208}
209
210void uart_rp2040::enableFIFO(bool val) {
211 if (!_init) init();
212 _uart->UARTLCR_H.FEN = val;
213}
214
215// Interrupt handler for UART0/1
217extern "C" {
218
219void UART0_IRQ_Handler(void) {
220 while(!UART0.UARTFR.RXFE) {
221 uart_rp2040::_intHandler[0](UART0.UARTDR.DATA);
222 }
223}
224
225void UART1_IRQ_Handler(void) {
226 while(!UART1.UARTFR.RXFE) {
227 uart_rp2040::_intHandler[1](UART1.UARTDR.DATA);
228 }
229}
230
231} // extern "C"