diff options
Diffstat (limited to 'libmaple')
| -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 | 
22 files changed, 815 insertions, 102 deletions
| 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))) | 
