iMCU7200EVB UDP 통신 Recv 인터럽트

안녕하세요
iMCU7200EVB 을 구입하여 UDP 통신을 구현중에 질문 드립니다.

해당 API 함수들이 잘되어 있어 통신을 구현하는데 시간을 단축할수 있었습니다.

우선 iMCU7200EVB 에서 UDPOpen 하여 주기적으로 UDPSend 하여 PC에서 데이터를 받아보는 것은 잘 됩니다
그런데 iMCU7200EVB 에서 수신이 궁금합니다.
지금 UDPRecv 함수는 폴링 방식으로 수신된 메세지가 있는지 항상 감시해야 하는 방식인듯 한데

iMCU7200EVB UDP 통신 Recv 인터럽트로 구현할수도 있는 것인가요 ?

왜냐하면 항상 UDPRecv 함수를 메인루프안에서 감시하는것은 자원 낭비인듯하고
인터럽트로 수신하여 바로 수신한 내용을 처리하였으면 해서 질문드립니다.

안녕하세요
위즈네트 입니다.

Cortex-m3와 W5200으로 구성된 W7200이 내부적으로 인터럽트 핀(GPIOB_13PIN)이 연결되어 있어
문의 하신 인터럽트로 수신처리가 가능합니다.

W5500의 인터럽트 처리부분은 하기 부분을 참고 부탁드립니다.

  1. 인터럽트 초기화
  • IMR를 이용하여 인터럽트 사용할 Socket을 설정한다.

[quote]IMR (Interrupt Mask Register)는 Interrupt를 Mask하기 위해 사용한다. 각 Interrupt Mask Bit는
Interrupt Register2 (IR2)의 Bit와 같다. Interrupt Mask Bit가 set되어있다면, IR2의 해당 Bit가 set되었을
때 Interrupt가 발생 할 것이다. 만약 IMR이 ‘0’으로 set되어 있다면, IR2의 해당 Bit가 set되더라도
Interrupt는 발생하지 않는다[/quote]

  1. 인러럽트 확인
    2.1 W5500의 인터럽트 발생시 IPconfict나 PPPoE Close는 IR를 이용하여
    Socket중 어느 소켓에서 인터럽트가 발생하였는지는 IR2를 이용하여 확인한다.

[quote]IR은 Interrupt 발생여부를 판단하기 위해 Host processor에 MCU에서 access한다. IR Bit가 set되면 이
INTn 신호는 low 상태 asserted되고 IR의 모든 Bit들을 clear하지 않는 이상 high상태로 변하지 않는다.
IR은 MCU에 Interrupt신호를 발생시킨다[/quote]

[quote]IR2는 W5200 SOCKET Interrupt가 발생할 경우 이것을 알려주는 register이다. Interrupt가 발생했을
때, IR2의 해당 Bit가 set된다. 이 경우 IR2의 모든 Bit들이 ‘0’으로 clear될 때까지 INTn 신호는 low상
태가 된다. Sn_IR Bit들을 이용해서 IR2 register를 clear하면 INTn 신호는 high 상태가 된다.
[/quote]

2.2 IR2에서 해당 소켓의 Sn_IR를 확인하여 인터럽트 타입을 확인한다. (RECV 인터럽트 포함)

[quote]Sn_IR register는 SOCKET n의 Interrupt (establishment, termination, receiving data, timeout) type과 같
은 정보를 제공한다. Interrupt가 발생하고 Sn_IMR의 해당 Mask Bit가 ‘1’인 경우 Sn_IR의 Interrupt Bit
는 ‘1’로 된다. Sn_IR Bit를 clear하기 위해서는, 해당 Bit에 다시 ‘1’을 write해야 한다.
[/quote]

  1. 인터럽트 발생 후 다음 인터럽트를 처리하기 위해 인터럽트 타입을 확인한 후 반드시 IR과 IR2의 해당 Bit에 '1’를 Write한다.

감사합니다.

