Virtual Timers

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

Moderators: tfAteba, barthess, RoccoMarco, lbednarz, utzig

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 » Sat Mar 07, 2015 11:42 pm

Giovanni,
No,no. You are the author and for you everything is easy. I'm still newbie in RTOS in general and in ChibiOS as well. Some obvious things for you still hard to follow to me. Sorry, that I take so much time from you.

Giovanni wrote:you have to put the spiUnselect() in the SPI callback, this way it is performed AFTER the SPI transfer is over without the need for delays.

So, you are talking about the callback that is part of my SPIConfig display_cfg.
Hmm... I thought this callback used for processing data after SPI/DMA interrupt in slave mode, for example...
How that callback function knows that it should call spiUnselect() only after SPI had been used in virtual timer handler?

I probably need to find an example of some other callbacks for SPI or serial port... :roll:

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 » Sun Mar 08, 2015 7:43 am

The demo ARMCM4-STM32F407-DISCOVERY in 2.6.7 does that.

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 » Sun Mar 08, 2015 1:18 pm

It does not work for me. Probably, because in this demo SPI transfer always starts in the ADC interrupt. In my case SPI transfer can be started either from some other function or from VT handler. I used a global variable to differentiate these cases and unselect the port in the callback only when it started in VT handler. May be I did it wrong?

Code: Select all

static const SPIConfig display_cfg =
{
   DisplayTimerSPIend,
   DISPLAY_CS_PORT,
   DISPLAY_CS_PIN,
   BR_VALUE      // Since CPHA and CPOL are 0, we don't need to set any control for it
} ;


static bool_t  DisplayTimerUsed = false;
static struct VirtualTimer DisplayTimer;
uint8_t dt_data[2];

void  hDisplayTimer(void *arg)
{
    ...

         palClearPad(DISPLAY_DC_PORT, DISPLAY_DC_PIN);   // display sending commands mode

         dt_data[0] = DISPLAY_CMD;
         dt_data[1] = DisplayState;

         chSysLockFromIsr();
            DisplayTimerUsed = true;
            SPID2.config = &display_cfg;
            spiSelectI(&SPID2);
            spiStartSendI(&SPID2, 2, dt_data);
         chSysUnlockFromIsr();

}

 void  DisplayTimerSPIend(SPIDriver *spip)
 {
    chSysLockFromIsr();
    if(DisplayTimerUsed == true)
    {
         DisplayTimerUsed = false;
         spiUnselectI(spip);
    }
    chSysUnlockFromIsr();
 }

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 » Tue Mar 10, 2015 1:33 am

May be go another way?
Let's say, VT sets some event and event handler sends according message to my thread with usual API. In this case my SPI interface would be called always from one place.

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 » Tue Mar 10, 2015 9:01 am

You cannot start two SPI transfer at the same time, how you achieve this is part of the design of your application, I cannot help there.

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 » Tue Mar 10, 2015 5:01 pm

No, I'm talking about exactly about one SPI transfer. The idea is following. My task that uses SPI for the display communication starts VT after certain command and continues to wait for new messages. And VT at its time generates event ( I saw that I function in some example - need to find it again :)) instead of sending data through SPI by its own. And that event handler will send a new message to my task for the new SPI transaction. See, there are no simultaneous two SPI transfers. And all of them started from one task.
Do you think it will not work?

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 » Tue Mar 10, 2015 5:04 pm

Everything will work unless it violates the driver state machine, in that case an assertion would catch the error, so just try.

In general, I always recommend to follow the KISS principle.

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 » Tue Mar 10, 2015 9:57 pm

I agree about the KISS :)
That is why I put just a simple loop (for the beginning), but that is wrong way for the multitasking environment. Using SPI callback does not work in my case.

Could you direct me to the simple example or demo for events handling?

============
UPD. Looks like Asynchronous wakeup from at http://www.chibios.org/dokuwiki/doku.ph ... tos:wakeup is good start.

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 » Wed Mar 11, 2015 1:42 am

Got it!!!

Code: Select all

static uint8_t  DisplayState = DISPLAYOFF;
static struct VirtualTimer DisplayTimer;

static Thread *tUI_EventsHandler;
static WORKING_AREA(waUI_EventsHandler, THD_WA_SIZE(128));
static msg_t UI_EventsHandler(void *p);
...

void UI_Console_Init(void)
{
 ...
    tUI_EventsHandler = chThdCreateStatic(waUI_EventsHandler, sizeof(waUI_EventsHandler),NORMALPRIO+1, UI_EventsHandler, NULL);
}

void UI_Send(ui_msg *msg, uint8_t *data, int cnt, ...)
{
...
  if(tag==DISPLAY_TXT)
    {
         ...
         chVTSet(&DisplayTimer, S2ST(5), hDisplayTimer, NULL);  // first set of VT if text sent to display. Sets time of full brightness
    }
}

void  hDisplayTimer(void *arg)
{
    (void)arg;

    chSysLockFromIsr();
    switch(DisplayState)
    {
        case DISPLAYON:  DisplayState = DISPLAYDIM;
                         chVTSetI(&DisplayTimer, S2ST(5), hDisplayTimer, NULL);  //Sets time of dim brightness
                         break;
        case DISPLAYDIM:
        case DISPLAYOFF:
        default:        DisplayState = DISPLAYOFF;
                        break;
    }
    chEvtSignalI(tUI_EventsHandler, (eventmask_t)DISPLAY_VT_REQUEST);
    chSysUnlockFromIsr();
}

static msg_t UI_EventsHandler(void *arg)     // VT event only yet
 {
     uint8_t localDisplayState;
    (void)arg;

     tUI_EventsHandler = chThdSelf();
     while(true)
     {
         chEvtWaitAny((eventmask_t)DISPLAY_VT_REQUEST);
         chSysLock();
         localDisplayState = DisplayState;
         chSysUnlock();

         UI_Send(&ui_dtmessage, dt_data, 2, DISPLAY_CMD, localDisplayState);
     }
    return 0;
 }


Seems like simple enough to respond to KISS requirements :)

Would be nice to figure out how to use arguments pointer and msg_t return... :)


Return to “General Support”

Who is online

Users browsing this forum: No registered users and 13 guests