Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32F2 Ethernet
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
pitt
Изучаю документацию и примеры кода. Комментарии непечатные. Не желает ли кто-нибудь поделиться собственной наработкой или дать ссылку на профессиоально сделаный код/пример.

Спасибо
pitt
Цитата(pitt @ Nov 23 2012, 12:22) *
Изучаю документацию и примеры кода. Комментарии непечатные. Не желает ли кто-нибудь поделиться собственной наработкой или дать ссылку на профессиоально сделаный код/пример.

Спасибо

Глупый, наверное, вопрос: Когда приложение шлет посылку на МАС, код копирует ее из памяти приложения в буфер DMA, который затем в фоновом режиме копирует дальше в собственно МАС. А почему нельзя DMA изначально направить на память приложения без дополнительной пересылки?

Спасибо.
scifi
Цитата(pitt @ Nov 24 2012, 18:25) *
А почему нельзя DMA изначально направить на память приложения без дополнительной пересылки?

Zero-copy transmission? Можно, я так и делаю:

CODE
/**
* @file stm32eth.c
* @brief Драйвер Ethernet для STM32
*/

#include "stm32eth.h"
#include "stm32f2regs.h"
#include "timer.h"
#include "netif/etharp.h"
#include "lwip/mem.h"
#include "lwip/memp.h"
#include "assert_static.h"
#include <string.h>
#include <assert.h>

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

struct buf_desc
{
uint32_t volatile status;
uint16_t len[2];
void* ptr[2];
struct pbuf* p[2];
};

static struct netif *mynetif;
static bool link, act;
static bool rx_more; /* if set, need to scan or allocate RX descriptors */
static struct buf_desc tx_desc[TX_RING_SIZE], rx_desc[RX_RING_SIZE];
/* first RX descriptor to check for new frame */
static int rx_current;
/* number of initialized RX descriptors */
static int rx_count;

static bool
smi_busy(void)
{
return !!REGBIT(ETH_MACMIIAR, 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, 0);
smi_write(0x1F, 0x8900);
}

static err_t
low_level_output(struct netif *netif, struct pbuf *p)
{
int i;
uint32_t mask;

while ((ETH_DMASR & 0x00700000) != 0x00600000)
{
/* wait until Tx DMA is suspended */
}
mask = (1u << 31) /* OWN bit */
| (1 << 28); /* first segment */
i = -1;
for (;;)
{
i++;
if (i == TX_RING_SIZE)
{
/* not enough TX descriptors */
return ERR_MEM;
}
tx_desc[i].len[0] = p->len;
tx_desc[i].ptr[0] = p->payload;
p = p->next;
if (p)
{
tx_desc[i].len[1] = p->len;
tx_desc[i].ptr[1] = p->payload;
p = p->next;
if (p)
{
tx_desc[i].status = mask;
mask = (1u << 31); /* OWN bit */
}
else
{
break;
}
}
else
{
tx_desc[i].len[1] = 0;
break;
}
}
mask |= (1 << 21) /* end of ring */
| (1 << 29); /* last segment */
tx_desc[i].status = mask;
REGBIT(ETH_DMASR, 10) = 1; /* reset ETS flag in status register */
ETH_DMATPDR = 0; /* start transmission */
while (REGBIT(ETH_DMASR, 10) == 0)
{
/* wait for data to be copied into Tx FIFO */
}
act = true;
return ERR_OK;
}

/**
* Initialize the Rx buffer descriptor ring by allocating buffers
* and assigning them to descriptors
*/
static void
rx_setup(void)
{
/* Index of first uninitialized Rx buffer descriptor */
int i, rx_start = rx_current + rx_count;
for (i = rx_start; rx_count < RX_RING_SIZE; i++)
{
struct pbuf *p;
int j = i & (RX_RING_SIZE - 1);
p = pbuf_alloc(PBUF_RAW, PBUF_POOL_BUFSIZE, PBUF_POOL);
if (!p)
{
rx_more = true;
break;
}
rx_desc[j].p[0] = p;
rx_desc[j].ptr[0] = p->payload;
rx_desc[j].len[0] = p->len;
if (j == (RX_RING_SIZE - 1))
{
rx_desc[j].len[0] |= (1 << 15);
}
rx_count++;
p = pbuf_alloc(PBUF_RAW, PBUF_POOL_BUFSIZE, PBUF_POOL);
if (p)
{
rx_desc[j].p[1] = p;
rx_desc[j].ptr[1] = p->payload;
rx_desc[j].len[1] = p->len;
}
else
{
rx_desc[j].len[1] = 0;
rx_more = true;
}
rx_desc[j].status = 1u << 31; /* OWN bit */
}
i = rx_current + rx_count;
while (i != rx_start)
{
i--;
rx_desc[i & (RX_RING_SIZE - 1)].status = 1u << 31; /* OWN bit */
}
}

