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) { | 
