Why event flag related functions does not work correctly outside of tasks in keil rtx? - rtos

As you know event flags are very useful (e.g. let task running),but unfortunately their control functions (os_evt_clr/set/wait) does not work outside of tasks bodies correctly(e.g. in interrupt handling functions). For alternative i used a variable ,I initialized it in Interrupt handler when needed ,then used it on another task to running a os_evt_set() function for let MCU entering a task.
bool Instance_Variable;
Interrupt_Handler()
{
if(xxxx)
Instance_Variable=1
}
//--------------------------
Secondary_Task()
{
//This is frequently run task
if(Instance_Variable==1)
{
os_evt_set (0x0001, Primary_Task_ID);
Instance_Variable=0;
}
}
//--------------------------
Primary_Task()
{
Result = os_evt_wait_or (0x0001, 0xFFFF);
//Task's body
os_evt_clr (0x0001, Primary_Task_ID);
}
Any better approach?WBR.

You can't use function prefixed with os_ inside ISR. Usage hints from RTX documentation:
Functions that begin with os_ can be called from a task, but not from an interrupt service routine.
Functions that begin with isr_ can be called from an IRQ interrupt service routine but not from a task.
This code will work:
Interrupt_Handler() {
if(xxxx) {
isr_evt_set (0x0001, Primary_Task_ID);
}
}
//--------------------------
Primary_Task() {
Result = os_evt_wait_or (0x0001, 0xFFFF);
//Task's body
os_evt_clr (0x0001, Primary_Task_ID);
}

Related

FreeRTOS ignores osDelay [STM32]

I am new here, but have often benefited from questions and their results.
Now I have a problem that I can not solve for days. It is about a STM32L431RCT6 with FreeRTOS. There are 3 tasks running on it. Two of them are dedicated to processing CanOpenNode (1 to send data, 1 to receive). One is a custom controller. The code works as it is, but when I enable the CRC unit (MX_CRC_Init()) the problem appears. With the CRC unit enabled, only the task to receive the data from Canopen is executed. The other tasks are set to "Ready". What I notice is that the osDelay() used in the receive task seems to be ignored. It doesn't seem to matter if I use osDelay(1) or osDelay(10000).
void start_CO_rec_Thread(void *argument)
{
/* USER CODE BEGIN start_CO_TI_Thread */
/* Infinite loop */
for(;;)
{
canopen_app_interrupt();
osDelay(1);
}
osThreadTerminate(NULL);
/* USER CODE END start_CO_TI_Thread */
}
Something else is added. If I remove functions and variables in the task by starting an own controller, the processing of the tasks works again. Now I have concluded that the tasks need more stack memory. But this is also not the solution of the puzzle...
Working Code:
void Start_Controller(void *argument)
{
Sensor = new DS18B20(htim6);
Regler = new Smithpredictor(Sensor);
// osTimerStart(LifetimerHandle, 1000);
for(;;)
{
if (global_state==4)
actual_Temperatur = Regler->run(target_Temperature);
osDelay(MBC_intervall_s*1000);
}
osThreadTerminate(NULL);
}
Not Working Code:
void Start_Controller(void *argument)
{
Sensor = new DS18B20(htim6);
Regler = new Smithpredictor(Sensor);
osTimerStart(LifetimerHandle, 1000);
for(;;)
{
if (global_state==4)
actual_Temperatur = Regler->run(target_Temperature);
osDelay(MBC_intervall_s*1000);
}
osThreadTerminate(NULL);
}
I hope someone has an idea how to proceed or can help me. Even if it is just another way to further identify the problem. Maybe I have also committed some stupidity, I am unfortunately not a computer scientist.

STM32 FreeRTOS - UART Deferred Interrupt Problem

