Hello,
I’m developing a part of code that records some measurements. After successful measurement, existing thread (lets call it MeasThread) notifies my new thread (lets call it RecorderActuatorThread) via binary semaphore. RecorderActuatorThread then writes the measurement to the buffer, accessing it using mutex. After 2 successful writes, third one results in hard fault in xSemaphoreGive(_recorder.buffer.mutex). RecorderActuatorThread runs in a loop, where it checks for a message from RecorderThread, that can change it’s state, and writes to buffer if the state is recording
The application already consists of multiple threads (GUI, Meas, etc). Before adding recorder thread it works like a charm so (I guess) we can assume that the problem is somewhere in Recorder thread.
The _recorder.buffer.mutex
is for now used only once in recorder thread and nowhere else.
Here is the code of recorder thread and its initialization:
static recorder_init_res_t _recorder_init(void)
{
_recorder.queue = xQueueCreate(RECORDER_QUEUE_SIZE, sizeof(recorder_msg_t));
if(_recorder.queue == NULL) return recorder_init_queue_error;
_recorder.buffer.mutex = xSemaphoreCreateMutex();
if(_recorder.buffer.mutex == NULL) return recorder_init_mutex_error;
_recorder.new_measurement = xSemaphoreCreateBinary();
if(_recorder.new_measurement == NULL) return recorder_init_semaphore_error;
// Create recorder actuator task
osThreadDef(recorder_acturator_thread, RecorderActuatorThread, osPriorityNormal, 0, 1024);
osThreadCreate(osThread(recorder_acturator_thread), NULL);
return recorder_init_ok;
}
void RecorderActuatorThread(void const * argument)
{
osEvent event;
while(1)
{
event = osMessageGet(_recorder.queue, 0);
if(event.status == osEventMessage)
{
.... (state machine - has nothing to do with freeRTOS)
}
if(_recorder.recording)
{
if(xSemaphoreTake(_recorder.new_measurement, 10) == pdTRUE)
{
_write_frame_to_buffer(recorder_frame_type_measurement);
}
}
else
{
osThreadYield();
}
}
}
static void _write_frame_to_buffer(recorder_frame_type_t type)
{
recorder_frame_settings_welding_t frame_settings_welding;
recorder_frame_program_settings_t frame_program_settings;
recorder_frame_finnish_t frame_finnish;
recorder_frame_header_t header = {.type = type, .version = RECORDER_FRAME_VERSION};
recorder_frame_t frame = {.header = header};
uint8_t *data_ptr = NULL;
uint16_t frame_size;
_recorder.buffer.frames_nr++;
switch(type)
{
case recorder_frame_type_welding_settings:
frame.header.data_size = sizeof(recorder_frame_settings_welding_t);
// fill frame here
frame_settings_welding.temp = 1;
data_ptr = (uint8_t *)&frame_settings_welding;
break;
case recorder_frame_type_program_settings:
frame.header.data_size = sizeof(recorder_frame_program_settings_t);
// fill frame here
frame_settings_welding.temp = 2;
data_ptr = (uint8_t *)&frame_program_settings;
break;
case recorder_frame_type_scan_results:
frame.header.data_size = sizeof(ScanResults_t);
data_ptr = (uint8_t *)&GenInfo.ScanResults;
break;
case recorder_frame_type_measurement:
frame.header.data_size = sizeof(MeasList2CH_t);
data_ptr = (uint8_t *)&GenInfo.Meas;
break;
case recorder_frame_type_finish:
frame.header.data_size = sizeof(recorder_frame_finnish_t);
frame_finnish.frames_nr = _recorder.buffer.frames_nr;
frame_finnish.error = GenInfo.error;
data_ptr = (uint8_t *)&frame_finnish;
break;
}
if(data_ptr != NULL && frame.header.data_size > 0)
{
memcpy(frame.data, data_ptr, frame.header.data_size);
}
// NOTE: make sure that frame size is aligned to 4 bytes because if not - HardFault can occur
frame_size = sizeof(recorder_frame_header_t) + frame.header.data_size;
_write_to_buffer((uint8_t *)&frame, frame_size);
}
static void _write_to_buffer(uint8_t *ptr, uint32_t size)
{
static uint64_t bytes_written = 0;
if(_recorder.buffer.write_ptr + size > _recorder.buffer.end_ptr)
{
_error_handler(recorder_error_write_buffer_overflow);
return;
}
xSemaphoreTake(_recorder.buffer.mutex, portMAX_DELAY);
memcpy(_recorder.buffer.write_ptr, ptr, size);
_recorder.buffer.write_ptr += size;
bytes_written += size;
xSemaphoreGive(_recorder.buffer.mutex);
}
And here is the function used for notifying about new measurement:
void recorder_new_measurement_notify(void)
{
if(_recorder.recording)
{
xSemaphoreGive(_recorder.new_measurement);
}
}
Now, I understand the concepts of mechanisms I use in the code, but I am aware that I don’t know all the specifics about FreeRTOS. I am struggling to find out what is the problem, as when I’m debugging the applicantion, the workflow seems fine, all the pointers look ok, and after two successful writes, xSemaphoreGive(_recorder.buffer.mutex)
at the end of _write_to_buffer
results in hard fault and I have no idea why. The debugger is struggling to unwind call stack properly so when the hard fault occurs, so I am not posting it. I hope that I provided enough information to let you see some thing I’m missing and you guys will help me out with it.