From 23112a6434261375e0d57308ddb06db1227d4b14 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 1 Nov 2016 11:04:49 -0700 Subject: [PATCH] atmel-samd: Merge init into the constructor and check all available SERCOMs during initialization. Fixes #16. It was broken because the MISO pin used the second SERCOM. --- atmel-samd/common-hal/modules/machine.c | 110 +++++++++++++----- atmel-samd/common-hal/modules/machine_types.h | 4 +- atmel-samd/modmachine_pin.h | 3 +- shared-bindings/modules/machine.c | 55 ++++----- 4 files changed, 111 insertions(+), 61 deletions(-) diff --git a/atmel-samd/common-hal/modules/machine.c b/atmel-samd/common-hal/modules/machine.c index b0558cd5ce..70ca0a67a2 100644 --- a/atmel-samd/common-hal/modules/machine.c +++ b/atmel-samd/common-hal/modules/machine.c @@ -32,6 +32,8 @@ #include "asf/sam0/drivers/sercom/i2c/i2c_master.h" +// We use ENABLE registers below we don't want to treat as a macro. +#undef ENABLE // Number of times to try to send packet if failed. #define TIMEOUT 1 @@ -42,33 +44,44 @@ void mp_hal_i2c_construct(machine_i2c_obj_t *self, const pin_obj_t* scl, i2c_master_get_config_defaults(&config_i2c_master); // Struct takes the argument in Khz not Hz. config_i2c_master.baud_rate = freq / 1000; - // TODO(tannewt): Utilize the secondary sercom if the first is already being - // used. - if (sda->primary_sercom.sercom == 0 || sda->primary_sercom.pad != 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, - "SDA pin must be on SERCOM pad 0")); + Sercom* sercom = NULL; + uint32_t sda_pinmux = 0; + uint32_t scl_pinmux = 0; + for (int i = 0; i < NUM_SERCOMS_PER_PIN; i++) { + Sercom* potential_sercom = sda->sercom[i].sercom; + if (potential_sercom == NULL || + potential_sercom->I2CM.CTRLA.bit.ENABLE != 0 || + sda->sercom[i].pad != 0) { + continue; + } + sda_pinmux = sda->sercom[i].pinmux; + for (int j = 0; j < NUM_SERCOMS_PER_PIN; j++) { + if (potential_sercom == scl->sercom[j].sercom && + scl->sercom[j].pad == 1) { + scl_pinmux = scl->sercom[j].pinmux; + sercom = potential_sercom; + break; + } + } + if (sercom != NULL) { + break; + } } - if (scl->primary_sercom.sercom == 0 || scl->primary_sercom.pad != 1) { + if (sercom == NULL) { nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, - "SCL pin must be on SERCOM pad 1")); + "No hardware support available with those pins.")); } - if (sda->primary_sercom.sercom != scl->primary_sercom.sercom) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, - "SDA and SCL pins must share a SERCOM")); - } - config_i2c_master.pinmux_pad0 = sda->primary_sercom.pinmux; // SDA - config_i2c_master.pinmux_pad1 = scl->primary_sercom.pinmux; // SCL + + config_i2c_master.pinmux_pad0 = sda_pinmux; // SDA + config_i2c_master.pinmux_pad1 = scl_pinmux; // SCL config_i2c_master.buffer_timeout = 10000; enum status_code status = i2c_master_init(&self->i2c_master_instance, - sda->primary_sercom.sercom, &config_i2c_master); + sercom, &config_i2c_master); if (status != STATUS_OK) { nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "I2C bus init error")); } -} - -void mp_hal_i2c_init(machine_i2c_obj_t *self) { i2c_master_enable(&self->i2c_master_instance); } @@ -212,18 +225,57 @@ void mp_hal_spi_construct(machine_spi_obj_t *self, const pin_obj_t * clock, struct spi_config config_spi_master; spi_get_config_defaults(&config_spi_master); + Sercom* sercom = NULL; + uint32_t clock_pinmux = 0; + uint32_t mosi_pinmux = 0; + uint32_t miso_pinmux = 0; + uint8_t clock_pad = 0; + uint8_t mosi_pad = 0; + uint8_t miso_pad = 0; + for (int i = 0; i < NUM_SERCOMS_PER_PIN; i++) { + Sercom* potential_sercom = clock->sercom[i].sercom; + if (potential_sercom == NULL || + potential_sercom->SPI.CTRLA.bit.ENABLE != 0) { + continue; + } + clock_pinmux = clock->sercom[i].pinmux; + clock_pad = clock->sercom[i].pad; + for (int j = 0; j < NUM_SERCOMS_PER_PIN; j++) { + mosi_pinmux = mosi->sercom[j].pinmux; + mosi_pad = mosi->sercom[j].pad; + for (int k = 0; k < NUM_SERCOMS_PER_PIN; k++) { + if (potential_sercom == miso->sercom[k].sercom) { + miso_pinmux = miso->sercom[k].pinmux; + miso_pad = miso->sercom[k].pad; + sercom = potential_sercom; + break; + } + } + if (sercom != NULL) { + break; + } + } + if (sercom != NULL) { + break; + } + } + if (sercom == NULL) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, + "No hardware support available with those pins.")); + } + // Depends on where MOSI and CLK are. uint8_t dopo = 8; - if (clock->primary_sercom.pad == 1) { - if (mosi->primary_sercom.pad == 0) { + if (clock_pad == 1) { + if (mosi_pad == 0) { dopo = 0; - } else if (mosi->primary_sercom.pad == 3) { + } else if (mosi_pad == 3) { dopo = 2; } - } else if (clock->primary_sercom.pad == 3) { - if (mosi->primary_sercom.pad == 0) { + } else if (clock_pad == 3) { + if (mosi_pad == 0) { dopo = 3; - } else if (mosi->primary_sercom.pad == 2) { + } else if (mosi_pad == 2) { dopo = 1; } } @@ -232,23 +284,21 @@ void mp_hal_spi_construct(machine_spi_obj_t *self, const pin_obj_t * clock, } config_spi_master.mux_setting = (dopo << SERCOM_SPI_CTRLA_DOPO_Pos) | - (miso->primary_sercom.pad << SERCOM_SPI_CTRLA_DIPO_Pos); + (miso_pad << SERCOM_SPI_CTRLA_DIPO_Pos); // Map pad to pinmux through a short array. uint32_t *pinmuxes[4] = {&config_spi_master.pinmux_pad0, &config_spi_master.pinmux_pad1, &config_spi_master.pinmux_pad2, &config_spi_master.pinmux_pad3}; - *pinmuxes[clock->primary_sercom.pad] = clock->primary_sercom.pinmux; - *pinmuxes[mosi->primary_sercom.pad] = mosi->primary_sercom.pinmux; - *pinmuxes[miso->primary_sercom.pad] = miso->primary_sercom.pinmux; + *pinmuxes[clock_pad] = clock_pinmux; + *pinmuxes[mosi_pad] = mosi_pinmux; + *pinmuxes[miso_pad] = miso_pinmux; config_spi_master.mode_specific.master.baudrate = baudrate; - spi_init(&self->spi_master_instance, mosi->primary_sercom.sercom, &config_spi_master); -} + spi_init(&self->spi_master_instance, sercom, &config_spi_master); -void mp_hal_spi_init(machine_spi_obj_t *self) { spi_enable(&self->spi_master_instance); } diff --git a/atmel-samd/common-hal/modules/machine_types.h b/atmel-samd/common-hal/modules/machine_types.h index 2267115d33..73150640f0 100644 --- a/atmel-samd/common-hal/modules/machine_types.h +++ b/atmel-samd/common-hal/modules/machine_types.h @@ -61,6 +61,7 @@ typedef struct { uint32_t mux; } pin_timer_t; +#define NUM_SERCOMS_PER_PIN 2 typedef struct { mp_obj_base_t base; qstr name; @@ -69,8 +70,7 @@ typedef struct { enum adc_positive_input adc_input; pin_timer_t primary_timer; pin_timer_t secondary_timer; - pin_sercom_t primary_sercom; - pin_sercom_t secondary_sercom; + pin_sercom_t sercom[NUM_SERCOMS_PER_PIN]; } pin_obj_t; typedef struct _machine_i2c_obj_t { diff --git a/atmel-samd/modmachine_pin.h b/atmel-samd/modmachine_pin.h index 820a792466..7707921a60 100644 --- a/atmel-samd/modmachine_pin.h +++ b/atmel-samd/modmachine_pin.h @@ -68,8 +68,7 @@ const pin_obj_t pin_## p_name = { \ .adc_input = p_adc_input, \ .primary_timer = p_primary_timer, \ .secondary_timer = p_secondary_timer, \ - .primary_sercom = p_primary_sercom, \ - .secondary_sercom = p_secondary_sercom \ + .sercom = {p_primary_sercom, p_secondary_sercom}, \ } #define NO_ADC_INPUT (0) diff --git a/shared-bindings/modules/machine.c b/shared-bindings/modules/machine.c index e58eda62bb..49c8b00aa7 100644 --- a/shared-bindings/modules/machine.c +++ b/shared-bindings/modules/machine.c @@ -31,7 +31,6 @@ #include "machine.h" - #include "py/runtime.h" //| :mod:`machine` --- functions related to the board @@ -82,17 +81,6 @@ STATIC mp_obj_t machine_i2c_make_new(const mp_obj_type_t *type, size_t n_args, s return (mp_obj_t)self; } -//| .. method:: I2C.init() -//| -//| Initializes control of the underlying hardware so other classes cannot -//| use it. -//| -STATIC mp_obj_t machine_i2c_obj_init(mp_obj_t self_in) { - machine_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_hal_i2c_init(self); - return self_in; -} -MP_DEFINE_CONST_FUN_OBJ_1(machine_i2c_init_obj, machine_i2c_obj_init); //| .. method:: I2C.deinit() //| @@ -105,6 +93,19 @@ STATIC mp_obj_t machine_i2c_obj_deinit(mp_obj_t self_in) { } MP_DEFINE_CONST_FUN_OBJ_1(machine_i2c_deinit_obj, machine_i2c_obj_deinit); +//| .. method:: I2C.__enter__() +//| +//| No-op used in Context Managers. +//| +STATIC mp_obj_t machine_i2c_obj___enter__(mp_obj_t self_in) { + return self_in; +} +MP_DEFINE_CONST_FUN_OBJ_1(machine_i2c___enter___obj, machine_i2c_obj___enter__); + +//| .. method:: I2C.__exit__() +//| +//| Automatically deinitializes the hardware on context exit. +//| STATIC mp_obj_t machine_i2c_obj___exit__(size_t n_args, const mp_obj_t *args) { (void)n_args; mp_hal_i2c_deinit(args[0]); @@ -268,9 +269,8 @@ STATIC mp_obj_t machine_i2c_writeto_mem(size_t n_args, const mp_obj_t *pos_args, STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_i2c_writeto_mem_obj, 1, machine_i2c_writeto_mem); STATIC const mp_rom_map_elem_t machine_i2c_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_i2c_init_obj) }, { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_i2c_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&machine_i2c_init_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&machine_i2c___enter___obj) }, { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&machine_i2c_obj___exit___obj) }, { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&machine_i2c_scan_obj) }, @@ -348,17 +348,6 @@ STATIC mp_obj_t machine_spi_make_new(const mp_obj_type_t *type, size_t n_args, s return (mp_obj_t)self; } -//| .. method:: SPI.init() -//| -//| Initialises the bus. -//| -STATIC mp_obj_t machine_spi_obj_init(mp_obj_t self_in) { - machine_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_hal_spi_init(self); - return self_in; -} -MP_DEFINE_CONST_FUN_OBJ_1(machine_spi_init_obj, machine_spi_obj_init); - //| .. method:: SPI.deinit() //| //| Turn off the SPI bus. @@ -370,6 +359,19 @@ STATIC mp_obj_t machine_spi_obj_deinit(mp_obj_t self_in) { } MP_DEFINE_CONST_FUN_OBJ_1(machine_spi_deinit_obj, machine_spi_obj_deinit); +//| .. method:: SPI.__enter__() +//| +//| No-op used by Context Managers. +//| +STATIC mp_obj_t machine_spi_obj___enter__(mp_obj_t self_in) { + return self_in; +} +MP_DEFINE_CONST_FUN_OBJ_1(machine_spi___enter___obj, machine_spi_obj___enter__); + +//| .. method:: SPI.__enter__() +//| +//| Automatically deinitializes the hardware when exiting a context. +//| STATIC mp_obj_t machine_spi_obj___exit__(size_t n_args, const mp_obj_t *args) { (void)n_args; mp_hal_spi_deinit(args[0]); @@ -441,9 +443,8 @@ STATIC mp_obj_t mp_machine_spi_readinto(size_t n_args, const mp_obj_t *args) { MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_readinto_obj, 2, 3, mp_machine_spi_readinto); STATIC const mp_rom_map_elem_t machine_spi_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_spi_init_obj) }, { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_spi_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&machine_spi_init_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&machine_spi___enter___obj) }, { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&machine_spi_obj___exit___obj) }, // Standard simultaneous read/write transfer.