ESPHome  2024.11.0
uart_component_rp2040.cpp
Go to the documentation of this file.
1 #ifdef USE_RP2040
4 #include "esphome/core/defines.h"
5 #include "esphome/core/helpers.h"
6 #include "esphome/core/log.h"
7 
8 #include <hardware/uart.h>
9 
10 #ifdef USE_LOGGER
12 #endif
13 
14 namespace esphome {
15 namespace uart {
16 
17 static const char *const TAG = "uart.arduino_rp2040";
18 
20  uint16_t config = 0;
21 
22  if (this->parity_ == UART_CONFIG_PARITY_NONE) {
23  config |= UART_PARITY_NONE;
24  } else if (this->parity_ == UART_CONFIG_PARITY_EVEN) {
25  config |= UART_PARITY_EVEN;
26  } else if (this->parity_ == UART_CONFIG_PARITY_ODD) {
27  config |= UART_PARITY_ODD;
28  }
29 
30  switch (this->data_bits_) {
31  case 5:
32  config |= SERIAL_DATA_5;
33  break;
34  case 6:
35  config |= SERIAL_DATA_6;
36  break;
37  case 7:
38  config |= SERIAL_DATA_7;
39  break;
40  case 8:
41  config |= SERIAL_DATA_8;
42  break;
43  }
44 
45  if (this->stop_bits_ == 1) {
46  config |= SERIAL_STOP_BIT_1;
47  } else {
48  config |= SERIAL_STOP_BIT_2;
49  }
50 
51  return config;
52 }
53 
55  ESP_LOGCONFIG(TAG, "Setting up UART bus...");
56 
57  uint16_t config = get_config();
58 
59  constexpr uint32_t valid_tx_uart_0 = __bitset({0, 12, 16, 28});
60  constexpr uint32_t valid_tx_uart_1 = __bitset({4, 8, 20, 24});
61 
62  constexpr uint32_t valid_rx_uart_0 = __bitset({1, 13, 17, 29});
63  constexpr uint32_t valid_rx_uart_1 = __bitset({5, 9, 21, 25});
64 
65  int8_t tx_hw = -1;
66  int8_t rx_hw = -1;
67 
68  if (this->tx_pin_ != nullptr) {
69  if (this->tx_pin_->is_inverted()) {
70  ESP_LOGD(TAG, "An inverted TX pin %u can only be used with SerialPIO", this->tx_pin_->get_pin());
71  } else {
72  if (((1 << this->tx_pin_->get_pin()) & valid_tx_uart_0) != 0) {
73  tx_hw = 0;
74  } else if (((1 << this->tx_pin_->get_pin()) & valid_tx_uart_1) != 0) {
75  tx_hw = 1;
76  } else {
77  ESP_LOGD(TAG, "TX pin %u can only be used with SerialPIO", this->tx_pin_->get_pin());
78  }
79  }
80  }
81 
82  if (this->rx_pin_ != nullptr) {
83  if (this->rx_pin_->is_inverted()) {
84  ESP_LOGD(TAG, "An inverted RX pin %u can only be used with SerialPIO", this->rx_pin_->get_pin());
85  } else {
86  if (((1 << this->rx_pin_->get_pin()) & valid_rx_uart_0) != 0) {
87  rx_hw = 0;
88  } else if (((1 << this->rx_pin_->get_pin()) & valid_rx_uart_1) != 0) {
89  rx_hw = 1;
90  } else {
91  ESP_LOGD(TAG, "RX pin %u can only be used with SerialPIO", this->rx_pin_->get_pin());
92  }
93  }
94  }
95 
96 #ifdef USE_LOGGER
97  if (tx_hw == rx_hw && logger::global_logger->get_uart() == tx_hw) {
98  ESP_LOGD(TAG, "Using SerialPIO as UART%d is taken by the logger", tx_hw);
99  tx_hw = -1;
100  rx_hw = -1;
101  }
102 #endif
103 
104  if (tx_hw == -1 || rx_hw == -1 || tx_hw != rx_hw) {
105  ESP_LOGV(TAG, "Using SerialPIO");
106  pin_size_t tx = this->tx_pin_ == nullptr ? SerialPIO::NOPIN : this->tx_pin_->get_pin();
107  pin_size_t rx = this->rx_pin_ == nullptr ? SerialPIO::NOPIN : this->rx_pin_->get_pin();
108  auto *serial = new SerialPIO(tx, rx, this->rx_buffer_size_); // NOLINT(cppcoreguidelines-owning-memory)
109  serial->begin(this->baud_rate_, config);
110  if (this->tx_pin_ != nullptr && this->tx_pin_->is_inverted())
111  gpio_set_outover(tx, GPIO_OVERRIDE_INVERT);
112  if (this->rx_pin_ != nullptr && this->rx_pin_->is_inverted())
113  gpio_set_inover(rx, GPIO_OVERRIDE_INVERT);
114  this->serial_ = serial;
115  } else {
116  ESP_LOGV(TAG, "Using Hardware Serial");
117  SerialUART *serial;
118  if (tx_hw == 0) {
119  serial = &Serial1;
120  } else {
121  serial = &Serial2;
122  }
123  serial->setTX(this->tx_pin_->get_pin());
124  serial->setRX(this->rx_pin_->get_pin());
125  serial->setFIFOSize(this->rx_buffer_size_);
126  serial->begin(this->baud_rate_, config);
127  this->serial_ = serial;
128  this->hw_serial_ = true;
129  }
130 }
131 
133  ESP_LOGCONFIG(TAG, "UART Bus:");
134  LOG_PIN(" TX Pin: ", tx_pin_);
135  LOG_PIN(" RX Pin: ", rx_pin_);
136  if (this->rx_pin_ != nullptr) {
137  ESP_LOGCONFIG(TAG, " RX Buffer Size: %u", this->rx_buffer_size_);
138  }
139  ESP_LOGCONFIG(TAG, " Baud Rate: %u baud", this->baud_rate_);
140  ESP_LOGCONFIG(TAG, " Data Bits: %u", this->data_bits_);
141  ESP_LOGCONFIG(TAG, " Parity: %s", LOG_STR_ARG(parity_to_str(this->parity_)));
142  ESP_LOGCONFIG(TAG, " Stop bits: %u", this->stop_bits_);
143  if (this->hw_serial_) {
144  ESP_LOGCONFIG(TAG, " Using hardware serial");
145  } else {
146  ESP_LOGCONFIG(TAG, " Using SerialPIO");
147  }
148 }
149 
150 void RP2040UartComponent::write_array(const uint8_t *data, size_t len) {
151  this->serial_->write(data, len);
152 #ifdef USE_UART_DEBUGGER
153  for (size_t i = 0; i < len; i++) {
154  this->debug_callback_.call(UART_DIRECTION_TX, data[i]);
155  }
156 #endif
157 }
158 bool RP2040UartComponent::peek_byte(uint8_t *data) {
159  if (!this->check_read_timeout_())
160  return false;
161  *data = this->serial_->peek();
162  return true;
163 }
164 bool RP2040UartComponent::read_array(uint8_t *data, size_t len) {
165  if (!this->check_read_timeout_(len))
166  return false;
167  this->serial_->readBytes(data, len);
168 #ifdef USE_UART_DEBUGGER
169  for (size_t i = 0; i < len; i++) {
170  this->debug_callback_.call(UART_DIRECTION_RX, data[i]);
171  }
172 #endif
173  return true;
174 }
175 int RP2040UartComponent::available() { return this->serial_->available(); }
177  ESP_LOGVV(TAG, " Flushing...");
178  this->serial_->flush();
179 }
180 
181 } // namespace uart
182 } // namespace esphome
183 
184 #endif // USE_RP2040
bool read_array(uint8_t *data, size_t len) override
bool peek_byte(uint8_t *data) override
virtual uint8_t get_pin() const =0
Logger * global_logger
Definition: logger.cpp:198
const char *const TAG
Definition: spi.cpp:8
void write_array(const uint8_t *data, size_t len) override
std::string size_t len
Definition: helpers.h:293
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
bool check_read_timeout_(size_t len=1)
CallbackManager< void(UARTDirection, uint8_t)> debug_callback_
const LogString * parity_to_str(UARTParityOptions parity)
Definition: uart.cpp:33
virtual bool is_inverted() const =0