你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32H7的FMC总线应用之驱动AD7606(8通道同步采样, 16bit, 正负10V)

[复制链接]
STMCU小助手 发布时间:2021-11-4 00:51
76.1 初学者重要提示
  学习本章节前,务必优先学习第47章,了解FMC总线的基础知识。
  AD7606 的配置很简单,它没有内部寄存器,量程范围和过采样参数是通过外部IO控制的,采样速率由MCU或DSP提供的脉冲频率控制。
  AD7606必须使用单5V供电。而AD7606和MCU之间的通信接口电平由VIO(VDRIVE)引脚控制。也就是说VIO必须接单片机的电源,可以是3.3V也可以是5V(范围2.3V – 5V)。
  正确的理解过采样,比如我们设置是1Ksps采样率,64倍过采样。意思是指每次采样,AD7606会采样64次数据并求平均,相当于AD7606以64Ksps进行采样的,只是将每64个采样点的值做了平均,用户得到的值就是平均后的数值。因此,如果使用AD7606最高的200Ksps采样率,就不可以使用过采样了。
  STM32H7驱动AD7606配合J-Scope实时输出,效果绝了,堪比示波器。使用方法详解本章节77.8小节。
  本章配套例子的串口数据展示推荐使用SecureCRT,因为数据展示做了特别处理,方便采集数据在串口软件同一个位置不断刷新。
  AD7606数据手册,模块原理图(通用版)和接线图都已经放到本章教程配置例子的Doc文件里。
  测试本章配套例子前重要提示:
  测试时,务必使用外置电源为开发板供电,因为AD7606需要5V供电电压。板子上插入AD7606模块时,注意对齐。
  板子上电后,默认是软件定时采集,0.5秒一次,适合串口展示数据。
  如果需要使用J-Scope实时展示采集的波形效果,需要按下K2按键切换到FIFO模式。
  如果使用的JLINK速度不够快,导致J-Scope无法最高速度实时上传,可以使用摇杆上下键设置过采样来降低上传速度。
  默认情况下,程序仅上传了AD7606通道1采集的数据。
76.2 ADC结构分类
这里将六种DAC结构为大家做个普及。注,这些知识翻译自美信和TI的英文技术手册。

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


76.2.1 SAR ADC(逐次逼近型)
逐次逼近型ADC通常是中高分辨率的首选架构,采样速率通常低于5Msps。SAR ADC最常见的分辨率范围是8位到20位,并具有低功耗和小尺寸的特点。这种组合使其非常适合各种应用,例如自动测试设备,电池供电的设备,数据采集系统,医疗仪器,电机和过程控制,工业自动化,电信,测试和测量,便携式系统,高速闭环系统和窄带接收器。

76.2.2 Sigma-Delta ADC
Sigma-delta ADC主要用于低速应用中,该应用需要通过过采样来权衡速度和分辨率,然后进行滤波以降低噪声。24位sigma-delta转换器用于自动化测试设备,高精度便携式传感器,医疗和科学仪器以及地震数据采集等应用中。

76.2.3 Integrating ADC
集成ADC提供高分辨率,并且可以提供良好的线路频率和噪声抑制。集成架构提供了一种新颖且直接的方法,可将低带宽模拟信号转换为数字表示形式。这些类型的转换器通常包括用于LCD或LED显示器的内置驱动器,并且在许多便携式仪器应用中都可以找到,包括数字面板表和数字万用表。

76.2.4 FLASH ADC
Flash ADC是将模拟信号转换为数字信号的最快方法。它们适用于需要非常大带宽的应用。然而,闪存转换器功率高,具有相对较低的分辨率,并且可能非常昂贵。这将它们限制在通常无法以其他任何方式解决的高频应用中。示例包括数据采集,卫星通信,雷达处理,示波器和高密度磁盘驱动器。

76.2.5 Pipelined ADC
流水线ADC已成为最受欢迎的ADC体系结构,其采样率从每秒几兆采样(MS / s)到最高100MS / s +,分辨率为8至16位。它们提供的分辨率和采样率,可覆盖各种应用,包括CCD成像,超声医学成像,数字接收器,基站,数字视频(例如HDTV),xDSL,电缆调制解调器和快速以太网。

76.2.6 Two Step ADC
两步ADC也称为子范围转换器,有时也称为多步或half flash(比Flash架构慢)。这是Flash ADC和流水线ADC的交叉点。与Flash ADC相比,可以实现更高的分辨率或更小的裸片尺寸。

76.3 AD7606硬件设计
这里将开发板上的AD7606硬件接口,普通型AD7606模块,屏蔽型AD7606模块和磁耦高速隔离型AD7606模块为大家做个说明。

76.3.1 AD7606硬件接口
V7板子上AD7606模块的插座的原理图如下:

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


实际对应开发板的位置如下:

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


为了方便大家更好的理解接线,下面是框图:

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


模块引脚说明:

  OS2 OS1 OS2 :
组合状态选择过采样模式。

  000表示无过采样,最大200Ksps采样速率。
  001表示2倍过采样, 也就是硬件内部采集2个样本求平均。
  010表示4倍过采样, 也就是硬件内部采集4个样本求平均。
  011表示8倍过采样, 也就是硬件内部采集8个样本求平均。
  100表示16倍过采样, 也就是硬件内部采集16个样本求平均。
  101表示32倍过采样, 也就是硬件内部采集32个样本求平均。
  110表示64倍过采样, 也就是硬件内部采集64个样本求平均。
过采样倍率越高,ADC转换时间越长,可得到的最大采样频率就越低。

  CVA,CVB :
启动AD转换的控制信号。CVA决定1-4通道,CVB决定5-8通道。2个信号可以错开短暂的时间。一般情况可以将CVA,CVB并联在一起。

  RAGE :
量程范围选择。0表示正负5V, 1表示正负10V。

RD :
读信号。

  RST :
复位信号。

  BUSY :
忙信号。

  CS :
片选信号。

  FRST :
第1个通道样本的指示信号。【注,此引脚可以省略不使用】

  VIO :
通信接口电平。

  DB0-DB15 :
数据总线。
如果采用SPI接口方式,接线框图如下:

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


76.3.2 AD7606模块(通用版)
产品规格:

1、 16bit分辨率,内置基准,单5V供电。

2、 8路模拟输入,阻抗1M欧姆。【无需负电源,无需前端模拟运放电路,可直接接传感器输出】

3、 输入范围可以选择正负5V或者正负10V,可通过IO控制量程。

4、 最大采样频率 200Ksps,支持8档过采样设置(可以有效降低抖动)。

5、 通信接口支持SPI或16位总线方式(也支持8位总线,一般用的比较少),接口IO电平可以是5V或3.3V。

重要提示:

1、 AD7606的配置很简单,它没有内部寄存器。量程范围和过采样参数是通过外部IO控制的。采样速率由MCU或DSP提供的脉冲频率控制。

2、 AD7606必须使用单5V供电。

3、 AD7606和MCU之间的通信接口电平由VIO(VDRIVE)引脚控制。也就是说VIO必须接单片机的电源,可以是3.3V也可以是5V。

产品效果:

20200508140550338.png


aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


8080或者SPI接口方式选择

出厂的AD7606模块缺省是8080并行接口,如果用SPI接口模式,需要修改R1、R2电阻配置。

并口模式跳线:R1 悬空(不贴),R2贴10K电阻。

SPI接口模式跳线:R1 贴10K电阻,R2 悬空(不贴)。

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


76.3.3 AD7606模块(屏蔽版)
屏蔽版主要是为了更好的应对复杂的电磁工作,软件代码与非屏蔽版是一样的:

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


20200508140605846.png



aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


20200508140615624.png



76.3.4 AD7606模块(磁耦高速隔离)
该款ADC模块采用磁耦隔离技术隔离SPI通信接口,采用DC-DC隔离电源模块隔离供电电源。高速SPI接口,ADC主芯片采用AD7606芯片。8通道200KHz采样。量程和滤波设置通过短路焊点设置。

产品规格

模拟通道 : 8路同步采集。

采样频率 : 最大200KHz。

ADC分辨率 : 16bit。

输入量程 : 正负5V或正负10V (通过焊点切换)。

滤波设置 : 0 - 64 共7级硬件均值滤波。

供电电压 : 5.0V,  耗电最大50mA。

通信接口 : SPI,最大时钟频率 16MHz。

接口电平 : 3.3V 或 5V  (3.3V时,耗电15mA)。

产品特点

1、电源隔离,隔离电压1500V。

2、SPI通信接口隔离,高速磁耦隔离技术。

3、短路点切换量程和过采样(滤波)参数。

4、体积小,2.0mm间距排针,节约主板面积。

产品效果:

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


引脚定义和接线图:

20200508140632288.png


20200508140645611.png


20200508140657153.png



76.4 AD7606关键知识点整理(重要)
驱动AD7606需要对下面这些知识点有个认识。

76.4.1 AD7606基础信息
  支持8通道同步采样,每个通道最高200Ksps,16bit分辨率。
  真双极模拟输入范围:±10V、±5V。
  5V单模拟电源,VDRIVER支持2.3V到5V。
  完全集成的数据采集解决方案:
  模拟输入钳位保护,可以耐受±16.5V的电压。
  具有1MΩ模拟输入阻抗的输入缓冲器。
  二阶抗混叠模拟滤波器。
片内精密基准电压及缓冲。
  通过数字滤波器,提供过采样功能。
  灵活的并行/串行即可,支持SPI/QSPI/MICROWIRE/DSP等。
  性能
  模拟输入通道提供7KV ESD。
  95.5dB SNR,-107dB THD,±0.5 LSB INL,±0.5 LSB DNL。
  低功耗:100mW。
  待机功耗:25mW。

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png



76.4.2 AD7606常用引脚的作用
AD7606的封装形式:

20200508140749777.png


aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png



这里把常用的几个引脚做个说明:

  AVcc
模拟电源电压,4.75V到5.25V。这是内部前端放大器和ADC内核的电源电压。应将这些电压引脚去偶接AGND。

  AGND
模拟地,这些引脚是AD7606上所有模拟电路的接地基准点。所有模拟输入信号和外部基准信号都应参考这些引脚。

  OS2 OS1 OS2 :
组合状态选择过采样模式。

  000表示无过采样,最大200Ksps采样速率。
  001表示2倍过采样, 也就是硬件内部采集2个样本求平均。
  010表示4倍过采样, 也就是硬件内部采集4个样本求平均。
  011表示8倍过采样, 也就是硬件内部采集8个样本求平均。
  100表示16倍过采样, 也就是硬件内部采集16个样本求平均。
  101表示32倍过采样, 也就是硬件内部采集32个样本求平均。
  110表示64倍过采样, 也就是硬件内部采集64个样本求平均。
过采样倍率越高,ADC转换时间越长,可得到的最大采样频率就越低。

  CONVSTA,CONVSTB :
启动AD转换的控制信号。CONVSTA决定1-4通道,CONVSTB决定5-8通道。2个信号可以错开短暂的时间。一般情况可以将CVA,CVB并联在一起。

  RAGE :
量程范围选择。0表示正负5V, 1表示正负10V.

RD /SCL:
读信号,低电平有效。

  RESET
复位信号。

  BUSY :
CONVST A和CONVST B均达到上升沿后,此引脚变为逻辑高电平,表示转换过程已经开始,BUSY输出保持高电平,直到所有通道的转换过程完成为止。BUSY下降沿表示转换数据正被锁存至输出数据寄存器,此时用户就可以读取数据。

  CS :
片选信号,低电平有效。

  FRST :
第1个通道样本的指示信号。【注,此引脚可以省略不使用】

  VDriver:
通信接口电平。

  DB0-DB15 :
数据总线。

  REF SELECT
内部/外部基准电压选择。如果设置此引脚设为逻辑高电平,使用内部基准电压。如果此引脚设为逻辑低电平,则内部基准电压禁止,必须将外部基准电压加到REFIN/REFOUT引脚。

  REFIN/REFOUT
基准电压输入(REFIN)/基准电压输出(REFOUT)引脚,如果REF SELECT引脚设置为逻辑高电平,此引脚将提供2.5V片内基准电压供外部使用。或者可以将REF SELECT引脚设置为逻辑低电平将禁止用内部基准电压。

  V1到V8
模拟输入,此引脚为单端模拟输入,此通道的模拟输入范围由RANGE引脚决定。

  V1GND到V8GND
模拟输入接地引脚,这些引脚与模拟输入引脚V1到V8对应,所有模拟输入AGND引脚都应连接到系统的AGND平面。

76.4.3 AD7606输出电压计算公式
AD7606的计算公式如下:

20200508140806631.png



采用二进制补码(其实就是16bit有符号数,将转换结果定义为int16_t即可),因为AD7606支持正负压采集。

  VIN
AD7606采集到的电压值范围-32768到32767。

  REF
一般使用内部基准,即2.5V。

76.4.4 AD7606时序图
了解时序参数是驱动AD7606能否成功的关键,我们这里对几个重要的参数做个说明。

1、AD7606的CONVST转换时序(转换之后读取数据):

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


  t5
CONVST A和CONVST B上升沿之间最大允许的延迟时间。一般我们是用一根控制线同时控制CONVST A和CONVST B,因此可以不用管这个时间。

  tCYCLE
并行模式,转换后并读取数据的最大值是5us,即最高支持的时钟速度是20MHz及其以上。

  tCONV
转换时间。

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


  t3
最短的CONVST A/B电平脉冲,最小值25ns。

  t4
BUSY下降沿到CS下降沿设置时间,最小值0ns,所以可以忽略。

2、AD7606的并行驱动模式有两种时序图,一个是独立的CS片选和RD读信号时序图:

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


  t8
CS到RD的设置时间,最小值是0ns,可以忽略。

  t10
RD读信号的低电平脉冲宽度,通信电压不同,时间不同。对于STM32来说,FMC通信电平一般是3.3V,即最小值21ns。

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


  t11
RD高电平脉冲宽度,最小值15ns。

  t9
CS到RD保持时间,最小值0ns,可以忽略。

  13到t17
这几个参数了解下即可:

20200508140823116.png


3、另一个是CS片选和RD相连的方式:

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


这个时序里面最重要的是t12。

  t12
CS和RD的高电平脉冲宽度,最小值22ns。

第2个和第3个时序图的主要区别是连续读取8路数据时,一个CS信号是全程低电平,另一个CS信号是与RD信号同步,每读取完一路,拉高一次。

76.4.5 AD7606的过采样
使用过采样可以改善SNR信噪比。SNR性能随着过采样倍率提高而改善,具体参数如下:

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


通过这个表,我们可以方便的了解不同过采样下的信噪比,3dB带宽时的频率和最高支持的采样率。

注意正确的理解过采样,比如我们设置是1Ksps采样率,64倍过采样。意思是指每次采样,AD7606会采样64次数据并求平均,相当于AD7606以64Ksps进行采样的,只是将每64个采样点的值做了平均,用户得到的值就是平均后的数值。因此,如果使用AD7606最高的200Ksps采样率,就不可以使用过采样了。

76.5 AD7606的FMC接口硬件设计
FMC硬件接口涉及到的知识点稍多,下面逐一为大家做个说明。

76.5.1 FMC的块区分配
FMC总线可操作的地址范围0x60000000到0xDFFFFFFF,具体的框图如下:

20200508140837436.png


从上面的框图可以看出,NOR/PSRAM/SRAM块区有4个片选NE1,NE2,NE3和NE4,但由于引脚复用,部分片选对应的引脚要用于其他功能,而且要控制的总线外设较多,导致片选不够用。因此需要增加译码器。

76.5.2 译码器及其地址计算
有了前面的认识之后再来看下面的译码器电路:

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


SN74LVC1G139APWR是双2-4线地址译码器,也就是带了两个译码器。原理图上仅用了一个。下面是139的真值表和引脚功能:

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png



通过上面的原理图和真值表就比较好理解了,真值表的输出是由片选FMC_NE1和地址线FMC_A10、FMC_A11控制。

FMC_NE1 输出低电平:

  FMC_A11(B),FMC_A10(A) = 00时,1Y0输出的低电平,选择的是OLED。
  FMC_A11(B),FMC_A10(A) = 01时,1Y1输出的低电平,选择的是74HC574。
  FMC_A11(B),FMC_A10(A) = 10时,1Y2输出的低电平,选择的是DM9000。
  FMC_A11(B),FMC_A10(A) = 11时,1Y3输出的低电平,选择的是AD7606。
然后我们再计算译码器的地址,注意,这里地址的计算都是按照FMC的32bit访问模式计算的,因为我们的V7程序中是将NE1对应的FMC配置为32bit模式了。

具体FMC的32bit访问模式,16bit访问模式和8bit访问模式的区别在第47章的2.4小节有详细讲解。

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


32bit模式下,我们计算A10和A11的时候,实际上需要按HADDR12和HADDR13计算的。

如果来算NE1 + HADDR12 + HADDR13的四种组合地址就是如下:

NE1 + HADDR13 + HADDR12 = 0x60000000 +  0<<13 + 0<<12 = 0x60000000

NE1 + HADDR13 + HADDR12 = 0x60000000 +  0<<13 + 1<<12 = 0x60001000

NE1 + HADDR13 + HADDR12 = 0x60000000 +  1<<13 + 0<<12 = 0x60002000

NE1 + HADDR13 + HADDR12 = 0x60000000 +  1<<13 + 1<<12 = 0x60003000

这样一来,原理图里面给的地址就对应上了。同理如果配置为16位模式和8位模式,大家应该也都会计算了。

76.6 AD7606的FMC接口驱动设计
AD7606的程序驱动框架设计如下:

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


有了这个框图,程序设计就比较好理解了。

76.6.1 第1步,AD7606整体驱动框架设计
主要实现了两种采集方式:

(1)软件定时获取方式,适合低速查询获取。

(2)FIFO工作模式,适合8路实时采集,支持最高采样率200Ksps。

  方案一:软件定时获取方式代码框架:
可以在硬件定时器中断服务程序或者软件定时器里面实现。

定时器中断ISR:
  1. {
  2.     中断入口;
  3. 读取8个通道的采样结果保存到RAM;  ----> 读取的是上次的采集结果,对于连续采集来说,是没有关系的
  4.     启动下次ADC采集;(翻转CVA和CVB)
  5.     中断返回;
  6. }
复制代码

定时器的频率就是ADC采样频率。这种模式可以不连接BUSY口线。

  方案二:FIFO工作模式框架:
    配置CVA、CVB引脚为PWM输出模式,周期设置为需要的采样频率,之后MCU将产生周期非常稳定的AD转换信号

    将BUSY口线设置为中断下降沿触发模式;

  1. 外部中断ISR:
  2. {
  3.     中断入口;
  4.     读取8个通道的采样结果保存到RAM;
  5. }
复制代码

  方案1和方案2的差异
(1)方案1 可以少用 BUSY口线,但是其他中断服务程序或者主程序临时关闭全局中断时,可能导致ADC转换周期存在轻微抖动。

(2)方案2 可以确保采集时钟的稳定性,因为它是MCU硬件产生的,但是需要多接一根BUSY口线。

