39
39
#include "py/mperrno.h"
40
40
#include "py/mphal.h"
41
41
#include "uart.h"
42
+ #include "machine_timer.h"
42
43
43
44
#if SOC_UART_SUPPORT_XTAL_CLK
44
45
// Works independently of APB frequency, on ESP32C3, ESP32S3.
54
55
55
56
#define UART_INV_MASK (UART_INV_TX | UART_INV_RX | UART_INV_RTS | UART_INV_CTS)
56
57
#define UART_IRQ_RX (1 << UART_DATA)
58
+ #define UART_IRQ_RXIDLE (0x1000)
57
59
#define UART_IRQ_BREAK (1 << UART_BREAK)
58
- #define MP_UART_ALLOWED_FLAGS (UART_IRQ_RX | UART_IRQ_BREAK)
60
+ #define MP_UART_ALLOWED_FLAGS (UART_IRQ_RX | UART_IRQ_RXIDLE | UART_IRQ_BREAK)
61
+ #define RXIDLE_TIMER_MIN (5000) // 500 us
62
+
63
+ enum {
64
+ RXIDLE_INACTIVE ,
65
+ RXIDLE_STANDBY ,
66
+ RXIDLE_ARMED ,
67
+ RXIDLE_ALERT ,
68
+ };
59
69
60
70
typedef struct _machine_uart_obj_t {
61
71
mp_obj_base_t base ;
@@ -78,6 +88,9 @@ typedef struct _machine_uart_obj_t {
78
88
uint16_t mp_irq_trigger ; // user IRQ trigger mask
79
89
uint16_t mp_irq_flags ; // user IRQ active IRQ flags
80
90
mp_irq_obj_t * mp_irq_obj ; // user IRQ object
91
+ machine_timer_obj_t * rxidle_timer ;
92
+ uint8_t rxidle_state ;
93
+ uint16_t rxidle_period ;
81
94
} machine_uart_obj_t ;
82
95
83
96
static const char * _parity_name [] = {"None" , "1" , "0" };
@@ -93,28 +106,67 @@ static const char *_parity_name[] = {"None", "1", "0"};
93
106
{ MP_ROM_QSTR(MP_QSTR_RTS), MP_ROM_INT(UART_HW_FLOWCTRL_RTS) }, \
94
107
{ MP_ROM_QSTR(MP_QSTR_CTS), MP_ROM_INT(UART_HW_FLOWCTRL_CTS) }, \
95
108
{ MP_ROM_QSTR(MP_QSTR_IRQ_RX), MP_ROM_INT(UART_IRQ_RX) }, \
109
+ { MP_ROM_QSTR(MP_QSTR_IRQ_RXIDLE), MP_ROM_INT(UART_IRQ_RXIDLE) }, \
96
110
{ MP_ROM_QSTR(MP_QSTR_IRQ_BREAK), MP_ROM_INT(UART_IRQ_BREAK) }, \
97
111
112
+ static void uart_timer_callback (void * self_in ) {
113
+ machine_timer_obj_t * self = self_in ;
114
+
115
+ uint32_t intr_status = timer_ll_get_intr_status (self -> hal_context .dev );
116
+
117
+ if (intr_status & TIMER_LL_EVENT_ALARM (self -> index )) {
118
+ timer_ll_clear_intr_status (self -> hal_context .dev , TIMER_LL_EVENT_ALARM (self -> index ));
119
+ if (self -> repeat ) {
120
+ timer_ll_enable_alarm (self -> hal_context .dev , self -> index , true);
121
+ }
122
+ }
123
+
124
+ // The UART object is referred here by the callback field.
125
+ machine_uart_obj_t * uart = (machine_uart_obj_t * )self -> callback ;
126
+ if (uart -> rxidle_state == RXIDLE_ALERT ) {
127
+ // At the first call, just switch the state
128
+ uart -> rxidle_state = RXIDLE_ARMED ;
129
+ } else if (uart -> rxidle_state == RXIDLE_ARMED ) {
130
+ // At the second call, run the irq callback and stop the timer
131
+ uart -> rxidle_state = RXIDLE_STANDBY ;
132
+ uart -> mp_irq_flags = UART_IRQ_RXIDLE ;
133
+ mp_irq_handler (uart -> mp_irq_obj );
134
+ mp_hal_wake_main_task_from_isr ();
135
+ machine_timer_disable (uart -> rxidle_timer );
136
+ }
137
+ }
138
+
98
139
static void uart_event_task (void * self_in ) {
99
140
machine_uart_obj_t * self = MP_OBJ_TO_PTR (self_in );
100
141
uart_event_t event ;
101
142
for (;;) {
102
143
// Waiting for an UART event.
103
144
if (xQueueReceive (self -> uart_queue , (void * )& event , (TickType_t )portMAX_DELAY )) {
104
- self -> mp_irq_flags = 0 ;
145
+ uint16_t mp_irq_flags = 0 ;
105
146
switch (event .type ) {
106
147
// Event of UART receiving data
107
148
case UART_DATA :
108
- self -> mp_irq_flags |= UART_IRQ_RX ;
149
+ if (self -> mp_irq_trigger & UART_IRQ_RXIDLE ) {
150
+ if (self -> rxidle_state != RXIDLE_INACTIVE ) {
151
+ if (self -> rxidle_state == RXIDLE_STANDBY ) {
152
+ self -> rxidle_timer -> repeat = true;
153
+ self -> rxidle_timer -> handle = NULL ;
154
+ machine_timer_enable (self -> rxidle_timer , uart_timer_callback );
155
+ }
156
+ }
157
+ self -> rxidle_state = RXIDLE_ALERT ;
158
+ }
159
+ mp_irq_flags |= UART_IRQ_RX ;
109
160
break ;
110
161
case UART_BREAK :
111
- self -> mp_irq_flags |= UART_IRQ_BREAK ;
162
+ mp_irq_flags |= UART_IRQ_BREAK ;
112
163
break ;
113
164
default :
114
165
break ;
115
166
}
116
167
// Check the flags to see if the user handler should be called
117
- if (self -> mp_irq_trigger & self -> mp_irq_flags ) {
168
+ if (self -> mp_irq_trigger & mp_irq_flags ) {
169
+ self -> mp_irq_flags = mp_irq_flags ;
118
170
mp_irq_handler (self -> mp_irq_obj );
119
171
mp_hal_wake_main_task_from_isr ();
120
172
}
@@ -390,6 +442,7 @@ static mp_obj_t mp_machine_uart_make_new(const mp_obj_type_t *type, size_t n_arg
390
442
self -> invert = 0 ;
391
443
self -> flowcontrol = 0 ;
392
444
self -> uart_event_task = 0 ;
445
+ self -> rxidle_state = RXIDLE_INACTIVE ;
393
446
394
447
switch (uart_num ) {
395
448
case UART_NUM_0 :
@@ -464,8 +517,35 @@ static void mp_machine_uart_sendbreak(machine_uart_obj_t *self) {
464
517
check_esp_err (uart_set_baudrate (self -> uart_num , baudrate ));
465
518
}
466
519
520
+ // Configure the timer used for IRQ_RXIDLE
521
+ static void uart_irq_configure_timer (machine_uart_obj_t * self , mp_uint_t trigger ) {
522
+
523
+ self -> rxidle_state = RXIDLE_INACTIVE ;
524
+
525
+ if (trigger & UART_IRQ_RXIDLE ) {
526
+ // The RXIDLE event is always a soft IRQ.
527
+ self -> mp_irq_obj -> ishard = false;
528
+ uint32_t baudrate ;
529
+ uart_get_baudrate (self -> uart_num , & baudrate );
530
+ mp_int_t period = TIMER_SCALE * 20 / baudrate + 1 ;
531
+ if (period < RXIDLE_TIMER_MIN ) {
532
+ period = RXIDLE_TIMER_MIN ;
533
+ }
534
+ self -> rxidle_period = period ;
535
+ self -> rxidle_timer -> period = period ;
536
+ // The Python callback is not used. So use this
537
+ // data field to hold a reference to the UART object.
538
+ self -> rxidle_timer -> callback = self ;
539
+ self -> rxidle_timer -> repeat = true;
540
+ self -> rxidle_timer -> handle = NULL ;
541
+ self -> rxidle_state = RXIDLE_STANDBY ;
542
+ }
543
+ }
544
+
467
545
static mp_uint_t uart_irq_trigger (mp_obj_t self_in , mp_uint_t new_trigger ) {
468
546
machine_uart_obj_t * self = MP_OBJ_TO_PTR (self_in );
547
+
548
+ uart_irq_configure_timer (self , new_trigger );
469
549
self -> mp_irq_trigger = new_trigger ;
470
550
return 0 ;
471
551
}
@@ -511,6 +591,9 @@ static mp_irq_obj_t *mp_machine_uart_irq(machine_uart_obj_t *self, bool any_args
511
591
}
512
592
self -> mp_irq_obj -> ishard = false;
513
593
self -> mp_irq_trigger = trigger ;
594
+ self -> rxidle_timer = machine_timer_create (0 );
595
+ uart_irq_configure_timer (self , trigger );
596
+
514
597
// Start a task for handling events
515
598
if (handler != mp_const_none && self -> uart_event_task == NULL ) {
516
599
xTaskCreatePinnedToCore (uart_event_task , "uart_event_task" , 2048 , self ,
0 commit comments