当前位置: 首页 > news >正文

基于ZYNQ7000的AD9226采集卡实现(3、PS LINUX DMA驱动实现)

本章节实现第三个小目标
实现PS侧DMA驱动,提供mmap和sysfs给应用程序提供接口

DMA初始化

此驱动为platform设备驱动,设备树和驱动匹配后执行probe函数,probe函数中进行DMA初始化等操作

/** @brief : fsdma2_rx_init         dma初始化* @param : p_fdma                 fdma指针* @return:                        ...*/
int fsdma_rx_init(struct fan_sdma_rx *p_fsdma)
{struct device *p_dev;p_dev = p_fsdma->fdev.p_dev;/* 创建信号量 */sema_init(&p_fsdma->sem_rx, 0);p_fsdma->frm_len = p_fsdma->config[RX_SDMA_FRAME_LEN];p_fsdma->frm_num = p_fsdma->config[RX_SDMA_FRAME_NUM];p_fsdma->buf_size = p_fsdma->frm_len * p_fsdma->frm_num;/* 简易DMA,分配报文buffer空间 */p_fsdma->p_buffer = dma_alloc_coherent(p_dev, p_fsdma->buf_size, &p_fsdma->phy_buffer, GFP_KERNEL);if (p_fsdma->p_buffer == NULL) {dev_info(p_dev, "sdma buffer alloc failed, size=(0x%x x 0x%x)\n", p_fsdma->frm_len, p_fsdma->frm_num);return -EBUSY;					// 不释放pDma->pInfo, 由fdmaDelete()处理}memset(p_fsdma->p_buffer, 0, p_fsdma->buf_size);	//初始化值为0dev_info(p_dev, "sdma buffer addr=%px, buf_phy=0x%zx, bufSize=0x%08x\n",	\p_fsdma->p_buffer, (size_t)p_fsdma->phy_buffer, p_fsdma->buf_size);/* 配置简易DMA */p_fsdma->p_reg->sdma_frm_addr_reg = p_fsdma->phy_buffer;p_fsdma->p_reg->sdma_frm_len_reg = p_fsdma->frm_len;p_fsdma->p_reg->sdma_frm_num_reg = p_fsdma->frm_num;return 0;
}

提供给应用的接口

read接口获取环形缓冲区写指针的位置,产生接受报文中断后fpga_idx会更新,并再中断处理函数中释放sem_rx信号量。

static irqreturn_t fsdma_rx_isr(int irq, void *dev_id)
{struct fan_sdma_rx *p_fsdma = (struct fan_sdma_rx *)dev_id;p_fsdma->fpga_idx = p_fsdma->p_reg->sdma_frm_w_point_reg;p_fsdma->irq_cnt++;up(&p_fsdma->sem_rx);return IRQ_HANDLED;
}ssize_t fsdma_rx_dev_read(struct file *file, \char __user *buf, size_t cnt, loff_t *ppos)
{struct fan_sdma_rx *p_fsdma;u32 temp_buf[1];p_fsdma = (struct fan_sdma_rx *)file->private_data;down_timeout(&p_fsdma->sem_rx, msecs_to_jiffies(1000));if (cnt >= sizeof(u32)) {temp_buf[0] = p_fsdma->fpga_idx;return copy_to_user(buf, (void *)temp_buf, sizeof(u32)) ? -EFAULT : sizeof(u32);} elsereturn 0;
}

mmap用于映射DMA缓存到应用程序虚拟地址,实现高效数据访问

int fsdma_rx_dev_mmap(struct file *file, struct vm_area_struct *vma)
{struct fan_sdma_rx *p_fsdma;p_fsdma = (struct fan_sdma_rx *)file->private_data;vma->vm_flags |= VM_IO | VM_SHARED;/* !!!物理内存和用户空间的虚拟内存之间存在cache,必须加nocache标记,否则应用空间数据修改会刷新不及时 */vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);	//赋nocache标志if (remap_pfn_range(vma,					//虚拟内存区域,即设备地址将要映射到这vma->vm_start,					//虚拟空间的起始地址p_fsdma->phy_buffer>>PAGE_SHIFT,			//与物理内存对应的页帧号,物理地址右移12使vma->vm_end - vma->vm_start,				//映射区域大小,一般是页大小的整数倿vma->vm_page_prot)						//保护属性) {dev_info(p_fsdma->fdev.p_dev, "remap_pfn_range failed\n");return -EAGAIN;}return 0;
}

sysfs文件导出DMA属性到用户空间,应用程序直接读写属性文件来控制DMA,通过sysfs提供DMA使能接口如下:

