嵌入式linux开发——stm32mp1完成视觉检测(一)

2023-12-18 05:12

本文主要是介绍嵌入式linux开发——stm32mp1完成视觉检测(一),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这里从今天开始给自己挖坑然后慢慢填坑……

打算基于自己买的正点原子的stm32mp157开发板还有OV5640摄像头,完成一个视觉检测的项目,最基础的版本是直接OpenCV打开摄像头然后完成简单的检测;进阶版把sklearn训练的模型通过cpp读取然后显示;最终目标是跑之前训练好的yolo模型。

那么问题就可以分成以下几步走:

  1. 驱动移植:包括linux的基础驱动,OV5640驱动,LCD驱动等等
  2. OpenCV+QT的库移植
  3. Python的机器学习库sklearn的相关模型保存还有C++读取方法
  4. 深度学习yolo的C++读取方法

那么第一篇显然就是基础的驱动移植,正式内容就此展开!

linux驱动移植

这里直接看正点原子开源的教程就可以了,里面很详细的有讲解linux驱动的移植过程,总结一下就是以下几步骤:

  1. TF-A:这个是imx这个最常见初学嵌入式linux的开发板芯片所没有的,是一个安全系统,需要完成移植
  2. U_Boot:经典的导引加载系统
  3. Linux内核:可剪裁的操作系统
  4. 根文件系统:这里主要使用Buildroot制作加载

可以直接跟着教程一步步完成。

LCD驱动

完成基础的Linux操作系统搭建后,视觉检测项目就需要一个显示器,买的开发板上就有LCD显示器,可以同样跟着教程完成LCD的驱动移植用于显示图像。

OV5640驱动

这个是这篇文章的重点!!!虽然开发板的出产系统是自带驱动的,但是那个驱动太多了,QT的界面也是已经搭建好的,对于我想从头自己做项目的话,起不到学习作用,所以也是对着出厂设置来自行移植!

这里的话,我搜了网上的很多资料,因为stm32mp1系列的开发板,根据正点原子工作人员的讲法,当时ST公司是限制了其产量,所以用的人很少,大多数都是用imx或者直接rk系列芯片,mp1系列的相关资料就很少,我网上就只找到了华清有几个相关的摄像头驱动教程,但是是直接加载到内核,而且写的文件跟正点原子的风格还是不太一样的,本着自我学习的精神,我也是自己研究出来了怎么移植,而不是网上搜到的大多数基于正点原子出厂系统的使用

进入正题,看看如何完成OV5640驱动移植。

设备树修改

需要在相关的设备树dts和dtsi文件中加入相关的内容,涉及到摄像头接口dcmi节点,ov5640节点以及相关的电源和时钟节点信息。

dcmi接口

首先需要添加dcmi节点,这是一个摄像头接口所使用的节点,这里根据正点原子的GPIO口需要在stm32mp157d-atk.dtsi文件中加入以下内容:

&pinctrl {dcmi_pins_b: dcmi-1 {pins {pinmux = <STM32_PINMUX('H', 8,  AF13)>,/* DCMI_HSYNC */<STM32_PINMUX('B', 7,  AF13)>,/* DCMI_VSYNC */<STM32_PINMUX('A', 6,  AF13)>,/* DCMI_PIXCLK */<STM32_PINMUX('H', 9,  AF13)>,/* DCMI_D0 */<STM32_PINMUX('H', 10, AF13)>,/* DCMI_D1 */<STM32_PINMUX('H', 11, AF13)>,/* DCMI_D2 */<STM32_PINMUX('H', 12, AF13)>,/* DCMI_D3 */<STM32_PINMUX('H', 14, AF13)>,/* DCMI_D4 */<STM32_PINMUX('I', 4,  AF13)>,/* DCMI_D5 */<STM32_PINMUX('B', 8,  AF13)>,/* DCMI_D6 */<STM32_PINMUX('E', 6,  AF13)>;/* DCMI_D7 */bias-disable;};};dcmi_sleep_pins_b: dcmi-sleep-1 {pins {pinmux = <STM32_PINMUX('H', 8,  ANALOG)>,/* DCMI_HSYNC */<STM32_PINMUX('B', 7,  ANALOG)>,/* DCMI_VSYNC */<STM32_PINMUX('A', 6,  ANALOG)>,/* DCMI_PIXCLK */<STM32_PINMUX('H', 9,  ANALOG)>,/* DCMI_D0 */<STM32_PINMUX('H', 10, ANALOG)>,/* DCMI_D1 */<STM32_PINMUX('H', 11, ANALOG)>,/* DCMI_D2 */<STM32_PINMUX('H', 12, ANALOG)>,/* DCMI_D3 */<STM32_PINMUX('H', 14, ANALOG)>,/* DCMI_D4 */<STM32_PINMUX('I', 4,  ANALOG)>,/* DCMI_D5 */<STM32_PINMUX('B', 8,  ANALOG)>,/* DCMI_D6 */<STM32_PINMUX('E', 6,  ANALOG)>;/* DCMI_D7 */};};
};

