硬汉嵌入式论坛

 找回密码
 立即注册
查看: 3647|回复: 7
收起左侧

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

[复制链接]

2

主题

8

回帖

14

积分

新手上路

积分
14
发表于 2015-3-28 18:08:24 | 显示全部楼层 |阅读模式
在這邊看了不少文章。

小弟目前有個需求,需要搞一個雙通道,採樣率要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嗎?
感謝感謝。

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

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106760
QQ
发表于 2015-3-28 19:19:52 | 显示全部楼层
F407的ADC性能不是很好,很容易受到干扰。
1. 可以单ADC超频3Msps。
2. 2ADC快速交替采样可以的。
回复

使用道具 举报

2

主题

8

回帖

14

积分

新手上路

积分
14
 楼主| 发表于 2015-3-28 22:52:41 | 显示全部楼层
請問干擾是指何種干擾?

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

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

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

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106760
QQ
发表于 2015-3-29 00:10:59 | 显示全部楼层

回 akiolin 的帖子

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

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

2ADC 2通道的使用方式,可以用ST提供的2adc採樣範例修改嗎?
....... (2015-03-28 22:52) 
比如使用FMSC,特别是驱动TFT屏时,干扰比较厉害。

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

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

使用道具 举报

2

主题

8

回帖

14

积分

新手上路

积分
14
 楼主| 发表于 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通道要怎麼設置
有點迷惑
回复

使用道具 举报

2

主题

8

回帖

14

积分

新手上路

积分
14
 楼主| 发表于 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[20480];

/**********************************************************************************************************
*    函 數 名: 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);
}

還請各位大蝦不吝賜教

感謝不盡
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106760
QQ
发表于 2015-3-30 22:46:17 | 显示全部楼层

回 akiolin 的帖子

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

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

處理流程是依照下列方式進行:
....... (2015-03-29 14:55) 
可以实际用这个代码采集一段波形,然后使用Matlab绘制下,看看实际效果。
回复

使用道具 举报

2

主题

8

回帖

14

积分

新手上路

积分
14
 楼主| 发表于 2015-4-11 17:41:50 | 显示全部楼层
經過一些摸索後,以下是目前改出來的程式碼。[s:123]
使用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檔案 waveform.pdf (46 KB, 下载次数: 105)

以下是程式碼:
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[ADC_LEN];
volatile unsigned short ch1_buffer[CH1_LEN];
volatile unsigned short ch2_buffer[CH2_LEN];

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[j + 0] = adc_buffer[i + 0];
        ch2_buffer[j + 0] = adc_buffer[i + 1];
        ch2_buffer[j + 1] = adc_buffer[i + 2];
        ch1_buffer[j + 1] = adc_buffer[i + 3];
    }
}

void ADC_Buffer_Dump(void) {
    int i = 0;

    printf("rn ch1  ch2 start........rn");
    for(i = 0; i < CH1_LEN; i++) printf("[%3d] %4d %4drn", i, ch1_buffer, ch2_buffer);
    printf("rn ch1  ch2   end........rn");
}
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-5 01:23 , Processed in 0.247963 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表