Easyelectronics.ru

Электроника для всех
Текущее время: 29 сен 2020, 03:39

Часовой пояс: UTC + 5 часов



JLCPCB – Прототипы печатных плат за $2/5шт. два слоя. $5/5шт. четыре слоя
Крупнейший производитель печатных плат и прототипов. Более 600000 клиентов и свыше 10000 заказов в день!
Получите скидку на почтовую отправку при первом заказе в JLCPCB!

Начать новую тему Ответить на тему  [ Сообщений: 98 ]  На страницу 1, 2, 3, 4  След.
Автор Сообщение
 Заголовок сообщения: Циклический(кольцевой) буфер.
СообщениеДобавлено: 02 май 2016, 10:33 
Старожил
Аватара пользователя

Зарегистрирован: 11 апр 2016, 18:04
Сообщения: 3569
Откуда: Китай, Пекин
Понадобилось мне тут...
Для начала, чтобы не изобретать велосипед, долго искал.
В итоге пришлось изобрести. Вроде работает, но... покритикуйте....
Изображение

Код:
#define RBUF_INIT(TYPE, LENPOW2 ) volatile struct { \
   uint32_t wr; \
   uint32_t rd; \
   TYPE data[ 1 << (LENPOW2)]; \
}

#define RBUF_PUT( RBUF, INN)  \
  { if((RBUF).rd == (RBUF).wr ) { \
      (RBUF).wr = 0; \
        (RBUF).rd = 0; \
   } \
       (RBUF).data[ RBUF_MASK(RBUF) & (RBUF).wr++] = INN; }


#define RBUF_MASK(RBUF) ( sizeof((RBUF).data)/sizeof((RBUF).data[0]) -1) 
#define RBUF_NOTEMPTY (RBUF) ((RBUF).rd < (RBUF).wr)
#define RBUF_NOTFULL (RBUF) ((RBUF).wr - (RBUF).rd <= RBUF_MASK(RBUF))

#define RBUF_GET( RBUF)  (RBUF).data[ RBUF_MASK(RBUF) & ((RBUF).rd++)];

//=========== ПРИМЕР ИСПОЛЬЗОВАНИЯ ========================

RBUF_INIT(uint8_t, 5) buf; //байтовый циклический буфер длинной 32
RBUF_INIT(Pack *, 3) packs; //циклический буфер пакетов длинной 8

void main(void)
{
   if (RBUF_NOTEMPTY(buf)) uint8_t data = RBUF_GET(buf);

   if (RBUF_NOTFULL(buf))RBUF_PUT(buf, 34);

}

_________________
unirail.org


Последний раз редактировалось cheblin 02 май 2016, 12:15, всего редактировалось 3 раз(а).

Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Циклический(кольцевой) буфер.
СообщениеДобавлено: 02 май 2016, 10:59 
Старожил
Аватара пользователя

Зарегистрирован: 04 окт 2011, 10:19
Сообщения: 2079
Оно конечно не thread safe, но может оно и не надо.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Циклический(кольцевой) буфер.
СообщениеДобавлено: 02 май 2016, 11:01 
Старожил
Аватара пользователя

Зарегистрирован: 11 апр 2016, 18:04
Сообщения: 3569
Откуда: Китай, Пекин
Цитата:
Оно конечно не thread safe

в каком именно месте? и какие проблемы от этого?

Цитата:
но может оно и не надо.
НАДО!

volatile struct

что то ещё можно сделать? (чтобы и в 8 битниках работало!)

_________________
unirail.org


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Циклический(кольцевой) буфер.
СообщениеДобавлено: 02 май 2016, 11:45 
Старожил

Зарегистрирован: 19 мар 2013, 19:37
Сообщения: 2795
Откуда: Санкт-Петербург
В макросы воткнуть синхронизацию, вестимо. Например, через ATOMIC_BLOCK из atomic.h (при этом даже volatile уже не нужен будет).
Но это, конечно, если не делать внешнюю синхронизацию (например, пара notempty/get просится в единый блок)


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Циклический(кольцевой) буфер.
СообщениеДобавлено: 02 май 2016, 11:50 
Старожил
Аватара пользователя

Зарегистрирован: 11 апр 2016, 18:04
Сообщения: 3569
Откуда: Китай, Пекин
Цитата:
ATOMIC_BLOCK из atomic.h

Цитата:
что то ещё можно сделать? (чтобы и в 8 битниках работало!)


Цитата:
notempty/get просится

а как обрабатывать логику если буфер пуст?

_________________
unirail.org


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Циклический(кольцевой) буфер.
СообщениеДобавлено: 02 май 2016, 12:16 
Старожил
Аватара пользователя

