cancel
Showing results for 
Search instead for 
Did you mean: 

Hardfault randomly when I do sprintf

Nickjmas
Associate III

Hello everyone,

I'm developing a firmware for an STM32F767 and I have a problem that happens randomly and I can't figure out why. From what I could analyze looking at the stack I think the problem comes when doing a sprintf and I have the hypothesis that it could be an overflow problem.

According to the fault analyzer, when the error is caught I have this context:

Hard Fault Details: Bus, memory management or usage fault (FORCED)

Bus Fault Details: Precise data access violation (PRECISERR) BFAR: 0x30333531

Register Content During Fault Exception:

  • sp(PSP): 0x20013480
  • r0: 0x30333531
  • r1: 0x0
  • r2: 0x18
  • r3: 0x20040fe0
  • r12: 0x819bc400
  • lr: 0x813dc81
  • pc: 0x813f6fa
  • xpsr: 0x2100000

It is curious since the BFAR and r0 register contains part of the value to be formatted by sprintf (the number is 15300), which further strengthens the hypothesis that there may be an overflow problem somewhere.

MPU and cache is used with the next configuration:

/* Configure the MPU attributes for the frontbuffer to normal memory (800px x 600px * 16bpp) */
	MPU_InitStruct.Enable = MPU_REGION_ENABLE;
	MPU_InitStruct.BaseAddress = 0xC0000000;
	MPU_InitStruct.Size = MPU_REGION_SIZE_2MB;
	MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
	MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
	MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
	MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
	MPU_InitStruct.Number = MPU_REGION_NUMBER1;
	MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
	MPU_InitStruct.SubRegionDisable = 0x00;
	MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
 
	HAL_MPU_ConfigRegion(&MPU_InitStruct);
 
	/* Configure the MPU attributes for the backbuffer to normal memory (800px x 600px * 16bpp) */
	MPU_InitStruct.Enable = MPU_REGION_ENABLE;
	MPU_InitStruct.BaseAddress = 0xC0200000;
	MPU_InitStruct.Size = MPU_REGION_SIZE_2MB;
	MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
	MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
	MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
	MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
	MPU_InitStruct.Number = MPU_REGION_NUMBER1;
	MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
	MPU_InitStruct.SubRegionDisable = 0x00;
	MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
 
	HAL_MPU_ConfigRegion(&MPU_InitStruct);
 
 
	/* Configure the MPU attributes as device for NOR (Strongly Ordered Memory) */
	MPU_InitStruct.Enable = MPU_REGION_ENABLE;
	MPU_InitStruct.BaseAddress = 0x60000000;
	MPU_InitStruct.Size = MPU_REGION_SIZE_256MB;
	MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS;
	MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
	MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
	MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
	MPU_InitStruct.Number = MPU_REGION_NUMBER3;
	MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
	MPU_InitStruct.SubRegionDisable = 0x00;
	MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
 
	HAL_MPU_ConfigRegion(&MPU_InitStruct);
 
	MPU_InitStruct.Enable = MPU_REGION_ENABLE;
	MPU_InitStruct.BaseAddress = 0x60000000;
	MPU_InitStruct.Size = MPU_REGION_SIZE_16MB;
	MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
	MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
	MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
	MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
	MPU_InitStruct.Number = MPU_REGION_NUMBER4;
	MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
	MPU_InitStruct.SubRegionDisable = 0x00;
	MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
 
	HAL_MPU_ConfigRegion(&MPU_InitStruct);
 
	MPU_InitStruct.Enable = MPU_REGION_ENABLE;
	MPU_InitStruct.BaseAddress = 0x20000000;
	MPU_InitStruct.Size = MPU_REGION_SIZE_512KB;
	MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
	MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
	MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
	MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
	MPU_InitStruct.Number = MPU_REGION_NUMBER5;
	MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
	MPU_InitStruct.SubRegionDisable = 0x00;
	MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
 
	HAL_MPU_ConfigRegion(&MPU_InitStruct);

I have tried increasing stacks, heaps and stacks of the task where the error occurs. But I am facing the same error.

