Add try_lock and unlock to I2C and SPI classes to make sure things

are shared well between threads and underlying MicroPython (SPI Flash
for example.)

It is recommended to use the bus device classes to manage the locks
and other transaction state.

https://github.com/adafruit/Adafruit_MicroPython_BusDevice

Fixed #58
Fixed #59
Fixed #60
This commit is contained in:
Scott Shawcroft 2016-11-30 15:08:34 -08:00
parent 03f49f8209
commit 26229efe78
23 changed files with 657 additions and 154 deletions

View File

@ -32,6 +32,21 @@ void common_hal_mcu_delay_us(uint32_t delay) {
mp_hal_delay_us(delay);
}
// Interrupt flags that will be saved and restored during disable/Enable
// interrupt functions below.
static irqflags_t irq_flags;
void common_hal_mcu_disable_interrupts(void) {
// Disable all interrupt sources for timing critical sections.
// Disable ASF-based interrupts.
irq_flags = cpu_irq_save();
}
void common_hal_mcu_enable_interrupts(void) {
// Enable all interrupt sources after timing critical sections.
// Restore ASF-based interrupts.
cpu_irq_restore(irq_flags);
}
// This maps MCU pin names to pin objects.
STATIC const mp_map_elem_t mcu_pin_global_dict_table[] = {
// Pins in datasheet order.

View File

@ -40,11 +40,11 @@
#define TIMEOUT 1
void common_hal_nativeio_i2c_construct(nativeio_i2c_obj_t *self,
const mcu_pin_obj_t* scl, const mcu_pin_obj_t* sda, uint32_t freq) {
const mcu_pin_obj_t* scl, const mcu_pin_obj_t* sda, uint32_t frequency) {
struct i2c_master_config config_i2c_master;
i2c_master_get_config_defaults(&config_i2c_master);
// Struct takes the argument in Khz not Hz.
config_i2c_master.baud_rate = freq / 1000;
config_i2c_master.baud_rate = frequency / 1000;
Sercom* sercom = NULL;
uint32_t sda_pinmux = 0;
uint32_t scl_pinmux = 0;
@ -106,6 +106,25 @@ bool common_hal_nativeio_i2c_probe(nativeio_i2c_obj_t *self, uint8_t addr) {
return status == STATUS_OK;
}
void common_hal_nativeio_i2c_configure(nativeio_i2c_obj_t *self,
uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) {
return;
}
bool common_hal_nativeio_i2c_try_lock(nativeio_i2c_obj_t *self) {
self->has_lock = i2c_master_lock(&self->i2c_master_instance) == STATUS_OK;
return self->has_lock;
}
bool common_hal_nativeio_i2c_has_lock(nativeio_i2c_obj_t *self) {
return self->has_lock;
}
void common_hal_nativeio_i2c_unlock(nativeio_i2c_obj_t *self) {
self->has_lock = false;
i2c_master_unlock(&self->i2c_master_instance);
}
bool common_hal_nativeio_i2c_write(nativeio_i2c_obj_t *self, uint16_t addr,
const uint8_t *data, size_t len, bool transmit_stop_bit) {
struct i2c_master_packet packet = {

View File

@ -39,7 +39,7 @@
void common_hal_nativeio_spi_construct(nativeio_spi_obj_t *self,
const mcu_pin_obj_t * clock, const mcu_pin_obj_t * mosi,
const mcu_pin_obj_t * miso, uint32_t baudrate) {
const mcu_pin_obj_t * miso) {
struct spi_config config_spi_master;
spi_get_config_defaults(&config_spi_master);
@ -67,9 +67,10 @@ void common_hal_nativeio_spi_construct(nativeio_spi_obj_t *self,
mosi_pad = mosi->sercom[j].pad;
if (miso_none) {
sercom = potential_sercom;
break;
}
} else {
break;
continue;
}
}
if (!miso_none) {
@ -130,8 +131,6 @@ void common_hal_nativeio_spi_construct(nativeio_spi_obj_t *self,
*pinmuxes[miso_pad] = miso_pinmux;
}
config_spi_master.mode_specific.master.baudrate = baudrate;
spi_init(&self->spi_master_instance, sercom, &config_spi_master);
spi_enable(&self->spi_master_instance);
@ -141,8 +140,64 @@ void common_hal_nativeio_spi_deinit(nativeio_spi_obj_t *self) {
spi_disable(&self->spi_master_instance);
}
bool common_hal_nativeio_spi_configure(nativeio_spi_obj_t *self,
uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) {
// TODO(tannewt): Check baudrate first before changing it.
enum status_code status = spi_set_baudrate(&self->spi_master_instance, baudrate);
if (status != STATUS_OK) {
return false;
}
SercomSpi *const spi_module = &(self->spi_master_instance.hw->SPI);
// If the settings are already what we want then don't reset them.
if (spi_module->CTRLA.bit.CPHA == phase &&
spi_module->CTRLA.bit.CPOL == polarity &&
spi_module->CTRLB.bit.CHSIZE == (bits - 8)) {
return true;
}
spi_disable(&self->spi_master_instance);
while (spi_is_syncing(&self->spi_master_instance)) {
/* Wait until the synchronization is complete */
}
spi_module->CTRLA.bit.CPHA = phase;
spi_module->CTRLA.bit.CPOL = polarity;
spi_module->CTRLB.bit.CHSIZE = bits - 8;
while (spi_is_syncing(&self->spi_master_instance)) {
/* Wait until the synchronization is complete */
}
/* Enable the module */
spi_enable(&self->spi_master_instance);
while (spi_is_syncing(&self->spi_master_instance)) {
/* Wait until the synchronization is complete */
}
return true;
}
bool common_hal_nativeio_spi_try_lock(nativeio_spi_obj_t *self) {
self->has_lock = spi_lock(&self->spi_master_instance) == STATUS_OK;
return self->has_lock;
}
bool common_hal_nativeio_spi_has_lock(nativeio_spi_obj_t *self) {
return self->has_lock;
}
void common_hal_nativeio_spi_unlock(nativeio_spi_obj_t *self) {
self->has_lock = false;
spi_unlock(&self->spi_master_instance);
}
bool common_hal_nativeio_spi_write(nativeio_spi_obj_t *self,
const uint8_t *data, size_t len) {
if (len == 0) {
return true;
}
enum status_code status = spi_write_buffer_wait(
&self->spi_master_instance,
data,
@ -152,6 +207,9 @@ bool common_hal_nativeio_spi_write(nativeio_spi_obj_t *self,
bool common_hal_nativeio_spi_read(nativeio_spi_obj_t *self,
uint8_t *data, size_t len) {
if (len == 0) {
return true;
}
enum status_code status = spi_read_buffer_wait(
&self->spi_master_instance,
data,

View File

@ -68,11 +68,13 @@ typedef struct {
typedef struct {
mp_obj_base_t base;
struct i2c_master_module i2c_master_instance;
bool has_lock;
} nativeio_i2c_obj_t;
typedef struct _machine_spi_obj_t {
mp_obj_base_t base;
struct spi_module spi_master_instance;
bool has_lock;
} nativeio_spi_obj_t;
typedef struct {

View File

@ -1,5 +1,3 @@
include ../py/mkenv.mk
# Select the board to build for: if not given on the command line,
# then default to PYBV10.
BOARD ?= feather_huzzah
@ -8,7 +6,9 @@ $(error Invalid BOARD specified)
endif
# If the build directory is not given, make it reflect the board name.
BUILD ?= build-$(BOARD)
BUILD ?= build
include ../py/mkenv.mk
# qstr definitions (must come before including py.mk)
QSTR_DEFS = qstrdefsport.h #$(BUILD)/pins_qstr.h

View File

@ -28,13 +28,29 @@
#include "shared-bindings/microcontroller/Pin.h"
#include "eagle_soc.h"
#include "osapi.h"
#include "ets_alt_task.h"
#include "etshal.h"
#include "osapi.h"
#include "xtirq.h"
#define ETS_LOOP_ITER_BIT (12)
void common_hal_mcu_delay_us(uint32_t delay) {
os_delay_us(delay);
}
static uint16_t saved_interrupt_state;
void common_hal_mcu_disable_interrupts() {
saved_interrupt_state = disable_irq();
saved_interrupt_state = (saved_interrupt_state & ~(1 << ETS_LOOP_ITER_BIT)) | (ets_loop_iter_disable << ETS_LOOP_ITER_BIT);
ets_loop_iter_disable = 1;
}
void common_hal_mcu_enable_interrupts() {
ets_loop_iter_disable = (saved_interrupt_state >> ETS_LOOP_ITER_BIT) & 1;
enable_irq(saved_interrupt_state & ~(1 << ETS_LOOP_ITER_BIT));
}
// This macro is used to simplify pin definition in boards/<board>/pins.c
#define PIN(p_name, p_gpio_number, p_gpio_function, p_peripheral) \
const mcu_pin_obj_t pin_## p_name = { \

View File

@ -71,7 +71,7 @@ void common_hal_nativeio_digitalinout_switch_to_output(
WRITE_PERI_REG(RTC_GPIO_CONF, READ_PERI_REG(RTC_GPIO_CONF) & ~1);
WRITE_PERI_REG(RTC_GPIO_ENABLE, (READ_PERI_REG(RTC_GPIO_ENABLE) & ~1) | 1); // output
} else if (!self->open_drain) {
gpio_output_set(0, 0, 1 << self->pin->gpio_function, 0);
gpio_output_set(0, 0, 1 << self->pin->gpio_number, 0);
PIN_PULLUP_DIS(self->pin->peripheral);
}
common_hal_nativeio_digitalinout_set_value(self, value);
@ -88,7 +88,6 @@ void common_hal_nativeio_digitalinout_set_value(
if (self->open_drain) {
// Disable output.
gpio_output_set(0, 0, 0, 1 << self->pin->gpio_number);
PIN_PULLUP_EN(self->pin->peripheral);
} else {
// Set high
gpio_output_set(1 << self->pin->gpio_number, 0, 0, 0);
@ -96,7 +95,6 @@ void common_hal_nativeio_digitalinout_set_value(
} else {
if (self->open_drain) {
// Enable the output
PIN_PULLUP_DIS(self->pin->peripheral);
gpio_output_set(0, 0, 1 << self->pin->gpio_number, 0);
}
// Set low

View File

@ -40,6 +40,17 @@ bool common_hal_nativeio_i2c_probe(nativeio_i2c_obj_t *self, uint8_t addr) {
return false;
}
bool common_hal_nativeio_i2c_try_lock(nativeio_i2c_obj_t *self) {
return false;
}
bool common_hal_nativeio_i2c_has_lock(nativeio_i2c_obj_t *self) {
return false;
}
void common_hal_nativeio_i2c_unlock(nativeio_i2c_obj_t *self) {
}
bool common_hal_nativeio_i2c_write(nativeio_i2c_obj_t *self, uint16_t addr,
const uint8_t * data, size_t len, bool transmit_stop_bit) {
return false;

View File

@ -26,6 +26,7 @@
#include "esp8266/ets_alt_task.h"
#include "esp8266/hspi.h"
#include "shared-bindings/microcontroller/__init__.h"
#include "shared-bindings/nativeio/SPI.h"
#include "py/nlr.h"
@ -37,11 +38,12 @@ extern const mcu_pin_obj_t pin_MTDI;
void common_hal_nativeio_spi_construct(nativeio_spi_obj_t *self,
const mcu_pin_obj_t * clock, const mcu_pin_obj_t * mosi,
const mcu_pin_obj_t * miso, uint32_t baudrate) {
const mcu_pin_obj_t * miso) {
if (clock != &pin_MTMS || mosi != &pin_MTCK || miso != &pin_MTDI) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError,
"Pins not valid for SPI"));
}
spi_init(HSPI);
}
void common_hal_nativeio_spi_deinit(nativeio_spi_obj_t *self) {
@ -50,6 +52,50 @@ void common_hal_nativeio_spi_deinit(nativeio_spi_obj_t *self) {
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 0);
}
bool common_hal_nativeio_spi_configure(nativeio_spi_obj_t *self,
uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) {
if (bits != 8) {
return false;
}
if (baudrate == 80000000L) {
// Special case for full speed.
spi_init_gpio(HSPI, SPI_CLK_80MHZ_NODIV);
spi_clock(HSPI, 0, 0);
} else if (baudrate > 40000000L) {
return false;
} else {
uint32_t divider = 40000000L / baudrate;
uint16_t prediv = MIN(divider, SPI_CLKDIV_PRE + 1);
uint16_t cntdiv = (divider / prediv) * 2; // cntdiv has to be even
if (cntdiv > SPI_CLKCNT_N + 1 || cntdiv == 0 || prediv == 0) {
return false;
}
spi_init_gpio(HSPI, SPI_CLK_USE_DIV);
spi_clock(HSPI, prediv, cntdiv);
}
spi_mode(HSPI, phase, polarity);
return true;
}
bool common_hal_nativeio_spi_try_lock(nativeio_spi_obj_t *self) {
bool success = false;
common_hal_mcu_disable_interrupts();
if (!self->locked) {
self->locked = true;
success = true;
}
common_hal_mcu_enable_interrupts();
return success;
}
bool common_hal_nativeio_spi_has_lock(nativeio_spi_obj_t *self) {
return self->locked;
}
void common_hal_nativeio_spi_unlock(nativeio_spi_obj_t *self) {
self->locked = false;
}
bool common_hal_nativeio_spi_write(nativeio_spi_obj_t *self,
const uint8_t * data, size_t len) {
size_t chunk_size = 1024;

View File

@ -58,6 +58,7 @@ typedef struct {
typedef struct {
mp_obj_base_t base;
bool locked;
} nativeio_spi_obj_t;
typedef struct {

View File

@ -36,7 +36,7 @@
//| :class:`I2C` --- Two wire serial protocol
//| ------------------------------------------
//|
//| .. class:: I2C(scl, sda, \*, freq=400000)
//| .. class:: I2C(scl, sda, \* frequency=400000)
//|
//| I2C is a two-wire protocol for communicating between devices. At the
//| physical level it consists of 2 wires: SCL and SDA, the clock and data
@ -44,7 +44,7 @@
//|
//| :param ~microcontroller.Pin scl: The clock pin
//| :param ~microcontroller.Pin sda: The data pin
//| :param int freq: The clock frequency
//| :param int frequency: The clock frequency of the bus
//|
STATIC mp_obj_t bitbangio_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) {
mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, true);
@ -52,11 +52,11 @@ STATIC mp_obj_t bitbangio_i2c_make_new(const mp_obj_type_t *type, size_t n_args,
self->base.type = &bitbangio_i2c_type;
mp_map_t kw_args;
mp_map_init_fixed_table(&kw_args, n_kw, pos_args + n_args);
enum { ARG_scl, ARG_sda, ARG_freq };
enum { ARG_scl, ARG_sda, ARG_frequency };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_sda, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} },
{ MP_QSTR_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} },
};
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);
@ -64,7 +64,7 @@ STATIC mp_obj_t bitbangio_i2c_make_new(const mp_obj_type_t *type, size_t n_args,
assert_pin(args[ARG_sda].u_obj, false);
const mcu_pin_obj_t* scl = MP_OBJ_TO_PTR(args[ARG_scl].u_obj);
const mcu_pin_obj_t* sda = MP_OBJ_TO_PTR(args[ARG_sda].u_obj);
shared_module_bitbangio_i2c_construct(self, scl, sda, args[ARG_freq].u_int);
shared_module_bitbangio_i2c_construct(self, scl, sda, args[ARG_frequency].u_int);
return (mp_obj_t)self;
}
@ -99,6 +99,12 @@ STATIC mp_obj_t bitbangio_i2c_obj___exit__(size_t n_args, const mp_obj_t *args)
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bitbangio_i2c_obj___exit___obj, 4, 4, bitbangio_i2c_obj___exit__);
static void check_lock(bitbangio_i2c_obj_t *self) {
if (!shared_module_bitbangio_i2c_has_lock(self)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Function requires I2C lock."));
}
}
//| .. method:: I2C.scan()
//|
//| Scan all I2C addresses between 0x08 and 0x77 inclusive and return a list of
@ -107,6 +113,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bitbangio_i2c_obj___exit___obj, 4, 4,
//|
STATIC mp_obj_t bitbangio_i2c_scan(mp_obj_t self_in) {
bitbangio_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
check_lock(self);
mp_obj_t list = mp_obj_new_list(0, NULL);
// 7-bit addresses 0b0000xxx and 0b1111xxx are reserved
for (int addr = 0x08; addr < 0x78; ++addr) {
@ -119,19 +126,97 @@ STATIC mp_obj_t bitbangio_i2c_scan(mp_obj_t self_in) {
}
MP_DEFINE_CONST_FUN_OBJ_1(bitbangio_i2c_scan_obj, bitbangio_i2c_scan);
//| .. method:: I2C.writeto(address, buffer, stop=True)
//| .. method:: I2C.try_lock()
//|
//| Attempts to grab the I2C lock. Returns True on success.
//|
STATIC mp_obj_t bitbangio_i2c_obj_try_lock(mp_obj_t self_in) {
shared_module_bitbangio_i2c_try_lock(MP_OBJ_TO_PTR(self_in));
return self_in;
}
MP_DEFINE_CONST_FUN_OBJ_1(bitbangio_i2c_try_lock_obj, bitbangio_i2c_obj_try_lock);
//| .. method:: I2C.unlock()
//|
//| Releases the I2C lock.
//|
STATIC mp_obj_t bitbangio_i2c_obj_unlock(mp_obj_t self_in) {
shared_module_bitbangio_i2c_unlock(MP_OBJ_TO_PTR(self_in));
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(bitbangio_i2c_unlock_obj, bitbangio_i2c_obj_unlock);
//| .. method:: I2C.readfrom_into(address, buffer, \*, start=0, end=len(buffer))
//|
//| Read into ``buffer`` from the slave specified by ``address``.
//| The number of bytes read will be the length of ``buffer``.
//|
//| If ``start`` or ``end`` is provided, then the buffer will be sliced
//| as if ``buffer[start:end]``. This will not cause an allocation like
//| ``buf[start:end]`` will so it saves memory.
//|
//| :param int address: 7-bit device address
//| :param bytearray buffer: buffer to write into
//| :param int start: Index to start writing at
//| :param int end: Index to write up to but not include
//|
STATIC mp_obj_t bitbangio_i2c_readfrom_into(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_address, ARG_buffer, ARG_start, ARG_end };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} },
};
bitbangio_i2c_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
check_lock(self);
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE);
int32_t end = args[ARG_end].u_int;
if (end < 0) {
end += bufinfo.len;
}
uint32_t start = args[ARG_start].u_int;
uint32_t len = end - start;
if ((uint32_t) end < start) {
len = 0;
} else if (len > bufinfo.len) {
len = bufinfo.len;
}
shared_module_bitbangio_i2c_read(self, args[ARG_address].u_int, ((uint8_t*)bufinfo.buf) + start, len);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(bitbangio_i2c_readfrom_into_obj, 3, bitbangio_i2c_readfrom_into);
//| .. method:: I2C.writeto(address, buffer, \*, start=0, end=len(buffer), stop=True)
//|
//| Write the bytes from ``buffer`` to the slave specified by ``address``.
//| Transmits a stop bit if ``stop`` is set.
//|
//| If ``start`` or ``end`` is provided, then the buffer will be sliced
//| as if ``buffer[start:end]``. This will not cause an allocation like
//| ``buffer[start:end]`` will so it saves memory.
//|
//| :param int address: 7-bit device address
//| :param bytearray buffer: buffer containing the bytes to write
//| :param int start: Index to start writing from
//| :param int end: Index to read up to but not include
//| :param bool stop: If true, output an I2C stop condition after the
//| buffer is written
//|
STATIC mp_obj_t bitbangio_i2c_writeto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_address, ARG_buffer, ARG_stop };
enum { ARG_address, ARG_buffer, ARG_start, ARG_end, ARG_stop };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_stop, MP_ARG_BOOL, {.u_bool = true} },
{ MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} },
{ MP_QSTR_stop, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
};
bitbangio_i2c_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
check_lock(self);
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
@ -139,9 +224,21 @@ STATIC mp_obj_t bitbangio_i2c_writeto(size_t n_args, const mp_obj_t *pos_args, m
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_READ);
int32_t end = args[ARG_end].u_int;
if (end < 0) {
end += bufinfo.len;
}
uint32_t start = args[ARG_start].u_int;
uint32_t len = end - start;
if ((uint32_t) end < start) {
len = 0;
} else if (len > bufinfo.len) {
len = bufinfo.len;
}
// do the transfer
bool ok = shared_module_bitbangio_i2c_write(self, args[ARG_address].u_int,
bufinfo.buf, bufinfo.len, args[ARG_stop].u_bool);
((uint8_t*) bufinfo.buf) + start, len, args[ARG_stop].u_bool);
if (!ok) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "I2C bus error"));
}
@ -149,27 +246,15 @@ STATIC mp_obj_t bitbangio_i2c_writeto(size_t n_args, const mp_obj_t *pos_args, m
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bitbangio_i2c_writeto_obj, 1, bitbangio_i2c_writeto);
//| .. method:: I2C.readfrom_into(address, buffer)
//|
//| Read into ``buffer`` from the slave specified by ``address``.
//| The number of bytes read will be the length of `buf`.
//|
STATIC mp_obj_t bitbangio_i2c_readfrom_into(mp_obj_t self_in, mp_obj_t addr_in, mp_obj_t buf_in) {
bitbangio_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE);
shared_module_bitbangio_i2c_read(self, mp_obj_get_int(addr_in), (uint8_t*)bufinfo.buf, bufinfo.len);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_3(bitbangio_i2c_readfrom_into_obj, bitbangio_i2c_readfrom_into);
STATIC const mp_rom_map_elem_t bitbangio_i2c_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&bitbangio_i2c_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&bitbangio_i2c___enter___obj) },
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&bitbangio_i2c_obj___exit___obj) },
{ MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&bitbangio_i2c_scan_obj) },
// standard bus operations
{ MP_ROM_QSTR(MP_QSTR_try_lock), MP_ROM_PTR(&bitbangio_i2c_try_lock_obj) },
{ MP_ROM_QSTR(MP_QSTR_unlock), MP_ROM_PTR(&bitbangio_i2c_unlock_obj) },
{ MP_ROM_QSTR(MP_QSTR_writeto), MP_ROM_PTR(&bitbangio_i2c_writeto_obj) },
{ MP_ROM_QSTR(MP_QSTR_readfrom_into), MP_ROM_PTR(&bitbangio_i2c_readfrom_into_obj) },
};

