AHTOXA 14 16 января, 2013 Опубликовано 16 января, 2013 · Жалоба TXE очищается записью в DR. Вручную его чистить не надо, он read-only. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 16 января, 2013 Опубликовано 16 января, 2013 · Жалоба USART_ClearITPendingBit(this->PORT,USART_IT_TXE); Это очистка признака возникновения прерывания, в у STM32 большинство битов (признаков) прерывания необходимо очищать вручную.К сожалению я использую для передачи DMA, поэтому у меня нет примера для UART c каналом. Без ОС рабочий код у меня выглядит так: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; } } Как видите, никаких ручных очисток. А в какой момент происходи включение прерываний? в suspend я не нашел включение прерываний.Из suspend() вызывается TKernelAgent::reschelule(), который в свою очередь вызывет TKernel::shed(), в котором есть такой код: do { enable_context_switch(); DUMMY_INSTR(); disable_context_switch(); } while(CurProcPriority != SchedProcPriority); // until context switch done Вот тут произойдет переключение на другой процесс, а уже этот процесс (если нет активных - то процесс Idle) выполняется с разрешенными прерываниями, т.е. при восстановлении его контекста прерывания будут разрешены. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 14 16 января, 2013 Опубликовано 16 января, 2013 · Жалоба Status &= pUART->CR1; // mask disabled ints А это зачем? Чтобы не реагировать на RXNE и TXE при маскировке этих прерываний? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 16 января, 2013 Опубликовано 16 января, 2013 · Жалоба А это зачем? Чтобы не реагировать на RXNE и TXE при маскировке этих прерываний?Да, на все запрещенные. В данном случае на TXE. RXNE у меня не запрещается. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
abutorin 0 16 января, 2013 Опубликовано 16 января, 2013 · Жалоба К сожалению я использую для передачи DMA, поэтому у меня нет примера для UART c каналом. У меня логика построена на том, что я с уартом работаю как с потоком байт, я не знаю сколько байт отправляюи сколько получу. Если даже с таким подходом это можно реализовать через DMA то был бы очень признателен за пример. Если с прерываниями стало ясно.то опять возникает вопрос в чем же тогда проблема? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 14 16 января, 2013 Опубликовано 16 января, 2013 · Жалоба Да, на все запрещенные. В данном случае на TXE. RXNE у меня не запрещается. У меня такого нет, и работает нормально. Это что получается, я при запрещённых прерываниях TXE всё равно каждый раз при входе в прерывание влетаю в эту ветку обработчика? Проверил - точно, влетаю. Неаккуратненько... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 17 января, 2013 Опубликовано 17 января, 2013 · Жалоба Если с прерываниями стало ясно.то опять возникает вопрос в чем же тогда проблема?Вы заводите в начале обработчика объект типа OS::TISRW (я в предыдущем сообщении описался, указав его как OS::TCritSect)? Без него прерывание не сможет при необходимости вызвать перепланирование. У меня логика построена на том, что я с уартом работаю как с потоком байт, я не знаю сколько байт отправляюи сколько получу. Если даже с таким подходом это можно реализовать через DMA то был бы очень признателен за пример.Как-то так, хотя мне самому этот код не очень нравится: //**** 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. Если же передается готовая строка из флеша или ОЗУ - буфер не используется. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
abutorin 0 17 января, 2013 Опубликовано 17 января, 2013 · Жалоба Как-то так, хотя мне самому этот код не очень нравится: Да, я понял. Но мои вопросы этот метод нерешит т.к. посылка делается по одному байту (как поток), тут изначально нельзя знать какой объем займет посылка. Плохо что DMA не умеет работать как кольцевой буфер. Тогда хотябы можно было накапливать данные и отсылать по таймауту в случае отсутствия новых. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 17 января, 2013 Опубликовано 17 января, 2013 · Жалоба Плохо что DMA не умеет работать как кольцевой буфер.Некое подобие можно сформировать. Укладывать данные в кольцевой буфер, а по таймауту или в прерывании окончания DMA перезагружать регистры DMA на очередной готовый участок этого буфера. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
abutorin 0 17 января, 2013 Опубликовано 17 января, 2013 · Жалоба Некое подобие можно сформировать. Укладывать данные в кольцевой буфер, а по таймауту или в прерывании окончания DMA перезагружать регистры DMA на очередной готовый участок этого буфера. Боюсь тогда алгоритм получится очень сложный а сказать уверенно что прерываний станет сильно меньше не получится, здесь наверное проще тогда сдлеать через накопление буфера и отправкой потом через ДМА когда буфер переполнен или по таймауту если данных больше нет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 14 17 января, 2013 Опубликовано 17 января, 2013 · Жалоба Насчёт работы с UART по DMA вот вам три темы: раз два три Там немножко разные подходы, выберите подходящий. Я делал по примеру от kan35 в конце третьей темы, работает. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
abutorin 0 18 января, 2013 Опубликовано 18 января, 2013 · Жалоба Насчёт работы с UART по DMA вот вам три темы: раз два три Там немножко разные подходы, выберите подходящий. Я делал по примеру от kan35 в конце третьей темы, работает. Спасибо, понял что нужно копать в направлении режима cilcularmode DMA. Попробую потом на досуге, сейчас сделал прием и передачу через прерывания. Код передачи выкладывал выше, прием сделал по образу и подобию, На ненагруженном камне прием уверенный на скорости в 0,5 мбит/с Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 18 января, 2013 Опубликовано 18 января, 2013 · Жалоба Спасибо, понял что нужно копать в направлении режима cilcularmode DMA.Ой. Вам ведь не нужно, чтобы УАСПП постоянно повторял содержимое всего буфера, включая мусор. сейчас сделал прием и передачу через прерывания.А в чем причина была, почему не работало? Обычно принято сообщать - чтобы тот, кто будет потом искать решение своей подобной проблемы нашел ответ, да и отвечавшим вам тоже любопытно - кто из них угадал :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
abutorin 0 18 января, 2013 Опубликовано 18 января, 2013 · Жалоба Ой. Вам ведь не нужно, чтобы УАСПП постоянно повторял содержимое всего буфера, включая мусор. Для приемника: Если я правильно понял то кольцевой режим работает так, что после того как счетчик добирается до конца выделено памяти он просто сбрасывает его на начальное значение и работает так дальше. А передача всеравно срабатывает по нужному событию. Там правда усложнится процес получения одного байта, нужно вести свой счетчик хвоста, но в результате такой подход гарантирует автоматическое хранение N последних пришедших байт. Если правда данные вовремя не считывать то они начинают затиратся, но затираются "аккуратно" N последних байт всеравно получены последовательно. Вообщем идея заманчивая. Для передатчика: Прийдется использовать еще и таймер и отправлять данные пачкой при заполнении буфера или истечении таймаута ожидания. Надо только. Тогда по идее все тоже будет достаточно ненакладно. А в чем причина была, почему не работало? Обычно принято сообщать - чтобы тот, кто будет потом искать решение своей подобной проблемы нашел ответ, да и отвечавшим вам тоже любопытно - кто из них угадал :) Код я выкладывал ранее. Я в итоге сделал без канала. Пришел к выводу что канал больше предназначен для межпроцессного взаимодействия, а в случае с УСАПП это больше ожидание одним потоком выполнения некоторого действия переферией. Доберусь до дома выложу код полностью. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
abutorin 0 18 января, 2013 Опубликовано 18 января, 2013 · Жалоба Как обещал ранее выкладываю код который у меня работает. 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(); } }; Отказ от канала в результате вызван тем, что канал больше предназначен для межпроцессного взаимодействия а не между процессом и прерыванием. Инициализацию порта необходимо выполнять самостоятельно. Сразу хочу заметить что данная реализация сделана на коленке и имеет достаточный потенциал для улучшения, сразу видно что целесообразно сделать данный класс через шаблон со статичными членами, с указанием порта как параметра и использовать данные методы без создания экземпляра класса. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться