Skip to content

Commit 9d44cad

Browse files
committed
Added 24LC32 EEPROM I2C example
1 parent 4c3a3dc commit 9d44cad

File tree

9 files changed

+223
-0
lines changed

9 files changed

+223
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ App|Description
159159
[ht16k33_i2c](i2c/ht16k33_i2c) | Drive a 4 digit 14 segment LED with an HT16K33.
160160
[slave_mem_i2c](i2c/slave_mem_i2c) | i2c slave example where the slave implements a 256 byte memory.
161161
[slave_mem_i2c_burst](i2c/slave_mem_i2c) | i2c slave example where the slave implements a 256 byte memory. This version inefficiently writes each byte in a separate call to demonstrate read and write burst mode.
162+
[24lc32_i2c](i2c/24lc32_i2c) | Read and write data to 24LC32 EEPROM via I2C.
162163

163164
### Interpolator
164165

i2c/24lc32_i2c/24lc32_i2c.fzz

51 KB
Binary file not shown.

i2c/24lc32_i2c/24lc32_i2c.png

271 KB
Loading

i2c/24lc32_i2c/24lc32_i2c_lib.c

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
#include <stdio.h>
2+
#include "pico/stdlib.h"
3+
#include "hardware/i2c.h"
4+
5+
// This is the max number of bytes which can be written at once during a page write
6+
#define MAX_PAGE_WRITE 32
7+
8+
// This is the 24LC32's capacity in bytes
9+
#define EEPROM_SIZE 4096
10+
11+
// Acknowledge polling can be used to see when a write cycle is complete
12+
// Wait for the i2c slave to acknowledge our empty write
13+
bool ack_poll(uint8_t i2c_addr, i2c_inst_t *i2c_instance) {
14+
int timeout = 100;
15+
for (int i = 0; i < timeout; i++) {
16+
if (i2c_write_blocking(i2c_instance, i2c_addr, NULL, 1, false) == 1) {
17+
return true;
18+
}
19+
sleep_ms(1);
20+
}
21+
printf("ack timeout\n");
22+
return false;
23+
}
24+
25+
// Read num bytes of memory starting at given address into result
26+
bool read_eeprom(uint16_t address, uint8_t *result, uint16_t num, uint8_t i2c_addr, i2c_inst_t *i2c_instance) {
27+
if ((address + num - 1) > EEPROM_SIZE) {
28+
printf("ERROR: Tried to write to memory outside EEPROM's range.\n");
29+
return false;
30+
}
31+
32+
for (int i = 0; i < num; i++) {
33+
uint8_t byte1 = (uint8_t)(address >> 8);
34+
uint8_t byte2 = (uint8_t)(address);
35+
36+
uint8_t buf[2] = {byte1, byte2};
37+
38+
i2c_write_blocking(i2c_instance, i2c_addr, buf, 2, true);
39+
i2c_read_blocking(i2c_instance, i2c_addr, (result + i), 1, false);
40+
41+
address++;
42+
}
43+
44+
return true;
45+
}
46+
47+
// Write a single byte of data at a specified address in memory
48+
bool byte_write_eeprom(uint16_t address, uint8_t data, uint8_t i2c_addr, i2c_inst_t *i2c_instance) {
49+
if (address > EEPROM_SIZE) {
50+
printf("ERROR: Tried to write to memory outside EEPROM's range.\n");
51+
return false;
52+
}
53+
54+
uint8_t byte1 = (uint8_t)(address >> 8);
55+
uint8_t byte2 = (uint8_t)(address);
56+
57+
uint8_t buf[3] = {byte1, byte2, data};
58+
59+
i2c_write_blocking(i2c_instance, i2c_addr, buf, 3, false);
60+
61+
// ack_poll to wait for write to be complete
62+
return ack_poll(i2c_addr, i2c_instance);
63+
}
64+
65+
// Write a block of data to eeprom
66+
bool page_write_eeprom(uint16_t address, uint8_t *data, uint8_t num, uint8_t i2c_addr, i2c_inst_t *i2c_instance) {
67+
if (num > MAX_PAGE_WRITE) {
68+
printf("ERROR: Tried to write more than 32 bytes.\n");
69+
return false;
70+
} else if ((address + num - 1) > EEPROM_SIZE) {
71+
printf("ERROR: Tried to write to memory outside EEPROM's range.\n");
72+
}
73+
74+
uint8_t byte1 = (uint8_t)(address >> 8);
75+
uint8_t byte2 = (uint8_t)(address);
76+
uint8_t buf[2 + num];
77+
buf[0] = byte1;
78+
buf[1] = byte2;
79+
80+
// transfer data into buffer
81+
for (int i = 0; i < num; i++) {
82+
buf[i + 2] = data[i];
83+
}
84+
85+
i2c_write_blocking(i2c_instance, i2c_addr, buf, 2 + num, false);
86+
87+
// ack_poll to wait for write to be complete
88+
return ack_poll(i2c_addr, i2c_instance);
89+
}
90+
91+
// Initialise i2c for given gpio at given frequency
92+
void eeprom_init(int sda_pin, int scl_pin, int freq, i2c_inst_t *i2c_instance) {
93+
i2c_init(i2c_instance, freq);
94+
95+
gpio_set_function(sda_pin, GPIO_FUNC_I2C);
96+
gpio_set_function(scl_pin, GPIO_FUNC_I2C);
97+
gpio_pull_up(sda_pin);
98+
gpio_pull_up(scl_pin);
99+
}
100+

