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]

Issues
  • `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
  • 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
  • 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 31 May 15, 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 18 Jan 17, 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 104 Jun 21, 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 28 Apr 3, 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 143 Jun 27, 2022
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 8 Jun 20, 2022
A C library for RP2040-powered boards to control LCDs via the I2C protocol

picoi2clcd A C library to control I2C LCD displays using the Rapsberry Pi Pico (or really any board using the RP2040 microcontroller). License All of

Kosmas Raptis 2 Oct 16, 2021
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 189 Jun 25, 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 Jun 19, 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 20 Apr 29, 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 52 Jun 26, 2022
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 34 Apr 7, 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 31 Jun 6, 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 44 Jun 10, 2022
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 553 Jun 22, 2022