15.7节 SRIO Direct I/O
写在前面的话:
在整理这部分内容之前,我已经调试完成了在两片6678 上通过NWRITE、NREAD、DOORBELL通讯。SRIO学习调试可以说是从之前的一无所知过度到了现在的入门级别,最初连最基本的概念也不知道,TI的英文手册看了一遍,没有看懂,网上也有对TI英文手册的部分理论章节的翻译,看了以后也是没有太懂,庆幸的是这段时间创龙出了对TI英文手册的全方位翻译,看了一遍也还是一知半解,并没有整体的把局。我总结道:首次阅读对于这种专业术语概念较强,寄存器只说特定位作用,此时自己又不能总结出总体框架的文章,即使是中文的也会让人读起来厌倦烦躁,但是第一次必须读一遍,即使是读一半也要读。后来我是放弃了文档的阅读,硬着头皮在创龙的例程基础上,第一次调试PORT端口连接成功,才渐渐有了感觉,接着根据SRIO初始化过程,将所使用到的寄存器再看了一遍,再后来,DSP与FPGA之间可以单项的传输数据,让我意识到SRIO的数据流动与以前串口 SPI数据流动还是挺大的,在Direct I/O模式下SRIO控制器软件做了很多事情,软件只需要负责初始化,然后配置命令即可,然后数据就由SRIO控制器硬件搬运了。再后来就有了质的突破,各种读写调试,这时候反而感觉SRIO并没有传说中的那么复杂,还是挺简单的,接着根据调试需求,进行了第二波技术手册的阅读,主要以中文文档和博客为主,这一次阅读感觉满满的,真可以说是书读百遍其义自见,(还要我有个好习惯,我会将以前看过的网页文章进行收集,减少了我再一次百度上搜索文章的时间,只需要将以前看过没看懂的文章,打开在看一遍)。最后在总结一点:技术上对于未接触过的新技术,想学明白,首先第一点是要在新技术上花费充分多的时间,如果没有过度的饱和时间,可能真只是一知半解的水平。经过这段时间的调试,SRIO Direct I/O方式调试目前算是有了一定理解,其中许多细节问题、操作(像Message方式通讯等待),需要在进一步的项目调试暴露,再整理记录,目前先整理这么多知识点,希望后续根据项目需求不断完善。
15.7.1 Direct I/O原理参考资料
- 参考资料
《SRIO学习(六)——Direct I/O 操作(一)》
https://blog.csdn.net/kunkliu/article/details/105273271
《SRIO学习(七)——Direct I/O 操作(二)》
https://blog.csdn.net/kunkliu/article/details/105273865
《FPGA+DSP SRIO通信(三)——基于LSU的数据传输》
https://blog.csdn.net/kunkliu/article/details/105274846
- C6678内部硬件上一共有8组LSU寄存器(Load/Store Unit),每组LSU都有自己的7个寄存器,即LSU_REG0-LSU_REG6,REG0-REG4用来存储控制信息,REG5、REG6用来存储命令和状态信息。除了REG6,其它寄存器都是可读可写的,只有REG6有只读和只写两种模式。
- 软件上配置完LSU_REG6之后,SRIO控制器就开始自动传输
- SRIO控制器会根据LSU寄存器配置情况,硬件组成SRIO标准包,然后发送出去,所以软件上Direct I/O方式的传输,就是对LSU寄存器的操作。
- doorbell的传输也是通过LSU寄存器配置实现的,与NWRITE一致。
- 每一组LSU寄存器对应存在着一定数量的影子寄存器,我的理解是,软件操作的是影子寄存器,然后控制器会将影子寄存器的值更新到真正的LSU寄存器,目前关于影子寄存器的细节理论我并没有完全理解。在软件上操作时可以并不用考虑影子寄存器,直接调用TI提供的API接口即可,如果实际使用中出现难以解释的通讯问题,在具体理解这一块内容
- LSU寄存器的状态获取,锁住,释放,判断是否发送完成等等细节知识点,目前也没有弄明白。
- 创龙提供的tl-srio-test例程使用描述中,有这么一段:此代码可以分别加载到8个核中同时运行,而他的使用LSU的方式为:每个核使用一组LSU,从而8个核在硬件上相互独立,但是PORT口这一块是怎么区分的,目前没有想明白,SRIO控制器内部有缓存仲裁机制,也是没有看明白原理。
- LSU寄存器
- LSU寄存器与NWRITE包的关系
- SRIO内部缓存机制
15.7.3 SRIO 通讯数据出错后必须重新断电运行,才可正常工作
15.7.4 SRIO 接收数据捕获接收包信息
- 调试6678 SRIO接收模式时,通过一下寄存器可以捕获到接收包的信息,以及出错信息。
- 只能使用
CSL_SRIO_SetErrorDetect(hSrio, 0, 1); //使能接收错误检测
CSL_SRIO_SetErrorDetectEnable(hSrio, 1, 1);
Uint32 address;
Uint8 xambs;
Uint8 msbDstID;
Uint8 lsbDstID;
Uint8 msbSrcID;
Uint8 lsbSrcID;
Uint8 ftype;
Uint8 ttype;
Uint8 msgInfo;
CSL_SRIO_GetHiAddressCapture(hSrio, &address);
printf("Haddress = 0x%x\n", address);
CSL_SRIO_GetLoAddressCapture(hSrio, &address, &xambs);
printf("Laddress = 0x%x, xambs = 0x%x\n", address, xambs);
CSL_SRIO_GetDeviceIDCapture(hSrio, &msbDstID, &lsbDstID, &msbSrcID, &lsbSrcID);
printf("msbDstID = 0x%x, lsbDstID = 0x%x, msbSrcID = 0x%x, lsbSrcID = 0x%x\n", msbDstID, lsbDstID, msbSrcID, lsbSrcID);
CSL_SRIO_GetLocalControlCapture(hSrio, &ftype, &ttype, &msgInfo);
printf("ftype = 0x%x, ttype = 0x%x, msgInfo = 0x%x\n", ftype, ttype, msgInfo);
15.7.5 SRIO 设置发送数据大小端
CSL_SRIO_SetLSUSwappingMode (hSrio, 3);
//CSL_SRIO_SetMAUSwappingMode(hSrio, 0);
CSL_SRIO_SetTXURXUSwappingMode (hSrio,3);
//CSL_SRIO_SetAMUSwappingMode (hSrio, 0);
15.8节 SRIO 协议总结
参考文章:https://blog.csdn.net/kunkliu/article/details/106699504
Ftype (Format Type) | Ttype (Transaction Type) | 包类型
| 功能 |
0~1 | —— | Reserve | 无 |
2 | 4’b0100 | NREAD | 读指定的地址 |
4’b1100 | ATOMIC increment | 先往指定的地址中传递数据,在把传递的数据加1,此操作为原子操作,不可打断 | |
4’b1101 | ATOMIC decrement | 先往指定的地址中传递数据,在把传递的数据减1,此操作为原子操作,不可打断 | |
4’b1110 | ATOMIC set | 把指定地址中的数据每个bit全部写1 | |
4’b1111 | ATOMIC clear | 把指定地址中的数据清0(每个bit全部清零) | |
3~4 | —— | Reserve | 无 |
5 | 4’b0100 | NWRITE | 往指定的地址写数据 |
4’b0101 | NWRITE_R | 往指定的地址写数据,写完成以后接收目标器件(Target)的响应 | |
4’b1101 | ATOMIC test/swap | 对指定地址中的数据进行测试并交换,此操作为原子操作,不可打断 | |
6 | 4’bxxxx | SWRITE | 以流写方式写指定的地址,与NWRITE以及NWRITE_R相比,此方式效率最高 |
7 | —— | Reserve | 无 |
8 | 4’b0000 | MAINTENANCE read request | 发起读配置,控制,状态寄存器请求 |
4’b0001 | MAINTENANCE write request | 发起写配置,控制,状态寄存器请求 | |
4’b0010 | MAINTENANCE read response | 产生读配置,控制,状态寄存器响应 | |
4’b0011 | MAINTENANCE write response | 产生写配置,控制,状态寄存器响应 | |
4’b0100 | MAINTENANCE write resquest | 端口写请求 | |
9 | —— | Reserve | 无 |
10 | 4’bxxxx | DOORBELL | 门铃 |
11 | 4’bxxxx | MESSAGE | 消息 |
12 | —— | Reserve | 无 |
13 | 4’b0000 | RESPONSE no data | 不带有效数据的响应包 |
4’b1000 | RESPONSE with data | 带有效数据的响应包 | |
14~15 | —— | Reserve | 无 |
在 RapidIO体系结构中定义了6种基本的I/O操作, 下表给出了这6种基本的I/O操作、用来执行相应操作的事务和对操作的描述
- 通过DIO方式,通讯双方必须知道数据写入和读取的内存地址。
- NWRITE时,请求方(Requestor)直接将数据写到目标方(Destination)对应的内存地址中,Destination只需要初始化SRIO成功即可,数据的搬移由SRIO控制器硬件完成
- NREAD命令,请求方(Requestor)直接将目标方(Destination)对应的内存地址中的数据搬回到Requestor的对应地址,Destination只需要初始化SRIO成功即可,数据的搬移和NREAD的RESPONSE均由SRIO控制器硬件完成,
- 总结:自我理解DIO方式的SRIO数据的搬移由硬件控制器完成,软件并不要做太多处理,只负责设置配置NWRITE NREAD命令即可,继而可以更深远写思考,通过SRIO连接的两个设备,我们从宏观上可以认为两个设备的内存对对方是可见的,此时SRIO可以想象成DMA的功能,执行一个指令(NWRITE NREAD),即可把数据搬移自己或者对方特定的内存地址中,然后对数据进行上层处理。即SRIO扩展了互联设备的内存。
15.9节 SRIO 5G速率配置
- 配置代码如下:
- 代码解释
① 硬件上参考时钟是156.25,我们选择MPY=16,半速模式。
② MPY设置在寄存器SerDes 宏配置寄存器(SRIO_SERDES_CFGPLL — 0x02620360)
③ 半速模式设置在寄存器中设置,每个PORT口都要设置:
SerDes 接收通道配置寄存器(SRIO_SERDES_CFGRX[0-3]) (0x02620364 +(n * 0x8))
SerDes 发送通道配置寄存器 (SERDES_CFGTXn_CNTL) (0x02620368 + (n * 0x8))
- 设置代码:
/*
* MPY = 0x80: 16x
* ENPLL = 1: PLL Enable
* srio_serdes_clock = RefClk(156.25MHz) * 16MPY = 2.5GHz
*/
CSL_BootCfgSetSRIOSERDESConfigPLL(0x81); // 5G
/*
* Configure the SRIO SERDES Receive Configuration
* ENOC = 1: Enable offset compensation
* EQ = 1: Fully adaptive equalization
* CDR = 5: First order with fast lock
* ALIGN = 1: Comma alignment enabled
* TERM = 1: Input termination, the only valid value for this field is 0x1
* RATE = 1: Data Rate = 2 * srio_serdes_clock = 5Gbps
* BUSWIDTH = 1: Bus width, indicate a 20-bit wide parallel bus to the clock
* ENRX = 1: Enable this receiver
*/
for(i = 0; i <= 3; i++)
CSL_BootCfgSetSRIOSERDESRxConfig(i, 0x00468495);
/*
* Configure the SRIO SERDES Transmit Configuration
* MSYNC = 1: Enables the channel as the master lane
* FIRUPT = 1: Transmitter pre and post cursor FIR filter update
* TWPST1 = 18: Adjacent post cursor Tap weight
* TWPRE = 1: Precursor Tap weight
* SWING = 16: Output swing
* RATE = 1: Data Rate = 2 * srio_serdes_clock = 5Gbps
* BUSWIDTH = 1: Bus width, indicate a 20-bit wide parallel bus to the clock
* ENRX = 1: Enable this receiver
*/
for(i = 0; i <= 3; i++)
CSL_BootCfgSetSRIOSERDESTxConfig(i, 0x001C8F95);
15.10节 SRIO 扫链过程
- DSP 6678 SRIO ID号要设置为0xFF或0xFFFF才能扫到。
- CSL_SRIO_SetPortGeneralCSR(hSrio, 0, 1, 0);函数中master_en位设置为1,才能发出去数据
- 尚未完成