Hi!
I am trying to use the standard pattern of having a task blocked on a (binary)semaphore and having a event give on that semaphore.
When I used to do this om a STM32, i used a macro called taskYEILD_FROM_ISR. However, i did that on the very last line in the ISR. In CW + PE, we normally dont edit the ISR but rather the event supplied.
I have instead used this code in my Event.
void AS1_OnRxChar(void){ /* Write your code here ... */ (void)AS1_DisableEvent(); if (xSemaphoreGiveFromISR(AS1_sem, NULL)) { // portTASK_SWITCH_FROM_ISR(); portYIELD(); }}
And then, after the data has been gotten out of the SCI, i would have reenabled the event.
Is this an acceptable approach, or should i refactor this?
// Martin
Hello,
taskYIELD_FROM_ISR is not a standard macro in an FreeRTOS port from what I can tell. I would need to check how this has been implemented on the STM32.
To your question: it depends on the cpu you use, and of course of the port you are using. I assume HCS08.
So here is what will happen:
- an interrupt from the RX line happens
- PE handles the interrupt entry, plus calls the AS1_OnRxChar() function
- If you can give the semaphore, then you do a portYIELD()
- portYIELD() will set the interrupt flag for a SWI interrupt. But as you are already in an ISR (with the I bit set), interrupts are disabled. So there will be no context switch right away
- the OnRxChar() function finishes, so does the caller.
- an RTI happens (end of interrupt)
- the CPU sees that there is a pending SWI interrupt, and calls that ISR (calling the RTOS to deal with the context switch)
So in general your approach works.
The problem I see with your approach is that you disable the events for RX. So you might miss incoming traffic if you are not fast enough.
I had a similar (I think) think, where I received interrupts and needed to deal with the incoming data. Not sure why you need to block another task, but I used a buffering instead:
Queue definition:
#define RADIO_QUEUE_NOF_ITEMS 8 /* number of items in the queue */#define RADIO_QUEUE_ITEM_SIZE 32 /* size of each queue item */static xQueueHandle RADIO_MsgQueue; /* queue for messages, format is: kind(8bit) dataSize(8bit) data */
Queue Initialization:
RADIO_MsgQueue = FRTOS1_xQueueCreate(RADIO_QUEUE_NOF_ITEMS, RADIO_QUEUE_ITEM_SIZE); if (RADIO_MsgQueue==NULL) { /* queue creation failed! */ for(;;) {} /* not enough memory? */ }
Then from the ISR a build a message packet (with my own special format of the message):
static void QueueMessage(uint8_t kind, const char *msg, uint8_t msgSize) { /* format is: kind(8bit) dataSize(8bit) data */ uint8_t i, buf[RADIO_QUEUE_ITEM_SIZE]; signed portBASE_TYPE pxHigherPriorityTaskWoken; buf[0] = kind; buf[1] = msgSize; i = 2; while(msgSize>0 && i<sizeof(buf)) { buf[i++] = *msg; msg++; msgSize--; } if (FRTOS1_xQueueSendToBackFromISR(RADIO_MsgQueue, &buf[0], &pxHigherPriorityTaskWoken)!=pdTRUE) { /* was not able to send to the queue. Well, not much we can do here... */ }}
The problem I would have here (as noted above) if my queue is full. If anywone has a good solution, let me know.
Then I call following method from my task to handle the queue:
/*! \brief Radio application state machine */void RADIO_Handle(void) { uint8_t buf[RADIO_QUEUE_ITEM_SIZE]; /* poll radio message queue */ if (FRTOS1_xQueueReceive(RADIO_MsgQueue, buf, 0)==pdPASS) { /* received message from queue */ RADIO_HandleMessage(buf); }}
That approach worked very well for me.
Hope that helps.
Hi BlackNight and thanks for your answer.
Yes i was using hcs08
Regarding the disabeling of the interrupt: I happen to know that my datastream will be very burst oriented. Thus, once i have received one byte, i can simply poll untill there are no more bytes to receive and then i reenable the interrupt. This will decrease the interrupt load.
Best regards
Martin
Hi BlackNight.
There is one warning that you could surpress.
in the define vSemaohreCreateBinary macro, add a "(void)" infront of the xSemaphoreGive call.
I guess that this should really be inside the FreeRTOS code instead, but as they dont support hcs08, i guess that they dont care about surpressing warnings from codewarriors compiler.
Best regards
Martiin
Hi Martin,
Thanks for the hint. But maybe you have an older version?
I already have this cast in my version.
Otherwise you can simply add it yourself in your version.
You find the files which are used for the RTOS in
C:\ProgramData\Processor Expert\CWMCU_PE5_00\Drivers\freeRTOS
(Windows7, CodeWarrior for MCUf10.x)
Thanks!
BK
Hi again!
I had to run the older version since i needed the old layout for the timers. You changed the timer used for the systick and I needed the old layout. I tried to migrate but all my attempts failed.
Anyway. Nice to see that you are maintaining it so well.
Best regards
Martin
thanks for BlackNight,
I have success run "FreeRTOS_31.07.2011.zip"
but how use xSemaphoreGiveFromISR in a interrupt event, like AS1_OnFreeTxBuf,
and force a context switch.
cai
Perhaps reading this would help:
http://www-users.cs.york.ac.uk/~pcc/MCP/FreeRTOS/html/group__xSemaphoreGiveFromISR.html
How about a FRTOS task bean?
Or did I miss something?
Hi Jim,
the question would be: what should this task do?
I mean: pretty much the task could do anything.
If a component (aka 'bean') would create a task, this would be generated by the component.
You could not add code to that code (unless you suspend code generation).
A way would be to have the component install a call back (which would be filled by the user).
What I could imagine is a component 'Task' with following properties:
- task name, priority, stack, etc
- delayunitl or delay (in ms)
Then this would create a task with an endless loop (waiting for the given time, if any), and would call a user function (where all the user code is located.
I think this might be useful. For me it was much more straight forward to just do things by hand. But now I think it might be worthwile to create such a component (that would not be too complicated).
Anyone else interested?
BK
Yes, that is pretty much what I had in mind.
You add a task bean with the properties you want and as you said an event callback is create where you put the task code, and you have code that starts the task at start up.
I have actaully used frtos before, but to be honest I did not remember how th add a task (iirc, I had a table where you put the tasks you wanted to start with a function pointer and the props for the task. Then in main I had a for loop that went thru the table and started them).
After reading this post, I added your beans (note: PE was a little wierd about have the FRTOD bean show up - it did finally), added the FRTOS bean then thought, now where (and how) to add a task....
Ok, I see what I can do over the week end (creating such a task component). Stay tuned.
Here are the simple steps how to create your task:
create a header file (I usually name it 'Application.h', with following:
/*-------------------------------------------------------------------------------------------------*/
#ifndef APPLICATION_H_
#define APPLICATION_H_
#include "Event.h"
void APP_Run(void);
#endif /* APPLICATION_H_ */
/*-------------------------------------------------------------------------------------------------*/
then create a file Application.c, with following:
/*-------------------------------------------------------------------------------------------------*/
#include "Application.h"
#include "FRTOS1.h" /* FreeRTOS component header */
static portTASK_FUNCTION(MainTask, pvParameters) {
(void)pvParameters; /* parameter not used */
for(; {
/* do what you have to do */
FRTOS1_vTaskDelay(10/portTICK_RATE_MS);
}
}
void APP_Run(void) {
if (FRTOS1_xTaskCreate(
MainTask, /* pointer to the task */
(signed portCHAR *)"Main", /* task name for kernel awareness debugging */
configMINIMAL_STACK_SIZE+100, /* task stack size */
(void*)NULL, /* optional task startup argument */
tskIDLE_PRIORITY, /* initial priority */
(xTaskHandle*)NULL /* optional task handle to create */
) != pdPASS) {
for(;{}; /* error! probably out of memory */
}
FRTOS1_vTaskStartScheduler();
}
/*-------------------------------------------------------------------------------------------------*/
Finally, call APP_Run() from main() in ProcessorExpert.c:
/*-------------------------------------------------------------------------------------------------*/
.....
/* User includes (#include below this line is not maintained by Processor Expert) */
#include "Application.h" /* <<<<<< add this */
void main(void)
{
/*** Processor Expert internal initialization. DON'T REMOVE THIS CODE!!! ***/
PE_low_level_init();
/*** End of Processor Expert internal initialization. ***/
APP_Run(); /* <<<<<< add this */
/*** Don't write any code pass this line, or it will be deleted during code generation. ***/
/*** Processor Expert end of main routine. DON'T MODIFY THIS CODE!!! ***/
for(;{}
/*** Processor Expert end of main routine. DON'T WRITE CODE BELOW!!! ***/
} /*** End of main routine. DO NOT MODIFY THIS TEXT!!! ***/
That's it :smileyhappy:
BK
Hi,
have you downloaded the latest version from
http://www.steinerberg.com/EmbeddedComponents/
?
I ask because earlier version of the FreeRTOS port for S08 did not had proper support for things like
xSemaphoreGiveFromISR().
Now your question indicates that you want to call xSemaphoreGiveFromISR() from another (stock) Processor Expert component code? For this you need to suspend code generation for that component, otherwise your added code will be overweritten.
BK
"I ask because earlier version of the FreeRTOS port for S08 did not had proper support for things like xSemaphoreGiveFromISR()."
Yes. use newest one, have define xSemaphoreGiveFromISR()
"Now your question indicates that you want to call xSemaphoreGiveFromISR() from another (stock) Processor Expert component code?"
Yes. If I have to rewrite stock component interrupt routine, like your system time tick service ?
#prama NO_ENTRY etc.
Hello,
>>Yes. If I have to rewrite stock component interrupt routine, like your system time tick service ?
I did not had to rewrite the system tick service: I used inheritance (the FreeRTOS component inherited the timer component, and re-used that code). But I think this is not much of relevance for you as you need to implement a component for this (you cannot do this within your normal code).
Ideally in your case the stock component would have an event called in the ISR, and then you can do whatever you need to do. I suggest you submit a service request for this as a new feature?
Until this is implemented (or somebody finds another way): you can as well take (copy) the generated code, and make a normal C module out of it. Then you can change/add/whatever you need.
BK
May be following code should work, AS1_OnMyFreeTxBuf() was called by a PE ISR.
it make a nest interrup happen, and more local stack be used.
but I don't know if have any after-effects.
void AS1_OnMyFreeTxBuf(void){ /* Write your code here ... */ static signed portBASE_TYPE wake = pdFALSE; wake = FRTOS1_xSemaphoreGiveFromISR(semOfAS1, &wake); if( wake ) { // We should not call portTASK_SWITCH_FROM_ISR() directly FRTOS1_taskYIELD(); // make switch by swi ISR }}
I don't really have a need for this, but Eric I know what it is like to put somehting out there and not get any feedback, so I got this all working just to see how it would go.
Follow up:
I got this all to work, but I was thrown off by the field called SWINumber in the main FRTOS component. What does this field really do? Do you need it? I at first set it to 1 thinking that it would use trap 1, but of course that generates a spurious interrrupt on EPORT. I eventually set it to 0 then correctly configured the RTOSSWI1 component for trap 1.
I also found a comment "If the "Generate ISR" project option is set to "yes", Processor Expert....". I am some what familiar with PE put I did not find any "Project Options"...
- I set the the total heap size in the FRTOS component to 4048 for the two tasks. Obviously, if you have a task component, this will get up dated automagically. You will end up looping in "FRTOS1_vApplicationMallocFailedHook" if there is not enough memory for a task, rather that the 0 I expected returned from FRTOS1_xTaskCreate (based on your example).
This is fine, it was wasy to look up the stack and see what caused it.
-If you leave the prioritys of the task at tskIDLE_PRIORITY they never actaully execute so I set one the tskIDLE_PRIORITY+3 and the other to tskIDLE_PRIORITY+2.
- The name of the second task is my example code should be Main2.
Updated Code:
/* * APP.C * * Created on: Sep 15, 2011 * Author: jimd */#include "FRTOS1.h" /* FreeRTOS component header */#include "App.h" portTASK_FUNCTION(MainTask, pvParameters);static portTASK_FUNCTION(MainTask2, pvParameters);signed portBASE_TYPE StartTasks(void); const TASKTABLE _task_table[]={ {MainTask,(signed portCHAR *)"Main",configMINIMAL_STACK_SIZE+100,(void*)NULL,tskIDLE_PRIORITY+3,(xTaskHandle*)NULL }, {MainTask2,(signed portCHAR *)"Main2",configMINIMAL_STACK_SIZE+100,(void*)NULL,tskIDLE_PRIORITY+2,(xTaskHandle*)NULL }, {0} };static portTASK_FUNCTION(MainTask, pvParameters) { (void)pvParameters; /* parameter not used */ for(;;) { /* do what you have to do */ FRTOS1_vTaskDelay(10/portTICK_RATE_MS); }}static portTASK_FUNCTION(MainTask2, pvParameters) { (void)pvParameters; /* parameter not used */ for(;;) { /* do what you have to do */ FRTOS1_vTaskDelay(10/portTICK_RATE_MS); }} signed portBASE_TYPE StartTasks(void){ int i; signed portBASE_TYPE rc= pdPASS; for(i = 0 ; _task_table[i].pvFunction ; ++i) { rc = FRTOS1_xTaskCreate( _task_table[i].pvFunction, /* pointer to the task */ _task_table[i].name, /* task name for kernel awareness debugging */ _task_table[i].stack_size, /* task stack size */ _task_table[i].parameters, /* optional task startup argument */ _task_table[i].priority, /* initial priority */ _task_table[i].task_handle /* optional task handle to create */ ); if( rc != pdPASS) break; } return rc;}void APP_Run(void) { if ( StartTasks() != pdPASS) { for(;;){}; /* error! probably out of memory */ } FRTOS1_vTaskStartScheduler();}
just a follow up:
- an example for the 52259 can be found on
http://www.steinerberg.com/EmbeddedComponents/Example_TWR-52259_FreeRTOS/home.htm
- >>"I also found a comment "If the "Generate ISR" project option is set to "yes", Processor Expert....". I am some what familiar with PE put I did not find any "Project Options"..."
Not sure about this one, but the 'project' (or build' options are in the CPU component settings: select the CPU component, then in the Component Inspector there is a 'Build options' tab which allow you to set things like generating vectors, etc.
BK
Well, I will have to figure out how to add P&E Bdm as you did not have that in there and I do not use the OSBDM on this board.
Also, how come you did not put a RAM config in it? It is soooo much fast to test things in RAM.
When I create sample projects, I put fash and ram, P&E, OSBDM and USBDM as I want to user to be be able ot jusst run it....
Hi,
to make things easier to switch between OSBDM and the P&E Multilink, I have added a P&E Multilink connection to the example on http://www.steinerberg.com/EmbeddedComponents/Example_TWR-52259_FreeRTOS/home.htm
Attached here as well.
BK