FuShenxiao 发表于 2024-10-7 11:27

STM32H7S78-DK测评(三)——OV5640摄像头测试

<div class='showpostmsg'> 本帖最后由 FuShenxiao 于 2024-10-7 11:55 编辑

<p><span style="font-size:18px;"><strong>转接板设计</strong></span></p>

<p>观察开发板原理图摄像头接口可以发现,接口居然有30pin,这和软排线连接的OV5640(24pin)或者OV5640模块(2*9pin)显然是不相同的。</p>

<p>恰好我手头有一块正点原子OV5640摄像头模块,于是我就针对它完成转接板的设计。</p>

<p style="text-align: center;"></p>

<p>观察正点原子OV5640摄像头模块原理图可以轻易地与STM32H7S78-DK的摄像头接口相对应。</p>

<p>I2C1_SCL&nbsp; &nbsp;---&gt;&nbsp; &nbsp;OV_SCL</p>

<p>I2C1_SDA&nbsp; &nbsp;---&gt;&nbsp; &nbsp;OV_SDA</p>

<p>DCMI_D0 ~ DMCI_D7&nbsp; &nbsp;---&gt;&nbsp; &nbsp;OV_D0 ~&nbsp;OV_D7</p>

<p>RSTI&nbsp; &nbsp;---&gt;&nbsp; &nbsp;OV_RESET</p>

<p>PWR_EN&nbsp; &nbsp;---&gt;&nbsp; &nbsp;OV_PWDN</p>

<p>DCMI_VSYNC&nbsp; &nbsp;---&gt;&nbsp; &nbsp;OV_VSYNC</p>

<p>DCMI_HSYNC&nbsp; &nbsp;---&gt;&nbsp; &nbsp;OV_HREF</p>

<p>DCMI_PIXCLK&nbsp; &nbsp;---&gt;&nbsp; &nbsp;OV_PCLK&nbsp;</p>

<p style="text-align: center;"></p>

<p>在嘉立创中绘制原理图如下</p>

<p style="text-align: center;"></p>

<p>绘制PCB如下。为了保证相关电学特性稳定,需要在OV5640供电端加入100nF的去耦电容,在SCL和SDA两个IIC接口上加入4.7k&Omega;的上拉电阻。</p>

<p style="text-align: center;"></p>

<p>最终得到PCB正反面如下图所示</p>

<p style="text-align: center;"></p>

<p style="text-align: center;">&nbsp;</p>

<p style="text-align: center;">&nbsp;</p>

<p>具体工程文件参见<a href="https://oshwhub.com/fushenxiao/stm32h7s78-dk-she-xiang-tou-zhuan-jie-ban">STM32H7S78-DK摄像头转接板 - 立创开源硬件平台 (oshwhub.com)</a></p>

<p><span style="font-size:18px;"><strong>引脚配置</strong></span></p>

<p>首先在CubeMX中配置时钟(这里不再赘述)</p>

<p>接着分别配置DCMIPP(摄像头接口)和LTDC(显示屏接口)</p>

<p style="text-align: center;"></p>

<p style="text-align: center;">&nbsp;</p>

<p style="text-align: center;"></p>

<p style="text-align: justify;">配置两个指示灯</p>

<p style="text-align: center;"></p>

<p>完成以上操作后,生成代码</p>

<p><span style="font-size:18px;"><strong>代码编写</strong></span></p>

<p>OV5640初始化代码,需要注意的是,OV5640默认原始图像是上下翻转的,所以要使用OV5640_FLIP将图像翻转</p>

<pre>
<code>static uint32_t OV5640_Config(uint32_t Resolution, uint32_t PixelFormat)
{
OV5640_IO_t            IOCtx;
uint32_t               id;
uint32_t               ret = OV5640_OK;
static OV5640_Object_t   OV5640Obj;

/* Configure the Camera driver */
IOCtx.Address   = CAMERA_OV5640_ADDRESS;
IOCtx.Init      = BSP_I2C1_Init;
IOCtx.DeInit      = BSP_I2C1_DeInit;
IOCtx.ReadReg   = BSP_I2C1_ReadReg16;
IOCtx.WriteReg    = BSP_I2C1_WriteReg16;
IOCtx.GetTick   = BSP_GetTick;

/* Register Bus IO */
if(OV5640_RegisterBusIO (&amp;OV5640Obj, &amp;IOCtx) != OV5640_OK)
{
    ret = OV5640_ERROR;
}

/* Read ID */
if(OV5640_ReadID(&amp;OV5640Obj, &amp;id) != OV5640_OK)
{
    ret = OV5640_ERROR;
}

if(id == OV5640_ID)
{
    /* Initialize the camera Module */
    Camera_Drv = (CAMERA_Drv_t *) &amp;OV5640_CAMERA_Driver;

    OV5640_DeInit(&amp;OV5640Obj);
    if(Camera_Drv-&gt;Init(&amp;OV5640Obj, Resolution, PixelFormat) != OV5640_OK)
    {
      ret = OV5640_ERROR;
    }
    else if(Camera_Drv-&gt;MirrorFlipConfig(&amp;OV5640Obj, OV5640_FLIP) != OV5640_OK)
    {
      ret = OV5640_ERROR;
    }
}

return ret;
}</code></pre>

<p>在主函数中使用如下代码完成OV5640初始化</p>

<pre>
<code>if(OV5640_Config(OV5640_R480x272, OV5640_RGB565) != OV5640_OK)
{
/* Camera Module Config KO */
Error_Handler();
}</code></pre>

<p>DCMIPP接口获取数据信息</p>

<pre>
<code>HAL_StatusTypeDef HAL_DCMIPP_PIPE_Start(DCMIPP_HandleTypeDef *hdcmipp, uint32_t Pipe, uint32_t DstAddress,
                                        uint32_t CaptureMode)
{
assert_param(IS_DCMIPP_PIPE(Pipe));
assert_param(IS_DCMIPP_CAPTURE_MODE(CaptureMode));

/* Check pointer validity */
if ((hdcmipp == NULL) || ((DstAddress &amp; 0xFU) != 0U))
{
    return HAL_ERROR;
}

/* Check DCMIPP pipe state */
if (hdcmipp-&gt;PipeState!= HAL_DCMIPP_PIPE_STATE_READY)
{
    return HAL_ERROR;
}

/* Set Capture Mode and Destination address for the selected pipe */
DCMIPP_SetConfig(hdcmipp, Pipe, DstAddress, CaptureMode);

/* Enable Capture for the selected Pipe */
DCMIPP_EnableCapture(hdcmipp, Pipe);

return HAL_OK;
}</code></pre>

<p>在主函数中用如下代码完成DCMIPP接口数据接收,将接收到的图像信息传到CAMERA_FRAME_BUFFER中。CAMERA_FRAME_BUFFER后面的传参为当前运行模式,除了可以选择DCMIPP_MODE_CONTINUOUS,还可以使用DCMIPP_MODE_SNAPSHOT</p>

<pre>
<code>if(HAL_DCMIPP_PIPE_Start(&amp;phdcmipp, DCMIPP_PIPE0, (uint32_t)CAMERA_FRAME_BUFFER , DCMIPP_MODE_CONTINUOUS) != HAL_OK)
{
Error_Handler();
}</code></pre>

<p>也可以使用双缓冲模式,代码如下</p>

<pre>
<code>HAL_StatusTypeDef HAL_DCMIPP_PIPE_DoubleBufferStart(DCMIPP_HandleTypeDef *hdcmipp, uint32_t Pipe, uint32_t DstAddress0,
                                                    uint32_t DstAddress1, uint32_t CaptureMode)
{
assert_param(IS_DCMIPP_PIPE(Pipe));
assert_param(IS_DCMIPP_CAPTURE_MODE(CaptureMode));

/* Check pointer validity */
if ((hdcmipp == NULL) || ((DstAddress0 &amp; 0xFU) != 0U) || ((DstAddress1 &amp; 0xFU) != 0U))
{
    return HAL_ERROR;
}

/* Check DCMIPP pipe state */
if (hdcmipp-&gt;PipeState!= HAL_DCMIPP_PIPE_STATE_READY)
{
    return HAL_ERROR;
}

/* Set Capture Mode and Destination addresses for the selected pipe */
DCMIPP_SetDBMConfig(hdcmipp, Pipe, DstAddress0, DstAddress1, CaptureMode);

/* Enable Capture for the selected Pipe */
DCMIPP_EnableCapture(hdcmipp, Pipe);

return HAL_OK;
}</code></pre>

<p>最后在显示屏上显示图像,在这一步中,需要将CAMERA_FRAME_BUFFER的数据显示到屏幕的指定区域内</p>

<pre>
<code>static void MX_LTDC_Init(void)
{

/* USER CODE BEGIN LTDC_Init 0 */

/* USER CODE END LTDC_Init 0 */

LTDC_LayerCfgTypeDef pLayerCfg = {0};

/* USER CODE BEGIN LTDC_Init 1 */

/* USER CODE END LTDC_Init 1 */
hltdc.Instance = LTDC;
hltdc.Init.HSPolarity = LTDC_HSPOLARITY_AL;
hltdc.Init.VSPolarity = LTDC_VSPOLARITY_AL;
hltdc.Init.DEPolarity = LTDC_DEPOLARITY_AL;
hltdc.Init.PCPolarity = LTDC_PCPOLARITY_IPC;
hltdc.Init.HorizontalSync = 3;
hltdc.Init.VerticalSync = 3;
hltdc.Init.AccumulatedHBP = 11;
hltdc.Init.AccumulatedVBP = 11;
hltdc.Init.AccumulatedActiveW = 811;
hltdc.Init.AccumulatedActiveH = 491;
hltdc.Init.TotalWidth = 819;
hltdc.Init.TotalHeigh = 499;
hltdc.Init.Backcolor.Blue = 0;
hltdc.Init.Backcolor.Green = 0;
hltdc.Init.Backcolor.Red = 0;
if (HAL_LTDC_Init(&amp;hltdc) != HAL_OK)
{
    Error_Handler();
}
pLayerCfg.WindowX0 = xpos;
pLayerCfg.WindowX1 = xpos + ImageWidth;
pLayerCfg.WindowY0 = ypos;
pLayerCfg.WindowY1 = ypos + ImageHeight;
pLayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_RGB565;
pLayerCfg.Alpha = 255;
pLayerCfg.Alpha0 = 0;
pLayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA;
pLayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA;
pLayerCfg.FBStartAdress = (uint32_t)CAMERA_FRAME_BUFFER;
pLayerCfg.ImageWidth = ImageWidth;
pLayerCfg.ImageHeight = ImageHeight;
pLayerCfg.Backcolor.Blue = 0;
pLayerCfg.Backcolor.Green = 0;
pLayerCfg.Backcolor.Red = 0;
if (HAL_LTDC_ConfigLayer(&amp;hltdc, &amp;pLayerCfg, 0) != HAL_OK)
{
    Error_Handler();
}
/* USER CODE BEGIN LTDC_Init 2 */

/* USER CODE END LTDC_Init 2 */

}</code></pre>

<p><strong><span style="font-size:18px;">结果展示</span></strong></p>

<p>当程序正常运行时,LD1会持续闪烁,OV5640中的内容也会实时传输到屏幕上,传输显示的过程还是较为流畅的。</p>

<p>不过噪声的问题似乎有些严重,面对比较白和亮的地方会产生一些紫色的点点,但是对着暗色调的就不会产生这个问题(比如我的书包,桌子在椅背的阴影部分)。考虑PCB绘制部分,网上对OV5640的建议是信号线之间的线长差距小于100mil,这个我符合要求。再考虑软排线的长度,10cm在诸多网友看来似乎确实有些长了,下一步尝试换短一点的软排线再试试。</p>

<p>不过让我费解的是,官方的板子既然做了这个接口,为什么不顺便再做一个适配的摄像头呢,就像STM32MP135F-DK开发板还配套摄像头模块。而且这个30pin的接口根本无法适配OV5640,还得自己画转接板。</p>

<p style="text-align: center;"></p>

<p style="text-align: center;">&nbsp;</p>

<p style="text-align: center;"> &nbsp;</p>

<p style="text-align: center;">&nbsp;</p>

<p style="text-align: justify;">6ff2fc34925b327c32ce635fc53741fe<br />
&nbsp;程序源码:</p>

<p style="text-align: justify;"></p>
</div><script>                                        var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;"   style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
                                       
                                        if(parseInt(discuz_uid)==0){
                                                                                                (function($){
                                                        var postHeight = getTextHeight(400);
                                                        $(".showpostmsg").html($(".showpostmsg").html());
                                                        $(".showpostmsg").after(loginstr);
                                                        $(".showpostmsg").css({height:postHeight,overflow:"hidden"});
                                                })(jQuery);
                                        }                </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>

cc1989summer 发表于 2024-10-8 14:00

<p></p>


<p>楼主。ST官方手册有说的,配套摄像头模块型号是MB1683,Mouser上售价400+元人民币。</p>

FuShenxiao 发表于 2024-10-8 22:10

cc1989summer 发表于 2024-10-8 14:00
楼主。ST官方手册有说的,配套摄像头模块型号是MB1683,Mouser上售价400+元人民币。

<p>抱歉我没仔细读文档,不过这个摄像头也是基于OV5640的,我看e络盟要将近300块,但是感觉都挺贵的,还是自己画个转接板划算</p>

<p style="text-align:center"> &nbsp;</p>

qzgiky 发表于 2024-10-9 11:06

<p>很不错,买了几块开发板,还没有实际操作下手,学习动起来。</p>

lugl4313820 发表于 2024-10-13 19:41

<p>楼主是太历害了呀,可以分享开发板的设计吗?</p>

FuShenxiao 发表于 2024-10-13 19:58

lugl4313820 发表于 2024-10-13 19:41
楼主是太历害了呀,可以分享开发板的设计吗?

<p>这块开发板是ST官方的开发板,ST官网上能找到开发板资料的。如果你说的是OV5640转接板,我已经在嘉立创开源了。</p>
页: [1]
查看完整版本: STM32H7S78-DK测评(三)——OV5640摄像头测试