|
5 | 5 | */ |
6 | 6 |
|
7 | 7 | /** |
8 | | - * @ingroup cpu_rp2350_riscv |
| 8 | + * @ingroup cpu_rp2350 |
9 | 9 | * @{ |
10 | 10 | * |
11 | 11 | * @file |
|
18 | 18 |
|
19 | 19 | #include "periph_cpu.h" |
20 | 20 |
|
21 | | -int uart_init(uart_t uart, uint32_t baud, uart_rx_cb_t rx_cb, void *arg) { |
22 | | - (void)uart; |
23 | | - (void)baud; |
24 | | - (void)rx_cb; |
25 | | - (void)arg; |
26 | | - /* Set the UART pins to the correct function */ |
27 | | - IO_BANK0->GPIO0_CTRL = FUNCTION_SELECT_UART; |
28 | | - IO_BANK0->GPIO1_CTRL = FUNCTION_SELECT_UART; |
29 | | - /* Clear the ISO bits */ |
30 | | - atomic_clear(&PADS_BANK0->GPIO0, PADS_BANK0_ISO_BITS); |
31 | | - atomic_clear(&PADS_BANK0->GPIO1, PADS_BANK0_ISO_BITS); |
32 | | - /* Set IE bit for gpio1 */ |
33 | | - PADS_BANK0->GPIO1 = PADS_BANK0->GPIO1 | PADS_BANK0_GPIO0_IE_BITS; |
| 21 | +#include "regs/uart.h" |
| 22 | +#include <RP2350.h> |
34 | 23 |
|
35 | | - /* We reset UART0 here, so we can be sure it is in a known state */ |
36 | | - reset_component(RESET_UART0, RESET_UART0); |
| 24 | +#define ENABLE_DEBUG 0 |
| 25 | +#include "debug.h" |
| 26 | + |
| 27 | +#include "xh3irq.h" |
| 28 | + |
| 29 | +#include "board.h" |
| 30 | + |
| 31 | +static uart_isr_ctx_t ctx[UART_NUMOF]; |
37 | 32 |
|
38 | | - UART0->UARTIBRD = IBRD; |
39 | | - UART0->UARTFBRD = FBRD; |
40 | | - uart_mode(0, 8, UART_PARITY_NONE, 1); |
41 | | - return 0; |
| 33 | +/* back up values of registers used during uart_poweroff() / uart_poweron() */ |
| 34 | +static uint32_t uartibrd; |
| 35 | +static uint32_t uartfbrd; |
| 36 | +static uint32_t uartlcr_h; |
| 37 | +static uint32_t uartcr; |
| 38 | + |
| 39 | +/** Pico1 uart uses non-sdk conform defines |
| 40 | + * @todo Change Pico1 defines if I ever get around to it |
| 41 | + */ |
| 42 | +#define UART0_UARTIMSC_RXIM_Msk (UART_UARTIMSC_RXIM_BITS) |
| 43 | + |
| 44 | +void _irq_enable(uart_t uart) { |
| 45 | + UART0_Type *dev = uart_config[uart].dev; |
| 46 | + /* We set the UART Receive Interrupt Mask (Bit 4) [See p979 UART 12.1]*/ |
| 47 | + dev->UARTIMSC = UART0_UARTIMSC_RXIM_Msk; |
| 48 | + /* Enable the IRQ in the NVIC */ |
| 49 | + xh3irq_enable_irq(uart_config[uart].irqn); |
42 | 50 | } |
43 | 51 |
|
44 | 52 | int uart_mode(uart_t uart, uart_data_bits_t data_bits, uart_parity_t parity, |
45 | | - uart_stop_bits_t stop_bits) { |
46 | | - (void)uart; |
| 53 | + uart_stop_bits_t stop_bits) { |
| 54 | + assert((unsigned)uart < UART_NUMOF); |
| 55 | + UART0_Type *dev = uart_config[uart].dev; |
| 56 | + |
47 | 57 | (void)data_bits; |
48 | 58 | (void)stop_bits; |
49 | | - atomic_clear(&UART0->UARTCR, UART_UARTCR_UARTEN_BITS | UART_UARTCR_RXE_BITS | |
50 | | - UART_UARTCR_TXE_BITS); |
| 59 | + |
| 60 | + /* Disable the UART before changing the mode */ |
| 61 | + atomic_clear(&dev->UARTCR, UART_UARTCR_UARTEN_BITS | UART_UARTCR_RXE_BITS | |
| 62 | + UART_UARTCR_TXE_BITS); |
51 | 63 |
|
52 | 64 | /* Set the data bits, parity, and stop bits |
53 | 65 | * Set to 8 bits (0b11) based on Table 1035 page 976 |
| 66 | + * @todo allow different data bits |
54 | 67 | */ |
55 | | - UART0->UARTLCR_H = 0b11 << 5; |
| 68 | + dev->UARTLCR_H = 0b11 << 5; |
56 | 69 |
|
57 | 70 | switch (parity) { |
58 | | - case UART_PARITY_NONE: |
| 71 | + case UART_PARITY_NONE: |
59 | 72 | break; |
60 | | - default: |
| 73 | + // case UART_PARITY_EVEN: |
| 74 | + // io_reg_atomic_set(&dev->UARTLCR_H, UART0_UARTLCR_H_EPS_Msk | UART0_UARTLCR_H_PEN_Msk); |
| 75 | + // break; |
| 76 | + // case UART_PARITY_ODD: |
| 77 | + // io_reg_atomic_set(&dev->UARTLCR_H, UART0_UARTLCR_H_PEN_Msk); |
| 78 | + // break; |
| 79 | + default: |
61 | 80 | return UART_NOMODE; |
62 | 81 | } |
63 | 82 |
|
64 | | - UART0->UARTCR = UART_UARTCR_TXE_BITS | UART_UARTCR_UARTEN_BITS; |
| 83 | + dev->UARTCR = UART_UARTCR_TXE_BITS | UART_UARTCR_UARTEN_BITS | UART_UARTCR_RXE_BITS; |
| 84 | + |
| 85 | + return UART_OK; |
| 86 | +} |
| 87 | + |
| 88 | +static void _reset_uart(uart_t uart) { |
| 89 | + switch (uart) { |
| 90 | + case 0: |
| 91 | + /* We reset UART0 here, so we can be sure it is in a known state */ |
| 92 | + reset_component(RESET_UART0, RESET_UART0); |
| 93 | + break; |
| 94 | + case 1: |
| 95 | + /* We reset UART1 here, so we can be sure it is in a known state */ |
| 96 | + reset_component(RESET_UART1, RESET_UART1); |
| 97 | + break; |
| 98 | + default: |
| 99 | + break; |
| 100 | + } |
| 101 | +} |
| 102 | + |
| 103 | +void uart_init_pins(uart_t uart) { |
| 104 | + assert((unsigned)uart < UART_NUMOF); |
| 105 | + UART0_Type *dev = uart_config[uart].dev; |
| 106 | + |
| 107 | + /* Set the UART pins to the correct function */ |
| 108 | + *(uint32_t *)calculate_gpio_io_ctrl_register_addr(uart_config[uart].tx_pin) = FUNCTION_SELECT_UART; |
| 109 | + *(uint32_t *)calculate_gpio_io_ctrl_register_addr(uart_config[uart].rx_pin) = FUNCTION_SELECT_UART; |
| 110 | + /* Clear the ISO bits */ |
| 111 | + atomic_clear((uint32_t *)calculate_gpio_pad_register_addr(uart_config[uart].tx_pin), PADS_BANK0_ISO_BITS); |
| 112 | + atomic_clear((uint32_t *)calculate_gpio_pad_register_addr(uart_config[uart].rx_pin), PADS_BANK0_ISO_BITS); |
| 113 | + |
| 114 | + /* Set Input Enable Flag */ |
| 115 | + atomic_set((uint32_t *)calculate_gpio_pad_register_addr(uart_config[uart].rx_pin), PADS_BANK0_GPIO0_IE_BITS); |
| 116 | + |
| 117 | + /* We reset UART0 here, so we can be sure it is in a known state */ |
| 118 | + _reset_uart(uart); |
| 119 | + |
| 120 | + dev->UARTIBRD = IBRD; |
| 121 | + dev->UARTFBRD = FBRD; |
| 122 | +} |
| 123 | + |
| 124 | +int uart_init(uart_t uart, uint32_t baud, uart_rx_cb_t rx_cb, void *arg) { |
| 125 | + (void)baud; |
| 126 | + |
| 127 | + if (uart >= UART_NUMOF) { |
| 128 | + return UART_NODEV; |
| 129 | + } |
| 130 | + |
| 131 | + UART0_Type *dev = uart_config[uart].dev; |
| 132 | + ctx[uart].rx_cb = rx_cb; |
| 133 | + ctx[uart].arg = arg; |
| 134 | + |
| 135 | + uart_init_pins(uart); |
| 136 | + |
| 137 | + if (uart_mode(uart, UART_DATA_BITS_8, UART_PARITY_NONE, UART_STOP_BITS_1) != UART_OK) { |
| 138 | + return UART_NOMODE; |
| 139 | + } |
| 140 | + |
| 141 | + /* enable RX and IRQs, if needed */ |
| 142 | + if (rx_cb != NULL) { |
| 143 | + _irq_enable(uart); |
| 144 | + /* clear any pending data and IRQ to avoid receiving a garbage char */ |
| 145 | + uint32_t status = dev->UARTRIS; |
| 146 | + dev->UARTICR = status; |
| 147 | + (void)dev->UARTDR; |
| 148 | + atomic_set(&dev->UARTCR, UART_UARTCR_RXE_BITS); |
| 149 | + } |
65 | 150 |
|
66 | 151 | return UART_OK; |
67 | 152 | } |
68 | 153 |
|
69 | 154 | void uart_write(uart_t uart, const uint8_t *data, size_t len) { |
70 | | - (void)uart; |
| 155 | + UART0_Type *dev = uart_config[uart].dev; |
71 | 156 | for (size_t i = 0; i < len; i++) { |
72 | | - UART0->UARTDR = data[i]; |
| 157 | + dev->UARTDR = data[i]; |
73 | 158 | /* Wait until the TX FIFO is empty before sending the next byte */ |
74 | | - while (!(UART0->UARTFR & UART_UARTFR_TXFE_BITS)) { |
| 159 | + while (!(dev->UARTFR & UART_UARTFR_TXFE_BITS)) { |
75 | 160 | } |
76 | 161 | } |
77 | 162 | } |
78 | 163 |
|
79 | 164 | void uart_poweron(uart_t uart) { |
80 | | - (void)uart; |
| 165 | + assert((unsigned)uart < UART_NUMOF); |
| 166 | + /* Get into a save state where we know whats up */ |
| 167 | + _reset_uart(uart); |
| 168 | + UART0_Type *dev = uart_config[uart].dev; |
| 169 | + /* Restore config from registers */ |
| 170 | + dev->UARTIBRD = uartibrd; |
| 171 | + dev->UARTFBRD = uartfbrd; |
| 172 | + dev->UARTLCR_H = uartlcr_h; |
| 173 | + dev->UARTCR = uartcr; |
| 174 | + /* restore IRQs, if needed */ |
| 175 | + if (ctx[uart].rx_cb != NULL) { |
| 176 | + _irq_enable(uart); |
| 177 | + } |
| 178 | + uart_init_pins(uart); |
| 179 | +} |
| 180 | + |
| 181 | +void uart_deinit_pins(uart_t uart) { |
| 182 | + assert((unsigned)uart < UART_NUMOF); |
| 183 | + /* @TODO */ |
| 184 | + /* gpio_reset_all_config(uart_config[uart].tx_pin); */ |
| 185 | + SIO->GPIO_OE_CLR = 1LU << uart_config[uart].tx_pin; |
| 186 | + if (ctx[uart].rx_cb) { |
| 187 | + /* gpio_reset_all_config(uart_config[uart].rx_pin); */ |
| 188 | + } |
81 | 189 | } |
| 190 | + |
82 | 191 | void uart_poweroff(uart_t uart) { |
83 | | - (void)uart; |
| 192 | + assert((unsigned)uart < UART_NUMOF); |
| 193 | + UART0_Type *dev = uart_config[uart].dev; |
| 194 | + /* backup configuration registers */ |
| 195 | + uartibrd = dev->UARTIBRD; |
| 196 | + uartfbrd = dev->UARTFBRD; |
| 197 | + uartlcr_h = dev->UARTLCR_H; |
| 198 | + uartcr = dev->UARTCR; |
| 199 | + /* disconnect GPIOs and power off peripheral */ |
| 200 | + uart_deinit_pins(uart); |
| 201 | + _reset_uart(uart); |
| 202 | +} |
| 203 | + |
| 204 | +void isr_handler(uint8_t num) { |
| 205 | + UART0_Type *dev = uart_config[num].dev; |
| 206 | + |
| 207 | + uint32_t status = dev->UARTMIS; |
| 208 | + dev->UARTICR = status; |
| 209 | + |
| 210 | + if (status & UART_UARTMIS_RXMIS_BITS) { |
| 211 | + uint32_t data = dev->UARTDR; |
| 212 | + // if (data & (UART0_UARTDR_BE_Msk | UART0_UARTDR_PE_Msk | UART0_UARTDR_FE_Msk)) { |
| 213 | + // DEBUG_PUTS("[rpx0xx] uart RX error (parity, break, or framing error"); |
| 214 | + // } |
| 215 | + // else { |
| 216 | + printf("UART%d received: %c\n", num, (char)(data & 0xFF)); |
| 217 | + ctx[num].rx_cb(ctx[num].arg, (uint8_t)data); |
| 218 | + // } |
| 219 | + } |
| 220 | +} |
| 221 | + |
| 222 | +/** Overwrites the WEAK_DEFAULT isr_uart0 */ |
| 223 | +void isr_uart0(void) { |
| 224 | + isr_handler(0); |
| 225 | +} |
| 226 | + |
| 227 | +void isr_uart1(void) { |
| 228 | + isr_handler(1); |
84 | 229 | } |
85 | 230 |
|
86 | 231 | /** @} */ |
0 commit comments