76.6.2 第2步,AD7606所涉及到的GPIO配置
这里需要把用到的GPIO时钟、FMC时钟、GPIO引脚和复用配置好即可:

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AD7606_CtrlLinesConfig
  4. *    功能说明: 配置GPIO口线,FMC管脚设置为复用功能
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. /*
  10.     安富莱STM32-H7开发板接线方法:4片74HC574挂在FMC 32位总线上。1个地址端口可以扩展出32个IO
  11.     PD0/FMC_D2
  12.     PD1/FMC_D3
  13.     PD4/FMC_NOE        ---- 读控制信号,OE = Output Enable , N 表示低有效
  14.     PD5/FMC_NWE        -XX- 写控制信号,AD7606 只有读,无写信号
  15.     PD8/FMC_D13
  16.     PD9/FMC_D14
  17.     PD10/FMC_D15
  18.     PD14/FMC_D0
  19.     PD15/FMC_D1

  20.     PE7/FMC_D4
  21.     PE8/FMC_D5
  22.     PE9/FMC_D6
  23.     PE10/FMC_D7
  24.     PE11/FMC_D8
  25.     PE12/FMC_D9
  26.     PE13/FMC_D10
  27.     PE14/FMC_D11
  28.     PE15/FMC_D12

  29.     PG0/FMC_A10        --- 和主片选FMC_NE2一起译码
  30.     PG1/FMC_A11        --- 和主片选FMC_NE2一起译码
  31.     PD7/FMC_NE1        --- 主片选(OLED, 74HC574, DM9000, AD7606)   

  32.      +-------------------+------------------+
  33.      +   32-bits Mode: D31-D16              +
  34.      +-------------------+------------------+
  35.      | PH8 <-> FMC_D16   | PI0 <-> FMC_D24  |
  36.      | PH9 <-> FMC_D17   | PI1 <-> FMC_D25  |
  37.      | PH10 <-> FMC_D18  | PI2 <-> FMC_D26  |
  38.      | PH11 <-> FMC_D19  | PI3 <-> FMC_D27  |
  39.      | PH12 <-> FMC_D20  | PI6 <-> FMC_D28  |
  40.      | PH13 <-> FMC_D21  | PI7 <-> FMC_D29  |
  41.      | PH14 <-> FMC_D22  | PI9 <-> FMC_D30  |
  42.      | PH15 <-> FMC_D23  | PI10 <-> FMC_D31 |
  43.      +------------------+-------------------+
  44. */

  45. /*
  46.     控制AD7606参数的其他IO分配在扩展的74HC574上
  47.     X13 - AD7606_OS0
  48.     X14 - AD7606_OS1
  49.     X15 - AD7606_OS2
  50.     X24 - AD7606_RESET
  51.     X25 - AD7606_RAGE   

  52.     PE5 - AD7606_BUSY
  53. */
  54. static void AD7606_CtrlLinesConfig(void)
  55. {
  56.     /* bsp_fm_io 已配置fmc,bsp_InitExtIO();
  57.        此处可以不必重复配置
  58.     */

  59.     GPIO_InitTypeDef gpio_init_structure;

  60.     /* 使能 GPIO时钟 */
  61.     __HAL_RCC_GPIOD_CLK_ENABLE();
  62.     __HAL_RCC_GPIOE_CLK_ENABLE();
  63.     __HAL_RCC_GPIOF_CLK_ENABLE();
  64.     __HAL_RCC_GPIOG_CLK_ENABLE();
  65.     __HAL_RCC_GPIOH_CLK_ENABLE();
  66.     __HAL_RCC_GPIOI_CLK_ENABLE();

  67.     /* 使能FMC时钟 */
  68.     __HAL_RCC_FMC_CLK_ENABLE();

  69.     /* 设置 GPIOD 相关的IO为复用推挽输出 */
  70.     gpio_init_structure.Mode = GPIO_MODE_AF_PP;
  71.     gpio_init_structure.Pull = GPIO_PULLUP;
  72.     gpio_init_structure.Speed = GPIO_SPEED_FREQ_HIGH;
  73.     gpio_init_structure.Alternate = GPIO_AF12_FMC;

  74.     /* 配置GPIOD */
  75.     gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_7 |
  76.                                 GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_14 |
  77.                                 GPIO_PIN_15;
  78.     HAL_GPIO_Init(GPIOD, &gpio_init_structure);

  79.     /* 配置GPIOE */
  80.     gpio_init_structure.Pin = GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 |
  81.                                 GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 |
  82.                                 GPIO_PIN_15;
  83.     HAL_GPIO_Init(GPIOE, &gpio_init_structure);

  84.     /* 配置GPIOG */
  85.     gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1;
  86.     HAL_GPIO_Init(GPIOG, &gpio_init_structure);

  87.     /* 配置GPIOH */
  88.     gpio_init_structure.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12
  89.                         | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
  90.     HAL_GPIO_Init(GPIOH, &gpio_init_structure);

  91.     /* 配置GPIOI */
  92.     gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_6
  93.                         | GPIO_PIN_7 | GPIO_PIN_9 | GPIO_PIN_10;
  94.     HAL_GPIO_Init(GPIOI, &gpio_init_structure);


  95.     /* 配置BUSY引脚,默认是普通IO状态 */
  96.     {
  97.         GPIO_InitTypeDef   GPIO_InitStructure;

  98.         __HAL_RCC_SYSCFG_CLK_ENABLE();

  99.         BUSY_RCC_GPIO_CLK_ENABLE();        /* 打开GPIO时钟 */

  100.         /* BUSY信号,使用的PE5,用于转换完毕检测 */
  101.         GPIO_InitStructure.Mode = GPIO_MODE_INPUT;   /* 设置推挽输出 */
  102.         GPIO_InitStructure.Pull = GPIO_NOPULL;       /* 无上拉下拉 */
  103.         GPIO_InitStructure.Pin = BUSY_PIN;           
  104.         HAL_GPIO_Init(BUSY_GPIO, &GPIO_InitStructure);   
  105.     }

  106.     /* CONVST 启动ADC转换的GPIO = PC6 */
  107.     {
  108.         GPIO_InitTypeDef   GPIO_InitStructure;
  109.         CONVST_RCC_GPIO_CLK_ENABLE();

  110.         /* 配置PC6 */
  111.         GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;        /* 设置推挽输出 */
  112.         GPIO_InitStructure.Pull = GPIO_NOPULL;            /* 上下拉电阻不使能 */
  113.         GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_MEDIUM;  /* GPIO速度等级 */   

  114.         GPIO_InitStructure.Pin = CONVST_PIN;   
  115.         HAL_GPIO_Init(CONVST_GPIO, &GPIO_InitStructure);   
  116.     }
  117. }
复制代码


这里重点注意AD7606_CONVST和AD7606_BUSY引脚,上电后的默认配置是普通IO。另外还有过采样的3个引脚,量程配置的1个引脚和复位控制的1个引脚,均通过V7板子的扩展IO实现:

  1. /* 设置过采样的IO, 在扩展的74HC574上 */
  2. #define OS0_1()        HC574_SetPin(AD7606_OS0, 1)
  3. #define OS0_0()        HC574_SetPin(AD7606_OS0, 0)
  4. #define OS1_1()        HC574_SetPin(AD7606_OS1, 1)
  5. #define OS1_0()        HC574_SetPin(AD7606_OS1, 0)
  6. #define OS2_1()        HC574_SetPin(AD7606_OS2, 1)
  7. #define OS2_0()        HC574_SetPin(AD7606_OS2, 0)

  8. /* 设置输入量程的GPIO, 在扩展的74HC574上 */
  9. #define RANGE_1()    HC574_SetPin(AD7606_RANGE, 1)
  10. #define RANGE_0()    HC574_SetPin(AD7606_RANGE, 0)

  11. /* AD7606复位口线, 在扩展的74HC574上 */
  12. #define RESET_1()    HC574_SetPin(AD7606_RESET, 1)
  13. #define RESET_0()    HC574_SetPin(AD7606_RESET, 0)
复制代码

76.6.3 第3步,FMC的时钟源选择
使用FMC可以选择如下几种时钟源HCLK3,PLL1Q,PLL2R和PER_CK:

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


我们这里直接使用HCLK3,配置STM32H7的主频为400MHz的时候,HCLK3输出的200MHz,这个速度是FMC支持的最高时钟,正好用于这里:

20200508140902195.png


76.6.4 第4步,FMC的时序配置(重要)
由于操作AD7606仅需要读操作,而且使用的是FMC总线的Mode_A,那么仅需按照如下时序图配置好即可:

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


根据这个时序图,重点配置好ADDSET地址建立时间和DATAST数据建立时间即可。

  DATAST(DataSetupTime,数据建立时间)
DATAST实际上对应的就是76.4.4小节里面的t10 。RD读信号的低电平脉冲宽度,通信电压不同,时间不同,对于STM32来说,FMC通信电平一般是3.3V,即最小值21ns。

20200508140922440.png


  ADDST(AddressSetupTime,地址建立时间)
DATAST实际上对应的就是76.4.4小节里面的t11 或者t12。

  如果采用CS(NEx)片选和RD(NOE)读信号独立方式,对应的时间最小15ns,即t11 。
  如果采用CS(NEx)片选和RD(NOE)读信号并联方式,对应的时间最小22ns,即t12  。
我们这里将t12作为最小值更合理,因为CS(NEx)片选信号,每读取完毕一路,拉高一次。



有了这些认识后,再来看FMC的时序配置就比较好理解了:

  1. 1.    /*
  2. 2.    ******************************************************************************************************
  3. 3.    *    函 数 名: AD7606_FSMCConfig
  4. 4.    *    功能说明: 配置FSMC并口访问时序
  5. 5.    *    形    参: 无
  6. 6.    *    返 回 值: 无
  7. 7.    ******************************************************************************************************
  8. 8.    */
  9. 9.    static void AD7606_FSMCConfig(void)
  10. 10.    {
  11. 11.        /*
  12. 12.           DM9000,扩展IO,OLED和AD7606公用一个FMC配置,如果都开启,请以FMC速度最慢的为准。
  13. 13.           从而保证所有外设都可以正常工作。
  14. 14.        */
  15. 15.        SRAM_HandleTypeDef hsram = {0};
  16. 16.        FMC_NORSRAM_TimingTypeDef SRAM_Timing = {0};
  17. 17.            
  18. 18.       /*
  19. 19.        AD7606规格书要求(3.3V时,通信电平Vdriver):RD读信号低电平脉冲宽度最短21ns,对应DataSetupTime
  20. 20.        CS片选和RD读信号独立方式的高电平脉冲最短宽度15ns。
  21. 21.        CS片选和RD读信号并联方式的高电平脉冲最短宽度22ns。
  22. 22.        这里将22ns作为最小值更合理些,对应FMC的AddressSetupTime。
  23. 23.        
  24. 24.            5-x-5-x-x-x  : RD高持续25ns, 低电平持续25ns. 读取8路样本数据到内存差不多就是400ns。
  25. 25.        */
  26. 26.        hsram.Instance  = FMC_NORSRAM_DEVICE;
  27. 27.        hsram.Extended  = FMC_NORSRAM_EXTENDED_DEVICE;
  28. 28.        
  29. 29.        /* FMC使用的HCLK3,主频200MHz,1个FMC时钟周期就是5ns */
  30. 30.        SRAM_Timing.AddressSetupTime       = 5; /* 5*5ns=25ns,地址建立时间,范围0 -15个FMC时钟周期个数 */
  31. 31.        SRAM_Timing.AddressHoldTime        = 2; /* 地址保持时间,配置为模式A时,用不到此参数 范围1 -15个
  32. 32.                                                    时钟周期个数 */
  33. 33.        SRAM_Timing.DataSetupTime          = 5;  /* 5*5ns=25ns,数据建立时间,范围1 -255个时钟周期个数 */
  34. 34.        SRAM_Timing.BusTurnAroundDuration  = 1;  /* 此配置用不到这个参数 */
  35. 35.        SRAM_Timing.CLKDivision            = 2;  /* 此配置用不到这个参数 */
  36. 36.        SRAM_Timing.DataLatency            = 2;  /* 此配置用不到这个参数 */
  37. 37.        SRAM_Timing.AccessMode             = FMC_ACCESS_MODE_A; /* 配置为模式A */
  38. 38.        hsram.Init.NSBank             = FMC_NORSRAM_BANK1;              /* 使用的BANK1,即使用的片选
  39. 39.                                                                            FMC_NE1 */
  40. 40.        hsram.Init.DataAddressMux     = FMC_DATA_ADDRESS_MUX_DISABLE;   /* 禁止地址数据复用 */
  41. 41.        hsram.Init.MemoryType         = FMC_MEMORY_TYPE_SRAM;           /* 存储器类型SRAM */
  42. 42.        hsram.Init.MemoryDataWidth    = FMC_NORSRAM_MEM_BUS_WIDTH_32;   /* 32位总线宽度 */
  43. 43.        hsram.Init.BurstAccessMode    = FMC_BURST_ACCESS_MODE_DISABLE;  /* 关闭突发模式 */
  44. 44.        hsram.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW;   /* 用于设置等待信号的极性,关闭突
  45. 45.                                                                            发模式,此参数无效 */
  46. 46.        hsram.Init.WaitSignalActive   = FMC_WAIT_TIMING_BEFORE_WS;      /* 关闭突发模式,此参数无效 */
  47. 47.        hsram.Init.WriteOperation     = FMC_WRITE_OPERATION_ENABLE;     /* 用于使能或者禁止写保护 */
  48. 48.        hsram.Init.WaitSignal         = FMC_WAIT_SIGNAL_DISABLE;        /* 关闭突发模式,此参数无效 */
  49. 49.        hsram.Init.ExtendedMode       = FMC_EXTENDED_MODE_DISABLE;      /* 禁止扩展模式 */
  50. 50.        hsram.Init.AsynchronousWait   = FMC_ASYNCHRONOUS_WAIT_DISABLE;  /* 用于异步传输期间,使能或者禁止
  51. 51.                                                                            等待信号,这里选择关闭 */
  52. 52.        hsram.Init.WriteBurst         = FMC_WRITE_BURST_DISABLE;        /* 禁止写突发 */
  53. 53.        hsram.Init.ContinuousClock    = FMC_CONTINUOUS_CLOCK_SYNC_ONLY; /* 仅同步模式才做时钟输出 */
  54. 54.        hsram.Init.WriteFifo          = FMC_WRITE_FIFO_ENABLE;          /* 使能写FIFO */
  55. 55.   
  56. 56.        /* 初始化SRAM控制器 */
  57. 57.        if (HAL_SRAM_Init(&hsram, &SRAM_Timing, &SRAM_Timing) != HAL_OK)
  58. 58.        {
  59. 59.            /* 初始化错误 */
  60. 60.            Error_Handler(__FILE__, __LINE__);
  61. 61.        }   
  62. 62.    }
