155 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			155 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/**
 | 
						|
 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
 | 
						|
 *
 | 
						|
 * SPDX-License-Identifier: BSD-3-Clause
 | 
						|
 */
 | 
						|
 | 
						|
// Example of reading/writing an external serial flash using the PL022 SPI interface
 | 
						|
 | 
						|
#include <stdio.h>
 | 
						|
#include "pico/stdlib.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
 | 
						|
 | 
						|
#define PIN_MISO 4
 | 
						|
#define PIN_CS   5
 | 
						|
#define PIN_SCK  6
 | 
						|
#define PIN_MOSI 7
 | 
						|
 | 
						|
static inline void cs_select(uint cs_pin) {
 | 
						|
    asm volatile("nop \n nop \n nop"); // FIXME
 | 
						|
    gpio_put(cs_pin, 0);
 | 
						|
    asm volatile("nop \n nop \n nop"); // FIXME
 | 
						|
}
 | 
						|
 | 
						|
static inline void cs_deselect(uint cs_pin) {
 | 
						|
    asm volatile("nop \n nop \n nop"); // FIXME
 | 
						|
    gpio_put(cs_pin, 1);
 | 
						|
    asm volatile("nop \n nop \n nop"); // FIXME
 | 
						|
}
 | 
						|
 | 
						|
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() {
 | 
						|
    // Enable UART so we can print status output
 | 
						|
    stdio_init_all();
 | 
						|
 | 
						|
    printf("SPI flash example\n");
 | 
						|
 | 
						|
    // Enable SPI 0 at 1 MHz and connect to GPIOs
 | 
						|
    spi_init(spi0, 1000 * 1000);
 | 
						|
    gpio_set_function(PIN_MISO, GPIO_FUNC_SPI);
 | 
						|
    gpio_set_function(PIN_SCK, GPIO_FUNC_SPI);
 | 
						|
    gpio_set_function(PIN_MOSI, GPIO_FUNC_SPI);
 | 
						|
 | 
						|
    // Chip select is active-low, so we'll initialise it to a driven-high state
 | 
						|
    gpio_init(PIN_CS);
 | 
						|
    gpio_put(PIN_CS, 1);
 | 
						|
    gpio_set_dir(PIN_CS, GPIO_OUT);
 | 
						|
 | 
						|
    printf("SPI initialised, let's goooooo\n");
 | 
						|
 | 
						|
    uint8_t page_buf[FLASH_PAGE_SIZE];
 | 
						|
 | 
						|
    const uint32_t target_addr = 0;
 | 
						|
 | 
						|
    flash_sector_erase(spi0, PIN_CS, target_addr);
 | 
						|
    flash_read(spi0, PIN_CS, 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(spi0, PIN_CS, target_addr, page_buf);
 | 
						|
    flash_read(spi0, PIN_CS, target_addr, page_buf, FLASH_PAGE_SIZE);
 | 
						|
 | 
						|
    printf("After program:\n");
 | 
						|
    printbuf(page_buf);
 | 
						|
 | 
						|
    flash_sector_erase(spi0, PIN_CS, target_addr);
 | 
						|
    flash_read(spi0, PIN_CS, target_addr, page_buf, FLASH_PAGE_SIZE);
 | 
						|
 | 
						|
    printf("Erase again:\n");
 | 
						|
    printbuf(page_buf);
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 |