klen 1 6 июля, 2011 Опубликовано 6 июля, 2011 · Жалоба здравствуйте. столькнулся с тем что не понимаю как это работает. настроенный dma канал читает данные с уарта в буффер озу в режиме DMA_Mode_Normal. после заполнения буфера как и положено становится как вкопаный. указатель позиции соответствует размеру буфера. как сказать ему чтоб он повторил действие. сброс указателя позиции и включение и выключение уарта и самого канала dma не приводит к началу записи в буфер. он явно чтото друго ждет от меня спасибо Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
prm 0 6 июля, 2011 Опубликовано 6 июля, 2011 · Жалоба Обычно описанные действия помогают. Может проще использовать DMA в режиме записи по кольцу, организовав тем самым подобие двойного буфера? В своем проекте использую FreeRTOS. Сделал отдельную задачу на прием информации по УАРТ. В обработчике прерывании от DMA в очередь событий (создаю отдельно) помещаю код возникшего события (буфер заполнен на половину, заполнен полностью, ошибка). В задаче приема вызываю xQueueReceive(..., ..., таймаут_ожидания_окончания_передачи). Если событие принято, обрабатываю данные буфера, запоминаю смещение (первая/вторая половина буфера, зависит от кода события). Если событие не принято (xQueueReceive завершилась по таймауту), определяю количество принятых байт с момента возникновения последнего события (знаю смещение в буфере, знаю сколько еще пришло DMA_GetCurrDataCounter(...)) и снова обрабатываю буфер. //============================================================================ /// Задача по приему данных от USART_DBG //============================================================================= void vDebugReceive(void *pvParameters) { const portTickType xTicksToWait = USART_DBG_RX_TIMEOUT_MS / portTICK_RATE_MS; uint8_t event_code; uint16_t last_data_cnt = USART_DBG_RX_BUF_SIZE; uint16_t cnt = 0; uint8_t offset = 0; //вечный цикл for(;;) { // ожидаю прихода события (данные считаны либо таймаут) if( xQueueReceive(dbg_rx_events, &event_code, xTicksToWait) == pdPASS ) { //получил событие switch(event_code) { case DBG_RX_HALF: { // заполнена первая половина приемного буфера for (; offset < (USART_DBG_RX_BUF_SIZE+1)/2; ++offset) xQueueSendToBack(dbg_rx_data, (const void*)&dbg_in_buf[offset],0); last_data_cnt = (USART_DBG_RX_BUF_SIZE+1)/2; break; } case DBG_RX_FULL: { // заполнена вторая половина приемного буфера for (; offset < USART_DBG_RX_BUF_SIZE; ++offset) xQueueSendToBack(dbg_rx_data, (const void*)&dbg_in_buf[offset],0); // смещение на начало буфера offset = 0; last_data_cnt = USART_DBG_RX_BUF_SIZE; break; } case DBG_RX_ERR: { // произошла ошибка при приеме данных. Заново включаем канал DMA DMA_Cmd(USART_DBG_Rx_DMA_Ch, ENABLE); offset = 0; break; } } } else { // проверяю, может пришла часть данных if ( last_data_cnt != DMA_GetCurrDataCounter(USART_DBG_Rx_DMA_Ch)) { // т.к. счетчик в DMA декрементируется, то вычитаем из last_data_cnt cnt = last_data_cnt - DMA_GetCurrDataCounter(USART_DBG_Rx_DMA_Ch); for (; cnt && offset < USART_DBG_RX_BUF_SIZE; ++offset, --cnt) xQueueSendToBack(dbg_rx_data,(const void*)&dbg_in_buf[offset],0); //ОБНУЛЯТЬ offset НЕЛЬЗЯ!!! Должно генерироваться прерывание по заполнению буфера } last_data_cnt = DMA_GetCurrDataCounter(USART_DBG_Rx_DMA_Ch); } } } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
klen 1 6 июля, 2011 Опубликовано 6 июля, 2011 · Жалоба спасибо. так у меня работает с кольцом. но хочу соптимизировать. я знаю что момент когда точно прийдет пакет и заню его длинну. поэтому чтоб не анализировать состояние кольца хочется перед приходом пакета оп уарт включить на оду запись буфера канал dma. я также знаю момент времени когла он уже пришел без прерываний. хочу обработать пакет, и сново поставить канал dma запись следующего. данные приходят четко и синхронно - на этом хочу выйграть в коде. только вот перезапустить канал дма на следующую запись не получается :smile3046: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
prm 0 6 июля, 2011 Опубликовано 6 июля, 2011 · Жалоба Понял. Я подобным образом работаю с DS18b20. Вот рабочий кусок кода(лишнее можно выбросить, я подстраховался): USART_Cmd(USART_DS18B20, DISABLE); //USART_DS18B20 USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate = 115200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART_DS18B20, &USART_InitStructure); // конфигурирую DMA DMA_InitTypeDef DMA_InitStructure; DMA_DeInit(USART_DS18B20_Rx_DMA_Ch); DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART_DS18B20_DR_Base; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)rx_data_buf; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = 1000; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(USART_DS18B20_Rx_DMA_Ch, &DMA_InitStructure); DMA_DeInit(USART_DS18B20_Tx_DMA_Ch); DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART_DS18B20_DR_Base; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)tx_data_buf; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; DMA_InitStructure.DMA_BufferSize = cnt; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(USART_DS18B20_Tx_DMA_Ch, &DMA_InitStructure); USART_ClearFlag(USART_DBG,USART_IT_TC); USART_Cmd(USART_DS18B20, ENABLE); USART_DMACmd(USART_DS18B20, USART_DMAReq_Tx | USART_DMAReq_Rx, ENABLE); DMA_ITConfig(USART_DS18B20_Tx_DMA_Ch, DMA_IT_TC | DMA_IT_TE, ENABLE); DMA_ITConfig(USART_DS18B20_Rx_DMA_Ch, DMA_IT_HT | DMA_IT_TC | DMA_IT_TE, DISABLE); // запускаю передачу DMA_Cmd(USART_DS18B20_Rx_DMA_Ch, ENABLE); DMA_Cmd(USART_DS18B20_Tx_DMA_Ch, ENABLE); // засыпаю до завершения передачи USART_Cmd(USART_DS18B20, DISABLE); DMA_Cmd(USART_DS18B20_Rx_DMA_Ch, DISABLE); DMA_Cmd(USART_DS18B20_Tx_DMA_Ch, DISABLE); DMA_ClearITPendingBit(DMA1_IT_GL2); DMA_ClearITPendingBit(DMA1_IT_GL3); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
klen 1 6 июля, 2011 Опубликовано 6 июля, 2011 · Жалоба и так пробывал - работает. но меня сильно напрягает что ВСЕ нада выключить и снова ПРОИНИТИТЬ и ВКЛЮЧИТЬ - этож бред. на мой вггляд достаточно былобы установить позицию записи сбросить флаг завершения передачи как сигнал того что нужно писать заново ..... если в се переинициализировать - это косяг, на это время тратится... наверно мы не понимаем как правильно. для передатчика я пробывал - кажется достаточно по окончании передачи сбросить разрешение работы для канала и сразу установить его и он зановов выдает буфер в переферию...... с приемником также должно быть по идее Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
prm 0 6 июля, 2011 Опубликовано 6 июля, 2011 · Жалоба может тогда причина не в DMA, а в УАРТ? с другой периферией не пробовали? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
klen 1 6 июля, 2011 Опубликовано 6 июля, 2011 · Жалоба может тогда причина не в DMA, а в УАРТ? с другой периферией не пробовали? ну мне же уарт нужен ;) с полной выключением переинициализацией и включением работает - но это явно через жёппу. если так работает у stm работает dma - то он хуже чем я думал, но не думаю что там дураки сидять. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 15 6 июля, 2011 Опубликовано 6 июля, 2011 · Жалоба Вот здесь вроде что-то по теме. (последний пост) Вроде всё логично: отключили DMA, сбросили адрес и количество байт, запустили DMA. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
klen 1 6 июля, 2011 Опубликовано 6 июля, 2011 · Жалоба коечто наковырял... делать нада так; 1. выключить канал dma 2. записать в CNDTR размер буфера 3. включить dma работает. может возникнуть вопрос а че я тут всем мозги парю? оказывается если по ходу работы отлачик остановится на точке прерывания - то! все отваливается. при отладке с остановами работаеттолько такой код: 1a. выключить uart 1. выключить канал dma 2. записать в CNDTR размер буфера 2.a записать CCR то что писалось при инициализации 3. включить dma 3a. включить uart возможно это ревизия кристала такая или еще чтото но поведение меняется если отладчик останавливате и потом пускает процессор. ктонибудб знает как эту 'фичу' помножить на ноль? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться