carmembeddedclockbare-metal

Undefined instruction MRS on bare metal


I want to run simple test code in C on the Renesas Synergy R7FS5D97E evaluation board (Cortex M4). I made a sample project + SDK and toolchain projects using official materials, successfully built and flashed it using Ozone debugger.

However, when I run it, an exception is raised on startup: HardFault with undefined instruction flag when executing MRS R1, PRIMASK in function R_BSP_RegisterProtectEnable.

It'd be understandable if it happened the first time this instruction was executed, but it's not - in fact, it's about 15th time this instruction (in this exact function and even the same value of PRIMASK register) is executed during the program's run, so it can't be simply unsupported on this hardware.

I managed to trace where the error happens: the call of R_BSP_RegisterProtectEnable/HW_CGC_HardwareLock right after SystemInit (system_S5D9.c:171) -> bsp_clock_init (bsp_clocks.c:150) -> R_CGC_SystemClockSet (r_cgc.c:707) -> r_cgc_system_dividers_set (r_cgc.c:2637), so I'm wondering if it could be some kind of clock configuration problem? In Ozone, I'm simply using default settings offered for this board.

Alternatively, I could've made a mistake in preparing this SDK and toolchain - I had to manually cobble together a pure Conan+CMake project from Renesas configuration files and perhaps I missed something. Still, it doesn't make sense for this specific instruction to fail. It's simply copying a special register value to a general register.

I've run the same kind of thing on a different Renesas Synergy board years ago (different SDK and toolchain files), and had my fair share of trouble there, but never this - and it worked in the end.

Attached system state before the error and the HardFault details from Ozone since I can't copy it as text.

SDK project, toolchain project; I don't think the sample project matters as the error happens during startup, but I can upload it if needed.

UPD: The error happens when setting ICLK divider and clock source in this branch. Clock source is set first in function r_cgc_clock_source_set, that calls R_BSP_RegisterProtectDisable, performs a store and calls R_BSP_RegisterProtectEnable. The first instruction in R_BSP_RegisterProtectEnable is MRS R1, PRIMASK, which executes successfully here. Assembly (inlined function):

LDR.W          R8, [R7, #28]
BL             R_BSP_RegisterProtectDisable
LDRB.W         R3, [R8, #38]
BFI            R3, R6, #0, #3
MOV            R0, R5
STRB.W         R3, [R8, #38]
BL             R_BSP_RegisterProtectEnable

Then the function r_cgc_system_dividers_set is called (source link). Assembly (this time non-inline):

LDR            R0, [R7, #28]
MOV            R1, R4
BL             r_cgc_system_dividers_set
~~~
PUSH           {R4-R6, LR}
LDRB           R2, [R1]
LDRB           R3, [R1, #1]
LDRB           R6, [R1, #2]
LDRB           R5, [R1, #3]
MOVS           R4, #0
AND            R3, R3, #7
BFI            R4, R2, #12, #3
LDR            R2, =gp_cgc_feature           ; [PC, #64] [0x00001CC0] =0x1FFE0214 
BFI            R4, R3, #8, #3
LDR            R2, [R2]
BFI            R4, R6, #4, #3
LDRB           R6, [R1, #4]
LDRB.W         R2, [R2, #42]
BFI            R4, R5, #0, #3
LDRB           R5, [R1, #5]
LDRB           R1, [R1, #6]
BFI            R4, R6, #16, #3
BFI            R4, R5, #28, #3
BFI            R4, R1, #24, #3
MOV            R5, R0
LSLS           R2, R2, #29
IT             MI
BFIMI          R4, R3, #16, #3
MOVS           R0, #0
BL             R_BSP_RegisterProtectDisable
STR            R4, [R5, #32]
MOVS           R0, #0
POP.W          {R4-R6, LR}
B.W            R_BSP_RegisterProtectEnable

This time, the first instruction MRS R1, PRIMASK in R_BSP_RegisterProtectEnable throws the undefined instruction error instead.

It's really starting to stink of bad clock configuration, but this code is downloaded from Renesas website for this exact device so I don't dare tinker with it unless I know exactly what to do. Hence my question.

UPD2: Internal clock divider in bsp_clock_cfg.h didn't match the manufacturer's files! Either I made a typo or reused a file from a different project, and didn't notice a problem because /1 seems like an ok internal clock divider, but changing it to /2 fixed this error. Perhaps it was causing instruction fetch/prefetch from flash to only finish after attempted decode...

Note that this file is normally auto-generated by Renesas software from XML configs (which include default values). I found those XMLs but needed to manually create headers with all required macros from them.

Thanks to everyone for the brainstorm session!


Solution

  • Internal clock divider needed to be set to CGC_SYS_CLOCK_DIV_2 (default from manufacturer's XML configs) instead of CGC_SYS_CLOCK_DIV_1. I made some mistake when creating the SDK.