|
|
 |
Ответов
|
Jan 13 2013, 20:45
|

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

|
Использовать канал в прерывании можно. Учтите только, что если вы в него что-то заталкиваете, а он полон, то будет сделана попытка усыпить прерванный процесс и дождаться освобождения (или при доставании из пустого канала). Вероятно, это не то поведение, которое ожидается в прерывании  Поэтому проверяйте наличие свободного места при запихивании чего-то в канал, и наличие данных при доставании из канала. Примерно вот так: Код 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(); } }
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jan 15 2013, 19:16
|
Участник

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

|
Цитата(AHTOXA @ Jan 14 2013, 00:45)  Использовать канал в прерывании можно. Учтите только, что если вы в него что-то заталкиваете, а он полон, то будет сделана попытка усыпить прерванный процесс и дождаться освобождения (или при доставании из пустого канала). Вероятно, это не то поведение, которое ожидается в прерывании  Поэтому проверяйте наличие свободного места при запихивании чего-то в канал, и наличие данных при доставании из канала. Примерно так и делал. Код 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
|
|
|
|
|
Jan 15 2013, 19:31
|
Участник

Группа: Участник
Сообщений: 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, запрет снимается в деструкторе, так вот деструктор не вызовется, т.к. потребитель канала находится в прерывании. Получается что канал использовать с прерываниями не получится.
|
|
|
|
|
Jan 15 2013, 22:46
|

Гуру
     
Группа: Модераторы
Сообщений: 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)
|
|
|
|
|
Jan 16 2013, 03:29
|
Участник

Группа: Участник
Сообщений: 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 я не нашел включение прерываний.
|
|
|
|
|
Jan 16 2013, 08:54
|

Гуру
     
Группа: Модераторы
Сообщений: 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)
|
|
|
|
|
Jan 16 2013, 11:33
|
Участник

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

|
Цитата(Сергей Борщ @ Jan 16 2013, 12:54)  К сожалению я использую для передачи DMA, поэтому у меня нет примера для UART c каналом. У меня логика построена на том, что я с уартом работаю как с потоком байт, я не знаю сколько байт отправляюи сколько получу. Если даже с таким подходом это можно реализовать через DMA то был бы очень признателен за пример. Если с прерываниями стало ясно.то опять возникает вопрос в чем же тогда проблема?
|
|
|
|
|
Jan 17 2013, 10:15
|

Гуру
     
Группа: Модераторы
Сообщений: 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)
|
|
|
|
Сообщений в этой теме
abutorin Возможность использования OS::channel в прерываниях Jan 13 2013, 19:25 abutorin Спасибо, проверку заполнености, проверку пустоты я... Jan 14 2013, 02:40    _Артём_ Цитата(abutorin @ Jan 15 2013, 21:31) Объ... Jan 15 2013, 20:10      _Артём_ Цитата(abutorin @ Jan 16 2013, 05:29) А в... Jan 16 2013, 04:45       AHTOXA TXE очищается записью в DR. Вручную его чистить не... Jan 16 2013, 05:05       AHTOXA Цитата(Сергей Борщ @ Jan 16 2013, 14:54) ... Jan 16 2013, 10:18        Сергей Борщ QUOTE (AHTOXA @ Jan 16 2013, 12:18) А это... Jan 16 2013, 11:27         AHTOXA Цитата(Сергей Борщ @ Jan 16 2013, 17:27) ... Jan 16 2013, 13:52         abutorin Цитата(Сергей Борщ @ Jan 17 2013, 14:15) ... Jan 17 2013, 12:25          Сергей Борщ QUOTE (abutorin @ Jan 17 2013, 14:25) Пло... Jan 17 2013, 13:12           abutorin Цитата(Сергей Борщ @ Jan 17 2013, 17:12) ... Jan 17 2013, 13:20            AHTOXA Насчёт работы с UART по DMA вот вам три темы:
раз... Jan 17 2013, 18:31             abutorin Цитата(AHTOXA @ Jan 17 2013, 22:31) Насчё... Jan 18 2013, 05:37              Сергей Борщ QUOTE (abutorin @ Jan 18 2013, 07:37) Спа... Jan 18 2013, 07:41               abutorin Цитата(Сергей Борщ @ Jan 18 2013, 11:41) ... Jan 18 2013, 09:14 Vasya777 Мне кажется для обмена по интерфейсам связи лучше ... Jan 15 2013, 15:07 abutorin Проблему решил использовав События:
Кодclass usart... Jan 15 2013, 20:14 _Артём_ Цитата(abutorin @ Jan 15 2013, 22:14) есл... Jan 15 2013, 20:20  abutorin Цитата(_Артём_ @ Jan 16 2013, 00:20) На ч... Jan 15 2013, 20:24   _Артём_ Цитата(abutorin @ Jan 15 2013, 22:24) Вто... Jan 15 2013, 20:52 abutorin Как обещал ранее выкладываю код который у меня раб... Jan 18 2013, 18:52 AHTOXA USART_ClearITPendingBit(this->PORT,USART_IT_TXE... Jan 19 2013, 04:43  abutorin Цитата(AHTOXA @ Jan 19 2013, 08:43) USART... Jan 19 2013, 17:19   AHTOXA Цитата(abutorin @ Jan 19 2013, 23:19) В к... Jan 19 2013, 17:42    abutorin Цитата(AHTOXA @ Jan 19 2013, 21:42) Код ... Jan 19 2013, 17:56     _Артём_ Цитата(abutorin @ Jan 19 2013, 19:56) В с... Jan 19 2013, 18:13    abutorin Цитата(AHTOXA @ Jan 19 2013, 21:42) Код ... Jan 19 2013, 18:42     AHTOXA Цитата(abutorin @ Jan 20 2013, 00:42) С т... Jan 19 2013, 19:12      abutorin Цитата(AHTOXA @ Jan 19 2013, 23:12) У мен... Jan 19 2013, 19:19       AHTOXA Насчёт компактности - думаю, что случайно так вышл... Jan 19 2013, 19:36        abutorin Цитата(AHTOXA @ Jan 19 2013, 23:36) А по ... Jan 19 2013, 20:01         AHTOXA Цитата(abutorin @ Jan 20 2013, 02:01) Есл... Jan 19 2013, 20:21          abutorin Цитата(AHTOXA @ Jan 20 2013, 00:21) А уве... Jan 19 2013, 20:42           AHTOXA Ну, с тех пор что-то же поменялось. Так что это бы... Jan 20 2013, 05:31            abutorin Цитата(AHTOXA @ Jan 20 2013, 09:31) В общ... Jan 20 2013, 05:57 сарматъ я так и не понял, а функции типа push_isr() не нуж... Sep 4 2013, 20:26 _Артём_ Цитата(сарматъ @ Sep 4 2013, 23:26) я так... Sep 4 2013, 21:41  сарматъ там могло бы быть что либо такого плана
CODEtempl... Sep 5 2013, 05:39   Сергей Борщ QUOTE (сарматъ @ Sep 5 2013, 07:39) там м... Sep 5 2013, 06:10 сарматъ да я уже подумал над этим правда придется не насле... Sep 5 2013, 06:24 dxp QUOTE (сарматъ @ Sep 5 2013, 13:24) да я ... Sep 5 2013, 07:21  сарматъ потому что нужен вот такой вот пул и если я его до... Sep 5 2013, 07:37   Сергей Борщ QUOTE (сарматъ @ Sep 5 2013, 09:37) потом... Sep 5 2013, 08:25 сарматъ да, класс канала отличный класс, плюс ко всем его ... Sep 5 2013, 08:33 Сергей Борщ QUOTE (сарматъ @ Sep 5 2013, 10:33) сдела... Sep 6 2013, 08:29 сарматъ ок, так и сделаю и потом выложу сюда что получилос... Sep 6 2013, 08:44
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|