杰发科技AC7801——ADC软件触发的简单使用

前言

7801资料读起来不是很好理解,大概率是之前MTK的大佬写的。在此以简单的方式进行描述。我们做一个简单的规则组软件触发Demo。因为规则组通道只有一个数据寄存器,因此还需要用上DMA方式搬运数据到内存

AC7801的ADC简介

7801的ADC是一种 12 逐次逼近型 模拟数字转换器,拥有 12 路外部通道和 2 路内部通道,支持单次、连续、扫描或间断转换多种模式。模拟监控器特性允许应用程序监测输入电压是否超出设定的电压范围。

特性

12 位分辨率
通道输入电压范围: AVSS < Vin < AVDD
最大转换速率: 1Msps
14 路通道: 12 路外部通道, 1 路内部温度传感器( T-Sensor ), 1 路内部带隙基准(Bandgap ),每路通道可单独配置采样时间
转换序列分为 规则组( regular group )和注入组( injection group
        − 规则组:最多可配置 12 个通道
        − 注入组:最多可配置 4 个通道
8 种操作模式 ( 方便起见,称为 mode x x=1~8)
        − 规则组单通道单次转换 (mode1)
        − 规则组单通道连续转换 (mode2)
        − 规则组扫描 + 注入组扫描模式多通道单次转换 (mode3 注入组扫描模式 )
        − 规则组扫描 + 注入组间隔模式多通道单次转换 (mode3 注入组间隔模式 )
        − 规则组扫描 + 自动触发注入组扫描模式多通道单次转换 (mode4)
        − 规则组扫描 + 注入组扫描模式多通道连续转换 (mode5 注入组扫描模式 )
        − 规则组扫描+注入组间隔模式多通道连续转换(mode5 注入组间隔模式 )
        − 规则组扫描 + 自动触发注入组扫描模式多通道连续转换 (mode6)
        − 规则组子组扫描模式转换 (mode7)
        − 注入组子组扫描模式转换 (mode8)
通过内部软件触发或外部硬件触发启动 ADC
模拟监控器功能:
        − 配置为单个或所有通道电压检查
        − 监控通道电压是否低于低阈值或高于高阈值
中断:
        − 规则或注入组转换结束 (EOC End Of Conversion)
        − 注入组转换结束 (IEOC)
        − 模拟监控器事件 (AMO)
DMA 访问,仅用于规则组通道

典型操作流程

ADC 首先上电,然后可以通过内部 SWSTART 或外部触发源触发 ADC ,该触发来源于其它模块。触发后ADC 转换器单元开始工作,并将选择信号发送至输入通道选择器,根据规则或注入组通道序列逐个选择所需的通道。在一个通道完成转换后,转换结果将根据当前转换通道所属的组存储到 RDR 或 IDRx 中,并且产生相应的 EOC IEOC 标志置位。模拟监控器工作时,如果发生相应的事件则会出现相关的状态标志。

使用DMA

由于规则组通道只有一个数据寄存器,因此建议使用 DMA 功能 ,以避免在有多个规则组通道进行转换时,丢失转换结果。DMA 功能专用于规则组通道。只有规则组通道转换结束标志才会产生 DMA 请求。只有产生了 DMA 请求, DMA 才会将转换数据从ADC_RDR 搬运到用户指定的目标位置。

ADC流程

经典的初始化,DMA初始化。

ADC的初始化,185/186两行注释看的一脸懵逼

ADC的回调

DMA的回调

业务代码

旋转电位器查看打印值

由单个ADC改成多个ADC

AC7801的ADC写的注释相对比较完整,但是没说明软件触发从1个怎么改到多个。

使用时候需要注意下图中红框部分有些DISABLE和ABLE的参数,错了大概率就不可能正常采样。黄框部分就是从1个ADC改成3个需要修改的地方。

读取时候,只需要触发一次ADC0即可

具体代码如下:

#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 %d\r\n", g_ADCValueBuffer[0],g_ADCValueBuffer[1],g_ADCValueBuffer[2]);
        mdelay(100);
    }
}

转换率公式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/187426.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

机器学习-激活函数的直观理解

机器学习-激活函数的直观理解 在机器学习中&#xff0c;激活函数&#xff08;Activation Function&#xff09;是用于引入非线性特性的一种函数&#xff0c;它在神经网络的每个神经元上被应用。 如果不使用任何的激活函数&#xff0c;那么神经元的响应就是wxb&#xff0c;相当…

【数据库】数据库物理执行计划最基本操作-表扫描机制与可选路径,基于代价的评估模型以及模型参数的含义

物理执行计划基本操作符 ​专栏内容&#xff1a; 手写数据库toadb 本专栏主要介绍如何从零开发&#xff0c;开发的步骤&#xff0c;以及开发过程中的涉及的原理&#xff0c;遇到的问题等&#xff0c;让大家能跟上并且可以一起开发&#xff0c;让每个需要的人成为参与者。 本专栏…

十大排序算法中的插入排序和希尔排序

文章目录 &#x1f412;个人主页&#x1f3c5;算法思维框架&#x1f4d6;前言&#xff1a; &#x1f380;插入排序 时间复杂度O(n^2)&#x1f387;1. 算法步骤思想&#x1f387;2.动画实现&#x1f387; 3.代码实现 &#x1f380;希尔排序 时间复杂度O(n*logn~n^2)希尔排序的设…

sql查询优化实际案例

1、第一步&#xff1a;sql优化 正对于海量数据的查询优化&#xff0c;且外键关联比较多的情况&#xff0c;通常情况是下sql层面的优化&#xff0c;有些时候是由于sql不合理的编写导致&#xff0c;如尽量少使用sql内查询等 如&#xff1a;避免使用 left join (select * form …

如何打造垂直LLM的护城河

