Skip to content

Commit 6c1d95f

Browse files
giulcioffifacchinm
authored andcommitted
RP2040: Add I2C slave
1 parent 2886c2b commit 6c1d95f

File tree

4 files changed

+177
-5
lines changed

4 files changed

+177
-5
lines changed

targets/TARGET_RASPBERRYPI/TARGET_RP2040/i2c_api.c

Lines changed: 143 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,23 @@
66
#include "i2c_api.h"
77
#include "pinmap.h"
88
#include "PeripheralPins.h"
9+
#include "objects.h"
10+
#include "stdio.h"
11+
12+
/******************************************************************************
13+
* DEFINE
14+
******************************************************************************/
15+
16+
#if 1
17+
#define DEBUG_PRINTF(...) printf(__VA_ARGS__)
18+
#else
19+
#define DEBUG_PRINTF(...)
20+
#endif
21+
22+
#define NoData 0 // the slave has not been addressed
23+
#define ReadAddressed 1 // the master has requested a read from this slave (slave = transmitter)
24+
#define WriteGeneral 2 // the master is writing to all slave
25+
#define WriteAddressed 3 // the master is writing to this slave (slave = receiver)
926

1027
/******************************************************************************
1128
* CONST
@@ -24,12 +41,23 @@ void i2c_init(i2c_t *obj, PinName sda, PinName scl)
2441
I2CName const i2c_scl = (I2CName)pinmap_peripheral(scl, PinMap_I2C_SCL);
2542
MBED_ASSERT(i2c_sda == i2c_scl);
2643

44+
#if DEVICE_I2CSLAVE
45+
/** was_slave is used to decide which driver call we need
46+
* to use when uninitializing a given instance
47+
*/
48+
obj->was_slave = false;
49+
obj->is_slave = false;
50+
obj->slave_addr = 0;
51+
#endif
52+
2753
/* Obtain the pointer to the I2C hardware instance. */
2854
obj->dev = (i2c_inst_t *)pinmap_function(sda, PinMap_I2C_SDA);
29-
obj->baudrate = DEFAULT_I2C_BAUDRATE;
55+
//obj->baudrate = DEFAULT_I2C_BAUDRATE;
56+
//Call this function because if we are configuring a slave, we don't have to set the frequency
57+
//i2c_frequency(obj->dev, DEFAULT_I2C_BAUDRATE);
3058

3159
/* Initialize the I2C module. */
32-
_i2c_init(obj->dev, obj->baudrate);
60+
_i2c_init(obj->dev, DEFAULT_I2C_BAUDRATE);
3361

3462
/* Configure GPIO for I2C as alternate function. */
3563
gpio_set_function(sda, GPIO_FUNC_I2C);
@@ -42,6 +70,14 @@ void i2c_init(i2c_t *obj, PinName sda, PinName scl)
4270

4371
void i2c_frequency(i2c_t *obj, int hz)
4472
{
73+
DEBUG_PRINTF("obj->is_slave: %d\r\n", obj->is_slave);
74+
75+
#if DEVICE_I2CSLAVE
76+
/* Slaves automatically get frequency from master */
77+
if(obj->is_slave) {
78+
return;
79+
}
80+
#endif
4581
obj->baudrate = i2c_set_baudrate(obj->dev, hz);
4682
}
4783

@@ -95,3 +131,108 @@ const PinMap *i2c_master_scl_pinmap()
95131
{
96132
return PinMap_I2C_SCL;
97133
}
134+
135+
const PinMap *i2c_slave_sda_pinmap()
136+
{
137+
return PinMap_I2C_SDA;
138+
}
139+
140+
const PinMap *i2c_slave_scl_pinmap()
141+
{
142+
return PinMap_I2C_SCL;
143+
}
144+
145+
int i2c_stop(i2c_t *obj)
146+
{
147+
148+
}
149+
150+
#if DEVICE_I2CSLAVE
151+
152+
/** Configure I2C as slave or master.
153+
* @param obj The I2C object
154+
* @param enable_slave Enable i2c hardware so you can receive events with ::i2c_slave_receive
155+
* @return non-zero if a value is available
156+
*/
157+
void i2c_slave_mode(i2c_t *obj, int enable_slave)
158+
{
159+
DEBUG_PRINTF("i2c_slave_mode: %p, %d\r\n", obj, enable_slave);
160+
161+
obj->is_slave = enable_slave;
162+
}
163+
164+
/** Check to see if the I2C slave has been addressed.
165+
* @param obj The I2C object
166+
* @return The status - 1 - read addressed, 2 - write to all slaves,
167+
* 3 write addressed, 0 - the slave has not been addressed
168+
*/
169+
int i2c_slave_receive(i2c_t *obj)
170+
{
171+
int retValue = NoData;
172+
173+
int rd_req = (obj->dev->hw->raw_intr_stat & I2C_IC_RAW_INTR_STAT_RD_REQ_BITS) >> 5;
174+
175+
if (rd_req == I2C_IC_RAW_INTR_STAT_RD_REQ_VALUE_ACTIVE) {
176+
DEBUG_PRINTF("Read addressed\r\n");
177+
return ReadAddressed;
178+
}
179+
180+
int wr_req = (obj->dev->hw->status & I2C_IC_STATUS_RFNE_BITS) >> 3;
181+
182+
if (wr_req == I2C_IC_STATUS_RFNE_VALUE_NOT_EMPTY) {
183+
DEBUG_PRINTF("Write addressed\r\n");
184+
return WriteAddressed;
185+
}
186+
187+
return (retValue);
188+
}
189+
190+
/** Configure I2C as slave or master.
191+
* @param obj The I2C objecti2c_get_read_availableread
192+
* @return non-zero if a value is available
193+
*/
194+
int i2c_slave_read(i2c_t *obj, char *data, int length)
195+
{
196+
size_t read_len = i2c_read_raw_blocking(obj->dev, (uint8_t *)data, length);
197+
198+
DEBUG_PRINTF("i2c_slave read %d bytes\r\n", read_len);
199+
200+
return read_len;
201+
}
202+
203+
/** Configure I2C as slave or master.
204+
* @param obj The I2C object
205+
* @param data The buffer for sending
206+
* @param length Number of bytes to write
207+
* @return non-zero if a value is available
208+
*/
209+
int i2c_slave_write(i2c_t *obj, const char *data, int length)
210+
{
211+
DEBUG_PRINTF("i2c_slave_write\r\n");
212+
213+
i2c_write_raw_blocking(obj->dev, (const uint8_t *)data, (size_t)length);
214+
215+
//Clear interrupt
216+
int clear_read_req = i2c_get_hw(obj->dev)->clr_rd_req;
217+
DEBUG_PRINTF("clear_read_req: %d\n", clear_read_req);
218+
219+
return length;
220+
}
221+
222+
/** Configure I2C address.
223+
* @param obj The I2C object
224+
* @param idx Currently not used
225+
* @param address The address to be set
226+
* @param mask Currently not used
227+
*/
228+
void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask)
229+
{
230+
if (obj->is_slave) {
231+
DEBUG_PRINTF("i2c_slave_address: %p, %d, %d, %d\r\n", obj, idx, address, mask);
232+
233+
obj->slave_addr = (uint8_t)(address >> 1);
234+
i2c_set_slave_mode(obj->dev, true, obj->slave_addr);
235+
}
236+
}
237+
238+
#endif // DEVICE_I2CSLAVE

targets/TARGET_RASPBERRYPI/TARGET_RP2040/objects.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,12 @@ struct serial_s {
9595
struct i2c_s {
9696
i2c_inst_t * dev;
9797
unsigned int baudrate;
98+
99+
#if DEVICE_I2CSLAVE
100+
bool was_slave;
101+
bool is_slave;
102+
uint8_t slave_addr;
103+
#endif
98104
};
99105

100106
struct spi_s {

targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_i2c/include/hardware/i2c.h

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "pico.h"
1111
#include "pico/time.h"
1212
#include "hardware/structs/i2c.h"
13+
#include "stdio.h"
1314

1415
// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_I2C, Enable/disable assertions in the I2C module, type=bool, default=0, group=hardware_i2c
1516
#ifndef PARAM_ASSERTIONS_ENABLED_I2C
@@ -289,12 +290,35 @@ static inline void i2c_write_raw_blocking(i2c_inst_t *i2c, const uint8_t *src, s
289290
* Reads directly from the I2C RX FIFO which us mainly useful for
290291
* slave-mode operation.
291292
*/
292-
static inline void i2c_read_raw_blocking(i2c_inst_t *i2c, uint8_t *dst, size_t len) {
293+
static inline size_t i2c_read_raw_blocking(i2c_inst_t *i2c, uint8_t *dst, size_t len) {
294+
295+
size_t bytes_read = 0;
296+
293297
for (size_t i = 0; i < len; ++i) {
294-
while (!i2c_get_read_available(i2c))
298+
299+
while (!i2c_get_read_available(i2c)) {
295300
tight_loop_contents();
296-
*dst++ = i2c_get_hw(i2c)->data_cmd;
301+
}
302+
303+
*dst = i2c_get_hw(i2c)->data_cmd;
304+
bytes_read++;
305+
306+
//printf("dst %d ,", *dst);
307+
308+
//Check stop condition
309+
int stop = (i2c->hw->raw_intr_stat & 0x00000200) >> 9;
310+
if (stop && !i2c_get_read_available(i2c)) {
311+
//Clear stop
312+
int clear_stop = i2c_get_hw(i2c)->clr_stop_det;
313+
printf("clear_stop reg: %d\n", clear_stop);
314+
break;
315+
} else {
316+
*dst++;
317+
}
318+
297319
}
320+
321+
return bytes_read;
298322
}
299323

300324
#ifdef __cplusplus

targets/targets.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8006,6 +8006,7 @@
80068006
"ANALOGIN",
80078007
"FLASH",
80088008
"I2C",
8009+
"I2CSLAVE",
80098010
"INTERRUPTIN",
80108011
"PORT_IN",
80118012
"PORT_OUT",

0 commit comments

Comments
 (0)