cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L562 Using TIM1 to trigger ADC1 Ch1 sampling at 5 kHz with DMA1 storing to a circular buffer. Stores 12 samples, then no further samples stored. What can stop this chain from functioning?

Grizz
Associate III

Here is the setup (Using timer 1 - 16 Mhz clock, counter = 3200) using OC channel to produce scope signal on output pin):

void MX_TIM1_Init(void)
{
 
  /* USER CODE BEGIN TIM1_Init 0 */
 
  /* USER CODE END TIM1_Init 0 */
 
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};
  TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
 
  /* USER CODE BEGIN TIM1_Init 1 */
 
  /* USER CODE END TIM1_Init 1 */
  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 0;
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = 3200;
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.RepetitionCounter = 0;
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_OC_Init(&htim1) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
  sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_TOGGLE;
  sConfigOC.Pulse = 0;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
  sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
  if (HAL_TIM_OC_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
  sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
  sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
  sBreakDeadTimeConfig.DeadTime = 0;
  sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
  sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
  sBreakDeadTimeConfig.BreakFilter = 0;
  sBreakDeadTimeConfig.BreakAFMode = TIM_BREAK_AFMODE_INPUT;
  sBreakDeadTimeConfig.Break2State = TIM_BREAK2_DISABLE;
  sBreakDeadTimeConfig.Break2Polarity = TIM_BREAK2POLARITY_HIGH;
  sBreakDeadTimeConfig.Break2Filter = 0;
  sBreakDeadTimeConfig.Break2AFMode = TIM_BREAK_AFMODE_INPUT;
  sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
  if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM1_Init 2 */
 
  /* USER CODE END TIM1_Init 2 */
  HAL_TIM_MspPostInit(&htim1);
 
}

Next the ADC1 Setup - one single ended channel:

/* ADC1 init function */
void MX_ADC1_Init(void)
{
 
  /* USER CODE BEGIN ADC1_Init 0 */
 
  /* USER CODE END ADC1_Init 0 */
 
  ADC_MultiModeTypeDef multimode = {0};
  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.ExternalTrigConv = ADC_EXTERNALTRIG_T1_TRGO;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
  hadc1.Init.DMAContinuousRequests = ENABLE;
  hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
  hadc1.Init.OversamplingMode = DISABLE;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }
 
  /** Configure the ADC multi-mode
  */
  multimode.Mode = ADC_MODE_INDEPENDENT;
  if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
  {
    Error_Handler();
  }
 
  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_1;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ADC1_Init 2 */
 
  /* USER CODE END ADC1_Init 2 */
 
}

Next DMA1 setup:

/**
  * Enable DMA controller clock
  */
void MX_DMA_Init(void)
{
 
  /* DMA controller clock enable */
  __HAL_RCC_DMAMUX1_CLK_ENABLE();
  __HAL_RCC_DMA1_CLK_ENABLE();
 
  /* DMA interrupt init */
  /* DMA1_Channel1_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
 
}

Finally start of conversion:

void StartSampling(void)
{
	// Storing is disabled and buffers are idle
	SampleControl = SAMPLING_IDLE;
	BufferManagement = BUFFERS_IDLE;
 
	// Start the time base to trigger sampling at 5 Khz
	if (HAL_TIM_Base_Start(&htim1) != HAL_OK)
	{
		 Error_Handler();
	}
	// Start the output channel scope trigger
	if (HAL_TIM_OC_Start(&htim1, TIM_CHANNEL_1) != HAL_OK)
	{
		 Error_Handler();
	}
	// Start ADC Conversions and DMA Channel
	// Note: Assumes ADC1 and DMA Init methods have been called.
	if (HAL_ADC_Start_DMA(&hadc1, (uint32_t*)RawBuffer, RAW_BUFFER_LENGTH) != HAL_OK)
	{
		 Error_Handler();
	}
}

I have the half complete and full complete interrupts enabled. My breakpoints on these handlers are never taken. If you break into my idle loop and display the buffer, you see 12 samples were stored, then nothing. Each of the peripherals appears to be running, and no errors. Yet, data is no longer being converted and stored.

Any ideas on how to diagnose? Did I miss something in the setup?

2 REPLIES 2
Grizz
Associate III

I've finally had time to come back and debug this problem... I'm nearly at the root cause but am still digging.  It appears there may be a conflict in internal resources and starting up the USWB CDC connection causes the call functions/step debug functions to hang.

I am using the SDMMC peripheral in 8-bit mode to interface with an eMMC chip, have the TIM1->ADC1->DMA in in place and auto store samples in a ring buffer at 5 kHz, have j-tag full 5 signal interface enabled, and have icache enabled in 1-way through mode.

The Cube MXC IDE flags partial disabling of USB due to the 8-bit eMMC and 5-bit j-tag, but it points to loss of USB-C and charging logic which I am not using.

Does anyone know what the USB peripheral is doing that could cause what seems to be a memory write hold-off?  It almost feels like arbitration or something is in the middle of this, but I can't be sure.  As I have stated, clicking pause on the debug console enables the stalled write to complete and you can step over code until you get to the next function call which causes a stack frame write and the CPU core stalls again until you hit the debug pause.

Someone has to have run into something like this by now???

Grizz
Associate III

One more update... if I step into and then step over the MX_USB_Device_Init() then everything works fine.  Setting a breakpoint inside the method and resuming still causes the memory write stall.  I did notice the problem occurs in USB_LL_Start() invoking HAL_PCD_Start().  Within this functions there are __HAL_LOCK(), __HAL_PCD_ENABLE, and __HAL_UNLOCK.

Whatever evil thing is happening has to do with these 3 macros.  The step over of __HAL_PCD_ENABLE takes 3 seconds when stepping but returns immediately on a step-over from 2 call levels up.  It's the fast return that tells me I am in that odd state where we can no longer write to memory freely.  This blocks the DMA writes as it does the CPU writes to stack.  The pause and step forces the CPU along but the DMA is forever blocked.  Any ideas out there?