Problem Analysis and solutions for booting from ROM BOOTLOADER in KL series

cancel
Showing results for 
Search instead for 
Did you mean: 

Problem Analysis and solutions for booting from ROM BOOTLOADER in KL series

Problem Analysis and solutions for booting from ROM BOOTLOADER in KL series

Problem Analysis and solutions for booting from ROM BOOTLOADER in KL series

1 Abstract

     When customer use the kinetis chip KL43, KL27 and KL17 which flash size is above 128K, they have found a problem that if the code boot from the ROM instead of the flash, the application code about the LPUART and I2C will run in abnormal state, especially when use PTA1 as the  LPUART receive pin, UART transmit function has no problem, but when the PTA1 receive the UART data, the code will run to the abnormal area and can’t return back, the code will be crash. This problem only happens on booting from the ROM and the uart and i2c peripheral are enabled in BCA 0x3d0 address, uart peripheral enablement in BCA area will influence the application PTA1 uart receive, i2c peripheral enablement in BCA area will influence the i2c0 module in the application code. If booting from the flash or booting from ROM but the uart and I2C peripheral are disabled in the BCA 0x3d0 address, everything is working ok in the application code.

     This document will take the UART problem as an example, give details of the problem reproduction, testing, analysis and the solutions. The I2C problem is the same when booting from the ROM bootloader.

2 Problem reproduction and analysis

 Testing preparation:

     We mainly reproduce the uart receive problem in two ways: new KDS PE project based on KSDK1.3.0 and official newest sample code package KSDK2.0_FRDM-KL43.

2.1 Problem reproduction in new creating kds project

Because the KSDK2.0 still doesn’t support the PE function in the KDS IDE, so we use the KSDK1.3.0 as the PE KSDK to create the new KDS project.

2.1.1 Create KDS KL43 project

The new KDS PE project creating is very simple, here just describe the important points which is relate to the UART problem after booting from the ROM. At first create a new KDS PE project which is based on KSDK1.3.0, and choose the chip as MKL43Z256VLH4, select the MCG mode as HIRC, and configure core clock to 48Mhz, bus clock to 24Mhz.

Then add the uart module fls_debug_console for testing, because the FRDM_KL43 is using PTA1 and PTA2, the console module can be configured like the following picture, after the module is configured, press the code generation button to generate the project code.

1.jpg

Then add the simple code in file main.c main function for testing:

char a;

for(;;)

{

                PRINTF(" test!\n");

                a= GETCHAR();

                PUTCHAR(a);

              }

The code function is: printf the “test!” to the COM port in the PC, then wait the uart data, if receive the data, then printf the received data back and run this loop function again.

 

2.1.2 Add the BCA area

   From the KL43 reference manual, we can get that, BCA start address is 0X3C0:

2.jpg

    The KDS newly created project didn’t contain the BCA area in the link file, so we need to add this area in the link file and add the BCA data in the start file by ourselves.

2.1.2.1 Divide the BCA flash are in .ld file

Add the following code to define the BCA start flash address and the flash size in the ProcessorExpert.ld memory area:

m_bca                 (RX)  : ORIGIN = 0x000003C0, LENGTH = 0x00000040

Then add this code in the SECTIONS area:

  .bca :

           {

             . = ALIGN(4);

             KEEP(*(.bca)) /* Bootloader Configuration Area (BCA) */

             . = ALIGN(4);

           } > m_bca

At last, the ld file is like this:

3.jpg

For the ld file protection, we can change the ld file properties to read-only, then this file won’t be changed to the initial one after building.

4.jpg

