2024-03-12 11:20 AM
Hello,
I'm encountering an issue where the printf function is providing an incorrect output for float or double values. The simplified code snippet causing this problem is as follows:
float f = 0.33;
printf("d:%4.2f;\r\n", f);
Upon analyzing the output using a logic analyzer, I initially observe the two bytes \xF0 \x87 followed by "0.33;\r\n", indicating that the "d:" prefix is not matching as expected.
I'm using a STM32L432KCU microcontroller with STM32CubeIDE version 1.14.0. The option to utilize floats with printf is enabled in the settings.
Would appreciate any insights or suggestions to resolve this issue.
Kind Regards
Lutz
2024-03-12 12:36 PM
This is a topic that's been addressed multiple times. Seem to recall you need to be pulling the right library too.
2024-03-12 12:58 PM
The default Newlib-nano library bundled with CubeIDE ARM toolchain does not support printing floats and some other types. Please refer to CubeIDE user guide.
2024-03-12 01:12 PM - edited 2024-03-13 02:38 AM
yes right, it has been reported several times, also that the stack memory is not the right size etc.
But what I notice is that it doesn't crash the first time, but displays the first two characters incorrectly the first time
On the second call the crash occurs
Now I have tested further and the lines
for (int n=0;n<samplenum;n++){
int len=sprintf(ch_buffer, "d:%7.5lf;%7.5lf;%d\r\n",tx_sin[n],tx_cos[n],tx_ref[n]);
if(len!=0){HAL_UART_Transmit(&huart2, (uint8_t *)ch_buffer, len, 100);}
}
the arrays are up to 800 elements in size. Regardless of whether the call runs from 0 to 99 or from 0 to 799, the first call for this loop works, i got the right data at the UART and i have no crash.
The second call of the loop also crashes.
All this does not fit into the picture I have read so far. I have understood that it does not work at all. What would be the right library, if I knew that I would have used it and not asked here.
But nevertheless it has to be said that the reports on errors with printf and float are 5 years old and older. As I understand it, they all report a crash, not that it sometimes works.
I hadn't noticed from the reports that it sometimes works, very often and then again not on the second call. That's why I asked.
2024-03-13 04:03 PM
The printf in newlib library needs working malloc and also is involved with multi-threading support (even if you don't use it). One of recent toolchains was broken IIRC. Use the latest toolchain of CubeIDE 1.14.1, or older ones (v. 9, 10). Or, find alternative printf, or make your own float formatting function with ecvt(), fcvt().
2024-03-13 11:33 PM - edited 2024-03-14 02:52 AM
Hallo, thank you very much for your advice
I recently ran an update, I have version 1.14.1 and the GNU tools are now "GNU Tooles for STM32 (12.3rel1)", which was previously 11
Are these the latest ones or should I install something else
it should then work or do I have to do something else
because I have the problem that the first call of the function "sendCalASCII" works and sends the data to the PC as intended, no matter if smplenum is 100 or 800
The second call I have the crash with the function "sprintf"
if anyone is surprised that
HAL_ADC_Start_DMA(&hadc1, (uint16_t*)buffer, 4);
is located after lines 12, 13, this is supposed to be the case because work is then carried out in parallel
But if anyone has a better idea then let me know
int sendCalASCII(uint16_t samplenum){
double sin[7]={0};
double cos[7]={0};
int ref=0;
HAL_ADC_Stop_DMA(&hadc1);
for(int i=0;i<4;i++){buffer[i]=1980;}
for (int n=0;n<samplenum;n++){
//HAL_ADC_Start_DMA(&hadc1, (uint16_t*)buffer, 4);
//HAL_Delay(1);
ref=(TIM1->CNT);
sin[1]=0.001*((buffer[0]+buffer[3])/2-1980);
cos[1]=0.001*((buffer[1]+buffer[2])/2-1980);
HAL_ADC_Start_DMA(&hadc1, (uint16_t*)buffer, 4);
sin[0]=coeff[10]; //zuweisen der Konstanten
cos[0]=coeff[21]; //zuweisen der Konstanten
for (int i=2;i<=6;i++){
sin[i]=sin[i-1]*sin[1]; // da es für jeden messwert aufgerufen wird sollte es so am schnellsten sein
cos[i]=cos[i-1]*cos[1];
}
sin[0] += sin[1]*coeff[0] + cos[1]*coeff[1];
sin[0] += sin[3]*coeff[2] + cos[3]*coeff[3];
sin[0] += sin[5]*coeff[4] + cos[5]*coeff[5];
sin[0] += sin[6]*coeff[6] + cos[6]*coeff[7];
sin[0] += sin[3]*cos[3]*coeff[8];
sin[0] += sin[5]*cos[5]*coeff[9];
cos[0] += sin[1]*coeff[11] + cos[1]*coeff[12];
cos[0] += sin[3]*coeff[13] + cos[3]*coeff[14];
cos[0] += sin[5]*coeff[15] + cos[5]*coeff[16];
cos[0] += sin[6]*coeff[17] + cos[6]*coeff[18];
cos[0] += sin[3]*cos[3]*coeff[19];
cos[0] += sin[5]*cos[5]*coeff[20];
tx_sin[n]=sin[0];//*100000;
tx_cos[n]=cos[0];//*100000;
tx_ref[n]=ref*10000;
}
printf("CAL\r\n");
printf("%d\r\n",samplenum);
for (int n=0;n<samplenum;n++){
//Format d: sin;cos;ref\n
//int len=sprintf(ch_buffer,"d:%d;%d;%d\r\n",tx_sin[n],tx_cos[n],tx_ref[n]);
int len=sprintf(ch_buffer,"d:%7.5lf;%7.5lf;%d\r\n",tx_sin[n],tx_cos[n],tx_ref[n]);
if(len!=0){HAL_UART_Transmit(&huart2, (uint8_t *)ch_buffer, len, 100);}
}
printf("END\r\n");
return 0;
}
2024-03-14 03:55 AM
I have not tested toolchain 12.3 yes but it is supposed to be good (no complaints heard recently). Your code looks quite involved and has DMA. Can you make a small focused test without ADC and DMA, just to verify printf and sprintf?
2024-03-14 04:47 AM
yes good idea, I hadn't tried it yet. I understand the background when two things process large amounts of memory that something can go wrong.
I have commented out DMA and tested it, unfortunately the same behavior, in the code line 48 int len=sprintf... the program jumps to the error handler
void HardFault_Handler(void)
{
/* USER CODE BEGIN HardFault_IRQn 0 */
/* USER CODE END HardFault_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_HardFault_IRQn 0 */
/* USER CODE END W1_HardFault_IRQn 0 */
}
}