329 views
in GUI Development by
Hello,

is there any possible reason that whe calling EwBspOsThreadCreate the thread does not get created?

Thanks.

1 Answer

0 votes
by
Hello,

EwBspOsThreadCreate is just a wrapper function for the underlying operating system. Please check the documentation of the used OS, e.g. FreeRTOS, Linux,...

If this does not help, please let us know more details what you have tried and what you got.

Best regards,

Manfred.
by

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 );

}

 

 

by
Difficult to say what is going wrong...

Have you checked the return value or error states of the FreeRTOS functions? Maybe there is not enough memory or not enough stack reserved for the additional tasks. Please check your settings in FreeRTOSConfig.h file.

Btw: There are many tasks created - for each data a separate task. Maybe you can check different data sources in one worker thread. Just to avoid that you create a lot of overhead just for reading an ADC or GPIO.
by
Hello Manfred, i tried reducing the dimension of the memory reserved for the thread in the stack and it worked.

Do yu have any hint on how to calculate the right amount to be reserved for optimal resource allocation?

Thanks a lot.
by
For the Embedded Wizard GUI task, the recommended stack size is 4...8 kByte. For your worker threads/tasks, it depends on the calling depth of the functions and their parameters. Maybe a few hundred bytes are enough. You cannot calculate it easily, you can just check the stack (e.g. by settings of your OS). Let me refer to the documentation of your RTOS.
by
as always thanks a lot Manfred.

Ask Embedded Wizard

Welcome to the question and answer site for Embedded Wizard users and UI developers.

Ask your question and receive answers from the Embedded Wizard support team or from other members of the community!

Embedded Wizard Website | Privacy Policy | Imprint

...