Embedded 带交错模式的STM32F3双ADC

Embedded 带交错模式的STM32F3双ADC,embedded,stm32,sampling,dma,Embedded,Stm32,Sampling,Dma,我正试图实现10MSP,如双交织模式一节中所述 首先,我尝试使用单DMA。我将DMA1通道1配置为从ADC1和2公共数据寄存器读取。它起作用了,但我只能达到8.47MSPS的采样率。超出该限制后,ADC1开始超支。 (寄存器ADC1_2->CCR:MULT=0x07,MDMA=0x02,DELAY=0x04)考虑到从adc结束转换后DMA读取公共数据寄存器,该问题在高采样率下似乎是合理的 所以我决定使用2个DMA。每个ADC一个: DMA1通道1从ADC1->DR复制到SRAM DMA2通道1从

我正试图实现10MSP,如双交织模式一节中所述

首先,我尝试使用单DMA。我将DMA1通道1配置为从ADC1和2公共数据寄存器读取。它起作用了,但我只能达到8.47MSPS的采样率。超出该限制后,ADC1开始超支。 (寄存器ADC1_2->CCR:MULT=0x07,MDMA=0x02,DELAY=0x04)考虑到从adc结束转换后DMA读取公共数据寄存器,该问题在高采样率下似乎是合理的

所以我决定使用2个DMA。每个ADC一个:
DMA1通道1从ADC1->DR复制到SRAM
DMA2通道1从ADC2->DR复制到SRAM
(寄存器ADC1_2->CCR:MULT=0x07,MDMA=0x00,延迟=0x04)

此配置也可以工作,但最高可达8SPS。高于该速率,ADC2开始超支。我无法理解为什么ADC2超支。我希望这个设置可以工作

当我使用上面的DMA配置在独立模式下运行ADC1和ADC2时,一切似乎都正常工作。无超限,两个ADC采样均为5.1MSPS,但独立

一个问题:当两个ADC以独立模式运行并从同一个源(例如TIM2)触发,但ADC1在时钟上升沿触发,ADC2在时钟下降沿触发时,会发生什么情况?这样行吗?这是我将尝试的下一件事

我使用的MCU是STM32F303CB
ADC采样时间为1.5个周期

如有任何建议,将不胜感激

编辑:我提供了一个在使用8MHz晶体的STM32F3 Discovery上运行的最小示例代码。程序直接跳转到main()


你不能这样做。您只需要使用一个DMA通道,两个样本都在一个32位DMA事务中传输

在6位模式下,我已存档超过18MSPS

我不知道如何使用HAL编程,因为我个人只使用裸寄存器方法

还有一个硬件问题(请阅读勘误表),有时在>8位模式下传输无法正常工作

对于双DMA,您需要:
通过将堆栈和变量(ADC缓冲区除外)放置在CCM RAM中或通过进入睡眠模式暂停任何核心活动,防止任何核心访问SRAM内存。

感谢您的回答!建议我应该使用双DMA。“当两个ADC在双交织模式下工作,且两个ADC都有一个DMA通道(MDMA[1:0]位等于0b10或0b11)时,可能会遇到DMA溢出情况。此限制适用于单一、连续和不连续模式。”我将尝试您的建议。顺便说一下,我忘了提到我是以12位进行采样的。再次感谢!我提供了一个示例代码。你能看一下吗?
// main.c
#include "stm32f30x.h"
#define DUALDMA

void sysinit();
void clockconfig();
void delay(int d);
void timerinit();
void adcinit();
void dmainit();
void dualdmainit();

int main(){
    sysinit();
    clockconfig();
    timerinit();

    #ifdef DUALDMA
    dualdmainit();
    #else
    dmainit();
    #endif

    adcinit();

    RCC->AHBENR |= RCC_AHBENR_GPIOEEN; // GPIOE enable
    RCC->AHBENR |= RCC_AHBENR_GPIOAEN; // GPIOA enable
    GPIOE->MODER = 0x55555555; // GPIOE -> output 
    GPIOA->MODER |= 0x0000FFFF;// GPIOA -> analog

    // Reset SRAM memory area
    for(int i = 0;i<1024*4;i+=4){
        *((uint32_t*)(0x20000800+i)) = 0;
    }


    // Blink LEDs
    while(1){
        GPIOE->ODR = 0xFFFF;
        delay(1000);
        GPIOE->ODR = 0x00FF;
        delay(1000);
    }
}

void delay(int d){
    // Dummy delay
    int l = d*1000;
    for(int i = 0;i<l;i++);
}

