Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32F107RB + LAN8742A
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
alexmiron31
Приветствую всех форумчан. Столкнулся с необходимостью интеграции в проект возможности подключения по Ethernet. Микросхема PHY - LAN8742A. Сложность заключается в том, что раньше я работал только с WiFi-модулем, вся суть общения с которым в самом худшем случае - это соединение по UART, поскольку TCP/IP-стек в нем уже интегрирован. А в сложившейся ситуации нужно писать драйвер для соединение микросхемы с контроллером, а потом, насколько я понимаю, еще и драйвер подключения к TCP/IP-стеку. Использовать SPL или HAL я не хочу, поскольку до этого прекрасно обходился регистрами, но пока что все найденные мною в общем доступе примеры по работе STM-ки с этой микросхемой сделаны именно на одной из этих двух библиотек, а обсуждения на форуме по похожим темам касаются уже следующих этапов, то есть непосредственно передачи данных, до чего я пока не дошел.
Суть вопроса: как написать драйвер для этой микросхемы, с чего начинать и куда смотреть? Буду благодарен за любой пинок в нужном направлении.
scifi
У меня STM32F107RC + KSZ8081RNA, но это практически то же самое. В основной прошивке lwip, в загрузчике uIP (из-за того, что он меньше). Всё портировал сам, драйвер делал сам. Кстати, драйвер для PHY - это сильно сказано, в отдельных случаях там вообще ничего не надо делать, но обычно лучше всё-таки отслеживать подключение и отключение кабеля.
alexmiron31
Цитата(scifi @ Mar 6 2018, 16:45) *
У меня STM32F107RC + KSZ8081RNA, но это практически то же самое. В основной прошивке lwip, в загрузчике uIP (из-за того, что он меньше). Всё портировал сам, драйвер делал сам. Кстати, драйвер для PHY - это сильно сказано, в отдельных случаях там вообще ничего не надо делать, но обычно лучше всё-таки отслеживать подключение и отключение кабеля.


У Вас есть возможность продемонстрировать части кода, отвечающие за инициализацию Ethernet и описание дескрипторов DMA в самом камне? Насколько я смог понять из найденных источников, это - самая проблемная часть. Или, если нет, то, может быть, сможете сказать, где найти какую-нибудь документацию под это дело? На сайте ST есть демонстрация работы lwIP с разными линейками, но она тоже обходит момент инициализации периферии, а больше аппноутов по этой теме я у них не нашел.
Сергей Борщ
QUOTE (alexmiron31 @ Mar 6 2018, 17:02) *
У Вас есть возможность продемонстрировать части кода, отвечающие за инициализацию Ethernet и описание дескрипторов DMA в самом камне?

Дескрипторы:
CODE

