8 years, 9 months ago.

Initial wait(); hangs

Hello

I'm currently working with an mbed enabled freedom kl25z board. I'm using the mbed export option to use my offline gcc compiler/debugger based on GNU GCC and openOCD.

My kl25z has an onboard flash resident bootloader based on the official Freescale 1.3.0 bootloader to enable customer based updating. After some searching a basic 'blinky' program starts fine after being bootloaded.

However, my wait() instructions hangs for a long time. After the initial 'hang' it works fine and timing is correct!

Blinky code is as basic as it can be and works fine if flashed as only user program starting at 0x0000:

DigitalOut blinky(LED_RED);

int main()
{

    while (1)
    {
         blinky = !blinky;
         // This hangs for 20s then blinks and works fine
         wait_ms(500);
    }
    return 0;
}

For my bootloader compatibility I had to change the following code in cmsis_nvic.c

// #define NVIC_FLASH_VECTOR_ADDRESS (0x0)       // Initial vector position in flash
// adjused to 0x8000 for Freescale bootloader. Maybe take this directly from linker script?
#define NVIC_FLASH_VECTOR_ADDRESS (0x8000)       // Initial vector position in flash

void NVIC_SetVector(IRQn_Type IRQn, uint32_t vector) {
    uint32_t *vectors = (uint32_t*)SCB->VTOR;
    uint32_t i;

    // Copy and switch to dynamic vectors if the first time called
    if (SCB->VTOR == NVIC_FLASH_VECTOR_ADDRESS) {
        uint32_t *old_vectors = vectors;
        vectors = (uint32_t*)NVIC_RAM_VECTOR_ADDRESS;
        for (i=0; i<NVIC_NUM_VECTORS; i++) {
            vectors[i] = old_vectors[i];
        }
        SCB->VTOR = (uint32_t)NVIC_RAM_VECTOR_ADDRESS;
    }
    vectors[IRQn + 16] = vector;
}

After some debugging I found that us_ticker_read() returns 0 for a long time and then when it kicks in seems to work fine

uint32_t us_ticker_read() {
    if (!us_ticker_inited)
        us_ticker_init();
    
    // The PIT is a countdown timer
    return ~(PIT->CHANNEL[1].CVAL); // This returns 0 for a long time
}

Off course my bootloader has also used the timer module to determine a timeout between starting the bootloader and running the user program.

void microseconds_init(void)
{
    uint32_t busClockDivider;

    //PIT clock gate control ON
    SIM->SCGC6 |= SIM_SCGC6_PIT_MASK;

    //Turn on PIT: MDIS = 0, FRZ = 0
    PIT->MCR = 0x00;

    //Set up timer 1 to max value
    PIT->CHANNEL[1].LDVAL = 0xFFFFFFFF;            //setup timer 1 for maximum counting period
    PIT->CHANNEL[1].TCTRL = 0;                     //Disable timer 1 interrupts
    PIT->CHANNEL[1].TFLG = 1;                      //clear the timer 1 flag
    PIT->CHANNEL[1].TCTRL |= PIT_TCTRL_CHN_MASK;   //chain timer 1 to timer 0
    PIT->CHANNEL[1].TCTRL |= PIT_TCTRL_TEN_MASK;   //start timer 1

    //Set up timer 0 to max value
    PIT->CHANNEL[0].LDVAL = 0xFFFFFFFF;            //setup timer 0 for maximum counting period
    PIT->CHANNEL[0].TFLG = 1;                      //clear the timer 0 flag
    PIT->CHANNEL[0].TCTRL = PIT_TCTRL_TEN_MASK;    //start timer 0

    /* Calculate this value early
     * The reason why use this solution is that lowest clock frequency supported by L0PB and L4KS
     * is 0.25MHz, this solution will make sure ticks per microscond is greater than 0.
     */
    busClockDivider = ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV4_MASK) >> SIM_CLKDIV1_OUTDIV4_SHIFT) + 1;
    s_tickPerMicrosecondMul8 = ((SystemCoreClock / busClockDivider) * 8) / kFrequency_1MHz;

    // Make sure this value is greater than 0
    if(!s_tickPerMicrosecondMul8)
    {
        s_tickPerMicrosecondMul8 = 1;
    }
}

