W5100 수신 문제

수고많으십니다.

현재 STM32F407ZGT를 사용하여 W5100 시험 중에 있습니다.

시험중에 수신부분을 확인하고자 W5100 설정 후, 수신 루프에서

한번만 수신을 하고 그 다음부터는 수신을 하지 않는 현상이 발생하였습니다.
*노트북에서 수신 받는 데이터크기는 16byte 입니다.

  1. 아래 소스의 recv_size 변수가 처음에는 24로 수신되고, 두 번째부터는 0으로 표시됩니다.

  2. 그리고 DBWrite8(S0_CR,0x40); //RECV 를 주석처리하면 recv_size는 24씩 증가를 합니다.

    이런 문제가 왜 발생하는지 알 수 있을까요??

아래는 수신 소스 입니다.

=================================================================
recv_size = (DBRead8(S0_RX_RSR1) << 8) + DBRead8(S0_RX_RSR2);
printf(“recv size : %d\r\n”,recv_size);

if(recv_size > 0)
{
	ptr = (DBRead8(S0_RX_RD1) << 8) + DBRead8(S0_RX_RD2);

	memcpy(g_iRecvData_W5100,(uint8_t *)(0x60006000+ptr),24);

	ptr += recv_size;

	ptr1 = (ptr & 0xff00) >> 8;
	ptr2 = ptr & 0x00ff;

	DBWrite8(S0_RX_RD1,ptr1);
	DBWrite8(S0_RX_RD2,ptr2);

	DBWrite8(S0_CR,0x40);	//RECV
}

================================================================
W5100 설정 부분
DBWrite8(0x0000,0x80); //W5100 Reset

DBWrite8(S0_MR,0x02);	//Socket Register Mode Setting(UDP)

DBWrite8(SUBNETMASK1,0xff);	//SubnetMask Setting, SUBR (Subnet Mask Register)
DBWrite8(SUBNETMASK2,0xff);	//255.255.255.0
DBWrite8(SUBNETMASK3,0xff);
DBWrite8(SUBNETMASK4,0x00);

DBWrite8(0x040c,0xc0);	//Destination IP Setting, Sn_DIPR (Socket n Destination IP Address Register)
DBWrite8(0x040d,0xa8);	//192.168.0.201
DBWrite8(0x040e,0x00);
DBWrite8(0x040f,0xc9);

DBWrite8(0x0410,0x07);	//Destination Port Setting, Sn_DPORT (Socket n Destination Port Register)
DBWrite8(0x0411,0xd0);	//2000

DBWrite8(S0_CR,0x01);	//Socket Open

DBWrite8(Source_IP1,0xc0);	//IP Setting, SIPR (Source IP Address Register)
DBWrite8(Source_IP2,0xa8);	//192.168.0.200
DBWrite8(Source_IP3,0x00);
DBWrite8(Source_IP4,0xc8);

DBWrite8(S0_PORT1,0x0b);	/ Port Setting(3000)
DBWrite8(S0_PORT2,0xb8);

Sn_RX_RSR 값은 Sn_RX_WR - Sn_RX_RD 값으로 계산되어집니다.
Sn_RX_WR, Sn_RX_RD 값을 첫번째 데이터를 전송하였을때와 두번째 데이터를 전송하였을때의 값을 비교해보셔서 어떤 레지스터가 문제인지 확인해보시면 좋을것 같습니다.

또한 변수의 사이즈를 한번더 확인해보시기 바랍니다.
recv_size 와 ptr은 unsigned int 16bit, ptr1과 ptr1는 unsigned int 8bit로 선언된것이 맞나요?

1 Like

네. 변수 사이즈는

uint16_t recv_size;
uint16_t ptr;
uint8_t ptr1,ptr2;

맞게 설정되어 있습니다.

Sn_RX_WR 번지수가 어떻게 되나요?

데이터시트에서는 검색이 안되네요.

