2025-03-10 20:43:14 +03:00
|
|
|
|
#include "flash.h"
|
2025-03-17 15:43:34 +03:00
|
|
|
|
#include <stdbool.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static uint32_t write_ptr = SECTOR_6;
|
|
|
|
|
|
2025-03-10 20:43:14 +03:00
|
|
|
|
|
|
|
|
|
void flash_unlock(){
|
|
|
|
|
|
|
|
|
|
// Check if flash is locked
|
|
|
|
|
if(!(FLASH->CR & FLASH_CR_LOCK)) {
|
|
|
|
|
return; // Already unlocked
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Write flash key sequence to unlock
|
|
|
|
|
FLASH->KEYR = 0x45670123; // First key
|
|
|
|
|
FLASH->KEYR = 0xCDEF89AB; // Second key
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void flash_lock() {
|
|
|
|
|
if(FLASH->CR & FLASH_CR_LOCK) {
|
|
|
|
|
return; // Already locked
|
|
|
|
|
}
|
|
|
|
|
FLASH->CR |= FLASH_CR_LOCK; // Lock flash memory
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void erase_sector(uint8_t sector){
|
|
|
|
|
|
|
|
|
|
// Wait if flash is busy
|
|
|
|
|
while(FLASH_BUSY);
|
|
|
|
|
|
|
|
|
|
// Check if flash is locked and unlock if needed
|
|
|
|
|
if(FLASH->CR & FLASH_CR_LOCK) {
|
|
|
|
|
flash_unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set sector erase bit and sector number
|
|
|
|
|
FLASH->CR |= FLASH_CR_SER;
|
|
|
|
|
FLASH->CR &= ~FLASH_CR_SNB;
|
|
|
|
|
FLASH->CR |= (sector << FLASH_CR_SNB_Pos) & FLASH_CR_SNB_Msk;
|
|
|
|
|
|
|
|
|
|
// Start erase
|
|
|
|
|
FLASH->CR |= FLASH_CR_STRT;
|
|
|
|
|
|
|
|
|
|
// Wait for erase to complete
|
|
|
|
|
while(FLASH_BUSY);
|
|
|
|
|
|
|
|
|
|
// Clear sector erase bit
|
|
|
|
|
FLASH->CR &= ~FLASH_CR_SER;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void flash_program_word(uint32_t address,uint32_t data,uint32_t byte_len){
|
|
|
|
|
|
|
|
|
|
// Wait if flash is busy
|
|
|
|
|
while(FLASH_BUSY);
|
|
|
|
|
// Check if flash is locked and unlock if needed
|
|
|
|
|
if(FLASH->CR & FLASH_CR_LOCK) {
|
|
|
|
|
flash_unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set program bit 32bit programm size and Write data to address
|
|
|
|
|
if(byte_len == 1) {
|
|
|
|
|
FLASH_8BYTE;
|
|
|
|
|
FLASH->CR |= FLASH_CR_PG;
|
|
|
|
|
*(volatile uint8_t*)address = (uint8_t)data;
|
|
|
|
|
} else {
|
|
|
|
|
FLASH_32BYTE;
|
|
|
|
|
FLASH->CR |= FLASH_CR_PG;
|
|
|
|
|
*(volatile uint32_t*)address = data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Wait for programming to complete
|
|
|
|
|
while(FLASH_BUSY);
|
|
|
|
|
|
|
|
|
|
// Clear program bit
|
|
|
|
|
FLASH->CR &= ~FLASH_CR_PG;
|
|
|
|
|
|
|
|
|
|
}
|
2025-03-17 15:43:34 +03:00
|
|
|
|
void flash_write(uint32_t addr, FLASH_RECORD* record){
|
|
|
|
|
|
|
|
|
|
uint32_t* data = (uint32_t*)record;
|
|
|
|
|
uint32_t size = FLASH_RECORD_SIZE / 4; //count words in struct
|
|
|
|
|
// Wait if flash is busy
|
|
|
|
|
while(FLASH_BUSY);
|
|
|
|
|
|
|
|
|
|
// Check if flash is locked and unlock if needed
|
|
|
|
|
if(FLASH->CR & FLASH_CR_LOCK) {
|
|
|
|
|
flash_unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set program bit and write data to flash
|
|
|
|
|
FLASH_32BYTE;
|
|
|
|
|
FLASH->CR |= FLASH_CR_PG;
|
|
|
|
|
|
|
|
|
|
for(int i = 0;i < size;i++){
|
|
|
|
|
*(volatile uint32_t*)(addr + i * 4) = data[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Clear program bit
|
|
|
|
|
FLASH->CR &= ~FLASH_CR_PG;
|
|
|
|
|
flash_lock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Wait if flash
|
|
|
|
|
|
2025-03-10 20:43:14 +03:00
|
|
|
|
|
2025-03-17 15:43:34 +03:00
|
|
|
|
bool validate_crc(FLASH_RECORD* crc){
|
|
|
|
|
if(crc->crc == 0x6933)
|
|
|
|
|
return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
/* read struct from FLASH */
|
|
|
|
|
void flash_read(uint32_t addr,FLASH_RECORD* ptr){
|
|
|
|
|
uint32_t* flash_ptr = (uint32_t*)addr;
|
|
|
|
|
uint32_t* dest = (uint32_t*)ptr;
|
|
|
|
|
for (int i = 0; i < FLASH_RECORD_SIZE / 4; i++) {
|
|
|
|
|
dest[i] = flash_ptr[i];
|
2025-03-10 20:43:14 +03:00
|
|
|
|
}
|
2025-03-17 15:43:34 +03:00
|
|
|
|
}
|
|
|
|
|
|
2025-03-10 20:43:14 +03:00
|
|
|
|
|
2025-03-17 15:43:34 +03:00
|
|
|
|
/* Поиск актуального адреса во флэш памяти */
|
|
|
|
|
FLASH_RECORD load_params(){
|
|
|
|
|
__disable_irq();
|
|
|
|
|
FLASH_RECORD latest = {0};
|
|
|
|
|
FLASH_RECORD res;
|
|
|
|
|
for(uint32_t addr = SECTOR_6;addr < SECTOR_6_END;addr +=FLASH_RECORD_SIZE) {
|
|
|
|
|
flash_read(addr,&res);
|
|
|
|
|
if (!validate_crc(&res))
|
|
|
|
|
break;
|
|
|
|
|
else if(res.data_id == addr_id) {
|
|
|
|
|
latest = res;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-03-10 20:43:14 +03:00
|
|
|
|
|
2025-03-17 15:43:34 +03:00
|
|
|
|
__enable_irq();
|
|
|
|
|
return latest;
|
2025-03-10 20:43:14 +03:00
|
|
|
|
}
|
2025-03-17 15:43:34 +03:00
|
|
|
|
/**
|
|
|
|
|
* @brief Записывает страницу данных во флеш-память
|
|
|
|
|
* @param data: Указатель на буфер с данными
|
|
|
|
|
* @param len: Длина данных в байтах (должна быть кратна 4)
|
|
|
|
|
* @retval bool: true - успех, false - ошибка
|
|
|
|
|
*/
|
|
|
|
|
void write_flash_page(const uint8_t* data, uint16_t len) { // Добавлен const
|
|
|
|
|
flash_unlock();
|
|
|
|
|
for (uint16_t i = 0; i < len; i += 4) {
|
|
|
|
|
uint32_t word;
|
|
|
|
|
memcpy(&word, &data[i], 4); // Безопасное копирование
|
|
|
|
|
HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, write_ptr + i, word);
|
|
|
|
|
}
|
|
|
|
|
flash_lock();
|
|
|
|
|
}
|