View File

@ -39,10 +39,14 @@ extern const mp_obj_type_t bitbangio_i2c_type;
extern void shared_module_bitbangio_i2c_construct(bitbangio_i2c_obj_t *self,
const mcu_pin_obj_t * scl,
const mcu_pin_obj_t * sda,
uint32_t freq);
uint32_t frequency);
extern void shared_module_bitbangio_i2c_deinit(bitbangio_i2c_obj_t *self);
extern bool shared_module_bitbangio_i2c_try_lock(bitbangio_i2c_obj_t *self);
extern bool shared_module_bitbangio_i2c_has_lock(bitbangio_i2c_obj_t *self);
extern void shared_module_bitbangio_i2c_unlock(bitbangio_i2c_obj_t *self);
// Probe the bus to see if a device acknowledges the given address.
extern bool shared_module_bitbangio_i2c_probe(bitbangio_i2c_obj_t *self, uint8_t addr);

View File

@ -47,14 +47,13 @@
//| select line. (This is common because multiple slaves can share the `!clock`,
//| `!MOSI` and `!MISO` lines and therefore the hardware.)
//|
//| .. class:: SPI(clock, MOSI, MISO, baudrate=1000000)
//| .. class:: SPI(clock, MOSI, MISO)
//|
//| Construct an SPI object on the given pins.
//|
//| :param ~microcontroller.Pin clock: the pin to use for the clock.
//| :param ~microcontroller.Pin MOSI: the Master Out Slave In pin.
//| :param ~microcontroller.Pin MISO: the Master In Slave Out pin.
//| :param int baudrate: is the SCK clock rate.
//|
// TODO(tannewt): Support LSB SPI.
@ -70,10 +69,6 @@ STATIC mp_obj_t bitbangio_spi_make_new(const mp_obj_type_t *type, size_t n_args,
{ MP_QSTR_clock, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_MOSI, MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_MISO, MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100000} },
{ MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} },
{ MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} },
{ MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
};
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);
@ -83,7 +78,7 @@ STATIC mp_obj_t bitbangio_spi_make_new(const mp_obj_type_t *type, size_t n_args,
const mcu_pin_obj_t* clock = MP_OBJ_TO_PTR(args[ARG_clock].u_obj);
const mcu_pin_obj_t* mosi = MP_OBJ_TO_PTR(args[ARG_MOSI].u_obj);
const mcu_pin_obj_t* miso = MP_OBJ_TO_PTR(args[ARG_MISO].u_obj);
shared_module_bitbangio_spi_construct(self, clock, mosi, miso, args[ARG_baudrate].u_int);
shared_module_bitbangio_spi_construct(self, clock, mosi, miso);
return (mp_obj_t)self;
}
@ -118,59 +113,113 @@ STATIC mp_obj_t bitbangio_spi_obj___exit__(size_t n_args, const mp_obj_t *args)
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bitbangio_spi_obj___exit___obj, 4, 4, bitbangio_spi_obj___exit__);
//| .. method:: SPI.transfer(write_buffer=None, read_buffer=None, address=0)
static void check_lock(bitbangio_spi_obj_t *self) {
if (!shared_module_bitbangio_spi_has_lock(self)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Function requires SPI lock."));
}
}
//| .. method:: SPI.configure(baudrate=100000)
//|
//| Write out ``write_buffer`` and then read into ``read_buffer``. They do
//| not need to be the same length. If either buffer is omitted then the
//| transfer skips the corresponding portion.
//| Configures the SPI bus. Only valid when locked.
//|
//| ``address`` is taken for I2C compatibility but is ignored.
//|
//| When writing, data received is dropped. When reading, zeroes are written
//| out.
//|
STATIC mp_obj_t bitbangio_spi_transfer(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_write_buffer, ARG_read_buffer, ARG_address };
STATIC mp_obj_t bitbangio_spi_configure(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_write_buffer, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL } },
{ MP_QSTR_read_buffer, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL } },
{ MP_QSTR_address, MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100000} },
{ MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
};
bitbangio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
check_lock(self);
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
// get the buffer to store data into
mp_buffer_info_t write_bufinfo;
if (!mp_get_buffer(args[ARG_write_buffer].u_obj, &write_bufinfo, MP_BUFFER_READ)) {
write_bufinfo.len = 0;
uint8_t polarity = args[ARG_polarity].u_int;
if (polarity != 0 && polarity != 1) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Invalid polarity."));
}
uint8_t phase = args[ARG_phase].u_int;
if (phase != 0 && phase != 1) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Invalid phase."));
}
uint8_t bits = args[ARG_bits].u_int;
if (bits != 8 && bits != 9) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Invalid number of bits."));
}
mp_buffer_info_t read_bufinfo;
if (!mp_get_buffer(args[ARG_read_buffer].u_obj, &read_bufinfo, MP_BUFFER_WRITE)) {
read_bufinfo.len = 0;
}
shared_module_bitbangio_spi_configure(self, args[ARG_baudrate].u_int, polarity, phase, bits);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(bitbangio_spi_configure_obj, 1, bitbangio_spi_configure);
if (write_bufinfo.len == 0 && read_bufinfo.len == 0) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "At least one buffer should be provided."));
}
//| .. method:: SPI.try_lock()
//|
//| Attempts to grab the SPI lock. Returns True on success.
//|
STATIC mp_obj_t bitbangio_spi_obj_try_lock(mp_obj_t self_in) {
shared_module_bitbangio_spi_try_lock(MP_OBJ_TO_PTR(self_in));
return self_in;
}
MP_DEFINE_CONST_FUN_OBJ_1(bitbangio_spi_try_lock_obj, bitbangio_spi_obj_try_lock);
// do the transfer
bool ok = shared_module_bitbangio_spi_transfer(self, write_bufinfo.buf,
write_bufinfo.len, read_bufinfo.buf, read_bufinfo.len);
//| .. method:: SPI.unlock()
//|
//| Releases the SPI lock.
//|
STATIC mp_obj_t bitbangio_spi_obj_unlock(mp_obj_t self_in) {
shared_module_bitbangio_spi_unlock(MP_OBJ_TO_PTR(self_in));
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(bitbangio_spi_unlock_obj, bitbangio_spi_obj_unlock);
//| .. method:: SPI.write(buf)
//|
//| Write the data contained in ``buf``. Requires the SPI being locked.
//|
STATIC mp_obj_t bitbangio_spi_write(mp_obj_t self_in, mp_obj_t wr_buf) {
mp_buffer_info_t src;
mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ);
bitbangio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
check_lock(self);
bool ok = shared_module_bitbangio_spi_write(self, src.buf, src.len);
if (!ok) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "I2C bus error"));
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "SPI bus error"));
}
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(bitbangio_spi_transfer_obj, 2, bitbangio_spi_transfer);
MP_DEFINE_CONST_FUN_OBJ_2(bitbangio_spi_write_obj, bitbangio_spi_write);
//| .. method:: SPI.readinto(buf)
//|
//| Read into the buffer specified by ``buf`` while writing zeroes. Requires the SPI being locked.
//|
STATIC mp_obj_t bitbangio_spi_readinto(size_t n_args, const mp_obj_t *args) {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE);
check_lock(args[0]);
bool ok = shared_module_bitbangio_spi_read(args[0], bufinfo.buf, bufinfo.len);
if (!ok) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "SPI bus error"));
}
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bitbangio_spi_readinto_obj, 2, 2, bitbangio_spi_readinto);
STATIC const mp_rom_map_elem_t bitbangio_spi_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&bitbangio_spi_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&bitbangio_spi___enter___obj) },
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&bitbangio_spi_obj___exit___obj) },
{ MP_ROM_QSTR(MP_QSTR_transfer), MP_ROM_PTR(&bitbangio_spi_transfer_obj) },
{ MP_ROM_QSTR(MP_QSTR_configure), MP_ROM_PTR(&bitbangio_spi_configure_obj) },
{ MP_ROM_QSTR(MP_QSTR_try_lock), MP_ROM_PTR(&bitbangio_spi_try_lock_obj) },
{ MP_ROM_QSTR(MP_QSTR_unlock), MP_ROM_PTR(&bitbangio_spi_unlock_obj) },
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&bitbangio_spi_readinto_obj) },
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&bitbangio_spi_write_obj) },
};
STATIC MP_DEFINE_CONST_DICT(bitbangio_spi_locals_dict, bitbangio_spi_locals_dict_table);

