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

 
 
10 страниц V  « < 7 8 9 10 >  
Reply to this topicStart new topic
> __LDREX __STREX в STM32F407
Forger
сообщение Jun 10 2017, 20:01
Сообщение #121


Профессионал
*****

Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831



Цитата(AHTOXA @ Jun 10 2017, 22:54) *
Да нет же, всё будет нормально.
Вашими устами да мед пить sm.gif



--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Jun 10 2017, 20:32
Сообщение #122


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(Forger @ Jun 11 2017, 01:01) *
Вашими устами да мед пить sm.gif

Не буду оригинален: слив засчитан. Вы меня разочаровали.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
Forger
сообщение Jun 11 2017, 06:06
Сообщение #123


Профессионал
*****

Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831



Цитата(AHTOXA @ Jun 10 2017, 23:32) *
Не буду оригинален ...


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

Предположим, что в очереди уже есть 255 еще не отправленных элементов (набивали очередь перед отправкой), т.е. put = 0x00FF, а в это время get = 0x0000
Мы собираемся класть туда 256-й элемент, т.е. указатель изменит сразу 9 бит из 16, изменятся оба байта в указателе, put должен стать 0x0100, но по-байтно

После изменения младшего байта put будет 0x0000 и тут возникло прерывание, мы видим, что [get == put], логично предполагаем, что буфер пуст, останавливаем передачу.
Выходим из прерывания.
Тут указатель put сразу же стал 0x0100 (записали старшее слово), мы наивно набиваем очередь дальше, думая, что передача продолжается.

На практике в подавляющем числе проектов такая ситуация практически никогда не возникает, но она существует.
Этот пример больше для того, чтобы продемонстрировать опасность доступа в прерываниях к не атомарно изменяемым данным (указателям в частности).

Именно по этой причине для реализации длинных аппаратных таймеров (например, 16-битный на 8-битном камне) используются теневые регистры,
а обновление финального регистра таймера производится аппаратно только при записи лишь одного из байтов теневого регистра.


--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Jun 11 2017, 06:48
Сообщение #124


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(Forger @ Jun 11 2017, 11:06) *
...

Ну наконец-то, я смог вытащить из вас примерsm.gif
Да, вы правы, указанный кольцевой буфер работает лишь при условии атомарности изменений указателей на засовывание/выборку. То есть, на 8-битниках индекс до 255. Для 32-битниов ограничения нет.
Но это требование гораздо слабее того, что вы изначально утверждали:
Цитата(Forger @ Jun 10 2017, 11:27) *
Обращение к обоим указателям должно быть атомарным.

К каждому из указателей - да, атомарность нужна. К обоим - нет.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
ViKo
сообщение Jun 11 2017, 07:06
Сообщение #125


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Известен способ правильного чтения длинных счетчиков в малоразрядных процессорах - читаем старший байт, затем младший, затем опять старший, и если он не изменился - у нас правильное слово. Если старший байт изменился, значит, попали в момент переполнения младшего байта. Нужно провести все чтение еще раз.
Go to the top of the page
 
+Quote Post
Forger
сообщение Jun 11 2017, 07:12
Сообщение #126


Профессионал
*****

Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831



Цитата(ViKo @ Jun 11 2017, 10:06) *
Нужно провести все чтение еще раз.
В итоге можно плотно зависнуть в таком цикле sm.gif




--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Jun 11 2017, 07:13
Сообщение #127


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(ViKo @ Jun 11 2017, 12:06) *
Известен способ правильного чтения длинных счетчиков в малоразрядных процессорах - читаем старший байт, затем младший, затем опять старший

Здесь это не поможет - здесь как раз чтение происходит в прерывании, и два чтения подряд дадут одинаковое значение.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
Forger
сообщение Jun 11 2017, 08:04
Сообщение #128


Профессионал
*****

Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831



Цитата(AHTOXA @ Jun 11 2017, 09:48) *
Но это требование гораздо слабее того, что вы изначально утверждали:

Это требование относилось конкретно к вашему примеру.

Цитата
К каждому из указателей - да,

Если указатель длиннее разрядности проца, то да. Иначе - нет.

Цитата
атомарность нужна. К обоим - нет.

Нужна, если производится расчет свободного/занятого места вычитанием одного указателя из другого.
Нужно защитить (сделать атомарным): вычитывание значений указателей, анализ их разницы и действие, выполняемое при этом.

Вот пример:

Пусть put = 10, get = 9, т.е. в очереди остался всего один еще не отправленный элемент.
Перед отправкой каждого элемента производится расчет свободного места в очереди посредством сравнения двух указателей и выполнения соотв. действий.
Предположим, произошло прерывание в отправляющей задаче сразу после копирования put и get в некие временные переменные, но проанализировать и принять решение еще не успели.

