Zynq-Linux移植学习笔记之64- 国产ZYNQ在linux下配置国产5396芯片
1、背景介绍
复旦微ZYNQ通过SPI配置国产JEM5396,框图如下:

现在需要在linux下的应用程序内配置JEM5396的寄存器。其中FMQL和进口的XILINX ZYNQ类似,JEM5396和进口的BCM5396兼容。因此可以参考进口ZYNQ在linux下配置BCM5396过程。Zynq-Linux移植学习笔记之41-linux下通过SPI访问broadcom 5396交换芯片_bcm5396-CSDN博客
2、内核配置
内核中将spidev.c编到内核内,同时在spidev.c中添加jem5396设备


3、设备树配置
设备树中在spi节点下添加jem5396设备

4、应用修改
由于复旦微FMQL中采用的SPI控制器不是SPI-CADENCE IP,所以不需要和进口ZYNQ那样改驱动。但是需要在应用APP中修改。参考JEM5396提供的差异说明
我司配套SPI驱动:使用ARM STM32F107VC型芯片内建的SPI IP实现SPI Master与5396 SPI Slave的通信。配置时需注意以下几点:
1.经过测试,5396 spi的CPHA选择必须为2Egde(CPOL可以为High或Low),才能保证与5396正常通信。
2. 由于内部设计原因导致spi接口的cs控制与sck时钟信号,两者可能出现信号对齐或大体重合,继而导致采样数据不准。因此,在时序上需要 cs触发后的第一个时钟沿向后延几个相位。如红框图位置
应用代码如下:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>#define NREAD (0x60)
#define NWRITE (0x61)#define SIO (0xF0)
#define STS (0xFE)
#define SPG (0xFF)#define SPIF (0x80)
#define RACK (0x20)
#define RXRDY (0x02)
#define TXRDY (0x01)uint8_t mode = SPI_CPHA|SPI_CPOL;
uint8_t bits = 8;
uint32_t speed = 2000000;
uint16_t delay=0;unsigned int readBCM5396Reg(unsigned char page,unsigned char offset,unsigned char regType)
{unsigned char wr_buf[32],rd_buf[32],*bp;int len, status;struct spi_ioc_transfer xfer[2];int file;unsigned int result;int ret=0;file = open("/dev/spidev2.0", O_RDWR);if (file<0) {printf("open 5396 error\n");return 1;}if (ioctl(file, SPI_IOC_WR_MODE, &mode) < 0){printf("SPI_IOC_WR_MODE failed\n");}if (ioctl(file, SPI_IOC_RD_MODE, &mode) < 0){printf("SPI_IOC_RD_MODE failed\n");}memset(wr_buf, 0, sizeof(wr_buf));memset(rd_buf, 0, sizeof(rd_buf));memset(xfer,0,sizeof(xfer));wr_buf[0] = NREAD;wr_buf[1] = STS;xfer[0].tx_buf = (unsigned long) wr_buf;xfer[0].rx_buf = (unsigned long) rd_buf;xfer[0].len = 3;status = ioctl(file, SPI_IOC_MESSAGE(1), xfer);printf("#1 status is %d\n",status);usleep(10000);printf("#1 NREAD response(%d): ", status);for (bp = rd_buf; len; len--)printf("%02x ", *bp++);printf("\n");wr_buf[0] = NWRITE;wr_buf[1] = SPG;wr_buf[2] = page;xfer[0].tx_buf = (unsigned long) wr_buf;xfer[0].rx_buf = (unsigned long) rd_buf;xfer[0].len = 3;status = ioctl(file, SPI_IOC_MESSAGE(1), xfer);//printf("#2 status is %d\n",status);//usleep(10000);printf("#2 NWRITE response(%d): ", status);for (bp = rd_buf; len; len--)printf("%02x ", *bp++);printf("\n");wr_buf[0] = NREAD;wr_buf[1] = offset;xfer[0].tx_buf = (unsigned long) wr_buf;xfer[0].rx_buf = (unsigned long) rd_buf;xfer[0].len = 3;status = ioctl(file, SPI_IOC_MESSAGE(1), xfer);//printf("#3 status is %d\n",status);//usleep(10000);printf("#3 NREAD response(%d): ", status);for (bp = rd_buf; len; len--)printf("%02x ", *bp++);printf("\n");wr_buf[0] = NREAD;wr_buf[1] = STS;xfer[0].tx_buf = (unsigned long) wr_buf;xfer[0].rx_buf = (unsigned long) rd_buf;xfer[0].len = 3;status = ioctl(file, SPI_IOC_MESSAGE(1), xfer);//printf("#4 status is %d\n",status);//usleep(10000);printf("#4 NREAD response(%d): ", status);for (bp = rd_buf; len; len--)printf("%02x ", *bp++);printf("\n");wr_buf[0] = NREAD;wr_buf[1] = SIO;xfer[0].tx_buf = (unsigned long) wr_buf;xfer[0].rx_buf = (unsigned long) rd_buf;xfer[0].len = 2+regType/8;status = ioctl(file, SPI_IOC_MESSAGE(1), xfer);//printf("#5 status is %d\n",status);len=status;if (status < 0) {perror("SPI_IOC_MESSAGE");return -1;}printf("#5 NREAD response(%d): ", status);for (bp = rd_buf; len; len--)printf("%02x ", *bp++);printf("\n");bp = rd_buf;memcpy(&result,bp+2,regType/8);printf("read result is 0x%x\n",result);close(file);return result;
}unsigned int writeBCM5396Reg(unsigned char page,unsigned char offset,unsigned char *pBuffer,unsigned char regType)
{unsigned char wr_buf[32],rd_buf[32],*bp;int len, status;struct spi_ioc_transfer xfer[2];int file,i;unsigned int result;file = open("/dev/spidev2.0", O_RDWR);if (file<0) {printf("open 5396 error\n");return 1;}if (ioctl(file, SPI_IOC_WR_MODE, &mode) < 0){printf("SPI_IOC_WR_MODE failed\n");}if (ioctl(file, SPI_IOC_RD_MODE, &mode) < 0){printf("SPI_IOC_RD_MODE failed\n");}memset(wr_buf, 0, sizeof(wr_buf));memset(rd_buf, 0, sizeof(rd_buf));memset(xfer,0,sizeof(xfer));wr_buf[0] = NREAD;wr_buf[1] = STS;xfer[0].tx_buf = (unsigned long) wr_buf;xfer[0].rx_buf = (unsigned long) rd_buf;xfer[0].len = 3;status = ioctl(file, SPI_IOC_MESSAGE(1), xfer);wr_buf[0] = NWRITE;wr_buf[1] = SPG;wr_buf[2] = page;xfer[0].tx_buf = (unsigned long) wr_buf;xfer[0].rx_buf = (unsigned long) rd_buf;xfer[0].len = 3;status = ioctl(file, SPI_IOC_MESSAGE(1), xfer);wr_buf[0] = NWRITE;wr_buf[1] = offset;for(i=0;i<regType/8;i++){wr_buf[2+i] = pBuffer[i];}xfer[0].tx_buf = (unsigned long) wr_buf;xfer[0].rx_buf = (unsigned long) rd_buf;xfer[0].len = 2+(regType/8);status = ioctl(file, SPI_IOC_MESSAGE(1), xfer);close(file);return status;
}int main()
{unsigned int temp;unsigned char buf[10];int res=0;buf[0]=0x00;buf[1]=0x0f;buf[2]=0x00;temp=readBCM5396Reg(0x2,0x30,32);printf("page 0x2 offset 0x30 is 0x%x\n",temp);sleep(1);//连续读之间需要加时延temp=readBCM5396Reg(0x31,0x00,32);printf("before write page 0x31 offset 0x0 is 0x%x\n",temp);res=writeBCM5396Reg(0x31, 0x00, buf,32);//Port 0 - Slot 10if(res<0){printf("write bcm5396 error\n");}temp=readBCM5396Reg(0x31,0x00,32);printf("after write page 0x31 offset 0x0 is 0x%x\n",temp);return 0;
}
5、测试验证
系统启动后,执行应用,可以看到能够正常读写

