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

 
 
4 страниц V   1 2 3 > »   
Reply to this topicStart new topic
> Возможность использования OS::channel в прерываниях
abutorin
сообщение Jan 13 2013, 19:25
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 40
Регистрация: 3-09-12
Пользователь №: 73 374



Добрый вечер.
Пробую сделать передачу по USART с использование буфера. Для межпроцессорного удобства очень нравится использовать OS::channel. Возможно ли его использовать и в прерываниях? Точнее интересует процедура получения элемента из канала?
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Jan 13 2013, 20:45
Сообщение #2


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

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



Использовать канал в прерывании можно. Учтите только, что если вы в него что-то заталкиваете, а он полон, то будет сделана попытка усыпить прерванный процесс и дождаться освобождения (или при доставании из пустого канала). Вероятно, это не то поведение, которое ожидается в прерыванииsm.gif
Поэтому проверяйте наличие свободного места при запихивании чего-то в канал, и наличие данных при доставании из канала.
Примерно вот так:
Код
void uart_t::irq_handler(){
    uint16_t status = USARTx->SR;
    if (status & USART_SR_RXNE){
        uint8_t ch = USARTx->DR;
        if (RxChannel.get_free_size())
            RxChannel.push(ch);
    }
            
    if (status & USART_SR_TXE){
        if (TxChannel.get_count()){
            char ch = 0;
            TxChannel.pop(ch);
            USARTx->DR = ch;
        }
        else
            disable_tx_interrupt();
    }
}


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
abutorin
сообщение Jan 14 2013, 02:40
Сообщение #3


Участник
*

Группа: Участник
Сообщений: 40
Регистрация: 3-09-12
Пользователь №: 73 374



Спасибо, проверку заполнености, проверку пустоты я уже учел.
Go to the top of the page
 
+Quote Post
Vasya777
сообщение Jan 15 2013, 15:07
Сообщение #4


Участник
*

Группа: Участник
Сообщений: 29
Регистрация: 22-01-12
Пользователь №: 69 790



Мне кажется для обмена по интерфейсам связи лучше использовать message, там есть специальный метод для вызова из прерываний. А уже в обычном процессе складывать сообщения в буфер. Поправьте, если я что-то не так сказал, я ещё новичёк.

Сообщение отредактировал Vasya777 - Jan 15 2013, 15:08
Go to the top of the page
 
+Quote Post
abutorin
сообщение Jan 15 2013, 19:16
Сообщение #5


Участник
*

Группа: Участник
Сообщений: 40
Регистрация: 3-09-12
Пользователь №: 73 374



Цитата(AHTOXA @ Jan 14 2013, 00:45) *
Использовать канал в прерывании можно. Учтите только, что если вы в него что-то заталкиваете, а он полон, то будет сделана попытка усыпить прерванный процесс и дождаться освобождения (или при доставании из пустого канала). Вероятно, это не то поведение, которое ожидается в прерыванииsm.gif
Поэтому проверяйте наличие свободного места при запихивании чего-то в канал, и наличие данных при доставании из канала.


Примерно так и делал.
Код
    
class usart_t
{
public:
    OS::channel<uint8_t,4> Rxbuf;
    OS::channel<uint8_t,4> Txbuf;
    USART_TypeDef * PORT;

INLINE void it_handler ()
    {

        if (USART_GetITStatus(this->PORT,USART_IT_TXE) != RESET)
        {
            {
                if(this->Txbuf.get_count())
                {
                    uint8_t data;
                    this->Txbuf.pop(data);
                    USART_SendData(this->PORT,data);
                }
                else
                {
                    USART_ITConfig(this->PORT, USART_IT_TXE, DISABLE);
                }

            }

            USART_ClearITPendingBit(this->PORT,USART_IT_TXE);
        }

    }

    void send(const uint8_t & data)
    {
        this->Txbuf.push(data);
        USART_ITConfig(this->PORT, USART_IT_TXE, ENABLE);

    }


Размер буфера 4 элемента. заполняю его в одном из потоков:
Код
        
      for(i=0;i<8;i++)
        {
            usart.send(i+0x30);
        }

