What Exception when accessing un-clocked peripherals?

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

What Exception when accessing un-clocked peripherals?

1,221 Views
chriscowdery
Contributor V

Hi All,

 As subject - what should happen if you access an unclocked peripheral?

Should you get an exception? or will the core 'hang' ?

Thanks,

Chris.

Labels (1)
9 Replies

1,092 Views
mjbcswitzerland
Specialist V

Chris

You get a hard-fault so ensure that you have a hard fault handler installed so that it doesn't transition to a more serious exception that looks to hang (or jumps back the the ROM Loader).

Regards

Mark

[uTasker project developer for Kinetis and i.MX RT]

1,092 Views
chriscowdery
Contributor V

Hi Mark,

 Are you absolutely sure about that?

I run these lines of code to trigger the exception:

    CLOCK_ControlGate(kCLOCK_Gpio1,kCLOCK_ClockNotNeeded);
    volatile uint32_t t = GPIO1->DR;    // will trigger an exception

My hardfault handler is pretty low rent (and I have tested it fires 'U's out of the UART by just calling it):

HardFault_Handler
        movs    r0, #0x55
        ldr        r1, =0x4018401c    ;LPUART1->DATA
        ldr        r2, =0x40184014    ;LPUART1->STAT
HardFault_loop
        str        r0,[r1]            ; send 'U' out of the uart
Hardfault_wait
        ldr        r3, [r0]
        lsls    r3, r3, #9
        bpl.n    Hardfault_wait
        b        HardFault_loop

I would expect to see lots of U's when I trigger the exception, but I see none!

Word of warning - if you put the trigger code at the top of your project, you'll brick your board unless you still have access to the Serial Downloader. Because it throws the debugger off, each time the debugger resets the board to download new code, it gets thrown off again.

Chris.

0 Kudos

1,092 Views
mjbcswitzerland
Specialist V

Hi Chris

1. From my experience hard-faults always result from un-clocked peripheral access.

2. I always have this code as a part of the processor initialisation:

static void fnWaitDebugger(void)
{
    FOREVER_LOOP() {
        if (WAIT_DEBUGGER_NOT_ACTIVE()) {    // if button is not pressed wait in loop
            break;
        }
        else {
            fnRetriggerWatchdog();
        }
    }
}

The WAIT_DEBUGGER_NOT_ACTIVE() macro is configured to poll a free GPIO input on each board (or a button on EVBs) so that if there is an issue starting (the debuggers are notorious at not being able to get control of the i.MX RTs in such cases) I can hold the button and the code loops waiting for the debugger to be connected and I can then release the button and continue debugging normally (including debugging whatever was the cause of it having problems connecting).

3. My hard fault handler is simply (since 2008 when starting with first Luminary Micro Cortex-M3s):

static void irq_hard_fault(void)
{
}

When I know that there is an issue to be investigated I disable the watchdogs and when a hard fault occurs it simply goes to this handler that then returns immediately. There are lots of handlers that try to analyse the cause and sit in a loop but if you have a debugger connect the above works much easier. The return jumps back to "the instruction" that caused the hard fault and then the hard fault occurs again (and this repeats forever). So rather than sit there and try to analyse registers and the call stack you just step back to the line that actually causes the problem and then it is mostly obvious (unless it is a follow on effect of corrupted memory where the reason for bad pointers and such is still not always clear). The additional potential advantage of this handler is that sometimes a peripheral is enabled and then accessed before its clock domain has become ready, which can result in the first access to the peripheral resulting in a hard fault but subsequent accesses (when the asynchronous clock domain has been synchronised to) work. This results in one (or a small number of hard faults with repetitions until it work and then the code continues without anyone knowing that there was a temporary problem (and it failing sporadically at an important demonstration). Often you will find library code enabling clocks and adding a few NOPs or a short delay before using the peripheral but this handler makes this redundant (if one doesn't like the fact that there is a "self-healing" fault taking place putting a break-point in the handler will also allow them to be caught during development so that one can decide the best workaround (eg. adding a delay, waiting on some flag or inserting some other code between the clock enable and peripheral access to give it some time).

Regards

Mark
[uTasker project developer for Kinetis and i.MX RT]

1,092 Views
chriscowdery
Contributor V

Hi Mark,

 Interesting debugging tips there - thankyou for those. It sounds like you've tripped over many of the same problems I have.

Hopefully someone from NXP will comment on the accessing of unclocked peripherals question as we have different answers, and they can try my example code on an EVK very easily.

Chris.

0 Kudos

1,092 Views
Sabina_Bruce
NXP Employee
NXP Employee

Hello Chris,

Hope you are doing well.

As Mark mentioned it should be entering a hard fault. I have made a quick test which should be essentially the same concept as you have mentioned. I took the blinky example and after the clock has been initialized I purposely disable the gpio1 clock which would be used by this example in the infinite loop. When attempting to write to the pin it goes to hard fault.  In addition, I've put the line above that is mentioned and it also does not work.

If you'd like to share your example here so I can check it with detail to see if there is any other differences I'd be happy to take a look.

Best Regards,

Sabina

-----------------------------------------------------------------------------------------------------------------------

Note: If this post answers your question, please click the Correct Answer button. Thank you!

----------------------------------------------------------------------------------------------------------------------- 

1,092 Views
chriscowdery
Contributor V

Hi sabinabruce‌.

I have made an example project which demonstrates this problem.

I am using iMXRT1021DAF5A (100pin MCU).

You can see it is a very simple main.c, which just disables the clock to GPIO1 then reads from it. For me, the debugger detaches and there is no hardfault.

I am debugging via J-Link and SWD.

I would be very pleased if you could look and see why it behaves differently to your test.

Note that the code originally came from the FreeRTOS_generic example for the MIMXRT1020-EVK.

Thanks,

Chris.

0 Kudos

1,092 Views
Sabina_Bruce
NXP Employee
NXP Employee

Hello Chris,

Hope you are doing well.

I'll be happy to check this from my end. When you hit the reply button you should see an option that says use advanced editor. So that you may attach the file to this post. Let me know if you are not able to so I can give you further instructions.

pastedImage_2.png

Best Regards,

Sabina

-----------------------------------------------------------------------------------------------------------------------

Note: If this post answers your question, please click the Correct Answer button. Thank you!

----------------------------------------------------------------------------------------------------------------------- 

0 Kudos

1,092 Views
chriscowdery
Contributor V

Hi Sabina,

 I don't have 'Use advanced editor' :-( . Is there another way to send you an attachment?

Thanks,


Chris.

pastedImage_1.png

0 Kudos

1,092 Views
Sabina_Bruce
NXP Employee
NXP Employee

Ok, not a problem. I will send you an email and create a case internally.

We can continue the support through that platform.

Best Regards,

Sabina

0 Kudos