Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32F217 & LwIP 1.3.2
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
ReRayne
Имеем плату starterkit STM32F217.
Ethernet PHY: KSZ8721BL.
С сайта STM взят вот этот пример с реализацией LwIp 1.3.2.
Запускаем, начинаем пинговать плату.
Все окей, она радостно нам отвечает с пингами <=1мс.
Потом в один прекрасный момент, рандомно, пинги начинают съезжать 400-2000мс.
В конце концов через несколько часов пинга плата перестает отвечать вообще.
При этом весьма забавен тот факт, если с другой машины начинать флудить пингом, то пинги станвятся нормальными 1-40мс.
Отключаешь флуд, снова съезжают пинги.

Собственно, меняли только настройки драйвера. Изменения отмечены жирным.
stm32f2x7_eth_bsp.c
CODE

#define CHECKSUM_BY_HARDWARE 1

/*...................*/

void ETH_BSP_Config(void)
{
/* Configure the GPIO ports for ethernet pins */
ETH_GPIO_Config();

/* Config NVIC for Ethernet */
ETH_NVIC_Config();

/* Configure the Ethernet MAC/DMA */
ETH_MACDMA_Config();

/* if (EthInitStatus == 0)
{
LCD_SetTextColor(Red);
LCD_DisplayStringLine(Line5, (uint8_t*)" Ethernet Init ");
LCD_DisplayStringLine(Line6, (uint8_t*)" failed ");
while(1);
}*/

/* Configure the PHY to generate an interrupt on change of link status */
// Eth_Link_PHYITConfig(DP83848_PHY_ADDRESS);

/* Configure the EXTI for Ethernet link status. */
// Eth_Link_EXTIConfig();

}

void ETH_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

/* Enable GPIOs clocks */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB |
RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOI |
RCC_AHB1Periph_GPIOG | RCC_AHB1Periph_GPIOH |
RCC_AHB1Periph_GPIOF, ENABLE);

/* Enable SYSCFG clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);

/* Configure MCO (PA8) */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOA, &GPIO_InitStructure);


/* MII/RMII Media interface selection --------------------------------------*/
#ifdef MII_MODE /* Mode MII with STM322xG-EVAL */
#ifdef PHY_CLOCK_MCO

/* Output HSE clock (25MHz) on MCO pin (PA8) to clock the PHY */
RCC_MCO1Config(RCC_MCO1Source_HSE, RCC_MCO1Div_1);
#endif /* PHY_CLOCK_MCO */

SYSCFG_ETH_MediaInterfaceConfig(SYSCFG_ETH_MediaInterface_MII);
#elif defined RMII_MODE /* Mode RMII with STM322xG-EVAL *///!

/* Output PLL clock divided by 2 (50MHz) on MCO pin (PA8) to clock the PHY */
RCC_MCO1Config(RCC_MCO1Source_PLLCLK, RCC_MCO1Div_2);

SYSCFG_ETH_MediaInterfaceConfig(SYSCFG_ETH_MediaInterface_RMII);
SYSCFG_CompensationCellCmd(ENABLE);
#endif

/* Configure PA1, PA2 and PA7 */
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource1, GPIO_AF_ETH);

GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_ETH);

GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_ETH);

/* Configure PC1, PC4 and PC5 */
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource4, GPIO_AF_ETH);

GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource5, GPIO_AF_ETH);

GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource1, GPIO_AF_ETH);

/* Configure PG14 and PG13 */
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOG, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOG, GPIO_PinSource13, GPIO_AF_ETH);
GPIO_PinAFConfig(GPIOG, GPIO_PinSource14, GPIO_AF_ETH);

/* Configure PB11 */
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_ETH);


}


system_stm32f2xx.c
Код
uint32_t SystemCoreClock = 100000000;
unkier
не все примеры от ST одинаково полезны.
Lexy_one
К сожелению с STM32F217 не работал... Но Имел дело с примерами для LPC23XX...
И как оказалось в примерах очень много багов (даже в официальных примерах)...
Посоветовал бы вам или досконально изучить пример, и попытаться повылавливать там баги, или написать свой драйвер.... Вот например на моей плате время пингов не превышает 3мс (в зависимости от загруженности программы) - а драйвер использую свой ( пришлось самому писать, так как в примерах то функционал слабенький, то глюки подобные описанному вами).
ReRayne
unkier, Lexy_one, да, глюки в самом драйвере к порту LwIP.
На форуме STM мне подсказали решение проблемы с пингами:
CODE

void ethernetif_input(void * pvParameters)
{
struct pbuf *p;

for( ;; )
{
if(xSemaphoreTake(s_xSemaphore, emacBLOCK_TIME_WAITING_FOR_INPUT)==pdTRUE)
{
GET_NEXT_FRAGMENT:
p = low_level_input( s_pxNetIf );
if (p != NULL)
{
if (ERR_OK != s_pxNetIf->input( p, s_pxNetIf))
{
pbuf_free(p);
p=NULL;
}
else
{
xSemaphoreTake(s_xSemaphore, 0);
goto GET_NEXT_FRAGMENT;
}
}
}
}
}


Но я тут же отловила еще один косяк в static void tcpip_thread(void *arg) в этом куске кода:
CODE

#if LWIP_ARP
if (msg->msg.inp.netif->flags & NETIF_FLAG_ETHARP)
{
ethernet_input(msg->msg.inp.p, msg->msg.inp.netif);
}

Адрес параметра почему-то msg->msg.inp.p = 0x23 => CPU hardfault. После 2Гб пингов.
scifi
Цитата(ReRayne @ Mar 5 2012, 15:07) *
Виноваты глюки самого LwIP.

Не надо катить бочку на lwip. Это творчество либо FreeRTOS, либо ST. Сделать глюкавый драйвер для lwip - проще простого.
=F8=
Уже час пингую STM32F207+RTL8201 с LwIP. Пример тот, что указан ТС с минимальными переделками. Проблем не обнаружил. Хотя драйвер таки немного кривоват - если перполняеся приемный буффер(который Rx_Buff в stm32f2x7_eth.c) то все. Не так чтоб зависает, но и нормально не работает. Ситуация при нормальной работе почти не реальная, но отладку осложняет.
ReRayne
А ни у кого не пробегал стабильный драйвер для LwIP? Или самой писать?)
Откуда в msg->msg.inp.p берется указатель на 0х23 ума не приложу.

scifi, беру свои слова назад, действительно косым оказался драйвер для LwIP под STM.
=F8=, плата стоять может очень долго. У меня последний раз под флудом пакетами 1024 байта она выстояла 19Гб, потом перестала отвечать. Я попробовала пропинговать ее пакетами по 32 байта. Плата отвечала еще некоторое время, а потом тоже перестала. При этом Hard Fault не произошел и ресив остановился по иной причине.
По поводу RxBuff, я так понимаю, надо добавить обработку переполнения?
scifi
Цитата(ReRayne @ Mar 7 2012, 12:05) *
А ни у кого не пробегал стабильный драйвер для LwIP? Или самой писать?

Кстати, для общего развития было бы невредно и написать.
У меня простейший драйвер вышел всего на 200 строк. Правда, это для uIP. Но при некоторой сноровке он легко прикручивается к lwip.
Ethernet MAC в STM32 порадовал: понятный, разумный, функциональный, значения регистров по умолчанию вменяемые.
CODE
/**
* @file stm32eth.h
* @brief Драйвер Ethernet для STM32
*/

#include "stm32eth.h"
#include "stm32f2regs.h"
#include "timer.h"
#include "net/uip.h"
#include <string.h>

#define SMI_TMPL 0x00000004 /* sets SMI clock range and PHY address */
#define RX_BUF_SIZE 256
#define RX_RING_SIZE 32

static bool link, act;
/* the only TX descriptor used in this program */
static uint32_t volatile tx_desc[4] = { 0, 0, (uint32_t)uip_buf, 0 };
static uint32_t volatile rx_desc[RX_RING_SIZE][4];
static uint8_t volatile rx_buf[RX_RING_SIZE][RX_BUF_SIZE];
/* first descriptor in frame, next descriptor to check */
static unsigned int rx_first, rx_cur;

