硬汉嵌入式论坛

 找回密码
 立即注册
搜索
查看: 347|回复: 0
收起左侧

[Lua] 备份个LUA实现的PY32F031的整片擦除和选项字节设置,实现整片擦除+解除保护+使能保护1.7秒完成

[复制链接]

1万

主题

7万

回帖

12万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
123910
QQ
发表于 2026-7-16 10:36:08 | 显示全部楼层 |阅读模式
用的官方最新版算法文件,整片擦除+解除保护+使能保护3-4秒完成,主要是没法全速运行,设置全速就出问题,得加一点延迟。

优化后,可以全速运行了,备份下,实际意义不大,这种差个1-2秒,实际生产操作,没啥区别,因为本身时间基数太小了。

[Lua] 纯文本查看 复制代码
-------------------------------------------------------
-- 文件名 : PY32F0_Lib.lua
-- 版  本 : V1.0  2022-04-15
-- 说  明 :  
-------------------------------------------------------

--复位期间执行的函数. 目的:debug期间冻结看门狗时钟,低功耗模式启动HCLK和FCLK
function InitUnderReset(void)
        local str = "error"

        print("InitUnderReset()")

        --Write32(0xE000EDF0, 0xA05F0001);                                        // Enable Core Debug via DHCSR
        --Write32(0x4002103C, Read32(0x4002103C) | 0x08000000);                   // Set RCC_APBENR1.DBGEN
                        
        -- if (pg_write32(0xE000EDF0, 0xA05F0001) == 0) then
        --         goto quit_err
        -- end

        -- if (pg_write32(0x4002103C, pg_write32(0x4002103C) | 0x08000000) == 0) then
        --         goto quit_err
        -- end

        -- --Write32(0x40015804, DbgMCU_CR);                                         // DBGMCU_CR: Configure MCU Debug
        -- --                Write32(0x40015808, DbgMCU_APB_Fz1);                                    // DBGMCU_APB_FZ1: Configure APB Peripheral Freeze1 Behavior
        -- --                Write32(0x4001580C, DbgMCU_APB_Fz2);                                    // DBGMCU_APB_FZ2: Configure APB Peripheral Freeze2 Behavior
        -- if (pg_write32(0x40015804, 2) == 0) then
        --         goto quit_err
        -- end

        -- if (pg_write32(0x40015808, 0) == 0) then
        --         goto quit_err
        -- end
        
        -- if (pg_write32(0x4001580C, 0) == 0) then
        --         goto quit_err
        -- end
        
        -- if (ReadDeviceID() ~= 0) then
                -- goto quit_err
        -- end

::quit_ok::
        str = "OK"

::quit_err::
        print(str)

        return str
end

--读芯片ID
function ReadDeviceID(void)
        local str
        local err = 0
        local j
        local ch_num

        if (MULTI_MODE == 0) then
                ch_num = 1
        else
                ch_num = MULTI_MODE
        end
        
        g_DevID = {pg_read32(0x40015800)} --全局变量g_DevID[]

        str = "..DeviceID = "
        for j = 1, ch_num, 1 do
                str = str..string.format("%08X ", g_DevID[j])
                if (g_DevID[j] == 0) then
                        if (ABORT_ON_ERROR == 1) then
                                err = 1
                        end
                end
        end

        print(str)
        return err
end

--[[
  PY32F031 Flash 操作 — Lua 版 (合并版)
  包含: 整片擦除 (MCU_EraseMass) + 选项字节编程 (MCU_ProgOptionBytes)

  不配置时钟,不配置看门狗,由调用方确保芯片在正确时钟下运行。

  寄存器地址速查 (FLASH base = 0x40022000):
    KEYR      0x40022008   Flash 解锁 (KEY1=0x45670123, KEY2=0xCDEF89AB)
    OPTKEYR   0x4002200C   OB 解锁 (OPTKEY1=0x08192A3B, OPTKEY2=0x4C5D6E7F)
    SR        0x40022010   状态 (EOP bit0 / WRPERR bit4 / OPTVERR bit15 / BSY bit16)
    CR        0x40022014   控制 (MER bit2 / OPTSTRT bit17 / EOPIE bit24 / OPTLOCK bit30 / LOCK bit31)
    OPTR      0x40022020   选项寄存器 (20位)
    SDKR      0x40022024   SDK 寄存器
    WRPR      0x4002202C   写保护寄存器

  Flash 基地址: 0x08000000
  OB 基地址:    0x1FFF0E80
]]


