camera内存之---dma_api简述(4)

Camera 内存相关知识,真的绕不开dma相关接口。这里自我总结一下。
下面只是个人的理解,方便自己以后修正:
一般isp内部会有单向的dma,也就是摄像头数据搬运到ddr,dma一般需求连续物理内存,那么dma api会提供内存分配,映射的接口。我们可以把它看做一个框架接口,具体实现这些接口对上不用关心。对下就可以有多种实现,比如cma,单个设备预留内存,iommu指向的总线内存,以及早期用到的ion内存。Dma api 对下也提供了相关接口用于实现不同种类的操作函数。

1.简单说明几种内存地址
Pa: 物理地址,真实存在的内存,对于硬件设备的寄存器等资源,kernel是按照物理地址来管理。
Va:虚拟地址 ,人为虚拟出来的,既然是虚拟的,那么总要对应到物理地址,页码表就是用来翻译从虚拟地址到物理地址。
Iova:总线地址 ,除了cpu有页码表,设备也有页码表,那么这个内存管理单元就是iommu。那么从虚拟地址要经过cpu的译码表,再到iommu的译码表,才能转换成物理地址。
2.要想使用dma api,都要包含<linux/dma-mapping.h>文件
里面定义和声明了一些对外接口函数。dma_map_ops是对下具体内存模块需要实现的相关函数。里面的dma_addr_t地址,在启用iommu的时候,对应为iova,如果没有iommu,那就是物理地址。
对于部分dma设备地址线的原因,只能访问系统的低位内存,也就是dma寻址限制,要调用下面函数,设置mask
dma_set_coherent_mask
dma api适用于各种架构,对于驱动开发工程师来说,只需要调用dma_map_xxx,而不用调用个总线pci_map_xxx,或者platfrom_map_xxx
3. Dma一致性映射特点
是持续使用的dma buffer,所以一般是在初始化的时候map,在设备退出的时候ummap。
一般使用的时候是noncache,这样不要考虑cache的影响,cpu和dma控制器都可以看到dmabuffer的更新
Dma流式映射
需要传输的时候才map,传输完成就ummap。
所以camera是一致性映射,因为buffer是要连续的接受数据。
4. 主要api函数
cpu_addr = dma_alloc_coherent(dev, size, &dma_handle, gfp);
这个是最常用的分配和映射大段内存的接口,返回dma_handle返回总线地址,cpu_addr是虚拟地址,gfp是内存分配的flag
当然与之对应的是dma_free_coherent

我们videobuffer模块,使用的就是dma_alloc_coherent去分配dam buffer。
dma_handle = dma_map_single(dev, addr, size, direction);
这个是流式dma映射函数,让dma引擎直接在上层传下来的内存里做事。
比如一段内存,开始并不知道要往dma走,所以没用dma分配连续内存,如果这段内存要给dma用,就要调用这个函数,或者dma_map_sg,取决于dma是否支持这种模式,由于这段内存很可能是cache,在调用的时候这个函数会执行之后要执行dma_sync_single_for_cpu 这个是调用cache的flush函数。参数最后是制定方向。主要是这几个
DMA_BIDIRECTIONAL
DMA_TO_DEVICE
DMA_FROM_DEVICE
DMA_NONE

