This repository has been archived on 2025-01-25. You can view files and clone it, but cannot push or open issues or pull requests.
rp2040_projects/pio/spi/spi_flash.c

162 lines
4.5 KiB
C

/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include "pico/stdlib.h"
#include "pico/binary_info.h"
#include "pio_spi.h"
// This example uses PIO to erase, program and read back a SPI serial flash
// memory.
// ----------------------------------------------------------------------------
// Generic serial flash code
#define FLASH_PAGE_SIZE 256
#define FLASH_SECTOR_SIZE 4096
#define FLASH_CMD_PAGE_PROGRAM 0x02
#define FLASH_CMD_READ 0x03
#define FLASH_CMD_STATUS 0x05
#define FLASH_CMD_WRITE_EN 0x06
#define FLASH_CMD_SECTOR_ERASE 0x20
#define FLASH_STATUS_BUSY_MASK 0x01
void flash_read(const pio_spi_inst_t *spi, uint32_t addr, uint8_t *buf, size_t len) {
uint8_t cmd[4] = {
FLASH_CMD_READ,
addr >> 16,
addr >> 8,
addr
};
gpio_put(spi->cs_pin, 0);
pio_spi_write8_blocking(spi, cmd, 4);
pio_spi_read8_blocking(spi, buf, len);
gpio_put(spi->cs_pin, 1);
}
void flash_write_enable(const pio_spi_inst_t *spi) {
uint8_t cmd = FLASH_CMD_WRITE_EN;
gpio_put(spi->cs_pin, 0);
pio_spi_write8_blocking(spi, &cmd, 1);
gpio_put(spi->cs_pin, 1);
}
void flash_wait_done(const pio_spi_inst_t *spi) {
uint8_t status;
do {
gpio_put(spi->cs_pin, 0);
uint8_t cmd = FLASH_CMD_STATUS;
pio_spi_write8_blocking(spi, &cmd, 1);
pio_spi_read8_blocking(spi, &status, 1);
gpio_put(spi->cs_pin, 1);
} while (status & FLASH_STATUS_BUSY_MASK);
}
void flash_sector_erase(const pio_spi_inst_t *spi, uint32_t addr) {
uint8_t cmd[4] = {
FLASH_CMD_SECTOR_ERASE,
addr >> 16,
addr >> 8,
addr
};
flash_write_enable(spi);
gpio_put(spi->cs_pin, 0);
pio_spi_write8_blocking(spi, cmd, 4);
gpio_put(spi->cs_pin, 1);
flash_wait_done(spi);
}
void flash_page_program(const pio_spi_inst_t *spi, uint32_t addr, uint8_t data[]) {
flash_write_enable(spi);
uint8_t cmd[4] = {
FLASH_CMD_PAGE_PROGRAM,
addr >> 16,
addr >> 8,
addr
};
gpio_put(spi->cs_pin, 0);
pio_spi_write8_blocking(spi, cmd, 4);
pio_spi_write8_blocking(spi, data, FLASH_PAGE_SIZE);
gpio_put(spi->cs_pin, 1);
flash_wait_done(spi);
}
// ----------------------------------------------------------------------------
// Example program
void printbuf(const uint8_t buf[FLASH_PAGE_SIZE]) {
for (int i = 0; i < FLASH_PAGE_SIZE; ++i)
printf("%02x%c", buf[i], i % 16 == 15 ? '\n' : ' ');
}
int main() {
stdio_init_all();
#if !defined(PICO_DEFAULT_SPI_SCK_PIN) || !defined(PICO_DEFAULT_SPI_TX_PIN) || !defined(PICO_DEFAULT_SPI_RX_PIN) || !defined(PICO_DEFAULT_SPI_CSN_PIN)
#warning pio/spi/spi_flash example requires a board with SPI pins
puts("Default SPI pins were not defined");
#else
puts("PIO SPI Example");
pio_spi_inst_t spi = {
.pio = pio0,
.sm = 0,
.cs_pin = PICO_DEFAULT_SPI_CSN_PIN
};
gpio_init(PICO_DEFAULT_SPI_CSN_PIN);
gpio_put(PICO_DEFAULT_SPI_CSN_PIN, 1);
gpio_set_dir(PICO_DEFAULT_SPI_CSN_PIN, GPIO_OUT);
// Make the CS pin available to picotool
bi_decl(bi_1pin_with_name(PICO_DEFAULT_SPI_CSN_PIN, "CS"));
uint offset = pio_add_program(spi.pio, &spi_cpha0_program);
printf("Loaded program at %d\n", offset);
pio_spi_init(spi.pio, spi.sm, offset,
8, // 8 bits per SPI frame
31.25f, // 1 MHz @ 125 clk_sys
false, // CPHA = 0
false, // CPOL = 0
PICO_DEFAULT_SPI_SCK_PIN,
PICO_DEFAULT_SPI_TX_PIN,
PICO_DEFAULT_SPI_RX_PIN
);
// Make the SPI pins available to picotool
bi_decl(bi_3pins_with_func(PICO_DEFAULT_SPI_RX_PIN, PICO_DEFAULT_SPI_TX_PIN, PICO_DEFAULT_SPI_SCK_PIN, GPIO_FUNC_PIO0));
uint8_t page_buf[FLASH_PAGE_SIZE];
const uint32_t target_addr = 0;
flash_sector_erase(&spi, target_addr);
flash_read(&spi, target_addr, page_buf, FLASH_PAGE_SIZE);
puts("After erase:");
printbuf(page_buf);
for (int i = 0; i < FLASH_PAGE_SIZE; ++i)
page_buf[i] = i;
flash_page_program(&spi, target_addr, page_buf);
flash_read(&spi, target_addr, page_buf, FLASH_PAGE_SIZE);
puts("After program:");
printbuf(page_buf);
flash_sector_erase(&spi, target_addr);
flash_read(&spi, target_addr, page_buf, FLASH_PAGE_SIZE);
puts("Erase again:");
printbuf(page_buf);
return 0;
#endif
}