static bool
smi_busy(void)
{
return (ETH_MACMIIAR & 1) != 0;
}

static void
smi_write(int reg, int val)
{
ETH_MACMIIDR = val;
ETH_MACMIIAR = (reg << 6) | SMI_TMPL | 3;
while (smi_busy())
{
/* wait */
}
}

static void
smi_start_read(int reg)
{
ETH_MACMIIAR = (reg << 6) | SMI_TMPL | 1;
}

static int
smi_read_data(void)
{
return ETH_MACMIIDR;
}

static void
phy_init(void)
{
smi_write(0, 0x1100);
smi_write(4, 0x0021);/* auto-negotiate 10Mb half-duplex only */
}

static void
fill_rx_desc(void)
{
int i;
for (i = 0; i < RX_RING_SIZE; i++)
{
rx_desc[i][0] = (1u << 31); /* OWN bit */
rx_desc[i][1] = RX_BUF_SIZE;
rx_desc[i][2] = (uint32_t)&rx_buf[i];
}
rx_desc[RX_RING_SIZE - 1][1] |= (1 << 15); /* end of ring */
}

void
stm32eth_init(void)
{
/* enable clocking of MAC core, ports A, B, C */
RCC_AHB1ENR |= 0x1E000007;
fill_rx_desc();
GPIOA_AFRL |= 0xB000BBBB;
GPIOB_AFRL |= 0x000000BB;
GPIOB_AFRH |= 0x00BBBB0B;
GPIOC_AFRL |= 0x00BBBBB0;
GPIOA_MODER |= 0x000080AA;
GPIOB_MODER |= 0x0AA2000A;
GPIOC_MODER |= 0x00000AA8;
timer_delay(TIMER_TPS / 1000);
ETH_DMATDLAR = (uint32_t)&tx_desc;
ETH_DMARDLAR = (uint32_t)&rx_desc;
ETH_MACCR = (1 << 16) /* disable carrier sense */
| (1 << 3) /* enable transmitter */
| (1 << 2);/* enable receiver */
ETH_DMAOMR = (1 << 21) /* transmit store and forward */
| (1 << 13) /* start transmission */
| (1 << 1);/* start reception */
phy_init();
smi_start_read(1);
}

void
stm32eth_setmac(const uint8_t mac[6])
{
ETH_MACA0LR = *(uint32_t*)mac;
ETH_MACA0HR = *(uint16_t*)(mac + 4);
}

static void
collect_frame(void)
{
int i, remlen;
uint8_t *dst = uip_buf;
remlen = (rx_desc[rx_cur & (RX_RING_SIZE - 1)][0] & 0x3FFF0000) >> 16;
uip_len = remlen;
for (i = rx_first; i <= rx_cur; i++)
{
int len;
len = (i != rx_cur) ? RX_BUF_SIZE : remlen;
memcpy(dst, (void*)rx_buf[i & (RX_RING_SIZE - 1)], len);
dst += len;
remlen -= len;
}
}

static void
reinit_rx_desc(void)
{
unsigned int i;
for (i = rx_cur; i != (rx_first - 1); i--)
{
rx_desc[i & (RX_RING_SIZE - 1)][0] = 1u << 31; /* OWN bit */
}
}

static void
rx_poll(void)
{
uint32_t status;
status = rx_desc[rx_cur & (RX_RING_SIZE - 1)][0];
if (status & (1u << 31)) /* OWN bit */
{
return;
}
if (status & (1 << 9)) /* first segment */
{
rx_first = rx_cur;
}
if (status & (1 << 8)) /* last segment */
{
if ((status & 0x4000F89F) == 0) /* error bits */
{
collect_frame();
}
reinit_rx_desc();
}
rx_cur++;
}

void
stm32eth_poll(void)
{
static timer_value prev;
timer_value now;
now = timer_getval();
if (timer_ticksbetween(prev, now) > TIMER_TPS / 100)
{
link = !!(smi_read_data() & 4);
smi_start_read(1);
prev = now;
}
rx_poll();
}