2.1.2.2 Add the BCA data in the start file

     After add the BCA flash area divide code, we still need to define the BCA data in the start file:

   /* BCA Area */

    .section .bca, "a"

                .ascii "kcfg"                            // [00:03] tag

                .long 0xFFFFFFFF // [07:04] crcStartAddress

                .long 0xFFFFFFFF // [0B:08] crcByteCount

                .long 0xFFFFFFFF // [0F:0C] crcExpectedValue

                .byte 0x03                                             // [10] enabledPeripherals  I2C and UART

                .byte 0xFF                                              // [11] i2cSlaveAddress

                .short 3000                           // [13:12] peripheralDetectionTimeout (milliseconds)

                .short 0xFFFF                        // [15:14] usbVid

                .short 0xFFFF                        // [17:16] usbPid

                .long 0xFFFFFFFF  // [1B:18] usbStringsPointer

                .byte 0xFF                                              // [1C] clockFlags

                .byte 0xFF                                              // [1D] clockDivider

                .byte 0xFF                                              // [1E] bootFlags

                .byte 0xFF                                              // [1F] reserved*/

   More details, please refer to this picture:

5.jpg

      So far, we have create the FRDM-KL43 test project which contains the BCA area, and boot from the ROM that can be modified in the flash address 0X40D, bit 6-7 in 0X40D is the BOOTSRC_SEL bits, 00 boot from flash, 10 and 11 boot from ROM, more details about the FOPT, please refer to Table 6-2. Flash Option Register (FTFA_FOPT) definition in reference manual.

 

 

2.1.3 Test result and analysis

      Now, list the test result after booting from ROM or flash, and boot from ROM but enable the peripherals.

Boot from:

ROM peripheral

Test Result

Flash

XX

OK

ROM

0XFF, enable all

NO, UART can’t receive

0X08, enable USB

Yes, UART can receive

0X04, enable SPI

Yes, UART can receive

0X02, enable I2C

Yes, UART can receive

0X01, enable LPUART

NO, UART can’t receive

     From the test result, we can reproduce the problem. The UART receive problem just happens on booting from ROM and the LPUART is enabled, when we run it with debugger, and test it step by step, we can find after the PTA1 have received the data, the code will run to the abnormal area.

Note:

when debug this code, please choose the JLINK as the debugger, because the P&E tool will protect the FOPT area automatically in the KDS IDE when do debugging, the code will still run from flash, so if customer use the P&E tool, they will found the PTA1 still can receive the data, this is not the real result, but the JLINK won’t protect FOPT area in the KDS IDE, it can reflect the real result.

     After using the JLINK as the debugger, and we have found after PTA1 getting data or pulling low, the code will enter to the abnormal area like this:

6.jpg

     We can get that the code run to the defaultISR, and display with USB_IRQHander, but this is not really the USB_IRQHander, just caused by the PC abnormal. Normally, it is caused by the missing of interrupt service function.

      Now, we test the NVIC data to check which module interrupt caused this, the following picture is the result by enabling the LPUART and I2C peripheral in the ROM BCA area.

7.jpg

We can find, even we didn’t do the cpu and peripheral initialization after booting from ROM, there still have peripheral be enabled, what the interrupt is enabled? From the definitive guide to the ARM Cortex-M0.pdf:

8.jpg

NVIC_ISER = 0x40000100, Vector46=IRQ30 and vector24=IRQ8 is enabled, it should be not disabled after booting from the ROM. Now check the KL43 reference manual, Table 3-2. Interrupt vector assignments, we can get that the I2C0 and PORTA interrupt is enabled.

9.jpg

Checking the PORTA register before do the cpu and peripheral initialization, PTA1 is enabled the port interrupt, and choose Flag and Interrupt on falling-edge.

10.jpg

    This can tell us why the PTA1 pin have the problem of uart receive data or give a falling edge in PTA1 will run abnormal, because in default, even we configure the PTA1 as the uart receive function, but the code didn’t clear IRQ and NVIC register, when the signal happens on PTA1 pin, it will caused the PORTA interrupt, but we didn’t add the PORTA interrupt ISR function, it is also not useful to us, then PC don’t know where to go, so it will run abnormal, enter the defaultISR, and can’t recover. If you have interest, you can add the PORTA_IRQHandler function, you will find the code will run to this function.