namespace ethernet
{

struct dma_rx_descriptor
{
union status
{
struct
{
uint32_t Payload_checksum_error : 1;
uint32_t CRC_error : 1;
uint32_t Dribble_bit_error : 1;
uint32_t Receive_error : 1;
uint32_t Watchdog_timeout : 1;
uint32_t Is_ethernet_frame : 1;
uint32_t Late_collision : 1;
uint32_t IP_header_checksum_error : 1;
uint32_t Last_descriptor : 1;
uint32_t First_descriptor : 1;
uint32_t VLAN_tag : 1;
uint32_t Overflow_error : 1;
uint32_t Length_error : 1;
uint32_t Src_addr_filter_fail : 1;
uint32_t Descriptor_error : 1;
uint32_t Error_summary : 1;
uint32_t Frame_length : 14;
uint32_t Dst_addr_filter_fail : 1;
uint32_t Owned_by_DMA : 1;
};
uint32_t Raw;
} Status;

union control
{
struct
{
uint32_t Buffer_size : 13;
uint32_t : 1;
uint32_t Is_chained : 1;
uint32_t Is_last : 1;
uint32_t : 13;
uint32_t : 2;
uint32_t : 1;
};
uint32_t Raw;
} Control;
uint32_t volatile * pBuffer;
dma_rx_descriptor volatile * pNext;
};

struct dma_tx_descriptor
{
union status
{
struct
{
uint32_t Deferred_bit : 1;
uint32_t Underflow_error : 1;
uint32_t Excessive_deferral : 1;
uint32_t Collision_count : 4;
uint32_t VLAN_frame : 1;
uint32_t Excessive_collision : 1;
uint32_t Late_collision : 1;
uint32_t No_carrier : 1;
uint32_t Loss_of_carrier : 1;
uint32_t IP_payload_error : 1;
uint32_t Frame_flushed : 1;
uint32_t Jabber_timeout : 1;
uint32_t Error_summary : 1;
uint32_t IP_header_error : 1;
uint32_t Tx_timestamp_status : 1;
uint32_t : 2;
uint32_t Is_chained : 1;
uint32_t Is_end_of_ring : 1;
uint32_t Checksum_insertion : 2;
uint32_t : 1;
uint32_t Tx_timestamp_enable : 1;
uint32_t Disable_pad : 1;
uint32_t Disable_CRC : 1;
uint32_t First_segment : 1;
uint32_t Last_segment : 1;
uint32_t Interrupt_on_completion: 1;
uint32_t Owned_by_DMA : 1;
};
uint32_t Raw;
} Status;
uint32_t Byte_count : 13;

uint32_t volatile * pBuffer;
dma_tx_descriptor volatile * pNext;
};

template<typename descriptor, size_t max_packet_size>
struct dma_chain
{
descriptor volatile Descriptor;
uint32_t volatile Data[(max_packet_size + sizeof(uint32_t) - 1) / sizeof(uint32_t)];
};

template<size_t packet_size>
uintptr_t init_descriptors_chain(dma_chain<dma_tx_descriptor, packet_size> * pChain, size_t elements)
{
auto pElement = pChain;
do
{
pElement->Descriptor.pBuffer = pElement->Data;
pElement->Descriptor.pNext = &pElement[1].Descriptor;
dma_tx_descriptor::status Status = {};
Status.Is_chained = true;
/* Setting the last segment and first segment bits (in this case a frame is transmitted in one descriptor) */
Status.First_segment = true;
Status.Last_segment = true;
Status.Checksum_insertion = 3; // IP header, payload, pseudo-header
pElement++->Descriptor.Status.Raw = Status.Raw;
}
while(--elements);
pElement[-1].Descriptor.pNext = &pChain->Descriptor;
return (uintptr_t)&pChain->Descriptor;
}

template<size_t packet_size>
uintptr_t init_descriptors_chain(dma_chain<dma_rx_descriptor, packet_size> * pChain, size_t elements)
{
auto pElement = pChain;
do
{
dma_rx_descriptor::status Status = {};
Status.Owned_by_DMA = true;
pElement->Descriptor.Status.Raw = Status.Raw;

dma_rx_descriptor::control Control = {};
Control.Buffer_size = packet_size;
Control.Is_chained = true;
pElement->Descriptor.Control.Raw = Control.Raw;
pElement->Descriptor.pBuffer = pElement->Data;
pElement->Descriptor.pNext = &pElement[1].Descriptor;
++pElement;
}
while(--elements);
pElement[-1].Descriptor.pNext = &pChain->Descriptor;
return (uintptr_t)&pChain->Descriptor;
}

template<typename T>
inline uintptr_t init_descriptors_chain(T & buffer)
{
return init_descriptors_chain(buffer, sizeof(buffer) / sizeof(buffer[0]));
}

} // namespace ethernet
Объявление:
CODE
#define ETH_MAX_PACKET_SIZE    1520    /*!< ETH_HEADER + ETH_EXTRA + MAX_ETH_PAYLOAD + ETH_CRC */