这一部分相当于给定了dcmi接口所使用的GPIO口的定义。

然后在stm32mp157d-atk.dts中加入如下内容:

&dcmi {status = "okay";pinctrl-names = "default", "sleep";pinctrl-0 = <&dcmi_pins_b>;pinctrl-1 = <&dcmi_sleep_pins_b>;port {dcmi_0: endpoint {remote-endpoint = <&ov5640_0>;bus-width = <8>;hsync-active = <0>;vsync-active = <0>;pclk-sample = <1>;pclk-max-frequency = <77000000>;};};
};

这里就是在设备树中添加了dcmi的节点,连接到了ov5640的节点,并且定义了一些属性内容,这一部分只要复制过来就可以了。

ov5640

需要在设备树节点中添加ov5640节点,这里可以去参考Documentation/devicetree/bindings/media/i2c/ov5640.txt,里面有通过i2c驱动ov5640需要在设备树中添加内容的示例,基于示例以及正点原子开发板的出厂配置,可以在stm32mp157d-atk.dts添加如下内容:

&i2c5 {	pinctrl-names = "default", "sleep";pinctrl-0 = <&i2c5_pins_a>;pinctrl-1 = <&i2c5_pins_sleep_a>;i2c-scl-rising-time-ns = <100>;i2c-scl-falling-time-ns = <7>;status = "okay";/delete-property/dmas;/delete-property/dma-names;ov5640: camera@3c {compatible = "ovti,ov5640";reg = <0x3c>;clocks = <&clk_ext_camera>;clock-names = "xclk";DOVDD-supply = <&v2v8>;powerdown-gpios = <&gpioe 11 (GPIO_ACTIVE_HIGH | GPIO_PUSH_PULL)>;reset-gpios = <&gpioe 1 (GPIO_ACTIVE_LOW | GPIO_PUSH_PULL)>;rotation = <180>;status = "okay";port {ov5640_0: endpoint {remote-endpoint = <&dcmi_0>;bus-width = <8>;data-shift = <2>;hsync-active = <0>;vsync-active = <0>;pclk-sample = <1>;pclk-max-frequency = <77000000>;};};};
};

这里就是把txt的内容拉过来,然后适配一下gpio的节点就可以了。

辅助节点

通过对ov5640的节点,可以发现需要时钟定义以及2.8V的电源定义,所以在stm32mp157d-atk.dts的根节点添加如下内容:

clocks {clk_ext_camera: clk-ext-camera {#clock-cells = <0>;compatible = "fixed-clock";clock-frequency = <24000000>;};};v2v8: regulator-v2v8 {compatible = "regulator-fixed";regulator-name = "v2v8";regulator-min-microvolt = <2800000>;regulator-max-microvolt = <2800000>;regulator-always-on;regulator-over-current-protection;};

之后就顺利的完成了设备树的内容一致啦。

Linux内核

这里的话其实也不用改,我按照教程学习Linux驱动的时候,按照教程移植过来的内核里面,menuconfig里面是已经把改配置的都已经配置好了。这里就我截个图,如果没配置就按照下面配置一下:

-> Device Drivers
-> <M> Multimedia support
-> V4L platform devices
-> <M> STM32 Digital Camera Memory Interface (DCMI) support
-> Device Drivers
-> <M> Multimedia support
-> I2C Encoders, decoders, sensors and other helper chips
-> <M> OmniVision OV5640 sensor support
我这边是把他都编译成模块化去生成动态加载的ko文件,之后去drivers文件夹里面复制到开发板就可以了。

以上操作均完成后就重新编译,命令如下:

make dtbs uImage LOADADDR=0XC2000040 -j16

最终移植加载

这一步也是很重要的,需要把如下的ko文件全部移动到开发板的/lib/modules/5.4.31中:

/drivers/media/i2c/ov5640.ko
/drivers/media/mc/mc.ko
/drivers/media/v4l2-core/vediodev.ko
/drivers/media/v4l2-core/v4l2-fwnode.ko
/drivers/media/v4l2-core/videobuf2-common.ko
/drivers/media/v4l2-core/videobuf2-memops.ko
/drivers/media/v4l2-core/videobuf2-v4l2.ko
/drivers/media/v4l2-core/videobuf2-dma-contig.ko
/drivers/media/platform/stm32/stm32-dcmi.ko

然后进去之后就只要输入以下命令就可以:

cd /lib/modules/5.4.31
modprobe stm32-dcmi.ko
modprobe ov5640.ko

大功告成!!

这篇关于嵌入式linux开发——stm32mp1完成视觉检测(一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/507147

相关文章

基于Linux的ffmpeg python的关键帧抽取

《基于Linux的ffmpegpython的关键帧抽取》本文主要介绍了基于Linux的ffmpegpython的关键帧抽取,实现以按帧或时间间隔抽取关键帧,文中通过示例代码介绍的非常详细,对大家的学... 目录1.FFmpeg的环境配置1) 创建一个虚拟环境envjavascript2) ffmpeg-py

OpenCV实现实时颜色检测的示例

《OpenCV实现实时颜色检测的示例》本文主要介绍了OpenCV实现实时颜色检测的示例,通过HSV色彩空间转换和色调范围判断实现红黄绿蓝颜色检测,包含视频捕捉、区域标记、颜色分析等功能,具有一定的参考... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间

Linux脚本(shell)的使用方式

《Linux脚本(shell)的使用方式》:本文主要介绍Linux脚本(shell)的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录概述语法详解数学运算表达式Shell变量变量分类环境变量Shell内部变量自定义变量:定义、赋值自定义变量:引用、修改、删

Python实例题之pygame开发打飞机游戏实例代码

《Python实例题之pygame开发打飞机游戏实例代码》对于python的学习者,能够写出一个飞机大战的程序代码,是不是感觉到非常的开心,:本文主要介绍Python实例题之pygame开发打飞机... 目录题目pygame-aircraft-game使用 Pygame 开发的打飞机游戏脚本代码解释初始化部

使用Python开发一个现代化屏幕取色器

《使用Python开发一个现代化屏幕取色器》在UI设计、网页开发等场景中,颜色拾取是高频需求,:本文主要介绍如何使用Python开发一个现代化屏幕取色器,有需要的小伙伴可以参考一下... 目录一、项目概述二、核心功能解析2.1 实时颜色追踪2.2 智能颜色显示三、效果展示四、实现步骤详解4.1 环境配置4.

Linux链表操作方式

《Linux链表操作方式》:本文主要介绍Linux链表操作方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、链表基础概念与内核链表优势二、内核链表结构与宏解析三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势六、典型应用场景七、调试技巧与

Python使用smtplib库开发一个邮件自动发送工具

《Python使用smtplib库开发一个邮件自动发送工具》在现代软件开发中,自动化邮件发送是一个非常实用的功能,无论是系统通知、营销邮件、还是日常工作报告,Python的smtplib库都能帮助我们... 目录代码实现与知识点解析1. 导入必要的库2. 配置邮件服务器参数3. 创建邮件发送类4. 实现邮件

详解Linux中常见环境变量的特点与设置

《详解Linux中常见环境变量的特点与设置》环境变量是操作系统和用户设置的一些动态键值对,为运行的程序提供配置信息,理解环境变量对于系统管理、软件开发都很重要,下面小编就为大家详细介绍一下吧... 目录前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变

Linux系统中的firewall-offline-cmd详解(收藏版)

《Linux系统中的firewall-offline-cmd详解(收藏版)》firewall-offline-cmd是firewalld的一个命令行工具,专门设计用于在没有运行firewalld服务的... 目录主要用途基本语法选项1. 状态管理2. 区域管理3. 服务管理4. 端口管理5. ICMP 阻断

Linux实现线程同步的多种方式汇总

《Linux实现线程同步的多种方式汇总》本文详细介绍了Linux下线程同步的多种方法,包括互斥锁、自旋锁、信号量以及它们的使用示例,通过这些同步机制,可以解决线程安全问题,防止资源竞争导致的错误,示例... 目录什么是线程同步?一、互斥锁(单人洗手间规则)适用场景:特点:二、条件变量(咖啡厅取餐系统)工作流