Merge remote-tracking branch 'upstream/master' into upstream/sync-1.16
This commit is contained in:
commit
e82d582dc9
@ -150,14 +150,13 @@ used to transmit or receive many other types of digital signals::
|
||||
from machine import Pin
|
||||
|
||||
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, idle_level=0)
|
||||
|
||||
# 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)
|
||||
# To apply a carrier frequency to the high output
|
||||
r = esp32.RMT(0, pin=Pin(18), clock_div=8, tx_carrier=(38000, 50, 1))
|
||||
|
||||
# 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), 0) # Send 0 for 100ns, 1 for 2000ns, 0 for 200ns, 1 for 4000ns
|
||||
|
||||
The input to the RMT module is an 80MHz clock (in the future it may be able to
|
||||
configure the input clock but, for now, it's fixed). ``clock_div`` *divides*
|
||||
@ -169,9 +168,6 @@ define the pulses.
|
||||
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.
|
||||
|
||||
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
|
||||
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,
|
||||
@ -186,16 +182,21 @@ For more details see Espressif's `ESP-IDF RMT documentation.
|
||||
*beta feature* and the interface may change in the future.
|
||||
|
||||
|
||||
.. class:: RMT(channel, *, pin=None, clock_div=8, carrier_freq=0, carrier_duty_percent=50)
|
||||
.. class:: RMT(channel, *, pin=None, clock_div=8, idle_level=False, tx_carrier=None)
|
||||
|
||||
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*,
|
||||
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
|
||||
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.
|
||||
channel allowing the resolution to be specified. *idle_level* specifies
|
||||
what level the output will be when no transmission is in progress and can
|
||||
be any value that converts to a boolean, with ``True`` representing high
|
||||
voltage and ``False`` representing low.
|
||||
|
||||
To enable the transmission carrier feature, *tx_carrier* should be a tuple
|
||||
of three positive integers: carrier frequency, duty percent (``0`` to
|
||||
``100``) and the output level to apply the carrier to (a boolean as per
|
||||
*idle_level*).
|
||||
|
||||
.. method:: RMT.source_freq()
|
||||
|
||||
@ -207,39 +208,47 @@ For more details see Espressif's `ESP-IDF RMT documentation.
|
||||
Return the clock divider. Note that the channel resolution is
|
||||
``1 / (source_freq / clock_div)``.
|
||||
|
||||
.. method:: RMT.wait_done(timeout=0)
|
||||
.. method:: RMT.wait_done(*, timeout=0)
|
||||
|
||||
Returns ``True`` if the channel is currently transmitting a stream of pulses
|
||||
started with a call to `RMT.write_pulses`.
|
||||
|
||||
If *timeout* (defined in ticks of ``source_freq / clock_div``) is specified
|
||||
the method will wait for *timeout* or until transmission is complete,
|
||||
returning ``False`` if the channel continues to transmit. If looping is
|
||||
enabled with `RMT.loop` and a stream has started, then this method will
|
||||
always (wait and) return ``False``.
|
||||
Returns ``True`` if the channel is idle or ``False`` if a sequence of
|
||||
pulses started with `RMT.write_pulses` is being transmitted. If the
|
||||
*timeout* keyword argument is given then block for up to this many
|
||||
milliseconds for transmission to complete.
|
||||
|
||||
.. method:: RMT.loop(enable_loop)
|
||||
|
||||
Configure looping on the channel. *enable_loop* is bool, set to ``True`` to
|
||||
enable looping on the *next* call to `RMT.write_pulses`. If called with
|
||||
``False`` while a looping stream is currently being transmitted then the
|
||||
current set of pulses will be completed before transmission stops.
|
||||
``False`` while a looping sequence is currently being transmitted then the
|
||||
current loop iteration will be completed and then transmission will stop.
|
||||
|
||||
.. method:: RMT.write_pulses(pulses, start)
|
||||
.. method:: RMT.write_pulses(duration, data=True)
|
||||
|
||||
Begin sending *pulses*, a list or tuple defining the stream of pulses. The
|
||||
length of each pulse is defined by a number to be multiplied by the channel
|
||||
resolution ``(1 / (source_freq / clock_div))``. *start* defines whether the
|
||||
stream starts at 0 or 1.
|
||||
Begin transmitting a sequence. There are three ways to specify this:
|
||||
|
||||
If transmission of a stream is currently in progress then this method will
|
||||
block until transmission of that stream has ended before beginning sending
|
||||
*pulses*.
|
||||
**Mode 1:** *duration* is a list or tuple of durations. The optional *data*
|
||||
argument specifies the initial output level. The output level will toggle
|
||||
after each duration.
|
||||
|
||||
If looping is enabled with `RMT.loop`, the stream of pulses will be repeated
|
||||
indefinitely. Further calls to `RMT.write_pulses` will end the previous
|
||||
stream - blocking until the last set of pulses has been transmitted -
|
||||
before starting the next stream.
|
||||
**Mode 2:** *duration* is a positive integer and *data* is a list or tuple
|
||||
of output levels. *duration* specifies a fixed duration for each.
|
||||
|
||||
**Mode 3:** *duration* and *data* are lists or tuples of equal length,
|
||||
specifying individual durations and the output level for each.
|
||||
|
||||
Durations are in integer units of the channel resolution (as described
|
||||
above), between 1 and 32767 units. Output levels are any value that can
|
||||
be converted to a boolean, with ``True`` representing high voltage and
|
||||
``False`` representing low.
|
||||
|
||||
If transmission of an earlier sequence is in progress then this method will
|
||||
block until that transmission is complete before beginning the new sequence.
|
||||
|
||||
If looping has been enabled with `RMT.loop`, the sequence will be
|
||||
repeated indefinitely. Further calls to this method will block until the
|
||||
end of the current loop iteration before immediately beginning to loop the
|
||||
new sequence of pulses. Looping sequences longer than 126 pulses is not
|
||||
supported by the hardware.
|
||||
|
||||
|
||||
Ultra-Low-Power co-processor
|
||||
|
||||
@ -52,8 +52,6 @@ typedef struct _esp32_rmt_obj_t {
|
||||
uint8_t channel_id;
|
||||
gpio_num_t pin;
|
||||
uint8_t clock_div;
|
||||
uint16_t carrier_duty_percent;
|
||||
uint32_t carrier_freq;
|
||||
mp_uint_t num_items;
|
||||
rmt_item32_t *items;
|
||||
bool loop_en;
|
||||
@ -64,24 +62,16 @@ 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_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_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_QSTR_idle_level, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, // low voltage
|
||||
{ MP_QSTR_tx_carrier, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // no carrier
|
||||
};
|
||||
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_uint_t channel_id = args[0].u_int;
|
||||
gpio_num_t pin_id = machine_pin_get_id(args[1].u_obj);
|
||||
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;
|
||||
}
|
||||
mp_uint_t idle_level = args[3].u_bool;
|
||||
mp_obj_t tx_carrier_obj = args[4].u_obj;
|
||||
|
||||
if (clock_div < 1 || clock_div > 255) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("clock_div must be between 1 and 255"));
|
||||
@ -92,8 +82,6 @@ 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->pin = pin_id;
|
||||
self->clock_div = clock_div;
|
||||
self->carrier_duty_percent = carrier_duty_percent;
|
||||
self->carrier_freq = carrier_freq;
|
||||
self->loop_en = false;
|
||||
|
||||
rmt_config_t config = {0};
|
||||
@ -103,12 +91,30 @@ 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.tx_config.loop_en = 0;
|
||||
|
||||
config.tx_config.carrier_en = carrier_en;
|
||||
if (tx_carrier_obj != mp_const_none) {
|
||||
mp_obj_t *tx_carrier_details = NULL;
|
||||
mp_obj_get_array_fixed_n(tx_carrier_obj, 3, &tx_carrier_details);
|
||||
mp_uint_t frequency = mp_obj_get_int(tx_carrier_details[0]);
|
||||
mp_uint_t duty = mp_obj_get_int(tx_carrier_details[1]);
|
||||
mp_uint_t level = mp_obj_is_true(tx_carrier_details[2]);
|
||||
|
||||
if (frequency == 0) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("tx_carrier frequency must be >0"));
|
||||
}
|
||||
if (duty > 100) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("tx_carrier duty must be 0..100"));
|
||||
}
|
||||
|
||||
config.tx_config.carrier_en = 1;
|
||||
config.tx_config.carrier_freq_hz = frequency;
|
||||
config.tx_config.carrier_duty_percent = duty;
|
||||
config.tx_config.carrier_level = level;
|
||||
} else {
|
||||
config.tx_config.carrier_en = 0;
|
||||
}
|
||||
|
||||
config.tx_config.idle_output_en = 1;
|
||||
config.tx_config.idle_level = 0;
|
||||
config.tx_config.carrier_duty_percent = self->carrier_duty_percent;
|
||||
config.tx_config.carrier_freq_hz = self->carrier_freq;
|
||||
config.tx_config.carrier_level = 1;
|
||||
config.tx_config.idle_level = idle_level;
|
||||
|
||||
config.clk_div = self->clock_div;
|
||||
|
||||
@ -121,14 +127,11 @@ 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) {
|
||||
esp32_rmt_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
if (self->pin != -1) {
|
||||
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);
|
||||
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, ")");
|
||||
}
|
||||
bool idle_output_en;
|
||||
rmt_idle_level_t idle_level;
|
||||
check_esp_err(rmt_get_idle_level(self->channel_id, &idle_output_en, &idle_level));
|
||||
mp_printf(print, "RMT(channel=%u, pin=%u, source_freq=%u, clock_div=%u, idle_level=%u)",
|
||||
self->channel_id, self->pin, APB_CLK_FREQ, self->clock_div, idle_level);
|
||||
} else {
|
||||
mp_printf(print, "RMT()");
|
||||
}
|
||||
@ -162,7 +165,7 @@ STATIC mp_obj_t esp32_rmt_clock_div(mp_obj_t self_in) {
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp32_rmt_clock_div_obj, esp32_rmt_clock_div);
|
||||
|
||||
// Query whether the channel has finished sending pulses. Takes an optional
|
||||
// timeout (in ticks of the 80MHz clock), returning true if the pulse stream has
|
||||
// timeout (in milliseconds), returning true if the pulse stream has
|
||||
// completed or false if they are still transmitting (or timeout is reached).
|
||||
STATIC mp_obj_t esp32_rmt_wait_done(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
@ -175,7 +178,7 @@ STATIC mp_obj_t esp32_rmt_wait_done(size_t n_args, const mp_obj_t *pos_args, mp_
|
||||
|
||||
esp32_rmt_obj_t *self = MP_OBJ_TO_PTR(args[0].u_obj);
|
||||
|
||||
esp_err_t err = rmt_wait_tx_done(self->channel_id, args[1].u_int);
|
||||
esp_err_t err = rmt_wait_tx_done(self->channel_id, args[1].u_int / portTICK_PERIOD_MS);
|
||||
return err == ESP_OK ? mp_const_true : mp_const_false;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp32_rmt_wait_done_obj, 1, esp32_rmt_wait_done);
|
||||
@ -195,45 +198,63 @@ STATIC mp_obj_t esp32_rmt_loop(mp_obj_t self_in, mp_obj_t loop) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp32_rmt_loop_obj, esp32_rmt_loop);
|
||||
|
||||
STATIC mp_obj_t esp32_rmt_write_pulses(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_self, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_pulses, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
|
||||
};
|
||||
STATIC mp_obj_t esp32_rmt_write_pulses(size_t n_args, const mp_obj_t *args) {
|
||||
esp32_rmt_obj_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||
mp_obj_t duration_obj = args[1];
|
||||
mp_obj_t data_obj = n_args > 2 ? args[2] : mp_const_true;
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
mp_uint_t duration = 0;
|
||||
size_t duration_length = 0;
|
||||
mp_obj_t *duration_ptr = NULL;
|
||||
mp_uint_t data = 0;
|
||||
size_t data_length = 0;
|
||||
mp_obj_t *data_ptr = NULL;
|
||||
mp_uint_t num_pulses = 0;
|
||||
|
||||
esp32_rmt_obj_t *self = MP_OBJ_TO_PTR(args[0].u_obj);
|
||||
mp_obj_t pulses = args[1].u_obj;
|
||||
mp_uint_t start = args[2].u_int;
|
||||
|
||||
if (start > 1) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("start must be 0 or 1"));
|
||||
if (!(mp_obj_is_type(data_obj, &mp_type_tuple) || mp_obj_is_type(data_obj, &mp_type_list))) {
|
||||
// Mode 1: array of durations, toggle initial data value
|
||||
mp_obj_get_array(duration_obj, &duration_length, &duration_ptr);
|
||||
data = mp_obj_is_true(data_obj);
|
||||
num_pulses = duration_length;
|
||||
} else if (mp_obj_is_int(duration_obj)) {
|
||||
// Mode 2: constant duration, array of data values
|
||||
duration = mp_obj_get_int(duration_obj);
|
||||
mp_obj_get_array(data_obj, &data_length, &data_ptr);
|
||||
num_pulses = data_length;
|
||||
} else {
|
||||
// Mode 3: arrays of durations and data values
|
||||
mp_obj_get_array(duration_obj, &duration_length, &duration_ptr);
|
||||
mp_obj_get_array(data_obj, &data_length, &data_ptr);
|
||||
if (duration_length != data_length) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("duration and data must have same length"));
|
||||
}
|
||||
num_pulses = duration_length;
|
||||
}
|
||||
|
||||
size_t pulses_length = 0;
|
||||
mp_obj_t *pulses_ptr = NULL;
|
||||
mp_obj_get_array(pulses, &pulses_length, &pulses_ptr);
|
||||
|
||||
mp_uint_t num_items = (pulses_length / 2) + (pulses_length % 2);
|
||||
if (self->loop_en && num_items > 63) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("too many pulses for loop"));
|
||||
if (num_pulses == 0) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("No pulses"));
|
||||
}
|
||||
if (self->loop_en && num_pulses > 126) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("Too many pulses for loop"));
|
||||
}
|
||||
|
||||
mp_uint_t num_items = (num_pulses / 2) + (num_pulses % 2);
|
||||
if (num_items > self->num_items) {
|
||||
self->items = (rmt_item32_t *)m_realloc(self->items, num_items * sizeof(rmt_item32_t *));
|
||||
self->num_items = num_items;
|
||||
}
|
||||
|
||||
for (mp_uint_t item_index = 0; item_index < num_items; item_index++) {
|
||||
mp_uint_t pulse_index = item_index * 2;
|
||||
self->items[item_index].duration0 = mp_obj_get_int(pulses_ptr[pulse_index++]);
|
||||
self->items[item_index].level0 = start++; // Note that start _could_ wrap.
|
||||
if (pulse_index < pulses_length) {
|
||||
self->items[item_index].duration1 = mp_obj_get_int(pulses_ptr[pulse_index]);
|
||||
self->items[item_index].level1 = start++;
|
||||
for (mp_uint_t item_index = 0, pulse_index = 0; item_index < num_items; item_index++) {
|
||||
self->items[item_index].duration0 = duration_length ? mp_obj_get_int(duration_ptr[pulse_index]) : duration;
|
||||
self->items[item_index].level0 = data_length ? mp_obj_is_true(data_ptr[pulse_index]) : data++;
|
||||
pulse_index++;
|
||||
if (pulse_index < num_pulses) {
|
||||
self->items[item_index].duration1 = duration_length ? mp_obj_get_int(duration_ptr[pulse_index]) : duration;
|
||||
self->items[item_index].level1 = data_length ? mp_obj_is_true(data_ptr[pulse_index]) : data++;
|
||||
pulse_index++;
|
||||
} else {
|
||||
self->items[item_index].duration1 = 0;
|
||||
self->items[item_index].level1 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -247,7 +268,7 @@ STATIC mp_obj_t esp32_rmt_write_pulses(size_t n_args, const mp_obj_t *pos_args,
|
||||
check_esp_err(rmt_wait_tx_done(self->channel_id, portMAX_DELAY));
|
||||
}
|
||||
|
||||
check_esp_err(rmt_write_items(self->channel_id, self->items, num_items, false /* non-blocking */));
|
||||
check_esp_err(rmt_write_items(self->channel_id, self->items, num_items, false));
|
||||
|
||||
if (self->loop_en) {
|
||||
check_esp_err(rmt_set_tx_intr_en(self->channel_id, false));
|
||||
@ -256,7 +277,7 @@ STATIC mp_obj_t esp32_rmt_write_pulses(size_t n_args, const mp_obj_t *pos_args,
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(esp32_rmt_write_pulses_obj, 2, esp32_rmt_write_pulses);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_rmt_write_pulses_obj, 2, 3, esp32_rmt_write_pulses);
|
||||
|
||||
STATIC const mp_rom_map_elem_t esp32_rmt_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&esp32_rmt_deinit_obj) },
|
||||
|
||||
@ -59,4 +59,7 @@ test: $(BUILD)/micropython.js $(TOP)/tests/run-tests.py
|
||||
$(eval DIRNAME=ports/$(notdir $(CURDIR)))
|
||||
cd $(TOP)/tests && MICROPY_MICROPYTHON=../ports/javascript/node_run.sh ./run-tests.py -j1
|
||||
|
||||
# Disable errors for array-bounds warnings on "sp[-MP_OBJ_ITER_BUF_NSLOTS + 2]" access.
|
||||
$(BUILD)/py/vm.o: CFLAGS += -Wno-error=array-bounds
|
||||
|
||||
include $(TOP)/py/mkrules.mk
|
||||
|
||||
@ -297,7 +297,7 @@ OBJ += $(BUILD)/pins_gen.o
|
||||
# Workaround for bug in older gcc, warning on "static usbd_device_t _usbd_dev = { 0 };"
|
||||
$(BUILD)/lib/tinyusb/src/device/usbd.o: CFLAGS += -Wno-missing-braces
|
||||
|
||||
all: $(BUILD)/firmware.hex
|
||||
all: $(BUILD)/firmware.hex $(BUILD)/firmware.bin
|
||||
|
||||
$(BUILD)/firmware.elf: $(OBJ)
|
||||
$(ECHO) "LINK $@"
|
||||
|
||||
@ -51,15 +51,19 @@
|
||||
/// val = adc.read_core_vref() # read MCU VREF
|
||||
|
||||
/* ADC defintions */
|
||||
|
||||
#if defined(STM32H7)
|
||||
#define ADCx (ADC3)
|
||||
#define PIN_ADC_MASK PIN_ADC3
|
||||
#define pin_adc_table pin_adc3
|
||||
#else
|
||||
#define ADCx (ADC1)
|
||||
#define PIN_ADC_MASK PIN_ADC1
|
||||
#define pin_adc_table pin_adc1
|
||||
|
||||
#if defined(STM32H7)
|
||||
// On the H7 ADC3 is used for ADCAll to be able to read internal
|
||||
// channels. For all other GPIO channels, ADC12 is used instead.
|
||||
#define ADCALLx (ADC3)
|
||||
#define pin_adcall_table pin_adc3
|
||||
#else
|
||||
// Use ADC1 for ADCAll instance by default for all other MCUs.
|
||||
#define ADCALLx (ADC1)
|
||||
#define pin_adcall_table pin_adc1
|
||||
#endif
|
||||
|
||||
#define ADCx_CLK_ENABLE __HAL_RCC_ADC1_CLK_ENABLE
|
||||
@ -142,7 +146,7 @@
|
||||
defined(STM32F746xx) || defined(STM32F765xx) || \
|
||||
defined(STM32F767xx) || defined(STM32F769xx)
|
||||
#define VBAT_DIV (4)
|
||||
#elif defined(STM32H743xx)
|
||||
#elif defined(STM32H743xx) || defined(STM32H747xx)
|
||||
#define VBAT_DIV (4)
|
||||
#elif defined(STM32L432xx) || \
|
||||
defined(STM32L451xx) || defined(STM32L452xx) || \
|
||||
@ -214,12 +218,12 @@ STATIC bool is_adcx_channel(int channel) {
|
||||
#endif
|
||||
}
|
||||
|
||||
STATIC void adc_wait_for_eoc_or_timeout(int32_t timeout) {
|
||||
STATIC void adc_wait_for_eoc_or_timeout(ADC_HandleTypeDef *adcHandle, int32_t timeout) {
|
||||
uint32_t tickstart = HAL_GetTick();
|
||||
#if defined(STM32F4) || defined(STM32F7)
|
||||
while ((ADCx->SR & ADC_FLAG_EOC) != ADC_FLAG_EOC) {
|
||||
while ((adcHandle->Instance->SR & ADC_FLAG_EOC) != ADC_FLAG_EOC) {
|
||||
#elif defined(STM32F0) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB)
|
||||
while (READ_BIT(ADCx->ISR, ADC_FLAG_EOC) != ADC_FLAG_EOC) {
|
||||
while (READ_BIT(adcHandle->Instance->ISR, ADC_FLAG_EOC) != ADC_FLAG_EOC) {
|
||||
#else
|
||||
#error Unsupported processor
|
||||
#endif
|
||||
@ -229,11 +233,15 @@ STATIC void adc_wait_for_eoc_or_timeout(int32_t timeout) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void adcx_clock_enable(void) {
|
||||
STATIC void adcx_clock_enable(ADC_HandleTypeDef *adch) {
|
||||
#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7)
|
||||
ADCx_CLK_ENABLE();
|
||||
#elif defined(STM32H7)
|
||||
__HAL_RCC_ADC3_CLK_ENABLE();
|
||||
if (adch->Instance == ADC3) {
|
||||
__HAL_RCC_ADC3_CLK_ENABLE();
|
||||
} else {
|
||||
__HAL_RCC_ADC12_CLK_ENABLE();
|
||||
}
|
||||
__HAL_RCC_ADC_CONFIG(RCC_ADCCLKSOURCE_CLKP);
|
||||
#elif defined(STM32L4) || defined(STM32WB)
|
||||
if (__HAL_RCC_GET_ADC_SOURCE() == RCC_ADCCLKSOURCE_NONE) {
|
||||
@ -246,9 +254,8 @@ STATIC void adcx_clock_enable(void) {
|
||||
}
|
||||
|
||||
STATIC void adcx_init_periph(ADC_HandleTypeDef *adch, uint32_t resolution) {
|
||||
adcx_clock_enable();
|
||||
adcx_clock_enable(adch);
|
||||
|
||||
adch->Instance = ADCx;
|
||||
adch->Init.Resolution = resolution;
|
||||
adch->Init.ContinuousConvMode = DISABLE;
|
||||
adch->Init.DiscontinuousConvMode = DISABLE;
|
||||
@ -308,6 +315,7 @@ STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) {
|
||||
mp_hal_pin_config(pin, MP_HAL_PIN_MODE_ADC, MP_HAL_PIN_PULL_NONE, 0);
|
||||
}
|
||||
|
||||
adc_obj->handle.Instance = ADCx;
|
||||
adcx_init_periph(&adc_obj->handle, ADC_RESOLUTION_12B);
|
||||
|
||||
#if defined(STM32L4) && defined(ADC_DUALMODE_REGSIMULT_INJECSIMULT)
|
||||
@ -335,7 +343,11 @@ STATIC void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel)
|
||||
#if defined(STM32F0)
|
||||
sConfig.SamplingTime = ADC_SAMPLETIME_55CYCLES_5;
|
||||
#elif defined(STM32F4) || defined(STM32F7)
|
||||
sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
|
||||
if (__HAL_ADC_IS_CHANNEL_INTERNAL(channel)) {
|
||||
sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
|
||||
} else {
|
||||
sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
|
||||
}
|
||||
#elif defined(STM32H7)
|
||||
if (__HAL_ADC_IS_CHANNEL_INTERNAL(channel)) {
|
||||
sConfig.SamplingTime = ADC_SAMPLETIME_810CYCLES_5;
|
||||
@ -370,8 +382,8 @@ STATIC void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel)
|
||||
|
||||
STATIC uint32_t adc_read_channel(ADC_HandleTypeDef *adcHandle) {
|
||||
HAL_ADC_Start(adcHandle);
|
||||
adc_wait_for_eoc_or_timeout(EOC_TIMEOUT);
|
||||
uint32_t value = ADCx->DR;
|
||||
adc_wait_for_eoc_or_timeout(adcHandle, EOC_TIMEOUT);
|
||||
uint32_t value = adcHandle->Instance->DR;
|
||||
HAL_ADC_Stop(adcHandle);
|
||||
return value;
|
||||
}
|
||||
@ -529,19 +541,19 @@ STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_
|
||||
} else {
|
||||
// for subsequent samples we can just set the "start sample" bit
|
||||
#if defined(STM32F4) || defined(STM32F7)
|
||||
ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART;
|
||||
self->handle.Instance->CR2 |= (uint32_t)ADC_CR2_SWSTART;
|
||||
#elif defined(STM32F0) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB)
|
||||
SET_BIT(ADCx->CR, ADC_CR_ADSTART);
|
||||
SET_BIT(self->handle.Instance->CR, ADC_CR_ADSTART);
|
||||
#else
|
||||
#error Unsupported processor
|
||||
#endif
|
||||
}
|
||||
|
||||
// wait for sample to complete
|
||||
adc_wait_for_eoc_or_timeout(EOC_TIMEOUT);
|
||||
adc_wait_for_eoc_or_timeout(&self->handle, EOC_TIMEOUT);
|
||||
|
||||
// read value
|
||||
uint value = ADCx->DR;
|
||||
uint value = self->handle.Instance->DR;
|
||||
|
||||
// store value in buffer
|
||||
if (typesize == 1) {
|
||||
@ -608,9 +620,9 @@ STATIC mp_obj_t adc_read_timed_multi(mp_obj_t adc_array_in, mp_obj_t buf_array_i
|
||||
adc_config_channel(&adc0->handle, adc0->channel);
|
||||
HAL_ADC_Start(&adc0->handle);
|
||||
// Wait for sample to complete and discard
|
||||
adc_wait_for_eoc_or_timeout(EOC_TIMEOUT);
|
||||
adc_wait_for_eoc_or_timeout(&adc0->handle, EOC_TIMEOUT);
|
||||
// Read (and discard) value
|
||||
uint value = ADCx->DR;
|
||||
uint value = adc0->handle.Instance->DR;
|
||||
|
||||
// Ensure first sample is on a timer tick
|
||||
__HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE);
|
||||
@ -639,17 +651,17 @@ STATIC mp_obj_t adc_read_timed_multi(mp_obj_t adc_array_in, mp_obj_t buf_array_i
|
||||
// for the first sample we need to turn the ADC on
|
||||
// ADC is started: set the "start sample" bit
|
||||
#if defined(STM32F4) || defined(STM32F7)
|
||||
ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART;
|
||||
adc->handle.Instance->CR2 |= (uint32_t)ADC_CR2_SWSTART;
|
||||
#elif defined(STM32F0) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB)
|
||||
SET_BIT(ADCx->CR, ADC_CR_ADSTART);
|
||||
SET_BIT(adc->handle.Instance->CR, ADC_CR_ADSTART);
|
||||
#else
|
||||
#error Unsupported processor
|
||||
#endif
|
||||
// wait for sample to complete
|
||||
adc_wait_for_eoc_or_timeout(EOC_TIMEOUT);
|
||||
adc_wait_for_eoc_or_timeout(&adc->handle, EOC_TIMEOUT);
|
||||
|
||||
// read value
|
||||
value = ADCx->DR;
|
||||
value = adc->handle.Instance->DR;
|
||||
|
||||
// store values in buffer
|
||||
if (typesize == 1) {
|
||||
@ -723,13 +735,14 @@ void adc_init_all(pyb_adc_all_obj_t *adc_all, uint32_t resolution, uint32_t en_m
|
||||
if (en_mask & (1 << channel)) {
|
||||
// Channels 0-16 correspond to real pins. Configure the GPIO pin in
|
||||
// ADC mode.
|
||||
const pin_obj_t *pin = pin_adc_table[channel];
|
||||
const pin_obj_t *pin = pin_adcall_table[channel];
|
||||
if (pin) {
|
||||
mp_hal_pin_config(pin, MP_HAL_PIN_MODE_ADC, MP_HAL_PIN_PULL_NONE, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
adc_all->handle.Instance = ADCALLx;
|
||||
adcx_init_periph(&adc_all->handle, resolution);
|
||||
}
|
||||
|
||||
|
||||
@ -155,6 +155,8 @@ int boardctrl_run_boot_py(boardctrl_state_t *state) {
|
||||
return BOARDCTRL_GOTO_SOFT_RESET_EXIT;
|
||||
}
|
||||
if (!ret) {
|
||||
// There was an error, prevent main.py from running and flash LEDs.
|
||||
state->reset_mode = BOARDCTRL_RESET_MODE_SAFE_MODE;
|
||||
flash_error(4);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1120,6 +1120,36 @@ void dma_nohal_init(const dma_descr_t *descr, uint32_t config) {
|
||||
init->FIFOMode // DMDIS
|
||||
| init->FIFOThreshold // FTH
|
||||
;
|
||||
|
||||
#if defined(STM32H7)
|
||||
// Configure DMAMUX
|
||||
uint32_t request = descr->sub_instance & DMAMUX_CxCR_DMAREQ_ID;
|
||||
if ((dma >= DMA1_Stream0 && dma <= DMA1_Stream7) || (dma >= DMA2_Stream0 && dma <= DMA2_Stream7)) {
|
||||
// DMA1/2 channels 0 to 7 are hardwired to DMAMUX1 channels 0-15.
|
||||
uint32_t stream = (((uint32_t)dma & 0xff) - 16) / 24 + ((dma >= DMA2_Stream0) ? 8 : 0);
|
||||
// Set DMAMUX channel peripheral request.
|
||||
((DMAMUX_Channel_TypeDef *)(((uint32_t)DMAMUX1_Channel0) + (stream * 4)))->CCR = request;
|
||||
DMAMUX1_ChannelStatus->CFR = 1 << (stream & 0x1F);
|
||||
// Configure DMAMUX request generator if needed.
|
||||
if (request >= DMA_REQUEST_GENERATOR0 && request <= DMA_REQUEST_GENERATOR7) {
|
||||
((DMAMUX_RequestGen_TypeDef *)(((uint32_t)DMAMUX1_RequestGenerator0) + ((request - 1) * 4)))->RGCR = 0;
|
||||
DMAMUX1_RequestGenStatus->RGCFR = 1 << (request - 1);
|
||||
}
|
||||
#if ENABLE_BDMA // TODO: BDMA is Not currently supported by this driver.
|
||||
} else if (dma >= BDMA_Channel0 && dma <= BDMA_Channel7) {
|
||||
// BDMA channels 0 to 7 are hardwired to DMAMUX2 channels 0-7.
|
||||
uint32_t stream = (((uint32_t)dma & 0xff) - 8) / 20;
|
||||
// Set DMAMUX channel peripheral request.
|
||||
((DMAMUX_Channel_TypeDef *)(((uint32_t)DMAMUX2_Channel0) + (stream * 4)))->CCR = request;
|
||||
DMAMUX2_ChannelStatus->CFR = 1 << (stream & 0x1F);
|
||||
// Configure DMAMUX request generator if needed.
|
||||
if (request >= DMA_REQUEST_GENERATOR0 && request <= DMA_REQUEST_GENERATOR7) {
|
||||
((DMAMUX_RequestGen_TypeDef *)(((uint32_t)DMAMUX2_RequestGenerator0) + ((request - 1) * 4)))->RGCR = 0;
|
||||
DMAMUX2_RequestGenStatus->RGCFR = 1 << (request - 1);
|
||||
}
|
||||
#endif // ENABLE_BDMA
|
||||
}
|
||||
#endif // STM32H7
|
||||
}
|
||||
|
||||
void dma_nohal_deinit(const dma_descr_t *descr) {
|
||||
|
||||
@ -662,6 +662,7 @@ soft_reset_exit:
|
||||
MICROPY_BOARD_END_SOFT_RESET(&state);
|
||||
|
||||
gc_sweep_all();
|
||||
mp_deinit();
|
||||
|
||||
goto soft_reset;
|
||||
}
|
||||
|
||||
@ -451,9 +451,11 @@ int sdio_transfer_cmd53(bool write, uint32_t block_size, uint32_t arg, size_t le
|
||||
#else
|
||||
printf("sdio_transfer_cmd53: timeout wr=%d len=%u dma=%u buf_idx=%u STA=%08x SDMMC=%08x:%08x IDMA=%08x\n", write, (uint)len, (uint)dma, sdmmc_buf_cur - buf, (uint)SDMMC->STA, (uint)SDMMC->DCOUNT, (uint)SDMMC->DCTRL, (uint)SDMMC->IDMACTRL);
|
||||
#endif
|
||||
#if defined(STM32F7)
|
||||
if (sdmmc_dma) {
|
||||
dma_nohal_deinit(&dma_SDIO_0);
|
||||
}
|
||||
#endif
|
||||
return -MP_ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
@ -466,9 +468,11 @@ int sdio_transfer_cmd53(bool write, uint32_t block_size, uint32_t arg, size_t le
|
||||
#else
|
||||
printf("sdio_transfer_cmd53: error=%08lx wr=%d len=%u dma=%u buf_idx=%u STA=%08x SDMMC=%08x:%08x IDMA=%08x\n", sdmmc_error, write, (uint)len, (uint)dma, sdmmc_buf_cur - buf, (uint)SDMMC->STA, (uint)SDMMC->DCOUNT, (uint)SDMMC->DCTRL, (uint)SDMMC->IDMACTRL);
|
||||
#endif
|
||||
#if defined(STM32F7)
|
||||
if (sdmmc_dma) {
|
||||
dma_nohal_deinit(&dma_SDIO_0);
|
||||
}
|
||||
#endif
|
||||
return -(0x1000000 | sdmmc_error);
|
||||
}
|
||||
|
||||
@ -478,7 +482,9 @@ int sdio_transfer_cmd53(bool write, uint32_t block_size, uint32_t arg, size_t le
|
||||
return -MP_EIO;
|
||||
}
|
||||
} else {
|
||||
#if defined(STM32F7)
|
||||
dma_nohal_deinit(&dma_SDIO_0);
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@ -139,7 +139,7 @@ $(HEADER_BUILD):
|
||||
ifneq ($(FROZEN_MANIFEST),)
|
||||
# to build frozen_content.c from a manifest
|
||||
$(BUILD)/frozen_content.c: FORCE $(BUILD)/genhdr/qstrdefs.generated.h
|
||||
$(Q)$(MAKE_MANIFEST) -o $@ -v "MPY_DIR=$(TOP)" -v "MPY_LIB_DIR=$(MPY_LIB_DIR)" -v "PORT_DIR=$(shell pwd)" -v "BOARD_DIR=$(BOARD_DIR)" -b "$(BUILD)" $(if $(MPY_CROSS_FLAGS),-f"$(MPY_CROSS_FLAGS)",) $(FROZEN_MANIFEST)
|
||||
$(Q)$(MAKE_MANIFEST) -o $@ -v "MPY_DIR=$(TOP)" -v "MPY_LIB_DIR=$(MPY_LIB_DIR)" -v "PORT_DIR=$(shell pwd)" -v "BOARD_DIR=$(BOARD_DIR)" -b "$(BUILD)" $(if $(MPY_CROSS_FLAGS),-f"$(MPY_CROSS_FLAGS)",) --mpy-tool-flags="$(MPY_TOOL_FLAGS)" $(FROZEN_MANIFEST)
|
||||
|
||||
ifneq ($(FROZEN_DIR),)
|
||||
$(error FROZEN_DIR cannot be used in conjunction with FROZEN_MANIFEST)
|
||||
|
||||
@ -163,17 +163,24 @@ void mp_obj_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kin
|
||||
if (o->args == NULL || o->args->len == 0) {
|
||||
mp_print_str(print, "");
|
||||
return;
|
||||
} else if (o->args->len == 1) {
|
||||
#if MICROPY_PY_UERRNO
|
||||
// try to provide a nice OSError error message
|
||||
if (o->base.type == &mp_type_OSError && mp_obj_is_small_int(o->args->items[0])) {
|
||||
qstr qst = mp_errno_to_str(o->args->items[0]);
|
||||
if (qst != MP_QSTRnull) {
|
||||
mp_printf(print, "[Errno " INT_FMT "] %q", MP_OBJ_SMALL_INT_VALUE(o->args->items[0]), qst);
|
||||
return;
|
||||
}
|
||||
|
||||
#if MICROPY_PY_UERRNO
|
||||
// try to provide a nice OSError error message
|
||||
if (o->base.type == &mp_type_OSError && o->args->len > 0 && o->args->len < 3 && mp_obj_is_small_int(o->args->items[0])) {
|
||||
qstr qst = mp_errno_to_str(o->args->items[0]);
|
||||
if (qst != MP_QSTRnull) {
|
||||
mp_printf(print, "[Errno " INT_FMT "] %q", MP_OBJ_SMALL_INT_VALUE(o->args->items[0]), qst);
|
||||
if (o->args->len > 1) {
|
||||
mp_print_str(print, ": ");
|
||||
mp_obj_print_helper(print, o->args->items[1], PRINT_STR);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
if (o->args->len == 1) {
|
||||
mp_obj_print_helper(print, o->args->items[0], PRINT_STR);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -12,6 +12,10 @@ print(type(uerrno.EIO))
|
||||
# check that errors are rendered in a nice way
|
||||
msg = str(OSError(uerrno.EIO))
|
||||
print(msg[:7], msg[-5:])
|
||||
msg = str(OSError(uerrno.EIO, "details"))
|
||||
print(msg[:7], msg[-14:])
|
||||
msg = str(OSError(uerrno.EIO, "details", "more details"))
|
||||
print(msg[:1], msg[-28:])
|
||||
|
||||
# check that unknown errno is still rendered
|
||||
print(str(OSError(9999)))
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
<class 'int'>
|
||||
[Errno ] EIO
|
||||
[Errno ] EIO: details
|
||||
( , 'details', 'more details')
|
||||
9999
|
||||
uerrno
|
||||
|
||||
@ -66,6 +66,8 @@ cd ../esp32
|
||||
${AUTODIR}/build-esp32-latest.sh ${IDF_PATH_V4} ${FW_TAG} ${LOCAL_FIRMWARE}
|
||||
cd ../rp2
|
||||
${AUTODIR}/build-rp2-latest.sh ${FW_TAG} ${LOCAL_FIRMWARE}
|
||||
cd ../mimxrt
|
||||
${AUTODIR}/build-mimxrt-latest.sh ${FW_TAG} ${LOCAL_FIRMWARE}
|
||||
|
||||
popd
|
||||
|
||||
|
||||
36
tools/autobuild/build-mimxrt-latest.sh
Executable file
36
tools/autobuild/build-mimxrt-latest.sh
Executable file
@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
|
||||
# function for building firmware
|
||||
function do_build() {
|
||||
descr=$1
|
||||
board=$2
|
||||
ext=$3
|
||||
shift
|
||||
shift
|
||||
shift
|
||||
echo "building $descr $board"
|
||||
build_dir=/tmp/mimxrt-build-$board
|
||||
$MICROPY_AUTOBUILD_MAKE $@ BOARD=$board BUILD=$build_dir || exit 1
|
||||
mv $build_dir/firmware.$ext $dest_dir/$descr$fw_tag.$ext
|
||||
rm -rf $build_dir
|
||||
}
|
||||
|
||||
# check/get parameters
|
||||
if [ $# != 2 ]; then
|
||||
echo "usage: $0 <fw-tag> <dest-dir>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
fw_tag=$1
|
||||
dest_dir=$2
|
||||
|
||||
# check we are in the correct directory
|
||||
if [ ! -r modmimxrt.c ]; then
|
||||
echo "must be in mimxrt directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# build the boards
|
||||
do_build TEENSY40 TEENSY40 hex
|
||||
do_build TEENSY41 TEENSY41 hex
|
||||
do_build MIMXRT1020_EVK MIMXRT1020_EVK bin
|
||||
@ -248,6 +248,7 @@ def main():
|
||||
"-f", "--mpy-cross-flags", default="", help="flags to pass to mpy-cross"
|
||||
)
|
||||
cmd_parser.add_argument("-v", "--var", action="append", help="variables to substitute")
|
||||
cmd_parser.add_argument("--mpy-tool-flags", default="", help="flags to pass to mpy-tool")
|
||||
cmd_parser.add_argument("files", nargs="+", help="input manifest list")
|
||||
args = cmd_parser.parse_args()
|
||||
|
||||
@ -341,6 +342,7 @@ def main():
|
||||
"-q",
|
||||
args.build_dir + "/genhdr/qstrdefs.preprocessed.h",
|
||||
]
|
||||
+ args.mpy_tool_flags.split()
|
||||
+ mpy_files
|
||||
)
|
||||
if res != 0:
|
||||
|
||||
@ -166,7 +166,7 @@ def do_connect(args):
|
||||
for p in sorted(serial.tools.list_ports.comports()):
|
||||
print(
|
||||
"{} {} {:04x}:{:04x} {} {}".format(
|
||||
p.device, p.serial_number, p.pid, p.vid, p.manufacturer, p.product
|
||||
p.device, p.serial_number, p.vid, p.pid, p.manufacturer, p.product
|
||||
)
|
||||
)
|
||||
return None
|
||||
|
||||
@ -656,6 +656,12 @@ def main():
|
||||
help="seconds to wait for USB connected board to become available",
|
||||
)
|
||||
group = cmd_parser.add_mutually_exclusive_group()
|
||||
group.add_argument(
|
||||
"--soft-reset",
|
||||
default=True,
|
||||
action=argparse.BooleanOptionalAction,
|
||||
help="Whether to perform a soft reset when connecting to the board.",
|
||||
)
|
||||
group.add_argument(
|
||||
"--follow",
|
||||
action="store_true",
|
||||
@ -695,7 +701,7 @@ def main():
|
||||
# we must enter raw-REPL mode to execute commands
|
||||
# this will do a soft-reset of the board
|
||||
try:
|
||||
pyb.enter_raw_repl()
|
||||
pyb.enter_raw_repl(args.soft_reset)
|
||||
except PyboardError as er:
|
||||
print(er)
|
||||
pyb.close()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user