Browse Source

stm32/network_lan: Add the phy_type=x keyword option to network.LAN().

With LAN8742, LAN8720, LAN83825 and DP83848 as possible options, and the
symbols PHY_LAN8720, PHY_LAN8742, PHY_DP83825 and PHY_DP8348.  The default
is PHY_LAN8742 which is the existing behaviour.

The eth_init() parameters for the Portenta H7 board are set to phy_addr=0
and phy_type=LAN8742, which matches the previous defaults and the
schematics.

Tested with LAN8720 and DP83848 breakout boards at 10M Duplex and 100M
Duplex modes.

Signed-off-by: robert-hh <robert@hammelrath.com>
pull/13630/head
robert-hh 9 months ago
committed by Damien George
parent
commit
bf68bb95f9
  1. 1
      ports/stm32/Makefile
  2. 2
      ports/stm32/boards/ARDUINO_PORTENTA_H7/board_init.c
  3. 52
      ports/stm32/eth.c
  4. 9
      ports/stm32/eth.h
  5. 59
      ports/stm32/eth_phy.c
  6. 67
      ports/stm32/eth_phy.h
  7. 12
      ports/stm32/network_lan.c

1
ports/stm32/Makefile

@ -251,6 +251,7 @@ SRC_C += \
pyb_can.c \
usb.c \
eth.c \
eth_phy.c \
gccollect.c \
help.c \
machine_bitstream.c \

2
ports/stm32/boards/ARDUINO_PORTENTA_H7/board_init.c

