реклама на сайте
подробности

 
 
> Работа с переменными в прерывании и основном теле, жутко неудобно выходит
Alexashka
сообщение Oct 3 2015, 19:40
Сообщение #1


Практикующий маг
******

Группа: Свой
Сообщений: 3 634
Регистрация: 28-04-05
Из: Дубна, Моск.обл
Пользователь №: 4 576



Добрый вечер sm.gif
Что имеем: 8 битный проц, программа в прерывании читает из кольцевого буфера, указатель чтения -просто индекс массива, двухбайтное число. В основном теле мне приходит поток байт, который я контролирую (запускаю/останавливаю поток) и размещаю байты в этом же кольцевом буфере по другому указателю -указателю записи (тоже индекс массива). До этих пор все замечательно, но чтобы управлять потоком мне нужно знать сколько байт содержится в буфере, для этого я беру разницу между указателями записи и чтения и побитно умножаю ее на (размер_массива - 1). Эту разницу приходится брать в нескольких местах программы, при этом на время вычисления нужно блокировать прерывание, поскольку операция не атомарная, а одна из переменных модифицируется в прерывании. Если этого не делать происходит глюк, если делать -появляется задержка обработки прерывания, а это нехорошо, т.к в нем происходит формирования аудио сигнала. Да и некрасиво это и неудобно -следить какую перменную обрабатываю, нужно или нет блокировать прерывание, ну и поскольку кольцевой буфер используется в различных прерываниях нужно еще и учитывать какое именно прерывание блокировать biggrin.gif
Может это както по-другому можно делать, подскажите.
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
gerber
сообщение Oct 3 2015, 19:44
Сообщение #2


Знающий
****

Группа: Участник
Сообщений: 750
Регистрация: 1-11-11
Пользователь №: 68 088



Цитата(Alexashka @ Oct 3 2015, 22:40) *
Может это както по-другому можно делать, подскажите.

Заведите переменную "количество байт в буфере" и обновляйте её вместе с изменением указателей чтения и записи.


--------------------
"... часами я мог наблюдать, как люди работают." (М. Горький)
Go to the top of the page
 
+Quote Post
Alexashka
сообщение Oct 3 2015, 19:49
Сообщение #3


Практикующий маг
******

Группа: Свой
Сообщений: 3 634
Регистрация: 28-04-05
Из: Дубна, Моск.обл
Пользователь №: 4 576



Цитата(gerber @ Oct 3 2015, 22:44) *
Заведите переменную "количество байт в буфере" и обновляйте её вместе с изменением указателей чтения и записи.

неа, смотрите, эта переменная тоже двухбайтная выходит. Допустим если байт в буфере больше 2000 нужно остановить поток, для этого я сравниваю ее с числом 2000, при этом сначала сравнивается младшие байты, потом старшие, если между этими операциями произойдет вызов подпрограммы, которая изменит старший байт "количество байт в буфере", то в результате сравнения можно получить очень неверный результат.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Oct 4 2015, 07:47
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(Alexashka @ Oct 4 2015, 01:49) *
неа, смотрите, эта переменная тоже двухбайтная выходит. Допустим если байт в буфере больше 2000 нужно остановить поток, для этого я сравниваю ее с числом 2000, при этом сначала сравнивается младшие байты, потом старшие, если между этими операциями произойдет вызов подпрограммы, которая изменит старший байт "количество байт в буфере", то в результате сравнения можно получить очень неверный результат.

Конечно не нужно никаких "количеств байт". Достаточно двух указателей (чтения/записи). И достаточно операции чтения/записи этих указателей сделать атомарными. И для вычисления кол-ва байт достаточно найти разность указателей (с учётом их цикличности), не нужно никаких "побитных умножений".
Неужто запрет прерывания на пару команд так влияет на выполнение алгоритма??? Тогда у Вас вероятно неправильно построен алгоритм.
Go to the top of the page
 
+Quote Post
Alexashka
сообщение Oct 4 2015, 21:53
Сообщение #5


Практикующий маг
******

Группа: Свой
Сообщений: 3 634
Регистрация: 28-04-05
Из: Дубна, Моск.обл
Пользователь №: 4 576



Цитата(jcxz @ Oct 4 2015, 10:47) *
Конечно не нужно никаких "количеств байт". Достаточно двух указателей (чтения/записи). И достаточно операции чтения/записи этих указателей сделать атомарными. И для вычисления кол-ва байт достаточно найти разность указателей (с учётом их цикличности), не нужно никаких "побитных умножений".
Неужто запрет прерывания на пару команд так влияет на выполнение алгоритма??? Тогда у Вас вероятно неправильно построен алгоритм.