i2c/24lc32_i2c/24lc32_i2c_lib.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#ifndef PICO_I2C_EEPROM_LIB_H
2+
#define PICO_I2C_EEPROM_LIB_H
3+
4+
#include "hardware/i2c.h"
5+
6+
bool ack_poll(uint8_t i2c_addr, i2c_inst_t *i2c_instance);
7+
bool read_eeprom(uint16_t address, uint8_t *result, uint16_t num, uint8_t i2c_addr, i2c_inst_t *i2c_instance);
8+
bool byte_write_eeprom(uint16_t address, uint8_t data, uint8_t i2c_addr, i2c_inst_t *i2c_instance);
9+
bool page_write_eeprom(uint16_t address, uint8_t *data, uint8_t num, uint8_t i2c_addr, i2c_inst_t *i2c_instance);
10+
void eeprom_init(int sda_pin, int scl_pin, int freq, i2c_inst_t *i2c_instance);
11+
12+
#endif

i2c/24lc32_i2c/CMakeLists.txt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Add libary
2+
add_library(24lc32_i2c_lib INTERFACE)
3+
target_sources(24lc32_i2c_lib INTERFACE
4+
${CMAKE_CURRENT_LIST_DIR}/24lc32_i2c_lib.c
5+
)
6+
target_include_directories(24lc32_i2c_lib INTERFACE
7+
${CMAKE_CURRENT_LIST_DIR}
8+
)
9+
target_link_libraries(24lc32_i2c_lib INTERFACE
10+
pico_stdlib
11+
hardware_i2c
12+
)
13+
14+
# Add executable
15+
add_executable(24lc32_i2c
16+
example.c
17+
)
18+
19+
target_link_libraries(24lc32_i2c
20+
24lc32_i2c_lib
21+
pico_stdlib
22+
hardware_i2c
23+
)
24+
25+
pico_add_extra_outputs(24lc32_i2c)

