|
|
  |
STM32F2 Ethernet |
|
|
|
Nov 24 2012, 14:25
|
Местный
  
Группа: Участник
Сообщений: 328
Регистрация: 1-06-06
Из: USA
Пользователь №: 17 672

|
Цитата(pitt @ Nov 23 2012, 12:22)  Изучаю документацию и примеры кода. Комментарии непечатные. Не желает ли кто-нибудь поделиться собственной наработкой или дать ссылку на профессиоально сделаный код/пример.
Спасибо Глупый, наверное, вопрос: Когда приложение шлет посылку на МАС, код копирует ее из памяти приложения в буфер DMA, который затем в фоновом режиме копирует дальше в собственно МАС. А почему нельзя DMA изначально направить на память приложения без дополнительной пересылки? Спасибо.
--------------------
|
|
|
|
|
Nov 25 2012, 12:47
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(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; }
|
|
|
|
|
Nov 25 2012, 21:04
|
Местный
  
Группа: Участник
Сообщений: 328
Регистрация: 1-06-06
Из: USA
Пользователь №: 17 672

|
Цитата(AlexandrY @ Nov 25 2012, 15:12)  Возможно оптимизировали по скорости. DMA из некоторых областей памяти очень медленно работает и замедляет выполнение программы при этом. Но ведь последующее копирование в ту же самую память приложения тоже стоит времени...Непонятно.
--------------------
|
|
|
|
|
Dec 8 2012, 04:24
|
Местный
  
Группа: Участник
Сообщений: 328
Регистрация: 1-06-06
Из: USA
Пользователь №: 17 672

|
Не запускается МАС. Ситуация следущая: разговариваю с 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. Спасибо.
--------------------
|
|
|
|
|
Dec 8 2012, 13:00
|
Местный
  
Группа: Участник
Сообщений: 328
Регистрация: 1-06-06
Из: USA
Пользователь №: 17 672

|
Цитата(Allregia @ Dec 8 2012, 04:05)  Из каких именно областей? Сильно сомневаюсь...0х2000....... А не затруднит ли поместить небольшой фрейм полностью...У меня подозрение, что МАС не воспринимает мой. Я НЕ использую IP. Все свое: код, апликации, протоколы...
--------------------
|
|
|
|
|
Dec 8 2012, 22:50
|
Местный
  
Группа: Участник
Сообщений: 328
Регистрация: 1-06-06
Из: USA
Пользователь №: 17 672

|
Не понимаю что тут написано: Цитата 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?
Сообщение отредактировал pitt - Dec 9 2012, 20:45
--------------------
|
|
|
|
|
Dec 10 2012, 10:54
|
Участник

Группа: Участник
Сообщений: 18
Регистрация: 11-01-08
Пользователь №: 33 988

|
Походу здесь UDP посылка обсуждается, OSI - модель прочтите заново...
|
|
|
|
|
Dec 10 2012, 12:26
|
Местный
  
Группа: Участник
Сообщений: 328
Регистрация: 1-06-06
Из: USA
Пользователь №: 17 672

|
Цитата(vsk @ Dec 10 2012, 05:54)  Походу здесь UDP посылка обсуждается, OSI - модель прочтите заново... Это, извините, описание МАС: Media Access Controller.
--------------------
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|