3

我在获取 PIC32MX795F512L 工作的引导加载程序时遇到问题。

我基于微芯片网站上的示例代码。

这是我应该写入内存的代码部分,到目前为止我已经验证了引导加载程序(解析十六进制文件很好,数据到达这一点但没有写入内存):

#define NVMOP_WORD_PGM          0x4001 


// Write the data into flash.   
Result = NVMemWriteWord(ProgAddress, WrData);   
// Assert on error. This must be caught during debug phase.
if(Result != 0)
{       
    ASSERT(Result==0);
}

UINT NVMemWriteWord(void* address, UINT data)
{
    UINT res;

    NVMADDR = KVA_TO_PA((unsigned int)address);

    // Load data into NVMDATA register
    NVMDATA = data;

    // Unlock and Write Word
    res = NVMemOperation(NVMOP_WORD_PGM);

    return res;
}

UINT __attribute__((nomips16)) NVMemOperation(UINT nvmop)
{
    int int_status;
    int susp;

    // Disable DMA & Disable Interrupts
    #ifdef _DMAC
    int_status = INTDisableInterrupts();
    susp = DmaSuspend();
    #else
    int_status = INTDisableInterrupts(); 
    #endif  // _DMAC

    // Enable Flash Write/Erase Operations
    NVMCON = nvmop;//NVMCON_WREN | nvmop;
    // Data sheet prescribes 6us delay for LVD to become stable.
    // To be on the safer side, we shall set 7us delay.
    delay_us(7);

    NVMKEY      = 0xAA996655;
    NVMKEY      = 0x556699AA;
    NVMCONSET   = NVMCON_WR;

    // Wait for WR bit to clear
    while(NVMCON & 0x8000);//NVMCON_WR);

    // Disable Flash Write/Erase operations
    NVMCONCLR = NVMCON_WREN;  


    // Enable DMA & Enable Interrupts
    #ifdef _DMAC
    DmaResume(susp);
    INTRestoreInterrupts(int_status);
    #else
    INTRestoreInterrupts(int_status);
    #endif // _DMAC

    // Return Error Status
    return(NVMemIsError());
}

正在加载的程序地址示例为:0x9D033358,数据为 2403000E

配置位在代码中设置,如下所示:

地址设置

1FC02FF0 FCFFFFFF

1FC02FF4 FFF8FFDF

1FC02FF8 FF69CC5B

1FC02FFC 7FFFFFFF

无法告诉您所有位的作用,但闪存位设置为可写并且代码保护已禁用。

4

2 回答 2

5

闪存的工作方式与普通 RAM 不同。为了写入它,您首先需要擦除要写入的块。这会将块中的所有位设置为 1。然后您可以使用程序操作将 1 位更改为 0 位。没有将位设置为 0 或 1 的写操作,您必须将这两个操作结合起来才能获得相同的效果。

请注意,可以在不先擦除的情况下执行编程操作。从将 1 位变为 0 位的意义上说,它仍然可以工作。但是,由于它不能将已经编程的 0 位更改为 1 位,因此您可能不会得到您想要的结果。

需要注意的一件事是擦除操作会损坏闪存,慢慢磨损它。您的控制器的数据表仅列出了故障前至少 1000 次擦除/写入周期。这对于定期固件更新和配置值来说绰绰有余,但如果您使用它来存储频繁更新的数据,则可能还不够。

于 2014-07-18T15:43:40.903 回答
2

解决方案(感谢 Ross Ridge): 在数据表注释中,有一条带有 Page erase 命令的注释说你需要在写入之前擦除内存。

添加了以下内容来解决问题(在执行任何内存写入之前调用命令):

#define FLASH_PAGE_SIZE 4096
void StartLoad(void)
{
    int Address = APP_FLASH_BASE_ADDRESS;

    RxBuff.Len = 0;

    while((Address + FLASH_PAGE_SIZE) <= APP_FLASH_END_ADDRESS)
    {
        NVMemErasePage(Address);
        Address += FLASH_PAGE_SIZE;
    }
}

UINT NVMemErasePage(void* address)
{
    UINT res;

    // Convert Address to Physical Address
    NVMADDR = KVA_TO_PA((unsigned int)address);

    // Unlock and Erase Page
    res = NVMemOperation(NVMOP_PAGE_ERASE);

    // Return WRERR state.
    return res;

}

以下链接也很有帮助,它在第 10 页和第 11 页列出了所有 Pic32 的闪存页面大小: http ://ww1.microchip.com/downloads/en/DeviceDoc/61145K.pdf

于 2014-09-23T15:05:00.513 回答