Skip to content

Commit 01156d5

Browse files
committed
stm: Add support for ctrl-C to interrupt running Python.
Using PendSV interrupt at lowest priority, code can now raise an exception during an interrupt by calling pendsv_nlr_jump. The exception will be raised when all interrupts are finished. This is used to trap ctrl-C from the USB VCP to break out of running Python code.
1 parent 532f2c3 commit 01156d5

File tree

8 files changed

+99
-1
lines changed

8 files changed

+99
-1
lines changed

stm/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ SRC_C = \
4545
string0.c \
4646
malloc0.c \
4747
systick.c \
48+
pendsv.c \
4849
gccollect.c \
4950
lexerfatfs.c \
5051
led.c \

stm/led.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ void led_toggle(pyb_led_t led) {
103103
return;
104104
}
105105

106+
// XXX this assumes LED is driven by a low MCU output (true for PYBv3, false for PYBv4)
106107
if (!(port->ODR & pin)) {
107108
// turn LED off
108109
PYB_LED_OFF(port, pin);

stm/main.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "gc.h"
3131
#include "gccollect.h"
3232
#include "systick.h"
33+
#include "pendsv.h"
3334
#include "led.h"
3435
#include "servo.h"
3536
#include "lcd.h"
@@ -327,7 +328,7 @@ int readline(vstr_t *line, const char *prompt) {
327328
}
328329
}
329330
if (escape == 0) {
330-
if (c == 4 && vstr_len(line) == len) {
331+
if (c == VCP_CHAR_CTRL_D && vstr_len(line) == len) {
331332
return 0;
332333
} else if (c == '\r') {
333334
stdout_tx_str("\r\n");
@@ -435,10 +436,14 @@ void do_repl(void) {
435436
nlr_buf_t nlr;
436437
uint32_t start = sys_tick_counter;
437438
if (nlr_push(&nlr) == 0) {
439+
usb_vcp_set_interrupt_char(VCP_CHAR_CTRL_C); // allow ctrl-C to interrupt us
438440
rt_call_function_0(module_fun);
441+
usb_vcp_set_interrupt_char(VCP_CHAR_NONE); // disable interrupt
439442
nlr_pop();
440443
} else {
441444
// uncaught exception
445+
// FIXME it could be that an interrupt happens just before we disable it here
446+
usb_vcp_set_interrupt_char(VCP_CHAR_NONE); // disable interrupt
442447
mp_obj_print_exception((mp_obj_t)nlr.ret_val);
443448
}
444449

@@ -488,11 +493,15 @@ bool do_file(const char *filename) {
488493

489494
nlr_buf_t nlr;
490495
if (nlr_push(&nlr) == 0) {
496+
usb_vcp_set_interrupt_char(VCP_CHAR_CTRL_C); // allow ctrl-C to interrupt us
491497
rt_call_function_0(module_fun);
498+
usb_vcp_set_interrupt_char(VCP_CHAR_NONE); // disable interrupt
492499
nlr_pop();
493500
return true;
494501
} else {
495502
// uncaught exception
503+
// FIXME it could be that an interrupt happens just before we disable it here
504+
usb_vcp_set_interrupt_char(VCP_CHAR_NONE); // disable interrupt
496505
mp_obj_print_exception((mp_obj_t)nlr.ret_val);
497506
return false;
498507
}
@@ -560,6 +569,10 @@ mp_obj_t pyb_rng_get(void) {
560569
return mp_obj_new_int(RNG_GetRandomNumber() >> 16);
561570
}
562571

572+
mp_obj_t pyb_millis(void) {
573+
return mp_obj_new_int(sys_tick_counter);
574+
}
575+
563576
int main(void) {
564577
// TODO disable JTAG
565578

@@ -592,6 +605,7 @@ int main(void) {
592605

593606
// basic sub-system init
594607
sys_tick_init();
608+
pendsv_init();
595609
led_init();
596610

597611
#if MICROPY_HW_ENABLE_RTC
@@ -693,6 +707,7 @@ int main(void) {
693707
rt_store_attr(m, MP_QSTR_Usart, rt_make_function_n(2, pyb_Usart));
694708
rt_store_attr(m, qstr_from_str("ADC_all"), (mp_obj_t)&pyb_ADC_all_obj);
695709
rt_store_attr(m, MP_QSTR_ADC, (mp_obj_t)&pyb_ADC_obj);
710+
rt_store_attr(m, qstr_from_str("millis"), rt_make_function_n(0, pyb_millis));
696711
rt_store_name(MP_QSTR_pyb, m);
697712

698713
rt_store_name(MP_QSTR_open, rt_make_function_n(2, pyb_io_open));

stm/pendsv.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#include <stdlib.h>
2+
#include <stm32f4xx.h>
3+
4+
#include "misc.h"
5+
#include "mpconfig.h"
6+
#include "qstr.h"
7+
#include "obj.h"
8+
#include "pendsv.h"
9+
10+
static mp_obj_t pendsv_object = MP_OBJ_NULL;
11+
12+
void pendsv_init(void) {
13+
// set PendSV interrupt at lowest priority
14+
NVIC_SetPriority(PendSV_IRQn, 0xff);
15+
}
16+
17+
// call this function to raise a pending exception during an interrupt
18+
// it will wait until all interrupts are finished then raise the given
19+
// exception object using nlr_jump in the context of the top-level thread
20+
void pendsv_nlr_jump(mp_obj_t o) {
21+
pendsv_object = o;
22+
SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
23+
}
24+
25+
void pendsv_isr_handler(void) {
26+
// re-jig the stack so that when we return from this interrupt handler
27+
// it returns instead to nlr_jump with argument pendsv_object
28+
__asm volatile (
29+
"ldr r0, pendsv_object_ptr\n"
30+
"ldr r0, [r0]\n"
31+
"str r0, [sp, #0]\n"
32+
"ldr r0, nlr_jump_ptr\n"
33+
"str r0, [sp, #24]\n"
34+
"bx lr\n"
35+
".align 2\n"
36+
"pendsv_object_ptr: .word pendsv_object\n"
37+
"nlr_jump_ptr: .word nlr_jump\n"
38+
);
39+
40+
/*
41+
sp[0] = r0 = exception to raise
42+
sp[6] = pc = nlr_jump
43+
uint32_t x[2] = {0x424242, 0xdeaddead};
44+
printf("PendSV: %p\n", x);
45+
for (uint32_t *p = (uint32_t*)(((uint32_t)x - 15) & 0xfffffff0), i = 64; i > 0; p += 4, i -= 4) {
46+
printf(" %p: %08x %08x %08x %08x\n", p, p[0], p[1], p[2], p[3]);
47+
}
48+
*/
49+
}

stm/pendsv.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
void pendsv_init(void);
2+
void pendsv_nlr_jump(mp_obj_t o);
3+
void pendsv_isr_handler(void);

stm/stm32fxxx_it.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ void DebugMon_Handler(void)
151151
*/
152152
void PendSV_Handler(void)
153153
{
154+
extern void pendsv_isr_handler(void);
155+
pendsv_isr_handler();
154156
}
155157

156158
/**

stm/usb.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "mpconfig.h"
1212
#include "qstr.h"
1313
#include "obj.h"
14+
#include "pendsv.h"
1415
#include "usb.h"
1516

1617
#ifdef USE_DEVICE_MODE
@@ -23,6 +24,8 @@ static int dev_is_enabled = 0;
2324
static char rx_buf[64];
2425
static int rx_buf_in;
2526
static int rx_buf_out;
27+
static int interrupt_char = VCP_CHAR_NONE;
28+
mp_obj_t mp_const_vcp_interrupt = MP_OBJ_NULL;
2629

2730
void pyb_usb_dev_init(void) {
2831
#ifdef USE_DEVICE_MODE
@@ -33,17 +36,36 @@ void pyb_usb_dev_init(void) {
3336
}
3437
rx_buf_in = 0;
3538
rx_buf_out = 0;
39+
interrupt_char = VCP_CHAR_NONE;
3640
dev_is_enabled = 1;
41+
42+
// create an exception object for interrupting by VCP
43+
mp_const_vcp_interrupt = mp_obj_new_exception(qstr_from_str("VCPInterrupt"));
3744
#endif
3845
}
3946

4047
bool usb_vcp_is_enabled(void) {
4148
return dev_is_enabled;
4249
}
4350

51+
void usb_vcp_set_interrupt_char(int c) {
52+
if (dev_is_enabled) {
53+
interrupt_char = c;
54+
}
55+
}
56+
4457
void usb_vcp_receive(const char *buf, uint32_t len) {
4558
if (dev_is_enabled) {
4659
for (int i = 0; i < len; i++) {
60+
61+
// catch special interrupt character
62+
if (buf[i] == interrupt_char) {
63+
// raise exception when interrupts are finished
64+
pendsv_nlr_jump(mp_const_vcp_interrupt);
65+
interrupt_char = VCP_CHAR_NONE;
66+
continue;
67+
}
68+
4769
rx_buf[rx_buf_in++] = buf[i];
4870
if (rx_buf_in >= sizeof(rx_buf)) {
4971
rx_buf_in = 0;

stm/usb.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1+
#define VCP_CHAR_NONE (0)
2+
#define VCP_CHAR_CTRL_C (3)
3+
#define VCP_CHAR_CTRL_D (4)
4+
15
void pyb_usb_dev_init(void);
26
bool usb_vcp_is_enabled(void);
7+
void usb_vcp_set_interrupt_char(int c);
38
int usb_vcp_rx_any(void);
49
char usb_vcp_rx_get(void);
510
void usb_vcp_send_str(const char* str);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy