Virtual Timers

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

Moderators: tfAteba, barthess, RoccoMarco, lbednarz, utzig

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 9:06 pm

Hi,

The problem is that you cannot call any function from any context, there are rules to follow.

From callbacks and ISRs you can only call those functions that end with upper case I. This is what that SV#4 means. Read "kernel concepts" in the documentation, function classes are explained 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 » Fri Mar 06, 2015 11:41 pm

Seems like instead of using _spi_wait_s(spip) in this case I should use old fashioned reading register in while loop, isn't it?
Should I read SPI register or DMA linked to the used SPI port?

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 Mar 07, 2015 7:35 am

Chudik wrote:Seems like instead of using _spi_wait_s(spip) in this case I should use old fashioned reading register in while loop, isn't it?
Should I read SPI register or DMA linked to the used SPI port?


You should not do any of this... just use the right function in the right place, few hints:

1) Messages are meant as thread-thread mechanism, you cannot use them from a callback.
2) You cannot use xxxStart() from a callback.
3) From callbacks you can only use functions with name ending in "I".

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 » Sat Mar 07, 2015 8:12 am

Yes, I understood that I need to use Ifunctions
After my experiments I got this code

Code: Select all

void  hDisplayTimer(void *arg)
{

    switch(DisplayState)
    {
        case DISPLAYON:  DisplayState = DISPLAYDIM;
                         break;
        case DISPLAYDIM: DisplayState = DISPLAYOFF;
                         break;
        case DISPLAYOFF:
        default:         DisplayState = DISPLAYOFF;
                         break;
    }


         chSysLockFromIsr();
         chVTSetI(&DisplayTimer, S2ST(5), hDisplayTimer, NULL);
         chSysUnlockFromIsr();


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

//         UI_Send(&ui_dtmessage, dt_data, 2, DISPLAY_CMD, DisplayState);
         dt_data[0] = DISPLAY_CMD;
         dt_data[1] = DisplayState;
//         spiAcquireBus(&SPID2);
/*         spiStart(&SPID2, &display_cfg);*/
         SPID2.config = &display_cfg;
//         spi_lld_start(&SPID2);


          spiSelectI(&SPID2);
          spiStartSendI(&SPID2, 2, dt_data);
//          _spi_wait_s(&SPID2);
            while(SPID2.spi->SR & 0x0040); // wait while SPI busy
          spiUnselectI(&SPID2);

//         spiReleaseBus(&SPID2);
}


Since I can not use _spi_wait_s() (got SV#11, misplaced S-class function.), but need to wait end of sending data, I read the SPI Status register.
When I go step by step this part is working, if run without stepping seems like data not been sent through SPI (text on the screen would not dim or off). However, system would not lock anywhere. Just coming every 5 sec back to this function.

What did I miss?

If I uncomment spi_lld_start(&SPID2) the system stuck in _idle_thread() (file chsys.h)

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 Mar 07, 2015 9:44 am

You cannot wait into a callback, it is called from an ISR.

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

Yes, I understand that. Actually there was no wait in one of my intermediate experiments. I just took it away again. The result is the same - when I go step by step, everything works, when I run it - system does not halt, but data does not go through SPI.

Update:
If I set break point on spiUnselectI(&SPID2); after sending data, everything is working. In free run - it does not. That means that in free run SPI takes CS signal away too fast - early than hardware finished the transaction. There should be some delay to finish it. Without using RTOS I would use either READY signal from SPI status register, or from DMA, or just inserted a couple of NOP commands. There has to be some waiting delay. Especially in situation when the processor works at 32 Mhz and SPI speed is 1MHz.
So, what kind of delay can I use here?

Update 2.
Put simple delay

Code: Select all

          spiSelectI(&SPID2);
          spiStartSendI(&SPID2, 2, dt_data);
          for(i=0; i<32; i++);
          spiUnselectI(&SPID2);

It works, but this is a bad style even with regular programming without multitasking.
Looks like the counter value will depend on the uC speed and SPI speed relation. In this case with sending two bytes this counter works at 32 and higher number, does not work if I put 16.
It is definitely a wrong solution and there should be a better way in RTOS.

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 6:39 pm

If I had one device on SPI bus I could use mechanism of automatic NSS insertion, but I have two devices, so, I need to use pair of "manual" functions spiSelectI()/spiUnselectI().

And I also have buttons connected through SPI extender. They have to be debounced, that means I will need to use a debouncing virtual timer, and it will require to use SPI again, but for reading in two steps: write command and address (2 bytes), read the data (1byte). Use the loop delay again?

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 Mar 07, 2015 8:35 pm

spiStartSendI() starts the operation and the operation continues even AFTER spiStartSendI() has returned, it is an asynchronous function.

If you need to do something after spiStartSendI() has finished then you need to use an SPI callback.

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

Yoг missed me... :roll:
Call SPI callback after I used spiStartSendI() in virtual interrupt handling?!!! :shock:

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 Mar 07, 2015 9:32 pm

Probably I am unable to explain it properly, my fault. I try to make it more obvious.

Code: Select all

spiSelectI(&SPID2);
spiStartSendI(&SPID2, 2, dt_data);
for(i=0; i<32; i++);
spiUnselectI(&SPID2);


This works because you are moving the spiUnselect() in time AFTER the SPI transfer completed, same when you go in sigle step, you just give it enough time to complete.

Code: Select all

If you need to do something after spiStartSendI() has finished then you need to use an SPI callback.


In other words 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.

Giovanni


Return to “General Support”

Who is online

Users browsing this forum: No registered users and 114 guests