aboutsummaryrefslogtreecommitdiffstats
path: root/wirish
diff options
context:
space:
mode:
authorMarti Bolivar <mbolivar@mit.edu>2010-10-22 21:13:02 -0400
committerMarti Bolivar <mbolivar@mit.edu>2010-10-22 21:13:02 -0400
commit6c956a383834b66c29591294f0926ced22f3e3b7 (patch)
tree00214f59655cf96d747228d9ffb8f6059b63b31c /wirish
parentdd7e6ecdafcb8938e23dfd18a36d70628fbc74bd (diff)
downloadlibrambutan-6c956a383834b66c29591294f0926ced22f3e3b7.tar.gz
librambutan-6c956a383834b66c29591294f0926ced22f3e3b7.zip
maple mini runs blinky now.
still need usb descriptors to improve, and also nothing else is tested.
Diffstat (limited to 'wirish')
-rw-r--r--wirish/HardwareTimer.cpp18
-rw-r--r--wirish/HardwareTimer.h285
-rw-r--r--wirish/boards.h79
-rw-r--r--wirish/ext_interrupts.c20
-rw-r--r--wirish/ext_interrupts.h41
-rw-r--r--wirish/io.h149
-rw-r--r--wirish/pwm.h11
-rw-r--r--wirish/wirish_digital.c7
8 files changed, 522 insertions, 88 deletions
diff --git a/wirish/HardwareTimer.cpp b/wirish/HardwareTimer.cpp
index 6fbad8b..5b80ec1 100644
--- a/wirish/HardwareTimer.cpp
+++ b/wirish/HardwareTimer.cpp
@@ -22,10 +22,8 @@
* THE SOFTWARE.
*****************************************************************************/
-/**
- * @brief wirish timer class to manage the four 16-bit timer peripherals
- *
- * This implementation is not very efficient (lots of duplicated functions)
+/*
+ * wirish timer class to manage the four 16-bit timer peripherals
*/
#include "wirish.h"
@@ -69,10 +67,6 @@ uint16 HardwareTimer::getCount(void) {
return timer_get_count(this->timerNum);
}
-/* This function will set the prescaler and overflow to get a period
- * of the given length with the most resolution; the return value is
- * the overflow value and thus the largest value that can be set as a
- * compare. */
uint16 HardwareTimer::setPeriod(uint32 microseconds) {
// XXX: 72MHz shouldn't be hard coded in here... global define?
@@ -92,19 +86,19 @@ uint16 HardwareTimer::setPeriod(uint32 microseconds) {
return this->overflow;
}
-void HardwareTimer::setChannel1Mode(uint8 mode) {
+void HardwareTimer::setChannel1Mode(TimerMode mode) {
timer_set_mode(this->timerNum,1,mode);
}
-void HardwareTimer::setChannel2Mode(uint8 mode) {
+void HardwareTimer::setChannel2Mode(TimerMode mode) {
timer_set_mode(this->timerNum,2,mode);
}
-void HardwareTimer::setChannel3Mode(uint8 mode) {
+void HardwareTimer::setChannel3Mode(TimerMode mode) {
timer_set_mode(this->timerNum,3,mode);
}
-void HardwareTimer::setChannel4Mode(uint8 mode) {
+void HardwareTimer::setChannel4Mode(TimerMode mode) {
timer_set_mode(this->timerNum,4,mode);
}
diff --git a/wirish/HardwareTimer.h b/wirish/HardwareTimer.h
index c6e11c8..b05085f 100644
--- a/wirish/HardwareTimer.h
+++ b/wirish/HardwareTimer.h
@@ -29,6 +29,26 @@
#ifndef _TIMER_H_
#define _TIMER_H_
+/**
+ * Interface to one of the 16-bit timer peripherals.
+ *
+ * User code should not instantiate this class directly; instead, use
+ * one of the predefined Timer<n> instances (Timer1, Timer2, etc.).
+ *
+ * HardwareTimer instances can be configured to generate periodic or
+ * delayed events with minimal work done by the microcontroller. Each
+ * timer maintains a single 16-bit count that can be configured with a
+ * prescaler and overflow value.
+ *
+ * By default, a timer's counter is incremented once per clock cycle.
+ * The prescaler acts as a divider of the 72MHz Maple system clock;
+ * without prescaling, the timer's count would reach 65535 (2**16-1)
+ * and roll over over 1000 times per second.
+ *
+ * The overflow value is the maximum value the counter will reach. It
+ * defaults to 65535; smaller values will cause the counter to reset
+ * more frequently.
+ */
class HardwareTimer {
private:
uint16 overflow;
@@ -37,39 +57,282 @@ class HardwareTimer {
public:
HardwareTimer(uint8 timer_num);
+ /**
+ * Stop the counter, without affecting its configuration.
+ *
+ * The timer will no longer count or fire interrupts after this
+ * function is called, until it is resumed. This function is
+ * useful during timer setup periods, in order to prevent
+ * interrupts from firing before the timer is fully configured.
+ *
+ * Note that there is some function call overhead associated with
+ * this method, so using it in concert with
+ * HardwareTimer::resume() is not a robust way to align multiple
+ * timers to the same count value.
+ *
+ * @see HardwareTimer::resume()
+ */
void pause(void);
+
+ /**
+ * Resume a paused timer, without affecting its configuration.
+ *
+ * The timer will resume counting and firing interrupts as
+ * appropriate.
+ *
+ * Note that there is some function call overhead associated with
+ * using this method, so using it in concert with
+ * HardwareTimer::resume() is not a robust way to align multiple
+ * timers to the same count value.
+ *
+ * @see HardwareTimer::pause()
+ */
void resume(void);
+
+ /**
+ * Set the timer prescale.
+ *
+ * The prescaler acts as a clock divider to slow down the rate at
+ * which the counter increments.
+ *
+ * For example, the system clock rate is 72MHz, so the counter
+ * will reach 65535 in (13.89 nanoseconds) * (65535 counts) =
+ * (910.22 microseconds), or about a thousand times a second. If
+ * the prescaler equals 1098, then the clock rate is effectively
+ * 65.56KHz, and the counter will reach 65536 in (15.25
+ * microseconds) * (65536 counts) = (0.999 seconds), or about once
+ * per second.
+ *
+ * The HardwareTimer::setPeriod() method may also be used as a
+ * convenient alternative.
+ *
+ * @param factor The new prescale value to set.
+ * @see HardwareTimer::setPeriod()
+ */
void setPrescaleFactor(uint16 factor);
- void setOverflow(uint16 val); // truncates to overflow
- void setCount(uint16 val); // truncates to overflow
+
+ /**
+ * Sets the timer overflow (or "reload") value.
+ *
+ * When the timer's counter reaches this, value it resets to
+ * zero. Its default value is 65535 (the largest unsigned 16-bit
+ * integer); setting the overflow to anything lower will cause
+ * interrupts to be called more frequently (see the setPeriod()
+ * function below for a shortcut). This number sets the maximum
+ * value for the channel compare values.
+ *
+ * @param val The new overflow value to set
+ * @see HardwareTimer::setOverflow()
+ */
+ void setOverflow(uint16 val);
+
+ /**
+ * Set the current timer count.
+ *
+ * Note that there is some function call overhead associated with
+ * callign this method, so using it is not a robust way to get
+ * multiple timers to share a count value.
+ *
+ * @param val The new count value to set. If this value exceeds
+ * the timer's overflow value, it is truncated to the
+ * overflow value.
+ */
+ void setCount(uint16 val);
+
+ /**
+ * Retrieve the current timer count.
+ *
+ * @return The timer's current count value
+ */
uint16 getCount(void);
- // tries to set prescaler and overflow wisely; returns overflow
+ /**
+ * Configure the prescaler and overflow values to generate a timer
+ * reload with a period as close to the given number of
+ * microseconds as possible.
+ *
+ * The return value is the overflow, which may be used to set
+ * channel compare values. However, if a clock that fires an
+ * interrupt every given number of microseconds is all that is
+ * desired, and the relative "phases" are unimportant, channel
+ * compare values may all be set to 1.
+ *
+ * @param microseconds the desired period of the timer.
+ * @return the overflow value (and thus, the largest value that can be
+ * set as a compare).
+ */
uint16 setPeriod(uint32 microseconds);
- void setChannel1Mode(uint8 mode);
- void setChannel2Mode(uint8 mode);
- void setChannel3Mode(uint8 mode);
- void setChannel4Mode(uint8 mode);
- void setCompare1(uint16 val); // truncates to overflow
- void setCompare2(uint16 val); // truncates to overflow
- void setCompare3(uint16 val); // truncates to overflow
- void setCompare4(uint16 val); // truncates to overflow
+
+ /**
+ * Set channel 1 of this timer to the given mode.
+ *
+ * Note: Timer1.setChannel1Mode(TIMER_PWM) may not work as
+ * expected; if you want PWM functionality on a channel make sure
+ * you don't set it to something else!
+ *
+ * @see TimerMode
+ */
+ void setChannel1Mode(TimerMode mode);
+
+ /**
+ * Set channel 2 of this timer to the given mode.
+ * @see TimerMode
+ */
+ void setChannel2Mode(TimerMode mode);
+
+ /**
+ * Set channel 3 of this timer to the given mode.
+ * @see TimerMode
+ */
+ void setChannel3Mode(TimerMode mode);
+
+ /**
+ * Set channel 4 of this timer to the given mode.
+ * @see TimerMode
+ */
+ void setChannel4Mode(TimerMode mode);
+
+ /**
+ * Sets the compare value for channel 1.
+ *
+ * When the counter reaches this value the interrupt for this
+ * channel will fire if channel 1 mode is TIMER_OUTPUTCOMPARE and
+ * an interrupt is attached.
+ *
+ * By default, this only changes the relative offsets between
+ * events on a single timer ("phase"); they don't control the
+ * frequency with which they occur. However, a common trick is to
+ * increment the compare value manually in the interrupt handler
+ * so that the event will fire again after the increment
+ * period. There can be a different increment value for each
+ * channel, so this trick allows events to be programmed at 4
+ * different rates on a single timer. Note that function call
+ * overheads mean that the smallest increment rate is at least a
+ * few microseconds.
+ *
+ * @param val The compare value to set. If greater than this
+ * timer's overflow value, it will be truncated to the
+ * overflow value.
+ *
+ * @see TimerMode
+ * @see HardwareTimer::setChannel1Mode()
+ */
+ void setCompare1(uint16 val);
+
+ /**
+ * Sets the compare value for channel 2.
+ *
+ * @param val The compare value to set. If greater than this
+ * timer's overflow value, it will be truncated to the
+ * overflow value.
+ * @see HardwareTimer::setCompare1()
+ */
+ void setCompare2(uint16 val);
+
+ /**
+ * Sets the compare value for channel 3.
+ *
+ * @param val The compare value to set. If greater than this
+ * timer's overflow value, it will be truncated to the
+ * overflow value.
+ * @see HardwareTimer::setCompare1()
+ */
+ void setCompare3(uint16 val);
+
+ /**
+ * Sets the compare value for channel 4.
+ *
+ * @param val The compare value to set. If greater than this
+ * timer's overflow value, it will be truncated to the
+ * overflow value.
+ * @see HardwareTimer::setCompare1()
+ */
+ void setCompare4(uint16 val);
+
+ /**
+ * Attach an interrupt handler to this timer's channel 1. This
+ * interrupt handler will be called when the timer's counter
+ * reaches its channel 1 compare value.
+ *
+ * The argument should be a function which takes no arguments and
+ * has no return value; i.e. it should have signature
+ *
+ * void (*handler)(void);
+ *
+ * Note: The function (often called an interrupt service routine,
+ * or ISR) should attempt to return as quickly as possible.
+ * Blinking the LED, some logic, PWM updates, and Serial writes
+ * are fine; writing to SerialUSB or waiting for user input can
+ * take a long time and other compare interrupts won't fire. Tip:
+ * if you have a delay() in your interrupt routine, you're probably
+ * doing it wrong.
+ *
+ * @param handler The ISR to attach to channel 1.
+ * @see voidFuncPtr
+ */
void attachCompare1Interrupt(voidFuncPtr handler);
+
+ /**
+ * Like attachCompare1Interrupt(), but for channel 2.
+ * @see HardwareTimer::attachCompare1Interrupt()
+ */
void attachCompare2Interrupt(voidFuncPtr handler);
+
+ /**
+ * Like attachCompare1Interrupt(), but for channel 3.
+ * @see HardwareTimer::attachCompare1Interrupt()
+ */
void attachCompare3Interrupt(voidFuncPtr handler);
+
+ /**
+ * Like attachCompare1Interrupt(), but for channel 4.
+ * @see HardwareTimer::attachCompare1Interrupt()
+ */
void attachCompare4Interrupt(voidFuncPtr handler);
+
+ /**
+ * Remove the interrupt handler attached to channel 1, if any.
+ * The handler will no longer be called by this timer.
+ * @see HardwareTimer::attachCompare1Interrupt()
+ */
void detachCompare1Interrupt(void);
+
+ /**
+ * Remove the interrupt handler attached to channel 2, if any.
+ * The handler will no longer be called by this timer.
+ * @see HardwareTimer::attachCompare1Interrupt()
+ */
void detachCompare2Interrupt(void);
+
+ /**
+ * Remove the interrupt handler attached to channel 3, if any.
+ * The handler will no longer be called by this timer.
+ * @see HardwareTimer::attachCompare1Interrupt()
+ */
void detachCompare3Interrupt(void);
+
+ /**
+ * Remove the interrupt handler attached to channel 4, if any.
+ * The handler will no longer be called by this timer.
+ * @see HardwareTimer::attachCompare1Interrupt()
+ */
void detachCompare4Interrupt(void);
};
+/** Pre-instantiated timer for use by user code. */
extern HardwareTimer Timer1;
+/** Pre-instantiated timer for use by user code. */
extern HardwareTimer Timer2;
+/** Pre-instantiated timer for use by user code. */
extern HardwareTimer Timer3;
+/** Pre-instantiated timer for use by user code. */
extern HardwareTimer Timer4;
#if NR_TIMERS >= 8
+/** Pre-instantiated timer for use by user code, on devices with
+ more than four timers (this does not include the Maple). */
extern HardwareTimer Timer5;
+/** Pre-instantiated timer for use by user code, on devices with
+ more than four timers (this does not include the Maple). */
extern HardwareTimer Timer8;
#endif
diff --git a/wirish/boards.h b/wirish/boards.h
index fed5ead..0625d0a 100644
--- a/wirish/boards.h
+++ b/wirish/boards.h
@@ -292,6 +292,85 @@ typedef struct PinMapping {
};
#endif
+#ifdef BOARD_maple_mini
+
+ #define CYCLES_PER_MICROSECOND 72
+ #define MAPLE_RELOAD_VAL 71999 /* takes a cycle to reload */
+
+ static __attribute__ ((unused)) PinMapping PIN_MAP[NR_GPIO_PINS] = {
+ /* D0/PC15 */
+ {GPIOC_BASE, 15, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID},
+ /* D1/PA0 */
+ {GPIOA_BASE, 0, ADC0, TIMER2_CH1_CCR, EXTI_CONFIG_PORTA, TIMER2, 1},
+ /* D2/PA1 */
+ {GPIOA_BASE, 1, ADC1, TIMER2_CH2_CCR, EXTI_CONFIG_PORTA, TIMER2, 2},
+ /* D3/PA2 */
+ {GPIOA_BASE, 2, ADC2, TIMER2_CH3_CCR, EXTI_CONFIG_PORTA, TIMER2, 3},
+ /* D4/PA3 */
+ {GPIOA_BASE, 3, ADC3, TIMER2_CH4_CCR, EXTI_CONFIG_PORTA, TIMER2, 4},
+ /* D5/PA4 */
+ {GPIOA_BASE, 4, ADC4, TIMER_INVALID, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID},
+ /* D6/PA5 */
+ {GPIOA_BASE, 5, ADC5, TIMER_INVALID, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID},
+ /* D7/PA6 */
+ {GPIOA_BASE, 6, ADC6, TIMER3_CH1_CCR, EXTI_CONFIG_PORTA, TIMER3, 1},
+ /* D8/PA7 */
+ {GPIOA_BASE, 7, ADC7, TIMER3_CH2_CCR, EXTI_CONFIG_PORTA, TIMER3, 2},
+ /* D9/PB0 */
+ {GPIOB_BASE, 0, ADC8, TIMER3_CH3_CCR, EXTI_CONFIG_PORTB, TIMER3, 3},
+ /* D10/PB1 */
+ {GPIOB_BASE, 1, ADC9, TIMER3_CH4_CCR, EXTI_CONFIG_PORTB, TIMER3, 4},
+ /* D11/PB2 */
+ {GPIOB_BASE, 2, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
+ /* D12/PB10 */
+ {GPIOB_BASE, 10, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
+ /* D13/PB11 */
+ {GPIOB_BASE, 11, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
+ /* D14/PB13 */
+ {GPIOB_BASE, 13, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
+ /* D15/PB14 */
+ {GPIOB_BASE, 14, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
+ /* D16/PB15 */
+ {GPIOB_BASE, 15, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
+ /* D17/PA8 */
+ {GPIOA_BASE, 8, ADC_INVALID, TIMER1_CH1_CCR, EXTI_CONFIG_PORTB, TIMER1, 1},
+ /* D18/PA9 */
+ {GPIOA_BASE, 9, ADC_INVALID, TIMER1_CH2_CCR, EXTI_CONFIG_PORTA, TIMER2, 2},
+ /* D19/PA10 */
+ {GPIOA_BASE, 10, ADC_INVALID, TIMER1_CH3_CCR, EXTI_CONFIG_PORTA, TIMER1, 3},
+ /* D20/PA11 */
+ {GPIOA_BASE, 11, ADC_INVALID, TIMER1_CH4_CCR, EXTI_CONFIG_PORTA, TIMER1, 4},
+ /* D21/PA12 */
+ {GPIOA_BASE, 12, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID},
+ /* D22/PA13 */
+ {GPIOA_BASE, 13, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID},
+ /* D23/PA14 */
+ {GPIOA_BASE, 14, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID},
+ /* D24/PA15 */
+ {GPIOA_BASE, 15, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID},
+ /* D25/PB3 */
+ {GPIOB_BASE, 3, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
+ /* D26/PB4 */
+ {GPIOB_BASE, 4, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
+ /* D27/PB5 */
+ {GPIOB_BASE, 5, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
+ /* D28/PB6 */
+ {GPIOB_BASE, 6, ADC_INVALID, TIMER4_CH1_CCR, EXTI_CONFIG_PORTB, TIMER4, 1},
+ /* D29/PB7 */
+ {GPIOB_BASE, 7, ADC_INVALID, TIMER4_CH2_CCR, EXTI_CONFIG_PORTB, TIMER4, 1},
+ /* D30/PC13 */
+ {GPIOC_BASE, 13, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID},
+ /* D31/PC14 */
+ {GPIOC_BASE, 14, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID},
+ /* D32/PB8 */
+ {GPIOB_BASE, 8, ADC_INVALID, TIMER4_CH3_CCR, EXTI_CONFIG_PORTB, TIMER4, 3},
+ /* D33/PB12 */
+ {GPIOB_BASE, 12, ADC_INVALID, TIMER_INVALID, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID},
+ };
+
+
+#endif
+
#ifndef CYCLES_PER_MICROSECOND
#error "Board type has not been selected correctly."
#endif
diff --git a/wirish/ext_interrupts.c b/wirish/ext_interrupts.c
index f02cdc5..dd7c1a8 100644
--- a/wirish/ext_interrupts.c
+++ b/wirish/ext_interrupts.c
@@ -32,17 +32,8 @@
#include "exti.h"
#include "ext_interrupts.h"
-/**
- * @brief Attach an interrupt handler to be triggered on a given
- * transition on the pin. Runs in interrupt context
- *
- * @param pin Maple pin number
- * @param handler Function to run upon external interrupt trigger.
- * @param mode Type of transition to trigger on, eg falling, rising, etc.
- *
- * @sideeffect Registers a handler
- */
-void attachInterrupt(uint8 pin, voidFuncPtr handler, uint32 mode) {
+/* Attach ISR handler on pin, triggering on the given mode. */
+void attachInterrupt(uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode) {
uint8 outMode;
/* Parameter checking */
@@ -65,6 +56,7 @@ void attachInterrupt(uint8 pin, voidFuncPtr handler, uint32 mode) {
outMode = EXTI_RISING_FALLING;
break;
default:
+ ASSERT(0);
return;
}
@@ -76,11 +68,7 @@ void attachInterrupt(uint8 pin, voidFuncPtr handler, uint32 mode) {
return;
}
-/**
- * @brief Disable an external interrupt
- * @param pin maple pin number
- * @sideeffect unregisters external interrupt handler
- */
+/* Disable any interrupts */
void detachInterrupt(uint8 pin) {
if (!(pin < NR_GPIO_PINS)) {
return;
diff --git a/wirish/ext_interrupts.h b/wirish/ext_interrupts.h
index fef8c8f..80e2e9e 100644
--- a/wirish/ext_interrupts.h
+++ b/wirish/ext_interrupts.h
@@ -22,6 +22,8 @@
* THE SOFTWARE.
*****************************************************************************/
+#include "libmaple_types.h"
+
/**
* @file ext_interrupts.h
*
@@ -31,17 +33,44 @@
#ifndef _EXT_INTERRUPTS_H_
#define _EXT_INTERRUPTS_H_
-enum {
- RISING,
- FALLING,
- CHANGE
-};
+/**
+ * The kind transition on an external pin which should trigger an
+ * interrupt.
+ */
+typedef enum ExtIntTriggerMode_ {
+ RISING, /**< To trigger an interrupt when the pin transitions LOW
+ to HIGH */
+ FALLING, /**< To trigger an interrupt when the pin transitions
+ HIGH to LOW */
+ CHANGE /**< To trigger an interrupt when the pin transitions from
+ LOW to HIGH or HIGH to LOW (i.e., when the pin
+ changes). */
+} ExtIntTriggerMode;
#ifdef __cplusplus
extern "C"{
#endif
-void attachInterrupt(uint8 pin, voidFuncPtr, uint32 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.
+ *
+ * @param pin Maple pin number
+ * @param handler Function to run upon external interrupt trigger.
+ * @param mode Type of transition to trigger on, e.g. falling, rising, etc.
+ *
+ * @sideeffect Registers a handler
+ */
+void attachInterrupt(uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode);
+
+/**
+ * @brief Disable any registered external interrupt.
+ * @param pin Maple pin number
+ * @sideeffect unregisters external interrupt handler
+ */
void detachInterrupt(uint8 pin);
#ifdef __cplusplus
diff --git a/wirish/io.h b/wirish/io.h
index 647e79c..f82e414 100644
--- a/wirish/io.h
+++ b/wirish/io.h
@@ -38,54 +38,125 @@
extern "C"{
#endif
+/**
+ * Specifies a GPIO pin behavior.
+ *
+ * Each of the GPIO pins on a Maple board may be configured using
+ * pinMode() to behave in a number of ways: as a digital output pin,
+ * or as an analog input pin, etc., depending on the particular pin.
+ *
+ * This enum specifies the complete set of possible configurations;
+ * not every pin can have all of these modes. For example, on the
+ * Maple, pin 15 may be configured as INPUT_ANALOG, but not as PWM.
+ * See your device's silkscreen and and the GPIO documentation for
+ * more information.
+ *
+ * @see pinMode()
+ */
typedef enum WiringPinMode {
- OUTPUT,
- OUTPUT_OPEN_DRAIN,
- INPUT,
- INPUT_ANALOG,
- INPUT_PULLUP,
- INPUT_PULLDOWN,
- INPUT_FLOATING,
- PWM,
- PWM_OPEN_DRAIN,
+ OUTPUT, /**< Basic digital output: when the pin is HIGH, the
+ voltage is held at +3.3v (Vcc) and when it is LOW, it
+ is pulled down to ground. */
+
+ OUTPUT_OPEN_DRAIN, /**< In open drain mode, the pin indicates
+ "low" by accepting current flow to ground
+ and "high" by providing increased
+ impedance. An example use would be to
+ connect a pin to a bus line (which is pulled
+ up to a positive voltage by a separate
+ supply through a large resistor). When the
+ pin is high, not much current flows through
+ to ground and the line stays at positive
+ voltage; when the pin is low the bus
+ "drains" to ground with a small amount of
+ current constantly flowing through the large
+ resistor from the external supply. In this
+ mode no current is ever actually /sourced/
+ from the pin. */
+
+ INPUT, /**< Basic digital input. The pin voltage is sampled; when
+ it is closer to 3.3v (Vcc) the pin status is high, and
+ when it is closer to 0v (ground) it is low. If no
+ external circuit is pulling the pin voltage to high or
+ low, it will tend to randomly oscillate and be very
+ sensitive to noise (eg a breath of air across the pin
+ will cause the state to flip). */
+
+ INPUT_ANALOG, /**< This is a special mode for when the pin will be
+ used for analog (not digital) reads. Enables ADC
+ conversion to be performed on the voltage at the
+ pin. */
+
+ INPUT_PULLUP, /**< The state of the pin in this mode is reported
+ the same way as with INPUT, but the pin voltage
+ is gently "pulled up" towards +3.3v. This means
+ the state will be high unless an external device
+ is specifically pulling the pin down to ground,
+ in which case the "gentle" pull up will not
+ affect the state of the input. */
+
+ INPUT_PULLDOWN, /**< The state of the pin in this mode is reported
+ the same way as with INPUT, but the pin voltage
+ is gently "pulled down" towards 0v. This means
+ the state will be low unless an external device
+ is specifically pulling the pin up to 3.3v, in
+ which case the "gentle" pull down will not
+ effect the state of the input. */
+
+ INPUT_FLOATING, /**< Synonym for INPUT. */
+
+ PWM, /**< This is a special mode for when the pin will be used for
+ PWM output (a special case of digital output). */
+
+ PWM_OPEN_DRAIN, /**< Like PWM, except that instead of alternating
+ cycles of LOW and HIGH, the voltage on the pin
+ consists of alternating cycles of LOW and
+ floating (disconnected). */
} WiringPinMode;
+/**
+ * Configure behavior of a GPIO pin.
+ *
+ * @param pin Pin to configure. One of: 0-38 (pin numbers as labeled
+ * on silkscreen), or D0-D38 (symbols for same)
+ * @param mode Mode corresponding to desired pin behavior.
+ * @see WiringPinMode
+ */
+void pinMode(uint8 pin, WiringPinMode mode);
-/* Set pin to mode
- * pinMode(pin, mode):
- * pin -> {0-38, D0-D39, A0-16}
- * mode -> {
- * INPUT/INPUT_DIGITAL
- * INPUT_PULLUP
- * INPUT_PULLDOWN
- * INPUT_ANALOG
- * OUTPUT/OUTPUT_PP
- * OUTPUT_OPEN_DRAIN
- * }
+/**
+ * Writes a (digital) value to a pin. The pin must have its
+ * mode set to <code>OUTPUT</code> or <code>OUTPUT_OPEN_DRAIN</code>.
+ *
+ * @param pin Pin to write to. One of: 0-38 (pin numbers as labeled
+ * on silkscreen), or D0-D38 (symbols for same)
+ * @param value Either LOW (write a 0) or HIGH (write a 1).
+ * @see pinMode()
*/
-void pinMode(uint8, uint8);
-
-/*
- * Writes VALUE to digital pin[0-38]
- * digitalWrite(pin, value):
- * pin -> {0-38, D0-D39, A0-16}
- * value -> LOW, HIGH;
-*/
-void digitalWrite(uint8, uint8);
-
-/* Read a digital value from pin, the pin mode must be set to
- * {INPUT, INPUT_PULLUP, INPUT_PULLDOWN}
- * digitalRead(pin)
- * pin -> {0-38, D0-D39, A0-16}
+void digitalWrite(uint8 pin, uint8 value);
+
+/**
+ * Read a digital value from a pin. The pin must have its mode set to
+ * one of INPUT, INPUT_PULLUP, and INPUT_PULLDOWN.
+ *
+ * @param pin Pin to read from. One of: 0-38 (pin numbers as labeled
+ * on silkscreen), or D0-D38 (symbols for same)
+ * @return LOW or HIGH.
+ * @see pinMode()
*/
uint32 digitalRead(uint8);
-/* Read an analog value from pin, the pin mode must be set
- * to INPUT_ANALOG
- * analogRead(pin)
- * pin -> {A0-A16}
+/**
+ * Read an analog value from pin. This function blocks during ADC
+ * conversion. The pin must have its mode set to INPUT_ANALOG.
+ *
+ * @param pin Pin to read from. One of: 0-38 (pin numbers as labeled
+ * on silkscreen), or D0-D38 (symbols for same)
+ * @return ADC-converted voltage, in the range 0--4095, inclusive.
+ * @see pinMode()
+ * @see analogReference()
*/
-uint32 analogRead(uint8);
+uint32 analogRead(uint8 pin);
#ifdef __cplusplus
} // extern "C"
diff --git a/wirish/pwm.h b/wirish/pwm.h
index fe170cd..6d0ddaf 100644
--- a/wirish/pwm.h
+++ b/wirish/pwm.h
@@ -36,7 +36,16 @@ extern "C"{
#endif
#define analogWrite pwmWrite
-void pwmWrite(uint8, uint16);
+
+/**
+ * Set the PWM duty.
+ *
+ * User code is expected to determine and honor the maximum value
+ * (based on the configured period). As a convenience, analogWrite is
+ * an alias of pwmWrite to ease porting Arduino code, though period
+ * and duty will have to be recalibrated
+ */
+void pwmWrite(uint8 pin, uint16 duty_cycle);
#ifdef __cplusplus
}
diff --git a/wirish/wirish_digital.c b/wirish/wirish_digital.c
index 9298b60..aa22196 100644
--- a/wirish/wirish_digital.c
+++ b/wirish/wirish_digital.c
@@ -22,8 +22,8 @@
* THE SOFTWARE.
*****************************************************************************/
-/**
- * @brief Arduino-compatible digital I/O implementation.
+/*
+ * Arduino-compatible digital I/O implementation.
*/
#include "wirish.h"
@@ -73,7 +73,8 @@ void pinMode(uint8 pin, WiringPinMode mode) {
gpio_set_mode(PIN_MAP[pin].port, PIN_MAP[pin].pin, outputMode);
if (PIN_MAP[pin].timer_num != TIMER_INVALID) {
- /* enable/disable timer channels if we're switching into or out of pwm */
+ /* enable/disable timer channels if we're switching into or
+ out of pwm */
if (pwm) {
timer_set_mode(PIN_MAP[pin].timer_num,
PIN_MAP[pin].timer_chan,