|
|
 |
Ответов
|
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)
|
|
|
|
|
Jan 17 2013, 12:25
|
Участник

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

|
Цитата(Сергей Борщ @ Jan 17 2013, 14:15)  Как-то так, хотя мне самому этот код не очень нравится: Да, я понял. Но мои вопросы этот метод нерешит т.к. посылка делается по одному байту (как поток), тут изначально нельзя знать какой объем займет посылка. Плохо что DMA не умеет работать как кольцевой буфер. Тогда хотябы можно было накапливать данные и отсылать по таймауту в случае отсутствия новых.
|
|
|
|
Сообщений в этой теме
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          Сергей Борщ 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
|
|
|