SystemClock_config() timeout while using the keil Simulator - microcontroller

In this example I will use SPI2 run in mode Master(NSS pin control by software) to send data.
SPI3 run in mode Slave (NSS pin control by harware) receive data using DMA.
PC2 (SPI2 MISO) connect to PC11(SPI3 MISO).
PC3 (SPI2 MOSI) connect to PC12(SPI3 MOSI).
PB10 (SPI2 SCK) connect to PC10 (SPI3 SCK).
PC6 (SPI2 NSS pin control by sofware) connect to PA4(SPI3 NSS pin control by hardware).
main.c
#include "stm32f4xx_hal.h"
#define spi_enable HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_RESET)
#define spi_disable HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_SET)
SPI_HandleTypeDef hspi2;
SPI_HandleTypeDef hspi3;
DMA_HandleTypeDef hdma_spi3_rx;
void SystemClock_Config(void);
void Error_Handler(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_SPI2_Init(void);
static void MX_SPI3_Init(void);
uint8_t send_data=32,receive_data=0;
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_SPI2_Init();
MX_SPI3_Init();
HAL_SPI_Receive_DMA(&hspi3,&receive_data,1);
while (1)
{
spi_enable;
HAL_SPI_Transmit_IT(&hspi2,&send_data,1);
HAL_Delay(1000);
send_data++;
}
}
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
if(hspi->Instance==hspi2.Instance)
{
spi_disable;
}
}
/** System Clock Configuration
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV4;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
Error_Handler();
}
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
/* SPI2 init function */
static void MX_SPI2_Init(void)
{
hspi2.Instance = SPI2;
hspi2.Init.Mode = SPI_MODE_MASTER;
hspi2.Init.Direction = SPI_DIRECTION_2LINES;
hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi2.Init.NSS = SPI_NSS_SOFT;
hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi2.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi2) != HAL_OK)
{
Error_Handler();
}
}
/* SPI3 init function */
static void MX_SPI3_Init(void)
{
hspi3.Instance = SPI3;
hspi3.Init.Mode = SPI_MODE_SLAVE;
hspi3.Init.Direction = SPI_DIRECTION_2LINES;
hspi3.Init.DataSize = SPI_DATASIZE_8BIT;
hspi3.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi3.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi3.Init.NSS = SPI_NSS_HARD_INPUT;
hspi3.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi3.Init.TIMode = SPI_TIMODE_DISABLE;
hspi3.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi3.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi3) != HAL_OK)
{
Error_Handler();
}
}
/**
* Enable DMA controller clock
*/
static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA interrupt init */
/* DMA1_Stream0_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
}
/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_SET);
/*Configure GPIO pin : PC6 */
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* #brief This function is executed in case of error occurrence.
* #param None
* #retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler */
/* User can add his own implementation to report the HAL error return state */
while(1)
{
}
/* USER CODE END Error_Handler */
}
#ifdef USE_FULL_ASSERT
/**
* #brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* #param file: pointer to the source file name
* #param line: assert_param error line source number
* #retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif
/**
* #}
*/
/**
* #}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
During debugging, I found that SystemClock_config() function continuously running given below code.
/* Wait till HSE is ready */
while(__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET)
{
if((HAL_GetTick() - tickstart ) > HSE_TIMEOUT_VALUE)
{
return HAL_TIMEOUT;
}
why is it not going to further function?

If you are using RTOS this could help:
http://www.keil.com/support/docs/3931.htm
Therefore the CMSIS RTOS already configures the priorities for some interrupts. Try to uncomment following code from SystemClock_Config() additionally to the description:
//HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
//HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* SysTick_IRQn interrupt configuration */
//HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
I hope it helps.

Related

Nginx Master process create a thread, but I can't kill it by pthread_cancel or pthread_kill,

In nginx master process, start a thread to implement a timer.
Fake code:
void* timer_proc(void* pdata)
{
struct timeval tv = {0};
timer_handle* phandle = (timer_handle*)pdata;
prctl(PR_SET_NAME, phandle->desc);
/* 设置线程取消点 */
//pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); /* 线程可取消 */
//pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); /* 实时取消, PTHREAD_CANCEL_DEFERRED 延时取消 */
while(phandle->repeat && !(phandle->stop))
{
tv.tv_sec = phandle->timeout;
tv.tv_usec = 0;
int nret = select(0,NULL,NULL,NULL,&tv);
if (0 == nret) {
phandle->pfunc(phandle->pdata);
}
}
return NULL;
}
But I can't kill it by pthread_cancel()or pthread_kill(), return error 3, errno 11, strerr: 'Resource temporarily unavailable'.

I2C comunication in STM32

My question is simple, I just want to send 20 bytes of data from a STM32F103C8 blue phill card in i2c slave mode to a raspberry pi 3 in master mode, I use STM32Cube IDE can any other IDE work for me. After browsing the web, I don't fully understand everything necessary for this. Thank you,
I add source code that I am testing, at the moment it does not work for me and I want to know what may be wrong,
#include "main.h"
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
//#define MASTER_BOARD
#define I2C_ADDRESS 0x30F
#define RXBUFFERSIZE 20
/* USER CODE END PD */
//#define I2C_SPEEDCLOCK 100000
#define I2C_DUTYCYCLE I2C_DUTYCYCLE_2
/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c1;
/* USER CODE BEGIN PV */
uint8_t aTxBuffer[] = " ****I2C_TwoBoards communication based on IT**** ****I2C_TwoBoards communication based on IT**** ";
uint8_t aRxBuffer[RXBUFFERSIZE];
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);
/* USER CODE BEGIN PFP */
int main(void) {
/* USER CODE BEGIN 1 */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
/* USER CODE BEGIN 2 */
if (HAL_I2C_Init(&I2cHandle) != HAL_OK) {
/* Initialization Error */
Error_Handler();
}
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1) {
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
if(HAL_I2C_Slave_Receive_IT(&I2cHandle, (uint8_t *)aRxBuffer, RXBUFFERSIZE) != HAL_OK)
{
/* Transfer error in reception process */
Error_Handler();
}
//**************************************************************************************************
while (HAL_I2C_GetState(&I2cHandle) != HAL_I2C_STATE_READY)
{
}
//**************************************************************************************************
if(HAL_I2C_Slave_Transmit_IT(&I2cHandle, (uint8_t*)aTxBuffer, TXBUFFERSIZE)!= HAL_OK)
{
/* Transfer error in transmission process */
Error_Handler();
}
//**************************************************************************************************
while (HAL_I2C_GetState(&I2cHandle) != HAL_I2C_STATE_READY)
{
}
//**************************************************************************************************
if(Buffercmp((uint8_t*)aTxBuffer,(uint8_t*)aRxBuffer,RXBUFFERSIZE))
{
/* Processing Error */
Error_Handler();
}
}
/**
* #brief System Clock Configuration
* #retval None
*/
void SystemClock_Config(void) {
RCC_OscInitTypeDef RCC_OscInitStruct = { 0 };
RCC_ClkInitTypeDef RCC_ClkInitStruct = { 0 };
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
Error_Handler();
}
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
| RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) {
Error_Handler();
}
}
/**
* #brief I2C1 Initialization Function
* #param None
* #retval None
*/
static void MX_I2C1_Init(void) {
/* USER CODE BEGIN I2C1_Init 0 */
/* USER CODE END I2C1_Init 0 */
/* USER CODE BEGIN I2C1_Init 1 */
/* USER CODE END I2C1_Init 1 */
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000;
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK) {
Error_Handler();
}
/* USER CODE BEGIN I2C1_Init 2 */
/* USER CODE END I2C1_Init 2 */
}
/**
* #brief GPIO Initialization Function
* #param None
* #retval None
*/
static void MX_GPIO_Init(void) {
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* #brief This function is executed in case of error occurrence.
* #retval None
*/
void Error_Handler(void) {
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* #brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* #param file: pointer to the source file name
* #param line: assert_param error line source number
* #retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
The question is broad so I will answer about the methodology to solve this kind of problems.
Try to narrow this down into smaller steps, each step could be broken down to smaller steps or even generate new questions here.
find a STM32 I2C slave example, build and flash it.
how to run a blinky example on STM32
how to open i2c port
connect your oscilloscope and observe output
read any data from RPi
Can you read data from a known good slave?
connect the devices
modify slave code to send custom data.
write the application on your raspberry pi

Stm32 FreeRtos Internal Flash Linker Script

I have some functions to read-and write to memory to STM32F103 internal memory. This functions work on the gcc and standard linker script. When I want to use the internal flash with stm32 and freertos. FreeRtos does not allow to me access when I want to write a data into internal flash. Here is the standard freertos linker script file.
Default linker script file for freertos for stm32.
/*************************************************
* linker script for ST32F103 & MPU REV 1.02
************************************************/
GROUP(libgcc.a libc.a)
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
SRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K
}
/* Higher address of the user mode stack */
_estack = ORIGIN(SRAM)+LENGTH(SRAM);
/*
*There will be a link error if there is not this amount of RAM free at the end.
*/
_Minimum_Stack_Size = 1K;
_Minimum_Heap_Size = 1K;
/* Variables used by FreeRTOS-MPU. */
_Privileged_Functions_Region_Size = 16K;
_Privileged_Data_Region_Size = 512;
__FLASH_segment_start__ = ORIGIN( FLASH );
__FLASH_segment_end__ = __FLASH_segment_start__ + LENGTH( FLASH );
__privileged_functions_start__ = ORIGIN( FLASH );
__privileged_functions_end__ = __privileged_functions_start__ + _Privileged_Functions_Region_Size;
__SRAM_segment_start__ = ORIGIN( SRAM );
__SRAM_segment_end__ = __SRAM_segment_start__ + LENGTH( SRAM );
__privileged_data_start__ = ORIGIN( SRAM );
__privileged_data_end__ = ORIGIN( SRAM ) + _Privileged_Data_Region_Size;
ENTRY(Reset_Handler)
SECTIONS
{
/*
Privileged section at the start of the flash.
Vectors must be first whatever.
*/
.isr_vectors :
{
. = ALIGN(4);
_isr_vectors_offs = . - __FLASH_segment_start__;
KEEP(*(.isr_vectors)) /* Startup code */
} >FLASH
privileged_functions :
{
. = ALIGN(4);
*(privileged_functions)
} > FLASH
/* Non privileged code starts here. */
.text_offset :
{
. = ALIGN(4);
. = . + _Privileged_Functions_Region_Size;
} > FLASH
.text :
{
. = ALIGN(4);
*(.text) /* remaining code */
*(.text.*) /* remaining code */
*(.rodata) /* read-only data (constants) */
*(.rodata*)
*(.glue_7)
*(.glue_7t)
} > FLASH
/*
.ARM.exidx is sorted, so has to go in its own output section.
*/
. = ALIGN(4);
__exidx_start = .;
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} >FLASH
__exidx_end = .;
/* -- */
.data.align :
{
. = ALIGN(4);
_etext = .;
_sipdata = _etext; /* Used by the startup in order to initialize privileged variables */
} >FLASH
/* -- */
.pdata.align :
{
. = ALIGN(4);
. = . + _Privileged_Data_Region_Size;
_sidata = .; /* Used by the startup in order to initialize variables */
} >FLASH
/*
* This is the Privileged data section. It is stored in RAM but the initial values
* are held in flash and copied to RAM by the startup code
*/
privileged_data : AT ( _sipdata ) /* AT makes the LMA follow on in the binary image */
{
. = ALIGN(4);
_bss = .;
_spdata = . ;
*(privileged_data)
_epdata = . ;
} > SRAM
/*
* This is the initialized data section. It is stored in RAM but the initial values
* are held in flash and copied to RAM by the startup code
*/
.data_offset :
{
. = ALIGN(4);
. = . + _Privileged_Data_Region_Size;
} > SRAM
.data : AT ( _sidata ) /* AT makes the LMA follow on in the binary image */
{
_sdata = . ; /* Used by the startup in order to initialize the .data section */
KEEP(*(vtable))
KEEP( *(.data) )
KEEP( *(.data.*) )
. = ALIGN(4);
_edata = . ; /* Used by the startup in order to initialize the .data section */
} >SRAM
/*
* This is the uninitialized data section. Date here is stored in RAM and will be
* set to zero by the startup code.
*/
.bss :
{
. = ALIGN(4);
_sbss = .; /* Used by the startup in order to initialize the .bss section */
*(.bss)
*(.bss.*)
*(COMMON)
. = ALIGN(4);
_ebss = . ; /* Used by the startup in order to initialize the .bss section */
} >SRAM
/*
* This is the heap section
* This is just to check that there is enough RAM left for the heap
* It should generate an error if it's full.
*/
._sheap :
{
. = ALIGN(4);
_heap_begin = . ;
. = . + _Minimum_Heap_Size ;
. = ALIGN(4);
_heap_end = . ;
} >SRAM
/*
* This is the user stack section
* This is just to check that there is enough RAM left for the User mode stack
* It should generate an error if it's full.
*/
._usrstack :
{
. = ALIGN(4);
_susrstack = . ;
. = . + _Minimum_Stack_Size ;
. = ALIGN(4);
_eusrstack = . ;
} >SRAM
PROVIDE ( end = _ebss );
PROVIDE ( _end = _ebss );
PROVIDE( _heap = _heap_begin );
PROVIDE ( _eheap = _heap_end );
}
and here is the my new linker script file here to access the last page of the stm32f103 which is page 255. When I want to modify the page255. It does not allow me. Do you have suggestion that how can use the internal flash of the stm32 with freertos? I just need to use one page in the flash when freertos in the usage. Everything works if I do not use freertos
/*************************************************
* linker script for ST32F103 & MPU REV 1.02
************************************************/
GROUP(libgcc.a libc.a)
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1022K
FLASH_STORAGE (rwx) : ORIGIN = 0x08000000+1022K, LENGTH = 2K
SRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K
}
/* Higher address of the user mode stack */
_estack = ORIGIN(SRAM)+LENGTH(SRAM);
/*
*There will be a link error if there is not this amount of RAM free at the end.
*/
_Minimum_Stack_Size = 1K;
_Minimum_Heap_Size = 1K;
/* Variables used by FreeRTOS-MPU. */
_Privileged_Functions_Region_Size = 16K;
_Privileged_Data_Region_Size = 512;
__FLASH_segment_start__ = ORIGIN( FLASH );
__FLASH_segment_end__ = __FLASH_segment_start__ + LENGTH( FLASH );
__privileged_functions_start__ = ORIGIN( FLASH );
__privileged_functions_end__ = __privileged_functions_start__ + _Privileged_Functions_Region_Size;
__SRAM_segment_start__ = ORIGIN( SRAM );
__SRAM_segment_end__ = __SRAM_segment_start__ + LENGTH( SRAM );
__privileged_data_start__ = ORIGIN( SRAM );
__privileged_data_end__ = ORIGIN( SRAM ) + _Privileged_Data_Region_Size;
ENTRY(Reset_Handler)
SECTIONS
{
/*
Privileged section at the start of the flash.
Vectors must be first whatever.
*/
.isr_vectors :
{
. = ALIGN(4);
_isr_vectors_offs = . - __FLASH_segment_start__;
KEEP(*(.isr_vectors)) /* Startup code */
} >FLASH
privileged_functions :
{
. = ALIGN(4);
*(privileged_functions)
} > FLASH
/* Non privileged code starts here. */
.text_offset :
{
. = ALIGN(4);
. = . + _Privileged_Functions_Region_Size;
} > FLASH
.text :
{
. = ALIGN(4);
*(.text) /* remaining code */
*(.text.*) /* remaining code */
*(.rodata) /* read-only data (constants) */
*(.rodata*)
*(.glue_7)
*(.glue_7t)
} > FLASH
/*
.ARM.exidx is sorted, so has to go in its own output section.
*/
. = ALIGN(4);
__exidx_start = .;
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} >FLASH
__exidx_end = .;
/* -- */
.data.align :
{
. = ALIGN(4);
_etext = .;
_sipdata = _etext; /* Used by the startup in order to initialize privileged variables */
} >FLASH
/* -- */
.pdata.align :
{
. = ALIGN(4);
. = . + _Privileged_Data_Region_Size;
_sidata = .; /* Used by the startup in order to initialize variables */
} >FLASH
/*
* This is the Privileged data section. It is stored in RAM but the initial values
* are held in flash and copied to RAM by the startup code
*/
privileged_data : AT ( _sipdata ) /* AT makes the LMA follow on in the binary image */
{
. = ALIGN(4);
_bss = .;
_spdata = . ;
*(privileged_data)
_epdata = . ;
} > SRAM
/*
* This is the initialized data section. It is stored in RAM but the initial values
* are held in flash and copied to RAM by the startup code
*/
.data_offset :
{
. = ALIGN(4);
. = . + _Privileged_Data_Region_Size;
} > SRAM
.data : AT ( _sidata ) /* AT makes the LMA follow on in the binary image */
{
_sdata = . ; /* Used by the startup in order to initialize the .data section */
KEEP(*(vtable))
KEEP( *(.data) )
KEEP( *(.data.*) )
. = ALIGN(4);
_edata = . ; /* Used by the startup in order to initialize the .data section */
} >SRAM
/*
* This is the uninitialized data section. Date here is stored in RAM and will be
* set to zero by the startup code.
*/
.bss :
{
. = ALIGN(4);
_sbss = .; /* Used by the startup in order to initialize the .bss section */
*(.bss)
*(.bss.*)
*(COMMON)
. = ALIGN(4);
_ebss = . ; /* Used by the startup in order to initialize the .bss section */
} >SRAM
/*
* This is the heap section
* This is just to check that there is enough RAM left for the heap
* It should generate an error if it's full.
*/
._sheap :
{
. = ALIGN(4);
_heap_begin = . ;
. = . + _Minimum_Heap_Size ;
. = ALIGN(4);
_heap_end = . ;
} >SRAM
/*
* This is the user stack section
* This is just to check that there is enough RAM left for the User mode stack
* It should generate an error if it's full.
*/
._usrstack :
{
. = ALIGN(4);
_susrstack = . ;
. = . + _Minimum_Stack_Size ;
. = ALIGN(4);
_eusrstack = . ;
} >SRAM
PROVIDE ( end = _ebss );
PROVIDE ( _end = _ebss );
PROVIDE( _heap = _heap_begin );
PROVIDE ( _eheap = _heap_end );
}
The changes are from this linker script
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
SRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K
}
to this linker script:
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1022K
FLASH_STORAGE (rwx) : ORIGIN = 0x08000000+1022K, LENGTH = 2K
SRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K
}
Here is the my codes to write the flash with FreeRtos.
flash.c file.
#include <FreeRTOS.h>
#include <queue.h>
#include <task.h>
/* -- */
#include "FlashMemoryDataStorage_FreeRtos.h"
/* -- */
/********************************************************************************
; Function: FlashMemoryDataStorage_UnLock
;
; Description: unlocks the flash memory
;
; Inputs: nothing
;
; Returns: Nothing
*********************************************************************************/
void FlashMemoryDataStorage_UnLock(void)
{
FLASH->KEYR = FLASH_KEY1;
FLASH->KEYR = FLASH_KEY2;
}
/********************************************************************************
; Function: FlashMemoryDataStorage_Lock
;
; Description: locks the flash memory
;
; Inputs: nothing
;
; Returns: Nothing
*********************************************************************************/
void FlashMemoryDataStorage_Lock(void)
{
FLASH->CR = FLASH_CR_LOCK;
}
/*********************************************************************************
; Function: FlashMemoryDataStorage_SectorErase
;
; Description: erases a sector
;
; Inputs: uint32_t address of erase operation
;
; Returns: Nothing
*********************************************************************************/
void FlashMemoryDataStorage_SectorErase(uint32_t addr)
{
FlashMemoryDataStorage_UnLock();
/* -- */
FLASH->CR |= FLASH_CR_PER;
FLASH->CR &= ~FLASH_CR_PG;
FLASH->CR |= FLASH_CR_OPTER;
FLASH->AR = addr;
FLASH->CR |= FLASH_CR_STRT;
/* wait until the operation finish */
while(FLASH->SR & (uint32_t)FLASH_SR_BSY);
FLASH->CR &= ~(FLASH_CR_PER | FLASH_CR_OPTER);
/* -- */
FlashMemoryDataStorage_Lock();
}
/*********************************************************************************
; Function: FlashMemoryDataStorage_SectorWrite
;
; Description: writes a sector
;
; Inputs: uint32_t address of write operation
;
; Inputs: uint32_t address of write buffer
;
; Returns: Nothing
*********************************************************************************/
ERRCODE FlashMemoryDataStorage_SectorWrite(uint32_t addr,void * pBuff)
{
ERRCODE ec = SUCCESS;
uint16_t size=0, *pAddr=NULL, *pBuffTemp=NULL;
/* -- */
size = FLASH_SECTOR_SIZE;
pAddr = (uint16_t *)addr;
pBuffTemp =(uint16_t *)pBuff;
size = size / 2; /* incoming values are in bytes (It should be 16-bit) */
/* -- */
while(size) {
FlashMemoryDataStorage_UnLock();
/* -- */
FLASH->CR &= ~FLASH_CR_PER;
FLASH->CR |= FLASH_CR_PG;
*(pAddr) = *(pBuffTemp);
tprintf("\r\nPage Erased22: \r\n");
while(1);
/* wait until the operation finish */
while(FLASH->SR & FLASH_SR_BSY);
if (FLASH->SR & FLASH_SR_PGERR) {
ec = FLASH_WRITE_PAGE_ERR;
tprintf("PAGE ERR");
while(1);
goto func_end;
}
/* -- */
if (FLASH->SR & FLASH_SR_WRPRTERR) {
ec = FLASH_WRITE_PROTECTION_ERR;
tprintf("WRTIE PROTEC");
while(1);
goto func_end;
}
pAddr++;
pBuffTemp++;
size--;
}
/* -- */
func_end:
FlashMemoryDataStorage_Lock();
return ec;
}
/*********************************************************************************************
; Function: FlashMemoryDataStorage_SectorDump
;
; Description: dumps a sector
;
; Inputs: uint32_t starting address of dump operation
;
; Returns: Nothing
***********************************************************************************************/
void FlashMemoryDataStorage_SectorDump(uint32_t addr)
{
uint16_t ndx=0, size=0;
size = FLASH_SECTOR_SIZE;
for( ndx=0; ndx < size; ndx++){
if(!(ndx % 16)) tprintf("\n\r0x%04x",ndx);
tprintf(" %02x",*(char *)addr);
addr++;
}
}
/*********************************************************************************************
; Function: FlashMemoryDataStorage_SectorRead
;
; Description: reads a sector
;
; Inputs: uint32_t starting address of read operation
;
; Inputs: char * read buffer pointer
;
; Returns: Nothing
;
***********************************************************************************************/
void FlashMemoryDataStorage_SectorRead(uint32_t addr, char *pBuff)
{
uint16_t index=0, size=0;
size = FLASH_SECTOR_SIZE;
for( index=0; index < size; index++){
pBuff[index] = *(char *)addr;
addr++;
}
}
/*********************************************************************************************
; Function: FlashMemoryDataStorage_SectorFillBuffer
;
; Description: fills the memory with a character
;
; Inputs: char * buffer pointer
;
; Inputs: char chacacter to fill
;
; Returns: Nothing
;
***********************************************************************************************/
void FlashMemoryDataStorage_SectorFillBuffer(char *pBuff, char ch)
{
uint16_t ndx=0, size=0;
size = FLASH_SECTOR_SIZE;
for( ndx=0; ndx < size; ndx++){
pBuff[ndx] = ch;
}
}
/* -- */
static void vTest_Flash( void *pvParameters )
{
/* The parameters are not used in this function. */
(void) pvParameters;
char buffw[FLASH_SECTOR_SIZE];
char buffr[FLASH_SECTOR_SIZE];
while(1) {
/* Erase Memory */
tprintf("\r\nPage Erased: \r\n");
FlashMemoryDataStorage_SectorErase(PAGE_255_ADDR);
/* sector 1 write operation */
FlashMemoryDataStorage_SectorFillBuffer(buffw,'a');
FlashMemoryDataStorage_SectorWrite(PAGE_255_TEST_SECTOR1,buffw);
FlashMemoryDataStorage_SectorRead(PAGE_255_TEST_SECTOR1,buffr);
if(0 != memcmp(buffw,buffr,FLASH_SECTOR_SIZE)) {
tprintf("\r\n flash read/error %d",PAGE_255_TEST_SECTOR1);
}
/* sector dump operations */
/* sector1 dump */
tprintf("\r\nSector 1 Dump: \r\n");
FlashMemoryDataStorage_SectorDump(PAGE_255_TEST_SECTOR1);
vTaskDelay(30000);;
}
}
/* -- */
int main()
{
portBASE_TYPE xReturn;
/* -- */
xReturn = xTaskCreate ( vTest_Flash, ( const signed portCHAR * const )"Test_Flash", configMINIMAL_STACK_SIZE<<5, NULL, tskIDLE_PRIORITY, NULL );
if( xReturn != pdPASS ) {
tprintf("\n\rTest_Flash initilisation problem.\n\r");
}
/* Now all the tasks have been started - start the scheduler. */
vTaskStartScheduler();
return 0;
}
flash.h file
/* -- */
#define FLASH_KEY1 0x45670123 /* These Values Come From PM0075(Programming Manual Section 2.3.1) */
#define FLASH_KEY2 0xCDEF89AB /* We Need To Set The Keys Sequentialy As Described In PM0075 */
/* -- */
#define FLASH_SECTOR_SIZE 128
/* -- */
#define FLASH_WRITE_PAGE_ERR 0x40
#define FLASH_WRITE_PROTECTION_ERR 0x41
/* -- */
#define PAGE_255_ADDR 0x0807F800
#define PAGE_255_TEST_SECTOR1 PAGE_255_ADDR
#define PAGE_255_TEST_SECTOR2 (PAGE_255_TEST_SECTOR1 + 0x200)
#define PAGE_255_TEST_SECTOR3 (PAGE_255_TEST_SECTOR2 + 0x200)
#define PAGE_255_TEST_SECTOR4 (PAGE_255_TEST_SECTOR3 + 0x200)
/* -- */
void FlashMemoryDataStorage_UnLock(void);
void FlashMemoryDataStorage_Lock(void);
void FlashMemoryDataStorage_SectorErase(uint32_t addr);
void FlashMemoryDataStorage_SectorRead(uint32_t addr, char *pBuff);
ERRCODE FlashMemoryDataStorage_SectorWrite(uint32_t addr,void * pBuff);
/* -- */

