Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: LwIP стек в STM32F217
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Страницы: 1, 2
Acvarif
На st имеется демка под LwIP на stm32f207 для PHY DP83848C (режим MII) (в демке реализованы почти все возможные варианты серверов и клиентов).
Поскольку у меня на столе имеется платка с stm32f217 + phy ks8721bl (режим RMII) пришлось демку LwIP переделать под нее (не поленился переделал все демки в том числе и под FREE RTOS). Все приложения работают без проблем. Вот ссылка на архив (большой ~47м ). (переделаны проекты для Keil, проекты под IAR переделываюся только сменой камня. Все работает также без проблем) Но остался вопрос.
Нормального понимания как работать с LwIP + stm32 пока нет. Дока на стек и демку не проясняет.
У кого есть опыт работы с LwIP + stm32 подсобите please для старта простым примером LwIP как принять одни данные по UDP и отправить другие.
В демке имеется UDP эхо сервер. Поможет даже подсказка как сделать так, чтобы сервер отправлял не эхо, а конкретные данные из конкретного буфера типа *my_buf.

Спасибо.

В main все начинается так:

Код
    /* check if any packet received */
    if (ETH_CheckFrameReceived())
    {
      /* process received ethernet packet */
      LwIP_Pkt_Handle();
    }


Функция ETH_CheckFrameReceived делает это:
CODE
/**
* @brief This function polls for a frame reception
* @param None
* @retval Returns 1 when a frame is received, 0 if none.
*/
uint32_t ETH_CheckFrameReceived(void)
{
/* check if last segment */
if(((DMARxDescToGet->Status & ETH_DMARxDesc_OWN) == (uint32_t)RESET) &&
((DMARxDescToGet->Status & ETH_DMARxDesc_LS) != (uint32_t)RESET))
{
DMA_RX_FRAME_infos->LS_Rx_Desc = DMARxDescToGet;
DMA_RX_FRAME_infos->Seg_Count++;
return 1;
}

/* check if first segment */
else if(((DMARxDescToGet->Status & ETH_DMARxDesc_OWN) == (uint32_t)RESET) &&
((DMARxDescToGet->Status & ETH_DMARxDesc_FS) != (uint32_t)RESET)&&
((DMARxDescToGet->Status & ETH_DMARxDesc_LS) == (uint32_t)RESET))
{
DMA_RX_FRAME_infos->FS_Rx_Desc = DMARxDescToGet;
DMA_RX_FRAME_infos->LS_Rx_Desc = NULL;
DMA_RX_FRAME_infos->Seg_Count = 1;
DMARxDescToGet = (ETH_DMADESCTypeDef*) (DMARxDescToGet->Buffer2NextDescAddr);
}

/* check if intermediate segment */
else if(((DMARxDescToGet->Status & ETH_DMARxDesc_OWN) == (uint32_t)RESET) &&
((DMARxDescToGet->Status & ETH_DMARxDesc_FS) == (uint32_t)RESET)&&
((DMARxDescToGet->Status & ETH_DMARxDesc_LS) == (uint32_t)RESET))
{
(DMA_RX_FRAME_infos->Seg_Count) ++;
DMARxDescToGet = (ETH_DMADESCTypeDef*) (DMARxDescToGet->Buffer2NextDescAddr);
}
return 0;
}

Я так понимаю, что функция проверяет имеется ли что-то в DMA В частности если имеется фрейм и сегмент в фрейме последний, то возвращается 1.
Что такое последний сегмент? Понимаю, что можно послать меня на очередной мануал. Но мануалы меня уже сильно достали из за их непоследовательности и часто бесполезности.
Ответьте пожалуйста на русском коротко работу функции ETH_CheckFrameReceived(void) (функция почемуто всегда, послал я фрейм или нет, возвращает 1)
Дальше начинается кошмар по имени
Код
      /* process received ethernet packet */
      LwIP_Pkt_Handle();
который далее переходит в
Код
  /* Read a received packet from the Ethernet buffers and send it to the lwIP for handling */
  ethernetif_input(&netif);

и куда дальше попадают собственно данные посланного из компа UDP пакета, так, чтобы с ними можно было -бы поработать и как послать компу ответ в виде своего пакета (а не того же самого) не допираю.
Подсобите, кто сталкивался с этим.
Нашел пока это http://lwip.wikia.com/wiki/Raw/UDP
Всеравно не понятно как на базе LwIP послать на комп UDP пакет Ну допустим так:

Код
   struct udp_pcb *upcb;
   /* Create a new UDP control block  */
   upcb = udp_new();    
   /* Bind the upcb to the UDP_PORT port */
   /* Using IP_ADDR_ANY allow the upcb to be used by any local interface */
   udp_bind(upcb, IP_ADDR_ANY, 23);
  /* Connect to the remote client */
  udp_connect(upcb, addr, 23);

В каком виде нужно записать addr?
Похоже, что дальше можно
Код
udp_send(struct udp_pcb * pcb, struct pbuf * p)

тоесть
Код
udp_send(upcb, p);

Что такое struct pbuf * p
kan35
Дока на lwIP существует, она вполне полезная, по крайней мере описание API нужно там изучить.
Я советую пользоваться только под FreeRTOS в силу того, что в ней как мне кажется существенно проще работать.

Создать дескриптор и соединение TCP (или UDP - по аналогии):
Код
struct netconn * conn;
conn = netconn_new(NETCONN_TCP);
struct ip_addr addr;
addr.addr = inet_addr("193.193.165.165");
unsigned short server_port = 45321;
if (netconn_connect(conn, &addr, server_port) == ERR_OK)
...

Отправить данные
Код
netconn_write(conn, "Hello...", strlen("Hello..."), NETCONN_NOCOPY);// передача данных

Принять данные в netbuf
Код
struct netbuf * in_buf = netconn_recv(conn)
..../// сделал что нужно с данными и удалил буфер
netbuf_delete(in_buf);

Еще можно добавить что netbuf это структура, описывающая склейку некоторого количества маленьких буферов, в ней храняться указатели на предыдущий буфер и на последующий и проч, работать напрямую не удобно, да и не нужно, так как в stm памяти достаточно чтобы с помощью API вытащить из буфера данные в линейный массив:
Код
unsigned long buflen = netbuf_len(in_buf);
incoming_data = (char *)pvPortMalloc(buflen);
netbuf_copy(in_buf, incoming_data, buflen);

