Pumpkin, Inc.

Pumpkin User Forums

Too short OSDelay()

If you can't make Salvo do what you want it to do, post it here.

Too short OSDelay()

Postby Jenny » Thu Oct 19, 2006 7:02 am

I am using a PIC18F4620 with compiler mcc18 v2.4 and salvo pro v3.2.2, MPLAB v7.31. I have some problems with one OSDelay() call in a task, it seems as though it is just yielding. The OSTimer() is called in an ISR every 10 ms. The other OSDelay:s seems to work fine, the one:s in the same task as well as in the other tasks. The delay I want is 50 ms ( OSDelay(5,Task) ) but when I debug it the execution time often is around 1 ms and the OSTimer() is only called once before it returns to the next instruction in the task. What am I doing wrong? If I change the number of ticks I start to get a delay when tick >40 (40 ms when tick=40, tick=50 -> delay of 160ms).

Code:

code:

/*
****************************************************************************
** Runtime include files
****************************************************************************
*/
#include <delays.h>
#include <usart.h>
#include <portb.h>

/*
****************************************************************************
** OS include files
****************************************************************************
*/
#include <salvo.h>
#include <iros.h>


#define DELAY_50_MS 5
#define DELAY_100_MS 10
#define DELAY_1150_MS 115


static void TaskBacAlarm(void)
{
static UInt16 inP1;
static UInt16 percP1;
static calibPressure_st cpress;
static movementAlarms_et passAlarm;
/*
sound generator
*/
static UInt8 repeats; // no of repeats
static UInt8 cycles; // no of cycles, constant
static UInt8 timeHL; // time high to start with, counted down
static UInt8 cntr = 0;
static UInt8 flash = 0;

/* Init */
cpress = CAL_GetCalibPressure();

for(; ;)
{
/* IN Port */
inP1 = ts_P1;
passAlarm = MVT_alarm;
if(passAlarm == MVT_NO_ALARM )
{
percP1 = P1_ConvertToPercentage(inP1);
// is Pressure below alarm level?
if(inP1 <= cpress.alarm)
{
if (cntr)
{
repeats = 3;
cycles = 0x30;

// Instead of calling function PressureAlarm we generate the sound in task context so we can
// yiel to let the other task run.
// set low pressure alarm variable to true, high and low interrupt can not be disbled->miss a button press
lowPressAlarmOn = TRUE;
do
{
timeHL = 20;
do
{

SED_Bell(timeHL,0,cycles);
--timeHL;
}
while(timeHL > (UInt8)5);

if (repeats == 2)
{ //display red light in the middle of sound
LED_BAC_ON = 0;
LED_WARN_OUT = 1;
}
SED_Bell(timeHL,0,cycles);
//THIS OSDELAY IS THE ONE NOT WORKING
OS_Delay((UInt16)DELAY_50_MS, TaskBacAlarm);
LED_WARN_OUT = 0;
}
while(--repeats);
lowPressAlarmOn = FALSE;
}
else
{
LED_BAC_ON = 0;
LED_WARN_OUT = 1;
OS_Delay((UInt16)DELAY_50_MS, TaskBacAlarm);
LED_WARN_OUT = 0;
}
cntr ^= 1;
ts_lowPress = TRUE;
}
else
{
if(ts_PositionLight)
{
LED_WARN_OUT = 0;
LED_BAC_ON =(UInt16)1;
OS_Delay((UInt16)DELAY_100_MS, TaskBacAlarm);
LED_BAC_ON =(UInt16)0;
}
ts_lowPress = FALSE;
}
}
else if(passAlarm == MVT_P_ALARM)
{
if(ts_PositionLight)
{
if (flash)
{
LED_BAC_ON =(UInt16)1;
}
else
{
LED_WARN_OUT = (UInt16)1;
}
flash ^= (UInt16)1;
OS_Delay((UInt16)DELAY_100_MS, TaskBacAlarm);
LED_BAC_ON =(UInt16)0;
LED_WARN_OUT =(UInt16)0;

}
}
OS_Delay((UInt16)DELAY_1150_MS, TaskBacAlarm);
}
}


[This message has been edited by aek (edited October 19, 2006).]

Jenny
 
Posts: 7
Joined: Wed Oct 18, 2006 11:00 pm

Re: Too short OSDelay()

Postby aek » Thu Oct 19, 2006 8:51 am

That's odd ... since Salvo's timer accuracy is specified as +/- 1 tick, you should only see "nonexistent" delays if you are doing OS_Delay(1) since 1 (-1) = 0. Any delay argument > 1 should always result in a proper, noticeable delay.

I can think of a few things:

1) your tick rate is too fast for your clock, i.e. not enough instructions transpire between calls to OSTimer(). We recommend 2,000-10,000 instruction cycles between calls to OSTimer(). Is it possible some other part of your application is messing with your clock?

2) I would examine the disassembly to ensure that the value=5 parameter is in fact being used in that particular call to OS_Delay(). Occasionally one finds a compiler error.

