machine/stm32, nrf: flash API (#3472)

machine/stm32, nrf: implement machine.Flash

Implements the machine.Flash interface using the same definition as the tinyfs BlockDevice.

This implementation covers the stm32f4, stm32l4, stm32wlx, nrf51, nrf52, and nrf528xx processors.
This commit is contained in:
Ron Evans
2023-02-27 13:55:38 +01:00
committed by GitHub
parent 8bf94b9231
commit 6e1b8a54aa
12 changed files with 817 additions and 0 deletions
+57
View File
@@ -0,0 +1,57 @@
package main
import (
"machine"
"time"
)
var (
err error
message = "1234567887654321123456788765432112345678876543211234567887654321"
)
func main() {
time.Sleep(3 * time.Second)
// Print out general information
println("Flash data start: ", machine.FlashDataStart())
println("Flash data end: ", machine.FlashDataEnd())
println("Flash data size, bytes:", machine.Flash.Size())
println("Flash write block size:", machine.Flash.WriteBlockSize())
println("Flash erase block size:", machine.Flash.EraseBlockSize())
println()
flash := machine.OpenFlashBuffer(machine.Flash, machine.FlashDataStart())
original := make([]byte, len(message))
saved := make([]byte, len(message))
// Read flash contents on start (data shall survive power off)
print("Reading data from flash: ")
_, err = flash.Read(original)
checkError(err)
println(string(original))
// Write the message to flash
print("Writing data to flash: ")
flash.Seek(0, 0) // rewind back to beginning
_, err = flash.Write([]byte(message))
checkError(err)
println(string(message))
// Read back flash contents after write (verify data is the same as written)
print("Reading data back from flash: ")
flash.Seek(0, 0) // rewind back to beginning
_, err = flash.Read(saved)
checkError(err)
println(string(saved))
println()
}
func checkError(err error) {
if err != nil {
for {
println(err.Error())
time.Sleep(time.Second)
}
}
}
+144
View File
@@ -0,0 +1,144 @@
//go:build nrf || nrf51 || nrf52 || nrf528xx || stm32f4 || stm32l4 || stm32wlx
package machine
import (
"errors"
"io"
"unsafe"
)
//go:extern __flash_data_start
var flashDataStart [0]byte
//go:extern __flash_data_end
var flashDataEnd [0]byte
// Return the start of the writable flash area, aligned on a page boundary. This
// is usually just after the program and static data.
func FlashDataStart() uintptr {
pagesize := uintptr(eraseBlockSize())
return (uintptr(unsafe.Pointer(&flashDataStart)) + pagesize - 1) &^ (pagesize - 1)
}
// Return the end of the writable flash area. Usually this is the address one
// past the end of the on-chip flash.
func FlashDataEnd() uintptr {
return uintptr(unsafe.Pointer(&flashDataEnd))
}
var (
errFlashCannotErasePage = errors.New("cannot erase flash page")
errFlashInvalidWriteLength = errors.New("write flash data must align to correct number of bits")
errFlashNotAllowedWriteData = errors.New("not allowed to write flash data")
errFlashCannotWriteData = errors.New("cannot write flash data")
errFlashCannotReadPastEOF = errors.New("cannot read beyond end of flash data")
errFlashCannotWritePastEOF = errors.New("cannot write beyond end of flash data")
)
// BlockDevice is the raw device that is meant to store flash data.
type BlockDevice interface {
// ReadAt reads the given number of bytes from the block device.
io.ReaderAt
// WriteAt writes the given number of bytes to the block device.
io.WriterAt
// Size returns the number of bytes in this block device.
Size() int64
// WriteBlockSize returns the block size in which data can be written to
// memory. It can be used by a client to optimize writes, non-aligned writes
// should always work correctly.
WriteBlockSize() int64
// EraseBlockSize returns the smallest erasable area on this particular chip
// in bytes. This is used for the block size in EraseBlocks.
// It must be a power of two, and may be as small as 1. A typical size is 4096.
EraseBlockSize() int64
// EraseBlocks erases the given number of blocks. An implementation may
// transparently coalesce ranges of blocks into larger bundles if the chip
// supports this. The start and len parameters are in block numbers, use
// EraseBlockSize to map addresses to blocks.
EraseBlocks(start, len int64) error
}
// FlashBuffer implements the ReadWriteCloser interface using the BlockDevice interface.
type FlashBuffer struct {
b BlockDevice
start uintptr
current uintptr
}
// OpenFlashBuffer opens a FlashBuffer.
func OpenFlashBuffer(b BlockDevice, address uintptr) *FlashBuffer {
return &FlashBuffer{b: b, start: address, current: address}
}
// Read data from a FlashBuffer.
func (fl *FlashBuffer) Read(p []byte) (n int, err error) {
fl.b.ReadAt(p, int64(fl.current))
fl.current += uintptr(len(p))
return len(p), nil
}
// Write data to a FlashBuffer.
func (fl *FlashBuffer) Write(p []byte) (n int, err error) {
// any new pages needed?
// NOTE probably will not work as expected if you try to write over page boundary
// of pages with different sizes.
pagesize := uintptr(fl.b.EraseBlockSize())
currentPageCount := (fl.current - fl.start + pagesize - 1) / pagesize
totalPagesNeeded := (fl.current - fl.start + uintptr(len(p)) + pagesize - 1) / pagesize
if currentPageCount == totalPagesNeeded {
// just write the data
n, err := fl.b.WriteAt(p, int64(fl.current))
if err != nil {
return 0, err
}
fl.current += uintptr(n)
return n, nil
}
// erase enough blocks to hold the data
page := fl.flashPageFromAddress(fl.start + (currentPageCount * pagesize))
fl.b.EraseBlocks(page, int64(totalPagesNeeded-currentPageCount))
// write the data
for i := 0; i < len(p); i += int(pagesize) {
var last int = i + int(pagesize)
if i+int(pagesize) > len(p) {
last = len(p)
}
_, err := fl.b.WriteAt(p[i:last], int64(fl.current))
if err != nil {
return 0, err
}
fl.current += uintptr(last - i)
}
return len(p), nil
}
// Close the FlashBuffer.
func (fl *FlashBuffer) Close() error {
return nil
}
// Seek implements io.Seeker interface, but with limitations.
// You can only seek relative to the start.
// Also, you cannot use seek before write operations, only read.
func (fl *FlashBuffer) Seek(offset int64, whence int) (int64, error) {
fl.current = fl.start + uintptr(offset)
return offset, nil
}
// calculate page number from address
func (fl *FlashBuffer) flashPageFromAddress(address uintptr) int64 {
return int64(address-memoryStart) / fl.b.EraseBlockSize()
}
+108
View File
@@ -3,7 +3,9 @@
package machine
import (
"bytes"
"device/nrf"
"encoding/binary"
"runtime/interrupt"
"unsafe"
)
@@ -382,3 +384,109 @@ func ReadTemperature() int32 {
nrf.TEMP.EVENTS_DATARDY.Set(0)
return temp
}
const memoryStart = 0x0
// compile-time check for ensuring we fulfill BlockDevice interface
var _ BlockDevice = flashBlockDevice{}
var Flash flashBlockDevice
type flashBlockDevice struct {
}
// ReadAt reads the given number of bytes from the block device.
func (f flashBlockDevice) ReadAt(p []byte, off int64) (n int, err error) {
if FlashDataStart()+uintptr(off)+uintptr(len(p)) > FlashDataEnd() {
return 0, errFlashCannotReadPastEOF
}
data := unsafe.Slice((*byte)(unsafe.Pointer(FlashDataStart()+uintptr(off))), len(p))
copy(p, data)
return len(p), nil
}
// WriteAt writes the given number of bytes to the block device.
// Only double-word (64 bits) length data can be programmed. See rm0461 page 78.
// If the length of p is not long enough it will be padded with 0xFF bytes.
// This method assumes that the destination is already erased.
func (f flashBlockDevice) WriteAt(p []byte, off int64) (n int, err error) {
if FlashDataStart()+uintptr(off)+uintptr(len(p)) > FlashDataEnd() {
return 0, errFlashCannotWritePastEOF
}
address := FlashDataStart() + uintptr(off)
padded := f.pad(p)
waitWhileFlashBusy()
nrf.NVMC.SetCONFIG_WEN(nrf.NVMC_CONFIG_WEN_Wen)
defer nrf.NVMC.SetCONFIG_WEN(nrf.NVMC_CONFIG_WEN_Ren)
for j := 0; j < len(padded); j += int(f.WriteBlockSize()) {
// write word
*(*uint32)(unsafe.Pointer(address)) = binary.LittleEndian.Uint32(padded[j : j+int(f.WriteBlockSize())])
address += uintptr(f.WriteBlockSize())
waitWhileFlashBusy()
}
return len(padded), nil
}
// Size returns the number of bytes in this block device.
func (f flashBlockDevice) Size() int64 {
return int64(FlashDataEnd() - FlashDataStart())
}
const writeBlockSize = 4
// WriteBlockSize returns the block size in which data can be written to
// memory. It can be used by a client to optimize writes, non-aligned writes
// should always work correctly.
func (f flashBlockDevice) WriteBlockSize() int64 {
return writeBlockSize
}
// EraseBlockSize returns the smallest erasable area on this particular chip
// in bytes. This is used for the block size in EraseBlocks.
// It must be a power of two, and may be as small as 1. A typical size is 4096.
func (f flashBlockDevice) EraseBlockSize() int64 {
return eraseBlockSize()
}
// EraseBlocks erases the given number of blocks. An implementation may
// transparently coalesce ranges of blocks into larger bundles if the chip
// supports this. The start and len parameters are in block numbers, use
// EraseBlockSize to map addresses to blocks.
func (f flashBlockDevice) EraseBlocks(start, len int64) error {
address := FlashDataStart() + uintptr(start*f.EraseBlockSize())
waitWhileFlashBusy()
nrf.NVMC.SetCONFIG_WEN(nrf.NVMC_CONFIG_WEN_Een)
defer nrf.NVMC.SetCONFIG_WEN(nrf.NVMC_CONFIG_WEN_Ren)
for i := start; i < start+len; i++ {
nrf.NVMC.ERASEPAGE.Set(uint32(address))
waitWhileFlashBusy()
address += uintptr(f.EraseBlockSize())
}
return nil
}
// pad data if needed so it is long enough for correct byte alignment on writes.
func (f flashBlockDevice) pad(p []byte) []byte {
paddingNeeded := f.WriteBlockSize() - (int64(len(p)) % f.WriteBlockSize())
if paddingNeeded == 0 {
return p
}
padding := bytes.Repeat([]byte{0xff}, int(paddingNeeded))
return append(p, padding...)
}
func waitWhileFlashBusy() {
for nrf.NVMC.GetREADY() != nrf.NVMC_READY_READY_Ready {
}
}
+6
View File
@@ -6,6 +6,12 @@ import (
"device/nrf"
)
const eraseBlockSizeValue = 1024
func eraseBlockSize() int64 {
return eraseBlockSizeValue
}
// Get peripheral and pin number for this GPIO pin.
func (p Pin) getPortPin() (*nrf.GPIO_Type, uint32) {
return nrf.GPIO, uint32(p)
+6
View File
@@ -63,3 +63,9 @@ var (
PWM1 = &PWM{PWM: nrf.PWM1}
PWM2 = &PWM{PWM: nrf.PWM2}
)
const eraseBlockSizeValue = 4096
func eraseBlockSize() int64 {
return eraseBlockSizeValue
}
+6
View File
@@ -84,3 +84,9 @@ var (
PWM2 = &PWM{PWM: nrf.PWM2}
PWM3 = &PWM{PWM: nrf.PWM3}
)
const eraseBlockSizeValue = 4096
func eraseBlockSize() int64 {
return eraseBlockSizeValue
}
+6
View File
@@ -102,3 +102,9 @@ func (pdm *PDM) Read(buf []int16) (uint32, error) {
return uint32(len(buf)), nil
}
const eraseBlockSizeValue = 4096
func eraseBlockSize() int64 {
return eraseBlockSizeValue
}
+122
View File
@@ -0,0 +1,122 @@
//go:build stm32f4 || stm32l4 || stm32wlx
package machine
import (
"device/stm32"
"bytes"
"unsafe"
)
// compile-time check for ensuring we fulfill BlockDevice interface
var _ BlockDevice = flashBlockDevice{}
var Flash flashBlockDevice
type flashBlockDevice struct {
}
// ReadAt reads the given number of bytes from the block device.
func (f flashBlockDevice) ReadAt(p []byte, off int64) (n int, err error) {
if FlashDataStart()+uintptr(off)+uintptr(len(p)) > FlashDataEnd() {
return 0, errFlashCannotReadPastEOF
}
data := unsafe.Slice((*byte)(unsafe.Pointer(FlashDataStart()+uintptr(off))), len(p))
copy(p, data)
return len(p), nil
}
// WriteAt writes the given number of bytes to the block device.
// Only double-word (64 bits) length data can be programmed. See rm0461 page 78.
// If the length of p is not long enough it will be padded with 0xFF bytes.
// This method assumes that the destination is already erased.
func (f flashBlockDevice) WriteAt(p []byte, off int64) (n int, err error) {
if FlashDataStart()+uintptr(off)+uintptr(len(p)) > FlashDataEnd() {
return 0, errFlashCannotWritePastEOF
}
unlockFlash()
defer lockFlash()
return writeFlashData(FlashDataStart()+uintptr(off), f.pad(p))
}
// Size returns the number of bytes in this block device.
func (f flashBlockDevice) Size() int64 {
return int64(FlashDataEnd() - FlashDataStart())
}
// WriteBlockSize returns the block size in which data can be written to
// memory. It can be used by a client to optimize writes, non-aligned writes
// should always work correctly.
func (f flashBlockDevice) WriteBlockSize() int64 {
return writeBlockSize
}
func eraseBlockSize() int64 {
return eraseBlockSizeValue
}
// EraseBlockSize returns the smallest erasable area on this particular chip
// in bytes. This is used for the block size in EraseBlocks.
// It must be a power of two, and may be as small as 1. A typical size is 4096.
// TODO: correctly handle processors that have differently sized blocks
// in different areas of memory like the STM32F40x and STM32F1x.
func (f flashBlockDevice) EraseBlockSize() int64 {
return eraseBlockSize()
}
// EraseBlocks erases the given number of blocks. An implementation may
// transparently coalesce ranges of blocks into larger bundles if the chip
// supports this. The start and len parameters are in block numbers, use
// EraseBlockSize to map addresses to blocks.
func (f flashBlockDevice) EraseBlocks(start, len int64) error {
unlockFlash()
defer lockFlash()
for i := start; i < start+len; i++ {
if err := eraseBlock(uint32(i)); err != nil {
return err
}
}
return nil
}
// pad data if needed so it is long enough for correct byte alignment on writes.
func (f flashBlockDevice) pad(p []byte) []byte {
paddingNeeded := f.WriteBlockSize() - (int64(len(p)) % f.WriteBlockSize())
if paddingNeeded == 0 {
return p
}
padded := bytes.Repeat([]byte{0xff}, int(paddingNeeded))
return append(p, padded...)
}
const memoryStart = 0x08000000
func unlockFlash() {
// keys as described rm0461 page 76
var fkey1 uint32 = 0x45670123
var fkey2 uint32 = 0xCDEF89AB
// Wait for the flash memory not to be busy
for stm32.FLASH.GetSR_BSY() != 0 {
}
// Check if the controller is unlocked already
if stm32.FLASH.GetCR_LOCK() != 0 {
// Write the first key
stm32.FLASH.SetKEYR(fkey1)
// Write the second key
stm32.FLASH.SetKEYR(fkey2)
}
}
func lockFlash() {
stm32.FLASH.SetCR_LOCK(1)
}
+141
View File
@@ -6,6 +6,8 @@ package machine
import (
"device/stm32"
"encoding/binary"
"errors"
"math/bits"
"runtime/interrupt"
"runtime/volatile"
@@ -791,3 +793,142 @@ func (i2c *I2C) getSpeed(config I2CConfig) uint32 {
}
}
}
//---------- Flash related code
// the block size actually depends on the sector.
// TODO: handle this correctly for sectors > 3
const eraseBlockSizeValue = 16384
// see RM0090 page 75
func sectorNumber(address uintptr) uint32 {
switch {
// 0x0800 0000 - 0x0800 3FFF
case address >= 0x08000000 && address <= 0x08003FFF:
return 0
// 0x0800 4000 - 0x0800 7FFF
case address >= 0x08004000 && address <= 0x08007FFF:
return 1
// 0x0800 8000 - 0x0800 BFFF
case address >= 0x08008000 && address <= 0x0800BFFF:
return 2
// 0x0800 C000 - 0x0800 FFFF
case address >= 0x0800C000 && address <= 0x0800FFFF:
return 3
// 0x0801 0000 - 0x0801 FFFF
case address >= 0x08010000 && address <= 0x0801FFFF:
return 4
// 0x0802 0000 - 0x0803 FFFF
case address >= 0x08020000 && address <= 0x0803FFFF:
return 5
// 0x0804 0000 - 0x0805 FFFF
case address >= 0x08040000 && address <= 0x0805FFFF:
return 6
case address >= 0x08060000 && address <= 0x0807FFFF:
return 7
case address >= 0x08080000 && address <= 0x0809FFFF:
return 8
case address >= 0x080A0000 && address <= 0x080BFFFF:
return 9
case address >= 0x080C0000 && address <= 0x080DFFFF:
return 10
case address >= 0x080E0000 && address <= 0x080FFFFF:
return 11
default:
return 0
}
}
// calculate sector number from address
// var sector uint32 = sectorNumber(address)
// see RM0090 page 85
// eraseBlock at the passed in block number
func eraseBlock(block uint32) error {
waitUntilFlashDone()
// clear any previous errors
stm32.FLASH.SR.SetBits(0xF0)
// set SER bit
stm32.FLASH.SetCR_SER(1)
defer stm32.FLASH.SetCR_SER(0)
// set the block (aka sector) to be erased
stm32.FLASH.SetCR_SNB(block)
defer stm32.FLASH.SetCR_SNB(0)
// start the page erase
stm32.FLASH.SetCR_STRT(1)
waitUntilFlashDone()
if err := checkError(); err != nil {
return err
}
return nil
}
const writeBlockSize = 2
// see RM0090 page 86
// must write data in word-length
func writeFlashData(address uintptr, data []byte) (int, error) {
if len(data)%writeBlockSize != 0 {
return 0, errFlashInvalidWriteLength
}
waitUntilFlashDone()
// clear any previous errors
stm32.FLASH.SR.SetBits(0xF0)
// set parallelism to x32
stm32.FLASH.SetCR_PSIZE(2)
for i := 0; i < len(data); i += writeBlockSize {
// start write operation
stm32.FLASH.SetCR_PG(1)
*(*uint16)(unsafe.Pointer(address)) = binary.BigEndian.Uint16(data[i : i+writeBlockSize])
waitUntilFlashDone()
if err := checkError(); err != nil {
return i, err
}
// end write operation
stm32.FLASH.SetCR_PG(0)
}
return len(data), nil
}
func waitUntilFlashDone() {
for stm32.FLASH.GetSR_BSY() != 0 {
}
}
var (
errFlashPGS = errors.New("errFlashPGS")
errFlashPGP = errors.New("errFlashPGP")
errFlashPGA = errors.New("errFlashPGA")
errFlashWRP = errors.New("errFlashWRP")
)
func checkError() error {
switch {
case stm32.FLASH.GetSR_PGSERR() != 0:
return errFlashPGS
case stm32.FLASH.GetSR_PGPERR() != 0:
return errFlashPGP
case stm32.FLASH.GetSR_PGAERR() != 0:
return errFlashPGA
case stm32.FLASH.GetSR_WRPERR() != 0:
return errFlashWRP
}
return nil
}
+103
View File
@@ -4,6 +4,8 @@ package machine
import (
"device/stm32"
"encoding/binary"
"errors"
"runtime/interrupt"
"runtime/volatile"
"unsafe"
@@ -543,3 +545,104 @@ func initRNG() {
stm32.RCC.AHB2ENR.SetBits(stm32.RCC_AHB2ENR_RNGEN)
stm32.RNG.CR.SetBits(stm32.RNG_CR_RNGEN)
}
//---------- Flash related code
const eraseBlockSizeValue = 2048
// see RM0394 page 83
// eraseBlock of the passed in block number
func eraseBlock(block uint32) error {
waitUntilFlashDone()
// clear any previous errors
stm32.FLASH.SR.SetBits(0x3FA)
// page erase operation
stm32.FLASH.SetCR_PER(1)
defer stm32.FLASH.SetCR_PER(0)
// set the page to be erased
stm32.FLASH.SetCR_PNB(block)
// start the page erase
stm32.FLASH.SetCR_START(1)
waitUntilFlashDone()
if err := checkError(); err != nil {
return err
}
return nil
}
const writeBlockSize = 8
// see RM0394 page 84
// It is only possible to program double word (2 x 32-bit data).
func writeFlashData(address uintptr, data []byte) (int, error) {
if len(data)%writeBlockSize != 0 {
return 0, errFlashInvalidWriteLength
}
waitUntilFlashDone()
// clear any previous errors
stm32.FLASH.SR.SetBits(0x3FA)
for j := 0; j < len(data); j += writeBlockSize {
// start page write operation
stm32.FLASH.SetCR_PG(1)
// write first word using double-word low order word
*(*uint32)(unsafe.Pointer(address)) = binary.BigEndian.Uint32(data[j+writeBlockSize/2 : j+writeBlockSize])
address += writeBlockSize / 2
// write second word using double-word high order word
*(*uint32)(unsafe.Pointer(address)) = binary.BigEndian.Uint32(data[j : j+writeBlockSize/2])
waitUntilFlashDone()
if err := checkError(); err != nil {
return j, err
}
// end flash write
stm32.FLASH.SetCR_PG(0)
address += writeBlockSize / 2
}
return len(data), nil
}
func waitUntilFlashDone() {
for stm32.FLASH.GetSR_BSY() != 0 {
}
}
var (
errFlashPGS = errors.New("errFlashPGS")
errFlashSIZE = errors.New("errFlashSIZE")
errFlashPGA = errors.New("errFlashPGA")
errFlashWRP = errors.New("errFlashWRP")
errFlashPROG = errors.New("errFlashPROG")
)
func checkError() error {
switch {
case stm32.FLASH.GetSR_PGSERR() != 0:
return errFlashPGS
case stm32.FLASH.GetSR_SIZERR() != 0:
return errFlashSIZE
case stm32.FLASH.GetSR_PGAERR() != 0:
return errFlashPGA
case stm32.FLASH.GetSR_WRPERR() != 0:
return errFlashWRP
case stm32.FLASH.GetSR_PROGERR() != 0:
return errFlashPROG
}
return nil
}
+114
View File
@@ -6,6 +6,8 @@ package machine
import (
"device/stm32"
"encoding/binary"
"errors"
"math/bits"
"runtime/interrupt"
"runtime/volatile"
@@ -424,3 +426,115 @@ const (
ARR_MAX = 0x10000
PSC_MAX = 0x10000
)
//---------- Flash related code
const eraseBlockSizeValue = 2048
// eraseBlock of the passed in block number
func eraseBlock(block uint32) error {
waitUntilFlashDone()
// check if operation is allowed.
if stm32.FLASH.GetSR_PESD() != 0 {
return errFlashCannotErasePage
}
// clear any previous errors
stm32.FLASH.SR.SetBits(0x3FA)
// page erase operation
stm32.FLASH.SetCR_PER(1)
defer stm32.FLASH.SetCR_PER(0)
// set the address to the page to be written
stm32.FLASH.SetCR_PNB(block)
defer stm32.FLASH.SetCR_PNB(0)
// start the page erase
stm32.FLASH.SetCR_STRT(1)
waitUntilFlashDone()
if err := checkError(); err != nil {
return err
}
return nil
}
const writeBlockSize = 8
func writeFlashData(address uintptr, data []byte) (int, error) {
if len(data)%writeBlockSize != 0 {
return 0, errFlashInvalidWriteLength
}
waitUntilFlashDone()
// check if operation is allowed
if stm32.FLASH.GetSR_PESD() != 0 {
return 0, errFlashNotAllowedWriteData
}
// clear any previous errors
stm32.FLASH.SR.SetBits(0x3FA)
for j := 0; j < len(data); j += writeBlockSize {
// start page write operation
stm32.FLASH.SetCR_PG(1)
// write first word using double-word low order word
*(*uint32)(unsafe.Pointer(address)) = binary.BigEndian.Uint32(data[j+writeBlockSize/2 : j+writeBlockSize])
address += writeBlockSize / 2
// write second word using double-word high order word
*(*uint32)(unsafe.Pointer(address)) = binary.BigEndian.Uint32(data[j : j+writeBlockSize/2])
waitUntilFlashDone()
if err := checkError(); err != nil {
return j, err
}
// end flash write
stm32.FLASH.SetCR_PG(0)
address += writeBlockSize / 2
}
return len(data), nil
}
func waitUntilFlashDone() {
for stm32.FLASH.GetSR_BSY() != 0 {
}
for stm32.FLASH.GetSR_CFGBSY() != 0 {
}
}
var (
errFlashPGS = errors.New("errFlashPGS")
errFlashSIZE = errors.New("errFlashSIZE")
errFlashPGA = errors.New("errFlashPGA")
errFlashWRP = errors.New("errFlashWRP")
errFlashPROG = errors.New("errFlashPROG")
)
func checkError() error {
switch {
case stm32.FLASH.GetSR_PGSERR() != 0:
return errFlashPGS
case stm32.FLASH.GetSR_SIZERR() != 0:
return errFlashSIZE
case stm32.FLASH.GetSR_PGAERR() != 0:
return errFlashPGA
case stm32.FLASH.GetSR_WRPERR() != 0:
return errFlashWRP
case stm32.FLASH.GetSR_PROGERR() != 0:
return errFlashPROG
}
return nil
}
+4
View File
@@ -69,3 +69,7 @@ _heap_start = _ebss;
_heap_end = ORIGIN(RAM) + LENGTH(RAM);
_globals_start = _sdata;
_globals_end = _ebss;
/* For the flash API */
__flash_data_start = LOADADDR(.data) + SIZEOF(.data);
__flash_data_end = ORIGIN(FLASH_TEXT) + LENGTH(FLASH_TEXT);