3606|1

530

帖子

4

TA的资源

一粒金砂(高级)

楼主
 

【GD32F350 都市青年家庭安防卫士 】第八贴 GD32F350如何接收OV5640数据 [复制链接]

本帖最后由 传媒学子 于 2018-10-12 21:15 编辑

【GD32F350 都市青年家庭安防卫士 】第八贴 GD32F350如何接收OV5640数据


前言

说实话,我在如何驱动上边花费了太多时间,开始自己懒,想着用GPIO读写看能不能驱动,试了很多次,结论是no.
因为,CPU处理一条指令或者一条复杂的指令,至少需要好几个周期,那么这个时间延迟,是很难捕捉到数据的。
最后,不得不硬着头皮,采用中断+DMA的方法做。



一、如何降低OV5640的PCLK速率

实际上,降低OV5640的频率是可行的。首先,你要看懂OV5640的手册,见附件1。



这图片中的寄存器,囊括了ov5640内部所有的时钟信号。

PLL1中的第二级,是一个 A ?B :C的语句,如果A成立,那么B,否则C。

其它的难度不大,但要注意从每一级的最小频率。另外,左下角的标注也要注意,YUV传输,PCLK要大于两倍的SCLK。

看懂了上图,就可以自己配置寄存器。

建议,参照网上野火和战舰的资料,或者去网上搜索一些寄存器配置,也可以参考我的,见附件2.这部分不再详细叙述。




二、GD32如何接收OV5640输出数据


我设定OV5640输出YUV4:2:0格式,我的算法只用到Y信号,输出格式是YYYY / YUYV。

这里稍微解释一下输出格式,因为关系到你得到正确数据。以160X120分辨率为例。YYYY是一行,另一行是YUYV。 YYYY的那一行是160Bytes,那么YUYV的那一行则是320Bytes. 这就是所谓的YUV 4:2:0.

所以,手册上说,YUV输出的RGB格式可以在最后输出2分频,但是YUV就不行,原因就在于此。


说了,这么多,还是需要你自己去体会。


下面说如何利用GD32F350的DMA传输。

ETI很好写,长中断和行中断分别连接2个引脚,此时千万不要尝试用中断来接收PCLK,因为中断响应时间也有几个系统周期,那么你根本采集不到想要的数据。


PCLK的速率高,用GPIO读也是困难的。


我是直接用DMA传输, TIMERA 定时器捕捉PCLK来实现的。


我刚开始很犹豫,因为我看了兆易创新给的手册,DMA中断源根本没有GPIO引脚,后来才明白,需要通过TImerA捕捉。


GD32的定时器真的很强大,捕捉功能还带滤波功能。

上代码:

  1. void config_timer(void)
  2. {
  3.          //PA1复用
  4.          gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP,GPIO_PIN_1);//PCLK
  5.          gpio_af_set(GPIOA, GPIO_AF_2, GPIO_PIN_1);
  6.         //TIM1
  7.         rcu_periph_clock_enable(RCU_TIMER1);
  8.         TIM_TimeBaseStructure.prescaler = 0;
  9.         TIM_TimeBaseStructure.alignedmode = TIMER_COUNTER_EDGE;
  10.         TIM_TimeBaseStructure.counterdirection = TIMER_COUNTER_UP;
  11.         TIM_TimeBaseStructure.period = 2;// 从0~200
  12.         TIM_TimeBaseStructure.clockdivision = TIMER_CKDIV_DIV1;
  13.         TIM_TimeBaseStructure.repetitioncounter = 0;
  14.         timer_init(TIMER1, &TIM_TimeBaseStructure);
  15.         
  16.         TIM_ICInitStructure.icpolarity = TIMER_IC_POLARITY_RISING;
  17.         TIM_ICInitStructure.icselection = TIMER_IC_SELECTION_DIRECTTI;
  18.         TIM_ICInitStructure.icprescaler = TIMER_IC_PSC_DIV2;//摄像头PCLK2分频,一行取80个点
  19.         TIM_ICInitStructure.icfilter = 0;
  20.         
  21.         timer_input_capture_config(TIMER1,TIMER_CH_1, &TIM_ICInitStructure);
  22.         timer_dma_enable(TIMER1, TIMER_DMA_CH1D);
  23.         timer_enable(TIMER1);
  24. }
复制代码



这里是DMA代码:

  1. void config_dma(void)
  2. {
  3.          rcu_periph_clock_enable(RCU_DMA);
  4.          DMA_InitStructure.periph_addr  = (uint32_t) &GPIO_ISTAT(GPIOC);//需要加&
  5.          DMA_InitStructure.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;
  6.          DMA_InitStructure.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
  7.          DMA_InitStructure.memory_addr = (uint32_t) data_buf;//不需要加&
  8.          DMA_InitStructure.memory_width = DMA_MEMORY_WIDTH_16BIT;
  9.    DMA_InitStructure.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
  10.          DMA_InitStructure.direction  = DMA_PERIPHERAL_TO_MEMORY;
  11.    DMA_InitStructure.number = 4050;
  12.          DMA_InitStructure.priority = DMA_PRIORITY_ULTRA_HIGH;
  13.         
  14.          dma_init(DMA_CH2, DMA_InitStructure);
  15.          //dma_circulation_disable(DMA_CH2);
  16.          dma_circulation_enable(DMA_CH2);
  17.         // dma_channel_enable(DMA_CH2);
  18. }
复制代码



DMA和TIMER 只需初始化就行了,CPU完全不参与,太实用了。

代码中:data _buf的定义如下:

  1. __IO uint16_t data_buf[4050]={0};
复制代码



我采集的图像不大, 就是81*50, 如何大得很,SDRM就放不下了,需要放到FLASH中,这个没尝试,大家有兴趣的可以尝试一下。


今天的分享就到这里了。谢谢~

最后指出一个坑,避免大家再次进入这个坑:
  1. /****************************************************************************************************
  2. //开始尝试用CPU查询GPIO的方法进行图像采集,尝试了1周,最终失败,因为
  3. //由于while在处理的过程中,至少会占据CPU大量周期,因此,采用此方法无法得到正确的摄像头数据**********/
  4. void camera_receive(void)
  5. {
  6.         //image_GPIO_init();//初始化摄像头输入GPIO
  7.        
  8.         while(v_switch)
  9.         {
  10.                 while(!Camera_VS);//上降沿
  11.                 vs_i++;
  12.                 if(vs_i == 2)
  13.                 {
  14.                         v_switch = 0;
  15.                         h_switch = 1;
  16.                         //printf("vs_i:%d\n", vs_i);
  17.                         //此时进入第二帧,camera_vs=1;
  18.                         //printf("vs:%d\n", Camera_VS);
  19.                        
  20.                 }
  21.                 if(vs_i != 2)
  22.                 while(Camera_VS);
  23.         }
  24.        
  25.         while(h_switch)
  26.         {
  27.                 if(Camera_VS == 0)
  28.                 {
  29.                         h_switch = 0;
  30.                 //v_switch = 1;
  31.                         //printf("hs_i:%d\n", hs_i);
  32.                         for (p_i=0;p_i<1200;p_i++) //2值化处理
  33.                         {
  34.                                 if(p_i%40==0) printf("\n");
  35.                                 printf("%x ",(uint8_t)((data_buf[p_i]>>6)&0x00ff));
  36.                         }

  37.                 }
  38.                 if(hs_i != 120) //否则会陷入死循环 因为HREF一直是低电平,所以会一直陷入while()中
  39.                 {
  40.                         while(!Camera_HS);
  41.                         if(hs_i%4 == 0) //30行
  42.                         {
  43.                          while(p_i < (160*hs_i))
  44.                          {
  45.                                         while(!Camera_PCLK);
  46.                                         if(((p_i++)%4) == 2) //取出YUYU中的第一个Y  40个点
  47.                                         {data_buf[p_j++] = (uint16_t)GPIO_ISTAT(GPIOC);}
  48.                                         while(Camera_PCLK);
  49.                                 }
  50.                         }
  51.                         hs_i++;       
  52.                         while(Camera_HS);
  53.                 }
  54.         }
  55. }
复制代码





附件1 OV5640参考手册(包含寄存器说明).pdf

1.17 MB, 下载次数: 11

附件2 OV5640寄存器初始化参考_YUV.c

5.95 KB, 下载次数: 7

此帖出自GD32 MCU论坛
点赞 关注
 

回复
举报

530

帖子

4

TA的资源

一粒金砂(高级)

沙发
 
本帖最后由 传媒学子 于 2023-6-15 19:12 编辑

小伙伴,如果觉得有帮助,记得点个赞呀 等我年纪大了,回来看看,也挺好的.. 不要雁过无声呀.. 

此帖出自GD32 MCU论坛
 
 
 

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

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/7 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表