Sn_RX_RD 바로 다음주소로
0번 socket의 경우 0x042A - 0x042B 입니다.

1 Like

Sn_RX_RD 읽어보면

0x042A : 0x0, 0x042B : 0x18

로 읽힙니다.

DBWrite8(S0_CR,0x40); //RECV 이 부분을 주석처리하면 값은 0x18씩 증가를 합니다.

주석을 해제하면 0x18 로 유지가 되네요.

지금은 계속 수신만 하게되어있는데, 수신 후에 송신을 해야 되는건가요??

수신 이후에 송신을 해야할 필요는 없습니다.
계속 수신만 하는것도 가능합니다.
유선상으로 말씀드렸다시피, Sn_RX_WR 레지스터는 Sn_CR 레지스터의 영향을 받지 않습니다.
데이터를 RECV할때마다 Sn_RX_WR 값이 증가하는것이 정상적인 동작입니다.
우선 아래 3가지 확인 부탁드립니다.

  1. DBWrite8(S0_CR,0x40);
    이후 S0_CR 레지스터를 read하시면 0x00으로 clear 되는지 확인바랍니다.
  2. DBWrite8(S0_CR,0x40); 이후에 Sn_SR 레지스터도 확인 하시어 socket 상태에 변화는 없는지 확인 바랍니다. (TCP 통신의 경우 ESTABLISH 상태로 0x17이여야 하며, UDP 통신의 경우 0x22여야 합니다.)
  3. Sn_CR 레지스터의 address가 맞는지(0x0401) 한번더 확인 바랍니다.
1 Like
    uint16_t recv_size;
uint16_t ptr;
uint8_t ptr1,ptr2;
uint8_t test,test2,test3,test4;
uint8_t c,d;

ptr1=0;
ptr2=0;
ptr=0;
recv_size=0;
test=0;
test2=0;
test3=0;
test4=0;
c=0;
d=0;

    recv_size = (DBRead8(S0_RX_RSR1) << 8) + DBRead8(S0_RX_RSR2);
printf("recv size : %d\r\n",recv_size);

if(recv_size > 0)
{
	ptr = (DBRead8(S0_RX_RD1) << 8) + DBRead8(S0_RX_RD2);
	ptr = ptr & 0x07ff;

	memcpy(g_iRecvData_W5100,(uint32_t *)(0x60006000+recv_size-24),24);

	ptr += recv_size;

	ptr1 = (ptr & 0xff00) >> 8;
	ptr2 = ptr & 0x00ff;

	DBWrite8(S0_RX_RD1,ptr1);
	DBWrite8(S0_RX_RD2,ptr2);

	DBWrite8(S0_CR,0x40);	//RECV
}

c=DBRead8(S0_CR);
d=DBRead8(S0_SR);
printf("S0_CR: 0x%x   S0_SR: 0x%x\r\n",c,d);

test=DBRead8(0x042A);
test2=DBRead8(0x042B);

test3=DBRead8(S0_RX_RD1);
test4=DBRead8(S0_RX_RD2);
printf("0x042A : 0x%x, 0x042B : 0x%x\r\nS0_RX_RD1 : 0x%x S0_RX_RD2 : 0x%x \r\n",test,test2,test3,test4);

위와 같이 테스트하였을 때

첫 번째 수신 시에는

recv size : 24
S0_CR: 0x0 S0_SR: 0x22
0x042A : 0x0, 0x042B : 0x18
S0_RX_RD1 : 0x0 S0_RX_RD2 : 0x18

두번 째는

recv size : 0
S0_CR: 0x0 S0_SR: 0x22
0x042A : 0x0, 0x042B : 0x18
S0_RX_RD1 : 0x0 S0_RX_RD2 : 0x18

입니다.

#define S0_CR 0x0401
#define S0_SR 0x0403

로 정의되어있습니다.

왜 못받는지 이해가 안되네요…ㅜㅜ

