-
Notifications
You must be signed in to change notification settings - Fork 955
Added 24LC32 EEPROM I2C example #709
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
#include <stdio.h> | ||
#include "pico/stdlib.h" | ||
#include "hardware/i2c.h" | ||
|
||
// This is the max number of bytes which can be written at once during a page write | ||
#define MAX_PAGE_WRITE 32 | ||
|
||
// This is the 24LC32's capacity in bytes | ||
#define EEPROM_SIZE 4096 | ||
Comment on lines
+5
to
+9
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @peterharperuk Would it make sense for these to be in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There may be a way to query the hardware for these values rather than hard code them. But maybe this is good enough for this example |
||
|
||
// Acknowledge polling can be used to see when a write cycle is complete | ||
// Wait for the i2c slave to acknowledge our empty write | ||
bool ack_poll(uint8_t i2c_addr, i2c_inst_t *i2c_instance) { | ||
int timeout = 100; | ||
for (int i = 0; i < timeout; i++) { | ||
if (i2c_write_blocking(i2c_instance, i2c_addr, NULL, 1, false) == 1) { | ||
return true; | ||
} | ||
sleep_ms(1); | ||
} | ||
printf("ack timeout\n"); | ||
return false; | ||
} | ||
|
||
// Read num bytes of memory starting at given address into result | ||
bool read_eeprom(uint16_t address, uint8_t *result, uint16_t num, uint8_t i2c_addr, i2c_inst_t *i2c_instance) { | ||
if ((address + num - 1) > EEPROM_SIZE) { | ||
printf("ERROR: Tried to read memory outside EEPROM's range.\n"); | ||
return false; | ||
} | ||
|
||
for (int i = 0; i < num; i++) { | ||
uint8_t byte1 = (uint8_t)(address >> 8); | ||
uint8_t byte2 = (uint8_t)(address); | ||
|
||
uint8_t buf[2] = {byte1, byte2}; | ||
Comment on lines
+33
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @peterharperuk Should these variables be declared outside of the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like it makes more sense as it is here? |
||
|
||
i2c_write_blocking(i2c_instance, i2c_addr, buf, 2, true); | ||
i2c_read_blocking(i2c_instance, i2c_addr, (result + i), 1, false); | ||
|
||
address++; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
// Write a single byte of data at a specified address in memory | ||
bool byte_write_eeprom(uint16_t address, uint8_t data, uint8_t i2c_addr, i2c_inst_t *i2c_instance) { | ||
if (address >= EEPROM_SIZE) { | ||
printf("ERROR: Tried to write to memory outside EEPROM's range.\n"); | ||
return false; | ||
} | ||
|
||
uint8_t byte1 = (uint8_t)(address >> 8); | ||
uint8_t byte2 = (uint8_t)(address); | ||
|
||
uint8_t buf[3] = {byte1, byte2, data}; | ||
|
||
i2c_write_blocking(i2c_instance, i2c_addr, buf, 3, false); | ||
|
||
// ack_poll to wait for write to be complete | ||
return ack_poll(i2c_addr, i2c_instance); | ||
} | ||
|
||
// Write a block of data to eeprom | ||
bool page_write_eeprom(uint16_t address, uint8_t *data, uint8_t num, uint8_t i2c_addr, i2c_inst_t *i2c_instance) { | ||
if (num > MAX_PAGE_WRITE) { | ||
printf("ERROR: Tried to write more than %i bytes.\n", MAX_PAGE_WRITE); | ||
return false; | ||
} else if ((address + num - 1) > EEPROM_SIZE) { | ||
printf("ERROR: Tried to write to memory outside EEPROM's range.\n"); | ||
Louis31423142 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return false; | ||
} | ||
|
||
uint8_t byte1 = (uint8_t)(address >> 8); | ||
uint8_t byte2 = (uint8_t)(address); | ||
uint8_t buf[2 + num]; | ||
buf[0] = byte1; | ||
buf[1] = byte2; | ||
|
||
// transfer data into buffer | ||
for (int i = 0; i < num; i++) { | ||
buf[i + 2] = data[i]; | ||
} | ||
|
||
i2c_write_blocking(i2c_instance, i2c_addr, buf, 2 + num, false); | ||
|
||
// ack_poll to wait for write to be complete | ||
return ack_poll(i2c_addr, i2c_instance); | ||
} | ||
|
||
// Initialise i2c for given gpio at given frequency | ||
void eeprom_init(int sda_pin, int scl_pin, int freq, i2c_inst_t *i2c_instance) { | ||
i2c_init(i2c_instance, freq); | ||
|
||
gpio_set_function(sda_pin, GPIO_FUNC_I2C); | ||
gpio_set_function(scl_pin, GPIO_FUNC_I2C); | ||
gpio_pull_up(sda_pin); | ||
gpio_pull_up(scl_pin); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
#ifndef PICO_I2C_EEPROM_LIB_H | ||
#define PICO_I2C_EEPROM_LIB_H | ||
|
||
#include "hardware/i2c.h" | ||
|
||
// Acknowledge polling can be used to see when a write cycle is complete | ||
// Wait for the i2c slave to acknowledge our empty write | ||
bool ack_poll(uint8_t i2c_addr, i2c_inst_t *i2c_instance); | ||
|
||
// Read num bytes of memory starting at given address into result | ||
bool read_eeprom(uint16_t address, uint8_t *result, uint16_t num, uint8_t i2c_addr, i2c_inst_t *i2c_instance); | ||
|
||
// Write a single byte of data at a specified address in memory | ||
bool byte_write_eeprom(uint16_t address, uint8_t data, uint8_t i2c_addr, i2c_inst_t *i2c_instance); | ||
|
||
// Write a block of data to eeprom | ||
bool page_write_eeprom(uint16_t address, uint8_t *data, uint8_t num, uint8_t i2c_addr, i2c_inst_t *i2c_instance); | ||
|
||
// Initialise i2c for given gpio at given frequency | ||
void eeprom_init(int sda_pin, int scl_pin, int freq, i2c_inst_t *i2c_instance); | ||
|
||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# Add libary | ||
add_library(24lc32_i2c_lib INTERFACE) | ||
target_sources(24lc32_i2c_lib INTERFACE | ||
${CMAKE_CURRENT_LIST_DIR}/24lc32_i2c_lib.c | ||
) | ||
target_include_directories(24lc32_i2c_lib INTERFACE | ||
${CMAKE_CURRENT_LIST_DIR} | ||
) | ||
target_link_libraries(24lc32_i2c_lib INTERFACE | ||
pico_stdlib | ||
hardware_i2c | ||
) | ||
|
||
# Add executable | ||
add_executable(24lc32_i2c | ||
example.c | ||
) | ||
|
||
target_link_libraries(24lc32_i2c | ||
24lc32_i2c_lib | ||
pico_stdlib | ||
hardware_i2c | ||
) | ||
|
||
pico_add_extra_outputs(24lc32_i2c) | ||
|
||
# add url via pico_set_program_url | ||
example_auto_set_url(24lc32_i2c) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
= Reading and writing 24LC32 EEPROM via I2C | ||
|
||
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. | ||
|
||
== Wiring information | ||
|
||
[[24lc32_i2c_wiring]] | ||
[pdfwidth=75%] | ||
.Wiring Diagram for 24LC32 EEPROM via I2C. | ||
image::24lc32_i2c.png[] | ||
|
||
== List of Files | ||
|
||
CMakeLists.txt:: CMake file to incorporate the example into the examples build tree. | ||
24lc32_i2c_lib.c:: Library containing functions to interact with 24LC32 eeprom via I2C. | ||
24lc32_i2c_lib.h:: Header file containing function declarations for the 24LC32 library. | ||
example.c:: The example code. | ||
|
||
== Bill of Materials | ||
|
||
.A list of materials required for the example | ||
[[24lc32_i2c-bom-table]] | ||
[cols=3] | ||
|=== | ||
| *Item* | *Quantity* | Details | ||
| Breadboard | 1 | generic part | ||
| Raspberry Pi Pico (any) | 1 | https://www.raspberrypi.com/products/raspberry-pi-pico/ | ||
| 24LC32-based breakout board | 1 | https://www.adafruit.com/product/5146 | ||
| M/M Jumper wires | 4 | generic part | ||
|=== |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
#include <stdio.h> | ||
#include "pico/stdlib.h" | ||
#include "hardware/i2c.h" | ||
#include "pico/binary_info.h" | ||
#include "24lc32_i2c_lib.h" | ||
|
||
// Default I2C address of 24LC32 | ||
#define I2C_ADDRESS 0x50 | ||
|
||
int main() { | ||
stdio_init_all(); | ||
|
||
#if !defined(i2c_default) || !defined(PICO_DEFAULT_I2C_SDA_PIN) || !defined(PICO_DEFAULT_I2C_SCL_PIN) | ||
#warning 24lc32_i2c example requires a board with i2c pins | ||
puts("Default I2C pins were not defined"); | ||
return 0; | ||
#else | ||
// useful information for picotool | ||
bi_decl(bi_2pins_with_func(PICO_DEFAULT_I2C_SDA_PIN, PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C)); | ||
bi_decl(bi_program_description("24LC32 I2C example for the Raspberry Pi Pico")); | ||
|
||
eeprom_init(PICO_DEFAULT_I2C_SDA_PIN, PICO_DEFAULT_I2C_SCL_PIN, 400*1000, i2c_default); | ||
|
||
printf("24LC32 I2C EEPROM example\nStarting test...\n\n"); | ||
|
||
// Write the byte at location 0x00 to 0 | ||
byte_write_eeprom(0x00, 0, I2C_ADDRESS, i2c_default); | ||
|
||
// Make an array of integers from 1 to 31 and write the array to eeprom starting at 0x01 | ||
uint8_t data_list[31]; | ||
for (int i = 0; i < 31; i++) { | ||
data_list[i] = i + 1; | ||
} | ||
page_write_eeprom(0x01, data_list, 31, I2C_ADDRESS, i2c_default); | ||
|
||
// Read eeprom, and ensure we observe ascending integers from 0 to 31 | ||
uint8_t result[32]; | ||
read_eeprom(0x0, result, 32, I2C_ADDRESS, i2c_default); | ||
|
||
for (int i = 0; i < 32; i++) { | ||
printf("read: %i, expected: %i\n", result[i], i); | ||
if (result[i] != i) { | ||
printf("Unexpected read!\n"); | ||
return 1; | ||
} | ||
} | ||
|
||
// Now re-write and re-read eeprom | ||
printf("\nReversing order...\n\n"); | ||
for (int i = 0; i < 31; i++) { | ||
data_list[i] = 31 - i; | ||
} | ||
page_write_eeprom(0x00, data_list, 31, I2C_ADDRESS, i2c_default); | ||
byte_write_eeprom(0x1F, 0, I2C_ADDRESS, i2c_default); | ||
|
||
// Read eeprom, and ensure we observe descending integers from 31 to 0 | ||
read_eeprom(0x0, result, 32, I2C_ADDRESS, i2c_default); | ||
|
||
for (int i = 0; i < 32; i++) { | ||
printf("read: %i, expected: %i\n", result[i], 31 - i); | ||
if (result[i] != 31 - i) { | ||
printf("Unexpected read!\n"); | ||
return 1; | ||
} | ||
} | ||
|
||
printf("Test passed!\n"); | ||
return 0; | ||
#endif | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
arguably missing an "a "