Cortex-M7s in Atmel Studio 7.0.1417, debugging failure and TCM configuration/linker mismatch

There was a subtle bug introduced in Atmel Studio 7.0.1417 when attempting to debug a Cortex-M7 (SAME70,SAMS70,SAMV70). The programmer will alter the GPNVMBITs without user action and reason. This also reveals a problem with the default linker script that Atmel provides.

What is the bug?

The programmer changes the GPNVMBITs value to 0x82 everytime you go to debug.

You can view the GPNVMBITs using the Device Programming window like this:

In particular to note, you want to look at and be changing the GPNVMBITS register in the bottom panel rather than the top panel with the BOOT_MODE checkbox. The top panel is missing the problem causing settings (not that’ll matter being able to see it :/)

Why does this cause problems?

The SAME70 GPNVMBITS contains 2 control bits in bits 7:6, these two bits configure the TCM interface (Tightly Coupled Memory) which is a feature of the Cortex-M7 core itself. The TCM can be used to gain enhanced memory access performance for the core if configured properly both in fuse bits and in firmware. But the trade off is you lose access to chunks of “normal” SRAM that your firmware may still want at the “normal” addresses.

The definition for the control bits is from this table which comes from the AT14971 app note.:

The default value for GPNVMBITS on a fresh microcontroller is 0x42. Bit 1 being set (0x02) causes it to boot to flash. Bit 6 being set configures the TCM to make 320KB of SRAM available.

What happens when the programmer alters the value automatically?

It sets the GPNVMBITs configuration to 0x82. Boot to flash is still set but Bit 7 being set and bit 6 being cleared results in only 256 KB of sram being available. The immediate symptom should be your firmware gets stuck in the startup code in the simple relocate section copy loop:

for (; pDest < &_erelocate;) {
		*pDest++ = *pSrc++;
}

because the SRAM addresses it tries to copy to are no longer valid due to TCM setting, the microcontroller simply gets stuck. The default watchdog configuration being “on” will cause the micro to keep resetting, hitting the invalid memory address and repeating. It could be possible your firmware doesn’t immediately get stuck here because GCC did not allocate a variable in the now off-limits SRAM area.

Workarounds?

  1. Downgrade to 7.0.1188, there is no way to avoid the debugging process from constantly changing GPNVMBITS back to 0x82 from whatever value you may have
  2. Fix the linker script to match the 0x82 configuration. This means limiting the SRAM to 256KB in length. But be warned, if they ever fix it, you’ll have to handle the default in a reprogramming step later on. Not a big deal as this should be part of any normal production flow to set the fuse byte.
  3. Modify the startup_same70.c, in particular Reset_Handler function. Before the relocate segment is copied, check if GPNVMbits are not set and use the EEFC peripheral to program the GPNVM bits in firmware and trigger a reset for them to take effect

What’s the issue with the linker script that Atmel provides?

Atmel’s default linker script declares 384KB of SRAM. However the default fuse byte setting is 0x42. Which means the micro only has 320KB of SRAM available. This will result in odd behavior if your firmware build under GCC decides to start allocating variables in the upper memory ranges. Either you correct the linker script to 320KB or you change the GPNVMBITS value to 0x02 which will give you maximum SRAM (384KB).

comments powered by Disqus