Запрет прерывания на пару команд не повлияет я так думаю, но вычисление разницы двухбайтных чисел с последующим умножением на маску это всё же не 2 операции, с другой стороны как я уже писал, проблема не в этом, а в том, что при каждом таком обращении нужно добавлять запрет и разрешение прерывания, либо оборачивать это в функцию, плюс нужно следить -если изменил прерывание например с АЦП на UART, то нужно переписывать функции чтения переменной, а также чтения/записи в буфер.
А вот сделать чтение двухбайтного указателя атомарной операцией невозможно, поскольку ядро 8-разрядное sm.gif Ну и до кучи объясните как сделать это
Цитата
И для вычисления кол-ва байт достаточно найти разность указателей (с учётом их цикличности), не нужно никаких "побитных умножений".

Допустим есть буфер, он занимает пространство от 0 до 2047, указатель есно двухбайтный, если мы возьмем разницу двух указателей например как "0"-"1" (значит в буфере 2047 байт данных) получим 0xFFFF, хотя должно быть 2047.

Цитата(_Pasha @ Oct 4 2015, 14:27) *
можно проверку делать с учетом неатомарности, поскольку указатели в данном случае readonly

Поясните пожалуйста, что значит readonly если я как читаю указатель, так и пишу его (инкрементирую) wacko.gif
И что делает эта строчка
Код
while(res != *dsc) res = *dsc;
К сожалению не читал обсуждение темы, о которой Вы говорите, если есть ссылочка прошу направить в нужном направлении sm.gif
Go to the top of the page
 
+Quote Post
jcxz
сообщение Oct 5 2015, 04:12
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(Alexashka @ Oct 5 2015, 03:53) *
Запрет прерывания на пару команд не повлияет я так думаю, но вычисление разницы двухбайтных чисел с последующим умножением на маску это всё же не 2 операции, с другой стороны как я уже писал, проблема не в этом, а в том, что при каждом таком обращении нужно добавлять запрет и разрешение прерывания, либо оборачивать это в функцию, плюс нужно следить -если изменил прерывание например с АЦП на UART, то нужно переписывать функции чтения переменной, а также чтения/записи в буфер.

ЗАЧЕМ???? wacko.gif

Цитата(Alexashka @ Oct 5 2015, 03:53) *
А вот сделать чтение двухбайтного указателя атомарной операцией невозможно, поскольку ядро 8-разрядное sm.gif Ну и до кучи объясните как сделать это

Сделать чтение двухбайтового числа на 8-разрядном процессоре атомарным (при отсутствии в нём команды чтения 16-разрядных чисел), элементарно:
u16 i;
__disable_interrupt();
i = var;
__enable_interrupt();
всё!

Цитата(Alexashka @ Oct 5 2015, 03:53) *
Допустим есть буфер, он занимает пространство от 0 до 2047, указатель есно двухбайтный, если мы возьмем разницу двух указателей например как "0"-"1" (значит в буфере 2047 байт данных) получим 0xFFFF, хотя должно быть 2047.


Код
//предполагаем размерность int >=16бит
int volatile rpos = 0, wpos = 0;
u8 buf[N];

int read()
{
  int ir = rpos;
  int iw = wpos;
  if (ir == iw) return -1;
  if (--ir < 0) ir = sizeof(buf) - 1;
  iw = buf[ir];
  rpos = ir;
  return iw;
}

int write(int data)
{
  int ir = rpos;
  int iw = wpos;
  if (--iw < 0) iw = sizeof(buf) - 1;
  if (ir == iw) return -1;
  buf[iw] = data;
  wpos = iw;
  return 0;
}

//кол-во данных в кольц. буфере
int occupy()
{
  int ir = rpos;
  int iw = wpos, i;
  if ((i = ir - iw) < 0) i += sizeof(buf);
  return i;
}

//свободное место в кольц. буфере
int free()
{
  int ir = rpos;
  int iw = wpos, i;
  if ((i = iw - ir - 1) < 0) i += sizeof(buf);
  return i;
}