void sysinit(){

    //STM32F303 reset state
    /* Reset the RCC clock configuration to the default reset state ------------*/
  /* Set HSION bit */
  RCC->CR |= 0x00000001U;
  /* Reset CFGR register */
  RCC->CFGR &= 0xF87FC00CU;
  /* Reset HSEON, CSSON and PLLON bits */
  RCC->CR &= 0xFEF6FFFFU;
  /* Reset HSEBYP bit */
  RCC->CR &= 0xFFFBFFFFU;
  /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE bits */
  RCC->CFGR &= 0xFF80FFFFU;
  /* Reset PREDIV1[3:0] bits */
  RCC->CFGR2 &= 0xFFFFFFF0U;
  /* Reset USARTSW[1:0], I2CSW and TIMs bits */
  RCC->CFGR3 &= 0xFF00FCCCU;
  /* Disable all interrupts */
  RCC->CIR = 0x00000000U;
  SCB->VTOR = 0x08000000; /* Vector Table Relocation in Internal FLASH */

}
void adcinit(){

    RCC->AHBENR |= RCC_AHBENR_ADC12EN; // Enable ADC clock
    RCC->CFGR2 |= RCC_CFGR2_ADCPRE12_4;// ADC clock prescaler = 1
    ADC1->CFGR |= ADC_CFGR_EXTEN_0; // Trigger on rising edge
    ADC1->CFGR |= ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_1; // TIM1 TRGO2

    ADC1->SQR1  |= ADC_SQR1_SQ1_0 ; // ch 1
    ADC1->CFGR |= ADC_CFGR_OVRMOD; // Stop on overrun
    ADC1->CFGR |=  ADC_CFGR_DMAEN; // DMA enable
    ADC1->CR &= ~(ADC_CR_ADVREGEN_1 | ADC_CR_ADVREGEN_0); // Enable VREG
    ADC1->CR |=  ADC_CR_ADVREGEN_0;
    ADC1->CR |= ADC_CR_ADEN;

    while( (ADC1->ISR & ADC_ISR_ADRD) == 0 );


    ADC2->SQR1  |= ADC_SQR1_SQ1_0 ; // ch 1
    ADC2->CFGR |=   ADC_CFGR_DMAEN;
    ADC2->CR &= ~(ADC_CR_ADVREGEN_1 | ADC_CR_ADVREGEN_0);
    ADC2->CR |=  ADC_CR_ADVREGEN_0;
    ADC2->CR |= ADC_CR_ADEN;
    while( (ADC1->ISR & ADC_ISR_ADRD) == 0 );

    ADC1_2->CCR |= ADC12_CCR_DELAY_2 ; // Delay = 4, 5 Cycles
    #ifndef DUALDMA
    ADC1_2->CCR |= ADC12_CCR_MDMA_1; // If single DMA is selected, configure MDMA bits for 12 bits
    #endif
    ADC1_2->CCR |= ADC12_CCR_MULTI_2 | ADC12_CCR_MULTI_1 | ADC12_CCR_MULTI_0; // Interleaved mode


}

void dmainit(){
    // DMA config for Single DMA, 32 bits
    RCC->AHBENR |= RCC_AHBENR_DMA1EN;

    DMA1_Channel1->CPAR = (uint32_t)&ADC1_2->CDR;
    DMA1_Channel1->CMAR = 0x20000800;
    DMA1_Channel1->CNDTR = 1024;
    DMA1_Channel1->CCR = DMA_CCR_EN | DMA_CCR_MINC | DMA_CCR_MSIZE_1 | DMA_CCR_PSIZE_1;
    //DMA1_Channel1->CCR = DMA_CCR_EN | DMA_CCR_MINC ;

}

void dualdmainit(){
    // DMA config for DUAL DMA, 16bits
    RCC->AHBENR |= RCC_AHBENR_DMA1EN; // DMA1 Enable
    RCC->AHBENR |= RCC_AHBENR_DMA2EN; // DMA2 Enable

    DMA1_Channel1->CPAR = (uint32_t)&ADC1->DR;
    DMA1_Channel1->CMAR = 0x20000800;
    DMA1_Channel1->CNDTR = 1024;
    DMA1_Channel1->CCR = DMA_CCR_EN | DMA_CCR_MINC | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0;

    DMA2_Channel1->CPAR = (uint32_t)&ADC2->DR;
    DMA2_Channel1->CMAR = 0x20000800+1024*2;
    DMA2_Channel1->CNDTR = 1024;
    DMA2_Channel1->CCR = DMA_CCR_EN | DMA_CCR_MINC | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0;

}

void timerinit(){
    RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; // Enable TIM1
    TIM1->CR2 |= TIM_CR2_MMS2_1; // Update event selected as TRGO2
    TIM1->PSC = 0;
    TIM1->ARR = 0x0d; // 5 MHz (72 MHz / 14 )
    TIM1->CR1 |= TIM_CR1_CEN;
}
void clockconfig(){
    // External oscillator (HSE): 8MHz 
    RCC->CR |= RCC_CR_HSEON; // Enable HSE
    while( (RCC->CR & RCC_CR_HSERDY) == 0 );

    RCC->CFGR |= RCC_CFGR_PLLMULL9; // PLL MUL = x9
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV2; // APB1 Prescaler = 2
    RCC->CFGR |= RCC_CFGR_PLLSRC; // PLL source = HSE

    FLASH->ACR |= FLASH_ACR_LATENCY_1; // Two wait states

    RCC->CR |= RCC_CR_PLLON;  // Enable and wait PLL
    while( (RCC->CR & RCC_CR_PLLRDY) == 0 );

    RCC->CFGR |= RCC_CFGR_SW_PLL; // Select PLL as system clock

}

LR_IROM1 0x08000000 0x00020000  {    ; load region size_region
  ER_IROM1 0x08000000 0x00020000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_IRAM2 0x10000000 0x00000200  {  ; RW data
   .ANY (+RW +ZI)
  }
}