Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32F107 + RTL8201 + lwip-1.4.0
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Страницы: 1, 2, 3, 4
сарматъ
хм... возможно я чего то не нашел, но то что мне нужно я не видел, к примеру, как обрабатывается ситуация пропадания появления линка? зависания phy? зависания мак контроллера? так же не увидел как вообще происходит инициализация езернета - есть только функции в драйверах но вот откуда они вызываюстя? откуда то из закрытых недр ос? то что переинициализация в кейле не требуется и она осуществляется на лету это здорово, но я делаю в жсс и на сам кейл перепозлать не собираюсь теперь уже точно ибо это кот в мешке по большому счету, что и как там происходит тайна за семью печатями

разные стеки мне не нужны, обработку пакетов делаю сам, интересует именно инициализация и поддержка в работоспособном состоянии именно это я назвал "примером хорошей работы"
smk
Прошу подсказать как мне настроить вторую сетевую карту, которая будет использоваться для работы с девайсом? При этом первая (на борту) уже используется под интернет. В частности что писать в строчку "шлюз"? Хотелось бы чтоб компьютер имел адрес 192.168.0.1, а девайс пусть будет 192.168.0.2 . Спасибо.

Поторопился с вопросом. Нашел тут для чайников: http://2bubna.com.ua/index.php/nastroyka-s...-kompyuter.html
smk
Железо проверил, все работает. Наконец-то можно приступить к вопросам непосредственно касающимся названия темы. У меня заведен проект в кейле, состоящий из драйвера от СТ, инициализации пинов и тактирования. Прикрепляю его к посту (может кто найдет время глянуть на что оно похоже). Собственно вопрос в том, можно ли как-то убедится в работоспособности уже имющейся программной части? Как мне теперь добавить LwIP чтоб пинговаться начало? Спасибо. Буду рад любой помощи и подсказкам.

Нажмите для просмотра прикрепленного файла
Golikov A.
самый первый тест это попихать данные в МАК контроллер, и поглядеть wireSharkom лезут ли они в сеть. Я не умничая фигачил Hello world, и видел шарком плохой ошибочный пакет с моими данными.

в обратную сторону я что-то в свое время быстрого и простого теста не придумал, надо на уровень драйвера винды спускаться... Но я подумал в одну сторону работает и в другую будет.

LwIP - хорошо бы примеры поглядеть. Стэк от кейла как то легче прикручивается.
smk
Пытался скачать стек от кейла но так и не увидел где ссылка. А что надежней, от кейла или lwip? А попытаться передавать это значит писать в буфер и как-то командовать отправку? С буфером понятно, но как пнуть на отправку? Я так понял, что буфер имеет несколько страниц, в частности 8 на прием, а 2 на передачу? В смысле в реализации от терры.
сарматъ
готовые стеки не использовал, начинал с приема арп пакета потом училс его отправлять, делал на основе примера от терры.. или пром? короче там где кусок от обработки камеры

однако если делаете в кейле то там как то все очень по своему
Golikov A.
Цитата(smk @ Nov 11 2013, 11:28) *
Пытался скачать стек от кейла но так и не увидел где ссылка. А что надежней, от кейла или lwip? А попытаться передавать это значит писать в буфер и как-то командовать отправку? С буфером понятно, но как пнуть на отправку? Я так понял, что буфер имеет несколько страниц, в частности 8 на прием, а 2 на передачу? В смысле в реализации от терры.


Да фиг его знает что надежнее
В LwIP есть исходники, если что можно переписать
Стэк от кейла - закрытый, библиотека и досвидос, если что не так, только им писать

С другой стороны кеил уважаемая фирма, и как в их среде можно выбрать из списка процессор и сразу его характеристики ставятся, так и стэк как то очень легко сам цепляется.


как пнуть начало передачи в СТМ что-то не знаю...
smk
А стек кейловский где скачать и где пишут про "прикрутить" библиотеку? Очень уж интригует что легко сам цепляется. Я думаю попробовать и то и то. Жизнь покажет. Только благоразумней начинать с того, что попроще дабы снизить вероятность ошибок.
vlad_new
Не надо ничего качать. Библиотека уже у вас лежит вот где то там ..\ARM\RV31\LIB\TCP_CM3.lib
В визарте Net_Config.c ставите галочки какие надо. К пректу надо подключить драйвер ETH соответствующий вашему модему.
В мэйне запускаете инициализацию портов. Затем запускается init_TcpNet(); далее в цыкле мэин вызавается timer_poll(); и main_TcpNet(); и все.
Все остальное делается при помощи callback функций, которые запускаются из библиотеки кейла. Все нужные callback функции сначала должны быть объявлены и проинициализированы. К примеру callback для приема и передачи пакетов по UDP выглядит так:
Код
    udp_soc=udp_get_socket(0,UDP_OPT_SEND_CS|UDP_OPT_CHK_CS,udp_callback);  // UDP socket
    if(udp_soc!= 0) udp_open(udp_soc, 1000);                                                             // Open UDP port 1000 for communication

Вот так ( к примеру ) выглядит прием команды по UDP и отправка разных параметров в ответ:
Код
u16 udp_callback1 (u8 socket, u8 *remip, u16 remport, u8 *buf, u16 len)
{
u8 *send;
char tbf[4];
u32 dp;

    if((!memcmp(buf,"GET",3))||(!memcmp(buf,"Get",3))||(!memcmp(buf,"get",3)))
      {
      if(DHCP_off) strcpy(tbf,"OFF"); else strcpy(tbf,"ON");
      dp=*(u32*)&localm[0];
      send = udp_get_buf(256);                                 // Len 256 !!!
      len=sprintf((char*)send,
      "\nMAC[%02X:%02X:%02X:%02X:%02X:%02X]"
      "\nIP[%d.%d.%d.%d]"
      "\nMASK[%d.%d.%d.%d]"
      "\nGW[%d.%d.%d.%d]"
      "\nDNS[%d.%d.%d.%d]"
      "\nDHCP_%s"
      "\nIP_DHCP[%d.%d.%d.%d]"
      "\nNAME[%s]\n",
      own_hw_adr[0], own_hw_adr[1], own_hw_adr[2], own_hw_adr[3], own_hw_adr[4], own_hw_adr[5],
      nlocalm[0].IpAdr[0],   nlocalm[0].IpAdr[1],   nlocalm[0].IpAdr[2],   nlocalm[0].IpAdr[3],
      nlocalm[0].NetMask[0], nlocalm[0].NetMask[1], nlocalm[0].NetMask[2], nlocalm[0].NetMask[3],
      nlocalm[0].DefGW[0],   nlocalm[0].DefGW[1],   nlocalm[0].DefGW[2],   nlocalm[0].DefGW[3],
      nlocalm[0].PriDNS[0],  nlocalm[0].PriDNS[1],  nlocalm[0].PriDNS[2],  nlocalm[0].PriDNS[3],
      tbf, dp&0xFF, (dp>>8)&0xFF, (dp>>16)&0xFF, (dp>>24)&0xFF, (char*)lhost_name);
      udp_send (udp_soc1, remip, 1000, send, len);
      }
  return (0);
}


В lwip точно так же все делается через callback функции.
smk
Добавил библиотеку и файл Net_Config.c; подключил Net_Config.h
Пишет вот такую ошибку: F:\PROGRAM\Keil454\ARM\RL\TCPnet\Config\Net_Config.c(859): error: #20: identifier "ERR_MEM_LOCK" is undefined

Что можно сделать? Спасибо.

С этим разобрался. Добавил в:
Код
typedef enum {                    /* << Fatal System Error Codes >>          */
  ERR_MEM_ALLOC,
  ERR_MEM_FREE,
  ERR_MEM_CORRUPT,
  ERR_MEM_LOCK,           //вот сюда
  ERR_UDP_ALLOC,
  ERR_TCP_ALLOC,
  ERR_TCP_STATE
} ERROR_CODE;


Теперь другие ошибки:

eth107.axf: Error: L6218E: Undefined symbol init_ethernet (referred from at_ethernet.o).
eth107.axf: Error: L6218E: Undefined symbol send_frame (referred from at_ethernet.o).

С этим сложнее. Может кто подскажет как поступить?

Net_lib.c нужно включать в проект?
Golikov A.
для кеил стэка еще системный таймер надо запустить на 1 мСек, чтобы
timer_poll(); правильно работал.

init_ethernet - это внутренняя функция библиотеки, к LPC есть файл со всеми патрахами мак контроллера
в нем написан такой коммент
/*----------------------------------------------------------------------------
* EMAC Ethernet Driver Functions
*----------------------------------------------------------------------------
* Required functions for Ethernet driver module:
* a. Polling mode: - void init_ethernet ()
* - void send_frame (OS_FRAME *frame)
* - void poll_ethernet (void)
* b. Interrupt mode: - void init_ethernet ()
* - void send_frame (OS_FRAME *frame)
* - void int_enable_eth ()
* - void int_disable_eth ()
* - interrupt function
*---------------------------------------------------------------------------*/

в Net_Config.h есть такое объявление
extern void init_ethernet (void);
extern void send_frame (OS_FRAME *frame);

smk
Цитата(Golikov A. @ Nov 11 2013, 21:41) *
в Net_Config.h есть такое объявление
extern void init_ethernet (void);
extern void send_frame (OS_FRAME *frame);


Это я видел. Самих функций не видел. Как поступить нужно в этой ситуации?
Golikov A.
ну вы их не увидите они в библиотеке кейла вызываются.
у меня тел этих функций тоже нет...

http://www.keil.com/support/man/docs/rlarm...it_ethernet.htm

The init_ethernet function is part of RL-TCPnet. The prototype is defined in net_config.h.
smk
Цитата(Golikov A. @ Nov 12 2013, 12:59) *
ну вы их не увидите они в библиотеке кейла вызываются.
у меня тел этих функций тоже нет...

http://www.keil.com/support/man/docs/rlarm...it_ethernet.htm

The init_ethernet function is part of RL-TCPnet. The prototype is defined in net_config.h.


Тогда почему кейл их не видит? Как я понимаю, если в net_config.h они упомянуты, то в net_config.с длжны быть описаны?


Убедительная просьба - ткните носом в пример от кейла, где все это работает. Попроще пример.
Golikov A.
нет конечно...
то что в хедере есть прототипы функций, совсем не означает что в модуле должно быть их описание. Они в библиотеке, и скрыты от вас как от пользователя.

Судя по всем у вас библиотека не подключена, поэтому линкер и не может найти эти функции...
smk
Цитата(Golikov A. @ Nov 12 2013, 20:53) *
нет конечно...
то что в хедере есть прототипы функций, совсем не означает что в модуле должно быть их описание. Они в библиотеке, и скрыты от вас как от пользователя.

Судя по всем у вас библиотека не подключена, поэтому линкер и не может найти эти функции...

Да подключил, как я понимаю. Или еще как-то нужно?
Нажмите для просмотра прикрепленного файла
Golikov A.
БЛИН!
прошу прощения, я вас полностью обманул...

вызова этих функций найти нельзя он внутри библиотеки, а сами эти функции должны быть созданы....


у меня к LPC есть еще файлик EMAC_LPC17xx.c - там описаны все патроха управления емаком, инициализируются прерывания и мак контроллер

в нем есть эта функция

CODE

