Перейти к содержанию
    

STM32H7 поведение буфера при передаче в функцию

Есть данные в флеш-памяти, хочу считать их и распихать по полям глобально объявленного экземпляра структуры. Написал для этого функцию, которую вызываю вот так:

__attribute__((at(0x20000100))) uint8_t rx_data_QSPI[FLASH_PROGRAM_SIZE];

ReadFirmwareInfo(&hqspi, rx_data_QSPI, sizeof(rx_data_QSPI), &CommonFirmwareInfo);

Реализация функции:

Спойлер
uint8_t ReadFirmwareInfo(QSPI_HandleTypeDef *h_FLASHqspi,
                         uint8_t *pArrayRX_dataQSPI,
                         uint32_t bufQSPI_size,
                         CommonFirmwareInfo_t *FirmwareInfoPtr)
{
  memset(pArrayRX_dataQSPI, 0xFF, bufQSPI_size); /// - обнуление массива, в который читается информация по QSPI;

  /// - чтение информации о прошивках из микросхемы флеш-памяти;
  int32_t res = MT25QL512ABB_ReadSTR_DMA(h_FLASHqspi,
                                         MT25QL512ABB_QPI_MODE,
                                         MT25QL512ABB_4BYTES_SIZE,
                                         pArrayRX_dataQSPI,
                                         START_ADDR_FIRMWARE_INFO,
                                         bufQSPI_size);
  
  /// - проверка результата чтения из флеш-памяти;
  if (res == MT25QL512ABB_ERROR)
  {
    return ERROR_READ_FIRMWARE_INFO;
  }

  /* ЗАКОММЕНТИРОВАНО!!! */
  //uint8_t locbufQSPI[bufQSPI_size];
  //memset(locbufQSPI, 0xFF, sizeof(locbufQSPI)); /// - обнуление массива, в который читается информация по QSPI;
  //memcpy(locbufQSPI, pArrayRX_dataQSPI, bufQSPI_size);

  /// - заполнения структуры с информацией о прошивках из прочитанного массива;
  uint8_t res_des = DeserializeSystemData(pArrayRX_dataQSPI, bufQSPI_size, FirmwareInfoPtr);
  
  /// - проверка КС дес. массива;
  if (res_des != true)
  {
    return ERROR_READ_FIRMWARE_INFO;
  }

  return SUCCESSFUL_READ_FIRMWARE_INFO;
}

static uint8_t DeserializeSystemData (const uint8_t *localbuf,
                                      uint32_t bufQSPI_size,
                                      CommonFirmwareInfo_t *FirmwareInfoPtr)
{
  uint16_t Index = 0; /// - определение переменной Index, которая является индексом десериализуемого массива;

  FirmwareInfoPtr->Firmware_info_1.start_address |= (localbuf[Index+0] << 24) & 0xFF000000;
  FirmwareInfoPtr->Firmware_info_1.start_address |= (localbuf[Index+1] << 16) & 0xFF0000;
  FirmwareInfoPtr->Firmware_info_1.start_address |= (localbuf[Index+2] << 8)  & 0xFF00;
  FirmwareInfoPtr->Firmware_info_1.start_address |= (localbuf[Index+3] << 0)  & 0xFF;
  Index += sizeof(FirmwareInfoPtr->Firmware_info_1.start_address);

  FirmwareInfoPtr->Firmware_info_1.stop_address |= (localbuf[Index+0] << 24) & 0xFF000000;
  FirmwareInfoPtr->Firmware_info_1.stop_address |= (localbuf[Index+1] << 16) & 0xFF0000;
  FirmwareInfoPtr->Firmware_info_1.stop_address |= (localbuf[Index+2] << 8)  & 0xFF00;
  FirmwareInfoPtr->Firmware_info_1.stop_address |= (localbuf[Index+3] << 0)  & 0xFF;
  Index += sizeof(FirmwareInfoPtr->Firmware_info_1.stop_address);

  FirmwareInfoPtr->Firmware_info_1.last_pack_size = localbuf[Index];
  Index += sizeof(FirmwareInfoPtr->Firmware_info_1.last_pack_size);
  
  // И ТАК ДАЛЕЕ
}

 

 В таком виде функция заполнит экземпляр структуры не полностью:

Спойлер

image.png.1d77533f095fcabaff9b226aec0dc458.png