추가로 코드를 한번더 확인해보니
Source IP와 Port를 Socket Open 이후에 설정해주시고 계신데
Socket Open전에 설정 바랍니다.

1 Like

오픈 전에 소스 IP와 Port를 설정하면 상태는 Sn_SR 상태는 0x22로 되는데

몇일 전에 수신이 되지 않아서 설정 순서를 바꾸다 보니 저 설정순서에서 수신이 되어 저렇게 하였습니다.

방금 설정 순서를 변경하였는데, 마지막에 오픈을 하니 수신이 안되네요.

Source IP와 Port를 설정하고나서 Socket을 오픈한 후,
Source IP와 Port 값을 확인할 경우에는 값이 남아있나요?

또한

아래는 ioDriver의 W5100에 대한 Recv 코드입니다.
지금 사용중이신 코드상에서는 masking 처리를 안해주고 있습니다.
현재 문제와 무관하다고 느끼실수 있으나,
masking 처리를 하지않고 데이터를 read할경우 chip의 엉뚱한 레지스터를 건드릴 수 있으므로 ptr에 masking 처리를 하여 데이터를 read하시기 바랍니다.
RxMAX 값은 Socket buffer size가 2KB로 설정되있다는 가정하에 2048, RXMASK 값은 2047(2048-1) 로 계산하시면 됩니다.

void wiz_recv_data(uint8_t sn, uint8_t *wizdata, uint16_t len)
{
  uint16_t ptr;
  uint16_t size;
  uint16_t src_mask;
  uint16_t src_ptr;

  ptr = getSn_RX_RD(sn);
  
  src_mask = (uint32_t)ptr & getSn_RxMASK(sn);
  src_ptr = (getSn_RxBASE(sn) + src_mask);

  
  if( (src_mask + len) > getSn_RxMAX(sn) ) 
  {
    size = getSn_RxMAX(sn) - src_mask;
    WIZCHIP_READ_BUF((uint32_t)src_ptr, (uint8_t*)wizdata, size);
    wizdata += size;
    size = len - size;
	src_ptr = getSn_RxBASE(sn);
    WIZCHIP_READ_BUF(src_ptr, (uint8_t*)wizdata, size);
  } 
  else
  {
    WIZCHIP_READ_BUF(src_ptr, (uint8_t*)wizdata, len);
  }
    
  ptr += len;
  
  setSn_RX_RD(sn, ptr);
}

uint32_t getSn_RxBASE(uint8_t sn)
{
   int8_t  i;
#if ( _WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_BUS_DIR_)
   uint32_t rxbase = _W5100_IO_BASE_ + _WIZCHIP_IO_RXBUF_;
#else   
   uint32_t rxbase = _WIZCHIP_IO_RXBUF_;
#endif   
   for(i = 0; i < sn; i++)
      rxbase += getSn_RxMAX(i);

   return rxbase;
}
1 Like

네. making 처리하겠습니다.

원인이 무엇인지 찾은 것 같습니다.

uint8_t Des_IP1,Des_IP2,Des_IP3,Des_IP4,Des_Port1,Des_Port2,Src_IP1,Src_IP2,Src_IP3,Src_IP4,Src_Port1,Src_Port2;

Des_IP1=0;
Des_IP2=0;
Des_IP3=0;
Des_IP4=0;
Des_Port1=0;
Des_Port2=0;
Src_IP1=0;
Src_IP2=0;
Src_IP3=0;
Src_IP4=0;
Src_Port1=0;
Src_Port2=0;

DBWrite8(0x0000,0x80);	//W5100 Reset

DBWrite8(S0_MR,0x02);	//Socket Register Mode Setting(UDP)

DBWrite8(SUBNETMASK1,0xff);	//SubnetMask Setting, SUBR (Subnet Mask Register)
DBWrite8(SUBNETMASK2,0xff);	//255.255.255.0
DBWrite8(SUBNETMASK3,0xff);
DBWrite8(SUBNETMASK4,0x00);

