alexmiron31 0 6 марта, 2018 Опубликовано 6 марта, 2018 · Жалоба Приветствую всех форумчан. Столкнулся с необходимостью интеграции в проект возможности подключения по Ethernet. Микросхема PHY - LAN8742A. Сложность заключается в том, что раньше я работал только с WiFi-модулем, вся суть общения с которым в самом худшем случае - это соединение по UART, поскольку TCP/IP-стек в нем уже интегрирован. А в сложившейся ситуации нужно писать драйвер для соединение микросхемы с контроллером, а потом, насколько я понимаю, еще и драйвер подключения к TCP/IP-стеку. Использовать SPL или HAL я не хочу, поскольку до этого прекрасно обходился регистрами, но пока что все найденные мною в общем доступе примеры по работе STM-ки с этой микросхемой сделаны именно на одной из этих двух библиотек, а обсуждения на форуме по похожим темам касаются уже следующих этапов, то есть непосредственно передачи данных, до чего я пока не дошел. Суть вопроса: как написать драйвер для этой микросхемы, с чего начинать и куда смотреть? Буду благодарен за любой пинок в нужном направлении. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
scifi 1 6 марта, 2018 Опубликовано 6 марта, 2018 · Жалоба У меня STM32F107RC + KSZ8081RNA, но это практически то же самое. В основной прошивке lwip, в загрузчике uIP (из-за того, что он меньше). Всё портировал сам, драйвер делал сам. Кстати, драйвер для PHY - это сильно сказано, в отдельных случаях там вообще ничего не надо делать, но обычно лучше всё-таки отслеживать подключение и отключение кабеля. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alexmiron31 0 6 марта, 2018 Опубликовано 6 марта, 2018 · Жалоба У меня STM32F107RC + KSZ8081RNA, но это практически то же самое. В основной прошивке lwip, в загрузчике uIP (из-за того, что он меньше). Всё портировал сам, драйвер делал сам. Кстати, драйвер для PHY - это сильно сказано, в отдельных случаях там вообще ничего не надо делать, но обычно лучше всё-таки отслеживать подключение и отключение кабеля. У Вас есть возможность продемонстрировать части кода, отвечающие за инициализацию Ethernet и описание дескрипторов DMA в самом камне? Насколько я смог понять из найденных источников, это - самая проблемная часть. Или, если нет, то, может быть, сможете сказать, где найти какую-нибудь документацию под это дело? На сайте ST есть демонстрация работы lwIP с разными линейками, но она тоже обходит момент инициализации периферии, а больше аппноутов по этой теме я у них не нашел. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 136 6 марта, 2018 Опубликовано 6 марта, 2018 · Жалоба У Вас есть возможность продемонстрировать части кода, отвечающие за инициализацию 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; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
scifi 1 6 марта, 2018 Опубликовано 6 марта, 2018 · Жалоба У Вас есть возможность продемонстрировать части кода, отвечающие за инициализацию 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(ð_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); } Ну и перед этим есть ещё немного инициализации: // 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 0 7 марта, 2018 Опубликовано 7 марта, 2018 · Жалоба Огромное спасибо, господа! Этого более чем достаточно для начала. Весьма признателен за помощь. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться