Цитата(alexmiron31 @ Mar 6 2018, 18:02)

У Вас есть возможность продемонстрировать части кода, отвечающие за инициализацию Ethernet и описание дескрипторов DMA в самом камне? Насколько я смог понять из найденных источников, это - самая проблемная часть. Или, если нет, то, может быть, сможете сказать, где найти какую-нибудь документацию под это дело? На сайте ST есть демонстрация работы lwIP с разными линейками, но она тоже обходит момент инициализации периферии, а больше аппноутов по этой теме я у них не нашел.
Мне не жалко. Вот как бы драйвер lwip, но это для STM32F4. В версии для STMF1 кое-какой глюк ещё не исправил, так что не стал приводить. Разница между STM32F1 и STM32F4 здесь в основном в устройстве GPIO.
CODE
#include "stm32eth.h"
#include "assert_static.h"
#include "pt.h"
#include "stm32f4xx.h"
#include "systime.h"
#include "lwip/netif.h"
#include "lwip/mem.h"
#include "netif/etharp.h"
#include <string.h>
#define SMI_TMPL 0x00000010 // sets SMI clock range and PHY address
#define RX_RING_SIZE 16
#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 struct buf_desc tx_desc[TX_RING_SIZE];
static struct buf_desc rx_desc[RX_RING_SIZE];
static unsigned int rx_head, rx_tail;
static struct pt eth_pt;
static bool activity;
static bool
smi_busy(void)
{
return !!(ETH->MACMIIAR & ETH_MACMIIAR_MB);
}
/*
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)
{
/* dummy read */
smi_start_read(0);
while (smi_busy())
{
/* wait */
}
}
static err_t
low_level_output(struct netif *netif, struct pbuf *p)
{
if (!netif_is_link_up(netif))
{
return ERR_OK;
}
uint32_t mask;
do
{
mask = ETH->DMASR & ETH_DMASR_TPS;
}
while (mask != ETH_DMASR_TPS_Suspended && mask != ETH_DMASR_TPS_Stopped);
mask = (1u << 31) // OWN bit
| (1 << 28); // first segment
int i = -1;
for (;;)
{
i++;
if (i == TX_RING_SIZE)
{
// not enough TX descriptors
return ERR_MEM;
}
if (!p->next)
{
tx_desc[i].len[0] = 0;
tx_desc[i].len[1] = p->len;
tx_desc[i].ptr[1] = p->payload;
break;
}
tx_desc[i].len[0] = p->len;
tx_desc[i].ptr[0] = p->payload;
p = p->next;
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;
}
}
mask |= (1 << 21) // end of ring
| (1 << 29); // last segment
tx_desc[i].status = mask;
ETH->DMASR = ETH_DMASR_ETS; // reset ETS flag in status register
ETH->DMATPDR = 0; // start transmission
while ((ETH->DMASR & ETH_DMASR_ETS) == 0)
{
// wait for data to be copied into Tx FIFO
}
activity = true;
return ERR_OK;
}
/**
* Initialize the Rx buffer descriptor ring by allocating buffers
* and assigning them to descriptors
*/
static void
rx_setup(void)
{
unsigned int prev_head = rx_head;
while (rx_head - rx_tail < RX_RING_SIZE)
{
struct pbuf *p = pbuf_alloc(PBUF_RAW, PBUF_POOL_BUFSIZE, PBUF_POOL);
if (!p)
{
break;
}
struct buf_desc *ptr = &rx_desc[rx_head & (RX_RING_SIZE - 1)];
ptr->p[1] = p;
ptr->ptr[1] = p->payload;
ptr->len[1] = p->len;
p = pbuf_alloc(PBUF_RAW, PBUF_POOL_BUFSIZE, PBUF_POOL);
if (p)
{
ptr->p[0] = p;
ptr->ptr[0] = p->payload;
ptr->len[0] = p->len;
}
else
{
ptr->len[0] = 0;
}
if ((++rx_head & (RX_RING_SIZE - 1)) == 0)
{
ptr->len[0] |= (1 << 15); // end of ring
}
}
unsigned int i = rx_head;
while (i != prev_head)
{
rx_desc[--i & (RX_RING_SIZE - 1)].status = 1u << 31; // OWN bit
}
}
/**
* Discard frame in case of reception error by deallocating buffers
*
* @param n Number of descriptors to discard
*/
static void
discard_frame(int n)
{
while (n-- > 0)
{
struct buf_desc *ptr = &rx_desc[rx_tail++ & (RX_RING_SIZE - 1)];
pbuf_free(ptr->p[1]);
if ((ptr->len[0] & 0x1FFF) != 0)
{
pbuf_free(ptr->p[0]);
}
}
}
/**
* Collect frame by chaining the corresponding pbufs
*
* @param n Number of buffer descriptors to collect
* @param len Frame length
*/
static struct pbuf*
collect_frame(int n, int len)
{
int n_arg = n;
struct pbuf *t = 0;
// walk ring last to first
do
{
n--;
struct buf_desc *ptr = &rx_desc[(rx_tail + n) & (RX_RING_SIZE - 1)];
struct pbuf *h = ptr->p[1];
if (t)
{
pbuf_cat(h, t);
}
t = h;
if (ptr->len[0] & 0x1FFF)
{
h = ptr->p[0];
pbuf_cat(h, t);
t = h;
}
}
while (n);
pbuf_realloc(t, len);
rx_tail += n_arg;
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)
{
uint32_t status;
int n = 0;
// Scan the Rx buffer rescriptor ring
for (;;)
{
if (rx_tail + n == rx_head)
{
// Descriptor uninitialized, quit
return 0;
}
struct buf_desc *ptr = &rx_desc[(rx_tail + n) & (RX_RING_SIZE - 1)];
status = ptr->status;
if (status & (1u << 31))
{
// Buffer still owned by DMA, quit
return 0;
}
// Buffer contains frame data, continue
n++;
if (status & (1 << 8))
{
// Last buffer in frame, finalize
break;
}
}
if ((status & 0x4000F89B) != 0) // error bits
{
discard_frame(n);
return 0;
}
activity = true;
return collect_frame(n, (status >> 16) & 0x3FFF);
}
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));
memset(tx_desc, 0, sizeof tx_desc);
memset(rx_desc, 0, sizeof rx_desc);
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;
// configure Ethernet signals
GPIOA->AFR[0] |= (11 << (4 * 1))
| (11 << (4 * 2))
| (11 << (4 * 7));
GPIOA->MODER |= GPIO_MODER_MODER1_1
| GPIO_MODER_MODER2_1
| GPIO_MODER_MODER7_1;
GPIOB->AFR[1] |= (11 << (4 * (11 - 8)))
| (11 << (4 * (12 - 8)))
| (11 << (4 * (13 - 8)));
GPIOB->MODER |= GPIO_MODER_MODER11_1
| GPIO_MODER_MODER12_1
| GPIO_MODER_MODER13_1;
GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR11_0
| GPIO_OSPEEDER_OSPEEDR12_0
| GPIO_OSPEEDER_OSPEEDR13_0;
GPIOC->AFR[0] |= (11 << (4 * 1))
| (11 << (4 * 4))
| (11 << (4 * 5));
GPIOC->MODER |= GPIO_MODER_MODER1_1
| GPIO_MODER_MODER4_1
| GPIO_MODER_MODER5_1;
// enable PHYRST
GPIOE->MODER |= GPIO_MODER_MODER11_0;
// deassert PHYRST
GPIOE->BSRR = 1 << 11;
systime_delay(SYSTIME_TPS / 10000);
phy_init();
// enable green LED
GPIOD->BSRR = 1 << 8;
GPIOD->MODER |= GPIO_MODER_MODER8_0;
PT_INIT(ð_pt);
return ERR_OK;
}
void
catch_frames(void)
{
if (ETH->DMASR & ETH_DMASR_RS)
{
// RS bit set: complete frame received
ETH->DMASR = ETH_DMASR_RS; // clear RS bit
}
struct pbuf *p = low_level_input();
if (p)
{
ethernet_input(p, mynetif);
}
rx_setup();
ETH->DMARPDR = 0; // start RX descriptor polling
}
static
PT_THREAD(led_thread(struct pt* pt))
{
PT_BEGIN(pt);
for (;;)
{
activity = false;
PT_WAIT_UNTIL(pt, activity);
GPIOD->BSRR = 1 << 8; // green led off
PT_YIELD(pt);
GPIOD->BSRR = 1 << (8 + 16); // green led on
}
PT_END(pt);
}
void
stm32eth_updatemac(void)
{
ETH->MACA0LR = (mynetif->hwaddr[0] << 0)
| (mynetif->hwaddr[1] << 8)
| (mynetif->hwaddr[2] << 16)
| (mynetif->hwaddr[3] << 24);
ETH->MACA0HR = (mynetif->hwaddr[4] << 0)
| (mynetif->hwaddr[5] << 8);
}
static
PT_THREAD(eth_thread(struct pt* pt))
{
PT_BEGIN(pt);
// assert Ethernet MAC reset
RCC->AHB1RSTR |= RCC_AHB1RSTR_ETHMACRST;
systime_delay(100); // make sure MAC is reset
// deassert Ethernet MAC reset
RCC->AHB1RSTR &= ~RCC_AHB1RSTR_ETHMACRST;
rx_head = 0;
rx_tail = 0;
rx_setup();
static unsigned int start;
int reg;
do
{
start = systime_ticks();
PT_WAIT_WHILE(pt, systime_ticks() - start < SYSTIME_TPS / 10);
smi_start_read(1);
PT_WAIT_WHILE(pt, smi_busy());
reg = smi_read_data();
}
while ((reg & (1 << 5)) == 0); // auto-negotiation complete flag
smi_start_read(0x1E);
PT_WAIT_WHILE(pt, smi_busy());
reg = smi_read_data() & 0xFF;
if (reg & (1 << 1))
{
reg |= ETH_MACCR_FES; // speed
}
if (reg & (1 << 2))
{
reg |= ETH_MACCR_DM; // duplex
}
reg &= 0xFF00;
while ((ETH->DMABMR & ETH_DMABMR_SR) != 0)
{
// wait for core reset to complete
}
stm32eth_updatemac();
ETH->DMATDLAR = (int)&tx_desc;
ETH->DMARDLAR = (int)&rx_desc;
ETH->MACCR = ETH_MACCR_CSD
| ETH_MACCR_TE
| ETH_MACCR_RE
| reg; // speed and duplex
ETH->DMABMR |= (2 << 2); // descriptor skip length = 2
ETH->DMAOMR = ETH_DMAOMR_TSF // transmit store and forward
| ETH_DMAOMR_ST // start transmission
| ETH_DMAOMR_SR; // start reception
netif_set_link_up(mynetif);
static struct pt led_pt;
PT_INIT(&led_pt);
GPIOD->BSRR = 1 << (8 + 16); // green led on
do
{
start = systime_ticks();
while(systime_ticks() - start < SYSTIME_TPS / 10)
{
catch_frames();
PT_YIELD(pt);
}
smi_start_read(1);
while(smi_busy())
{
catch_frames();
PT_YIELD(pt);
}
reg = smi_read_data();
(void)PT_SCHEDULE(led_thread(&led_pt));
}
while ((reg & (1 << 5)) != 0); // auto-negotiation complete flag
GPIOD->BSRR = 1 << 8; // green led off
// assert Ethernet MAC reset
RCC->AHB1RSTR |= RCC_AHB1RSTR_ETHMACRST;
netif_set_link_down(mynetif);
// link down, deallocate buffers
if (rx_head != rx_tail)
{
discard_frame(rx_head - rx_tail);
}
PT_END(pt);
}
void
stm32eth_poll(void)
{
(void)PT_SCHEDULE(eth_thread(ð_pt));
}
bool
stm32eth_link(void)
{
return !!netif_is_up(mynetif);
}
Ну и перед этим есть ещё немного инициализации:
CODE
// enable clocks
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN
| RCC_APB2ENR_ADC1EN
| RCC_APB2ENR_ADC2EN
| RCC_APB2ENR_ADC3EN
| RCC_APB2ENR_USART1EN;
// reset MAC
RCC->AHB1RSTR |= RCC_AHB1RSTR_ETHMACRST;
// select RMII mode
SYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL;
// enable clocks
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN
| RCC_AHB1ENR_GPIOBEN
| RCC_AHB1ENR_GPIOCEN
| RCC_AHB1ENR_GPIODEN
| RCC_AHB1ENR_GPIOEEN
| RCC_AHB1ENR_ETHMACEN
| RCC_AHB1ENR_ETHMACRXEN
| RCC_AHB1ENR_ETHMACTXEN
| RCC_AHB1ENR_DMA1EN
| RCC_AHB1ENR_DMA2EN;
RCC->AHB2ENR |= RCC_AHB2ENR_RNGEN;
RCC->APB1ENR |= RCC_APB1ENR_SPI3EN
| RCC_APB1ENR_TIM3EN
| RCC_APB1ENR_TIM4EN;
// ADC clock = PCLK2 / 4 = 21 MHz
ADC->CCR |= ADC_CCR_ADCPRE_0;
// clock for Ethernet PHY
GPIOA->MODER |= GPIO_MODER_MODER8_1; // AF mode, PA8 = MCO1 output