2017-03-25 29 views
0

ST의 AN4666 코드를 기반으로 8 비트 병렬 데이터를 수신하도록 STM32F769I-EVAL을 구성했습니다. 내 입력 장치의 클럭은 입력 캡처 DMA를 트리거하고 OC 타이머 인터럽트가 전송을 사용할 수 없을 때까지 SDRAM에 데이터를 씁니다. 그 시점에서 SDRAM의 데이터를 조작하고 다른 곳으로 전송할 수 있습니다. 그러나 하드웨어를 구성하고 인풋 캡처를 활성화하면 DMA 전송 오류가 발생합니다. HAL_DMA_IRQHandler 함수의 errorcode (6) 값은 FIFO 및 전송 오류 플래그가 모두 설정되었음을 나타냅니다. datasheet (266 페이지 참조)에 대한 나의 이해에 따르면,이 방법이 가능해서는 안됩니다. 설정을 어딘가 잘못 설정했다고 가정합니다. 그러나 진행 방법에 대해서는 손실이 있습니다. 이 문제를 해결하기 위해 어떤 단계를 밟아야합니까?STM32 DMA 전송 오류 모두 FIFO 및 전송 오류 플래그 설정

DMA 구성 : 본체로부터

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim) 
{ 
    GPIO_InitTypeDef GPIO_InitStruct; 
    static DMA_HandleTypeDef hdma_tim; 

    /* TIMx clock enable */ 
    TIMx_CLK_ENABLE(); 

    /* Enable DMA clock */ 
    DMAx_CLK_ENABLE(); 

    /* Enable TIM input GPIO clock */ 
    TIMx_CHy_GPIOCLK_ENABLE(); 

    /* Configure input of TIMx_CHy on AF */ 
    GPIO_InitStruct.Pin = TIMx_CHy_PIN; 
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; 
    GPIO_InitStruct.Pull = GPIO_NOPULL; 
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; 
    GPIO_InitStruct.Alternate = GPIO_AF_TIMx; 
    HAL_GPIO_Init(TIMx_CHy_PORT, &GPIO_InitStruct); 

    /* Set the parameters to be configured */ 
    hdma_tim.Init.Channel = DMA_CHANNEL; 
    hdma_tim.Init.Direction = DMA_PERIPH_TO_MEMORY; 
    hdma_tim.Init.PeriphInc = DMA_PINC_DISABLE; 
    hdma_tim.Init.MemInc = DMA_MINC_ENABLE; 
    hdma_tim.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE ; /* Reading in GPIO PC[7:0]*/ 
    hdma_tim.Init.MemDataAlignment = DMA_MDATAALIGN_WORD ; 
    hdma_tim.Init.Mode = DMA_NORMAL; /* double memory buffer used */ 
    hdma_tim.Init.Priority = DMA_PRIORITY_HIGH; 
    hdma_tim.Init.FIFOMode = DMA_FIFOMODE_ENABLE; /* using FIFO mode since memory datasize=32bit and GPIO=8bits in our case */ 
    hdma_tim.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL; /* flushing FIFO at each 32bit reception (4 data) */ 
    hdma_tim.Init.MemBurst = DMA_MBURST_SINGLE; 
    hdma_tim.Init.PeriphBurst = DMA_PBURST_SINGLE; 

    /* Set hdma_tim instance */ 
    hdma_tim.Instance = DMA_STREAM; 

    /* Link hdma_tim to hdma[CC1] */ 
    __HAL_LINKDMA(htim, hdma[TIMx_DMA_ID], hdma_tim); 

    /* Initialize TIMx DMA handle */ 
    HAL_DMA_Init(htim->hdma[TIMx_DMA_ID]); 

    /* NVIC configuration for TIMx output compare interrupt */ 
    HAL_NVIC_SetPriority(TIMx_IRQn, 0, 2); 
    HAL_NVIC_EnableIRQ(TIMx_IRQn); 

    /* Configure the NVIC for DMA        */ 
    /* NVIC configuration for DMA transfer complete interrupt */ 
    HAL_NVIC_SetPriority(TIMx_DMA_IRQn, 0, 0); 
    HAL_NVIC_EnableIRQ(TIMx_DMA_IRQn); 

} 

코드 : 데이터를 수신하면서

/* Initialize SDRAM */ 
BSP_SDRAM_Init(); 

/* Configure the Data GPIO in input mode */ 
Data_GPIO_Config(); 

/* Set Timers instance */ 
TimHandle.Instance = TIMx; 

/* Initialize global Timer parameters */ 
TimHandle.Init.Period   = MAX_COUNTER; 
TimHandle.Init.Prescaler   = TIMx_PRESCALER - 1; 
TimHandle.Init.ClockDivision  = TIM_CLOCKDIVISION_DIV1; 
TimHandle.Init.CounterMode  = TIM_COUNTERMODE_UP; 
TimHandle.Init.RepetitionCounter = 0; 
if (HAL_TIM_Base_Init(&TimHandle) != HAL_OK) 
{ 
    /* Initialization Error */ 
    Error_Handler(); 
} 

