硬汉嵌入式论坛

 找回密码
 立即注册
查看: 929|回复: 6
收起左侧

STM32F429 AD7606 FMC 数据为o

[复制链接]

3

主题

10

回帖

19

积分

新手上路

积分
19
发表于 2024-7-1 11:46:43 | 显示全部楼层 |阅读模式
移植 V6AD7606 DMA双缓冲,供电电压5V,VIO3.3V,使用BANK1 PD7,仿真数据全为0
硬件原理图
下载 (1).png

下载.png
[C] 纯文本查看 复制代码
/*
*********************************************************************************************************
*
*        模块名称 : AD7606数据采集模块【原创】
*        文件名称 : bsp_fmcdma_ad7606.c
*        版    本 : V1.0
*        说    明 : AD7606 FMC DMA采集方式,支持双缓冲
*
*        修改记录 :
*                版本号  日期        作者     说明
*                V1.0    2020-05-24 armfly  正式发布
*
*        Copyright (C), 2020-2030, 安富莱电子 [url=http://www.armfly.com]www.armfly.com[/url]
*
*********************************************************************************************************
*/
#include "bsp.h"



/*
        STM32-V6开发板 + AD7606模块, 控制采集的IO:
        
        PC6/TIM3_CH1/TIM8_CH1     ----> AD7606_CONVST  (和摄像头复用),  输出PWM方波,作为ADC启动信号
        PE5/DCMI_D6/AD7606_BUSY   <---- AD7606_BUSY    , CPU在BUSY中断服务程序中读取采集结果
        
        这个两个IO和STM32-V5开发板是不同的
*/

/* CONVST 启动ADC转换的GPIO = PC6 */
#define CONVST_RCC_GPIO_CLK_ENABLE        __HAL_RCC_GPIOC_CLK_ENABLE
#define CONVST_TIM8_CLK_ENABLE      __HAL_RCC_TIM8_CLK_ENABLE
#define CONVST_RCC_GPIO_CLK_DISBALE        __HAL_RCC_GPIOC_CLK_DISABLE
#define CONVST_TIM8_CLK_DISABLE     __HAL_RCC_TIM8_CLK_DISABLE
#define CONVST_GPIO                GPIOC
#define CONVST_PIN                GPIO_PIN_6
#define CONVST_AF                GPIO_AF3_TIM8
#define CONVST_TIMX                TIM8
#define CONVST_TIMCH        TIM_CHANNEL_1

/* FMC DMA */
#define TIMx_UP_DMA_STREAM_CLK_ENABLE          __HAL_RCC_DMA2_CLK_ENABLE
#define TIMx_UP_DMA_STREAM_CLK_DISABLE  __HAL_RCC_DMA2_CLK_DISABLE
#define TIMx_UP_DMA_STREAM             DMA2_Stream1
#define TIMx_UP_DMA_CHANNEL            DMA_CHANNEL_7
#define TIMx_UP_DMA_IRQn               DMA2_Stream1_IRQn
#define TIMx_UP_DMA_IRQHandler         DMA2_Stream1_IRQHandler

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


/* RESET */
#define PORT_RESET        GPIOC
#define PIN_RESET        GPIO_PIN_7

#define RESET_0()        PORT_RESET->BSRR = ((uint32_t)PIN_RESET << 16U)
#define RESET_1()        PORT_RESET->BSRR = PIN_RESET



/* AD7606 FSMC总线地址,只能读,无需写 */
#define AD7606_BASE            0x60000000

static DMA_HandleTypeDef TIMDMA = {0};
static TIM_HandleTypeDef TimHandle = {0};


/* 8路同步采集,每次采集16字节数据,防止DMA突发方式1KB边界问题,即每次采集不要有跨边界的情况 */
#define AD7606_BUFSIZE        16
__align(16) int16_t g_sAd7606Buf[AD7606_BUFSIZE];   

AD7606_VAR_T g_tAD7606;                /* 定义1个全局变量,保存一些参数 */

static void AD7606_CtrlLinesConfig(void);
static void AD7606_FSMCConfig(void);
static void AD7606_SetTIMOutPWM(TIM_TypeDef* TIMx, uint32_t _ulFreq);


