Skip to content

stm32: Add support for ETH RMII peripheral (version 2) #4541

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 15 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions extmod/modlwip.c
Original file line number Diff line number Diff line change
Expand Up @@ -447,9 +447,12 @@ STATIC mp_uint_t lwip_udp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui
len = 0xffff;
}

MICROPY_PY_LWIP_ENTER

// FIXME: maybe PBUF_ROM?
struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
if (p == NULL) {
MICROPY_PY_LWIP_EXIT
*_errno = MP_ENOMEM;
return -1;
}
Expand All @@ -467,6 +470,8 @@ STATIC mp_uint_t lwip_udp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui

pbuf_free(p);

MICROPY_PY_LWIP_EXIT

// udp_sendto can return 1 on occasion for ESP8266 port. It's not known why
// but it seems that the send actually goes through without error in this case.
// So we treat such cases as a success until further investigation.
Expand Down Expand Up @@ -505,10 +510,14 @@ STATIC mp_uint_t lwip_udp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_

struct pbuf *p = socket->incoming.pbuf;

MICROPY_PY_LWIP_ENTER

u16_t result = pbuf_copy_partial(p, buf, ((p->tot_len > len) ? len : p->tot_len), 0);
pbuf_free(p);
socket->incoming.pbuf = NULL;

MICROPY_PY_LWIP_EXIT

return (mp_uint_t) result;
}

Expand All @@ -526,11 +535,14 @@ STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui
// Check for any pending errors
STREAM_ERROR_CHECK(socket);

MICROPY_PY_LWIP_ENTER

u16_t available = tcp_sndbuf(socket->pcb.tcp);

if (available == 0) {
// Non-blocking socket
if (socket->timeout == 0) {
MICROPY_PY_LWIP_EXIT
*_errno = MP_EAGAIN;
return MP_STREAM_ERROR;
}
Expand All @@ -543,11 +555,13 @@ STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui
// reset) by error callback.
// Avoid sending too small packets, so wait until at least 16 bytes available
while (socket->state >= STATE_CONNECTED && (available = tcp_sndbuf(socket->pcb.tcp)) < 16) {
MICROPY_PY_LWIP_EXIT
if (socket->timeout != -1 && mp_hal_ticks_ms() - start > socket->timeout) {
*_errno = MP_ETIMEDOUT;
return MP_STREAM_ERROR;
}
poll_sockets();
MICROPY_PY_LWIP_REENTER
}

// While we waited, something could happen
Expand All @@ -563,6 +577,8 @@ STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui
err = tcp_output(socket->pcb.tcp);
}

MICROPY_PY_LWIP_EXIT

if (err != ERR_OK) {
*_errno = error_lookup_table[-err];
return MP_STREAM_ERROR;
Expand Down Expand Up @@ -608,6 +624,8 @@ STATIC mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_
}
}

MICROPY_PY_LWIP_ENTER

assert(socket->pcb.tcp != NULL);

struct pbuf *p = socket->incoming.pbuf;
Expand All @@ -633,6 +651,8 @@ STATIC mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_
}
tcp_recved(socket->pcb.tcp, len);

MICROPY_PY_LWIP_EXIT

return len;
}

Expand Down Expand Up @@ -865,16 +885,21 @@ STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
mp_raise_OSError(MP_EALREADY);
}
}

// Register our receive callback.
MICROPY_PY_LWIP_ENTER
tcp_recv(socket->pcb.tcp, _lwip_tcp_recv);
socket->state = STATE_CONNECTING;
err = tcp_connect(socket->pcb.tcp, &dest, port, _lwip_tcp_connected);
if (err != ERR_OK) {
MICROPY_PY_LWIP_EXIT
socket->state = STATE_NEW;
mp_raise_OSError(error_lookup_table[-err]);
}
socket->peer_port = (mp_uint_t)port;
memcpy(socket->peer, &dest, sizeof(socket->peer));
MICROPY_PY_LWIP_EXIT

// And now we wait...
if (socket->timeout != -1) {
for (mp_uint_t retries = socket->timeout / 100; retries--;) {
Expand Down Expand Up @@ -1209,6 +1234,8 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_
lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in);
mp_uint_t ret;

MICROPY_PY_LWIP_ENTER

if (request == MP_STREAM_POLL) {
uintptr_t flags = arg;
ret = 0;
Expand Down Expand Up @@ -1259,6 +1286,7 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_
bool socket_is_listener = false;

if (socket->pcb.tcp == NULL) {
MICROPY_PY_LWIP_EXIT
return 0;
}

Expand Down Expand Up @@ -1305,6 +1333,8 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_
ret = MP_STREAM_ERROR;
}

MICROPY_PY_LWIP_EXIT

return ret;
}

Expand Down Expand Up @@ -1452,7 +1482,10 @@ STATIC mp_obj_t lwip_getaddrinfo(size_t n_args, const mp_obj_t *args) {
getaddrinfo_state_t state;
state.status = 0;

MICROPY_PY_LWIP_ENTER
err_t ret = dns_gethostbyname(host, (ip_addr_t*)&state.ipaddr, lwip_getaddrinfo_cb, &state);
MICROPY_PY_LWIP_EXIT

switch (ret) {
case ERR_OK:
// cached
Expand Down
6 changes: 6 additions & 0 deletions lib/netutils/netutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@

#define NETUTILS_IPV4ADDR_BUFSIZE 4

#define NETUTILS_TRACE_IS_TX (0x0001)
#define NETUTILS_TRACE_PAYLOAD (0x0002)
#define NETUTILS_TRACE_NEWLINE (0x0004)

typedef enum _netutils_endian_t {
NETUTILS_LITTLE,
NETUTILS_BIG,
Expand All @@ -47,4 +51,6 @@ void netutils_parse_ipv4_addr(mp_obj_t addr_in, uint8_t *out_ip, netutils_endian
// puts IP in out_ip (which must take at least IPADDR_BUF_SIZE bytes).
mp_uint_t netutils_parse_inet_addr(mp_obj_t addr_in, uint8_t *out_ip, netutils_endian_t endian);

void netutils_ethernet_trace(const mp_print_t *print, size_t len, const uint8_t *buf, unsigned int flags);

#endif // MICROPY_INCLUDED_LIB_NETUTILS_NETUTILS_H
150 changes: 150 additions & 0 deletions lib/netutils/trace.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2019 Damien P. George
*
* 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 "lib/netutils/netutils.h"

static uint32_t get_be16(const uint8_t *buf) {
return buf[0] << 8 | buf[1];
}

static uint32_t get_be32(const uint8_t *buf) {
return buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
}

static void dump_hex_bytes(const mp_print_t *print, size_t len, const uint8_t *buf) {
for (size_t i = 0; i < len; ++i) {
mp_printf(print, " %02x", buf[i]);
}
}

static const char *ethertype_str(uint16_t type) {
// A value between 0x0000 - 0x05dc (inclusive) indicates a length, not type
switch (type) {
case 0x0800: return "IPv4";
case 0x0806: return "ARP";
case 0x86dd: return "IPv6";
default: return NULL;
}
}

void netutils_ethernet_trace(const mp_print_t *print, size_t len, const uint8_t *buf, unsigned int flags) {
mp_printf(print, "[% 8d] ETH%cX len=%u", mp_hal_ticks_ms(), flags & NETUTILS_TRACE_IS_TX ? 'T' : 'R', len);
mp_printf(print, " dst=%02x:%02x:%02x:%02x:%02x:%02x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
mp_printf(print, " src=%02x:%02x:%02x:%02x:%02x:%02x", buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]);

const char *ethertype = ethertype_str(buf[12] << 8 | buf[13]);
if (ethertype) {
mp_printf(print, " type=%s", ethertype);
} else {
mp_printf(print, " type=0x%04x", buf[12] << 8 | buf[13]);
}
if (len > 14) {
len -= 14;
buf += 14;
if (buf[-2] == 0x08 && buf[-1] == 0x00 && buf[0] == 0x45) {
// IPv4 packet
len = get_be16(buf + 2);
mp_printf(print, " srcip=%u.%u.%u.%u dstip=%u.%u.%u.%u",
buf[12], buf[13], buf[14], buf[15],
buf[16], buf[17], buf[18], buf[19]);
uint8_t prot = buf[9];
buf += 20;
len -= 20;
if (prot == 6) {
// TCP packet
uint16_t srcport = get_be16(buf);
uint16_t dstport = get_be16(buf + 2);
uint32_t seqnum = get_be32(buf + 4);
uint32_t acknum = get_be32(buf + 8);
uint16_t dataoff_flags = get_be16(buf + 12);
uint16_t winsz = get_be16(buf + 14);
mp_printf(print, " TCP srcport=%u dstport=%u seqnum=%u acknum=%u dataoff=%u flags=%x winsz=%u",
srcport, dstport, (unsigned)seqnum, (unsigned)acknum, dataoff_flags >> 12, dataoff_flags & 0x1ff, winsz);
buf += 20;
len -= 20;
if (dataoff_flags >> 12 > 5) {
mp_printf(print, " opts=");
size_t opts_len = ((dataoff_flags >> 12) - 5) * 4;
dump_hex_bytes(print, opts_len, buf);
buf += opts_len;
len -= opts_len;
}
} else if (prot == 17) {
// UDP packet
uint16_t srcport = get_be16(buf);
uint16_t dstport = get_be16(buf + 2);
mp_printf(print, " UDP srcport=%u dstport=%u", srcport, dstport);
len = get_be16(buf + 4);
buf += 8;
if ((srcport == 67 && dstport == 68) || (srcport == 68 && dstport == 67)) {
// DHCP
if (srcport == 67) {
mp_printf(print, " DHCPS");
} else {
mp_printf(print, " DHCPC");
}
dump_hex_bytes(print, 12 + 16 + 16 + 64, buf);
size_t n = 12 + 16 + 16 + 64 + 128;
len -= n;
buf += n;
mp_printf(print, " opts:");
switch (buf[6]) {
case 1: mp_printf(print, " DISCOVER"); break;
case 2: mp_printf(print, " OFFER"); break;
case 3: mp_printf(print, " REQUEST"); break;
case 4: mp_printf(print, " DECLINE"); break;
case 5: mp_printf(print, " ACK"); break;
case 6: mp_printf(print, " NACK"); break;
case 7: mp_printf(print, " RELEASE"); break;
case 8: mp_printf(print, " INFORM"); break;
}
}
} else {
// Non-UDP packet
mp_printf(print, " prot=%u", prot);
}
} else if (buf[-2] == 0x86 && buf[-1] == 0xdd && (buf[0] >> 4) == 6) {
// IPv6 packet
uint32_t h = get_be32(buf);
uint16_t l = get_be16(buf + 4);
mp_printf(print, " tclass=%u flow=%u len=%u nexthdr=%u hoplimit=%u", (unsigned)((h >> 20) & 0xff), (unsigned)(h & 0xfffff), l, buf[6], buf[7]);
mp_printf(print, " srcip=");
dump_hex_bytes(print, 16, buf + 8);
mp_printf(print, " dstip=");
dump_hex_bytes(print, 16, buf + 24);
buf += 40;
len -= 40;
}
if (flags & NETUTILS_TRACE_PAYLOAD) {
mp_printf(print, " data=");
dump_hex_bytes(print, len, buf);
}
}
if (flags & NETUTILS_TRACE_NEWLINE) {
mp_printf(print, "\n");
}
}
3 changes: 3 additions & 0 deletions ports/stm32/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ SRC_LIB = $(addprefix lib/,\
oofatfs/option/unicode.c \
mp-readline/readline.c \
netutils/netutils.c \
netutils/trace.c \
timeutils/timeutils.c \
utils/pyexec.c \
utils/interrupt_char.c \
Expand Down Expand Up @@ -240,6 +241,7 @@ SRC_C = \
can.c \
usb.c \
wdt.c \
eth.c \
gccollect.c \
help.c \
machine_i2c.c \
Expand All @@ -251,6 +253,7 @@ SRC_C = \
moduos.c \
modutime.c \
modusocket.c \
network_lan.c \
modnetwork.c \
extint.c \
usrsw.c \
Expand Down
13 changes: 13 additions & 0 deletions ports/stm32/boards/NUCLEO_F429ZI/mpconfigboard.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#define MICROPY_HW_BOARD_NAME "NUCLEO-F429ZI"
#define MICROPY_HW_MCU_NAME "STM32F429"

#define MICROPY_PY_LWIP (1)

#define MICROPY_HW_HAS_SWITCH (1)
#define MICROPY_HW_HAS_FLASH (1)
#define MICROPY_HW_ENABLE_RNG (1)
Expand Down Expand Up @@ -81,3 +83,14 @@
#define MICROPY_HW_USB_FS (1)
#define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9)
#define MICROPY_HW_USB_OTG_ID_PIN (pin_A10)

// Ethernet via RMII
#define MICROPY_HW_ETH_MDC (pin_C1)
#define MICROPY_HW_ETH_MDIO (pin_A2)
#define MICROPY_HW_ETH_RMII_REF_CLK (pin_A1)
#define MICROPY_HW_ETH_RMII_CRS_DV (pin_A7)
#define MICROPY_HW_ETH_RMII_RXD0 (pin_C4)
#define MICROPY_HW_ETH_RMII_RXD1 (pin_C5)
#define MICROPY_HW_ETH_RMII_TX_EN (pin_G11)
#define MICROPY_HW_ETH_RMII_TXD0 (pin_G13)
#define MICROPY_HW_ETH_RMII_TXD1 (pin_B13)
9 changes: 9 additions & 0 deletions ports/stm32/boards/NUCLEO_F429ZI/pins.csv
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,12 @@ PG2,PG2
SW,PA0
LED_GREEN,PG13
LED_RED,PG14
ETH_MDC,PC1
ETH_MDIO,PA2
ETH_RMII_REF_CLK,PA1
ETH_RMII_CRS_DV,PA7
ETH_RMII_RXD0,PC4
ETH_RMII_RXD1,PC5
ETH_RMII_TX_EN,PG11
ETH_RMII_TXD0,PG13
ETH_RMII_TXD1,PB13
Loading