akiolin 发表于 2015-3-28 18:08:24

關於3ADC高速採樣的範例擴展為雙通道

在這邊看了不少文章。

小弟目前有個需求,需要搞一個雙通道,採樣率要2.2MHz左右
想說使用3ADC單通道高速採樣的範例來修改成為雙通道,請問可行嗎?

又看了很多關於STM32F4 ADC的使用說明。
其中提到ADC的clock最高到36MHz,12bit的最高有效採樣率為2.4MSPS。

如果主頻是180MHz的429,ADC的 clock會在180/2 / 4 ==> 22.5MHz左右。
12bit精確度的情況下大約是22.5MHz / 15cycles ==> 1.5MSPS
如果可以用2ADC交錯方式,雙通道,可以達成每個通道3MSPS嗎?
感謝感謝。

又要如何驗證實際的採樣率?

eric2013 发表于 2015-3-28 19:19:52

F407的ADC性能不是很好,很容易受到干扰。
1. 可以单ADC超频3Msps。
2. 2ADC快速交替采样可以的。

akiolin 发表于 2015-3-28 22:52:41

請問干擾是指何種干擾?

如果精度只要8bit,使用10bit採樣,可以降低嗎?

2ADC 2通道的使用方式,可以用ST提供的2adc採樣範例修改嗎?

又429和407的ADC是一樣的嗎 ?

eric2013 发表于 2015-3-29 00:10:59

回 akiolin 的帖子

akiolin:請問干擾是指何種干擾?

如果精度只要8bit,使用10bit採樣,可以降低嗎?

2ADC 2通道的使用方式,可以用ST提供的2adc採樣範例修改嗎?
....... (2015-03-28 22:52) images/back.gif

比如使用FMSC,特别是驱动TFT屏时,干扰比较厉害。

降低到8bit或者10bit 效果跟12bit区别不大。

我们有例子的,429跟407使用一样,注意主频区别就行:看看基础篇配套例子,ADC的多种方式都有:
http://www.armbbs.cn/forum.php?mod=viewthread&tid=1285

akiolin 发表于 2015-3-29 12:03:50

感謝eric2013回覆

之前在看STM32F407的data shee, DM00037051.pdf,
t以及STM32F429 data sheet, DM00071990.pdf,
發現407沒有提到ENOB429有提到。大約是在10.5bit左右。

在DM00050879.pdf中提到429/439的adc跟art的操作關係 。
ART的模式對於ADC精確度有一定程度的影響。

請問這個部份,就實際應用上來說,大約到多大的程度?

例如我的應用在於定位控制來說,會影響很大嘛?

假設精度只要8bit,採樣用12bit。

看eric2013的程式碼,滿享受的。
寫得很清晰。

只是現在對於2ADC 2通道要怎麼設置
有點迷惑

akiolin 发表于 2015-3-29 14:55:18

以下是小弟根據『雙ADC快速交叉採樣』和『雙ADC多通道掃瞄』二個範例,參考修改出來的程式碼。

目標是用雙ADC對雙通道進行採樣。以最高速度採樣即可。不需要使用Timer進行觸發。

處理流程是依照下列方式進行:
0. 初始化ADC、DMA。
1. 開啟ADC、DMA,抓取資料。
2. 等待DMA傳輸完成中斷發生,在中斷函式中關閉ADC、停止DMA資料傳輸。
3. 把雙通道採樣得到的資料進行分離,然後進行計算。
4. 顯示結果。
5. 回到步驟1,依序進行。

目前是先搞定ADC、DMA的設定方式,之後針對DMA搬完後的中斷觸發程式碼進行研究。

對於
ADC_CommonInitStructure.ADC_Mode = ADC_DualMode_RegSimult;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1;

這二個設定,不知道是對還是不對?

對於DMA始能的部份,在『雙ADC快速交叉採樣』有啟動。
/* 使能 ADC1 DMA */
ADC_DMACmd(ADC1, ENABLE);

在『雙ADC多通道掃瞄』則沒有啟動。
在『雙ADC對雙通道』應該是不需要啟動才是。

接下來就是關於ADCBuffer中的資料排列方式。
目前是使用ADC_DMAAccessMode_1方式進行DMA搬移資料。

資料擺放方式是

PA5_ADC1, PA7_ADC1, PA5_ADC2, PA7_ADC2嘛?

PAX_ADCY -->代表從PAX來的資料,X是5或者7。Y可以是ADC1或者ADC2。
所以有四腫組合。資料擺放方式就需要向各位高手請教。


以下是程式碼:
#define ADC_CDR_ADDRESS    ((uint32_t)0x40012308)

/* 變量 ----------------------------------------------------------------------*/
__IO uint16_t ADCBuffer;

/**********************************************************************************************************
*    函 數 名: bsp_InitADC
*    功能說明: ADC初始化
*    形    參: 無
*    返 回 值: 無
**********************************************************************************************************/
void bsp_InitADC(void)
{
    ADC_InitTypeDef       ADC_InitStructure;
    ADC_CommonInitTypeDef ADC_CommonInitStructure;
    DMA_InitTypeDef       DMA_InitStructure;
    GPIO_InitTypeDef      GPIO_InitStructure;
    NVIC_InitTypeDef      NVIC_InitStructure;

    /* 使能 ADC1, ADC2, DMA2 和 GPIO 時鐘****************************/
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2, ENABLE);

    /* 配置引腳 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* DMA2 Stream0 channel0 配置 */
    DMA_InitStructure.DMA_Channel = DMA_Channel_0;
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCBuffer;
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC_CDR_ADDRESS;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
    DMA_InitStructure.DMA_BufferSize = 20480;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;         
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    DMA_Init(DMA2_Stream0, &DMA_InitStructure);

    DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);
    DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_HTIF0);

    DMA_Cmd(DMA2_Stream0, ENABLE);

    // warten bis DMA-Stream enable
    while(DMA_GetCmdStatus(DMA2_Stream0)==DISABLE);

    DMA_ITConfig(DMA2_Stream0, DMA_IT_TC | DMA_IT_HT, ENABLE);

    // NVIC konfig
    NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

   
    /****************************************************************************   
      PCLK2 = HCLK / 2
      下面選擇的是2分頻
      ADCCLK = PCLK2 /4 = HCLK / 4 = 168 / 4 = 42M
      雙ADC採樣頻率: 42 / 6 = 7Mbps
    *****************************************************************************/
   
    /* ADC 公共部分配置 *************************************************/
    ADC_CommonInitStructure.ADC_Mode = ADC_DualMode_RegSimult;
    ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
    ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1;
    ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
    ADC_CommonInit(&ADC_CommonInitStructure);
   
    ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    ADC_InitStructure.ADC_ScanConvMode = ENABLE;
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;

    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfConversion = 2;

    /* ADC1 規則通道配置 -------------------------------------------------------*/
    ADC_Init(ADC1, &ADC_InitStructure);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 1, ADC_SampleTime_3Cycles);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 2, ADC_SampleTime_3Cycles);

    /* ADC2 規則通道配置 -------------------------------------------------------*/
    ADC_Init(ADC2, &ADC_InitStructure);
    ADC_RegularChannelConfig(ADC2, ADC_Channel_5, 1, ADC_SampleTime_3Cycles);
    ADC_RegularChannelConfig(ADC2, ADC_Channel_7, 2, ADC_SampleTime_3Cycles);

    /* 使能 ADC1 DMA */
    ADC_DMACmd(ADC1, ENABLE);

    /* 使能DMA請求 (多ADC模式) --------------------------------------------------*/
    ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);

    /* 使能 ADC1 */
    ADC_Cmd(ADC1, ENABLE);
    /* 使能 ADC2 */
    ADC_Cmd(ADC2, ENABLE);

    /* 軟件啟動轉換 */
    ADC_SoftwareStartConv(ADC1);
}

還請各位大蝦不吝賜教

感謝不盡

eric2013 发表于 2015-3-30 22:46:17

回 akiolin 的帖子

akiolin:以下是小弟根據『雙ADC快速交叉採樣』和『雙ADC多通道掃瞄』二個範例,參考修改出來的程式碼。

目標是用雙ADC對雙通道進行採樣。以最高速度採樣即可。不需要使用Timer進行觸發。

處理流程是依照下列方式進行:
....... (2015-03-29 14:55) images/back.gif

可以实际用这个代码采集一段波形,然后使用Matlab绘制下,看看实际效果。

akiolin 发表于 2015-4-11 17:41:50

經過一些摸索後,以下是目前改出來的程式碼。
使用ADC1, ADC2對PA5, PA7進行取樣。
MCU是429。
Clock為180MHz,ADC Clock為APB2的一半,45MHz。
就給ADC小小的超頻,跑在45MHz。

3 cycles 取樣,12 cycles轉換 ==> 45M / 15 ==> 3MSPS

因為同時對PA5, PA7取樣,所以設定方式為
ADC1 ==> PA5, PA7
ADC2 ==> PA7, PA5

用3MSPS取樣的結果來看,8KHz方波,看來效果不錯。
目前用示波器確認過訊號是8KHz。
怎麼知道取樣率是3MSPS?
因為一個週期有375樣本點,所以一秒鐘8K個週期,總共有8K * 375 ==> 3MSPS

看來Noise有點大,需要想點辦法做一些濾波處理了。
可以看以下的pdf檔案

以下是程式碼:
void DMA2_Stream0_IRQHandler(void);
void RCC_Configuration(void);
void GPIO_Configuration(void);
void ADC_Configuration(void);
void DMA_Configuration(void);
void NVIC_Configuration(void);

void ADC_Buffer_Init(void);
void ADC_Buffer_Copy(void);
void ADC_Buffer_Dump(void);

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "stm32f4xx_adc.h"
#include "stm32f4xx_dma.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_gpio.h"
#include "misc.h"

#include "adc_dma.h"

