Skip to content

Commit c001cfa

Browse files
committed
rp2/mpnetworkport: Convert network task scheduling to use PendSV IRQ.
It is more reliable and scales better when more components need it. Work done in collaboration with Graham Sanderson and Peter Harper. Signed-off-by: Damien George <[email protected]>
1 parent 7cdad05 commit c001cfa

File tree

4 files changed

+134
-47
lines changed

4 files changed

+134
-47
lines changed

ports/rp2/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ set(MICROPY_SOURCE_PORT
111111
mphalport.c
112112
mpnetworkport.c
113113
mpthreadport.c
114+
pendsv.c
114115
rp2_flash.c
115116
rp2_pio.c
116117
tusb_port.c
@@ -141,6 +142,7 @@ set(MICROPY_SOURCE_QSTR
141142
)
142143

143144
set(PICO_SDK_COMPONENTS
145+
cmsis_core
144146
hardware_adc
145147
hardware_base
146148
hardware_clocks

ports/rp2/mpnetworkport.c

Lines changed: 13 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
#include "py/runtime.h"
2828
#include "py/mphal.h"
29+
#include "pendsv.h"
2930

3031
#if MICROPY_PY_LWIP
3132

@@ -36,77 +37,42 @@
3637
#define LWIP_TICK_RATE_MS 64
3738

3839
static alarm_id_t lwip_alarm_id = -1;
39-
static bool lwip_can_poll = true;
40-
static bool lwip_poll_pending = false;
4140

4241
#if MICROPY_PY_NETWORK_WIZNET5K
43-
static bool wiznet_poll_pending = false;
44-
4542
void wiznet5k_poll(void);
4643
void wiznet5k_deinit(void);
44+
45+
void wiznet5k_try_poll(void) {
46+
pendsv_schedule_dispatch(PENDSV_DISPATCH_WIZNET, wiznet5k_poll);
47+
}
4748
#endif
4849

4950
u32_t sys_now(void) {
5051
// Used by LwIP
5152
return mp_hal_ticks_ms();
5253
}
5354

54-
STATIC uint32_t lwip_poll(void) {
55+
STATIC void lwip_poll(void) {
5556
// Run the lwIP internal updates
5657
sys_check_timeouts();
57-
58-
return MAX(5, MIN(sys_timeouts_sleeptime(), LWIP_TICK_RATE_MS));
5958
}
6059

6160
void lwip_lock_acquire(void) {
62-
lwip_can_poll = false;
61+
// Prevent PendSV from running.
62+
pendsv_suspend();
6363
}
6464

6565
void lwip_lock_release(void) {
66-
lwip_can_poll = false;
67-
#if MICROPY_PY_NETWORK_WIZNET5K
68-
if (wiznet_poll_pending) {
69-
wiznet5k_poll();
70-
wiznet_poll_pending = false;
71-
}
72-
#endif
73-
74-
if (lwip_poll_pending) {
75-
lwip_poll();
76-
lwip_poll_pending = false;
77-
}
78-
lwip_can_poll = true;
66+
// Allow PendSV to run again.
67+
pendsv_resume();
7968
}
8069

81-
uint32_t lwip_try_poll(void) {
82-
uint32_t ret = LWIP_TICK_RATE_MS;
83-
if (lwip_can_poll) {
84-
lwip_can_poll = false;
85-
ret = lwip_poll();
86-
lwip_can_poll = true;
87-
} else {
88-
lwip_poll_pending = true;
89-
}
90-
return ret;
91-
}
92-
93-
#if MICROPY_PY_NETWORK_WIZNET5K
94-
void wiznet5k_try_poll(void) {
95-
if (lwip_can_poll) {
96-
lwip_can_poll = false;
97-
wiznet5k_poll();
98-
lwip_can_poll = true;
99-
} else {
100-
wiznet_poll_pending = true;
101-
}
102-
}
103-
#endif
104-
10570
STATIC int64_t alarm_callback(alarm_id_t id, void *user_data) {
71+
pendsv_schedule_dispatch(PENDSV_DISPATCH_LWIP, lwip_poll);
10672
#if MICROPY_PY_NETWORK_WIZNET5K
107-
wiznet5k_try_poll();
73+
pendsv_schedule_dispatch(PENDSV_DISPATCH_WIZNET, wiznet5k_poll);
10874
#endif
109-
return (int64_t)lwip_try_poll() * 1000;
75+
return LWIP_TICK_RATE_MS * 1000;
11076
}
11177

11278
void mod_network_lwip_init(void) {

ports/rp2/pendsv.c

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2022 Damien P. George
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#include <assert.h>
28+
#include "pendsv.h"
29+
#include "RP2040.h"
30+
31+
static pendsv_dispatch_t pendsv_dispatch_table[PENDSV_DISPATCH_NUM_SLOTS];
32+
static int pendsv_lock;
33+
34+
void pendsv_suspend(void) {
35+
pendsv_lock++;
36+
}
37+
38+
void pendsv_resume(void) {
39+
pendsv_lock--;
40+
assert(pendsv_lock >= 0);
41+
// Run pendsv if needed. Find an entry with a dispatch and call pendsv dispatch
42+
// with it. If pendsv runs it will service all slots.
43+
int count = PENDSV_DISPATCH_NUM_SLOTS;
44+
while (count--) {
45+
if (pendsv_dispatch_table[count]) {
46+
pendsv_schedule_dispatch(count, pendsv_dispatch_table[count]);
47+
break;
48+
}
49+
}
50+
}
51+
52+
void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f) {
53+
assert(pendsv_lock >= 0);
54+
pendsv_dispatch_table[slot] = f;
55+
if (pendsv_lock == 0) {
56+
SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
57+
}
58+
}
59+
60+
// PendSV interrupt handler to perform background processing.
61+
void PendSV_Handler(void) {
62+
assert(pendsv_lock == 0);
63+
for (size_t i = 0; i < PENDSV_DISPATCH_NUM_SLOTS; ++i) {
64+
if (pendsv_dispatch_table[i] != NULL) {
65+
pendsv_dispatch_t f = pendsv_dispatch_table[i];
66+
pendsv_dispatch_table[i] = NULL;
67+
f();
68+
}
69+
}
70+
}

ports/rp2/pendsv.h

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2022 Damien P. George
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
#ifndef MICROPY_INCLUDED_RP2_PENDSV_H
27+
#define MICROPY_INCLUDED_RP2_PENDSV_H
28+
29+
#include <stddef.h>
30+
31+
enum {
32+
#if MICROPY_PY_LWIP
33+
PENDSV_DISPATCH_LWIP,
34+
#endif
35+
#if MICROPY_PY_NETWORK_WIZNET5K
36+
PENDSV_DISPATCH_WIZNET,
37+
#endif
38+
PENDSV_DISPATCH_MAX
39+
};
40+
41+
#define PENDSV_DISPATCH_NUM_SLOTS PENDSV_DISPATCH_MAX
42+
43+
typedef void (*pendsv_dispatch_t)(void);
44+
45+
void pendsv_suspend(void);
46+
void pendsv_resume(void);
47+
void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f);
48+
49+
#endif // MICROPY_INCLUDED_RP2_PENDSV_H

0 commit comments

Comments
 (0)