/*
*********************************************************************************************************
*        函 数 名: bsp_InitAD7606
*        功能说明: 配置连接外部SRAM的GPIO和FSMC
*        形    参: 无
*        返 回 值: 无
*********************************************************************************************************
*/
void bsp_InitAD7606(void)
{
        AD7606_CtrlLinesConfig();
        AD7606_FSMCConfig();

//        AD7606_SetOS(AD_OS_NO);                /* 无过采样 */
//        AD7606_SetInputRange(0);        /* 0表示输入量程为正负5V, 1表示正负10V */
        AD7606_Reset();                                /* 复位 */
        CONVST_1();                                        /* 启动转换的GPIO,平时设置为高 */
}

/*
*********************************************************************************************************
*        函 数 名: AD7606_CtrlLinesConfig
*        功能说明: 配置GPIO口线,FMC管脚设置为复用功能
*        形    参: 无
*        返 回 值: 无
*********************************************************************************************************
*/
/*
        安富莱STM32-V6开发板接线方法:
        PD0/FMC_D2
        PD1/FMC_D3
        PD4/FMC_NOE                ---- 读控制信号,OE = Output Enable , N 表示低有效
        PD5/FMC_NWE                -XX- 写控制信号,AD7606 只有读,无写信号
        PD8/FMC_D13
        PD9/FMC_D14
        PD10/FMC_D15
        PD14/FMC_D0
        PD15/FMC_D1

        PE7/FMC_D4
        PE8/FMC_D5
        PE9/FMC_D6
        PE10/FMC_D7
        PE11/FMC_D8
        PE12/FMC_D9
        PE13/FMC_D10
        PE14/FMC_D11
        PE15/FMC_D12


        PD7/FMC_NE2                --- 主片选
*/

/* 
        控制AD7606参数的其他IO分配在扩展的74HC574上
硬件控制 - AD7606_OS0
硬件控制 - AD7606_OS1
硬件控制 - AD7606_OS2
PC7 - AD7606_RESET
硬件控制 - AD7606_RAGE        
*/
static void AD7606_CtrlLinesConfig(void)
{
        /* bsp_fm_io 已配置fmc,bsp_InitExtIO();
           此处可以不必重复配置FMC,其它的要配置。
        */

        GPIO_InitTypeDef gpio_init_structure;

        /* 使能 GPIO时钟 */
        __HAL_RCC_GPIOD_CLK_ENABLE();
        __HAL_RCC_GPIOE_CLK_ENABLE();
        __HAL_RCC_GPIOF_CLK_ENABLE();
        __HAL_RCC_GPIOG_CLK_ENABLE();
        __HAL_RCC_GPIOH_CLK_ENABLE();
        __HAL_RCC_GPIOI_CLK_ENABLE();

        /* 使能FMC时钟 */
        __HAL_RCC_FMC_CLK_ENABLE();

        /* 设置 GPIOD 相关的IO为复用推挽输出 */
        gpio_init_structure.Mode = GPIO_MODE_AF_PP;
        gpio_init_structure.Pull = GPIO_PULLUP;
        gpio_init_structure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
        gpio_init_structure.Alternate = GPIO_AF12_FMC;
        
        /* 配置GPIOD */
        gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5  |
                                    GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_14 |
                                    GPIO_PIN_15 | GPIO_PIN_7;
        HAL_GPIO_Init(GPIOD, &gpio_init_structure);

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

        /* 配置GPIOG */
//        gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1| GPIO_PIN_9;
//        HAL_GPIO_Init(GPIOG, &gpio_init_structure);
        
        /* CONVST 启动ADC转换的GPIO = PC6 */
        {
                GPIO_InitTypeDef   GPIO_InitStructure;
                CONVST_RCC_GPIO_CLK_ENABLE();

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

                GPIO_InitStructure.Pin = CONVST_PIN;        
                HAL_GPIO_Init(CONVST_GPIO, &GPIO_InitStructure);        
                
                GPIO_InitStructure.Pin = PIN_RESET;        
                HAL_GPIO_Init(PORT_RESET, &GPIO_InitStructure);
        }
}