2.2 Problem reproduction in KSDK2.0 IAR project

 Test project: SDK_2.0_FRDM-KL43Z\boards\frdmkl43z\demo_apps\hello_world

 Test the official project just to make sure, it is really the chip hardware function, not only the problem from new generated code in KDS.

  Because the IAR IDE will protect the 0X400 area, then if we want to modify the FOPT, we need to modify the .board, add –enable_config_write at first.

 11.jpg

 Then modify the FOPT in startup_MKL43Z.s:

__FlashConfig

        DCD 0xFFFFFFFF

        DCD 0xFFFFFFFF

        DCD 0xFFFFFFFF

        DCD 0xFFFFFFFE   ; 0xFFFF3FFE  

__FlashConfig_End

  Because the BCA peripheral area is in default as 0XFF, it enables all the peripheral, we don’t need to define the BCA area independently.

 For getting the real test result, we add the NVIC and PORTA_PCR1 register printf code in the main function,

   PRINTF("PORTA_PCR1=%X \n", PORTA->PCR[1]);

   PRINTF("NVIC=%X \n", NVIC->ICER[0U]);

And download the modified KSDK sample code to the chip, after testing, we get this result:

hello world.

PORTA_PCR1=A0205

NVIC=40000100

It is the same result as the new created project after booting from the ROM, PORTA interrupt and I2C interrupt is enabled, and it caused the PTA1 receive data problem.

 3 Solutions and test result

3.1 Solutions

     From the Chapter 2 testing and analysis, we can get that UART receive problem is caused by the PORT interrupt and NVIC is enabled after booting from the ROM, this should be caused by exiting the ROM, the ROM forget to disable it. We also can find some descriptions from the KL43 reference manual page 211:

12.jpg

So, if customer want to solve this problem, to avoid the application enter to the abnormal area, we can disable the NVIC in the application code like this, the I2C NVIC is the same:

    NVIC_DisableIRQ(8);//disable I2C0 interrupt

    NVIC_DisableIRQ(30); //disable PTA interrupt

3.2 Test result

13.jpg

  From the test result after adding the NVIC I2C and PORTA disable code, we can get the uart can works ok, if you have interest to test, the I2C will also work ok.

4 Conclusion

When customer use the kinetis chip KL43, KL27 and KL17 which flash size is above 128K, and want to boot from the ROM and enable the LPUART and I2C in BCA area, please add the NVIC I2C(IRQ8) and PORTA(IRQ30) disable code in the application code:

    NVIC_DisableIRQ(8);//disable I2C0 interrupt

    NVIC_DisableIRQ(30); //disable PTA interrupt

So far, I just find KL43, KL27 and KL17 which flash size is above 128K have this problem, other kinetis chip which have ROM bootloader don’t have this problem.

Labels (1)
Attachments
Comments

Hi Jingjing,

looks like your code after exiting ROM bootloader code keep vector table addresses at the ROM memory location. It means that if in your appplication code program wants to enter interrupt handler (LPUART or I2C) the NVIC (interrupt controller) is taking the vector from ROM and enter likely the ROM interrupt handler which at the and stall at this ROM code location.

This solution may be help:

in your application code check for boot source (if ROM based). If yes, clear boot source flag and generate system reset e.g. (in SDK 2.0)

  if (RCM_GetBootRomSource(RCM)&kRCM_BootRomBoth)

  {

    RCM_ClearBootRomSource(RCM);

    NVIC_SystemReset();

  }

this will re-allocated VTOR (interrupt vector table) into the flash. Hope it will be helpful.

regards

R.

Hi Rastislav,

    Thank you for your comment.

   Yes, you are right, it caused me a lot of time to find the root problem, it is really need to reset the NVIC after booting from ROM.

   Could you tell me where the function RCM_GetBootRomSource which you are using from? Is it  from KSDK2.0 API or need to write by the customer? I check the fsl_rcm.c, and didn't find this API.

Best Regards,

Jingjing

Hi Jingjing,

it is an inline function defined in .h file

static inline rcm_boot_rom_config_t RCM_GetBootRomSource(RCM_Type *base)

{

    return (rcm_boot_rom_config_t)((base->MR & RCM_MR_BOOTROM_MASK) >> RCM_MR_BOOTROM_SHIFT);

}

