STM32l431: ADC + DMA + Timer = fel

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Rick81
Inlägg: 746
Blev medlem: 30 december 2005, 13:07:09

STM32l431: ADC + DMA + Timer = fel

Inlägg av Rick81 »

Jag blir tokig på detta.
Har satt upp Tim6 för att trigga ADC och via DMA2 spara ned 100 ADC värden i en buffer. Allt verkar funkar, DMA räknaren minskar och jag får DMA interrupt, men bara första värdet sparas i arrayen, resten blir 0 (init värden). Nån som ser var jag missat?

Jag har använt cubeMX för genera initiering och sedan lagt till kod för att köra.

Kod: Markera allt

void main()
	....
	for(i = 0; i < ADC_CONVERTED_DATA_BUFFER_SIZE; i++)
	{
		aADCxConvertedData[i] = 0;
	}
 
	Configure_ADC();
	Configure_DMA();
	Configure_TIM_TimeBase_ADC_trigger();
 
	__HAL_RCC_ADC_CLK_ENABLE();
	__HAL_RCC_DMA2_CLK_ENABLE();
	PrintDMA();
	HAL_TIM_Base_Start(&htim6);
	err = HAL_ADC_Start_DMA(&hadc1,(uint32_t *)aADCxConvertedData, ADC_CONVERTED_DATA_BUFFER_SIZE);
	if (err != HAL_OK)
	{
		printf("DMA err %d\n\r", err);
	}
	PrintDMA();
 
	HAL_NVIC_SetPriority(DMA2_Channel3_IRQn, 0, 0);
	HAL_NVIC_EnableIRQ(DMA2_Channel3_IRQn);
 
	HW_TIM_Delay(100);	// wait 100 ms
 
	for(i = 0; i < 10; i++)
	{
		printf("%d\n\r", aADCxConvertedData[i]);
	}
}
	
	
void PrintDMA()
{
	printf("TIM6: %d: DMA2: %d: %d/%d\n\r", (int)htim6.Instance->CNT, (int)LL_DMA_IsActiveFlag_TC3(DMA2), LL_DMA_GetDataLength(DMA2, LL_DMA_CHANNEL_3), ADC_CONVERTED_DATA_BUFFER_SIZE);
	printf("En %d. Flags %d %d\n\r", LL_DMA_IsEnabledChannel(DMA2, LL_DMA_CHANNEL_3), (int)LL_DMA_IsActiveFlag_TE1(DMA2), (int)LL_DMA_IsActiveFlag_TE2(DMA2));
 
}
 
 
 
void Configure_ADC(void)
{
	//ADC_ChannelConfTypeDef sConfig = {0};
 
	/* USER CODE BEGIN ADC1_Init 1 */
 
	/* USER CODE END ADC1_Init 1 */
	/** Common config
	*/
	hadc1.Instance = ADC1;
	hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
	hadc1.Init.Resolution = ADC_RESOLUTION_12B;
	hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
	hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
	hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
	hadc1.Init.LowPowerAutoWait = DISABLE;
	hadc1.Init.ContinuousConvMode = DISABLE;
	hadc1.Init.NbrOfConversion = 1;
	hadc1.Init.DiscontinuousConvMode = DISABLE;
	hadc1.Init.NbrOfDiscConversion = 1;
	hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIG_T6_TRGO;
	hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
	hadc1.Init.DMAContinuousRequests = DISABLE;
	hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
	hadc1.Init.OversamplingMode = DISABLE;
 
	hadc1.Init.ContinuousConvMode = ENABLE;
	hadc1.Init.DiscontinuousConvMode = DISABLE;
	hadc1.Init.DMAContinuousRequests = ENABLE;
 
	if (HAL_ADC_Init(&hadc1) != HAL_OK)
	{
	//Error_Handler();
	}
	
	if (HAL_ADC_ConfigChannel(&hadc1, ADC_CHANNEL_13) != HAL_OK)
	{
	//Error_Handler();
	}
}
 
void Configure_DMA(void)
{
	GPIO_InitTypeDef  GPIO_InitStruct;
 
 
	HAL_DMA_DeInit(&hdma_adc1);
 
	__HAL_RCC_DMA2_FORCE_RESET();
	__HAL_RCC_DMA2_RELEASE_RESET();
 
	__HAL_RCC_ADC_CLK_ENABLE();
	__HAL_RCC_GPIOC_CLK_ENABLE();
	/**ADC1 GPIO Configuration
	PC4     ------> ADC1_IN13
	*/
	GPIO_InitStruct.Pin = GPIO_PIN_4;
	GPIO_InitStruct.Mode = GPIO_MODE_ANALOG_ADC_CONTROL;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
 
	/* ADC1 DMA Init */
	/* ADC1 Init */
	hdma_adc1.Instance = DMA2_Channel3;
	hdma_adc1.Init.Request = DMA_REQUEST_0;
	hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
	hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
	hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
	hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
	hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
	hdma_adc1.Init.Mode = DMA_NORMAL;
	hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;
	if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
	{
		Error_Handler();
	}
 
	__HAL_LINKDMA(&hadc1,DMA_Handle,hdma_adc1);
}
 
 
void Configure_TIM_TimeBase_ADC_trigger(void)
{
	
	TIM_MasterConfigTypeDef sMasterConfig = {0};
 
	/* USER CODE BEGIN TIM6_Init 1 */
 
	__HAL_RCC_TIM6_CLK_ENABLE();
	/* USER CODE END TIM6_Init 1 */
	htim6.Instance = TIM6;
	htim6.Init.Prescaler = 20;	//timer_prescaler-1;
	htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
	htim6.Init.Period = 1000;
	htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
	htim6.Init.RepetitionCounter = 0;
	if (HAL_TIM_Base_Init(&htim6) != HAL_OK)
	{
		Error_Handler();
	}
	sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
 
	sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
	if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK)
	{
		Error_Handler();
	}
 
}
Användarvisningsbild
adent
Inlägg: 4094
Blev medlem: 27 november 2008, 22:56:23
Ort: Utanför Jönköping
Kontakt:

Re: STM32l431: ADC + DMA + Timer = fel

Inlägg av adent »

Mycket intressant. Jag är inte insatt i stm32:ans DMA än. Har pillat på DMA på TI:s MSP430 dock.

Första tanken är att denna raden eller motsvarande saknades, men det gör den ju inte:

hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;

Lite svårt när man inte själv kan snurra runt i koden och kolla.
Men om du löser det är jag nyfiken på att höra svaret!
Föresten hur är kedjan med timer, ADC och DMA uppbyggd? Ska läsa på om det.
(vem som triggar vem och var inställningarna görs)
Rick81
Inlägg: 746
Blev medlem: 30 december 2005, 13:07:09

Re: STM32l431: ADC + DMA + Timer = fel

Inlägg av Rick81 »

Flyttade

_HAL_RCC_ADC_CLK_ENABLE();
__HAL_RCC_DMA2_CLK_ENABLE();
till innan intiering av ADC och DMA och då funkar det. Förstår inte riktigt hur det kunde funka halvdant innan....

Så här funkar det:
1) Timer triggar ADC
2) ADC trigger DMA
3) DMA kör interupt när 100 mätningar är gjorda så processorn kan bearbeta data.

Ganska trevlig konstruktion.....
Skriv svar