forked from raspberrypi/pico-examples
-
Notifications
You must be signed in to change notification settings - Fork 0
/
spi_flash.c
159 lines (132 loc) · 4.87 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
*/
// Example of reading/writing an external serial flash using the PL022 SPI interface
#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"); // 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();
#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");
// Enable SPI 0 at 1 MHz and connect to GPIOs
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);
// 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_SPI));
// Chip select is active-low, so we'll initialise it to a driven-high state
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, "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
}