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

 
 
> Возможность использования 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
4 страниц V   1 2 3 > »   
Start new topic
Ответов (1 - 54)
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
AHTOXA
сообщение Jan 16 2013, 05:05
Сообщение #16


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

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



TXE очищается записью в DR. Вручную его чистить не надо, он read-only.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jan 16 2013, 08:54
Сообщение #17


Гуру
******

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



QUOTE (abutorin @ Jan 16 2013, 05:29) *
USART_ClearITPendingBit(this->PORT,USART_IT_TXE); Это очистка признака возникновения прерывания, в у STM32 большинство битов (признаков) прерывания необходимо очищать вручную.
К сожалению я использую для передачи DMA, поэтому у меня нет примера для UART c каналом. Без ОС рабочий код у меня выглядит так:
CODE
INLINE void uart::handler()
{
    uint32_t Status = pUART->SR;
    Status &= pUART->CR1;   // mask disabled ints

    if(Status & USART_SR_RXNE)
    {
        uint8_t Data = pUART->DR;
        if(Rx_buffer.has_place())
            Rx_buffer.put(Data);
    }
    if(Status & USART_SR_TXE)
    {
        pUART->DR = Tx_buffer.get();
        if(!Tx_buffer.has_data())
            pUART->CR1 &= ~USART_CR1_TXEIE;
    }
}
Как видите, никаких ручных очисток.


QUOTE (abutorin @ Jan 16 2013, 05:29) *
А в какой момент происходи включение прерываний? в suspend я не нашел включение прерываний.
Из suspend() вызывается TKernelAgent::reschelule(), который в свою очередь вызывет TKernel::shed(), в котором есть такой код:
CODE
        do
        {
            enable_context_switch();
            DUMMY_INSTR();
            disable_context_switch();
        }
        while(CurProcPriority != SchedProcPriority); // until context switch done
Вот тут произойдет переключение на другой процесс, а уже этот процесс (если нет активных - то процесс Idle) выполняется с разрешенными прерываниями, т.е. при восстановлении его контекста прерывания будут разрешены.


--------------------
На любой вопрос даю любой ответ
"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
AHTOXA
сообщение Jan 16 2013, 10:18
Сообщение #18


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

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



Цитата(Сергей Борщ @ Jan 16 2013, 14:54) *
Код
    Status &= pUART->CR1;   // mask disabled ints

А это зачем? Чтобы не реагировать на RXNE и TXE при маскировке этих прерываний?


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jan 16 2013, 11:27
Сообщение #19


Гуру
******

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



QUOTE (AHTOXA @ Jan 16 2013, 12:18) *
А это зачем? Чтобы не реагировать на RXNE и TXE при маскировке этих прерываний?
Да, на все запрещенные. В данном случае на TXE. RXNE у меня не запрещается.


--------------------
На любой вопрос даю любой ответ
"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, 11:33
Сообщение #20


Участник
*

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



Цитата(Сергей Борщ @ Jan 16 2013, 12:54) *
К сожалению я использую для передачи DMA, поэтому у меня нет примера для UART c каналом.

У меня логика построена на том, что я с уартом работаю как с потоком байт, я не знаю сколько байт отправляюи сколько получу. Если даже с таким подходом это можно реализовать через DMA то был бы очень признателен за пример.
Если с прерываниями стало ясно.то опять возникает вопрос в чем же тогда проблема?
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Jan 16 2013, 13:52
Сообщение #21


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

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



Цитата(Сергей Борщ @ Jan 16 2013, 17:27) *
Да, на все запрещенные. В данном случае на TXE. RXNE у меня не запрещается.

У меня такого нет, и работает нормально. Это что получается, я при запрещённых прерываниях TXE всё равно каждый раз при входе в прерывание влетаю в эту ветку обработчика?
Проверил - точно, влетаю. Неаккуратненько...


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jan 17 2013, 10:15
Сообщение #22


Гуру
******

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



QUOTE (abutorin @ Jan 16 2013, 13:33) *
Если с прерываниями стало ясно.то опять возникает вопрос в чем же тогда проблема?
Вы заводите в начале обработчика объект типа OS::TISRW (я в предыдущем сообщении описался, указав его как OS::TCritSect)? Без него прерывание не сможет при необходимости вызвать перепланирование.

QUOTE (abutorin @ Jan 16 2013, 13:33) *
У меня логика построена на том, что я с уартом работаю как с потоком байт, я не знаю сколько байт отправляюи сколько получу. Если даже с таким подходом это можно реализовать через DMA то был бы очень признателен за пример.
Как-то так, хотя мне самому этот код не очень нравится:
CODE

//**** uart.h: *****
#ifndef UART_H__
#define UART_H__
#include <stdint.h>
#include <stm32f10x.h>
#include <scmRTOS.h>
#include <string.h>

#include <stdarg.h>
#include <stdio.h>

