结合使用STM32L4 ADC和DMA来读取图像传感器

问题描述

我正在阅读很多有关如何进行多通道ADC读数的文章。我的第一个成功是通过民意测验进行转换。然后我设法切换到具有DMA的ADC,但是我坚持了自己的新目标。我有要读取的图像传感器的模拟输出。我不会用完整的循环来打扰您,但基本上最重要的是列的循环:

  1. 设置像素列的8位地址(带有BSRR的8个GPIO引脚)
  2. 等待40ns,然后再读取模拟输出(由于计算导致的时间延迟,必要时添加一些NOP)
  3. 读取两个输出(同时读取2个像素)并对其进行一些计算

使用频道选择和轮询进行转换非常慢,我希望每秒有几帧(越多越好)。 我试图在“扫描”模式,2个通道,禁用contconv,将DMA设置为“正常”模式下进行此操作。我仍然看到每次ADC启动都会产生很大的开销。 最好的主意是使用ADC + DMA读取整行的320个值,然后停止ADC,进行一些计算,然后继续下一行。我想一个大问题是我尝试通过Truestudio在调试模式下对其进行检查,因此,任何建议如何以最佳方式进行都会受到赞赏。首先,一些澄清的问题:

  1. 尽管我有2个通道,但为DMA设置ADCbuffer [320]并写入HAL_ADC_Start_DMA(&hadc1,ADCBuffer,320)是否正确?我希望ADC在contconv模式下循环2个通道的序列,因此DMA将填充缓冲区。我的想法是检查列号,并在到达最后一个列时停止ADC。 如果这不可行,我将坚持使用ADCbuffer [2]和DMA的两个读数。

当我尝试使用具有2个通道和循环DMA的contconv ADC调试情况时,我注意到了许多问题(其中一些可能是由于调试器模式引起的)。顺便说一下,系统时钟为100MHz(我的处理器的Flash为4 WS),ADC的工作频率为80MHz:

  1. 无论我选择哪种积分时间,两次HAL_ADC_ConvHalfCpltCallback之间的时间都保持约150个滴答。即使在640.5个周期的情况下,我也会得到200个滴答声。我觉得很奇怪,但这可能是由于调试模式所致。
  2. 虽然定期调用HAL_ADC_ConvHalfCpltCallback,并且我可以插入下一个像素的总线更改,但不会随机调用HAL_ADC_ConvCpltCallback或很少随机调用。知道为什么会这样吗?

考虑到时序问题,我很好奇是否可以将ADC与DMA,禁用的contconv,正常模式DMA一起使用,但需要快速启动ADC(不是HAL)或中断ADC启动。因此,我可以确定我读取了2个值,将命令发送到传感器以读取下一个像素,依此类推,但开销较小。 我认为目前我的代码设置正确,但是如果有人发现解决某些问题的问题,我会予以张贴。我正在使用STM32L4R5ZI:

static void MX_ADC1_Init(void)
{


  ADC_ChannelConfTypeDef sConfig = {0};

  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_ENABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
  hadc1.Init.LowPowerAutoWait = DISABLE;
  hadc1.Init.ContinuousConvMode = ENABLE;
  hadc1.Init.NbrOfConversion = 2;
  hadc1.Init.NbrOfDiscConversion = 0;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.DMAContinuousRequests = ENABLE; 
  hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc1.Init.OversamplingMode = DISABLE;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }

  sConfig.Channel = ADC_CHANNEL_1;
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_12CYCLES_5; 
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  if (HAL_ADC_ConfigChannel(&hadc1,&sConfig) != HAL_OK)
  {
    Error_Handler();
  }

  sConfig.Channel = ADC_CHANNEL_2;
  sConfig.Rank = 2;
  if (HAL_ADC_ConfigChannel(&hadc1,&sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  HAL_NVIC_SetPriority(ADC1_IRQn,0);
  HAL_NVIC_EnableIRQ(ADC1_IRQn);
}


static void MX_DMA_Init(void)
{

  /* DMA controller clock enable */
  __HAL_RCC_DMAMUX1_CLK_ENABLE();
  __HAL_RCC_DMA2_CLK_ENABLE();
  __DMA2_CLK_ENABLE();

  /* DMA interrupt init */
  hdma_adc1.Instance = DMA2_Channel3;
  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_WORD;
  hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
  hdma_adc1.Init.Mode = DMA_CIRCULAR;
  hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;
  //HAL_DMA_DeInit(&hdma_adc1);
  HAL_DMA_Init(&hdma_adc1);
  __HAL_LINKDMA(&hadc1,DMA_Handle,hdma_adc1);

  DMAMUX1_Channel9->CCR = 0x5;


  /* DMA interrupt init */
  /* DMA1_Channel1_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA2_Channel3_IRQn,0);
  HAL_NVIC_EnableIRQ(DMA2_Channel3_IRQn);
  /* DMAMUX1_OVR_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMAMUX1_OVR_IRQn,0);
  HAL_NVIC_EnableIRQ(DMAMUX1_OVR_IRQn);

}


//somewhere in main.c,the read out loop:
uint32_t ADCBuffer[2];

GPIOF -> BSRR = (col) | (((~col) & 0xFF) << (16)); //r_col case,F0:7
HAL_ADC_Start_DMA(&hadc1,ADCBuffer,2);


//And the callbacks and handlers in STM32L4xx_it.c:

void DMA2_Channel3_IRQHandler(void)
{
  HAL_DMA_IRQHandler(&hdma_adc1);
  HAL_ADC_IRQHandler(&hadc1);
}

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
    if(vCol==159){
        HAL_ADC_Stop_DMA(hadc);
    }
}

void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc)
{
    vCol++;
    GPIOF -> BSRR = (vCol) | (((~vCol) & 0xFF) << (16)); //r_col case,F0:7
    
    rsum = rsum + ADCBuffer[0] + ADCBuffer[1];
}

void ADC_IRQHandler()
{
    HAL_ADC_IRQHandler(&hadc1);
}

非常感谢任何帮助和想法,以继续进行!

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...