關於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嗎?
感謝感謝。
又要如何驗證實際的採樣率? F407的ADC性能不是很好,很容易受到干扰。
1. 可以单ADC超频3Msps。
2. 2ADC快速交替采样可以的。 請問干擾是指何種干擾?
如果精度只要8bit,使用10bit採樣,可以降低嗎?
2ADC 2通道的使用方式,可以用ST提供的2adc採樣範例修改嗎?
又429和407的ADC是一樣的嗎 ?
回 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 感謝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通道要怎麼設置
有點迷惑 以下是小弟根據『雙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);
}
還請各位大蝦不吝賜教
感謝不盡
回 akiolin 的帖子
akiolin:以下是小弟根據『雙ADC快速交叉採樣』和『雙ADC多通道掃瞄』二個範例,參考修改出來的程式碼。目標是用雙ADC對雙通道進行採樣。以最高速度採樣即可。不需要使用Timer進行觸發。
處理流程是依照下列方式進行:
....... (2015-03-29 14:55) images/back.gif
可以实际用这个代码采集一段波形,然后使用Matlab绘制下,看看实际效果。 經過一些摸索後,以下是目前改出來的程式碼。
使用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]