mirror of
https://github.com/espressif/esp-idf
synced 2025-03-10 01:29:21 -04:00
spi: add eeprom example
This commit is contained in:
parent
0f1041cc04
commit
f53812d27a
6
examples/peripherals/spi_master/hd_eeprom/CMakeLists.txt
Normal file
6
examples/peripherals/spi_master/hd_eeprom/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(spi_eeprom)
|
9
examples/peripherals/spi_master/hd_eeprom/Makefile
Normal file
9
examples/peripherals/spi_master/hd_eeprom/Makefile
Normal file
@ -0,0 +1,9 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := spi_eeprom
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
24
examples/peripherals/spi_master/hd_eeprom/README.md
Normal file
24
examples/peripherals/spi_master/hd_eeprom/README.md
Normal file
@ -0,0 +1,24 @@
|
||||
## SPI master half duplex EEPROM example
|
||||
|
||||
This code demonstrates how to use the SPI master half duplex mode to read/write a AT93C46D
|
||||
EEPROM (8-bit mode). There is also an Kconfig option `EXAMPLE_USE_SPI1_PINS` allowing use the
|
||||
SPI1 (bus with code Flash connected on official modules).
|
||||
|
||||
### Connections
|
||||
|
||||
For different chip and host used, the connections may be different.
|
||||
|
||||
| | ESP32 | ESP32 | ESP32S2 |
|
||||
| ---- | ----- | ----- | ------- |
|
||||
| Host | SPI1 | HSPI | FSPI |
|
||||
| VCC | 3.3V | 3.3V | 3.3V |
|
||||
| GND | GND | GND | GND |
|
||||
| DO | 7 | 18 | 37 |
|
||||
| DI | 8 | 23 | 35 |
|
||||
| SK | 6 | 19 | 36 |
|
||||
| CS | 13 | 13 | 34 |
|
||||
| ORG | GND | GND | GND |
|
||||
|
||||
### Notes
|
||||
|
||||
If you meet timeout issues, please check your connections.
|
@ -0,0 +1,4 @@
|
||||
idf_component_register(SRCS "spi_eeprom.c"
|
||||
LDFRAGMENTS "linker.lf"
|
||||
INCLUDE_DIRS ".")
|
||||
|
@ -0,0 +1,6 @@
|
||||
#
|
||||
# Main Makefile. This is basically the same as a component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||
|
||||
COMPONENT_ADD_LDFRAGMENTS += "linker.lf"
|
@ -0,0 +1,24 @@
|
||||
# This example supports running on the SPI1 bus, which is shared with SPI flash accessed by the
|
||||
# cache. When doing transaction on SPI1 bus, data cannot be fetched from the flash, so all the data
|
||||
# used during this time should be put into the internal RAM.
|
||||
|
||||
[mapping:eeprom]
|
||||
archive: libeeprom.a
|
||||
entries:
|
||||
* (noflash)
|
||||
|
||||
[mapping:ext_driver]
|
||||
archive: libdriver.a
|
||||
entries:
|
||||
# gpio_set_level, gpio_get_level, gpio_context, _gpio_hal, etc...
|
||||
gpio (noflash)
|
||||
|
||||
[mapping:ext_soc]
|
||||
archive: libsoc.a
|
||||
entries:
|
||||
gpio_hal (noflash)
|
||||
|
||||
[mapping:ext_newlib]
|
||||
archive: libnewlib.a
|
||||
entries:
|
||||
time:usleep (noflash)
|
@ -0,0 +1,324 @@
|
||||
/*
|
||||
This code demonstrates how to use the SPI master half duplex mode to read/write a AT932C46D
|
||||
EEPROM (8-bit mode).
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include "spi_eeprom.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "driver/gpio.h"
|
||||
#include <unistd.h>
|
||||
#include "esp_log.h"
|
||||
#include <sys/param.h>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
|
||||
#define EEPROM_BUSY_TIMEOUT_MS 5
|
||||
|
||||
#define EEPROM_CLK_FREQ (1*1000*1000) //When powered by 3.3V, EEPROM max freq is 1MHz
|
||||
#define EEPROM_INPUT_DELAY_NS ((1000*1000*1000/EEPROM_CLK_FREQ)/2+20)
|
||||
|
||||
#define ADDR_MASK 0x7f
|
||||
|
||||
#define CMD_EWDS 0x200
|
||||
#define CMD_WRAL 0x200
|
||||
#define CMD_ERAL 0x200
|
||||
#define CMD_EWEN 0x200
|
||||
#define CMD_CKBS 0x000
|
||||
#define CMD_READ 0x300
|
||||
#define CMD_ERASE 0x380
|
||||
#define CMD_WRITE 0x280
|
||||
|
||||
#define ADD_EWDS 0x00
|
||||
#define ADD_WRAL 0x20
|
||||
#define ADD_ERAL 0x40
|
||||
#define ADD_EWEN 0x60
|
||||
|
||||
/// Context (config and data) of the spi_eeprom
|
||||
struct eeprom_context_t{
|
||||
eeprom_config_t cfg; ///< Configuration by the caller.
|
||||
spi_device_handle_t spi; ///< SPI device handle
|
||||
xSemaphoreHandle ready_sem; ///< Semaphore for ready signal
|
||||
};
|
||||
|
||||
typedef struct eeprom_context_t eeprom_context_t;
|
||||
|
||||
static const char TAG[] = "eeprom";
|
||||
|
||||
|
||||
// Workaround: The driver depends on some data in the flash and cannot be placed to DRAM easily for
|
||||
// now. Using the version in LL instead.
|
||||
#define gpio_set_level gpio_set_level_patch
|
||||
#include "hal/gpio_ll.h"
|
||||
static inline esp_err_t gpio_set_level_patch(gpio_num_t gpio_num, uint32_t level)
|
||||
{
|
||||
gpio_ll_set_level(&GPIO, gpio_num, level);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
static esp_err_t eeprom_simple_cmd(eeprom_context_t *ctx, uint16_t cmd)
|
||||
{
|
||||
spi_transaction_t t = {
|
||||
.cmd = cmd,
|
||||
.user = ctx
|
||||
};
|
||||
return spi_device_polling_transmit(ctx->spi, &t);
|
||||
}
|
||||
|
||||
static esp_err_t eeprom_wait_done(eeprom_context_t* ctx)
|
||||
{
|
||||
//have to keep cs low for 250ns
|
||||
usleep(1);
|
||||
//clear signal
|
||||
if (ctx->cfg.intr_used) {
|
||||
xSemaphoreTake(ctx->ready_sem, 0);
|
||||
gpio_set_level(ctx->cfg.cs_io, 1);
|
||||
gpio_intr_enable(ctx->cfg.miso_io);
|
||||
|
||||
//Max processing time is 5ms, tick=1 may happen very soon, set to 2 at least
|
||||
uint32_t tick_to_wait = MAX(EEPROM_BUSY_TIMEOUT_MS / portTICK_PERIOD_MS, 2);
|
||||
BaseType_t ret = xSemaphoreTake(ctx->ready_sem, tick_to_wait);
|
||||
gpio_intr_disable(ctx->cfg.miso_io);
|
||||
gpio_set_level(ctx->cfg.cs_io, 0);
|
||||
|
||||
if (ret != pdTRUE) return ESP_ERR_TIMEOUT;
|
||||
} else {
|
||||
bool timeout = true;
|
||||
gpio_set_level(ctx->cfg.cs_io, 1);
|
||||
for (int i = 0; i < EEPROM_BUSY_TIMEOUT_MS * 1000; i ++) {
|
||||
if (gpio_get_level(ctx->cfg.miso_io)) {
|
||||
timeout = false;
|
||||
break;
|
||||
}
|
||||
usleep(1);
|
||||
}
|
||||
gpio_set_level(ctx->cfg.cs_io, 0);
|
||||
if (timeout) return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void cs_high(spi_transaction_t* t)
|
||||
{
|
||||
ESP_EARLY_LOGV(TAG, "cs high %d.", ((eeprom_context_t*)t->user)->cfg.cs_io);
|
||||
gpio_set_level(((eeprom_context_t*)t->user)->cfg.cs_io, 1);
|
||||
}
|
||||
|
||||
static void cs_low(spi_transaction_t* t)
|
||||
{
|
||||
gpio_set_level(((eeprom_context_t*)t->user)->cfg.cs_io, 0);
|
||||
ESP_EARLY_LOGV(TAG, "cs low %d.", ((eeprom_context_t*)t->user)->cfg.cs_io);
|
||||
}
|
||||
|
||||
void ready_rising_isr(void* arg)
|
||||
{
|
||||
eeprom_context_t* ctx = (eeprom_context_t*)arg;
|
||||
xSemaphoreGive(ctx->ready_sem);
|
||||
ESP_EARLY_LOGV(TAG, "ready detected.");
|
||||
}
|
||||
|
||||
esp_err_t spi_eeprom_deinit(eeprom_context_t* ctx)
|
||||
{
|
||||
spi_bus_remove_device(ctx->spi);
|
||||
if (ctx->cfg.intr_used) {
|
||||
vSemaphoreDelete(ctx->ready_sem);
|
||||
}
|
||||
free(ctx);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t spi_eeprom_init(const eeprom_config_t *cfg, eeprom_context_t** out_ctx)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
if (cfg->intr_used && cfg->host == SPI1_HOST) {
|
||||
ESP_LOGE(TAG, "interrupt cannot be used on SPI1 host.");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
eeprom_context_t* ctx = (eeprom_context_t*)malloc(sizeof(eeprom_context_t));
|
||||
if (!ctx) return ESP_ERR_NO_MEM;
|
||||
|
||||
*ctx = (eeprom_context_t) {
|
||||
.cfg = *cfg,
|
||||
};
|
||||
|
||||
spi_device_interface_config_t devcfg={
|
||||
.command_bits = 10,
|
||||
.clock_speed_hz = EEPROM_CLK_FREQ,
|
||||
.mode = 0, //SPI mode 0
|
||||
/*
|
||||
* The timing requirements to read the busy signal from the EEPROM cannot be easily emulated
|
||||
* by SPI transactions. We need to control CS pin by SW to check the busy signal manually.
|
||||
*/
|
||||
.spics_io_num = -1,
|
||||
.queue_size = 1,
|
||||
.flags = SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_POSITIVE_CS,
|
||||
.pre_cb = cs_high,
|
||||
.post_cb = cs_low,
|
||||
.input_delay_ns = EEPROM_INPUT_DELAY_NS, //the EEPROM output the data half a SPI clock behind.
|
||||
};
|
||||
//Attach the EEPROM to the SPI bus
|
||||
err = spi_bus_add_device(ctx->cfg.host, &devcfg, &ctx->spi);
|
||||
if (err != ESP_OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
gpio_set_level(ctx->cfg.cs_io, 0);
|
||||
gpio_config_t cs_cfg = {
|
||||
.pin_bit_mask = BIT64(ctx->cfg.cs_io),
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
};
|
||||
gpio_config(&cs_cfg);
|
||||
|
||||
if (ctx->cfg.intr_used) {
|
||||
ctx->ready_sem = xSemaphoreCreateBinary();
|
||||
if (ctx->ready_sem == NULL) {
|
||||
err = ESP_ERR_NO_MEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
gpio_set_intr_type(ctx->cfg.miso_io, GPIO_INTR_POSEDGE);
|
||||
err = gpio_isr_handler_add(ctx->cfg.miso_io, ready_rising_isr, ctx);
|
||||
if (err != ESP_OK) {
|
||||
goto cleanup;
|
||||
}
|
||||
gpio_intr_disable(ctx->cfg.miso_io);
|
||||
}
|
||||
*out_ctx = ctx;
|
||||
return ESP_OK;
|
||||
|
||||
cleanup:
|
||||
if (ctx->spi) {
|
||||
spi_bus_remove_device(ctx->spi);
|
||||
ctx->spi = NULL;
|
||||
}
|
||||
if (ctx->ready_sem) {
|
||||
vSemaphoreDelete(ctx->ready_sem);
|
||||
ctx->ready_sem = NULL;
|
||||
}
|
||||
free(ctx);
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t spi_eeprom_read(eeprom_context_t* ctx, uint8_t addr, uint8_t* out_data)
|
||||
{
|
||||
spi_transaction_t t = {
|
||||
.cmd = CMD_READ | (addr & ADDR_MASK),
|
||||
.rxlength = 8,
|
||||
.flags = SPI_TRANS_USE_RXDATA,
|
||||
.user = ctx,
|
||||
};
|
||||
esp_err_t err = spi_device_polling_transmit(ctx->spi, &t);
|
||||
if (err!= ESP_OK) return err;
|
||||
|
||||
*out_data = t.rx_data[0];
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t spi_eeprom_erase(eeprom_context_t* ctx, uint8_t addr)
|
||||
{
|
||||
esp_err_t err;
|
||||
err = spi_device_acquire_bus(ctx->spi, portMAX_DELAY);
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
err = eeprom_simple_cmd(ctx, CMD_ERASE | (addr & ADDR_MASK));
|
||||
|
||||
if (err == ESP_OK) {
|
||||
err = eeprom_wait_done(ctx);
|
||||
}
|
||||
|
||||
spi_device_release_bus(ctx->spi);
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t spi_eeprom_write(eeprom_context_t* ctx, uint8_t addr, uint8_t data)
|
||||
{
|
||||
esp_err_t err;
|
||||
err = spi_device_acquire_bus(ctx->spi, portMAX_DELAY);
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
spi_transaction_t t = {
|
||||
.cmd = CMD_WRITE | (addr & ADDR_MASK),
|
||||
.length = 8,
|
||||
.flags = SPI_TRANS_USE_TXDATA,
|
||||
.tx_data = {data},
|
||||
.user = ctx,
|
||||
};
|
||||
err = spi_device_polling_transmit(ctx->spi, &t);
|
||||
|
||||
if (err == ESP_OK) {
|
||||
err = eeprom_wait_done(ctx);
|
||||
}
|
||||
|
||||
spi_device_release_bus(ctx->spi);
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t spi_eeprom_write_enable(eeprom_context_t* ctx)
|
||||
{
|
||||
return eeprom_simple_cmd(ctx, CMD_EWEN | ADD_EWEN);
|
||||
}
|
||||
|
||||
esp_err_t spi_eeprom_write_disable(eeprom_context_t* ctx)
|
||||
{
|
||||
return eeprom_simple_cmd(ctx, CMD_EWDS | ADD_EWDS);
|
||||
}
|
||||
|
||||
esp_err_t spi_eeprom_erase_all(eeprom_context_t* ctx)
|
||||
{
|
||||
#if !CONFIG_EXAMPLE_5V_COMMANDS
|
||||
//not supported in 3.3V VCC
|
||||
ESP_LOGE(TAG, "erase all not supported by EEPROM under 3.3V VCC");
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
#endif
|
||||
|
||||
esp_err_t err;
|
||||
err = spi_device_acquire_bus(ctx->spi, portMAX_DELAY);
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
err = eeprom_simple_cmd(ctx, CMD_ERAL | ADD_ERAL);
|
||||
|
||||
if (err == ESP_OK) {
|
||||
err = eeprom_wait_done(ctx);
|
||||
}
|
||||
|
||||
spi_device_release_bus(ctx->spi);
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t spi_eeprom_write_all(eeprom_context_t* ctx, uint8_t data)
|
||||
{
|
||||
#if !CONFIG_EXAMPLE_5V_COMMANDS
|
||||
//not supported in 3.3V VCC
|
||||
ESP_LOGE(TAG, "write all not supported by EEPROM under 3.3V VCC");
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
#endif
|
||||
|
||||
esp_err_t err;
|
||||
err = spi_device_acquire_bus(ctx->spi, portMAX_DELAY);
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
spi_transaction_t t = {
|
||||
.cmd = CMD_WRAL | ADD_WRAL,
|
||||
.length = 8,
|
||||
.flags = SPI_TRANS_USE_TXDATA,
|
||||
.tx_data = {data},
|
||||
.user = ctx,
|
||||
};
|
||||
err = spi_device_polling_transmit(ctx->spi, &t);
|
||||
|
||||
if (err == ESP_OK) {
|
||||
err = eeprom_wait_done(ctx);
|
||||
}
|
||||
|
||||
spi_device_release_bus(ctx->spi);
|
||||
return err;
|
||||
}
|
@ -0,0 +1,123 @@
|
||||
/*
|
||||
This code demonstrates how to use the SPI master half duplex mode to read/write a AT932C46D
|
||||
EEPROM (8-bit mode).
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "driver/spi_master.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
/// Configurations of the spi_eeprom
|
||||
typedef struct {
|
||||
spi_host_device_t host; ///< The SPI host used, set before calling `spi_eeprom_init()`
|
||||
gpio_num_t cs_io; ///< CS gpio number, set before calling `spi_eeprom_init()`
|
||||
gpio_num_t miso_io; ///< MISO gpio number, set before calling `spi_eeprom_init()`
|
||||
bool intr_used; ///< Whether to use polling or interrupt when waiting for write to be done. Set before calling `spi_eeprom_init()`.
|
||||
} eeprom_config_t;
|
||||
|
||||
typedef struct eeprom_context_t* eeprom_handle_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize the hardware.
|
||||
*
|
||||
* @param config Configuration of the EEPROM
|
||||
* @param out_handle Output context of EEPROM communication.
|
||||
* @return
|
||||
* - ESP_OK: on success
|
||||
* - ESP_ERR_INVALID_ARG: If the configuration in the context is incorrect.
|
||||
* - ESP_ERR_NO_MEM: if semaphore create failed.
|
||||
* - or other return value from `spi_bus_add_device()` or `gpio_isr_handler_add()`.
|
||||
*/
|
||||
esp_err_t spi_eeprom_init(const eeprom_config_t *config, eeprom_handle_t* out_handle);
|
||||
|
||||
/**
|
||||
* @brief Release the resources used by the EEPROM.
|
||||
*
|
||||
* @param handle Context of EEPROM communication.
|
||||
* @return Always ESP_OK
|
||||
*/
|
||||
esp_err_t spi_eeprom_deinit(eeprom_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Read a byte from the EEPROM.
|
||||
*
|
||||
* @param handle Context of EEPROM communication.
|
||||
* @param addr Address to read.
|
||||
* @param out_data Buffer to output the read data.
|
||||
* @return return value from `spi_device_polling_transmit()`.
|
||||
*/
|
||||
esp_err_t spi_eeprom_read(eeprom_handle_t handle, uint8_t addr, uint8_t* out_data);
|
||||
|
||||
/**
|
||||
* @brief Erase a byte in the EEPROM.
|
||||
*
|
||||
* @param handle Context of EEPROM communication.
|
||||
* @param addr Address to erase.
|
||||
* @return
|
||||
* - ESP_OK: on success
|
||||
* - ESP_ERR_TIMEOUT: if the EEPROM is not able to be ready before the time in the spec. This may mean that the connection is not correct.
|
||||
* - or return value from `spi_device_acquire_bus()` `spi_device_polling_transmit()`.
|
||||
*/
|
||||
esp_err_t spi_eeprom_erase(eeprom_handle_t handle, uint8_t addr);
|
||||
|
||||
/**
|
||||
* @brief Write a byte into the EEPROM
|
||||
*
|
||||
* @param handle Context of EEPROM communication.
|
||||
* @param addr Address to write.
|
||||
* @param data The byte to write.
|
||||
* @return
|
||||
* - ESP_OK: on success
|
||||
* - ESP_ERR_TIMEOUT: if the EEPROM is not able to be ready before the time in the spec. This may mean that the connection is not correct.
|
||||
* - or return value from `spi_device_acquire_bus()` `spi_device_polling_transmit()`.
|
||||
*/
|
||||
esp_err_t spi_eeprom_write(eeprom_handle_t handle, uint8_t addr, uint8_t data);
|
||||
|
||||
/**
|
||||
* @brief Enable following write/erase to the EEPROM.
|
||||
*
|
||||
* @param handle Context of EEPROM communication.
|
||||
* @return return value from `spi_device_polling_transmit()`.
|
||||
*/
|
||||
esp_err_t spi_eeprom_write_enable(eeprom_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Disable following write/erase to the EEPROM.
|
||||
*
|
||||
* @param handle Context of EEPROM communication.
|
||||
* @return return value from `spi_device_polling_transmit()`.
|
||||
*/
|
||||
esp_err_t spi_eeprom_write_disable(eeprom_handle_t handle);
|
||||
|
||||
#if CONFIG_EXAMPLE_5V_COMMANDS
|
||||
/**
|
||||
* @brief Erase all the memory in the EEPROM.
|
||||
*
|
||||
* @note This is only supported when EEPROM VCC is 5V.
|
||||
* @param handle Context of EEPROM communication.
|
||||
* @return
|
||||
* - ESP_OK: on success
|
||||
* - ESP_ERR_TIMEOUT: if the EEPROM is not able to be ready before the time in the spec. This may mean that the connection is not correct.
|
||||
* - or return value from `spi_device_acquire_bus()` `spi_device_polling_transmit()`.
|
||||
*/
|
||||
esp_err_t spi_eeprom_erase_all(eeprom_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief write all the memory in the EEPROM to the value given.
|
||||
*
|
||||
* @note This is only supported when EEPROM VCC is 5V.
|
||||
* @param handle Context of EEPROM communication.
|
||||
* @return
|
||||
* - ESP_OK: on success
|
||||
* - ESP_ERR_TIMEOUT: if the EEPROM is not able to be ready before the time in the spec. This may mean that the connection is not correct.
|
||||
* - or return value from `spi_device_acquire_bus()` `spi_device_polling_transmit()`.
|
||||
*/
|
||||
esp_err_t spi_eeprom_write_all(eeprom_handle_t handle, uint8_t data);
|
||||
#endif //CONFIG_EXAMPLE_5V_COMMANDS
|
@ -0,0 +1,5 @@
|
||||
set(srcs "spi_eeprom_main.c")
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
INCLUDE_DIRS ".")
|
||||
|
@ -0,0 +1,32 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_USE_SPI1_PINS
|
||||
bool "The example runs on SPI1 pins or some other pins"
|
||||
default n
|
||||
depends on IDF_TARGET_ESP32
|
||||
help
|
||||
Enable this option will make the EEPROM use SPI1 pins, which is shared with the main
|
||||
flash chip.
|
||||
|
||||
Currently this example hasn't supported SPI1 pins on other chips yet.
|
||||
|
||||
config EXAMPLE_INTR_USED
|
||||
bool "Use the interrupt to detect the eeprom busy"
|
||||
default y
|
||||
depends on !EXAMPLE_USE_SPI1_PINS
|
||||
help
|
||||
Enable this option will allow the example to be blocked while the EEPROM is working
|
||||
in progress, and unblocked by GPIO interrupt. Otherwise the example will keep polling
|
||||
until the EEPROM is idle.
|
||||
|
||||
config EXAMPLE_5V_COMMANDS
|
||||
bool "The EEPROM is supplied by 5V power"
|
||||
default n
|
||||
help
|
||||
The Erase_All and Write_All commands of EEPROM are only supported when EEPROM is
|
||||
supplied by 5V power. Enable this to use those two commands.
|
||||
|
||||
But please note that ESP chips don't support 5V IO, you need to add external
|
||||
level-shifting circuits between ESP chip to the EEPROM.
|
||||
|
||||
endmenu
|
@ -0,0 +1,4 @@
|
||||
#
|
||||
# Main Makefile. This is basically the same as a component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
113
examples/peripherals/spi_master/hd_eeprom/main/spi_eeprom_main.c
Normal file
113
examples/peripherals/spi_master/hd_eeprom/main/spi_eeprom_main.c
Normal file
@ -0,0 +1,113 @@
|
||||
/* SPI Master Half Duplex EEPROM example.
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/spi_master.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_log.h"
|
||||
#include "spi_eeprom.h"
|
||||
|
||||
|
||||
/*
|
||||
This code demonstrates how to use the SPI master half duplex mode to read/write a AT932C46D EEPROM (8-bit mode).
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
# ifdef CONFIG_EXAMPLE_USE_SPI1_PINS
|
||||
# define EEPROM_HOST SPI1_HOST
|
||||
# define DMA_CHAN 0
|
||||
// Use default pins, same as the flash chip.
|
||||
# define PIN_NUM_MISO 7
|
||||
# define PIN_NUM_MOSI 8
|
||||
# define PIN_NUM_CLK 6
|
||||
# else
|
||||
# define EEPROM_HOST HSPI_HOST
|
||||
# define DMA_CHAN 2
|
||||
# define PIN_NUM_MISO 18
|
||||
# define PIN_NUM_MOSI 23
|
||||
# define PIN_NUM_CLK 19
|
||||
# endif
|
||||
|
||||
# define PIN_NUM_CS 13
|
||||
#elif defined CONFIG_IDF_TARGET_ESP32S2
|
||||
# define EEPROM_HOST SPI2_HOST
|
||||
# define DMA_CHAN EEPROM_HOST
|
||||
|
||||
# define PIN_NUM_MISO 37
|
||||
# define PIN_NUM_MOSI 35
|
||||
# define PIN_NUM_CLK 36
|
||||
# define PIN_NUM_CS 34
|
||||
#endif
|
||||
|
||||
static const char TAG[] = "main";
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
esp_err_t ret;
|
||||
#ifndef CONFIG_EXAMPLE_USE_SPI1_PINS
|
||||
ESP_LOGI(TAG, "Initializing bus SPI%d...", EEPROM_HOST+1);
|
||||
spi_bus_config_t buscfg={
|
||||
.miso_io_num = PIN_NUM_MISO,
|
||||
.mosi_io_num = PIN_NUM_MOSI,
|
||||
.sclk_io_num = PIN_NUM_CLK,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
.max_transfer_sz = 32,
|
||||
};
|
||||
//Initialize the SPI bus
|
||||
ret = spi_bus_initialize(EEPROM_HOST, &buscfg, DMA_CHAN);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
#else
|
||||
ESP_LOGI(TAG, "Attach to main flash bus...");
|
||||
#endif
|
||||
|
||||
eeprom_config_t eeprom_config = {
|
||||
.cs_io = PIN_NUM_CS,
|
||||
.host = EEPROM_HOST,
|
||||
.miso_io = PIN_NUM_MISO,
|
||||
};
|
||||
#ifdef CONFIG_EXAMPLE_INTR_USED
|
||||
eeprom_config.intr_used = true;
|
||||
gpio_install_isr_service(0);
|
||||
#endif
|
||||
|
||||
eeprom_handle_t eeprom_handle;
|
||||
|
||||
ESP_LOGI(TAG, "Initializing device...");
|
||||
spi_eeprom_init(&eeprom_config, &eeprom_handle);
|
||||
|
||||
spi_eeprom_write_enable(eeprom_handle);
|
||||
|
||||
const char test_str[] = "Hello World!";
|
||||
ESP_LOGI(TAG, "Write: %s", test_str);
|
||||
for (int i = 0; i < sizeof(test_str); i++) {
|
||||
// No need for this EEPROM to erase before write.
|
||||
ret = spi_eeprom_write(eeprom_handle, i, test_str[i]);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
}
|
||||
|
||||
uint8_t test_buf[32] = "";
|
||||
for (int i = 0; i < sizeof(test_str); i++) {
|
||||
ret = spi_eeprom_read(eeprom_handle, i, &test_buf[i]);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
}
|
||||
ESP_LOGI(TAG, "Read: %s", test_buf);
|
||||
|
||||
ESP_LOGI(TAG, "Example finished.");
|
||||
|
||||
while (1) {
|
||||
// Add your main loop handling code here.
|
||||
vTaskDelay(1);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user