diff options
-rw-r--r-- | contrib/automake/Makefile.am | 115 | ||||
-rw-r--r-- | contrib/automake/configure.ac | 8 | ||||
-rw-r--r-- | libmaple/adc.h | 7 | ||||
-rw-r--r-- | libmaple/bkp.c | 86 | ||||
-rw-r--r-- | libmaple/bkp.h | 86 | ||||
-rw-r--r-- | libmaple/dma.c | 148 | ||||
-rw-r--r-- | libmaple/dma.h | 122 | ||||
-rw-r--r-- | libmaple/exti.c | 6 | ||||
-rw-r--r-- | libmaple/exti.h | 5 | ||||
-rw-r--r-- | libmaple/iwdg.c | 56 | ||||
-rw-r--r-- | libmaple/iwdg.h | 61 | ||||
-rw-r--r-- | libmaple/libmaple.h | 5 | ||||
-rw-r--r-- | libmaple/nvic.c | 17 | ||||
-rw-r--r-- | libmaple/nvic.h | 37 | ||||
-rw-r--r-- | libmaple/pwr.h | 46 | ||||
-rw-r--r-- | libmaple/rcc.c | 6 | ||||
-rw-r--r-- | libmaple/rcc.h | 13 | ||||
-rw-r--r-- | libmaple/ring_buffer.h | 99 | ||||
-rw-r--r-- | libmaple/rules.mk | 23 | ||||
-rw-r--r-- | libmaple/systick.c | 7 | ||||
-rw-r--r-- | libmaple/systick.h | 9 | ||||
-rw-r--r-- | libmaple/usart.c | 64 | ||||
-rw-r--r-- | libmaple/usart.h | 6 | ||||
-rw-r--r-- | libmaple/util.h | 8 | ||||
-rwxr-xr-x | support/stm32loader.py | 133 | ||||
-rw-r--r-- | wirish/time.h | 11 | ||||
-rw-r--r-- | wirish/wirish.c | 2 |
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); |