class uart
{
public:
uart(USART_TypeDef * usart, uint32_t dma_channel)
: Tx_ready(OS::TEventFlag::efOn)
, pUART(usart)
, DMA_channel_no(dma_channel - 1)
, DMA_channel((DMA_Channel_TypeDef *)(DMA1_Channel1_BASE + (dma_channel - 1) * 0x14))
{}

void send(const uint8_t &byte);
void send(char const * string);
void send(char * string, OS::TMutex * pLock);
void send_HEX(uint8_t data);
void send_HEX(uint16_t data);
void new_line();
void vprintf(char const * format, va_list args);
void printf(char const * format, ...);
bool is_transmitting() {return !(pUART->SR & USART_SR_TXE);}

bool hasinput() {return Rx_buffer.get_count();}
bool receive(uint8_t & data, timeout_t timeout);
bool receive(char & data, timeout_t timeout);
uint8_t receive() { uint8_t Data; Rx_buffer.pop(Data); return Data;}

void speed_setup(uint_fast32_t baudrate) { pUART->BRR = (PCLK1_FREQ + baudrate / 2) / baudrate; }
void tx_dma_handler();
void rx_handler();
protected:
static size_t const RX_BUFF_SIZE = 16;

OS::TEventFlag Tx_ready;
uint8_t Tx_byte_buffer;
OS::TMutex Tx_byte_buffer_lock;

OS::TMutex Tx_buffer_lock;
char Tx_buffer[80];

OS::TMutex * pDMA_buffer_lock;
void setup_tx_dma(uint8_t const * pSrc, size_t size, OS::TMutex *pLock = 0);

OS::channel<uint8_t volatile, RX_BUFF_SIZE> Rx_buffer;
private:
USART_TypeDef * pUART;
uint_fast32_t DMA_channel_no;
DMA_Channel_TypeDef * DMA_channel;
};
// =========== receiving ==============
INLINE void uart::rx_handler()
{
uint8_t Data = pUART->DR;
if(Rx_buffer.get_free_size())
Rx_buffer.push(Data);
}

inline bool uart::receive(uint8_t & symbol, timeout_t timeout)
{
if(timeout <= 0 || !Rx_buffer.pop(symbol, timeout))
return false;
return true;
}

inline bool uart::receive(char & symbol, timeout_t timeout)
{
uint8_t data;
if(timeout <= 0 || !Rx_buffer.pop(data, timeout))
return false;
symbol = char(data);
return true;
}

// ========== transmitting ===========

INLINE void uart::tx_dma_handler()
{
DMA1->IFCR = DMA_IFCR_CTCIF1 << (4 * DMA_channel_no);
DMA_channel->CCR = 0
;
Tx_ready.signal_isr();
if(pDMA_buffer_lock)
pDMA_buffer_lock->unlock_isr();
}

#endif //UART_H__


//**** uart.cpp ******
#include "uart.h"
#include <string.h>

void uart::setup_tx_dma(uint8_t const * pSrc, size_t size, OS::TMutex * pLock)
{
Tx_ready.wait();
pDMA_buffer_lock = pLock;
// --------- DMA setup -----------
DMA_channel->CPAR = uintptr_t(&pUART->DR);
DMA_channel->CMAR = uintptr_t(pSrc);
DMA_channel->CNDTR = size;
DMA_channel->CCR = 0
| 1 * DMA_CCR1_EN // Channel enable
| 1 * DMA_CCR1_TCIE // Transfer complete interrupt enable
| 0 * DMA_CCR1_HTIE // Half Transfer interrupt enable
| 0 * DMA_CCR1_TEIE // Transfer error interrupt enable
| 1 * DMA_CCR1_DIR // Data transfer direction: Memory->Peripheral
| 0 * DMA_CCR1_CIRC // Circular mode
| 0 * DMA_CCR1_PINC // Peripheral increment mode
| 1 * DMA_CCR1_MINC // Memory increment mode
| 0 * DMA_CCR1_PSIZE_0 // Peripheral size: 8 bits
| 0 * DMA_CCR1_MSIZE_0 // Memory size: 8 bits
| 1 * DMA_CCR1_PL_0 // Channel Priority level: higher than lowest, conversion frequency is low enough
| 0 * DMA_CCR1_MEM2MEM // Memory to memory mode disabled
;

}

void uart::send(uint8_t const &byte)
{
Tx_byte_buffer_lock.lock();
Tx_byte_buffer = byte;
setup_tx_dma(&Tx_byte_buffer, 1, &Tx_byte_buffer_lock);
}

void uart::send(char const * pString)
{
setup_tx_dma((uint8_t const *)pString, strlen(pString));
}

void uart::send(char * pString, OS::TMutex * pLock)
{
setup_tx_dma((uint8_t const *)pString, strlen(pString), pLock);
}

void uart::vprintf(char const * format, va_list args)
{

Tx_buffer_lock.lock();
vsprintf (Tx_buffer, format, args);
send(Tx_buffer, &Tx_buffer_lock);
}

void uart::printf(char const * format, ...)
{
va_list args;
va_start (args, format);
uart::vprintf (format, args);
va_end (args);
}


uart Serial(USART2, 7);
uart & Console = Serial;


extern "C" void DMA1_Channel7_IRQHandler(void)
{
OS::TISRW ISR_wrapper;
Console.tx_dma_handler();
}

extern "C" void USART2_IRQHandler(void)
{
OS::TISRW ISR_wrapper;
Console.rx_handler();
}

Тут готовность DMA передается через флаг Tx_ready, а буфер передачи (если он используется для данной посылки) защищен мутексом Tx_byte_buffer_lock. Если же передается готовая строка из флеша или ОЗУ - буфер не используется.


--------------------
На любой вопрос даю любой ответ
"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 17 2013, 12:25
Сообщение #23


Участник
*

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



Цитата(Сергей Борщ @ Jan 17 2013, 14:15) *
Как-то так, хотя мне самому этот код не очень нравится:


Да, я понял. Но мои вопросы этот метод нерешит т.к. посылка делается по одному байту (как поток), тут изначально нельзя знать какой объем займет посылка. Плохо что DMA не умеет работать как кольцевой буфер. Тогда хотябы можно было накапливать данные и отсылать по таймауту в случае отсутствия новых.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jan 17 2013, 13:12
Сообщение #24


Гуру
******

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



QUOTE (abutorin @ Jan 17 2013, 14:25) *
Плохо что DMA не умеет работать как кольцевой буфер.
Некое подобие можно сформировать. Укладывать данные в кольцевой буфер, а по таймауту или в прерывании окончания DMA перезагружать регистры DMA на очередной готовый участок этого буфера.


--------------------
На любой вопрос даю любой ответ
"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 17 2013, 13:20
Сообщение #25


Участник
*

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



Цитата(Сергей Борщ @ Jan 17 2013, 17:12) *
Некое подобие можно сформировать. Укладывать данные в кольцевой буфер, а по таймауту или в прерывании окончания DMA перезагружать регистры DMA на очередной готовый участок этого буфера.

Боюсь тогда алгоритм получится очень сложный а сказать уверенно что прерываний станет сильно меньше не получится, здесь наверное проще тогда сдлеать через накопление буфера и отправкой потом через ДМА когда буфер переполнен или по таймауту если данных больше нет.
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Jan 17 2013, 18:31
Сообщение #26


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

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



Насчёт работы с UART по DMA вот вам три темы:

Там немножко разные подходы, выберите подходящий.
Я делал по примеру от kan35 в конце третьей темы, работает.


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


Участник
*

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



Цитата(AHTOXA @ Jan 17 2013, 22:31) *
Насчёт работы с UART по DMA вот вам три темы:

Там немножко разные подходы, выберите подходящий.
Я делал по примеру от kan35 в конце третьей темы, работает.

Спасибо, понял что нужно копать в направлении режима cilcularmode DMA. Попробую потом на досуге, сейчас сделал прием и передачу через прерывания. Код передачи выкладывал выше, прием сделал по образу и подобию, На ненагруженном камне прием уверенный на скорости в 0,5 мбит/с
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jan 18 2013, 07:41
Сообщение #28


Гуру
******

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



QUOTE (abutorin @ Jan 18 2013, 07:37) *
Спасибо, понял что нужно копать в направлении режима cilcularmode DMA.
Ой. Вам ведь не нужно, чтобы УАСПП постоянно повторял содержимое всего буфера, включая мусор.
QUOTE (abutorin @ Jan 18 2013, 07:37) *
сейчас сделал прием и передачу через прерывания.
А в чем причина была, почему не работало? Обычно принято сообщать - чтобы тот, кто будет потом искать решение своей подобной проблемы нашел ответ, да и отвечавшим вам тоже любопытно - кто из них угадал sm.gif


--------------------
На любой вопрос даю любой ответ
"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 18 2013, 09:14
Сообщение #29


Участник
*

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



Цитата(Сергей Борщ @ Jan 18 2013, 11:41) *
Ой. Вам ведь не нужно, чтобы УАСПП постоянно повторял содержимое всего буфера, включая мусор.


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

Цитата(Сергей Борщ @ Jan 18 2013, 11:41) *
А в чем причина была, почему не работало? Обычно принято сообщать - чтобы тот, кто будет потом искать решение своей подобной проблемы нашел ответ, да и отвечавшим вам тоже любопытно - кто из них угадал sm.gif

Код я выкладывал ранее. Я в итоге сделал без канала. Пришел к выводу что канал больше предназначен для межпроцессного взаимодействия, а в случае с УСАПП это больше ожидание одним потоком выполнения некоторого действия переферией. Доберусь до дома выложу код полностью.
Go to the top of the page
 
+Quote Post
abutorin
сообщение Jan 18 2013, 18:52
Сообщение #30


Участник
*

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



Как обещал ранее выкладываю код который у меня работает.

Код
class usart_transport
{
private:
    usr::ring_buffer<uint8_t, 30, uint8_t> TxPool;
    usr::ring_buffer<uint8_t, 30, uint8_t> RxPool;

    OS::TEventFlag TxNotFull;
    OS::TEventFlag RxNotEmpty;

public:

    USART_TypeDef * PORT;

    bool open (bool)
    {
        USART_ITConfig(this->PORT, USART_IT_RXNE, ENABLE);
        return true;
    }

    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);
        }

        if (USART_GetITStatus(this->PORT,USART_IT_RXNE) != RESET)
        {
            if (this->RxPool.get_free_size())
            {
                this->RxPool.push(USART_ReceiveData(this->PORT));
                this->RxNotEmpty.signal_isr();
            }
            else
            {
                //здесь должна быть обработка переполнения буфера
            }
            USART_ClearITPendingBit(this->PORT,USART_IT_RXNE);
        }

    }

    INLINE bool full ()
    {
        TCritSect cs;

        return !this->TxPool.get_free_size();

    }
    INLINE bool empty ()
    {
        TCritSect cs;

        return !this->RxPool.get_count();
    }

    void send(const uint8_t & data)
    {
        this->TxNotFull.clear();

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

        {
            TCritSect cs;
            this->TxPool.push(data);
        }

        USART_ITConfig(this->PORT, USART_IT_TXE, ENABLE);
    }

    uint8_t get ()
    {
        this->RxNotEmpty.clear();

        while (this->empty())
        {
            this->RxNotEmpty.wait();
        }

        TCritSect cs;

        return this->RxPool.pop();
    }
};