I am trying to read data with unkown size using UART Receive Interrupt. In the call back function, I enabled Rx interrupt in order to read characters until \n is gotten. If \n is get, then higher priority task which is deferred interrupt handler is woken. The problem is that I tried to read one by one byte via call back function and I tried to put each character into a buffer, but unfortunately buffer could not get any character. Moreover, deferred interrupt handler could not be woken.
My STM32 board is STM32F767ZI, and my IDE is KEIL.
Some Important notes before sharing the code:
1. rxIndex and gpsBuffer are declared as global.
2. Periodic function works without any problem.
Here is my code:
Periodic Function, Priority = 1
void vPeriodicTask(void *pvParameters)
{
const TickType_t xDelay500ms = pdMS_TO_TICKS(500UL);
while (1) {
vTaskDelay(xDelay500ms);
HAL_UART_Transmit(&huart3,(uint8_t*)"Imu\r\n",sizeof("Imu\r\n"),1000);
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_7);
}
}
Deferred Interrupt, Priority = 3
void vHandlerTask(void *pvParameters)
{
const TickType_t xMaxExpectedBlockTime = pdMS_TO_TICKS(1000);
while(1) {
if (xSemaphoreTake(xBinarySemaphore,xMaxExpectedBlockTime) == pdPASS) {
HAL_UART_Transmit(&huart3,(uint8_t*)"Semaphore Acquired\r\n",sizeof("Semaphore
Acquired\r\n"),1000);
// Some important processes will be added here
rxIndex = 0;
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_14);
}
}
}
Call back function:
void HAL_UART_RxCptlCallBack(UART_HandleTypeDef *huart)
{
gpsBuffer[rxIndex++] = rData;
if (rData == 0x0A) {
BaseType_t xHigherPriorityTaskWoken;
xSemaphoreGiveFromISR(xBinarySemaphore,&xHigherPriorityTaskWoken);
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
}
HAL_UART_Receive_IT(huart,(uint8_t*)&rData,1);
}
Main function
HAL_UART_Receive_IT(&huart3,&rData,1);
xBinarySemaphore = xSemaphoreCreateBinary();
if (xBinarySemaphore != NULL) {
//success
xTaskCreate(vHandlerTask,"Handler",128,NULL,1,&vHandlerTaskHandler);
xTaskCreate(vPeriodicTask,"Periodic",128,NULL,3,&vPeriodicTaskHandler);
vTaskStartScheduler();
}
Using HAL for it is a best way to get into the troubles. It uses HAL_Delay which is systick dependant and you should rewrite this function to read RTOS tick instead.
I use queues to pass the data (the references to data) but it should work. There is always a big question mark when using the HAL functions.
void HAL_UART_RxCptlCallBack(UART_HandleTypeDef *huart)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
gpsBuffer[rxIndex++] = rData;
if (rData == 0x0A) {
if(xSemaphoreGiveFromISR(xBinarySemaphore,&xHigherPriorityTaskWoken) == pdFALSE)
{
/* some error handling */
}
}
HAL_UART_Receive_IT(huart,(uint8_t*)&rData,1);
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
}
Concluding if I use HAL & RTOS I always modify the way HAL handles timeouts.

Will an item submitted to the main `DispatchQueue` ever interrupt currently executing code on the main thread?

The below code is used to execute a long running calculation on a background thread:
enum CalculationInterface {
private static var latestKey: AnyObject? // Used to cancel previous calculations when a new one is initiated.
static func output(from input: Input, return: #escaping (Output?) -> ()) {
self.latestKey = EmptyObject()
let key = self.latestKey! // Made to enable capturing `self.latestKey's` value.
DispatchQueue.global().async {
do {
let output = try calculateOutput(from: input, shouldContinue: { key === self.latestKey }) // Function cancels by throwing an error.
DispatchQueue.main.async { if (key === self.latestKey) { `return`(output) } }
} catch {}
}
}
}
This function is called from the main thread like so:
/// Initiates calculation of the output and sets it to the result when finished.
private func recalculateOutput() {
self.output = .calculating // Triggers calculation in-progress animation for user.
CalculationInterface.output(from: input) { self.output = $0 } // Ends animation once set and displays calculated output to user.
}
I'm wondering if it's possible for the closure that's pushed to DispatchQueue.main to execute while the main thread is running my code. Or in other words execute after self.output = .calculating but before self.latestKey is re-set to the new object. If it could, then the stale calculation output could be displayed to the user.
I'm wondering if it's possible for the closure that's pushed to DispatchQueue.main to execute while the main thread is running my code
No, it isn't possible. The main queue is a serial queue. If code is running on the main queue, no "other" main queue code can run. Your DispatchQueue.main.async effectively means: "Wait until all code running on the main queue comes naturally to an end, and then run this on the main queue."
On the other hand, DispatchQueue.global() is not a serial queue. Thus it is theoretically possible for two calls to calculateOutput to overlap. That isn't something you want to have happen; you want to be sure that any executing instance of calculateOutput finishes (and we proceed to grapple with the latestKey) before another one can start. In other words, you want to ensure that the sequence
set latestKey on the main thread
perform calculateOutput in the background
look at latestKey on the main thread
happens coherently. The way to ensure that is to set aside a DispatchQueue that you create with DispatchQueue(label:), that you will always use for running calculateOutput. That queue will be a serial queue by default.

