Skip to content

Commit dbeefcc

Browse files
Wikwoj0512juiceofglass
authored andcommitted
[feature] added flash support analogous to esp32c3 to esp32s3
1 parent 1a1506e commit dbeefcc

3 files changed

Lines changed: 1390 additions & 315 deletions

File tree

src/machine/flash.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//go:build esp32c3 || nrf || nrf51 || nrf52 || nrf528xx || stm32f4 || stm32l0 || stm32l4 || stm32wlx || atsamd21 || atsamd51 || atsame5x || rp2040 || rp2350
1+
//go:build esp32c3 || esp32s3 || nrf || nrf51 || nrf52 || nrf528xx || stm32f4 || stm32l0 || stm32l4 || stm32wlx || atsamd21 || atsamd51 || atsame5x || rp2040 || rp2350
22

33
package machine
44

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
//go:build esp32s3
2+
3+
package machine
4+
5+
import (
6+
"runtime/interrupt"
7+
"unsafe"
8+
)
9+
10+
/*
11+
#include <stdint.h>
12+
extern int esp_rom_spiflash_read(uint32_t src_addr, uint32_t *data, uint32_t len);
13+
extern int esp_rom_spiflash_write(uint32_t dest_addr, const uint32_t *data, uint32_t len);
14+
extern int esp_rom_spiflash_erase_sector(uint32_t sector_num);
15+
extern int esp_rom_spiflash_unlock(void);
16+
extern void Cache_Invalidate_Addr(uint32_t addr, uint32_t size);
17+
*/
18+
import "C"
19+
20+
// compile-time check for ensuring we fulfill BlockDevice interface
21+
var _ BlockDevice = flashBlockDevice{}
22+
23+
var Flash flashBlockDevice
24+
25+
type flashBlockDevice struct {
26+
}
27+
28+
// ReadAt reads the given number of bytes from the block device.
29+
func (f flashBlockDevice) ReadAt(p []byte, off int64) (n int, err error) {
30+
if readAddress(off)+uintptr(len(p)) > FlashDataEnd() {
31+
return 0, errFlashCannotReadPastEOF
32+
}
33+
34+
data := unsafe.Slice((*byte)(unsafe.Add(unsafe.Pointer(FlashDataStart()), off)), len(p))
35+
copy(p, data)
36+
37+
return len(p), nil
38+
}
39+
40+
// WriteAt writes the given number of bytes to the block device.
41+
// Only word (32 bits) length data can be programmed.
42+
// If the length of p is not long enough it will be padded with 0xFF bytes.
43+
// This method assumes that the destination is already erased.
44+
func (f flashBlockDevice) WriteAt(p []byte, off int64) (n int, err error) {
45+
return f.writeAt(p, off)
46+
}
47+
48+
// Size returns the number of bytes in this block device.
49+
func (f flashBlockDevice) Size() int64 {
50+
return int64(FlashDataEnd() - FlashDataStart())
51+
}
52+
53+
const writeBlockSize = 4
54+
55+
// WriteBlockSize returns the block size in which data can be written to
56+
// memory. It can be used by a client to optimize writes, non-aligned writes
57+
// should always work correctly.
58+
func (f flashBlockDevice) WriteBlockSize() int64 {
59+
return writeBlockSize
60+
}
61+
62+
const eraseBlockSizeValue = 1 << 12
63+
64+
func eraseBlockSize() int64 {
65+
return eraseBlockSizeValue
66+
}
67+
68+
// EraseBlockSize returns the smallest erasable area on this particular chip
69+
// in bytes. This is used for the block size in EraseBlocks.
70+
func (f flashBlockDevice) EraseBlockSize() int64 {
71+
return eraseBlockSize()
72+
}
73+
74+
// EraseBlocks erases the given number of blocks. An implementation may
75+
// transparently coalesce ranges of blocks into larger bundles if the chip
76+
// supports this. The start and len parameters are in block numbers, use
77+
// EraseBlockSize to map addresses to blocks.
78+
func (f flashBlockDevice) EraseBlocks(start, length int64) error {
79+
return f.eraseBlocks(start, length)
80+
}
81+
82+
// return the correct address to be used for reads
83+
func readAddress(off int64) uintptr {
84+
return FlashDataStart() + uintptr(off)
85+
}
86+
87+
const flashDROMStart = 0x3C000000
88+
89+
// return the correct physical address to be used for write/erase
90+
func writeAddress(off int64) uint32 {
91+
// DROM maps 1:1 with flash physical offset, starting at 0x3C000000.
92+
return uint32(readAddress(off) - flashDROMStart)
93+
}
94+
95+
func (f flashBlockDevice) writeAt(p []byte, off int64) (n int, err error) {
96+
if readAddress(off)+uintptr(len(p)) > FlashDataEnd() {
97+
return 0, errFlashCannotWritePastEOF
98+
}
99+
100+
address := writeAddress(off)
101+
padded := flashPad(p, int(f.WriteBlockSize()))
102+
103+
state := interrupt.Disable()
104+
defer interrupt.Restore(state)
105+
106+
C.esp_rom_spiflash_unlock()
107+
res := C.esp_rom_spiflash_write(C.uint32_t(address), (*C.uint32_t)(unsafe.Pointer(&padded[0])), C.uint32_t(len(padded)))
108+
C.Cache_Invalidate_Addr(C.uint32_t(readAddress(off)), C.uint32_t(len(padded)))
109+
if res != 0 {
110+
return 0, errFlashCannotWriteData
111+
}
112+
113+
return len(padded), nil
114+
}
115+
116+
func (f flashBlockDevice) eraseBlocks(start, length int64) error {
117+
address := writeAddress(start * f.EraseBlockSize())
118+
if uintptr(unsafe.Add(unsafe.Pointer(uintptr(address)+flashDROMStart), length*f.EraseBlockSize())) > FlashDataEnd() {
119+
return errFlashCannotErasePastEOF
120+
}
121+
122+
state := interrupt.Disable()
123+
defer interrupt.Restore(state)
124+
125+
C.esp_rom_spiflash_unlock()
126+
sector := address / uint32(f.EraseBlockSize())
127+
128+
for i := int64(0); i < length; i++ {
129+
res := C.esp_rom_spiflash_erase_sector(C.uint32_t(sector + uint32(i)))
130+
C.Cache_Invalidate_Addr(C.uint32_t(readAddress((start+i)*f.EraseBlockSize())), C.uint32_t(f.EraseBlockSize()))
131+
if res != 0 {
132+
return errFlashCannotErasePage
133+
}
134+
}
135+
136+
return nil
137+
}

0 commit comments

Comments
 (0)