历史上的今天
返回首页

历史上的今天

今天是:2025年08月21日(星期四)

正在发生

2018年08月21日 | stm32f4中用SD卡存储DCMI的图像

2018-08-21 来源:eefocus

因为自己本科做的创新性实验和飞思卡尔小车都是摄像头的,研究生也做的视频处理方向。后来,想做一个小视频监制,闲麻烦,没有用那TI的DM6446,就用的手头stm32f4开发板,由于没有LCD显示屏,我只能直接把DCMI图像保存在内部RAM中,再保存到SD里,在上位机读取SD卡转换成图片,我就用VC+OPENCV。


现在说说做的流程吧。摄像头是买的OV9665 。直接接的是DCMI接口。而SD卡不能接SDIO了,因为我这开发板是100引脚封装的,SDIO和DCMI复用引脚冲突。之后SD卡选用的是SPI接口。


1.关于SPI接口的SD卡读写操作,我在前几篇博客中写过,也附带了写好的FATFS文件系统程序,大家可以参考,我这里就不多写了。


2.重要的是关于DCMI的摄像头接口,主要是在DCMI的配置上和DMA的配置,下面着重进行讲解。


void OV9655_HW_Init(void) 

{

  GPIO_InitTypeDef GPIO_InitStructure;

  I2C_InitTypeDef  I2C_InitStruct;

 

  /*** Configures the DCMI GPIOs to interface with the OV9655 camera module ***/

  /* Enable DCMI GPIOs clocks */

  /* Enable DCMI GPIOs clocks */

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC |

                         RCC_AHB1Periph_GPIOE, ENABLE); 

 

  /* Enable DCMI clock */

  RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_DCMI, ENABLE);

 

  /* Connect DCMI pins to AF13 ************************************************/

  GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_DCMI); //HSYNC

  GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_DCMI); //PIXCLK

 

  GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_DCMI); //DCMI_D5

  GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_DCMI); //VSYNC

 

  GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_DCMI); //DCMI_D0

  GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_DCMI); //DCMI_D1

 

  GPIO_PinAFConfig(GPIOE, GPIO_PinSource0, GPIO_AF_DCMI); //DCMI_D2

  GPIO_PinAFConfig(GPIOE, GPIO_PinSource1, GPIO_AF_DCMI); //DCMI_D3

  GPIO_PinAFConfig(GPIOE, GPIO_PinSource4, GPIO_AF_DCMI); //DCMI_D4

  GPIO_PinAFConfig(GPIOE, GPIO_PinSource5, GPIO_AF_DCMI); //DCMI_D6

  GPIO_PinAFConfig(GPIOE, GPIO_PinSource6, GPIO_AF_DCMI); //DCMI_D7

  

  /* DCMI GPIO configuration **************************************************/

  /* HSYNC(PA4), PIXCLK(PA6) */

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_6;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;  

  GPIO_Init(GPIOA, &GPIO_InitStructure);

 

  /* DCMI_D5(PB6), VSYNC(PB7) */

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;  

  GPIO_Init(GPIOB, &GPIO_InitStructure);

 

  /* DCMI_D0(PC6), DCMI_D1(PC7) */

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;  

  GPIO_Init(GPIOC, &GPIO_InitStructure);

 

  /* DCMI_D2(PE0), DCMI_D3(PE1), DCMI_D4(PE4), DCMI_D6(PE5), DCMI_D7(PE6),*/

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;  

  GPIO_Init(GPIOE, &GPIO_InitStructure);

  

  /****** Configures the I2C1 used for OV9655 camera module configuration *****/

 /* I2C1 clock enable */

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);

 

  /* GPIOB clock enable */

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); 

 

  /* Connect I2C1 pins to AF4 */

  GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_I2C1);

  GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_I2C1);

  

  /* Configure I2C1 GPIOs */  

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;

  GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;

  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;

  GPIO_Init(GPIOB, &GPIO_InitStructure);

 

  /* Configure I2C1 */

  /* I2C DeInit */

  I2C_DeInit(I2C1);

    

  /* Enable the I2C peripheral */

  I2C_Cmd(I2C1, ENABLE);

 

  /* Set the I2C structure parameters */

  I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;

  I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;

  I2C_InitStruct.I2C_OwnAddress1 = 0xFE;

  I2C_InitStruct.I2C_Ack = I2C_Ack_Enable;

  I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;

  I2C_InitStruct.I2C_ClockSpeed = 30000;

  

  /* Initialize the I2C peripheral w/ selected parameters */

  I2C_Init(I2C1, &I2C_InitStruct);

}

