summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReinhard Feger <feg@LT-Feger.icie.jku.at>2020-07-24 23:08:41 +0200
committerDamien George <damien@micropython.org>2020-12-08 15:27:44 +1100
commitd986b2012289cecba1f249c4e29446a0bfe680a2 (patch)
treedc22c845516e5fee17c02dc7e2521862720f550b
parentcd61fc8e44202feb20a4c52b56f75740aa72d075 (diff)
stm32/eth: Add support for H7 processors.
-rw-r--r--ports/stm32/eth.c231
1 files changed, 226 insertions, 5 deletions
diff --git a/ports/stm32/eth.c b/ports/stm32/eth.c
index 33d20707e..7a08e8c28 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)&eth_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)&eth_dma.rx_buf[i * RX_BUF_SIZE];
eth_dma.rx_descr[i].rdes3 = (uint32_t)&eth_dma.rx_descr[(i + 1) % RX_BUF_NUM];
+ #endif
}
+
+ #if defined(STM32H7)
+ ETH->DMACRDLAR = (uint32_t)&eth_dma.rx_descr[0];
+ #else
ETH->DMARDLAR = (uint32_t)&eth_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)&eth_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)&eth_dma.tx_descr[0];
+ #else
ETH->DMATDLAR = (uint32_t)&eth_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 = &eth_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 = &eth_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 = &eth_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)&eth_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)&eth_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)&eth_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 = &eth_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 = &eth_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 = &eth_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(&eth_instance, len, buf);