void
stm32eth_send(void)
{
tx_desc[1] = uip_len;
tx_desc[0] = (1u << 31) /* OWN bit */
| (1 << 29) /* last segment */
| (1 << 28) /* first segment */
| (1 << 21);/* end of ring */
ETH_DMATPDR = 0; /* start transmission */
while (tx_desc[0] & (1u << 31))
{
/* wait until TX descriptor is released */
}
}

bool
stm32eth_link(void)
{
return link;
}

bool
stm32eth_act(void)
{
bool ret;
ret = act;
act = false;
return ret;
}
=F8=
Цитата(ReRayne @ Mar 7 2012, 11:05) *
По поводу RxBuff, я так понимаю, надо добавить обработку переполнения?


Да, добавил в low_level_input(в принципе можно куда угодно) строку if(ETH->DMASR & (1<<7)) NVIC_SystemReset(); Но это, конечно, лечение головной боли отрубанием головы. По хорошему надо покорректней, без сброса.
ReRayne
scifi, спасибо!)
=F8=, мне такое не подходит, увы, а в доке не могу найти как правильно переинициализировать буфер DMA =(
Вообще в low_level_input есть следующий код для переполнения:
CODE

/* When Rx Buffer unavailable flag is set: clear it and resume reception */
if ((ETH->DMASR & ETH_DMASR_RBUS) != (u32)RESET)
{
/* Clear RBUS ETHERNET DMA flag */
ETH->DMASR = ETH_DMASR_RBUS;

/* Resume DMA reception */
ETH->DMARPDR = 0;
}
shreck
Добрый день.

Чем закончилась эта история?
Удалось "причесать" драйвер eth и порт lwIP?
Может еще какие блохи всплыли в коде?

Интересуюсь потому, что сам недавно начал пытаться запустить эту связку lwIP+ST32F207. Собираю информацию.
unkier
Цитата(shreck @ Aug 16 2012, 08:23) *
Добрый день.

Чем закончилась эта история?
Удалось "причесать" драйвер eth и порт lwIP?
Может еще какие блохи всплыли в коде?

Интересуюсь потому, что сам недавно начал пытаться запустить эту связку lwIP+ST32F207. Собираю информацию.


камень 407. всё отлично.
IXUS666
Здесь решили проблемму переполнения буффера при отладке http://lists.gnu.org/archive/html/lwip-use...9/msg00053.html
Цитата(ReRayne @ Mar 9 2012, 17:09) *
scifi, спасибо!)
=F8=, мне такое не подходит, увы, а в доке не могу найти как правильно переинициализировать буфер DMA =(
Вообще в low_level_input есть следующий код для переполнения:
CODE

/* When Rx Buffer unavailable flag is set: clear it and resume reception */
if ((ETH->DMASR & ETH_DMASR_RBUS) != (u32)RESET)
{
/* Clear RBUS ETHERNET DMA flag */
ETH->DMASR = ETH_DMASR_RBUS;

/* Resume DMA reception */
ETH->DMARPDR = 0;
}

athlon64
У меня очередная проблема с этой демкой.
Утекает память буфера PBUF. Через пару часов контроллер перестаёт отвечать.
Сталкивался кто-нибудь?

Ну и в HardFault периодически попадаю (раз в несколько часов непрерывного опроса). Судя по регистрам, исключение происходит в момент переключения задач, последняя активная задача при этом Eth_if.
Мусатов Константин
Прошло много времени. Не удалось ли решить проблему?
У меня на похожем проекте на STM32F207VET+RTL8201 c FreeRTOS 8.2 + LwIP 1.4.0 происходит падучесть или через HardFault или через переполнение стека в контроле при переключении задач (vTaskSwitchContext) у несуществующей задачи. При этом стеки существующих задач в порядке и имеют большой запас по использованной длине. А указатель смотрит на то место, где скоро должна появиться новая задача, но эта область еще не очищена. Процедуру создания задачи проверил, там критическая область корректно определена. Происходит этот бардак при приходе IP пакета. Причем пинг не приводит к падению. Вероятность падения сильно растет с повышением скорости обмена. Т.е. если на ftp сервер лезть руками через утилиту ftp, то живется заметно лучше, чем через ftp клиента в far или проводник.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.