//Initialize Timer "OC" channel for OC mode 
sOConfig.OCMode  = TIM_OCMODE_TIMING/*TIM_OCMODE_TOGGLE*/; 
sOConfig.OCPolarity = TIM_OCPOLARITY_HIGH; 
sOConfig.Pulse  = NB_COUNTER_CYCLE; 
sOConfig.OCNPolarity = TIM_OCPOLARITY_HIGH; 
sOConfig.OCFastMode = TIM_OCFAST_DISABLE; 
sOConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET; 
sOConfig.OCIdleState = TIM_OCIDLESTATE_RESET; 
if (HAL_TIM_OC_ConfigChannel(&TimHandle, &sOConfig, TIMx_CHANNEL_OC) != HAL_OK) 
{ 
    //Configuration Error 
Error_Handler(); 
} 

/* Initialize Timer "IC" channel for IC mode  */ 
sICConfig.ICPolarity = CLK_LATCHING_DATA_EDGE; 
sICConfig.ICSelection = TIM_ICSELECTION_DIRECTTI; 
sICConfig.ICPrescaler = TIM_ICPSC_DIV1; 
sICConfig.ICFilter = TIM_IC_FILTER; /* filter the clock signal over/undershoot */ 
if (HAL_TIM_IC_ConfigChannel(&TimHandle, &sICConfig, TIMx_CHANNEL_IC) != HAL_OK) 
{ 
    /* Configuration Error */ 
    Error_Handler(); 
} 

/* Set the DMA memory0 conversion complete callback */ 
TimHandle.hdma[TIMx_DMA_ID]->XferCpltCallback = TransferComplete; 
/* Set the DMA memory1 conversion complete callback */ 
TimHandle.hdma[TIMx_DMA_ID]->XferM1CpltCallback = TransferComplete; 
/* Set the DMA error callback */ 
TimHandle.hdma[TIMx_DMA_ID]->XferErrorCallback = TransferError ; 

/* Update second memory address */ 
second_mem_address = (uint32_t)((SDRAM_BANK_ADDR + WRITE_READ_ADDR) + (DMA_MEM_BUFF_SIZE)); 

/* Start DMA multi buffer transfer */ 
if (HAL_DMAEx_MultiBufferStart_IT(TimHandle.hdma[TIMx_DMA_ID], GPIOx_IDR, (SDRAM_BANK_ADDR + WRITE_READ_ADDR), second_mem_address, DMA_MEM_BUFF_SIZE) != HAL_OK) 
{ 
    /* Transfer Error */ 
    Error_Handler(); 
} 

__HAL_TIM_ENABLE_DMA(&TimHandle, TIMx_DMA_CC); 

/* Enable the TIMx OC channel interrupt */ 
__HAL_TIM_ENABLE_IT(&TimHandle, TIMx_IT_OC); 
/* Enable the TIMX OC channel */ 
TIM_CCxChannelCmd(TimHandle.Instance, TIMx_CHANNEL_OC, TIM_CCx_ENABLE); 

/* Enable the TIMx IC channel */ 
TIM_CCxChannelCmd(TimHandle.Instance, TIMx_CHANNEL_IC, TIM_CCx_ENABLE); 

HAL_TIM_OC_Start(&TimHandle, TIMx_CHANNEL_OC); // enable counter 

/* processing while Timeout not reached */ 
while (timeout_flag == 0); 
+1

STlib HAL은 효과가없는 단지 부 아트웨어입니다. 직접 레지스터 프로그래밍을 사용하십시오. 그렇게하면 상태 레지스터를 직접 검사하고 플래그의 의미를 확인할 수 있습니다. 면밀한 검사를 위해 디버거를 사용하십시오. – Olaf

+0

ST의 HAL은 자신의 드라이버를 작성했을 때 상태 레지스터의 값을 변경합니다. 디버거에서 상태 레지스터를 볼 수 있으며 앞에서 설명한 오류 플래그가 DMA_HISR 인터럽트 상태 레지스터에 설정되어 있지만보고있는 문제를 해결하기 위해 무엇을 찾고 있어야하는지 알지 못합니다. – anOkCoder

+0

그 혼란에 대해 처음으로 들었을 때부터 HAL에서 작동하지 않습니다. 그것이 "하드웨어 ** 추상화 ** 계층"이라고 주장하기 때문에, 나는 그것이 가능하다고 생각할 것입니다. 그러나 디버깅과 코드가 복잡합니다. 하드웨어 액세스를 의미 론적 드라이버로 랩핑하십시오 (어쨌든, HAL이든 아니든). – Olaf

답변

1

에러는 FIFO 오버런 상태에 기인 하였다. FIFO 임계 값을 1/4에서 최대로 늘리면 전송 오류가 발생하지 않습니다.

cortex-M7은 DMA 전송에 문제를 일으킬 수있는 데이터 및 명령어 캐시를 도입하지만 이것이 사실이 아님을 확인했습니다. 자세한 정보는 here입니다.