/**
* Discard frame in case of reception error by deallocating buffers
*
* @param first Index of first buffer descriptor to discard
* @param last Index of last buffer descriptor to discard
*/
static void
discard_frame(int first, int last)
{
int i = first - 1;
do
{
i = (i + 1) & (RX_RING_SIZE - 1);
pbuf_free(rx_desc[i].p[0]);
if (rx_desc[i].len[1] != 0)
{
pbuf_free(rx_desc[i].p[1]);
}
}
while (i != last);
/* Keep index in sync with Rx DMA */
rx_current = (last + 1) & (RX_RING_SIZE - 1);
}

/**
* Collect frame by chaining the corresponding pbufs
*
* @param first Index of first buffer descriptor to collect
* @param last Index of last buffer descriptor to collect
* @param lastlen Length of last buffer in chain
*/
static struct pbuf*
collect_frame(int first, int last, int lastlen)
{
unsigned int i;
struct pbuf *h, *t;

/* Trim last buffer, so complete frame length is correct */
if (rx_desc[last].len[1] != 0)
{
t = rx_desc[last].p[1];
pbuf_realloc(t, lastlen);
h = rx_desc[last].p[0];
pbuf_cat(h, t);
t = h;
}
else
{
t = rx_desc[last].p[0];
pbuf_realloc(t, lastlen);
}
/* Walk the buffers from (last - 1) to first */
i = last;
while (i != first)
{
i = (i - 1) & (RX_RING_SIZE - 1);
h = rx_desc[i].p[1];
pbuf_cat(h, t);
t = h;
h = rx_desc[i].p[0];
pbuf_cat(h, t);
t = h;
}
/* Keep index in sync with Rx DMA */
rx_current = (last + 1) & (RX_RING_SIZE - 1);
return t;
}

/**
* Zero-copy reception. Collect DMA'ed data and return frame as pbuf chain.
*
* @return a pbuf filled with the received packet (including MAC header)
* NULL if no received frames
*/
static struct pbuf*
low_level_input(void)
{
int i, n, len0, len, lastlen, status;

i = rx_current;
len = 0;
n = 0;
/* Scan the Rx buffer rescriptor ring */
for (;;)
{
if (i == (rx_current + rx_count))
{
/* Descriptor uninitialized, quit */
return 0;
}
status = rx_desc[i].status;
if (status & (1u << 31))
{
/* Buffer still owned by DMA, quit */
rx_more = false;
return 0;
}
/* Buffer contains frame data, continue */
n++;
len0 = rx_desc[i].len[0] & 0x1FFF;
if (status & (1 << 8))
{
/* Last buffer in frame, finalize */
break;
}
len += len0;
len += rx_desc[i].len[1];
i = (i + 1) & (RX_RING_SIZE - 1);
/* Move on to next buffer in frame */
}
/* Mark processed descriptors as uninitialized */
rx_count -= n;
if ((status & 0x4000F89F) != 0) /* error bits */
{
discard_frame(rx_current, i);
return 0;
}
lastlen = ((status >> 16) & 0x3FFF) - len;
if (lastlen <= len0)
{
if (rx_desc[i].len[1] != 0)
{
pbuf_free(rx_desc[i].p[1]);
rx_desc[i].len[1] = 0;
}
}
else
{
lastlen -= len0;
}
return collect_frame(rx_current, i, lastlen);
}

err_t
stm32eth_init(struct netif *netif)
{
assert_static(IS_PWR_OF_TWO(RX_RING_SIZE));
assert_static(IS_PWR_OF_TWO(TX_RING_SIZE));
mynetif = netif;
netif->name[0] = 'e';
netif->name[1] = 'n';
netif->hwaddr_len = ETHARP_HWADDR_LEN;
netif->mtu = 1500;
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
netif->output = etharp_output;
netif->linkoutput = low_level_output;
/* enable clocking of MAC core, ports A, B, C */
RCC_AHB1ENR |= 0x1E000007;
rx_setup();
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_MACA0LR = *(uint32_t*)netif->hwaddr;
ETH_MACA0HR = *(uint16_t*)(netif->hwaddr + 4);
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_DMABMR |= (2 << 2); /* descriptor skip length = 2 */
ETH_DMAOMR = (1 << 21) /* transmit store and forward */
| (1 << 13) /* start transmission */
| (1 << 1);/* start reception */
phy_init();
smi_start_read(0x1F);
return ERR_OK;
}

