Merge pull request #719 from tannewt/fix_i2c_hang
Fix I2C init hang when the SCL pin is pulled low.
This commit is contained in:
commit
77938db8c8
@ -34,6 +34,7 @@
|
|||||||
|
|
||||||
#include "peripherals.h"
|
#include "peripherals.h"
|
||||||
#include "pins.h"
|
#include "pins.h"
|
||||||
|
#include "shared-bindings/microcontroller/__init__.h"
|
||||||
|
|
||||||
|
|
||||||
// Number of times to try to send packet if failed.
|
// Number of times to try to send packet if failed.
|
||||||
@ -72,24 +73,46 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self,
|
|||||||
mp_raise_ValueError("Invalid pins");
|
mp_raise_ValueError("Invalid pins");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test that the pins are in a high state. (Hopefully indicating they are pulled up.)
|
||||||
|
gpio_set_pin_function(sda->pin, GPIO_PIN_FUNCTION_OFF);
|
||||||
|
gpio_set_pin_function(scl->pin, GPIO_PIN_FUNCTION_OFF);
|
||||||
|
gpio_set_pin_direction(sda->pin, GPIO_DIRECTION_IN);
|
||||||
|
gpio_set_pin_direction(scl->pin, GPIO_DIRECTION_IN);
|
||||||
|
|
||||||
|
gpio_set_pin_pull_mode(sda->pin, GPIO_PULL_DOWN);
|
||||||
|
gpio_set_pin_pull_mode(scl->pin, GPIO_PULL_DOWN);
|
||||||
|
|
||||||
|
common_hal_mcu_delay_us(10);
|
||||||
|
|
||||||
|
gpio_set_pin_pull_mode(sda->pin, GPIO_PULL_OFF);
|
||||||
|
gpio_set_pin_pull_mode(scl->pin, GPIO_PULL_OFF);
|
||||||
|
|
||||||
|
// We must pull up within 3us to achieve 400khz.
|
||||||
|
common_hal_mcu_delay_us(3);
|
||||||
|
|
||||||
|
if (!gpio_get_pin_level(sda->pin) || !gpio_get_pin_level(scl->pin)) {
|
||||||
|
reset_pin(sda->pin);
|
||||||
|
reset_pin(scl->pin);
|
||||||
|
mp_raise_RuntimeError("SDA or SCL needs a pull up");
|
||||||
|
}
|
||||||
|
gpio_set_pin_function(sda->pin, sda_pinmux);
|
||||||
|
gpio_set_pin_function(scl->pin, scl_pinmux);
|
||||||
|
|
||||||
// Set up I2C clocks on sercom.
|
// Set up I2C clocks on sercom.
|
||||||
samd_peripherals_sercom_clock_init(sercom, sercom_index);
|
samd_peripherals_sercom_clock_init(sercom, sercom_index);
|
||||||
|
|
||||||
if (i2c_m_sync_init(&self->i2c_desc, sercom) != ERR_NONE) {
|
if (i2c_m_sync_init(&self->i2c_desc, sercom) != ERR_NONE) {
|
||||||
|
reset_pin(sda->pin);
|
||||||
|
reset_pin(scl->pin);
|
||||||
mp_raise_OSError(MP_EIO);
|
mp_raise_OSError(MP_EIO);
|
||||||
}
|
}
|
||||||
|
|
||||||
gpio_set_pin_pull_mode(sda->pin, GPIO_PULL_OFF);
|
|
||||||
gpio_set_pin_function(sda->pin, sda_pinmux);
|
|
||||||
|
|
||||||
gpio_set_pin_pull_mode(scl->pin, GPIO_PULL_OFF);
|
|
||||||
gpio_set_pin_function(scl->pin, scl_pinmux);
|
|
||||||
|
|
||||||
// clkrate is always 0. baud_rate is in kHz.
|
// clkrate is always 0. baud_rate is in kHz.
|
||||||
|
|
||||||
// Frequency must be set before the I2C device is enabled.
|
// Frequency must be set before the I2C device is enabled.
|
||||||
if (i2c_m_sync_set_baudrate(&self->i2c_desc, 0, frequency / 1000) != ERR_NONE) {
|
if (i2c_m_sync_set_baudrate(&self->i2c_desc, 0, frequency / 1000) != ERR_NONE) {
|
||||||
|
reset_pin(sda->pin);
|
||||||
|
reset_pin(scl->pin);
|
||||||
mp_raise_ValueError("Unsupported baudrate");
|
mp_raise_ValueError("Unsupported baudrate");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user