├── src
├── SConscript
└── flash_blob.c
├── SConscript
├── .github
└── workflows
│ └── cmake-single-platform.yml
├── port
├── GD32
│ ├── GD32_FLASH_DEV.c
│ └── GD32_FLASH_PRG.c
└── STM32
│ ├── STM32_FLASH_DRV.c
│ └── STM32_FLASH_DEV.c
├── kk.flash_blob.pdsc
├── readme.md
├── gen_pack.sh
├── inc
└── flash_blob.h
├── LICENSE
└── docs
└── readme.md
/src/SConscript:
--------------------------------------------------------------------------------
1 | from building import *
2 |
3 | cwd = GetCurrentDir()
4 | src = Glob('*.c')
5 | CPPPATH = [cwd + '/../inc']
6 |
7 | group = DefineGroup('flash_blob', src, depend = ['PKG_USING_FLASH_BLOB'], CPPPATH = CPPPATH)
8 |
9 | Return('group')
--------------------------------------------------------------------------------
/SConscript:
--------------------------------------------------------------------------------
1 | # RT-Thread building script for bridge
2 |
3 | import os
4 | from building import *
5 |
6 | cwd = GetCurrentDir()
7 | objs = []
8 | list = os.listdir(cwd)
9 |
10 | if GetDepend('PKG_USING_FLASH_BLOB'):
11 | for d in list:
12 | path = os.path.join(cwd, d)
13 | if os.path.isfile(os.path.join(path, 'SConscript')):
14 | objs = objs + SConscript(os.path.join(d, 'SConscript'))
15 |
16 | Return('objs')
--------------------------------------------------------------------------------
/.github/workflows/cmake-single-platform.yml:
--------------------------------------------------------------------------------
1 | name: Build documentation and pack
2 |
3 | on:
4 | workflow_dispatch:
5 | push:
6 | branches: [ main ]
7 | pull_request:
8 | branches: [ main ]
9 | release:
10 | types: [published]
11 |
12 | jobs:
13 | pack:
14 | name: Generate pack
15 | runs-on: ubuntu-20.04
16 | steps:
17 | - name: Checkout repository
18 | uses: actions/checkout@v3
19 | with:
20 | fetch-depth: 0
21 |
22 | - name: Fetch tags
23 | if: ${{ github.event_name == 'release' }}
24 | run: |
25 | git fetch --tags --force
26 |
27 | - name: Make gen_pack.sh executable
28 | run: chmod +x ./gen_pack.sh
29 |
30 | - name: Generate Pack
31 | uses: Open-CMSIS-Pack/gen-pack-action@main
32 | with:
33 | doxygen-version: 1.9.2
34 | packchk-version: 1.3.96
35 | gen-pack-script: ./gen_pack.sh
36 | gen-pack-output: ./output
37 |
--------------------------------------------------------------------------------
/port/GD32/GD32_FLASH_DEV.c:
--------------------------------------------------------------------------------
1 | #include "flash_blob.h"
2 | #ifdef GD32E50X
3 | #include "gd32e50x_fmc.h"
4 | static flash_dev_t const FlashDevice = {
5 | FLASH_DRV_VERS, // Driver Version, do not modify!
6 | "GD32E50X 512kB Flash", // Device Name (512kB)
7 | ONCHIP, // Device Type
8 | 0x08000000, // Device Start Address
9 | 0x00080000, // Device Size in Bytes (512kB)
10 | 0x00002000, // Programming Page Size
11 | 0, // Reserved, must be 0
12 | 0xFF, // Initial Content of Erased Memory
13 | 100, // Program Page Timeout 100 mSec
14 | 6000, // Erase Sector Timeout 6000 mSec
15 | // Specify Size and Address of Sectors
16 | 0x2000, 0x000000, // Sector Size 8kB (64 Sectors)
17 | SECTOR_END
18 | };
19 | #endif // GD32E50X_512
20 |
21 | #ifdef GD32F30X_CL
22 | #include "gd32f30x_fmc.h"
23 | static flash_dev_t const FlashDevice = {
24 | FLASH_DRV_VERS, // Driver Version, do not modify!
25 | "GD32F30X 256kB Flash", // Device Name (512kB)
26 | ONCHIP, // Device Type
27 | 0x08000000, // Device Start Address
28 | 0x00040000, // Device Size in Bytes (256kB)
29 | 0x00000800, // Programming Page Size
30 | 0, // Reserved, must be 0
31 | 0xFF, // Initial Content of Erased Memory
32 | 100, // Program Page Timeout 100 mSec
33 | 6000, // Erase Sector Timeout 6000 mSec
34 | // Specify Size and Address of Sectors
35 | 0x0800, 0x000000, // Sector Size 2kB (128 Sectors)
36 | SECTOR_END
37 | };
38 | #endif // GD32E50X_256
39 |
40 |
--------------------------------------------------------------------------------
/kk.flash_blob.pdsc:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | kk
5 | flash_blob
6 | An abstraction layer for address-based FLASH management and operation.
7 | https://github.com/Aladdin-Wang/flash_blob/
8 | https://github.com/Aladdin-Wang/flash_blob/issues
9 | LICENSE
10 |
11 |
12 |
13 |
14 | https://github.com/Aladdin-Wang/flash_blob.git
15 |
16 |
17 |
18 |
19 | Active development ...
20 |
21 |
22 |
23 | Initial release of flash_blob.
24 |
25 |
26 | Initial release of flash_blob.
27 |
28 |
29 |
30 |
31 |
32 | FLASH
33 | C Language
34 | Data Structures
35 |
36 |
37 |
38 |
39 |
40 | An abstraction layer for address-based FLASH management and operation.
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | An abstraction layer for address-based FLASH management and operation.
52 |
53 |
54 |
--------------------------------------------------------------------------------
/port/GD32/GD32_FLASH_PRG.c:
--------------------------------------------------------------------------------
1 | #include "flash_blob.h"
2 | #include "gd32e50x_fmc.h"
3 | #include "GD32_FLASH_DEV.c"
4 | /*
5 | * Initialize Flash Programming Functions
6 | * Parameter: adr: Device Base Address
7 | * clk: Clock Frequency (Hz)
8 | * fnc: Function Code (1 - Erase, 2 - Program, 3 - Verify)
9 | * Return Value: 0 - OK, 1 - Failed
10 | */
11 |
12 | static int32_t Init(uint32_t adr, uint32_t clk, uint32_t fnc)
13 | {
14 | fmc_unlock();
15 | return (0);
16 | }
17 |
18 | /*
19 | * De-Initialize Flash Programming Functions
20 | * Parameter: fnc: Function Code (1 - Erase, 2 - Program, 3 - Verify)
21 | * Return Value: 0 - OK, 1 - Failed
22 | */
23 |
24 | static int32_t UnInit(uint32_t fnc)
25 | {
26 | fmc_lock();
27 | return (0);
28 | }
29 |
30 | /*
31 | * Erase complete Flash Memory
32 | * Return Value: 0 - OK, 1 - Failed
33 | */
34 |
35 | static int32_t EraseChip(void)
36 | {
37 | fmc_mass_erase();
38 | return (0);
39 | }
40 |
41 | /*
42 | * Erase Sector in Flash Memory
43 | * Parameter: adr: Sector Address
44 | * Return Value: 0 - OK, 1 - Failed
45 | */
46 | static int32_t EraseSector(uint32_t adr)
47 | {
48 | fmc_page_erase(adr);
49 | return (0);
50 | }
51 |
52 | /*
53 | * Program Page in Flash Memory
54 | * Parameter: adr: Page Start Address
55 | * sz: Page Size
56 | * buf: Page Data
57 | * Return Value: 0 - OK, 1 - Failed
58 | */
59 | static int32_t ProgramPage(uint32_t addr, uint32_t sz, uint8_t* buf)
60 | {
61 | int32_t result = 0;
62 | uint32_t end_addr = addr + sz;
63 | while (addr < end_addr) {
64 | if (fmc_word_program(addr, *((uint32_t *)buf)) == FMC_READY) {
65 | if (*(uint32_t *)addr != *(uint32_t *)buf) {
66 | result = 1;
67 | break;
68 | }
69 | addr += 4;
70 | buf += 4;
71 | } else {
72 | result = 1;
73 | break;
74 | }
75 | }
76 | return result;
77 | }
78 |
79 | static flash_blob_t flash_device = {
80 | .tFlashops.Init = Init,
81 | .tFlashops.UnInit = UnInit,
82 | .tFlashops.EraseChip = EraseChip,
83 | .tFlashops.EraseSector = EraseSector,
84 | .tFlashops.ProgramPage = ProgramPage,
85 | .tFlashops.Read = NULL,
86 | .ptFlashDev = &FlashDevice,
87 | };
88 |
89 | __attribute__((constructor))
90 | static int flash_blob_device_register(void)
91 | {
92 | flash_dev_register(&flash_device);
93 | return 0 ;
94 | }
95 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # flash_blob
2 |
3 | ## 1、介绍
4 |
5 | 利用MDK的FLM文件快速生成通用flash驱动。
6 | - 同时支持多个flash芯片级联,根据地址自动选择flash驱动。
7 | - 可以作为直接操作 `片内 Flash` 和 `SPI Flash` 的后端实现。
8 |
9 | ### 1.1、API接口
10 | ```c
11 | extern bool target_flash_init(uint32_t flash_start, int32_t size);
12 | extern bool target_flash_uninit(uint32_t flash_start);
13 | extern int32_t target_flash_write(uint32_t addr, const uint8_t *buf, int32_t size);
14 | extern int32_t target_flash_erase(uint32_t addr, int32_t size);
15 | extern int32_t target_flash_read(uint32_t addr, const uint8_t *buf, int32_t size);
16 | ```
17 |
18 | ### 1.2、目录结构
19 |
20 | | doc | 文档 |
21 | | ----- | ------------ |
22 | | src | 源代码 |
23 | | inc | 头文件 |
24 | | tools | 驱动生成工具 |
25 |
26 | ### 1.3、许可证
27 |
28 | Agile Upgrade 遵循 `Apache-2.0` 许可,详见 `LICENSE` 文件。
29 |
30 |
31 |
32 | ## 2、使用 flash_blob
33 | 1. 在rtthread软件包中找到flash_blob,然后添加进工程。
34 |
35 | 2. 添加对应芯片的代码进工程,如果有多个flash器件,可以连续添加。
36 |
37 | 注意:多个设备的话每个flash的FlashDevice 的设备起始地址不可重叠,flash抽象层根据地址,自动选择相应的驱动。
38 |
39 | 以上步骤完成后,就可以快速使用了,例如将YMODEM接收到的数据,写到flash中,代码如下:
40 |
41 |
42 | ```c
43 | uint8_t *ymodem_call_back_receive(uint8_t *pchBuffer, uint16_t hwSize)
44 | {
45 | static char *s_pchFileName = NULL, *s_pchFileSize = NULL;
46 | static uint32_t s_wFileSize = 0, s_wRemainLen = 0, s_wOffSet = 0;
47 |
48 | static enum {
49 | START = 0,
50 | RECEIVE,
51 | END,
52 | } s_tState = {START};
53 |
54 | switch(s_tState) {
55 | case START:
56 | s_wOffSet = 0;
57 | s_pchFileName = (char *)&pchBuffer[0];
58 | s_pchFileSize = (char *)&pchBuffer[strlen(s_pchFileName) + 1];
59 | s_wFileSize = atol(s_pchFileSize);
60 |
61 | LOG_D("Ymodem file_name:%s", s_pchFileName);
62 | LOG_D("Ymodem file_size:%d", s_wFileSize);
63 |
64 | if(target_flash_init(APP_PART_ADDR, s_wFileSize) == false) {
65 | LOG_E("target flash uninit.");
66 | return NULL;
67 | }
68 |
69 | if(target_flash_erase(APP_PART_ADDR, s_wFileSize) < 0) {
70 | LOG_E("target flash erase error.");
71 | return NULL;
72 | }
73 |
74 | s_tState = RECEIVE;
75 | break;
76 |
77 | case RECEIVE:
78 | s_wRemainLen = s_wFileSize - s_wOffSet;
79 |
80 | if(hwSize > s_wRemainLen) {
81 | hwSize = s_wRemainLen;
82 | s_tState = END;
83 | }
84 |
85 | if(target_flash_write(APP_PART_ADDR + s_wOffSet, pchBuffer, hwSize) < 0) {
86 | LOG_E("target flash write data error.");
87 | return NULL;
88 | }
89 | s_wOffSet += hwSize;
90 |
91 | break;
92 |
93 | case END:
94 | target_flash_uninit(APP_PART_ADDR);
95 | s_tState = START;
96 | break;
97 | }
98 |
99 | return s_chBuffer;
100 | }
101 | ```
102 |
103 |
--------------------------------------------------------------------------------
/gen_pack.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | # Version: 2.7
3 | # Date: 2023-05-22
4 | # This bash script generates a CMSIS Software Pack:
5 | #
6 |
7 | set -o pipefail
8 |
9 | # Set version of gen pack library
10 | # For available versions see https://github.com/Open-CMSIS-Pack/gen-pack/tags.
11 | # Use the tag name without the prefix "v", e.g., 0.7.0
12 | REQUIRED_GEN_PACK_LIB="0.8.4"
13 |
14 | # Set default command line arguments
15 | DEFAULT_ARGS=(-c "v")
16 |
17 | # Pack warehouse directory - destination
18 | # Default: ./output
19 | #
20 | # PACK_OUTPUT=./output
21 |
22 | # Temporary pack build directory,
23 | # Default: ./build
24 | #
25 | # PACK_BUILD=./build
26 |
27 | # Specify directory names to be added to pack base directory
28 | # An empty list defaults to all folders next to this script.
29 | # Default: empty (all folders)
30 | #
31 | PACK_DIRS="
32 | src
33 | inc
34 | port
35 | "
36 |
37 | # Specify file names to be added to pack base directory
38 | # Default: empty
39 | #
40 | PACK_BASE_FILES="
41 | LICENSE
42 | flash_blob.c
43 | flash_blob.h
44 | README.md
45 | "
46 |
47 | # Specify file names to be deleted from pack build directory
48 | # Default: empty
49 | #
50 | # PACK_DELETE_FILES="
51 | # "
52 |
53 | # Specify patches to be applied
54 | # Default: empty
55 | #
56 | # PACK_PATCH_FILES="
57 | #
58 | # "
59 |
60 | # Specify addition argument to packchk
61 | # Default: empty
62 | #
63 | # PACKCHK_ARGS=()
64 |
65 | # Specify additional dependencies for packchk
66 | # Default: empty
67 | #
68 | # PACKCHK_DEPS="
69 | #
70 | # "
71 |
72 | # Optional: restrict fallback modes for changelog generation
73 | # Default: full
74 | # Values:
75 | # - full Tag annotations, release descriptions, or commit messages (in order)
76 | # - release Tag annotations, or release descriptions (in order)
77 | # - tag Tag annotations only
78 | #
79 | # PACK_CHANGELOG_MODE=""
80 |
81 | #
82 | # custom pre-processing steps
83 | #
84 | # usage: preprocess
85 | # The build folder
86 | #
87 | function preprocess() {
88 | # add custom steps here to be executed
89 | # before populating the pack build folder
90 | return 0
91 | }
92 |
93 | #
94 | # custom post-processing steps
95 | #
96 | # usage: postprocess
97 | # The build folder
98 | #
99 | function postprocess() {
100 | # add custom steps here to be executed
101 | # after populating the pack build folder
102 | # but before archiving the pack into output folder
103 | return 0
104 | }
105 |
106 | ############ DO NOT EDIT BELOW ###########
107 |
108 | function install_lib() {
109 | local URL="https://github.com/Open-CMSIS-Pack/gen-pack/archive/refs/tags/v$1.tar.gz"
110 | local STATUS=$(curl -sLI "${URL}" | grep "^HTTP" | tail -n 1 | cut -d' ' -f2 || echo "$((600+$?))")
111 | if [[ $STATUS -ge 400 ]]; then
112 | echo "Wrong/unavailable gen-pack lib version '$1'!" >&2
113 | echo "Check REQUIRED_GEN_PACK_LIB variable." >&2
114 | echo "For available versions see https://github.com/Open-CMSIS-Pack/gen-pack/tags." >&2
115 | exit 1
116 | fi
117 | echo "Downloading gen-pack lib version '$1' to '$2' ..."
118 | mkdir -p "$2"
119 | curl -L "${URL}" -s | tar -xzf - --strip-components 1 -C "$2" || exit 1
120 | }
121 |
122 | function load_lib() {
123 | if [[ -d ${GEN_PACK_LIB} ]]; then
124 | . "${GEN_PACK_LIB}/gen-pack"
125 | return 0
126 | fi
127 | local GLOBAL_LIB="/usr/local/share/gen-pack/${REQUIRED_GEN_PACK_LIB}"
128 | local USER_LIB="${HOME}/.local/share/gen-pack/${REQUIRED_GEN_PACK_LIB}"
129 | if [[ ! -d "${GLOBAL_LIB}" && ! -d "${USER_LIB}" ]]; then
130 | echo "Required gen_pack lib not found!" >&2
131 | install_lib "${REQUIRED_GEN_PACK_LIB}" "${USER_LIB}"
132 | fi
133 |
134 | if [[ -d "${GLOBAL_LIB}" ]]; then
135 | . "${GLOBAL_LIB}/gen-pack"
136 | elif [[ -d "${USER_LIB}" ]]; then
137 | . "${USER_LIB}/gen-pack"
138 | else
139 | echo "Required gen-pack lib is not installed!" >&2
140 | exit 1
141 | fi
142 | }
143 |
144 | load_lib
145 | gen_pack "${DEFAULT_ARGS[@]}" "$@"
146 |
147 | exit 0
--------------------------------------------------------------------------------
/inc/flash_blob.h:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | * Copyright 2022 KK (https://github.com/WALI-KANG) *
3 | * *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); *
5 | * you may not use this file except in compliance with the License. *
6 | * You may obtain a copy of the License at *
7 | * *
8 | * http://www.apache.org/licenses/LICENSE-2.0 *
9 | * *
10 | * Unless required by applicable law or agreed to in writing, software *
11 | * distributed under the License is distributed on an "AS IS" BASIS, *
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13 | * See the License for the specific language governing permissions and *
14 | * limitations under the License. *
15 | * *
16 | ****************************************************************************/
17 |
18 | #ifndef FLASH_BLOB_H
19 | #define FLASH_BLOB_H
20 | #include
21 | #include
22 | #include
23 | #include
24 |
25 | #if USE_PERF_COUNTER == ENABLED
26 | #include "perf_counter.h"
27 | #else
28 | #ifndef safe_atom_code
29 | #include "cmsis_compiler.h"
30 | #define safe_atom_code() \
31 | for( uint32_t SAFE_NAME(temp) = \
32 | ({uint32_t SAFE_NAME(temp2)=__get_PRIMASK(); \
33 | __disable_irq(); \
34 | SAFE_NAME(temp2);}),*SAFE_NAME(temp3) = NULL; \
35 | SAFE_NAME(temp3)++ == NULL; \
36 | __set_PRIMASK(SAFE_NAME(temp)))
37 |
38 |
39 | #endif
40 | #endif
41 |
42 | #define VERS 1 // Interface Version 1.01
43 |
44 | #define UNKNOWN 0 // Unknown
45 | #define ONCHIP 1 // On-chip Flash Memory
46 | #define EXT8BIT 2 // External Flash Device on 8-bit Bus
47 | #define EXT16BIT 3 // External Flash Device on 16-bit Bus
48 | #define EXT32BIT 4 // External Flash Device on 32-bit Bus
49 | #define EXTSPI 5 // External Flash Device on SPI
50 |
51 | #define SECTOR_NUM 16 // Max Number of Sector Items
52 |
53 | #define FLASH_DRV_VERS (0x0100+VERS)
54 |
55 | #define SECTOR_END 0xFFFFFFFF, 0xFFFFFFFF
56 |
57 | struct FlashSectors {
58 | unsigned long szSector; // Sector Size in Bytes
59 | unsigned long AddrSector; // Address of Sector
60 | };
61 |
62 | typedef struct FlashDevice {
63 | unsigned short Vers; // Version Number and Architecture
64 | char DevName[32];// Device Name and Description
65 | unsigned short DevType; // Device Type: ONCHIP, EXT8BIT, EXT16BIT, ...
66 | unsigned long DevAdr; // Default Device Start Address
67 | unsigned long szDev; // Total Size of Device
68 | unsigned long szPage; // Programming Page Size
69 | unsigned long Res; // Reserved for future Extension
70 | unsigned char valEmpty; // Content of Erased Memory
71 |
72 | unsigned long toProg; // Time Out of Program Page Function
73 | unsigned long toErase; // Time Out of Erase Sector Function
74 |
75 | struct FlashSectors sectors[SECTOR_NUM];
76 | } flash_dev_t;
77 |
78 | typedef struct {
79 | int32_t (*Init)(uint32_t adr, uint32_t clk, uint32_t fnc);
80 | int32_t (*UnInit)(uint32_t fnc);
81 | int32_t (*EraseChip)(void);
82 | int32_t (*EraseSector)(uint32_t adr);
83 | int32_t (*Program)(uint32_t adr, uint32_t sz, uint8_t* buf);
84 | int32_t (*Read)(uint32_t adr, uint32_t sz, uint8_t* buf);
85 | } flash_ops_t;
86 |
87 | typedef struct flash_blob_t flash_blob_t;
88 | typedef struct flash_blob_t{
89 | flash_dev_t const *ptFlashDev;
90 | flash_ops_t tFlashops;
91 | } flash_blob_t;
92 |
93 | extern void flash_dev_register(flash_blob_t *ptFlashDevice);
94 | extern bool target_flash_init(uint32_t addr);
95 | extern bool target_flash_uninit(uint32_t addr);
96 | extern int32_t target_flash_write(uint32_t addr, const uint8_t *buf, size_t size);
97 | extern int32_t target_flash_erase(uint32_t addr, size_t size);
98 | extern int32_t target_flash_read(uint32_t addr, uint8_t *buf, size_t size);
99 | #endif
100 |
--------------------------------------------------------------------------------
/port/STM32/STM32_FLASH_DRV.c:
--------------------------------------------------------------------------------
1 | #include "flash_blob.h"
2 | #include "STM32_FLASH_DEV.c"
3 | /*
4 | * Initialize Flash Programming Functions
5 | * Parameter: adr: Device Base Address
6 | * clk: Clock Frequency (Hz)
7 | * fnc: Function Code (1 - Erase, 2 - Program, 3 - Verify)
8 | * Return Value: 0 - OK, 1 - Failed
9 | */
10 |
11 | static int32_t Init(uint32_t adr, uint32_t clk, uint32_t fnc)
12 | {
13 | HAL_FLASH_Unlock();
14 | return (0);
15 | }
16 |
17 | /*
18 | * De-Initialize Flash Programming Functions
19 | * Parameter: fnc: Function Code (1 - Erase, 2 - Program, 3 - Verify)
20 | * Return Value: 0 - OK, 1 - Failed
21 | */
22 |
23 | static int32_t UnInit(uint32_t fnc)
24 | {
25 | HAL_FLASH_Lock();
26 | return (0);
27 | }
28 |
29 | /*
30 | * Erase complete Flash Memory
31 | * Return Value: 0 - OK, 1 - Failed
32 | */
33 |
34 | static int32_t EraseChip(void)
35 | {
36 | int32_t result = 0;
37 | uint32_t PAGEError = 0;
38 | FLASH_EraseInitTypeDef EraseInitStruct;
39 | EraseInitStruct.TypeErase = FLASH_TYPEERASE_MASSERASE;
40 | #if defined(FLASH_BANK2_END)
41 | EraseInitStruct.Banks = FLASH_BANK_2;
42 | if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK)
43 | {
44 | result = 1;
45 | }
46 | #endif
47 | EraseInitStruct.Banks = FLASH_BANK_1;
48 | if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK)
49 | {
50 | result = 1;
51 | }
52 | return result;
53 | }
54 |
55 | /*
56 | * Erase Sector in Flash Memory
57 | * Parameter: adr: Sector Address
58 | * Return Value: 0 - OK, 1 - Failed
59 | */
60 | static int32_t EraseSector(uint32_t adr)
61 | {
62 | int32_t result = 0;
63 | uint32_t PAGEError = 0;
64 |
65 | /*Variable used for Erase procedure*/
66 | FLASH_EraseInitTypeDef EraseInitStruct;
67 | #if defined(FLASH_BANK2_END)
68 | /* Fill EraseInit structure*/
69 | EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
70 | EraseInitStruct.PageAddress = adr;
71 | EraseInitStruct.NbPages = 1;
72 | if(adr > FLASH_BANK1_END){
73 | EraseInitStruct.Banks = FLASH_BANK_2;
74 | }else{
75 | EraseInitStruct.Banks = FLASH_BANK_1;
76 | }
77 |
78 | if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK)
79 | {
80 | result = 1;
81 | }
82 | #else
83 | EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
84 | EraseInitStruct.Sector = (adr - FLASH_BANK1_BASE) / FLASH_SECTOR_SIZE;;
85 | EraseInitStruct.NbSectors = 1;
86 | EraseInitStruct.Banks = FLASH_BANK_1;
87 | EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
88 | if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK)
89 | {
90 | result = 1;
91 | }
92 | #endif
93 | return result;
94 | }
95 |
96 | /*
97 | * Program Page in Flash Memory
98 | * Parameter: adr: Page Start Address
99 | * sz: Page Size
100 | * buf: Page Data
101 | * Return Value: 0 - OK, 1 - Failed
102 | */
103 | static int32_t ProgramPage(uint32_t addr, uint32_t sz, uint8_t* buf)
104 | {
105 | int32_t result = 0;
106 | uint32_t write_granularity = FLASH_NB_32BITWORD_IN_FLASHWORD * 4;
107 | uint32_t write_size = write_granularity;
108 | uint32_t end_addr = addr + sz - 1,write_addr;
109 | uint8_t write_buffer[32] = {0};
110 | write_addr = (uint32_t)buf;
111 | __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR);
112 | while (addr < end_addr) {
113 | if(end_addr - addr + 1 < write_granularity)
114 | {
115 | write_size = end_addr - addr + 1;
116 | for(size_t i = 0; i < write_size; i++)
117 | {
118 | write_buffer[i] = *((uint8_t *)(write_addr + i));
119 | }
120 | write_addr = (uint32_t)((uint32_t *)write_buffer);
121 | }
122 | if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, addr, write_addr) == HAL_OK) {
123 | for(uint8_t i = 0; i < write_size; i++)
124 | {
125 | if (*(uint8_t *)(addr + i) != *(uint8_t *)(write_addr + i))
126 | {
127 | result = 1;
128 | break;
129 | }
130 | }
131 | addr += write_granularity;
132 | write_addr += write_granularity;
133 | } else {
134 | result = 1;
135 | break;
136 | }
137 | }
138 | return result;
139 | }
140 |
141 | const flash_blob_t onchip_flash_device = {
142 | .tFlashops.Init = Init,
143 | .tFlashops.UnInit = UnInit,
144 | .tFlashops.EraseChip = EraseChip,
145 | .tFlashops.EraseSector = EraseSector,
146 | .tFlashops.Program = ProgramPage,
147 | .tFlashops.Read = NULL,
148 | .ptFlashDev = &FlashDevice,
149 | };
150 |
151 |
--------------------------------------------------------------------------------
/port/STM32/STM32_FLASH_DEV.c:
--------------------------------------------------------------------------------
1 | #include "flash_blob.h"
2 |
3 | #ifdef STM32F10x_16
4 | #include "stm32f1xx_hal.h"
5 | static struct FlashDevice const FlashDevice = {
6 | FLASH_DRV_VERS, // Driver Version, do not modify!
7 | "STM32F10x Low-density Flash", // Device Name (16kB)
8 | ONCHIP, // Device Type
9 | 0x08000000, // Device Start Address
10 | 0x00004000, // Device Size in Bytes (16kB)
11 | 1024, // Programming Page Size
12 | 0, // Reserved, must be 0
13 | 0xFF, // Initial Content of Erased Memory
14 | 100, // Program Page Timeout 100 mSec
15 | 500, // Erase Sector Timeout 500 mSec
16 |
17 | // Specify Size and Address of Sectors
18 | 0x0400, 0x000000, // Sector Size 1kB (128 Sectors)
19 | SECTOR_END
20 | };
21 | #endif
22 |
23 | #ifdef STM32F10x_128
24 | #include "stm32f1xx_hal.h"
25 | static struct FlashDevice const FlashDevice = {
26 | FLASH_DRV_VERS, // Driver Version, do not modify!
27 | "STM32F10x Med-density Flash", // Device Name (128kB/64kB/32kB)
28 | ONCHIP, // Device Type
29 | 0x08000000, // Device Start Address
30 | 0x00020000, // Device Size in Bytes (128kB)
31 | 1024, // Programming Page Size
32 | 0, // Reserved, must be 0
33 | 0xFF, // Initial Content of Erased Memory
34 | 100, // Program Page Timeout 100 mSec
35 | 500, // Erase Sector Timeout 500 mSec
36 |
37 | // Specify Size and Address of Sectors
38 | 0x0400, 0x000000, // Sector Size 1kB (128 Sectors)
39 | SECTOR_END
40 | };
41 | #endif
42 |
43 | #ifdef STM32F10x_512
44 | #include "stm32f1xx_hal.h"
45 | static struct FlashDevice const FlashDevice = {
46 | FLASH_DRV_VERS, // Driver Version, do not modify!
47 | "STM32F10x High-density Flash",// Device Name (512kB/384kB/256kB)
48 | ONCHIP, // Device Type
49 | 0x08000000, // Device Start Address
50 | 0x00080000, // Device Size in Bytes (512kB)
51 | 1024, // Programming Page Size
52 | 0, // Reserved, must be 0
53 | 0xFF, // Initial Content of Erased Memory
54 | 100, // Program Page Timeout 100 mSec
55 | 500, // Erase Sector Timeout 500 mSec
56 |
57 | // Specify Size and Address of Sectors
58 | 0x0800, 0x000000, // Sector Size 2kB (256 Sectors)
59 | SECTOR_END
60 | };
61 | #endif
62 |
63 | #ifdef STM32F10x_1024
64 | #include "stm32f1xx_hal.h"
65 | static struct FlashDevice const FlashDevice = {
66 | FLASH_DRV_VERS, // Driver Version, do not modify!
67 | "STM32F10x XL-density Flash",// Device Name (1024kB/768kB)
68 | ONCHIP, // Device Type
69 | 0x08000000, // Device Start Address
70 | 0x00100000, // Device Size in Bytes (1024kB)
71 | 1024, // Programming Page Size
72 | 0, // Reserved, must be 0
73 | 0xFF, // Initial Content of Erased Memory
74 | 100, // Program Page Timeout 100 mSec
75 | 500, // Erase Sector Timeout 500 mSec
76 |
77 | // Specify Size and Address of Sectors
78 | 0x0800, 0x000000, // Sector Size 2kB (512 Sectors)
79 | SECTOR_END
80 | };
81 | #endif
82 |
83 | #ifdef STM32F10x_CL
84 | #include "stm32f1xx_hal.h"
85 | static struct FlashDevice const FlashDevice = {
86 | FLASH_DRV_VERS, // Driver Version, do not modify!
87 | "STM32F10x Connectivity Line Flash",// Device Name (256kB/128kB/64kB)
88 | ONCHIP, // Device Type
89 | 0x08000000, // Device Start Address
90 | 0x00040000, // Device Size in Bytes (256kB)
91 | 1024, // Programming Page Size
92 | 0, // Reserved, must be 0
93 | 0xFF, // Initial Content of Erased Memory
94 | 100, // Program Page Timeout 100 mSec
95 | 500, // Erase Sector Timeout 500 mSec
96 |
97 | // Specify Size and Address of Sectors
98 | 0x0800, 0x000000, // Sector Size 2kB (128 Sectors)
99 | SECTOR_END
100 | };
101 | #endif
102 |
103 | #ifdef STM32H7x_2048
104 | #include "stm32h7xx_hal.h"
105 | static struct FlashDevice const FlashDevice = {
106 | FLASH_DRV_VERS, // Driver Version, do not modify!
107 | "STM32H7x_2048", // Device Name
108 | ONCHIP, // Device Type
109 | 0x08000000, // Device Start Address
110 | 0x00200000, // Device Size in Bytes (2048kB)
111 | 1024, // Programming Page Size
112 | 0, // Reserved, must be 0
113 | 0xFF, // Initial Content of Erased Memory
114 | 100, // Program Page Timeout 100 mSec
115 | 6000, // Erase Sector Timeout 6000 mSec
116 |
117 | // Specify Size and Address of Sectors
118 | 0x20000, 0x000000, // Sector Size 128kB (16 Sectors)
119 | SECTOR_END
120 | };
121 |
122 | #endif
--------------------------------------------------------------------------------
/src/flash_blob.c:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | * Copyright 2022 KK (https://github.com/WALI-KANG) *
3 | * *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); *
5 | * you may not use this file except in compliance with the License. *
6 | * You may obtain a copy of the License at *
7 | * *
8 | * http://www.apache.org/licenses/LICENSE-2.0 *
9 | * *
10 | * Unless required by applicable law or agreed to in writing, software *
11 | * distributed under the License is distributed on an "AS IS" BASIS, *
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13 | * See the License for the specific language governing permissions and *
14 | * limitations under the License. *
15 | * *
16 | ****************************************************************************/
17 | #include "flash_blob.h"
18 | #include "flash_blob_cfg.h"
19 | /* Array containing flash devices and their configurations */
20 | static const flash_blob_t * const flash_table[] = FLASH_DEV_TABLE;
21 |
22 | /* Length of the flash_table array */
23 | static const size_t flash_table_len = sizeof(flash_table) / sizeof(flash_table[0]);
24 |
25 | /*
26 | * Function: flash_dev_find
27 | * Description: Finds the flash device based on the specified address.
28 | * Parameters:
29 | * - addr: Flash memory address to find.
30 | * Returns: Pointer to the flash_blob_t structure if found, NULL otherwise.
31 | */
32 | static const flash_blob_t * flash_dev_find(uint32_t addr)
33 | {
34 | for (uint16_t i = 0; i < flash_table_len; i++) {
35 | if(addr >= flash_table[i]->ptFlashDev->DevAdr &&
36 | addr < flash_table[i]->ptFlashDev->DevAdr + flash_table[i]->ptFlashDev->szDev) {
37 | return flash_table[i];
38 | }
39 | }
40 |
41 | return NULL;
42 | }
43 | /*
44 | * Function: target_flash_init
45 | * Description: Initializes the flash memory based on the specified address.
46 | * Parameters:
47 | * - addr: Flash memory address to initialize.
48 | * Returns: True if initialization is successful, false otherwise.
49 | */
50 | bool target_flash_init(uint32_t addr)
51 | {
52 | if (addr % 4 != 0) {
53 | /*flash addr must be 4-byte alignment*/
54 | return false;
55 | }
56 |
57 | const flash_blob_t *ptFlashDevice = flash_dev_find(addr);
58 |
59 | if(ptFlashDevice != NULL) {
60 | ptFlashDevice->tFlashops.Init(addr, 0, 0);
61 | return true;
62 | }
63 |
64 | return false;
65 | }
66 | /*
67 | * Function: target_flash_uninit
68 | * Description: Uninitializes the flash memory based on the specified address.
69 | * Parameters:
70 | * - addr: Flash memory address to uninitialize.
71 | * Returns: True if uninitialization is successful, false otherwise.
72 | */
73 | bool target_flash_uninit(uint32_t addr)
74 | {
75 | const flash_blob_t *ptFlashDevice = flash_dev_find(addr);
76 |
77 | if(ptFlashDevice != NULL) {
78 | ptFlashDevice->tFlashops.UnInit(addr);
79 | return true;
80 | }
81 |
82 | return true;
83 | }
84 | /*
85 | * Function: target_flash_write
86 | * Description: Writes data to the flash memory.
87 | * Parameters:
88 | * - addr: Flash memory address to start writing.
89 | * - buf: Pointer to the data to be written.
90 | * - size: Number of bytes to write.
91 | * Returns: Number of bytes actually written.
92 | */
93 | int target_flash_write(uint32_t addr, const uint8_t *buf, size_t size)
94 | {
95 | const flash_blob_t *ptFlashDevice = flash_dev_find(addr);
96 |
97 | safe_atom_code(){
98 | if(ptFlashDevice != NULL) {
99 | if (addr % 4 != 0) {
100 | /*addr must be 4-byte alignment*/
101 | size = 0;
102 | continue;
103 | }
104 |
105 | if ((addr - ptFlashDevice->ptFlashDev->DevAdr + size) > ptFlashDevice->ptFlashDev->szDev) {
106 | /*write outrange flash size*/
107 | size = 0;
108 | continue;
109 | }
110 |
111 | if(ptFlashDevice->tFlashops.Program) {
112 | if( 0 != ptFlashDevice->tFlashops.Program(addr, size, (uint8_t *)buf)) {
113 | /*Programming Failed*/
114 | size = 0;
115 | continue;
116 | }
117 | } else {
118 | size = 0;
119 | continue;
120 | }
121 | }
122 | }
123 | return size;
124 | }
125 |
126 | /*
127 | * Function: target_flash_read
128 | * Description: Reads data from the flash memory.
129 | * Parameters:
130 | * - addr: Flash memory address to start reading.
131 | * - buf: Pointer to store the read data.
132 | * - size: Number of bytes to read.
133 | * Returns: Number of bytes actually read.
134 | */
135 | int target_flash_read(uint32_t addr, uint8_t *buf, size_t size)
136 | {
137 | const flash_blob_t *ptFlashDevice = flash_dev_find(addr);
138 |
139 | safe_atom_code(){
140 | if(ptFlashDevice != NULL) {
141 | if (addr % 4 != 0) {
142 | /*addr must be 4-byte alignment*/
143 | size = 0;
144 | continue;
145 | }
146 |
147 | if ((addr - ptFlashDevice->ptFlashDev->DevAdr + size) > ptFlashDevice->ptFlashDev->szDev) {
148 | /*read outrange flash size*/
149 | size = 0;
150 | continue;
151 | }
152 |
153 | if(ptFlashDevice->tFlashops.Read) {
154 | if( 0 != ptFlashDevice->tFlashops.Read(addr, size, (uint8_t *)buf)) {
155 | /*Read Failed*/
156 | size = 0;
157 | continue;
158 | }
159 | } else {
160 | for (uint16_t i = 0; i < size; i++, buf++, addr++) {
161 | *buf = *(uint8_t *) addr;
162 | }
163 | }
164 | }
165 | }
166 |
167 | return size;
168 | }
169 |
170 | /*
171 | * Function: target_flash_erase
172 | * Description: Erases a specified portion of the flash memory.
173 | * Parameters:
174 | * - addr: Flash memory address to start erasing.
175 | * - size: Number of bytes to erase.
176 | * Returns: Number of bytes actually erased.
177 | */
178 | int target_flash_erase(uint32_t addr, size_t size)
179 | {
180 | size_t wSector = 0;
181 | size_t wEraseSize = 0;
182 | const flash_blob_t *ptFlashDevice = flash_dev_find(addr);
183 | if(ptFlashDevice != NULL) {
184 | safe_atom_code(){
185 | if (size > ptFlashDevice->ptFlashDev->szDev) {
186 | /*erase outrange flash size */
187 | wEraseSize = 0;
188 | continue;
189 | }
190 |
191 | while(wEraseSize < size) {
192 | if(ptFlashDevice->tFlashops.EraseSector) {
193 | if(0 != ptFlashDevice->tFlashops.EraseSector(addr)) {
194 | /*erase Failed*/
195 | break;
196 | }
197 | } else {
198 | break;
199 | }
200 |
201 | for(wSector = 0; wSector < SECTOR_NUM; wSector++) {
202 | if(ptFlashDevice->ptFlashDev->sectors[wSector + 1].szSector == 0XFFFFFFFF )
203 | break;
204 |
205 | if(((addr - ptFlashDevice->ptFlashDev->DevAdr) < ptFlashDevice->ptFlashDev->sectors[wSector + 1].AddrSector) &&
206 | ((addr - ptFlashDevice->ptFlashDev->DevAdr) >= ptFlashDevice->ptFlashDev->sectors[wSector].AddrSector) )
207 | break;
208 | }
209 |
210 | addr += ptFlashDevice->ptFlashDev->sectors[wSector].szSector;
211 | wEraseSize += ptFlashDevice->ptFlashDev->sectors[wSector].szSector;
212 | }
213 | }
214 | return wEraseSize;
215 | }
216 |
217 | return 0;
218 | }
219 |
220 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/docs/readme.md:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | # 前言
4 | 在进行Flash操作时,一般我们需要设计一套Flash抽象层,至少要包括flash的init,read、write、erase这些操作。但每更换一个单片机或者flash器件就要额外去编写flash驱动去适配init,read、write、erase。尽管有会者不难的属性加持,但适配所有的单片机或者flash器件,工作量也可想而知。
5 |
6 | 本文为大家提供一个适配几乎任意单片机型号的flash驱动,之所以说是几乎,是因为我们这次要借东风,而这个东风就是Keil的FLM文件。
7 |
8 | 项目开源地址:[https://gitee.com/Aladdin-Wang/flash_blob](https://gitee.com/Aladdin-Wang/flash_blob)
9 |
10 | ---
11 |
12 | # 一、FLM文件是什么?
13 | 熟悉Keil的朋友们都知道,当我们要下载编译好的镜像到Flash时,首先要做的一步就是选择合适的Flash下载算法,而这个算法本身就是一个FLM文件:
14 | 
15 | 所谓Flash下载算法,是负责擦除,下载应用数据到flash的一个软件。而Keil往往会集成不少FLM文件以支持大多数的flash型号。
16 | 当然,这些算法也是根据不同型号的flash所编写的。只不过,前人们已经为我们种好了大树,我们可以直接在树下乘凉了。
17 |
18 | # 二、FLM文件结构
19 | Keil规定了FLM文件的构成,它是一成不变的,我们才可以放心的对文件本身进行解析,并为自己所用。
20 |
21 | 生成FLM文件的程序中,有两个非常重要的文件,分别是
22 | - FlashPrg.c中包含编程算法。
23 | - FlashDev.c中包含设备参数。
24 | ## 1.FlashPrg.c
25 | FlashPrg.c文件包含强制性flash编程函数Init、UnInit、EraseSector和ProgramPage。可选地,根据设备特性,可以实现函数EraseChip、BlankCheck和Verify 。
26 | | Function Name | Indication | Description |
27 | | ------------- | ---------- | ------------------------------------------------------------ |
28 | | BlankCheck | optional | Check and compare patterns. |
29 | | EraseChip | optional | Delete entire Flash memory content. |
30 | | EraseSector | mandatory | Delete Flash memory content of a specific sector. |
31 | | Init | mandatory | Initialize and prepare device for Flash programming. |
32 | | ProgramPage | mandatory | Write the application into the Flash memory. |
33 | | UnInit | mandatory | De-initialize the microcontroller after one of the Flash programming steps. |
34 | | Verify | optional | Compare Flash memory content with the program code. |
35 |
36 | 其中有4个是必须要有的,我们来逐一说明:
37 | 1. Init
38 | 函数Init为 Flash 编程初始化微控制器。每当尝试将程序下载到 Flash 时都会调用它。
39 | ```c
40 | int Init (unsigned long adr, unsigned long clk, unsigned long fnc);
41 | ```
42 |
43 |
44 | 参数adr指定设备的基址。
45 |
46 | 参数clk指定用于编程设备的时钟频率。
47 |
48 | 参数fnc是一个数字:
49 |
50 | 1 代表擦除。
51 | 2代表程序。
52 | 3代表验证。
53 |
54 | Code Example:
55 |
56 | ```c
57 | int Init (unsigned long adr, unsigned long clk, unsigned long fnc) {
58 |
59 | // Zero Wait State
60 | FLASH->ACR = 0x00000000;
61 |
62 | // Unlock Flash
63 | FLASH->KEYR = FLASH_KEY1;
64 | FLASH->KEYR = FLASH_KEY2;
65 |
66 | // Test if IWDG is running (IWDG in HW mode)
67 | if ((FLASH->OBR & 0x04) == 0x00) {
68 | // Set IWDG time out to ~32.768 second
69 | IWDG->KR = 0x5555; // Enable write access to IWDG_PR and IWDG_RLR
70 | IWDG->PR = 0x06; // Set prescaler to 256
71 | IWDG->RLR = 4095; // Set reload value to 4095
72 | }
73 |
74 | return (0);
75 | }
76 | ```
77 | 2. ProgramPage
78 | 函数ProgramPage用于将代码写入闪存。它被调用以将程序下载到 Flash。由于flash通常以块或页的形式组织,因此函数ProgramPage的参数不得跨越这些闪存页的对齐边界。页面大小在结构 FlashDevice 中指定,值为Program Page Size。
79 |
80 | ```c
81 | int ProgramPage ( unsigned long adr, unsigned long sz, unsigned char *buf);
82 | ```
83 |
84 | 参数adr指定要编程的页面的起始地址。它由主机编程系统与flash页面的起始地址对齐。
85 |
86 | 参数sz指定数据缓冲区中的数据大小。主机编程系统确保不跨越页面边界。
87 |
88 | 参数buf指向包含要编程的数据的数据缓冲区。
89 |
90 | Code Example:
91 |
92 | ```c
93 | int ProgramPage (unsigned long adr, unsigned long sz, unsigned char *buf) {
94 |
95 | sz = (sz + 1) & ~1; // Adjust size for Half Words
96 |
97 | while (sz) {
98 |
99 | FLASH->CR |= FLASH_PG; // Programming Enabled
100 |
101 | M16(adr) = *((unsigned short *)buf); // Program Half Word
102 | while (FLASH->SR & FLASH_BSY);
103 |
104 | FLASH->CR &= ~FLASH_PG; // Programming Disabled
105 |
106 | // Check for Errors
107 | if (FLASH->SR & (FLASH_PGERR | FLASH_WRPRTERR)) {
108 | FLASH->SR |= FLASH_PGERR | FLASH_WRPRTERR;
109 | return (1); // Failed
110 | }
111 |
112 | // Go to next Half Word
113 | adr += 2;
114 | buf += 2;
115 | sz -= 2;
116 | }
117 |
118 | return (0); // Done
119 | }
120 | ```
121 | 3. EraseSector
122 | 函数EraseSector删除从参数adr指定的地址开始的扇区内容。
123 |
124 | ```c
125 | int EraseSector (unsigned long adr);
126 | ```
127 |
128 | 参数adr扇区地址
129 |
130 | Code Example:
131 | ```c
132 | int EraseSector (unsigned long adr) {
133 |
134 | FLASH->CR |= FLASH_PER; // Page Erase Enabled
135 | FLASH->AR = adr; // Page Address
136 | FLASH->CR |= FLASH_STRT; // Start Erase
137 |
138 | while (FLASH->SR & FLASH_BSY) {
139 | IWDG->KR = 0xAAAA; // Reload IWDG
140 | }
141 |
142 | FLASH->CR &= ~FLASH_PER; // Page Erase Disabled
143 |
144 | return (0); // Done
145 | }
146 | ```
147 | 4. UnInit
148 | 函数UnInit取消初始化微控制器,并在擦除、编程或验证步骤结束时调用。
149 | ```c
150 | int UnInit (unsigned long fnc);
151 | ```
152 |
153 | Code Example
154 |
155 | ```c
156 | int UnInit (unsigned long fnc) {
157 |
158 | // Lock Flash
159 | FLASH->CR |= FLASH_LOCK;
160 |
161 | return (0);
162 | }
163 | ```
164 | ## 2.FlashPrg.c
165 | 文件FlashDev.c包含以下参数定义:
166 | 1. Flash编程功能。
167 | 2. FlashDevice结构:
168 | ```c
169 | struct FlashDevice const FlashDevice = {
170 | FLASH_DRV_VERS, // 驱动版本,请勿修改!
171 | "New Device 256kB Flash" , // 设备名称
172 | ONCHIP, // 设备类型
173 | 0x00000000, // 设备起始地址
174 | 0x00040000, // 以字节为单位的设备大小 (256kB)
175 | 1024, // 编程页面大小
176 | 0, // 保留,必须为0
177 | 0xFF, // 已擦除内存的初始内容
178 | 100, // 程序页面超时 100 毫秒
179 | 3000, // 擦除扇区超时 3000 毫秒
180 |
181 | // 指定扇区的大小和地址
182 | 0x002000, 0x000000, // 扇区大小 8kB(8 个扇区)
183 | 0x010000, 0x010000, // 扇区大小 64kB(2 个扇区)
184 | 0x002000, 0x030000, // 扇区大小 8kB(8 个扇区)
185 | SECTOR_END
186 | };
187 | ```
188 | Device Name通常显示在工具中,用于识别 Flash 算法。确保此名称反映设备名称。
189 | 编程页面大小指定使用函数ProgramPage进行编程 的块大小。对于块大小较小的设备,最好指定物理块大小的倍数,因为这可以减少与目标的通信开销。快速编程的最佳块大小为 1024 字节,但系统本身并不限制此大小值。
190 | # 三、解析FLM文件
191 | ## 1.解析flm文件
192 | 下面让我们解析一下现有的FLM文件,以STM32F4xx_1024.FLM为例:
193 | 将ARM:CMSIS Pack文件夹(通常在D:\Users\Administrator\AppData\Local\Arm\Packs\Keil\STM32F4xx_DFP\2.15.0\CMSIS\Flash)中的内容复制到一个新文件夹中。
194 |
195 | 打开命令行工具,输入arm-none-eabi-readelf -a STM32F4xx_1024.FLM:
196 |
197 | ```c
198 | $ arm-none-eabi-readelf -a STM32F4xx_1024.FLM
199 | ELF Header:
200 | Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
201 | Class: ELF32
202 | Data: 2's complement, little endian
203 | Version: 1 (current)
204 | OS/ABI: UNIX - System V
205 | ABI Version: 0
206 | Type: EXEC (Executable file)
207 | Machine: ARM
208 | Version: 0x1
209 | Entry point address: 0x0
210 | Start of program headers: 12172 (bytes into file)
211 | Start of section headers: 12236 (bytes into file)
212 | Flags: 0x5000000, Version5 EABI
213 | Size of this header: 52 (bytes)
214 | Size of program headers: 32 (bytes)
215 | Number of program headers: 2
216 | Size of section headers: 40 (bytes)
217 | Number of section headers: 16
218 | Section header string table index: 15
219 |
220 | Section Headers:
221 | [Nr] Name Type Addr Off Size ES Flg Lk Inf Al
222 | [ 0] NULL 00000000 000000 000000 00 0 0 0
223 | [ 1] PrgCode PROGBITS 00000000 000034 000144 00 AX 0 0 4
224 | [ 2] PrgData PROGBITS 00000144 000178 000004 00 WA 0 0 4
225 | [ 3] DevDscr PROGBITS 00000148 00017c 0010a0 00 A 0 0 4
226 | [ 4] .debug_abbrev PROGBITS 00000000 00121c 0005a4 00 0 0 1
227 | [ 5] .debug_frame PROGBITS 00000000 0017c0 000104 00 0 0 1
228 | [ 6] .debug_info PROGBITS 00000000 0018c4 00064c 00 0 0 1
229 | [ 7] .debug_line PROGBITS 00000000 001f10 000218 00 0 0 1
230 | [ 8] .debug_loc PROGBITS 00000000 002128 0001b8 00 0 0 1
231 | [ 9] .debug_macinfo PROGBITS 00000000 0022e0 000614 00 0 0 1
232 | [10] .debug_pubnames PROGBITS 00000000 0028f4 000096 00 0 0 1
233 | [11] .symtab SYMTAB 00000000 00298c 000110 10 12 9 4
234 | [12] .strtab STRTAB 00000000 002a9c 000100 00 0 0 1
235 | [13] .note NOTE 00000000 002b9c 00001c 00 0 0 4
236 | [14] .comment PROGBITS 00000000 002bb8 000334 00 0 0 1
237 | [15] .shstrtab STRTAB 00000000 002eec 0000a0 00 0 0 1
238 | Key to Flags:
239 | W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
240 | L (link order), O (extra OS processing required), G (group), T (TLS),
241 | C (compressed), x (unknown), o (OS specific), E (exclude),
242 | y (purecode), p (processor specific)
243 |
244 | There are no section groups in this file.
245 |
246 | Program Headers:
247 | Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
248 | LOAD 0x000034 0x00000000 0x00000000 0x00148 0x00148 RWE 0x4
249 | LOAD 0x00017c 0x00000148 0x00000148 0x010a0 0x010a0 R 0x4
250 |
251 | Section to Segment mapping:
252 | Segment Sections...
253 | 00 PrgCode PrgData
254 | 01 DevDscr
255 |
256 | There is no dynamic section in this file.
257 |
258 | There are no relocations in this file.
259 |
260 | There are no unwind sections in this file.
261 |
262 | Symbol table '.symtab' contains 17 entries:
263 | Num: Value Size Type Bind Vis Ndx Name
264 | 0: 00000000 0 NOTYPE LOCAL DEFAULT UND
265 | 1: 00000000 0 NOTYPE LOCAL DEFAULT 1 $t
266 | 2: 00000122 0 NOTYPE LOCAL DEFAULT 1 $d
267 | 3: 00000144 0 NOTYPE LOCAL DEFAULT 2 $d.realdata
268 | 4: 00000148 0 NOTYPE LOCAL DEFAULT 3 $d.realdata
269 | 5: 00000000 0 FILE LOCAL DEFAULT ABS FlashPrg.c
270 | 6: 00000000 0 SECTION LOCAL DEFAULT 1 .text
271 | 7: 00000000 0 FILE LOCAL DEFAULT ABS FlashDev.c
272 | 8: 00000148 4256 SECTION LOCAL DEFAULT 3 .constdata
273 | 9: 00000000 0 NOTYPE GLOBAL HIDDEN ABS BuildAttributes$$THM_ISAv
274 | 10: 00000001 28 FUNC GLOBAL HIDDEN 1 GetSecNum
275 | 11: 0000001d 46 FUNC GLOBAL HIDDEN 1 Init
276 | 12: 0000004b 14 FUNC GLOBAL HIDDEN 1 UnInit
277 | 13: 00000059 44 FUNC GLOBAL HIDDEN 1 EraseChip
278 | 14: 00000085 76 FUNC GLOBAL HIDDEN 1 EraseSector
279 | 15: 000000d1 82 FUNC GLOBAL HIDDEN 1 ProgramPage
280 | 16: 00000148 4256 OBJECT GLOBAL HIDDEN 3 FlashDevice
281 |
282 | No version information found in this file.
283 |
284 | Displaying notes found at file offset 0x00002b9c with length 0x0000001c:
285 | Owner Data size Description
286 | ARM 0x0000000c Unknown note type: (0x40000000)
287 | ```
288 | 通过Symbol table信息我们可以找到Init、UnInit、EraseSector和ProgramPage函数所在的位置。
289 |
290 | 我们还需要根据Section Headers所描述的位置提取出Prgcode(代码),PrgData(数据),DevDscr(设备描述)的信息。
291 |
292 | 在命令行中输入arm-none-eabi-objdum -s -d STM32F4xx_1024.FLM:-s参数可以将所有段的内容一十六进制方式打印出来,-d参数可以将所有包含指令的段反汇编。
293 |
294 | ```c
295 | $ arm-none-eabi-objdump -s -d STM32F4xx_1024.FLM
296 |
297 | STM32F4xx_1024.FLM: file format elf32-littlearm
298 |
299 | Contents of section PrgCode:
300 | 0000 0003000e 202802d3 4009001d 70471028 .... (..@...pG.(
301 | 0010 02d30009 c01c7047 80087047 42484149 ......pG..pGBHAI
302 | 0020 41604249 41600021 0160c168 f0221143 A`BIA`.!.`.h.".C
303 | 0030 c1604069 800606d4 3e483d49 01600621 .`@i....>H=I.`.!
304 | 0040 41603d49 81600020 70473748 01694205 A`=I.`. pG7H.iB.
305 | 0050 11430161 00207047 10b53348 01690424 .C.a. pG..3H.i.$
306 | 0060 21430161 0169a203 11430161 3349314a !C.a.i...C.a3I1J
307 | 0070 00e01160 c368db03 fbd40169 a1430161 ...`.h.....i.C.a
308 | 0080 002010bd 30b5fff7 bbff2749 ca68f023 . ..0.....'I.h.#
309 | 0090 1a43ca60 02240c61 0a690007 400e0243 .C.`.$.a.i..@..C
310 | 00a0 0a610869 e2031043 08612448 214a00e0 .a.i...C.a$H!J..
311 | 00b0 1060cd68 ed03fbd4 0869a043 0861c868 .`.h.....i.C.a.h
312 | 00c0 0006000f 03d0c868 1843c860 012030bd .......h.C.`. 0.
313 | 00d0 70b5154d c91c8908 eb688900 f0263343 p..M.....h...&3C
314 | 00e0 eb600023 2b61164b 17e02c69 1c432c61 .`.#+a.K..,i.C,a
315 | 00f0 14680460 ec68e403 fcd42c69 64086400 .h.`.h....,id.d.
316 | 0100 2c61ec68 2406240f 04d0e868 3043e860 ,a.h$.$....h0C.`
317 | 0110 012070bd 001d121d 091f0029 e5d10020 . p........)...
318 | 0120 70bd0000 23016745 003c0240 ab89efcd p...#.gE.<.@....
319 | 0130 55550000 00300040 ff0f0000 aaaa0000 UU...0.@........
320 | 0140 01020000 ....
321 | Contents of section PrgData:
322 | 0144 00000000 ....
323 | Contents of section DevDscr:
324 | 0148 01015354 4d333246 34787820 466c6173 ..STM32F4xx Flas
325 | 0158 68000000 00000000 00000000 00000000 h...............
326 | 0168 00000000 00000000 00000000 00000000 ................
327 | 0178 00000000 00000000 00000000 00000000 ................
328 | 0188 00000000 00000000 00000000 00000000 ................
329 | 0198 00000000 00000000 00000000 00000000 ................
330 | 01a8 00000000 00000000 00000000 00000000 ................
331 | 01b8 00000000 00000000 00000000 00000000 ................
332 | 01c8 00000100 00000008 00001000 00040000 ................
333 | 01d8 00000000 ff000000 64000000 70170000 ........d...p...
334 | 01e8 00400000 00000000 00000100 00000100 .@..............
335 | 01f8 00000200 00000200 ffffffff ffffffff ................
336 | ```
337 | 我们所需要的正是以上信息,接下来的任务只需要写一个上位机,将以上文件提取出来即可,这个工具我已经写好,如图:
338 | 
339 |
340 | 选择STM32F4xx_1024.FLM,生成STM32F4xx_1024.FLM.c文件,然后直接添加到我们的工程中即可,生成的代码如下:
341 |
342 | ```c
343 | #include "flash_blob.h"
344 |
345 | #define OPS_OFFSET ((uint32_t)&flash_code)
346 |
347 | #define DEV_OFFSET ((uint32_t)&flash_dev)
348 |
349 | #define RAM_OFFSET ((uint32_t)&rw_data)
350 |
351 | static const uint32_t flash_code[] =
352 | {
353 | 0X0E000300,0XD3022820,0X1D000940,0X28104770,0X0900D302,0X47701CC0,0X47700880,0X49414842,
354 | 0X49426041,0X21036041,0X68C16001,0X431122F0,0X694060C1,0XD4060680,0X493D483E,0X21066001,
355 | 0X493D6041,0X20006081,0X48374770,0X05426901,0X61014311,0X47702000,0X4833B510,0X24046901,
356 | 0X61014321,0X03A26901,0X61014311,0X4A314933,0X6011E000,0X03DB68C3,0X6901D4FB,0X610143A1,
357 | 0XBD102000,0XF7FFB530,0X4927FFBB,0X23F068CA,0X60CA431A,0X610C2402,0X0700690A,0X43020E40,
358 | 0X6908610A,0X431003E2,0X48246108,0XE0004A21,0X68CD6010,0XD4FB03ED,0X43A06908,0X68C86108,
359 | 0X0F000600,0X68C8D003,0X60C84318,0XBD302001,0X4D15B570,0X08891CC9,0X008968EB,0X433326F0,
360 | 0X230060EB,0X4B16612B,0X692CE017,0X612C431C,0X60046814,0X03E468EC,0X692CD4FC,0X00640864,
361 | 0X68EC612C,0X0F240624,0X68E8D004,0X60E84330,0XBD702001,0X1D121D00,0X29001F09,0X2000D1E5,
362 | 0X0000BD70,0X45670123,0X40023C00,0XCDEF89AB,0X00005555,0X40003000,0X00000FFF,0X0000AAAA,
363 | 0X00000201,0X00000000,
364 | };
365 |
366 | static const uint32_t flash_dev[] =
367 | {
368 | 0X54530101,0X4632334D,0X20787834,0X73616C46,0X00000068,0X00000000,0X00000000,0X00000000,
369 | 0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
370 | 0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
371 | 0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
372 | 0X00010000,0X08000000,0X00100000,0X00000400,0X00000000,0X000000FF,0X00000064,0X00001770,
373 | 0X00004000,0X00000000,0X00010000,0X00010000,0X00020000,0X00020000,0XFFFFFFFF,0XFFFFFFFF,
374 | };
375 |
376 | static uint32_t rw_data[] =
377 | {
378 | 0X00000000,
379 | };
380 |
381 | static flash_blob_device_t flash_device =
382 | {
383 | (void*)(OPS_OFFSET + 0X001D), // Init
384 | (void*)(OPS_OFFSET + 0X004B), // UnInit
385 | (void*)(OPS_OFFSET + 0X0059), // EraseChip
386 | (void*)(OPS_OFFSET + 0X0085), // EraseSector
387 | (void*)(OPS_OFFSET + 0X00D1), // ProgramPage
388 | (void*)(DEV_OFFSET),
389 | (void*)(RAM_OFFSET),
390 | };
391 | static int flash_blob_device_register(void)
392 | {
393 | flash_dev_register(&flash_device);
394 | return 0 ;
395 | }
396 | INIT_BOARD_EXPORT(flash_blob_device_register);
397 |
398 | ```
399 |
400 | # 四、设计flash驱动抽象层
401 | 接下来,为了方便后续使用,需要设计一个flash驱动抽象层,代码如下:
402 | flash_blob.h
403 | ```c
404 | #ifndef FLASH_BLOB_H
405 | #define FLASH_BLOB_H
406 | #include "rtthread.h"
407 | #include
408 | #include
409 | #include
410 |
411 | #define VERS 1 // Interface Version 1.01
412 |
413 | #define UNKNOWN 0 // Unknown
414 | #define ONCHIP 1 // On-chip Flash Memory
415 | #define EXT8BIT 2 // External Flash Device on 8-bit Bus
416 | #define EXT16BIT 3 // External Flash Device on 16-bit Bus
417 | #define EXT32BIT 4 // External Flash Device on 32-bit Bus
418 | #define EXTSPI 5 // External Flash Device on SPI
419 |
420 | #define SECTOR_NUM 16 // Max Number of Sector Items
421 |
422 | struct FlashSectors {
423 | unsigned long szSector; // Sector Size in Bytes
424 | unsigned long AddrSector; // Address of Sector
425 | };
426 |
427 | typedef struct FlashDevice {
428 | unsigned short Vers; // Version Number and Architecture
429 | char DevName[128]; // Device Name and Description
430 | unsigned short DevType; // Device Type: ONCHIP, EXT8BIT, EXT16BIT, ...
431 | unsigned long DevAdr; // Default Device Start Address
432 | unsigned long szDev; // Total Size of Device
433 | unsigned long szPage; // Programming Page Size
434 | unsigned long Res; // Reserved for future Extension
435 | unsigned char valEmpty; // Content of Erased Memory
436 |
437 | unsigned long toProg; // Time Out of Program Page Function
438 | unsigned long toErase; // Time Out of Erase Sector Function
439 |
440 | struct FlashSectors sectors[SECTOR_NUM];
441 | }flash_dev_t;
442 |
443 | typedef struct {
444 | int (*Init)(uint32_t adr, uint32_t clk, uint32_t fnc);
445 | int (*UnInit)(uint32_t fnc);
446 | int (*EraseChip)(void);
447 | int (*EraseSector)(uint32_t adr);
448 | int (*ProgramPage)(uint32_t adr, uint32_t sz, uint8_t* buf);
449 | }flash_ops_t;
450 |
451 | typedef struct
452 | {
453 | flash_ops_t tFlashops;
454 | flash_dev_t *ptFlashDev;
455 | int *pPrgData;
456 | rt_slist_t slist;
457 | }flash_blob_t;
458 |
459 | extern void flash_dev_register(flash_blob_t *ptFlashDevice);
460 | extern bool target_flash_init(uint32_t flash_start, int32_t size);
461 | extern bool target_flash_uninit(uint32_t flash_start);
462 | extern int32_t target_flash_write(uint32_t addr, const uint8_t *buf, int32_t size);
463 | extern int32_t target_flash_erase(uint32_t addr, int32_t size);
464 | extern int32_t target_flash_read(uint32_t addr, const uint8_t *buf, int32_t size);
465 | #endif
466 |
467 | ```
468 | flash_blob.c
469 |
470 | ```c
471 | #include "flash_blob.h"
472 | #include "stdio.h"
473 | #include "stdlib.h"
474 | #include "string.h"
475 |
476 | static bool s_bIsInit = false;
477 | static rt_slist_t _slist_head = RT_SLIST_OBJECT_INIT(_slist_head);
478 | register int *pPrgDataBase __asm("r9");
479 |
480 | void flash_dev_register(flash_blob_t *ptFlashDevice)
481 | {
482 | rt_slist_init(&(ptFlashDevice->slist));
483 | rt_slist_append(&_slist_head, &(ptFlashDevice->slist));
484 | }
485 |
486 | static flash_blob_t * flash_dev_find(uint32_t flash_start)
487 | {
488 | rt_slist_t *node;
489 | rt_slist_for_each(node, &_slist_head) {
490 | flash_blob_t *ptFlashDevice = rt_slist_entry(node, flash_blob_t, slist);
491 |
492 | if(flash_start >= ptFlashDevice->ptFlashDev->DevAdr &&
493 | flash_start < ptFlashDevice->ptFlashDev->DevAdr + ptFlashDevice->ptFlashDev->szDev) {
494 | return ptFlashDevice;
495 | }
496 | }
497 | return NULL;
498 | }
499 |
500 | bool target_flash_init(uint32_t flash_start, int32_t size)
501 | {
502 | if (flash_start % 4 != 0) {
503 | LOG_E("flash addr must be 4-byte alignment");
504 | return NULL;
505 | }
506 |
507 | flash_blob_t *ptFlashDevice = flash_dev_find(flash_start);
508 |
509 | if(ptFlashDevice != NULL) {
510 | pPrgDataBase = ptFlashDevice->pPrgData;
511 | ptFlashDevice->tFlashops.Init(flash_start, 0, 0);
512 | return true;
513 | }
514 |
515 | return false;
516 | }
517 |
518 | bool target_flash_uninit(uint32_t flash_start)
519 | {
520 | flash_blob_t *ptFlashDevice = flash_dev_find(flash_start);
521 |
522 | if(ptFlashDevice != NULL) {
523 | pPrgDataBase = ptFlashDevice->pPrgData;
524 | ptFlashDevice->tFlashops.UnInit(flash_start);
525 | return true;
526 | }
527 |
528 | return true;
529 | }
530 |
531 | int target_flash_write(uint32_t addr, const uint8_t *buf, int32_t size)
532 | {
533 | flash_blob_t *ptFlashDevice = flash_dev_find(addr);
534 |
535 | if(ptFlashDevice != NULL) {
536 | pPrgDataBase = ptFlashDevice->pPrgData;
537 |
538 | while(size > 0) {
539 | uint32_t write_size = size > ptFlashDevice->ptFlashDev->szPage ? ptFlashDevice->ptFlashDev->szPage : size;
540 |
541 | if( 0 != ptFlashDevice->tFlashops.ProgramPage(addr, write_size, (uint8_t *)buf)) {
542 | LOG_E("Programming Failed");
543 | return -1;
544 | }
545 |
546 | addr += write_size;
547 | buf += write_size;
548 | size -= write_size;
549 | }
550 |
551 | return size;
552 | }
553 |
554 | return -1;
555 | }
556 |
557 | int32_t target_flash_read(uint32_t addr, const uint8_t *buf, int32_t size)
558 | {
559 | flash_blob_t *ptFlashDevice;
560 | pPrgDataBase = ptFlashDevice->pPrgData;
561 | return size;
562 | }
563 |
564 | int32_t target_flash_erase(uint32_t addr, int32_t size)
565 | {
566 | int32_t wSector, wRemainLen;
567 | flash_blob_t *ptFlashDevice = flash_dev_find(addr);
568 |
569 | if(ptFlashDevice != NULL) {
570 | if (size > ptFlashDevice->ptFlashDev->szDev) {
571 | LOG_E("erase outrange flash size! addr is (0x%p)\n", (void *)(addr + size));
572 | return -1;
573 | }
574 |
575 | pPrgDataBase = ptFlashDevice->pPrgData;
576 | wRemainLen = size;
577 | while(wRemainLen > 0) {
578 | if(0 != ptFlashDevice->tFlashops.EraseSector(addr)) {
579 | LOG_E("erase Failed! addr is (0x%p)\n", (void *)addr);
580 | return -1;
581 | }
582 |
583 | for(wSector = 0; wSector < SECTOR_NUM; wSector++) {
584 | if(ptFlashDevice->ptFlashDev->sectors[wSector + 1].szSector == 0XFFFFFFFF )
585 | break;
586 |
587 | if(((addr - ptFlashDevice->ptFlashDev->DevAdr) < ptFlashDevice->ptFlashDev->sectors[wSector + 1].AddrSector) &&
588 | ((addr - ptFlashDevice->ptFlashDev->DevAdr) >= ptFlashDevice->ptFlashDev->sectors[wSector].AddrSector) )
589 | break;
590 | }
591 |
592 | addr += ptFlashDevice->ptFlashDev->sectors[wSector].szSector;
593 | wRemainLen -= ptFlashDevice->ptFlashDev->sectors[wSector].szSector;
594 | }
595 |
596 | return size;
597 | }
598 |
599 | return -1;
600 | }
601 |
602 | int32_t target_flash_verify (uint32_t addr, uint8_t *buf, int32_t size)
603 | {
604 |
605 | return size;
606 | }
607 | ```
608 |
609 | # 五、快速使用
610 | 本项目借用了rtthread的自动初始化机制和链表,所以最快的使用方式是直接作为rtthread的软件包使用,使用方法如下:
611 |
612 | 1.在rtthread软件包中找到flash_blob,然后添加进工程。
613 | 2. 通过tools文件下的工具,生成对应的xxx.FLM.c文件,将xxx.FLM.c添加进工程,如果有多个flash器件,可以连续添加。
614 | 注意:多个设备的话每个flash的FlashDevice 的设备起始地址不可重叠,flash抽象层根据地址,自动选择相应的驱动。
615 | 3.由于flash驱动需要占用“r9”寄存器,所以需要在编译选项中添加`-ffixed-r9`
616 |
617 | 
618 |
619 | 以上步骤完成后,就可以快速使用了,例如将YMODEM接收到的数据,写到flash中,代码如下:
620 |
621 |
622 | ```c
623 | uint8_t *ymodem_call_back_receive(uint8_t *pchBuffer, uint16_t hwSize)
624 | {
625 | static char *s_pchFileName = NULL, *s_pchFileSize = NULL;
626 | static uint32_t s_wFileSize = 0, s_wRemainLen = 0, s_wOffSet = 0;
627 |
628 | static enum {
629 | START = 0,
630 | RECEIVE,
631 | END,
632 | } s_tState = {START};
633 |
634 | switch(s_tState) {
635 | case START:
636 | s_wOffSet = 0;
637 | s_pchFileName = (char *)&pchBuffer[0];
638 | s_pchFileSize = (char *)&pchBuffer[strlen(s_pchFileName) + 1];
639 | s_wFileSize = atol(s_pchFileSize);
640 |
641 | LOG_D("Ymodem file_name:%s", s_pchFileName);
642 | LOG_D("Ymodem file_size:%d", s_wFileSize);
643 |
644 | if(target_flash_init(APP_PART_ADDR, s_wFileSize) == false) {
645 | LOG_E("target flash uninit.");
646 | return NULL;
647 | }
648 |
649 | if(target_flash_erase(APP_PART_ADDR, s_wFileSize) < 0) {
650 | LOG_E("target flash erase error.");
651 | return NULL;
652 | }
653 |
654 | s_tState = RECEIVE;
655 | break;
656 |
657 | case RECEIVE:
658 | s_wRemainLen = s_wFileSize - s_wOffSet;
659 |
660 | if(hwSize > s_wRemainLen) {
661 | hwSize = s_wRemainLen;
662 | s_tState = END;
663 | }
664 |
665 | if(target_flash_write(APP_PART_ADDR + s_wOffSet, pchBuffer, hwSize) < 0) {
666 | LOG_E("target flash write data error.");
667 | return NULL;
668 | }
669 | s_wOffSet += hwSize;
670 |
671 | break;
672 |
673 | case END:
674 | target_flash_uninit(APP_PART_ADDR);
675 | s_tState = START;
676 | break;
677 | }
678 |
679 | return s_chBuffer;
680 | }
681 | ```
682 |
683 |
--------------------------------------------------------------------------------