[ESP32] Make a logger task with FreeRTOS

I'm trying to write logs from IMU to flash file system, for that I'm using LittleFS. I've one task polling from IMU and creating a char buffer (this task is running at 32 Hz), the IMU task then sends the char buffer to the logger task with the help of a queue. Things are running smooth for the first couple of minutes. As soon as the file size grows to over mb, writing speed seems to slow down and the queue starts to fill up and eventually fills up and starts missing some of the incoming values.

IMU task looks something like this:

static void imu_task(void *pvParameter)
{
	TickType_t xLastWakeTime = xTaskGetTickCount();
	const TickType_t xFrequency = (31); // delay for mS

	for (;;) {
		mpu6050_get_acce(mpu6050, &acce);
		mpu6050_get_gyro(mpu6050, &gyro);
		imu_values.ax = acce.acce_x;
		imu_values.ay = acce.acce_y;
		imu_values.az = acce.acce_z;

		imu_values.gx = gyro.gyro_x;
		imu_values.gy = gyro.gyro_y;
		imu_values.gz = gyro.gyro_z;
		
		IMUvalues[0][marker] = imu_values.ax;
		IMUvalues[1][marker] = imu_values.ay;
		IMUvalues[2][marker] = imu_values.az;
		IMUvalues[3][marker] = imu_values.gx;
		IMUvalues[4][marker] = imu_values.gy;
		IMUvalues[5][marker] = imu_values.gz;

		snprintf(spiffs_buffer, sizeof(spiffs_buffer),
			 "%llu,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%.1f,%d,%d,%d\n",
			 esp_timer_get_time() / 1000ULL, IMUvalues[0][marker], IMUvalues[1][marker],
			 IMUvalues[2][marker], IMUvalues[3][marker], IMUvalues[4][marker],
			 IMUvalues[5][marker], freq, sos, leg_client_connected, voltage_1);

		ESP_LOGI(tag, "IMU task high water mark %d", uxTaskGetStackHighWaterMark(NULL));

		if (xQueueSendToBack(data_queue, spiffs_buffer, 5 / portTICK_PERIOD_MS) != pdTRUE)
			ESP_LOGW(tag, "Could not send to queue");

		vTaskDelayUntil(&xLastWakeTime, xFrequency);
	}
}

The logger task looks something like this:

static void logger_task(void *args)
{
	char incomming_messages[1024];

	for (;;) {
		if (xQueueReceive(data_queue, incomming_messages, 5 / portTICK_PERIOD_MS) != pdTRUE)
			continue;
		else {
			uint16_t FreeSpace = uxQueueSpacesAvailable(data_queue);

			printf("Free Space on queue: %d\n", FreeSpace);

			int remaining_space = filesystem_get_free_space(conf);
			if (!remaining_space && f != NULL) {
				fprintf(f, "%s", incomming_messages);
			}
		}

		if (uxQueueMessagesWaiting(data_queue) == 0) { // no message? take a break
			vTaskDelay(10 / portTICK_RATE_MS); // delay 15s
		}
	}
	vTaskDelete(NULL);
}

And the queue is defined as such: data_queue = xQueueCreate(100, sizeof(char) * 1024);.

What would be a good solution to this, splitting the files ?

Hi @brahmajit

I'm curious as to why you're continually timing out and going back round the loop with 5 / portTICK_PERIOD_MS:

for (;;) {
  if (xQueueReceive(data_queue, incomming_messages, 5 / portTICK_PERIOD_MS) != pdTRUE)
    continue;

...rather than using portMAX_DELAY?

Also, do you need to check the queue and add a vTaskDelay()?:

if (uxQueueMessagesWaiting(data_queue) == 0) { // no message? take a break
  vTaskDelay(10 / portTICK_RATE_MS); // delay 15s
}

...since the xQueueReceive() function will cause the receiving task to block anyway.

@MartinL I'm new to using freertos, I found an example online that showed how to use a freertos queue and followed that example. If you think that using those will be a better, then I'll use that.

Thanks for sharing BTW.

Hi @brahmajit

I found these excellent FreeRTOS tutorial and reference guides really helpful.

The tutorial is clearly written and describes how a real-time system operates: (tasks, priority, multitasking, queues, semaphores, group events, task notification, etc, etc...). It contains a number of queue based examples:

The reference provides a complete overview of all the FreeRTOS functions and macros:

Thanks @MartinL. Although my problem was not related to queue, still great resources.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.