复制代码

这里把几个关键的地方阐释下:

  第15- 16行,对作为局部变量的HAL库结构体做初始化,防止不确定值配置时出问题。
  第30行,地址建立时间,对于AD7606来说,这个地方最小值22ns。保险起见,这里取值5个FMC时钟周期,即25ns。
  第31行,地址保持时间,对于FMC模式A来说,此参数用不到。
  第33行,数据建立时间,对于AD7606来说,这个地方最小值是21ns,保险起见,这里取值5个FMC时钟周期,即25ns。
  第34 – 36行,当前配置用不到这三个参数。
  第38行,使用的BANK1,即使用的片选FMC_NE1。

76.6.5 第5步,FMC的MPU配置
实际测试发现,使能FMC_NE1所管理的存储区的Cache功能后,会出现扩展IO的NE片选和NWE信号输出2次的问题。经过各种Cache方式配置、FMC带宽配置、操作FMC时的数据位宽设置,发现禁止了Cache功能就正常了,也就是说,设置FMC_NE1所管理的存储区MPU属性为Device或者Strongly Ordered即可。

  1. /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
  2.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
  3.     MPU_InitStruct.BaseAddress      = 0x60000000;
  4.     MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;   
  5.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  6.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
  7.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;
  8.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
  9.     MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
  10.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
  11.     MPU_InitStruct.SubRegionDisable = 0x00;
  12.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;

  13.     HAL_MPU_ConfigRegion(&MPU_InitStruct);
复制代码



MPU配置中直接从FMC_NE1的首地址开始配置,设置了64KB空间的属性。将FMC_NE1通过译码器所管理的所有设备地址全部设置为此配置:

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


76.6.6 第6步,AD7606的软件定时器读取数据(方案一)
AD7606的软件定时器读取方式比较简单,周期性调用下面两个函数即可:

  1. AD7606_ReadNowAdc();        /* 读取采样结果 */
  2. AD7606_StartConvst();        /* 启动下次转换 */
  3. 函数AD7606_ReadNowAdc的实现如下:

  4. /* AD7606 FSMC总线地址,只能读,无需写 */
  5. #define AD7606_RESULT()    *(__IO uint16_t *)0x60003000

  6. void AD7606_ReadNowAdc(void)
  7. {
  8.     g_tAD7606.sNowAdc[0] = AD7606_RESULT();    /* 读第1路样本 */
  9.     g_tAD7606.sNowAdc[1] = AD7606_RESULT();    /* 读第2路样本 */
  10.     g_tAD7606.sNowAdc[2] = AD7606_RESULT();    /* 读第3路样本 */
  11.     g_tAD7606.sNowAdc[3] = AD7606_RESULT();    /* 读第4路样本 */
  12.     g_tAD7606.sNowAdc[4] = AD7606_RESULT();    /* 读第5路样本 */
  13.     g_tAD7606.sNowAdc[5] = AD7606_RESULT();    /* 读第6路样本 */
  14.     g_tAD7606.sNowAdc[6] = AD7606_RESULT();    /* 读第7路样本 */
  15.     g_tAD7606.sNowAdc[7] = AD7606_RESULT();    /* 读第8路样本 */

  16.     AD7606_SEGGER_RTTOUT();
  17. }
复制代码

启动ADC转换的函数实现如下:

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AD7606_StartConvst
  4. *    功能说明: 启动1次ADC转换
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. void AD7606_StartConvst(void)
  10. {
  11.     /* page 7:  CONVST 高电平脉冲宽度和低电平脉冲宽度最短 25ns */
  12.     /* CONVST平时为高 */
  13.     CONVST_0();
  14.     CONVST_0();
  15.     CONVST_0();

  16.     CONVST_1();
  17. }
复制代码

76.6.7 第7步,AD7606的FIFO方式实时读取数据(方案二)
通过下面的框图可以对AD7606的FIFO方式有个整体认识:

20200508140943263.png


  启动采集函数AD7606_StartRecord
这个函数的主要作用是配置TIM8的CH1 PWM输出并使能BUSY引脚的EXTI中断。

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AD7606_StartRecord
  4. *    功能说明: 开始采集
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. void AD7606_StartRecord(uint32_t _ulFreq)
  10. {
  11.     AD7606_StopRecord();

  12.     AD7606_Reset();            /* 复位硬件 */
  13.     AD7606_StartConvst();        /* 启动采样,避免第1组数据全0的问题 */

  14.     g_tAdcFifo.usRead = 0;        /* 必须在开启定时器之前清0 */
  15.     g_tAdcFifo.usWrite = 0;
  16.     g_tAdcFifo.usCount = 0;
  17.     g_tAdcFifo.ucFull = 0;

  18.     AD7606_EnterAutoMode(_ulFreq);
  19. }
  20. /*
  21. *********************************************************************************************************
  22. *    函 数 名: AD7606_EnterAutoMode
  23. *    功能说明: 配置硬件工作在自动采集模式,结果存储在FIFO缓冲区。
  24. *    形    参:  _ulFreq : 采样频率,单位Hz,    1k,2k,5k,10k,20K,50k,100k,200k
  25. *    返 回 值: 无
  26. *********************************************************************************************************
  27. */
  28. void AD7606_EnterAutoMode(uint32_t _ulFreq)
  29. {
  30.     /* 配置PC6为TIM8_CH1功能,输出占空比50%的方波 */
  31.     bsp_SetTIMOutPWM(CONVST_GPIO, CONVST_PIN, CONVST_TIMX,  CONVST_TIMCH, _ulFreq, 5000);

  32.     /* 配置PE5, BUSY 作为中断输入口,下降沿触发 */
  33.     {
  34.         GPIO_InitTypeDef   GPIO_InitStructure;

  35.         CONVST_RCC_GPIO_CLK_ENABLE();    /* 打开GPIO时钟 */
  36.         __HAL_RCC_SYSCFG_CLK_ENABLE();

  37.         GPIO_InitStructure.Mode = GPIO_MODE_IT_FALLING;    /* 中断下降沿触发 */
  38.         GPIO_InitStructure.Pull = GPIO_NOPULL;
  39.         GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;        
  40.         GPIO_InitStructure.Pin = BUSY_PIN;
  41.         HAL_GPIO_Init(BUSY_GPIO, &GPIO_InitStructure);   

  42.         HAL_NVIC_SetPriority(BUSY_IRQn, 2, 0);
  43.         HAL_NVIC_EnableIRQ(BUSY_IRQn);   
  44.     }        
  45. }
复制代码


  AD7606转换完毕后,中断服务程序的处理。
下面这几个函数的调用关系是

  EXTI9_5_IRQHandler调用HAL_GPIO_EXTI_IRQHandler。
  HAL_GPIO_EXTI_IRQHandler调用HAL_GPIO_EXTI_Callback。
  HAL_GPIO_EXTI_Callback调用AD7606_ISR。
  AD7606_ISR调用AD7606_ReadNowAdc。
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: EXTI9_5_IRQHandler
  4. *    功能说明: 外部中断服务程序。
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. void EXTI9_5_IRQHandler(void)
  10. {
  11.     HAL_GPIO_EXTI_IRQHandler(BUSY_PIN);
  12. }

  13. /*
  14. *********************************************************************************************************
  15. *    函 数 名: EXTI9_5_IRQHandler
  16. *    功能说明: 外部中断服务程序入口, AD7606_BUSY 下降沿中断触发
  17. *    形    参: 无
  18. *    返 回 值: 无
  19. *********************************************************************************************************
  20. */
  21. void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
  22. {
  23.     if (GPIO_Pin == BUSY_PIN)
  24.     {
  25.         AD7606_ISR();
  26.     }
  27. }

  28. /*
  29. *********************************************************************************************************
  30. *    函 数 名: AD7606_ISR
  31. *    功能说明: 定时采集中断服务程序
  32. *    形    参: 无
  33. *    返 回 值: 无
  34. *********************************************************************************************************
  35. */
  36. void AD7606_ISR(void)
  37. {
  38.     uint8_t i;

  39.     AD7606_ReadNowAdc();

  40.     for (i = 0; i < 8; i++)
  41.     {
  42.         g_tAdcFifo.sBuf[g_tAdcFifo.usWrite] = g_tAD7606.sNowAdc<i>;
  43.     </i>    if (++g_tAdcFifo.usWrite >= ADC_FIFO_SIZE)
  44.         {
  45.             g_tAdcFifo.usWrite = 0;
  46.         }
  47.         if (g_tAdcFifo.usCount < ADC_FIFO_SIZE)
  48.         {
  49.             g_tAdcFifo.usCount++;
  50.         }
  51.         else
  52.         {
  53.             g_tAdcFifo.ucFull = 1;        /* FIFO 满,主程序来不及处理数据 */
  54.         }
  55.     }
  56. }
复制代码


这里的FIFO比较好理解,与前面按键FIFO章节的实现是一样的,详情可重温下按键FIFO的实现。

76.6.8 第8步,AD7606的双缓冲方式存储思路
为了方便大家实时处理采集的数据,专门预留了一个弱定义函数AD7606_SEGGER_RTTOUT,方便大家将采集函数存储到双缓冲里面,这个函数是在中断服务程序里面调用的。

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AD7606_ReadNowAdc
  4. *    功能说明: 读取8路采样结果。结果存储在全局变量 g_tAD7606
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. /* 弱定义,方便用户将采集的结果实时输出 */
  10. __weak void AD7606_SEGGER_RTTOUT(void)
  11. {

  12. }

  13. void AD7606_ReadNowAdc(void)
  14. {
  15.     g_tAD7606.sNowAdc[0] = AD7606_RESULT();    /* 读第1路样本 */
  16.     g_tAD7606.sNowAdc[1] = AD7606_RESULT();    /* 读第2路样本 */
  17.     g_tAD7606.sNowAdc[2] = AD7606_RESULT();    /* 读第3路样本 */
  18.     g_tAD7606.sNowAdc[3] = AD7606_RESULT();    /* 读第4路样本 */
  19.     g_tAD7606.sNowAdc[4] = AD7606_RESULT();    /* 读第5路样本 */
  20.     g_tAD7606.sNowAdc[5] = AD7606_RESULT();    /* 读第6路样本 */
  21.     g_tAD7606.sNowAdc[6] = AD7606_RESULT();    /* 读第7路样本 */
  22.     g_tAD7606.sNowAdc[7] = AD7606_RESULT();    /* 读第8路样本 */

  23.     AD7606_SEGGER_RTTOUT();
  24. }
复制代码

本章是将此函数用于实时采集数据并输出到J-Scope。

76.6.9 第9步,AD7606过采样设置
AD7606的过采样实现比较简单,通过IO引脚就可以控制,支持2倍,4倍,8倍,16倍,32倍和64倍过采样设置。

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AD7606_SetOS
  4. *    功能说明: 配置AD7606数字滤波器,也就设置过采样倍率。
  5. *              通过设置 AD7606_OS0、OS1、OS2口线的电平组合状态决定过采样倍率。
  6. *              启动AD转换之后,AD7606内部自动实现剩余样本的采集,然后求平均值输出。
  7. *
  8. *              过采样倍率越高,转换时间越长。
  9. *              0、无过采样时,AD转换时间 = 3.45us - 4.15us
  10. *              1、2倍过采样时 = 7.87us - 9.1us
  11. *              2、4倍过采样时 = 16.05us - 18.8us
  12. *              3、8倍过采样时 = 33us - 39us
  13. *              4、16倍过采样时 = 66us - 78us
  14. *              5、32倍过采样时 = 133us - 158us
  15. *              6、64倍过采样时 = 257us - 315us
  16. *
  17. *    形    参: _ucOS : 过采样倍率, 0 - 6
  18. *    返 回 值: 无
  19. *********************************************************************************************************
  20. */
  21. void AD7606_SetOS(uint8_t _ucOS)
  22. {
  23.     g_tAD7606.ucOS = _ucOS;
  24.     switch (_ucOS)
  25.     {
  26.         case AD_OS_X2:
  27.             OS2_0();
  28.             OS1_0();
  29.             OS0_1();
  30.             break;

  31.         case AD_OS_X4:
  32.             OS2_0();
  33.             OS1_1();
  34.             OS0_0();
  35.             break;

  36.         case AD_OS_X8:
  37.             OS2_0();
  38.             OS1_1();
  39.             OS0_1();
  40.             break;

  41.         case AD_OS_X16:
  42.             OS2_1();
  43.             OS1_0();
  44.             OS0_0();
  45.             break;

  46.         case AD_OS_X32:
  47.             OS2_1();
  48.             OS1_0();
  49.             OS0_1();
  50.             break;

  51.         case AD_OS_X64:
  52.             OS2_1();
  53.             OS1_1();
  54.             OS0_0();
  55.             break;

  56.         case AD_OS_NO:
  57.         default:
  58.             g_tAD7606.ucOS = AD_OS_NO;
  59.             OS2_0();
  60.             OS1_0();
  61.             OS0_0();
  62.             break;
  63.     }
  64. }

复制代码

76.6.10   第10步,AD7606量程设置
AD7606支持两种量程,±5V和±10V,实现代码如下:

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AD7606_SetInputRange
  4. *    功能说明: 配置AD7606模拟信号输入量程。
  5. *    形    参: _ucRange : 0 表示正负5V   1表示正负10V
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. void AD7606_SetInputRange(uint8_t _ucRange)
  10. {
  11.     if (_ucRange == 0)
  12.     {
  13.         g_tAD7606.ucRange = 0;
  14.         RANGE_0();    /* 设置为正负5V */
  15.     }
  16.     else
  17.     {
  18.         g_tAD7606.ucRange = 1;
  19.         RANGE_1();    /* 设置为正负10V */
  20.     }
  21. }
复制代码

76.6.11   第11步,操作数据位宽注意事项
在bsp_fmc_ad7606.c文件开头有个宏定义

#define AD7606_RESULT() *(__IO uint16_t *)0x60003000

特别注意,这里是要操作地址0x60003000上的16位数据空间,即做了一个强制转换uint16_t *。

76.7 AD7606板级支持包(bsp_fmc_ad7606.c)
AD7606驱动文件bsp_fmc_ad7606.c主要实现了如下几个API供用户调用:

  bsp_InitAD7606
  AD7606_SetOS
  AD7606_SetInputRange
  AD7606_Reset
  AD7606_StartConvst
  AD7606_ReadNowAdc
  AD7606_EnterAutoMode
  AD7606_StartRecord
  AD7606_StopRecord
  AD7606_FifoNewData
  AD7606_ReadFifo
  AD7606_FifoFull
76.7.1 函数bsp_InitAD7606
函数原型:

void bsp_InitAD7606(void)

函数描述:

主要用于AD7606的初始化。

76.7.2 函数AD7606_SetOS
函数原型:

void AD7606_SetOS(uint8_t _ucOS)

函数描述:

此函数用于配置AD7606数字滤波器,也就设置过采样倍率。通过设置 AD7606_OS0、OS1、OS2口线的电平组合状态决定过采样倍率。启动AD转换之后,AD7606内部自动实现剩余样本的采集,然后求平均值输出。

过采样倍率越高,转换时间越长。

无过采样时,AD转换时间 = 3.45us - 4.15us。

2倍过采样时 = 7.87us - 9.1us。

4倍过采样时 = 16.05us - 18.8us。

8倍过采样时 = 33us - 39us。

16倍过采样时 = 66us - 78us。

32倍过采样时 = 133us - 158us。

64倍过采样时 = 257us - 315us。

函数参数:

  第1个参数为范围0 – 6,分别对应无过采样,2倍过采样,4倍过采样,8倍过采样,16倍过采样,32倍过采样和64倍过采样。
76.7.3 函数AD7606_SetInputRange
函数原型:

void AD7606_SetInputRange(uint8_t _ucRange)

函数描述:

配置AD7606模拟信号输入量程。

函数参数:

  第1个参数为0 表示正负5V ,1表示正负10V。
76.7.4 函数AD7606_Reset
函数原型:

void AD7606_Reset(void)

函数描述:

此函数用于硬件复位AD7606,复位之后恢复到正常工作状态。

76.7.5 函数AD7606_StartConvst
函数原型:

void AD7606_StartConvst(void)

函数描述:

此函数用于启动1次ADC转换。

76.7.6 函数AD7606_ReadNowAdc
函数原型:

void AD7606_ReadNowAdc(void)

函数描述:

此函数用于读取8路采样结果,结果存储在全局变量 g_tAD7606。

76.7.7 函数AD7606_EnterAutoMode
函数原型:

void AD7606_EnterAutoMode(uint32_t _ulFreq)

函数描述:

此函数用于配置硬件工作在自动采集模式,结果存储在FIFO缓冲区。一般不单独调用,函数AD7606_StartRecord会调用。

函数参数:

  第1个参数是采样频率,范围1-200KHz,单位Hz。
76.7.8 函数AD7606_StartRecord
函数原型:

void AD7606_StartRecord(uint32_t _ulFreq)

函数描述:

用于启动采集。

函数参数:

  第1个参数是采样频率,范围1-200KHz,单位Hz。
76.7.9 函数AD7606_StopRecord
函数原型:

void AD7606_StopRecord(void)

函数描述:

此函数用于停止采集定时器。函数AD7606_StartRecord和AD7606_StopRecord是配套的。

76.7.10   函数AD7606_FifoNewData
函数原型:

uint8_t AD7606_HasNewData(void)

函数描述:

此函数用于判断FIFO中是否有新数据。

函数参数:

  返回值,1 表示有,0表示暂无数据。
76.7.11   函数AD7606_ReadFifo
函数原型:

uint8_t AD7606_ReadFifo(uint16_t *_usReadAdc)

函数描述:

此函数用于从FIFO中读取一个ADC值。

函数参数:

  第1个参数是存放ADC结果的变量指针。
  返回值,1 表示OK,0表示暂无数据。
76.7.12   函数AD7606_FifoFull
函数原型:

uint8_t AD7606_FifoFull(void)

函数描述:

此函数用于判断FIFO是否满。

函数参数:

  返回值,1 表示满,0表示未满。

76.8 J-Scope实时展示AD7606采集数据说明
J-Scope专题教程(实时展示要用J-Scope的RTT模式)。
看完专题教程,基本就会操作了,这里有三点注意事项需要大家提前有个了解。另外,推荐使用MDK版工程做测试J-Scope,IAR版容易测试不正常。

76.8.1 J-Scope闪退问题解决办法
如下界面,不要点击选择按钮,闪退就是因为点击了这个选择按钮。

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


直接手动填写型号即可,比如STM32H743XI,STM32F429BI,STM32F407IG,STM32F103ZE等。

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


76.8.2 J-Scope多通道传输实现
J-Scope的多通道传输配置好函数SEGGER_RTT_ConfigUpBuffer即可,主要是通过第2个参数实现的。

  1.    /*
  2.         配置通道1,上行配置
  3.         默认情况下,J-Scope仅显示1个通道。
  4.         上传1个通道的波形,配置第2个参数为JScope_i2
  5.         上传2个通道的波形,配置第2个参数为JScope_i2i2
  6.         上传3个通道的波形,配置第2个参数为JScope_i2i2i2
  7.         上传4个通道的波形,配置第2个参数为JScope_i2i2i2i2
  8.         上传5个通道的波形,配置第2个参数为JScope_i2i2i2i2i2
  9.         上传6个通道的波形,配置第2个参数为JScope_i2i2i2i2i2i2
  10.         上传7个通道的波形,配置第2个参数为JScope_i2i2i2i2i2i2i2
  11.         上传8个通道的波形,配置第2个参数为JScope_i2i2i2i2i2i2i2i2
  12.     */   
  13.     SEGGER_RTT_ConfigUpBuffer(1, "JScope_i2", buf, 20480, SEGGER_RTT_MODE_NO_BLOCK_SKIP);
复制代码

使用函数SEGGER_RTT_Write上传数据时,要跟配置的通道数匹配,比如配置的三个通道,就需要调用三次函数:

  1. SEGGER_RTT_Write(1, &(g_tAD7606.sNowAdc[0]), 2);
  2. SEGGER_RTT_Write(1, &(g_tAD7606.sNowAdc[1]), 2);   
  3. SEGGER_RTT_Write(1, &(g_tAD7606.sNowAdc[2]), 2);
复制代码

多路效果:

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


76.8.3 J-Scope带宽问题
普通的JLINK时钟速度8 - 12MHz时, J-Scope的速度基本可以达到500KB/S(注意,单位是字节)AD7606的最高采样率是200Ksps,16bit,那么一路采集就有400KB/S的速速,所以要根据设置的采样率设置要显示的J-Scope通道数,如果超出了最高通信速度,波形显示会混乱。

       200Ksps时,实时显示1路

       100Ksps时,实时显示2路

       50Ksps时, 实时显示4路

       25Ksps时, 实时显示8路

实际速度以底栏的展示为准,如果与设置的速度差异较大,说明传输异常了。

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


76.9 AD7606驱动移植和使用
AD7606移植步骤如下:

  第1步:复制bsp_fmc_ad7606.c和bsp_fmc_ad7606.h到自己的工程目录,并添加到工程里面。
  第2步:根据使用的CONVST引脚,BUSY引脚,过采样引脚,量程控制引脚,复位引脚,修改bsp_fmc_ad7606.c开头的宏定义。
这里要特别注意过采样引脚,量程控制引脚和复位引脚是采用的扩展IO,需要大家根据自己的情况修改。

  1. /* CONVST 启动ADC转换的GPIO = PC6 */
  2. #define CONVST_RCC_GPIO_CLK_ENABLE    __HAL_RCC_GPIOC_CLK_ENABLE
  3. #define CONVST_TIM8_CLK_DISABLE     __HAL_RCC_TIM8_CLK_DISABLE
  4. #define CONVST_GPIO        GPIOC
  5. #define CONVST_PIN        GPIO_PIN_6
  6. #define CONVST_TIMX        TIM8
  7. #define CONVST_TIMCH    1

  8. /* BUSY 转换完毕信号 = PE5 */
  9. #define BUSY_RCC_GPIO_CLK_ENABLE __HAL_RCC_GPIOE_CLK_ENABLE
  10. #define BUSY_GPIO        GPIOE
  11. #define BUSY_PIN        GPIO_PIN_5
  12. #define BUSY_IRQn        EXTI9_5_IRQn
  13. #define BUSY_IRQHandler    EXTI9_5_IRQHandler

  14. /* 设置过采样的IO, 在扩展的74HC574上 */
  15. #define OS0_1()        HC574_SetPin(AD7606_OS0, 1)
  16. #define OS0_0()        HC574_SetPin(AD7606_OS0, 0)
  17. #define OS1_1()        HC574_SetPin(AD7606_OS1, 1)
  18. #define OS1_0()        HC574_SetPin(AD7606_OS1, 0)
  19. #define OS2_1()        HC574_SetPin(AD7606_OS2, 1)
  20. #define OS2_0()        HC574_SetPin(AD7606_OS2, 0)

  21. /* 启动AD转换的GPIO : PC6 */
  22. #define CONVST_1()        CONVST_GPIO->BSRR = CONVST_PIN
  23. #define CONVST_0()        CONVST_GPIO->BSRR = ((uint32_t)CONVST_PIN << 16U)

  24. /* 设置输入量程的GPIO, 在扩展的74HC574上 */
  25. #define RANGE_1()    HC574_SetPin(AD7606_RANGE, 1)
  26. #define RANGE_0()    HC574_SetPin(AD7606_RANGE, 0)

  27. /* AD7606复位口线, 在扩展的74HC574上 */
  28. #define RESET_1()    HC574_SetPin(AD7606_RESET, 1)
  29. #define RESET_0()    HC574_SetPin(AD7606_RESET, 0)
复制代码

  第3步:根据具体用到的FMC引脚,修改函数AD7606_CtrlLinesConfig里面做的IO配置。
  第4步:根据使用的FMC BANK,修改函数AD7606_FSMCConfig里面的BANK配置,这点非常容易疏忽。
  第5步:注意MPU配置,详情见本章77.7.5小节。
  第6步:初始化AD7606。
bsp_InitAD7606();  /* 配置AD7606所用的GPIO */
  第7步:AD7606驱动主要用到HAL库的FMC驱动文件,简单省事些可以添加所有HAL库C源文件进来。
  第8步:应用方法看本章节配套例子即可。


76.10          实验例程设计框架
通过程序设计框架,让大家先对配套例程有一个全面的认识,然后再理解细节,本次实验例程的设计框架如下:

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


  第1阶段,上电启动阶段:

这部分在第14章进行了详细说明。
  第2阶段,进入main函数:

  第1部分,硬件初始化,主要是MPU,Cache,HAL库,系统时钟,滴答定时器和LED。
  第2部分,应用程序设计部分,测试AD7606的两种采集方案。
76.11          实验例程说明(MDK)
配套例子:

V7-056_AD7606的FMC总线驱动方式实现(8通道同步采样, 16bit, 正负10V)

实验目的:

学习AD7606的FMC驱动方式实现。
重要提示:

板子上电后,默认是软件定时采集,0.5秒一次,适合串口展示数据。
如果需要使用J-Scope实时展示采集的波形效果,需要按下K2按键切换到FIFO模式。
如果使用的JLINK速度不够快,导致J-Scope无法最高速度实时上传,可以使用摇杆上下键设置过采样来降低上传速度。
默认情况下,程序仅上传了AD7606通道1采集的数据。
串口数据展示推荐使用SecureCRT,因为数据展示做了特别处理,方便采集数据在串口软件同一个位置不断刷新。
实验内容:

1、AD7606的FMC驱动做了两种采集方式

(1)软件定时获取方式,适合低速查询获取。

(2)FIFO工作模式,适合8路实时采集,支持最高采样率200Ksps。

2、数据展示方式:

(1)软件查询方式,数据通过串口打印输出。

(2)FIFO工作模式,数据通过J-Scope实时输出。

(3)J-Scope的实时输出方法请看V7板子用户手册对应的AD7606章节。

3、将模拟输入接地时,采样值是0左右。

4、模拟输入端悬空时,采样值在某个范围浮动(这是正常的,这是AD7606内部输入电阻导致的浮动电压)。

5、出厂的AD7606模块缺省是8080 并行接口。如果用SPI接口模式,需要修改 R1 R2电阻配置。

6、配置CVA CVB 引脚为PWM输出模式,周期设置为需要的采样频率,之后MCU将产生周期非常稳定的AD转换信号。

实验操作:

启动一个自动重装软件定时器,每100ms翻转一次LED2。
K1键       : 切换量程(5V或10V)。
K2键       : 进入FIFO工作模式。
K3键       : 进入软件定时采集模式。
摇杆上下键 : 调节过采样参数。
上电后串口打印的信息:

波特率 115200,数据位 8,奇偶校验位无,停止位 1。

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


J-Scope波形效果:

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


模块插入位置:

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


程序设计:

  系统栈大小分配:

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


  RAM空间用的DTCM:

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


  硬件外设初始化

硬件外设的初始化是在 bsp.c 文件实现:

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: bsp_Init
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. void bsp_Init(void)
  10. {
  11.     /* 配置MPU */
  12.     MPU_Config();

  13.     /* 使能L1 Cache */
  14.     CPU_CACHE_Enable();

  15.     /*
  16.        STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:
  17.        - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
  18.        - 设置NVIV优先级分组为4。
  19.      */
  20.     HAL_Init();

  21.     /*
  22.        配置系统时钟到400MHz
  23.        - 切换使用HSE。
  24.        - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
  25.     */
  26.     SystemClock_Config();

  27.     /*
  28.        Event Recorder:
  29.        - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
  30.        - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第xx章
  31.     */   
  32. #if Enable_EventRecorder == 1  
  33.     /* 初始化EventRecorder并开启 */
  34.     EventRecorderInitialize(EventRecordAll, 1U);
  35.     EventRecorderStart();
  36. #endif

  37. bsp_InitDWT();      /* 初始化DWT时钟周期计数器 */      
  38.     bsp_InitKey();         /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
  39.     bsp_InitTimer();       /* 初始化滴答定时器 */
  40.     bsp_InitLPUart();     /* 初始化串口 */
  41.     bsp_InitExtIO();     /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */   
  42.     bsp_InitLed();         /* 初始化LED */   
  43. bsp_InitExtSDRAM(); /* 初始化SDRAM */

  44.     /* 针对不同的应用程序,添加需要的底层驱动模块初始化函数 */   
  45.     bsp_InitAD7606();    /* 配置AD7606所用的GPIO */
  46. }
复制代码



  MPU配置和Cache配置:

数据Cache和指令Cache都开启。配置了AXI SRAM区(本例子未用到AXI SRAM)和FMC的扩展IO区。

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: MPU_Config
  4. *    功能说明: 配置MPU
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void MPU_Config( void )
  10. {
  11.     MPU_Region_InitTypeDef MPU_InitStruct;

  12.     /* 禁止 MPU */
  13.     HAL_MPU_Disable();

  14.     /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
  15.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
  16.     MPU_InitStruct.BaseAddress      = 0x24000000;
  17.     MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;
  18.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  19.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
  20.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
  21.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
  22.     MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
  23.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
  24.     MPU_InitStruct.SubRegionDisable = 0x00;
  25.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;

  26.     HAL_MPU_ConfigRegion(&MPU_InitStruct);


  27.     /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
  28.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
  29.     MPU_InitStruct.BaseAddress      = 0x60000000;
  30.     MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;   
  31.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  32.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
  33.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;   
  34.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
  35.     MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
  36.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
  37.     MPU_InitStruct.SubRegionDisable = 0x00;
  38.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;

  39.     HAL_MPU_ConfigRegion(&MPU_InitStruct);

  40.     /*使能 MPU */
  41.     HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
  42. }

  43. /*
  44. *********************************************************************************************************
  45. *    函 数 名: CPU_CACHE_Enable
  46. *    功能说明: 使能L1 Cache
  47. *    形    参: 无
  48. *    返 回 值: 无
  49. *********************************************************************************************************
  50. */
  51. static void CPU_CACHE_Enable(void)
  52. {
  53.     /* 使能 I-Cache */
  54.     SCB_EnableICache();

  55.     /* 使能 D-Cache */
  56.     SCB_EnableDCache();
  57. }
复制代码


  每10ms调用一次按键处理:

按键处理是在滴答定时器中断里面实现,每10ms执行一次检测。

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: bsp_RunPer10ms
  4. *    功能说明: 该函数每隔10ms被Systick中断调用1次。详见 bsp_timer.c的定时中断服务程序。一些处理时间要求
  5. *              不严格的任务可以放在此函数。比如:按键扫描、蜂鸣器鸣叫控制等。
  6. *    形    参: 无
  7. *    返 回 值: 无
  8. *********************************************************************************************************
  9. */
  10. void bsp_RunPer10ms(void)
  11. {
  12.     bsp_KeyScan10ms();
  13. }

复制代码

  主功能:

主程序实现如下操作:

  启动一个自动重装软件定时器,每100ms翻转一次LED2。
  K1键       : 切换量程(5V或10V)。
  K2键       : 进入FIFO工作模式。
  K3键       : 进入软件定时采集模式。
  摇杆上下键 : 调节过采样参数。
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: main
  4. *    功能说明: c程序入口
  5. *    形    参: 无
  6. *    返 回 值: 错误代码(无需处理)
  7. *********************************************************************************************************
  8. */
  9. int main(void)
  10. {
  11.     bsp_Init();        /* 硬件初始化 */

  12.     PrintfLogo();    /* 打印例程名称和版本等信息 */

  13.     DemoFmcAD7606(); /* AD7606测试 */
  14. }

  15. /*
  16. *********************************************************************************************************
  17. *    函 数 名: DemoFmcAD7606
  18. *    功能说明: AD7606测试
  19. *    形    参: 无
  20. *    返 回 值: 无
  21. *********************************************************************************************************
  22. */
  23. void DemoFmcAD7606(void)
  24. {
  25.     uint8_t ucKeyCode;
  26.     uint8_t ucRefresh = 0;
  27.     uint8_t ucFifoMode;

  28.     sfDispMenu();        /* 打印命令提示 */

  29.     ucFifoMode = 0;         /* AD7606进入普通工作模式 */
  30.     ucRefresh = 0;        /* 数据在串口刷新的标志 */

  31.     AD7606_SetOS(AD_OS_NO);        /* 无过采样 */
  32.     AD7606_SetInputRange(1);    /* 0表示输入量程为正负5V, 1表示正负10V */
  33.     AD7606_StartConvst();        /* 启动1次转换 */

  34.     bsp_StartAutoTimer(0, 500);    /* 启动1个500ms的自动重装的定时器 */
  35.     bsp_StartAutoTimer(3, 200);    /* 启动1个200ms的自动重装的定时器 */

  36.     /*
  37.         配置通道1,上行配置
  38.         默认情况下,J-Scope仅显示1个通道。
  39.         上传1个通道的波形,配置第2个参数为JScope_i2
  40.         上传2个通道的波形,配置第2个参数为JScope_i2i2
  41.         上传3个通道的波形,配置第2个参数为JScope_i2i2i2
  42.         上传4个通道的波形,配置第2个参数为JScope_i2i2i2i2
  43.         上传5个通道的波形,配置第2个参数为JScope_i2i2i2i2i2
  44.         上传6个通道的波形,配置第2个参数为JScope_i2i2i2i2i2i2
  45.         上传7个通道的波形,配置第2个参数为JScope_i2i2i2i2i2i2i2
  46.         上传8个通道的波形,配置第2个参数为JScope_i2i2i2i2i2i2i2i2
  47.     */   
  48.     SEGGER_RTT_ConfigUpBuffer(1, "JScope_i2", buf, 20480, SEGGER_RTT_MODE_NO_BLOCK_SKIP);

  49.     while(1)
  50.     {
  51.         bsp_Idle();        /* 这个函数在bsp.c文件。用户可以修改这个函数实现CPU休眠和喂狗 */

  52.         /* 判断定时器超时时间 */
  53.         if (bsp_CheckTimer(3))   
  54.         {
  55.             /* 每隔100ms 进来一次 */  
  56.             bsp_LedToggle(2);
  57.         }

  58.         if (ucRefresh == 1)
  59.         {
  60.             ucRefresh = 0;

  61.             /* 处理数据 */
  62.             AD7606_Mak();

  63.             /* 打印ADC采样结果 */
  64.             AD7606_Disp();        
  65.         }

  66.         if (ucFifoMode == 0)    /* AD7606 普通工作模式 */
  67.         {
  68.             if (bsp_CheckTimer(0))
  69.             {
  70.                 /* 每隔500ms 进来一次. 由软件启动转换 */
  71.                 AD7606_ReadNowAdc();        /* 读取采样结果 */
  72.                 AD7606_StartConvst();        /* 启动下次转换 */

  73.                 ucRefresh = 1;    /* 刷新显示 */
  74.             }
  75.         }
  76.         else
  77.         {
  78.             /*
  79.                 在FIFO工作模式,bsp_AD7606自动进行采集,数据存储在FIFO缓冲区。
  80.                 结果可以通过下面的函数读取:
  81.                 uint8_t AD7606_ReadFifo(uint16_t *_usReadAdc)

  82.                 大家可以将数据保存到SD卡,或者保存到外部SRAM。

  83.                 本例未对FIFO中的数据进行处理,进行打印当前最新的样本值和J-Scope的实时输出展示。

  84.                 如果主程序不能及时读取FIFO数据,那么 AD7606_FifoFull() 将返回真。

  85.                 8通道200K采样时,数据传输率 = 200 000 * 2 * 8 = 3.2MB/S
  86.             */

  87.             if (bsp_CheckTimer(0))
  88.             {
  89.                 ucRefresh = 1;    /* 刷新显示 */
  90.             }
  91.         }

  92.         /* 按键检测由后台systick中断服务程序实现,我们只需要调用bsp_GetKey读取键值即可。这个函数不会
  93.         等待按键按下,这样我们可以在while循环内做其他的事情 */
  94.         ucKeyCode = bsp_GetKey();    /* 读取键值, 无键按下时返回 KEY_NONE = 0 */
  95.         if (ucKeyCode != KEY_NONE)
  96.         {

  97.             switch (ucKeyCode)
  98.             {
  99.                 case KEY_DOWN_K1:            /* K1键按下 切换量程 */
  100.                     if (g_tAD7606.ucRange == 0)
  101.                     {
  102.                         AD7606_SetInputRange(1);
  103.                     }
  104.                     else
  105.                     {
  106.                         AD7606_SetInputRange(0);
  107.                     }
  108.                     ucRefresh = 1;
  109.                     break;

  110.                 case KEY_DOWN_K2:                        /* K2键按下 */
  111.                     ucFifoMode = 1;                      /* AD7606进入FIFO工作模式 */
  112.                     g_tAD7606.ucOS = 1;                    /* 无过采样 */
  113.                     AD7606_StartRecord(AD7606_SampleFreq[g_tAD7606.ucOS]);    /* 启动100kHz采样速率 */
  114.                     AD7606_SetOS(g_tAD7606.ucOS);       /* 设置无过采样 */
  115.                     printf("\33[%dA", (int)1);          /* 光标上移n行 */   
  116.                     printf("AD7606进入FIFO工作模式 (200KHz 8通道同步采集)...\r\n");
  117.                     break;

  118.                 case KEY_DOWN_K3:            /* K3键按下 */
  119.                     AD7606_StopRecord();    /* 停止记录 */
  120.                     ucFifoMode = 0;         /* AD7606进入普通工作模式 */
  121.                     g_tAD7606.ucOS = 0;     /* 无过采样 */
  122.                     AD7606_SetOS(g_tAD7606.ucOS);
  123.                     printf("\33[%dA", (int)1);  /* 光标上移n行 */
  124.                     printf("AD7606进入普通工作模式(0.5s定时8通道同步采集)...\r\n");
  125.                     break;

  126.                 case JOY_DOWN_U:            /* 摇杆UP键按下 */
  127.                     if (g_tAD7606.ucOS < 6)
  128.                     {
  129.                         g_tAD7606.ucOS++;
  130.                     }

  131.                     AD7606_SetOS(g_tAD7606.ucOS);

  132.                     /* 如果是FIFO模式,*/
  133.                     if(ucFifoMode == 1)
  134.                     {
  135.                             /* 启动当前过采样下最高速度 */
  136.                         AD7606_StartRecord(AD7606_SampleFreq[g_tAD7606.ucOS]);   
  137.                     }

  138.                     ucRefresh = 1;
  139.                     break;

  140.                 case JOY_DOWN_D:            /* 摇杆DOWN键按下 */
  141.                     if (g_tAD7606.ucOS > 0)
  142.                     {
  143.                         g_tAD7606.ucOS--;
  144.                     }
  145.                     AD7606_SetOS(g_tAD7606.ucOS);
  146.                     ucRefresh = 1;

  147.                     /* 如果是FIFO模式,*/
  148.                     if(ucFifoMode == 1)
  149.                     {
  150. /* 启动当前过采样下最高速度 */
  151.                         AD7606_StartRecord(AD7606_SampleFreq[g_tAD7606.ucOS]);   
  152.                     }
  153.                     break;

  154.                 default:
  155.                     /* 其他的键值不处理 */
  156.                     break;
  157.             }
  158.         }
  159.     }
  160. }
复制代码


76.12          实验例程说明(IAR)
配套例子:

V7-056_AD7606的FMC总线驱动方式实现(8通道同步采样, 16bit, 正负10V)

实验目的:

学习AD7606的FMC驱动方式实现。
重要提示:

板子上电后,默认是软件定时采集,0.5秒一次,适合串口展示数据。
如果需要使用J-Scope实时展示采集的波形效果,需要按下K2按键切换到FIFO模式。
如果使用的JLINK速度不够快,导致J-Scope无法最高速度实时上传,可以使用摇杆上下键设置过采样来降低上传速度。
默认情况下,程序仅上传了AD7606通道1采集的数据。
串口数据展示推荐使用SecureCRT,因为数据展示做了特别处理,方便采集数据在串口软件同一个位置不断刷新。
实验内容:

1、AD7606的FMC驱动做了两种采集方式

(1)软件定时获取方式,适合低速查询获取。

(2)FIFO工作模式,适合8路实时采集,支持最高采样率200Ksps。

2、数据展示方式:

(1)软件查询方式,数据通过串口打印输出。

(2)FIFO工作模式,数据通过J-Scope实时输出。

(3)J-Scope的实时输出方法请看V7板子用户手册对应的AD7606章节。

3、将模拟输入接地时,采样值是0左右。

4、模拟输入端悬空时,采样值在某个范围浮动(这是正常的,这是AD7606内部输入电阻导致的浮动电压)。

5、出厂的AD7606模块缺省是8080 并行接口。如果用SPI接口模式,需要修改 R1 R2电阻配置。

6、配置CVA CVB 引脚为PWM输出模式,周期设置为需要的采样频率,之后MCU将产生周期非常稳定的AD转换信号。

实验操作:

启动一个自动重装软件定时器,每100ms翻转一次LED2。
K1键       : 切换量程(5V或10V)。
K2键       : 进入FIFO工作模式。
K3键       : 进入软件定时采集模式。
摇杆上下键 : 调节过采样参数。
上电后串口打印的信息:

波特率 115200,数据位 8,奇偶校验位无,停止位 1。

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


J-Scope波形效果:

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


模块插入位置:

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


程序设计:

  系统栈大小分配:

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


  RAM空间用的DTCM:

aHR0cHM6Ly9pbWcyMDIwLmNuYmxvZ3MuY29tL2Jsb2cvMTM3OTEwNy8yMDIwMDUvMTM3OTEwNy0yMDIw.png


  硬件外设初始化

硬件外设的初始化是在 bsp.c 文件实现:

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: bsp_Init
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. void bsp_Init(void)
  10. {
  11.     /* 配置MPU */
  12.     MPU_Config();

  13.     /* 使能L1 Cache */
  14.     CPU_CACHE_Enable();

  15.     /*
  16.        STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:
  17.        - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
  18.        - 设置NVIV优先级分组为4。
  19.      */
  20.     HAL_Init();

  21.     /*
  22.        配置系统时钟到400MHz
  23.        - 切换使用HSE。
  24.        - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
  25.     */
  26.     SystemClock_Config();

  27.     /*
  28.        Event Recorder:
  29.        - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
  30.        - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第xx章
  31.     */   
  32. #if Enable_EventRecorder == 1  
  33.     /* 初始化EventRecorder并开启 */
  34.     EventRecorderInitialize(EventRecordAll, 1U);
  35.     EventRecorderStart();
  36. #endif

  37. bsp_InitDWT();      /* 初始化DWT时钟周期计数器 */      
  38.     bsp_InitKey();         /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
  39.     bsp_InitTimer();       /* 初始化滴答定时器 */
  40.     bsp_InitLPUart();     /* 初始化串口 */
  41.     bsp_InitExtIO();     /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */   
  42.     bsp_InitLed();         /* 初始化LED */   
  43. bsp_InitExtSDRAM(); /* 初始化SDRAM */

  44.     /* 针对不同的应用程序,添加需要的底层驱动模块初始化函数 */   
  45.     bsp_InitAD7606();    /* 配置AD7606所用的GPIO */
  46. }

复制代码

  MPU配置和Cache配置:

数据Cache和指令Cache都开启。配置了AXI SRAM区(本例子未用到AXI SRAM)和FMC的扩展IO区。

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: MPU_Config
  4. *    功能说明: 配置MPU
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void MPU_Config( void )
  10. {
  11.     MPU_Region_InitTypeDef MPU_InitStruct;

  12.     /* 禁止 MPU */
  13.     HAL_MPU_Disable();

  14.     /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
  15.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
  16.     MPU_InitStruct.BaseAddress      = 0x24000000;
  17.     MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;
  18.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  19.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
  20.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
  21.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
  22.     MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
  23.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
  24.     MPU_InitStruct.SubRegionDisable = 0x00;
  25.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;

  26.     HAL_MPU_ConfigRegion(&MPU_InitStruct);


  27.     /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
  28.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
  29.     MPU_InitStruct.BaseAddress      = 0x60000000;
  30.     MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;   
  31.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  32.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
  33.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;   
  34.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
  35.     MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
  36.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
  37.     MPU_InitStruct.SubRegionDisable = 0x00;
  38.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;

  39.     HAL_MPU_ConfigRegion(&MPU_InitStruct);

  40.     /*使能 MPU */
  41.     HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
  42. }

  43. /*
  44. *********************************************************************************************************
  45. *    函 数 名: CPU_CACHE_Enable
  46. *    功能说明: 使能L1 Cache
  47. *    形    参: 无
  48. *    返 回 值: 无
  49. *********************************************************************************************************
  50. */
  51. static void CPU_CACHE_Enable(void)
  52. {
  53.     /* 使能 I-Cache */
  54.     SCB_EnableICache();

  55.     /* 使能 D-Cache */
  56.     SCB_EnableDCache();
  57. }
复制代码

  每10ms调用一次按键处理:

按键处理是在滴答定时器中断里面实现,每10ms执行一次检测。

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: bsp_RunPer10ms
  4. *    功能说明: 该函数每隔10ms被Systick中断调用1次。详见 bsp_timer.c的定时中断服务程序。一些处理时间要求
  5. *              不严格的任务可以放在此函数。比如:按键扫描、蜂鸣器鸣叫控制等。
  6. *    形    参: 无
  7. *    返 回 值: 无
  8. *********************************************************************************************************
  9. */
  10. void bsp_RunPer10ms(void)
  11. {
  12.     bsp_KeyScan10ms();
  13. }

复制代码

  主功能:

主程序实现如下操作:

  启动一个自动重装软件定时器,每100ms翻转一次LED2。
  K1键       : 切换量程(5V或10V)。
  K2键       : 进入FIFO工作模式。
  K3键       : 进入软件定时采集模式。
  摇杆上下键 : 调节过采样参数。
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: main
  4. *    功能说明: c程序入口
  5. *    形    参: 无
  6. *    返 回 值: 错误代码(无需处理)
  7. *********************************************************************************************************
  8. */
  9. int main(void)
  10. {
  11.     bsp_Init();        /* 硬件初始化 */

  12.     PrintfLogo();    /* 打印例程名称和版本等信息 */

  13.     DemoFmcAD7606(); /* AD7606测试 */
  14. }

  15. /*
  16. *********************************************************************************************************
  17. *    函 数 名: DemoFmcAD7606
  18. *    功能说明: AD7606测试
  19. *    形    参: 无
  20. *    返 回 值: 无
  21. *********************************************************************************************************
  22. */
  23. void DemoFmcAD7606(void)
  24. {
  25.     uint8_t ucKeyCode;
  26.     uint8_t ucRefresh = 0;
  27.     uint8_t ucFifoMode;

  28.     sfDispMenu();        /* 打印命令提示 */

  29.     ucFifoMode = 0;         /* AD7606进入普通工作模式 */
  30.     ucRefresh = 0;        /* 数据在串口刷新的标志 */

  31.     AD7606_SetOS(AD_OS_NO);        /* 无过采样 */
  32.     AD7606_SetInputRange(1);    /* 0表示输入量程为正负5V, 1表示正负10V */
  33.     AD7606_StartConvst();        /* 启动1次转换 */

  34.     bsp_StartAutoTimer(0, 500);    /* 启动1个500ms的自动重装的定时器 */
  35.     bsp_StartAutoTimer(3, 200);    /* 启动1个200ms的自动重装的定时器 */

  36.     /*
  37.         配置通道1,上行配置
  38.         默认情况下,J-Scope仅显示1个通道。
  39.         上传1个通道的波形,配置第2个参数为JScope_i2
  40.         上传2个通道的波形,配置第2个参数为JScope_i2i2
  41.         上传3个通道的波形,配置第2个参数为JScope_i2i2i2
  42.         上传4个通道的波形,配置第2个参数为JScope_i2i2i2i2
  43.         上传5个通道的波形,配置第2个参数为JScope_i2i2i2i2i2
  44.         上传6个通道的波形,配置第2个参数为JScope_i2i2i2i2i2i2
  45.         上传7个通道的波形,配置第2个参数为JScope_i2i2i2i2i2i2i2
  46.         上传8个通道的波形,配置第2个参数为JScope_i2i2i2i2i2i2i2i2
  47.     */   
  48.     SEGGER_RTT_ConfigUpBuffer(1, "JScope_i2", buf, 20480, SEGGER_RTT_MODE_NO_BLOCK_SKIP);

  49.     while(1)
  50.     {
  51.         bsp_Idle();        /* 这个函数在bsp.c文件。用户可以修改这个函数实现CPU休眠和喂狗 */

  52.         /* 判断定时器超时时间 */
  53.         if (bsp_CheckTimer(3))   
  54.         {
  55.             /* 每隔100ms 进来一次 */  
  56.             bsp_LedToggle(2);
  57.         }

  58.         if (ucRefresh == 1)
  59.         {
  60.             ucRefresh = 0;

  61.             /* 处理数据 */
  62.             AD7606_Mak();

  63.             /* 打印ADC采样结果 */
  64.             AD7606_Disp();        
  65.         }

  66.         if (ucFifoMode == 0)    /* AD7606 普通工作模式 */
  67.         {
  68.             if (bsp_CheckTimer(0))
  69.             {
  70.                 /* 每隔500ms 进来一次. 由软件启动转换 */
  71.                 AD7606_ReadNowAdc();        /* 读取采样结果 */
  72.                 AD7606_StartConvst();        /* 启动下次转换 */

  73.                 ucRefresh = 1;    /* 刷新显示 */
  74.             }
  75.         }
  76.         else
  77.         {
  78.             /*
  79.                 在FIFO工作模式,bsp_AD7606自动进行采集,数据存储在FIFO缓冲区。
  80.                 结果可以通过下面的函数读取:
  81.                 uint8_t AD7606_ReadFifo(uint16_t *_usReadAdc)

  82.                 大家可以将数据保存到SD卡,或者保存到外部SRAM。

  83.                 本例未对FIFO中的数据进行处理,进行打印当前最新的样本值和J-Scope的实时输出展示。

  84.                 如果主程序不能及时读取FIFO数据,那么 AD7606_FifoFull() 将返回真。

  85.                 8通道200K采样时,数据传输率 = 200 000 * 2 * 8 = 3.2MB/S
  86.             */

  87.             if (bsp_CheckTimer(0))
  88.             {
  89.                 ucRefresh = 1;    /* 刷新显示 */
  90.             }
  91.         }

  92.         /* 按键检测由后台systick中断服务程序实现,我们只需要调用bsp_GetKey读取键值即可。这个函数不会
  93.         等待按键按下,这样我们可以在while循环内做其他的事情 */
  94.         ucKeyCode = bsp_GetKey();    /* 读取键值, 无键按下时返回 KEY_NONE = 0 */
  95.         if (ucKeyCode != KEY_NONE)
  96.         {

  97.             switch (ucKeyCode)
  98.             {
  99.                 case KEY_DOWN_K1:            /* K1键按下 切换量程 */
  100.                     if (g_tAD7606.ucRange == 0)
  101.                     {
  102.                         AD7606_SetInputRange(1);
  103.                     }
  104.                     else
  105.                     {
  106.                         AD7606_SetInputRange(0);
  107.                     }
  108.                     ucRefresh = 1;
  109.                     break;

  110.                 case KEY_DOWN_K2:                        /* K2键按下 */
  111.                     ucFifoMode = 1;                      /* AD7606进入FIFO工作模式 */
  112.                     g_tAD7606.ucOS = 1;                    /* 无过采样 */
  113.                     AD7606_StartRecord(AD7606_SampleFreq[g_tAD7606.ucOS]);    /* 启动100kHz采样速率 */
  114.                     AD7606_SetOS(g_tAD7606.ucOS);       /* 设置无过采样 */
  115.                     printf("\33[%dA", (int)1);          /* 光标上移n行 */   
  116.                     printf("AD7606进入FIFO工作模式 (200KHz 8通道同步采集)...\r\n");
  117.                     break;

  118.                 case KEY_DOWN_K3:            /* K3键按下 */
  119.                     AD7606_StopRecord();    /* 停止记录 */
  120.                     ucFifoMode = 0;         /* AD7606进入普通工作模式 */
  121.                     g_tAD7606.ucOS = 0;     /* 无过采样 */
  122.                     AD7606_SetOS(g_tAD7606.ucOS);
  123.                     printf("\33[%dA", (int)1);  /* 光标上移n行 */
  124.                     printf("AD7606进入普通工作模式(0.5s定时8通道同步采集)...\r\n");
  125.                     break;

  126.                 case JOY_DOWN_U:            /* 摇杆UP键按下 */
  127.                     if (g_tAD7606.ucOS < 6)
  128.                     {
  129.                         g_tAD7606.ucOS++;
  130.                     }

  131.                     AD7606_SetOS(g_tAD7606.ucOS);

  132.                     /* 如果是FIFO模式,*/
  133.                     if(ucFifoMode == 1)
  134.                     {
  135.                             /* 启动当前过采样下最高速度 */
  136.                         AD7606_StartRecord(AD7606_SampleFreq[g_tAD7606.ucOS]);   
  137.                     }

  138.                     ucRefresh = 1;
  139.                     break;

  140.                 case JOY_DOWN_D:            /* 摇杆DOWN键按下 */
  141.                     if (g_tAD7606.ucOS > 0)
  142.                     {
  143.                         g_tAD7606.ucOS--;
  144.                     }
  145.                     AD7606_SetOS(g_tAD7606.ucOS);
  146.                     ucRefresh = 1;

  147.                     /* 如果是FIFO模式,*/
  148.                     if(ucFifoMode == 1)
  149.                     {
  150. /* 启动当前过采样下最高速度 */
  151.                         AD7606_StartRecord(AD7606_SampleFreq[g_tAD7606.ucOS]);   
  152.                     }
  153.                     break;

  154.                 default:
  155.                     /* 其他的键值不处理 */
  156.                     break;
  157.             }
  158.         }
  159.     }
复制代码



76.13   总结
本章节涉及到的知识点非常多,实战性较强,需要大家稍花点精力去研究。
————————————————
版权声明:本文为CSDN博主「Simon223」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Simon223/article/details/105995329


收藏 1 评论1 发布时间:2021-11-4 00:51

举报

1个回答
feng过不留痕 回答时间:2024-2-27 13:02:54

采样率能达到多少?

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版