您好!
我使用 ADC 通过 MSP430f5172微控制器感应电压和电流。 我正在使用 MODOSC 时钟、因此数据表显示它以5MHz 的频率运行。 然而、当我使用一个简单的 LED 打开和关闭代码来查看它的执行时间时、它的频率为10s 或更低。 这是测量 ADC 采样频率的正确方法吗? 我本来期望~300kHz、因为我正在使用采样并保存16个样本。
This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
您好!
我使用 ADC 通过 MSP430f5172微控制器感应电压和电流。 我正在使用 MODOSC 时钟、因此数据表显示它以5MHz 的频率运行。 然而、当我使用一个简单的 LED 打开和关闭代码来查看它的执行时间时、它的频率为10s 或更低。 这是测量 ADC 采样频率的正确方法吗? 我本来期望~300kHz、因为我正在使用采样并保存16个样本。
Bruce、您好!
感谢你的答复。 以下是我的代码。 我正在使用 DMA 并同时读取通道序列。
#include
#include
#include
//定义函数
void SetVcoreUp (unsigned int level);
void SetADC ();
void SetDMA();
#define T_BUCK 200 //降压级周期- 200MHz/500kHz (所需频率)=400
#define T_BOOST 200 ////升压级周期
unsigned int adc_result[9];// 10位 ADC 转换结果数组
int iin_temp;// 10位 ADC 转换结果数组
int Vin_temp;// 10位 ADC 转换结果数组
int vbat_temp;// 10位 ADC 转换结果数组
int ibat_temp;// 10位 ADC 转换结果数组
int Vout_temp;// 10位 ADC 转换结果数组
int Iout_temp;// 10位 ADC 转换结果数组
int Vbuckout_temp;
void main (void){
WDTCTL = WDTPW + WDTHOLD;//停止看门狗计时器
//配置 PWM 通道
P1SEL |= BIT7;//将 P1.7设置为输出方向-高降压
P1DIR |= BIT7;
P3SEL |= BIT0;//将 P3.0设置为输出方向- BAT_GD_EN
P3DIR |= BIT0;
P2SEL |= BIT0;//将 P2.0设置为输出方向-低降压
P2DIR |= BIT0;
P2SEL |= BIT2;//将 P2.2设置为输出方向-高升压
P2DIR |= BIT2;
P2SEL |= BIT3;//将 P2.3设置为输出方向-低升压
P2DIR |= BIT3;
P2SEL |= BIT6;//将 P2.6设定为输出方向- Vgate BAT
P2DIR |= BIT6;
//配置 ADC 引脚
PMAPPWD = 0x02D52;//启用写入访问以修改端口映射寄存器
PMAPCTL = PMAPRECFG;//允许在运行时重新配置
//P1MAP0|= PM_ANALOG;//修改所有 PxMAPy 寄存器- A0
P1MAP1|= PM_ANALOG;//修改所有 PxMAPy 寄存器- A1
P1MAP2|= PM_ANALOG;//修改所有 PxMAPy 寄存器- A2
P1MAP3|= PM_ANALOG;//修改所有 PxMAPy 寄存器- A3
P1OMAP4|= PM_ANALOG;//修改所有 PxMAPy 寄存器- A4
P1MAP5|= PM_ANALOG;//修改所有 PxMAPy 寄存器- A5
P3MAP5|= PM_ANALOG;//修改所有 PxMAPy 寄存器- A8
P3MAP6|= PM_ANALOG;//修改所有 PxMAPy 寄存器- A7
PMAPPWD = 0;//通过写入不正确的密钥来禁用写入访问以修改端口映射寄存器
P1SEL |=BIT5+BIT4+BIT3+BIT2+BIT1+BIT0;//在应用模拟信号时将端口映射寄存器 PxMAPy 与 PxSEL.y=1一起设置为 PM_ANALOG
P3SEL |=BIT6+BIT4;
//将 Vcore 设置增加到3级以支持 fsystem=25MHz
//注意:一次改变一个电平内核电压。
SetVcoreUp (0x01);
SetVcoreUp (0x02);
SetVcoreUp (0x03);
//将 DCO 初始化为25MHz
_bis_SR_register (SCG0);//禁用 FLL 控制循环-设置 SCG0
UCSCTL0 = 0x0000;//设置可能的最低 DCOx、MODx
UCSCTL1 = DCORSEL_6;//选择 DCO 范围4.6MHz-88MHz 运行
UCSCTL2 = FLLD_1_763;//将 DCO 乘法器设置为25MHz
//(N + 1)* FLLRef = Fdco
//(762 + 1)* 32768 = 25MHz
//设置 FLL Div = fDCOCLK/2
_BIC_SR_register (SCG0);//启用 FLL 控制循环-清除 SCG0
// DCO 范围位已经存在时、DCO 的最坏情况稳定时间
//已更改 n x 32 x 32 x f_MCLK / f_FLL_reference。 请参阅5xx 中的 UCS 一章
// UG 进行优化。
// 32 x 32 x 25 MHz/32、768Hz = 781250 = DCO 稳定的 MCLK 周期
//__delay_cycles (781250);
_DELAY_CYCLES (782000);
SetADC();
SetDMA();
SetPWM (T_BUCK、T_BOOST);
__DELAY_CYCLES (100);//序列转换之间的延迟
P1DIR |= BIT0;//将 P1.0设置为输出方向
for (;;){
// ADC 采样频率
P1OUT ^= BIT0;//使用异或切换 P1.0
while (ADC10CTL1 & BUSY);//如果 ADC10内核处于活动状态则等待
ADC10CTL0 |= ADC10ENC + ADC10SC;//采样和转换准备就绪
_bis_SR_register (CPUOFF + GIE);// LPM0、ADC10_ISR 将强制退出
}
_bis_SR_register (LPM0_bits);//输入 LPM0
}
// DMA ISR
#if defined (__TI_Compiler_version__)|| Defined (__IAR_systems_ICC__)
#pragma vector=dma_vector
_interrupt void DMA0_ISR (void)
#Elif defined (_GNU_)
void __attribute__((中断(DMA_vector)) DMA0_ISR (void)
其他
错误编译器不受支持!
#endif
{
switch (__evo_in_range (DMAIV、16))
{
情况0:中断;//无中断
案例2:
//转换序列完成
ADC10CTL0 &=~ADC10ENC;//禁用 ADC 转换
_BIC_SR_REGISTER_ON_EXIT (CPUOFF);//退出 LPM
中断;// DMA0IFG
案例4:中断;// DMA1IFG
案例6:中断;// DMA2IFG
案例8:中断;//保留
案例10:中断;//保留
案例12:中断;//保留
案例14:中断;//保留
案例16:中断;//保留
默认值:break;
}
}
//函数
void SetVcoreUp (无符号 int 级别)
{
//子例程来更改内核电压
//打开 PMM 寄存器进行写入
PMMCTL0_H = PMMPW_H;
//将 SVS/SVM 高电平设置为新的电平
SVSMHCTL = SVSHE + SVSHRVL0 *电平+ SVMHE + SVSMHRRL0 *电平;
//将 SVM 低电平设置为新的电平
SVSMLCTL = SVSLE + SVMLE + SVSMLRRL0 *电平;
//等待 SVM 稳定
while ((PMMIFG & SVSMLDLYIFG)=0);
//清除已设置的标志
PMMIFG &=~(SVMLVLRIFG + SVMLIFG);
//将 VCORE 设置为新的电平
PMMCTL0_L = PMMCOREV0 *电平;
//等待达到新级别
IF (((PMMIFG 和 SVMLIFG))
while ((PMMIFG & SVMLVLRIFG)=0);
//将 SVS/SVM 低电平侧设定为新的电平
SVSMLCTL = SVSLE + SVSLRVL0 *电平+ SVMLE + SVSMLRRL0 *电平;
//锁定 PMM 寄存器以进行写访问
PMMCTL0_H = 0x00;
}
//配置 ADC 通道
void SetADC (){
ADC10CTL0 = ADC10SHT_2 + ADC10MSC + ADC10ON;// 16xADC 时钟周期、多采样转换、ADC10ON
ADC10CTL1 = ADC10SSEL_0+ADC10SHP+ ADC10CONSEQ_1;// ADCCLK = MODOSC;采样信号来源于采样定时器、单次序列
ADC10CTL2 = ADC10RES;// 10位转换结果
ADC10MCTL0= ADC10INCH_8 + ADC10SREF_1;//选择 ADC 通道;使用 VR+= VREF 和 VR-= AVSS
//默认情况下、REFMSTR=1 => REFCTL 被用来配置内部基准
while (REFCTL0 & REFGENBUSY);//如果基准发生器忙,请等待
REFCTL0 |= REFVSEL_2 + REFON;//选择内部基准= 2.5V
_DELAY_CYCLS (75);//参考建立延迟(~75us)-ADC10采样和转换=(32+13)*2/SMCLK = 90/SMCLK = 75us
}
void SetDMA(){
//配置 DMA0 (ADC10IFG 触发器)
DMACTL0 = DMA0TSEL_24;// ADC10IFG 触发器
__data20_write_long ((uintptr_t)&DMA0SA、(uintptr_t)&ADC10MEM0);//源单地址
__data20_write_long ((uintptr_t)&DMA0DA、(uintptr_t)&ADC_Result [0]);//更新目标数组地址
DMA0SZ = 0x09;// 8次转换-字节或字传输的数量
DMA0CTL = DMADT_4 + DMADSTINCR_3 + DMAEN +DMAIE;// Rpt、inc dest、启用转换序列后的 int
}
是的,这接近于我得到的值。 不过、我有两个问题。 我们为什么要除以(16+11)。 我明白为什么有16个、但不确定是否有11个。 我的第二个问题 与在每个 通道中使用 DMA 与顺序代码进行感应有关。 我的硬件原型上有大约7个传感器、我认为使用 DMA 和自动扫描模式来获取所有通道将有助于我提高性能。 我是否应该使用某种方法来提高性能? 我在降压和升压转换器级中使用该器件、由于与开关频率(500kHz)相比、我的采样频率非常小、因此我的闭环无法稳定
1) 1) 11表示10个转换时钟和1个移动结果时钟。 [参考 UG 图27-7]。 查看 UG 表27-5、"10"指的是8位结果。 您的情况(10位)需要(12+1)才能实现正确的转换。
2) 2)带有 DMA 的 CONSEQ=1非常接近您可以做的最好的事情。 您可以选择 CONSEQ=3、但不能选择采样率。 只有一个采样电容器(SET)、因此您无法并行进行转换。
一个选项是减少采样/保持时间(SHT0)。 有一个较低的限制、它实际上是电气限制(源阻抗)、但如果您不处于该限制、则可以获取几个时钟[参考 UG 章节27.2.5.3]。 您还可以执行8位采样、这样可以减少2个转换时钟。 即使所有这些都不会使您获得超过40%的增益。
数据表仅声明200ksps (渐近)、并将其分布在9个通道上、每个通道的工作速率约为22ksps。 即使是单个500kHz 信号、也不会成功进行奈奎斯特采样。 我对开关稳压器的工作方式不了解多少详细信息。 您是否有机会在数字域中执行某些操作?
感谢您的详细回答。 我尝试在 PLECs 仿真中降低采样频率、它可以工作、但在硬件中不能工作。 我将研究其他选项。
此外、计算中可能缺少系数2、因为我刚刚检查了采样频率、它实际上是计算结果的~一半。 对于9个样本、采样频率为9kHz;对于1个样本、采样频率约为62.5KHz。 此外、当我使用子模块/主时钟时、采样频率高于 MODOSC。 我本来希望 MODCLCK 的值更高、但 DMA 也能与 MODCLK 配合使用、所以在使用这些替代时钟时、我没有获得正确的传感器读数。 我是否可以在设置中执行错误操作?
如果您使用的是 SMCLK (25MHz)、请记住 ADC10_A 被限制为5.5MHz 时钟[参考数据表(SLAS619R)第5.39节]、因此您需要对 SMCLK 进行分频、此时您也可以使用 MODCLK。
我怀疑您也受到源阻抗的限制;这通常表现为串扰。 这是一项物理定律(您将电子输入采样电容器的速度有多快?) 因此、这里没有太多技巧。 如果将 SHT0降低得太低、则会得到相同的效果。
UG 章节 27.2.5.3中有一个公式、可为您提供最短采样时间(然后转换为时钟)。 我的经验是,这个公式有点乐观,我通常不得不四舍五入。