Зарегистрирован: 11 апр 2016, 18:04
Сообщения: 3569
Откуда: Китай, Пекин
добавил скобочек в RBUF_NOTEMPTY и RBUF_NOTFULL для того, чтобы можно было писать

Код:
if(!RBUF_NOTEMPTY(buf)){

}

_________________
unirail.org


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Циклический(кольцевой) буфер.
СообщениеДобавлено: 02 май 2016, 12:37 
Старожил

Зарегистрирован: 10 июн 2011, 23:01
Сообщения: 3459
https://github.com/scmrtos/scmrtos/blob ... e/usrlib.h
https://github.com/scmrtos/scmrtos/blob ... usrlib.cpp


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Циклический(кольцевой) буфер.
СообщениеДобавлено: 02 май 2016, 12:43 
Старожил
Аватара пользователя

Зарегистрирован: 11 апр 2016, 18:04
Сообщения: 3569
Откуда: Китай, Пекин
Цитата:
https://github.com/scmrtos/scmrtos/blob ... e/usrlib.h
https://github.com/scmrtos/scmrtos/blob ... usrlib.cpp


Цитата:
что то ещё можно сделать? (чтобы и в 8 битниках работало!)

_________________
unirail.org


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Циклический(кольцевой) буфер.
СообщениеДобавлено: 02 май 2016, 13:32 
Старожил
Аватара пользователя

Зарегистрирован: 06 ноя 2013, 16:07
Сообщения: 711
Откуда: Германия
1. Оно не компилируется - лишние пробелы и точка с запятой.
2. Оно не работает - при переполнении wr.
3. Thread-safe потом обсудим.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Циклический(кольцевой) буфер.
СообщениеДобавлено: 02 май 2016, 14:04 
Старожил

Зарегистрирован: 10 июн 2011, 23:01
Сообщения: 3459
cheblin писал(а):
Цитата:
что то ещё можно сделать? (чтобы и в 8 битниках работало!)

а что, не работает?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Циклический(кольцевой) буфер.
СообщениеДобавлено: 02 май 2016, 14:07 
Старожил
Аватара пользователя

Зарегистрирован: 11 апр 2016, 18:04
Сообщения: 3569
Откуда: Китай, Пекин
Цитата:
1. Оно не компилируется - лишние пробелы и точка с запятой.

дайка угадаю - компилятор cosmic? в IAR прекрасно компилится.
Цитата:
2. Оно не работает - при переполнении wr.

4 гигабайта непрерывного, интенсивного трафика на приём? мы точно про микроконтроллеры говорим?
Цитата:
3. Thread-safe потом обсудим.

звучит зловеще многообещающе, бум ждать...

_________________
unirail.org


Последний раз редактировалось cheblin 02 май 2016, 14:17, всего редактировалось 1 раз.

Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Циклический(кольцевой) буфер.
СообщениеДобавлено: 02 май 2016, 14:11 
Старожил
Аватара пользователя

Зарегистрирован: 11 апр 2016, 18:04
Сообщения: 3569
Откуда: Китай, Пекин
Цитата:
а что, не работает?

возможно и работает, но в моём IAR-e кнопочка скомпилировать С++ с шаблонами серая и не нажимается.... чянд?

_________________
unirail.org


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Циклический(кольцевой) буфер.
СообщениеДобавлено: 02 май 2016, 14:15 
Старожил
Аватара пользователя

Зарегистрирован: 06 ноя 2013, 16:07
Сообщения: 711
Откуда: Германия
1. gcc
2. Вероятностное программирование?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Циклический(кольцевой) буфер.
СообщениеДобавлено: 02 май 2016, 14:42 
Старожил
Аватара пользователя

Зарегистрирован: 11 апр 2016, 18:04
Сообщения: 3569
Откуда: Китай, Пекин
Цитата:
Вероятностное программирование?

2% невзлетевших ракет - реальный индустриальный показатель.

да, эта реализация не для тех, кто собрался прокачивать непрерывно 4 гигабайта на 8 битном контроллере.

на более мощных машинках и чрезвычайно интенсивном трафике можно использовать ulong, но по мне - так это излишество.

_________________
unirail.org


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Циклический(кольцевой) буфер.
СообщениеДобавлено: 02 май 2016, 14:59 
Старожил
Аватара пользователя

Зарегистрирован: 06 ноя 2013, 16:07
Сообщения: 711
Откуда: Германия
Ну тогда рассуждать о многопоточности не имеет смысла - вероятность сбоев небольшая, и так сойдет.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Циклический(кольцевой) буфер.
СообщениеДобавлено: 02 май 2016, 15:36 
Старожил
Аватара пользователя

