我在获取PIC32MX795F512L的引导加载程序时遇到问题。
我的基础是微芯片网站上的示例代码。
以下是我应该编写内存的代码部分,到目前为止我已经验证了引导加载程序(解析hex文件很好,数据到达这一点但不会写入内存):< / p>
#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
无法告诉您所有位的功能,但闪存位设置为可写且禁用了代码保护。
答案 0 :(得分:4)
闪存与普通RAM的工作方式不同。为了写入它,首先需要擦除要写入的块。这会将块中的所有位设置为1.然后,您可以使用编程操作将1位更改为0位。没有写操作将位设置为0或1,您必须组合这两个操作才能获得相同的效果。
请注意,可以在不先擦除的情况下执行编程操作。它仍将工作,它将1位更改为0位。但是,由于它无法将已编程的0位更改为1位,因此您可能无法获得所需的结果。
需要注意的一点是擦除操作会损坏闪存,慢慢磨损。 datasheet for your controller仅列出失败前至少1000次擦除/写入周期。这对于定期固件更新和配置值来说已经足够了,但如果您使用它来存储经常更新的数据,则可能还不够。
答案 1 :(得分:2)
解决方案(感谢Ross Ridge): 如此隐藏在数据表中的注释中有一个页面擦除命令的注释,表示在写入之前需要擦除内存。
添加以下内容以解决问题(在执行任何内存写入之前调用命令):
#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