正常看完这些接口,发现实际都是操作内存的,实际没有dma控制器的相关操作。 接下来看dma engine,就是说的这些。
要说这些先得说下dma的一些概念。
1.Channel
Dma 一般有多个channel,传输数据可以选择不同的channel, 这些硬件channel看似可以同时搬运,但因为总线的访问机制,不可能做到同时,实际上内部有仲裁机制。对于使用者而言,无关乎这些,可以认为是同时的。另外除了硬件channel,软件也可以虚拟出channel来, 用软件管理这些channel。对于上层来说,操作都是一样的.
2.Request line
早先看到datasheet在这里插入图片描述
有点不解,只是给出一样表说是Request Mapping Table。
其实dma并不是所有的设备都可以使用(以前我傻b以为是这样),实际每个dma只有专门的几个模块可以使用,具体多少个模块,跟控制器内部连线有关。这个连线称为Request line,让然具体连了多少线,怎么连的我没具体去了解。用于dma和外设通信,是否有数据,fifo是否空闲等等,可以决定是否传输。所以上图应该描述的是外设线为高时候,表明当前设备可以传输。
每个设备都对应一个Request line,但通道数可以小于或者等于连接的外设总数,因为并不是所有外设都需要同时传输。
3.传输参数
传输大小:这个很好理解,一次dma传输总数据大小,为transfer size
传输宽度:在某些场景需要固定每次传输大小,比如声卡16bit采样,每次传输宽度为16bit。这个是transfer width
触发传输大小:当dma用于memory之间的传输的时候。Dma如果一个个搬运也很暂用总线时间,dma可以内部申请buffer,然后buffer填充到一定程度后,来一次dma传输。buffer的大小可以称为burst size
4.主要api接口
 include/linux/dmaengine.h
里面包含实现的主要接口函数以及结构体
dma_device
dma_chan
这两个结构体是驱动主要实现的部分。里面有相关的设备函数。
int dma_async_device_register(struct dma_device *device);
注册函数,在probe中调用,rk代码在kernel\drivers\dma pl330.c
drivers/dma/dmaengine.h
里面包含了几个cookie的接口
static inline void dma_cookie_init(struct dma_chan *chan)
static inline dma_cookie_t dma_cookie_assign(struct dma_async_tx_descriptor *tx)
static inline void dma_cookie_complete(struct dma_async_tx_descriptor *tx)
static inline enum dma_status dma_cookie_status(struct dma_chan *chan,
dma_cookie_t cookie, struct dma_tx_state *state)
static inline void dma_set_residue(struct dma_tx_state *state, u32 residue)
cookie有关的辅助接口,看函数其实是个标志

在ROS2中,需要对代码进行一些修改和调整来适应新的API和数据类型。以下是将代码移植到ROS2的示例: ```cpp #include "rclcpp/rclcpp.hpp" #include "sensor_msgs/msg/camera_info.hpp" class CheckpointDetector : public rclcpp::Node { public: CheckpointDetector() : Node("checkpoint_detector") { camera_info_subscription_ = create_subscription<sensor_msgs::msg::CameraInfo>( "camera_info", 10, std::bind(&CheckpointDetector::cameraInfoCallback, this, std::placeholders::_1)); } private: void cameraInfoCallback(const sensor_msgs::msg::CameraInfo::SharedPtr camera_info) { sensor_msgs::msg::CameraInfo my_camera_info; my_camera_info.header = camera_info->header; my_camera_info.distortion_model = camera_info->distortion_model; my_camera_info.binning_x = camera_info->binning_x; my_camera_info.binning_y = camera_info->binning_y; my_camera_info.width = camera_info->width; my_camera_info.height = camera_info->height; my_camera_info.d = camera_info->d; my_camera_info.k = camera_info->k; my_camera_info.p = camera_info->p; my_camera_info.r = camera_info->r; } rclcpp::Subscription<sensor_msgs::msg::CameraInfo>::SharedPtr camera_info_subscription_; }; int main(int argc, char** argv) { rclcpp::init(argc, argv); rclcpp::spin(std::make_shared<CheckpointDetector>()); rclcpp::shutdown(); return 0; } ``` 请注意,ROS2中使用`rclcpp`库代替了ROS中的`ros::NodeHandle`和`ros::Subscriber`等。另外,`sensor_msgs::CameraInfo`的成员变量名称也有所不同。在ROS2中,它们被改为小写字母。 你可以将这个代码段放入你的ROS2工程中,并进行构建和运行。这样,当订阅到`camera_info`主题时,`cameraInfoCallback`函数将被调用,并将`camera_info`消息的内容赋值给`my_camera_info`变量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值