I'm basically trying to get a LED to light up after I push a button. Below is the snippet of the code that's supposed to handle this:
void task_player1(void *pvParameters)
{
while (1)
{
if (xSemaphoreTake(player1_signal, portMAX_DELAY))
{
printf(">>>Semaphore taken\n<<<");
ioport_set_pin_level(L1, HIGH);
xSemaphoreGive(player1_signal);
}
else
{
ioport_set_pin_level(L1, LOW);
}
}
}
void task_ctrl(void *pvParameters)
{
bool button1 = 0;
while (1)
{
button1 = ioport_get_pin_level(B1);
if (button1)
{
xSemaphoreGive(player1_signal);
printf("Semaphore given\n");
}
}
}
The way I'm envisioning this is that task_ctrl
gives the semaphore on button press. Task_player1
is blocked until it takes the semaphore after which it should turn on the LED.
The problem is it never seems to take the semaphore. I'm running the printf
statements to show me how far the program reaches and it never gets into the part where the LED lights up. But when I run xSemaphoreGive
without the button press in task_ctrl
the semaphore is taken.
The weird part is that "Semaphore given\n"
statement gets printed out on button click which should mean that the semaphore is given as well but never gets taken.
The tasks work on their own, I've even managed to give the semaphore without the button press if-statement like I stated above.
I'm guessing it's something with the button press code, which also works on it's own outside the tasks. So what am I doing wrong? Am I not using the FreeRTOS correctly?
Edit: Including the task creation code
#define TASK_STACK_SIZE (2048/ sizeof(portSTACK_TYPE))
xTaskCreate(task_ctrl, (const signed char * const) "Control", TASK_STACK_SIZE, NULL, 1, NULL);
xTaskCreate(task_player1, (const signed char * const) "Player1", TASK_STACK_SIZE, NULL, 1, NULL);
Edit 2: Probably something I should have mentioned is that I'm using FreeRTOS 7.3 since Atmel Studio doesn't have any newer versions. So no yield functions are available, as far as I can tell.
task_ctrl
never blocks - which will prevent any task of equal or lower priority from ever running. So if task_player
is equal or lower priority the the task will never be scheduled even when the semaphore is given.
It appearing to work without the button polling is harder to explain, but you have not shown that code so I cannot comment.
You should do two things:
task_ctrl
has lower priority that at least task_player1
(and lower than any task if it does not block - the idle task will never run in this case).task_ctrl
blocks - even if that is just a polling delay, so that it does not eat up all available CPU cycles.while (1)
{
button1 = ioport_get_pin_level(B1);
if (button1)
{
xSemaphoreGive(player1_signal);
printf("Semaphore given\n");
vtaskDelay( 1 ) ; // at least 1 tick
}
}
One possible problem with task_ctrl
is that it will give the semaphore continuously and repeatedly while the button is held. Some sort of state change detection and switch de-bounce rather then level polling might be preferable.
An alternative solution to a polling task is to use a hardware interrupt for teh button and have either the polling task block on an event from the ISR, or have the ISR give the semaphore directly - in either case you will have to deal with debounce.