[W5300] 소켓 UDP 통신 (1:N) 질문입니다.

안녕하세요.

UDP통신에서 1:N을 진행 하려고 합니다.
네트워크를 모르다 보니 프로젝트 진행도중
UDP는 데이터 전송시 상대방 IP주소가 바뀌면 "ARP"를 전송하여 맥을 확인하는 작업이 있는줄 몰랐습니다.

STM103 MCU를 사용중이고 SendTo를 하는 시간을 체크해보니 28us 소모되었습니다.
SendTo 함수에서 “while (!((isr = getSn_IR(s)) & Sn_IR_SENDOK))” 부분이 있어서 상관 없는줄 알았으나 수백 수천번을 연속적으로 진행하다보니
데이터가 밀리는 현상이 발생되었습니다.

예를 들어 A가
B한테는 11 22 33 44을 전송하고
C한테는 55 66 77 88을 전송하는데 일정 시간 후에 보면

B한테는 22 33 44 11이 전송되고
C한테는 77 88 55 66이 전송 되는 데이터 밀림 현상이 발생됩니다.

추가적으로는 위 증상이 발생될때 11 22 33 44를 보내고 있다가
55 66 77 88를 전송하면 소켓 메모리에 11 22 33 44가 저장된 상태였는지
55 66 77 88 데이터가 아닌 11 22 33 44 데이터가 전송되었습니다.

아래는 사용하고 있는 함수입니다. “ARP” 전송 후 응답시간을 sendto 후에 얼마나 줘야 할지 몰라서 delay를 170us를 주었는도 계속 발생되네요…
그래서 1분마다 해당 소켓을 열고 닫고를 하는
setSn_CR(s, Sn_CR_CLOSE);
setSn_CR(s, Sn_CR_OPEN);
위 코드를 사용하니 해당 증상이 나오지는 않지만 어쩔 수 없이 닫고 여는 순간의 데이터가 빠지다보니 이걸로는 해결이 안되겠더라구요…

별도로 더 참고해야하는 부분이 있거나 놓친부분이 있을까요…?

uint32 SendTo_UDP(SOCKET s, uint8 * buf, uint32 len, uint8 * addr, uint16 port)
{
uint8 status=0;
uint8 isr=0;
uint32 ret=0;

if (len > getIINCHIP_TxMAX(s)) ret = getIINCHIP_TxMAX(s); // check size not to exceed MAX size.
else ret = len;

// set destination IP address
IINCHIP_WRITE(Sn_DIPR(s),(((uint16)addr[0])<<8) + (uint16) addr[1]);
IINCHIP_WRITE(Sn_DIPR2(s),(((uint16)addr[2])<<8) + (uint16) addr[3]);
// set destination port number
IINCHIP_WRITE(Sn_DPORTR(s),port);

wiz_write_buf(s, buf, ret); // copy data
// send
setSn_TX_WRSR(s,ret);
setSn_CR(s, Sn_CR_SEND);

g_mgrDevice.nTemp = 0;
while (!((isr = getSn_IR(s)) & Sn_IR_SENDOK)) // wait SEND command completion
{
g_mgrDevice.nTemp++;
if( g_mgrDevice.nTemp >= 50 )
{
setSn_IR(s,Sn_IR_TIMEOUT);
return 0;
}

status = getSn_SSR(s);                                // warning ---------------------------------------
if ((status == SOCK_CLOSED) || (isr & Sn_IR_TIMEOUT)) // Sn_IR_TIMEOUT causes the decrement of Sn_TX_FSR
{                                                     // -----------------------------------------------
  setSn_IR(s,Sn_IR_TIMEOUT);
  return 0;
}

}
setSn_IR(s, Sn_IR_SENDOK); // Clear Sn_IR_SENDOK

Delay(1000); // 약 170us

return ret;
}

안녕하세요

ioLibrary에 sendto함수가 있는데 사용하시지 않는 이유가 있으신가요?
해당함수를 사용하실경우 말씀하신현상과 같은 이슈는 없는것으로 알고 있습니다.
ARP는 자동으로 전송되며 Send 완료후 interrupt 발생을 체크하는데 왜 Delay를 주시는지 이해가 가질 않습니다.

기존에 사용하던 2009년도 부터 사용하던 sendto 함수에 맞춰있다보니
현재 ioLibrary의 sendto함수를 적용하기에는 기존에 사용하던게 있어서 뒤엎기는 힘들었습니다.
/**

  • \file socket.c
  • Implemetation of WIZnet SOCKET API fucntions
  • This file implements the WIZnet SOCKET API functions that is used in your internat application program.
  • Revision History :

  • Date Version Author Description

  • 24/03/2008 1.0.0 MidnightCow Release with W5300 launching

  • 15/05/2008 1.1.0 MidnightCow Refer to M_15052008.
  •                               Modify the warning code block in recv(). 
    

  • 04/07/2008 1.1.1 MidnightCow Refer to M_04072008.
  •                               Modify the warning code block in recv(). 
    

  • 08/08/2008 1.2.0 MidnightCow Refer to M_08082008.
  •                               Modify close(). 
    

*/