Здесь и везде по стеку используется куча, потому не забываем удалять выделенные области после изспользования. Все примеры на функциях из доки на lwIP.
Конечно можно перейти на нижний уровень или на верхний - с сокетами, но я рекомендую начать netconn API.
Acvarif
Спасибо. Начало проясняться.

Удалось послать строку по UDP на комп. Смутно понимаю (придется таки почитать мануал на LwIP), как стек это делает, в коде это достаточно просто.

CODE
struct udp_pcb *upcb;
struct pbuf *p;
struct ip_addr DestIPaddr;
char tdata[] = {"Test"};
char *data = tdata;

/* Create a new UDP control block */
upcb = udp_new();
/*assign destination IP address */
IP4_ADDR( &DestIPaddr, DEST_IP_ADDR0, DEST_IP_ADDR1, DEST_IP_ADDR2, DEST_IP_ADDR3 );
/* configure destination IP address and port */
udp_connect(upcb, &DestIPaddr, UDP_SERVER_PORT);
/* allocate pbuf from pool*/
p = pbuf_alloc(PBUF_TRANSPORT,strlen((char*)data), PBUF_POOL);
/* copy data to pbuf */
pbuf_take(p, (char*)data, strlen((char*)data));
/* send udp data */
udp_send(upcb, p);

После этого очевидно нужно еще разорвать соединение и освободить занятую память
Код
/* Reset the upcb */
   udp_disconnect(upcb);
/* Free the p buffer */
   pbuf_free(p);
kan35
Вы продолжаете работать на уровне pcb, я же предлагаю использовать netbuf API и netconn интерфейс или socket интерфейс и будет работать не сложнее чем с сериальным портом.
Вот пример из доки в полной мере делающий то же что и ваш код
CODE
int
main()
{
struct netconn *conn;
struct netbuf *buf;
struct ip_addr addr;
char *data;
char text[] = "A static text";
int i;
/* create a new connection */
conn = netconn_new(NETCONN_UDP);
/* set up the IP address of the remote host */
addr.addr = htonl(0x0a000001);
/* connect the connection to the remote host */
netconn_connect(conn, &addr, 7000);
/* create a new netbuf */
buf = netbuf_new();
data = netbuf_alloc(buf, 10);
/* create some arbitrary data */
for(i = 0; i < 10; i++)
data[i] = i;
/* send the arbitrary data */
netconn_send(conn, buf);
/* reference the text into the netbuf */
netbuf_ref(buf, text, sizeof(text));
/* send the text */
netconn_send(conn, buf);
/* deallocate connection and netbuf */
netconn_delete(conn);
netconn_delete(buf);
}
Acvarif
Цитата
Вы продолжаете работать на уровне pcb, я же предлагаю использовать netbuf API и netconn интерфейс или socket интерфейс и будет работать не сложнее чем с сериальным портом.

Нет. Просто меня пробило как передать пакет на уровне pcb (без глубокого копания).

Конечно же я попробую Ваше предложение, тем более, если это не сложнее Com.
Спасибо за пример. В доке действительно все расписано. Но...

Пытаюсь откомпилировать...Не хватает нужных #include для вызываемых функций. Попробую поискать в файлах стека где они спрятаны.
Acvarif
Цитата(Acvarif @ Jan 13 2012, 15:39) *
Пытаюсь откомпилировать...Не хватает нужных #include для вызываемых функций. Попробую поискать в файлах стека где они спрятаны.


К проекту из LwIP подключена папка api где имеются файлы netbuf.c, api_lib.c

При компиляции выскакивает:

compiling main.c...
..\src\main.c(134): warning: #223-D: function "netconn_new" declared implicitly
..\src\main.c(134): error: #20: identifier "NETCONN_UDP" is undefined
..\src\main.c(134): error: #513: a value of type "int" cannot be assigned to an entity of type "struct netconn *"
..\src\main.c(138): warning: #223-D: function "netconn_connect" declared implicitly
..\src\main.c(146): warning: #223-D: function "netconn_send" declared implicitly
..\src\main.c(152): warning: #223-D: function "netconn_delete" declared implicitly
..\src\main.c - 2 Error(s), 4 Warning(s).

Например NETCONN_UDP находится в api.h который в свою очередь подключен к api_lib.c

Пока непонятно что не так.
Acvarif
Все прояснилось. Мануал 2001 года подходит для LwIP 1.1.0, а в демках применен LwIP 1.3.2 (хотя заголовок демки именуется как STM32F2x7_ETH_LwIP_V1.1.0)
В новой версии стека нет netconn_new(NETCONN_UDP); и т. д.

Там есть struct netconn * netconn_new_with_proto_and_callback (enum netconn_type t, u8_t proto, netconn_callback callback)
Что это и с чем его едят придется разбираться. Примеров использования пока не нашел.
kan35
Чтобы активировать те или иные Api кроме того, чтобы включить файлы надо настроить стек. Делается это в файле lwipopt.h
У вас должно быть так:
Код
/**
* LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c)
*/
#define LWIP_NETCONN                    1

и пока что мануал актуален на все 100
Acvarif
Спасибо. Почти получилось...
Портит картину netconn_delete(buf);
..\src\main.c(154): error: #167: argument of type "struct netbuf *" is incompatible with parameter of type "struct netconn *"
Очевидно в мануале ошибка
Нужно так
Код
netconn_delete(conn);
netbuf_delete(buf);

