本文介绍: 7801的ADC是一种12位逐次逼近型模拟数字转换器,拥有12路外部通道和2路内部通道,支持单次、连续、扫描或间断转换多种模式。模拟监控器特性允许应用程序监测输入电压是否超出设定的电压范围。
前言
7801资料读起来不是很好理解,大概率是之前MTK的大佬写的。在此以简单的方式进行描述。我们做一个简单的规则组软件触发Demo。因为规则组通道只有一个数据寄存器,因此还需要用上DMA方式搬运数据到内存。
AC7801的ADC简介
7801的ADC是一种
12
位
逐次逼近型
模拟数字转换器,拥有
12
路外部通道和
2
路内部通道,支持单次、连续、扫描或间断转换多种模式。模拟监控器特性允许应用程序监测输入电压是否超出设定的电压范围。
12
位
逐次逼近型
模拟数字转换器,拥有
12
路外部通道和
2
路内部通道,支持单次、连续、扫描或间断转换多种模式。模拟监控器特性允许应用程序监测输入电压是否超出设定的电压范围。
特性
− 注入组转换结束
(IEOC)
(IEOC)
典型操作流程
ADC 首先上电,然后可以通过内部
SWSTART
或外部触发源触发
ADC
,该触发来源于其它模块。触发后ADC
转换器单元开始工作,并将选择信号发送至输入通道选择器,根据规则或注入组通道序列逐个选择所需的通道。在一个通道完成转换后,转换结果将根据当前转换通道所属的组存储到 RDR
或 IDRx 中,并且产生相应的
EOC
或
IEOC
标志置位。模拟监控器工作时,如果发生相应的事件则会出现相关的状态标志。
SWSTART
或外部触发源触发
ADC
,该触发来源于其它模块。触发后ADC
转换器单元开始工作,并将选择信号发送至输入通道选择器,根据规则或注入组通道序列逐个选择所需的通道。在一个通道完成转换后,转换结果将根据当前转换通道所属的组存储到 RDR
或 IDRx 中,并且产生相应的
EOC
或
IEOC
标志置位。模拟监控器工作时,如果发生相应的事件则会出现相关的状态标志。
使用DMA
由于规则组通道只有一个数据寄存器,因此建议使用 DMA 功能
,以避免在有多个规则组通道进行转换时,丢失转换结果。DMA
功能专用于规则组通道。只有规则组通道转换结束标志才会产生 DMA
请求。只有产生了
DMA
请求,
DMA
才会将转换数据从ADC_RDR 搬运到用户指定的目标位置。
,以避免在有多个规则组通道进行转换时,丢失转换结果。DMA
功能专用于规则组通道。只有规则组通道转换结束标志才会产生 DMA
请求。只有产生了
DMA
请求,
DMA
才会将转换数据从ADC_RDR 搬运到用户指定的目标位置。
ADC流程
ADC的回调
DMA的回调
由单个ADC改成多个ADC
AC7801的ADC写的注释相对比较完整,但是没说明软件触发从1个怎么改到多个。
使用时候需要注意下图中红框部分有些DISABLE和ABLE的参数,错了大概率就不可能正常采样。黄框部分就是从1个ADC改成3个需要修改的地方。
具体代码如下:
#include "adc_sample.h"
#define Delay5us (APB_BUS_FREQ/200000-1)
#define Delay5ms (APB_BUS_FREQ/200-1)
#define Delay1s (APB_BUS_FREQ-1)
uint8_t g_dmaFinish = 0; // DMA传输完成
uint8_t g_halfDmaFinish = 0; // DMA传输半完成
uint8_t g_dmaTransError = 0; // DMA传输错误
uint32_t g_ADCValueBuffer[DMA_TRANSFER_NUM + 1] = {0};
uint32_t g_timerCnt = 0;
uint16_t g_regularAverageSampleValue = 0; // 规则组采样平均值
uint16_t g_injectAverageSampleValue = 0; // 注入组采样平均值
uint16_t g_adcInjectValue[4];
uint8_t g_AMOFlag = 0; // 模拟看门狗事件标志
/*
注意:EOC标志写0或读取ADC_RDR都会清除该标志位。
在进行debug时,如果有打开memory窗口或打开ADC寄存器。
该标志会被debug清除。
*/
uint8_t g_EOCFlag = 0; // 规则组转换结束标志。
uint8_t g_IEOCFlag = 0; // 注入组转换结束标志。
void ADC_Callback(void *device, uint32_t wpara, uint32_t lpara)
{
if (wpara & ADC_STR_EOC_Msk) // 规则组中断标志
{
g_EOCFlag = 1;
}
if (wpara & ADC_STR_AMO_Msk) // 模拟监控中断标志
{
g_AMOFlag = 1;
}
}
void ADC_DMACallback(void *device, uint32_t wpara, uint32_t lpara)
{
/*
wparam为DMA通道状态,状态含义可参考CHANNELx_STATUS寄存器,
CHANNELx_STATUS[2] 传输错误
CHANNELx_STATUS[1] 半传输完成(相对设置的transferNum,如果半传输中断有使能,transferNum设为6,则DATA_TRANS_NUM为3时产生中断,进入回调)
CHANNELx_STATUS[0] 传输完成
*/
if ((wpara & 0x01) == 0x1)
{
g_dmaFinish = 1;
}
if ((wpara & 0x02) == 0x2)
{
g_halfDmaFinish = 1;
}
if ((wpara & 0x04) == 0x4)
{
g_dmaTransError = 1;
}
}
void ADC_DMAInit(void)
{
uint32_t tmpMemStartAddr = (uint32_t)&g_ADCValueBuffer[0];
uint32_t tmpMemEndAddr = (uint32_t)&g_ADCValueBuffer[DMA_TRANSFER_NUM + 1]; ///< Setting memory DMA address
DMA_ConfigType tmpDMAConfig;
memset(&tmpDMAConfig, 0x00, sizeof(DMA_ConfigType));
tmpDMAConfig.memStartAddr = tmpMemStartAddr; // 设置DMA开始地址
tmpDMAConfig.memEndAddr = tmpMemEndAddr; // 设置DMA结束地址
tmpDMAConfig.periphStartAddr = (uint32_t)(&(ADC0->RDR)); ///< Move ADC DR to memory
tmpDMAConfig.channelEn = ENABLE; ///< 使能DMAx通道
tmpDMAConfig.finishInterruptEn = ENABLE; ///< 使能DMA传输完成中断
tmpDMAConfig.halfFinishInterruptEn = DISABLE; ///< 去能DMA半传输完成中断
tmpDMAConfig.errorInterruptEn = ENABLE; ///< 使能DMA传输错误中断
tmpDMAConfig.channelPriority = DMA_PRIORITY_VERY_HIGH; ///< 设置DMA通道优先级,0~3 :优先级由低到高
tmpDMAConfig.circular = ENABLE; ///< 使能循环模式,如果只想工作一次,设为0即可。
tmpDMAConfig.direction = DMA_READ_FROM_PERIPH; ///< 0: 从外设读取,1:从存储器读取
tmpDMAConfig.MEM2MEM = DISABLE; ///< 0:在非存储器与存储器之间传输,1:在存储器与存储器之间传输
tmpDMAConfig.memByteMode = DMA_MEM_BYTE_MODE_1TIME; ///< MEM字分割传输数,0:32-bit,1:16-bit[15:0]; 2:16-bit[23:16][7:0];3:8-bit。详情可参考AC781X芯片手册 表20-2 可编程数据宽度&数据对齐
tmpDMAConfig.memIncrement = ENABLE; ///< 1:MEM地址增加
tmpDMAConfig.periphIncrement = DISABLE; ///< 0:外设地址固定
tmpDMAConfig.memSize = DMA_MEM_SIZE_32BIT; ///< 0:8-bit,1:16-bit,2:32-bit
tmpDMAConfig.periphSize = DMA_PERIPH_SIZE_16BIT; ///< 0:8-bit,1:16-bit,2:32-bit
tmpDMAConfig.transferNum = DMA_TRANSFER_NUM; ///< DMA通道传输长度
tmpDMAConfig.periphSelect = DMA_PEPIRH_ADC0; // 外设选择
tmpDMAConfig.callBack = ADC_DMACallback; ///< 设置DMA中断回调
DMA_Init(DMA0_CHANNEL0, &tmpDMAConfig); ///< ADC 使用DMA1通道,每个模块对应的DMA通道,可参考 AC781X芯片手册 表20-1 DMA请求列表
NVIC_EnableIRQ(DMA0_CHANNEL0_IRQn); ///< 使能DMA1中断请求
}
void ADC_init()
{
ADC_ConfigType tempAdcConfig;
ADC_ConfigType *adcConfig;
adcConfig = &tempAdcConfig;
// 配置PINMUX
GPIO_SetFunc(GPIOA, GPIO_PIN4, GPIO_FUN2); ///< ADC_IN6 Analog function enable
GPIO_SetFunc(GPIOA, GPIO_PIN3, GPIO_FUN2); ///< ADC_IN7 Analog function enable
GPIO_SetFunc(GPIOA, GPIO_PIN2, GPIO_FUN2); ///< ADC_IN8 Analog function enable
adcConfig->clkPsc = ADC_CLK_PRESCALER_1; ///< Set ADC Clk = 24M/2/(0+1)
adcConfig->scanModeEn = ENABLE; // 扫描模式
adcConfig->continousModeEn = DISABLE; // 连续模式
adcConfig->regularDiscontinousModeEn = DISABLE; // 1:打开规则组间断转换模式
adcConfig->injectDiscontinousModeEn = DISABLE; // 1:打开注入组间断转换模式
adcConfig->injectAutoModeEn = DISABLE; // 1:自动注入模式
adcConfig->intervalModeEn = DISABLE; // 1:注入组为间隔转换模式
adcConfig->regularDiscontinousNum = 0; //
adcConfig->EOCInterruptEn = ENABLE; // EOC中断使能
adcConfig->IEOCInterruptEn = ENABLE; // IEOC中断使能
adcConfig->interruptEn = ENABLE; // 中断使能
adcConfig->regularDMAEn = ENABLE; // 使能ADC DMA
adcConfig->regularTriggerMode = ADC_TRIGGER_INTERNAL; // ADC触发源,内部触发
adcConfig->regularSequenceLength = 3; // 规则组长度设为3
adcConfig->dataAlign = ADC_DATA_ALIGN_RIGHT; // 右对齐
adcConfig->callBack = ADC_Callback; // 回调
adcConfig->powerMode = ADC_POWER_ON; // 上电
ADC_Init(ADC0, adcConfig); ///< ADC works Mode Config
// ADC转换率计算公式: 转换时间= 采样时间+转换时间+同步时间 转换时间= (SPT+12)/ADC模块时钟频率+5/APB时钟频率
// 备注:1.同步时间为5个APB CLK。2.ADC时钟频率 = APB时钟频率 /(分频系数+1)
// 规则组通道设置
ADC_SetRegularGroupChannel(ADC0, ADC_CH_7, ADC_SPT_CLK_7, 0); // 采样&转换时间= (7+12)/24000000 + 5/24000000 = 1us
ADC_SetRegularGroupChannel(ADC0, ADC_CH_8, ADC_SPT_CLK_7, 1); // 采样&转换时间= (7+12)/24000000 + 5/24000000 = 1us
ADC_SetRegularGroupChannel(ADC0, ADC_CH_6, ADC_SPT_CLK_7, 2); // 采样&转换时间= (7+12)/24000000 + 5/24000000 = 1us
}
void ADC_SampleSoftwareTrigerADC(void)
{
ADC_init();
ADC_DMAInit(); // ADC DMA初始化
while (1)
{
// 每次转换数据清零
memset(g_ADCValueBuffer, 0x00, sizeof(g_ADCValueBuffer));
ADC_SoftwareStartRegularConvert(ADC0); /// 软件触发规则组采样
udelay(8); // 需要采样8个通道,延时8us以保证数据采样完成
printf("%d %d %drn", g_ADCValueBuffer[0],g_ADCValueBuffer[1],g_ADCValueBuffer[2]);
mdelay(100);
}
}
转换率公式
原文地址:https://blog.csdn.net/qq_35697978/article/details/134418766
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_10913.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。