单片机技术网|技术阅读
登录|注册

您现在的位置是:单片机技术网 > 技术阅读 > RT1052内部ADC(四)——外部触发程序

RT1052内部ADC(四)——外部触发程序


编者悟语很多时候没有太大代价的开始是很有必要的。


通过前面三篇大家对RT1052内部ADC应该有一个整体的认识,前面部分主要是概述、接口说明和功能机制描述,此篇进行程序代码的分析与说明,通过这篇文章能让大家基本上掌握RT1052内部ADC的程序编制方法。

1 程序功能介绍


1)硬件平台


IMXRT1052-EVKB官方评估板。


2)软件IDE


IAR。


3)程序来源


官方SDK程序,版本为

SDK_2.5.0_MIMXRT1052xxxxB。


4)程序路径


C:\...\SDK_2.5.0_MIMXRT1052xxxxB\boards\evkbimxrt1050\driver_examples\adc_etc\adc_etc_hardware_trigger_conv\iar。


5)程序功能


程序实现了如何用ADC_ETC产生一个由PIT通道10触发ADC转换的过程。


每1秒PIT通道10会发送一个触发信号给ADC_ETC,ADC_ETC可以校准并管理多个外部触发器,并能产生ADC触发信号。


在此例中,ADC配置为硬件触发。一旦ADC从ADC_ETC获得触发信号,AD就开始转换,接着ADC_ETC的中断服务函数会被执行。


ADC0_IN15 和 ADC0_IN0作为ADC输入。


通过J23-1和 J23-2引脚采样电压。


2 程序框架


1)ADC配置及函数实现


fsl_adc.h 和 fsl_adc.c。


2)ADC外部触发控制实现


fsl_etc_adc.h 和 fsl_etc_adc.c。


3)PIT定时器


fsl_pit.c和fsl_pit.h。


4)XBAR内部关联


bsp_xbara.c和bsp_xbar.h。


5)主程序


adc_etc_hardware_trigger_conv.c。


3 ADC主要结构体


1)ADC配置结构体adc_config_t


typedef struct _adc_config

{    

     // 设置新转换结果是否可覆盖前面的转换结果

     bool enableOverWrite;   

 

     // 设置是否支持ADC连续转换                        

     bool enableContinuousConversion;   

 

     // 设置是否使能高速模式               

     bool enableHighSpeed; 

     

     // 设置是否使能低功耗模式

     bool enableLowPower;             


     // 设置是否使能长采样

     bool enableLongSample;     

     

     // 设置是否使能异步时钟输出                  

     bool enableAsynchronousClockOutput;         


     // 设置ADC参考电压源

     adc_reference_voltage_source_t \

     referenceVoltageSource;


     // 设置ADC采样周期模式

     adc_sample_period_mode_t \

     samplePeriodMode; 


     // 设置ADC时钟源

     adc_clock_source_t clockSource; 


     // 设置ADC时钟分频

     adc_clock_driver_t clockDriver;

    

     // 设置ADC转换精度位数

     adc_resolution_t resolution;   


} adc_config_t;


     2)ADC通道配置结构体adc_channel_config_t

typedef struct _adc_channel_config

{

    // 设置进行转换的通道号,范围为0-31

    uint32_t channelNumber;         

   

    // 设置是否一旦转换完成就产生一个中断请求

    bool \

    enableInterruptOnConversionCompleted; 


} adc_channel_config_t;


   3)ADC外部触发控制结构体adc_etc_config_t


typedef struct _adc_etc_config

{

    // enableTSCBypass = true,TSC触发器会直接

    // 触发ADC,否则将会通过ADC_ETC触发ADC

    bool enableTSCBypass;   


    // 使能外部TSC0触发器, 

    // 当enableTSCBypass=false有效

    bool enableTSC0Trigger; 


    // 使能外部TSC1触发器

    // 当enableTSCBypass = false有效

    bool enableTSC1Trigger; 


#if defined( \

    FSL_FEATURE_ADC_ETC_HAS_CTRL_\

    DMA_MODE_SEL) 

    && 

    FSL_FEATURE_ADC_ETC_HAS_CTRL_\

    DMA_MODE_SEL


    // 配置ADC_ETC DMA模式

    adc_etc_dma_mode_selection_t dmaMode; 


#endif   

  

    // 外部TSC0触发器优先级,7最高,0最低

    uint32_t TSC0triggerPriority;       

 

    // 外部TSC1触发器优先级,7最高,0最低

    uint32_t TSC1triggerPriority;    

  

    // 预分频器用于设置触发延时和间隔,

    // 可用范围为0-255,时钟会被

    // clockPreDivider+1进行分配

    uint32_t clockPreDivider;     

       

    // 使能相应的触发源可用范围为trigger0:0x01

    // trigger7:0x80。

    // 例如XBARtriggerMask=0x7U,trigger0, 

    // trigger1及trigger2被使能

    uint32_t XBARtriggerMask; 

} adc_etc_config_t;


   4)ADC触发器配置结构器

   adc_etc_trigger_config_t


typedef struct _adc_etc_trigger_config

{

    // 设置ADC1与ADC2是同步模式还是异步模式

    // 同步模式两个ADC的触发源相同 

    bool enableSyncMode;


    // 设置是软件触发还是硬件触发 

    bool enableSWTriggerMode;     


    // 设置ADC触发链的长度

    // 0: 对应触发链长度1--7:对应触发链长度8

    uint32_t triggerChainLength; 

 

    // 设置外部触发优先级,7最高,0最低

    uint32_t triggerPriority;    


    // 设置采样间隔延时计数器 

    uint32_t sampleIntervalDelay;


    // 设置触发器初始化延时计数器

    uint32_t initialDelay;   

    

} adc_etc_trigger_config_t;


     5)ADC触发链配置结构体

      adc_etc_trigger_chain_config_t

typedef struct _adc_etc_trigger_chain_config

{

    // 是否使能ADC_ETC BackToBack模式

    // 即一个接一个连续触发模式

    bool enableB2BMode;   

 

    // 选择相关的触发控制寄存器 1U : HC0, 

    // 2U: HC1, 4U: HC2,ADCx_HC0支持软硬件

    // 其他的只支持硬件触发

    uint32_t ADCHCRegisterSelect; 


    // 选择ADC采样通道

    uint32_t ADCChannelSelect;    


    // 配置触发后是否使能中断

    adc_etc_interrupt_enable_t InterruptEnable;

 

} adc_etc_trigger_chain_config_t;


      6)PIT配置结构体pit_config_t


typedef struct _pit_config

{    

     /*

      *   true:定时器可以在调试模式运行

      *   false:定时器在调试模式停止运行

      */

     bool enableRunInDebug; 


} pit_config_t;


4 XBAR映射


void XBARA_Configuration(void)

{

    // 初始化xbara模块 

    XBARA_Init(DEMO_XBARA_BASE);


    // 配置XBARA信号连接

    XBARA_SetSignalsConnection(

    DEMO_XBARA_BASE, 

    DEMO_XBARA_INPUT_PITCH0, 

    DEMO_XBARA_OUTPUT_ADC_ETC);

}


5 PIT定时器


void PIT_Configuration(void)

{

    // 初始化PIT结构体 

    pit_config_t pitConfig;


    // 初始化PIT模块

    PIT_GetDefaultConfig(&pitConfig);

    PIT_Init(PIT, &pitConfig);


    // 设置通道0的定时器周期

    PIT_SetTimerPeriod(PIT, kPIT_Chnl_0, 

    USEC_TO_COUNT(1000000U, \

    PIT_SOURCE_CLOCK)); 

}


USEC_TO_COUNT的宏定义如下,将始终频率转换为微秒。


#define USEC_TO_COUNT(us,clockFreqInHz)  \

        (uint64_t)((uint64_t)us*clockFreqInHz / 

        1000000U)


6 ADC程序


void ADC_Configuration(void)

