diff --git a/ports/atmel-samd/common-hal/busio/SPI.c b/ports/atmel-samd/common-hal/busio/SPI.c index 4414d7ca91..ca98d1d2f2 100644 --- a/ports/atmel-samd/common-hal/busio/SPI.c +++ b/ports/atmel-samd/common-hal/busio/SPI.c @@ -122,10 +122,7 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, // Always start at 250khz which is what SD cards need. They are sensitive to // SPI bus noise before they are put into SPI mode. - uint8_t baud_value = samd_peripherals_baudrate_to_baud_reg_value(250000); - if (baud_value == 0) { - mp_raise_RuntimeError("SPI initial baudrate out of range."); - } + uint8_t baud_value = samd_peripherals_spi_baudrate_to_baud_reg_value(250000); if (spi_m_sync_set_baudrate(&self->spi_desc, baud_value) != ERR_NONE) { // spi_m_sync_set_baudrate does not check for validity, just whether the device is // busy or not @@ -179,10 +176,7 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { bool common_hal_busio_spi_configure(busio_spi_obj_t *self, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) { - uint8_t baud_reg_value = samd_peripherals_baudrate_to_baud_reg_value(baudrate); - if (baud_reg_value == 0) { - mp_raise_ValueError("baudrate out of range"); - } + uint8_t baud_reg_value = samd_peripherals_spi_baudrate_to_baud_reg_value(baudrate); void * hw = self->spi_desc.dev.prvt; // If the settings are already what we want then don't reset them. @@ -279,3 +273,7 @@ bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, uint8_t *data_out, uin // } return status >= 0; // Status is number of chars read or an error code < 0. } + +uint32_t common_hal_busio_spi_get_frequency(busio_spi_obj_t* self) { + return samd_peripherals_spi_baud_reg_value_to_baudrate(hri_sercomspi_read_BAUD_reg(self->spi_desc.dev.prvt)); +} diff --git a/ports/atmel-samd/peripherals.c b/ports/atmel-samd/peripherals.c index 6de813cca7..0c7f1dc63a 100644 --- a/ports/atmel-samd/peripherals.c +++ b/ports/atmel-samd/peripherals.c @@ -31,13 +31,15 @@ // Routines that are the same across all samd variants. -// Convert frequency to clock-speed-dependent value. Return 0 if out of range. -uint8_t samd_peripherals_baudrate_to_baud_reg_value(const uint32_t baudrate) { +// Convert frequency to clock-speed-dependent value. Return 255 if > 255. +uint8_t samd_peripherals_spi_baudrate_to_baud_reg_value(const uint32_t baudrate) { uint32_t baud_reg_value = (uint32_t) (((float) PROTOTYPE_SERCOM_SPI_M_SYNC_CLOCK_FREQUENCY / - (2 * baudrate)) + 0.5f); - if (baud_reg_value > 0xff) { - return 0; - } - return (uint8_t) baud_reg_value; + (2 * baudrate)) - 0.5f); + return (uint8_t) (baud_reg_value > 255 ? 255 : baud_reg_value); +} + +// Convert BAUD reg value back to a frequency. +uint32_t samd_peripherals_spi_baud_reg_value_to_baudrate(const uint8_t baud_reg_value) { + return PROTOTYPE_SERCOM_SPI_M_SYNC_CLOCK_FREQUENCY / (2 * (baud_reg_value + 1)); } diff --git a/ports/atmel-samd/peripherals.h b/ports/atmel-samd/peripherals.h index 95bc1ec53f..bb01bc1acd 100644 --- a/ports/atmel-samd/peripherals.h +++ b/ports/atmel-samd/peripherals.h @@ -32,7 +32,8 @@ #include "mpconfigport.h" // Routines common across chip families. -uint8_t samd_peripherals_baudrate_to_baud_reg_value(const uint32_t baudrate); +uint8_t samd_peripherals_spi_baudrate_to_baud_reg_value(const uint32_t baudrate); +uint32_t samd_peripherals_spi_baud_reg_value_to_baudrate(const uint8_t baud_reg_value); #ifdef SAMD21 #include "samd21_peripherals.h" diff --git a/ports/atmel-samd/spi_flash.c b/ports/atmel-samd/spi_flash.c index 1070481ea8..55a00dcba3 100644 --- a/ports/atmel-samd/spi_flash.c +++ b/ports/atmel-samd/spi_flash.c @@ -280,7 +280,7 @@ void spi_flash_init(void) { hri_sercomspi_write_CTRLA_DOPO_bf(SPI_FLASH_SERCOM, SPI_FLASH_DOPO); hri_sercomspi_write_CTRLA_DIPO_bf(SPI_FLASH_SERCOM, SPI_FLASH_DIPO); - spi_m_sync_set_baudrate(&spi_flash_desc, samd_peripherals_baudrate_to_baud_reg_value(SPI_FLASH_BAUDRATE)); + spi_m_sync_set_baudrate(&spi_flash_desc, samd_peripherals_spi_baudrate_to_baud_reg_value(SPI_FLASH_BAUDRATE)); gpio_set_pin_direction(SPI_FLASH_CS_PIN, GPIO_DIRECTION_OUT); // There's already a pull-up on the board. diff --git a/ports/esp8266/common-hal/busio/SPI.c b/ports/esp8266/common-hal/busio/SPI.c index aa2b3a3547..b862c1da79 100644 --- a/ports/esp8266/common-hal/busio/SPI.c +++ b/ports/esp8266/common-hal/busio/SPI.c @@ -67,6 +67,7 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2); spi_clock(HSPI, SPI_CLK_PREDIV, SPI_CLK_CNTDIV); + self->frequency = SPI_CLK_FREQ; spi_tx_byte_order(HSPI, SPI_BYTE_ORDER_HIGH_TO_LOW); spi_rx_byte_order(HSPI, SPI_BYTE_ORDER_HIGH_TO_LOW); @@ -107,6 +108,7 @@ bool common_hal_busio_spi_configure(busio_spi_obj_t *self, // Special case for full speed. spi_init_gpio(HSPI, SPI_CLK_80MHZ_NODIV); spi_clock(HSPI, 0, 0); + self->frequency = 80000000L; } else if (baudrate > 40000000L) { return false; } else { @@ -118,6 +120,7 @@ bool common_hal_busio_spi_configure(busio_spi_obj_t *self, } spi_init_gpio(HSPI, SPI_CLK_USE_DIV); spi_clock(HSPI, prediv, cntdiv); + self->frequency = 80000000L / (prediv * cntdiv); } spi_mode(HSPI, phase, polarity); return true; @@ -205,3 +208,7 @@ bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, uint8_t *data_out, uin return true; } + +uint32_t common_hal_busio_spi_get_frequency(busio_spi_obj_t* self) { + return self->frequency; +} diff --git a/ports/esp8266/common-hal/busio/SPI.h b/ports/esp8266/common-hal/busio/SPI.h index 24822ca3c8..ba9a5268e0 100644 --- a/ports/esp8266/common-hal/busio/SPI.h +++ b/ports/esp8266/common-hal/busio/SPI.h @@ -33,6 +33,7 @@ typedef struct { mp_obj_base_t base; + uint32_t frequency; bool locked; bool deinited; } busio_spi_obj_t; diff --git a/ports/esp8266/posix_helpers.c b/ports/esp8266/posix_helpers.c index 1fc677c5c5..1c20c8b0b1 100644 --- a/ports/esp8266/posix_helpers.c +++ b/ports/esp8266/posix_helpers.c @@ -33,7 +33,7 @@ // Functions for external libs like axTLS, BerkeleyDB, etc. void *malloc(size_t size) { - void *p = gc_alloc(size, false); + void *p = gc_alloc(size, false, false); if (p == NULL) { // POSIX requires ENOMEM to be set in case of error errno = ENOMEM; diff --git a/shared-bindings/busio/SPI.c b/shared-bindings/busio/SPI.c index c4c139105f..d68b61d9b4 100644 --- a/shared-bindings/busio/SPI.c +++ b/shared-bindings/busio/SPI.c @@ -36,7 +36,7 @@ #include "lib/utils/buffer_helper.h" #include "lib/utils/context_manager_helpers.h" #include "py/mperrno.h" -#include "py/nlr.h" +#include "py/objproperty.h" #include "py/runtime.h" //| .. currentmodule:: busio @@ -137,7 +137,9 @@ static void check_lock(busio_spi_obj_t *self) { //| //| Configures the SPI bus. Only valid when locked. //| -//| :param int baudrate: the clock rate in Hertz +//| :param int baudrate: the desired clock rate in Hertz. The actual clock rate may be higher or lower +//| due to the granularity of available clock settings. +//| Check the `frequency` attribute for the actual clock rate. //| :param int polarity: the base state of the clock line (0 or 1) //| :param int phase: the edge of the clock that data is captured. First (0) //| or second (1). Rising or falling depends on clock polarity. @@ -350,6 +352,25 @@ STATIC mp_obj_t busio_spi_write_readinto(size_t n_args, const mp_obj_t *pos_args } MP_DEFINE_CONST_FUN_OBJ_KW(busio_spi_write_readinto_obj, 2, busio_spi_write_readinto); +//| .. attribute:: frequency +//| +//| The actual SPI bus frequency. This may not match the frequency requested +//| due to internal limitations. +//| +STATIC mp_obj_t busio_spi_obj_get_frequency(mp_obj_t self_in) { + busio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); + raise_error_if_deinited(common_hal_busio_spi_deinited(self)); + return MP_OBJ_NEW_SMALL_INT(common_hal_busio_spi_get_frequency(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(busio_spi_get_frequency_obj, busio_spi_obj_get_frequency); + +const mp_obj_property_t busio_spi_frequency_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&busio_spi_get_frequency_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + STATIC const mp_rom_map_elem_t busio_spi_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&busio_spi_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, @@ -362,6 +383,7 @@ STATIC const mp_rom_map_elem_t busio_spi_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&busio_spi_readinto_obj) }, { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&busio_spi_write_obj) }, { MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&busio_spi_write_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_frequency), MP_ROM_PTR(&busio_spi_frequency_obj) } }; STATIC MP_DEFINE_CONST_DICT(busio_spi_locals_dict, busio_spi_locals_dict_table); diff --git a/shared-bindings/busio/SPI.h b/shared-bindings/busio/SPI.h index b6e5c9b1b3..555f32c928 100644 --- a/shared-bindings/busio/SPI.h +++ b/shared-bindings/busio/SPI.h @@ -58,4 +58,7 @@ extern bool common_hal_busio_spi_read(busio_spi_obj_t *self, uint8_t *data, size // Reads and write len bytes simultaneously. extern bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, uint8_t *data_out, uint8_t *data_in, size_t len); +// Return actual SPI bus frequency. +uint32_t common_hal_busio_spi_get_frequency(busio_spi_obj_t* self); + #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_SPI_H