void init_ethernet (void)
{
/* Initialize the EMAC ethernet controller. */
uint32_t regv,tout,id1,id2;
DBG_PHY("");
DBG_PHY("\r\nDBG_PHY: Starting Init Physic");
/* Power Up the EMAC controller. */
LPC_SC->PCONP |= 0x40000000;

/* Configure PHY */
LPC_GPIO4 -> FIOSET |= 1<<29;
LPC_GPIO4 -> FIODIR |= 1<<29;
LPC_GPIO1 -> FIOCLR |= 1<<14;
LPC_GPIO1 -> FIODIR |= 1<<14;
LPC_GPIO1 -> FIOCLR |= 1<<8;
LPC_GPIO1 -> FIODIR |= 1<<8;

/* Power doun/up Reset PHY for strapping */
LPC_GPIO4 -> FIOCLR |= 1<<29;
for(tout=0;tout<1000000;tout++);
LPC_GPIO4 -> FIOSET |= 1<<29;
for(tout=0;tout<1000000;tout++);

/* Enable P1 Ethernet Pins. */
LPC_PINCON->PINSEL2 = 0x50150105;
/* LPC176x devices, no MDIO, MDC remap. */
LPC_PINCON->PINSEL3 = (LPC_PINCON->PINSEL3 & ~0x0000000F) | 0x00000005;

/* Reset all EMAC internal modules. */
LPC_EMAC->MAC1 = MAC1_RES_TX | MAC1_RES_MCS_TX | MAC1_RES_RX |
MAC1_RES_MCS_RX | MAC1_SIM_RES | MAC1_SOFT_RES;
LPC_EMAC->Command = CR_REG_RES | CR_TX_RES | CR_RX_RES | CR_PASS_RUNT_FRM;

/* A short delay after reset. */
for (tout = 100; tout; tout--);

/* Initialize MAC control registers. */
LPC_EMAC->MAC1 = MAC1_PASS_ALL;
LPC_EMAC->MAC2 = MAC2_CRC_EN | MAC2_PAD_EN;
LPC_EMAC->MAXF = ETH_MAX_FLEN;
LPC_EMAC->CLRT = CLRT_DEF;
LPC_EMAC->IPGR = IPGR_DEF;

/*PCLK=18MHz, clock select=6, MDC=18/6=3MHz */
LPC_EMAC->MCFG = MCFG_CLK_DIV28 | MCFG_RES_MII;
for (tout = 100000; tout; tout--);
LPC_EMAC->MCFG = MCFG_CLK_DIV28;
for (tout = 100000; tout; tout--);

/* Enable Reduced MII interface. */
LPC_EMAC->Command = CR_RMII | CR_PASS_RUNT_FRM;
//LPC_EMAC->Command = CR_RMII | CR_PASS_RUNT_FRM | CR_PASS_RX_FILT;

/* Reset Reduced MII Logic. */
LPC_EMAC->SUPP = SUPP_RES_RMII;
for (tout = 100; tout; tout--);
LPC_EMAC->SUPP = 0;

//PHY_ADDR = 0;
DBG_PHY("\r\nDBG_PHY: Starting Scan PHY address:\r\n");
//while(1)
for(PHY_ADDR = 0; PHY_ADDR<32;PHY_ADDR++)
{
DBG_PHY(".");
/* Put the PHY in reset mode */
write_PHY (PHY_REG_BMCR, 0x8000);
for (tout = 10000; tout; tout--);

/* Wait for hardware reset to end. */
for (tout = 0; tout < 0x100; tout++)
{
regv = read_PHY (PHY_REG_BMCR);
if (!(regv & 0x8000))
{
/* Reset complete */
break;
}
}
if (tout < 0x100) break;
else ;
//PHY_ADDR++;
//PHY_ADDR&=0x1f;
}
if(PHY_ADDR<31)
{
DBG_PHY("\r\nDBG_PHY: Found at PHY_ADDR = %d",PHY_ADDR);
}
else
{
DBG_PHY_ERR("\r\nDBG_PHY_ERR: PHY_ADDR Error");
return;
}

/* Check if this is a kz8721 PHY. */
id1 = read_PHY (PHY_REG_IDR1);
id2 = read_PHY (PHY_REG_IDR2);
DBG_PHY("\r\nDBG_PHY: ID1-0x%04X, ID2-0x%04X",id1, id2);


if (((id1 << 16) | (id2 & 0xFFF0)) != 0x221610)
{
DBG_PHY_ERR("\r\nDDBG_PHY_ERR: Not a KS8721 PHY - ID1-0x%04X, ID2-0x%04X",id1, id2);
return;
}
else
{
DBG_PHY("\r\nDBG_PHY: KS8721 PHY - Sucñess");
}

/* Configure the PHY device */
#if defined (_10MBIT_)
/* Connect at 10MBit */
write_PHY (PHY_REG_BMCR, PHY_FULLD_10M);
#elif defined (_100MBIT_)
/* Connect at 100MBit */
write_PHY (PHY_REG_BMCR, PHY_FULLD_100M);
#else
DBG_PHY("\r\nDBG_PHY: Starting AutoNegotiation Process\r\n");
/* Use autonegotiation about the link speed. */
write_PHY (PHY_REG_BMCR, PHY_AUTO_NEG);
/* Wait to complete Auto_Negotiation. */
for (tout = 0; tout < 0x30000; tout++)
{
regv = read_PHY (PHY_REG_BMSR);
if( !(tout%3000) ) DBG_PHY(".");
if (regv & 0x0020)
{
DBG_PHY("\r\nDBG_PHY: AutoNegotiation Sucñess tout = %d Counts",tout);
/* Autonegotiation Complete. */
break;
}
}
#endif
if (tout >= 0x30000)
{
DBG_PHY_ERR("\r\nDBG_PHY_ERR: AutoNegotiation failed.");
DBG_PHY_ERR("\r\nDBG_PHY:Possibly Cable Unplugget");
DBG_PHY_ERR("\r\nDBG_PHY:Manual Assign: Full duplex - 100 Mbit Mode");
write_PHY (PHY_REG_BMCR, PHY_FULLD_100M);
//return; // auto_neg failed
}

/* Check the link status. */
for (tout = 0; tout < 0x10000; tout++)
{
regv = read_PHY (PHY_REG_BMSR);
if (regv & 0x0004)
{
/* Link is on. */
DBG_PHY("\r\nDBG_PHY: Link is ON");
break;
}
}

if (tout >= 0x10000)
{
DBG_PHY("\r\nDBG_PHY: Link is OFF");
}

regv = ((read_PHY (0x1f))>>2)&0x7;

/* Configure Full/Half Duplex mode. */

if ((regv==0x0005)||(regv==0x0006))
{
/* Full duplex is enabled. */
LPC_EMAC->MAC2 |= MAC2_FULL_DUP;
LPC_EMAC->Command |= CR_FULL_DUP;
LPC_EMAC->IPGT = IPGT_FULL_DUP;
DBG_PHY("\r\nDBG_PHY: Full duplex is enabled.");
}

if ((regv==0x0001)||(regv==0x0002))
{
/* Half duplex mode. */
LPC_EMAC->IPGT = IPGT_HALF_DUP;
DBG_PHY("\r\nDBG_PHY: Half duplex is enabled.");
}

if ((regv==0x0005)||(regv==0x0001))
{
/* 10MBit mode. */
LPC_EMAC->SUPP = 0;
DBG_PHY("\r\nDBG_PHY: 10MBit mode.");
}
if ((regv==0x0006)||(regv==0x0002))
{
/* 100MBit mode. */
LPC_EMAC->SUPP = SUPP_SPEED;
DBG_PHY("\r\nDBG_PHY: 100MBit mode.");
}

#ifdef DEBUG
regv = read_PHY (PHY_REG_BMCR);
DBG_PHY("\r\nDBG_PHY: Register 0h - Basic Control = 0x%X",regv);
regv = read_PHY (PHY_REG_BMSR);
DBG_PHY("\r\nDBG_PHY: Register 1h - Basic Status = 0x%X",regv);

regv = read_PHY (PHY_REG_ANAR);
DBG_PHY("\r\nDBG_PHY: Register 4h - Auto-Negotiation Advertisement = 0x%X",regv);
regv = read_PHY (PHY_REG_ANLPAR);
DBG_PHY("\r\nDBG_PHY: Register 5h - Auto-Negotiation Link Partner Ability = 0x%X",regv);
regv = read_PHY (PHY_REG_ANER);
DBG_PHY("\r\nDBG_PHY: Register 6h - Auto-Negotiation Expansion = 0x%X",regv);
regv = read_PHY (PHY_REG_ANNPTR);
DBG_PHY("\r\nDBG_PHY: Register 7h - Auto-Negotiation Next Page = 0x%X",regv);
regv = read_PHY (PHY_REG_LPNPA);
DBG_PHY("\r\nDBG_PHY: Register 8h - Link Partner Next Page Ability = 0x%X",regv);
#endif

{ /* Using Device Serial Number For Define Last 3 MAC Address */
uint32_t p0,p1,p2,p3,s;
DBG_PHY("\r\nDBG_PHY: Reading Device Serial Number:");
u32IAP_ReadSerialNumber(&p0, &p1, &p2, &p3);
//óïàêóåì ñåðèéíûé íîìåð â 32 áèòà
s = p0 + p1 + p2 + p3;
//32 áèòà óïàêóåì â 24, ÷òîáû èñïîëüçîâàòü äëÿ ìàê àäðåñà
s = s&0xFF + s>>8;
DBG_PHY("\r\nDBG_PHY: Chip Serial Number = 0x%08X 0x%08X 0x%08X 0x%08X",p0,p1,p2,p3);
DBG_PHY("\r\nDBG_PHY: Chip Summ Serial = 0x%08X ",s);
DBG_PHY("\r\nDBG_PHY: Device Hardware Address:" );
own_hw_adr[3] = ( (s>>16) & 0xFF);
own_hw_adr[4] = ( (s>>8 ) & 0xFF);
own_hw_adr[5] = ( (s ) & 0xFF);
DBG_PHY("\r\nDBG_PHY: %02X %02X %02X %02X %02X %02X", own_hw_adr[0], own_hw_adr[1], own_hw_adr[2],
own_hw_adr[3], own_hw_adr[4], own_hw_adr[5] );
}
/* Set the Ethernet MAC Address registers */
LPC_EMAC->SA0 = ((uint32_t)own_hw_adr[5] << 8) | (uint32_t)own_hw_adr[4];
LPC_EMAC->SA1 = ((uint32_t)own_hw_adr[3] << 8) | (uint32_t)own_hw_adr[2];
LPC_EMAC->SA2 = ((uint32_t)own_hw_adr[1] << 8) | (uint32_t)own_hw_adr[0];

/* Initialize Tx and Rx DMA Descriptors */
rx_descr_init ();
tx_descr_init ();

/* Receive Broadcast, Multicast and Perfect Match Packets */
LPC_EMAC->RxFilterCtrl = RFC_MCAST_EN | RFC_BCAST_EN | RFC_PERFECT_EN;
/* Receive Broadcast and Perfect Match Packets */
//LPC_EMAC->RxFilterCtrl = RFC_BCAST_EN | RFC_PERFECT_EN;

/* Enable EMAC interrupts. */
LPC_EMAC->IntEnable = INT_RX_DONE | INT_TX_DONE ;

/* Reset all interrupts */
LPC_EMAC->IntClear = 0xFFFF;

/* Enable receive and transmit mode of MAC Ethernet core */
LPC_EMAC->Command |= (CR_RX_EN | CR_TX_EN);
LPC_EMAC->MAC1 |= MAC1_REC_EN;

DBG_PHY("\r\nDBG_PHY: PHY Config Done\r\n" );
return;
}