Это классика.
Если операции чтения/записи wpos, rpos в данном CPU атомарны, то можно использовать read(), write() в разных процессах/ISR как есть, без запретов прерываний.
Только обязательно read() и write() каждая должна вызываться только из одного процесса!
Если чтение/запись указателей неатомарны, то необходимо сделать их таковыми с помощью например запретов прерываний. В процессе, вызывающем read(), запрет прерываний необходим
при чтении wpos и записи rpos. Для write() - наоборот. Для occupy() и free() - аналогично - запрет прерываний для чтения того указателя, который модифицируется в другом процессе.

Цитата(_Pasha @ Oct 4 2015, 17:27) *
можно проверку делать с учетом неатомарности, поскольку указатели в данном случае readonly
100500 раз об этом говорили, но давно, лет 6-7 назад. Пора обновлять rolleyes.gif
например.

Это то же самое, что просто запрет прерывания на время чтения *dsc. Никакого преимущества не даёт по сранению с обычным запретом прерываний.
По скорости может быть как медленнее так и быстрее запрета - в зависимости от CPU.
Go to the top of the page
 
+Quote Post
Alexashka
сообщение Oct 5 2015, 12:25
Сообщение #7


Практикующий маг
******

Группа: Свой
Сообщений: 3 634
Регистрация: 28-04-05
Из: Дубна, Моск.обл
Пользователь №: 4 576



Цитата(jcxz @ Oct 5 2015, 07:12) *
ЗАЧЕМ???? wacko.gif
... элементарно:
u16 i;
__disable_interrupt();
i = var;
__enable_interrupt();
всё!

<РУКАЛИЦО> Я так и делаю (см.первый пост) и уже дважды объяснил почему мне не нравится этот метод.

Цитата
Если чтение/запись указателей неатомарны, то необходимо сделать их таковыми с помощью например запретов прерываний. В процессе, вызывающем read(), запрет прерываний необходим
при чтении wpos и записи rpos. Для write() - наоборот. Для occupy() и free() - аналогично - запрет прерываний для чтения того указателя, который модифицируется в другом процессе.
Вот об этом и речь -прикиньте, сколько таких мест, где нужно локально блокирова/разрешать прерывание. Можно конечно проще -блокировать прерывание перед вызовом функции read/write/free, но тогда задержка обработки прерывания станет недопустимо большой. Есть у меня идея использовать теневые регистры, которые будут обновляться в прерывании в том случае, если в основном теле к ним не производится обращение, но это уже в другой раз, пока что обошелся локальной блокировкой прерываний.
Посмотрел Ваш код, в принципе у меня примерно также, только не понял зачем Вы копируете глобальные rpos, wpos в локальные ir,iw ведь можно работать непосредственно с глобальными?
Да, к слову, указатели не использую, слишком медленно они обрабатываются в 8051: сначала ф-я чтения по указателю должна определить какую область памяти адресует указатель, а затем перейти к соответствующей команде чтения (там вроде как 4 варианта обращения к памяти и соответственно 4 разные ассемблерные команды) , с массивом такой ерунды не происходит -компилятор уже на этапе компиляции знает к какому типу памяти мы обращаемся поэутому все делается очень быстро.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Oct 5 2015, 12:58
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(Alexashka @ Oct 5 2015, 18:25) *
Посмотрел Ваш код, в принципе у меня примерно также, только не понял зачем Вы копируете глобальные rpos, wpos в локальные ir,iw ведь можно работать непосредственно с глобальными?

И что значит "работать с глобальными"? Там где они модифицируются, можно делать только так, как я написал. А не напрямую глобальные.
Если Вы этого не поняли, значит не поняли ничего в моих функциях.
Go to the top of the page
 
+Quote Post
Alexashka
сообщение Oct 6 2015, 07:29
Сообщение #9


Практикующий маг
******

Группа: Свой
Сообщений: 3 634
Регистрация: 28-04-05
Из: Дубна, Моск.обл
Пользователь №: 4 576



Цитата(jcxz @ Oct 5 2015, 15:58) *
Там где они модифицируются, можно делать только так, как я написал. А не напрямую глобальные.
Если Вы этого не поняли, значит не поняли ничего в моих функциях.

Да вроде понятно всЁ. Ну я например работаю непосредственно с глобальными и вроде все работает (блокирую прерывание непосредственно перед сравнением двух глобальных переменных).
С копированием получается наглядней в том смысле что имеем только 2 места где нужно ставить блокировку прерывания, и к локальной переменной можно обращаться сколько угодно раз. Я правильно понимаю идею?