제가 사용하고 있는 socket.c 릴리즈 정보입니다.


g_mgrDevice.nTemp++;
if( g_mgrDevice.nTemp >= 50 )
{
setSn_IR(s,Sn_IR_TIMEOUT);
return 0;
}

기존 라이브러리 sendto함수에서 윗부분만 추가하였습니다.
1cycle당 2ms로 주기성이 맞게 하다보니 해당 위 내용은 (약 20us) 이상 전송 완료가 안 되더라도 다른 내용을 처리하기 위해 while문도 빠져나오고 TIMEOUT을 넣었습니다.

위 처럼 강제로 TIMEOUT을 넣게되면 문제가 생길까요?

밑에 Delay(1000); // 약 170us 부분은
while (!((isr = getSn_IR(s)) & Sn_IR_SENDOK))로 완료된 후
5~10us뒤에 바로 다른IP로 sendto를 보내는 동작을 하는 순간 send가 안되서
Delay를 넣으니 동작이 되길래 추가하였습니다.

--------------------------추가----------

g_mgrDevice.nTemp++;
if( g_mgrDevice.nTemp >= 50 )
{
setSn_IR(s,Sn_IR_TIMEOUT);
return 0;
}

Delay(1000);
두 부분을 제거 하고 해봤습니다.

3개의 IP에 보내게 되면 어떻게 될지 모르겠으나

A가 동시에 전송을 할때
B - 11 22 33 44를 전송하고
C - 55 66 77 88을 전송을 했으나

B - 55 66 77 88이 전송되고
C - 11 22 33 44가 전송되었습니다.

B,C가 서로 반대되는 데이터를 수신하였습니다.

B와 C를 따로따로 전송할때는 정상적으로
B - 11 22 33 44, C - 55 66 77 88을 수신하였습니다.

초기에 send로 ARP를 받아 상대방의 Mac을 저장하고
send_mac 방식을 사용하자니 에러확률이 있어서 사용을 못하겠네요…

위 내용을 해결하기 위한 방법이 더 있을까요…?

안녕하세요

Sn_IR 레지스터에 1 을 write하는것은 아무 의미가 없습니다.
Sn_IR 에 wirte는 Interrupt clear 처리를 위한것이지 Timeout 처리가 되지않습니다.
Timeout 처리를 빨리하고싶다면 RCR, RTR 레지스터를 설정하시는 것을 추천드립니다.

Dealy를 추가하는것은 궁극적인 문제 해결방법에 도움이 되지않아보입니다.

RCR = 1 // 총 2회 전송(자동전송 1회, 재전송 1회)
RTR = 1 // 100us
수정 하였습니다.

위처럼 수정 후 강제 TIMEOUT 부분이나 Delay(1000)부분을 삭제 하여도
위에서 작성된 것처럼 A가 동시에 B,C에게 데이터를 전송할 때
B가 받아야할 데이터를 C가 받고
C가 받아야할 데이터를 B가 받는 증상이 계속 나오고 있습니다.

동시에 보내지 않고 개별적으로 보내면 정상적입니다.

위 현상은 다른 레지스터를 확인해봐야 하나요…?

동시에 전송이라고 말씀하시는것은 어떤부분일까요?
같은 socket으로 동시에 여러곳에 send하는 프로세스라면 같은 레지스터와 메모리 공간이 공유되기때문에 당연히 데이터가 꼬일 수 밖에없습니다.
socket을 여러개 쓰시는것을 추천드립니다.

같은 Socket을 사용 하였습니다.

Sn_IR_SENDOK 인터럽트 처리가 된 후에 다음 데이터를 전송하게 되어서 메모리를 공유하더라도 데이터 처리가 괜찮을지 알았습니다…

Socket이 부족하여 한개의 Socket으로 처리했는데 그게 문제가 되는가 보네요.

메모리 공유가 문제라면 SEND_MAC도 동일한 증상이 나올 확률이 있다는건데
그렇다면 한 개의 Socket으로 위처럼 UDP를 이용한 1:N 통신 할 방법이 없는건가요?
(멀티캐스트를 제외한 방법입니다)

말씀하신 동작에 대해 이해가 잘 되지않습니다.
Destination IP 설정, 버퍼 데이터 복사, 데이터 전송, send ok 확인
위의 플로우가 섞여서 동작하지 않는다면 문제가 없습니다.

예를 들어
B의 IP설정 - B에 전송할 데이터 복사 - B데이터 전송 - B send ok 확인 - C 전송동작 반복
일경우 문제가 없습니다.