Merge remote-tracking branch 'upstream/master' into upstream/sync-1.16

This commit is contained in:
Themba Dube 2021-07-02 18:26:56 -04:00
commit e82d582dc9
18 changed files with 282 additions and 138 deletions

View File

@ -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

View File

@ -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) },

View File

@ -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

View File

@ -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 $@"

View File

@ -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)
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)
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);
}

View File

@ -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);
}
}

View File

@ -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) {

View File

@ -662,6 +662,7 @@ soft_reset_exit:
MICROPY_BOARD_END_SOFT_RESET(&state);
gc_sweep_all();
mp_deinit();
goto soft_reset;
}

View File

@ -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;

View File

@ -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)

View File

@ -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])) {
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
if (o->args->len == 1) {
mp_obj_print_helper(print, o->args->items[0], PRINT_STR);
return;
}

View File

@ -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)))

View File

@ -1,4 +1,6 @@
<class 'int'>
[Errno ] EIO
[Errno ] EIO: details
( , 'details', 'more details')
9999
uerrno

View File

@ -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

View 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

View File

@ -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:

View File

@ -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

View File

@ -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()