Но если пройти пошагово в отладчике по этой функции или поставить точку останова сразу после строчки int32_t res = MT25QL512ABB_ReadSTR_DMA..., а потом продолжить выполнение или раскомментировать 3 строчки после /* ЗАКОММЕНТИРОВАНО!!! */, то заполняется правильно (видно инкремент во всех полях):

Спойлер

image.png.7c732665bb3ba3f2bc4ee469fdae8667.png

Не могу понять в чем дело, указатель на массив вроде передал правильно (смотрел примеры на этом форуме), читает данные из памяти в массив rx_data_QSPI всегда правильно. Не посоветуете в чем тут может быть дело? Буду признателен за любые советы и критику (за конструктивную так особенно).

Изменено пользователем Turgenev

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

25 minutes ago, EdgeAligned said:

Для чтения используете DMA? Ттгда он просто не успевает передать данные

Точно

И не видно callback по завершению DMA

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

5 minutes ago, Allregia said:

Зачем здесь вообще DMA, если все равно ждать окончания передачи?

Какая разница зачем. Захотел и сделал.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Самое смешное (удивительное и чудесное), что эту "информацию о прошивках" можно не перекопировать в SRAM, а читать прямо из флеша. Это ведь константные данные, так ведь? Ну так и пусть они остаются в неизменяемой части, во флеше. И сделать УКАЗАТЕЛЬ на структуру, который накладывается на заданную область памяти, как ящик-шаблон, и эта область делится на "отсеки", как прописано в структуре. Таким образом, хранится только указатель типа "структура", этому указателю присваиваем адрес начала блока с данными, и производим вычитывание данных по указателю на структуру через ptr->xxx. Это работает аналогично тому, как сделано с GPIOA->ODR. 
Пардон, забыл, что флеш-то - внешняя, через SPI! 🙂 Сорян, тогда коммент отменяется (считать недействительным)

Изменено пользователем EdgeAligned

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

6 часов назад, Turgenev сказал:
  Скрыть контент
FirmwareInfoPtr->Firmware_info_1.start_address |= (localbuf[Index+0] << 24) & 0xFF000000;
  FirmwareInfoPtr->Firmware_info_1.start_address |= (localbuf[Index+1] << 16) & 0xFF0000;
  FirmwareInfoPtr->Firmware_info_1.start_address |= (localbuf[Index+2] << 8)  & 0xFF00;
  FirmwareInfoPtr->Firmware_info_1.start_address |= (localbuf[Index+3] << 0)  & 0xFF;
  Index += sizeof(FirmwareInfoPtr->Firmware_info_1.start_address);

  FirmwareInfoPtr->Firmware_info_1.stop_address |= (localbuf[Index+0] << 24) & 0xFF000000;
  FirmwareInfoPtr->Firmware_info_1.stop_address |= (localbuf[Index+1] << 16) & 0xFF0000;
  FirmwareInfoPtr->Firmware_info_1.stop_address |= (localbuf[Index+2] << 8)  & 0xFF00;
  FirmwareInfoPtr->Firmware_info_1.stop_address |= (localbuf[Index+3] << 0)  & 0xFF;
  Index += sizeof(FirmwareInfoPtr->Firmware_info_1.stop_address);

Ужас конечно. Кровь из глаз... :suicide2:   Понимаю теперь почему современные программы имеют такие невменяемые размеры.....

ТС, ваш CPU умеет команду REV! Советую наконец-то открыть и почитать мануал на ваш процессор.

 

И на кой интересно rx_data_QSPI прибит гвоздями к абсолютному адресу??

 

4 часа назад, EdgeAligned сказал:

Для чтения используете DMA? Ттгда он просто не успевает передать данные

Посещали курсы телепатов? Или вы телепат-любитель?   :sarcastic:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 часа назад, EdgeAligned сказал:

Для чтения используете DMA? Ттгда он просто не успевает передать данные

Да, вы правы, забыл его мониторить при выполнении функции, хотя колбек и флаги заведены.

10 минут назад, jcxz сказал:

Ужас конечно. Кровь из глаз...

Претензии только к размеру? Про REV обязательно почитаю.

11 минут назад, jcxz сказал:

И на кой интересно rx_data_QSPI прибит гвоздями к абсолютному адресу??

