1212
1313#if !defined(M5_UNIT_UNIFIED_USING_RMT_V2)
1414
15- #include < esp_clk.h>
15+ // #include <esp_clk.h>
16+ #include < esp32/clk.h>
1617using namespace m5 ::unit::gpio;
1718
1819namespace {
1920
2021uint32_t using_rmt_channel_bits{};
2122
22- rmt_channel_t retrieve_available_rmt_channel ()
23+ rmt_channel_t retrieve_available_rmt_channel (const int8_t first = 0 )
2324{
24- for (int_fast8_t ch = 0 ; ch < RMT_CHANNEL_MAX; ++ch) {
25+ for (int_fast8_t ch = first ; ch < RMT_CHANNEL_MAX; ++ch) {
2526 if (((1U << ch) & using_rmt_channel_bits) == 0 ) {
2627 return (rmt_channel_t )ch;
2728 }
@@ -48,124 +49,247 @@ void clear_use_rmt_channel(const int ch)
4849rmt_config_t to_rmt_config_tx (const adapter_config_t & cfg, const uint32_t apb_freq_hz)
4950{
5051 rmt_config_t out{};
51- out.rmt_mode = RMT_MODE_TX;
52- out.mem_block_num = cfg.tx .mem_blocks ;
53-
54- out.clk_div = calculate_rmt_clk_div (apb_freq_hz, cfg.tx .tick_ns ) ;
55- out.tx_config .carrier_en = false ;
56- out.tx_config .idle_output_en = cfg.tx .idle_output ;
52+ out.rmt_mode = RMT_MODE_TX;
53+ out.mem_block_num = std::min< uint8_t >( cfg.tx .mem_blocks , 8u ) ;
54+ out. clk_div = calculate_rmt_clk_div (apb_freq_hz, cfg. tx . tick_ns );
55+ out.tx_config . loop_en = cfg.tx .loop_enabled ;
56+ // out.tx_config.carrier_en = cfg.tx.carrier_enabled ;
57+ out.tx_config .idle_output_en = cfg.tx .idle_output_enabled ;
5758 out.tx_config .idle_level = cfg.tx .idle_level_high ? RMT_IDLE_LEVEL_HIGH : RMT_IDLE_LEVEL_LOW;
58- out.tx_config .loop_en = cfg.tx .loop_enabled ;
5959 return out;
6060}
6161
62- #if 0
6362rmt_config_t to_rmt_config_rx (const adapter_config_t & cfg, const uint32_t apb_freq_hz)
6463{
6564 rmt_config_t out{};
66- out.rmt_mode = RMT_MODE_RX;
67- out.mem_block_num = cfg.tx.mem_blocks;
68- out.clk_div = calculate_rmt_clk_div(apb_freq_hz, cfg.rx.tick_ns);
69- out.rx_config.filter_en = true;
70- out.rx_config.filter_ticks_thresh = 30;
71- out.rx_config.idle_threshold = 300;
65+ out.rmt_mode = RMT_MODE_RX;
66+ out.mem_block_num = std::min<uint8_t >(cfg.rx .mem_blocks , 8u );
67+ out.clk_div = calculate_rmt_clk_div (apb_freq_hz, cfg.rx .tick_ns );
68+ out.rx_config .filter_en = cfg.rx .filter_enabled ;
69+ out.rx_config .filter_ticks_thresh =
70+ std::min<uint8_t >(static_cast <uint32_t >(cfg.rx .filter_ticks_threshold ) * 1000 / cfg.rx .tick_ns , 255U );
71+ out.rx_config .idle_threshold =
72+ static_cast <uint16_t >(static_cast <uint32_t >(cfg.rx .idle_ticks_threshold ) * 1000 / cfg.rx .tick_ns );
7273 return out;
7374}
75+
76+ void dump_rmt_config (const rmt_config_t & cfg, const char * title = " RMT CONFIG" )
77+ {
78+ M5_LIB_LOGI (" === %s ===" , title);
79+ M5_LIB_LOGI (" rmt_mode : %s" , cfg.rmt_mode == RMT_MODE_TX ? " TX" : " RX" );
80+ M5_LIB_LOGI (" channel : %d" , static_cast <int >(cfg.channel ));
81+ M5_LIB_LOGI (" gpio_num : %d" , static_cast <int >(cfg.gpio_num ));
82+ M5_LIB_LOGI (" mem_block_num : %d" , cfg.mem_block_num );
83+ M5_LIB_LOGI (" clk_div : %d" , cfg.clk_div );
84+
85+ if (cfg.rmt_mode == RMT_MODE_TX) {
86+ M5_LIB_LOGI (" TX CONFIG:" );
87+ M5_LIB_LOGI (" loop_en : %s" , cfg.tx_config .loop_en ? " true" : " false" );
88+ M5_LIB_LOGI (" carrier_en : %s" , cfg.tx_config .carrier_en ? " true" : " false" );
89+ M5_LIB_LOGI (" idle_output_en : %s" , cfg.tx_config .idle_output_en ? " true" : " false" );
90+ M5_LIB_LOGI (" idle_level : %d" , cfg.tx_config .idle_level );
91+ M5_LIB_LOGI (" carrier_freq_hz : %d" , cfg.tx_config .carrier_freq_hz );
92+ M5_LIB_LOGI (" carrier_duty : %d%%" , cfg.tx_config .carrier_duty_percent );
93+ M5_LIB_LOGI (" carrier_level : %d" , cfg.tx_config .carrier_level );
94+ } else {
95+ M5_LIB_LOGI (" RX CONFIG:" );
96+ M5_LIB_LOGI (" filter_en : %s" , cfg.rx_config .filter_en ? " true" : " false" );
97+ M5_LIB_LOGI (" filter_thresh : %d" , cfg.rx_config .filter_ticks_thresh );
98+ M5_LIB_LOGI (" idle_threshold : %d" , cfg.rx_config .idle_threshold );
99+ }
100+ }
101+
102+ #if 0
103+ void dump_items(const rmt_item32_t* items, const uint32_t item_num)
104+ {
105+ for (uint32_t i = 0; i < item_num; ++i) {
106+ auto d = items[i];
107+ M5_LIB_LOGI("[%02u]:{%u,%u,%u,%u}", i, d.duration0, d.level0, d.duration1, d.level1);
108+ }
109+ }
74110#endif
111+
75112} // namespace
76113
77114namespace m5 {
78115namespace unit {
79116
80117class GPIOImplV1 : public AdapterGPIOBase ::GPIOImpl {
81118public:
82- GPIOImplV1 () : AdapterGPIOBase::GPIOImpl(-1 , -1 )
83- {
84- }
85- GPIOImplV1 (const int8_t rx_pin, const int8_t tx_pin) : AdapterGPIOBase::GPIOImpl(rx_pin, tx_pin)
119+ explicit GPIOImplV1 (const int8_t rx_pin = -1 , const int8_t tx_pin = -1 ) : AdapterGPIOBase::GPIOImpl(rx_pin, tx_pin)
86120 {
121+ _rx_config.channel = RMT_CHANNEL_MAX;
122+ _tx_config.channel = RMT_CHANNEL_MAX;
87123 }
88124 virtual ~GPIOImplV1 ()
89125 {
90- rmt_tx_stop (_tx_config.channel );
91- rmt_driver_uninstall (_tx_config.channel );
92- clear_use_rmt_channel (_tx_config.channel );
93-
94- rmt_rx_stop (_rx_config.channel );
95- rmt_driver_uninstall (_rx_config.channel );
96- clear_use_rmt_channel (_rx_config.channel );
126+ if (_tx_config.channel != RMT_CHANNEL_MAX) {
127+ rmt_tx_stop (_tx_config.channel );
128+ rmt_driver_uninstall (_tx_config.channel );
129+ clear_use_rmt_channel (_tx_config.channel );
130+ }
131+ if (_rx_config.channel != RMT_CHANNEL_MAX) {
132+ rmt_rx_stop (_rx_config.channel );
133+ rmt_driver_uninstall (_rx_config.channel );
134+ clear_use_rmt_channel (_rx_config.channel );
135+ }
97136 }
98137
99138 virtual bool begin (const gpio::adapter_config_t & cfg) override
100139 {
101140 _adapter_cfg = cfg;
102141
103- if (_tx_config.clk_div || _rx_config.clk_div ) {
104- M5_LIB_LOGD (" Already begun" );
105- return true ;
106- }
107-
108142 // RMT TX
109- if (cfg.mode == gpio::Mode::RmtTX || cfg.mode == gpio::Mode::RmtRXTX) {
143+ if (_tx_config.channel == RMT_CHANNEL_MAX &&
144+ (cfg.mode == gpio::Mode::RmtTX || cfg.mode == gpio::Mode::RmtRXTX)) {
110145 rmt_channel_t ch = retrieve_available_rmt_channel ();
111146 if (ch >= RMT_CHANNEL_MAX) {
112- M5_LIB_LOGE (" RMT(v1) No room on channel" );
147+ M5_LIB_LOGE (" RMT(v1) No room on TX channel" );
113148 return false ;
114149 }
115- declrare_use_rmt_channel (ch);
116- M5_LIB_LOGI (" Retrive RMT(v1) %u" , ch);
117-
118150 _tx_config = to_rmt_config_tx (cfg, esp_clk_apb_freq ());
119151 _tx_config.channel = ch;
120152 _tx_config.gpio_num = tx_pin ();
121153
154+ dump_rmt_config (_tx_config, " TX" );
155+
122156 auto err = rmt_config (&_tx_config);
123157 if (err != ESP_OK) {
124- M5_LIB_LOGE (" Failed to configurate %d:%s" , err, esp_err_to_name (err));
158+ M5_LIB_LOGE (" Failed to config TX %d:%s" , err, esp_err_to_name (err));
125159 return false ;
126160 }
161+
127162 err = rmt_driver_install (_tx_config.channel , 0 , 0 );
128163 if (err != ESP_OK) {
129- M5_LIB_LOGE (" Failed to install %d:%s" , err, esp_err_to_name (err));
164+ M5_LIB_LOGE (" Failed to install TX %d:%s" , err, esp_err_to_name (err));
130165 return false ;
131166 }
167+
168+ if (_adapter_cfg.tx .invert_signal ) {
169+ gpio_matrix_out (_tx_config.gpio_num , _tx_config.channel + RMT_SIG_OUT0_IDX, true , false );
170+ }
171+
172+ declrare_use_rmt_channel (ch);
173+ M5_LIB_LOGI (" Retrive RMT(v1) TX %d/%u" , tx_pin (), ch);
132174 }
133175 // RMT RX
134- if (cfg.mode == gpio::Mode::RmtRX || cfg.mode == gpio::Mode::RmtRXTX) {
135- // TODO
136- }
176+ if (_rx_config.channel == RMT_CHANNEL_MAX &&
177+ (cfg.mode == gpio::Mode::RmtRX || cfg.mode == gpio::Mode::RmtRXTX)) {
178+ #if defined(CONFIG_IDF_TARGET_ESP32S3)
179+ int8_t first = 4 ; // RX channel 4 - 7
180+ #elif defined(CONFIG_IDF_TARGET_ESP32C6)
181+ int8_t first = 2 ; // RX channel 2 - 3
182+ #else
183+ int8_t first = 0 ;
184+ #endif
185+ rmt_channel_t ch = retrieve_available_rmt_channel (first);
186+ if (ch >= RMT_CHANNEL_MAX) {
187+ M5_LIB_LOGE (" RMT(v1) No room on RX channel" );
188+ return false ;
189+ }
190+
191+ _rx_config = to_rmt_config_rx (cfg, esp_clk_apb_freq ());
192+ _rx_config.channel = ch;
193+ _rx_config.gpio_num = rx_pin ();
194+
195+ dump_rmt_config (_rx_config, " RX" );
137196
197+ auto err = rmt_config (&_rx_config);
198+ if (err != ESP_OK) {
199+ M5_LIB_LOGE (" Failed to config RX %d:%s" , err, esp_err_to_name (err));
200+ return false ;
201+ }
202+
203+ err = rmt_driver_install (_rx_config.channel , cfg.rx .ring_buffer_size , 0 );
204+ if (err != ESP_OK) {
205+ M5_LIB_LOGE (" Failed to install RX %d:%s" , err, esp_err_to_name (err));
206+ return false ;
207+ }
208+
209+ if (_adapter_cfg.rx .invert_signal ) {
210+ gpio_matrix_in (_rx_config.gpio_num , _rx_config.channel + RMT_SIG_IN0_IDX, true );
211+ }
212+
213+ declrare_use_rmt_channel (ch);
214+ M5_LIB_LOGI (" Retrieve RMT(v1) RX %d/%u" , rx_pin (), ch);
215+
216+ if (rmt_rx_start (_rx_config.channel , true ) != ESP_OK) {
217+ M5_LIB_LOGE (" Failed to start RX" );
218+ return false ;
219+ }
220+
221+ // Discard garbage
222+ size_t rx_size{};
223+ RingbufHandle_t rb{};
224+ rmt_get_ringbuf_handle (_rx_config.channel , &rb);
225+ if (rb) {
226+ rmt_item32_t * items = (rmt_item32_t *)xRingbufferReceive (rb, &rx_size, 10 / portTICK_PERIOD_MS);
227+ if (items) {
228+ vRingbufferReturnItem (rb, items);
229+ }
230+ }
231+ }
138232 return true ;
139233 }
140234
141235 m5::hal::error::error_t writeWithTransaction (const uint8_t * data, const size_t len, const uint32_t waitMs) override
142236 {
143- if (_adapter_cfg.mode == Mode::RmtTX || _adapter_cfg.mode == Mode::RmtRXTX) {
144- auto err = rmt_write_items (_tx_config.channel , (gpio::m5_rmt_item_t *)data, len, true );
237+ if (_tx_config.channel == RMT_CHANNEL_MAX) {
238+ M5_LIB_LOGE (" Invalid channel" );
239+ return m5::hal::error::error_t ::UNKNOWN_ERROR;
240+ }
241+
242+ // m5::utility::log::dump(data, len, false);
243+ // dump_items((rmt_item32_t*)data, len / sizeof(rmt_item32_t));
244+
245+ auto err = rmt_write_items (_tx_config.channel , (gpio::m5_rmt_item_t *)data, len / sizeof (rmt_item32_t ), false );
246+ if (err != ESP_OK) {
247+ M5_LIB_LOGE (" Failed to write %d:%s" , err, esp_err_to_name (err));
248+ return m5::hal::error::error_t ::UNKNOWN_ERROR;
249+ }
250+ if (err == ESP_OK && waitMs) {
251+ // M5_LIB_LOGE(">>> wait_tx_done %d,%u", _tx_config.channel, waitMs);
252+ err = rmt_wait_tx_done (_tx_config.channel , waitMs);
145253 if (err != ESP_OK) {
146- M5_LIB_LOGE (" Failed to write %d:%s" , err, esp_err_to_name (err));
147- return m5::hal::error::error_t ::UNKNOWN_ERROR;
254+ M5_LIB_LOGE (" Failed to wait %d:%s" , err, esp_err_to_name (err));
148255 }
149- if (err == ESP_OK && waitMs) {
150- err = rmt_wait_tx_done (_tx_config.channel , pdMS_TO_TICKS (50 ));
151- if (err != ESP_OK) {
152- M5_LIB_LOGE (" Failed to wait %d:%s" , err, esp_err_to_name (err));
153- }
154- }
155- return err == ESP_OK ? m5::hal::error::error_t ::OK : m5::hal::error::error_t ::UNKNOWN_ERROR;
156256 }
157-
158- M5_LIB_LOGE (" Failed invalid config" );
159- return m5::hal::error::error_t ::UNKNOWN_ERROR;
257+ return err == ESP_OK ? m5::hal::error::error_t ::OK : m5::hal::error::error_t ::UNKNOWN_ERROR;
160258 }
161259
162- void copy_from (GPIOImplV1* ptr )
260+ m5::hal::error:: error_t readWithTransaction ( uint8_t * data, const size_t len )
163261 {
164- _rx_pin = ptr->_rx_pin ;
165- _tx_pin = ptr->_tx_pin ;
166- _adapter_cfg = ptr->_adapter_cfg ;
167- _rx_config = ptr->_rx_config ;
168- _tx_config = ptr->_tx_config ;
262+ if (_rx_config.channel == RMT_CHANNEL_MAX) {
263+ M5_LIB_LOGE (" Invalid channel" );
264+ return m5::hal::error::error_t ::UNKNOWN_ERROR;
265+ }
266+
267+ if (len < 4 ) {
268+ M5_LIB_LOGE (" length too small %zu" , len);
269+ return m5::hal::error::error_t ::INVALID_ARGUMENT;
270+ }
271+
272+ RingbufHandle_t rb{};
273+ if (rmt_get_ringbuf_handle (_rx_config.channel , &rb) != ESP_OK || rb == nullptr ) {
274+ M5_LIB_LOGE (" Failed to get RX ringbuffer" );
275+ return m5::hal::error::error_t ::UNKNOWN_ERROR;
276+ }
277+
278+ size_t max_len = len - 2 ; // Top of 2bytes is receive length
279+ size_t rx_size{};
280+ rmt_item32_t * items = (rmt_item32_t *)xRingbufferReceive (rb, &rx_size, pdMS_TO_TICKS (50 ));
281+
282+ // dump_items(items, rx_size / sizeof(rmt_item32_t));
283+ *(uint16_t *)data = 0 ;
284+ if (items && rx_size) {
285+ uint16_t rlen = std::min<uint16_t >(rx_size, max_len);
286+ *(uint16_t *)data = rlen;
287+ memcpy (data + 2 , items, rlen);
288+ }
289+ if (items) {
290+ vRingbufferReturnItem (rb, items);
291+ }
292+ return rx_size ? m5::hal::error::error_t ::OK : m5::hal::error::error_t ::TIMEOUT_ERROR;
169293 }
170294
171295protected:
0 commit comments