Missing i2c slave functions. #508

Open
opened 2021-07-14 08:28:02 -05:00 by ghost · 1 comment
ghost commented 2021-07-14 08:28:02 -05:00 (Migrated from github.com)

Hello,

I believe that there is currently no helper function for proper i2c slave support.

To get a pico working as a i2c slave cache of 256 bytes, I had to do something like this:

#include <stdio.h>

#include "pico/stdlib.h"
#include "hardware/i2c.h"
#include "hardware/irq.h"

#define I2C0_SLAVE_ADDR 0x04

#define GPIO_SDA0 0
#define GPIO_SCK0 1

uint8_t ram_addr;
uint8_t ram[256];

void i2c0_irq_handler() {
    uint32_t status = i2c0_hw->intr_stat;
    uint32_t value;

    /* Check to see if we have received data from the I2C master. */
    if (status & I2C_IC_INTR_STAT_R_RX_FULL_BITS) {
        /* Read the data (this will clear the interrupt). */
        value = i2c0_hw->data_cmd;

        /* Check if this is the first byte we have received. */
        if (value & I2C_IC_DATA_CMD_FIRST_DATA_BYTE_BITS) {
            ram_addr = (uint8_t)(value & I2C_IC_DATA_CMD_BITS);
        }
        else {
            /* If it is not the first byte, store the data in the RAM. */
            ram[ram_addr++] = (uint8_t)(value & I2C_IC_DATA_CMD_BITS);
        }
    }

    /* Check if the I2C master is requesting data from us. */
    if (status & I2C_IC_INTR_STAT_R_RD_REQ_BITS) {
        /* Write the data from the current address in RAM. */
        i2c0_hw->data_cmd = (uint32_t)(ram[ram_addr++]);

        /* Clear the interrupt. */
        i2c0_hw->clr_rd_req;
    }
}

int main() {
    stdio_init_all();

    i2c_init(i2c0, 100e3);
    i2c_set_slave_mode(i2c0, true, I2C0_SLAVE_ADDR);

    gpio_set_function(GPIO_SDA0, GPIO_FUNC_I2C);
    gpio_set_function(GPIO_SCK0, GPIO_FUNC_I2C);
    gpio_pull_up(GPIO_SDA0);
    gpio_pull_up(GPIO_SCK0);

    ram_addr = 0;

    /* Select the interrupts we want. */
    i2c0_hw->intr_mask = I2C_IC_INTR_MASK_M_RD_REQ_BITS
        | I2C_IC_INTR_MASK_M_RX_FULL_BITS;

    /* Set up the interrupt handler. */
    irq_set_exclusive_handler(I2C0_IRQ, i2c0_irq_handler);
    /* Enable I2C interrupts. */
    irq_set_enabled(I2C0_IRQ, true);

    while (true) {
        tight_loop_contents();
    }

    return 0;
}

I feel like there should be a function that takes some of the work away, like selecting the interrupts and setting the irq_handler.

Hello, I believe that there is currently no helper function for proper i2c slave support. To get a pico working as a i2c slave cache of 256 bytes, I had to do something like this: ```c++ #include <stdio.h> #include "pico/stdlib.h" #include "hardware/i2c.h" #include "hardware/irq.h" #define I2C0_SLAVE_ADDR 0x04 #define GPIO_SDA0 0 #define GPIO_SCK0 1 uint8_t ram_addr; uint8_t ram[256]; void i2c0_irq_handler() { uint32_t status = i2c0_hw->intr_stat; uint32_t value; /* Check to see if we have received data from the I2C master. */ if (status & I2C_IC_INTR_STAT_R_RX_FULL_BITS) { /* Read the data (this will clear the interrupt). */ value = i2c0_hw->data_cmd; /* Check if this is the first byte we have received. */ if (value & I2C_IC_DATA_CMD_FIRST_DATA_BYTE_BITS) { ram_addr = (uint8_t)(value & I2C_IC_DATA_CMD_BITS); } else { /* If it is not the first byte, store the data in the RAM. */ ram[ram_addr++] = (uint8_t)(value & I2C_IC_DATA_CMD_BITS); } } /* Check if the I2C master is requesting data from us. */ if (status & I2C_IC_INTR_STAT_R_RD_REQ_BITS) { /* Write the data from the current address in RAM. */ i2c0_hw->data_cmd = (uint32_t)(ram[ram_addr++]); /* Clear the interrupt. */ i2c0_hw->clr_rd_req; } } int main() { stdio_init_all(); i2c_init(i2c0, 100e3); i2c_set_slave_mode(i2c0, true, I2C0_SLAVE_ADDR); gpio_set_function(GPIO_SDA0, GPIO_FUNC_I2C); gpio_set_function(GPIO_SCK0, GPIO_FUNC_I2C); gpio_pull_up(GPIO_SDA0); gpio_pull_up(GPIO_SCK0); ram_addr = 0; /* Select the interrupts we want. */ i2c0_hw->intr_mask = I2C_IC_INTR_MASK_M_RD_REQ_BITS | I2C_IC_INTR_MASK_M_RX_FULL_BITS; /* Set up the interrupt handler. */ irq_set_exclusive_handler(I2C0_IRQ, i2c0_irq_handler); /* Enable I2C interrupts. */ irq_set_enabled(I2C0_IRQ, true); while (true) { tight_loop_contents(); } return 0; } ``` I feel like there should be a function that takes some of the work away, like selecting the interrupts and setting the irq_handler.
kilograham commented 2021-07-27 16:31:53 -05:00 (Migrated from github.com)

it is a reasonable request

it is a reasonable request
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
gh-raspberrypi/pico-sdk#508
No description provided.