Перейти к содержанию
    

STM32F107RB + LAN8742A

Приветствую всех форумчан. Столкнулся с необходимостью интеграции в проект возможности подключения по Ethernet. Микросхема PHY - LAN8742A. Сложность заключается в том, что раньше я работал только с WiFi-модулем, вся суть общения с которым в самом худшем случае - это соединение по UART, поскольку TCP/IP-стек в нем уже интегрирован. А в сложившейся ситуации нужно писать драйвер для соединение микросхемы с контроллером, а потом, насколько я понимаю, еще и драйвер подключения к TCP/IP-стеку. Использовать SPL или HAL я не хочу, поскольку до этого прекрасно обходился регистрами, но пока что все найденные мною в общем доступе примеры по работе STM-ки с этой микросхемой сделаны именно на одной из этих двух библиотек, а обсуждения на форуме по похожим темам касаются уже следующих этапов, то есть непосредственно передачи данных, до чего я пока не дошел.

Суть вопроса: как написать драйвер для этой микросхемы, с чего начинать и куда смотреть? Буду благодарен за любой пинок в нужном направлении.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У меня STM32F107RC + KSZ8081RNA, но это практически то же самое. В основной прошивке lwip, в загрузчике uIP (из-за того, что он меньше). Всё портировал сам, драйвер делал сам. Кстати, драйвер для PHY - это сильно сказано, в отдельных случаях там вообще ничего не надо делать, но обычно лучше всё-таки отслеживать подключение и отключение кабеля.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У меня STM32F107RC + KSZ8081RNA, но это практически то же самое. В основной прошивке lwip, в загрузчике uIP (из-за того, что он меньше). Всё портировал сам, драйвер делал сам. Кстати, драйвер для PHY - это сильно сказано, в отдельных случаях там вообще ничего не надо делать, но обычно лучше всё-таки отслеживать подключение и отключение кабеля.

 

У Вас есть возможность продемонстрировать части кода, отвечающие за инициализацию Ethernet и описание дескрипторов DMA в самом камне? Насколько я смог понять из найденных источников, это - самая проблемная часть. Или, если нет, то, может быть, сможете сказать, где найти какую-нибудь документацию под это дело? На сайте ST есть демонстрация работы lwIP с разными линейками, но она тоже обходит момент инициализации периферии, а больше аппноутов по этой теме я у них не нашел.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У Вас есть возможность продемонстрировать части кода, отвечающие за инициализацию Ethernet и описание дескрипторов DMA в самом камне?

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

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

Объявление:

#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;

Инициализация:

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;
}

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У Вас есть возможность продемонстрировать части кода, отвечающие за инициализацию Ethernet и описание дескрипторов DMA в самом камне? Насколько я смог понять из найденных источников, это - самая проблемная часть. Или, если нет, то, может быть, сможете сказать, где найти какую-нибудь документацию под это дело? На сайте ST есть демонстрация работы lwIP с разными линейками, но она тоже обходит момент инициализации периферии, а больше аппноутов по этой теме я у них не нашел.

Мне не жалко. Вот как бы драйвер lwip, но это для STM32F4. В версии для STMF1 кое-какой глюк ещё не исправил, так что не стал приводить. Разница между STM32F1 и STM32F4 здесь в основном в устройстве GPIO.

#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);
}

 

Ну и перед этим есть ещё немного инициализации:

// 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Огромное спасибо, господа! Этого более чем достаточно для начала. Весьма признателен за помощь.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...