В понедельник проверю на железе.
Спасибо kan35
Удачного Старого Нового Года!
Acvarif
Таки не выдержал. Попытался откомпилировать весь проект. Для удобства поиска в файлах перешел с Keil на IAR (принципиально ничего не меняется) Напоролся на недопонимание в файлах api_lib.c, api_msg.c
api_lib.c - выскочила куча ошибок и предупреждений. Интуиция подсказала, что в файле не хватает
#include "lwip/api_msg.h" После компиляции количество непоняток уменьшилось но не совсем...
CODE
Warning[Pe223]: function "TCPIP_APIMSG" declared implicitly \src\api\api_lib.c 82
Error[Pe020]: identifier "SYS_SEM_NULL" is undefined \src\api\api_lib.c 86
Error[Pe020]: identifier "SYS_MBOX_NULL" is undefined \src\api\api_lib.c 87
Error[Pe020]: identifier "SYS_MBOX_NULL" is undefined \src\api\api_lib.c 88
Warning[Pe223]: function "tcpip_apimsg" declared implicitly \src\api\api_lib.c 118
Warning[Pe223]: function "TCPIP_APIMSG" declared implicitly \src\api\api_lib.c 151
Warning[Pe223]: function "TCPIP_APIMSG" declared implicitly \src\api\api_lib.c 177
Warning[Pe223]: function "tcpip_apimsg" declared implicitly \src\api\api_lib.c 201
Warning[Pe223]: function "TCPIP_APIMSG" declared implicitly \src\api\api_lib.c 220
Warning[Pe223]: function "TCPIP_APIMSG" declared implicitly \src\api\api_lib.c 247
Error[Pe020]: identifier "SYS_MBOX_NULL" is undefined \src\api\api_lib.c 263
Warning[Pe223]: function "sys_arch_mbox_fetch" declared implicitly \src\api\api_lib.c 270
Error[Pe020]: identifier "SYS_MBOX_NULL" is undefined \src\api\api_lib.c 306
Warning[Pe223]: function "sys_arch_mbox_fetch" declared implicitly \src\api\api_lib.c 339
Warning[Pe223]: function "TCPIP_APIMSG" declared implicitly \src\api\api_lib.c 375
Warning[Pe223]: function "sys_arch_mbox_fetch" declared implicitly \src\api\api_lib.c 384
Warning[Pe223]: function "TCPIP_APIMSG" declared implicitly \src\api\api_lib.c 438
Warning[Pe223]: function "TCPIP_APIMSG" declared implicitly \src\api\api_lib.c 469
Warning[Pe223]: function "tcpip_apimsg" declared implicitly \src\api\api_lib.c 488

Например Error[Pe020]: identifier "SYS_SEM_NULL" is undefined \src\api\api_lib.c 86
касается этого
Код
LWIP_ASSERT("conn has no op_completed", conn->op_completed != SYS_SEM_NULL);

Warning[Pe223]: function "tcpip_apimsg" declared implicitly \src\api\api_lib.c 118
касается этого
Код
tcpip_apimsg(&msg);


Для api_msg.c еще больше непоняток.
CODE
Error[Pe020]: identifier "SYS_MBOX_NULL" is undefined \src\api\api_msg.c 93
Error[Pe029]: expected an expression \src\api\api_msg.c 116
Error[Pe020]: identifier "SYS_MBOX_NULL" is undefined \src\api\api_msg.c 159
Error[Pe029]: expected an expression \src\api\api_msg.c 185
Error[Pe020]: identifier "SYS_MBOX_NULL" is undefined \src\api\api_msg.c 215
Error[Pe029]: expected an expression \src\api\api_msg.c 227
Error[Pe020]: identifier "SYS_MBOX_NULL" is undefined \src\api\api_msg.c 314
Error[Pe020]: identifier "SYS_SEM_NULL" is undefined \src\api\api_msg.c 319
Error[Pe020]: identifier "SYS_MBOX_NULL" is undefined \src\api\api_msg.c 323
Error[Pe020]: identifier "SYS_MBOX_NULL" is undefined \src\api\api_msg.c 376
Error[Pe029]: expected an expression \src\api\api_msg.c 388
Warning[Pe223]: function "TCPIP_APIMSG_ACK" declared implicitly \src\api\api_msg.c 482
Error[Pe020]: identifier "SYS_SEM_NULL" is undefined \src\api\api_msg.c 536
Error[Pe020]: identifier "SYS_MBOX_NULL" is undefined \src\api\api_msg.c 540
Error[Pe020]: identifier "SYS_MBOX_NULL" is undefined \src\api\api_msg.c 546
Warning[Pe550]: variable "size" was set but never used \src\api\api_msg.c 499
Error[Pe020]: identifier "SYS_MBOX_NULL" is undefined \src\api\api_msg.c 581
Error[Pe029]: expected an expression \src\api\api_msg.c 582
Error[Pe020]: identifier "SYS_MBOX_NULL" is undefined \src\api\api_msg.c 596
Error[Pe029]: expected an expression \src\api\api_msg.c 597
Error[Pe020]: identifier "SYS_SEM_NULL" is undefined \src\api\api_msg.c 605
Error[Pe020]: identifier "SYS_SEM_NULL" is undefined \src\api\api_msg.c 709
Warning[Pe223]: function "TCPIP_APIMSG_ACK" declared implicitly \src\api\api_msg.c 750
Warning[Pe223]: function "TCPIP_APIMSG_ACK" declared implicitly \src\api\api_msg.c 843
Error[Pe020]: identifier "SYS_MBOX_NULL" is undefined \src\api\api_msg.c 869
Error[Pe020]: identifier "SYS_MBOX_NULL" is undefined \src\api\api_msg.c 874
Warning[Pe223]: function "TCPIP_APIMSG_ACK" declared implicitly \src\api\api_msg.c 893
Warning[Pe223]: function "TCPIP_APIMSG_ACK" declared implicitly \src\api\api_msg.c 931
Warning[Pe223]: function "TCPIP_APIMSG_ACK" declared implicitly \src\api\api_msg.c 959
Warning[Pe223]: function "TCPIP_APIMSG_ACK" declared implicitly \src\api\api_msg.c 1097
Warning[Pe223]: function "TCPIP_APIMSG_ACK" declared implicitly \src\api\api_msg.c 1145


Пытался найти решение проблем в настройках lwipopts.h - не получилось.
В стеке еще имеется файл opt.h но как с ним работать непонятно. Файл вообще с атрибутами только для чтения.
kan35
opt.h - это настройки по умолчанию, их не стоит трогать, потому он read only
lwipopt.h - это файл для настройки пользователем, они имеют приоритет над настройками по умолчанию, его и крутите

