Quality RTOS & Embedded Software

 Real time embedded FreeRTOS RSS feed 
Quick Start Supported MCUs PDF Books Trace Tools Ecosystem TCP & FAT




Loading

Semaphore from SPI Interrupt not working!

Posted by biker126 on October 8, 2007
hello again guys!

I'm sorry to make a new post again but this is the first time I'm using freeRTOS semaphores and I can't get them work :-(

I want to synch my SPI Task with the SPI ISR, so that the Task writes a byte, then waits for the semaphore. When the write is done the ISR fires and should release the semaphore so the SPI Task can go on (read and do anothe write etc).

here's my code:

**********************
SPI TASK
**********************

only the relevant part of the code

for (i = 0; i < ui8_dataLength; i++)
{
// take semaphore once so that its taken
xSemaphoreTake(SPISemaphore, (portTickType)portMAX_DELAY);

// write the data
S0SPDR = *pui8_readPointer++;

// take semaphore again, its empty already so task should block here!
xSemaphoreTake(SPISemaphore, (portTickType)portMAX_DELAY);

// when the ISR has fired the write was done and the semaphore (should) be
// give back. thus, we can read the received data now
*pui8_writePointer++ = S0SPDR;
}

with the for-loop I send several bytes (some sort of "message"). the messages to send are received by queue from another task (that should be working).

*****************
SPI ISR
*****************

void SPI_ISR( void )
{
portENTER_SWITCHING_ISR();

uint32 xTaskWoken = pdFALSE;

ui8_readDummyByte = S0SPSR;
// Clear the interrupt
S0SPINT = 0x01;

// problem lies here: xTaskWoken wont become 0x1 !!
xTaskWoken = xSemaphoreGiveFromISR(SPISemaphore, xTaskWoken);

// Acknowledge interrupt in the VIC
VICVectAddr = 0;
// Switch to the SPITask
portEXIT_SWITCHING_ISR( xTaskWoken );
}

within the spi.h the ISR is defined as __attribute__((naked)) (the ISR itself is working - or at least its executed)
the semaphore I create in main.ch with:
vSemaphoreCreateBinary(SPISemaphore);

I already checked: PCLKSEL0, PINSEL0/1, PCONP, VicAddr10, VicPrio10, VicEnable, S0SPICR, SP0SPCCR and they all should be ok (as the ISR is running).

the only big error I've found is that xTaskWoken won't get true...
System is still LPC2378/68 with GCC/eclipse

I'm at bit clueless now so I would appreciate it if someone has some ideas and tips!

RE: Semaphore from SPI Interrupt not working!

Posted by David Hawks on October 8, 2007
You need to move the first xSemaphoreTake() call outside of your loop. As written, the second time through the loop you are taking the semaphore before writing the second byte. The ISR will not run after the first time so you will be stuck waiting for the semaphore forever.

RE: Semaphore from SPI Interrupt not working!

Posted by biker126 on October 8, 2007
are you sure about that?

I already thought it might got something to do with getting stuck at a "take". but if I understand it right you need to call xSemaphoreTake() TWICE in order to block ONCE? since the first time you attempt to take it the semaphore is free, thus you can take it and continue (no blocking) and then the second time you attmpt to take the semaphore its empty and thus the program blocks.

so what I was thinking is that each time before a SPI write I take the semaphore to empty it, and each time after writing I "take" it again to block.

only thing that come to my mind is that RIGHT AFTER the SPI write the ISR fires (before the task asks for the semaphore a 2nd time) and gives the semaphore back. then the task asks a 2nd time for it and DOESN'T block since its been released already. so what happens in this situation would be that the task blocks at the FIRST semaphoreTake (in the 2nd run of the loop) and it'll never be released as there was no SPI write yet (and thus no ISR firing).

however, I would guess that its kinda unlickly for the ISR to fire inbetween "S0SPDR = *pui8_readPointer++;" and "xSemaphoreTake(..)". and if it does, I dunno really how to solve that issue :-/

