STM32F7:ADC DMA传输仅工作一次

问题描述 投票:0回答:2

我想连续读取ADC值并使用DMA将它们写入数组。我使用的电路板是带有STM32F767ZI的Nucleo电路板。为了保持输出数据的简单,我使用的是带有STM32板包的Arduino IDE。我能够让ADC在连续模式下工作,但是当我添加DMA时,它将无法工作。似乎只传输了一个单一的值。包含要传输的数据量的NDTR寄存器保持在我将其设置为减1的值。

这是一个小程序:

volatile static bool dma_active = 1;
#define maxSamples 512
int16_t dataPoints[maxSamples];

void setup() {
  RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN; // GPIOA clock enable
  GPIOA->MODER |= (0b11 << 6); // PA3 as analog input
  Serial.begin(115200);
  Serial.println("starting");  
  initADC();
  initDMA();
}

void initADC() {
  RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;     // ADC1 clock enable
  ADC1->CR2 |= ADC_CR2_ADON;              //  ADC on
  ADC1->CR2 |= ADC_CR2_CONT;              //  continuous conversion mode
  ADC1->CR1 |= ADC_CR1_EOCIE;             // EOC interrupt
  ADC1->CR1 &= ~ADC_CR1_DISCEN;           // discontinuous mode disabled

  ADC1->CR1 &= ~ADC_CR1_SCAN;             // scan mode disabled
  ADC1->CR2 |= ADC_CR2_DMA;               // DMA mode
  ADC1->CR2 |= ADC_CR2_DDS;               // continuous DMA request
  ADC1->SQR3 |= 0b11;                     // ADC1_IN3 = PA3
  ADC1->SQR1 &= ~(0b1111 << ADC_SQR1_L);  // 1 conversion
  ADC1->CR2 |= ADC_CR2_SWSTART;           // Start conversion
}

void initDMA() {
  // DMA2 Stream4 : Channel 0 is ADC1
  RCC->AHB1ENR |= (1 << 22);                        // DMA2 clock enable
  DMA2_Stream4->CR &= ~DMA_SxCR_EN; // Disable
  while (DMA2_Stream4->CR & (1 << 0));
  DMA2_Stream4->CR |= (0b0100 << DMA_SxCR_CHSEL);   // Channel 4
  DMA2_Stream4->CR |= (0b11 << DMA_SxCR_PL);        // Very high priority
  DMA2_Stream4->PAR = (uint32_t)&ADC1->DR;          // Data source register
  DMA2_Stream4->M0AR = uint32_t(&dataPoints);      // Buffer 1
//  DMA2_Stream4->M1AR = uint32_t(&dataPoints1);      // Buffer 2
  DMA2_Stream4->NDTR = maxSamples;                  // Number of transferred data
  DMA2_Stream4->CR |= (0b01 << DMA_SxCR_PSIZE);     // Source data size (00 = byte, 01 = half word, 10 = word)
  DMA2_Stream4->CR |= (0b01 << DMA_SxCR_MSIZE);     // Memory data size (00 = byte, 01 = half word, 10 = word)
  DMA2_Stream4->CR |= DMA_SxCR_TCIE;                // Transfer complete interrupt enable
  DMA2_Stream4->CR |= DMA_SxCR_CIRC;                // circular mode
  DMA2_Stream4->CR &= ~DMA_SxCR_PINC;               // no peripheral increment mode
  DMA2_Stream4->CR |= DMA_SxCR_MINC;                // memory increment mode
//  DMA2_Stream4->CR |= DMA_SxCR_DBM;               // double buffer mode
  DMA2->HIFCR |= 0b111101;                         // clear flags
  NVIC_EnableIRQ(DMA2_Stream4_IRQn);
  delay(20);
  DMA2_Stream4->CR |= DMA_SxCR_EN;                  // Enable
}

void loop() {
  Serial.print(ADC1->DR);
  Serial.print("  ");
  Serial.print(dataPoints[0]);
  Serial.print("  ");
  Serial.print(dma_active);
  Serial.print("  ");
  Serial.println(DMA2_Stream4->NDTR);
  delay(100);
 }



void DMA2_Stream4_IRQHandler(void) {
  dma_active = 0;
}

我成功地在STM32F3上使用了ADC + DMA,但我不能让它在这个F7上工作。

GPIOA的时钟使能,PA3设置为模拟输入。 ADC的时钟启用。 ADC设置为连续模式,具有DMA模式和连续DMA请求。输入是PA3。 ADC转换开始。 DMA流4被设置为ADC1(通道0)的正确通道。设置输入和输出地址以及要传输的数据数量,并启用内存增量模式。然后启用流。

我不知道我在这里失去了什么。

我将衷心感谢您的帮助!

编辑#2

我意外地误将通道误认为是流,因此我为DMA选择了错误的通道(通道4而不是DMA2流4中ADC1的通道0)。这是它无效的主要问题。现在它在双缓冲模式下工作正常,除了一件事:当我启用传输完成中断时,程序不再工作。它只是通过Serial.print写一个字母,从开始的“s”。没有传输任何值。我做了中断,所以它应该暂时禁用DMA,但由于某种原因,中断似乎根本不起作用。