Interrupt는 중첩 발생할 수 있으며, Pending을 지원하지 않습니다.
따라서, 말씀하신 Recevie Interrupt가 발생할 경우 Receive를 처리할 경우, 처리 속도에 따라 Interrupt가 중첩되어 Loss가 발생할 수 있습니다. Interrupt가 발생할 경우 Flag만 체크하시고, ISR routine이 아닌 곳에서 Flag를 확인하여 수신을 처리하는 것을 권장합니다.
굳이, ISR에서 모든 Receive 처리하실 경우 Sn_RX_RSR이 0인 경우에 Sn_IR(RECV)를 Clear하시고 ISR routine을 빠져나올 수 있도록 하여야 합니다.

네 답변 감사드립니다.

그런데 아직 구현을 못했습니다.

W7200매뉴얼을 보니 말씀하신대로 PC13번이 내부적으로 연결되었더군요

위즈넷에서 제공하는 드라이버 코드로 구현중인데
GPIO_Configuration(); 내용중에 아래와 같이 하였지만 아직 인터럽트가 제대로 되지 않고 있습니다.

GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource13);
//GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource13);
EXTI_InitStructure.EXTI_Line = EXTI_Line13;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
EXTI_GenerateSWInterrupt(EXTI_Line13);

드라이버 코드에 이미 인터럽트를 대비한 코드가 있을 듯한데
어디 어디를 찾아서 수정하여야 하는지 가이드 라인을 주실수 있으신지요 ?
혹시 구현된 예제를 얻을순 없을까요 ?
단순히 UDP 통신이 들어올때마나 ISR 함수 까지 진입하는것을 볼수 있는 GPIO 아 INT 셋팅 만 알면 충분할 것 같습니다.

혹시 IMR 즉 interrupt mask regsiter 와 IMR2 resiter 값이 0xFF로 각각 설정되어 있는지 확인부탁합니다.

문제점 증상

  1. Sn_IR (SOCKET n Interrupt Register) [R] [0x4002+0x0n00] [0x00]
    분명 R, READ라고 써있는데 인터럽트 마스킹 하려면 Sn_IR레지스터에 1Write하여 클리어 해야하는게
    맞나요? R/W라고 쓰여있어야 하는거 아닌가요?

  2. IMR레지스터와 IMR2레지스터에서 5200데이타 시트 보면 IMR/IMR2에 대해 안나와있내요?
    7200에 맞는 데이타시트와 레지스터에 관하여 나온건 어디있나요?
    데이타 시트에서 못찾겠네요 ~

  3. 이것저것 테스트 해보니 IMR2레지스터에 0x02를 주고, PortC 13번 핀 인터럽트 설정해서
    Falling일때 인터럽트를 확인하니 잘되는데 이게 맞나요?

  4. 인터럽트에서 레지스터 클리어 해줬더니 중간에 가서 멈추는 증상이 생겨 메인루틴에서
    인터럽트 확인하고 클리어하고 그중에 RECV일때만 받는걸 처리하여 작성하였는데
    소스 를 첨부하였는데 확인가능하시면 부탁드립니다.

  5. UDP로 250Byte이상 받게되면 한번 받고 멈춰버립니다.
    제가 레지스터 들을 잘 설정 하였는지 확인 해 주실수 있으실까요 ?
    첨부소스는 IAR 6503으로 작성되어있습니다.
    제가 원하는건 20mS마다 UDP로 데이타 200Byte 날라오면 받아서 PWM으로 출력하는것을 원합니다.
    지금 소스에서는 200byte이상 전송받으면 멈추어 버립니다.
    어떠한 경우라도 시스템이 멈추면 안되는데 현재 계획은 200 byte 이지만 혹시 용도가 확장되어 바이트수가 늘어 날 수 도 있기에 확인 부탁드립니다.
    w7200의 퍼포먼스나 버퍼 여유는 충분한 것 같은데 이상하네요.

메인루프
if(udp_ok) {
udp_ok=0;
if(getSn_IR(socket) == Sn_IR_RECV) {
status_recv = UDPRecv(socket, (uint8_t*)recv_buf, 5000, Server_Ip, (uint16_t *)80);
printf(“UDP_OK, Size:%d,cnt:%d data123:%d %d %d \r\n”,status_recv, udp_cnt, recv_buf[0],recv_buf[1],recv_buf[2]);
IINCHIP_WRITE(Sn_IR(socket),0xff);
}
}

