We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
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.