From fcd1788937c267da7eddea1925391b906a49e9e6 Mon Sep 17 00:00:00 2001 From: robert-hh Date: Wed, 16 Nov 2022 08:17:48 +0100 Subject: [PATCH] samd: Avoid under-/overflow in I2C and SPI baudrate calculations. Applies to both SPI and I2C. The underflow caused high baudrate settings resulting in the lowest possible baudrate. The overflow resulted in erratic baudrates, not just the lowest possible. --- ports/samd/machine_i2c.c | 11 +++++++++-- ports/samd/machine_spi.c | 8 +++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/ports/samd/machine_i2c.c b/ports/samd/machine_i2c.c index d943b6b2f4..76d24674f0 100644 --- a/ports/samd/machine_i2c.c +++ b/ports/samd/machine_i2c.c @@ -35,7 +35,7 @@ #include "clock_config.h" #define DEFAULT_I2C_FREQ (400000) -#define RISETIME_NS (300) +#define RISETIME_NS (200) #define I2C_TIMEOUT (100) #define IS_BUS_BUSY (i2c->I2CM.STATUS.bit.BUSSTATE == 3) @@ -184,7 +184,14 @@ mp_obj_t machine_i2c_make_new(const mp_obj_type_t *type, size_t n_args, size_t n // baud = peripheral_freq / (2 * baudrate) - 5 - (rise_time * peripheral_freq) / 2 // Just set the minimal configuration for standard and fast mode. // Set Baud. Assume ~300ns rise time. Maybe set later by a keyword argument. - i2c->I2CM.BAUD.reg = get_peripheral_freq() / (2 * self->freq) - 5 - (get_peripheral_freq() / 1000000) * RISETIME_NS / 2000; + int32_t baud = get_peripheral_freq() / (2 * self->freq) - 5 - (get_peripheral_freq() / 1000000) * RISETIME_NS / 2000; + if (baud < 0) { + baud = 0; + } + if (baud > 255) { + baud = 255; + } + i2c->I2CM.BAUD.reg = baud; // Enable interrupts sercom_register_irq(self->id, &common_i2c_irq_handler); diff --git a/ports/samd/machine_spi.c b/ports/samd/machine_spi.c index 4ffc7095cc..d2cdf2cd4c 100644 --- a/ports/samd/machine_spi.c +++ b/ports/samd/machine_spi.c @@ -208,7 +208,13 @@ STATIC void machine_spi_init(mp_obj_base_t *self_in, size_t n_args, const mp_obj // SPI is driven by the clock of GCLK Generator 2, freq by get_peripheral_freq() // baud = bus_freq / (2 * baudrate) - 1 - uint32_t baud = get_peripheral_freq() / (2 * self->baudrate) - 1; + uint32_t baud = get_peripheral_freq() / (2 * self->baudrate); + if (baud > 0) { // Avoid underflow + baud -= 1; + } + if (baud > 255) { // Avoid overflow + baud = 255; + } spi->SPI.BAUD.reg = baud; // Set Baud // Enable RXC interrupt only if miso is defined