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正常通信 ”描述一致。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/128173.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

云服务器 centos 部署 code-server 并配置 c/c++ 环境

将你的云服务器改为 centos 8 为什么要将云服务器的操作系统改成 centos 8 呢&#xff1f;原因就是 centos 7 里面的配置满足不了 code-server 的需求。如果你使用的是 centos 7 那么就需要你升级一些东西&#xff0c;这个过程比较麻烦。我在 centos 7 上面运行 code-server 的…

k8s、pod

Pod k8s中的port【端口&#xff1a;30000-32767】 port &#xff1a;为Service 在 cluster IP 上暴露的端口 targetPort&#xff1a;对应容器映射在 pod 端口上 nodePort&#xff1a;可以通过k8s 集群外部使用 node IP node port 访问Service containerPort&#xff1a;容…

velero备份k8s集群

流程图 velero备份原理 本地 Velero 客户端发送备份指令。Kubernetes 集群内就会创建一个 Backup 对象。BackupController 监测 Backup 对象并开始备份过程。BackupController 会向 API Server 查询相关数据。BackupController 将查询到的数据备份到远端的对象存储。 velero的…

osg三角带

案例1 #include <osg/Geode> #include <osg/Geometry> #include <osgDB/Registry> #include <osgDB/WriteFile> #include <osg/Notify> #include <osg/PrimitiveSet> #include <osgViewer/Viewer> #include <osgUtil/Optimizer&g…

【数据结构】希尔排序

文章目录 前言一、希尔排序的演示图例二、希尔排序&#xff1a;插入排序的优化版本☆三、核心算法思路四、算法思路步骤&#xff08;一&#xff09;预排序 gap>1&#xff08;二&#xff09;gap1 插入排序 完成排序收尾 五、码源详解&#xff08;1&#xff09;ShellSort1 ——…

Linux CentOS7.9安装OpenJDK17

Linux CentOS7.9安装OpenJDK17 一、OpenJDK下载 清华大学开源软件镜像站 国内的站点&#xff0c;下载速度贼快 二、上传解压 文件上传到服务器后&#xff0c;解压命令&#xff1a; tar -zxvf jdk-xxxx-linux-x64.tar.gz三、配置环境 export JAVA_HOME/home/local/java/j…

idea 配置checkstyle全过程

checkstyle是提高代码质量,检查代码规范的很好用的一款工具&#xff0c;本文简单介绍一下集成的步骤&#xff0c;并提供一份完整的checkstyle的代码规范格式文件&#xff0c;以及常见的格式问题的解决方法。 一&#xff0c;安装 打开idea的文件选项&#xff0c;选择设置&…

搜维尔科技:scalefit生物力学人体工学软件分析!

人体工程学分析 21加载参数和头像显示 识别(隐藏的)健康风险 根据DGUV交通灯进行生物反馈(DIN/ISO) 实时应力分析 三维空间可视化 静态/动态肩载 用左/右赋值加载输入 腰椎间盘压缩计算 距离和定时器显示 带有运动跟踪的化身/视频叠加 外骨骼与CAD工作站仿真 CSV原始…

【机器学习合集】模型设计之残差网络 ->(个人学习记录笔记)

文章目录 模型设计之残差网络1. 什么是残差结构1.1 网络加深遇到的优化问题1.2 short connect技术 2. 残差网络及有效性理解2.1 残差网络 3. 残差网络的发展3.1 密集残差网络3.2 更宽的残差网络(wide resnet)3.3 分组残差网络3.4 Dual Path Network3.5 加权残差网络3.6 预激活残…

WIN11如何固定文件夹查看方式

找一个文件夹&#xff0c;设置成自己需要的视图方式 文件夹选项>查看>应用到文件夹 缺点&#xff1a;所有相同类型文件夹都会使用此视图

数据结构——线性表①(顺序表)

一、线性表定义 线性表是一种数据结构&#xff0c;它是由n个具有相同数据类型的数据元素a1,a2,…,an组成的有限序列。 其中&#xff0c;除第一个元素a1外&#xff0c;每一个元素有且只有一个直接前驱元素&#xff0c;除了最后一个元素an外&#xff0c;每一个元素有且只有一个…

Redis(11)| 持久化AOF和RDB

一、AOF&#xff08;Append Only File&#xff09; Redis 每执行一条写操作命令&#xff0c;就把该命令以追加的方式写入到一个文件里&#xff0c;然后重启 Redis 的时候&#xff0c;先去读取这个文件里的命令&#xff0c;并且执行它。 注意&#xff1a;只会记录写操作命令&am…

微信小程序:两层循环的练习,两层循环显示循环图片大图(大图显示、多层循环)

效果 代码分析 外层循环 外层循环的框架 <view wx:for"{{info}}" wx:key"index"></view> wx:for"{{info}}"&#xff1a;这里wx:for指令用于指定要遍历的数据源&#xff0c;即info数组。当遍历开始时&#xff0c;会依次将数组中的每…

stable-diffusion 电商领域prompt测评集合

和GhostReivew一个思路&#xff0c;还是从比较好的图片或者是civitai上找一些热门的prompt&#xff0c;从小红书上也找到了不少的prompt&#xff0c;lexica.art上也有不少&#xff0c;主要是为了电商场景的一些测评&#xff1a; 小红书、civitai、Lexica、Liblib.ai、 depth o…

Leetcode—707.设计链表【中等】双链表的设计明天再写

2023每日刷题&#xff08;十七&#xff09; Leetcode—707.设计链表 设计单链表实现代码 typedef struct Node {int val;struct Node* next; } MyLinkedList;MyLinkedList* myLinkedListCreate() {MyLinkedList* mList (MyLinkedList *)malloc(sizeof(MyLinkedList));mList-&…

Wpf 使用 Prism 实战开发Day02

一.设计首页导航条 导航条的样式&#xff0c;主要是从Material DesignThemes UI 拷贝过来修改的,项目用了这个UI组件库&#xff0c;就看自己需要什么&#xff0c;就去拷过来使用&#xff0c;界面布局或其他组件使用&#xff0c;不做介绍。 直接下载源码&#xff0c;编译运行就可…

【进程控制⑥】:进程替换/exec*()系列接口

【进程控制⑥】&#xff1a;进程替换/ exec*(&#xff09;系列接口 一.进程替换原理二.替换特点1.独立性2.唯一性3.不变性4.不返回 三.程序替换应用【exec*系列系统调用】①execl&#xff1a;②execlp&#xff1a;③execv&#xff1a;④execle&#xff1a; 一.进程替换原理 我…

视频编码转换技巧:视频批量转码H264转H265,高效且顺畅

随着数字媒体的广泛应用&#xff0c;视频编码转换已成为一种普遍的需求。不同的视频格式和编码标准使得在不同设备上播放视频成为可能&#xff0c;同时也带来了兼容性和传输效率的问题。本文讲解引用云炫AI智剪使视频编码转换技巧&#xff0c;即批量将H264编码转换为H265编码&a…

厦门万宾科技智能井盖监测仪器的作用如何?

越来越多的人们希望改善生活&#xff0c;走出农村走出大山&#xff0c;前往城市之中居住。由此城市的人口和车辆在不断增加&#xff0c;与之而来的是城市的交通压力越来越大&#xff0c;时常会出现道路安全隐患&#xff0c;这给城市未来发展和智慧城市建设都带来一定的难题&…

sass相关

1、代码简化 1.1、简化媒介查询 mixin flex{display: flex;justify-content: center;align-items: center; } .header{width: 100%;include flex;//可以这样引用 }//加入参数 mixin flex($layout){display: flex;justify-content: $layout;align-items: $layout; } .header{w…