一,整个ethercat项目开发流程
通过STM32相关学习板,理解EtherCAT协议栈和通信步骤。根据项目需求构建XML,该XML将会由TwinCAT2解析,将相关特STM32程序烧写,修改应用层协议的程序。STM32作为SPI主模式与ZYNQ LAN9252进行数据交互,对其交互流程在复杂协议栈逐渐理解。
二,ZYNQ LAN9252
1,LAN9252四种工作模式:
自我工作模式(数字I/O模式),8入8出 |
|
SPI 串口通信模式,4线串行数据(或更多SQI) |
|
并行通信模式(HBI),16/8位数据交互 |
|
扩展模式,LAN9252与MCU之间SPI通信,同时对外再提供一组MII接口,可扩展连接另一组PHY芯片,多接一个RJ45端子。 |
2,整个工程中,LAN9252作用:
PHY的作用:所有跟以太网RJ45交互的工作由LAN9252完成。
网络交换作用:EtherCAT要求从站必须有一拖一的能力,不可以终结总线,LAN9252有2端口/3端口模式,内部做网络交换。
三,zynq block design IP核搭建连线注意事项
1,zynq根LAN9252的通信用的就是SPI四根线的使能。
2,PS端口增加一个定时器中断,1ms周期,调用ECAT_CheckTimer()函数,但不要一上来就初始化使能这个中断,根据接口定义好使能入口,让协议栈调用,以上电就开启这个定时器中断会导致连接失败。
3,三个外部中断:IRQ,SCY0,SCY1。其中IRQ必须实现连接到IRQ_F2P中断。SCY0和SCY1是分布式时钟同步用的,可以选择使用(也一起连接到IRQ_F2P),也可不使用(不用连接)。注意这三个中断的使能同样要根据代码中的接口定义入口,由协议栈使能和失能中断,不能上电就直接使能中断。
为LAN9252和PIC24设置相同的中断极性。例如,如果PIC24 ESC中断线为-则LAN9252 IRQ线路应配置为活动低。还应为LAN9252和PIC24配置SYNC0/SYNC1中断极性。例如,如果PIC24 SYNC0/SYNC1线配置为负沿,则LAN9252 SYNC0/SYNC1应为配置为有效低。SYNC0/SYNC1配置可通过EEPROM更改。
SPI从接口支持两种地址模式:2字节寻址模式和3字节寻址模式。在2字节寻址的情况下,较低的13个地址位A[12:0]由SPI主控器选择,而较高的3个位A[15:13]假设为SPI从控器内的000b,因此只能访问EtherCAT从控器地址空间中的前8k字节。3字节寻址用于访问EtherCAT从机的整个64K字节地址空间。
中断中处理的函数示范:
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == LAN9252_IRQ_Pin)
{
PDI_Isr();
return;
}
if (GPIO_Pin == LAN9252_SYC0_Pin)
{
DISABLE_ESC_INT();
Sync0_Isr();
ENABLE_ESC_INT();
return;
}
if (GPIO_Pin == LAN9252_SYC1_Pin)
{
DISABLE_ESC_INT();
Sync1_Isr();
ENABLE_ESC_INT();
return;
}
}
4,ps端中断读取处理:开启线程,轮询读取。linux下中断号是31+30=61
axi_quad_spi_0: axi_quad_spi@41e00000
{
bits-per-word = <8>;
clock-names = "ext_spi_clk", "s_axi_aclk";
clocks = <&clkc 15>, <&clkc 15>;
compatible = "xlnx,axi-quad-spi-3.2", "xlnx,xps-spi-2.00.a";
fifo-size = <16>;
interrupt-names = "ip2intc_irpt";
interrupt-parent = <&intc>;
interrupts = <0 31 1>;
num-cs = <0x1>;
reg = <0x41e00000 0x10000>;
xlnx,num-ss-bits = <0x1>;
xlnx,spi-mode = <2>;
};
LAN9252代码是由三个大任务函数构成
int main(void)
{
HW_Init(); /*PDI(过程数据接口)初始化,这里用的是MCI接口*/
MainInit(); /*主函数初始化包含:ESC和COE*/
bRunApplication = TRUE; /*处于运行状态标志*/
do
{
MainLoop();/*主循环函数,实现周期性和非周期性数据交换*/
} while (bRunApplication == TRUE); /*检查是否处于运行状态*/
HW_Release(); //无意义的函数
return 0; //设置正确返回
}
1,HW_Init(void)函数,定义了PDI接口,定义了ESC到PDI中断的映射:
ESC的PDI(过程数据接口)有这几种情况:
(1)Up to 32 bit digital I/O——32位数字量I/O
(2)Serial Peripheral Interface ——SPI总线
(3)8/16-bit synchronous/asynchronous Microcontroller Interface ——MCI接口
(4)With FPGA, specific on-board-bus——带FPGA的,特定的on-board-bus
在倍福的手册中也可以看到0x0140寄存器描述了PDI过程数据接口的几种情况。
2,MainInit(void)函数,定义了EtherCAT从站接口,COE(CANopen Over EtherCAT)相关的配置。其中的ECAT_Init()函数用于初始化从站接口。COE_ObjInit函数用于COE对象字典的初始化。
3,这样就完成了MainInit()函数,处于运行状态了,下一步就开始跑应用层的任务,只要处于运行状态就循环进行MainLoop()函数。
配置LAN9252中断配置寄存器
通过ZYNQ PS读写SPI接口发送数据
地址 |
判断 |
|
读0x314 |
data[31]==1 |
判断当前是不是在写过程数据:是则跳转到状态b,否则跳转到状态c |
写0x314 |
data[30]<= 1 |
停止当前写过程数据 |
写0x310 |
data<={length,address} |
ddress <= 0x1400,这是Lan9252写过程数据区的起始地址;Length <= 待搬运的数据长度,单位为byte |
写0x314 |
启动写操作 |
|
读0x314 |
判断data[0]==0?是,则开始DMA数据搬运;否,则停留在这个操作等待可用。【判断是否有可用空间,如果有,则Fifocnt <= data[8+:5]】 |
|
#include
#include
#include
#include
int main(int argc, char **argv)
{
int fd;
int len;
unsigned char buf[10];
unsigned char tmp;/* 验证输入参数个数 */
if(3 != argc)
{
printf("none para\n");
return -1;
}
/* 打开输入的设备文件, 获取文件句柄 */
fd = open(argv[1], O_RDWR);
if(fd < 0)
{
/* 打开文件失败 */
printf("Can't open file %s\r\n", argv[1]);return -1;
}
int i = 0;int j = 0;len =strlen(argv[2]);
for(i=0;i='0' && argv[2][i]<='9')
{
tmp = argv[2][i] - '0';
}
else if(argv[2][i]>='a' && argv[2][i]<='f')
{
tmp = argv[2][i] - 'a'+10;
}
else if(argv[2][i]>='A' && argv[2][i]<='F')
{
tmp = argv[2][i] - 'A'+10;
}
else
{
printf("Invalid input parameters \r\n");
return -1;
}
if(i%2==0)
buf[j] = tmp<<4;
else
{
buf[j] += tmp;
j++;
}
}
len = j;
printf("Test wr:");
for(i=0;i