diff --git a/ports/stm32/eth.c b/ports/stm32/eth.c index 33d20707e2..7a08e8c28c 100644 --- a/ports/stm32/eth.c +++ b/ports/stm32/eth.c @@ -61,7 +61,19 @@ #define PHY_SCSR_SPEED_100FULL (6 << PHY_SCSR_SPEED_Pos) // ETH DMA RX and TX descriptor definitions +#if defined(STM32H7) +#define RX_DESCR_3_OWN_Pos (31) +#define RX_DESCR_3_IOC_Pos (30) +#define RX_DESCR_3_BUF1V_Pos (24) +#define RX_DESCR_3_PL_Msk (0x7fff) +#define TX_DESCR_3_OWN_Pos (31) +#define TX_DESCR_3_LD_Pos (29) +#define TX_DESCR_3_FD_Pos (28) +#define TX_DESCR_3_CIC_Pos (16) +#define TX_DESCR_2_B1L_Pos (0) +#define TX_DESCR_2_B1L_Msk (0x3fff << TX_DESCR_2_B1L_Pos) +#else #define RX_DESCR_0_OWN_Pos (31) #define RX_DESCR_0_FL_Pos (16) #define RX_DESCR_0_FL_Msk (0x3fff << RX_DESCR_0_FL_Pos) @@ -78,6 +90,7 @@ #define TX_DESCR_0_TER_Pos (21) #define TX_DESCR_0_TCH_Pos (20) #define TX_DESCR_1_TBS1_Pos (0) +#endif // Configuration values @@ -121,6 +134,20 @@ STATIC void eth_mac_deinit(eth_t *self); STATIC void eth_process_frame(eth_t *self, size_t len, const uint8_t *buf); STATIC void eth_phy_write(uint32_t reg, uint32_t val) { + #if defined(STM32H7) + while (ETH->MACMDIOAR & ETH_MACMDIOAR_MB) { + } + uint32_t ar = ETH->MACMDIOAR; + ar &= ~ETH_MACMDIOAR_RDA_Msk; + ar |= reg << ETH_MACMDIOAR_RDA_Pos; + ar &= ~ETH_MACMDIOAR_MOC_Msk; + ar |= ETH_MACMDIOAR_MOC_WR; + ar |= ETH_MACMDIOAR_MB; + ETH->MACMDIODR = val; + ETH->MACMDIOAR = ar; + while (ETH->MACMDIOAR & ETH_MACMDIOAR_MB) { + } + #else while (ETH->MACMIIAR & ETH_MACMIIAR_MB) { } ETH->MACMIIDR = val; @@ -129,9 +156,24 @@ STATIC void eth_phy_write(uint32_t reg, uint32_t val) { ETH->MACMIIAR = ar; while (ETH->MACMIIAR & ETH_MACMIIAR_MB) { } + #endif } STATIC uint32_t eth_phy_read(uint32_t reg) { + #if defined(STM32H7) + while (ETH->MACMDIOAR & ETH_MACMDIOAR_MB) { + } + uint32_t ar = ETH->MACMDIOAR; + ar &= ~ETH_MACMDIOAR_RDA_Msk; + ar |= reg << ETH_MACMDIOAR_RDA_Pos; + ar &= ~ETH_MACMDIOAR_MOC_Msk; + ar |= ETH_MACMDIOAR_MOC_RD; + ar |= ETH_MACMDIOAR_MB; + ETH->MACMDIOAR = ar; + while (ETH->MACMDIOAR & ETH_MACMDIOAR_MB) { + } + return ETH->MACMDIODR; + #else while (ETH->MACMIIAR & ETH_MACMIIAR_MB) { } uint32_t ar = ETH->MACMIIAR; @@ -140,6 +182,7 @@ STATIC uint32_t eth_phy_read(uint32_t reg) { while (ETH->MACMIIAR & ETH_MACMIIAR_MB) { } return ETH->MACMIIDR; + #endif } void eth_init(eth_t *self, int mac_idx) { @@ -160,7 +203,7 @@ STATIC int eth_mac_init(eth_t *self) { // Configure GPIO mp_hal_pin_config_alt_static(MICROPY_HW_ETH_MDC, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_MDC); mp_hal_pin_config_alt_static(MICROPY_HW_ETH_MDIO, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_MDIO); - mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RMII_REF_CLK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_RMII_REF_CLK); + mp_hal_pin_config_alt_static_speed(MICROPY_HW_ETH_RMII_REF_CLK, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, MP_HAL_PIN_SPEED_MEDIUM, STATIC_AF_ETH_RMII_REF_CLK); mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RMII_CRS_DV, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_RMII_CRS_DV); mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RMII_RXD0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_RMII_RXD0); mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RMII_RXD1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_RMII_RXD1); @@ -168,26 +211,53 @@ STATIC int eth_mac_init(eth_t *self) { mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RMII_TXD0, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_RMII_TXD0); mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RMII_TXD1, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_RMII_TXD1); + #if defined(STM32H7) + __HAL_RCC_ETH1MAC_CLK_ENABLE(); + __HAL_RCC_ETH1TX_CLK_ENABLE(); + __HAL_RCC_ETH1RX_CLK_ENABLE(); + __HAL_RCC_ETH1MAC_FORCE_RESET(); + #else __HAL_RCC_ETH_CLK_ENABLE(); __HAL_RCC_ETHMAC_FORCE_RESET(); + #endif // Select RMII interface + #if defined(STM32H7) + SYSCFG->PMCR = (SYSCFG->PMCR & ~SYSCFG_PMCR_EPIS_SEL_Msk) | SYSCFG_PMCR_EPIS_SEL_2; + #else __HAL_RCC_SYSCFG_CLK_ENABLE(); SYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL; + #endif + #if defined(STM32H7) + __HAL_RCC_ETH1MAC_RELEASE_RESET(); + + __HAL_RCC_ETH1MAC_CLK_SLEEP_ENABLE(); + __HAL_RCC_ETH1TX_CLK_SLEEP_ENABLE(); + __HAL_RCC_ETH1RX_CLK_SLEEP_ENABLE(); + #else __HAL_RCC_ETHMAC_RELEASE_RESET(); __HAL_RCC_ETHMAC_CLK_SLEEP_ENABLE(); __HAL_RCC_ETHMACTX_CLK_SLEEP_ENABLE(); __HAL_RCC_ETHMACRX_CLK_SLEEP_ENABLE(); + #endif // Do a soft reset of the MAC core - ETH->DMABMR = ETH_DMABMR_SR; + #if defined(STM32H7) + #define ETH_SOFT_RESET(eth) do { eth->DMAMR = ETH_DMAMR_SWR; } while (0) + #define ETH_IS_RESET(eth) (eth->DMAMR & ETH_DMAMR_SWR) + #else + #define ETH_SOFT_RESET(eth) do { eth->DMABMR = ETH_DMABMR_SR; } while (0) + #define ETH_IS_RESET(eth) (eth->DMABMR & ETH_DMABMR_SR) + #endif + + ETH_SOFT_RESET(ETH); mp_hal_delay_ms(2); // Wait for soft reset to finish uint32_t t0 = mp_hal_ticks_ms(); - while (ETH->DMABMR & ETH_DMABMR_SR) { + while (ETH_IS_RESET(ETH)) { if (mp_hal_ticks_ms() - t0 > 1000) { return -MP_ETIMEDOUT; } @@ -196,6 +266,21 @@ STATIC int eth_mac_init(eth_t *self) { // Set MII clock range uint32_t hclk = HAL_RCC_GetHCLKFreq(); uint32_t cr_div; + #if defined(STM32H7) + cr_div = ETH->MACMDIOAR & ~ETH_MACMDIOAR_CR; + if (hclk < 35000000) { + cr_div |= ETH_MACMDIOAR_CR_DIV16; + } else if (hclk < 60000000) { + cr_div |= ETH_MACMDIOAR_CR_DIV26; + } else if (hclk < 100000000) { + cr_div |= ETH_MACMDIOAR_CR_DIV42; + } else if (hclk < 150000000) { + cr_div |= ETH_MACMDIOAR_CR_DIV62; + } else { + cr_div |= ETH_MACMDIOAR_CR_DIV102; + } + ETH->MACMDIOAR = cr_div; + #else if (hclk < 35000000) { cr_div = ETH_MACMIIAR_CR_Div16; } else if (hclk < 60000000) { @@ -208,6 +293,12 @@ STATIC int eth_mac_init(eth_t *self) { cr_div = ETH_MACMIIAR_CR_Div102; } ETH->MACMIIAR = cr_div; + #endif + + #if defined(STM32H7) + // don't skip 32bit words since our desriptors are continuous in memory + ETH->DMACCR &= ~(ETH_DMACCR_DSL_Msk); + #endif // Reset the PHY eth_phy_write(PHY_BCR, PHY_BCR_SOFT_RESET); @@ -249,17 +340,36 @@ STATIC int eth_mac_init(eth_t *self) { uint16_t phy_scsr = eth_phy_read(PHY_SCSR); // Burst mode configuration + #if defined(STM32H7) + ETH->DMASBMR = ETH->DMASBMR & ~ETH_DMASBMR_AAL & ~ETH_DMASBMR_FB; + #else ETH->DMABMR = 0; + #endif mp_hal_delay_ms(2); // Select DMA interrupts + #if defined(STM32H7) + ETH->DMACIER = ETH->DMACIER + | ETH_DMACIER_NIE // enable normal interrupts + | ETH_DMACIER_RIE // enable RX interrupt + ; + #else ETH->DMAIER = ETH_DMAIER_NISE // enable normal interrupts | ETH_DMAIER_RIE // enable RX interrupt ; + #endif // Configure RX descriptor lists for (size_t i = 0; i < RX_BUF_NUM; ++i) { + #if defined(STM32H7) + eth_dma.rx_descr[i].rdes3 = + 1 << RX_DESCR_3_OWN_Pos + | (1 << RX_DESCR_3_BUF1V_Pos) // buf1 address valid + | (1 << RX_DESCR_3_IOC_Pos) // Interrupt Enabled on Completion + ; + eth_dma.rx_descr[i].rdes0 = (uint32_t)ð_dma.rx_buf[i * RX_BUF_SIZE]; // buf 1 address + #else eth_dma.rx_descr[i].rdes0 = 1 << RX_DESCR_0_OWN_Pos; eth_dma.rx_descr[i].rdes1 = 1 << RX_DESCR_1_RCH_Pos // chained @@ -267,31 +377,64 @@ STATIC int eth_mac_init(eth_t *self) { ; eth_dma.rx_descr[i].rdes2 = (uint32_t)ð_dma.rx_buf[i * RX_BUF_SIZE]; eth_dma.rx_descr[i].rdes3 = (uint32_t)ð_dma.rx_descr[(i + 1) % RX_BUF_NUM]; + #endif } + + #if defined(STM32H7) + ETH->DMACRDLAR = (uint32_t)ð_dma.rx_descr[0]; + #else ETH->DMARDLAR = (uint32_t)ð_dma.rx_descr[0]; + #endif eth_dma.rx_descr_idx = 0; // Configure TX descriptor lists for (size_t i = 0; i < TX_BUF_NUM; ++i) { + #if defined(STM32H7) + eth_dma.tx_descr[i].tdes0 = 0; + eth_dma.tx_descr[i].tdes1 = 0; + eth_dma.tx_descr[i].tdes2 = TX_BUF_SIZE & TX_DESCR_2_B1L_Msk; + eth_dma.tx_descr[i].tdes3 = 0; + #else eth_dma.tx_descr[i].tdes0 = 1 << TX_DESCR_0_TCH_Pos; eth_dma.tx_descr[i].tdes1 = 0; eth_dma.tx_descr[i].tdes2 = 0; eth_dma.tx_descr[i].tdes3 = (uint32_t)ð_dma.tx_descr[(i + 1) % TX_BUF_NUM]; + #endif } + + #if defined(STM32H7) + // set number of descriptors and buffers + ETH->DMACTDRLR = TX_BUF_NUM - 1; + ETH->DMACRDRLR = RX_BUF_NUM - 1; + + ETH->DMACTDLAR = (uint32_t)ð_dma.tx_descr[0]; + #else ETH->DMATDLAR = (uint32_t)ð_dma.tx_descr[0]; + #endif eth_dma.tx_descr_idx = 0; // Configure DMA + #if defined(STM32H7) + // read from RX FIFO only after a full frame is written + ETH->MTLRQOMR = ETH_MTLRQOMR_RSF; + // transmission starts when a full packet resides in the Tx queue + ETH->MTLTQOMR = ETH_MTLTQOMR_TSF; + #else ETH->DMAOMR = ETH_DMAOMR_RSF // read from RX FIFO after a full frame is written | ETH_DMAOMR_TSF // transmit when a full frame is in TX FIFO (needed by errata) ; + #endif mp_hal_delay_ms(2); // Select MAC filtering options + #if defined(STM32H7) + ETH->MACPFR = ETH_MACPFR_RA; // pass all frames up + #else ETH->MACFFR = ETH_MACFFR_RA // pass all frames up ; + #endif mp_hal_delay_ms(2); // Set MAC address @@ -318,10 +461,15 @@ STATIC int eth_mac_init(eth_t *self) { mp_hal_delay_ms(2); // Start DMA layer + #if defined(STM32H7) + ETH->DMACRCR |= ETH_DMACRCR_SR; // start RX + ETH->DMACTCR |= ETH_DMACTCR_ST; // start TX + #else ETH->DMAOMR |= ETH_DMAOMR_ST // start TX | ETH_DMAOMR_SR // start RX ; + #endif mp_hal_delay_ms(2); // Enable interrupts @@ -334,9 +482,15 @@ STATIC int eth_mac_init(eth_t *self) { STATIC void eth_mac_deinit(eth_t *self) { (void)self; HAL_NVIC_DisableIRQ(ETH_IRQn); + #if defined(STM32H7) + __HAL_RCC_ETH1MAC_FORCE_RESET(); + __HAL_RCC_ETH1MAC_RELEASE_RESET(); + __HAL_RCC_ETH1MAC_CLK_DISABLE(); + #else __HAL_RCC_ETHMAC_FORCE_RESET(); __HAL_RCC_ETHMAC_RELEASE_RESET(); __HAL_RCC_ETH_CLK_DISABLE(); + #endif } STATIC int eth_tx_buf_get(size_t len, uint8_t **buf) { @@ -348,19 +502,32 @@ STATIC int eth_tx_buf_get(size_t len, uint8_t **buf) { eth_dma_tx_descr_t *tx_descr = ð_dma.tx_descr[eth_dma.tx_descr_idx]; uint32_t t0 = mp_hal_ticks_ms(); for (;;) { + #if defined(STM32H7) + if (!(tx_descr->tdes3 & (1 << TX_DESCR_3_OWN_Pos))) { + break; + } + #else if (!(tx_descr->tdes0 & (1 << TX_DESCR_0_OWN_Pos))) { break; } + #endif if (mp_hal_ticks_ms() - t0 > 1000) { return -MP_ETIMEDOUT; } } + #if defined(STM32H7) + // Update TX descriptor with length and buffer pointer + *buf = ð_dma.tx_buf[eth_dma.tx_descr_idx * TX_BUF_SIZE]; + tx_descr->tdes2 = len & TX_DESCR_2_B1L_Msk; + tx_descr->tdes0 = (uint32_t)*buf; + #else // Update TX descriptor with length, buffer pointer and linked list pointer *buf = ð_dma.tx_buf[eth_dma.tx_descr_idx * TX_BUF_SIZE]; tx_descr->tdes1 = len << TX_DESCR_1_TBS1_Pos; tx_descr->tdes2 = (uint32_t)*buf; tx_descr->tdes3 = (uint32_t)ð_dma.tx_descr[(eth_dma.tx_descr_idx + 1) % TX_BUF_NUM]; + #endif return 0; } @@ -371,6 +538,14 @@ STATIC int eth_tx_buf_send(void) { eth_dma.tx_descr_idx = (eth_dma.tx_descr_idx + 1) % TX_BUF_NUM; // Schedule to send next outgoing frame + #if defined(STM32H7) + tx_descr->tdes3 = + 1 << TX_DESCR_3_OWN_Pos // owned by DMA + | 1 << TX_DESCR_3_LD_Pos // last segment + | 1 << TX_DESCR_3_FD_Pos // first segment + | 3 << TX_DESCR_3_CIC_Pos // enable all checksums inserted by hardware + ; + #else tx_descr->tdes0 = 1 << TX_DESCR_0_OWN_Pos // owned by DMA | 1 << TX_DESCR_0_LS_Pos // last segment @@ -378,13 +553,21 @@ STATIC int eth_tx_buf_send(void) { | 3 << TX_DESCR_0_CIC_Pos // enable all checksums inserted by hardware | 1 << TX_DESCR_0_TCH_Pos // TX descriptor is chained ; + #endif // Notify ETH DMA that there is a new TX descriptor for sending __DMB(); + #if defined(STM32H7) + if (ETH->DMACSR & ETH_DMACSR_TBU) { + ETH->DMACSR = ETH_DMACSR_TBU; + } + ETH->DMACTDTPR = (uint32_t)ð_dma.tx_descr[eth_dma.tx_descr_idx]; + #else if (ETH->DMASR & ETH_DMASR_TBUS) { ETH->DMASR = ETH_DMASR_TBUS; ETH->DMATPDR = 0; } + #endif return 0; } @@ -396,6 +579,12 @@ STATIC void eth_dma_rx_free(void) { eth_dma.rx_descr_idx = (eth_dma.rx_descr_idx + 1) % RX_BUF_NUM; // Schedule to get next incoming frame + #if defined(STM32H7) + rx_descr->rdes0 = (uint32_t)buf; + rx_descr->rdes3 = 1 << RX_DESCR_3_OWN_Pos; // owned by DMA + rx_descr->rdes3 |= 1 << RX_DESCR_3_BUF1V_Pos; // buf 1 address valid + rx_descr->rdes3 |= 1 << RX_DESCR_3_IOC_Pos; // Interrupt Enabled on Completion + #else rx_descr->rdes1 = 1 << RX_DESCR_1_RCH_Pos // RX descriptor is chained | RX_BUF_SIZE << RX_DESCR_1_RBS1_Pos // maximum buffer length @@ -403,28 +592,60 @@ STATIC void eth_dma_rx_free(void) { rx_descr->rdes2 = (uint32_t)buf; rx_descr->rdes3 = (uint32_t)ð_dma.rx_descr[eth_dma.rx_descr_idx]; rx_descr->rdes0 = 1 << RX_DESCR_0_OWN_Pos; // owned by DMA + #endif // Notify ETH DMA that there is a new RX descriptor available __DMB(); + #if defined(STM32H7) + ETH->DMACRDTPR = (uint32_t)&rx_descr[eth_dma.rx_descr_idx]; + #else ETH->DMARPDR = 0; + #endif } void ETH_IRQHandler(void) { + #if defined(STM32H7) + uint32_t sr = ETH->DMACSR; + ETH->DMACSR = ETH_DMACSR_NIS; + uint32_t rx_interrupt = sr & ETH_DMACSR_RI; + #else uint32_t sr = ETH->DMASR; ETH->DMASR = ETH_DMASR_NIS; - if (sr & ETH_DMASR_RS) { + uint32_t rx_interrupt = sr & ETH_DMASR_RS; + #endif + if (rx_interrupt) { + #if defined(STM32H7) + ETH->DMACSR = ETH_DMACSR_RI; + #else ETH->DMASR = ETH_DMASR_RS; + #endif for (;;) { + #if defined(STM32H7) + eth_dma_rx_descr_t *rx_descr_l = ð_dma.rx_descr[eth_dma.rx_descr_idx]; + if (rx_descr_l->rdes3 & (1 << RX_DESCR_3_OWN_Pos)) { + // No more RX descriptors ready to read + break; + } + #else eth_dma_rx_descr_t *rx_descr = ð_dma.rx_descr[eth_dma.rx_descr_idx]; if (rx_descr->rdes0 & (1 << RX_DESCR_0_OWN_Pos)) { // No more RX descriptors ready to read break; } + #endif // Get RX buffer containing new frame + #if defined(STM32H7) + size_t len = (rx_descr_l->rdes3 & RX_DESCR_3_PL_Msk); + #else size_t len = (rx_descr->rdes0 & RX_DESCR_0_FL_Msk) >> RX_DESCR_0_FL_Pos; + #endif len -= 4; // discard CRC at end + #if defined(STM32H7) + uint8_t *buf = ð_dma.rx_buf[eth_dma.rx_descr_idx * RX_BUF_SIZE]; + #else uint8_t *buf = (uint8_t *)rx_descr->rdes2; + #endif // Process frame eth_process_frame(ð_instance, len, buf);