View File

@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2016 Scott Shawcroft
* Copyright (c) 2016 Scott Shawcroft for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -38,14 +38,21 @@ extern const mp_obj_type_t bitbangio_spi_type;
// Construct an underlying SPI object.
extern void shared_module_bitbangio_spi_construct(bitbangio_spi_obj_t *self,
const mcu_pin_obj_t * clock, const mcu_pin_obj_t * mosi,
const mcu_pin_obj_t * miso, uint32_t baudrate);
const mcu_pin_obj_t * miso);
extern void shared_module_bitbangio_spi_deinit(bitbangio_spi_obj_t *self);
// Write out write_buffer then read read_buffer. Returns true on success, false
// otherwise.
extern bool shared_module_bitbangio_spi_transfer(bitbangio_spi_obj_t *self,
const uint8_t *write_buffer, size_t write_buffer_len,
uint8_t *read_buffer, size_t read_buffer_len);
extern void shared_module_bitbangio_spi_configure(bitbangio_spi_obj_t *self,
uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits);
extern bool shared_module_bitbangio_spi_try_lock(bitbangio_spi_obj_t *self);
extern bool shared_module_bitbangio_spi_has_lock(bitbangio_spi_obj_t *self);
extern void shared_module_bitbangio_spi_unlock(bitbangio_spi_obj_t *self);
// Writes out the given data.
extern bool shared_module_bitbangio_spi_write(bitbangio_spi_obj_t *self, const uint8_t *data, size_t len);
// Reads in len bytes while outputting zeroes.
extern bool shared_module_bitbangio_spi_read(bitbangio_spi_obj_t *self, uint8_t *data, size_t len);
#endif // __MICROPY_INCLUDED_SHARED_BINDINGS_BITBANGIO_SPI_H__

View File

@ -70,6 +70,26 @@ STATIC mp_obj_t mcu_delay_us(mp_obj_t delay_obj) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mcu_delay_us_obj, mcu_delay_us);
//| .. method:: disable_interrupts()
//|
//| Disable all interrupts. Be very careful, this can stall everything.
//|
STATIC mp_obj_t mcu_disable_interrupts(void) {
common_hal_mcu_disable_interrupts();
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mcu_disable_interrupts_obj, mcu_disable_interrupts);
//| .. method:: enable_interrupts()
//|
//| Enable the interrupts that were enabled at the last disable.
//|
STATIC mp_obj_t mcu_enable_interrupts(void) {
common_hal_mcu_enable_interrupts();
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mcu_enable_interrupts_obj, mcu_enable_interrupts);
//| :mod:`microcontroller.pin` --- Microcontroller pin names
//| --------------------------------------------------------
//|
@ -87,6 +107,8 @@ const mp_obj_module_t mcu_pin_module = {
STATIC const mp_rom_map_elem_t mcu_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_microcontroller) },
{ MP_ROM_QSTR(MP_QSTR_delay_us), MP_ROM_PTR(&mcu_delay_us_obj) },
{ MP_ROM_QSTR(MP_QSTR_disable_interrupts), MP_ROM_PTR(&mcu_disable_interrupts_obj) },
{ MP_ROM_QSTR(MP_QSTR_enable_interrupts), MP_ROM_PTR(&mcu_enable_interrupts_obj) },
{ MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&mcu_pin_type) },
{ MP_ROM_QSTR(MP_QSTR_pin), MP_ROM_PTR(&mcu_pin_module) },
};

