aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--examples/test-session.cpp19
-rw-r--r--examples/test-timers.cpp372
-rw-r--r--libmaple/bitband.h5
-rw-r--r--libmaple/delay.h2
-rw-r--r--libmaple/nvic.h101
-rw-r--r--libmaple/rules.mk2
-rw-r--r--libmaple/spi.h3
-rw-r--r--libmaple/timer.c449
-rw-r--r--libmaple/timer.h1010
-rw-r--r--libmaple/timers.c526
-rw-r--r--libmaple/timers.h435
-rw-r--r--libmaple/util.c2
-rw-r--r--libraries/Servo/Servo.h1
-rw-r--r--notes/portable.txt94
-rw-r--r--notes/usb.txt4
-rw-r--r--notes/vga.txt9
-rw-r--r--wirish/boards.cpp646
-rw-r--r--wirish/boards.h9
-rw-r--r--wirish/comm/HardwareSPI.cpp4
-rw-r--r--wirish/comm/HardwareSerial.cpp20
-rw-r--r--wirish/comm/HardwareSerial.h12
-rw-r--r--wirish/pwm.cpp22
-rw-r--r--wirish/rules.mk1
-rw-r--r--wirish/wirish.cpp122
-rw-r--r--wirish/wirish.h3
-rw-r--r--wirish/wirish_digital.cpp6
27 files changed, 2095 insertions, 1786 deletions
diff --git a/Makefile b/Makefile
index d31c9ed..109a126 100644
--- a/Makefile
+++ b/Makefile
@@ -97,7 +97,7 @@ endif
LIBMAPLE_MODULES := $(SRCROOT)/libmaple
LIBMAPLE_MODULES += $(SRCROOT)/wirish
# Official libraries:
-LIBMAPLE_MODULES += $(SRCROOT)/libraries/Servo
+# LIBMAPLE_MODULES += $(SRCROOT)/libraries/Servo
LIBMAPLE_MODULES += $(SRCROOT)/libraries/LiquidCrystal
LIBMAPLE_MODULES += $(SRCROOT)/libraries/Wire
diff --git a/examples/test-session.cpp b/examples/test-session.cpp
index a147e06..9b4bce4 100644
--- a/examples/test-session.cpp
+++ b/examples/test-session.cpp
@@ -15,7 +15,6 @@
//#define COMM Serial2
//#define COMM Serial3
-
#define ESC ((uint8)27)
int rate = 0;
@@ -610,17 +609,15 @@ void cmd_servo_sweep(void) {
COMM.println("(reset serial port)");
}
+static uint16 init_all_timers_prescale = 0;
+
+static void set_prescale(timer_dev *dev) {
+ timer_set_prescaler(dev, init_all_timers_prescale);
+}
+
void init_all_timers(uint16 prescale) {
- timer_init(TIMER1, prescale);
- timer_init(TIMER2, prescale);
- timer_init(TIMER3, prescale);
- timer_init(TIMER4, prescale);
-#ifdef STM32_HIGH_DENSITY
- timer_init(TIMER5, prescale);
- // timer_init(TIMER6, prescale);
- // timer_init(TIMER7, prescale);
- timer_init(TIMER8, prescale);
-#endif
+ init_all_timers_prescale = prescale;
+ timer_foreach(set_prescale);
}
// Force init to be called *first*, i.e. before static object allocation.
diff --git a/examples/test-timers.cpp b/examples/test-timers.cpp
index f3cfdcc..a4fbc8a 100644
--- a/examples/test-timers.cpp
+++ b/examples/test-timers.cpp
@@ -1,8 +1,7 @@
-// Program to test the wirish timers implementation
+// Program to test the timer.h implementation's essential functionality.
#include "wirish.h"
-
-#define LED_PIN BOARD_LED_PIN
+#include "timer.h"
void handler1(void);
void handler2(void);
@@ -27,208 +26,253 @@ uint16 val2 = 10000;
uint16 val3 = 10000;
uint16 val4 = 10000;
-HardwareTimer Timers[] = {Timer1, Timer2, Timer3, Timer4};
+// FIXME high density timer test (especially basic timers + DAC)
+timer_dev *timers[] = {TIMER1, TIMER2, TIMER3, TIMER4};
+voidFuncPtr handlers[] = {handler1, handler2, handler3, handler4};
+
+void initTimer(timer_dev *dev);
+void setTimerPeriod(timer_dev *dev, uint32 period_us);
+void testSetTimerPeriod(uint32 period);
+void testTimerChannels(timer_dev *dev);
+int timerNumber(timer_dev *dev);
-void setup()
-{
- /* Set up the LED to blink */
- pinMode(LED_PIN, OUTPUT);
+void setup() {
+ // Set up the LED to blink
+ pinMode(BOARD_LED_PIN, OUTPUT);
// Setup the button as input
pinMode(BOARD_BUTTON_PIN, INPUT);
- // Wait for user to attach...
- waitForButtonPress(0);
-
- // Send a message out SerialUSB
- SerialUSB.println("Beginning timer test...");
- for(int t=0; t<4; t++) {
- Timers[t].setChannel1Mode(TIMER_OUTPUTCOMPARE);
- Timers[t].setChannel2Mode(TIMER_OUTPUTCOMPARE);
- Timers[t].setChannel3Mode(TIMER_OUTPUTCOMPARE);
- Timers[t].setChannel4Mode(TIMER_OUTPUTCOMPARE);
- }
+ // Send a message out Serial2
+ Serial2.begin(115200);
+ Serial2.println("*** Initializing timers...");
+ Serial2.println("foo");
+ timer_foreach(initTimer);
+ Serial2.println("*** Done. Beginning timer test.");
}
void loop() {
- SerialUSB.println("-----------------------------------------------------");
- SerialUSB.println("Testing setCount/getCount");
- SerialUSB.print("Timer1.getCount() = "); SerialUSB.println(Timer1.getCount());
- SerialUSB.println("Timer1.setCount(1234)");
- Timer1.setCount(1234);
- SerialUSB.print("Timer1.getCount() = "); SerialUSB.println(Timer1.getCount());
- // This tests whether the pause/resume functions work; when BUT is held
- // down Timer4 is in the "pause" state and the timer doesn't increment, so
- // the final counts should reflect the ratio of time that BUT was held down
- SerialUSB.println("-----------------------------------------------------");
- SerialUSB.println("Testing Pause/Resume; button roughly controls Timer4");
+ Serial2.println("-----------------------------------------------------");
+
+ Serial2.println("Testing timer_get_count()/timer_set_count()");
+ Serial2.print("TIMER1 count = ");
+ Serial2.println(timer_get_count(TIMER1));
+ Serial2.println("timer_set_count(TIMER1, 1234)");
+ timer_set_count(TIMER1, 1234);
+ Serial2.print("timer_get_count(TIMER1) = ");
+ Serial2.println(timer_get_count(TIMER1));
+
+ Serial2.println("-----------------------------------------------------");
+ Serial2.println("Testing pause/resume; button roughly controls TIMER4");
+ // when BUT is held down, TIMER4 is in the "pause" state and the
+ // timer doesn't increment, so the final counts should reflect the
+ // ratio of time that BUT was held down.
count3 = 0;
count4 = 0;
- Timer3.setChannel1Mode(TIMER_OUTPUTCOMPARE);
- Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE);
- Timer3.pause();
- Timer4.pause();
- Timer3.setCount(0);
- Timer4.setCount(0);
- Timer3.setOverflow(30000);
- Timer4.setOverflow(30000);
- Timer3.setCompare1(1000);
- Timer4.setCompare1(1000);
- Timer3.attachCompare1Interrupt(handler3b);
- Timer4.attachCompare1Interrupt(handler4b);
- Timer3.resume();
- Timer4.resume();
- SerialUSB.println("~4 seconds...");
- for(int i = 0; i<4000; i++) {
- if(isButtonPressed()) {
- Timer4.pause();
+ timer_set_mode(TIMER3, TIMER_CH1, TIMER_OUTPUT_COMPARE);
+ timer_set_mode(TIMER4, TIMER_CH1, TIMER_OUTPUT_COMPARE);
+ timer_pause(TIMER3);
+ timer_pause(TIMER4);
+ timer_set_count(TIMER3, 0);
+ timer_set_count(TIMER4, 0);
+ timer_set_reload(TIMER3, 30000);
+ timer_set_reload(TIMER4, 30000);
+ timer_set_compare(TIMER3, 1, 1000);
+ timer_set_compare(TIMER4, 1, 1000);
+ timer_attach_interrupt(TIMER3, TIMER_CC1_INTERRUPT, handler3b);
+ timer_attach_interrupt(TIMER4, TIMER_CC1_INTERRUPT, handler4b);
+ timer_resume(TIMER3);
+ timer_resume(TIMER4);
+
+ Serial2.println("Testing for ~4 seconds...");
+ for(int i = 0; i < 4000; i++) {
+ if (isButtonPressed()) {
+ timer_pause(TIMER4);
} else {
- Timer4.resume();
+ timer_resume(TIMER4);
}
delay(1);
}
- Timer3.setChannel1Mode(TIMER_DISABLED);
- Timer4.setChannel1Mode(TIMER_DISABLED);
- SerialUSB.print("Count3: "); SerialUSB.println(count3);
- SerialUSB.print("Count4: "); SerialUSB.println(count4);
-
- // These test the setPeriod auto-configure functionality
- SerialUSB.println("-----------------------------------------------------");
- SerialUSB.println("Testing setPeriod");
- Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE);
- Timer4.setCompare1(1);
- Timer4.setPeriod(10);
- Timer4.pause();
- Timer4.setCount(0);
- Timer4.attachCompare1Interrupt(handler4b);
- SerialUSB.println("Period 10ms, wait 2 seconds...");
- count4 = 0;
- Timer4.resume();
- delay(2000);
- Timer4.pause();
- Timer4.setChannel1Mode(TIMER_DISABLED);
- SerialUSB.print("Count4: "); SerialUSB.println(count4);
- SerialUSB.println("(should be around 2sec/10ms = 200000)");
- Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE);
- Timer4.setCompare1(1);
- Timer4.pause();
- Timer4.setPeriod(30000);
- Timer4.setCount(0);
- Timer4.attachCompare1Interrupt(handler4b);
- SerialUSB.println("Period 30000ms, wait 2 seconds...");
- count4 = 0;
- Timer4.resume();
- delay(2000);
- Timer4.pause();
- Timer4.setChannel1Mode(TIMER_DISABLED);
- SerialUSB.print("Count4: "); SerialUSB.println(count4);
- SerialUSB.println("(should be around 2sec/30000ms ~ 67)");
-
- Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE);
- Timer4.setPeriod(300000);
- Timer4.setCompare1(1);
- Timer4.pause();
- Timer4.setCount(0);
- Timer4.attachCompare1Interrupt(handler4b);
- SerialUSB.println("Period 300000ms, wait 2 seconds...");
- count4 = 0;
- Timer4.resume();
- delay(2000);
- Timer4.pause();
- Timer4.setChannel1Mode(TIMER_DISABLED);
- SerialUSB.print("Count4: "); SerialUSB.println(count4);
- SerialUSB.println("(should be around 2sec/300000ms ~ 6.7)");
-
- Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE);
- Timer4.setPrescaleFactor(33);
- Timer4.setOverflow(65454);
- Timer4.pause();
- Timer4.setCount(0);
- Timer4.setCompare1(1);
- Timer4.attachCompare1Interrupt(handler4b);
- SerialUSB.println("Period 30000ms, wait 2 seconds...");
+
+ timer_set_mode(TIMER3, TIMER_CH1, TIMER_DISABLED);
+ timer_set_mode(TIMER4, TIMER_CH1, TIMER_DISABLED);
+
+ Serial2.print("TIMER3 count: ");
+ Serial2.println(timer_get_count(TIMER3));
+ Serial2.print("TIMER4 count: ");
+ Serial2.println(timer_get_count(TIMER4));
+
+ Serial2.println("-----------------------------------------------------");
+ Serial2.println("Testing setTimerPeriod()");
+ testSetTimerPeriod(10);
+ testSetTimerPeriod(30000);
+ testSetTimerPeriod(300000);
+ testSetTimerPeriod(30000);
+
+ Serial2.println("Sanity check (with hand-coded reload and prescaler for "
+ "72 MHz timers):");
+ timer_set_mode(TIMER4, TIMER_CH1, TIMER_OUTPUT_COMPARE);
+ timer_set_prescaler(TIMER4, 33);
+ timer_set_reload(TIMER4, 65454);
+ timer_pause(TIMER4);
+ timer_set_count(TIMER4, 0);
+ timer_set_compare(TIMER4, TIMER_CH1, 1);
+ timer_attach_interrupt(TIMER4, TIMER_CC1_INTERRUPT, handler4b);
+ Serial2.println("Period 30000ms, wait 2 seconds...");
count4 = 0;
- Timer4.resume();
+ timer_resume(TIMER4);
delay(2000);
- Timer4.pause();
- Timer4.setChannel1Mode(TIMER_DISABLED);
- SerialUSB.print("Count4: "); SerialUSB.println(count4);
- SerialUSB.println("(should be around 2sec/30000ms ~ 67)");
-
- Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE);
- Timer4.setCompare1(1);
- Timer4.setPeriod(30000);
- Timer4.pause();
- Timer4.setCount(0);
- Timer4.attachCompare1Interrupt(handler4b);
- SerialUSB.println("Period 30000ms, wait 2 seconds...");
+ timer_pause(TIMER4);
+ timer_set_mode(TIMER4, TIMER_CH1, TIMER_DISABLED);
+ Serial2.print("TIMER4 count: ");
+ Serial2.println(count4);
+ Serial2.println(" (Should be around 2sec/30000ms ~ 67)");
+
+ // Test all the individual timer channels
+ timer_foreach(testTimerChannels);
+}
+
+void initTimer(timer_dev *dev) {
+ switch (dev->type) {
+ case TIMER_ADVANCED:
+ case TIMER_GENERAL:
+ Serial2.print("Initializing timer ");
+ Serial2.println(timerNumber(dev));
+ for (int c = 1; c <= 4; c++) {
+ timer_set_mode(dev, c, TIMER_OUTPUT_COMPARE);
+ }
+ Serial2.println("Done.");
+ break;
+ case TIMER_BASIC:
+ break;
+ }
+}
+
+void testSetTimerPeriod(uint32 period) {
+ timer_set_mode(TIMER4, TIMER_CH1, TIMER_OUTPUT_COMPARE);
+ timer_set_compare(TIMER4, TIMER_CH1, 1);
+ setTimerPeriod(TIMER4, period);
+ timer_pause(TIMER4);
+ timer_set_count(TIMER4, 0);
+ timer_attach_interrupt(TIMER4, TIMER_CC1_INTERRUPT, handler4b);
+ Serial2.println("Period ");
+ Serial2.print(period);
+ Serial2.print(" ms. Waiting 2 seconds...");
count4 = 0;
- Timer4.resume();
+ timer_resume(TIMER4);
delay(2000);
- Timer4.pause();
- Timer4.setChannel1Mode(TIMER_DISABLED);
- SerialUSB.print("Count4: "); SerialUSB.println(count4);
- SerialUSB.println("(should be around 2sec/30000ms ~ 67)");
-
- // This section is to touch every channel of every timer. The output
- // ratios should reflect the ratios of the rate variables. Demonstrates
- // that over time the actual timing rates get blown away by other system
- // interrupts.
- for(t=0; t<4; t++) {
- toggleLED();
- delay(100);
- SerialUSB.println("-----------------------------------------------------");
- SerialUSB.print("Testing Timer "); SerialUSB.println(t+1);
+ timer_pause(TIMER4);
+ timer_set_mode(TIMER4, TIMER_CH1, TIMER_DISABLED);
+ Serial2.print("TIMER4 count: ");
+ Serial2.println(timer_get_count(TIMER4));
+ Serial2.print(" (Should be around 2 sec / ");
+ Serial2.print(period);
+ Serial2.print(" ms = ");
+ Serial2.print(double(2) / period * 1000);
+ Serial2.println(", modulo delays due to interrupts)");
+}
+
+int timerNumber(timer_dev *dev) {
+ switch (dev->clk_id) {
+ case RCC_TIMER1:
+ return 1;
+ case RCC_TIMER2:
+ return 2;
+ case RCC_TIMER3:
+ return 3;
+ case RCC_TIMER4:
+ return 4;
+#ifdef STM32_HIGH_DENSITY
+ case RCC_TIMER5:
+ return 5;
+ case RCC_TIMER6:
+ return 6;
+ case RCC_TIMER7:
+ return 7;
+ case RCC_TIMER8:
+ return 8;
+#endif
+ default:
+ ASSERT(0);
+ return 0;
+ }
+}
+
+/* This function touches every channel of a given timer. The output
+ * ratios should reflect the ratios of the rate variables. It
+ * demonstrates that, over time, the actual timing rates get blown
+ * away by other system interrupts. */
+void testTimerChannels(timer_dev *dev) {
+ t = timerNumber(dev);
+ toggleLED();
+ delay(100);
+ Serial2.println("-----------------------------------------------------");
+ switch (dev->type) {
+ case TIMER_BASIC:
+ Serial2.print("NOT testing channels for basic timer ");
+ Serial2.println(t);
+ break;
+ case TIMER_ADVANCED:
+ case TIMER_GENERAL:
+ Serial2.print("Testing channels for timer ");
+ Serial2.println(t);
+ timer_pause(dev);
count1 = count2 = count3 = count4 = 0;
- Timers[t].setOverflow(0xFFFF);
- Timers[t].setPrescaleFactor(1);
- Timers[t].setCompare1(65535);
- Timers[t].setCompare2(65535);
- Timers[t].setCompare3(65535);
- Timers[t].setCompare4(65535);
- Timers[t].setChannel1Mode(TIMER_OUTPUTCOMPARE);
- Timers[t].setChannel2Mode(TIMER_OUTPUTCOMPARE);
- Timers[t].setChannel3Mode(TIMER_OUTPUTCOMPARE);
- Timers[t].setChannel4Mode(TIMER_OUTPUTCOMPARE);
- Timers[t].attachCompare1Interrupt(handler1);
- Timers[t].attachCompare2Interrupt(handler2);
- Timers[t].attachCompare3Interrupt(handler3);
- Timers[t].attachCompare4Interrupt(handler4);
- Timers[t].resume();
+ timer_set_reload(dev, 0xFFFF);
+ timer_set_prescaler(dev, 1);
+ for (int c = 1; c <= 4; c++) {
+ timer_set_compare(dev, c, 65535);
+ timer_set_mode(dev, c, TIMER_OUTPUT_COMPARE);
+ timer_attach_interrupt(dev, c, handlers[c - 1]);
+ }
+ timer_resume(dev);
delay(3000);
- Timers[t].setChannel1Mode(TIMER_DISABLED);
- Timers[t].setChannel2Mode(TIMER_DISABLED);
- Timers[t].setChannel3Mode(TIMER_DISABLED);
- Timers[t].setChannel4Mode(TIMER_DISABLED);
- SerialUSB.print("Count1: "); SerialUSB.println(count1);
- SerialUSB.print("Count2: "); SerialUSB.println(count2);
- SerialUSB.print("Count3: "); SerialUSB.println(count3);
- SerialUSB.print("Count4: "); SerialUSB.println(count4);
+ for (int c = 1; c <= 4; c++) {
+ timer_set_mode(dev, c, TIMER_DISABLED);
+ }
+ Serial2.print("Channel 1 count: "); Serial2.println(count1);
+ Serial2.print("Channel 2 count: "); Serial2.println(count2);
+ Serial2.print("Channel 3 count: "); Serial2.println(count3);
+ Serial2.print("Channel 4 count: "); Serial2.println(count4);
+ break;
+ }
+}
+
+// FIXME move this into the new wirish timer implementation
+void setTimerPeriod(timer_dev *dev, uint32 period_us) {
+ if (!period_us) {
+ // FIXME handle this case
+ ASSERT(0);
+ return;
}
+ uint32 cycles = period_us * CYCLES_PER_MICROSECOND;
+ uint16 pre = (uint16)((cycles >> 16) + 1);
+ timer_set_prescaler(dev, pre);
+ timer_set_reload(dev, cycles / pre - 1);
}
void handler1(void) {
val1 += rate1;
- Timers[t].setCompare1(val1);
+ timer_set_compare(timers[t], TIMER_CH1, val1);
count1++;
}
void handler2(void) {
val2 += rate2;
- Timers[t].setCompare2(val2);
+ timer_set_compare(timers[t], TIMER_CH2, val2);
count2++;
}
void handler3(void) {
val3 += rate3;
- Timers[t].setCompare3(val3);
+ timer_set_compare(timers[t], TIMER_CH3, val3);
count3++;
}
void handler4(void) {
val4 += rate4;
- Timers[t].setCompare4(val4);
+ timer_set_compare(timers[t], TIMER_CH4, val4);
count4++;
}
diff --git a/libmaple/bitband.h b/libmaple/bitband.h
index 3e02702..870abe9 100644
--- a/libmaple/bitband.h
+++ b/libmaple/bitband.h
@@ -30,6 +30,9 @@
* @brief Bit-banding utility functions
*/
+#ifndef _BITBAND_H_
+#define _BITBAND_H_
+
#define BB_SRAM_REF 0x20000000
#define BB_SRAM_BASE 0x22000000
#define BB_PERI_REF 0x40000000
@@ -103,3 +106,5 @@ static inline __io uint32* __bb_addr(__io void *address,
uint32 bb_ref) {
return (__io uint32*)(bb_base + ((uint32)address - bb_ref) * 32 + bit * 4);
}
+
+#endif /* _BITBAND_H_ */
diff --git a/libmaple/delay.h b/libmaple/delay.h
index 10839c9..e4d85c5 100644
--- a/libmaple/delay.h
+++ b/libmaple/delay.h
@@ -1,5 +1,5 @@
/**
- * @brief
+ * @brief Delay implementation
*/
#ifndef _DELAY_H_
diff --git a/libmaple/nvic.h b/libmaple/nvic.h
index fe9990f..cbcd49c 100644
--- a/libmaple/nvic.h
+++ b/libmaple/nvic.h
@@ -53,9 +53,6 @@ extern "C"{
/* System control registers */
#define SCB_VTOR 0xE000ED08 // Vector table offset register
-#define NVIC_VectTab_RAM ((u32)0x20000000)
-#define NVIC_VectTab_FLASH ((u32)0x08000000)
-
#define NVIC_BASE 0xE000E100
#define NVIC ((nvic_reg_map*)NVIC_BASE)
@@ -75,52 +72,58 @@ typedef struct nvic_reg_map {
__io uint32 STIR; // Software Trigger Interrupt Registers
} nvic_reg_map;
-enum {
- NVIC_NMI = -14,
- NVIC_MEM_MANAGE = -12,
- NVIC_BUS_FAULT = -11,
- NVIC_USAGE_FAULT = -10,
- NVIC_SVC = -5,
- NVIC_DEBUG_MON = -4,
- NVIC_PEND_SVC = -2,
- NVIC_SYSTICK = -1,
- NVIC_TIMER1 = 27,
- NVIC_TIMER2 = 28,
- NVIC_TIMER3 = 29,
- NVIC_TIMER4 = 30,
- NVIC_TIMER5 = 50, // high density only (Maple Native, Maple Audio)
- NVIC_TIMER6 = 54, // high density only
- NVIC_TIMER7 = 55, // high density only
- NVIC_TIMER8 = 46, // high density only
-
- NVIC_USART1 = 37,
- NVIC_USART2 = 38,
- NVIC_USART3 = 39,
- NVIC_UART4 = 52, // high density only
- NVIC_UART5 = 53, // high density only
-
- NVIC_EXTI0 = 6,
- NVIC_EXTI1 = 7,
- NVIC_EXTI2 = 8,
- NVIC_EXTI3 = 9,
- NVIC_EXTI4 = 10,
- NVIC_EXTI9_5 = 23,
- NVIC_EXTI15_10 = 40,
-
- NVIC_DMA_CH1 = 11,
- NVIC_DMA_CH2 = 12,
- NVIC_DMA_CH3 = 13,
- NVIC_DMA_CH4 = 14,
- NVIC_DMA_CH5 = 15,
- NVIC_DMA_CH6 = 16,
- NVIC_DMA_CH7 = 17,
-
- NVIC_I2C1_EV = 31,
- NVIC_I2C1_ER = 32,
- NVIC_I2C2_EV = 33,
- NVIC_I2C2_ER = 34
-};
-
+typedef enum nvic_irq_num {
+ NVIC_NMI = -14,
+ NVIC_MEM_MANAGE = -12,
+ NVIC_BUS_FAULT = -11,
+ NVIC_USAGE_FAULT = -10,
+ NVIC_SVC = -5,
+ NVIC_DEBUG_MON = -4,
+ NVIC_PEND_SVC = -2,
+ NVIC_SYSTICK = -1,
+
+ NVIC_TIMER1_BRK = 24,
+ NVIC_TIMER1_UP = 25,
+ NVIC_TIMER1_TRG_COM = 26,
+ NVIC_TIMER1_CC = 27,
+ NVIC_TIMER2 = 28,
+ NVIC_TIMER3 = 29,
+ NVIC_TIMER4 = 30,
+ NVIC_TIMER5 = 50,
+ NVIC_TIMER6 = 54,
+ NVIC_TIMER7 = 55,
+ NVIC_TIMER8_BRK = 43,
+ NVIC_TIMER8_UP = 44,
+ NVIC_TIMER8_TRG_COM = 45,
+ NVIC_TIMER8_CC = 46,
+
+ NVIC_USART1 = 37,
+ NVIC_USART2 = 38,
+ NVIC_USART3 = 39,
+ NVIC_UART4 = 52,
+ NVIC_UART5 = 53,
+
+ NVIC_EXTI0 = 6,
+ NVIC_EXTI1 = 7,
+ NVIC_EXTI2 = 8,
+ NVIC_EXTI3 = 9,
+ NVIC_EXTI4 = 10,
+ NVIC_EXTI9_5 = 23,
+ NVIC_EXTI15_10 = 40,
+
+ NVIC_DMA_CH1 = 11,
+ NVIC_DMA_CH2 = 12,
+ NVIC_DMA_CH3 = 13,
+ NVIC_DMA_CH4 = 14,
+ NVIC_DMA_CH5 = 15,
+ NVIC_DMA_CH6 = 16,
+ NVIC_DMA_CH7 = 17,
+
+ NVIC_I2C1_EV = 31,
+ NVIC_I2C1_ER = 32,
+ NVIC_I2C2_EV = 33,
+ NVIC_I2C2_ER = 34
+} nvic_irq_num;
#define nvic_globalirq_enable() asm volatile("cpsie i")
#define nvic_globalirq_disable() asm volatile("cpsid i")
diff --git a/libmaple/rules.mk b/libmaple/rules.mk
index 48b5ed4..a9d7e50 100644
--- a/libmaple/rules.mk
+++ b/libmaple/rules.mk
@@ -28,7 +28,7 @@ cSRCS_$(d) := adc.c \
spi.c \
syscalls.c \
systick.c \
- timers.c \
+ timer.c \
usart.c \
util.c \
usb/descriptors.c \
diff --git a/libmaple/spi.h b/libmaple/spi.h
index db8aa9c..5ebf52d 100644
--- a/libmaple/spi.h
+++ b/libmaple/spi.h
@@ -31,6 +31,9 @@
#ifndef _SPI_H_
#define _SPI_H_
+#include "libmaple_types.h"
+#include "util.h"
+
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/libmaple/timer.c b/libmaple/timer.c
new file mode 100644
index 0000000..ad0ec6f
--- /dev/null
+++ b/libmaple/timer.c
@@ -0,0 +1,449 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 LeafLabs, LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *****************************************************************************/
+
+/**
+ * @file timer.c
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief New-style timer interface
+ */
+
+#include "timer.h"
+
+#if defined(STM32_MEDIUM_DENSITY)
+#define NR_TIMERS 4
+#elif defined(STM32_HIGH_DENSITY)
+#define NR_TIMERS 8
+#endif
+
+/* Just like the corresponding DIER bits:
+ * [0] = Update handler;
+ * [1,2,3,4] = capture/compare 1,2,3,4 handlers, respectively;
+ * [5] = COM;
+ * [6] = TRG;
+ * [7] = BRK. */
+#define NR_ADV_HANDLERS 8
+/* Update, capture/compare 1,2,3,4; <junk>; trigger. */
+#define NR_GEN_HANDLERS 6
+/* Update only. */
+#define NR_BAS_HANDLERS 1
+
+static timer_dev timer1 = {
+ .regs = {.adv = TIMER1_BASE},
+ .clk_id = RCC_TIMER1,
+ .type = TIMER_ADVANCED,
+ .handlers = { [NR_ADV_HANDLERS - 1] = 0 },
+};
+timer_dev *TIMER1 = &timer1;
+
+static timer_dev timer2 = {
+ .regs = {.gen = TIMER2_BASE},
+ .clk_id = RCC_TIMER2,
+ .type = TIMER_GENERAL,
+ .handlers = { [NR_GEN_HANDLERS - 1] = 0 },
+};
+timer_dev *TIMER2 = &timer2;
+
+static timer_dev timer3 = {
+ .regs = {.gen = TIMER3_BASE},
+ .clk_id = RCC_TIMER3,
+ .type = TIMER_GENERAL,
+ .handlers = { [NR_GEN_HANDLERS - 1] = 0 },
+};
+timer_dev *TIMER3 = &timer3;
+
+static timer_dev timer4 = {
+ .regs = {.gen = TIMER4_BASE},
+ .clk_id = RCC_TIMER4,
+ .type = TIMER_GENERAL,
+ .handlers = { [NR_GEN_HANDLERS - 1] = 0 },
+};
+timer_dev *TIMER4 = &timer4;
+
+#ifdef STM32_HIGH_DENSITY
+static timer_dev timer5 = {
+ .regs = {.gen = TIMER5_BASE},
+ .clk_id = RCC_TIMER5,
+ .type = TIMER_GENERAL,
+ .handlers = { [NR_GEN_HANDLERS - 1] = 0 },
+};
+timer_dev *TIMER5 = &timer5;
+
+static timer_dev timer6 = {
+ .regs = {.bas = TIMER6_BASE},
+ .clk_id = RCC_TIMER6,
+ .type = TIMER_BASIC,
+ .handlers = { [NR_BAS_HANDLERS - 1] = 0 },
+};
+timer_dev *TIMER6 = &timer6;
+
+static timer_dev timer7 = {
+ .regs = {.bas = TIMER7_BASE},
+ .clk_id = RCC_TIMER7,
+ .type = TIMER_BASIC,
+ .handlers = { [NR_BAS_HANDLERS - 1] = 0 },
+};
+timer_dev *TIMER7 = &timer7;
+
+static timer_dev timer8 = {
+ .regs = {.adv = TIMER8_BASE},
+ .clk_id = RCC_TIMER8,
+ .type = TIMER_ADVANCED,
+ .handlers = { [NR_ADV_HANDLERS - 1] = 0 },
+};
+timer_dev *TIMER8 = &timer8;
+#endif
+
+/*
+ * Convenience routines
+ */
+
+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);
+
+/**
+ * Initialize a timer, and reset its register map.
+ * @param dev Timer to initialize
+ */
+void timer_init(timer_dev *dev) {
+ rcc_clk_enable(dev->clk_id);
+ rcc_reset_dev(dev->clk_id);
+}
+
+/**
+ * @brief Disable a timer.
+ *
+ * The timer will stop counting, all DMA requests and interrupts will
+ * be disabled, and no state changes will be output.
+ *
+ * @param dev Timer to disable.
+ */
+void timer_disable(timer_dev *dev) {
+ (dev->regs).bas->CR1 = 0;
+ (dev->regs).bas->DIER = 0;
+ switch (dev->type) {
+ case TIMER_ADVANCED: /* fall-through */
+ case TIMER_GENERAL:
+ (dev->regs).gen->CCER = 0;
+ break;
+ case TIMER_BASIC:
+ break;
+ }
+}
+
+/**
+ * Sets the mode of an individual timer channel.
+ *
+ * Note that not all timers can be configured in every mode. For
+ * example, basic timers cannot be configured to output compare mode.
+ * Be sure to use a timer which is appropriate for the mode you want.
+ *
+ * @param dev Timer whose channel mode to set
+ * @param channel Relevant channel
+ * @param mode New timer mode for channel
+ */
+void timer_set_mode(timer_dev *dev, uint8 channel, timer_mode mode) {
+ ASSERT(channel > 0 && channel <= 4);
+
+ /* TODO decide about the basic timers */
+ ASSERT(dev->type != TIMER_BASIC);
+ if (dev->type == TIMER_BASIC)
+ return;
+
+ switch (mode) {
+ case TIMER_DISABLED:
+ disable_channel(dev, channel);
+ break;
+ case TIMER_PWM:
+ pwm_mode(dev, channel);
+ break;
+ case TIMER_OUTPUT_COMPARE:
+ output_compare_mode(dev, channel);
+ break;
+ }
+}
+
+/**
+ * @brief Call a given function on all timers.
+ * @param fn Function to call on each timer.
+ */
+void timer_foreach(void (*fn)(timer_dev*)) {
+ fn(TIMER1);
+ fn(TIMER2);
+ fn(TIMER3);
+ fn(TIMER4);
+#ifdef STM32_HIGH_DENSITY
+ fn(TIMER5);
+ fn(TIMER6);
+ fn(TIMER7);
+ fn(TIMER8);
+#endif
+}
+
+/**
+ * @brief Attach a timer interrupt.
+ * @param dev Timer device
+ * @param interrupt Interrupt number to attach to; this may be any
+ * timer_interrupt_id or timer_channel value appropriate
+ * for the timer.
+ * @param handler Handler to attach to the given interrupt.
+ * @see timer_interrupt_id
+ * @see timer_channel
+ */
+void timer_attach_interrupt(timer_dev *dev,
+ uint8 interrupt,
+ voidFuncPtr handler) {
+ dev->handlers[interrupt] = handler;
+ timer_enable_interrupt(dev, interrupt);
+ enable_irq(dev, interrupt);
+}
+
+/**
+ * @brief Detach a timer interrupt.
+ * @param dev Timer device
+ * @param interrupt Interrupt number to detach; this may be any
+ * timer_interrupt_id or timer_channel value appropriate
+ * for the timer.
+ * @see timer_interrupt_id
+ * @see timer_channel
+ */
+void timer_detach_interrupt(timer_dev *dev, uint8 interrupt) {
+ timer_disable_interrupt(dev, interrupt);
+ dev->handlers[interrupt] = NULL;
+}
+
+/*
+ * IRQ handlers
+ */
+
+static inline void dispatch_adv_brk(timer_dev *dev);
+static inline void dispatch_adv_up(timer_dev *dev);
+static inline void dispatch_adv_trg_com(timer_dev *dev);
+static inline void dispatch_adv_cc(timer_dev *dev);
+static inline void dispatch_general(timer_dev *dev);
+static inline void dispatch_basic(timer_dev *dev);
+
+void __irq_tim1_brk(void) {
+ dispatch_adv_brk(TIMER1);
+}
+
+void __irq_tim1_up(void) {
+ dispatch_adv_up(TIMER1);
+}
+
+void __irq_tim1_trg_com(void) {
+ dispatch_adv_trg_com(TIMER1);
+}
+
+void __irq_tim1_cc(void) {
+ dispatch_adv_cc(TIMER1);
+}
+
+void __irq_tim2(void) {
+ dispatch_general(TIMER2);
+}
+
+void __irq_tim3(void) {
+ dispatch_general(TIMER3);
+}
+
+void __irq_tim4(void) {
+ dispatch_general(TIMER4);
+}
+
+#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
+
+void __irq_tim5(void) {
+ dispatch_general(TIMER5);
+}
+
+void __irq_tim6(void) {
+ dispatch_basic(TIMER6);
+}
+
+void __irq_tim7(void) {
+ dispatch_basic(TIMER7);
+}
+
+void __irq_tim8_brk(void) {
+ dispatch_adv_brk(TIMER8);
+}
+
+void __irq_tim8_up(void) {
+ dispatch_adv_up(TIMER8);
+}
+
+void __irq_tim8_trg_com(void) {
+ dispatch_adv_trg_com(TIMER8);
+}
+
+void __irq_tim8_cc(void) {
+ dispatch_adv_cc(TIMER8);
+}
+#endif
+
+static inline void dispatch_irq(timer_dev *dev, uint8 iid, uint8 sr_bit);
+static inline void dispatch_cc_irqs(timer_dev *dev);
+
+static inline void dispatch_adv_brk(timer_dev *dev) {
+ dispatch_irq(dev, TIMER_BREAK_INTERRUPT, TIMER_SR_BIF_BIT);
+}
+
+static inline void dispatch_adv_up(timer_dev *dev) {
+ dispatch_irq(dev, TIMER_UPDATE_INTERRUPT, TIMER_SR_UIF_BIT);
+}
+
+static inline void dispatch_adv_trg_com(timer_dev *dev) {
+ dispatch_irq(dev, TIMER_TRG_INTERRUPT, TIMER_SR_TIF_BIT);
+ dispatch_irq(dev, TIMER_COM_INTERRUPT, TIMER_SR_COMIF_BIT);
+}
+
+static inline void dispatch_adv_cc(timer_dev *dev) {
+ dispatch_cc_irqs(dev);
+}
+
+static inline void dispatch_general(timer_dev *dev) {
+ dispatch_irq(dev, TIMER_TRG_INTERRUPT, TIMER_SR_TIF_BIT);
+ dispatch_cc_irqs(dev);
+ dispatch_irq(dev, TIMER_UPDATE_INTERRUPT, TIMER_SR_UIF_BIT);
+}
+
+static inline void dispatch_basic(timer_dev *dev) {
+ dispatch_irq(dev, TIMER_UPDATE_INTERRUPT, TIMER_SR_UIF_BIT);
+}
+
+static inline void dispatch_irq(timer_dev *dev, uint8 iid, uint8 sr_bit) {
+ __io uint32 *sr = &(dev->regs).bas->SR;
+ if (bb_peri_get_bit(sr, sr_bit)) {
+ if (dev->handlers[iid])
+ (dev->handlers[iid])();
+ bb_peri_set_bit(sr, sr_bit, 0);
+ }
+}
+
+static inline void dispatch_cc_irqs(timer_dev *dev) {
+ uint32 sr = (dev->regs).gen->SR;
+ uint32 sr_clear = 0;
+ uint32 b;
+
+ ASSERT(sr & (TIMER_SR_CC1IF | TIMER_SR_CC2IF |
+ TIMER_SR_CC3IF | TIMER_SR_CC4IF));
+
+ for (b = TIMER_SR_CC1IF_BIT; b <= TIMER_SR_CC4IF_BIT; b++) {
+ uint32 mask = BIT(b);
+ if (sr & mask) {
+ if (dev->handlers[b])
+ (dev->handlers[b])();
+ sr_clear |= mask;
+ }
+ }
+
+ (dev->regs).gen->SR &= ~sr_clear;
+}
+
+/*
+ * Utilities
+ */
+
+static void disable_channel(timer_dev *dev, uint8 channel) {
+ timer_detach_interrupt(dev, channel);
+ timer_cc_disable(dev, channel);
+}
+
+static void pwm_mode(timer_dev *dev, uint8 channel) {
+ timer_disable_interrupt(dev, channel);
+ timer_oc_set_mode(dev, channel, TIMER_OC_MODE_PWM_1, TIMER_OC_PE);
+ timer_cc_enable(dev, channel);
+}
+
+static void output_compare_mode(timer_dev *dev, uint8 channel) {
+ timer_oc_set_mode(dev, channel, TIMER_OC_MODE_ACTIVE_ON_MATCH, 0);
+ timer_cc_enable(dev, channel);
+}
+
+static void enable_advanced_irq(timer_dev *dev, timer_interrupt_id id);
+static void enable_nonmuxed_irq(timer_dev *dev);
+
+static inline void enable_irq(timer_dev *dev, timer_interrupt_id iid) {
+ if (dev->type == TIMER_ADVANCED) {
+ enable_advanced_irq(dev, iid);
+ } else {
+ enable_nonmuxed_irq(dev);
+ }
+}
+
+static void enable_advanced_irq(timer_dev *dev, timer_interrupt_id id) {
+ uint8 is_timer1 = dev->clk_id == RCC_TIMER1;
+
+ switch (id) {
+ case TIMER_UPDATE_INTERRUPT:
+ nvic_irq_enable(is_timer1 ? NVIC_TIMER1_UP : NVIC_TIMER8_UP);
+ break;
+ case TIMER_CC1_INTERRUPT:
+ case TIMER_CC2_INTERRUPT:
+ case TIMER_CC3_INTERRUPT:
+ case TIMER_CC4_INTERRUPT:
+ nvic_irq_enable(is_timer1 ? NVIC_TIMER1_CC : NVIC_TIMER8_CC);
+ break;
+ case TIMER_COM_INTERRUPT:
+ case TIMER_TRG_INTERRUPT:
+ nvic_irq_enable(is_timer1 ? NVIC_TIMER1_TRG_COM : NVIC_TIMER8_TRG_COM);
+ break;
+ case TIMER_BREAK_INTERRUPT:
+ nvic_irq_enable(is_timer1 ? NVIC_TIMER1_BRK : NVIC_TIMER8_BRK);
+ break;
+ }
+}
+
+static void enable_nonmuxed_irq(timer_dev *dev) {
+ switch (dev->clk_id) {
+ case RCC_TIMER2:
+ nvic_irq_enable(NVIC_TIMER2);
+ break;
+ case RCC_TIMER3:
+ nvic_irq_enable(NVIC_TIMER3);
+ break;
+ case RCC_TIMER4:
+ nvic_irq_enable(NVIC_TIMER4);
+ break;
+#ifdef STM32_HIGH_DENSITY
+ case RCC_TIMER5:
+ nvic_irq_enable(NVIC_TIMER5);
+ break;
+ case RCC_TIMER6:
+ nvic_irq_enable(NVIC_TIMER6);
+ break;
+ case RCC_TIMER7:
+ nvic_irq_enable(NVIC_TIMER7);
+ break;
+#endif
+ default:
+ ASSERT(0);
+ break;
+ }
+}
diff --git a/libmaple/timer.h b/libmaple/timer.h
new file mode 100644
index 0000000..025bcb0
--- /dev/null
+++ b/libmaple/timer.h
@@ -0,0 +1,1010 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 LeafLabs, LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *****************************************************************************/
+
+/**
+ * @file timer.h
+ * @author Marti Bolivar <mbolivar@leaflabs.com>
+ * @brief New-style timer interface.
+ *
+ * Replaces old timers.h implementation.
+ */
+
+#ifndef _TIMERS_H_
+#define _TIMERS_H_
+
+#include "libmaple.h"
+#include "rcc.h"
+#include "nvic.h"
+#include "bitband.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+/*
+ * Register maps and devices
+ */
+
+/** Advanced control timer register map type */
+typedef struct timer_adv_reg_map {
+ __io uint32 CR1; /**< Control register 1 */
+ __io uint32 CR2; /**< Control register 2 */
+ __io uint32 SMCR; /**< Slave mode control register */
+ __io uint32 DIER; /**< DMA/Interrupt enable register */
+ __io uint32 SR; /**< Status register */
+ __io uint32 EGR; /**< Event generation register */
+ __io uint32 CCMR1; /**< Capture/compare mode register 1 */
+ __io uint32 CCMR2; /**< Capture/compare mode register 2 */
+ __io uint32 CCER; /**< Capture/compare enable register */
+ __io uint32 CNT; /**< Counter */
+ __io uint32 PSC; /**< Prescaler */
+ __io uint32 ARR; /**< Auto-reload register */
+ __io uint32 RCR; /**< Repetition counter register */
+ __io uint32 CCR1; /**< Capture/compare register 1 */
+ __io uint32 CCR2; /**< Capture/compare register 2 */
+ __io uint32 CCR3; /**< Capture/compare register 3 */
+ __io uint32 CCR4; /**< Capture/compare register 4 */
+ __io uint32 BDTR; /**< Break and dead-time register */
+ __io uint32 DCR; /**< DMA control register */
+ __io uint32 DMAR; /**< DMA address for full transfer */
+} timer_adv_reg_map;
+
+/** General purpose timer register map type */
+typedef struct timer_gen_reg_map {
+ __io uint32 CR1; /**< Control register 1 */
+ __io uint32 CR2; /**< Control register 2 */
+ __io uint32 SMCR; /**< Slave mode control register */
+ __io uint32 DIER; /**< DMA/Interrupt enable register */
+ __io uint32 SR; /**< Status register */
+ __io uint32 EGR; /**< Event generation register */
+ __io uint32 CCMR1; /**< Capture/compare mode register 1 */
+ __io uint32 CCMR2; /**< Capture/compare mode register 2 */
+ __io uint32 CCER; /**< Capture/compare enable register */
+ __io uint32 CNT; /**< Counter */
+ __io uint32 PSC; /**< Prescaler */
+ __io uint32 ARR; /**< Auto-reload register */
+ const uint32 RESERVED1; /**< Reserved */
+ __io uint32 CCR1; /**< Capture/compare register 1 */
+ __io uint32 CCR2; /**< Capture/compare register 2 */
+ __io uint32 CCR3; /**< Capture/compare register 3 */
+ __io uint32 CCR4; /**< Capture/compare register 4 */
+ const uint32 RESERVED2; /**< Reserved */
+ __io uint32 DCR; /**< DMA control register */
+ __io uint32 DMAR; /**< DMA address for full transfer */
+} timer_gen_reg_map;
+
+/** Basic timer register map type */
+typedef struct timer_bas_reg_map {
+ __io uint32 CR1; /**< Control register 1 */
+ __io uint32 CR2; /**< Control register 2 */
+ const uint32 RESERVED1; /**< Reserved */
+ __io uint32 DIER; /**< DMA/Interrupt enable register */
+ __io uint32 SR; /**< Status register */
+ __io uint32 EGR; /**< Event generation register */
+ const uint32 RESERVED2; /**< Reserved */
+ const uint32 RESERVED3; /**< Reserved */
+ const uint32 RESERVED4; /**< Reserved */
+ __io uint32 CNT; /**< Counter */
+ __io uint32 PSC; /**< Prescaler */
+ __io uint32 ARR; /**< Auto-reload register */
+} timer_bas_reg_map;
+
+/** Timer 1 register map base pointer */
+#define TIMER1_BASE ((struct timer_adv_reg_map*)0x40012C00)
+/** Timer 2 register map base pointer */
+#define TIMER2_BASE ((struct timer_gen_reg_map*)0x40000000)
+/** Timer 3 register map base pointer */
+#define TIMER3_BASE ((struct timer_gen_reg_map*)0x40000400)
+/** Timer 4 register map base pointer */
+#define TIMER4_BASE ((struct timer_gen_reg_map*)0x40000800)
+#ifdef STM32_HIGH_DENSITY
+/** Timer 5 register map base pointer */
+#define TIMER5_BASE ((struct timer_gen_reg_map*)0x40000C00)
+/** Timer 6 register map base pointer */
+#define TIMER6_BASE ((struct timer_bas_reg_map*)0x40001000)
+/** Timer 7 register map base pointer */
+#define TIMER7_BASE ((struct timer_bas_reg_map*)0x40001400)
+/** Timer 8 register map base pointer */
+#define TIMER8_BASE ((struct timer_adv_reg_map*)0x40013400)
+#endif
+
+/*
+ * Timer devices
+ */
+
+typedef union {
+ timer_adv_reg_map *adv;
+ timer_gen_reg_map *gen;
+ timer_bas_reg_map *bas;
+} timer_reg_map_union;
+
+typedef enum {
+ TIMER_ADVANCED,
+ TIMER_GENERAL,
+ TIMER_BASIC
+} timer_type;
+
+/** Timer device type */
+typedef struct timer_dev {
+ timer_reg_map_union regs;
+ rcc_clk_id clk_id;
+ timer_type type;
+ voidFuncPtr handlers[];
+} timer_dev;
+
+/** Timer 1 device (advanced) */
+extern timer_dev *TIMER1;
+/** Timer 2 device (general-purpose) */
+extern timer_dev *TIMER2;
+/** Timer 3 device (general-purpose) */
+extern timer_dev *TIMER3;
+/** Timer 4 device (general-purpose) */
+extern timer_dev *TIMER4;
+#ifdef STM32_HIGH_DENSITY
+/** Timer 5 device (general-purpose) */
+extern timer_dev *TIMER5;
+/** Timer 6 device (basic) */
+extern timer_dev *TIMER6;
+/** Timer 7 device (basic) */
+extern timer_dev *TIMER7;
+/** Timer 8 device (basic) */
+extern timer_dev *TIMER8;
+#endif
+
+/*
+ * Register bit definitions
+ */
+
+/* Control register 1 (CR1) */
+
+#define TIMER_CR1_ARPE_BIT 7
+#define TIMER_CR1_DIR_BIT 4
+#define TIMER_CR1_OPM_BIT 3
+#define TIMER_CR1_URS_BIT 2
+#define TIMER_CR1_UDIS_BIT 1
+#define TIMER_CR1_CEN_BIT 0
+
+#define TIMER_CR1_CKD (0x3 << 8)
+#define TIMER_CR1_CKD_1TCKINT (0x0 << 8)
+#define TIMER_CR1_CKD_2TCKINT (0x1 << 8)
+#define TIMER_CR1_CKD_4TICKINT (0x2 << 8)
+#define TIMER_CR1_ARPE BIT(TIMER_CR1_ARPE_BIT)
+#define TIMER_CR1_CKD_CMS (0x3 << 5)
+#define TIMER_CR1_CKD_CMS_EDGE (0x0 << 5)
+#define TIMER_CR1_CKD_CMS_CENTER1 (0x1 << 5)
+#define TIMER_CR1_CKD_CMS_CENTER2 (0x2 << 5)
+#define TIMER_CR1_CKD_CMS_CENTER3 (0x3 << 5)
+#define TIMER_CR1_DIR BIT(TIMER_CR1_DIR_BIT)
+#define TIMER_CR1_OPM BIT(TIMER_CR1_OPM_BIT)
+#define TIMER_CR1_URS BIT(TIMER_CR1_URS_BIT)
+#define TIMER_CR1_UDIS BIT(TIMER_CR1_UDIS_BIT)
+#define TIMER_CR1_CEN BIT(TIMER_CR1_CEN_BIT)
+
+/* Control register 2 (CR2) */
+
+#define TIMER_CR2_OIS4_BIT 14
+#define TIMER_CR2_OIS3N_BIT 13
+#define TIMER_CR2_OIS3_BIT 12
+#define TIMER_CR2_OIS2N_BIT 11
+#define TIMER_CR2_OIS2_BIT 10
+#define TIMER_CR2_OIS1N_BIT 9
+#define TIMER_CR2_OIS1_BIT 8
+#define TIMER_CR2_TI1S_BIT 7 /* tills? yikes */
+#define TIMER_CR2_CCDS_BIT 3
+#define TIMER_CR2_CCUS_BIT 2
+#define TIMER_CR2_CCPC_BIT 0
+
+#define TIMER_CR2_OIS4 BIT(TIMER_CR2_OIS4_BIT)
+#define TIMER_CR2_OIS3N BIT(TIMER_CR2_OIS3N_BIT)
+#define TIMER_CR2_OIS3 BIT(TIMER_CR2_OIS3_BIT)
+#define TIMER_CR2_OIS2N BIT(TIMER_CR2_OIS2N_BIT)
+#define TIMER_CR2_OIS2 BIT(TIMER_CR2_OIS2_BIT)
+#define TIMER_CR2_OIS1N BIT(TIMER_CR2_OIS1N_BIT)
+#define TIMER_CR2_OIS1 BIT(TIMER_CR2_OIS1_BIT)
+#define TIMER_CR2_TI1S BIT(TIMER_CR2_TI1S_BIT)
+#define TIMER_CR2_MMS (0x7 << 4)
+#define TIMER_CR2_MMS_RESET (0x0 << 4)
+#define TIMER_CR2_MMS_ENABLE (0x1 << 4)
+#define TIMER_CR2_MMS_UPDATE (0x2 << 4)
+#define TIMER_CR2_MMS_COMPARE_PULSE (0x3 << 4)
+#define TIMER_CR2_MMS_COMPARE_OC1REF (0x4 << 4)
+#define TIMER_CR2_MMS_COMPARE_OC2REF (0x5 << 4)
+#define TIMER_CR2_MMS_COMPARE_OC3REF (0x6 << 4)
+#define TIMER_CR2_MMS_COMPARE_OC4REF (0x7 << 4)
+#define TIMER_CR2_CCDS BIT(TIMER_CR2_CCDS_BIT)
+#define TIMER_CR2_CCUS BIT(TIMER_CR2_CCUS_BIT)
+#define TIMER_CR2_CCPC BIT(TIMER_CR2_CCPC_BIT)
+
+/* Slave mode control register (SMCR) */
+
+#define TIMER_SMCR_ETP_BIT 15
+#define TIMER_SMCR_ECE_BIT 14
+#define TIMER_SMCR_MSM_BIT 7
+
+#define TIMER_SMCR_ETP BIT(TIMER_SMCR_ETP_BIT)
+#define TIMER_SMCR_ECE BIT(TIMER_SMCR_ECE_BIT)
+#define TIMER_SMCR_ETPS (0x3 << 12)
+#define TIMER_SMCR_ETPS_OFF (0x0 << 12)
+#define TIMER_SMCR_ETPS_DIV2 (0x1 << 12)
+#define TIMER_SMCR_ETPS_DIV4 (0x2 << 12)
+#define TIMER_SMCR_ETPS_DIV8 (0x3 << 12)
+#define TIMER_SMCR_ETF (0xF << 12)
+#define TIMER_SMCR_MSM BIT(TIMER_SMCR_MSM_BIT)
+#define TIMER_SMCR_TS (0x3 << 4)
+#define TIMER_SMCR_TS_ITR0 (0x0 << 4)
+#define TIMER_SMCR_TS_ITR1 (0x1 << 4)
+#define TIMER_SMCR_TS_ITR2 (0x2 << 4)
+#define TIMER_SMCR_TS_ITR3 (0x3 << 4)
+#define TIMER_SMCR_TS_TI1F_ED (0x4 << 4)
+#define TIMER_SMCR_TS_TI1FP1 (0x5 << 4)
+#define TIMER_SMCR_TS_TI2FP2 (0x6 << 4)
+#define TIMER_SMCR_TS_ETRF (0x7 << 4)
+#define TIMER_SMCR_SMS 0x3
+#define TIMER_SMCR_SMS_DISABLED 0x0
+#define TIMER_SMCR_SMS_ENCODER1 0x1
+#define TIMER_SMCR_SMS_ENCODER2 0x2
+#define TIMER_SMCR_SMS_ENCODER3 0x3
+#define TIMER_SMCR_SMS_RESET 0x4
+#define TIMER_SMCR_SMS_GATED 0x5
+#define TIMER_SMCR_SMS_TRIGGER 0x6
+#define TIMER_SMCR_SMS_EXTERNAL 0x7
+
+/* DMA/Interrupt enable register (DIER) */
+
+#define TIMER_DIER_TDE_BIT 14
+#define TIMER_DIER_CC4DE_BIT 12
+#define TIMER_DIER_CC3DE_BIT 11
+#define TIMER_DIER_CC2DE_BIT 10
+#define TIMER_DIER_CC1DE_BIT 9
+#define TIMER_DIER_UDE_BIT 8
+#define TIMER_DIER_TIE_BIT 6
+#define TIMER_DIER_CC4IE_BIT 4
+#define TIMER_DIER_CC3IE_BIT 3
+#define TIMER_DIER_CC2IE_BIT 2
+#define TIMER_DIER_CC1IE_BIT 1
+#define TIMER_DIER_UIE_BIT 0
+
+#define TIMER_DIER_TDE BIT(TIMER_DIER_TDE_BIT)
+#define TIMER_DIER_CC4DE BIT(TIMER_DIER_CC4DE_BIT)
+#define TIMER_DIER_CC3DE BIT(TIMER_DIER_CC3DE_BIT)
+#define TIMER_DIER_CC2DE BIT(TIMER_DIER_CC2DE_BIT)
+#define TIMER_DIER_CC1DE BIT(TIMER_DIER_CC1DE_BIT)
+#define TIMER_DIER_UDE BIT(TIMER_DIER_UDE_BIT)
+#define TIMER_DIER_TIE BIT(TIMER_DIER_TIE_BIT)
+#define TIMER_DIER_CC4IE BIT(TIMER_DIER_CC4IE_BIT)
+#define TIMER_DIER_CC3IE BIT(TIMER_DIER_CC3IE_BIT)
+#define TIMER_DIER_CC2IE BIT(TIMER_DIER_CC2IE_BIT)
+#define TIMER_DIER_CC1IE BIT(TIMER_DIER_CC1IE_BIT)
+#define TIMER_DIER_UIE BIT(TIMER_DIER_UIE_BIT)
+
+/* Status register (SR) */
+
+#define TIMER_SR_CC4OF_BIT 12
+#define TIMER_SR_CC3OF_BIT 11
+#define TIMER_SR_CC2OF_BIT 10
+#define TIMER_SR_CC1OF_BIT 9
+#define TIMER_SR_BIF_BIT 7
+#define TIMER_SR_TIF_BIT 6
+#define TIMER_SR_COMIF_BIT 5
+#define TIMER_SR_CC4IF_BIT 4
+#define TIMER_SR_CC3IF_BIT 3
+#define TIMER_SR_CC2IF_BIT 2
+#define TIMER_SR_CC1IF_BIT 1
+#define TIMER_SR_UIF_BIT 0
+
+#define TIMER_SR_CC4OF BIT(TIMER_SR_CC4OF_BIT)
+#define TIMER_SR_CC3OF BIT(TIMER_SR_CC3OF_BIT)
+#define TIMER_SR_CC2OF BIT(TIMER_SR_CC2OF_BIT)
+#define TIMER_SR_CC1OF BIT(TIMER_SR_CC1OF_BIT)
+#define TIMER_SR_BIF BIT(TIMER_SR_BIF_BIT)
+#define TIMER_SR_TIF BIT(TIMER_SR_TIF_BIT)
+#define TIMER_SR_COMIF BIT(TIMER_SR_COMIF_BIT)
+#define TIMER_SR_CC4IF BIT(TIMER_SR_CC4IF_BIT)
+#define TIMER_SR_CC3IF BIT(TIMER_SR_CC3IF_BIT)
+#define TIMER_SR_CC2IF BIT(TIMER_SR_CC2IF_BIT)
+#define TIMER_SR_CC1IF BIT(TIMER_SR_CC1IF_BIT)
+#define TIMER_SR_UIF BIT(TIMER_SR_UIF_BIT)
+
+/* Event generation register (EGR) */
+
+#define TIMER_EGR_TG_BIT 6
+#define TIMER_EGR_CC4G_BIT 4
+#define TIMER_EGR_CC3G_BIT 3
+#define TIMER_EGR_CC2G_BIT 2
+#define TIMER_EGR_CC1G_BIT 1
+#define TIMER_EGR_UG_BIT 0
+
+#define TIMER_EGR_TG BIT(TIMER_EGR_TG_BIT)
+#define TIMER_EGR_CC4G BIT(TIMER_EGR_CC4G_BIT)
+#define TIMER_EGR_CC3G BIT(TIMER_EGR_CC3G_BIT)
+#define TIMER_EGR_CC2G BIT(TIMER_EGR_CC2G_BIT)
+#define TIMER_EGR_CC1G BIT(TIMER_EGR_CC1G_BIT)
+#define TIMER_EGR_UG BIT(TIMER_EGR_UG_BIT)
+
+/* Capture/compare mode registers, common values */
+
+#define TIMER_CCMR_CCS_OUTPUT 0x0
+#define TIMER_CCMR_CCS_INPUT_TI1 0x1
+#define TIMER_CCMR_CCS_INPUT_TI2 0x2
+#define TIMER_CCMR_CCS_INPUT_TRC 0x3
+
+/* Capture/compare mode register 1 (CCMR1) */
+
+#define TIMER_CCMR1_OC2CE_BIT 15
+#define TIMER_CCMR1_OC2PE_BIT 11
+#define TIMER_CCMR1_OC2FE_BIT 10
+#define TIMER_CCMR1_OC1CE_BIT 7
+#define TIMER_CCMR1_OC1PE_BIT 3
+#define TIMER_CCMR1_OC1FE_BIT 2
+
+#define TIMER_CCMR1_OC2CE BIT(TIMER_CCMR1_OC2CE_BIT)
+#define TIMER_CCMR1_OC2M (0x3 << 12)
+#define TIMER_CCMR1_IC2F (0xF << 12)
+#define TIMER_CCMR1_OC2PE BIT(TIMER_CCMR1_OC2PE_BIT)
+#define TIMER_CCMR1_OC2FE BIT(TIMER_CCMR1_OC2FE_BIT)
+#define TIMER_CCMR1_IC2PSC (0x3 << 10)
+#define TIMER_CCMR1_CC2S (0x3 << 8)
+#define TIMER_CCMR1_CC2S_OUTPUT (TIMER_CCMR_CCS_OUTPUT << 8)
+#define TIMER_CCMR1_CC2S_INPUT_TI1 (TIMER_CCMR_CCS_INPUT_TI1 << 8)
+#define TIMER_CCMR1_CC2S_INPUT_TI2 (TIMER_CCMR_CCS_INPUT_TI2 << 8)
+#define TIMER_CCMR1_CC2S_INPUT_TRC (TIMER_CCMR_CCS_INPUT_TRC << 8)
+#define TIMER_CCMR1_OC1CE BIT(TIMER_CCMR1_OC1CE_BIT)
+#define TIMER_CCMR1_OC1M (0x3 << 4)
+#define TIMER_CCMR1_IC1F (0xF << 4)
+#define TIMER_CCMR1_OC1PE BIT(TIMER_CCMR1_OC1PE_BIT)
+#define TIMER_CCMR1_OC1FE BIT(TIMER_CCMR1_OC1FE_BIT)
+#define TIMER_CCMR1_IC1PSC (0x3 << 2)
+#define TIMER_CCMR1_CC1S 0x3
+#define TIMER_CCMR1_CC1S_OUTPUT TIMER_CCMR_CCS_OUTPUT
+#define TIMER_CCMR1_CC1S_INPUT_TI1 TIMER_CCMR_CCS_INPUT_TI1
+#define TIMER_CCMR1_CC1S_INPUT_TI2 TIMER_CCMR_CCS_INPUT_TI2
+#define TIMER_CCMR1_CC1S_INPUT_TRC TIMER_CCMR_CCS_INPUT_TRC
+
+/* Capture/compare mode register 2 (CCMR2) */
+
+#define TIMER_CCMR2_OC4CE_BIT 15
+#define TIMER_CCMR2_OC4PE_BIT 11
+#define TIMER_CCMR2_OC4FE_BIT 10
+#define TIMER_CCMR2_OC3CE_BIT 7
+#define TIMER_CCMR2_OC3PE_BIT 3
+#define TIMER_CCMR2_OC3FE_BIT 2
+
+#define TIMER_CCMR2_OC4CE BIT(TIMER_CCMR2_OC4CE_BIT)
+#define TIMER_CCMR2_OC4M (0x3 << 12)
+#define TIMER_CCMR2_IC2F (0xF << 12)
+#define TIMER_CCMR2_OC4PE BIT(TIMER_CCMR2_OC4PE_BIT)
+#define TIMER_CCMR2_OC4FE BIT(TIMER_CCMR2_OC4FE_BIT)
+#define TIMER_CCMR2_IC2PSC (0x3 << 10)
+#define TIMER_CCMR2_CC4S (0x3 << 8)
+#define TIMER_CCMR1_CC4S_OUTPUT (TIMER_CCMR_CCS_OUTPUT << 8)
+#define TIMER_CCMR1_CC4S_INPUT_TI1 (TIMER_CCMR_CCS_INPUT_TI1 << 8)
+#define TIMER_CCMR1_CC4S_INPUT_TI2 (TIMER_CCMR_CCS_INPUT_TI2 << 8)
+#define TIMER_CCMR1_CC4S_INPUT_TRC (TIMER_CCMR_CCS_INPUT_TRC << 8)
+#define TIMER_CCMR2_OC3CE BIT(TIMER_CCMR2_OC3CE_BIT)
+#define TIMER_CCMR2_OC3M (0x3 << 4)
+#define TIMER_CCMR2_IC1F (0xF << 4)
+#define TIMER_CCMR2_OC3PE BIT(TIMER_CCMR2_OC3PE_BIT)
+#define TIMER_CCMR2_OC3FE BIT(TIMER_CCMR2_OC3FE_BIT)
+#define TIMER_CCMR2_IC1PSC (0x3 << 2)
+#define TIMER_CCMR2_CC3S 0x3
+#define TIMER_CCMR1_CC3S_OUTPUT TIMER_CCMR_CCS_OUTPUT
+#define TIMER_CCMR1_CC3S_INPUT_TI1 TIMER_CCMR_CCS_INPUT_TI1
+#define TIMER_CCMR1_CC3S_INPUT_TI2 TIMER_CCMR_CCS_INPUT_TI2
+#define TIMER_CCMR1_CC3S_INPUT_TRC TIMER_CCMR_CCS_INPUT_TRC
+
+/* Capture/compare enable register (CCER) */
+
+#define TIMER_CCER_CC4P_BIT 13
+#define TIMER_CCER_CC4E_BIT 12
+#define TIMER_CCER_CC3P_BIT 9
+#define TIMER_CCER_CC3E_BIT 8
+#define TIMER_CCER_CC2P_BIT 5
+#define TIMER_CCER_CC2E_BIT 4
+#define TIMER_CCER_CC1P_BIT 1
+#define TIMER_CCER_CC1E_BIT 0
+
+#define TIMER_CCER_CC4P BIT(TIMER_CCER_CC4P_BIT)
+#define TIMER_CCER_CC4E BIT(TIMER_CCER_CC4E_BIT)
+#define TIMER_CCER_CC3P BIT(TIMER_CCER_CC3P_BIT)
+#define TIMER_CCER_CC3E BIT(TIMER_CCER_CC3E_BIT)
+#define TIMER_CCER_CC2P BIT(TIMER_CCER_CC2P_BIT)
+#define TIMER_CCER_CC2E BIT(TIMER_CCER_CC2E_BIT)
+#define TIMER_CCER_CC1P BIT(TIMER_CCER_CC1P_BIT)
+#define TIMER_CCER_CC1E BIT(TIMER_CCER_CC1E_BIT)
+
+/* Break and dead-time register (BDTR) */
+
+#define TIMER_BDTR_MOE_BIT 15
+#define TIMER_BDTR_AOE_BIT 14
+#define TIMER_BDTR_BKP_BIT 13
+#define TIMER_BDTR_BKE_BIT 12
+#define TIMER_BDTR_OSSR_BIT 11
+#define TIMER_BDTR_OSSI_BIT 10
+
+#define TIMER_BDTR_MOE BIT(TIMER_BDTR_MOE_BIT)
+#define TIMER_BDTR_AOE BIT(TIMER_BDTR_AOE_BIT)
+#define TIMER_BDTR_BKP BIT(TIMER_BDTR_BKP_BIT)
+#define TIMER_BDTR_BKE BIT(TIMER_BDTR_BKE_BIT)
+#define TIMER_BDTR_OSSR BIT(TIMER_BDTR_OSSR_BIT)
+#define TIMER_BDTR_OSSI BIT(TIMER_BDTR_OSSI_BIT)
+#define TIMER_BDTR_LOCK (0x3 << 8)
+#define TIMER_BDTR_LOCK_OFF (0x0 << 8)
+#define TIMER_BDTR_LOCK_LEVEL1 (0x1 << 8)
+#define TIMER_BDTR_LOCK_LEVEL2 (0x2 << 8)
+#define TIMER_BDTR_LOCK_LEVEL3 (0x3 << 8)
+#define TIMER_BDTR_DTG 0xFF
+
+/* DMA control register (DCR) */
+
+#define TIMER_DCR_DBL (0x1F << 8)
+#define TIMER_DCR_DBL_1BYTE (0x0 << 8)
+#define TIMER_DCR_DBL_2BYTE (0x1 << 8)
+#define TIMER_DCR_DBL_3BYTE (0x2 << 8)
+#define TIMER_DCR_DBL_4BYTE (0x3 << 8)
+#define TIMER_DCR_DBL_5BYTE (0x4 << 8)
+#define TIMER_DCR_DBL_6BYTE (0x5 << 8)
+#define TIMER_DCR_DBL_7BYTE (0x6 << 8)
+#define TIMER_DCR_DBL_8BYTE (0x7 << 8)
+#define TIMER_DCR_DBL_9BYTE (0x8 << 8)
+#define TIMER_DCR_DBL_10BYTE (0x9 << 8)
+#define TIMER_DCR_DBL_11BYTE (0xA << 8)
+#define TIMER_DCR_DBL_12BYTE (0xB << 8)
+#define TIMER_DCR_DBL_13BYTE (0xC << 8)
+#define TIMER_DCR_DBL_14BYTE (0xD << 8)
+#define TIMER_DCR_DBL_15BYTE (0xE << 8)
+#define TIMER_DCR_DBL_16BYTE (0xF << 8)
+#define TIMER_DCR_DBL_17BYTE (0x10 << 8)
+#define TIMER_DCR_DBL_18BYTE (0x11 << 8)
+#define TIMER_DCR_DBA 0x1F
+#define TIMER_DCR_DBA_CR1 0x0
+#define TIMER_DCR_DBA_CR2 0x1
+#define TIMER_DCR_DBA_SMCR 0x2
+#define TIMER_DCR_DBA_DIER 0x3
+#define TIMER_DCR_DBA_SR 0x4
+#define TIMER_DCR_DBA_EGR 0x5
+#define TIMER_DCR_DBA_CCMR1 0x6
+#define TIMER_DCR_DBA_CCMR2 0x7
+#define TIMER_DCR_DBA_CCER 0x8
+#define TIMER_DCR_DBA_CNT 0x9
+#define TIMER_DCR_DBA_PSC 0xA
+#define TIMER_DCR_DBA_ARR 0xB
+#define TIMER_DCR_DBA_RCR 0xC
+#define TIMER_DCR_DBA_CCR1 0xD
+#define TIMER_DCR_DBA_CCR2 0xE
+#define TIMER_DCR_DBA_CCR3 0xF
+#define TIMER_DCR_DBA_CCR4 0x10
+#define TIMER_DCR_DBA_BDTR 0x11
+#define TIMER_DCR_DBA_DCR 0x12
+#define TIMER_DCR_DBA_DMAR 0x13
+
+/*
+ * Convenience routines
+ */
+
+/**
+ * Used to configure the behavior of a timer channel. Note that not
+ * all timers can be configured in every mode.
+ */
+/* TODO TIMER_PWM_CENTER_ALIGNED, TIMER_INPUT_CAPTURE, TIMER_ONE_PULSE */
+typedef enum timer_mode {
+ TIMER_DISABLED, /**< In this mode, the timer stops counting,
+ channel interrupts are detached, and no state
+ changes are output. */
+ TIMER_PWM, /**< PWM output mode. This is the default mode for pins
+ after initialization. */
+ /* TIMER_PWM_CENTER_ALIGNED, /\**< Center-aligned PWM output mode. *\/ */
+ TIMER_OUTPUT_COMPARE, /**< In this mode, the timer counts from 0
+ to its reload value repeatedly; every
+ time the counter value reaches one of
+ the channel compare values, the
+ corresponding interrupt is fired. */
+ /* TIMER_INPUT_CAPTURE, /\**< In this mode, the timer can measure the */
+ /* pulse lengths of input signals. *\/ */
+ /* TIMER_ONE_PULSE /\**< In this mode, the timer can generate a single */
+ /* pulse on a GPIO pin for a specified amount of */
+ /* time. *\/ */
+} timer_mode;
+
+/** Timer channel numbers */
+typedef enum timer_channel {
+ TIMER_CH1 = 1, /**< Channel 1 */
+ TIMER_CH2 = 2, /**< Channel 2 */
+ TIMER_CH3 = 3, /**< Channel 3 */
+ TIMER_CH4 = 4 /**< Channel 4 */
+} timer_channel;
+
+/*
+ * Note: Don't require timer_channel arguments! We want to be able to say
+ *
+ * for (int channel = 1; channel <= 4; channel++) {
+ * ...
+ * }
+ *
+ * without the compiler yelling at us.
+ */
+
+void timer_init(timer_dev *dev);
+void timer_disable(timer_dev *dev);
+void timer_set_mode(timer_dev *dev, uint8 channel, timer_mode mode);
+void timer_foreach(void (*fn)(timer_dev*));
+
+/**
+ * @brief Timer interrupt number.
+ *
+ * Not all timers support all of these values; see the descriptions
+ * for each value.
+ */
+typedef enum timer_interrupt_id {
+ TIMER_UPDATE_INTERRUPT, /**< Update interrupt, available on all timers. */
+ TIMER_CC1_INTERRUPT, /**< Capture/compare 1 interrupt, available
+ on general and advanced timers only. */
+ TIMER_CC2_INTERRUPT, /**< Capture/compare 2 interrupt, general and
+ advanced timers only. */
+ TIMER_CC3_INTERRUPT, /**< Capture/compare 3 interrupt, general and
+ advanced timers only. */
+ TIMER_CC4_INTERRUPT, /**< Capture/compare 4 interrupt, general and
+ advanced timers only. */
+ TIMER_COM_INTERRUPT, /**< COM interrupt, advanced timers only */
+ TIMER_TRG_INTERRUPT, /**< Trigger interrupt, general and advanced
+ timers only */
+ TIMER_BREAK_INTERRUPT /**< Break interrupt, advanced timers only. */
+} timer_interrupt_id;
+
+void timer_attach_interrupt(timer_dev *dev,
+ uint8 interrupt,
+ voidFuncPtr handler);
+void timer_detach_interrupt(timer_dev *dev, uint8 interrupt);
+
+/**
+ * Initialize all timer devices on the chip.
+ */
+static inline void timer_init_all(void) {
+ timer_foreach(timer_init);
+}
+
+/**
+ * Disables all timers on the device.
+ */
+static inline void timer_disable_all(void) {
+ timer_foreach(timer_disable);
+}
+
+/**
+ * @brief Stop a timer's counter from changing.
+ *
+ * Does not affect the timer's mode or other settings.
+ *
+ * @param dev Device whose counter to pause.
+ */
+static inline void timer_pause(timer_dev *dev) {
+ *bb_perip(&(dev->regs).bas->CR1, TIMER_CR1_CEN_BIT) = 0;
+}
+
+/**
+ * @brief Start a timer's counter.
+ *
+ * Does not affect the timer's mode or other settings.
+ *
+ * @param dev Device whose counter to resume
+ */
+static inline void timer_resume(timer_dev *dev) {
+ *bb_perip(&(dev->regs).bas->CR1, TIMER_CR1_CEN_BIT) = 1;
+}
+
+/**
+ * @brief Returns the timer's counter value.
+ *
+ * This value is likely to be inaccurate if the counter is running
+ * with a low prescaler.
+ *
+ * @param dev Timer whose counter to return
+ */
+static inline uint16 timer_get_count(timer_dev *dev) {
+ return (uint16)(dev->regs).bas->CNT;
+}
+
+/**
+ * @brief Sets the counter value for the given timer.
+ * @param timer_num Timer whose counter to set
+ * @param value New counter value
+ */
+static inline void timer_set_count(timer_dev *dev, uint16 value) {
+ (dev->regs).bas->CNT = value;
+}
+
+/**
+ * @brief Returns the given timer's prescaler.
+ *
+ * Note that if the timer's prescaler is set (e.g. via
+ * timer_set_prescaler() or accessing a TIMx_PSC register), the value
+ * returned by this function will reflect the new setting, but the
+ * timer's counter will only reflect the new prescaler at the next
+ * update event.
+ *
+ * @param dev Timer whose prescaler to return
+ * @see timer_generate_update()
+ */
+static inline uint16 timer_get_prescaler(timer_dev *dev) {
+ return (uint16)(dev->regs).bas->PSC;
+}
+
+/**
+ * @brief Set a timer's prescale value.
+ *
+ * The new value will not take effect until the next update event.
+ *
+ * @param dev Timer whose prescaler to set
+ * @param psc New prescaler value
+ * @see timer_generate_update()
+ */
+static inline void timer_set_prescaler(timer_dev *dev, uint16 psc) {
+ (dev->regs).bas->PSC = psc;
+}
+
+/**
+ * @brief Returns a timer's reload value.
+ * @param dev Timer whose reload value to return
+ */
+static inline uint16 timer_get_reload(timer_dev *dev) {
+ return (uint16)(dev->regs).bas->ARR;
+}
+
+/**
+ * @brief Set a timer's reload value.
+ * @param dev Timer whose reload value to set
+ * @param arr New reload value to use. Takes effect at next update event.
+ * @see timer_generate_update()
+ */
+static inline void timer_set_reload(timer_dev *dev, uint16 arr) {
+ (dev->regs).bas->ARR = arr;
+}
+
+/**
+ * @brief Get the compare value for the given timer channel.
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @param channel Channel whose compare value to get.
+ */
+static inline uint16 timer_get_compare(timer_dev *dev, uint8 channel) {
+ __io uint32 *ccr = &(dev->regs).gen->CCR1 + (channel - 1);
+ return *ccr;
+}
+
+/**
+ * @brief Set the compare value for the given timer channel.
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @param channel Channel whose compare value to set.
+ * @param value New compare value.
+ */
+static inline void timer_set_compare(timer_dev *dev,
+ uint8 channel,
+ uint16 value) {
+ __io uint32 *ccr = &(dev->regs).gen->CCR1 + (channel - 1);
+ *ccr = value;
+}
+
+/**
+ * @brief Generate an update event for the given timer.
+ *
+ * Normally, this will cause the prescaler and auto-reload values in
+ * the PSC and ARR registers to take immediate effect. However, this
+ * function will do nothing if the UDIS bit is set in the timer's CR1
+ * register (UDIS is cleared by default).
+ *
+ * @param dev Timer device to generate an update for.
+ */
+static inline void timer_generate_update(timer_dev *dev) {
+ *bb_perip(&(dev->regs).bas->EGR, TIMER_EGR_UG_BIT) = 1;
+}
+
+/**
+ * @brief Enable a timer's trigger DMA request
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL
+ */
+static inline void timer_trigger_dma_enable_request(timer_dev *dev) {
+ *bb_perip(&(dev->regs).gen->DIER, TIMER_DIER_TDE_BIT) = 1;
+}
+
+/**
+ * @brief Disable a timer's trigger DMA request
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL
+ */
+static inline void timer_trigger_dma_disable_request(timer_dev *dev) {
+ *bb_perip(&(dev->regs).gen->DIER, TIMER_DIER_TDE_BIT) = 0;
+}
+
+/**
+ * @brief Enable a timer channel's DMA request.
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL
+ * @param channel Channel whose DMA request to enable.
+ */
+static inline void timer_dma_enable_request(timer_dev *dev, uint8 channel) {
+ *bb_perip(&(dev->regs).gen->DIER, channel + 8) = 1;
+}
+
+/**
+ * @brief Disable a timer channel's DMA request.
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @param channel Channel whose DMA request to disable.
+ */
+static inline void timer_dma_disable_request(timer_dev *dev, uint8 channel) {
+ *bb_perip(&(dev->regs).gen->DIER, channel + 8) = 0;
+}
+
+/**
+ * @brief Enable a timer interrupt.
+ * @param dev Timer device.
+ * @param interrupt Interrupt number to enable; this may be any
+ * timer_interrupt_id value appropriate for the timer.
+ * @see timer_interrupt_id
+ * @see timer_channel
+ */
+static inline void timer_enable_interrupt(timer_dev *dev, uint8 interrupt) {
+ *bb_perip(&(dev->regs).adv->DIER, interrupt) = 1;
+}
+
+/**
+ * @brief Disable a timer interrupt.
+ * @param dev Timer device.
+ * @param interrupt Interrupt number to disable; this may be any
+ * timer_interrupt_id value appropriate for the timer.
+ * @see timer_interrupt_id
+ * @see timer_channel
+ */
+static inline void timer_disable_interrupt(timer_dev *dev, uint8 interrupt) {
+ *bb_perip(&(dev->regs).adv->DIER, interrupt) = 0;
+}
+
+/**
+ * @brief Enable a timer channel's capture/compare signal.
+ *
+ * If the channel is configured as output, the corresponding output
+ * compare signal will be output on the corresponding output pin. If
+ * the channel is configured as input, enables capture of the counter
+ * value into the input capture/compare register.
+ *
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @param channel Channel to enable, from 1 to 4.
+ */
+static inline void timer_cc_enable(timer_dev *dev, uint8 channel) {
+ *bb_perip(&(dev->regs).gen->CCER, 4 * (channel - 1)) = 1;
+}
+
+/**
+ * @brief Disable a timer channel's output compare or input capture signal.
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @param channel Channel to disable, from 1 to 4.
+ * @see timer_cc_enable()
+ */
+static inline void timer_cc_disable(timer_dev *dev, uint8 channel) {
+ *bb_perip(&(dev->regs).gen->CCER, 4 * (channel - 1)) = 0;
+}
+
+/**
+ * @brief Get a channel's capture/compare output polarity
+ * @brief dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @brief channel Channel whose capture/compare output polarity to get.
+ * @return Polarity, either 0 or 1.
+ * @see timer_cc_set_polarity()
+ */
+static inline uint8 timer_cc_get_polarity(timer_dev *dev, uint8 channel) {
+ return *bb_perip(&(dev->regs).gen->CCER, 4 * (channel - 1) + 1);
+}
+
+/**
+ * @brief Set a timer channel's capture/compare output polarity.
+ *
+ * If the timer channel is configured as output: polarity == 0 means
+ * the output channel will be active high; polarity == 1 means active
+ * low.
+ *
+ * If the timer channel is configured as input: polarity == 0 means
+ * capture is done on the rising edge of ICn; when used as an external
+ * trigger, ICn is non-inverted. polarity == 1 means capture is done
+ * on the falling edge of ICn; when used as an external trigger, ICn
+ * is inverted.
+ *
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @param channel Channel whose capture/compare output polarity to set.
+ * @param pol New polarity, 0 or 1.
+ */
+static inline void timer_cc_set_polarity(timer_dev *dev,
+ uint8 channel,
+ uint8 pol) {
+ *bb_perip(&(dev->regs).gen->CCER, 4 * (channel - 1) + 1) = pol;
+}
+
+/**
+ * @brief Get a timer's DMA burst length.
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @return Number of bytes to be transferred per DMA request, from 1 to 18.
+ */
+static inline uint8 timer_get_dma_burst_length(timer_dev *dev) {
+ uint32 dbl = ((dev->regs).gen->DCR & TIMER_DCR_DBL) >> 8;
+ return dbl + 1; /* 0 means 1 byte, etc. */
+}
+
+/**
+ * @brief Set a timer's DMA burst length.
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @param length DMA burst length; i.e., number of bytes to transfer
+ * per DMA request, from 1 to 18.
+ */
+static inline void timer_set_dma_burst_length(timer_dev *dev, uint8 length) {
+ uint32 tmp = (dev->regs).gen->DCR;
+ tmp &= ~TIMER_DCR_DBL;
+ tmp |= (length << 8) - 1;
+ (dev->regs).gen->DCR = tmp;
+}
+
+/**
+ * @brief Timer DMA base address.
+ *
+ * Defines the base address for DMA transfers.
+ */
+typedef enum timer_dma_base_address {
+ TIMER_DMA_BASE_CR1 = TIMER_DCR_DBA_CR1, /**< Base is control register 1 */
+ TIMER_DMA_BASE_CR2 = TIMER_DCR_DBA_CR2, /**< Base is control register 2 */
+ TIMER_DMA_BASE_SMCR = TIMER_DCR_DBA_SMCR, /**< Base is slave mode
+ control register */
+ TIMER_DMA_BASE_DIER = TIMER_DCR_DBA_DIER, /**< Base is DMA interrupt enable
+ register */
+ TIMER_DMA_BASE_SR = TIMER_DCR_DBA_SR, /**< Base is status register */
+ TIMER_DMA_BASE_EGR = TIMER_DCR_DBA_EGR, /**< Base is event generation
+ register */
+ TIMER_DMA_BASE_CCMR1 = TIMER_DCR_DBA_CCMR1, /**< Base is capture/compare
+ mode register 1 */
+ TIMER_DMA_BASE_CCMR2 = TIMER_DCR_DBA_CCMR2, /**< Base is capture/compare
+ mode register 2 */
+ TIMER_DMA_BASE_CCER = TIMER_DCR_DBA_CCER, /**< Base is capture/compare
+ enable register */
+ TIMER_DMA_BASE_CNT = TIMER_DCR_DBA_CNT, /**< Base is counter */
+ TIMER_DMA_BASE_PSC = TIMER_DCR_DBA_PSC, /**< Base is prescaler */
+ TIMER_DMA_BASE_ARR = TIMER_DCR_DBA_ARR, /**< Base is auto-reload
+ register */
+ TIMER_DMA_BASE_RCR = TIMER_DCR_DBA_RCR, /**< Base is repetition
+ counter register */
+ TIMER_DMA_BASE_CCR1 = TIMER_DCR_DBA_CCR1, /**< Base is capture/compare
+ register 1 */
+ TIMER_DMA_BASE_CCR2 = TIMER_DCR_DBA_CCR2, /**< Base is capture/compare
+ register 2 */
+ TIMER_DMA_BASE_CCR3 = TIMER_DCR_DBA_CCR3, /**< Base is capture/compare
+ register 3 */
+ TIMER_DMA_BASE_CCR4 = TIMER_DCR_DBA_CCR4, /**< Base is capture/compare
+ register 4 */
+ TIMER_DMA_BASE_BDTR = TIMER_DCR_DBA_BDTR, /**< Base is break and
+ dead-time register */
+ TIMER_DMA_BASE_DCR = TIMER_DCR_DBA_DCR, /**< Base is DMA control
+ register */
+ TIMER_DMA_BASE_DMAR = TIMER_DCR_DBA_DMAR /**< Base is DMA address for
+ full transfer */
+} timer_dma_base_address;
+
+/**
+ * @brief Get the timer's DMA base address.
+ *
+ * Some restrictions apply; see ST RM0008.
+ *
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @return DMA base address
+ */
+static inline timer_dma_base_address
+timer_get_dma_base_address(timer_dev *dev) {
+ uint32 dcr = (dev->regs).gen->DCR;
+ return (timer_dma_base_address)(dcr & TIMER_DCR_DBA);
+}
+
+/**
+ * @brief Set the timer's DMA base address.
+ *
+ * Some restrictions apply; see ST RM0008.
+ *
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @param dma_base DMA base address.
+ */
+static inline void
+timer_set_dma_base_address(timer_dev *dev, timer_dma_base_address dma_base) {
+ uint32 tmp = (dev->regs).gen->DCR;
+ tmp &= ~TIMER_DCR_DBA;
+ tmp |= dma_base;
+ (dev->regs).gen->DCR = tmp;
+}
+
+/**
+ * Timer output compare modes.
+ */
+typedef enum timer_oc_mode {
+ TIMER_OC_MODE_FROZEN = 0 << 4, /**< Frozen: comparison between output
+ compare register and counter has no
+ effect on the outputs. */
+ TIMER_OC_MODE_ACTIVE_ON_MATCH = 1 << 4, /**< OCxREF signal is forced
+ high when the count matches
+ the channel capture/compare
+ register. */
+ TIMER_OC_MODE_INACTIVE_ON_MATCH = 2 << 4, /**< OCxREF signal is forced
+ low when the counter matches
+ the channel capture/compare
+ register. */
+ TIMER_OC_MODE_TOGGLE = 3 << 4, /**< OCxREF toggles when counter
+ matches the cannel capture/compare
+ register. */
+ TIMER_OC_MODE_FORCE_INACTIVE = 4 << 4, /**< OCxREF is forced low. */
+ TIMER_OC_MODE_FORCE_ACTIVE = 5 << 4, /**< OCxREF is forced high. */
+ TIMER_OC_MODE_PWM_1 = 6 << 4, /**< PWM mode 1. In upcounting, channel is
+ active as long as count is less than
+ channel capture/compare register, else
+ inactive. In downcounting, channel is
+ inactive as long as count exceeds
+ capture/compare register, else
+ active. */
+ TIMER_OC_MODE_PWM_2 = 7 << 4 /**< PWM mode 2. In upcounting, channel is
+ inactive as long as count is less than
+ capture/compare register, else active.
+ In downcounting, channel is active as
+ long as count exceeds capture/compare
+ register, else inactive. */
+} timer_oc_mode;
+
+/**
+ * Timer output compare mode flags.
+ * @see timer_oc_set_mode()
+ */
+typedef enum timer_oc_mode_flags {
+ TIMER_OC_CE = BIT(7), /**< Output compare clear enable. */
+ TIMER_OC_PE = BIT(3), /**< Output compare preload enable. */
+ TIMER_OC_FE = BIT(2) /**< Output compare fast enable. */
+} timer_oc_mode_flags;
+
+/**
+ * @brief Configure a channel's output compare mode.
+ *
+ * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL.
+ * @param channel Channel to configure in output compare mode.
+ * @param flags OR of timer_oc_mode_flags.
+ * @see timer_oc_mode
+ * @see timer_oc_mode_flags
+ */
+static inline void timer_oc_set_mode(timer_dev *dev,
+ uint8 channel,
+ timer_oc_mode mode,
+ uint8 flags) {
+ uint8 bit0 = channel & 1;
+ uint8 bit1 = (channel >> 1) & 1;
+ /* channel == 1,2 -> CCMR1; channel == 3,4 -> CCMR2 */
+ __io uint32 *ccmr = &(dev->regs).gen->CCMR1 + bit1;
+ /* channel == 1,3 -> shift = 0, channel == 2,4 -> shift = 8 */
+ uint8 shift = 8 * (1 - bit0);
+
+ uint32 tmp = *ccmr;
+ tmp &= ~(0xFF << shift);
+ tmp |= (mode | flags | TIMER_CCMR_CCS_OUTPUT) << shift;
+ *ccmr = tmp;
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/libmaple/timers.c b/libmaple/timers.c
deleted file mode 100644
index c561d39..0000000
--- a/libmaple/timers.c
+++ /dev/null
@@ -1,526 +0,0 @@
-/******************************************************************************
- * The MIT License
- *
- * Copyright (c) 2010 Perry Hung.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *****************************************************************************/
-
-/**
- * @brief General timer routines
- */
-
-/* TODO: actually support timer5 and timer8 */
-
-#include "libmaple.h"
-#include "rcc.h"
-#include "nvic.h"
-#include "timers.h"
-
-/* Timer descriptor table */
-struct timer_dev timer_dev_table[] = {
- [TIMER1] = {
- .base = (timer_port*)TIMER1_BASE,
- .rcc_dev_num = RCC_TIMER1,
- .nvic_dev_num = NVIC_TIMER1
- },
- [TIMER2] = {
- .base = (timer_port*)TIMER2_BASE,
- .rcc_dev_num = RCC_TIMER2,
- .nvic_dev_num = NVIC_TIMER2
- },
- [TIMER3] = {
- .base = (timer_port*)TIMER3_BASE,
- .rcc_dev_num = RCC_TIMER3,
- .nvic_dev_num = NVIC_TIMER3
- },
- [TIMER4] = {
- .base = (timer_port*)TIMER4_BASE,
- .rcc_dev_num = RCC_TIMER4,
- .nvic_dev_num = NVIC_TIMER4
- },
-#ifdef STM32_HIGH_DENSITY
- /* High density devices only (eg, Maple Native) */
- [TIMER5] = {
- .base = (timer_port*)TIMER5_BASE,
- .rcc_dev_num = RCC_TIMER5,
- .nvic_dev_num = NVIC_TIMER5
- },
- [TIMER8] = {
- .base = (timer_port*)TIMER8_BASE,
- .rcc_dev_num = RCC_TIMER8,
- .nvic_dev_num = NVIC_TIMER8
- },
-#endif
-};
-
-/* This function should probably be rewriten to take (timer_num, mode)
- * and have prescaler set elsewhere. The mode can be passed through to
- * set_mode at the end */
-void timer_init(timer_dev_num timer_num, uint16 prescale) {
- /* TODO: doesn't catch 6+7 */
-
- timer_port *timer = timer_dev_table[timer_num].base;
- uint8 is_advanced = 0;
-
- if (timer_num == TIMER1) {
- is_advanced = 1;
- }
-#ifdef STM32_HIGH_DENSITY
- if (timer_num == TIMER8) {
- is_advanced = 1;
- }
-#endif
-
- rcc_clk_enable(timer_dev_table[timer_num].rcc_dev_num);
-
- timer->CR1 = ARPE; // No clock division
- // Do not buffer auto-reload preload
- // Edge aligned
- // Upcounter
- // Do not stop counter at update event
- // Update events enabled (etc, see bits [1:2])
- // Counter disabled for now
-
- timer->PSC = prescale; // Prescaling by prescale (duh)
- timer->ARR = 0xFFFF; // Max reload cont
-
- /* initialize all the channels to 50% duty cycle,
- * TODO: none of them actually get output unless the gpio pin
- * is set, this will probably consume a bit more power but
- * we'll worry about that later. */
- timer->CCR1 = 0x8FFF; // PWM start value
- timer->CCMR1 |= 0x68; // PWM mode 1, enable preload register.
-
- timer->CCR2 = 0x8FFF; // PWM start value
- timer->CCMR1 |= (0x68 << 8);// PWM mode 1, enable preload register.
-
- timer->CCR3 = 0x8FFF; // PWM start value
- timer->CCMR2 |= 0x68; // PWM mode 1, enable preload register.
-
- timer->CCR4 = 0x8FFF; // PWM start value
- timer->CCMR2 |= (0x68 << 8);// PWM mode 1, enable preload register.
-
- /* Advanced timer? */
- if (is_advanced) {
- timer->BDTR = 0x8000; // moe enable
- }
-
- timer->SR = 0; // clear it
- timer->DIER = 0; // disable update interrupt
- timer->EGR = 1; // Initialize update event and shadow registers
- timer->CR1 |= 1; // Enable timer
-}
-
-/* Stops the counter; the mode and settings are not modified */
-void timer_pause(timer_dev_num timer_num) {
- timer_port *timer = timer_dev_table[timer_num].base;
-
- timer->CR1 &= ~(0x0001); // CEN
-}
-
-/* Starts the counter; the mode and settings are not modified */
-void timer_resume(timer_dev_num timer_num) {
- timer_port *timer = timer_dev_table[timer_num].base;
-
- timer->CR1 |= 0x0001; // CEN
-}
-
-/* Returns the current timer counter value. Probably very inaccurate
- * if the counter is running with a low prescaler. */
-uint16 timer_get_count(timer_dev_num timer_num) {
- timer_port *timer = timer_dev_table[timer_num].base;
-
- return timer->CNT;
-}
-
-/* This function sets the counter value via register for the specified
- * timer. Can't think of specific usecases except for resetting to
- * zero but it's easy to implement and allows for "creative"
- * programming */
-void timer_set_count(timer_dev_num timer_num, uint16 value) {
- timer_port *timer = timer_dev_table[timer_num].base;
-
- timer->CNT = value;
-}
-
-/* Get the prescaler buffer value (remember, the actual prescaler
- * doesn't get set until an update event). */
-uint16 timer_get_prescaler(timer_dev_num timer_num) {
- timer_port *timer = timer_dev_table[timer_num].base;
- return timer->PSC;
-}
-
-/* Sets the prescaler */
-void timer_set_prescaler(timer_dev_num timer_num, uint16 prescale) {
- timer_port *timer = timer_dev_table[timer_num].base;
-
- timer->PSC = prescale;
-}
-
-/* Get the reload value for the entire timer. */
-uint16 timer_get_reload(timer_dev_num timer_num) {
- timer_port *timer = timer_dev_table[timer_num].base;
- return timer->ARR;
-}
-
-/* This sets the "reload" or "overflow" value for the entire timer. We
- * should probably settle on either "reload" or "overflow" to prevent
- * confusion? */
-void timer_set_reload(timer_dev_num timer_num, uint16 max_reload) {
- timer_port *timer = timer_dev_table[timer_num].base;
-
- timer->ARR = max_reload;
-}
-
-/* This quickly disables all 4 timers, presumably as part of a system shutdown
- * or similar to prevent interrupts and PWM output without 16 seperate function
- * calls to timer_set_mode */
-void timer_disable_all(void) {
- timer_port *timer;
-#ifdef STM32_HIGH_DENSITY
- timer_port *timers[6] = { (timer_port*)TIMER1_BASE,
- (timer_port*)TIMER2_BASE,
- (timer_port*)TIMER3_BASE,
- (timer_port*)TIMER4_BASE,
- (timer_port*)TIMER5_BASE,
- (timer_port*)TIMER8_BASE,
- };
- uint8 i;
- for (i = 0; i < 6; i++) {
- timer = timers[i];
- timer->CR1 = 0;
- timer->CCER = 0;
- }
-#else
- timer_port *timers[4] = { (timer_port*)TIMER1_BASE,
- (timer_port*)TIMER2_BASE,
- (timer_port*)TIMER3_BASE,
- (timer_port*)TIMER4_BASE,
- };
- uint8 i;
- for (i = 0; i < 4; i++) {
- timer = timers[i];
- timer->CR1 = 0;
- timer->CCER = 0;
- }
-#endif
-}
-
-/* Sets the mode of individual timer channels, including a DISABLE mode */
-void timer_set_mode(timer_dev_num timer_num, uint8 channel, TimerMode mode) {
- timer_port *timer = timer_dev_table[timer_num].base;
- ASSERT(channel >= 1);
-
- switch(mode) {
- case TIMER_DISABLED:
- /* Disable the channel
- * Disable any interrupt
- * Clear interrupt SR? (TODO) */
- timer->DIER &= ~(1 << channel); // 1-indexed compare nums
- timer_detach_interrupt(timer_num, channel);
- timer->CCER &= ~(1 << (4*(channel - 1))); // 0-indexed
- break;
- case TIMER_PWM:
- /* Set CCMR mode
- * Keep existing reload value
- * Disable any interrupt
- * Clear interrupt SR? (TODO)
- * Enable channel */
- timer->DIER &= ~(1 << channel); // 1-indexed compare nums
- switch (channel) {
- case 1:
- timer->CCMR1 &= ~(0xFF);
- timer->CCMR1 |= 0x68; // PWM mode 1, enable preload register.
- break;
- case 2:
- timer->CCMR1 &= ~(0xFF00);
- timer->CCMR1 |= (0x68 << 8);// PWM mode 1, enable preload register.
- break;
- case 3:
- timer->CCMR2 &= ~(0xFF);
- timer->CCMR2 |= 0x68; // PWM mode 1, enable preload register.
- break;
- case 4:
- timer->CCMR2 &= ~(0xFF00);
- timer->CCMR2 |= (0x68 << 8);// PWM mode 1, enable preload register.
- break;
- default:
- ASSERT(0);
- }
- timer->CCER |= (1 << (4*(channel - 1))); // Enable
- break;
- case TIMER_OUTPUTCOMPARE:
- /* Set CCMR mode
- * Keep existing reload value
- * Don't modify interrupt (needs to be attached to enable)
- * Clear interrupt SR? (TODO)
- * Enable channel */
- switch (channel) {
- case 1:
- timer->CCMR1 &= ~(0xFF);
- timer->CCMR1 |= 0x0010; // PWM mode 1, enable preload register.
- break;
- case 2:
- timer->CCMR1 &= ~(0xFF00);
- timer->CCMR1 |= 0x1000; // PWM mode 1, enable preload register.
- break;
- case 3:
- timer->CCMR2 &= ~(0xFF);
- timer->CCMR2 |= 0x0010; // PWM mode 1, enable preload register.
- break;
- case 4:
- timer->CCMR2 &= ~(0xFF00);
- timer->CCMR2 |= 0x1000; // PWM mode 1, enable preload register.
- break;
- default:
- ASSERT(0);
- }
- timer->CCER |= (1 << (4*(channel - 1))); // Enable
- break;
- default:
- ASSERT(0);
- }
-}
-
-uint16 timer_get_compare_value(timer_dev_num timer_num, uint8 channel_num) {
- /* faster: just read TIMERx_CHy_CCR (see timers.h) */
- ASSERT(channel_num > 0 && channel_num <= 4);
- timer_port *timer = timer_dev_table[timer_num].base;
- switch(channel_num) {
- case 1:
- return timer->CCR1;
- case 2:
- return timer->CCR2;
- case 3:
- return timer->CCR3;
- case 4:
- return timer->CCR4;
- default: /* in case ASSERT is disabled */
- return 0;
- }
-}
-
-/* This sets the compare value (aka the trigger) for a given timer
- * channel */
-void timer_set_compare_value(timer_dev_num timer_num,
- uint8 channel_num,
- uint16 value) {
- ASSERT(channel_num > 0 && channel_num <= 4);
-
- /* The faster version of this function is the inline
- timer_pwm_write_ccr */
- timer_port *timer = timer_dev_table[timer_num].base;
-
- switch(channel_num) {
- case 1:
- timer->CCR1 = value;
- break;
- case 2:
- timer->CCR2 = value;
- break;
- case 3:
- timer->CCR3 = value;
- break;
- case 4:
- timer->CCR4 = value;
- break;
- }
-}
-
-/* Stores a pointer to the passed usercode interrupt function and configures
- * the actual ISR so that it will actually be called */
-void timer_attach_interrupt(timer_dev_num timer_num,
- uint8 compare_num,
- voidFuncPtr handler) {
- ASSERT(compare_num > 0 && compare_num <= 4);
-
- timer_port *timer = timer_dev_table[timer_num].base;
-
- timer_dev_table[timer_num].handlers[compare_num-1] = handler;
- timer->DIER |= (1 << compare_num); // 1-indexed compare nums
- nvic_irq_enable(timer_dev_table[timer_num].nvic_dev_num);
-}
-
-void timer_detach_interrupt(timer_dev_num timer_num, uint8 compare_num) {
- ASSERT(compare_num > 0 && compare_num <= 4);
-
- timer_port *timer = timer_dev_table[timer_num].base;
-
- timer_dev_table[timer_num].handlers[compare_num-1] = 0;
- timer->DIER &= ~(1 << compare_num); // 1-indexed compare nums
-}
-
-void timer_generate_update(timer_dev_num timer_num) {
- /* cause update event by setting UG bit in EGR. updates prescaler
- ratio etc. */
- timer_port *timer = timer_dev_table[timer_num].base;
- timer->EGR |= 0x1;
-}
-
-/* The following are the actual interrupt handlers; 1 for each timer which must
- * determine which actual compare value (aka channel) was triggered.
- *
- * These ISRs get called when the timer interrupt is enabled, the
- * timer is running, and the timer count equals any of the CCR
- * registers /or/ has overflowed.
- *
- * This is a rather long implementation... */
-void __irq_tim1_cc(void) {
- timer_port *timer = (timer_port*)TIMER1_BASE;
- uint16 sr_buffer;
- sr_buffer = timer->SR;
-
- /* Simply switch/case-ing here doesn't work because multiple
- * CC flags may be high. */
- if(sr_buffer & 0x10){ // CC4 flag
- timer->SR &= ~(0x10);
- if(timer_dev_table[TIMER1].handlers[3]) {
- timer_dev_table[TIMER1].handlers[3]();
- }
- }
- if(sr_buffer & 0x8){ // CC3 flag
- timer->SR &= ~(0x8);
- if(timer_dev_table[TIMER1].handlers[2]) {
- timer_dev_table[TIMER1].handlers[2]();
- }
- }
- if(sr_buffer & 0x4){ // CC2 flag
- timer->SR &= ~(0x4);
- if(timer_dev_table[TIMER1].handlers[1]) {
- timer_dev_table[TIMER1].handlers[1]();
- }
- }
- if(sr_buffer & 0x2){ // CC1 flag
- timer->SR &= ~(0x2);
- if(timer_dev_table[TIMER1].handlers[0]) {
- timer_dev_table[TIMER1].handlers[0]();
- }
- }
- if(sr_buffer & 0x1){ // Update flag
- timer->SR &= ~(0x1);
- //timer->EGR = 1;
- }
-}
-void __irq_tim2(void) {
- /* This is a rather long implementation... */
- timer_port *timer = (timer_port*)TIMER2_BASE;
- uint16 sr_buffer;
- sr_buffer = timer->SR;
-
- if(sr_buffer & 0x10){ // CC4 flag
- timer->SR &= ~(0x10);
- if(timer_dev_table[TIMER2].handlers[3]) {
- timer_dev_table[TIMER2].handlers[3]();
- }
- }
- if(sr_buffer & 0x8){ // CC3 flag
- timer->SR &= ~(0x8);
- if(timer_dev_table[TIMER2].handlers[2]) {
- timer_dev_table[TIMER2].handlers[2]();
- }
- }
- if(sr_buffer & 0x4){ // CC2 flag
- timer->SR &= ~(0x4);
- if(timer_dev_table[TIMER2].handlers[1]) {
- timer_dev_table[TIMER2].handlers[1]();
- }
- }
- if(sr_buffer & 0x2){ // CC1 flag
- timer->SR &= ~(0x2);
- if(timer_dev_table[TIMER2].handlers[0]) {
- timer_dev_table[TIMER2].handlers[0]();
- }
- }
- if(sr_buffer & 0x1){ // Update flag
- timer->SR &= ~(0x1);
- //timer->EGR = 1;
- }
-}
-void __irq_tim3(void) {
- /* This is a rather long implementation... */
- timer_port *timer = (timer_port*)TIMER3_BASE;
- uint16 sr_buffer;
- sr_buffer = timer->SR;
-
- if(sr_buffer & 0x10){ // CC4 flag
- timer->SR &= ~(0x10);
- if(timer_dev_table[TIMER3].handlers[3]) {
- timer_dev_table[TIMER3].handlers[3]();
- }
- }
- if(sr_buffer & 0x8){ // CC3 flag
- timer->SR &= ~(0x8);
- if(timer_dev_table[TIMER3].handlers[2]) {
- timer_dev_table[TIMER3].handlers[2]();
- }
- }
- if(sr_buffer & 0x4){ // CC2 flag
- timer->SR &= ~(0x4);
- if(timer_dev_table[TIMER3].handlers[1]) {
- timer_dev_table[TIMER3].handlers[1]();
- }
- }
- if(sr_buffer & 0x2){ // CC1 flag
- timer->SR &= ~(0x2);
- if(timer_dev_table[TIMER3].handlers[0]) {
- timer_dev_table[TIMER3].handlers[0]();
- }
- }
- if(sr_buffer & 0x1){ // Update flag
- timer->SR &= ~(0x1);
- //timer->EGR = 1;
- }
-}
-
-void __irq_tim4(void) {
- /* This is a rather long implementation... */
- timer_port*timer = (timer_port*)TIMER4_BASE;
- uint16 sr_buffer;
- sr_buffer = timer->SR;
-
- if(sr_buffer & 0x10){ // CC4 flag
- timer->SR &= ~(0x10);
- if(timer_dev_table[TIMER4].handlers[3]) {
- timer_dev_table[TIMER4].handlers[3]();
- }
- }
- if(sr_buffer & 0x8){ // CC3 flag
- timer->SR &= ~(0x8);
- if(timer_dev_table[TIMER4].handlers[2]) {
- timer_dev_table[TIMER4].handlers[2]();
- }
- }
- if(sr_buffer & 0x4){ // CC2 flag
- timer->SR &= ~(0x4);
- if(timer_dev_table[TIMER4].handlers[1]) {
- timer_dev_table[TIMER4].handlers[1]();
- }
- }
- if(sr_buffer & 0x2){ // CC1 flag
- timer->SR &= ~(0x2);
- if(timer_dev_table[TIMER4].handlers[0]) {
- timer_dev_table[TIMER4].handlers[0]();
- }
- }
- if(sr_buffer & 0x1){ // Update flag
- timer->SR &= ~(0x1);
- //timer->EGR = 1;
- }
-}
diff --git a/libmaple/timers.h b/libmaple/timers.h
deleted file mode 100644
index 1f6afcd..0000000
--- a/libmaple/timers.h
+++ /dev/null
@@ -1,435 +0,0 @@
-/******************************************************************************
- * The MIT License
- *
- * Copyright (c) 2010 Perry Hung.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *****************************************************************************/
-
-/**
- * @file timers.h
- *
- * @brief Timer prototypes and various definitions
- */
-
-/* Note to self:
- * The timer clock frequencies are automatically fixed by hardware.
- * There are two cases:
- * 1. if the APB prescaler is 1, the timer clock frequencies are
- * set to the same frequency as that of the APB domain to which
- * the timers are connected.
- * 2. otherwise, they are set to twice (x2) the frequency of the
- * APB domain to which the timers are connected.
- * See stm32 manual, 77/995
- *
- * hence, 72 mhz timers
- */
-
-/* Maple Timer channels:
- * Timer Maple Pin STM32 Pin Type
- * TIM1_CH1 D6 PA8 Advanced
- * TIM1_CH2 D7 PA9 Advanced
- * TIM1_CH3 D8 PA10 Advanced
- *
- * TIM2_CH1 D2 PA0
- * TIM2_CH2 D3 PA1
- * TIM2_CH3 D1 PA2
- * TIM2_CH4 D0 PA3
- *
- * TIM3_CH1 D12 PA6
- * TIM3_CH2 D11 PA7
- * TIM3_CH3 EXT7 PB0
- * TIM3_CH4 EXT8 PB1
- *
- * TIM4_CH1 EXT5 PB6
- * TIM4_CH1 EXT9 PB7
- * TIM4_CH1 EXT15 PB8
- * TIM4_CH1 EXT4 PB9
- *
- * Not supported:
- * TIM1_CH4 USBDM, not available PA11 Advanced
- * TIM1_CH1_N EXT12 PB13
- * TIM1_CH2_N EXT13 PB14
- * TIM1_CH3_N EXT14 PB15
- * */
-
-/* I don't like the Arduino API for dealing with pin modes.
- * How about...
- *
- * pinMode(digitalPin, PWM);
- * pwmWrite(digitalPin) */
-
-#ifndef _TIMERS_H_
-#define _TIMERS_H_
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-
-typedef volatile uint16* TimerCCR;
-
-#define TIMER1_BASE 0x40012C00
-#define TIMER2_BASE 0x40000000
-#define TIMER3_BASE 0x40000400
-#define TIMER4_BASE 0x40000800
-#define TIMER5_BASE 0x40000C00 // High-density devices only
-#define TIMER6_BASE 0x40001000 // High-density devices only
-#define TIMER7_BASE 0x40001400 // High-density devices only
-#define TIMER8_BASE 0x40013400 // High-density devices only
-
-#define ARPE BIT(7) // Auto-reload preload enable
-#define NOT_A_TIMER 0
-
-#define TIMER_CCR(NUM,CHAN) (TIMER ## NUM ## _CH ## CHAN ## _CRR)
-
-/* Timers 1-4 are present on the entire STM32 line. */
-
-#define TIMER1_CH1_CCR ((TimerCCR)(TIMER1_BASE + 0x34))
-#define TIMER1_CH2_CCR ((TimerCCR)(TIMER1_BASE + 0x38))
-#define TIMER1_CH3_CCR ((TimerCCR)(TIMER1_BASE + 0x3C))
-#define TIMER1_CH4_CCR ((TimerCCR)(TIMER1_BASE + 0x40))
-
-#define TIMER2_CH1_CCR ((TimerCCR)(TIMER2_BASE + 0x34))
-#define TIMER2_CH2_CCR ((TimerCCR)(TIMER2_BASE + 0x38))
-#define TIMER2_CH3_CCR ((TimerCCR)(TIMER2_BASE + 0x3C))
-#define TIMER2_CH4_CCR ((TimerCCR)(TIMER2_BASE + 0x40))
-
-#define TIMER3_CH1_CCR ((TimerCCR)(TIMER3_BASE + 0x34))
-#define TIMER3_CH2_CCR ((TimerCCR)(TIMER3_BASE + 0x38))
-#define TIMER3_CH3_CCR ((TimerCCR)(TIMER3_BASE + 0x3C))
-#define TIMER3_CH4_CCR ((TimerCCR)(TIMER3_BASE + 0x40))
-
-#define TIMER4_CH1_CCR ((TimerCCR)(TIMER4_BASE + 0x34))
-#define TIMER4_CH2_CCR ((TimerCCR)(TIMER4_BASE + 0x38))
-#define TIMER4_CH3_CCR ((TimerCCR)(TIMER4_BASE + 0x3C))
-#define TIMER4_CH4_CCR ((TimerCCR)(TIMER4_BASE + 0x40))
-
-/* Timers 5 and 8 are in high-density devices only (such as Maple
- Native). Timers 6 and 7 in these devices have no output compare
- pins. */
-
-#define TIMER5_CH1_CCR ((TimerCCR)(TIMER5_BASE + 0x34))
-#define TIMER5_CH2_CCR ((TimerCCR)(TIMER5_BASE + 0x38))
-#define TIMER5_CH3_CCR ((TimerCCR)(TIMER5_BASE + 0x3C))
-#define TIMER5_CH4_CCR ((TimerCCR)(TIMER5_BASE + 0x40))
-
-#define TIMER8_CH1_CCR ((TimerCCR)(TIMER8_BASE + 0x34))
-#define TIMER8_CH2_CCR ((TimerCCR)(TIMER8_BASE + 0x38))
-#define TIMER8_CH3_CCR ((TimerCCR)(TIMER8_BASE + 0x3C))
-#define TIMER8_CH4_CCR ((TimerCCR)(TIMER8_BASE + 0x40))
-
-/**
- * Used to configure the behavior of a timer.
- */
-typedef enum TimerMode {
- TIMER_DISABLED, /**< In this mode, the timer stops counting,
- interrupts are not called, and no state changes
- are output. */
- TIMER_PWM, /**< This is the default mode for pins after
- initialization. */
- TIMER_OUTPUTCOMPARE, /**< In this mode, the timer counts from 0 to
- its reload value repeatedly; every time
- the counter value reaches one of the
- channel compare values, the corresponding
- interrupt is fired. */
-} TimerMode;
-
-typedef struct {
- /* Fields up to ARR common to general purpose (2,3,4,5), advanced
- control (1,8) and basic (6, 7) timers: */
- volatile uint16 CR1;
- uint16 RESERVED0;
- volatile uint16 CR2;
- uint16 RESERVED1;
- volatile uint16 SMCR;
- uint16 RESERVED2;
- volatile uint16 DIER;
- uint16 RESERVED3;
- volatile uint16 SR;
- uint16 RESERVED4;
- volatile uint16 EGR;
- uint16 RESERVED5;
- volatile uint16 CCMR1;
- uint16 RESERVED6;
- volatile uint16 CCMR2;
- uint16 RESERVED7;
- volatile uint16 CCER;
- uint16 RESERVED8;
- volatile uint16 CNT;
- uint16 RESERVED9;
- volatile uint16 PSC;
- uint16 RESERVED10;
- volatile uint16 ARR;
- uint16 RESERVED11;
- /* Basic timers have none of the following: */
- volatile uint16 RCR; /* Advanced control timers only */
- uint16 RESERVED12; /* Advanced control timers only */
- volatile uint16 CCR1;
- uint16 RESERVED13;
- volatile uint16 CCR2;
- uint16 RESERVED14;
- volatile uint16 CCR3;
- uint16 RESERVED15;
- volatile uint16 CCR4;
- uint16 RESERVED16;
- volatile uint16 BDTR; /* Advanced control timers only */
- uint16 RESERVED17; /* Advanced control timers only */
- volatile uint16 DCR;
- uint16 RESERVED18;
- volatile uint16 DMAR;
- uint16 RESERVED19;
-} timer_port;
-
-/**
- * Timer device numbers. See STM32 reference manual, chapters 13-15.
- */
-/* several locations depend on TIMER1=0, etc.; don't change the
- enumerator values to start at 1. */
-typedef enum {
- TIMER1, /*< Advanced control timer TIM1 */
- TIMER2, /*< General purpose timer TIM2 */
- TIMER3, /*< General purpose timer TIM3 */
- TIMER4, /*< General purpose timer TIM4 */
-#ifdef STM32_HIGH_DENSITY
- TIMER5, /*< General purpose timer TIM5; high density only */
- /* FIXME maple native: put timers 6 and 7 back in and make the
- corresponding changes to timers.c */
- /* TIMER6, /\*< Basic timer TIM6; high density only *\/ */
- /* TIMER7, /\*< Basic timer TIM7; high density only *\/ */
- TIMER8, /*< Advanced control timer TIM8; high density only */
-#endif
- TIMER_INVALID /* FIXME: this is starting to seem like a bad idea */
-} timer_dev_num;
-
-/* timer descriptor */
-struct timer_dev {
- timer_port *base;
- const uint8 rcc_dev_num;
- const uint8 nvic_dev_num;
- volatile voidFuncPtr handlers[4];
-};
-
-extern struct timer_dev timer_dev_table[];
-
-/**
- * Initializes timer with prescale as the clock divisor.
- *
- * @param timer_num Timer number.
- *
- * @param prescale value in the range 1--65535 to use as a prescaler
- * for timer counter increment frequency.
- *
- * @see timer_dev_num
- * @see timer_set_prescaler()
- * @see timer_set_mode()
- */
-void timer_init(timer_dev_num timer_num, uint16 prescale);
-
-/**
- * Quickly disable all timers. Calling this function is faster than,
- * e.g., calling timer_set_mode() for all available timers/channels.
- */
-void timer_disable_all(void);
-
-/**
- * Returns the timer's counter value. Due to function call overhead,
- * this value is likely to be inaccurate if the counter is running
- * with a low prescaler.
- *
- * @param timer_num the timer whose counter to return.
- *
- * @pre Timer has been initialized.
- */
-uint16 timer_get_count(timer_dev_num timer_num);
-
-/**
- * Sets the counter value for the given timer.
- *
- * @param timer_num the timer whose counter to set.
- *
- * @param value the new counter value.
- *
- * @pre Timer has been initialized.
- */
-void timer_set_count(timer_dev_num timer_num, uint16 value);
-
-/**
- * Stops the timer's counter from incrementing. Does not modify the
- * timer's mode or settings.
- *
- * @param timer_num the timer to pause.
- *
- * @see timer_resume()
- *
- * @pre Timer has been initialized.
- */
-void timer_pause(timer_dev_num timer_num);
-
-/**
- * Starts the counter for the given timer. Does not modify the
- * timer's mode or settings. The timer will begin counting on the
- * first rising clock cycle after it has been re-enabled using this
- * function.
- *
- * @param timer_num the timer to resume.
- *
- * @see timer_pause()
- *
- * @pre Timer has been initialized.
- */
-void timer_resume(timer_dev_num timer_num);
-
-/**
- * Returns the prescaler for the given timer.
- *
- * @param timer_num the timer whose prescaler to return.
- *
- * @see timer_set_prescaler()
- *
- * @pre Timer has been initialized.
- */
-uint16 timer_get_prescaler(timer_dev_num timer_num);
-
-/**
- * Sets the prescaler for the given timer. This value goes into the
- * PSC register, so it's 0-based (i.e., a prescale of 0 counts 1 tick
- * per clock cycle). This prescale does not take effect until the
- * next update event.
- *
- * @param timer_num the timer whose prescaler to set.
- *
- * @param prescale the new prescaler.
- *
- * @pre Timer has been initialized.
- */
-void timer_set_prescaler(timer_dev_num timer_num, uint16 prescale);
-
-/**
- * Gets the reload value for the timer.
- *
- * @see timer_set_reload()
- *
- * @pre Timer has been initialized.
- */
-uint16 timer_get_reload(timer_dev_num timer_num);
-
-/**
- * Sets the reload value for the timer.
- *
- * After this function returns, the timer's counter will reset to 0
- * after it has reached the value max_reload.
- *
- * @pre Timer has been initialized.
- */
-void timer_set_reload(timer_dev_num timer_num, uint16 max_reload);
-
-/* TODO: timer_get_mode */
-
-/**
- * Set the mode of an individual timer channel.
- *
- * @see timer_disable_all()
- * @see TimerMode
- * @see timer_dev_num
- * @pre Timer has been initialized.
- */
-void timer_set_mode(timer_dev_num timer_num, uint8 channel, TimerMode mode);
-
-/**
- * Get the compare value for the given timer channel.
- * @see timer_set_compare_value()
- * @see timer_dev_num
- * @pre Timer has been initialized.
- */
-uint16 timer_get_compare_value(timer_dev_num timer_num, uint8 channel);
-
-/**
- * Sets the compare value for a given timer channel. Useful for
- * scheduling when interrupt handlers will be called.
- *
- * @see timer_attach_interrupt()
- * @see timer_detach_interrupt()
- * @see timer_set_reload()
- * @see timer_dev_num
- * @pre Timer has been initialized.
- */
-void timer_set_compare_value(timer_dev_num timer_num, uint8 channel,
- uint16 value);
-
-/**
- * Detach the interrupt handler for the given timer channel, if any.
- * After this function returns, any handler attached to the given
- * channel will no longer be called.
- *
- * @see timer_attach_interrupt()
- * @pre Timer has been initialized.
- * @see timer_dev_num
- */
-void timer_detach_interrupt(timer_dev_num timer_num, uint8 channel);
-
-/**
- * Attach an interrupt handler for the given timer and channel. The
- * given ISR, handler, will be called whenever the timer's counter
- * reaches the compare value for the given timer and channel.
- *
- * @see timer_set_compare_value()
- * @see timer_detach_interrupt()
- * @see timer_set_mode()
- * @see timer_dev_num
- * @see voidFuncPtr
- * @pre Timer has been initialized.
- * @pre The channel's mode must be set to TIMER_OUTPUTCOMPARE, or the
- * interrupt handler will not get called.
- */
-void timer_attach_interrupt(timer_dev_num timer_num, uint8 channel,
- voidFuncPtr handler);
-
-/**
- * Programmatically generate an update event on the given timer. This
- * updates the prescaler, reloads the compare value (in upcounting
- * mode, etc.).
- *
- * @pre Timer has been initialized.
- */
-void timer_generate_update(timer_dev_num timer_num);
-
-/**
- * Turn on PWM with duty_cycle.
- *
- * @param ccr TIMERx_CHn_CCR, where x ranges over timers, and n ranges
- * from 1 to 4.
- *
- * @param duty_cycle: A number between 0 and
- * timer_get_compare_value(TIMERx, y), where x and y are as above.
- *
- * @pre Pin has been set to alternate function output.
- *
- * @pre Timer has been initialized.
- */
-static inline void timer_pwm_write_ccr(TimerCCR ccr, uint16 duty_cycle) {
- *ccr = duty_cycle;
-}
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-
-#endif
-
diff --git a/libmaple/util.c b/libmaple/util.c
index 09fbecd..6b4f216 100644
--- a/libmaple/util.c
+++ b/libmaple/util.c
@@ -32,7 +32,7 @@
#include "gpio.h"
#include "nvic.h"
#include "adc.h"
-#include "timers.h"
+#include "timer.h"
/* Failed asserts send out a message on this USART. */
#ifndef ERROR_USART_NUM
diff --git a/libraries/Servo/Servo.h b/libraries/Servo/Servo.h
index 1c75618..583312e 100644
--- a/libraries/Servo/Servo.h
+++ b/libraries/Servo/Servo.h
@@ -28,6 +28,7 @@
#include <stdint.h>
#include "wirish.h" /* hack for IDE compile */
+#include "HardwareTimer.h"
/* Note on Arduino compatibility:
diff --git a/notes/portable.txt b/notes/portable.txt
index 69952d7..cc1f2ac 100644
--- a/notes/portable.txt
+++ b/notes/portable.txt
@@ -1,98 +1,28 @@
+Board portability is implemented in boards.h, libmaple.h, and stm32.h.
-Disclaimer text: // High-density devices only (Maple Native)
+At compile time, we currently expect one of STM32_MEDIUM_DENSITY or
+STM32_HIGH_DENSITY to be defined. There's no support for low-density
+chips. XL-density isn't in the near horizon; patches welcome. You'll
+also need to define some BOARD_foo if you expect to use Wirish; this
+comes along with some additional assumptions about your board's layout.
+The code in usb/ is not very portable at all right now; expect this to
+change in the future, but for now, we're focusing on rolling out a
+more complete backend.
-Board portability is implemented by adding a header file to ./libmaple with the
-name of the BOARD target, and then editing libmaple.h to add this file as an
-option.
-
-A pin maple file should be added to ./notes describing the pin numbering
-
-Files to check by hand:
-# adc.c
-# adc.h
-# exc.c
-# exti.c
-# exti.h
-# flash.c
-# flash.h
-# gpio.c
-# gpio.h
-# libmaple_types.h
-# nvic.c
-# nvic.h
-# rcc.c
-# rcc.h
-# ring_buffer.h
-# rules.mk
-# spi.c
-- spi.h
-# syscalls.c
-# systick.c
-# systick.h
-# timers.c
-# timers.h
-# usart.c
-# usart.h
-# util.c
-# util.h
-# libmaple.h
-# usb/*
-
-wirish/:
-# bits.h
-# boards.h
-# cxxabi-compat.cpp
-# ext_interrupts.c
-# ext_interrupts.h
-# HardwareTimer.cpp
-# HardwareTimer.h
-# io.h
-# main.cxx
-# Print.cpp
-# Print.h
-# pwm.c
-# pwm.h
-# rules.mk
-# time.c
-# time.h
-# usb_serial.cpp
-# usb_serial.h
-# wirish_analog.c
-# wirish.c
-# wirish_digital.c
-# wirish.h
-# wirish_math.cpp
-# wirish_math.h
-# wirish_shift.c
-# WProgram.h
-- comm/
-
-
-
-ADC Notes:
- only using ADC1?
- untested
-
-EXTI Notes:
- need to update huge table in comments?
- untested
+A file should be added to ./notes describing the pin numbering of any
+new board you add.
NVIC Notes:
- I don't think NVIC_ISER3 and NVIC_ICER3 actually exist?
Only CANBUS and USB OTG use interrupts above #63, but I updated the nvic code anyways
RCC Notes:
Added some clock stuff to all boards even though they aren't usable... blah.
SPI Notes:
- SPI3 is only in XL chips so didn't really handle that
+ SPI3 is only in XL chips, so we don't handle that.
TIMER Notes:
- High-density devices add an advanced timer (TIMER8) and another normal one (TIMER5).
- TIMER6 and TIMER7 are much less useful.
- There is some partial progress towards adding timer5/timer8 functionality,
- but not much. This should probably all be rewritten.
The wirish timer implementation should be refactored to use pin numbers.
USART Notes:
diff --git a/notes/usb.txt b/notes/usb.txt
index 5e00354..9552b9f 100644
--- a/notes/usb.txt
+++ b/notes/usb.txt
@@ -1,3 +1,7 @@
+XXX
+XXX This file may be out of date!
+XXX
+
[NOTE: this is a long term proposal. The current implementation just does a
2ms TIMEOUT]
diff --git a/notes/vga.txt b/notes/vga.txt
index d75281a..43b6830 100644
--- a/notes/vga.txt
+++ b/notes/vga.txt
@@ -7,8 +7,7 @@ gpio_write_bit() is about 360ns (2.78MHz)
Writing to GPIO?_BASE is about 60ns (16.6MHz -> 18MHz)
-pwm write 0x0001 is about 30ns (33MHz) with prescaler as 1 (default)
-pwm write 0x0001 is about 14ns (72MHz) with prescaler as 0 (!)
+PWM write 0x0001 is about 14ns (72MHz) with prescaler as 0 (!)
VGA Timing
------------------------------------------------------------------------------
@@ -34,9 +33,3 @@ Crude 640x480 directions:
11 lines front porch
2 lines Vsync (low)
31 lines back porch
-
-Currently, setting vs. clearing GPIO registers seems to take a different amount
-of time? Or perhaps i'm not analyzing branching correctly. Regardless, if you
-SET 100x times then UNSET on one line, then UNSET 100x then SET the next line,
-the two changes in color will generally not line up.
-
diff --git a/wirish/boards.cpp b/wirish/boards.cpp
index 66f008f..d99b019 100644
--- a/wirish/boards.cpp
+++ b/wirish/boards.cpp
@@ -1,96 +1,56 @@
#include "boards.h"
-// think of the poor column numbers
+// For concision
#define ADCx ADC_INVALID
-#define TIMERx TIMER_INVALID
#if defined(BOARD_maple)
PinMapping PIN_MAP[NR_GPIO_PINS] = {
- /* D0/PA3 */
- {GPIOA, 3, 3, TIMER2_CH4_CCR, TIMER2, 4, AFIO_EXTI_PA},
- /* D1/PA2 */
- {GPIOA, 2, 2, TIMER2_CH3_CCR, TIMER2, 3, AFIO_EXTI_PA},
- /* D2/PA0 */
- {GPIOA, 0, 0, TIMER2_CH1_CCR, TIMER2, 1, AFIO_EXTI_PA},
- /* D3/PA1 */
- {GPIOA, 1, 1, TIMER2_CH2_CCR, TIMER2, 2, AFIO_EXTI_PA},
- /* D4/PB5 */
- {GPIOB, 5, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB},
- /* D5/PB6 */
- {GPIOB, 6, ADCx, TIMER4_CH1_CCR, TIMER4, 1, AFIO_EXTI_PB},
- /* D6/PA8 */
- {GPIOA, 8, ADCx, TIMER1_CH1_CCR, TIMER1, 1, AFIO_EXTI_PA},
- /* D7/PA9 */
- {GPIOA, 9, ADCx, TIMER1_CH2_CCR, TIMER1, 2, AFIO_EXTI_PA},
- /* D8/PA10 */
- {GPIOA, 10, ADCx, TIMER1_CH3_CCR, TIMER1, 3, AFIO_EXTI_PA},
- /* D9/PB7 */
- {GPIOB, 7, ADCx, TIMER4_CH2_CCR, TIMER4, 2, AFIO_EXTI_PB},
- /* D10/PA4 */
- {GPIOA, 4, 4, 0, TIMERx, TIMERx, AFIO_EXTI_PA},
- /* D11/PA7 */
- {GPIOA, 7, 7, TIMER3_CH2_CCR, TIMER3, 2, AFIO_EXTI_PA},
- /* D12/PA6 */
- {GPIOA, 6, 6, TIMER3_CH1_CCR, TIMER3, 1, AFIO_EXTI_PA},
- /* D13/PA5 */
- {GPIOA, 5, 5, 0, TIMERx, TIMERx, AFIO_EXTI_PA},
- /* D14/PB8 */
- {GPIOB, 8, ADCx, TIMER4_CH3_CCR, TIMER4, 3, AFIO_EXTI_PB},
+ {GPIOA, 3, 3, TIMER2, 4, AFIO_EXTI_PA}, /* D0/PA3 */
+ {GPIOA, 2, 2, TIMER2, 3, AFIO_EXTI_PA}, /* D1/PA2 */
+ {GPIOA, 0, 0, TIMER2, 1, AFIO_EXTI_PA}, /* D2/PA0 */
+ {GPIOA, 1, 1, TIMER2, 2, AFIO_EXTI_PA}, /* D3/PA1 */
+ {GPIOB, 5, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D4/PB5 */
+ {GPIOB, 6, ADCx, TIMER4, 1, AFIO_EXTI_PB}, /* D5/PB6 */
+ {GPIOA, 8, ADCx, TIMER1, 1, AFIO_EXTI_PA}, /* D6/PA8 */
+ {GPIOA, 9, ADCx, TIMER1, 2, AFIO_EXTI_PA}, /* D7/PA9 */
+ {GPIOA, 10, ADCx, TIMER1, 3, AFIO_EXTI_PA}, /* D8/PA10 */
+ {GPIOB, 7, ADCx, TIMER4, 2, AFIO_EXTI_PB}, /* D9/PB7 */
+ {GPIOA, 4, 4, NULL, 0, AFIO_EXTI_PA}, /* D10/PA4 */
+ {GPIOA, 7, 7, TIMER3, 2, AFIO_EXTI_PA}, /* D11/PA7 */
+ {GPIOA, 6, 6, TIMER3, 1, AFIO_EXTI_PA}, /* D12/PA6 */
+ {GPIOA, 5, 5, NULL, 0, AFIO_EXTI_PA}, /* D13/PA5 (LED) */
+ {GPIOB, 8, ADCx, TIMER4, 3, AFIO_EXTI_PB}, /* D14/PB8 */
/* Little header */
- /* D15/PC0 */
- {GPIOC, 0, 10, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D16/PC1 */
- {GPIOC, 1, 11, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D17/PC2 */
- {GPIOC, 2, 12, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D18/PC3 */
- {GPIOC, 3, 13, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D19/PC4 */
- {GPIOC, 4, 14, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D20/PC5 */
- {GPIOC, 5, 15, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
+ {GPIOC, 0, 10, NULL, 0, AFIO_EXTI_PC}, /* D15/PC0 */
+ {GPIOC, 1, 11, NULL, 0, AFIO_EXTI_PC}, /* D16/PC1 */
+ {GPIOC, 2, 12, NULL, 0, AFIO_EXTI_PC}, /* D17/PC2 */
+ {GPIOC, 3, 13, NULL, 0, AFIO_EXTI_PC}, /* D18/PC3 */
+ {GPIOC, 4, 14, NULL, 0, AFIO_EXTI_PC}, /* D19/PC4 */
+ {GPIOC, 5, 15, NULL, 0, AFIO_EXTI_PC}, /* D20/PC5 */
/* External header */
- /* D21/PC13 */
- {GPIOC, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D22/PC14 */
- {GPIOC, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D23/PC15 */
- {GPIOC, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D24/PB9 */
- {GPIOB, 9, ADCx, TIMER4_CH4_CCR, TIMER4, 4, AFIO_EXTI_PB},
- /* D25/PD2 */
- {GPIOD, 2, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD},
- /* D26/PC10 */
- {GPIOC, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D27/PB0 */
- {GPIOB, 0, 8, TIMER3_CH3_CCR, TIMER3, 3, AFIO_EXTI_PB},
- /* D28/PB1 */
- {GPIOB, 1, 9, TIMER3_CH4_CCR, TIMER3, 4, AFIO_EXTI_PB},
- /* D29/PB10 */
- {GPIOB, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB},
- /* D30/PB11 */
- {GPIOB, 11, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB},
- /* D31/PB12 */
- {GPIOB, 12, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB},
- /* D32/PB13 */
- {GPIOB, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB},
- /* D33/PB14 */
- {GPIOB, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB},
- /* D34/PB15 */
- {GPIOB, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB},
- /* D35/PC6 */
- {GPIOC, 6, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D36/PC7 */
- {GPIOC, 7, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D37/PC8 */
- {GPIOC, 8, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D38/PC9 (BUT) */
- {GPIOC, 9, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}
+ {GPIOC, 13, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D21/PC13 */
+ {GPIOC, 14, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D22/PC14 */
+ {GPIOC, 15, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D23/PC15 */
+ {GPIOB, 9, ADCx, TIMER4, 4, AFIO_EXTI_PB}, /* D24/PB9 */
+ {GPIOD, 2, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D25/PD2 */
+ {GPIOC, 10, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D26/PC10 */
+ {GPIOB, 0, 8, TIMER3, 3, AFIO_EXTI_PB}, /* D27/PB0 */
+ {GPIOB, 1, 9, TIMER3, 4, AFIO_EXTI_PB}, /* D28/PB1 */
+ {GPIOB, 10, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D29/PB10 */
+ {GPIOB, 11, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D30/PB11 */
+ {GPIOB, 12, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D31/PB12 */
+ {GPIOB, 13, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D32/PB13 */
+ {GPIOB, 14, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D33/PB14 */
+ {GPIOB, 15, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D34/PB15 */
+ {GPIOC, 6, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D35/PC6 */
+ {GPIOC, 7, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D36/PC7 */
+ {GPIOC, 8, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D37/PC8 */
+ {GPIOC, 9, ADCx, NULL, 0, AFIO_EXTI_PC} /* D38/PC9 (BUT) */
};
#elif defined(BOARD_maple_native)
@@ -98,375 +58,207 @@ PinMapping PIN_MAP[NR_GPIO_PINS] = {
PinMapping PIN_MAP[NR_GPIO_PINS] = {
/* Top header */
- /* D0/PB10 */
- {GPIOB, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB},
- /* D1/PB2 */
- {GPIOB, 2, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB},
- /* D2/PB12 */
- {GPIOB, 12, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB},
- /* D3/PB13 */
- {GPIOB, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB},
- /* D4/PB14 */
- {GPIOB, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB},
- /* D5/PB15 */
- {GPIOB, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB},
- /* D6/PC0 */
- {GPIOC, 0, 10, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D7/PC1 */
- {GPIOC, 1, 11, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D8/PC2 */
- {GPIOC, 2, 12, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D9/PC3 */
- {GPIOC, 3, 13, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D10/PC4 */
- {GPIOC, 4, 14, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D11/PC5 */
- {GPIOC, 5, 15, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D12/PC6 */
- {GPIOC, 6, ADCx, TIMER8_CH1_CCR, TIMER8, 1, AFIO_EXTI_PC},
- /* D13/PC7 */
- {GPIOC, 7, ADCx, TIMER8_CH2_CCR, TIMER8, 2, AFIO_EXTI_PC},
- /* D14/PC8 */
- {GPIOC, 8, ADCx, TIMER8_CH3_CCR, TIMER8, 3, AFIO_EXTI_PC},
- /* D15/PC9 */
- {GPIOC, 9, ADCx, TIMER8_CH4_CCR, TIMER8, 4, AFIO_EXTI_PC},
- /* D16/PC10 */
- {GPIOC, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D17/PC11 */
- {GPIOC, 11, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D18/PC12 */
- {GPIOC, 12, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D19/PC13 */
- {GPIOC, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D20/PC14 */
- {GPIOC, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D21/PC15 */
- {GPIOC, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D22/PA8 */
- {GPIOA, 8, ADCx, TIMER1_CH1_CCR, TIMER1, 1, AFIO_EXTI_PA},
- /* D23/PA9 */
- {GPIOA, 9, ADCx, TIMER1_CH2_CCR, TIMER1, 2, AFIO_EXTI_PA},
- /* D24/PA10 */
- {GPIOA, 10, ADCx, TIMER1_CH3_CCR, TIMER1, 3, AFIO_EXTI_PA},
- /* D25/PB9 */
- {GPIOB, 9, ADCx, TIMER4_CH4_CCR, TIMER4, 4, AFIO_EXTI_PB},
+ {GPIOB, 10, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D0/PB10 */
+ {GPIOB, 2, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D1/PB2 */
+ {GPIOB, 12, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D2/PB12 */
+ {GPIOB, 13, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D3/PB13 */
+ {GPIOB, 14, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D4/PB14 */
+ {GPIOB, 15, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D5/PB15 */
+ {GPIOC, 0, 10, NULL, 0, AFIO_EXTI_PC}, /* D6/PC0 */
+ {GPIOC, 1, 11, NULL, 0, AFIO_EXTI_PC}, /* D7/PC1 */
+ {GPIOC, 2, 12, NULL, 0, AFIO_EXTI_PC}, /* D8/PC2 */
+ {GPIOC, 3, 13, NULL, 0, AFIO_EXTI_PC}, /* D9/PC3 */
+ {GPIOC, 4, 14, NULL, 0, AFIO_EXTI_PC}, /* D10/PC4 */
+ {GPIOC, 5, 15, NULL, 0, AFIO_EXTI_PC}, /* D11/PC5 */
+ {GPIOC, 6, ADCx, TIMER8, 1, AFIO_EXTI_PC}, /* D12/PC6 */
+ {GPIOC, 7, ADCx, TIMER8, 2, AFIO_EXTI_PC}, /* D13/PC7 */
+ {GPIOC, 8, ADCx, TIMER8, 3, AFIO_EXTI_PC}, /* D14/PC8 */
+ {GPIOC, 9, ADCx, TIMER8, 4, AFIO_EXTI_PC}, /* D15/PC9 */
+ {GPIOC, 10, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D16/PC10 */
+ {GPIOC, 11, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D17/PC11 */
+ {GPIOC, 12, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D18/PC12 */
+ {GPIOC, 13, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D19/PC13 */
+ {GPIOC, 14, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D20/PC14 */
+ {GPIOC, 15, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D21/PC15 */
+ {GPIOA, 8, ADCx, TIMER1, 1, AFIO_EXTI_PA}, /* D22/PA8 */
+ {GPIOA, 9, ADCx, TIMER1, 2, AFIO_EXTI_PA}, /* D23/PA9 */
+ {GPIOA, 10, ADCx, TIMER1, 3, AFIO_EXTI_PA}, /* D24/PA10 */
+ {GPIOB, 9, ADCx, TIMER4, 4, AFIO_EXTI_PB}, /* D25/PB9 */
/* Bottom header */
+ /* FIXME (?) What about D48--D50 also being TIMER2_CH[234]? */
- /* D26/PD2 */
- {GPIOD, 2, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD},
- /* D27/PD3 */
- {GPIOD, 3, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD},
- /* D28/PD6 */
- {GPIOD, 6, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD},
- /* D29/PG11 */
- {GPIOG, 11, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG},
- /* D30/PG12 */
- {GPIOG, 12, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG},
- /* D31/PG13 */
- {GPIOG, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG},
- /* D32/PG14 */
- {GPIOG, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG},
- /* D33/PG8 */
- {GPIOG, 8, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG},
- /* D34/PG7 */
- {GPIOG, 7, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG},
- /* D35/PG6 */
- {GPIOG, 6, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG},
- /* D36/PB5 */
- {GPIOB, 5, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB},
- /* D37/PB6 */
- {GPIOB, 6, ADCx, TIMER4_CH1_CCR, TIMER4, 1, AFIO_EXTI_PB},
- /* D38/PB7 */
- {GPIOB, 7, ADCx, TIMER4_CH2_CCR, TIMER4, 2, AFIO_EXTI_PB},
- /* D39/PF6 */
- {GPIOF, 6, 4, 0, TIMERx, TIMERx, AFIO_EXTI_PF},
- /* D40/PF7 */
- {GPIOF, 7, 5, 0, TIMERx, TIMERx, AFIO_EXTI_PF},
- /* D41/PF8 */
- {GPIOF, 8, 6, 0, TIMERx, TIMERx, AFIO_EXTI_PF},
- /* D42/PF9 */
- {GPIOF, 9, 7, 0, TIMERx, TIMERx, AFIO_EXTI_PF},
- /* D43/PF10 */
- {GPIOF, 10, 8, 0, TIMERx, TIMERx, AFIO_EXTI_PF},
- /* D44/PF11 */
- {GPIOF, 11, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF},
- /* D45/PB1 */
- {GPIOB, 1, 9, TIMER3_CH4_CCR, TIMER3, 4, AFIO_EXTI_PB},
- /* D46/PB0 */
- {GPIOB, 0, 8, TIMER3_CH3_CCR, TIMER3, 3, AFIO_EXTI_PB},
- /* D47/PA0 */
- {GPIOA, 0, 0, TIMER5_CH1_CCR, TIMER5, 1, AFIO_EXTI_PA},
- /* D48/PA1 */ /* FIXME (?)
- What about D48--D50 also being TIMER2_CH[234]? */
- {GPIOA, 1, 1, TIMER5_CH2_CCR, TIMER5, 2, AFIO_EXTI_PA},
- /* D49/PA2 */
- {GPIOA, 2, 2, TIMER5_CH3_CCR, TIMER5, 3, AFIO_EXTI_PA},
- /* D50/PA3 */
- {GPIOA, 3, 3, TIMER5_CH4_CCR, TIMER5, 4, AFIO_EXTI_PA},
- /* D51/PA4 */
- {GPIOA, 4, 4, 0, TIMERx, TIMERx, AFIO_EXTI_PA},
- /* D52/PA5 */
- {GPIOA, 5, 5, 0, TIMERx, TIMERx, AFIO_EXTI_PA},
- /* D53/PA6 */
- {GPIOA, 6, 6, TIMER3_CH1_CCR, TIMER3, 1, AFIO_EXTI_PA},
- /* D54/PA7 */
- {GPIOA, 7, 7, TIMER3_CH2_CCR, TIMER3, 2, AFIO_EXTI_PA},
+ {GPIOD, 2, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D26/PD2 */
+ {GPIOD, 3, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D27/PD3 */
+ {GPIOD, 6, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D28/PD6 */
+ {GPIOG, 11, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D29/PG11 */
+ {GPIOG, 12, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D30/PG12 */
+ {GPIOG, 13, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D31/PG13 */
+ {GPIOG, 14, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D32/PG14 */
+ {GPIOG, 8, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D33/PG8 */
+ {GPIOG, 7, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D34/PG7 */
+ {GPIOG, 6, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D35/PG6 */
+ {GPIOB, 5, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D36/PB5 */
+ {GPIOB, 6, ADCx, TIMER4, 1, AFIO_EXTI_PB}, /* D37/PB6 */
+ {GPIOB, 7, ADCx, TIMER4, 2, AFIO_EXTI_PB}, /* D38/PB7 */
+ {GPIOF, 6, 4, NULL, 0, AFIO_EXTI_PF}, /* D39/PF6 */
+ {GPIOF, 7, 5, NULL, 0, AFIO_EXTI_PF}, /* D40/PF7 */
+ {GPIOF, 8, 6, NULL, 0, AFIO_EXTI_PF}, /* D41/PF8 */
+ {GPIOF, 9, 7, NULL, 0, AFIO_EXTI_PF}, /* D42/PF9 */
+ {GPIOF, 10, 8, NULL, 0, AFIO_EXTI_PF}, /* D43/PF10 */
+ {GPIOF, 11, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D44/PF11 */
+ {GPIOB, 1, 9, TIMER3, 4, AFIO_EXTI_PB}, /* D45/PB1 */
+ {GPIOB, 0, 8, TIMER3, 3, AFIO_EXTI_PB}, /* D46/PB0 */
+ {GPIOA, 0, 0, TIMER5, 1, AFIO_EXTI_PA}, /* D47/PA0 */
+ {GPIOA, 1, 1, TIMER5, 2, AFIO_EXTI_PA}, /* D48/PA1 */
+ {GPIOA, 2, 2, TIMER5, 3, AFIO_EXTI_PA}, /* D49/PA2 */
+ {GPIOA, 3, 3, TIMER5, 4, AFIO_EXTI_PA}, /* D50/PA3 */
+ {GPIOA, 4, 4, NULL, 0, AFIO_EXTI_PA}, /* D51/PA4 */
+ {GPIOA, 5, 5, NULL, 0, AFIO_EXTI_PA}, /* D52/PA5 */
+ {GPIOA, 6, 6, TIMER3, 1, AFIO_EXTI_PA}, /* D53/PA6 */
+ {GPIOA, 7, 7, TIMER3, 2, AFIO_EXTI_PA}, /* D54/PA7 */
/* Right (triple) header */
- /* D55/PF0 */
- {GPIOF, 0, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF},
- /* D56/PD11 */
- {GPIOD, 11, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD},
- /* D57/PD14 */
- {GPIOD, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD},
- /* D58/PF1 */
- {GPIOF, 1, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF},
- /* D59/PD12 */
- {GPIOD, 12, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD},
- /* D60/PD15 */
- {GPIOD, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD},
- /* D61/PF2 */
- {GPIOF, 2, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF},
- /* D62/PD13 */
- {GPIOD, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD},
- /* D63/PD0 */
- {GPIOD, 0, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD},
- /* D64/PF3 */
- {GPIOF, 3, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF},
- /* D65/PE3 */
- {GPIOE, 3, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE},
- /* D66/PD1 */
- {GPIOD, 1, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD},
- /* D67/PF4 */
- {GPIOF, 4, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF},
- /* D68/PE4 */
- {GPIOE, 4, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE},
- /* D69/PE7 */
- {GPIOE, 7, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE},
- /* D70/PF5 */
- {GPIOF, 5, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF},
- /* D71/PE5 */
- {GPIOE, 5, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE},
- /* D72/PE8 */
- {GPIOE, 8, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE},
- /* D73/PF12 */
- {GPIOF, 12, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF},
- /* D74/PE6 */
- {GPIOE, 6, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE},
- /* D75/PE9 */
- {GPIOE, 9, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE},
- /* D76/PF13 */
- {GPIOF, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF},
- /* D77/PE10 */
- {GPIOE, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE},
- /* D78/PF14 */
- {GPIOF, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF},
- /* D79/PG9 */
- {GPIOG, 9, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG},
- /* D80/PE11 */
- {GPIOE, 11, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE},
- /* D81/PF15 */
- {GPIOF, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF},
- /* D82/PG10 */
- {GPIOG, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG},
- /* D83/PE12 */
- {GPIOE, 12, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE},
- /* D84/PG0 */
- {GPIOG, 0, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG},
- /* D85/PD5 */
- {GPIOD, 5, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD},
- /* D86/PE13 */
- {GPIOE, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE},
- /* D87/PG1 */
- {GPIOG, 1, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG},
- /* D88/PD4 */
- {GPIOD, 4, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD},
- /* D89/PE14 */
- {GPIOE, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE},
- /* D90/PG2 */
- {GPIOG, 2, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG},
- /* D91/PE1 */
- {GPIOE, 1, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE},
- /* D92/PE15 */
- {GPIOE, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE},
- /* D93/PG3 */
- {GPIOG, 3, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG},
- /* D94/PE0 */
- {GPIOE, 0, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE},
- /* D95/PD8 */
- {GPIOD, 8, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD},
- /* D96/PG4 */
- {GPIOG, 4, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG},
- /* D97/PD9 */
- {GPIOD, 9, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD},
- /* D98/PG5 */
- {GPIOG, 5, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG},
- /* D99/PD10 */
- {GPIOD, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}
+ {GPIOF, 0, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D55/PF0 */
+ {GPIOD, 11, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D56/PD11 */
+ {GPIOD, 14, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D57/PD14 */
+ {GPIOF, 1, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D58/PF1 */
+ {GPIOD, 12, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D59/PD12 */
+ {GPIOD, 15, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D60/PD15 */
+ {GPIOF, 2, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D61/PF2 */
+ {GPIOD, 13, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D62/PD13 */
+ {GPIOD, 0, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D63/PD0 */
+ {GPIOF, 3, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D64/PF3 */
+ {GPIOE, 3, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D65/PE3 */
+ {GPIOD, 1, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D66/PD1 */
+ {GPIOF, 4, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D67/PF4 */
+ {GPIOE, 4, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D68/PE4 */
+ {GPIOE, 7, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D69/PE7 */
+ {GPIOF, 5, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D70/PF5 */
+ {GPIOE, 5, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D71/PE5 */
+ {GPIOE, 8, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D72/PE8 */
+ {GPIOF, 12, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D73/PF12 */
+ {GPIOE, 6, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D74/PE6 */
+ {GPIOE, 9, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D75/PE9 */
+ {GPIOF, 13, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D76/PF13 */
+ {GPIOE, 10, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D77/PE10 */
+ {GPIOF, 14, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D78/PF14 */
+ {GPIOG, 9, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D79/PG9 */
+ {GPIOE, 11, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D80/PE11 */
+ {GPIOF, 15, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D81/PF15 */
+ {GPIOG, 10, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D82/PG10 */
+ {GPIOE, 12, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D83/PE12 */
+ {GPIOG, 0, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D84/PG0 */
+ {GPIOD, 5, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D85/PD5 */
+ {GPIOE, 13, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D86/PE13 */
+ {GPIOG, 1, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D87/PG1 */
+ {GPIOD, 4, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D88/PD4 */
+ {GPIOE, 14, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D89/PE14 */
+ {GPIOG, 2, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D90/PG2 */
+ {GPIOE, 1, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D91/PE1 */
+ {GPIOE, 15, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D92/PE15 */
+ {GPIOG, 3, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D93/PG3 */
+ {GPIOE, 0, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D94/PE0 */
+ {GPIOD, 8, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D95/PD8 */
+ {GPIOG, 4, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D96/PG4 */
+ {GPIOD, 9, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D97/PD9 */
+ {GPIOG, 5, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D98/PG5 */
+ {GPIOD, 10, ADCx, NULL, 0, AFIO_EXTI_PD} /* D99/PD10 */
};
#elif defined(BOARD_maple_mini)
PinMapping PIN_MAP[NR_GPIO_PINS] = {
- /* D0/PB11 */
- {GPIOB, 11, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB},
- /* D1/PB10 */
- {GPIOB, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB},
- /* D2/PB2 */
- {GPIOB, 2, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB},
- /* D3/PB0 */
- {GPIOB, 0, 8, TIMER3_CH3_CCR, TIMER3, 3, AFIO_EXTI_PB},
- /* D4/PA7 */
- {GPIOA, 7, 7, TIMER3_CH2_CCR, TIMER3, 2, AFIO_EXTI_PA},
- /* D5/PA6 */
- {GPIOA, 6, 6, TIMER3_CH1_CCR, TIMER3, 1, AFIO_EXTI_PA},
- /* D6/PA5 */
- {GPIOA, 5, 5, 0, TIMERx, TIMERx, AFIO_EXTI_PA},
- /* D7/PA4 */
- {GPIOA, 4, 4, 0, TIMERx, TIMERx, AFIO_EXTI_PA},
- /* D8/PA3 */
- {GPIOA, 3, 3, TIMER2_CH4_CCR, TIMER2, 4, AFIO_EXTI_PA},
- /* D9/PA2 */
- {GPIOA, 2, 2, TIMER2_CH3_CCR, TIMER2, 3, AFIO_EXTI_PA},
- /* D10/PA1 */
- {GPIOA, 1, 1, TIMER2_CH2_CCR, TIMER2, 2, AFIO_EXTI_PA},
- /* D11/PA0 */
- {GPIOA, 0, 0, TIMER2_CH1_CCR, TIMER2, 1, AFIO_EXTI_PA},
- /* D12/PC15 */
- {GPIOC, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D13/PC14 */
- {GPIOC, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D14/PC13 */
- {GPIOC, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D15/PB7 */
- {GPIOB, 7, ADCx, TIMER4_CH2_CCR, TIMER4, 2, AFIO_EXTI_PB},
- /* D16/PB6 */
- {GPIOB, 6, ADCx, TIMER4_CH1_CCR, TIMER4, 1, AFIO_EXTI_PB},
- /* D17/PB5 */
- {GPIOB, 5, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB},
- /* D18/PB4 */
- {GPIOB, 4, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB},
- /* D19/PB3 */
- {GPIOB, 3, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB},
- /* D20/PA15 */
- {GPIOA, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PA},
- /* D21/PA14 */
- {GPIOA, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PA},
- /* D22/PA13 */
- {GPIOA, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PA},
- /* D23/PA12 */
- {GPIOA, 12, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PA},
- /* D24/PA11 */
- {GPIOA, 11, ADCx, TIMER1_CH4_CCR, TIMER1, 4, AFIO_EXTI_PA},
- /* D25/PA10 */
- {GPIOA, 10, ADCx, TIMER1_CH3_CCR, TIMER1, 3, AFIO_EXTI_PA},
- /* D26/PA9 */
- {GPIOA, 9, ADCx, TIMER1_CH2_CCR, TIMER2, 2, AFIO_EXTI_PA},
- /* D27/PA8 */
- {GPIOA, 8, ADCx, TIMER1_CH1_CCR, TIMER1, 1, AFIO_EXTI_PA},
- /* D28/PB15 */
- {GPIOB, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB},
- /* D29/PB14 */
- {GPIOB, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB},
- /* D30/PB13 */
- {GPIOB, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB},
- /* D31/PB12 */
- {GPIOB, 12, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB},
- /* D32/PB8 */
- {GPIOB, 8, ADCx, TIMER4_CH3_CCR, TIMER4, 3, AFIO_EXTI_PB},
- /* D33/PB1 */
- {GPIOB, 1, 9, TIMER3_CH4_CCR, TIMER3, 4, AFIO_EXTI_PB},
+ /* Top header */
+
+ {GPIOB, 11, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D0/PB11 */
+ {GPIOB, 10, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D1/PB10 */
+ {GPIOB, 2, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D2/PB2 */
+ {GPIOB, 0, 8, TIMER3, 3, AFIO_EXTI_PB}, /* D3/PB0 */
+ {GPIOA, 7, 7, TIMER3, 2, AFIO_EXTI_PA}, /* D4/PA7 */
+ {GPIOA, 6, 6, TIMER3, 1, AFIO_EXTI_PA}, /* D5/PA6 */
+ {GPIOA, 5, 5, NULL, 0, AFIO_EXTI_PA}, /* D6/PA5 */
+ {GPIOA, 4, 4, NULL, 0, AFIO_EXTI_PA}, /* D7/PA4 */
+ {GPIOA, 3, 3, TIMER2, 4, AFIO_EXTI_PA}, /* D8/PA3 */
+ {GPIOA, 2, 2, TIMER2, 3, AFIO_EXTI_PA}, /* D9/PA2 */
+ {GPIOA, 1, 1, TIMER2, 2, AFIO_EXTI_PA}, /* D10/PA1 */
+ {GPIOA, 0, 0, TIMER2, 1, AFIO_EXTI_PA}, /* D11/PA0 */
+ {GPIOC, 15, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D12/PC15 */
+ {GPIOC, 14, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D13/PC14 */
+ {GPIOC, 13, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D14/PC13 */
+
+ /* Bottom header */
+
+ {GPIOB, 7, ADCx, TIMER4, 2, AFIO_EXTI_PB}, /* D15/PB7 */
+ {GPIOB, 6, ADCx, TIMER4, 1, AFIO_EXTI_PB}, /* D16/PB6 */
+ {GPIOB, 5, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D17/PB5 */
+ {GPIOB, 4, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D18/PB4 */
+ {GPIOB, 3, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D19/PB3 */
+ {GPIOA, 15, ADCx, NULL, 0, AFIO_EXTI_PA}, /* D20/PA15 */
+ {GPIOA, 14, ADCx, NULL, 0, AFIO_EXTI_PA}, /* D21/PA14 */
+ {GPIOA, 13, ADCx, NULL, 0, AFIO_EXTI_PA}, /* D22/PA13 */
+ {GPIOA, 12, ADCx, NULL, 0, AFIO_EXTI_PA}, /* D23/PA12 */
+ {GPIOA, 11, ADCx, TIMER1, 4, AFIO_EXTI_PA}, /* D24/PA11 */
+ {GPIOA, 10, ADCx, TIMER1, 3, AFIO_EXTI_PA}, /* D25/PA10 */
+ {GPIOA, 9, ADCx, TIMER2, 2, AFIO_EXTI_PA}, /* D26/PA9 */
+ {GPIOA, 8, ADCx, TIMER1, 1, AFIO_EXTI_PA}, /* D27/PA8 */
+ {GPIOB, 15, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D28/PB15 */
+ {GPIOB, 14, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D29/PB14 */
+ {GPIOB, 13, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D30/PB13 */
+ {GPIOB, 12, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D31/PB12 */
+ {GPIOB, 8, ADCx, TIMER4, 3, AFIO_EXTI_PB}, /* D32/PB8 */
+ {GPIOB, 1, 9, TIMER3, 4, AFIO_EXTI_PB}, /* D33/PB1 */
};
#elif defined(BOARD_maple_RET6)
PinMapping PIN_MAP[NR_GPIO_PINS] = {
- /* D0/PA3 */
- {GPIOA, 3, 3, TIMER2_CH4_CCR, TIMER2, 4, AFIO_EXTI_PA},
- /* D1/PA2 */
- {GPIOA, 2, 2, TIMER2_CH3_CCR, TIMER2, 3, AFIO_EXTI_PA},
- /* D2/PA0 */
- {GPIOA, 0, 0, TIMER2_CH1_CCR, TIMER2, 1, AFIO_EXTI_PA},
- /* D3/PA1 */
- {GPIOA, 1, 1, TIMER2_CH2_CCR, TIMER2, 2, AFIO_EXTI_PA},
- /* D4/PB5 */
- {GPIOB, 5, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB},
- /* D5/PB6 */
- {GPIOB, 6, ADCx, TIMER4_CH1_CCR, TIMER4, 1, AFIO_EXTI_PB},
- /* D6/PA8 */
- {GPIOA, 8, ADCx, TIMER1_CH1_CCR, TIMER1, 1, AFIO_EXTI_PA},
- /* D7/PA9 */
- {GPIOA, 9, ADCx, TIMER1_CH2_CCR, TIMER1, 2, AFIO_EXTI_PA},
- /* D8/PA10 */
- {GPIOA, 10, ADCx, TIMER1_CH3_CCR, TIMER1, 3, AFIO_EXTI_PA},
- /* D9/PB7 */
- {GPIOB, 7, ADCx, TIMER4_CH2_CCR, TIMER4, 2, AFIO_EXTI_PB},
- /* D10/PA4 */
- {GPIOA, 4, 4, 0, TIMERx, TIMERx, AFIO_EXTI_PA},
- /* D11/PA7 */
- {GPIOA, 7, 7, TIMER3_CH2_CCR, TIMER3, 2, AFIO_EXTI_PA},
- /* D12/PA6 */
- {GPIOA, 6, 6, TIMER3_CH1_CCR, TIMER3, 1, AFIO_EXTI_PA},
- /* D13/PA5 */
- {GPIOA, 5, 5, 0, TIMERx, TIMERx, AFIO_EXTI_PA},
- /* D14/PB8 */
- {GPIOB, 8, ADCx, TIMER4_CH3_CCR, TIMER4, 3, AFIO_EXTI_PB},
+ {GPIOA, 3, 3, TIMER2, 4, AFIO_EXTI_PA}, /* D0/PA3 */
+ {GPIOA, 2, 2, TIMER2, 3, AFIO_EXTI_PA}, /* D1/PA2 */
+ {GPIOA, 0, 0, TIMER2, 1, AFIO_EXTI_PA}, /* D2/PA0 */
+ {GPIOA, 1, 1, TIMER2, 2, AFIO_EXTI_PA}, /* D3/PA1 */
+ {GPIOB, 5, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D4/PB5 */
+ {GPIOB, 6, ADCx, TIMER4, 1, AFIO_EXTI_PB}, /* D5/PB6 */
+ {GPIOA, 8, ADCx, TIMER1, 1, AFIO_EXTI_PA}, /* D6/PA8 */
+ {GPIOA, 9, ADCx, TIMER1, 2, AFIO_EXTI_PA}, /* D7/PA9 */
+ {GPIOA, 10, ADCx, TIMER1, 3, AFIO_EXTI_PA}, /* D8/PA10 */
+ {GPIOB, 7, ADCx, TIMER4, 2, AFIO_EXTI_PB}, /* D9/PB7 */
+ {GPIOA, 4, 4, NULL, 0, AFIO_EXTI_PA}, /* D10/PA4 */
+ {GPIOA, 7, 7, TIMER3, 2, AFIO_EXTI_PA}, /* D11/PA7 */
+ {GPIOA, 6, 6, TIMER3, 1, AFIO_EXTI_PA}, /* D12/PA6 */
+ {GPIOA, 5, 5, NULL, 0, AFIO_EXTI_PA}, /* D13/PA5 (LED) */
+ {GPIOB, 8, ADCx, TIMER4, 3, AFIO_EXTI_PB}, /* D14/PB8 */
/* Little header */
- /* D15/PC0 */
- {GPIOC, 0, 10, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D16/PC1 */
- {GPIOC, 1, 11, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D17/PC2 */
- {GPIOC, 2, 12, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D18/PC3 */
- {GPIOC, 3, 13, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D19/PC4 */
- {GPIOC, 4, 14, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D20/PC5 */
- {GPIOC, 5, 15, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
+ {GPIOC, 0, 10, NULL, 0, AFIO_EXTI_PC}, /* D15/PC0 */
+ {GPIOC, 1, 11, NULL, 0, AFIO_EXTI_PC}, /* D16/PC1 */
+ {GPIOC, 2, 12, NULL, 0, AFIO_EXTI_PC}, /* D17/PC2 */
+ {GPIOC, 3, 13, NULL, 0, AFIO_EXTI_PC}, /* D18/PC3 */
+ {GPIOC, 4, 14, NULL, 0, AFIO_EXTI_PC}, /* D19/PC4 */
+ {GPIOC, 5, 15, NULL, 0, AFIO_EXTI_PC}, /* D20/PC5 */
/* External header */
- /* D21/PC13 */
- {GPIOC, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D22/PC14 */
- {GPIOC, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D23/PC15 */
- {GPIOC, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D24/PB9 */
- {GPIOB, 9, ADCx, TIMER4_CH4_CCR, TIMER4, 4, AFIO_EXTI_PB},
- /* D25/PD2 */
- {GPIOD, 2, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD},
- /* D26/PC10 */
- {GPIOC, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC},
- /* D27/PB0 */
- {GPIOB, 0, 8, TIMER3_CH3_CCR, TIMER3, 3, AFIO_EXTI_PB},
- /* D28/PB1 */
- {GPIOB, 1, 9, TIMER3_CH4_CCR, TIMER3, 4, AFIO_EXTI_PB},
- /* D29/PB10 */
- {GPIOB, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB},
- /* D30/PB11 */
- {GPIOB, 11, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB},
- /* D31/PB12 */
- {GPIOB, 12, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB},
- /* D32/PB13 */
- {GPIOB, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB},
- /* D33/PB14 */
- {GPIOB, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB},
- /* D34/PB15 */
- {GPIOB, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB},
- /* D35/PC6 */
- {GPIOC, 6, ADCx, TIMER8_CH1_CCR, TIMER8, 1, AFIO_EXTI_PC},
- /* D36/PC7 */
- {GPIOC, 7, ADCx, TIMER8_CH1_CCR, TIMER8, 2, AFIO_EXTI_PC},
- /* D37/PC8 */
- {GPIOC, 8, ADCx, TIMER8_CH1_CCR, TIMER8, 3, AFIO_EXTI_PC},
- /* D38/PC9 (BUT) */
- {GPIOC, 9, ADCx, TIMER8_CH1_CCR, TIMER8, 4, AFIO_EXTI_PC}
+ {GPIOC, 13, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D21/PC13 */
+ {GPIOC, 14, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D22/PC14 */
+ {GPIOC, 15, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D23/PC15 */
+ {GPIOB, 9, ADCx, TIMER4, 4, AFIO_EXTI_PB}, /* D24/PB9 */
+ {GPIOD, 2, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D25/PD2 */
+ {GPIOC, 10, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D26/PC10 */
+ {GPIOB, 0, 8, TIMER3, 3, AFIO_EXTI_PB}, /* D27/PB0 */
+ {GPIOB, 1, 9, TIMER3, 4, AFIO_EXTI_PB}, /* D28/PB1 */
+ {GPIOB, 10, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D29/PB10 */
+ {GPIOB, 11, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D30/PB11 */
+ {GPIOB, 12, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D31/PB12 */
+ {GPIOB, 13, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D32/PB13 */
+ {GPIOB, 14, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D33/PB14 */
+ {GPIOB, 15, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D34/PB15 */
+ {GPIOC, 6, ADCx, TIMER8, 1, AFIO_EXTI_PC}, /* D35/PC6 */
+ {GPIOC, 7, ADCx, TIMER8, 2, AFIO_EXTI_PC}, /* D36/PC7 */
+ {GPIOC, 8, ADCx, TIMER8, 3, AFIO_EXTI_PC}, /* D37/PC8 */
+ {GPIOC, 9, ADCx, TIMER8, 4, AFIO_EXTI_PC} /* D38/PC9 (BUT) */
};
#else
diff --git a/wirish/boards.h b/wirish/boards.h
index 94566fa..d186dc4 100644
--- a/wirish/boards.h
+++ b/wirish/boards.h
@@ -33,7 +33,8 @@
#include "libmaple.h"
#include "gpio.h"
-#include "timers.h"
+#include "timer.h"
+#include "native_sram.h"
/* Set of all possible pin names; not all boards have all these (note
that we use the Dx convention since all of the Maple's pins are
@@ -56,9 +57,8 @@ typedef struct PinMapping {
gpio_dev *gpio_device;
uint32 pin;
uint32 adc_channel;
- TimerCCR timer_ccr;
- timer_dev_num timer_num;
- uint32 timer_chan;
+ timer_dev* timer_device;
+ uint8 timer_chan;
afio_exti_port ext_port;
} PinMapping;
@@ -94,6 +94,7 @@ extern PinMapping PIN_MAP[];
#define NR_GPIO_PINS 100
#define BOARD_INIT do { \
+ initNativeSRAM();
} while(0)
#elif defined(BOARD_maple_mini)
diff --git a/wirish/comm/HardwareSPI.cpp b/wirish/comm/HardwareSPI.cpp
index 20090f5..aea7734 100644
--- a/wirish/comm/HardwareSPI.cpp
+++ b/wirish/comm/HardwareSPI.cpp
@@ -47,8 +47,10 @@
* TODO: Do the complementary PWM outputs mess up SPI2?
* */
-#include "wirish.h"
#include "spi.h"
+#include "timer.h"
+
+#include "wirish.h"
#include "HardwareSPI.h"
static const uint32 prescaleFactors[MAX_SPI_FREQS] = {
diff --git a/wirish/comm/HardwareSerial.cpp b/wirish/comm/HardwareSerial.cpp
index 08252d8..97a5ec3 100644
--- a/wirish/comm/HardwareSerial.cpp
+++ b/wirish/comm/HardwareSerial.cpp
@@ -31,12 +31,10 @@
#include "wirish.h"
#include "HardwareSerial.h"
#include "usart.h"
-#include "gpio.h"
-#include "timers.h"
-HardwareSerial Serial1(USART1, 4500000UL, GPIOA, 9,10, TIMER1, 2);
-HardwareSerial Serial2(USART2, 2250000UL, GPIOA, 2, 3, TIMER2, 3);
-HardwareSerial Serial3(USART3, 2250000UL, GPIOB, 10,11, TIMER_INVALID, 0);
+HardwareSerial Serial1(USART1, 4500000UL, GPIOA, 9, 10, TIMER1, 2);
+HardwareSerial Serial2(USART2, 2250000UL, GPIOA, 2, 3, TIMER2, 3);
+HardwareSerial Serial3(USART3, 2250000UL, GPIOB, 10, 11, NULL, 0);
// TODO: High density device ports
HardwareSerial::HardwareSerial(uint8 usart_num,
@@ -44,15 +42,15 @@ HardwareSerial::HardwareSerial(uint8 usart_num,
gpio_dev *gpio_device,
uint8 tx_pin,
uint8 rx_pin,
- timer_dev_num timer_num,
- uint8 compare_num) {
+ timer_dev *timer_device,
+ uint8 channel_num) {
this->usart_num = usart_num;
this->max_baud = max_baud;
this->gpio_device = gpio_device;
this->tx_pin = tx_pin;
this->rx_pin = rx_pin;
- this->timer_num = timer_num;
- this->compare_num = compare_num;
+ this->timer_device = timer_device;
+ this->channel_num = channel_num;
}
uint8 HardwareSerial::read(void) {
@@ -75,9 +73,9 @@ void HardwareSerial::begin(uint32 baud) {
gpio_set_mode(gpio_device, tx_pin, GPIO_AF_OUTPUT_PP);
gpio_set_mode(gpio_device, rx_pin, GPIO_INPUT_FLOATING);
- if (timer_num != TIMER_INVALID) {
+ if (timer_device != NULL) {
/* turn off any pwm if there's a conflict on this usart */
- timer_set_mode(timer_num, compare_num, TIMER_DISABLED);
+ timer_set_mode(timer_device, channel_num, TIMER_DISABLED);
}
usart_init(usart_num, baud);
diff --git a/wirish/comm/HardwareSerial.h b/wirish/comm/HardwareSerial.h
index ef19a56..7852d51 100644
--- a/wirish/comm/HardwareSerial.h
+++ b/wirish/comm/HardwareSerial.h
@@ -31,7 +31,9 @@
#ifndef _HARDWARESERIAL_H_
#define _HARDWARESERIAL_H_
-#include "timers.h"
+#include "libmaple_types.h"
+#include "gpio.h"
+#include "timer.h"
#include "Print.h"
@@ -49,16 +51,16 @@ class HardwareSerial : public Print {
gpio_dev *gpio_device;
uint8 tx_pin;
uint8 rx_pin;
- timer_dev_num timer_num;
- uint8 compare_num;
+ timer_dev *timer_device;
+ uint8 channel_num;
public:
HardwareSerial(uint8 usart_num,
uint32 max_baud,
gpio_dev *gpio_device,
uint8 tx_pin,
uint8 rx_pin,
- timer_dev_num timer_num,
- uint8 compare_num);
+ timer_dev *timer_device,
+ uint8 channel_num);
void begin(uint32 baud);
void end(void);
uint32 available(void);
diff --git a/wirish/pwm.cpp b/wirish/pwm.cpp
index 072e4cd..6b09cef 100644
--- a/wirish/pwm.cpp
+++ b/wirish/pwm.cpp
@@ -23,26 +23,20 @@
*****************************************************************************/
/**
- * @brief Arduino-compatible PWM implementation.
+ * @brief Arduino-style PWM implementation.
*/
-#include "wirish.h"
-#include "timers.h"
-#include "io.h"
+#include "libmaple_types.h"
+#include "timer.h"
+
+#include "boards.h"
#include "pwm.h"
void pwmWrite(uint8 pin, uint16 duty_cycle) {
- TimerCCR ccr;
-
- if (pin >= NR_GPIO_PINS) {
- return;
- }
-
- ccr = PIN_MAP[pin].timer_ccr;
-
- if (ccr == 0) {
+ timer_dev *dev = PIN_MAP[pin].timer_device;
+ if (pin >= NR_GPIO_PINS || dev == NULL || dev->type == TIMER_BASIC) {
return;
}
- timer_pwm_write_ccr(ccr, duty_cycle);
+ timer_set_compare(dev, PIN_MAP[pin].timer_chan, duty_cycle);
}
diff --git a/wirish/rules.mk b/wirish/rules.mk
index 3dd4b2d..d250cb9 100644
--- a/wirish/rules.mk
+++ b/wirish/rules.mk
@@ -18,7 +18,6 @@ cppSRCS_$(d) := wirish_math.cpp \
comm/HardwareSerial.cpp \
comm/HardwareSPI.cpp \
usb_serial.cpp \
- HardwareTimer.cpp \
cxxabi-compat.cpp \
wirish.cpp \
wirish_shift.cpp \
diff --git a/wirish/wirish.cpp b/wirish/wirish.cpp
index 65d0262..6dcb1b5 100644
--- a/wirish/wirish.cpp
+++ b/wirish/wirish.cpp
@@ -23,61 +23,107 @@
*****************************************************************************/
/**
- * @brief generic maple board bring up:
+ * @brief Generic Maple board initialization.
*
- * By default, we bring up all maple boards running on the stm32 to 72mhz,
- * clocked off the PLL, driven by the 8MHz external crystal.
- *
- * AHB and APB2 are clocked at 72MHz
- * APB1 is clocked at 36MHz
+ * By default, we bring up all Maple boards to 72MHz, clocked off the
+ * PLL, driven by the 8MHz external crystal. AHB and APB2 are clocked
+ * at 72MHz. APB1 is clocked at 36MHz.
*/
#include "wirish.h"
+
+#include "flash.h"
+#include "rcc.h"
+#include "nvic.h"
#include "systick.h"
#include "gpio.h"
-#include "nvic.h"
+#include "adc.h"
+#include "timer.h"
#include "usb.h"
-#include "rcc.h"
-#include "fsmc.h"
-#include "dac.h"
-#include "flash.h"
-#include "native_sram.h"
+static void setupFlash(void);
+static void setupClocks(void);
+static void setupADC(void);
+static void setupTimers(void);
+
+/**
+ * Board-wide initialization function. Called before main().
+ */
void init(void) {
- /* make sure the flash is ready before spinning the high speed clock up */
+ setupFlash();
+ setupClocks();
+ nvic_init();
+ systick_init(SYSTICK_RELOAD_VAL);
+ gpio_init_all();
+ afio_init();
+ setupADC();
+ setupTimers();
+ setupUSB();
+
+ BOARD_INIT;
+}
+
+static void setupFlash(void) {
flash_enable_prefetch();
flash_set_latency(FLASH_WAIT_STATE_2);
+}
-#ifdef BOARD_maple_native
- initNativeSRAM();
-#endif
-
- /* initialize clocks */
+/*
+ * Clock setup. Note that some of this only takes effect if we're
+ * running bare metal and the bootloader hasn't done it for us
+ * already.
+ *
+ * If you change this function, you MUST change the file-level Doxygen
+ * comment above.
+ */
+static void setupClocks() {
rcc_clk_init(RCC_CLKSRC_PLL, RCC_PLLSRC_HSE, RCC_PLLMUL_9);
rcc_set_prescaler(RCC_PRESCALER_AHB, RCC_AHB_SYSCLK_DIV_1);
rcc_set_prescaler(RCC_PRESCALER_APB1, RCC_APB1_HCLK_DIV_2);
rcc_set_prescaler(RCC_PRESCALER_APB2, RCC_APB2_HCLK_DIV_1);
+}
- nvic_init();
- systick_init(SYSTICK_RELOAD_VAL);
- gpio_init_all();
- afio_init();
-
- /* Initialize the ADC for slow conversions, to allow for high
- impedance inputs. */
+/* TODO initialize more ADCs on high density boards. */
+static void setupADC() {
adc_init(ADC1, 0);
- adc_set_sample_rate(ADC1, ADC_SMPR_55_5);
-
- timer_init(TIMER1, 1);
- timer_init(TIMER2, 1);
- timer_init(TIMER3, 1);
- timer_init(TIMER4, 1);
-#ifdef STM32_HIGH_DENSITY
- timer_init(TIMER5, 1);
- timer_init(TIMER8, 1);
-#endif
- setupUSB();
+ adc_set_sample_rate(ADC1, ADC_SMPR_55_5); // for high impedance inputs
+}
- /* include the board-specific init macro */
- BOARD_INIT;
+static void timerDefaultConfig(timer_dev*);
+
+static void setupTimers() {
+ timer_foreach(timerDefaultConfig);
+}
+
+static void timerDefaultConfig(timer_dev *dev) {
+ timer_adv_reg_map *regs = (dev->regs).adv;
+ const uint16 full_overflow = 0xFFFF;
+ const uint16 half_duty = 0x8FFF;
+
+ timer_init(dev);
+ timer_pause(dev);
+
+ regs->CR1 = TIMER_CR1_ARPE;
+ regs->PSC = 1;
+ regs->SR = 0;
+ regs->DIER = 0;
+ regs->EGR = TIMER_EGR_UG;
+
+ switch (dev->type) {
+ case TIMER_ADVANCED:
+ regs->BDTR = TIMER_BDTR_MOE | TIMER_BDTR_LOCK_OFF;
+ // fall-through
+ case TIMER_GENERAL:
+ timer_set_reload(dev, full_overflow);
+
+ for (int channel = 1; channel <= 4; channel++) {
+ timer_set_compare(dev, channel, half_duty);
+ timer_oc_set_mode(dev, channel, TIMER_OC_MODE_PWM_1, TIMER_OC_PE);
+ }
+ // fall-through
+ case TIMER_BASIC:
+ break;
+ }
+
+ timer_resume(dev);
}
diff --git a/wirish/wirish.h b/wirish/wirish.h
index 447b2b6..319df97 100644
--- a/wirish/wirish.h
+++ b/wirish/wirish.h
@@ -32,7 +32,6 @@
#define _WIRISH_H_
#include "libmaple.h"
-#include "timers.h"
#include "boards.h"
#include "io.h"
@@ -44,7 +43,6 @@
#include "HardwareSPI.h"
#include "HardwareSerial.h"
#include "usb_serial.h"
-#include "HardwareTimer.h"
/* Arduino wiring macros and bit defines */
#define HIGH 0x1
@@ -69,7 +67,6 @@ typedef uint8 boolean;
typedef uint8 byte;
void init(void);
-void shiftOut(uint8 dataPin, uint8 clockPin, uint8 bitOrder, byte val);
#endif
diff --git a/wirish/wirish_digital.cpp b/wirish/wirish_digital.cpp
index 0c0bd85..4b68861 100644
--- a/wirish/wirish_digital.cpp
+++ b/wirish/wirish_digital.cpp
@@ -72,15 +72,15 @@ void pinMode(uint8 pin, WiringPinMode mode) {
gpio_set_mode(PIN_MAP[pin].gpio_device, PIN_MAP[pin].pin, outputMode);
- if (PIN_MAP[pin].timer_num != TIMER_INVALID) {
+ if (PIN_MAP[pin].timer_device != NULL) {
/* enable/disable timer channels if we're switching into or
out of pwm */
if (pwm) {
- timer_set_mode(PIN_MAP[pin].timer_num,
+ timer_set_mode(PIN_MAP[pin].timer_device,
PIN_MAP[pin].timer_chan,
TIMER_PWM);
} else {
- timer_set_mode(PIN_MAP[pin].timer_num,
+ timer_set_mode(PIN_MAP[pin].timer_device,
PIN_MAP[pin].timer_chan,
TIMER_DISABLED);
}