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:
Scott Shawcroft 2016-11-01 11:04:49 -07:00
parent 674f3d46e8
commit 23112a6434
4 changed files with 111 additions and 61 deletions

View File

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

View File

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

View File

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

View File

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