注意:国产JEM5396在连续读写寄存器时存在问题,连续两次读之间需要加1s延迟。具体看应用示例。
另外,调试时发现有个小工具很好用spidev_test,这样就不需要自己写代码,直接模拟SPI读写时序
spidev_test -D /dev/spidev2.0 -s 2000000 -H -O -p "\x60\xFE\x00" -v #NREAD,STS,rd_sts_spif(0x00)spidev_test -D /dev/spidev2.0 -s 2000000 -H -O -p "\x61\xFF\x02" -v #NWRITE,SPG,page(0x02)spidev_test -D /dev/spidev2.0 -s 2000000 -H -O -p "\x60\x30\x00" -v #NREAD,reg(0x30),rd_nonespidev_test -D /dev/spidev2.0 -s 2000000 -H -O -p "\x60\xFE\x00" -v #NREAD,STS,rd_sts_rack(0xA0)spidev_test -D /dev/spidev2.0 -s 2000000 -H -O -p "\x60\xF0\x00" -v #NREAD,SIO,rd_5396_id(0x60)

上图为读出JEM5396的ID操作
Spidev_test具体用法如下:

当然,使用这个工具的前提是有个正确的时序,然后通过spidev_test去实现这个时序,比如spidev_test中设置-H(配置CPHA)和-O(配置CPOL),这个与芯片说明中的“经过测试,5396 spi的CPHA选择必须为2Egde(CPOL可以为High或Low),才能保证与5396正常通信 ”描述一致。
相关文章:
Zynq-Linux移植学习笔记之64- 国产ZYNQ在linux下配置国产5396芯片
1、背景介绍 复旦微ZYNQ通过SPI配置国产JEM5396,框图如下: 现在需要在linux下的应用程序内配置JEM5396的寄存器。其中FMQL和进口的XILINX ZYNQ类似,JEM5396和进口的BCM5396兼容。因此可以参考进口ZYNQ在linux下配置BCM5396过程。Zynq-Linux移…...
系统架构设计师-第19章-大数据架构设计理论与实践-软考学习笔记
传统数据处理系统存在的问题 传统数据处理系统存在以下问题: 1. 数据孤岛问题:不同部门或系统之间的数据隔离,数据无法共享和整合。 2. 数据不一致性问题:由于数据维护分散,同一数据在不同系统或部门中可能存在不同…...
论坛搭建.
目录 一.配置软件仓库 二.安装http php miriadb 三.配置数据库 四.源码拖拽并解压 五.防火墙通过 六.浏览器安装测试 七.界面参数设置 一.配置软件仓库 1.进入仓库目录 cd /etc/yum.repos.d 2.创建仓库文件 vim local.repo 3.在 local.repo中写入:(粘贴的时候注意位…...
三种前端埋点方式
什么是埋点 埋点是数据采集领域(尤其是用户行为数据采集领域)的术语,指的是针对特定用户行为或事件进行捕获、处理和发送的相关技术及其实施过程。比如用户某个icon点击次数、观看某个视频的时长等等。 我们可以知道埋点实际上是对特定事件或…...
html获取网络数据,列表展示 第二种
html获取网络数据,列表展示 第二种 js遍历json数组中的json对象 image.png || - 判断数据是否为空,为空就显示 - <!DOCTYPE html> <html><head><meta charset"utf-8"><title>网页列表</title><script …...
【Python 算法】信号处理通过陷波滤波器准确去除工频干扰
对于一个信号来说通常汇入工频噪声往往是因为交流电产生的电泳,影响了我们信号采集导致信号上存在工频干扰。 那么matlab去除工频干扰可以通过陷波滤波器实现。 通常使用scipy.signal实现信号的处理。 Scipy的信号处理模块(scipy.signal)来创…...
Redis(08)| 线程模型
一、redis 的线程模型 redis 内部使用文件事件处理器 file event handler,它是单线程的,所以redis才叫做单线程模型。它采用IO多路复用机制同时监听多个 socket,将产生事件的 socket 压入内存队列中,事件分派器根据 socket 上的事…...
Java14-16新特性
目录 一、Java14新特性 1、instanceof模式匹配 2、友好的空指针(NullPointerException)提示 3、record类型 二、Java15新特性 1、Sealed Classes 2、CharSequence新增方法 3、TreeMap新增方法 4、文本块 5、无需配置环境变量 三、Java16新特性 1、包装类构造方法的…...
中兴再推爆款,双2.5G网口的巡天AX3000Pro+仅需299元
10月30日消息,中兴新款路由器中兴巡天AX3000Pro将于10月31日20:00正式开售,当前可在天猫、京东及红魔商城进行预约,首发价格299元。 据了解,中兴巡天AX3000Pro是中兴智慧家庭推出的巡天系列新品,也是当前市场上唯一一款300元价位内配备双2.5G网口的路由器。 中兴巡天AX3000Pro…...
【系统架构】架构风格专题
目录 1、定义 2、通用架构风格分类 3、架构风格比较 4、示例:管道-过滤 VS 数据仓库)比较因素分析 1、定义 架构风格:描述某一特定应用领域中系统组织方式的惯用模式,反映了领域中众多系统所共有的结构和语义特性,…...
【Qt】盒子布局、网格布局、表单布局和堆栈布局
盒子布局 QBoxLayout可以在水平方向或垂直方向上排列控件,分别派生了QHBoxLayout、QVBoxLayout子类。 QHBoxLayout:水平布局,在水平方向上排列控件,即:左右排列。QVBoxLayout:垂直布局,在垂直…...
GO语言,半自动打怪
仅供学习参考,切勿用于商业用途 package mainimport ("fmt""github.com/go-vgo/robotgo""math/rand""time" )const (taskNum 7 )type Task struct {Name stringSleepTime1 intSleepTime2 intFunc func() }fu…...
【Java 进阶篇】Java登录案例详解
登录是Web应用程序中常见的功能,它允许用户提供凭证(通常是用户名和密码)以验证其身份。本文将详细介绍如何使用Java创建一个简单的登录功能,并解释登录的工作原理。我们将覆盖以下内容: 登录的基本概念创建一个简单的…...
Vue 菜单导航栏,轮播图
导航菜单栏结构和样式代码实现 一级导航栏 views/HomeView.vue <template><div><Shortcut></Shortcut><Header></Header><div class"inner"><Navigation></Navigation></div><div>我是主页&l…...
讲述为什么要学习Adobe XD以及 Adobe XD下载安装
首先 我们要了解 Adobe XD 是个什么东西 XD是Adobe公司专门开发出来面向交互、界面设计的矢量绘图工具。 然后是 他可以做什么? 最基本的 可以做UI界面设置 所有 手机 平板 电脑等设备的UI界面 我们都可以通过XD完成 还有就是原型设置 我们可以做各种界面图 还有…...
Netty复习:(1)Http server: hello world
一、加依赖 <dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.72.Final</version></dependency>二、创建自定义的handler package cn.edu.tju.handler;import io.netty.buffer.ByteB…...
【Python 千题 —— 基础篇】加法计算
题目描述 题目描述 编写一个程序,接受用户输入的两个数字,然后计算这两个数字的和,并输出结果。 输入描述 输入两个数字,用回车隔开两个数字。 输出描述 程序将计算这两个数字的和,并输出结果。 示例 示例 ① …...
基于纵横交叉算法的无人机航迹规划-附代码
基于纵横交叉算法的无人机航迹规划 文章目录 基于纵横交叉算法的无人机航迹规划1.纵横交叉搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要:本文主要介绍利用纵横交叉算法来优化无人机航迹规划。 …...
D-Bus:数据类型
D-Bus中描述接口的属性和方法,有其自己定义的一套签名描述方式: 数据类型描述符号对应C++数据类型avector/array数组, ai表示的是vector<int32_t>bboolddouble双精度浮点数iint32_t,32位有符号整数nint16_t,16位有符号整数oobject_path对象路径quint16_t,16位无符号…...
BI零售数据分析,告别拖延症,及时掌握一线信息
在日常的零售数据分析中,经常会因为数据量太大,分析指标太多且计算组合多变而导致数据分析报表难产,零售运营决策被迫拖延症。随着BI数据可视化分析技术的发展,智能化、可视化、自助分析的BI数据分析逐渐成熟,形成一套…...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
JavaScript 中的 ES|QL:利用 Apache Arrow 工具
作者:来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗?了解下一期 Elasticsearch Engineer 培训的时间吧! Elasticsearch 拥有众多新功能,助你为自己…...
微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...
Mobile ALOHA全身模仿学习
一、题目 Mobile ALOHA:通过低成本全身远程操作学习双手移动操作 传统模仿学习(Imitation Learning)缺点:聚焦与桌面操作,缺乏通用任务所需的移动性和灵活性 本论文优点:(1)在ALOHA…...
Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
【UE5 C++】通过文件对话框获取选择文件的路径
目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 ,这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器,右键点击 .uproject 文件,选择 "Generate Visual Studio project files",重…...
Python训练营-Day26-函数专题1:函数定义与参数
题目1:计算圆的面积 任务: 编写一个名为 calculate_circle_area 的函数,该函数接收圆的半径 radius 作为参数,并返回圆的面积。圆的面积 π * radius (可以使用 math.pi 作为 π 的值)要求:函数接收一个位置参数 radi…...
在 Visual Studio Code 中使用驭码 CodeRider 提升开发效率:以冒泡排序为例
目录 前言1 插件安装与配置1.1 安装驭码 CodeRider1.2 初始配置建议 2 示例代码:冒泡排序3 驭码 CodeRider 功能详解3.1 功能概览3.2 代码解释功能3.3 自动注释生成3.4 逻辑修改功能3.5 单元测试自动生成3.6 代码优化建议 4 驭码的实际应用建议5 常见问题与解决建议…...
Python常用模块:time、os、shutil与flask初探
一、Flask初探 & PyCharm终端配置 目的: 快速搭建小型Web服务器以提供数据。 工具: 第三方Web框架 Flask (需 pip install flask 安装)。 安装 Flask: 建议: 使用 PyCharm 内置的 Terminal (模拟命令行) 进行安装,避免频繁切换。 PyCharm Terminal 配置建议: 打开 Py…...