Как я понимаю все эти ошибки из за того, что стек не видит FreeRTOS.
И еще, файлы sys_arch являются связкой между FreeRTOS и lwIP и тоже должны иметься в проекте.
Acvarif
Понял. Спасибо. Файл нашел.
Можно ли подружить этот файл ( sys_arch.h) со стеком без FreeRTOS?
Вроде в нем есть то чего не хватает для нормальной компиляции api_lib.c, api_msg.c
Наверняка должен же как то стек (имеется ввиду netbuf API и netconn ) работать в stm32 и без какой-либо операционной системы (уровень pcb работает без ОС).
Очевидно для работы стека в режиме netbuf API и netconn без ОС нужны другие файлы api_lib.c, api_msg.c и может еще некоторые другие h файлы.
kan35
Должен работать конечно, но нюансов не скажу, так как я так же как и вы взял пример от ST и кручу его под свою задачу.
И вы берите пример с ОС, как я и посоветовал в первом своем посте, грех на таком чипе без нее что либо вообще делать. Самому FreeRTOS можно конечно приладить, но без опыта можно долго биться, да и зачем когда есть пример.
Немного лирики. Отличие с ОС и без ОС в том, что без ОС надо по таймерам вызывать определенные процедуры из стека, ловить пакеты через callback-и и прочие неудобства, а когда ОС - просто крутится поток, а взаимодействие стека с вашим приложением идет через через API, которые используют сервисы ОС и в итоге интерфейс с lwIP становится совершенно элементарным.
Acvarif
Понял. Спасибо. С ОС стек компилится без проблем. Попробую уровень netbuf API и netconn.
MK2
А чем вы с компьютера посылали пакеты?
Acvarif
Цитата(MK2 @ Jan 15 2012, 22:20) *
А чем вы с компьютера посылали пакеты?


Да вот этой штукой http://www.hw-group.com/products/hercules/index_en.html Хотя в демке есть программки (вроде под DOS), но они лишены визуальности - работать неудобно.
Acvarif
В общем вроде все получилось. Использовал имеющийся в демке проект под FreeRTOS udptcp_echo_server_netconn
и функцию мигания светодиодом void ToggleLed4(void * pvParameters).
Немного ее модифицировал:
CODE
void ToggleLed4(void * pvParameters)
{
struct netconn *connn;
struct netbuf *buf1;
struct netbuf *buf2;
struct ip_addr addr;
char *data1;
char *data2;
char text1[] = "Hello,my name is SK-STM32F217\n\r";
char text2[] = "I am transmit UDP package\n\r";
int i,n = 0;

/* create a new connection */
connn = netconn_new(NETCONN_UDP);
/* set up the IP address of the remote host */
addr.addr = htonl(0xC0A802A8);
/* connect the connection to the remote host */
netconn_connect(connn, &addr, 7);
/* create a new netbuf */
buf1 = netbuf_new();
buf2 = netbuf_new();

while(1)
{
test = xnetif.ip_addr.addr;
/*check if IP address assigned*/
if (test !=0)
{
for( ;; )
{
/* toggle LED1 each 250ms */
STM_EVAL_LEDToggle(LED1);
vTaskDelay(1000);

data1 = netbuf_alloc(buf1, strlen(text1));
/* create some arbitrary data */
for(i = 0; i < sizeof(text1); i++)
data1[i] = text1[i];

data2 = netbuf_alloc(buf2, strlen(text2));
/* create some arbitrary data */
for(i = 0; i < sizeof(text2); i++)
data2[i] = text2[i];
if(n == 0)
{
n = 1;
netbuf_ref(buf1, text1, strlen(text1));
netconn_send(connn, buf1);
netbuf_delete(buf1);
}
else
{
n = 0;
netbuf_ref(buf2, text2, strlen(text2));
netconn_send(connn, buf2);
netbuf_delete(buf2);
}
}
}
}
}


Все вроде работает. Теперь стала задача подсчитать скорость передачи, а заодно и проверить надежность передающей системы.
Как можно это сделать на базе этой функции.
Ну допустим запустить цикл передачи в 1000 пакетов по 256 байт и осциллоскопом как-то (пока не представляю как) померять период передачи 1000 пакетов.
Может можно както без осциллоскопа?
scifi
Цитата(Acvarif @ Jan 16 2012, 17:23) *
Все вроде работает. Теперь стала задача подсчитать скорость передачи, а заодно и проверить надежность передающей системы.
Как можно это сделать на базе этой функции.
Ну допустим запустить цикл передачи в 1000 пакетов по 256 байт и осциллоскопом как-то (пока не представляю как) померять период передачи 1000 пакетов.

В MAC есть счётчики для различной статистики (например, число отправленных и принятых пакетов). Просто смотрите их содержимое до и после "передачи в 1000 пакетов по 256 байт". То же самое полезно проделать со стороны ПК.
Acvarif
Цитата(scifi @ Jan 16 2012, 17:36) *
В MAC есть счётчики для различной статистики (например, число отправленных и принятых пакетов). Просто смотрите их содержимое до и после "передачи в 1000 пакетов по 256 байт". То же самое полезно проделать со стороны ПК.


Спасибо за информацию. Посмотрю.
Попытался сделать влоб, поставив светодиод (вроде должен индицировать время передачи 1000 пакетов) типа так:
CODE

...
STM_EVAL_LEDOn(LED2);
for(j = 0; j < 1000; j++)
{
data1 = netbuf_alloc(buf1, strlen(text1));
/* create some arbitrary data */
for(i = 0; i < sizeof(text1); i++)
data1[i] = text1[i];

data2 = netbuf_alloc(buf2, strlen(text2));
/* create some arbitrary data */
for(i = 0; i < sizeof(text2); i++)
data2[i] = text2[i];

if(n == 0)
{
n = 1;
netbuf_ref(buf1, text1, strlen(text1));
netconn_send(connn, buf1);
netbuf_delete(buf1);
}
else
{
n = 0;
netbuf_ref(buf2, text2, strlen(text2));
netconn_send(connn, buf2);
netbuf_delete(buf2);
}
}
STM_EVAL_LEDOff(LED2);
}