-- ========================================================================
-- 寄存器常量
-- ========================================================================
local FLASH_KEYR      = 0x40022008
local FLASH_OPTKEYR   = 0x4002200C
local FLASH_SR         = 0x40022010
local FLASH_CR         = 0x40022014
local FLASH_OPTR       = 0x40022020
local FLASH_SDKR       = 0x40022024
local FLASH_WRPR       = 0x4002202C
local FLASH_OB_ADDR    = 0x1FFF0E80
local FLASH_BASE_ADDR  = 0x08000000

-- Flash Control Register bits
local FLASH_CR_PG       = 0x00000001   -- bit 0:  页编程
local FLASH_CR_PER      = 0x00000002   -- bit 1:  页擦除
local FLASH_CR_MER      = 0x00000004   -- bit 2:  整片擦除
local FLASH_CR_OPTSTRT  = 0x00020000   -- bit 17: 启动 OB 编程
local FLASH_CR_EOPIE    = 0x01000000   -- bit 24: EOP 中断使能
local FLASH_CR_OPTLOCK  = 0x40000000   -- bit 30: OB 锁定
local FLASH_CR_LOCK     = 0x80000000   -- bit 31: Flash 锁定

-- Flash Status Register bits
local FLASH_SR_EOP      = 0x00000001   -- bit 0:  操作完成
local FLASH_SR_WRPERR   = 0x00000010   -- bit 4:  写保护错误
local FLASH_SR_OPTVERR  = 0x00008000   -- bit 15: OB 有效性错误
local FLASH_SR_BSY      = 0x00010000   -- bit 16: 忙标志

-- 错误标志掩码
local FLASH_OB_ERR = FLASH_SR_WRPERR | FLASH_SR_OPTVERR

-- 解锁常量
local UNLOCK_KEY1    = 0x45670123
local UNLOCK_KEY2    = 0xCDEF89AB
local OB_UNLOCK_KEY1 = 0x08192A3B
local OB_UNLOCK_KEY2 = 0x4C5D6E7F


-- ========================================================================
-- 辅助函数
-- ========================================================================

--[[
  判断data数组标志,成功返回mask,失败返回0
  (用于检查是否所有核心的标志位都等于 mask)
]]
function SWD_CheckFlagQuit0(data, mask)
  local i
  local ret

  if (MULTI_MODE > 0) then
    for i = 1, MULTI_MODE, 1 do
      ret = (data[i] & mask)
      if (ret ~= mask) then
        ret = 0
        break
      end
    end
  else
    ret = (data[1] & mask)
    if (ret ~= mask) then
      ret = 0
    end
  end

  return ret
end

--[[
  判断data数组标志,全部为0则退出
  (用于检查所有核心与 mask 的 AND 结果是否为 0)
]]
function CheckFlagQuit0(data, mask)
  local i
  local ret

  if (MULTI_MODE > 0) then
    ret = 0
    for i = 1, MULTI_MODE, 1 do
      ret = ret | (data[i] & mask)
    end
  else
    ret = data[1] & mask
  end

  return ret
end

-- 读32位寄存器 (兼容MULTI_MODE,取第一个核心)
local function rd32(addr)
  return ({pg_read32(addr)})[1]
end

-- 修改寄存器指定位 (等价 C 的 MODIFY_REG)
local function rmw32(addr, clearmask, setmask)
  local val = rd32(addr)
  pg_write32(addr, (val & ~clearmask) | setmask)
end

-- 等待 BSY 清零,返回1=成功,0=超时
local function WaitBSY(timeout)
  local reg = {}
  local j = 0
  for i = 1, timeout, 1 do
    j = j + 1
    reg = {pg_read32(FLASH_SR)}
    if (CheckFlagQuit0(reg, FLASH_SR_BSY) == 0) then
      break
    end
    delayms(10)
  end
  print(string.format("WaitBSY() 等待时间: %dms", j * 10))
  return (CheckFlagQuit0(reg, FLASH_SR_BSY) == 0) and 1 or 0
