diff options
Diffstat (limited to 'stm')
-rw-r--r-- | stm/Makefile | 1 | ||||
-rw-r--r-- | stm/led.c | 1 | ||||
-rw-r--r-- | stm/main.c | 17 | ||||
-rw-r--r-- | stm/pendsv.c | 49 | ||||
-rw-r--r-- | stm/pendsv.h | 3 | ||||
-rw-r--r-- | stm/stm32fxxx_it.c | 2 | ||||
-rw-r--r-- | stm/stmusbd/usbd_cdc_vcp.c | 7 | ||||
-rw-r--r-- | stm/usb.c | 26 | ||||
-rw-r--r-- | stm/usb.h | 5 |
9 files changed, 105 insertions, 6 deletions
diff --git a/stm/Makefile b/stm/Makefile index 1958252381..003bf32e79 100644 --- a/stm/Makefile +++ b/stm/Makefile @@ -45,6 +45,7 @@ SRC_C = \ string0.c \ malloc0.c \ systick.c \ + pendsv.c \ gccollect.c \ lexerfatfs.c \ led.c \ @@ -103,6 +103,7 @@ void led_toggle(pyb_led_t led) { return; } + // XXX this assumes LED is driven by a low MCU output (true for PYBv3, false for PYBv4) if (!(port->ODR & pin)) { // turn LED off PYB_LED_OFF(port, pin); diff --git a/stm/main.c b/stm/main.c index 313a868c41..b7d201cf02 100644 --- a/stm/main.c +++ b/stm/main.c @@ -30,6 +30,7 @@ #include "gc.h" #include "gccollect.h" #include "systick.h" +#include "pendsv.h" #include "led.h" #include "servo.h" #include "lcd.h" @@ -327,7 +328,7 @@ int readline(vstr_t *line, const char *prompt) { } } if (escape == 0) { - if (c == 4 && vstr_len(line) == len) { + if (c == VCP_CHAR_CTRL_D && vstr_len(line) == len) { return 0; } else if (c == '\r') { stdout_tx_str("\r\n"); @@ -435,10 +436,14 @@ void do_repl(void) { nlr_buf_t nlr; uint32_t start = sys_tick_counter; if (nlr_push(&nlr) == 0) { + usb_vcp_set_interrupt_char(VCP_CHAR_CTRL_C); // allow ctrl-C to interrupt us rt_call_function_0(module_fun); + usb_vcp_set_interrupt_char(VCP_CHAR_NONE); // disable interrupt nlr_pop(); } else { // uncaught exception + // FIXME it could be that an interrupt happens just before we disable it here + usb_vcp_set_interrupt_char(VCP_CHAR_NONE); // disable interrupt mp_obj_print_exception((mp_obj_t)nlr.ret_val); } @@ -488,11 +493,15 @@ bool do_file(const char *filename) { nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { + usb_vcp_set_interrupt_char(VCP_CHAR_CTRL_C); // allow ctrl-C to interrupt us rt_call_function_0(module_fun); + usb_vcp_set_interrupt_char(VCP_CHAR_NONE); // disable interrupt nlr_pop(); return true; } else { // uncaught exception + // FIXME it could be that an interrupt happens just before we disable it here + usb_vcp_set_interrupt_char(VCP_CHAR_NONE); // disable interrupt mp_obj_print_exception((mp_obj_t)nlr.ret_val); return false; } @@ -560,6 +569,10 @@ mp_obj_t pyb_rng_get(void) { return mp_obj_new_int(RNG_GetRandomNumber() >> 16); } +mp_obj_t pyb_millis(void) { + return mp_obj_new_int(sys_tick_counter); +} + int main(void) { // TODO disable JTAG @@ -592,6 +605,7 @@ int main(void) { // basic sub-system init sys_tick_init(); + pendsv_init(); led_init(); #if MICROPY_HW_ENABLE_RTC @@ -693,6 +707,7 @@ soft_reset: rt_store_attr(m, MP_QSTR_Usart, rt_make_function_n(2, pyb_Usart)); rt_store_attr(m, qstr_from_str("ADC_all"), (mp_obj_t)&pyb_ADC_all_obj); rt_store_attr(m, MP_QSTR_ADC, (mp_obj_t)&pyb_ADC_obj); + rt_store_attr(m, qstr_from_str("millis"), rt_make_function_n(0, pyb_millis)); rt_store_name(MP_QSTR_pyb, m); rt_store_name(MP_QSTR_open, rt_make_function_n(2, pyb_io_open)); diff --git a/stm/pendsv.c b/stm/pendsv.c new file mode 100644 index 0000000000..e8e5b840c6 --- /dev/null +++ b/stm/pendsv.c @@ -0,0 +1,49 @@ +#include <stdlib.h> +#include <stm32f4xx.h> + +#include "misc.h" +#include "mpconfig.h" +#include "qstr.h" +#include "obj.h" +#include "pendsv.h" + +static mp_obj_t pendsv_object = MP_OBJ_NULL; + +void pendsv_init(void) { + // set PendSV interrupt at lowest priority + NVIC_SetPriority(PendSV_IRQn, 0xff); +} + +// call this function to raise a pending exception during an interrupt +// it will wait until all interrupts are finished then raise the given +// exception object using nlr_jump in the context of the top-level thread +void pendsv_nlr_jump(mp_obj_t o) { + pendsv_object = o; + SCB->ICSR = SCB_ICSR_PENDSVSET_Msk; +} + +void pendsv_isr_handler(void) { + // re-jig the stack so that when we return from this interrupt handler + // it returns instead to nlr_jump with argument pendsv_object + __asm volatile ( + "ldr r0, pendsv_object_ptr\n" + "ldr r0, [r0]\n" + "str r0, [sp, #0]\n" + "ldr r0, nlr_jump_ptr\n" + "str r0, [sp, #24]\n" + "bx lr\n" + ".align 2\n" + "pendsv_object_ptr: .word pendsv_object\n" + "nlr_jump_ptr: .word nlr_jump\n" + ); + + /* + sp[0] = r0 = exception to raise + sp[6] = pc = nlr_jump + uint32_t x[2] = {0x424242, 0xdeaddead}; + printf("PendSV: %p\n", x); + for (uint32_t *p = (uint32_t*)(((uint32_t)x - 15) & 0xfffffff0), i = 64; i > 0; p += 4, i -= 4) { + printf(" %p: %08x %08x %08x %08x\n", p, p[0], p[1], p[2], p[3]); + } + */ +} diff --git a/stm/pendsv.h b/stm/pendsv.h new file mode 100644 index 0000000000..b07ab71375 --- /dev/null +++ b/stm/pendsv.h @@ -0,0 +1,3 @@ +void pendsv_init(void); +void pendsv_nlr_jump(mp_obj_t o); +void pendsv_isr_handler(void); diff --git a/stm/stm32fxxx_it.c b/stm/stm32fxxx_it.c index 7b5030bc6e..97cdee6a84 100644 --- a/stm/stm32fxxx_it.c +++ b/stm/stm32fxxx_it.c @@ -151,6 +151,8 @@ void DebugMon_Handler(void) */ void PendSV_Handler(void) { + extern void pendsv_isr_handler(void); + pendsv_isr_handler(); } /** diff --git a/stm/stmusbd/usbd_cdc_vcp.c b/stm/stmusbd/usbd_cdc_vcp.c index 6885f7cffe..cb16b58f1d 100644 --- a/stm/stmusbd/usbd_cdc_vcp.c +++ b/stm/stmusbd/usbd_cdc_vcp.c @@ -48,6 +48,9 @@ LINE_CODING linecoding = /* These are external variables imported from CDC core to be used for IN
transfer management. */
+
+extern uint32_t APP_dev_is_connected; // set if CDC device is connected
+
extern uint8_t APP_Rx_Buffer []; /* Write CDC received data in this buffer.
These data will be sent over USB IN endpoint
in the CDC core functions. */
@@ -62,8 +65,6 @@ static uint16_t VCP_Ctrl (uint32_t Cmd, uint8_t* Buf, uint32_t Len); static uint16_t VCP_DataTx (const uint8_t* Buf, uint32_t Len);
static uint16_t VCP_DataRx (uint8_t* Buf, uint32_t Len);
-extern int dev_is_connected;
-
CDC_IF_Prop_TypeDef VCP_fops =
{
VCP_Init,
@@ -160,7 +161,7 @@ static uint16_t VCP_Ctrl (uint32_t Cmd, uint8_t* Buf, uint32_t Len) break;
case SET_CONTROL_LINE_STATE:
- dev_is_connected = Len & 0x1; //wValue passed in Len
+ APP_dev_is_connected = Len & 0x1; // wValue is passed in Len (bit of a hack)
break;
case SEND_BREAK:
@@ -11,6 +11,7 @@ #include "mpconfig.h" #include "qstr.h" #include "obj.h" +#include "pendsv.h" #include "usb.h" #ifdef USE_DEVICE_MODE @@ -20,10 +21,12 @@ extern CDC_IF_Prop_TypeDef VCP_fops; USB_OTG_CORE_HANDLE USB_OTG_Core; static int dev_is_enabled = 0; -int dev_is_connected=0; /* used by usbd_cdc_vcp */ +uint32_t APP_dev_is_connected = 0; /* used by usbd_cdc_vcp */ static char rx_buf[64]; static int rx_buf_in; static int rx_buf_out; +static int interrupt_char = VCP_CHAR_NONE; +mp_obj_t mp_const_vcp_interrupt = MP_OBJ_NULL; void pyb_usb_dev_init(void) { #ifdef USE_DEVICE_MODE @@ -34,7 +37,11 @@ void pyb_usb_dev_init(void) { } rx_buf_in = 0; rx_buf_out = 0; + interrupt_char = VCP_CHAR_NONE; dev_is_enabled = 1; + + // create an exception object for interrupting by VCP + mp_const_vcp_interrupt = mp_obj_new_exception(qstr_from_str("VCPInterrupt")); #endif } @@ -43,12 +50,27 @@ bool usb_vcp_is_enabled(void) { } bool usb_vcp_is_connected(void) { - return dev_is_connected; + return APP_dev_is_connected; +} + +void usb_vcp_set_interrupt_char(int c) { + if (dev_is_enabled) { + interrupt_char = c; + } } void usb_vcp_receive(const char *buf, uint32_t len) { if (dev_is_enabled) { for (int i = 0; i < len; i++) { + + // catch special interrupt character + if (buf[i] == interrupt_char) { + // raise exception when interrupts are finished + pendsv_nlr_jump(mp_const_vcp_interrupt); + interrupt_char = VCP_CHAR_NONE; + continue; + } + rx_buf[rx_buf_in++] = buf[i]; if (rx_buf_in >= sizeof(rx_buf)) { rx_buf_in = 0; @@ -1,6 +1,11 @@ +#define VCP_CHAR_NONE (0) +#define VCP_CHAR_CTRL_C (3) +#define VCP_CHAR_CTRL_D (4) + void pyb_usb_dev_init(void); bool usb_vcp_is_enabled(void); bool usb_vcp_is_connected(void); +void usb_vcp_set_interrupt_char(int c); int usb_vcp_rx_any(void); char usb_vcp_rx_get(void); void usb_vcp_send_str(const char* str); |