summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien George <damien@micropython.org>2025-07-26 16:22:36 +1000
committerDamien George <damien@micropython.org>2025-11-20 13:01:35 +1100
commit5a69d4756751b92e13a6ea9a0c7b755dd3b43f7c (patch)
tree9857858d5a81757641a4858e948be419d145c212
parent2ad1d29747df1f35c638b32477684c6e141d0f81 (diff)
stm32/eth: Add support for Ethernet on N6 MCUs.
This adds working support for 100MBit Ethernet on N6 MCUs. Signed-off-by: Damien George <damien@micropython.org>
-rw-r--r--ports/stm32/boards/stm32n657_af.csv11
-rw-r--r--ports/stm32/boards/stm32n6xx_hal_conf_base.h1
-rw-r--r--ports/stm32/eth.c214
-rw-r--r--ports/stm32/main.c7
-rw-r--r--ports/stm32/powerctrlboot.c5
5 files changed, 203 insertions, 35 deletions
diff --git a/ports/stm32/boards/stm32n657_af.csv b/ports/stm32/boards/stm32n657_af.csv
index 220d27b3f..d7af19399 100644
--- a/ports/stm32/boards/stm32n657_af.csv
+++ b/ports/stm32/boards/stm32n657_af.csv
@@ -20,6 +20,7 @@ PortC,PC9 , , , ,
PortC,PC10, , , , , , , , , , ,SDMMC1_D2 , , , , , ,
PortC,PC11, , , , , , , , , , ,SDMMC1_D3 , , , , , ,
PortC,PC12, , , , , , , , , , ,SDMMC1_CK , , , , , ,
+PortD,PD1 , , , , , , , , , , , ,ETH1_MDC , , , , ,
PortD,PD2 , , , , , , , , , , , ,SDMMC2_CK , , , , ,
PortD,PD5 , , , , , , , ,USART2_TX , , , , , , , , ,
PortD,PD6 , , , , ,TIM15_CH2 , , , , , , , , , , , ,
@@ -27,6 +28,7 @@ PortD,PD7 , , , ,
PortD,PD8 , , , , , , , ,USART3_TX , , , , , , , , ,
PortD,PD9 , , , , , , , ,USART3_RX , , , , , , , , ,
PortD,PD11, , , , , ,SPI2_MISO , , , , , , , , , , ,
+PortD,PD12, , , , , , , , , , , ,ETH1_MDIO , , , , ,
PortD,PD13, , ,TIM4_CH2 , , , , , , , , , , , , , ,
PortE,PE5 , , , , , , , ,USART1_TX , , , , , , , , ,
PortE,PE6 , , , , , , , ,USART1_RX , , , , , , , , ,
@@ -38,12 +40,21 @@ PortE,PE13, , , ,
PortE,PE14, , , , ,I2C4_SDA , , , , , , , , , , , ,
PortE,PE15, , , , , ,SPI5_SCK , , , , , , , , , , ,
PortF,PF3 , , , , , , , ,USART2_RTS , , , , , , , , ,ADC1_INP16
+PortF,PF4 , , , , , , , , , , , ,ETH1_MDIO , , , , ,
PortF,PF6 , , , , , , , ,USART2_RX , , , , , , , , ,
+PortF,PF7 , , , , , , , , , , , ,ETH1_RMII_REF_CLK , , , , ,
+PortF,PF10, , , , , , , , , , , ,ETH1_RMII_CRS_DV , , , , ,
+PortF,PF11, , , , , , , , , , , ,ETH1_RMII_TX_EN , , , , ,
+PortF,PF12, , , , , , , , , , , ,ETH1_RMII_TXD0 , , , , ,
+PortF,PF13, , , , , , , , , , , ,ETH1_RMII_TXD1 , , , , ,
+PortF,PF14, , , , , , , , , , , ,ETH1_RMII_RXD0 , , , , ,
+PortF,PF15, , , , , , , , , , , ,ETH1_RMII_RXD1 , , , , ,
PortG,PG0 , , ,TIM12_CH1 , , , , , , , , , , , , , ,
PortG,PG1 , , , , , ,SPI5_MISO , , , , , , , , , , ,
PortG,PG2 , , , , , ,SPI5_MOSI , , , , , , , , , , ,
PortG,PG5 , , , , , , , ,USART2_CTS , , , , , , , , ,
PortG,PG8 , , , , , , , , , , , ,SDMMC2_D1 , , , , ,
+PortG,PG11, , , , , , , , , , , ,ETH1_MDC , , , , ,
PortG,PG12, ,TIM17_CH1 , , , , , , , , , , , , , , ,
PortG,PG13, , ,TIM4_CH1 , , , , ,USART3_RTS , , , , , , , , ,
PortG,PG15, , , , , , , , , , , , , , , , ,ADC12_INP7/ADC12_INN3
diff --git a/ports/stm32/boards/stm32n6xx_hal_conf_base.h b/ports/stm32/boards/stm32n6xx_hal_conf_base.h
index 641a003d8..87556cf15 100644
--- a/ports/stm32/boards/stm32n6xx_hal_conf_base.h
+++ b/ports/stm32/boards/stm32n6xx_hal_conf_base.h
@@ -160,7 +160,6 @@
#include "stm32n6xx_hal_dcmipp.h"
#include "stm32n6xx_hal_dma2d.h"
#include "stm32n6xx_hal_dts.h"
-#include "stm32n6xx_hal_eth.h"
#include "stm32n6xx_hal_exti.h"
#include "stm32n6xx_hal_fdcan.h"
#include "stm32n6xx_hal_gfxmmu.h"
diff --git a/ports/stm32/eth.c b/ports/stm32/eth.c
index 9f6553068..0f8af5311 100644
--- a/ports/stm32/eth.c
+++ b/ports/stm32/eth.c
@@ -41,8 +41,19 @@
#include "lwip/dhcp.h"
#include "netif/ethernet.h"
+// Register and IRQ compatibility for STM32N6.
+#if defined(STM32N6)
+#define ETH ETH1
+#define ETH_MACMDIOAR_MB (ETH_MACMDIOAR_GB)
+#define ETH_MACMDIOAR_MOC_Msk (ETH_MACMDIOAR_GOC_Msk)
+#define ETH_MACMDIOAR_MOC_WR (ETH_MACMDIOAR_GOC_0)
+#define ETH_MACMDIOAR_MOC_RD (ETH_MACMDIOAR_GOC_1 | ETH_MACMDIOAR_GOC_0)
+#define ETH_IRQn ETH1_IRQn
+#define ETH_IRQHandler ETH1_IRQHandler
+#endif
+
// ETH DMA RX and TX descriptor definitions
-#if defined(STM32H5)
+#if defined(STM32H5) || defined(STM32N6)
#define RX_DESCR_3_OWN_Pos (31)
#define RX_DESCR_3_IOC_Pos (30)
#define RX_DESCR_3_BUF1V_Pos (24)
@@ -85,6 +96,13 @@
#define TX_DESCR_1_TBS1_Pos (0)
#endif
+// Static alternate function macro.
+#if defined(STM32N6)
+#define STATIC_AF_ETH(signal) STATIC_AF_ETH1_##signal
+#else
+#define STATIC_AF_ETH(signal) STATIC_AF_ETH_##signal
+#endif
+
// Configuration values
#define PHY_INIT_TIMEOUT_MS (10000)
@@ -95,6 +113,12 @@
#define RX_BUF_NUM (5)
#define TX_BUF_NUM (5)
+#if defined(STM32N6)
+// The N6 has two DMA channels, so use one for RX and one for TX.
+#define RX_DMA_CH (0)
+#define TX_DMA_CH (1)
+#endif
+
typedef struct _eth_dma_rx_descr_t {
volatile uint32_t rdes0, rdes1, rdes2, rdes3;
} eth_dma_rx_descr_t;
@@ -129,7 +153,7 @@ static void eth_mac_deinit(eth_t *self);
static void eth_process_frame(eth_t *self, size_t len, const uint8_t *buf);
void eth_phy_write(uint32_t phy_addr, uint32_t reg, uint32_t val) {
- #if defined(STM32H5) || defined(STM32H7)
+ #if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
while (ETH->MACMDIOAR & ETH_MACMDIOAR_MB) {
}
uint32_t ar = ETH->MACMDIOAR;
@@ -157,7 +181,7 @@ void eth_phy_write(uint32_t phy_addr, uint32_t reg, uint32_t val) {
}
uint32_t eth_phy_read(uint32_t phy_addr, uint32_t reg) {
- #if defined(STM32H5) || defined(STM32H7)
+ #if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
while (ETH->MACMDIOAR & ETH_MACMDIOAR_MB) {
}
uint32_t ar = ETH->MACMDIOAR;
@@ -197,15 +221,15 @@ int eth_init(eth_t *self, int mac_idx, uint32_t phy_addr, int phy_type) {
}
// 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_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);
- mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RMII_TX_EN, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH_RMII_TX_EN);
- 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);
+ 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_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));
+ mp_hal_pin_config_alt_static(MICROPY_HW_ETH_RMII_TX_EN, MP_HAL_PIN_MODE_ALT, MP_HAL_PIN_PULL_NONE, STATIC_AF_ETH(RMII_TX_EN));
+ 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));
// Enable peripheral clock
#if defined(STM32H5)
@@ -216,6 +240,11 @@ int eth_init(eth_t *self, int mac_idx, uint32_t phy_addr, int phy_type) {
__HAL_RCC_ETH1MAC_CLK_ENABLE();
__HAL_RCC_ETH1TX_CLK_ENABLE();
__HAL_RCC_ETH1RX_CLK_ENABLE();
+ #elif defined(STM32N6)
+ __HAL_RCC_ETH1_CLK_ENABLE();
+ __HAL_RCC_ETH1MAC_CLK_ENABLE();
+ __HAL_RCC_ETH1TX_CLK_ENABLE();
+ __HAL_RCC_ETH1RX_CLK_ENABLE();
#else
__HAL_RCC_ETH_CLK_ENABLE();
#endif
@@ -229,7 +258,7 @@ void eth_set_trace(eth_t *self, uint32_t value) {
static int eth_mac_init(eth_t *self) {
// Configure MPU
uint32_t irq_state = mpu_config_start();
- #if defined(STM32H5)
+ #if defined(STM32H5) || defined(STM32N6)
mpu_config_region(MPU_REGION_ETH, (uint32_t)&eth_dma, MPU_CONFIG_ETH(16 * 1024));
#else
mpu_config_region(MPU_REGION_ETH, (uint32_t)&eth_dma, MPU_CONFIG_ETH(MPU_REGION_SIZE_16KB));
@@ -241,16 +270,29 @@ static int eth_mac_init(eth_t *self) {
__HAL_RCC_ETH_FORCE_RESET();
#elif defined(STM32H7)
__HAL_RCC_ETH1MAC_FORCE_RESET();
+ #elif defined(STM32N6)
+ __HAL_RCC_ETH1_FORCE_RESET();
#else
__HAL_RCC_ETHMAC_FORCE_RESET();
#endif
+ // Select clock sources.
+ #if defined(STM32N6)
+ LL_RCC_SetETHREFTXClockSource(LL_RCC_ETH1REFTX_CLKSOURCE_EXT); // max 25MHz
+ LL_RCC_SetETHREFRXClockSource(LL_RCC_ETH1REFRX_CLKSOURCE_EXT); // max 125MHz
+ LL_RCC_SetETHClockSource(LL_RCC_ETH1_CLKSOURCE_IC12); // max 125MHz
+ LL_RCC_SetETH1PTPDivider(LL_RCC_ETH1PTP_DIV_1);
+ LL_RCC_SetETHPTPClockSource(LL_RCC_ETH1PTP_CLKSOURCE_HCLK); // max 200MHz
+ #endif
+
// Select RMII interface
#if defined(STM32H5)
__HAL_RCC_SBS_CLK_ENABLE();
SBS->PMCR = (SBS->PMCR & ~SBS_PMCR_ETH_SEL_PHY_Msk) | SBS_PMCR_ETH_SEL_PHY_2;
#elif defined(STM32H7)
SYSCFG->PMCR = (SYSCFG->PMCR & ~SYSCFG_PMCR_EPIS_SEL_Msk) | SYSCFG_PMCR_EPIS_SEL_2;
+ #elif defined(STM32N6)
+ LL_RCC_SetETHPHYInterface(LL_RCC_ETH1PHY_IF_RMII);
#else
__HAL_RCC_SYSCFG_CLK_ENABLE();
SYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL;
@@ -268,6 +310,13 @@ static int eth_mac_init(eth_t *self) {
__HAL_RCC_ETH1MAC_CLK_SLEEP_ENABLE();
__HAL_RCC_ETH1TX_CLK_SLEEP_ENABLE();
__HAL_RCC_ETH1RX_CLK_SLEEP_ENABLE();
+ #elif defined(STM32N6)
+ __HAL_RCC_ETH1_RELEASE_RESET();
+
+ __HAL_RCC_ETH1_CLK_SLEEP_ENABLE();
+ __HAL_RCC_ETH1MAC_CLK_SLEEP_ENABLE();
+ __HAL_RCC_ETH1TX_CLK_SLEEP_ENABLE();
+ __HAL_RCC_ETH1RX_CLK_SLEEP_ENABLE();
#else
__HAL_RCC_ETHMAC_RELEASE_RESET();
@@ -277,7 +326,7 @@ static int eth_mac_init(eth_t *self) {
#endif
// Do a soft reset of the MAC core
- #if defined(STM32H5) || defined(STM32H7)
+ #if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
#define ETH_SOFT_RESET(eth) do { eth->DMAMR = ETH_DMAMR_SWR; } while (0)
#define ETH_IS_RESET(eth) (eth->DMAMR & ETH_DMAMR_SWR)
#else
@@ -299,7 +348,7 @@ static int eth_mac_init(eth_t *self) {
// Set MII clock range
uint32_t hclk = HAL_RCC_GetHCLKFreq();
uint32_t cr_div;
- #if defined(STM32H5)
+ #if defined(STM32H5) || defined(STM32N6)
cr_div = ETH->MACMDIOAR & ~ETH_MACMDIOAR_CR;
if (hclk < 35000000) {
cr_div |= ETH_MACMDIOAR_CR_DIV16;
@@ -311,8 +360,17 @@ static int eth_mac_init(eth_t *self) {
cr_div |= ETH_MACMDIOAR_CR_DIV62;
} else if (hclk < 250000000) {
cr_div |= ETH_MACMDIOAR_CR_DIV102;
+ #if defined(STM32H5)
} else {
cr_div |= ETH_MACMDIOAR_CR_DIV124;
+ #else
+ } else if (hclk < 300000000) {
+ cr_div |= ETH_MACMDIOAR_CR_DIV124;
+ } else if (hclk < 500000000) {
+ cr_div |= ETH_MACMDIOAR_CR_DIV204;
+ } else {
+ cr_div |= ETH_MACMDIOAR_CR_DIV324;
+ #endif
}
ETH->MACMDIOAR = cr_div;
#elif defined(STM32H7)
@@ -344,9 +402,17 @@ static int eth_mac_init(eth_t *self) {
ETH->MACMIIAR = cr_div;
#endif
+ #if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
+ // Configure the MAC 1-us tick counter register.
+ WRITE_REG(ETH->MAC1USTCR, HAL_RCC_GetHCLKFreq() / 1000000U - 1U);
+ #endif
+
#if defined(STM32H5) || defined(STM32H7)
// don't skip 32bit words since our descriptors are continuous in memory
ETH->DMACCR &= ~(ETH_DMACCR_DSL_Msk);
+ #elif defined(STM32N6)
+ ETH->DMA_CH[RX_DMA_CH].DMACCR &= ~(ETH_DMACxCR_DSL_Msk);
+ ETH->DMA_CH[TX_DMA_CH].DMACCR &= ~(ETH_DMACxCR_DSL_Msk);
#endif
// Reset the PHY
@@ -397,7 +463,7 @@ static int eth_mac_init(eth_t *self) {
uint16_t phy_scsr = self->phy_get_link_status(self->phy_addr);
// Burst mode configuration
- #if defined(STM32H5) || defined(STM32H7)
+ #if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
ETH->DMASBMR = ETH->DMASBMR & ~ETH_DMASBMR_AAL & ~ETH_DMASBMR_FB;
#else
ETH->DMABMR = 0;
@@ -410,6 +476,11 @@ static int eth_mac_init(eth_t *self) {
| ETH_DMACIER_NIE // enable normal interrupts
| ETH_DMACIER_RIE // enable RX interrupt
;
+ #elif defined(STM32N6)
+ ETH->DMA_CH[RX_DMA_CH].DMACIER =
+ ETH_DMACxIER_NIE // enable normal interrupts
+ | ETH_DMACxIER_RIE // enable RX interrupt
+ ;
#else
ETH->DMAIER =
ETH_DMAIER_NISE // enable normal interrupts
@@ -419,7 +490,7 @@ static int eth_mac_init(eth_t *self) {
// Configure RX descriptor lists
for (size_t i = 0; i < RX_BUF_NUM; ++i) {
- #if defined(STM32H5) || defined(STM32H7)
+ #if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
eth_dma.rx_descr[i].rdes3 =
1 << RX_DESCR_3_OWN_Pos
| (1 << RX_DESCR_3_BUF1V_Pos) // buf1 address valid
@@ -439,6 +510,11 @@ static int eth_mac_init(eth_t *self) {
#if defined(STM32H5) || defined(STM32H7)
ETH->DMACRDLAR = (uint32_t)&eth_dma.rx_descr[0];
+ #elif defined(STM32N6)
+ // Set number of RX descriptors and buffer pointers.
+ ETH->DMA_CH[RX_DMA_CH].DMACRXRLR = RX_BUF_NUM - 1;
+ ETH->DMA_CH[RX_DMA_CH].DMACRXDLAR = (uint32_t)&eth_dma.rx_descr[0];
+ ETH->DMA_CH[RX_DMA_CH].DMACRXDTPR = (uint32_t)&eth_dma.rx_descr[RX_BUF_NUM - 1];
#else
ETH->DMARDLAR = (uint32_t)&eth_dma.rx_descr[0];
#endif
@@ -446,7 +522,7 @@ static int eth_mac_init(eth_t *self) {
// Configure TX descriptor lists
for (size_t i = 0; i < TX_BUF_NUM; ++i) {
- #if defined(STM32H5) || defined(STM32H7)
+ #if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
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;
@@ -465,6 +541,11 @@ static int eth_mac_init(eth_t *self) {
ETH->DMACRDRLR = RX_BUF_NUM - 1;
ETH->DMACTDLAR = (uint32_t)&eth_dma.tx_descr[0];
+ #elif defined(STM32N6)
+ // Set number of TX descriptors and buffer pointers.
+ ETH->DMA_CH[TX_DMA_CH].DMACTXRLR = TX_BUF_NUM - 1;
+ ETH->DMA_CH[TX_DMA_CH].DMACTXDLAR = (uint32_t)&eth_dma.tx_descr[0];
+ ETH->DMA_CH[TX_DMA_CH].DMACTXDTPR = (uint32_t)&eth_dma.tx_descr[0];
#else
ETH->DMATDLAR = (uint32_t)&eth_dma.tx_descr[0];
#endif
@@ -476,6 +557,11 @@ static int eth_mac_init(eth_t *self) {
ETH->MTLRQOMR = ETH_MTLRQOMR_RSF;
// transmission starts when a full packet resides in the Tx queue
ETH->MTLTQOMR = ETH_MTLTQOMR_TSF;
+ #elif defined(STM32N6)
+ // read from RX FIFO only after a full frame is written
+ ETH->MTL_QUEUE[0].MTLRXQOMR = ETH_MTLRXQxOMR_RSF;
+ // transmission starts when a full packet resides in the Tx queue
+ ETH->MTL_QUEUE[0].MTLTXQOMR = ETH_MTLTXQxOMR_TSF;
#else
ETH->DMAOMR =
ETH_DMAOMR_RSF // read from RX FIFO after a full frame is written
@@ -485,7 +571,7 @@ static int eth_mac_init(eth_t *self) {
mp_hal_delay_ms(2);
// Select MAC filtering options
- #if defined(STM32H5) || defined(STM32H7)
+ #if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
ETH->MACPFR = ETH_MACPFR_RA; // pass all frames up
#else
ETH->MACFFR =
@@ -501,15 +587,47 @@ static int eth_mac_init(eth_t *self) {
ETH->MACA0LR = mac[3] << 24 | mac[2] << 16 | mac[1] << 8 | mac[0];
mp_hal_delay_ms(2);
+ // Work out the line speed configuration for MACCR.
+ uint32_t maccr = 0;
+ if (phy_scsr & PHY_SPEED_100HALF) {
+ maccr |= ETH_MACCR_FES;
+ }
+ if (phy_scsr & PHY_DUPLEX) {
+ maccr |= ETH_MACCR_DM;
+ }
+
+ #if defined(STM32N6)
+
+ maccr |=
+ ETH_MACCR_IPG_96BIT
+ | ETH_MACCR_SARC_REPADDR0
+ | ETH_MACCR_IPC
+ | ETH_MACCR_PS
+ | ETH_MACCR_BL_10
+ | ETH_MACCR_PRELEN_7;
+
+ ETH->MACCR = maccr;
+ ETH->MACECR = 0x618U;
+ ETH->MACWTR = ETH_MACWTR_WTO_2KB;
+ ETH->MACQ0TXFCR = ETH_MACQ0TXFCR_PLT_MINUS4;
+ ETH->MACRXFCR = 0;
+ ETH->MACRXQC0R = ETH_MACRXQC0R_RXQ0EN_GT | ETH_MACRXQC0R_RXQ1EN_NOT;
+
+ ETH->MTLOMR = ETH_MTLOMR_SCHALG_SP | ETH_MTLOMR_RAA_SP;
+ ETH->MTLRXQDMAMR = ETH_MTLRXQDMAMR_Q0MDMACH_DMACH0 | ETH_MTLRXQDMAMR_Q1MDMACH_DMACH1;
+ ETH->MTL_QUEUE[0].MTLTXQOMR = ETH_MTLTXQxOMR_TXQEN_EN | ETH_MTLTXQxOMR_TSF | 7 << ETH_MTLTXQxOMR_TQS_Pos;
+ ETH->MTL_QUEUE[1].MTLTXQOMR = ETH_MTLTXQxOMR_TXQEN_EN | ETH_MTLTXQxOMR_TSF | 7 << ETH_MTLTXQxOMR_TQS_Pos;
+ ETH->MTL_QUEUE[0].MTLRXQOMR = ETH_MTLRXQxOMR_RSF | 15 << ETH_MTLRXQxOMR_RQS_Pos;
+ ETH->MTL_QUEUE[1].MTLRXQOMR = ETH_MTLRXQxOMR_RSF | 15 << ETH_MTLRXQxOMR_RQS_Pos;
+
+ #else
+
// Set main MAC control register
- ETH->MACCR =
- phy_scsr == PHY_SPEED_10FULL ? ETH_MACCR_DM
- : phy_scsr == PHY_SPEED_100HALF ? ETH_MACCR_FES
- : phy_scsr == PHY_SPEED_100FULL ? (ETH_MACCR_FES | ETH_MACCR_DM)
- : 0
- ;
+ ETH->MACCR = maccr;
mp_hal_delay_ms(2);
+ #endif
+
// Start MAC layer
ETH->MACCR |=
ETH_MACCR_TE // enable TX
@@ -521,6 +639,15 @@ static int eth_mac_init(eth_t *self) {
#if defined(STM32H5) || defined(STM32H7)
ETH->DMACRCR |= ETH_DMACRCR_SR; // start RX
ETH->DMACTCR |= ETH_DMACTCR_ST; // start TX
+ #elif defined(STM32N6)
+ ETH->MTL_QUEUE[0].MTLTXQOMR |= ETH_MTLTXQxOMR_FTQ; // flush TX FIFO
+ ETH->MTL_QUEUE[1].MTLTXQOMR |= ETH_MTLTXQxOMR_FTQ; // flush TX FIFO
+ ETH->DMA_CH[RX_DMA_CH].DMACRXCR = RX_BUF_SIZE << ETH_DMACxRXCR_RBSZ_Pos;
+ ETH->DMA_CH[RX_DMA_CH].DMACRXCR |= ETH_DMACxRXCR_SR; // start RX
+ ETH->DMA_CH[TX_DMA_CH].DMACTXCR = 4 << ETH_DMACxTXCR_TXPBL_Pos;
+ ETH->DMA_CH[TX_DMA_CH].DMACTXCR |= ETH_DMACxTXCR_ST; // start TX
+ ETH->DMA_CH[RX_DMA_CH].DMACSR |= ETH_DMACxSR_TPS | ETH_DMACxSR_RPS; // clear TX/RX process stopped flags
+ ETH->DMA_CH[TX_DMA_CH].DMACSR |= ETH_DMACxSR_TPS | ETH_DMACxSR_RPS; // clear TX/RX process stopped flags
#else
ETH->DMAOMR |=
ETH_DMAOMR_ST // start TX
@@ -547,6 +674,10 @@ static void eth_mac_deinit(eth_t *self) {
__HAL_RCC_ETH1MAC_FORCE_RESET();
__HAL_RCC_ETH1MAC_RELEASE_RESET();
__HAL_RCC_ETH1MAC_CLK_DISABLE();
+ #elif defined(STM32N6)
+ __HAL_RCC_ETH1_FORCE_RESET();
+ __HAL_RCC_ETH1_RELEASE_RESET();
+ __HAL_RCC_ETH1_CLK_DISABLE();
#else
__HAL_RCC_ETHMAC_FORCE_RESET();
__HAL_RCC_ETHMAC_RELEASE_RESET();
@@ -563,7 +694,7 @@ 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(STM32H5) || defined(STM32H7)
+ #if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
if (!(tx_descr->tdes3 & (1 << TX_DESCR_3_OWN_Pos))) {
break;
}
@@ -577,7 +708,7 @@ static int eth_tx_buf_get(size_t len, uint8_t **buf) {
}
}
- #if defined(STM32H5) || defined(STM32H7)
+ #if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
// 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;
@@ -599,7 +730,7 @@ 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(STM32H5) || defined(STM32H7)
+ #if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
tx_descr->tdes3 =
1 << TX_DESCR_3_OWN_Pos // owned by DMA
| 1 << TX_DESCR_3_LD_Pos // last segment
@@ -623,6 +754,11 @@ static int eth_tx_buf_send(void) {
ETH->DMACSR = ETH_DMACSR_TBU;
}
ETH->DMACTDTPR = (uint32_t)&eth_dma.tx_descr[eth_dma.tx_descr_idx];
+ #elif defined(STM32N6)
+ if (ETH->DMA_CH[TX_DMA_CH].DMACSR & ETH_DMACxSR_TBU) {
+ ETH->DMA_CH[TX_DMA_CH].DMACSR = ETH_DMACxSR_TBU;
+ }
+ ETH->DMA_CH[TX_DMA_CH].DMACTXDTPR = (uint32_t)&eth_dma.tx_descr[eth_dma.tx_descr_idx];
#else
if (ETH->DMASR & ETH_DMASR_TBUS) {
ETH->DMASR = ETH_DMASR_TBUS;
@@ -640,7 +776,7 @@ 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(STM32H5) || defined(STM32H7)
+ #if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
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
@@ -659,16 +795,24 @@ static void eth_dma_rx_free(void) {
__DMB();
#if defined(STM32H5) || defined(STM32H7)
ETH->DMACRDTPR = (uint32_t)&rx_descr[eth_dma.rx_descr_idx];
+ #elif defined(STM32N6)
+ ETH->DMA_CH[RX_DMA_CH].DMACRXDTPR = (uint32_t)&rx_descr[eth_dma.rx_descr_idx];
#else
ETH->DMARPDR = 0;
#endif
}
void ETH_IRQHandler(void) {
+ MP_STATIC_ASSERT(ETH_IRQn > 0);
+
#if defined(STM32H5) || defined(STM32H7)
uint32_t sr = ETH->DMACSR;
ETH->DMACSR = ETH_DMACSR_NIS;
uint32_t rx_interrupt = sr & ETH_DMACSR_RI;
+ #elif defined(STM32N6)
+ uint32_t sr = ETH->DMA_CH[RX_DMA_CH].DMACSR;
+ ETH->DMA_CH[RX_DMA_CH].DMACSR = ETH_DMACxSR_NIS;
+ uint32_t rx_interrupt = sr & ETH_DMACxSR_RI;
#else
uint32_t sr = ETH->DMASR;
ETH->DMASR = ETH_DMASR_NIS;
@@ -677,11 +821,13 @@ void ETH_IRQHandler(void) {
if (rx_interrupt) {
#if defined(STM32H5) || defined(STM32H7)
ETH->DMACSR = ETH_DMACSR_RI;
+ #elif defined(STM32N6)
+ ETH->DMA_CH[RX_DMA_CH].DMACSR = ETH_DMACxSR_RI;
#else
ETH->DMASR = ETH_DMASR_RS;
#endif
for (;;) {
- #if defined(STM32H5) || defined(STM32H7)
+ #if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
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
@@ -696,13 +842,13 @@ void ETH_IRQHandler(void) {
#endif
// Get RX buffer containing new frame
- #if defined(STM32H5) || defined(STM32H7)
+ #if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
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(STM32H5) || defined(STM32H7)
+ #if defined(STM32H5) || defined(STM32H7) || defined(STM32N6)
uint8_t *buf = &eth_dma.rx_buf[eth_dma.rx_descr_idx * RX_BUF_SIZE];
#else
uint8_t *buf = (uint8_t *)rx_descr->rdes2;
@@ -875,6 +1021,8 @@ void eth_low_power_mode(eth_t *self, bool enable) {
// Enable eth clock
#if defined(STM32H7)
__HAL_RCC_ETH1MAC_CLK_ENABLE();
+ #elif defined(STM32N6)
+ __HAL_RCC_ETH1_CLK_ENABLE();
#else
__HAL_RCC_ETH_CLK_ENABLE();
#endif
@@ -886,6 +1034,8 @@ void eth_low_power_mode(eth_t *self, bool enable) {
// Disable eth clock.
#if defined(STM32H7)
__HAL_RCC_ETH1MAC_CLK_DISABLE();
+ #elif defined(STM32N6)
+ __HAL_RCC_ETH1_CLK_DISABLE();
#else
__HAL_RCC_ETH_CLK_DISABLE();
#endif
diff --git a/ports/stm32/main.c b/ports/stm32/main.c
index 2d97adb1d..6f7413694 100644
--- a/ports/stm32/main.c
+++ b/ports/stm32/main.c
@@ -318,11 +318,14 @@ static void risaf_init(void) {
rimc_master.MasterCID = RIF_CID_1;
rimc_master.SecPriv = RIF_ATTRIBUTE_SEC | RIF_ATTRIBUTE_PRIV;
- HAL_RIF_RISC_SetSlaveSecureAttributes(RIF_RISC_PERIPH_INDEX_ADC12, RIF_ATTRIBUTE_SEC | RIF_ATTRIBUTE_PRIV);
HAL_RIF_RIMC_ConfigMasterAttributes(RIF_MASTER_INDEX_SDMMC1, &rimc_master);
- HAL_RIF_RISC_SetSlaveSecureAttributes(RIF_RISC_PERIPH_INDEX_SDMMC1, RIF_ATTRIBUTE_SEC | RIF_ATTRIBUTE_PRIV);
HAL_RIF_RIMC_ConfigMasterAttributes(RIF_MASTER_INDEX_SDMMC2, &rimc_master);
+ HAL_RIF_RIMC_ConfigMasterAttributes(RIF_MASTER_INDEX_ETH1, &rimc_master);
+
+ HAL_RIF_RISC_SetSlaveSecureAttributes(RIF_RISC_PERIPH_INDEX_ADC12, RIF_ATTRIBUTE_SEC | RIF_ATTRIBUTE_PRIV);
+ HAL_RIF_RISC_SetSlaveSecureAttributes(RIF_RISC_PERIPH_INDEX_SDMMC1, RIF_ATTRIBUTE_SEC | RIF_ATTRIBUTE_PRIV);
HAL_RIF_RISC_SetSlaveSecureAttributes(RIF_RISC_PERIPH_INDEX_SDMMC2, RIF_ATTRIBUTE_SEC | RIF_ATTRIBUTE_PRIV);
+ HAL_RIF_RISC_SetSlaveSecureAttributes(RIF_RISC_PERIPH_INDEX_ETH1, RIF_ATTRIBUTE_SEC | RIF_ATTRIBUTE_PRIV);
}
#endif
diff --git a/ports/stm32/powerctrlboot.c b/ports/stm32/powerctrlboot.c
index a8ef8c34a..7baaa6773 100644
--- a/ports/stm32/powerctrlboot.c
+++ b/ports/stm32/powerctrlboot.c
@@ -482,6 +482,11 @@ void SystemClock_Config(void) {
LL_RCC_IC11_SetDivider(1);
LL_RCC_IC11_Enable();
+ // Configure IC12 at 100MHz for ETH1CLKSEL.
+ LL_RCC_IC12_SetSource(LL_RCC_ICCLKSOURCE_PLL1);
+ LL_RCC_IC12_SetDivider(8);
+ LL_RCC_IC12_Enable();
+
// Configure IC14 at 100MHz for slower peripherals.
LL_RCC_IC14_SetSource(LL_RCC_ICCLKSOURCE_PLL1);
LL_RCC_IC14_SetDivider(8);