View File

@ -31,6 +31,9 @@
extern void common_hal_mcu_delay_us(uint32_t);
extern void common_hal_mcu_disable_interrupts(void);
extern void common_hal_mcu_enable_interrupts(void);
extern const mp_obj_dict_t mcu_pin_globals;
#endif // __MICROPY_INCLUDED_SHARED_BINDINGS_MICROCONTROLLER___INIT___H__

View File

@ -36,7 +36,7 @@
//| :class:`I2C` --- Two wire serial protocol
//| ------------------------------------------
//|
//| .. class:: I2C(scl, sda, \*, freq=400000)
//| .. class:: I2C(scl, sda, \*, frequency=400000)
//|
//| I2C is a two-wire protocol for communicating between devices. At the
//| physical level it consists of 2 wires: SCL and SDA, the clock and data
@ -44,7 +44,7 @@
//|
//| :param ~microcontroller.Pin scl: The clock pin
//| :param ~microcontroller.Pin sda: The data pin
//| :param int freq: The clock frequency
//| :param int frequency: The clock frequency
//|
STATIC mp_obj_t nativeio_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *pos_args) {
mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, true);
@ -52,11 +52,11 @@ STATIC mp_obj_t nativeio_i2c_make_new(const mp_obj_type_t *type, size_t n_args,
self->base.type = &nativeio_i2c_type;
mp_map_t kw_args;
mp_map_init_fixed_table(&kw_args, n_kw, pos_args + n_args);
enum { ARG_scl, ARG_sda, ARG_freq };
enum { ARG_scl, ARG_sda, ARG_frequency };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_sda, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} },
{ MP_QSTR_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} },
};
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);
@ -64,7 +64,7 @@ STATIC mp_obj_t nativeio_i2c_make_new(const mp_obj_type_t *type, size_t n_args,
assert_pin(args[ARG_sda].u_obj, false);
const mcu_pin_obj_t* scl = MP_OBJ_TO_PTR(args[ARG_scl].u_obj);
const mcu_pin_obj_t* sda = MP_OBJ_TO_PTR(args[ARG_sda].u_obj);
common_hal_nativeio_i2c_construct(self, scl, sda, args[ARG_freq].u_int);
common_hal_nativeio_i2c_construct(self, scl, sda, args[ARG_frequency].u_int);
return (mp_obj_t)self;
}
@ -99,6 +99,12 @@ STATIC mp_obj_t nativeio_i2c_obj___exit__(size_t n_args, const mp_obj_t *args) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(nativeio_i2c___exit___obj, 4, 4, nativeio_i2c_obj___exit__);
static void check_lock(nativeio_i2c_obj_t *self) {
if (!common_hal_nativeio_i2c_has_lock(self)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Function requires I2C lock."));
}
}
//| .. method:: I2C.scan()
//|
//| Scan all I2C addresses between 0x08 and 0x77 inclusive and return a
@ -109,6 +115,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(nativeio_i2c___exit___obj, 4, 4, nati
//|
STATIC mp_obj_t nativeio_i2c_scan(mp_obj_t self_in) {
nativeio_i2c_obj_t *self = MP_OBJ_TO_PTR(self_in);
check_lock(self);
mp_obj_t list = mp_obj_new_list(0, NULL);
// 7-bit addresses 0b0000xxx and 0b1111xxx are reserved
for (int addr = 0x08; addr < 0x78; ++addr) {
@ -121,6 +128,26 @@ STATIC mp_obj_t nativeio_i2c_scan(mp_obj_t self_in) {
}
MP_DEFINE_CONST_FUN_OBJ_1(nativeio_i2c_scan_obj, nativeio_i2c_scan);
//| .. method:: I2C.try_lock()
//|
//| Attempts to grab the I2C lock. Returns True on success.
//|
STATIC mp_obj_t nativeio_i2c_obj_try_lock(mp_obj_t self_in) {
common_hal_nativeio_i2c_try_lock(MP_OBJ_TO_PTR(self_in));
return self_in;
}
MP_DEFINE_CONST_FUN_OBJ_1(nativeio_i2c_try_lock_obj, nativeio_i2c_obj_try_lock);
//| .. method:: I2C.unlock()
//|
//| Releases the I2C lock.
//|
STATIC mp_obj_t nativeio_i2c_obj_unlock(mp_obj_t self_in) {
common_hal_nativeio_i2c_unlock(MP_OBJ_TO_PTR(self_in));
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(nativeio_i2c_unlock_obj, nativeio_i2c_obj_unlock);
//| .. method:: I2C.readfrom_into(address, buffer, \*, start=0, end=len(buffer))
//|
//| Read into ``buffer`` from the slave specified by ``address``.
@ -144,6 +171,7 @@ STATIC mp_obj_t nativeio_i2c_readfrom_into(size_t n_args, const mp_obj_t *pos_ar
{ MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} },
};
nativeio_i2c_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
check_lock(self);
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
@ -191,6 +219,7 @@ STATIC mp_obj_t nativeio_i2c_writeto(size_t n_args, const mp_obj_t *pos_args, mp
{ MP_QSTR_stop, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
};
nativeio_i2c_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
check_lock(self);
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
@ -226,6 +255,9 @@ STATIC const mp_rom_map_elem_t nativeio_i2c_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&nativeio_i2c___exit___obj) },
{ MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&nativeio_i2c_scan_obj) },
{ MP_ROM_QSTR(MP_QSTR_try_lock), MP_ROM_PTR(&nativeio_i2c_try_lock_obj) },
{ MP_ROM_QSTR(MP_QSTR_unlock), MP_ROM_PTR(&nativeio_i2c_unlock_obj) },
{ MP_ROM_QSTR(MP_QSTR_readfrom_into), MP_ROM_PTR(&nativeio_i2c_readfrom_into_obj) },
{ MP_ROM_QSTR(MP_QSTR_writeto), MP_ROM_PTR(&nativeio_i2c_writeto_obj) },
};

