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