Merge pull request #560 from dhalbert/3.0_issue_464_spi_baud_rate
Correct computation of SPI baud rate register value, and allow for the value to be 0.
This commit is contained in:
commit
6085599963
@ -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));
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -33,6 +33,7 @@
|
||||
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
uint32_t frequency;
|
||||
bool locked;
|
||||
bool deinited;
|
||||
} busio_spi_obj_t;
|
||||
|
@ -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;
|
||||
|
@ -184,3 +184,23 @@ 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) {
|
||||
switch (self->spi->FREQUENCY) {
|
||||
case SPI_FREQUENCY_FREQUENCY_K125:
|
||||
return 125000;
|
||||
case SPI_FREQUENCY_FREQUENCY_K250:
|
||||
return 250000;
|
||||
case SPI_FREQUENCY_FREQUENCY_K500:
|
||||
return 500000;
|
||||
case SPI_FREQUENCY_FREQUENCY_M1:
|
||||
return 1000000;
|
||||
case SPI_FREQUENCY_FREQUENCY_M2:
|
||||
return 2000000;
|
||||
case SPI_FREQUENCY_FREQUENCY_M4:
|
||||
return 4000000;
|
||||
case SPI_FREQUENCY_FREQUENCY_M8:
|
||||
return 8000000;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -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,12 @@ 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.
|
||||
//| **Note:** on the SAMD21, it is possible to set the baud rate to 24 MHz, but that
|
||||
//| speed is not guaranteed to work. 12 MHz is the next available lower speed, and is
|
||||
//| within spec for the SAMD21.
|
||||
//| :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 +355,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 +386,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);
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user