I want to understand RTOSs better and therefore started implementing a scheduler. I want to test my code, but unfortunately I have no HW lying around right now. What is an easy way to pretend executing an ISR corresponding to timer in C?
EDIT: Thanks to the answer of Sneftel I was able to simulate a timer interrupt. The code below is inspired by http://www.makelinux.net/alp/069. The only thing I am missing is to do it in a nested way. So if the ISR is running another timer interrupt would cause a new instance of the ISR preempting the first one.
#include<stdlib.h>
#include<stdio.h>
#include<assert.h>
#include<signal.h>
#include<sys/time.h>
#include<string.h>
#ifdef X86_TEST_ENVIRONMENT
void simulatedTimer(int signum)
{
static int i=0;
printf("System time is %d.\n", i);
}
#endif
int main(void)
{
#ifdef X86_TEST_ENVIRONMENT
struct sigaction sa;
struct itimerval timer;
/* Install timer_handler as the signal handler for SIGVTALRM. */
memset (&sa, 0, sizeof (sa));
sa.sa_handler = &simulatedTimer;
sigaction (SIGVTALRM, &sa, NULL);
/* Configure the timer to expire after 250 msec... */
timer.it_value.tv_sec = 0;
timer.it_value.tv_usec = CLOCK_TICK_RATE_MS * 1000;
/* ... and every 250 msec after that. */
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = CLOCK_TICK_RATE_MS * 1000;
/* Start a virtual timer. It counts down whenever this process is executing. */
setitimer (ITIMER_VIRTUAL, &timer, NULL);
#endif
#ifdef X86_TEST_ENVIRONMENT
/* Do busy work. */
while (1);
#endif
return 0;
}
The closest thing in POSIX terms is probably signal handlers; SIGALRM is fired asynchronously within the process in much the same way that an ISR is. There's significant differences in what's safe to do, though, so I wouldn't go too far with the analogy.
Related
I am porting LittleFS on STM32 G431Rb internal Flash. Every thing is OK when I read and write file on main function. But when I write some thing in Task, System will be stuck on osdlelay.
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void *argument)
{
/* USER CODE BEGIN 5 */
/* Infinite loop */
int i = 0;
for(;;)
{
ULOG_TRACE("Trace count = %d",i);
i++;
osDelay(5);
}
/* USER CODE END 5 */
}
In ULOG_TRACE function, I called lfs_fs_write function.
lfs_fs_write function call HAL_FLASHEx_Erase and HAL_FLASH_Prog.
static FLASH_EraseInitTypeDef EraseInitStruct;
int stm32_interl_flash_block_erase(const struct lfs_config *c, lfs_block_t block)
{
uint32_t PageError;
__disable_irq();
HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP |
FLASH_FLAG_OPERR |
FLASH_FLAG_PROGERR |
FLASH_FLAG_WRPERR |
FLASH_FLAG_PGAERR |
FLASH_FLAG_SIZERR |
FLASH_FLAG_PGSERR |
FLASH_FLAG_MISERR );
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
EraseInitStruct.Banks = FLASH_BANK_1;
EraseInitStruct.Page = FS_BASE_PAGE_START + block;
EraseInitStruct.NbPages = 1;
if (HAL_FLASHEx_Erase(&EraseInitStruct,&PageError)!= HAL_OK){
__enable_irq();
return HAL_FLASH_GetError();
}
HAL_FLASH_Lock();
__enable_irq();
return 0;
}
int stm32_interl_flash_block_prog(const struct lfs_config *c, lfs_block_t block,
lfs_off_t off, const void *buffer, lfs_size_t size)
{
__disable_irq();
HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP |
FLASH_FLAG_OPERR |
FLASH_FLAG_PROGERR |
FLASH_FLAG_WRPERR |
FLASH_FLAG_PGAERR |
FLASH_FLAG_SIZERR |
FLASH_FLAG_PGSERR |
FLASH_FLAG_MISERR );
uint32_t dest_addr = FS_BASE_ADDR + c->block_size*block +off;
uint64_t *pSrc = (uint64_t*)buffer;
uint32_t write_size = 0;
while(write_size < size){
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD,dest_addr,*(pSrc)) != HAL_OK){
HAL_FLASH_Lock();
__enable_irq();
return HAL_FLASH_GetError();
}
pSrc++;
dest_addr += 8;
write_size += 8;
}
HAL_FLASH_Lock();
__enable_irq();
return 0;
}
I googled these problem, some guys said the problem is that the task schedule interrupt occur when I erase or prog internal flash.But I add disable_irq, it also have the problem.
Do not disable all interrupts. At least the HAL tick should run further. The HAL_FLASH_* methods depend on them.
Use osKernelSuspend() and osKernelResume() to stop and continue thread scheduling.
Further more check all return codes, also from HAL_FLASH_Unlock.
The flash peripheral is a little nasty on the STM32 controller family.
If something going wrong, either you access addresses unaligned, out of bounds or simple not in the correct order the peripheral set its error bits and the HAL functions do not operate anymore. You already clear the error flags.
I've experienced that checking and clearing the error flags also after HAL_FLASH_Program is always a good idea.
PS: If your code really stuck in osDelay then your cmsis os scheduler interrupt is not running or the scheduler is disabled/stoped.
You haven't specified how long the code gets stuck for or why you think it is stuck in osDelay, but here is one guess:
If you are writing or erasing in the same flash bank as you are executing code from, your code will stop until the operation has completed. This will block all tasks and all interrupts whether they are turned on or off. This is because no instructions can be fetched from flash while it is writing or erasing. A few instructions might still execute if they have already been prefetched.
If you are able to use dual-bank mode you can write one bank while executing from the other, but I think the 128kB parts might only support single bank flash, and others may have dual-bank disabled by default.
I am trying to write uint64_t(double word) variable into the flash memory, without success though. Here is the code.
#define APPLICATION_START_ADDRESS 0x8008000
void flashErase(uint8_t startSector, uint8_t numberOfSectors)
{
HAL_FLASH_Unlock();
Flash_eraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
Flash_eraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
Flash_eraseInitStruct.Sector = startSector;
Flash_eraseInitStruct.NbSectors = numberOfSectors;
if(HAL_FLASHEx_Erase(&Flash_eraseInitStruct, &Flash_halOperationSectorError) != HAL_OK)
{
Flash_raiseError(errHAL_FLASHEx_Erase);
}
HAL_FLASH_Lock();
}
int main(void)
{
HAL_Init();
main_clockSystemInit();
__IO uint64_t word = 0x1234567890;
flashErase(2, 1);
// flashProgramWord(aTxBuffer, APPLICATION_START_ADDRESS, 2 );
HAL_FLASH_Unlock();
HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, APPLICATION_START_ADDRESS, word);
}
I get error flag raised PGSERR and PGAERR. The erase operation goes without problems. But programming returns ERROR.
Some Ideas?
There is no STM32F249, did you mean STM32F429?
In order to use 64 bit programming, VPP (BOOT0) has to be powered by 8 - 9 Volts. Is it?
See the Reference Manual Section 3.6.2
By the way,
__IO uint64_t word = 0x1234567890;
would not work as (presumably) expected. It is a 32 bit architecture, integer constants will be truncated to 32 bits, unless there is an L suffix. U wouldn't hurt either, because the variable is unsigned. __IO is unnecessary.
uint64_t word = 0x1234567890UL;
I have some trouble to receive data over the USART. What I actually want to achieve ist, that I can receive a command over USART with no specific length (only a maximum possible length). So I use the interrupt routine to check each character received, but I somehow still cannot achieve what I want. The routine is called each time I receive a new character, but somehow HAL_UART_Receive_IT(&huart1,rx_data,buff_size_rx) does not upgrade in realtime, then I don't see the received character when I check rx_data[pointer], but a few time later it is in the rx_data buffer.
What I have so far:
int pointer =0;
...
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
if ( USART1->ISR & UART_IT_TXE) {
}
if ( USART1->ISR & UART_IT_RXNE) {
HAL_UART_Receive_IT(&huart1,rx_data,buff_size_rx);
if(rx_data[pointer]=='\0') {
pointer=0;
readCommand(rx_data);
clearBuffer(rx_data,buff_size_rx);
} else {
pointer++;
if(pointer>=buff_size_rx) {
pointer=0;
}
}
}
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
HAL_UART_Receive_IT() is not meant to be called from an interrupt handler that way, but to initiate receiving a fixed number of bytes via interrupt.
A possible workaround is to check your input buffer after HAL_UART_IRQHandler() completes, i.e. in the /* USER CODE BEGIN USART1_IRQn 1 */ section. When a command is processed, you can reset pRxBuffPtr and RxXferCount in the handle structure to their original values to start from the start of the buffer again.
Another horrible possible workaround would be to call HAL_UART_Receive_IT() with a buffer size of 1, and set up a HAL_UART_RxCpltCallback() handler that checks the received byte each time, and calls HAL_UART_Receive_IT() again when necessary.
Of course you could do it without HAL, as PeterJ and others (always) suggest.
You've already implemented pin and interrupt setup, leave them unchanged at first.
Calculate the UART->BRR value according to the reference manual, or copy the relevant code from hal.
set UART->CR1=USART_CR1_RE|USART_CR1_TE|USART_CR1_UE|USART_CR1_RXNEIE; Now, you are getting interrupts.
In the interrupt function, read UART->SR into a temporary variable, and examine it.
Read UART->DR when there is a received byte waiting, do the error handling otherwise (later).
Get rid of the rest of the HAL calls when the above is working.
Interrupt response and processing time is often critical in embedded applications, and the HAL just wastes a lot of that.
The normal HAL library is not useful for continuous reception or commands with different length.
If you have the complete HAL package installed, you could look at the examples for the LowLevel interface.
Projects\STM32F411RE-Nucleo\Examples_LL\USART\USART_Communication_Rx_IT_Continuous
The main thing is to set you usart to continuous reception:
void Configure_USART(void) {
/* (1) Enable GPIO clock and configures the USART pins *********************/
/* Enable the peripheral clock of GPIO Port */
USARTx_GPIO_CLK_ENABLE();
/* Configure Tx Pin as : Alternate function, High Speed, Push pull, Pull up */
LL_GPIO_SetPinMode(USARTx_TX_GPIO_PORT, USARTx_TX_PIN, LL_GPIO_MODE_ALTERNATE);
USARTx_SET_TX_GPIO_AF();
LL_GPIO_SetPinSpeed(USARTx_TX_GPIO_PORT, USARTx_TX_PIN, LL_GPIO_SPEED_FREQ_HIGH);
LL_GPIO_SetPinOutputType(USARTx_TX_GPIO_PORT, USARTx_TX_PIN, LL_GPIO_OUTPUT_PUSHPULL);
LL_GPIO_SetPinPull(USARTx_TX_GPIO_PORT, USARTx_TX_PIN, LL_GPIO_PULL_UP);
/* Configure Rx Pin as : Alternate function, High Speed, Push pull, Pull up */
LL_GPIO_SetPinMode(USARTx_RX_GPIO_PORT, USARTx_RX_PIN, LL_GPIO_MODE_ALTERNATE);
USARTx_SET_RX_GPIO_AF();
LL_GPIO_SetPinSpeed(USARTx_RX_GPIO_PORT, USARTx_RX_PIN, LL_GPIO_SPEED_FREQ_HIGH);
LL_GPIO_SetPinOutputType(USARTx_RX_GPIO_PORT, USARTx_RX_PIN, LL_GPIO_OUTPUT_PUSHPULL);
LL_GPIO_SetPinPull(USARTx_RX_GPIO_PORT, USARTx_RX_PIN, LL_GPIO_PULL_UP);
/* (2) NVIC Configuration for USART interrupts */
/* - Set priority for USARTx_IRQn */
/* - Enable USARTx_IRQn */
NVIC_SetPriority(USARTx_IRQn, 0);
NVIC_EnableIRQ(USARTx_IRQn);
/* (3) Enable USART peripheral clock and clock source ***********************/
USARTx_CLK_ENABLE();
/* (4) Configure USART functional parameters ********************************/
/* TX/RX direction */
LL_USART_SetTransferDirection(USARTx_INSTANCE, LL_USART_DIRECTION_TX_RX);
/* 8 data bit, 1 start bit, 1 stop bit, no parity */
LL_USART_ConfigCharacter(USARTx_INSTANCE, LL_USART_DATAWIDTH_8B, LL_USART_PARITY_NONE, LL_USART_STOPBITS_1);
/* No Hardware Flow control */
/* Reset value is LL_USART_HWCONTROL_NONE */
// LL_USART_SetHWFlowCtrl(USARTx_INSTANCE, LL_USART_HWCONTROL_NONE);
/* Oversampling by 16 */
/* Reset value is LL_USART_OVERSAMPLING_16 */
// LL_USART_SetOverSampling(USARTx_INSTANCE, LL_USART_OVERSAMPLING_16);
/* Set Baudrate to 115200 using APB frequency set to 100000000/APB_Div Hz */
/* Frequency available for USART peripheral can also be calculated through LL RCC macro */
/* Ex :
Periphclk = LL_RCC_GetUSARTClockFreq(Instance); or
LL_RCC_GetUARTClockFreq(Instance); depending on USART/UART instance
In this example, Peripheral Clock is expected to be equal to
100000000/APB_Div Hz => equal to SystemCoreClock/APB_Div
*/
LL_USART_SetBaudRate(USARTx_INSTANCE, SystemCoreClock/APB_Div, LL_USART_OVERSAMPLING_16, 115200);
/* (5) Enable USART *********************************************************/
LL_USART_Enable(USARTx_INSTANCE);
}
The USART IT Handler should look like
void USARTx_IRQHandler(void)
{
/* Check RXNE flag value in SR register */
if(LL_USART_IsActiveFlag_RXNE(USARTx_INSTANCE) && LL_USART_IsEnabledIT_RXNE(USARTx_INSTANCE))
{
/* RXNE flag will be cleared by reading of DR register (done in call) */
/* Call function in charge of handling Character reception */
USART_CharReception_Callback();
}
else
{
/* Call Error function */
Error_Callback();
}
}
The last thing to set up is the Callback
void USART_CharReception_Callback(void);
Where you could put the bytes into an buffer and handle it in the main loop or where you want.
Since I stumbled over the problem today and could not find a good solution to it, I like to present a very simple one, using most of the HAL but avoiding the problems described...
Short verison of my approach is:
In the last user code section (for the appropriate USART instance, if using more than one) of void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle), enable the IRQ with:
__HAL_UART_ENABLE_IT(&huartx, UART_IT_RXNE);
Then put the desired code in your interrupt function:
void USART3_IRQHandler(void) {
/* USER CODE BEGIN USART3_IRQn 0 */
CallMyCodeHere();
return; // To avoid calling the default HAL handler at all
// (in case you want to save the time)
/* USER CODE END USART3_IRQn 0 */
HAL_UART_IRQHandler(&huart3); // This is the CubeMX generated HAL handler
/* USER CODE BEGIN USART3_IRQn 1 */
/* USER CODE END USART3_IRQn 1 */
}
Don't use HAL_UART_Receive_IT anywhere, it will disable the IRQ and you need to re-enable it, if you want to get called with every reception.
The long version could be found in my post here...
Here is the full example of receiving data and idle line detection by interrupts:
Enable the receive interrupts and idle line detection in main.c:
/* USER CODE BEGIN USART2_Init 2 */
__HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE); // enable receive intterupts
__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE); // enable idle line detection
/* USER CODE END USART2_Init 2 */
Sort out the idle line event from within USARTx_IRQHandler in stm32f4xx_it.c:
void USART2_IRQHandler(void)
{
/* USER CODE BEGIN USART2_IRQn 0 */
if (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_IDLE)) {
__HAL_UART_CLEAR_IDLEFLAG(&huart2); // taken from https://electronics.stackexchange.com/questions/471272/setting-up-stm32-timer-for-uart-idle-detection#comment1353999_480556
uart2_idleHandler();
} else {
uart2_handler();
}
return;
/* USER CODE END USART2_IRQn 0 */
HAL_UART_IRQHandler(&huart2);
/* USER CODE BEGIN USART2_IRQn 1 */
/* USER CODE END USART2_IRQn 1 */
}
Testing:
Create the following handlers:
char my_uart_buffer[256];
int my_uart_buffer_index = 0;
void uart2_handler(void){
char buff;
HAL_UART_Receive (&huart2, (uint8_t *)&buff, 1, 400);
my_uart_buffer[my_uart_buffer_index++] = buff;
}
void uart2_idleHandler(){
my_uart_buffer_index = 0;
}
Open a serial port client in your PC, setup as 115200 baud, 8N1.
Set a breakpoint to uart2_idleHandler().
Send "Hello world".
You can examine your buffer by p/c *my_uart_buffer#20 when breakpoint hits.
Example Project
Here is the full example that runs on STM32F407 Discovery board.
You can make it work using HAL! It may not be as elegant as other implementations but it is doable.
You have to create an error handler function and then the function that calls the HAL_UART_RCV_IT must flush the UART RX whenever there is an overrun error.
In addition, I work with two buffers. While the Interrupt is filling one buffer the main loop is emptying the other.
Here it how it is working well for me:
typedef enum
{
UARTREADY = 0,
UARTBUSY = 1,
UARTDATA = 2,
UARTERROR = 3
} enumUartStatus;
while(1){
if(UARTREADY == isUsart3RxReady()){
Usart3RxBuffer((char *)&SOMRxBytesBuffer[use_buffer_index], RCV_BUFFER_BANK_SIZE); // receive bytes in the raw buffer
if(use_buffer_index == RCV_BUFFER_BANK1_INDEX){
use_buffer_index = RCV_BUFFER_BANK2_INDEX;
rxb1_stats++;
}else{
use_buffer_index = RCV_BUFFER_BANK1_INDEX;
rxb2_stats++;
}
}
}
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
if(huart == NULL){
return;
}
if(huart->Instance == USART3){
if(HAL_UART_GetError(huart) == HAL_UART_ERROR_FE){
Usart3Ready = UARTREADY;
}else{
Usart3Ready = UARTERROR;
}
}
}
void Usart3RxBuffer(char *buffer, unsigned short rxbuffersize){
/* Reset transmission flag */
if(Usart3Ready != UARTREADY)
{
return;
}
if(HAL_UART_GetState(&huart3) == HAL_UART_STATE_READY){
/*##-3- Put UART peripheral in reception process ###########################*/
if (HAL_UART_Receive_IT(&huart3, (uint8_t *)buffer, rxbuffersize) != HAL_OK)
{
// TODO: Error_Handler();
DEBUG_TRACE(DEBUG_MSK_MAIN, "UART3 error starting receiver!\r\n");
}else{
// An interrupt HAL_UART_ErrorCallback hit right here !!!!
// There is an overrun error happening here so we have to retry
// this is because we are using the Receive_IT in a continous communication and there is no handshake or flow control
if(Usart3Ready != UARTERROR){
/* Busy waiting to receive bytes */
Usart3Ready = UARTBUSY;
}
}
}
if(Usart3Ready == UARTERROR){
HAL_UART_AbortReceive_IT(&huart3);
Usart3Ready = UARTREADY;
}
}
i'm actually working on my final project for graduation. I'm using FreeRTOS on STM32F4 discovery. It all works properly, but the tasks are not ordered as i like. they execute in this cycle : task3 twice, task2 once, then again task3 twice and tas2 once and then task1 once.
I want them to execute iin this order : task1 then task2 then task3. Thank you!
Here is a portion of my code:
/* The period of the example software timer, specified in milliseconds, and
converted to ticks using the portTICK_RATE_MS constant. */
#define mainSOFTWARE_TIMER_PERIOD_MS ( 1000 / portTICK_RATE_MS )
int main(void)
{
/* Configure the system ready to run the demo. The clock configuration
can be done here if it was not done before main() was called. */
prvSetupHardware();
/* Create the queue used by the queue send and queue receive tasks.
http://www.freertos.org/a00116.html */
xQueue = xQueueCreate( mainQUEUE_LENGTH, /* The number of items the queue can hold. */
sizeof( uint32_t ) ); /* The size of each item the queue holds. */
/* Add to the registry, for the benefit of kernel aware debugging. */
vQueueAddToRegistry( xQueue, ( signed char * ) "MainQueue" );
/* Create the semaphore used by the FreeRTOS tick hook function and the
event semaphore task. */
vSemaphoreCreateBinary( xEventSemaphore );
/* Add to the registry, for the benefit of kernel aware debugging. */
vQueueAddToRegistry( xEventSemaphore, ( signed char * ) "xEventSemaphore" );
/* Create the MPXV7002DP task */
xTaskCreate( vMPXV7002DPTask, /* The function that implements the task. */
( signed char * ) "MPXV7002DP", /* Text name for the task, just to help debugging. */
configMINIMAL_STACK_SIZE, /* The size (in words) of the stack that should be created for the task. */
NULL, /* A parameter that can be passed into the task. Not used in this simple demo. */
configMAX_PRIORITIES - 1, /* The priority to assign to the task. tskIDLE_PRIORITY (which is 0) is the lowest priority. configMAX_PRIORITIES - 1 is the highest priority. */
NULL ); /* Used to obtain a handle to the created task. Not used in this simple demo, so set to NULL. */
/* Create the MPU9250 task */
xTaskCreate( vMPU9250Task,
( signed char * ) "MPU9250",
configMINIMAL_STACK_SIZE,
NULL,
configMAX_PRIORITIES - 1,
NULL );
/* Create the MPL3115A2 task */
xTaskCreate( vMPL3115A2Task,
( signed char * ) "MPL3115A2",
configMINIMAL_STACK_SIZE,
NULL,
configMAX_PRIORITIES - 1,
NULL );
/* Create the TOPC task */
//xTaskCreate( vToPcTask,
// ( signed char * ) "ToPc",
// configMINIMAL_STACK_SIZE,
// NULL,
//configMAX_PRIORITIES - 4,
//NULL );
/* Start the tasks and timer running. */
vTaskStartScheduler();
}
static void vMPXV7002DPTask(void *pvParameters)
{
int convertedValue,pressure,v;
for(;;)
{
if(xSemaphoreTake( xEventSemaphore, mainSOFTWARE_TIMER_PERIOD_MS ))
{USART_puts(USART1, "mpxv begin\n\r");
ADC_SoftwareStartConv(ADC1);//Start the conversion
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));//Processing the conversion
convertedValue = ADC_GetConversionValue(ADC1); //Return the converted dat
convertedValue=(5*convertedValue)/255;
pressure=(convertedValue+0.0625*4)-0.5;
v=sqrt((2*pressure)/1.293);
USART_puts(USART1, "mpxv end\n\r");
xSemaphoreGive( xEventSemaphore );
}
vTaskDelay( mainSOFTWARE_TIMER_PERIOD_MS );
}
}
static void vMPU9250Task(void *pvParameters)
{
int16_t xa,ya,za,xg,yg,zg,xm,ym,zm;
uint8_t res[22];
for( ;; )
{
if(xSemaphoreTake( xEventSemaphore, mainSOFTWARE_TIMER_PERIOD_MS ))
{USART_puts(USART1, "mpu begin\n\r");
SPI_Tx(0x25,0x0C|0x80);//read from slv0
SPI_Tx(0x26,0x03);//reg from which start reading
SPI_Tx(0x27,0x87);//read 7 bytes
SPI_Rx_seq(0x3A,res,22);
xa=((int16_t)res[1]<<8)|res[2];
xa/=8192;
ya=((int16_t)res[3]<<8)|res[4];
ya/=8192;
za=((int16_t)res[5]<<8)|res[6];
za/=8192;
xg=((int16_t)res[9]<<8)|res[10];
xg/=131;
yg=((int16_t)res[11]<<8)|res[12];
yg/=131;
zg=((int16_t)res[13]<<8)|res[14];
zg/=131;
//AK8963_Rx_seq( 0x03, mag_asax, 7);
//SPI_Rx_seq(0x49,mag_asax,7);
xm=((int16_t)res[16]<<8)|res[15];
ym=((int16_t)res[18]<<8)|res[17];
zm=((int16_t)res[20]<<8)|res[19];
USART_puts(USART1, "mpu end\n\r");
xSemaphoreGive( xEventSemaphore );
}
vTaskDelay( mainSOFTWARE_TIMER_PERIOD_MS/2 );
}
}
static void vMPL3115A2Task( void *pvParameters )
{
uint8_t altitude[3];
uint32_t x;
char alt[1];
for( ;; )
{
if(xSemaphoreTake( xEventSemaphore, mainSOFTWARE_TIMER_PERIOD_MS ))
{USART_puts(USART1, "mpl begin\n\r");
Read_IIC1_seq(0x60<<1, 0x01, altitude, 3);
x=altitude[0];x<<=8;
x|=altitude[1];x<<=8;
x|=altitude[2];x>>=4;
x/=49920;
USART_puts(USART1, "mpl end\n\r");
xSemaphoreGive( xEventSemaphore );
}
vTaskDelay( mainSOFTWARE_TIMER_PERIOD_MS/4 );
}
}
Look at the call to vTaskDelay() in each task function. One task delays for PERIOD, the next for PERIOD/2, and the third for PERIOD/4. The task that delays for PERIOD/4 will be ready to run four times for every time that the task that delays for PERIOD will be ready to run. This is why you are seeing one task run four times, the next two times, and the third once. Why did you use different delay periods if you want the tasks to run at the same rate?
As for which task runs first at the beginning, that is going to depend on how the FreeRTOS scheduler is implemented. You assigned the same priority (configMAX_PRIORITIES - 1) to each task in the calls to xTaskCreate(). The FreeRTOS scheduler is probably using its round-robin scheduling algorithm for tasks with the same priority. And I'm guessing that the scheduler readies the tasks in the order they were created (or maybe reverse order). So you might be able to affect the ready order by changing the creation order. But I'm just guessing and you should look at the source code for the FreeRTOS scheduler to learn what it does. Or maybe you should give the tasks different priorities. Then the FreeRTOS scheduler should make the task with the highest priority ready to run first.
I am attempting to send data from device to host using the Gazelle protocol, however, when reading a time varying signal in on MATLAB the values continuously change elements in the array.
Here is the Simblee/Rfduino host code:
#include <SimbleeGZLL.h>
device_t role = HOST;
char array[5];
void setup() {
Serial.begin(9600);
SimbleeGZLL.begin(role);
timer_one(1); // 1 ms timer
}
void loop() {
Serial.flush();
printf(EMG);
}
void SimbleeGZLL_onReceive(device_t device, int rssi, char *data, int len)
{
if (len > 0) {
digitalWrite(2,HIGH);
array[0] = data[0];
array[1] = data[1];
array[2] = data[2];
array[3] = data[3];
array[4] = '\0';
} else SimbleeGZLL.sendToDevice(device, 'A');
}
And the device code:
include
device_t role = DEVICE1;
volatile int state;
char array[4];
void setup() {
SimbleeGZLL.begin(role);
Serial.begin(9600);
timer_one(1);
}
void loop() {
array[0] = analogRead(2);
array[1] = analogRead(3);
array[2] = analogRead(4);
array[3] = analogRead(5);
SimbleeGZLL.sendToHost(EMG,4);
}
Could someone please provide some assistance to identify where the issue may lie?
Thank you!
Matlab is not super reliable with serial communication. I actually had a similar issue with a serial device where the input values would be out of order. Are you signaling when to start and stop printing? What does your matlab code look like?
I would set up a ring buffer on the host and the device to deal with the asycn time issues.
You are going to get timing issues with the current method. What kind of frequency are you going for? The analogRead is super slow, and double multiple in a row seems to make things even slower. Could you try to set up an ADC interrupt?
Where is your timer code?