@ -115,7 +115,7 @@ void PORTENTA_board_early_init(void) {
mp_hal_pin_write(pyb_pin_ETH_RST, 1);
// Put Eth in low-power mode
eth_init(&eth_instance, MP_HAL_MAC_ETH0, 0);
eth_init(&eth_instance, MP_HAL_MAC_ETH0, 0, ETH_PHY_LAN8742);
eth_low_power_mode(&eth_instance, true);
#if MICROPY_HW_USB_HS_ULPI3320

52
ports/stm32/eth.c

@ -32,6 +32,7 @@
#include "extmod/modnetwork.h"
#include "mpu.h"
#include "eth.h"
#include "eth_phy.h"
#if defined(MICROPY_HW_ETH_MDC)
@ -40,26 +41,6 @@
#include "lwip/dhcp.h"
#include "netif/ethernet.h"
// ETH PHY register definitions (for LAN8742 and LAN8720/LAN8710)
#undef PHY_BCR
#define PHY_BCR (0x0000)
#define PHY_BCR_SOFT_RESET (0x8000)
#define PHY_BCR_AUTONEG_EN (0x1000)
#define PHY_BCR_POWER_DOWN (0x0800U)
#undef PHY_BSR
#define PHY_BSR (0x0001)
#define PHY_BSR_LINK_STATUS (0x0004)
#define PHY_BSR_AUTONEG_DONE (0x0020)
#define PHY_SCSR (0x001f)
#define PHY_SCSR_SPEED_Pos (2)
#define PHY_SCSR_SPEED_Msk (7 << PHY_SCSR_SPEED_Pos)
#define PHY_SCSR_SPEED_10HALF (1 << PHY_SCSR_SPEED_Pos)
#define PHY_SCSR_SPEED_10FULL (5 << PHY_SCSR_SPEED_Pos)
#define PHY_SCSR_SPEED_100HALF (2 << PHY_SCSR_SPEED_Pos)
#define PHY_SCSR_SPEED_100FULL (6 << PHY_SCSR_SPEED_Pos)
// ETH DMA RX and TX descriptor definitions
#if defined(STM32H5)
#define RX_DESCR_3_OWN_Pos (31)
@ -137,6 +118,7 @@ typedef struct _eth_t {
struct netif netif;
struct dhcp dhcp_struct;
uint32_t phy_addr;
int16_t (*phy_get_link_status)(uint32_t phy_addr);
} eth_t;
static eth_dma_t eth_dma __attribute__((aligned(16384)));
@ -146,7 +128,7 @@ eth_t eth_instance;
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 phy_addr, uint32_t reg, uint32_t val) {
void eth_phy_write(uint32_t phy_addr, uint32_t reg, uint32_t val) {
#if defined(STM32H5) || defined(STM32H7)
while (ETH->MACMDIOAR & ETH_MACMDIOAR_MB) {
}
@ -174,7 +156,7 @@ static void eth_phy_write(uint32_t phy_addr, uint32_t reg, uint32_t val) {
#endif
}
static uint32_t eth_phy_read(uint32_t phy_addr, uint32_t reg) {
uint32_t eth_phy_read(uint32_t phy_addr, uint32_t reg) {
#if defined(STM32H5) || defined(STM32H7)
while (ETH->MACMDIOAR & ETH_MACMDIOAR_MB) {
}
@ -202,10 +184,17 @@ static uint32_t eth_phy_read(uint32_t phy_addr, uint32_t reg) {
#endif
}
void eth_init(eth_t *self, int mac_idx, uint32_t phy_addr) {
int eth_init(eth_t *self, int mac_idx, uint32_t phy_addr, int phy_type) {
mp_hal_get_mac(mac_idx, &self->netif.hwaddr[0]);
self->netif.hwaddr_len = 6;
self->phy_addr = phy_addr;
if (phy_type == ETH_PHY_DP83825 || phy_type == ETH_PHY_DP83848) {
self->phy_get_link_status = eth_phy_dp838xx_get_link_status;
} else if (phy_type == ETH_PHY_LAN8720 || phy_type == ETH_PHY_LAN8742) {
self->phy_get_link_status = eth_phy_lan87xx_get_link_status;
} else {
return -1;
}
// 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);
@ -230,6 +219,7 @@ void eth_init(eth_t *self, int mac_idx, uint32_t phy_addr) {
#else
__HAL_RCC_ETH_CLK_ENABLE();
#endif
return 0;
}
void eth_set_trace(eth_t *self, uint32_t value) {
@ -381,6 +371,14 @@ static int eth_mac_init(eth_t *self) {
break;
case 1:
if (bsr & PHY_BSR_LINK_STATUS) {
// Announce all modes
eth_phy_write(self->phy_addr, PHY_ANAR,
PHY_ANAR_SPEED_10HALF |
PHY_ANAR_SPEED_10FULL |
PHY_ANAR_SPEED_100HALF |
PHY_ANAR_SPEED_100FULL |
PHY_ANAR_IEEE802_3);
// Start autonegotiate.
eth_phy_write(self->phy_addr, PHY_BCR, PHY_BCR_AUTONEG_EN);
phy_state = 2;
}
@ -396,7 +394,7 @@ static int eth_mac_init(eth_t *self) {
}
// Get register with link status
uint16_t phy_scsr = eth_phy_read(self->phy_addr, PHY_SCSR);
uint16_t phy_scsr = self->phy_get_link_status(self->phy_addr);
// Burst mode configuration
#if defined(STM32H5) || defined(STM32H7)
@ -505,9 +503,9 @@ static int eth_mac_init(eth_t *self) {
// Set main MAC control register
ETH->MACCR =
(phy_scsr & PHY_SCSR_SPEED_Msk) == PHY_SCSR_SPEED_10FULL ? ETH_MACCR_DM
: (phy_scsr & PHY_SCSR_SPEED_Msk) == PHY_SCSR_SPEED_100HALF ? ETH_MACCR_FES
: (phy_scsr & PHY_SCSR_SPEED_Msk) == PHY_SCSR_SPEED_100FULL ? (ETH_MACCR_FES | ETH_MACCR_DM)
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
;
mp_hal_delay_ms(2);

9
ports/stm32/eth.h

@ -26,10 +26,17 @@
#ifndef MICROPY_INCLUDED_STM32_ETH_H
#define MICROPY_INCLUDED_STM32_ETH_H
enum {
ETH_PHY_LAN8742 = 0,
ETH_PHY_LAN8720,
ETH_PHY_DP83848,
ETH_PHY_DP83825
};
typedef struct _eth_t eth_t;
extern eth_t eth_instance;
void eth_init(eth_t *self, int mac_idx, uint32_t phy_addr);
int eth_init(eth_t *self, int mac_idx, uint32_t phy_addr, int phy_type);
void eth_set_trace(eth_t *self, uint32_t value);
struct netif *eth_netif(eth_t *self);
int eth_link_status(eth_t *self);

59
ports/stm32/eth_phy.c

@ -0,0 +1,59 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2019 Damien P. George
* Copyright (c) 2024 Robert Hammelrath
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "py/mphal.h"
#include "eth_phy.h"
#if defined(MICROPY_HW_ETH_MDC)
#define PHY_SCSR_LAN87XX (0x001f)
#define PHY_SCSR_LAN87XX_SPEED_Pos (2)
#define PHY_SCSR_LAN87XX_SPEED_Msk (7)
#define PHY_SCSR_DP838XX (0x0010)
#define PHY_RECR_DP838XX (0x0015)
#define PHY_SCSR_DP838XX_DUPLEX_Msk (4)
#define PHY_SCSR_DP838XX_10M_Msk (2)
int16_t eth_phy_lan87xx_get_link_status(uint32_t phy_addr) {
// Get the link mode & speed
int16_t scsr = eth_phy_read(phy_addr, PHY_SCSR_LAN87XX);
return (scsr >> PHY_SCSR_LAN87XX_SPEED_Pos) & PHY_SCSR_LAN87XX_SPEED_Msk;
}
int16_t eth_phy_dp838xx_get_link_status(uint32_t phy_addr) {
int16_t scsr = 0;
// Get the link mode & speed
uint16_t temp = eth_phy_read(phy_addr, PHY_SCSR_DP838XX);
scsr = (temp & PHY_SCSR_DP838XX_10M_Msk) ? PHY_SPEED_10HALF : PHY_SPEED_100HALF;
if (temp & PHY_SCSR_DP838XX_DUPLEX_Msk) {
scsr |= PHY_DUPLEX;
}
return scsr;
}
#endif

67
ports/stm32/eth_phy.h

@ -0,0 +1,67 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2019 Damien P. George
* Copyright (c) 2024 Robert Hammelrath
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_STM32_PHY_H
#define MICROPY_INCLUDED_STM32_PYH_H
#if defined(MICROPY_HW_ETH_MDC)
// Common ETH PHY register definitions
#undef PHY_BCR
#define PHY_BCR (0x0000)
#define PHY_BCR_SOFT_RESET (0x8000)
#define PHY_BCR_AUTONEG_EN (0x1000)
#define PHY_BCR_POWER_DOWN (0x0800U)
#undef PHY_BSR
#define PHY_BSR (0x0001)
#define PHY_BSR_LINK_STATUS (0x0004)
#define PHY_BSR_AUTONEG_DONE (0x0020)
#undef PHY_ANAR
#define PHY_ANAR (0x0004)
#define PHY_ANAR_SPEED_10HALF (0x0020)
#define PHY_ANAR_SPEED_10FULL (0x0040)
#define PHY_ANAR_SPEED_100HALF (0x0080)
#define PHY_ANAR_SPEED_100FULL (0x0100)
#define PHY_ANAR_IEEE802_3 (0x0001)
#define PHY_SPEED_10HALF (1)
#define PHY_SPEED_10FULL (5)
#define PHY_SPEED_100HALF (2)
#define PHY_SPEED_100FULL (6)
#define PHY_DUPLEX (4)
uint32_t eth_phy_read(uint32_t phy_addr, uint32_t reg);
void eth_phy_write(uint32_t phy_addr, uint32_t reg, uint32_t val);
int16_t eth_phy_lan87xx_get_link_status(uint32_t phy_addr);
int16_t eth_phy_dp838xx_get_link_status(uint32_t phy_addr);
#endif
#endif // MICROPY_INCLUDED_STM32_PHY_H

12
ports/stm32/network_lan.c

@ -54,16 +54,19 @@ static void network_lan_print(const mp_print_t *print, mp_obj_t self_in, mp_prin
}
static mp_obj_t network_lan_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
enum { ARG_phy_addr};
enum { ARG_phy_addr, ARG_phy_type};
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_phy_addr, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_phy_type, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = ETH_PHY_LAN8742} },
};
// Parse args.
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
const network_lan_obj_t *self = &network_lan_eth0;
eth_init(self->eth, MP_HAL_MAC_ETH0, args[ARG_phy_addr].u_int);
if (eth_init(self->eth, MP_HAL_MAC_ETH0, args[ARG_phy_addr].u_int, args[ARG_phy_type].u_int) != 0) {
mp_raise_ValueError(MP_ERROR_TEXT("invalid phy_type"));
}
return MP_OBJ_FROM_PTR(self);
}
@ -162,6 +165,11 @@ static const mp_rom_map_elem_t network_lan_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&network_lan_ifconfig_obj) },
{ MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&network_lan_status_obj) },
{ MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&network_lan_config_obj) },
{ MP_ROM_QSTR(MP_QSTR_PHY_LAN8742), MP_ROM_INT(ETH_PHY_LAN8742) },
{ MP_ROM_QSTR(MP_QSTR_PHY_LAN8720), MP_ROM_INT(ETH_PHY_LAN8720) },
{ MP_ROM_QSTR(MP_QSTR_PHY_DP83848), MP_ROM_INT(ETH_PHY_DP83848) },
{ MP_ROM_QSTR(MP_QSTR_PHY_DP83825), MP_ROM_INT(ETH_PHY_DP83825) },
};
static MP_DEFINE_CONST_DICT(network_lan_locals_dict, network_lan_locals_dict_table);

Loading…
Cancel
Save