diff --git a/examples/stm32/nucleo-f429zi-baremetal/mcu.h b/examples/stm32/nucleo-f429zi-baremetal/mcu.h index 29b8a3b4..0ce8bea0 100644 --- a/examples/stm32/nucleo-f429zi-baremetal/mcu.h +++ b/examples/stm32/nucleo-f429zi-baremetal/mcu.h @@ -1,6 +1,6 @@ // Copyright (c) 2022 Cesanta Software Limited // All rights reserved -// https://www.st.com/resource/en/reference_manual/dm00124865-stm32f75xxx-and-stm32f74xxx-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf +// https://www.st.com/resource/en/reference_manual/dm00031020-stm32f405-415-stm32f407-417-stm32f427-437-and-stm32f429-439-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf #pragma once diff --git a/mip/driver_stm32.c b/mip/driver_stm32.c index 11d49151..0f633986 100644 --- a/mip/driver_stm32.c +++ b/mip/driver_stm32.c @@ -97,8 +97,11 @@ static bool mip_driver_stm32_init(uint8_t *mac, void *userdata) { ETH->MACCR = BIT(2) | BIT(3) | BIT(11) | BIT(14); // RE, TE, Duplex, Fast ETH->DMAOMR = BIT(1) | BIT(13) | BIT(21) | BIT(25); // SR, ST, TSF, RSF - // TODO(cpq): setup MAC filtering - (void) userdata, (void) mac; + // MAC address filtering + ETH->MACA0HR = ((uint32_t) mac[5] << 8U) | mac[4]; + ETH->MACA0LR = (uint32_t) (mac[3] << 24) | ((uint32_t) mac[2] << 16) | + ((uint32_t) mac[1] << 8) | mac[0]; + (void) userdata; return true; } @@ -139,9 +142,7 @@ static bool mip_driver_stm32_up(void *userdata) { void ETH_IRQHandler(void); void ETH_IRQHandler(void) { -#ifdef MIP_QPROFILE qp_mark(QP_IRQTRIGGERED, 0); -#endif volatile uint32_t sr = ETH->DMASR; if (sr & BIT(6)) { // Frame received, loop for (uint32_t i = 0; i < ETH_DESC_CNT; i++) { diff --git a/mip/mip.c b/mip/mip.c index c887971e..9155efd1 100644 --- a/mip/mip.c +++ b/mip/mip.c @@ -64,7 +64,8 @@ struct mip_if { uint64_t timer_1000ms; // 1000 ms timer: for DHCP and link state uint8_t arp_cache[MIP_ARP_CS]; // Each entry is 12 bytes uint16_t eport; // Next ephemeral port - int state; // Current state + uint16_t dropped; // Number of dropped frames + uint8_t state; // Current state #define MIP_STATE_DOWN 0 // Interface is down #define MIP_STATE_UP 1 // Interface is up #define MIP_STATE_READY 2 // Interface is up and has IP @@ -202,7 +203,11 @@ static bool q_write(struct queue *q, const void *buf, size_t len) { return success; } -static size_t q_avail(struct queue *q) { +static inline size_t q_space(struct queue *q) { + return q->tail > q->head ? q->tail - q->head : q->tail + (q->len - q->head); +} + +static inline size_t q_avail(struct queue *q) { size_t n = 0; if (q->tail != q->head) q_copyout(q, (uint8_t *) &n, sizeof(n), q->tail); return n; @@ -788,13 +793,9 @@ static void mip_poll(struct mip_if *ifp, uint64_t uptime_ms) { : ifp->driver->rx(ifp->rx.buf, ifp->rx.len, ifp->driver_data); if (len == 0) break; -#ifdef MIP_QPROFILE - qp_mark(QP_FRAMEPOPPED, (int) len); -#endif + qp_mark(QP_FRAMEPOPPED, (int) q_space(&ifp->queue)); mip_rx(ifp, ifp->rx.buf, len); -#ifdef MIP_QPROFILE - qp_mark(QP_FRAMEDONE, (int) len); -#endif + qp_mark(QP_FRAMEDONE, (int) q_space(&ifp->queue)); } // Process timeouts @@ -825,12 +826,13 @@ static void mip_poll(struct mip_if *ifp, uint64_t uptime_ms) { // our lock-free queue with preallocated buffer to copy data and return asap static void on_rx(void *buf, size_t len, void *userdata) { struct mip_if *ifp = (struct mip_if *) userdata; -#ifndef MIP_QPROFILE - if (!q_write(&ifp->queue, buf, len)) MG_ERROR(("dropped %d", (int) len)); -#else - qp_mark(q_write(&ifp->queue, buf, len) ? QP_FRAMEPUSHED : QP_FRAMEDROPPED, - (int) len); -#endif + if (q_write(&ifp->queue, buf, len)) { + qp_mark(QP_FRAMEPUSHED, (int) q_space(&ifp->queue)); + } else { + ifp->dropped++; + qp_mark(QP_FRAMEDROPPED, ifp->dropped); + MG_ERROR(("dropped %d", (int) len)); + } } void mip_init(struct mg_mgr *mgr, struct mip_cfg *ipcfg, @@ -958,7 +960,7 @@ bool mg_send(struct mg_connection *c, const void *buf, size_t len) { #pragma pack(push, 1) struct qpentry { - uint64_t timestamp; + uint32_t timestamp; uint16_t type; uint16_t len; }; @@ -970,14 +972,11 @@ static struct queue qp; // TODO(scaprile): avoid concurrency issues (2 queues ?) void qp_mark(unsigned int type, int len) { static bool ovf = false; - static uint16_t drop_ctr = 0, irq_ctr = 0; - struct qpentry e = { - .timestamp = mg_millis(), .type = (uint16_t) type, .len = (uint16_t) len}; - - if (type == QP_IRQTRIGGERED) - e.len = ++irq_ctr; // only incremented on IRQ calls - else if (type == QP_FRAMEDROPPED) - ++drop_ctr; // only incremented on IRQ calls + static uint16_t irq_ctr = 0, drop_ctr = 0; + struct qpentry e = {.timestamp = (uint32_t) mg_millis(), + .type = (uint16_t) type, + .len = (uint16_t) len}; + if (type == QP_IRQTRIGGERED) e.len = ++irq_ctr; if (ovf) { e.type = (uint16_t) QP_QUEUEOVF; e.len = drop_ctr; @@ -987,20 +986,15 @@ void qp_mark(unsigned int type, int len) { void qp_log(void) { struct qpentry e; - - for (int i = 0; i < 10; i++) - if (q_read(&qp, &e)) - MG_INFO(("%llu, %u, %u", e.timestamp, e.type, e.len)); - else - break; + const char *titles[] = {"IRQ ", "PUSH", "POP ", "DONE", "DROP", "OVFL"}; + for (int i = 0; i < 10 && q_read(&qp, &e); i++) { + MG_INFO(("%lx %s %u", e.timestamp, titles[e.type], e.len)); + } } void qp_init(void) { - unsigned int qlen = 500 * (sizeof(size_t) + sizeof(struct qpentry)); - - qp.buf = calloc(1, qlen); - qp.len = qlen; - // THERE IS NO FREE + qp.len = 500 * (sizeof(size_t) + sizeof(struct qpentry)); + qp.buf = calloc(1, qp.len); // THERE IS NO FREE } #endif // MIP_QPROFILE diff --git a/mip/mip.h b/mip/mip.h index 716d5654..0c9fd5d4 100644 --- a/mip/mip.h +++ b/mip/mip.h @@ -32,17 +32,18 @@ struct mip_spi { }; #ifdef MIP_QPROFILE -enum { // payload is frame length unless otherwise noted +enum { QP_IRQTRIGGERED = 0, // payload is number of interrupts so far - QP_FRAMEPUSHED, - QP_FRAMEPOPPED, - QP_FRAMEDONE, - QP_FRAMEDROPPED, - QP_QUEUEOVF // profiling queue is full, payload is number of frame drops so - // far + QP_FRAMEPUSHED, // available space in the frame queue + QP_FRAMEPOPPED, // available space in the frame queue + QP_FRAMEDONE, // available space in the frame queue + QP_FRAMEDROPPED, // number of dropped frames + QP_QUEUEOVF // profiling queue is full, payload is number of frame drops }; void qp_mark(unsigned int type, int len); void qp_log(void); // timestamp, type, payload void qp_init(void); +#else +#define qp_mark(a, b) #endif diff --git a/mongoose.c b/mongoose.c index edc951b4..5239da57 100644 --- a/mongoose.c +++ b/mongoose.c @@ -6079,8 +6079,11 @@ static bool mip_driver_stm32_init(uint8_t *mac, void *userdata) { ETH->MACCR = BIT(2) | BIT(3) | BIT(11) | BIT(14); // RE, TE, Duplex, Fast ETH->DMAOMR = BIT(1) | BIT(13) | BIT(21) | BIT(25); // SR, ST, TSF, RSF - // TODO(cpq): setup MAC filtering - (void) userdata, (void) mac; + // MAC address filtering + ETH->MACA0HR = ((uint32_t) mac[5] << 8U) | mac[4]; + ETH->MACA0LR = (uint32_t) (mac[3] << 24) | ((uint32_t) mac[2] << 16) | + ((uint32_t) mac[1] << 8) | mac[0]; + (void) userdata; return true; } @@ -6121,9 +6124,7 @@ static bool mip_driver_stm32_up(void *userdata) { void ETH_IRQHandler(void); void ETH_IRQHandler(void) { -#ifdef MIP_QPROFILE qp_mark(QP_IRQTRIGGERED, 0); -#endif volatile uint32_t sr = ETH->DMASR; if (sr & BIT(6)) { // Frame received, loop for (uint32_t i = 0; i < ETH_DESC_CNT; i++) { @@ -6365,7 +6366,8 @@ struct mip_if { uint64_t timer_1000ms; // 1000 ms timer: for DHCP and link state uint8_t arp_cache[MIP_ARP_CS]; // Each entry is 12 bytes uint16_t eport; // Next ephemeral port - int state; // Current state + uint16_t dropped; // Number of dropped frames + uint8_t state; // Current state #define MIP_STATE_DOWN 0 // Interface is down #define MIP_STATE_UP 1 // Interface is up #define MIP_STATE_READY 2 // Interface is up and has IP @@ -6503,7 +6505,11 @@ static bool q_write(struct queue *q, const void *buf, size_t len) { return success; } -static size_t q_avail(struct queue *q) { +static inline size_t q_space(struct queue *q) { + return q->tail > q->head ? q->tail - q->head : q->tail + (q->len - q->head); +} + +static inline size_t q_avail(struct queue *q) { size_t n = 0; if (q->tail != q->head) q_copyout(q, (uint8_t *) &n, sizeof(n), q->tail); return n; @@ -7089,13 +7095,9 @@ static void mip_poll(struct mip_if *ifp, uint64_t uptime_ms) { : ifp->driver->rx(ifp->rx.buf, ifp->rx.len, ifp->driver_data); if (len == 0) break; -#ifdef MIP_QPROFILE - qp_mark(QP_FRAMEPOPPED, (int) len); -#endif + qp_mark(QP_FRAMEPOPPED, (int) q_space(&ifp->queue)); mip_rx(ifp, ifp->rx.buf, len); -#ifdef MIP_QPROFILE - qp_mark(QP_FRAMEDONE, (int) len); -#endif + qp_mark(QP_FRAMEDONE, (int) q_space(&ifp->queue)); } // Process timeouts @@ -7126,12 +7128,13 @@ static void mip_poll(struct mip_if *ifp, uint64_t uptime_ms) { // our lock-free queue with preallocated buffer to copy data and return asap static void on_rx(void *buf, size_t len, void *userdata) { struct mip_if *ifp = (struct mip_if *) userdata; -#ifndef MIP_QPROFILE - if (!q_write(&ifp->queue, buf, len)) MG_ERROR(("dropped %d", (int) len)); -#else - qp_mark(q_write(&ifp->queue, buf, len) ? QP_FRAMEPUSHED : QP_FRAMEDROPPED, - (int) len); -#endif + if (q_write(&ifp->queue, buf, len)) { + qp_mark(QP_FRAMEPUSHED, (int) q_space(&ifp->queue)); + } else { + ifp->dropped++; + qp_mark(QP_FRAMEDROPPED, ifp->dropped); + MG_ERROR(("dropped %d", (int) len)); + } } void mip_init(struct mg_mgr *mgr, struct mip_cfg *ipcfg, @@ -7259,7 +7262,7 @@ bool mg_send(struct mg_connection *c, const void *buf, size_t len) { #pragma pack(push, 1) struct qpentry { - uint64_t timestamp; + uint32_t timestamp; uint16_t type; uint16_t len; }; @@ -7271,14 +7274,11 @@ static struct queue qp; // TODO(scaprile): avoid concurrency issues (2 queues ?) void qp_mark(unsigned int type, int len) { static bool ovf = false; - static uint16_t drop_ctr = 0, irq_ctr = 0; - struct qpentry e = { - .timestamp = mg_millis(), .type = (uint16_t) type, .len = (uint16_t) len}; - - if (type == QP_IRQTRIGGERED) - e.len = ++irq_ctr; // only incremented on IRQ calls - else if (type == QP_FRAMEDROPPED) - ++drop_ctr; // only incremented on IRQ calls + static uint16_t irq_ctr = 0, drop_ctr = 0; + struct qpentry e = {.timestamp = (uint32_t) mg_millis(), + .type = (uint16_t) type, + .len = (uint16_t) len}; + if (type == QP_IRQTRIGGERED) e.len = ++irq_ctr; if (ovf) { e.type = (uint16_t) QP_QUEUEOVF; e.len = drop_ctr; @@ -7288,20 +7288,15 @@ void qp_mark(unsigned int type, int len) { void qp_log(void) { struct qpentry e; - - for (int i = 0; i < 10; i++) - if (q_read(&qp, &e)) - MG_INFO(("%llu, %u, %u", e.timestamp, e.type, e.len)); - else - break; + const char *titles[] = {"IRQ ", "PUSH", "POP ", "DONE", "DROP", "OVFL"}; + for (int i = 0; i < 10 && q_read(&qp, &e); i++) { + MG_INFO(("%lx %s %u", e.timestamp, titles[e.type], e.len)); + } } void qp_init(void) { - unsigned int qlen = 500 * (sizeof(size_t) + sizeof(struct qpentry)); - - qp.buf = calloc(1, qlen); - qp.len = qlen; - // THERE IS NO FREE + qp.len = 500 * (sizeof(size_t) + sizeof(struct qpentry)); + qp.buf = calloc(1, qp.len); // THERE IS NO FREE } #endif // MIP_QPROFILE diff --git a/mongoose.h b/mongoose.h index 34f50824..8e08c751 100644 --- a/mongoose.h +++ b/mongoose.h @@ -1456,19 +1456,20 @@ struct mip_spi { }; #ifdef MIP_QPROFILE -enum { // payload is frame length unless otherwise noted +enum { QP_IRQTRIGGERED = 0, // payload is number of interrupts so far - QP_FRAMEPUSHED, - QP_FRAMEPOPPED, - QP_FRAMEDONE, - QP_FRAMEDROPPED, - QP_QUEUEOVF // profiling queue is full, payload is number of frame drops so - // far + QP_FRAMEPUSHED, // available space in the frame queue + QP_FRAMEPOPPED, // available space in the frame queue + QP_FRAMEDONE, // available space in the frame queue + QP_FRAMEDROPPED, // number of dropped frames + QP_QUEUEOVF // profiling queue is full, payload is number of frame drops }; void qp_mark(unsigned int type, int len); void qp_log(void); // timestamp, type, payload void qp_init(void); +#else +#define qp_mark(a, b) #endif #ifdef __cplusplus