Added I2C Slave to RP2040

Added length to I2C slave callback.
This commit is contained in:
curuvar 2022-07-15 11:28:11 -04:00 committed by Xiang Xiao
parent 2428438037
commit d69d9eb0c9
6 changed files with 847 additions and 20 deletions

View File

@ -0,0 +1,114 @@
/****************************************************************************
* arch/arm/include/rp2040/i2c_slave.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __ARCH_ARM_INCLUDE_RP2040_I2C_SLAVE_H
#define __ARCH_ARM_INCLUDE_RP2040_I2C_SLAVE_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/i2c/i2c_slave.h>
#ifndef __ASSEMBLY__
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/* There is no driver for I2C slave operations. To create an I2C slave,
* include this file (as: <arch/chip/i2c_slave.h>) and use either
* rp2040_i2c0_slave_initialize or rp2040_i2c1_slave_initialize to
* initialize the I2C for slave operations.
*/
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: rp2040_i2c0_slave_initialize
*
* Description:
* Initialize I2C controller zero for slave operation, and return a pointer
* to the instance of struct i2c_slave_s. This function should only be
* called once of a give controller.
*
* Note: the same port cannot be initalized as both master and slave.
*
* Input Parameters:
* rx_buffer - Buffer for data transmitted to us by an I2C master.
* rx_buffer_len - Length of rx_buffer.
* callback - Callback function called when messages are received.
*
* Returned Value:
* Valid I2C device structure reference on success; a NULL on failure
*
****************************************************************************/
#ifdef CONFIG_RP2040_I2C0_SLAVE
struct i2c_slave_s *rp2040_i2c0_slave_initialize
(uint8_t *rx_buffer,
size_t rx_buffer_len,
i2c_slave_callback_t *callback);
#endif
/****************************************************************************
* Name: rp2040_i2c1_slave_initialize
*
* Description:
* Initialize I2C controller zero for slave operation, and return a pointer
* to the instance of struct i2c_slave_s. This function should only be
* called once of a give controller.
*
* Note: the same port cannot be initalized as both master and slave.
*
* Input Parameters:
* rx_buffer - Buffer for data transmitted to us by an I2C master.
* rx_buffer_len - Length of rx_buffer.
* callback - Callback function called when messages are received.
*
* Returned Value:
* Valid I2C device structure reference on success; a NULL on failure
*
****************************************************************************/
#ifdef CONFIG_RP2040_I2C1_SLAVE
struct i2c_slave_s *rp2040_i2c1_slave_initialize
(uint8_t *rx_buffer,
size_t rx_buffer_len,
i2c_slave_callback_t *callback);
#endif
#undef EXTERN
#if defined(__cplusplus)
}
#endif
#endif /* __ASSEMBLY__ */
#endif /* __ARCH_ARM_INCLUDE_RP2040_I2C_SLAVE_H */

View File

@ -118,8 +118,12 @@ config RP2040_SPI_DRIVER
endif
config RP2040_I2C
bool "I2C"
bool "I2C Master"
select I2C
---help---
Build in support for I2C master mode.
Note: Do not configure the same port as both master and slave.
if RP2040_I2C
@ -141,6 +145,86 @@ config RP2040_I2C_DRIVER
endif
config RP2040_I2C_SLAVE
bool "I2C Slave"
select I2C_SLAVE
---help---
Build in support for I2C slave mode.
Note: Do not configure the same port as both master and slave.
if RP2040_I2C_SLAVE
config RP2040_I2C0_SLAVE
bool "I2C0"
if RP2040_I2C0_SLAVE
config RP2040_I2C0_SLAVE_SDA
int "GPIO pin number for SDA (data) line"
default 4
---help---
This pin must be one of: 0, 4, 8, 12, 16, 20, 24, or 28
config RP2040_I2C0_SLAVE_SCL
int "GPIO pin number for SCL (clock) line"
default 5
---help---
This pin must be one of: 1, 5, 9, 13, 17, 21, 25, or 29
config RP2040_I2C0_SLAVE_ADDRESS
int "Slave Address (in decimal)"
default 42
---help---
This is the default address of this device on the I2C bus.
It should be the canonical address (not the shifted address)
in the range 8-119 for 7-bit mode and in the range 0-1023
for 10-bit mode.
config RP2040_I2C0_SLAVE_10BIT
bool "Enable 10-bit slave address"
default n
---help---
Set to enable 10-bit mode addressing.
endif
config RP2040_I2C1_SLAVE
bool "I2C1"
if RP2040_I2C1_SLAVE
config RP2040_I2C1_SLAVE_SDA
int "GPIO pin number for SDA (data) line"
default 6
---help---
This pin must be one of: 2, 6, 10, 14, 18, 22, or 26
config RP2040_I2C1_SLAVE_SCL
int "GPIO pin number for SCL (clock) line"
default 7
---help---
This pin must be one of: 3, 7, 11, 15, 19, 23, or 27
config RP2040_I2C1_SLAVE_ADDRESS
int "Slave Address (in decimal)"
default 42
---help---
This is the default address of this device on the I2C bus.
It should be the canonical address (not the shifted address)
in the range 8-119 for 7-bit mode and in the range 0-1023
for 10-bit mode.
config RP2040_I2C1_SLAVE_10BIT
bool "Enable 10-bit slave address"
default n
---help---
Set to enable 10-bit mode addressing.
endif
endif
menuconfig RP2040_PWM
bool "PWM"
select PWM

View File

@ -57,6 +57,10 @@ ifeq ($(CONFIG_RP2040_I2C),y)
CHIP_CSRCS += rp2040_i2c.c
endif
ifeq ($(CONFIG_RP2040_I2C_SLAVE),y)
CHIP_CSRCS += rp2040_i2c_slave.c
endif
ifeq ($(CONFIG_RP2040_I2S),y)
CHIP_CSRCS += rp2040_i2s.c
CHIP_CSRCS += rp2040_i2s_pio.c

View File

@ -0,0 +1,589 @@
/****************************************************************************
* arch/arm/src/rp2040/rp2040_i2c_slave.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <debug.h>
#include <assert.h>
#include <nuttx/arch.h>
#include <nuttx/i2c/i2c_slave.h>
#include <nuttx/irq.h>
#include <nuttx/kmalloc.h>
#include <arch/chip/i2c_slave.h>
#include <arch/board/board.h>
#include "chip.h"
#include "arm_internal.h"
#include "rp2040_i2c.h"
#include "hardware/rp2040_i2c.h"
#include "hardware/rp2040_resets.h"
#include "rp2040_gpio.h"
#ifdef CONFIG_RP2040_I2C_SLAVE
#define FIFO_LENGTH 16
#define TX_BUF_LEN 8
#define RX_BUF_LEN 8
/****************************************************************************
* Private Types
****************************************************************************/
typedef struct rp2040_i2c_slave_s
{
struct i2c_slave_s dev; /* Generic I2C device */
int8_t controller; /* I2C controller number */
int error; /* Error value */
uint8_t *rx_buffer;
uint8_t *rx_buf_ptr;
uint8_t *rx_buf_end;
const uint8_t *tx_buffer;
const uint8_t *tx_buf_ptr;
const uint8_t *tx_buf_end;
i2c_slave_callback_t *callback; /* Callback function */
void *callback_arg; /* Argument for callback */
} rp2040_i2c_slave_t;
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static int i2c_interrupt(int irq,
void *context,
void *arg);
static int my_set_own_address(struct i2c_slave_s *dev,
int address,
int nbits);
static int my_write(struct i2c_slave_s *dev,
const uint8_t *buffer,
int length);
static int my_read(struct i2c_slave_s *dev,
uint8_t *buffer,
int length);
static int my_register_callback(struct i2c_slave_s *dev,
i2c_slave_callback_t *callback,
void *arg);
static void enable_i2c_slave(struct i2c_slave_s *dev);
/****************************************************************************
* Private Data
****************************************************************************/
struct i2c_slaveops_s i2c_slaveops =
{
.setownaddress = my_set_own_address,
.write = my_write,
.read = my_read,
.registercallback = my_register_callback,
};
#ifdef CONFIG_RP2040_I2C0_SLAVE
rp2040_i2c_slave_t i2c0_slave_dev =
{
.dev.ops = &i2c_slaveops, /* Slave operations */
.controller = 0, /* I2C controller number */
};
#endif
#ifdef CONFIG_RP2040_I2C1_SLAVE
rp2040_i2c_slave_t i2c1_slave_dev =
{
.dev.ops = &i2c_slaveops, /* Slave operations */
.controller = 1, /* I2C controller number */
};
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: i2c_interrupt
*
* Description:
* The I2C Interrupt Handler
*
****************************************************************************/
static int i2c_interrupt(int irq, void *context, void *arg)
{
rp2040_i2c_slave_t *priv = (rp2040_i2c_slave_t *)arg;
uint32_t data_cmd;
uint32_t state;
state = getreg32(RP2040_I2C_IC_INTR_STAT(priv->controller));
/* -- We need to transmit data (Read Request) -- */
if (state & RP2040_I2C_IC_INTR_STAT_R_RD_REQ)
{
if (priv->tx_buf_ptr < priv->tx_buf_end)
{
while (priv->tx_buf_ptr < priv->tx_buf_end
&& getreg32(RP2040_I2C_IC_TXFLR(priv->controller))
< FIFO_LENGTH)
{
putreg32(*priv->tx_buf_ptr++,
RP2040_I2C_IC_DATA_CMD(priv->controller));
}
}
else
{
putreg32(0, RP2040_I2C_IC_DATA_CMD(priv->controller));
}
getreg32(RP2040_I2C_IC_CLR_RD_REQ(priv->controller));
}
/* -- We are receiving data (Write Request) -- */
if (state & RP2040_I2C_IC_INTR_STAT_R_RX_FULL)
{
while (getreg32(RP2040_I2C_IC_RXFLR(priv->controller)) > 0)
{
data_cmd = getreg32(RP2040_I2C_IC_DATA_CMD(priv->controller));
if (data_cmd & RP2040_I2C_IC_DATA_CMD_FIRST_DATA_BYTE)
{
priv->rx_buf_ptr = priv->rx_buffer;
}
if (priv->rx_buf_ptr < priv->rx_buf_end)
{
*priv->rx_buf_ptr++ = (uint8_t) data_cmd;
}
}
}
/* -- Restart -- */
if (state & RP2040_I2C_IC_INTR_STAT_R_RESTART_DET)
{
if (priv->callback != NULL && priv->rx_buf_ptr > priv->rx_buffer)
{
priv->callback(priv, priv->rx_buf_ptr - priv->rx_buffer);
priv->rx_buf_ptr = priv->rx_buffer;
}
getreg32(RP2040_I2C_IC_CLR_RESTART_DET(priv->controller));
}
/* -- End of transfer -- */
if (state & RP2040_I2C_IC_INTR_STAT_R_STOP_DET)
{
if (priv->callback != NULL && priv->rx_buf_ptr > priv->rx_buffer)
{
priv->callback(priv, priv->rx_buf_ptr - priv->rx_buffer);
priv->rx_buf_ptr = priv->rx_buffer;
}
getreg32(RP2040_I2C_IC_CLR_STOP_DET(priv->controller));
}
/* -- Transmit Abort -- */
if (state & RP2040_I2C_IC_INTR_STAT_R_TX_ABRT)
{
getreg32(RP2040_I2C_IC_CLR_TX_ABRT(priv->controller));
priv->error = -ENODEV;
}
if (state & RP2040_I2C_IC_INTR_STAT_R_TX_OVER)
{
getreg32(RP2040_I2C_IC_CLR_TX_OVER(priv->controller));
priv->error = -EIO;
}
if (state & RP2040_I2C_IC_INTR_STAT_R_RX_OVER)
{
getreg32(RP2040_I2C_IC_CLR_RX_OVER(priv->controller));
priv->error = -EIO;
}
if (state & RP2040_I2C_IC_INTR_STAT_R_RX_UNDER)
{
getreg32(RP2040_I2C_IC_CLR_RX_UNDER(priv->controller));
priv->error = -EIO;
}
#ifdef NEEDED_FOR_MASTER_MODE_
if (state & RP2040_I2C_IC_INTR_STAT_R_TX_EMPTY)
{
/* TX_EMPTY is automatically cleared by hardware
* when the buffer level goes above the threshold.
*/
modbits_reg32(RP2040_I2C_IC_INTR_MASK(priv->controller),
0
RP2040_I2C_IC_INTR_MASK_M_TX_EMPTY);
}
if (state & RP2040_I2C_IC_INTR_STAT_R_RX_FULL)
{
/* RX_FULL is automatically cleared by hardware
* when the buffer level goes below the threshold.
*/
modbits_reg32(RP2040_I2C_IC_INTR_MASK(priv->controller),
0,
RP2040_I2C_IC_INTR_MASK_M_RX_FULL);
rp2040_i2c_drainrxfifo(priv);
}
if ((priv->error) || (state & RP2040_I2C_IC_INTR_STAT_R_TX_EMPTY)
|| (state & RP2040_I2C_IC_INTR_STAT_R_RX_FULL))
{
/* Failure of wd_cancel() means that the timer expired.
* In this case, nxsem_post() has already been called.
* Therefore, call nxsem_post() only when wd_cancel() succeeds.
*/
ret = wd_cancel(&priv->timeout);
if (ret == OK)
{
i2c_givesem(&priv->wait);
}
}
#endif
return OK;
}
/****************************************************************************
* Name: enable_i2c_slave
*
* Description:
* Enable the I2C device as a slave and start handing I2C interrupts.
*
****************************************************************************/
static void enable_i2c_slave(struct i2c_slave_s *dev)
{
rp2040_i2c_slave_t *priv = (rp2040_i2c_slave_t *) dev;
irqstate_t flags;
flags = enter_critical_section();
uint32_t intr_mask = RP2040_I2C_IC_INTR_STAT_R_RD_REQ
| RP2040_I2C_IC_INTR_STAT_R_RX_FULL
| RP2040_I2C_IC_INTR_STAT_R_STOP_DET
| RP2040_I2C_IC_INTR_STAT_R_RESTART_DET
| RP2040_I2C_IC_INTR_STAT_R_TX_ABRT;
putreg32(0, RP2040_I2C_IC_ENABLE(priv->controller));
putreg32(intr_mask, RP2040_I2C_IC_INTR_MASK(priv->controller));
putreg32(0, RP2040_I2C_IC_ENABLE(priv->controller));
if (priv->controller == 0)
{
irq_attach(RP2040_I2C0_IRQ, i2c_interrupt, dev);
up_enable_irq(RP2040_I2C0_IRQ);
}
else
{
irq_attach(RP2040_I2C1_IRQ, i2c_interrupt, dev);
up_enable_irq(RP2040_I2C1_IRQ);
}
putreg32(RP2040_I2C_IC_ENABLE_ENABLE,
RP2040_I2C_IC_ENABLE(priv->controller));
leave_critical_section(flags);
}
/****************************************************************************
* Name: my_set_own_address
*
* Description:
* Called to set the address listened to, and enable I2C as a slave device.
*
****************************************************************************/
static int my_set_own_address(struct i2c_slave_s *dev,
int address,
int nbits)
{
rp2040_i2c_slave_t *priv = (rp2040_i2c_slave_t *) dev;
uint32_t con = RP2040_I2C_IC_CON_RX_FIFO_FULL_HLD_CTRL
| RP2040_I2C_IC_CON_SPEED_FAST;
irqstate_t flags;
flags = enter_critical_section();
putreg32(address, RP2040_I2C_IC_SAR(priv->controller));
if (nbits == 10)
{
con |= RP2040_I2C_IC_CON_IC_10BITADDR_SLAVE;
}
putreg32(con, RP2040_I2C_IC_CON(priv->controller));
enable_i2c_slave(dev);
leave_critical_section(flags);
return OK;
}
/****************************************************************************
* Name: my_write
*
* Description:
* Called to set the data to be read on the next I2C read transaction.
*
****************************************************************************/
static int my_write(struct i2c_slave_s *dev,
const uint8_t *buffer,
int length)
{
rp2040_i2c_slave_t *priv = (rp2040_i2c_slave_t *) dev;
irqstate_t flags;
flags = enter_critical_section();
priv->tx_buffer = buffer;
priv->tx_buf_ptr = buffer;
priv->tx_buf_end = priv->tx_buffer + length;
leave_critical_section(flags);
return OK;
}
/****************************************************************************
* Name: my_read
*
* Description:
* Called to register a buffer to receive data from the next I2C write
* transaction.
*
****************************************************************************/
static int my_read(struct i2c_slave_s *dev,
uint8_t *buffer,
int length)
{
rp2040_i2c_slave_t *priv = (rp2040_i2c_slave_t *) dev;
irqstate_t flags;
flags = enter_critical_section();
priv->rx_buffer = buffer;
priv->rx_buf_ptr = buffer;
priv->rx_buf_end = priv->rx_buffer + length;
leave_critical_section(flags);
return OK;
}
/****************************************************************************
* Name: my_register_callback
*
* Description:
* Called to register a callback function that will be called when
* data becomes available due to an I2C write transaction.
*
****************************************************************************/
static int my_register_callback(struct i2c_slave_s *dev,
i2c_slave_callback_t *callback,
void *arg)
{
rp2040_i2c_slave_t *priv = (rp2040_i2c_slave_t *) dev;
irqstate_t flags;
flags = enter_critical_section();
priv->callback = callback;
priv->callback_arg = arg;
leave_critical_section(flags);
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: rp2040_i2c0_slave_initialize
*
* Description:
* Initialize I2C controller zero for slave operation, and return a pointer
* to the instance of struct i2c_slave_s. This function should only be
* called once of a give controller.
*
* Input Parameters:
* sda_pin - The GPIO pin for the SDA line.
* scl_pin - The GPIO pin for the SCL line.
* address - The slave address to listen to.
* ten_bin - Set true for 10-bit I2C addressing.
* rx_buffer - Buffer for data transmitted to us by an I2C master.
* rx_buffer_len - Length of rx_buffer.
* callback - Callback function called when messages are received.
*
* Returned Value:
* Valid I2C device structure reference on success; a NULL on failure
*
****************************************************************************/
#ifdef CONFIG_RP2040_I2C0_SLAVE
struct i2c_slave_s * rp2040_i2c0_slave_initialize
(uint8_t *rx_buffer,
size_t rx_buffer_len,
i2c_slave_callback_t *callback)
{
rp2040_i2c_slave_t *priv = &i2c0_slave_dev;
rp2040_gpio_set_function(CONFIG_RP2040_I2C0_SLAVE_SDA,
RP2040_GPIO_FUNC_I2C);
rp2040_gpio_set_pulls(CONFIG_RP2040_I2C0_SLAVE_SDA, true, false);
rp2040_gpio_set_function(CONFIG_RP2040_I2C0_SLAVE_SCL,
RP2040_GPIO_FUNC_I2C);
rp2040_gpio_set_pulls(CONFIG_RP2040_I2C0_SLAVE_SCL, true, false);
priv->rx_buffer = rx_buffer;
priv->rx_buf_ptr = rx_buffer;
priv->rx_buf_end = priv->rx_buffer + rx_buffer_len;
if (callback != NULL)
{
my_register_callback(&(priv->dev), callback, priv);
}
#ifdef CONFIG_RP2040_I2C0_SLAVE_10BIT
my_set_own_address(&(priv->dev),
CONFIG_RP2040_I2C0_SLAVE_ADDRESS,
10);
#else
my_set_own_address(&(priv->dev),
CONFIG_RP2040_I2C0_SLAVE_ADDRESS,
7);
#endif
return &(priv->dev);
}
#endif /* CONFIG_RP2040_I2C0_SLAVE */
/****************************************************************************
* Name: rp2040_i2c1_slave_initialize
*
* Description:
* Initialize I2C controller one for slave operation, and return a pointer
* to the instance of struct i2c_slave_s. This function should only be
* called once of a give controller.
*
* Input Parameters:
* sda_pin - The GPIO pin for the SDA line.
* scl_pin - The GPIO pin for the SCL line.
* address - The slave address to listen to.
* ten_bin - Set true for 10-bit I2C addressing.
* rx_buffer - Buffer for data transmitted to us by an I2C master.
* rx_buffer_len - Length of rx_buffer.
* callback - Callback function called when messages are received.
*
* Returned Value:
* Valid I2C device structure reference on success; a NULL on failure
*
****************************************************************************/
#ifdef CONFIG_RP2040_I2C1_SLAVE
struct i2c_slave_s * rp2040_i2c1_slave_initialize
(uint8_t *rx_buffer,
size_t rx_buffer_len,
i2c_slave_callback_t *callback)
{
rp2040_i2c_slave_t *priv = &i2c1_slave_dev;
rp2040_gpio_set_function(CONFIG_RP2040_I2C1_SLAVE_SDA,
RP2040_GPIO_FUNC_I2C);
rp2040_gpio_set_pulls(CONFIG_RP2040_I2C1_SLAVE_SDA, true, false);
rp2040_gpio_set_function(CONFIG_RP2040_I2C1_SLAVE_SCL,
RP2040_GPIO_FUNC_I2C);
rp2040_gpio_set_pulls(CONFIG_RP2040_I2C1_SLAVE_SCL, true, false);
priv->rx_buffer = rx_buffer;
priv->rx_buf_ptr = rx_buffer;
priv->rx_buf_end = priv->rx_buffer + rx_buffer_len;
if (callback != NULL)
{
my_register_callback(&(priv->dev), callback, priv);
}
#ifdef CONFIG_RP2040_I2C1_SLAVE_10BIT
my_set_own_address(&(priv->dev),
CONFIG_RP2040_I2C1_SLAVE_ADDRESS,
10);
#else
my_set_own_address(&(priv->dev),
CONFIG_RP2040_I2C1_SLAVE_ADDRESS,
7);
#endif
return &(priv->dev);
}
#endif /* CONFIG_RP2040_I2C1_SLAVE */
#endif /* CONFIG_RP2040_I2C_SLAVE */

View File

@ -102,8 +102,8 @@ struct s32k1xx_lpi2c_slave_priv_s
int write_buflen; /* Write buffer size */
int write_bufindex; /* Write buffer index */
int (*callback)(void *arg); /* Callback function when data has been received */
void *callback_arg; /* Argument of callback function */
i2c_slave_callback_t *callback; /* Callback function when data has been received */
void *callback_arg; /* Argument of callback function */
int refs; /* Reference count */
};
@ -137,7 +137,7 @@ static int s32k1xx_lpi2c_write(struct i2c_slave_s *dev,
static int s32k1xx_lpi2c_read(struct i2c_slave_s *dev,
uint8_t *buffer, int buflen);
static int s32k1xx_lpi2c_registercallback(struct i2c_slave_s *dev,
int (*callback)(void *arg),
i2c_slave_callback_t *callback,
void *arg);
/****************************************************************************
@ -427,7 +427,8 @@ static int s32k1xx_lpi2c_slave_isr_process(
if ((priv->read_bufindex > 0) && (priv->callback != NULL))
{
priv->callback(priv->callback_arg);
priv->callback(priv->callback_arg, priv->read_bufindex);
priv->read_bufindex = 0;
}
}
@ -793,7 +794,8 @@ static int s32k1xx_lpi2c_read(struct i2c_slave_s *dev,
****************************************************************************/
static int s32k1xx_lpi2c_registercallback(struct i2c_slave_s *dev,
int (*callback)(void *arg), void *arg)
i2c_slave_callback_t *callback,
void *arg)
{
struct s32k1xx_lpi2c_slave_priv_s *priv;
irqstate_t flags;

View File

@ -21,6 +21,30 @@
#ifndef __INCLUDE_NUTTX_I2C_I2C_SLAVE_H
#define __INCLUDE_NUTTX_I2C_I2C_SLAVE_H
/****************************************************************************
* Using I2C slave mode:
*
* After I2C slave mode is initialized by calling an architecture defined
* initialization function, the hardware will monitor the I2C bus waiting
* for messages with this device's address.
*
* Before I2C data can be received, the I2CS_READ macro should be called
* to register a buffer where the received data will be stored, and a
* callback function should be registered with either (not both) the
* I2CS_REGISTERCALLBACK macro. When the data is received (via an I2C
* write message) it will be written to the supplied buffer and the callback
* function will be called.
*
* The I2C_WRITE macro is used to register a buffer with data to be
* sent when the master next issues an I2C read message. There is no
* specific notification that the data has been read, but since usual
* I2C operation is for the master to transmit a message indicating
* the desired data before reading, the slave should register the
* return data in the callback function and preserve it until the next
* callback it received.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
@ -90,10 +114,8 @@
* Name: I2CS_WRITE
*
* Description:
* Send a block of data on I2C using the previously selected I2C
* frequency and slave address. Each write operational will be an 'atomic'
* operation in the sense that any other I2C actions will be serialized
* and pend until this write completes. Required.
* Send a block of data on I2C to the next master to issue an I2C read
* transaction to this slave. Required.
*
* Input Parameters:
* dev - Device-specific state data
@ -112,10 +134,10 @@
* Name: I2CS_READ
*
* Description:
* Receive a block of data from I2C using the previously selected I2C
* frequency and slave address. Each read operational will be an 'atomic'
* operation in the sense that any other I2C actions will be serialized
* and pend until this read completes. Required.
* Register a buffer to receive the data from the next I2C write
* transaction addressed to this slave. The callback function supplied
* by the I2CS_REGISTERCALLBACK macro will be called once the buffer
* has been filled. Required.
*
* Input Parameters:
* dev - Device-specific state data
@ -152,18 +174,30 @@
* Public Types
****************************************************************************/
/* The callback function */
typedef int (i2c_slave_callback_t)(void *arg, size_t rx_len);
/* The I2C vtable */
struct i2c_slave_s;
struct i2c_slaveops_s
{
int (*setownaddress)(FAR struct i2c_slave_s *dev, int addr, int nbits);
int (*write)(FAR struct i2c_slave_s *dev, FAR const uint8_t *buffer,
int buflen);
int (*read)(FAR struct i2c_slave_s *dev, FAR uint8_t *buffer,
int buflen);
int (*setownaddress)(FAR struct i2c_slave_s *dev,
int addr,
int nbits);
int (*write)(FAR struct i2c_slave_s *dev,
FAR const uint8_t *buffer,
int buflen);
int (*read)(FAR struct i2c_slave_s *dev,
FAR uint8_t *buffer,
int buflen);
int (*registercallback)(FAR struct i2c_slave_s *dev,
int (*callback)(FAR void *arg), FAR void *arg);
i2c_slave_callback_t *callback,
FAR void *arg);
};
/* I2C private data. This structure only defines the initial fields of the