В проекте есть еще SPI DMA, который не работает , если линковщик все разместит в DTCM и наоборот: MDMA не заработает, если все разместить в AXI SRAM.

 

В примере моего кода есть функция DeserializeSystemData. Она раскладывает значения массива по полям экземпляра структуры шагая по адресам, где находится массив.

Если выполнять обратную операцию, укладывая значения экземпляра структуры в массив, который создается в этой функции сериализации, размером, также переданным в функцию, то как компилятор понимает сколько памяти выделить массиву, если его размер не известен, пока не вызовется функция? Просто ошибок компилятор не выдает и позволяет так сделать, но результат не понятный. 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

58 минут назад, jcxz сказал:

Понимаю теперь почему современные программы имеют такие невменяемые размеры.....

Эт верно! 🙂 На смартфоне установлены только самые необходимые приложения, и они занимают нынче аж 28 ГБ! Чем больше памяти у смартфонов, тем больше места занимают ровно те же самые приложения, которые раньше весили гораздо меньше.

 

1 час назад, jcxz сказал:

Посещали курсы телепатов? Или вы телепат-любитель?

Неее, я просто вспоминаю свои косяки, всякое случалось. Но я подключал лог.анализатор, рылся в мануалах.

48 минут назад, Turgenev сказал:

если линковщик все разместит в DTCM и наоборот:

Верно. DTCM - data tightly coupled memomy, область памяти для наикратчайшего и быстрого доступа со стороны ядра. Обычно эту область используют для текущих быстрых вычислений, а не для хранения редкоиспользуемых данных.

Но линковщику можно указывать не жесткий адрес, а секции памяти, которые были созданы в ld-скрипте. И при размещении переменной указывается секция через __attribute__((section("Xxxx")))

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

15 hours ago, Turgenev said:

В проекте есть еще SPI DMA, который не работает , если линковщик все разместит в DTCM и наоборот: MDMA не заработает, если все разместить в AXI SRAM.

Опять то же самое, размещение данных в памяти по нужным адресам. Вроде, неделю назад обсуждали, и ссылки на доки Кейла был, где всё это описаны и показаны примеры.

14 hours ago, EdgeAligned said:

секции памяти, которые были созданы в ld-скрипте.

У ТС Кейл.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

52 minutes ago, tonyk_av said:

Вроде, неделю назад обсуждали, и ссылки на доки Кейла был, где всё это описаны и показаны примеры.

Рыбки гуппи помнят 1 день только

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

16 часов назад, Turgenev сказал:

Претензии только к размеру? Про REV обязательно почитаю.

Почти к каждой строчке. Вы разве сами не замечаете, что там понаписали?

Начиная от:

memset(pArrayRX_dataQSPI, 0xFF, bufQSPI_size); /// - обнуление массива, в который читается информация по QSPI;

Зачем вообще какое-то "обнуление"? Почему ложь в комменте?

Также на кой задавать такие вопросы и не выкладывать описание ВСЕХ используемых типов данных и функций? И описание начальных значений переменных, с которыми что-то делаете в коде? Вы здесь телепатов ищете, которые должны всё это угадать?

Смотрите на свой пост и на каждой строчке пробуйте включать мозг.

16 часов назад, Turgenev сказал:

В проекте есть еще SPI DMA, который не работает , если линковщик все разместит в DTCM и наоборот: MDMA не заработает, если все разместить в AXI SRAM.

И что? Вопросы про компоновку в заданные адреса тут обсасывались уже многократно. И в очередной раз - совсем недавно. Попробуйте быть не только "чукчей-писателем".

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

11 minutes ago, jcxz said:

Вы разве сами не замечаете, что там понаписали?

Не волнуйтесь. Мало ли говнокода на планете Земля. Одним больше, одним меньше.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Раньше это называлось "индусский код", который, согласно преданию, нужно было петь и танцевать, и чем больше строчек кода, тем длиннее индийский сериал 🙂 

Лично я бы не делал отдельной фукнции под названием "ReadFirmwareInfo()", поскольку по смыслу она равносильна универсальной функции, выполняющей чтение из внешней флеши из указанного адреса в указанный адрес SRAM. Поэтому, здесь должна быть универсальная функция чтения ReadFromExtFlash(source_address, destination_address, size), как бы вот и всё. То есть, не делать индусского кода. (что такое индусский код, можно загуглить в википедии).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...