Skip to content

RP2040: Implement short I2C writes (2 bytes or less) using bitbangio #4315

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Mar 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ports/raspberrypi/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ SRC_SDK := \
src/common/pico_sync/lock_core.c \
src/common/pico_sync/mutex.c \
src/common/pico_time/time.c \
src/common/pico_time/timeout_helper.c \
src/common/pico_util/pheap.c \
src/rp2_common/hardware_adc/adc.c \
src/rp2_common/hardware_claim/claim.c \
Expand Down
75 changes: 59 additions & 16 deletions ports/raspberrypi/common-hal/busio/I2C.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,23 @@
* THE SOFTWARE.
*/

#include "shared-bindings/busio/I2C.h"
#include "py/mperrno.h"
#include "py/mphal.h"
#include "shared-bindings/busio/I2C.h"
#include "py/runtime.h"

#include "shared-bindings/microcontroller/__init__.h"
#include "supervisor/shared/translate.h"
#include "shared-bindings/bitbangio/I2C.h"

#include "src/rp2_common/hardware_gpio/include/hardware/gpio.h"

// Synopsys DW_apb_i2c (v2.01) IP

#define NO_PIN 0xff

// One second
#define BUS_TIMEOUT_US 1000000

STATIC bool never_reset_i2c[2];
STATIC i2c_inst_t* i2c[2] = {i2c0, i2c1};

Expand Down Expand Up @@ -94,15 +98,23 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self,
}
#endif

gpio_set_function(sda->number, GPIO_FUNC_I2C);
gpio_set_function(scl->number, GPIO_FUNC_I2C);
// Create a bitbangio.I2C object to do short writes.
// Must be done before setting up the I2C pins, since they will be
// set up as GPIO by the bitbangio.I2C object.
//
// Sets pins to open drain, high, and input.
shared_module_bitbangio_i2c_construct(&self->bitbangio_i2c, scl, sda,
frequency, timeout);

self->baudrate = i2c_init(self->peripheral, frequency);

self->sda_pin = sda->number;
self->scl_pin = scl->number;
claim_pin(sda);
self->sda_pin = sda->number;
claim_pin(scl);
claim_pin(sda);

gpio_set_function(self->scl_pin, GPIO_FUNC_I2C);
gpio_set_function(self->sda_pin, GPIO_FUNC_I2C);
}

bool common_hal_busio_i2c_deinited(busio_i2c_obj_t *self) {
Expand All @@ -124,8 +136,7 @@ void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) {
}

bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) {
uint8_t fake_read = 0;
return i2c_read_blocking(self->peripheral, addr, &fake_read, 1, false) != PICO_ERROR_GENERIC;
return common_hal_busio_i2c_write(self, addr, NULL, 0, true) == 0;
}

bool common_hal_busio_i2c_try_lock(busio_i2c_obj_t *self) {
Expand All @@ -147,24 +158,56 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) {

uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr,
const uint8_t *data, size_t len, bool transmit_stop_bit) {
int result = i2c_write_blocking(self->peripheral, addr, data, len, !transmit_stop_bit);
if (len <= 2) {
// The RP2040 I2C peripheral will not do writes 2 bytes or less long.
// So use bitbangio.I2C to do the write.

gpio_set_function(self->scl_pin, GPIO_FUNC_SIO);
gpio_set_function(self->sda_pin, GPIO_FUNC_SIO);
gpio_set_dir(self->scl_pin, GPIO_IN);
gpio_set_dir(self->sda_pin, GPIO_IN);
gpio_put(self->scl_pin, false);
gpio_put(self->sda_pin, false);

uint8_t status = shared_module_bitbangio_i2c_write(&self->bitbangio_i2c,
addr, data, len, transmit_stop_bit);

// The pins must be set back to GPIO_FUNC_I2C in the order given here,
// SCL first, otherwise reads will hang.
gpio_set_function(self->scl_pin, GPIO_FUNC_I2C);
gpio_set_function(self->sda_pin, GPIO_FUNC_I2C);

return status;
}

int result = i2c_write_timeout_us(self->peripheral, addr, data, len, !transmit_stop_bit, BUS_TIMEOUT_US);
if (result == len) {
return 0;
} else if (result == PICO_ERROR_GENERIC) {
return MP_ENODEV;
}
return MP_EIO;
switch (result) {
case PICO_ERROR_GENERIC:
return MP_ENODEV;
case PICO_ERROR_TIMEOUT:
return MP_ETIMEDOUT;
default:
return MP_EIO;
}
}

uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr,
uint8_t *data, size_t len) {
int result = i2c_read_blocking(self->peripheral, addr, data, len, false);
int result = i2c_read_timeout_us(self->peripheral, addr, data, len, false, BUS_TIMEOUT_US);
if (result == len) {
return 0;
} else if (result == PICO_ERROR_GENERIC) {
return MP_ENODEV;
}
return MP_EIO;
switch (result) {
case PICO_ERROR_GENERIC:
return MP_ENODEV;
case PICO_ERROR_TIMEOUT:
return MP_ETIMEDOUT;
default:
return MP_EIO;
}
}

void common_hal_busio_i2c_never_reset(busio_i2c_obj_t *self) {
Expand Down
2 changes: 2 additions & 0 deletions ports/raspberrypi/common-hal/busio/I2C.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#define MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_BUSIO_I2C_H

#include "common-hal/microcontroller/Pin.h"
#include "shared-module/bitbangio/I2C.h"

#include "py/obj.h"

Expand All @@ -36,6 +37,7 @@
typedef struct {
mp_obj_base_t base;
i2c_inst_t * peripheral;
bitbangio_i2c_obj_t bitbangio_i2c;
bool has_lock;
uint baudrate;
uint8_t scl_pin;
Expand Down
2 changes: 1 addition & 1 deletion shared-bindings/bitbangio/I2C.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
#include "py/obj.h"

#include "common-hal/microcontroller/Pin.h"
#include "shared-module/bitbangio/types.h"
#include "shared-module/bitbangio/I2C.h"

// Type object used in Python. Should be shared between ports.
extern const mp_obj_type_t bitbangio_i2c_type;
Expand Down
2 changes: 1 addition & 1 deletion shared-bindings/bitbangio/OneWire.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
#define MICROPY_INCLUDED_SHARED_BINDINGS_BITBANGIO_ONEWIRE_H

#include "common-hal/microcontroller/Pin.h"
#include "shared-module/bitbangio/types.h"
#include "shared-module/bitbangio/OneWire.h"

extern const mp_obj_type_t bitbangio_onewire_type;

Expand Down
2 changes: 1 addition & 1 deletion shared-bindings/bitbangio/SPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
#include "py/obj.h"

#include "common-hal/microcontroller/Pin.h"
#include "shared-module/bitbangio/types.h"
#include "shared-module/bitbangio/SPI.h"

// Type object used in Python. Should be shared between ports.
extern const mp_obj_type_t bitbangio_spi_type;
Expand Down
1 change: 0 additions & 1 deletion shared-bindings/bitbangio/__init__.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
#include "shared-bindings/bitbangio/I2C.h"
#include "shared-bindings/bitbangio/OneWire.h"
#include "shared-bindings/bitbangio/SPI.h"
#include "shared-module/bitbangio/types.h"

#include "py/runtime.h"

Expand Down
1 change: 0 additions & 1 deletion shared-module/bitbangio/I2C.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
#include "common-hal/microcontroller/Pin.h"
#include "shared-bindings/microcontroller/__init__.h"
#include "shared-bindings/digitalio/DigitalInOut.h"
#include "shared-module/bitbangio/types.h"
#include "supervisor/shared/translate.h"

STATIC void delay(bitbangio_i2c_obj_t *self) {
Expand Down
43 changes: 43 additions & 0 deletions shared-module/bitbangio/I2C.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2016 Scott Shawcroft
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#ifndef MICROPY_INCLUDED_SHARED_MODULE_BITBANGIO_I2C_H
#define MICROPY_INCLUDED_SHARED_MODULE_BITBANGIO_I2C_H

#include "common-hal/digitalio/DigitalInOut.h"

#include "py/obj.h"

typedef struct {
mp_obj_base_t base;
digitalio_digitalinout_obj_t scl;
digitalio_digitalinout_obj_t sda;
uint32_t us_delay;
uint32_t us_timeout;
volatile bool locked;
} bitbangio_i2c_obj_t;

#endif // MICROPY_INCLUDED_SHARED_MODULE_BITBANGIO_I2C_H
1 change: 0 additions & 1 deletion shared-module/bitbangio/OneWire.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
#include "shared-bindings/bitbangio/OneWire.h"
#include "shared-bindings/microcontroller/__init__.h"
#include "shared-bindings/digitalio/DigitalInOut.h"
#include "shared-module/bitbangio/types.h"

// Durations are taken from here: https://www.maximintegrated.com/en/app-notes/index.mvp/id/126

Expand Down
39 changes: 39 additions & 0 deletions shared-module/bitbangio/OneWire.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2016 Scott Shawcroft
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#ifndef MICROPY_INCLUDED_SHARED_MODULE_BITBANGIO_ONEWIRE_H
#define MICROPY_INCLUDED_SHARED_MODULE_BITBANGIO_ONEWIRE_H

#include "common-hal/digitalio/DigitalInOut.h"

#include "py/obj.h"

typedef struct {
mp_obj_base_t base;
digitalio_digitalinout_obj_t pin;
} bitbangio_onewire_obj_t;

#endif // MICROPY_INCLUDED_SHARED_MODULE_BITBANGIO_ONEWIRE_H
4 changes: 2 additions & 2 deletions shared-module/bitbangio/SPI.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@
#include "py/runtime.h"

#include "common-hal/microcontroller/Pin.h"
#include "shared-bindings/microcontroller/__init__.h"
#include "shared-bindings/bitbangio/SPI.h"
#include "shared-bindings/digitalio/DigitalInOut.h"
#include "shared-module/bitbangio/types.h"
#include "shared-bindings/microcontroller/__init__.h"
#include "supervisor/shared/translate.h"

#define MAX_BAUDRATE (common_hal_mcu_get_clock_frequency() / 48)
Expand Down
20 changes: 3 additions & 17 deletions shared-module/bitbangio/types.h → shared-module/bitbangio/SPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,27 +24,13 @@
* THE SOFTWARE.
*/

#ifndef MICROPY_INCLUDED_SHARED_MODULE_BITBANGIO_TYPES_H
#define MICROPY_INCLUDED_SHARED_MODULE_BITBANGIO_TYPES_H
#ifndef MICROPY_INCLUDED_SHARED_MODULE_BITBANGIO_SPI_H
#define MICROPY_INCLUDED_SHARED_MODULE_BITBANGIO_SPI_H

#include "common-hal/digitalio/DigitalInOut.h"

#include "py/obj.h"

typedef struct {
mp_obj_base_t base;
digitalio_digitalinout_obj_t scl;
digitalio_digitalinout_obj_t sda;
uint32_t us_delay;
uint32_t us_timeout;
volatile bool locked;
} bitbangio_i2c_obj_t;

typedef struct {
mp_obj_base_t base;
digitalio_digitalinout_obj_t pin;
} bitbangio_onewire_obj_t;

typedef struct {
mp_obj_base_t base;
digitalio_digitalinout_obj_t clock;
Expand All @@ -58,4 +44,4 @@ typedef struct {
volatile bool locked:1;
} bitbangio_spi_obj_t;

#endif // MICROPY_INCLUDED_SHARED_MODULE_BITBANGIO_TYPES_H
#endif // MICROPY_INCLUDED_SHARED_MODULE_BITBANGIO_SPI_H
2 changes: 1 addition & 1 deletion shared-module/busio/I2C.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
#ifndef MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BUSIO_I2C_H
#define MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BUSIO_I2C_H

#include "shared-module/bitbangio/types.h"
#include "shared-module/bitbangio/I2C.h"

#include "py/obj.h"

Expand Down
2 changes: 1 addition & 1 deletion shared-module/busio/OneWire.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
#ifndef MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BUSIO_ONEWIRE_H
#define MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BUSIO_ONEWIRE_H

#include "shared-module/bitbangio/types.h"
#include "shared-module/bitbangio/OneWire.h"

#include "py/obj.h"

Expand Down
1 change: 0 additions & 1 deletion supervisor/shared/rgb_led_status.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ static uint8_t status_apa102_color[APA102_BUFFER_LENGTH] = {0, 0, 0, 0, 0xff, 0,

#if CIRCUITPY_BITBANG_APA102
#include "shared-bindings/bitbangio/SPI.h"
#include "shared-module/bitbangio/types.h"
static bitbangio_spi_obj_t status_apa102 = {
.base = {
.type = &bitbangio_spi_type,
Expand Down