aboutsummaryrefslogtreecommitdiffstats
path: root/libmaple
diff options
context:
space:
mode:
authorbnewbold <bnewbold@robocracy.org>2010-03-31 08:52:45 +0800
committeriperry <iperry@gmail.com>2010-03-31 09:43:10 +0800
commit1d3861ef93f8423176c6010ab606abdab00a7cbd (patch)
tree5c95101e295bcfdd7f9f4292ce9204ddf7e7f662 /libmaple
parent8d6bf3b196c2a0bc1adda4a04669e54fdc5b65cb (diff)
downloadlibrambutan-1d3861ef93f8423176c6010ab606abdab00a7cbd.tar.gz
librambutan-1d3861ef93f8423176c6010ab606abdab00a7cbd.zip
Major hierarchy reorganization; see README.
copy-to-ide and Makefile updated to conform; .gitignore added; LICENSE added
Diffstat (limited to 'libmaple')
-rw-r--r--libmaple/adc.c97
-rw-r--r--libmaple/adc.h93
-rw-r--r--libmaple/bootVect.h52
-rw-r--r--libmaple/exti.c279
-rw-r--r--libmaple/exti.h152
-rw-r--r--libmaple/gpio.c55
-rw-r--r--libmaple/gpio.h97
-rw-r--r--libmaple/libmaple.h33
-rw-r--r--libmaple/libmaple_types.h42
-rw-r--r--libmaple/nvic.c59
-rw-r--r--libmaple/nvic.h67
-rw-r--r--libmaple/stm32f10x_conf.h132
-rw-r--r--libmaple/stm32f10x_it.c252
-rw-r--r--libmaple/syscalls.c157
-rw-r--r--libmaple/systick.c52
-rw-r--r--libmaple/systick.h62
-rw-r--r--libmaple/timers.c192
-rw-r--r--libmaple/timers.h145
-rw-r--r--libmaple/usart.c345
-rw-r--r--libmaple/usart.h53
-rw-r--r--libmaple/usb.c83
-rw-r--r--libmaple/usb.h32
-rw-r--r--libmaple/usb_regs.h555
-rw-r--r--libmaple/util.c103
-rw-r--r--libmaple/util.h82
25 files changed, 3271 insertions, 0 deletions
diff --git a/libmaple/adc.c b/libmaple/adc.c
new file mode 100644
index 0000000..7169824
--- /dev/null
+++ b/libmaple/adc.c
@@ -0,0 +1,97 @@
+/* *****************************************************************************
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Created: 12/18/09 02:34:47
+ * Copyright (c) 2009 Perry L. Hung. All rights reserved.
+ *
+ * ****************************************************************************/
+
+/**
+ * @file adc.c
+ *
+ * @brief Analog to digital converter routines
+ */
+
+#include "stm32f10x_rcc.h"
+#include "adc.h"
+#include <stdio.h>
+#include <inttypes.h>
+
+/* The ADC input clock is generated from PCLK2/APB2 divided by a prescaler
+ * and it must not exceed 14MHz.
+ *
+ * ADC1 and ADC2 are clocked by APB2
+ *
+ * 1) Power on by setting ADON in ADC_CR2
+ * Conversion starts when ADON is set for a second time after some
+ * time t > t_stab.
+ *
+ * Up to 16 selected conversion must be selected in ADC_SQRx
+ *
+ * Single conversion mode:
+ * Set the ADON bit in the ADC_CR2 register
+ * Once the conversion is complete:
+ * Converted data is stored in ADC_DR
+ * EOC flag is set
+ * Interrupt is generated if EOCIE is set
+ *
+ * Calibration:
+ * Calibration is started by setting the CAL bit in the ADC_CR2 register.
+ * Once calibration is over, the CAL bit is reset by hardware and normal
+ * conversion can be performed. Calibrate at power-on.
+ *
+ * ALIGN in ADC_CR2 selects the alignment of data
+ *
+ * IMPORTANT: maximum external impedance must be below 0.4kOhms for 1.5
+ * sample conversion time.
+ *
+ * At 55.5 cycles/sample, the external input impedance < 50kOhms*/
+
+void adc_init(void) {
+ /* PCLK2 is the APB2 clock */
+ RCC_ADCCLKConfig(RCC_PCLK2_Div6);
+
+ /* Enable ADC1 clock so that we can talk to it */
+ RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
+
+ /* Put everything back to power-on defaults */
+ RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1, ENABLE);
+ RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1, DISABLE);
+
+ ADC_CR1 = 0;
+ ADC_CR2 = CR2_EXTSEL_SWSTART | CR2_EXTTRIG; // Software triggers conversions
+ ADC_SQR1 = 0;
+
+ /* Up the sample conversion time to 55.5 cycles/sec, see note above */
+ /* TODO: fix magic numbers */
+ ADC_SMPR1 = 0xB6DB6D;
+ ADC_SMPR2 = 0x2DB6DB6D;
+
+ /* Enable the ADC */
+ CR2_ADON_BIT = 1;
+
+ /* Reset the calibration registers and then perform a reset */
+ CR2_RSTCAL_BIT = 1;
+ while(CR2_RSTCAL_BIT)
+ ;
+
+ CR2_CAL_BIT = 1;
+ while(CR2_CAL_BIT)
+ ;
+}
+
+
+void adc_disable(void) {
+ CR2_ADON_BIT = 0;
+}
diff --git a/libmaple/adc.h b/libmaple/adc.h
new file mode 100644
index 0000000..d554b02
--- /dev/null
+++ b/libmaple/adc.h
@@ -0,0 +1,93 @@
+/* *****************************************************************************
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Created: 12/18/09 02:35:10
+ * Copyright (c) 2009 Perry L. Hung. All rights reserved.
+ *
+ * ****************************************************************************/
+
+/**
+ * @file adc.h
+ *
+ * @brief ADC prototypes and defines
+ */
+
+#ifndef _ADC_H_
+#define _ADC_H_
+#include <inttypes.h>
+#include "util.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+/* Notes:
+ * The maximum input impedance on each channel MUST be below .4kohms,
+ * or face the wrath of incorrect readings...
+ * This can be changed at the expense of sample time... see datasheet
+ *
+ * Need to up the sample time if otherwise... see datasheet */
+
+/* We'll only use ADC1 for now... */
+#define ADC_BASE 0x40012400
+#define ADC_SR *(volatile uint32_t*)(ADC_BASE + 0)
+#define ADC_CR1 *(volatile uint32_t*)(ADC_BASE + 0x4)
+#define ADC_CR2 *(volatile uint32_t*)(ADC_BASE + 0x8)
+#define ADC_SMPR1 *(volatile uint32_t*)(ADC_BASE + 0xC)
+#define ADC_SMPR2 *(volatile uint32_t*)(ADC_BASE + 0x10)
+#define ADC_SQR1 *(volatile uint32_t*)(ADC_BASE + 0x2C)
+#define ADC_SQR3 *(volatile uint32_t*)(ADC_BASE + 0x34)
+#define ADC_DR *(volatile uint32_t*)(ADC_BASE + 0x4C)
+
+#define CR2_EXTSEL_SWSTART (0xE << 16)
+#define CR2_RSTCAL (BIT(3))
+#define CR2_EXTTRIG (BIT(20))
+
+/* Bit banded bits */
+#define CR2_ADON_BIT *(volatile uint32_t*)(BITBAND_PERI(ADC_BASE+0x8, 0))
+#define CR2_CAL_BIT *(volatile uint32_t*)(BITBAND_PERI(ADC_BASE+0x8, 2))
+#define CR2_RSTCAL_BIT *(volatile uint32_t*)(BITBAND_PERI(ADC_BASE+0x8, 3))
+#define CR2_SWSTART_BIT *(volatile uint32_t*)(BITBAND_PERI(ADC_BASE+0x8 + 2, 6))
+#define SR_EOC_BIT *(volatile uint32_t*)(BITBAND_PERI(ADC_BASE+0, 1))
+
+#define NR_ANALOG_PINS 16
+
+/* Initialize ADC1 to do one-shot conversions */
+void adc_init(void);
+void adc_disable(void);
+
+/* Perform a single conversion on ADC[0-16],
+ * PRECONDITIONS:
+ * adc initialized */
+static inline int adc_read(int channel) {
+ /* Set channel */
+ ADC_SQR3 = channel;
+
+ /* Start the conversion */
+ CR2_SWSTART_BIT = 1;
+
+ /* Wait for it to finish */
+ while(SR_EOC_BIT == 0)
+ ;
+
+ return ADC_DR;
+}
+
+
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+#endif
+
diff --git a/libmaple/bootVect.h b/libmaple/bootVect.h
new file mode 100644
index 0000000..5bcb42b
--- /dev/null
+++ b/libmaple/bootVect.h
@@ -0,0 +1,52 @@
+/* *****************************************************************************
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * ****************************************************************************/
+
+/**
+ * @file HardwareUsb.h
+ *
+ * @brief Defines the maple boot vector structure
+ */
+
+#ifndef _BOOTVECT_H_
+#define _BOOTVECT_H_
+
+#define BOOTLOADER_VECT_TABLE ((uint32_t*)0x20000000)
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+typedef void (*FuncPtr)(void);
+
+typedef struct {
+ FuncPtr serial_tx_cb;
+ FuncPtr serial_rx_cb;
+ FuncPtr serial_linecoding_cb;
+ uint32_t* serial_count_in;
+ uint32_t* serial_count_out;
+ uint8_t* serial_buffer_out;
+ void* linecoding;
+ uint8_t major_rev;
+ uint8_t minor_rev;
+ void* usb_device_ptr;
+ void* usb_local_obj_ptr;
+} BootVectTable;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _BOOTVECT_H_
diff --git a/libmaple/exti.c b/libmaple/exti.c
new file mode 100644
index 0000000..bdaa204
--- /dev/null
+++ b/libmaple/exti.c
@@ -0,0 +1,279 @@
+/* *****************************************************************************
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Created: 12/18/09 02:35:22
+ * Copyright (c) 2009 Perry L. Hung. All rights reserved.
+ *
+ * ****************************************************************************/
+
+/**
+ * @file exti.c
+ *
+ * @brief External interrupt control routines
+ */
+
+#include "libmaple.h"
+#include "exti.h"
+#include "nvic.h"
+
+volatile static voidFuncPtr exti_handlers[NR_EXTI_CHANNELS];
+
+static inline void clear_pending(int bit) {
+ REG_SET(EXTI_PR, BIT(bit));
+ /* If the pending bit is cleared as the last instruction in an ISR,
+ * it won't actually be cleared in time and the ISR will fire again.
+ * Insert a 2-cycle buffer to allow it to take effect. */
+ asm volatile("nop");
+ asm volatile("nop");
+}
+
+/* For EXTI0 through EXTI4, only one handler
+ * is associated with each channel, so we
+ * don't have to keep track of which channel
+ * we came from */
+void EXTI0_IRQHandler(void) {
+ ASSERT(exti_handlers[EXTI0]);
+ if (exti_handlers[EXTI0]) {
+ exti_handlers[EXTI0]();
+ }
+
+ /* Clear pending bit*/
+ clear_pending(EXTI0);
+}
+
+void EXTI1_IRQHandler(void) {
+ ASSERT(exti_handlers[EXTI1]);
+ /* Call registered handler */
+ if (exti_handlers[EXTI1]) {
+ exti_handlers[EXTI1]();
+ }
+
+ /* Clear pending bit*/
+ clear_pending(EXTI1);
+}
+
+void EXTI2_IRQHandler(void) {
+ ASSERT(exti_handlers[EXTI2]);
+ /* Call registered handler */
+ if (exti_handlers[EXTI2]) {
+ exti_handlers[EXTI2]();
+ }
+
+ /* Clear pending bit*/
+ clear_pending(EXTI2);
+}
+
+void EXTI3_IRQHandler(void) {
+ ASSERT(exti_handlers[EXTI3]);
+ /* Call registered handler */
+ if (exti_handlers[EXTI3]) {
+ exti_handlers[EXTI3]();
+ }
+
+ /* Clear pending bit*/
+ clear_pending(EXTI3);
+}
+
+void EXTI4_IRQHandler(void) {
+ ASSERT(exti_handlers[EXTI4]);
+ /* Call registered handler */
+ if (exti_handlers[EXTI4]) {
+ exti_handlers[EXTI4]();
+ }
+
+ /* Clear pending bit*/
+ clear_pending(EXTI4);
+}
+
+void EXTI9_5_IRQHandler(void) {
+ /* Figure out which channel it came from */
+ uint32_t pending;
+ uint32_t i;
+ pending = REG_GET(EXTI_PR);
+ pending = GET_BITS(pending, 5, 9);
+
+ /* Dispatch every handler if the pending bit is set */
+ for (i = 0; i < 5; i++) {
+ if (pending & 0x1) {
+ ASSERT(exti_handlers[EXTI5 + i]);
+ exti_handlers[EXTI5 + i]();
+ clear_pending(EXTI5 + i);
+ }
+ pending >>= 1;
+ }
+}
+
+void EXTI15_10_IRQHandler(void) {
+ /* Figure out which channel it came from */
+ uint32_t pending;
+ uint32_t i;
+ pending = REG_GET(EXTI_PR);
+ pending = GET_BITS(pending, 10, 15);
+
+ /* Dispatch every handler if the pending bit is set */
+ for (i = 0; i < 6; i++) {
+ if (pending & 0x1) {
+ ASSERT(exti_handlers[EXTI10 + i]);
+ exti_handlers[EXTI10 + i]();
+ clear_pending(EXTI10 + i);
+ }
+ pending >>= 1;
+ }
+}
+
+
+void exti_attach_interrupt(uint8_t channel, uint8_t port, voidFuncPtr handler, uint8_t mode) {
+ ASSERT(channel < NR_EXTI_CHANNELS);
+ ASSERT(port < NR_EXTI_PORTS);
+ ASSERT(mode < NR_EXTI_MODES);
+ ASSERT(EXTI0 == 0);
+ ASSERT(handler);
+
+ /* Note: All of the following code assumes that EXTI0 = 0 */
+
+ /* Map port to the correct EXTI channel */
+ switch (channel) {
+ case EXTI0:
+ case EXTI1:
+ case EXTI2:
+ case EXTI3:
+ REG_SET_MASK(AFIO_EXTICR1, BIT_MASK_SHIFT(port, channel*4));
+ break;
+
+ case EXTI4:
+ case EXTI5:
+ case EXTI6:
+ case EXTI7:
+ REG_SET_MASK(AFIO_EXTICR2, BIT_MASK_SHIFT(port, (channel-4)*4));
+ break;
+
+ case EXTI8:
+ case EXTI9:
+ case EXTI10:
+ case EXTI11:
+ REG_SET_MASK(AFIO_EXTICR3, BIT_MASK_SHIFT(port, (channel-8)*4));
+ break;
+
+ case EXTI12:
+ case EXTI13:
+ case EXTI14:
+ case EXTI15:
+ REG_SET_MASK(AFIO_EXTICR4, BIT_MASK_SHIFT(port, (channel-12)*4));
+ break;
+ }
+
+ /* Unmask appropriate interrupt line */
+ REG_SET_BIT(EXTI_IMR, channel);
+
+ /* Set trigger mode */
+ switch (mode) {
+ case EXTI_RISING:
+ REG_SET_BIT(EXTI_RTSR, channel);
+ break;
+
+ case EXTI_FALLING:
+ REG_SET_BIT(EXTI_FTSR, channel);
+ break;
+
+ case EXTI_RISING_FALLING:
+ REG_SET_BIT(EXTI_RTSR, channel);
+ REG_SET_BIT(EXTI_FTSR, channel);
+ break;
+ }
+
+ /* Configure the enable interrupt bits for the NVIC */
+ switch (channel) {
+ case EXTI0:
+ case EXTI1:
+ case EXTI2:
+ case EXTI3:
+ case EXTI4:
+ REG_SET(NVIC_ISER0, BIT(channel + 6));
+ break;
+
+ /* EXTI5-9 map to the same isr */
+ case EXTI5:
+ case EXTI6:
+ case EXTI7:
+ case EXTI8:
+ case EXTI9:
+ REG_SET(NVIC_ISER0, BIT(23));
+ break;
+
+ /* EXTI10-15 map to the same isr */
+ case EXTI10:
+ case EXTI11:
+ case EXTI12:
+ case EXTI13:
+ case EXTI14:
+ case EXTI15:
+ REG_SET(NVIC_ISER1, BIT(8));
+ break;
+ }
+
+ /* Register the handler */
+ exti_handlers[channel] = handler;
+}
+
+
+void exti_detach_interrupt(uint8_t channel) {
+ ASSERT(channel < NR_EXTI_CHANNELS);
+ ASSERT(EXTI0 == 0);
+ /* Is this interrupt actually on? */
+ ASSERT((REG_GET(EXTI_IMR) >> channel) & 0x01);
+
+ /* Clear EXTI_IMR line */
+ REG_CLEAR_BIT(EXTI_IMR, channel);
+
+ /* Clear triggers */
+ REG_CLEAR_BIT(EXTI_FTSR, channel);
+ REG_CLEAR_BIT(EXTI_RTSR, channel);
+
+ /* Turn off the associated interrupt */
+ switch (channel) {
+ case EXTI0:
+ case EXTI1:
+ case EXTI2:
+ case EXTI3:
+ case EXTI4:
+ REG_SET(NVIC_ICER0, BIT(channel + 6));
+ break;
+ case EXTI5:
+ case EXTI6:
+ case EXTI7:
+ case EXTI8:
+ case EXTI9:
+ /* Are there any other channels enabled?
+ * If so, don't disable the interrupt handler */
+ if (GET_BITS(REG_GET(EXTI_IMR), 5, 9) == 0) {
+ REG_SET(NVIC_ICER0, BIT(23));
+ }
+ break;
+ case EXTI10:
+ case EXTI11:
+ case EXTI12:
+ case EXTI13:
+ case EXTI14:
+ case EXTI15:
+ /* Are there any other channels enabled?
+ * If so, don't disable the interrupt handler */
+ if (GET_BITS(REG_GET(EXTI_IMR), 10, 15) == 0) {
+ REG_SET(NVIC_ICER1, BIT(8));
+ }
+ break;
+ }
+
+ /* Clear handler function pointer */
+ exti_handlers[channel] = 0;
+}
diff --git a/libmaple/exti.h b/libmaple/exti.h
new file mode 100644
index 0000000..c728454
--- /dev/null
+++ b/libmaple/exti.h
@@ -0,0 +1,152 @@
+/* *****************************************************************************
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Created: 12/18/09 02:35:33
+ * Copyright (c) 2009 Perry L. Hung. All rights reserved.
+ *
+ * ****************************************************************************/
+
+/**
+ * @file exti.h
+ *
+ * @brief External interrupt control prototypes and defines
+ */
+
+#ifndef _EXTI_H_
+#define _EXTI_H_
+
+#include <inttypes.h>
+/* Notes:
+ *
+ * To generate the interrupt, the interrupt line should be configured and
+ * enabled. This is done by programming the two trigger registers with the
+ * desired edge detection and by enabling the interrupt request by writing a
+ * '1' to the corresponding bit in the interrupt mask register. When the
+ * selected edge occurs on the external interrupt line, an interrupt request is
+ * generated. The pending bit corresponding to the interrupt line is also set.
+ * This request is reset by writing a '1' in the pending register.
+ *
+ * Hardware interrupt selection:
+ * To configure the 20 lines as interrupt sources, use the following procedure:
+ * 1) Configure AFIO_EXTIICR[y] to select the source input for EXTIx external
+ * interrupt
+ * 2) Configure the mask bits of the 20 interrupt lines (EXTI_IMR)
+ * 3) Configure the trigger selection bits of the interrupt lines (EXTI_RTSR and EXTI_FTSR)
+ * 4) Configure the enable and mask bits that control the NVIC_IRQ channel mapped to the External
+ * Interrupt Controller (EXTI) so that an inerrupt coming from one of the 20 lines
+ * can be correctly acknowledged.
+ *
+ * AFIO clock must be on.
+ *
+ * RM0008, page 107: "PD0, PD1 cannot be used for external interrupt/event generation
+ * on 36, 48, 64-bin packages."
+ *
+ * ----------------------------------------------------------------------------
+ * Pin to EXTI Line Mappings:
+ * EXTI0 EXTI1 EXTI2 EXTI3 EXTI4
+ * ----------------------------------------------------------------------------
+ * D2/PA0 D3/PA1 D1/PA2 D0/A6/PA3 D10/A10/PA4
+ * D26/EXT7/PB0 D27/EXT8/PB1 D16/A2/PC2 D17/A3/PC3 D18/A4/PC4
+ * D14/A0/PC0 D15/PC1 D25/EXT5/PD2
+ *
+ * EXTI5 EXTI6 EXTI7 EXTI8 EXTI9
+ * ----------------------------------------------------------------------------
+ * D13/A13/PA5 D12/A12/PA6 D11/A11/PA7 D6/PA8 D7/PA9
+ * D4/PB5 D5/PB6 D9/PB7 D38/PB8 D23/EXT4/PB9
+ * D19/A5/PC5 D34/EXTI15/PC6 D35/EXT16/PC7 D36/PC8 D37/EXT18/PC9
+ *
+ * EXTI10 EXTI11 EXTI12 EXTI13 EXTI14
+ * ----------------------------------------------------------------------------
+ * D8/PA10 D29/EXT10/PB11 D30/EXTI1/PB12 D31/EXTI12/PB13 D32/EXT13/PB14
+ * D28/PB10 D20/EXTI1/PC13 D21/EXT2/PC14
+ * D25/PC10
+ *
+ * EXTI15
+ * ----------------------------------------------------------------------------
+ * D33/EXTI14/PB15
+ * D22/EXT3/PC15
+ *
+ *
+ * The 16 EXTI interrupts are mapped to 7 interrupt handlers.
+ *
+ * EXTI Lines to Interrupt Mapping:
+ * EXTI0 -> EXTI0
+ * EXTI1 -> EXTI1
+ * EXTI2 -> EXTI2
+ * EXTI3 -> EXTI3
+ * EXTI4 -> EXTI4
+ * EXTI[5-9] -> EXT9_5
+ * EXTI[10-15] -> EXT15_10
+ *
+ *
+ * */
+
+#define NR_EXTI_CHANNELS 16
+#define NR_EXTI_PORTS 4
+#define NR_EXTI_MODES 3
+
+#define EXTI_IMR 0x40010400 // Interrupt mask register
+#define EXTI_EMR (EXTI_IMR + 0x04) // Event mask register
+#define EXTI_RTSR (EXTI_IMR + 0x08) // Rising trigger selection register
+#define EXTI_FTSR (EXTI_IMR + 0x0C) // Falling trigger selection register
+#define EXTI_SWIER (EXTI_IMR + 0x10) // Software interrupt event register
+#define EXTI_PR (EXTI_IMR + 0x14) // Pending register
+
+#define AFIO_EVCR 0x40010000
+#define AFIO_EXTICR1 (AFIO_EVCR + 0x08)
+#define AFIO_EXTICR2 (AFIO_EVCR + 0x0C)
+#define AFIO_EXTICR3 (AFIO_EVCR + 0x10)
+#define AFIO_EXTICR4 (AFIO_EVCR + 0x14)
+
+#define EXTI_RISING 0
+#define EXTI_FALLING 1
+#define EXTI_RISING_FALLING 2
+
+#define EXTI0 0
+#define EXTI1 1
+#define EXTI2 2
+#define EXTI3 3
+#define EXTI4 4
+#define EXTI5 5
+#define EXTI6 6
+#define EXTI7 7
+#define EXTI8 8
+#define EXTI9 9
+#define EXTI10 10
+#define EXTI11 11
+#define EXTI12 12
+#define EXTI13 13
+#define EXTI14 14
+#define EXTI15 15
+
+#define EXTI_CONFIG_PORTA 0
+#define EXTI_CONFIG_PORTB 1
+#define EXTI_CONFIG_PORTC 2
+#define EXTI_CONFIG_PORTD 3
+
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+void exti_attach_interrupt(uint8_t, uint8_t, voidFuncPtr, uint8_t);
+void exti_detach_interrupt(uint8_t);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+
+#endif
+
diff --git a/libmaple/gpio.c b/libmaple/gpio.c
new file mode 100644
index 0000000..facb514
--- /dev/null
+++ b/libmaple/gpio.c
@@ -0,0 +1,55 @@
+/* *****************************************************************************
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Created: 12/18/09 02:35:49
+ * Copyright (c) 2009 Perry L. Hung. All rights reserved.
+ *
+ * ****************************************************************************/
+
+/**
+ * @file gpio.c
+ *
+ * @brief GPIO initialization routine
+ */
+
+#include "libmaple.h"
+#include "stm32f10x_rcc.h"
+#include "gpio.h"
+
+void gpio_init(void) {
+ /* Turn on clocks for GPIO */
+ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |
+ RCC_APB2Periph_GPIOB |
+ RCC_APB2Periph_GPIOC |
+ RCC_APB2Periph_GPIOD |
+ RCC_APB2Periph_AFIO,
+ ENABLE);
+}
+
+void gpio_set_mode(GPIO_Port* port, uint8 gpio_pin, uint8 mode) {
+ uint32_t tmp;
+ uint32_t shift = POS(gpio_pin % 8);
+ GPIOReg CR;
+
+ ASSERT(port);
+ ASSERT(gpio_pin < 16);
+
+ CR = (gpio_pin < 8) ? &(port->CRL) : &(port->CRH);
+
+ tmp = *CR;
+ tmp &= POS_MASK(shift);
+ tmp |= mode << shift;
+
+ *CR = tmp;
+}
diff --git a/libmaple/gpio.h b/libmaple/gpio.h
new file mode 100644
index 0000000..5e7cf29
--- /dev/null
+++ b/libmaple/gpio.h
@@ -0,0 +1,97 @@
+/* *****************************************************************************
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Created: 12/18/09 02:36:01
+ * Copyright (c) 2009 Perry L. Hung. All rights reserved.
+ *
+ * ****************************************************************************/
+
+/**
+ * @file gpio.h
+ *
+ * @brief GPIO prototypes, defines, and inlined access functions
+ */
+
+#ifndef _GPIO_H
+#define _GPIO_H
+
+/* Each of the GPIO port bits can be in the following modes (STM32 138/995):
+ * Input floating
+ * Input pull-up
+ * Input pull-down
+ * Analog Input
+ * Output open-drain
+ * Output push-pull
+ * Alternate function push-pull
+ * Alternate function open-drain
+ *
+ * - After reset, the alternate functions are not active and IO prts
+ * are set to Input Floating mode */
+
+#define GPIOA_BASE (GPIO_Port*)0x40010800
+#define GPIOB_BASE (GPIO_Port*)0x40010C00
+#define GPIOC_BASE (GPIO_Port*)0x40011000
+#define GPIOD_BASE (GPIO_Port*)0x40011400
+
+/* Pin modes are set by [CNFx[1:0] : MODEx[1:0]] */
+#define GPIO_SPEED_50MHZ (0x3) // Max output speed 50 MHz
+#define GPIO_MODE_OUTPUT_PP ((0x00 << 2) | GPIO_SPEED_50MHZ)
+#define GPIO_MODE_OUTPUT_OD ((0x01 << 2) | GPIO_SPEED_50MHZ)
+
+#define GPIO_MODE_AF_OUTPUT_PP ((0x02 << 2) | GPIO_SPEED_50MHZ)
+#define GPIO_MODE_AF_OUTPUT_OD ((0x03 << 2) | GPIO_SPEED_50MHZ)
+
+/* Note: mode bits must be set to zero for input mode */
+#define GPIO_MODE_INPUT_ANALOG (0x00 << 2)
+#define GPIO_MODE_INPUT_FLOATING (0x01 << 2)
+#define GPIO_MODE_INPUT_PD (0x02 << 2)
+#define GPIO_MODE_INPUT_PU (0x02 << 2)
+
+typedef struct {
+ volatile uint32 CRL; // Port configuration register low
+ volatile uint32 CRH; // Port configuration register high
+ volatile uint32 IDR; // Port input data register
+ volatile uint32 ODR; // Port output data register
+ volatile uint32 BSRR; // Port bit set/reset register
+ volatile uint32 BRR; // Port bit reset register
+ volatile uint32 LCKR; // Port configuration lock register
+} GPIO_Port;
+
+typedef volatile uint32* GPIOReg;
+
+#define POS_MASK(shift) (~(0xF << shift))
+#define POS(val) (val << 2)
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+void gpio_init(void);
+void gpio_set_mode(GPIO_Port* port, uint8 gpio_pin, uint8 mode);
+
+static inline void gpio_write_bit(GPIO_Port *port, uint8 gpio_pin, uint8 val) {
+ if (val){
+ port->BSRR = BIT(gpio_pin);
+ } else {
+ port->BRR = BIT(gpio_pin);
+ }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+
+#endif
+
diff --git a/libmaple/libmaple.h b/libmaple/libmaple.h
new file mode 100644
index 0000000..dc9ffd2
--- /dev/null
+++ b/libmaple/libmaple.h
@@ -0,0 +1,33 @@
+/* *****************************************************************************
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Created: 12/19/09 02:37:22 EST
+ * Copyright (c) 2009 Perry L. Hung. All rights reserved.
+ *
+ * ****************************************************************************/
+
+/**
+ * @file libmaple.h
+ *
+ * @brief general include file for libmaple
+ */
+
+#ifndef _LIBMAPLE_H_
+#define _LIBMAPLE_H_
+
+#include "libmaple_types.h"
+#include "util.h"
+
+#endif
+
diff --git a/libmaple/libmaple_types.h b/libmaple/libmaple_types.h
new file mode 100644
index 0000000..b798587
--- /dev/null
+++ b/libmaple/libmaple_types.h
@@ -0,0 +1,42 @@
+/* *****************************************************************************
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Created: 12/19/09 02:35:14 EST
+ * Copyright (c) 2009 Perry L. Hung. All rights reserved.
+ *
+ * ****************************************************************************/
+
+/**
+ * @file libmaple_types.h
+ *
+ * @brief libmaple types
+ */
+
+#ifndef _LIBMAPLE_TYPES_H_
+#define _LIBMAPLE_TYPES_H_
+
+typedef unsigned char uint8;
+typedef unsigned short uint16;
+typedef unsigned int uint32;
+typedef unsigned long long uint64;
+
+typedef signed char int8;
+typedef short int16;
+typedef int int32;
+typedef long long int64;
+
+typedef void (*voidFuncPtr)(void);
+
+#endif
+
diff --git a/libmaple/nvic.c b/libmaple/nvic.c
new file mode 100644
index 0000000..9b8c84f
--- /dev/null
+++ b/libmaple/nvic.c
@@ -0,0 +1,59 @@
+/* *****************************************************************************
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Created: 12/18/09 02:36:19
+ * Copyright (c) 2009 Perry L. Hung. All rights reserved.
+ *
+ * ****************************************************************************/
+
+/**
+ * @file nvic.c
+ *
+ * @brief Nested interrupt controller routines
+ */
+
+#include "libmaple.h"
+#include "nvic.h"
+#include "systick.h"
+
+void nvic_disable_interrupts(void) {
+ /* Turn off all interrupts */
+ REG_SET(NVIC_ICER0, 0xFFFFFFFF);
+ REG_SET(NVIC_ICER1, 0xFFFFFFFF);
+
+ /* Turn off systick exception */
+ REG_CLEAR_BIT(SYSTICK_CSR, 0);
+}
+
+
+void nvic_set_vector_table(uint32_t *addr, uint32_t offset) {
+// SCB->VTOR = NVIC_VectTab | (Offset & (u32)0x1FFFFF80);
+}
+
+
+/**
+ * @brief turn on interrupt number n
+ * @param[in] n interrupt number
+ */
+void nvic_enable_interrupt(uint32 n) {
+ if (n >= NVIC_NR_INTERRUPTS) {
+ return;
+ }
+
+ if (n < 32) {
+ REG_SET_BIT(NVIC_ISER0, n);
+ } else {
+ REG_SET_BIT(NVIC_ISER1, n - 32);
+ }
+}
diff --git a/libmaple/nvic.h b/libmaple/nvic.h
new file mode 100644
index 0000000..5908e9c
--- /dev/null
+++ b/libmaple/nvic.h
@@ -0,0 +1,67 @@
+/* *****************************************************************************
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Created: 12/18/09 02:36:47
+ * Copyright (c) 2009 Perry L. Hung. All rights reserved.
+ *
+ * ****************************************************************************/
+
+/**
+ * @file nvic.h
+ *
+ * @brief Nested interrupt controller defines and prototypes
+ */
+
+#ifndef _NVIC_H_
+#define _NVIC_H_
+
+#define NVIC_INT_USBHP 19
+#define NVIC_INT_USBLP 20
+#define NVIC_EXTI1_OFFSET (NVIC_ISER0 + 0x07)
+#define NVIC_EXTI9_5_OFFSET (NVIC_ISER0 + 0x17)
+
+/* NVIC Interrupt Enable registers */
+#define NVIC_ISER0 0xE000E100
+#define NVIC_ISER1 0xE000E104
+#define NVIC_ISER2 0xE000E108
+#define NVIC_ISER3 0xE000E10C
+
+/* NVIC Interrupt Clear registers */
+#define NVIC_ICER0 0xE000E180
+#define NVIC_ICER1 0xE000E184
+#define NVIC_ICER2 0xE000E188
+#define NVIC_ICER3 0xE000E18C
+
+/* 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_NR_INTERRUPTS 60
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+void nvic_disable_interrupts(void);
+void nvic_enable_interrupt(uint32);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
diff --git a/libmaple/stm32f10x_conf.h b/libmaple/stm32f10x_conf.h
new file mode 100644
index 0000000..ddd1833
--- /dev/null
+++ b/libmaple/stm32f10x_conf.h
@@ -0,0 +1,132 @@
+/******************** (C) COPYRIGHT 2008 STMicroelectronics ********************
+* File Name : stm32f10x_conf.h
+* Author : MCD Application Team
+* Version : V2.0.2
+* Date : 07/11/2008
+* Description : Library configuration file.
+********************************************************************************
+* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
+* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
+* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
+* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
+* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+*******************************************************************************/
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F10x_CONF_H
+#define __STM32F10x_CONF_H
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32f10x_type.h"
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+/* Uncomment the line below to compile the library in DEBUG mode, this will expanse
+ the "assert_param" macro in the firmware library code (see "Exported macro"
+ section below) */
+/* #define DEBUG 1*/
+
+/* Comment the line below to disable the specific peripheral inclusion */
+/************************************* ADC ************************************/
+//#define _ADC
+//#define _ADC1
+//#define _ADC2
+//#define _ADC3
+//#define _BKP
+//#define _CAN
+//#define _CRC
+//#define _DAC
+//#define _DBGMCU
+//#define _DMA
+//#define _DMA1_Channel1
+//#define _DMA1_Channel2
+//#define _DMA1_Channel3
+//#define _DMA1_Channel4
+//#define _DMA1_Channel5
+//#define _DMA1_Channel6
+//#define _DMA1_Channel7
+//#define _DMA2_Channel1
+//#define _DMA2_Channel2
+//#define _DMA2_Channel3
+//#define _DMA2_Channel4
+//#define _DMA2_Channel5
+#define _EXTI
+#define _FLASH
+
+/* Uncomment the line below to enable FLASH program/erase/protections functions,
+ otherwise only FLASH configuration (latency, prefetch, half cycle) functions
+ are enabled */
+/* #define _FLASH_PROG */
+
+#if 0
+#define _FSMC
+#define _GPIO
+#define _GPIOA
+#define _GPIOB
+#define _GPIOC
+#define _GPIOD
+#define _GPIOE
+#define _GPIOF
+#define _GPIOG
+#define _I2C
+#define _I2C1
+#define _I2C2
+#define _IWDG
+#define _PWR
+#define _RTC
+#define _SDIO
+#define _SPI
+#define _SPI1
+#define _SPI2
+#define _SPI3
+#define _SysTick
+#define _TIM
+#define _TIM1
+#define _TIM2
+#define _TIM3
+#define _TIM4
+#define _TIM5
+#define _TIM6
+#define _TIM7
+#define _TIM8
+#define _USART
+#define _USART1
+#define _USART3
+#define _UART4
+#define _UART5
+#endif
+#define _USART2
+#define _NVIC
+#define _RCC
+#define _AFIO
+
+/************************************* WWDG ***********************************/
+#define _WWDG
+
+/* In the following line adjust the value of External High Speed oscillator (HSE)
+ used in your application */
+#define HSE_Value ((u32)8000000) /* Value of the External oscillator in Hz*/
+
+/* Exported macro ------------------------------------------------------------*/
+#ifdef DEBUG
+/*******************************************************************************
+* Macro Name : assert_param
+* Description : The assert_param macro is used for function's parameters check.
+* It is used only if the library is compiled in DEBUG mode.
+* Input : - expr: If expr is false, it calls assert_failed function
+* which reports the name of the source file and the source
+* line number of the call that failed.
+* If expr is true, it returns no value.
+* Return : None
+*******************************************************************************/
+ #define assert_param(expr) ((expr) ? (void)0 : assert_failed((u8 *)__FILE__, __LINE__))
+/* Exported functions ------------------------------------------------------- */
+ void assert_failed(u8* file, u32 line);
+#else
+ #define assert_param(expr) ((void)0)
+#endif /* DEBUG */
+
+#endif /* __STM32F10x_CONF_H */
+
+/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/
diff --git a/libmaple/stm32f10x_it.c b/libmaple/stm32f10x_it.c
new file mode 100644
index 0000000..70d3269
--- /dev/null
+++ b/libmaple/stm32f10x_it.c
@@ -0,0 +1,252 @@
+void NMIException(void) {
+}
+void HardFaultException(void) {
+ while (1) {
+ }
+}
+
+void MemManageException(void) {
+ while (1) {
+ }
+}
+
+void BusFaultException(void) {
+ while (1) {
+ }
+}
+
+void UsageFaultException(void) {
+ while (1) {
+ }
+}
+
+#if 0
+void DebugMonitor(void) {
+}
+
+void SVCHandler(void) {
+}
+
+void PendSVC(void) {
+}
+
+void WWDG_IRQHandler(void) {
+}
+
+void PVD_IRQHandler(void) {
+}
+
+void TAMPER_IRQHandler(void) {
+}
+
+void RTC_IRQHandler(void) {
+}
+
+void FLASH_IRQHandler(void) {
+}
+
+void RCC_IRQHandler(void) {
+}
+
+void DMA1_Channel1_IRQHandler(void) {
+}
+
+void DMA1_Channel2_IRQHandler(void) {
+}
+
+void DMA1_Channel3_IRQHandler(void) {
+}
+
+void DMA1_Channel4_IRQHandler(void) {
+}
+
+void DMA1_Channel5_IRQHandler(void) {
+}
+
+void DMA1_Channel6_IRQHandler(void) {
+}
+
+void DMA1_Channel7_IRQHandler(void) {
+}
+
+void ADC1_2_IRQHandler(void) {
+}
+
+void USB_HP_CAN_TX_IRQHandler(void) {
+}
+
+void USB_LP_CAN_RX0_IRQHandler(void) {
+}
+
+void CAN_RX1_IRQHandler(void) {
+}
+
+void CAN_SCE_IRQHandler(void) {
+}
+
+void TIM1_BRK_IRQHandler(void) {
+}
+
+void TIM1_UP_IRQHandler(void) {
+ while(1) {
+ }
+}
+
+void TIM1_TRG_COM_IRQHandler(void) {
+}
+
+void TIM1_CC_IRQHandler(void) {
+ while(1)
+ ;
+}
+
+void TIM2_IRQHandler(void) {
+}
+
+void TIM3_IRQHandler(void) {
+}
+
+void TIM4_IRQHandler(void) {
+}
+
+void I2C1_EV_IRQHandler(void) {
+}
+
+void I2C1_ER_IRQHandler(void) {
+}
+
+void I2C2_EV_IRQHandler(void) {
+}
+
+void I2C2_ER_IRQHandler(void) {
+}
+
+void SPI1_IRQHandler(void) {
+}
+
+void SPI2_IRQHandler(void) {
+}
+
+void USART1_IRQHandler(void) {
+#if 0
+ if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
+ {
+ /* Read one byte from the receive data register */
+ RxBuffer[RxCounter++] = (USART_ReceiveData(USART1) & 0x7F);
+
+ if(RxCounter == NbrOfDataToRead)
+ {
+ /* Disable the USART Receive interrupt */
+ USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);
+ }
+ }
+
+ if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET)
+ {
+ /* Write one byte to the transmit data register */
+ USART_SendData(USART1, TxBuffer[TxCounter++]);
+
+ if(TxCounter == NbrOfDataToTransfer)
+ {
+ /* Disable the USART1 Transmit interrupt */
+ USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
+ }
+ }
+#endif
+}
+
+void USART2_IRQHandler(void) {
+#if 0
+ if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
+ {
+ /* Echo the character back */
+ RxBuffer[0] = (USART_ReceiveData(USART2) & 0x7F);
+ USART_SendData(USART2, RxBuffer[0]);
+ // /* Read one byte from the receive data register */
+ // RxBuffer[RxCounter++] = (USART_ReceiveData(USART2) & 0x7F);
+
+ // if(RxCounter == NbrOfDataToRead)
+ // {
+ // /* Disable the USART Receive interrupt */
+ // USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);
+ // }
+ }
+
+#endif
+
+#if 0
+ if(USART_GetITStatus(USART2, USART_IT_TXE) != RESET)
+ {
+ /* Write one byte to the transmit data register */
+ USART_SendData(USART2, 'Y');
+ TxCounter++;
+// USART_SendData(USART2, TxBuffer[TxCounter++]);
+
+ if(TxCounter == NbrOfDataToTransfer) {
+ /* Disable the USART1 Transmit interrupt */
+ USART_ITConfig(USART2, USART_IT_TXE, DISABLE);
+ }
+ }
+#endif
+}
+
+void USART3_IRQHandler(void) {
+}
+
+void RTCAlarm_IRQHandler(void) {
+}
+
+void USBWakeUp_IRQHandler(void) {
+}
+
+void TIM8_BRK_IRQHandler(void) {
+}
+
+void TIM8_UP_IRQHandler(void) {
+}
+
+void TIM8_TRG_COM_IRQHandler(void) {
+}
+
+void TIM8_CC_IRQHandler(void) {
+}
+
+void ADC3_IRQHandler(void) {
+}
+
+void FSMC_IRQHandler(void) {
+}
+
+void SDIO_IRQHandler(void) {
+}
+
+void TIM5_IRQHandler(void) {
+}
+
+void SPI3_IRQHandler(void) {
+}
+
+void UART4_IRQHandler(void) {
+}
+
+void UART5_IRQHandler(void) {
+}
+
+void TIM6_IRQHandler(void) {
+}
+
+void TIM7_IRQHandler(void) {
+}
+
+void DMA2_Channel1_IRQHandler(void) {
+}
+
+void DMA2_Channel2_IRQHandler(void) {
+}
+
+void DMA2_Channel3_IRQHandler(void) {
+}
+
+void DMA2_Channel4_5_IRQHandler(void) {
+}
+#endif
diff --git a/libmaple/syscalls.c b/libmaple/syscalls.c
new file mode 100644
index 0000000..390cecd
--- /dev/null
+++ b/libmaple/syscalls.c
@@ -0,0 +1,157 @@
+#include "libmaple.h"
+#include <sys/stat.h>
+
+/* _end is set in the linker command file */
+extern caddr_t _end;
+
+/* just in case, most boards have at least some memory */
+#ifndef RAMSIZE
+# define RAMSIZE (caddr_t)0x50000
+#endif
+
+#define STACK_TOP 0x20000800
+
+void uart_send(const char*str);
+
+/*
+ * sbrk -- changes heap size size. Get nbytes more
+ * RAM. We just increment a pointer in what's
+ * left of memory on the board.
+ */
+caddr_t
+_sbrk(nbytes)
+int nbytes;
+{
+ static caddr_t heap_ptr = NULL;
+ caddr_t base;
+
+ if (heap_ptr == NULL) {
+ heap_ptr = (caddr_t)&_end;
+ }
+
+ if ((STACK_TOP - (unsigned int)heap_ptr) >= 0) {
+ base = heap_ptr;
+ heap_ptr += nbytes;
+ return (base);
+ } else {
+ uart_send("heap full!\r\n");
+ return ((caddr_t)-1);
+ }
+}
+
+int _open(const char *path, int flags, ...)
+{
+ return 1;
+}
+
+int _close(int fd)
+{
+ return 0;
+}
+
+int _fstat(int fd, struct stat *st)
+{
+ st->st_mode = S_IFCHR;
+ return 0;
+}
+
+int _isatty(int fd)
+{
+ return 1;
+}
+
+int isatty(int fd)
+{
+ return 1;
+}
+
+int _lseek(int fd, off_t pos, int whence)
+{
+ return -1;
+}
+
+unsigned char getch(void)
+{
+// while (!(USART2->SR & USART_FLAG_RXNE));
+// return USART2->DR;
+ return 0;
+}
+
+
+int _read(int fd, char *buf, size_t cnt)
+{
+ *buf = getch();
+
+ return 1;
+}
+
+void putch(unsigned char c)
+{
+// if (c == '\n') putch('\r');
+
+// while (!(USART2->SR & USART_FLAG_TXE));
+// USART2->DR = c;
+}
+
+void cgets(char *s, int bufsize)
+{
+ char *p;
+ int c;
+ int i;
+
+ for (i = 0; i < bufsize; i++) {
+ *(s+i) = 0;
+ }
+// memset(s, 0, bufsize);
+
+ p = s;
+
+ for (p = s; p < s + bufsize-1;)
+ {
+ c = getch();
+ switch (c)
+ {
+ case '\r' :
+ case '\n' :
+ putch('\r');
+ putch('\n');
+ *p = '\n';
+ return;
+
+ case '\b' :
+ if (p > s)
+ {
+ *p-- = 0;
+ putch('\b');
+ putch(' ');
+ putch('\b');
+ }
+ break;
+
+ default :
+ putch(c);
+ *p++ = c;
+ break;
+ }
+ }
+ return;
+}
+
+int _write(int fd, const char *buf, size_t cnt)
+{
+ int i;
+// uart_send("_write\r\n");
+
+ for (i = 0; i < cnt; i++)
+ putch(buf[i]);
+
+ return cnt;
+}
+
+/* Override fgets() in newlib with a version that does line editing */
+char *fgets(char *s, int bufsize, void *f)
+{
+// uart_send("fgets\r\n");
+ cgets(s, bufsize);
+ return s;
+}
diff --git a/libmaple/systick.c b/libmaple/systick.c
new file mode 100644
index 0000000..47be69e
--- /dev/null
+++ b/libmaple/systick.c
@@ -0,0 +1,52 @@
+/* *****************************************************************************
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Created: 12/18/09 02:37:24
+ * Copyright (c) 2009 Perry L. Hung. All rights reserved.
+ *
+ * ****************************************************************************/
+
+/**
+ * @file systick.c
+ *
+ * @brief System timer interrupt handler and initialization routines
+ */
+
+#include "libmaple.h"
+#include "systick.h"
+
+#define MILLIS_INC 1
+
+volatile uint32_t systick_timer_millis = 0;
+
+void systick_init(void) {
+ /* Set the reload counter to tick every 1ms */
+ REG_SET_MASK(SYSTICK_RELOAD, MAPLE_RELOAD_VAL);
+// SYSTICK_RELOAD = MAPLE_RELOAD_VAL;
+
+ /* Clock the system timer with the core clock
+ * and turn it on, interrrupt every 1ms to keep track of millis()*/
+ REG_SET(SYSTICK_CSR, SYSTICK_SRC_HCLK |
+ SYSTICK_ENABLE |
+ SYSTICK_TICKINT);
+// SYSTICK_CSR = SYSTICK_SRC_HCLK |
+// SYSTICK_ENABLE |
+// SYSTICK_TICKINT;
+}
+
+void SysTickHandler(void) {
+ systick_timer_millis++;
+}
+
+
diff --git a/libmaple/systick.h b/libmaple/systick.h
new file mode 100644
index 0000000..61789c4
--- /dev/null
+++ b/libmaple/systick.h
@@ -0,0 +1,62 @@
+/* *****************************************************************************
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Created: 12/18/09 02:37:37
+ * Copyright (c) 2009 Perry L. Hung. All rights reserved.
+ *
+ * ****************************************************************************/
+
+/**
+ * @file systick.h
+ *
+ * @brief Various system timer definitions
+ */
+
+#ifndef _SYSTICK_H_
+#define _SYSTICK_H_
+
+#include "libmaple.h"
+
+/* To the ARM technical manual... there's nearly nothing on the systick
+ * timer in the stm32 manual */
+
+#define SYSTICK_CSR 0xE000E010 // Control and status register
+#define SYSTICK_RELOAD 0xE000E014 // Reload value register
+#define SYSTICK_CNT 0xE000E018 // Current value register
+#define SYSTICK_CALIB 0xE000E01C // Calibration value register
+
+#define SYSTICK_SRC_HCLK BIT(2) // Use core clock
+#define SYSTICK_TICKINT BIT(1) // Interrupt on systick countdown
+#define SYSTICK_ENABLE BIT(0) // Turn on the counter
+
+/* We use the systick timer to tick once
+ * every millisecond */
+#define MAPLE_RELOAD_VAL 72000
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+void systick_init(void);
+
+static inline uint32_t systick_get_count(void) {
+ return (uint32_t)*(volatile uint32*)SYSTICK_CNT;
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
+
diff --git a/libmaple/timers.c b/libmaple/timers.c
new file mode 100644
index 0000000..773ae36
--- /dev/null
+++ b/libmaple/timers.c
@@ -0,0 +1,192 @@
+/* *****************************************************************************
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Created: 12/18/09 02:37:54
+ * Copyright (c) 2009 Perry L. Hung. All rights reserved.
+ *
+ * ****************************************************************************/
+
+/**
+ * @file timers.c
+ *
+ * @brief General timer routines
+ */
+
+#include "libmaple.h"
+#include "stm32f10x_rcc.h"
+#include "timers.h"
+
+typedef struct {
+ volatile uint16_t CR1;
+ uint16_t RESERVED0;
+ volatile uint16_t CR2;
+ uint16_t RESERVED1;
+ volatile uint16_t SMCR;
+ uint16_t RESERVED2;
+ volatile uint16_t DIER;
+ uint16_t RESERVED3;
+ volatile uint16_t SR;
+ uint16_t RESERVED4;
+ volatile uint16_t EGR;
+ uint16_t RESERVED5;
+ volatile uint16_t CCMR1;
+ uint16_t RESERVED6;
+ volatile uint16_t CCMR2;
+ uint16_t RESERVED7;
+ volatile uint16_t CCER;
+ uint16_t RESERVED8;
+ volatile uint16_t CNT;
+ uint16_t RESERVED9;
+ volatile uint16_t PSC;
+ uint16_t RESERVED10;
+ volatile uint16_t ARR;
+ uint16_t RESERVED11;
+ volatile uint16_t RCR;
+ uint16_t RESERVED12;
+ volatile uint16_t CCR1;
+ uint16_t RESERVED13;
+ volatile uint16_t CCR2;
+ uint16_t RESERVED14;
+ volatile uint16_t CCR3;
+ uint16_t RESERVED15;
+ volatile uint16_t CCR4;
+ uint16_t RESERVED16;
+ volatile uint16_t BDTR; // Not used in general purpose timers
+ uint16_t RESERVED17; // Not used in general purpose timers
+ volatile uint16_t DCR;
+ uint16_t RESERVED18;
+ volatile uint16_t DMAR;
+ uint16_t RESERVED19;
+} Timer;
+
+void timer_init(uint8_t timer_num, uint16_t prescale) {
+ Timer *timer;
+ uint32_t is_advanced = 0;
+
+ ASSERT(timer_num > 0 && timer_num <= 4);
+
+ switch(timer_num) {
+ case 1:
+ timer = (Timer*)TIMER1_BASE;
+ RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
+ is_advanced = 1;
+ break;
+ case 2:
+ timer = (Timer*)TIMER2_BASE;
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
+ break;
+ case 3:
+ timer = (Timer*)TIMER3_BASE;
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
+ break;
+ case 4:
+ timer = (Timer*)TIMER4_BASE;
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
+ break;
+ }
+
+ 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->CCER |= 0x001; // enable ch
+
+ timer->CCR2 = 0x8FFF; // PWM start value
+ timer->CCMR1 |= (0x68 << 8);// PWM mode 1, enable preload register.
+ timer->CCER |= 0x010; // enable ch
+
+ timer->CCR3 = 0x8FFF; // PWM start value
+ timer->CCMR2 |= 0x68; // PWM mode 1, enable preload register.
+ timer->CCER |= 0x100; // enable ch
+
+ timer->CCR4 = 0x8FFF; // PWM start value
+ timer->CCMR2 |= (0x68 << 8);// PWM mode 1, enable preload register.
+ timer->CCER |= 0x1000; // enable ch
+
+ /* Advanced timer? */
+ if (is_advanced) {
+ timer->BDTR = 0x8000; // moe enable
+ }
+
+ timer->DIER = 0; // disable update interrupt
+ timer->EGR = 1; // Initialize update event and shadow registers
+ timer->CR1 |= 1; // Enable timer
+}
+
+void timers_disable(void) {
+ Timer *timer;
+ int i;
+ Timer *timers[4] = {
+ (Timer*)TIMER1_BASE,
+ (Timer*)TIMER2_BASE,
+ (Timer*)TIMER3_BASE,
+ (Timer*)TIMER4_BASE,
+ };
+
+ for (i = 0; i < 4; i++) {
+ timer = timers[i];
+ timer->CR1 = 0;
+ timer->CCER = 0;
+ }
+}
+
+void timers_disable_channel(uint8 timer_num, uint8 channel) {
+ Timer *timer;
+ switch (timer_num) {
+ case 1:
+ timer = (Timer*)TIMER1_BASE;
+ break;
+ case 2:
+ timer = (Timer*)TIMER2_BASE;
+ break;
+ case 3:
+ timer = (Timer*)TIMER3_BASE;
+ break;
+ case 4:
+ timer = (Timer*)TIMER4_BASE;
+ break;
+ default:
+ ASSERT(0);
+ }
+
+ switch (channel) {
+ case 1:
+ timer->CCER &= ~(0x1);
+ break;
+ case 2:
+ timer->CCER &= ~(0x10);
+ break;
+ case 3:
+ timer->CCER &= ~(0x100);
+ break;
+ case 4:
+ timer->CCER &= ~(0x1000);
+ break;
+ default:
+ ASSERT(0);
+ }
+}
diff --git a/libmaple/timers.h b/libmaple/timers.h
new file mode 100644
index 0000000..18b0afb
--- /dev/null
+++ b/libmaple/timers.h
@@ -0,0 +1,145 @@
+/* *****************************************************************************
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Created: 12/18/09 02:38:10
+ * Copyright (c) 2009 Perry L. Hung. All rights reserved.
+ *
+ * ****************************************************************************/
+
+/**
+ * @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_
+#include <inttypes.h>
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+typedef volatile uint32_t* TimerCCR;
+
+#define TIMER1_BASE 0x40012C00
+#define TIMER2_BASE 0x40000000
+#define TIMER3_BASE 0x40000400
+#define TIMER4_BASE 0x40000800
+
+#define ARPE BIT(7) // Auto-reload preload enable
+#define NOT_A_TIMER 0
+
+#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)
+
+
+/* Turn on timer with prescale as the divisor
+ * void timer_init(uint32_t timer, uint16_t prescale)
+ * timer -> {1-4}
+ * prescale -> {1-65535}
+ * */
+void timer_init(uint8_t, uint16_t);
+void timers_disable(void);
+void timers_disable_channel(uint8, uint8);
+
+/* Turn on PWM with duty_cycle on the specified channel in timer.
+ * This function takes in a pointer to the corresponding CCR
+ * register for the pin cause it saves pwmWrite() a couple of
+ * cycles.
+ *
+ * void timer_pwm(uint8_t channel, uint8_t duty_cycle);
+ * channel -> {TIMERx_CHn_CCR}
+ * duty_cycle -> {0-65535}
+ *
+ * PRECONDITIONS:
+ * pin has been set to alternate function output
+ * timer has been initialized
+ */
+static inline void timer_pwm_write_ccr(TimerCCR CCR, uint16_t duty_cycle) {
+ *CCR = duty_cycle;
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+
+#endif
+
diff --git a/libmaple/usart.c b/libmaple/usart.c
new file mode 100644
index 0000000..9987641
--- /dev/null
+++ b/libmaple/usart.c
@@ -0,0 +1,345 @@
+/* *****************************************************************************
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Created: 12/18/09 02:38:26
+ * Copyright (c) 2009 Perry L. Hung. All rights reserved.
+ *
+ * ****************************************************************************/
+
+/**
+ * @file usart.c
+ *
+ * @brief USART control routines
+ */
+
+#include "libmaple.h"
+#include "stm32f10x_rcc.h"
+#include "usart.h"
+#include "nvic.h"
+
+#define USART1_BASE 0x40013800
+#define USART2_BASE 0x40004400
+#define USART3_BASE 0x40004800
+
+#define USART_UE BIT(13)
+#define USART_M BIT(12)
+#define USART_TE BIT(3)
+#define USART_RE BIT(2)
+#define USART_RXNEIE BIT(5) // read data register not empty interrupt enable
+#define USART_TXE BIT(7)
+#define USART_TC BIT(6)
+
+#define USART_STOP_BITS_1 BIT_MASK_SHIFT(0b0, 12)
+#define USART_STOP_BITS_05 BIT_MASK_SHIFT(0b01, 12)
+#define USART_STOP_BITS_2 BIT_MASK_SHIFT(0b02, 12)
+#define USART_STOP_BITS_15 BIT_MASK_SHIFT(0b02, 12)
+
+#define USART1_CLK 72000000UL
+#define USART2_CLK 36000000UL
+#define USART3_CLK 36000000UL
+
+#define USART_RECV_BUF_SIZE 64
+
+/* Ring buffer notes:
+ * The buffer is empty when head == tail.
+ * The buffer is full when the head is one byte in front of the tail
+ * The total buffer size must be a power of two
+ * Note, one byte is necessarily left free with this scheme */
+typedef struct usart_ring_buf {
+ uint32 head;
+ uint32 tail;
+ uint8 buf[USART_RECV_BUF_SIZE];
+} usart_ring_buf;
+
+static usart_ring_buf ring_buf1;
+static usart_ring_buf ring_buf2;
+static usart_ring_buf ring_buf3;
+
+typedef struct usart_port {
+ volatile uint32 SR; // Status register
+ volatile uint32 DR; // Data register
+ volatile uint32 BRR; // Baud rate register
+ volatile uint32 CR1; // Control register 1
+ volatile uint32 CR2; // Control register 2
+ volatile uint32 CR3; // Control register 3
+ volatile uint32 GTPR; // Guard time and prescaler register
+} usart_port;
+
+void USART1_IRQHandler(void) {
+ /* Read the data */
+ ring_buf1.buf[ring_buf1.tail++] = (uint8_t)(((usart_port*)(USART1_BASE))->DR);
+ ring_buf1.tail %= USART_RECV_BUF_SIZE;
+}
+
+/* Don't overrun your buffer, seriously */
+void USART2_IRQHandler(void) {
+ /* Read the data */
+ ring_buf2.buf[ring_buf2.tail++] = (uint8_t)(((usart_port*)(USART2_BASE))->DR);
+ ring_buf2.tail %= USART_RECV_BUF_SIZE;
+}
+/* Don't overrun your buffer, seriously */
+void USART3_IRQHandler(void) {
+ /* Read the data */
+ ring_buf3.buf[ring_buf3.tail++] = (uint8_t)(((usart_port*)(USART3_BASE))->DR);
+ ring_buf3.tail %= USART_RECV_BUF_SIZE;
+}
+
+/**
+ * @brief Enable a USART in single buffer transmission mode, multibuffer
+ * receiver mode.
+ *
+ * @param usart_num USART to be initialized
+ * @param baud Baud rate to be set at
+ * @param recvBuf buf buffer for receiver
+ * @param len size of recvBuf
+ *
+ * @sideeffect Turns on the specified USART
+ */
+void usart_init(uint8 usart_num, uint32 baud) {
+ ASSERT((usart_num <= NR_USARTS) && (usart_num > 0));
+ ASSERT(baud && (baud < USART_MAX_BAUD));
+
+ usart_port *port;
+ usart_ring_buf *ring_buf;
+
+ uint32 clk_speed;
+ uint32 integer_part;
+ uint32 fractional_part;
+ uint32 tmp;
+
+ switch (usart_num) {
+ case 1:
+ port = (usart_port*)USART1_BASE;
+ ring_buf = &ring_buf1;
+ clk_speed = USART1_CLK;
+ RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
+ REG_SET(NVIC_ISER1, BIT(5));
+ break;
+ case 2:
+ port = (usart_port*)USART2_BASE;
+ ring_buf = &ring_buf2;
+ clk_speed = USART2_CLK;
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
+ REG_SET(NVIC_ISER1, BIT(6));
+ break;
+ case 3:
+ port = (usart_port*)USART3_BASE;
+ ring_buf = &ring_buf3;
+ clk_speed = USART3_CLK;
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
+ REG_SET(NVIC_ISER1, BIT(7));
+ break;
+ default:
+ /* should never get here */
+ ASSERT(0);
+ }
+
+ /* Initialize ring buffer */
+ ring_buf->head = 0;
+ ring_buf->tail = 0;
+
+ /* Set baud rate */
+ integer_part = ((25 * clk_speed) / (4 * baud));
+ tmp = (integer_part / 100) << 4;
+
+ fractional_part = integer_part - (100 * (tmp >> 4));
+ tmp |= (((fractional_part * 16) + 50) / 100) & ((uint8)0x0F);
+
+ port->BRR = (uint16_t)tmp;
+
+ port->CR1 = USART_TE | // transmitter enable
+ USART_RE | // receiver enable
+ USART_RXNEIE; // receive interrupt enable
+
+
+ /* Enable the USART and set mode to 8n1 */
+ port->CR1 |= USART_UE;
+}
+
+
+/**
+ * @brief Turn off a USART.
+ *
+ * @param USART to be disabled
+ *
+ * @sideeffect Turns off the specified USART
+ */
+void usart_disable(uint8 usart_num) {
+ ASSERT((usart_num <= NR_USARTS) && (usart_num > 0));
+ usart_port *port;
+
+ switch (usart_num) {
+ case 1:
+ port = (usart_port*)USART1_BASE;
+ break;
+ case 2:
+ port = (usart_port*)USART2_BASE;
+ break;
+ case 3:
+ port = (usart_port*)USART3_BASE;
+ break;
+ default:
+ /* should never get here */
+ ASSERT(0);
+ }
+
+ /* Is this usart enabled? */
+ if (!(port->SR & USART_UE))
+ return;
+
+ /* TC bit must be high before disabling the usart */
+ while ((port->SR & USART_TC) == 0)
+ ;
+
+ /* Disable UE */
+ port->CR1 = 0;
+}
+
+
+/**
+ * @brief Print a null terminated string to the specified USART
+ *
+ * @param[in] usart_num USART to send on
+ * @param[in] str String to send
+ */
+void usart_putstr(uint8 usart_num, const char* str) {
+ ASSERT((usart_num <= NR_USARTS) && (usart_num > 0));
+ char ch;
+
+ while((ch = *(str++)) != '\0') {
+ usart_putc(usart_num, ch);
+ }
+}
+
+/**
+ * @brief Print an unsigned integer to the specified usart
+ *
+ * @param[in] usart_num usart to send on
+ * @param[in] val number to print
+ */
+void usart_putudec(uint8 usart_num, uint32 val) {
+ ASSERT((usart_num <= NR_USARTS) && (usart_num > 0));
+ char digits[12];
+ int i;
+
+ i = 0;
+ do {
+ digits[i++] = val % 10 + '0';
+ val /= 10;
+ } while (val > 0);
+ while (--i >= 0) {
+ usart_putc(usart_num, digits[i]);
+ }
+
+}
+
+
+/**
+ * @brief Return one character from the receive buffer. Assumes
+ * that there is data available.
+ *
+ * @param[in] usart_num number of the usart to read from
+ *
+ * @return character from ring buffer
+ *
+ * @sideeffect may update the head pointer of the recv buffer
+ */
+uint8 usart_getc(uint8 usart_num) {
+ uint8 ch;
+ usart_ring_buf *rb;
+
+ switch (usart_num) {
+ case 1:
+ rb = &ring_buf1;
+ break;
+ case 2:
+ rb = &ring_buf2;
+ break;
+ case 3:
+ rb = &ring_buf3;
+ break;
+ default:
+ ASSERT(0);
+ }
+
+ /* Make sure there's actually data to be read */
+ ASSERT(rb->head != rb->tail);
+
+ /* Read the data and check for wraparound */
+ ch = rb->buf[rb->head++];
+ rb->head %= USART_RECV_BUF_SIZE;
+
+ return ch;
+}
+
+uint32 usart_data_available(uint8 usart_num) {
+ usart_ring_buf *rb;
+
+ switch (usart_num) {
+ case 1:
+ rb = &ring_buf1;
+ break;
+ case 2:
+ rb = &ring_buf2;
+ break;
+ case 3:
+ rb = &ring_buf3;
+ break;
+ default:
+ ASSERT(0);
+ }
+
+ return rb->tail - rb->head;
+}
+
+
+
+/**
+ * @brief Output a byte out the uart
+ *
+ * @param[in] usart_num usart number to output on
+ * @param[in] byte byte to send
+ *
+ */
+void usart_putc(uint8 usart_num, uint8 byte) {
+ ASSERT((usart_num <= NR_USARTS) && (usart_num > 0));
+ usart_port *port;
+
+ switch (usart_num) {
+ case 1:
+ port = (usart_port*)USART1_BASE;
+ break;
+ case 2:
+ port = (usart_port*)USART2_BASE;
+ break;
+ case 3:
+ port = (usart_port*)USART3_BASE;
+ break;
+ default:
+ /* Should never get here */
+ ASSERT(0);
+ }
+
+// if (ch == '\n') {
+// usart_putc(usart_num, '\r');
+// }
+
+ port->DR = byte;
+
+ /* Wait for transmission to complete */
+ while ((port->SR & USART_TXE) == 0)
+ ;
+}
+
+
diff --git a/libmaple/usart.h b/libmaple/usart.h
new file mode 100644
index 0000000..b9efdd5
--- /dev/null
+++ b/libmaple/usart.h
@@ -0,0 +1,53 @@
+/* *****************************************************************************
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Created: 12/18/09 02:38:35
+ * Copyright (c) 2009 Perry L. Hung. All rights reserved.
+ *
+ * ****************************************************************************/
+
+/**
+ * @file usart.h
+ *
+ * @brief USART Definitions
+ */
+
+#ifndef _USART_H_
+#define _USART_H_
+
+#define NR_USARTS 0x3
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#define USART_MAX_BAUD 225000
+
+void usart_init(uint8 usart_num, uint32 baud);
+void usart_disable(uint8 usart_num);
+
+void usart_putstr(uint8 usart_num, const char*);
+void usart_putudec(uint8 usart_num, uint32 val);
+void usart_putc(uint8 usart_num, uint8 ch);
+
+uint32 usart_data_available(uint8 usart_num);
+uint8 usart_getc(uint8 usart_num);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+
+#endif
+
diff --git a/libmaple/usb.c b/libmaple/usb.c
new file mode 100644
index 0000000..8c312f8
--- /dev/null
+++ b/libmaple/usb.c
@@ -0,0 +1,83 @@
+#include <inttypes.h>
+#include "usb.h"
+
+void usb_lpIRQHandler(void)
+{
+ typedef void (*funcPtr)(void);
+
+ const uint32_t usbIsrAddr = *(uint32_t*)(USB_ISR_ADDR);
+ void (*ptrToUsbISR)(void) = (funcPtr) usbIsrAddr;
+ ptrToUsbISR();
+}
+
+void usb_userToPMABufferCopy(u8 *pbUsrBuf, u16 wPMABufAddr, u16 wNBytes)
+{
+ u32 n = (wNBytes + 1) >> 1; /* n = (wNBytes + 1) / 2 */
+ u32 i, temp1, temp2;
+ u16 *pdwVal;
+ pdwVal = (u16 *)(wPMABufAddr * 2 + PMAAddr);
+ for (i = n; i != 0; i--)
+ {
+ temp1 = (u16) * pbUsrBuf;
+ pbUsrBuf++;
+ temp2 = temp1 | (u16) * pbUsrBuf << 8;
+ *pdwVal++ = temp2;
+ pdwVal++;
+ pbUsrBuf++;
+ }
+}
+
+void usb_PMAToUserBufferCopy(u8 *pbUsrBuf, u16 wPMABufAddr, u16 wNBytes)
+{
+ u32 n = (wNBytes + 1) >> 1;/* /2*/
+ u32 i;
+ u32 *pdwVal;
+ pdwVal = (u32 *)(wPMABufAddr * 2 + PMAAddr);
+ for (i = n; i != 0; i--)
+ {
+ *(u16*)pbUsrBuf++ = *pdwVal++;
+ pbUsrBuf++;
+ }
+}
+
+void usb_serialWriteStr(const char* outStr) {
+ u8 offset=0;
+ BootVectTable *bootVector = ((BootVectTable*)BOOTLOADER_VECT_TABLE);
+
+ while ((outStr[offset] != '\0')
+ && (offset < USB_SERIAL_BUF_SIZE)) {
+ offset++;
+ }
+
+ delay(offset*1);
+
+ bootVector->serial_count_in = (u32*) &offset;
+ usb_userToPMABufferCopy((u8*)outStr,USB_SERIAL_ENDP_TXADDR,offset);
+ _SetEPTxCount(USB_SERIAL_ENDP_TX,offset);
+ _SetEPTxValid(USB_SERIAL_ENDP_TX);
+
+}
+
+void usb_serialWriteChar(unsigned char ch) {
+ BootVectTable *bootVector = ((BootVectTable*)BOOTLOADER_VECT_TABLE);
+
+ delay(1);
+
+ *(bootVector->serial_count_in) = 1;
+ usb_userToPMABufferCopy((u8*)(&ch),USB_SERIAL_ENDP_TXADDR,1);
+ _SetEPTxCount(USB_SERIAL_ENDP_TX,1);
+ _SetEPTxValid(USB_SERIAL_ENDP_TX);
+
+}
+
+uint8_t usb_serialGetRecvLen() {
+ uint8_t count_out =_GetEPRxCount(USB_SERIAL_ENDP_RX);
+ return count_out;
+}
+
+void usb_copyRecvBuffer(unsigned char* dest, uint8_t len) {
+ ASSERT(len < USB_SERIAL_BUF_SIZE);
+ usb_PMAToUserBufferCopy((u8*)(dest),USB_SERIAL_ENDP_RXADDR,len);
+ _SetEPRxValid(USB_SERIAL_ENDP_RX);
+}
+
diff --git a/libmaple/usb.h b/libmaple/usb.h
new file mode 100644
index 0000000..3b7a971
--- /dev/null
+++ b/libmaple/usb.h
@@ -0,0 +1,32 @@
+#ifndef _USB_H_
+#define _USB_H_
+
+#include <inttypes.h>
+#include "util.h"
+#include "cortexm3_macro.h"
+#include "usb_regs.h"
+#include "bootVect.h"
+
+#define USB_ISR_ADDR (0x08000090)
+#define USB_SERIAL_ENDP_TXADDR ((uint32_t) 0xC0)
+#define USB_SERIAL_ENDP_RXADDR ((uint32_t) 0x110)
+#define USB_SERIAL_ENDP_TX ((uint16_t) 0x1)
+#define USB_SERIAL_ENDP_RX ((uint16_t) 0x3)
+#define USB_SERIAL_BUF_SIZE (0x40)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void usb_lpIRQHandler(void);
+void usb_userToPMABufferCopy(u8 *pbUsrBuf,u16 wPMABufAddr,u16 wNBytes);
+void usb_PMAToUserBufferCopy(u8 *pbUsrBuf,u16 wPMABufAddr,u16 wNBytes);
+void usb_serialWriteStr(const char *outStr);
+void usb_serialWriteChar(unsigned char ch);
+uint8_t usb_serialGetRecvLen();
+void usb_copyRecvBuffer(unsigned char* dest, uint8_t len);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+#endif //_USB_H
diff --git a/libmaple/usb_regs.h b/libmaple/usb_regs.h
new file mode 100644
index 0000000..135d645
--- /dev/null
+++ b/libmaple/usb_regs.h
@@ -0,0 +1,555 @@
+/******************** (C) COPYRIGHT 2008 STMicroelectronics ********************
+* File Name : usb_regs.h
+* Author : MCD Application Team
+* Version : V2.2.1
+* Date : 09/22/2008
+* Description : Interface prototype functions to USB cell registers
+********************************************************************************
+* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
+* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
+* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
+* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
+* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+*******************************************************************************/
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __USB_REGS_H
+#define __USB_REGS_H
+
+/* Includes ------------------------------------------------------------------*/
+/* Exported types ------------------------------------------------------------*/
+#include "stm32f10x_type.h"
+
+typedef enum _EP_DBUF_DIR
+{
+ /* double buffered endpoint direction */
+ EP_DBUF_ERR,
+ EP_DBUF_OUT,
+ EP_DBUF_IN
+}EP_DBUF_DIR;
+
+/* endpoint buffer number */
+enum EP_BUF_NUM
+{
+ EP_NOBUF,
+ EP_BUF0,
+ EP_BUF1
+};
+
+/* Exported constants --------------------------------------------------------*/
+#define RegBase (0x40005C00L) /* USB_IP Peripheral Registers base address */
+#define PMAAddr (0x40006000L) /* USB_IP Packet Memory Area base address */
+
+/******************************************************************************/
+/* General registers */
+/******************************************************************************/
+
+/* Control register */
+#define CNTR ((volatile unsigned *)(RegBase + 0x40))
+/* Interrupt status register */
+#define ISTR ((volatile unsigned *)(RegBase + 0x44))
+/* Frame number register */
+#define FNR ((volatile unsigned *)(RegBase + 0x48))
+/* Device address register */
+#define DADDR ((volatile unsigned *)(RegBase + 0x4C))
+/* Buffer Table address register */
+#define BTABLE ((volatile unsigned *)(RegBase + 0x50))
+/******************************************************************************/
+/* Endpoint registers */
+/******************************************************************************/
+#define EP0REG ((volatile unsigned *)(RegBase)) /* endpoint 0 register address */
+
+/* endpoints enumeration */
+#define ENDP0 ((u8)0)
+#define ENDP1 ((u8)1)
+#define ENDP2 ((u8)2)
+#define ENDP3 ((u8)3)
+#define ENDP4 ((u8)4)
+#define ENDP5 ((u8)5)
+#define ENDP6 ((u8)6)
+#define ENDP7 ((u8)7)
+/******************************************************************************/
+/* ISTR interrupt events */
+/******************************************************************************/
+#define ISTR_CTR (0x8000) /* Correct TRansfer (clear-only bit) */
+#define ISTR_DOVR (0x4000) /* DMA OVeR/underrun (clear-only bit) */
+#define ISTR_ERR (0x2000) /* ERRor (clear-only bit) */
+#define ISTR_WKUP (0x1000) /* WaKe UP (clear-only bit) */
+#define ISTR_SUSP (0x0800) /* SUSPend (clear-only bit) */
+#define ISTR_RESET (0x0400) /* RESET (clear-only bit) */
+#define ISTR_SOF (0x0200) /* Start Of Frame (clear-only bit) */
+#define ISTR_ESOF (0x0100) /* Expected Start Of Frame (clear-only bit) */
+
+
+#define ISTR_DIR (0x0010) /* DIRection of transaction (read-only bit) */
+#define ISTR_EP_ID (0x000F) /* EndPoint IDentifier (read-only bit) */
+
+#define CLR_CTR (~ISTR_CTR) /* clear Correct TRansfer bit */
+#define CLR_DOVR (~ISTR_DOVR) /* clear DMA OVeR/underrun bit*/
+#define CLR_ERR (~ISTR_ERR) /* clear ERRor bit */
+#define CLR_WKUP (~ISTR_WKUP) /* clear WaKe UP bit */
+#define CLR_SUSP (~ISTR_SUSP) /* clear SUSPend bit */
+#define CLR_RESET (~ISTR_RESET) /* clear RESET bit */
+#define CLR_SOF (~ISTR_SOF) /* clear Start Of Frame bit */
+#define CLR_ESOF (~ISTR_ESOF) /* clear Expected Start Of Frame bit */
+
+/******************************************************************************/
+/* CNTR control register bits definitions */
+/******************************************************************************/
+#define CNTR_CTRM (0x8000) /* Correct TRansfer Mask */
+#define CNTR_DOVRM (0x4000) /* DMA OVeR/underrun Mask */
+#define CNTR_ERRM (0x2000) /* ERRor Mask */
+#define CNTR_WKUPM (0x1000) /* WaKe UP Mask */
+#define CNTR_SUSPM (0x0800) /* SUSPend Mask */
+#define CNTR_RESETM (0x0400) /* RESET Mask */
+#define CNTR_SOFM (0x0200) /* Start Of Frame Mask */
+#define CNTR_ESOFM (0x0100) /* Expected Start Of Frame Mask */
+
+
+#define CNTR_RESUME (0x0010) /* RESUME request */
+#define CNTR_FSUSP (0x0008) /* Force SUSPend */
+#define CNTR_LPMODE (0x0004) /* Low-power MODE */
+#define CNTR_PDWN (0x0002) /* Power DoWN */
+#define CNTR_FRES (0x0001) /* Force USB RESet */
+
+/******************************************************************************/
+/* FNR Frame Number Register bit definitions */
+/******************************************************************************/
+#define FNR_RXDP (0x8000) /* status of D+ data line */
+#define FNR_RXDM (0x4000) /* status of D- data line */
+#define FNR_LCK (0x2000) /* LoCKed */
+#define FNR_LSOF (0x1800) /* Lost SOF */
+#define FNR_FN (0x07FF) /* Frame Number */
+/******************************************************************************/
+/* DADDR Device ADDRess bit definitions */
+/******************************************************************************/
+#define DADDR_EF (0x80)
+#define DADDR_ADD (0x7F)
+/******************************************************************************/
+/* Endpoint register */
+/******************************************************************************/
+/* bit positions */
+#define EP_CTR_RX (0x8000) /* EndPoint Correct TRansfer RX */
+#define EP_DTOG_RX (0x4000) /* EndPoint Data TOGGLE RX */
+#define EPRX_STAT (0x3000) /* EndPoint RX STATus bit field */
+#define EP_SETUP (0x0800) /* EndPoint SETUP */
+#define EP_T_FIELD (0x0600) /* EndPoint TYPE */
+#define EP_KIND (0x0100) /* EndPoint KIND */
+#define EP_CTR_TX (0x0080) /* EndPoint Correct TRansfer TX */
+#define EP_DTOG_TX (0x0040) /* EndPoint Data TOGGLE TX */
+#define EPTX_STAT (0x0030) /* EndPoint TX STATus bit field */
+#define EPADDR_FIELD (0x000F) /* EndPoint ADDRess FIELD */
+
+/* EndPoint REGister MASK (no toggle fields) */
+#define EPREG_MASK (EP_CTR_RX|EP_SETUP|EP_T_FIELD|EP_KIND|EP_CTR_TX|EPADDR_FIELD)
+
+/* EP_TYPE[1:0] EndPoint TYPE */
+#define EP_TYPE_MASK (0x0600) /* EndPoint TYPE Mask */
+#define EP_BULK (0x0000) /* EndPoint BULK */
+#define EP_CONTROL (0x0200) /* EndPoint CONTROL */
+#define EP_ISOCHRONOUS (0x0400) /* EndPoint ISOCHRONOUS */
+#define EP_INTERRUPT (0x0600) /* EndPoint INTERRUPT */
+#define EP_T_MASK (~EP_T_FIELD & EPREG_MASK)
+
+
+/* EP_KIND EndPoint KIND */
+#define EPKIND_MASK (~EP_KIND & EPREG_MASK)
+
+/* STAT_TX[1:0] STATus for TX transfer */
+#define EP_TX_DIS (0x0000) /* EndPoint TX DISabled */
+#define EP_TX_STALL (0x0010) /* EndPoint TX STALLed */
+#define EP_TX_NAK (0x0020) /* EndPoint TX NAKed */
+#define EP_TX_VALID (0x0030) /* EndPoint TX VALID */
+#define EPTX_DTOG1 (0x0010) /* EndPoint TX Data TOGgle bit1 */
+#define EPTX_DTOG2 (0x0020) /* EndPoint TX Data TOGgle bit2 */
+#define EPTX_DTOGMASK (EPTX_STAT|EPREG_MASK)
+
+/* STAT_RX[1:0] STATus for RX transfer */
+#define EP_RX_DIS (0x0000) /* EndPoint RX DISabled */
+#define EP_RX_STALL (0x1000) /* EndPoint RX STALLed */
+#define EP_RX_NAK (0x2000) /* EndPoint RX NAKed */
+#define EP_RX_VALID (0x3000) /* EndPoint RX VALID */
+#define EPRX_DTOG1 (0x1000) /* EndPoint RX Data TOGgle bit1 */
+#define EPRX_DTOG2 (0x2000) /* EndPoint RX Data TOGgle bit1 */
+#define EPRX_DTOGMASK (EPRX_STAT|EPREG_MASK)
+/* Exported macro ------------------------------------------------------------*/
+/* SetCNTR */
+#define _SetCNTR(wRegValue) (*CNTR = (u16)wRegValue)
+
+/* SetISTR */
+#define _SetISTR(wRegValue) (*ISTR = (u16)wRegValue)
+
+/* SetDADDR */
+#define _SetDADDR(wRegValue) (*DADDR = (u16)wRegValue)
+
+/* SetBTABLE */
+#define _SetBTABLE(wRegValue)(*BTABLE = (u16)(wRegValue & 0xFFF8))
+
+/* GetCNTR */
+#define _GetCNTR() ((u16) *CNTR)
+
+/* GetISTR */
+#define _GetISTR() ((u16) *ISTR)
+
+/* GetFNR */
+#define _GetFNR() ((u16) *FNR)
+
+/* GetDADDR */
+#define _GetDADDR() ((u16) *DADDR)
+
+/* GetBTABLE */
+#define _GetBTABLE() ((u16) *BTABLE)
+
+/* SetENDPOINT */
+#define _SetENDPOINT(bEpNum,wRegValue) (*(EP0REG + bEpNum)= \
+ (u16)wRegValue)
+
+/* GetENDPOINT */
+#define _GetENDPOINT(bEpNum) ((u16)(*(EP0REG + bEpNum)))
+
+/*******************************************************************************
+* Macro Name : SetEPType
+* Description : sets the type in the endpoint register(bits EP_TYPE[1:0])
+* Input : bEpNum: Endpoint Number.
+* wType
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _SetEPType(bEpNum,wType) (_SetENDPOINT(bEpNum,\
+ ((_GetENDPOINT(bEpNum) & EP_T_MASK) | wType)))
+
+/*******************************************************************************
+* Macro Name : GetEPType
+* Description : gets the type in the endpoint register(bits EP_TYPE[1:0])
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : Endpoint Type
+*******************************************************************************/
+#define _GetEPType(bEpNum) (_GetENDPOINT(bEpNum) & EP_T_FIELD)
+
+/*******************************************************************************
+* Macro Name : SetEPTxStatus
+* Description : sets the status for tx transfer (bits STAT_TX[1:0]).
+* Input : bEpNum: Endpoint Number.
+* wState: new state
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _SetEPTxStatus(bEpNum,wState) {\
+ register u16 _wRegVal; \
+ _wRegVal = _GetENDPOINT(bEpNum) & EPTX_DTOGMASK;\
+ /* toggle first bit ? */ \
+ if((EPTX_DTOG1 & wState)!= 0) \
+ _wRegVal ^= EPTX_DTOG1; \
+ /* toggle second bit ? */ \
+ if((EPTX_DTOG2 & wState)!= 0) \
+ _wRegVal ^= EPTX_DTOG2; \
+ _SetENDPOINT(bEpNum, _wRegVal); \
+ } /* _SetEPTxStatus */
+
+/*******************************************************************************
+* Macro Name : SetEPRxStatus
+* Description : sets the status for rx transfer (bits STAT_TX[1:0])
+* Input : bEpNum: Endpoint Number.
+* wState: new state.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _SetEPRxStatus(bEpNum,wState) {\
+ register u16 _wRegVal; \
+ \
+ _wRegVal = _GetENDPOINT(bEpNum) & EPRX_DTOGMASK;\
+ /* toggle first bit ? */ \
+ if((EPRX_DTOG1 & wState)!= 0) \
+ _wRegVal ^= EPRX_DTOG1; \
+ /* toggle second bit ? */ \
+ if((EPRX_DTOG2 & wState)!= 0) \
+ _wRegVal ^= EPRX_DTOG2; \
+ _SetENDPOINT(bEpNum, _wRegVal); \
+ } /* _SetEPRxStatus */
+/*******************************************************************************
+* Macro Name : GetEPTxStatus / GetEPRxStatus
+* Description : gets the status for tx/rx transfer (bits STAT_TX[1:0]
+* /STAT_RX[1:0])
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : status .
+*******************************************************************************/
+#define _GetEPTxStatus(bEpNum) ((u16)_GetENDPOINT(bEpNum) & EPTX_STAT)
+
+#define _GetEPRxStatus(bEpNum) ((u16)_GetENDPOINT(bEpNum) & EPRX_STAT)
+
+/*******************************************************************************
+* Macro Name : SetEPTxValid / SetEPRxValid
+* Description : sets directly the VALID tx/rx-status into the enpoint register
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _SetEPTxValid(bEpNum) (_SetEPTxStatus(bEpNum, EP_TX_VALID))
+
+#define _SetEPRxValid(bEpNum) (_SetEPRxStatus(bEpNum, EP_RX_VALID))
+
+/*******************************************************************************
+* Macro Name : GetTxStallStatus / GetRxStallStatus.
+* Description : checks stall condition in an endpoint.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : TRUE = endpoint in stall condition.
+*******************************************************************************/
+#define _GetTxStallStatus(bEpNum) (_GetEPTxStatus(bEpNum) \
+ == EP_TX_STALL)
+#define _GetRxStallStatus(bEpNum) (_GetEPRxStatus(bEpNum) \
+ == EP_RX_STALL)
+
+/*******************************************************************************
+* Macro Name : SetEP_KIND / ClearEP_KIND.
+* Description : set & clear EP_KIND bit.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _SetEP_KIND(bEpNum) (_SetENDPOINT(bEpNum, \
+ (_GetENDPOINT(bEpNum) | EP_KIND) & EPREG_MASK))
+#define _ClearEP_KIND(bEpNum) (_SetENDPOINT(bEpNum, \
+ (_GetENDPOINT(bEpNum) & EPKIND_MASK)))
+
+/*******************************************************************************
+* Macro Name : Set_Status_Out / Clear_Status_Out.
+* Description : Sets/clears directly STATUS_OUT bit in the endpoint register.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _Set_Status_Out(bEpNum) _SetEP_KIND(bEpNum)
+#define _Clear_Status_Out(bEpNum) _ClearEP_KIND(bEpNum)
+
+/*******************************************************************************
+* Macro Name : SetEPDoubleBuff / ClearEPDoubleBuff.
+* Description : Sets/clears directly EP_KIND bit in the endpoint register.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _SetEPDoubleBuff(bEpNum) _SetEP_KIND(bEpNum)
+#define _ClearEPDoubleBuff(bEpNum) _ClearEP_KIND(bEpNum)
+
+/*******************************************************************************
+* Macro Name : ClearEP_CTR_RX / ClearEP_CTR_TX.
+* Description : Clears bit CTR_RX / CTR_TX in the endpoint register.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _ClearEP_CTR_RX(bEpNum) (_SetENDPOINT(bEpNum,\
+ _GetENDPOINT(bEpNum) & 0x7FFF & EPREG_MASK))
+#define _ClearEP_CTR_TX(bEpNum) (_SetENDPOINT(bEpNum,\
+ _GetENDPOINT(bEpNum) & 0xFF7F & EPREG_MASK))
+
+/*******************************************************************************
+* Macro Name : ToggleDTOG_RX / ToggleDTOG_TX .
+* Description : Toggles DTOG_RX / DTOG_TX bit in the endpoint register.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _ToggleDTOG_RX(bEpNum) (_SetENDPOINT(bEpNum, \
+ EP_DTOG_RX | _GetENDPOINT(bEpNum) & EPREG_MASK))
+#define _ToggleDTOG_TX(bEpNum) (_SetENDPOINT(bEpNum, \
+ EP_DTOG_TX | _GetENDPOINT(bEpNum) & EPREG_MASK))
+
+/*******************************************************************************
+* Macro Name : ClearDTOG_RX / ClearDTOG_TX.
+* Description : Clears DTOG_RX / DTOG_TX bit in the endpoint register.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _ClearDTOG_RX(bEpNum) if((_GetENDPOINT(bEpNum) & EP_DTOG_RX) != 0)\
+ _ToggleDTOG_RX(bEpNum)
+#define _ClearDTOG_TX(bEpNum) if((_GetENDPOINT(bEpNum) & EP_DTOG_TX) != 0)\
+ _ToggleDTOG_TX(bEpNum)
+/*******************************************************************************
+* Macro Name : SetEPAddress.
+* Description : Sets address in an endpoint register.
+* Input : bEpNum: Endpoint Number.
+* bAddr: Address.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _SetEPAddress(bEpNum,bAddr) _SetENDPOINT(bEpNum,\
+ _GetENDPOINT(bEpNum) & EPREG_MASK | bAddr)
+
+/*******************************************************************************
+* Macro Name : GetEPAddress.
+* Description : Gets address in an endpoint register.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _GetEPAddress(bEpNum) ((u8)(_GetENDPOINT(bEpNum) & EPADDR_FIELD))
+
+#define _pEPTxAddr(bEpNum) ((u32 *)((_GetBTABLE()+bEpNum*8 )*2 + PMAAddr))
+#define _pEPTxCount(bEpNum) ((u32 *)((_GetBTABLE()+bEpNum*8+2)*2 + PMAAddr))
+#define _pEPRxAddr(bEpNum) ((u32 *)((_GetBTABLE()+bEpNum*8+4)*2 + PMAAddr))
+#define _pEPRxCount(bEpNum) ((u32 *)((_GetBTABLE()+bEpNum*8+6)*2 + PMAAddr))
+
+/*******************************************************************************
+* Macro Name : SetEPTxAddr / SetEPRxAddr.
+* Description : sets address of the tx/rx buffer.
+* Input : bEpNum: Endpoint Number.
+* wAddr: address to be set (must be word aligned).
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _SetEPTxAddr(bEpNum,wAddr) (*_pEPTxAddr(bEpNum) = ((wAddr >> 1) << 1))
+#define _SetEPRxAddr(bEpNum,wAddr) (*_pEPRxAddr(bEpNum) = ((wAddr >> 1) << 1))
+
+/*******************************************************************************
+* Macro Name : GetEPTxAddr / GetEPRxAddr.
+* Description : Gets address of the tx/rx buffer.
+* Input : bEpNum: Endpoint Number.
+* Output : None.
+* Return : address of the buffer.
+*******************************************************************************/
+#define _GetEPTxAddr(bEpNum) ((u16)*_pEPTxAddr(bEpNum))
+#define _GetEPRxAddr(bEpNum) ((u16)*_pEPRxAddr(bEpNum))
+
+/*******************************************************************************
+* Macro Name : SetEPCountRxReg.
+* Description : Sets counter of rx buffer with no. of blocks.
+* Input : pdwReg: pointer to counter.
+* wCount: Counter.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _BlocksOf32(dwReg,wCount,wNBlocks) {\
+ wNBlocks = wCount >> 5;\
+ if((wCount & 0x1f) == 0)\
+ wNBlocks--;\
+ *pdwReg = (u32)((wNBlocks << 10) | 0x8000);\
+ }/* _BlocksOf32 */
+
+#define _BlocksOf2(dwReg,wCount,wNBlocks) {\
+ wNBlocks = wCount >> 1;\
+ if((wCount & 0x1) != 0)\
+ wNBlocks++;\
+ *pdwReg = (u32)(wNBlocks << 10);\
+ }/* _BlocksOf2 */
+
+#define _SetEPCountRxReg(dwReg,wCount) {\
+ u16 wNBlocks;\
+ if(wCount > 62){_BlocksOf32(dwReg,wCount,wNBlocks);}\
+ else {_BlocksOf2(dwReg,wCount,wNBlocks);}\
+ }/* _SetEPCountRxReg */
+
+
+
+#define _SetEPRxDblBuf0Count(bEpNum,wCount) {\
+ u32 *pdwReg = _pEPTxCount(bEpNum); \
+ _SetEPCountRxReg(pdwReg, wCount);\
+ }
+/*******************************************************************************
+* Macro Name : SetEPTxCount / SetEPRxCount.
+* Description : sets counter for the tx/rx buffer.
+* Input : bEpNum: endpoint number.
+* wCount: Counter value.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _SetEPTxCount(bEpNum,wCount) (*_pEPTxCount(bEpNum) = wCount)
+#define _SetEPRxCount(bEpNum,wCount) {\
+ u32 *pdwReg = _pEPRxCount(bEpNum); \
+ _SetEPCountRxReg(pdwReg, wCount);\
+ }
+/*******************************************************************************
+* Macro Name : GetEPTxCount / GetEPRxCount.
+* Description : gets counter of the tx buffer.
+* Input : bEpNum: endpoint number.
+* Output : None.
+* Return : Counter value.
+*******************************************************************************/
+#define _GetEPTxCount(bEpNum)((u16)(*_pEPTxCount(bEpNum)) & 0x3ff)
+#define _GetEPRxCount(bEpNum)((u16)(*_pEPRxCount(bEpNum)) & 0x3ff)
+
+/*******************************************************************************
+* Macro Name : SetEPDblBuf0Addr / SetEPDblBuf1Addr.
+* Description : Sets buffer 0/1 address in a double buffer endpoint.
+* Input : bEpNum: endpoint number.
+* : wBuf0Addr: buffer 0 address.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _SetEPDblBuf0Addr(bEpNum,wBuf0Addr) {_SetEPTxAddr(bEpNum, wBuf0Addr);}
+#define _SetEPDblBuf1Addr(bEpNum,wBuf1Addr) {_SetEPRxAddr(bEpNum, wBuf1Addr);}
+
+/*******************************************************************************
+* Macro Name : SetEPDblBuffAddr.
+* Description : Sets addresses in a double buffer endpoint.
+* Input : bEpNum: endpoint number.
+* : wBuf0Addr: buffer 0 address.
+* : wBuf1Addr = buffer 1 address.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _SetEPDblBuffAddr(bEpNum,wBuf0Addr,wBuf1Addr) { \
+ _SetEPDblBuf0Addr(bEpNum, wBuf0Addr);\
+ _SetEPDblBuf1Addr(bEpNum, wBuf1Addr);\
+ } /* _SetEPDblBuffAddr */
+
+/*******************************************************************************
+* Macro Name : GetEPDblBuf0Addr / GetEPDblBuf1Addr.
+* Description : Gets buffer 0/1 address of a double buffer endpoint.
+* Input : bEpNum: endpoint number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _GetEPDblBuf0Addr(bEpNum) (_GetEPTxAddr(bEpNum))
+#define _GetEPDblBuf1Addr(bEpNum) (_GetEPRxAddr(bEpNum))
+
+/*******************************************************************************
+* Macro Name : SetEPDblBuffCount / SetEPDblBuf0Count / SetEPDblBuf1Count.
+* Description : Gets buffer 0/1 address of a double buffer endpoint.
+* Input : bEpNum: endpoint number.
+* : bDir: endpoint dir EP_DBUF_OUT = OUT
+* EP_DBUF_IN = IN
+* : wCount: Counter value
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _SetEPDblBuf0Count(bEpNum, bDir, wCount) { \
+ if(bDir == EP_DBUF_OUT)\
+ /* OUT endpoint */ \
+ {_SetEPRxDblBuf0Count(bEpNum,wCount);} \
+ else if(bDir == EP_DBUF_IN)\
+ /* IN endpoint */ \
+ *_pEPTxCount(bEpNum) = (u32)wCount; \
+ } /* SetEPDblBuf0Count*/
+
+#define _SetEPDblBuf1Count(bEpNum, bDir, wCount) { \
+ if(bDir == EP_DBUF_OUT)\
+ /* OUT endpoint */ \
+ {_SetEPRxCount(bEpNum,wCount);}\
+ else if(bDir == EP_DBUF_IN)\
+ /* IN endpoint */\
+ *_pEPRxCount(bEpNum) = (u32)wCount; \
+ } /* SetEPDblBuf1Count */
+
+#define _SetEPDblBuffCount(bEpNum, bDir, wCount) {\
+ _SetEPDblBuf0Count(bEpNum, bDir, wCount); \
+ _SetEPDblBuf1Count(bEpNum, bDir, wCount); \
+ } /* _SetEPDblBuffCount */
+
+/*******************************************************************************
+* Macro Name : GetEPDblBuf0Count / GetEPDblBuf1Count.
+* Description : Gets buffer 0/1 rx/tx counter for double buffering.
+* Input : bEpNum: endpoint number.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+#define _GetEPDblBuf0Count(bEpNum) (_GetEPTxCount(bEpNum))
+#define _GetEPDblBuf1Count(bEpNum) (_GetEPRxCount(bEpNum))
+
+#endif
+/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/
diff --git a/libmaple/util.c b/libmaple/util.c
new file mode 100644
index 0000000..d323611
--- /dev/null
+++ b/libmaple/util.c
@@ -0,0 +1,103 @@
+/* *****************************************************************************
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Created: 12/18/09 02:38:44
+ * Copyright (c) 2009 Perry L. Hung. All rights reserved.
+ *
+ * ****************************************************************************/
+
+/**
+ * @file util.h
+ *
+ * @brief Utility procedures for debugging, mostly an error LED fade and
+ * messages dumped over a uart for failed asserts.
+ */
+
+#include "libmaple.h"
+#include "usart.h"
+#include "gpio.h"
+#include "nvic.h"
+#include "adc.h"
+#include "timers.h"
+
+#define ERROR_LED_PORT GPIOA_BASE
+#define ERROR_LED_PIN 5
+#define ERROR_USART_NUM 2
+#define ERROR_USART_BAUD 9600
+#define ERROR_TX_PIN 2
+#define ERROR_TX_PORT GPIOA_BASE
+
+/* Error assert + fade */
+void _fail(const char* file, int line, const char* exp) {
+ int32_t slope = 1;
+ int32_t CC = 0x0000;
+ int32_t TOP_CNT = 0x02FF;
+ int32_t i = 0;
+
+ /* Turn off interrupts */
+ nvic_disable_interrupts();
+
+ /* Turn off timers */
+ timers_disable();
+
+ /* Turn off ADC */
+ adc_disable();
+
+ /* Turn off all usarts */
+ usart_disable(1);
+ usart_disable(2);
+ usart_disable(3);
+
+ /* Initialize the error usart */
+ gpio_set_mode(ERROR_TX_PORT, ERROR_TX_PIN, GPIO_MODE_AF_OUTPUT_PP);
+ usart_init(ERROR_USART_NUM, ERROR_USART_BAUD);
+
+ /* Print failed assert message */
+ usart_putstr(ERROR_USART_NUM, "ERROR: FAILED ASSERT(");
+ usart_putstr(ERROR_USART_NUM, exp);
+ usart_putstr(ERROR_USART_NUM, "): ");
+ usart_putstr(ERROR_USART_NUM, file);
+ usart_putstr(ERROR_USART_NUM, ": ");
+ usart_putudec(ERROR_USART_NUM, line);
+ usart_putc(ERROR_USART_NUM, '\n');
+
+ /* Turn on the error LED */
+ gpio_set_mode(ERROR_LED_PORT, ERROR_LED_PIN, GPIO_MODE_OUTPUT_PP);
+
+ /* Turn the USB interrupt back on so the bootloader keeps on functioning */
+ nvic_enable_interrupt(NVIC_INT_USBHP);
+ nvic_enable_interrupt(NVIC_INT_USBLP);
+
+ /* Error fade */
+ while (1) {
+ if (CC == TOP_CNT) {
+ slope = -1;
+ } else if (CC == 0) {
+ slope = 1;
+ }
+
+ if (i == TOP_CNT) {
+ CC += slope;
+ i = 0;
+ }
+
+ if (i < CC) {
+ gpio_write_bit(ERROR_LED_PORT, ERROR_LED_PIN, 1);
+ } else {
+ gpio_write_bit(ERROR_LED_PORT, ERROR_LED_PIN, 0);
+ }
+ i++;
+ }
+}
+
diff --git a/libmaple/util.h b/libmaple/util.h
new file mode 100644
index 0000000..e425cc0
--- /dev/null
+++ b/libmaple/util.h
@@ -0,0 +1,82 @@
+/* *****************************************************************************
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Created: 12/18/09 02:39:27
+ * Copyright (c) 2009 Perry L. Hung. All rights reserved.
+ *
+ * ****************************************************************************/
+
+/**
+ * @file util.h
+ *
+ * @brief Various macros and utility procedures.
+ */
+
+/* Generally "useful" utility procedures */
+#ifndef _UTIL_H_
+#define _UTIL_H_
+#include <inttypes.h>
+
+#define MAPLE_DEBUG 1
+
+#define BIT(shift) (1 << (shift))
+#define BIT_MASK_SHIFT(mask, shift) ((mask) << (shift))
+
+/* Return bits m to n of x */
+#define GET_BITS(x, m, n) ((((uint32_t)x) << (31 - (n))) >> ((31 - (n)) + (m)))
+
+/* Bit-banding macros */
+#define BITBAND_SRAM_REF 0x20000000
+#define BITBAND_SRAM_BASE 0x22000000
+#define BITBAND_SRAM(a,b) ((BITBAND_SRAM_BASE + (a-BITBAND_SRAM_REF)*32 + (b*4))) // Convert SRAM address
+#define BITBAND_PERI_REF 0x40000000
+#define BITBAND_PERI_BASE 0x42000000
+#define BITBAND_PERI(a,b) ((BITBAND_PERI_BASE + (a-BITBAND_PERI_REF)*32 + (b*4))) // Convert PERI address
+
+#define COUNTFLAG *((volatile unsigned char*) (BITBAND_PERI(SYSTICK_CSR,2)))
+
+#define REG_SET(reg, val) (*(volatile uint32_t*)(reg) = (val))
+#define REG_SET_BIT(reg, bit) (*(volatile uint32_t*)(reg) |= BIT(bit))
+#define REG_CLEAR_BIT(reg, bit) (*(volatile uint32_t*)(reg) &= ~BIT(bit))
+#define REG_SET_MASK(reg, mask) (*(volatile uint32_t*)(reg) |= (uint32_t)(mask))
+#define REG_CLEAR_MASK(reg, mask) (*(volatile uint32_t*)(reg) &= (uint32_t)~(mask))
+
+#define REG_GET(reg) *(volatile uint32_t*)(reg)
+
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+void _fail(const char*, int, const char*);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+
+/* Assert for sanity checks, undefine MAPLE_DEBUG to compile
+ * out these checks */
+#if MAPLE_DEBUG
+#define ASSERT(exp) \
+ if (exp) \
+ {} \
+ else \
+ _fail(__FILE__, __LINE__, #exp)
+#else
+#define ASSERT(exp) (void)((0))
+#endif
+
+#endif
+