Skip to content
Snippets Groups Projects
Commit 493f363d authored by Micah Elizabeth Scott's avatar Micah Elizabeth Scott
Browse files

Cleaner and more reliable reset+halt

Now works even when the CPU is stuck in a watchdog reset loop, as it would be when the flash is totally blank.
parent 77bb6f19
No related branches found
No related tags found
No related merge requests found
......@@ -587,3 +587,15 @@ void ARMDebug::log(int level, const char *fmt, ...)
Serial.println(buffer);
}
}
void ARMDebug::setLogLevel(LogLevel newLevel)
{
logLevel = newLevel;
}
void ARMDebug::setLogLevel(LogLevel newLevel, LogLevel &prevLevel)
{
prevLevel = logLevel;
logLevel = newLevel;
}
......@@ -62,6 +62,10 @@ public:
// Poll for an expected value
bool memPoll(unsigned addr, uint32_t &data, uint32_t mask, uint32_t expected, unsigned retries = DEFAULT_RETRIES);
// Change log levels, optionally returning the old level so it can be restored.
void setLogLevel(LogLevel newLevel);
void setLogLevel(LogLevel newLevel, LogLevel &prevLevel);
private:
uint8_t clockPin, dataPin;
LogLevel logLevel;
......
......@@ -48,61 +48,79 @@ bool ARMKinetisDebug::detect()
bool ARMKinetisDebug::resetHalt()
{
uint32_t status, dhcsr;
// System resets can be slow, give them more time than the default.
const unsigned resetRetries = 2000;
// Keep trying to reset/halt, in case we're fighting with watchdog timer :(
unsigned outerRetries = 50;
// Put the control register in a known state, and make sure we aren't already in the middle of a reset
uint32_t status;
if (!apWrite(REG_MDM_CONTROL, REG_MDM_CONTROL_CORE_HOLD_RESET))
return false;
if (!apReadPoll(REG_MDM_STATUS, status, REG_MDM_STATUS_SYS_NRESET, -1, resetRetries))
return false;
while (outerRetries--) {
// System reset
if (!apWrite(REG_MDM_CONTROL, REG_MDM_CONTROL_SYS_RESET_REQ))
return false;
if (!apReadPoll(REG_MDM_STATUS, status, REG_MDM_STATUS_SYS_NRESET, 0))
return false;
if (!apWrite(REG_MDM_CONTROL, 0))
return false;
// Put the control register in a known state, and make sure we aren't already in the middle of a reset
if (!apWrite(REG_MDM_CONTROL, REG_MDM_CONTROL_CORE_HOLD_RESET))
continue;
if (!apReadPoll(REG_MDM_STATUS, status, REG_MDM_STATUS_SYS_NRESET, -1, resetRetries))
continue;
// Wait until the flash controller is ready & system is out of reset.
// Also wait for security bit to be cleared. Early in reset, the chip is determining
// its security status. When the security bit is set, AHB-AP is disabled.
if (!apReadPoll(REG_MDM_STATUS, status,
REG_MDM_STATUS_SYS_NRESET | REG_MDM_STATUS_FLASH_READY | REG_MDM_STATUS_SYS_SECURITY,
REG_MDM_STATUS_SYS_NRESET | REG_MDM_STATUS_FLASH_READY,
resetRetries))
return false;
// System reset
if (!apWrite(REG_MDM_CONTROL, REG_MDM_CONTROL_SYS_RESET_REQ))
continue;
if (!apReadPoll(REG_MDM_STATUS, status, REG_MDM_STATUS_SYS_NRESET, 0))
continue;
if (!apWrite(REG_MDM_CONTROL, 0))
continue;
// Set up CSW, no auto-increment.
if (!apWrite(MEM_CSW, CSW_DBGSWENABLE | CSW_MASTER_DEBUG | CSW_HPROT | CSW_32BIT | CSW_ADDRINC_OFF))
return false;
// Wait until the flash controller is ready & system is out of reset.
// Also wait for security bit to be cleared. Early in reset, the chip is determining
// its security status. When the security bit is set, AHB-AP is disabled.
if (!apReadPoll(REG_MDM_STATUS, status,
REG_MDM_STATUS_SYS_NRESET | REG_MDM_STATUS_FLASH_READY | REG_MDM_STATUS_SYS_SECURITY,
REG_MDM_STATUS_SYS_NRESET | REG_MDM_STATUS_FLASH_READY,
resetRetries))
continue;
// Point at the debug halt control/status register
if (!apWrite(MEM_TAR, REG_SCB_DHCSR))
return false;
// Re-initialize the AHB-AP after reset
if (!initMemPort())
continue;
/*
* Enable debug, request a halt, and read back status.
*
* This part is somewhat timing critical, since we're racing against the watchdog
* timer. Avoid memWait() by calling the lower-level interface directly.
*
* Since this is expected to fail a bunch before succeeding, mute errors temporarily.
*/
unsigned haltRetries = 200;
LogLevel savedLogLevel;
uint32_t dhcsr;
// Enable debugging
if (!memStore(REG_SCB_DHCSR, 0xA05F0001))
setLogLevel(LOG_NONE, savedLogLevel);
while (haltRetries) {
haltRetries--;
if (!apWrite(MEM_DRW, 0xA05F0003))
continue;
if (!apRead(MEM_DRW, dhcsr))
continue;
unsigned haltRetries = 50;
while (haltRetries--) {
// Request a halt, and read back status
if (!memStore(REG_SCB_DHCSR, 0xA05F0003))
break;
if (!memLoad(REG_SCB_DHCSR, dhcsr))
break;
if (dhcsr & (1 << 17)) {
// Halted!
return true;
}
if (dhcsr & (1 << 17)) {
// Halted!
break;
}
}
// Restore previous settings
initMemPort();
setLogLevel(savedLogLevel);
if (haltRetries) {
log(LOG_NORMAL, "CPU reset & halt successful. Now in debug mode.");
return true;
}
log(LOG_ERROR, "ARMKinetisDebug: Failed to put CPU in debug halt state. (DHCSR: %08x)", dhcsr);
return false;
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment