所以这可能会带来更多的问题而不是答案。我完全能够证明PFSWAP有时会以1的速度启动。肯的数据表指出PFSWIT的初始值是未定义的,这让我想到了我的方法。与MZ DA芯片相匹配,保证启动时PFSWAP为0,我认为最好在启动时强制PFSWATE为0。无论如何,为了证明,我把这个代码放在AppIn初始化中:这个代码将在SysSyrimalItdit中执行,并且将在对BooLoad Services任务的任何调用之前发生,其中包含调用EntLyApvest:唯一调用SWAPFlash面板的函数,因此调用PLIPYNVMY程序Flash BANK2LUVER区域的唯一函数。这就提出了以下问题:如果在启动时PFSWAP是1,那么对SynLead应用程序中的以下代码段会有什么影响:宏扩展到这个(LoeReFaseIdBaseBaseAddio= 0x9D900My):在EngIn应用程序中交换面板的决定基于以下内容:我们可以合作吗?但是,假设PFSWAP的状态,在这两种情况下,LoeLer-Flash ID和UpPurFlash ID都是从同一点读取的?我不知道我们可以,但我也不是一个关于虚拟到物理宏的专家。如果这带来了问题,那么修复很简单:交换面板,使PFSWIT为0,因为它将在一个电源周期。这个解决方案的优点是:如果它不是问题,那么代码将永远不会被执行,如果它是,那么我们知道PFSWAP将在正确的状态之前,任何闪存面板操作。因此,在EngILL应用程序中,微芯片的面板切换逻辑,只要使用一个电源周期就可以很好地工作,它具有正确的逻辑,不需要修改。这是我在没有问题的情况下开始使用的;我上面的尝试并没有起作用(正如我今天早上发现的),因为我认为PFSWAP在启动螺钉上设置了Flash ID逻辑。我修改了SavaFlash面板函数(类似于前一篇文章),Studio应用程序(以反映SavaFlash面板现在采取布尔参数),并且BooDouthRoLi初始化(现在包含一个简单的if语句,如果PFSWAP是1,交换面板)。再次感谢肯!
以上来自于百度翻译
以下为原文
So this will probably add more questions than answers, but here goes. I have been absolutely able to prove that some times PFSWAP will start up as 1. Ken's point about the datasheet stating that the initial value for PFSWAP being undefined got me thinking about my approach. Couple that with the MZ DA chips guaranteeing that PFSWAP is 0 at startup, I figured it would be better to FORCE PFSWAP to 0 on startup.
Anyway, for proof, I put this code in APP_Initialize:
if (PLIB_NVM_ProgramFlashBank2IsLowerRegion(NVM_ID_0))
while (1);
This code will execute in SYS_Initialize and will occur before any calls to Bootloader_Tasks, which contains a call to Enter_Application: the only function that calls SwapFlashPanels, and thus the only function that calls PLIB_NVM_ProgramFlashBank2LowerRegion.
Sure enough the program would lock up in the while loop. This raises the following question: if PFSWAP is 1 at startup, what does this do to the following section of code in Enter_Application:
T_FLASH_ID *lower_flash_id = LOWER_FLASH_ID_READ;
T_FLASH_ID *upper_flash_id = UPPER_FLASH_ID_READ;
The macros expand to this (LOWER_FLASH_ID_BASE_ADDRESS = 0x9D000000 in my case):
#define LOWER_FLASH_ID_READ ((T_FLASH_ID *)KVA0_TO_KVA1(LOWER_FLASH_ID_BASE_ADDRESS))
#define UPPER_FLASH_ID_READ ((T_FLASH_ID *)KVA0_TO_KVA1(UPPER_FLASH_ID_BASE_ADDRESS))
The decision to swap panels in Enter_Application is based on the following:
if(upper_flash_id->flash_id > lower_flash_id->flash_id)
{
SwapFlashPanels(true);
}
Can we conclude that, given the state of PFSWAP, that lower_flash_id and upper_flash_id are reading from the same spot in both cases? I don't know that we can, but I'm also not an expert regarding the virtual to physical macros.
If this poses a problem then the fix is simple: swap the panels such that PFSWAP is 0, as it would be on a power cycle. The beauty of this solution is this: if it's not a problem then the code will never be executed, and if it is then we know that PFSWAP will be in the correct state before any flash panel manipulation. Thus Microchip's panel switching logic in Enter_Application, which works very well as long as a power cycle is used, has the correct logic and need not be modified.
Here is what I have started using without issues; my above attempt didn't work as well (as I found this morning) because I think having PFSWAP set on start up screws with the flash ID logic. I modified the SwapFlashPanels function (similar to a previous post), Enter_Application (to reflect that SwapFlashPanels now takes a boolean argument), and Bootloader_Initialize (now contains a simple if statement that swaps the panels if PFSWAP is 1).
Thanks again Ken!
#if(BOOTLOADER_LIVE_UPDATE_SWITCHER == 1)
/********************************************************************
* Function: SwapFlashPanels()
*
* Precondition:
*
* Input: Boolean indicating Program Flash Bank 2 is to be mapped
* to the lower mapped region.
*
* Output:
*
* Side Effects:
*
* Overview: The function will swap the flash panels in a safe
* place.
*
*
* Note: This is placed in the .cache_init section in order
* to have it in boot flash rather than program flash.
********************************************************************/
void __longcall__ __attribute__ ((section (".cache_init"))) SwapFlashPanels(bool panel2)
{
PLIB_NVM_MemoryModifyInhibit(NVM_ID_0);
PLIB_NVM_FlashWriteKeySequence(NVM_ID_0, NVM_PROGRAM_UNLOCK_KEY1);
PLIB_NVM_FlashWriteKeySequence(NVM_ID_0, NVM_PROGRAM_UNLOCK_KEY2);
if (panel2)
{
PLIB_NVM_ProgramFlashBank2LowerRegion(NVM_ID_0);
}
else
{
PLIB_NVM_ProgramFlashBank1LowerRegion(NVM_ID_0);
}
}
#endif
#if(BOOTLOADER_LIVE_UPDATE_STATE_SAVE != 1)
/********************************************************************
* Function: Enter_Application()
*
* Precondition:
*
* Input: None.
*
* Output:
*
* Side Effects: No return from here.
*
* Overview: The function will program the checksum for the respective
* flash panel and jumps to application programmed in it.
*
*
* Note:
********************************************************************/
static void Enter_Application(void)
{
void (*fptr)(void);
/* Set default to APP_RESET_ADDRESS */
fptr = (void (*)(void))APP_RESET_ADDRESS;
#if(BOOTLOADER_LIVE_UPDATE_SWITCHER == 1)
T_FLASH_ID *lower_flash_id = LOWER_FLASH_ID_READ;
T_FLASH_ID *upper_flash_id = UPPER_FLASH_ID_READ;
SYS_DEVCON_InstructionCacheFlush();
/* Application has been programmed first time into flash panel 1 by the bootloader */
if( *(uint32_t *)LOWER_FLASH_ID_READ == FLASH_ID_CHECKSUM_CLR &&
*(uint32_t *)UPPER_FLASH_ID_READ == FLASH_ID_CHECKSUM_CLR)
{
/* Program Checksum and initial ID's for both panels*/
T_FLASH_ID low_flash_id = { 0 };
T_FLASH_ID up_flash_id = { 0 };
low_flash_id.flash_id = 1;
low_flash_id.checksum_start = FLASH_ID_CHECKSUM_START;
low_flash_id.checksum_end = FLASH_ID_CHECKSUM_END;
up_flash_id.flash_id = 0;
up_flash_id.checksum_start = FLASH_ID_CHECKSUM_START;
up_flash_id.checksum_end = FLASH_ID_CHECKSUM_END;
APP_NVMQuadWordWrite((void *)LOWER_FLASH_ID_BASE_ADDRESS, (uint32_t *)&low_flash_id);
APP_NVMQuadWordWrite((void *)UPPER_FLASH_ID_BASE_ADDRESS, (uint32_t *)&up_flash_id);
}
/* If both the panels have proper checksum*/
else if((lower_flash_id->checksum_start == FLASH_ID_CHECKSUM_START) &&
(lower_flash_id->checksum_end == FLASH_ID_CHECKSUM_END) &&
(upper_flash_id->checksum_start == FLASH_ID_CHECKSUM_START) &&
(upper_flash_id->checksum_end == FLASH_ID_CHECKSUM_END))
{
if(upper_flash_id->flash_id > lower_flash_id->flash_id)
{
SwapFlashPanels(true);
}
}
/* Fallback Cases when either of Panels checksum is corrupted*/
else if((upper_flash_id->checksum_start == FLASH_ID_CHECKSUM_START) &&
(upper_flash_id->checksum_end == FLASH_ID_CHECKSUM_END))
{
SwapFlashPanels(true);
}
#endif // BOOTLOADER_LIVE_UPDATE_SWITCHER == 1
/* Disable Global Interrupts and Jump to Application*/
PLIB_INT_Disable(INT_ID_0);
if (bootloaderData.StartAppFunc != NULL)
bootloaderData.StartAppFunc();
fptr();
}
#endif // BOOTLOADER_LIVE_UPDATE_STATE_SAVE != 1
/******************************************************************************
Function:
SYS_MODULE_OBJ Bootloader_Initialize(const SYS_MODULE_INDEX moduleIndex,
const SYS_MODULE_INIT * const moduleInit)
Summary:
Initializes primitive data structures for the general features
of the primitive layer.
Description:
Initializes external and internal data structure for the general
features of the primitive layer.
This function must be called at system initialization.
Remarks:
None.
*/
void Bootloader_Initialize ( const BOOTLOADER_INIT *drvBootloaderInit )
{
#if(BOOTLOADER_LIVE_UPDATE_SWITCHER == 1)
if (PLIB_NVM_ProgramFlashBank2IsLowerRegion(NVM_ID_0))
{
SwapFlashPanels(false);
}
#endif
/* Place the App state machine in it's initial state. */
bootloaderData.currentState = BOOTLOADER_CHECK_FOR_TRIGGER;
bootloaderData.cmdBufferLength = 0;
bootloaderData.streamHandle = DRV_HANDLE_INVALID;
bootloaderData.datastreamStatus = DRV_CLIENT_STATUS_ERROR;
bootloaderData.usrBufferEventComplete = false;
bootloaderData.data = &data_buff;
bootloaderData.type = drvBootloaderInit->drvType;
#ifdef BOOTLOADER_LEGACY
BootloaderTriggerCheck = drvBootloaderInit->drvTrigger;
#endif
bootloaderData.FlashEraseFunc = (BOOTLOADER_CALLBACK)NULL;
bootloaderData.StartAppFunc = (BOOTLOADER_CALLBACK)NULL;
bootloaderData.BlankCheckFunc = (BOOTLOADER_CALLBACK)NULL;
bootloaderData.ProgramCompleteFunc = (BOOTLOADER_CALLBACK)NULL;
bootloaderData.ForceBootloadFunc = (BOOTLOADER_CALLBACK)NULL;
bootloaderData.softReset = (SYS_RESET_ReasonGet() & RESET_REASON_SOFTWARE) == RESET_REASON_SOFTWARE;
#if(BOOTLOADER_LIVE_UPDATE_STATE_SAVE != 1)
SYS_RESET_ReasonClear(RESET_REASON_SOFTWARE);
/* Delay to allow the internal pullups to stabilize */
_CP0_SET_COUNT(0);
while (_CP0_GET_COUNT() < SYS_CLK_FREQ / 5000);
#endif
}