|
|
  |
Циклический буфер на AVR, (Примеры применения) |
|
|
|
Aug 29 2007, 12:13
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(SasaVitebsk @ Aug 29 2007, 10:05)  Я вот всё больше и больше склоняюсь к мысли что необходимо унифицировать некоторые узлы и блоки, процедуры процессоронезависимые и даже переменные и структуры.
Прошу прощения за отход от темы может кто посоветует хорошую книгу в данной области. То есть что-то по типу визуализации/структурирования. Даже не знаю как назвать эту область. Короче выработки единого подхода к написанию прог на Си. Попробуйте вот эту книжку: Ван Тассел Д. Стиль, разработка, эффективность, отладка и испытание программ: Пер. с англ. , 1981. Много ценных мыслей, в своё время очень мне помогла систематизировать программирование, как вид деятельности.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Aug 31 2007, 12:37
|
Участник

Группа: Участник
Сообщений: 44
Регистрация: 30-03-06
Пользователь №: 15 598

|
Вот одна из возможных реализаций. Имеется индекс чтения, количество занятых ячеек, флаг состояния переполнения и сам буфер. Запрет прерывания при чтении нужен, если запись в буфер происходит в прерываниях. Внимание! Программа не тестировалась в реальной работе. Если есть косяки, буду признателен за поправки. Опыт работы с AVR очень маленький. Код .dseg
.equ BUF_SIZE = 64 ; размер буфера, может быть n^2 <= 256
buf: .byte 3 + BUF_SIZE; счетчик занятых ячеек, индекс чтения, состояние буфера, буфер
.cseg
;------------------------------------------------ init_buf: ;------------------------------------------------ ; инициализация буфера ; используются r16, r28, r29
; в Y адрес структуры, задающей буфер mov YL, LOW(buf) mov YH, HIGH(buf) clr r16 std Y, r16 std Y+1, r16 std Y+2, r16 ret
;------------------------------------------------ write_buf: ;------------------------------------------------ ; в r16 байт для записи ; используются регисты r17, r18, r28, r29
; в Y адрес структуры, задающей буфер mov YL, LOW(buf) mov YH, HIGH(buf)
; если буфер полный не записывать, установить флаг переполнения ld r17, Y cpi r17, BUF_SIZE - 1 brcs L1 ldi r17, 1 std Y+2, r17 ret L1: ; определить индекс для записи ; i = (rindex + count) & (BUF_SIZE - 1) ld r18, Y + 1 add r18, r17 andi r18, BUF_SIZE-1 ; увеличить счетчик занятых ячеек в буфере ; count++ inc r17 st Y, r17
; buf[i] = data; clr r17 add YL, r18 adc YH, r17 std Y+3, r16 ret
;------------------------------------------------ read_buf: ;------------------------------------------------ ; возвращает байт в r16 ; используются регисты r16, r17, r28, r29
; в Y адрес структуры, задающей буфер mov YL, LOW(buf) mov YH, HIGH(buf)
; c = buf[rindex] ldd r16, Y+3
cli
; count-- ld r17, Y dec r17 st Y, r17 ; rindex = (rindex + 1) & BUF_SIZE - 1 ldd r17, Y+1 dec r17 andi r17, BUF_SIZE-1 std Y+1, r16 sei ret
Сообщение отредактировал alcosar - Aug 31 2007, 12:40
|
|
|
|
|
Aug 31 2007, 15:12
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(alcosar @ Aug 31 2007, 11:37)  Код ; в Y адрес структуры, задающей буфер mov YL, LOW(buf) mov YH, HIGH(buf) ; c = buf[rindex] ldd r16, Y+3 Здесь логическая ошибка, вы всё время читаете из одной и той же ячейки памяти. Идея сделать отдельный счётчик на заполнение буфера мне кажется здравой, надо обдумать на досуге. Для загрузки непосредственных данных в регистр применяется команда ldi, а не mov.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Aug 31 2007, 18:37
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(prottoss @ Aug 31 2007, 19:53)  Пара вопросов:
1.Сколько памяти программ и памяти данных занимает код с циклическими буферами для USART?
2.Почему во всех приведенных кодах процедуры чтения-записи из-в буферЫ нет команд запрета прерываний от обработчиков приема-окончания-передачи USART? 1. Вы же видите - очень мало. Но не это главное. Циклический буфер позволяет работать с максимальной производительностью и абсолютно отделяет работу с внешним устройством от интерфейса. Это можно использовать в любом месте. Например в последней теме у меня два таких буфера. 1-UART, 2-EEPROM. 2. В этом есть особый смысл.  Классическая структура буфера - сам буфер+2переменных. Указатель на голову и указатель на хвост. Представим себе приём. В прерывании используется только хвост(добавляются символы), а в main только голова буфера (забираются данные). Есть ещё один приятный момент. Если работаешь с подтверждениями (например CRC), то тоже имеется огромный плюс. Представьте кольцевой буфер и три указателя. Первых два я описал, а третий - указатель на недостоверные данные. Таким образом всё работает тем же способом, а по принятию решения (сравнение CRC) указатель на хвост присваивается либо указателю на принятые недостоверные данные (данные верны) либо наоборот указателю на недостоверные данные присваивается указатель на хвост (данные неверны и пакет требуется повторить). Никаких дополнительных средств и инструментов не требуется. 2 GM сенькую именно такую книгу искал (в смысле задача стоит именно как вы и написали). Сейчас буду искать саму книгу.
|
|
|
|
|
Aug 31 2007, 18:57
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Цитата(SasaVitebsk @ Sep 1 2007, 02:37)  1. Вы же видите - очень мало. Но не это главное. Циклический буфер позволяет работать с максимальной производительностью и абсолютно отделяет работу с внешним устройством от интерфейса. Это можно использовать в любом месте. Например в последней теме у меня два таких буфера. 1-UART, 2-EEPROM. В полезности циклических буферов я нисколько не сомневаюсь  и сам оччень часто их применяю. НО, очень мало, это сколько?  допустим применительно к АВР и его USART. Просто не вижу большого смысла тщательно рассказывать, как забивать гвозди... Почему нет ни единого примера на Си? Цитата(SasaVitebsk @ Sep 1 2007, 02:37)  2. В этом есть особый смысл.  Классическая структура буфера - сам буфер+2переменных. Указатель на голову и указатель на хвост. Представим себе приём. В прерывании используется только хвост(добавляются символы), а в main только голова буфера (забираются данные). А когда хвост догнал голову, а он важнее (ибо прерывание) получается баальшой булик  Цитата(SasaVitebsk @ Sep 1 2007, 02:37)  Есть ещё один приятный момент.
..................Никаких дополнительных средств и инструментов не требуется. Кроме анальгина
--------------------
|
|
|
|
|
Aug 31 2007, 19:56
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата Циклический буфер позволяет работать с максимальной производительностью Всё-таки накладные нужно отметить - это удвоенное время пересылки байтов - в буфер и из него. Кроме того имеем некоторые вопросы с обслуживанием флагов при приёме - приходится либо принимать решение о загрузке байта в буфер по месту (при обслуживании флагов), либо расширять буфер для трансляции флагов. Пропуск повреждённых байтов (типа не сошлась четность) может привести к ожиданию конца пакета по таймауту, а это не всегда одинаково полезно При передаче использование модификатора __generic (иногда приятно пользоваться удобствами) для указателей приводит к удорожанию их обслуживания
--------------------
aka Vit
|
|
|
|
|
Sep 1 2007, 07:03
|
Знающий
   
