💾 hal::flash
Flash Memory Programming - Program Storage and Data Persistence
~340 lines
~15 function
STM32/GD32
📖 Overview
Flash memory modülü, mikrokontrolcünün dahili flash belleğine program kodu yazma, okuma ve silme işlemlerini sağlar. Kalıcı veri saklama, firmware güncelleme (OTA), konfigürasyon ayarları ve EEPROM emülasyonu for kullanılır.
🔑 Key Features
- Program memory read/write/erase
- Page/sector based erase operations
- Mass erase support
- Write protection mechanisms
- Option bytes programming
- Dual-bank flash (F4/F7)
- ECC error detection
- Flash memory locking
🚀 Quick Start
import hal::flash
// Unlock flash for writing
flash.unlock()
// Erase a page
flash.erase_page(0x0801F800) // Last page
// Write data
let data = [0x12345678, 0xABCDEF00, 0xDEADBEEF]
flash.write(0x0801F800, data)
// Lock flash
flash.lock()
// Read back
let value = flash.read_word(0x0801F800)
io.println("Okunan değer: 0x" + value.to_hex())
📦 Tipler ve Enum'lar
// Flash Latency
enum Latency {
WS0, // 0 wait state
WS1, // 1 wait state
WS2, // 2 wait states
WS3, // 3 wait states
WS4, // 4 wait states
WS5 // 5 wait states
}
// Flash Bank
enum Bank {
BANK_1,
BANK_2
}
// Sector Size (STM32F4)
enum SectorSize {
SECTOR_16K,
SECTOR_64K,
SECTOR_128K
}
struct FlashInfo do
total_size: int, // Bytes
page_size: int, // Bytes
num_pages: int,
write_alignment: int // 1, 2, 4, 8 bytes
end
💡 Example 1: EEPROM Emulation
Flash'ta key-value storage sistemi
import hal::flash
const EEPROM_START = 0x0801F000 // Son 4KB
const EEPROM_END = 0x08020000
const MAGIC_HEADER = 0xDEADBEEF
struct EEPROMEntry do
key: int,
value: int,
checksum: int
end
function eeprom_write(key: int, value: int) do
flash.unlock()
// Boş slot bul
let addr = EEPROM_START
loop addr < EEPROM_END for do
let magic = flash.read_word(addr)
if magic == 0xFFFFFFFF do
// Boş slot bulundu
flash.write_word(addr, MAGIC_HEADER)
flash.write_word(addr + 4, key)
flash.write_word(addr + 8, value)
flash.write_word(addr + 12, key ^ value) // Checksum
çık
end
addr += 16 // Entry size
end
flash.lock()
end
function eeprom_read(key: int) -> Seçenek[int] do
let addr = EEPROM_START
loop addr < EEPROM_END for do
let magic = flash.read_word(addr)
if magic == MAGIC_HEADER do
let stored_key = flash.read_word(addr + 4)
if stored_key == key do
let value = flash.read_word(addr + 8)
let checksum = flash.read_word(addr + 12)
// Verify checksum
if checksum == (key ^ value) do
return Bazı(value)
end
end
end
addr += 16
end
return Hiçbiri
end
function eeprom_format() do
flash.unlock()
flash.erase_page(EEPROM_START)
flash.lock()
io.println("EEPROM formatted")
end
function ana() do
// Write configuration
eeprom_write(1, 12345) // key=1, value=12345
eeprom_write(2, 67890)
// Read back
if let val = eeprom_read(1) do
io.println("Key 1: " + val.yazıya())
end
end
💡 Example 2: Firmware Update (Bootloader)
OTA firmware güncelleme
import hal::flash, hal::crc
const APP_START = 0x08010000 // Application start
const APP_SIZE = 0x00030000 // 192 KB
const UPDATE_START = 0x08040000 // Update area
struct FirmwareHeader do
magic: int, // 0x42455247 (BERK)
version: int,
size: int,
crc32: int
end
function firmware_validate(addr: int) -> bool do
// Read header
let header = flash.read_struct::(addr)
if header.magic != 0x42455247 do
return yanlış
end
// Calculate CRC
let calculated_crc = crc.calculate(
addr + sizeofreşitli,
header.size
)
return calculated_crc == header.crc32
end
function firmware_copy(src: int, dest: int, size: int) do
flash.unlock()
// Erase destination
let pages = (size + 2047) / 2048
for i in 0..pages for do
flash.erase_page(dest + i * 2048)
end
// Copy data
let offset = 0
loop offset < size for do
let data = flash.read_word(src + offset)
flash.write_word(dest + offset, data)
offset += 4
end
flash.lock()
end
function bootloader_ana() do
io.println("Bootloader başlatılıyor...")
// Check for update
if firmware_validate(UPDATE_START) do
io.println("Yeni firmware bulundu, güncelleniyor...")
let header = flash.read_struct::(UPDATE_START)
// Copy new firmware to application area
firmware_copy(
UPDATE_START,
APP_START,
header.size
)
// Verify
if firmware_validate(APP_START) do
io.println("Güncelleme başarılı!")
// Clear update area
flash.unlock()
flash.erase_sector(UPDATE_START)
flash.lock()
else do
io.println("Güncelleme başarısız!")
return
end
end
// Jump to application
io.println("Uygulamaya atlanıyor...")
jump_to_application(APP_START)
end
function jump_to_application(addr: int) do
// Read stack pointer and reset vector
let sp = flash.read_word(addr)
let reset_handler = flash.read_word(addr + 4)
// Disable interrupts
asm!("cpsid i")
// Set stack pointer
asm!("msr msp, {}", in(reg) sp)
// Jump to reset handler
let jump: function() = transmute(reset_handler)
jump()
end
💡 Example 3: Option Bytes Programming
Read protection ve write protection ayarları
import hal::flash
enum ReadProtection {
LEVEL_0, // No protection
LEVEL_1, // Memory read protection
LEVEL_2 // Permanent protection (irreversible!)
}
function set_read_protection(level: ReadProtection) do
flash.unlock()
flash.unlock_option_bytes()
if level == ReadProtection.LEVEL_1 do
flash.set_option_byte(flash.OB_RDP, 0x00)
io.println("UYARI: Read protection Level 1 etkinleştirildi")
else if level == ReadProtection.LEVEL_2 do
io.println("UYARI: Level 2 GERİ ALINAMAZ! Devam edilsin mi? (y/n)")
// Level 2 is permanent - chip cannot be debugged anymore!
end
flash.lock_option_bytes()
flash.lock()
end
function protect_bootloader() do
// Protect first 16KB (bootloader area)
flash.unlock()
flash.unlock_option_bytes()
flash.set_write_protection(do
sectors: [flash.SECTOR_0, flash.SECTOR_1],
enable: doğru
end)
flash.lock_option_bytes()
flash.lock()
io.println("Bootloader koruması etkinleştirildi")
end
📊 API Referansı
Lock/Unlock
function unlock()
function lock()
function is_locked() -> bool
Erase Operations
function erase_page(address: int)
function erase_sector(sector: int)
function mass_erase()
function mass_erase_bank(bank: Bank)
Write Operations
function write_byte(address: int, data: u8)
function write_halfword(address: int, data: u16)
function write_word(address: int, data: u32)
function write_doubleword(address: int, data: u64)
function write(address: int, data: Dizi[u32])
Read Operations
function read_byte(address: int) -> u8
function read_halfword(address: int) -> u16
function read_word(address: int) -> u32
function read(address: int, length: int) -> Dizi[u8]
Option Bytes
function unlock_option_bytes()
function lock_option_bytes()
function set_option_byte(option: int, value: int)
function get_option_byte(option: int) -> int
⚙️ Platform Desteği
| Platform | Flash Size | Page Size | Write Align |
|---|---|---|---|
| STM32F1 | 64-512 KB | 1-2 KB | 2 bytes |
| STM32F4 | 512 KB-2 MB | 16-128 KB | 4 bytes |
| STM32F7 | 1-2 MB | 32-256 KB | 4 bytes |
| GD32VF103 | 64-128 KB | 1 KB | 4 bytes |
💡 Best Practices
- Write alignment: Data her zaman belirtilen alignment'a uygun olmalı
- Erase before write: Flash sadece 1 → 0 yazabilir, önce erase (0xFF) gerekli
- Wear leveling: Aynı sayfaya çok sık yazma yapılmamalı (100K cycle limit)
- Power loss: Yazma sırasında güç kaybında data corruption olabilir
- Interrupts: Flash programming sırasında interrupt'ları dikkatli kullanın
- Read-while-write: Bazı MCU'lar yazarken okuma yapamaz
⚠️ Önemli Notlar
- Flash programming CPU'yu bloklar (~20-50ms per page)
- Option bytes Level 2 read protection geri alınamaz!
- Flash endurance tipik 10K-100K erase cycle
- Data retention: 10+ yıl (25°C'de)
🔗 Related Modules
- hal::crc - CRC verification for stored data
- hal::watchdog - Disable during flash erase