static ssize_t sysfs_dma_enable_show(struct device *dev, struct device_attribute *attr, char *m)
{struct fan_dev *p_fdev = dev_get_drvdata(dev);return sprintf(m, "%d", FDEV_CSR_READ(p_fdev, FREG_DMA_RX, SDMA_EN_REG));
}static ssize_t sysfs_dma_enable_set(struct device *dev, struct device_attribute *attr,const char *m, size_t siz)
{long intv;struct fan_dev *p_fdev = dev_get_drvdata(dev);if (!siz || !sscanf(m, "%ld", &intv))return -EINVAL;FDEV_CSR_WRITE(p_fdev, FREG_DMA_RX, SDMA_EN_REG, intv ? ENABLE : DISABLE);return siz;
}static DEVICE_ATTR(dma_enable, S_IWUSR | S_IRUGO, sysfs_dma_enable_show, sysfs_dma_enable_set);

提供debugfs接口查看调试信息,调试信息包括DMA帧长,帧数量,写指针位置等

/** @brief : fsdma_rx_show          打印dma rx信息* @param : m                      ...* @param : p_fdma                 fdma指针* @return:                        ...*/
void fsdma_rx_show(struct fan_sdma_rx *p_fsdma, struct seq_file *m)
{seq_printf(m, "\nRX SDMA INFORMATION\n");seq_printf(m, "\tp_buffer=%px, fpga_idx=%zx\n", p_fsdma->p_buffer, p_fsdma->phy_buffer);seq_printf(m, "\topened=%d, fpga_idx=%u, irq_cnt=%u\n", p_fsdma->fdev.opened, p_fsdma->fpga_idx, p_fsdma->irq_cnt);seq_printf(m, "\tframe_number=%u, frame_length=%u, buffer_size=%u(byte)\n", p_fsdma->config[RX_SDMA_FRAME_NUM],	\p_fsdma->config[RX_SDMA_FRAME_LEN], p_fsdma->buf_size);seq_printf(m, "\titem_num=%u, timeout=%u(us), period=%u(us)\n", p_fsdma->config[RX_SDMA_ITEM_NUM], \p_fsdma->config[RX_SDMA_TIME_OUT], p_fsdma->config[RX_SDMA_PERIOD]);seq_printf(m, "\n\tstate=%u, frm_w_point=%u, frm_total_cnt=%u, frm_err_cnt=%u\n", p_fsdma->p_reg->sdma_state_reg,			\p_fsdma->p_reg->sdma_frm_w_point_reg,		\p_fsdma->p_reg->sdma_frm_total_count_reg,	\p_fsdma->p_reg->sdma_frm_err_count_reg);seq_printf(m, "\tcmd_w_point=%u, cmd_total_count=%u\n", p_fsdma->p_reg->sdma_cmd_w_point_reg,		\p_fsdma->p_reg->sdma_cmd_total_count_reg);
}
http://www.dtcms.com/a/269555.html

相关文章:

  • vue3 el-table 行数据沾满格自动换行
  • 【debug】git clone 报错
  • Web前端: :is(通用选择器)
  • 图像轮廓检测与绘制:OpenCV 实战指南
  • claude code-- 基于Claude 4 模型的智能编程工具,重塑你的编程体验
  • 微软上线Deep Research:OpenAI同款智能体,o3+必应双王炸
  • Web后端开发-Mybatis
  • 玩转Docker | 使用Docker部署NotepadMX笔记应用程序
  • UDP的socket编程
  • unity 模型UV重叠问题相关(重新整理)
  • BUUCTF在线评测-练习场-WebCTF习题[GXYCTF2019]BabySQli1-flag获取、解析
  • 无法访问宝塔面板 - 特网科技
  • Coze智能体平台全景解析:从零构建企业级AI应用的实战指南
  • Spring Boot 企业项目技术选型
  • UI前端大数据可视化实战策略:如何设计符合用户认知的数据展示方式?
  • 京东携手HarmonyOS SDK首发家电AR高精摆放功能
  • 开发在线商店:基于Vue2+ElementUI的电商平台前端实践
  • 二刷(李宏毅深度学习,醍醐灌顶,长刷长爽)
  • AI技术通过提示词工程(Prompt Engineering)正在深度重塑职场生态和行业格局,这种变革不仅体现在效率提升,更在重构人机协作模式。
  • 车载网络安全是当代车辆功能很重要的组成部分
  • 语言模型 RLHF 实践指南(一):策略网络、价值网络与 PPO 损失函数
  • 【OceanBase 诊断调优】—— SQL 查询触发笛卡尔积怎么处理
  • Rust BSS段原理与实践解析
  • 自动驾驶感知系统
  • OpenWebUI(4)源码学习-后端routers路由模块
  • Halcon 入门教程:卡尺工具(Measure)详解与实战应用
  • 采煤机:技术革新驱动下的全球市场格局与未来趋势
  • 无缝矩阵的音频合成与音频分离功能详解
  • 大数据在UI前端的应用深化:用户偏好的动态调整与个性化推荐
  • Next.js ISR 缓存机制与最佳实践教程