diff options
32 files changed, 708 insertions, 222 deletions
diff --git a/examples/blinky.cpp b/examples/blinky.cpp index fad71f8..751475e 100644 --- a/examples/blinky.cpp +++ b/examples/blinky.cpp @@ -6,18 +6,11 @@ void setup() { pinMode(BOARD_LED_PIN, OUTPUT); } -int toggle = 1; - void loop() { - // You could just use toggleLED() instead, but this illustrates - // the use of digitalWrite(): - digitalWrite(BOARD_LED_PIN, toggle); - toggle ^= 1; + togglePin(BOARD_LED_PIN); delay(100); } -// Force init to be called *first*, i.e. before static object allocation. -// Otherwise, statically allocated objects that need libmaple may fail. __attribute__((constructor)) void premain() { init(); } diff --git a/examples/exti-interrupt-callback.cpp b/examples/exti-interrupt-callback.cpp new file mode 100644 index 0000000..c87c064 --- /dev/null +++ b/examples/exti-interrupt-callback.cpp @@ -0,0 +1,87 @@ +// Toggles the built-in LED when the built in button +// on the Maple is pushed in. This uses the attachInterrupt function to +// setup the interrupt handler for the button being pressed. +// +// This is similar to the exti-interrupt example, but shows the use of a class +// method to handle interrupts. +// +// More about attachInterrupt: +// http://leaflabs.com/docs/lang/api/attachinterrupt.html +// + + +#include <wirish/wirish.h> + +class MyAwesomeClass { +public: + // Setup the interrupt handler + void initialize() { + // LED is off by default + this->isLEDOn = false; + + // Attach interrupt to class method handler + attachInterrupt(BOARD_BUTTON_PIN, buttonInterruptHandler, this, RISING); + } + +private: + + bool isLEDOn; + + // Static event handler takes a void * argument that was originally + // passed to the attachInterrupt call. If the argument in question is an + // instance of the class (MyAwesomeClass in this case), the static function + // get access to that instance's data (even private data). + // + // In other words, this setup allows the Maple to have class method + // interrupt handlers (albeit with a work around). + // + // However, as you might imagine, this argument can be anything (if you + // don't need instance data access). + // + static void buttonInterruptHandler(void *arg) { + // Cast the "generic" void argument to the class instance. + MyAwesomeClass *instance = (MyAwesomeClass *)arg; + + // Accessing private instance data + instance->isLEDOn = !(instance->isLEDOn); + + // Set LED + digitalWrite(BOARD_LED_PIN, instance->isLEDOn); + + // Delay slightly for switch de-bouncing + delay(20); + } +}; + +MyAwesomeClass myClass; + +// Setup pin modes and the interrupt handler class +void setup() { + pinMode(BOARD_BUTTON_PIN, INPUT); + pinMode(BOARD_LED_PIN, OUTPUT); + + // The initialize method sets up the event handler to the private method + // in MyAwesomeClass. There is however, nothing stopping you from setting + // up event handlers which are public methods in classes. + myClass.initialize(); +} + +// Loop. Does nothing in this example. +void loop() { + +} + +// Force init to be called *first*, i.e. before static object allocation. +// Otherwise, statically allocated objects that need libmaple may fail. +__attribute__((constructor)) void premain() { + init(); +} + +int main(void) { + setup(); + + while (true) { + loop(); + } + return 0; +} diff --git a/examples/exti-interrupt.cpp b/examples/exti-interrupt.cpp new file mode 100644 index 0000000..89382d7 --- /dev/null +++ b/examples/exti-interrupt.cpp @@ -0,0 +1,50 @@ +// Toggles the built-in LED when the built in button +// on the Maple is pushed in. This uses the attachInterrupt function to +// setup the interrupt handler for the button being pressed. +// +// More about attachInterrupt: +// http://leaflabs.com/docs/lang/api/attachinterrupt.html +// + +#include <wirish/wirish.h> + +// LED is off by default +bool isLEDOn = false; + +// Interrupt handler takes in nothing and returns nothing. +void interruptHandler() { + // Set LED + isLEDOn = !isLEDOn; + digitalWrite(BOARD_LED_PIN, isLEDOn); + + // Delay slightly for switch debouncing. + delay(20); +} + +// Setup pin modes and the interrupt handler +void setup() { + pinMode(BOARD_BUTTON_PIN, INPUT); + pinMode(BOARD_LED_PIN, OUTPUT); + + attachInterrupt(BOARD_BUTTON_PIN, interruptHandler, RISING); +} + +// Loop. Does nothing in this example. +void loop() { + +} + +// Force init to be called *first*, i.e. before static object allocation. +// Otherwise, statically allocated objects that need libmaple may fail. +__attribute__((constructor)) void premain() { + init(); +} + +int main(void) { + setup(); + + while (true) { + loop(); + } + return 0; +} diff --git a/libmaple/adc.c b/libmaple/adc.c index e108332..7ea85dd 100644 --- a/libmaple/adc.c +++ b/libmaple/adc.c @@ -2,6 +2,7 @@ * The MIT License * * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2011, 2012 LeafLabs, LLC. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation diff --git a/libmaple/exti.c b/libmaple/exti.c index 9023782..f8ee8c3 100644 --- a/libmaple/exti.c +++ b/libmaple/exti.c @@ -43,27 +43,27 @@ static inline void dispatch_extis(uint32 start, uint32 stop); */ typedef struct exti_channel { - void (*handler)(void); - uint32 irq_line; + void (*handler)(void *); + void *arg; } exti_channel; static exti_channel exti_channels[] = { - { .handler = NULL, .irq_line = NVIC_EXTI0 }, // EXTI0 - { .handler = NULL, .irq_line = NVIC_EXTI1 }, // EXTI1 - { .handler = NULL, .irq_line = NVIC_EXTI2 }, // EXTI2 - { .handler = NULL, .irq_line = NVIC_EXTI3 }, // EXTI3 - { .handler = NULL, .irq_line = NVIC_EXTI4 }, // EXTI4 - { .handler = NULL, .irq_line = NVIC_EXTI_9_5 }, // EXTI5 - { .handler = NULL, .irq_line = NVIC_EXTI_9_5 }, // EXTI6 - { .handler = NULL, .irq_line = NVIC_EXTI_9_5 }, // EXTI7 - { .handler = NULL, .irq_line = NVIC_EXTI_9_5 }, // EXTI8 - { .handler = NULL, .irq_line = NVIC_EXTI_9_5 }, // EXTI9 - { .handler = NULL, .irq_line = NVIC_EXTI_15_10 }, // EXTI10 - { .handler = NULL, .irq_line = NVIC_EXTI_15_10 }, // EXTI11 - { .handler = NULL, .irq_line = NVIC_EXTI_15_10 }, // EXTI12 - { .handler = NULL, .irq_line = NVIC_EXTI_15_10 }, // EXTI13 - { .handler = NULL, .irq_line = NVIC_EXTI_15_10 }, // EXTI14 - { .handler = NULL, .irq_line = NVIC_EXTI_15_10 }, // EXTI15 + { .handler = NULL, .arg = NULL }, // EXTI0 + { .handler = NULL, .arg = NULL }, // EXTI1 + { .handler = NULL, .arg = NULL }, // EXTI2 + { .handler = NULL, .arg = NULL }, // EXTI3 + { .handler = NULL, .arg = NULL }, // EXTI4 + { .handler = NULL, .arg = NULL }, // EXTI5 + { .handler = NULL, .arg = NULL }, // EXTI6 + { .handler = NULL, .arg = NULL }, // EXTI7 + { .handler = NULL, .arg = NULL }, // EXTI8 + { .handler = NULL, .arg = NULL }, // EXTI9 + { .handler = NULL, .arg = NULL }, // EXTI10 + { .handler = NULL, .arg = NULL }, // EXTI11 + { .handler = NULL, .arg = NULL }, // EXTI12 + { .handler = NULL, .arg = NULL }, // EXTI13 + { .handler = NULL, .arg = NULL }, // EXTI14 + { .handler = NULL, .arg = NULL }, // EXTI15 }; /* @@ -90,10 +90,37 @@ void exti_attach_interrupt(exti_num num, exti_cfg port, voidFuncPtr handler, exti_trigger_mode mode) { + // Call callback version with arg being null + exti_attach_callback(num, port, (voidArgumentFuncPtr)handler, NULL, mode); +} + +/** + * @brief Register a handler with an argument to run upon external interrupt. + * + * This function assumes that the interrupt request corresponding to + * the given external interrupt is masked. + * + * @param num External interrupt line number. + * @param port Port to use as source input for external interrupt. + * @param handler Function handler to execute when interrupt is triggered. + * @param arg Argument to pass to the interrupt handler. + * @param mode Type of transition to trigger on, one of: + * EXTI_RISING, EXTI_FALLING, EXTI_RISING_FALLING. + * @see exti_num + * @see exti_cfg + * @see voidFuncPtr + * @see exti_trigger_mode + */ +void exti_attach_callback(exti_num num, + exti_cfg port, + voidArgumentFuncPtr handler, + void *arg, + exti_trigger_mode mode) { ASSERT(handler); /* Register the handler */ exti_channels[num].handler = handler; + exti_channels[num].arg = arg; /* Set trigger mode */ switch (mode) { @@ -116,7 +143,39 @@ void exti_attach_interrupt(exti_num num, bb_peri_set_bit(&EXTI_BASE->IMR, num, 1); /* Enable the interrupt line */ - nvic_irq_enable(exti_channels[num].irq_line); + switch(num) + { + case EXTI0: + nvic_irq_enable(NVIC_EXTI0); + break; + case EXTI1: + nvic_irq_enable(NVIC_EXTI1); + break; + case EXTI2: + nvic_irq_enable(NVIC_EXTI2); + break; + case EXTI3: + nvic_irq_enable(NVIC_EXTI3); + break; + case EXTI4: + nvic_irq_enable(NVIC_EXTI4); + break; + case EXTI5: + case EXTI6: + case EXTI7: + case EXTI8: + case EXTI9: + nvic_irq_enable(NVIC_EXTI_9_5); + break; + case EXTI10: + case EXTI11: + case EXTI12: + case EXTI13: + case EXTI14: + case EXTI15: + nvic_irq_enable(NVIC_EXTI_15_10); + break; + } } /** @@ -134,6 +193,7 @@ void exti_detach_interrupt(exti_num num) { /* Finally, unregister the user's handler */ exti_channels[num].handler = NULL; + exti_channels[num].arg = NULL; } /* @@ -199,13 +259,13 @@ static __always_inline void clear_pending_msk(uint32 exti_msk) { /* This dispatch routine is for non-multiplexed EXTI lines only; i.e., * it doesn't check EXTI_PR. */ static __always_inline void dispatch_single_exti(uint32 exti) { - voidFuncPtr handler = exti_channels[exti].handler; + voidArgumentFuncPtr handler = exti_channels[exti].handler; if (!handler) { return; } - handler(); + handler(exti_channels[exti].arg); clear_pending_msk(1U << exti); } @@ -219,9 +279,9 @@ static __always_inline void dispatch_extis(uint32 start, uint32 stop) { for (exti = start; exti <= stop; exti++) { uint32 eb = (1U << exti); if (pr & eb) { - voidFuncPtr handler = exti_channels[exti].handler; + voidArgumentFuncPtr handler = exti_channels[exti].handler; if (handler) { - handler(); + handler(exti_channels[exti].arg); handled_msk |= eb; } } diff --git a/libmaple/flash.c b/libmaple/flash.c index 0cdff59..c57bbbf 100644 --- a/libmaple/flash.c +++ b/libmaple/flash.c @@ -2,6 +2,7 @@ * The MIT License * * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2011, 2012 LeafLabs, LLC. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation diff --git a/libmaple/gpio.c b/libmaple/gpio.c index 898007a..6e63d2f 100644 --- a/libmaple/gpio.c +++ b/libmaple/gpio.c @@ -2,6 +2,7 @@ * The MIT License * * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2011, 2012 LeafLabs, LLC. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation diff --git a/libmaple/include/libmaple/exti.h b/libmaple/include/libmaple/exti.h index 3800b4a..1d201ac 100644 --- a/libmaple/include/libmaple/exti.h +++ b/libmaple/include/libmaple/exti.h @@ -115,6 +115,11 @@ void exti_attach_interrupt(exti_num num, exti_cfg port, voidFuncPtr handler, exti_trigger_mode mode); +void exti_attach_callback(exti_num num, + exti_cfg port, + voidArgumentFuncPtr handler, + void *arg, + exti_trigger_mode mode); void exti_detach_interrupt(exti_num num); /** diff --git a/libmaple/include/libmaple/libmaple_types.h b/libmaple/include/libmaple/libmaple_types.h index 9e1fbb3..60dd2ff 100644 --- a/libmaple/include/libmaple/libmaple_types.h +++ b/libmaple/include/libmaple/libmaple_types.h @@ -48,6 +48,7 @@ typedef int int32; typedef long long int64; typedef void (*voidFuncPtr)(void); +typedef void (*voidArgumentFuncPtr)(void *); #define __io volatile #define __attr_flash __attribute__((section (".USER_FLASH"))) diff --git a/libmaple/include/libmaple/usb.h b/libmaple/include/libmaple/usb.h index 2be5971..ea24030 100644 --- a/libmaple/include/libmaple/usb.h +++ b/libmaple/include/libmaple/usb.h @@ -151,6 +151,7 @@ typedef struct usblib_dev { void (**ep_int_in)(void); void (**ep_int_out)(void); usb_dev_state state; + usb_dev_state prevState; rcc_clk_id clk_id; } usblib_dev; diff --git a/libmaple/include/libmaple/usb_cdcacm.h b/libmaple/include/libmaple/usb_cdcacm.h index 8b3c1fe..5fe832c 100644 --- a/libmaple/include/libmaple/usb_cdcacm.h +++ b/libmaple/include/libmaple/usb_cdcacm.h @@ -72,6 +72,27 @@ extern "C" { #define USB_INTERFACE_SUBCLASS_CDC_ACM 0x02 #define USB_INTERFACE_CLASS_DIC 0x0A +/* + * Endpoint configuration + */ + +#define USB_CDCACM_CTRL_ENDP 0 +#define USB_CDCACM_CTRL_RX_ADDR 0x40 +#define USB_CDCACM_CTRL_TX_ADDR 0x80 +#define USB_CDCACM_CTRL_EPSIZE 0x40 + +#define USB_CDCACM_TX_ENDP 1 +#define USB_CDCACM_TX_ADDR 0xC0 +#define USB_CDCACM_TX_EPSIZE 0x40 + +#define USB_CDCACM_MANAGEMENT_ENDP 2 +#define USB_CDCACM_MANAGEMENT_ADDR 0x100 +#define USB_CDCACM_MANAGEMENT_EPSIZE 0x40 + +#define USB_CDCACM_RX_ENDP 3 +#define USB_CDCACM_RX_ADDR 0x110 +#define USB_CDCACM_RX_EPSIZE 0x40 + #ifndef __cplusplus #define USB_CDCACM_DECLARE_DEV_DESC(vid, pid) \ { \ @@ -106,6 +127,7 @@ uint32 usb_cdcacm_peek(uint8* buf, uint32 len); uint32 usb_cdcacm_data_available(void); /* in RX buffer */ uint16 usb_cdcacm_get_pending(void); +uint8 usb_cdcacm_is_transmitting(void); uint8 usb_cdcacm_get_dtr(void); uint8 usb_cdcacm_get_rts(void); diff --git a/libmaple/nvic.c b/libmaple/nvic.c index fe7c7bc..149e780 100644 --- a/libmaple/nvic.c +++ b/libmaple/nvic.c @@ -2,6 +2,7 @@ * The MIT License * * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2011 LeafLabs, LLC. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation diff --git a/libmaple/stm32f1/bkp.c b/libmaple/stm32f1/bkp.c index f435ff1..01ad419 100644 --- a/libmaple/stm32f1/bkp.c +++ b/libmaple/stm32f1/bkp.c @@ -62,14 +62,14 @@ void bkp_init(void) { * @see bkp_init() */ void bkp_enable_writes(void) { - *bb_perip(&PWR_BASE->CR, PWR_CR_DBP) = 1; + *bb_perip(&PWR_BASE->CR, PWR_CR_DBP_BIT) = 1; } /** * Disable write access to the backup registers. */ void bkp_disable_writes(void) { - *bb_perip(&PWR_BASE->CR, PWR_CR_DBP) = 0; + *bb_perip(&PWR_BASE->CR, PWR_CR_DBP_BIT) = 0; } /** diff --git a/libmaple/stm32f1/dma.c b/libmaple/stm32f1/dma.c index 5364a04..6400d15 100644 --- a/libmaple/stm32f1/dma.c +++ b/libmaple/stm32f1/dma.c @@ -145,6 +145,7 @@ static int config_to_per(dma_tube_reg_map *chregs, dma_tube_config *cfg) { cfg->tube_src_size, cfg->tube_flags & DMA_CFG_SRC_INC, cfg->tube_dst_size, cfg->tube_flags & DMA_CFG_DST_INC, (cfg_ccr_flags(cfg->tube_flags) | DMA_CCR_DIR_FROM_MEM)); + chregs->CNDTR = cfg->tube_nr_xfers; chregs->CMAR = (uint32)cfg->tube_src; chregs->CPAR = (uint32)cfg->tube_dst; return DMA_TUBE_CFG_SUCCESS; diff --git a/libmaple/stm32f1/include/series/dma.h b/libmaple/stm32f1/include/series/dma.h index 3b19e2b..bedb602 100644 --- a/libmaple/stm32f1/include/series/dma.h +++ b/libmaple/stm32f1/include/series/dma.h @@ -145,6 +145,16 @@ typedef struct dma_tube_reg_map { /* Interrupt status register */ +#define DMA_ISR_TEIF_BIT 3 +#define DMA_ISR_HTIF_BIT 2 +#define DMA_ISR_TCIF_BIT 1 +#define DMA_ISR_GIF_BIT 0 + +#define DMA_ISR_TEIF (1 << DMA_ISR_TEIF_BIT) +#define DMA_ISR_HTIF (1 << DMA_ISR_HTIF_BIT) +#define DMA_ISR_TCID (1 << DMA_ISR_TCIF_BIT) +#define DMA_ISR_GIF (1 << DMA_ISR_GIF_BIT) + #define DMA_ISR_TEIF7_BIT 27 #define DMA_ISR_HTIF7_BIT 26 #define DMA_ISR_TCIF7_BIT 25 diff --git a/libmaple/stm32f1/performance/isrs.S b/libmaple/stm32f1/performance/isrs.S index a8f0709..c638078 100644 --- a/libmaple/stm32f1/performance/isrs.S +++ b/libmaple/stm32f1/performance/isrs.S @@ -26,6 +26,8 @@ /* STM32F1 performance line ISR weak declarations */ +#include <libmaple/stm32.h> + .thumb /* Default handler for all non-overridden interrupts and exceptions */ diff --git a/libmaple/stm32f1/performance/vector_table.S b/libmaple/stm32f1/performance/vector_table.S index b489b94..8be3fa6 100644 --- a/libmaple/stm32f1/performance/vector_table.S +++ b/libmaple/stm32f1/performance/vector_table.S @@ -26,6 +26,8 @@ /* STM32F1 performance line vector table */ +#include <libmaple/stm32.h> + .section ".stm32.interrupt_vector" .globl __stm32_vector_table diff --git a/libmaple/stm32f1/rules.mk b/libmaple/stm32f1/rules.mk index 3ca0813..f1cc23e 100644 --- a/libmaple/stm32f1/rules.mk +++ b/libmaple/stm32f1/rules.mk @@ -6,6 +6,7 @@ BUILDDIRS += $(BUILD_PATH)/$(d) # Local flags CFLAGS_$(d) = -I$(d) $(LIBMAPLE_PRIVATE_INCLUDES) $(LIBMAPLE_INCLUDES) -Wall -Werror +ASFLAGS_$(d) = -I$(d) $(LIBMAPLE_PRIVATE_INCLUDES) $(LIBMAPLE_INCLUDES) -Wall -Werror # Extra BUILDDIRS BUILDDIRS += $(BUILD_PATH)/$(d)/$(MCU_F1_LINE) @@ -33,7 +34,7 @@ OBJS_$(d) := $(sFILES_$(d):%.S=$(BUILD_PATH)/%.o) \ $(cFILES_$(d):%.c=$(BUILD_PATH)/%.o) DEPS_$(d) := $(OBJS_$(d):%.o=%.d) -$(OBJS_$(d)): TGT_ASFLAGS := +$(OBJS_$(d)): TGT_ASFLAGS := $(ASFLAGS_$(d)) $(OBJS_$(d)): TGT_CFLAGS := $(CFLAGS_$(d)) TGT_BIN += $(OBJS_$(d)) diff --git a/libmaple/systick.c b/libmaple/systick.c index 80c0c47..7568abe 100644 --- a/libmaple/systick.c +++ b/libmaple/systick.c @@ -2,6 +2,7 @@ * The MIT License * * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2010, 2011 LeafLabs, LLC. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation diff --git a/libmaple/timer.c b/libmaple/timer.c index 24ae7fa..c22fe9d 100644 --- a/libmaple/timer.c +++ b/libmaple/timer.c @@ -38,7 +38,7 @@ static void disable_channel(timer_dev *dev, uint8 channel); static void pwm_mode(timer_dev *dev, uint8 channel); static void output_compare_mode(timer_dev *dev, uint8 channel); -static inline void enable_irq(timer_dev *dev, uint8 interrupt); +static inline void enable_irq(timer_dev *dev, timer_interrupt_id iid); /* * Devices diff --git a/libmaple/usart.c b/libmaple/usart.c index 253cf9f..1d88234 100644 --- a/libmaple/usart.c +++ b/libmaple/usart.c @@ -2,6 +2,7 @@ * The MIT License * * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2011 LeafLabs, LLC. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation diff --git a/libmaple/usb/stm32f1/usb.c b/libmaple/usb/stm32f1/usb.c index c20cc71..f694f04 100644 --- a/libmaple/usb/stm32f1/usb.c +++ b/libmaple/usb/stm32f1/usb.c @@ -28,7 +28,7 @@ * @file libmaple/usb/stm32f1/usb.c * @brief USB support. * - * This is a mess. What we need almost amounts to a ground-up rewrite. + * This is a mess. */ #include <libmaple/usb.h> @@ -69,13 +69,14 @@ typedef enum { } RESUME_STATE; struct { - volatile RESUME_STATE eState; - volatile uint8 bESOFcnt; + volatile RESUME_STATE eState; + volatile uint8 bESOFcnt; } ResumeS; static usblib_dev usblib = { .irq_mask = USB_ISR_MSK, .state = USB_UNCONNECTED, + .prevState = USB_UNCONNECTED, .clk_id = RCC_USB, }; usblib_dev *USBLIB = &usblib; @@ -105,147 +106,151 @@ void usb_init_usblib(usblib_dev *dev, } static void usb_suspend(void) { - uint16 cntr; - - /* TODO decide if read/modify/write is really what we want - * (e.g. usb_resume_init() reconfigures CNTR). */ - cntr = USB_BASE->CNTR; - cntr |= USB_CNTR_FSUSP; - USB_BASE->CNTR = cntr; - cntr |= USB_CNTR_LP_MODE; - USB_BASE->CNTR = cntr; - - USBLIB->state = USB_SUSPENDED; + uint16 cntr; + + /* TODO decide if read/modify/write is really what we want + * (e.g. usb_resume_init() reconfigures CNTR). */ + cntr = USB_BASE->CNTR; + cntr |= USB_CNTR_FSUSP; + USB_BASE->CNTR = cntr; + cntr |= USB_CNTR_LP_MODE; + USB_BASE->CNTR = cntr; + + USBLIB->prevState = USBLIB->state; + USBLIB->state = USB_SUSPENDED; } static void usb_resume_init(void) { - uint16 cntr; + uint16 cntr; - cntr = USB_BASE->CNTR; - cntr &= ~USB_CNTR_LP_MODE; - USB_BASE->CNTR = cntr; + cntr = USB_BASE->CNTR; + cntr &= ~USB_CNTR_LP_MODE; + USB_BASE->CNTR = cntr; - /* Enable interrupt lines */ - USB_BASE->CNTR = USB_ISR_MSK; + /* Enable interrupt lines */ + USB_BASE->CNTR = USB_ISR_MSK; } static void usb_resume(RESUME_STATE eResumeSetVal) { - uint16 cntr; + uint16 cntr; - if (eResumeSetVal != RESUME_ESOF) - ResumeS.eState = eResumeSetVal; + if (eResumeSetVal != RESUME_ESOF) { + ResumeS.eState = eResumeSetVal; + } - switch (ResumeS.eState) - { + switch (ResumeS.eState) { case RESUME_EXTERNAL: - usb_resume_init(); - ResumeS.eState = RESUME_OFF; - break; + usb_resume_init(); + ResumeS.eState = RESUME_OFF; + USBLIB->state = USBLIB->prevState; + break; case RESUME_INTERNAL: - usb_resume_init(); - ResumeS.eState = RESUME_START; - break; + usb_resume_init(); + ResumeS.eState = RESUME_START; + break; case RESUME_LATER: - ResumeS.bESOFcnt = 2; - ResumeS.eState = RESUME_WAIT; - break; + ResumeS.bESOFcnt = 2; + ResumeS.eState = RESUME_WAIT; + break; case RESUME_WAIT: - ResumeS.bESOFcnt--; - if (ResumeS.bESOFcnt == 0) - ResumeS.eState = RESUME_START; - break; + ResumeS.bESOFcnt--; + if (ResumeS.bESOFcnt == 0) { + ResumeS.eState = RESUME_START; + } + break; case RESUME_START: - cntr = USB_BASE->CNTR; - cntr |= USB_CNTR_RESUME; - USB_BASE->CNTR = cntr; - ResumeS.eState = RESUME_ON; - ResumeS.bESOFcnt = 10; - break; + cntr = USB_BASE->CNTR; + cntr |= USB_CNTR_RESUME; + USB_BASE->CNTR = cntr; + ResumeS.eState = RESUME_ON; + ResumeS.bESOFcnt = 10; + break; case RESUME_ON: - ResumeS.bESOFcnt--; - if (ResumeS.bESOFcnt == 0) { - cntr = USB_BASE->CNTR; - cntr &= ~USB_CNTR_RESUME; - USB_BASE->CNTR = cntr; - ResumeS.eState = RESUME_OFF; - } - break; + ResumeS.bESOFcnt--; + if (ResumeS.bESOFcnt == 0) { + cntr = USB_BASE->CNTR; + cntr &= ~USB_CNTR_RESUME; + USB_BASE->CNTR = cntr; + USBLIB->state = USBLIB->prevState; + ResumeS.eState = RESUME_OFF; + } + break; case RESUME_OFF: case RESUME_ESOF: default: - ResumeS.eState = RESUME_OFF; - break; + ResumeS.eState = RESUME_OFF; + break; } } #define SUSPEND_ENABLED 1 void __irq_usb_lp_can_rx0(void) { - uint16 istr = USB_BASE->ISTR; + uint16 istr = USB_BASE->ISTR; - /* Use USB_ISR_MSK to only include code for bits we care about. */ + /* Use USB_ISR_MSK to only include code for bits we care about. */ #if (USB_ISR_MSK & USB_ISTR_RESET) - if (istr & USB_ISTR_RESET & USBLIB->irq_mask) { - USB_BASE->ISTR = ~USB_ISTR_RESET; - pProperty->Reset(); - } + if (istr & USB_ISTR_RESET & USBLIB->irq_mask) { + USB_BASE->ISTR = ~USB_ISTR_RESET; + pProperty->Reset(); + } #endif #if (USB_ISR_MSK & USB_ISTR_PMAOVR) - if (istr & ISTR_PMAOVR & USBLIB->irq_mask) { - USB_BASE->ISTR = ~USB_ISTR_PMAOVR; - } + if (istr & ISTR_PMAOVR & USBLIB->irq_mask) { + USB_BASE->ISTR = ~USB_ISTR_PMAOVR; + } #endif #if (USB_ISR_MSK & USB_ISTR_ERR) - if (istr & USB_ISTR_ERR & USBLIB->irq_mask) { - USB_BASE->ISTR = ~USB_ISTR_ERR; - } + if (istr & USB_ISTR_ERR & USBLIB->irq_mask) { + USB_BASE->ISTR = ~USB_ISTR_ERR; + } #endif #if (USB_ISR_MSK & USB_ISTR_WKUP) - if (istr & USB_ISTR_WKUP & USBLIB->irq_mask) { - USB_BASE->ISTR = ~USB_ISTR_WKUP; - usb_resume(RESUME_EXTERNAL); - } + if (istr & USB_ISTR_WKUP & USBLIB->irq_mask) { + USB_BASE->ISTR = ~USB_ISTR_WKUP; + usb_resume(RESUME_EXTERNAL); + } #endif #if (USB_ISR_MSK & USB_ISTR_SUSP) - if (istr & USB_ISTR_SUSP & USBLIB->irq_mask) { - /* check if SUSPEND is possible */ - if (SUSPEND_ENABLED) { - usb_suspend(); - } else { - /* if not possible then resume after xx ms */ - usb_resume(RESUME_LATER); + if (istr & USB_ISTR_SUSP & USBLIB->irq_mask) { + /* check if SUSPEND is possible */ + if (SUSPEND_ENABLED) { + usb_suspend(); + } else { + /* if not possible then resume after xx ms */ + usb_resume(RESUME_LATER); + } + /* clear of the ISTR bit must be done after setting of CNTR_FSUSP */ + USB_BASE->ISTR = ~USB_ISTR_SUSP; } - /* clear of the ISTR bit must be done after setting of CNTR_FSUSP */ - USB_BASE->ISTR = ~USB_ISTR_SUSP; -} #endif #if (USB_ISR_MSK & USB_ISTR_SOF) - if (istr & USB_ISTR_SOF & USBLIB->irq_mask) { - USB_BASE->ISTR = ~USB_ISTR_SOF; - } + if (istr & USB_ISTR_SOF & USBLIB->irq_mask) { + USB_BASE->ISTR = ~USB_ISTR_SOF; + } #endif #if (USB_ISR_MSK & USB_ISTR_ESOF) - if (istr & USB_ISTR_ESOF & USBLIB->irq_mask) { - USB_BASE->ISTR = ~USB_ISTR_ESOF; - /* resume handling timing is made with ESOFs */ - usb_resume(RESUME_ESOF); /* request without change of the machine state */ - } + if (istr & USB_ISTR_ESOF & USBLIB->irq_mask) { + USB_BASE->ISTR = ~USB_ISTR_ESOF; + /* resume handling timing is made with ESOFs */ + usb_resume(RESUME_ESOF); /* request without change of the machine state */ + } #endif - /* - * Service the correct transfer interrupt. - */ + /* + * Service the correct transfer interrupt. + */ #if (USB_ISR_MSK & USB_ISTR_CTR) - if (istr & USB_ISTR_CTR & USBLIB->irq_mask) { - dispatch_ctr_lp(); - } + if (istr & USB_ISTR_CTR & USBLIB->irq_mask) { + dispatch_ctr_lp(); + } #endif } @@ -274,8 +279,9 @@ static void dispatch_ctr_lp() { * once we're done serving endpoint zero, but not okay if * there are multiple nonzero endpoint transfers to * handle. */ - if (dispatch_endpt_zero(istr & USB_ISTR_DIR)) + if (dispatch_endpt_zero(istr & USB_ISTR_DIR)) { return; + } } else { dispatch_endpt(ep_id); } diff --git a/libmaple/usb/stm32f1/usb_cdcacm.c b/libmaple/usb/stm32f1/usb_cdcacm.c index fc70e39..d4d4262 100644 --- a/libmaple/usb/stm32f1/usb_cdcacm.c +++ b/libmaple/usb/stm32f1/usb_cdcacm.c @@ -82,27 +82,6 @@ static void usbSetConfiguration(void); static void usbSetDeviceAddress(void); /* - * Endpoint configuration - */ - -#define USB_CDCACM_CTRL_ENDP 0 -#define USB_CDCACM_CTRL_RX_ADDR 0x40 -#define USB_CDCACM_CTRL_TX_ADDR 0x80 -#define USB_CDCACM_CTRL_EPSIZE 0x40 - -#define USB_CDCACM_TX_ENDP 1 -#define USB_CDCACM_TX_ADDR 0xC0 -#define USB_CDCACM_TX_EPSIZE 0x40 - -#define USB_CDCACM_MANAGEMENT_ENDP 2 -#define USB_CDCACM_MANAGEMENT_ADDR 0x100 -#define USB_CDCACM_MANAGEMENT_EPSIZE 0x40 - -#define USB_CDCACM_RX_ENDP 3 -#define USB_CDCACM_RX_ADDR 0x110 -#define USB_CDCACM_RX_EPSIZE 0x40 - -/* * Descriptors */ @@ -288,6 +267,8 @@ static volatile uint8 vcomBufferRx[USB_CDCACM_RX_EPSIZE]; static volatile uint32 rx_offset = 0; /* Number of bytes left to transmit */ static volatile uint32 n_unsent_bytes = 0; +/* Are we currently sending an IN packet? */ +static volatile uint8 transmitting = 0; /* Number of unread bytes */ static volatile uint32 n_unread_bytes = 0; @@ -328,16 +309,19 @@ static void (*ep_int_out[7])(void) = /* * Globals required by usb_lib/ + * + * Mark these weak so they can be overriden to implement other USB + * functionality. */ #define NUM_ENDPTS 0x04 -DEVICE Device_Table = { +__weak DEVICE Device_Table = { .Total_Endpoint = NUM_ENDPTS, .Total_Configuration = 1 }; #define MAX_PACKET_SIZE 0x40 /* 64B, maximum for USB FS Devices */ -DEVICE_PROP Device_Property = { +__weak DEVICE_PROP Device_Property = { .Init = usbInit, .Reset = usbReset, .Process_Status_IN = NOP_Process, @@ -352,7 +336,7 @@ DEVICE_PROP Device_Property = { .MaxPacketSize = MAX_PACKET_SIZE }; -USER_STANDARD_REQUESTS User_Standard_Requests = { +__weak USER_STANDARD_REQUESTS User_Standard_Requests = { .User_GetConfiguration = NOP_Process, .User_SetConfiguration = usbSetConfiguration, .User_GetInterface = NOP_Process, @@ -413,7 +397,7 @@ void usb_cdcacm_putc(char ch) { * buffer, and returns the number of bytes copied. */ uint32 usb_cdcacm_tx(const uint8* buf, uint32 len) { /* Last transmission hasn't finished, so abort. */ - if (n_unsent_bytes) { + if (usb_cdcacm_is_transmitting()) { return 0; } @@ -425,10 +409,14 @@ uint32 usb_cdcacm_tx(const uint8* buf, uint32 len) { /* Queue bytes for sending. */ if (len) { usb_copy_to_pma(buf, len, USB_CDCACM_TX_ADDR); - usb_set_ep_tx_count(USB_CDCACM_TX_ENDP, len); - n_unsent_bytes = len; - usb_set_ep_tx_stat(USB_CDCACM_TX_ENDP, USB_EP_STAT_TX_VALID); } + // We still need to wait for the interrupt, even if we're sending + // zero bytes. (Sending zero-size packets is useful for flushing + // host-side buffers.) + usb_set_ep_tx_count(USB_CDCACM_TX_ENDP, len); + n_unsent_bytes = len; + transmitting = 1; + usb_set_ep_tx_stat(USB_CDCACM_TX_ENDP, USB_EP_STAT_TX_VALID); return len; } @@ -437,7 +425,11 @@ uint32 usb_cdcacm_data_available(void) { return n_unread_bytes; } -uint16 usb_cdcacm_get_pending() { +uint8 usb_cdcacm_is_transmitting(void) { + return transmitting; +} + +uint16 usb_cdcacm_get_pending(void) { return n_unsent_bytes; } @@ -518,12 +510,8 @@ int usb_cdcacm_get_n_data_bits(void) { */ static void vcomDataTxCb(void) { - /* The following assumes that all of the bytes we copied during - * the last call to usb_cdcacm_tx were sent during the IN - * transaction (this seems to be the case). */ - /* TODO find out why this is broken: - * n_unsent_bytes = usb_get_ep_tx_count(USB_CDCACM_TX_ENDP); */ n_unsent_bytes = 0; + transmitting = 0; } static void vcomDataRxCb(void) { @@ -535,6 +523,13 @@ static void vcomDataRxCb(void) { usb_copy_from_pma((uint8*)vcomBufferRx, n_unread_bytes, USB_CDCACM_RX_ADDR); + + if (n_unread_bytes == 0) { + usb_set_ep_rx_count(USB_CDCACM_RX_ENDP, USB_CDCACM_RX_EPSIZE); + usb_set_ep_rx_stat(USB_CDCACM_RX_ENDP, USB_EP_STAT_RX_VALID); + rx_offset = 0; + } + if (rx_hook) { rx_hook(USB_CDCACM_HOOK_RX, 0); } @@ -614,6 +609,7 @@ static void usbReset(void) { n_unread_bytes = 0; n_unsent_bytes = 0; rx_offset = 0; + transmitting = 0; } static RESULT usbDataSetup(uint8 request) { diff --git a/libmaple/usb/stm32f1/usb_reg_map.c b/libmaple/usb/stm32f1/usb_reg_map.c index 75562e1..ea60cb3 100644 --- a/libmaple/usb/stm32f1/usb_reg_map.c +++ b/libmaple/usb/stm32f1/usb_reg_map.c @@ -58,8 +58,7 @@ void usb_copy_from_pma(uint8 *buf, uint16 len, uint16 pma_offset) { } } -void usb_set_ep_rx_count(uint8 ep, uint16 count) { - uint32 *rxc = usb_ep_rx_count_ptr(ep); +static void usb_set_ep_rx_count_common(uint32 *rxc, uint16 count) { uint16 nblocks; if (count > 62) { /* use 32-byte memory block size */ @@ -77,3 +76,13 @@ void usb_set_ep_rx_count(uint8 ep, uint16 count) { *rxc = nblocks << 10; } } + +void usb_set_ep_rx_buf0_count(uint8 ep, uint16 count) { + uint32 *rxc = usb_ep_rx_buf0_count_ptr(ep); + usb_set_ep_rx_count_common(rxc, count); +} + +void usb_set_ep_rx_count(uint8 ep, uint16 count) { + uint32 *rxc = usb_ep_rx_count_ptr(ep); + usb_set_ep_rx_count_common(rxc, count); +} diff --git a/libmaple/usb/stm32f1/usb_reg_map.h b/libmaple/usb/stm32f1/usb_reg_map.h index ea483d2..2e3f6bc 100644 --- a/libmaple/usb/stm32f1/usb_reg_map.h +++ b/libmaple/usb/stm32f1/usb_reg_map.h @@ -88,6 +88,7 @@ typedef struct usb_reg_map { #define USB_EP_EP_TYPE_ISO (0x2 << 9) #define USB_EP_EP_TYPE_INTERRUPT (0x3 << 9) #define USB_EP_EP_KIND BIT(USB_EP_EP_KIND_BIT) +#define USB_EP_EP_KIND_DBL_BUF (0x1 << USB_EP_EP_KIND_BIT) #define USB_EP_CTR_TX BIT(USB_EP_CTR_TX_BIT) #define USB_EP_DTOG_TX BIT(USB_EP_DTOG_TX_BIT) #define USB_EP_STAT_TX (0x3 << 4) @@ -205,6 +206,86 @@ static inline void usb_clear_ctr_tx(uint8 ep) { USB_BASE->EP[ep] = epr & ~USB_EP_CTR_TX & __EP_NONTOGGLE; } +static inline uint32 usb_get_ep_dtog_tx(uint8 ep) { + uint32 epr = USB_BASE->EP[ep]; + return epr & USB_EP_DTOG_TX; +} + +static inline uint32 usb_get_ep_dtog_rx(uint8 ep) { + uint32 epr = USB_BASE->EP[ep]; + return epr & USB_EP_DTOG_RX; +} + +static inline uint32 usb_get_ep_tx_sw_buf(uint8 ep) { + return usb_get_ep_dtog_rx(ep); +} + +static inline uint32 usb_get_ep_rx_sw_buf(uint8 ep) { + return usb_get_ep_dtog_tx(ep); +} + +static inline void usb_toggle_ep_dtog_tx(uint8 ep) { + uint32 epr = USB_BASE->EP[ep]; + epr &= __EP_NONTOGGLE; + epr |= USB_EP_DTOG_TX; + USB_BASE->EP[ep] = epr; +} + +static inline void usb_toggle_ep_dtog_rx(uint8 ep) { + uint32 epr = USB_BASE->EP[ep]; + epr &= __EP_NONTOGGLE; + epr |= USB_EP_DTOG_RX; + USB_BASE->EP[ep] = epr; +} + +static inline void usb_clear_ep_dtog_tx(uint8 ep) { + if (usb_get_ep_dtog_tx(ep) != 0) { + usb_toggle_ep_dtog_tx(ep); + } +} + +static inline void usb_clear_ep_dtog_rx(uint8 ep) { + if (usb_get_ep_dtog_rx(ep) != 0) { + usb_toggle_ep_dtog_rx(ep); + } +} + +static inline void usb_set_ep_dtog_tx(uint8 ep) { + if (usb_get_ep_dtog_tx(ep) == 0) { + usb_toggle_ep_dtog_tx(ep); + } +} + +static inline void usb_set_ep_dtog_rx(uint8 ep) { + if (usb_get_ep_dtog_rx(ep) == 0) { + usb_toggle_ep_dtog_rx(ep); + } +} + +static inline void usb_toggle_ep_rx_sw_buf(uint8 ep) { + usb_toggle_ep_dtog_tx(ep); +} + +static inline void usb_toggle_ep_tx_sw_buf(uint8 ep) { + usb_toggle_ep_dtog_rx(ep); +} + +static inline void usb_clear_ep_rx_sw_buf(uint8 ep) { + usb_clear_ep_dtog_tx(ep); +} + +static inline void usb_clear_ep_tx_sw_buf(uint8 ep) { + usb_clear_ep_dtog_rx(ep); +} + +static inline void usb_set_ep_rx_sw_buf(uint8 ep) { + usb_set_ep_dtog_tx(ep); +} + +static inline void usb_set_ep_tx_sw_buf(uint8 ep) { + usb_set_ep_dtog_rx(ep); +} + static inline void usb_set_ep_rx_stat(uint8 ep, uint32 status) { uint32 epr = USB_BASE->EP[ep]; epr &= ~(USB_EP_STAT_TX | USB_EP_DTOG_RX | USB_EP_DTOG_TX); @@ -235,6 +316,17 @@ static inline void usb_set_ep_kind(uint8 ep, uint32 kind) { USB_BASE->EP[ep] = epr; } +static inline uint32 usb_get_ep_type(uint8 ep) { + uint32 epr = USB_BASE->EP[ep]; + return epr & USB_EP_EP_TYPE; +} + +static inline uint32 usb_get_ep_kind(uint8 ep) { + uint32 epr = USB_BASE->EP[ep]; + return epr & USB_EP_EP_TYPE; +} + + static inline void usb_clear_status_out(uint8 ep) { usb_set_ep_kind(ep, 0); } @@ -275,42 +367,42 @@ union usb_btable_ent; /* Bidirectional endpoint BTABLE entry */ typedef struct usb_btable_bidi { - __io uint16 addr_tx; const uint16 PAD1; - __io uint16 count_tx; const uint16 PAD2; - __io uint16 addr_rx; const uint16 PAD3; - __io uint16 count_rx; const uint16 PAD4; + __io uint16 addr_tx; const uint16 PAD1; + __io uint16 count_tx; const uint16 PAD2; + __io uint16 addr_rx; const uint16 PAD3; + __io uint16 count_rx; const uint16 PAD4; } usb_btable_bidi; /* Unidirectional receive-only endpoint BTABLE entry */ typedef struct usb_btable_uni_rx { - __io uint16 empty1; const uint16 PAD1; - __io uint16 empty2; const uint16 PAD2; - __io uint16 addr_rx; const uint16 PAD3; - __io uint16 count_rx; const uint16 PAD4; + __io uint16 empty1; const uint16 PAD1; + __io uint16 empty2; const uint16 PAD2; + __io uint16 addr_rx; const uint16 PAD3; + __io uint16 count_rx; const uint16 PAD4; } usb_btable_uni_rx; /* Unidirectional transmit-only endpoint BTABLE entry */ typedef struct usb_btable_uni_tx { - __io uint16 addr_tx; const uint16 PAD1; - __io uint16 count_tx; const uint16 PAD2; - __io uint16 empty1; const uint16 PAD3; - __io uint16 empty2; const uint16 PAD4; + __io uint16 addr_tx; const uint16 PAD1; + __io uint16 count_tx; const uint16 PAD2; + __io uint16 empty1; const uint16 PAD3; + __io uint16 empty2; const uint16 PAD4; } usb_btable_uni_tx; /* Double-buffered transmission endpoint BTABLE entry */ typedef struct usb_btable_dbl_tx { - __io uint16 addr_tx0; const uint16 PAD1; - __io uint16 count_tx0; const uint16 PAD2; - __io uint16 addr_tx1; const uint16 PAD3; - __io uint16 count_tx1; const uint16 PAD4; + __io uint16 addr_tx0; const uint16 PAD1; + __io uint16 count_tx0; const uint16 PAD2; + __io uint16 addr_tx1; const uint16 PAD3; + __io uint16 count_tx1; const uint16 PAD4; } usb_btable_dbl_tx; /* Double-buffered reception endpoint BTABLE entry */ typedef struct usb_btable_dbl_rx { - __io uint16 addr_rx0; const uint16 PAD1; - __io uint16 count_rx0; const uint16 PAD2; - __io uint16 addr_rx1; const uint16 PAD3; - __io uint16 count_rx1; const uint16 PAD4; + __io uint16 addr_rx0; const uint16 PAD1; + __io uint16 count_rx0; const uint16 PAD2; + __io uint16 addr_rx1; const uint16 PAD3; + __io uint16 count_rx1; const uint16 PAD4; } usb_btable_dbl_rx; /* TODO isochronous endpoint entries */ @@ -336,10 +428,6 @@ static inline uint32* usb_btable_ptr(uint32 offset) { return (uint32*)usb_pma_ptr(USB_BASE->BTABLE + offset); } -static inline usb_btable_ent *usb_btable(void) { - return (usb_btable_ent*)usb_btable_ptr(0); -} - /* TX address */ static inline uint32* usb_ep_tx_addr_ptr(uint8 ep) { @@ -399,6 +487,100 @@ static inline uint16 usb_get_ep_rx_count(uint8 ep) { void usb_set_ep_rx_count(uint8 ep, uint16 count); +/* double buffer definitions */ +static inline uint32* usb_get_ep_tx_buf0_addr_ptr(uint8 ep) { + return usb_ep_tx_addr_ptr(ep); +} + +static inline uint16 usb_get_ep_tx_buf0_addr(uint8 ep) { + return usb_get_ep_tx_addr(ep); +} + +static inline void usb_set_ep_tx_buf0_addr(uint8 ep, uint16 addr) { + usb_set_ep_tx_addr(ep, addr); +} + +static inline uint32* usb_get_ep_tx_buf1_addr_ptr(uint8 ep) { + return usb_ep_rx_addr_ptr(ep); +} + +static inline uint16 usb_get_ep_tx_buf1_addr(uint8 ep) { + return usb_get_ep_rx_addr(ep); +} + +static inline void usb_set_ep_tx_buf1_addr(uint8 ep, uint16 addr) { + usb_set_ep_rx_addr(ep, addr); +} + +static inline uint32* usb_ep_tx_buf0_count_ptr(uint8 ep) { + return usb_ep_tx_count_ptr(ep); +} + +static inline uint16 usb_get_ep_tx_buf0_count(uint8 ep) { + return usb_get_ep_tx_count(ep); +} + +static inline void usb_set_ep_tx_buf0_count(uint8 ep, uint16 count) { + usb_set_ep_tx_count(ep, count); +} + +static inline uint32* usb_ep_tx_buf1_count_ptr(uint8 ep) { + return usb_ep_rx_count_ptr(ep); +} + +static inline uint16 usb_get_ep_tx_buf1_count(uint8 ep) { + return usb_get_ep_rx_count(ep); +} + +static inline void usb_set_ep_tx_buf1_count(uint8 ep, uint16 count) { + usb_set_ep_rx_count(ep, count); +} +static inline uint32* usb_get_ep_rx_buf0_addr_ptr(uint8 ep) { + return usb_ep_tx_addr_ptr(ep); +} + +static inline uint16 usb_get_ep_rx_buf0_addr(uint8 ep) { + return usb_get_ep_tx_addr(ep); +} + +static inline void usb_set_ep_rx_buf0_addr(uint8 ep, uint16 addr) { + usb_set_ep_tx_addr(ep, addr); +} + +static inline uint32* usb_get_ep_rx_buf1_addr_ptr(uint8 ep) { + return usb_ep_rx_addr_ptr(ep); +} + +static inline uint16 usb_get_ep_rx_buf1_addr(uint8 ep) { + return usb_get_ep_rx_addr(ep); +} + +static inline void usb_set_ep_rx_buf1_addr(uint8 ep, uint16 addr) { + usb_set_ep_rx_addr(ep, addr); +} + +static inline uint32* usb_ep_rx_buf0_count_ptr(uint8 ep) { + return usb_ep_tx_count_ptr(ep); +} + +static inline uint16 usb_get_ep_rx_buf0_count(uint8 ep) { + return usb_get_ep_tx_count(ep); +} + +void usb_set_ep_rx_buf0_count(uint8 ep, uint16 count); + +static inline uint32* usb_ep_rx_buf1_count_ptr(uint8 ep) { + return usb_ep_rx_count_ptr(ep); +} + +static inline uint16 usb_get_ep_rx_buf1_count(uint8 ep) { + return usb_get_ep_rx_count(ep); +} + +static inline void usb_set_ep_rx_buf1_count(uint8 ep, uint16 count) { + usb_set_ep_rx_count(ep, count); +} + /* * Misc. types */ diff --git a/libmaple/util.c b/libmaple/util.c index 2ee5ede..4c0b2c8 100644 --- a/libmaple/util.c +++ b/libmaple/util.c @@ -2,6 +2,7 @@ * The MIT License * * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2011, 2012 LeafLabs, LLC. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation diff --git a/support/make/build-rules.mk b/support/make/build-rules.mk index d180c89..eec986f 100644 --- a/support/make/build-rules.mk +++ b/support/make/build-rules.mk @@ -1,13 +1,15 @@ # Useful tools -CC := arm-none-eabi-gcc -CXX := arm-none-eabi-g++ -LD := arm-none-eabi-ld -v -AR := arm-none-eabi-ar -AS := arm-none-eabi-gcc -OBJCOPY := arm-none-eabi-objcopy -DISAS := arm-none-eabi-objdump -OBJDUMP := arm-none-eabi-objdump -SIZE := arm-none-eabi-size +CROSS_COMPILE ?= arm-none-eabi- + +CC := $(CROSS_COMPILE)gcc +CXX := $(CROSS_COMPILE)g++ +LD := $(CROSS_COMPILE)ld -v +AR := $(CROSS_COMPILE)ar +AS := $(CROSS_COMPILE)gcc +OBJCOPY := $(CROSS_COMPILE)objcopy +DISAS := $(CROSS_COMPILE)objdump +OBJDUMP := $(CROSS_COMPILE)objdump +SIZE := $(CROSS_COMPILE)size DFU := dfu-util # Suppress annoying output unless V is set @@ -39,6 +41,10 @@ ifneq ($(findstring ARM/embedded,$(shell $(CC) --version)),) # GCC ARM Embedded, https://launchpad.net/gcc-arm-embedded/ LD_TOOLCHAIN_PATH := $(LDDIR)/toolchains/gcc-arm-embedded endif +ifneq ($(findstring Linaro GCC,$(shell $(CC) --version)),) +# Summon/Linaro GCC ARM Embedded, https://github.com/esden/summon-arm-toolchain +LD_TOOLCHAIN_PATH := $(LDDIR)/toolchains/gcc-arm-embedded +endif # Add toolchain directory to LD search path TOOLCHAIN_LDFLAGS := -L $(LD_TOOLCHAIN_PATH) diff --git a/wirish/boards.cpp b/wirish/boards.cpp index dbc308e..a693fa6 100644 --- a/wirish/boards.cpp +++ b/wirish/boards.cpp @@ -143,13 +143,10 @@ static void setup_clocks(void) { * These addresses are where usercode starts when a bootloader is * present. If no bootloader is present, the user NVIC usually starts * at the Flash base address, 0x08000000. - * - * FIXME Let the build specify the vector table address numerically to - * avoid having these magic values -- some people have been fixing up - * the bootloader so it uses less space. */ #define USER_ADDR_ROM 0x08005000 #define USER_ADDR_RAM 0x20000C00 +extern char __text_start__; static void setup_nvic(void) { #ifdef VECT_TAB_FLASH @@ -158,8 +155,13 @@ static void setup_nvic(void) { nvic_init(USER_ADDR_RAM, 0); #elif defined VECT_TAB_BASE nvic_init((uint32)0x08000000, 0); +#elif defined VECT_TAB_ADDR + // A numerically supplied value + nvic_init((uint32)VECT_TAB_ADDR, 0); #else -#error "You must select a base address for the vector table." + // Use the __text_start__ value from the linker script; this + // should be the start of the vector table. + nvic_init((uint32)&__text_start__, 0); #endif } diff --git a/wirish/ext_interrupts.cpp b/wirish/ext_interrupts.cpp index a3e61fd..1195ea9 100644 --- a/wirish/ext_interrupts.cpp +++ b/wirish/ext_interrupts.cpp @@ -39,13 +39,6 @@ static inline exti_trigger_mode exti_out_mode(ExtIntTriggerMode mode); -/** - * @brief Attach an interrupt handler to a pin, triggering on the given mode. - * @param pin Pin to attach an interrupt handler onto. - * @param handler Function to call when the external interrupt is triggered. - * @param mode Trigger mode for the given interrupt. - * @see ExtIntTriggerMode - */ void attachInterrupt(uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode) { if (pin >= BOARD_NR_GPIO_PINS || !handler) { return; @@ -59,10 +52,21 @@ void attachInterrupt(uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode) { outMode); } -/** - * @brief Disable any external interrupt attached to a pin. - * @param pin Pin number to detach any interrupt from. - */ +void attachInterrupt(uint8 pin, voidArgumentFuncPtr handler, void *arg, + ExtIntTriggerMode mode) { + if (pin >= BOARD_NR_GPIO_PINS || !handler) { + return; + } + + exti_trigger_mode outMode = exti_out_mode(mode); + + exti_attach_callback((exti_num)(PIN_MAP[pin].gpio_bit), + gpio_exti_port(PIN_MAP[pin].gpio_device), + handler, + arg, + outMode); +} + void detachInterrupt(uint8 pin) { if (pin >= BOARD_NR_GPIO_PINS) { return; diff --git a/wirish/include/wirish/ext_interrupts.h b/wirish/include/wirish/ext_interrupts.h index 933be04..ce1ca03 100644 --- a/wirish/include/wirish/ext_interrupts.h +++ b/wirish/include/wirish/ext_interrupts.h @@ -69,6 +69,28 @@ typedef enum ExtIntTriggerMode { void attachInterrupt(uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode); /** + * @brief Registers an interrupt handler on a pin. + * + * The interrupt will be triggered on a given transition on the pin, + * as specified by the mode parameter. The handler runs in interrupt + * context. The new handler will replace whatever handler is + * currently registered for the pin, if any. + * + * @param pin Pin number + * @param handler Static class member function to run upon external interrupt + * trigger. The handler should take 1 argument and return void + * @param arg Argument that the handler will be passed when it's called. One + * use of this is to pass the specific instance of the class that + * will handle the interrupt. + * @param mode Type of transition to trigger on, e.g. falling, rising, etc. + * + * @sideeffect Registers a handler + * @see detachInterrupt() + */ +void attachInterrupt(uint8 pin, voidArgumentFuncPtr handler, void *arg, + ExtIntTriggerMode mode); + +/** * @brief Disable any registered external interrupt. * @param pin Maple pin number * @sideeffect unregisters external interrupt handler diff --git a/wirish/syscalls.c b/wirish/syscalls.c index 1e62d51..d5f2d9f 100644 --- a/wirish/syscalls.c +++ b/wirish/syscalls.c @@ -37,17 +37,18 @@ #include <sys/stat.h> #include <errno.h> +#include <stddef.h> /* If CONFIG_HEAP_START (or CONFIG_HEAP_END) isn't defined, then * assume _lm_heap_start (resp. _lm_heap_end) is appropriately set by * the linker */ #ifndef CONFIG_HEAP_START extern char _lm_heap_start; -#define CONFIG_HEAP_START ((caddr_t)&_lm_heap_start) +#define CONFIG_HEAP_START ((void *)&_lm_heap_start) #endif #ifndef CONFIG_HEAP_END extern char _lm_heap_end; -#define CONFIG_HEAP_END ((caddr_t)&_lm_heap_end) +#define CONFIG_HEAP_END ((void *)&_lm_heap_end) #endif /* @@ -56,9 +57,9 @@ extern char _lm_heap_end; * Get incr bytes more RAM (for use by the heap). malloc() and * friends call this function behind the scenes. */ -caddr_t _sbrk(int incr) { - static caddr_t pbreak = NULL; /* current program break */ - caddr_t ret; +void *_sbrk(int incr) { + static void * pbreak = NULL; /* current program break */ + void * ret; if (pbreak == NULL) { pbreak = CONFIG_HEAP_START; @@ -67,7 +68,7 @@ caddr_t _sbrk(int incr) { if ((CONFIG_HEAP_END - pbreak < incr) || (pbreak - CONFIG_HEAP_START < -incr)) { errno = ENOMEM; - return (caddr_t)-1; + return (void *)-1; } ret = pbreak; @@ -168,3 +169,8 @@ __weak char *fgets(char *s, int bufsize, void *f) { cgets(s, bufsize); return s; } + +__weak void _exit(int exitcode) { + while (1) + ; +} diff --git a/wirish/usb_serial.cpp b/wirish/usb_serial.cpp index 380f197..d21766f 100644 --- a/wirish/usb_serial.cpp +++ b/wirish/usb_serial.cpp @@ -92,13 +92,24 @@ void USBSerial::write(const void *buf, uint32 len) { uint32 old_txed = 0; uint32 start = millis(); + uint32 sent = 0; + while (txed < len && (millis() - start < USB_TIMEOUT)) { - txed += usb_cdcacm_tx((const uint8*)buf + txed, len - txed); + sent = usb_cdcacm_tx((const uint8*)buf + txed, len - txed); + txed += sent; if (old_txed != txed) { start = millis(); } old_txed = txed; } + + + if (sent == USB_CDCACM_TX_EPSIZE) { + while (usb_cdcacm_is_transmitting() != 0) { + } + /* flush out to avoid having the pc wait for more data */ + usb_cdcacm_tx(NULL, 0); + } } uint32 USBSerial::available(void) { |