View File

@ -46,10 +46,14 @@ extern const mp_obj_type_t nativeio_i2c_type;
extern void common_hal_nativeio_i2c_construct(nativeio_i2c_obj_t *self,
const mcu_pin_obj_t * scl,
const mcu_pin_obj_t * sda,
uint32_t freq);
uint32_t frequency);
extern void common_hal_nativeio_i2c_deinit(nativeio_i2c_obj_t *self);
extern bool common_hal_nativeio_i2c_try_lock(nativeio_i2c_obj_t *self);
extern bool common_hal_nativeio_i2c_has_lock(nativeio_i2c_obj_t *self);
extern void common_hal_nativeio_i2c_unlock(nativeio_i2c_obj_t *self);
// Probe the bus to see if a device acknowledges the given address.
extern bool common_hal_nativeio_i2c_probe(nativeio_i2c_obj_t *self, uint8_t addr);

View File

@ -32,6 +32,7 @@
#include "shared-bindings/microcontroller/Pin.h"
#include "shared-bindings/nativeio/SPI.h"
#include "py/nlr.h"
#include "py/runtime.h"
//| .. currentmodule:: nativeio
@ -47,14 +48,13 @@
//| select line. (This is common because multiple slaves can share the `!clock`,
//| `!MOSI` and `!MISO` lines and therefore the hardware.)
//|
//| .. class:: SPI(clock, MOSI, MISO, baudrate=1000000)
//| .. class:: SPI(clock, MOSI, MISO)
//|
//| Construct an SPI object on the given pins.
//|
//| :param ~microcontroller.Pin clock: the pin to use for the clock.
//| :param ~microcontroller.Pin MOSI: the Master Out Slave In pin.
//| :param ~microcontroller.Pin MISO: the Master In Slave Out pin.
//| :param int baudrate: is the SCK clock rate.
//|
// TODO(tannewt): Support LSB SPI.
@ -68,12 +68,8 @@ STATIC mp_obj_t nativeio_spi_make_new(const mp_obj_type_t *type, size_t n_args,
enum { ARG_clock, ARG_MOSI, ARG_MISO, ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_clock, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_MOSI, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_MISO, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100000} },
{ MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} },
{ MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} },
{ MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
{ MP_QSTR_MOSI, MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_MISO, MP_ARG_OBJ, {.u_obj = mp_const_none} },
};
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);
@ -83,7 +79,7 @@ STATIC mp_obj_t nativeio_spi_make_new(const mp_obj_type_t *type, size_t n_args,
const mcu_pin_obj_t* clock = MP_OBJ_TO_PTR(args[ARG_clock].u_obj);
const mcu_pin_obj_t* mosi = MP_OBJ_TO_PTR(args[ARG_MOSI].u_obj);
const mcu_pin_obj_t* miso = MP_OBJ_TO_PTR(args[ARG_MISO].u_obj);
common_hal_nativeio_spi_construct(self, clock, mosi, miso, args[ARG_baudrate].u_int);
common_hal_nativeio_spi_construct(self, clock, mosi, miso);
return (mp_obj_t)self;
}
@ -92,24 +88,24 @@ STATIC mp_obj_t nativeio_spi_make_new(const mp_obj_type_t *type, size_t n_args,
//| Turn off the SPI bus.
//|
STATIC mp_obj_t nativeio_spi_obj_deinit(mp_obj_t self_in) {
nativeio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
common_hal_nativeio_spi_deinit(self);
return mp_const_none;
nativeio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
common_hal_nativeio_spi_deinit(self);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(nativeio_spi_deinit_obj, nativeio_spi_obj_deinit);
//| .. method:: SPI.__enter__()
//|
//| No-op used by Context Managers.
//| No-op used by Context Managers.
//|
STATIC mp_obj_t nativeio_spi_obj___enter__(mp_obj_t self_in) {
return self_in;
return self_in;
}
MP_DEFINE_CONST_FUN_OBJ_1(nativeio_spi___enter___obj, nativeio_spi_obj___enter__);
//| .. method:: SPI.__exit__()
//|
//| Automatically deinitializes the hardware when exiting a context.
//| Automatically deinitializes the hardware when exiting a context.
//|
STATIC mp_obj_t nativeio_spi_obj___exit__(size_t n_args, const mp_obj_t *args) {
(void)n_args;
@ -118,15 +114,79 @@ STATIC mp_obj_t nativeio_spi_obj___exit__(size_t n_args, const mp_obj_t *args) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(nativeio_spi_obj___exit___obj, 4, 4, nativeio_spi_obj___exit__);
static void check_lock(nativeio_spi_obj_t *self) {
if (!common_hal_nativeio_spi_has_lock(self)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Function requires SPI lock."));
}
}
//| .. method:: SPI.configure(baudrate=100000)
//|
//| Configures the SPI bus. Only valid when locked.
//|
STATIC mp_obj_t nativeio_spi_configure(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100000} },
{ MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} },
};
nativeio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
check_lock(self);
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
uint8_t polarity = args[ARG_polarity].u_int;
if (polarity != 0 && polarity != 1) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Invalid polarity."));
}
uint8_t phase = args[ARG_phase].u_int;
if (phase != 0 && phase != 1) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Invalid phase."));
}
uint8_t bits = args[ARG_bits].u_int;
if (bits != 8 && bits != 9) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Invalid number of bits."));
}
if (!common_hal_nativeio_spi_configure(self, args[ARG_baudrate].u_int,
polarity, phase, bits)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "SPI configure failed."));
}
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(nativeio_spi_configure_obj, 1, nativeio_spi_configure);
//| .. method:: SPI.try_lock()
//|
//| Attempts to grab the SPI lock. Returns True on success.
//|
STATIC mp_obj_t nativeio_spi_obj_try_lock(mp_obj_t self_in) {
common_hal_nativeio_spi_try_lock(MP_OBJ_TO_PTR(self_in));
return self_in;
}
MP_DEFINE_CONST_FUN_OBJ_1(nativeio_spi_try_lock_obj, nativeio_spi_obj_try_lock);
//| .. method:: SPI.unlock()
//|
//| Releases the SPI lock.
//|
STATIC mp_obj_t nativeio_spi_obj_unlock(mp_obj_t self_in) {
common_hal_nativeio_spi_unlock(MP_OBJ_TO_PTR(self_in));
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(nativeio_spi_unlock_obj, nativeio_spi_obj_unlock);
//| .. method:: SPI.write(buf)
//|
//| Write the data contained in `!buf`.
//| Returns the number of bytes written.
//| Write the data contained in ``buf``. Requires the SPI being locked.
//|
STATIC mp_obj_t nativeio_spi_write(mp_obj_t self_in, mp_obj_t wr_buf) {
mp_buffer_info_t src;
mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ);
nativeio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
check_lock(self);
bool ok = common_hal_nativeio_spi_write(self, src.buf, src.len);
if (!ok) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "SPI bus error"));
@ -138,13 +198,12 @@ MP_DEFINE_CONST_FUN_OBJ_2(nativeio_spi_write_obj, nativeio_spi_write);
//| .. method:: SPI.readinto(buf)
//|
//| Read into the buffer specified by `!buf` while writing the data
//| specified by `!write`.
//| Return the number of bytes read.
//| Read into the buffer specified by ``buf`` while writing zeroes. Requires the SPI being locked.
//|
STATIC mp_obj_t nativeio_spi_readinto(size_t n_args, const mp_obj_t *args) {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE);
check_lock(args[0]);
bool ok = common_hal_nativeio_spi_read(args[0], bufinfo.buf, bufinfo.len);
if (!ok) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "SPI bus error"));
@ -158,6 +217,10 @@ STATIC const mp_rom_map_elem_t nativeio_spi_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&nativeio_spi___enter___obj) },
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&nativeio_spi_obj___exit___obj) },
{ MP_ROM_QSTR(MP_QSTR_configure), MP_ROM_PTR(&nativeio_spi_configure_obj) },
{ MP_ROM_QSTR(MP_QSTR_try_lock), MP_ROM_PTR(&nativeio_spi_try_lock_obj) },
{ MP_ROM_QSTR(MP_QSTR_unlock), MP_ROM_PTR(&nativeio_spi_unlock_obj) },
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&nativeio_spi_readinto_obj) },
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&nativeio_spi_write_obj) },
};