STM32F429 CAN receive (polling) doesn't work

I am using an STM32F429 device for CAN polling transmitting and receiving messages.
I have used part of the "STM32Cube_FW_F4_V1.21.0" LOOPBACK example. By difference I have turned loopback mode to normal mode.
I can transmit messages successfully, but I can not receive any message. I am transmitting CAN messages with Id=0x22 with another device to STM32F429, but it can not receive them and FIFO level is always zero. Here is the code:
/* Includes -------------------------------------------------------- */
#include "main.h"
#include "stm32f4xx_hal.h"
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private variables ----------------------------------------------- */
CAN_HandleTypeDef hcan1;
/* USER CODE BEGIN PV */
/* Private variables ----------------------------------------------- */
/* USER CODE END PV */
/* Private function prototypes ------------------------------------- */
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_CAN1_Init(void);
void Can_Transmit();
void Can_Recieve();
CAN_HandleTypeDef CanHandle;
CAN_TxHeaderTypeDef TxHeader;
CAN_RxHeaderTypeDef RxHeader;
uint8_t TxData[8];
uint8_t RxData[8];
uint32_t TxMailbox;
uint32_t RcvData = 0;
uint32_t td = 0x67;
uint8_t ERR = 0;
/* USER CODE BEGIN PFP */
/* Private function prototypes ------------------------------------- */
/* USER CODE END PFP */
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* #brief The application entry point.
*
* #retval None
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration---------------------------------------------------------- */
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_CAN1_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
if (HAL_CAN_GetRxFifoFillLevel(&CanHandle, CAN_RX_FIFO0) != 1)
{
/* Reception Missing */
Error_Handler();
}
if (HAL_CAN_GetRxMessage(&CanHandle, CAN_RX_FIFO0, &RxHeader, RxData) != HAL_OK)
{
/* Reception Error */
Error_Handler();
}
if (RxHeader.StdId == 0x22)
RcvData = ((RxData[1]<<8) | RxData[0]);
}
}
/**
* #brief System Clock Configuration
* #retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
/** Configure the main internal regulator output voltage */
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the CPU, AHB and APB busses clocks */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/** Initializes the CPU, AHB and APB busses clocks */
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/** Configure the Systick interrupt time */
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
/** Configure the Systick */
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
/* CAN1 init function */
static void MX_CAN1_Init(void)
{
CAN_FilterTypeDef sFilterConfig;
/* ## -1- Configure the CAN peripheral ########################### */
CanHandle.Instance = CAN1;
CanHandle.Init.TimeTriggeredMode = DISABLE;
CanHandle.Init.AutoBusOff = DISABLE;
CanHandle.Init.AutoWakeUp = DISABLE;
CanHandle.Init.AutoRetransmission = ENABLE;
CanHandle.Init.ReceiveFifoLocked = DISABLE;
CanHandle.Init.TransmitFifoPriority = DISABLE;
CanHandle.Init.Mode = CAN_MODE_NORMAL;
CanHandle.Init.SyncJumpWidth = CAN_SJW_1TQ;
CanHandle.Init.TimeSeg1 = CAN_BS1_4TQ;
CanHandle.Init.TimeSeg2 = CAN_BS2_2TQ;
CanHandle.Init.Prescaler = 12;
if (HAL_CAN_Init(&CanHandle) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
/* ## -2- Configure the CAN Filter ############################### */
sFilterConfig.FilterBank = 0;
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig.FilterIdHigh = 0x0000;
sFilterConfig.FilterIdLow = 0x0000;
sFilterConfig.FilterMaskIdHigh = 0x0000;
sFilterConfig.FilterMaskIdLow = 0x0000;
sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;
sFilterConfig.FilterActivation = ENABLE;
sFilterConfig.SlaveStartFilterBank = 14;
if (HAL_CAN_ConfigFilter(&CanHandle, &sFilterConfig) != HAL_OK)
{
/* Filter configuration Error */
Error_Handler();
}
/* ## -3- Start the CAN peripheral ############################### */
if (HAL_CAN_Start(&CanHandle) != HAL_OK)
{
/* Start Error */
Error_Handler();
}
}
/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
static void MX_GPIO_Init(void)
{
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* #brief This function is executed in case of error occurrence.
* #param file: The file name as string.
* #param line: The line in file as a number.
* #retval None
*/
void _Error_Handler(char *file, int line)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL
error return state */
while(1){
}
/* USER CODE END Error_Handler_Debug */
}
If this is still active, try sth. like this:
//set filter / mask to accept every identifier
CAN_FilterTypeDef filter = {0};
filter.FilterIdHigh = 0x1fff;
filter.FilterIdLow = 0xffff;
filter.FilterMaskIdHigh = 0;
filter.FilterMaskIdLow = 0;
filter.FilterFIFOAssignment = CAN_RX_FIFO0;
filter.FilterBank = 0;
filter.FilterMode = CAN_FILTERMODE_IDMASK;
filter.FilterScale = CAN_FILTERSCALE_16BIT;
filter.FilterActivation = ENABLE;
filter.SlaveStartFilterBank = 0;
if (HAL_CAN_ConfigFilter(&can_handle, &filter) != HAL_OK)
return (1);

QT C++ wait till specific time to execute function

I am trying to create an app that holds a list of tasks and for each time a deadline, now i want to execute a function (show a popup) once a deadline is met.
i have this:
#ifndef TIMER_H
#define TIMER_H
#include <QWidget>
#include <QTimer>
#include <QtGui>
#include <QObject>
class Timer : public QWidget
{
Q_OBJECT
public:
Timer(QWidget * parent = 0);
void setTimer(QString title, QString description, QDate date, QTime reminderTime);
public slots:
void showWarning() {QString show = tit;
QPushButton * thanks = new QPushButton(QObject::tr("Thank you for reminding me!"));
show.append("\n");
show.append(des);
QMessageBox popup;
popup.setText(show);
popup.setWindowTitle("Calendar : Reminder");
popup.setDefaultButton(thanks);
popup.exec();
}
private:
QString tit;
QString des;
QDateTime now;
QDateTime timeoftheaction;
QTimer *timer;
};
cpp file:
#endif // TIMER_H
#include "timer.h"
#include <iostream>
using namespace std;
Timer::Timer(QWidget * parent)
: QWidget(parent)
{
}
void Timer::setTimer(QString title, QString description, QDate date, QTime reminderTime)
{
now.currentDateTime();
timer = new QTimer;
tit = title;
des = description;
timeoftheaction.setDate(date);
timeoftheaction.setTime(reminderTime);
connect(timer, SIGNAL(timeout()),this,SLOT(showWarning()));
timer->start(now.secsTo(timeoftheaction)*1000);
}
Yet function showWarning is never being called...
no compilation errors, function showWarning works perfectly (tested)
I think the error is in the connect but i am not sure...
Short answer:
Change:
now.currentDateTime();
to
now = QDateTime::currentDateTime();
Longish answer:
currentDateTime() is a static function which instead of changing your existing object, actually returns a new QDataTime object. Although you are calling it as a member function, it's still called as a static one and leaves your object intact, which is still invalid.
Your later call to secsTo() on an invalid data time probably gets you an negative or really large number that either has passed (never going to trigger) or really late in the future.
Here is something that might be a more generic solution.
#include <QThread>
#include <QTimer>
#include <QObject>
#include <map>
/**
* Singleton to implement simple 'relative' timer.
* Implements busy wait and also timeout-notifications (useful to monitor operations that could hang, etc).
*
* If the whole application is stalled (e.g. when a new device is connected), and we only want to
* wait for a period during which application was 'really' working (not just hanging waiting for OS)
* - then ticks will be missed too. This way - it's should be possible to avoid unnecessary timeouts
* that could happen if global time was measured (especially annoying on WINdows platforms)
*/
class RelativeTimer : public QObject
{
Q_OBJECT
typedef std::multimap <unsigned int, std::pair <QObject*, QString> > Notifications;
public:
/**
* Call to busy-wait for number of ticks.
*/
static void wait_num_of_ticks(unsigned int num_of_ticks_to_wait)
{
if(self.timer_id == 0)
{
qDebug("timer not initialised, call 'RelativeTimer::Init()'");
return;
}
if(num_of_ticks_to_wait > 0)
{
unsigned long until = self.tick_counter + num_of_ticks_to_wait; // it's ok if it wraps around..
while(self.tick_counter != until)
{
QCoreApplication::processEvents(); // let others to their job..
// or comment above out and just busy wait..
}
}
}
/**
* Call to busy-wait until ms_to_wait have elapsed.
* If ms_to_wait is < tick period
* Interval will define 'tick' frequency (and accuracy).
*/
static void wait_ms(unsigned int ms_to_wait)
{
wait_num_of_ticks(num_of_ticks_to_wait(ms_to_wait));
}
/**
* Call to schedule a notification after a given timeout.
* returns notification_id that can be used to cancel this notification.
*/
static unsigned long notify_timeout_ms(unsigned int ms_to_wait,
QObject *receiver,
const char* method_name)
{
unsigned long ticks_to_wait = 0;
if(receiver && method_name)
{
ticks_to_wait = num_of_ticks_to_wait(ms_to_wait);
if(ticks_to_wait > 1)
{
ticks_to_wait += self.tick_counter;
if(ticks_to_wait == 0) // avoid 0 - make it one tick more (to alow to see if successfully added this notif)
{
ticks_to_wait = 1;
}
self.notifications.insert(std::make_pair(ticks_to_wait,
std::make_pair(receiver, method_name)));
qDebug("added delayed call..");
}
else
{
QMetaObject::invokeMethod(receiver, method_name, Qt::QueuedConnection);
ticks_to_wait = 0;
}
}
return ticks_to_wait;
}
/**
* Call to cancel a notification with a given id.
* Specify name if there were more notification with the same id (scheduled for the same tick).
* returns true on successfull cancellation, false otherwise.
*/
static bool cancel_timeout_notification(unsigned long notification_id, QString notification_name="")
{
bool cancelled = false;
if(self.notifications.size())
{
std::pair<Notifications::iterator, Notifications::iterator> to_cancel = self.notifications.equal_range(notification_id);
Notifications::iterator n = to_cancel.first;
for( ;n != to_cancel.second; ++n)
{
if(notification_name.size()== 0 || n->second.second == notification_name)
{
self.notifications.erase(n);
cancelled = true;
break;
}
}
}
return cancelled;
}
static const unsigned int default_tick_period_ms = 100;
/**
* Call this method after event loop is created- to initiate (re-start) timer.
* tick period defines 'tick' frequency (and accuracy of the timer)
* (note on Windows that there's no point to go down below 100ms).
*/
static void Init(unsigned int tick_period_ms = default_tick_period_ms)
{
self.moveToThread(&self.thread);
self.thread.start();
while(!self.thread.isRunning());
self.current_interval = tick_period_ms;
// InitMe() should execute in the thread context..
QMetaObject::invokeMethod(&self, "InitMe", Qt::QueuedConnection);
}
private:
/**
* Internal method to convert ms to number of ticks.
*/
static unsigned int num_of_ticks_to_wait(unsigned int ms_to_wait)
{
if(ms_to_wait > self.current_interval)
{
if(ms_to_wait % self.current_interval)
{
// average it..
ms_to_wait = ms_to_wait + self.current_interval / 2;
}
ms_to_wait /= self.current_interval;
}
else
{
ms_to_wait = 0;
}
return ms_to_wait;
}
/**
* Internal method to handle tick. Increments counter and invokes notifications.
*/
void timerEvent ( QTimerEvent* /*event*/ )
{
tick_counter++;
if(notifications.size())
{
std::pair<Notifications::iterator, Notifications::iterator> to_notify = notifications.equal_range(tick_counter);
Notifications::iterator n = to_notify.first;
for( ;n != to_notify.second; ++n)
{
QMetaObject::invokeMethod(n->second.first,
n->second.second.toStdString().c_str(),
Qt::QueuedConnection);
}
notifications.erase(to_notify.first, to_notify.second);
}
}
private slots:
/**
* Internal slot to initialize the timer. Should be called in this->timer context.
*/
void InitMe()
{
if(timer_id != 0)
{
killTimer(timer_id);
timer_id = 0;
}
tick_counter = 0;
timer_id = self.startTimer(self.current_interval);
}
private:
RelativeTimer()
{
}
~RelativeTimer()
{
thread.quit();
thread.wait();
}
QThread thread;
Notifications notifications;
int timer_id;
unsigned int current_interval;
unsigned long tick_counter;
static RelativeTimer self; // implement it as a signleton.. Define it in your C file, e.g.:
// RelativeTimer RelativeTimer::self;
};
Can be used like:
CurrQObjectClass::OnTimeout()
{
// ...
}
CurrQObjectClass::SomeMethod()
{
RelativeTimer::notify_timeout_ms(5000, this, "OnTimeout");
}
but also for busy-waiting:
RelativeTimer::wait_ms(2000);
Enjoy.

Resources