RE: Semaphore from SPI Interrupt not working!

Posted by biker126 on October 8, 2007
edit:

I think are are indeed right :-)

I forgot that a xSemaphoreTake() if it blocks still takes the Semaphore as soon as its release and thus the Semaphore is empty again ^^

so I simply need one xSemaphoreTake() call before the first SPI write ever (to initial empty the semaphore. in uC/OS-II you can create empty semaphores... :-p) and then after every single SPI write the semaphore gets emptied again so it always blocks after a write.

that still doesn't solve the problem tho, as the semaphore still ain't given back by the ISR!! :-/

RE: Semaphore from SPI Interrupt not working!

Posted by saiberion on October 9, 2007
In general, if a semphore isn't active a task will block on the semaphore.
But after successful creation you should take the semaphore one time to make sure it's empty.

Creation:
vSemaphoreCreateBinary(xSem);
if (xSem != NULL)
{
___xSemaphoreTake(xSem, 10);
}
The semaphore is now existing and empty

Task Code:
for(;;)
{
[...]
___xSemaphoreTake(xSem, portMAX_DELAY);
___//work with received data
}
After data is processed the task loop starts again and will block in the semaphore now

ISR Code:
[...]
// receive Data and store it
xWoken = xSemaphoreGiveFromISR(xSem, xWoken);
This will wake the Task blocking on semaphore.


For your example it might work to remove the fisr xSemaphoreTake and put it after task creation.

RE: Semaphore from SPI Interrupt not working!

Posted by biker126 on October 9, 2007
thats what I did already. my code structure looks exactly as your suggestion. the problem is tho, that xSemaphoreGiveFromISR() fails to release the semaphore - or at least it fails to wake the task (xWoken is always zero).

RE: Semaphore from SPI Interrupt not working!

Posted by saiberion on October 9, 2007
As far as I know the xWoken mechanism is used if you do multiple calls of xSemaphoreGiveFromISR within the same interrupt. As the documentation says the first call of this function always returns 0 (pdFALSE).
If you use the interrupt to handle a 2nd semaphore or queue this call should return 1 (pdTRUE) and at the end of the Interrupt the determination of the highest priority task is forced with portEXIT_SWITCHING_ISR(xWoken).

So if you application still doesn't send the data maybe you are blocked somewhere else.

RE: Semaphore from SPI Interrupt not working!

Posted by biker126 on October 9, 2007
I have replaced the semaphore by a MessageQueue with room for 1 message now (this should be the same as a semaphore...).

the ISR is posting messages into the queue now and the task is w8ing for them after writing 1 byte. this all works fine, however there's one more odd thing:

the time from when the ISR is executed (I set a Pin to detect that with a logic analyzer) to until the xQueueReceive() stops blocking (right after xQueueReceive i set another Pin) is 128us!!!

if I under stand freeRTOS correct, then the ISR should force a reschedule (xQueueSendToBackFromISR() gives a TaskWoken back which I pass to EXIT_SWITCHING_ISR(TaskWoken)) and then my task (which is w8ing for a message to be posted) should get scheduled immediatly (it is the highest task that got something to do. all other tasks like LED/LCD one have lower priority).

but I dont think that the scheduling time is 128us (that would be aweful for a "RTOS" :-p).

so I'm wondering what could be the reason for that huge delay between execution of ISR and the Task continuening execution...


[ Back to the top ]    [ About FreeRTOS ]    [ Sitemap ]    [ ]




Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.

Latest News

FreeRTOS kernel V10 is available for immediate download. Now MIT licensed.


FreeRTOS Partners

ARM Connected RTOS partner for all ARM microcontroller cores

IAR Partner

Microchip Premier RTOS Partner

RTOS partner of NXP for all NXP ARM microcontrollers

STMicro RTOS partner supporting ARM7, ARM Cortex-M3, ARM Cortex-M4 and ARM Cortex-M0

Texas Instruments MCU Developer Network RTOS partner for ARM and MSP430 microcontrollers

OpenRTOS and SafeRTOS