Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Запрет/Разрешение прерываний в кольцевых буферах
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Smallday
Пожалуйста, подскажите как правильно и оптимально Запрешать/Разрешать прерывания при работе с программыми буферами устройств. Попробовал несколько вариантов:
1)
cpsr=DisableIRQ();

.... // работа с буфером

RestoreIRQ(cpsr);
2)
VICIntEnClr = 1 << UART0_INT;

.... // работа с буфером

VICIntEnable = 1 << UART0_INT;
3)
cpsr=DisableIRQ();
U0IER &= ~UIER_ETBEI;
RestoreIRQ(cpsr);

.... // работа с буфером

cpsr=DisableIRQ();
U0IER |= UIER_ETBEI;
RestoreIRQ(cpsr);

Второй случай давал сбои и зависание на LPC2138, а вот на LPC2368 работаспособен..
sensor_ua
запрет источника прерывания приводит к потере запроса прерывания, возникшего во время запрета. При глобальном запрещении прерываний запросы прерываний взводят флаги, и если они не сброшены до глобального разрешения прерываний, то после разрешения срабатывает логика контроллера прерваний и вызываются соответствующие обработчики в установленном этой логикой порядке (логика зависит от типа контроллера прерываний или конкретного решения конкретного микроконтроллера, а общий механизм един для процессорных систем). Так что второй вариант не годится.
ИМХО, в русском техническом языке существуют как минимум такие понятия как источник прерывания, запрос прерывания, контроллер прерывания, обработчик прерывания, а вот само слово прерывание в разных контекстах обозначает разное сочетание этих понятий (к моему сожалению всё чаще русскоязычные словосочетания забываются и с английского переводится без учёта контекста). А глобальное разрешение прерываний грубо относится к "кнопке" управления контроллера прерываний со стороны процессора (ядра), которая в случае запрета на время как бы придерживает выдачу запроса прерывания от контроллера прерывания к ядру (в случае с ARM это, например, IRQ со своим запретом и FIQ со своим запретом).
Что касается буферов, то они бывают разными и есть варианты построения и дисциплины работы, не требующие запрета прерываний.
Что касается вариантов 1 и 3, то существуют разные подходы в части использования и способов входа/выхода в/из критических секций и это отдельный вопрос, по которому на форуме было достаточно много обсуждений.
tag
Цитата(sensor_ua @ Jun 18 2008, 09:29) *
запрет источника прерывания приводит к потере запроса прерывания, возникшего во время запрета.


...Вы уверены? Потеря запроса прерывания может произойти в том случае если имеется запрос на данный момент времени (по каким либо причинам не получивший обработку) и появился следующий запрос от этого же источника прерывания. Таким образом риск потери запроса прерывания возникает в том случае когда время обработки прерывания (и/или время реакции на прерывание) превышает минимально-возможное время между двумя запросами.
sensor_ua
Цитата
...Вы уверены?

Абсолютно. Толко я чуть ошибся с контекстом. Читать "запрет обработки запроса прерывания", хотя и при запрете источника будет так же не работать.
Вопрос же скорости обработки запросов и их потерь при неуспевании, ИМХО, суть другой вопрос.
tag
Цитата(sensor_ua @ Jun 18 2008, 10:13) *
Читать "запрет обработки запроса прерывания",


мне кажется сути это не меняет. А вы попробуйте запретить прервание по приему от UART и отправьте на него символ, а потом разрешите прерывание и посмотрите что получится
aaarrr
Цитата(sensor_ua @ Jun 18 2008, 09:29) *
запрет источника прерывания приводит к потере запроса прерывания, возникшего во время запрета.

Да ну?! Посмотрите хотя бы картинку Interrupt request logic в описании VIC'а.
sensor_ua
Цитата
Посмотрите хотя бы картинку Interrupt request logic в описании VIC'а.

Смотрю документ
http://infocenter.arm.com/help/topic/com.a...81e/DDI0181.pdf Figure 2-2 и триггеров не наблюдаю. Читаем до того на стр. 20 примечание
The VIC does not handle interrupt sources with transient behavior. For example, an
interrupt is asserted and then deasserted before software can clear the interrupt source. ... However, when a transient interrupt occurs, the priority logic of
the VIC is not set ...
Может я, конечно чего не понимаю, но в LPC2138, например, для источника прерывания по ExtInt проложен регистр (триггеры) ДО VIC (смотрю UM LPC2138 раздел 5-2 External Interrupt Flag register) и если выходы таких регистров служат запросами прерывания, то, естественно, если триггер не сбросишь, то запросы прерывания на соответствующих входах Interrupt Request Logic VIC будет активны.
aaarrr
Цитата(sensor_ua @ Jun 18 2008, 11:19) *
Смотрю документ
http://infocenter.arm.com/help/topic/com.a...81e/DDI0181.pdf Figure 2-2 и триггеров не наблюдаю.

Зато у UART'а они имеются, как и у >90% других источников.

Просто ваши слова можно было истолковать так, как будто в ситуации "запретили прерывание->получили запрос->разрешили прерывание" запрос будет в любом случае потерян, что неверно.
Rst7
Цитата
Что касается буферов, то они бывают разными и есть варианты построения и дисциплины работы, не требующие запрета прерываний.


