I'll try to explain...
I have different threads running underside the GUI monitoring some inputs/outputs.
Some of them are started when the Device autoobject is created, and others starts when presenting some screens or chechking options.
So the ErrorObserver and EnableObserver works fine.... but when i have the TemperatureObserver and RemainingTimeObserver working simultaneosly... only the TemperatureObserver works.
I debugged the various calls of methods, ad determinated that when calling EwBspOsThreadCreate for the RemainingTime variable calculation, the function that calls ST49_SolderCycleTime_Thread_Start is executed but the thread nevers starts.
I attach the code of the threads ( the ones involved in the screen):
/*
Include all necessary files to access the real device and/or to get access
to the required operating system calls.
*/
#include "ewrte.h"
#include "ew_bsp_inout.h"
#include "ew_bsp_os.h"
/*
Include the generated header file to access the device class, for example to
access the class 'DeviceClass' from the unit 'Application' include the
generated file 'Application.h'.
*/
#include "Application.h"
/*
Include the SINERGO and STM32 application drivers
*/
#include "SINERGO_bsp.h"
#include "SINERGOThreads.h"
#include "stm32f4xx_hal.h"
#include "stm32f4xx_hal_adc.h"
#include "stm32f4xx_hal_adc_ex.h"
/*
Include basic logic functions
*/
#include "stdio.h"
#include "math.h"
#include "stdbool.h"
/* Device Initialization State */
static volatile int ST49_Initialized = 0;
/*Peripheral Extern Reference for use in Threads */
extern UART_HandleTypeDef huart2;
extern ADC_HandleTypeDef hadc1;
extern ADC_HandleTypeDef hadc2;
extern DMA_HandleTypeDef hdma_adc1;
extern DMA_HandleTypeDef hdma_adc2;
extern TIM_HandleTypeDef htim8;
extern TIM_HandleTypeDef htim3;
extern SPI_HandleTypeDef hspi6;
extern DMA_HandleTypeDef hdma_spi6_rx;
extern DMA_HandleTypeDef hdma_spi6_tx;
/*Flags and Variables extern reference for use in Threads */
extern bool volatile PyroEnableState; //Stato Enable Pirometro
extern uint8_t data[11]; //Buffer per seriale
extern bool volatile SolderCycleStartState;
extern uint32_t SolderCycleRemainingTime;
uint32_t FinalSignal = 0;
volatile uint32_t ErrorGPIOEXP = 0;
extern volatile uint32_t OutSignalGPIOEXT;
/*Internal worker functions used by the threads*/
static void AdcPyroWorkerThread( const void* arg );
static void UpdatePyroValueProc( const void* aData );
static void EnableWorkerThread( const void* arg );
static void UpdateEnableStateProc( const void* aData );
static void UpdatePedalStateProc( const void* aData );
static void PedalWorkerThread( const void* arg );
static void UpdateAlarmsStateProc( const void* aData );
static void UpdateAlarmsCodeProc( const void* aData );
static void AlarmsWorkerThread( const void* arg );
static void GPIOEXP1WorkerThread( const void* arg );
static void GPIOEXP2WorkerThread( const void* arg );
static void UpdateGPIOEXP1StateProc( const void* aData );
static void UpdateGPIOEXP2StateProc( const void* aData );
static void UpdateRemainingTimeProc( const void* aData );
static void SolderCycleTimeThread( const void* arg );
/* Threads Declaration */
static volatile XThreadHandle ST49_Solder_Time_Thread = 0;
static volatile XThreadHandle ST49_Pirometer_Thread = 0;
static volatile XThreadHandle ST49_PedalCheck_Thread = 0;
static volatile XThreadHandle ST49_EnableCheck_Thread = 0 ;
static volatile XThreadHandle ST49_AlarmsCheck_Thread = 0 ;
static volatile XThreadHandle ST49_GPIOEXP1Check_Thread = 0;
static volatile XThreadHandle ST49_GPIOEXP2Check_Thread = 0 ;
static volatile XThreadHandle ST49_PID_Thread = 0;
/*ADC Buffer*/
#define ADC_BUF_LEN 100
uint16_t adc1buffer[ADC_BUF_LEN];
/*-------------------------------------------------------------------------THREADS GENERAL FUNCTIONS----------------------------------------------*/
/* Main Initialization For Threads*/
void ST49_Thread_Init( void )
{
/* check for initialization */
if ( ST49_Initialized )
return;
#if EW_USE_OPERATING_SYSTEM == 1
/* create and start the worker thread to process Signal input */
ST49_PedalCheck_Thread = EwBspOsThreadCreate( PedalWorkerThread, EW_BSP_OS_THREAD_PRIORITY_NORMAL, 1024, 0 );
ST49_EnableCheck_Thread = EwBspOsThreadCreate( EnableWorkerThread, EW_BSP_OS_THREAD_PRIORITY_NORMAL, 1024, 0 );
ST49_AlarmsCheck_Thread = EwBspOsThreadCreate( AlarmsWorkerThread, EW_BSP_OS_THREAD_PRIORITY_NORMAL, 1024, 0 );
ST49_GPIOEXP1Check_Thread = EwBspOsThreadCreate( GPIOEXP1WorkerThread, EW_BSP_OS_THREAD_PRIORITY_NORMAL, 1024, 0 );
ST49_GPIOEXP2Check_Thread = EwBspOsThreadCreate( GPIOEXP2WorkerThread, EW_BSP_OS_THREAD_PRIORITY_NORMAL, 1024, 0 );
ST49_Initialized = 1;
#endif
}
/* Main De-Initialization For Threads*/
void ST49_Thread_DeInit( void )
{
ST49_Initialized = 0;
#if EW_USE_OPERATING_SYSTEM == 1
/* wait until the threads are really terminated */
while ( ST49_EnableCheck_Thread || ST49_PedalCheck_Thread || ST49_AlarmsCheck_Thread || ST49_GPIOEXP1Check_Thread || ST49_GPIOEXP2Check_Thread )
EwBspOsDelay( 1 );
#endif
}
/*------------------------------------------------------THREAD CICLO--------------------------------------------------*/
void ST49_SolderCycleTime_Thread_Start( void )
{
/* check for initialization */
if ( !ST49_Initialized )
return;
if ( ST49_Initialized )
{
HAL_TIM_Base_Start_IT(&htim3);
#if EW_USE_OPERATING_SYSTEM == 1
/* create and start the worker thread to process data */
ST49_Solder_Time_Thread = EwBspOsThreadCreate( SolderCycleTimeThread, EW_BSP_OS_THREAD_PRIORITY_NORMAL, 512, 0 );
#endif
#if EW_USE_OPERATING_SYSTEM == 1
#endif
}
}
static void SolderCycleTimeThread( const void* arg )
{
float toPass = 0;
LED_DEBUG_0_ON;
while (ST49_Initialized && SolderCycleRemainingTime > 0)
{
/*
Important note: This function is a separate thread/task and not executed
in the context of the main GUI thread/task. NEVER make a direct function
call to a method of the driver class or any other generated code
from an interrupt handler or any other thread/task.
EwInvoke() or EwInvokeCopy() have to be used to schedule the invocation of
the desired method in the context of the GUI thread/task.
*/
toPass = (float)SolderCycleRemainingTime;
LED_DEBUG_1_TGL;
EwInvokeCopy( UpdateRemainingTimeProc, &toPass, sizeof( float));
/* sleep for a certain period... */
EwBspOsDelay(50);
}
HAL_TIM_Base_Stop_IT(&htim3);
toPass = (float)SolderCycleRemainingTime;
LED_DEBUG_1_OFF;
LED_DEBUG_0_OFF;
EwInvokeCopy( UpdateRemainingTimeProc, &toPass, sizeof( float));
/* terminate the worker thread */
ST49_Solder_Time_Thread = 0;
EwBspOsThreadDestroy( EwBspOsThreadGetHandle());
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == htim3.Instance)
{
if(SolderCycleRemainingTime>0)
SolderCycleRemainingTime = SolderCycleRemainingTime-1;
else
SolderCycleRemainingTime = 0;
}
}
static void UpdateRemainingTimeProc( const void* aData )
{
float RemainingTime = *((float*)aData);
/* only in case that the device driver is still initialized and the worker
thread is still running, the data should be provided to the device class
- otherwise, a new autoobject will be created and a new worker thread
started... */
ApplicationDeviceClass device = EwGetAutoObject( &ApplicationDevice, ApplicationDeviceClass );
ApplicationDeviceClass__UpdateRemainingTime( device, RemainingTime );
}
/*------------------------------------------------------THREAD PIROMETRO--------------------------------------------------*/
void ST49_Pirometer_Thread_Start( void )
{
/* check for initialization */
if ( !ST49_Initialized )
return;
if ( ST49_Initialized )
{
if (HAL_TIM_Base_Start_IT(&htim8) != HAL_OK )
{
Error_Handler(15);
}
if(HAL_ADC_Start_DMA(&hadc2, (uint32_t*)adc1buffer, ADC_BUF_LEN) != HAL_OK )
{
Error_Handler(7);
}
#if EW_USE_OPERATING_SYSTEM == 1
/* create and start the worker thread to process ADC data */
ST49_Pirometer_Thread = EwBspOsThreadCreate( AdcPyroWorkerThread, EW_BSP_OS_THREAD_PRIORITY_NORMAL, 1024, 0 );
#endif
}
}
/* Elaborate ADC Readings and call method to update view */
static void AdcPyroWorkerThread( const void* arg )
{
while (ST49_Initialized && PyroEnableState)
{
/*
Important note: This function is a separate thread/task and not executed
in the context of the main GUI thread/task. NEVER make a direct function
call to a method of the driver class or any other generated code
from an interrupt handler or any other thread/task.
EwInvoke() or EwInvokeCopy() have to be used to schedule the invocation of
the desired method in the context of the GUI thread/task.
*/
HAL_TIM_Base_Stop_IT(&htim8);
float sum = 0;
for (int i = 0; i<ADC_BUF_LEN; i++)
{
sum= sum+(adc1buffer[i]) ;
}
sum= (int32_t)(sum/ADC_BUF_LEN);
EwInvokeCopy( UpdatePyroValueProc, &sum, sizeof( float));
HAL_TIM_Base_Start_IT(&htim8);
/* sleep for a certain period... */
EwBspOsDelay(50);
}
HAL_TIM_Base_Stop_IT(&htim8);
HAL_ADC_Stop_DMA(&hadc2);
float reset = -1;
EwInvokeCopy( UpdatePyroValueProc, &reset, sizeof( float));
/* terminate the worker thread */
ST49_Pirometer_Thread = 0;
EwBspOsThreadDestroy( EwBspOsThreadGetHandle());
}
/* Update the GUI value */
static void UpdatePyroValueProc( const void* aData )
{
float adcValueToDisplay = *((float*)aData);
/* only in case that the device driver is still initialized and the worker
thread is still running, the data should be provided to the device class
- otherwise, a new autoobject will be created and a new worker thread
started... */
ApplicationDeviceClass device = EwGetAutoObject( &ApplicationDevice, ApplicationDeviceClass );
ApplicationDeviceClass__PyroValueUpdate( device, adcValueToDisplay );
}
/*------------------------------------------------------THREAD ENABLE--------------------------------------------------*/
/* Elaborate Enable state and call method to update view */
static void EnableWorkerThread( const void* arg )
{
while ( ST49_Initialized )
{
bool Enablestate = HAL_GPIO_ReadPin(CHECK_ABILITAZIONE_GPIO_Port, CHECK_ABILITAZIONE_Pin);
EwInvokeCopy( UpdateEnableStateProc, &Enablestate, sizeof( bool));
/* sleep for a certain period... */
EwBspOsDelay( 100 );
}
/* terminate the worker thread */
ST49_EnableCheck_Thread = 0;
EwBspOsThreadDestroy( EwBspOsThreadGetHandle());
}
/* Update the GUI value */
static void UpdateEnableStateProc( const void* aData )
{
bool state = *((bool*)aData);
/* only in case that the device driver is still initialized and the worker
thread is still running, the data should be provided to the device class
- otherwise, a new autoobject will be created and a new worker thread
started... */
ApplicationDeviceClass device = EwGetAutoObject( &ApplicationDevice, ApplicationDeviceClass );
ApplicationDeviceClass__UpdateEnableState( device, state );
}
/*------------------------------------------------------THREAD PEDAL--------------------------------------------------*/
/* Elaborate Pedal state and call method to update view */
static void PedalWorkerThread( const void* arg )
{
while ( ST49_Initialized )
{
bool Pedalstate = HAL_GPIO_ReadPin(START_PEDALE_GPIO_Port, START_PEDALE_Pin);
EwInvokeCopy( UpdatePedalStateProc, &Pedalstate, sizeof( bool));
/* sleep for a certain period... */
EwBspOsDelay( 100 );
}
/* terminate the worker thread */
ST49_PedalCheck_Thread = 0;
EwBspOsThreadDestroy( EwBspOsThreadGetHandle());
}
/* Update the GUI value */
static void UpdatePedalStateProc( const void* aData )
{
bool state = *((bool*)aData);
/* only in case that the device driver is still initialized and the worker
thread is still running, the data should be provided to the device class
- otherwise, a new autoobject will be created and a new worker thread
started... */
ApplicationDeviceClass device = EwGetAutoObject( &ApplicationDevice, ApplicationDeviceClass );
ApplicationDeviceClass__UpdatePedalState( device, state );
}