Tiny storage(file) system on MCU internal flash memory for Nucleo F4xx. The purpose of SOFBlock class is to provide a way to write data on flash memory in the same way of file handling class in the file system.

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SOF_dev_stm32_l4xx.cpp Source File

SOF_dev_stm32_l4xx.cpp

00001 /**
00002 * @file SOF_dev_stm32_l4xx.c
00003 *
00004 * @brief Flash device access interface for STM32 L4xx series
00005 *
00006 *
00007 * History:
00008 */
00009 
00010 #include <stdio.h>
00011 #include "SOF_dev.h"
00012 #include <string.h>
00013 
00014 #include "mbed.h"
00015 
00016 #include "stm32l4xx_hal_flash.h"
00017 
00018 #define DCRLF   "\r\n"
00019 
00020 #if 0
00021 extern Serial pc;
00022 #define DPRINTF pc.printf
00023 #define DASSERT(cond)  \
00024     if (!(cond)) { \
00025         pc.printf("%s:%d assertion failed! '%s\r\n"\
00026             , __FILE__, __LINE__, #cond); \
00027     }
00028 #else
00029 #define DPRINTF(...)
00030 #define DASSERT(...)
00031 #endif
00032 
00033 // 1024*4*sizeof(byte) = 4Kbyte flash must (application)
00034 //
00035 // STM32L4xx flash area
00036 //  bank  address      size  page   (virtual_sector)
00037 //  1     0x08000000   2k    0
00038 //  1     0x08000800   2k    1
00039 //  1     0x08001000   2k    2
00040 //
00041 //  1     0x0803C000   2k    120     11
00042 //  1     0x0803C800   2k    121     11
00043 //  1     0x0803D000   2k    122     11
00044 //  1     0x0803D800   2k    123     11
00045 //  1     0x0803E000   2k    124     11 <-- ここを11セクタの先頭とする
00046 //  1     0x0803E800   2k    125     11
00047 //  1     0x0803F000   2k    126     11
00048 //  1     0x0803F800   2k    127     11 <-- STM32L432KC ここまで (256KB)
00049 //
00050 //  1     0x0807C000   2k    248     11 
00051 //  1     0x0807C800   2k    249     11
00052 //  1     0x0807D000   2k    250     11
00053 //  1     0x0807D800   2k    251     11
00054 //  1     0x0807E000   2k    252     11
00055 //  1     0x0807E800   2k    253     11
00056 //  1     0x0807F000   2k    254     11
00057 //  1     0x0807F800   2k    255     11 <-- 512KB
00058 #define REQ_SECTOR  11
00059 #define PAGE_SIZE   2048
00060 #define START_ADDRESS  0x0803E000 //11セクタの先頭アドレス
00061 
00062 /*--- sector11 table ---*/
00063 #if defined(STM32L431xx) || defined(STM32L432xx) || defined(STM32L433xx) || defined(STM32L442xx) || defined(STM32L443xx)
00064 static const SOF_SectorSpec_t _sec11_spec[] = {
00065 //   page    address              size
00066     {124,    START_ADDRESS+0x0000, PAGE_SIZE},
00067     {125,    START_ADDRESS+0x0800, PAGE_SIZE},
00068     {126,    START_ADDRESS+0x1000, PAGE_SIZE},
00069     {127,    START_ADDRESS+0x1800, PAGE_SIZE},//last page
00070 };
00071 #elif defined(STM32L451xx) || defined(STM32L452xx) || defined(STM32L462xx)
00072 static const SOF_SectorSpec_t _sec11_spec_example[] = {
00073     {255,    START_ADDRESS+0x0000, PAGE_SIZE},//last page
00074 };
00075 #else
00076   #error "Not supported device"
00077 #endif
00078 
00079 #define N_PAGE_SPEC    (sizeof(_sec11_spec)/sizeof(_sec11_spec[0]))
00080 #define PAGE_NO(page)   _sec11_spec[0].sec_no //top page
00081 #define PAGE_ADDR(page)  _sec11_spec[0].sec_addr //top address
00082 
00083 static const SOF_SectorSpec_t _sec11_dummy = {
00084     //                         ここ重要。ページの最後をセットすること
00085     REQ_SECTOR, START_ADDRESS, PAGE_SIZE*N_PAGE_SPEC
00086 };
00087 
00088 static uint64_t _data64w = 0;
00089 static uint64_t _data64b = 0;
00090 static int32_t _offset_addr_w = -1;
00091 static int32_t _offset_addr_b = -1;
00092 
00093 static inline size_t handle_to_sector_index(SOF_DevHandle_t hdev)
00094 {
00095     DASSERT(hdev == REQ_SECTOR);
00096     return hdev;
00097 }
00098 
00099 int SOF_dev_is_valid_sector(uint8_t sector_index)
00100 {
00101     return sector_index == REQ_SECTOR;
00102 }
00103 
00104 const SOF_SectorSpec_t *SOF_dev_info_by_index(uint8_t sector_index)
00105 {
00106     DASSERT(SOF_dev_is_valid_sector(sector_index));
00107     return &_sec11_dummy;
00108 }
00109 
00110 const SOF_SectorSpec_t *SOF_dev_info(SOF_DevHandle_t hdev)
00111 {
00112     uint8_t sector_index = handle_to_sector_index(hdev);
00113     return SOF_dev_info_by_index(sector_index);
00114 }
00115 
00116 SOF_DevHandle_t SOF_dev_open(uint8_t sector_index)
00117 {
00118     DPRINTF("SOF_dev_open %d\r\n", sector_index);
00119     _data64w = _data64b = 0;
00120     _offset_addr_w = -1;
00121     _offset_addr_b = -1;
00122 
00123     DASSERT(sector_index == REQ_SECTOR);
00124     return (SOF_DevHandle_t)sector_index;
00125 }
00126 
00127 void SOF_dev_close(SOF_DevHandle_t hdev)
00128 {
00129     uint8_t sector_index = handle_to_sector_index(hdev);
00130     DPRINTF("SOF_dev_close %d\r\n", sector_index);
00131 
00132     //if write pending, must write
00133     //
00134     if(_offset_addr_w >= 0){
00135         SOF_dev_write_word(sector_index, _offset_addr_w + 4, 0);//+4:write finish
00136     }
00137     if(_offset_addr_b >= 0){
00138         SOF_dev_write_byte(sector_index, _offset_addr_b + 7, 0);//+7:write finish
00139     }
00140 }
00141 
00142 uint8_t *SOF_dev_get_hw_addr(SOF_DevHandle_t hdev)
00143 {
00144     uint8_t sector_index = handle_to_sector_index(hdev);
00145     return (uint8_t *)PAGE_ADDR(sector_index);
00146 }
00147 
00148 /*--- hdev is sector (11 only by application)  ---*/
00149 void SOF_dev_erase(SOF_DevHandle_t hdev)
00150 {
00151     uint8_t sector_index = handle_to_sector_index(hdev);
00152     FLASH_EraseInitTypeDef ei;
00153     uint32_t error = 0;
00154 
00155     DPRINTF("FLASH_Erase_Page %d"DCRLF, PAGE_NO(sector_index));
00156     HAL_FLASH_Unlock();
00157 
00158     ei.TypeErase = FLASH_TYPEERASE_PAGES;
00159 #if defined(STM32L431xx) || defined(STM32L432xx) || defined(STM32L433xx) || defined(STM32L442xx) || defined(STM32L443xx) ||\
00160     defined(STM32L451xx) || defined(STM32L452xx) || defined(STM32L462xx)
00161     ei.Banks = FLASH_BANK_1;//bank1 only
00162 #else
00163     ei.Banks = FLASH_BANK_2;
00164 #endif
00165     ei.Page = PAGE_NO(secotr_index); //top page
00166     ei.NbPages = N_PAGE_SPEC; //number of page
00167     HAL_StatusTypeDef ret = HAL_FLASHEx_Erase(&ei, &error);
00168 
00169     HAL_FLASH_Lock();
00170     DPRINTF("FLASH_Erase_Page ret=%d, page=%d, n=%d\r\n", ret, ei.Page, ei.NbPages);
00171 }
00172 
00173 uint64_t SOF_dev_read_dword(SOF_DevHandle_t hdev, uint32_t offset_addr)
00174 {
00175     uint8_t sector_index = handle_to_sector_index(hdev);
00176     uint32_t src = PAGE_ADDR(sector_index) + offset_addr;
00177     uint64_t ret = *(volatile uint64_t*)src;
00178     return ret;
00179 }
00180 
00181 int SOF_dev_write_word(SOF_DevHandle_t hdev, uint32_t offset_addr, uint32_t data)
00182 {
00183     uint8_t sector_index = handle_to_sector_index(hdev);
00184     uint32_t dst = PAGE_ADDR(sector_index) + offset_addr;
00185     DPRINTF("SOF_dev_write_word dst=%08X ofs=%d, ", dst, offset_addr);
00186     // +0     +4     +8
00187     //  +------+------+
00188     //  |DWORDH|DWORDL|
00189     //  +------+------+
00190     if(offset_addr % 8 == 0){//address 8 multiple
00191         _data64w |= data;
00192         _offset_addr_w = offset_addr;
00193         DPRINTF("data=%08X\r\n", data);
00194         return 0;//next waiting
00195     } else if(offset_addr % 4 == 0){//address 4 multiple
00196         _data64w |= ((uint64_t)data << 32);
00197         dst = PAGE_ADDR(sector_index) + _offset_addr_w;
00198         DPRINTF("data=%08X\r\n", data);
00199     }
00200 
00201     DASSERT((offset_addr % sizeof(uint32_t)) == 0);//required address 4 multiple
00202     HAL_FLASH_Unlock();
00203 
00204     if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, dst, _data64w) != HAL_OK) {
00205         DPRINTF("FLASH_ProgramWord failed: %#x"DCRLF, dst);
00206         HAL_FLASH_Lock();
00207         return -1;
00208     }
00209 
00210     HAL_FLASH_Lock();
00211 
00212 /*--- read back ---*/
00213     if (_data64w != SOF_dev_read_dword(hdev, _offset_addr_w)) {
00214         DPRINTF("addr=%X %#04X %#04X"DCRLF, dst, data, SOF_dev_read_dword(hdev, _offset_addr_w));
00215         return -1;
00216     }
00217 
00218     _data64w = 0;//finish
00219     _offset_addr_w = -1;//finish
00220 
00221     return 0;
00222 }
00223 
00224 uint32_t SOF_dev_read_word(SOF_DevHandle_t hdev, uint32_t offset_addr)
00225 {
00226     uint8_t sector_index = handle_to_sector_index(hdev);
00227     uint32_t src = PAGE_ADDR(sector_index) + offset_addr;
00228     DASSERT((offset_addr % sizeof(uint32_t)) == 0);//required address 4 multiple
00229 
00230     uint32_t ret = *(volatile uint32_t*)src;
00231     DPRINTF("SOF_dev_read_word src=%08X, ret=%08X\r\n", src, ret);
00232     return ret;
00233 }
00234 
00235 int SOF_dev_write_byte(SOF_DevHandle_t hdev, uint32_t offset_addr, uint8_t data)
00236 {
00237     uint8_t sector_index = handle_to_sector_index(hdev);
00238     uint32_t dst = PAGE_ADDR(sector_index) + offset_addr;
00239     DPRINTF("SOF_dev_write_byte dst=%08X ofs=%d, ", dst, offset_addr);
00240     // +0     +1     +2     +3     +4             +8
00241     //  +------+------+------+------+----   +------+
00242     //  |BYTE1 |BYTE2 |BYTE3 |BYTE4 |       |BYTE8 |
00243     //  +------+------+------+------+----   +------+
00244     if(offset_addr % 8 == 0){//address 4 multiple
00245         _data64b |= ((uint64_t)data << (64-64));
00246         _offset_addr_b = offset_addr;
00247         DPRINTF("data=%02X\r\n", data);
00248         return 0;//next waiting
00249     } else if(offset_addr % 8 == 1){
00250         _data64b |= ((uint64_t)data << (64-56));
00251         DPRINTF("data=%02X\r\n", data);
00252         return 0;
00253     } else if(offset_addr % 8 == 2){
00254         _data64b |= ((uint64_t)data << (64-48));
00255         DPRINTF("data=%02X\r\n", data);
00256         return 0;
00257     } else if(offset_addr % 8 == 3){
00258         _data64b |= ((uint64_t)data << (64-40));
00259         DPRINTF("data=%02X\r\n", data);
00260         return 0;
00261     } else if(offset_addr % 8 == 4){
00262         _data64b |= ((uint64_t)data << (64-32));
00263         DPRINTF("data=%02X\r\n", data);
00264         return 0;
00265     } else if(offset_addr % 8 == 5){
00266         _data64b |= ((uint64_t)data << (64-24));
00267         DPRINTF("data=%02X\r\n", data);
00268         return 0;
00269     } else if(offset_addr % 8 == 6){
00270         _data64b |= ((uint64_t)data << (64-16));
00271         DPRINTF("data=%02X\r\n", data);
00272         return 0;
00273     } else if(offset_addr % 8 == 7){
00274         _data64b |= ((uint64_t)data << (64-8));
00275         dst = PAGE_ADDR(sector_index) + _offset_addr_b;
00276         DPRINTF("data=%02X\r\n", data);
00277     }
00278 
00279     HAL_FLASH_Unlock();
00280 
00281     if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, dst, _data64b) != HAL_OK) {
00282         DPRINTF("FLASH_ProgramByte failed: %#x"DCRLF, dst);
00283         HAL_FLASH_Lock();
00284         return -1;
00285     }
00286 
00287     HAL_FLASH_Lock();
00288 
00289 /*--- read back ---*/
00290     if (_data64b != SOF_dev_read_dword(hdev, _offset_addr_b)) {
00291         DPRINTF("addr=%X %#04X %#04X"DCRLF, dst, data, SOF_dev_read_dword(hdev, _offset_addr_b));
00292         return -1;
00293     }
00294 
00295     _data64b = 0;//finish
00296     _offset_addr_b = -1;//finish
00297 
00298     return 0;
00299 }
00300 
00301 uint8_t SOF_dev_read_byte(SOF_DevHandle_t hdev, uint32_t offset_addr)
00302 {
00303     uint8_t sector_index = handle_to_sector_index(hdev);
00304     uint32_t src = PAGE_ADDR(sector_index) + offset_addr;
00305     uint8_t ret = *(volatile uint8_t*)src;
00306     DPRINTF("SOF_dev_read_byte src=%08X, ret=%02X\r\n", src, ret);
00307     return ret;
00308 }
00309 
00310 
00311