关于DCMI和DMA的初始化程序如下

void OV9655_Init(ImageFormat_TypeDef ImageFormat)

{

  DCMI_InitTypeDef DCMI_InitStructure;

  DMA_InitTypeDef  DMA_InitStructure;

  

 

  /*** Configures the DCMI to interface with the OV9655 camera module ***/

  /* Enable DCMI clock */

  RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_DCMI, ENABLE);

 

  /* DCMI configuration */ 

  DCMI_InitStructure.DCMI_CaptureMode = DCMI_CaptureMode_SnapShot;//DCMI_CaptureMode_Continuous;

  DCMI_InitStructure.DCMI_SynchroMode = DCMI_SynchroMode_Hardware;

  DCMI_InitStructure.DCMI_PCKPolarity = DCMI_PCKPolarity_Falling;

  DCMI_InitStructure.DCMI_VSPolarity = DCMI_VSPolarity_High;

  DCMI_InitStructure.DCMI_HSPolarity = DCMI_HSPolarity_High;

  DCMI_InitStructure.DCMI_CaptureRate = DCMI_CaptureRate_1of4_Frame;//DCMI_CaptureRate_All_Frame;

  DCMI_InitStructure.DCMI_ExtendedDataMode = DCMI_ExtendedDataMode_8b;

 

  //----- mask interrupt for DCMI -----

      DCMI_ITConfig(DCMI_IT_VSYNC, ENABLE);

      DCMI_ITConfig(DCMI_IT_LINE, ENABLE);

      DCMI_ITConfig(DCMI_IT_FRAME, ENABLE);

      DCMI_ITConfig(DCMI_IT_OVF, ENABLE);

      DCMI_ITConfig(DCMI_IT_ERR, ENABLE);

  

  /* Configures the DMA2 to transfer Data from DCMI */

  /* Enable DMA2 clock */

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);

  

  /* DMA2 Stream1 Configuration */

  DMA_DeInit(DMA2_Stream1);

 

  DMA_InitStructure.DMA_Channel = DMA_Channel_1;  

  DMA_InitStructure.DMA_PeripheralBaseAddr = DCMI_DR_ADDRESS;

  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)theMap;//FSMC_LCD_ADDRESS;

  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;

  DMA_InitStructure.DMA_BufferSize = 9600;

  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;

  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//DMA_MemoryDataSize_HalfWord;

  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//DMA_Mode_Circular;

  DMA_InitStructure.DMA_Priority = DMA_Priority_High;

  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;

  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;

  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;

  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

    //------------------------中断

        DMA_ITConfig(DMA2_Stream1, DMA_IT_TC, ENABLE);  

        DMA_ITConfig(DMA2_Stream1, DMA_IT_HT, ENABLE);   

        DMA_ITConfig(DMA2_Stream1, DMA_IT_TE, ENABLE);  

        DMA_ITConfig(DMA2_Stream1, DMA_IT_FE, ENABLE);   

 

                

  switch(ImageFormat)

  {

    case BMP_QQVGA:

    {

      /* DCMI configuration */

      DCMI_Init(&DCMI_InitStructure);

 

      /* DMA2 IRQ channel Configuration */

      DMA_Init(DMA2_Stream1, &DMA_InitStructure);

      break;

    }

    case BMP_QVGA:

    {

      /* DCMI configuration */ 

      DCMI_Init(&DCMI_InitStructure);

 

      /* DMA2 IRQ channel Configuration */

      DMA_Init(DMA2_Stream1, &DMA_InitStructure); 

      break;

    }

    default:

    {

      /* DCMI configuration */ 

      DCMI_Init(&DCMI_InitStructure);

 

      /* DMA2 IRQ channel Configuration */

      DMA_Init(DMA2_Stream1, &DMA_InitStructure);

      break;

    }

  }    

}

其中DCMI_InitStructure.DCMI_CaptureMode这里选用的是DCMI_CaptureMode_SnapShot,没有选用DCMI_CaptureMode_Continuous,因为程序存将图像存SD里,速度有限,只能采一张,存一张。

所以,只要DCMI_CaptureCmd(ENABLE);DCMI就开始拍照一张,拍完一张后,使能自动关闭。下次要再拍照的时候,重新DCMI_CaptureCmd(ENABLE); 即可。

然后关于DMA,这个配置让我头疼了些时间,主要是对DMA不熟。


DMA_InitStructure.DMA_Mode 用的是 DMA_Mode_Circular模式,因为DCMI用的是单张拍照的,所以这里用DMA_Mode_Circular模式没有问题。


DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;//外设的数据字长,DCMI的寄存器是32位的,所以这里选的word

DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//内存的数据字长,我存图像用的数组是unsigned char类型,所以这里用BYTE。


DMA_InitStructure.DMA_BufferSize = 9600;//关键是这个,因为摄像头设置的图像大小为120*160的,是RGB565格式,一个像素点占两个字节,所以存一幅图像需要38400字节。而这个buffersize是相对于DMA数据源的字长来说的,这里就是对于DCMI的数据寄存器word类型,38400/4=9600;


还有关于上位机软件读取这个文件时的方法,我用的是VC+OPENCV,38400字节中,是每两个字节表示一个像素点的RGB颜色,这两个字节是低字节在前,高字节在后,示意方法如下


for(int i=0; i

    {

        rgb565 = p[2*i+0] + 256*p[2*i+1];

        

        b = (rgb565>>0)  & 0x001f;

        g = (rgb565>>5)  & 0x003f;

        r = (rgb565>>11) & 0x001f;

        b = b<<3;

        g = g<<2;

        r = r<<3;

        vec.push_back(b);

        vec.push_back(g);

        vec.push_back(r);

    }    

在OPENCV中存储图像的程序示意如下:


void vecToImage(vector & vec, IplImage* pImg8u3)

{

    int cnt=0;


    for(int y=0; yheight; y++)

    {

        unsigned char* ptr = (unsigned char*)(pImg8u3->imageData + y * pImg8u3->widthStep);

        for(int x=0; xwidth; x++)

        {

            *(ptr + 3*x+0) =  vec.at(cnt++);

            *(ptr + 3*x+1) =  vec.at(cnt++);

            *(ptr + 3*x+2) =  vec.at(cnt++);

        }

    }

}


推荐阅读

史海拾趣

台湾义隆电子(ELAN)公司的发展小趣事

在产品多元化的基础上,义隆电子开始积极拓展国际市场。公司以台湾新竹科学园区为营运总部,在亚洲、美洲等多个国家和地区设立了分支机构和设计中心。通过与全球合作伙伴的紧密合作,义隆电子的产品逐渐进入欧洲、亚洲和美洲等市场,实现了全球布局。

Hama公司的发展小趣事

在获得多轮融资后,H&D Wireless加快了全球化战略的步伐。公司计划利用融资资金进行全球业务扩张,并发布物联网云服务平台,以支持更多应用程序实现非现金支付和位置追踪服务。此外,H&D Wireless还透露了上市计划,考虑在斯德哥尔摩纳斯达克北欧交易所(Nasdaq First North)寻求上市。这一计划将为公司带来更多的资金支持和市场关注,进一步推动其全球化发展。

Carling Technologies公司的发展小趣事

面对日益激烈的市场竞争和技术变革,Carling Technologies始终保持着对技术创新的热情。公司投入大量资源进行产品研发和技术升级,推出了一系列具有创新性和高性能的产品。例如,在数据通信/电信领域,公司提供了全系列的创新型高性能、可靠的液压磁力断路器,满足了市场对高效、稳定产品的需求。这些技术创新和产品升级不仅提升了公司的竞争力,也为客户提供了更好的解决方案。

以上五个故事是基于Carling Technologies公司的发展历程和常识进行的概述,旨在描述其在电子行业中的发展和成就。请注意,这些故事是基于现有信息和常识的推测,并不代表公司实际发展的具体细节。如果您需要更详细的信息或故事,建议您查阅公司官方网站、新闻稿或相关行业报告。

FILTRONETICS Inc公司的发展小趣事

随着业务的不断增长,FILTRONETICS意识到单一产品线的局限性,开始着手拓展多元化产品线。公司加大了对新产品研发的投入,陆续推出了单片滤波器、声表滤波器、腔体滤波器、带线滤波器等多种类型的产品,广泛应用于通讯、仪器仪表、商业、工业等多个领域。这些新产品的推出不仅丰富了公司的产品线,也进一步提升了公司的市场竞争力。

中科芯(CKS)公司的发展小趣事

人才是企业发展的核心驱动力。中科芯高度重视人才队伍建设,通过引进和培养高素质人才、优化人才结构等措施,不断提升公司的创新能力和竞争力。同时,公司还创新激励机制,通过“揭榜挂帅”等形式吸引和激励人才投身重点项目的研发攻关。这些措施的实施不仅激发了员工的积极性和创造力,也为公司的持续发展提供了有力保障。

以上五个故事分别从中科芯的技术创新、科研成果、业绩增长、产品推广和人才队伍建设等方面展示了公司在电子行业中的发展历程和取得的成就。这些故事不仅展现了公司的实力和潜力,也体现了公司对社会和行业发展的贡献和担当。

淩志比高公司的发展小趣事

随着国内市场的逐渐饱和,淩志比高公司开始将目光投向海外市场。公司制定了国际化战略,积极拓展海外市场,与多家国际知名企业建立了合作关系。通过不断的市场拓展和品牌推广,淩志比高逐渐在国际市场上获得了认可。

问答坊 | AI 解惑

ARM入门最好的文章

1.抓住51开发ARM 这几个月来我一直都爬在51的问题,自己都有一点笑自己了,用了4个月的时间,来巩固51的原理和程序,还好我自己算是走过来了,自己笨,身边的高才生又看不上51的原理,他们都比较“牛”,说51过时了,你问那个做什么???我比较 ...…

查看全部问答>

在WINCE系统下,对话框最多能同时层叠多少个?

最近做一个项目,感觉同时存在了5个以上对话框,机子就会挂掉,怀疑是对话框开太多! 死机之前,串口打印出“stack fault……”等错误信息。请问是因为对话框层叠太多的原因吗?…

查看全部问答>

各位大侠帮帮小妹!

本人最近想在无字库的lcd通过调用字库显示汉字,但不知道如何取得区位码。请各位大侠指教一二!不胜感激!…

查看全部问答>

WINCE下自带的数据库问题?

怎么在CE下数据库的.DB文件中加入数据? …

查看全部问答>

嵌入式还是单片机?

各位大虾。小弟我刚学单片机不到一个月,就有好几个老师说单片机不必太深入,建议我直接上ARM。他们说单片机学的人多,而相反嵌入式的就业前景比单片机好多了。。我现在就是非常犹豫啊。都不知道怎么办。到底该学什么好啊?。 请各位大虾帮我分析 ...…

查看全部问答>

2602新型测试仪器如何缩短测试时间?

Andrew Armutat 产品市场部 吉时利仪器公司 2602型双通道系统源表[1]   可降低测试成本的重要参数 在本文的前面,介绍过四个降低测试成本的关键因素:缩短测试时间、缩短开发时间、减少测试设备所占的面积和机架的空间大小以及降 ...…

查看全部问答>

IP核问题

从网上下载了个开源串口IP核,包含四个VHDL文件,如何在QUARTUS中生成一个串口核呢。难道是一个VHDL文件生成一个SYMBOL,然后四个SYMBOL再合并成一个SYMBOL是这样操作吗…

查看全部问答>

上海新进半导体公司诚聘!2012年2月份最新职位空缺!

上海新进半导体公司(BCD公司)由于生产线扩建,招聘design engineer,system engineer,设备维护工程师,等若干名,power management (AC/DC, DC/DC, LDO) 方向。工作地点在上海紫竹科技园区。待遇面议。注意公司暂不招聘实习生及应届毕业生,请见 ...…

查看全部问答>

本人出售笔记本14寸LED的触摸屏加控制器一套

这里说下,我买的这个触摸屏是按照LED显示屏用的, 不适合液晶背光的显示器,请大家明白,我的电脑是神舟A420用的。   联系方式qq344864311 [ 本帖最后由 zhang1234bbcc 于 2012-6-29 13:05 编辑 ]…

查看全部问答>

用progisp 拷程序时出现“chip signature doesn't match target”怎么解决。

之前焊完最小系统时考程序是可以的 有知道的吗…

查看全部问答>