посылка фрейма там же

CODE
void send_frame (OS_FRAME *frame)
{
/* Send frame to EMAC ethernet controller */
uint32_t idx,len;
uint32_t *sp,*dp;

idx = LPC_EMAC->TxProduceIndex;
sp = (uint32_t *)&frame->data[0];
dp = (uint32_t *)Tx_Desc[idx].Packet;

/* Copy frame data to EMAC packet buffers. */
for (len = (frame->length + 3) >> 2; len; len--) {
*dp++ = *sp++;
}
Tx_Desc[idx].Ctrl = (frame->length-1) | (TCTRL_INT | TCTRL_LAST);

/* Start frame transmission. */
if (++idx == NUM_TX_FRAG) idx = 0;
LPC_EMAC->TxProduceIndex = idx;
}


это я чего то реально затупил. Это же привязанные к конкретному железу функции, они не могли быть в библиотеке....

у вас должен быть библиотека - драйвер от вашего мак контролера, найдите в ней подходящие функции и организуйте вызов!
ksv198
Цитата(smk @ Nov 12 2013, 23:03) *
Да подключил, как я понимаю. Или еще как-то нужно?


Попробуйте начать с простого.
1. Создайте пустой проект в Кейле, где есть только начальная инициализация STM32F107 и убедитесь, что контроллер нормально запускается (например мигает светодиодом). Хорошо бы проконтролировать частоту ядра выводом на выход PA8.
2. Далее подключите в проект файлы ETH_STM32X.c и ETH_STM32X.h (лежат в c:\Keil\ARM\RL\TCPnet\Drivers\). Это драйвер Кейла для Ethernet MAC и инициализация PHY. Он очень простой по сравнению с STM-овским, в нём легче разобраться для начала. По умолчанию там всё для физики DP83848C.
3. Вам нужно поправить в ETH_STM32X.h всё, что ниже строки комментария /* DP83848C PHY Registers */. Для простоты я бы оставил сначала только первые 8 регистров, для проверки работоспособности хватит (если у Вас RTL8201 то первые 6 регистров). Исправьте #define DP83848C_ID 0x20005C90 на свой (из даташита на Вашу микросхему физики). Исправьте #define DP83848C_DEF_ADR 0x01 на адрес Вашей микросхемы физики (обратите внимание, что он может изменяться от схемы включения - всё описано в даташите).
4. Далее в файле ETH_STM32X.c идём в функцию void init_ethernet (void). Там два варианта подключения физики - по MII или по RMII. Оставьте только свой вариант, чтобы не путаться. Затем необходимо обратить внимание на строку /* MDC Clock range 60-72MHz. */ ETH->MACMIIAR = 0x00000000; Если у Вас частота ядра менее 60 МГц, то надо из референс мануал подставить другое значение (см. RM0008 раздел SMI clock selection). Уберите временно проверку по условию if (((id1 << 16) | (id2 & 0xFFF0)) == DP83848C_ID) - это проверка идентификатора физики. Уберите блок от /* Check the link status. */ - в Вашей микросхеме физики может не быть этого регистра. Обратите внимание на массив extern U8 own_hw_adr[];. Это массив МАС адреса, на данном этапе, чтобы не подключать Net_Config.c определите его локально (не забудьте младший байт поставить в 0х00 для начала, чтобы случайно не сделать броадкаст).
5. Начинаем отладку. В main() вызываем init_ethernet () и Вашим любимым методом (дебагом или принтом через последовательный порт, или выводом на экранчик, если есть) смотрим возвращаемые функцией read_PHY() значения. Сравнивайте с тем, что видите в описании битов регистра в даташите на Ваш PHY. Здесь пригодятся регистры 0х02 и 0х03 - в них идентификатор. Если все время читается 0xff или 0х00 то попробуйте менять адрес (в строке #define DP83848C_DEF_ADR) от 0 до 32. Если все равно ничего не получается возвращайтесь к анализу схемы (желательно с осциллографом).
6. Когда начнут нормально читаться регистры, пройдитесь по всем доступным в даташите и посмотрите, что с физикой становится после инициализации. Возможно будут проблемы с autonegotiation - PHY может не определить скорость сам. Пните его принудительно: write_PHY (PHY_REG_BMCR, PHY_FULLD_10M); или write_PHY (PHY_REG_BMCR, PHY_FULLD_100M);.
7. Когда увидите по состоянию регистров физики, что линк поднят - только тогда можно переходить к попыткам поднять стек. Это отдельно уже.
Удачи!
smk
ksv198, благодарю! как глоток воздуха! Сделаю - отпишусь.
DmitryM
Цитата(ksv198 @ Nov 13 2013, 13:59) *
менять адрес (в строке #define DP83848C_DEF_ADR) от 0 до 32.

от 0 до 31 biggrin.gif
ksv198
Цитата(DmitryM @ Nov 13 2013, 18:42) *
от 0 до 31 biggrin.gif


Вы правы biggrin.gif
smk
Что удалось сделать. П.1-4 сделал полностью. Инициализацию пинов сделал без ремапа так, как собрано на плате. Добавил #include "type.h" чтоб вручную все не доводить. Но дальше не пошло т.к. остались сообщения об ошибке:
Код
ETH_keil.axf: Error: L6218E: Undefined symbol alloc_mem (referred from eth_stm32x.o).
ETH_keil.axf: Error: L6218E: Undefined symbol put_in_queue (referred from eth_stm32x.o).


Что можно предпринять? Спасибо.

Вот там похоже упомянуты:
Код
/*--------------------------- interrupt_ethernet ----------------------------*/

void ETH_IRQHandler (void) {
  /* Ethernet Controller Interrupt function. */
  OS_FRAME *frame;
  U32 i,RxLen,int_stat;
  U32 *sp,*dp;

  while (((int_stat = ETH->DMASR) & INT_NISE) != 0) {
    ETH->DMASR = int_stat;
    if (int_stat & INT_RIE) {
      /* Valid frame has been received. */
      i = RxBufIndex;
      if (Rx_Desc[i].Stat & DMA_RX_ERROR_MASK) {
        goto rel;
      }
      if ((Rx_Desc[i].Stat & DMA_RX_SEG_MASK) != DMA_RX_SEG_MASK) {
        goto rel;
      }
      RxLen = ((Rx_Desc[i].Stat >> 16) & 0x3FFF) - 4;
      if (RxLen > ETH_MTU) {
        /* Packet too big, ignore it and free buffer. */
        goto rel;
      }
      /* Flag 0x80000000 to skip sys_error() call when out of memory. */
      frame = alloc_mem (RxLen | 0x80000000);
      /* if 'alloc_mem()' has failed, ignore this packet. */
      if (frame != NULL) {
        sp = (U32 *)(Rx_Desc[i].Addr & ~3);
        dp = (U32 *)&frame->data[0];
        for (RxLen = (RxLen + 3) >> 2; RxLen; RxLen--) {
          *dp++ = *sp++;
        }
        put_in_queue (frame);
      }
      /* Release this frame from ETH IO buffer. */
rel:  Rx_Desc[i].Stat = DMA_RX_OWN;

      if (++i == NUM_RX_BUF) i = 0;
      RxBufIndex = i;
    }
    if (int_stat & INT_TIE) {
      /* Frame transmit completed. */
    }
  }
}


Закоментировал обработчик и получилось скомпилировать. Физику читает, идентификатор читает правильно. Линк светится. С autonegotiation проблем нет если кабель подключен. PHY_REG_BMSR = 0x7869. Адрес физики = 31.
Golikov A.
#include "Net_Config.h"
?
smk
Цитата(Golikov A. @ Nov 13 2013, 22:05) *
#include "Net_Config.h"
?

Пробовал. Вылазит куча другого. Думаю для текущего этапа закоментировать - лучшее решение.
Golikov A.
ну тогда остается только свои функции - заглушки написать.
smk
Цитата(Golikov A. @ Nov 13 2013, 23:13) *
ну тогда остается только свои функции - заглушки написать.

Двигаюсь в соответствии с постом №68. Пока удачно. В целом начинать с простого это самое то, что нужно. Т.к. с езернетом до этого дел не имел. Так что для лучшего понимания нужно пройти все шаги.
Pasha_a13
Добрый день!

Прошу совета.
Вкратце опишу суть вопроса.

В своих устройствах использую микроконтроллеры различных семейств(PIC, MSP430, планирую для более сложных проектов перейти на STM32).
В основном устройства не очень сложные.
Сейчас возникла необходимость в разработке устройств с web-интерфейсом(для конфигурирования, просмотра логов и т.п.) а также устройства должны будут складывать данные на удаленный сервер, обновлять прошивку удаленно и т.п.

Смотрел на микросхему W5100 со встроенным TCP/IP стеком.
Запустить не ней простой web-интерфейс , насколько я понял, будет довольно несложно, однако смущает ее дороговизна и не сильно широкое растространение (я так понимаю ввиду ограниченности возможностей ее стека?).
В результате этого пришел к выводу что все-таки предпочтительнее использовать софтверный стек внутри контроллера и простую физику снаружи(в случае PIC18F97J60 и подобных еще дешевле все получается, т.к. физика внутри контроллера).

Уважаемые специалисты, посоветуйте пожалуйста новичку какой из стеков (lwip, или от microchip, или еще какой-то) мне лучше выбрать чтобы, так сказать, он был более универсальным, т.е. при необходимости его можно было портировать на разные семейства контроллеров?
Или же предпочтительно остановиться на каком-то одном семействе для работы с ethernet?
smk
Ну вобщем-то с текущими проблемами разобрался. Хотелось бы идти дальше. Физику читает/пишет.
psL
Цитата(Pasha_a13 @ Nov 23 2013, 16:40) *
какой из стеков (lwip, или от microchip, или еще какой-то) мне лучше выбрать чтобы, так сказать, он был более универсальным, т.е. при необходимости его можно было портировать на разные семейства контроллеров?
Или же предпочтительно остановиться на каком-то одном семействе для работы с ethernet?

Для переносимости лучше написать обертку над сокетами/протосокетами/... конкретной реализации tcp/ip, тогда приложение можно будет хоть на x86 запускать. А еще лучше вместо микростеков использовать полноценные стеки и соответствующие микроконтроллеры. Какой-нибудь TL-MR3020 уже 500 рублей в розницу...
smk
С физикой все более-менее понятно. Хотелось бы уже и попинговать попробовать. Как собственно запустить кейловский стек? Состояние RTL8201CP сподключенным кабелем привожу на картинке.
Нажмите для просмотра прикрепленного файла
Golikov A.
init_TcpNet ();

а потом в цикле вызывайте
main_TcpNet();

не забудьте заполнить
tcpip_user.с

вроде на пинг после этого должен начать отвечать

потом сделаете сокеты, и пропишите функции обменов

smk
Цитата(Golikov A. @ Nov 25 2013, 21:29) *
init_TcpNet ();

а потом в цикле вызывайте
main_TcpNet();

не забудьте заполнить
tcpip_user.с

вроде на пинг после этого должен начать отвечать

потом сделаете сокеты, и пропишите функции обменов

Может имеет смысл подключить библиотеку от кейла и нужные файлы?

Попытался скомпилировать с библиотекой и файлами Net_Config.c / Net_Config.h
Получил ошибку:

Код
F:\Program\Keil454\ARM\RV31\Inc\RTL.h(37): error:  #256: invalid redeclaration of type name "S8" (declared at line 31 of "type.h")


Как цивилизованно выйти из ситуации?
Golikov A.
Цитата(smk @ Nov 26 2013, 21:46) *
Может имеет смысл подключить библиотеку от кейла и нужные файлы?

Попытался скомпилировать с библиотекой и файлами Net_Config.c / Net_Config.h
Получил ошибку:

Код
F:\Program\Keil454\ARM\RV31\Inc\RTL.h(37): error:  #256: invalid redeclaration of type name "S8" (declared at line 31 of "type.h")


Как цивилизованно выйти из ситуации?


ну подключать библиотеку и нужные файлы само собой разумелось.


проверить что все файлы, а в честности type.h защищены
#ifndef header_name
#define header_name

#endif

ну а дальше править файлы, где у вас один тип по 2 раза объявляется...
файлы библиотеки считать основными, ваши файлы вторыми...
smk
Разобрался с проблемой. Скомпилировалось. Хочу спросить, если применять библиотеку TCP_CM3.lib, то нужен ли SysTick?
Golikov A.
да, без тика жизни нет...

в ТСР стэке есть время зависимые функции. ДХЦП например обрабатывается с интервалами, таймауты считать для работы модулей тоже...

smk
Цитата(Golikov A. @ Nov 27 2013, 14:17) *
да, без тика жизни нет...

в ТСР стэке есть время зависимые функции. ДХЦП например обрабатывается с интервалами, таймауты считать для работы модулей тоже...

А что нужно сделать/дописать?
Golikov A.
у меня как то так
функция которую вызываю в цикле постоянно
только коменты по кривому вставляютсяsad.gif, так что без них

Код
void TCP_IP_Process(void)
{
   int16_t i; //ïàðàìåòð öèêëà
   timer_poll (); //îïðàøèâàåì òàéìåð, ôîðìèðóåì íåîáõîäèìûå äëÿ ðàáîòû ÒÑÐ òèêè
   main_TcpNet(); //îñíîâíàÿ ôóíêöèÿ ðàáîòû ÒÑÐ ñòýêà
   dhcp_check (); //ïðîâåðÿåì DHCP
        
   //îòïðàâêà ãîòîâûõ äàííûõ UDP
   SendUDPdata(&UdpSock);
    
  //ïðîâåðÿåì äëÿ êàêèõ ñîêåòîâ âîçìîæíî î÷èñòèòü îêíî è îòïðàâëÿåì ãîòîâûå äàííûå åñëè åñòü
  for(i = 0; i < TCP_SOCKET_NUMBER; i++)//öèêë ïî âñåì ñîêåòà
   {
    SendTCPdata(&(TcpSock[i])); //îòïðàâêà ãîòîâûõ äàííûõ
    if( GetFIFOBufferSize(TcpSock[i].InputBufferStr) >= TcpSock[i].FreeWindowSize) //åñëè â áóôåðå åñòü äîñòàòî÷íî ìåñòà
      tcp_reset_window(TcpSock[i].SocketNumber);    //î÷èùàåì îêíî äàííîãî ñîêåòà
   }
  tick = __FALSE; //ñáðàñûâàåì òèê åñëè ïîÿâèëñÿ, åñëè íåò, íè÷åãî ñòðàøíîãî
}



SendTCP, SendUDP - это мои функции отправки ТСР и UDP сообщений из моих буферов, GetFIFOBufferSize - это тоже моя для проверки места в буфере, чтобы понять можно окно ТСР отпускать или еще нет.

и вот функция таймера что тики выставляет
Код
char Tcp100mSec = 0;
static void timer_poll ()
{
  /* System tick timer running in poll mode */
  if (SysTick->CTRL & 0x10000)  
  {
    if ( Tcp100mSec++ >= 100  )
    {
      Tcp100mSec = 0;
      /* Timer tick every 100 ms */
      timer_tick();
      tick = __TRUE;
    }
  }
}

в этой функции ставиться глобальный tick тот что в dhcp у меня используется, а timer_tick() - это функция стэка

а tick  используется в DHCP, для расчета таймаута и опроса не нашел ли он айпишник.
smk
Наконец-то вернулся к своей теме. Результаты такие: дописал SysTick из примера от кейл. Дописал вызовы функций из того же примера. Скомпилировал. Пинга нет. Что нехватает? Прошу помочь. Проект прилагаю.
Нажмите для просмотра прикрепленного файла
bzx
1. Ваш Phy чип определяется?
Цитата
/* Check if this is a RTL8201CP PHY. */
id1 = read_PHY (PHY_REG_IDR1);
id2 = read_PHY (PHY_REG_IDR2);

что в регистрах id1 и id2, т.е. идентификатор для RTL8201 определяется корректно? Пробегитись с отладчиком, после указанных строк в if попадаете?

2. Где 'Net_lib.c'?
Golikov A.
init_ethernet() - вроде вызывать не надо, оно само вызовется в init_TcpNet ();

дальше все вроде верно выглядит

Пингуете из той же под сети?
Аутонеготинация прошла?
DHCP выключили не забыли? или вы по нему IP получаете?
dhcp_disable (); до этого момента заданный в netconfig IP адрес не присвоится, а без него IP 0.0.0.0, а этот айпи запрещен, он служебный


smk
Цитата(bzx @ Dec 4 2013, 19:30) *
1. Ваш Phy чип определяется?

что в регистрах id1 и id2, т.е. идентификатор для RTL8201 определяется корректно? Пробегитись с отладчиком, после указанных строк в if попадаете?

2. Где 'Net_lib.c'?

Определяется. Пробежался.
Net_lib.c - что такое?

init_ethernet(); закоментил, dhcp_disable (); добавил. Пингуетя!!! Ура!!!

Теперь хочется двигаться дальше. Например принимать - передвать пакет. Сначала хоть маленький, затем и в пару десятков кило можно.

Код
int main (void)
{
    
    USART1_Init();    
//    init_ethernet();
  init_TcpNet ();
    dhcp_disable ();

  /* Setup and enable the SysTick timer for 100ms. */
  SysTick->LOAD = (72000000 / 10) - 1;
  SysTick->CTRL = 0x05;
    
  while (1)
    {    

    timer_poll ();
        main_TcpNet();
            
    } /* Loop forever */
}
Golikov A.
дальше уже дело техники,
все очень просто!

Код
//выделяете сокет
SocketNumber = tcp_get_socket (TCP_TYPE_SERVER | TCP_TYPE_DELAY_ACK | TCP_TYPE_FLOW_CTRL | TCP_TYPE_KEEP_ALIVE, 0, 65535, tcp_callback);

//если получилось, ставите его на прослушку - это сокет который принимает конект
if (SocketNumber != 0)
  {
    /* Start listening on TCP port DevEthInfo.CtrlPort */
    tcp_listen (SocketNumber, PortNumber);
  }



tcp_callback - это функция обработки событий


Код
uint16_t tcp_callback (uint8_t soc, uint8_t evt, uint8_t *buf, uint16_t len) {
  /* This function is called by the TCP module on TCP event */
  /* Check the Net_Config.h for possible events.            */
  switch (evt)
  {
        case TCP_EVT_DATA: //ïðèøëè äàííûå
            /* TCP data frame has arrived, data is located at *buf, */
            /* data length is len. Allocate buffer to send reply.   */
            break;    

    case TCP_EVT_CONREQ:
      /* Remote host is trying to connect to our TCP socket. */
      return (1);
      
    case TCP_EVT_ABORT:
      break;
      
    case TCP_EVT_CONNECT:
      /* Socket is connected to remote peer. */
            return (1);
    
    case TCP_EVT_CLOSE:
      break;
                    
      
    case TCP_EVT_ACK:
      /* Our sent data has been acknowledged by remote peer */
      break;
  }
  return (0);


в эту функцию надо написать прием данных по событию TCP_EVT_DATA, buf - данные, len - длинна
учтите если вы никуда не сохранили данные они просто пропадут

чтобы послать данные
tcp_send (SocketNumber, sendbuf, SendDataSize);


для сброса окна
tcp_reset_window(SocketNumber)
это функция нужна если сокет делали с флагом TCP_TYPE_FLOW_CTRL
она сбрасывает окно, в кейловском стеке окно сбрасывается разом, по кусочкам из него не вычитывается.



самое простое - это сервер
в функцию приема воткнуть посылку данных обратно и сброс окна.




А да забыл.
после того как вы это сделали и запустили, надо конектиться из винды(юникса, макоса и бла бла бла) к этому сокету, по заданному порту, и слать данные.

со стороны винды(юникса) самое простое взять netcat
это программка консольная которая позволяет устанавливать ТСР соединение по заданному порту, слать и принимать данные

smk
Вот такое сообщение об ошибке получилось:
Код
main_eth.c(48): error:  #20: identifier "TCP_TYPE_KEEP_ALIVE" is undefined

и ведь действительно в rtl.h не определено. Как поступить?

Попутно хотелось бы понимать ситуацию когда обращается скажем 2 и более клиента, при этом каждому нужны свои данные. Как их различать и отслеживать? Количество одновременных коннектов, я так понимаю лимитируется только размером памяти?
Golikov A.
у меня такое написано

Код
#define TCP_TYPE_SERVER    0x01   /* Socket Type Server (open for listening) */
#define TCP_TYPE_CLIENT    0x02   /* Socket Type Client (initiate connect)   */
#define TCP_TYPE_DELAY_ACK 0x04   /* Socket Type Delayed Acknowledge         */
#define TCP_TYPE_FLOW_CTRL 0x08   /* Socket Type Flow Control                */
#define TCP_TYPE_KEEP_ALIVE 0x10  /* Socket Type Keep Alive                  */
#define TCP_TYPE_CLIENT_SERVER (TCP_TYPE_SERVER | TCP_TYPE_CLIENT)


может старая версия стэка... она к 4.3 изменилась, FLOW_CTRL добавился вроде бы

надо про ТСР читать.
Соединение ТСР сокет - сокет, сокеты различаются по IP и номеру порта.
по конекту вызывается калбэк, с параметрами того кто конектится,
В установленное соединение сокет - сокет никто влезть не может.

у меня 3 сокета в проекте, на каждом свой тип данных.
smk
Спасибо, что уделяетемне время!

Версия кейла у меня 4.54, может там и нет такого. Его добавить или наоборот убрать? Может файлы просто заменить в кейле на те, что от более нового?

Теперь про сокеты не соображу. Вот выполнилось условие if (SocketNumber != 0). Будет вызван tcp_listen. Я так понимаю оттуда будет вызван tcp_callback. У каждого клиента будет свой номер или как мне различить их?
Golikov A.
sm.gif
нет такого флага в вашем кейле и вашей библиотеке, значит его использовать нельзя.
это от 4.72, когда прошла смена стэка мне не ведомо, в 3.7 flow контроля не было по моим данным

Вам надо концептуально понять
Сокет - это розетка. Воткнули вилку - розетку заняли

SocketNumber - это идентификатор этой розетки.
если в него кто-то подсоединится он собой этот сокет займет. И все что сокет пошлет, будет для него, а все что он пошлет придет в этот сокет
если номер 0 - то значит сокет не сделался, для этого проверка, а если он сделался, то к нему подключается прослушка и калбэк функция

обратите внимание что в
uint16_t tcp_callback (uint8_t soc, uint8_t evt, uint8_t *buf, uint16_t len)

есть параметр soc - это как раз этот номер, то есть если вы сделаете много сокетов, то они будут вызывать калбэк функцию каждый со своим номером.


smk
Цитата(Golikov A. @ Dec 5 2013, 22:45) *
sm.gif
нет такого флага в вашем кейле и вашей библиотеке, значит его использовать нельзя.
это от 4.72, когда прошла смена стэка мне не ведомо, в 3.7 flow контроля не было по моим данным

Вам надо концептуально понять
Сокет - это розетка. Воткнули вилку - розетку заняли

SocketNumber - это идентификатор этой розетки.
если в него кто-то подсоединится он собой этот сокет займет. И все что сокет пошлет, будет для него, а все что он пошлет придет в этот сокет
если номер 0 - то значит сокет не сделался, для этого проверка, а если он сделался, то к нему подключается прослушка и калбэк функция

обратите внимание что в
uint16_t tcp_callback (uint8_t soc, uint8_t evt, uint8_t *buf, uint16_t len)

есть параметр soc - это как раз этот номер, то есть если вы сделаете много сокетов, то они будут вызывать калбэк функцию каждый со своим номером.


Появилось время продолжить.

Про сокет я понял. Только не соображу как все устроено. Если сокетов несколько, то как все изменится программно? SocketNumber я так понимаю переменная которую надо объявить? "есть параметр soc - это как раз этот номер" т.е. всякий раз когда вызвана tcp_callback используя soc можно узнать для какого сокета произошел вызов и соответственно обработать, так? Только вот не ясно. Скажем есть сокеты с номерами 1,2,3,4. Если сокет №2 освободился, то остальные так и останутся со своими номерами? "ставим на прослушку" имеется в виду, что нужно постоянно проверять значение SocketNumber?
smk
С помощью терминальной программы: http://www.hw-group.com/products/hercules/index_en.html пробовал отсылать пару байт. В режиме TCP-Client соединение происходит и Wireshark показывает, что плата отвечает. Однако я никак не могу попасть в tcp_callback. Как правильно проверить связь? Порт задал 80.


На всякий случай выкладываю архив с проектом в последней эволюционной стадии, может делаю чего не так. Компилируется, пингуется.
Нажмите для просмотра прикрепленного файла
DmitryM
Цитата(smk @ Dec 22 2013, 15:01) *
Есть ли какая=то терминальная программа для ethernet? искал в сети, но что-то безрезультатно...


Netcat
PuTTY
smk
Цитата(DmitryM @ Dec 22 2013, 14:21) *
PuTTY

Нашел, загрузил и запустил. Не пойму как услать пару байт...
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.