View File

@ -38,10 +38,16 @@ extern const mp_obj_type_t nativeio_spi_type;
// Construct an underlying SPI object.
extern void common_hal_nativeio_spi_construct(nativeio_spi_obj_t *self,
const mcu_pin_obj_t * clock, const mcu_pin_obj_t * mosi,
const mcu_pin_obj_t * miso, uint32_t baudrate);
const mcu_pin_obj_t * miso);
extern void common_hal_nativeio_spi_deinit(nativeio_spi_obj_t *self);
extern bool common_hal_nativeio_spi_configure(nativeio_spi_obj_t *self, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits);
extern bool common_hal_nativeio_spi_try_lock(nativeio_spi_obj_t *self);
extern bool common_hal_nativeio_spi_has_lock(nativeio_spi_obj_t *self);
extern void common_hal_nativeio_spi_unlock(nativeio_spi_obj_t *self);
// Writes out the given data.
extern bool common_hal_nativeio_spi_write(nativeio_spi_obj_t *self, const uint8_t *data, size_t len);

View File

@ -141,8 +141,8 @@ STATIC bool read_byte(bitbangio_i2c_obj_t *self, uint8_t *val, bool ack) {
void shared_module_bitbangio_i2c_construct(bitbangio_i2c_obj_t *self,
const mcu_pin_obj_t * scl,
const mcu_pin_obj_t * sda,
uint32_t freq) {
self->us_delay = 500000 / freq;
uint32_t frequency) {
self->us_delay = 500000 / frequency;
if (self->us_delay == 0) {
self->us_delay = 1;
}
@ -166,6 +166,25 @@ void shared_module_bitbangio_i2c_deinit(bitbangio_i2c_obj_t *self) {
common_hal_nativeio_digitalinout_deinit(&self->sda);
}
bool shared_module_bitbangio_i2c_try_lock(bitbangio_i2c_obj_t *self) {
bool success = false;
common_hal_mcu_disable_interrupts();
if (!self->locked) {
self->locked = true;
success = true;
}
common_hal_mcu_enable_interrupts();
return success;
}
bool shared_module_bitbangio_i2c_has_lock(bitbangio_i2c_obj_t *self) {
return self->locked;
}
void shared_module_bitbangio_i2c_unlock(bitbangio_i2c_obj_t *self) {
self->locked = false;
}
bool shared_module_bitbangio_i2c_probe(bitbangio_i2c_obj_t *self, uint8_t addr) {
start(self);
bool ok = write_byte(self, addr << 1);

View File

@ -36,7 +36,7 @@
#define MAX_BAUDRATE (common_hal_mcu_get_clock_frequency() / 48)
extern void shared_module_bitbangio_spi_construct(bitbangio_spi_obj_t *self,
void shared_module_bitbangio_spi_construct(bitbangio_spi_obj_t *self,
const mcu_pin_obj_t * clock, const mcu_pin_obj_t * mosi,
const mcu_pin_obj_t * miso, uint32_t baudrate) {
digitalinout_result_t result = common_hal_nativeio_digitalinout_construct(&self->clock, clock);
@ -65,18 +65,12 @@ extern void shared_module_bitbangio_spi_construct(bitbangio_spi_obj_t *self,
}
self->has_miso = true;
}
self->delay_half = 500000 / baudrate;
// round delay_half up so that: actual_baudrate <= requested_baudrate
if (500000 % baudrate != 0) {
self->delay_half += 1;
}
self->delay_half = 5;
self->polarity = 0;
self->phase = 0;
}
extern void shared_module_bitbangio_spi_deinit(bitbangio_spi_obj_t *self) {
void shared_module_bitbangio_spi_deinit(bitbangio_spi_obj_t *self) {
common_hal_nativeio_digitalinout_deinit(&self->clock);
if (self->has_mosi) {
common_hal_nativeio_digitalinout_deinit(&self->mosi);
@ -86,17 +80,43 @@ extern void shared_module_bitbangio_spi_deinit(bitbangio_spi_obj_t *self) {
}
}
bool shared_module_bitbangio_spi_transfer(bitbangio_spi_obj_t *self,
const uint8_t *write_buffer, size_t write_buffer_len,
uint8_t *read_buffer, size_t read_buffer_len) {
if (write_buffer_len > 0 && !self->has_mosi) {
void shared_module_bitbangio_spi_configure(bitbangio_spi_obj_t *self,
uint32_t baudrate, uint8_t polarity, uint8_t phase) {
self->delay_half = 500000 / baudrate;
// round delay_half up so that: actual_baudrate <= requested_baudrate
if (500000 % baudrate != 0) {
self->delay_half += 1;
}
self->polarity = polarity;
self->phase = phase;
}
bool shared_module_bitbangio_spi_try_lock(bitbangio_spi_obj_t *self) {
bool success = false;
common_hal_mcu_disable_interrupts();
if (!self->locked) {
self->locked = true;
success = true;
}
common_hal_mcu_enable_interrupts();
return success;
}
bool shared_module_bitbangio_spi_has_lock(bitbangio_spi_obj_t *self) {
return self->locked;
}
void shared_module_bitbangio_spi_unlock(bitbangio_spi_obj_t *self) {
self->locked = false;
}
// Writes out the given data.
bool shared_module_bitbangio_spi_write(bitbangio_spi_obj_t *self, const uint8_t *data, size_t len) {
if (len > 0 && !self->has_mosi) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError,
"Cannot write without MOSI pin."));
}
if (read_buffer_len > 0 && !self->has_miso) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError,
"Cannot read without MISO pin."));
}
uint32_t delay_half = self->delay_half;
// only MSB transfer is implemented
@ -106,8 +126,8 @@ bool shared_module_bitbangio_spi_transfer(bitbangio_spi_obj_t *self,
// will run as fast as possible, limited only by CPU speed and GPIO time.
#ifdef MICROPY_PY_MACHINE_SPI_MIN_DELAY
if (delay_half <= MICROPY_PY_MACHINE_SPI_MIN_DELAY) {
for (size_t i = 0; i < write_buffer_len; ++i) {
uint8_t data_out = write_buffer[i];
for (size_t i = 0; i < len; ++i) {
uint8_t data_out = data[i];
for (int j = 0; j < 8; ++j, data_out <<= 1) {
common_hal_nativeio_digitalinout_set_value(&self->mosi, (data_out >> 7) & 1);
common_hal_nativeio_digitalinout_set_value(&self->clock, 1 - self->polarity);
@ -117,26 +137,12 @@ bool shared_module_bitbangio_spi_transfer(bitbangio_spi_obj_t *self,
dest[i] = data_in;
}
}
// Clock out zeroes while we read.
if (self->has_mosi) {
common_hal_nativeio_digitalinout_set_value(&self->mosi, false);
}
for (size_t i = 0; i < read_buffer_len; ++i) {
uint8_t data_in = 0;
for (int j = 0; j < 8; ++j, data_out <<= 1) {
common_hal_nativeio_digitalinout_set_value(&self->clock, 1 - self->polarity);
data_in = (data_in << 1) | common_hal_nativeio_digitalinout_get_value(&self->miso);
common_hal_nativeio_digitalinout_set_value(&self->clock, self->polarity);
}
read_buffer[i] = data_in;
}
return true;
}
#endif
for (size_t i = 0; i < write_buffer_len; ++i) {
uint8_t data_out = write_buffer[i];
for (size_t i = 0; i < len; ++i) {
uint8_t data_out = data[i];
for (int j = 0; j < 8; ++j, data_out <<= 1) {
common_hal_nativeio_digitalinout_set_value(&self->mosi, (data_out >> 7) & 1);
if (self->phase == 0) {
@ -161,10 +167,45 @@ bool shared_module_bitbangio_spi_transfer(bitbangio_spi_obj_t *self,
MICROPY_EVENT_POLL_HOOK;
#endif
}
return true;
}
// Reads in len bytes while outputting zeroes.
bool shared_module_bitbangio_spi_read(bitbangio_spi_obj_t *self, uint8_t *data, size_t len) {
if (len > 0 && !self->has_miso) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError,
"Cannot read without MISO pin."));
}
uint32_t delay_half = self->delay_half;
// only MSB transfer is implemented
// If a port defines MICROPY_PY_MACHINE_SPI_MIN_DELAY, and the configured
// delay_half is equal to this value, then the software SPI implementation
// will run as fast as possible, limited only by CPU speed and GPIO time.
#ifdef MICROPY_PY_MACHINE_SPI_MIN_DELAY
if (delay_half <= MICROPY_PY_MACHINE_SPI_MIN_DELAY) {
// Clock out zeroes while we read.
if (self->has_mosi) {
common_hal_nativeio_digitalinout_set_value(&self->mosi, false);
}
for (size_t i = 0; i < len; ++i) {
uint8_t data_in = 0;
for (int j = 0; j < 8; ++j, data_out <<= 1) {
common_hal_nativeio_digitalinout_set_value(&self->clock, 1 - self->polarity);
data_in = (data_in << 1) | common_hal_nativeio_digitalinout_get_value(&self->miso);
common_hal_nativeio_digitalinout_set_value(&self->clock, self->polarity);
}
data[i] = data_in;
}
return true;
}
#endif
if (self->has_mosi) {
common_hal_nativeio_digitalinout_set_value(&self->mosi, false);
}
for (size_t i = 0; i < read_buffer_len; ++i) {
for (size_t i = 0; i < len; ++i) {
uint8_t data_in = 0;
for (int j = 0; j < 8; ++j) {
if (self->phase == 0) {
@ -183,7 +224,7 @@ bool shared_module_bitbangio_spi_transfer(bitbangio_spi_obj_t *self,
common_hal_mcu_delay_us(delay_half);
}
}
read_buffer[i] = data_in;
data[i] = data_in;
// Some ports need a regular callback, but probably we don't need
// to do this every byte, or even at all.

View File

@ -36,18 +36,20 @@ typedef struct {
nativeio_digitalinout_obj_t scl;
nativeio_digitalinout_obj_t sda;
uint32_t us_delay;
volatile bool locked;
} bitbangio_i2c_obj_t;
typedef struct {
mp_obj_base_t base;
nativeio_digitalinout_obj_t clock;
bool has_mosi;
nativeio_digitalinout_obj_t mosi;
bool has_miso;
nativeio_digitalinout_obj_t miso;
uint32_t delay_half;
uint8_t polarity;
uint8_t phase;
bool has_miso:1;
bool has_mosi:1;
uint8_t polarity:1;
uint8_t phase:1;
volatile bool locked:1;
} bitbangio_spi_obj_t;
#endif // __MICROPY_INCLUDED_SHARED_MODULE_BITBANGIO_TYPES_H__