regards

R.

Thank you for the analysis.

Comes down to clearing NVIC at the start of any code, and good hygiene of completely initializing any peripherals that are used.

Put this at start of reset_init() in vectors.c (or equivalent names for your code).

  /*

   * "Problem Analysis and solutions for booting from ROM BOOTLOADER

   * in KL series" says the KL43/27/17 bootloaders are buggy. NVIC

   * needs to be cleared if got here via buggy bootloader.

   */

  NVIC_ICER |= ~0UL;

  NVIC_ICPR |= ~0UL;

To do a reset as Rastislav Pavlanin suggests, without any frame works or such, which gets the data sheet reset values, do this:

  /*

   * RCM_MR Indicates the boot source, the boot source remains set

   * until the next System Reset or software can write logic one to

   * clear the corresponding mode bit.  While either bit is set the

   * NMI input is disabled and the vector table is relocated to the

   * ROM base address at 0x1C00_0000. These bits should be cleared by

   * writing logic one before executing any code from either Flash or

   * SRAM.

   *

   * A reset is forced to clear out anything that the ROM

   * bootloader did, so we are sure we have the data sheet reset

   * values.

   *

   * This method works around the buggy KL43/27/17 bootloaders as

   * described in: "Problem Analysis and solutions for booting from

   * ROM BOOTLOADER in KL series".

   */

  if( 0U != (RCM_MR & RCM_MR_BOOTROM_MASK) )

    {

      RCM_MR = RCM_MR_BOOTROM_MASK; /* Clear the bits that indicated a bootlaoder boot via ROM */

      RCM_FM = 0U;                  /* Boot from Flash not ROM on next reset */

      SCB_AIRCR = (SCB_AIRCR_VECTKEY(0x05FAU) | SCB_AIRCR_SYSRESETREQ_MASK); /* Force a Software Reset */

    }

Hi Bob

Have you tested the code that commands a reset after the ROM BOOT LOADER was detected as having run?
RCM_FM = 0 is the default value and so can be overridden by any other force BOOT settings (such as BOOTCFG0 or the FOPT[7]) which suggests that this will result in a forever loop:

- ROM loader (due to BOOTCGG0 for example)
- SW reset

- ROM loader (due to BOOTCGG0 for example)
- SW reset

..

I didn't test this but it is what I would expect.

I also decided against commanding a software reset due to the fact that the original reset cause (eg. due to watchdog) is lost (replaced by SW reset).

The following is the workaround that I am using for the uTasker project - notice that also possible pending interrupt are cleared (not just masked) since unexpected pending peripheral interrupts are also a source of application failure when peripherals are enabled, which is missing in the "Analysis and Solution" document.

Regards

Mark

#if defined KINETIS_KL && defined ROM_BOOTLOADER && defined BOOTLOADER_ERRATA // {125}
    if ((RCM_MR & (RCM_MR_BOOTROM_BOOT_FROM_ROM_BOOTCFG0 | RCM_MR_BOOTROM_BOOT_FROM_ROM_FOPT7)) != 0) { // if the reset was via the ROM loader
        // PORT clock gate, pin mux and peripheral registers are not reset to default values on ROM exit
        //
        PORTA_PCR1 = PORT_PS_UP_ENABLE;                                  // set LPUAR0, I2C0 and SPI0 ports back to defaults
        PORTA_PCR2 = PORT_PS_UP_ENABLE;
        PORTB_PCR0 = PORT_PS_UP_ENABLE;
        PORTB_PCR1 = PORT_PS_UP_ENABLE;
        PORTC_PCR4 = PORT_PS_UP_ENABLE;
        PORTC_PCR5 = PORT_PS_UP_ENABLE;
        PORTC_PCR6 = PORT_PS_UP_ENABLE;
        PORTC_PCR7 = PORT_PS_UP_ENABLE;
        POWER_DOWN(5, (SIM_SCGC5_PORTA | SIM_SCGC5_PORTB | SIM_SCGC5_PORTC | SIM_SCGC5_PORTD | SIM_SCGC5_PORTE | SIM_SCGC5_LPUART0)); // power down ports and LPUART0
        POWER_DOWN(4, (SIM_SCGC4_I2C0 | SIM_SCGC4_SPI0));                // power down I2C0 and SPI0
        SIM_SOPT2 = 0;                                                   // set default LPUART0 clock source
        IRQ0_31_CER = 0xffffffff;                                        // disable and clear all possible pending interrupts
        IRQ32_63_CER = 0xffffffff;
        IRQ64_95_CER = 0xffffffff;
        IRQ0_31_CPR = 0xffffffff;
        IRQ32_63_CPR = 0xffffffff;
        IRQ64_95_CPR = 0xffffffff;
        // UART cannot work at 57600 baudrate with default core clock (not worked around)
        //
        // COP is disabled in ROM and it cannot be re-enabled by an application that is jumped to from ROM
        // - cannot be worked around; advise to use FTFL_FOPT_BOOTSRC_SEL_FLASH together with FTFL_FOPT_BOOTPIN_OPT_ENABLE
        //
    }
