µTasker Forum > µTasker general

Configuring Foreign Applications to work with the uTasker Serial Loader

(1/1)

mark:
Hi Al

Since I often get the question as to how applications can be linked and their interrupts be configured so that they work with the uTasker Serial Loader I have copied a reference solution here. It is specific for the Freescale Kinetis (with PE generated linker script) but is quite general to ARM so I thought it best located in the general section.

Regards

Mark



--- Quote ---1. You need to link your code to the start location of the application (eg. 0x8080). The following changes to the linker script should do it:

MEMORY {
  m_interrupts (RX) : ORIGIN = 0x00008080, LENGTH = 0x000001E0
  m_text      (RX) : ORIGIN = 0x00008290, LENGTH = 0x00040000-0x8290
  m_data      (RW) : ORIGIN = 0x1FFF0000, LENGTH = 0x00010000
  m_data_20000000 (RW) : ORIGIN = 0x20000000, LENGTH = 0x00010000
  m_cfmprotrom  (RX) : ORIGIN = 0x00008280, LENGTH = 0x00000010
}

Note that m_cfmprotrom is for flash configuration but is not useful for a boot loaded application since the boot loader determines the settings (see the "FLASH configuration settings" in the uTasker serial or "BM" loader in app_hw_kinetis.h)

2. The setting in 1. puts the reset vectors (and fixed interrupt vectors) at 0x8080. This address can't be used to operate them from because the Cortex M4 can only operate them on 512 byte aligned addresses. If you don't need the USB-MSD loader (which stores a file object in the first 0x80 bytes - and so uses 0x8080 rather than 0x8000 - and can use lower addresses like 0x2800 [check the size of the loader to see which lowest address is possible]) you can also use an aligned address instead. In such a case you can leave your interrupt vectors in Flash and you only need to add the following line of code to the application startup file:
SCB_VTOR = 0x8000;    // use vector table in flash at this offset (check the definition of SCB_VTOR since this example is from the Teensy3.1 Arduino project and your header files may spell it differently)

3. Generally it is preferred to locate the vectors in SRAM since they are then faster and can be swapped during run time if required. To do this you can leave space for them in SRAM by changing the linker script RAM setting:
  m_data      (RW) : ORIGIN = 0x1FFF0200, LENGTH = 0x00010000-0x200
so that the first 0x200 bytes are not used by the linker (they are then free for vector usage).

In the start up code simply copy the fixed ones from the code to here and then point the Cortex M4 vector offset register to them.

    memcpy((void *)0x1fff0000, (void *)0x8080, 0x200); // copy fixed interrupt vectors to the start of SRAM - assuming the project is linked to 0x8080, which is an invalid address for fixed vectors
    SCB_VTOR = 0x1fff0000;

Of course defines can be used rather than fixed values to make it portable but the example should be clearer like this.

Note that the uTasker project enters each interrupt when required by calling
extern void fnEnterInterrupt(int iInterruptID, unsigned char ucPriority, void (*InterruptFunc)(void));
eg. fnEnterInterrupt(irq_USB_OTG_ID, PRIORITY_USB_OTG, _usb_otg_isr); // enter and configure USB OTG interrupt
and so doesn't need to fix vectors in the code.
--- End quote ---

mark:
Hi All

I am attaching this to this thread since it is related.
Often the question arises as to the method of moving a boot loader from a stanard development board to a custom board where things may be a little different (different clocks, different memory size, change of port use etc.). This is a reference responds (in this case for a Freescale K64 based board after initial work with the FRDM-K64F) but also serves as general guide for any board/proessor family:


--- Quote ---To prepare your own board for the loader there are the following things to check:

1. The clock setup
Check how FRDM_K64F is doing this in app_hw_kinetis.h.
The default is to run from 50MHz clock input (from PHY) and set the PLL to 120MHz.
If you have a different clock source you can adjust the values there.
You can also set RUN_FROM_HIRC_PLL as option so that it runs from the internal IRC48M, which would make it HW independent. (Specific to parts with internal clocking options).

2. The chip type. Again check in the same file for the FRDM_KL64F

#elif defined FRDM_K64F
  //#define KINETIS_FLEX                                                 // X part with flex memory rather than N part with program Flash only
    #define PIN_COUNT           PIN_COUNT_100_PIN                        // 100 LQFP pin package
  //#define PIN_COUNT           PIN_COUNT_121_PIN                        // 121 XFBGA
  //#define PIN_COUNT           PIN_COUNT_144_PIN                        // 144 LQFP/MAPBGA pin package
    #define PACKAGE_TYPE        PACKAGE_LQFP
  //#define PACKAGE_TYPE        PACKAGE_MAPBGA
    #define SIZE_OF_FLASH       (1024 * 1024)                            // 1M FLASH
    #define SIZE_OF_RAM         (256 * 1024)                             // 256k SRAM

If you have a different memory type set the corresponding values here to match. Beware that you may have to modifiy the linker script file to suit too.

3. If using UART.
Make sure that
#define LOADER_UART           X
matches the UART that you are using  (X can be 0..6 for K64)

Then verify that the pin mux is as required for your HW.
Each UART has a default setting and this can be overridden by defines such as

  //#define UART3_ON_B                                                   // alternative UART3 pin mapping
  //#define UART3_ON_C                                                   // alternative UART3 pin mapping
  //#define UART4_ON_C                                                   // alternative UART4 pin mapping

