I2C slave library for the Raspberry Pi Pico

Overview

I2C slave library for the Raspberry Pi Pico

The Raspberry Pi Pico C/C++ SDK has all you need to write an I2C master, but is curiously lacking when it comes to I2C in slave mode. This library fills that gap to easily turn the Pico into an I2C slave.

Example

An example program is included where the slave acts as a 256 byte external memory.

To keep it simple, both master and slave run on the same board. Just wire up the two I2C instances: GP4 to GP6 (SDA), and GP5 to GP7 (SCL).

Building

Follow the instructions in Getting started with Raspberry Pi Pico to setup your build environment. Then:

  • clone repo
  • mkdir build, cd build, cmake ../, make
  • copy i2c_slave_example.uf2 to Raspberry Pico
  • open a serial connection and check output

Links

Authors

Valentin Milea [email protected]

Comments
  • `i2c_write_byte` discards byte if TX FIFO buffer is full

    `i2c_write_byte` discards byte if TX FIFO buffer is full

    Hi thx for the library code u provided. This got me a working back and forth comm with an ESP32 with wire library.

    I had to add some stall loops to the i2c_write_byte function to transmit multiple bytes (20) in a row. Without the code only 17 went thru.

    I added the i2c_wait_until_ready_to_write function, which I then use in i2c_write_byte to make sure the buffer is ready to send.

    /**
     * \brief Checks the Tx FIFO if not full
     * If full stall for maximum `max_wait_loops` times, 
     * returns false if the buffer was still full.
     * 
     * \param i2c I2C instance.
     * \param max_wait_loops stall this amount of loops until buffer is ready.
     */
        static inline bool i2c_wait_until_ready_to_write(i2c_inst_t *i2c, uint16_t max_wait_loops)
        {
            i2c_hw_t *hw = i2c_get_hw(i2c);
            while (!(hw->status & I2C_IC_STATUS_TFNF_BITS))
            {
                if (max_wait_loops-- == 0)
                    return false;
            }
            return true;
        }
    
    /**
     * \brief Push a byte into I2C Tx FIFO.
     * 
     * \param i2c I2C instance.
     * \param value Byte value.
     */
        static inline void i2c_write_byte(i2c_inst_t *i2c, uint8_t value)
        {
            i2c_hw_t *hw = i2c_get_hw(i2c);
            i2c_wait_until_ready_to_write(i2c, 3000);                     // required to wait for tx buffer to send
            hard_assert_if(I2C, !(hw->status & I2C_IC_STATUS_TFNF_BITS)); // Tx FIFO must not be full
            hw->data_cmd = value;
        }
    

    maybe there is a better way to request a flush/send.

    opened by constant-flow 5
  • I2C_SLAVE_FINISH before transmission is done

    I2C_SLAVE_FINISH before transmission is done

    I am using a pycom device as I2C master running MicroPython. When I try to send/read some bytes, this is the order that the pico_i2c_slave i2c_slave_handler triggers:

    1. I2C_SLAVE_RECEIVE
    2. I2C_SLAVE_FINISH
    3. I2C_SLAVE_RECEIVE

    The first (1) package is correct, but then the "I2C_SLAVE_FINISH" is hit before the actual data is recieved. I have tried this with 4 bytes, and the same happens. What could cause this? Is there something I can try to do?

    Pycom command

    from machine import I2C
    i2c = I2C(0, I2C.MASTER, baudrate=100000)
    i2c.writeto_mem(0x17, 0x00, 0x03)
    

    4 Bytes:

    from machine import I2C
    i2c = I2C(0, I2C.MASTER, baudrate=100000)
    i2c.writeto_mem(0x17, 0x00, b'\x01\x02\x03\x04')
    
    1. I2C_SLAVE_RECEIVE
    2. I2C_SLAVE_FINISH
    3. I2C_SLAVE_RECEIVE
    4. I2C_SLAVE_RECEIVE
    5. I2C_SLAVE_RECEIVE
    6. I2C_SLAVE_RECEIVE
    opened by zzzbatmand 2
  • IRQ callback invoked just once?

    IRQ callback invoked just once?

    I am utilizing your library as you suggested in issue #2 namely

    Produce the data in your main loop, and consume it in the callback. If there's nothing ready to send yet, simply return from the callback and it will be invoked again. For producer-consumer scheme there's buffering and synchronization to deal with.

    I am using pico/util/queue.h to pass the data from the main thread to the interrupt (I also experimented simply with volatile variables). The IRQ gets called without data being ready, and for my application this is a guarantee that will happen all the time, but for now I am just doing a test in which the data is not ready at the beginning. Based on what you wrote above, I expected that the callback would be automatically called a few more times, until the data was ready. Instead, the data gets prepared, but the IRQ callback is never called again, and everything comes to a stall.

    I could make a dummy packet for these situations, but I really want to avoid that, since it's a lot of unnecessary traffic (and some additional code on both the sender and receiver side to deal with) which I really want to avoid. As such, can you please elaborate more on the "it will be invoked again" part? In what circumstances will that happen? Just making a single call to i2c_read_blocking on the controller side, and nothing else on the worker side, does not trigger that re-invocation, only a single invocation (from which I return as discussed above) and then a hang. Should I use timeouts on the controller and re-invoke the read? Or anything else on the callback to sign that the IRQ should not be cleared?

    Sorry for being such a pester, I really counted on I2C to work in both directions and encountering all these issues is a huge disappointment about using the picos for my project.

    opened by davidedelvento 1
  • Intermittent i2c slave mode errors, interrupts delayed or fired in the wrong order resulting in data corruption

    Intermittent i2c slave mode errors, interrupts delayed or fired in the wrong order resulting in data corruption

    Hi, I have been using your very useful library to create some test code to try and get to the bottom of an issue I originally encountered using I2C slave mode with Arduino-Pico.

    I recreated a test scenario using pure SDK and your library and found similar issues, the issues are fully detailed in this post along with scope traces. https://github.com/raspberrypi/pico-sdk/issues/1102

    The issues are only really noticeable at I2C bus speeds above 100KHz. Earle Philhower added a recent commit to his Arduino-Pico Wire API implementation which provides a workaround for the bulk of the issues, getting the failure rate down to around 0.02%, from originally being up to 50% at 1Mhz bus speed. (fast mode plus)

    It looks to me like the remaining issues are with the SDK or maybe the hardware.

    opened by chrisckc 0
  • transfer_in_progress gets stuck to true sometimes at higher bus speeds

    transfer_in_progress gets stuck to true sometimes at higher bus speeds

    Hello! First of all thank you for creating this awesome library. We've used it in the firmware for an open source device we're building (https://github.com/badgeteam/mch2022-firmware-rp2040/tree/renze/i2c-debug).

    We're encountering a problem: if we talk to the RP2040 at low speeds (8kHz bus speed) everything is stable but once we increase the bus speed to 100kHz (or 400kHz) we found that the RP2040 can get into a state where slave->transfer_in_progress gets stuck high until a new transfer is started from the bus master.

    We're using that flag to implement a simple form of locking on the register map, preventing registers to be used by the firmware until the transfer is done. Thus when it gets stuck on true the firmware doesn't handle requests anymore.

    What bus speed did you test this library at and do you have any idea what might be causing the transfer_in_progress flag to get stuck to true until a new transfer gets it unstuck again?

    opened by renzenicolai 1
  • Only with interrupts?

    Only with interrupts?

    Thanks for providing this example, in fact the Raspberry Pi Pico C/C++ SDK is really incomplete in this regard!!!

    Are interrupts like your library does really the only way to implement I2C slave on the Pico?

    I need to do something like the following on my pico slave

    while(true) {
        prepare some stuff
        write some_stuff to the i2c bus # ok to block
    }
    

    Of course I could change that code to use interrupt, but it becomes unnecessary more complicated, so I tried using i2c_write_blocking() and i2c_write_raw_blocking() but those do not seem to be working. Is it really so, or am I doing anything wrong?

    enhancement 
    opened by davidedelvento 8
Owner
Valentin Milea
Valentin Milea
Tetris on a Raspberry Pi Pico mounted on a Pimoroni Pico Explorer

PicoTetris Classic Tetris game running on a Raspberry Pi Pico microcontroller. Pico C port by Richard Birkby Original JavaScript implementation - Jake

Richard Birkby 34 Dec 3, 2022
Breakout game for Raspberry Pi Pico with Pimoroni Pico Display pack

breakout_rpi_pico Breakout game for Raspberry Pi Pico with Pimoroni Pico Display pack Prebuilt binary (breakout.uf2) is here. To build your own binary

null 19 Oct 15, 2022
Pico-uart-bridge - Raspberry Pi Pico UART-USB bridge

Raspberry Pi Pico USB-UART Bridge This program bridges the Raspberry Pi Pico HW UARTs to two independent USB CDC serial devices in order to behave lik

Álvaro Fernández Rojas 156 Dec 23, 2022
Digital rain animation gif with glow squeezed into a raspberry pi pico and pimoroni pico-display

pico-display-matrix Digital rain animation gif with glow squeezed into a raspberry pi pico and pimoroni pico-display or how to actually use all Flash

null 32 Sep 10, 2022
Prueba del Raspberry PI PICO con un display Raspberry PI TFT 3.5"

Raspberry-PI-PICO-display-RPI35 Prueba del Raspberry PI PICO con un display Raspberry PI TFT 3.5" Con ayuda de la libreria https://github.com/khoih-pr

null 1 Nov 10, 2021
This project design to mine Duino-Coin using an Esp8266 as a master and Arduino as a slave.

DuinoCoinI2C This project design to mine Duino-Coin using an Esp8266/Esp32 as a master and Arduino as a slave. Using the I2C communication to connect

Luiz Henrique Cassettari 153 Jan 3, 2023
Streaming video over USB 3.0 using MAX10 FPGA and CYUSB3014 synchronous slave mode.

DECA_USB3_Cam Streaming video over USB 3.0 using MAX10 FPGA and CYUSB3014 synchronous slave mode. Video: Block diagram _______

Dmitry Koroteev 9 Apr 18, 2022
Lib2 - C/C++ Library for Raspberry Pi Pico

Lib2 - C/C++ Library for Raspberry Pi Pico Description: Lib2 library implements wrapper functions and device driver for Raspberry Pi Pico. With lib2 i

Ocean 9 Apr 7, 2022
📚🪛 Arduino library to calibrate and improve ADC measurements with the Raspberry Pi Pico.

Arduino-Pico-Analog-Correction Arduino library to calibrate and improve ADC measurements with the Raspberry Pi Pico. Can compensate ADC offsets, calcu

NuclearPhoenix 11 Jan 3, 2023
Raspberry Pi Pico (RP2040) and Micro-ROS (ROS 2) Integration

The Pico is an amazing microcontroller and I couldn't wait for ROS 2 support or Arduino Core, so here is my approach. Once the Arduino Core for RP2040 is out it will be easier to use micro_ros_arduino.

Darko Lukić 19 Jun 19, 2022
built-in CMSIS-DAP debugger tailored especially for the RP2040 “Raspberry Pi Pico”

RP2040 has two ARM Cortex-M0+ cores, and the second core normally remains dormant. pico-debug runs on one core in a RP2040 and provides a USB CMSIS-DAP interface to debug the other core. No hardware is added; it is as if there were a virtual debug pod built-in.

null 272 Dec 30, 2022
🦠 µnix is a UNIX-like operating system for the raspberry pi pico.

The µnix Operating System "µnix", "munix" or, "micro unix" aims to be a micro kernel based operating system targeting the Raspberry Pi Pico. "µnix" is

Sleepy Monax 57 Dec 11, 2022
Fractal rendering for Raspberry Pi Pico microcontroller

picofract Mandelbrot Set rendering demo for Raspberry Pi Pico microcontroller with Pico Display Pack. Building If you already have the Pimoroni SDK bu

null 22 Dec 7, 2022
Arduino API for the Raspberry Pico

Raspberry PI Pico - Arduino API On Friday I was receiving my Raspberry PI Pico and I had the opportunity to play around with it. Actually most of the

Phil Schatzmann 59 Jan 2, 2023
x86 emulator on Raspberry Pi Pico

picox86 x86 emulator on Raspberry Pi Pico https://user-images.githubusercontent.com/10139098/110543817-13299080-812b-11eb-9c88-674cdae919fc.mp4 PCB fr

null 39 Nov 9, 2022
A laser cut Dreamcast Pop'n Music controller and integrated memory card using the Raspberry Pi Pico's Programmable IO

Dreamcast Pop'n Music Controller Using Raspbery Pi Pico (RP2040) Intro This is a homebrew controller for playing the Pop'n Music games on the Sega Dre

null 42 Dec 29, 2022
Web Server based on the Raspberry Pico using an ESP8266 with AT firmware for WiFi

PicoWebServer This program runs on a Raspberry Pico RP2040 to provide a web server when connected to an Espressif ESP8266. This allows the Pico to be

null 52 Jan 7, 2023
Raspberry Pi Pico Arduino core, for all RP2040 boards

Arduino-Pico Raspberry Pi Pico Arduino core, for all RP2040 boards This is a port of the RP2040 (Raspberry Pi Pico processor) to the Arduino ecosystem

Earle F. Philhower, III 929 Jan 5, 2023
A programming environment for Lua for the Raspberry Pi Pico microcontroller

picolua A programming environment for Lua for the Raspberry Pi Pico microcontroller. Version 0.3, April 2021 What is this? picolua is a proof-of-conce

Kevin Boone 65 Jan 8, 2023