Использую в своем проекте DMA для циклической передачи данных через UART3. Контроллер STM32F100. При включении передачи через некоторое время работы контроллер зависает и вываливается в HardFault_Handler. Если передачу через DMA отключить, то все хорошо работает. В чем может быть причина? Куда копать?
Вот код:
/**
* @brief Инициализация DMA
* @retval None
*/
void InitDMA()
{
DMA_StructInit(&dma);
dma.DMA_PeripheralBaseAddr = (uint32_t)&(USART3->DR);
dma.DMA_MemoryBaseAddr = (uint32_t)&dataBuffer[0];
dma.DMA_DIR = DMA_DIR_PeripheralDST;
dma.DMA_BufferSize = DMA_BUFFER_SIZE;
dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
dma.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
dma.DMA_Mode = DMA_Mode_Normal;
DMA_Init(DMA1_Channel2, &dma);
USART_DMACmd(USART3, USART_DMAReq_Tx, ENABLE);
USART_Cmd(USART3, ENABLE);
//Разрешаем обработку прерываний по окончанию передачи
NVIC_EnableIRQ(DMA1_Channel2_IRQn);
DMA_ITConfig(DMA1_Channel2, DMA_IT_TC, ENABLE);
}
/**
* @brief Переключение DMA для циклической отправки данных
* @retval None
*/
void SendDMA()
{
DMA_Cmd(DMA1_Channel2, DISABLE);
DMA_Init(DMA1_Channel2, &dma);
DMA_Cmd(DMA1_Channel2, ENABLE);
}
Использовал таймер для циклического запуска DMA:
void TIM6_DAC_IRQHandler()
{
SendDMA();
if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM6, TIM_IT_Update);
debug_count++;
}
}
Пытался вынести опрос в отдельную задачу для RL-ARM, все равно не работает:
__task void UART_Poolling(void)
{
for(;;)
{
SendDMA();
os_dly_wait(100);
}
}
USART + DMA = HardFault_Handler
-
demmon1986
- Первый раз сказал Мяу!
- Сообщения: 25
- Зарегистрирован: Пт июл 04, 2014 14:27:58
- oleg110592
- Друг Кота
- Сообщения: 3832
- Зарегистрирован: Сб сен 10, 2011 17:46:25
Re: USART + DMA = HardFault_Handler
а обработчик DMA1_Channel2_IRQHandler есть?
Re: USART + DMA = HardFault_Handler
Может стека не хватает... может кучи... А ваще... у Кейла есть апнота 209... там расписано как найти причину попадания в Hard Fault...
"Я не даю готовых решений, я заставляю думать!"(С)
Re: USART + DMA = HardFault_Handler
Зачем в SendDMA() каждый раз вызывать DMA_Init(DMA1_Channel2, &dma) ?
Почему DMA_Cmd(DMA1_Channel2, DISABLE) не перенести в обработчик прерывания DMA1_Channel2_IRQHandler и выполнять её по Transfer Complete ?
Почему DMA_Cmd(DMA1_Channel2, DISABLE) не перенести в обработчик прерывания DMA1_Channel2_IRQHandler и выполнять её по Transfer Complete ?
Иван Сусанин - первый полупроводник 
-
maksim-starcity
- Родился
- Сообщения: 9
- Зарегистрирован: Вс янв 04, 2015 17:50:37
Re: USART + DMA = HardFault_Handler
Зачем такой огород?
dma.DMA_MemoryBaseAddr = (uint32_t)&dataBuffer[0];
Можно просто так
dma.DMA_MemoryBaseAddr = dataBuffer;
Попробуйте поменять местами строчки:
USART_DMACmd(USART3, USART_DMAReq_Tx, ENABLE);
USART_Cmd(USART3, ENABLE);
Вы включаете прерывание и не обрабатываете:
NVIC_EnableIRQ(DMA1_Channel2_IRQn);
Нужно либо закомментарить эту строку и следить за флагом transfer complete вручную в while-цикле, либо обрабатывать прерывание и сбрасывать флаг transfer complete.
dma.DMA_MemoryBaseAddr = (uint32_t)&dataBuffer[0];
Можно просто так
dma.DMA_MemoryBaseAddr = dataBuffer;
Попробуйте поменять местами строчки:
USART_DMACmd(USART3, USART_DMAReq_Tx, ENABLE);
USART_Cmd(USART3, ENABLE);
Вы включаете прерывание и не обрабатываете:
NVIC_EnableIRQ(DMA1_Channel2_IRQn);
Нужно либо закомментарить эту строку и следить за флагом transfer complete вручную в while-цикле, либо обрабатывать прерывание и сбрасывать флаг transfer complete.