[8/16位单片机] PIC 16 单片机 write flash 按照行写 重启后MCU不能正常工作

[复制链接]
503|12
 楼主 | 2019-7-10 13:52 | 显示全部楼层 |阅读模式
本帖最后由 小卡 于 2019-7-12 14:01 编辑

PIC 16 18346 单片机 write flash  按照行写 重启后MCU不能正常工作, 描述如下,求助大神:

按照行(一行32个字)写后,重启后MCU不能正常起来,表现为按照步骤,我一步一步看,有引起反复重启 以及 电流从200MA下降至89MA两种问题:
实现部分:
void test(void)
{
    uint16_t addr = 0x1F00, addr_ram;
    uint16_t i;
    uint16_t max_count=1;
    uart_send_char("start  write\r\n");

    addr_ram = addr;
    for(i=0; i<max_count; i++)
    {
         //when max_count==1, ok,
         //when max_count ==2 , reset all along in some minutes, then 200ma--->89ma
        //when max_count ==80, after reset , 200ma-->89ma
        FLASH_EraseRow(addr_ram);
        FLASH_EraseRow(addr_ram+32);


        //reset all along
        FLASH_WriteRow(addr_ram, test_array);


        addr_ram += 64;
   }
}

void FLASH_EraseRow(uint16_t startAddr)
{
    uint8_t GIEBitValue = INTCONbits.GIE;   // Save interrupt enable

    // Load lower 8 bits of erase address boundary
    NVMADRL = (startAddr & 0xFF);
    // Load upper 6 bits of erase address boundary
    NVMADRH = ((startAddr & 0xFF00) >> 8);

    // Block erase sequence
    NVMCON1bits.NVMREGS = 0;    // Deselect Configuration space
    NVMCON1bits.FREE = 1;    // Specify an erase operation
    NVMCON1bits.WREN = 1;    // Allows erase cycles

    INTCONbits.GIE = 0; // Disable interrupts

    // Start of required sequence to initiate erase
    NVMCON2 = 0x55;
    NVMCON2 = 0xAA;
    NVMCON1bits.WR = 1;      // Set WR bit to begin erase
    NOP();
    NOP();
    NOP();
    NOP();

    INTCONbits.GIE = GIEBitValue;        // Restore interrupt enable
    NVMCON1bits.WREN = 0;       // Disable writes
}


int8_t FLASH_WriteRow(uint16_t writeAddr, uint16_t *flashWordArray)
{
    uint16_t i;
   
    NVMCON1bits.NVMREGS = 0;
   
    //row addr
//    NVMADRL = writeAddr & 0x00e0;
//    NVMADRH = (writeAddr & 0x7f00) >> 8;
    NVMADR = writeAddr & 0x7FE0;
   
    NVMCON1bits.FREE = 0;
    NVMCON1bits.LWLO = 1;
    NVMCON1bits.WREN = 1;
   
    for(i=0; i<32; i++)
    {
//        NVMDATL = *(flashWordArray+i) & 0xff;
//        NVMDATH = (*(flashWordArray+i) >> 8) & 0x3f;
        NVMDAT = *(flashWordArray+i) & 0x3fff;
        
        if (i == 31)
        {
            break;
        }
        
        INTCONbits.GIE = 0;
        
        //unlock
        NVMCON2 = 0x55;
        NVMCON2 = 0xaa;
        NVMCON1bits.WR = 1;
        //unlock
        
        INTCONbits.GIE = 1;
        
        NVMADRL += 1;
    }
   
    NVMCON1bits.LWLO = 0;
    INTCONbits.GIE = 0;
   
    //unlock
    NVMCON2 = 0x55;
    NVMCON2 = 0xaa;
    NVMCON1bits.WR = 1;
    //unlock
   
    NOP();
    NOP();
   
    INTCONbits.GIE = 1;
    NVMCON1bits.WREN = 0;
   
    return 0;
}

使用特权

评论回复
| 2019-7-10 14:44 | 显示全部楼层
帮顶,大神们快来

使用特权

评论回复
| 2019-7-11 09:11 | 显示全部楼层
用工具把整个flash读出来, 然后研究你刚刚操作的那段flash的内容, 看看是不是你期望的,
如果不是期望的就是错的咯, 看看错在哪里, 是地址错了,还是内容有误.
不难找到原因的啊

使用特权

评论回复
 楼主 | 2019-7-11 09:38 | 显示全部楼层
CoolSilicon 发表于 2019-7-11 09:11
用工具把整个flash读出来, 然后研究你刚刚操作的那段flash的内容, 看看是不是你期望的,
如果不是期望的就 ...

直接从菜单  window--->PIC memory views-->program memory看?

使用特权

评论回复
| 2019-7-11 09:45 | 显示全部楼层
不完全是的..
先连上你的 烧录工具, 然后read一下,
839135d26948a7fe33.png

最后才是在program memory里面看你操作的地址及对应内容..

细心一点, 很容易找到问题的..加油!

使用特权

评论回复

评论

yhy08090 2019-7-11 11:02 回复TA
能读整个flash,如有神助,问题解决了,谢谢 还有个地方有问题: 编译提示:Program space used 1AA8h ( 6824) of 4000h words ( 41.7%) 但烧录的时候信息: 以下存储器区域将被编程: 程序存储器: 起始地址 = 0x0, 结束地址 = 0x20df 这0x1aa8--->0x20df之间还有好大一段空白的地方, 这个0x20df能否被更改 
| 2019-7-11 11:11 | 显示全部楼层
@yhy08090
编译提示的占用space,是指生成的代码, 如果一句连一句, 实打实的需要1AA8H这么多条.
但是,实际上, 编译器将这些放到整个ROM区域, 可能不是连续.
我猜你这里想"空白利用"的意思, 或者说, 你是想在ROM拿一段区域出来自行擦写,自行存放数据用..
你可以 在项目属性里面指定 你想要的ROM区域..如下图所示:
看一下注释说明, 应该很清楚用法的哈..
97115d26a8b5961d5.png

使用特权

评论回复
| 2019-7-11 13:46 | 显示全部楼层
看一下flash区域,别写道寄存器地址去了

使用特权

评论回复

评论

yhy08090 2019-7-11 16:49 回复TA
是写到代码空间去了 
| 2019-7-12 14:01 | 显示全部楼层
加分类

使用特权

评论回复
| 2019-7-12 15:29 | 显示全部楼层
楼主解决了的话分享一下, 这种问题我很好奇

使用特权

评论回复
 楼主 | 2019-7-15 15:53 | 显示全部楼层
@CoolSilicon
请教pic里面的32位变量正确的定义和使用方式:
unsigned long int len;
unsigned int lenh, lenl;
lenh = 0x9988;
lenl = 0x7766;
//以上打印出来正确
len = (lenh <<16)|lenl;
lenh = (len & 0xffff0000) >> 16;
lenl = len&0x0000ffff;
//打印出来lenh  lenl分别是0000 FFEE

使用特权

评论回复
 楼主 | 2019-7-15 15:56 | 显示全部楼层
奔波儿熊 发表于 2019-7-12 15:29
楼主解决了的话分享一下, 这种问题我很好奇

擦写地址指向到代码空间了。

使用特权

评论回复
扫描二维码,随时随地手机跟帖
您需要登录后才可以回帖 登录 | 注册

本版积分规则

我要发帖 投诉建议 创建版块 申请版主

快速回复

您需要登录后才可以回帖
登录 | 注册
高级模式

论坛热帖

在线客服 快速回复 返回顶部 返回列表