[W5100S] ioLibrary 포팅시 레지스터 엑세스에 대하여

포팅중에 w5100s의 레지스터를 엑세스하는 코드에서 의문이 있어서 문의드립니다.
저는 indirect 모드를 사용하려는데,
코드를 보니 아래처럼 정의되어 있는데,
#if (WIZCHIP_IO_MODE & WIZCHIP_IO_MODE_SPI)
#define getMR() WIZCHIP_READ(MR)
#else
#define getMR() ((uint8_t)MR)
#endif

그렇다면 indirect 모드에서는
#define getMR() ((uint8_t)MR)
인데, 제가 보기에는 이코드는 direct모드의 코드로 보이는데 ??
주소에서 바로 값을 읽어오는 위의 코드는 direct모드가 아닌가요?
indirect 모드에서는 주소를 보내고 MR값을 읽어와야 하는게 아닌가요?

안녕하세요.

말씀하신대로 Indirect mode를 사용할 경우,

     ADDR  :   01       10        11
     DATA  : ADDR_H    ADDR_L    DATA

와 같이 동작을 합니다.

단, MR의 경우는 조금 다르다고 볼수 있습니다.
MR의 경우 ADDR의 00이 MR의 주소를 나타냅니다.
→ 이는 W5100를 사용하고 있는 사용자들이 W5100S로 변경하기 원할때, 별도의 firmware작업없이 사용할수 있게 만들어졌기때문입니다.

아래의 그림은 W5100의 DataSheet에서 발췌한것입니다.
image

해당하는 부분은 Datasheet에 추가 설명해 놓겠습니다.

감사합니다.
irina

신속한 답변에 감사합니다.
그런데, 제 질문의 의도가 제대로 전달되지 않은것 같습니다.

#define setMR(mr) (((uint8_t)MR) = mr) 이므로,

setMR(0x80) 은 아래처럼 해석됩니다.

(((uint8_t)(0x60000000 + (0x0000))) = 0x80)

즉, 0x60000000 번지에 0x80을 쓰게 됩니다.

결국, 이 번지는 대부분의 마이컴에서는 기술되지 않은 부분이어서 익셉션이 발생하게 될꺼라는 질문이었습니다.

제가 무슨 착각을 하고있는건가요?? ^^;;

결론적으로, 아래 코드가 indir 모드에서는 제대로 동작하지 않는게 아닌가 하는 질문입니다.

/**

  • @ingroup Common_register_access_function_W5100S
  • @brief Set Mode Register
  • @param (uint8_t)mr The value to be set.
  • @sa getMR()
    /
    #if (WIZCHIP_IO_MODE & WIZCHIP_IO_MODE_SPI)
    #define setMR(mr) WIZCHIP_WRITE(MR,mr)
    #else
    #define setMR(mr) (
    ((uint8_t*)MR) = mr)
    #endif

/**

  • @ingroup Common_register_access_function_W5100S
  • @brief Get @ref MR.
  • @return uint8_t. The value of Mode register.
  • @sa setMR()
    /
    #if (WIZCHIP_IO_MODE & WIZCHIP_IO_MODE_SPI)
    #define getMR() WIZCHIP_READ(MR)
    #else
    #define getMR() (
    (uint8_t*)MR)
    #endif

안녕하세요.

말씀해 주시는 부분이 맞습니다.

Indirect mode를 사용할 경우, 아래의 주소를 사용하기 때문에, 말씀하신대로 0x6000_0000이 맞습니다

#define _WIZCHIP_IO_BASE_	0x60000000	// for 5100S IND
#define IDM_OR             ((_WIZCHIP_IO_BASE  + 0x0000))
#define IDM_AR0            ((_WIZCHIP_IO_BASE_ + 0x0001))
#define IDM_AR1            ((_WIZCHIP_IO_BASE_ + 0x0002))
#define IDM_DR             ((_WIZCHIP_IO_BASE_ + 0x0003))

여기에서 아셔야 할점은, W5100와 W5100S에서의 IDM_OR은 실제 MR 을 나타내는 주소입니다.
이전에도 말씀드렸듯이 W5100에서 W5100S을 변경하고자하는 고객을 위해 설계된부분이고,
W5100에서는 Direct mode에서 indirect mode로 변경시 IDM_OR의 한 bit를 세팅해주면 변경이 되었습니다.
이 부분에 관해서는 W5100S에서 해당 비트는 사용하지 않지만, W5100사용자들을 위해 0x6000_0000에 값을 쓰거나 읽게 되면, MR register에 접근을 하게 됩니다.

이부분은 테스트 완료 된 부분이기때문에, 익센셥이 발생하지 않습니다.

기술되지 않은 부분이란 어떤걸 얘기하시는건지…
Indirect mode 일때,WIZCHIP_IO_BASE 의 값은 MCU 마다 다른 부분입니다.
Wiznet에서 제공하는 예제의 MCU에서 는 해당 address를 사용하기 때문에, 0x6000_0000에 Base address로 세팅되어있는 것입니다.

다른 MCU를 사용하신다면, MCU에 맞는 주소를 설정하셔서 사용하셔야합니다.

감사합니다.
irina

아… 이제 말씀하시는 의미를 알겠습니다.

즉, W5100s에서 AD0,1은 (외부메모리 인터페이스에 사용되는) 어드레스 버스신호선(보통 AD[31:0])의 최하위 2비트를 W5100s에 연결하는 경우를 말씀하시는 거군요.

예, 맞습니다.
이 경우에는 정성동작하겠네요.
(그런데, 이렇게 사용하는 유저는 별로 없을 듯…)

저도 CORTEX-M0의 GPIO를 AD0,1에 연결해서 사용합니다.
이경우에는 0x6000_0000은 사용되지 않는 영역이므로 메모리 익셉션이 발생하게 됩니다.(확인했습니다)
저와 같은 경우에는 ioLibrary의 함수를 그대로 사용하면 않되겠네요.
수정이 필요하겠네요.

혹시 수정할 점에 대하여 도움될 코드가 있으면 좋겠는데…
하여튼 감사합니다.

이제야 왜 아래처럼 선언했는지 이해가 됩니다.

#define WIZCHIP_IO_BASE 0x60000000 // for 5100S IND
#define IDM_OR ((_WIZCHIP_IO_BASE + 0x0000))
#define IDM_AR0 ((WIZCHIP_IO_BASE + 0x0001))
#define IDM_AR1 ((WIZCHIP_IO_BASE + 0x0002))
#define IDM_DR ((WIZCHIP_IO_BASE + 0x0003))

ioLibrary 를 사용하여 쓰실경우
WIZCHIP_IO_BASE의 값을 사용가능한 memory 주소로 매핑하신다면 어렵지 않게 사용하실수 있을것 같습니다.

감사합니다.
irina

예 감사합니다.

wizchip_setnetinfo(&info);
wizchip_settimeout(&nettime);
wizchip_init(txsize, rxsize);

위 코드를 실행한 후
다시 netinfo를 읽어보니 정상적으로 읽어지는 것을 확인했습니다.

그런데, 또 문제가 발생했습니다.ㅠㅠ

int8_t close(uint8_t sn) 에서

setSn_CR(sn,Sn_CR_CLOSE);
/* wait to process the command… */
while( getSn_CR(sn) );