Цитата(Сергей Борщ @ Oct 5 2015, 15:53) *
Все три известные мне компилятора для x51 (Кейл, Иар и SDCC) позволяли объявлять указатель на конкретный тип памяти. Такие указатели и меньше места занимают и работают без этого ветвления. Посмотрите документацию на свой компилятор, наверняка они там есть.

Проверил- и действительно: добавил спецификатор памяти в объявление указателя и всё лишнее в коде исчезло. Вот оно как оказывается, Михалыч (с) laughing.gif Спасибо за информацию, Сергей! a14.gif

Цитата(_Pasha @ Oct 5 2015, 16:36) *
Мы читаем указатель, но не запрещаем прерывания. Указатель считается валидным, если за два чтения подряд он не был изменен процессом более высокого приоритета. Это и есть неатомарное чтение. Быстро ли, медленно ли? Наверное, если это имеет значение - пора утяжелять прерывание.

Понял идею, но это ведь можно провернуть не только с указателем, но и с любой переменной?
Добавлено: попробовал Вашу функцию, вроде работает, только выдает предупреждение
Цитата
Pointer truncation
A spaced pointer has been assigned some constant value which exceeds the
range covered by the pointers memory space. For example:

char idata *p1 = 0x1234; /* result is 0x34 */
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Oct 6 2015, 11:51
Сообщение #10


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(Alexashka @ Oct 6 2015, 10:29) *
Добавлено: попробовал Вашу функцию, вроде работает, только выдает предупреждение

Ну я как бы тоже "из головы" писал, не с реального примера. У меня не случались неатомарные чтения по указателю. Мог и что-то упустить.
Go to the top of the page
 
+Quote Post
Alexashka
сообщение Oct 6 2015, 16:36
Сообщение #11


Практикующий маг
******

Группа: Свой
Сообщений: 3 634
Регистрация: 28-04-05
Из: Дубна, Моск.обл
Пользователь №: 4 576



Цитата(_Pasha @ Oct 6 2015, 14:51) *
Ну я как бы тоже "из головы" писал, не с реального примера. У меня не случались неатомарные чтения по указателю. Мог и что-то упустить.

Да нет все ок, разобрался sm.gif
Заменил
Код
char *p  = nonatomic_ptr(&r_pos);

на
Код
char *p;
p = nonatomic_ptr(&r_pos);

и ашИпка ушла
Go to the top of the page
 
+Quote Post

