Author Topic: Explanation and solution of LPC23XXX instability with some standalone GCC builds  (Read 4550 times)

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3068
    • View Profile
    • uTasker
Hi All

I finally have a solution to some instability problems with the LPC23XX project when compiled with certain GCC versions.

It originates from the vector table in startup_gnu.s

/* reset vector followed by exception vectors */
_vectors:
    ldr pc, [pc, #_reset_handler - . - 8]                                /* reset vector             */
    ldr pc, [pc, #_undef_handler - . - 8]                                /* undefined instruction    */
    ldr pc, [pc, #_swi_handler - . - 8]                                  /* swi handler              */
    ldr pc, [pc, #_pabort_handler - . - 8]                               /* abort prefetch           */
    ldr pc, [pc, #_dabort_handler - . - 8]                               /* abort data               */
#ifndef _DEBUG_CODE_
    .word 0xB8A06F88                                                     /* LPC boot loader checksum */
#else
    .word 0xB8A06F88
    /*nop*/                                                              /* reserved                 */
#endif
    ldr pc, [pc, #_irq_handler - . - 8]                                  /* irq                      */
    ldr pc, [pc, #_fiq_handler - . - 8]                                  /* fiq                      */


Note the #ifdef. This is used by the Rowley Crossworks project as a method of setting the check sum so that the LPC boot loader knows that there is valid application code to be started. When loading with FLASHMagic or similar it isn't needed since it is inserted when downloading.

However (to my surprise and shock...) some GCC versions assemble this to ignore the #ifdef and thus generates TWO check sums.
The result is that the IRQ vector is pushed 4 bytes back and the check sum is executed as an instruction each times an interrupt occurs before executing the IRQ dispatcher itself.
Don't ask me what the instruction executions does - I don't want to know... but it was generally not noticeable until for some reason it suddenly gave a data abort, usually during Ethernet activity. The simple solution is to remove the #ifdef as below:

_vectors:
    ldr pc, [pc, #_reset_handler - . - 8]                                /* reset vector             */
    ldr pc, [pc, #_undef_handler - . - 8]                                /* undefined instruction    */
    ldr pc, [pc, #_swi_handler - . - 8]                                  /* swi handler              */
    ldr pc, [pc, #_pabort_handler - . - 8]                               /* abort prefetch           */
    ldr pc, [pc, #_dabort_handler - . - 8]                               /* abort data               */
    .word 0xB8A06F88                                                     /* {1} LPC boot loader checksum */
    ldr pc, [pc, #_irq_handler - . - 8]                                  /* irq                      */
    ldr pc, [pc, #_fiq_handler - . - 8]                                  /* fiq                      */


Now the double check sum disappears and the IRQ handling is normal again. My tests showed no more signs of instability so I am very happy that this strange problem has finally been solved!

Regards

Mark

Offline aaronlawrence

  • Jr. Member
  • **
  • Posts: 66
    • View Profile
Ouch. Can you explain more what the consequences of this problem are?

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3068
    • View Profile
    • uTasker
Hi Aaron

I can't explain more that the fact that the instruction 0xB8A06F88 (whatever it is) was being executed on each interrupt. This was generally not noticeable since it didn't cause any problems but when Ethernet was in use there was a chance that a data abort occurred.

This was restricted to GCC standalone build and was not a problem with Rowley since its compiler (GCC but maybe tuned?) was handling the #ifdef

Regards

Mark