end


-- ========================================================================
-- 整片擦除
-- ========================================================================

--[[
  芯片专有的整片擦除
  流程: 解锁Flash → 清标志/等BSY → 使能MER → 触发擦除 → 等BSY → 检查EOP → 清理 → 锁定Flash
  返回: "OK" or "FAIL"
]]
function MCU_EraseMass(void)
  local reg = {}
  local val
  local i

  -- 1. 解锁 Flash
  pg_write32(0x40022008, 0x45670123)  -- FLASH->KEYR = KEY1
  pg_write32(0x40022008, 0xCDEF89AB)  -- FLASH->KEYR = KEY2

  -- 2. 清除 EOP 标志 (写1清零), 等待 BSY 清零
  pg_write32(0x40022010, 0x00000001)  -- SR |= EOP (w1c)
  for i = 1, 1000, 1 do
    reg = {pg_read32(0x40022010)}
    if (SWD_CheckFlagQuit0(reg, 0x00010000) == 0) then
      break
    end
    delayms(1)
  end

  -- 3. 使能整片擦除: MER(bit2) + EOPIE(bit24)
  val = rd32(0x40022014)
  pg_write32(0x40022014, val | 0x01000004)

  -- 4. 触发擦除 (向 Flash 基地址写 0xFF)
  pg_write32(0x08000000, 0x000000FF)
  delayms(1)

  -- 5. 等待擦除完成 (BSY 清零)
  for i = 1, 10000, 1 do
    reg = {pg_read32(0x40022010)}
    if (SWD_CheckFlagQuit0(reg, 0x00010000) == 0) then
      break
    end
    delayms(1)
  end

  -- 6. 检查 EOP 标志
  reg = {pg_read32(0x40022010)}
  if (SWD_CheckFlagQuit0(reg, 0x00000001) == 0) then
    print("PY32F031 EraseMass: EOP not set, FAILED")
    val = rd32(0x40022014)
    pg_write32(0x40022014, val & ~0x01000004)  -- 清 MER+EOPIE
    pg_write32(0x40022014, 0x80000000)          -- 锁定 Flash
    return "FAIL"
  end

  -- 7. 清除 MER 和 EOPIE
  val = rd32(0x40022014)
  pg_write32(0x40022014, val & ~0x01000004)

  -- 8. 复位 EOP 标志
  pg_write32(0x40022010, 0x00000001)

  -- 9. 锁定 Flash
  --val = rd32(0x40022014)
  --pg_write32(0x40022014, val | 0x80000000)  -- CR |= LOCK

  print("PY32F031 EraseMass OK")
  return "OK"
end


-- ========================================================================
-- 选项字节编程
-- ========================================================================
-- OB 配置值 (8字节: OPTR + BOR + SDKR + WRPR, 各2字节小端)
--OB_SECURE_OFF  = "AA B8 00 00 1F 00 FF FF"  -- SECURE_ENABLE = 0, 编程完毕后写入
--OB_SECURE_ON   = "00 B8 00 00 1F 00 FF FF"  -- SECURE_ENABLE = 1, 编程完毕后写入
--[[
  解析8字节OB数据
  格式: OPTR(2) + BOR(2) + SDKR(2) + WRPR(2), 各小端
  返回: optr_final(20位), sdkr(16位), wrpr(16位)

  对应 C 代码:
    optr = *((u32*)(buf+0x00)) & 0xFFFF;
    bor  = *((u32*)(buf+0x04)) & 0xF;
    optr = optr | (bor << 16);
    sdkr = *((u32*)(buf+0x08)) & 0xFFFF;
    wrpr = *((u32*)(buf+0x0C)) & 0xFFFF;
]]
local function ParseOB(ob)
  local ob_bin = hex_to_bin(ob)
  local optr = string.byte(ob_bin, 1) | (string.byte(ob_bin, 2) << 8)
  local bor  = string.byte(ob_bin, 3) | (string.byte(ob_bin, 4) << 8)
  local sdkr = string.byte(ob_bin, 5) | (string.byte(ob_bin, 6) << 8)
  local wrpr = string.byte(ob_bin, 7) | (string.byte(ob_bin, 8) << 8)
  -- BOR[3:0] 合并到 OPTR[19:16]
  local optr_final = (optr & 0xFFFF) | ((bor & 0xF) << 16)
  return optr_final & 0xFFFFF, sdkr & 0xFFFF, wrpr & 0xFFFF