3) Are you controlling your interrupts (see OSPIC18_INTERRUPT_MASK) properly? If not, you could have an interrupt-based corruption of that parameter or of Salvo itself.

4) Are you _sure_ that the OS_Delay() call is failing, and that it's not something else in overall program flow.

The way I would debug this would be to step through the Salvo source (either via a debug-enabled library, or via a source-code build) and verify that a value of 5 is making its way into the function OSDelay(). This would eliminate all the variable issues and point most likely at incorrect use of OSPIC18_INTERRUPT_MASK.

The way you're using OS_Delay() is consistent across the calls and I don't see any glaring errors.

------------------

-------
aek
aek
 
Posts: 1888
Joined: Sat Aug 26, 2000 11:00 pm

Re: Too short OSDelay()

Postby Jenny » Thu Oct 26, 2006 12:11 am

Hello again,

Thanks for your quick reply, I've been occupied but looked at your tips yesterday.
1) My tick rate is not too fast I think, 25' instructions (10MHz) between calling OSTimer().
2) Using MPLAB I can see that value=5 is used in OSDelay()
3) Changing the interrupt mask is not helping
4) I think this is the problem and I have tried to slim down the code. When I only used the OSDelay()'s in the task without function calls the OSDelay's works fine. However when adding the do{...}while loops the OSDelay will fail when I add a while{} loop in the last do{..}while loop (see code below). (SED_Bell() contains a do{..}while loop with while{} calls in it, see the first code I sent you). I troubleshoot by setting a LED before the OSDelay() call, clearing it after the call and then look at it on the oscilloscope. The PIC handle the loops correctly but it seems as though something that the OSDelay() is using is manipulated when adding the last loop. The system just seems to yield(OS_Yield) since the time the LED is lightened can vary, 1-6ms or more. Doing two calls to OSDelay() after each other will result in what seems to be a yield and then a real delay. I attach some code that is slimmed down and simplified.

Code:

code:
static void TaskBacAlarm(void)
{
/*
sound generator
*/
static UInt8 repeats; // no of repeats
static UInt8 cycles; // no of cycles, constant
static UInt8 timeHL; // time high to start with, counted down
static UInt8 cntr = 0;
static UInt8 flash = 0;
UInt8 tmpTimeHigh;
/* Init */

for(; ;)
{
/* IN Port */
if (cntr)
{
repeats = 3;
cycles = 0x35;
do
{
timeHL = 20;
do
{
//simplified SED_BELL cut'n pasted into task
do
{
tmpTimeHigh = timeHL;

//REMOVING THIS while loop -> OSDelay() works fine!
while(tmpTimeHigh)
{
tmpTimeHigh--;
}
}
while(--cycles);
//end of simplified SED_BELL
--timeHL;
}
while(timeHL > (UInt8)4);
LED_WARN_OUT = 1;
OS_Delay((UInt16)DELAY_50_MS, TaskBacAlarm);
LED_WARN_OUT = 0;
}
while(--repeats);
}
else
{
LED_BAC_ON = 0;
LED_WARN_OUT = 1;
OS_Delay((UInt16)DELAY_50_MS, TaskBacAlarm);
LED_WARN_OUT = 0;
}
cntr ^= 1;
OS_Delay((UInt16)DELAY_1150_MS, TaskBacAlarm);
}
}


[This message has been edited by aek (edited October 26, 2006).]

Jenny
 
Posts: 7
Joined: Wed Oct 18, 2006 11:00 pm

Re: Too short OSDelay()

Postby aek » Thu Oct 26, 2006 8:13 am

quote:
My tick rate is not too fast I think, 25' instructions (10MHz) between calling OSTimer().
25 instructions? Or 25,000 instructions.

I.e. what is the rate (measured, with a 'scope) at which you are calling OSTimer()?

------------------

-------
aek
aek
 
Posts: 1888
Joined: Sat Aug 26, 2000 11:00 pm

Re: Too short OSDelay()

Postby aek » Thu Oct 26, 2006 8:16 am

quote:
//REMOVING THIS while loop -> OSDelay() works fine!
Change it (tmpTimeHigh) to static. The current Salvo port for MCC18 does not support any auto variables in tasks. Note that in your original post all of the task's variables were static, and so I didn't mention this -- thought you knew.

------------------

[This message has been edited by aek (edited October 26, 2006).]

-------
aek
aek
 
Posts: 1888
Joined: Sat Aug 26, 2000 11:00 pm

Re: Too short OSDelay()

Postby Jenny » Thu Oct 26, 2006 9:26 am

Sorry for being unclear 25' = 25,000 instructions. I was a bit quick when I cut'n pasted the code, of course it should be static, I changed this but the problem still exists. Any ideas?
Jenny
 
Posts: 7
Joined: Wed Oct 18, 2006 11:00 pm

Re: Too short OSDelay()

Postby Jenny » Fri Oct 27, 2006 6:04 am

I have tried without optimization, will try to narrow it down to just this task.

Thanks!

Jenny
 
Posts: 7
Joined: Wed Oct 18, 2006 11:00 pm

Re: Too short OSDelay()

Postby aek » Fri Oct 27, 2006 11:14 am

Two things:

1) Have you tried the code with all optimizations disabled?

2) Can you reproduce the problem (maybe a simple applicvation with only this task) in the mPLAB SIM?

------------------

-------
aek
aek
 
Posts: 1888
Joined: Sat Aug 26, 2000 11:00 pm

Re: Too short OSDelay()

Postby aek » Fri Oct 27, 2006 11:19 am

Looking at your latest description, it sounds like there is some effect of your nested functions that is affecting overall timing. Do you have some numbers (in ms) as to how long those delays take?

I suspect what is happening is that you have something in that task that is taking much longer than you think -- several ticks worth -- and this is skewing the behavior of OS_Delay().

------------------

-------
aek
aek
 
Posts: 1888
Joined: Sat Aug 26, 2000 11:00 pm

Re: Too short OSDelay()

Postby Jenny » Tue Oct 31, 2006 6:03 am

Hi again!

I have narrowed it down to just one task and tested it in MPLAB SIM (10 MHz). The problem still exists.

The nestled functions are supposed to generate sound, a specific pattern 400ms*3 with an OSDelay(5, soundTask) between each repetition. So, yes the task will be occupied through several ticks (~40 between each repetition). Is this a problem? The OSTimer is still called every 10 ms. Should the task be shorter? Is there a limit to the execution time of a task?

I attach the code used in MPLAB SIM:

code:

#include <salvo.h>
#include <iros.h>


static void TaskBac(void);
static void SysInit(void);


#define DELAY_50_MS 5
#define DELAY_200_MS 20
#define DELAY_1150_MS 115

void main( void )
{
/* initialize Salvo.*/
OSInit();

/* create tasks */
(void)OSCreateTask(TaskBac, TASK_BAC_P, (UInt8)PRIO_TASK_BAC);

/*lint -e717 */
OSEi();
/*lint +e717 */
for (;;)
{
OSSched();
}
}


static void TaskBac(void)
{
static sysStates_et sysState = SYS_RUN_INIT;
static UInt8 times = 2;
/*
sound generator
*/
static UInt8 repeats; // no of repeats
static UInt8 cycles; // no of cycles, constant
static UInt8 timeHL; // time high to start with, counted down
static UInt8 cntr = 0;
static UInt8 flash = 0;
static UInt8 tmpTimeHigh;


for(;;)
{
switch(sysState)
{
case SYS_SHUTDOWN:
//nothing happens here, debug version
break;

case SYS_STANDBY:
//nothing happens here, debug version
break;

case SYS_START_UP_TEST:
//nothing happens here, debug version
break;

case SYS_RUN_INIT:
// Start timers, interrupts, set variables
SysInit();
/* ok, lets do the state stuff */
/* Let the started tasks exec */
OS_Delay((UInt16)DELAY_200_MS, TaskBac);
sysState = SYS_RUN;
break;

case SYS_RUN:
/* IN Port */
repeats = 3;
cycles = 0x35;
do
{
timeHL = 20;
do
{
//simplified SED_BELL cut'n pasted into task

//REMOVING THIS while loop -> OSDelay() works fine, 50ms delay!
/* do
{
tmpTimeHigh = timeHL;

//REMOVING THIS while loop -> OSDelay() works ok, 45ms delay!
while(tmpTimeHigh)
{
tmpTimeHigh--;
}
}
while(--cycles);*/
//end of simplified SED_BELL
--timeHL;
}
while(timeHL > (UInt8)4);
LED_WARN_OUT = 1;
OS_Delay((UInt16)DELAY_50_MS, TaskBacAlarm);
LED_WARN_OUT = 0;
}
while(--repeats);

OS_Delay((UInt16)DELAY_1150_MS, TaskBacAlarm);
break;

case SYS_SERVICE:
//nothing happens here, debug version
break;

default:
break;
}
}
}

static void SysInit(void)
{

/* T0CON TMR0ON T08BIT T0CS T0SE PSA T0PS2 T0PS1 T0PS0
* 0 1 0 1 0 1 1 1
*/
T0CON = 0x57;
/* Timer 0 int */
INTCON2bits.TMR0IP = 0;
/* enable int prio */
RCONbits.IPEN = 1;
/* Start interrupts*/
INTCON |=0xE0;
/* Start timer 0*/
T0CONbits.TMR0ON = 1;
}


#pragma interruptlow ISRLow save=PROD,section(".tmpdata")
void ISRLow( void )
{
// rember to set RB6 & RB7 low when alarm not active
if ( INTCONbits.TMR0IE && INTCONbits.TMR0IF )
{
INTCONbits.TMR0IF = 0;
TMR0H = TMR0H_RELOAD;
TMR0L = TMR0L_RELOAD;
(void)OSTimer();
}

}


[This message has been edited by aek (edited October 31, 2006).]

Jenny
 
Posts: 7
Joined: Wed Oct 18, 2006 11:00 pm

Next

Return to Coding

Who is online

Users browsing this forum: No registered users and 2 guests

cron