Зарегистрирован: 29 янв 2010, 15:41
Сообщения: 1127
Откуда: Германия
thread safe'м и не пахнет.
Т.е. в прерываниях использовать нельзя.
На 8ми битниках тем более. И 4 гига тут вовсе не причем. Даже на 10 байтах и драйвере, построенном на прерываниях, а не на polling'е, будет вылет в какой нить аборт.

_________________
Мои поделки
http://www.fun-electronic.net/


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Циклический(кольцевой) буфер.
СообщениеДобавлено: 02 май 2016, 15:41 
Старожил
Аватара пользователя

Зарегистрирован: 30 янв 2014, 18:09
Сообщения: 647
Откуда: Киев
Я бы перешёл на указатели. Потому что вот это:
(RBUF).data[ RBUF_MASK(RBUF) & (RBUF).wr++]
вычисляется ну очень долго.
Как-то так:
Код:
#define RBUF_INIT(TYPE, LENPOW2 ) volatile struct { \
   TYPE data[ 1 << (LENPOW2)]; \
   TYPE *wr = data; \
   TYPE *rd = data; \
}

#define RBUF_PUT( RBUF, INN)  \
   { if((RBUF).rd == (RBUF).wr ) { \
   (RBUF).wr = data; \
   (RBUF).rd = data; \
   } \
   *(RBUF).data = INN;  \
   (RBUF).data++;}

#define RBUF_NOTEMPTY (RBUF) ((RBUF).rd < (RBUF).wr)
#define RBUF_NOTFULL (RBUF) ((RBUF).wr <  &(RBUF).data [1 << (LENPOW2)])

#define RBUF_GET( RBUF, DATA)  {(RBUF).rd++); \
        DATA = *(RBUF).data; }



Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Циклический(кольцевой) буфер.
СообщениеДобавлено: 02 май 2016, 15:43 
Старожил

Зарегистрирован: 19 мар 2013, 19:37
Сообщения: 2795
Откуда: Санкт-Петербург
cheblin писал(а):
Цитата:
notempty/get просится

а как обрабатывать логику если буфер пуст?

Я имел в виду в самом кольцевом буфере "thread safety" не делать, а все обращения к нему убирать в ATOMIC_BLOCK там, где они используются. Причём вызов "isempty" с последующим "get" - в один блок.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Циклический(кольцевой) буфер.
СообщениеДобавлено: 02 май 2016, 16:15 
Старожил
Аватара пользователя

Зарегистрирован: 11 апр 2016, 18:04
Сообщения: 3569
Откуда: Китай, Пекин
нету в STM8, например, ATOMIC_BLOCK. совсем. есть только отменить прерывания,чёта сделать, и возобновить. всё.

но мне это кажется ещё хуже. ибо летят данные....

на эту тему... http://we.easyelectronics.ru/STM32/atomic-makrosy-dlya-arm.html как я и сказал.

В любом случае спасибо. Это полезное примечание.

_________________
unirail.org


Последний раз редактировалось cheblin 02 май 2016, 16:43, всего редактировалось 3 раз(а).

Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Циклический(кольцевой) буфер.
СообщениеДобавлено: 02 май 2016, 16:19 
Старожил
Аватара пользователя

Зарегистрирован: 06 ноя 2013, 16:07
Сообщения: 711
Откуда: Германия
SOVA писал(а):
Я бы перешёл на указатели. Потому что вот это:
(RBUF).data[ RBUF_MASK(RBUF) & (RBUF).wr++]
вычисляется ну очень долго.
Как-то так:


И потерять при этом цикличность буфера.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Циклический(кольцевой) буфер.
СообщениеДобавлено: 02 май 2016, 16:24 
Старожил
Аватара пользователя

Зарегистрирован: 11 апр 2016, 18:04
Сообщения: 3569
Откуда: Китай, Пекин
Цитата:
(RBUF).data[ RBUF_MASK(RBUF) & (RBUF).wr++]
вычисляется ну очень долго.

почему? RBUF_MASK(RBUF) в итоге на этапе компиляции превращается в константу.

_________________
unirail.org


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Циклический(кольцевой) буфер.
СообщениеДобавлено: 02 май 2016, 16:35 
Старожил
Аватара пользователя

Зарегистрирован: 11 апр 2016, 18:04
Сообщения: 3569
Откуда: Китай, Пекин
Цитата:
thread safe'м и не пахнет.

это уже второе подобное замечание, с объяснением ужасов последствий (которые и так очевидны), многозначительными намёками, но без пояснения в каком именно месте??? и как было бы правильно.

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

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

_________________
unirail.org


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Циклический(кольцевой) буфер.
СообщениеДобавлено: 02 май 2016, 16:56 
Старожил
Аватара пользователя