DBWrite8(0x040c,0xc0);	//Destination IP Setting, Sn_DIPR (Socket n Destination IP Address Register)
DBWrite8(0x040d,0xa8);	//192.168.0.201
DBWrite8(0x040e,0x00);
DBWrite8(0x040f,0xc9);

DBWrite8(0x0410,0x07);	//Destination Port Setting, Sn_DPORT (Socket n Destination Port Register)
DBWrite8(0x0411,0xd0);	//2000

DBWrite8(S0_CR,0x01);	//Socket Open

DBWrite8(Source_IP1,0xc0);	//IP Setting, SIPR (Source IP Address Register)
DBWrite8(Source_IP2,0xa8);	//192.168.0.200
DBWrite8(Source_IP3,0x00);
DBWrite8(Source_IP4,0xc8);

DBWrite8(S0_PORT1,0x0b);	//Port Setting(3000)
DBWrite8(S0_PORT2,0xb8);

Des_IP1=DBRead8(0x040c);
Des_IP2=DBRead8(0x040d);
Des_IP3=DBRead8(0x040e);
Des_IP4=DBRead8(0x040f);
Des_Port1=DBRead8(0x0410);
Des_Port1=DBRead8(0x0411);
Src_IP1=DBRead8(Source_IP1);
Src_IP2=DBRead8(Source_IP2);
Src_IP3=DBRead8(Source_IP3);
Src_IP4=DBRead8(Source_IP4);
Src_Port1=DBRead8(S0_PORT1);
Src_Port2=DBRead8(S0_PORT2);

printf("Des IP : %d.%d.%d.%d  Port : %d ", Des_IP1,Des_IP2,Des_IP3,Des_IP4,((Des_Port1<<8)|(Des_Port2)));
printf("Src IP : %d.%d.%d.%d   Port : %d \r\n", Src_IP1,Src_IP2,Src_IP3,Src_IP4,((Src_Port1<<8)|(Src_Port2)));

부팅 시 설정하는 부분입니다.

Des IP와 Port를 설정 → 오픈 → Src IP와 Port 설정
프린트 출력을 보면,

Des IP : 0.0.0.0 Port : 0 Src IP : 192.168.0.200 Port : 3000

Des IP와 Port가 0으로 초기화가 됩니다.

그리고 수신 후, IP와 Port를 보면

Des IP : 0.0.0.0 Port : 0 Src IP : 192.168.0.200 Port : 184

Src Port가 변경됨을 확인이 되네요.

Recv 커맨드 이후에 이런 현상이 있는 것 같습니다.

지속적으로 IP와 Port를 설정해줘야 되는건가요??

Source IP와 Port는 한번 설정해주면 변경되지 않는것이 정상동작입니다.
아까 말씀드린 포인터 부분때문에 CHIP의 엉뚱한 부분을 잘못건드릴 수 있습니다.
수정이후 동작을 다시한번 확인해보시기 바랍니다.

1 Like

S0_PORT1의 값이 정상인지 확인 바랍니다.
Port의 출력되는 값이 3000의 하위 8bit 값인 184가 나오는 것으로 보아 address가 잘못 되지 않았을까 생각됩니다.

1 Like

masking 중에 이상한 점이 있는데요. 정상적인 동작인지는 확인 부탁드리겠습니다.

ptr 을 masking하여 수신 중에 0xf0 다음에 24를 더하면 0x108이 되어야하는데

0x1f0로 읽힙니다.

아래 소스 코드 입니다.

    recv_size = (uint16_t)(DBRead8(S0_RX_RSR1) << 8) + (uint16_t)DBRead8(S0_RX_RSR2);
printf("recv size : %d\r\n",recv_size);

