`EFM8通过EXP PORT可以引出SPI接口,并且支持SPI master模式.
一、硬件端口选择
如图所示
可见,SPI所需的4个引脚都已经引出,分别为4-P1.0 SPI0-MOSI/6-P0.7 SPI0-MISO/8-P0.6 SPIO-SCK/10-P1.1 SPI0-SN
二、初始化SPI接口
1、打开efm8的外设
如图所示,勾选SPI0外设,使能SPI设备。
2、SPI参数配置
按照上图所示配置SPI0参数,需要特别注意,这里我选择了Master 3-wire mode,也就是cs引脚需要通过外部gpio的方式控制。
另一个就是SPI Clock Frequency的选择,我这里选为12.25MHz,这么选的目的是因为希望尽量快的操作W5500,W5500允许80MHz最大的SPI时钟。
3、外设引脚选择
当SPI外设参数配置完成后,我们需要选择SPI的引脚,默认情况下mosi,miso和sck会自动选定,由于前面cs引脚选定为P1.1,所以我们用gpio的方式操作P1.1,我们修改P1.1的名字为SPI_CS。
二、W5500基础操作函数的移植
1、spi写1字节
- void spi_writechar(unsigned char d)
- {
- unsigned char i;
- SPI0CN0_SPIF=0;
- SPI0DAT=d; /* Send Register Address */
- while(SPI0CN0_SPIF==0);
- i=SPI0DAT;
- }
复制代码
2、spi写2字节
- void spi_writeint(unsigned int d)
- {
- unsigned char i;
- SPI0CN0_SPIF=0;
- SPI0DAT=d/256; /* Send Register Address */
- while(SPI0CN0_SPIF==0);
- i=SPI0DAT;
- SPI0CN0_SPIF=0;
- SPI0DAT=d; /* Send Register Address */
- while(SPI0CN0_SPIF==0);
- i=SPI0DAT;
- }
复制代码
3、spi读1字节
unsigned char spi_read(void)
{
unsigned char i;
SPI0CN0_SPIF=0;
SPI0DAT=0xff; /* Send Register Address */
while(SPI0CN0_SPIF==0);
i=SPI0DAT;
return i;
}
三、与W5500有关的函数移植
- /******************************* W5500 Write Operation *******************************/
- /* Write W5500 Common Register a byte */
- void Write_1_Byte(unsigned int data reg, unsigned char data dat)
- {
- /* Set W5500 SCS Low */
- SPI_CS = 0; // -select the Slave
- /* Write Address */
- spi_writeint(reg);
- /* Write Control Byte */
- spi_writechar(FDM1|RWB_WRITE|COMMON_R);
- /* Write 1 byte */
- spi_writechar(dat);
- /* Set W5500 SCS High */
- SPI_CS = 1; // De-select the Slave
- }
- /* Write W5500 Common Register 2 bytes */
- void Write_2_Byte(unsigned int data reg, unsigned char data *dat_ptr)
- {
- /* Set W5500 SCS Low */
- SPI_CS=0;
- /* Write Address */
- spi_writeint(reg);
- /* Write Control Byte */
- spi_writechar(FDM2|RWB_WRITE|COMMON_R);
- /* Write 2 bytes */
- spi_writechar(*dat_ptr++);
- spi_writechar(*dat_ptr);
- /* Set W5500 SCS High */
- SPI_CS=1;;
- }
- /* Write W5500 Common Register n bytes */
- void Write_Bytes(unsigned int data reg, unsigned char data *dat_ptr, unsigned int data size)
- {
- unsigned int i;
- /* Set W5500 SCS Low */
- SPI_CS=0;
- /* Write Address */
- spi_writeint(reg);
- /* Write Control Byte */
- spi_writechar(VDM|RWB_WRITE|COMMON_R);
- /* Write n bytes */
- for(i=0;i
- {
- spi_writechar(*dat_ptr++);
- }
- /* Set W5500 SCS High */
- SPI_CS=1;
- }
- /* Write W5500 Socket Register 1 byte */
- void Write_SOCK_1_Byte(SOCKET data s, unsigned int data reg, unsigned char data dat)
- {
- /* Set W5500 SCS Low */
- SPI_CS=0;
- /* Write Address */
- spi_writeint(reg);
- /* Write Control Byte */
- spi_writechar(FDM1|RWB_WRITE|(s*0x20+0x08));
- /* Write 1 byte */
- spi_writechar(dat);
- /* Set W5500 SCS High */
- SPI_CS=1;
- }
- /* Write W5500 Socket Register 2 byte */
- void Write_SOCK_2_Byte(SOCKET data s, unsigned int data reg, unsigned int data dat)
- {
- /* Set W5500 SCS Low */
- SPI_CS=0;
- /* Write Address */
- spi_writeint(reg);
- /* Write Control Byte */
- spi_writechar(FDM2|RWB_WRITE|(s*0x20+0x08));
- /* Write 2 bytes */
- spi_writeint(dat);
- /* Set W5500 SCS High */
- SPI_CS=1;
- }
- /* Write W5500 Socket Register 2 byte */
- void Write_SOCK_4_Byte(SOCKET data s, unsigned int data reg, unsigned char data *dat_ptr)
- {
- unsigned char i;
- /* Set W5500 SCS Low */
- SPI_CS=0;
- /* Write Address */
- spi_writeint(reg);
- /* Write Control Byte */
- spi_writechar(FDM4|RWB_WRITE|(s*0x20+0x08));
- /* Write 4 bytes */
- for(i=0;i<4;i++)
- spi_writechar(*dat_ptr++);
- /* Set W5500 SCS High */
- SPI_CS=1;
- }
- /******************************* W5500 Read Operation *******************************/
- /* Read W5500 Common register 1 Byte */
- unsigned char Read_1_Byte(unsigned int data reg)
- {
- unsigned char data i;
- /* Set W5500 SCS Low */
- SPI_CS=0;
- /* Write Address */
- spi_writeint(reg);
- /* Write Control Byte */
- spi_writechar(FDM1|RWB_READ|COMMON_R);
- /* Write a dummy byte */
- i = spi_read();
- /* Set W5500 SCS High*/
- SPI_CS=1;
- return i;
- }
- /* Read W5500 Socket register 1 Byte */
- unsigned char Read_SOCK_1_Byte(SOCKET data s, unsigned int data reg)
- {
- unsigned char data i;
- /* Set W5500 SCS Low */
- SPI_CS=0;
- /* Write Address */
- spi_writeint(reg);
- /* Write Control Byte */
- spi_writechar(FDM1|RWB_READ|(s*0x20+0x08));
- /* Write a dummy byte */
- i = spi_read();
- /* Set W5500 SCS High*/
- SPI_CS=1;
- return i;
- }
- /* Read W5500 Socket register 2 Bytes */
- unsigned int Read_SOCK_2_Byte(SOCKET data s, unsigned int data reg)
- {
- unsigned int data i;
- /* Set W5500 SCS Low */
- SPI_CS=0;
- /* Write Address */
- spi_writeint(reg);
- /* Write Control Byte */
- spi_writechar(FDM2|RWB_READ|(s*0x20+0x08));
- // i=SPI0DAT;
- /* Write a dummy byte */
- SPI0CN0_SPIF=0;
- i = spi_read();
- i*=256;
- i += spi_read();
- /* Set W5500 SCS High*/
- SPI_CS=1;
- return i;
- }
- /******************** Read data from W5500 Socket data RX Buffer *******************/
- unsigned int Read_SOCK_Data_Buffer(SOCKET data s, unsigned char xdata *dat_ptr)
- {
- unsigned int data rx_size;
- unsigned int data offset, offset1;
- unsigned int data i;
- rx_size=Read_SOCK_2_Byte(s,Sn_RX_RSR);
- if(rx_size==0) /* if no data received, return */
- return 0;
- if(rx_size>1460)
- rx_size=1460;
- offset=Read_SOCK_2_Byte(s,Sn_RX_RD);
- offset1=offset;
- offset&=(S_RX_SIZE-1); /* Calculate the real physical address */
- /* Set W5500 SCS Low */
- SPI_CS=0;
- /* Write Address */
- spi_writeint(offset);
- /* Write Control Byte */
- spi_writechar(VDM|RWB_READ|(s*0x20+0x18));
-
- if((offset+rx_size)
- {
- /* Read Data */
- for(i=0;i
- {
- *dat_ptr++ = spi_read();
- }
- }
- else
- {
- offset=S_RX_SIZE-offset;
- for(i=0;i
- {
- *dat_ptr++ = spi_read();
- }
- /* Set W5500 SCS High*/
- SPI_CS=1;
- /* Set W5500 SCS Low */
- SPI_CS=0;
- /* Write Address */
- spi_writeint(0);
- /* Write Control Byte */
- spi_writechar(VDM|RWB_READ|(s*0x20+0x18));
- /* Read Data */
- for(;i
- {
- *dat_ptr++ = spi_read();
- }
- }
- /* Set W5500 SCS High*/
- SPI_CS=1;
- /* Update offset*/
- offset1+=rx_size;
- Write_SOCK_2_Byte(s, Sn_RX_RD, offset1);
- Write_SOCK_1_Byte(s, Sn_CR, RECV); /* Write RECV Command */
- return rx_size;
- }
复制代码
四、初始化W5500的相关函数及初始化过程
1、配置W5500函数
- /* Config W5500 */
- void W5500_Config(void)
- {
- unsigned char data dat[6];
- Write_1_Byte(MR,RST);
- Delay(100);
- /* Set Dateway IP as 192.168.0.1 */
- dat[0]=192;
- dat[1]=168;
- dat[2]=1;
- dat[3]=1;
- Write_Bytes(GAR,dat,4);
- /* Set SUBNET MASK as 255.255.255.0 */
- dat[0]=255;
- dat[1]=255;
- dat[2]=255;
- dat[3]=0;
- Write_Bytes(SUBR,dat,4);
- /* Set MAC Address as: 0x48,0x53,0x00,0x57,0x55,0x00 */
- dat[0]=0x48;
- dat[1]=0x53;
- dat[2]=0x00;
- dat[3]=0x57;
- dat[4]=0x55;
- dat[5]=0x00;
- Write_Bytes(SHAR, dat, 6);
- /* Set W5500 IP as 192.168.0.20 */
- dat[0]=192;
- dat[1]=168;
- dat[2]=1;
- dat[3]=20;
- Write_Bytes(SIPR,dat,4);
- }
复制代码
2、检测网关
- /* Detect Gateway */
- unsigned char Detect_Gateway(void)
- {
- unsigned char data dat[4];
- /* Set a different subnet destination IP */
- dat[0]=192+1;
- dat[1]=168+1;
- dat[2]=0+1;
- dat[3]=20+1;
- Write_SOCK_4_Byte(0,Sn_DIPR,dat);
- /* Set Socket n in TCP mode */
- Write_SOCK_1_Byte(0,Sn_MR,MR_TCP);
- /* Open Socket n */
- Write_SOCK_1_Byte(0,Sn_CR,OPEN);
- Delay(5); /* Wait for a moment */
- if(Read_SOCK_1_Byte(0,Sn_SR)!=SOCK_INIT)
- {
- Write_SOCK_1_Byte(0,Sn_CR,CLOSE); /* Close Socket 0 */
- return FALSE;
- }
- /* Make connect */
- Write_SOCK_1_Byte(0,Sn_CR,CONNECT);
- do
- {
- if(Read_SOCK_1_Byte(0,Sn_IR)&IR_TIMEOUT) /* No Gateway Detected */
- {
- Write_SOCK_1_Byte(0,Sn_CR,CLOSE); /* Close Socket 0 */
- return FALSE;
- }
- else if(Read_SOCK_1_Byte(0,Sn_DHAR)!=0xff) /* Detect Gateway */
- {
- Write_SOCK_1_Byte(0,Sn_CR,CLOSE); /* Close Socket 0 */
- break;
- }
- }while(1);
- return TRUE;
- }
复制代码
3、配置Socket0
- /* Config Scoket */
- void Socket0_Config(void)
- {
- unsigned char data dat[4];
- Write_SOCK_1_Byte(0,Sn_CR,CLOSE);
- /* Set Socket 0 Port Number as 5000 */
- Write_SOCK_2_Byte(0,Sn_PORT,5000);
- /* Set Socket0 Destination IP as 192.168.0.40*/
- dat[0]=192;
- dat[1]=168;
- dat[2]=1;
- dat[3]=101;
- Write_SOCK_4_Byte(0,Sn_DIPR,dat);
- /* Set Socket0 Destination Port Number as 5000 */
- Write_SOCK_2_Byte(0,Sn_DPORTR,5000);
- /* Set Maximum Segment Size as 1470 */
- Write_SOCK_2_Byte(0, Sn_MSSR, 500);
- /* Set RX Buffer Size as 2K */
- Write_SOCK_1_Byte(0,Sn_RXBUF_SIZE, 0x02);
- /* Set TX Buffer Size as 2K */
- Write_SOCK_1_Byte(0,Sn_TXBUF_SIZE, 0x02);
- }
复制代码
4、初始化W5500
- /* Detect Ethernet Link */
- do
- {
- Delay(100); /* wait 100ms */
- i=Read_1_Byte(PHYCFGR);
- }while((i&LINK)==0);
- W5500_Config(); /* Initialize W5200 */
- if(Detect_Gateway()==TRUE) /* Detect Gateway */
- LED0 = 0;
复制代码
五、检测移植效果
完成移植过程后,看看是否可以ping通。
电路连接方式参看下图:
ping的过程展示
`
|