Но очевидно так будет не корректно. Не знаю почему но пакет из ~10 000 байт светодиод отсчитывает за 160 мс, что очень много для скорости в TBase100
Хотя я не уверен, что скорость Mac выставлена 100. Покак не допру где это утанавливается. Да даже если скорость 10 всеравно 160мс это многовато будет.
scifi
Цитата(Acvarif @ Jan 16 2012, 18:52) *
Но очевидно так будет не корректно. Не знаю почему но пакет из ~10 000 байт светодиод отсчитывает за 160 мс, что очень много для скорости в TBase100
Хотя я не уверен, что скорость Mac выставлена 100. Покак не допру где это утанавливается. Да даже если скорость 10 всеравно 160мс это многовато будет.

Пакет 10000 байт? Вы в курсе, что макс. размер кадра Ethernet - это 1500 байт или около того? Это если не учитывать экзотику типа Jumbo Frame. Значит, пакет фрагментируется на уровне IP. Я думаю, скорость физического уровня здесь ни при чём. В lwip есть огромное множество настроек, которые могут влиять на самые разные вещи, включая задержки при пересылке. Но это только предположение.
Acvarif
Цитата(scifi @ Jan 16 2012, 22:43) *
Пакет 10000 байт? Вы в курсе, что макс. размер кадра Ethernet - это 1500 байт или около того? Это если не учитывать экзотику типа Jumbo Frame. Значит, пакет фрагментируется на уровне IP. Я думаю, скорость физического уровня здесь ни при чём. В lwip есть огромное множество настроек, которые могут влиять на самые разные вещи, включая задержки при пересылке. Но это только предположение.

Да, я в курсе. Просто я передаю 1000 кадров по 100 байт в каждом. Опять же, наверняка так не корректно. Очевидно нужно передавать просто один кадр, например 500 байт, и как то определять его период. Хотя и в этом не уверен.
Буду признателен, за подсказку - технологию определения скорости.
И вообще интересует вопрос реально ли на LwIP + FreeRtos + UDP + stm32f217 получить сорость ~90..100?
MALLOY2
Цитата(Acvarif @ Jan 16 2012, 22:16) *
Да, я в курсе. Просто я передаю 1000 кадров по 100 байт в каждом. Опять же, наверняка так не корректно. Очевидно нужно передавать просто один кадр, например 500 байт, и как то определять его период. Хотя и в этом не уверен.
Буду признателен, за подсказку - технологию определения скорости.
И вообще интересует вопрос реально ли на LwIP + FreeRtos + UDP + stm32f217 получить сорость ~90..100?


90 реально, но не по 100 байт, как минимум 512, а то и 1024
sparcmaster
Цитата(Acvarif @ Jan 17 2012, 00:16) *
Буду признателен, за подсказку - технологию определения скорости.

Я в свое время для оценки скорости замерял за сколько девайс отдаст файл размером в 100 мбайт.
=F8=
Цитата(Acvarif @ Jan 16 2012, 17:52) *
Но очевидно так будет не корректно. Не знаю почему но пакет из ~10 000 байт светодиод отсчитывает за 160 мс, что очень много для скорости в TBase100
Хотя я не уверен, что скорость Mac выставлена 100. Покак не допру где это утанавливается. Да даже если скорость 10 всеравно 160мс это многовато будет.


Параметр TCP_WND сильно на скорость передачи влияет. Увеличить его попробуйте.
MALLOY2
Цитата
Буду признателен, за подсказку - технологию определения скорости.


Я пользуюсь этой
iperf
scifi
Цитата(=F8= @ Jan 17 2012, 13:11) *
Параметр TCP_WND сильно на скорость передачи влияет. Увеличить его попробуйте.

Это из рубрики "Вредные советы"? :-)
Каким образом TCP_WND может повлиять на UDP?
=F8=
Цитата(scifi @ Jan 17 2012, 14:10) *
Это из рубрики "Вредные советы"? :-)
Каким образом TCP_WND может повлиять на UDP?

Сорри, недосмотрел. На UDP никак.
Twen
Аналогично использую МК stm32 + LwIp на FreeRTOS, при ключении прибора не всегда начинает пинговаться, после нескольких сбросов отвечает, хотя эзернет модуль принимает данные(проверено)...У кого нибудь возник еще такая проблема?
Хотя, когда прошил пример без ОС udp_echo_server, пингуется ставильно после вкл./выкл. питания.
Acvarif
Цитата(MALLOY2 @ Jan 17 2012, 12:44) *
Я пользуюсь этой
iperf


Спасибо. Уже ближе. Попробую с этим разобраться применительно к stm32.
В окончательном варианте для тестирования сделал так.
CODE
void ToggleLed4(void * pvParameters)
{
const int Size = 255;
const int Count = 100;
struct netconn *connn;
struct netbuf *buf1;
struct ip_addr addr;
char *data1;
char text1[Size];
int i,j,n = 0;

for(n = 0; n < Size; n++)
text1[n] = 0x55;
/* create a new connection */
connn = netconn_new(NETCONN_UDP);
/* set up the IP address of the remote host */
addr.addr = htonl(0xC0A802A8);
/* connect the connection to the remote host */
netconn_connect(connn, &addr, 7);
/* create a new netbuf */
buf1 = netbuf_new();

while(1)
{
test = xnetif.ip_addr.addr;
/*check if IP address assigned*/
if (test !=0)
{
for( ;; )
{
/* toggle LED1 each 250ms */
STM_EVAL_LEDToggle(LED1);
vTaskDelay(1000);

STM_EVAL_LEDOn(LED2);
for(j = 0; j < Count; j++)
{
data1 = netbuf_alloc(buf1, strlen(text1));
/* create some arbitrary data */
for(i = 0; i < sizeof(text1); i++)
data1[i] = text1[i];


netbuf_ref(buf1, text1, strlen(text1));
netconn_send(connn, buf1);
netbuf_delete(buf1);
}
STM_EVAL_LEDOff(LED2);
}
}
}
}

Отправка из потока ToggleLed4 на комп 100 пакетов по 255 байт. Количеством пакетов и их размером можно управлять. Передается без проблем (со скоростью буду разбираться).
Да, по ходу возникла небольшая проблема. Пакеты немногим более 300 байт не хотят отправляться.
Вообще все виснет. Хотя в UDP должны нормально отправляться (без фрагментации) не менее 512. Очевидно что то в настройках LwIP...

