硬汉嵌入式论坛

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

[DMA] STM32H7的DMA句柄关联到外设函数__HAL_LINKDMA注意事项

  [复制链接]

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
发表于 2019-3-5 02:31:50 | 显示全部楼层 |阅读模式
这个函数是将DMA句柄关联到DCMI句柄里面,如果DMA句柄被设置为局部变量,退出此函数会被释放掉,
导致DCMI句柄在其它函数里面引用DMA句柄时出错。
11.jpg


此函数的源代码:
  1. #define __HAL_LINKDMA(__HANDLE__, __PPP_DMA_FIELD__, __DMA_HANDLE__)               \
  2.                         do{                                                      \
  3.                               (__HANDLE__)->__PPP_DMA_FIELD__ = &(__DMA_HANDLE__); \
  4.                               (__DMA_HANDLE__).Parent = (__HANDLE__);             \
  5.                           } while(0)
复制代码


回复

使用道具 举报

17

主题

248

回帖

299

积分

高级会员

积分
299
发表于 2019-3-5 09:35:19 | 显示全部楼层
硬汉这个“但是”看着有点懵。这里表达的意思应该是DMA句柄应该定义成全局的吧,不然使用DCMI引用DMA句柄的时候会出错。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
 楼主| 发表于 2019-3-5 10:41:44 | 显示全部楼层
xieyang__ 发表于 2019-3-5 09:35
硬汉这个“但是”看着有点懵。这里表达的意思应该是DMA句柄应该定义成全局的吧,不然使用DCMI引用DMA句柄的 ...

语句不通,感觉告知,我修改下。
回复

使用道具 举报

76

主题

208

回帖

436

积分

高级会员

积分
436
发表于 2020-12-2 16:11:11 | 显示全部楼层
eric2013 发表于 2019-3-5 10:41
语句不通,感觉告知,我修改下。

硬汉兄,stm32f407hal库,使用定时器输入捕获计算频率,现在已实现中断读取数据计数而计算频率,但是中断太频繁,想改用DMA获取,下面这个函数中间那个参数,是不是用的TIM_HandleTypeDef里的 hdma数组呢(如图2)
1.png

图2

图2
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
 楼主| 发表于 2020-12-3 09:30:02 | 显示全部楼层
薪火相传 发表于 2020-12-2 16:11
硬汉兄,stm32f407hal库,使用定时器输入捕获计算频率,现在已实现中断读取数据计数而计算频率,但是中断 ...

QQ截图20201203092953.png
回复

使用道具 举报

76

主题

208

回帖

436

积分

高级会员

积分
436
发表于 2020-12-3 13:42:26 | 显示全部楼层

硬汉兄,有没有试过用DMA读取输入捕获的CCR数据
回复

使用道具 举报

76

主题

208

回帖

436

积分

高级会员

积分
436
发表于 2020-12-3 14:03:02 | 显示全部楼层

使用stm32f407VET6 用的TIM1  脉冲输入引脚为PA11(TIM1_CH4),目前已实现中断读取CC4的数值,因为中断太频繁想改用DMA获取的方法,不知道怎么操作?uint32_t IC4_value[2];
//定时器配置
static void TIM_PWMINPUT_Config(void)
{
    TIM_IC_InitTypeDef TIM_ICInitStructure;
    TIM_SlaveConfigTypeDef TIM_SlaveConfigStructure;

    __TIM1_CLK_ENABLE();
    TIM_PWMINPUT_Handle.Instance = TIM1;
    TIM_PWMINPUT_Handle.Init.Period = 0xFFFF;
// 高级控制定时器时钟源 TIMxCLK = HCLK=168MHz
// 设定定时器频率为=TIMxCLK/(TIM_Prescaler+1)=1MHz
    TIM_PWMINPUT_Handle.Init.Prescaler = 168 - 1;
    TIM_PWMINPUT_Handle.Init.ClockDivision = 0;
    TIM_PWMINPUT_Handle.Init.CounterMode = TIM_COUNTERMODE_UP;
    HAL_TIM_IC_Init(&TIM_PWMINPUT_Handle);

    TIM_ICInitStructure.ICPolarity = TIM_ICPOLARITY_RISING;
    TIM_ICInitStructure.ICSelection = TIM_ICSELECTION_DIRECTTI;
    TIM_ICInitStructure.ICPrescaler = TIM_ICPSC_DIV1;
    TIM_ICInitStructure.ICFilter = 0x0;
    HAL_TIM_IC_ConfigChannel(&TIM_PWMINPUT_Handle, &TIM_ICInitStructure, TIM_CHANNEL_4);
//    HAL_TIM_IC_Start_IT(&TIM_PWMINPUT_Handle, TIM_CHANNEL_4);
}


