0
\$\begingroup\$

I am struggling with a bus fault error on my samg55 µC based on arm cortex m4 architecture. The issue occurs sporadically and is not 100% reproductible. Let me give some details.

Application code writes periodically some datas into reserved internal flash memory. To do this I use the EFC (embedded flash controller) of the µC which is mapped at address 0x400E0A00 in system controller.

This writing leads in certain conditions to a hard fault. I dumped registers and got the following:

R4_20001368  R5_00000001  R6_00000338  R7_00000020
R8_00000020  R9_2001bcc8 R10_200128cc R11_0043d3a9
R0_402e0a00  R1_5a03380b  R2_5a033800  R3_20000067
R12_200129cc  LR_0043320b  PC_2000006a PSR_010f0000

SHCSR: 0x00000000
CFSR:  0x00008600
HFSR:  0x40000000
DFSR:  0x00000000
MMFAR: 0x402e0a08
BFAR:  0x402e0a08
AFSR:  0x00000000

CFSR indicates a bus fault with BFARVALID flag set. Looking at BFAR register I can see the value 0x402e0a08 which base address 0x402e0a00 is just one bit different from the EFC address 0x400E0A00.

I digged into the code but could not find the bug. Here is suspected code:

Assembler code

004331d4 <efc_perform_command>:
  4331d4:   f1a1 030e   sub.w   r3, r1, #14
  4331d8:   2b01        cmp r3, #1
  4331da:   b537        push    {r0, r1, r2, r4, r5, lr}
  4331dc:   d91d        bls.n   43321a <efc_perform_command+0x46>
  4331de:   f3ef 8310   mrs r3, PRIMASK
  4331e2:   fab3 f383   clz r3, r3
  4331e6:   095b        lsrs    r3, r3, #5
  4331e8:   9301        str r3, [sp, #4]
  4331ea:   b672        cpsid   i
  4331ec:   f3bf 8f5f   dmb sy
  4331f0:   4c0b        ldr r4, [pc, #44]   ; (433220 <efc_perform_command+0x4c>)
  4331f2:   2300        movs    r3, #0
  4331f4:   7023        strb    r3, [r4, #0]
  4331f6:   4b0b        ldr r3, [pc, #44]   ; (433224 <efc_perform_command+0x50>)
  4331f8:   9d01        ldr r5, [sp, #4]
  4331fa:   ea03 2202   and.w   r2, r3, r2, lsl #8
  4331fe:   f042 42b4   orr.w   r2, r2, #1509949440 ; 0x5a000000
  433202:   b2c9        uxtb    r1, r1
  433204:   4311        orrs    r1, r2
  433206:   4b08        ldr r3, [pc, #32]   ; (433228 <efc_perform_command+0x54>)
  433208:   4798        blx r3
  43320a:   b125        cbz r5, 433216 <efc_perform_command+0x42>
  43320c:   2301        movs    r3, #1
  43320e:   7023        strb    r3, [r4, #0]
  433210:   f3bf 8f5f   dmb sy
  433214:   b662        cpsie   i
  433216:   b003        add sp, #12
  433218:   bd30        pop {r4, r5, pc}
  43321a:   f04f 30ff   mov.w   r0, #4294967295 ; 0xffffffff
  43321e:   e7fa        b.n 433216 <efc_perform_command+0x42>
  433220:   20001368    .word   0x20001368
  433224:   00ffff00    .word   0x00ffff00
  433228:   20000067    .word   0x20000067

20000066 <efc_perform_fcr>:
20000066:   b082        sub sp, #8
20000068:   6041        str r1, [r0, #4]
2000006a:   6883        ldr r3, [r0, #8]
2000006c:   9301        str r3, [sp, #4]
2000006e:   9b01        ldr r3, [sp, #4]
20000070:   07db        lsls    r3, r3, #31
20000072:   d5fa        bpl.n   2000006a <efc_perform_fcr+0x4>
20000074:   9801        ldr r0, [sp, #4]
20000076:   f000 000e   and.w   r0, r0, #14
2000007a:   b002        add sp, #8
2000007c:   4770        bx  lr

C code

/**
 * \brief Perform the given command and wait until its completion (or an error).
 *
 * \note Unique ID commands are not supported, use efc_perform_read_sequence.
 *
 * \param p_efc Pointer to an EFC instance.
 * \param ul_command Command to perform.
 * \param ul_argument Optional command argument.
 *
 * \note This function will automatically choose to use IAP function.
 *
 * \return 0 if successful, otherwise returns an error code.
 */
uint32_t efc_perform_command(Efc *p_efc, uint32_t ul_command,
        uint32_t ul_argument)
{
    uint32_t result;
    irqflags_t flags;

    /* Unique ID commands are not supported. */
    if (ul_command == EFC_FCMD_STUI || ul_command == EFC_FCMD_SPUI) {
        return EFC_RC_NOT_SUPPORT;
    }

    flags = cpu_irq_save();
    /* Use RAM Function. */
    result = efc_perform_fcr(p_efc,
            EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FARG(ul_argument) |
            EEFC_FCR_FCMD(ul_command));
    cpu_irq_restore(flags);
    return result;
}


/**
 * \brief Perform command.
 *
 * \param p_efc Pointer to an EFC instance.
 * \param ul_fcr Flash command.
 *
 * \return The current status.
 */
__no_inline
RAMFUNC
uint32_t efc_perform_fcr(Efc *p_efc, uint32_t ul_fcr)
{
    volatile uint32_t ul_status;

    p_efc->EEFC_FCR = ul_fcr;
    do {
        ul_status = p_efc->EEFC_FSR;
    } while ((ul_status & EEFC_FSR_FRDY) != EEFC_FSR_FRDY);

    return (ul_status & EEFC_ERROR_FLAGS);
}

Code is compiled with arm-none-eabi-gcc (gcc-arm-none-eabi-7-2017-q4-major) with -Os optimization.

Note: issue seems to occurs more frequently in low temperature (0°C), so I don't exclude hardware related problem, even though operating range of µC is -40 to 85 °C...

Any idea what could go wrong ? Thanks for your help !

PS: I am not ready to blame cosmic ray... ;-)

EDIT: Adding some details after more investigation

First, system is clearly more stable with dynamic wait state setting according to core frequency. This is true for temperature nearby 0°C and a little less.

But it becomes totally unstable at -15°C.

I am suspecting that the internal oscillator that we are using has a significant drift due to low temperature (and/or voltage instability). This oscillator (16MHz) is used as source for core and also for peripherals like timer and usart. I have two other possibilities for source oscillator: - External fast oscillator at 12 MHz - External slow oscillator at 32.768 KHz

Oscillator at 12 MHz is not very suitable to generate good clock for uart with a 115200 baudrate. Slow oscillator can be used to generale a pll clock with frequency between 24 and 48 MHz, that can be used as source for peripherals. I tried this solution and have good results so far at very low temp, but I am not sure it is recommended, specifically for uart. So my question is, is using a pll as source for uart a bad practice ?

The hardware solution would be to replace external fast oscillator, selecting suitable frequency for uart, but it is not possible for now.

\$\endgroup\$

migrated from superuser.com Jan 23 at 11:11

This question came from our site for computer enthusiasts and power users.

  • \$\begingroup\$ Thanks Andrew for advice. I will try to move it to EE site. \$\endgroup\$ – Kev1 Jan 23 at 11:03
  • 1
    \$\begingroup\$ These kind of bootloader firmware residing on-chip typically wants you to reserve RAM for them. Is this the case and if so, have you done it? And there's also likely some app note regarding this which is a must-read. Btw your debugging seems quite archaic, why are you working with register dumps? Just set a breakpoint at the exception handler then view the instruction trace, to find out exactly which C line that is the culprit, together with the state of all registers. You might need a tool chain free of Eclipse and other diseases though. \$\endgroup\$ – Lundin Jan 23 at 11:36
  • 1
    \$\begingroup\$ I've seen issues like this before which resulted from incorrectly configuring the micro's internal Flash timing registers, resulting in the Flash being 'overclocked' and occasionally returning invalid code. \$\endgroup\$ – brhans Jan 23 at 12:12
  • 1
    \$\begingroup\$ @Lundin - "free of Eclipse and other diseases" ;) \$\endgroup\$ – brhans Jan 23 at 12:13
  • 1
    \$\begingroup\$ Yeah - that's exactly the issue I'm referring to. If your Flash wait states are not set correctly it could appear to sort-kinda-work most of the time, but occasionally you'll find your flash toggles a bit somewhere as the core reads instructions or data and that'll manifest in some really weird symptoms. \$\endgroup\$ – brhans Jan 23 at 15:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.