[BLE]CC2640之ADC功能实现和供电电压的採集
一、开篇
Write programs that do one thing and do it well ~~~~~
发现非常多人关于使用CC2640/CC2650的过程中比較难以应对的问题就是实现ADC。为了方便大家,所以有了本篇博客,都是一些自己的理解。不正确的地方请大家指正。
TI的这款新品上市不久,还有须要须要更新的地方,尤其是以往以其文档多为优势。而现在到了CC26xx这却差点儿没什么可參考的文档了,大家就等等吧。肯定会越来越完好的。
本篇主要介绍怎样使用TI官方给的driverlib实现ADC的使用,SCS也能控制ADC的实现,可是这个过于复杂。生产的代码也比較难以理解,所以还是使用driverlib吧。
三、试验平台
Software Version:BLE_STACK_CC26XX_2.1.0
Hardware Version:CC2640/CC2650
IDE:IAR 7.40
四、基础知识
1) ADC模数转换器,顾名思义也就是输入模拟量输出数字量。我们感知世界上的不论什么事物都是感知的模拟量,可是相应于CPU而言仅仅能识别非0即1的数字量,所以产生了ADC,ADC的实现过程中基本的两个过程就是採用保持和量化(感觉在讲废话)。在外设接口中ADC属于较难得部分了,关于ADC的一些基本概念还是比較多的,当中INL和DNL须要特别注意一下(Ps:我旁边坐了一位专门研究ADC的beauty,是她讲的。平时实验室关于ADC不懂得都找她解决)。由于本篇博文主要是解说关于CC26xx的ADC实现的,它的ADC是内部集成的12位ADC,採样速率高达200Ks/s,所以本篇博文不再具体介绍在ADC芯片选型方面要考虑的參数了,可是本篇涉及的參数肯定是选型时须要考虑的。
2)以下结合CC26xx的Datasheet介绍一些关于ADC的基本參数,下图是ADC在整个IC内部的位置。由下图可知CC26xx的ADC在RF core内部。由M0核控制,在实现ADC时能够使用官方的driverlib也能够使用官方特有的SCS平台去控制实现ADC的基本功能。CC26xx的Sensor
controller的功能还是相当强大的,可惜我还不会使用。在低功耗中使用UART就是靠的它用流控控制的。
3)例如以下图中所看到的。因为INL和DNL(详细含义去百度吧)以及offset的原因,在採集数据时就会存在一个偏差。这个是不可避免的,这个採集数据的偏差还是自行软件处理吧,内部ADC的功耗还是比較低的。
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" align="middle" alt="">
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" align="middle" alt="">
五、怎样在project中实现ADC
1、首先你要知道有一个driverlib库的存在。这个里面TI官方给出了使用时调用的API,此处就不在赘述了。路径太长不方便写。
2、然后CC26xx芯片不是全部的IO口都能够作为的ADC接口使用的。官方在TRM中也给出了介绍。例如以下图。
3、include库文件
在simpleBLEPeripheral.c文件里加入例如以下头文件。
#include <driverlib/aux_adc.h>
#include <driverlib/aux_wuc.h>
4、配置ADC(最关键的一步)
代码实现部分,放在simpleBLEPeripheral.c就可以。ADC不须要像使用UART那样再去配置IO口映射。
//*****************************************************************************
//! \brief Selects internal or external input for the ADC
//! Note that calling this function also selects the same input for AUX_COMPB.
//! \param input
//! Internal/external input selection:
//! - \ref ADC_COMPB_IN_VDD1P2V
//! - \ref ADC_COMPB_IN_VSSA
//! - \ref ADC_COMPB_IN_VDDA3P3V
//! - \ref ADC_COMPB_IN_AUXIO7 //DIO9
//! - \ref ADC_COMPB_IN_AUXIO6 //DIO8
//! - \ref ADC_COMPB_IN_AUXIO5 //DIO7
//! - \ref ADC_COMPB_IN_AUXIO4 //DIO6
//! - \ref ADC_COMPB_IN_AUXIO3 //DIO5
//! - \ref ADC_COMPB_IN_AUXIO2
//! - \ref ADC_COMPB_IN_AUXIO1
//! - \ref ADC_COMPB_IN_AUXIO0
//*****************************************************************************
uint32_t AdcOneShotRead(uint8_t auxIo)
{
uint32_t turnedOnClocks = 0;
//////////// Config clock/////////////////////
// Only turn on clocks that are not already enabled. Not thread-safe, obviously.
turnedOnClocks |= AUXWUCClockStatus(AUX_WUC_ADC_CLOCK) ? 0 : AUX_WUC_ADC_CLOCK;
turnedOnClocks |= AUXWUCClockStatus(AUX_WUC_ADI_CLOCK) ? 0 : AUX_WUC_ADI_CLOCK;
turnedOnClocks |= AUXWUCClockStatus(AUX_WUC_SOC_CLOCK) ? 0 : AUX_WUC_SOC_CLOCK;
// Enable clocks and wait for ready
AUXWUCClockEnable(turnedOnClocks);
while(AUX_WUC_CLOCK_OFF == AUXWUCClockStatus(turnedOnClocks));
/////// Seclect auxIO /////////////
AUXADCSelectInput(auxIo);
////////// Enable ///////////
AUXADCEnableSync(AUXADC_REF_FIXED, AUXADC_SAMPLE_TIME_2P7_US, AUXADC_TRIGGER_MANUAL);
delay(10);
//Scaling disable
AUXADCDisableInputScaling();
AUXADCGenManualTrigger(); // Trigger sample
uint32_t adcValue = AUXADCReadFifo();
AUXADCDisable();//Power_Saving
return adcValue;
}
在上述实现代码中所涉及的一些问题,讲述一下自己的理解,假设不过为了实现ADC功能那么以下能够不用看了,以下讲的比較细了。
1)首先是ADC使能函数
跟踪查看函数原型例如以下。
//*****************************************************************************
// Enables the ADC for synchronous operation
//*****************************************************************************
void AUXADCEnableSync(uint32_t refSource, uint32_t sampleTime, uint32_t trigger)
{
// Enable the ADC reference, with the following options:
// - SRC: Set when using relative reference
// - REF_ON_IDLE: Set when using fixed reference and sample time < 21.3 us
uint8_t adcref0 = refSource | ADI_4_AUX_ADCREF0_EN_M;
if (!refSource && (sampleTime < AUXADC_SAMPLE_TIME_21P3_US)) {
adcref0 |= ADI_4_AUX_ADCREF0_REF_ON_IDLE_M;
}
ADI8BitsSet(AUX_ADI4_BASE, ADI_4_AUX_O_ADCREF0, adcref0); // Enable the ADC clock
HWREG(AUX_WUC_BASE + AUX_WUC_O_ADCCLKCTL) = AUX_WUC_ADCCLKCTL_REQ_M;
while (!(HWREG(AUX_WUC_BASE + AUX_WUC_O_ADCCLKCTL) & AUX_WUC_ADCCLKCTL_ACK_M)); // Enable the ADC data interface
if (trigger == AUXADC_TRIGGER_MANUAL) {
// Manual trigger: No need to configure event routing from GPT
HWREG(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCCTL) = AUX_ANAIF_ADCCTL_START_SRC_NO_EVENT0 | AUX_ANAIF_ADCCTL_CMD_EN;
} else {
// GPT trigger: Configure event routing via MCU_EV to the AUX domain
HWREG(EVENT_BASE + EVENT_O_AUXSEL0) = trigger;
HWREG(AUX_ANAIF_BASE + AUX_ANAIF_O_ADCCTL) = AUX_ANAIF_ADCCTL_START_SRC_MCU_EV | AUX_ANAIF_ADCCTL_CMD_EN;
}
// Release reset and enable the ADC
ADI8BitsSet(AUX_ADI4_BASE, ADI_4_AUX_O_ADC0, ADI_4_AUX_ADC0_EN_M | ADI_4_AUX_ADC0_RESET_N_M |
(sampleTime << ADI_4_AUX_ADC0_SMPL_CYCLE_EXP_S));
}
用法:AUXADCEnableSync(AUXADC_REF_FIXED, AUXADC_SAMPLE_TIME_2P7_US, AUXADC_TRIGGER_MANUAL)。比較重要的就是第一和第二个參数。
当中第一个參数AUXADC_REF_FIXED是4.3V,关于这个4.3的由来,TI一直没有给相关的介绍。我认为应该是由电源端引入然后经过内部的boost电路升压到4.3V作为这个參考电压的。当中还有几个能够作为參考电压的,我没有试过。仅仅是用了AUXADC_REF_FIXED这一个,不敢妄下结论,大家能够去实測一下。第二个參数就是所谓的採样时间,其倒数就是採样频率,由于这套代码配置是使用的同步採样(Sync)。所以採样频率的配置就不能像用单独的用timer去尾随实现非同步採样(Async)产生的採样频率多了。仅仅有官方给的几个能够用,感觉这个影响不大。接近即可了,例如以下。
*****************************************************************************
// Defines for ADC sampling type for synchronous operation.
*****************************************************************************
#define AUXADC_SAMPLE_TIME_2P7_US 3
#define AUXADC_SAMPLE_TIME_5P3_US 4
#define AUXADC_SAMPLE_TIME_10P6_US 5
#define AUXADC_SAMPLE_TIME_21P3_US 6
#define AUXADC_SAMPLE_TIME_42P6_US 7
#define AUXADC_SAMPLE_TIME_85P3_US 8
#define AUXADC_SAMPLE_TIME_170_US 9
#define AUXADC_SAMPLE_TIME_341_US 10
#define AUXADC_SAMPLE_TIME_682_US 11
#define AUXADC_SAMPLE_TIME_1P37_MS 12
#define AUXADC_SAMPLE_TIME_2P73_MS 13
#define AUXADC_SAMPLE_TIME_5P46_MS 14
#define AUXADC_SAMPLE_TIME_10P9_MS 15
假设使用使用非同步採样(Async)的话。CC26xx就不能进入standby状态了,官方解释例如以下图(应该没有理解错吧)。
2)Scaling disable
作用就是缩小ADC的IO口的採样电压的范围。disable以后最大输入电压1.49就达到满量程了(实測),所以这样能够提升单位电压内的分辨率(1.49/4096)。
函数原型:
//*****************************************************************************
// Disables scaling of the ADC input
//*****************************************************************************
// Register: ADI_4_AUX_O_ADC1
// Field: [0] SCALE_DIS
// Disable capacitive input voltage scaling. Should only be 1 for test
// purposes.
// 0: ADC input is scaled from 0-4.3V to 0-1.4V internally
// 1: ADC input is not scaled. Do not exceed 1.4V on input
#define ADI_4_AUX_ADC1_SCALE_DIS 0x00000001
#define ADI_4_AUX_ADC1_SCALE_DIS_BITN 0
#define ADI_4_AUX_ADC1_SCALE_DIS_M 0x00000001
#define ADI_4_AUX_ADC1_SCALE_DIS_S 0 */
//*****************************************************************************
void
AUXADCDisableInputScaling(void)
{
ADI8BitsSet(AUX_ADI4_BASE, ADI_4_AUX_O_ADC1, ADI_4_AUX_ADC1_SCALE_DIS_M);
}
六、关于精度和測试结果
TI的 R&D给出了一份他们在实验的測试结果,大家能够依照这个作为比較,实測和这份数据差点儿相同。
七、附加题(你肯定懂得它的含义)
什么?不知道“附加题”的意义何在?
那你肯定没经历过高考的洗礼~~~~
原本想再单独写一篇博文介绍关于供电电压採集的。可是感觉比較简单就和ADC放在一起讲吧,它俩比較接近。首先,非常多project师在做类似于手环、心率计、HCG等等时可能都须要使用到芯片的ADC功能。又想实时的获取供电电压。可是内部ADC的数量又是有限的。怎样实现多路使用ADC呢,大家首先想到的应该就是切换使用内部ADC,可是在一路正在使用的时候直接切换掉是不是对正在ADC採集的数据导致错误呢。或者说这个切换的时间怎样把握呢。所以CC26xx有了这个Battery
Monitor的功能。让project师測量供电电压时不再占用外部adc_io接口。
关于IO口重映射是怎样实现的,我也不了解(who knows? tell me.),反正认为比較牛掰,用起来很顺手,尤其是在layout布局布线的时候。个人臆測可能是使用电子开关之类的方法切换的吧,电子开关的功耗也很小,搞硬件的就是牛掰。
为什么这些高科技都是国外的。那么有哪些是“黑科技”掌握在国人手里呢?例如以下就是。国人之骄傲~~~
好吧,废话不多说。
关于供电电压的測试问题,这个能够不使用ADC測试了,CC26xx内部有专门測试芯片供电电压的(还有測试芯片温度的,不再赘述測试温度)。
1、代码实现
在simpleBLEPeripheral.c文件里加入例如以下头文件。
#include <driverlib/aon_batmon.h>
在须要的地方使用例如以下代码获取当前的电池电压。
//BAT Monitor
AONBatMonEnable();
// <int.frac> format size <3.8> in units of volt
//返回值32位中[10:8]代表INT 。 [7:0]代表FRAC ,对于小数部分,一个单位代表0.00390625v,小数部分的分辨率仅仅有50mV(TYP)
batval = AONBatMonBatteryVoltageGet();
AONBatMonBatteryVoltageGet()的函数原型是:
__STATIC_INLINE uint32_t
AONBatMonBatteryVoltageGet(void)
{
uint32_t ui32CurrentBattery;
ui32CurrentBattery = HWREG(AON_BATMON_BASE + AON_BATMON_O_BAT);
// Return the current battery voltage measurement.
return (ui32CurrentBattery >> AON_BATMON_BAT_FRAC_S);
}
返回值是依据不同的位代表芯片供电电压的整数部分和小数部分的,具体介绍例如以下。
//*****************************************************************************
// Register: AON_BATMON_O_BAT
//*****************************************************************************
// Field: [10:8] INT
// Integer part:
// 0x0: 0V + fractional part
// ...
// 0x3: 3V + fractional part
// 0x4: 4V + fractional part
#define AON_BATMON_BAT_INT_M 0x00000700
#define AON_BATMON_BAT_INT_S 8
// Field: [7:0] FRAC
// Fractional part, standard binary fractional encoding.
// 0x00: .0V
// ...
// 0x20: 1/8 = .125V
// 0x40: 1/4 = .25V
// 0x80: 1/2 = .5V
// ...
// 0xA0: 1/2 + 1/8 = .625V
// ...
// 0xFF: Max
#define AON_BATMON_BAT_FRAC_M 0x000000FF
#define AON_BATMON_BAT_FRAC_S 0
測试结果:仅仅測试了0.1V的电压变化值。能够精确获取到。
八、结论
实在不知道写什么了,还是打个广告吧。
学挖掘机技术哪家强?
[BLE]CC2640之ADC功能实现和供电电压的採集的更多相关文章
- mtools 是由MongoDB 官方工程师实现的一套工具集,可以很快速的日志查询分析、统计功能,此外还支持本地集群部署管理.
mtools 是由MongoDB 官方工程师实现的一套工具集,可以很快速的日志查询分析.统计功能,此外还支持本地集群部署管理 https://www.cnblogs.com/littleatp/p/9 ...
- BLE各版本新功能总结
文章转载自:http://www.sunyouqun.com/2017/04/ 协议发布时间 协议版本 2016/12 Bluetooth 5 2014/12 Bluetooth 4.2 2013/1 ...
- row_number() over()分组排序功能 partition by 用于给结果集分组
select * from ( select row_number() over(partition by Gid order by Gid ASC) as RowN, * from( select ...
- CesiumLab V1.1 新功能 (免费Cesium处理工具集)
Cesiumlab 自从上周(3月20日)发布之后,赢得小伙伴一致好评. 本周继续推出重大更新: 建筑物矢量数据 转 3dtiles, 建筑物矢量数据 转 3dtiles, 建筑物矢量数据 转 3 ...
- 开源 java CMS - FreeCMS2.3 Web页面信息採集
原文地址:http://javaz.cn/site/javaz/site_study/info/2015/23312.html 项目地址:http://www.freeteam.cn/ Web页面信息 ...
- 开源 java CMS - FreeCMS2.1公布
项目地址:http://www.freeteam.cn/ FreeCMS商业版V2.1更新功能 1.web页面信息採集:通过简单配置就可以抓取目标网页信息,支持增量式採集.keyword替换.定时採集 ...
- C++开发人脸性别识别教程(19)——界面美化
在这篇博文中将完毕<C++开发人脸性别识别>的收尾工作.主要内容分为两部分:加入视频暂定功能.界面规范化. 一 视频暂停功能 严格来说这个视频暂定功能算是视频人脸性别识别的一个遗留问题,本 ...
- 日志系统之基于Zookeeper的分布式协同设计
近期这段时间在设计和实现日志系统.在整个日志系统系统中Zookeeper的作用非常重要--它用于协调各个分布式组件并提供必要的配置信息和元数据.这篇文章主要分享一下Zookeeper的使用场景. 这里 ...
- ADC自动转接功能Lua实现
一.背景介绍: 虽然使用Mod_fifo和mod_callcenter可以做呼叫中心的应用,但在实现应用中,这两个模块很难客制化需求,再此我用Lua实现了5路客服(1000-1004),一个呼叫中心号 ...
随机推荐
- strcpy与strcat函数原型
1.strcpy函数原型 char *my_strcpy(char *dest,const char *src) //const使在函数中不能修改*src其原先的值{ char *strDest ...
- Hive 导入数据报错,驱动版本过低
Failed with exception Unable to alter table. javax.jdo.JDODataStoreException: You have an error in y ...
- Appium解锁九宫格(TouchAction)
TouchAction 1.源码可以在这个路径找到:Lib\site-packages\appium\webdriver\common\touch_action.py class TouchActio ...
- python第三方库之openpyxl(1)
python第三方库之openpyxl(1) 简介 Openpyxl是一个用于读写Excel 2010 xlsx/xlsm/xltx/xltm文件的Python库,其功能非常强大.Excel表格可以理 ...
- lnmp环境的使用
lnmp环境的使用 安装的软件都安装到了:/usr/local 管理nginx service nginx start|stop|restart|reload 管理mysql 直接执行mysql即可登 ...
- 总结搭建Oracle11g DG踩的坑
此次的操作环境是Oracle11g 单实例,os为Linux,采用duplicate在线创建物理备库 primary上设置相关参数 ALTER SYSTEM SET LOG_ARCHIVE_CONFI ...
- HDU——2955Robberies(小数背包)
Robberies Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total ...
- 刷题总结——魔法森林(bzoj3669)
题目: Description 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号为1..N,边标号为1..M.初始时小E同 ...
- bzoj3743 [Coci2015]Kamp 常州模拟赛d6t2
3743: [Coci2015]Kamp Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 484 Solved: 229[Submit][Status ...
- 常州模拟赛d5t2 mogician
分析:一个暴力的思想是枚举g,然后枚举每个数ai,看能不能符合要求,这样复杂度是O(nA)的,直接T掉了.也没什么其他的办法了,在暴力的基础上优化一下,优化的关键是要如何快速统计出不满足要求的数的个数 ...