Отказ от канала в результате вызван тем, что канал больше предназначен для межпроцессного взаимодействия а не между процессом и прерыванием. Инициализацию порта необходимо выполнять самостоятельно. Сразу хочу заметить что данная реализация сделана на коленке и имеет достаточный потенциал для улучшения, сразу видно что целесообразно сделать данный класс через шаблон со статичными членами, с указанием порта как параметра и использовать данные методы без создания экземпляра класса.
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Jan 19 2013, 04:43
Сообщение #31


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

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



USART_ClearITPendingBit(this->PORT,USART_IT_TXE); - бессмысленная операция. (как я уже писал выше, этот флаг не сбрасывается программно, он read-only).
USART_ClearITPendingBit(this->PORT,USART_IT_RXNE); - лучше перенести в ветку else.
Ну а вообще, OS::channel делает всё то же самое, так что это в некотором роде "закат солнца вручную":)
Цитата(abutorin @ Jan 19 2013, 00:52) *
канал больше предназначен для межпроцессного взаимодействия а не между процессом и прерыванием.

Можете обосновать это утверждение?


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


Участник
*

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



Цитата(AHTOXA @ Jan 19 2013, 08:43) *
USART_ClearITPendingBit(this->PORT,USART_IT_TXE); - бессмысленная операция. (как я уже писал выше, этот флаг не сбрасывается программно, он read-only).

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

Цитата(AHTOXA @ Jan 19 2013, 08:43) *
USART_ClearITPendingBit(this->PORT,USART_IT_RXNE); - лучше перенести в ветку else.

В какую ветку? Очистка флага нужно всегда когда прерываниеуже обработано.
Цитата(AHTOXA @ Jan 19 2013, 08:43) *
Ну а вообще, OS::channel делает всё то же самое, так что это в некотором роде "закат солнца вручную":)

Можете обосновать это утверждение?


У OS::channel есть дополнительные члены для хранения списка производителей и потребителей, у него более крупная процедура получения первого элемента. Это все годится для межпроцессного взаимодействия, в моем случае все проще и статичнее.
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Jan 19 2013, 17:42
Сообщение #33


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

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



Цитата(abutorin @ Jan 19 2013, 23:19) *
В какую ветку? Очистка флага нужно всегда когда прерываниеуже обработано.

Код
            if (this->RxPool.get_free_size())
            {
                this->RxPool.push(USART_ReceiveData(this->PORT)); //  в этой ветке флаг сбрасывается вот этой строчкой
                this->RxNotEmpty.signal_isr();
            }
            else
            {
                //здесь должна быть обработка переполнения буфера
                USART_ClearITPendingBit(this->PORT,USART_IT_RXNE);  // << вот сюда
            }
            // USART_ClearITPendingBit(this->PORT,USART_IT_RXNE); // << отсюда.

Всё же почитайте документацию, использование библиотек не отменяет необходимости её читать. Тогда всё будет работать как надо.
Цитата(abutorin @ Jan 19 2013, 23:19) *
У OS::channel есть дополнительные члены для хранения списка производителей и потребителей, у него более крупная процедура получения первого элемента. Это все годится для межпроцессного взаимодействия, в моем случае все проще и статичнее.

Взамен этих членов вы завели пару штук OS::TEventFlag (TxNotFull, RxNotEmpty). Это явно тяжелее. С остальным тоже не согласен. Но это, конечно, дело вкуса.


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


Участник
*

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



Цитата(AHTOXA @ Jan 19 2013, 21:42) *
Код
            if (this->RxPool.get_free_size())
            {
                this->RxPool.push(USART_ReceiveData(this->PORT)); //  в этой ветке флаг сбрасывается вот этой строчкой
                this->RxNotEmpty.signal_isr();
            }
            else
            {
                //здесь должна быть обработка переполнения буфера
                USART_ClearITPendingBit(this->PORT,USART_IT_RXNE);  // << вот сюда
            }
            // USART_ClearITPendingBit(this->PORT,USART_IT_RXNE); // << отсюда.

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

Взамен этих членов вы завели пару штук OS::TEventFlag (TxNotFull, RxNotEmpty). Это явно тяжелее. С остальным тоже не согласен. Но это, конечно, дело вкуса.

В случае использования OS::channel в какой момент будет вызыватся перепланировка процессов?
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Jan 19 2013, 18:13
Сообщение #35


Гуру
******

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



Цитата(abutorin @ Jan 19 2013, 19:56) *
В случае использования OS::channel в какой момент будет вызыватся перепланировка процессов?

Если речь о прерываниях, то перепланировка вызовется в ISR_Exit в любом случае.
Go to the top of the page
 
+Quote Post
abutorin
сообщение Jan 19 2013, 18:42
Сообщение #36


Участник
*

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



Цитата(AHTOXA @ Jan 19 2013, 21:42) *
Код
            if (this->RxPool.get_free_size())
            {
                this->RxPool.push(USART_ReceiveData(this->PORT)); //  в этой ветке флаг сбрасывается вот этой строчкой
                this->RxNotEmpty.signal_isr();
            }
            else
            {
                //здесь должна быть обработка переполнения буфера
                USART_ClearITPendingBit(this->PORT,USART_IT_RXNE);  // << вот сюда
            }
            // USART_ClearITPendingBit(this->PORT,USART_IT_RXNE); // << отсюда.

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