namespace ethernet
{
static dma_chain<dma_rx_descriptor, ETH_MAX_PACKET_SIZE> Rx_buffer[ETH_RXBUFNB];
static dma_chain<dma_tx_descriptor, ETH_MAX_PACKET_SIZE> Tx_buffer[ETH_TXBUFNB];

static dma_tx_descriptor volatile * Tx_next = &Tx_buffer[0].Descriptor;
static dma_rx_descriptor volatile * Rx_last = &Rx_buffer[0].Descriptor;

Инициализация:
CODE
err_t stm32_if_init(struct netif *netif)
{
LWIP_ASSERT("netif != NULL", (netif != NULL));
/*
* Initialize the snmp variables and counters inside the struct netif.
* The last argument should be replaced with your link speed, in units
* of bits per second.
*/
// NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 100000000);

/* We directly use etharp_output() here to save a function call.
* You can instead declare your own function an call etharp_output()
* from it if you have to do some checks before sending (e.g. if link
* is available...) */
netif->output = etharp_output;
netif->linkoutput = stm32_if_output;

/* initialize the hardware */
/* set MAC hardware address length */
netif->hwaddr_len = ETHARP_HWADDR_LEN;
/* maximum transfer unit */
netif->mtu = 1500;
/* device capabilities */
/* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;

lan8720a::init();

while(ETH->DMABMR & ETH_DMABMR_SR)
;
/* set MAC hardware address */
ETH->MACA0HR = 0
| (netif->hwaddr[5] << 8)
| (netif->hwaddr[4] << 0)
;
ETH->MACA0LR = 0
| (netif->hwaddr[3] << 24)
| (netif->hwaddr[2] << 16)
| (netif->hwaddr[1] << 8)
| (netif->hwaddr[0] << 0)
;

ETH->MACFFR = 0
| 0 * ETH_MACFFR_RA // Receive all
| 0 * ETH_MACFFR_HPF // Hash or perfect filter
| 0 * ETH_MACFFR_SAF // Source address filter
| 0 * ETH_MACFFR_SAIF // SA inverse filtering
| 1 * ETH_MACFFR_PCF // Pass control frames:
// 1: MAC filters all control frames from reaching the application
// 2: MAC forwards all control frames to application even if they fail the Address Filter
// 3: MAC forwards control frames that pass the Address Filter
| 0 * ETH_MACFFR_BFD // Broadcast frame disable
| 0 * ETH_MACFFR_PAM // Pass all multicast
| 0 * ETH_MACFFR_DAIF // DA Inverse filtering
| 0 * ETH_MACFFR_HM // Hash multicast
| 0 * ETH_MACFFR_HU // Hash unicast
| 0 * ETH_MACFFR_PM // Promiscuous mode
;
// Hash table
ETH->MACHTHR = 0;
ETH->MACHTLR = 0;

ETH->MACFCR = 0
| 0 * (ETH_MACFCR_PT & -ETH_MACFCR_PT) // Pause time
| 1 * ETH_MACFCR_ZQPD // Zero-quanta pause disable
| 0 * (ETH_MACFCR_PLT & -ETH_MACFCR_PLT)// Pause low threshold:
// 0: Pause time minus 4 slot times
// 1: Pause time minus 28 slot times
// 2: Pause time minus 144 slot times
// 3: Pause time minus 256 slot times
| 0 * ETH_MACFCR_UPFD // Unicast pause frame detect
| 1 * ETH_MACFCR_RFCE // Receive flow control enable
| 1 * ETH_MACFCR_TFCE // Transmit flow control enable
| 0 * ETH_MACFCR_FCBBPA // Flow control busy/backpressure activate
;

ETH->MACVLANTR = 0
| 0 * ETH_MACVLANTR_VLANTC // 12-bit VLAN tag comparison
| 0 * (ETH_MACVLANTR_VLANTI & -ETH_MACVLANTR_VLANTI) // VLAN tag identifier
;

/* Initialize Tx Descriptors list: Chain Mode */
ETH->DMATDLAR = init_descriptors_chain(Tx_buffer);
/* Initialize Rx Descriptors list: Chain Mode, owned by DMA, ints enabled */
ETH->DMARDLAR = init_descriptors_chain(Rx_buffer);

ETH->DMABMR = 0
| 1 * ETH_DMABMR_AAB // Address-aligned beats
| 0 * ETH_DMABMR_FPM // 4xPBL mode
| 0 * ETH_DMABMR_USP // Use separate PBL
| 1 * (ETH_DMABMR_RDP & -ETH_DMABMR_RDP) // RxDMA programmable burst length, must be 2^n
| 0 * ETH_DMABMR_FB // Fixed burst
| 0 * (ETH_DMABMR_RTPR & -ETH_DMABMR_RTPR) // Rx/Tx priority ratio
| 1 * (ETH_DMABMR_PBL & -ETH_DMABMR_PBL) // TxDMA (or both) programmable burst length
| 0 * ETH_DMABMR_DSL // Descriptor Skip Length
| 0 * ETH_DMABMR_DA // DMA arbitration scheme: 0 - roubd-robbin, 1 - rx priority
| 0 * ETH_DMABMR_SR // Software reset
;

/* Enable MAC transmission and reception*/
ETH->MACCR = 0
| 0 * ETH_MACCR_WD // Watchdog disabling
| 0 * ETH_MACCR_JD // Jabber disabling
| 0 * (ETH_MACCR_IFG & -ETH_MACCR_IFG) // Inter-frame gap
| 0 * ETH_MACCR_CSD // Carrier sense disabling
| 1 * ETH_MACCR_FES // Fast ethernet speed
| 0 * ETH_MACCR_ROD // Receive own disabling
| 0 * ETH_MACCR_LM // loopback mode
| 1 * ETH_MACCR_DM // Duplex mode
| 0 * ETH_MACCR_IPCO // IP Checksum offload
| 0 * ETH_MACCR_RD // Retry disable
| 0 * ETH_MACCR_APCS // Automatic Pad/CRC stripping
| 0 * (ETH_MACCR_BL &-ETH_MACCR_BL) // Back-off limit: random integer number ® of slot time delays before rescheduling
// a transmission attempt during retries after a collision: 0 =< r <2^k
| 0 * ETH_MACCR_DC // Defferal check
| 1 * ETH_MACCR_TE // Transmitter enable
| 1 * ETH_MACCR_RE // Receiver enable
;
/* Flush Transmit FIFO, enable DMA transmission and DMA reception */
ETH->DMAOMR = 0
| 1 * ETH_DMAOMR_DTCEFD // Disabling dropping of TCP/IP checksum error frames
| 1 * ETH_DMAOMR_RSF // Receive store and forward
| 1 * ETH_DMAOMR_DFRF // Disabling flushing of received frames
| 1 * ETH_DMAOMR_TSF // Transmit store and forward Mandatory for hardware CRC calc.
| 0 * ETH_DMAOMR_FTF // Flush transmit FIFO
| 0 * (ETH_DMAOMR_TTC & -ETH_DMAOMR_TTC)// Transmit threshold control:
// 0: 64 Bytes
// 1: 128 Bytes
// 2: 192 Bytes
// 3: 256 Bytes
// 4: 40 Bytes
// 5: 32 Bytes
// 6: 24 Bytes
// 7: 16 Bytes
| 1 * ETH_DMAOMR_ST // Start/stop transmission command
| 0 * ETH_DMAOMR_FEF // Forward error frames
| 0 * ETH_DMAOMR_FUGF // Forward undersized good frames
| 0 * (ETH_DMAOMR_RTC & -ETH_DMAOMR_RTC)// receive threshold control
// 0: 64 Bytes
// 1: 32 Bytes
// 2: 96 Bytes
// 3: 128 Bytes
| 0 * ETH_DMAOMR_OSF // operate on second frame
| 1 * ETH_DMAOMR_SR // Start/stop receive
;
etharp_init();
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);

ETH->DMAIER = ETH_DMAIER_NISE | ETH_DMAIER_RIE; // enable receive interrupt

return ERR_OK;
}

scifi
Цитата(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(&eth_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(&eth_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
alexmiron31
Огромное спасибо, господа! Этого более чем достаточно для начала. Весьма признателен за помощь.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.