/*
*********************************************************************************************************
*        函 数 名: AD7606_FSMCConfig
*        功能说明: 配置FSMC并口访问时序
*        形    参: 无
*        返 回 值: 无
*********************************************************************************************************
*/
static void AD7606_FSMCConfig(void)
{
        /* 
           DM9000,扩展IO,OLED和AD7606公用一个FMC配置,如果都开启,请以FMC速度最慢的为准。
           从而保证所有外设都可以正常工作。
        */
        SRAM_HandleTypeDef hsram = {0};
        FMC_NORSRAM_TimingTypeDef SRAM_Timing = {0};
                
        /*
                AD7606规格书要求(3.3V时,通信电平Vdriver):RD读信号低电平脉冲宽度最短21ns,对应FMC的DataSetupTime
                CS片选和RD读信号独立方式的高电平脉冲最短宽度15ns。
                CS片选和RD读信号并联方式的高电平脉冲最短宽度22ns。
                这里将22ns作为最小值更合理些,对应FMC的AddressSetupTime
        
                4-x-6-x-x-x  : RD高持续35.7ns,低电平持续23.8ns. 读取8路样本数据到内存差不多就是476ns。
        */
        hsram.Instance  = FMC_NORSRAM_DEVICE;
        hsram.Extended  = FMC_NORSRAM_EXTENDED_DEVICE;
        
        /* FMC使用的HCLK,主频168MHz,1个FMC时钟周期就是5.95ns */   
        SRAM_Timing.AddressSetupTime       = 4;  /* 4*5.95ns=23.8ns,地址建立时间,范围0 -15个FMC时钟周期个数 */
        SRAM_Timing.AddressHoldTime        = 0;  /* 地址保持时间,配置为模式A时,用不到此参数 范围1 -15个时钟周期个数 */
        SRAM_Timing.DataSetupTime          = 6;  /* 6*5.95ns=35.7ns,数据保持时间,范围1 -255个时钟周期个数 */
        SRAM_Timing.BusTurnAroundDuration  = 0;  /* 此配置用不到这个参数 */
        SRAM_Timing.CLKDivision            = 0;  /* 此配置用不到这个参数 */
        SRAM_Timing.DataLatency            = 0;  /* 此配置用不到这个参数 */
        SRAM_Timing.AccessMode             = FMC_ACCESS_MODE_A; /* 配置为模式A */

        hsram.Init.NSBank             = FMC_NORSRAM_BANK1;              /* 使用的BANK1,即使用的片选FMC_NE1 */
        hsram.Init.DataAddressMux     = FMC_DATA_ADDRESS_MUX_DISABLE;   /* 禁止地址数据复用 */
        hsram.Init.MemoryType         = FMC_MEMORY_TYPE_SRAM;           /* 存储器类型SRAM */
        hsram.Init.MemoryDataWidth    = FMC_NORSRAM_MEM_BUS_WIDTH_32;        /* 32位总线宽度 */
        hsram.Init.BurstAccessMode    = FMC_BURST_ACCESS_MODE_DISABLE;  /* 关闭突发模式 */
        hsram.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW;   /* 用于设置等待信号的极性,关闭突发模式,此参数无效 */
        hsram.Init.WaitSignalActive   = FMC_WAIT_TIMING_BEFORE_WS;      /* 关闭突发模式,此参数无效 */
        hsram.Init.WriteOperation     = FMC_WRITE_OPERATION_ENABLE;     /* 用于使能或者禁止写保护 */
        hsram.Init.WaitSignal         = FMC_WAIT_SIGNAL_DISABLE;        /* 关闭突发模式,此参数无效 */
        hsram.Init.ExtendedMode       = FMC_EXTENDED_MODE_DISABLE;      /* 禁止扩展模式 */
        hsram.Init.AsynchronousWait   = FMC_ASYNCHRONOUS_WAIT_DISABLE;  /* 用于异步传输期间,使能或者禁止等待信号,这里选择关闭 */
        hsram.Init.WriteBurst         = FMC_WRITE_BURST_DISABLE;        /* 禁止写突发 */
        hsram.Init.ContinuousClock    = FMC_CONTINUOUS_CLOCK_SYNC_ONLY; /* 仅同步模式才做时钟输出 */
    hsram.Init.WriteFifo          = FMC_WRITE_FIFO_ENABLE;          /* 使能写FIFO */

        /* 初始化SRAM控制器 */
        if (HAL_SRAM_Init(&hsram, &SRAM_Timing, &SRAM_Timing) != HAL_OK)
        {
                /* 初始化错误 */
                Error_Handler(__FILE__, __LINE__);
        }        
}

/*
*********************************************************************************************************
*        函 数 名: 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;
//        }
//}

/*
*********************************************************************************************************
*        函 数 名: 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 */
//        }
//}

/*
*********************************************************************************************************
*        函 数 名: AD7606_Reset
*        功能说明: 硬件复位AD7606,复位之后恢复到正常工作状态。
*        形    参: 无
*        返 回 值: 无
*********************************************************************************************************
*/
void AD7606_Reset(void)
{
        RESET_0();        /* 退出复位状态 */

        RESET_1();        /* 进入复位状态 */
        RESET_1();        /* 仅用于延迟。 RESET复位高电平脉冲宽度最小50ns。 */
        RESET_1();
        RESET_1();

        RESET_0();        /* 退出复位状态 */
}

/*
*********************************************************************************************************
*        函 数 名: AD7606_StartConvst
*        功能说明: 启动1次ADC转换
*        形    参: 无
*        返 回 值: 无
*********************************************************************************************************
*/
void AD7606_StartConvst(void)
{
        /* page 7:  CONVST 高电平脉冲宽度和低电平脉冲宽度最短 25ns */
        /* CONVST平时为高 */
        CONVST_0();
        CONVST_0();
        CONVST_0();

        CONVST_1();
}

/*
*********************************************************************************************************
*        函 数 名: AD7606_StartRecord
*        功能说明: 开始采集
*        形    参: _ulFreq : 采样频率,单位Hz , 对于AD7606来说,范围1 - 200KHz
*        返 回 值: 无
*********************************************************************************************************
*/
void AD7606_StartRecord(uint32_t _ulFreq)
{
        AD7606_StopRecord();

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

        /* 配置PC6为TIM8_CH1功能 */
        AD7606_SetTIMOutPWM(CONVST_TIMX, _ulFreq);
}

/*
*********************************************************************************************************
*        函 数 名: AD7606_StopRecord
*        功能说明: 停止采集定时器
*        形    参: 无
*        返 回 值: 无
*********************************************************************************************************
*/
void AD7606_StopRecord(void)
{
        /* 配置PC6 输出低电平,关闭TIM */
        HAL_GPIO_DeInit(CONVST_GPIO, CONVST_PIN);
        CONVST_TIM8_CLK_DISABLE();
        TIMx_UP_DMA_STREAM_CLK_DISABLE();
        
        /* CONVST 启动ADC转换的GPIO = PC6 */
        {
                GPIO_InitTypeDef   GPIO_InitStructure;
                CONVST_RCC_GPIO_CLK_ENABLE();

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

                GPIO_InitStructure.Pin = CONVST_PIN;        
                HAL_GPIO_Init(CONVST_GPIO, &GPIO_InitStructure);        
        }
        
        CONVST_1();                        /* 启动转换的GPIO平时设置为高 */        
}

/*
*********************************************************************************************************
*        函 数 名: AD7606_SetTIMOutPWM
*        功能说明: 用于设置定时UP更新触发DMA传输,并设置定时器PWM作为AD7606的触发时钟
*        形    参: TIMx : TIM1 - TIM14
*                          _ulFreq : PWM信号频率,单位Hz,范围1Hz - 200KHz
*        返 回 值: 无
*********************************************************************************************************
*/
/* DMA传输完成回调函数,弱定义 */
__weak void AD7606_DmaCplCb(DMA_HandleTypeDef *hdma)
{
        
}

/* DMA半传输完成回调函数,弱定义 */
__weak void AD7606_DmaHalfCplCb(DMA_HandleTypeDef *hdma)
{
        
}

/* DMA中断服务程序 */
void TIMx_UP_DMA_IRQHandler(void)
{
        HAL_DMA_IRQHandler(&TIMDMA);
}

static void AD7606_SetTIMOutPWM(TIM_TypeDef* TIMx, uint32_t _ulFreq)
{
        TIM_OC_InitTypeDef sConfig = {0};        
        GPIO_InitTypeDef   GPIO_InitStruct;
        uint16_t usPeriod;
        uint16_t usPrescaler;
        uint32_t uiTIMxCLK;
        uint32_t pulse;

        
        /* 配置时钟 */
        CONVST_RCC_GPIO_CLK_ENABLE();
        CONVST_TIM8_CLK_ENABLE();
        TIMx_UP_DMA_STREAM_CLK_ENABLE();
        
        
        /* 配置引脚 */
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
        GPIO_InitStruct.Alternate = CONVST_AF;
        GPIO_InitStruct.Pin = CONVST_PIN;
        HAL_GPIO_Init(CONVST_GPIO, &GPIO_InitStruct);
        
        /*-----------------------------------------------------------------------
                system_stm32f4xx.c 文件中 void SetSysClock(void) 函数对时钟的配置如下:

                HCLK = SYSCLK / 1     (AHB1Periph)
                PCLK2 = HCLK / 2      (APB2Periph)
                PCLK1 = HCLK / 4      (APB1Periph)

                因为APB1 prescaler != 1, 所以 APB1上的TIMxCLK = PCLK1 x 2 = SystemCoreClock / 2;
                因为APB2 prescaler != 1, 所以 APB2上的TIMxCLK = PCLK2 x 2 = SystemCoreClock;

                APB1 定时器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM7, TIM12, TIM13,TIM14
                APB2 定时器有 TIM1, TIM8 ,TIM9, TIM10, TIM11

        ----------------------------------------------------------------------- */
        if ((TIMx == TIM1) || (TIMx == TIM8) || (TIMx == TIM9) || (TIMx == TIM10) || (TIMx == TIM11))
        {
                /* APB2 定时器时钟 = 168M */
                uiTIMxCLK = SystemCoreClock;
                
                if (_ulFreq < 100)
                {
                        usPrescaler = 10000 - 1;                                                /* 分频比 = 10000 */
                        usPeriod =  (uiTIMxCLK / 10000) / _ulFreq  - 1;        /* 自动重装的值, usPeriod最小值168, 单位59us */
                        pulse = usPeriod;                               /* 设置低电平时间59us,注意usPeriod已经进行了减1操作 */
                } 
                else if (_ulFreq < 3000)
                {
                        usPrescaler = 100 - 1;                                                        /* 分频比 = 100 */
                        usPeriod =  (uiTIMxCLK / 100) / _ulFreq  - 1;        /* 自动重装的值, usPeriod最小值560,单位595ns */
                        pulse = usPeriod-1;                                   /* 设置低电平时间1.19us,注意usPeriod已经进行了减1操作 */
                }
                else        /* 大于4K的频率,无需分频 */
                {
                        usPrescaler = 0;                                                                /* 分频比 = 1 */
                        usPeriod = uiTIMxCLK / _ulFreq - 1;                                /* 自动重装的值, usPeriod最小值840,单位5.95ns */
                        pulse = usPeriod - 199;                                      /* 设置低电平时间1.19us,注意usPeriod已经进行了减1操作 */
                }
        }
        else        
        {
                /* APB1 定时器 = 84M */
                uiTIMxCLK = SystemCoreClock / 2;
                
                if (_ulFreq < 100)
                {
                        usPrescaler = 10000 - 1;                                                        /* 分频比 = 10000 */
                        usPeriod =  (uiTIMxCLK / 10000) / _ulFreq  - 1;                /* 自动重装的值, usPeriod最小值84, 单位119us */
                        pulse = usPeriod;                                       /* 设置低电平时间119us,注意usPeriod已经进行了减1操作 */
                } 
                else if (_ulFreq < 3000)
                {
                        usPrescaler = 100 - 1;                                                        /* 分频比 = 100 */
                        usPeriod =  (uiTIMxCLK / 100) / _ulFreq  - 1;        /* 自动重装的值, usPeriod最小值280,单位1.19us */
                        pulse = usPeriod;                                   /* 设置低电平时间1.19us,注意usPeriod已经进行了减1操作 */
                }
                else        /* 大于4K的频率,无需分频 */
                {
                        usPrescaler = 0;                                                                /* 分频比 = 1 */
                        usPeriod = uiTIMxCLK / _ulFreq - 1;                                /* 自动重装的值, usPeriod最小值420,单位11.9ns */
                        pulse = usPeriod - 99;                                      /* 设置低电平时间1.19us,注意usPeriod已经进行了减1操作 */
                }
        }
    
        /*  PWM频率 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)*/
        TimHandle.Instance = TIMx;
        TimHandle.Init.Prescaler         = usPrescaler;         /* 用于设置定时器分频 */
        TimHandle.Init.Period            = usPeriod;            /* 用于设置定时器周期 */
        TimHandle.Init.ClockDivision     = 0;                   /* 用于指示定时器时钟 (CK_INT) 频率与死区发生器以及数字滤波器(ETR、 TIx)
                                                                   所使用的死区及采样时钟 (tDTS) 之间的分频比*/
        TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;  /* 用于设置计数模式,向上计数模式 */
        TimHandle.Init.RepetitionCounter = 0;                   /* 用于设置重复计数器,仅 TIM1 和 TIM8 有,其它定时器没有 */
        TimHandle.Init.AutoReloadPreload = 0;                   /* 用于设置定时器的 ARR 自动重装寄存器是更新事件产生时写入有效 */
        
        if (HAL_TIM_PWM_DeInit(&TimHandle) != HAL_OK)
        {
                Error_Handler(__FILE__, __LINE__);                
        }
        
        if (HAL_TIM_PWM_Init(&TimHandle) != HAL_OK)
        {
                Error_Handler(__FILE__, __LINE__);
        }

        /* 配置定时器PWM输出通道 */
        sConfig.OCMode       = TIM_OCMODE_PWM1;         /* 配置输出比较模式 */
        sConfig.OCPolarity   = TIM_OCPOLARITY_HIGH;     /* 设置输出高电平有效 */
        sConfig.OCFastMode   = TIM_OCFAST_DISABLE;      /* 关闭快速输出模式 */
        sConfig.OCNPolarity  = TIM_OCNPOLARITY_HIGH;    /* 配置互补输出高电平有效 */
        sConfig.OCIdleState  = TIM_OCIDLESTATE_SET;     /* 空闲状态时,设置输出比较引脚为高电平 */
        sConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET;  /* 空闲状态时,设置互补输出比较引脚为低电平 */

        /* 占空比 */
        sConfig.Pulse = (pulse);
        if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &sConfig, CONVST_TIMCH) != HAL_OK)
        {
                Error_Handler(__FILE__, __LINE__);
        }
        
        /* 使能定时器中断  */
        __HAL_TIM_ENABLE_DMA(&TimHandle, TIM_DMA_UPDATE);
        
        /* 启动PWM输出 */
        if (HAL_TIM_PWM_Start(&TimHandle, CONVST_TIMCH) != HAL_OK)
        {
                Error_Handler(__FILE__, __LINE__);
        }
        
        /* 定时器UP更新触发DMA传输 */                
        TIMDMA.Instance                 = TIMx_UP_DMA_STREAM;      /* 例化使用的DMA数据流 */
        TIMDMA.Init.FIFOMode            = DMA_FIFOMODE_ENABLE;     /* 使能FIFO*/
        TIMDMA.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL; /* 用于设置阀值 */
        TIMDMA.Init.MemBurst            = DMA_MBURST_INC8;               /* 用于存储器突发 */
        TIMDMA.Init.PeriphBurst         = DMA_PBURST_INC8;               /* 用于外设突发 */
        TIMDMA.Init.Channel             = TIMx_UP_DMA_CHANNEL;     /* DMA通道 */  
        TIMDMA.Init.Direction           = DMA_PERIPH_TO_MEMORY;    /* 传输方向是从外设到存储器 */  
        TIMDMA.Init.PeriphInc           = DMA_PINC_DISABLE;        /* 外设地址自增禁止 */ 
        TIMDMA.Init.MemInc              = DMA_MINC_ENABLE;         /* 存储器地址自增使能 */  
        TIMDMA.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; /* 外设数据传输位宽选择半字,即16bit */ 
        TIMDMA.Init.MemDataAlignment    = DMA_MDATAALIGN_HALFWORD; /* 存储器数据传输位宽选择半字,即16bit */    
        TIMDMA.Init.Mode                = DMA_CIRCULAR;                    /* 循环模式 */
        TIMDMA.Init.Priority            = DMA_PRIORITY_LOW;        /* 优先级低 */
        
         /* 复位DMA */
        if(HAL_DMA_DeInit(&TIMDMA) != HAL_OK)
        {
                /* DMA处于忙状态,直接终止DMA */
                if(HAL_DMA_Abort_IT(&TIMDMA) != HAL_OK)
                {
                        Error_Handler(__FILE__, __LINE__);                     
                }   
        }
        
         /* 初始化DMA */
        if(HAL_DMA_Init(&TIMDMA) != HAL_OK)
        {
                Error_Handler(__FILE__, __LINE__);     
        }
        
        /* 关联DMA句柄到TIM */
        //__HAL_LINKDMA(&TimHandle, hdma[TIM_DMA_ID_UPDATE], TIMDMA);        
        
        /* 配置DMA中断 */
        HAL_NVIC_SetPriority(TIMx_UP_DMA_IRQn, 1, 0);
        HAL_NVIC_EnableIRQ(TIMx_UP_DMA_IRQn);
        
        /* 注册半传输完成中断和传输完成中断 */
        HAL_DMA_RegisterCallback(&TIMDMA, HAL_DMA_XFER_CPLT_CB_ID, AD7606_DmaCplCb);
        HAL_DMA_RegisterCallback(&TIMDMA, HAL_DMA_XFER_HALFCPLT_CB_ID, AD7606_DmaHalfCplCb);
        
        /* 启动DMA传输 */
        HAL_DMA_Start_IT(&TIMDMA, (uint32_t)AD7606_BASE, (uint32_t)g_sAd7606Buf, 16);
}

/***************************** 安富莱电子 [url=http://www.armfly.com]www.armfly.com[/url] (END OF FILE) *********************************/

示波器测量 PD4 NOE
下载 (2).png
8080与SPI选择
下载 (3).png
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
115653
QQ
发表于 2024-7-1 12:55:51 | 显示全部楼层
中断正常进入没
回复

使用道具 举报

3

主题

10

回帖

19

积分

新手上路

积分
19
 楼主| 发表于 2024-7-1 13:52:10 | 显示全部楼层
正常,定时器触发DMA, DMA半完成中断和完成中断正常
回复

使用道具 举报

33

主题

188

回帖

287

积分

高级会员

积分
287
发表于 2024-7-1 14:24:17 | 显示全部楼层
看看手册,这个对应地址能不能支持DMA
回复

使用道具 举报

3

主题

10

回帖

19

积分

新手上路

积分
19
 楼主| 发表于 2024-7-1 15:06:20 | 显示全部楼层
LinY 发表于 2024-7-1 14:24
看看手册,这个对应地址能不能支持DMA



回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
115653
QQ
发表于 2024-7-1 15:18:37 | 显示全部楼层
zqy 发表于 2024-7-1 13:52
正常,定时器触发DMA, DMA半完成中断和完成中断正常

做一个简单的测试,V6不是还有个软件方式触发转换,比较简单的那种实现方案,不使用DMA, 测试读取的数据是否正常。如果没问题,说明你的硬件测试环境是没问题的,然后再搞下DMA方式。
回复

使用道具 举报

3

主题

10

回帖

19

积分

新手上路

积分
19
 楼主| 发表于 2024-7-3 16:20:56 | 显示全部楼层
找到一个问题CONVST A,CONVST B,我直接一个CONVST A,数据全为0,busy引脚没有信号,连个并联就有数据了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-5-10 03:56 , Processed in 0.345869 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表