        OS::sleep(1000);

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

Поэкспериментировал немного с размером буфера и размером отправляемых данных, если размер буфера поставить 5 и отправлять 8 байт то все работает нормально, размер буфера 14 количество отправляемых данных 16 тоже нормально. На лицо правило размер буфера = количество отправляемых данных - 2.

Сообщение отредактировал abutorin - Jan 15 2013, 19:03
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Jan 15 2013, 19:26
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Не знаю почему зависает, наверное что-то неправильно ...
Не пойму, в чём сермяга посать всюду this->?
Go to the top of the page
 
+Quote Post
abutorin
сообщение Jan 15 2013, 19:31
Сообщение #7


Участник
*

Группа: Участник
Сообщений: 40
Регистрация: 3-09-12
Пользователь №: 73 374



Цитата(_Артём_ @ Jan 15 2013, 23:26) *
Не знаю почему зависает, наверное что-то неправильно ...
Не пойму, в чём сермяга посать всюду this->?

Объектный подход, да можно былобы статичным класом обойтись, думаю это не критично.

Посмотрел поглубже, помоему нашел в чем проблема:
Код
template<typename T, uint16_t Size, typename S>
void OS::channel<T, Size, S>::push(const T& item)
{
    TCritSect cs;

    while(!pool.get_free_size())
    {
        // channel is full, suspend current process until data removed
        suspend(ProducersProcessMap);
    }

    pool.push_back(item);
    resume_all(ConsumersProcessMap);
}

Судя по коду, push выполняется с запретом прерывания. Как я понимаю работу TCritSect, запрет снимается в деструкторе, так вот деструктор не вызовется, т.к. потребитель канала находится в прерывании.
Получается что канал использовать с прерываниями не получится.
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Jan 15 2013, 20:10
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(abutorin @ Jan 15 2013, 21:31) *
Объектный подход,

Объектный - это хорошо, только this-> зачем всегда писать? попробуйте без него. Писанины меньше.

Цитата(abutorin @ Jan 15 2013, 21:31) *
Посмотрел поглубже, помоему нашел в чем проблема:

Проблема в отсутствии метода push_isr. А вот почему его нет - вопрос? Наверное руки недошли...Применять то можно судя по примерам выше.

Цитата(abutorin @ Jan 15 2013, 21:31) *
т.к. потребитель канала находится в прерывании.

Хуже того - будет усыплён процесс прерванный прерыванием (Idle например) и наверное не только это .
Go to the top of the page
 
+Quote Post
abutorin
сообщение Jan 15 2013, 20:14
Сообщение #9


Участник
*

Группа: Участник
Сообщений: 40
Регистрация: 3-09-12
Пользователь №: 73 374



Проблему решил использовав События:
Код
class usart
{
public:
    usr::ring_buffer<uint8_t, 10, uint8_t> TxPool;

    OS::TEventFlag TxNotFull;

    USART_TypeDef * PORT;

INLINE void it_handler ()
    {

        if (USART_GetITStatus(this->PORT,USART_IT_TXE) != RESET)
        {
            {
                if(this->TxPool.get_count())
                {
                    USART_SendData(this->PORT,this->TxPool.pop());
                    this->TxNotFull.signal_isr();
                }
                else
                {
                    USART_ITConfig(this->PORT, USART_IT_TXE, DISABLE);
                }
            }
            USART_ClearITPendingBit(this->PORT,USART_IT_TXE);
        }

    }

    INLINE bool full ()
    {
        TCritSect cs;

        return !this->TxPool.get_free_size();

    }

    void send(const uint8_t & data)
    {

        this->TxNotFull.clear();

        while (this->full())
        {
            this->TxNotFull.wait();
        }

        this->TxPool.push(data);

        USART_ITConfig(USART1, USART_IT_TXE, ENABLE);

    }

Решение черновое в плане оформления класа, но концептуально думаю досточно простое и надежное. Оно правда подразумевает что заполнять буфер будет только один поток, т.к. из средств синхронизации используется только критическая секция на проверку заполненности.

Цитата(_Артём_ @ Jan 16 2013, 00:10) *
Объектный - это хорошо, только this-> зачем всегда писать? попробуйте без него. Писанины меньше.

если писать this то IDE подставляет выбор членов класса ). Так что this писать зачастую короче чем помнить точное название члена.
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Jan 15 2013, 20:20
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(abutorin @ Jan 15 2013, 22:14) *
если писать this то IDE подставляет выбор членов класса ). Так что this писать зачастую короче чем помнить точное название члена.

На что только не пойдёт человек, лишь бы новое не осваивать.
IDE у вас какая-то устаревшая.

А IO-регистры подсказывает?
Go to the top of the page
 
+Quote Post
abutorin
сообщение Jan 15 2013, 20:24
Сообщение #11


Участник
*

Группа: Участник
Сообщений: 40
Регистрация: 3-09-12
Пользователь №: 73 374



Цитата(_Артём_ @ Jan 16 2013, 00:20) *
На что только не пойдёт человек, лишь бы новое не осваивать.
IDE у вас какая-то устаревшая.

А IO-регистры подсказывает?


Второйдовод писать всегда, этоодним взглядом на код понятно что это член класса а не какаянибудь переменная локальная. IDE у меня Eclipse под линуксом. Последнее время работают только с STM32 и использую стандартную библиотеку, до регистров решил не опускатся. Сейчас больше интересует "бизнес-логика" алгоритмов.
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Jan 15 2013, 20:52
Сообщение #12


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(abutorin @ Jan 15 2013, 22:24) *
Второйдовод писать всегда, этоодним взглядом на код понятно что это член класса а не какаянибудь переменная локальная.