void
stm32eth_poll(void)
{
static unsigned int prev;
unsigned int now;
now = timer_get();
if (now - prev > TIMER_TPS / 50)
{
link = !!(smi_read_data() & (1 << 12));
smi_start_read(0x1F);
prev = now;
}
if (REGBIT(ETH_DMASR, 6))
{
/* RS bit set: complete frame received */
REGBIT(ETH_DMASR, 6) = 1; /* clear RS bit */
rx_more = true;
}
if (rx_more)
{
struct pbuf *p;
p = low_level_input();
if (p)
{
ethernet_input(p, mynetif);
}
rx_setup();
ETH_DMARPDR = 0; /* start RX descriptor polling */
}
}

bool
stm32eth_link(void)
{
return link;
}

bool
stm32eth_act(void)
{
bool ret;
ret = act;
act = false;
return ret;
}
AlexandrY
Цитата(pitt @ Nov 24 2012, 16:25) *
Глупый, наверное, вопрос: Когда приложение шлет посылку на МАС, код копирует ее из памяти приложения в буфер DMA, который затем в фоновом режиме копирует дальше в собственно МАС. А почему нельзя DMA изначально направить на память приложения без дополнительной пересылки?

Спасибо.


Возможно оптимизировали по скорости.
DMA из некоторых областей памяти очень медленно работает и замедляет выполнение программы при этом.
pitt
Цитата(AlexandrY @ Nov 25 2012, 15:12) *
Возможно оптимизировали по скорости.
DMA из некоторых областей памяти очень медленно работает и замедляет выполнение программы при этом.

Но ведь последующее копирование в ту же самую память приложения тоже стоит времени...Непонятно.
scifi
Цитата(pitt @ Nov 26 2012, 01:04) *
Но ведь последующее копирование в ту же самую память приложения тоже стоит времени...Непонятно.

Упрощение кода. Без вариантов.

Update:
Вообще-то есть варианты. EMAC DMA не может вытаскивать данные из on-chip flash. Копирование данных перед отправкой снимает это ограничение.
pitt
Не запускается МАС. Ситуация следущая: разговариваю с PHY, есть линк(autoneg) на 100/fd; дескриптор передачи приготовлен. Запускаю DMA. пока не сбросится TDESC0.31 OWN читаю ETH->DMADBGR(почему-то, у них он записан как ETH->RESERVED1[1], там все нули и ничего не происходит. DMA заканчивает работу, suspends. Линк стоит, МАС в IDLE... Советы? Предложения? Примеры СОБСТВЕННОГО кода? Кстати, а как МАС узнает длину фрейма? Length/Type если больше 1536 уже не длина, а тип, которых разнообразие, с разными заголовками и знать их все МАС попросту не может... Цитата из RM0033
Цитата
Bit 21TSF: Transmit store and forward
When this bit is set, transmission starts when a full frame resides in the Transmit FIFO. When this bit is set, the TTC values specified by the ETH_DMAOMR register bits [16:14] are ignored.


Спасибо.
Allregia
Цитата(AlexandrY @ Nov 25 2012, 22:12) *
Возможно оптимизировали по скорости.
DMA из некоторых областей памяти очень медленно работает и замедляет выполнение программы при этом.


Из каких именно областей?
pitt
Цитата(Allregia @ Dec 8 2012, 04:05) *
Из каких именно областей?

Сильно сомневаюсь...0х2000.......
А не затруднит ли поместить небольшой фрейм полностью...У меня подозрение, что МАС не воспринимает мой. Я НЕ использую IP. Все свое: код, апликации, протоколы...
pitt
Не понимаю что тут написано:
Цитата
After the EOF is transferred to the MAC core, the core completes normal transmission and then gives the status of transmission back to the DMA. If a normal collision (in Half-duplex mode) occurs during transmission, the MAC core makes the transmit status valid, then accepts and drops all further data until the next SOF is received. The same frame should be retransmitted from SOF on observing a Retry request (in the Status) from the MAC. The MAC issues an underflow status if the data are not provided continuously during the transmission. During the normal transfer of a frame, if the MAC receives an SOF without getting an EOF for the previous frame, then the SOF is ignored and the new frame is considered as the continuation of the previous frame.
RM0033 Doc ID 15403 Rev 5 p.826/1334
SOF == SFD? Если нет то что? А что у них EOF?
vsk
Походу здесь UDP посылка обсуждается, OSI - модель прочтите заново...
pitt
Цитата(vsk @ Dec 10 2012, 05:54) *
Походу здесь UDP посылка обсуждается, OSI - модель прочтите заново...
Это, извините, описание МАС: Media Access Controller.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.