问题
In reference to SO question: 52164135
The setup:
I have a function which converts many double
values into a predefined string. The input is a array of struct
from which we concatenate two double values into a string. A double is of size 8 bytes or 64 bits and my MCU of operation is STM32, a 32 bit ARM micro-controller.
An interrupt
is also running parallelly.
The data should look like:
[[12.11111111,12.11111111],[12.22222222,12.22222222],...]
But I get (very rarely):
[[12.11111111,12.11111111],[55.01[12.33333333,12.33333333],...]
Note: I missed out [12.22222222,12.22222222]
sprintf is not re-entrant:
According to this discussion, on AVRFreaks, sprintf is not re-entrant.
(The discussion is on using sprintf in a interrupt enabled hardware environment.) Which means if an interrupt occurs in-between a sprintf
operation the stack fails to continue the operation it was doing.
Since my MCU is a 32 bit one, to perform a 64 bit operation it will take two clock cycles. And if we assume an interrupt occurred in between the sprintf operation according the the above discussion sprintf
should fail.
Question
1. Will sprintf
fail in case it is interrupted?
Here is the string function, an interrupt routine also runs in the background which deals with other sensor data (local and global)
/* @brief From the array of GPS structs we create a string of the format
* [[lat,long],[lat,long],..]
* @param input The input array of GPS structs
* @param output The output string which will contain lat, long
* @param sz Size left in the output buffer
* @return 0 Successfully completed operation
* 1 Failed / Error
*/
int get_gps60secString(GPS_periodic_t input[GPS_PERIODIC_ARRAY_SIZE],
char *output, size_t sz)
{
int cnt = snprintf(output, sz, "[");
if (cnt < 0 || cnt >= sz)
return 1;
output += cnt;
sz -= cnt;
int i = 0;
for (i = 0; i < GPS_PERIODIC_ARRAY_SIZE; i++) {
cnt = snprintf(output, sz, "[%0.8f,%0.8f]%s",
input[i].point.latitude, input[i].point.longitude,
i + 1 == GPS_PERIODIC_ARRAY_SIZE ? "" : ",");
if (cnt < 0 || cnt >= sz)
return 1;
output += cnt;
sz -= cnt;
}
cnt = snprintf(output, sz, "]");
if (cnt < 0 || cnt >= sz)
return 1;
return 0; // no error
}
What's happening inside the interrupt routine
void GPS_InterruptHandler(UART_HandleTypeDef *UartHandle)
{
gps_UART_RxInterrupt_Disable();
GPS_t l_sGpsInfo;
memset(&l_sGpsInfo,0,sizeof(GPS_t));
status=Validate_get_gpsInfo((char*)g_gps_readBuff,&l_sGpsInfo,100);
MEMS_interruptHandler(); //Inertial sensor ISR
gps_UART_RxInterrupt_Enable();
}
回答1:
sprintf
will ony fail during an interrupt if it is called again during that interrupt (assuming it uses global variables that are re-used; would it use only stack variables, then it is re-entrant).
So if your interrupt handler is calling sprintf
and during that call a new, same or higher priority interrupt occurs then it can fail. However, during the processing of an interrupt, interrupts are normally disabled so there can't (shouldn't!) be another interupt of the same type occurring.
But why convert this raw data during interrupt handling? Why not store/pass this data to the user-level routine via a buffer and have that functionality convert the raw data? That would be consistent with the idea that an interrupt handler should be as short (fast) as possible.
来源:https://stackoverflow.com/questions/52388489/sprintf-re-entry-into-64bit-operation-in-32-bit-mcu-with-interrupts