Сообщений в этой теме
- Alexashka   Работа с переменными в прерывании и основном теле   Oct 3 2015, 19:40
|- - _Pasha   Цитата(jcxz @ Oct 4 2015, 10:47) Неужто з...   Oct 4 2015, 11:27
||- - ViKo   Цитата(_Pasha @ Oct 4 2015, 14:27) Кодvol...   Oct 8 2015, 09:31
||- - _Pasha   Цитата(ViKo @ Oct 8 2015, 12:31) Читать и...   Oct 8 2015, 16:55
|||- - jcxz   Цитата(Alexashka @ Oct 5 2015, 18:25) -пр...   Oct 5 2015, 12:51
|||- - Сергей Борщ   Цитата(Alexashka @ Oct 5 2015, 15:25) сли...   Oct 5 2015, 12:53
|||- - jcxz   Цитата(Alexashka @ Oct 6 2015, 13:29) Да ...   Oct 6 2015, 08:10
||||- - Alexashka   Цитата(jcxz @ Oct 6 2015, 11:10) просто т...   Oct 6 2015, 08:41
||- - MrYuran   Цитата(jcxz @ Oct 5 2015, 07:12) Это то ж...   Oct 6 2015, 10:49
||- - jcxz   Цитата(MrYuran @ Oct 6 2015, 16:49) Преим...   Oct 7 2015, 02:41
|- - _Pasha   Цитата(Alexashka @ Oct 5 2015, 00:53) Поя...   Oct 5 2015, 13:36
- - gerber   Значит, можно сделать порог кратным 256 и ограничи...   Oct 3 2015, 20:05
|- - Alexashka   ЦитатаЗначит, можно сделать порог кратным 256 и ог...   Oct 3 2015, 22:28
- - aaarrr   Разделите свой большой буфер на N маленьких и опер...   Oct 3 2015, 20:14
- - smalcom   ЦитатаРазделите свой большой буфер на N маленьких ...   Oct 3 2015, 21:43
- - Valentine Loginov   Вариант с так называемым "nonatomic" по-...   Oct 7 2015, 07:13
|- - zltigo   QUOTE (Valentine Loginov @ Oct 7 2015, 10...   Oct 7 2015, 07:25
- - Valentine Loginov   Идея в том, что атомарный флаг делается тоже через...   Oct 8 2015, 07:35
|- - Alexashka   Цитата(Valentine Loginov @ Oct 8 2015, 11...   Oct 8 2015, 07:58
||- - jcxz   Цитата(Alexashka @ Oct 8 2015, 13:58) Ест...   Oct 8 2015, 09:09
||- - Alexashka   Цитата(jcxz @ Oct 8 2015, 13:09) Есть вер...   Oct 8 2015, 18:17
||- - jcxz   Цитата(Alexashka @ Oct 9 2015, 00:17) Да ...   Oct 9 2015, 03:18
||- - ASN   Alexashka Так и не понял, почему запрет прерываний...   Oct 9 2015, 06:05
|- - zltigo   QUOTE (Valentine Loginov @ Oct 8 2015, 10...   Oct 8 2015, 09:13
- - Valentine Loginov   Вообще долгая работа с данными в прерывании плохо....   Oct 9 2015, 06:51
|- - Alexashka   Цитата(Valentine Loginov @ Oct 9 2015, 10...   Oct 9 2015, 07:40
|- - zltigo   QUOTE (Alexashka @ Oct 9 2015, 10:40) Я х...   Oct 9 2015, 08:33
|- - Alexashka   Цитата(zltigo @ Oct 9 2015, 12:33) Лучше ...   Oct 9 2015, 13:09
|- - zltigo   QUOTE (Alexashka @ Oct 9 2015, 16:09) А к...   Oct 9 2015, 13:42
- - rudy_b   Цитата(Alexashka @ Oct 3 2015, 22:40) Доб...   Oct 9 2015, 13:19
|- - Alexashka   Цитата(rudy_b @ Oct 9 2015, 17:19) Как-то...   Oct 9 2015, 17:09
- - ViKo   Так зачем "чутка освободится..."? Сделай...   Oct 9 2015, 18:19
|- - rudy_b   Цитата(ViKo @ Oct 9 2015, 21:19) Так заче...   Oct 9 2015, 23:08
||- - Dog Pawlowa   Какие компоненты в систему заложишь, так она и поп...   Oct 10 2015, 03:51
|- - Alexashka   Цитата(ViKo @ Oct 9 2015, 22:19) Так заче...   Oct 10 2015, 11:19
|- - ViKo   Цитата(Alexashka @ Oct 10 2015, 14:19) Эт...   Oct 10 2015, 11:39
||- - Alexashka   Цитата(ViKo @ Oct 10 2015, 15:39) Красиво...   Oct 10 2015, 12:09
||- - Tanya   Цитата(Alexashka @ Oct 10 2015, 15:09) Жа...   Oct 10 2015, 12:19
||- - Alexashka   Цитата(Tanya @ Oct 10 2015, 16:19) Понима...   Oct 10 2015, 15:31
||- - _Pasha   Цитата(Alexashka @ Oct 10 2015, 18:31) Ду...   Oct 10 2015, 18:06
|- - Tanya   Цитата(Alexashka @ Oct 10 2015, 14:19) И ...   Oct 10 2015, 11:47
- - ViKo   Можно и одним буфером обойтись, если разбить его н...   Oct 10 2015, 13:57
- - smalcom   тогда будет ограничение на размер буфера.   Oct 10 2015, 18:56
|- - zltigo   QUOTE (smalcom @ Oct 10 2015, 21:56) тогд...   Oct 10 2015, 19:04
|- - Alexashka   Цитата(zltigo @ Oct 10 2015, 23:04) Вам у...   Oct 11 2015, 20:56
|- - zltigo   QUOTE (Alexashka @ Oct 11 2015, 23:56) Вы...   Oct 11 2015, 21:01
|- - Alexashka   Цитата(zltigo @ Oct 12 2015, 01:01) Если ...   Oct 12 2015, 06:38
- - smalcom   а?   Oct 10 2015, 20:09
- - ViKo   Да, для 8-битников 16 256-байтовых буферов будет л...   Oct 12 2015, 05:45
- - smalcom   для этого используйте 3, 4 и т.д. буферов.   Oct 12 2015, 08:00


Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 24th June 2025 - 12:09
Рейтинг@Mail.ru


Страница сгенерированна за 0.0156 секунд с 7
ELECTRONIX ©2004-2016