Если писать всега this, то сомнений не возникнет...

Цитата(abutorin @ Jan 15 2013, 22:24) *
а не какаянибудь переменная локальная.

обычно так делаю
Код
if (local_variable != GlobalVariable)

, то есть через правила именования, но они у каждого свои, да.

Цитата(abutorin @ Jan 15 2013, 22:24) *
IDE у меня Eclipse под линуксом.

Ошибся, IDE - не устаревшая.

Цитата(abutorin @ Jan 15 2013, 22:24) *
Последнее время работают только с STM32 и использую стандартную библиотеку, до регистров решил не опускатся. Сейчас больше интересует "бизнес-логика" алгоритмов.


"решил не опускатся" или решил не подниматься?

Цитата(abutorin @ Jan 15 2013, 22:24) *
Сейчас больше интересует "бизнес-логика" алгоритмов.

Логика у вас... в смысле логика тоже дело...
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jan 15 2013, 22:46
Сообщение #13


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (abutorin @ Jan 15 2013, 21:31) *
Судя по коду, push выполняется с запретом прерывания. Как я понимаю работу TCritSect, запрет снимается в деструкторе, так вот деструктор не вызовется, т.к. потребитель канала находится в прерывании.
Прерывания будут разрешены во время suspend() при передаче управления другому процессу. Что касается вашей проблемы - мне кажется причина в том, что вы делаете USART_ClearITPendingBit(this->PORT,USART_IT_TXE); даже если данных не было и ничего не было передано. И когда данные в канале появляются - у процессора нет причин вызвать прерывание и отправить их. Хотя я не очень хорошо помню, как этот механизм (pending) работает в кортексах. Также полагаю, что объект типа OS::TCritSect вы в начале обработчика прерывания создаете. Если нет - это тоже может быть причиной.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
abutorin
сообщение Jan 16 2013, 03:29
Сообщение #14


Участник
*

Группа: Участник
Сообщений: 40
Регистрация: 3-09-12
Пользователь №: 73 374



Цитата(Сергей Борщ @ Jan 16 2013, 02:46) *
Прерывания будут разрешены во время suspend() при передаче управления другому процессу. Что касается вашей проблемы - мне кажется причина в том, что вы делаете USART_ClearITPendingBit(this->PORT,USART_IT_TXE); даже если данных не было и ничего не было передано. И когда данные в канале появляются - у процессора нет причин вызвать прерывание и отправить их. Хотя я не очень хорошо помню, как этот механизм (pending) работает в кортексах. Также полагаю, что объект типа OS::TCritSect вы в начале обработчика прерывания создаете. Если нет - это тоже может быть причиной.

USART_ClearITPendingBit(this->PORT,USART_IT_TXE); Это очистка признака возникновения прерывания, в у STM32 большинство битов (признаков) прерывания необходимо очищать вручную. Прерывание по USART_IT_TXE выключается командой USART_ITConfig(this->PORT, USART_IT_TXE, DISABLE); только в случае если канал пустой. А в процедуре которая заполняет канал send это прерывание всегда включаетсся.
USART_ITConfig(USART1, USART_IT_TXE, ENABLE);

Посмотрел еще раз
Код
   void OS::TService::suspend(TProcessMap volatile & waiters_map)
    {
        TProcessMap PrioTag = cur_proc_prio_tag();
    
        set_prio_tag(waiters_map, PrioTag);                   // put current process to wait map
        clr_prio_tag(ready_process_map(), PrioTag);           // remove current process from ready map
    
    #if scmRTOS_DEBUG_ENABLE == 1
        cur_proc_waiting_for() = this;                        // catch current service address to process debug data
    #endif

    #if scmRTOS_PROCESS_RESTART_ENABLE == 1
        cur_proc_waiting_map() = &waiters_map;
    #endif
        
        reschedule();
        
    #if scmRTOS_DEBUG_ENABLE == 1
        cur_proc_waiting_for() = 0;                           // remove current service address from process debug data
    #endif
        
    #if scmRTOS_PROCESS_RESTART_ENABLE == 1
        cur_proc_waiting_map() = 0;
    #endif
        
    }

void OS::channel<T, Size, S>::push(const T& item)
{
    TCritSect cs;

    while(!pool.get_free_size())
    {
        // channel is full, suspend current process until data removed
        suspend(ProducersProcessMap);
    }

    pool.push_back(item);
    resume_all(ConsumersProcessMap);
}

А в какой момент происходи включение прерываний? в suspend я не нашел включение прерываний.
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Jan 16 2013, 04:45
Сообщение #15


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(abutorin @ Jan 16 2013, 05:29) *
А в какой момент происходи включение прерываний? в suspend я не нашел включение прерываний.

В suspend произойдёт перепланировка (reschedule), запустится на выполнение очередной готовый процесс и где-то в конце этой процедуры будут разрешены прерывания.
Go to the top of the page
 
+Quote Post

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

 


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


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