В прерывании смотрим наличие данных в буфере, сравнивая put и get, тут они не равны,
берем данные из буфера, изменяем указатель get (= 10), отправляем данные, выходим из прерывания
по некоторой причине управление долго не передавалось отправляющей задаче (работали другие более приоритетные задачи) и вновь возникло прерывание от передатчика,
в этом прерывании смотрим, что get == put и прекращаем передачу (прерываний от передатчика не будет, пока заново их не запустим) выходим из прерывания.
Наконец-то попадаем в отправляющую задачу.

В данный момент w = 10, get = 9. Т. е. буфер как бы непустой, смело докладываем новый элемент.
А так, как буфер был непустой, то запуск передачи не делаем (не формируем соотв. прерывание от передатчика).
В итоге кладем в буфер данные, надеясь, что они отправляются, а это не так.
По-хорошему, решение о запуске прерываний нужно делать повторно вычитывая put и get.
Но кто даст гарантию, что прерывание не возникнет после сравнения put/get но перед принятием решения и запуске прерываний от передатчика?

Т. е. проблема тут не в самих указателях, а в действиях, предпринимаемых для запуска/останова аппаратного передатчика.
Фактически, нужно делать атомарным (для прерывания от передатчика): чтение указателей, сравнение, анализ результата и управление передатчиком.





--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
Go to the top of the page
 
+Quote Post
ViKo
сообщение Jun 11 2017, 08:18
Сообщение #129


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Так запретите прерывание чтения, когда модифицируете счетчик записи. Проблема, не стоящая ломаного яйца.
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Jun 11 2017, 09:16
Сообщение #130


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(Forger @ Jun 11 2017, 13:04) *
Это требование относилось конкретно к вашему примеру.

Это вы не со мной спорили. Я же специально сделал цитату со ссылкой - ткните, посмотрите контекст. Причём на тот момент восьмибитность ещё не упоминалась, это вы её уже потом за уши притянули, что само по себе доставляет: в разделе ARM, в теме про LDREX/STREX (!).

Цитата(Forger @ Jun 11 2017, 13:04) *
В данный момент w = 10, get = 9. Т. е. буфер как бы непустой, смело докладываем новый элемент.
А так, как буфер был непустой, то запуск передачи не делаем (не формируем соотв. прерывание от передатчика).
В итоге кладем в буфер данные, надеясь, что они отправляются, а это не так.

А при чём здесь буфер? Буфер здесь не при делах, его дело - быть буфером. Принять элемент, и выдать его потом. В порядке очереди. И описанный буфер это делает, чётко, без сбоев.
А описанная вами проблема ортогональна кольцевому буферу. Решать можно кучей способов. Например, разрешая прерывания без всяких проверок - раз мы положили элемент в буфер, то безусловно включаем прерывание, потому что в буфере гарантированно имеются данные. Или, как предложил ViKo - запрещая прерывания передатчика в момент засовывания элемента в буфер.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
AVI-crak
сообщение Jun 11 2017, 09:28
Сообщение #131


Частый гость
**

Группа: Участник
Сообщений: 182
Регистрация: 16-10-15
Пользователь №: 88 894



Цитата(Forger @ Jun 11 2017, 14:04) *
Вот пример:

Пусть put = 10, get = 9, т.е. в очереди остался всего один еще не отправленный элемент.

Конкретный пример кольцевого буфера на Си.
Сначала проверяется возможность записи данных, и только потом пишется, и только после этого указатель переписывается.
Сначала проверяется возможность чтения, потом читается, и только после этого - переписывается указатель.
Кстати, лично у меня использование глобальных переменных в функции в прямом виде - приводит к их использованию в виде локальных переменных. В результате любое изменение сразу записывается в память (это грёбаное ускорение от GCC). Чтобы этого не происходило - нужно глобальные перемененные переписывать локальные принудительно, и уже с ними работать. Этот глюк появился в GCC с переходом от 4,2 до 4,8 версии.
Кроме всего прочего, частое переписывание указателей (по чайной ложке) - это банальная нагрузка на память.

Буфер всегда должен иметь хотя-бы один пустой элемент, это есть защита от глюка.
Одинаковые указатели - признак пустого буфера.

Go to the top of the page
 
+Quote Post
Forger
сообщение Jun 11 2017, 10:22
Сообщение #132


Профессионал
*****

Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831



Цитата(AHTOXA @ Jun 11 2017, 12:16) *
Решать можно кучей способов. Например, разрешая прерывания без всяких проверок - раз мы положили элемент в буфер, то безусловно включаем прерывание,

Именно! А речь ведь была про то, что запреты/разрешения прерываний тут не нужны.
Я же пытаюсь донести, что не все тут так просто.

