Защита заполнения буфера, считываемого из SRAM в STM32F429I

Я пытаюсь прочитать буфер из системы шин с помощью stm32F4 при падающем прерывании. Проблема в том, что мне нужно обработать данные в основном цикле, и мне не нужна задержка. Падающее прерывание происходит через 500 нс, и я не хочу пропустить какие-либо данные. Поэтому отключение разрешения прерывания здесь не принесет пользы.

Я ищу способ уменьшить задержку и не пропустить ни одного прерывания. Вот мой подход:

В основном цикле:

    while (1)
    {
        if (iowr_set)
        {
            iowr_set = 0;
              for (int i = 0; i < BUFFER_SIZE; i++)
              {
                  processData(aRxBuffer[i]);
              }

        }
}

Прерывать:

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {


    if (GPIO_Pin == GPIO_PIN_6) { // IORD

        HAL_SRAM_Read_16b(&hsram1, (uint32_t *)(SRAM_BANK_ADDR + WRITE_READ_ADDR), aRxBuffer, BUFFER_SIZE);

        iowr_set = 1;
    }
}

Декларации:

#define BUFFER_SIZE         ((uint32_t)0x0100)
#define WRITE_READ_ADDR     ((uint32_t)0x0800)

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
SRAM_HandleTypeDef hsram1;
FMC_NORSRAM_TimingTypeDef SRAM_Timing;

/* Read/Write Buffers */
volatile uint16_t aRxBuffer[BUFFER_SIZE];

Вы можете использовать два чередующихся буфера. Один считывается при обработке содержимого другого. Итак volatile uint16_t aRxBuffer[2][BUFFER_SIZE];

Weather Vane 19.05.2024 14:33

Если мои расчеты верны, то если вы запустите процессор на частоте 180 МГц (максимальная частота, поддерживаемая этим чипом), каждый такт составит ~5,5 нс. Это означает, что вы можете выполнить ~90 инструкций за 500 нс, если каждая инструкция занимает один такт. И за это время вам нужно прочитать и обработать 256 байт (или 64 uint32). Вы уверены, что это вообще возможно?

pmacfarlane 19.05.2024 18:55

@pmacfarlane Вы правы с анализом. Что мне следует сделать, чтобы решить эту проблему, пожалуйста? Я имел в виду обрабатывающую часть

Andre Ahmed 19.05.2024 19:27

@WeatherVane Что, если я обрабатываю только одну переменную, а не буфер, из-за ограничений обработки

Andre Ahmed 19.05.2024 19:35

@pmacfarlane Интересно, с учетом вашего анализа, что образец FMC_SRAM имеет 256 байт, и они выполняют одинаковую обработку, хотя без двойной буферизации...

Andre Ahmed 19.05.2024 19:39

То же самое: используйте альтернативные переменные, обычно стоит буферизовать данные между ISR и считывателем. Но как бы вы это ни делали, как пишет pmacfarlane, нужно уметь справляться с пропускной способностью. Я предполагаю, что чем больше данных вы читаете за одно прерывание, тем эффективнее оно будет: меньше прерываний (компенсируется типичной необходимостью свести к минимуму время отклика на прерывание).

Weather Vane 19.05.2024 19:39

@WeatherVane, а как насчет его анализа? поэтому мне следует увеличить buffer_size или уменьшить его

Andre Ahmed 19.05.2024 19:55

Это компромисс с другими частями программы. Как долго программа может терпеть отключенные прерывания? Могут быть и другие прерывания, которые должны работать. Но посмотрите на время, выбранное pmac. Как бы то ни было, вам нужно справиться с общей пропускной способностью данных. Если не получается, то нужно уменьшить скорость ввода данных.

Weather Vane 19.05.2024 20:02

@WeatherVane Я не могу уменьшить скорость входных данных, извините, но я не понял, что такое общая пропускная способность данных. Как я могу с этим справиться?

Andre Ahmed 19.05.2024 20:09

Вам необходимо прочитать и обработать 64 32-битных значения в 90 инструкциях. Я не знаю, что для вас означает «процесс», но даже прочитать значения за это время будет сложно. Вы могли бы развернуть цикл и, возможно, просто продолжать, предполагая, что вы вообще не обрабатывали. В принципе кажется, что это будет невозможно. Если вам нужна такая скорость передачи данных, вам нужен (намного) более быстрый MCU.

pmacfarlane 19.05.2024 20:24

Забудьте об обработке значений... Предполагая, что шина данных SRAM 16-битная (из HAL_SRAM_Read_16b), в лучших возможных обстоятельствах вы физически не можете передать 128 16-битных значений за 90 циклов HCLK. Таким образом, единственный способ, которым это вообще возможно, - это 32-битная шина, двойной буфер DMA от шины (без прерываний для ее перезапуска - не уверен, что это вообще возможно), каким-то образом избежать всех/почти всех внутренних задержек арбитража шины (отдельный код, процессор буфер и буфер DMA в SRAM1/2/3 и надейтесь на лучшее), а затем у вас осталось 90 циклов на обработку данных - так что, возможно, вы сможете выполнить xor их все, но не более того...

Andrey Turkin 19.05.2024 21:59

Нам нужно знать, как и чем заполняется SRAM. (например) В момент T1 SRAM начинает заполняться. В момент T2 SRAM заполнена и генерируется прерывание. Все это время между T1 и T2 тратится процессором впустую, когда он может получать данные. После Т2 заполнитель сразу же снова начинает заполнять байт 0? Если да, то это состояние гонки. Как наполнитель/отправитель и процессор руки синхронизируют процессы? Вы используете функцию *_16b HAL. *_32b может быть в два раза быстрее.

Craig Estey 20.05.2024 00:45

AFAICT, есть версия DMA: *_DMA. При его использовании циклы процессора, затраченные на передачу из SRAM в основную RAM, доступны для обработки данных, а не просто для их передачи. То есть обработка может перекрывать передачу. Но в лучшем случае скорость процессора находится на грани того, чтобы успевать обрабатывать данные, даже с учетом этих уловок/настроек.

Craig Estey 20.05.2024 00:49
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
13
111
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ваш STM32F429 может работать на максимальной тактовой частоте 180 МГц. Это означает, что, если предположить, что каждая инструкция занимает один такт, вы можете выполнить 180 инструкций за 1 мкс или 90 инструкций за 500 нс.

Ваша цель — обработать 256 байт за 500 нс или 64 32-битных слова. Значит, вам нужно уметь обрабатывать 64 слова в 90 инструкциях.

Давайте представим, что вы просто хотели за это время прочитать эти слова по памяти. Итак, давайте упростим ваш код до этого:

#include <stdint.h>

void read_data(uint32_t * data)
{
    for (int i = 0; i < 256 / sizeof(uint32_t); ++i)
    {
        volatile uint32_t datum = data[i];
        // No processing
    }
}

Может ли этот код прочитать 64 слова в 90 инструкциях? Возможно нет. Кажется, что такой наивный подход потребует около 4 инструкций на слово. https://godbolt.org/z/MarW37qvq

Вы могли бы развернуть цикл и, возможно, просто возможно, сможете читать данные из оперативной памяти с необходимой скоростью. Но это без какой-либо обработки.

Вдобавок ко всему, у вас есть вызов HAL_SRAM_Read_16b(), который сам по себе, вероятно, займет сотни, если не тысячи тактов. И вы используете прерывания, которые добавляют еще больше накладных расходов.

То, что вы пытаетесь сделать, в принципе невозможно. Вам придется снизить скорость передачи данных или смириться с отсутствием некоторых данных.

Другие вопросы по теме