Page 1 of 3
Virtual Timers
Posted: Sat May 05, 2012 9:47 am
by levrik
Hi there,
I'm having problems implementing a RX-timeout with Virtual timers:
1. Is there a way to implement the vt-callback not in a IRQ-context?
2. Is there a way to reset the timer before it reaches its end to implement a timeout?
Momentarily i've implemented it this way:
Code: Select all
if( chVTIsArmedI( &rfmp->vt ) )
{
chSysLock();
chVTResetI( &rfmp->vt );
chVTSetI( &rfmp->vt, MS2ST(msec), vtmr_cb, rfmp );
chSysUnlock();
}
This code does not work for me properly, because sometimes it seems, that the vt does not start. Looking into the vt-structure with a debugger shows that it contains a valid vt->vt-time, a valid vt->vt_func and a valid vt->vt_par, but the callback does not get called. Any hints?
Thanks in advance.
Thanks.
Re: Virtual Timers
Posted: Sat May 05, 2012 9:59 am
by Giovanni
Hi,
1) Not directly, you can wakeup a thread from there, then do processing from the thread. Alternatively you can use an "Event Timer" see under ./os/various.
2) Yes, it is done in several places, see the function chSchGoSleepTimeoutS() for an example.
You code is failing because before resetting a timer you have to check if it is armed. See the example:
Code: Select all
chSysLock();
if (chVTIsArmedI(vtp))
chVTResetI(vtp);
chSysUnlock();
Giovanni
Re: Virtual Timers
Posted: Mon May 07, 2012 3:11 pm
by levrik
Hi Giovanny,
thank you for your answer. It works now with code similar to the example you've presented.
But i do not understand why the first version did not work, because there the timer was also checked if armed before it was reset.
Kind regards.
Re: Virtual Timers
Posted: Mon May 07, 2012 3:26 pm
by Giovanni
Hi,
Because chVTIsArmedI() was called outside the lock, the whole operation is not atomic. The timer could expire after chVTIsArmedI() and before chVTResetI().
That "sometime", was a clear hint about a race condition somewhere.
Giovanni
Re: Virtual Timers
Posted: Fri Mar 06, 2015 5:03 am
by Chudik
Have a problem with sending data through SPI in Virtual Driver header. Symptoms are as same as I had when I just started to work with SPI and used wrong driver. Can't figure out how to solve it.
Shortly, what I need. I'm using OLED display in my design and since it has limited time of life, I want to switch off the display. So, after showing text on the display, I want to switch on the display, run virtual timer, dim the display after 1 sec and switch off after the next 1 sec.
Here is part of my code
Code: Select all
uint8_t dt_data[2];
void hDisplayTimer(void *arg);
static uint8_t DisplayState = DISPLAYOFF;
static struct VirtualTimer DisplayTimer;
void UI_Send(ui_msg *msg, uint8_t *data, int cnt, ...)
{
va_list ap;
uint8_t i, checkcmd = 0, tag;
int indata;
uint32_t address;
va_start(ap,cnt);
indata = va_arg(ap, int);
msg->tag = (uint8_t)indata;
tag = msg->tag;
switch (tag)
{
....
}
chMsgSend(UI_Console,(msg_t)msg);
if(tag==DISPLAY_TXT)
{
DisplayState = DISPLAYON;
dt_data[0] = DISPLAY_CMD;
dt_data[1] = DisplayState;
spiAcquireBus(&SPID2);
spiStart(&SPID2, &display_cfg);
UISendData(&SPID2, 2, dt_data); // <<<--- here it works without any problem
spiReleaseBus(&SPID2);
chVTSet(&DisplayTimer, S2ST(1), hDisplayTimer, NULL);
}
}
void hDisplayTimer(void *arg)
{
switch(DisplayState)
{
case DISPLAYON: DisplayState = DISPLAYDIM;
break;
case DISPLAYDIM: DisplayState = DISPLAYOFF;
break;
case DISPLAYOFF:
default: DisplayState = DISPLAYOFF;
break;
}
dt_data[0] = DISPLAY_CMD;
dt_data[1] = DisplayState;
spiAcquireBus(&SPID2);
spiStart(&SPID2, &display_cfg);
UISendData(&SPID2, 2, dt_data); // <<<--- here it does not work, data sent to SPI, but can't get back from this function
spiReleaseBus(&SPID2);
chSysLockFromIsr();
chVTSetI(&DisplayTimer, S2ST(1), hDisplayTimer, NULL);
chSysUnlockFromIsr();
}
Probably it happens because I send data to SPI from the timer interrupt handler (is it true?). So I tried to use chSysLockFromIsr() instead of chSysLock() (used in SPISend() anyway). It did not help.
What would be the solution for that?
And another problem related to that. Why after I ran the timer it calls the handler immediately, without actual waiting for one second? I watch window I see the values. Not sure that 0x205 (517d) is correct value for 1 second, though.
CH_FREQUENCY defined as 1000
Re: Virtual Timers
Posted: Fri Mar 06, 2015 5:35 am
by skute
Chudik wrote:Have a problem with sending data through SPI in Virtual Driver header. Symptoms are as same as I had when I just started to work with SPI and used wrong driver. Can't figure out how to solve it.
Shortly, what I need. I'm using OLED display in my design and since it has limited time of life, I want to switch off the display. So, after showing text on the display, I want to switch on the display, run virtual timer, dim the display after 1 sec and switch off after the next 1 sec.
Here is part of my code
Code: Select all
uint8_t dt_data[2];
void hDisplayTimer(void *arg);
static uint8_t DisplayState = DISPLAYOFF;
static struct VirtualTimer DisplayTimer;
void UI_Send(ui_msg *msg, uint8_t *data, int cnt, ...)
{
va_list ap;
uint8_t i, checkcmd = 0, tag;
int indata;
uint32_t address;
va_start(ap,cnt);
indata = va_arg(ap, int);
msg->tag = (uint8_t)indata;
tag = msg->tag;
switch (tag)
{
....
}
chMsgSend(UI_Console,(msg_t)msg);
if(tag==DISPLAY_TXT)
{
DisplayState = DISPLAYON;
dt_data[0] = DISPLAY_CMD;
dt_data[1] = DisplayState;
spiAcquireBus(&SPID2);
spiStart(&SPID2, &display_cfg);
UISendData(&SPID2, 2, dt_data); // <<<--- here it works without any problem
spiReleaseBus(&SPID2);
chVTSet(&DisplayTimer, S2ST(1), hDisplayTimer, NULL);
}
}
void hDisplayTimer(void *arg)
{
switch(DisplayState)
{
case DISPLAYON: DisplayState = DISPLAYDIM;
break;
case DISPLAYDIM: DisplayState = DISPLAYOFF;
break;
case DISPLAYOFF:
default: DisplayState = DISPLAYOFF;
break;
}
dt_data[0] = DISPLAY_CMD;
dt_data[1] = DisplayState;
spiAcquireBus(&SPID2);
spiStart(&SPID2, &display_cfg);
UISendData(&SPID2, 2, dt_data); // <<<--- here it does not work, data sent to SPI, but can't get back from this function
spiReleaseBus(&SPID2);
chSysLockFromIsr();
chVTSetI(&DisplayTimer, S2ST(1), hDisplayTimer, NULL);
chSysUnlockFromIsr();
}
Probably it happens because I send data to SPI from the timer interrupt handler (is it true?). So I tried to use chSysLockFromIsr() instead of chSysLock() (used in SPISend() anyway). It did not help.
What would be the solution for that?
And another problem related to that. Why after I ran the timer it calls the handler immediately, without actual waiting for one second? I watch window I see the values. Not sure that 0x205 (517d) is correct value for 1 second, though.
CH_FREQUENCY defined as 1000
Chudik,
It's likely that the SPI driver uses interrupts and you are blocking them from happening because you are attempting a SPI transfer from an interrupt handler. However, even more incorrect is that you are calling spiAcquireBus from the timer interrupt handler because this will attempt to acquire a mutex and "block" the ISR if the mutex isn't available and cause an exception. As Giovanni always asks, please enable the state checker as it would catch these errors.
Re: Virtual Timers
Posted: Fri Mar 06, 2015 10:21 am
by Chudik
Of course, my mistake was with setting the time - 1 min, not 1 second.
So, the last question in my previous post is not a problem,
However, all the other stuff is valid. When I try to send data to SPI from the handler, the system gets into _unhandled_exception() and stuck in there.
Re: Virtual Timers
Posted: Fri Mar 06, 2015 10:31 am
by Chudik
skute wrote:It's likely that the SPI driver uses interrupts and you are blocking them from happening because you are attempting a SPI transfer from an interrupt handler.
Yes, it is correct statement. However, in my original version I was trying to send message to my UI_ConsoleServer with the same result. After that happened I decided to try such direct attempt.
I will try tomorrow to change it back to sending message to be sure that I get the same problem
skute wrote:As Giovanni always asks, please enable the state checker as it would catch these errors.
How to enable it?
Re: Virtual Timers
Posted: Fri Mar 06, 2015 11:32 am
by Giovanni
Hi,
See the debug section in chconf.h, I recommend enabling assertions, checks and state checker during development. It stops your application in case of errors then inspect the global variable dbg_panic_msg, it points to an error message in memory.
Giovanni
Re: Virtual Timers
Posted: Fri Mar 06, 2015 8:45 pm
by Chudik
OK, got panic message
SV#4, misplaced @p chSysLock().
Traced the program. Got this message in chMsgSend() (chmsg.c)
Line 80. Calling chSysLock()
Do I need to show where chMsgSend() called from?