aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/blinky.cpp9
-rw-r--r--examples/exti-interrupt-callback.cpp87
-rw-r--r--examples/exti-interrupt.cpp50
-rw-r--r--libmaple/adc.c1
-rw-r--r--libmaple/exti.c106
-rw-r--r--libmaple/flash.c1
-rw-r--r--libmaple/gpio.c1
-rw-r--r--libmaple/include/libmaple/exti.h5
-rw-r--r--libmaple/include/libmaple/libmaple_types.h1
-rw-r--r--libmaple/include/libmaple/usb.h1
-rw-r--r--libmaple/include/libmaple/usb_cdcacm.h22
-rw-r--r--libmaple/nvic.c1
-rw-r--r--libmaple/stm32f1/bkp.c4
-rw-r--r--libmaple/stm32f1/dma.c1
-rw-r--r--libmaple/stm32f1/include/series/dma.h10
-rw-r--r--libmaple/stm32f1/performance/isrs.S2
-rw-r--r--libmaple/stm32f1/performance/vector_table.S2
-rw-r--r--libmaple/stm32f1/rules.mk3
-rw-r--r--libmaple/systick.c1
-rw-r--r--libmaple/timer.c2
-rw-r--r--libmaple/usart.c1
-rw-r--r--libmaple/usb/stm32f1/usb.c196
-rw-r--r--libmaple/usb/stm32f1/usb_cdcacm.c64
-rw-r--r--libmaple/usb/stm32f1/usb_reg_map.c13
-rw-r--r--libmaple/usb/stm32f1/usb_reg_map.h230
-rw-r--r--libmaple/util.c1
-rw-r--r--support/make/build-rules.mk24
-rw-r--r--wirish/boards.cpp12
-rw-r--r--wirish/ext_interrupts.cpp26
-rw-r--r--wirish/include/wirish/ext_interrupts.h22
-rw-r--r--wirish/syscalls.c18
-rw-r--r--wirish/usb_serial.cpp13
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) {