Virtual Timers

ChibiOS public support forum for all topics not covered by a specific support forum.

Moderators: tfAteba, barthess, RoccoMarco, lbednarz, utzig

User avatar
levrik
Posts: 26
Joined: Wed Dec 21, 2011 7:35 am

Virtual Timers

Postby levrik » Sat May 05, 2012 9:47 am

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.

User avatar
Giovanni
Site Admin
Posts: 14704
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1146 times
Been thanked: 960 times

Re: Virtual Timers

Postby Giovanni » Sat May 05, 2012 9:59 am

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

User avatar
levrik
Posts: 26
Joined: Wed Dec 21, 2011 7:35 am

Re: Virtual Timers

Postby levrik » Mon May 07, 2012 3:11 pm

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.

User avatar
Giovanni
Site Admin
Posts: 14704
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1146 times
Been thanked: 960 times

Re: Virtual Timers

Postby Giovanni » Mon May 07, 2012 3:26 pm

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

User avatar
Chudik
Posts: 152
Joined: Fri Jan 16, 2015 7:51 am
Location: California
Has thanked: 7 times
Been thanked: 1 time

Re: Virtual Timers

Postby Chudik » Fri Mar 06, 2015 5:03 am

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

skute
Posts: 64
Joined: Wed Aug 29, 2012 10:17 pm

Re: Virtual Timers

Postby skute » Fri Mar 06, 2015 5:35 am

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.

User avatar
Chudik
Posts: 152
Joined: Fri Jan 16, 2015 7:51 am
Location: California
Has thanked: 7 times
Been thanked: 1 time

Re: Virtual Timers

Postby Chudik » Fri Mar 06, 2015 10:21 am

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.

User avatar
Chudik
Posts: 152
Joined: Fri Jan 16, 2015 7:51 am
Location: California
Has thanked: 7 times
Been thanked: 1 time

Re: Virtual Timers

Postby Chudik » Fri Mar 06, 2015 10:31 am

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?

User avatar
Giovanni
Site Admin
Posts: 14704
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1146 times
Been thanked: 960 times

Re: Virtual Timers

Postby Giovanni » Fri Mar 06, 2015 11:32 am

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

User avatar
Chudik
Posts: 152
Joined: Fri Jan 16, 2015 7:51 am
Location: California
Has thanked: 7 times
Been thanked: 1 time

Re: Virtual Timers

Postby Chudik » Fri Mar 06, 2015 8:45 pm

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?


Return to “General Support”

Who is online

Users browsing this forum: No registered users and 106 guests