硬汉嵌入式论坛

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

[摄像头] 关于DCMI的VSYNC和HSYNC信号

[复制链接]

9

主题

40

回帖

67

积分

初级会员

积分
67
发表于 2025-5-20 10:36:10 | 显示全部楼层 |阅读模式
最近在研究STM32的DCMI模块,在查看应用手册AN5020的3.4.1章节时,发现针对VSYNC信号和HSYNC信号的有效电平描述这里怪怪的
原文:
"如果为DCMI_VSYNC和DCMI_HSYNC信号设定了有效电平(高电平有效或低电平有效),则当VSYNC或HSYNC处于该电平(高或低)时,并行接口中的数据无效。
例如,如果VSYNC被设定为高电平有效:
• 当VSYNC处于低电平时,数据有效
• 当VSYNC处于高电平时,数据无效(垂直消隐)。"

有效电平的字面意义难道不是指信号在这段时间内是有效的嘛?为啥这个是反过来的。感觉有点反直觉呢??

Dingtalk_20250520103117.jpg
回复

使用道具 举报

9

主题

40

回帖

67

积分

初级会员

积分
67
 楼主| 发表于 2025-5-20 11:50:47 | 显示全部楼层
还有一个疑问,针对于中断信号IT_VSYNC和IT_FRAME,手册上说IT_VSYNC是DCMI_VSYNC 每次从无效电平变为有效电平时都生成一个中断,而IT_FRAME是接收完成一帧数据或裁剪窗口内的数据(在裁剪模式下),生成一个中断。这两者有什么区别吗
当我VSYNC跳变的时候,就代表我的一帧数据结束了哇?这两个中断不是一个意思吗?
找到的一篇问答,但是我也没理解其中意义
https://community.st.com/t5/stm3 ... terrupt/td-p/325364
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117512
QQ
发表于 2025-5-21 06:44:51 | 显示全部楼层
ltdc的de同步信号也有这个问题。之前实测

F429驱动TFT裸屏时LTDC时序配置说明(以V6的7寸驱动为例)
https://forum.anfulai.cn/forum.p ... 8528&fromuid=58
(出处: 硬汉嵌入式论坛)
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117512
QQ
发表于 2025-5-21 06:54:27 | 显示全部楼层
Yhlr 发表于 2025-5-20 11:50
还有一个疑问,针对于中断信号IT_VSYNC和IT_FRAME,手册上说IT_VSYNC是DCMI_VSYNC 每次从无效电平变为有效 ...

vsync应该无法有效表示裁剪区内一帧的结束
回复

使用道具 举报

9

主题

40

回帖

67

积分

初级会员

积分
67
 楼主| 发表于 2025-5-21 09:39:20 | 显示全部楼层
eric2013 发表于 2025-5-21 06:54
vsync应该无法有效表示裁剪区内一帧的结束

感谢硬汉解惑。目前我这边还遇见了一个问题。目前项目上是使用DCMI与FPGA做大数据内容交互,我开辟了两倍内容的缓存区,我想在DMA半满中断和全满中断时分别对上半部分缓存和下半缓存处理,这样达到双缓存的目的。但是目前我发现每次DMA中断进入时,半满中断的标志位和全满中断的标志位同时触发?
下面是我的代码配置。(因为加密问题。无法上传完整工程)
[mw_shl_code=c,true]/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    dcmi.c
  * @brief   This file provides code for the configuration
  *          of the DCMI instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "dcmi.h"

/* USER CODE BEGIN 0 */
#include "string.h"
#include "stdlib.h"

ALIGN_32BYTES(volatile s_DCMI_ORIGINAL_DATA DCMI_DataBuffer[DCMI_PACKET_FRAMES*2]) __attribute__((section(".SRAM2")));

/* USER CODE END 0 */

DCMI_HandleTypeDef hdcmi;
DMA_HandleTypeDef hdma_dcmi;

/* DCMI init function */
void MX_DCMI_Init(void)
{

  /* USER CODE BEGIN DCMI_Init 0 */

  /* USER CODE END DCMI_Init 0 */

  /* USER CODE BEGIN DCMI_Init 1 */

  /* USER CODE END DCMI_Init 1 */
  hdcmi.Instance = DCMI;
  hdcmi.Init.SynchroMode = DCMI_SYNCHRO_HARDWARE;
  hdcmi.Init.PCKPolarity = DCMI_PCKPOLARITY_RISING;
  hdcmi.Init.VSPolarity = DCMI_VSPOLARITY_HIGH;
  hdcmi.Init.HSPolarity = DCMI_HSPOLARITY_HIGH;
  hdcmi.Init.CaptureRate = DCMI_CR_ALL_FRAME;
  hdcmi.Init.ExtendedDataMode = DCMI_EXTEND_DATA_8B;
  hdcmi.Init.JPEGMode = DCMI_JPEG_DISABLE;
  hdcmi.Init.ByteSelectMode = DCMI_BSM_ALL;
  hdcmi.Init.ByteSelectStart = DCMI_OEBS_ODD;
  hdcmi.Init.LineSelectMode = DCMI_LSM_ALL;
  hdcmi.Init.LineSelectStart = DCMI_OELS_ODD;
  if (HAL_DCMI_Init(&hdcmi) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN DCMI_Init 2 */

  /* USER CODE END DCMI_Init 2 */

}

void HAL_DCMI_MspInit(DCMI_HandleTypeDef* dcmiHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(dcmiHandle->Instance==DCMI)
  {
  /* USER CODE BEGIN DCMI_MspInit 0 */

  /* USER CODE END DCMI_MspInit 0 */
    /* DCMI clock enable */
    __HAL_RCC_DCMI_CLK_ENABLE();

    __HAL_RCC_GPIOE_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOD_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**DCMI GPIO Configuration
    PE4     ------> DCMI_D4
    PA4     ------> DCMI_HSYNC
    PA6     ------> DCMI_PIXCLK
    PA9     ------> DCMI_D0
    PA10     ------> DCMI_D1
    PD3     ------> DCMI_D5
    PB7     ------> DCMI_VSYNC
    PB8     ------> DCMI_D6
    PB9     ------> DCMI_D7
    PE0     ------> DCMI_D2
    PE1     ------> DCMI_D3
    */
    GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_0|GPIO_PIN_1;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF13_DCMI;
    HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_6|GPIO_PIN_9|GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF13_DCMI;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF13_DCMI;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF13_DCMI;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* DCMI DMA Init */
    /* DCMI Init */
    hdma_dcmi.Instance = DMA2_Stream1;
    hdma_dcmi.Init.Request = DMA_REQUEST_DCMI;
    hdma_dcmi.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_dcmi.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_dcmi.Init.MemInc = DMA_MINC_ENABLE;
    hdma_dcmi.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    hdma_dcmi.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
    hdma_dcmi.Init.Mode = DMA_CIRCULAR;
    hdma_dcmi.Init.Priority = DMA_PRIORITY_VERY_HIGH;
    hdma_dcmi.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_dcmi) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(dcmiHandle,DMA_Handle,hdma_dcmi);

    /* DCMI interrupt Init */
    HAL_NVIC_SetPriority(DCMI_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(DCMI_IRQn);
  /* USER CODE BEGIN DCMI_MspInit 1 */

  /* USER CODE END DCMI_MspInit 1 */
  }
}

void HAL_DCMI_MspDeInit(DCMI_HandleTypeDef* dcmiHandle)
{

  if(dcmiHandle->Instance==DCMI)
  {
  /* USER CODE BEGIN DCMI_MspDeInit 0 */

  /* USER CODE END DCMI_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_DCMI_CLK_DISABLE();

    /**DCMI GPIO Configuration
    PE4     ------> DCMI_D4
    PA4     ------> DCMI_HSYNC
    PA6     ------> DCMI_PIXCLK
    PA9     ------> DCMI_D0
    PA10     ------> DCMI_D1
    PD3     ------> DCMI_D5
    PB7     ------> DCMI_VSYNC
    PB8     ------> DCMI_D6
    PB9     ------> DCMI_D7
    PE0     ------> DCMI_D2
    PE1     ------> DCMI_D3
    */
    HAL_GPIO_DeInit(GPIOE, GPIO_PIN_4|GPIO_PIN_0|GPIO_PIN_1);

    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_4|GPIO_PIN_6|GPIO_PIN_9|GPIO_PIN_10);

    HAL_GPIO_DeInit(GPIOD, GPIO_PIN_3);

    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9);

    /* DCMI DMA DeInit */
    HAL_DMA_DeInit(dcmiHandle->DMA_Handle);

    /* DCMI interrupt Deinit */
    HAL_NVIC_DisableIRQ(DCMI_IRQn);
  /* USER CODE BEGIN DCMI_MspDeInit 1 */

  /* USER CODE END DCMI_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */
size_t callback = 0;
void dcmi_halfcaplt(DMA_HandleTypeDef *_hdma)
{
   
    callback++;
}

/**********************************************************************************************************
*
图片是DMA中断进入时的状态

Dingtalk_20250521093358.jpg
回复

使用道具 举报

9

主题

40

回帖

67

积分

初级会员

积分
67
 楼主| 发表于 2025-5-21 09:57:16 | 显示全部楼层
本帖最后由 Yhlr 于 2025-5-21 09:59 编辑
Yhlr 发表于 2025-5-21 09:39
感谢硬汉解惑。目前我这边还遇见了一个问题。目前项目上是使用DCMI与FPGA做大数据内容交互,我开辟了两倍 ...

发现代码没有贴完整,我直接上传C文件吧

dcmi.c

6.73 KB, 下载次数: 2

回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117512
QQ
发表于 2025-5-22 07:18:00 | 显示全部楼层
Yhlr 发表于 2025-5-21 09:57
发现代码没有贴完整,我直接上传C文件吧

感觉你的中断处理姿势不太对,dcmi本身是不是有个半传输完成和传输完成回调注册,用它的这个注册。

还有就是dma中断里面就调用hal库的dma handler函数就行
回复

使用道具 举报

9

主题

40

回帖

67

积分

初级会员

积分
67
 楼主| 发表于 2025-5-22 10:03:06 | 显示全部楼层
eric2013 发表于 2025-5-22 07:18
感觉你的中断处理姿势不太对,dcmi本身是不是有个半传输完成和传输完成回调注册,用它的这个注册。

还 ...


1.dcmi本身的话是没有这个半传输完成或者传输完成回调的。只有帧数据接收完成或者行数据接受完成中断。半满和全满中断应该是只有DMA才有的。
2.可能截图没有截取完整。在dma中断最后面确实是调用了hal库的dma handler函数。我调试的时候发现。进入中断后。半满处理函数和全满处理函数几乎是同时触发的,所以才去调试,发现两个标志通同时置位、在中断handle函数里,又同时都会对标志进行检测。
0E99FC52-9503-402c-B431-C556530622CF.png
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117512
QQ
发表于 2025-5-23 07:41:40 | 显示全部楼层
Yhlr 发表于 2025-5-22 10:03
1.dcmi本身的话是没有这个半传输完成或者传输完成回调的。只有帧数据接收完成或者行数据接受完成中断。 ...

等我出院回去了,我看下这dcmi代码。

当前还有个dma double buffer的专用dma双缓冲函数,不知道用在你这里是否合适
回复

使用道具 举报

9

主题

40

回帖

67

积分

初级会员

积分
67
 楼主| 发表于 2025-5-23 12:07:37 | 显示全部楼层
eric2013 发表于 2025-5-23 07:41
等我出院回去了,我看下这dcmi代码。

当前还有个dma double buffer的专用dma双缓冲函数,不知道用在你 ...

好的,感谢硬汉哥,祝早日康复

针对double buffer这个问题,在应用手册AN5020中说,一般是一帧数据的搬运次数超过了65535用这个双缓冲
在HAL_DCMI_Start_DMA这个函数内部,也确实是这样处理的

Dingtalk_20250523120650.jpg
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-8-12 00:49 , Processed in 0.050434 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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