* 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 "hardware/spi.h"
#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
static inline void cs_select(uint cs_pin) {
asm volatile("nop \n nop \n nop");
gpio_put(cs_pin, 0);
asm volatile("nop \n nop \n nop");
}
static inline void cs_deselect(uint cs_pin) {
asm volatile("nop \n nop \n nop");
gpio_put(cs_pin, 1);
asm volatile("nop \n nop \n nop");
}
void __not_in_flash_func(flash_read)(spi_inst_t *spi, uint cs_pin, uint32_t addr, uint8_t *buf, size_t len) {
cs_select(cs_pin);
uint8_t cmdbuf[4] = {
FLASH_CMD_READ,
addr >> 16,
addr >> 8,
addr
};
spi_write_blocking(spi, cmdbuf, 4);
spi_read_blocking(spi, 0, buf, len);
cs_deselect(cs_pin);
}
void __not_in_flash_func(flash_write_enable)(spi_inst_t *spi, uint cs_pin) {
cs_select(cs_pin);
uint8_t cmd = FLASH_CMD_WRITE_EN;
spi_write_blocking(spi, &cmd, 1);
cs_deselect(cs_pin);
}
void __not_in_flash_func(flash_wait_done)(spi_inst_t *spi, uint cs_pin) {
uint8_t status;
do {
cs_select(cs_pin);
uint8_t buf[2] = {FLASH_CMD_STATUS, 0};
spi_write_read_blocking(spi, buf, buf, 2);
cs_deselect(cs_pin);
status = buf[1];
} while (status & FLASH_STATUS_BUSY_MASK);
}
void __not_in_flash_func(flash_sector_erase)(spi_inst_t *spi, uint cs_pin, uint32_t addr) {
uint8_t cmdbuf[4] = {
FLASH_CMD_SECTOR_ERASE,
addr >> 16,
addr >> 8,
addr
};
flash_write_enable(spi, cs_pin);
cs_select(cs_pin);
spi_write_blocking(spi, cmdbuf, 4);
cs_deselect(cs_pin);
flash_wait_done(spi, cs_pin);
}
void __not_in_flash_func(flash_page_program)(spi_inst_t *spi, uint cs_pin, uint32_t addr, uint8_t data[]) {
uint8_t cmdbuf[4] = {
FLASH_CMD_PAGE_PROGRAM,
addr >> 16,
addr >> 8,
addr
};
flash_write_enable(spi, cs_pin);
cs_select(cs_pin);
spi_write_blocking(spi, cmdbuf, 4);
spi_write_blocking(spi, data, FLASH_PAGE_SIZE);
cs_deselect(cs_pin);
flash_wait_done(spi, cs_pin);
}
void printbuf(uint8_t buf[FLASH_PAGE_SIZE]) {
for (int i = 0; i < FLASH_PAGE_SIZE; ++i) {
if (i % 16 == 15)
printf("%02x\n", buf[i]);
else
printf("%02x ", buf[i]);
}
}
int main() {
stdio_init_all();
#if !defined(spi_default) || !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 spi/spi_flash example requires a board with SPI pins
puts("Default SPI pins were not defined");
#else
printf("SPI flash example\n");
spi_init(spi_default, 1000 * 1000);
gpio_set_function(PICO_DEFAULT_SPI_RX_PIN, GPIO_FUNC_SPI);
gpio_set_function(PICO_DEFAULT_SPI_SCK_PIN, GPIO_FUNC_SPI);
gpio_set_function(PICO_DEFAULT_SPI_TX_PIN, GPIO_FUNC_SPI);
bi_decl(bi_3pins_with_func(PICO_DEFAULT_SPI_RX_PIN, PICO_DEFAULT_SPI_TX_PIN, PICO_DEFAULT_SPI_SCK_PIN, GPIO_FUNC_SPI));
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);
bi_decl(bi_1pin_with_name(PICO_DEFAULT_SPI_CSN_PIN, "SPI CS"));
printf("SPI initialised, let's goooooo\n");
uint8_t page_buf[FLASH_PAGE_SIZE];
const uint32_t target_addr = 0;
flash_sector_erase(spi_default, PICO_DEFAULT_SPI_CSN_PIN, target_addr);
flash_read(spi_default, PICO_DEFAULT_SPI_CSN_PIN, target_addr, page_buf, FLASH_PAGE_SIZE);
printf("After erase:\n");
printbuf(page_buf);
for (int i = 0; i < FLASH_PAGE_SIZE; ++i)
page_buf[i] = i;
flash_page_program(spi_default, PICO_DEFAULT_SPI_CSN_PIN, target_addr, page_buf);
flash_read(spi_default, PICO_DEFAULT_SPI_CSN_PIN, target_addr, page_buf, FLASH_PAGE_SIZE);
printf("After program:\n");
printbuf(page_buf);
flash_sector_erase(spi_default, PICO_DEFAULT_SPI_CSN_PIN, target_addr);
flash_read(spi_default, PICO_DEFAULT_SPI_CSN_PIN, target_addr, page_buf, FLASH_PAGE_SIZE);
printf("Erase again:\n");
printbuf(page_buf);
return 0;
#endif
}