А можно примерчик такого?
tag
Цитата(Rst7 @ Jun 18 2008, 13:56) *
А можно примерчик такого?


...вот пример кольцевого буфера не требующего запрета прерываний

struct
{
U8 in;
U8 out;
U8 data [256];
} buf;


void init_buf(void)
{
buf.in = buf.out;
}



void isr_rx(void)
{
U8 c;
...

if ((U8)(buf.in + 1) != buf.out) buf.data [buf.in++] = c;
else return;
}


void main(void)
{
U8 c;

...

if (buf.in != buf.out) c = buf.data[buf.out++];

...

}

Rst7
Цитата
..вот пример кольцевого буфера не требующего запрета прерываний


Да, такая конструкция работает. По причине атомарности добавления. А вот аналогиная передача - работать не будет.
rezident
Для кольцевых буферов я лично использую два индекса - один индекс для чтения, другой для записи. Ну и счетчик еще. Счетчик индицирует количество элементов в буфере. При записи сначала происходит запись в буфер, затем инкремент индекса, затем инкремент счетчика. При чтении - сначала извлечение из буфера, затем декремент счетчика, затем инкремент индекса. Естественно при изменениях и индексы и значение счетчика каждый раз проверяются на выход за границы диапазона буфера.
Rst7
А можно пример кода?
mdmitry
Идея кольцевых буферов и код есть в avr-lib. У меня на его основе сделаны кольцевые буферы USART, но для AVR. Идею можно перенести на любую платформу.
Rst7
Цитата
Идея кольцевых буферов и код есть в avr-lib


Да где ее только нет. Я и сам могу десяток реализаций разных сделать (и делал). Я к тому веду, что в общем случае, при работе с кольцевыми буферами необходима атомарная RMW-операция с памятью хотя-бы в одном месте. С учетом того, что на RISC-процах нет столь любимого на PDP11 INC и DEC прямо ячейки памяти, получается, что необходимо уметь запрещать/разрешать прерывания (или переключение задач в общем случае). Кстати, в ARM есть комманда SWP для управления семафорами (она как раз RMW), только я не могу пока придумать, как ее использовать для циклических буферов.
AHTOXA
Цитата(rezident @ Jun 18 2008, 20:21) *
Для кольцевых буферов я лично использую два индекса - один индекс для чтения, другой для записи. Ну и счетчик еще.


Я тоже так делаю :-) Но всё равно, изменение значения счётчика приходится выполнять при запрещённых прервыаниях, ибо операция не атомарная.


Цитата(Rst7 @ Jun 18 2008, 23:11) *
Я к тому веду, что в общем случае, при работе с кольцевыми буферами необходима атомарная RMW-операция с памятью хотя-бы в одном месте. С учетом того, что на RISC-процах нет столь любимого на PDP11 INC и DEC прямо ячейки памяти, получается, что необходимо уметь запрещать/разрешать прерывания (или переключение задач в общем случае).


Во-воsmile.gif
defunct
Цитата(Rst7 @ Jun 18 2008, 15:02) *
>> if ((U8)(buf.in + 1) != buf.out) buf.data [buf.in++] = c;

Да, такая конструкция работает. По причине атомарности добавления. А вот аналогиная передача - - работать не будет.


Это еще почему?! Еще как будет работать. По причине того что in++ делается уже после того как байт добавлен в очередь.

Предположим передатчик прервал фоновую задачу в любой момент выполнения

if ((U8)(buf.in + 1) != buf.out) buf.data [buf.in++] = c;

Если индекс "in" соответвует разрядности процессора, и будет записан в память одной командой ST тогда будем иметь только три возможные комбинации в обработчике прерывания:

buf.in == buf.out нет новых данных (ничего не отправлено)
buf.in == buf.out есть новые данные (ничего не отправлено, т.к. индексы говорят об отсутсвии данных)
buf.in != buf.out есть новые данные (берем сколько можно пока out != in)

Все комбинации безопасны.

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

Для работоспособности этой конструкции необходимо
- чтобы данные шли всегда из одного и того же источника (задачи)
- забирались всегда одним и тем же адресатом (задачей)
(источник и адресат - могут быть разными задачами)
и достаточно атомарности обновления индекса (запись одной командой ST), т.е. индекс не может быть большей разрядности чем разрядность регистров процессора. Все остальное не важно.
tag
Цитата(Rst7 @ Jun 18 2008, 16:02) *
Да, такая конструкция работает. По причине атомарности добавления. А вот аналогиная передача - работать не будет.

...и передача тоже будет работать и по причине атомарности в том числе
Rst7
Цитата
Это еще почему?! Еще как будет работать.


Да, согласен. Тут я погорячился, но...

Цитата
Для работоспособности этой конструкции необходимо - чтобы данные шли всегда из одного и того же источника (задачи)


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

В общем случае я бы такую задачу формулировал и решал с точки зрения минимизации нахождения в состоянии с запрещенными прерываниями.
tag
...скажу даже больше, так реализован обмен с модемом в библиотеке TCP/IP для ARM от Keil-а кажется
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.