Почитал про iperf - получается, что в моем случае придется воспользоваться UDP эхо сервером, который работает в другом потоке ОС
=F8=
Если кто не знает. В LwIP системма выдачи отладочной информации.
1. Чтоб ее задействовать нужно определить макрос LWIP_PLATFORM_DIAG в файле debug.h Если говорить про iar то все просто:
#define LWIP_PLATFORM_DIAG printf
и устанавливаете в опциях пректа флажек "include semihosting interfice", если поддерживает контороллер и отладчик включаете режим "Semihosted, stdout/stderr via SWO"(в режиме "Semihosted, stdout/stderr via semihosting" лучше даже не пытаться - уж больно тормозяво, если не получается через SWO лучше уж через UART предварительно написав драйвер с приличным буфером), в общем включаете выдачу отладочных сообщений на консоль.
2 в файле opt.h
#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL/LWIP_DBG_LEVEL_WARNING/LWIP_DBG_LEVEL_SERIOUS в зависимости от того какие сообщения хотите получать.
там-же #define LWIP_DBG_TYPES_ON LWIP_DBG_ON
там-же настраиваете от каких модулей хотите получать сообщения.
90% вопросов "почему не работает" отпадет при просмотре логов.
Ваш К.О.
Acvarif
Спасибо за полезную информацию.
Что имеется ввиду под консолью?

Протестировал выдачу по UDP - 1 пакет 255 байт с помощью iperf -u -s -i1 -p 7
Вот результат

Неужели скорость всего 2кб/сек?
Если так, то в чем загвоздка?
А вот 500 пакетов

Не пойму, как это правильно разшифровать. Что такое 0.2 мс?
Почему же такая маленькая скорость 1Mbits/sec ?
=F8=
Цитата(Acvarif @ Jan 17 2012, 18:12) *
Спасибо за полезную информацию.
Что имеется ввиду под консолью?

Если непосредственно в IARе то в режиме отладки View->Terminal IO. Если используете как оболочку Eclipse то Window->Show View->Console, в окне консоли нажимаете кнопку с монитором и выбираете C-SPY Terminal I/O.
Acvarif
Цитата(=F8= @ Jan 17 2012, 16:48) *
Если кто не знает. В LwIP системма выдачи отладочной информации.
1. Чтоб ее задействовать нужно определить макрос LWIP_PLATFORM_DIAG в файле debug.h Если говорить про iar то все просто:
#define LWIP_PLATFORM_DIAG printf
и устанавливаете в опциях пректа флажек "include semihosting interfice", если поддерживает контороллер и отладчик включаете режим "Semihosted, stdout/stderr via SWO"(в режиме "Semihosted, stdout/stderr via semihosting" лучше даже не пытаться - уж больно тормозяво, если не получается через SWO лучше уж через UART предварительно написав драйвер с приличным буфером), в общем включаете выдачу отладочных сообщений на консоль.
2 в файле opt.h
#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL/LWIP_DBG_LEVEL_WARNING/LWIP_DBG_LEVEL_SERIOUS в зависимости от того какие сообщения хотите получать.
там-же #define LWIP_DBG_TYPES_ON LWIP_DBG_ON
там-же настраиваете от каких модулей хотите получать сообщения.
90% вопросов "почему не работает" отпадет при просмотре логов.
Ваш К.О.


Пытаюсь повторить в IAR.
#define LWIP_PLATFORM_DIAG printf в файле debug.h установлено по умолчанию
в файле opt.h по умолчанию
Код
#ifndef LWIP_DBG_MIN_LEVEL
#define LWIP_DBG_MIN_LEVEL              LWIP_DBG_LEVEL_ALL
#endif#ifndef LWIP_DBG_TYPES_ON
#define LWIP_DBG_TYPES_ON               LWIP_DBG_ON
#endif

А это
Цитата
и устанавливаете в опциях пректа флажек "include semihosting interfice",
не нашел.
Пользуюсь J-Link 8
kan35
Я бы не парился с этим режимом.
лучше напишите свой putchar и гоните в свободный UART, их у вас все таки 5
Acvarif
Цитата(kan35 @ Jan 18 2012, 11:11) *
Я бы не парился с этим режимом.
лучше напишите свой putchar и гоните в свободный UART, их у вас все таки 5

