STM32F3双ADC,具备交错模式

问题描述 投票:1回答:1

我试图达到10MSPS的部分双交错模式下,作为记录在STM32F30x ADC modes and application

首先,我试图用单一的DMA。我配置了DMA1通道1从ADC1和2通用数据寄存器读取。它的工作,但我也只能达到8.47MSPS的采样率。除此之外限制,ADC1开始溢出。 (寄存器ADC1_2-> CCR:MULT = 0×07,MDMA = 0×02,DELAY = 0×04)考虑到DMA从属ADC之后读取所述公共数据寄存器结束它的转换,这个问题似乎是合理的,在高采样率。

所以我决定用2个DMA。为每个ADC: 从ADC1-> DR DMA1通道1复制到SRAM 从ADC2-> DR DMA2通道1复制到SRAM (寄存器ADC1_2-> CCR:MULT = 0×07,MDMA = 0×00,DELAY = 0×04)

这种配置也工作,但再次达到8MSPS。以上这样的速度,ADC2开始溢出。我不明白为什么ADC2超支。我预计,这种设置是可行的。

当我在独立模式与DMA配置运行ADC1和ADC2上面,一切似乎都正常工作。没有超支,在5.1MSPS但二者独立ADC采样。

疑问一:当两个ADC独立模式下运行,并从同一来源(例如TIM2)触发,但ADC1在上升沿触发,ADC2在时钟的下降沿触发,会发生什么?将它的工作?这是未来的事情,我会尝试。

我一起工作的MCU是STM32F303CB。 ADC的采样时间为1.5周。

任何建议将被认真考虑。

编辑:我已经提供了关于STM32F3发现运行具有一个8 MHz晶体的最小样本代码。程序直接跳转到主()

// 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)
  }
}
embedded stm32 sampling dma
1个回答
2
投票

你不能做这种方式。您只需要使用一个DMA通道和两个样品中一个32位的DMA交易中传输。

在6位模式下我能比18MSPS归档更多

enter image description here

我不知道如何使用它HAL编程,因为我亲手做的只是光秃秃的寄存器方法

有一个硬件问题,以及(阅读勘误),有时在> 8位模式转移不能正常工作。

对于双DMA需要:防止任何核心访问SRAM存储器通过将堆和变量(除ADC缓冲区)在CCM RAM还是进入睡眠模式悬浮剂任何核心活动。

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