I am currently using the standard c library which incorporates the latest version Atollic True Studio 9.3.0. Can you suggest what I can do or what I can check to see where the error is coming from?

Thank you in advance

Best regards

1 ACCEPTED SOLUTION

Accepted Solutions

Look at disasm at and before address pc: 0x813f6fa . Which function is it in?

Do you use RTOS? If yes, don't use printf(), it's not reentrant. (I mean, generally, using printf() in microcontrollers is something which should be considered twice and then rejected).

JW

View solution in original post

10 REPLIES 10
KnarfB
Principal III

Is the sprintf buffer large enough? Can you make it static (to remove it from the stack)?

Besides, your code says twice MPU_REGION_NUMBER1, copy&paste error?

hth

KnarfB

Hi KnarfB

thank you for your suggestions. About buffer used, it is static and has enought size to show the data (100 bytes).

About the MPU configuration, you are in true, I have twice MPU_REGION_NUMBER1 and source is wrong. I will fix and I will try again.

Best regards

Even though not likely your issue (if your buffer really is large enough), use snprintf() instead of sprintf(). It prevents any possible buffer overrun.

You don't show to sprintf() call that generated the fault. Are you trying to print floats?

Look at disasm at and before address pc: 0x813f6fa . Which function is it in?

Do you use RTOS? If yes, don't use printf(), it's not reentrant. (I mean, generally, using printf() in microcontrollers is something which should be considered twice and then rejected).

JW

TDK
Guru

sprintf/printf calls malloc under the hood. Likely the malloc call is failing, or returning a bogus address. Source code would be good to see.

If you feel a post has answered your question, please click "Accept as Solution".

Hi Bob S,

thank you for you suggestions. I wasn't clear in my main question and I forget say that I was using snprintf to avoid overrunt the buffer. Also I add null termination at the end of this buffer.

This is the snprintf where the fault is generated and yes, I try to format print floats.

void WEITSK_Format(float weight, uint8_t dp, char *str_unit,  char *msg, uint32_t size_msg) {
		
	snprintf(msg, size_msg, "%.*f %s", dp, weight, str_unit);
 
	/* Ensure has null termination */
	msg[size_msg - 1] = 0;
}

Hi wacakwek.jan,

thank you for you comments. The fault fall between Balloc and Bfree functions (see picture)


_legacyfs_online_stmicro_images_0693W00000dDgdHQAS.pngI'm using FreeRTOS with #define configUSE_NEWLIB_REENTRANT 0 because I'm using C standar library (no newlib). Analyzing the Call Stack, what I undertand is the standard C library is using reentrant functions since the most of them have the "_r" ending.

0x0813DC89 - _dtoa_r (Where the fault is triggered)

0x0813F702 - _Balloc

0x0813FD27 - __2db

0x0813DC89 - _dtoa_r

0x081404D3 - __ssprint_r

0x0813A6B5 - __ssvfscanf_r

Do you suggest use any alternative to format float values without using the standar library?

Best regards

When printing floats, printf does use malloc as @TDK​ mentioned. And malloc() is not re-entrant unless you take specific steps to make it so (newer versions of CubeMX/IDE make this easier but not foolproof). So malloc() is probably the failure point as @Community member​ said.

Even though you see the functions with trailing _r, if you don't define configUSE_NEWLIB_REENTRANT then FreeRTOS doesn't make space for the reentrant structure in its task blocks (I think - need to verify this). No matter WHICH library you are using (clib or newlib).

[EDIT] And using floating point in multiple tasks has its own set of pitfalls.

I agree with you that the problem probably comes when doing a malloc when trying to printf a float value. @Community member​  link is very interesting, I think it's vitally important to apply the changes he mentions so that the system is consistent.

In addition, after review a project configuration I was wrong (and a litle confused) and it is using newlib library. Then, as you said, I need config FreeRTOS with configUSE_NEWLIB_REENTRANT to work properly with reentrant structs.

I will made this changes and I will keep you updated.

Thank you for yours comments