芯科ADC采集使用tailgating实现周期扫描与随机单次采样而不影响周期扫描采样时序的方法
我们在使用adc采样的时候有时候会遇到这样的场景,只用一个ADC,有一个需要周期采样的数据,并且时序要求比较高,比如心电数据这种时序要求高的采样对象,并且想多采样多个其他数据比如板子上的其他温度,气压,电压数据等这类对时序无要求的数据,正常我们的解决方案有两种:
1)将这类数据放到adc扫描列表中,而当产品对功耗非常敏感时,将这类较长时间才采样一次的数据放置到扫描列表里每次都参加扫描,将会导致功耗浪费在许多不需要的采集中,这是功耗敏感型应用所无法接受的
2)判断下扫描周期时间,避开adc周期采样时间,避免影响到adc周期扫描采样,但是这样也会导致功耗上升并且实现方法较为复杂
而在芯科的adc参考手册中,你可以看到这样一种方法,它可以实现不影响周期采样的时序的情况下,随机穿插一个单次采样,并且相对只有周期扫描的功耗上升微乎其微,这种方法叫tailgating,意思就是在adc采集时增加一个队列,将采集的命令都放在队列中,在随机来的采样命令中放置队列尾部,在每次周期采样时间实现队列中的命令,以下为原理:
实现的方法很简单,只需要将scan和single的adc采样方式,一起进行初始化,将scan ADC的命令放在定时器的周期中断中实现周期scan采样,然后在任意时候使用单次采样都会在下一次scan命令采集完进行单次采样命令。
下面是以定时中断扫描,按键触发单次采样并以串口输出结果为例的代码示例:
1、初始化ADC
void initIADC(void)
{
app_log("Init adc_tailgating\r\n");
// Declare initialization structures
IADC_Init_t init = IADC_INIT_DEFAULT;
IADC_AllConfigs_t initAllConfigs = IADC_ALLCONFIGS_DEFAULT;
IADC_InitScan_t initScan = IADC_INITSCAN_DEFAULT;
/*******************************************************************/
IADC_InitSingle_t initSingle = IADC_INITSINGLE_DEFAULT;
IADC_SingleInput_t initSingleInput = IADC_SINGLEINPUT_DEFAULT;
/*******************************************************************/
// Scan table structure
IADC_ScanTable_t scanTable = IADC_SCANTABLE_DEFAULT;
CMU_ClockEnable(cmuClock_IADC0, true);
/*******************************************************************/
app_log("ready to IADC_reset\r\n");
IADC_reset(IADC0);
app_log("IADC_reset done \r\n");
/*******************************************************************/
// Use the FSRC0 as the IADC clock so it can run in EM2
CMU_ClockSelectSet(cmuClock_IADCCLK, cmuSelect_FSRCO);
// Set the prescaler needed for the intended IADC clock frequency
init.srcClkPrescale = IADC_calcSrcClkPrescale(IADC0, CLK_SRC_ADC_FREQ, 0);
// Shutdown between conversions to reduce current
init.warmup = iadcWarmupNormal;
initSingle.singleTailgate = tailgating_switch;
/*
* Configuration 0 is used by both scan and single conversions by
* default. Use internal bandgap as the reference and specify the
* reference voltage in mV.
*
* Resolution is not configurable directly but is based on the
* selected oversampling ratio (osrHighSpeed), which defaults to
* 2x and generates 12-bit results.
*/
initAllConfigs.configs[0].reference = iadcCfgReferenceInt1V2;
initAllConfigs.configs[0].vRef = 1210;
initAllConfigs.configs[0].osrHighSpeed = iadcCfgOsrHighSpeed2x;
initAllConfigs.configs[0].analogGain = iadcCfgAnalogGain0P5x;
/*
* CLK_SRC_ADC is prescaled to derive the intended CLK_ADC frequency.
*
* Based on the default 2x oversampling rate (OSRHS)...
*
* conversion time = ((4 * OSRHS) + 2) / fCLK_ADC
*
* ...which, results in a maximum sampling rate of 833 ksps with the
* 2-clock input multiplexer switching time is included.
*/
initAllConfigs.configs[0].adcClkPrescale = IADC_calcAdcClkPrescale(IADC0,
CLK_ADC_FREQ,
0,
iadcCfgModeNormal,
init.srcClkPrescale);
/*
* Set the SCANFIFODVL flag when there are 4 entries in the scan
* FIFO.
*
* Tag FIFO entries with scan table entry IDs.
*
* Allow a scan conversion sequence to start as soon as there is a
* trigger event.
*/
initScan.dataValidLevel = iadcFifoCfgDvl4;
initScan.showId = true;
initScan.start = true;
/*
* Configure entries in scan table. CH0 is single-ended from
* input 0; CH1 is single-ended from input 1.
*/
scanTable.entries[0].posInput = IADC_INPUT_0_PORT_PIN;
scanTable.entries[0].negInput = iadcNegInputGnd;
scanTable.entries[0].includeInScan = true;
scanTable.entries[1].posInput = IADC_INPUT_1_PORT_PIN;
scanTable.entries[1].negInput = iadcNegInputGnd;
scanTable.entries[1].includeInScan = true;
scanTable.entries[2].posInput = iadcPosInputAvdd; // Add AVDD to scan for demonstration purposes
scanTable.entries[2].negInput = iadcNegInputGnd | 1; // When measuring a supply, PINNEG must be odd (1, 3, 5,...)
scanTable.entries[2].includeInScan = true;
scanTable.entries[3].posInput = iadcPosInputVddio; // Add VDDIO to scan for demonstration purposes
scanTable.entries[3].negInput = iadcNegInputGnd | 1; // When measuring a supply, PINNEG must be odd (1, 3, 5,...)
scanTable.entries[3].includeInScan = true;
scanTable.entries[4].posInput = iadcPosInputVss; // Add VSS to scan for demonstration purposes
scanTable.entries[4].negInput = iadcNegInputGnd | 1; // When measuring a supply, PINNEG must be odd (1, 3, 5,...)
scanTable.entries[4].includeInScan = false; // FIFO is only 4 entries deep
scanTable.entries[5].posInput = iadcPosInputVssaux; // Add VSSAUX (same as VSS) to scan for demonstration purposes
scanTable.entries[5].negInput = iadcNegInputGnd | 1; // When measuring a supply, PINNEG must be odd (1, 3, 5,...)
scanTable.entries[5].includeInScan = false;
scanTable.entries[6].posInput = iadcPosInputDvdd; // Add DVDD to scan for demonstration purposes
scanTable.entries[6].negInput = iadcNegInputGnd | 1; // When measuring a supply, PINNEG must be odd (1, 3, 5,...)
scanTable.entries[6].includeInScan = false;
scanTable.entries[7].posInput = iadcPosInputDecouple; // Add DECOUPLE to scan for demonstration purposes
scanTable.entries[7].negInput = iadcNegInputGnd | 1; // When measuring a supply, PINNEG must be odd (1, 3, 5,...)
scanTable.entries[7].includeInScan = false;
// Initialize IADC
IADC_init(IADC0, &init, &initAllConfigs);
// Initialize scan
IADC_initScan(IADC0, &initScan, &scanTable);
/*******************************************************************/
// Initialize Single
IADC_initSingle(IADC0, &initSingle, &initSingleInput);
/*******************************************************************/
// Allocate the analog bus for IADC0 inputs
GPIO->IADC_INPUT_0_BUS |= IADC_INPUT_0_BUSALLOC;
GPIO->IADC_INPUT_1_BUS |= IADC_INPUT_1_BUSALLOC;
// Clear any previous interrupt flags
IADC_clearInt(IADC0, _IADC_IF_MASK);
// Enable scan interrupts
IADC_enableInt(IADC0, IADC_IEN_SCANTABLEDONE);
// Enable single done interrupts
IADC_enableInt(IADC0, IADC_IEN_SINGLEDONE);
// Enable IADC interrupts
NVIC_ClearPendingIRQ(IADC_IRQn);
NVIC_EnableIRQ(IADC_IRQn);
}
2、初始化定时器,1秒定时
/**************************************************************************//**
* @brief LETIMER initialization
*****************************************************************************/
void initLETIMER(void)
{
CMU_LFXOInit_TypeDef lfxoInit = CMU_LFXOINIT_DEFAULT;
LETIMER_Init_TypeDef letimerInit = LETIMER_INIT_DEFAULT;
// Initialize the LFXO and use it as the EM23GRPACLK source
CMU_LFXOInit(&lfxoInit);
CMU_ClockSelectSet(cmuClock_EM23GRPACLK, cmuSelect_LFXO);
CMU_ClockEnable(cmuClock_LETIMER0, true);
// Calculate the top value (frequency) based on clock source
uint32_t topValue = CMU_ClockFreqGet(cmuClock_LETIMER0) / LETIMER_FREQ;
// Reload top on underflow, pulse output, and run in free mode
letimerInit.comp0Top = true;
letimerInit.topValue = topValue;
letimerInit.ufoa0 = letimerUFOAPulse;
letimerInit.repMode = letimerRepeatFree;
// Initialize LETIMER
LETIMER_Init(LETIMER0, &letimerInit);
// Clear any previous interrupt flags
LETIMER_IntClear(LETIMER0, _LETIMER_IF_MASK);
// Enable underflow interrupts
LETIMER_IntEnable(LETIMER0, LETIMER_IEN_UF);
// Enable LETIMER interrupts
NVIC_ClearPendingIRQ(LETIMER0_IRQn);
NVIC_EnableIRQ(LETIMER0_IRQn);
app_log("LETIMER0 init done\r\n");
}
3、定时器中断
/**************************************************************************//**
* @brief LETIMER IRQ Handler
*****************************************************************************/
void LETIMER0_IRQHandler(void)
{
uint32_t flags = LETIMER_IntGet(LETIMER0);
// Trigger an IADC scan conversion
IADC_command(IADC0, iadcCmdStartScan);
app_log("LETIMER0 timeout\r\n");
// Clear LETIMER interrupt flags
LETIMER_IntClear(LETIMER0, flags);
}
4、采样中断
/**************************************************************************//**
* @brief IADC interrupt handler
*****************************************************************************/
void IADC_IRQHandler(void)
{
IADC_Result_t result = {0, 0};
// While the FIFO count is non-zero...
while (IADC_getScanFifoCnt(IADC0))
{
// Pull a scan result from the FIFO
result = IADC_pullScanFifoResult(IADC0);
/*
* Calculate the voltage converted as follows:
*
* For single-ended conversions, the result can range from 0 to
* +Vref, i.e., for Vref = VBGR = 1.21V, and with analog gain = 0.5,
* 0xFFF represents the full scale value of 2.42V.
*/
scanResult[result.id] = result.data * 2.42 / 0xFFF;
/*
* Scan results 2 - 6 are for external supply voltages, which are
* presented to the IADC divided by 4 for conversion. Back this
* out to get the correct result in volts. Note that DECOUPLE,
* scan table entry 7 in this example, is an internal supply (the
* output of the core supply regulator) and is connected directly
* to the IADC without a divide-by-4 stage.
*/
if ((result.id > 1) && (result.id < 7)) {
scanResult[result.id] *= 4;
}
app_log("scanResult[%d] : %lf\r\n",result.id,scanResult[result.id]);
}
while (IADC_getSingleFifoCnt(IADC0))
{
sample = IADC_pullSingleFifoResult(IADC0);
singleResult = sample.data * 2.42 / 0xFFF;
app_log("singleResult : %lf\r\n",singleResult);
}
// Alternate between the first and second set of scan table entries.
if (result.id == 3) {
IADC_setScanMask(IADC0, 0x0070);
}
else {
IADC_setScanMask(IADC0, 0x000F);
}
/*
* Clear the scan table complete interrupt. Reading FIFO results
* does not do this automatically.
*/
IADC_clearInt(IADC0, IADC_IF_SCANTABLEDONE);
IADC_clearInt(IADC0, IADC_IF_SINGLEDONE);
}
5、按键中断
void sl_button_on_change(const sl_button_t *handle)
{
(void)handle;
IADC_command(IADC0, iadcCmdStartSingle);
}
- |
- +1 赞 0
- 收藏
- 评论 0
本文由SpiderMan提供,版权归世强硬创平台所有,非经授权,任何媒体、网站或个人不得转载,授权转载时须注明“来源:世强硬创平台”。
相关推荐
【经验】EFR32BG22系列蓝牙SOC电池电压与VDD供电电压检测ADC的方法
EFR32BG22作为低功耗蓝牙SOC方案,经常应用于电池供电的方案中,一般采用内部的ADC作为采集通道,内部的输入源作为输入接口,来测试VDD供电电压。本文将讲解电池电压与VDD供电电压检测ADC的方法。
设计经验 发布时间 : 2020-11-28
【经验】蓝牙SoC EFR32BG22的高精度ADC配置步骤与注意事项
Silicon Labs的EFR32BG22系列蓝牙SoC内部集成高精度ADC功能,采用内部1.21V作为Vref,ADC真实有效位数可达13.5bit,使用外部1.25V基准源作为Vref,精度可达14.3bit。本文介绍ADC配置相关步骤以及注意项目。
设计经验 发布时间 : 2020-11-04
【经验】如何解决Silicon Labs EFR32B22在开启一次ADC转换后,功耗变高的问题?
在使用芯科科技EFR32BG22蓝牙SoC开发低功耗应用时,可能会使用到ADC这个外设,但在ADC转换后,会出现芯片在休眠时功耗比较高的情况。本文将介绍如何解决EFR32B22在开启一次ADC转换后,功耗变高的问题?
设计经验 发布时间 : 2023-06-28
解决物联网应用的网络安全性议题
随着物联网应用的普及,物联网设备已经逐渐出现在我们的日常生活之中,但这些产品也成为了恶意份子攻击的目标,如何确保物联网设备的安全性,成为产品开发过程中必须要关注的议题。本文将为您介绍物联网应用所面对的网络攻击问题,以及由Silicon Labs所推出的相关解决方案的功能与特性。
技术探讨 发布时间 : 2024-05-16
高性价比Silicon labs EFM8单片机,STM8完美备选方案
Silicon Labs EFM8BB系列8位单片机采用流水线式CIP-51内核,70%指令的执行时间为1-2个时钟周期,与标准的8051指令集完全兼容,外设资源、性能指标及设计灵活性都具有自身独特的优势。
新产品 发布时间 : 2018-02-08
【技术】EFM8LB单片机之14位高精度ADC模数转换器,900Ksps采样率
Silicon Labs推出的EFM8LB系列8位单片机, 操作频率最高为72MHz, 3mm × 3mm的QFN封装,集成14位ADC模数转换器和4路12位DAC数模转换输出。
技术探讨 发布时间 : 2018-01-23
芯科科技推出包含一整套业界前沿先进安全功能的Secure Vault,解决物联网应用的网络安全
Silicon Labs推出的Secure Vault包含一整套业界前沿的先进安全功能,可解决不断升级的物联网威胁,极大降低物联网生态系统安全漏洞风险,降低因仿冒导致的知识产权或收入损失的影响,将可提升物联网设备的安全性。
应用方案 发布时间 : 2024-01-30
最高精度的ADC采样的单片机,能够达到多少位?
Silicon Labs 8位MCU C8051F350集成的ADC可以达到24位。还有芯海科技的8位MCU CSU8RP1186/CSU18MB86等集成的ADC也可以达到24位、芯海的BLE SOC CST34M96集成的ADC也是24位的。
技术问答 发布时间 : 2019-12-17
C8051F91x-C8051F90x Single/Dual Battery, 0.9–3.6 V, 16–8 kB, SmaRTClock, 12/10-Bit ADC MCU
型号- C8051F902-D-GU,C8051F90X,C8051F901-D-GDI,C8051F911-D-GDI,C8051F91X,C8051F902-D-GM,C8051F902-D-GDI,C8051F912-D-GDI,C8051F912-D-GM,C8051F901-D-GM,C8051F911-D-GU,C8051F912-D-GU,C8051F901-D-GU,C8051F911-D-GM
我使用的是芯片EFR32MG1P232F256GM48,创建的是BLE工程,使能了UART,IIC,SPI,ADC,其他的都是普通IO口, 在进入EM2后,电流在170-300ua跳动,请问下在em2时应该怎么设置使功耗最低,外围硬件除外。看门狗和rtcc默认是没使能的吧,像UART,IIC,SPI,ADC这些在进入em2时要不要设置?
1、Silicon Labs 蓝牙BLE低功耗测试,可以参考:【经验】EFR32BG系列蓝牙SoC之低功耗测试操作指导在这个测试指导里面,使用到的参考工程,都是没有开启这些外设的,可以先测试一下。2、开启外设之后,需要考虑进入EM2模式后,为了实现最低功耗,这些外设需要关闭,尤其是ADC模块需要关闭,同时考虑这些外设所使用的GPIO外围电路,是否有放电的回路,如果有的话,也需要配置GPIO的方向,输入输出,上拉等配置。3、建议单个外设模块单独添加,并测试进入EM2后的功耗情况,以便查找功耗问题。
技术问答 发布时间 : 2020-06-08
需要遥控器钥匙方案,了解到无线单片机产品Si4010是不带ADC功能,是否有带有ADC功能的类似无线芯片?
新款无线MCU Si106x/8x就符合,属于主推无线单片机,既有发射模块,也有AD模块。
技术问答 发布时间 : 2016-10-25
Emerging Bluetooth LE Use Cases and Applications
型号- RS9116W,XG27,XGM210P,XG24,XGM220P,RS9116,XGM240P,XG22,XG21,XGM220S,XGM240S,XGM27
【经验】蓝牙SoC EFR32BG22的差分ADC配置注意事项
Silicon Labs的蓝牙SoC EFR32BG22在使用内部的VREF=1.2V的时候,ADC的实际有效bit为13.5,对除了需要蓝牙功能、还对模拟信号输入有要求的方案具有非常大优势。使用差分输入的方式,可以提高ADC的精度,有效避开干扰。本文主要介绍差分ADC的配置注意事项。
设计经验 发布时间 : 2020-11-18
对于8位单片机EFM8LB10,在使用ADC功能时,如何计算ADC详细的转换时间以及速率?
根据EFM8LB1 Datasheet,ADC转换总所需时间为:Total ConverSion Time=RPT×(ADTK+NUMBITS+1)×T(SARCLK)+(T(ADCCLK)×4);where RPT is the number of converSions represented by the ADRPT field and ADCCLK is the clock selected for the ADC;在高速模式下,以最快的SARCLK为18MHz 计算,跟踪时间至少需230ns( =T(SARCLK)x4),若RPT为累计一个样本,ADCCLK为系统时钟72MHz,那么ADC的转换速率约为:14 Bit Mode:1/[230ns+(14+1)/18MHz+4/72MHz]=0.9Mbps;12 Bit Mode:1/[230ns+(12+1)/18MHz+4/72MHz]=1Mbps;10 Bit Mode:1/[230ns+(10+1)/18MHz+4/72MHz]=1.1Mbps。
技术问答 发布时间 : 2017-05-05
C8051F930-G1DI Tested Single/Dual Battery, 0.9–3.6 V, 64 kB Flash, SmaRTClock, 10-Bit ADC MCU Die in Wafer Form
型号- C8051F930-G-GDI,C8051F930-G1DI,C8051F93X,C8051F930G,C8051F930-G-G1DI,C8051F92X,C8051F930-GDI
电子商城
品牌:SILICON LABS
品类:Wireless Gecko SoC
价格:¥8.1764
现货: 104,128
品牌:SILICON LABS
品类:Wireless Gecko SoC
价格:¥10.4994
现货: 61,779
品牌:SILICON LABS
品类:Wireless Gecko SoC
价格:¥19.2326
现货: 2,500
现货市场
登录 | 立即注册
提交评论