aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--contrib/automake/Makefile.am115
-rw-r--r--contrib/automake/configure.ac8
-rw-r--r--libmaple/adc.h7
-rw-r--r--libmaple/bkp.c86
-rw-r--r--libmaple/bkp.h86
-rw-r--r--libmaple/dma.c148
-rw-r--r--libmaple/dma.h122
-rw-r--r--libmaple/exti.c6
-rw-r--r--libmaple/exti.h5
-rw-r--r--libmaple/iwdg.c56
-rw-r--r--libmaple/iwdg.h61
-rw-r--r--libmaple/libmaple.h5
-rw-r--r--libmaple/nvic.c17
-rw-r--r--libmaple/nvic.h37
-rw-r--r--libmaple/pwr.h46
-rw-r--r--libmaple/rcc.c6
-rw-r--r--libmaple/rcc.h13
-rw-r--r--libmaple/ring_buffer.h99
-rw-r--r--libmaple/rules.mk23
-rw-r--r--libmaple/systick.c7
-rw-r--r--libmaple/systick.h9
-rw-r--r--libmaple/usart.c64
-rw-r--r--libmaple/usart.h6
-rw-r--r--libmaple/util.h8
-rwxr-xr-xsupport/stm32loader.py133
-rw-r--r--wirish/time.h11
-rw-r--r--wirish/wirish.c2
27 files changed, 1046 insertions, 140 deletions
diff --git a/contrib/automake/Makefile.am b/contrib/automake/Makefile.am
new file mode 100644
index 0000000..50747db
--- /dev/null
+++ b/contrib/automake/Makefile.am
@@ -0,0 +1,115 @@
+# Top level Makefile for libmaple
+
+# The main library
+lib_LIBRARIES = \
+ libmaple.a \
+ libmapleusb.a \
+ libwirish.a
+
+noinst_PROGRAMS = \
+ main
+
+main_SOURCES = \
+ startup2.c \
+ main.cpp
+
+X = $(srcdir)/support/ld/maple_native
+
+main_LDFLAGS = \
+ --gc-sections \
+ -Map=main.map
+
+main_LDADD = libmaple.a
+
+# Main library
+libmaple_a_SOURCES = \
+ libmaple/adc.c \
+ libmaple/dac.c \
+ libmaple/exc.c \
+ libmaple/exti.c \
+ libmaple/flash.c \
+ libmaple/fsmc.c \
+ libmaple/gpio.c \
+ libmaple/nvic.c \
+ libmaple/rcc.c \
+ libmaple/spi.c \
+ libmaple/systick.c \
+ libmaple/timers.c \
+ libmaple/usart.c \
+ libmaple/util.c
+
+nobase_include_HEADERS = \
+ libmaple/adc.h \
+ libmaple/dac.h \
+ libmaple/exti.h \
+ libmaple/flash.h \
+ libmaple/fsmc.h \
+ libmaple/gpio.h \
+ libmaple/libmaple.h \
+ libmaple/libmaple_types.h \
+ libmaple/nvic.h \
+ libmaple/rcc.h \
+ libmaple/ring_buffer.h \
+ libmaple/spi.h \
+ libmaple/systick.h \
+ libmaple/timers.h \
+ libmaple/usart.h \
+ libmaple/util.h \
+ libmaple/usb/descriptors.h \
+ libmaple/usb/usb.h \
+ libmaple/usb/usb_callbacks.h \
+ libmaple/usb/usb_config.h \
+ libmaple/usb/usb_hardware.h \
+ libmaple/usb/usb_lib/usb_core.h \
+ libmaple/usb/usb_lib/usb_def.h \
+ libmaple/usb/usb_lib/usb_init.h \
+ libmaple/usb/usb_lib/usb_int.h \
+ libmaple/usb/usb_lib/usb_lib.h \
+ libmaple/usb/usb_lib/usb_mem.h \
+ libmaple/usb/usb_lib/usb_regs.h \
+ libmaple/usb/usb_lib/usb_type.h
+
+libmapleusb_a_SOURCES = \
+ libmaple/usb/descriptors.c \
+ libmaple/usb/usb.c \
+ libmaple/usb/usb_callbacks.c \
+ libmaple/usb/usb_hardware.c \
+ libmaple/usb/usb_lib/usb_core.c \
+ libmaple/usb/usb_lib/usb_init.c \
+ libmaple/usb/usb_lib/usb_int.c \
+ libmaple/usb/usb_lib/usb_mem.c \
+ libmaple/usb/usb_lib/usb_regs.c
+
+libwirish_a_SOURCES = \
+ wirish/HardwareTimer.cpp \
+ wirish/Print.cpp \
+ wirish/comm/HardwareSPI.cpp \
+ wirish/comm/HardwareSerial.cpp \
+ wirish/cxxabi-compat.cpp \
+ wirish/ext_interrupts.c \
+ wirish/pwm.c \
+ wirish/time.c \
+ wirish/usb_serial.cpp \
+ wirish/wirish.c \
+ wirish/wirish_analog.c \
+ wirish/wirish_digital.c \
+ wirish/wirish_math.cpp \
+ wirish/wirish_shift.c
+
+MCU := STM32F103RB
+BOARD ?= maple_native
+
+FLAGS = \
+ -Os -g -nostdlib -Wall \
+ -ffunction-sections -fdata-sections -Wl,--gc-sections \
+ -mcpu=cortex-m3 -mthumb -fshort-enums -mfloat-abi=soft \
+ -DBOARD_$(BOARD) -DMCU_$(MCU) -DVECT_TAB_BASE \
+ -I$(srcdir)/libmaple \
+ -I$(srcdir)/libmaple/usb \
+ -I$(srcdir)/libmaple/usb/usb_lib
+
+AM_CFLAGS = $(FLAGS) -std=gnu99
+
+AM_CXXFLAGS = $(FLAGS) \
+ -I$(srcdir)/wirish -I$(srcdir)/wirish/comm \
+ -fno-rtti -fno-exceptions
diff --git a/contrib/automake/configure.ac b/contrib/automake/configure.ac
new file mode 100644
index 0000000..4c52ce2
--- /dev/null
+++ b/contrib/automake/configure.ac
@@ -0,0 +1,8 @@
+AC_INIT(libmaple, 0.1)
+AM_INIT_AUTOMAKE(foreign subdir-objects color-tests)
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_FILES(Makefile)
+AM_PROG_AS
+AC_PROG_CXX
+AM_PROG_LIBTOOL
+AC_OUTPUT
diff --git a/libmaple/adc.h b/libmaple/adc.h
index ce67116..fe1196f 100644
--- a/libmaple/adc.h
+++ b/libmaple/adc.h
@@ -66,15 +66,16 @@ extern "C"{
#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 + 2, 6))
+#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) */
-/* Initialize ADC1 to do one-shot conversions */
+/** Initialize ADC1 to do one-shot conversions */
void adc_init(void);
void adc_disable(void);
-/* Perform a single conversion on ADC[0-15],
+/**
+ * Perform a single conversion on ADC[0-15].
* PRECONDITIONS:
* adc initialized */
static inline int adc_read(int channel) {
diff --git a/libmaple/bkp.c b/libmaple/bkp.c
new file mode 100644
index 0000000..e89abd0
--- /dev/null
+++ b/libmaple/bkp.c
@@ -0,0 +1,86 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 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 "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 */
+
+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;
+}
+
+void bkp_init(void) {
+ /* Set PWREN (28) and BKPEN (27) bits */
+ __set_bits(RCC_APB1ENR, BIT(28) | BIT(27));
+}
+
+void bkp_disable(void) {
+ __clear_bits(RCC_APB1ENR, BIT(28) | BIT(27));
+}
+
+void bkp_enable_writes(void) {
+ /* Set the DBP bit in PWR_CR */
+ __write(BITBAND_PERI(PWR_CR, PWR_CR_DBP), 1);
+}
+
+void bkp_disable_writes(void) {
+ __write(BITBAND_PERI(PWR_CR, PWR_CR_DBP), 0);
+}
+
+uint16 bkp_read(uint8 reg) {
+ volatile uint16* addr = reg_addr(reg);
+ if (addr != 0) {
+ return *addr;
+ }
+ ASSERT(0); /* nonexistent register */
+ return 0;
+}
+
+void bkp_write(uint8 reg, uint16 val) {
+ volatile uint16* addr = reg_addr(reg);
+ if (addr != 0) {
+ *addr = val;
+ }
+ ASSERT(0); /* nonexistent register */
+}
diff --git a/libmaple/bkp.h b/libmaple/bkp.h
new file mode 100644
index 0000000..9ad4c41
--- /dev/null
+++ b/libmaple/bkp.h
@@ -0,0 +1,86 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 LeafLabs, LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *****************************************************************************/
+
+/**
+ * @file bkp.h
+ * @brief Backup register support.
+ */
+
+#ifndef _BKP_H_
+#define _BKP_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)
+
+/**
+ * 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);
+
+/** Disable power and backup interface clocks. */
+void bkp_disable(void);
+
+/**
+ * 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);
+
+/**
+ * Disable write access to the backup registers. Does not disable
+ * backup interface clocks.
+ */
+void bkp_disable_writes(void);
+
+/**
+ * Read a value from given backup data register.
+ * @param reg Data register to read, from 1 to NR_BKP_REGS (10 on Maple).
+ */
+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
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/libmaple/dma.c b/libmaple/dma.c
new file mode 100644
index 0000000..15c96e1
--- /dev/null
+++ b/libmaple/dma.c
@@ -0,0 +1,148 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Michael Hope.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *****************************************************************************/
+
+/**
+ * @file dma.c
+ *
+ * @brief Direct Memory Access peripheral support
+ */
+
+#include "libmaple.h"
+#include "dma.h"
+#include "rcc.h"
+#include "nvic.h"
+
+#define DMA_EN BIT(0)
+
+typedef struct dma_regs {
+ uint32 CCR;
+ uint32 CNDTR;
+ uint32 CPAR;
+ uint32 CMAR;
+} dma_regs;
+
+typedef struct DMAChannel {
+ void (*handler)(void);
+ uint32 irq_line;
+} DMAChannel;
+
+volatile static DMAChannel dma_channels[] = {
+ { .handler = NULL, .irq_line = NVIC_DMA_CH1 },
+ { .handler = NULL, .irq_line = NVIC_DMA_CH2 },
+ { .handler = NULL, .irq_line = NVIC_DMA_CH3 },
+ { .handler = NULL, .irq_line = NVIC_DMA_CH4 },
+ { .handler = NULL, .irq_line = NVIC_DMA_CH5 },
+ { .handler = NULL, .irq_line = NVIC_DMA_CH6 },
+ { .handler = NULL, .irq_line = NVIC_DMA_CH7 }
+};
+
+/** Get the base address of the given channel, asserting and returning
+ * NULL on illegal
+ */
+static dma_regs *dma_get_regs(uint8 channel) {
+ if (channel >= 1 && channel <= 7) {
+ return (dma_regs *)(DMA1_CCR1 + DMA_CHANNEL_STRIDE * (channel-1));
+ } else {
+ ASSERT(0);
+ return NULL;
+ }
+}
+
+/* Zero-based indexing */
+static inline void dispatch_handler(uint8 channel_idx) {
+ ASSERT(dma_channels[channel_idx].handler);
+ if (dma_channels[channel_idx].handler) {
+ (dma_channels[channel_idx].handler)();
+ }
+}
+
+void DMAChannel1_IRQHandler(void) {
+ dispatch_handler(0);
+}
+
+void DMAChannel2_IRQHandler(void) {
+ dispatch_handler(1);
+}
+
+void DMAChannel3_IRQHandler(void) {
+ dispatch_handler(2);
+}
+
+void DMAChannel4_IRQHandler(void) {
+ dispatch_handler(3);
+}
+
+void DMAChannel5_IRQHandler(void) {
+ dispatch_handler(4);
+}
+
+void DMAChannel6_IRQHandler(void) {
+ dispatch_handler(5);
+}
+
+void DMAChannel7_IRQHandler(void) {
+ dispatch_handler(6);
+}
+
+void dma_init(uint8 channel, volatile void *paddr,
+ dma_transfer_size psize, dma_transfer_size msize,
+ int mode) {
+ volatile dma_regs *regs = dma_get_regs(channel);
+
+ if (regs != NULL) {
+ rcc_clk_enable(RCC_DMA1);
+
+ regs->CCR = ((0 << 12) /* Low priority */
+ | (msize << 10)
+ | (psize << 8)
+ | (0 << 0) /* Disabled (until started) */
+ | mode);
+
+ regs->CPAR = (uint32)paddr;
+ }
+}
+
+void dma_start(uint8 channel, volatile void *buffer, uint16 count) {
+ volatile dma_regs *regs = dma_get_regs(channel);
+
+ if (regs != NULL) {
+ regs->CCR &= ~DMA_EN; /* CMAR may not be written with EN set */
+ regs->CMAR = (uint32)buffer;
+ regs->CNDTR = count;
+
+ regs->CCR |= DMA_EN;
+ }
+}
+
+void dma_attach_interrupt(uint8 channel, voidFuncPtr handler) {
+ channel--; /* 1-based -> 0-based indexing */
+ dma_channels[channel].handler = handler;
+ nvic_irq_enable(dma_channels[channel].irq_line);
+}
+
+void dma_detach_interrupt(uint8 channel) {
+ channel--;
+ nvic_irq_disable(dma_channels[channel].irq_line);
+ dma_channels[channel].handler = NULL;
+}
diff --git a/libmaple/dma.h b/libmaple/dma.h
new file mode 100644
index 0000000..3417f02
--- /dev/null
+++ b/libmaple/dma.h
@@ -0,0 +1,122 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Michael Hope.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *****************************************************************************/
+
+/**
+ * @file dma.h
+ *
+ * @brief Direct Memory Access peripheral support
+ *
+ * TODO: add DMA2 support for high-density devices.
+ */
+
+#ifndef _DMA_H_
+#define _DMA_H_
+
+#include "libmaple_types.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+/** Base address of the DMA1 peripheral */
+#define DMA1_BASE 0x40020000
+/** DMA Interrupt Status Register */
+#define DMA1_ISR (DMA1_BASE + 0x00)
+/** DMA Interrupt Flag Clear Register */
+#define DMA1_IFCR (DMA1_BASE + 0x04)
+/** DMA Channel Configuration Register */
+#define DMA1_CCR1 (DMA1_BASE + 0x08)
+/** DMA Channel Number of Data Register */
+#define DMA1_CNDTR1 (DMA1_BASE + 0x0C)
+/** DMA Channel Peripheral Address Register */
+#define DMA1_CPAR1 (DMA1_BASE + 0x10)
+/** DMA Channel Memory Address Register */
+#define DMA1_CMAR1 (DMA1_BASE + 0x14)
+/** Spacing between channel registers */
+#define DMA_CHANNEL_STRIDE 20
+
+/** Flags for DMA transfer configuration. */
+typedef enum dma_mode_flags {
+ DMA_MINC_MODE = 1 << 7, /**< Auto-increment memory address */
+ DMA_PINC_MODE = 1 << 6, /**< Auto-increment peripheral address */
+ DMA_CIRC_MODE = 1 << 5, /**< Circular mode */
+ DMA_FROM_MEM = 1 << 4, /**< Read from memory to peripheral */
+ DMA_TRNS_ERR = 1 << 3, /**< Interrupt on transfer error */
+ DMA_HALF_TRNS = 1 << 2, /**< Interrupt on half-transfer */
+ DMA_TRNS_CMPLT = 1 << 1 /**< Interrupt on transfer completion */
+} dma_mode_flags;
+
+/** Source and destination transfer sizes. */
+typedef enum dma_transfer_size {
+ DMA_SIZE_8BITS = 0,
+ DMA_SIZE_16BITS = 1,
+ DMA_SIZE_32BITS = 2
+} dma_transfer_size;
+
+/**
+ * Initialize a DMA channel. If desired, attach an interrupt handler
+ * using dma_attach_interrupt(). Start the transfer using
+ * dma_start().
+ *
+ * @param channel the channel number (1..7)
+ * @param paddr address of the peripheral
+ * @param psize peripheral size
+ * @param msize memory size
+ * @param mode OR of the dma_mode_flags
+ * @see dma_mode_flags
+ * @see dma_attach_interrupt()
+ * @see dma_start() */
+void dma_init(uint8 channel, volatile void *paddr,
+ dma_transfer_size psize, dma_transfer_size msize,
+ int mode);
+
+/**
+ * Begin a DMA transfer initialized with dma_init().
+ *
+ * @param channel Channel transfer to start.
+ * @param buffer Buffer to write to (unless DMA_FROM_MEM was set in
+ * mode argument to dma_init(), in which case, buffer
+ * to read from). This must be aligned with msize
+ * argument to dma_init().
+ * @param count Number of elements to transfer.
+ * @see dma_init() */
+void dma_start(uint8 channel, volatile void *buffer, uint16 count);
+
+/**
+ * Attach an interrupt handler for the given DMA channel.
+ * @param channel DMA channel (1..7)
+ * @param handler Interrupt handler to attach
+ * @see voidFuncPtr */
+void dma_attach_interrupt(uint8 channel, voidFuncPtr handler);
+
+/**
+ * Detach any handler associated with the given DMA channel.
+ * @param channel Channel whose interrupt handler to detach. */
+void dma_detach_interrupt(uint8 channel);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/libmaple/exti.c b/libmaple/exti.c
index 496f0a1..150dd05 100644
--- a/libmaple/exti.c
+++ b/libmaple/exti.c
@@ -180,11 +180,11 @@ void exti_attach_interrupt(uint32 port,
break;
}
- /* Configure the enable interrupt bits for the NVIC */
- nvic_irq_enable(exti_channels[channel].irq_line);
-
/* Register the handler */
exti_channels[channel].handler = handler;
+
+ /* Configure the enable interrupt bits for the NVIC */
+ nvic_irq_enable(exti_channels[channel].irq_line);
}
diff --git a/libmaple/exti.h b/libmaple/exti.h
index cab2963..806578f 100644
--- a/libmaple/exti.h
+++ b/libmaple/exti.h
@@ -153,8 +153,9 @@
extern "C"{
#endif
-void exti_attach_interrupt(uint32, uint32, voidFuncPtr, uint32);
-void exti_detach_interrupt(uint32);
+void exti_attach_interrupt(uint32 port, uint32 pin, voidFuncPtr handler,
+ uint32 mode);
+void exti_detach_interrupt(uint32 channel);
#ifdef __cplusplus
} // extern "C"
diff --git a/libmaple/iwdg.c b/libmaple/iwdg.c
new file mode 100644
index 0000000..82a0151
--- /dev/null
+++ b/libmaple/iwdg.c
@@ -0,0 +1,56 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Michael Hope.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *****************************************************************************/
+
+/**
+ * @file iwdg.c
+ *
+ * @brief Independent watchdog support
+ */
+
+#include "libmaple.h"
+#include "iwdg.h"
+
+#define IWDG_UNLOCK 0x5555
+#define IWDG_START 0xCCCC
+#define IWDG_FEED 0xAAAA
+
+/**
+ * @brief Initialise and start the watchdog
+ *
+ * The prescaler and reload set the timeout. A prescaler of 3 divides
+ * the 40 kHz clock by 32 and gives roughly 1 ms per reload.
+ */
+void iwdg_init(uint8 prescaler, uint16 reload) {
+ __write(IWDG_KR, IWDG_UNLOCK);
+ __write(IWDG_PR, prescaler);
+ __write(IWDG_RLR, reload);
+
+ /* Start things off */
+ __write(IWDG_KR, IWDG_START);
+ __write(IWDG_KR, IWDG_FEED);
+}
+
+void iwdg_feed(void) {
+ __write(IWDG_KR, IWDG_FEED);
+}
diff --git a/libmaple/iwdg.h b/libmaple/iwdg.h
new file mode 100644
index 0000000..4ab0ddf
--- /dev/null
+++ b/libmaple/iwdg.h
@@ -0,0 +1,61 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 Michael Hope.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *****************************************************************************/
+
+/**
+ * @file iwdg.h
+ *
+ * @brief Independent watchdog support
+ */
+
+#ifndef _IWDG_H_
+#define _IWDG_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#define IWDG_BASE 0x40003000
+#define IWDG_KR (IWDG_BASE + 0x0)
+#define IWDG_PR (IWDG_BASE + 0x4)
+#define IWDG_RLR (IWDG_BASE + 0x8)
+#define IWDG_SR (IWDG_BASE + 0xC)
+
+enum {
+ IWDG_PRE_4,
+ IWDG_PRE_8,
+ IWDG_PRE_16,
+ IWDG_PRE_32,
+ IWDG_PRE_64,
+ IWDG_PRE_128,
+ IWDG_PRE_256
+};
+
+void iwdg_init(uint8 prescaler, uint16 reload);
+void iwdg_feed(void);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/libmaple/libmaple.h b/libmaple/libmaple.h
index 225d7c4..dbc77a4 100644
--- a/libmaple/libmaple.h
+++ b/libmaple/libmaple.h
@@ -52,6 +52,9 @@
/* 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
@@ -103,6 +106,7 @@
#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
@@ -140,6 +144,7 @@
#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
diff --git a/libmaple/nvic.c b/libmaple/nvic.c
index fc77054..b1da605 100644
--- a/libmaple/nvic.c
+++ b/libmaple/nvic.c
@@ -53,15 +53,20 @@ void nvic_irq_disable(uint32 n) {
}
void nvic_irq_disable_all(void) {
- short n;
- for(n=0; n<65; n++) {
- nvic_irq_disable(n);
- }
+ /* Each ICER register contains 1 bit per interrupt. Writing a 1
+ to that bit disables the corresponding interrupt. So each of
+ the following lines disables up to 32 interrupts at a time.
+ Since low, medium, and high-density devices all have less than
+ 64 interrupts, this suffices. */
+ /* TODO: fix for connectivity line: __write(NVIC_ICER2,1),
+ requires connectivity line support in libmaple.h */
+ __write(NVIC_ICER0, 0xFFFFFFFF);
+ __write(NVIC_ICER1, 0xFFFFFFFF);
}
/**
- * @brief Initialice the NVIC at address addr
- * @param addr Address to set the vector table at
+ * @brief Initialize the NVIC according to VECT_TAB_FLASH,
+ * VECT_TAB_RAM, or VECT_TAB_BASE.
*/
void nvic_init(void) {
#ifdef VECT_TAB_FLASH
diff --git a/libmaple/nvic.h b/libmaple/nvic.h
index d99e57d..6004c36 100644
--- a/libmaple/nvic.h
+++ b/libmaple/nvic.h
@@ -30,46 +30,41 @@
#ifndef _NVIC_H_
#define _NVIC_H_
+#ifdef __cplusplus
+extern "C"{
+#endif
+
#define NVIC_INT_USBHP 19
#define NVIC_INT_USBLP 20
/* NVIC Interrupt Enable registers */
#define NVIC_ISER0 0xE000E100
#define NVIC_ISER1 0xE000E104
-#define NVIC_ISER2 0xE000E108
-#define NVIC_ISER3 0xE000E10C // Non existant?
+/* NVIC_ISER2 only on connectivity line */
/* NVIC Interrupt Clear registers */
#define NVIC_ICER0 0xE000E180
#define NVIC_ICER1 0xE000E184
-#define NVIC_ICER2 0xE000E188
-#define NVIC_ICER3 0xE000E18C // Non existant?
+/* NVIC_ICER2 only on connectivity line */
/* System control registers */
#define SCB_VTOR 0xE000ED08 // Vector table offset register
-#define NVIC_VectTab_RAM ((u32)0x20000000)
-#define NVIC_VectTab_FLASH ((u32)0x08000000)
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-
enum {
NVIC_TIMER1 = 27,
NVIC_TIMER2 = 28,
NVIC_TIMER3 = 29,
NVIC_TIMER4 = 30,
- NVIC_TIMER5 = 50, // high density only (Maple Native)
- NVIC_TIMER6 = 54, // high density only (Maple Native)
- NVIC_TIMER7 = 55, // high density only (Maple Native)
- NVIC_TIMER8 = 46, // high density only (Maple Native)
+ NVIC_TIMER5 = 50, // high density only (Maple Native, Maple Audio)
+ NVIC_TIMER6 = 54, // high density only
+ NVIC_TIMER7 = 55, // high density only
+ NVIC_TIMER8 = 46, // high density only
NVIC_USART1 = 37,
NVIC_USART2 = 38,
NVIC_USART3 = 39,
- NVIC_USART4 = 52, // high density only (Maple Native)
- NVIC_USART5 = 53, // high density only (Maple Native)
+ NVIC_UART4 = 52, // high density only
+ NVIC_UART5 = 53, // high density only
NVIC_EXTI0 = 6,
NVIC_EXTI1 = 7,
@@ -78,6 +73,14 @@ enum {
NVIC_EXTI4 = 10,
NVIC_EXTI9_5 = 23,
NVIC_EXTI15_10 = 40,
+
+ NVIC_DMA_CH1 = 11,
+ NVIC_DMA_CH2 = 12,
+ NVIC_DMA_CH3 = 13,
+ NVIC_DMA_CH4 = 14,
+ NVIC_DMA_CH5 = 15,
+ NVIC_DMA_CH6 = 16,
+ NVIC_DMA_CH7 = 17
};
diff --git a/libmaple/pwr.h b/libmaple/pwr.h
new file mode 100644
index 0000000..96a8356
--- /dev/null
+++ b/libmaple/pwr.h
@@ -0,0 +1,46 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 LeafLabs, LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *****************************************************************************/
+
+/**
+ * @file pwr.h
+ * @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 */
diff --git a/libmaple/rcc.c b/libmaple/rcc.c
index 582e9a9..313eaf7 100644
--- a/libmaple/rcc.c
+++ b/libmaple/rcc.c
@@ -57,8 +57,8 @@ static const struct rcc_dev_info rcc_dev_table[] = {
[RCC_USART1] = { .clk_domain = APB2, .line_num = 14 },
[RCC_USART2] = { .clk_domain = APB1, .line_num = 17 },
[RCC_USART3] = { .clk_domain = APB1, .line_num = 18 },
- [RCC_USART4] = { .clk_domain = APB1, .line_num = 19 }, // High-density only
- [RCC_USART5] = { .clk_domain = APB1, .line_num = 20 }, // High-density only
+ [RCC_UART4] = { .clk_domain = APB1, .line_num = 19 }, // High-density only
+ [RCC_UART5] = { .clk_domain = APB1, .line_num = 20 }, // High-density only
[RCC_TIMER1] = { .clk_domain = APB2, .line_num = 11 },
[RCC_TIMER2] = { .clk_domain = APB1, .line_num = 0 },
[RCC_TIMER3] = { .clk_domain = APB1, .line_num = 1 },
@@ -71,6 +71,8 @@ static const struct rcc_dev_info rcc_dev_table[] = {
[RCC_SPI2] = { .clk_domain = APB1, .line_num = 14 },
[RCC_FSMC] = { .clk_domain = AHB, .line_num = 8 }, // High-density only
[RCC_DAC] = { .clk_domain = APB1, .line_num = 9 }, // High-density only
+ [RCC_DMA1] = { .clk_domain = AHB, .line_num = 0 },
+ [RCC_DMA2] = { .clk_domain = AHB, .line_num = 1 }, // High-density only
};
/**
diff --git a/libmaple/rcc.h b/libmaple/rcc.h
index a12f4b4..4b1f35d 100644
--- a/libmaple/rcc.h
+++ b/libmaple/rcc.h
@@ -30,6 +30,10 @@
#ifndef _RCC_H_
#define _RCC_H_
+#ifdef __cplusplus
+extern "C"{
+#endif
+
/* registers */
#define RCC_BASE 0x40021000
#define RCC_CR (RCC_BASE + 0x0)
@@ -155,8 +159,8 @@ enum {
RCC_USART1,
RCC_USART2,
RCC_USART3,
- RCC_USART4, // High-density devices only (Maple Native)
- RCC_USART5, // High-density devices only (Maple Native)
+ RCC_UART4, // High-density devices only (Maple Native)
+ RCC_UART5, // High-density devices only (Maple Native)
RCC_TIMER1,
RCC_TIMER2,
RCC_TIMER3,
@@ -169,6 +173,8 @@ enum {
RCC_SPI2,
RCC_FSMC, // High-density devices only (Maple Native)
RCC_DAC, // High-density devices only (Maple Native)
+ RCC_DMA1,
+ RCC_DMA2, // High-density devices only (Maple Native)
};
@@ -177,5 +183,8 @@ void rcc_clk_enable(uint32 dev);
void rcc_reset_dev(uint32 dev);
void rcc_set_prescaler(uint32 prescaler, uint32 divider);
+#ifdef __cplusplus
+} // extern "C"
#endif
+#endif
diff --git a/libmaple/ring_buffer.h b/libmaple/ring_buffer.h
index aa4f83f..a44088e 100644
--- a/libmaple/ring_buffer.h
+++ b/libmaple/ring_buffer.h
@@ -1,6 +1,9 @@
/**
* @file ring_buffer.h
- * @brief simple circular buffer
+ * @brief Simple circular buffer
+ *
+ * This implementation is not thread-safe. In particular, none of
+ * these functions are guaranteed re-entrant.
*/
#ifndef _RING_BUFFER_H_
@@ -11,40 +14,100 @@ extern "C"{
#endif
/* 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
- * One byte is left free to distinguish empty from full */
+ *
+ * The buffer is full when the head is one byte in front of the tail,
+ * modulo buffer length.
+ *
+ * One byte is left free to distinguish empty from full. */
typedef struct ring_buffer {
- uint32 head;
- uint32 tail;
- uint8 size;
- uint8 *buf;
+ /** Buffer items are stored into */
+ volatile uint8 *buf;
+ /** Index of the next item to remove */
+ uint16 head;
+ /** Index where the next item will get inserted */
+ uint16 tail;
+ /** Buffer capacity minus one */
+ uint16 size;
} ring_buffer;
-static inline void rb_init(ring_buffer *rb, uint8 size, uint8 *buf) {
- ASSERT(IS_POWER_OF_TWO(size));
+/**
+ * Initialise a ring buffer.
+ *
+ * @param rb Instance to initialise
+ *
+ * @param size Number of items in buf. The ring buffer will always
+ * leave one element unoccupied, so the maximum number of
+ * elements it can store will be size - 1. Thus, size
+ * must be at least 2.
+ *
+ * @param buf Buffer to store items into
+ */
+__attribute__((unused))
+static void rb_init(ring_buffer *rb, uint16 size, uint8 *buf) {
rb->head = 0;
rb->tail = 0;
- rb->size = size;
+ rb->size = size - 1;
rb->buf = buf;
}
+/** Return the number of elements stored in the ring buffer. */
+static inline uint16 rb_full_count(ring_buffer *rb) {
+ volatile ring_buffer *arb = rb;
+ int32 size = arb->tail - arb->head;
+ if (arb->tail < arb->head) {
+ size += arb->size + 1;
+ }
+ return (uint16)size;
+}
+
+/** Return true if and only if the ring buffer is full. */
+static inline int rb_is_full(ring_buffer *rb) {
+ return (rb->tail + 1 == rb->head) ||
+ (rb->tail == rb->size && rb->head == 0);
+}
+
+/** Append element onto the end of the ring buffer. */
static inline void rb_insert(ring_buffer *rb, uint8 element) {
- rb->buf[(rb->tail)++] = element;
- rb->tail &= (rb->size - 1);
+ rb->buf[rb->tail] = element;
+ rb->tail = (rb->tail == rb->size) ? 0 : rb->tail + 1;
}
+/** Remove and return the first item from the ring buffer. */
static inline uint8 rb_remove(ring_buffer *rb) {
- uint8 ch = rb->buf[rb->head++];
- rb->head &= (rb->size - 1);
+ uint8 ch = rb->buf[rb->head];
+ rb->head = (rb->head == rb->size) ? 0 : rb->head + 1;
return ch;
}
-static inline uint32 rb_full_count(ring_buffer *rb) {
- return rb->tail - rb->head;
+/**
+ * If rb is not full, appends element and returns true; otherwise,
+ * does nothing and returns false. */
+static inline int rb_safe_insert(ring_buffer *rb, uint8 element) {
+ if (rb_is_full(rb)) {
+ return 0;
+ }
+ rb_insert(rb, element);
+ return 1;
+}
+
+/**
+ * Append an item onto the end of a non-full ring buffer. If the
+ * buffer is full, removes its first item, then inserts the new
+ * element at the end.
+ *
+ * On success, returns -1. If an element was popped, returns the
+ * popped value. */
+static inline int rb_push_insert(ring_buffer *rb, uint8 element) {
+ int ret = -1;
+ if (rb_is_full(rb)) {
+ ret = rb_remove(rb);
+ }
+ rb_insert(rb, element);
+ return ret;
}
-static inline void rb_reset(ring_buffer *rb) {
+/** Discard all items from the buffer */
+static inline void rb_reset(ring_buffer *rb) {
rb->tail = rb->head;
}
diff --git a/libmaple/rules.mk b/libmaple/rules.mk
index cd50495..b87595d 100644
--- a/libmaple/rules.mk
+++ b/libmaple/rules.mk
@@ -12,24 +12,27 @@ LIBMAPLE_INCLUDES := -I$(LIBMAPLE_PATH) -I$(LIBMAPLE_PATH)/usb -I$(LIBMAPLE_PATH
CFLAGS_$(d) = -I$(d) $(LIBMAPLE_INCLUDES) -D$(VECT_BASE_ADDR)
# Local rules and targets
-cSRCS_$(d) := systick.c \
- timers.c \
- adc.c \
- syscalls.c \
+cSRCS_$(d) := adc.c \
+ bkp.c \
+ dac.c \
+ dma.c \
exti.c \
+ flash.c \
+ fsmc.c \
gpio.c \
+ iwdg.c \
nvic.c \
- usart.c \
- util.c \
rcc.c \
- flash.c \
spi.c \
- fsmc.c \
- dac.c \
+ syscalls.c \
+ systick.c \
+ timers.c \
+ usart.c \
+ util.c \
+ usb/descriptors.c \
usb/usb.c \
usb/usb_callbacks.c \
usb/usb_hardware.c \
- usb/descriptors.c \
usb/usb_lib/usb_core.c \
usb/usb_lib/usb_init.c \
usb/usb_lib/usb_int.c \
diff --git a/libmaple/systick.c b/libmaple/systick.c
index 7935cc0..b056001 100644
--- a/libmaple/systick.c
+++ b/libmaple/systick.c
@@ -37,7 +37,7 @@
#define SYSTICK_TICKINT BIT(1) // Interrupt on systick countdown
#define SYSTICK_ENABLE BIT(0) // Turn on the counter
-volatile uint32 systick_timer_millis = 0;
+volatile uint32 systick_timer_millis;
void systick_init(uint32 reload_val) {
/* Set the reload counter to tick every 1ms */
@@ -57,14 +57,13 @@ void systick_disable() {
}
void systick_resume() {
- /* re-enable init registers without changing relead_val */
+ /* re-enable init registers without changing reload val */
__write(SYSTICK_CSR, SYSTICK_SRC_HCLK |
SYSTICK_ENABLE |
SYSTICK_TICKINT);
}
+/** SysTick interrupt handler. Bumps up the tick counter. */
void SysTickHandler(void) {
systick_timer_millis++;
}
-
-
diff --git a/libmaple/systick.h b/libmaple/systick.h
index 7ec8497..33a3cf8 100644
--- a/libmaple/systick.h
+++ b/libmaple/systick.h
@@ -33,14 +33,17 @@
#include "libmaple.h"
+#ifdef __cplusplus
+extern "C"{
+#endif
+
#define SYSTICK_CSR 0xE000E010 // Control and status register
#define SYSTICK_CNT 0xE000E018 // Current value register
#define SYSTICK_CSR_COUNTFLAG BIT(16)
-#ifdef __cplusplus
-extern "C"{
-#endif
+/** System elapsed time in milliseconds */
+extern volatile uint32 systick_timer_millis;
void systick_init(uint32 reload_val);
void systick_disable();
diff --git a/libmaple/usart.c b/libmaple/usart.c
index e63e8f6..44a5c92 100644
--- a/libmaple/usart.c
+++ b/libmaple/usart.c
@@ -61,45 +61,59 @@ struct usart_dev usart_dev_table[] = {
.rcc_dev_num = RCC_USART3,
.nvic_dev_num = NVIC_USART3
},
- /*
- #if NR_USART >= 5
- [UART4] = {
- .base = (usart_port*)UART4_BASE,
- .rcc_dev_num = RCC_UART4,
- .nvic_dev_num = NVIC_UART4
- },
- [UART5] = {
- .base = (usart_port*)UART5_BASE,
- .rcc_dev_num = RCC_UART5,
- .nvic_dev_num = NVIC_UART5
- },
- #endif
- */
+#if NR_USART >= 5
+ /* TODO test */
+ [UART4] = {
+ .base = (usart_port*)UART4_BASE,
+ .rcc_dev_num = RCC_UART4,
+ .nvic_dev_num = NVIC_UART4
+ },
+ [UART5] = {
+ .base = (usart_port*)UART5_BASE,
+ .rcc_dev_num = RCC_UART5,
+ .nvic_dev_num = NVIC_UART5
+ },
+#endif
};
-/* usart interrupt handlers */
+/*
+ * Usart interrupt handlers.
+ */
+
+static inline void usart_irq(int usart_num) {
+#ifdef USART_SAFE_INSERT
+ /* Ignore old bytes if the user defines USART_SAFE_INSERT. */
+ rb_safe_insert(&(usart_dev_table[usart_num].rb),
+ (uint8)((usart_dev_table[usart_num].base)->DR));
+#else
+ /* By default, push bytes around in the ring buffer. */
+ rb_push_insert(&(usart_dev_table[usart_num].rb),
+ (uint8)((usart_dev_table[usart_num].base)->DR));
+#endif
+}
+
+/* TODO: Check the disassembly for the following functions to make
+ sure GCC inlined properly. */
+
void USART1_IRQHandler(void) {
- rb_insert(&(usart_dev_table[USART1].rb),
- (uint8)(((usart_port*)(USART1_BASE))->DR));
+ usart_irq(USART1);
}
void USART2_IRQHandler(void) {
- rb_insert(&(usart_dev_table[USART2].rb),
- (uint8)(((usart_port*)(USART2_BASE))->DR));
+ usart_irq(USART2);
}
void USART3_IRQHandler(void) {
- rb_insert(&usart_dev_table[USART3].rb,
- (uint8)(((usart_port*)(USART3_BASE))->DR));
+ usart_irq(USART3);
}
+
#if NR_USART >= 5
void UART4_IRQHandler(void) {
- rb_insert(&usart_dev_table[UART4].rb,
- (uint8)(((usart_port*)(UART4_BASE))->DR));
+ usart_irq(UART4);
}
+
void UART5_IRQHandler(void) {
- rb_insert(&usart_dev_table[UART5].rb,
- (uint8)(((usart_port*)(UART5_BASE))->DR));
+ usart_irq(UART5);
}
#endif
diff --git a/libmaple/usart.h b/libmaple/usart.h
index 49978e9..0ca3f55 100644
--- a/libmaple/usart.h
+++ b/libmaple/usart.h
@@ -77,11 +77,11 @@ extern struct usart_dev usart_dev_table[];
static inline void usart_putc(uint8 usart_num, uint8 byte) {
usart_port *port = usart_dev_table[usart_num].base;
- port->DR = byte;
-
- /* Wait for transmission to complete */
+ /* Wait for the buffer to empty */
while ((port->SR & USART_TXE) == 0)
;
+
+ port->DR = byte;
}
/**
diff --git a/libmaple/util.h b/libmaple/util.h
index 1aa58ec..64782d9 100644
--- a/libmaple/util.h
+++ b/libmaple/util.h
@@ -52,14 +52,14 @@
#define REG_SET_MASK(reg, mask) (*(volatile uint32*)(reg) |= (uint32)(mask))
#define REG_CLEAR_MASK(reg, mask) (*(volatile uint32*)(reg) &= (uint32)~(mask))
-#define REG_GET(reg) *(volatile uint32*)(reg)
+#define REG_GET(reg) (*(volatile uint32*)(reg))
-#define __set_bits(addr, mask) *(volatile uint32*)(addr) |= (uint32)(mask)
+#define __set_bits(addr, mask) (*(volatile uint32*)(addr) |= (uint32)(mask))
#define __clear_bits(addr, mask) (*(volatile uint32*)(addr) &= (uint32)~(mask))
#define __get_bits(addr, mask) (*(volatile uint32*)(addr) & (uint32)(mask))
-#define __read(reg) *(volatile uint32*)(reg)
-#define __write(reg, value) *(volatile uint32*)(reg) = (value)
+#define __read(reg) (*(volatile uint32*)(reg))
+#define __write(reg, value) (*(volatile uint32*)(reg) = (value))
#define IS_POWER_OF_TWO(v) (v && !(v & (v - 1)))
diff --git a/support/stm32loader.py b/support/stm32loader.py
index f717c9a..874d278 100755
--- a/support/stm32loader.py
+++ b/support/stm32loader.py
@@ -25,6 +25,11 @@
import sys, getopt
import serial
import time
+import glob
+import time
+import tempfile
+import os
+import subprocess
try:
from progressbar import *
@@ -53,28 +58,28 @@ class CommandInterface:
stopbits=1,
xonxoff=0, # enable software flow control
rtscts=0, # disable RTS/CTS flow control
- timeout=5 # set a timeout value, None for waiting forever
+ timeout=0.5 # set a timeout value, None for waiting forever
)
def _wait_for_ask(self, info = ""):
+ got = self.sp.read(1)
+
+ if not got:
+ raise CmdException("No response to %s" % info)
+
# wait for ask
- try:
- ask = ord(self.sp.read())
- except:
- raise CmdException("Can't read port or timeout")
- else:
- if ask == 0x79:
- # ACK
- return 1
- else:
- if ask == 0x1F:
- # NACK
- raise CmdException("NACK "+info)
- else:
- # Unknow responce
- raise CmdException("Unknow response. "+info+": "+hex(ask))
+ ask = ord(got)
+
+ if ask == 0x79:
+ # ACK
+ return 1
+ elif ask == 0x1F:
+ # NACK
+ raise CmdException("Chip replied with a NACK during %s" % info)
+ # Unknown response
+ raise CmdException("Unrecognised response 0x%x to %s" % (ask, info))
def reset(self):
self.sp.setDTR(0)
@@ -87,8 +92,21 @@ class CommandInterface:
self.sp.setRTS(0)
self.reset()
- self.sp.write("\x7F") # Syncro
- return self._wait_for_ask("Syncro")
+ # Be a bit more persistent when trying to initialise the chip
+ stop = time.time() + 5.0
+
+ while time.time() <= stop:
+ self.sp.write('\x7f')
+
+ got = self.sp.read()
+
+ # The chip will ACK a sync the very first time and
+ # NACK it every time afterwards
+ if got and got in '\x79\x1f':
+ # Synced up
+ return
+
+ raise CmdException('No response while trying to sync')
def releaseChip(self):
self.sp.setRTS(1)
@@ -257,7 +275,7 @@ class CommandInterface:
if usepbar:
widgets = ['Reading: ', Percentage(),', ', ETA(), ' ', Bar()]
pbar = ProgressBar(widgets=widgets,maxval=lng, term_width=79).start()
-
+
while lng > 256:
if usepbar:
pbar.update(pbar.maxval-lng)
@@ -279,7 +297,7 @@ class CommandInterface:
if usepbar:
widgets = ['Writing: ', Percentage(),' ', ETA(), ' ', Bar()]
pbar = ProgressBar(widgets=widgets, maxval=lng, term_width=79).start()
-
+
offs = 0
while lng > 256:
if usepbar:
@@ -300,7 +318,7 @@ class CommandInterface:
- def __init__(self) :
+ def __init__(self) :
pass
@@ -314,7 +332,7 @@ def usage():
-v Verify
-r Read
-l length Length of read
- -p port Serial port (default: /dev/tty.usbserial-ftCYPMYJ)
+ -p port Serial port (default: first USB-like port in /dev)
-b baud Baud speed (default: 115200)
-a addr Target address
@@ -322,9 +340,37 @@ def usage():
""" % sys.argv[0]
+def read(filename):
+ """Read the file to be programmed and turn it into a binary"""
+ with open(filename, 'rb') as f:
+ bytes = f.read()
+
+ if bytes.startswith('\x7FELF'):
+ # Actually an ELF file. Convert to binary
+ handle, path = tempfile.mkstemp(suffix='.bin', prefix='stm32loader')
+
+ try:
+ os.close(handle)
+
+ # Try a couple of options for objcopy
+ for name in ['arm-none-eabi-objcopy', 'arm-linux-gnueabi-objcopy']:
+ try:
+ code = subprocess.call([name, '-Obinary', filename, path])
+
+ if code == 0:
+ return read(path)
+ except OSError:
+ pass
+ else:
+ raise Exception('Error %d while converting to a binary file' % code)
+ finally:
+ # Remove the temporary file
+ os.unlink(path)
+ else:
+ return [ord(x) for x in bytes]
if __name__ == "__main__":
-
+
# Import Psyco if available
try:
import psyco
@@ -334,7 +380,7 @@ if __name__ == "__main__":
pass
conf = {
- 'port': '/dev/tty.usbserial-FTD3TMCH',
+ 'port': 'auto',
'baud': 115200,
'address': 0x08000000,
'erase': 0,
@@ -386,27 +432,52 @@ if __name__ == "__main__":
else:
assert False, "unhandled option"
+ # Try and find the port automatically
+ if conf['port'] == 'auto':
+ ports = []
+
+ # Get a list of all USB-like names in /dev
+ for name in ['tty.usbserial', 'ttyUSB']:
+ ports.extend(glob.glob('/dev/%s*' % name))
+
+ ports = sorted(ports)
+
+ if ports:
+ # Found something - take it
+ conf['port'] = ports[0]
+
cmd = CommandInterface()
cmd.open(conf['port'], conf['baud'])
- mdebug(10, "Open port %(port)s, baud %(baud)d" % {'port':conf['port'], 'baud':conf['baud']})
+ mdebug(10, "Open port %(port)s, baud %(baud)d" % {'port':conf['port'],
+ 'baud':conf['baud']})
try:
+ if (conf['write'] or conf['verify']):
+ data = read(args[0])
+
try:
cmd.initChip()
- except:
+ except CmdException:
print "Can't init. Ensure that BOOT0 is enabled and reset device"
bootversion = cmd.cmdGet()
- mdebug(0, "Bootloader version %X" % bootversion)
- mdebug(0, "Chip id `%s'" % str(map(lambda c: hex(ord(c)), cmd.cmdGetID())))
+
+ mdebug(0, "Bootloader version 0x%X" % bootversion)
+
+ if bootversion < 20 or bootversion >= 100:
+ raise Exception('Unreasonable bootloader version %d' % bootversion)
+
+ id = [ord(x) for x in cmd.cmdGetID()]
+ mdebug(0, "Chip id '%s'" % ' '.join('0x%x' % x for x in id))
+
+ if len(id) < 2 or id[0] != 0x04:
+ raise Exception('Unrecognised chip ID')
+
# cmd.cmdGetVersion()
# cmd.cmdGetID()
# cmd.cmdReadoutUnprotect()
# cmd.cmdWriteUnprotect()
# cmd.cmdWriteProtect([0, 1])
- if (conf['write'] or conf['verify']):
- data = map(lambda c: ord(c), file(args[0]).read())
-
if conf['erase']:
cmd.cmdEraseMemory()
diff --git a/wirish/time.h b/wirish/time.h
index c925f74..8d3d074 100644
--- a/wirish/time.h
+++ b/wirish/time.h
@@ -30,17 +30,16 @@
#ifndef _TIME_H
#define _TIME_H
-#ifdef __cplusplus
-extern "C"{
-#endif
-
+#include "libmaple.h"
#include "nvic.h"
#include "systick.h"
#include "boards.h"
-#define US_PER_MS 1000
+#ifdef __cplusplus
+extern "C"{
+#endif
-extern volatile uint32 systick_timer_millis;
+#define US_PER_MS 1000
/**
* Returns time (in milliseconds) since the beginning of program
diff --git a/wirish/wirish.c b/wirish/wirish.c
index db38050..5935f95 100644
--- a/wirish/wirish.c
+++ b/wirish/wirish.c
@@ -54,7 +54,7 @@ void init(void) {
#if NR_DAC_PINS > 0
dac_init();
#endif
-
+
/* initialize clocks */
rcc_clk_init(RCC_CLKSRC_PLL, RCC_PLLSRC_HSE, RCC_PLLMUL_9);
rcc_set_prescaler(RCC_PRESCALER_AHB, RCC_AHB_SYSCLK_DIV_1);