stm32f4中用SD卡存储DCMI的图像

发布者:京玩儿最新更新时间:2018-08-21 来源: eefocus关键字:stm32f4  SD卡存储  DCMI 手机看文章 扫描二维码
随时随地手机看文章

因为自己本科做的创新性实验和飞思卡尔小车都是摄像头的,研究生也做的视频处理方向。后来,想做一个小视频监制,闲麻烦,没有用那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++);

        }

    }

}


关键字:stm32f4  SD卡存储  DCMI 引用地址:stm32f4中用SD卡存储DCMI的图像

上一篇:STM32CubeMX本地升级固件库方法
下一篇:STM32F103测试SD卡串口写入测试

推荐阅读最新更新时间:2024-03-16 16:11

STM32F4_ 引领入门
Ⅰ、概述 该文写给那些想学ST芯片开发(或初级学习)的朋友,文章着重细节,或许有点简单。 笔者想告诉那些刚开始学习ST的朋友,不管你使用哪一个系列(F0、F1、F2),哪一种型号芯片,其实学习的方法和原理都是差不多的。或许不同系列,不同型号的芯片,它们之间确实存在一定的差异,但万变不离其宗,设计芯片的厂家都是按照常理(而且是人们习惯性的思维)来设计芯片,及其开发原理。 笔者在这里告诉大家吧,ST的芯片不管是硬件(引脚),还是软件(寄存器、库等)它们的兼容性都是很好的,有可能不同系列,不同型号的芯片,硬件换了,软件不换,可以达到同样的效果(笔者已经尝试过的,如:STM32F205VC和STM32F417VE,除了明显一点的速
[单片机]
<font color='red'>STM32F4</font>_ 引领入门
STM32F429 >> 20. CAN 通讯(一)
CAN 是控制器局域网络(Controller Area Network)的简称,是国际上应用最广泛的现场总线之一。 简介 物理层 与 I2C、SPI 等具有时钟信号的同步通讯方式不同,CAN 通讯并不是以时钟信号来进行同步的,它是一种异步通讯,只具有 CAN_High 和 CAN_Low 两条信号线,共同构成一组差分信号线,以差分信号的形式进行通讯。 CAN 物理层的形式主要有两种:闭环总线网络 和 开环总线网络; 1. 闭环总线网络 该网络是一种遵循 ISO11898 标准的高速、短距离“闭环网络”,它的总线最大长度为 40m,通信速度最高为 1Mbps,总线的两端各要求有一个“120 欧”的电阻。 2. 开
[单片机]
<font color='red'>STM32F4</font>29 >> 20. CAN 通讯(一)
LinkedInSTM32F4时钟系统初始化的程序代码分享
时钟系统 寄存器 LinkedInSTM32F4 时钟系统初始化是在system_stm32f4xx.c中的 SystemInit()函数中完成的。 对于系统时钟关键寄存器设置主要是在 SystemInit 函数中调用 SetSysClock()函数来设置的。我们可以先看看 SystemInit ()函数体: void SystemInit(void) { #if (__FPU_PRESENT == 1) && (__FPU_USED == 1) SCB-》CPACR |= ((3UL 《《 10*2)|(3UL 《《 11*2)); #endif RCC-》CR |= (uint32_t)0x00000001
[单片机]
LinkedIn<font color='red'>STM32F4</font>时钟系统初始化的程序代码分享
第45章 DCMI—OV2640摄像头—零死角玩转STM32-F429系列
本章参考资料:《STM32F4xx参考手册》、《STM32F4xx规格书》、库帮助文档《stm32f4xx_dsp_stdperiph_lib_um.chm》。 关于开发板配套的OV2640摄像头参数可查阅《ov2640datasheet》配套资料获知。 STM32F4芯片具有浮点运算单元,适合对图像信息使用DSP进行基本的图像处理,其处理速度比传统的8、16位机快得多,而且它还具有与摄像头通讯的专用DCMI接口,所以使用它驱动摄像头采集图像信息并进行基本的加工处理非常适合。本章讲解如何使用STM32驱动OV2640型号的摄像头。 45.1 摄像头简介 在各类信息中,图像含有最丰富的信息,作为机器视觉领域的核心部件,摄
[单片机]
第45章 <font color='red'>DCMI</font>—OV2640摄像头—零死角玩转STM32-F429系列
STM32F4 UART DMA初始化
F4的片子内部DMA初始化和F103的有很大区别,在这里引入了数据流(Stream),2个DMA共16的数据流(每个控制器8个),每个数据流则可已处理多达8个通道的数据,每个通道都有一个仲裁器处理DMA请求的优先级。下面贴出DMA请求映射事例 在DMA2中可以看出UART1的发送是数据流7的第4通道,接收是数据流5的第4通道。所以在配置DMA时要注意选择对应的数据流然后配置对应的通道,最后初始化对应数据流和对应的通道。 下面贴出代码 //****************************配置UART1 DMA发送 DMA_DeInit(DMA2_Stream7); while (DMA_GetCmd
[单片机]
<font color='red'>STM32F4</font> UART DMA初始化
DMA和UART的深刻认识--串口接收的3种工作方式(附STM32F4代码)
可能会遇到的问题: 1.能实现接收但不发送 注意是否是识别函数出错 2.DMA单次传输模式要求再初始化,否者出现第二次中断不执行。使用循环模式出现的问题是要结合配置公式: 3.DMA再次初始化不完全,会出现接收一次成功,再来一次不行。第三次能接收的问题 4.串口调试连续点击的次数太快,会使的里面的发送程序出错 一.串口uart中断接收 遇到的问题: 1、串口调试接收引脚坏掉 2.接收数据识别,使用的库函数出错 串口设置的一般步骤可以总结为如下几个步骤: 1) 串口时钟使能, GPIO 时钟使能。 2) 设置引脚复用器映射:调用 GPIO_PinAFConfig 函数。 3) GPIO 初始
[单片机]
DMA和UART的深刻认识--串口接收的3种工作方式(附<font color='red'>STM32F4</font>代码)
第17章 STM32F429之GPIO的HAL库API
17.1 初学者重要提示 1、如何阅读HAL库源码的问题 HAL库实现的函数有复杂的,也有简单的,简单的可以直接阅读代码。复杂的代码阅读起来比较耗时间,如果再配合参考手册抠每个寄存器的配置,那就更消耗时间了。所以对于这种函数,用户仅需了解每个部分实行的功能即可,而且HAL库都做了关键注释,以说明这部分实现的功能。所以用户没有必要去抠每个配置是如何实现的,仅需知道实现了什么功能。以后工程项目有需要了解具体配置时,再看即可。 2、学习本章节前,务必保证已经学习了第15章。 17.2 GPIO涉及到的寄存器 GPIO外设涉及到的寄存器比较少,也容易理解,推荐大家阅读GPIO源码的时候将参考手册中对应的寄存器功能做一个了解。
[单片机]
STM32F4 SPI2初始化及收发数据使用库函数
我的STM32F4 Discovery上边有一个加速度传感器LIS302DL。在演示工程中,ST的工程师使用这个传感器做了个很令人羡慕的东西:解算开发板的姿态。当开发板倾斜时候,处于最上边的LED点亮,其他LED不亮。同时,用MicroUSB数据线将开发板连接电脑时,开发板就会虚拟成一个鼠标。倾斜开发板时,鼠标指针会向倾斜的方向移动。归根结底,就是牛B的ST工程师用加速度传感器完成了姿态解算。 在开发板上,加速度传感器使用了SPI方式用STM32F4芯片进行通信。STM32F4的SPI1 作为主机,与LIS302Dl进行通信,读取或者写入数据。由于我没有使用过STM32的SPI口,因此在板子的空余资源中找到了SPI2接口来
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

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