1 /*
2 * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 // The LL layer for UART register operations.
8 // Note that most of the register operations in this layer are non-atomic operations.
9
10
11 #pragma once
12
13 #include <stdlib.h>
14 #include "hal/misc.h"
15 #include "hal/uart_types.h"
16 #include "soc/uart_reg.h"
17 #include "soc/uart_struct.h"
18 #include "soc/system_reg.h"
19 #include "soc/dport_reg.h"
20 #include "esp_attr.h"
21
22 #ifdef __cplusplus
23 extern "C" {
24 #endif
25
26 // The default fifo depth
27 #define UART_LL_FIFO_DEF_LEN (SOC_UART_FIFO_LEN)
28 // Get UART hardware instance with giving uart num
29 #define UART_LL_GET_HW(num) (((num) == 0) ? (&UART0) : (&UART1))
30
31 #define UART_LL_MIN_WAKEUP_THRESH (3)
32 #define UART_LL_INTR_MASK (0x7ffff) //All interrupt mask
33
34 // Define UART interrupts
35 typedef enum {
36 UART_INTR_RXFIFO_FULL = (0x1<<0),
37 UART_INTR_TXFIFO_EMPTY = (0x1<<1),
38 UART_INTR_PARITY_ERR = (0x1<<2),
39 UART_INTR_FRAM_ERR = (0x1<<3),
40 UART_INTR_RXFIFO_OVF = (0x1<<4),
41 UART_INTR_DSR_CHG = (0x1<<5),
42 UART_INTR_CTS_CHG = (0x1<<6),
43 UART_INTR_BRK_DET = (0x1<<7),
44 UART_INTR_RXFIFO_TOUT = (0x1<<8),
45 UART_INTR_SW_XON = (0x1<<9),
46 UART_INTR_SW_XOFF = (0x1<<10),
47 UART_INTR_GLITCH_DET = (0x1<<11),
48 UART_INTR_TX_BRK_DONE = (0x1<<12),
49 UART_INTR_TX_BRK_IDLE = (0x1<<13),
50 UART_INTR_TX_DONE = (0x1<<14),
51 UART_INTR_RS485_PARITY_ERR = (0x1<<15),
52 UART_INTR_RS485_FRM_ERR = (0x1<<16),
53 UART_INTR_RS485_CLASH = (0x1<<17),
54 UART_INTR_CMD_CHAR_DET = (0x1<<18),
55 UART_INTR_WAKEUP = (0x1 << 19),
56 } uart_intr_t;
57
58 /**
59 * @brief Check if UART is enabled or disabled.
60 *
61 * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
62 *
63 * @return true: enabled; false: disabled
64 */
uart_ll_is_enabled(uint32_t uart_num)65 FORCE_INLINE_ATTR bool uart_ll_is_enabled(uint32_t uart_num)
66 {
67 uint32_t uart_rst_bit = ((uart_num == 0) ? DPORT_UART_RST :
68 (uart_num == 1) ? DPORT_UART1_RST : 0);
69 uint32_t uart_en_bit = ((uart_num == 0) ? DPORT_UART_CLK_EN :
70 (uart_num == 1) ? DPORT_UART1_CLK_EN : 0);
71 return DPORT_REG_GET_BIT(DPORT_PERIP_RST_EN_REG, uart_rst_bit) == 0 &&
72 DPORT_REG_GET_BIT(DPORT_PERIP_CLK_EN_REG, uart_en_bit) != 0;
73 }
74
75 /**
76 * @brief Set the UART source clock.
77 *
78 * @param hw Beginning address of the peripheral registers.
79 * @param source_clk The UART source clock. The source clock can be APB clock or REF_TICK.
80 * If the source clock is REF_TICK, the UART can still work when the APB changes.
81 *
82 * @return None.
83 */
uart_ll_set_sclk(uart_dev_t * hw,uart_sclk_t source_clk)84 FORCE_INLINE_ATTR void uart_ll_set_sclk(uart_dev_t *hw, uart_sclk_t source_clk)
85 {
86 hw->conf0.tick_ref_always_on = (source_clk == UART_SCLK_APB) ? 1 : 0;
87 }
88
89 /**
90 * @brief Get the UART source clock type.
91 *
92 * @param hw Beginning address of the peripheral registers.
93 * @param source_clk The pointer to accept the UART source clock type.
94 *
95 * @return None.
96 */
uart_ll_get_sclk(uart_dev_t * hw,uart_sclk_t * source_clk)97 FORCE_INLINE_ATTR void uart_ll_get_sclk(uart_dev_t *hw, uart_sclk_t* source_clk)
98 {
99 *source_clk = hw->conf0.tick_ref_always_on ? UART_SCLK_APB : UART_SCLK_REF_TICK;
100 }
101
102 /**
103 * @brief Configure the baud-rate.
104 *
105 * @param hw Beginning address of the peripheral registers.
106 * @param baud The baud rate to be set. When the source clock is APB, the max baud rate is `UART_LL_BITRATE_MAX`
107 * @param sclk_freq Frequency of the clock source of UART, in Hz.
108
109 * @return None
110 */
uart_ll_set_baudrate(uart_dev_t * hw,uint32_t baud,uint32_t sclk_freq)111 FORCE_INLINE_ATTR void uart_ll_set_baudrate(uart_dev_t *hw, uint32_t baud, uint32_t sclk_freq)
112 {
113 uint32_t clk_div;
114
115 clk_div = ((sclk_freq) << 4) / baud;
116 // The baud rate configuration register is divided into
117 // an integer part and a fractional part.
118 hw->clk_div.div_int = clk_div >> 4;
119 hw->clk_div.div_frag = clk_div & 0xf;
120 }
121
122 /**
123 * @brief Get the current baud-rate.
124 *
125 * @param hw Beginning address of the peripheral registers.
126 * @param sclk_freq Frequency of the clock source of UART, in Hz.
127 *
128 * @return The current baudrate
129 */
uart_ll_get_baudrate(uart_dev_t * hw,uint32_t sclk_freq)130 FORCE_INLINE_ATTR uint32_t uart_ll_get_baudrate(uart_dev_t *hw, uint32_t sclk_freq)
131 {
132 typeof(hw->clk_div) div_reg;
133 div_reg.val = hw->clk_div.val;
134 return ((sclk_freq << 4)) / ((div_reg.div_int << 4) | div_reg.div_frag);
135 }
136
137 /**
138 * @brief Enable the UART interrupt based on the given mask.
139 *
140 * @param hw Beginning address of the peripheral registers.
141 * @param mask The bitmap of the interrupts need to be enabled.
142 *
143 * @return None
144 */
uart_ll_ena_intr_mask(uart_dev_t * hw,uint32_t mask)145 FORCE_INLINE_ATTR void uart_ll_ena_intr_mask(uart_dev_t *hw, uint32_t mask)
146 {
147 hw->int_ena.val |= mask;
148 }
149
150 /**
151 * @brief Disable the UART interrupt based on the given mask.
152 *
153 * @param hw Beginning address of the peripheral registers.
154 * @param mask The bitmap of the interrupts need to be disabled.
155 *
156 * @return None
157 */
uart_ll_disable_intr_mask(uart_dev_t * hw,uint32_t mask)158 FORCE_INLINE_ATTR void uart_ll_disable_intr_mask(uart_dev_t *hw, uint32_t mask)
159 {
160 hw->int_ena.val &= (~mask);
161 }
162
163 /**
164 * @brief Get the UART raw interrupt status.
165 *
166 * @param hw Beginning address of the peripheral registers.
167 *
168 * @return The UART interrupt status.
169 */
uart_ll_get_intraw_mask(uart_dev_t * hw)170 static inline uint32_t uart_ll_get_intraw_mask(uart_dev_t *hw)
171 {
172 return hw->int_raw.val;
173 }
174
175 /**
176 * @brief Get the UART interrupt status.
177 *
178 * @param hw Beginning address of the peripheral registers.
179 *
180 * @return The UART interrupt status.
181 */
uart_ll_get_intsts_mask(uart_dev_t * hw)182 FORCE_INLINE_ATTR uint32_t uart_ll_get_intsts_mask(uart_dev_t *hw)
183 {
184 return hw->int_st.val;
185 }
186
187 /**
188 * @brief Clear the UART interrupt status based on the given mask.
189 *
190 * @param hw Beginning address of the peripheral registers.
191 * @param mask The bitmap of the interrupts need to be cleared.
192 *
193 * @return None
194 */
uart_ll_clr_intsts_mask(uart_dev_t * hw,uint32_t mask)195 FORCE_INLINE_ATTR void uart_ll_clr_intsts_mask(uart_dev_t *hw, uint32_t mask)
196 {
197 hw->int_clr.val = mask;
198 }
199
200 /**
201 * @brief Get status of enabled interrupt.
202 *
203 * @param hw Beginning address of the peripheral registers.
204 *
205 * @return interrupt enable value
206 */
uart_ll_get_intr_ena_status(uart_dev_t * hw)207 FORCE_INLINE_ATTR uint32_t uart_ll_get_intr_ena_status(uart_dev_t *hw)
208 {
209 return hw->int_ena.val;
210 }
211
212 /**
213 * @brief Read the UART rxfifo.
214 *
215 * @param hw Beginning address of the peripheral registers.
216 * @param buf The data buffer. The buffer size should be large than 128 byts.
217 * @param rd_len The data length needs to be read.
218 *
219 * @return None.
220 */
uart_ll_read_rxfifo(uart_dev_t * hw,uint8_t * buf,uint32_t rd_len)221 FORCE_INLINE_ATTR void uart_ll_read_rxfifo(uart_dev_t *hw, uint8_t *buf, uint32_t rd_len)
222 {
223 //Get the UART fifo addr, ESP32-S2 have 2 UART
224 uint32_t fifo_addr = (hw == &UART0) ? UART_FIFO_AHB_REG(0) : UART_FIFO_AHB_REG(1);
225 for(uint32_t i = 0; i < rd_len; i++) {
226 buf[i] = READ_PERI_REG(fifo_addr);
227 }
228 }
229
230 /**
231 * @brief Write byte to the UART txfifo.
232 *
233 * @param hw Beginning address of the peripheral registers.
234 * @param buf The data buffer.
235 * @param wr_len The data length needs to be writen.
236 *
237 * @return None
238 */
uart_ll_write_txfifo(uart_dev_t * hw,const uint8_t * buf,uint32_t wr_len)239 FORCE_INLINE_ATTR void uart_ll_write_txfifo(uart_dev_t *hw, const uint8_t *buf, uint32_t wr_len)
240 {
241 //Get the UART fifo addr, ESP32-S2 have 2 UART
242 uint32_t fifo_addr = (hw == &UART0) ? UART_FIFO_AHB_REG(0) : UART_FIFO_AHB_REG(1);
243 for(uint32_t i = 0; i < wr_len; i++) {
244 WRITE_PERI_REG(fifo_addr, buf[i]);
245 }
246 }
247
248 /**
249 * @brief Reset the UART hw rxfifo.
250 *
251 * @param hw Beginning address of the peripheral registers.
252 *
253 * @return None
254 */
uart_ll_rxfifo_rst(uart_dev_t * hw)255 FORCE_INLINE_ATTR void uart_ll_rxfifo_rst(uart_dev_t *hw)
256 {
257 hw->conf0.rxfifo_rst = 1;
258 hw->conf0.rxfifo_rst = 0;
259 }
260
261 /**
262 * @brief Reset the UART hw txfifo.
263 *
264 * @param hw Beginning address of the peripheral registers.
265 *
266 * @return None
267 */
uart_ll_txfifo_rst(uart_dev_t * hw)268 FORCE_INLINE_ATTR void uart_ll_txfifo_rst(uart_dev_t *hw)
269 {
270 hw->conf0.txfifo_rst = 1;
271 hw->conf0.txfifo_rst = 0;
272 }
273
274 /**
275 * @brief Get the length of readable data in UART rxfifo.
276 *
277 * @param hw Beginning address of the peripheral registers.
278 *
279 * @return The readable data length in rxfifo.
280 */
uart_ll_get_rxfifo_len(uart_dev_t * hw)281 FORCE_INLINE_ATTR uint32_t uart_ll_get_rxfifo_len(uart_dev_t *hw)
282 {
283 return hw->status.rxfifo_cnt;
284 }
285
286 /**
287 * @brief Get the writable data length of UART txfifo.
288 *
289 * @param hw Beginning address of the peripheral registers.
290 *
291 * @return The data length of txfifo can be written.
292 */
uart_ll_get_txfifo_len(uart_dev_t * hw)293 FORCE_INLINE_ATTR uint32_t uart_ll_get_txfifo_len(uart_dev_t *hw)
294 {
295 return UART_LL_FIFO_DEF_LEN - hw->status.txfifo_cnt;
296 }
297
298 /**
299 * @brief Configure the UART stop bit.
300 *
301 * @param hw Beginning address of the peripheral registers.
302 * @param stop_bit The stop bit number to be set.
303 *
304 * @return None.
305 */
uart_ll_set_stop_bits(uart_dev_t * hw,uart_stop_bits_t stop_bit)306 FORCE_INLINE_ATTR void uart_ll_set_stop_bits(uart_dev_t *hw, uart_stop_bits_t stop_bit)
307 {
308 hw->conf0.stop_bit_num = stop_bit;
309 }
310
311 /**
312 * @brief Get the configuration of the UART stop bit.
313 *
314 * @param hw Beginning address of the peripheral registers.
315 * @param stop_bit The pointer to accept the stop bit configuration
316 *
317 * @return None.
318 */
uart_ll_get_stop_bits(uart_dev_t * hw,uart_stop_bits_t * stop_bit)319 FORCE_INLINE_ATTR void uart_ll_get_stop_bits(uart_dev_t *hw, uart_stop_bits_t *stop_bit)
320 {
321 *stop_bit = (uart_stop_bits_t)hw->conf0.stop_bit_num;
322 }
323
324 /**
325 * @brief Configure the UART parity check mode.
326 *
327 * @param hw Beginning address of the peripheral registers.
328 * @param parity_mode The parity check mode to be set.
329 *
330 * @return None.
331 */
uart_ll_set_parity(uart_dev_t * hw,uart_parity_t parity_mode)332 FORCE_INLINE_ATTR void uart_ll_set_parity(uart_dev_t *hw, uart_parity_t parity_mode)
333 {
334 if(parity_mode != UART_PARITY_DISABLE) {
335 hw->conf0.parity = parity_mode & 0x1;
336 }
337 hw->conf0.parity_en = (parity_mode >> 1) & 0x1;
338 }
339
340 /**
341 * @brief Get the UART parity check mode configuration.
342 *
343 * @param hw Beginning address of the peripheral registers.
344 * @param parity_mode The pointer to accept the parity check mode configuration.
345 *
346 * @return None.
347 */
uart_ll_get_parity(uart_dev_t * hw,uart_parity_t * parity_mode)348 FORCE_INLINE_ATTR void uart_ll_get_parity(uart_dev_t *hw, uart_parity_t *parity_mode)
349 {
350 if(hw->conf0.parity_en) {
351 *parity_mode = (uart_parity_t)(0x2 | hw->conf0.parity);
352 } else {
353 *parity_mode = UART_PARITY_DISABLE;
354 }
355 }
356
357 /**
358 * @brief Set the UART rxfifo full threshold value. When the data in rxfifo is more than the threshold value,
359 * it will produce rxfifo_full_int_raw interrupt.
360 *
361 * @param hw Beginning address of the peripheral registers.
362 * @param full_thrhd The full threshold value of the rxfifo. `full_thrhd` should be less than `UART_LL_FIFO_DEF_LEN`.
363 *
364 * @return None.
365 */
uart_ll_set_rxfifo_full_thr(uart_dev_t * hw,uint16_t full_thrhd)366 FORCE_INLINE_ATTR void uart_ll_set_rxfifo_full_thr(uart_dev_t *hw, uint16_t full_thrhd)
367 {
368 hw->conf1.rxfifo_full_thrhd = full_thrhd;
369 }
370
371 /**
372 * @brief Set the txfifo empty threshold. when the data length in txfifo is less than threshold value,
373 * it will produce txfifo_empty_int_raw interrupt.
374 *
375 * @param hw Beginning address of the peripheral registers.
376 * @param empty_thrhd The empty threshold of txfifo.
377 *
378 * @return None.
379 */
uart_ll_set_txfifo_empty_thr(uart_dev_t * hw,uint16_t empty_thrhd)380 FORCE_INLINE_ATTR void uart_ll_set_txfifo_empty_thr(uart_dev_t *hw, uint16_t empty_thrhd)
381 {
382 hw->conf1.txfifo_empty_thrhd = empty_thrhd;
383 }
384
385 /**
386 * @brief Set the UART rx-idle threshold value. when receiver takes more time than rx_idle_thrhd to receive a byte data,
387 * it will produce frame end signal for uhci to stop receiving data.
388 *
389 * @param hw Beginning address of the peripheral registers.
390 * @param rx_idle_thr The rx-idle threshold to be set.
391 *
392 * @return None.
393 */
uart_ll_set_rx_idle_thr(uart_dev_t * hw,uint32_t rx_idle_thr)394 FORCE_INLINE_ATTR void uart_ll_set_rx_idle_thr(uart_dev_t *hw, uint32_t rx_idle_thr)
395 {
396 hw->idle_conf.rx_idle_thrhd = rx_idle_thr;
397 }
398
399 /**
400 * @brief Configure the duration time between transfers.
401 *
402 * @param hw Beginning address of the peripheral registers.
403 * @param idle_num the duration time between transfers.
404 *
405 * @return None.
406 */
uart_ll_set_tx_idle_num(uart_dev_t * hw,uint32_t idle_num)407 FORCE_INLINE_ATTR void uart_ll_set_tx_idle_num(uart_dev_t *hw, uint32_t idle_num)
408 {
409 hw->idle_conf.tx_idle_num = idle_num;
410 }
411
412 /**
413 * @brief Configure the transmiter to send break chars.
414 *
415 * @param hw Beginning address of the peripheral registers.
416 * @param break_num The number of the break chars need to be send.
417 *
418 * @return None.
419 */
uart_ll_tx_break(uart_dev_t * hw,uint32_t break_num)420 FORCE_INLINE_ATTR void uart_ll_tx_break(uart_dev_t *hw, uint32_t break_num)
421 {
422 if(break_num > 0) {
423 HAL_FORCE_MODIFY_U32_REG_FIELD(hw->idle_conf, tx_brk_num, break_num);
424 hw->conf0.txd_brk = 1;
425 } else {
426 hw->conf0.txd_brk = 0;
427 }
428 }
429
430 /**
431 * @brief Configure the UART hardware flow control.
432 *
433 * @param hw Beginning address of the peripheral registers.
434 * @param flow_ctrl The hw flow control configuration.
435 * @param rx_thrs The rx flow control signal will be active if the data length in rxfifo is more than this value.
436 *
437 * @return None.
438 */
uart_ll_set_hw_flow_ctrl(uart_dev_t * hw,uart_hw_flowcontrol_t flow_ctrl,uint32_t rx_thrs)439 FORCE_INLINE_ATTR void uart_ll_set_hw_flow_ctrl(uart_dev_t *hw, uart_hw_flowcontrol_t flow_ctrl, uint32_t rx_thrs)
440 {
441 //only when UART_HW_FLOWCTRL_RTS is set , will the rx_thresh value be set.
442 if(flow_ctrl & UART_HW_FLOWCTRL_RTS) {
443 hw->mem_conf.rx_flow_thrhd = rx_thrs;
444 hw->conf1.rx_flow_en = 1;
445 } else {
446 hw->conf1.rx_flow_en = 0;
447 }
448 if(flow_ctrl & UART_HW_FLOWCTRL_CTS) {
449 hw->conf0.tx_flow_en = 1;
450 } else {
451 hw->conf0.tx_flow_en = 0;
452 }
453 }
454
455 /**
456 * @brief Configure the hardware flow control.
457 *
458 * @param hw Beginning address of the peripheral registers.
459 * @param flow_ctrl A pointer to accept the hw flow control configuration.
460 *
461 * @return None.
462 */
uart_ll_get_hw_flow_ctrl(uart_dev_t * hw,uart_hw_flowcontrol_t * flow_ctrl)463 FORCE_INLINE_ATTR void uart_ll_get_hw_flow_ctrl(uart_dev_t *hw, uart_hw_flowcontrol_t *flow_ctrl)
464 {
465 *flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
466 if(hw->conf1.rx_flow_en) {
467 *flow_ctrl = (uart_hw_flowcontrol_t)((unsigned int)(*flow_ctrl) | (unsigned int)UART_HW_FLOWCTRL_RTS);
468 }
469 if(hw->conf0.tx_flow_en) {
470 *flow_ctrl = (uart_hw_flowcontrol_t)((unsigned int)(*flow_ctrl) | (unsigned int)UART_HW_FLOWCTRL_CTS);
471 }
472 }
473
474 /**
475 * @brief Configure the software flow control.
476 *
477 * @param hw Beginning address of the peripheral registers.
478 * @param flow_ctrl The UART sofware flow control settings.
479 * @param sw_flow_ctrl_en Set true to enable software flow control, otherwise set it false.
480 *
481 * @return None.
482 */
uart_ll_set_sw_flow_ctrl(uart_dev_t * hw,uart_sw_flowctrl_t * flow_ctrl,bool sw_flow_ctrl_en)483 FORCE_INLINE_ATTR void uart_ll_set_sw_flow_ctrl(uart_dev_t *hw, uart_sw_flowctrl_t *flow_ctrl, bool sw_flow_ctrl_en)
484 {
485 if(sw_flow_ctrl_en) {
486 hw->flow_conf.xonoff_del = 1;
487 hw->flow_conf.sw_flow_con_en = 1;
488 hw->swfc_conf1.xon_threshold = flow_ctrl->xon_thrd;
489 hw->swfc_conf0.xoff_threshold = flow_ctrl->xoff_thrd;
490 HAL_FORCE_MODIFY_U32_REG_FIELD(hw->swfc_conf1, xon_char, flow_ctrl->xon_char);
491 HAL_FORCE_MODIFY_U32_REG_FIELD(hw->swfc_conf0, xoff_char, flow_ctrl->xoff_char);
492 } else {
493 hw->flow_conf.sw_flow_con_en = 0;
494 hw->flow_conf.xonoff_del = 0;
495 }
496 }
497
498 /**
499 * @brief Configure the AT cmd char. When the receiver receives a continuous AT cmd char, it will produce at_cmd_char_det interrupt.
500 *
501 * @param hw Beginning address of the peripheral registers.
502 * @param cmd_char The AT cmd char configuration.The configuration member is:
503 * - cmd_char The AT cmd character
504 * - char_num The number of received AT cmd char must be equal to or greater than this value
505 * - gap_tout The interval between each AT cmd char, when the duration is less than this value, it will not take this data as AT cmd char
506 * - pre_idle The idle time before the first AT cmd char, when the duration is less than this value, it will not take the previous data as the last AT cmd char
507 * - post_idle The idle time after the last AT cmd char, when the duration is less than this value, it will not take this data as the first AT cmd char
508 *
509 * @return None.
510 */
uart_ll_set_at_cmd_char(uart_dev_t * hw,uart_at_cmd_t * cmd_char)511 FORCE_INLINE_ATTR void uart_ll_set_at_cmd_char(uart_dev_t *hw, uart_at_cmd_t *cmd_char)
512 {
513 HAL_FORCE_MODIFY_U32_REG_FIELD(hw->at_cmd_char, data, cmd_char->cmd_char);
514 HAL_FORCE_MODIFY_U32_REG_FIELD(hw->at_cmd_char, char_num, cmd_char->char_num);
515 HAL_FORCE_MODIFY_U32_REG_FIELD(hw->at_cmd_postcnt, post_idle_num, cmd_char->post_idle);
516 HAL_FORCE_MODIFY_U32_REG_FIELD(hw->at_cmd_precnt, pre_idle_num, cmd_char->pre_idle);
517 HAL_FORCE_MODIFY_U32_REG_FIELD(hw->at_cmd_gaptout, rx_gap_tout, cmd_char->gap_tout);
518 }
519
520 /**
521 * @brief Set the UART data bit mode.
522 *
523 * @param hw Beginning address of the peripheral registers.
524 * @param data_bit The data bit mode to be set.
525 *
526 * @return None.
527 */
uart_ll_set_data_bit_num(uart_dev_t * hw,uart_word_length_t data_bit)528 FORCE_INLINE_ATTR void uart_ll_set_data_bit_num(uart_dev_t *hw, uart_word_length_t data_bit)
529 {
530 hw->conf0.bit_num = data_bit;
531 }
532
533 /**
534 * @brief Set the rts active level.
535 *
536 * @param hw Beginning address of the peripheral registers.
537 * @param level The rts active level, 0 or 1.
538 *
539 * @return None.
540 */
uart_ll_set_rts_active_level(uart_dev_t * hw,int level)541 FORCE_INLINE_ATTR void uart_ll_set_rts_active_level(uart_dev_t *hw, int level)
542 {
543 hw->conf0.sw_rts = level & 0x1;
544 }
545
546 /**
547 * @brief Set the dtr active level.
548 *
549 * @param hw Beginning address of the peripheral registers.
550 * @param level The dtr active level, 0 or 1.
551 *
552 * @return None.
553 */
uart_ll_set_dtr_active_level(uart_dev_t * hw,int level)554 FORCE_INLINE_ATTR void uart_ll_set_dtr_active_level(uart_dev_t *hw, int level)
555 {
556 hw->conf0.sw_dtr = level & 0x1;
557 }
558
559 /**
560 * @brief Set the UART wakeup threshold.
561 *
562 * @param hw Beginning address of the peripheral registers.
563 * @param wakeup_thrd The wakeup threshold value to be set. When the input rx edge changes more than this value,
564 * the UART will active from light sleeping mode.
565 *
566 * @return None.
567 */
uart_ll_set_wakeup_thrd(uart_dev_t * hw,uint32_t wakeup_thrd)568 FORCE_INLINE_ATTR void uart_ll_set_wakeup_thrd(uart_dev_t *hw, uint32_t wakeup_thrd)
569 {
570 // System would wakeup when the number of positive edges of RxD signal is larger than or equal to (UART_ACTIVE_THRESHOLD+3)
571 hw->sleep_conf.active_threshold = wakeup_thrd - UART_LL_MIN_WAKEUP_THRESH;
572 }
573
574 /**
575 * @brief Configure the UART work in normal mode.
576 *
577 * @param hw Beginning address of the peripheral registers.
578 *
579 * @return None.
580 */
uart_ll_set_mode_normal(uart_dev_t * hw)581 FORCE_INLINE_ATTR void uart_ll_set_mode_normal(uart_dev_t *hw)
582 {
583 hw->rs485_conf.en = 0;
584 hw->rs485_conf.tx_rx_en = 0;
585 hw->rs485_conf.rx_busy_tx_en = 0;
586 hw->conf0.irda_en = 0;
587 }
588
589 /**
590 * @brief Configure the UART work in rs485_app_ctrl mode.
591 *
592 * @param hw Beginning address of the peripheral registers.
593 *
594 * @return None.
595 */
uart_ll_set_mode_rs485_app_ctrl(uart_dev_t * hw)596 FORCE_INLINE_ATTR void uart_ll_set_mode_rs485_app_ctrl(uart_dev_t *hw)
597 {
598 // Application software control, remove echo
599 hw->rs485_conf.rx_busy_tx_en = 1;
600 hw->conf0.irda_en = 0;
601 hw->conf0.sw_rts = 0;
602 hw->conf0.irda_en = 0;
603 hw->rs485_conf.en = 1;
604 }
605
606 /**
607 * @brief Configure the UART work in rs485_half_duplex mode.
608 *
609 * @param hw Beginning address of the peripheral registers.
610 *
611 * @return None.
612 */
uart_ll_set_mode_rs485_half_duplex(uart_dev_t * hw)613 FORCE_INLINE_ATTR void uart_ll_set_mode_rs485_half_duplex(uart_dev_t *hw)
614 {
615 // Enable receiver, sw_rts = 1 generates low level on RTS pin
616 hw->conf0.sw_rts = 1;
617 // Must be set to 0 to automatically remove echo
618 hw->rs485_conf.tx_rx_en = 0;
619 // This is to void collision
620 hw->rs485_conf.rx_busy_tx_en = 1;
621 hw->conf0.irda_en = 0;
622 hw->rs485_conf.en = 1;
623 }
624
625 /**
626 * @brief Get the rs485_half_duplex mode.
627 *
628 * @param hw Beginning address of the peripheral registers.
629 *
630 * @return True if RS485 half duplex mode enabled.
631 */
uart_ll_is_mode_rs485_half_duplex(uart_dev_t * hw)632 FORCE_INLINE_ATTR bool uart_ll_is_mode_rs485_half_duplex(uart_dev_t *hw)
633 {
634 return (!hw->rs485_conf.rx_busy_tx_en && hw->rs485_conf.en);
635 }
636
637 /**
638 * @brief Configure the UART work in collision_detect mode.
639 *
640 * @param hw Beginning address of the peripheral registers.
641 *
642 * @return None.
643 */
uart_ll_set_mode_collision_detect(uart_dev_t * hw)644 FORCE_INLINE_ATTR void uart_ll_set_mode_collision_detect(uart_dev_t *hw)
645 {
646 hw->conf0.irda_en = 0;
647 // Transmitters output signal loop back to the receivers input signal
648 hw->rs485_conf.tx_rx_en = 1 ;
649 // Transmitter should send data when the receiver is busy
650 hw->rs485_conf.rx_busy_tx_en = 1;
651 hw->conf0.sw_rts = 0;
652 hw->rs485_conf.en = 1;
653 }
654
655 /**
656 * @brief Configure the UART work in irda mode.
657 *
658 * @param hw Beginning address of the peripheral registers.
659 *
660 * @return None.
661 */
uart_ll_set_mode_irda(uart_dev_t * hw)662 FORCE_INLINE_ATTR void uart_ll_set_mode_irda(uart_dev_t *hw)
663 {
664 hw->rs485_conf.en = 0;
665 hw->rs485_conf.tx_rx_en = 0;
666 hw->rs485_conf.rx_busy_tx_en = 0;
667 hw->conf0.sw_rts = 0;
668 hw->conf0.irda_en = 1;
669 }
670
671 /**
672 * @brief Set uart mode.
673 *
674 * @param hw Beginning address of the peripheral registers.
675 * @param mode The UART mode to be set.
676 *
677 * @return None.
678 */
uart_ll_set_mode(uart_dev_t * hw,uart_mode_t mode)679 FORCE_INLINE_ATTR void uart_ll_set_mode(uart_dev_t *hw, uart_mode_t mode)
680 {
681 switch (mode) {
682 default:
683 case UART_MODE_UART:
684 uart_ll_set_mode_normal(hw);
685 break;
686 case UART_MODE_RS485_COLLISION_DETECT:
687 uart_ll_set_mode_collision_detect(hw);
688 break;
689 case UART_MODE_RS485_APP_CTRL:
690 uart_ll_set_mode_rs485_app_ctrl(hw);
691 break;
692 case UART_MODE_RS485_HALF_DUPLEX:
693 uart_ll_set_mode_rs485_half_duplex(hw);
694 break;
695 case UART_MODE_IRDA:
696 uart_ll_set_mode_irda(hw);
697 break;
698 }
699 }
700
701 /**
702 * @brief Get the UART AT cmd char configuration.
703 *
704 * @param hw Beginning address of the peripheral registers.
705 * @param cmd_char The Pointer to accept value of UART AT cmd char.
706 * @param char_num Pointer to accept the repeat number of UART AT cmd char.
707 *
708 * @return None.
709 */
uart_ll_get_at_cmd_char(uart_dev_t * hw,uint8_t * cmd_char,uint8_t * char_num)710 FORCE_INLINE_ATTR void uart_ll_get_at_cmd_char(uart_dev_t *hw, uint8_t *cmd_char, uint8_t *char_num)
711 {
712 *cmd_char = HAL_FORCE_READ_U32_REG_FIELD(hw->at_cmd_char, data);
713 *char_num = HAL_FORCE_READ_U32_REG_FIELD(hw->at_cmd_char, char_num);
714 }
715
716 /**
717 * @brief Get the UART wakeup threshold value.
718 *
719 * @param hw Beginning address of the peripheral registers.
720 *
721 * @return The UART wakeup threshold value.
722 */
uart_ll_get_wakeup_thrd(uart_dev_t * hw)723 FORCE_INLINE_ATTR uint32_t uart_ll_get_wakeup_thrd(uart_dev_t *hw)
724 {
725 return hw->sleep_conf.active_threshold + UART_LL_MIN_WAKEUP_THRESH;
726 }
727
728 /**
729 * @brief Get the UART data bit configuration.
730 *
731 * @param hw Beginning address of the peripheral registers.
732 * @param data_bit The pointer to accept the UART data bit configuration.
733 *
734 * @return The bit mode.
735 */
uart_ll_get_data_bit_num(uart_dev_t * hw,uart_word_length_t * data_bit)736 FORCE_INLINE_ATTR void uart_ll_get_data_bit_num(uart_dev_t *hw, uart_word_length_t *data_bit)
737 {
738 *data_bit = (uart_word_length_t)hw->conf0.bit_num;
739 }
740
741 /**
742 * @brief Check if the UART sending state machine is in the IDLE state.
743 *
744 * @param hw Beginning address of the peripheral registers.
745 *
746 * @return True if the state machine is in the IDLE state, otherwise false is returned.
747 */
uart_ll_is_tx_idle(uart_dev_t * hw)748 FORCE_INLINE_ATTR bool uart_ll_is_tx_idle(uart_dev_t *hw)
749 {
750 return ((hw->status.txfifo_cnt == 0) && (hw->fsm_status.st_utx_out == 0));
751 }
752
753 /**
754 * @brief Check if the UART rts flow control is enabled.
755 *
756 * @param hw Beginning address of the peripheral registers.
757 *
758 * @return True if hw rts flow control is enabled, otherwise false is returned.
759 */
uart_ll_is_hw_rts_en(uart_dev_t * hw)760 FORCE_INLINE_ATTR bool uart_ll_is_hw_rts_en(uart_dev_t *hw)
761 {
762 return hw->conf1.rx_flow_en;
763 }
764
765 /**
766 * @brief Check if the UART cts flow control is enabled.
767 *
768 * @param hw Beginning address of the peripheral registers.
769 *
770 * @return True if hw cts flow control is enabled, otherwise false is returned.
771 */
uart_ll_is_hw_cts_en(uart_dev_t * hw)772 FORCE_INLINE_ATTR bool uart_ll_is_hw_cts_en(uart_dev_t *hw)
773 {
774 return hw->conf0.tx_flow_en;
775 }
776
777 /**
778 * @brief Configure TX signal loop back to RX module, just for the testing purposes
779 *
780 * @param hw Beginning address of the peripheral registers.
781 * @param loop_back_en Set ture to enable the loop back function, else set it false.
782 *
783 * @return None
784 */
uart_ll_set_loop_back(uart_dev_t * hw,bool loop_back_en)785 FORCE_INLINE_ATTR void uart_ll_set_loop_back(uart_dev_t *hw, bool loop_back_en)
786 {
787 hw->conf0.loopback = loop_back_en;
788 }
789
790 /**
791 * @brief Inverse the UART signal with the given mask.
792 *
793 * @param hw Beginning address of the peripheral registers.
794 * @param inv_mask The UART signal bitmap needs to be inversed.
795 * Use the ORred mask of `uart_signal_inv_t`;
796 *
797 * @return None.
798 */
uart_ll_inverse_signal(uart_dev_t * hw,uint32_t inv_mask)799 FORCE_INLINE_ATTR void uart_ll_inverse_signal(uart_dev_t *hw, uint32_t inv_mask)
800 {
801 typeof(hw->conf0) conf0_reg;
802 conf0_reg.val = hw->conf0.val;
803 conf0_reg.irda_tx_inv = (inv_mask & UART_SIGNAL_IRDA_TX_INV) ? 1 : 0;
804 conf0_reg.irda_rx_inv = (inv_mask & UART_SIGNAL_IRDA_RX_INV) ? 1 : 0;
805 conf0_reg.rxd_inv = (inv_mask & UART_SIGNAL_RXD_INV) ? 1 : 0;
806 conf0_reg.cts_inv = (inv_mask & UART_SIGNAL_CTS_INV) ? 1 : 0;
807 conf0_reg.dsr_inv = (inv_mask & UART_SIGNAL_DSR_INV) ? 1 : 0;
808 conf0_reg.txd_inv = (inv_mask & UART_SIGNAL_TXD_INV) ? 1 : 0;
809 conf0_reg.rts_inv = (inv_mask & UART_SIGNAL_RTS_INV) ? 1 : 0;
810 conf0_reg.dtr_inv = (inv_mask & UART_SIGNAL_DTR_INV) ? 1 : 0;
811 hw->conf0.val = conf0_reg.val;
812 }
813
814 /**
815 * @brief Configure the timeout value for receiver receiving a byte, and enable rx timeout function.
816 *
817 * @param hw Beginning address of the peripheral registers.
818 * @param tout_thrd The timeout value as UART bit time. The rx timeout function will be disabled if `tout_thrd == 0`.
819 *
820 * @return None.
821 */
uart_ll_set_rx_tout(uart_dev_t * hw,uint16_t tout_thrd)822 FORCE_INLINE_ATTR void uart_ll_set_rx_tout(uart_dev_t *hw, uint16_t tout_thrd)
823 {
824 uint16_t tout_val = tout_thrd;
825 if(tout_thrd > 0) {
826 hw->mem_conf.rx_tout_thrhd = tout_val;
827 hw->conf1.rx_tout_en = 1;
828 } else {
829 hw->conf1.rx_tout_en = 0;
830 }
831 }
832
833 /**
834 * @brief Get the timeout value for receiver receiving a byte.
835 *
836 * @param hw Beginning address of the peripheral registers.
837 *
838 * @return tout_thr The timeout threshold value. If timeout feature is disabled returns 0.
839 */
uart_ll_get_rx_tout_thr(uart_dev_t * hw)840 FORCE_INLINE_ATTR uint16_t uart_ll_get_rx_tout_thr(uart_dev_t *hw)
841 {
842 uint16_t tout_thrd = 0;
843 if(hw->conf1.rx_tout_en > 0) {
844 tout_thrd = hw->mem_conf.rx_tout_thrhd;
845 }
846 return tout_thrd;
847 }
848
849 /**
850 * @brief Get UART maximum timeout threshold.
851 *
852 * @param hw Beginning address of the peripheral registers.
853 *
854 * @return maximum timeout threshold.
855 */
uart_ll_max_tout_thrd(uart_dev_t * hw)856 FORCE_INLINE_ATTR uint16_t uart_ll_max_tout_thrd(uart_dev_t *hw)
857 {
858 return UART_RX_TOUT_THRHD_V;
859 }
860
861 /**
862 * @brief Configure the auto baudrate.
863 *
864 * @param hw Beginning address of the peripheral registers.
865 * @param enable Boolean marking whether the auto baudrate should be enabled or not.
866 */
uart_ll_set_autobaud_en(uart_dev_t * hw,bool enable)867 FORCE_INLINE_ATTR void uart_ll_set_autobaud_en(uart_dev_t *hw, bool enable)
868 {
869 hw->auto_baud.en = enable ? 1 : 0;
870 }
871
872 /**
873 * @brief Get the RXD edge count.
874 *
875 * @param hw Beginning address of the peripheral registers.
876 */
uart_ll_get_rxd_edge_cnt(uart_dev_t * hw)877 FORCE_INLINE_ATTR uint32_t uart_ll_get_rxd_edge_cnt(uart_dev_t *hw)
878 {
879 return hw->rxd_cnt.edge_cnt;
880 }
881
882 /**
883 * @brief Get the positive pulse minimum count.
884 *
885 * @param hw Beginning address of the peripheral registers.
886 */
uart_ll_get_pos_pulse_cnt(uart_dev_t * hw)887 FORCE_INLINE_ATTR uint32_t uart_ll_get_pos_pulse_cnt(uart_dev_t *hw)
888 {
889 return hw->pospulse.min_cnt;
890 }
891
892 /**
893 * @brief Get the negative pulse minimum count.
894 *
895 * @param hw Beginning address of the peripheral registers.
896 */
uart_ll_get_neg_pulse_cnt(uart_dev_t * hw)897 FORCE_INLINE_ATTR uint32_t uart_ll_get_neg_pulse_cnt(uart_dev_t *hw)
898 {
899 return hw->negpulse.min_cnt;
900 }
901
902 /**
903 * @brief Get the high pulse minimum count.
904 *
905 * @param hw Beginning address of the peripheral registers.
906 */
uart_ll_get_high_pulse_cnt(uart_dev_t * hw)907 FORCE_INLINE_ATTR uint32_t uart_ll_get_high_pulse_cnt(uart_dev_t *hw)
908 {
909 return hw->highpulse.min_cnt;
910 }
911
912 /**
913 * @brief Get the low pulse minimum count.
914 *
915 * @param hw Beginning address of the peripheral registers.
916 */
uart_ll_get_low_pulse_cnt(uart_dev_t * hw)917 FORCE_INLINE_ATTR uint32_t uart_ll_get_low_pulse_cnt(uart_dev_t *hw)
918 {
919 return hw->lowpulse.min_cnt;
920 }
921
922 /**
923 * @brief Force UART xoff.
924 *
925 * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
926 *
927 * @return None.
928 */
uart_ll_force_xoff(uart_port_t uart_num)929 FORCE_INLINE_ATTR void uart_ll_force_xoff(uart_port_t uart_num)
930 {
931 REG_CLR_BIT(UART_FLOW_CONF_REG(uart_num), UART_FORCE_XON);
932 REG_SET_BIT(UART_FLOW_CONF_REG(uart_num), UART_SW_FLOW_CON_EN | UART_FORCE_XOFF);
933 }
934
935 /**
936 * @brief Force UART xon.
937 *
938 * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
939 *
940 * @return None.
941 */
uart_ll_force_xon(uart_port_t uart_num)942 FORCE_INLINE_ATTR void uart_ll_force_xon(uart_port_t uart_num)
943 {
944 REG_CLR_BIT(UART_FLOW_CONF_REG(uart_num), UART_FORCE_XOFF);
945 REG_SET_BIT(UART_FLOW_CONF_REG(uart_num), UART_FORCE_XON);
946 REG_CLR_BIT(UART_FLOW_CONF_REG(uart_num), UART_SW_FLOW_CON_EN | UART_FORCE_XON);
947 }
948
949 /**
950 * @brief Get UART finite-state machine status.
951 *
952 * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
953 *
954 * @return UART module FSM status.
955 */
uart_ll_get_fsm_status(uart_port_t uart_num)956 FORCE_INLINE_ATTR uint32_t uart_ll_get_fsm_status(uart_port_t uart_num)
957 {
958 return REG_GET_FIELD(UART_FSM_STATUS_REG(uart_num), UART_ST_UTX_OUT);
959 }
960
961 /**
962 * @brief Configure UART whether to discard when receiving wrong data
963 *
964 * @param hw Beginning address of the peripheral registers.
965 * @param discard true: Receiver stops storing data into FIFO when data is wrong
966 * false: Receiver continue storing data into FIFO when data is wrong
967 */
uart_ll_discard_error_data(uart_dev_t * hw,bool discard)968 FORCE_INLINE_ATTR void uart_ll_discard_error_data(uart_dev_t *hw, bool discard)
969 {
970 hw->conf0.err_wr_mask = discard ? 1 : 0;
971 }
972
973 #ifdef __cplusplus
974 }
975 #endif
976