//DMA配置
void tim_dma_config(void)
{
    __DMA2_CLK_ENABLE();
    TIM_DMA_Handle.Instance = DMA2_Stream4;
    TIM_DMA_Handle.Init.Channel = DMA_CHANNEL_6;
    TIM_DMA_Handle.Init.Direction = DMA_PERIPH_TO_MEMORY;
    TIM_DMA_Handle.Init.PeriphInc = DMA_PINC_DISABLE;
    TIM_DMA_Handle.Init.MemInc = DMA_MINC_ENABLE;
    TIM_DMA_Handle.Init.PeriphDataAlignment = DMA_MDATAALIGN_WORD;
    TIM_DMA_Handle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
    TIM_DMA_Handle.Init.Mode = DMA_CIRCULAR;
    TIM_DMA_Handle.Init.Priority = DMA_PRIORITY_MEDIUM;
    TIM_DMA_Handle.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    TIM_DMA_Handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
    TIM_DMA_Handle.Init.MemBurst = DMA_MBURST_SINGLE;
    TIM_DMA_Handle.Init.PeriphBurst = DMA_PBURST_SINGLE;

    __HAL_LINKDMA(&TIM_PWMINPUT_Handle,hdma[TIM_DMA_ID_CC4], TIM_DMA_Handle);

    HAL_DMA_Init(TIM_PWMINPUT_Handle.hdma[TIM_DMA_ID_CC4]);
    HAL_TIM_IC_Start_DMA(&TIM_PWMINPUT_Handle,TIM_CHANNEL_4,&IC4_value,4);
//    HAL_NVIC_EnableIRQ(DMA2_Stream4_IRQn);

}

接下来,怎么判断IC4_value值就是上升沿捕获CCR寄存器的值呢

回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
 楼主| 发表于 2020-12-4 09:55:34 | 显示全部楼层
薪火相传 发表于 2020-12-3 13:42
硬汉兄,有没有试过用DMA读取输入捕获的CCR数据

搞过,

STM32H7的定时器输入捕获可以实现12MHz方波的双边沿捕获,单边沿可以做到24MHz
http://www.armbbs.cn/forum.php?m ... 1283&fromuid=58
(出处: 硬汉嵌入式论坛)
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
 楼主| 发表于 2020-12-4 09:56:41 | 显示全部楼层
薪火相传 发表于 2020-12-3 14:03
使用stm32f407VET6 用的TIM1  脉冲输入引脚为PA11(TIM1_CH4),目前已实现中断读取CC4的数值,因为中断太频 ...

你配置好IC输入极性即可。
回复

使用道具 举报

76

主题

208

回帖

436

积分

高级会员

积分
436
发表于 2020-12-4 11:06:37 | 显示全部楼层
eric2013 发表于 2020-12-4 09:56
你配置好IC输入极性即可。

不太了解DMA机制,需要判断dma传输完成才能获取存储区的数据吗?
回复

使用道具 举报

76

主题

208

回帖

436

积分

高级会员

积分
436
发表于 2020-12-4 11:09:30 | 显示全部楼层
eric2013 发表于 2020-12-4 09:55
搞过,

STM32H7的定时器输入捕获可以实现12MHz方波的双边沿捕获,单边沿可以做到24MHz

这个例子在哪里
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
 楼主| 发表于 2020-12-5 10:01:54 | 显示全部楼层
薪火相传 发表于 2020-12-4 11:06
不太了解DMA机制,需要判断dma传输完成才能获取存储区的数据吗?

进入DMA完成中断即可。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
 楼主| 发表于 2020-12-5 10:03:11 | 显示全部楼层

这个没有写例子,是用的STM32CubeH7软件包里面的输入捕获加上DMA修改的。
回复

使用道具 举报

76

主题

208

回帖

436

积分

高级会员

积分
436
发表于 2020-12-5 13:50:49 | 显示全部楼层
eric2013 发表于 2020-12-5 10:01
进入DMA完成中断即可。

使用HAL_DMA_RegisterCallback注册了个完成中断回调函数,但就是始终没进入DMA完成中断回调函数。我具体说一下:

回复

使用道具 举报

76

主题

208

回帖

436

积分

高级会员

积分
436
发表于 2020-12-5 14:38:42 | 显示全部楼层
eric2013 发表于 2020-12-5 10:01
进入DMA完成中断即可。

我详细说一下我这个需求和代码实现,硬汉兄有空就帮我看一下,
需求:检测输入脉冲的频率。
实现:通过stm32f407的PA11(TIM1_CH4),输入捕获获得CCR4的数值,使用DMA方式。

代码:

TIM_HandleTypeDef  TIM_PWMINPUT_Handle;
DMA_HandleTypeDef TIM_DMA_Handle;

uint32_t IC4_value[2]={0,0};//读取CCR4寄存器的值

//输入捕获引脚配置
static void TIMx_GPIO_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

     __GPIOA_CLK_ENABLE();

    GPIO_InitStructure.Pin = GPIO_PIN_11;
    GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStructure.Pull = GPIO_NOPULL;
    GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
    GPIO_InitStructure.Alternate = GPIO_AF1_TIM1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
}



/*定时器模式设置*/
static void TIM_PWMINPUT_Config(void)
{
    TIM_IC_InitTypeDef TIM_ICInitStructure;
    TIM_SlaveConfigTypeDef TIM_SlaveConfigStructure;

    __TIM1_CLK_ENABLE();
    TIM_PWMINPUT_Handle.Instance = TIM1;
    TIM_PWMINPUT_Handle.Init.Period = 0xFFFF;
// 高级控制定时器时钟源 TIMxCLK = HCLK=168MHz
// 设定定时器频率为=TIMxCLK/(TIM_Prescaler+1)=1MHz
    TIM_PWMINPUT_Handle.Init.Prescaler = 168 - 1;
    TIM_PWMINPUT_Handle.Init.ClockDivision = 0;
    TIM_PWMINPUT_Handle.Init.CounterMode = TIM_COUNTERMODE_UP;
    HAL_TIM_IC_Init(&TIM_PWMINPUT_Handle);

    TIM_ICInitStructure.ICPolarity = TIM_ICPOLARITY_RISING;
    TIM_ICInitStructure.ICSelection = TIM_ICSELECTION_DIRECTTI;
    TIM_ICInitStructure.ICPrescaler = TIM_ICPSC_DIV1;
    TIM_ICInitStructure.ICFilter = 0x0;
    HAL_TIM_IC_ConfigChannel(&TIM_PWMINPUT_Handle, &TIM_ICInitStructure, TIM_CHANNEL_4);
//    HAL_TIM_IC_Start_IT(&TIM_PWMINPUT_Handle, TIM_CHANNEL_4);
}


/*DMA传输完成回调函数*/
void dma_tra_complete(DMA_HandleTypeDef *_hdma)
{
    LOG_D("transfer finish!");

}


//DMA配置
void tim_dma_config(void)
{
    __DMA2_CLK_ENABLE();
    TIM_DMA_Handle.Instance = DMA2_Stream4;

    TIM_DMA_Handle.Init.Channel = DMA_CHANNEL_6;
    TIM_DMA_Handle.Init.Direction = DMA_PERIPH_TO_MEMORY;
    TIM_DMA_Handle.Init.PeriphInc = DMA_PINC_DISABLE;
    TIM_DMA_Handle.Init.MemInc = DMA_MINC_ENABLE;
    TIM_DMA_Handle.Init.PeriphDataAlignment = DMA_MDATAALIGN_WORD;
    TIM_DMA_Handle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
    TIM_DMA_Handle.Init.Mode = DMA_CIRCULAR;
    TIM_DMA_Handle.Init.Priority = DMA_PRIORITY_HIGH;
    TIM_DMA_Handle.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    TIM_DMA_Handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
    TIM_DMA_Handle.Init.MemBurst = DMA_MBURST_SINGLE;
    TIM_DMA_Handle.Init.PeriphBurst = DMA_PBURST_SINGLE;

    __HAL_LINKDMA(&TIM_PWMINPUT_Handle,hdma[TIM_DMA_ID_CC4], TIM_DMA_Handle);

    /* 复位 DMA */
    if(HAL_DMA_DeInit(&TIM_DMA_Handle) != HAL_OK)
    {
        LOG_E("HAL_DMA_DeInit error!");
    }
    /* 初始化 DMA */
    if(HAL_DMA_Init(&TIM_DMA_Handle) != HAL_OK)
    {
        LOG_E("HAL_DMA_Init error!");
    }

    HAL_DMA_RegisterCallback(TIM_PWMINPUT_Handle.hdma[TIM_DMA_ID_CC4],HAL_DMA_XFER_M1CPLT_CB_ID,dma_tra_complete);

//     HAL_DMA_Init(TIM_PWMINPUT_Handle.hdma[TIM_DMA_ID_CC4]);
    /* 配置 DMA 中断 */
    HAL_NVIC_SetPriority(DMA2_Stream4_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(DMA2_Stream4_IRQn);
    /* 启动 DMA 传输 */
    HAL_TIM_IC_Start_DMA(&TIM_PWMINPUT_Handle,TIM_CHANNEL_4,IC4_value,2);
}

//DMA中断
void DMA2_Stream4_IRQHandler(void)
{
    HAL_DMA_IRQHandler(TIM_PWMINPUT_Handle.hdma[TIM_DMA_ID_CC4]);
}


//测试函数
void pwm_test(void)
{
    TIMx_GPIO_Config();
    TIM_PWMINPUT_Config();
    tim_dma_config();
    while (1)
    {
        LOG_D("IC4_value[0]:%d \n",IC4_value[0]);
        LOG_D("IC4_value[1]:%d \n",IC4_value[1]);
        rt_thread_mdelay(500);
    }
}



运行程序后,打印的数据如图:IC4_value[1]一直为0,而且并没有进去DMA传输完成回调函数,请教大佬哪里有问题。抱拳。


1.png
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
 楼主| 发表于 2020-12-6 11:57:38 | 显示全部楼层
薪火相传 发表于 2020-12-5 14:38
我详细说一下我这个需求和代码实现,硬汉兄有空就帮我看一下,
需求:检测输入脉冲的频率。
实现:通 ...

定时器结构体做局部变量必须初始化为0

   TIM_IC_InitTypeDef TIM_ICInitStructure;
    TIM_SlaveConfigTypeDef TIM_SlaveConfigStructure;
回复

使用道具 举报

76

主题

208

回帖

436

积分

高级会员

积分
436
发表于 2020-12-7 09:09:28 | 显示全部楼层
eric2013 发表于 2020-12-6 11:57
定时器结构体做局部变量必须初始化为0

   TIM_IC_InitTypeDef TIM_ICInitStructure;

我把这两个放在全局变量也一样,其实跟这两个应该没关系,因为通过开启中断读取数据是可以的
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
 楼主| 发表于 2020-12-7 11:22:06 | 显示全部楼层
薪火相传 发表于 2020-12-7 09:09
我把这两个放在全局变量也一样,其实跟这两个应该没关系,因为通过开启中断读取数据是可以的

因为你用的是TIM1,有几个多出来的参数程序,是必须要配置的。
回复

使用道具 举报

76

主题

208

回帖

436

积分

高级会员

积分
436
发表于 2020-12-9 15:02:44 | 显示全部楼层
eric2013 发表于 2020-12-7 11:22
因为你用的是TIM1,有几个多出来的参数程序,是必须要配置的。

用cubemx配置了一下,倒是可以了
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
 楼主| 发表于 2020-12-9 15:13:23 | 显示全部楼层
薪火相传 发表于 2020-12-9 15:02
用cubemx配置了一下,倒是可以了

果然是配置问题。。。
回复

使用道具 举报

0

主题

19

回帖

19

积分

新手上路

积分
19
发表于 2021-8-24 14:04:03 | 显示全部楼层
薪火相传 发表于 2020-12-9 15:02
用cubemx配置了一下,倒是可以了

薪火哥,配置好的代码是什么样的哇,可以 发出来看一看嘛
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
 楼主| 发表于 2021-8-24 16:19:31 | 显示全部楼层
梦幻的帅帅 发表于 2021-8-24 14:04
薪火哥,配置好的代码是什么样的哇,可以 发出来看一看嘛

可以使用我做的例子。
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-4-28 13:21 , Processed in 0.315557 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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