diff --git a/app/code_page/bsp_interface.py b/app/code_page/bsp_interface.py index f1d5de0..0a12798 100644 --- a/app/code_page/bsp_interface.py +++ b/app/code_page/bsp_interface.py @@ -1376,7 +1376,225 @@ class bsp_pwm(QWidget): if name_widget: name_widget.setText(saved_config['custom_name']) -# 更新get_bsp_page函数以包含PWM + +class bsp_flash(QWidget): + """Flash BSP配置界面 - 自动识别MCU型号并生成对应的Flash配置""" + def __init__(self, project_path): + super().__init__() + self.project_path = project_path + self.mcu_name = None + self.flash_config = None + # 加载描述 + describe_path = os.path.join(CodeGenerator.get_assets_dir("User_code/bsp"), "describe.csv") + self.descriptions = CodeGenerator.load_descriptions(describe_path) + self._detect_mcu() + self._init_ui() + self._load_config() + + def _detect_mcu(self): + """自动检测MCU型号并获取Flash配置""" + ioc_files = [f for f in os.listdir(self.project_path) if f.endswith('.ioc')] + if ioc_files: + ioc_path = os.path.join(self.project_path, ioc_files[0]) + self.mcu_name = analyzing_ioc.get_mcu_name_from_ioc(ioc_path) + if self.mcu_name: + self.flash_config = analyzing_ioc.get_flash_config_from_mcu(self.mcu_name) + + def _init_ui(self): + layout = QVBoxLayout(self) + + # 顶部布局 + top_layout = QHBoxLayout() + top_layout.setAlignment(Qt.AlignVCenter) + + self.generate_checkbox = CheckBox("生成 Flash 代码") + self.generate_checkbox.stateChanged.connect(self._on_generate_changed) + top_layout.addWidget(self.generate_checkbox, alignment=Qt.AlignLeft) + + top_layout.addStretch() + + title = SubtitleLabel("Flash 配置 ") + title.setAlignment(Qt.AlignHCenter) + top_layout.addWidget(title, alignment=Qt.AlignHCenter) + + top_layout.addStretch() + + layout.addLayout(top_layout) + + desc = self.descriptions.get("flash", "自动根据MCU型号配置Flash扇区") + if desc: + desc_label = BodyLabel(desc) + desc_label.setWordWrap(True) + layout.addWidget(desc_label) + + # 内容区域 + self.content_widget = QWidget() + content_layout = QVBoxLayout(self.content_widget) + + if not self.flash_config: + no_config_label = BodyLabel("❌ 无法识别MCU型号或不支持的MCU") + content_layout.addWidget(no_config_label) + else: + # 显示检测到的MCU信息 + mcu_info = BodyLabel(f"✅ 检测到MCU: {self.mcu_name}") + content_layout.addWidget(mcu_info) + + flash_size = (self.flash_config['end_address'] - 0x08000000) // 1024 + flash_type = self.flash_config.get('type', 'sector') + + if flash_type == 'page': + # F1系列 - Page模式 + page_size = self.flash_config.get('page_size', 1) + flash_info = BodyLabel(f"Flash容量: {flash_size} KB ({len(self.flash_config['sectors'])} 个页,每页 {page_size}KB)") + content_layout.addWidget(flash_info) + type_info = BodyLabel(f"📄 Page模式 (F1系列)") + content_layout.addWidget(type_info) + else: + # F4/H7系列 - Sector模式 + flash_info = BodyLabel(f"Flash容量: {flash_size} KB ({len(self.flash_config['sectors'])} 个扇区)") + content_layout.addWidget(flash_info) + + if self.flash_config['dual_bank']: + max_sector = len(self.flash_config['sectors']) - 1 + bank_info = BodyLabel(f"⚠️ 双Bank Flash (Sector 0-{max_sector})") + else: + max_sector = len(self.flash_config['sectors']) - 1 + bank_info = BodyLabel(f"单Bank Flash (Sector 0-{max_sector})") + content_layout.addWidget(bank_info) + + layout.addWidget(self.content_widget) + self.content_widget.setEnabled(False) + + def _on_generate_changed(self, state): + self.content_widget.setEnabled(state == 2) + + def is_need_generate(self): + return self.generate_checkbox.isChecked() and self.flash_config is not None + + def _generate_bsp_code_internal(self): + if not self.is_need_generate(): + return False + + if not self.flash_config: + return False + + # 生成头文件 + if not self._generate_header_file(): + return False + + # 生成源文件 + if not self._generate_source_file(): + return False + + self._save_config() + return True + + def _generate_header_file(self): + """生成flash.h""" + periph_folder = "flash" + template_base_dir = CodeGenerator.get_assets_dir("User_code/bsp") + template_path = os.path.join(template_base_dir, periph_folder, "flash.h") + + if not os.path.exists(template_path): + return False + + template_content = CodeGenerator.load_template(template_path) + if not template_content: + return False + + # 生成Sector/Page定义 + flash_type = self.flash_config.get('type', 'sector') + sector_lines = [] + + for item in self.flash_config['sectors']: + addr = item['address'] + size = item['size'] + item_id = item['id'] + + if flash_type == 'page': + # F1系列 - Page模式 + sector_lines.append( + f"#define ADDR_FLASH_PAGE_{item_id} ((uint32_t)0x{addr:08X})" + ) + sector_lines.append( + f"/* Base address of Page {item_id}, {size} Kbytes */" + ) + else: + # F4/H7系列 - Sector模式 + sector_lines.append( + f"#define ADDR_FLASH_SECTOR_{item_id} ((uint32_t)0x{addr:08X})" + ) + sector_lines.append( + f"/* Base address of Sector {item_id}, {size} Kbytes */" + ) + + content = CodeGenerator.replace_auto_generated( + template_content, "AUTO GENERATED FLASH_SECTORS", "\n".join(sector_lines) + ) + + # 生成结束地址 + end_addr = self.flash_config['end_address'] + end_line = f"#define ADDR_FLASH_END ((uint32_t)0x{end_addr:08X}) /* End address for flash */" + content = CodeGenerator.replace_auto_generated( + content, "AUTO GENERATED FLASH_END_ADDRESS", end_line + ) + + output_path = os.path.join(self.project_path, "User/bsp/flash.h") + CodeGenerator.save_with_preserve(output_path, content) + return True + + def _generate_source_file(self): + """生成flash.c""" + periph_folder = "flash" + template_base_dir = CodeGenerator.get_assets_dir("User_code/bsp") + template_path = os.path.join(template_base_dir, periph_folder, "flash.c") + + if not os.path.exists(template_path): + return False + + template_content = CodeGenerator.load_template(template_path) + if not template_content: + return False + + # 生成最大Sector数定义 + max_sector = len(self.flash_config['sectors']) - 1 + max_sector_line = f"#define BSP_FLASH_MAX_SECTOR {max_sector}" + content = CodeGenerator.replace_auto_generated( + template_content, "AUTO GENERATED FLASH_MAX_SECTOR", max_sector_line + ) + + # 生成擦除检查代码 + erase_check = f" if (sector > 0 && sector <= {max_sector}) {{" + content = CodeGenerator.replace_auto_generated( + content, "AUTO GENERATED FLASH_ERASE_CHECK", erase_check + ) + + output_path = os.path.join(self.project_path, "User/bsp/flash.c") + CodeGenerator.save_with_preserve(output_path, content) + return True + + def _save_config(self): + """保存配置""" + config_path = os.path.join(self.project_path, "User/bsp/bsp_config.yaml") + config_data = CodeGenerator.load_config(config_path) + config_data['flash'] = { + 'enabled': True, + 'mcu_name': self.mcu_name, + 'dual_bank': self.flash_config['dual_bank'], + 'sectors': len(self.flash_config['sectors']) + } + CodeGenerator.save_config(config_data, config_path) + + def _load_config(self): + """加载配置""" + config_path = os.path.join(self.project_path, "User/bsp/bsp_config.yaml") + config_data = CodeGenerator.load_config(config_path) + conf = config_data.get('flash', {}) + if conf.get('enabled', False): + self.generate_checkbox.setChecked(True) + + +# 更新get_bsp_page函数以包含PWM和Flash def get_bsp_page(peripheral_name, project_path): """根据外设名返回对应的页面类,没有特殊类则返回默认BspSimplePeripheral""" name_lower = peripheral_name.lower() @@ -1387,7 +1605,8 @@ def get_bsp_page(peripheral_name, project_path): "spi": bsp_spi, "uart": bsp_uart, "gpio": bsp_gpio, - "pwm": bsp_pwm, # 添加PWM + "pwm": bsp_pwm, + "flash": bsp_flash, # 添加Flash自动配置 # 以后可以继续添加特殊外设 } if name_lower in special_classes: diff --git a/app/tools/analyzing_ioc.py b/app/tools/analyzing_ioc.py index 542cbb4..6084009 100644 --- a/app/tools/analyzing_ioc.py +++ b/app/tools/analyzing_ioc.py @@ -341,4 +341,242 @@ class analyzing_ioc: 'signal': signal }) - return pwm_channels \ No newline at end of file + return pwm_channels + + @staticmethod + def get_mcu_name_from_ioc(ioc_path): + """ + 从.ioc文件中获取MCU型号 + 返回格式: 'STM32F407IGHx' 等 + """ + with open(ioc_path, encoding='utf-8', errors='ignore') as f: + for line in f: + line = line.strip() + if not line or line.startswith('#'): + continue + if '=' in line: + key, value = line.split('=', 1) + key = key.strip() + value = value.strip() + # 查找MCU名称 + if key == 'Mcu.UserName' or key == 'Mcu.Name': + return value + return None + + @staticmethod + def get_flash_config_from_mcu(mcu_name): + """ + 根据MCU型号返回Flash配置 + 支持STM32F1/F4/H7系列 + 返回格式: { + 'sectors': [...], # Sector/Page配置列表 + 'dual_bank': False, # 是否双Bank + 'end_address': 0x08100000, # Flash结束地址 + 'type': 'sector' or 'page' # Flash类型 + } + """ + if not mcu_name: + return None + + mcu_upper = mcu_name.upper() + + # STM32F1系列 - 使用Page而不是Sector + if mcu_upper.startswith('STM32F1'): + return analyzing_ioc._get_stm32f1_flash_config(mcu_upper) + + # STM32F4系列 - 使用Sector + elif mcu_upper.startswith('STM32F4'): + return analyzing_ioc._get_stm32f4_flash_config(mcu_upper) + + # STM32H7系列 - 使用Sector + elif mcu_upper.startswith('STM32H7'): + return analyzing_ioc._get_stm32h7_flash_config(mcu_upper) + + return None + + @staticmethod + def _get_stm32f1_flash_config(mcu_upper): + """ + STM32F1系列Flash配置 + F1使用Page而不是Sector + - 小/中容量设备: 1KB/page + - 大容量/互联型设备: 2KB/page + 容量代码: 4/6=16/32KB, 8/B=64/128KB, C=256KB, D/E=384/512KB, F/G=768KB/1MB + """ + flash_size_map_f1 = { + '4': 16, # 16KB + '6': 32, # 32KB + '8': 64, # 64KB + 'B': 128, # 128KB + 'C': 256, # 256KB + 'D': 384, # 384KB + 'E': 512, # 512KB + 'F': 768, # 768KB (互联型) + 'G': 1024, # 1MB (互联型) + } + + # F1命名: STM32F103C8T6, C在索引9 + if len(mcu_upper) < 10: + return None + + flash_code = mcu_upper[9] + flash_size = flash_size_map_f1.get(flash_code) + + if not flash_size: + return None + + # 判断页大小: <=128KB用1KB页, >128KB用2KB页 + page_size = 1 if flash_size <= 128 else 2 + num_pages = flash_size // page_size + + config = { + 'type': 'page', + 'dual_bank': False, + 'sectors': [], # F1中这里存的是Page + 'page_size': page_size, + } + + # 生成所有页 + current_address = 0x08000000 + for page_id in range(num_pages): + config['sectors'].append({ + 'id': page_id, + 'address': current_address, + 'size': page_size + }) + current_address += page_size * 1024 + + config['end_address'] = current_address + return config + + @staticmethod + def _get_stm32f4_flash_config(mcu_upper): + """ + STM32F4系列Flash配置 + 容量代码: C=256KB, E=512KB, G=1MB, I=2MB + """ + flash_size_map = { + 'C': 256, # 256KB + 'E': 512, # 512KB + 'G': 1024, # 1MB + 'I': 2048, # 2MB + } + + # F4命名: STM32F407IGHx, I在索引9 + if len(mcu_upper) < 10: + return None + + flash_code = mcu_upper[9] + flash_size = flash_size_map.get(flash_code) + + if not flash_size: + return None + + config = { + 'type': 'sector', + 'dual_bank': False, + 'sectors': [], + } + + # STM32F4系列单Bank Flash布局 + # Sector 0-3: 16KB each + # Sector 4: 64KB + # Sector 5-11: 128KB each (如果有) + + base_sectors = [ + {'id': 0, 'address': 0x08000000, 'size': 16}, + {'id': 1, 'address': 0x08004000, 'size': 16}, + {'id': 2, 'address': 0x08008000, 'size': 16}, + {'id': 3, 'address': 0x0800C000, 'size': 16}, + {'id': 4, 'address': 0x08010000, 'size': 64}, + ] + + config['sectors'] = base_sectors.copy() + current_address = 0x08020000 + current_id = 5 + remaining_kb = flash_size - (16 * 4 + 64) # 减去前5个sector + + # 添加128KB的sectors + while remaining_kb > 0 and current_id < 12: + config['sectors'].append({ + 'id': current_id, + 'address': current_address, + 'size': 128 + }) + current_address += 0x20000 # 128KB + remaining_kb -= 128 + current_id += 1 + + # 设置结束地址 + config['end_address'] = current_address + + # 2MB Flash需要双Bank (Sector 12-23) + if flash_size >= 2048: + config['dual_bank'] = True + # Bank 2 的sectors (12-15: 16KB, 16: 64KB, 17-23: 128KB) + bank2_sectors = [ + {'id': 12, 'address': 0x08100000, 'size': 16}, + {'id': 13, 'address': 0x08104000, 'size': 16}, + {'id': 14, 'address': 0x08108000, 'size': 16}, + {'id': 15, 'address': 0x0810C000, 'size': 16}, + {'id': 16, 'address': 0x08110000, 'size': 64}, + {'id': 17, 'address': 0x08120000, 'size': 128}, + {'id': 18, 'address': 0x08140000, 'size': 128}, + {'id': 19, 'address': 0x08160000, 'size': 128}, + {'id': 20, 'address': 0x08180000, 'size': 128}, + {'id': 21, 'address': 0x081A0000, 'size': 128}, + {'id': 22, 'address': 0x081C0000, 'size': 128}, + {'id': 23, 'address': 0x081E0000, 'size': 128}, + ] + config['sectors'].extend(bank2_sectors) + config['end_address'] = 0x08200000 + + return config + + @staticmethod + def _get_stm32h7_flash_config(mcu_upper): + """ + STM32H7系列Flash配置 + - 每个Sector 128KB + - 单Bank: 8个Sector (1MB) + - 双Bank: 16个Sector (2MB), 每个Bank 8个Sector + 容量代码: B=128KB, G=1MB, I=2MB + 命名格式: STM32H7 + 23 + V(引脚) + G(容量) + T(封装) + 6 + """ + flash_size_map_h7 = { + 'B': 128, # 128KB (1个Sector) + 'G': 1024, # 1MB (8个Sector, 单Bank) + 'I': 2048, # 2MB (16个Sector, 双Bank) + } + + # H7命名: STM32H723VGT6, G在索引10 + if len(mcu_upper) < 11: + return None + + flash_code = mcu_upper[10] + flash_size = flash_size_map_h7.get(flash_code) + + if not flash_size: + return None + + config = { + 'type': 'sector', + 'dual_bank': flash_size >= 2048, + 'sectors': [], + } + + num_sectors = flash_size // 128 # 每个Sector 128KB + + # 生成Sector配置 + current_address = 0x08000000 + for sector_id in range(num_sectors): + config['sectors'].append({ + 'id': sector_id, + 'address': current_address, + 'size': 128, + 'bank': 1 if sector_id < 8 else 2 # Bank信息 + }) + current_address += 0x20000 # 128KB + + config['end_address'] = current_address + return config \ No newline at end of file diff --git a/assets/User_code/bsp/describe.csv b/assets/User_code/bsp/describe.csv index 2788635..392034e 100644 --- a/assets/User_code/bsp/describe.csv +++ b/assets/User_code/bsp/describe.csv @@ -9,4 +9,4 @@ time,获取时间戳函数,需要开启freerots dwt,需要开启dwt,获取时间 i2c,请开启i2c的dma和中断 pwm,用于选择那些勇于输出pwm - +flash,自动识别MCU型号并配置Flash,支持STM32F1(Page)/F4(Sector)/H7(Sector),自动处理单Bank/双Bank配置 diff --git a/assets/User_code/bsp/flash/CHANGELOG.md b/assets/User_code/bsp/flash/CHANGELOG.md new file mode 100644 index 0000000..1216745 --- /dev/null +++ b/assets/User_code/bsp/flash/CHANGELOG.md @@ -0,0 +1,77 @@ +# Flash BSP 更新日志 + +## v2.0 - 2026-01-01 + +### 新增功能 +✨ **多系列MCU支持** +- 新增 STM32F1 系列支持(Page模式) +- 新增 STM32H7 系列支持(Sector模式) +- 保持 STM32F4 系列支持(Sector模式) + +### STM32F1系列详情 +- **Flash组织**: Page模式(页) +- **页大小**: + - 小/中容量(≤128KB): 1KB/页 + - 大容量/互联型(>128KB): 2KB/页 +- **容量支持**: 16KB - 1MB +- **容量代码**: 4/6/8/B/C/D/E/F/G +- **生成宏**: `ADDR_FLASH_PAGE_X` + +### STM32H7系列详情 +- **Flash组织**: Sector模式(扇区) +- **扇区大小**: 固定128KB +- **容量支持**: 128KB - 2MB +- **容量代码**: B/G/I +- **Bank支持**: + - 单Bank: 1MB (8个Sector) + - 双Bank: 2MB (16个Sector) +- **生成宏**: `ADDR_FLASH_SECTOR_X` + +### 技术改进 +- 重构 `get_flash_config_from_mcu()` 函数为多系列架构 +- 新增 `_get_stm32f1_flash_config()` - F1系列专用配置 +- 新增 `_get_stm32f4_flash_config()` - F4系列专用配置 +- 新增 `_get_stm32h7_flash_config()` - H7系列专用配置 +- 配置中新增 `type` 字段区分 'page' 和 'sector' 模式 +- 界面自动识别并显示Page或Sector模式 +- 代码生成支持Page和Sector两种宏定义 + +### 示例支持的芯片型号 +**STM32F1:** +- STM32F103C8T6 → 64KB (64 pages × 1KB) +- STM32F103RCT6 → 256KB (128 pages × 2KB) +- STM32F103ZET6 → 512KB (256 pages × 2KB) + +**STM32F4:** +- STM32F407VGT6 → 1MB (Sector 0-11) +- STM32F407IGH6 → 2MB (Sector 0-23, 双Bank) +- STM32F405RGT6 → 1MB (Sector 0-11) + +**STM32H7:** +- STM32H750VBT6 → 128KB (1 sector) +- STM32H743VGT6 → 1MB (8 sectors) +- STM32H743VIT6 → 2MB (16 sectors, 双Bank) + +### 配置文件变化 +```yaml +# 新增字段 +flash: + type: page # 或 sector + page_size: 2 # 仅F1系列有此字段 +``` + +### 文档更新 +- 更新 README.md 包含三个系列的完整说明 +- 新增各系列的Flash布局图 +- 新增各系列的使用示例 +- 更新注意事项包含擦除时间和寿命信息 + +--- + +## v1.0 - 初始版本 + +### 初始功能 +- STM32F4 系列支持 +- 自动识别芯片型号 +- 单Bank/双Bank配置 +- 基础API(擦除、读、写) diff --git a/assets/User_code/bsp/flash/README.md b/assets/User_code/bsp/flash/README.md new file mode 100644 index 0000000..ad3676d --- /dev/null +++ b/assets/User_code/bsp/flash/README.md @@ -0,0 +1,346 @@ +# Flash BSP 自动配置说明 + +## 功能特性 + +Flash BSP模块能够自动识别STM32芯片型号并生成对应的Flash配置代码。 + +### 支持的芯片系列 + +#### STM32F1 系列 +- 使用**Page**组织方式(而非Sector) +- 自动检测Flash容量(16KB - 1MB) +- 小/中容量设备:1KB/页 +- 大容量/互联型设备:2KB/页 + +#### STM32F4 系列 +- 使用**Sector**组织方式 +- 自动检测Flash容量(256KB/512KB/1MB/2MB) +- 自动配置单Bank或双Bank模式 +- 不同大小的Sector(16KB/64KB/128KB) + +#### STM32H7 系列 +- 使用**Sector**组织方式 +- 每个Sector固定128KB +- 自动检测Flash容量(128KB/1MB/2MB) +- 自动配置单Bank或双Bank模式 + +### Flash容量识别规则 + +根据STM32命名规则中的第9位字符识别Flash容量: + +**STM32F1系列:** +- **4**: 16KB (16 pages × 1KB) +- **6**: 32KB (32 pages × 1KB) +- **8**: 64KB (64 pages × 1KB) +- **B**: 128KB (128 pages × 1KB) +- **C**: 256KB (128 pages × 2KB) +- **D**: 384KB (192 pages × 2KB) +- **E**: 512KB (256 pages × 2KB) +- **F**: 768KB (384 pages × 2KB, 互联型) +- **G**: 1MB (512 pages × 2KB, 互联型) + +**STM32F4系列:** +- **C**: 256KB (单Bank, Sector 0-7) +- **E**: 512KB (单Bank, Sector 0-9) +- **G**: 1MB (单Bank, Sector 0-11) +- **I**: 2MB (双Bank, Sector 0-23) + +**STM32H7系列:** +- **B**: 128KB (1个Sector, 单Bank) +- **G**: 1MB (8个Sector, 单Bank) +- **I**: 2MB (16个Sector, 双Bank) + +例如: +- `STM32F103C8T6` → 64KB Flash (64 pages × 1KB) +- `STM32F103RCT6` → 256KB Flash (128 pages × 2KB) +- `STM32F103ZET6` → 512KB Flash (256 pages × 2KB) +- `STM32F407VGT6` → 1MB Flash (Sector 0-11) +- `STM32F407IGH6` → 2MB Flash (Sector 0-23, 双Bank) +- `STM32F405RGT6` → 1MB Flash (Sector 0-11) +- `STM32H743VIT6` → 2MB Flash (16 sectors × 128KB, 双Bank) +- `STM32H750VBT6` → 128KB Flash (1 sector × 128KB) + +## Flash布局 + +### STM32F1 Page模式 (16KB - 1MB) +``` +小/中容量 (≤128KB): 每页1KB + Page 0: 0x08000000 - 0x080003FF (1KB) + Page 1: 0x08000400 - 0x080007FF (1KB) + ... + +大容量/互联型 (>128KB): 每页2KB + Page 0: 0x08000000 - 0x080007FF (2KB) + Page 1: 0x08000800 - 0x08000FFF (2KB) + ... +``` + +### STM32F4 单Bank模式 (256KB - 1MB) +``` +Sector 0-3: 16KB each (0x08000000 - 0x0800FFFF) +Sector 4: 64KB (0x08010000 - 0x0801FFFF) +Sector 5-11: 128KB each (0x08020000 - 0x080FFFFF) +``` + +### STM32F4 双Bank模式 (2MB) +``` +Bank 1: + Sector 0-3: 16KB each (0x08000000 - 0x0800FFFF) + Sector 4: 64KB (0x08010000 - 0x0801FFFF) + Sector 5-11: 128KB each (0x08020000 - 0x080FFFFF) + +Bank 2: + Sector 12-15: 16KB each (0x08100000 - 0x0810FFFF) + Sector 16: 64KB (0x08110000 - 0x0811FFFF) + Sector 17-23: 128KB each (0x08120000 - 0x081FFFFF) +``` + +### STM32H7 Sector模式 +``` +单Bank (1MB): + Sector 0-7: 128KB each (0x08000000 - 0x080FFFFF) + +双Bank (2MB): + Bank 1: + Sector 0-7: 128KB each (0x08000000 - 0x080FFFFF) + Bank 2: + Sector 8-15: 128KB each (0x08100000 - 0x081FFFFF) +``` + +## 使用方法 + +### 1. 在BSP配置界面启用Flash +在代码生成界面的BSP标签中,勾选"生成 Flash 代码"选项。 + +### 2. 自动检测 +系统会自动: +- 读取项目中的`.ioc`文件 +- 提取MCU型号信息 +- 计算Flash扇区配置 +- 生成对应的宏定义 + +### 3. 生成的代码示例 + +**STM32F1系列** (以STM32F103RCT6为例 - 256KB): +```c +// flash.h +#define ADDR_FLASH_PAGE_0 ((uint32_t)0x08000000) +/* Base address of Page 0, 2 Kbytes */ +#define ADDR_FLASH_PAGE_1 ((uint32_t)0x08000800) +/* Base address of Page 1, 2 Kbytes */ +... +#define ADDR_FLASH_PAGE_127 ((uint32_t)0x0803F800) +/* Base address of Page 127, 2 Kbytes */ +#define ADDR_FLASH_END ((uint32_t)0x08040000) + +// flash.c +#define BSP_FLASH_MAX_PAGE 127 +if (page >= 0 && page <= 127) { + // 擦除代码... +} +``` + +**STM32F4系列** (以STM32F407IGH6为例 - 2MB): +```c +// flash.h +#define ADDR_FLASH_SECTOR_0 ((uint32_t)0x08000000) +/* Base address of Sector 0, 16 Kbytes */ +... +#define ADDR_FLASH_SECTOR_23 ((uint32_t)0x081E0000) +/* Base address of Sector 23, 128 Kbytes */ + +#define ADDR_FLASH_END ((uint32_t)0x08200000) +/* End address for flash */ +``` + +**flash.c**: +```c +#define BSP_FLASH_MAX_SECTOR 23 + +void BSP_Flash_EraseSector(uint32_t sector) { + if (sector > 0 && sector <= 23) { + // 擦除代码... + } +} +``` + +**STM32H7系列** (以STM32H743VIT6为例 - 2MB): +```c +// flash.h +#define ADDR_FLASH_SECTOR_0 ((uint32_t)0x08000000) +/* Base address of Sector 0, 128 Kbytes */ +... +#define ADDR_FLASH_SECTOR_15 ((uint32_t)0x081E0000) +/* Base address of Sector 15, 128 Kbytes */ + +#define ADDR_FLASH_END ((uint32_t)0x08200000) + +// flash.c +#define BSP_FLASH_MAX_SECTOR 15 +if (sector > 0 && sector <= 15) { + // 擦除代码... +} +``` + +## API接口 + +### BSP_Flash_EraseSector (F4/H7) / BSP_Flash_ErasePage (F1) +擦除指定扇区或页 +```c +// F4/H7系列 +void BSP_Flash_EraseSector(uint32_t sector); +// F1系列 +void BSP_Flash_ErasePage(uint32_t page); +``` +- **参数**: + - sector/page - 扇区号或页号 + - F1: 0 到 (页数-1) + - F4: 0-11 或 0-23(根据芯片型号) + - H7: 0-7 或 0-15(根据芯片型号) + +### BSP_Flash_WriteBytes +写入数据到Flash +```c +void BSP_Flash_WriteBytes(uint32_t address, const uint8_t *buf, size_t len); +``` +- **参数**: + - address - Flash地址 + - buf - 数据缓冲区 + - len - 数据长度 + +### BSP_Flash_ReadBytes +从Flash读取数据 +```c +void BSP_Flash_ReadBytes(uint32_t address, void *buf, size_t len); +``` +- **参数**: + - address - Flash地址 + - buf - 接收缓冲区 + - len - 读取长度 + +## 使用示例 + +### STM32F1系列示例 +```c +#include "bsp/flash.h" + +void save_config_f1(void) { + // 擦除Page 127 (最后一页,通常用于存储用户数据) + BSP_Flash_ErasePage(127); + + // 写入配置数据 + uint8_t config[100] = {/* 配置数据 */}; + BSP_Flash_WriteBytes(ADDR_FLASH_PAGE_127, config, sizeof(config)); +} + +void load_config_f1(void) { + // 读取配置数据 + uint8_t config[100]; + BSP_Flash_ReadBytes(ADDR_FLASH_PAGE_127, config, sizeof(config)); +} +``` + +### STM32F4系列示例 +```c +#include "bsp/flash.h" + +void save_config_f4(void) { + // 擦除Sector 11 (通常用于存储用户数据) + BSP_Flash_EraseSector(11); + + // 写入配置数据 + uint8_t config[100] = {/* 配置数据 */}; + BSP_Flash_WriteBytes(ADDR_FLASH_SECTOR_11, config, sizeof(config)); +} + +void load_config_f4(void) { + // 读取配置数据 + uint8_t config[100]; + BSP_Flash_ReadBytes(ADDR_FLASH_SECTOR_11, config, sizeof(config)); +} +``` + +### STM32H7系列示例 + +### STM32H7系列示例 +```c +#include "bsp/flash.h" + +void save_config(void) { + // 擦除Sector 11 (通常用于存储用户数据) + BSP_Flash_EraseSector(11); + + // 写入配置数据 + uint8_t config[100] = {/* 配置数据 */}; + BSP_Flash_WriteBytes(ADDR_FLASH_SECTOR_11, config, sizeof(config)); +} + +void load_config(void) { + // 读取配置数据 + uint8_t config[100]; + BSP_Flash_ReadBytes(ADDR_FLASH_SECTOR_11, config, sizeof(config)); +} +``` + +## 注意事项 + +1. **擦除时间**: Flash擦除需要一定时间,注意不要在中断中执行 + - F1 Page擦除: ~20ms + - F4 Sector擦除: 16KB~100ms, 64KB~300ms, 128KB~500ms + - H7 Sector擦除: ~200ms +2. **写入前擦除**: + - F1: 必须先擦除整页才能写入 + - F4/H7: 必须先擦除整个扇区才能写入 +3. **区域选择**: 避免擦除包含程序代码的扇区/页 + - F1: 通常最后几页用于存储数据 + - F4: Sector 11 或 23 常用于存储数据 + - H7: Sector 7 或 15 常用于存储数据 +4. **写入对齐**: 建议按字节写入,HAL库会处理对齐 +5. **断电保护**: 写入过程中断电可能导致数据丢失 +6. **擦写次数限制**: + - F1: 典型10,000次 + - F4/H7: 典型10,000-100,000次 + +## 配置文件 + +配置信息保存在 `bsp_config.yaml`: + +**STM32F1:** +```yaml +flash: + enabled: true + mcu_name: STM32F103RCT6 + dual_bank: false + sectors: 128 # 实际是128个页 + type: page + page_size: 2 +``` + +**STM32F4:** +```yaml +flash: + enabled: true + mcu_name: STM32F407IGHx + dual_bank: true + sectors: 24 + type: sector +``` + +**STM32H7:** +```yaml +flash: + enabled: true + mcu_name: STM32H743VIT6 + dual_bank: true + sectors: 16 + type: sector +``` + +## 扩展支持 + +当前支持的系列: +- ✅ STM32F1 (Page模式) +- ✅ STM32F4 (Sector模式) +- ✅ STM32H7 (Sector模式) + +如需支持其他STM32系列(如F2/F3/L4/G4等),可在 `analyzing_ioc.py` 的 `get_flash_config_from_mcu()` 函数中添加相应的配置规则。 diff --git a/assets/User_code/bsp/flash/flash.c b/assets/User_code/bsp/flash/flash.c new file mode 100644 index 0000000..0df01ca --- /dev/null +++ b/assets/User_code/bsp/flash/flash.c @@ -0,0 +1,55 @@ +/* Includes ----------------------------------------------------------------- */ +#include "bsp/flash.h" + +#include +#include + +/* Private define ----------------------------------------------------------- */ +/* USER CODE BEGIN FLASH_MAX_SECTOR */ +/* AUTO GENERATED FLASH_MAX_SECTOR */ +/* USER CODE END FLASH_MAX_SECTOR */ + +/* Private macro ------------------------------------------------------------ */ +/* Private typedef ---------------------------------------------------------- */ +/* Private variables -------------------------------------------------------- */ +/* Private function -------------------------------------------------------- */ +/* Exported functions ------------------------------------------------------- */ + +void BSP_Flash_EraseSector(uint32_t sector) { + FLASH_EraseInitTypeDef flash_erase; + uint32_t sector_error; + + /* USER CODE BEGIN FLASH_ERASE_CHECK */ + /* AUTO GENERATED FLASH_ERASE_CHECK */ + /* USER CODE END FLASH_ERASE_CHECK */ + flash_erase.Sector = sector; + flash_erase.TypeErase = FLASH_TYPEERASE_SECTORS; + flash_erase.VoltageRange = FLASH_VOLTAGE_RANGE_3; + flash_erase.NbSectors = 1; + + HAL_FLASH_Unlock(); + while (FLASH_WaitForLastOperation(50) != HAL_OK) + ; + HAL_FLASHEx_Erase(&flash_erase, §or_error); + HAL_FLASH_Lock(); + } + /* USER CODE BEGIN FLASH_ERASE_END */ + /* USER CODE END FLASH_ERASE_END */ +} + +void BSP_Flash_WriteBytes(uint32_t address, const uint8_t *buf, size_t len) { + HAL_FLASH_Unlock(); + while (len > 0) { + while (FLASH_WaitForLastOperation(50) != HAL_OK) + ; + HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, address, *buf); + address++; + buf++; + len--; + } + HAL_FLASH_Lock(); +} + +void BSP_Flash_ReadBytes(uint32_t address, void *buf, size_t len) { + memcpy(buf, (void *)address, len); +} diff --git a/assets/User_code/bsp/flash/flash.h b/assets/User_code/bsp/flash/flash.h new file mode 100644 index 0000000..68a0a80 --- /dev/null +++ b/assets/User_code/bsp/flash/flash.h @@ -0,0 +1,31 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------ */ +#include + +#include "bsp/bsp.h" + +/* Exported constants -------------------------------------------------------- */ +/* Base address of the Flash sectors */ +/* USER CODE BEGIN FLASH_SECTOR_DEFINES */ +/* AUTO GENERATED FLASH_SECTORS */ +/* USER CODE END FLASH_SECTOR_DEFINES */ + +/* USER CODE BEGIN FLASH_END_ADDRESS */ +/* AUTO GENERATED FLASH_END_ADDRESS */ +/* USER CODE END FLASH_END_ADDRESS */ + +/* Exported macro ------------------------------------------------------------ */ +/* Exported types ------------------------------------------------------------ */ +/* Exported functions prototypes --------------------------------------------- */ +void BSP_Flash_EraseSector(uint32_t sector); +void BSP_Flash_WriteBytes(uint32_t address, const uint8_t *buf, size_t len); +void BSP_Flash_ReadBytes(uint32_t address, void *buf, size_t len); + +#ifdef __cplusplus +} +#endif diff --git a/assets/User_code/config.csv b/assets/User_code/config.csv index 592952d..e13d9ac 100644 --- a/assets/User_code/config.csv +++ b/assets/User_code/config.csv @@ -1,4 +1,4 @@ -bsp,can,fdcan,dwt,gpio,i2c,mm,spi,uart,pwm,time +bsp,can,fdcan,dwt,gpio,i2c,mm,spi,uart,pwm,time,flash component,ahrs,capacity,cmd,crc8,crc16,error_detect,filter,FreeRTOS_CLI,limiter,mixer,pid,ui,user_math device,dr16,bmi088,ist8310,motor,motor_rm,motor_dm,motor_vesc,motor_lk,motor_lz,motor_odrive,dm_imu,rc_can,servo,buzzer,led,ws2812,vofa,ops9,oid,lcd_driver module,config, \ No newline at end of file