#endif

Mark Butcher wrote:

Have you tested the code that commands a reset after the ROM BOOT LOADER was detected as having run?
RCM_FM = 0 is the default value and so can be overridden by any other force BOOT settings (such as BOOTCFG0 or the FOPT[7]) which suggests that this will result in a forever loop ...

 

I also decided against commanding a software reset due to the fact that the original reset cause (eg. due to watchdog) is lost (replaced by SW reset).

Yes I tested.  It is what I found that worked after several experiments.  There are sections in the datasheet that don't seem to reflect how the part really works.  In booting FOPT et.al. appear to set internal latches that are not cleared until after the reset vector has been taken.  There is also the bug that if booting from the USB HID the bootloader will not reset via the software command from the PC.  It gets stuck in endless cycle of enumeration.

To see if the part was reset by the Watchdog look at RCM_SSRS0 the 'Sticky' register.

The datasheet values reflect Power Up (Vcc Rise), not all reset sources.  This can be seen in the SPIN bit.  SPIN indicates if there was a Reset Pin reset, clearing this bit at reset makes no sense, which is what the datasheet default value indicates.  I look at Sticky SWDOG to log it in my code; I have a complex timer/DMA/LPUART thing going on and am not convinced that the LPUART does not lock up at times leading the watchdog to bark.  I've not seen anyone else complaining about LPUART issues.

Bob

Thanks, it sounds as though your experiences fill in more details than expected from the documentation.

Therefore I will revisit this in a couple of weeks when I start a new production run of a KL27 based part that needs USB programming (on fresh parts) in the factory  - a USB-MSD loader will be programmed for subsequent operation so ROM bugs won't have a huge effect, but it will give an opportunity to get to know better its real behavior.

Regards

Mark

Hi, I have the following comment from a customer.   Can it be reviewed for possible update to DOC-332389?

****

I actually disagree with the solution shown in DOC-332389 because they are using an over simplified test case.  Their proposed solution to block the port pin interrupt from the LPUART Rx pin was to do this:

NVIC_DisableIRQ(30); //disable PTA interrupt

 

This goes to the NVIC and disables interrupts from *all* pins on port A.  If you want to get an interrupt from any of the other pins on port A, you have to go back to the NVIC and re-enable the PTA interrupt which would allow the same unhandled interrupt to occur.  Since we are trying to avoid an unexpected interrupt on a specific port pin (PTA1), I believe a better solution is to do the following where “gpio” is what is needed for modifying PTA1:

PORT_HAL_SetPinIntMode(gpioGetPortPtr(gpio), gpio->pinIdx, GpioIrq_Never);

******

It is correct that BOTH NVIC source and pin source need to be disabled to avoid the risk of an unexpected interrupt possibly taking place when the application uses these features.

Regards

Mark

Version history
Revision #:
1 of 1
Last update:
‎08-15-2016 01:02 AM
Updated by: