Как вы справляетесь с большими объемами передачи данных во встроенных системах с очень ограниченным объемом памяти? - PullRequest
6 голосов
/ 11 декабря 2008

У меня есть микроконтроллер, который должен загрузить большой файл с последовательного порта ПК (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.

Ответы [ 4 ]

4 голосов
/ 11 декабря 2008

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

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

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

4 голосов
/ 11 декабря 2008

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

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

3 голосов
/ 11 декабря 2008

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

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

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

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

1 голос
/ 11 декабря 2008

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...