我想连续读取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
}
}
答案 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缓存所致。禁用它。