发新帖我要提问
12
返回列表
打印
[STM32H7]

STM32H7的FMC总线应用之驱动AD7606(8通道同步采样, 16bit, 正负...

[复制链接]
楼主: 磨砂
手机看帖
扫描二维码
随时随地手机跟帖
21
磨砂|  楼主 | 2021-8-1 13:09 | 只看该作者 |只看大图 回帖奖励 |倒序浏览
6.9 第9步,AD7606过采样设置

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

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

        case AD_OS_X4:
            OS2_0();
            OS1_1();
            OS0_0();
            break;

        case AD_OS_X8:
            OS2_0();
            OS1_1();
            OS0_1();
            break;

        case AD_OS_X16:
            OS2_1();
            OS1_0();
            OS0_0();
            break;

        case AD_OS_X32:
            OS2_1();
            OS1_0();
            OS0_1();
            break;

        case AD_OS_X64:
            OS2_1();
            OS1_1();
            OS0_0();
            break;

        case AD_OS_NO:
        default:
            g_tAD7606.ucOS = AD_OS_NO;
            OS2_0();
            OS1_0();
            OS0_0();
            break;
    }
}


使用特权

评论回复
22
磨砂|  楼主 | 2021-8-1 13:11 | 只看该作者
6.10   第10步,AD7606量程设置

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

/*
*********************************************************************************************************
*    函 数 名: AD7606_SetInputRange
*    功能说明: 配置AD7606模拟信号输入量程。
*    形    参: _ucRange : 0 表示正负5V   1表示正负10V
*    返 回 值: 无
*********************************************************************************************************
*/
void AD7606_SetInputRange(uint8_t _ucRange)
{
    if (_ucRange == 0)
    {
        g_tAD7606.ucRange = 0;
        RANGE_0();    /* 设置为正负5V */
    }
    else
    {
        g_tAD7606.ucRange = 1;
        RANGE_1();    /* 设置为正负10V */
    }
}


使用特权

评论回复
23
磨砂|  楼主 | 2021-8-1 13:12 | 只看该作者
6.11   第11步,操作数据位宽注意事项

在bsp_fmc_ad7606.c文件开头有个宏定义

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

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


使用特权

评论回复
24
磨砂|  楼主 | 2021-8-1 13:15 | 只看该作者
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


7.1 函数bsp_InitAD7606
函数原型:

void bsp_InitAD7606(void)

函数描述:

主要用于AD7606的初始化。

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倍过采样。


7.3 函数AD7606_SetInputRange
函数原型:

void AD7606_SetInputRange(uint8_t _ucRange)

函数描述:

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

函数参数:

  •   第1个参数为0 表示正负5V ,1表示正负10V。


7.4 函数AD7606_Reset
函数原型:

void AD7606_Reset(void)

函数描述:

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

7.5 函数AD7606_StartConvst
函数原型:

void AD7606_StartConvst(void)

函数描述:

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

7.6 函数AD7606_ReadNowAdc
函数原型:

void AD7606_ReadNowAdc(void)

函数描述:

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

7.7 函数AD7606_EnterAutoMode
函数原型:

void AD7606_EnterAutoMode(uint32_t _ulFreq)

函数描述:

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

函数参数:

  •   第1个参数是采样频率,范围1-200KHz,单位Hz。


7.8 函数AD7606_StartRecord
函数原型:

void AD7606_StartRecord(uint32_t _ulFreq)

函数描述:

用于启动采集。

函数参数:

  •   第1个参数是采样频率,范围1-200KHz,单位Hz。


7.9 函数AD7606_StopRecord
函数原型:

void AD7606_StopRecord(void)

函数描述:

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


7.10   函数AD7606_FifoNewData
函数原型:

uint8_t AD7606_HasNewData(void)

函数描述:

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

函数参数:

  •   返回值,1 表示有,0表示暂无数据。


7.11   函数AD7606_ReadFifo
函数原型:

uint8_t AD7606_ReadFifo(uint16_t *_usReadAdc)

函数描述:

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

函数参数:

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


7.12   函数AD7606_FifoFull
函数原型:

uint8_t AD7606_FifoFull(void)

函数描述:

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

函数参数:

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



使用特权

评论回复
25
磨砂|  楼主 | 2021-8-1 13:16 | 只看该作者
8 J-Scope实时展示AD7606采集数据说明



这里有三点注意事项需要大家提前有个了解。另外,推荐使用MDK版工程做测试J-Scope,IAR版容易测试不正常。

8.1 J-Scope闪退问题解决办法

如下界面,不要点击选择按钮,闪退就是因为点击了这个选择按钮。



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



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

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


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

SEGGER_RTT_Write(1, &(g_tAD7606.sNowAdc[0]), 2);
SEGGER_RTT_Write(1, &(g_tAD7606.sNowAdc[1]), 2);   
SEGGER_RTT_Write(1, &(g_tAD7606.sNowAdc[2]), 2);


多路效果:




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路



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



使用特权

评论回复
26
磨砂|  楼主 | 2021-8-1 13:18 | 只看该作者
9 AD7606驱动移植和使用

AD7606移植步骤如下:

  •   第1步:复制bsp_fmc_ad7606.c和bsp_fmc_ad7606.h到自己的工程目录,并添加到工程里面。
  •   第2步:根据使用的CONVST引脚,BUSY引脚,过采样引脚,量程控制引脚,复位引脚,修改bsp_fmc_ad7606.c开头的宏定义。


这里要特别注意过采样引脚,量程控制引脚和复位引脚是采用的扩展IO,需要大家根据自己的情况修改。

/* CONVST 启动ADC转换的GPIO = PC6 */
#define CONVST_RCC_GPIO_CLK_ENABLE    __HAL_RCC_GPIOC_CLK_ENABLE
#define CONVST_TIM8_CLK_DISABLE     __HAL_RCC_TIM8_CLK_DISABLE
#define CONVST_GPIO        GPIOC
#define CONVST_PIN        GPIO_PIN_6
#define CONVST_TIMX        TIM8
#define CONVST_TIMCH    1

/* BUSY 转换完毕信号 = PE5 */
#define BUSY_RCC_GPIO_CLK_ENABLE __HAL_RCC_GPIOE_CLK_ENABLE
#define BUSY_GPIO        GPIOE
#define BUSY_PIN        GPIO_PIN_5
#define BUSY_IRQn        EXTI9_5_IRQn
#define BUSY_IRQHandler    EXTI9_5_IRQHandler

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

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

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

/* AD7606复位口线, 在扩展的74HC574上 */
#define RESET_1()    HC574_SetPin(AD7606_RESET, 1)
#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步:应用方法看本章节配套例子即可。



使用特权

评论回复
27
磨砂|  楼主 | 2021-8-1 13:19 | 只看该作者
10          实验例程设计框架
通过程序设计框架,让大家先对配套例程有一个全面的认识,然后再理解细节,本次实验例程的设计框架如下:



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

  • 这部分在第14章进行了详细说明。

  第2阶段,进入main函数:

  •   第1部分,硬件初始化,主要是MPU,Cache,HAL库,系统时钟,滴答定时器和LED。
  •   第2部分,应用程序设计部分,测试AD7606的两种采集方案。



使用特权

评论回复
28
磨砂|  楼主 | 2021-8-1 13:23 | 只看该作者
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。



J-Scope波形效果:



模块插入位置:



程序设计:

  系统栈大小分配:



  RAM空间用的DTCM:



  硬件外设初始化

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

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

    /* 使能L1 Cache */
    CPU_CACHE_Enable();

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

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

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

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

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


  MPU配置和Cache配置:

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

/*
*********************************************************************************************************
*    函 数 名: MPU_Config
*    功能说明: 配置MPU
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
static void MPU_Config( void )
{
    MPU_Region_InitTypeDef MPU_InitStruct;

    /* 禁止 MPU */
    HAL_MPU_Disable();

    /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
    MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    MPU_InitStruct.BaseAddress      = 0x24000000;
    MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;
    MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
    MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
    MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
    MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
    MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
    MPU_InitStruct.SubRegionDisable = 0x00;
    MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;

    HAL_MPU_ConfigRegion(&MPU_InitStruct);


    /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
    MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    MPU_InitStruct.BaseAddress      = 0x60000000;
    MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;   
    MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
    MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;   
    MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
    MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
    MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
    MPU_InitStruct.SubRegionDisable = 0x00;
    MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;

    HAL_MPU_ConfigRegion(&MPU_InitStruct);

    /*使能 MPU */
    HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}

/*
*********************************************************************************************************
*    函 数 名: CPU_CACHE_Enable
*    功能说明: 使能L1 Cache
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
static void CPU_CACHE_Enable(void)
{
    /* 使能 I-Cache */
    SCB_EnableICache();

    /* 使能 D-Cache */
    SCB_EnableDCache();
}


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

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

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


  主功能:

主程序实现如下操作:

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

/*
*********************************************************************************************************
*    函 数 名: main
*    功能说明: c程序入口
*    形    参: 无
*    返 回 值: 错误代码(无需处理)
*********************************************************************************************************
*/
int main(void)
{
    bsp_Init();        /* 硬件初始化 */

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

    DemoFmcAD7606(); /* AD7606测试 */
}

/*
*********************************************************************************************************
*    函 数 名: DemoFmcAD7606
*    功能说明: AD7606测试
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
void DemoFmcAD7606(void)
{
    uint8_t ucKeyCode;
    uint8_t ucRefresh = 0;
    uint8_t ucFifoMode;

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

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

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

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

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

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

        /* 判断定时器超时时间 */
        if (bsp_CheckTimer(3))   
        {
            /* 每隔100ms 进来一次 */  
            bsp_LedToggle(2);
        }

        if (ucRefresh == 1)
        {
            ucRefresh = 0;

            /* 处理数据 */
            AD7606_Mak();

            /* 打印ADC采样结果 */
            AD7606_Disp();        
        }

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

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

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

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

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

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

            if (bsp_CheckTimer(0))
            {
                ucRefresh = 1;    /* 刷新显示 */
            }
        }

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

            switch (ucKeyCode)
            {
                case KEY_DOWN_K1:            /* K1键按下 切换量程 */
                    if (g_tAD7606.ucRange == 0)
                    {
                        AD7606_SetInputRange(1);
                    }
                    else
                    {
                        AD7606_SetInputRange(0);
                    }
                    ucRefresh = 1;
                    break;

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

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

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

                    AD7606_SetOS(g_tAD7606.ucOS);

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

                    ucRefresh = 1;
                    break;

                case JOY_DOWN_D:            /* 摇杆DOWN键按下 */
                    if (g_tAD7606.ucOS > 0)
                    {
                        g_tAD7606.ucOS--;
                    }
                    AD7606_SetOS(g_tAD7606.ucOS);
                    ucRefresh = 1;

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

                default:
                    /* 其他的键值不处理 */
                    break;
            }
        }
    }
}


使用特权

评论回复
29
磨砂|  楼主 | 2021-8-1 13:25 | 只看该作者
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。



J-Scope波形效果:



模块插入位置:



程序设计:

  系统栈大小分配:



  RAM空间用的DTCM:



  硬件外设初始化

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

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

    /* 使能L1 Cache */
    CPU_CACHE_Enable();

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

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

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

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

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


  MPU配置和Cache配置:

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

/*
*********************************************************************************************************
*    函 数 名: MPU_Config
*    功能说明: 配置MPU
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
static void MPU_Config( void )
{
    MPU_Region_InitTypeDef MPU_InitStruct;

    /* 禁止 MPU */
    HAL_MPU_Disable();

    /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
    MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    MPU_InitStruct.BaseAddress      = 0x24000000;
    MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;
    MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
    MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
    MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
    MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
    MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
    MPU_InitStruct.SubRegionDisable = 0x00;
    MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;

    HAL_MPU_ConfigRegion(&MPU_InitStruct);


    /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
    MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    MPU_InitStruct.BaseAddress      = 0x60000000;
    MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;   
    MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
    MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;   
    MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
    MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
    MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
    MPU_InitStruct.SubRegionDisable = 0x00;
    MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;

    HAL_MPU_ConfigRegion(&MPU_InitStruct);

    /*使能 MPU */
    HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}

/*
*********************************************************************************************************
*    函 数 名: CPU_CACHE_Enable
*    功能说明: 使能L1 Cache
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
static void CPU_CACHE_Enable(void)
{
    /* 使能 I-Cache */
    SCB_EnableICache();

    /* 使能 D-Cache */
    SCB_EnableDCache();
}


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

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

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


  主功能:

主程序实现如下操作:

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

/*
*********************************************************************************************************
*    函 数 名: main
*    功能说明: c程序入口
*    形    参: 无
*    返 回 值: 错误代码(无需处理)
*********************************************************************************************************
*/
int main(void)
{
    bsp_Init();        /* 硬件初始化 */

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

    DemoFmcAD7606(); /* AD7606测试 */
}

/*
*********************************************************************************************************
*    函 数 名: DemoFmcAD7606
*    功能说明: AD7606测试
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
void DemoFmcAD7606(void)
{
    uint8_t ucKeyCode;
    uint8_t ucRefresh = 0;
    uint8_t ucFifoMode;

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

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

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

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

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

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

        /* 判断定时器超时时间 */
        if (bsp_CheckTimer(3))   
        {
            /* 每隔100ms 进来一次 */  
            bsp_LedToggle(2);
        }

        if (ucRefresh == 1)
        {
            ucRefresh = 0;

            /* 处理数据 */
            AD7606_Mak();

            /* 打印ADC采样结果 */
            AD7606_Disp();        
        }

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

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

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

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

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

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

            if (bsp_CheckTimer(0))
            {
                ucRefresh = 1;    /* 刷新显示 */
            }
        }

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

            switch (ucKeyCode)
            {
                case KEY_DOWN_K1:            /* K1键按下 切换量程 */
                    if (g_tAD7606.ucRange == 0)
                    {
                        AD7606_SetInputRange(1);
                    }
                    else
                    {
                        AD7606_SetInputRange(0);
                    }
                    ucRefresh = 1;
                    break;

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

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

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

                    AD7606_SetOS(g_tAD7606.ucOS);

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

                    ucRefresh = 1;
                    break;

                case JOY_DOWN_D:            /* 摇杆DOWN键按下 */
                    if (g_tAD7606.ucOS > 0)
                    {
                        g_tAD7606.ucOS--;
                    }
                    AD7606_SetOS(g_tAD7606.ucOS);
                    ucRefresh = 1;

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

                default:
                    /* 其他的键值不处理 */
                    break;
            }
        }
    }


使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则