There should be a set for all possible Muxing.


4. The LED that is used to signal the operation can be adjusted (or removed) using the defines:
#define BLINK_LED   PORTE_BIT26
#define INIT_WATCHDOG_LED() _CONFIG_DRIVE_PORT_OUTPUT_VALUE(E, (BLINK_LED), (BLINK_LED), (PORT_SRE_SLOW | PORT_DSE_HIGH))
#define TOGGLE_WATCHDOG_LED()   _TOGGLE_PORT(E, BLINK_LED)

Note that the port must match in each macro (eg. if output is moved to PORTA_BIT12 - also _CONFIG_DRIVE_PORT_OUTPUT_VALUE(A, and _TOGGLE_PORT(A, BLINK_LED) must match.

5. The input(s) used to control watchdog/forced start.

    #define SWITCH_2               (PORTC_BIT6)
    #define SWITCH_3               (PORTA_BIT4)

#define WATCHDOG_DISABLE()     (_READ_PORT_MASK(A, SWITCH_3) == 0)
#define INIT_WATCHDOG_DISABLE() _CONFIG_PORT_INPUT_FAST_LOW(C, (SWITCH_2), PORT_PS_UP_ENABLE);  _CONFIG_PORT_INPUT_FAST_LOW(A, (SWITCH_3), PORT_PS_UP_ENABLE);
#define FORCE_BOOT()       (_READ_PORT_MASK(C, SWITCH_2) == 0)

In a similar fashion to point 4 these can be adjusted to suit.
[Specifically for Kinetis] Beware of the _CONFIG_PORT_INPUT_FAST_LOW() [and  _CONFIG_PORT_INPUT_FAST_HIGH] macros.
These act only on 16 bits so PORTx_BIT0..PORT_BIT15 require yyy_LOW() and PORTx_BIT16..PORT_BIT31 require yyy_HIGH(). Alternatively use _CONFIG_PORT_INPUT() macro (acts on 32 bits but is less efficient).


That should be all that is required. You can do a project search for FRDM_K64F to see all locations where there are board dependencies. Either modify the FRDM_K64F settings or else add a new set for your own board. (A new set is useful since you an then easily switch between the reference and your board if needed).

--- End quote ---

mark:
Hi All

A final point that is worth mentioning is that the serial loader configures the processor clocks before jumping to the application.

It has been found that some applications use code to configure the clock that can't handle the case when it has already been set up and will hang. In such instances this code may need to be modified to first check the clock state and ensure that it correctly handles any reconfiguration that it may prefer to do.

In most cases the clock speeds are already suitable for the application and so the application's clock configuration can just be removed if it otherwise causes problems.

Regards

Mark

FABRIZIO:
Hi Mark,
I'm using a custom board with Kinetis KEAZN64 (64LQFP), I would like to program the kinetis via bootloader (with UART) I followed the instructions in the various videos and forums, but I'm doing something wrong. my hardware has an external ceramic resonator at 16MHz but everything is still, I checked with an oscilloscope at the output and there is no clock signal. Is there any particular recommendation to follow for this microcontroller? If necessary I will send you the source code of app_hw_kinetis.h or other that you will require me .. Thank you very much
 
Fabrizio

mark:
Hi Fabrizo

The open source version didn't have serial loader targets for the KEA boards so I just copied them in to it - if you synchronise to Git Hub you should be able to use FRDM_KEAZ64Q64 target as reference - this also has an 8MHz crystal.

The trick to using the oscillator is to choose an input divider to divide the crystal frequency to a frequency in the range 31.25kHz..39.06525kHz. In addition, the oscillator also needs to be enabled. The FLL will then operate at about 40MHz. Since the bus/flash clock is limited to 24MHz this needs to be divided by 2 to remain within specification.

This is the configuration (hw_app_kinetis.h) to do this:
    #define CRYSTAL_FREQUENCY    8000000                                 // 8 MHz crystal
  //#define RUN_FROM_EXTERNAL_CLOCK                                      // run directly from external 8MHz clock (without FLL)
    #define _EXTERNAL_CLOCK      CRYSTAL_FREQUENCY
    #define CLOCK_DIV            256                                     // input must be divided to 31.25kHz..39.06525kHz range (/1, 2, 4, 8, 16, 32, 64, 128, 256, 512 or 1024 possible)
                                                                         // this input is multiplied by 1280 to 40MHz..50MHz at the FLL output
    #define SYSTEM_CLOCK_DIVIDE  1                                       // divide the clock output to give the system clock (maximum 48MHz) (/1, 2, 4, 8, 16, 32, 64 or 128 possible)
    #if defined RUN_FROM_EXTERNAL_CLOCK
        #define BUS_CLOCK_DIVIDE 1                                       // divide by 1 or 2 to give bus and flash clock (maximum 24MHz)
    #else
        #define BUS_CLOCK_DIVIDE 2                                       // divide by 1 or 2 to give bus and flash clock (maximum 24MHz)
    #endif



Beware that I also updated kinetis.c since it otherwise was not using the correct register for the KEA64 to set the bus/flash divide.

Good luck

Regards

Mark

Navigation

[0] Message Index

Go to full version