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.
This commit is contained in:
parent
674f3d46e8
commit
23112a6434
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue