Skip to content

Commit 5e1c1ca

Browse files
Add i2c slave example (#320)
* Add i2c slave example from https://github.com/vmilea/pico_i2c_slave To test you need to wire pin GP4 to GP6 (SDA), and pin GP5 to GP7 (SCL)
1 parent f3f5d9f commit 5e1c1ca

File tree

4 files changed

+146
-0
lines changed

4 files changed

+146
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ App|Description
8787
[pa1010d_i2c](i2c/pa1010d_i2c) | Read GPS location data, parse and display data via I2C.
8888
[pcf8523_i2c](i2c/pcf8523_i2c) | Read time and date values from a real time clock. Set current time and alarms on it.
8989
[ht16k33_i2c](i2c/ht16k33_i2c) | Drive a 4 digit 14 segment LED with an HT16K33.
90+
[slave_mem_i2c](i2c/slave_mem_i2c) | i2c slave example where the slave implements a 256 byte memory
9091

9192
### Interpolator
9293

i2c/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ if (NOT PICO_NO_HARDWARE)
1111
add_subdirectory(pa1010d_i2c)
1212
add_subdirectory(pcf8523_i2c)
1313
add_subdirectory(ht16k33_i2c)
14+
add_subdirectory(slave_mem_i2c)
1415
endif ()

i2c/slave_mem_i2c/CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
add_executable(slave_mem_i2c
2+
slave_mem_i2c.c
3+
)
4+
target_link_libraries(slave_mem_i2c
5+
pico_i2c_slave
6+
hardware_i2c
7+
pico_stdlib
8+
)
9+
pico_add_extra_outputs(slave_mem_i2c)
10+
example_auto_set_url(slave_mem_i2c)

i2c/slave_mem_i2c/slave_mem_i2c.c

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/*
2+
* Copyright (c) 2021 Valentin Milea <[email protected]>
3+
* Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
4+
*
5+
* SPDX-License-Identifier: BSD-3-Clause
6+
*/
7+
8+
#include <hardware/i2c.h>
9+
#include <pico/i2c_slave.h>
10+
#include <pico/stdlib.h>
11+
#include <stdio.h>
12+
#include <string.h>
13+
14+
static const uint I2C_SLAVE_ADDRESS = 0x17;
15+
static const uint I2C_BAUDRATE = 100000; // 100 kHz
16+
17+
// For this example, we run both the master and slave from the same board.
18+
// You'll need to wire pin GP4 to GP6 (SDA), and pin GP5 to GP7 (SCL).
19+
static const uint I2C_SLAVE_SDA_PIN = PICO_DEFAULT_I2C_SDA_PIN; // 4
20+
static const uint I2C_SLAVE_SCL_PIN = PICO_DEFAULT_I2C_SCL_PIN; // 5
21+
static const uint I2C_MASTER_SDA_PIN = 6;
22+
static const uint I2C_MASTER_SCL_PIN = 7;
23+
24+
// The slave implements a 256 byte memory. To write a series of bytes, the master first
25+
// writes the memory address, followed by the data. The address is automatically incremented
26+
// for each byte transferred, looping back to 0 upon reaching the end. Reading is done
27+
// sequentially from the current memory address.
28+
static struct
29+
{
30+
uint8_t mem[256];
31+
uint8_t mem_address;
32+
bool mem_address_written;
33+
} context;
34+
35+
// Our handler is called from the I2C ISR, so it must complete quickly. Blocking calls /
36+
// printing to stdio may interfere with interrupt handling.
37+
static void i2c_slave_handler(i2c_inst_t *i2c, i2c_slave_event_t event) {
38+
switch (event) {
39+
case I2C_SLAVE_RECEIVE: // master has written some data
40+
if (!context.mem_address_written) {
41+
// writes always start with the memory address
42+
context.mem_address = i2c_read_byte_raw(i2c);
43+
context.mem_address_written = true;
44+
} else {
45+
// save into memory
46+
context.mem[context.mem_address] = i2c_read_byte_raw(i2c);
47+
context.mem_address++;
48+
}
49+
break;
50+
case I2C_SLAVE_REQUEST: // master is requesting data
51+
// load from memory
52+
i2c_write_byte_raw(i2c, context.mem[context.mem_address]);
53+
context.mem_address++;
54+
break;
55+
case I2C_SLAVE_FINISH: // master has signalled Stop / Restart
56+
context.mem_address_written = false;
57+
break;
58+
default:
59+
break;
60+
}
61+
}
62+
63+
static void setup_slave() {
64+
gpio_init(I2C_SLAVE_SDA_PIN);
65+
gpio_set_function(I2C_SLAVE_SDA_PIN, GPIO_FUNC_I2C);
66+
gpio_pull_up(I2C_SLAVE_SDA_PIN);
67+
68+
gpio_init(I2C_SLAVE_SCL_PIN);
69+
gpio_set_function(I2C_SLAVE_SCL_PIN, GPIO_FUNC_I2C);
70+
gpio_pull_up(I2C_SLAVE_SCL_PIN);
71+
72+
i2c_init(i2c0, I2C_BAUDRATE);
73+
// configure I2C0 for slave mode
74+
i2c_slave_init(i2c0, I2C_SLAVE_ADDRESS, &i2c_slave_handler);
75+
}
76+
77+
static void run_master() {
78+
gpio_init(I2C_MASTER_SDA_PIN);
79+
gpio_set_function(I2C_MASTER_SDA_PIN, GPIO_FUNC_I2C);
80+
// pull-ups are already active on slave side, this is just a fail-safe in case the wiring is faulty
81+
gpio_pull_up(I2C_MASTER_SDA_PIN);
82+
83+
gpio_init(I2C_MASTER_SCL_PIN);
84+
gpio_set_function(I2C_MASTER_SCL_PIN, GPIO_FUNC_I2C);
85+
gpio_pull_up(I2C_MASTER_SCL_PIN);
86+
87+
i2c_init(i2c1, I2C_BAUDRATE);
88+
89+
for (uint8_t mem_address = 0;; mem_address = (mem_address + 32) % 256) {
90+
char msg[32];
91+
snprintf(msg, sizeof(msg), "Hello, I2C slave! - 0x%02X", mem_address);
92+
uint8_t msg_len = strlen(msg);
93+
94+
uint8_t buf[32];
95+
buf[0] = mem_address;
96+
memcpy(buf + 1, msg, msg_len);
97+
// write message at mem_address
98+
printf("Write at 0x%02X: '%s'\n", mem_address, msg);
99+
int count = i2c_write_blocking(i2c1, I2C_SLAVE_ADDRESS, buf, 1 + msg_len, false);
100+
if (count < 0) {
101+
puts("Couldn't write to slave, please check your wiring!");
102+
return;
103+
}
104+
hard_assert(count == 1 + msg_len);
105+
106+
// seek to mem_address
107+
count = i2c_write_blocking(i2c1, I2C_SLAVE_ADDRESS, buf, 1, true);
108+
hard_assert(count == 1);
109+
// partial read
110+
uint8_t split = 5;
111+
count = i2c_read_blocking(i2c1, I2C_SLAVE_ADDRESS, buf, split, true);
112+
hard_assert(count == split);
113+
buf[count] = '\0';
114+
printf("Read at 0x%02X: '%s'\n", mem_address, buf);
115+
hard_assert(memcmp(buf, msg, split) == 0);
116+
// read the remaining bytes, continuing from last address
117+
count = i2c_read_blocking(i2c1, I2C_SLAVE_ADDRESS, buf, msg_len - split, false);
118+
hard_assert(count == msg_len - split);
119+
buf[count] = '\0';
120+
printf("Read at 0x%02X: '%s'\n", mem_address + split, buf);
121+
hard_assert(memcmp(buf, msg + split, msg_len - split) == 0);
122+
123+
puts("");
124+
sleep_ms(2000);
125+
}
126+
}
127+
128+
int main() {
129+
stdio_init_all();
130+
puts("\nI2C slave example");
131+
132+
setup_slave();
133+
run_master();
134+
}

0 commit comments

Comments
 (0)