Я делаю так.
В передающей задаче при передаче данных вот что делается.
В методе отправке элемента данных: если буфер пустой, просто взводится флажок прерывания от передатчика о том, что он пустой (регистр передатчика пуст), т. е. принудительно запускаем передачу.
Если это делать во время работы передатчика, то будет глюк, т.к. передатчик в этом момент все еще работает и может нарушить последовательность логику работы с указателями (описано выше).
Поэтому перед запуском передачи следует просто временно запретить прерывание от передатчика (только от него).
Если же буфер в данный момент пустой, то нужно взвести флажок прерывания о том, что аппаратный буфер передатчика пустой, чтобы вызвать по выходу соотв. прерывание.
Если же буфер не пустой, и есть в нем место, то просто положить туда данные и только после этого разрешить прерывание от передатчика.
Также прерывание от передатчика нужно запрещать перед входом во flush, т. к. там модифицируется оба указателя. Более того нужно принудительно очищать весь аппаратный буфер передатчика.
Никакие другие прерывания запрещать, конечно же, не нужно.
В особых случаях можно принудительно заново проинициализировать весь передатчик. Особенно, если допускается на ходу менять скорость обмена.

В прерывании передатчика использую еще один флажок прерывания - передача окончена, это когда опустел и аппаратный буфер передатчика и опустел выходной сдвиговый регистра передатчика (речь про USART).
Тут у меня к задачам семафорится факт того, что все передачи завершены.
Это очень удобно для построения протокола в стиле запрос-ответ, особенно по каналу RS-485, где нужно управлять направлением работы внешнего трансивера.
На всякий случай в этом обработчике можно запретить прерывания от передатчика, хотя это и не обязательно.

По аналогии работаю с приемником, но чуть иначе: запрещать прерывания от приемника нужно лишь перед вызовом flush(), после сразу же разрешить.
По аналогии с передатчиком нужно принудительно очищать весь аппаратный буфер приемника.
Если этого не делать, то указатель приема может отличаться от указателя передачи по выходу из flush. Это при условии, что flush вызывается в фоне задачи.
В принимающей задаче если используется счетный семафор RTOS, запрещать прерывания от приемника уже не нужно: по сути защиту от исчерпания буфера обеспечивает семафор.

Вот именно об этих критических секциях я и говорил.

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


--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
Go to the top of the page
 
+Quote Post
AVI-crak
сообщение Jun 11 2017, 10:47
Сообщение #133


Частый гость
**

Группа: Участник
Сообщений: 182
Регистрация: 16-10-15
Пользователь №: 88 894



Цитата(Forger @ Jun 11 2017, 16:22) *
Я же пытаюсь донести, что не все тут так просто.

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

А для USART кольцевой буфер мало подходит, для него необходимо иметь два линейных!!! Переписывать данные в ручном режиме, дабы дма могло нормально работать.
(я охреневаю от всплывающих подробностей twak.gif )
Go to the top of the page
 
+Quote Post
Forger
сообщение Jun 11 2017, 11:02
Сообщение #134


Профессионал
*****

Группа: Свой
Сообщений: 1 215
Регистрация: 22-02-05
Пользователь №: 2 831



Цитата(AVI-crak @ Jun 11 2017, 13:47) *
Сначала проверяем свободное место, потом пишем данные, потом переписываем указатель.
Сначала проверяем наличие данных, потом их читаем, потом переписываем указатель.

Я именно так и делаю, но прерывания временно запрещаю, т. к. между проверкой и изменением указателя проходит время, в которое может влезть прерывание, которое обращается к тем же указателям.
Без эти временных запретов в одном из моих старых проектов вылезала редкая и потому очень трудноуловимая ошибка (((

Цитата
А для USART кольцевой буфер мало подходит,
У меня два кольцевых буфера - один на прием, другой на передачу.
Каждый буфер работает независимо от другого. По сути они ничего не знают друг о друге. Временно запрещают прерывания только от своих источников.
Более того, обе задачи, которые разгребают эти буферы, тоже ничего не знают друг о друге.
Приемная задача разгребает свою очередь, проверяя контрольные суммы, заголовки и т.п.
Передающая задача наоборот, все это упаковывает и отправляет на передачу.
Задачи выше работают с этими задачами на уровне логических пакетов, ни как не связанных со средой передачи.
Разумеется, реализованы механизмы таймаута как между пакетами, а так и между байтами. Контроль битых пакетов. Перезапуск разорванной и восстановленной связи.
В итоге любые сбои в канале связи никогда не вызывают опасных непредсказуемых глюков в приложении.




--------------------
Кругозор некоторых людей - круг с нулевым радиусом. Они называют его "точкой зрения".
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Jun 11 2017, 11:06
Сообщение #135


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(Forger @ Jun 11 2017, 15:22) *
Именно!

Вы поразительный человек! Вроде как уже всё объяснено, разжёвано до мельчайших подробностей, и тут вы с репликой "Именно!" начинаете всю канитель по-новой. Я так общаться не могу, чесслово.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post

10 страниц V  « < 7 8 9 10 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 21st July 2025 - 22:15
Рейтинг@Mail.ru


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