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
Virtual Timers
Moderators: tfAteba, barthess, RoccoMarco, lbednarz, utzig
- Giovanni
- Site Admin
- Posts: 14704
- Joined: Wed May 27, 2009 8:48 am
- Location: Salerno, Italy
- Has thanked: 1146 times
- Been thanked: 960 times
- Chudik
- Posts: 152
- Joined: Fri Jan 16, 2015 7:51 am
- Location: California
- Has thanked: 7 times
- Been thanked: 1 time
Re: Virtual Timers
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?
Should I read SPI register or DMA linked to the used SPI port?
- 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
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
- Chudik
- Posts: 152
- Joined: Fri Jan 16, 2015 7:51 am
- Location: California
- Has thanked: 7 times
- Been thanked: 1 time
Re: Virtual Timers
Yes, I understood that I need to use Ifunctions
After my experiments I got this code
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)
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)
- Giovanni
- Site Admin
- Posts: 14704
- Joined: Wed May 27, 2009 8:48 am
- Location: Salerno, Italy
- Has thanked: 1146 times
- Been thanked: 960 times
- Chudik
- Posts: 152
- Joined: Fri Jan 16, 2015 7:51 am
- Location: California
- Has thanked: 7 times
- Been thanked: 1 time
Re: Virtual Timers
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
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.
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.
- Chudik
- Posts: 152
- Joined: Fri Jan 16, 2015 7:51 am
- Location: California
- Has thanked: 7 times
- Been thanked: 1 time
Re: Virtual Timers
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?
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?
- 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
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
If you need to do something after spiStartSendI() has finished then you need to use an SPI callback.
Giovanni
- 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
Probably I am unable to explain it properly, my fault. I try to make it more obvious.
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.
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
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
Who is online
Users browsing this forum: No registered users and 114 guests