end

--[[
  编程选项字节
  参数: ob — 8字节hex字符串, 如 "AA B8 00 00 1F 00 FF FF"
  返回: "OK" or "error"

  对应 C 代码 FLASH_OB ProgramPage():
    1. 写 OPTR / SDKR / WRPR 寄存器
    2. CR |= OPTSTRT + EOPIE
    3. M32(0x1FFF0E80) = 0xFF  (触发)
    4. 等 BSY 清零
    5. 检查 EOP
    6. 清 OPTSTRT + EOPIE
    7. 锁定 OB + Flash
]]
function MCU_ProgOptionBytes(ob)
  local err = "OK"
  local reg = {}

  print("MCU_ProgOptionBytes()")

  -- 1. 解锁 Flash
  pg_write32(FLASH_KEYR, UNLOCK_KEY1)
  pg_write32(FLASH_KEYR, UNLOCK_KEY2)

  -- 2. 解锁 Option Bytes
  pg_write32(FLASH_OPTKEYR, OB_UNLOCK_KEY1)
  pg_write32(FLASH_OPTKEYR, OB_UNLOCK_KEY2)

  -- 3. 清除错误标志 (写1清零)
  pg_write32(FLASH_SR, FLASH_OB_ERR)

  -- 4. 解析 OB 数据
  local optr_val, sdkr_val, wrpr_val = ParseOB(ob)
  print(string.format("OPTR=0x%05X  SDKR=0x%04X  WRPR=0x%04X",
                       optr_val, sdkr_val, wrpr_val))

  -- 5. 清除 EOP 标志,等待 BSY 清零
  pg_write32(FLASH_SR, FLASH_SR_EOP)
  WaitBSY(500)

  -- 6. 写入 OPTR / SDKR / WRPR 寄存器
  pg_write32(FLASH_OPTR, optr_val)
  pg_write32(FLASH_SDKR, sdkr_val)
  pg_write32(FLASH_WRPR, wrpr_val)

  -- 7. 启动 OB 编程: CR |= OPTSTRT + EOPIE
  rmw32(FLASH_CR, 0, FLASH_CR_OPTSTRT | FLASH_CR_EOPIE)

  -- 8. 触发写入 (向 OB 基地址写 0xFF, 等价 C 的 M32(0x1FFF0E80)=0xFF + DSB)
  pg_write32(FLASH_OB_ADDR, 0x000000FF)

  -- 9. 等待编程完成
  print("等待OB编程完成......")
  WaitBSY(500)

  delayms(10)

  -- 10. 检查 EOP 标志 (成功标志)
  reg = {pg_read32(FLASH_SR)}
  if (CheckFlagQuit0(reg, FLASH_SR_EOP) == 0) then
    print("PY32F031 ProgOB: EOP not set, FAILED")
    err = "error"
  end

  -- 11. 检查错误标志
  reg = {pg_read32(FLASH_SR)}
  if (CheckFlagQuit0(reg, FLASH_OB_ERR) ~= 0) then
    print("PY32F031 ProgOB: error flags set, FAILED")
    err = "error"
  end

  -- 12. 清除 OPTSTRT + EOPIE
  rmw32(FLASH_CR, FLASH_CR_OPTSTRT | FLASH_CR_EOPIE, 0)

  -- 13. 锁定 Option Bytes 和 Flash
  rmw32(FLASH_CR, 0, FLASH_CR_OPTLOCK)
  rmw32(FLASH_CR, 0, FLASH_CR_LOCK)

  if (err == "OK") then
    print("PY32F031 ProgOB OK")
  end

  return err
end

--[[
  芯片专有的解除保护函数
  返回: "OK" or "error"
]]
function MCU_RemoveProtect(void)
  return MCU_ProgOptionBytes(OB_SECURE_OFF)
end



回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2026-8-26 21:35 , Processed in 1.811275 second(s), 24 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表