B2B人工智能初创企业的一个伟大策略是打造“垂直人工智能”产品&#xff1a;成为特定行业的人工智能助手&#xff0c;比如律师、金融服务、医生。 听起来很简单&#xff1a;你可以利用LLM的超能力&#xff0c;并将其应用于宠物行业的特定数据和用例。 这就是我们在Explain所做的…

量子计算的发展

目录 一、量子力学的发展历程二、量子计算的发展历程三、量子计算机的发展历程四、量子信息科学的发展 一、量子力学的发展历程 量子力学是现代物理学的一个基本分支&#xff0c;它的发展始于20世纪初。以下是量子力学发展的几个重要阶段&#xff1a; 普朗克&#xff08;1900&…

基于JavaWeb+SpringBoot+Vue医院管理系统小程序的设计和实现

基于JavaWebSpringBootVue医院管理系统小程序的设计和实现 源码获取入口Lun文目录前言主要技术系统设计功能截图订阅经典源码专栏[Java 源码获取 源码获取入口 Lun文目录 目录 1系统概述 1 1.1 研究背景 1 1.2研究目的 1 1.3系统设计思想 1 2相关技术 2 2.1微信小程序 2 2.2 …

「Java开发中文指南」IntelliJ IDEA插件安装(一)

IntelliJ IDEA是java编程语言开发的集成环境。IntelliJ在业界被公认为最好的Java开发工具&#xff0c;尤其在智能代码助手、代码自动提示、重构、JavaEE支持、各类版本工具(git、svn等)、JUnit、CVS整合、代码分析、 创新的GUI设计等方面的功能是非常强大的。 插件扩展了Intel…

MYSQL基础知识之【创建,删除,选择数据库】

文章目录 前言MySQL 创建数据库使用 mysqladmin 创建数据库使用 PHP脚本 创建数据库 MySQL 删除数据库使用 mysqladmin 删除数据库使用PHP脚本删除数据库 MySQL 选择数据库从命令提示窗口中选择MySQL数据库使用PHP脚本选择MySQL数据库 后言 前言 hello world欢迎来到前端的新世…

网络层(IP协议)

文章目录 网络层IP协议IP协议报头32位源IP地址和目的IP地址:为了解决IP地址不够用的情况 IP地址管理子网掩码特殊IP 路由选择(简介) 网络层 网络层主要负责地址管理和路由选择.代表协议就是IP协议. IP协议 IP协议报头 4位版本: 4: 表示IPv4 ; 6: 表示IPv6 4位首部长度: 描述…

格式化输入输出

跟着肯哥&#xff08;不是我&#xff09;学格式化输入输出 C语言格式化输入 在C语言中&#xff0c;格式化输入&#xff08;Formatted Input&#xff09;是一种从标准输入读取数据并按照指定格式进行解析的操作&#xff0c;它主要通过使用标准库函数scanf()来实现格式化输入。 …

YOLOv8改进 | 2023 | FocusedLinearAttention实现有效涨点

论文地址&#xff1a;官方论文地址 代码地址&#xff1a;官方代码地址 一、本文介绍 本文给大家带来的改进机制是Focused Linear Attention&#xff08;聚焦线性注意力&#xff09;是一种用于视觉Transformer模型的注意力机制(但是其也可以用在我们的YOLO系列当中从而提高检测…

小程序项目:springboot+vue基本微信小程序的学生健康管理系统

项目介绍 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时…

基于协作搜索算法优化概率神经网络PNN的分类预测 - 附代码

基于协作搜索算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于协作搜索算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于协作搜索优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神…

“升级图片质量:批量提高或缩小像素,赋予图片全新生命力!“

如果你想让你的图片更加清晰、更加美观&#xff0c;或者符合特定的像素要求&#xff0c;那么现在有一个好消息要告诉你&#xff01;我们推出了一款全新的图片处理工具&#xff0c;可以帮助你批量提高或缩小图片像素&#xff0c;让你的图片焕发出新的生机&#xff01; 第一步&a…

基于人工蜂鸟算法优化概率神经网络PNN的分类预测 - 附代码

基于人工蜂鸟算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于人工蜂鸟算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于人工蜂鸟优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神…

我的崩溃。。想鼠??!

身为程序员哪一个瞬间让你最奔溃&#xff1f; 某天一个下午崩溃产生。。。 一个让我最奔溃的瞬间是关于一个看似无害的拼写错误。我当时正在为一个电子商务网站添加支付功能&#xff0c;使用了一个第三方支付库。所有的配置看起来都正确&#xff0c;代码也没有报错&#xff0c;…

zookeeper 单机伪集群搭建简单记录

1、官方下载加压后&#xff0c;根目录下新建data和log目录&#xff0c;然后分别拷贝两份&#xff0c;分别放到D盘&#xff0c;E盘&#xff0c;F盘 2、data目录下面新建myid文件&#xff0c;文件内容分别为1&#xff0c;2&#xff0c;3.注意文件没有后缀&#xff0c;不能是txt文…

数据结构—小堆的实现

前言&#xff1a;前面我们已经学习了二叉树&#xff0c;今天我们来学习堆&#xff0c;堆也是一个二叉树&#xff0c;堆有大堆有小堆&#xff0c;大堆父节点大于子节点&#xff0c;小堆父节点总小于子节点&#xff0c;我们在学习C语言的时候也有一个堆的概念&#xff0c;那个堆是…

栈和队列OJ题目——C语言

目录 LeetCode 20、有效的括号 题目描述&#xff1a; 思路解析&#xff1a; 解题代码&#xff1a; 通过代码&#xff1a; LeetCode 225、用队列实现栈 题目描述&#xff1a; 思路解析&#xff1a; 解题代码&#xff1a; 通过代码&#xff1a; LeetCode 232、用栈…