pyOCD
pyOCD copied to clipboard
"reset" to nRF52840 does not reset everything
Currently playing around with Sysview...
After flashing the test program below via pyocd to a nRF52840 target, DWT->CYCCNT is initialized and running as expected. After issuing a reset command via pyocd with the same firmware in flash, CYCCNT is not running. Specifying the reset mode does not help.
Doing a reset with openocd, CYCCNT is running as expected.
Investigating a little bit further showed, that inserting a delay in main() before init of CYCCNT solves the problem.
Is order of init / disconnect wrong?
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
//#include "SEGGER_RTT.h"
#include "SEGGER_SYSVIEW.h"
static void _Delay(int period)
{
volatile int i = (100000 / 17) * period;
do {
;
} while (i--);
} // _Delay
#define SYSVIEW_DEVICE_NAME "PCA10056 Cortex-M4"
#define SYSVIEW_APP_NAME "SysView Games"
/* DWT (Data Watchpoint and Trace) registers, only exists on ARM Cortex with a DWT unit */
#define KIN1_DWT_CONTROL (*((volatile uint32_t*)0xE0001000))
/*!< DWT Control register */
#define KIN1_DWT_CYCCNTENA_BIT (1UL<<0)
/*!< CYCCNTENA bit in DWT_CONTROL register */
#define KIN1_DWT_CYCCNT (*((volatile uint32_t*)0xE0001004))
/*!< DWT Cycle Counter register */
#define KIN1_DEMCR (*((volatile uint32_t*)0xE000EDFC))
/*!< DEMCR: Debug Exception and Monitor Control Register */
#define KIN1_TRCENA_BIT (1UL<<24)
/*!< Trace enable bit in DEMCR register */
#define KIN1_InitCycleCounter() KIN1_DEMCR |= KIN1_TRCENA_BIT
/*!< TRCENA: Enable trace and debug block DEMCR (Debug Exception and Monitor Control Register */
#define KIN1_ResetCycleCounter() KIN1_DWT_CYCCNT = 0
/*!< Reset cycle counter */
#define KIN1_EnableCycleCounter() KIN1_DWT_CONTROL |= KIN1_DWT_CYCCNTENA_BIT
/*!< Enable cycle counter */
#define KIN1_DisableCycleCounter() KIN1_DWT_CONTROL &= ~KIN1_DWT_CYCCNTENA_BIT
/*!< Disable cycle counter */
#define KIN1_GetCycleCounter() KIN1_DWT_CYCCNT
/*!< Read cycle counter register */
static void _cbSendSystemDesc(void) {
SEGGER_SYSVIEW_SendSysDesc("N=" SYSVIEW_APP_NAME ",D=" SYSVIEW_DEVICE_NAME ",O=None");
SEGGER_SYSVIEW_SendSysDesc("I#15=SysTick");
}
void SEGGER_SYSVIEW_Conf(void)
{
//SEGGER_RTT_Init();
KIN1_InitCycleCounter();
KIN1_ResetCycleCounter();
KIN1_EnableCycleCounter();
SEGGER_SYSVIEW_Init(64000000, 64000000, NULL, _cbSendSystemDesc);
SEGGER_SYSVIEW_SetRAMBase(0x20000000);
} // SEGGER_SYSVIEW_Conf
int main()
{
//_Delay(200); // this delay is required to have a running CYCCNT after reset
SEGGER_SYSVIEW_Conf();
SEGGER_SYSVIEW_Start();
SEGGER_SYSVIEW_EnableEvents(0xffff);
_Delay(222);
SEGGER_SYSVIEW_Error("Start\n");
for (int i = 0; i < 30; ++i) {
SEGGER_SYSVIEW_MarkStart(0x1111);
SEGGER_SYSVIEW_MarkStart(0x3333);
SEGGER_SYSVIEW_WarnfTarget("cyccnt %d %u\n", i, KIN1_GetCycleCounter());
SEGGER_SYSVIEW_MarkStop(0x3333);
SEGGER_SYSVIEW_MarkStart(0x2222);
_Delay(87);
SEGGER_SYSVIEW_MarkStop(0x2222);
SEGGER_SYSVIEW_MarkStop(0x1111);
}
SEGGER_SYSVIEW_DisableEvents(0xffff);
SEGGER_SYSVIEW_Print("Stop\n");
SEGGER_SYSVIEW_Stop();
for (;;) {
}
} // main
Hi @rgrr
I'm pretty sure I know what it is… Currently on disconnect, DEMCR.TRCENA
is written to 0 to disable extra debug logic, including DWT
. During connect, there would be some delay before DEMCR.TRCENA
is set to 1. The exact timing and sequence of events, I'm not sure about without fully reproducing your setup.
This should only happen if you are calling pyocd reset
or equivalent, so that it's performing a full connect/disconnect sequence. Doing a reset while pyocd remains connected, eg in gdb, should not affect debug logic at all.
There are two related changes that should probably be made:
- Don't clear
DEMCR.TRCENA
if theresume_on_disconnect
option is False (default is True). - Add an option to not clear
DEMCR.TRCENA
on disconnect. In many cases this should be cleared, so that the device is restored to non-debug mode and debug logic isn't consuming power.
Short term, you could add a line to your code to write DEMCR.TRCENA
to 1. (It should actually do this anyway, to guarantee availability of DWT.)
See #1541 for a patch that changes this. Just the first of the two changes above. On second thought, it might be best to leave the second change to a user script via the stop_core_debug
delegate function.
In the process, I realised an issue with the debug sequence support I just merged: the DebugCoreStop
standard sequence assumes that DHCSR
and DEMCR
must be cleared, therefore resuming the core and disabling debug logic, making it incompatible with leaving the core halted on disconnect. 😄
Hello Chris
I have pulled the version of #1541 and tested reset with both -Oresume_on_disconnect=false/true
. No success. CYCCNT
is always stuck.
In my code TRCENA
is already set. It is hidden in the function macro KIN1_InitCycleCounter()
.
Any suggestions what to test further?
Hmm, that's unfortunate. Still #1541 was a useful change, so thanks for helping identify it.
What doesn't make sense here is why your code in SEGGER_SYSVIEW_Conf()
doesn't always successfully enable the cycle counter. Regardless of what pyocd is doing during connection, this should work. (Because both pyocd and your code are performing read-modify-writes of DEMCR
and DWT_CTRL
, there's a possibility of concurrency issues, but that would probably be very intermittent.) So there must be something in the usage sequence that I'm missing.
What are the sequence of pyocd commands that you are using? If you have a project with this code that you could attach, that would also be helpful.
Yes, you are right, it is weird, that CYCCNT is not running. Even more that it is stuck at some value. Could it be possible, that pyOCD starts the target and after that clears the TRCENA bit? Or would the counter value than again zero?
I'm issuing just a simple "pyocd reset -t nrf52840"
Example project is here: https://github.com/rgrr/playground/tree/feature/xray/tools/SystemView
Pyocd doesn't clear TRCENA anywhere except on exit, as we've discussed. All other places where it writes DEMCR (mostly related to vector catch) use read-modify-writes with masks to set/clear bits, so won't touch TRCENA.
CYCCNT would be stuck if it had been running at some point, then DWT_CTRL.CYCCNTEN is cleared. I think the effect of clearing TRCENA in that case will vary depending on the special CPU variant and MCU clocking design, not entirely sure.
Thanks for the project link.