sprintf повторный вход в 64-битную операцию в 32-битном MCU с прерываниями - PullRequest
0 голосов
/ 18 сентября 2018

По вопросу SO: 52164135

Настройка :У меня есть функция, которая преобразует многие double значения в предопределенную строку.Вводом является array of struct, из которого мы объединяем два двойных значения в строку.Дабл имеет размер 8 байт или 64 бита, и мой MCU - STM32, 32-битный микроконтроллер ARM.interrupt также работает параллельно.

Данные должны выглядеть следующим образом:

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

Но я получаю (очень редко):

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

Примечание: я пропустил [12.22222222,12.22222222]

sprintf не возвращается t:Согласно этому обсуждению для AVRFreaks, sprintf is not re-entrant. (речь идет об использовании 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();
}

1 Ответ

0 голосов
/ 18 сентября 2018

sprintf потерпит неудачу только во время прерывания, если он будет вызван снова во время этого прерывания (при условии, что он использует глобальные переменные, которые используются повторно; если он будет использовать только переменные стека, то он будет повторно введен).

Таким образом, если ваш обработчик прерываний вызывает sprintf и во время этого вызова возникает новое прерывание с таким же или более высоким приоритетом, то оно может дать сбой.Однако во время обработки прерывания прерывания обычно отключаются, поэтому не может быть (не должно быть!) Другого прерывания того же типа.

Но зачем преобразовывать эти необработанные данные во время обработки прерывания?Почему бы не сохранить / передать эти данные в подпрограмму уровня пользователя через буфер и сделать так, чтобы эти функции преобразовывали необработанные данные?Это согласуется с идеей, что обработчик прерываний должен быть максимально коротким (быстрым).

...