//! @brief Shutdown the microsecond timer
void microseconds_shutdown(void)
{
    //Turn off PIT: MDIS = 1, FRZ = 0
    PIT->MCR |= PIT_MCR_MDIS_MASK;
}

It seems like by using the timer in the boatloader the initial timer setup in mbed causes some kind of hang. I could really use some help sorting this out. I already tried explicitly disabling the timer in mbed once again without success. Other interrupts such as the UART interrupt seem to work find and my debugger correctly recognizes the interrupt vector at 0x8000 when entering CMSIS_SetVector() for the first time.

Kind of at a loss why a second initialization of the timer would cause a hang like this.

Can you set up a blinky demo with the initialization of the timer you shared above, and test if it causes this hang (no bootloader used). Then we can test it on regular KL25Z, and someone might fix it.

posted by Martin Kojtal 08 Jul 2015

Hi Martin

after testing some more the following code works both with and without bootloader:

uint32_t tickPerMicrosecond;

static void pit_init(void) {

    SIM->SCGC6 |= SIM_SCGC6_PIT_MASK;   // Clock PIT
    PIT->MCR = 0;                       // Enable PIT

    // Channel 1
    PIT->CHANNEL[1].LDVAL = 0xFFFFFFFF;
    PIT->CHANNEL[1].TCTRL = 0;                     //Disable timer 1 interrupts
    PIT->CHANNEL[1].TFLG = 1;                      //clear the timer 1 flag
    PIT->CHANNEL[1].TCTRL |= PIT_TCTRL_CHN_MASK;    // Chain to timer 0, disable Interrupts
    PIT->CHANNEL[1].TCTRL |= PIT_TCTRL_TEN_MASK;   // Start timer 1

    // Use channel 0 as a prescaler for channel 1
    PIT->CHANNEL[0].LDVAL = 0xFFFFFFFF;
    PIT->CHANNEL[0].TFLG = 1;                      //clear the timer 0 flag
    PIT->CHANNEL[0].TCTRL = PIT_TCTRL_TEN_MASK;    // Start timer 0, disable interrupts*/

    tickPerMicrosecond = ((bus_frequency()) * 8) / 1000000UL;

    if (!tickPerMicrosecond) tickPerMicrosecond = 1;
}

uint32_t us_ticker_read() {
    if (!us_ticker_inited)
        us_ticker_init();

    // The PIT is a countdown timer
    uint32_t valueH = PIT->LTMR64H;
    uint32_t valueL = PIT->LTMR64L;

    // Invert to turn into an up counter
    uint64_t ticks = ~(((uint64_t)valueH << 32) + (uint64_t)(valueL));
    return ( 8 * ticks / tickPerMicrosecond);

}
posted by K. N. L. V. 08 Jul 2015

Hi K. N. L. V, did you manage to solve this? I have exactly the same issue and I'm a bit lost!

posted by Alexander Agudelo 16 Sep 2015

Answering my own question:

The documentation states that writing a new value to the LDVAL register will not actually restart the timer but instead the value will be set after the current timer expires (count down reaches 0). That's why the program "hangs" for a while and then runs normally. Freescale's bootloader sets the LDVAL to 0xFFFFFFFF while mbed uses 0x17 (If BusClock is 24Mhz) for the kl25z.

To fix this you just need to disable the timer before setting the new value:

PIT->CHANNEL[0].TCTRL &= PIT_TCTRL_TEN_MASK;

This has to be done in the "static void pit_init(void)" method in the us_ticker.c

I will try to do a pull request when I have more time.

Good luck!

Alex.

posted by Alexander Agudelo 16 Sep 2015
Be the first to answer this question.