설정

uint8 IINCHIP_WRITE(uint16 addr,uint8 data);
void EXTI15_10_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line13) == SET)
{
uint8_t xxx=1;
EXTI_ClearITPendingBit(EXTI_Line13);
udp_ok=1;
udp_cnt = udp_cnt + 1;
GPIOB->ODR ^= GPIO_Pin_1;
}
}

void wiznet_interrupt(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
// WIZ Interrupt
GPIO_InitStructure.GPIO_Pin = WIZ_INT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;

GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource13);

EXTI_InitStructure.EXTI_Line = EXTI_Line13;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
EXTI_GenerateSWInterrupt(EXTI_Line13);
EXTI_IMR_EMR_enable();

setIMR2(0x02);
//setIMR(Sn_IR_RECV);

}

데이타시트가 보기가 힘든거 같은데 맨땅에 해딩하고 있네요
W7200 으로 인터럽트 수신 예제를 만들어 주실 계획은 없으신지요 ?
아니면 저의 소스를 수정하여 공개하셔도 상관 없을 듯 합니다.
Wiznet_w7200_UDP.zip (9.44 MB)

안녕하세요

문제점 증상

  1. Sn_IR (SOCKET n Interrupt Register) [R] [0x4002+0x0n00] [0x00]
    분명 R, READ라고 써있는데 인터럽트 마스킹 하려면 Sn_IR레지스터에 1Write하여 클리어 해야하는게
    맞나요? R/W라고 쓰여있어야 하는거 아닌가요?
    → R/W라 하면 유저가 임의의 값을 쓸 경우 값이 바뀌는 형식입니다. 하지만 Sn_IR은 단순히 클리어 하는 목적이므로
    R/W로 하면 오히려 혼동을 줄 수 있는 경우가 있기 때문에 R로만 적은 것입니다.

  2. IMR레지스터와 IMR2레지스터에서 5200데이타 시트 보면 IMR/IMR2에 대해 안나와있내요?
    7200에 맞는 데이타시트와 레지스터에 관하여 나온건 어디있나요?
    데이타 시트에서 못찾겠네요 ~
    → W5200의 데이터 시트를 참조하시면 됩니다. 1.3.0버전 IMR-19페이지, IMR2-23페이지에 상세히 나와있습니다.

  3. 이것저것 테스트 해보니 IMR2레지스터에 0x02를 주고, PortC 13번 핀 인터럽트 설정해서
    Falling일때 인터럽트를 확인하니 잘되는데 이게 맞나요?
    –>IMR2의 경우 IP conflict와 PPPoE 인터럽트 마스크 이며, IMR은 각 소켓별 인터럽트 마스크 입니다.
    약간의 혼동이 있지만, IR2의 마스크는 IMR이며 IR의 마스크는 IMR2 입니다.
    즉, IMR을 이용하여 원하는 소켓의 인터럽트를 활성화 시키시면 됩니다. 그 후 해당 소켓의 인터럽트가 발생하면 인터럽트 핀이 low로 떨어지게 됩니다.

안녕하세요.

4, 5 번 답변드릴게요.

4.번의 경우
void EXTI15_10_IRQHandler(void) 함수 안에서 TCP/IP core의 인터럽트도 clear시켜야 될 것 같네요

IINCHIP_WRITE(Sn_IR(socket),0xff);를 이용해서

core를 클리어 시키지 않는다면, core의 인터럽트 신호는 계속 low상태일 거고, 그러면 메인으로 다시 들어가도 또 다시 인터럽트 루틴을 콜 하게 될겁니다.

그래서 멈추는 현상이 발생하는 것 같습니다.

5번의 경우도 4번때문에 발생할 가능성이 있으므로 4번을 먼저 해결해 보시고 5번의 문제가 여전히 남아있다면 다시 질문 부탁드리겠습니다.

감사합니다.