摘要: 应用说明386提供了如何在配置模式下配置DS3131 HDLC控制器上的单个端口的示例。本应用程序说明是作为编码示例提供的,以便于适应最终用户应用程序。
本应用笔记介绍如何配置DS3131在配置模式下的单个端口的示例。此外,本示例还描述了如何在该端口上以环回模式构造、发送、接收和检查数据包。本应用程序说明是作为编码示例提供的,以便于适应最终用户应用程序。
DS3131的本地总线可以在两种模式下工作:PCI桥模式和配置总线模式。
在配置模式下,本地总线仅用于控制和监视DS3131, HDLC包数据通过PCI总线传输。在这种模式下,数据不能从本地总线传递到PCI总线。(请参阅DS3131数据表第10节。)
本例配置如下:
仅分配DS3131的1号端口和1号通道。其他所有端口未被使用。
DS3131的HDLC通道1分配了4个Rx FIFO块,4个Tx FIFO块,一个Rx FIFO高水位为3,一个Tx低水位为1。
在主机内存中使用一个Tx缓冲区、一个Tx描述符和一个Tx挂起队列条目构造一个16字节的数据包。由于DS3131处于环回模式,当数据包被传输时,它也会被DS3131接收。接收到的数据包使用一个Rx缓冲区、一个Rx描述符和一个Rx完成队列条目写入主机内存。
主机内存配置如下:
接收方:
Rx空闲队列基址(RFQBA1/0)
= | 0 x10000000 |
Rx完成队列基址(RDQBA1/0)
= | 0 x10000100 |
Rx描述符基址(RDBA1/0)
= | 0 x10000200 |
Rx缓冲区基址
= | 0 x10001000 |
传输: |
Tx等待队列基址(TPQBA1/0)
= | 0 x10000300 |
Tx完成队列基址(TDQBA1/0)
= | 0 x10000400 |
Tx描述符基址(TDBA1/0)
= | 0 x10000500 |
Tx缓冲区基址
= | 0 x10002000 |
为了提高可读性,本例中的代码使用了几个函数调用。这些函数的定义如下:
将指定的数据写入指定的DS3131寄存器地址。
输入: | ||
地址 | = | 要写入数据的寄存器地址 |
数据 | = | 要写入指定寄存器的数据 |
输出: | 没有一个 |
读取指定地址上DS3131寄存器的内容。
输入: | ||
地址 | = | 要读取的寄存器地址 |
输出: | ||
数据 | = | 从寄存器中读取的值 |
将指定的数据写入指定的DS3131间接选择寄存器,然后在返回之前等待该寄存器的忙位清除。
输入: | ||
地址 | = | 要写入数据的间接选择寄存器 |
数据 | = | 要写入指定寄存器的数据 |
输出 | 没有一个 | |
函数代码: | write_reg(地址、数据); Bit_check = 0x8000; While (bit_check &0 x8000) |
read_reg(地址、bit_check);
将指定的32位数据值写入指定的32位主机内存地址。
输入: | ||
地址 | = | 要写入数据的主机内存地址 |
数据 | = | 要写入指定内存地址的数据 |
输出: | 没有一个 |
从指定的32位主机内存地址中读取32位数据值。
输入: | ||
地址 | = | 要读取的主机内存地址 |
输出: | ||
数据 | = | 从主机内存中读取的32位数据值 |
当帧周期为125µs时,提供等于count帧周期的时延。
输入: | ||
数 | = | 等待的帧周期数 |
输出: | 没有一个 |
本应用说明中的代码由以下步骤组成:
复位DS3131
配置DS3131
开启HDLC通道
将HDLC通道设置为环回模式
对数据包进行排队、发送、接收和检查
以下各节将通过简要描述和编码示例详细介绍这些步骤。为了提高可读性,使用寄存器名代替地址。DS3131内部设备配置寄存器的相应地址/偏移量列在附表中。另外,使用缩写Tx和Rx分别表示发送端和接收端。有关更详细的信息,请参阅DS3131数据表。
可以使用主复位寄存器(MRID)对DS3131中的所有寄存器执行软件复位。当MRID寄存器的0位被设置为1时,所有内部寄存器都被设置为默认值0。主机必须将这个位设置回0,设备才能被编程正常运行。通过发送和接收RAM中的通道启用位,确保DMA在发送和接收端关闭。
抵消/地址 | 首字母缩写 | 注册的名字 | 数据表部分 |
0000 | MRID | 主复位和ID寄存器 | 4.1 |
//使用MRID寄存器主复位位复位DS3131。write_reg(MRID, 0x0001); write_reg(MRID, 0x0000);
抵消/地址 | 首字母缩写 | 注册的名字 | 数据表部分 |
0770 | RDMACIS | 接收DMA配置间接选择 | 8.1.5 |
0774 | RDMAC | 接收DMA配置 | 8.1.5 |
//禁用RX DMA配置RAM write_reg(RDMAC, 0x0000); for(channel=0;channel< 40;1) write_reg_IS(RDMACIS, 0x0400 + channel);
抵消/地址 | 首字母缩写 | 注册的名字 | 数据表部分 |
0870 | TDMACIS | 传输DMA配置间接选择 | 8.2.5 |
0774 | TDMAC | 发送DMA配置 | 8.2.5 |
//禁用TX DMA配置RAM write_reg(TDMAC, 0x0000); for(channel=0;channel< 40;1) write_reg_IS(TDMACIS, 0x0400 + channel);
DS3131的配置包括以下步骤:
配置PCI寄存器
配置DMA寄存器
配置FIFO寄存器
配置端口寄存器(第一层)
配置HDLC寄存器(第二层)
每个寄存器集的配置将在下面的小节中详细介绍。使用几个变量来提高可读性并提供更算法化的代码结构。下面的代码提供了这些变量的初始化:
/ /这个例子使用端口1通道1端口= 1;信道= 1;/ / RX免费队列基地址rfq_base_addr = 0 x10000000; / / RX免费队列结束地址/ / RX免费队列大小= 16 rfq_end_idx = 0 x0010; / / RX队列完成基地址rdq_base_addr = 0 x10000100; / / RX完成队列结束地址/ / RX完成队列大小= 16 rdq_end_idx = 0 x0010; / / RX描述符基地址/ / RX描述符表大小= 256 rdscr_base_addr = 0 x10000200; / / RX数据缓冲区基地址rx_buf_base_addr = 0 x10001000; / /TX未决队列基地址tpq_base_addr = 0 x10000300; / / TX未决队列结束地址/ / TX未决队列大小= 16 tpq_end_idx = 0 x0010; / / TX队列完成基地址tdq_base_addr = 0 x10000400; / / TX完成队列结束地址/ / TX完成队列大小= 16 tdq_end_idx = 0 x0010; / / TX描述符基地址/ / TX描述符表大小= 256 tdscr_base_addr = 0 x10000500; / / TX数据缓冲区基地址tx_buf_base_addr = 0 x10002000;
配置PCI寄存器
在配置模式下,PCI寄存器控制DS3131在执行DMA操作时如何与PCI总线接口。PCI寄存器配置依赖于系统,因此可能需要修改下面的编码示例以支持特定的用户应用程序。
抵消/地址 | 首字母缩写 | 注册的名字 | 数据表部分 |
0 x0004/0a04 | PCMD0 | PCI命令状态0 | 9.2 |
// PCI命令/状态寄存器0 -控制DS3131 DMA功能 //设置位2 = 1允许设备在PCI总线上作为总线主操作(DMA需要) //设置位6 = 1对奇偶校验错误起作用 //设置位8 = 1启用PSERR引脚 write_reg(PCMD0, 0x0144);
配置DMA寄存器
DMA块处理数据包数据从FIFO块到PCI块的传输,反之亦然。PCI块控制DS3131和外部PCI总线之间的数据传输。主机被定义为位于PCI总线上的CPU或智能控制器,它指示DS3131如何处理传入和传出数据。这是使用描述符完成的,这些描述符被定义为从主机传递到DMA块的预格式化消息,反之亦然。使用这些描述符,主机通知DMA要传输的数据包数据的位置和状态,以及将接收到的数据包数据放置在何处。DMA使用这些描述符告诉主机已传输的数据包数据的状态,以及已接收的数据包数据的状态和位置。
在接收端,主机写入空闲队列描述符,通知DMA可以将传入的数据包数据放置在哪里。与每个空闲队列条目相关联的是接收数据缓冲区位置和包描述符。当DS3131使用接收空闲队列条目将接收到的数据包数据写入主机内存时,它会在Rx完成队列中创建条目。这些Rx完成队列条目通知主机接收数据的位置和状态。有关更详细的信息,请参阅DS3131数据表。主机必须通过写入下表中的所有寄存器来配置Rx DMA:
抵消/地址 | 首字母缩写 | 注册的名字 | 数据表部分 |
0700 | RFQBA0 | 接收空闲队列基址0(下一个字) | 8.1.3 |
0704 | RFQBA1 | 接收空闲队列基地地址1(上一个字) | 8.1.3 |
0708 | RFQEA | 接收空闲队列结束地址 | 8.1.3 |
070 c | RFQSBSA | 接收免费的小缓冲区起始地址 | 8.1.3 |
0710 | RFQLBWP | 接收空闲队列大缓冲区主机写指针 | 8.1.3 |
0714 | RFQSBWP | 接收空闲队列小缓冲区主机写指针 | 8.1.3 |
0718 | RFQLBRP | 接收空闲队列大缓冲区DMA读指针 | 8.1.3 |
071 c | RFQSBRP | 接收空闲队列小缓冲区DMA读指针 | 8.1.3 |
0730 | RDQBA0 | 接收完成队列基址0(下一个字) | 8.1.4 |
0734 | RDQBA1 | 接收完成队列基地地址1(上字) | 8.1.4 |
0738 | RDQEA | 接收完成队列结束地址 | 8.1.4 |
073 c | RDQRP | 接收完成队列主机读指针 | 8.1.4 |
0740 | RDQWP | 接收完成队列DMA写指针 | 8.1.4 |
0750 | RDBA0 | 接收描述符基址0(下一个字) | 8.1.2 |
0754 | RDBA1 | 接收描述符基址1(上一个字) | 8.1.2 |
0770 | RDMACIS | 接收DMA配置间接选择 | 8.1.5 |
0774 | RDMAC | 接收DMA配置 | 8.1.5 |
0790 | RLBS | 接收大缓冲区大小 | 8.1.1 |
// RX大缓冲区大小= 256字节 write_reg(RLBS, 0x0100); // RX空闲队列基数地址 write_reg(RFQBA0, rfq_base_addr & write_reg(RFQBA1, (rfq_base_addr >>16),0 x0000ffff); / / RX免费队列大型缓冲区读和写指针= 0 write_reg (RFQLBRP 0 x0000); write_reg (RFQLBWP 0 x0000); / / RX免费队列小缓冲起始地址= 16 write_reg (RFQSBSA rfq_end_idx); / / RX免费小队列缓冲区读和写指针= 0 write_reg (RFQSBRP 0 x0000); write_reg (RFQSBWP 0 x0000); / / RX免费队列结束地址write_reg (RFQEA rfq_end_idx); / / RX队列完成基地址write_reg (RDQBA0 rdq_base_addr和; write_reg(RDQBA1, (rdq_base_addr >>16), // RX完成队列读写指针= 0 write_reg(RDQRP, 0x0000); write_reg(RDQWP, 0x0000); // RX完成队列结束地址 write_reg(RDQEA, rdq_end_idx); // RX描述符基址 write_reg(RDBA0, rdscr_base_addr & write_reg(RDBA1, (rdscr_base_addr >>16),0 x0000ffff); / / RX DMA通道配置/ / RDMAC寄存器中的数据写入或读取接收配置RAM / / / /设置位0 = 0禁用为频道/ /设置一些2 - 1 = 00大型缓冲区只/ /设置位6 = 0000 0字节抵消从第一个数据缓冲区的数据缓冲区地址/ /设置位9-7 = 000 DMA写入完成队列后包接收/ /完成/ /设置为频道号码RDMACIS注册write_reg (RDMAC, write_reg_IS(RDMACIS, 0x0400 + channel);
在传输端,主机向挂起队列写入数据,通知DMA哪些通道有准备传输的数据包数据。与每个挂起队列描述符相关联的是一个或多个描述数据包数据的传输数据包描述符的链表。每个传输包描述符都有一个指向传输数据缓冲区的指针,该缓冲区包含HDLC包的实际数据有效载荷。当DS3131进程传输挂起队列描述符项时,它创建传输完成队列描述符队列项。当DMA完成传输完整的数据包或数据缓冲区时,它将写入完成队列,这取决于DS3131的配置方式。使用这些完成队列描述符,DMA通知主机有关传出数据包数据的状态。有关更详细的信息,请参阅DS3131数据表。主机必须通过写入下表中的所有寄存器来配置Tx DMA:
抵消/地址 | 首字母缩写 | 注册的名字 | 数据表部分 |
0800 | TPQBA0 | 传输等待队列基址0(下一个字) | 8.2.3 |
0804 | TPQBA1 | 发送等待队列基地地址1(上一个字) | 8.2.3 |
0808 | TPQEA | 传输等待队列结束地址 | 8.2.3 |
080 c | TPQWP | 传输挂起队列主机写指针 | 8.2.3 |
0810 | TPQRP | 传输挂起队列DMA读指针 | 8.2.3 |
0830 | TDQBA0 | 发送完成队列基址0(下一个字) | 8.2.4 |
0834 | TDQBA1 | 发送完成队列基址1(上一个字) | 8.2.4 |
0838 | TDQEA | 发送完成队列结束地址 | 8.2.4 |
083 c | TDQRP | 传输完成队列主机读指针 | 8.2.4 |
0840 | TDQWP | 传输完成队列DMA写指针 | 8.2.4 |
0850 | TDBA0 | 发送描述符基址0(下一个字) | 8.2.2 |
0854 | TDBA1 | 发送描述符基址1(上一个字) | 8.2.2 |
0870 | TDMACIS | 传输DMA配置间接选择 | 8.2.5 |
0874 | TDMAC | 发送DMA配置 | 8.2.5 |
// TX等待队列基地地址 write_reg(TPQBA0, tpq_base_addr & write_reg(TPQBA1, (tpq_base_addr >>16), // TX待处理队列读写指针= 0 write_reg(TPQRP, 0x0000); write_reg(TPQWP, 0x0000); // TX待处理队列结束地址 write_reg(TPQEA, tpq_end_idx); // TX待处理队列基础地址 write_reg(TDQBA0, tdq_base_addr & write_reg(TDQBA1, (tdq_base_addr >>16), // TX完成队列读写指针= 0 write_reg(TDQRP, 0x0000); write_reg(TDQWP, 0x0000); // TX完成队列结束地址 write_reg(TDQEA, tdq_end_idx); // TX描述符基址 write_reg(TDBA0, tdscr_base_addr & write_reg(TDBA1, (tdscr_base_addr >>16), // TX DMA通道配置 // TDMAC寄存器中的数据被写入或从接收配置RAM中读取 //设置位0 = 0禁用HDLC通道 //设置位1 = 0用于数据包传输后的写完成队列 //通过TDMACIS寄存器设置HDLC通道号 write_reg(TDMAC, 0x0000); write_reg_IS(TDMACIS, 0x0200 +通道);
配置FIFO寄存器
DS3131包含一个8kB的发送FIFO和一个8kB的接收FIFO。每个FIFO被分成512块,每块4个字,或16个字节。FIFO内存是在HDLC信道的基础上分配的。分配给每个HDLC通道的FIFO内存的数量是可编程的,可以是最少4个块,最多512个块。FIFO内存通过从一组块中创建一个循环链表来分配给HDLC通道,其中每个块指向链中的下一个块,最后一个块指向第一个块。FIFO块链表通过在链表中分配一个块作为该通道的FIFO起始块指针来分配给特定的HDLC通道。
块数、高水位、低水位的计算:
Blocks = 512 /端口使用数
高水位= Block / 2
低水位= Block / 2
在这个例子中,四个Tx FIFO块和四个Rx FIFO块被分配给HDLC通道。本例还使用Rx FIFO高水位为3,Tx FIFO低水位为1。Rx FIFO高水位表示在DMA开始将数据发送到PCI总线之前,HDLC引擎应该将多少块写入Rx FIFO。对于所涉及的特定信道,高水位设置必须在一个块到比链表链中的块数少一个块之间。Tx FIFO低水位表示在DMA开始从PCI总线获取更多数据之前,Tx FIFO中应该留下多少块。HDLC通道防止发送溢出和接收溢出所需的FIFO内存,Rx FIFO高水位和Tx FIFO低水位的数量取决于应用程序。DS3131的Tx FIFO和Rx FIFO通过下表中列出的寄存器在HDLC通道上独立配置。
抵消/地址 | 首字母缩写 | 注册的名字 | 数据表部分 |
0910 | RFBPIS | 接收FIFO块指针间接选择 | 7.2 |
0914 | RFBP | 接收FIFO块指针 | 7.2 |
//建立RX FIFO块链表 // 0->1->2->3->0 for (block=0;block< 4;块=块+ 1){/ /位在这里9 RFBP寄存器指示哪些块是/ /下一个链表write_reg (RFBP,块+ 1);write_reg_IS (RFBPIS、块);}/ /最后一块指向第一个块创建一个循环链表write_reg (RFBP 0 x0000); write_reg_IS (RFBPIS 0 x0003); / /循环链表分配给一个特定的频道write_reg (RFSBP 0 x0000); write_reg_IS (RFSBPIS、通道);
抵消/地址 | 首字母缩写 | 注册的名字 | 数据表部分 |
0920 | RFHWMIS | 接收FIFO高水位间接选择 | 7.2 |
0924 | RFHWM | 接收FIFO高水位 | 7.2 |
//设置RX FIFO高水位为3 write_reg(RFHWM, 0x0003); write_reg_IS(RFHWMIS, channel);
抵消/地址 | 首字母缩写 | 注册的名字 | 数据表部分 |
0990 | TFBPIS | 发送FIFO块指针间接选择 | 7.2 |
0994 | TFBP | 发送FIFO块指针 | 7.2 |
// TX FIFO块链表 // 0->1->2->3->0 for (block=0;block< 3;block=block+1) { // RFBP寄存器中的9-0位表示链表中的下一个块 write_reg(TFBP, block+1); write_reg_IS(TFBPIS, block); } //最后一个块指向第一个块创建一个循环链表 write_reg(TFBP, 0x0000); write_reg_IS(TFBPIS, 0x0003);
抵消/地址 | 首字母缩写 | 注册的名字 | 数据表部分 |
0980 | TFSBPIS | 传输FIFO起始块指针间接选择 | 7.2 |
0984 | TFSBP | 发送FIFO起始块指针 | 7.2 |
//指定循环链表到指定通道 write_reg(TFSBP, 0x0000); write_reg_IS(TFSBPIS, channel); //设置通道的TX FIFO低水位为1 write_reg(TFLWM, 0x0001); write_reg_IS(TFLWMIS, channel);
配置端口寄存器(第一层)
DS3131的每个端口都包含一个第一层控制器,该控制器执行多种功能,包括:
-为输入和输出数据分配HDLC通道号
—BERT功能之间的数据路由
第一层配置是由RP[n]CR、TP[n]CR、寄存器(其中n为要配置的端口)按端口进行的。
抵消/地址 | 首字母缩写 | 注册的名字 | 数据表部分 |
01 xx | RP [n] CR | 接收端口n控制寄存器 | 5.2 |
02年xx | TP [n] CR | 发送端口n控制寄存器 | 5.2 |
//设置RX端口控制寄存器 //设置位1-0 = 00时钟和数据不反转 //设置位10 = 0禁用本地环回A write_reg(r0cr + 4* Port, 0x0000) //设置TX端口控制寄存器 //设置位1-0 = 00时钟和数据不反转 //设置位3 = 0强制TD的所有数据为1 (TFDA1) write_reg(TP0CR + 4* Port, 0x0000);
配置HDLC寄存器(第二层)
DS3131包含一个40 HDLC控制器,它执行第二层功能。该控制器执行的功能包括:
-零填充和去填充
-标志检测和字节对齐
- CRC生成和校验
-数据反转和位翻转
HDLC控制器通过RH[n]CD和TH[n]CD寄存器在通道基础上配置。
抵消/地址 | 首字母缩写 | 注册的名字 | 数据表部分 |
03 xx | RH [n] CR | 接收HDLC控制寄存器 | 6.2 |
04 xx | [n] CR | 在控制寄存器中传输HDLC | 6.2 |
// RX HDLC配置 //设置位3-2 = 10为32位CRC write_reg(RH[n]CR, 0x0008) // TX HDLC配置 //设置位1= 0为32位CRC选择一个7E的中间填充字节 //设置位3-2 = 10为32位CRC //设置位11-8 = 1000为关闭标志/无中间填充字节/打开标志 write_reg(TH[n]CR, 0x0108);
DS3131初始化之后,下一步是启用HDLC通道。除了已经描述的配置步骤之外,必须执行以下步骤才能在DS3131中启用数据包传输和接收:
在端口Tx和Rx配置ram中启用通道
启用端口一层数据传输
使能DS3131的Tx DMA和Rx DMA
在Tx DMA和Rx DMA中启用HDLC通道
抵消/地址 | 首字母缩写 | 注册的名字 | 数据表部分 |
0010 | MC | 主配置寄存器 | 4.2 |
02年xx | TP [n] CR | 发送端口n控制寄存器 | 5.2 |
03 xx | RH [n] CR | 接收HDLC控制寄存器 | 6.2 |
0770 | RDMACIS | 接收DMA配置间接选择寄存器 | 8.1.5 |
0774 | RDMAC | 接收DMA配置寄存器 | 8.1.5 |
0870 | TDMACIS | 传输DMA配置间接选择寄存器 | 8.2.5 |
0874 | TDMAC | 发送DMA配置寄存器 | 8.2.5 |
/ / TX端口控制寄存器/ /设置位3 = 1,允许数据传输正常read_reg (TP0CR + 4 *端口、数据);write_reg (TP0CR + 4 *端口、数据| 0 x0008); / / RX为配置/ /设置位9 = 1,使港口(RPEN) write_reg (RH [n] CR, 0 x0200); / /从RX DMA读取当前的信道值配置RAM / /设置RDMACIS位5 = / /频道设置RDMACIS位换= 100字读低的话2 / /设置RDMACIS 14位= 1阅读从RAM write_reg_IS (RDMACIS,0 x4400 +频道);read_reg (RDMAC、数据);/ /启用通道RX DMA / /用新值更新RAM / /设置RDMAC位0 = 1,使为频道/ /设置RDMACIS位5 = / /频道设置RDMACIS位换= 100字读低的话2 / /设置RDMACIS 14位= 1阅读从RAM write_reg (RDMAC、数据| 0 x0001); write_reg_IS (RDMACIS, //从TX DMA配置RAM中读取当前通道值 //设置TDMACIS位5-0 =通道 //设置TDMACIS位11-8 = 0010读取dword 1的下一个字 //设置TDMACIS位14 = 1从RAM中读取 write_reg_IS(TDMACIS, 0x4200 +通道); read_reg(TDMAC, //启用通道TX DMA //用新值更新RAM //设置TDMAC位0 = 1启用HDLC通道 //设置TDMACIS位5-0 =通道 //设置TDMACIS位11-8 = 0010读取dword 1的下一个字 //设置TDMACIS位14 = 0写入RAM write_reg((TDMAC, data | 0x0001); write_reg_IS(TDMACIS, 0x0200,+频道);/ /使TX和RX DMA DS3131主配置寄存器/ /设置位0 = 1,使接收DMA / /设置位2 - 1 = 00破裂长度最大是32个dword / /设置位3 = 1,使传输DMA / /设置为6位= 1包PCI总线上的数据是大端字节/ /设置位12-7 = 000000选择端口0的专用资源伯特write_reg (MC, 0 x0049);
在通道配置和启用后,DS3131的内部逻辑完成向新配置的过渡大约需要5帧周期,即625µs。一旦这个转换完成,HDLC通道就可以被置于环回模式,这样在该通道上传输的所有数据也可以在该通道上接收。在5帧等待期之前将HDLC通道置于环回模式可能导致垃圾数据被写入通道的Rx FIFO。
抵消/地址 | 首字母缩写 | 注册的名字 | 数据表部分 |
01 xx | RP [n] CR | 接收端口n控制寄存器 | 5.2 |
//等待至少5个帧周期完成DS3131内部初始化 frame_wait(5) //设置bit10 = 1,使环回路由将数据发送回接收端口 read_reg(r0cr + 4*端口,数据) write_reg(r0cr + 4*端口,数据| 0x0400);
一旦DS3131初始化完成,就可以发送和接收数据。由于DS3131处于环回模式,在HDLC通道上传输的所有数据也在该通道上接收。介绍在主机内存中建立数据包、发送数据包、接收数据包和检查结果的过程。下面几节将详细描述这个过程。
在DS3131可以将dma接收的数据包从其内部FIFO传输到主机内存之前,主机必须指示DS3131将数据放在哪里。这是通过Rx free队列完成的。Rx空闲队列中的每个条目都包含一个指向Rx数据缓冲区的指针和一个Rx包描述符索引。本例使用一个Rx空闲队列条目。这个条目包含一个Rx空闲队列大缓冲区和一个Rx包描述符。DS3131 Rx大数据缓冲区大小已设置为256字节(RLBS = 256)。此外,DS3131已配置为使用4字节的CRC,并将Rx CRC写入Rx数据缓冲区。因此,一个Rx大的数据缓冲区能够容纳多达252字节的数据包数据。
抵消/地址 | 首字母缩写 | 注册的名字 | 数据表部分 |
0710 | RFQLBWP | 接收空闲队列大缓冲区主机写指针 | 8.1.3 |
0718 | RFQLBRP | 接收空闲队列大缓冲区DMA读指针 | 8.1.3 |
//检查RX大空闲队列中是否有空间 read_reg(RFQLBWP, wr_ptr); read_reg(RFQLBRP, rd_ptr); if (rd_ptr >wr_ptr) cnt = rd_ptr - wr_ptr - 1; else cnt = rfq_end_idx - wr_ptr + rd_ptr; //如果RX空闲队列中有空间,则在队列中放入1个条目 // dword 0 = RX数据缓冲区地址 //(从RX缓冲区的基址开始使用RX数据缓冲区) // dword 1 =对应的RX描述符索引(使用RX描述符表索引0) If (cnt >0) { rx_dscr_idx = 0; wr_dword(rfq_base_addr + wr_ptr*8, rx_buf_base_addr); wr_dword(rfq_base_addr + wr_ptr*8 + 4, rx_dscr_idx); //将RX空闲队列大缓冲区写指针提前1个 write_reg(RFQLBWP, (wr_ptr + 1) % (rfq_end_idx + 1)); }
本例发送一个16字节的数据包。在发送数据包之前,它必须在主机内存中构造。此外,还必须在主机内存中构造相应的Tx包描述符。下面的代码详细介绍了这些任务。
/ /创建一个16字节的数据包在TX缓冲区内存的起始地址TX / /缓冲区基地址wr_dword (tx_buf_base_addr 0 x01234567); wr_dword (tx_buf_base_addr + 4 0 x89abcdef); wr_dword (tx_buf_base_addr + 8,0 x02468ace); wr_dword (tx_buf_base_addr + 12,0 x13579bdf); / /创建一个TX描述符(4 dword) TX的包描述符/ / TX描述符表索引0 / / dword0 = TX缓冲区地址/ / dword1 = EOF,简历,字节数,下一个描述符指针 // dowrd2 = HDLC通道 // dword3 = PV,下一个挂起的描述符指针(设为0) tx_dscr_idx = 0 wr_dword(tdscr_base_addr + tx_dscr_idx*16 + 16, tx_buf_base_addr) wr_dword(tdscr_base_addr + tx_dscr_idx*16 + 4, 0x80100000) wr_dword(tdscr_base_addr + tx_dscr_idx*16 + 8, 0x00000000 +通道) wr_dword(tdscr_base_addr + tx_dscr_idx*16 + 12, 0x00000000);
为了传输数据包,必须将Tx描述符放在传输挂起队列中,然后必须增加传输挂起队列写指针(TPQWP)。当DS3131检测到挂起队列不是空的(TPQWP不等于TPQRP)时,它开始处理队列条目并传输数据包。
抵消/地址 | 首字母缩写 | 注册的名字 | 数据表部分 |
0028 | SDMA | DMA状态寄存器 | 4.3.2 |
080 c | TPQWP | 传输挂起队列主机写指针 | 8.2.3 |
0810 | TPQRP | 传输挂起队列DMA读指针 | 8.2.3 |
//读取SDMA寄存器以清除任何先前设置的状态位 read_reg(SDMA, data); //检查TX挂起队列的空闲空间 read_reg(TPQWP, wr_ptr); read_reg(TPQRP, rd_ptr) if (rd_ptr >wr_ptr) cnt = rd_ptr - wr_ptr - 1; else cnt = rfq_end_idx - wr_ptr + rd_ptr; //如果TX挂起队列中有空间为数据包创建一个条目 If (cnt >0) { wr_dword(tpq_base_addr + wr_ptr*4, 0x0000000 +(通道<< //提前TX挂起队列写指针 write_reg(TPQWP, (wr_ptr + 1) % (tpq_end_idx + 1)); }
在等待数据包的发送和接收足够的时间后,可以执行几个检查来确定数据包的发送和接收是否成功。下面的代码详细说明了这些检查。
抵消/地址 | 首字母缩写 | 注册的名字 | 数据表部分 |
0028 | SDMA | DMA状态寄存器 | 4.3.2 |
0710 | RFQLBWP | 接收空闲队列大缓冲区主机写指针 | 8.1.3 |
0718 | RFQLBRP | 接收空闲队列大缓冲区DMA读指针 | 8.1.3 |
073 c | RDQRP | 接收完成队列主机读指针 | 8.1.4 |
0740 | RDQWP | 接收完成队列DMA写指针 | 8.1.4 |
083 c | TDQRP | 传输完成队列主机读指针 | 8.2.4 |
0840 | TDQWP | 传输完成队列DMA写指针 | 8.2.4 |
/ / 2帧时间等待数据包传输/接收frame_wait(2); / /检查SDMA注册/ / = 0 x6440期望值,如果不是,这意味着有错误read_reg (SDMA、数据);/ /查看有多少条目TX完成队列(/ / TDQWP TDQRP距离)/ /期望值是1 - TX完成队列中的一个条目对应的包/ /发送read_reg (TDQRP rd_ptr); read_reg (TDQWP,wr_ptr);如果(wr_ptr祝辞= rd_ptr)问= wr_ptr - rd_ptr;其他问= tdq_end_idx + 1 - rd_ptr + wr_ptr; / /检查TX完成队列描述符/ /预期值= 0 x0001000 0表示描述符指针/ / / /比特位节显示通道号码,应该是本例中1 / / 28-26指示数据包状态,所有0表示数据包传输完成 //并且描述符指针字段对应于HDLC数据包中的第一个描述符 //已经传输 rd_dword(tdq_base_addr + rd_ptr*4, tdq_entry); //推进TX完成队列读指针 write_reg(TDQRP,(rd_ptr + 1) % (tdq_end_idx + 1)); //检查RX大空闲队列,看看队列中有多少RX缓冲区(距离 //从RFQLBRP到RFQLBWP) //预期数量为0,因为队列在接收数据包之前有一个缓冲区, //数据包接收需要1个缓冲区 read_reg(RFQLBRP, rd_ptr); read_reg(RFQLBWP,wr_ptr);如果(wr_ptr祝辞= rd_ptr)问= wr_ptr - rd_ptr;其他问= rfq_end_idx + 1 - rd_ptr + wr_ptr; / /检查RX完成队列是否收到任何数据包(/ / RDQWP RDQRP距离)/ /期望值是1 - RX完成队列中的一个条目条目对应于一个/ /包,应该是收到read_reg (RDQRP rd_ptr); read_reg (RDQWP,wr_ptr);如果(wr_ptr祝辞= rd_ptr)问= wr_ptr - rd_ptr;其他问= rdq_end_idx + 1 - rd_ptr + wr_ptr; / /检查RX完成队列描述符/ / = 0 x40010000期望值,0表示描述符指针/ / / /比特位节显示通道号码,应该是本例中1 / /位26-24指示缓冲区数,所有0意味着一个完整的包/ /收到rd_dword (rdq_base_addr + 8 * rd_ptr,rdq_entry); / /检查相应的RX描述符字(4 dword) / / 0 = 0 x10001000期望值RX缓冲区地址/ / dword 1 = 0 x80140000期望值/ /位的是下一个结果,描述符指针/ /位28-16是存储在数据缓冲区的字节数算31 - 29显示缓冲区状态/ / / /位dword 2除外值= 0 x000b7503 / /位5表示为频道号码(应该匹配TDQ入口通道)/ /位31-8显示时间戳(不同)rdscr_idx = rdq_entry,0 x0000ffff; rd_dword (rdscr_base_addr + 16 * rdscr_idx rdscr_dword0); rd_dword (rdscr_base_addr + 16 * rdscr_idx + 4, rdscr_dword1); rd_dword (rdscr_base_addr + 16 * rdscr_idx + 8, rdscr_dword2); / /检查RX缓冲区中的数据/ / 16字节的数据+ 4字节的CRC / /预期值= 0 0 x89abcdef x01234567 / / / / 0 x02468ace / / 0 x13579bdf / / 0 x05127b09(4字节的CRC) byte_count = (rdscr_dword1祝辞祝辞16),0x00001FFF; for (addr=rdscr_dword0, addr<rdscr_dword0+byte_count;addr=addr+4) rd_dword(addr, data); //推进RX完成队列读指针 write_reg(RDQRP, (rd_ptr + 1) % (rdq_end_idx + 1));
社群二维码
关注“华强商城“微信公众号
Copyright 2010-2023 hqbuy.com,Inc.All right reserved. 服务热线:400-830-6691 粤ICP备05106676号 经营许可证:粤B2-20210308