if(recv_size > 0)
{
	ptr = (uint16_t)(DBRead8(S0_RX_RD1) << 8) + (uint16_t)DBRead8(S0_RX_RD2);
	printf("ptr1 : 0x%x \r\n  ",ptr);

	read_data(ptr,g_iRecvData_W5100,recv_size);
	ptr += recv_size;

	ptr1 = (ptr & 0xff00) >> 8;
	ptr2 = ptr & 0x00ff;

	printf(" -I- ptr1 : 0x%x  prt2 : 0x%x \r\n  ",ptr1,ptr2);
	DBWrite8(S0_RX_RD1,ptr1);
	DBWrite8(S0_RX_RD2,ptr2);

	DBWrite8(S0_CR,0x40);	//RECV

	ptr = (uint16_t)(DBRead8(S0_RX_RD1) << 8) + (uint16_t)DBRead8(S0_RX_RD2);
	printf("ptr2 : 0x%x \r\n  ",ptr);
}

프린트 출력을 보면

recv size : 24
ptr1 : 0xd8
Head : 0x5533 - SN : 8399
-I- ptr1 : 0x0 prt2 : 0xf0
ptr2 : 0xf0

recv size : 24
ptr1 : 0x1f0
Head : 0x5533 - SN : 7941
-I- ptr1 : 0x2 prt2 : 0x8
ptr2 : 0x308

ptr2 가 0xf0에서 수신되었을 때 읽으면 ptr1 이 0xf0가 되고, ptr2가 0x108이 되어야 된다고 생각됩니다.

그리고 RECV 이후에, 포트는 다시 설정하고 있습니다.
설정을 주석처리하니 수신이 안되네요.
masking 정상동작하게되면 시험해보겠습니다.

read_data 함수입니다.

 void read_data(uint16_t src, uint8_t * dst, uint16_t len)
{
uint16_t size;
uint16_t src_mask;
uint32_t * src_ptr;

src_mask = src & 0x07FF;
src_ptr = (uint32_t *)(0x60006000 + src_mask);

if( (src_mask + len) > (uint16_t)(2048) )
{
	size = (uint16_t)2048 - src_mask;
	memcpy(dst, (uint32_t *)src_ptr, size);

	dst += size;
	size = len - size;
	src_ptr = (uint32_t *)(0x60006000);
	memcpy(dst, (uint32_t *)src_ptr, size);
}
else
{
	memcpy(dst, (uint32_t *)src_ptr, len);
}
}

확인부탁드립니다.

#define S0_PORT1 0x0404
#define S0_PORT2 0x0405

로 정의하였습니다.

이부분에서도 문제가 있는것 같습니다.
0x208이어야하는데 0x308이 되었네요

이 부분도 Source Port와 마찬가지로 Command 레지스터에 write한 이후 변경되고 있는듯한 느낌이 듭니다.
Read pointer를 잘못 건드려서 문제가 발생하고 있는것이 맞는지 확인하기 위해
read_data() 부분을 주석처리하고 동작할경우에는 이런문제가 안생기는지 확인부탁드립니다.

1 Like

해결했습니다. 감사합니다^^

read_data 함수는 지속적으로 시험해보면 될 것같습니다.

컴파일러 문제였네요.
~을

recv_size = (uint16_t)(DBRead8(S0_RX_RSR1) << 8) + (uint16_t)DBRead8(S0_RX_RSR2);

~으로

recv_size1 = DBRead8(S0_RX_RSR1);
recv_size2 = DBRead8(S0_RX_RSR2);
recv_size = (recv_size1 << 8) + recv_size2;

변경하니깐 이상없이 잘 동작합니다. ㅜㅜ

TrueSTUDIO 사용하는데 이런 문제가 있네요.

포트 설정은 RECV 이후에 해주고 있는데 포트설정이 계속해서 변경이 되네요.

안녕하세요.
Compiler 문제라기 보단 ( ) 연산에 대한 casting 우선 순위가 바뀌어서 생긴 문제로 보입니다.

recv_siz = (((uinit16_t)DBRead(S0_RX_RSR1)) << 8) + (uint16_t)DBRead8(S0_RX_RSR2)

맞는 Syntax인 것 같네요.