Группа: Свой
Сообщений: 709
Регистрация: 3-05-05
Пользователь №: 4 693

|
Цитата(sensor_ua @ Aug 31 2007, 23:56)  Всё-таки накладные нужно отметить - это удвоенное время пересылки байтов - в буфер и из него. ... Для УАРТовых времян это слёзы. Цитата А когда хвост догнал голову, а он важнее (ибо прерывание) получается баальшой булик Практика такова, что это хвост постоянно сидит на хвосте у головы ;О) Даже если УАРТ работает на мегабоде, то между двумя байтами 160 тактов. За это время фон успеет прожевать не один байт. Конечно, если его тормознут на 100мкС, тогда приёмник ему накидает. Но всё равно, потом фон огуляет принятое гораздо быстрее. ;О)
|
|
|
|
|
Sep 1 2007, 07:45
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата Почему нет ни единого примера на Си? Файл прицепить не получилось, так что как есть... (Рулёжка по типам камешков была, так её вырезал. Вроде корректно) Код #include "uart.h"
unsigned char U0_RxBufGetIndex = 0; unsigned char U0_RxBufPutIndex = 0; unsigned char U0_RxBufSize = BUF0RXSIZE; unsigned int U0_RxBuffer[BUF0RXSIZE] = {0};
void USART0_Ring_Flush(void){ U0_RxBufGetIndex = U0_RxBufPutIndex; return; }
int UART0_getc (void){ int proxy = 0; if(U0_RxBufPutIndex != U0_RxBufGetIndex){ //proxy = U0_RxBuffer[U0_RxBufGetIndex] & (~(((!!PARITY)<<RXB80)<<8)); proxy = U0_RxBuffer[U0_RxBufGetIndex]; U0_RxBufGetIndex = (U0_RxBufGetIndex+1)&(U0_RxBufSize-1); // modulo UART0_RxBufSize return (proxy); } return (EOF); }
#ifdef __ICCAVR__ #pragma vector = USART_RX_vect __interrupt void USART_RX_Handler(void){ #else ISR(USART_RX_vect){ #endif
unsigned char status; // unsigned char resh; status = UCSR0A; //resh = UCSR0B; // Read flags U0_RxBuffer[U0_RxBufPutIndex] = (status & ((1<<FE0)|(1<<DOR0)|(1<<UPE0))) << 8; // Filter the 9th bit, then return //U0_RxBuffer[U0_RxBufPutIndex] |= _BLV(resh, RXB80) << 8; //(resh >> 1) & 0x01;
U0_RxBuffer[U0_RxBufPutIndex] |= UDR0; // normal ready, save into the Data Ring Buffer
U0_RxBufPutIndex=(U0_RxBufPutIndex+1)&(U0_RxBufSize-1); // PutIndex modulo BufferSize
if(U0_RxBufPutIndex == U0_RxBufGetIndex) { U0_RxBufPutIndex--; U0_RxBufPutIndex &= U0_RxBufSize-1; // PutIndex modulo BufferSize } return; } то: sensor_uaНу хоть тэгами пользуйтесь для выделения исходников
Сообщение отредактировал zltigo - Sep 1 2007, 08:24
--------------------
aka Vit
|
|
|
|
|
Sep 1 2007, 08:36
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(sensor_ua @ Sep 1 2007, 10:45)  Код U0_RxBuffer[U0_RxBufPutIndex] |= UDR0; // normal ready, save into the Data Ring Buffer
U0_RxBufPutIndex=(U0_RxBufPutIndex+1)&(U0_RxBufSize-1); // PutIndex modulo BufferSize А так: Код U0_RxBuffer[(U0_RxBufPutIndex++)&(U0_RxBufSize-1)] |= UDR0; При этом Вы имеете всегда полный индекс равный счетчику помещенных извлеченных байтов и одним простым арифметическим действием (в пределах размерности счетчиков, естественно ) можете узнать количество байтов в буфере.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Sep 1 2007, 08:57
|
Знающий
   
Группа: Свой
Сообщений: 709
Регистрация: 3-05-05
Пользователь №: 4 693

|
Цитата(prottoss @ Sep 1 2007, 11:15)  Практика Ваша? Или мировая? Или кЫтайская? 160 тактов, как сказал один чел выше - это очень мало  Если за это время основной поток не заберет из головы данные, то хвост накидает голове байтов по самые уши - будет потеря данных Опять же сказанное мной выше то - что показывает практика Практичная практика. Проистекает от навыков владения калькулятором и головным мосхом: Если загрузка фона сильная, то разработчик обязан оценить эту загрузку и взять глубину буфера, чтобы голова не топталась по хвосту, пока фон топчется по своим делам. Задача сродни определению требуемой глубины стека. Если таинством арифметики разрабоччик, таки, настойчиво овладел, то 160 тактов ему - выше крыши. А тому одному челу сверху виднее, чего он наворотил, мож ему и мало. А я на 160 тактах зайца в поле загоняю.
|
|
|
|
|
Sep 1 2007, 09:03
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата Ну хоть тэгами пользуйтесь для выделения исходников Пробовал pre и code - не получилось Цитата А так:
U0_RxBuffer[(U0_RxBufPutIndex++)&(U0_RxBufSize-1)] |= UDR0; Ничего против. Просто я при переполнении переписываю последний доступный для записи байт буфера принятым символом (это может быть полезным при поиске управляющих символов, но тогда ещё одна пересылка данных и сравнение внизу). Потому "не верю" этому счётчику. И мне вообще-то не приходится в моих последующих процедурах узнавать размер данных попавших в буфер  - может ещё и потому и не пытаюсь семафорить. Кроме того, так (в одну строку) не пишу, потому как иногда пользую буфер размером не кратным 2^N. Тогда (может мне кажется) рихтуется меньше.
--------------------
aka Vit
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|