STM32F7:ADC DMA传输仅工作一次

时间:2019-03-20 23:53:12

标签: stm32 dma adc stm32f7 nucleo

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

这是小程序:

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选择了错误的通道(对于DMA2流4中的ADC1,通道4而不是通道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
  }
}

2 个答案:

答案 0 :(得分:1)

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

相同错误:

ADC1->SQR1 &= ~(0b1111 << ADC_SQR1_L);不会限制SQR1寄存器中的L。

应为ADC1->SQR1 &= ~(ADC_SQR1_L_Msk << ADC_SQR1_L_Pos);

到处都有相同的错误:(例如) 0b01 << DMA_SxCR_PSIZE

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

还有更多:)

答案 1 :(得分:0)

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