This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

delay milisecond

Hi all Iam using STR912FW44 based board and I want a delay function that should give the delay in milisecond I made a function


void delay_ms (unsigned long nCount){   /* Wait function                    */
  nCount=nCount+16000000L;

  while (nCount--);
}


when I call

delay_ms(10000);

it gives arround 10 second delay but when I call

delay_ms(20000);
it should give arround 20 second delay but it does not happen

but when I call

delay_ms(10000);
delay_ms(10000);

it gives arround 15 sec delay

please tell me exact way to build a delay function

regards
rupesh

  • you is be using the softwear delay you be knowing.

    use the hardwear timer rupesh .

  • things to take into account:
    * you are not using a hardware timer, so haw can you guarantee anything? your code depends on how fast the CPU can crunch instructions, not the frequency of a peripheral designed to help you (hence a hardware timer).
    * you are using C to write a delay loop - which makes you sensitive to optimization, compiler whims etc. use assembly for exact delays.

    /*
    ** Copyright (C) 2008 Tamir Michael
    **
    ** This program is free software; you can redistribute it and/or modify
    ** it under the terms of the GNU General Public License as published by
    ** the Free Software Foundation; either version 2 of the License, or
    ** (at your option) any later version.
    **
    ** This program is distributed in the hope that it will be useful,
    ** but WITHOUT ANY WARRANTY; without even the implied warranty of
    ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    ** GNU General Public License for more details.
    **
    ** You should have received a copy of the GNU General Public License
    ** along with this program; if not, write to the Free Software
    ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    */
    
    #ifndef __TIMER_H
    #define __TIMER_H
    
    #include "general_definitions.h"
    
    #define TIMER_TICKING     1
    #define TIMER_NOT_TICKING 2
    
    typedef enum
    {
            e_timer_not_ticking = 0,
            e_timer_ticking,
            e_timer_expired
    } timer_state ;
    
    typedef enum
    {
            e_timer_poll_mode,
            e_timer_exact_period_mode,
            e_timer_exact_oneshot_mode
    } timer_mode ;
    
    typedef struct
    {
            timer_state             state ; // 0 means not ticking, 1 means ticking
            timer_mode              mode ;
            callback_ptr    callback ;
            int32s                  *callback_parameter ;
            int32u                  deadline_countdown ; // a user provided timeout in units of 10 milliseconds
            int32u                  late_counter ; // this user provided flag is incremented every 10 milliseconds to indicate how late the timer actually was
            int32u                  period ;
    } timer_t ;
    
    typedef struct
    {
            callback_ptr callback ;
            int32s           *parameter ;
    } timer_callback_prop_t ;
    
    void    timer_module_init(void) ;
    int32s  timer_poll(int32s, int32s, int32s *) ;
    int32s  timer_exact(int32s, int32s, timer_callback_prop_t, timer_mode) ;
    int32s  timer_stop(int32s) ;
    void    timer_stop_all(void) ;
    int32u  timer_ticks_remaining(int32s) ;
    
    void    TIM1_callback(void) ;
    
    #endif
    
    

  • /*
    ** Copyright (C) 2008 Tamir Michael
    **
    ** This program is free software; you can redistribute it and/or modify
    ** it under the terms of the GNU General Public License as published by
    ** the Free Software Foundation; either version 2 of the License, or
    ** (at your option) any later version.
    **
    ** This program is distributed in the hope that it will be useful,
    ** but WITHOUT ANY WARRANTY; without even the implied warranty of
    ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    ** GNU General Public License for more details.
    **
    ** You should have received a copy of the GNU General Public License
    ** along with this program; if not, write to the Free Software
    ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    */
    
    #ifdef TIMER_MODULE
    
    #include "general_definitions.h"
    #include "timer.h"
    #include "config.h"
    #include "scheduler.h"
    #include "system_services.h"
    #include "system_notifications.h"
    
    // this module uses TIM2 to measure time intervals using polling with a flag indicating that
    // the desired time has elapsed, so that the interrupt line does not have to be disabled
    
    // avoid char and alike and use int instead. registers and stack are 32 bit wide anyway.
    // using a char for the index adds one instruction to its decrement.
    
    // making the size of arrays a multiple of 4 or 8 makes it easy to:
    // * fast calculate the index of the next element in a circular buffer ( index &= (size - 1) )
    // * east unroll of loops to reduce the 2 instruction overhead per loop iteration of the ARM
    
    // to add new timers, increase the value of 'USER_TIMER_SLOTS'. in addition, each task
    // has its own timer for delays.
    
    // note: the first MAX_TASKS timers are dedicated to wait timers of tasks
    // all timers beyond that are user timers.
    static timer_t  s_timers[1 + MAX_TASKS + USER_TIMER_SLOTS] ; // including the idle task
    static int32u   s_max_timers = (sizeof(s_timers) / sizeof(timer_t)) ;
    
    void timer_module_init(void)
    {
            int32u l_index, l_scheduler_state ;
    
            l_index = s_max_timers - 1 ;
    
            refuse_interrupt_context() ;
    
            scheduler_disable(&l_scheduler_state) ;
            system_timer_disable() ;
    
            do
            {
                    timer_t *lp_timer = s_timers + l_index ;
    
                    lp_timer->state = e_timer_not_ticking ;
                    lp_timer->deadline_countdown = 0 ;
                    lp_timer->late_counter = 0 ;
                    lp_timer->mode = e_timer_poll_mode ;
            }
            while ( (l_index--) != 0) ;
    
            system_timer_enable() ;
            scheduler_restore(l_scheduler_state) ;
    }
    
    // call 'timer_poll' repeatedly to wait for a certain time period to elapse.
    // a_timeout should be given using the defines in general_definitions.h. either way,
    // the unit is 10 milliseconds e.g giving this function '30' (or MILLISECONDS_X_10(30) )
    // will start incrementing the provided flag after 300 milliseconds.
    // note that calling this function results in the
    // timer restarting if it has expired, starting if it not started or resuming if the
    // deadline has not been reached yet. the reference point is set only if the timer
    // has expired or if it is not ticking as the time of the call.
    // the return value is the amount time that has elapsed
    // since the deadline has expired, or 0 if the timer is still ticking
    int32s timer_poll(int32s a_index, int32s a_timeout, int32s *a_ticks_left)
    {
            timer_t *lp_timer ;
            int32s   l_result = -1 ;
    
            if (a_timeout < 0)
            {
                    software_error("%d %s %d", ERR_INVALID_PARAMETER, __FILE__, __LINE__) ;
            }
    
            if ( (a_index < s_max_timers) && (a_index >= 0) )
            {
                    int32u l_scheduler_state, l_timer_state ;
    
                    scheduler_disable(&l_scheduler_state) ;
                    system_timer_disable() ;
    
                    lp_timer = s_timers + a_index ;
                    l_timer_state = lp_timer->state ;
    
                    system_timer_enable() ;
                    scheduler_restore(l_scheduler_state) ;
    
                    if (a_ticks_left)
                    {
                            *a_ticks_left = 0 ;
                    }
    
                    if (l_timer_state == e_timer_expired)
                    {
                            scheduler_disable(&l_scheduler_state) ;
    
                            lp_timer->deadline_countdown = a_timeout ; // reload the timer
                            l_result = lp_timer->late_counter ; // return how long before the call the deadline has expired
    
                            scheduler_restore(l_scheduler_state) ;
                    }
                    else if (lp_timer->state == e_timer_not_ticking)
                    {
                            scheduler_disable(&l_scheduler_state) ;
    
                            lp_timer->mode = e_timer_poll_mode ;
                            lp_timer->deadline_countdown = a_timeout ; // reload the timer
    
                            scheduler_restore(l_scheduler_state) ;
    
                            l_result = 0 ;
                    }
                    else
                    {
                            // lp_timer->deadline_countdown is not reloaded if timer is still ticking
                            l_result = 0 ;
                    }
    
                    scheduler_disable(&l_scheduler_state) ;
    
                    lp_timer->late_counter = 0 ;
                    lp_timer->state = e_timer_ticking ;
    
                    if (a_ticks_left)
                    {
                            *a_ticks_left = lp_timer->deadline_countdown ;
                    }
    
                    scheduler_restore(l_scheduler_state) ;
    
                    system_timer_enable() ;
            }
    
            return l_result ;
    }
    

  • // this system call will only stop user timers - never the first MAX_TASKS timers dedicated
    // to waiting periods of tasks
    void timer_stop_all(void)
    {
            int32u  l_index = USER_TIMER_SLOTS - 1, l_scheduler_state ;
            timer_t *lp_timer = s_timers + MAX_TASKS - 1 + USER_TIMER_SLOTS - 1 ;
    
            scheduler_disable(&l_scheduler_state) ;
            system_timer_disable() ;
    
            do
            {
                    lp_timer->state = e_timer_not_ticking ;
                    --lp_timer ;
            } while (l_index-- != 0) ;
    
            system_timer_enable() ;
            scheduler_restore(l_scheduler_state) ;
    }
    
    // stop a specific user timer. stopped a timer whose index is smaller than MAX_TASKS is not
    // allowed as these timers are dedicated to waiting tasks
    int32s timer_stop(int32s a_index)
    {
            int32s l_result = 0 ;
    
            if ( ( (a_index >= 0) && (a_index < MAX_TASKS) ) ||
                     (a_index < 0) )
            {
                    l_result = ERR_INVALID_PARAMETER ;
            }
            else
            {
                    int32u l_scheduler_state ;
    
                    scheduler_disable(&l_scheduler_state) ;
                    system_timer_disable() ;
    
                    (s_timers + a_index)->state = e_timer_not_ticking ;
    
                    system_timer_enable() ;
                    scheduler_restore(l_scheduler_state) ;
            }
    
            return l_result ;
    }
    
    int32u timer_ticks_remaining(int32s a_index)
    {
            int32u l_result = 0 ;
    
            // user is allowed to investigate remaining time for every timer - also timers that
            // are integrated into tasks (for wait purposes...)
            if (a_index < 0)
            {
                    software_error("%d %s %d", ERR_INVALID_PARAMETER, __FILE__, __LINE__) ;
            }
            else
            {
                    int32u l_scheduler_state ;
    
                    scheduler_disable(&l_scheduler_state) ;
                    system_timer_disable() ;
    
                    l_result = (s_timers + a_index)->deadline_countdown ;
    
                    system_timer_enable() ;
                    scheduler_restore(l_scheduler_state) ;
            }
    
            return l_result ;
    }
    
    // invoked from TIM1 ISR
    void TIM1_callback(void)
    {
            timer_t *lp_timer ;
            int32u   l_index = s_max_timers - 1 ;
    
            ++g_tick_count ;
    
            // update all timers
            do
            {
                    lp_timer = s_timers + l_index ;
    
                    // an interrupt can occur before the next call to timer_poll that will reset 'deadline_countdown'
                    // prevent an underflow
                    if ( (lp_timer->state == e_timer_ticking) && (lp_timer->deadline_countdown > 0) )
                    {
                            --lp_timer->deadline_countdown ;
                    }
    
                    if ( (lp_timer->state == e_timer_ticking) && (lp_timer->deadline_countdown == 0) )
                    {
                            // the next call to timer_poll will reveal how late the call way with regards to
                            // the expiration of the timer
                            switch (lp_timer->mode)
                            {
                                    case e_timer_poll_mode:
                                    {
                                            lp_timer->state = e_timer_expired ;
                                            lp_timer->late_counter = 1 ;
    
                                            if ( ( (*(g_tcb + l_index))->status == e_task_waiting) ||
                                                     ( (*(g_tcb + l_index))->status == e_task_waiting_for_message) )
                                            {
                                                    scheduler_declare_task_ready(l_index, (*(g_tcb + l_index))->priority) ;
                                            }
                                    }
                                    break ;
    
                                    case e_timer_exact_period_mode:
                                    {
                                            lp_timer->deadline_countdown = lp_timer->period ;
    
                                            // invoke callback
                                            if (lp_timer->callback)
                                            {
                                                    lp_timer->callback(lp_timer->callback_parameter) ;
                                            }
                                    }
                                    break ;
    
                                    case e_timer_exact_oneshot_mode:
                                    {
                                            lp_timer->state = e_timer_expired ;
    
                                            // invoke callback
                                            if (lp_timer->callback)
                                            {
                                                    lp_timer->callback(lp_timer->callback_parameter) ;
                                            }
                                    }
                                    break ;
    
                                    default:
                                            software_error("%d %s %d\n", ERR_INVALID_TIMER_MODE, __FILE__, __LINE__ ) ;
                            }
                    }
                    else if (lp_timer->state == e_timer_expired) //&& (lp_timer->deadline_countdown == 0) )
                    {
                            ++lp_timer->late_counter ; // this will specify to the caller by how much time he was late
                    }
            } while (l_index-- != 0) ;
    }
    
    #endif // TIMER_MODULE
    

  • // this system call is an asynchronous call that is used to register a callback for exact
    // time-based notifications. any timer can serve as either in 'exact' mode or in 'poll'
    // mode.
    // 'a_index' if the index of the timer in 's_timers', a_timoeut should be given
    // using the MILLISECONDS_X_10 macro, 'a_timer' is a struct that contains a pointer to a
    // callback that shall be invoked once the timer elapses and the required parameter to be
    // send alog, and 'a_mode' is the timer more - must be either 'e_timer_exact_period_mode' or
    // 'e_timer_exact_oneshot_mode' when using the system call.
    // note that the first 1 + MAX_TASKS timers are dedicated to internal timers of tasks, and
    // should not be used for any other purpose. user timers having an index USER_TIMER_0,
    // USER_TIMER_1 etc. should be used instead.
    int32s timer_exact(int32s a_index, int32s a_timeout, timer_callback_prop_t a_timer, timer_mode a_mode)
    {
            int32u   l_scheduler_state ;
            timer_t *lp_timer ;
    
            if ( (a_timeout < 0) ||
                     (!a_timer.callback) ||
                     ( (a_mode != e_timer_exact_period_mode) && (a_mode != e_timer_exact_oneshot_mode) ) )
            {
                    software_error("%d %s %d", ERR_INVALID_PARAMETER, __FILE__, __LINE__) ;
            }
    
            scheduler_disable(&l_scheduler_state) ;
            system_timer_disable() ;
    
            lp_timer = (s_timers + a_index) ;
            lp_timer->state = e_timer_ticking ;
            lp_timer->deadline_countdown = a_timeout ;
            lp_timer->period = a_timeout ;
            lp_timer->callback = a_timer.callback ;
            lp_timer->callback_parameter = a_timer.parameter ;
            lp_timer->mode = a_mode ;
    
            system_timer_enable() ;
            scheduler_restore(l_scheduler_state) ;
    
            return 0 ;
    }
    

  • First off - you should replace your "timed" busy-loop with a real delay. Tamir seems to have helped out with options.

    But you should also invest some time into debugging. You are sending in a ms value into your function and then adding (!) a fixed constant. Your function will give almost the same delay even if you send in the delay value zero.

    If course, you will have to _multiply_ the ms value with a constant to get the number of turns through the loop.

    Just reading the code should have caught this. Stepping through the code with different input parameters should have caught this. Testing with the special case 0 should have caught this. Do spend time on debugging before asking for help. If you can't manage to figure out the problem with a single loop - how do you think you will manage to write real code?

    But once more: Do _not_ use this kind of delay. A change in compiler version, compiler optimization or possibly just available register variables may totally change the speed of a loop.

  • tamir ,

    you be gived a goodly ansewr

    you be having lot of time to write!!

  • Ho no no no kalib...this is what I sometimes do on my way to work :-)
    It is part of an open-source kernel for an STR9 that I'm working on. I'll publish a link here once I am done.

  • hi Tamir,

    does str9 support linux kernel?
    can we download kernel for that?

  • I know that the AT91SAM9261 can run embedded Linux.

  • The AT91SAM9261 has a core with an MMU. However, I don't think that a core like the STR912FW44 can do it because it does not have such a peripheral.

  • That is: ARM926EJ-S core vs. ARM966E-S core.