2

I'm trying to read ADC values from three different channels(right now, later it will be 6 channels, 3 on each ADC), and I would like to access my ADC buffer after some random time and send it forward using UART later on. Right now they are just connected to +3.3V with a trimpotentiometer inbetween, resulting in different voltages on all three pins, which means I should be able to read the ADCs wuite often? Anyway, to do this I'm using a STM32f303k8 board where I've set up ADC1 channel 2,4 & 11 to be used. I generated the code using STM32CubeMX, using HAL libraries, where I configured it to be using DMA in circular mode, scan conversion with continous conversion and different ranks. Upon startup(using breakpoints), I can see that the init-part of the code works fine. The ADC is initialized and the DMA is started, I even get values into my buffer from ADC1 with correct values, channel1 != channel2 != channel3. The problem is when proceeding, the process gets stuck in and infinite loop handler and does never reach my while(1) where I have some arbitrary statement. Code below.

I've been following different guides to see if maybe I've set it up wrong. One of them being https://tunizem.blogspot.com/2014/09/using-adc-with-dma-on-stm32.html?showComment=1562660027777#c1229743050555367742. I've tried changing the sampletime from 1.5 all the way up to 601.5 cycles, also tried changing EOCSelection from single to sequential.

ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;

void MX_DMA_Init(void) 
{
  /* DMA controller clock 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);
}


/* ADC1 init function */
void MX_ADC1_Init(void)
{
  ADC_MultiModeTypeDef multimode = {0};
  ADC_ChannelConfTypeDef sConfig = {0};

  /** Common config 
  */
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
  hadc1.Init.ContinuousConvMode = ENABLE;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.NbrOfConversion = 3;
  hadc1.Init.DMAContinuousRequests = ENABLE;//ENABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc1.Init.LowPowerAutoWait = DISABLE;
  hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;//OVERWRITTEN;
  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_2;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.SamplingTime = ADC_SAMPLETIME_61CYCLES_5;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
     Error_Handler();
  }
  /** Configure Regular Channel 
  */
  sConfig.Channel = ADC_CHANNEL_4;
  sConfig.Rank = ADC_REGULAR_RANK_2;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
     Error_Handler();
  }
  /** Configure Regular Channel 
  */
  sConfig.Channel = ADC_CHANNEL_11;
  sConfig.Rank = ADC_REGULAR_RANK_3;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

}

 *
 *
 *


uint32_t adcValue1[60];

int main(void)
{
  /* MCU Configuration-----------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the 
Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ADC1_Init();
  //MX_ADC2_Init();
  MX_I2C1_Init();
  MX_USART1_UART_Init();
  MX_USART2_UART_Init();

  //Start ADC writing to DMA on scan complete
  if(HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adcValue1, 120) != HAL_OK)
      return 0;


  uint32_t stopwatch = HAL_GetTick();

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while(1)
  {
      if(((uint32_t)HAL_GetTick() - stopwatch) > 49)
      {
          stopwatch = HAL_GetTick();
          HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_3);

          sprintf((char*)buffer, "(%d)\t ADC1, (%d)\t ADC2, (%d)\t ADC3", 
adcValue1[0],
                  adcValue1[1], adcValue1[2]);

      }
  }
  /* USER CODE END 3 */
}
}

I've got a breakpoint at "uint32_t stopwatch = HAL_GetTick();" where I can see that adcValue1 is reading values. Those are correct since there is 3.3V going into all three with the difference that the potentiometer is set to give out 2.2V at channel 2, i.e. it's lower than the other two. But this is the only time I can see a reading being done since it get stuck in the infinite loop after this.

enter code here

adcValue1   uint32_t [60]   0x20000220 <adcValue1>  
adcValue1[0]    uint32_t    2614    
adcValue1[1]    uint32_t    3638    
adcValue1[2]    uint32_t    3639    
adcValue1[3]    uint32_t    2612    
adcValue1[4]    uint32_t    3639    
adcValue1[5]    uint32_t    3637    
adcValue1[6]    uint32_t    2615    
adcValue1[7]    uint32_t    3642    
adcValue1[8]    uint32_t    3641    
adcValue1[9]    uint32_t    2616    
adcValue1[10]   uint32_t    3642    
adcValue1[11]   uint32_t    3638    
adcValue1[12]   uint32_t    2611    
adcValue1[13]   uint32_t    3637    
adcValue1[14]   uint32_t    3640    
adcValue1[15]   uint32_t    2614    
adcValue1[16]   uint32_t    3639    
adcValue1[17]   uint32_t    3639    
adcValue1[18]   uint32_t    2615    
adcValue1[19]   uint32_t    3643    


 * @brief  This is the code that gets called when the processor receives 
an
 *         unexpected interrupt.  This simply enters an infinite loop, 
preserving
 *         the system state for examination by a debugger.
 *
 * @param  None
 * @retval : None
 */

Default_Handler:
Infinite_Loop:  <--- STUCK HERE
    b   Infinite_Loop
    .size   Default_Handler, .-Default_Handler
Mikebebe
  • 21
  • 1
  • 2
  • Does this -http://www.keil.com/support/docs/3907.htm relate to your problem? – Piotr Kamoda Jul 09 '19 at 09:18
  • Good input, removing HAL_GetTick() resulted in the process reaching the statement and toggle the GPIO, but then it goes back to the infinite loop. So I removed all the GetTick calls and changed the statement to if(adcValue[0] != 0), but still reaches Default_Handler after 1 loop.. – Mikebebe Jul 09 '19 at 09:27
  • When removing HAL_GetTick() and HAL_Delay(), I noticed that I can use "Step Into" to actually make it work. The process enters my statement, toggles the pin and then back to the statement again etc. But if I press "Resume" and just let the process proceed, it doesn't reach my statement ever again, it just gets stuck. Could there be a timing problem?? – Mikebebe Jul 09 '19 at 09:40

1 Answers1

3

Default_Handler is invoked when there is an interrupt for which no handler exists in the user code. All addresses in the interrupt vector table point to this code, when you don't supply a handler for that interrupt.

You can examine the VECTACTIVE bits in SCB->ICSR (see the STM32F4 programming manual) to find out which interrupt vector is missing, then provide a proper handler in your code.

  • Okey, so I need an interrupt handler for the DMA? Does this mean I wont be able to just read the data whenever I want without interrupting my other processess which I'm going to implement? Or can I solve it without interrupting ? – Mikebebe Jul 09 '19 at 10:52
  • Of course it's possible, without using HAL functions. Just follow the Reference Manual, [AN4031](https://www.st.com/resource/en/application_note/dm00046011.pdf) and [AN3116](https://www.st.com/resource/en/application_note/cd00258017.pdf). – followed Monica to Codidact Jul 09 '19 at 11:16
  • @berendi No. Default handler is invoked if you have standard STM start-up code for all the exceptions. I do not think that OP wrote his own ones. Diagnosis is IMO wrong. – 0___________ Jul 09 '19 at 22:41
  • You can. But HAL library is designed this way. If you do not want interrupts you need to use bare registers. – 0___________ Jul 09 '19 at 22:43
  • If you use cube ide or still if use the hard fault plugin. It will show you what was the source of the HF and very often the address of the code where it happened – 0___________ Jul 09 '19 at 22:45
  • Do you have any sort of idea of where the problem lies? Since it doesn't reach HF when I use step into, it actually works as long as I don't let it run continuously.. – Mikebebe Jul 10 '19 at 07:38
  • @Mikebebe again, what does `SCB->ICSR` contain? – followed Monica to Codidact Jul 10 '19 at 07:43
  • Okej, this isn't one of my strongest sides. I had a hard time trying to figure out where the ICSR got set(stepped through the whole code). I didn't find the codelines, however I added SCB to watch and saw that first ICSR gets the value:100100000001111000000000000. When DMA gets started it resets to 0 I guess, cause it was only 0. When the program reaches HF ICSR gets the following values: 100000000001111100000011011. I'm sorry but I'm having a hard time trying to figure out what this actually means.. – Mikebebe Jul 10 '19 at 08:37
  • You have to figure out register access eventually, because apparently HAL won't do what you want. Anyway, the interrupt number is 11 (`DMA1_Channel1_IRQn`), meaning that your code didn't supply a `DMA1_Channel1_IRQHandler()` function, and the default one was called. – followed Monica to Codidact Jul 10 '19 at 15:41
  • @Mikebebe here's another idea. As long as you don't have more than 5 channels to convert, make a conversion sequence of 1 regular channel and the rest as injected channels. Injected channels have their own data registers, unlike regular channels that share one. With this sequence running continuously, you can read the converted values anytime directly from the controller. – followed Monica to Codidact Jul 10 '19 at 15:49