Да я бы рад. LwIP определяет это так
CODE
#ifdef LWIP_DEBUG
/** print debug message only if debug message type is enabled...
* AND is of correct type AND is at least LWIP_DBG_LEVEL
*/
#define LWIP_PLATFORM_DIAG printf
#define LWIP_DEBUGF(debug, message) do { \
if ( \
((debug) & LWIP_DBG_ON) && \
((debug) & LWIP_DBG_TYPES_ON) && \
((s16_t)((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL)) { \
LWIP_PLATFORM_DIAG message; \
if ((debug) & LWIP_DBG_HALT) { \
while(1); \
} \
} \
} while(0)

#else /* LWIP_DEBUG */
#define LWIP_DEBUGF(debug, message)
#endif /* LWIP_DEBUG */

Получается определяет функцию для выдачи сообщений
Как к ней приладить свой putchar?
kan35
Все верно у тебя сделано.

Чтобы printf куда-то выводил строки, надо ему дать через что, вот putchar и есть это "что", пиши свою ф-ю по типу:
int putchar (int);
В ней просто вываливай байт в последовательный порт
MALLOY2
Цитата
Получается определяет функцию для выдачи сообщений
Как к ней приладить свой putchar?


Все это делается в файле "сс.h"

Вот мой

CODE
#ifndef __CCT_H__
#define __CCT_H__

#include <stdint.h>
#include <intrinsics.h>
#include "mk_heap.h"

#ifdef __cplusplus
extern "C"
{
#endif

extern void dev_debugf(const char *args, ...);
#define LWIP_PLATFORM_ASSERT(x) do \
{dev_debugf("Assertion \"%s\" failed at line %d in %s\r", x, __LINE__, __FILE__);} \
while(0)
#define LWIP_PLATFORM_DIAG(x) {dev_debugf x;}

#define LWIP_NOASSERT
#define LWIP_DEBUG
#define ETHERNET_CHECKSUM_BY_HARDWARE
#define PACK_STRUCT_USE_INCLUDES

#define PACK_STRUCT_STRUCT
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x

#define BYTE_ORDER LITTLE_ENDIAN
#define LWIP_PLATFORM_BYTESWAP 1

#if LWIP_PLATFORM_BYTESWAP
#define LWIP_PLATFORM_HTONS(x) __REV16(x)
#define LWIP_PLATFORM_NTONS(x) __REV16(x)
#define LWIP_PLATFORM_HTONL(x) __REV(x)
#define LWIP_PLATFORM_NTONL(x) __REV(x)
#endif

#define mem_free mk_free

#define mem_malloc mk_malloc

#define mem_calloc mk_calloc

#define LWIP_ERR_T int32_t

#define U16_F "u"
#define S16_F "d"
#define X16_F "x"
#define U32_F "lu"
#define S32_F "ld"
#define X32_F "lx"

typedef uint8_t u8_t;
typedef int8_t s8_t;
typedef uint16_t u16_t;
typedef int16_t s16_t;
typedef uint32_t u32_t;
typedef int32_t s32_t;
typedef uint64_t u64_t;
typedef int64_t s64_t;
typedef u32_t mem_ptr_t;

typedef uint32_t sys_prot_t;

#ifdef __cplusplus
}
#endif

#endif


Сдесь функция dev_debugf это моя функция вывода в уарт.
=F8=
Цитата(Acvarif @ Jan 18 2012, 10:40) *
А это не нашел.
Пользуюсь J-Link 8

Извиняюсь, дал названия из eclipse. Непосредственно в IARе: Project->Option->General Option->Library Configuration->Library Low-level interface impletation ->Переключаете в в режим Semihosted и stdout/stderr в режим Via SWO. Если отлаживаете через JTAG, а не через SWD то режим Via SWO естественно недоступен. IAR 6.21.
Цитата
Я бы не парился с этим режимом. лучше напишите свой putchar и гоните в свободный UART, их у вас все таки 5

При наличии J-Linkа поддерживающего SWD и контроллера с SWD такой возможностью грех не воспользоватся. Уже давно на кортексах все отладочные сообщения вывожу именно через отладчик.
А с UARTом не так все просто. Если в putchar тупо кидать данные в UART то, например при выводе более-менее приличного обема данных в прерывании есть шанс пропустить другое прерывание, это в худшем случае, но даже без этого вывод через UART без буфферизации занимает слишком много времени.
Acvarif
Цитата(=F8= @ Jan 18 2012, 14:25) *
Извиняюсь, дал названия из eclipse. Непосредственно в IARе: Project->Option->General Option->Library Configuration->Library Low-level interface impletation ->Переключаете в в режим Semihosted и stdout/stderr в режим Via SWO. Если отлаживаете через JTAG, а не через SWD то режим Via SWO естественно недоступен. IAR 6.21.

Все сделал. Тоже в IAR 6.21
oph.h
Код
/**
* API_LIB_DEBUG: Enable debugging in api_lib.c.
*/
#ifndef API_LIB_DEBUG
#define API_LIB_DEBUG                   LWIP_DBG_OFF
#endif

Хотя файл защищен от записи. Пришлось изменить ему атрибуты и вместо LWIP_DBG_OFF написать LWIP_DBG_ON
Отладчик запустился с появлением зеленой кнопки SWO, но сообщений пока на терминале нет. Хотя в api_lib.c есть что выводить на терминал
Может еще что нужно сделать ON для того, чтобы увидеть работу терминала при работе стека?
=F8=
Прежде всего нужно переопределить макрос LWIP_DBG_TYPES_ON с LWIP_DBG_OFF на LWIP_DBG_ON - это глобальное разрешение выдачи отладочных сообщение. Затем макросом LWIP_DBG_MIN_LEVEL регулируем что именно мы хотим получать - все(LWIP_DBG_LEVEL_ALL), предупреждения(LWIP_DBG_LEVEL_WARNING) или ошибки (LWIP_DBG_LEVEL_SERIOUS).
После с помощью макросов ETHARP_DEBUG, NETIF_DEBUG, PBUF_DEBUG...... в том числе API_LIB_DEBUG указывеме из каких модулей вы хотите получать сообщения( например API_LIB_DEBUG управляет отладочными сообщенияим из модуля api_lib.c).
PS Для проверки добавте в main что-небудь вроде printf("test\r\n"); если с настройками собственно отладочных сообщений все в норме то при запуске увидите в терминале "test".
Acvarif
Сделано так
LWIP_DBG_ON
LWIP_DBG_LEVEL_ALL
CODE
/**
* UDP_DEBUG: Enable debugging in UDP.
*/
#ifndef UDP_DEBUG
#define UDP_DEBUG LWIP_DBG_ON
#endif
.....
/**
* UDP_DEBUG: Enable debugging in UDP.
*/
#ifndef UDP_DEBUG
#define UDP_DEBUG LWIP_DBG_ON
#endif


В функцию мигания светодиодом и посылки UDP пакетов добавлено printf("test\r\n");
Код
        ........
        /* toggle LED1 each 250ms */
        STM_EVAL_LEDToggle(LED1);
        vTaskDelay(1000);
        printf("test\r\n");
        ..............

Не получается застревает на
Код
void HardFault_Handler(void)
{
  /* Go to infinite loop when Hard Fault exception occurs */
  while (1)
  {
  }
}

Восстанавливается если убрать printf("test\r\n");
=F8=
Глубина стека в задаче какая? printf довольно стекожрущая процедура. Отлаживаете точно через SWD?
PS если нет ничего военного выложите куда-небуть весь проект.
Acvarif
Цитата(=F8= @ Jan 18 2012, 18:56) *
Глубина стека в задаче какая? printf довольно стекожрущая процедура. Отлаживаете точно через SWD?
PS если нет ничего военного выложите куда-небуть весь проект.

Вроде через SWD (J-link v8 от starterkit) + платка от того же starterkit SK-STM32F217
Проект (Iar Arm 6.21) не военный, пока только тест на базе демки от st, для оценки возможностей FreeRTOS + LwIP + UDP. Находится тут http://depositfiles.com/files/aulnju494
В проекте закомментил все потоки кроме одного, в котором выдается 100 UDP пакетов по 255 байт в каждом один раз в секунду и при этом мигают 2 светодиода. Для консоли все настройки выставил.
1. Не пойму почему не позволяется создавать пакет больше 300 (с хвостиком) байт (поток виснет).
2. Никак не получается померять скорость Судя по времени за которое прокручивается выдача 25 000 байт (10 мс) получается 20 Mbits/s Маловато будет. Но очевидно так мерять не орректно. А iperf вооще показывает 0.2 Mbits/s Не пойму где тут собака порылась.
=F8=
Чтоб появились сообшения в настройках проекта укажите правильно частоту на которой работает контроллер Project->Option->J-Link/j-trace->Clock Setup->CPU Clock установить 120 MHz, SWO clock или оставить как есть или переключить в "Auto".
Acvarif
Цитата(=F8= @ Jan 19 2012, 13:14) *
Чтоб появились сообшения в настройках проекта укажите правильно частоту на которой работает контроллер Project->Option->J-Link/j-trace->Clock Setup->CPU Clock установить 120 MHz, SWO clock или оставить как есть или переключить в "Auto".

Большое спасибо. Работает.
Посоветуйте пожалуйста, что в opt.h нужно сделать ON для контроля работы netconn.
Может сталкивались - не получается посылать UDP пакеты размером > 300 байт (#define SIZE 355)
Поток застревает на
Код
/* create a new connection */
connn = netconn_new(NETCONN_UDP);

После команды Break поток оказывается на
Код
void HardFault_Handler(void)
{
  /* Go to infinite loop when Hard Fault exception occurs */
  while (1)
  {
  }
}
=F8=
Посмотрел код.....
1 Вы обявляете локальную переменную char text1[SIZE]; размером в 255 байт, при этом размер стека у потока configMINIMAL_STACK_SIZE 128 * 4 = 512 байт. т.е. одна локальная переменная съедает мол стека. Оставшихся 64 слов хватает едава едава. Отсюда и зависания при вызове printf и невозможность увеличить SIZE.
2 разберитесь с назначением функций netbuf_alloc и netbuf_ref. А то у вас пулучается что сначала вы с помощью data1 = netbuf_alloc(buf1, sizeof(text1)); создаете новый буфер в buf1, затем с помощью netbuf_ref(buf1, text1, sizeof(text1)); прикрепляете к buf1 буффер text1. Что при этом происходит с предварительно выделеным буфером - х.з.
ниже привел исправленный код, у меня с ним, правда с MII интерфейсом(RTL8201) получается скорость около 90-95Mbit
CODE
#define SIZE 1000
void ToggleLed4(void * pvParameters)
{
struct netconn *connn;
struct netbuf *buf1;
struct ip_addr addr;
static char text1[SIZE];//!!!! Буфер объявлен как static

memset(text1, 0x55, SIZE);
// create a new connection
connn = netconn_new(NETCONN_UDP);
// set up the IP address of the remote host
IP4_ADDR(&addr, 192, 168, 0, 18);//Не забудте исправить IP
// connect the connection to the remote host
netconn_connect(connn, &addr, 7);
// create a new netbuf
buf1 = netbuf_new();

while(1)
{
vTaskDelay(1000);

test = xnetif.ip_addr.addr;
//check if IP address assigned
if (test !=0)
{
for(;; )
{
// toggle LED1 each 1000ms
STM_EVAL_LEDToggle(LED1);
//vTaskDelay(1000);
//printf("test\r\n");

STM_EVAL_LEDOn(LED2);
for(int j = 0; j < 10000; j++)
{
netbuf_ref(buf1, text1, sizeof(text1));
netconn_send(connn, buf1);
}
STM_EVAL_LEDOff(LED2);
}
}
}
}
Acvarif
Цитата(=F8= @ Jan 19 2012, 16:04) *
Посмотрел код.....
1 Вы обявляете локальную переменную char text1[SIZE]; размером в 255 байт, при этом размер стека у потока configMINIMAL_STACK_SIZE 128 * 4 = 512 байт. т.е. одна локальная переменная съедает мол стека. Оставшихся 64 слов хватает едава едава. Отсюда и зависания при вызове printf и невозможность увеличить SIZE.
2 разберитесь с назначением функций netbuf_alloc и netbuf_ref. А то у вас пулучается что сначала вы с помощью data1 = netbuf_alloc(buf1, sizeof(text1)); создаете новый буфер в buf1, затем с помощью netbuf_ref(buf1, text1, sizeof(text1)); прикрепляете к buf1 буффер text1. Что при этом происходит с предварительно выделеным буфером - х.з.


Большое спасибо.
Все заработало.
Виноват. Совсем вылетело, что у ОС свой стек у каждого потока. А локалка заседает в стеке. Надо будет с FreeRTOS поразбираться. До сего времени использовал только scmRTOS
Про функции буду читать мануал.
Со скоростью пока не понятно. Perf показывает ~13 Mbits/s

Или я не врубился как мерять или что то не так с инициализацией MAC+RMII на нужной скорости или со скоростью камня что то не так

=F8=
А размер пакета(SIZE) увеличить не забыли? От этого скорость очень сильно зависит.
SIZE = 250
Нажмите для просмотра прикрепленного файла
SIZE = 1400
Нажмите для просмотра прикрепленного файла
Acvarif
Цитата(=F8= @ Jan 19 2012, 17:50) *
А размер пакета(SIZE) увеличить не забыли? От этого скорость очень сильно зависит.

Да, все сделал. Спасибо.
Сначала не врубился. Теперь все прояснилось. Режим отладки нужно выключить (LWIP_DBG_OFF). Тормозит однако.
Получилось так
Нажмите для просмотра прикрепленного файла
Acvarif
Касательно этой темы:

1. Удержит ли LwIP+FreeRtos скорость ~90 если FreeRtos будет иметь еще 2...3 потока. Например работа с ADC, DAC, цифровая обработка сигналов с ADC?
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.