sprintf re-entry into 64bit operation in 32 bit MCU with interrupts

拈花ヽ惹草 提交于 2020-01-26 04:43:06

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!