【辉芒微】FT61F0A 存储器及看门狗
本文最后更新于30 天前,其中的信息可能已经过时,如有错误请发送邮件到tudougin@163.com

1. EEPROM

​ FT61F0Ax / FT64F0Ax 片内集成的非易失性 数据存储器DROM和程序存储器 PROM 。均可通过指令进行读/写访问,由 “CFGS” 和 “EEPGD” 选择所访问的存储区。128 x 8−bit 的 DROM 和 10k x 14−bit (160 page x 64 words) 的程序 PROM 相互独立。

​ DROM 擦除/编程实了硬件自定时,无需软件查询,以节省有限的代码空间,因此写操作可在后台运行,不影响 CPU 执行其他指令,甚至可进入 SLEEP 状态。但 PROM 擦除/编程时,CPU 将停止执行指令。不支持连续读(sequential READ) 或连续写(sequential WRITE),因此每次读/写都必须更新相应的地址。

1.1 数据存储器DROM

地址范围为 0x00 ~ 0x7F,每次可读取或写入的单位为 1个 byte (8−bit),没有页模式(page mode)。

1.1.1 官方例程

/*-------------------------------------------------
 * 函数名:EEPROMread
 * 功能:  读EEPROM数据
 * 输入:  EEAddr需读取数据的地址
 * 输出:  ReEEPROMread对应地址读出的数据
 --------------------------------------------------*/
uint8_t EEPROMread (uint8_t EEAddr)
{
    uint8_t ReEEPROMread;
    while(GIE)                  //等待GIE为0
    {
          GIE = 0;                //读数据必须关闭中断
          NOP();               
          NOP();            
    }               
    EEADRL=EEAddr;

    CFGS=0;
    EEPGD=0;
    RD=1;
    NOP();
    NOP();
    NOP();
    NOP();
    ReEEPROMread=EEDATL;

    return ReEEPROMread;
}
/*-------------------------------------------------
 * 函数名:Unlock_Flash
 * 功能:  进行FLASH/EEDATA操作时,解锁FLASH/EEDATA的时序不能被打断。
 *           程序中要将此段用汇编指令处理防止被优化
 * 输入:  无
 * 输出:  无
 --------------------------------------------------*/
void Unlock_Flash()
{
#asm
    MOVLW    0x03
    MOVWF    _BSREG
    MOVLW    0x55
    MOVWF    _EECON2 & 0x7F
    MOVLW    0xAA
    MOVWF    _EECON2 & 0x7F
    BSF        _EECON1 & 0x7F,1        //WR=1;
    NOP
    NOP
#endasm
}
/*-------------------------------------------------
 * 函数名:EEPROMwrite
 * 功能:  写数据到EEPROM
 * 输入:  EEAddr为需要写入数据的地址,Data为需要写入的数据
 * 输出:  无
 --------------------------------------------------*/
 void EEPROMwrite(uint8_t EEAddr,uint8_t Data)
 {
    while(GIE)                  //等待GIE为0
    {
        GIE = 0;                //写数据必须关闭中断
        NOP();               
        NOP();            
    }               
    EEADRL=EEAddr;              //EEPROM的地址
    EEDATL=Data;                //EEPROM的数据

    CFGS=0;
    EEPGD=0;
    WREN=1;                     //写使能
    EEIF=0;

    Unlock_Flash();             //Flash 解锁时序不能修改
    NOP();
    NOP();
    NOP();
    NOP();

    while(WR);                  //等待EEPROM写入完成
    WREN=0;
    GIE=1;
 }

1.1.2 使用示例

​ 初始化时将数值 0x55 写入起始地址 0x3F。之后依次进行如下操作:读取当前地址的数据,值加 1 后写入下一个地址,并更新当前地址指针。该过程共执行 16 次,最终在地址 0x40 至 0x4F(共 16 个地址)中存入一个线性递增的数据序列。该操作可用于验证存储器读写功能或初始化测试数据。

void main(void){
    DelayMs(10);
    sysInit();
    EEPROMwrite(0x3F,0x55);        //0x55写入地址0x3F
    for(uint8_t i = 0x40;i <= 0x4F;i++){
        DelayMs(50);
        uint8_t data =  EEPROMread(i - 1);
        EEPROMwrite(i,data+1);   
    }
    while(1);
}

1.2 程序存储器PROM

​ 程序地址计数器 PC 为 15 位(0x0000 ~ 0x7FFF),最多支持 32k 地址空间。FT61F0Ax / FT64F0Ax 实现了 10k 的程序 PROM,共分为 160 page x 64 words (1 word = 14 bits),地址范围为 0x0000 ~ 0x27FF,当程序地址超过 0x27FF 将导致回卷到 0x0000。

​ 软件需先对程序 PROM 进行擦除,再执行编程操作。

1.2.1 功能——实现远程升级

  1. 主机下发“进入升级”命令
  2. 从机进入 Bootloader 模式(一般复位或跳转)
  3. 主机发送程序数据(Hex 格式或 Binary 格式)
  4. 从机擦除主程序区域 Flash
  5. 从机将数据写入 Flash(通过自擦写函数)
  6. 从机校验完整性(CRC 或 Checksum)
  7. 写入成功后重启,跳转到主程序
image-20250520212451652
区域地址范围说明
Bootloader0x0000 ~ 0x04FF固定不变,负责升级
主程序区0x0500 ~ 0x27FF正常程序区域

1.2.2 实现远程升级Bootloader的大致框架(暂未验证)

  1. 主函数部分
void main(void) {
    system_init();          // 初始化时钟、串口、IO
    if (!check_upgrade_flag()) {
        jump_to_application(); // 无升级请求时跳转主程序
    }

    uart_init();            // 初始化串口(9600波特等)

    while (1) {
        if (receive_firmware_frame()) {
            flash_write_frame();
            uart_send_ack();
        }

        if (all_data_received()) {
            jump_to_application();
        }
    }
}
  1. 串口接收逻辑
#define FRAME_SIZE 16
uint8_t rx_buf[FRAME_SIZE + 4]; // 包括帧头、地址、数据、校验等

bool receive_firmware_frame() {
    // 简单帧格式: [0xA5][addr_L][addr_H][16字节数据][checksum]
    if (uart_available() >= 19) {
        for (uint8_t i = 0; i < 19; i++) {
            rx_buf[i] = uart_read();
        }
        if (rx_buf[0] == 0xA5 && verify_checksum(rx_buf)) {
            return true;
        }
    }
    return false;
}
  1. Flash 写入函数
void flash_write_frame() {
    uint16_t addr = rx_buf[1] | (rx_buf[2] << 8);
    for (uint8_t i = 0; i < 16; i++) {
        flash_write_byte(addr + i, rx_buf[3 + i]);
    }
}

void flash_write_byte(uint16_t addr, uint8_t data) {
    // Flash 写入流程(FT61F0A5,简化版)
    GIE = 0;
    EEADR = addr & 0xFF;
    EEDATH = (addr >> 8) & 0xFF;
    EEDAT = data;
    EECON1 = 0x84;         // 设置 WR=1, WREN=1, EEPGD=1 (写程序区)
    EECON2 = 0x55;
    EECON2 = 0xAA;
    EECON1 |= 0x02;        // 设置 WR=1 启动写
    while (EECON1 & 0x02); // 等待写完
    EECON1 &= ~0x04;       // 清除 WREN
    GIE = 1;
}
  1. 跳转到APP代码
void jump_to_application() {
    // 直接跳转到主程序地址(0x0200)
    ((void (*)(void))0x0500)();
}
  1. 简单的校验函数
bool verify_checksum(uint8_t *buf) {
    uint8_t sum = 0;
    for (int i = 0; i < 18; i++) {
        sum += buf[i];
    }
    return (sum == buf[18]);
}
  1. 可参考的数据帧格式
[0xA5] [addr_L] [addr_H] [16 bytes data] [checksum]

2. 软件看门狗

image-20250520212441849

计时超过看门狗定时时间:
$$
WDT_{定时时间} = \frac{WDT_{周期} \times WDT_{预分频比} }{ WDT_{时钟频率} }
$$
WDT 溢出前可设置的最长定时时间为:2^16 x 2^7 / 32kHz = ~262 seconds

2.1 配置及使用

  1. 软件看门狗的配置
void WDT_INITIAL(void){
    CLRWDT();
    MISC0=0B00000000;            //看门狗时钟LIRC 32kHz
    WDTCON=0B00001011;            //打开看门狗,预分频1:1,定时器周期1:1024,即看门狗周期为32ms
}
  1. 喂狗
CLRWDT();
  1. 放狗/收狗

SWDTEN = 1; //当 WDTE 选择由 SWDTEN 控制时:1 = WDT 使能/0 = WDT 关闭

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