이부분에서 Sn_CR 값이 0으로 되질 않습니다.

참고로,
ADDR0,ADDR1 은 GPIO를 사용하고 있습니다.

혹시나 해서 PCB도 다시 조립해 봤지만 마찬가지 였습니다.
어느 부분을 검토해 봐야 할까요?
조언을 부탁드립니다.

안녕하세요 .
Sn_CR의 경우 로직상
자동으로 Clear되도록 설계되어있습니다.

어떤 동작을 한후 Sn_CR의 값이 0이 되지 않는건가요?
예를 들어 connect 함수에서 동작하지 않는다…
사용하는 SOCKET의 Sn_CR이 맞는지 확인해야할것 같습니다.

감사합니다.
irina 드림.

실행한 프로그램을 순서대로 코드를 나열하면 아래와 같습니다.

pin_low(RST);
// 여기 약간의 다른 코드가 있고,
pin_high(RST);

Wait_10us(200 * 100);

위처럼 리셋 작업을 한 후

uint8_t txsize[4] = {2, 2, 2, 2};
uint8_t rxsize[4] = {2, 2, 2, 2};

reg_wizchip_cris_cbfunc(enable_irq, disable_irq);
reg_wizchip_cs_cbfunc(cs_low, cs_high);
reg_wizchip_bus_cbfunc(bus_readdata, bus_writedata);

wiz_NetInfo info = {
.dhcp=NETINFO_STATIC
};

// MAC ADDRESS
for (i = 0 ; i < 6; i++) {
info.mac[5-i] = (param.mac >> (i * 8)) & 0xFF;
}
// Local IP ADDRESS
for (i = 0 ; i < 4; i++) {
info.ip[3-i] = (param.ip >> (i * 8)) & 0xFF;
}
// Subnet Mask ADDRESS
for (i = 0 ; i < 4; i++) {
info.sn[3-i] = (param.subnet >> (i * 8)) & 0xFF;
}
// GateWay ADDRESS
for (i = 0 ; i < 4; i++) {
info.gw[3-i] = (param.gateway >> (i * 8)) & 0xFF;
}

wiz_NetTimeout nettime = {
.retry_cnt = param.retryCount,
.time_100us = param.retryTime
};

wizchip_setnetinfo(&info);
wizchip_settimeout(&nettime);
wizchip_init(txsize, rxsize);

위에서 처럼 초기화 했습니다.
ip, subnet,gw는 정상적으로 써졌다는것을 확인했습니다.

TcpServer(0, 8698);

마지막으로 위처럼 TcpServer를 실행했는데,
여기서부터는 ioLibrary내의 코드이므로 잘 알고 계실것으로 생각되는데,

socket(s,Sn_MR_TCP,port,0x00);

을 호출하고,
또 socket()에서는

close(sn);
을 호출 하지요.

또, close() 에서는

setSn_CR(sn,Sn_CR_CLOSE);
/* wait to process the command… */
while( getSn_CR(sn) );

위의 코드가 있습니다.
여기서 while 문에서 무한루프를 돕니다.
값을 확인해보면 0으로 리셋되지 않고 Sn_CR_CLOSE가 그대로 있 습니다.