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

 
 
 
Reply to this topicStart new topic
> Глобальное прерывание, возможно ли?
Yaumen
сообщение Nov 5 2009, 13:32
Сообщение #1


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

Группа: Свой
Сообщений: 187
Регистрация: 22-06-05
Из: Минск, Беларусь
Пользователь №: 6 213



В очередной раз натолкнулся на проблему. В этот раз связанную с прерываниями.

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

Есть ли решение в этой ситуации или надо полностью менять подход при работе с очередью?
Go to the top of the page
 
+Quote Post
_dem
сообщение Nov 5 2009, 13:43
Сообщение #2


Местный
***

Группа: Свой
Сообщений: 263
Регистрация: 2-02-07
Из: CN, Ukraine
Пользователь №: 24 970



"В этом процессоре" - это в Athlon X2 5400 ?
Go to the top of the page
 
+Quote Post
sergeeff
сообщение Nov 5 2009, 13:52
Сообщение #3


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

Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007



Да, очень интересно, что это за процессор, у которого нет команд разрешить/запретить прерывания? Надо же так спрашивать ни о чем?
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Nov 5 2009, 13:53
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Если речь идет о глобальном разрешении/запрещении прерываний на уровне ядра, то заведуют этим биты I и F регистра PSR для IRQ и FIQ соответственно. Управляются из-под C посредством intrinsic функций (типа __disable_irq(), __enable_irq() и т.п).
Go to the top of the page
 
+Quote Post
sergeeff
сообщение Nov 5 2009, 13:56
Сообщение #5


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

Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007



Вообще-то для этого существуют критические секции. В scmRTOS, к примеру, сделан для этого простенький, но очень удобный С++ класс. Основное отличие критической секции от просто запрета/разрешения состоит в том, что критическая секция на входе запоминает текущее состояние прерывания, а на выходе его восстанавливает, что более правильно в данном случае.
Go to the top of the page
 
+Quote Post
_dem
сообщение Nov 5 2009, 15:25
Сообщение #6


Местный
***

Группа: Свой
Сообщений: 263
Регистрация: 2-02-07
Из: CN, Ukraine
Пользователь №: 24 970



Позволю себе подправить - запоминает текущее состояние контроллера прерывания, а главное - pending interrupts. И при выходе из секции делает текущему OR с сохраненным.
Автору топика - вообще почитайте внимательно про ядро ARM и контроллер прерываний в вашем конкретном Атлоне smile.gif - сэкономите массу времени и анальгина в будущем.
Go to the top of the page
 
+Quote Post
defunct
сообщение Nov 6 2009, 16:15
Сообщение #7


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Цитата(Yaumen @ Nov 5 2009, 15:32) *
Есть ли решение в этой ситуации или надо полностью менять подход при работе с очередью?

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

Код
typedef struct tagQUEUE
{
     volatile int put;
     volatile int get;
     int cnt;
     PVOID *pStorage;
} TQUEUE, *PQUEUE;

void queue_define( PQUEUE pq, PVOID storage, int storage_size)
{
    pq->cnt = storage_size / sizeof( PVOID );
    pq->put = pq->get = 0;
    pq->pStorage = storage;
}

PVOID queue_read( PQUEUE pq )
{
    PVOID retval = NULL;
    if (pq->get != pq->put)
    {  // got smth to read
         int new_index = pq->get + 1;
         if (new_index >= pq->cnt)
             new_index = 0;
         retval = pq->pStorage[ pq->get ];
         pq->get = new_index;
     }
     return retval;
}

void queue_write( PQUEUE pq, PVOID msg )
{
     int new_index = pq->put + 1;
     if (new_index >= pq->cnt)
         new_index = 0;
     pq->pStorage[ pq->put ] = msg;  // <-- эта операция защищена, т.к. индекс put еще не изменился, функция чтения не знает о наличии новой записи
     pq->put = new_index;  // <-- здесь требуется атомарная модификация индекса, т.е. чтобы переменная  put записалась одной асм командой (отсюда переменная put не может быть разрядностью больше чем разрядность регистров процессора).
}
Go to the top of the page
 
+Quote Post
sergeeff
сообщение Nov 6 2009, 16:30
Сообщение #8


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

Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007



Цитата(defunct @ Nov 6 2009, 19:15) *
Очереди (направленные очереди если быть точнее) можно организовать так, что запрет прерываний непотребуется.


У автора нет никаких очередей. Где-то в цикле в main() чего обрабатывается, а по прерыванию - заполняется. При таком подходе поможет только механизм критических секций.

Цитата(_dem)
Позволю себе подправить - запоминает текущее состояние контроллера прерывания, а главное - pending interrupts. И при выходе из секции делает текущему OR с сохраненным.


Если запрещать/восстанавливать глобальное прерывание на уровне процессора, то в контроллере прерываний все автоматом запоминается/выполняется и нет никакого смысла на уровне контроллера прерываний усложнять себе жизнь.
Go to the top of the page
 
+Quote Post
defunct
сообщение Nov 6 2009, 16:41
Сообщение #9


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Цитата(sergeeff @ Nov 6 2009, 18:30) *
У автора нет никаких очередей.

Будьте внимательнее, в самом первом посте написано:
Цитата
я организовал очередь сообщений, которая пополняется вызовом метода AddMessage


А по поводу
Цитата
Где-то в цикле в main() чего обрабатывается, а по прерыванию - заполняется. При таком подходе поможет только механизм критических секций.

см. код выше. Гарантирую что он будет работать так как надо без крит секций и запрета прерываний.
Go to the top of the page
 
+Quote Post
sergeeff
сообщение Nov 6 2009, 17:04
Сообщение #10


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

Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007



Цитата(defunct @ Nov 6 2009, 19:41) *
Гарантирую что он будет работать так как надо без крит секций и запрета прерываний.


А как вы собираетесь добиться атомарности в операции модификация индекса без запрета прерываний? Если бы в левой части оператора присвоения стояла бы локальная переменная той же размерности , что и переменная слева от оператора присвоения - вопросов нет. Но слева - член структуры. И все зависит от того как конкретный компилятор при определенных опциях оттранслирует это присваивание. Да, скорее всего - атомарно. Но не факт, что это будет выполняться всегда и везде.
Go to the top of the page
 
+Quote Post
defunct
сообщение Nov 6 2009, 17:07
Сообщение #11


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Цитата(sergeeff @ Nov 6 2009, 19:04) *
А как вы собираетесь добиться атомарности в операции модификация индекса без запрета прерываний?

там написано:
(отсюда переменная put не может быть разрядностью больше чем разрядность регистров процессора)
к get это тоже относится

Цитата
И все зависит от того как конкретный компилятор при определенных опциях оттранслирует это присваивание.

Не важно сколько команд уйдет на выполнение Сишной конструкции
pq->put = new_index;

важно, чтобы именно запись (STR) осуществилась атомарно. т.е. чтобы переменная put ни при каких условиях не оказалась в памяти "частично модифицированной". А для этого достаточно сделать ее шириной в регистр проца и пользовать соответвующее выравнивание (чтобы компилятор не дробил инструкцию записи напр STR на несколько инструкций STRB).
Go to the top of the page
 
+Quote Post
sergeeff
сообщение Nov 6 2009, 17:24
Сообщение #12


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

Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007



Действительно не дурно!
Go to the top of the page
 
+Quote Post
Yaumen
сообщение Nov 10 2009, 07:13
Сообщение #13


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

Группа: Свой
Сообщений: 187
Регистрация: 22-06-05
Из: Минск, Беларусь
Пользователь №: 6 213



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

Теперь относитьно вопроса. Я сейчас работаю с LPC2366 поэтому этот вопрос касался именно его, понятно, что этого в самом сообщении не видно, поэтому так же извиняюсь.
unsure.gif

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

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

Сейчас "очередь" используется при работе с CAN. ID CAN побитово разбит так, что в нем уживаются ID кому, ID от кого и индекс фрагмента сообщения (для сообщений с длиной более 8-ми байт). Передающее устройство разбивает большое сообщение на фрагменты по 8-м байт и передает. Приемное устройство принимает и ориентируясь на IDs и индексы собирает сообщение. Так как на шине могут быть несколько передатчиков, то для каждого из них создается свой минибуферчик в общем большом массиве, выделенном для приема сообщений по CAN. После окончания приема по прерываниям, основной цикл забирает сообщение, которое необязательно может находиться в начале "очереди", при этом весь остальной массив перестраивается. Так вот чтобы индексация не нарушалась и требовалось запретить прерывание на время пока будет массив перестраиваться.
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 18th July 2025 - 20:00
Рейтинг@Mail.ru


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