Взамен этих членов вы завели пару штук OS::TEventFlag (TxNotFull, RxNotEmpty). Это явно тяжелее. С остальным тоже не согласен. Но это, конечно, дело вкуса.

Решил последовать вашим рекомендациям и проверить оба варианта, свой и с использовапние канала

Код
template <typename _Tp,typename BufSizeType,BufSizeType TxbufSize,BufSizeType RxbufSize>
class usart
{
private:
    OS::channel<_Tp, TxbufSize, BufSizeType> TxPool;
    OS::channel<_Tp, RxbufSize, BufSizeType> RxPool;

    bool RxBufferOverflow;

public:

    USART_TypeDef * PORT;

    INLINE bool overflow ()
    {
        return RxBufferOverflow;
    }

    bool open (bool)
    {
        USART_ITConfig(PORT, USART_IT_RXNE, ENABLE);
        return true;
    }

    INLINE void it_handler ()
    {
        OS::TISRW ISRW;

        if (USART_GetITStatus(PORT,USART_IT_TXE) != RESET)
        {
            if(TxPool.get_count())
            {
                _Tp data;
                TxPool.pop(data);
                USART_SendData(PORT,data);
            }
            else
            {
                USART_ITConfig(PORT, USART_IT_TXE, DISABLE);
            }
        }

        if (USART_GetITStatus(PORT,USART_IT_RXNE) != RESET)
        {
            if (RxPool.get_free_size())
            {
                RxPool.push(USART_ReceiveData(PORT));
            }
            else
            {
                RxBufferOverflow = true;
                USART_ClearITPendingBit(PORT,USART_IT_RXNE);
            }
        }

    }

    void send(const _Tp & data)
    {
        TxPool.push(data);
        USART_ITConfig(PORT, USART_IT_TXE, ENABLE);
    }

    _Tp get ()
    {
        _Tp data;
        RxPool.pop(data);
        return data;
    }
};

Из того что не делал ранее это добавил в обработчик прерывания OS::TISRW. С таким кодом передача работает нормально, а вот при попытке принять данные камень зависает. Сразу должен заметить что размер кода увеличился на 176 байт. Размер занимаемой RAMна 4 байта.
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Jan 19 2013, 19:12
Сообщение #37


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

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



Цитата(abutorin @ Jan 20 2013, 00:42) *
С таким кодом передача работает нормально, а вот при попытке принять данные камень зависает.

У меня такой вариант работает нормально. Наверное какая-то мелочь осталась незамеченной. Например, забыли включить приёмsm.gif
Цитата(abutorin @ Jan 20 2013, 00:42) *
Сразу должен заметить что размер кода увеличился на 176 байт. Размер занимаемой RAMна 4 байта.

Ну, это мелочиsm.gif


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


Участник
*

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



Цитата(AHTOXA @ Jan 19 2013, 23:12) *
У меня такой вариант работает нормально. Наверное какая-то мелочь осталась незамеченной. Например, забыли включить приёмsm.gif

Весь остальной код остался неизменный. Менял только код данного класса. Идея использовать готовый код для решения своих задач мне всгда нравится, я потому и поднял эту тему. После того как не смог с вашей помощью решить поставленную задачу попробовал сделать свой вариант. В результате оказалось что мой вариант получается несколько компактнее. Для законченности все же остается понять почему не работает.
Вы какого размера пакеты отправляет и посылает? Я в свое время заметил что такой код работает нормально если посылаешь и принимаешь пакет меньше чем размер буфера то проблем нет. А вот как только объем больше то и происходят зависания.

Сообщение отредактировал abutorin - Jan 19 2013, 19:25
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Jan 19 2013, 19:36
Сообщение #39


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

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



Насчёт компактности - думаю, что случайно так вышло. По ОЗУ должен быть паритет (У каждого EventFlag есть TProcessMap и TValue, а у каждого channel - два TProcessMap). А по коду - если вы будете использовать channel где-то ещё (а вероятность этого ~100%), то этот код всё равно добавится.
С другой стороны, код у channel проверенный в плане межпроцессного взаимодействия (моменты запрещения прерываний, ожидание, и проч.). А с самодельным вариантом может всплыть что-то.
Почему не работает - неясно. Вы как-то не совсем внятно объясняете, что именно не работает. Приём одного байта - работает?
Тот код, который вы показали, содержит только функции записи/чтения одного символа. А вы пишете, что зависает при приёме блока.


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


Участник
*

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



Цитата(AHTOXA @ Jan 19 2013, 23:36) *
А по коду - если вы будете использовать channel где-то ещё (а вероятность этого ~100%), то этот код всё равно добавится.

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

Цитата(AHTOXA @ Jan 19 2013, 23:36) *
С другой стороны, код у channel проверенный в плане межпроцессного взаимодействия (моменты запрещения прерываний, ожидание, и проч.). А с самодельным вариантом может всплыть что-то.

Неверное использование проверенного кода тоже может вызвать проблемы.

Цитата(AHTOXA @ Jan 19 2013, 23:36) *
Почему не работает - неясно. Вы как-то не совсем внятно объясняете, что именно не работает.

Есть некий проект (кода много чтобы выкладывать), пробую использовать оба варианта класса который описывал. Еще раз повторю, для чисторы эксперимента меняю только код данного класса, все остальное остается прежним. Так вот при использовании канала похоже чтокамень на чемто зависает, сказать где не могу, знаю только что процесс с наивысшим приоритетом перестает работать.
Цитата(AHTOXA @ Jan 19 2013, 23:36) *
Приём одного байта - работает?

По одному байту не использую.

Цитата(AHTOXA @ Jan 19 2013, 23:36) *
Тот код, который вы показали, содержит только функции записи/чтения одного символа. А вы пишете, что зависает при приёме блока.


Блок передаю в цикле по одному байту.
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Jan 19 2013, 20:21
Сообщение #41


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

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



Цитата(abutorin @ Jan 20 2013, 02:01) *
Если параметры шаблано отличаются, то код начинает дублироватся. Так что тут код всегда будет больше.

А если не отличаются, то не начнёт. Значит - не всегдаsm.gif
Ну да ладно, в любом случае мне плевать на такой прирост кода.
Цитата(abutorin @ Jan 20 2013, 02:01) *
Неверное использование проверенного кода тоже может вызвать проблемы.

Поэтому я и заинтересовался. Если есть проблемы с использованием OS::channel в прерываниях, то я очень хочу знать про них.
Цитата(abutorin @ Jan 20 2013, 02:01) *
Так вот при использовании канала похоже чтокамень на чемто зависает, сказать где не могу, знаю только что процесс с наивысшим приоритетом перестает работать.

А увеличение размера буфера больше размера максимального пакета избавляет от зависаний?


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


Участник
*

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



Цитата(AHTOXA @ Jan 20 2013, 00:21) *
А увеличение размера буфера больше размера максимального пакета избавляет от зависаний?

Да.
Я писал про это на второй странице помоему.
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Jan 20 2013, 05:31
Сообщение #43


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

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



Ну, с тех пор что-то же поменялось. Так что это было неочевидно.
В общем, я не знаю, чем помочь. Может быть вы сделаете минимальный проект, где проблема проявляется, и выложите его?


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


Участник
*

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



Цитата(AHTOXA @ Jan 20 2013, 09:31) *
В общем, я не знаю, чем помочь. Может быть вы сделаете минимальный проект, где проблема проявляется, и выложите его?

Тогда пока предлагаю отложить этот вопрос.
Резюме по теме можно сделать такое:
По мнению разработчиков OS:channel можно использовать в прерываниях с некоторыми замечаниями "обязательна проверка на наличие свободного места или данных для для получения из него".
Лично у меня использовать его не получилось по неустановленным причинам. На мой субъективный взгляд использование OS:channel является более накладным (по размеру кода) чем использование собсвтенного кольцевого буфера (из библиотеки usrlib) и двух OS::TEventFlag.

PS. забыл как на форуме можно подправить название темы, чтобы вписать в нее "решено"

Сообщение отредактировал abutorin - Jan 20 2013, 06:39
Go to the top of the page
 
+Quote Post
сарматъ
сообщение Sep 4 2013, 20:26
Сообщение #45


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

Группа: Участник
Сообщений: 153
Регистрация: 19-11-12
Пользователь №: 74 463



я так и не понял, а функции типа push_isr() не нужны?и если не нужны то почему?
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Sep 4 2013, 21:41
Сообщение #46


Гуру
******

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



Цитата(сарматъ @ Sep 4 2013, 23:26) *
я так и не понял, а функции типа push_isr() не нужны?и если не нужны то почему?


Не нужны.


