Кольцевой буфер



Кольцевой буфер на ассемблере
Кольцевой буфер – это метод передачи данных в котором используется оперативная память фиксированного размера. В процессе передачи данных после заполнения последней ячейки памяти, запись начинается с первой ячейки, при этом старые данные перезаписываются, чтение из буфера происходит таким же образом, по замкнутому маршруту. Чтобы лучше понять, в каких случаях можно использовать кольцевой буфер, рассмотрим два примера:

1. Требуется равномерно передавать данные от источника к приемнику, без задержек, при этом время получения единицы данных (например, байта) от источника может сильно варьироваться (присутствует асинхронность работы источника и приемника). Источник может задержать выдачу данных из-за программных/аппаратных особенностей, задержка может появиться вследствие промежуточных вычислений в процессе передачи данных и т.д. Кольцевой буфер позволит избавиться от задержек, так как в запасе всегда будет находиться некоторое количество данных полученных от приемника. Для корректной работы буфера, должно соблюдаться следующее условие: средняя скорость получение данных от источника должна быть равна или выше скорости передачи данных на приемник.

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

Рассмотрим организацию кольцевого буфера в микроконтроллерах PIC. Память ОЗУ выделенную под кольцевой буфер, я делю на две равные части. Обе части буфера могут располагаться в одном банке ОЗУ, или в двух банках в целях увеличения объема буфера. На следующей картинке можно наглядно увидеть распределение памяти под кольцевой буфер в микроконтроллерах PIC:

Кольцевой буфер для PIC
Ниже представлен код программы с реализацией кольцевого буфера для варианта, где требуется равномерная передача данных от источника к приемнику:

Обращение к регистрам ОЗУ выполняется с помощью косвенной адресации, в начале программы задаются начальный (bnk_start) и конечный (bnk_end) адреса для обеих частей буфера, 1-я часть буфера расположена в 0-м банке ОЗУ, 2-я часть в 1-ом банке. Напомню что если буфер затрагивает регистры 2-го и 3-го банка, то в программе потребуется дополнительная манипуляция с битом IRP регистра STATUS, для правильного выбора банков памяти. Кроме этого в начале программы перечисляются вспомогательные регистры для работы с обработчиком прерываний. В подпрограмме обработки прерываний осуществляется извлечение данных из буфера для дальнейшего процесса передачи или обработки. Для того чтобы процесс был равномерным, прерывание генерируется по переполнению таймера. В основной программе происходит загрузка буфера данными, полученными от какого-либо источника.

В начале основной программы настраиваются внутренние регистры, а также таймер для обработчика прерываний. Сначала обе части буфера заполняются данными, полученными от источника. Далее выполняется переход на метку zapusk, где в регистр FSR_prer загружается адрес 1-го регистра 1-й половины буфера, после чего сбрасывается флаг занятости буферов flag,0. Эти действия выполняются однократно перед запуском таймера. После запуска таймера начинается круговой цикл передачи данных. Далее необходимо дополнительно проверить кнопки, флаги и т.д., сигнализирующие о необходимости остановки кругового цикла, иначе без этого программа уйдет в бесконечный цикл.

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

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

Данный алгоритм реализован в музыкальном звонке, где требуется равномерная загрузка модуля ШИМ данными, считанными с карты памяти, для получения неискаженного звука.

Последние записи:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *