c - sprintf 在 32 位 MCU 中通过中断重新进入 64 位操作

标签 c arm embedded

引用SO问题:52164135

设置:
我有一个函数可以将许多 double 值转换为预定义的字符串。输入是一个结构数组,我们将两个 double 值连接成一个字符串。 double 的大小为 8 字节或 64 位,我的操作 MCU 是 STM32,一个 32 位 ARM 微 Controller 。
中断也在并行运行。

数据应如下所示:

[[12.11111111,12.11111111],[12.22222222,12.22222222],...]

但我得到(很少):

[[12.11111111,12.11111111],[55.01[12.33333333,12.33333333],...]

注意:我错过了[12.22222222,12.22222222]

sprintf 无法重新进入:
据此discussion ,在 AVRFreaks 上,sprintf 不可重入。(讨论的是在支持中断的硬件环境中使用 sprintf。)这意味着如果在 sprintf 之间发生中断> 操作堆栈无法继续其正在执行的操作。

由于我的 MCU 是 32 位的,因此执行 64 位操作需要两个时钟周期。如果我们根据上面的讨论假设 sprintf 操作之间发生了中断,sprintf 就会失败。

问题
1.sprintf如果被中断会失败吗?

这是字符串函数,中断例程也在后台运行,处理其他传感器数据(本地和全局)

/* @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
}

中断例程内部发生了什么

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();
}

最佳答案

sprintf 只有在中断期间再次调用它才会失败(假设它使用可重复使用的全局变量;如果它仅使用堆栈变量,那么它是可重入的) )。

因此,如果您的中断处理程序正在调用 sprintf,并且在该调用期间发生新的、相同或更高优先级的中断,那么它可能会失败。然而,在处理中断期间,中断通常被禁用,因此不能(不应该!)发生另一个相同类型的中断。

但是为什么要在中断处理期间转换这些原始数据呢?为什么不通过缓冲区将此数据存储/传递到用户级例程并让该功能转换原始数据?这与中断处理程序应尽可能短(快)的想法是一致的。

关于c - sprintf 在 32 位 MCU 中通过中断重新进入 64 位操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52388489/

相关文章:

c++ - 复制命令/Powershell 窗口屏幕缓冲区

java - Java 中的 TCP 客户端和 C 中的服务器

gcc - 交叉编译 : GCC ignores --sysroot

assembly - 使用单个 aarch64 指令获取余数?

c - 在没有填充的情况下处理 C 中的位数组

c++ - OOP可以在嵌入式C中使用吗?

c - 如何使用 RSA 加密/解密长输入消息? [OpenSSL, C]

c - fread() 在不同的字节序机器上表现不同吗?

c - 使用 Newlib 实现 write()、_write() 或 _write_r()?

rust - 如果将结构 move 到不同的位置,Rust 中是否有任何特性会得到通知?