Run a thread continuously without blocking main thread in swift

I wrote a code and I need to run it continuously. Initially I used RunLoop.current.run(). It works fine. The problem is it blocks the main thread. How can I run it in background continuously without blocking.
Basic class structure:
class Keylogger
{
func start()
{
let observer = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())
/* Connected and Disconnected Call Backs */
IOHIDManagerRegisterDeviceMatchingCallback(manager, Handle_DeviceMatchingCallback, observer)
IOHIDManagerRegisterDeviceRemovalCallback(manager, Handle_DeviceRemovalCallback, observer)
/* Input value Call Backs */
IOHIDManagerRegisterInputValueCallback(manager, Handle_IOHIDInputValueCallback, observer);
/* schedule */
IOHIDManagerScheduleWithRunLoop(manager, CFRunLoopGetMain(), CFRunLoopMode.defaultMode.rawValue)
print("Started")
}
}
And in main.swift
var logger = Keylogger()
logger.start()
RunLoop.current.run()
// Whatever written below this will not be executed obviously
I used DispatchQueue before for background tasks( which is just a piece of code) but how to execute it continuously?
I tried this:
var d = Keylogger()
var ff = {
d.start()
}
var f = DispatchQueue(label: "Keylogger", qos: .userInteractive, attributes: .concurrent)
f.async(execute: ff)
while true
{}
But the start() of Keylogger is never executed.
I thought of creating executable and running the executable through NSTask. Other than this is there any way to do it?
I think you are not understanding the purpose of RunLoop.current.run().
Your code works only when your program is running. Constantly.
Your keylogger code is ran on an another thread. So, to keep that thread alive, the main thread must be active. That is the reason for RunLoop.current.run().
So, try to use callbacks(like keylogger is using) and schedule it on another thread. Or, do everything you want and place RunLoop.current.run() at the very end of your code.

Differentiating between Binary semaphore and Mutex using same code

void forward(void *pvparam)
{
while(1)
{
if(xSemaphoreTake(xSemaphore,1000)==pdTRUE)
{
UART0_SendStr("Frwd took it\n");
}
else
{
UART0_SendStr("Frwd couldn't take it\n");
}
vTaskDelay(1000);
}
}
void back(void *pvparam)
{
vTaskDelay(100);
while(1)
{
if(xSemaphoreGive(xSemaphore)==pdTRUE)
{
UART0_SendStr("Back Gave it:MF\n");
}
else
{
UART0_SendStr("Back couldn't give it:MS\n");
}
vTaskDelay(1000);
}
}
Above code is the one which i am using for both Binary semaphore and Mutex.
The only difference is for binary semaphore i am writing "xSemaphoreCreateBinary(xsemaphore);" in main and
for mutex
xSemaphoreCreateMutex(xsemaphore) in main.
According to the definetion
"A semaphore(Mutex) occupied by the task can only be given by that Task and the Semaphore(Binary) created by a Task can be given by any of the Tasks"
But both the codes(i.e for binary semaphore and mutex) are giving same output.
Mutexes are used for controlling exclusive access to resources / data. If you take a mutex protecting the resource / data, you must give it back when you have finished, otherwise you will permanently block the resource. Mutexes also allow for priority inheritance.
Binary Semaphores on the other hand are used for task synchronization purposes. You do not give a give the semaphore back once you have taken it.
Looking at your code above I think that the Binary Semaphore is the way to go.