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:
Dan Halbert 2018-01-30 12:09:12 -08:00 committed by GitHub
commit 6085599963
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 77 additions and 20 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -33,6 +33,7 @@
typedef struct {
mp_obj_base_t base;
uint32_t frequency;
bool locked;
bool deinited;
} busio_spi_obj_t;

View File

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

View File

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

View File

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

View File

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