Код
void OS::TChannel::push(uint8_t x)
{
    TCritSect cs;

    while (!Cbuf.get_free_size())
    {
        // channel is full, suspend current process
        suspend(ProducersProcessMap);
    }

////.....


В случае, если кончилось место для записи в фифо, процесс который пишет в буфер засыпает (channel is full, suspend current process). Если запись происходит в прерывании и место кончилось, то кого усыплять-то? Такая ситуация говорит о том что либо буфер мал, либо данные поступают слишком быстро, либо данные читаются слишком медленно.




Go to the top of the page
 
+Quote Post
сарматъ
сообщение Sep 5 2013, 05:39
Сообщение #47


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

Группа: Участник
Сообщений: 153
Регистрация: 19-11-12
Пользователь №: 74 463



там могло бы быть что либо такого плана

CODE
template<typename T, uint16_t Size, typename S>
void OS::channel<T, Size, S>::push_isr(const T& item)
{
  TCritSect cs;
if(pool.get_free_size_isr())
{
pool.push_back_isr(item);
resume_all_isr(ConsumersProcessMap);
}
}


Сообщение отредактировал сарматъ - Sep 5 2013, 05:41
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Sep 5 2013, 06:10
Сообщение #48


Гуру
******

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



QUOTE (сарматъ @ Sep 5 2013, 07:39) *
там могло бы быть что либо такого плана
Всего предусмотреть невозможно. Но выход есть:
CODE
template<typename T, uint16_t Size, typename S = uint8_t>
class my_channel_with_isr : public channel<T, Size, S>
{
public:
      void push_isr(const T& item);
}


--------------------
На любой вопрос даю любой ответ
"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
сарматъ
сообщение Sep 5 2013, 06:24
Сообщение #49


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

Группа: Участник
Сообщений: 153
Регистрация: 19-11-12
Пользователь №: 74 463



да я уже подумал над этим правда придется не наследовать а копировать шаблон - чтоб в него поместить уже наследника от ring_buffer иначе внутри my_channel_with_isr будет два объекта типа ring_buffer, а если править непосредственно текст системы то совместимость пропадет(
Go to the top of the page
 
+Quote Post
dxp
сообщение Sep 5 2013, 07:21
Сообщение #50


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



QUOTE (сарматъ @ Sep 5 2013, 13:24) *
да я уже подумал над этим правда придется не наследовать а копировать шаблон - чтоб в него поместить уже наследника от ring_buffer иначе внутри my_channel_with_isr будет два объекта типа ring_buffer, а если править непосредственно текст системы то совместимость пропадет(

Почему два ring_buffer? Наследование не размножает потроха предка.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
сарматъ
сообщение Sep 5 2013, 07:37
Сообщение #51


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

Группа: Участник
Сообщений: 153
Регистрация: 19-11-12
Пользователь №: 74 463



потому что нужен вот такой вот пул и если я его добавляю в наследника канала то в нем о тпредка еще родной ring_buffer будет сидеть

CODE
namespace usr
{
template<typename T, uint16_t Size, typename S = uint8_t>
class ring_buffer_isr : public ring_buffer<T, Size, S>
{
public:
INLINE bool push_back_isr(const T item);
};
}


или я что то путаю? (повторюсь я очень не силен в плюсах)

ругается на инлайн(... а это эклипс ругается gcc скомпилировал

Сообщение отредактировал сарматъ - Sep 5 2013, 08:12
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Sep 5 2013, 08:25
Сообщение #52


Гуру
******

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



QUOTE (сарматъ @ Sep 5 2013, 09:37) *
потому что нужен вот такой вот пул
Честно говоря, не понимаю - что вы пытаетесь создать. У нас есть класс канала, который вас устраивает всем, кроме отсутствия функции-члена посылки из прерывания. Я предложил вам создать новый класс, наследник канала в котором реализовать недостающую функцию. То есть все остальные функции канала, а также собственно буфер и прочие необходимые переменные используются от родителя и лишь недостающая добавлена в наследнике. Зачем тут начинать все заново с ring_buffer - совершенно непонятно.

QUOTE (сарматъ @ Sep 5 2013, 09:37) *
и если я его добавляю в наследника канала то в нем о тпредка еще родной ring_buffer будет сидеть
Опять же непонятно - зачем добавлять еще один ring_buffer в наследника? Надо использовать родительский. Или я снова не понял вопроса.


--------------------
На любой вопрос даю любой ответ
"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
сарматъ
сообщение Sep 5 2013, 08:33
Сообщение #53


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

Группа: Участник
Сообщений: 153
Регистрация: 19-11-12
Пользователь №: 74 463



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

то же самое и с буфером хочется чтобы вот эта функция push_back_isr была бы инлайновой

сделал пока так но без ковыряния исходников все равно не обошлось - в ринг буфере заменил секцию приват на протектед самую последнюю с переменными

CODE
/*
* classes_isr.h
*
* Created on: 05 сент. 2013 г.
*/

#ifndef CLASSES_ISR_H_
#define CLASSES_ISR_H_

#include "usrlib.h"

namespace usr
{
template<typename T, uint16_t Size, typename S = uint8_t>
class ring_buffer_isr : public ring_buffer<T, Size, S>
{
public:
INLINE bool push_back_isr(const T item);
INLINE S get_free_size_isr() const { return Size - this->Count; }
private:
INLINE void push_item_isr(const T item);
};
}
namespace OS
{
template<typename T, uint16_t Size, typename S = uint8_t>
class channel_isr : public TService
{
public:
INLINE channel_isr() : ProducersProcessMap(0)
, ConsumersProcessMap(0)
, pool()
{
}

//----------------------------------------------------------------
//
// Data transfer functions
//
void write(const T* data, const S cnt);
bool read (T* const data, const S cnt, timeout_t timeout = 0);

void push (const T& item);
INLINE void push_isr (const T& item);
void push_front(const T& item);

bool pop (T& item, timeout_t timeout = 0);
bool pop_back(T& item, timeout_t timeout = 0);


//----------------------------------------------------------------
//
// Service functions
//
INLINE S get_count() const { TCritSect cs; return pool.get_count(); }
INLINE S get_free_size() const { TCritSect cs; return pool.get_free_size(); }
void flush();

protected:
volatile TProcessMap ProducersProcessMap;
volatile TProcessMap ConsumersProcessMap;
usr::ring_buffer_isr<T, Size, S> pool;
};
}
template<typename T, uint16_t Size, typename S>
INLINE bool usr::ring_buffer_isr<T, Size, S>::push_back_isr(const T item){
if(this->Count == Size)
return false;

push_item_isr(item);
return true;
}
template<typename T, uint16_t Size, typename S>
INLINE void usr::ring_buffer_isr<T, Size, S>::push_item_isr(const T item){
this->Buf[this->Last] = item;
this->Last++;
this->Count++;

if(this->Last == Size)
this->Last = 0;

}

//------------------------------------------------------------------------------
template<typename T, uint16_t Size, typename S>
void OS::channel_isr<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);
}
//------------------------------------------------------------------------------
template<typename T, uint16_t Size, typename S>
INLINE void OS::channel_isr<T, Size, S>::push_isr(const T& item)
{
TCritSect cs;

if(pool.get_free_size_isr())
{
pool.push_back_isr(item);
resume_all_isr(ConsumersProcessMap);
}

}
//------------------------------------------------------------------------------
template<typename T, uint16_t Size, typename S>
void OS::channel_isr<T, Size, S>::push_front(const T& item)
{
TCritSect cs;

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

pool.push_front(item);
resume_all(ConsumersProcessMap);

}
//------------------------------------------------------------------------------
template<typename T, uint16_t Size, typename S>
bool OS::channel_isr<T, Size, S>::pop(T& item, timeout_t timeout)
{
TCritSect cs;

if(pool.get_count())
{
item = pool.pop();
resume_all(ProducersProcessMap);
return true;
}
else
{
cur_proc_timeout() = timeout;

for(;;)
{
// channel is empty, suspend current process until data received or timeout
suspend(ConsumersProcessMap);
if(is_timeouted(ConsumersProcessMap))
return false;

if(pool.get_count())
{
cur_proc_timeout() = 0;
item = pool.pop();
resume_all(ProducersProcessMap);
return true;
}
// otherwise another process caught data
}
}
}
//------------------------------------------------------------------------------
template<typename T, uint16_t Size, typename S>
bool OS::channel_isr<T, Size, S>::pop_back(T& item, timeout_t timeout)
{
TCritSect cs;

if(pool.get_count())
{
item = pool.pop_back();
resume_all(ProducersProcessMap);
return true;
}
else
{
cur_proc_timeout() = timeout;

for(;;)
{
// channel is empty, suspend current process until data received or timeout
suspend(ConsumersProcessMap);
if(is_timeouted(ConsumersProcessMap))
return false;

if(pool.get_count())
{
cur_proc_timeout() = 0;
item = pool.pop_back();
resume_all(ProducersProcessMap);
return true;
}
// otherwise another process caught data
}
}
}
//------------------------------------------------------------------------------
template<typename T, uint16_t Size, typename S>
void OS::channel_isr<T, Size, S>::flush()
{
TCritSect cs;
pool.flush();
resume_all(ProducersProcessMap);
}
//------------------------------------------------------------------------------
template<typename T, uint16_t Size, typename S>
void OS::channel_isr<T, Size, S>::write(const T* data, const S count)
{
TCritSect cs;

while(pool.get_free_size() < count)
{
// channel does not have enough space, suspend current process until data removed
suspend(ProducersProcessMap);
}

pool.write(data, count);
resume_all(ConsumersProcessMap);

}
//------------------------------------------------------------------------------
template<typename T, uint16_t Size, typename S>
bool OS::channel_isr<T, Size, S>::read(T* const data, const S count, timeout_t timeout)
{
TCritSect cs;

cur_proc_timeout() = timeout;

while(pool.get_count() < count)
{
// channel doesn't contain enough data, suspend current process until data received or timeout
suspend(ConsumersProcessMap);
if(is_timeouted(ConsumersProcessMap))
return false;
}

cur_proc_timeout() = 0;
pool.read(data, count);
resume_all(ProducersProcessMap);

return true;
}
//------------------------------------------------------------------------------


#endif /* CLASSES_ISR_H_ */


работает примерно так же как и ивент если судить по количеству потерянных пакетов, теперь вопрос: если исходники все равно ковырял то лучше изменения все в них внести чтобы код не дублировать понапрасну?

Сообщение отредактировал сарматъ - Sep 5 2013, 12:26
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Sep 6 2013, 08:29
Сообщение #54


Гуру
******

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



QUOTE (сарматъ @ Sep 5 2013, 10:33) *
сделал пока так но без ковыряния исходников все равно не обошлось - в ринг буфере заменил секцию приват на протектед самую последнюю с переменными
Боюсь, вы пошли несколько неправильным путем - вы в своем производном классе практически продублировали весь код функций родителя ради добавления INLINE. Я бы сделал новые inline - функции в родителе и в родителе же используя их же сделал бы не-inline версии:
CODE
template<typename T, uint16_t Size, typename S = uint8_t>
class ring_buffer
{
public:
ring_buffer() : Count(0), First(0), Last(0) { }

//----------------------------------------------------------------
//
// Data transfer functions
//
bool write(const T* data, const S cnt);
void read(T* const data, const S cnt);

INLINE bool push_back_inline(const T item);
INLINE bool push_front_inline(const T item);
bool push_back(const T item);
bool push_front(const T item);
......

template<typename T, uint16_t Size, typename S>
bool usr::ring_buffer<T, Size, S>::push_back_inline(const T item)
{
if(Count == Size)
return false;

push_item(item);
return true;
}

template<typename T, uint16_t Size, typename S>
bool usr::ring_buffer<T, Size, S>::push_back(const T item)
{
return push_back_inline(item);
}
Таким образом полностью исключил бы дублирование кода и получил возможность в наследниках использовать и inline и не-inline варианты. И это никак бы не повлияло на старые проекты - вот такое изменение вполне можно было бы внести в официальные исходники ОС.


--------------------
На любой вопрос даю любой ответ
"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
сарматъ
сообщение Sep 6 2013, 08:44
Сообщение #55


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

Группа: Участник
Сообщений: 153
Регистрация: 19-11-12
Пользователь №: 74 463



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

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

Сообщение отредактировал сарматъ - Sep 6 2013, 11:41
Прикрепленные файлы
Прикрепленный файл  usrlib.h.tar.gz ( 2.6 килобайт ) Кол-во скачиваний: 20
Прикрепленный файл  OS_Services.h.tar.gz ( 4.19 килобайт ) Кол-во скачиваний: 22
 
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 Текстовая версия Сейчас: 14th August 2025 - 08:23
Рейтинг@Mail.ru


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