Select one of the symbols to view example projects that use it.
 
Outline
#include "hardware/flash.h"
#include "pico/bootrom.h"
#include "hardware/structs/io_qspi.h"
#include "hardware/structs/ssi.h"
#include "hardware/structs/qmi.h"
#define FLASH_BLOCK_ERASE_CMD
#define FLASH_RUID_CMD
#define FLASH_RUID_DUMMY_BYTES
#define FLASH_RUID_DATA_BYTES
#define FLASH_RUID_TOTAL_BYTES
#define BOOT2_SIZE_WORDS
flash_init_boot2_copyout()
flash_enable_xip_via_boot2()
flash_range_erase(uint32_t, size_t)
flash_flush_cache()
flash_range_program(uint32_t, const uint8_t *, size_t)
flash_get_unique_id(uint8_t *)
Files
loading...
SourceVuRaspberry Pi Pico SDK and ExamplesPicoSDKsrc/rp2_common/hardware_flash/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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/* * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. * * SPDX-License-Identifier: BSD-3-Clause *//* ... */ #include "hardware/flash.h" #include "pico/bootrom.h" #if PICO_RP2040 #include "hardware/structs/io_qspi.h" #include "hardware/structs/ssi.h" /* ... */#else #include "hardware/structs/qmi.h" #endif #define FLASH_BLOCK_ERASE_CMD 0xd8 // Standard RUID instruction: 4Bh command prefix, 32 dummy bits, 64 data bits. #define FLASH_RUID_CMD 0x4b #define FLASH_RUID_DUMMY_BYTES 4 #define FLASH_RUID_DATA_BYTES 8 #define FLASH_RUID_TOTAL_BYTES (1 + FLASH_RUID_DUMMY_BYTES + FLASH_RUID_DATA_BYTES) 5 defines //----------------------------------------------------------------------------- // Infrastructure for reentering XIP mode after exiting for programming (take // a copy of boot2 before XIP exit). Calling boot2 as a function works because // it accepts a return vector in LR (and doesn't trash r4-r7). Bootrom passes // NULL in LR, instructing boot2 to enter flash vector table's reset handler. #if !PICO_NO_FLASH #define BOOT2_SIZE_WORDS 64 static uint32_t boot2_copyout[BOOT2_SIZE_WORDS]; static bool boot2_copyout_valid = false; static void __no_inline_not_in_flash_func(flash_init_boot2_copyout)(void) { if (boot2_copyout_valid) return; // todo we may want the option of boot2 just being a free function in // user RAM, e.g. if it is larger than 256 bytes #if PICO_RP2040 const volatile uint32_t *copy_from = (uint32_t *)XIP_BASE; #else const volatile uint32_t *copy_from = (uint32_t *)BOOTRAM_BASE; #endif for (int i = 0; i < BOOT2_SIZE_WORDS; ++i) boot2_copyout[i] = copy_from[i]; __compiler_memory_barrier(); boot2_copyout_valid = true; ...} static void __no_inline_not_in_flash_func(flash_enable_xip_via_boot2)(void) { ((void (*)(void))((intptr_t)boot2_copyout+1))(); ...} /* ... */ #else static void __no_inline_not_in_flash_func(flash_init_boot2_copyout)(void) {} static void __no_inline_not_in_flash_func(flash_enable_xip_via_boot2)(void) { // Set up XIP for 03h read on bus access (slow but generic) rom_flash_enter_cmd_xip_fn flash_enter_cmd_xip_func = (rom_flash_enter_cmd_xip_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_ENTER_CMD_XIP); assert(flash_enter_cmd_xip_func); flash_enter_cmd_xip_func(); ...} /* ... */ #endif //----------------------------------------------------------------------------- // Actual flash programming shims (work whether or not PICO_NO_FLASH==1) void __no_inline_not_in_flash_func(flash_range_erase)(uint32_t flash_offs, size_t count) { #ifdef PICO_FLASH_SIZE_BYTES hard_assert(flash_offs + count <= PICO_FLASH_SIZE_BYTES); #endif invalid_params_if(HARDWARE_FLASH, flash_offs & (FLASH_SECTOR_SIZE - 1)); invalid_params_if(HARDWARE_FLASH, count & (FLASH_SECTOR_SIZE - 1)); rom_connect_internal_flash_fn connect_internal_flash_func = (rom_connect_internal_flash_fn)rom_func_lookup_inline(ROM_FUNC_CONNECT_INTERNAL_FLASH); rom_flash_exit_xip_fn flash_exit_xip_func = (rom_flash_exit_xip_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_EXIT_XIP); rom_flash_range_erase_fn flash_range_erase_func = (rom_flash_range_erase_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_RANGE_ERASE); rom_flash_flush_cache_fn flash_flush_cache_func = (rom_flash_flush_cache_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_FLUSH_CACHE); assert(connect_internal_flash_func && flash_exit_xip_func && flash_range_erase_func && flash_flush_cache_func); flash_init_boot2_copyout(); // No flash accesses after this point __compiler_memory_barrier(); connect_internal_flash_func(); flash_exit_xip_func(); flash_range_erase_func(flash_offs, count, FLASH_BLOCK_SIZE, FLASH_BLOCK_ERASE_CMD); flash_flush_cache_func(); // Note this is needed to remove CSn IO force as well as cache flushing flash_enable_xip_via_boot2(); ...} void __no_inline_not_in_flash_func(flash_flush_cache)(void) { rom_flash_flush_cache_fn flash_flush_cache_func = (rom_flash_flush_cache_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_FLUSH_CACHE); flash_flush_cache_func(); ...} void __no_inline_not_in_flash_func(flash_range_program)(uint32_t flash_offs, const uint8_t *data, size_t count) { #ifdef PICO_FLASH_SIZE_BYTES hard_assert(flash_offs + count <= PICO_FLASH_SIZE_BYTES); #endif invalid_params_if(HARDWARE_FLASH, flash_offs & (FLASH_PAGE_SIZE - 1)); invalid_params_if(HARDWARE_FLASH, count & (FLASH_PAGE_SIZE - 1)); rom_connect_internal_flash_fn connect_internal_flash_func = (rom_connect_internal_flash_fn)rom_func_lookup_inline(ROM_FUNC_CONNECT_INTERNAL_FLASH); rom_flash_exit_xip_fn flash_exit_xip_func = (rom_flash_exit_xip_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_EXIT_XIP); rom_flash_range_program_fn flash_range_program_func = (rom_flash_range_program_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_RANGE_PROGRAM); rom_flash_flush_cache_fn flash_flush_cache_func = (rom_flash_flush_cache_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_FLUSH_CACHE); assert(connect_internal_flash_func && flash_exit_xip_func && flash_range_program_func && flash_flush_cache_func); flash_init_boot2_copyout(); __compiler_memory_barrier(); connect_internal_flash_func(); flash_exit_xip_func(); flash_range_program_func(flash_offs, data, count); flash_flush_cache_func(); // Note this is needed to remove CSn IO force as well as cache flushing flash_enable_xip_via_boot2(); ...} //----------------------------------------------------------------------------- // Lower-level flash access functions #if !PICO_NO_FLASH // Bitbanging the chip select using IO overrides, in case RAM-resident IRQs // are still running, and the FIFO bottoms out. (the bootrom does the same) static void __no_inline_not_in_flash_func(flash_cs_force)(bool high) { #if PICO_RP2040 uint32_t field_val = high ? IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_HIGH : IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_LOW; hw_write_masked(&io_qspi_hw->io[1].ctrl, field_val << IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_LSB, IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_BITS );/* ... */ #else if (high) { hw_clear_bits(&qmi_hw->direct_csr, QMI_DIRECT_CSR_ASSERT_CS0N_BITS); }if (high) { ... } else { hw_set_bits(&qmi_hw->direct_csr, QMI_DIRECT_CSR_ASSERT_CS0N_BITS); }else { ... } /* ... */#endif ...} void __no_inline_not_in_flash_func(flash_do_cmd)(const uint8_t *txbuf, uint8_t *rxbuf, size_t count) { rom_connect_internal_flash_fn connect_internal_flash_func = (rom_connect_internal_flash_fn)rom_func_lookup_inline(ROM_FUNC_CONNECT_INTERNAL_FLASH); rom_flash_exit_xip_fn flash_exit_xip_func = (rom_flash_exit_xip_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_EXIT_XIP); rom_flash_flush_cache_fn flash_flush_cache_func = (rom_flash_flush_cache_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_FLUSH_CACHE); assert(connect_internal_flash_func && flash_exit_xip_func && flash_flush_cache_func); flash_init_boot2_copyout(); __compiler_memory_barrier(); connect_internal_flash_func(); flash_exit_xip_func(); flash_cs_force(0); size_t tx_remaining = count; size_t rx_remaining = count; #if PICO_RP2040 // Synopsys SSI version // We may be interrupted -- don't want FIFO to overflow if we're distracted. const size_t max_in_flight = 16 - 2; while (tx_remaining || rx_remaining) { uint32_t flags = ssi_hw->sr; bool can_put = flags & SSI_SR_TFNF_BITS; bool can_get = flags & SSI_SR_RFNE_BITS; if (can_put && tx_remaining && rx_remaining - tx_remaining < max_in_flight) { ssi_hw->dr0 = *txbuf++; --tx_remaining; }if (can_put && tx_remaining && rx_remaining - tx_remaining < max_in_flight) { ... } if (can_get && rx_remaining) { *rxbuf++ = (uint8_t)ssi_hw->dr0; --rx_remaining; }if (can_get && rx_remaining) { ... } }while (tx_remaining || rx_remaining) { ... } /* ... */#else // QMI version -- no need to bound FIFO contents as QMI stalls on full DIRECT_RX. hw_set_bits(&qmi_hw->direct_csr, QMI_DIRECT_CSR_EN_BITS); while (tx_remaining || rx_remaining) { uint32_t flags = qmi_hw->direct_csr; bool can_put = !(flags & QMI_DIRECT_CSR_TXFULL_BITS); bool can_get = !(flags & QMI_DIRECT_CSR_RXEMPTY_BITS); if (can_put && tx_remaining) { qmi_hw->direct_tx = *txbuf++; --tx_remaining; }if (can_put && tx_remaining) { ... } if (can_get && rx_remaining) { *rxbuf++ = (uint8_t)qmi_hw->direct_rx; --rx_remaining; }if (can_get && rx_remaining) { ... } }while (tx_remaining || rx_remaining) { ... } hw_clear_bits(&qmi_hw->direct_csr, QMI_DIRECT_CSR_EN_BITS);/* ... */ #endif flash_cs_force(1); flash_flush_cache_func(); flash_enable_xip_via_boot2(); ...}/* ... */ #endif // Use standard RUID command to get a unique identifier for the flash (and // hence the board) static_assert(FLASH_UNIQUE_ID_SIZE_BYTES == FLASH_RUID_DATA_BYTES, ""); void flash_get_unique_id(uint8_t *id_out) { #if PICO_NO_FLASH __unused uint8_t *ignore = id_out; panic_unsupported();/* ... */ #else uint8_t txbuf[FLASH_RUID_TOTAL_BYTES] = {0}; uint8_t rxbuf[FLASH_RUID_TOTAL_BYTES] = {0}; txbuf[0] = FLASH_RUID_CMD; flash_do_cmd(txbuf, rxbuf, FLASH_RUID_TOTAL_BYTES); for (int i = 0; i < FLASH_RUID_DATA_BYTES; i++) id_out[i] = rxbuf[i + 1 + FLASH_RUID_DUMMY_BYTES];/* ... */ #endif }{ ... }
Details