Зарегистрирован: 29 янв 2010, 15:41
Сообщения: 1127
Откуда: Германия
cheblin писал(а):
Цитата:
thread safe'м и не пахнет.

это уже второе подобное замечание, с объяснением ужасов последствий (которые и так очевидны), многозначительными намёками, но без пояснения в каком именно месте??? и как было бы правильно.

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

сейчас этот код работает, и показывает себя очень хорошо. в прерывании UART1 происходит заливка данных в фоновом процессе выгребание. ошибок нет!

Ну раз хотели... :

Операция внесения байта в буфер не атомарная.

RBUF_PUT( RBUF, INN) \
{ if((RBUF).rd == (RBUF).wr ) { \
(RBUF).wr = 0; \
(RBUF).rd = 0; \
} \
(RBUF).data[ RBUF_MASK(RBUF) & (RBUF).wr++] = INN; }

Т.е. в любой момент времени в этой куче операторов может произойти прерывание.
В случай с восьмибитником, прерывание имеет обыкновение происходить в момент, когда пишется или читается один из 4х байт одной переменной. Допустим, основной цикл пишет в буфер, а прерывание уарт - читает буфер и отправляет на выход данные.
И так - в операторе выше мы сравнили rd и wr, и начали писать в rd 0. Но произошло прерывание аккурат на середине писанины, когда половина переменной уже в 0, а другая еще держит какое то значение. И в прерывании мы смотрим есть ли чего для выдачи - ага. rd не равен ни 0 ни rw -> значит данные есть! Читаем и пишем. Что читаем? Мы не в курсе, куда теперь показывает этот самый rd , потому как половину его затерли а остальное - может вообще указывать за пределы как массива, так и всей памяти.

Тоже самое и тут:
RBUF_GET( RBUF) (RBUF).data[ RBUF_MASK(RBUF) & ((RBUF).rd++)];

Как надо? Ну вариантов валом - один из них - на время всей операции чтения/записи вывешивать семафор. Но тогда у вас буфер будет однонаправленный, т.е. писать в прерывании, а читать в основном цикле и никак не наоборот.
Еще вариант, как только вызвали функцию работы с буфером - сохранили указатели rd и wr в локальные переменные, потом работаете с локальными переменными, и в конце, когда все уже посчитали - пишите локальные в глобальные.
Тут, если соблюсти правильно последовательность чтения из глобальных в локальные, даже семафоров не надо. На 32хбитниках. На 8ми - кажется, все еще надо семафорить.
Ну как то так примерно.

_________________
Мои поделки
http://www.fun-electronic.net/


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Циклический(кольцевой) буфер.
СообщениеДобавлено: 02 май 2016, 17:08 
Старожил
Аватара пользователя

Зарегистрирован: 11 апр 2016, 18:04
Сообщения: 3569
Откуда: Китай, Пекин
Цитата:
rd не равен ни 0 ни rw

#define RBUF_NOTEMPTY (RBUF) ((RBUF).rd < (RBUF).wr)

rd должен быть меньше wr для того, чтобы начать читать....
именно поэтому в RBUF_PUT

сначала (RBUF).wr = 0;
потом (RBUF).rd = 0;

Цитата:
Ну раз хотели... :

хотел, очень. Спасибо!
разгребая чужие косяки, в о числе в много поточности на Scalа, я деньги зарабатываю.
А тут, на STM8, я весьма ограничен в средствах и возможностях... Ваше замечание правильно, но слишком очевидно. В принципе секцию с обнулением wr/rd можно было бы и выкинуть ваще. Не нравится мне она.

_________________
unirail.org


Последний раз редактировалось cheblin 02 май 2016, 17:16, всего редактировалось 1 раз.

Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Циклический(кольцевой) буфер.
СообщениеДобавлено: 02 май 2016, 17:12 
Старожил
Аватара пользователя

Зарегистрирован: 29 янв 2010, 15:41
Сообщения: 1127
Откуда: Германия
cheblin писал(а):
Цитата:
rd не равен ни 0 ни rw

#define RBUF_NOTEMPTY (RBUF) ((RBUF).rd < (RBUF).wr)

rd должен быть меньше wr для того, чтобы начать читать....
именно поэтому в RBUF_PUT

сначала (RBUF).wr = 0;
потом (RBUF).rd = 0;

Прекрассно. Прерывание происходит в середине записи нуля в wr. т.е. wr еще не 0, но уже и не то, что было раньше. Т.е. rd != wr == есть данные.

_________________
Мои поделки
http://www.fun-electronic.net/


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 98 ]  На страницу 1, 2, 3, 4  След.


Часовой пояс: UTC + 5 часов


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  

Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
Русская поддержка phpBB