i2c/24lc32_i2c/README.adoc

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
= Reading and writing 24LC32 EEPROM via I2C
2+
3+
This example code demonstrates how to read and write data from 24LC32 EEPROM. It contains a library with functions for reading data, writing single bytes, and writing pages; and an example which uses these functions.
4+
== Wiring information
5+
6+
[[24lc32_i2c_wiring]]
7+
[pdfwidth=75%]
8+
.Wiring Diagram for 24LC32 EEPROM via I2C.
9+
image::24lc32_i2c.png[]
10+
11+
== List of Files
12+
13+
CMakeLists.txt:: CMake file to incorporate the example into the examples build tree.
14+
24lc32_i2c_lib.c:: Library containing functions to interact with 24LC32 eeprom via I2C.
15+
24lc32_i2c_lib.h:: Header file containing function declarations for the 24LC32 library.
16+
example.c:: The example code.
17+
18+
== Bill of Materials
19+
20+
.A list of materials required for the example
21+
[[24lc32_i2c-bom-table]]
22+
[cols=3]
23+
|===
24+
| *Item* | *Quantity* | Details
25+
| Breadboard | 1 | generic part
26+
| Raspberry Pi Pico (any) | 1 | https://www.raspberrypi.com/products/raspberry-pi-pico/
27+
| 24LC32-based breakout board | 1 | https://www.adafruit.com/product/5146
28+
| M/M Jumper wires | 4 | generic part
29+
|===

i2c/24lc32_i2c/example.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#include <stdio.h>
2+
#include "pico/stdlib.h"
3+
#include "hardware/i2c.h"
4+
#include "24lc32_i2c_lib.h"
5+
6+
// Default I2C address of 24LC32
7+
#define I2C_ADDRESS 0x50
8+
9+
int main() {
10+
stdio_init_all();
11+
12+
eeprom_init(PICO_DEFAULT_I2C_SDA_PIN, PICO_DEFAULT_I2C_SCL_PIN, 400*1000, i2c_default);
13+
14+
// Write the byte at location 0x00 to 0
15+
byte_write_eeprom(0x00, 0, I2C_ADDRESS, i2c_default);
16+
17+
// Make an array of integers from 1 to 31 and write the array to eeprom starting at 0x01
18+
uint8_t data_list[31];
19+
for (int i = 0; i < 31; i++) {
20+
data_list[i] = i + 1;
21+
}
22+
page_write_eeprom(0x01, data_list, 31, I2C_ADDRESS, i2c_default);
23+
24+
// Read eeprom, and ensure we observe ascending integers from 0 to 31
25+
uint8_t result[32];
26+
read_eeprom(0x0, result, 32, I2C_ADDRESS, i2c_default);
27+
28+
for (int i = 0; i < 32; i++) {
29+
printf("read: %i, expected: %i\n", result[i], i);
30+
if (result[i] != i) {
31+
printf("Unexpected read!\n");
32+
return 1;
33+
}
34+
}
35+
36+
// Now re-write and re-read eeprom
37+
for (int i = 0; i < 31; i++) {
38+
data_list[i] = 32 - i;
39+
}
40+
page_write_eeprom(0x1F, data_list, 0, I2C_ADDRESS, i2c_default);
41+
42+
// Read eeprom, and ensure we observe descending integers from 31 to 0
43+
read_eeprom(0x0, result, 32, I2C_ADDRESS, i2c_default);
44+
45+
for (int i = 0; i < 32; i++) {
46+
printf("read: %i, expected: %i\n", result[i], 32 - i);
47+
if (result[i] != 32 - i) {
48+
printf("Unexpected read!\n");
49+
return 1;
50+
}
51+
}
52+
53+
printf("Test passed!\n");
54+
return 0;
55+
}

i2c/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ if (TARGET hardware_i2c)
1212
add_subdirectory_exclude_platforms(pcf8523_i2c)
1313
add_subdirectory_exclude_platforms(ht16k33_i2c)
1414
add_subdirectory_exclude_platforms(slave_mem_i2c)
15+
add_subdirectory_exclude_platforms(24lc32_i2c)
1516
else()
1617
message("Skipping I2C examples as hardware_i2c is unavailable on this platform")
1718
endif()

0 commit comments

Comments
 (0)