Как вы справляетесь с передачей больших объемов данных во встроенных системах с очень ограниченным объемом памяти?

StackOverflow https://stackoverflow.com/questions/359745

Вопрос

У меня есть микроконтроллер, который должен загрузить большой файл из последовательного порта ПК (115200 бод) и записать его в последовательную флэш-память через SPI (~ 2 МГц).Запись флэш-памяти должна осуществляться блоками по 256 байт, которым предшествуют команда записи и адрес страницы.Общий объем оперативной памяти, доступной в системе, составляет 1 КБ с размером стека 80 байт.

В настоящее время это работает путем заполнения 256-байтового буфера из UART, а затем пинг-понга в другой 256-байтовый буфер, заполняемый прерыванием по сигналу готовности буфера RX, в то время как во флэш-память выполняется занятая запись.Замена буфера повторяется до завершения операции.

Я бы предпочел настроить обработчики прерываний TX/RX для портов SPI и UART, которые работают с отдельными кольцевыми буферами.Таким образом, вместо того, чтобы запрашивать новые байты и ждать завершения операций, я могу просто заполнить буферы TX и включить прерывание или проверить буферы на наличие входящих данных.Это дало бы гораздо больше тактов для реальной работы вместо ожидания периферийных устройств.

После реализации IRQ с 128-байтовыми кольцевыми буферами я опрашиваю буфер UART RX на наличие данных и немедленно помещаю их в буфер SPI TX для передачи файлов.Проблема, с которой я сталкиваюсь при таком подходе, заключается в том, что у меня недостаточно оперативной памяти для буферов, а приемный буфер ПК заполняется быстрее, чем я передаю данные во флэш-буфер передачи.Очевидно, что проблема не в скорости передачи (115,2 кГц на входе и 2 МГц на выходе), но после передачи каждой 256-байтовой страницы происходит ожидание цикла записи.


Похоже, что частые прерывания SPI блокировали некоторые прерывания UART и приводили к пропуску байтов.Решение, которое я выбрал, состояло в том, чтобы использовать кольцевой буфер для прерывания приема UART и подавать данные в страничный буфер размером 256 байт, который отправляется на последовательную флэш-память путем опроса передачи байтов и завершения записи.Кольцевой буфер на 128 пикселей достаточно велик, чтобы предотвратить переполнение во время записи SPI.

Это было полезно?

Решение

Я бы сделал что-то вроде скаттер-сборки на ПК.Создайте связанный список структуры следующим образом:

typedef struct data_buffer {
    char flags;
    char[128] data;
}

Один из битов флага означает «ReadyToFlash», а другой — «Flashing».У вас должна быть возможность настроить количество буферов в вашем связанном списке, чтобы флэш-память не перехватывала UART во время записи или наоборот.

Если флэш-память попадет в буферный блок, который не является «ReadyToFlash», он заглохнет, и вам потребуется, чтобы UART IRQ снова запустил его.Если UART доходит до блока «ReadyToFlash» или «Flashing», он заполняется слишком быстро, и вам, вероятно, понадобится другой буфер. Если у вас есть динамическая память, вы можете выполнить эту настройку во время выполнения и добавить буфер в список на лету. , в противном случае вам просто нужно будет провести эмпирическое тестирование.

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

Поддерживает ли UART и часть приложения для ПК квитирование связи RS-232 (управление потоком)?Если это так, когда ваш приемный буфер приближается к заполнению, попросите ISR отключить линию CTS - если сторона ПК настроена на соблюдение аппаратного управления потоком, она должна прекратить отправку, когда увидит это условие.Как только вы опустошите (или почти опустошите) буфер приема, снова установите CTS, и компьютер должен снова начать отправку.

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

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

Я предполагаю, что вы передаете двоичный файл, поэтому XON-XOFF — не лучшее решение, поскольку остается аппаратное управление потоком.

Другой вариант — использовать протокол со встроенным управлением потоком, например XModem.У меня есть аналогичный встроенный проект, где флэш-память записана на страницах по 128 байт.Какое совпадение, что XModem отправляет данные порциями по 128 байт, а затем ждет подтверждения, прежде чем отправить следующий.

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

Но вы хотите сказать, что это работало, когда у вас были блочные буферы, а теперь, когда у вас есть байтовые буферы, это не так?

Можете ли вы придерживаться буферов блоков, которые заполняются прерыванием UART RX, и, когда каждый буфер заполнен, передать его коду SPI/Flash для очистки этого буфера с помощью прерывания SPI?Это избавит вас от копирования каждого байта, и вместо того, чтобы дважды выполнять логику кольцевого буфера для каждого байта, вам придется делать это только для каждого блока.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top