#define ADC_BUFFER_LEN 4096
#define ADC_CDR_ADDRESS    0x40012308

volatile unsigned int dma_counts = 0;
volatile unsigned int dma_status = 0;

#define ADC_LEN (ADC_BUFFER_LEN << 1)
#define CH1_LEN    (ADC_BUFFER_LEN)
#define CH2_LEN    (ADC_BUFFER_LEN)

volatile unsigned short adc_buffer;
volatile unsigned short ch1_buffer;
volatile unsigned short ch2_buffer;

void ADC_Buffer_Init() {
    dma_counts = 0;
    dma_status = 0;
    memset(adc_buffer, 0xFF, sizeof(unsigned short) * ADC_LEN);
    memset(ch1_buffer, 0xFF, sizeof(unsigned short) * CH1_LEN);
    memset(ch2_buffer, 0xFF, sizeof(unsigned short) * CH2_LEN);
}

void RCC_Configuration(void) {
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2, ENABLE);
}

void GPIO_Configuration(void) {
    GPIO_InitTypeDef GPIO_InitStructure;

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
}

void DMA_Configuration(void) {
    DMA_InitTypeDef DMA_InitStructure;

    DMA_InitStructure.DMA_Channel = DMA_Channel_0;
    DMA_InitStructure.DMA_Memory0BaseAddr = (unsigned int)&adc_buffer;
    DMA_InitStructure.DMA_PeripheralBaseAddr = (unsigned int)ADC_CDR_ADDRESS;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
    DMA_InitStructure.DMA_BufferSize = ADC_LEN;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    DMA_Init(DMA2_Stream0, &DMA_InitStructure);

    // Enable DMA Stream Half / Transfer Complete interrupt
    DMA_ITConfig(DMA2_Stream0, DMA_IT_TC | DMA_IT_HT, ENABLE);

    // DMA2_Stream0 enable
    DMA_Cmd(DMA2_Stream0, ENABLE);
}

void ADC_Configuration(void) {
    ADC_CommonInitTypeDef ADC_CommonInitStructure;
    ADC_InitTypeDef ADC_InitStructure;

    // ADC Common Initialization
    ADC_CommonInitStructure.ADC_Mode = ADC_DualMode_RegSimult;
    ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
    ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1; // ADC 1 then 2
    ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_18Cycles;
    ADC_CommonInit(&ADC_CommonInitStructure);

    ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    ADC_InitStructure.ADC_ScanConvMode = ENABLE;
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; // Ignored
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfConversion = 2;

    // ADC1 regular channel 5, 7 configuration
    ADC_Init(ADC1, &ADC_InitStructure);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 1, ADC_SampleTime_3Cycles); // PA5 (3 or 15 cycles, less than 18-2)
    ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 2, ADC_SampleTime_3Cycles); // PA7 (3 or 15 cycles, less than 18-2)

    // ADC2 regular channel 7, 5 configuration
    ADC_Init(ADC2, &ADC_InitStructure);
    ADC_RegularChannelConfig(ADC2, ADC_Channel_7, 1, ADC_SampleTime_3Cycles); // PA7 (3 or 15 cycles, less than 18-2)
    ADC_RegularChannelConfig(ADC2, ADC_Channel_5, 2, ADC_SampleTime_3Cycles); // PA5 (3 or 15 cycles, less than 18-2)

    // Enable DMA request after last transfer (Multi-ADC mode)
    ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);

    // Enable ADC1 DMA
    ADC_DMACmd(ADC1, ENABLE);

    // Enable ADC1
    ADC_Cmd(ADC1, ENABLE);

    // Enable ADC2
    ADC_Cmd(ADC2, ENABLE);
}

void NVIC_Configuration(void) {
    NVIC_InitTypeDef NVIC_InitStructure;

    // Enable the DMA Stream IRQ Channel
    NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

void DMA2_Stream0_IRQHandler(void) {
    if (DMA_GetITStatus(DMA2_Stream0, DMA_IT_HTIF0)) {
      DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_HTIF0);
      GPIOG->ODR ^= GPIO_Pin_14;
    }

    if (DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0)) {
      DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);
      GPIOG->ODR ^= GPIO_Pin_13;
      dma_counts++;
      if(dma_status == 1) {
            ADC_Buffer_Copy();
            dma_status = 0;
      }
    }
}

void ADC_Buffer_Copy(void) {
    int i = 0;
    int j = 0;

    for(i = 0, j = 0; j < CH1_LEN; i += 4, j += 2) {
      ch1_buffer = adc_buffer;
      ch2_buffer = adc_buffer;
      ch2_buffer = adc_buffer;
      ch1_buffer = adc_buffer;
    }
}

void ADC_Buffer_Dump(void) {
    int i = 0;

    printf("rn ch1ch2 start........rn");
    for(i = 0; i < CH1_LEN; i++) printf("[%3d] %4d %4drn", i, ch1_buffer, ch2_buffer);
    printf("rn ch1ch2   end........rn");
}
页: [1]
查看完整版本: 關於3ADC高速採樣的範例擴展為雙通道