-
Notifications
You must be signed in to change notification settings - Fork 851
/
spi_flash.c
159 lines (129 loc) · 4.46 KB
/
spi_flash.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/**
* 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);
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_4pins_with_names(PICO_DEFAULT_SPI_RX_PIN, "SPI RX", PICO_DEFAULT_SPI_TX_PIN, "SPI TX", PICO_DEFAULT_SPI_SCK_PIN, "SPI SCK", PICO_DEFAULT_SPI_CSN_PIN, "SPI CS"));
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
}