Страница 1 из 1
Загадка DMA[STM32F205RG]
Добавлено: Вс май 24, 2015 10:30:46
Foxek
Добрый день. Помогите решить загадку связанную с работой DMA на контроллере STM32F205RG.
Загадка состоит в следующем. Я в непрерывном цикле при помощи DMA снимаю данные с канала UART. Все прекрасно работает и приходят валидные данные. Но, порой, после 6 -8 часов непрерывной работы передача попросту прекращается. Причем данные на вход UART идут все также непрерывно как и раньше. Отловил проблему в отладчике, выяснилось что программа крутится в основном цикле ожидая прерывания от DMA, но прерывания не происходит, несмотря на наличие данных в регистре UART. И до тех пор пока не сбросишь контроллер в Reset, запись не возобновляется. Данная ошибка не имеет какой то осознанного цикла повторения: возникнуть может как через 2 часа так и через 8 часов.
Подскажите, может кто то сталкивался с такой ошибкой.
P.S. Выкладывать свой код не вижу смысла, так как все вполне себе отлично работает в течении долгого времени и ошибки в конфигурации чего либо быть не должно. Тут надо размышлять)
Re: Загадка DMA[STM32F205RG]
Добавлено: Вс май 24, 2015 13:04:30
Neekeetos
Foxek писал(а):P.S. Выкладывать свой код не вижу смысла, так как все вполне себе отлично работает в течении долгого времени и ошибки в конфигурации чего либо быть не должно. Тут надо размышлять)
Пока гадалки подтягиваются выскажу свое предположение. Флаги статуса уарта не проверяются никак, происходит переполнение после чего уарт перестает делать запросы дма.
Re: Загадка DMA[STM32F205RG]
Добавлено: Вс май 24, 2015 15:25:59
Foxek
Допустим я выложу код, но какую именно его часть мне выложить? инициализацию и обработку прерывания?
Re: Загадка DMA[STM32F205RG]
Добавлено: Вс май 24, 2015 15:41:38
Neekeetos
Foxek писал(а):но какую именно его часть мне выложить? инициализацию и обработку прерывания?
Да, для начала будет достаточно. Сам процессор сильно загружен?
Re: Загадка DMA[STM32F205RG]
Добавлено: Вс май 24, 2015 15:55:20
Foxek
Один канал DMA собирает данные по UART в кольцевой буфер, Другой канал по SDIO пишет на SD карту.+ Парочку счетных таймеров и один ШИМ таймер. Но их приоритеты меньше чем приоритет DMA.
Инициализация DMA и UART:
Код: Выделить всё
void UART_INIT(void){
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
USART_DeInit(USART1);
USART_InitStructure.USART_BaudRate = 4000000;
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_OverSampling8Cmd(USART1, ENABLE);
USART_Init(USART1,&USART_InitStructure);
USART_Cmd(USART1, ENABLE);
}
void DMA_INIT(uint32_t* dma_buf_0, uint32_t* dma_buf_1 ){
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
/* Configure RX DMA double buffering DMA2_Stream5 Channel 4 USART1_RX */
DMA_DeInit(DMA2_Stream5);
DMA_USARTStructure.DMA_Channel = DMA_Channel_4;
DMA_USARTStructure.DMA_PeripheralBaseAddr =(uint32_t) (&(USART1->DR)) ;
DMA_USARTStructure.DMA_Memory0BaseAddr = (uint32_t) dma_buf_0;
DMA_USARTStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_USARTStructure.DMA_BufferSize = (uint32_t) RECEIVE_BUF_SIZE;
DMA_USARTStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_USARTStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_USARTStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_USARTStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_USARTStructure.DMA_Mode = DMA_Mode_Circular;
DMA_USARTStructure.DMA_Priority = DMA_Priority_Medium;
DMA_USARTStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
DMA_USARTStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_USARTStructure.DMA_MemoryBurst = DMA_MemoryBurst_INC16 ;
DMA_USARTStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_DoubleBufferModeConfig(DMA2_Stream5, (uint32_t) dma_buf_1, DMA_Memory_0);
DMA_DoubleBufferModeCmd(DMA2_Stream5, ENABLE);
DMA_Init(DMA2_Stream5,&DMA_USARTStructure);
/* Enable DMA Stream Transfer Complete interrupt */
DMA_ITConfig(DMA2_Stream5, DMA_IT_TC, ENABLE);
/* Enable DMA USART RX Stream */
USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
DMA_Cmd(DMA2_Stream5,ENABLE);
}
Обработка прерываний от DMA
Код: Выделить всё
void DMA2_Stream5_IRQHandler(void){
if (DMA_GetFlagStatus(DMA2_Stream5, DMA_FLAG_TCIF5) == SET){
DMA_ClearFlag(DMA2_Stream5, DMA_FLAG_TCIF5);
if ( DMA_GetCurrentMemoryTarget(DMA2_Stream5) == 0 )
bufInfoSDWrite.buf = (uint32_t*) DMA2_Stream5->M1AR;
else
bufInfoSDWrite.buf= (uint32_t*) DMA2_Stream5->M0AR;
bufInfoSDWrite.bufSize = RECEIVE_BUF_SIZE;
DeviceMode = DEVICE_MODE_SD_WRITE;
}
}
Re: Загадка DMA[STM32F205RG]
Добавлено: Вс май 24, 2015 16:58:30
Neekeetos
Foxek писал(а):Один канал DMA собирает данные по UART в кольцевой буфер,
Как я и предположил исключения UART не обрабатываются, это приведет к остановке запросов к дма в случае возникновения переполнения или других ошибок. Поэтому нужно активировать прерывание уарта в нвик и написать обработчик уарт. В самом уарте нужно включить бит EIE в CR3, это будет генерировать прерывания в случае если активируются флажки ORE,FE,NF из SR. Соотв. в обработчике нужно будет зафиксировать что именно произошло и сбросить соответствующий флаг , это запустит нормальный прием.
Re: Загадка DMA[STM32F205RG]
Добавлено: Вс май 24, 2015 18:09:46
Foxek
Спасибо, попробую. А такой вопроса, какую именно ошибку я жду, какой именно флаг мне сбрасывать в прерывании?
Re: Загадка DMA[STM32F205RG]
Добавлено: Вс май 24, 2015 18:41:57
Neekeetos
Foxek писал(а):А такой вопроса, какую именно ошибку я жду
Это вопрос на 5 баллов, нужно писать прерывание и смотреть что вылезет. Я думаю что это скорее всего переполнение (aka overrun), но если процессор не занят ничем то она маловероятна, остаются ошибки фрейминга. Раз данные идут непрерывно вполне можно представить ситуацию, когда такты приемника и передатчика не совпадают и время от времени будет возникать ошибка синхронизации.
Foxek писал(а):какой именно флаг мне сбрасывать в прерывании?
Все сразу, при считывании SR и затем DR любой из них сбросится. Главное проверить что за флаги были активны, от этого зависят дальнейшие действия.
Re: Загадка DMA[STM32F205RG]
Добавлено: Вс май 24, 2015 23:06:52
Foxek
А допустим, если я отловлю эту ошибку, как мне дальше поступать?)Ведь по идее, флаг прерывания сбрасывается если прочитать данные, а они читаются посредством DMA. То есть если я найду ошибку мне надо просто включить прерывания по нему и в обработике даже нчиего делать не надо?
Re: Загадка DMA[STM32F205RG]
Добавлено: Пн май 25, 2015 00:30:29
B@R5uk
Задача программиста — написать не ту программу, которая работает, когда всё хорошо, а ту, которая работает, когда всё плохо. Другими словами, если ошибка возможна, то всегда должен быть код, который эту ошибку в случае возникновения соответствующим образом обрабатывает.
Re: Загадка DMA[STM32F205RG]
Добавлено: Пн май 25, 2015 07:05:01
Neekeetos
Foxek писал(а):А допустим, если я отловлю эту ошибку, как мне дальше поступать?)
Барсук в общем верно сказал. Как минимум нужно обнаруживать факт ошибок и сбрасывать их, тогда будет восстанавливаться нормальная работа а не как сейчас все встает колом. С другой стороны, если будет известно что за ошибка, можно попробовать еще и сделать так, чтобы она не возникала. Например в передатчике сделать паузы передачи или увеличить количество стоп битов или еще что. Все сильно зависит от конкретной проблемы, может дело в помехах из за которых возникают ошибки и уж тут мало что можно поделать кроме как молча потерять байт - два на приеме.
Re: Загадка DMA[STM32F205RG]
Добавлено: Ср июн 10, 2015 15:22:43
B@R5uk
Я тут внезапно понял, что при асинхронном приёме чтобы UART восстановил свою работу после неудачно принятой посылки необходимо, чтобы линия данных находилась в состоянии Idle в течении длительности хотя бы одной посылки или чтобы в одном из посылаемых сообщений все посылаемые биты (включая бит чётности) были единицами. Если данные шлются непрерывно, то может получиться так, что UART не сможет синхронизироваться по той причине, что каждый раз будет принимать за старт-бит какой-то из посылаемых нулей.
Возможно, у топикстартера именно такая проблема.