volatile static bool dma_active = 1;
#define maxSamples 512
int16_t dataPoints[maxSamples];
int16_t dataPoints2[maxSamples];
void setup() {
  RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN_Msk; // GPIOA clock enable
  GPIOA->MODER |= (0b11 << GPIO_MODER_MODER3_Pos); // PA3 as analog input
  Serial.begin(115200);
  Serial.println("starting");
   initDMA(); 
 initADC();
}

void initADC() {
  RCC->APB2ENR |= RCC_APB2ENR_ADC1EN_Msk;     // ADC1 clock enable
  ADC1->CR2 |= ADC_CR2_ADON_Msk;              //  ADC on
  ADC1->CR2 |= ADC_CR2_CONT_Msk;              //  continuous conversion mode
  ADC1->CR1 |= ADC_CR1_EOCIE_Msk;             // EOC interrupt
  ADC1->CR1 &= ~(ADC_CR1_DISCEN_Msk);           // discontinuous mode disabled

  ADC1->CR1 &= ~(ADC_CR1_SCAN_Msk);             // scan mode disabled
  ADC1->CR2 |= ADC_CR2_DMA_Msk;               // DMA mode
  ADC1->CR2 |= ADC_CR2_DDS_Msk;               // continuous DMA request
  ADC1->SQR3 |= 0b11;                     // ADC1_IN3 = PA3
  ADC1->SQR1 &= ~(0b1111 << ADC_SQR1_L_Pos);  // 1 conversion
  ADC1->CR2 |= ADC_CR2_SWSTART_Msk;           // Start conversion
}

void initDMA() {
  // DMA2 Stream4 : Channel 0 is ADC1
  RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN_Msk;                            // DMA2 clock enable
  DMA2_Stream4->CR &= ~(DMA_SxCR_EN_Msk);               // Disable
  while (DMA2_Stream4->CR & (1 << 0));
  DMA2->HIFCR |= 0b111101;                              // clear flags
  DMA2_Stream4->CR |= (0b11 << DMA_SxCR_PL_Pos);        // Very high priority
  DMA2_Stream4->PAR = (uint32_t)&(ADC1->DR);              // Data source register
  DMA2_Stream4->M0AR = uint32_t(&dataPoints);           // Buffer 1
  DMA2_Stream4->M1AR = uint32_t(&dataPoints2);           // Buffer 2
  DMA2_Stream4->NDTR = maxSamples;                      // Number of transferred data
  DMA2_Stream4->CR &= ~(0b1111 << DMA_SxCR_CHSEL_Pos);   // Channel 4
  DMA2_Stream4->CR |= (0b01 << DMA_SxCR_PSIZE_Pos);     // Source data size (00 = byte, 01 = half word, 10 = word)
  DMA2_Stream4->CR |= (0b01 << DMA_SxCR_MSIZE_Pos);     // Memory data size (00 = byte, 01 = half word, 10 = word)
//  DMA2_Stream4->CR |= DMA_SxCR_TCIE_Msk;                // Transfer complete interrupt enable
//  DMA2_Stream4->CR |= DMA_SxCR_CIRC_Msk;                // circular mode
  DMA2_Stream4->CR |= DMA_SxCR_DBM_Msk;                // double buffer mode
  DMA2_Stream4->CR &= ~(DMA_SxCR_PINC_Msk);             // no peripheral increment mode
  DMA2_Stream4->CR |= DMA_SxCR_MINC_Msk;                // memory increment mode

  NVIC_EnableIRQ(DMA2_Stream4_IRQn);
  DMA2_Stream4->CR |= DMA_SxCR_EN_Msk;                  // Enable
}

void loop() {
  for (int i = 0; i < maxSamples; i++)
  {
    Serial.print(dataPoints[i]);
    Serial.print("  ");
 //   Serial.print(dataPoints2[i]);
    Serial.print("  ");
    Serial.print(dma_active);
    Serial.println("");
  }
  delay(2000);
}

void DMA2_Stream4_IRQHandler(void) {
  if ((DMA2->HISR) & DMA_HISR_TCIF4_Msk)
  {
    DMA2_Stream4->CR &= ~DMA_SxCR_EN_Msk;                  // Disable
    dma_active = 0;
    DMA2->HIFCR |= 0b111101;                         // clear flags
  }
}
stm32 dma adc stm32f7 nucleo
2个回答
1
投票

首先,你不清除中断标志,并且一直在调用中断。

相同的错误:

qazxsw poi没有清除SQR1寄存器中的L.

它应该是ADC1->SQR1 &= ~(0b1111 << ADC_SQR1_L);

到处都是同样的错误:(例如)ADC1->SQR1 &= ~(ADC_SQR1_L_Msk << ADC_SQR1_L_Pos);

在我的.h文件中DMA_SxCR_PSIZE是0x00001800 :)

还有很多:)


0
投票

这是由于D和I缓存。禁用它。

© www.soinside.com 2019 - 2024. All rights reserved.