{

    adc_config_t k_adcConfig;

    adc_channel_config_t \

    adcChannelConfigStruct;


    // 初始化ADC模块,使能硬件触发

    ADC_GetDefaultConfig(&k_adcConfig);

    ADC_Init(DEMO_ADC_BASE, &k_adcConfig);

    ADC_EnableHardwareTrigger( \

    DEMO_ADC_BASE, true);


    // 从ADC_ETC选择外部触发通道 

    adcChannelConfigStruct.channelNumber \

    = DEMO_ADC_USER_CHANNEL; 


    // 转换完成不使能中断

    adcChannelConfigStruct.\

    enableInterruptOnConversionCompleted\ 

    = false;


    // 设置通道组0配置参数,实际ADC通道15

    ADC_SetChannelConfig(

    DEMO_ADC_BASE, 

    DEMO_ADC_CHANNEL_GROUP0,

    &adcChannelConfigStruct);


    // 设置通道组1配置参数,实际ADC通道0

    ADC_SetChannelConfig(

    DEMO_ADC_BASE, 

    DEMO_ADC_CHANNEL_GROUP1,

    &adcChannelConfigStruct);


    // 进行自动硬件校准

    if (kStatus_Success == \

    ADC_DoAutoCalibration(DEMO_ADC_BASE))

    {

        PRINTF("ADC_DoAntoCalibration()\

        Done.\r\n");

    }

    else

    {

        PRINTF("ADC_DoAutoCalibration()\

        Failed.\r\n");

    }

}


7 中断服务程序


void EXAMPLE_ADC_ETC_DONE0_Handler\

(void)

{

     ADC_ETC_ClearInterruptStatusFlags(

     DEMO_ADC_ETC_BASE, 

     kADC_ETC_Trg0TriggerSource, 

     kADC_ETC_Done0StatusFlagMask

     );


     // 获取外部触发器0的触发链chain0的结果 

     g_AdcConversionValue0 = 

     ADC_ETC_GetADCConversionValue(\

     DEMO_ADC_ETC_BASE, 0U, 0U); 

     __DSB();//ARM v7 架构指令

}


void EXAMPLE_ADC_ETC_DONE1_Handler\

(void)

{

     ADC_ETC_ClearInterruptStatusFlags(

     DEMO_ADC_ETC_BASE,

     kADC_ETC_Trg0TriggerSource, 

     kADC_ETC_Done1StatusFlagMask

     );

    

     // 获取外部触发器0的触发链chain1的结果

     g_AdcConversionValue1 = 

     ADC_ETC_GetADCConversionValue(\

     DEMO_ADC_ETC_BASE, 0U, 1U); 

     __DSB();

}


8 主程序

int main(void)

{

    adc_etc_config_t adcEtcConfig;


    adc_etc_trigger_config_t \

    adcEtcTriggerConfig;


    adc_etc_trigger_chain_config_t \

    adcEtcTriggerChainConfig;


    BOARD_ConfigMPU();

    BOARD_InitPins();

    BOARD_BootClockRUN();

    BOARD_InitDebugConsole();


    // 设置PERCLK_CLK时钟源为OSC_CLK

    CLOCK_SetMux(kCLOCK_PerclkMux, 1U);


    // 设置PERCLK_CLK时钟分频为1

    CLOCK_SetDiv(kCLOCK_PerclkDiv, 0U);


    PRINTF("ADC_ETC_Hardware_Trigger_Conv\ 

    Start!\r\n");


      // ADC配置调用默认配置,转换精度12位

    ADC_Configuration();


    XBARA_Configuration();

    PIT_Configuration();


    // 获取ADC_ETC默认配置参数

    ADC_ETC_GetDefaultConfig(&adcEtcConfig);

     

    // 使能外部XBAR trigger0

    adcEtcConfig.XBARtriggerMask = 1U; 

    

    // 初始化ADC_ETC

    ADC_ETC_Init(DEMO_ADC_ETC_BASE,\

    &adcEtcConfig);


    // 设置XBAR trigger0 配置结构

    adcEtcTriggerConfig.enableSyncMode\

    = false;

    adcEtcTriggerConfig.enableSWTriggerMode\

    = false;

    

    // 触发链长度为2,宏为1,从0开始计

    adcEtcTriggerConfig.triggerChainLength = 

    DEMO_ADC_ETC_CHAIN_LENGTH; 


    adcEtcTriggerConfig.triggerPriority = 0U;

    adcEtcTriggerConfig.sampleIntervalDelay\

    = 0U;

    adcEtcTriggerConfig.initialDelay = 0U;

    

    ADC_ETC_SetTriggerConfig(

    DEMO_ADC_ETC_BASE, 

    0U,&adcEtcTriggerConfig);


    // 设置外部XBAR trigger0 chain配置,

    // 使能B2B模式

    adcEtcTriggerChainConfig.\ 

    enableB2BMode true;


    // 选择ADC_HC0寄存器用于触发控制寄存器

    adcEtcTriggerChainConfig.\

    ADCHCRegisterSelect 

    1U << DEMO_ADC_CHANNEL_GROUP0; 


    // 外部触发控制通道0,实际ADC输入通道是15

    adcEtcTriggerChainConfig.\

    ADCChannelSelect =

    DEMO_ADC_ETC_CHANNEL0; 


    // 使能Done0中断

    adcEtcTriggerChainConfig.InterruptEnable = 

    kADC_ETC_Done0InterruptEnable; 


    // 配置trigger0 chain0

    ADC_ETC_SetTriggerChainConfig( 

    DEMO_ADC_ETC_BASE, 0U, 0U, 

    &adcEtcTriggerChainConfig);


    // 选择ADC_HC1通到用于转换控制

    adcEtcTriggerChainConfig.\

    ADCHCRegisterSelect  

    1U << DEMO_ADC_CHANNEL_GROUP1; 


    // 外部触发控制通道1,实际ADC输入通道是0

    adcEtcTriggerChainConfig.\ 

    ADCChannelSelect =

    DEMO_ADC_ETC_CHANNEL1; 


    // 使能Done1中断

    adcEtcTriggerChainConfig.InterruptEnable = 

    kADC_ETC_Done1InterruptEnable; 


    // 配置trigger0 chain1

    ADC_ETC_SetTriggerChainConfig(

    DEMO_ADC_ETC_BASE, 0U, 1U,

    &adcEtcTriggerChainConfig);


    // 使能NVIC中断

    EnableIRQ(ADC_ETC_IRQ0_IRQn);

    EnableIRQ(ADC_ETC_IRQ1_IRQn);


    // 开启PIT channel0定时器

    PIT_StartTimer(PIT, kPIT_Chnl_0);


    PRINTF("ADC Full Range: %d\r\n",\

    g_Adc_12bitFullRange);


    PRINTF("Please press any key to get\ 

    user channel's ADC value.\r\n");


    while (1)

    {

        GETCHAR();

        PRINTF("ADC conversion vaule is %d\

        and %d\r\n",g_AdcConversionValue0, 

        g_AdcConversionValue1);

    }

}


9 运行结果

ADC_ETC_Hardware_Trigger_Conv Start!

ADC_DoAntoCalibration() Done.

ADC Full Range: XXXX

Please press any key to get user channel's ADC value.

ADC conversion vaule is 107 and 3882

ADC conversion vaule is 103 and 3884

ADC conversion vaule is 104 and 3880

ADC conversion vaule is 88 and 3890

ADC conversion vaule is 88 and 3890

ADC conversion vaule is 88 and 3890

ADC conversion vaule is 104 and 3882

ADC conversion vaule is 104 and 3882


10 总结    
    通过上面的代码举例,我们可以仿照SDK的程序,通过改变配置结构参数,及触发和通道等的内容用RT1052的内部ADC实现采样实际参数的需要,因为时间有限,描述难免存在缺漏,希望大家批评指正。

    公众号上放程序调整格式比较麻烦,所以用了很多换行符\,大家注意多担待下吧,有时间了会探索下在公众号上放代码的其他方式。

相关文章:





关注微信公众号【嵌入式杂牌军】,会为您送上阵阵清爽的风。

长按上图二维码关注公众号