esp32/esp32_rmt: Extend RMT to support carrier feature.
The ESP32 RMT peripheral has hardware support for a carrier frequency, and this commit exposes it to Python with the keyword arguments carrier_freq and carrier_duty_percent in the constructor. Example usage: r = esp32.RMT(0, pin=Pin(2), clock_div=80, carrier_freq=38000, carrier_duty_percent=50)
This commit is contained in:
parent
a51eef4471
commit
1678f41744
|
@ -151,6 +151,11 @@ used to transmit or receive many other types of digital signals::
|
||||||
|
|
||||||
r = esp32.RMT(0, pin=Pin(18), clock_div=8)
|
r = esp32.RMT(0, pin=Pin(18), clock_div=8)
|
||||||
r # RMT(channel=0, pin=18, source_freq=80000000, clock_div=8)
|
r # RMT(channel=0, pin=18, source_freq=80000000, clock_div=8)
|
||||||
|
|
||||||
|
# To use carrier frequency
|
||||||
|
r = esp32.RMT(0, pin=Pin(18), clock_div=8, carrier_freq=38000)
|
||||||
|
r # RMT(channel=0, pin=18, source_freq=80000000, clock_div=8, carrier_freq=38000, carrier_duty_percent=50)
|
||||||
|
|
||||||
# The channel resolution is 100ns (1/(source_freq/clock_div)).
|
# The channel resolution is 100ns (1/(source_freq/clock_div)).
|
||||||
r.write_pulses((1, 20, 2, 40), start=0) # Send 0 for 100ns, 1 for 2000ns, 0 for 200ns, 1 for 4000ns
|
r.write_pulses((1, 20, 2, 40), start=0) # Send 0 for 100ns, 1 for 2000ns, 0 for 200ns, 1 for 4000ns
|
||||||
|
|
||||||
|
@ -164,6 +169,9 @@ define the pulses.
|
||||||
multiplying the resolution by a 15-bit (0-32,768) number. There are eight
|
multiplying the resolution by a 15-bit (0-32,768) number. There are eight
|
||||||
channels (0-7) and each can have a different clock divider.
|
channels (0-7) and each can have a different clock divider.
|
||||||
|
|
||||||
|
To enable the carrier frequency feature of the esp32 hardware, specify the
|
||||||
|
``carrier_freq`` as something like 38000, a typical IR carrier frequency.
|
||||||
|
|
||||||
So, in the example above, the 80MHz clock is divided by 8. Thus the
|
So, in the example above, the 80MHz clock is divided by 8. Thus the
|
||||||
resolution is (1/(80Mhz/8)) 100ns. Since the ``start`` level is 0 and toggles
|
resolution is (1/(80Mhz/8)) 100ns. Since the ``start`` level is 0 and toggles
|
||||||
with each number, the bitstream is ``0101`` with durations of [100ns, 2000ns,
|
with each number, the bitstream is ``0101`` with durations of [100ns, 2000ns,
|
||||||
|
@ -174,17 +182,20 @@ For more details see Espressif's `ESP-IDF RMT documentation.
|
||||||
|
|
||||||
.. Warning::
|
.. Warning::
|
||||||
The current MicroPython RMT implementation lacks some features, most notably
|
The current MicroPython RMT implementation lacks some features, most notably
|
||||||
receiving pulses and carrier transmit. RMT should be considered a
|
receiving pulses. RMT should be considered a
|
||||||
*beta feature* and the interface may change in the future.
|
*beta feature* and the interface may change in the future.
|
||||||
|
|
||||||
|
|
||||||
.. class:: RMT(channel, \*, pin=None, clock_div=8)
|
.. class:: RMT(channel, \*, pin=None, clock_div=8, carrier_freq=0, carrier_duty_percent=50)
|
||||||
|
|
||||||
This class provides access to one of the eight RMT channels. *channel* is
|
This class provides access to one of the eight RMT channels. *channel* is
|
||||||
required and identifies which RMT channel (0-7) will be configured. *pin*,
|
required and identifies which RMT channel (0-7) will be configured. *pin*,
|
||||||
also required, configures which Pin is bound to the RMT channel. *clock_div*
|
also required, configures which Pin is bound to the RMT channel. *clock_div*
|
||||||
is an 8-bit clock divider that divides the source clock (80MHz) to the RMT
|
is an 8-bit clock divider that divides the source clock (80MHz) to the RMT
|
||||||
channel allowing the resolution to be specified.
|
channel allowing the resolution to be specified. *carrier_freq* is used to
|
||||||
|
enable the carrier feature and specify its frequency, default value is ``0``
|
||||||
|
(not enabled). To enable, specify a positive integer. *carrier_duty_percent*
|
||||||
|
defaults to 50.
|
||||||
|
|
||||||
.. method:: RMT.source_freq()
|
.. method:: RMT.source_freq()
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,8 @@ typedef struct _esp32_rmt_obj_t {
|
||||||
uint8_t channel_id;
|
uint8_t channel_id;
|
||||||
gpio_num_t pin;
|
gpio_num_t pin;
|
||||||
uint8_t clock_div;
|
uint8_t clock_div;
|
||||||
|
uint16_t carrier_duty_percent;
|
||||||
|
uint32_t carrier_freq;
|
||||||
mp_uint_t num_items;
|
mp_uint_t num_items;
|
||||||
rmt_item32_t *items;
|
rmt_item32_t *items;
|
||||||
} esp32_rmt_obj_t;
|
} esp32_rmt_obj_t;
|
||||||
|
@ -61,6 +63,8 @@ STATIC mp_obj_t esp32_rmt_make_new(const mp_obj_type_t *type, size_t n_args, siz
|
||||||
{ MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} },
|
{ MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = -1} },
|
||||||
{ MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
{ MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||||
{ MP_QSTR_clock_div, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, // 100ns resolution
|
{ MP_QSTR_clock_div, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, // 100ns resolution
|
||||||
|
{ MP_QSTR_carrier_duty_percent, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 50} },
|
||||||
|
{ MP_QSTR_carrier_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||||
};
|
};
|
||||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||||
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||||
|
@ -68,6 +72,16 @@ STATIC mp_obj_t esp32_rmt_make_new(const mp_obj_type_t *type, size_t n_args, siz
|
||||||
gpio_num_t pin_id = machine_pin_get_id(args[1].u_obj);
|
gpio_num_t pin_id = machine_pin_get_id(args[1].u_obj);
|
||||||
mp_uint_t clock_div = args[2].u_int;
|
mp_uint_t clock_div = args[2].u_int;
|
||||||
|
|
||||||
|
bool carrier_en = false;
|
||||||
|
mp_uint_t carrier_duty_percent = 0;
|
||||||
|
mp_uint_t carrier_freq = 0;
|
||||||
|
|
||||||
|
if (args[4].u_int > 0) {
|
||||||
|
carrier_en = true;
|
||||||
|
carrier_duty_percent = args[3].u_int;
|
||||||
|
carrier_freq = args[4].u_int;
|
||||||
|
}
|
||||||
|
|
||||||
if (clock_div < 1 || clock_div > 255) {
|
if (clock_div < 1 || clock_div > 255) {
|
||||||
mp_raise_ValueError(MP_ERROR_TEXT("clock_div must be between 1 and 255"));
|
mp_raise_ValueError(MP_ERROR_TEXT("clock_div must be between 1 and 255"));
|
||||||
}
|
}
|
||||||
|
@ -77,6 +91,8 @@ STATIC mp_obj_t esp32_rmt_make_new(const mp_obj_type_t *type, size_t n_args, siz
|
||||||
self->channel_id = channel_id;
|
self->channel_id = channel_id;
|
||||||
self->pin = pin_id;
|
self->pin = pin_id;
|
||||||
self->clock_div = clock_div;
|
self->clock_div = clock_div;
|
||||||
|
self->carrier_duty_percent = carrier_duty_percent;
|
||||||
|
self->carrier_freq = carrier_freq;
|
||||||
|
|
||||||
rmt_config_t config;
|
rmt_config_t config;
|
||||||
config.rmt_mode = RMT_MODE_TX;
|
config.rmt_mode = RMT_MODE_TX;
|
||||||
|
@ -85,11 +101,11 @@ STATIC mp_obj_t esp32_rmt_make_new(const mp_obj_type_t *type, size_t n_args, siz
|
||||||
config.mem_block_num = 1;
|
config.mem_block_num = 1;
|
||||||
config.tx_config.loop_en = 0;
|
config.tx_config.loop_en = 0;
|
||||||
|
|
||||||
config.tx_config.carrier_en = 0;
|
config.tx_config.carrier_en = carrier_en;
|
||||||
config.tx_config.idle_output_en = 1;
|
config.tx_config.idle_output_en = 1;
|
||||||
config.tx_config.idle_level = 0;
|
config.tx_config.idle_level = 0;
|
||||||
config.tx_config.carrier_duty_percent = 0;
|
config.tx_config.carrier_duty_percent = self->carrier_duty_percent;
|
||||||
config.tx_config.carrier_freq_hz = 0;
|
config.tx_config.carrier_freq_hz = self->carrier_freq;
|
||||||
config.tx_config.carrier_level = 1;
|
config.tx_config.carrier_level = 1;
|
||||||
|
|
||||||
config.clk_div = self->clock_div;
|
config.clk_div = self->clock_div;
|
||||||
|
@ -103,8 +119,14 @@ STATIC mp_obj_t esp32_rmt_make_new(const mp_obj_type_t *type, size_t n_args, siz
|
||||||
STATIC void esp32_rmt_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
STATIC void esp32_rmt_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||||
esp32_rmt_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
esp32_rmt_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
if (self->pin != -1) {
|
if (self->pin != -1) {
|
||||||
mp_printf(print, "RMT(channel=%u, pin=%u, source_freq=%u, clock_div=%u)",
|
mp_printf(print, "RMT(channel=%u, pin=%u, source_freq=%u, clock_div=%u",
|
||||||
self->channel_id, self->pin, APB_CLK_FREQ, self->clock_div);
|
self->channel_id, self->pin, APB_CLK_FREQ, self->clock_div);
|
||||||
|
if (self->carrier_freq > 0) {
|
||||||
|
mp_printf(print, ", carrier_freq=%u, carrier_duty_percent=%u)",
|
||||||
|
self->carrier_freq, self->carrier_duty_percent);
|
||||||
|
} else {
|
||||||
|
mp_printf(print, ")");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
mp_printf(print, "RMT()");
|
mp_printf(print, "RMT()");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue