Страница 1 из 1

USART + DMA = HardFault_Handler

Добавлено: Сб янв 03, 2015 12:19:41
demmon1986
Использую в своем проекте 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);
}
}

Re: USART + DMA = HardFault_Handler

Добавлено: Сб янв 03, 2015 12:42:06
oleg110592
а обработчик DMA1_Channel2_IRQHandler есть?

Re: USART + DMA = HardFault_Handler

Добавлено: Сб янв 03, 2015 12:45:09
HHIMERA
Может стека не хватает... может кучи... А ваще... у Кейла есть апнота 209... там расписано как найти причину попадания в Hard Fault...

Re: USART + DMA = HardFault_Handler

Добавлено: Сб янв 03, 2015 12:51:00
Myp3ik
Зачем в SendDMA() каждый раз вызывать DMA_Init(DMA1_Channel2, &dma) ?
Почему DMA_Cmd(DMA1_Channel2, DISABLE) не перенести в обработчик прерывания DMA1_Channel2_IRQHandler и выполнять её по Transfer Complete ?

Re: USART + DMA = HardFault_Handler

Добавлено: Вс янв 04, 2015 19:21:44
maksim-starcity
Зачем такой огород?
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.