aboutsummaryrefslogtreecommitdiffstats
path: root/libmaple
diff options
context:
space:
mode:
Diffstat (limited to 'libmaple')
-rw-r--r--libmaple/adc.c142
-rw-r--r--libmaple/adc.h203
-rw-r--r--libmaple/bkp.c112
-rw-r--r--libmaple/bkp.h102
-rw-r--r--libmaple/dac.c89
-rw-r--r--libmaple/dac.h135
-rw-r--r--libmaple/dma.c14
-rw-r--r--libmaple/exc.S71
-rw-r--r--libmaple/exti.c14
-rw-r--r--libmaple/libmaple.h163
-rw-r--r--libmaple/libmaple_types.h2
-rw-r--r--libmaple/pwr.c42
-rw-r--r--libmaple/pwr.h64
-rw-r--r--libmaple/rcc.c21
-rw-r--r--libmaple/rcc.h15
-rw-r--r--libmaple/systick.c2
-rw-r--r--libmaple/timers.c18
-rw-r--r--libmaple/timers.h6
-rw-r--r--libmaple/usart.c22
-rw-r--r--libmaple/usart.h2
-rw-r--r--libmaple/usb/descriptors.c73
-rw-r--r--libmaple/usb/usb.c2
-rw-r--r--libmaple/usb/usb.h2
-rw-r--r--libmaple/usb/usb_config.h76
-rw-r--r--libmaple/util.c69
-rw-r--r--libmaple/util.h37
26 files changed, 946 insertions, 552 deletions
diff --git a/libmaple/adc.c b/libmaple/adc.c
index 3e6818c..cd71118 100644
--- a/libmaple/adc.c
+++ b/libmaple/adc.c
@@ -24,84 +24,88 @@
/**
* @brief Analog to digital converter routines
+ *
+ * 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.
+ *
+ * See stm32 manual RM008 for how to calculate this.
*/
#include "libmaple.h"
#include "rcc.h"
#include "adc.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*/
+adc_dev adc1 = {
+ .regs = ADC1_BASE,
+ .clk_id = RCC_ADC1
+};
+const adc_dev *ADC1 = &adc1;
-void set_adc_smprx(adc_smp_rate smp_rate);
+adc_dev adc2 = {
+ .regs = ADC2_BASE,
+ .clk_id = RCC_ADC2
+};
+const adc_dev *ADC2 = &adc2;
-void adc_init(adc_smp_rate smp_rate) {
- rcc_set_prescaler(RCC_PRESCALER_ADC, RCC_ADCPRE_PCLK_DIV_6);
- rcc_clk_enable(RCC_ADC1);
- rcc_reset_dev(RCC_ADC1);
+#ifdef STM32_HIGH_DENSITY
+adc_dev adc3 = {
+ .regs = ADC3_BASE,
+ .clk_id = RCC_ADC3
+};
+const adc_dev *ADC3 = &adc3;
+#endif
- ADC_CR1 = 0;
- /* Software triggers conversions */
- ADC_CR2 = CR2_EXTSEL_SWSTART | CR2_EXTTRIG;
- ADC_SQR1 = 0;
+static void adc_calibrate(const adc_dev *dev);
- /* Set the sample conversion time. See note above for impedance
- requirements. */
- adc_set_sample_rate(smp_rate);
+/**
+ * @brief Initialize an ADC peripheral. Only supports software triggered
+ * conversions.
+ * @param dev ADC peripheral to initialize
+ * @param flags unused
+ */
+void adc_init(const adc_dev *dev, uint32 flags) {
+ /* Spin up the clocks */
+ rcc_set_prescaler(RCC_PRESCALER_ADC, RCC_ADCPRE_PCLK_DIV_6);
+ rcc_clk_enable(dev->clk_id);
+ rcc_reset_dev(dev->clk_id);
- /* Enable the ADC */
- CR2_ADON_BIT = 1;
+ /* Software triggers conversions, conversion on external events */
+ adc_set_extsel(dev, 7);
+ adc_set_exttrig(dev, 1);
- /* Reset the calibration registers and then perform a reset */
- CR2_RSTCAL_BIT = 1;
- while(CR2_RSTCAL_BIT)
- ;
+ /* Enable the ADC */
+ adc_enable(dev);
- CR2_CAL_BIT = 1;
- while(CR2_CAL_BIT)
- ;
+ /* Calibrate ADC */
+ adc_calibrate(dev);
}
-
-void adc_disable(void) {
- CR2_ADON_BIT = 0;
+/**
+ * @brief Set external event select for regular group
+ * @param dev adc device
+ * @param trigger event to select. See ADC_CR2 EXTSEL[2:0] bits.
+ */
+void adc_set_extsel(const adc_dev *dev, uint8 trigger) {
+ uint32 cr2 = dev->regs->CR2;
+ cr2 &= ~ADC_CR2_EXTSEL;
+ cr2 |= (trigger & 0x7) << 17;
+ dev->regs->CR2 = cr2;
}
-/* Turn the given sample rate into values for ADC_SMPRx. (Don't
- * precompute in order to avoid wasting space).
- *
- * Don't call this during conversion!
+
+/**
+ * @brief Turn the given sample rate into values for ADC_SMPRx. Don't
+ * call this during conversion.
+ * @param dev adc device
+ * @param smp_rate sample rate to set
+ * @see adc_smp_rate
*/
-void adc_set_sample_rate(adc_smp_rate smp_rate) {
+void adc_set_sample_rate(const adc_dev *dev, adc_smp_rate smp_rate) {
uint32 adc_smpr1_val = 0, adc_smpr2_val = 0;
int i;
+
for (i = 0; i < 10; i++) {
if (i < 8) {
/* ADC_SMPR1 determines sample time for channels [10,17] */
@@ -110,6 +114,24 @@ void adc_set_sample_rate(adc_smp_rate smp_rate) {
/* ADC_SMPR2 determines sample time for channels [0,9] */
adc_smpr2_val |= smp_rate << (i * 3);
}
- ADC_SMPR1 = adc_smpr1_val;
- ADC_SMPR2 = adc_smpr2_val;
+
+ dev->regs->SMPR1 = adc_smpr1_val;
+ dev->regs->SMPR2 = adc_smpr2_val;
+}
+
+/**
+ * @brief Calibrate an ADC peripheral
+ * @param dev adc device
+ */
+static void adc_calibrate(const adc_dev *dev) {
+ __io uint32 *rstcal_bit = (__io uint32*)BITBAND_PERI(&(dev->regs->CR2), 3);
+ __io uint32 *cal_bit = (__io uint32*)BITBAND_PERI(&(dev->regs->CR2), 2);
+
+ *rstcal_bit = 1;
+ while (*rstcal_bit)
+ ;
+
+ *cal_bit = 1;
+ while (*cal_bit)
+ ;
}
diff --git a/libmaple/adc.h b/libmaple/adc.h
index 976986f..ac386fb 100644
--- a/libmaple/adc.h
+++ b/libmaple/adc.h
@@ -25,87 +25,174 @@
/**
* @file adc.h
*
- * @brief Analog-to-Digital Conversion (ADC) routines.
+ * @brief Analog-to-Digital Conversion (ADC) header.
*/
#ifndef _ADC_H_
#define _ADC_H_
#include "util.h"
+#include "rcc.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 */
-
-/* TODO: We'll only use ADC1 for now. See page 41 of the manual for
- ADC2 and ADC3's real addresses. */
-#define ADC1_BASE 0x40012400
-#define ADC2_BASE 0x40012400
-#define ADC3_BASE 0x40012400
-
-#define ADC_SR *(volatile uint32*)(ADC1_BASE + 0)
-#define ADC_CR1 *(volatile uint32*)(ADC1_BASE + 0x4)
-#define ADC_CR2 *(volatile uint32*)(ADC1_BASE + 0x8)
-#define ADC_SMPR1 *(volatile uint32*)(ADC1_BASE + 0xC)
-#define ADC_SMPR2 *(volatile uint32*)(ADC1_BASE + 0x10)
-#define ADC_SQR1 *(volatile uint32*)(ADC1_BASE + 0x2C)
-#define ADC_SQR3 *(volatile uint32*)(ADC1_BASE + 0x34)
-#define ADC_DR *(volatile uint32*)(ADC1_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*)(BITBAND_PERI(ADC1_BASE+0x8, 0))
-#define CR2_CAL_BIT *(volatile uint32*)(BITBAND_PERI(ADC1_BASE+0x8, 2))
-#define CR2_RSTCAL_BIT *(volatile uint32*)(BITBAND_PERI(ADC1_BASE+0x8, 3))
-#define CR2_SWSTART_BIT *(volatile uint32*)(BITBAND_PERI(ADC1_BASE+0x8, 22))
-#define SR_EOC_BIT *(volatile uint32*)(BITBAND_PERI(ADC1_BASE+0, 1))
-/* (NR_ANALOG_PINS is board specific) */
+typedef struct adc_reg_map {
+ __io uint32 SR; ///< Status register
+ __io uint32 CR1; ///< Control register 1
+ __io uint32 CR2; ///< Control register 2
+ __io uint32 SMPR1; ///< Sample time register 1
+ __io uint32 SMPR2; ///< Sample time register 2
+ __io uint32 JOFR1; ///< Injected channel data offset register 1
+ __io uint32 JOFR2; ///< Injected channel data offset register 2
+ __io uint32 JOFR3; ///< Injected channel data offset register 3
+ __io uint32 JOFR4; ///< Injected channel data offset register 4
+ __io uint32 HTR; ///< Watchdog high threshold register
+ __io uint32 LTR; ///< Watchdog low threshold register
+ __io uint32 SQR1; ///< Regular sequence register 1
+ __io uint32 SQR2; ///< Regular sequence register 2
+ __io uint32 SQR3; ///< Regular sequence register 3
+ __io uint32 JSQR; ///< Injected sequence register
+ __io uint32 JDR1; ///< Injected data register 1
+ __io uint32 JDR2; ///< Injected data register 2
+ __io uint32 JDR3; ///< Injected data register 3
+ __io uint32 JDR4; ///< Injected data register 4
+ __io uint32 DR; ///< Regular data register
+} adc_reg_map;
+
+typedef struct adc_dev {
+ adc_reg_map *regs;
+ rcc_clk_id clk_id;
+} adc_dev;
+
+extern const adc_dev *ADC1;
+extern const adc_dev *ADC2;
+#ifdef STM32_HIGH_DENSITY
+extern const adc_dev *ADC3;
+#endif
+
+/*
+ * ADC peripheral base addresses
+ */
+#define ADC1_BASE ((adc_reg_map*)0x40012400)
+#define ADC2_BASE ((adc_reg_map*)0x40012800)
+#define ADC3_BASE ((adc_reg_map*)0x40013C00)
+
+/*
+ * Register bit definitions
+ */
+
+/* Status register */
+#define ADC_SR_AWD BIT(0)
+#define ADC_SR_EOC BIT(1)
+#define ADC_SR_JEOC BIT(2)
+#define ADC_SR_JSTRT BIT(3)
+#define ADC_SR_STRT BIT(4)
+
+/* Control register 1 */
+#define ADC_CR1_AWDCH (0x1F)
+#define ADC_CR1_EOCIE BIT(5)
+#define ADC_CR1_AWDIE BIT(6)
+#define ADC_CR1_JEOCIE BIT(7)
+#define ADC_CR1_SCAN BIT(8)
+#define ADC_CR1_AWDSGL BIT(9)
+#define ADC_CR1_JAUTO BIT(10)
+#define ADC_CR1_DISCEN BIT(11)
+#define ADC_CR1_JDISCEN BIT(12)
+#define ADC_CR1_DISCNUM (0xE000)
+#define ADC_CR1_JAWDEN BIT(22)
+#define ADC_CR1_AWDEN BIT(23)
+
+/* Control register 2 */
+#define ADC_CR2_ADON BIT(0)
+#define ADC_CR2_CONT BIT(1)
+#define ADC_CR2_CAL BIT(2)
+#define ADC_CR2_RSTCAL BIT(3)
+#define ADC_CR2_DMA BIT(8)
+#define ADC_CR2_ALIGN BIT(11)
+#define ADC_CR2_JEXTSEL (0x7000)
+#define ADC_CR2_JEXTTRIG BIT(15)
+#define ADC_CR2_EXTSEL (0xE0000)
+#define ADC_CR2_EXTTRIG BIT(20)
+#define ADC_CR2_JSWSTART BIT(21)
+#define ADC_CR2_SWSTART BIT(22)
+#define ADC_CR2_TSEREFE BIT(23)
+
+void adc_init(const adc_dev *dev, uint32 flags);
+void adc_set_extsel(const adc_dev *dev, uint8 trigger);
/** ADC per-sample conversion times, in ADC clock cycles */
typedef enum {
- ADC_SMPR_1_5,
- ADC_SMPR_7_5,
- ADC_SMPR_13_5,
- ADC_SMPR_28_5,
- ADC_SMPR_41_5,
- ADC_SMPR_55_5,
- ADC_SMPR_71_5,
- ADC_SMPR_239_5
+ ADC_SMPR_1_5, ///< 1.5 ADC cycles
+ ADC_SMPR_7_5, ///< 7.5 ADC cycles
+ ADC_SMPR_13_5, ///< 13.5 ADC cycles
+ ADC_SMPR_28_5, ///< 28.5 ADC cycles
+ ADC_SMPR_41_5, ///< 41.5 ADC cycles
+ ADC_SMPR_55_5, ///< 55.5 ADC cycles
+ ADC_SMPR_71_5, ///< 71.5 ADC cycles
+ ADC_SMPR_239_5 ///< 239.5 ADC cycles
} adc_smp_rate;
-/** Initialize ADC1 to do one-shot conversions at the given sample
- rate. */
-void adc_init(adc_smp_rate smp_rate);
-
-void adc_set_sample_rate(adc_smp_rate smp_rate);
-
-void adc_disable(void);
+void adc_set_sample_rate(const adc_dev *dev, adc_smp_rate smp_rate);
/**
- * Perform a single conversion on ADC[0-15].
- * PRECONDITIONS:
- * adc initialized */
-static inline int adc_read(int channel) {
- /* Set channel */
- ADC_SQR3 = channel;
+ * @brief Perform a single synchronous software triggered conversion on a
+ * channel
+ * @param regs ADC register map
+ * @param channel channel to convert
+ * @return conversion result
+ */
+static inline uint32 adc_read(const adc_dev *dev, uint8 channel) {
+ adc_reg_map *regs = dev->regs;
+
+ /* Set target channel */
+ regs->SQR3 = channel;
/* Start the conversion */
- CR2_SWSTART_BIT = 1;
+ regs->CR2 |= ADC_CR2_SWSTART;
/* Wait for it to finish */
- while(SR_EOC_BIT == 0)
+ while((regs->SR & ADC_SR_EOC) == 0)
;
- return ADC_DR;
+ return regs->DR;
+}
+
+/**
+ * @brief Set external trigger conversion mode event for regular channels
+ * @param dev adc device
+ * @param enable if 1, conversion on external events is enabled, 0 to disable
+ */
+static inline void adc_set_exttrig(const adc_dev *dev, uint8 enable) {
+ __write(BITBAND_PERI(&(dev->regs->CR2), 20), enable);
+}
+
+/**
+ * @brief Enable an adc peripheral
+ * @param regs register map of peripheral to enable
+ */
+static inline void adc_enable(const adc_dev *dev) {
+ __write(BITBAND_PERI(&(dev->regs->CR2), 0), 1);
+}
+
+/**
+ * @brief Disable an adc peripheral
+ * @param regs register map of peripheral to disable
+ */
+static inline void adc_disable(const adc_dev *dev) {
+ __write(BITBAND_PERI(&(dev->regs->CR2), 0), 0);
+}
+
+/**
+ * @brief Disable all ADCs
+ */
+static inline void adc_disable_all(void) {
+ adc_disable(ADC1);
+ adc_disable(ADC2);
+#ifdef STM32_HIGH_DENSITY
+ adc_disable(ADC3);
+#endif
}
#ifdef __cplusplus
diff --git a/libmaple/bkp.c b/libmaple/bkp.c
index e89abd0..ed107d8 100644
--- a/libmaple/bkp.c
+++ b/libmaple/bkp.c
@@ -24,63 +24,101 @@
* SOFTWARE.
*****************************************************************************/
-#include "libmaple.h"
#include "bkp.h"
#include "pwr.h"
#include "rcc.h"
#include "util.h"
-/* Data register memory layout is not contiguous. It's split up from
- 1--NR_LOW_DRS, beginning at BKP_LOW_OFFSET, through
- (NR_LOW_DRS+1)--NR_DRS, beginning at BKP_HIGH_OFFSET. */
-#define NR_LOW_DRS 10
-#define BKP_LOW_OFFSET 0x4 /* start offset for data registers 1--10 */
-#define BKP_HIGH_OFFSET 0x40 /* start offset for data registers 11--42 */
+static inline __io uint32* data_register(uint8 reg);
-inline volatile uint16* reg_addr(uint8 reg) {
- if (1 <= reg) {
- if (reg <= NR_LOW_DRS) {
- return (volatile uint16*)(BKP_BASE + BKP_LOW_OFFSET +
- (reg - 1) * 4);
- } else if (reg <= NR_BKP_REGS) {
- return (volatile uint16*)(BKP_BASE + BKP_HIGH_OFFSET +
- (reg - NR_LOW_DRS - 1) * 4);
- }
- }
- return 0;
-}
+bkp_dev bkp = {
+ .regs = BKP_BASE,
+};
-void bkp_init(void) {
- /* Set PWREN (28) and BKPEN (27) bits */
- __set_bits(RCC_APB1ENR, BIT(28) | BIT(27));
-}
+const bkp_dev *BKP = &bkp;
-void bkp_disable(void) {
- __clear_bits(RCC_APB1ENR, BIT(28) | BIT(27));
+/**
+ * @brief Initialize backup interface.
+ *
+ * Enables the power and backup interface clocks, and resets the
+ * backup device.
+ */
+void bkp_init(void) {
+ /* Don't call pwr_init(), or you'll reset the device. We just
+ * need the clock. */
+ rcc_clk_enable(RCC_PWR);
+ rcc_clk_enable(RCC_BKP);
+ rcc_reset_dev(RCC_BKP);
}
+/**
+ * Enable write access to the backup registers. Backup interface must
+ * be initialized for subsequent register writes to work.
+ * @see bkp_init()
+ */
void bkp_enable_writes(void) {
- /* Set the DBP bit in PWR_CR */
- __write(BITBAND_PERI(PWR_CR, PWR_CR_DBP), 1);
+ __write(BITBAND_PERI(&(PWR_BASE->CR), PWR_CR_DBP), 1);
}
+/**
+ * Disable write access to the backup registers.
+ */
void bkp_disable_writes(void) {
- __write(BITBAND_PERI(PWR_CR, PWR_CR_DBP), 0);
+ __write(BITBAND_PERI(&(PWR_BASE->CR), PWR_CR_DBP), 0);
}
+/**
+ * Read a value from given backup data register.
+ * @param reg Data register to read, from 1 to BKP_NR_DATA_REGS (10 on
+ * medium-density devices, 42 on high-density devices).
+ */
uint16 bkp_read(uint8 reg) {
- volatile uint16* addr = reg_addr(reg);
- if (addr != 0) {
- return *addr;
+ __io uint32* dr = data_register(reg);
+ if (!dr) {
+ ASSERT(0); /* nonexistent register */
+ return 0;
}
- ASSERT(0); /* nonexistent register */
- return 0;
+ return (uint16)*dr;
}
+/**
+ * @brief Write a value to given data register.
+ *
+ * Write access to backup registers must be enabled.
+ *
+ * @param reg Data register to write, from 1 to BKP_NR_DATA_REGS (10
+ * on medium-density devices, 42 on high-density devices).
+ * @param val Value to write into the register.
+ * @see bkp_enable_writes()
+ */
void bkp_write(uint8 reg, uint16 val) {
- volatile uint16* addr = reg_addr(reg);
- if (addr != 0) {
- *addr = val;
+ __io uint32* dr = data_register(reg);
+ if (!dr) {
+ ASSERT(0); /* nonexistent register */
+ return;
+ }
+ *dr = (uint32)val;
+}
+
+/*
+ * Data register memory layout is not contiguous. It's split up from
+ * 1--NR_LOW_DRS, beginning at BKP_BASE->DR1, through to
+ * (NR_LOW_DRS+1)--BKP_NR_DATA_REGS, beginning at BKP_BASE->DR11.
+ */
+#define NR_LOW_DRS 10
+
+static inline __io uint32* data_register(uint8 reg) {
+ if (reg < 1 || reg > BKP_NR_DATA_REGS) {
+ return 0;
+ }
+
+#if BKP_NR_DATA_REGS == NR_LOW_DRS
+ return (uint32*)BKP_BASE + reg;
+#else
+ if (reg <= NR_LOW_DRS) {
+ return (uint32*)BKP_BASE + reg;
+ } else {
+ return (uint32*)&(BKP_BASE->DR11) + (reg - NR_LOW_DRS - 1);
}
- ASSERT(0); /* nonexistent register */
+#endif
}
diff --git a/libmaple/bkp.h b/libmaple/bkp.h
index 9ad4c41..96ef8d2 100644
--- a/libmaple/bkp.h
+++ b/libmaple/bkp.h
@@ -32,51 +32,89 @@
#ifndef _BKP_H_
#define _BKP_H_
+#include "libmaple.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#define BKP_BASE 0x40006C00
-#define BKP_RTCCR (BKP_BASE + 0x2C)
-#define BKP_CR (BKP_BASE + 0x30)
-#define BKP_CSR (BKP_BASE + 0x34)
+#if defined(STM32_MEDIUM_DENSITY)
+#define BKP_NR_DATA_REGS 10
+#elif defined(STM32_HIGH_DENSITY)
+#define BKP_NR_DATA_REGS 42
+#endif
-/**
- * Initialize backup interface. This function enables the power and
- * backup interface clocks. It does not enable write access to the
- * backup registers.
- */
-void bkp_init(void);
+typedef struct bkp_reg_map {
+ const uint32 RESERVED1;
+ __io uint32 DR1; ///< Data register 1
+ __io uint32 DR2; ///< Data register 2
+ __io uint32 DR3; ///< Data register 3
+ __io uint32 DR4; ///< Data register 4
+ __io uint32 DR5; ///< Data register 5
+ __io uint32 DR6; ///< Data register 6
+ __io uint32 DR7; ///< Data register 7
+ __io uint32 DR8; ///< Data register 8
+ __io uint32 DR9; ///< Data register 9
+ __io uint32 DR10; ///< Data register 10
+ __io uint32 RTCCR; ///< RTC control register
+ __io uint32 CR; ///< Control register
+ __io uint32 CSR; ///< Control and status register
+#ifdef STM32_HIGH_DENSITY
+ const uint32 RESERVED2;
+ const uint32 RESERVED3;
+ __io uint32 DR11; ///< Data register 11
+ __io uint32 DR12; ///< Data register 12
+ __io uint32 DR13; ///< Data register 13
+ __io uint32 DR14; ///< Data register 14
+ __io uint32 DR15; ///< Data register 15
+ __io uint32 DR16; ///< Data register 16
+ __io uint32 DR17; ///< Data register 17
+ __io uint32 DR18; ///< Data register 18
+ __io uint32 DR19; ///< Data register 19
+ __io uint32 DR20; ///< Data register 20
+ __io uint32 DR21; ///< Data register 21
+ __io uint32 DR22; ///< Data register 22
+ __io uint32 DR23; ///< Data register 23
+ __io uint32 DR24; ///< Data register 24
+ __io uint32 DR25; ///< Data register 25
+ __io uint32 DR26; ///< Data register 26
+ __io uint32 DR27; ///< Data register 27
+ __io uint32 DR28; ///< Data register 28
+ __io uint32 DR29; ///< Data register 29
+ __io uint32 DR30; ///< Data register 30
+ __io uint32 DR31; ///< Data register 31
+ __io uint32 DR32; ///< Data register 32
+ __io uint32 DR33; ///< Data register 33
+ __io uint32 DR34; ///< Data register 34
+ __io uint32 DR35; ///< Data register 35
+ __io uint32 DR36; ///< Data register 36
+ __io uint32 DR37; ///< Data register 37
+ __io uint32 DR38; ///< Data register 38
+ __io uint32 DR39; ///< Data register 39
+ __io uint32 DR40; ///< Data register 40
+ __io uint32 DR41; ///< Data register 41
+ __io uint32 DR42; ///< Data register 42
+#endif
+} bkp_reg_map;
-/** Disable power and backup interface clocks. */
-void bkp_disable(void);
+typedef struct bkp_dev {
+ bkp_reg_map *regs;
+} bkp_dev;
/**
- * Enable write access to the backup registers. Backup interface must
- * be initialized for subsequent register writes to work.
- * @see bkp_init()
+ * Backup device.
*/
-void bkp_enable_writes(void);
+extern const bkp_dev *BKP;
-/**
- * Disable write access to the backup registers. Does not disable
- * backup interface clocks.
+/*
+ * Backup peripheral base.
*/
-void bkp_disable_writes(void);
+#define BKP_BASE ((bkp_reg_map*)0x40006C00)
-/**
- * Read a value from given backup data register.
- * @param reg Data register to read, from 1 to NR_BKP_REGS (10 on Maple).
- */
+void bkp_init(void);
+void bkp_enable_writes(void);
+void bkp_disable_writes(void);
uint16 bkp_read(uint8 reg);
-
-/**
- * Write a value to given data register. Backup interface must have
- * been previously initialized, and write access to backup registers
- * must be enabled.
- * @param reg Data register to write, from 1 to NR_BKP_REGS (10 on Maple).
- * @param val Value to write into the register.
- */
void bkp_write(uint8 reg, uint16 val);
#ifdef __cplusplus
diff --git a/libmaple/dac.c b/libmaple/dac.c
index 63a96ac..54b555b 100644
--- a/libmaple/dac.c
+++ b/libmaple/dac.c
@@ -23,7 +23,6 @@
*****************************************************************************/
#include "libmaple.h"
-#include "rcc.h"
#include "gpio.h"
#include "dac.h"
@@ -31,35 +30,81 @@
* @brief DAC peripheral routines.
*/
-/* This numbering follows the registers (1-indexed) */
-#define DAC_CH1 1
-#define DAC_CH2 2
+dac_dev dac = {
+ .regs = DAC_BASE,
+};
+const dac_dev *DAC = &dac;
-DAC_Map *dac = (DAC_Map*)(DAC_BASE);
-
-/* Sets up the DAC peripheral */
-void dac_init(void) {
+/**
+ * @brief Initialize the digital to analog converter
+ * @param flags Flags:
+ * DAC_CH1: Enable channel 1
+ * DAC_CH2: Enable channel 2
+ * @sideeffect May set PA4 or PA5 to INPUT_ANALOG
+ */
+void dac_init(uint32 flags) {
/* First turn on the clock */
rcc_clk_enable(RCC_DAC);
+ rcc_reset_dev(RCC_DAC);
- /* Then setup ANALOG mode on PA4 and PA5 */
- gpio_set_mode(GPIOA_BASE, 4, CNF_INPUT_ANALOG);
- gpio_set_mode(GPIOA_BASE, 5, CNF_INPUT_ANALOG);
+ if (flags & DAC_CH1) {
+ dac_enable_channel(1);
+ }
- /* Then do register stuff. Default does no triggering, and
- * buffered output, so all good. */
- dac->CR = DAC_CR_EN1 | DAC_CR_EN2;
+ if (flags & DAC_CH2) {
+ dac_enable_channel(2);
+ }
}
-void dac_write(uint8 chan, uint16 val) {
- switch(chan) {
- case DAC_CH1:
- dac->DHR12R1 = 0x0FFF & val;
+/**
+ * @brief Write a 12-bit value to the DAC to output
+ * @param channel channel to select (1 or 2)
+ * @param val value to write
+ */
+void dac_write_channel(uint8 channel, uint16 val) {
+ switch(channel) {
+ case 1:
+ DAC->regs->DHR12R1 = DAC_DHR12R1_DACC1DHR & val;
+ break;
+ case 2:
+ DAC->regs->DHR12R2 = DAC_DHR12R2_DACC2DHR & val;
+ break;
+ }
+}
+
+/**
+ * @brief Enable a DAC channel
+ * @param channel channel to enable, either 1 or 2
+ * @sideeffect May change pin mode of PA4 or PA5
+ */
+void dac_enable_channel(uint8 channel) {
+ /*
+ * Setup ANALOG mode on PA4 and PA5. This mapping is consistent across
+ * all STM32 chips with a DAC. See RM008 12.2.
+ */
+ switch (channel) {
+ case 1:
+ gpio_set_mode(GPIOA_BASE, 4, GPIO_MODE_INPUT_ANALOG);
+ DAC->regs->CR |= DAC_CR_EN1;
+ break;
+ case 2:
+ gpio_set_mode(GPIOA_BASE, 5, GPIO_MODE_INPUT_ANALOG);
+ DAC->regs->CR |= DAC_CR_EN2;
+ break;
+ }
+}
+
+/**
+ * @brief Disable a DAC channel
+ * @param channel channel to disable, either 1 or 2
+ */
+void dac_disable_channel(uint8 channel) {
+ switch (channel) {
+ case 1:
+ DAC->regs->CR &= ~DAC_CR_EN1;
break;
- case DAC_CH2:
- dac->DHR12R2 = 0x0FFF & val;
+ case 2:
+ DAC->regs->CR &= ~DAC_CR_EN2;
break;
- default:
- ASSERT(0); // can't happen
}
}
diff --git a/libmaple/dac.h b/libmaple/dac.h
index 340a49a..bc64324 100644
--- a/libmaple/dac.h
+++ b/libmaple/dac.h
@@ -22,92 +22,131 @@
* THE SOFTWARE.
*****************************************************************************/
-/*
- * See ../notes/dac.txt for more info
- */
-
/**
* @file dac.h
+ * @brief Digital to analog converter header file
+ * See notes/dac.txt for more info
*/
#ifndef _DAC_H_
#define _DAC_H_
+#include "rcc.h"
+
#ifdef __cplusplus
extern "C"{
#endif
-#define DAC_BASE 0x40007400
-
-typedef struct {
- volatile uint32 CR;
- volatile uint32 SWTRIGR;
- volatile uint32 DHR12R1;
- volatile uint32 DHR12L1;
- volatile uint32 DHR8R1;
- volatile uint32 DHR12R2;
- volatile uint32 DHR12L2;
- volatile uint32 DHR8R2;
- volatile uint32 DHR12RD;
- volatile uint32 DHR12LD;
- volatile uint32 DHR8RD;
- volatile uint32 DOR1;
- volatile uint32 DOR2;
-} DAC_Map;
-
-/* There's only one DAC, so expose it. */
-extern DAC_Map *dac;
-
-// And here are the register bit ranges
-#define DAC_CR_EN1 BIT(0)
-#define DAC_CR_BOFF1 BIT(1)
-#define DAC_CR_TEN1 BIT(2)
-#define DAC_CR_TSEL1 (BIT(3) | BIT(4) | BIT(5))
-#define DAC_CR_WAVE1 (BIT(6) | BIT(7))
-#define DAC_CR_MAMP1 (BIT(8) | BIT(9) | BIT(10) | BIT(11))
-#define DAC_CR_DMAEN1 BIT(12)
-#define DAC_CR_EN2 BIT(16)
-#define DAC_CR_BOFF2 BIT(17)
-#define DAC_CR_TEN2 BIT(18)
-#define DAC_CR_TSEL2 (BIT(19) | BIT(20) | BIT(21))
-#define DAC_CR_WAVE2 (BIT(22) | BIT(23))
-#define DAC_CR_MAMP2 (BIT(24) | BIT(25) | BIT(26) | BIT(27))
-#define DAC_CR_DMAEN2 BIT(28)
-
-#define DAC_SWTRIGR_SWTRIG1 BIT(0)
-#define DAC_SWTRIGR_SWTRIG2 BIT(1)
+/** DAC register map. */
+typedef struct dac_reg_map {
+ __io uint32 CR; /**< Control register */
+ __io uint32 SWTRIGR; /**< Software trigger register */
+ __io uint32 DHR12R1; /**< Channel 1 12-bit right-aligned data
+ holding register */
+ __io uint32 DHR12L1; /**< Channel 1 12-bit left-aligned data
+ holding register */
+ __io uint32 DHR8R1; /**< Channel 1 8-bit left-aligned data
+ holding register */
+ __io uint32 DHR12R2; /**< Channel 2 12-bit right-aligned data
+ holding register */
+ __io uint32 DHR12L2; /**< Channel 2 12-bit left-aligned data
+ holding register */
+ __io uint32 DHR8R2; /**< Channel 2 8-bit left-aligned data
+ holding register */
+ __io uint32 DHR12RD; /**< Dual DAC 12-bit right-aligned data
+ holding register */
+ __io uint32 DHR12LD; /**< Dual DAC 12-bit left-aligned data
+ holding register */
+ __io uint32 DHR8RD; /**< Dual DAC 8-bit left-aligned data holding
+ register */
+ __io uint32 DOR1; /**< Channel 1 data output register */
+ __io uint32 DOR2; /**< Channel 2 data output register */
+} dac_reg_map;
+
+typedef struct dac_dev {
+ dac_reg_map *regs;
+} dac_dev;
+
+/** DAC device. */
+extern const dac_dev *DAC;
+
+/*
+ * DAC peripheral base address
+ */
+#define DAC_BASE ((dac_reg_map*)0x40007400)
+
+/*
+ * Register bit definitions and masks
+ */
+/* Control register */
+/* Channel 1 control */
+#define DAC_CR_EN1 BIT(0) /* Enable */
+#define DAC_CR_BOFF1 BIT(1) /* Output buffer disable */
+#define DAC_CR_TEN1 BIT(2) /* Trigger enable */
+#define DAC_CR_TSEL1 (0x7 << 3) /* Trigger selection */
+#define DAC_CR_WAVE1 (0x3 << 6) /* Noise/triangle wave enable */
+#define DAC_CR_MAMP1 (0xF << 8) /* Mask/amplitude selector */
+#define DAC_CR_DMAEN1 BIT(12) /* DMA enable */
+/* Channel 2 control */
+#define DAC_CR_EN2 BIT(16) /* Enable */
+#define DAC_CR_BOFF2 BIT(17) /* Output buffer disable */
+#define DAC_CR_TEN2 BIT(18) /* Trigger enable */
+#define DAC_CR_TSEL2 (0x7 << 19) /* Trigger selection */
+#define DAC_CR_WAVE2 (0x3 << 22) /* Noise/triangle wave generation*/
+#define DAC_CR_MAMP2 (0xF << 24) /* Mask/amplitude selector */
+#define DAC_CR_DMAEN2 BIT(28) /* DMA enable */
+
+/* Software trigger register */
+#define DAC_SWTRIGR_SWTRIG1 BIT(0) /* Channel 1 software trigger */
+#define DAC_SWTRIGR_SWTRIG2 BIT(1) /* Channel 2 software trigger */
+
+/* Channel 1 12-bit right-aligned data holding register */
#define DAC_DHR12R1_DACC1DHR 0x00000FFF
+/* Channel 1 12-bit left-aligned data holding register */
#define DAC_DHR12L1_DACC1DHR 0x0000FFF0
+/* Channel 1 8-bit left-aligned data holding register */
#define DAC_DHR8R1_DACC1DHR 0x000000FF
+/* Channel 2 12-bit right-aligned data holding register */
#define DAC_DHR12R2_DACC2DHR 0x00000FFF
+/* Channel 2 12-bit left-aligned data holding register */
#define DAC_DHR12L2_DACC2DHR 0x0000FFF0
+/* Channel 2 8-bit left-aligned data holding register */
#define DAC_DHR8R2_DACC2DHR 0x000000FF
+/* Dual DAC 12-bit right-aligned data holding register */
#define DAC_DHR12RD_DACC1DHR 0x00000FFF
#define DAC_DHR12RD_DACC2DHR 0x0FFF0000
+/* Dual DAC 12-bit left-aligned data holding register */
#define DAC_DHR12LD_DACC1DHR 0x0000FFF0
#define DAC_DHR12LD_DACC2DHR 0xFFF00000
+/* Dual DAC 8-bit left-aligned data holding register */
#define DAC_DHR8RD_DACC1DHR 0x000000FF
#define DAC_DHR8RD_DACC2DHR 0x0000FF00
-#define DAC_DOR1 0x00000FFF
+/* Channel 1 data output register */
+#define DAC_DOR1_DACC1DOR 0x00000FFF
+
+/* Channel 1 data output register */
+#define DAC_DOR2_DACC2DOR 0x00000FFF
-#define DAC_DOR2 0x00000FFF
+#define DAC_CH1 0x1
+#define DAC_CH2 0x2
+void dac_init(uint32 flags);
-void dac_init(void);
-void dac_write(uint8 chan, uint16 val);
+void dac_write_channel(uint8 channel, uint16 val);
+void dac_enable_channel(uint8 channel);
+void dac_disable_channel(uint8 channel);
#ifdef __cplusplus
} // extern "C"
#endif
-
#endif
diff --git a/libmaple/dma.c b/libmaple/dma.c
index 15c96e1..c71e52c 100644
--- a/libmaple/dma.c
+++ b/libmaple/dma.c
@@ -77,31 +77,31 @@ static inline void dispatch_handler(uint8 channel_idx) {
}
}
-void DMAChannel1_IRQHandler(void) {
+void __irq_dma1_channel1(void) {
dispatch_handler(0);
}
-void DMAChannel2_IRQHandler(void) {
+void __irq_dma1_channel2(void) {
dispatch_handler(1);
}
-void DMAChannel3_IRQHandler(void) {
+void __irq_dma2_channel3(void) {
dispatch_handler(2);
}
-void DMAChannel4_IRQHandler(void) {
+void __irq_dma2_channel4(void) {
dispatch_handler(3);
}
-void DMAChannel5_IRQHandler(void) {
+void __irq_dma2_channel5(void) {
dispatch_handler(4);
}
-void DMAChannel6_IRQHandler(void) {
+void __irq_dma2_channel6(void) {
dispatch_handler(5);
}
-void DMAChannel7_IRQHandler(void) {
+void __irq_dma2_channel7(void) {
dispatch_handler(6);
}
diff --git a/libmaple/exc.S b/libmaple/exc.S
index 2713ee3..7631e48 100644
--- a/libmaple/exc.S
+++ b/libmaple/exc.S
@@ -41,22 +41,61 @@
# SP--> r0
.text
-.globl HardFaultException
+.globl __exc_hardfault
+.globl __exc_nmi
+.globl __exc_hardfault
+.globl __exc_memmanage
+.globl __exc_busfault
+.globl __exc_usagefault
+
+.code 16
+.thumb_func
+__exc_nmi:
+ mov r0, #1
+ b __default_exc
+
+.thumb_func
+__exc_hardfault:
+ mov r0, #2
+ b __default_exc
+
+.thumb_func
+__exc_memmanage:
+ mov r0, #3
+ b __default_exc
+
+.thumb_func
+__exc_busfault:
+ mov r0, #4
+ b __default_exc
+
+.thumb_func
+__exc_usagefault:
+ mov r0, #5
+ b __default_exc
+
.thumb_func
-HardFaultException:
- b HardFaultException
- ldr r0, CPSR_MASK @ Set default CPSR
- push {r0}
- ldr r0, TARGET_PC @ Set target pc
- push {r0}
- sub sp, sp, #24 @ its not like i even care
- ldr r0, EXC_RETURN @ Return to thread mode
- mov lr, r0
- bx lr @ Exception exit
-
- .align 4
- CPSR_MASK: .word 0x61000000
- EXC_RETURN: .word 0xFFFFFFF9
- TARGET_PC: .word throb
+__default_exc:
+ ldr r2, NVIC_CCR @ Enable returning to thread mode even if there are
+ mov r1 ,#1 @ pending exceptions. See flag NONEBASETHRDENA.
+ str r1, [r2]
+ cpsid i @ Disable global interrupts
+ ldr r2, SYSTICK_CSR @ Disable systick handler
+ mov r1, #0
+ str r1, [r2]
+ ldr r1, CPSR_MASK @ Set default CPSR
+ push {r1}
+ ldr r1, TARGET_PC @ Set target pc
+ push {r1}
+ sub sp, sp, #24 @ Don't care
+ ldr r1, EXC_RETURN @ Return to thread mode
+ mov lr, r1
+ bx lr @ Exception exit
+.align 4
+CPSR_MASK: .word 0x61000000
+EXC_RETURN: .word 0xFFFFFFF9
+TARGET_PC: .word __error
+NVIC_CCR: .word 0xE000ED14 @ NVIC configuration control register
+SYSTICK_CSR: .word 0xE000E010 @ Systick control register
diff --git a/libmaple/exti.c b/libmaple/exti.c
index 150dd05..e8ad52a 100644
--- a/libmaple/exti.c
+++ b/libmaple/exti.c
@@ -74,32 +74,32 @@ static inline void dispatch_handler(uint32 channel) {
* is associated with each channel, so we
* don't have to keep track of which channel
* we came from */
-void EXTI0_IRQHandler(void) {
+void __irq_exti0(void) {
dispatch_handler(EXTI0);
clear_pending(EXTI0);
}
-void EXTI1_IRQHandler(void) {
+void __irq_exti1(void) {
dispatch_handler(EXTI1);
clear_pending(EXTI1);
}
-void EXTI2_IRQHandler(void) {
+void __irq_exti2(void) {
dispatch_handler(EXTI2);
clear_pending(EXTI2);
}
-void EXTI3_IRQHandler(void) {
+void __irq_exti3(void) {
dispatch_handler(EXTI3);
clear_pending(EXTI3);
}
-void EXTI4_IRQHandler(void) {
+void __irq_exti4(void) {
dispatch_handler(EXTI4);
clear_pending(EXTI4);
}
-void EXTI9_5_IRQHandler(void) {
+void __irq_exti9_5(void) {
/* Figure out which channel it came from */
uint32 pending;
uint32 i;
@@ -116,7 +116,7 @@ void EXTI9_5_IRQHandler(void) {
}
}
-void EXTI15_10_IRQHandler(void) {
+void __irq_exti15_10(void) {
/* Figure out which channel it came from */
uint32 pending;
uint32 i;
diff --git a/libmaple/libmaple.h b/libmaple/libmaple.h
index 3e7fea9..6b75c96 100644
--- a/libmaple/libmaple.h
+++ b/libmaple/libmaple.h
@@ -24,164 +24,50 @@
/**
* @file libmaple.h
- *
- * @brief general include file for libmaple
+ * @brief General include file for libmaple
*/
#ifndef _LIBMAPLE_H_
#define _LIBMAPLE_H_
#include "libmaple_types.h"
-#include "stm32.h"
-
-/* General configuration */
-#define DEBUG_NONE 0
-#define DEBUG_FAULT 1
-#define DEBUG_ALL 2
+#include "util.h"
-#ifndef DEBUG_LEVEL
-#define DEBUG_LEVEL DEBUG_ALL
-#endif
+/*
+ * Where to put usercode, based on space reserved for bootloader.
+ *
+ * FIXME this has no business being here
+ */
+#define USER_ADDR_ROM 0x08005000
+#define USER_ADDR_RAM 0x20000C00
+#define STACK_TOP 0x20000800
/* MCU-specific configuration */
#if defined(MCU_STM32F103RB)
/* e.g., LeafLabs Maple */
/* Number of GPIO ports (GPIOA, GPIOB, etc.) */
- #define NR_GPIO_PORTS 4
-
- /* Total number of GPIO pins */
- #define NR_GPIO_PINS 39
-
- /* Number of 16-bit backup registers */
- #define NR_BKP_REGS 10
-
- /* Number of timer devices ports, definitely used */
- #define NR_TIMERS 4
-
- /* Number of USART ports */
- #define NR_USART 3
-
- /* Has an FSMC bus? */
- #define NR_FSMC 0
-
- /* Has a DAC? */
- #define NR_DAC_PINS 0
-
- /* Number of maskable interrupts */
- #define NR_INTERRUPTS 43
-
- /* USB Identifier numbers */
- /* Descriptor strings must be modified by hand in
- usb/descriptors.c for now */
- #define VCOM_ID_VENDOR 0x1EAF
- #define VCOM_ID_PRODUCT 0x0004
- #define USB_DISC_BANK GPIOC_BASE
- #define USB_DISC_PIN 12
- #define USB_CONFIG_MAX_POWER (100 >> 1)
- #define RESET_DELAY (100)
-
- /* Where to put usercode (based on space reserved for bootloader) */
- #define USER_ADDR_ROM 0x08005000
- #define USER_ADDR_RAM 0x20000C00
- #define STACK_TOP 0x20000800
-
- /* Debug port settings (from ASSERT) */
- #define ERROR_LED_PORT GPIOB_BASE
- #define ERROR_LED_PIN 12
- #define ERROR_USART_NUM USART2
- #define ERROR_USART_BAUD 9600
- #define ERROR_TX_PORT GPIOA_BASE
- #define ERROR_TX_PIN 2
-
- /* Just in case, most boards have at least some memory */
- #ifndef RAMSIZE
- # define RAMSIZE (caddr_t)0x50000
- #endif
-
- /* Bitbanded Memory sections */
- #define BITBAND_SRAM_REF 0x20000000
- #define BITBAND_SRAM_BASE 0x22000000
- #define BITBAND_PERI_REF 0x40000000
- #define BITBAND_PERI_BASE 0x42000000
+ #define NR_GPIO_PORTS 4
+
+ /* SRAM size, in bytes */
+ #define SRAM_SIZE 0x5000
#elif defined(MCU_STM32F103ZE)
/* e.g., LeafLabs Maple Native */
- #define NR_GPIO_PORTS 7
- #define NR_GPIO_PINS 100
- #define NR_BKP_REGS 42 /* TODO test on Native */
- #define NR_TIMERS 8
- #define NR_USART 5 /* NB: 4 and 5 are UART only */
- #define NR_FSMC 1
- #define NR_DAC_PINS 2
- #define NR_INTERRUPTS 60
-
- #define VCOM_ID_VENDOR 0x1EAF
- #define VCOM_ID_PRODUCT 0x0004
- #define USB_DISC_BANK GPIOB_BASE
- #define USB_DISC_PIN 8
- #define USB_CONFIG_MAX_POWER (100 >> 1)
- #define RESET_DELAY (100)
-
- #define USER_ADDR_ROM 0x08005000
- #define USER_ADDR_RAM 0x20000C00
- #define STACK_TOP 0x20000800
-
- #define ERROR_LED_PORT GPIOC_BASE
- #define ERROR_LED_PIN 15
- #define ERROR_USART_NUM USART1
- #define ERROR_USART_BAUD 9600
- #define ERROR_TX_PORT GPIOA_BASE
- #define ERROR_TX_PIN 10
-
- #ifndef RAMSIZE
- # define RAMSIZE (caddr_t)0x50000
- #endif
-
- #define BITBAND_SRAM_REF 0x20000000
- #define BITBAND_SRAM_BASE 0x22000000
- #define BITBAND_PERI_REF 0x40000000
- #define BITBAND_PERI_BASE 0x42000000
+ #define NR_GPIO_PORTS 7
+
+ #define SRAM_SIZE 0x10000
#elif defined(MCU_STM32F103CB)
/* e.g., LeafLabs Maple Mini */
- #define NR_GPIO_PORTS 3
- #define NR_GPIO_PINS 34
- #define NR_BKP_REGS 10 /* TODO test on Mini */
- #define NR_TIMERS 4
- #define NR_USART 3
- #define NR_FSMC 0
- #define NR_DAC_PINS 0
-
- #define VCOM_ID_VENDOR 0x1EAF
- #define VCOM_ID_PRODUCT 0x0005
- #define USB_DISC_BANK GPIOB_BASE
- #define USB_DISC_PIN 9
- #define USB_CONFIG_MAX_POWER (100 >> 1)
- #define RESET_DELAY 100
-
- #define USER_ADDR_ROM 0x08005000
- #define USER_ADDR_RAM 0x20000C00
- #define STACK_TOP 0x20000800
-
- #define ERROR_LED_PORT GPIOB_BASE
- #define ERROR_LED_PIN 12
- #define ERROR_USART_NUM USART2
- #define ERROR_USART_BAUD 9600
- #define ERROR_TX_PORT GPIOA_BASE
- #define ERROR_TX_PIN 2
-
- #ifndef RAMSIZE
- # define RAMSIZE (caddr_t)0x50000
- #endif
-
- /* Bitbanded Memory sections */
- #define BITBAND_SRAM_REF 0x20000000
- #define BITBAND_SRAM_BASE 0x22000000
- #define BITBAND_PERI_REF 0x40000000
- #define BITBAND_PERI_BASE 0x42000000
+ /* Note that this is not, strictly speaking, true. But only pins
+ 0 and 1 exist, and they're used for OSC on the Mini, so we'll
+ live with this for now. */
+ #define NR_GPIO_PORTS 3
+
+ #define SRAM_SIZE 0x5000
#else
@@ -190,8 +76,5 @@
#endif
-/* Requires board configuration info */
-#include "util.h"
-
#endif
diff --git a/libmaple/libmaple_types.h b/libmaple/libmaple_types.h
index 8d216a8..a976a9e 100644
--- a/libmaple/libmaple_types.h
+++ b/libmaple/libmaple_types.h
@@ -45,8 +45,6 @@ typedef void (*voidFuncPtr)(void);
#define __io volatile
-#define ALWAYS_INLINE inline __attribute__((always_inline))
-
#ifndef NULL
#define NULL 0
#endif
diff --git a/libmaple/pwr.c b/libmaple/pwr.c
new file mode 100644
index 0000000..b43193e
--- /dev/null
+++ b/libmaple/pwr.c
@@ -0,0 +1,42 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 LeafLabs, LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *****************************************************************************/
+
+#include "pwr.h"
+#include "rcc.h"
+
+pwr_dev pwr = {
+ .regs = PWR_BASE;
+};
+
+const pwr_dev *PWR = &pwr;
+
+/**
+ * Enables the power interface clock, and resets the power device.
+ */
+void pwr_init(void) {
+ rcc_clk_enable(RCC_PWR);
+ rcc_reset_dev(RCC_PWR);
+}
diff --git a/libmaple/pwr.h b/libmaple/pwr.h
index 96a8356..5ff815d 100644
--- a/libmaple/pwr.h
+++ b/libmaple/pwr.h
@@ -29,18 +29,52 @@
* @brief Power control (PWR) defines.
*/
-#define PWR_BASE 0x40007000
-
-#define PWR_CR (PWR_BASE + 0x0)
-#define PWR_CR_DBP 8 /* Disable backup domain write protection bit */
-#define PWR_CR_PVDE 4 /* Power voltage detector enable bit */
-#define PWR_CR_CSBF 3 /* Clear standby flag bit */
-#define PWR_CR_CWUF 2 /* Clear wakeup flag bit */
-#define PWR_CR_PDDS 1 /* Power down deepsleep bit */
-#define PWR_CR_LPDS 0 /* Low-power deepsleep bit */
-
-#define PWR_CSR (PWR_BASE + 0x4)
-#define PWR_CSR_EWUP 8 /* Enable wakeup pin bit */
-#define PWR_CSR_PVDO 2 /* PVD output bit */
-#define PWR_CSR_SBF 1 /* Standby flag bit */
-#define PWR_CSR_WUF 0 /* Wakeup flag bit */
+#include "libmaple.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Power interface register map. */
+typedef struct pwr_reg_map {
+ __io uint32 CR; /**< Control register */
+ __io uint32 CSR; /**< Control and status register */
+} pwr_reg_map;
+
+/*
+ * Power peripheral base.
+ */
+#define PWR_BASE ((pwr_reg_map*)0x40007000)
+
+/** Power interface device. */
+typedef struct pwr_dev {
+ pwr_reg_map *regs;
+} pwr_dev;
+
+/**
+ * Power device.
+ */
+extern const pwr_dev *PWR;
+/*
+ * Register bit definitions
+ */
+
+/* Control register */
+#define PWR_CR_DBP 8 /**< Disable backup domain write protection bit */
+#define PWR_CR_PVDE 4 /**< Power voltage detector enable bit */
+#define PWR_CR_CSBF 3 /**< Clear standby flag bit */
+#define PWR_CR_CWUF 2 /**< Clear wakeup flag bit */
+#define PWR_CR_PDDS 1 /**< Power down deepsleep bit */
+#define PWR_CR_LPDS 0 /**< Low-power deepsleep bit */
+
+/* Control and status register */
+#define PWR_CSR_EWUP 8 /**< Enable wakeup pin bit */
+#define PWR_CSR_PVDO 2 /**< PVD output bit */
+#define PWR_CSR_SBF 1 /**< Standby flag bit */
+#define PWR_CSR_WUF 0 /**< Wakeup flag bit */
+
+void pwr_init(void);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/libmaple/rcc.c b/libmaple/rcc.c
index 8edccd9..d3fb6a3 100644
--- a/libmaple/rcc.c
+++ b/libmaple/rcc.c
@@ -54,6 +54,7 @@ static const struct rcc_dev_info rcc_dev_table[] = {
[RCC_AFIO] = { .clk_domain = APB2, .line_num = 0 },
[RCC_ADC1] = { .clk_domain = APB2, .line_num = 9 },
[RCC_ADC2] = { .clk_domain = APB2, .line_num = 10 },
+ [RCC_ADC3] = { .clk_domain = APB2, .line_num = 15 },
[RCC_USART1] = { .clk_domain = APB2, .line_num = 14 },
[RCC_USART2] = { .clk_domain = APB1, .line_num = 17 },
[RCC_USART3] = { .clk_domain = APB1, .line_num = 18 },
@@ -73,6 +74,8 @@ static const struct rcc_dev_info rcc_dev_table[] = {
[RCC_DAC] = { .clk_domain = APB1, .line_num = 29 }, // High-density only
[RCC_DMA1] = { .clk_domain = AHB, .line_num = 0 },
[RCC_DMA2] = { .clk_domain = AHB, .line_num = 1 }, // High-density only
+ [RCC_PWR] = { .clk_domain = APB1, .line_num = 28},
+ [RCC_BKP] = { .clk_domain = APB1, .line_num = 27}
[RCC_I2C1] = { .clk_domain = APB1, .line_num = 21 }, // High-density only
[RCC_I2C2] = { .clk_domain = APB1, .line_num = 22 }, // High-density only
};
@@ -118,18 +121,18 @@ void rcc_clk_init(uint32 sysclk_src, uint32 pll_src, uint32 pll_mul) {
/**
* @brief Turn on the clock line on a device
- * @param dev_num device to turn on
+ * @param device Clock ID of the device to turn on.
*/
-void rcc_clk_enable(uint32 dev_num) {
+void rcc_clk_enable(rcc_clk_id device) {
static const uint32 enable_regs[] = {
[APB1] = RCC_APB1ENR,
[APB2] = RCC_APB2ENR,
[AHB] = RCC_AHBENR,
};
- uint8 clk_domain = rcc_dev_table[dev_num].clk_domain;
+ uint8 clk_domain = rcc_dev_table[device].clk_domain;
- __set_bits(enable_regs[clk_domain], BIT(rcc_dev_table[dev_num].line_num));
+ __set_bits(enable_regs[clk_domain], BIT(rcc_dev_table[device].line_num));
}
/**
@@ -155,16 +158,16 @@ void rcc_set_prescaler(uint32 prescaler, uint32 divider) {
/**
* @brief reset a device
- * @param dev_num device to reset
+ * @param device Clock ID of the device to reset.
*/
-void rcc_reset_dev(uint32 dev_num) {
+void rcc_reset_dev(rcc_clk_id device) {
static const uint32 reset_regs[] = {
[APB1] = RCC_APB1RSTR,
[APB2] = RCC_APB2RSTR,
};
- uint8 clk_domain = rcc_dev_table[dev_num].clk_domain;
+ uint8 clk_domain = rcc_dev_table[device].clk_domain;
- __set_bits(reset_regs[clk_domain], BIT(rcc_dev_table[dev_num].line_num));
- __clear_bits(reset_regs[clk_domain], BIT(rcc_dev_table[dev_num].line_num));
+ __set_bits(reset_regs[clk_domain], BIT(rcc_dev_table[device].line_num));
+ __clear_bits(reset_regs[clk_domain], BIT(rcc_dev_table[device].line_num));
}
diff --git a/libmaple/rcc.h b/libmaple/rcc.h
index 1a59219..569da57 100644
--- a/libmaple/rcc.h
+++ b/libmaple/rcc.h
@@ -144,8 +144,10 @@ enum {
RCC_PRESCALER_ADC
};
-// RCC Devices
-enum {
+/*
+ * Identifies bus and clock line for a device
+ */
+typedef enum {
RCC_GPIOA,
RCC_GPIOB,
RCC_GPIOC,
@@ -156,6 +158,7 @@ enum {
RCC_AFIO,
RCC_ADC1,
RCC_ADC2,
+ RCC_ADC3,
RCC_USART1,
RCC_USART2,
RCC_USART3,
@@ -175,14 +178,16 @@ enum {
RCC_DAC, // High-density devices only (Maple Native)
RCC_DMA1,
RCC_DMA2, // High-density devices only (Maple Native)
+ RCC_PWR,
+ RCC_BKP,
RCC_I2C1,
RCC_I2C2
-};
+} rcc_clk_id;
void rcc_clk_init(uint32 sysclk_src, uint32 pll_src, uint32 pll_mul);
-void rcc_clk_enable(uint32 dev);
-void rcc_reset_dev(uint32 dev);
+void rcc_clk_enable(rcc_clk_id device);
+void rcc_reset_dev(rcc_clk_id device);
void rcc_set_prescaler(uint32 prescaler, uint32 divider);
#ifdef __cplusplus
diff --git a/libmaple/systick.c b/libmaple/systick.c
index b056001..b9a52c1 100644
--- a/libmaple/systick.c
+++ b/libmaple/systick.c
@@ -64,6 +64,6 @@ void systick_resume() {
}
/** SysTick interrupt handler. Bumps up the tick counter. */
-void SysTickHandler(void) {
+void __exc_systick(void) {
systick_timer_millis++;
}
diff --git a/libmaple/timers.c b/libmaple/timers.c
index 29aeeba..c561d39 100644
--- a/libmaple/timers.c
+++ b/libmaple/timers.c
@@ -55,7 +55,7 @@ struct timer_dev timer_dev_table[] = {
.rcc_dev_num = RCC_TIMER4,
.nvic_dev_num = NVIC_TIMER4
},
-#if NR_TIMERS >= 8
+#ifdef STM32_HIGH_DENSITY
/* High density devices only (eg, Maple Native) */
[TIMER5] = {
.base = (timer_port*)TIMER5_BASE,
@@ -82,7 +82,7 @@ void timer_init(timer_dev_num timer_num, uint16 prescale) {
if (timer_num == TIMER1) {
is_advanced = 1;
}
-#if NR_TIMERS >= 8
+#ifdef STM32_HIGH_DENSITY
if (timer_num == TIMER8) {
is_advanced = 1;
}
@@ -193,12 +193,8 @@ void timer_set_reload(timer_dev_num timer_num, uint16 max_reload) {
* or similar to prevent interrupts and PWM output without 16 seperate function
* calls to timer_set_mode */
void timer_disable_all(void) {
- // TODO: refactor
-
- /* Note: this must be very robust because it gets called from,
- e.g., ASSERT */
timer_port *timer;
-#if NR_TIMERS >= 8
+#ifdef STM32_HIGH_DENSITY
timer_port *timers[6] = { (timer_port*)TIMER1_BASE,
(timer_port*)TIMER2_BASE,
(timer_port*)TIMER3_BASE,
@@ -386,7 +382,7 @@ void timer_generate_update(timer_dev_num timer_num) {
* registers /or/ has overflowed.
*
* This is a rather long implementation... */
-void TIM1_CC_IRQHandler(void) {
+void __irq_tim1_cc(void) {
timer_port *timer = (timer_port*)TIMER1_BASE;
uint16 sr_buffer;
sr_buffer = timer->SR;
@@ -422,7 +418,7 @@ void TIM1_CC_IRQHandler(void) {
//timer->EGR = 1;
}
}
-void TIM2_IRQHandler(void) {
+void __irq_tim2(void) {
/* This is a rather long implementation... */
timer_port *timer = (timer_port*)TIMER2_BASE;
uint16 sr_buffer;
@@ -457,7 +453,7 @@ void TIM2_IRQHandler(void) {
//timer->EGR = 1;
}
}
-void TIM3_IRQHandler(void) {
+void __irq_tim3(void) {
/* This is a rather long implementation... */
timer_port *timer = (timer_port*)TIMER3_BASE;
uint16 sr_buffer;
@@ -493,7 +489,7 @@ void TIM3_IRQHandler(void) {
}
}
-void TIM4_IRQHandler(void) {
+void __irq_tim4(void) {
/* This is a rather long implementation... */
timer_port*timer = (timer_port*)TIMER4_BASE;
uint16 sr_buffer;
diff --git a/libmaple/timers.h b/libmaple/timers.h
index 99bcab6..1f6afcd 100644
--- a/libmaple/timers.h
+++ b/libmaple/timers.h
@@ -206,7 +206,7 @@ typedef enum {
TIMER2, /*< General purpose timer TIM2 */
TIMER3, /*< General purpose timer TIM3 */
TIMER4, /*< General purpose timer TIM4 */
-#if NR_TIMERS >= 8
+#ifdef STM32_HIGH_DENSITY
TIMER5, /*< General purpose timer TIM5; high density only */
/* FIXME maple native: put timers 6 and 7 back in and make the
corresponding changes to timers.c */
@@ -412,8 +412,8 @@ void timer_generate_update(timer_dev_num timer_num);
/**
* Turn on PWM with duty_cycle.
*
- * @param ccr TIMERx_CHn_CCR, where x goes from 1 to NR_TIMERS,
- * and n goes from 1 to 4.
+ * @param ccr TIMERx_CHn_CCR, where x ranges over timers, and n ranges
+ * from 1 to 4.
*
* @param duty_cycle: A number between 0 and
* timer_get_compare_value(TIMERx, y), where x and y are as above.
diff --git a/libmaple/usart.c b/libmaple/usart.c
index 44a5c92..494a29f 100644
--- a/libmaple/usart.c
+++ b/libmaple/usart.c
@@ -61,7 +61,7 @@ struct usart_dev usart_dev_table[] = {
.rcc_dev_num = RCC_USART3,
.nvic_dev_num = NVIC_USART3
},
-#if NR_USART >= 5
+#ifdef STM32_HIGH_DENSITY
/* TODO test */
[UART4] = {
.base = (usart_port*)UART4_BASE,
@@ -95,24 +95,24 @@ static inline void usart_irq(int usart_num) {
/* TODO: Check the disassembly for the following functions to make
sure GCC inlined properly. */
-void USART1_IRQHandler(void) {
+void __irq_usart1(void) {
usart_irq(USART1);
}
-void USART2_IRQHandler(void) {
+void __irq_usart2(void) {
usart_irq(USART2);
}
-void USART3_IRQHandler(void) {
+void __irq_usart3(void) {
usart_irq(USART3);
}
-#if NR_USART >= 5
-void UART4_IRQHandler(void) {
+#ifdef STM32_HIGH_DENSITY
+void __irq_uart4(void) {
usart_irq(UART4);
}
-void UART5_IRQHandler(void) {
+void __irq_uart5(void) {
usart_irq(UART5);
}
#endif
@@ -124,7 +124,11 @@ void UART5_IRQHandler(void) {
* @param baud Baud rate to be set at
*/
void usart_init(uint8 usart_num, uint32 baud) {
- ASSERT(usart_num <= NR_USART);
+#ifdef STM32_HIGH_DENSITY
+ ASSERT(usart_num <= UART5);
+#else
+ ASSERT(usart_num <= USART3);
+#endif
usart_port *port;
ring_buffer *ring_buf;
@@ -170,7 +174,7 @@ void usart_disable_all() {
usart_disable(USART1);
usart_disable(USART2);
usart_disable(USART3);
-#if NR_USART >= 5
+#ifdef STM32_HIGH_DENSITY
usart_disable(UART4);
usart_disable(UART5);
#endif
diff --git a/libmaple/usart.h b/libmaple/usart.h
index 0ca3f55..90b3415 100644
--- a/libmaple/usart.h
+++ b/libmaple/usart.h
@@ -43,8 +43,10 @@ enum {
USART1,
USART2,
USART3,
+#ifdef STM32_HIGH_DENSITY
UART4,
UART5,
+#endif
};
/* peripheral register struct */
diff --git a/libmaple/usb/descriptors.c b/libmaple/usb/descriptors.c
index 360e6dd..8dd9521 100644
--- a/libmaple/usb/descriptors.c
+++ b/libmaple/usb/descriptors.c
@@ -150,43 +150,50 @@ const USB_Descriptor_Config usbVcomDescriptor_Config = {
// }
};
-/*
- String Identifiers:
+/*****************************************************************************
+ *****************************************************************************
+ ***
+ *** FIXME FIXME FIXME NOT THE RIGHT THING! MOVE ALL THIS INTO TO WIRISH!
+ ***
+ *****************************************************************************
+ *****************************************************************************/
- we may choose to specify any or none of the following string
- identifiers:
+const uint8 usbVcomDescriptor_LangID[USB_DESCRIPTOR_STRING_LEN(1)] = {
+ USB_DESCRIPTOR_STRING_LEN(1),
+ USB_DESCRIPTOR_TYPE_STRING,
+ 0x09,
+ 0x04
+};
- iManufacturer: LeafLabs
- iProduct: Maple R3
- iSerialNumber: NONE
- iConfiguration: NONE
- iInterface(CCI): NONE
- iInterface(DCI): NONE
+const uint8 usbVcomDescriptor_iManufacturer[USB_DESCRIPTOR_STRING_LEN(8)] = {
+ USB_DESCRIPTOR_STRING_LEN(8),
+ USB_DESCRIPTOR_TYPE_STRING,
+ 'L', 0, 'e', 0, 'a', 0, 'f', 0,
+ 'L', 0, 'a', 0, 'b', 0, 's', 0
+};
- additionally we must provide the unicode language identifier,
- which is 0x0409 for US English
-*/
+/*
+ String Identifiers:
-const uint8 usbVcomDescriptor_LangID[USB_DESCRIPTOR_STRING_LEN(1)] =
-{
- USB_DESCRIPTOR_STRING_LEN(1),
- USB_DESCRIPTOR_TYPE_STRING,
- 0x09,
- 0x04
-};
+ we may choose to specify any or none of the following string
+ identifiers:
-const uint8 usbVcomDescriptor_iManufacturer[USB_DESCRIPTOR_STRING_LEN(8)] =
-{
- USB_DESCRIPTOR_STRING_LEN(8),
- USB_DESCRIPTOR_TYPE_STRING,
- 'L', 0, 'e', 0, 'a', 0, 'f', 0,
- 'L', 0, 'a', 0, 'b', 0, 's', 0
-};
+ iManufacturer: LeafLabs
+ iProduct: Maple R3
+ iSerialNumber: NONE
+ iConfiguration: NONE
+ iInterface(CCI): NONE
+ iInterface(DCI): NONE
-const uint8 usbVcomDescriptor_iProduct[USB_DESCRIPTOR_STRING_LEN(8)] =
-{
- USB_DESCRIPTOR_STRING_LEN(8),
- USB_DESCRIPTOR_TYPE_STRING,
- 'M', 0, 'a', 0, 'p', 0, 'l', 0,
- 'e', 0, ' ', 0, 'R', 0, '3', 0
+ additionally we must provide the unicode language identifier,
+ which is 0x0409 for US English
+*/
+const uint8 usbVcomDescriptor_iProduct[USB_DESCRIPTOR_STRING_LEN(8)] = {
+ USB_DESCRIPTOR_STRING_LEN(8),
+ USB_DESCRIPTOR_TYPE_STRING,
+ 'M', 0, 'a', 0, 'p', 0, 'l', 0,
+ 'e', 0, ' ', 0, ' ', 0, ' ', 0
};
+
+/*****************************************************************************
+ *****************************************************************************/
diff --git a/libmaple/usb/usb.c b/libmaple/usb/usb.c
index d875785..62f56fc 100644
--- a/libmaple/usb/usb.c
+++ b/libmaple/usb/usb.c
@@ -241,7 +241,7 @@ void usbDsbISR(void) {
}
/* overloaded ISR routine, this is the main usb ISR */
-void usb_lpIRQHandler(void) {
+void __irq_usb_lp_can_rx0(void) {
wIstr = _GetISTR();
/* go nuts with the preproc switches since this is an ISTR and must be FAST */
diff --git a/libmaple/usb/usb.h b/libmaple/usb/usb.h
index 0ed02e5..92f606c 100644
--- a/libmaple/usb/usb.h
+++ b/libmaple/usb/usb.h
@@ -69,7 +69,7 @@ void usbDsbISR(void);
void usbEnbISR(void);
/* overloaded ISR routine, this is the main usb ISR */
-void usb_lpIRQHandler(void);
+void __irq_usb_lp_can_rx0(void);
void usbWaitReset(void);
/* blocking functions for send/receive */
diff --git a/libmaple/usb/usb_config.h b/libmaple/usb/usb_config.h
index e5f3979..394c580 100644
--- a/libmaple/usb/usb_config.h
+++ b/libmaple/usb/usb_config.h
@@ -5,6 +5,67 @@
#include "usb_lib.h"
+/******************************************************************************
+ ******************************************************************************
+ ***
+ *** HACK ALERT
+ ***
+ *** FIXME FIXME FIXME FIXME
+ ***
+ *** A bunch of board-specific #defines that are only used by the
+ *** USB routines got put into libmaple.h for what appear to be
+ *** historical reasons. I'm [mbolivar] putting them in here for
+ *** now, so that we can treat the usb/ directory as a black box,
+ *** freeing the rest of libmaple/ to be implemented as a
+ *** general-purpose STM32 library. All of this REALLY needs to get
+ *** moved into wirish when we get a chance to redo the USB stack.
+ ***
+ ******************************************************************************
+ *****************************************************************************/
+
+#define VCOM_ID_VENDOR 0x1EAF
+#define RESET_DELAY (100)
+#define USB_CONFIG_MAX_POWER (100 >> 1)
+
+#if defined(BOARD_maple)
+
+ /* USB Identifier numbers */
+ #define VCOM_ID_PRODUCT 0x0004
+ #define USB_DISC_BANK GPIOC_BASE
+ #define USB_DISC_PIN 12
+
+#elif defined(BOARD_maple_mini)
+
+ #define VCOM_ID_PRODUCT 0x0005
+ #define USB_DISC_BANK GPIOB_BASE
+ #define USB_DISC_PIN 9
+
+#elif defined(BOARD_maple_native)
+
+ #define VCOM_ID_PRODUCT 0x0006
+ #define USB_DISC_BANK GPIOB_BASE
+ #define USB_DISC_PIN 8
+
+#else
+
+#error ("Sorry! the USB stack relies on LeafLabs board-specific " \
+ "configuration right now. If you want, you can pretend you're one " \
+ "of our boards; i.e., #define BOARD_maple, BOARD_maple_mini, or " \
+ "BOARD_maple_native according to what matches your MCU best. " \
+ "You should also take a look at libmaple/usb/descriptors.c; we make " \
+ "some assumptions there that you probably won't like.")
+
+#endif
+
+/******************************************************************************
+ ******************************************************************************
+ ***
+ *** END HACK
+ ***
+ ******************************************************************************
+ *****************************************************************************/
+
+
/* choose addresses to give endpoints the max 64 byte buffers */
#define USB_BTABLE_ADDRESS 0x00
#define VCOM_CTRL_EPNUM 0x00
@@ -33,14 +94,15 @@
#define NUM_ENDPTS 0x04
/* handle all usb interrupts */
-#define ISR_MSK ( CNTR_CTRM | \
- CNTR_WKUPM | \
- CNTR_SUSPM | \
- CNTR_ERRM | \
- CNTR_SOFM | \
- CNTR_ESOFM | \
- CNTR_RESETM )
+#define ISR_MSK (CNTR_CTRM | \
+ CNTR_WKUPM | \
+ CNTR_SUSPM | \
+ CNTR_ERRM | \
+ CNTR_SOFM | \
+ CNTR_ESOFM | \
+ CNTR_RESETM)
#define F_SUSPEND_ENABLED 1
+
#endif
diff --git a/libmaple/util.c b/libmaple/util.c
index 135f005..3408a2e 100644
--- a/libmaple/util.c
+++ b/libmaple/util.c
@@ -34,25 +34,58 @@
#include "adc.h"
#include "timers.h"
-/* Error assert + fade */
-void _fail(const char* file, int line, const char* exp) {
- int32 slope = 1;
- uint32 CC = 0x0000;
- uint32 TOP_CNT = 0x02FF;
- uint32 i = 0;
+/* Failed asserts send out a message on this USART. */
+#ifndef ERROR_USART_NUM
+#define ERROR_USART_NUM USART2
+#define ERROR_USART_BAUD 9600
+#define ERROR_TX_PORT GPIOA_BASE
+#define ERROR_TX_PIN 2
+#endif
+
+/* If you define ERROR_LED_PORT and ERROR_LED_PIN, then a failed
+ assert will also throb an LED connected to that port an pin.
+ FIXME this should work together with wirish somehow. */
+#if defined(ERROR_LED_PORT) && defined(ERROR_LED_PIN)
+#define HAVE_ERROR_LED
+#endif
- /* Turn off interrupts */
+/**
+ * @brief Disables all peripheral interrupts except USB and fades the
+ * error LED.
+ *
+ * Called from exc.S with global interrupts disabled.
+ */
+void __error(void) {
+ /* Turn off peripheral interrupts */
nvic_irq_disable_all();
/* Turn off timers */
timer_disable_all();
/* Turn off ADC */
- adc_disable();
+ adc_disable_all();
/* Turn off all usarts */
usart_disable_all();
+ /* Turn the USB interrupt back on so the bootloader keeps on functioning */
+ nvic_irq_enable(NVIC_INT_USBHP);
+ nvic_irq_enable(NVIC_INT_USBLP);
+
+ /* Reenable global interrupts */
+ nvic_globalirq_enable();
+ throb();
+}
+
+/**
+ * @brief Prints an error message on a uart upon a failed assertion
+ * and error throbs.
+ * @param file Source file of failed assertion
+ * @param line Source line of failed assertion
+ * @param exp String representation of failed assertion
+ * @sideeffect Turns of all peripheral interrupts except USB.
+ */
+void _fail(const char* file, int line, const char* exp) {
/* 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);
@@ -67,18 +100,17 @@ void _fail(const char* file, int line, const char* exp) {
usart_putc(ERROR_USART_NUM, '\n');
usart_putc(ERROR_USART_NUM, '\r');
- /* 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_irq_enable(NVIC_INT_USBHP);
- nvic_irq_enable(NVIC_INT_USBLP);
-
/* Error fade */
- throb();
+ __error();
}
+
+/**
+ * @brief Fades the error LED on and off
+ * @sideeffect Sets output push-pull on ERROR_LED_PIN.
+ */
void throb(void) {
+#ifdef HAVE_ERROR_LED
int32 slope = 1;
uint32 CC = 0x0000;
uint32 TOP_CNT = 0x0200;
@@ -105,5 +137,10 @@ void throb(void) {
}
i++;
}
+#else
+ /* No error LED is connected; do nothing. */
+ while (1)
+ ;
+#endif
}
diff --git a/libmaple/util.h b/libmaple/util.h
index 64782d9..fb524c2 100644
--- a/libmaple/util.h
+++ b/libmaple/util.h
@@ -32,7 +32,18 @@
#ifndef _UTIL_H_
#define _UTIL_H_
-#include "libmaple.h"
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+/* Debug configuration */
+#define DEBUG_NONE 0
+#define DEBUG_FAULT 1
+#define DEBUG_ALL 2
+
+#ifndef DEBUG_LEVEL
+#define DEBUG_LEVEL DEBUG_ALL
+#endif
#define BIT(shift) (1UL << (shift))
#define BIT_MASK_SHIFT(mask, shift) ((mask) << (shift))
@@ -41,10 +52,16 @@
#define GET_BITS(x, m, n) ((((uint32)x) << (31 - (n))) >> ((31 - (n)) + (m)))
/* Bit-banding macros */
+/* Bitbanded Memory sections */
+#define BITBAND_SRAM_REF 0x20000000
+#define BITBAND_SRAM_BASE 0x22000000
+#define BITBAND_PERI_REF 0x40000000
+#define BITBAND_PERI_BASE 0x42000000
/* Convert SRAM address */
#define BITBAND_SRAM(a,b) ((BITBAND_SRAM_BASE+(a-BITBAND_SRAM_REF)*32+(b*4)))
-/* Convert PERI address */
-#define BITBAND_PERI(a,b) ((BITBAND_PERI_BASE+(a-BITBAND_PERI_REF)*32+(b*4)))
+/* Convert peripheral address */
+#define BITBAND_PERI(a, b) ((BITBAND_PERI_BASE + \
+ ((uint32)a - BITBAND_PERI_REF) * 32 + (b * 4)))
#define REG_SET(reg, val) (*(volatile uint32*)(reg) = (val))
#define REG_SET_BIT(reg, bit) (*(volatile uint32*)(reg) |= BIT(bit))
@@ -62,18 +79,10 @@
#define __write(reg, value) (*(volatile uint32*)(reg) = (value))
#define IS_POWER_OF_TWO(v) (v && !(v & (v - 1)))
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-
+void __error(void);
void _fail(const char*, int, const char*);
void throb(void);
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
/* Asserts for sanity checks, redefine DEBUG_LEVEL in libmaple.h to
* compile out these checks */
@@ -99,5 +108,9 @@ void throb(void);
#define ASSERT_FAULT(exp) (void)((0))
#endif
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
#endif