From f4cdcfa51096f73a49642c400681d91847137dfb Mon Sep 17 00:00:00 2001 From: Perry Hung Date: Fri, 18 Feb 2011 05:22:39 -0500 Subject: checkpoint --- .gdbinit | 9 + .gitignore | 5 +- Makefile | 2 +- libmaple/exc.S | 1 + libmaple/i2c.c | 502 +++++++++++++++++++++++++++++++++++++++++++++++++++ libmaple/i2c.h | 172 ++++++++++++++++++ libmaple/libmaple.h | 5 + libmaple/nvic.c | 33 ++++ libmaple/nvic.h | 41 ++++- libmaple/rcc.c | 2 + libmaple/rcc.h | 2 + libmaple/rules.mk | 1 + libmaple/scb.h | 58 ++++++ libmaple/stm32.h | 12 ++ main.cpp | 84 +++++++++ support/ld/names.inc | 8 +- test.gdb | 112 ++++++++++++ wirish/wirish.c | 19 +- 18 files changed, 1052 insertions(+), 16 deletions(-) create mode 100644 .gdbinit create mode 100644 libmaple/i2c.c create mode 100644 libmaple/i2c.h create mode 100644 libmaple/scb.h create mode 100644 libmaple/stm32.h create mode 100644 main.cpp create mode 100644 test.gdb diff --git a/.gdbinit b/.gdbinit new file mode 100644 index 0000000..9e88d09 --- /dev/null +++ b/.gdbinit @@ -0,0 +1,9 @@ +target remote localhost:3333 +symbol-file build/maple.elf +source test.gdb +delete breakpoints +##break main.cpp:setup() +##monitor reset halt +#display/i $pc +# display/x *0xe000ed2c +# display/x *0xE000ED28 diff --git a/.gitignore b/.gitignore index 7e29a09..be8bc38 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,13 @@ build/ docs/build/ -main.cpp libmaple.layout tags TAGS *~ *.swp docs/doxygen/ +<<<<<<< Updated upstream arm +======= +notes/ +>>>>>>> Stashed changes diff --git a/Makefile b/Makefile index 9bf0c9d..2782c0a 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,7 @@ LIBMAPLE_PATH := $(SRCROOT)/libmaple SUPPORT_PATH := $(SRCROOT)/support # Useful variables -GLOBAL_CFLAGS := -Os -g -mcpu=cortex-m3 -mthumb -march=armv7-m -nostdlib \ +GLOBAL_CFLAGS := -Os -g3 -gdwarf-2 -mcpu=cortex-m3 -mthumb -march=armv7-m -nostdlib \ -ffunction-sections -fdata-sections -Wl,--gc-sections \ -DBOARD_$(BOARD) -DMCU_$(MCU) GLOBAL_CXXFLAGS := -fno-rtti -fno-exceptions -Wall -DBOARD_$(BOARD) -DMCU_$(MCU) diff --git a/libmaple/exc.S b/libmaple/exc.S index a9f6561..2713ee3 100644 --- a/libmaple/exc.S +++ b/libmaple/exc.S @@ -44,6 +44,7 @@ .globl HardFaultException .thumb_func HardFaultException: + b HardFaultException ldr r0, CPSR_MASK @ Set default CPSR push {r0} ldr r0, TARGET_PC @ Set target pc diff --git a/libmaple/i2c.c b/libmaple/i2c.c new file mode 100644 index 0000000..2064723 --- /dev/null +++ b/libmaple/i2c.c @@ -0,0 +1,502 @@ +/* ***************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * 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. + * ****************************************************************************/ + +/** + * @brief + * TODO: Rejigger hard fault handler and error throbs to turn off all + * interrupts and jump to error throb to reenable usb bootloader + */ + +#include "libmaple.h" +#include "rcc.h" +#include "nvic.h" +#include "gpio.h" +#include "nvic.h" +#include "i2c.h" +#include "string.h" + +/* 2/17 Started 10pm-4am + * 2/19 Started 7pm-2am + * 2/20 Started 7pm-7pm + * 2/23 Started 8pm */ + +static inline int32 wait_for_state_change(i2c_dev *dev, i2c_state state); + +i2c_dev i2c_dev1 = { + .regs = (i2c_reg_map*)I2C1_BASE, + .gpio_port = GPIOB_BASE, + .sda_pin = 7, + .scl_pin = 6, + .clk_line = RCC_I2C1, + .ev_nvic_line = NVIC_I2C1_EV, + .er_nvic_line = NVIC_I2C1_ER, + .state = I2C_STATE_IDLE +}; + +/** + * @brief IRQ handler for i2c master. Handles transmission/reception. + * @param dev i2c device + */ + +void delay_us(uint32 us) { + /* So (2^32)/12 micros max, or less than 6 minutes */ + us *= 12; + + /* fudge for function call overhead */ + us--; + asm volatile(" mov r0, %[us] \n\t" + "1: subs r0, #1 \n\t" + " bhi 1b \n\t" + : + : [us] "r" (us) + : "r0"); +} +static inline void debug_toggle(uint32 delay) { + gpio_write_bit(GPIOA_BASE, 5, 1); + delay_us(delay); + gpio_write_bit(GPIOA_BASE, 5, 0); +} + +struct crumb { + uint32 event; + uint32 sr1; + uint32 sr2; +}; + +static struct crumb crumbs[100]; +static uint32 cur_crumb = 0; + +static inline void leave_big_crumb(uint32 event, uint32 sr1, uint32 sr2) { + if (cur_crumb < 100) { + struct crumb *crumb = &crumbs[cur_crumb++]; + crumb->event = event; + crumb->sr1 = sr1; + crumb->sr2 = sr2; + } +} + +enum { + IRQ_ENTRY = 1, + TXE_ONLY = 2, + TXE_BTF = 3, + STOP_SENT = 4, + TEST = 5, + RX_ADDR_START = 6, + RX_ADDR_STOP = 7, + RXNE_ONLY = 8, + RXNE_SENDING = 9, + RXNE_START_SENT = 10, + RXNE_STOP_SENT = 11, + RXNE_DONE = 12, +}; + +static void i2c_irq_handler(i2c_dev *dev) { + i2c_msg *msg = dev->msg; + + uint8 read = msg->flags & I2C_MSG_READ; + + uint32 sr1 = dev->regs->SR1; + uint32 sr2 = dev->regs->SR2; + leave_big_crumb(IRQ_ENTRY, sr1, sr2); + + /* + * EV5: Start condition sent + */ + if (sr1 & I2C_SR1_SB) { + msg->xferred = 0; + i2c_enable_irq(dev->regs, I2C_IRQ_BUFFER); + + /* + * Master receiver + */ + if (read) { + i2c_enable_ack(dev->regs); + } + i2c_send_slave_addr(dev->regs, msg->addr, read); + sr1 = sr2 = 0; + } + + /* + * EV6: Slave address sent + */ + if (sr1 & I2C_SR1_ADDR) { + /* + * Special case event EV6_1 for master receiver. + * Generate NACK and restart/stop condition after ADDR + * is cleared. + */ + if (read) { + if (msg->length == 1) { + i2c_disable_ack(dev->regs); + dev->msgs_left--; + if (dev->msgs_left) { + i2c_start_condition(dev->regs); + leave_big_crumb(RX_ADDR_START, 0, 0); + } else { + i2c_stop_condition(dev->regs); + leave_big_crumb(RX_ADDR_STOP, 0, 0); + } + } + } else { + /* + * Master transmitter: write first byte to fill shift register. + * We should get another TXE interrupt immediately to fill DR again. + */ + i2c_write(dev->regs, msg->data[msg->xferred++]); + } + sr1 = sr2 = 0; + } + + /* + * EV8: Master transmitter + * Transmit buffer empty, but we haven't finished transmitting the last + * byte written. + */ + if ((sr1 & I2C_SR1_TXE) && !(sr1 & I2C_SR1_BTF)) { + leave_big_crumb(TXE_ONLY, 0, 0); + if (dev->msgs_left) { + i2c_write(dev->regs, msg->data[msg->xferred++]); + if (msg->xferred == msg->length) { + /* + * End of this message. Turn off TXE/RXNE and wait for + * BTF to send repeated start or stop condition. + */ + i2c_disable_irq(dev->regs, I2C_IRQ_BUFFER); + dev->msgs_left--; + } + } else { + /* + * This should be impossible... + */ + throb(); + } + sr1 = sr2 = 0; + } + + /* + * EV8_2: Master transmitter + * Last byte sent, program repeated start/stop + */ + if ((sr1 & I2C_SR1_TXE) && (sr1 & I2C_SR1_BTF)) { + leave_big_crumb(TXE_BTF, 0, 0); + if (dev->msgs_left) { + leave_big_crumb(TEST, 0, 0); + /* + * Repeated start insanity: We can't disable ITEVTEN or else SB + * won't interrupt, but if we don't disable ITEVTEN, BTF will + * continually interrupt us. What the fuck ST? + */ + i2c_start_condition(dev->regs); + while (!(dev->regs->SR1 & I2C_SR1_SB)) + ; + dev->msg++; + } else { + i2c_stop_condition(dev->regs); + /* + * Turn off event interrupts to keep BTF from firing until the end + * of the stop condition. Why on earth they didn't have a start/stop + * condition request clear BTF is beyond me. + */ + i2c_disable_irq(dev->regs, I2C_IRQ_EVENT); + leave_big_crumb(STOP_SENT, 0, 0); + dev->state = I2C_STATE_XFER_DONE; + } + sr1 = sr2 = 0; + } + + /* + * EV7: Master Receiver + */ + if (sr1 & I2C_SR1_RXNE) { + leave_big_crumb(RXNE_ONLY, 0, 0); + msg->data[msg->xferred++] = dev->regs->DR; + + /* + * EV7_1: Second to last byte in the reception? Set NACK and generate + * stop/restart condition in time for the last byte. We'll get one more + * RXNE interrupt before shutting things down. + */ + if (msg->xferred == (msg->length - 1)) { + i2c_disable_ack(dev->regs); + if (dev->msgs_left > 2) { + i2c_start_condition(dev->regs); + leave_big_crumb(RXNE_START_SENT, 0, 0); + } else { + i2c_stop_condition(dev->regs); + leave_big_crumb(RXNE_STOP_SENT, 0, 0); + } + } else if (msg->xferred == msg->length) { + dev->msgs_left--; + if (dev->msgs_left == 0) { + /* + * We're done. + */ + leave_big_crumb(RXNE_DONE, 0, 0); + dev->state = I2C_STATE_XFER_DONE; + } else { + dev->msg++; + } + } + } +} + +void I2C1_EV_IRQHandler(void) { + i2c_dev *dev = I2C1; + i2c_irq_handler(dev); +} + +static void i2c_bus_reset(i2c_dev *dev) { + /* Release both lines */ + gpio_write_bit(dev->gpio_port, dev->scl_pin, 1); + gpio_write_bit(dev->gpio_port, dev->sda_pin, 1); + gpio_set_mode(dev->gpio_port, dev->scl_pin, GPIO_MODE_OUTPUT_OD); + gpio_set_mode(dev->gpio_port, dev->sda_pin, GPIO_MODE_OUTPUT_OD); + + /* + * Make sure the bus is free by clocking it until any slaves release the + * bus. + */ + while (!gpio_read_bit(dev->gpio_port, dev->sda_pin)) { + /* Wait for any clock stretching to finish */ + while (!gpio_read_bit(dev->gpio_port, dev->scl_pin)) + ; + delay_us(10); + + /* Pull low */ + gpio_write_bit(dev->gpio_port, dev->scl_pin, 0); + delay_us(10); + + /* Release high again */ + gpio_write_bit(dev->gpio_port, dev->scl_pin, 1); + delay_us(10); + } + + /* Generate start then stop condition */ + gpio_write_bit(dev->gpio_port, dev->sda_pin, 0); + delay_us(10); + gpio_write_bit(dev->gpio_port, dev->scl_pin, 0); + delay_us(10); + gpio_write_bit(dev->gpio_port, dev->scl_pin, 1); + delay_us(10); + gpio_write_bit(dev->gpio_port, dev->sda_pin, 1); +} + +/** + * @brief Initialize an i2c device as bus master + * @param device to enable + * @param flags bitwise or of the following I2C options: + * I2C_FAST_MODE: 400 khz operation + * I2C_10BIT_ADDRESSING: Enable 10-bit addressing + */ +void i2c_master_enable(i2c_dev *dev, uint32 flags) { +#define STANDARD_CCR (PCLK1/(100000*2)) +#define STANDARD_TRISE 37 + /* Reset the bus. Clock out any hung slaves. */ + i2c_bus_reset(dev); + + /* Turn on clock and set GPIO modes */ + rcc_reset_dev(dev->clk_line); + rcc_clk_enable(dev->clk_line); + gpio_set_mode(dev->gpio_port, dev->sda_pin, GPIO_MODE_AF_OUTPUT_OD); + gpio_set_mode(dev->gpio_port, dev->scl_pin, GPIO_MODE_AF_OUTPUT_OD); + + /* I2C1 and I2C2 are fed from APB1, clocked at 36MHz */ + i2c_set_input_clk(dev->regs, 36); + + /* 100 khz only for now */ + i2c_set_clk_control(dev->regs, STANDARD_CCR); + + /* + * Set scl rise time, standard mode for now. + * Max rise time in standard mode: 1000 ns + * Max rise time in fast mode: 300ns + */ + i2c_set_trise(dev->regs, STANDARD_TRISE); + + /* Enable event and buffer interrupts */ + nvic_irq_enable(dev->ev_nvic_line); + i2c_enable_irq(dev->regs, I2C_IRQ_EVENT | I2C_IRQ_BUFFER); + + /* + * Important STM32 Errata: + * + * See STM32F10xx8 and STM32F10xxB Errata sheet (Doc ID 14574 Rev 8), + * Section 2.11.1, 2.11.2. + * + * 2.11.1: + * When the EV7, EV7_1, EV6_1, EV6_3, EV2, EV8, and EV3 events are not + * managed before the current byte is being transferred, problems may be + * encountered such as receiving an extra byte, reading the same data twice + * or missing data. + * + * 2.11.2: + * In Master Receiver mode, when closing the communication using + * method 2, the content of the last read data can be corrupted. + * + * If the user software is not able to read the data N-1 before the STOP + * condition is generated on the bus, the content of the shift register + * (data N) will be corrupted. (data N is shifted 1-bit to the left). + * + * ---------------------------------------------------------------------- + * + * In order to ensure that events are not missed, the i2c interrupt must + * not be preempted. We set the i2c interrupt priority to be the highest + * interrupt in the system (priority level 0). All other interrupts have + * been initialized to priority level 16. See nvic_init(). + */ + nvic_irq_set_priority(dev->ev_nvic_line, 0); + + /* Make it go! */ + i2c_peripheral_enable(dev->regs); +} + + +int32 i2c_master_xfer(i2c_dev *dev, i2c_msg *msgs, uint16 num) { + int32 rc; + static int times = 0; + + dev->msg = msgs; + dev->msgs_left = num; + + memset(crumbs, 0, sizeof crumbs); + + dev->regs->CR2 |= I2C_CR2_ITEVTEN; + + /* Is this necessary? */ + while (dev->regs->SR2 & I2C_SR2_BUSY) + ; + + dev->state = I2C_STATE_BUSY; + + i2c_start_condition(dev->regs); + rc = wait_for_state_change(dev, I2C_STATE_XFER_DONE); + if (rc < 0) { + goto out; + } + + dev->state = I2C_STATE_IDLE; + rc = num; +out: + return rc; +} + +static inline int32 wait_for_state_change(i2c_dev *dev, i2c_state state) { + int32 rc; + i2c_state tmp; + + while (1) { + tmp = dev->state; + if ((tmp == state) || (tmp == I2C_STATE_ERROR)) { + return (tmp == I2C_STATE_ERROR) ? -1 : 0; + } + } +} + + +/* + * Low level register twiddling functions + */ + +/** + * @brief turn on an i2c peripheral + * @param map i2c peripheral register base + */ +void i2c_peripheral_enable(i2c_reg_map *regs) { + regs->CR1 |= I2C_CR1_PE; +} + +/** + * @brief turn off an i2c peripheral + * @param map i2c peripheral register base + */ +void i2c_peripheral_disable(i2c_reg_map *regs) { + regs->CR1 &= ~I2C_CR1_PE; +} + +/** + * @brief Set input clock frequency, in mhz + * @param device to configure + * @param freq frequency in megahertz (2-36) + */ +void i2c_set_input_clk(i2c_reg_map *regs, uint32 freq) { + uint32 cr2 = regs->CR2; + cr2 &= ~I2C_CR2_FREQ; + cr2 |= freq; + regs->CR2 = freq; +} + +void i2c_set_clk_control(i2c_reg_map *regs, uint32 val) { + uint32 ccr = regs->CCR; + ccr &= ~I2C_CCR_CCR; + ccr |= val; + regs->CCR = ccr; +} + +void i2c_set_fast_mode(i2c_reg_map *regs) { + regs->CCR |= I2C_CCR_FS; +} + +void i2c_set_standard_mode(i2c_reg_map *regs) { + regs->CCR &= ~I2C_CCR_FS; +} + +/** + * @brief Set SCL rise time + * @param + */ + +void i2c_set_trise(i2c_reg_map *regs, uint32 trise) { + regs->TRISE = trise; +} + +void i2c_start_condition(i2c_reg_map *regs) { + regs->CR1 |= I2C_CR1_START; +} + +void i2c_stop_condition(i2c_reg_map *regs) { + regs->CR1 |= I2C_CR1_STOP; +} + +void i2c_send_slave_addr(i2c_reg_map *regs, uint32 addr, uint32 rw) { + regs->DR = (addr << 1) | rw; +} + +void i2c_enable_irq(i2c_reg_map *regs, uint32 irqs) { + regs->CR2 |= irqs; +} + +void i2c_disable_irq(i2c_reg_map *regs, uint32 irqs) { + regs->CR2 &= ~irqs; +} + +void i2c_enable_ack(i2c_reg_map *regs) { + regs->CR1 |= I2C_CR1_ACK; +} + +void i2c_disable_ack(i2c_reg_map *regs) { + regs->CR1 &= ~I2C_CR1_ACK; +} + + + diff --git a/libmaple/i2c.h b/libmaple/i2c.h new file mode 100644 index 0000000..2e6d00d --- /dev/null +++ b/libmaple/i2c.h @@ -0,0 +1,172 @@ +/* ***************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * 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. + * ****************************************************************************/ + +/** + * @brief libmaple i2c header + */ + +#ifndef _I2C_H_ +#define _I2C_H_ + +typedef struct i2c_reg_map { + __io uint32 CR1; + __io uint32 CR2; + __io uint32 OAR1; + __io uint32 OAR2; + __io uint32 DR; + __io uint32 SR1; + __io uint32 SR2; + __io uint32 CCR; + __io uint32 TRISE; +} i2c_reg_map; + +typedef enum i2c_state { + I2C_STATE_IDLE, + I2C_STATE_XFER_DONE, + I2C_STATE_BUSY, + I2C_STATE_ERROR = -1 +} i2c_state; + +typedef struct i2c_msg { + uint16 addr; +#define I2C_MSG_READ 0x1 +#define I2C_MSG_10BIT_ADDR 0x2 + uint16 flags; + uint16 length; + uint16 xferred; + uint8 *data; +} i2c_msg; + +typedef struct i2c_dev { + i2c_reg_map *regs; + GPIO_Port *gpio_port; + uint8 sda_pin; + uint8 scl_pin; + uint8 clk_line; + uint8 ev_nvic_line; + uint8 er_nvic_line; + volatile uint8 state; + uint16 msgs_left; + i2c_msg *msg; +} i2c_dev; + + +extern i2c_dev i2c_dev1; +extern i2c_dev i2c_dev2; + +#define I2C1 (i2c_dev*)&i2c_dev1 +#define I2C2 (i2c_dev*)&i2c_dev2 + +#define I2C1_BASE 0x40005400 +#define I2C2_BASE 0x40005800 + +/* i2c enable options */ +#define I2C_FAST_MODE 0x1 // 400 khz +#define I2C_DUTY_16_9 0x2 // 16/9 duty ratio + +/* Control register 1 bits */ +#define I2C_CR1_SWRST BIT(15) // Software reset +#define I2C_CR1_ALERT BIT(13) // SMBus alert +#define I2C_CR1_PEC BIT(12) // Packet error checking +#define I2C_CR1_POS BIT(11) // Acknowledge/PEC position +#define I2C_CR1_ACK BIT(10) // Acknowledge enable +#define I2C_CR1_START BIT(8) // Start generation +#define I2C_CR1_STOP BIT(9) // Stop generation +#define I2C_CR1_PE BIT(0) // Peripheral Enable + +/* Control register 2 bits */ +#define I2C_CR2_LAST BIT(12) // DMA last transfer +#define I2C_CR2_DMAEN BIT(11) // DMA requests enable +#define I2C_CR2_ITBUFEN BIT(10) // Buffer interrupt enable +#define I2C_CR2_ITEVTEN BIT(9) // Event interupt enable +#define I2C_CR2_ITERREN BIT(8) // Error interupt enable +#define I2C_CR2_FREQ 0xFFF // Peripheral input frequency + +/* Clock control register bits */ +#define I2C_CCR_FS BIT(15) // Master mode selection +#define I2C_CCR_CCR 0xFFF // Clock control bits + +/* Status register 1 bits */ +#define I2C_SR1_SB BIT(0) // Start bit +#define I2C_SR1_ADDR BIT(1) // Address sent/matched +#define I2C_SR1_BTF BIT(2) // Byte transfer finished +#define I2C_SR1_ADD10 BIT(3) // 10-bit header sent +#define I2C_SR1_STOPF BIT(4) // Stop detection +#define I2C_SR1_RXNE BIT(6) // Data register not empty +#define I2C_SR1_TXE BIT(7) // Data register empty +#define I2C_SR1_BERR BIT(8) // Bus error +#define I2C_SR1_ARLO BIT(9) // Arbitration lost +#define I2C_SR1_AF BIT(10) // Acknowledge failure +#define I2C_SR1_OVR BIT(11) // Overrun/underrun +#define I2C_SR1_PECERR BIT(12) // PEC Error in reception +#define I2C_SR1_TIMEOUT BIT(14) // Timeout or Tlow error +#define I2C_SR1_SMBALERT BIT(15) // SMBus alert + +/* Status register 2 bits */ +#define I2C_SR2_MSL BIT(0) // Master/slave +#define I2C_SR2_BUSY BIT(1) // Bus busy +#define I2C_SR2_TRA BIT(2) // Transmitter/receiver +#define I2C_SR2_GENCALL BIT(4) // General call address +#define I2C_SR2_SMBDEFAULT BIT(5) // SMBus device default address +#define I2C_SR2_SMBHOST BIT(6) // SMBus host header +#define I2C_SR2_DUALF BIT(7) // Dual flag +#define I2C_SR2_PEC 0xFF00 // Packet error checking register + +#ifdef __cplusplus +extern "C" { +#endif + +void i2c_master_enable(i2c_dev *dev, uint32 flags); +int32 i2c_master_xfer(i2c_dev *dev, i2c_msg *msgs, uint16 num); + +void i2c_start_condition(i2c_reg_map *regs); +void i2c_stop_condition(i2c_reg_map *regs); +void i2c_send_slave_addr(i2c_reg_map *regs, uint32 addr, uint32 rw); +void i2c_set_input_clk(i2c_reg_map *regs, uint32 freq); +void i2c_set_clk_control(i2c_reg_map *regs, uint32 val); +void i2c_set_fast_mode(i2c_reg_map *regs); +void i2c_set_standard_mode(i2c_reg_map *regs); +void i2c_set_trise(i2c_reg_map *regs, uint32 trise); +void i2c_enable_ack(i2c_reg_map *regs); +void i2c_disable_ack(i2c_reg_map *regs); + +/* interrupt flags */ +#define I2C_IRQ_ERROR I2C_CR2_ITERREN +#define I2C_IRQ_EVENT I2C_CR2_ITEVTEN +#define I2C_IRQ_BUFFER I2C_CR2_ITBUFEN +void i2c_enable_irq(i2c_reg_map *regs, uint32 irqs); +void i2c_disable_irq(i2c_reg_map *regs, uint32 irqs); +void i2c_peripheral_enable(i2c_reg_map *regs); +void i2c_peripheral_disable(i2c_reg_map *regs); + +static inline void i2c_write(i2c_reg_map *regs, uint8 byte) { + regs->DR = byte; +} + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/libmaple/libmaple.h b/libmaple/libmaple.h index 02e27d3..3e7fea9 100644 --- a/libmaple/libmaple.h +++ b/libmaple/libmaple.h @@ -32,6 +32,7 @@ #define _LIBMAPLE_H_ #include "libmaple_types.h" +#include "stm32.h" /* General configuration */ #define DEBUG_NONE 0 @@ -67,6 +68,9 @@ /* Has a DAC? */ #define NR_DAC_PINS 0 + /* Number of maskable interrupts */ + #define NR_INTERRUPTS 43 + /* USB Identifier numbers */ /* Descriptor strings must be modified by hand in usb/descriptors.c for now */ @@ -111,6 +115,7 @@ #define NR_USART 5 /* NB: 4 and 5 are UART only */ #define NR_FSMC 1 #define NR_DAC_PINS 2 + #define NR_INTERRUPTS 60 #define VCOM_ID_VENDOR 0x1EAF #define VCOM_ID_PRODUCT 0x0004 diff --git a/libmaple/nvic.c b/libmaple/nvic.c index b1da605..28ca169 100644 --- a/libmaple/nvic.c +++ b/libmaple/nvic.c @@ -27,6 +27,7 @@ */ #include "libmaple.h" +#include "scb.h" #include "nvic.h" #include "systick.h" @@ -64,11 +65,32 @@ void nvic_irq_disable_all(void) { __write(NVIC_ICER1, 0xFFFFFFFF); } + +/** + * @brief Set interrupt priority for an interrupt line + * Note: The STM32 only implements 4 bits of priority, ignoring + * the lower 4 bits. This means there are only 16 levels of priority. + * Bits[3:0] read as zero and ignore writes. + * @param irqn device to set + * @param priority priority to set, 0 being highest priority and 15 being + * lowest. + */ +void nvic_irq_set_priority(int32 irqn, uint8 priority) { + if (irqn < 0) { + /* This interrupt is in the system handler block */ + SCB->SHP[((uint32)irqn & 0xF) - 4] = (priority & 0xF) << 4; + } else { + NVIC->IP[irqn] = (priority & 0xF) << 4; + } +} + /** * @brief Initialize the NVIC according to VECT_TAB_FLASH, * VECT_TAB_RAM, or VECT_TAB_BASE. */ void nvic_init(void) { + uint32 i; + #ifdef VECT_TAB_FLASH nvic_set_vector_table(USER_ADDR_ROM, 0x0); #elif defined VECT_TAB_RAM @@ -78,4 +100,15 @@ void nvic_init(void) { #else #error "You must set a base address for the vector table!" #endif + + /* + * Lower priority level for all peripheral interrupts to lowest + * possible. + */ + for (i = 0; i < NR_INTERRUPTS; i++) { + nvic_irq_set_priority(i, 0xF); + } + + /* Lower systick interrupt priority to lowest level */ + nvic_irq_set_priority(NVIC_SYSTICK, 0xF); } diff --git a/libmaple/nvic.h b/libmaple/nvic.h index 6004c36..fe9990f 100644 --- a/libmaple/nvic.h +++ b/libmaple/nvic.h @@ -47,10 +47,43 @@ extern "C"{ #define NVIC_ICER1 0xE000E184 /* NVIC_ICER2 only on connectivity line */ +/* NVIC Priority */ +#define NVIC_PRI_BASE 0xE000E400 + /* System control registers */ #define SCB_VTOR 0xE000ED08 // Vector table offset register +#define NVIC_VectTab_RAM ((u32)0x20000000) +#define NVIC_VectTab_FLASH ((u32)0x08000000) + +#define NVIC_BASE 0xE000E100 +#define NVIC ((nvic_reg_map*)NVIC_BASE) + +typedef struct nvic_reg_map { + __io uint32 ISER[8]; // Interrupt Set Enable Registers + uint32 RESERVED0[24]; + __io uint32 ICER[8]; // Interrupt Clear Enable Registers + uint32 RSERVED1[24]; + __io uint32 ISPR[8]; // Interrupt Set Pending Registers + uint32 RESERVED2[24]; + __io uint32 ICPR[8]; // Interrupt Clear Pending Registers + uint32 RESERVED3[24]; + __io uint32 IABR[8]; // Interrupt Active bit Registers + uint32 RESERVED4[56]; + __io uint8 IP[240]; // Interrupt Priority Registers + uint32 RESERVED5[644]; + __io uint32 STIR; // Software Trigger Interrupt Registers +} nvic_reg_map; + enum { + NVIC_NMI = -14, + NVIC_MEM_MANAGE = -12, + NVIC_BUS_FAULT = -11, + NVIC_USAGE_FAULT = -10, + NVIC_SVC = -5, + NVIC_DEBUG_MON = -4, + NVIC_PEND_SVC = -2, + NVIC_SYSTICK = -1, NVIC_TIMER1 = 27, NVIC_TIMER2 = 28, NVIC_TIMER3 = 29, @@ -80,7 +113,12 @@ enum { NVIC_DMA_CH4 = 14, NVIC_DMA_CH5 = 15, NVIC_DMA_CH6 = 16, - NVIC_DMA_CH7 = 17 + NVIC_DMA_CH7 = 17, + + NVIC_I2C1_EV = 31, + NVIC_I2C1_ER = 32, + NVIC_I2C2_EV = 33, + NVIC_I2C2_ER = 34 }; @@ -91,6 +129,7 @@ void nvic_init(void); void nvic_irq_enable(uint32 device); void nvic_irq_disable(uint32 device); void nvic_irq_disable_all(void); +void nvic_set_priority(int32 irqn, uint8 priority); #ifdef __cplusplus } diff --git a/libmaple/rcc.c b/libmaple/rcc.c index 6905c22..8edccd9 100644 --- a/libmaple/rcc.c +++ b/libmaple/rcc.c @@ -73,6 +73,8 @@ static const struct rcc_dev_info rcc_dev_table[] = { [RCC_DAC] = { .clk_domain = APB1, .line_num = 29 }, // High-density only [RCC_DMA1] = { .clk_domain = AHB, .line_num = 0 }, [RCC_DMA2] = { .clk_domain = AHB, .line_num = 1 }, // High-density only + [RCC_I2C1] = { .clk_domain = APB1, .line_num = 21 }, // High-density only + [RCC_I2C2] = { .clk_domain = APB1, .line_num = 22 }, // High-density only }; /** diff --git a/libmaple/rcc.h b/libmaple/rcc.h index 4b1f35d..1a59219 100644 --- a/libmaple/rcc.h +++ b/libmaple/rcc.h @@ -175,6 +175,8 @@ enum { RCC_DAC, // High-density devices only (Maple Native) RCC_DMA1, RCC_DMA2, // High-density devices only (Maple Native) + RCC_I2C1, + RCC_I2C2 }; diff --git a/libmaple/rules.mk b/libmaple/rules.mk index b87595d..3d8171f 100644 --- a/libmaple/rules.mk +++ b/libmaple/rules.mk @@ -22,6 +22,7 @@ cSRCS_$(d) := adc.c \ gpio.c \ iwdg.c \ nvic.c \ + i2c.c \ rcc.c \ spi.c \ syscalls.c \ diff --git a/libmaple/scb.h b/libmaple/scb.h new file mode 100644 index 0000000..f851a08 --- /dev/null +++ b/libmaple/scb.h @@ -0,0 +1,58 @@ +/* ***************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * 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. + * ****************************************************************************/ + +/** + * @brief System control block header + */ + +#ifndef _SCB_H_ +#define _SCB_H_ + +typedef struct scb_reg_map { + __io uint32 CPUID; // CPU ID Base Register + __io uint32 ICSR; // Interrupt Control State Register + __io uint32 VTOR; // Vector Table Offset Register + __io uint32 AIRCR; // Application Interrupt / Reset Control Register + __io uint32 SCR; // System Control Register + __io uint32 CCR; // Configuration Control Register + __io uint8 SHP[12]; // System Handlers Priority Registers (4-7, 8-11, 12-15) + __io uint32 SHCSR; // System Handler Control and State Register + __io uint32 CFSR; // Configurable Fault Status Register + __io uint32 HFSR; // Hard Fault Status Register + __io uint32 DFSR; // Debug Fault Status Register + __io uint32 MMFAR; // Mem Manage Address Register + __io uint32 BFAR; // Bus Fault Address Register + __io uint32 AFSR; // Auxiliary Fault Status Register + __io uint32 PFR[2]; // Processor Feature Register + __io uint32 DFR; // Debug Feature Register + __io uint32 ADR; // Auxiliary Feature Register + __io uint32 MMFR[4]; // Memory Model Feature Register + __io uint32 ISAR[5]; // ISA Feature Register +} scb_reg_map; + +#define SCB_BASE 0xE000ED00 +#define SCB ((scb_reg_map*)(SCB_BASE)) + +#endif + diff --git a/libmaple/stm32.h b/libmaple/stm32.h new file mode 100644 index 0000000..e65b28c --- /dev/null +++ b/libmaple/stm32.h @@ -0,0 +1,12 @@ +/** + * @brief General STM32 specific definitions + */ + +#ifndef _STM32_H_ +#define _STM32_H_ + +#define PCLK1 36000000U +#define PCLK2 72000000U + +#endif + diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..0480b5d --- /dev/null +++ b/main.cpp @@ -0,0 +1,84 @@ +// Sample main.cpp file. Blinks the built-in LED, sends a message out +// USART2, and turns on PWM on pin 2. + +#include "wirish.h" +#include "i2c.h" + +static const uint8 slave_address = 0b1010001; + +#define NR_ELEMENTS 64 +uint8 buf0[NR_ELEMENTS + 2] = {0x0, 0x0}; +uint8 buf1[] = {0x0, 0x0}; +uint8 buf2[NR_ELEMENTS]; + +void setup() { + i2c_msg msgs[3]; + uint32 i; + + pinMode(BOARD_LED_PIN, OUTPUT); + + i2c_master_enable(I2C1, 0); + for (i = 0; i < sizeof buf0; i++) { + buf0[i + 2] = i & 0xFF; + } + +#if 0 + /* Write some bytes */ + msgs[0].addr = slave_address; + msgs[0].flags = 0; + msgs[0].length = sizeof buf0; + msgs[0].data = buf0; + + i2c_master_xfer(I2C1, msgs, 1); + delay(5); + return; +#endif + + msgs[1].addr = slave_address; + msgs[1].flags = 0; + msgs[1].length = sizeof buf1; + msgs[1].data = buf1; + + msgs[2].addr = slave_address; + msgs[2].flags = I2C_MSG_READ; + msgs[2].length = sizeof buf2; + msgs[2].data = buf2; + i2c_master_xfer(I2C1, msgs + 1, 2); +#if 0 + for (i = 0; i < 256; i++) { + /* Read it back */ + buf1[1] = i; + msgs[1].addr = slave_address; + msgs[1].flags = 0; + msgs[1].length = 2; + msgs[1].data = buf1; + + msgs[2].addr = slave_address; + msgs[2].flags = I2C_MSG_READ; + msgs[2].length = 1; + msgs[2].data = buf2; + i2c_master_xfer(I2C1, msgs + 1, 2); + delay(10); + } +#endif +} + +void loop() { + toggleLED(); + delay(100); +} + +// Force init to be called *first*, i.e. before static object allocation. +// Otherwise, statically allocated object that need libmaple may fail. +__attribute__(( constructor )) void premain() { + init(); +} + +int main(void) { + setup(); + + while (1) { + loop(); + } + return 0; +} diff --git a/support/ld/names.inc b/support/ld/names.inc index a0e1fb2..bb65dcd 100644 --- a/support/ld/names.inc +++ b/support/ld/names.inc @@ -47,10 +47,10 @@ EXTERN (TIM1_CC_IRQHandler) EXTERN (TIM2_IRQHandler) EXTERN (TIM3_IRQHandler) EXTERN (TIM4_IRQHandler) -EXTERN (I2C1_EV_IRQHandler) -EXTERN (I2C1_ER_IRQHandler) -EXTERN (I2C2_EV_IRQHandler) -EXTERN (I2C2_ER_IRQHandler) +EXTERN (i2c1_ev_irq_handler) +EXTERN (i2c1_er_irq_handler) +EXTERN (i2c2_ev_irq_handler) +EXTERN (i2c2_er_irq_handler) EXTERN (SPI1_IRQHandler) EXTERN (SPI2_IRQHandler) EXTERN (USART1_IRQHandler) diff --git a/test.gdb b/test.gdb new file mode 100644 index 0000000..8b71320 --- /dev/null +++ b/test.gdb @@ -0,0 +1,112 @@ +define i2c_sr1_flags +set $s = $arg0 +printf "SR1: " + +if (($s & (1 << 15))) + printf "SMBALERT " +end + +if (($s & (1 << 14))) + printf "TIMEOUT " +end + +if (($s & (1 << 12))) + printf "PECERR " +end + +if (($s & (1 << 11))) + printf "OVR " +end + +if (($s & (1 << 10))) + printf "AF " +end + +if (($s & (1 << 9))) + printf "ARLO " +end + +if (($s & (1 << 8))) + printf "BERR " +end + +if (($s & (1 << 7))) + printf "TXE " +end + +if (($s & (1 << 6))) + printf "RXNE " +end + +if (($s & (1 << 4))) + printf "STOPF " +end + +if (($s & (1 << 3))) + printf "ADD10 " +end + +if (($s & (1 << 2))) + printf "BTF " +end + +if (($s & (1 << 1))) + printf "ADDR " +end + +if (($s & (1 << 0))) + printf "SB " +end +end + +define i2c_sr2_flags +set $s = $arg0 +printf "SR2: " + +if (($s & (1 << 7))) + printf "DUALF " +end + +if (($s & (1 << 6))) + printf "SMBHOST " +end + +if (($s & (1 << 5))) + printf "SMBDEFAULT " +end + +if (($s & (1 << 4))) + printf "GENCALL " +end + + +if (($s & (1 << 2))) + printf "TRA " +end + +if (($s & (1 << 1))) + printf "BUSY " +end + +if (($s & (1 << 0))) + printf "MSL " +end + +end + +define pbc +set $c = crumbs +while ($c->event) + if ($c->event != 0) + printf "Event: %d ", $c->event + if ($c->event == 1) + i2c_sr1_flags $c->sr1 + printf "\t" + i2c_sr2_flags $c->sr2 + end + printf "\n" + end + set $c = $c + 1 +end + + diff --git a/wirish/wirish.c b/wirish/wirish.c index aaae9d4..622cdfd 100644 --- a/wirish/wirish.c +++ b/wirish/wirish.c @@ -64,18 +64,19 @@ void init(void) { nvic_init(); systick_init(SYSTICK_RELOAD_VAL); gpio_init(); + /* Initialize the ADC for slow conversions, to allow for high impedance inputs. */ adc_init(ADC_SMPR_55_5); - timer_init(TIMER1, 1); - timer_init(TIMER2, 1); - timer_init(TIMER3, 1); - timer_init(TIMER4, 1); -#if NR_TIMERS >= 8 - timer_init(TIMER5, 1); - timer_init(TIMER8, 1); -#endif - setupUSB(); +// timer_init(TIMER1, 1); +// timer_init(TIMER2, 1); +// timer_init(TIMER3, 1); +// timer_init(TIMER4, 1); +//#if NR_TIMERS >= 8 +// timer_init(TIMER5, 1); +// timer_init(TIMER8, 1); +//#endif +// setupUSB(); /* include the board-specific init macro */ BOARD_INIT; -- cgit v1.2.3 From c8ca7a2eb7528462677c80497854b940931eab16 Mon Sep 17 00:00:00 2001 From: Perry Hung Date: Sun, 27 Feb 2011 02:55:43 -0500 Subject: workaround to compile test-session.cpp --- examples/test-session.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/test-session.cpp b/examples/test-session.cpp index 845547d..86bab6d 100644 --- a/examples/test-session.cpp +++ b/examples/test-session.cpp @@ -512,7 +512,7 @@ void cmd_sequential_gpio_writes(void) { // make sure to skip the TX/RX headers for(uint32 i = 2; i Date: Sun, 27 Feb 2011 03:07:31 -0500 Subject: libmaple: Refactor ADC routines ADC routines rewritten, support for ADC2, 3, added. Signed-off-by: Marti Bolivar --- libmaple/adc.c | 140 ++++++++++++---------- libmaple/adc.h | 193 ++++++++++++++++++++++--------- libmaple/libmaple.h | 5 + libmaple/rcc.c | 1 + libmaple/rcc.h | 9 +- libmaple/util.c | 2 +- libmaple/util.h | 3 +- wirish/boards.h | 307 ++++++++++++++++++++++++------------------------- wirish/wirish.c | 5 +- wirish/wirish_analog.c | 4 +- 10 files changed, 389 insertions(+), 280 deletions(-) diff --git a/libmaple/adc.c b/libmaple/adc.c index 3e6818c..adadc63 100644 --- a/libmaple/adc.c +++ b/libmaple/adc.c @@ -24,82 +24,85 @@ /** * @brief Analog to digital converter routines + * + * IMPORTANT: maximum external impedance must be below 0.4kOhms for 1.5 + * sample conversion time. + * + * At 55.5 cycles/sample, the external input impedance < 50kOhms. + * + * See stm32 manual RM008 for how to calculate this. */ #include "libmaple.h" #include "rcc.h" #include "adc.h" -/* The ADC input clock is generated from PCLK2/APB2 divided by a prescaler - * and it must not exceed 14MHz. - * - * ADC1 and ADC2 are clocked by APB2 - * - * 1) Power on by setting ADON in ADC_CR2 - * Conversion starts when ADON is set for a second time after some - * time t > t_stab. - * - * Up to 16 selected conversion must be selected in ADC_SQRx - * - * Single conversion mode: - * Set the ADON bit in the ADC_CR2 register - * Once the conversion is complete: - * Converted data is stored in ADC_DR - * EOC flag is set - * Interrupt is generated if EOCIE is set - * - * Calibration: - * Calibration is started by setting the CAL bit in the ADC_CR2 register. - * Once calibration is over, the CAL bit is reset by hardware and normal - * conversion can be performed. Calibrate at power-on. - * - * ALIGN in ADC_CR2 selects the alignment of data - * - * IMPORTANT: maximum external impedance must be below 0.4kOhms for 1.5 - * sample conversion time. - * - * At 55.5 cycles/sample, the external input impedance < 50kOhms*/ +adc_dev adc1 = { + .regs = (adc_reg_map*)ADC1_BASE, + .clk_id = RCC_ADC1 +}; +const adc_dev *ADC1 = &adc1; -void set_adc_smprx(adc_smp_rate smp_rate); +adc_dev adc2 = { + .regs = (adc_reg_map*)ADC2_BASE, + .clk_id = RCC_ADC2 +}; +const adc_dev *ADC2 = &adc2; -void adc_init(adc_smp_rate smp_rate) { - rcc_set_prescaler(RCC_PRESCALER_ADC, RCC_ADCPRE_PCLK_DIV_6); - rcc_clk_enable(RCC_ADC1); - rcc_reset_dev(RCC_ADC1); +#if NR_ADCS >= 3 +adc_dev adc3 = { + .regs = (adc_reg_map*)ADC3_BASE, + .clk_id = RCC_ADC3 +}; +const adc_dev *ADC3 = &adc3; +#endif - ADC_CR1 = 0; - /* Software triggers conversions */ - ADC_CR2 = CR2_EXTSEL_SWSTART | CR2_EXTTRIG; - ADC_SQR1 = 0; +static void adc_calibrate(adc_reg_map *regs); - /* Set the sample conversion time. See note above for impedance - requirements. */ - adc_set_sample_rate(smp_rate); +/** + * @brief Initialize an ADC peripheral. Only supports software triggered + * conversions. + * @param dev ADC peripheral to initialize + * @param flags unused + */ +void adc_init(const adc_dev *dev, uint32 flags) { + /* Spin up the clocks */ + rcc_set_prescaler(RCC_PRESCALER_ADC, RCC_ADCPRE_PCLK_DIV_6); + rcc_clk_enable(dev->clk_id); + rcc_reset_dev(dev->clk_id); - /* Enable the ADC */ - CR2_ADON_BIT = 1; + /* Software triggers conversions, conversion on external events */ + adc_set_extsel(dev->regs, 7); + adc_set_exttrig(dev->regs, 1); - /* Reset the calibration registers and then perform a reset */ - CR2_RSTCAL_BIT = 1; - while(CR2_RSTCAL_BIT) - ; + /* Enable the ADC */ + adc_enable(dev->regs); - CR2_CAL_BIT = 1; - while(CR2_CAL_BIT) - ; + /* Calibrate ADC */ + adc_calibrate(dev->regs); } - -void adc_disable(void) { - CR2_ADON_BIT = 0; +/** + * @brief Set external event select for regular group + * @param regs adc register map + * @param trigger event to select. See ADC_CR2 EXTSEL[2:0] bits. + */ +void adc_set_extsel(adc_reg_map *regs, uint8 trigger) { + uint32 cr2 = regs->CR2; + cr2 &= ~ADC_CR2_EXTSEL; + cr2 |= (trigger & 0x7) << 17; + regs->CR2 = cr2; } -/* Turn the given sample rate into values for ADC_SMPRx. (Don't - * precompute in order to avoid wasting space). - * - * Don't call this during conversion! + +/** + * @brief Turn the given sample rate into values for ADC_SMPRx. Don't + * call this during conversion. + * @param regs adc register map + * @param smp_rate sample rate to set + * @see adc_smp_rate */ -void adc_set_sample_rate(adc_smp_rate smp_rate) { +void adc_set_sample_rate(adc_reg_map *regs, adc_smp_rate smp_rate) { uint32 adc_smpr1_val = 0, adc_smpr2_val = 0; int i; for (i = 0; i < 10; i++) { @@ -110,6 +113,23 @@ void adc_set_sample_rate(adc_smp_rate smp_rate) { /* ADC_SMPR2 determines sample time for channels [0,9] */ adc_smpr2_val |= smp_rate << (i * 3); } - ADC_SMPR1 = adc_smpr1_val; - ADC_SMPR2 = adc_smpr2_val; + regs->SMPR1 = adc_smpr1_val; + regs->SMPR2 = adc_smpr2_val; +} + +/** + * @brief Calibrate an ADC peripheral + * @param regs adc register map + */ +static void adc_calibrate(adc_reg_map *regs) { + __io uint32 *rstcal_bit = (__io uint32*)BITBAND_PERI(&(regs->CR2), 3); + __io uint32 *cal_bit = (__io uint32*)BITBAND_PERI(&(regs->CR2), 2); + + *rstcal_bit = 1; + while (*rstcal_bit) + ; + + *cal_bit = 1; + while (*cal_bit) + ; } diff --git a/libmaple/adc.h b/libmaple/adc.h index 976986f..4997d14 100644 --- a/libmaple/adc.h +++ b/libmaple/adc.h @@ -25,87 +25,168 @@ /** * @file adc.h * - * @brief Analog-to-Digital Conversion (ADC) routines. + * @brief Analog-to-Digital Conversion (ADC) header. */ #ifndef _ADC_H_ #define _ADC_H_ #include "util.h" +#include "rcc.h" + #ifdef __cplusplus extern "C"{ #endif -/* Notes: - * The maximum input impedance on each channel MUST be below .4kohms, - * or face the wrath of incorrect readings... - * This can be changed at the expense of sample time... see datasheet - * - * Need to up the sample time if otherwise... see datasheet */ +typedef struct adc_reg_map { + __io uint32 SR; ///< Status register + __io uint32 CR1; ///< Control register 1 + __io uint32 CR2; ///< Control register 2 + __io uint32 SMPR1; ///< Sample time register 1 + __io uint32 SMPR2; ///< Sample time register 2 + __io uint32 JOFR1; ///< Injected channel data offset register 1 + __io uint32 JOFR2; ///< Injected channel data offset register 2 + __io uint32 JOFR3; ///< Injected channel data offset register 3 + __io uint32 JOFR4; ///< Injected channel data offset register 4 + __io uint32 HTR; ///< Watchdog high threshold register + __io uint32 LTR; ///< Watchdog low threshold register + __io uint32 SQR1; ///< Regular sequence register 1 + __io uint32 SQR2; ///< Regular sequence register 2 + __io uint32 SQR3; ///< Regular sequence register 3 + __io uint32 JSQR; ///< Injected sequence register + __io uint32 JDR1; ///< Injected data register 1 + __io uint32 JDR2; ///< Injected data register 2 + __io uint32 JDR3; ///< Injected data register 3 + __io uint32 JDR4; ///< Injected data register 4 + __io uint32 DR; ///< Regular data register +} adc_reg_map; + +typedef struct adc_dev { + adc_reg_map *regs; + rcc_clk_id clk_id; +} adc_dev; + +extern const adc_dev *ADC1; +extern const adc_dev *ADC2; +#if NR_ADCS >= 3 +extern const adc_dev *ADC3; +#endif -/* TODO: We'll only use ADC1 for now. See page 41 of the manual for - ADC2 and ADC3's real addresses. */ +/* + * ADC peripheral base addresses + */ #define ADC1_BASE 0x40012400 -#define ADC2_BASE 0x40012400 -#define ADC3_BASE 0x40012400 - -#define ADC_SR *(volatile uint32*)(ADC1_BASE + 0) -#define ADC_CR1 *(volatile uint32*)(ADC1_BASE + 0x4) -#define ADC_CR2 *(volatile uint32*)(ADC1_BASE + 0x8) -#define ADC_SMPR1 *(volatile uint32*)(ADC1_BASE + 0xC) -#define ADC_SMPR2 *(volatile uint32*)(ADC1_BASE + 0x10) -#define ADC_SQR1 *(volatile uint32*)(ADC1_BASE + 0x2C) -#define ADC_SQR3 *(volatile uint32*)(ADC1_BASE + 0x34) -#define ADC_DR *(volatile uint32*)(ADC1_BASE + 0x4C) - -#define CR2_EXTSEL_SWSTART (0xE << 16) -#define CR2_RSTCAL (BIT(3)) -#define CR2_EXTTRIG (BIT(20)) - -/* Bit banded bits */ -#define CR2_ADON_BIT *(volatile uint32*)(BITBAND_PERI(ADC1_BASE+0x8, 0)) -#define CR2_CAL_BIT *(volatile uint32*)(BITBAND_PERI(ADC1_BASE+0x8, 2)) -#define CR2_RSTCAL_BIT *(volatile uint32*)(BITBAND_PERI(ADC1_BASE+0x8, 3)) -#define CR2_SWSTART_BIT *(volatile uint32*)(BITBAND_PERI(ADC1_BASE+0x8, 22)) -#define SR_EOC_BIT *(volatile uint32*)(BITBAND_PERI(ADC1_BASE+0, 1)) -/* (NR_ANALOG_PINS is board specific) */ +#define ADC2_BASE 0x40012800 +#define ADC3_BASE 0x40013C00 + +/* + * Register bit definitions + */ + +/* Status register */ +#define ADC_SR_AWD BIT(0) +#define ADC_SR_EOC BIT(1) +#define ADC_SR_JEOC BIT(2) +#define ADC_SR_JSTRT BIT(3) +#define ADC_SR_STRT BIT(4) + +/* Control register 1 */ +#define ADC_CR1_AWDCH (0x1F) +#define ADC_CR1_EOCIE BIT(5) +#define ADC_CR1_AWDIE BIT(6) +#define ADC_CR1_JEOCIE BIT(7) +#define ADC_CR1_SCAN BIT(8) +#define ADC_CR1_AWDSGL BIT(9) +#define ADC_CR1_JAUTO BIT(10) +#define ADC_CR1_DISCEN BIT(11) +#define ADC_CR1_JDISCEN BIT(12) +#define ADC_CR1_DISCNUM (0xE000) +#define ADC_CR1_JAWDEN BIT(22) +#define ADC_CR1_AWDEN BIT(23) + +/* Control register 2 */ +#define ADC_CR2_ADON BIT(0) +#define ADC_CR2_CONT BIT(1) +#define ADC_CR2_CAL BIT(2) +#define ADC_CR2_RSTCAL BIT(3) +#define ADC_CR2_DMA BIT(8) +#define ADC_CR2_ALIGN BIT(11) +#define ADC_CR2_JEXTSEL (0x7000) +#define ADC_CR2_JEXTTRIG BIT(15) +#define ADC_CR2_EXTSEL (0xE0000) +#define ADC_CR2_EXTTRIG BIT(20) +#define ADC_CR2_JSWSTART BIT(21) +#define ADC_CR2_SWSTART BIT(22) +#define ADC_CR2_TSEREFE BIT(23) + +void adc_init(const adc_dev *dev, uint32 flags); +void adc_set_extsel(adc_reg_map *regs, uint8 trigger); /** ADC per-sample conversion times, in ADC clock cycles */ typedef enum { - ADC_SMPR_1_5, - ADC_SMPR_7_5, - ADC_SMPR_13_5, - ADC_SMPR_28_5, - ADC_SMPR_41_5, - ADC_SMPR_55_5, - ADC_SMPR_71_5, - ADC_SMPR_239_5 + ADC_SMPR_1_5, ///< 1.5 ADC cycles + ADC_SMPR_7_5, ///< 7.5 ADC cycles + ADC_SMPR_13_5, ///< 13.5 ADC cycles + ADC_SMPR_28_5, ///< 28.5 ADC cycles + ADC_SMPR_41_5, ///< 41.5 ADC cycles + ADC_SMPR_55_5, ///< 55.5 ADC cycles + ADC_SMPR_71_5, ///< 71.5 ADC cycles + ADC_SMPR_239_5 ///< 239.5 ADC cycles } adc_smp_rate; -/** Initialize ADC1 to do one-shot conversions at the given sample - rate. */ -void adc_init(adc_smp_rate smp_rate); - -void adc_set_sample_rate(adc_smp_rate smp_rate); - -void adc_disable(void); +void adc_set_sample_rate(adc_reg_map *regs, adc_smp_rate smp_rate); /** - * Perform a single conversion on ADC[0-15]. - * PRECONDITIONS: - * adc initialized */ -static inline int adc_read(int channel) { - /* Set channel */ - ADC_SQR3 = channel; + * @brief Perform a single synchronous software triggered conversion on a + * channel + * @param regs ADC register map + * @param channel channel to convert + * @return conversion result + */ +static inline uint32 adc_read(adc_reg_map *regs, uint8 channel) { + /* Set target channel */ + regs->SQR3 = channel; /* Start the conversion */ - CR2_SWSTART_BIT = 1; + regs->CR2 |= ADC_CR2_SWSTART; /* Wait for it to finish */ - while(SR_EOC_BIT == 0) + while((regs->SR & ADC_SR_EOC) == 0) ; - return ADC_DR; + return regs->DR; +} + +/** + * @brief Set external trigger conversion mode event for regular channels + * @param regs adc register map + * @param enable if 1, conversion on external events is enabled, 0 to disable + */ +static inline void adc_set_exttrig(adc_reg_map *regs, uint8 enable) { + __write(BITBAND_PERI(&(regs->CR2), 20), enable); +} + +/** + * @brief Enable an adc peripheral + * @param regs register map of peripheral to enable + */ +static inline void adc_enable(adc_reg_map *regs) { + __write(BITBAND_PERI(&(regs->CR2), 0), 1); +} + +/** + * @brief Disable an adc peripheral + * @param regs register map of peripheral to disable + */ +static inline void adc_disable(adc_reg_map *regs) { + __write(BITBAND_PERI(&(regs->CR2), 0), 0); +} + +/** + * @brief Disable all ADCs + */ +static inline void adc_disable_all(void) { + adc_disable(ADC1->regs); } #ifdef __cplusplus diff --git a/libmaple/libmaple.h b/libmaple/libmaple.h index 02e27d3..4f9a71a 100644 --- a/libmaple/libmaple.h +++ b/libmaple/libmaple.h @@ -61,6 +61,9 @@ /* Number of USART ports */ #define NR_USART 3 + /* Number of ADCs */ + #define NR_ADCS 2 + /* Has an FSMC bus? */ #define NR_FSMC 0 @@ -109,6 +112,7 @@ #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_ADCS 3 #define NR_FSMC 1 #define NR_DAC_PINS 2 @@ -147,6 +151,7 @@ #define NR_BKP_REGS 10 /* TODO test on Mini */ #define NR_TIMERS 4 #define NR_USART 3 + #define NR_ADCS 2 #define NR_FSMC 0 #define NR_DAC_PINS 0 diff --git a/libmaple/rcc.c b/libmaple/rcc.c index 6905c22..a9d7c96 100644 --- a/libmaple/rcc.c +++ b/libmaple/rcc.c @@ -54,6 +54,7 @@ static const struct rcc_dev_info rcc_dev_table[] = { [RCC_AFIO] = { .clk_domain = APB2, .line_num = 0 }, [RCC_ADC1] = { .clk_domain = APB2, .line_num = 9 }, [RCC_ADC2] = { .clk_domain = APB2, .line_num = 10 }, + [RCC_ADC3] = { .clk_domain = APB2, .line_num = 15 }, [RCC_USART1] = { .clk_domain = APB2, .line_num = 14 }, [RCC_USART2] = { .clk_domain = APB1, .line_num = 17 }, [RCC_USART3] = { .clk_domain = APB1, .line_num = 18 }, diff --git a/libmaple/rcc.h b/libmaple/rcc.h index 4b1f35d..5daca57 100644 --- a/libmaple/rcc.h +++ b/libmaple/rcc.h @@ -144,8 +144,10 @@ enum { RCC_PRESCALER_ADC }; -// RCC Devices -enum { +/* + * Identifies bus and clock line for a device + */ +typedef enum { RCC_GPIOA, RCC_GPIOB, RCC_GPIOC, @@ -156,6 +158,7 @@ enum { RCC_AFIO, RCC_ADC1, RCC_ADC2, + RCC_ADC3, RCC_USART1, RCC_USART2, RCC_USART3, @@ -175,7 +178,7 @@ enum { RCC_DAC, // High-density devices only (Maple Native) RCC_DMA1, RCC_DMA2, // High-density devices only (Maple Native) -}; +} rcc_clk_id; void rcc_clk_init(uint32 sysclk_src, uint32 pll_src, uint32 pll_mul); diff --git a/libmaple/util.c b/libmaple/util.c index 135f005..11f9b34 100644 --- a/libmaple/util.c +++ b/libmaple/util.c @@ -48,7 +48,7 @@ void _fail(const char* file, int line, const char* exp) { timer_disable_all(); /* Turn off ADC */ - adc_disable(); + adc_disable_all(); /* Turn off all usarts */ usart_disable_all(); diff --git a/libmaple/util.h b/libmaple/util.h index 64782d9..63427cc 100644 --- a/libmaple/util.h +++ b/libmaple/util.h @@ -44,7 +44,8 @@ /* Convert SRAM address */ #define BITBAND_SRAM(a,b) ((BITBAND_SRAM_BASE+(a-BITBAND_SRAM_REF)*32+(b*4))) /* Convert PERI address */ -#define BITBAND_PERI(a,b) ((BITBAND_PERI_BASE+(a-BITBAND_PERI_REF)*32+(b*4))) +#define BITBAND_PERI(a, b) ((BITBAND_PERI_BASE + \ + ((uint32)a - BITBAND_PERI_REF) * 32 + (b * 4))) #define REG_SET(reg, val) (*(volatile uint32*)(reg) = (val)) #define REG_SET_BIT(reg, bit) (*(volatile uint32*)(reg) |= BIT(bit)) diff --git a/wirish/boards.h b/wirish/boards.h index f8505ab..ac3a74d 100644 --- a/wirish/boards.h +++ b/wirish/boards.h @@ -51,18 +51,13 @@ enum { D92, D93, D94, D95, D96, D97, D98, D99, D100, D101, D102, D103, D104, D105, D106, D107, D108, D109, D110, D111, }; -/* Set of all possible analog pin names; not all boards have all these */ -enum { - ADC0, ADC1, ADC2, ADC3, ADC4, ADC5, ADC6, ADC7, ADC8, ADC9, ADC10, ADC11, - ADC12, ADC13, ADC14, ADC15, ADC16, ADC17, ADC18, ADC19, ADC20, }; - #define ADC_INVALID 0xFFFFFFFF /* Types used for the tables below */ typedef struct PinMapping { GPIO_Port *port; uint32 pin; - uint32 adc; + uint32 adc_channel; TimerCCR timer_ccr; uint32 exti_port; timer_dev_num timer_num; @@ -80,89 +75,89 @@ typedef struct PinMapping { static __attribute__ ((unused)) PinMapping PIN_MAP[NR_GPIO_PINS] = { /* D0/PA3 */ - {GPIOA_BASE, 3, ADC3, TIMER2_CH4_CCR, EXTI_CONFIG_PORTA, TIMER2, 4}, + {GPIOA_BASE, 3, 3, TIMER2_CH4_CCR, EXTI_CONFIG_PORTA, TIMER2, 4}, /* D1/PA2 */ - {GPIOA_BASE, 2, ADC2, TIMER2_CH3_CCR, EXTI_CONFIG_PORTA, TIMER2, 3}, + {GPIOA_BASE, 2, 2, TIMER2_CH3_CCR, EXTI_CONFIG_PORTA, TIMER2, 3}, /* D2/PA0 */ - {GPIOA_BASE, 0, ADC0, TIMER2_CH1_CCR, EXTI_CONFIG_PORTA, TIMER2, 1}, + {GPIOA_BASE, 0, 0, TIMER2_CH1_CCR, EXTI_CONFIG_PORTA, TIMER2, 1}, /* D3/PA1 */ - {GPIOA_BASE, 1, ADC1, TIMER2_CH2_CCR, EXTI_CONFIG_PORTA, TIMER2, 2}, + {GPIOA_BASE, 1, 1, TIMER2_CH2_CCR, EXTI_CONFIG_PORTA, TIMER2, 2}, /* D4/PB5 */ - {GPIOB_BASE, 5, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, + {GPIOB_BASE, 5, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, /* D5/PB6 */ - {GPIOB_BASE, 6, ADC_INVALID, TIMER4_CH1_CCR, EXTI_CONFIG_PORTB, TIMER4, 1}, + {GPIOB_BASE, 6, ADC_INVALID, TIMER4_CH1_CCR, EXTI_CONFIG_PORTB, TIMER4, 1}, /* D6/PA8 */ - {GPIOA_BASE, 8, ADC_INVALID, TIMER1_CH1_CCR, EXTI_CONFIG_PORTA, TIMER1, 1}, + {GPIOA_BASE, 8, ADC_INVALID, TIMER1_CH1_CCR, EXTI_CONFIG_PORTA, TIMER1, 1}, /* D7/PA9 */ - {GPIOA_BASE, 9, ADC_INVALID, TIMER1_CH2_CCR, EXTI_CONFIG_PORTA, TIMER1, 2}, + {GPIOA_BASE, 9, ADC_INVALID, TIMER1_CH2_CCR, EXTI_CONFIG_PORTA, TIMER1, 2}, /* D8/PA10 */ - {GPIOA_BASE, 10, ADC_INVALID, TIMER1_CH3_CCR, EXTI_CONFIG_PORTA, TIMER1, 3}, + {GPIOA_BASE, 10, ADC_INVALID, TIMER1_CH3_CCR, EXTI_CONFIG_PORTA, TIMER1, 3}, /* D9/PB7 */ - {GPIOB_BASE, 7, ADC_INVALID, TIMER4_CH2_CCR, EXTI_CONFIG_PORTB, TIMER4, 2}, + {GPIOB_BASE, 7, ADC_INVALID, TIMER4_CH2_CCR, EXTI_CONFIG_PORTB, TIMER4, 2}, /* D10/PA4 */ - {GPIOA_BASE, 4, ADC4, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID}, + {GPIOA_BASE, 4, 4, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID}, /* D11/PA7 */ - {GPIOA_BASE, 7, ADC7, TIMER3_CH2_CCR, EXTI_CONFIG_PORTA, TIMER3, 2}, + {GPIOA_BASE, 7, 7, TIMER3_CH2_CCR, EXTI_CONFIG_PORTA, TIMER3, 2}, /* D12/PA6 */ - {GPIOA_BASE, 6, ADC6, TIMER3_CH1_CCR, EXTI_CONFIG_PORTA, TIMER3, 1}, + {GPIOA_BASE, 6, 6, TIMER3_CH1_CCR, EXTI_CONFIG_PORTA, TIMER3, 1}, /* D13/PA5 */ - {GPIOA_BASE, 5, ADC5, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID}, + {GPIOA_BASE, 5, 5, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID}, /* D14/PB8 */ - {GPIOB_BASE, 8, ADC_INVALID, TIMER4_CH3_CCR, EXTI_CONFIG_PORTB, TIMER4, 3}, + {GPIOB_BASE, 8, ADC_INVALID, TIMER4_CH3_CCR, EXTI_CONFIG_PORTB, TIMER4, 3}, /* Little header */ /* D15/PC0 */ - {GPIOC_BASE, 0, ADC10, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, + {GPIOC_BASE, 0, 10, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, /* D16/PC1 */ - {GPIOC_BASE, 1, ADC11, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, + {GPIOC_BASE, 1, 11, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, /* D17/PC2 */ - {GPIOC_BASE, 2, ADC12, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, + {GPIOC_BASE, 2, 12, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, /* D18/PC3 */ - {GPIOC_BASE, 3, ADC13, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, + {GPIOC_BASE, 3, 13, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, /* D19/PC4 */ - {GPIOC_BASE, 4, ADC14, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, + {GPIOC_BASE, 4, 14, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, /* D20/PC5 */ - {GPIOC_BASE, 5, ADC15, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, + {GPIOC_BASE, 5, 15, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, /* External header */ /* D21/PC13 */ - {GPIOC_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, + {GPIOC_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, /* D22/PC14 */ - {GPIOC_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, + {GPIOC_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, /* D23/PC15 */ - {GPIOC_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, + {GPIOC_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, /* D24/PB9 */ - {GPIOB_BASE, 9, ADC_INVALID, TIMER4_CH4_CCR, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, + {GPIOB_BASE, 9, ADC_INVALID, TIMER4_CH4_CCR, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, /* D25/PD2 */ - {GPIOD_BASE, 2, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, + {GPIOD_BASE, 2, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, /* D26/PC10 */ - {GPIOC_BASE, 10, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, + {GPIOC_BASE, 10, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, /* D27/PB0 */ - {GPIOB_BASE, 0, ADC8, TIMER3_CH3_CCR, EXTI_CONFIG_PORTB, TIMER3, 3}, + {GPIOB_BASE, 0, 8, TIMER3_CH3_CCR, EXTI_CONFIG_PORTB, TIMER3, 3}, /* D28/PB1 */ - {GPIOB_BASE, 1, ADC9, TIMER3_CH4_CCR, EXTI_CONFIG_PORTB, TIMER3, 4}, + {GPIOB_BASE, 1, 9, TIMER3_CH4_CCR, EXTI_CONFIG_PORTB, TIMER3, 4}, /* D29/PB10 */ - {GPIOB_BASE, 10, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, + {GPIOB_BASE, 10, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, /* D30/PB11 */ - {GPIOB_BASE, 11, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, + {GPIOB_BASE, 11, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, /* D31/PB12 */ - {GPIOB_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, + {GPIOB_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, /* D32/PB13 */ - {GPIOB_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, + {GPIOB_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, /* D33/PB14 */ - {GPIOB_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, + {GPIOB_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, /* D34/PB15 */ - {GPIOB_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, + {GPIOB_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, /* D35/PC6 */ - {GPIOC_BASE, 6, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, + {GPIOC_BASE, 6, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, /* D36/PC7 */ - {GPIOC_BASE, 7, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, + {GPIOC_BASE, 7, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, /* D37/PC8 */ - {GPIOC_BASE, 8, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, + {GPIOC_BASE, 8, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, /* D38/PC9 (BUT) */ - {GPIOC_BASE, 9, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID} + {GPIOC_BASE, 9, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID} }; #define BOARD_INIT do { \ @@ -182,212 +177,212 @@ typedef struct PinMapping { /* Top header */ /* D0/PB10 */ - {GPIOB_BASE, 10, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, + {GPIOB_BASE, 10, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, /* D1/PB2 */ - {GPIOB_BASE, 2, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, + {GPIOB_BASE, 2, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, /* D2/PB12 */ - {GPIOB_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, + {GPIOB_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, /* D3/PB13 */ - {GPIOB_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, + {GPIOB_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, /* D4/PB14 */ - {GPIOB_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, + {GPIOB_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, /* D5/PB15 */ - {GPIOB_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, + {GPIOB_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, /* D6/PC0 */ - {GPIOC_BASE, 0, ADC10, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, + {GPIOC_BASE, 0, 10, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, /* D7/PC1 */ - {GPIOC_BASE, 1, ADC11, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, + {GPIOC_BASE, 1, 11, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, /* D8/PC2 */ - {GPIOC_BASE, 2, ADC12, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, + {GPIOC_BASE, 2, 12, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, /* D9/PC3 */ - {GPIOC_BASE, 3, ADC13, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, + {GPIOC_BASE, 3, 13, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, /* D10/PC4 */ - {GPIOC_BASE, 4, ADC14, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, + {GPIOC_BASE, 4, 14, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, /* D11/PC5 */ - {GPIOC_BASE, 5, ADC15, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, + {GPIOC_BASE, 5, 15, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, /* D12/PC6 */ - {GPIOC_BASE, 6, ADC_INVALID, TIMER8_CH1_CCR, EXTI_CONFIG_PORTC, TIMER8, 1}, + {GPIOC_BASE, 6, ADC_INVALID, TIMER8_CH1_CCR, EXTI_CONFIG_PORTC, TIMER8, 1}, /* D13/PC7 */ - {GPIOC_BASE, 7, ADC_INVALID, TIMER8_CH2_CCR, EXTI_CONFIG_PORTC, TIMER8, 2}, + {GPIOC_BASE, 7, ADC_INVALID, TIMER8_CH2_CCR, EXTI_CONFIG_PORTC, TIMER8, 2}, /* D14/PC8 */ - {GPIOC_BASE, 8, ADC_INVALID, TIMER8_CH3_CCR, EXTI_CONFIG_PORTC, TIMER8, 3}, + {GPIOC_BASE, 8, ADC_INVALID, TIMER8_CH3_CCR, EXTI_CONFIG_PORTC, TIMER8, 3}, /* D15/PC9 */ - {GPIOC_BASE, 9, ADC_INVALID, TIMER8_CH4_CCR, EXTI_CONFIG_PORTC, TIMER8, 4}, + {GPIOC_BASE, 9, ADC_INVALID, TIMER8_CH4_CCR, EXTI_CONFIG_PORTC, TIMER8, 4}, /* D16/PC10 */ - {GPIOC_BASE, 10, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, + {GPIOC_BASE, 10, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, /* D17/PC11 */ - {GPIOC_BASE, 11, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, + {GPIOC_BASE, 11, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, /* D18/PC12 */ - {GPIOC_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, + {GPIOC_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, /* D19/PC13 */ - {GPIOC_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, + {GPIOC_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, /* D20/PC14 */ - {GPIOC_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, + {GPIOC_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, /* D21/PC15 */ - {GPIOC_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, + {GPIOC_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, /* D22/PA8 */ - {GPIOA_BASE, 8, ADC_INVALID, TIMER1_CH1_CCR, EXTI_CONFIG_PORTA, TIMER1, 1}, + {GPIOA_BASE, 8, ADC_INVALID, TIMER1_CH1_CCR, EXTI_CONFIG_PORTA, TIMER1, 1}, /* D23/PA9 */ - {GPIOA_BASE, 9, ADC_INVALID, TIMER1_CH2_CCR, EXTI_CONFIG_PORTA, TIMER1, 2}, + {GPIOA_BASE, 9, ADC_INVALID, TIMER1_CH2_CCR, EXTI_CONFIG_PORTA, TIMER1, 2}, /* D24/PA10 */ - {GPIOA_BASE, 10, ADC_INVALID, TIMER1_CH3_CCR, EXTI_CONFIG_PORTA, TIMER1, 3}, + {GPIOA_BASE, 10, ADC_INVALID, TIMER1_CH3_CCR, EXTI_CONFIG_PORTA, TIMER1, 3}, /* D25/PB9 */ - {GPIOB_BASE, 9, ADC_INVALID, TIMER4_CH4_CCR, EXTI_CONFIG_PORTB, TIMER4, 4}, + {GPIOB_BASE, 9, ADC_INVALID, TIMER4_CH4_CCR, EXTI_CONFIG_PORTB, TIMER4, 4}, /* Bottom header */ /* D26/PD2 */ - {GPIOD_BASE, 2, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, + {GPIOD_BASE, 2, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, /* D27/PD3 */ - {GPIOD_BASE, 3, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, + {GPIOD_BASE, 3, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, /* D28/PD6 */ - {GPIOD_BASE, 6, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, + {GPIOD_BASE, 6, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, /* D29/PG11 */ - {GPIOG_BASE, 11, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, + {GPIOG_BASE, 11, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, /* D30/PG12 */ - {GPIOG_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, + {GPIOG_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, /* D31/PG13 */ - {GPIOG_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, + {GPIOG_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, /* D32/PG14 */ - {GPIOG_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, + {GPIOG_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, /* D33/PG8 */ - {GPIOG_BASE, 8, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, + {GPIOG_BASE, 8, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, /* D34/PG7 */ - {GPIOG_BASE, 7, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, + {GPIOG_BASE, 7, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, /* D35/PG6 */ - {GPIOG_BASE, 6, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, + {GPIOG_BASE, 6, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, /* D36/PB5 */ - {GPIOB_BASE, 5, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, + {GPIOB_BASE, 5, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, /* D37/PB6 */ - {GPIOB_BASE, 6, ADC_INVALID, TIMER4_CH1_CCR, EXTI_CONFIG_PORTB, TIMER4, 1}, + {GPIOB_BASE, 6, ADC_INVALID, TIMER4_CH1_CCR, EXTI_CONFIG_PORTB, TIMER4, 1}, /* D38/PB7 */ - {GPIOB_BASE, 7, ADC_INVALID, TIMER4_CH2_CCR, EXTI_CONFIG_PORTB, TIMER4, 2}, + {GPIOB_BASE, 7, ADC_INVALID, TIMER4_CH2_CCR, EXTI_CONFIG_PORTB, TIMER4, 2}, /* D39/PF6 */ - {GPIOF_BASE, 6, ADC4, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, + {GPIOF_BASE, 6, 4, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, /* D40/PF7 */ - {GPIOF_BASE, 7, ADC5, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, + {GPIOF_BASE, 7, 5, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, /* D41/PF8 */ - {GPIOF_BASE, 8, ADC6, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, + {GPIOF_BASE, 8, 6, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, /* D42/PF9 */ - {GPIOF_BASE, 9, ADC7, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, + {GPIOF_BASE, 9, 7, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, /* D43/PF10 */ - {GPIOF_BASE, 10, ADC8, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, + {GPIOF_BASE, 10, 8, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, /* D44/PF11 */ - {GPIOF_BASE, 11, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, + {GPIOF_BASE, 11, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, /* D45/PB1 */ - {GPIOB_BASE, 1, ADC9, TIMER3_CH4_CCR, EXTI_CONFIG_PORTB, TIMER3, 4}, + {GPIOB_BASE, 1, 9, TIMER3_CH4_CCR, EXTI_CONFIG_PORTB, TIMER3, 4}, /* D46/PB0 */ - {GPIOB_BASE, 0, ADC8, TIMER3_CH3_CCR, EXTI_CONFIG_PORTB, TIMER3, 3}, + {GPIOB_BASE, 0, 8, TIMER3_CH3_CCR, EXTI_CONFIG_PORTB, TIMER3, 3}, /* D47/PA0 */ - {GPIOA_BASE, 0, ADC0, TIMER5_CH1_CCR, EXTI_CONFIG_PORTA, TIMER5, 1}, + {GPIOA_BASE, 0, 0, TIMER5_CH1_CCR, EXTI_CONFIG_PORTA, TIMER5, 1}, /* D48/PA1 */ - {GPIOA_BASE, 1, ADC1, TIMER5_CH2_CCR, EXTI_CONFIG_PORTA, TIMER5, 2}, /* FIXME (?) what to do about D48--D50 - also being TIMER2_CH[2,3,4]? */ + {GPIOA_BASE, 1, 1, TIMER5_CH2_CCR, EXTI_CONFIG_PORTA, TIMER5, 2}, /* FIXME (?) what to do about D48--D50 + also being TIMER2_CH[2,3,4]? */ /* D49/PA2 */ - {GPIOA_BASE, 2, ADC2, TIMER5_CH3_CCR, EXTI_CONFIG_PORTA, TIMER5, 3}, + {GPIOA_BASE, 2, 2, TIMER5_CH3_CCR, EXTI_CONFIG_PORTA, TIMER5, 3}, /* D50/PA3 */ - {GPIOA_BASE, 3, ADC3, TIMER5_CH4_CCR, EXTI_CONFIG_PORTA, TIMER5, 4}, + {GPIOA_BASE, 3, 3, TIMER5_CH4_CCR, EXTI_CONFIG_PORTA, TIMER5, 4}, /* D51/PA4 */ - {GPIOA_BASE, 4, ADC4, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID}, + {GPIOA_BASE, 4, 4, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID}, /* D52/PA5 */ - {GPIOA_BASE, 5, ADC5, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID}, + {GPIOA_BASE, 5, 5, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID}, /* D53/PA6 */ - {GPIOA_BASE, 6, ADC6, TIMER3_CH1_CCR, EXTI_CONFIG_PORTA, TIMER3, 1}, + {GPIOA_BASE, 6, 6, TIMER3_CH1_CCR, EXTI_CONFIG_PORTA, TIMER3, 1}, /* D54/PA7 */ - {GPIOA_BASE, 7, ADC7, TIMER3_CH2_CCR, EXTI_CONFIG_PORTA, TIMER3, 2}, + {GPIOA_BASE, 7, 7, TIMER3_CH2_CCR, EXTI_CONFIG_PORTA, TIMER3, 2}, /* Right (triple) header */ /* D55/PF0 */ - {GPIOF_BASE, 0, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, + {GPIOF_BASE, 0, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, /* D56/PD11 */ - {GPIOD_BASE, 11, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, + {GPIOD_BASE, 11, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, /* D57/PD14 */ - {GPIOD_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, + {GPIOD_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, /* D58/PF1 */ - {GPIOF_BASE, 1, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, + {GPIOF_BASE, 1, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, /* D59/PD12 */ - {GPIOD_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, + {GPIOD_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, /* D60/PD15 */ - {GPIOD_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, + {GPIOD_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, /* D61/PF2 */ - {GPIOF_BASE, 2, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, + {GPIOF_BASE, 2, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, /* D62/PD13 */ - {GPIOD_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, + {GPIOD_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, /* D63/PD0 */ - {GPIOD_BASE, 0, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, + {GPIOD_BASE, 0, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, /* D64/PF3 */ - {GPIOF_BASE, 3, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, + {GPIOF_BASE, 3, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, /* D65/PE3 */ - {GPIOE_BASE, 3, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, + {GPIOE_BASE, 3, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, /* D66/PD1 */ - {GPIOD_BASE, 1, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, + {GPIOD_BASE, 1, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, /* D67/PF4 */ - {GPIOF_BASE, 4, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, + {GPIOF_BASE, 4, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, /* D68/PE4 */ - {GPIOE_BASE, 4, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, + {GPIOE_BASE, 4, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, /* D69/PE7 */ - {GPIOE_BASE, 7, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, + {GPIOE_BASE, 7, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, /* D70/PF5 */ - {GPIOF_BASE, 5, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, + {GPIOF_BASE, 5, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, /* D71/PE5 */ - {GPIOE_BASE, 5, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, + {GPIOE_BASE, 5, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, /* D72/PE8 */ - {GPIOE_BASE, 8, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, + {GPIOE_BASE, 8, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, /* D73/PF12 */ - {GPIOF_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, + {GPIOF_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, /* D74/PE6 */ - {GPIOE_BASE, 6, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, + {GPIOE_BASE, 6, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, /* D75/PE9 */ - {GPIOE_BASE, 9, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, + {GPIOE_BASE, 9, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, /* D76/PF13 */ - {GPIOF_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, + {GPIOF_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, /* D77/PE10 */ - {GPIOE_BASE, 10, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, + {GPIOE_BASE, 10, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, /* D78/PF14 */ - {GPIOF_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, + {GPIOF_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, /* D79/PG9 */ - {GPIOG_BASE, 9, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, + {GPIOG_BASE, 9, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, /* D80/PE11 */ - {GPIOE_BASE, 11, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, + {GPIOE_BASE, 11, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, /* D81/PF15 */ - {GPIOF_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, + {GPIOF_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, /* D82/PG10 */ - {GPIOG_BASE, 10, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, + {GPIOG_BASE, 10, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, /* D83/PE12 */ - {GPIOE_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, + {GPIOE_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, /* D84/PG0 */ - {GPIOG_BASE, 0, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, + {GPIOG_BASE, 0, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, /* D85/PD5 */ - {GPIOD_BASE, 5, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, + {GPIOD_BASE, 5, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, /* D86/PE13 */ - {GPIOE_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, + {GPIOE_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, /* D87/PG1 */ - {GPIOG_BASE, 1, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, + {GPIOG_BASE, 1, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, /* D88/PD4 */ - {GPIOD_BASE, 4, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, + {GPIOD_BASE, 4, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, /* D89/PE14 */ - {GPIOE_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, + {GPIOE_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, /* D90/PG2 */ - {GPIOG_BASE, 2, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, + {GPIOG_BASE, 2, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, /* D91/PE1 */ - {GPIOE_BASE, 1, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, + {GPIOE_BASE, 1, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, /* D92/PE15 */ - {GPIOE_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, + {GPIOE_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, /* D93/PG3 */ - {GPIOG_BASE, 3, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, + {GPIOG_BASE, 3, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, /* D94/PE0 */ - {GPIOE_BASE, 0, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, + {GPIOE_BASE, 0, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, /* D95/PD8 */ - {GPIOD_BASE, 8, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, + {GPIOD_BASE, 8, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, /* D96/PG4 */ - {GPIOG_BASE, 4, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, + {GPIOG_BASE, 4, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, /* D97/PD9 */ - {GPIOD_BASE, 9, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, + {GPIOD_BASE, 9, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, /* D98/PG5 */ - {GPIOG_BASE, 5, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, + {GPIOG_BASE, 5, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, /* D99/PD10 */ - {GPIOD_BASE, 10, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID} + {GPIOD_BASE, 10, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID} }; #define BOARD_INIT do { \ @@ -409,23 +404,23 @@ typedef struct PinMapping { /* D2/PB2 */ {GPIOB_BASE, 2, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, /* D3/PB0 */ - {GPIOB_BASE, 0, ADC8, TIMER3_CH3_CCR, EXTI_CONFIG_PORTB, TIMER3, 3}, + {GPIOB_BASE, 0, 8, TIMER3_CH3_CCR, EXTI_CONFIG_PORTB, TIMER3, 3}, /* D4/PA7 */ - {GPIOA_BASE, 7, ADC7, TIMER3_CH2_CCR, EXTI_CONFIG_PORTA, TIMER3, 2}, + {GPIOA_BASE, 7, 7, TIMER3_CH2_CCR, EXTI_CONFIG_PORTA, TIMER3, 2}, /* D5/PA6 */ - {GPIOA_BASE, 6, ADC6, TIMER3_CH1_CCR, EXTI_CONFIG_PORTA, TIMER3, 1}, + {GPIOA_BASE, 6, 6, TIMER3_CH1_CCR, EXTI_CONFIG_PORTA, TIMER3, 1}, /* D6/PA5 */ - {GPIOA_BASE, 5, ADC5, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID}, + {GPIOA_BASE, 5, 5, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID}, /* D7/PA4 */ - {GPIOA_BASE, 4, ADC4, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID}, + {GPIOA_BASE, 4, 4, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID}, /* D8/PA3 */ - {GPIOA_BASE, 3, ADC3, TIMER2_CH4_CCR, EXTI_CONFIG_PORTA, TIMER2, 4}, + {GPIOA_BASE, 3, 3, TIMER2_CH4_CCR, EXTI_CONFIG_PORTA, TIMER2, 4}, /* D9/PA2 */ - {GPIOA_BASE, 2, ADC2, TIMER2_CH3_CCR, EXTI_CONFIG_PORTA, TIMER2, 3}, + {GPIOA_BASE, 2, 2, TIMER2_CH3_CCR, EXTI_CONFIG_PORTA, TIMER2, 3}, /* D10/PA1 */ - {GPIOA_BASE, 1, ADC1, TIMER2_CH2_CCR, EXTI_CONFIG_PORTA, TIMER2, 2}, + {GPIOA_BASE, 1, 1, TIMER2_CH2_CCR, EXTI_CONFIG_PORTA, TIMER2, 2}, /* D11/PA0 */ - {GPIOA_BASE, 0, ADC0, TIMER2_CH1_CCR, EXTI_CONFIG_PORTA, TIMER2, 1}, + {GPIOA_BASE, 0, 0, TIMER2_CH1_CCR, EXTI_CONFIG_PORTA, TIMER2, 1}, /* D12/PC15 */ {GPIOC_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, /* D13/PC14 */ @@ -469,7 +464,7 @@ typedef struct PinMapping { /* D32/PB8 */ {GPIOB_BASE, 8, ADC_INVALID, TIMER4_CH3_CCR, EXTI_CONFIG_PORTB, TIMER4, 3}, /* D33/PB1 */ - {GPIOB_BASE, 1, ADC9, TIMER3_CH4_CCR, EXTI_CONFIG_PORTB, TIMER3, 4}, + {GPIOB_BASE, 1, 9, TIMER3_CH4_CCR, EXTI_CONFIG_PORTB, TIMER3, 4}, }; /* since we want the Serial Wire/JTAG pins as GPIOs, disable both diff --git a/wirish/wirish.c b/wirish/wirish.c index aaae9d4..1ea4863 100644 --- a/wirish/wirish.c +++ b/wirish/wirish.c @@ -64,9 +64,12 @@ void init(void) { nvic_init(); systick_init(SYSTICK_RELOAD_VAL); gpio_init(); + /* Initialize the ADC for slow conversions, to allow for high impedance inputs. */ - adc_init(ADC_SMPR_55_5); + adc_init(ADC1, 0); + adc_set_sample_rate(ADC1->regs, ADC_SMPR_55_5); + timer_init(TIMER1, 1); timer_init(TIMER2, 1); timer_init(TIMER3, 1); diff --git a/wirish/wirish_analog.c b/wirish/wirish_analog.c index 3c63342..ba1290d 100644 --- a/wirish/wirish_analog.c +++ b/wirish/wirish_analog.c @@ -33,9 +33,9 @@ /* Assumes that the ADC has been initialized and that the pin is set * to ANALOG_INPUT */ uint32 analogRead(uint8 pin) { - if(PIN_MAP[pin].adc == ADC_INVALID) { + if(PIN_MAP[pin].adc_channel == ADC_INVALID) { return 0; } - return adc_read(PIN_MAP[pin].adc); + return adc_read(ADC1->regs, PIN_MAP[pin].adc_channel); } -- cgit v1.2.3 From 9136ea9015c68fba7302dbe33a759aea43860b2f Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Sun, 27 Feb 2011 05:39:55 -0500 Subject: Refactor backup (BKP) and power (PWR) routines. --- examples/test-bkp.cpp | 78 +++++++++++++++++++++++++++++++++++ libmaple/bkp.c | 110 +++++++++++++++++++++++++++++++++----------------- libmaple/bkp.h | 98 +++++++++++++++++++++++++++++--------------- libmaple/pwr.c | 42 +++++++++++++++++++ libmaple/pwr.h | 64 ++++++++++++++++++++++------- libmaple/rcc.c | 20 ++++----- libmaple/rcc.h | 6 ++- 7 files changed, 322 insertions(+), 96 deletions(-) create mode 100644 examples/test-bkp.cpp create mode 100644 libmaple/pwr.c diff --git a/examples/test-bkp.cpp b/examples/test-bkp.cpp new file mode 100644 index 0000000..27f87bd --- /dev/null +++ b/examples/test-bkp.cpp @@ -0,0 +1,78 @@ +#include + +#include "wirish.h" +#include "bkp.h" +#include "iwdg.h" + +void print_bkp_contents(); +void write_to_bkp(uint16 val); + +void setup() { + pinMode(BOARD_BUTTON_PIN, INPUT); + + Serial2.begin(9600); + Serial2.println("*** Beginning BKP test"); + + Serial2.println("Init..."); + bkp_init(); + Serial2.println("Done."); + + print_bkp_contents(); + write_to_bkp(10); + print_bkp_contents(); + + Serial2.println("Enabling backup writes."); + bkp_enable_writes(); + write_to_bkp(20); + print_bkp_contents(); + + Serial2.println("Disabling backup writes."); + bkp_disable_writes(); + write_to_bkp(30); + print_bkp_contents(); + + Serial2.println("Done testing backup registers; press button to enable " + "independent watchdog (in order to cause a reset)."); + waitForButtonPress(0); + iwdg_init(IWDG_PRE_4, 1); + Serial2.println(); +} + +void loop() { +} + +void print_bkp_contents() { + Serial2.println("Backup data register contents:"); + char buf[100]; + for (int i = 1; i <= NR_BKP_REGS; i++) { + snprintf(buf, sizeof buf, "DR%d: %d ", i, bkp_read(i)); + Serial2.print(buf); + if (i % 5 == 0) Serial2.println(); + } + Serial2.println(); +} + +void write_to_bkp(uint16 val) { + Serial2.print("Attempting to write "); + Serial2.print(val); + Serial2.println(" to backup registers..."); + for (int i = 1; i <= NR_BKP_REGS; i++) { + bkp_write(i, val); + } + Serial2.println("Done."); +} + +__attribute__((constructor)) void premain() { + init(); +} + +int main(void) { + init(); + setup(); + + while (1) { + loop(); + } + return 0; +} + diff --git a/libmaple/bkp.c b/libmaple/bkp.c index e89abd0..ac9aeae 100644 --- a/libmaple/bkp.c +++ b/libmaple/bkp.c @@ -24,63 +24,99 @@ * SOFTWARE. *****************************************************************************/ -#include "libmaple.h" #include "bkp.h" #include "pwr.h" #include "rcc.h" #include "util.h" -/* Data register memory layout is not contiguous. It's split up from - 1--NR_LOW_DRS, beginning at BKP_LOW_OFFSET, through - (NR_LOW_DRS+1)--NR_DRS, beginning at BKP_HIGH_OFFSET. */ -#define NR_LOW_DRS 10 -#define BKP_LOW_OFFSET 0x4 /* start offset for data registers 1--10 */ -#define BKP_HIGH_OFFSET 0x40 /* start offset for data registers 11--42 */ +static inline __io uint32* data_register(uint8 reg); -inline volatile uint16* reg_addr(uint8 reg) { - if (1 <= reg) { - if (reg <= NR_LOW_DRS) { - return (volatile uint16*)(BKP_BASE + BKP_LOW_OFFSET + - (reg - 1) * 4); - } else if (reg <= NR_BKP_REGS) { - return (volatile uint16*)(BKP_BASE + BKP_HIGH_OFFSET + - (reg - NR_LOW_DRS - 1) * 4); - } - } - return 0; -} +bkp_dev bkp = { + .regs = BKP_BASE, +}; -void bkp_init(void) { - /* Set PWREN (28) and BKPEN (27) bits */ - __set_bits(RCC_APB1ENR, BIT(28) | BIT(27)); -} +const bkp_dev *BKP = &bkp; -void bkp_disable(void) { - __clear_bits(RCC_APB1ENR, BIT(28) | BIT(27)); +/** + * @brief Initialize backup interface. + * + * Enables the power and backup interface clocks, and resets the + * backup device. + */ +void bkp_init(void) { + /* Don't call pwr_init(), or you'll reset the device. We just + * need the clock. */ + rcc_clk_enable(RCC_PWR); + rcc_clk_enable(RCC_BKP); + rcc_reset_dev(RCC_BKP); } +/** + * Enable write access to the backup registers. Backup interface must + * be initialized for subsequent register writes to work. + * @see bkp_init() + */ void bkp_enable_writes(void) { - /* Set the DBP bit in PWR_CR */ - __write(BITBAND_PERI(PWR_CR, PWR_CR_DBP), 1); + __write(BITBAND_PERI(&(PWR_BASE->CR), PWR_CR_DBP), 1); } +/** + * Disable write access to the backup registers. + */ void bkp_disable_writes(void) { - __write(BITBAND_PERI(PWR_CR, PWR_CR_DBP), 0); + __write(BITBAND_PERI(&(PWR_BASE->CR), PWR_CR_DBP), 0); } +/** + * Read a value from given backup data register. + * @param reg Data register to read, from 1 to NR_BKP_REGS (10 on Maple). + */ uint16 bkp_read(uint8 reg) { - volatile uint16* addr = reg_addr(reg); - if (addr != 0) { - return *addr; + __io uint32* dr = data_register(reg); + if (!dr) { + ASSERT(0); /* nonexistent register */ + return 0; } - ASSERT(0); /* nonexistent register */ - return 0; + return (uint16)*dr; } +/** + * @brief Write a value to given data register. + * + * Write access to backup registers must be enabled. + * + * @param reg Data register to write, from 1 to NR_BKP_REGS (10 on Maple). + * @param val Value to write into the register. + * @see bkp_enable_writes() + */ void bkp_write(uint8 reg, uint16 val) { - volatile uint16* addr = reg_addr(reg); - if (addr != 0) { - *addr = val; + __io uint32* dr = data_register(reg); + if (!dr) { + ASSERT(0); /* nonexistent register */ + return; + } + *dr = (uint32)val; +} + +/* + * Data register memory layout is not contiguous. It's split up from + * 1--NR_LOW_DRS, beginning at BKP_BASE->DR1, through to + * (NR_LOW_DRS+1)--NR_BKP_REGS, beginning at BKP_BASE->DR10. + */ +#define NR_LOW_DRS 10 + +static inline __io uint32* data_register(uint8 reg) { + if (reg < 1 || reg > NR_BKP_REGS) { + return 0; + } + +#if NR_BKP_REGS == NR_LOW_DRS + return (uint32*)BKP_BASE + reg; +#else + if (reg <= NR_LOW_DRS) { + return (uint32*)BKP_BASE + reg; + } else { + return (uint32*)&(BKP_BASE->DR11) + (reg - NR_LOW_DRS - 1); } - ASSERT(0); /* nonexistent register */ +#endif } diff --git a/libmaple/bkp.h b/libmaple/bkp.h index 9ad4c41..ce8e6c7 100644 --- a/libmaple/bkp.h +++ b/libmaple/bkp.h @@ -32,51 +32,83 @@ #ifndef _BKP_H_ #define _BKP_H_ +#include "libmaple.h" + #ifdef __cplusplus extern "C" { #endif -#define BKP_BASE 0x40006C00 -#define BKP_RTCCR (BKP_BASE + 0x2C) -#define BKP_CR (BKP_BASE + 0x30) -#define BKP_CSR (BKP_BASE + 0x34) - -/** - * Initialize backup interface. This function enables the power and - * backup interface clocks. It does not enable write access to the - * backup registers. - */ -void bkp_init(void); +typedef struct bkp_reg_map { + const uint32 RESERVED1; + __io uint32 DR1; ///< Data register 1 + __io uint32 DR2; ///< Data register 2 + __io uint32 DR3; ///< Data register 3 + __io uint32 DR4; ///< Data register 4 + __io uint32 DR5; ///< Data register 5 + __io uint32 DR6; ///< Data register 6 + __io uint32 DR7; ///< Data register 7 + __io uint32 DR8; ///< Data register 8 + __io uint32 DR9; ///< Data register 9 + __io uint32 DR10; ///< Data register 10 + __io uint32 RTCCR; ///< RTC control register + __io uint32 CR; ///< Control register + __io uint32 CSR; ///< Control and status register +#if NR_BKP_REGS > 10 + const uint32 RESERVED2; + const uint32 RESERVED3; + __io uint32 DR11; ///< Data register 11 + __io uint32 DR12; ///< Data register 12 + __io uint32 DR13; ///< Data register 13 + __io uint32 DR14; ///< Data register 14 + __io uint32 DR15; ///< Data register 15 + __io uint32 DR16; ///< Data register 16 + __io uint32 DR17; ///< Data register 17 + __io uint32 DR18; ///< Data register 18 + __io uint32 DR19; ///< Data register 19 + __io uint32 DR20; ///< Data register 20 + __io uint32 DR21; ///< Data register 21 + __io uint32 DR22; ///< Data register 22 + __io uint32 DR23; ///< Data register 23 + __io uint32 DR24; ///< Data register 24 + __io uint32 DR25; ///< Data register 25 + __io uint32 DR26; ///< Data register 26 + __io uint32 DR27; ///< Data register 27 + __io uint32 DR28; ///< Data register 28 + __io uint32 DR29; ///< Data register 29 + __io uint32 DR30; ///< Data register 30 + __io uint32 DR31; ///< Data register 31 + __io uint32 DR32; ///< Data register 32 + __io uint32 DR33; ///< Data register 33 + __io uint32 DR34; ///< Data register 34 + __io uint32 DR35; ///< Data register 35 + __io uint32 DR36; ///< Data register 36 + __io uint32 DR37; ///< Data register 37 + __io uint32 DR38; ///< Data register 38 + __io uint32 DR39; ///< Data register 39 + __io uint32 DR40; ///< Data register 40 + __io uint32 DR41; ///< Data register 41 + __io uint32 DR42; ///< Data register 42 +#endif +} bkp_reg_map; -/** Disable power and backup interface clocks. */ -void bkp_disable(void); +typedef struct bkp_dev { + bkp_reg_map *regs; +} bkp_dev; /** - * Enable write access to the backup registers. Backup interface must - * be initialized for subsequent register writes to work. - * @see bkp_init() + * Backup device. */ -void bkp_enable_writes(void); +extern const bkp_dev *BKP; -/** - * Disable write access to the backup registers. Does not disable - * backup interface clocks. +/* + * Backup peripheral base. */ -void bkp_disable_writes(void); +#define BKP_BASE ((bkp_reg_map*)0x40006C00) -/** - * Read a value from given backup data register. - * @param reg Data register to read, from 1 to NR_BKP_REGS (10 on Maple). - */ +void bkp_init(void); +void bkp_enable_writes(void); +void bkp_disable_writes(void); uint16 bkp_read(uint8 reg); - -/** - * Write a value to given data register. Backup interface must have - * been previously initialized, and write access to backup registers - * must be enabled. - * @param reg Data register to write, from 1 to NR_BKP_REGS (10 on Maple). - * @param val Value to write into the register. - */ void bkp_write(uint8 reg, uint16 val); #ifdef __cplusplus diff --git a/libmaple/pwr.c b/libmaple/pwr.c new file mode 100644 index 0000000..b43193e --- /dev/null +++ b/libmaple/pwr.c @@ -0,0 +1,42 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +#include "pwr.h" +#include "rcc.h" + +pwr_dev pwr = { + .regs = PWR_BASE; +}; + +const pwr_dev *PWR = &pwr; + +/** + * Enables the power interface clock, and resets the power device. + */ +void pwr_init(void) { + rcc_clk_enable(RCC_PWR); + rcc_reset_dev(RCC_PWR); +} diff --git a/libmaple/pwr.h b/libmaple/pwr.h index 96a8356..5ff815d 100644 --- a/libmaple/pwr.h +++ b/libmaple/pwr.h @@ -29,18 +29,52 @@ * @brief Power control (PWR) defines. */ -#define PWR_BASE 0x40007000 - -#define PWR_CR (PWR_BASE + 0x0) -#define PWR_CR_DBP 8 /* Disable backup domain write protection bit */ -#define PWR_CR_PVDE 4 /* Power voltage detector enable bit */ -#define PWR_CR_CSBF 3 /* Clear standby flag bit */ -#define PWR_CR_CWUF 2 /* Clear wakeup flag bit */ -#define PWR_CR_PDDS 1 /* Power down deepsleep bit */ -#define PWR_CR_LPDS 0 /* Low-power deepsleep bit */ - -#define PWR_CSR (PWR_BASE + 0x4) -#define PWR_CSR_EWUP 8 /* Enable wakeup pin bit */ -#define PWR_CSR_PVDO 2 /* PVD output bit */ -#define PWR_CSR_SBF 1 /* Standby flag bit */ -#define PWR_CSR_WUF 0 /* Wakeup flag bit */ +#include "libmaple.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Power interface register map. */ +typedef struct pwr_reg_map { + __io uint32 CR; /**< Control register */ + __io uint32 CSR; /**< Control and status register */ +} pwr_reg_map; + +/* + * Power peripheral base. + */ +#define PWR_BASE ((pwr_reg_map*)0x40007000) + +/** Power interface device. */ +typedef struct pwr_dev { + pwr_reg_map *regs; +} pwr_dev; + +/** + * Power device. + */ +extern const pwr_dev *PWR; +/* + * Register bit definitions + */ + +/* Control register */ +#define PWR_CR_DBP 8 /**< Disable backup domain write protection bit */ +#define PWR_CR_PVDE 4 /**< Power voltage detector enable bit */ +#define PWR_CR_CSBF 3 /**< Clear standby flag bit */ +#define PWR_CR_CWUF 2 /**< Clear wakeup flag bit */ +#define PWR_CR_PDDS 1 /**< Power down deepsleep bit */ +#define PWR_CR_LPDS 0 /**< Low-power deepsleep bit */ + +/* Control and status register */ +#define PWR_CSR_EWUP 8 /**< Enable wakeup pin bit */ +#define PWR_CSR_PVDO 2 /**< PVD output bit */ +#define PWR_CSR_SBF 1 /**< Standby flag bit */ +#define PWR_CSR_WUF 0 /**< Wakeup flag bit */ + +void pwr_init(void); + +#ifdef __cplusplus +} +#endif diff --git a/libmaple/rcc.c b/libmaple/rcc.c index a9d7c96..2841af3 100644 --- a/libmaple/rcc.c +++ b/libmaple/rcc.c @@ -74,6 +74,8 @@ static const struct rcc_dev_info rcc_dev_table[] = { [RCC_DAC] = { .clk_domain = APB1, .line_num = 29 }, // High-density only [RCC_DMA1] = { .clk_domain = AHB, .line_num = 0 }, [RCC_DMA2] = { .clk_domain = AHB, .line_num = 1 }, // High-density only + [RCC_PWR] = { .clk_domain = APB1, .line_num = 28}, + [RCC_BKP] = { .clk_domain = APB1, .line_num = 27} }; /** @@ -117,18 +119,18 @@ void rcc_clk_init(uint32 sysclk_src, uint32 pll_src, uint32 pll_mul) { /** * @brief Turn on the clock line on a device - * @param dev_num device to turn on + * @param device Clock ID of the device to turn on. */ -void rcc_clk_enable(uint32 dev_num) { +void rcc_clk_enable(rcc_clk_id device) { static const uint32 enable_regs[] = { [APB1] = RCC_APB1ENR, [APB2] = RCC_APB2ENR, [AHB] = RCC_AHBENR, }; - uint8 clk_domain = rcc_dev_table[dev_num].clk_domain; + uint8 clk_domain = rcc_dev_table[device].clk_domain; - __set_bits(enable_regs[clk_domain], BIT(rcc_dev_table[dev_num].line_num)); + __set_bits(enable_regs[clk_domain], BIT(rcc_dev_table[device].line_num)); } /** @@ -154,16 +156,16 @@ void rcc_set_prescaler(uint32 prescaler, uint32 divider) { /** * @brief reset a device - * @param dev_num device to reset + * @param device Clock ID of the device to reset. */ -void rcc_reset_dev(uint32 dev_num) { +void rcc_reset_dev(rcc_clk_id device) { static const uint32 reset_regs[] = { [APB1] = RCC_APB1RSTR, [APB2] = RCC_APB2RSTR, }; - uint8 clk_domain = rcc_dev_table[dev_num].clk_domain; + uint8 clk_domain = rcc_dev_table[device].clk_domain; - __set_bits(reset_regs[clk_domain], BIT(rcc_dev_table[dev_num].line_num)); - __clear_bits(reset_regs[clk_domain], BIT(rcc_dev_table[dev_num].line_num)); + __set_bits(reset_regs[clk_domain], BIT(rcc_dev_table[device].line_num)); + __clear_bits(reset_regs[clk_domain], BIT(rcc_dev_table[device].line_num)); } diff --git a/libmaple/rcc.h b/libmaple/rcc.h index 5daca57..410ab8b 100644 --- a/libmaple/rcc.h +++ b/libmaple/rcc.h @@ -178,12 +178,14 @@ typedef enum { RCC_DAC, // High-density devices only (Maple Native) RCC_DMA1, RCC_DMA2, // High-density devices only (Maple Native) + RCC_PWR, + RCC_BKP, } rcc_clk_id; void rcc_clk_init(uint32 sysclk_src, uint32 pll_src, uint32 pll_mul); -void rcc_clk_enable(uint32 dev); -void rcc_reset_dev(uint32 dev); +void rcc_clk_enable(rcc_clk_id device); +void rcc_reset_dev(rcc_clk_id device); void rcc_set_prescaler(uint32 prescaler, uint32 divider); #ifdef __cplusplus -- cgit v1.2.3 From c54f98951ea2827598babd4602e0f808b3ee311c Mon Sep 17 00:00:00 2001 From: Perry Hung Date: Sun, 27 Feb 2011 06:38:53 -0500 Subject: Refactor DAC DAC header and source slightly cleaned up. Test on Maple Native prototype. Add flags parameter to allow selective enabling of channels. --- examples/test-dac.cpp | 6 +-- libmaple/dac.c | 89 ++++++++++++++++++++++++++++--------- libmaple/dac.h | 121 ++++++++++++++++++++++++++++++-------------------- wirish/wirish.c | 4 -- 4 files changed, 144 insertions(+), 76 deletions(-) diff --git a/examples/test-dac.cpp b/examples/test-dac.cpp index 3a699e2..62f40eb 100644 --- a/examples/test-dac.cpp +++ b/examples/test-dac.cpp @@ -16,7 +16,7 @@ void setup() { Serial1.println("**** Beginning DAC test"); Serial1.print("Init... "); - dac_init(); + dac_init(DAC_CH1 | DAC_CH2); Serial1.println("Done."); } @@ -29,8 +29,8 @@ void loop() { count = 0; } - dac_write(1, 2048); - dac_write(2, count); + dac_write_channel(1, 4095 - count); + dac_write_channel(2, count); } int main(void) { diff --git a/libmaple/dac.c b/libmaple/dac.c index 63a96ac..54b555b 100644 --- a/libmaple/dac.c +++ b/libmaple/dac.c @@ -23,7 +23,6 @@ *****************************************************************************/ #include "libmaple.h" -#include "rcc.h" #include "gpio.h" #include "dac.h" @@ -31,35 +30,81 @@ * @brief DAC peripheral routines. */ -/* This numbering follows the registers (1-indexed) */ -#define DAC_CH1 1 -#define DAC_CH2 2 +dac_dev dac = { + .regs = DAC_BASE, +}; +const dac_dev *DAC = &dac; -DAC_Map *dac = (DAC_Map*)(DAC_BASE); - -/* Sets up the DAC peripheral */ -void dac_init(void) { +/** + * @brief Initialize the digital to analog converter + * @param flags Flags: + * DAC_CH1: Enable channel 1 + * DAC_CH2: Enable channel 2 + * @sideeffect May set PA4 or PA5 to INPUT_ANALOG + */ +void dac_init(uint32 flags) { /* First turn on the clock */ rcc_clk_enable(RCC_DAC); + rcc_reset_dev(RCC_DAC); - /* Then setup ANALOG mode on PA4 and PA5 */ - gpio_set_mode(GPIOA_BASE, 4, CNF_INPUT_ANALOG); - gpio_set_mode(GPIOA_BASE, 5, CNF_INPUT_ANALOG); + if (flags & DAC_CH1) { + dac_enable_channel(1); + } - /* Then do register stuff. Default does no triggering, and - * buffered output, so all good. */ - dac->CR = DAC_CR_EN1 | DAC_CR_EN2; + if (flags & DAC_CH2) { + dac_enable_channel(2); + } } -void dac_write(uint8 chan, uint16 val) { - switch(chan) { - case DAC_CH1: - dac->DHR12R1 = 0x0FFF & val; +/** + * @brief Write a 12-bit value to the DAC to output + * @param channel channel to select (1 or 2) + * @param val value to write + */ +void dac_write_channel(uint8 channel, uint16 val) { + switch(channel) { + case 1: + DAC->regs->DHR12R1 = DAC_DHR12R1_DACC1DHR & val; + break; + case 2: + DAC->regs->DHR12R2 = DAC_DHR12R2_DACC2DHR & val; + break; + } +} + +/** + * @brief Enable a DAC channel + * @param channel channel to enable, either 1 or 2 + * @sideeffect May change pin mode of PA4 or PA5 + */ +void dac_enable_channel(uint8 channel) { + /* + * Setup ANALOG mode on PA4 and PA5. This mapping is consistent across + * all STM32 chips with a DAC. See RM008 12.2. + */ + switch (channel) { + case 1: + gpio_set_mode(GPIOA_BASE, 4, GPIO_MODE_INPUT_ANALOG); + DAC->regs->CR |= DAC_CR_EN1; + break; + case 2: + gpio_set_mode(GPIOA_BASE, 5, GPIO_MODE_INPUT_ANALOG); + DAC->regs->CR |= DAC_CR_EN2; + break; + } +} + +/** + * @brief Disable a DAC channel + * @param channel channel to disable, either 1 or 2 + */ +void dac_disable_channel(uint8 channel) { + switch (channel) { + case 1: + DAC->regs->CR &= ~DAC_CR_EN1; break; - case DAC_CH2: - dac->DHR12R2 = 0x0FFF & val; + case 2: + DAC->regs->CR &= ~DAC_CR_EN2; break; - default: - ASSERT(0); // can't happen } } diff --git a/libmaple/dac.h b/libmaple/dac.h index 340a49a..3148809 100644 --- a/libmaple/dac.h +++ b/libmaple/dac.h @@ -22,88 +22,115 @@ * THE SOFTWARE. *****************************************************************************/ -/* - * See ../notes/dac.txt for more info - */ - /** * @file dac.h + * @brief Digital to analog converter header file + * See notes/dac.txt for more info */ #ifndef _DAC_H_ #define _DAC_H_ +#include "rcc.h" + #ifdef __cplusplus extern "C"{ #endif -#define DAC_BASE 0x40007400 - -typedef struct { - volatile uint32 CR; - volatile uint32 SWTRIGR; - volatile uint32 DHR12R1; - volatile uint32 DHR12L1; - volatile uint32 DHR8R1; - volatile uint32 DHR12R2; - volatile uint32 DHR12L2; - volatile uint32 DHR8R2; - volatile uint32 DHR12RD; - volatile uint32 DHR12LD; - volatile uint32 DHR8RD; - volatile uint32 DOR1; - volatile uint32 DOR2; -} DAC_Map; - -/* There's only one DAC, so expose it. */ -extern DAC_Map *dac; - -// And here are the register bit ranges -#define DAC_CR_EN1 BIT(0) -#define DAC_CR_BOFF1 BIT(1) -#define DAC_CR_TEN1 BIT(2) -#define DAC_CR_TSEL1 (BIT(3) | BIT(4) | BIT(5)) -#define DAC_CR_WAVE1 (BIT(6) | BIT(7)) -#define DAC_CR_MAMP1 (BIT(8) | BIT(9) | BIT(10) | BIT(11)) -#define DAC_CR_DMAEN1 BIT(12) -#define DAC_CR_EN2 BIT(16) -#define DAC_CR_BOFF2 BIT(17) -#define DAC_CR_TEN2 BIT(18) -#define DAC_CR_TSEL2 (BIT(19) | BIT(20) | BIT(21)) -#define DAC_CR_WAVE2 (BIT(22) | BIT(23)) -#define DAC_CR_MAMP2 (BIT(24) | BIT(25) | BIT(26) | BIT(27)) -#define DAC_CR_DMAEN2 BIT(28) - -#define DAC_SWTRIGR_SWTRIG1 BIT(0) -#define DAC_SWTRIGR_SWTRIG2 BIT(1) +typedef struct dac_reg_map { + __io uint32 CR; ///< Control register + __io uint32 SWTRIGR; ///< Software trigger register + __io uint32 DHR12R1; ///< Channel 1 12-bit right aligned data holding register + __io uint32 DHR12L1; ///< Channel 1 12-bit left aligned data holding register + __io uint32 DHR8R1; ///< Channel 1 8-bit left aligned data holding register + __io uint32 DHR12R2; ///< Channel 2 12-bit right aligned data holding register + __io uint32 DHR12L2; ///< Channel 2 12-bit left aligned data holding register + __io uint32 DHR8R2; ///< Channel 2 8-bit left aligned data holding register + __io uint32 DHR12RD; ///< Dual DAC 12-bit right aligned data holding register + __io uint32 DHR12LD; ///< Dual DAC 12-bit left aligned data holding register + __io uint32 DHR8RD; ///< Dual DAC 8-bit left aligned data holding register + __io uint32 DOR1; ///< Channel 1 data output register + __io uint32 DOR2; ///< Channel 2 data output register +} dac_reg_map; + +typedef struct dac_dev { + dac_reg_map *regs; +} dac_dev; + +extern const dac_dev *DAC; +/* + * DAC peripheral base address + */ +#define DAC_BASE ((dac_reg_map*)0x40007400) + +/* + * Register bit definitions and masks + */ + +/* Control register */ +#define DAC_CR_EN1 BIT(0) // Channel 1 enable +#define DAC_CR_BOFF1 BIT(1) // Channel 1 output buffer disable +#define DAC_CR_TEN1 BIT(2) // Channel 1 trigger enable +#define DAC_CR_TSEL1 (0x7 << 3) // Channel 1 trigger selection +#define DAC_CR_WAVE1 (0x3 << 6) // Channel 1 noise/triangle wave generationg enable +#define DAC_CR_MAMP1 (0xF << 8) // Channel 1 mask/amplitude selector +#define DAC_CR_DMAEN1 BIT(12) // Channel 1 DMA enable +#define DAC_CR_EN2 BIT(16) // Channel 2 enable +#define DAC_CR_BOFF2 BIT(17) // Channel 2 output buffer disable +#define DAC_CR_TEN2 BIT(18) // Channel 2 trigger enable +#define DAC_CR_TSEL2 (0x7 << 19) // Channel 2 trigger selection +#define DAC_CR_WAVE2 (0x3 << 22) // Channel 2 noise/triangle wave generationg enable +#define DAC_CR_MAMP2 (0xF << 24) // Channel 2 mask/amplitude selector +#define DAC_CR_DMAEN2 BIT(28) // Channel 2 DMA enable + +/* Software trigger register */ +#define DAC_SWTRIGR_SWTRIG1 BIT(0) // Channel 1 software trigger +#define DAC_SWTRIGR_SWTRIG2 BIT(1) // Channel 2 software trigger + +/* Channel 1 12-bit right aligned data holding register */ #define DAC_DHR12R1_DACC1DHR 0x00000FFF +/* Channel 1 12-bit left aligned data holding register */ #define DAC_DHR12L1_DACC1DHR 0x0000FFF0 +/* Channel 1 8-bit left aligned data holding register */ #define DAC_DHR8R1_DACC1DHR 0x000000FF +/* Channel 2 12-bit right aligned data holding register */ #define DAC_DHR12R2_DACC2DHR 0x00000FFF +/* Channel 2 12-bit left aligned data holding register */ #define DAC_DHR12L2_DACC2DHR 0x0000FFF0 +/* Channel 2 8-bit left aligned data holding register */ #define DAC_DHR8R2_DACC2DHR 0x000000FF +/* Dual DAC 12-bit right aligned data holding register */ #define DAC_DHR12RD_DACC1DHR 0x00000FFF #define DAC_DHR12RD_DACC2DHR 0x0FFF0000 +/* Dual DAC 12-bit left aligned data holding register */ #define DAC_DHR12LD_DACC1DHR 0x0000FFF0 #define DAC_DHR12LD_DACC2DHR 0xFFF00000 +/* Dual DAC 8-bit left aligned data holding register */ #define DAC_DHR8RD_DACC1DHR 0x000000FF #define DAC_DHR8RD_DACC2DHR 0x0000FF00 -#define DAC_DOR1 0x00000FFF +/* Channel 1 data output register */ +#define DAC_DOR1_DACC1DOR 0x00000FFF + +/* Channel 1 data output register */ +#define DAC_DOR2_DACC2DOR 0x00000FFF -#define DAC_DOR2 0x00000FFF +#define DAC_CH1 0x1 +#define DAC_CH2 0x2 +void dac_init(uint32 flags); -void dac_init(void); -void dac_write(uint8 chan, uint16 val); +void dac_write_channel(uint8 channel, uint16 val); +void dac_enable_channel(uint8 channel); +void dac_disable_channel(uint8 channel); #ifdef __cplusplus } // extern "C" diff --git a/wirish/wirish.c b/wirish/wirish.c index 1ea4863..a74e297 100644 --- a/wirish/wirish.c +++ b/wirish/wirish.c @@ -51,10 +51,6 @@ void init(void) { fsmc_native_sram_init(); #endif -#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); -- cgit v1.2.3 From b192af253494e68ccef222c14fea5d8bedc02c35 Mon Sep 17 00:00:00 2001 From: Perry Hung Date: Sun, 27 Feb 2011 07:25:20 -0500 Subject: .gitignore: Ignore cscope* files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 7e29a09..eab8f74 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ TAGS *.swp docs/doxygen/ arm +cscope* -- cgit v1.2.3 From e05a9ef311ad2c690a0d9176004a167effb537c8 Mon Sep 17 00:00:00 2001 From: Perry Hung Date: Sun, 27 Feb 2011 07:37:19 -0500 Subject: Refactor ADC: Pass device pointer instead of register map --- libmaple/adc.c | 42 ++++++++++++++++++++++-------------------- libmaple/adc.h | 34 ++++++++++++++++++++-------------- wirish/wirish.c | 2 +- wirish/wirish_analog.c | 2 +- 4 files changed, 44 insertions(+), 36 deletions(-) diff --git a/libmaple/adc.c b/libmaple/adc.c index adadc63..17d63b8 100644 --- a/libmaple/adc.c +++ b/libmaple/adc.c @@ -38,26 +38,26 @@ #include "adc.h" adc_dev adc1 = { - .regs = (adc_reg_map*)ADC1_BASE, + .regs = ADC1_BASE, .clk_id = RCC_ADC1 }; const adc_dev *ADC1 = &adc1; adc_dev adc2 = { - .regs = (adc_reg_map*)ADC2_BASE, + .regs = ADC2_BASE, .clk_id = RCC_ADC2 }; const adc_dev *ADC2 = &adc2; #if NR_ADCS >= 3 adc_dev adc3 = { - .regs = (adc_reg_map*)ADC3_BASE, + .regs = ADC3_BASE, .clk_id = RCC_ADC3 }; const adc_dev *ADC3 = &adc3; #endif -static void adc_calibrate(adc_reg_map *regs); +static void adc_calibrate(const adc_dev *dev); /** * @brief Initialize an ADC peripheral. Only supports software triggered @@ -72,39 +72,40 @@ void adc_init(const adc_dev *dev, uint32 flags) { rcc_reset_dev(dev->clk_id); /* Software triggers conversions, conversion on external events */ - adc_set_extsel(dev->regs, 7); - adc_set_exttrig(dev->regs, 1); + adc_set_extsel(dev, 7); + adc_set_exttrig(dev, 1); /* Enable the ADC */ - adc_enable(dev->regs); + adc_enable(dev); /* Calibrate ADC */ - adc_calibrate(dev->regs); + adc_calibrate(dev); } /** * @brief Set external event select for regular group - * @param regs adc register map + * @param dev adc device * @param trigger event to select. See ADC_CR2 EXTSEL[2:0] bits. */ -void adc_set_extsel(adc_reg_map *regs, uint8 trigger) { - uint32 cr2 = regs->CR2; +void adc_set_extsel(const adc_dev *dev, uint8 trigger) { + uint32 cr2 = dev->regs->CR2; cr2 &= ~ADC_CR2_EXTSEL; cr2 |= (trigger & 0x7) << 17; - regs->CR2 = cr2; + dev->regs->CR2 = cr2; } /** * @brief Turn the given sample rate into values for ADC_SMPRx. Don't * call this during conversion. - * @param regs adc register map + * @param dev adc device * @param smp_rate sample rate to set * @see adc_smp_rate */ -void adc_set_sample_rate(adc_reg_map *regs, adc_smp_rate smp_rate) { +void adc_set_sample_rate(const adc_dev *dev, adc_smp_rate smp_rate) { uint32 adc_smpr1_val = 0, adc_smpr2_val = 0; int i; + for (i = 0; i < 10; i++) { if (i < 8) { /* ADC_SMPR1 determines sample time for channels [10,17] */ @@ -113,17 +114,18 @@ void adc_set_sample_rate(adc_reg_map *regs, adc_smp_rate smp_rate) { /* ADC_SMPR2 determines sample time for channels [0,9] */ adc_smpr2_val |= smp_rate << (i * 3); } - regs->SMPR1 = adc_smpr1_val; - regs->SMPR2 = adc_smpr2_val; + + dev->regs->SMPR1 = adc_smpr1_val; + dev->regs->SMPR2 = adc_smpr2_val; } /** * @brief Calibrate an ADC peripheral - * @param regs adc register map + * @param dev adc device */ -static void adc_calibrate(adc_reg_map *regs) { - __io uint32 *rstcal_bit = (__io uint32*)BITBAND_PERI(&(regs->CR2), 3); - __io uint32 *cal_bit = (__io uint32*)BITBAND_PERI(&(regs->CR2), 2); +static void adc_calibrate(const adc_dev *dev) { + __io uint32 *rstcal_bit = (__io uint32*)BITBAND_PERI(&(dev->regs->CR2), 3); + __io uint32 *cal_bit = (__io uint32*)BITBAND_PERI(&(dev->regs->CR2), 2); *rstcal_bit = 1; while (*rstcal_bit) diff --git a/libmaple/adc.h b/libmaple/adc.h index 4997d14..ab6e643 100644 --- a/libmaple/adc.h +++ b/libmaple/adc.h @@ -75,9 +75,9 @@ extern const adc_dev *ADC3; /* * ADC peripheral base addresses */ -#define ADC1_BASE 0x40012400 -#define ADC2_BASE 0x40012800 -#define ADC3_BASE 0x40013C00 +#define ADC1_BASE ((adc_reg_map*)0x40012400) +#define ADC2_BASE ((adc_reg_map*)0x40012800) +#define ADC3_BASE ((adc_reg_map*)0x40013C00) /* * Register bit definitions @@ -120,7 +120,7 @@ extern const adc_dev *ADC3; #define ADC_CR2_TSEREFE BIT(23) void adc_init(const adc_dev *dev, uint32 flags); -void adc_set_extsel(adc_reg_map *regs, uint8 trigger); +void adc_set_extsel(const adc_dev *dev, uint8 trigger); /** ADC per-sample conversion times, in ADC clock cycles */ typedef enum { @@ -134,7 +134,7 @@ typedef enum { ADC_SMPR_239_5 ///< 239.5 ADC cycles } adc_smp_rate; -void adc_set_sample_rate(adc_reg_map *regs, adc_smp_rate smp_rate); +void adc_set_sample_rate(const adc_dev *dev, adc_smp_rate smp_rate); /** * @brief Perform a single synchronous software triggered conversion on a @@ -143,7 +143,9 @@ void adc_set_sample_rate(adc_reg_map *regs, adc_smp_rate smp_rate); * @param channel channel to convert * @return conversion result */ -static inline uint32 adc_read(adc_reg_map *regs, uint8 channel) { +static inline uint32 adc_read(const adc_dev *dev, uint8 channel) { + adc_reg_map *regs = dev->regs; + /* Set target channel */ regs->SQR3 = channel; @@ -159,34 +161,38 @@ static inline uint32 adc_read(adc_reg_map *regs, uint8 channel) { /** * @brief Set external trigger conversion mode event for regular channels - * @param regs adc register map + * @param dev adc device * @param enable if 1, conversion on external events is enabled, 0 to disable */ -static inline void adc_set_exttrig(adc_reg_map *regs, uint8 enable) { - __write(BITBAND_PERI(&(regs->CR2), 20), enable); +static inline void adc_set_exttrig(const adc_dev *dev, uint8 enable) { + __write(BITBAND_PERI(&(dev->regs->CR2), 20), enable); } /** * @brief Enable an adc peripheral * @param regs register map of peripheral to enable */ -static inline void adc_enable(adc_reg_map *regs) { - __write(BITBAND_PERI(&(regs->CR2), 0), 1); +static inline void adc_enable(const adc_dev *dev) { + __write(BITBAND_PERI(&(dev->regs->CR2), 0), 1); } /** * @brief Disable an adc peripheral * @param regs register map of peripheral to disable */ -static inline void adc_disable(adc_reg_map *regs) { - __write(BITBAND_PERI(&(regs->CR2), 0), 0); +static inline void adc_disable(const adc_dev *dev) { + __write(BITBAND_PERI(&(dev->regs->CR2), 0), 0); } /** * @brief Disable all ADCs */ static inline void adc_disable_all(void) { - adc_disable(ADC1->regs); + adc_disable(ADC1); + adc_disable(ADC2); +#if NR_ADCS >= 3 + adc_disable(ADC3); +#endif } #ifdef __cplusplus diff --git a/wirish/wirish.c b/wirish/wirish.c index a74e297..c5dec22 100644 --- a/wirish/wirish.c +++ b/wirish/wirish.c @@ -64,7 +64,7 @@ void init(void) { /* Initialize the ADC for slow conversions, to allow for high impedance inputs. */ adc_init(ADC1, 0); - adc_set_sample_rate(ADC1->regs, ADC_SMPR_55_5); + adc_set_sample_rate(ADC1, ADC_SMPR_55_5); timer_init(TIMER1, 1); timer_init(TIMER2, 1); diff --git a/wirish/wirish_analog.c b/wirish/wirish_analog.c index ba1290d..a658184 100644 --- a/wirish/wirish_analog.c +++ b/wirish/wirish_analog.c @@ -37,5 +37,5 @@ uint32 analogRead(uint8 pin) { return 0; } - return adc_read(ADC1->regs, PIN_MAP[pin].adc_channel); + return adc_read(ADC1, PIN_MAP[pin].adc_channel); } -- cgit v1.2.3 From a949fe81d069fb3ee727537ba3d5f9f926129d62 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Sun, 27 Feb 2011 07:43:21 -0500 Subject: Made DAC comments 80-column clean. --- libmaple/dac.h | 90 +++++++++++++++++++++++++++++++++------------------------- 1 file changed, 51 insertions(+), 39 deletions(-) diff --git a/libmaple/dac.h b/libmaple/dac.h index 3148809..bc64324 100644 --- a/libmaple/dac.h +++ b/libmaple/dac.h @@ -37,26 +37,37 @@ extern "C"{ #endif +/** DAC register map. */ typedef struct dac_reg_map { - __io uint32 CR; ///< Control register - __io uint32 SWTRIGR; ///< Software trigger register - __io uint32 DHR12R1; ///< Channel 1 12-bit right aligned data holding register - __io uint32 DHR12L1; ///< Channel 1 12-bit left aligned data holding register - __io uint32 DHR8R1; ///< Channel 1 8-bit left aligned data holding register - __io uint32 DHR12R2; ///< Channel 2 12-bit right aligned data holding register - __io uint32 DHR12L2; ///< Channel 2 12-bit left aligned data holding register - __io uint32 DHR8R2; ///< Channel 2 8-bit left aligned data holding register - __io uint32 DHR12RD; ///< Dual DAC 12-bit right aligned data holding register - __io uint32 DHR12LD; ///< Dual DAC 12-bit left aligned data holding register - __io uint32 DHR8RD; ///< Dual DAC 8-bit left aligned data holding register - __io uint32 DOR1; ///< Channel 1 data output register - __io uint32 DOR2; ///< Channel 2 data output register + __io uint32 CR; /**< Control register */ + __io uint32 SWTRIGR; /**< Software trigger register */ + __io uint32 DHR12R1; /**< Channel 1 12-bit right-aligned data + holding register */ + __io uint32 DHR12L1; /**< Channel 1 12-bit left-aligned data + holding register */ + __io uint32 DHR8R1; /**< Channel 1 8-bit left-aligned data + holding register */ + __io uint32 DHR12R2; /**< Channel 2 12-bit right-aligned data + holding register */ + __io uint32 DHR12L2; /**< Channel 2 12-bit left-aligned data + holding register */ + __io uint32 DHR8R2; /**< Channel 2 8-bit left-aligned data + holding register */ + __io uint32 DHR12RD; /**< Dual DAC 12-bit right-aligned data + holding register */ + __io uint32 DHR12LD; /**< Dual DAC 12-bit left-aligned data + holding register */ + __io uint32 DHR8RD; /**< Dual DAC 8-bit left-aligned data holding + register */ + __io uint32 DOR1; /**< Channel 1 data output register */ + __io uint32 DOR2; /**< Channel 2 data output register */ } dac_reg_map; typedef struct dac_dev { dac_reg_map *regs; } dac_dev; +/** DAC device. */ extern const dac_dev *DAC; /* @@ -69,52 +80,54 @@ extern const dac_dev *DAC; */ /* Control register */ -#define DAC_CR_EN1 BIT(0) // Channel 1 enable -#define DAC_CR_BOFF1 BIT(1) // Channel 1 output buffer disable -#define DAC_CR_TEN1 BIT(2) // Channel 1 trigger enable -#define DAC_CR_TSEL1 (0x7 << 3) // Channel 1 trigger selection -#define DAC_CR_WAVE1 (0x3 << 6) // Channel 1 noise/triangle wave generationg enable -#define DAC_CR_MAMP1 (0xF << 8) // Channel 1 mask/amplitude selector -#define DAC_CR_DMAEN1 BIT(12) // Channel 1 DMA enable -#define DAC_CR_EN2 BIT(16) // Channel 2 enable -#define DAC_CR_BOFF2 BIT(17) // Channel 2 output buffer disable -#define DAC_CR_TEN2 BIT(18) // Channel 2 trigger enable -#define DAC_CR_TSEL2 (0x7 << 19) // Channel 2 trigger selection -#define DAC_CR_WAVE2 (0x3 << 22) // Channel 2 noise/triangle wave generationg enable -#define DAC_CR_MAMP2 (0xF << 24) // Channel 2 mask/amplitude selector -#define DAC_CR_DMAEN2 BIT(28) // Channel 2 DMA enable +/* Channel 1 control */ +#define DAC_CR_EN1 BIT(0) /* Enable */ +#define DAC_CR_BOFF1 BIT(1) /* Output buffer disable */ +#define DAC_CR_TEN1 BIT(2) /* Trigger enable */ +#define DAC_CR_TSEL1 (0x7 << 3) /* Trigger selection */ +#define DAC_CR_WAVE1 (0x3 << 6) /* Noise/triangle wave enable */ +#define DAC_CR_MAMP1 (0xF << 8) /* Mask/amplitude selector */ +#define DAC_CR_DMAEN1 BIT(12) /* DMA enable */ +/* Channel 2 control */ +#define DAC_CR_EN2 BIT(16) /* Enable */ +#define DAC_CR_BOFF2 BIT(17) /* Output buffer disable */ +#define DAC_CR_TEN2 BIT(18) /* Trigger enable */ +#define DAC_CR_TSEL2 (0x7 << 19) /* Trigger selection */ +#define DAC_CR_WAVE2 (0x3 << 22) /* Noise/triangle wave generation*/ +#define DAC_CR_MAMP2 (0xF << 24) /* Mask/amplitude selector */ +#define DAC_CR_DMAEN2 BIT(28) /* DMA enable */ /* Software trigger register */ -#define DAC_SWTRIGR_SWTRIG1 BIT(0) // Channel 1 software trigger -#define DAC_SWTRIGR_SWTRIG2 BIT(1) // Channel 2 software trigger +#define DAC_SWTRIGR_SWTRIG1 BIT(0) /* Channel 1 software trigger */ +#define DAC_SWTRIGR_SWTRIG2 BIT(1) /* Channel 2 software trigger */ -/* Channel 1 12-bit right aligned data holding register */ +/* Channel 1 12-bit right-aligned data holding register */ #define DAC_DHR12R1_DACC1DHR 0x00000FFF -/* Channel 1 12-bit left aligned data holding register */ +/* Channel 1 12-bit left-aligned data holding register */ #define DAC_DHR12L1_DACC1DHR 0x0000FFF0 -/* Channel 1 8-bit left aligned data holding register */ +/* Channel 1 8-bit left-aligned data holding register */ #define DAC_DHR8R1_DACC1DHR 0x000000FF -/* Channel 2 12-bit right aligned data holding register */ +/* Channel 2 12-bit right-aligned data holding register */ #define DAC_DHR12R2_DACC2DHR 0x00000FFF -/* Channel 2 12-bit left aligned data holding register */ +/* Channel 2 12-bit left-aligned data holding register */ #define DAC_DHR12L2_DACC2DHR 0x0000FFF0 -/* Channel 2 8-bit left aligned data holding register */ +/* Channel 2 8-bit left-aligned data holding register */ #define DAC_DHR8R2_DACC2DHR 0x000000FF -/* Dual DAC 12-bit right aligned data holding register */ +/* Dual DAC 12-bit right-aligned data holding register */ #define DAC_DHR12RD_DACC1DHR 0x00000FFF #define DAC_DHR12RD_DACC2DHR 0x0FFF0000 -/* Dual DAC 12-bit left aligned data holding register */ +/* Dual DAC 12-bit left-aligned data holding register */ #define DAC_DHR12LD_DACC1DHR 0x0000FFF0 #define DAC_DHR12LD_DACC2DHR 0xFFF00000 -/* Dual DAC 8-bit left aligned data holding register */ +/* Dual DAC 8-bit left-aligned data holding register */ #define DAC_DHR8RD_DACC1DHR 0x000000FF #define DAC_DHR8RD_DACC2DHR 0x0000FF00 @@ -136,5 +149,4 @@ void dac_disable_channel(uint8 channel); } // extern "C" #endif - #endif -- cgit v1.2.3 From 4e90248a2e81ec7bd8d3cfa858cef4a045cc1003 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Sun, 27 Feb 2011 11:42:56 -0500 Subject: Cleaned out libmaple.h; this had wide-ranging implications. Many of the #defines in libmaple.h were board-specific, not MCU-specific. Most of these were only used by code under libmaple/usb/. These were moved into usb_config.h, and are clearly marked as being terrible hacks. I'm going to treat the USB stack as a black box that we'll deal with later. Further, instead of having a variety of #defines like "How many USARTS do I have?", we decide that based on the density of the chip. This is determined by testing for STM32_MEDIUM_DENSITY or STM32_HIGH_DENSITY defines. libmaple currently doesn't support low-density chips, so that suffices. The Makefile will set these automatically based on the MCU. Other offending #defines are ERROR_LED_PORT and ERROR_LED_PIN; these were made optional, but they're set in the Makefile as a hack to keep things working. --- Makefile | 37 ++++++++-- docs/source/language.rst | 57 ++++++++-------- examples/test-bkp.cpp | 38 ++++++----- examples/test-session.cpp | 3 +- libmaple/adc.c | 2 +- libmaple/adc.h | 4 +- libmaple/bkp.c | 12 ++-- libmaple/bkp.h | 8 ++- libmaple/libmaple.h | 163 +++++++-------------------------------------- libmaple/libmaple_types.h | 2 - libmaple/timers.c | 10 +-- libmaple/timers.h | 6 +- libmaple/usart.c | 12 ++-- libmaple/usart.h | 2 + libmaple/usb/descriptors.c | 73 +++++++++++--------- libmaple/usb/usb_config.h | 76 +++++++++++++++++++-- libmaple/util.c | 23 +++++++ libmaple/util.h | 33 ++++++--- wirish/HardwareTimer.cpp | 4 +- wirish/HardwareTimer.h | 2 +- wirish/boards.h | 18 +++-- wirish/ext_interrupts.h | 4 +- wirish/wirish.c | 4 +- 23 files changed, 308 insertions(+), 285 deletions(-) diff --git a/Makefile b/Makefile index a709696..149f54a 100644 --- a/Makefile +++ b/Makefile @@ -9,17 +9,27 @@ VENDOR_ID := 1EAF PRODUCT_ID := 0003 # Guess the MCU based on the BOARD (can be overridden ) +# FIXME the error LED config needs to be in wirish/ instead ifeq ($(BOARD), maple) MCU := STM32F103RB PRODUCT_ID := 0003 + ERROR_LED_PORT := GPIOA_BASE + ERROR_LED_PIN := 5 + DENSITY := STM32_MEDIUM_DENSITY endif ifeq ($(BOARD), maple_native) MCU := STM32F103ZE PRODUCT_ID := 0003 + ERROR_LED_PORT := GPIOC_BASE + ERROR_LED_PIN := 15 + DENSITY := STM32_HIGH_DENSITY endif ifeq ($(BOARD), maple_mini) MCU := STM32F103CB PRODUCT_ID := 0003 + ERROR_LED_PORT := GPIOB_BASE + ERROR_LED_PIN := 1 + DENSITY := STM32_MEDIUM_DENSITY endif # Useful paths @@ -32,13 +42,26 @@ BUILD_PATH = build LIBMAPLE_PATH := $(SRCROOT)/libmaple SUPPORT_PATH := $(SRCROOT)/support -# Useful variables -GLOBAL_CFLAGS := -Os -g3 -gdwarf-2 -mcpu=cortex-m3 -mthumb -march=armv7-m -nostdlib \ - -ffunction-sections -fdata-sections -Wl,--gc-sections \ - -DBOARD_$(BOARD) -DMCU_$(MCU) -GLOBAL_CXXFLAGS := -fno-rtti -fno-exceptions -Wall -DBOARD_$(BOARD) -DMCU_$(MCU) -GLOBAL_ASFLAGS := -mcpu=cortex-m3 -march=armv7-m -mthumb -DBOARD_$(BOARD) \ - -DMCU_$(MCU) -x assembler-with-cpp +# Compilation flags. +# FIXME remove the ERROR_LED config +GLOBAL_CFLAGS := -Os -g3 -gdwarf-2 -mcpu=cortex-m3 -mthumb -march=armv7-m \ + -nostdlib \ + -ffunction-sections -fdata-sections -Wl,--gc-sections \ + -DBOARD_$(BOARD) -DMCU_$(MCU) \ + -DERROR_LED_PORT=$(ERROR_LED_PORT) \ + -DERROR_LED_PIN=$(ERROR_LED_PIN) \ + -D$(DENSITY) +GLOBAL_CXXFLAGS := -fno-rtti -fno-exceptions -Wall \ + -DBOARD_$(BOARD) -DMCU_$(MCU) \ + -DERROR_LED_PORT=$(ERROR_LED_PORT) \ + -DERROR_LED_PIN=$(ERROR_LED_PIN) \ + -D$(DENSITY) +GLOBAL_ASFLAGS := -mcpu=cortex-m3 -march=armv7-m -mthumb \ + -x assembler-with-cpp \ + -DBOARD_$(BOARD) -DMCU_$(MCU) \ + -DERROR_LED_PORT=$(ERROR_LED_PORT) \ + -DERROR_LED_PIN=$(ERROR_LED_PIN) \ + -D$(DENSITY) LDDIR := $(SUPPORT_PATH)/ld LDFLAGS = -T$(LDDIR)/$(LDSCRIPT) -L$(LDDIR) \ diff --git a/docs/source/language.rst b/docs/source/language.rst index 2ebe03c..b2f4650 100644 --- a/docs/source/language.rst +++ b/docs/source/language.rst @@ -17,36 +17,6 @@ language and C++ may wish to skip to the .. contents:: Contents :local: -Unique Maple Additions ----------------------- - -.. _language-assert: - -``ASSERT(...)`` - The ``ASSERT()`` function can be very useful for basic program - debugging. The function accepts a boolean; for example:: - - ASSERT(state == WAIT); - - zero is false and any other number is true. If the boolean is true - the assertion passes and the program continues as usual. If it is - false, the assertion fails: the program is halted, debug - information is printed to USART2, and the status LED begins to - throb in intensity (it's noticeably different from blinking). The - debug information is printed at 9600 baud and consists of the - filename and line number where the particular assertion failed. - - Including assertions in a program increases the program size. When - using libmaple **from the command line only**, they can be - disabled by making the definition :: - - #define DEBUG_LEVEL DEBUG_NONE - - before including either wirish.h or libmaple.h. In this case, all - assertions will pass without any lost clock cycles. Note that - this will **not work in the IDE**; even with this definition, - assertions will still be enabled. - .. _language-lang-docs: Maple Language Reference @@ -217,6 +187,33 @@ A more exhaustive index is available at the :ref:`language-index`. | | | | +--------------------------------------------+----------------------------------------------+---------------------------------------------------+ +``ASSERT(...)`` +--------------- + +The ``ASSERT()`` function can be very useful for basic program +debugging. The function accepts a boolean; for example:: + + ASSERT(state == WAIT); + +Zero is false and any other number is true. If the boolean is true, the +assertion passes and the program continues as usual. If it is false, +the assertion fails: the program is halted, debug information is +printed to USART2, and the status LED begins to throb in intensity +(it's noticeably different from blinking). The debug information is +printed at 9600 baud and consists of the filename and line number +where the particular assertion failed. + +Including assertions in a program increases the program size. When +using libmaple **from the command line only**, they can be disabled by +making the definition :: + + #define DEBUG_LEVEL DEBUG_NONE + +before including either wirish.h or libmaple.h. In this case, all +assertions will pass without any lost clock cycles. Note that this +will **not work in the IDE**; even with this definition, assertions +will still be enabled. + .. _language-missing-features: Missing Arduino Features diff --git a/examples/test-bkp.cpp b/examples/test-bkp.cpp index 27f87bd..d0aa564 100644 --- a/examples/test-bkp.cpp +++ b/examples/test-bkp.cpp @@ -7,59 +7,61 @@ void print_bkp_contents(); void write_to_bkp(uint16 val); +#define comm Serial2 + void setup() { pinMode(BOARD_BUTTON_PIN, INPUT); - Serial2.begin(9600); - Serial2.println("*** Beginning BKP test"); + comm.begin(9600); + comm.println("*** Beginning BKP test"); - Serial2.println("Init..."); + comm.println("Init..."); bkp_init(); - Serial2.println("Done."); + comm.println("Done."); print_bkp_contents(); write_to_bkp(10); print_bkp_contents(); - Serial2.println("Enabling backup writes."); + comm.println("Enabling backup writes."); bkp_enable_writes(); write_to_bkp(20); print_bkp_contents(); - Serial2.println("Disabling backup writes."); + comm.println("Disabling backup writes."); bkp_disable_writes(); write_to_bkp(30); print_bkp_contents(); - Serial2.println("Done testing backup registers; press button to enable " + comm.println("Done testing backup registers; press button to enable " "independent watchdog (in order to cause a reset)."); waitForButtonPress(0); iwdg_init(IWDG_PRE_4, 1); - Serial2.println(); + comm.println(); } void loop() { } void print_bkp_contents() { - Serial2.println("Backup data register contents:"); + comm.println("Backup data register contents:"); char buf[100]; - for (int i = 1; i <= NR_BKP_REGS; i++) { + for (int i = 1; i <= BKP_NR_DATA_REGS; i++) { snprintf(buf, sizeof buf, "DR%d: %d ", i, bkp_read(i)); - Serial2.print(buf); - if (i % 5 == 0) Serial2.println(); + comm.print(buf); + if (i % 5 == 0) comm.println(); } - Serial2.println(); + comm.println(); } void write_to_bkp(uint16 val) { - Serial2.print("Attempting to write "); - Serial2.print(val); - Serial2.println(" to backup registers..."); - for (int i = 1; i <= NR_BKP_REGS; i++) { + comm.print("Attempting to write "); + comm.print(val); + comm.println(" to backup registers..."); + for (int i = 1; i <= BKP_NR_DATA_REGS; i++) { bkp_write(i, val); } - Serial2.println("Done."); + comm.println("Done."); } __attribute__((constructor)) void premain() { diff --git a/examples/test-session.cpp b/examples/test-session.cpp index 86bab6d..72d64d6 100644 --- a/examples/test-session.cpp +++ b/examples/test-session.cpp @@ -614,9 +614,8 @@ void init_all_timers(uint16 prescale) { timer_init(TIMER1, prescale); timer_init(TIMER2, prescale); timer_init(TIMER3, prescale); -#if NR_TIMERS >= 4 timer_init(TIMER4, prescale); -#elif NR_TIMERS >= 8 // TODO test this on maple native +#ifdef STM32_HIGH_DENSITY timer_init(TIMER5, prescale); timer_init(TIMER6, prescale); timer_init(TIMER7, prescale); diff --git a/libmaple/adc.c b/libmaple/adc.c index 17d63b8..cd71118 100644 --- a/libmaple/adc.c +++ b/libmaple/adc.c @@ -49,7 +49,7 @@ adc_dev adc2 = { }; const adc_dev *ADC2 = &adc2; -#if NR_ADCS >= 3 +#ifdef STM32_HIGH_DENSITY adc_dev adc3 = { .regs = ADC3_BASE, .clk_id = RCC_ADC3 diff --git a/libmaple/adc.h b/libmaple/adc.h index ab6e643..ac386fb 100644 --- a/libmaple/adc.h +++ b/libmaple/adc.h @@ -68,7 +68,7 @@ typedef struct adc_dev { extern const adc_dev *ADC1; extern const adc_dev *ADC2; -#if NR_ADCS >= 3 +#ifdef STM32_HIGH_DENSITY extern const adc_dev *ADC3; #endif @@ -190,7 +190,7 @@ static inline void adc_disable(const adc_dev *dev) { static inline void adc_disable_all(void) { adc_disable(ADC1); adc_disable(ADC2); -#if NR_ADCS >= 3 +#ifdef STM32_HIGH_DENSITY adc_disable(ADC3); #endif } diff --git a/libmaple/bkp.c b/libmaple/bkp.c index ac9aeae..ed107d8 100644 --- a/libmaple/bkp.c +++ b/libmaple/bkp.c @@ -69,7 +69,8 @@ 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). + * @param reg Data register to read, from 1 to BKP_NR_DATA_REGS (10 on + * medium-density devices, 42 on high-density devices). */ uint16 bkp_read(uint8 reg) { __io uint32* dr = data_register(reg); @@ -85,7 +86,8 @@ uint16 bkp_read(uint8 reg) { * * Write access to backup registers must be enabled. * - * @param reg Data register to write, from 1 to NR_BKP_REGS (10 on Maple). + * @param reg Data register to write, from 1 to BKP_NR_DATA_REGS (10 + * on medium-density devices, 42 on high-density devices). * @param val Value to write into the register. * @see bkp_enable_writes() */ @@ -101,16 +103,16 @@ void bkp_write(uint8 reg, uint16 val) { /* * Data register memory layout is not contiguous. It's split up from * 1--NR_LOW_DRS, beginning at BKP_BASE->DR1, through to - * (NR_LOW_DRS+1)--NR_BKP_REGS, beginning at BKP_BASE->DR10. + * (NR_LOW_DRS+1)--BKP_NR_DATA_REGS, beginning at BKP_BASE->DR11. */ #define NR_LOW_DRS 10 static inline __io uint32* data_register(uint8 reg) { - if (reg < 1 || reg > NR_BKP_REGS) { + if (reg < 1 || reg > BKP_NR_DATA_REGS) { return 0; } -#if NR_BKP_REGS == NR_LOW_DRS +#if BKP_NR_DATA_REGS == NR_LOW_DRS return (uint32*)BKP_BASE + reg; #else if (reg <= NR_LOW_DRS) { diff --git a/libmaple/bkp.h b/libmaple/bkp.h index ce8e6c7..96ef8d2 100644 --- a/libmaple/bkp.h +++ b/libmaple/bkp.h @@ -38,6 +38,12 @@ extern "C" { #endif +#if defined(STM32_MEDIUM_DENSITY) +#define BKP_NR_DATA_REGS 10 +#elif defined(STM32_HIGH_DENSITY) +#define BKP_NR_DATA_REGS 42 +#endif + typedef struct bkp_reg_map { const uint32 RESERVED1; __io uint32 DR1; ///< Data register 1 @@ -53,7 +59,7 @@ typedef struct bkp_reg_map { __io uint32 RTCCR; ///< RTC control register __io uint32 CR; ///< Control register __io uint32 CSR; ///< Control and status register -#if NR_BKP_REGS > 10 +#ifdef STM32_HIGH_DENSITY const uint32 RESERVED2; const uint32 RESERVED3; __io uint32 DR11; ///< Data register 11 diff --git a/libmaple/libmaple.h b/libmaple/libmaple.h index 4f9a71a..6b75c96 100644 --- a/libmaple/libmaple.h +++ b/libmaple/libmaple.h @@ -24,164 +24,50 @@ /** * @file libmaple.h - * - * @brief general include file for libmaple + * @brief General include file for libmaple */ #ifndef _LIBMAPLE_H_ #define _LIBMAPLE_H_ #include "libmaple_types.h" +#include "util.h" -/* General configuration */ -#define DEBUG_NONE 0 -#define DEBUG_FAULT 1 -#define DEBUG_ALL 2 - -#ifndef DEBUG_LEVEL -#define DEBUG_LEVEL DEBUG_ALL -#endif +/* + * Where to put usercode, based on space reserved for bootloader. + * + * FIXME this has no business being here + */ +#define USER_ADDR_ROM 0x08005000 +#define USER_ADDR_RAM 0x20000C00 +#define STACK_TOP 0x20000800 /* MCU-specific configuration */ #if defined(MCU_STM32F103RB) /* e.g., LeafLabs Maple */ /* Number of GPIO ports (GPIOA, GPIOB, etc.) */ - #define NR_GPIO_PORTS 4 - - /* Total number of GPIO pins */ - #define NR_GPIO_PINS 39 - - /* Number of 16-bit backup registers */ - #define NR_BKP_REGS 10 - - /* Number of timer devices ports, definitely used */ - #define NR_TIMERS 4 - - /* Number of USART ports */ - #define NR_USART 3 - - /* Number of ADCs */ - #define NR_ADCS 2 - - /* Has an FSMC bus? */ - #define NR_FSMC 0 - - /* Has a DAC? */ - #define NR_DAC_PINS 0 - - /* USB Identifier numbers */ - /* Descriptor strings must be modified by hand in - usb/descriptors.c for now */ - #define VCOM_ID_VENDOR 0x1EAF - #define VCOM_ID_PRODUCT 0x0004 - #define USB_DISC_BANK GPIOC_BASE - #define USB_DISC_PIN 12 - #define USB_CONFIG_MAX_POWER (100 >> 1) - #define RESET_DELAY (100) - - /* Where to put usercode (based on space reserved for bootloader) */ - #define USER_ADDR_ROM 0x08005000 - #define USER_ADDR_RAM 0x20000C00 - #define STACK_TOP 0x20000800 - - /* Debug port settings (from ASSERT) */ - #define ERROR_LED_PORT GPIOB_BASE - #define ERROR_LED_PIN 12 - #define ERROR_USART_NUM USART2 - #define ERROR_USART_BAUD 9600 - #define ERROR_TX_PORT GPIOA_BASE - #define ERROR_TX_PIN 2 - - /* Just in case, most boards have at least some memory */ - #ifndef RAMSIZE - # define RAMSIZE (caddr_t)0x50000 - #endif - - /* Bitbanded Memory sections */ - #define BITBAND_SRAM_REF 0x20000000 - #define BITBAND_SRAM_BASE 0x22000000 - #define BITBAND_PERI_REF 0x40000000 - #define BITBAND_PERI_BASE 0x42000000 + #define NR_GPIO_PORTS 4 + + /* SRAM size, in bytes */ + #define SRAM_SIZE 0x5000 #elif defined(MCU_STM32F103ZE) /* e.g., LeafLabs Maple Native */ - #define NR_GPIO_PORTS 7 - #define NR_GPIO_PINS 100 - #define NR_BKP_REGS 42 /* TODO test on Native */ - #define NR_TIMERS 8 - #define NR_USART 5 /* NB: 4 and 5 are UART only */ - #define NR_ADCS 3 - #define NR_FSMC 1 - #define NR_DAC_PINS 2 - - #define VCOM_ID_VENDOR 0x1EAF - #define VCOM_ID_PRODUCT 0x0004 - #define USB_DISC_BANK GPIOB_BASE - #define USB_DISC_PIN 8 - #define USB_CONFIG_MAX_POWER (100 >> 1) - #define RESET_DELAY (100) - - #define USER_ADDR_ROM 0x08005000 - #define USER_ADDR_RAM 0x20000C00 - #define STACK_TOP 0x20000800 - - #define ERROR_LED_PORT GPIOC_BASE - #define ERROR_LED_PIN 15 - #define ERROR_USART_NUM USART1 - #define ERROR_USART_BAUD 9600 - #define ERROR_TX_PORT GPIOA_BASE - #define ERROR_TX_PIN 10 - - #ifndef RAMSIZE - # define RAMSIZE (caddr_t)0x50000 - #endif - - #define BITBAND_SRAM_REF 0x20000000 - #define BITBAND_SRAM_BASE 0x22000000 - #define BITBAND_PERI_REF 0x40000000 - #define BITBAND_PERI_BASE 0x42000000 + #define NR_GPIO_PORTS 7 + + #define SRAM_SIZE 0x10000 #elif defined(MCU_STM32F103CB) /* e.g., LeafLabs Maple Mini */ - #define NR_GPIO_PORTS 3 - #define NR_GPIO_PINS 34 - #define NR_BKP_REGS 10 /* TODO test on Mini */ - #define NR_TIMERS 4 - #define NR_USART 3 - #define NR_ADCS 2 - #define NR_FSMC 0 - #define NR_DAC_PINS 0 - - #define VCOM_ID_VENDOR 0x1EAF - #define VCOM_ID_PRODUCT 0x0005 - #define USB_DISC_BANK GPIOB_BASE - #define USB_DISC_PIN 9 - #define USB_CONFIG_MAX_POWER (100 >> 1) - #define RESET_DELAY 100 - - #define USER_ADDR_ROM 0x08005000 - #define USER_ADDR_RAM 0x20000C00 - #define STACK_TOP 0x20000800 - - #define ERROR_LED_PORT GPIOB_BASE - #define ERROR_LED_PIN 12 - #define ERROR_USART_NUM USART2 - #define ERROR_USART_BAUD 9600 - #define ERROR_TX_PORT GPIOA_BASE - #define ERROR_TX_PIN 2 - - #ifndef RAMSIZE - # define RAMSIZE (caddr_t)0x50000 - #endif - - /* Bitbanded Memory sections */ - #define BITBAND_SRAM_REF 0x20000000 - #define BITBAND_SRAM_BASE 0x22000000 - #define BITBAND_PERI_REF 0x40000000 - #define BITBAND_PERI_BASE 0x42000000 + /* Note that this is not, strictly speaking, true. But only pins + 0 and 1 exist, and they're used for OSC on the Mini, so we'll + live with this for now. */ + #define NR_GPIO_PORTS 3 + + #define SRAM_SIZE 0x5000 #else @@ -190,8 +76,5 @@ #endif -/* Requires board configuration info */ -#include "util.h" - #endif diff --git a/libmaple/libmaple_types.h b/libmaple/libmaple_types.h index 8d216a8..a976a9e 100644 --- a/libmaple/libmaple_types.h +++ b/libmaple/libmaple_types.h @@ -45,8 +45,6 @@ typedef void (*voidFuncPtr)(void); #define __io volatile -#define ALWAYS_INLINE inline __attribute__((always_inline)) - #ifndef NULL #define NULL 0 #endif diff --git a/libmaple/timers.c b/libmaple/timers.c index 29aeeba..ff548c0 100644 --- a/libmaple/timers.c +++ b/libmaple/timers.c @@ -55,7 +55,7 @@ struct timer_dev timer_dev_table[] = { .rcc_dev_num = RCC_TIMER4, .nvic_dev_num = NVIC_TIMER4 }, -#if NR_TIMERS >= 8 +#ifdef STM32_HIGH_DENSITY /* High density devices only (eg, Maple Native) */ [TIMER5] = { .base = (timer_port*)TIMER5_BASE, @@ -82,7 +82,7 @@ void timer_init(timer_dev_num timer_num, uint16 prescale) { if (timer_num == TIMER1) { is_advanced = 1; } -#if NR_TIMERS >= 8 +#ifdef STM32_HIGH_DENSITY if (timer_num == TIMER8) { is_advanced = 1; } @@ -193,12 +193,8 @@ void timer_set_reload(timer_dev_num timer_num, uint16 max_reload) { * or similar to prevent interrupts and PWM output without 16 seperate function * calls to timer_set_mode */ void timer_disable_all(void) { - // TODO: refactor - - /* Note: this must be very robust because it gets called from, - e.g., ASSERT */ timer_port *timer; -#if NR_TIMERS >= 8 +#ifdef STM32_HIGH_DENSITY timer_port *timers[6] = { (timer_port*)TIMER1_BASE, (timer_port*)TIMER2_BASE, (timer_port*)TIMER3_BASE, diff --git a/libmaple/timers.h b/libmaple/timers.h index 99bcab6..1f6afcd 100644 --- a/libmaple/timers.h +++ b/libmaple/timers.h @@ -206,7 +206,7 @@ typedef enum { TIMER2, /*< General purpose timer TIM2 */ TIMER3, /*< General purpose timer TIM3 */ TIMER4, /*< General purpose timer TIM4 */ -#if NR_TIMERS >= 8 +#ifdef STM32_HIGH_DENSITY TIMER5, /*< General purpose timer TIM5; high density only */ /* FIXME maple native: put timers 6 and 7 back in and make the corresponding changes to timers.c */ @@ -412,8 +412,8 @@ void timer_generate_update(timer_dev_num timer_num); /** * Turn on PWM with duty_cycle. * - * @param ccr TIMERx_CHn_CCR, where x goes from 1 to NR_TIMERS, - * and n goes from 1 to 4. + * @param ccr TIMERx_CHn_CCR, where x ranges over timers, and n ranges + * from 1 to 4. * * @param duty_cycle: A number between 0 and * timer_get_compare_value(TIMERx, y), where x and y are as above. diff --git a/libmaple/usart.c b/libmaple/usart.c index 44a5c92..030d3cc 100644 --- a/libmaple/usart.c +++ b/libmaple/usart.c @@ -61,7 +61,7 @@ struct usart_dev usart_dev_table[] = { .rcc_dev_num = RCC_USART3, .nvic_dev_num = NVIC_USART3 }, -#if NR_USART >= 5 +#ifdef STM32_HIGH_DENSITY /* TODO test */ [UART4] = { .base = (usart_port*)UART4_BASE, @@ -107,7 +107,7 @@ void USART3_IRQHandler(void) { usart_irq(USART3); } -#if NR_USART >= 5 +#ifdef STM32_HIGH_DENSITY void UART4_IRQHandler(void) { usart_irq(UART4); } @@ -124,7 +124,11 @@ void UART5_IRQHandler(void) { * @param baud Baud rate to be set at */ void usart_init(uint8 usart_num, uint32 baud) { - ASSERT(usart_num <= NR_USART); +#ifdef STM32_HIGH_DENSITY + ASSERT(usart_num <= UART5); +#else + ASSERT(usart_num <= USART3); +#endif usart_port *port; ring_buffer *ring_buf; @@ -170,7 +174,7 @@ void usart_disable_all() { usart_disable(USART1); usart_disable(USART2); usart_disable(USART3); -#if NR_USART >= 5 +#ifdef STM32_HIGH_DENSITY usart_disable(UART4); usart_disable(UART5); #endif diff --git a/libmaple/usart.h b/libmaple/usart.h index 0ca3f55..90b3415 100644 --- a/libmaple/usart.h +++ b/libmaple/usart.h @@ -43,8 +43,10 @@ enum { USART1, USART2, USART3, +#ifdef STM32_HIGH_DENSITY UART4, UART5, +#endif }; /* peripheral register struct */ diff --git a/libmaple/usb/descriptors.c b/libmaple/usb/descriptors.c index 360e6dd..8dd9521 100644 --- a/libmaple/usb/descriptors.c +++ b/libmaple/usb/descriptors.c @@ -150,43 +150,50 @@ const USB_Descriptor_Config usbVcomDescriptor_Config = { // } }; -/* - String Identifiers: +/***************************************************************************** + ***************************************************************************** + *** + *** FIXME FIXME FIXME NOT THE RIGHT THING! MOVE ALL THIS INTO TO WIRISH! + *** + ***************************************************************************** + *****************************************************************************/ - we may choose to specify any or none of the following string - identifiers: +const uint8 usbVcomDescriptor_LangID[USB_DESCRIPTOR_STRING_LEN(1)] = { + USB_DESCRIPTOR_STRING_LEN(1), + USB_DESCRIPTOR_TYPE_STRING, + 0x09, + 0x04 +}; - iManufacturer: LeafLabs - iProduct: Maple R3 - iSerialNumber: NONE - iConfiguration: NONE - iInterface(CCI): NONE - iInterface(DCI): NONE +const uint8 usbVcomDescriptor_iManufacturer[USB_DESCRIPTOR_STRING_LEN(8)] = { + USB_DESCRIPTOR_STRING_LEN(8), + USB_DESCRIPTOR_TYPE_STRING, + 'L', 0, 'e', 0, 'a', 0, 'f', 0, + 'L', 0, 'a', 0, 'b', 0, 's', 0 +}; - additionally we must provide the unicode language identifier, - which is 0x0409 for US English -*/ +/* + String Identifiers: -const uint8 usbVcomDescriptor_LangID[USB_DESCRIPTOR_STRING_LEN(1)] = -{ - USB_DESCRIPTOR_STRING_LEN(1), - USB_DESCRIPTOR_TYPE_STRING, - 0x09, - 0x04 -}; + we may choose to specify any or none of the following string + identifiers: -const uint8 usbVcomDescriptor_iManufacturer[USB_DESCRIPTOR_STRING_LEN(8)] = -{ - USB_DESCRIPTOR_STRING_LEN(8), - USB_DESCRIPTOR_TYPE_STRING, - 'L', 0, 'e', 0, 'a', 0, 'f', 0, - 'L', 0, 'a', 0, 'b', 0, 's', 0 -}; + iManufacturer: LeafLabs + iProduct: Maple R3 + iSerialNumber: NONE + iConfiguration: NONE + iInterface(CCI): NONE + iInterface(DCI): NONE -const uint8 usbVcomDescriptor_iProduct[USB_DESCRIPTOR_STRING_LEN(8)] = -{ - USB_DESCRIPTOR_STRING_LEN(8), - USB_DESCRIPTOR_TYPE_STRING, - 'M', 0, 'a', 0, 'p', 0, 'l', 0, - 'e', 0, ' ', 0, 'R', 0, '3', 0 + additionally we must provide the unicode language identifier, + which is 0x0409 for US English +*/ +const uint8 usbVcomDescriptor_iProduct[USB_DESCRIPTOR_STRING_LEN(8)] = { + USB_DESCRIPTOR_STRING_LEN(8), + USB_DESCRIPTOR_TYPE_STRING, + 'M', 0, 'a', 0, 'p', 0, 'l', 0, + 'e', 0, ' ', 0, ' ', 0, ' ', 0 }; + +/***************************************************************************** + *****************************************************************************/ diff --git a/libmaple/usb/usb_config.h b/libmaple/usb/usb_config.h index e5f3979..394c580 100644 --- a/libmaple/usb/usb_config.h +++ b/libmaple/usb/usb_config.h @@ -5,6 +5,67 @@ #include "usb_lib.h" +/****************************************************************************** + ****************************************************************************** + *** + *** HACK ALERT + *** + *** FIXME FIXME FIXME FIXME + *** + *** A bunch of board-specific #defines that are only used by the + *** USB routines got put into libmaple.h for what appear to be + *** historical reasons. I'm [mbolivar] putting them in here for + *** now, so that we can treat the usb/ directory as a black box, + *** freeing the rest of libmaple/ to be implemented as a + *** general-purpose STM32 library. All of this REALLY needs to get + *** moved into wirish when we get a chance to redo the USB stack. + *** + ****************************************************************************** + *****************************************************************************/ + +#define VCOM_ID_VENDOR 0x1EAF +#define RESET_DELAY (100) +#define USB_CONFIG_MAX_POWER (100 >> 1) + +#if defined(BOARD_maple) + + /* USB Identifier numbers */ + #define VCOM_ID_PRODUCT 0x0004 + #define USB_DISC_BANK GPIOC_BASE + #define USB_DISC_PIN 12 + +#elif defined(BOARD_maple_mini) + + #define VCOM_ID_PRODUCT 0x0005 + #define USB_DISC_BANK GPIOB_BASE + #define USB_DISC_PIN 9 + +#elif defined(BOARD_maple_native) + + #define VCOM_ID_PRODUCT 0x0006 + #define USB_DISC_BANK GPIOB_BASE + #define USB_DISC_PIN 8 + +#else + +#error ("Sorry! the USB stack relies on LeafLabs board-specific " \ + "configuration right now. If you want, you can pretend you're one " \ + "of our boards; i.e., #define BOARD_maple, BOARD_maple_mini, or " \ + "BOARD_maple_native according to what matches your MCU best. " \ + "You should also take a look at libmaple/usb/descriptors.c; we make " \ + "some assumptions there that you probably won't like.") + +#endif + +/****************************************************************************** + ****************************************************************************** + *** + *** END HACK + *** + ****************************************************************************** + *****************************************************************************/ + + /* choose addresses to give endpoints the max 64 byte buffers */ #define USB_BTABLE_ADDRESS 0x00 #define VCOM_CTRL_EPNUM 0x00 @@ -33,14 +94,15 @@ #define NUM_ENDPTS 0x04 /* handle all usb interrupts */ -#define ISR_MSK ( CNTR_CTRM | \ - CNTR_WKUPM | \ - CNTR_SUSPM | \ - CNTR_ERRM | \ - CNTR_SOFM | \ - CNTR_ESOFM | \ - CNTR_RESETM ) +#define ISR_MSK (CNTR_CTRM | \ + CNTR_WKUPM | \ + CNTR_SUSPM | \ + CNTR_ERRM | \ + CNTR_SOFM | \ + CNTR_ESOFM | \ + CNTR_RESETM) #define F_SUSPEND_ENABLED 1 + #endif diff --git a/libmaple/util.c b/libmaple/util.c index 11f9b34..481cd60 100644 --- a/libmaple/util.c +++ b/libmaple/util.c @@ -34,6 +34,21 @@ #include "adc.h" #include "timers.h" +/* Failed asserts send out a message on this USART. */ +#ifndef ERROR_USART_NUM +#define ERROR_USART_NUM USART2 +#define ERROR_USART_BAUD 9600 +#define ERROR_TX_PORT GPIOA_BASE +#define ERROR_TX_PIN 2 +#endif + +/* If you define ERROR_LED_PORT and ERROR_LED_PIN, then a failed + assert will also throb an LED connected to that port an pin. + FIXME this should work together with wirish somehow. */ +#if defined(ERROR_LED_PORT) && defined(ERROR_LED_PIN) +#define HAVE_ERROR_LED +#endif + /* Error assert + fade */ void _fail(const char* file, int line, const char* exp) { int32 slope = 1; @@ -67,8 +82,10 @@ void _fail(const char* file, int line, const char* exp) { usart_putc(ERROR_USART_NUM, '\n'); usart_putc(ERROR_USART_NUM, '\r'); +#ifdef HAVE_ERROR_LED /* Turn on the error LED */ gpio_set_mode(ERROR_LED_PORT, ERROR_LED_PIN, GPIO_MODE_OUTPUT_PP); +#endif /* Turn the USB interrupt back on so the bootloader keeps on functioning */ nvic_irq_enable(NVIC_INT_USBHP); @@ -79,6 +96,7 @@ void _fail(const char* file, int line, const char* exp) { } void throb(void) { +#ifdef HAVE_ERROR_LED int32 slope = 1; uint32 CC = 0x0000; uint32 TOP_CNT = 0x0200; @@ -105,5 +123,10 @@ void throb(void) { } i++; } +#else + /* No error LED is connected; do nothing. */ + while (1) + ; +#endif } diff --git a/libmaple/util.h b/libmaple/util.h index 63427cc..28ce970 100644 --- a/libmaple/util.h +++ b/libmaple/util.h @@ -32,7 +32,18 @@ #ifndef _UTIL_H_ #define _UTIL_H_ -#include "libmaple.h" +#ifdef __cplusplus +extern "C"{ +#endif + +/* Debug configuration */ +#define DEBUG_NONE 0 +#define DEBUG_FAULT 1 +#define DEBUG_ALL 2 + +#ifndef DEBUG_LEVEL +#define DEBUG_LEVEL DEBUG_ALL +#endif #define BIT(shift) (1UL << (shift)) #define BIT_MASK_SHIFT(mask, shift) ((mask) << (shift)) @@ -41,9 +52,14 @@ #define GET_BITS(x, m, n) ((((uint32)x) << (31 - (n))) >> ((31 - (n)) + (m))) /* Bit-banding macros */ +/* Bitbanded Memory sections */ +#define BITBAND_SRAM_REF 0x20000000 +#define BITBAND_SRAM_BASE 0x22000000 +#define BITBAND_PERI_REF 0x40000000 +#define BITBAND_PERI_BASE 0x42000000 /* Convert SRAM address */ #define BITBAND_SRAM(a,b) ((BITBAND_SRAM_BASE+(a-BITBAND_SRAM_REF)*32+(b*4))) -/* Convert PERI address */ +/* Convert peripheral address */ #define BITBAND_PERI(a, b) ((BITBAND_PERI_BASE + \ ((uint32)a - BITBAND_PERI_REF) * 32 + (b * 4))) @@ -63,18 +79,9 @@ #define __write(reg, value) (*(volatile uint32*)(reg) = (value)) #define IS_POWER_OF_TWO(v) (v && !(v & (v - 1))) - -#ifdef __cplusplus -extern "C"{ -#endif - void _fail(const char*, int, const char*); void throb(void); -#ifdef __cplusplus -} // extern "C" -#endif - /* Asserts for sanity checks, redefine DEBUG_LEVEL in libmaple.h to * compile out these checks */ @@ -100,5 +107,9 @@ void throb(void); #define ASSERT_FAULT(exp) (void)((0)) #endif +#ifdef __cplusplus +} // extern "C" +#endif + #endif diff --git a/wirish/HardwareTimer.cpp b/wirish/HardwareTimer.cpp index 354663e..0f8bec6 100644 --- a/wirish/HardwareTimer.cpp +++ b/wirish/HardwareTimer.cpp @@ -199,7 +199,7 @@ HardwareTimer Timer1(TIMER1); HardwareTimer Timer2(TIMER2); HardwareTimer Timer3(TIMER3); HardwareTimer Timer4(TIMER4); -#if NR_TIMERS >= 8 +#ifdef STM32_HIGH_DENSITY HardwareTimer Timer5(TIMER5); // High-density devices only HardwareTimer Timer8(TIMER8); // High-density devices only #endif @@ -214,7 +214,7 @@ HardwareTimer* getTimer(timer_dev_num timerNum) { return &Timer3; case TIMER4: return &Timer4; -#if NR_TIMERS >= 8 +#ifdef STM32_HIGH_DENSITY case TIMER5: return &Timer5; case TIMER8: diff --git a/wirish/HardwareTimer.h b/wirish/HardwareTimer.h index 4034b1f..4030adc 100644 --- a/wirish/HardwareTimer.h +++ b/wirish/HardwareTimer.h @@ -382,7 +382,7 @@ extern HardwareTimer Timer2; extern HardwareTimer Timer3; /** Pre-instantiated timer for use by user code. */ extern HardwareTimer Timer4; -#if NR_TIMERS >= 8 +#ifdef STM32_HIGH_DENSITY /** Pre-instantiated timer for use by user code, on devices with more than four timers (this does not include the Maple). */ extern HardwareTimer Timer5; diff --git a/wirish/boards.h b/wirish/boards.h index ac3a74d..989eea1 100644 --- a/wirish/boards.h +++ b/wirish/boards.h @@ -70,8 +70,12 @@ typedef struct PinMapping { #define CYCLES_PER_MICROSECOND 72 #define SYSTICK_RELOAD_VAL 71999 /* takes a cycle to reload */ - #define BOARD_BUTTON_PIN 38 - #define BOARD_LED_PIN 13 + #define BOARD_BUTTON_PIN 38 + #define BOARD_LED_PIN 13 + + /* Total number of GPIO pins that are broken out to headers and + intended for general use. */ + #define NR_GPIO_PINS 39 static __attribute__ ((unused)) PinMapping PIN_MAP[NR_GPIO_PINS] = { /* D0/PA3 */ @@ -173,6 +177,8 @@ typedef struct PinMapping { #define BOARD_LED_PIN D21 #define BOARD_BUTTON_PIN D18 + #define NR_GPIO_PINS 100 + static __attribute__ ((unused)) PinMapping PIN_MAP[NR_GPIO_PINS] = { /* Top header */ @@ -390,11 +396,13 @@ typedef struct PinMapping { #elif defined(BOARD_maple_mini) - #define CYCLES_PER_MICROSECOND 72 + #define CYCLES_PER_MICROSECOND 72 #define SYSTICK_RELOAD_VAL 71999 /* takes a cycle to reload */ - #define BOARD_BUTTON_PIN 32 - #define BOARD_LED_PIN 33 + #define BOARD_BUTTON_PIN 32 + #define BOARD_LED_PIN 33 + + #define NR_GPIO_PINS 34 static __attribute__ ((unused)) PinMapping PIN_MAP[NR_GPIO_PINS] = { /* D0/PB11 */ diff --git a/wirish/ext_interrupts.h b/wirish/ext_interrupts.h index 304e267..4e22c71 100644 --- a/wirish/ext_interrupts.h +++ b/wirish/ext_interrupts.h @@ -86,7 +86,7 @@ void detachInterrupt(uint8 pin); * * @see noInterrupts() */ -static ALWAYS_INLINE void interrupts() { +static inline void interrupts() { nvic_globalirq_enable(); } @@ -100,7 +100,7 @@ static ALWAYS_INLINE void interrupts() { * * @see interrupts() */ -static ALWAYS_INLINE void noInterrupts() { +static inline void noInterrupts() { nvic_globalirq_disable(); } diff --git a/wirish/wirish.c b/wirish/wirish.c index c5dec22..4c84d26 100644 --- a/wirish/wirish.c +++ b/wirish/wirish.c @@ -47,7 +47,7 @@ void init(void) { flash_enable_prefetch(); flash_set_latency(FLASH_WAIT_STATE_2); -#if NR_FSMC > 0 +#ifdef STM32_HIGH_DENSITY fsmc_native_sram_init(); #endif @@ -70,7 +70,7 @@ void init(void) { timer_init(TIMER2, 1); timer_init(TIMER3, 1); timer_init(TIMER4, 1); -#if NR_TIMERS >= 8 +#ifdef STM32_HIGH_DENSITY timer_init(TIMER5, 1); timer_init(TIMER8, 1); #endif -- cgit v1.2.3 From 43c5092d944ee1aa1424f2743c31bf33cb860c27 Mon Sep 17 00:00:00 2001 From: Perry Hung Date: Sun, 27 Feb 2011 14:53:53 -0500 Subject: Generate map file --- build-targets.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-targets.mk b/build-targets.mk index 0718b15..207d324 100644 --- a/build-targets.mk +++ b/build-targets.mk @@ -11,7 +11,7 @@ library: $(BUILD_PATH)/libmaple.a .PHONY: library $(BUILD_PATH)/$(BOARD).elf: $(BUILDDIRS) $(TGT_BIN) $(BUILD_PATH)/main.o - $(SILENT_LD) $(CXX) $(LDFLAGS) -o $@ $(TGT_BIN) $(BUILD_PATH)/main.o + $(SILENT_LD) $(CXX) $(LDFLAGS) -o $@ $(TGT_BIN) $(BUILD_PATH)/main.o -Wl,-Map,$(BUILD_PATH)/$(BOARD).map $(BUILD_PATH)/$(BOARD).bin: $(BUILD_PATH)/$(BOARD).elf $(SILENT_OBJCOPY) $(OBJCOPY) -v -Obinary $(BUILD_PATH)/$(BOARD).elf $@ 1>/dev/null -- cgit v1.2.3 From 214941537f2211d5e2ef16e34440485d7e872d1a Mon Sep 17 00:00:00 2001 From: Perry Hung Date: Sun, 27 Feb 2011 15:49:51 -0500 Subject: Refactor linker scripts. Rename irq and exception handlers. Add common linker scripts for ram and rom. Add medium and high density libraries for libcs3. --- libmaple/dma.c | 14 +- libmaple/exc.S | 44 ++++- libmaple/exti.c | 14 +- libmaple/systick.c | 2 +- libmaple/timers.c | 8 +- libmaple/usart.c | 10 +- libmaple/usb/usb.c | 2 +- libmaple/usb/usb.h | 2 +- support/ld/common_ram.inc | 221 +++++++++++++++++++++ support/ld/common_rom.inc | 223 +++++++++++++++++++++ support/ld/libcs3-lanchon-stm32.a | Bin 10134 -> 0 bytes support/ld/libcs3-lanchon-stm32.tar.gz | Bin 2775 -> 0 bytes support/ld/libcs3_stm32_high_density.a | Bin 0 -> 9464 bytes support/ld/libcs3_stm32_med_density.a | Bin 0 -> 9464 bytes support/ld/libcs3_stm32_src/Makefile | 35 ++++ support/ld/libcs3_stm32_src/start.S | 27 +++ support/ld/libcs3_stm32_src/start_c.c | 58 ++++++ support/ld/libcs3_stm32_src/stm32_isrs.S | 235 +++++++++++++++++++++++ support/ld/libcs3_stm32_src/stm32_vector_table.S | 90 +++++++++ support/ld/maple/flash.ld | 219 ++------------------- support/ld/maple/jtag.ld | 192 ++---------------- support/ld/maple/ram.ld | 227 ++-------------------- support/ld/maple_mini/flash.ld | 218 ++------------------- support/ld/maple_mini/jtag.ld | 192 ++---------------- support/ld/maple_mini/ram.ld | 227 ++-------------------- support/ld/maple_native/flash.ld | 211 ++------------------ support/ld/maple_native/jtag.ld | 187 ++---------------- support/ld/maple_native/ram.ld | 220 ++------------------- support/ld/names.inc | 137 +++++++------ support/ld/src.zip | Bin 15774 -> 0 bytes 30 files changed, 1163 insertions(+), 1852 deletions(-) create mode 100644 support/ld/common_ram.inc create mode 100644 support/ld/common_rom.inc delete mode 100644 support/ld/libcs3-lanchon-stm32.a delete mode 100644 support/ld/libcs3-lanchon-stm32.tar.gz create mode 100644 support/ld/libcs3_stm32_high_density.a create mode 100644 support/ld/libcs3_stm32_med_density.a create mode 100644 support/ld/libcs3_stm32_src/Makefile create mode 100644 support/ld/libcs3_stm32_src/start.S create mode 100644 support/ld/libcs3_stm32_src/start_c.c create mode 100644 support/ld/libcs3_stm32_src/stm32_isrs.S create mode 100644 support/ld/libcs3_stm32_src/stm32_vector_table.S delete mode 100644 support/ld/src.zip diff --git a/libmaple/dma.c b/libmaple/dma.c index 15c96e1..c71e52c 100644 --- a/libmaple/dma.c +++ b/libmaple/dma.c @@ -77,31 +77,31 @@ static inline void dispatch_handler(uint8 channel_idx) { } } -void DMAChannel1_IRQHandler(void) { +void __irq_dma1_channel1(void) { dispatch_handler(0); } -void DMAChannel2_IRQHandler(void) { +void __irq_dma1_channel2(void) { dispatch_handler(1); } -void DMAChannel3_IRQHandler(void) { +void __irq_dma2_channel3(void) { dispatch_handler(2); } -void DMAChannel4_IRQHandler(void) { +void __irq_dma2_channel4(void) { dispatch_handler(3); } -void DMAChannel5_IRQHandler(void) { +void __irq_dma2_channel5(void) { dispatch_handler(4); } -void DMAChannel6_IRQHandler(void) { +void __irq_dma2_channel6(void) { dispatch_handler(5); } -void DMAChannel7_IRQHandler(void) { +void __irq_dma2_channel7(void) { dispatch_handler(6); } diff --git a/libmaple/exc.S b/libmaple/exc.S index a9f6561..d01e3d5 100644 --- a/libmaple/exc.S +++ b/libmaple/exc.S @@ -41,16 +41,42 @@ # SP--> r0 .text -.globl HardFaultException +.globl __exc_hardfault +.globl __exc_nmi +.globl __exc_hardfault +.globl __exc_memmanage +.globl __exc_busfault +.globl __exc_usagefault + +/* TODO: Fix this up. */ +.thumb_func +__exc_nmi: + mov r0, #1 + +.thumb_func +__exc_hardfault: + mov r0, #2 + .thumb_func -HardFaultException: - ldr r0, CPSR_MASK @ Set default CPSR - push {r0} - ldr r0, TARGET_PC @ Set target pc - push {r0} - sub sp, sp, #24 @ its not like i even care - ldr r0, EXC_RETURN @ Return to thread mode - mov lr, r0 +__exc_memmanage: + mov r0, #3 + +.thumb_func +__exc_busfault: + mov r0, #4 + +.thumb_func +__exc_usagefault: + mov r0, #5 + +__default: + ldr r1, CPSR_MASK @ Set default CPSR + push {r1} + ldr r1, TARGET_PC @ Set target pc + push {r1} + sub sp, sp, #24 @ Don't care + ldr r1, EXC_RETURN @ Return to thread mode + mov lr, r1 bx lr @ Exception exit .align 4 diff --git a/libmaple/exti.c b/libmaple/exti.c index 150dd05..e8ad52a 100644 --- a/libmaple/exti.c +++ b/libmaple/exti.c @@ -74,32 +74,32 @@ static inline void dispatch_handler(uint32 channel) { * is associated with each channel, so we * don't have to keep track of which channel * we came from */ -void EXTI0_IRQHandler(void) { +void __irq_exti0(void) { dispatch_handler(EXTI0); clear_pending(EXTI0); } -void EXTI1_IRQHandler(void) { +void __irq_exti1(void) { dispatch_handler(EXTI1); clear_pending(EXTI1); } -void EXTI2_IRQHandler(void) { +void __irq_exti2(void) { dispatch_handler(EXTI2); clear_pending(EXTI2); } -void EXTI3_IRQHandler(void) { +void __irq_exti3(void) { dispatch_handler(EXTI3); clear_pending(EXTI3); } -void EXTI4_IRQHandler(void) { +void __irq_exti4(void) { dispatch_handler(EXTI4); clear_pending(EXTI4); } -void EXTI9_5_IRQHandler(void) { +void __irq_exti9_5(void) { /* Figure out which channel it came from */ uint32 pending; uint32 i; @@ -116,7 +116,7 @@ void EXTI9_5_IRQHandler(void) { } } -void EXTI15_10_IRQHandler(void) { +void __irq_exti15_10(void) { /* Figure out which channel it came from */ uint32 pending; uint32 i; diff --git a/libmaple/systick.c b/libmaple/systick.c index b056001..b9a52c1 100644 --- a/libmaple/systick.c +++ b/libmaple/systick.c @@ -64,6 +64,6 @@ void systick_resume() { } /** SysTick interrupt handler. Bumps up the tick counter. */ -void SysTickHandler(void) { +void __exc_systick(void) { systick_timer_millis++; } diff --git a/libmaple/timers.c b/libmaple/timers.c index ff548c0..c561d39 100644 --- a/libmaple/timers.c +++ b/libmaple/timers.c @@ -382,7 +382,7 @@ void timer_generate_update(timer_dev_num timer_num) { * registers /or/ has overflowed. * * This is a rather long implementation... */ -void TIM1_CC_IRQHandler(void) { +void __irq_tim1_cc(void) { timer_port *timer = (timer_port*)TIMER1_BASE; uint16 sr_buffer; sr_buffer = timer->SR; @@ -418,7 +418,7 @@ void TIM1_CC_IRQHandler(void) { //timer->EGR = 1; } } -void TIM2_IRQHandler(void) { +void __irq_tim2(void) { /* This is a rather long implementation... */ timer_port *timer = (timer_port*)TIMER2_BASE; uint16 sr_buffer; @@ -453,7 +453,7 @@ void TIM2_IRQHandler(void) { //timer->EGR = 1; } } -void TIM3_IRQHandler(void) { +void __irq_tim3(void) { /* This is a rather long implementation... */ timer_port *timer = (timer_port*)TIMER3_BASE; uint16 sr_buffer; @@ -489,7 +489,7 @@ void TIM3_IRQHandler(void) { } } -void TIM4_IRQHandler(void) { +void __irq_tim4(void) { /* This is a rather long implementation... */ timer_port*timer = (timer_port*)TIMER4_BASE; uint16 sr_buffer; diff --git a/libmaple/usart.c b/libmaple/usart.c index 030d3cc..494a29f 100644 --- a/libmaple/usart.c +++ b/libmaple/usart.c @@ -95,24 +95,24 @@ static inline void usart_irq(int usart_num) { /* TODO: Check the disassembly for the following functions to make sure GCC inlined properly. */ -void USART1_IRQHandler(void) { +void __irq_usart1(void) { usart_irq(USART1); } -void USART2_IRQHandler(void) { +void __irq_usart2(void) { usart_irq(USART2); } -void USART3_IRQHandler(void) { +void __irq_usart3(void) { usart_irq(USART3); } #ifdef STM32_HIGH_DENSITY -void UART4_IRQHandler(void) { +void __irq_uart4(void) { usart_irq(UART4); } -void UART5_IRQHandler(void) { +void __irq_uart5(void) { usart_irq(UART5); } #endif diff --git a/libmaple/usb/usb.c b/libmaple/usb/usb.c index d875785..62f56fc 100644 --- a/libmaple/usb/usb.c +++ b/libmaple/usb/usb.c @@ -241,7 +241,7 @@ void usbDsbISR(void) { } /* overloaded ISR routine, this is the main usb ISR */ -void usb_lpIRQHandler(void) { +void __irq_usb_lp_can_rx0(void) { wIstr = _GetISTR(); /* go nuts with the preproc switches since this is an ISTR and must be FAST */ diff --git a/libmaple/usb/usb.h b/libmaple/usb/usb.h index 0ed02e5..92f606c 100644 --- a/libmaple/usb/usb.h +++ b/libmaple/usb/usb.h @@ -69,7 +69,7 @@ void usbDsbISR(void); void usbEnbISR(void); /* overloaded ISR routine, this is the main usb ISR */ -void usb_lpIRQHandler(void); +void __irq_usb_lp_can_rx0(void); void usbWaitReset(void); /* blocking functions for send/receive */ diff --git a/support/ld/common_ram.inc b/support/ld/common_ram.inc new file mode 100644 index 0000000..be83e84 --- /dev/null +++ b/support/ld/common_ram.inc @@ -0,0 +1,221 @@ +/* Linker script for STM32 (by Lanchon with Mods by LeafLabs) */ + +OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") +SEARCH_DIR(.) +/* + * Link against libgcc, libc, and libm + */ +GROUP(libgcc.a libc.a libm.a) + +/* These force the linker to search for particular symbols from + * the start of the link process and thus ensure the user's + * overrides are picked up + */ +INCLUDE names.inc + +/* STM32 vector table. See stm32_vector_table.S */ +EXTERN(__cs3_stm32_vector_table) + +/* libcs3 C start function. See cs3.h */ +EXTERN(__cs3_start_c) + +/* main entry point */ +EXTERN(main) + +/* Initial stack pointer value. */ +EXTERN(__cs3_stack) +PROVIDE(__cs3_stack = __cs3_region_start_ram + __cs3_region_size_ram); + +/* Reset vector and chip reset entry point. See start.S */ +EXTERN(_start) +ENTRY(_start) +PROVIDE(__cs3_reset = _start); + +/* Beginning of the heap */ +PROVIDE(__cs3_heap_start = _end); + +/* End of the heap */ +PROVIDE(__cs3_heap_end = __cs3_region_start_ram + LENGTH(ram)); + + +SECTIONS +{ + .text : + { + CREATE_OBJECT_SYMBOLS + __cs3_region_start_ram = .; + *(.cs3.region-head.ram) + + /* + * STM32 vector table + */ + __cs3_interrupt_vector = __cs3_stm32_vector_table; + *(.cs3.interrupt_vector) + /* Make sure we pulled in an interrupt vector. */ + ASSERT (. != __cs3_stm32_vector_table, "No interrupt vector"); + + /* + * Program code and vague linking + */ + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + *(.gnu.warning) + *(.glue_7t) *(.glue_7) *(.vfp11_veneer) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + + *(.ARM.extab* .gnu.linkonce.armextab.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + . = ALIGN(4); + KEEP(*(.init)) + + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + + . = ALIGN(0x4); + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + + . = ALIGN(4); + KEEP(*(.fini)) + + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + . = ALIGN(4); + __cs3_regions = .; + LONG (0) + LONG (__cs3_region_init_ram) + LONG (__cs3_region_start_ram) + LONG (__cs3_region_init_size_ram) + LONG (__cs3_region_zero_size_ram) + } > ram + + /* + * .ARM.exidx exception unwinding + */ + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > ram + __exidx_end = .; + + /* + * End of text + */ + .text.align : + { + . = ALIGN(8); + _etext = .; + } > ram + + .cs3.rom : + { + __cs3_region_start_rom = .; + *(.cs3.region-head.rom) + *(.rom) + . = ALIGN (8); + } >ram + + .cs3.rom.bss : + { + *(.rom.b) + . = ALIGN (8); + } >ram + /* __cs3_region_end_rom is deprecated */ + __cs3_region_end_rom = __cs3_region_start_rom + LENGTH(ram); + __cs3_region_size_rom = LENGTH(ram); + __cs3_region_init_rom = LOADADDR (.cs3.rom); + __cs3_region_init_size_rom = SIZEOF(.cs3.rom); + __cs3_region_zero_size_rom = SIZEOF(.cs3.rom.bss); + + /* + * Start of data + */ + .data : + { + KEEP(*(.jcr)) + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + *(.ram) + . = ALIGN (8); + _edata = .; + } > ram + + .bss : + { + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + *(.ram.b) + . = ALIGN (8); + _end = .; + __end = .; + } > ram + + /* __cs3_region_end_ram is deprecated */ + __cs3_region_end_ram = __cs3_region_start_ram + LENGTH(ram); + __cs3_region_size_ram = LENGTH(ram); + __cs3_region_init_ram = LOADADDR (.text); + __cs3_region_init_size_ram = _edata - ADDR (.text); + __cs3_region_zero_size_ram = _end - _edata; + __cs3_region_num = 1; + + /* + * Debugging sections + */ + .stab 0 (NOLOAD) : { *(.stab) } + .stabstr 0 (NOLOAD) : { *(.stabstr) } + /* DWARF debug sections. + * Symbols in the DWARF debugging sections are relative to the beginning + * of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + + .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) } + .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) } + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git a/support/ld/common_rom.inc b/support/ld/common_rom.inc new file mode 100644 index 0000000..e0c295f --- /dev/null +++ b/support/ld/common_rom.inc @@ -0,0 +1,223 @@ +/* Linker script for STM32 (by Lanchon with Mods by LeafLabs) */ + +OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") +ENTRY(_start) +SEARCH_DIR(.) +/* + * Link against libgcc, libc, and libm + */ +GROUP(libgcc.a libc.a libm.a) + +/* These force the linker to search for particular symbols from + * the start of the link process and thus ensure the user's + * overrides are picked up + */ +INCLUDE names.inc + +/* STM32 vector table. See stm32_vector_table.S */ +EXTERN(__cs3_stm32_vector_table) + +/* libcs3 C start function. See cs3.h */ +EXTERN(__cs3_start_c) + +/* main entry point */ +EXTERN(main) + +/* Initial stack pointer value. */ +EXTERN(__cs3_stack) +PROVIDE(__cs3_stack = __cs3_region_start_ram + __cs3_region_size_ram); + +/* Reset vector and chip reset entry point. See start.S */ +EXTERN(_start) +PROVIDE(__cs3_reset = _start); + +/* Beginning of the heap */ +PROVIDE(__cs3_heap_start = _end); + +/* End of the heap */ +PROVIDE(__cs3_heap_end = __cs3_region_start_ram + LENGTH(ram)); + + +SECTIONS +{ + .text : + { + CREATE_OBJECT_SYMBOLS + __cs3_region_start_rom = .; + *(.cs3.region-head.rom) + + /* + * STM32 vector table + */ + __cs3_interrupt_vector = __cs3_stm32_vector_table; + *(.cs3.interrupt_vector) + /* Make sure we pulled in an interrupt vector. */ + ASSERT (. != __cs3_stm32_vector_table, "No interrupt vector"); + + *(.rom) + *(.rom.b) + + /* + * Program code and vague linking + */ + *(.rom) + *(.rom.b) + *(.text .text.* .gnu.linkonce.t.*) + *(.plt) + *(.gnu.warning) + *(.glue_7t) *(.glue_7) *(.vfp11_veneer) + + *(.rodata .rodata.* .gnu.linkonce.r.*) + + *(.ARM.extab* .gnu.linkonce.armextab.*) + *(.gcc_except_table) + *(.eh_frame_hdr) + *(.eh_frame) + + . = ALIGN(4); + KEEP(*(.init)) + + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + + . = ALIGN(0x4); + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + + . = ALIGN(4); + KEEP(*(.fini)) + + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + + . = ALIGN(4); + __cs3_regions = .; + LONG (0) + LONG (__cs3_region_init_ram) + LONG (__cs3_region_start_ram) + LONG (__cs3_region_init_size_ram) + LONG (__cs3_region_zero_size_ram) + } > REGION_TEXT + + /* + * .ARM.exidx exception unwinding + */ + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > REGION_TEXT + __exidx_end = .; + + /* + * End of text + */ + .text.align : + { + . = ALIGN(8); + _etext = .; + } > REGION_TEXT + + /* expose a custom rom only section */ + .USER_FLASH : + { + *(.USER_FLASH) + } >rom + + /* __cs3_region_end_rom is deprecated */ + __cs3_region_end_rom = __cs3_region_start_rom + LENGTH(rom); + __cs3_region_size_rom = LENGTH(rom); + __cs3_region_num = 1; + + /* + * Start of data + */ + .data : + { + ram_begin = DEFINED(RAM_BUILD) ? . : . ; + *(.cs3.region-head.ram_begin) + + __cs3_region_start_ram = .; + *(.cs3.region-head.ram) + + KEEP(*(.jcr)) + *(.got.plt) *(.got) + *(.shdata) + *(.data .data.* .gnu.linkonce.d.*) + *(.ram) + . = ALIGN (8); + _edata = .; + } > REGION_DATA AT> REGION_TEXT + + .bss : + { + *(.shbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + *(.ram.b) + . = ALIGN (8); + _end = .; + __end = .; + } > REGION_BSS AT> REGION_TEXT + + /* __cs3_region_end_ram is deprecated */ + __cs3_region_end_ram = __cs3_region_start_ram + LENGTH(ram); + __cs3_region_size_ram = LENGTH(ram); + __cs3_region_init_ram = LOADADDR (.data); + __cs3_region_init_size_ram = _edata - ADDR (.data); + __cs3_region_zero_size_ram = _end - _edata; + __cs3_region_num = 1; + + /* + * Debugging sections + */ + .stab 0 (NOLOAD) : { *(.stab) } + .stabstr 0 (NOLOAD) : { *(.stabstr) } + /* DWARF debug sections. + * Symbols in the DWARF debugging sections are relative to the beginning + * of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + + .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) } + .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) } + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git a/support/ld/libcs3-lanchon-stm32.a b/support/ld/libcs3-lanchon-stm32.a deleted file mode 100644 index 4ed858f..0000000 Binary files a/support/ld/libcs3-lanchon-stm32.a and /dev/null differ diff --git a/support/ld/libcs3-lanchon-stm32.tar.gz b/support/ld/libcs3-lanchon-stm32.tar.gz deleted file mode 100644 index 5cbcf7d..0000000 Binary files a/support/ld/libcs3-lanchon-stm32.tar.gz and /dev/null differ diff --git a/support/ld/libcs3_stm32_high_density.a b/support/ld/libcs3_stm32_high_density.a new file mode 100644 index 0000000..472ed28 Binary files /dev/null and b/support/ld/libcs3_stm32_high_density.a differ diff --git a/support/ld/libcs3_stm32_med_density.a b/support/ld/libcs3_stm32_med_density.a new file mode 100644 index 0000000..07a991d Binary files /dev/null and b/support/ld/libcs3_stm32_med_density.a differ diff --git a/support/ld/libcs3_stm32_src/Makefile b/support/ld/libcs3_stm32_src/Makefile new file mode 100644 index 0000000..d5275b9 --- /dev/null +++ b/support/ld/libcs3_stm32_src/Makefile @@ -0,0 +1,35 @@ +# setup environment + +TARGET_ARCH = -mcpu=cortex-m3 -mthumb + +CC = arm-none-eabi-gcc +CFLAGS = + +AS = $(CC) -x assembler-with-cpp -c $(TARGET_ARCH) +ASFLAGS = + +AR = arm-none-eabi-ar +ARFLAGS = cr + +LIB_OBJS = stm32_vector_table.o stm32_isrs.o start.o start_c.o + +help: + @echo "Targets:" + @echo "\t medium-density: Target medium density chips (e.g. Maple)" + @echo "\t high-density: Target high density chips (e.g. Maple-native)" + +.PHONY: help medium high + +medium-density: $(LIB_OBJS) + $(AR) $(ARFLAGS) libcs3_stm32_med_density.a $(LIB_OBJS) + rm -f $(LIB_OBJS) + +high-density: CFLAGS := -DSTM32_HIGH_DENSITY +high-density: $(LIB_OBJS) + $(AR) $(ARFLAGS) libcs3_stm32_high_density.a $(LIB_OBJS) + rm -f $(LIB_OBJS) + +# clean +.PHONY: clean +clean: + -rm -f $(LIB_OBJS) *.a diff --git a/support/ld/libcs3_stm32_src/start.S b/support/ld/libcs3_stm32_src/start.S new file mode 100644 index 0000000..ae75747 --- /dev/null +++ b/support/ld/libcs3_stm32_src/start.S @@ -0,0 +1,27 @@ +/* + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + */ + + .text + .code 16 + .thumb_func + + .globl _start + .type _start, %function +_start: + .fnstart + ldr r1,=__cs3_stack + mov sp,r1 + ldr r1,=__cs3_start_c + bx r1 + .pool + .cantunwind + .fnend diff --git a/support/ld/libcs3_stm32_src/start_c.c b/support/ld/libcs3_stm32_src/start_c.c new file mode 100644 index 0000000..dff9fa3 --- /dev/null +++ b/support/ld/libcs3_stm32_src/start_c.c @@ -0,0 +1,58 @@ +/* CS3 start_c routine. + * + * Copyright (c) 2006, 2007 CodeSourcery Inc + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + */ + +#include "cs3.h" + +extern void __libc_init_array (void); + +extern int main (int, char **, char **); + +extern void exit (int) __attribute__ ((noreturn, weak)); + +void __attribute ((noreturn)) +__cs3_start_c (void) +{ + unsigned regions = __cs3_region_num; + const struct __cs3_region *rptr = __cs3_regions; + int exit_code; + + /* Initialize memory */ + for (regions = __cs3_region_num, rptr = __cs3_regions; regions--; rptr++) + { + long long *src = (long long *)rptr->init; + long long *dst = (long long *)rptr->data; + unsigned limit = rptr->init_size; + unsigned count; + + if (src != dst) + for (count = 0; count != limit; count += sizeof (long long)) + *dst++ = *src++; + else + dst = (long long *)((char *)dst + limit); + limit = rptr->zero_size; + for (count = 0; count != limit; count += sizeof (long long)) + *dst++ = 0; + } + + /* Run initializers. */ + __libc_init_array (); + + exit_code = main (0, NULL, NULL); + if (exit) + exit (exit_code); + /* If exit is NULL, make sure we don't return. */ + for (;;) + continue; +} diff --git a/support/ld/libcs3_stm32_src/stm32_isrs.S b/support/ld/libcs3_stm32_src/stm32_isrs.S new file mode 100644 index 0000000..f95468c --- /dev/null +++ b/support/ld/libcs3_stm32_src/stm32_isrs.S @@ -0,0 +1,235 @@ +/* STM32 ISR weak declarations */ + + .thumb + +/* Default handler for all non-overridden interrupts and exceptions */ + .globl __default_handler + .type __default_handler, %function + +__default_handler: + b . + + .weak __exc_nmi + .globl __exc_nmi + .set __exc_nmi, __default_handler + .weak __exc_hardfault + .globl __exc_hardfault + .set __exc_hardfault, __default_handler + .weak __exc_memmanage + .globl __exc_memmanage + .set __exc_memmanage, __default_handler + .weak __exc_busfault + .globl __exc_busfault + .set __exc_busfault, __default_handler + .weak __exc_usagefault + .globl __exc_usagefault + .set __exc_usagefault, __default_handler + .weak __stm32reservedexception7 + .globl __stm32reservedexception7 + .set __stm32reservedexception7, __default_handler + .weak __stm32reservedexception8 + .globl __stm32reservedexception8 + .set __stm32reservedexception8, __default_handler + .weak __stm32reservedexception9 + .globl __stm32reservedexception9 + .set __stm32reservedexception9, __default_handler + .weak __stm32reservedexception10 + .globl __stm32reservedexception10 + .set __stm32reservedexception10, __default_handler + .weak __exc_svc + .globl __exc_svc + .set __exc_svc, __default_handler + .weak __exc_debug_monitor + .globl __exc_debug_monitor + .set __exc_debug_monitor, __default_handler + .weak __stm32reservedexception13 + .globl __stm32reservedexception13 + .set __stm32reservedexception13, __default_handler + .weak __exc_pendsv + .globl __exc_pendsv + .set __exc_pendsv, __default_handler + .weak __exc_systick + .globl __exc_systick + .set __exc_systick, __default_handler + .weak __irq_wwdg + .globl __irq_wwdg + .set __irq_wwdg, __default_handler + .weak __irq_pvd + .globl __irq_pvd + .set __irq_pvd, __default_handler + .weak __irq_tamper + .globl __irq_tamper + .set __irq_tamper, __default_handler + .weak __irq_rtc + .globl __irq_rtc + .set __irq_rtc, __default_handler + .weak __irq_flash + .globl __irq_flash + .set __irq_flash, __default_handler + .weak __irq_rcc + .globl __irq_rcc + .set __irq_rcc, __default_handler + .weak __irq_exti0 + .globl __irq_exti0 + .set __irq_exti0, __default_handler + .weak __irq_exti1 + .globl __irq_exti1 + .set __irq_exti1, __default_handler + .weak __irq_exti2 + .globl __irq_exti2 + .set __irq_exti2, __default_handler + .weak __irq_exti3 + .globl __irq_exti3 + .set __irq_exti3, __default_handler + .weak __irq_exti4 + .globl __irq_exti4 + .set __irq_exti4, __default_handler + .weak __irq_dma1_channel1 + .globl __irq_dma1_channel1 + .set __irq_dma1_channel1, __default_handler + .weak __irq_dma1_channel2 + .globl __irq_dma1_channel2 + .set __irq_dma1_channel2, __default_handler + .weak __irq_dma1_channel3 + .globl __irq_dma1_channel3 + .set __irq_dma1_channel3, __default_handler + .weak __irq_dma1_channel4 + .globl __irq_dma1_channel4 + .set __irq_dma1_channel4, __default_handler + .weak __irq_dma1_channel5 + .globl __irq_dma1_channel5 + .set __irq_dma1_channel5, __default_handler + .weak __irq_dma1_channel6 + .globl __irq_dma1_channel6 + .set __irq_dma1_channel6, __default_handler + .weak __irq_dma1_channel7 + .globl __irq_dma1_channel7 + .set __irq_dma1_channel7, __default_handler + .weak __irq_adc + .globl __irq_adc + .set __irq_adc, __default_handler + .weak __irq_usb_hp_can_tx + .globl __irq_usb_hp_can_tx + .set __irq_usb_hp_can_tx, __default_handler + .weak __irq_usb_lp_can_rx0 + .globl __irq_usb_lp_can_rx0 + .set __irq_usb_lp_can_rx0, __default_handler + .weak __irq_can_rx1 + .globl __irq_can_rx1 + .set __irq_can_rx1, __default_handler + .weak __irq_can_sce + .globl __irq_can_sce + .set __irq_can_sce, __default_handler + .weak __irq_exti9_5 + .globl __irq_exti9_5 + .set __irq_exti9_5, __default_handler + .weak __irq_tim1_brk + .globl __irq_tim1_brk + .set __irq_tim1_brk, __default_handler + .weak __irq_tim1_up + .globl __irq_tim1_up + .set __irq_tim1_up, __default_handler + .weak __irq_tim1_trg_com + .globl __irq_tim1_trg_com + .set __irq_tim1_trg_com, __default_handler + .weak __irq_tim1_cc + .globl __irq_tim1_cc + .set __irq_tim1_cc, __default_handler + .weak __irq_tim2 + .globl __irq_tim2 + .set __irq_tim2, __default_handler + .weak __irq_tim3 + .globl __irq_tim3 + .set __irq_tim3, __default_handler + .weak __irq_tim4 + .globl __irq_tim4 + .set __irq_tim4, __default_handler + .weak __irq_i2c1_ev + .globl __irq_i2c1_ev + .set __irq_i2c1_ev, __default_handler + .weak __irq_i2c1_er + .globl __irq_i2c1_er + .set __irq_i2c1_er, __default_handler + .weak __irq_i2c2_ev + .globl __irq_i2c2_ev + .set __irq_i2c2_ev, __default_handler + .weak __irq_i2c2_er + .globl __irq_i2c2_er + .set __irq_i2c2_er, __default_handler + .weak __irq_spi1 + .globl __irq_spi1 + .set __irq_spi1, __default_handler + .weak __irq_spi2 + .globl __irq_spi2 + .set __irq_spi2, __default_handler + .weak __irq_usart1 + .globl __irq_usart1 + .set __irq_usart1, __default_handler + .weak __irq_usart2 + .globl __irq_usart2 + .set __irq_usart2, __default_handler + .weak __irq_usart3 + .globl __irq_usart3 + .set __irq_usart3, __default_handler + .weak __irq_exti15_10 + .globl __irq_exti15_10 + .set __irq_exti15_10, __default_handler + .weak __irq_rtcalarm + .globl __irq_rtcalarm + .set __irq_rtcalarm, __default_handler + .weak __irq_usbwakeup + .globl __irq_usbwakeup + .set __irq_usbwakeup, __default_handler +#if defined (STM32_HIGH_DENSITY) + .weak __irq_tim8_brk + .globl __irq_tim8_brk + .set __irq_tim8_brk, __default_handler + .weak __irq_tim8_up + .globl __irq_tim8_up + .set __irq_tim8_up, __default_handler + .weak __irq_tim8_trg_com + .globl __irq_tim8_trg_com + .set __irq_tim8_trg_com, __default_handler + .weak __irq_tim8_cc + .globl __irq_tim8_cc + .set __irq_tim8_cc, __default_handler + .weak __irq_adc3 + .globl __irq_adc3 + .set __irq_adc3, __default_handler + .weak __irq_fsmc + .globl __irq_fsmc + .set __irq_fsmc, __default_handler + .weak __irq_sdio + .globl __irq_sdio + .set __irq_sdio, __default_handler + .weak __irq_tim5 + .globl __irq_tim5 + .set __irq_tim5, __default_handler + .weak __irq_spi3 + .globl __irq_spi3 + .set __irq_spi3, __default_handler + .weak __irq_uart4 + .globl __irq_uart4 + .set __irq_uart4, __default_handler + .weak __irq_uart5 + .globl __irq_uart5 + .set __irq_uart5, __default_handler + .weak __irq_tim6 + .globl __irq_tim6 + .set __irq_tim6, __default_handler + .weak __irq_tim7 + .globl __irq_tim7 + .set __irq_tim7, __default_handler + .weak __irq_dma2_channel1 + .globl __irq_dma2_channel1 + .set __irq_dma2_channel1, __default_handler + .weak __irq_dma2_channel2 + .globl __irq_dma2_channel2 + .set __irq_dma2_channel2, __default_handler + .weak __irq_dma2_channel3 + .globl __irq_dma2_channel3 + .set __irq_dma2_channel3, __default_handler + .weak __irq_dma2_channel4_5 + .globl __irq_dma2_channel4_5 + .set __irq_dma2_channel4_5, __default_handler +#endif /* STM32_HIGH_DENSITY */ diff --git a/support/ld/libcs3_stm32_src/stm32_vector_table.S b/support/ld/libcs3_stm32_src/stm32_vector_table.S new file mode 100644 index 0000000..8c71cb5 --- /dev/null +++ b/support/ld/libcs3_stm32_src/stm32_vector_table.S @@ -0,0 +1,90 @@ +/* STM32 vector table */ + + .section ".cs3.interrupt_vector" + + .globl __cs3_stm32_vector_table + .type __cs3_stm32_vector_table, %object + +__cs3_stm32_vector_table: +/* CM3 core interrupts */ + .long __cs3_stack + .long __cs3_reset + .long __exc_nmi + .long __exc_hardfault + .long __exc_memmanage + .long __exc_busfault + .long __exc_usagefault + .long __stm32reservedexception7 + .long __stm32reservedexception8 + .long __stm32reservedexception9 + .long __stm32reservedexception10 + .long __exc_svc + .long __exc_debug_monitor + .long __stm32reservedexception13 + .long __exc_pendsv + .long __exc_systick +/* Peripheral interrupts */ + .long __irq_wwdg + .long __irq_pvd + .long __irq_tamper + .long __irq_rtc + .long __irq_flash + .long __irq_rcc + .long __irq_exti0 + .long __irq_exti1 + .long __irq_exti2 + .long __irq_exti3 + .long __irq_exti4 + .long __irq_dma1_channel1 + .long __irq_dma1_channel2 + .long __irq_dma1_channel3 + .long __irq_dma1_channel4 + .long __irq_dma1_channel5 + .long __irq_dma1_channel6 + .long __irq_dma1_channel7 + .long __irq_adc + .long __irq_usb_hp_can_tx + .long __irq_usb_lp_can_rx0 + .long __irq_can_rx1 + .long __irq_can_sce + .long __irq_exti9_5 + .long __irq_tim1_brk + .long __irq_tim1_up + .long __irq_tim1_trg_com + .long __irq_tim1_cc + .long __irq_tim2 + .long __irq_tim3 + .long __irq_tim4 + .long __irq_i2c1_ev + .long __irq_i2c1_er + .long __irq_i2c2_ev + .long __irq_i2c2_er + .long __irq_spi1 + .long __irq_spi2 + .long __irq_usart1 + .long __irq_usart2 + .long __irq_usart3 + .long __irq_exti15_10 + .long __irq_rtcalarm + .long __irq_usbwakeup +#if defined (STM32_HIGH_DENSITY) + .weak __irq_tim8_brk + .weak __irq_tim8_up + .weak __irq_tim8_trg_com + .weak __irq_tim8_cc + .weak __irq_adc3 + .weak __irq_fsmc + .weak __irq_sdio + .weak __irq_tim5 + .weak __irq_spi3 + .weak __irq_uart4 + .weak __irq_uart5 + .weak __irq_tim6 + .weak __irq_tim7 + .weak __irq_dma2_channel1 + .weak __irq_dma2_channel2 + .weak __irq_dma2_channel3 + .weak __irq_dma2_channel4_5 +#endif /* STM32_HIGH_DENSITY */ + + .size __cs3_stm32_vector_table, . - __cs3_stm32_vector_table diff --git a/support/ld/maple/flash.ld b/support/ld/maple/flash.ld index 2d40100..9c3efcb 100644 --- a/support/ld/maple/flash.ld +++ b/support/ld/maple/flash.ld @@ -1,211 +1,28 @@ -/* Linker script for STM32 (by Lanchon with Mods by LeafLabs) - * - * Version:Sourcery G++ 4.2-84 - * BugURL:https://support.codesourcery.com/GNUToolchain/ - * - * Copyright 2007 CodeSourcery. - * - * The authors hereby grant permission to use, copy, modify, distribute, - * and license this software and its documentation for any purpose, provided - * that existing copyright notices are retained in all copies and that this - * notice is included verbatim in any distributions. No written agreement, - * license, or royalty fee is required for any of the authorized uses. - * Modifications to this software may be copyrighted by their authors - * and need not follow the licensing terms described here, provided that - * the new terms are clearly indicated on the first page of each file where - * they apply. */ - -/* Linker script for STM32 (by Lanchon), - * ROM and RAM relocated to their positions - * as placed by Maple bootloader - * - * Configure target memory and included script - * according to your application requirements. */ +/* + * Linker script for STM32. + * STM32F103RBT6 medium density chip linker script for use with + * maple bootloader. Loads to flash. + */ -/* Define memory spaces. */ +/* + * Define memory spaces. + */ MEMORY { ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K rom (rx) : ORIGIN = 0x08005000, LENGTH = 108K } -OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") -ENTRY(_start) -SEARCH_DIR(.) -/* GROUP(-lgcc -lc -lcs3 -lcs3unhosted -lcs3-lanchon-stm32) */ -GROUP(libgcc.a libc.a libm.a libcs3-lanchon-stm32.a) - -/* These force the linker to search for particular symbols from - * the start of the link process and thus ensure the user's - * overrides are picked up +/* + * Use medium density device vector table */ -EXTERN(__cs3_reset_lanchon_stm32) -INCLUDE names.inc -EXTERN(__cs3_interrupt_vector_lanchon_stm32) -EXTERN(__cs3_start_c main __cs3_stack __cs3_heap_end) -EXTERN(_start) - -PROVIDE(__cs3_stack = __cs3_region_start_ram + __cs3_region_size_ram); -PROVIDE(__cs3_heap_start = _end); -PROVIDE(__cs3_heap_end = __cs3_region_start_ram + __cs3_region_size_ram); - -SECTIONS -{ - .text : - { - CREATE_OBJECT_SYMBOLS - __cs3_region_start_rom = .; - *(.cs3.region-head.rom) - __cs3_interrupt_vector = __cs3_interrupt_vector_lanchon_stm32; - *(.cs3.interrupt_vector) - /* Make sure we pulled in an interrupt vector. */ - ASSERT (. != __cs3_interrupt_vector_lanchon_stm32, "No interrupt vector"); - *(.rom) - *(.rom.b) - - PROVIDE(__cs3_reset_lanchon_stm32 = _start); - __cs3_reset = __cs3_reset_lanchon_stm32; - *(.cs3.reset) - - *(.text .text.* .gnu.linkonce.t.*) - *(.plt) - *(.gnu.warning) - *(.glue_7t) *(.glue_7) *(.vfp11_veneer) - - *(.rodata .rodata.* .gnu.linkonce.r.*) - - *(.ARM.extab* .gnu.linkonce.armextab.*) - *(.gcc_except_table) - *(.eh_frame_hdr) - *(.eh_frame) - - . = ALIGN(4); - KEEP(*(.init)) - - . = ALIGN(4); - __preinit_array_start = .; - KEEP (*(.preinit_array)) - __preinit_array_end = .; +GROUP(libcs3_stm32_med_density.a) - . = ALIGN(4); - __init_array_start = .; - KEEP (*(SORT(.init_array.*))) - KEEP (*(.init_array)) - __init_array_end = .; +REGION_ALIAS("REGION_TEXT", rom); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); - . = ALIGN(0x4); - KEEP (*crtbegin.o(.ctors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) - KEEP (*(SORT(.ctors.*))) - KEEP (*crtend.o(.ctors)) - - . = ALIGN(4); - KEEP(*(.fini)) - - . = ALIGN(4); - __fini_array_start = .; - KEEP (*(.fini_array)) - KEEP (*(SORT(.fini_array.*))) - __fini_array_end = .; - - KEEP (*crtbegin.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*crtend.o(.dtors)) - - . = ALIGN(4); - __cs3_regions = .; - LONG (0) - LONG (__cs3_region_init_ram) - LONG (__cs3_region_start_ram) - LONG (__cs3_region_init_size_ram) - LONG (__cs3_region_zero_size_ram) - } >rom - - /* .ARM.exidx is sorted, so has to go in its own output section. */ - __exidx_start = .; - .ARM.exidx : - { - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - } >rom - __exidx_end = .; - .text.align : - { - . = ALIGN(8); - _etext = .; - } >rom - -/* expose a custom rom only section */ - .USER_FLASH : - { - *(.USER_FLASH) - } >rom - - - /* __cs3_region_end_rom is deprecated */ - __cs3_region_end_rom = __cs3_region_start_rom + LENGTH(rom); - __cs3_region_size_rom = LENGTH(rom); - __cs3_region_num = 1; - - .data : - { - __cs3_region_start_ram = .; - *(.cs3.region-head.ram) - KEEP(*(.jcr)) - *(.got.plt) *(.got) - *(.shdata) - *(.data .data.* .gnu.linkonce.d.*) - *(.ram) - . = ALIGN (8); - _edata = .; - } >ram AT>rom - .bss : - { - *(.shbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - *(.ram.b) - . = ALIGN (8); - _end = .; - __end = .; - } >ram AT>rom - /* __cs3_region_end_ram is deprecated */ - __cs3_region_end_ram = __cs3_region_start_ram + LENGTH(ram); - __cs3_region_size_ram = LENGTH(ram); - __cs3_region_init_ram = LOADADDR (.data); - __cs3_region_init_size_ram = _edata - ADDR (.data); - __cs3_region_zero_size_ram = _end - _edata; - __cs3_region_num = 1; - - .stab 0 (NOLOAD) : { *(.stab) } - .stabstr 0 (NOLOAD) : { *(.stabstr) } - /* DWARF debug sections. - * Symbols in the DWARF debugging sections are relative to the beginning - * of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } - - .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) } - .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) } - /DISCARD/ : { *(.note.GNU-stack) } -} +/* + * Define the rest of the sections + */ +INCLUDE common_rom.inc diff --git a/support/ld/maple/jtag.ld b/support/ld/maple/jtag.ld index 435e3f0..caf90ee 100644 --- a/support/ld/maple/jtag.ld +++ b/support/ld/maple/jtag.ld @@ -1,186 +1,28 @@ -/* Linker script for STM32 (by Lanchon), - * ROM and RAM relocated to their positions - * as placed by Maple bootloader - * - * Configure target memory and included script - * according to your application requirements. */ +/* + * Linker script for STM32. + * STM32F103RBT6 medium density chip linker script. + */ -/* Define memory spaces. */ +/* + * Define memory spaces. + */ MEMORY { ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K } -OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") -ENTRY(_start) -SEARCH_DIR(.) -/* GROUP(-lgcc -lc -lcs3 -lcs3unhosted -lcs3-lanchon-stm32) */ -GROUP(libgcc.a libc.a libm.a libcs3-lanchon-stm32.a) - -/* These force the linker to search for particular symbols from - * the start of the link process and thus ensure the user's - * overrides are picked up +/* + * Use medium density device vector table */ -EXTERN(__cs3_reset_lanchon_stm32) -INCLUDE names.inc -EXTERN(__cs3_interrupt_vector_lanchon_stm32) -EXTERN(__cs3_start_c main __cs3_stack __cs3_heap_end) -EXTERN(_start) - -PROVIDE(__cs3_stack = __cs3_region_start_ram + __cs3_region_size_ram); -PROVIDE(__cs3_heap_start = _end); -PROVIDE(__cs3_heap_end = __cs3_region_start_ram + __cs3_region_size_ram); - -SECTIONS -{ - .text : - { - CREATE_OBJECT_SYMBOLS - __cs3_region_start_rom = .; - *(.cs3.region-head.rom) - __cs3_interrupt_vector = __cs3_interrupt_vector_lanchon_stm32; - *(.cs3.interrupt_vector) - /* Make sure we pulled in an interrupt vector. */ - ASSERT (. != __cs3_interrupt_vector_lanchon_stm32, "No interrupt vector"); - *(.rom) - *(.rom.b) - - PROVIDE(__cs3_reset_lanchon_stm32 = _start); - __cs3_reset = __cs3_reset_lanchon_stm32; - *(.cs3.reset) - - *(.text .text.* .gnu.linkonce.t.*) - *(.plt) - *(.gnu.warning) - *(.glue_7t) *(.glue_7) *(.vfp11_veneer) - - *(.rodata .rodata.* .gnu.linkonce.r.*) - - *(.ARM.extab* .gnu.linkonce.armextab.*) - *(.gcc_except_table) - *(.eh_frame_hdr) - *(.eh_frame) - - . = ALIGN(4); - KEEP(*(.init)) +GROUP(libcs3_stm32_med_density.a) - . = ALIGN(4); - __preinit_array_start = .; - KEEP (*(.preinit_array)) - __preinit_array_end = .; +REGION_ALIAS("REGION_TEXT", rom); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); - . = ALIGN(4); - __init_array_start = .; - KEEP (*(SORT(.init_array.*))) - KEEP (*(.init_array)) - __init_array_end = .; - - . = ALIGN(0x4); - KEEP (*crtbegin.o(.ctors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) - KEEP (*(SORT(.ctors.*))) - KEEP (*crtend.o(.ctors)) - - . = ALIGN(4); - KEEP(*(.fini)) - - . = ALIGN(4); - __fini_array_start = .; - KEEP (*(.fini_array)) - KEEP (*(SORT(.fini_array.*))) - __fini_array_end = .; - - KEEP (*crtbegin.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*crtend.o(.dtors)) - - . = ALIGN(4); - __cs3_regions = .; - LONG (0) - LONG (__cs3_region_init_ram) - LONG (__cs3_region_start_ram) - LONG (__cs3_region_init_size_ram) - LONG (__cs3_region_zero_size_ram) - } >rom - - /* .ARM.exidx is sorted, so has to go in its own output section. */ - __exidx_start = .; - .ARM.exidx : - { - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - } >rom - __exidx_end = .; - .text.align : - { - . = ALIGN(8); - _etext = .; - } >rom - /* __cs3_region_end_rom is deprecated */ - __cs3_region_end_rom = __cs3_region_start_rom + LENGTH(rom); - __cs3_region_size_rom = LENGTH(rom); - __cs3_region_num = 1; - - .data : - { - __cs3_region_start_ram = .; - *(.cs3.region-head.ram) - KEEP(*(.jcr)) - *(.got.plt) *(.got) - *(.shdata) - *(.data .data.* .gnu.linkonce.d.*) - *(.ram) - . = ALIGN (8); - _edata = .; - } >ram AT>rom - .bss : - { - *(.shbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - *(.ram.b) - . = ALIGN (8); - _end = .; - __end = .; - } >ram AT>rom - /* __cs3_region_end_ram is deprecated */ - __cs3_region_end_ram = __cs3_region_start_ram + LENGTH(ram); - __cs3_region_size_ram = LENGTH(ram); - __cs3_region_init_ram = LOADADDR (.data); - __cs3_region_init_size_ram = _edata - ADDR (.data); - __cs3_region_zero_size_ram = _end - _edata; - __cs3_region_num = 1; - - .stab 0 (NOLOAD) : { *(.stab) } - .stabstr 0 (NOLOAD) : { *(.stabstr) } - /* DWARF debug sections. - * Symbols in the DWARF debugging sections are relative to the beginning - * of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } +/* + * Define the rest of the sections + */ +INCLUDE common_rom.inc - .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) } - .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) } - /DISCARD/ : { *(.note.GNU-stack) } -} diff --git a/support/ld/maple/ram.ld b/support/ld/maple/ram.ld index 1fbecc5..b1e285e 100644 --- a/support/ld/maple/ram.ld +++ b/support/ld/maple/ram.ld @@ -1,220 +1,27 @@ -/* Linker script for STM32 (by Lanchon with Mods by LeafLabs) - * - * Version:Sourcery G++ 4.2-84 - * BugURL:https://support.codesourcery.com/GNUToolchain/ - * - * Copyright 2007 CodeSourcery. - * - * The authors hereby grant permission to use, copy, modify, distribute, - * and license this software and its documentation for any purpose, provided - * that existing copyright notices are retained in all copies and that this - * notice is included verbatim in any distributions. No written agreement, - * license, or royalty fee is required for any of the authorized uses. - * Modifications to this software may be copyrighted by their authors - * and need not follow the licensing terms described here, provided that - * the new terms are clearly indicated on the first page of each file where - * they apply. */ - -/* Linker script for STM32 (by Lanchon), - * ROM and RAM relocated to their positions - * as placed by Maple bootloader - * - * Configure target memory and included script - * according to your application requirements. */ +/* + * Linker script for STM32. + * STM32F103RBT6 medium density chip linker script. Loads to ram. + */ -/* Define memory spaces. */ +/* + * Define memory spaces. + */ MEMORY { ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K rom (rx) : ORIGIN = 0x08005000, LENGTH = 0K } - -OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") -ENTRY(_start) -SEARCH_DIR(.) -/* GROUP(-lgcc -lc -lcs3 -lcs3unhosted -lcs3-lanchon-stm32) */ -GROUP(libgcc.a libc.a libm.a libcs3-lanchon-stm32.a) - -/* These force the linker to search for particular symbols from - * the start of the link process and thus ensure the user's - * overrides are picked up +/* + * Use medium density device vector table */ -EXTERN(__cs3_reset_lanchon_stm32) -INCLUDE names.inc -EXTERN(__cs3_interrupt_vector_lanchon_stm32) -EXTERN(__cs3_start_c main __cs3_stack __cs3_heap_end) -EXTERN(_start) - -PROVIDE(__cs3_stack = __cs3_region_start_ram + __cs3_region_size_ram); -PROVIDE(__cs3_heap_start = _end); -PROVIDE(__cs3_heap_end = __cs3_region_start_ram + __cs3_region_size_ram); - -SECTIONS -{ - .text : - { - CREATE_OBJECT_SYMBOLS - __cs3_region_start_ram = .; - *(.cs3.region-head.ram) - __cs3_interrupt_vector = __cs3_interrupt_vector_lanchon_stm32; - *(.cs3.interrupt_vector) - /* Make sure we pulled in an interrupt vector. */ - ASSERT (. != __cs3_interrupt_vector_lanchon_stm32, "No interrupt vector"); - - PROVIDE(__cs3_reset_lanchon_stm32 = _start); - __cs3_reset = __cs3_reset_lanchon_stm32; - *(.cs3.reset) - - *(.text .text.* .gnu.linkonce.t.*) - *(.plt) - *(.gnu.warning) - *(.glue_7t) *(.glue_7) *(.vfp11_veneer) - - *(.rodata .rodata.* .gnu.linkonce.r.*) - - *(.ARM.extab* .gnu.linkonce.armextab.*) - *(.gcc_except_table) - *(.eh_frame_hdr) - *(.eh_frame) - - . = ALIGN(4); - KEEP(*(.init)) - - . = ALIGN(4); - __preinit_array_start = .; - KEEP (*(.preinit_array)) - __preinit_array_end = .; +GROUP(libcs3_stm32_med_density.a) - . = ALIGN(4); - __init_array_start = .; - KEEP (*(SORT(.init_array.*))) - KEEP (*(.init_array)) - __init_array_end = .; - - . = ALIGN(0x4); - KEEP (*crtbegin.o(.ctors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) - KEEP (*(SORT(.ctors.*))) - KEEP (*crtend.o(.ctors)) - - . = ALIGN(4); - KEEP(*(.fini)) - - . = ALIGN(4); - __fini_array_start = .; - KEEP (*(.fini_array)) - KEEP (*(SORT(.fini_array.*))) - __fini_array_end = .; - - KEEP (*crtbegin.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*crtend.o(.dtors)) - - . = ALIGN(4); - __cs3_regions = .; - LONG (0) - LONG (__cs3_region_init_ram) - LONG (__cs3_region_start_ram) - LONG (__cs3_region_init_size_ram) - LONG (__cs3_region_zero_size_ram) - } >ram - - /* .ARM.exidx is sorted, so has to go in its own output section. */ - /* even cs3.rom is in ram since its running as user code under the Maple - bootloader */ - __exidx_start = .; - .ARM.exidx : - { - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - } >ram - __exidx_end = .; - .text.align : - { - . = ALIGN(8); - _etext = .; - } >ram - - .cs3.rom : - { - __cs3_region_start_rom = .; - *(.cs3.region-head.rom) - *(.rom) - . = ALIGN (8); - } >ram - - .cs3.rom.bss : - { - *(.rom.b) - . = ALIGN (8); - } >ram - /* __cs3_region_end_rom is deprecated */ - __cs3_region_end_rom = __cs3_region_start_rom + LENGTH(ram); - __cs3_region_size_rom = LENGTH(ram); - __cs3_region_init_rom = LOADADDR (.cs3.rom); - __cs3_region_init_size_rom = SIZEOF(.cs3.rom); - __cs3_region_zero_size_rom = SIZEOF(.cs3.rom.bss); - - .data : - { - - KEEP(*(.jcr)) - *(.got.plt) *(.got) - *(.shdata) - *(.data .data.* .gnu.linkonce.d.*) - *(.ram) - . = ALIGN (8); - _edata = .; - } >ram - .bss : - { - *(.shbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - *(.ram.b) - . = ALIGN (8); - _end = .; - __end = .; - } >ram - /* __cs3_region_end_ram is deprecated */ - __cs3_region_end_ram = __cs3_region_start_ram + LENGTH(ram); - __cs3_region_size_ram = LENGTH(ram); - __cs3_region_init_ram = LOADADDR (.text); - __cs3_region_init_size_ram = _edata - ADDR (.text); - __cs3_region_zero_size_ram = _end - _edata; - __cs3_region_num = 1; - - .stab 0 (NOLOAD) : { *(.stab) } - .stabstr 0 (NOLOAD) : { *(.stabstr) } - /* DWARF debug sections. - * Symbols in the DWARF debugging sections are relative to the beginning - * of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } - - .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) } - .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) } - /DISCARD/ : { *(.note.GNU-stack) } -} +REGION_ALIAS("REGION_TEXT", ram); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); +/* + * Define the rest of the sections + */ +INCLUDE common_ram.inc diff --git a/support/ld/maple_mini/flash.ld b/support/ld/maple_mini/flash.ld index 2d40100..4c26da2 100644 --- a/support/ld/maple_mini/flash.ld +++ b/support/ld/maple_mini/flash.ld @@ -1,211 +1,27 @@ -/* Linker script for STM32 (by Lanchon with Mods by LeafLabs) - * - * Version:Sourcery G++ 4.2-84 - * BugURL:https://support.codesourcery.com/GNUToolchain/ - * - * Copyright 2007 CodeSourcery. - * - * The authors hereby grant permission to use, copy, modify, distribute, - * and license this software and its documentation for any purpose, provided - * that existing copyright notices are retained in all copies and that this - * notice is included verbatim in any distributions. No written agreement, - * license, or royalty fee is required for any of the authorized uses. - * Modifications to this software may be copyrighted by their authors - * and need not follow the licensing terms described here, provided that - * the new terms are clearly indicated on the first page of each file where - * they apply. */ - -/* Linker script for STM32 (by Lanchon), - * ROM and RAM relocated to their positions - * as placed by Maple bootloader - * - * Configure target memory and included script - * according to your application requirements. */ +/* + * Linker script for STM32. + * Maple mini flash linker script. + */ -/* Define memory spaces. */ +/* + * Define memory spaces. + */ MEMORY { ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K rom (rx) : ORIGIN = 0x08005000, LENGTH = 108K } -OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") -ENTRY(_start) -SEARCH_DIR(.) -/* GROUP(-lgcc -lc -lcs3 -lcs3unhosted -lcs3-lanchon-stm32) */ -GROUP(libgcc.a libc.a libm.a libcs3-lanchon-stm32.a) - -/* These force the linker to search for particular symbols from - * the start of the link process and thus ensure the user's - * overrides are picked up +/* + * Use medium density device vector table */ -EXTERN(__cs3_reset_lanchon_stm32) -INCLUDE names.inc -EXTERN(__cs3_interrupt_vector_lanchon_stm32) -EXTERN(__cs3_start_c main __cs3_stack __cs3_heap_end) -EXTERN(_start) - -PROVIDE(__cs3_stack = __cs3_region_start_ram + __cs3_region_size_ram); -PROVIDE(__cs3_heap_start = _end); -PROVIDE(__cs3_heap_end = __cs3_region_start_ram + __cs3_region_size_ram); - -SECTIONS -{ - .text : - { - CREATE_OBJECT_SYMBOLS - __cs3_region_start_rom = .; - *(.cs3.region-head.rom) - __cs3_interrupt_vector = __cs3_interrupt_vector_lanchon_stm32; - *(.cs3.interrupt_vector) - /* Make sure we pulled in an interrupt vector. */ - ASSERT (. != __cs3_interrupt_vector_lanchon_stm32, "No interrupt vector"); - *(.rom) - *(.rom.b) - - PROVIDE(__cs3_reset_lanchon_stm32 = _start); - __cs3_reset = __cs3_reset_lanchon_stm32; - *(.cs3.reset) - - *(.text .text.* .gnu.linkonce.t.*) - *(.plt) - *(.gnu.warning) - *(.glue_7t) *(.glue_7) *(.vfp11_veneer) - - *(.rodata .rodata.* .gnu.linkonce.r.*) - - *(.ARM.extab* .gnu.linkonce.armextab.*) - *(.gcc_except_table) - *(.eh_frame_hdr) - *(.eh_frame) - - . = ALIGN(4); - KEEP(*(.init)) - - . = ALIGN(4); - __preinit_array_start = .; - KEEP (*(.preinit_array)) - __preinit_array_end = .; +GROUP(libcs3_stm32_med_density.a) - . = ALIGN(4); - __init_array_start = .; - KEEP (*(SORT(.init_array.*))) - KEEP (*(.init_array)) - __init_array_end = .; +REGION_ALIAS("REGION_TEXT", rom); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); - . = ALIGN(0x4); - KEEP (*crtbegin.o(.ctors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) - KEEP (*(SORT(.ctors.*))) - KEEP (*crtend.o(.ctors)) - - . = ALIGN(4); - KEEP(*(.fini)) - - . = ALIGN(4); - __fini_array_start = .; - KEEP (*(.fini_array)) - KEEP (*(SORT(.fini_array.*))) - __fini_array_end = .; - - KEEP (*crtbegin.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*crtend.o(.dtors)) - - . = ALIGN(4); - __cs3_regions = .; - LONG (0) - LONG (__cs3_region_init_ram) - LONG (__cs3_region_start_ram) - LONG (__cs3_region_init_size_ram) - LONG (__cs3_region_zero_size_ram) - } >rom - - /* .ARM.exidx is sorted, so has to go in its own output section. */ - __exidx_start = .; - .ARM.exidx : - { - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - } >rom - __exidx_end = .; - .text.align : - { - . = ALIGN(8); - _etext = .; - } >rom - -/* expose a custom rom only section */ - .USER_FLASH : - { - *(.USER_FLASH) - } >rom - - - /* __cs3_region_end_rom is deprecated */ - __cs3_region_end_rom = __cs3_region_start_rom + LENGTH(rom); - __cs3_region_size_rom = LENGTH(rom); - __cs3_region_num = 1; - - .data : - { - __cs3_region_start_ram = .; - *(.cs3.region-head.ram) - KEEP(*(.jcr)) - *(.got.plt) *(.got) - *(.shdata) - *(.data .data.* .gnu.linkonce.d.*) - *(.ram) - . = ALIGN (8); - _edata = .; - } >ram AT>rom - .bss : - { - *(.shbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - *(.ram.b) - . = ALIGN (8); - _end = .; - __end = .; - } >ram AT>rom - /* __cs3_region_end_ram is deprecated */ - __cs3_region_end_ram = __cs3_region_start_ram + LENGTH(ram); - __cs3_region_size_ram = LENGTH(ram); - __cs3_region_init_ram = LOADADDR (.data); - __cs3_region_init_size_ram = _edata - ADDR (.data); - __cs3_region_zero_size_ram = _end - _edata; - __cs3_region_num = 1; - - .stab 0 (NOLOAD) : { *(.stab) } - .stabstr 0 (NOLOAD) : { *(.stabstr) } - /* DWARF debug sections. - * Symbols in the DWARF debugging sections are relative to the beginning - * of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } - - .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) } - .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) } - /DISCARD/ : { *(.note.GNU-stack) } -} +/* + * Define the rest of the sections + */ +INCLUDE common_rom.inc diff --git a/support/ld/maple_mini/jtag.ld b/support/ld/maple_mini/jtag.ld index 435e3f0..31768ed 100644 --- a/support/ld/maple_mini/jtag.ld +++ b/support/ld/maple_mini/jtag.ld @@ -1,186 +1,28 @@ -/* Linker script for STM32 (by Lanchon), - * ROM and RAM relocated to their positions - * as placed by Maple bootloader - * - * Configure target memory and included script - * according to your application requirements. */ +/* + * Linker script for STM32. + * Maple mini linker script bare metal target linker script. + */ -/* Define memory spaces. */ +/* + * Define memory spaces. + */ MEMORY { ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K } -OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") -ENTRY(_start) -SEARCH_DIR(.) -/* GROUP(-lgcc -lc -lcs3 -lcs3unhosted -lcs3-lanchon-stm32) */ -GROUP(libgcc.a libc.a libm.a libcs3-lanchon-stm32.a) - -/* These force the linker to search for particular symbols from - * the start of the link process and thus ensure the user's - * overrides are picked up +/* + * Use medium density device vector table */ -EXTERN(__cs3_reset_lanchon_stm32) -INCLUDE names.inc -EXTERN(__cs3_interrupt_vector_lanchon_stm32) -EXTERN(__cs3_start_c main __cs3_stack __cs3_heap_end) -EXTERN(_start) - -PROVIDE(__cs3_stack = __cs3_region_start_ram + __cs3_region_size_ram); -PROVIDE(__cs3_heap_start = _end); -PROVIDE(__cs3_heap_end = __cs3_region_start_ram + __cs3_region_size_ram); - -SECTIONS -{ - .text : - { - CREATE_OBJECT_SYMBOLS - __cs3_region_start_rom = .; - *(.cs3.region-head.rom) - __cs3_interrupt_vector = __cs3_interrupt_vector_lanchon_stm32; - *(.cs3.interrupt_vector) - /* Make sure we pulled in an interrupt vector. */ - ASSERT (. != __cs3_interrupt_vector_lanchon_stm32, "No interrupt vector"); - *(.rom) - *(.rom.b) - - PROVIDE(__cs3_reset_lanchon_stm32 = _start); - __cs3_reset = __cs3_reset_lanchon_stm32; - *(.cs3.reset) - - *(.text .text.* .gnu.linkonce.t.*) - *(.plt) - *(.gnu.warning) - *(.glue_7t) *(.glue_7) *(.vfp11_veneer) - - *(.rodata .rodata.* .gnu.linkonce.r.*) - - *(.ARM.extab* .gnu.linkonce.armextab.*) - *(.gcc_except_table) - *(.eh_frame_hdr) - *(.eh_frame) - - . = ALIGN(4); - KEEP(*(.init)) +GROUP(libcs3_stm32_med_density.a) - . = ALIGN(4); - __preinit_array_start = .; - KEEP (*(.preinit_array)) - __preinit_array_end = .; +REGION_ALIAS("REGION_TEXT", rom); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); - . = ALIGN(4); - __init_array_start = .; - KEEP (*(SORT(.init_array.*))) - KEEP (*(.init_array)) - __init_array_end = .; - - . = ALIGN(0x4); - KEEP (*crtbegin.o(.ctors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) - KEEP (*(SORT(.ctors.*))) - KEEP (*crtend.o(.ctors)) - - . = ALIGN(4); - KEEP(*(.fini)) - - . = ALIGN(4); - __fini_array_start = .; - KEEP (*(.fini_array)) - KEEP (*(SORT(.fini_array.*))) - __fini_array_end = .; - - KEEP (*crtbegin.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*crtend.o(.dtors)) - - . = ALIGN(4); - __cs3_regions = .; - LONG (0) - LONG (__cs3_region_init_ram) - LONG (__cs3_region_start_ram) - LONG (__cs3_region_init_size_ram) - LONG (__cs3_region_zero_size_ram) - } >rom - - /* .ARM.exidx is sorted, so has to go in its own output section. */ - __exidx_start = .; - .ARM.exidx : - { - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - } >rom - __exidx_end = .; - .text.align : - { - . = ALIGN(8); - _etext = .; - } >rom - /* __cs3_region_end_rom is deprecated */ - __cs3_region_end_rom = __cs3_region_start_rom + LENGTH(rom); - __cs3_region_size_rom = LENGTH(rom); - __cs3_region_num = 1; - - .data : - { - __cs3_region_start_ram = .; - *(.cs3.region-head.ram) - KEEP(*(.jcr)) - *(.got.plt) *(.got) - *(.shdata) - *(.data .data.* .gnu.linkonce.d.*) - *(.ram) - . = ALIGN (8); - _edata = .; - } >ram AT>rom - .bss : - { - *(.shbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - *(.ram.b) - . = ALIGN (8); - _end = .; - __end = .; - } >ram AT>rom - /* __cs3_region_end_ram is deprecated */ - __cs3_region_end_ram = __cs3_region_start_ram + LENGTH(ram); - __cs3_region_size_ram = LENGTH(ram); - __cs3_region_init_ram = LOADADDR (.data); - __cs3_region_init_size_ram = _edata - ADDR (.data); - __cs3_region_zero_size_ram = _end - _edata; - __cs3_region_num = 1; - - .stab 0 (NOLOAD) : { *(.stab) } - .stabstr 0 (NOLOAD) : { *(.stabstr) } - /* DWARF debug sections. - * Symbols in the DWARF debugging sections are relative to the beginning - * of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } +/* + * Define the rest of the sections + */ +INCLUDE common_rom.inc - .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) } - .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) } - /DISCARD/ : { *(.note.GNU-stack) } -} diff --git a/support/ld/maple_mini/ram.ld b/support/ld/maple_mini/ram.ld index 1fbecc5..7dd7ee5 100644 --- a/support/ld/maple_mini/ram.ld +++ b/support/ld/maple_mini/ram.ld @@ -1,220 +1,27 @@ -/* Linker script for STM32 (by Lanchon with Mods by LeafLabs) - * - * Version:Sourcery G++ 4.2-84 - * BugURL:https://support.codesourcery.com/GNUToolchain/ - * - * Copyright 2007 CodeSourcery. - * - * The authors hereby grant permission to use, copy, modify, distribute, - * and license this software and its documentation for any purpose, provided - * that existing copyright notices are retained in all copies and that this - * notice is included verbatim in any distributions. No written agreement, - * license, or royalty fee is required for any of the authorized uses. - * Modifications to this software may be copyrighted by their authors - * and need not follow the licensing terms described here, provided that - * the new terms are clearly indicated on the first page of each file where - * they apply. */ - -/* Linker script for STM32 (by Lanchon), - * ROM and RAM relocated to their positions - * as placed by Maple bootloader - * - * Configure target memory and included script - * according to your application requirements. */ +/* + * Linker script for STM32. + * Maple mini ram target linker script. + */ -/* Define memory spaces. */ +/* + * Define memory spaces. + */ MEMORY { ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K rom (rx) : ORIGIN = 0x08005000, LENGTH = 0K } - -OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") -ENTRY(_start) -SEARCH_DIR(.) -/* GROUP(-lgcc -lc -lcs3 -lcs3unhosted -lcs3-lanchon-stm32) */ -GROUP(libgcc.a libc.a libm.a libcs3-lanchon-stm32.a) - -/* These force the linker to search for particular symbols from - * the start of the link process and thus ensure the user's - * overrides are picked up +/* + * Use medium density device vector table */ -EXTERN(__cs3_reset_lanchon_stm32) -INCLUDE names.inc -EXTERN(__cs3_interrupt_vector_lanchon_stm32) -EXTERN(__cs3_start_c main __cs3_stack __cs3_heap_end) -EXTERN(_start) - -PROVIDE(__cs3_stack = __cs3_region_start_ram + __cs3_region_size_ram); -PROVIDE(__cs3_heap_start = _end); -PROVIDE(__cs3_heap_end = __cs3_region_start_ram + __cs3_region_size_ram); - -SECTIONS -{ - .text : - { - CREATE_OBJECT_SYMBOLS - __cs3_region_start_ram = .; - *(.cs3.region-head.ram) - __cs3_interrupt_vector = __cs3_interrupt_vector_lanchon_stm32; - *(.cs3.interrupt_vector) - /* Make sure we pulled in an interrupt vector. */ - ASSERT (. != __cs3_interrupt_vector_lanchon_stm32, "No interrupt vector"); - - PROVIDE(__cs3_reset_lanchon_stm32 = _start); - __cs3_reset = __cs3_reset_lanchon_stm32; - *(.cs3.reset) - - *(.text .text.* .gnu.linkonce.t.*) - *(.plt) - *(.gnu.warning) - *(.glue_7t) *(.glue_7) *(.vfp11_veneer) - - *(.rodata .rodata.* .gnu.linkonce.r.*) - - *(.ARM.extab* .gnu.linkonce.armextab.*) - *(.gcc_except_table) - *(.eh_frame_hdr) - *(.eh_frame) - - . = ALIGN(4); - KEEP(*(.init)) - - . = ALIGN(4); - __preinit_array_start = .; - KEEP (*(.preinit_array)) - __preinit_array_end = .; +GROUP(libcs3_stm32_med_density.a) - . = ALIGN(4); - __init_array_start = .; - KEEP (*(SORT(.init_array.*))) - KEEP (*(.init_array)) - __init_array_end = .; - - . = ALIGN(0x4); - KEEP (*crtbegin.o(.ctors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) - KEEP (*(SORT(.ctors.*))) - KEEP (*crtend.o(.ctors)) - - . = ALIGN(4); - KEEP(*(.fini)) - - . = ALIGN(4); - __fini_array_start = .; - KEEP (*(.fini_array)) - KEEP (*(SORT(.fini_array.*))) - __fini_array_end = .; - - KEEP (*crtbegin.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*crtend.o(.dtors)) - - . = ALIGN(4); - __cs3_regions = .; - LONG (0) - LONG (__cs3_region_init_ram) - LONG (__cs3_region_start_ram) - LONG (__cs3_region_init_size_ram) - LONG (__cs3_region_zero_size_ram) - } >ram - - /* .ARM.exidx is sorted, so has to go in its own output section. */ - /* even cs3.rom is in ram since its running as user code under the Maple - bootloader */ - __exidx_start = .; - .ARM.exidx : - { - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - } >ram - __exidx_end = .; - .text.align : - { - . = ALIGN(8); - _etext = .; - } >ram - - .cs3.rom : - { - __cs3_region_start_rom = .; - *(.cs3.region-head.rom) - *(.rom) - . = ALIGN (8); - } >ram - - .cs3.rom.bss : - { - *(.rom.b) - . = ALIGN (8); - } >ram - /* __cs3_region_end_rom is deprecated */ - __cs3_region_end_rom = __cs3_region_start_rom + LENGTH(ram); - __cs3_region_size_rom = LENGTH(ram); - __cs3_region_init_rom = LOADADDR (.cs3.rom); - __cs3_region_init_size_rom = SIZEOF(.cs3.rom); - __cs3_region_zero_size_rom = SIZEOF(.cs3.rom.bss); - - .data : - { - - KEEP(*(.jcr)) - *(.got.plt) *(.got) - *(.shdata) - *(.data .data.* .gnu.linkonce.d.*) - *(.ram) - . = ALIGN (8); - _edata = .; - } >ram - .bss : - { - *(.shbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - *(.ram.b) - . = ALIGN (8); - _end = .; - __end = .; - } >ram - /* __cs3_region_end_ram is deprecated */ - __cs3_region_end_ram = __cs3_region_start_ram + LENGTH(ram); - __cs3_region_size_ram = LENGTH(ram); - __cs3_region_init_ram = LOADADDR (.text); - __cs3_region_init_size_ram = _edata - ADDR (.text); - __cs3_region_zero_size_ram = _end - _edata; - __cs3_region_num = 1; - - .stab 0 (NOLOAD) : { *(.stab) } - .stabstr 0 (NOLOAD) : { *(.stabstr) } - /* DWARF debug sections. - * Symbols in the DWARF debugging sections are relative to the beginning - * of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } - - .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) } - .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) } - /DISCARD/ : { *(.note.GNU-stack) } -} +REGION_ALIAS("REGION_TEXT", ram); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); +/* + * Define the rest of the sections + */ +INCLUDE common_ram.inc diff --git a/support/ld/maple_native/flash.ld b/support/ld/maple_native/flash.ld index 4e820d2..4358419 100644 --- a/support/ld/maple_native/flash.ld +++ b/support/ld/maple_native/flash.ld @@ -1,211 +1,22 @@ -/* Linker script for STM32 (by Lanchon with Mods by LeafLabs) - * - * Version:Sourcery G++ 4.2-84 - * BugURL:https://support.codesourcery.com/GNUToolchain/ - * - * Copyright 2007 CodeSourcery. - * - * The authors hereby grant permission to use, copy, modify, distribute, - * and license this software and its documentation for any purpose, provided - * that existing copyright notices are retained in all copies and that this - * notice is included verbatim in any distributions. No written agreement, - * license, or royalty fee is required for any of the authorized uses. - * Modifications to this software may be copyrighted by their authors - * and need not follow the licensing terms described here, provided that - * the new terms are clearly indicated on the first page of each file where - * they apply. */ - -/* Linker script for STM32 (by Lanchon), - * ROM and RAM relocated to their positions - * as placed by Maple bootloader - * - * Configure target memory and included script - * according to your application requirements. */ +/* + * Linker script for STM32. + * STM32 high density chip linker script. Loads to flash with Maple bootloader + */ -/* Define memory spaces. */ MEMORY { ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 61K rom (rx) : ORIGIN = 0x08005000, LENGTH = 492K } -OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") -ENTRY(_start) -SEARCH_DIR(.) -/* GROUP(-lgcc -lc -lcs3 -lcs3unhosted -lcs3-lanchon-stm32) */ -GROUP(libgcc.a libc.a libm.a libcs3-lanchon-stm32.a) - -/* These force the linker to search for particular symbols from - * the start of the link process and thus ensure the user's - * overrides are picked up +/* + * Use high density device vector table */ -EXTERN(__cs3_reset_lanchon_stm32) -INCLUDE names.inc -EXTERN(__cs3_interrupt_vector_lanchon_stm32) -EXTERN(__cs3_start_c main __cs3_stack __cs3_heap_end) -EXTERN(_start) - -PROVIDE(__cs3_stack = __cs3_region_start_ram + __cs3_region_size_ram); -PROVIDE(__cs3_heap_start = _end); -PROVIDE(__cs3_heap_end = __cs3_region_start_ram + __cs3_region_size_ram); - -SECTIONS -{ - .text : - { - CREATE_OBJECT_SYMBOLS - __cs3_region_start_rom = .; - *(.cs3.region-head.rom) - __cs3_interrupt_vector = __cs3_interrupt_vector_lanchon_stm32; - *(.cs3.interrupt_vector) - /* Make sure we pulled in an interrupt vector. */ - ASSERT (. != __cs3_interrupt_vector_lanchon_stm32, "No interrupt vector"); - *(.rom) - *(.rom.b) - - PROVIDE(__cs3_reset_lanchon_stm32 = _start); - __cs3_reset = __cs3_reset_lanchon_stm32; - *(.cs3.reset) - - *(.text .text.* .gnu.linkonce.t.*) - *(.plt) - *(.gnu.warning) - *(.glue_7t) *(.glue_7) *(.vfp11_veneer) - - *(.rodata .rodata.* .gnu.linkonce.r.*) - - *(.ARM.extab* .gnu.linkonce.armextab.*) - *(.gcc_except_table) - *(.eh_frame_hdr) - *(.eh_frame) - - . = ALIGN(4); - KEEP(*(.init)) - - . = ALIGN(4); - __preinit_array_start = .; - KEEP (*(.preinit_array)) - __preinit_array_end = .; +GROUP(libcs3_stm32_high_density.a) - . = ALIGN(4); - __init_array_start = .; - KEEP (*(SORT(.init_array.*))) - KEEP (*(.init_array)) - __init_array_end = .; +REGION_ALIAS("REGION_TEXT", rom); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); - . = ALIGN(0x4); - KEEP (*crtbegin.o(.ctors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) - KEEP (*(SORT(.ctors.*))) - KEEP (*crtend.o(.ctors)) +INCLUDE common_rom.inc - . = ALIGN(4); - KEEP(*(.fini)) - - . = ALIGN(4); - __fini_array_start = .; - KEEP (*(.fini_array)) - KEEP (*(SORT(.fini_array.*))) - __fini_array_end = .; - - KEEP (*crtbegin.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*crtend.o(.dtors)) - - . = ALIGN(4); - __cs3_regions = .; - LONG (0) - LONG (__cs3_region_init_ram) - LONG (__cs3_region_start_ram) - LONG (__cs3_region_init_size_ram) - LONG (__cs3_region_zero_size_ram) - } >rom - - /* .ARM.exidx is sorted, so has to go in its own output section. */ - __exidx_start = .; - .ARM.exidx : - { - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - } >rom - __exidx_end = .; - .text.align : - { - . = ALIGN(8); - _etext = .; - } >rom - -/* expose a custom rom only section */ - .USER_FLASH : - { - *(.USER_FLASH) - } >rom - - - /* __cs3_region_end_rom is deprecated */ - __cs3_region_end_rom = __cs3_region_start_rom + LENGTH(rom); - __cs3_region_size_rom = LENGTH(rom); - __cs3_region_num = 1; - - .data : - { - __cs3_region_start_ram = .; - *(.cs3.region-head.ram) - KEEP(*(.jcr)) - *(.got.plt) *(.got) - *(.shdata) - *(.data .data.* .gnu.linkonce.d.*) - *(.ram) - . = ALIGN (8); - _edata = .; - } >ram AT>rom - .bss : - { - *(.shbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - *(.ram.b) - . = ALIGN (8); - _end = .; - __end = .; - } >ram AT>rom - /* __cs3_region_end_ram is deprecated */ - __cs3_region_end_ram = __cs3_region_start_ram + LENGTH(ram); - __cs3_region_size_ram = LENGTH(ram); - __cs3_region_init_ram = LOADADDR (.data); - __cs3_region_init_size_ram = _edata - ADDR (.data); - __cs3_region_zero_size_ram = _end - _edata; - __cs3_region_num = 1; - - .stab 0 (NOLOAD) : { *(.stab) } - .stabstr 0 (NOLOAD) : { *(.stabstr) } - /* DWARF debug sections. - * Symbols in the DWARF debugging sections are relative to the beginning - * of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } - - .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) } - .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) } - /DISCARD/ : { *(.note.GNU-stack) } -} diff --git a/support/ld/maple_native/jtag.ld b/support/ld/maple_native/jtag.ld index 90a0a3f..0e99c3b 100644 --- a/support/ld/maple_native/jtag.ld +++ b/support/ld/maple_native/jtag.ld @@ -1,186 +1,21 @@ -/* Linker script for STM32 (by Lanchon), - * ROM and RAM relocated to their positions - * as placed by Maple bootloader - * - * Configure target memory and included script - * according to your application requirements. */ - -/* Define memory spaces. */ +/* + * Linker script for STM32. + * STM32 high density chip linker script. Bare metal linker script. + */ MEMORY { ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64K rom (rx) : ORIGIN = 0x08000000, LENGTH = 512K } -OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") -ENTRY(_start) -SEARCH_DIR(.) -/* GROUP(-lgcc -lc -lcs3 -lcs3unhosted -lcs3-lanchon-stm32) */ -GROUP(libgcc.a libc.a libm.a libcs3-lanchon-stm32.a) - -/* These force the linker to search for particular symbols from - * the start of the link process and thus ensure the user's - * overrides are picked up +/* + * Use high density device vector table */ -EXTERN(__cs3_reset_lanchon_stm32) -INCLUDE names.inc -EXTERN(__cs3_interrupt_vector_lanchon_stm32) -EXTERN(__cs3_start_c main __cs3_stack __cs3_heap_end) -EXTERN(_start) - -PROVIDE(__cs3_stack = __cs3_region_start_ram + __cs3_region_size_ram); -PROVIDE(__cs3_heap_start = _end); -PROVIDE(__cs3_heap_end = __cs3_region_start_ram + __cs3_region_size_ram); - -SECTIONS -{ - .text : - { - CREATE_OBJECT_SYMBOLS - __cs3_region_start_rom = .; - *(.cs3.region-head.rom) - __cs3_interrupt_vector = __cs3_interrupt_vector_lanchon_stm32; - *(.cs3.interrupt_vector) - /* Make sure we pulled in an interrupt vector. */ - ASSERT (. != __cs3_interrupt_vector_lanchon_stm32, "No interrupt vector"); - *(.rom) - *(.rom.b) - - PROVIDE(__cs3_reset_lanchon_stm32 = _start); - __cs3_reset = __cs3_reset_lanchon_stm32; - *(.cs3.reset) - - *(.text .text.* .gnu.linkonce.t.*) - *(.plt) - *(.gnu.warning) - *(.glue_7t) *(.glue_7) *(.vfp11_veneer) - - *(.rodata .rodata.* .gnu.linkonce.r.*) - - *(.ARM.extab* .gnu.linkonce.armextab.*) - *(.gcc_except_table) - *(.eh_frame_hdr) - *(.eh_frame) +GROUP(libcs3_stm32_high_density.a) - . = ALIGN(4); - KEEP(*(.init)) +REGION_ALIAS("REGION_TEXT", rom); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); - . = ALIGN(4); - __preinit_array_start = .; - KEEP (*(.preinit_array)) - __preinit_array_end = .; +INCLUDE common_rom.inc - . = ALIGN(4); - __init_array_start = .; - KEEP (*(SORT(.init_array.*))) - KEEP (*(.init_array)) - __init_array_end = .; - - . = ALIGN(0x4); - KEEP (*crtbegin.o(.ctors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) - KEEP (*(SORT(.ctors.*))) - KEEP (*crtend.o(.ctors)) - - . = ALIGN(4); - KEEP(*(.fini)) - - . = ALIGN(4); - __fini_array_start = .; - KEEP (*(.fini_array)) - KEEP (*(SORT(.fini_array.*))) - __fini_array_end = .; - - KEEP (*crtbegin.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*crtend.o(.dtors)) - - . = ALIGN(4); - __cs3_regions = .; - LONG (0) - LONG (__cs3_region_init_ram) - LONG (__cs3_region_start_ram) - LONG (__cs3_region_init_size_ram) - LONG (__cs3_region_zero_size_ram) - } >rom - - /* .ARM.exidx is sorted, so has to go in its own output section. */ - __exidx_start = .; - .ARM.exidx : - { - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - } >rom - __exidx_end = .; - .text.align : - { - . = ALIGN(8); - _etext = .; - } >rom - /* __cs3_region_end_rom is deprecated */ - __cs3_region_end_rom = __cs3_region_start_rom + LENGTH(rom); - __cs3_region_size_rom = LENGTH(rom); - __cs3_region_num = 1; - - .data : - { - __cs3_region_start_ram = .; - *(.cs3.region-head.ram) - KEEP(*(.jcr)) - *(.got.plt) *(.got) - *(.shdata) - *(.data .data.* .gnu.linkonce.d.*) - *(.ram) - . = ALIGN (8); - _edata = .; - } >ram AT>rom - .bss : - { - *(.shbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - *(.ram.b) - . = ALIGN (8); - _end = .; - __end = .; - } >ram AT>rom - /* __cs3_region_end_ram is deprecated */ - __cs3_region_end_ram = __cs3_region_start_ram + LENGTH(ram); - __cs3_region_size_ram = LENGTH(ram); - __cs3_region_init_ram = LOADADDR (.data); - __cs3_region_init_size_ram = _edata - ADDR (.data); - __cs3_region_zero_size_ram = _end - _edata; - __cs3_region_num = 1; - - .stab 0 (NOLOAD) : { *(.stab) } - .stabstr 0 (NOLOAD) : { *(.stabstr) } - /* DWARF debug sections. - * Symbols in the DWARF debugging sections are relative to the beginning - * of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } - - .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) } - .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) } - /DISCARD/ : { *(.note.GNU-stack) } -} diff --git a/support/ld/maple_native/ram.ld b/support/ld/maple_native/ram.ld index a5e1482..22c09cd 100644 --- a/support/ld/maple_native/ram.ld +++ b/support/ld/maple_native/ram.ld @@ -1,220 +1,22 @@ -/* Linker script for STM32 (by Lanchon with Mods by LeafLabs) - * - * Version:Sourcery G++ 4.2-84 - * BugURL:https://support.codesourcery.com/GNUToolchain/ - * - * Copyright 2007 CodeSourcery. - * - * The authors hereby grant permission to use, copy, modify, distribute, - * and license this software and its documentation for any purpose, provided - * that existing copyright notices are retained in all copies and that this - * notice is included verbatim in any distributions. No written agreement, - * license, or royalty fee is required for any of the authorized uses. - * Modifications to this software may be copyrighted by their authors - * and need not follow the licensing terms described here, provided that - * the new terms are clearly indicated on the first page of each file where - * they apply. */ - -/* Linker script for STM32 (by Lanchon), - * ROM and RAM relocated to their positions - * as placed by Maple bootloader - * - * Configure target memory and included script - * according to your application requirements. */ +/* + * Linker script for STM32. + * STM32 high density chip linker script. Loads to RAM with Maple bootloader + */ -/* Define memory spaces. */ MEMORY { ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 61K rom (rx) : ORIGIN = 0x08005000, LENGTH = 0K } - -OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") -ENTRY(_start) -SEARCH_DIR(.) -/* GROUP(-lgcc -lc -lcs3 -lcs3unhosted -lcs3-lanchon-stm32) */ -GROUP(libgcc.a libc.a libm.a libcs3-lanchon-stm32.a) - -/* These force the linker to search for particular symbols from - * the start of the link process and thus ensure the user's - * overrides are picked up +/* + * Use high density device vector table */ -EXTERN(__cs3_reset_lanchon_stm32) -INCLUDE names.inc -EXTERN(__cs3_interrupt_vector_lanchon_stm32) -EXTERN(__cs3_start_c main __cs3_stack __cs3_heap_end) -EXTERN(_start) - -PROVIDE(__cs3_stack = __cs3_region_start_ram + __cs3_region_size_ram); -PROVIDE(__cs3_heap_start = _end); -PROVIDE(__cs3_heap_end = __cs3_region_start_ram + __cs3_region_size_ram); - -SECTIONS -{ - .text : - { - CREATE_OBJECT_SYMBOLS - __cs3_region_start_ram = .; - *(.cs3.region-head.ram) - __cs3_interrupt_vector = __cs3_interrupt_vector_lanchon_stm32; - *(.cs3.interrupt_vector) - /* Make sure we pulled in an interrupt vector. */ - ASSERT (. != __cs3_interrupt_vector_lanchon_stm32, "No interrupt vector"); - - PROVIDE(__cs3_reset_lanchon_stm32 = _start); - __cs3_reset = __cs3_reset_lanchon_stm32; - *(.cs3.reset) - - *(.text .text.* .gnu.linkonce.t.*) - *(.plt) - *(.gnu.warning) - *(.glue_7t) *(.glue_7) *(.vfp11_veneer) - - *(.rodata .rodata.* .gnu.linkonce.r.*) - - *(.ARM.extab* .gnu.linkonce.armextab.*) - *(.gcc_except_table) - *(.eh_frame_hdr) - *(.eh_frame) - - . = ALIGN(4); - KEEP(*(.init)) - - . = ALIGN(4); - __preinit_array_start = .; - KEEP (*(.preinit_array)) - __preinit_array_end = .; +GROUP(libcs3_stm32_high_density.a) - . = ALIGN(4); - __init_array_start = .; - KEEP (*(SORT(.init_array.*))) - KEEP (*(.init_array)) - __init_array_end = .; +REGION_ALIAS("REGION_TEXT", ram); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); - . = ALIGN(0x4); - KEEP (*crtbegin.o(.ctors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) - KEEP (*(SORT(.ctors.*))) - KEEP (*crtend.o(.ctors)) - - . = ALIGN(4); - KEEP(*(.fini)) - - . = ALIGN(4); - __fini_array_start = .; - KEEP (*(.fini_array)) - KEEP (*(SORT(.fini_array.*))) - __fini_array_end = .; - - KEEP (*crtbegin.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*crtend.o(.dtors)) - - . = ALIGN(4); - __cs3_regions = .; - LONG (0) - LONG (__cs3_region_init_ram) - LONG (__cs3_region_start_ram) - LONG (__cs3_region_init_size_ram) - LONG (__cs3_region_zero_size_ram) - } >ram - - /* .ARM.exidx is sorted, so has to go in its own output section. */ - /* even cs3.rom is in ram since its running as user code under the Maple - bootloader */ - __exidx_start = .; - .ARM.exidx : - { - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - } >ram - __exidx_end = .; - .text.align : - { - . = ALIGN(8); - _etext = .; - } >ram - - .cs3.rom : - { - __cs3_region_start_rom = .; - *(.cs3.region-head.rom) - *(.rom) - . = ALIGN (8); - } >ram - - .cs3.rom.bss : - { - *(.rom.b) - . = ALIGN (8); - } >ram - /* __cs3_region_end_rom is deprecated */ - __cs3_region_end_rom = __cs3_region_start_rom + LENGTH(ram); - __cs3_region_size_rom = LENGTH(ram); - __cs3_region_init_rom = LOADADDR (.cs3.rom); - __cs3_region_init_size_rom = SIZEOF(.cs3.rom); - __cs3_region_zero_size_rom = SIZEOF(.cs3.rom.bss); - - .data : - { - - KEEP(*(.jcr)) - *(.got.plt) *(.got) - *(.shdata) - *(.data .data.* .gnu.linkonce.d.*) - *(.ram) - . = ALIGN (8); - _edata = .; - } >ram - .bss : - { - *(.shbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - *(.ram.b) - . = ALIGN (8); - _end = .; - __end = .; - } >ram - /* __cs3_region_end_ram is deprecated */ - __cs3_region_end_ram = __cs3_region_start_ram + LENGTH(ram); - __cs3_region_size_ram = LENGTH(ram); - __cs3_region_init_ram = LOADADDR (.text); - __cs3_region_init_size_ram = _edata - ADDR (.text); - __cs3_region_zero_size_ram = _end - _edata; - __cs3_region_num = 1; - - .stab 0 (NOLOAD) : { *(.stab) } - .stabstr 0 (NOLOAD) : { *(.stabstr) } - /* DWARF debug sections. - * Symbols in the DWARF debugging sections are relative to the beginning - * of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } - - .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) } - .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) } - /DISCARD/ : { *(.note.GNU-stack) } -} +INCLUDE common_ram.inc diff --git a/support/ld/names.inc b/support/ld/names.inc index a0e1fb2..9fab36c 100644 --- a/support/ld/names.inc +++ b/support/ld/names.inc @@ -1,61 +1,78 @@ -/* ISR names for STM32 (by Lanchon) */ +EXTERN(__cs3_stack) +EXTERN(__cs3_reset) +EXTERN(__exc_nmi) +EXTERN(__exc_hardfault) +EXTERN(__exc_memmanage) +EXTERN(__exc_busfault) +EXTERN(__exc_usagefault) +EXTERN(__stm32reservedexception7) +EXTERN(__stm32reservedexception8) +EXTERN(__stm32reservedexception9) +EXTERN(__stm32reservedexception10) +EXTERN(__exc_svc) +EXTERN(__exc_debug_monitor) +EXTERN(__stm32reservedexception13) +EXTERN(__exc_pendsv) +EXTERN(__exc_systick) -EXTERN (__cs3_stack) -EXTERN (__cs3_reset) -EXTERN (NMIException) -EXTERN (HardFaultException) -EXTERN (MemManageException) -EXTERN (BusFaultException) -EXTERN (UsageFaultException) -EXTERN (__STM32ReservedException7) -EXTERN (__STM32ReservedException8) -EXTERN (__STM32ReservedException9) -EXTERN (__STM32ReservedException10) -EXTERN (SVCHandler) -EXTERN (DebugMonitor) -EXTERN (__STM32ReservedException13) -EXTERN (PendSVC) -EXTERN (SysTickHandler) -EXTERN (WWDG_IRQHandler) -EXTERN (PVD_IRQHandler) -EXTERN (TAMPER_IRQHandler) -EXTERN (RTC_IRQHandler) -EXTERN (FLASH_IRQHandler) -EXTERN (RCC_IRQHandler) -EXTERN (EXTI0_IRQHandler) -EXTERN (EXTI1_IRQHandler) -EXTERN (EXTI2_IRQHandler) -EXTERN (EXTI3_IRQHandler) -EXTERN (EXTI4_IRQHandler) -EXTERN (DMAChannel1_IRQHandler) -EXTERN (DMAChannel2_IRQHandler) -EXTERN (DMAChannel3_IRQHandler) -EXTERN (DMAChannel4_IRQHandler) -EXTERN (DMAChannel5_IRQHandler) -EXTERN (DMAChannel6_IRQHandler) -EXTERN (DMAChannel7_IRQHandler) -EXTERN (ADC_IRQHandler) -EXTERN (USB_HP_CAN_TX_IRQHandler) -EXTERN (USB_LP_CAN_RX0_IRQHandler) -EXTERN (CAN_RX1_IRQHandler) -EXTERN (CAN_SCE_IRQHandler) -EXTERN (EXTI9_5_IRQHandler) -EXTERN (TIM1_BRK_IRQHandler) -EXTERN (TIM1_UP_IRQHandler) -EXTERN (TIM1_TRG_COM_IRQHandler) -EXTERN (TIM1_CC_IRQHandler) -EXTERN (TIM2_IRQHandler) -EXTERN (TIM3_IRQHandler) -EXTERN (TIM4_IRQHandler) -EXTERN (I2C1_EV_IRQHandler) -EXTERN (I2C1_ER_IRQHandler) -EXTERN (I2C2_EV_IRQHandler) -EXTERN (I2C2_ER_IRQHandler) -EXTERN (SPI1_IRQHandler) -EXTERN (SPI2_IRQHandler) -EXTERN (USART1_IRQHandler) -EXTERN (USART2_IRQHandler) -EXTERN (USART3_IRQHandler) -EXTERN (EXTI15_10_IRQHandler) -EXTERN (RTCAlarm_IRQHandler) -EXTERN (USBWakeUp_IRQHandler) +EXTERN(__irq_wwdg) +EXTERN(__irq_pvd) +EXTERN(__irq_tamper) +EXTERN(__irq_rtc) +EXTERN(__irq_flash) +EXTERN(__irq_rcc) +EXTERN(__irq_exti0) +EXTERN(__irq_exti1) +EXTERN(__irq_exti2) +EXTERN(__irq_exti3) +EXTERN(__irq_exti4) +EXTERN(__irq_dma_channel1) +EXTERN(__irq_dma_channel2) +EXTERN(__irq_dma_channel3) +EXTERN(__irq_dma_channel4) +EXTERN(__irq_dma_channel5) +EXTERN(__irq_dma_channel6) +EXTERN(__irq_dma_channel7) +EXTERN(__irq_adc) +EXTERN(__irq_usb_hp_can_tx) +EXTERN(__irq_usb_lp_can_rx0) +EXTERN(__irq_can_rx1) +EXTERN(__irq_can_sce) +EXTERN(__irq_exti9_5) +EXTERN(__irq_tim1_brk) +EXTERN(__irq_tim1_up) +EXTERN(__irq_tim1_trg_com) +EXTERN(__irq_tim1_cc) +EXTERN(__irq_tim2) +EXTERN(__irq_tim3) +EXTERN(__irq_tim4) +EXTERN(__irq_i2c1_ev) +EXTERN(__irq_i2c1_er) +EXTERN(__irq_i2c2_ev) +EXTERN(__irq_i2c2_er) +EXTERN(__irq_spi1) +EXTERN(__irq_spi2) +EXTERN(__irq_usart1) +EXTERN(__irq_usart2) +EXTERN(__irq_usart3) +EXTERN(__irq_exti15_10) +EXTERN(__irq_rtcalarm) +EXTERN(__irq_usbwakeup) + +EXTERN(__irq_tim8_brk) +EXTERN(__irq_tim8_up) +EXTERN(__irq_tim8_trg_com) +EXTERN(__irq_tim8_cc) +EXTERN(__irq_adc3) +EXTERN(__irq_fsmc) +EXTERN(__irq_sdio) +EXTERN(__irq_tim5) +EXTERN(__irq_spi3) +EXTERN(__irq_uart4) +EXTERN(__irq_uart5) +EXTERN(__irq_tim6) +EXTERN(__irq_tim7) +EXTERN(__irq_dma2_channel1) +EXTERN(__irq_dma2_channel2) +EXTERN(__irq_dma2_channel3) +EXTERN(__irq_dma2_channel4_5) diff --git a/support/ld/src.zip b/support/ld/src.zip deleted file mode 100644 index 58ff908..0000000 Binary files a/support/ld/src.zip and /dev/null differ -- cgit v1.2.3 From 68c483e3c9c382779d2580598fb0f90a9f55d2ab Mon Sep 17 00:00:00 2001 From: Perry Hung Date: Sun, 27 Feb 2011 17:26:19 -0500 Subject: Set NONEBASETHRDENA on exception. --- libmaple/exc.S | 40 +++++++++++++++++++++++++--------------- libmaple/util.c | 50 ++++++++++++++++++++++++++++++++------------------ libmaple/util.h | 1 + 3 files changed, 58 insertions(+), 33 deletions(-) diff --git a/libmaple/exc.S b/libmaple/exc.S index d01e3d5..823bbc5 100644 --- a/libmaple/exc.S +++ b/libmaple/exc.S @@ -48,40 +48,50 @@ .globl __exc_busfault .globl __exc_usagefault -/* TODO: Fix this up. */ +.code 16 .thumb_func __exc_nmi: mov r0, #1 + b __default_exc .thumb_func __exc_hardfault: mov r0, #2 + b __default_exc .thumb_func __exc_memmanage: mov r0, #3 + b __default_exc .thumb_func __exc_busfault: mov r0, #4 + b __default_exc .thumb_func __exc_usagefault: mov r0, #5 + b __default_exc -__default: - ldr r1, CPSR_MASK @ Set default CPSR - push {r1} - ldr r1, TARGET_PC @ Set target pc - push {r1} - sub sp, sp, #24 @ Don't care - ldr r1, EXC_RETURN @ Return to thread mode - mov lr, r1 - bx lr @ Exception exit - - .align 4 - CPSR_MASK: .word 0x61000000 - EXC_RETURN: .word 0xFFFFFFF9 - TARGET_PC: .word throb +.thumb_func +__default_exc: + ldr r2, NVIC_CCR @ Enabling returning to thread mode from an + mov r1 ,#1 @ exception. See flag NONEBASETHRDENA. + str r1, [r2] + cpsid i @ Disable global interrupts + ldr r1, CPSR_MASK @ Set default CPSR + push {r1} + ldr r1, TARGET_PC @ Set target pc + push {r1} + sub sp, sp, #24 @ Don't care + ldr r1, EXC_RETURN @ Return to thread mode + mov lr, r1 + bx lr @ Exception exit +.align 4 +CPSR_MASK: .word 0x61000000 +EXC_RETURN: .word 0xFFFFFFF9 +TARGET_PC: .word __error +NVIC_CCR: .word 0xE000ED14 @ NVIC configuration control register diff --git a/libmaple/util.c b/libmaple/util.c index 481cd60..3408a2e 100644 --- a/libmaple/util.c +++ b/libmaple/util.c @@ -49,14 +49,14 @@ #define HAVE_ERROR_LED #endif -/* Error assert + fade */ -void _fail(const char* file, int line, const char* exp) { - int32 slope = 1; - uint32 CC = 0x0000; - uint32 TOP_CNT = 0x02FF; - uint32 i = 0; - - /* Turn off interrupts */ +/** + * @brief Disables all peripheral interrupts except USB and fades the + * error LED. + * + * Called from exc.S with global interrupts disabled. + */ +void __error(void) { + /* Turn off peripheral interrupts */ nvic_irq_disable_all(); /* Turn off timers */ @@ -68,6 +68,24 @@ void _fail(const char* file, int line, const char* exp) { /* Turn off all usarts */ usart_disable_all(); + /* Turn the USB interrupt back on so the bootloader keeps on functioning */ + nvic_irq_enable(NVIC_INT_USBHP); + nvic_irq_enable(NVIC_INT_USBLP); + + /* Reenable global interrupts */ + nvic_globalirq_enable(); + throb(); +} + +/** + * @brief Prints an error message on a uart upon a failed assertion + * and error throbs. + * @param file Source file of failed assertion + * @param line Source line of failed assertion + * @param exp String representation of failed assertion + * @sideeffect Turns of all peripheral interrupts except USB. + */ +void _fail(const char* file, int line, const char* exp) { /* Initialize the error usart */ gpio_set_mode(ERROR_TX_PORT, ERROR_TX_PIN, GPIO_MODE_AF_OUTPUT_PP); usart_init(ERROR_USART_NUM, ERROR_USART_BAUD); @@ -82,19 +100,15 @@ void _fail(const char* file, int line, const char* exp) { usart_putc(ERROR_USART_NUM, '\n'); usart_putc(ERROR_USART_NUM, '\r'); -#ifdef HAVE_ERROR_LED - /* Turn on the error LED */ - gpio_set_mode(ERROR_LED_PORT, ERROR_LED_PIN, GPIO_MODE_OUTPUT_PP); -#endif - - /* Turn the USB interrupt back on so the bootloader keeps on functioning */ - nvic_irq_enable(NVIC_INT_USBHP); - nvic_irq_enable(NVIC_INT_USBLP); - /* Error fade */ - throb(); + __error(); } + +/** + * @brief Fades the error LED on and off + * @sideeffect Sets output push-pull on ERROR_LED_PIN. + */ void throb(void) { #ifdef HAVE_ERROR_LED int32 slope = 1; diff --git a/libmaple/util.h b/libmaple/util.h index 28ce970..fb524c2 100644 --- a/libmaple/util.h +++ b/libmaple/util.h @@ -79,6 +79,7 @@ extern "C"{ #define __write(reg, value) (*(volatile uint32*)(reg) = (value)) #define IS_POWER_OF_TWO(v) (v && !(v & (v - 1))) +void __error(void); void _fail(const char*, int, const char*); void throb(void); -- cgit v1.2.3 From 3d455ef619036b2cc77a87b715cf1d45c95ce271 Mon Sep 17 00:00:00 2001 From: Perry Hung Date: Sun, 27 Feb 2011 18:32:50 -0500 Subject: Also disable systick handler in exception path. --- libmaple/exc.S | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/libmaple/exc.S b/libmaple/exc.S index 823bbc5..f31fccd 100644 --- a/libmaple/exc.S +++ b/libmaple/exc.S @@ -80,6 +80,9 @@ __default_exc: mov r1 ,#1 @ exception. See flag NONEBASETHRDENA. str r1, [r2] cpsid i @ Disable global interrupts + ldr r2, SYSTICK_CSR @ Disable systick handler + mov r1, #0 + str r1, [r2] ldr r1, CPSR_MASK @ Set default CPSR push {r1} ldr r1, TARGET_PC @ Set target pc @@ -90,8 +93,9 @@ __default_exc: bx lr @ Exception exit .align 4 -CPSR_MASK: .word 0x61000000 -EXC_RETURN: .word 0xFFFFFFF9 -TARGET_PC: .word __error -NVIC_CCR: .word 0xE000ED14 @ NVIC configuration control register +CPSR_MASK: .word 0x61000000 +EXC_RETURN: .word 0xFFFFFFF9 +TARGET_PC: .word __error +NVIC_CCR: .word 0xE000ED14 @ NVIC configuration control register +SYSTICK_CSR: .word 0xE000E010 @ Systick control register -- cgit v1.2.3 From 17aeb4e3dd9001ebe63a342c00b58cb7ac0e6231 Mon Sep 17 00:00:00 2001 From: Perry Hung Date: Sun, 27 Feb 2011 20:20:11 -0500 Subject: comment fix --- libmaple/exc.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libmaple/exc.S b/libmaple/exc.S index f31fccd..7631e48 100644 --- a/libmaple/exc.S +++ b/libmaple/exc.S @@ -76,8 +76,8 @@ __exc_usagefault: .thumb_func __default_exc: - ldr r2, NVIC_CCR @ Enabling returning to thread mode from an - mov r1 ,#1 @ exception. See flag NONEBASETHRDENA. + ldr r2, NVIC_CCR @ Enable returning to thread mode even if there are + mov r1 ,#1 @ pending exceptions. See flag NONEBASETHRDENA. str r1, [r2] cpsid i @ Disable global interrupts ldr r2, SYSTICK_CSR @ Disable systick handler -- cgit v1.2.3 From 0b9559f8a7fa755cf62093ff72c3c7c5f204c0a0 Mon Sep 17 00:00:00 2001 From: Perry Hung Date: Tue, 1 Mar 2011 12:27:59 -0500 Subject: Add 24LC256 EEPROM example. --- main.cpp | 32 +++++++------------------------- 1 file changed, 7 insertions(+), 25 deletions(-) diff --git a/main.cpp b/main.cpp index 0480b5d..5e3ddf3 100644 --- a/main.cpp +++ b/main.cpp @@ -1,5 +1,5 @@ -// Sample main.cpp file. Blinks the built-in LED, sends a message out -// USART2, and turns on PWM on pin 2. +// Sample i2c master example for development i2c branch. Writes 0-63 to +// addresses 0-63 on a 24LC256 EEPROM, then reads them back. #include "wirish.h" #include "i2c.h" @@ -17,50 +17,32 @@ void setup() { pinMode(BOARD_LED_PIN, OUTPUT); - i2c_master_enable(I2C1, 0); for (i = 0; i < sizeof buf0; i++) { buf0[i + 2] = i & 0xFF; } -#if 0 + i2c_master_enable(I2C1, 0); + /* Write some bytes */ msgs[0].addr = slave_address; msgs[0].flags = 0; msgs[0].length = sizeof buf0; msgs[0].data = buf0; - i2c_master_xfer(I2C1, msgs, 1); delay(5); - return; -#endif + /* Write slave address to read */ msgs[1].addr = slave_address; msgs[1].flags = 0; - msgs[1].length = sizeof buf1; + msgs[1].length = 2; msgs[1].data = buf1; + /* Repeated start condition, then read NR_ELEMENTS bytes back */ msgs[2].addr = slave_address; msgs[2].flags = I2C_MSG_READ; msgs[2].length = sizeof buf2; msgs[2].data = buf2; i2c_master_xfer(I2C1, msgs + 1, 2); -#if 0 - for (i = 0; i < 256; i++) { - /* Read it back */ - buf1[1] = i; - msgs[1].addr = slave_address; - msgs[1].flags = 0; - msgs[1].length = 2; - msgs[1].data = buf1; - - msgs[2].addr = slave_address; - msgs[2].flags = I2C_MSG_READ; - msgs[2].length = 1; - msgs[2].data = buf2; - i2c_master_xfer(I2C1, msgs + 1, 2); - delay(10); - } -#endif } void loop() { -- cgit v1.2.3 From 07536e9a1a92af2b1bad8f32b1b0f6b868957d26 Mon Sep 17 00:00:00 2001 From: Perry Hung Date: Tue, 1 Mar 2011 12:33:59 -0500 Subject: Rename i2c irq handler to new naming convention. --- libmaple/i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmaple/i2c.c b/libmaple/i2c.c index 2064723..1a595f5 100644 --- a/libmaple/i2c.c +++ b/libmaple/i2c.c @@ -261,7 +261,7 @@ static void i2c_irq_handler(i2c_dev *dev) { } } -void I2C1_EV_IRQHandler(void) { +void __irq_i2c1_ev(void) { i2c_dev *dev = I2C1; i2c_irq_handler(dev); } -- cgit v1.2.3 From 4c8ab9d1717002d5faad9c2af6db6d12da761ec9 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Wed, 2 Mar 2011 00:07:10 -0500 Subject: Fixing typo in main.cpp.example. --- main.cpp.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.cpp.example b/main.cpp.example index 8fc522a..3ae114b 100644 --- a/main.cpp.example +++ b/main.cpp.example @@ -27,7 +27,7 @@ void loop() { } // Force init to be called *first*, i.e. before static object allocation. -// Otherwise, statically allocated object that need libmaple may fail. +// Otherwise, statically allocated objects that need libmaple may fail. __attribute__(( constructor )) void premain() { init(); } -- cgit v1.2.3 From 91f1b596c63407aaea9a1d17d31243c47b4f8d20 Mon Sep 17 00:00:00 2001 From: Perry Hung Date: Wed, 2 Mar 2011 00:30:19 -0500 Subject: cscope: Find .S instead of .s files --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 149f54a..01e1e72 100644 --- a/Makefile +++ b/Makefile @@ -153,7 +153,7 @@ debug: cscope: rm -rf *.cscope - find . -name '*.[hcs]' -o -name '*.cpp' | xargs cscope -b + find . -name '*.[hcS]' -o -name '*.cpp' | xargs cscope -b tags: etags `find . -name "*.c" -o -name "*.cpp" -o -name "*.h"` -- cgit v1.2.3 From 1decaa2d7baacd9af10694255c4efad783815f51 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Fri, 4 Mar 2011 19:15:24 -0500 Subject: Untabifying docs/source/conf.py --- docs/source/conf.py | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 1ad4e57..f232b7c 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -117,25 +117,25 @@ html_theme = 'default' # further. For a list of options available for each theme, see the # documentation. html_theme_options = { - ## Sidebar placement options - #'stickysidebar' : 'true', - 'rightsidebar' : 'true', - #'collapsiblesidebar' : 'true', - - ## Color - 'sidebarbgcolor' : '#C8C8C8', - 'sidebarlinkcolor' : 'green', - 'sidebartextcolor' : 'black', + ## Sidebar placement options + #'stickysidebar' : 'true', + 'rightsidebar' : 'true', + #'collapsiblesidebar' : 'true', + + ## Color + 'sidebarbgcolor' : '#C8C8C8', + 'sidebarlinkcolor' : 'green', + 'sidebartextcolor' : 'black', #'sidebarbtncolor' : 'black', - 'footerbgcolor' : 'green', - 'relbarbgcolor' : 'green', - 'headlinkcolor' : '#000000', - 'linkcolor' : 'green', - 'visitedlinkcolor' : 'green', - - ## Font - 'headfont' : 'Georgia', - 'bodyfont' : 'Lucidia' + 'footerbgcolor' : 'green', + 'relbarbgcolor' : 'green', + 'headlinkcolor' : '#000000', + 'linkcolor' : 'green', + 'visitedlinkcolor' : 'green', + + ## Font + 'headfont' : 'Georgia', + 'bodyfont' : 'Lucidia' } # Add any paths that contain custom themes here, relative to this directory. @@ -174,7 +174,7 @@ html_last_updated_fmt = '%b %d, %Y' # re-add commented line when custom template for api finished html_sidebars = { '**': ['globaltoc.html', 'searchbox.html'], - #'lang/api**':['searchbox.html', 'apilist.html'], + #'lang/api**':['searchbox.html', 'apilist.html'], } -- cgit v1.2.3 From 52d5cc53307cce58c86aa74ccd9010bbad59ff63 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Fri, 4 Mar 2011 19:16:07 -0500 Subject: Cosmetic changes to wirish/main.cxx --- wirish/main.cxx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/wirish/main.cxx b/wirish/main.cxx index f0158f8..dd5e296 100644 --- a/wirish/main.cxx +++ b/wirish/main.cxx @@ -1,4 +1,4 @@ -/* ***************************************************************************** +/****************************************************************************** * The MIT License * * Copyright (c) 2010 LeafLabs LLC. @@ -20,16 +20,15 @@ * 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. - * ****************************************************************************/ + *****************************************************************************/ // Force init to be called *first*, i.e. before static object allocation. -// Otherwise, statically allocated object that need libmaple may fail. +// Otherwise, statically allocated objects that need libmaple may fail. __attribute__(( constructor )) void premain() { init(); } -int main(void) -{ +int main(void) { setup(); while (1) { -- cgit v1.2.3 From 7973deea3908f4f865f59c5e2df1eef6810cc70e Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Fri, 4 Mar 2011 19:16:42 -0500 Subject: Cosmetic/documentation changes to adc.c --- libmaple/adc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libmaple/adc.c b/libmaple/adc.c index cd71118..a464746 100644 --- a/libmaple/adc.c +++ b/libmaple/adc.c @@ -23,6 +23,8 @@ *****************************************************************************/ /** + * @file adc.c + * * @brief Analog to digital converter routines * * IMPORTANT: maximum external impedance must be below 0.4kOhms for 1.5 @@ -30,7 +32,7 @@ * * At 55.5 cycles/sample, the external input impedance < 50kOhms. * - * See stm32 manual RM008 for how to calculate this. + * See STM32 manual RM0008 for how to calculate this. */ #include "libmaple.h" -- cgit v1.2.3 From 02e76ec27b5737bce836a5460427b538076f01ef Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Fri, 4 Mar 2011 20:25:26 -0500 Subject: Brought examples/ up to date; PIN_MAP bugfix for D24. --- examples/blinky.cpp | 6 +- examples/debug-dtrrts.cpp | 23 ++--- examples/qa-slave-shield.cpp | 45 ++++----- examples/spi_master.cpp | 7 +- examples/test-bkp.cpp | 2 +- examples/test-dac.cpp | 4 - examples/test-fsmc.cpp | 22 ++--- examples/test-serial-flush.cpp | 18 +--- examples/test-serialusb.cpp | 74 +++++++------- examples/test-systick.cpp | 50 +++++----- examples/test-timers.cpp | 68 ++++++------- examples/vga-leaf.cpp | 162 +++++++++++++++++++------------ examples/vga-scope.cpp | 212 ++++++++++++++++++++++++++--------------- wirish/boards.h | 2 +- 14 files changed, 381 insertions(+), 314 deletions(-) diff --git a/examples/blinky.cpp b/examples/blinky.cpp index 5611987..209a6e6 100644 --- a/examples/blinky.cpp +++ b/examples/blinky.cpp @@ -1,4 +1,4 @@ -// Blinks the LED, pin 13 +// Blinks the built-in LED #include "wirish.h" @@ -20,8 +20,8 @@ void loop() { } // Force init to be called *first*, i.e. before static object allocation. -// Otherwise, statically allocated object that need libmaple may fail. - __attribute__(( constructor )) void premain() { +// Otherwise, statically allocated objects that need libmaple may fail. +__attribute__((constructor)) void premain() { init(); } diff --git a/examples/debug-dtrrts.cpp b/examples/debug-dtrrts.cpp index f9f8b96..61c061a 100644 --- a/examples/debug-dtrrts.cpp +++ b/examples/debug-dtrrts.cpp @@ -1,14 +1,12 @@ -// Sample main.cpp file. Blinks an LED, sends a message out USART2 -// and turns on PWM on pin 2 +// Test sketch for figuring out DTR/RTS behavior on different platforms. #include "wirish.h" #include "usb.h" -#define LED_PIN 13 -#define PWM_PIN 2 +#define LED_PIN BOARD_LED_PIN +#define PWM_PIN 2 -void setup() -{ +void setup() { /* Set up the LED to blink */ pinMode(LED_PIN, OUTPUT); @@ -18,12 +16,10 @@ void setup() } -int toggle = 0; - void loop() { - toggle ^= 1; - digitalWrite(LED_PIN, toggle); + toggleLED(); delay(100); + Serial2.print("DTR: "); Serial2.print(usbGetDTR(), DEC); Serial2.print("\tRTS: "); @@ -31,13 +27,12 @@ void loop() { } // Force init to be called *first*, i.e. before static object allocation. -// Otherwise, statically allocated object that need libmaple may fail. - __attribute__(( constructor )) void premain() { +// Otherwise, statically allocated objects that need libmaple may fail. +__attribute__((constructor)) void premain() { init(); } -int main(void) -{ +int main(void) { setup(); while (1) { diff --git a/examples/qa-slave-shield.cpp b/examples/qa-slave-shield.cpp index b395cca..178b780 100644 --- a/examples/qa-slave-shield.cpp +++ b/examples/qa-slave-shield.cpp @@ -1,50 +1,51 @@ -// slave mode for QA shield +// Slave mode for QA shield #include "wirish.h" -#define LED_PIN 13 -#define NUM_GPIO 38 // not the number of the max... +// FIXME generalize for Maple Native, Maple Mini (NUM_GPIO, Mini USB +// breakout pins, etc.) -int i; +#define LED_PIN BOARD_LED_PIN +#define NUM_GPIO 38 // Ignore JTAG pins. -void setup() -{ +void setup() { /* Set up the LED to blink */ pinMode(LED_PIN, OUTPUT); - digitalWrite(LED_PIN, 1); + digitalWrite(LED_PIN, HIGH); - for(i=0; i +#include // for snprintf() #include "wirish.h" #include "bkp.h" diff --git a/examples/test-dac.cpp b/examples/test-dac.cpp index 62f40eb..af98030 100644 --- a/examples/test-dac.cpp +++ b/examples/test-dac.cpp @@ -1,8 +1,4 @@ - #include "wirish.h" -#include "fsmc.h" -#include "rcc.h" -#include "gpio.h" #include "dac.h" uint16 count = 0; diff --git a/examples/test-fsmc.cpp b/examples/test-fsmc.cpp index f4fd068..4211e4d 100644 --- a/examples/test-fsmc.cpp +++ b/examples/test-fsmc.cpp @@ -1,14 +1,12 @@ - #include "wirish.h" #include "fsmc.h" -#define LED_PIN 23 // hack for maple native -#define DISC_PIN 14 // hack for USB on native +#define LED_PIN BOARD_LED_PIN // System control block registers #define SCB_BASE (SCB_Reg*)(0xE000ED00) -// This stuff should ultimately get moved to util.h or scb.h or w/e. +// This stuff should ultimately get moved to util.h or scb.h or w/e. // Also in interactive test program and the HardFault IRQ handler. typedef struct { volatile uint32 CPUID; @@ -23,15 +21,14 @@ typedef struct { volatile uint32 SHCRS; volatile uint32 CFSR; volatile uint32 HFSR; - uint32 pad1; + uint32 pad1; volatile uint32 MMAR; volatile uint32 BFAR; } SCB_Reg; -SCB_Reg *scb; +SCB_Reg *scb; uint16 *ptr; -int toggle = 0; int count = 0; void setup() { @@ -39,8 +36,6 @@ void setup() { scb = (SCB_Reg*)SCB_BASE; pinMode(LED_PIN, OUTPUT); - pinMode(DISC_PIN, OUTPUT); - digitalWrite(DISC_PIN,1); digitalWrite(LED_PIN,1); Serial1.begin(9600); @@ -82,15 +77,14 @@ void setup() { Serial1.print("BFAR: "); id = scb->BFAR; Serial1.println(id,BIN); - + Serial1.println("Now testing all memory addresses... (will hardfault at the end)"); delay(3000); } void loop() { - digitalWrite(LED_PIN, toggle); - toggle ^= 1; - delay(1); + toggleLED(); + delay(1); for(int i = 0; i<100; i++) { // modify this to speed things up count++; @@ -102,7 +96,7 @@ void loop() { while(1) { } } } - + Serial1.print((uint32)(ptr),HEX); Serial1.print(": "); Serial1.println(*ptr,BIN); diff --git a/examples/test-serial-flush.cpp b/examples/test-serial-flush.cpp index d7fbf7a..1cd82b6 100644 --- a/examples/test-serial-flush.cpp +++ b/examples/test-serial-flush.cpp @@ -2,22 +2,13 @@ #include "wirish.h" -void setup() -{ +void setup() { /* Send a message out USART2 */ Serial2.begin(9600); Serial2.println("Hello world!"); } -int toggle = 0; - void loop() { - - Serial2.println("This is the first line."); - Serial2.end(); - Serial2.println("This is the second line."); - - Serial2.begin(9600); Serial2.println("Waiting for multiple input..."); while(Serial2.available() < 5) { } Serial2.println(Serial2.read()); @@ -29,13 +20,12 @@ void loop() { } // Force init to be called *first*, i.e. before static object allocation. -// Otherwise, statically allocated object that need libmaple may fail. - __attribute__(( constructor )) void premain() { +// Otherwise, statically allocated objects that need libmaple may fail. +__attribute__((constructor)) void premain() { init(); } -int main(void) -{ +int main(void) { setup(); while (1) { diff --git a/examples/test-serialusb.cpp b/examples/test-serialusb.cpp index 9d0a862..678c2b9 100644 --- a/examples/test-serialusb.cpp +++ b/examples/test-serialusb.cpp @@ -1,11 +1,10 @@ -// Sample main.cpp file. Blinks an LED, sends a message out USART2 -// and turns on PWM on pin 2 +// Tests SerialUSB functionality. #include "wirish.h" #include "usb.h" -#define LED_PIN 13 -#define BUT_PIN 38 +#define LED_PIN BOARD_LED_PIN +#define BUT_PIN BOARD_BUTTON_PIN uint32 state = 0; #define QUICKPRINT 0 @@ -14,33 +13,29 @@ uint32 state = 0; #define SIMPLE 3 #define ONOFF 4 - -void setup() -{ +void setup() { /* Set up the LED to blink */ pinMode(LED_PIN, OUTPUT); /* Set up the Button */ - pinMode(BUT_PIN, INPUT_PULLUP); + pinMode(BUT_PIN, INPUT); Serial2.begin(9600); - Serial2.println("Hello world! This is the debug channel."); -} + Serial2.println("This is the debug channel. Press BUT."); -int toggle = 0; + waitForButtonPress(0); +} uint8 c1 = '-'; void loop() { - toggle ^= 1; - digitalWrite(LED_PIN, toggle); + toggleLED(); delay(1000); - if(digitalRead(BUT_PIN)) { - while(digitalRead(BUT_PIN)) {}; + if(isButtonPressed()) { state++; } - + switch(state) { case QUICKPRINT: for(int i = 0; i<30; i++) { @@ -48,34 +43,34 @@ void loop() { SerialUSB.print('.'); SerialUSB.print('|'); } - Serial2.println(SerialUSB.pending(),DEC); + Serial2.println(SerialUSB.pending(), DEC); SerialUSB.println(); break; case BIGSTUFF: - SerialUSB.println("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"); - SerialUSB.println((uint32)123456789,DEC); + SerialUSB.println("0123456789012345678901234567890123456789" + "0123456789012345678901234567890123456789" + "012345678901234567890"); + SerialUSB.println((int64)123456789, DEC); SerialUSB.println(3.1415926535); - Serial2.println(SerialUSB.pending(),DEC); + Serial2.println(SerialUSB.pending(), DEC); break; case NUMBERS: SerialUSB.println("Numbers! -----------------------------"); Serial2.println("Numbers! -----------------------------"); SerialUSB.println('1'); Serial2.println('1'); - SerialUSB.println(1,DEC); - Serial2.println(1,DEC); - SerialUSB.println(-1,DEC); - Serial2.println(-1,DEC); + SerialUSB.println(1, DEC); + Serial2.println(1, DEC); + SerialUSB.println(-1, DEC); + Serial2.println(-1, DEC); SerialUSB.println(3.14159265); Serial2.println(3.14159265); - SerialUSB.println(3.14159265,9); - Serial2.println(3.14159265,9); - SerialUSB.println(123456789,DEC); - Serial2.println(123456789,DEC); - SerialUSB.println(-123456789,DEC); - Serial2.println(-123456789,DEC); - SerialUSB.println(65535,HEX); - Serial2.println(65535,HEX); + SerialUSB.println(123456789, DEC); + Serial2.println(123456789, DEC); + SerialUSB.println(-123456789, DEC); + Serial2.println(-123456789, DEC); + SerialUSB.println(65535, HEX); + Serial2.println(65535, HEX); break; case SIMPLE: Serial2.println("Trying write('a')"); @@ -92,8 +87,8 @@ void loop() { SerialUSB.print("hij\n\r"); SerialUSB.write(' '); SerialUSB.println(); - Serial2.println("Trying println(123456789,DEC)"); - SerialUSB.println(123456789); + Serial2.println("Trying println(123456789, DEC)"); + SerialUSB.println(123456789, DEC); Serial2.println("Trying println(3.141592)"); SerialUSB.println(3.141592); Serial2.println("Trying println(\"DONE\")"); @@ -103,12 +98,12 @@ void loop() { Serial2.println("Shutting down..."); SerialUSB.println("Shutting down..."); SerialUSB.end(); - Serial2.println("Waiting 4seconds..."); + Serial2.println("Waiting 4 seconds..."); delay(4000); Serial2.println("Starting up..."); SerialUSB.begin(); SerialUSB.println("Hello World!"); - Serial2.println("Waiting 4seconds..."); + Serial2.println("Waiting 4 seconds..."); delay(4000); state++; break; @@ -118,13 +113,12 @@ void loop() { } // Force init to be called *first*, i.e. before static object allocation. -// Otherwise, statically allocated object that need libmaple may fail. - __attribute__(( constructor )) void premain() { +// Otherwise, statically allocated objects that need libmaple may fail. +__attribute__((constructor)) void premain() { init(); } -int main(void) -{ +int main(void) { setup(); while (1) { diff --git a/examples/test-systick.cpp b/examples/test-systick.cpp index 247892d..c7b5529 100644 --- a/examples/test-systick.cpp +++ b/examples/test-systick.cpp @@ -3,54 +3,48 @@ #include "wirish.h" #include "systick.h" -#define LED_PIN 13 -#define PWM_PIN 2 -#define BUT 38 +#define LED_PIN BOARD_LED_PIN +#define PWM_PIN 2 +#define BUT BOARD_BUTTON_PIN -void setup() -{ +void setup() { /* Set up the LED to blink */ pinMode(LED_PIN, OUTPUT); - - /* Turn on PWM on pin PWM_PIN */ - pinMode(PWM_PIN, PWM); - pwmWrite(PWM_PIN, 0x8000); - - pinMode(BUT, INPUT_PULLDOWN); + pinMode(BUT, INPUT); } -int toggle = 0; +bool disable = true; long time = 0; void loop() { - toggle ^= 1; - digitalWrite(LED_PIN, toggle); + volatile int i = 0; + toggleLED(); // An artificial delay - int16 i = 1; - float j = 1; - for(i=0; i<6553; i++) { - j = sqrt(j) + 1; - } - - if(digitalRead(BUT)) { - systick_disable(); - } else { - systick_resume(); + for(i = 0; i < 150000; i++) + ; + + if(isButtonPressed()) { + if (disable) { + systick_disable(); + SerialUSB.println("Disabling SysTick"); + } else { + SerialUSB.println("Re-enabling SysTick"); + systick_resume(); + } + disable = !disable; } - //SerialUSB.println(micros()); // there is a bug with this SerialUSB.println(millis()); } // Force init to be called *first*, i.e. before static object allocation. // Otherwise, statically allocated object that need libmaple may fail. - __attribute__(( constructor )) void premain() { +__attribute__((constructor)) void premain() { init(); } -int main(void) -{ +int main(void) { setup(); while (1) { diff --git a/examples/test-timers.cpp b/examples/test-timers.cpp index ccba251..f3cfdcc 100644 --- a/examples/test-timers.cpp +++ b/examples/test-timers.cpp @@ -2,7 +2,7 @@ #include "wirish.h" -#define LED_PIN 13 +#define LED_PIN BOARD_LED_PIN void handler1(void); void handler2(void); @@ -12,7 +12,6 @@ void handler4(void); void handler3b(void); void handler4b(void); -int toggle = 0; int t; int count1 = 0; @@ -36,25 +35,24 @@ void setup() pinMode(LED_PIN, OUTPUT); // Setup the button as input - pinMode(38, INPUT_PULLUP); + pinMode(BOARD_BUTTON_PIN, INPUT); - /* Send a message out USART2 */ - //SerialUSB.begin(9600); - SerialUSB.println("Begining timer test..."); + // Wait for user to attach... + waitForButtonPress(0); + + // Send a message out SerialUSB + SerialUSB.println("Beginning timer test..."); for(int t=0; t<4; t++) { Timers[t].setChannel1Mode(TIMER_OUTPUTCOMPARE); Timers[t].setChannel2Mode(TIMER_OUTPUTCOMPARE); Timers[t].setChannel3Mode(TIMER_OUTPUTCOMPARE); Timers[t].setChannel4Mode(TIMER_OUTPUTCOMPARE); } - - // Wait for user to attach... - delay(2000); } void loop() { SerialUSB.println("-----------------------------------------------------"); - SerialUSB.println("Testing setCount/getCount"); + SerialUSB.println("Testing setCount/getCount"); SerialUSB.print("Timer1.getCount() = "); SerialUSB.println(Timer1.getCount()); SerialUSB.println("Timer1.setCount(1234)"); Timer1.setCount(1234); @@ -63,7 +61,7 @@ void loop() { // down Timer4 is in the "pause" state and the timer doesn't increment, so // the final counts should reflect the ratio of time that BUT was held down SerialUSB.println("-----------------------------------------------------"); - SerialUSB.println("Testing Pause/Resume; button roughly controls Timer4"); + SerialUSB.println("Testing Pause/Resume; button roughly controls Timer4"); count3 = 0; count4 = 0; Timer3.setChannel1Mode(TIMER_OUTPUTCOMPARE); @@ -80,9 +78,9 @@ void loop() { Timer4.attachCompare1Interrupt(handler4b); Timer3.resume(); Timer4.resume(); - SerialUSB.println("~4 seconds..."); + SerialUSB.println("~4 seconds..."); for(int i = 0; i<4000; i++) { - if(digitalRead(38)) { + if(isButtonPressed()) { Timer4.pause(); } else { Timer4.resume(); @@ -96,14 +94,14 @@ void loop() { // These test the setPeriod auto-configure functionality SerialUSB.println("-----------------------------------------------------"); - SerialUSB.println("Testing setPeriod"); + SerialUSB.println("Testing setPeriod"); Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE); Timer4.setCompare1(1); - Timer4.setPeriod(10); + Timer4.setPeriod(10); Timer4.pause(); Timer4.setCount(0); Timer4.attachCompare1Interrupt(handler4b); - SerialUSB.println("Period 10ms, wait 2 seconds..."); + SerialUSB.println("Period 10ms, wait 2 seconds..."); count4 = 0; Timer4.resume(); delay(2000); @@ -114,10 +112,10 @@ void loop() { Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE); Timer4.setCompare1(1); Timer4.pause(); - Timer4.setPeriod(30000); + Timer4.setPeriod(30000); Timer4.setCount(0); Timer4.attachCompare1Interrupt(handler4b); - SerialUSB.println("Period 30000ms, wait 2 seconds..."); + SerialUSB.println("Period 30000ms, wait 2 seconds..."); count4 = 0; Timer4.resume(); delay(2000); @@ -127,12 +125,12 @@ void loop() { SerialUSB.println("(should be around 2sec/30000ms ~ 67)"); Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE); - Timer4.setPeriod(300000); + Timer4.setPeriod(300000); Timer4.setCompare1(1); Timer4.pause(); Timer4.setCount(0); Timer4.attachCompare1Interrupt(handler4b); - SerialUSB.println("Period 300000ms, wait 2 seconds..."); + SerialUSB.println("Period 300000ms, wait 2 seconds..."); count4 = 0; Timer4.resume(); delay(2000); @@ -146,9 +144,9 @@ void loop() { Timer4.setOverflow(65454); Timer4.pause(); Timer4.setCount(0); - Timer4.setCompare1(1); + Timer4.setCompare1(1); Timer4.attachCompare1Interrupt(handler4b); - SerialUSB.println("Period 30000ms, wait 2 seconds..."); + SerialUSB.println("Period 30000ms, wait 2 seconds..."); count4 = 0; Timer4.resume(); delay(2000); @@ -159,11 +157,11 @@ void loop() { Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE); Timer4.setCompare1(1); - Timer4.setPeriod(30000); + Timer4.setPeriod(30000); Timer4.pause(); Timer4.setCount(0); Timer4.attachCompare1Interrupt(handler4b); - SerialUSB.println("Period 30000ms, wait 2 seconds..."); + SerialUSB.println("Period 30000ms, wait 2 seconds..."); count4 = 0; Timer4.resume(); delay(2000); @@ -177,7 +175,7 @@ void loop() { // that over time the actual timing rates get blown away by other system // interrupts. for(t=0; t<4; t++) { - toggle ^= 1; digitalWrite(LED_PIN, toggle); + toggleLED(); delay(100); SerialUSB.println("-----------------------------------------------------"); SerialUSB.print("Testing Timer "); SerialUSB.println(t+1); @@ -214,33 +212,39 @@ void handler1(void) { val1 += rate1; Timers[t].setCompare1(val1); count1++; -} +} + void handler2(void) { val2 += rate2; Timers[t].setCompare2(val2); count2++; -} +} + void handler3(void) { val3 += rate3; Timers[t].setCompare3(val3); count3++; -} +} + void handler4(void) { val4 += rate4; Timers[t].setCompare4(val4); count4++; -} +} void handler3b(void) { count3++; -} +} + void handler4b(void) { count4++; -} +} +__attribute__((constructor)) void premain() { + init(); +} int main(void) { - init(); setup(); while (1) { diff --git a/examples/vga-leaf.cpp b/examples/vga-leaf.cpp index d1c6d7d..9d9fce2 100644 --- a/examples/vga-leaf.cpp +++ b/examples/vga-leaf.cpp @@ -1,21 +1,21 @@ /* - Crude VGA Output + VGA Output - Outputs a red and white leaf to VGA. This implementation is crude and noisy, - but a fun demo. It should run most VGA monitors at 640x480, though it does - not follow the timing spec very carefully. Real twisted or shielded wires, - proper grounding, and not doing this on a breadboard are recommended (but - it seems to work ok without). + Outputs a red and white leaf to VGA. It should run most VGA monitors + at 640x480, though it does not follow the timing spec very + carefully. Real twisted or shielded wires, proper grounding, and not + doing this on a breadboard are recommended (but it seems to work ok + without). - SerialUSB is disabled to get rid of most interrupts (which mess with timing); - the SysTick is probably the source of the remaining flickers. This means that - you have to use perpetual bootloader or the reset button to flash new - programs. + SerialUSB and SysTick are disabled to get rid of the most frequently + occurring interrupts (which mess with timing). This means that you + have to use perpetual bootloader mode or the reset button to flash + new programs. How to wire this to a VGA port: - D5 via ~200ohms to VGA Red (1) - D6 via ~200ohms to VGA Green (2) - D7 via ~200ohms to VGA Blue (3) + D6 via ~200ohms to VGA Red (1) + D7 via ~200ohms to VGA Green (2) + D8 via ~200ohms to VGA Blue (3) D11 to VGA VSync (14) (swapped?) D12 to VGA HSync (13) (swapped?) GND to VGA Ground (5) @@ -24,48 +24,71 @@ See also: - http://pinouts.ru/Video/VGA15_pinout.shtml - http://www.epanorama.net/documents/pc/vga_timing.html - + Created 20 July 2010 By Bryan Newbold for LeafLabs This code is released with no strings attached. - + + Modified 4 March 2011 + By Marti Bolivar + Disabled SysTick, kept up-to-date with libmaple. */ +// FIXME: generalize for Native and Mini + #include "wirish.h" -#define LED_PIN 13 +#define LED_PIN BOARD_LED_PIN -// Pinouts -#define VGA_R 5 // STM32: B6 -#define VGA_G 6 // STM32: A8 -#define VGA_B 7 // STM32: A9 +// Pinouts -- you also must change the GPIO macros below if you change +// these +#define VGA_R 6 // STM32: A8 +#define VGA_G 7 // STM32: A9 +#define VGA_B 8 // STM32: A10 #define VGA_V 11 // STM32: A6 #define VGA_H 12 // STM32: A7 -// These low level macros make GPIO writes much faster -#define VGA_R_HIGH (GPIOB_BASE)->BSRR = BIT(6) -#define VGA_R_LOW (GPIOB_BASE)->BRR = BIT(6) -#define VGA_G_HIGH (GPIOA_BASE)->BSRR = BIT(8) -#define VGA_G_LOW (GPIOA_BASE)->BRR = BIT(8) -#define VGA_B_HIGH (GPIOA_BASE)->BSRR = BIT(9) -#define VGA_B_LOW (GPIOA_BASE)->BRR = BIT(9) -#define VGA_V_HIGH (GPIOA_BASE)->BSRR = BIT(6) -#define VGA_V_LOW (GPIOA_BASE)->BRR = BIT(6) -#define VGA_H_HIGH (GPIOA_BASE)->BSRR = BIT(7) -#define VGA_H_LOW (GPIOA_BASE)->BRR = BIT(7) +// These low level (and STM32 specific) macros make GPIO writes much +// faster +#define ABSRR ((volatile uint32*)0x40010810) +#define ABRR ((volatile uint32*)0x40010814) + +#define RBIT 8 // (see pinouts) +#define GBIT 9 +#define BBIT 10 + +#define VGA_R_HIGH *ABSRR = BIT(RBIT) +#define VGA_R_LOW *ABRR = BIT(RBIT) +#define VGA_G_HIGH *ABSRR = BIT(GBIT) +#define VGA_G_LOW *ABRR = BIT(GBIT) +#define VGA_B_HIGH *ABSRR = BIT(BBIT) +#define VGA_B_LOW *ABRR = BIT(BBIT) + +#define ON_COLOR BIT(RBIT) +#define OFF_COLOR (BIT(RBIT) | BIT(GBIT) | BIT(BBIT)) + +// set has priority, so clear every bit and set some given bits: +#define VGA_COLOR(c) (*ABSRR = c | \ + BIT(RBIT+16) | BIT(GBIT+16) | BIT(BBIT+16)) + +#define VGA_V_HIGH *ABSRR = BIT(6) +#define VGA_V_LOW *ABRR = BIT(6) +#define VGA_H_HIGH *ABSRR = BIT(7) +#define VGA_H_LOW *ABRR = BIT(7) void isr_porch(void); void isr_start(void); void isr_stop(void); void isr_update(void); -uint8 toggle; uint16 x = 0; // X coordinate uint16 y = 0; // Y coordinate -uint8 v_active = 1; // Are we in the image? +uint16 logo_y = 0; // Y coordinate, mapped into valid logo index (for speed) +bool v_active = true; // Are we in the image? -// 1-bit! -uint8 logo[18][16] = { +const uint8 x_max = 16; +const uint8 y_max = 18; +uint32 logo[y_max][x_max] = { {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, {0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,}, {0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,}, @@ -99,9 +122,20 @@ void setup() { digitalWrite(VGA_H, HIGH); digitalWrite(VGA_V, HIGH); + // Fill the logo array with color patterns corresponding to its + // truth value. Note that we could get more tricky here, since + // there are 3 bits of color. + for (int y = 0; y < y_max; y++) { + for (int x = 0; x < x_max; x++) { + logo[y][x] = logo[y][x] ? ON_COLOR : OFF_COLOR; + } + } + // This gets rid of the majority of the interrupt artifacts; + // there's still a glitch for low values of y, but let's not worry + // about that. (Probably due to the hackish way vsync is done). SerialUSB.end(); - SystemTick.end(); + systick_disable(); // Configure Timer4.pause(); // while we configure @@ -120,14 +154,13 @@ void setup() { Timer4.attachCompare3Interrupt(isr_stop); Timer4.setCompare4(1); // Could be zero I guess Timer4.attachCompare4Interrupt(isr_update); - + Timer4.setCount(0); // Ready... Timer4.resume(); // Go! } void loop() { - toggle ^= 1; - digitalWrite(LED_PIN, toggle); + toggleLED(); delay(100); // Everything happens in the interrupts! @@ -139,51 +172,59 @@ void loop() { void isr_porch(void) { VGA_H_HIGH; y++; + logo_y = map(y, 0, 478, 0, y_max); // Back to the top - if(y>=523) { - y=1; - v_active = 1; + if(y >= 523) { + y = 1; + logo_y = 0; + v_active = true; return; } // Other vsync stuff below the image - if(y>=492) { + if(y >= 492) { VGA_V_HIGH; return; } - if(y>=490) { + if(y >= 490) { VGA_V_LOW; return; } - if(y>=479) { - v_active = 0; + if(y >= 479) { + v_active = false; return; } } // This is the main horizontal sweep -void isr_start(void) { +void isr_start(void) { // Skip if we're not in the image at all - if(!v_active) { return; } + if (!v_active) { + return; + } // Start Red VGA_R_LOW; VGA_R_HIGH; - // For each "pixel" (really 20 or so screen pixels?) go red or white - for(x=0; x<32; x++) { - if(logo[y/28][x/2]) { - VGA_G_HIGH; - VGA_B_HIGH; - } else { - VGA_G_LOW; - VGA_B_LOW; - } + // For each "pixel", go ON_COLOR or OFF_COLOR + for(x = 0; x < 16; x++) { + // setting the color several times is just an easy way to + // delay, so the image is wider. if you only do the following + // once, you'll be able to make the logo array a lot wider: + VGA_COLOR(logo[logo_y][x]); + VGA_COLOR(logo[logo_y][x]); + VGA_COLOR(logo[logo_y][x]); + VGA_COLOR(logo[logo_y][x]); + VGA_COLOR(logo[logo_y][x]); + VGA_COLOR(logo[logo_y][x]); } } // End of the horizontal line void isr_stop(void) { - if(!v_active) { return; } + if (!v_active) { + return; + } VGA_R_LOW; VGA_G_LOW; VGA_B_LOW; @@ -194,8 +235,11 @@ void isr_update(void) { VGA_H_LOW; } -int main(void) { +__attribute__((constructor)) void premain() { init(); +} + +int main(void) { setup(); while (1) { diff --git a/examples/vga-scope.cpp b/examples/vga-scope.cpp index 0265f9c..9c6dca5 100644 --- a/examples/vga-scope.cpp +++ b/examples/vga-scope.cpp @@ -1,34 +1,90 @@ -// Low-level, non-wirish demonstration of VGA -// -// Connect a microphone or something less to ANALOG_PIN +/* + VGA Oscilloscope demo. + + Connect a microphone or something like it to ANALOG_PIN (0V -- 3.3V + only; 0.2V -- 3.1V will probably look nicer); an attached VGA + monitor will display the signal roughly in real-time. + + The thick blue line corresponds roughly to 0V. + + This is a fairy crude hack, but it's fun to watch/toy around with. + + SerialUSB and SysTick are disabled to get rid of the most frequently + occurring interrupts (which mess with timing). This means that you + have to use perpetual bootloader mode or the reset button to flash + new programs. + + How to wire this to a VGA port: + D6 via ~200ohms to VGA Red (1) + D7 via ~200ohms to VGA Green (2) + D8 via ~200ohms to VGA Blue (3) + D11 to VGA VSync (14) (swapped?) + D12 to VGA HSync (13) (swapped?) + GND to VGA Ground (5) + GND to VGA Sync Ground (10) + + See also: + - http://pinouts.ru/Video/VGA15_pinout.shtml + - http://www.epanorama.net/documents/pc/vga_timing.html + + This code is released into the public domain. + */ #include "wirish.h" +#include "systick.h" + +// FIXME generalize for Native and Mini -#define LED_PIN 13 +#define LED_PIN BOARD_LED_PIN #define ANALOG_PIN 18 -#define VGA_R 5 // B6 -#define VGA_G 6 // A8 -#define VGA_B 7 // A9 -#define VGA_V 11 // A6 -#define VGA_H 12 // A7 -#define VGA_R_HIGH (GPIOB_BASE)->BSRR = BIT(6) -#define VGA_R_LOW (GPIOB_BASE)->BRR = BIT(6) -#define VGA_G_HIGH (GPIOA_BASE)->BSRR = BIT(8) -#define VGA_G_LOW (GPIOA_BASE)->BRR = BIT(8) -#define VGA_B_HIGH (GPIOA_BASE)->BSRR = BIT(9) -#define VGA_B_LOW (GPIOA_BASE)->BRR = BIT(9) -#define VGA_V_HIGH (GPIOA_BASE)->BSRR = BIT(6) -#define VGA_V_LOW (GPIOA_BASE)->BRR = BIT(6) -#define VGA_H_HIGH (GPIOA_BASE)->BSRR = BIT(7) -#define VGA_H_LOW (GPIOA_BASE)->BRR = BIT(7) + +// Pinouts -- you also must change the GPIO macros below if you change +// these +#define VGA_R 6 // STM32: A8 +#define VGA_G 7 // STM32: A9 +#define VGA_B 8 // STM32: A10 +#define VGA_V 11 // STM32: A6 +#define VGA_H 12 // STM32: A7 + +// These low level (and STM32 specific) macros make GPIO writes much +// faster +#define ABSRR ((volatile uint32*)0x40010810) +#define ABRR ((volatile uint32*)0x40010814) + +#define RBIT 8 // (see pinouts) +#define GBIT 9 +#define BBIT 10 + +#define VGA_R_HIGH *ABSRR = BIT(RBIT) +#define VGA_R_LOW *ABRR = BIT(RBIT) +#define VGA_G_HIGH *ABSRR = BIT(GBIT) +#define VGA_G_LOW *ABRR = BIT(GBIT) +#define VGA_B_HIGH *ABSRR = BIT(BBIT) +#define VGA_B_LOW *ABRR = BIT(BBIT) + +#define COLOR_WHITE (BIT(RBIT) | BIT(GBIT) | BIT(BBIT)) +#define COLOR_BLACK 0 +#define COLOR_RED BIT(RBIT) +#define COLOR_GREEN BIT(GBIT) +#define COLOR_BLUE BIT(BBIT) + +#define BORDER_COLOR COLOR_BLUE + +// set has priority, so clear every bit and set some given bits: +#define VGA_COLOR(c) (*ABSRR = c | \ + BIT(RBIT+16) | BIT(GBIT+16) | BIT(BBIT+16)) + +#define VGA_V_HIGH *ABSRR = BIT(6) +#define VGA_V_LOW *ABRR = BIT(6) +#define VGA_H_HIGH *ABSRR = BIT(7) +#define VGA_H_LOW *ABRR = BIT(7) void isr_porch(void); void isr_start(void); void isr_stop(void); void isr_update(void); -void setup() -{ +void setup() { pinMode(LED_PIN, OUTPUT); pinMode(ANALOG_PIN, INPUT_ANALOG); digitalWrite(LED_PIN, 1); @@ -38,104 +94,104 @@ void setup() pinMode(VGA_V, OUTPUT); pinMode(VGA_H, OUTPUT); - /* Send a message out USART2 */ + // Send a message out USART2 Serial2.begin(9600); - Serial2.println("Video time..."); + Serial2.println("Time to kill the radio star..."); // This gets rid of the majority of the interrupt artifacts; - // a SysTick.end() is required as well + // there's still a glitch for low values of y, but let's not worry + // about that. (Probably due to the hackish way vsync is done). SerialUSB.end(); - + systick_disable(); + digitalWrite(VGA_R, 0); digitalWrite(VGA_G, 0); digitalWrite(VGA_B, 0); - digitalWrite(VGA_H,1); - digitalWrite(VGA_V,1); - - timer_set_prescaler(4,0); - timer_set_mode(4, 1, TIMER_OUTPUTCOMPARE); - timer_set_mode(4, 2, TIMER_OUTPUTCOMPARE); - timer_set_mode(4, 3, TIMER_OUTPUTCOMPARE); - timer_set_mode(4, 4, TIMER_OUTPUTCOMPARE); - timer_set_reload(4, 2287); - timer_set_compare_value(4,1,200); - timer_set_compare_value(4,2,300); - timer_set_compare_value(4,3,2170); // 2219 max... - timer_set_compare_value(4,4,1); - timer_attach_interrupt(4,1,isr_porch); - timer_attach_interrupt(4,2,isr_start); - timer_attach_interrupt(4,3,isr_stop); - timer_attach_interrupt(4,4,isr_update); - - timer_set_count(4,0); + digitalWrite(VGA_H, 1); + digitalWrite(VGA_V, 1); + + timer_pause(TIMER4); + timer_set_prescaler(TIMER4, 0); + timer_set_mode(TIMER4, 1, TIMER_OUTPUTCOMPARE); + timer_set_mode(TIMER4, 2, TIMER_OUTPUTCOMPARE); + timer_set_mode(TIMER4, 3, TIMER_OUTPUTCOMPARE); + timer_set_mode(TIMER4, 4, TIMER_OUTPUTCOMPARE); + timer_set_reload(TIMER4, 2287); + timer_set_compare_value(TIMER4, 1, 200); + timer_set_compare_value(TIMER4, 2, 250); + timer_set_compare_value(TIMER4, 3, 2170); // 2219 max... + timer_set_compare_value(TIMER4, 4, 1); + timer_attach_interrupt(TIMER4, 1, isr_porch); + timer_attach_interrupt(TIMER4, 2, isr_start); + timer_attach_interrupt(TIMER4, 3, isr_stop); + timer_attach_interrupt(TIMER4, 4, isr_update); + + timer_set_count(TIMER4, 0); + timer_resume(TIMER4); } -int toggle = 0; -uint16 x = 0; uint16 y = 0; uint16 val = 0; -uint8 v_active = 1; -GPIO_Port *portb = GPIOB_BASE; +bool v_active = true; +const uint16 x_max = 60; // empirically (and lazily) determined void isr_porch(void) { VGA_H_HIGH; y++; - if(y>=523) { - y=1; - v_active = 1; + val = map(analogRead(ANALOG_PIN), 0, 4095, 0, x_max); + if(y >= 523) { + y = 1; + v_active = true; return; } - if(y>=492) { + if(y >= 492) { VGA_V_HIGH; return; } - if(y>=490) { + if(y >= 490) { VGA_V_LOW; return; } - if(y>=479) { // 479 - v_active = 0; + if(y >= 479) { + v_active = false; return; } } void isr_start(void) { - if(!v_active) { return; } - VGA_R_HIGH; - VGA_R_HIGH; - VGA_R_HIGH; - VGA_R_LOW; - //delayMicroseconds(2); - //gpio_write_bit(GPIOA_BASE, 8, 1); // VGA_G - for(x=0; x<(val>>6); x++) { - } - VGA_B_HIGH; - VGA_G_HIGH; - VGA_G_LOW; - VGA_B_LOW; - //VGA_R_HIGH; - //val = (val + analogRead(ANALOG_PIN))/2; - val = analogRead(ANALOG_PIN); - + if (!v_active) { + return; + } + VGA_COLOR(BORDER_COLOR); + for (int x = 0; x < val; x++) { + VGA_COLOR(COLOR_BLACK); + } + VGA_COLOR(COLOR_WHITE); + VGA_COLOR(COLOR_BLACK); } + void isr_stop(void) { - if(!v_active) { return; } - VGA_R_LOW; - VGA_G_LOW; - VGA_B_LOW; + if (!v_active) { + return; + } + VGA_COLOR(COLOR_BLACK); } + void isr_update(void) { VGA_H_LOW; } void loop() { - //val = analogRead(ANALOG_PIN); + toggleLED(); + delay(100); } +__attribute__((constructor)) void premain() { + init(); +} int main(void) { - init(); setup(); while (1) { diff --git a/wirish/boards.h b/wirish/boards.h index 989eea1..ee93c5a 100644 --- a/wirish/boards.h +++ b/wirish/boards.h @@ -133,7 +133,7 @@ typedef struct PinMapping { /* D23/PC15 */ {GPIOC_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, /* D24/PB9 */ - {GPIOB_BASE, 9, ADC_INVALID, TIMER4_CH4_CCR, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, + {GPIOB_BASE, 9, ADC_INVALID, TIMER4_CH4_CCR, EXTI_CONFIG_PORTB, TIMER4, 4}, /* D25/PD2 */ {GPIOD_BASE, 2, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, /* D26/PC10 */ -- cgit v1.2.3 From 12277ce5ac4a81a1f42b7fd695dafbf195c6f8e3 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Fri, 4 Mar 2011 23:16:53 -0500 Subject: USBSerial docs fix. --- docs/source/lang/api/serialusb.rst | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/source/lang/api/serialusb.rst b/docs/source/lang/api/serialusb.rst index 87fa641..4ddfa4a 100644 --- a/docs/source/lang/api/serialusb.rst +++ b/docs/source/lang/api/serialusb.rst @@ -224,7 +224,7 @@ running from battery, or connected but not monitored. You may need to experiment with the DTR/RTS logic for your platform and device configuration. :: - #define LED_PIN 13 + #define LED_PIN BOARD_LED_PIN void setup() { /* Set up the LED to blink */ @@ -232,22 +232,22 @@ configuration. :: } void loop() { - // LED will stay off if we are disconnected; - // will blink quickly if USB is unplugged (battery etc) + // LED will stay off if we are disconnected, and will blink + // quickly if USB is unplugged (battery power, etc.). if(SerialUSB.isConnected()) { digitalWrite(LED_PIN, 1); } delay(100); - // If this logic fails to detect if bytes are going to - // be read by the USB host, then the println() will fully - // many times, causing a very slow LED blink. - // If the characters are printed and read, the blink will - // only slow a small amount when "really" connected, and fast - // when the virtual port is only configured. + // If this logic fails to detect if bytes are going to be read + // by the USB host, then the println() take a long time, + // causing a very slow LED blink. If the characters are + // printed and read, the blink will only slow a small amount + // when "really" connected, and will be fast fast when the + // virtual port is only configured. if(SerialUSB.isConnected() && (SerialUSB.getDTR() || SerialUSB.getRTS())) { - for(int i=0; i<10; i++) { - SerialUSB.println(123456,BIN); + for(int i = 0; i < 10; i++) { + SerialUSB.println(123456, BIN); } } digitalWrite(LED_PIN, 0); -- cgit v1.2.3 From 4651227fa9f7dece1dd24d2170db16c2e35dc04e Mon Sep 17 00:00:00 2001 From: Perry Hung Date: Wed, 9 Mar 2011 23:25:03 -0500 Subject: Merge refactor into i2c-wip: Squashed commit of the following: commit 4d6662dadfda7f2fd55107535165dc98a0638a3c Merge: 174d9ab 7ddc844 Author: Marti Bolivar Date: Fri Mar 4 23:18:29 2011 -0500 Merge remote branch 'origin/refactor' into refactor commit 174d9ab73cc3387a3812e6f3d3e97519bf5b2150 Author: Marti Bolivar Date: Fri Mar 4 23:16:53 2011 -0500 USBSerial docs fix. commit f217acb73d94f0a88bf33a42684e6e988dcb3685 Author: Marti Bolivar Date: Fri Mar 4 20:25:26 2011 -0500 Brought examples/ up to date; PIN_MAP bugfix for D24. commit c4ba3ba05fc39ef260cd80d91759966952df74ae Author: Marti Bolivar Date: Fri Mar 4 19:16:42 2011 -0500 Cosmetic/documentation changes to adc.c commit e7747b4eb831621951deef6d31629f55cb5c3500 Author: Marti Bolivar Date: Fri Mar 4 19:16:07 2011 -0500 Cosmetic changes to wirish/main.cxx commit e2f9d4116e59d8487c936989384228ea084a3501 Author: Marti Bolivar Date: Fri Mar 4 19:15:24 2011 -0500 Untabifying docs/source/conf.py commit 7ddc84481b4eebe337065a0219e3d8dc000791e5 Author: Perry Hung Date: Wed Mar 2 00:30:19 2011 -0500 cscope: Find .S instead of .s files commit 62cb09ed6357eae58b0234fbc074c44e9c0aa5e5 Author: Marti Bolivar Date: Wed Mar 2 00:07:10 2011 -0500 Fixing typo in main.cpp.example. --- Makefile | 2 +- docs/source/conf.py | 38 +++---- docs/source/lang/api/serialusb.rst | 22 ++-- examples/blinky.cpp | 6 +- examples/debug-dtrrts.cpp | 23 ++-- examples/qa-slave-shield.cpp | 45 ++++---- examples/spi_master.cpp | 7 +- examples/test-bkp.cpp | 2 +- examples/test-dac.cpp | 4 - examples/test-fsmc.cpp | 22 ++-- examples/test-serial-flush.cpp | 18 +--- examples/test-serialusb.cpp | 74 ++++++------- examples/test-systick.cpp | 50 ++++----- examples/test-timers.cpp | 68 ++++++------ examples/vga-leaf.cpp | 162 +++++++++++++++++----------- examples/vga-scope.cpp | 212 +++++++++++++++++++++++-------------- libmaple/adc.c | 4 +- main.cpp.example | 2 +- wirish/boards.h | 2 +- wirish/main.cxx | 9 +- 20 files changed, 420 insertions(+), 352 deletions(-) diff --git a/Makefile b/Makefile index 149f54a..01e1e72 100644 --- a/Makefile +++ b/Makefile @@ -153,7 +153,7 @@ debug: cscope: rm -rf *.cscope - find . -name '*.[hcs]' -o -name '*.cpp' | xargs cscope -b + find . -name '*.[hcS]' -o -name '*.cpp' | xargs cscope -b tags: etags `find . -name "*.c" -o -name "*.cpp" -o -name "*.h"` diff --git a/docs/source/conf.py b/docs/source/conf.py index 1ad4e57..f232b7c 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -117,25 +117,25 @@ html_theme = 'default' # further. For a list of options available for each theme, see the # documentation. html_theme_options = { - ## Sidebar placement options - #'stickysidebar' : 'true', - 'rightsidebar' : 'true', - #'collapsiblesidebar' : 'true', - - ## Color - 'sidebarbgcolor' : '#C8C8C8', - 'sidebarlinkcolor' : 'green', - 'sidebartextcolor' : 'black', + ## Sidebar placement options + #'stickysidebar' : 'true', + 'rightsidebar' : 'true', + #'collapsiblesidebar' : 'true', + + ## Color + 'sidebarbgcolor' : '#C8C8C8', + 'sidebarlinkcolor' : 'green', + 'sidebartextcolor' : 'black', #'sidebarbtncolor' : 'black', - 'footerbgcolor' : 'green', - 'relbarbgcolor' : 'green', - 'headlinkcolor' : '#000000', - 'linkcolor' : 'green', - 'visitedlinkcolor' : 'green', - - ## Font - 'headfont' : 'Georgia', - 'bodyfont' : 'Lucidia' + 'footerbgcolor' : 'green', + 'relbarbgcolor' : 'green', + 'headlinkcolor' : '#000000', + 'linkcolor' : 'green', + 'visitedlinkcolor' : 'green', + + ## Font + 'headfont' : 'Georgia', + 'bodyfont' : 'Lucidia' } # Add any paths that contain custom themes here, relative to this directory. @@ -174,7 +174,7 @@ html_last_updated_fmt = '%b %d, %Y' # re-add commented line when custom template for api finished html_sidebars = { '**': ['globaltoc.html', 'searchbox.html'], - #'lang/api**':['searchbox.html', 'apilist.html'], + #'lang/api**':['searchbox.html', 'apilist.html'], } diff --git a/docs/source/lang/api/serialusb.rst b/docs/source/lang/api/serialusb.rst index 87fa641..4ddfa4a 100644 --- a/docs/source/lang/api/serialusb.rst +++ b/docs/source/lang/api/serialusb.rst @@ -224,7 +224,7 @@ running from battery, or connected but not monitored. You may need to experiment with the DTR/RTS logic for your platform and device configuration. :: - #define LED_PIN 13 + #define LED_PIN BOARD_LED_PIN void setup() { /* Set up the LED to blink */ @@ -232,22 +232,22 @@ configuration. :: } void loop() { - // LED will stay off if we are disconnected; - // will blink quickly if USB is unplugged (battery etc) + // LED will stay off if we are disconnected, and will blink + // quickly if USB is unplugged (battery power, etc.). if(SerialUSB.isConnected()) { digitalWrite(LED_PIN, 1); } delay(100); - // If this logic fails to detect if bytes are going to - // be read by the USB host, then the println() will fully - // many times, causing a very slow LED blink. - // If the characters are printed and read, the blink will - // only slow a small amount when "really" connected, and fast - // when the virtual port is only configured. + // If this logic fails to detect if bytes are going to be read + // by the USB host, then the println() take a long time, + // causing a very slow LED blink. If the characters are + // printed and read, the blink will only slow a small amount + // when "really" connected, and will be fast fast when the + // virtual port is only configured. if(SerialUSB.isConnected() && (SerialUSB.getDTR() || SerialUSB.getRTS())) { - for(int i=0; i<10; i++) { - SerialUSB.println(123456,BIN); + for(int i = 0; i < 10; i++) { + SerialUSB.println(123456, BIN); } } digitalWrite(LED_PIN, 0); diff --git a/examples/blinky.cpp b/examples/blinky.cpp index 5611987..209a6e6 100644 --- a/examples/blinky.cpp +++ b/examples/blinky.cpp @@ -1,4 +1,4 @@ -// Blinks the LED, pin 13 +// Blinks the built-in LED #include "wirish.h" @@ -20,8 +20,8 @@ void loop() { } // Force init to be called *first*, i.e. before static object allocation. -// Otherwise, statically allocated object that need libmaple may fail. - __attribute__(( constructor )) void premain() { +// Otherwise, statically allocated objects that need libmaple may fail. +__attribute__((constructor)) void premain() { init(); } diff --git a/examples/debug-dtrrts.cpp b/examples/debug-dtrrts.cpp index f9f8b96..61c061a 100644 --- a/examples/debug-dtrrts.cpp +++ b/examples/debug-dtrrts.cpp @@ -1,14 +1,12 @@ -// Sample main.cpp file. Blinks an LED, sends a message out USART2 -// and turns on PWM on pin 2 +// Test sketch for figuring out DTR/RTS behavior on different platforms. #include "wirish.h" #include "usb.h" -#define LED_PIN 13 -#define PWM_PIN 2 +#define LED_PIN BOARD_LED_PIN +#define PWM_PIN 2 -void setup() -{ +void setup() { /* Set up the LED to blink */ pinMode(LED_PIN, OUTPUT); @@ -18,12 +16,10 @@ void setup() } -int toggle = 0; - void loop() { - toggle ^= 1; - digitalWrite(LED_PIN, toggle); + toggleLED(); delay(100); + Serial2.print("DTR: "); Serial2.print(usbGetDTR(), DEC); Serial2.print("\tRTS: "); @@ -31,13 +27,12 @@ void loop() { } // Force init to be called *first*, i.e. before static object allocation. -// Otherwise, statically allocated object that need libmaple may fail. - __attribute__(( constructor )) void premain() { +// Otherwise, statically allocated objects that need libmaple may fail. +__attribute__((constructor)) void premain() { init(); } -int main(void) -{ +int main(void) { setup(); while (1) { diff --git a/examples/qa-slave-shield.cpp b/examples/qa-slave-shield.cpp index b395cca..178b780 100644 --- a/examples/qa-slave-shield.cpp +++ b/examples/qa-slave-shield.cpp @@ -1,50 +1,51 @@ -// slave mode for QA shield +// Slave mode for QA shield #include "wirish.h" -#define LED_PIN 13 -#define NUM_GPIO 38 // not the number of the max... +// FIXME generalize for Maple Native, Maple Mini (NUM_GPIO, Mini USB +// breakout pins, etc.) -int i; +#define LED_PIN BOARD_LED_PIN +#define NUM_GPIO 38 // Ignore JTAG pins. -void setup() -{ +void setup() { /* Set up the LED to blink */ pinMode(LED_PIN, OUTPUT); - digitalWrite(LED_PIN, 1); + digitalWrite(LED_PIN, HIGH); - for(i=0; i +#include // for snprintf() #include "wirish.h" #include "bkp.h" diff --git a/examples/test-dac.cpp b/examples/test-dac.cpp index 62f40eb..af98030 100644 --- a/examples/test-dac.cpp +++ b/examples/test-dac.cpp @@ -1,8 +1,4 @@ - #include "wirish.h" -#include "fsmc.h" -#include "rcc.h" -#include "gpio.h" #include "dac.h" uint16 count = 0; diff --git a/examples/test-fsmc.cpp b/examples/test-fsmc.cpp index f4fd068..4211e4d 100644 --- a/examples/test-fsmc.cpp +++ b/examples/test-fsmc.cpp @@ -1,14 +1,12 @@ - #include "wirish.h" #include "fsmc.h" -#define LED_PIN 23 // hack for maple native -#define DISC_PIN 14 // hack for USB on native +#define LED_PIN BOARD_LED_PIN // System control block registers #define SCB_BASE (SCB_Reg*)(0xE000ED00) -// This stuff should ultimately get moved to util.h or scb.h or w/e. +// This stuff should ultimately get moved to util.h or scb.h or w/e. // Also in interactive test program and the HardFault IRQ handler. typedef struct { volatile uint32 CPUID; @@ -23,15 +21,14 @@ typedef struct { volatile uint32 SHCRS; volatile uint32 CFSR; volatile uint32 HFSR; - uint32 pad1; + uint32 pad1; volatile uint32 MMAR; volatile uint32 BFAR; } SCB_Reg; -SCB_Reg *scb; +SCB_Reg *scb; uint16 *ptr; -int toggle = 0; int count = 0; void setup() { @@ -39,8 +36,6 @@ void setup() { scb = (SCB_Reg*)SCB_BASE; pinMode(LED_PIN, OUTPUT); - pinMode(DISC_PIN, OUTPUT); - digitalWrite(DISC_PIN,1); digitalWrite(LED_PIN,1); Serial1.begin(9600); @@ -82,15 +77,14 @@ void setup() { Serial1.print("BFAR: "); id = scb->BFAR; Serial1.println(id,BIN); - + Serial1.println("Now testing all memory addresses... (will hardfault at the end)"); delay(3000); } void loop() { - digitalWrite(LED_PIN, toggle); - toggle ^= 1; - delay(1); + toggleLED(); + delay(1); for(int i = 0; i<100; i++) { // modify this to speed things up count++; @@ -102,7 +96,7 @@ void loop() { while(1) { } } } - + Serial1.print((uint32)(ptr),HEX); Serial1.print(": "); Serial1.println(*ptr,BIN); diff --git a/examples/test-serial-flush.cpp b/examples/test-serial-flush.cpp index d7fbf7a..1cd82b6 100644 --- a/examples/test-serial-flush.cpp +++ b/examples/test-serial-flush.cpp @@ -2,22 +2,13 @@ #include "wirish.h" -void setup() -{ +void setup() { /* Send a message out USART2 */ Serial2.begin(9600); Serial2.println("Hello world!"); } -int toggle = 0; - void loop() { - - Serial2.println("This is the first line."); - Serial2.end(); - Serial2.println("This is the second line."); - - Serial2.begin(9600); Serial2.println("Waiting for multiple input..."); while(Serial2.available() < 5) { } Serial2.println(Serial2.read()); @@ -29,13 +20,12 @@ void loop() { } // Force init to be called *first*, i.e. before static object allocation. -// Otherwise, statically allocated object that need libmaple may fail. - __attribute__(( constructor )) void premain() { +// Otherwise, statically allocated objects that need libmaple may fail. +__attribute__((constructor)) void premain() { init(); } -int main(void) -{ +int main(void) { setup(); while (1) { diff --git a/examples/test-serialusb.cpp b/examples/test-serialusb.cpp index 9d0a862..678c2b9 100644 --- a/examples/test-serialusb.cpp +++ b/examples/test-serialusb.cpp @@ -1,11 +1,10 @@ -// Sample main.cpp file. Blinks an LED, sends a message out USART2 -// and turns on PWM on pin 2 +// Tests SerialUSB functionality. #include "wirish.h" #include "usb.h" -#define LED_PIN 13 -#define BUT_PIN 38 +#define LED_PIN BOARD_LED_PIN +#define BUT_PIN BOARD_BUTTON_PIN uint32 state = 0; #define QUICKPRINT 0 @@ -14,33 +13,29 @@ uint32 state = 0; #define SIMPLE 3 #define ONOFF 4 - -void setup() -{ +void setup() { /* Set up the LED to blink */ pinMode(LED_PIN, OUTPUT); /* Set up the Button */ - pinMode(BUT_PIN, INPUT_PULLUP); + pinMode(BUT_PIN, INPUT); Serial2.begin(9600); - Serial2.println("Hello world! This is the debug channel."); -} + Serial2.println("This is the debug channel. Press BUT."); -int toggle = 0; + waitForButtonPress(0); +} uint8 c1 = '-'; void loop() { - toggle ^= 1; - digitalWrite(LED_PIN, toggle); + toggleLED(); delay(1000); - if(digitalRead(BUT_PIN)) { - while(digitalRead(BUT_PIN)) {}; + if(isButtonPressed()) { state++; } - + switch(state) { case QUICKPRINT: for(int i = 0; i<30; i++) { @@ -48,34 +43,34 @@ void loop() { SerialUSB.print('.'); SerialUSB.print('|'); } - Serial2.println(SerialUSB.pending(),DEC); + Serial2.println(SerialUSB.pending(), DEC); SerialUSB.println(); break; case BIGSTUFF: - SerialUSB.println("01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"); - SerialUSB.println((uint32)123456789,DEC); + SerialUSB.println("0123456789012345678901234567890123456789" + "0123456789012345678901234567890123456789" + "012345678901234567890"); + SerialUSB.println((int64)123456789, DEC); SerialUSB.println(3.1415926535); - Serial2.println(SerialUSB.pending(),DEC); + Serial2.println(SerialUSB.pending(), DEC); break; case NUMBERS: SerialUSB.println("Numbers! -----------------------------"); Serial2.println("Numbers! -----------------------------"); SerialUSB.println('1'); Serial2.println('1'); - SerialUSB.println(1,DEC); - Serial2.println(1,DEC); - SerialUSB.println(-1,DEC); - Serial2.println(-1,DEC); + SerialUSB.println(1, DEC); + Serial2.println(1, DEC); + SerialUSB.println(-1, DEC); + Serial2.println(-1, DEC); SerialUSB.println(3.14159265); Serial2.println(3.14159265); - SerialUSB.println(3.14159265,9); - Serial2.println(3.14159265,9); - SerialUSB.println(123456789,DEC); - Serial2.println(123456789,DEC); - SerialUSB.println(-123456789,DEC); - Serial2.println(-123456789,DEC); - SerialUSB.println(65535,HEX); - Serial2.println(65535,HEX); + SerialUSB.println(123456789, DEC); + Serial2.println(123456789, DEC); + SerialUSB.println(-123456789, DEC); + Serial2.println(-123456789, DEC); + SerialUSB.println(65535, HEX); + Serial2.println(65535, HEX); break; case SIMPLE: Serial2.println("Trying write('a')"); @@ -92,8 +87,8 @@ void loop() { SerialUSB.print("hij\n\r"); SerialUSB.write(' '); SerialUSB.println(); - Serial2.println("Trying println(123456789,DEC)"); - SerialUSB.println(123456789); + Serial2.println("Trying println(123456789, DEC)"); + SerialUSB.println(123456789, DEC); Serial2.println("Trying println(3.141592)"); SerialUSB.println(3.141592); Serial2.println("Trying println(\"DONE\")"); @@ -103,12 +98,12 @@ void loop() { Serial2.println("Shutting down..."); SerialUSB.println("Shutting down..."); SerialUSB.end(); - Serial2.println("Waiting 4seconds..."); + Serial2.println("Waiting 4 seconds..."); delay(4000); Serial2.println("Starting up..."); SerialUSB.begin(); SerialUSB.println("Hello World!"); - Serial2.println("Waiting 4seconds..."); + Serial2.println("Waiting 4 seconds..."); delay(4000); state++; break; @@ -118,13 +113,12 @@ void loop() { } // Force init to be called *first*, i.e. before static object allocation. -// Otherwise, statically allocated object that need libmaple may fail. - __attribute__(( constructor )) void premain() { +// Otherwise, statically allocated objects that need libmaple may fail. +__attribute__((constructor)) void premain() { init(); } -int main(void) -{ +int main(void) { setup(); while (1) { diff --git a/examples/test-systick.cpp b/examples/test-systick.cpp index 247892d..c7b5529 100644 --- a/examples/test-systick.cpp +++ b/examples/test-systick.cpp @@ -3,54 +3,48 @@ #include "wirish.h" #include "systick.h" -#define LED_PIN 13 -#define PWM_PIN 2 -#define BUT 38 +#define LED_PIN BOARD_LED_PIN +#define PWM_PIN 2 +#define BUT BOARD_BUTTON_PIN -void setup() -{ +void setup() { /* Set up the LED to blink */ pinMode(LED_PIN, OUTPUT); - - /* Turn on PWM on pin PWM_PIN */ - pinMode(PWM_PIN, PWM); - pwmWrite(PWM_PIN, 0x8000); - - pinMode(BUT, INPUT_PULLDOWN); + pinMode(BUT, INPUT); } -int toggle = 0; +bool disable = true; long time = 0; void loop() { - toggle ^= 1; - digitalWrite(LED_PIN, toggle); + volatile int i = 0; + toggleLED(); // An artificial delay - int16 i = 1; - float j = 1; - for(i=0; i<6553; i++) { - j = sqrt(j) + 1; - } - - if(digitalRead(BUT)) { - systick_disable(); - } else { - systick_resume(); + for(i = 0; i < 150000; i++) + ; + + if(isButtonPressed()) { + if (disable) { + systick_disable(); + SerialUSB.println("Disabling SysTick"); + } else { + SerialUSB.println("Re-enabling SysTick"); + systick_resume(); + } + disable = !disable; } - //SerialUSB.println(micros()); // there is a bug with this SerialUSB.println(millis()); } // Force init to be called *first*, i.e. before static object allocation. // Otherwise, statically allocated object that need libmaple may fail. - __attribute__(( constructor )) void premain() { +__attribute__((constructor)) void premain() { init(); } -int main(void) -{ +int main(void) { setup(); while (1) { diff --git a/examples/test-timers.cpp b/examples/test-timers.cpp index ccba251..f3cfdcc 100644 --- a/examples/test-timers.cpp +++ b/examples/test-timers.cpp @@ -2,7 +2,7 @@ #include "wirish.h" -#define LED_PIN 13 +#define LED_PIN BOARD_LED_PIN void handler1(void); void handler2(void); @@ -12,7 +12,6 @@ void handler4(void); void handler3b(void); void handler4b(void); -int toggle = 0; int t; int count1 = 0; @@ -36,25 +35,24 @@ void setup() pinMode(LED_PIN, OUTPUT); // Setup the button as input - pinMode(38, INPUT_PULLUP); + pinMode(BOARD_BUTTON_PIN, INPUT); - /* Send a message out USART2 */ - //SerialUSB.begin(9600); - SerialUSB.println("Begining timer test..."); + // Wait for user to attach... + waitForButtonPress(0); + + // Send a message out SerialUSB + SerialUSB.println("Beginning timer test..."); for(int t=0; t<4; t++) { Timers[t].setChannel1Mode(TIMER_OUTPUTCOMPARE); Timers[t].setChannel2Mode(TIMER_OUTPUTCOMPARE); Timers[t].setChannel3Mode(TIMER_OUTPUTCOMPARE); Timers[t].setChannel4Mode(TIMER_OUTPUTCOMPARE); } - - // Wait for user to attach... - delay(2000); } void loop() { SerialUSB.println("-----------------------------------------------------"); - SerialUSB.println("Testing setCount/getCount"); + SerialUSB.println("Testing setCount/getCount"); SerialUSB.print("Timer1.getCount() = "); SerialUSB.println(Timer1.getCount()); SerialUSB.println("Timer1.setCount(1234)"); Timer1.setCount(1234); @@ -63,7 +61,7 @@ void loop() { // down Timer4 is in the "pause" state and the timer doesn't increment, so // the final counts should reflect the ratio of time that BUT was held down SerialUSB.println("-----------------------------------------------------"); - SerialUSB.println("Testing Pause/Resume; button roughly controls Timer4"); + SerialUSB.println("Testing Pause/Resume; button roughly controls Timer4"); count3 = 0; count4 = 0; Timer3.setChannel1Mode(TIMER_OUTPUTCOMPARE); @@ -80,9 +78,9 @@ void loop() { Timer4.attachCompare1Interrupt(handler4b); Timer3.resume(); Timer4.resume(); - SerialUSB.println("~4 seconds..."); + SerialUSB.println("~4 seconds..."); for(int i = 0; i<4000; i++) { - if(digitalRead(38)) { + if(isButtonPressed()) { Timer4.pause(); } else { Timer4.resume(); @@ -96,14 +94,14 @@ void loop() { // These test the setPeriod auto-configure functionality SerialUSB.println("-----------------------------------------------------"); - SerialUSB.println("Testing setPeriod"); + SerialUSB.println("Testing setPeriod"); Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE); Timer4.setCompare1(1); - Timer4.setPeriod(10); + Timer4.setPeriod(10); Timer4.pause(); Timer4.setCount(0); Timer4.attachCompare1Interrupt(handler4b); - SerialUSB.println("Period 10ms, wait 2 seconds..."); + SerialUSB.println("Period 10ms, wait 2 seconds..."); count4 = 0; Timer4.resume(); delay(2000); @@ -114,10 +112,10 @@ void loop() { Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE); Timer4.setCompare1(1); Timer4.pause(); - Timer4.setPeriod(30000); + Timer4.setPeriod(30000); Timer4.setCount(0); Timer4.attachCompare1Interrupt(handler4b); - SerialUSB.println("Period 30000ms, wait 2 seconds..."); + SerialUSB.println("Period 30000ms, wait 2 seconds..."); count4 = 0; Timer4.resume(); delay(2000); @@ -127,12 +125,12 @@ void loop() { SerialUSB.println("(should be around 2sec/30000ms ~ 67)"); Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE); - Timer4.setPeriod(300000); + Timer4.setPeriod(300000); Timer4.setCompare1(1); Timer4.pause(); Timer4.setCount(0); Timer4.attachCompare1Interrupt(handler4b); - SerialUSB.println("Period 300000ms, wait 2 seconds..."); + SerialUSB.println("Period 300000ms, wait 2 seconds..."); count4 = 0; Timer4.resume(); delay(2000); @@ -146,9 +144,9 @@ void loop() { Timer4.setOverflow(65454); Timer4.pause(); Timer4.setCount(0); - Timer4.setCompare1(1); + Timer4.setCompare1(1); Timer4.attachCompare1Interrupt(handler4b); - SerialUSB.println("Period 30000ms, wait 2 seconds..."); + SerialUSB.println("Period 30000ms, wait 2 seconds..."); count4 = 0; Timer4.resume(); delay(2000); @@ -159,11 +157,11 @@ void loop() { Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE); Timer4.setCompare1(1); - Timer4.setPeriod(30000); + Timer4.setPeriod(30000); Timer4.pause(); Timer4.setCount(0); Timer4.attachCompare1Interrupt(handler4b); - SerialUSB.println("Period 30000ms, wait 2 seconds..."); + SerialUSB.println("Period 30000ms, wait 2 seconds..."); count4 = 0; Timer4.resume(); delay(2000); @@ -177,7 +175,7 @@ void loop() { // that over time the actual timing rates get blown away by other system // interrupts. for(t=0; t<4; t++) { - toggle ^= 1; digitalWrite(LED_PIN, toggle); + toggleLED(); delay(100); SerialUSB.println("-----------------------------------------------------"); SerialUSB.print("Testing Timer "); SerialUSB.println(t+1); @@ -214,33 +212,39 @@ void handler1(void) { val1 += rate1; Timers[t].setCompare1(val1); count1++; -} +} + void handler2(void) { val2 += rate2; Timers[t].setCompare2(val2); count2++; -} +} + void handler3(void) { val3 += rate3; Timers[t].setCompare3(val3); count3++; -} +} + void handler4(void) { val4 += rate4; Timers[t].setCompare4(val4); count4++; -} +} void handler3b(void) { count3++; -} +} + void handler4b(void) { count4++; -} +} +__attribute__((constructor)) void premain() { + init(); +} int main(void) { - init(); setup(); while (1) { diff --git a/examples/vga-leaf.cpp b/examples/vga-leaf.cpp index d1c6d7d..9d9fce2 100644 --- a/examples/vga-leaf.cpp +++ b/examples/vga-leaf.cpp @@ -1,21 +1,21 @@ /* - Crude VGA Output + VGA Output - Outputs a red and white leaf to VGA. This implementation is crude and noisy, - but a fun demo. It should run most VGA monitors at 640x480, though it does - not follow the timing spec very carefully. Real twisted or shielded wires, - proper grounding, and not doing this on a breadboard are recommended (but - it seems to work ok without). + Outputs a red and white leaf to VGA. It should run most VGA monitors + at 640x480, though it does not follow the timing spec very + carefully. Real twisted or shielded wires, proper grounding, and not + doing this on a breadboard are recommended (but it seems to work ok + without). - SerialUSB is disabled to get rid of most interrupts (which mess with timing); - the SysTick is probably the source of the remaining flickers. This means that - you have to use perpetual bootloader or the reset button to flash new - programs. + SerialUSB and SysTick are disabled to get rid of the most frequently + occurring interrupts (which mess with timing). This means that you + have to use perpetual bootloader mode or the reset button to flash + new programs. How to wire this to a VGA port: - D5 via ~200ohms to VGA Red (1) - D6 via ~200ohms to VGA Green (2) - D7 via ~200ohms to VGA Blue (3) + D6 via ~200ohms to VGA Red (1) + D7 via ~200ohms to VGA Green (2) + D8 via ~200ohms to VGA Blue (3) D11 to VGA VSync (14) (swapped?) D12 to VGA HSync (13) (swapped?) GND to VGA Ground (5) @@ -24,48 +24,71 @@ See also: - http://pinouts.ru/Video/VGA15_pinout.shtml - http://www.epanorama.net/documents/pc/vga_timing.html - + Created 20 July 2010 By Bryan Newbold for LeafLabs This code is released with no strings attached. - + + Modified 4 March 2011 + By Marti Bolivar + Disabled SysTick, kept up-to-date with libmaple. */ +// FIXME: generalize for Native and Mini + #include "wirish.h" -#define LED_PIN 13 +#define LED_PIN BOARD_LED_PIN -// Pinouts -#define VGA_R 5 // STM32: B6 -#define VGA_G 6 // STM32: A8 -#define VGA_B 7 // STM32: A9 +// Pinouts -- you also must change the GPIO macros below if you change +// these +#define VGA_R 6 // STM32: A8 +#define VGA_G 7 // STM32: A9 +#define VGA_B 8 // STM32: A10 #define VGA_V 11 // STM32: A6 #define VGA_H 12 // STM32: A7 -// These low level macros make GPIO writes much faster -#define VGA_R_HIGH (GPIOB_BASE)->BSRR = BIT(6) -#define VGA_R_LOW (GPIOB_BASE)->BRR = BIT(6) -#define VGA_G_HIGH (GPIOA_BASE)->BSRR = BIT(8) -#define VGA_G_LOW (GPIOA_BASE)->BRR = BIT(8) -#define VGA_B_HIGH (GPIOA_BASE)->BSRR = BIT(9) -#define VGA_B_LOW (GPIOA_BASE)->BRR = BIT(9) -#define VGA_V_HIGH (GPIOA_BASE)->BSRR = BIT(6) -#define VGA_V_LOW (GPIOA_BASE)->BRR = BIT(6) -#define VGA_H_HIGH (GPIOA_BASE)->BSRR = BIT(7) -#define VGA_H_LOW (GPIOA_BASE)->BRR = BIT(7) +// These low level (and STM32 specific) macros make GPIO writes much +// faster +#define ABSRR ((volatile uint32*)0x40010810) +#define ABRR ((volatile uint32*)0x40010814) + +#define RBIT 8 // (see pinouts) +#define GBIT 9 +#define BBIT 10 + +#define VGA_R_HIGH *ABSRR = BIT(RBIT) +#define VGA_R_LOW *ABRR = BIT(RBIT) +#define VGA_G_HIGH *ABSRR = BIT(GBIT) +#define VGA_G_LOW *ABRR = BIT(GBIT) +#define VGA_B_HIGH *ABSRR = BIT(BBIT) +#define VGA_B_LOW *ABRR = BIT(BBIT) + +#define ON_COLOR BIT(RBIT) +#define OFF_COLOR (BIT(RBIT) | BIT(GBIT) | BIT(BBIT)) + +// set has priority, so clear every bit and set some given bits: +#define VGA_COLOR(c) (*ABSRR = c | \ + BIT(RBIT+16) | BIT(GBIT+16) | BIT(BBIT+16)) + +#define VGA_V_HIGH *ABSRR = BIT(6) +#define VGA_V_LOW *ABRR = BIT(6) +#define VGA_H_HIGH *ABSRR = BIT(7) +#define VGA_H_LOW *ABRR = BIT(7) void isr_porch(void); void isr_start(void); void isr_stop(void); void isr_update(void); -uint8 toggle; uint16 x = 0; // X coordinate uint16 y = 0; // Y coordinate -uint8 v_active = 1; // Are we in the image? +uint16 logo_y = 0; // Y coordinate, mapped into valid logo index (for speed) +bool v_active = true; // Are we in the image? -// 1-bit! -uint8 logo[18][16] = { +const uint8 x_max = 16; +const uint8 y_max = 18; +uint32 logo[y_max][x_max] = { {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, {0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,}, {0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,}, @@ -99,9 +122,20 @@ void setup() { digitalWrite(VGA_H, HIGH); digitalWrite(VGA_V, HIGH); + // Fill the logo array with color patterns corresponding to its + // truth value. Note that we could get more tricky here, since + // there are 3 bits of color. + for (int y = 0; y < y_max; y++) { + for (int x = 0; x < x_max; x++) { + logo[y][x] = logo[y][x] ? ON_COLOR : OFF_COLOR; + } + } + // This gets rid of the majority of the interrupt artifacts; + // there's still a glitch for low values of y, but let's not worry + // about that. (Probably due to the hackish way vsync is done). SerialUSB.end(); - SystemTick.end(); + systick_disable(); // Configure Timer4.pause(); // while we configure @@ -120,14 +154,13 @@ void setup() { Timer4.attachCompare3Interrupt(isr_stop); Timer4.setCompare4(1); // Could be zero I guess Timer4.attachCompare4Interrupt(isr_update); - + Timer4.setCount(0); // Ready... Timer4.resume(); // Go! } void loop() { - toggle ^= 1; - digitalWrite(LED_PIN, toggle); + toggleLED(); delay(100); // Everything happens in the interrupts! @@ -139,51 +172,59 @@ void loop() { void isr_porch(void) { VGA_H_HIGH; y++; + logo_y = map(y, 0, 478, 0, y_max); // Back to the top - if(y>=523) { - y=1; - v_active = 1; + if(y >= 523) { + y = 1; + logo_y = 0; + v_active = true; return; } // Other vsync stuff below the image - if(y>=492) { + if(y >= 492) { VGA_V_HIGH; return; } - if(y>=490) { + if(y >= 490) { VGA_V_LOW; return; } - if(y>=479) { - v_active = 0; + if(y >= 479) { + v_active = false; return; } } // This is the main horizontal sweep -void isr_start(void) { +void isr_start(void) { // Skip if we're not in the image at all - if(!v_active) { return; } + if (!v_active) { + return; + } // Start Red VGA_R_LOW; VGA_R_HIGH; - // For each "pixel" (really 20 or so screen pixels?) go red or white - for(x=0; x<32; x++) { - if(logo[y/28][x/2]) { - VGA_G_HIGH; - VGA_B_HIGH; - } else { - VGA_G_LOW; - VGA_B_LOW; - } + // For each "pixel", go ON_COLOR or OFF_COLOR + for(x = 0; x < 16; x++) { + // setting the color several times is just an easy way to + // delay, so the image is wider. if you only do the following + // once, you'll be able to make the logo array a lot wider: + VGA_COLOR(logo[logo_y][x]); + VGA_COLOR(logo[logo_y][x]); + VGA_COLOR(logo[logo_y][x]); + VGA_COLOR(logo[logo_y][x]); + VGA_COLOR(logo[logo_y][x]); + VGA_COLOR(logo[logo_y][x]); } } // End of the horizontal line void isr_stop(void) { - if(!v_active) { return; } + if (!v_active) { + return; + } VGA_R_LOW; VGA_G_LOW; VGA_B_LOW; @@ -194,8 +235,11 @@ void isr_update(void) { VGA_H_LOW; } -int main(void) { +__attribute__((constructor)) void premain() { init(); +} + +int main(void) { setup(); while (1) { diff --git a/examples/vga-scope.cpp b/examples/vga-scope.cpp index 0265f9c..9c6dca5 100644 --- a/examples/vga-scope.cpp +++ b/examples/vga-scope.cpp @@ -1,34 +1,90 @@ -// Low-level, non-wirish demonstration of VGA -// -// Connect a microphone or something less to ANALOG_PIN +/* + VGA Oscilloscope demo. + + Connect a microphone or something like it to ANALOG_PIN (0V -- 3.3V + only; 0.2V -- 3.1V will probably look nicer); an attached VGA + monitor will display the signal roughly in real-time. + + The thick blue line corresponds roughly to 0V. + + This is a fairy crude hack, but it's fun to watch/toy around with. + + SerialUSB and SysTick are disabled to get rid of the most frequently + occurring interrupts (which mess with timing). This means that you + have to use perpetual bootloader mode or the reset button to flash + new programs. + + How to wire this to a VGA port: + D6 via ~200ohms to VGA Red (1) + D7 via ~200ohms to VGA Green (2) + D8 via ~200ohms to VGA Blue (3) + D11 to VGA VSync (14) (swapped?) + D12 to VGA HSync (13) (swapped?) + GND to VGA Ground (5) + GND to VGA Sync Ground (10) + + See also: + - http://pinouts.ru/Video/VGA15_pinout.shtml + - http://www.epanorama.net/documents/pc/vga_timing.html + + This code is released into the public domain. + */ #include "wirish.h" +#include "systick.h" + +// FIXME generalize for Native and Mini -#define LED_PIN 13 +#define LED_PIN BOARD_LED_PIN #define ANALOG_PIN 18 -#define VGA_R 5 // B6 -#define VGA_G 6 // A8 -#define VGA_B 7 // A9 -#define VGA_V 11 // A6 -#define VGA_H 12 // A7 -#define VGA_R_HIGH (GPIOB_BASE)->BSRR = BIT(6) -#define VGA_R_LOW (GPIOB_BASE)->BRR = BIT(6) -#define VGA_G_HIGH (GPIOA_BASE)->BSRR = BIT(8) -#define VGA_G_LOW (GPIOA_BASE)->BRR = BIT(8) -#define VGA_B_HIGH (GPIOA_BASE)->BSRR = BIT(9) -#define VGA_B_LOW (GPIOA_BASE)->BRR = BIT(9) -#define VGA_V_HIGH (GPIOA_BASE)->BSRR = BIT(6) -#define VGA_V_LOW (GPIOA_BASE)->BRR = BIT(6) -#define VGA_H_HIGH (GPIOA_BASE)->BSRR = BIT(7) -#define VGA_H_LOW (GPIOA_BASE)->BRR = BIT(7) + +// Pinouts -- you also must change the GPIO macros below if you change +// these +#define VGA_R 6 // STM32: A8 +#define VGA_G 7 // STM32: A9 +#define VGA_B 8 // STM32: A10 +#define VGA_V 11 // STM32: A6 +#define VGA_H 12 // STM32: A7 + +// These low level (and STM32 specific) macros make GPIO writes much +// faster +#define ABSRR ((volatile uint32*)0x40010810) +#define ABRR ((volatile uint32*)0x40010814) + +#define RBIT 8 // (see pinouts) +#define GBIT 9 +#define BBIT 10 + +#define VGA_R_HIGH *ABSRR = BIT(RBIT) +#define VGA_R_LOW *ABRR = BIT(RBIT) +#define VGA_G_HIGH *ABSRR = BIT(GBIT) +#define VGA_G_LOW *ABRR = BIT(GBIT) +#define VGA_B_HIGH *ABSRR = BIT(BBIT) +#define VGA_B_LOW *ABRR = BIT(BBIT) + +#define COLOR_WHITE (BIT(RBIT) | BIT(GBIT) | BIT(BBIT)) +#define COLOR_BLACK 0 +#define COLOR_RED BIT(RBIT) +#define COLOR_GREEN BIT(GBIT) +#define COLOR_BLUE BIT(BBIT) + +#define BORDER_COLOR COLOR_BLUE + +// set has priority, so clear every bit and set some given bits: +#define VGA_COLOR(c) (*ABSRR = c | \ + BIT(RBIT+16) | BIT(GBIT+16) | BIT(BBIT+16)) + +#define VGA_V_HIGH *ABSRR = BIT(6) +#define VGA_V_LOW *ABRR = BIT(6) +#define VGA_H_HIGH *ABSRR = BIT(7) +#define VGA_H_LOW *ABRR = BIT(7) void isr_porch(void); void isr_start(void); void isr_stop(void); void isr_update(void); -void setup() -{ +void setup() { pinMode(LED_PIN, OUTPUT); pinMode(ANALOG_PIN, INPUT_ANALOG); digitalWrite(LED_PIN, 1); @@ -38,104 +94,104 @@ void setup() pinMode(VGA_V, OUTPUT); pinMode(VGA_H, OUTPUT); - /* Send a message out USART2 */ + // Send a message out USART2 Serial2.begin(9600); - Serial2.println("Video time..."); + Serial2.println("Time to kill the radio star..."); // This gets rid of the majority of the interrupt artifacts; - // a SysTick.end() is required as well + // there's still a glitch for low values of y, but let's not worry + // about that. (Probably due to the hackish way vsync is done). SerialUSB.end(); - + systick_disable(); + digitalWrite(VGA_R, 0); digitalWrite(VGA_G, 0); digitalWrite(VGA_B, 0); - digitalWrite(VGA_H,1); - digitalWrite(VGA_V,1); - - timer_set_prescaler(4,0); - timer_set_mode(4, 1, TIMER_OUTPUTCOMPARE); - timer_set_mode(4, 2, TIMER_OUTPUTCOMPARE); - timer_set_mode(4, 3, TIMER_OUTPUTCOMPARE); - timer_set_mode(4, 4, TIMER_OUTPUTCOMPARE); - timer_set_reload(4, 2287); - timer_set_compare_value(4,1,200); - timer_set_compare_value(4,2,300); - timer_set_compare_value(4,3,2170); // 2219 max... - timer_set_compare_value(4,4,1); - timer_attach_interrupt(4,1,isr_porch); - timer_attach_interrupt(4,2,isr_start); - timer_attach_interrupt(4,3,isr_stop); - timer_attach_interrupt(4,4,isr_update); - - timer_set_count(4,0); + digitalWrite(VGA_H, 1); + digitalWrite(VGA_V, 1); + + timer_pause(TIMER4); + timer_set_prescaler(TIMER4, 0); + timer_set_mode(TIMER4, 1, TIMER_OUTPUTCOMPARE); + timer_set_mode(TIMER4, 2, TIMER_OUTPUTCOMPARE); + timer_set_mode(TIMER4, 3, TIMER_OUTPUTCOMPARE); + timer_set_mode(TIMER4, 4, TIMER_OUTPUTCOMPARE); + timer_set_reload(TIMER4, 2287); + timer_set_compare_value(TIMER4, 1, 200); + timer_set_compare_value(TIMER4, 2, 250); + timer_set_compare_value(TIMER4, 3, 2170); // 2219 max... + timer_set_compare_value(TIMER4, 4, 1); + timer_attach_interrupt(TIMER4, 1, isr_porch); + timer_attach_interrupt(TIMER4, 2, isr_start); + timer_attach_interrupt(TIMER4, 3, isr_stop); + timer_attach_interrupt(TIMER4, 4, isr_update); + + timer_set_count(TIMER4, 0); + timer_resume(TIMER4); } -int toggle = 0; -uint16 x = 0; uint16 y = 0; uint16 val = 0; -uint8 v_active = 1; -GPIO_Port *portb = GPIOB_BASE; +bool v_active = true; +const uint16 x_max = 60; // empirically (and lazily) determined void isr_porch(void) { VGA_H_HIGH; y++; - if(y>=523) { - y=1; - v_active = 1; + val = map(analogRead(ANALOG_PIN), 0, 4095, 0, x_max); + if(y >= 523) { + y = 1; + v_active = true; return; } - if(y>=492) { + if(y >= 492) { VGA_V_HIGH; return; } - if(y>=490) { + if(y >= 490) { VGA_V_LOW; return; } - if(y>=479) { // 479 - v_active = 0; + if(y >= 479) { + v_active = false; return; } } void isr_start(void) { - if(!v_active) { return; } - VGA_R_HIGH; - VGA_R_HIGH; - VGA_R_HIGH; - VGA_R_LOW; - //delayMicroseconds(2); - //gpio_write_bit(GPIOA_BASE, 8, 1); // VGA_G - for(x=0; x<(val>>6); x++) { - } - VGA_B_HIGH; - VGA_G_HIGH; - VGA_G_LOW; - VGA_B_LOW; - //VGA_R_HIGH; - //val = (val + analogRead(ANALOG_PIN))/2; - val = analogRead(ANALOG_PIN); - + if (!v_active) { + return; + } + VGA_COLOR(BORDER_COLOR); + for (int x = 0; x < val; x++) { + VGA_COLOR(COLOR_BLACK); + } + VGA_COLOR(COLOR_WHITE); + VGA_COLOR(COLOR_BLACK); } + void isr_stop(void) { - if(!v_active) { return; } - VGA_R_LOW; - VGA_G_LOW; - VGA_B_LOW; + if (!v_active) { + return; + } + VGA_COLOR(COLOR_BLACK); } + void isr_update(void) { VGA_H_LOW; } void loop() { - //val = analogRead(ANALOG_PIN); + toggleLED(); + delay(100); } +__attribute__((constructor)) void premain() { + init(); +} int main(void) { - init(); setup(); while (1) { diff --git a/libmaple/adc.c b/libmaple/adc.c index cd71118..a464746 100644 --- a/libmaple/adc.c +++ b/libmaple/adc.c @@ -23,6 +23,8 @@ *****************************************************************************/ /** + * @file adc.c + * * @brief Analog to digital converter routines * * IMPORTANT: maximum external impedance must be below 0.4kOhms for 1.5 @@ -30,7 +32,7 @@ * * At 55.5 cycles/sample, the external input impedance < 50kOhms. * - * See stm32 manual RM008 for how to calculate this. + * See STM32 manual RM0008 for how to calculate this. */ #include "libmaple.h" diff --git a/main.cpp.example b/main.cpp.example index 8fc522a..3ae114b 100644 --- a/main.cpp.example +++ b/main.cpp.example @@ -27,7 +27,7 @@ void loop() { } // Force init to be called *first*, i.e. before static object allocation. -// Otherwise, statically allocated object that need libmaple may fail. +// Otherwise, statically allocated objects that need libmaple may fail. __attribute__(( constructor )) void premain() { init(); } diff --git a/wirish/boards.h b/wirish/boards.h index 989eea1..ee93c5a 100644 --- a/wirish/boards.h +++ b/wirish/boards.h @@ -133,7 +133,7 @@ typedef struct PinMapping { /* D23/PC15 */ {GPIOC_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, /* D24/PB9 */ - {GPIOB_BASE, 9, ADC_INVALID, TIMER4_CH4_CCR, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, + {GPIOB_BASE, 9, ADC_INVALID, TIMER4_CH4_CCR, EXTI_CONFIG_PORTB, TIMER4, 4}, /* D25/PD2 */ {GPIOD_BASE, 2, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, /* D26/PC10 */ diff --git a/wirish/main.cxx b/wirish/main.cxx index f0158f8..dd5e296 100644 --- a/wirish/main.cxx +++ b/wirish/main.cxx @@ -1,4 +1,4 @@ -/* ***************************************************************************** +/****************************************************************************** * The MIT License * * Copyright (c) 2010 LeafLabs LLC. @@ -20,16 +20,15 @@ * 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. - * ****************************************************************************/ + *****************************************************************************/ // Force init to be called *first*, i.e. before static object allocation. -// Otherwise, statically allocated object that need libmaple may fail. +// Otherwise, statically allocated objects that need libmaple may fail. __attribute__(( constructor )) void premain() { init(); } -int main(void) -{ +int main(void) { setup(); while (1) { -- cgit v1.2.3 From 9872b3975bd40c55652bb9dead5f54e2be9740d0 Mon Sep 17 00:00:00 2001 From: Perry Hung Date: Thu, 10 Mar 2011 00:04:58 -0500 Subject: Fix merge error and compile error. --- libmaple/delay.h | 22 +++++++ libmaple/i2c.c | 168 ++++++++++++---------------------------------------- libmaple/i2c.h | 116 ++++++++++++++++++++++++++++-------- libmaple/libmaple.h | 2 + libmaple/rcc.c | 2 +- libmaple/stm32.h | 10 ++++ main.cpp | 28 ++++++--- wirish/time.c | 13 +--- 8 files changed, 186 insertions(+), 175 deletions(-) create mode 100644 libmaple/delay.h diff --git a/libmaple/delay.h b/libmaple/delay.h new file mode 100644 index 0000000..10839c9 --- /dev/null +++ b/libmaple/delay.h @@ -0,0 +1,22 @@ +/** + * @brief + */ + +#ifndef _DELAY_H_ +#define _DELAY_H_ + +static inline void delay_us(uint32 us) { + /* So (2^32)/12 micros max, or less than 6 minutes */ + us *= 12; + + /* fudge for function call overhead */ + us--; + asm volatile(" mov r0, %[us] \n\t" + "1: subs r0, #1 \n\t" + " bhi 1b \n\t" + : + : [us] "r" (us) + : "r0"); +} +#endif + diff --git a/libmaple/i2c.c b/libmaple/i2c.c index 1a595f5..3e948f6 100644 --- a/libmaple/i2c.c +++ b/libmaple/i2c.c @@ -39,11 +39,12 @@ /* 2/17 Started 10pm-4am * 2/19 Started 7pm-2am * 2/20 Started 7pm-7pm - * 2/23 Started 8pm */ + * 2/23 Started 8pm-8am + * 3/9 Started 11pm */ static inline int32 wait_for_state_change(i2c_dev *dev, i2c_state state); -i2c_dev i2c_dev1 = { +static i2c_dev i2c_dev1 = { .regs = (i2c_reg_map*)I2C1_BASE, .gpio_port = GPIOB_BASE, .sda_pin = 7, @@ -54,30 +55,13 @@ i2c_dev i2c_dev1 = { .state = I2C_STATE_IDLE }; +i2c_dev* const I2C1 = &i2c_dev1; + /** * @brief IRQ handler for i2c master. Handles transmission/reception. * @param dev i2c device */ -void delay_us(uint32 us) { - /* So (2^32)/12 micros max, or less than 6 minutes */ - us *= 12; - - /* fudge for function call overhead */ - us--; - asm volatile(" mov r0, %[us] \n\t" - "1: subs r0, #1 \n\t" - " bhi 1b \n\t" - : - : [us] "r" (us) - : "r0"); -} -static inline void debug_toggle(uint32 delay) { - gpio_write_bit(GPIOA_BASE, 5, 1); - delay_us(delay); - gpio_write_bit(GPIOA_BASE, 5, 0); -} - struct crumb { uint32 event; uint32 sr1; @@ -125,15 +109,15 @@ static void i2c_irq_handler(i2c_dev *dev) { */ if (sr1 & I2C_SR1_SB) { msg->xferred = 0; - i2c_enable_irq(dev->regs, I2C_IRQ_BUFFER); + i2c_enable_irq(dev, I2C_IRQ_BUFFER); /* * Master receiver */ if (read) { - i2c_enable_ack(dev->regs); + i2c_enable_ack(dev); } - i2c_send_slave_addr(dev->regs, msg->addr, read); + i2c_send_slave_addr(dev, msg->addr, read); sr1 = sr2 = 0; } @@ -148,13 +132,13 @@ static void i2c_irq_handler(i2c_dev *dev) { */ if (read) { if (msg->length == 1) { - i2c_disable_ack(dev->regs); + i2c_disable_ack(dev); dev->msgs_left--; if (dev->msgs_left) { - i2c_start_condition(dev->regs); + i2c_start_condition(dev); leave_big_crumb(RX_ADDR_START, 0, 0); } else { - i2c_stop_condition(dev->regs); + i2c_stop_condition(dev); leave_big_crumb(RX_ADDR_STOP, 0, 0); } } @@ -163,7 +147,7 @@ static void i2c_irq_handler(i2c_dev *dev) { * Master transmitter: write first byte to fill shift register. * We should get another TXE interrupt immediately to fill DR again. */ - i2c_write(dev->regs, msg->data[msg->xferred++]); + i2c_write(dev, msg->data[msg->xferred++]); } sr1 = sr2 = 0; } @@ -176,13 +160,13 @@ static void i2c_irq_handler(i2c_dev *dev) { if ((sr1 & I2C_SR1_TXE) && !(sr1 & I2C_SR1_BTF)) { leave_big_crumb(TXE_ONLY, 0, 0); if (dev->msgs_left) { - i2c_write(dev->regs, msg->data[msg->xferred++]); + i2c_write(dev, msg->data[msg->xferred++]); if (msg->xferred == msg->length) { /* * End of this message. Turn off TXE/RXNE and wait for * BTF to send repeated start or stop condition. */ - i2c_disable_irq(dev->regs, I2C_IRQ_BUFFER); + i2c_disable_irq(dev, I2C_IRQ_BUFFER); dev->msgs_left--; } } else { @@ -207,18 +191,21 @@ static void i2c_irq_handler(i2c_dev *dev) { * won't interrupt, but if we don't disable ITEVTEN, BTF will * continually interrupt us. What the fuck ST? */ - i2c_start_condition(dev->regs); + i2c_start_condition(dev); while (!(dev->regs->SR1 & I2C_SR1_SB)) ; dev->msg++; } else { - i2c_stop_condition(dev->regs); + i2c_stop_condition(dev); +// while (dev->regs->CR1 & I2C_CR1_STOP) { +// ; +// } /* * Turn off event interrupts to keep BTF from firing until the end * of the stop condition. Why on earth they didn't have a start/stop * condition request clear BTF is beyond me. */ - i2c_disable_irq(dev->regs, I2C_IRQ_EVENT); + i2c_disable_irq(dev, I2C_IRQ_EVENT); leave_big_crumb(STOP_SENT, 0, 0); dev->state = I2C_STATE_XFER_DONE; } @@ -238,12 +225,12 @@ static void i2c_irq_handler(i2c_dev *dev) { * RXNE interrupt before shutting things down. */ if (msg->xferred == (msg->length - 1)) { - i2c_disable_ack(dev->regs); + i2c_disable_ack(dev); if (dev->msgs_left > 2) { - i2c_start_condition(dev->regs); + i2c_start_condition(dev); leave_big_crumb(RXNE_START_SENT, 0, 0); } else { - i2c_stop_condition(dev->regs); + i2c_stop_condition(dev); leave_big_crumb(RXNE_STOP_SENT, 0, 0); } } else if (msg->xferred == msg->length) { @@ -262,11 +249,18 @@ static void i2c_irq_handler(i2c_dev *dev) { } void __irq_i2c1_ev(void) { - i2c_dev *dev = I2C1; - i2c_irq_handler(dev); + i2c_irq_handler(&i2c_dev1); +} + +static void i2c_irq_error_handler(i2c_dev *dev) { + __error(); } -static void i2c_bus_reset(i2c_dev *dev) { +void __irq_i2c1_er(void) { + i2c_irq_error_handler(&i2c_dev1); +} + +static void i2c_bus_reset(const i2c_dev *dev) { /* Release both lines */ gpio_write_bit(dev->gpio_port, dev->scl_pin, 1); gpio_write_bit(dev->gpio_port, dev->sda_pin, 1); @@ -322,21 +316,21 @@ void i2c_master_enable(i2c_dev *dev, uint32 flags) { gpio_set_mode(dev->gpio_port, dev->scl_pin, GPIO_MODE_AF_OUTPUT_OD); /* I2C1 and I2C2 are fed from APB1, clocked at 36MHz */ - i2c_set_input_clk(dev->regs, 36); + i2c_set_input_clk(dev, 36); /* 100 khz only for now */ - i2c_set_clk_control(dev->regs, STANDARD_CCR); + i2c_set_clk_control(dev, STANDARD_CCR); /* * Set scl rise time, standard mode for now. * Max rise time in standard mode: 1000 ns * Max rise time in fast mode: 300ns */ - i2c_set_trise(dev->regs, STANDARD_TRISE); + i2c_set_trise(dev, STANDARD_TRISE); /* Enable event and buffer interrupts */ nvic_irq_enable(dev->ev_nvic_line); - i2c_enable_irq(dev->regs, I2C_IRQ_EVENT | I2C_IRQ_BUFFER); + i2c_enable_irq(dev, I2C_IRQ_EVENT | I2C_IRQ_BUFFER); /* * Important STM32 Errata: @@ -368,13 +362,12 @@ void i2c_master_enable(i2c_dev *dev, uint32 flags) { nvic_irq_set_priority(dev->ev_nvic_line, 0); /* Make it go! */ - i2c_peripheral_enable(dev->regs); + i2c_peripheral_enable(dev); } int32 i2c_master_xfer(i2c_dev *dev, i2c_msg *msgs, uint16 num) { int32 rc; - static int times = 0; dev->msg = msgs; dev->msgs_left = num; @@ -389,7 +382,7 @@ int32 i2c_master_xfer(i2c_dev *dev, i2c_msg *msgs, uint16 num) { dev->state = I2C_STATE_BUSY; - i2c_start_condition(dev->regs); + i2c_start_condition(dev); rc = wait_for_state_change(dev, I2C_STATE_XFER_DONE); if (rc < 0) { goto out; @@ -414,89 +407,6 @@ static inline int32 wait_for_state_change(i2c_dev *dev, i2c_state state) { } -/* - * Low level register twiddling functions - */ - -/** - * @brief turn on an i2c peripheral - * @param map i2c peripheral register base - */ -void i2c_peripheral_enable(i2c_reg_map *regs) { - regs->CR1 |= I2C_CR1_PE; -} - -/** - * @brief turn off an i2c peripheral - * @param map i2c peripheral register base - */ -void i2c_peripheral_disable(i2c_reg_map *regs) { - regs->CR1 &= ~I2C_CR1_PE; -} - -/** - * @brief Set input clock frequency, in mhz - * @param device to configure - * @param freq frequency in megahertz (2-36) - */ -void i2c_set_input_clk(i2c_reg_map *regs, uint32 freq) { - uint32 cr2 = regs->CR2; - cr2 &= ~I2C_CR2_FREQ; - cr2 |= freq; - regs->CR2 = freq; -} - -void i2c_set_clk_control(i2c_reg_map *regs, uint32 val) { - uint32 ccr = regs->CCR; - ccr &= ~I2C_CCR_CCR; - ccr |= val; - regs->CCR = ccr; -} - -void i2c_set_fast_mode(i2c_reg_map *regs) { - regs->CCR |= I2C_CCR_FS; -} - -void i2c_set_standard_mode(i2c_reg_map *regs) { - regs->CCR &= ~I2C_CCR_FS; -} - -/** - * @brief Set SCL rise time - * @param - */ - -void i2c_set_trise(i2c_reg_map *regs, uint32 trise) { - regs->TRISE = trise; -} - -void i2c_start_condition(i2c_reg_map *regs) { - regs->CR1 |= I2C_CR1_START; -} - -void i2c_stop_condition(i2c_reg_map *regs) { - regs->CR1 |= I2C_CR1_STOP; -} - -void i2c_send_slave_addr(i2c_reg_map *regs, uint32 addr, uint32 rw) { - regs->DR = (addr << 1) | rw; -} - -void i2c_enable_irq(i2c_reg_map *regs, uint32 irqs) { - regs->CR2 |= irqs; -} - -void i2c_disable_irq(i2c_reg_map *regs, uint32 irqs) { - regs->CR2 &= ~irqs; -} - -void i2c_enable_ack(i2c_reg_map *regs) { - regs->CR1 |= I2C_CR1_ACK; -} - -void i2c_disable_ack(i2c_reg_map *regs) { - regs->CR1 &= ~I2C_CR1_ACK; -} diff --git a/libmaple/i2c.h b/libmaple/i2c.h index 2e6d00d..be05615 100644 --- a/libmaple/i2c.h +++ b/libmaple/i2c.h @@ -72,14 +72,10 @@ typedef struct i2c_dev { } i2c_dev; -extern i2c_dev i2c_dev1; -extern i2c_dev i2c_dev2; +extern i2c_dev* const I2C1; -#define I2C1 (i2c_dev*)&i2c_dev1 -#define I2C2 (i2c_dev*)&i2c_dev2 - -#define I2C1_BASE 0x40005400 -#define I2C2_BASE 0x40005800 +#define I2C1_BASE (i2c_reg_map*)0x40005400 +#define I2C2_BASE (i2c_reg_map*)0x40005800 /* i2c enable options */ #define I2C_FAST_MODE 0x1 // 400 khz @@ -140,28 +136,98 @@ extern "C" { void i2c_master_enable(i2c_dev *dev, uint32 flags); int32 i2c_master_xfer(i2c_dev *dev, i2c_msg *msgs, uint16 num); -void i2c_start_condition(i2c_reg_map *regs); -void i2c_stop_condition(i2c_reg_map *regs); -void i2c_send_slave_addr(i2c_reg_map *regs, uint32 addr, uint32 rw); -void i2c_set_input_clk(i2c_reg_map *regs, uint32 freq); -void i2c_set_clk_control(i2c_reg_map *regs, uint32 val); -void i2c_set_fast_mode(i2c_reg_map *regs); -void i2c_set_standard_mode(i2c_reg_map *regs); -void i2c_set_trise(i2c_reg_map *regs, uint32 trise); -void i2c_enable_ack(i2c_reg_map *regs); -void i2c_disable_ack(i2c_reg_map *regs); - -/* interrupt flags */ +static inline void i2c_write(i2c_dev *dev, uint8 byte) { + dev->regs->DR = byte; +} + +/* + * Low level register twiddling functions + */ + +/** + * @brief turn on an i2c peripheral + * @param map i2c peripheral register base + */ +static inline void i2c_peripheral_enable(i2c_dev *dev) { + dev->regs->CR1 |= I2C_CR1_PE; +} + +/** + * @brief turn off an i2c peripheral + * @param map i2c peripheral register base + */ +static inline void i2c_peripheral_disable(i2c_dev *dev) { + dev->regs->CR1 &= ~I2C_CR1_PE; +} + +/** + * @brief Set input clock frequency, in mhz + * @param device to configure + * @param freq frequency in megahertz (2-36) + */ +static inline void i2c_set_input_clk(i2c_dev *dev, uint32 freq) { + uint32 cr2 = dev->regs->CR2; + cr2 &= ~I2C_CR2_FREQ; + cr2 |= freq; + dev->regs->CR2 = freq; +} + +static inline void i2c_set_clk_control(i2c_dev *dev, uint32 val) { + uint32 ccr = dev->regs->CCR; + ccr &= ~I2C_CCR_CCR; + ccr |= val; + dev->regs->CCR = ccr; +} + +static inline void i2c_set_fast_mode(i2c_dev *dev) { + dev->regs->CCR |= I2C_CCR_FS; +} + +static inline void i2c_set_standard_mode(i2c_dev *dev) { + dev->regs->CCR &= ~I2C_CCR_FS; +} + +/** + * @brief Set SCL rise time + * @param + */ +static inline void i2c_set_trise(i2c_dev *dev, uint32 trise) { + dev->regs->TRISE = trise; +} + +extern void toggle(void); +static inline void i2c_start_condition(i2c_dev *dev) { + uint32 cr1 = dev->regs->CR1; +// if (cr1 & (I2C_CR1_START | I2C_CR1_STOP | I2C_CR1_PEC)) { +// } + dev->regs->CR1 |= I2C_CR1_START; +} + +static inline void i2c_stop_condition(i2c_dev *dev) { + dev->regs->CR1 |= I2C_CR1_STOP; +} + +static inline void i2c_send_slave_addr(i2c_dev *dev, uint32 addr, uint32 rw) { + dev->regs->DR = (addr << 1) | rw; +} + #define I2C_IRQ_ERROR I2C_CR2_ITERREN #define I2C_IRQ_EVENT I2C_CR2_ITEVTEN #define I2C_IRQ_BUFFER I2C_CR2_ITBUFEN -void i2c_enable_irq(i2c_reg_map *regs, uint32 irqs); -void i2c_disable_irq(i2c_reg_map *regs, uint32 irqs); -void i2c_peripheral_enable(i2c_reg_map *regs); -void i2c_peripheral_disable(i2c_reg_map *regs); +static inline void i2c_enable_irq(i2c_dev *dev, uint32 irqs) { + dev->regs->CR2 |= irqs; +} + +static inline void i2c_disable_irq(i2c_dev *dev, uint32 irqs) { + dev->regs->CR2 &= ~irqs; +} + +static inline void i2c_enable_ack(i2c_dev *dev) { + dev->regs->CR1 |= I2C_CR1_ACK; +} -static inline void i2c_write(i2c_reg_map *regs, uint8 byte) { - regs->DR = byte; +static inline void i2c_disable_ack(i2c_dev *dev) { + dev->regs->CR1 &= ~I2C_CR1_ACK; } #ifdef __cplusplus diff --git a/libmaple/libmaple.h b/libmaple/libmaple.h index 6b75c96..50887bc 100644 --- a/libmaple/libmaple.h +++ b/libmaple/libmaple.h @@ -31,7 +31,9 @@ #define _LIBMAPLE_H_ #include "libmaple_types.h" +#include "stm32.h" #include "util.h" +#include "delay.h" /* * Where to put usercode, based on space reserved for bootloader. diff --git a/libmaple/rcc.c b/libmaple/rcc.c index d3fb6a3..6445958 100644 --- a/libmaple/rcc.c +++ b/libmaple/rcc.c @@ -75,7 +75,7 @@ static const struct rcc_dev_info rcc_dev_table[] = { [RCC_DMA1] = { .clk_domain = AHB, .line_num = 0 }, [RCC_DMA2] = { .clk_domain = AHB, .line_num = 1 }, // High-density only [RCC_PWR] = { .clk_domain = APB1, .line_num = 28}, - [RCC_BKP] = { .clk_domain = APB1, .line_num = 27} + [RCC_BKP] = { .clk_domain = APB1, .line_num = 27}, [RCC_I2C1] = { .clk_domain = APB1, .line_num = 21 }, // High-density only [RCC_I2C2] = { .clk_domain = APB1, .line_num = 22 }, // High-density only }; diff --git a/libmaple/stm32.h b/libmaple/stm32.h index e65b28c..21c18df 100644 --- a/libmaple/stm32.h +++ b/libmaple/stm32.h @@ -8,5 +8,15 @@ #define PCLK1 36000000U #define PCLK2 72000000U +#ifdef STM32_MEDIUM_DENSITY + #define NR_INTERRUPTS 43 +#else +#ifdef STM32_HIGH_DENSITY + #define NR_INTERRUPTS 60 +#else +#error "No STM32 board type defined!" +#endif +#endif + #endif diff --git a/main.cpp b/main.cpp index 5e3ddf3..7771fa7 100644 --- a/main.cpp +++ b/main.cpp @@ -6,19 +6,29 @@ static const uint8 slave_address = 0b1010001; -#define NR_ELEMENTS 64 +#define NR_ELEMENTS 4 uint8 buf0[NR_ELEMENTS + 2] = {0x0, 0x0}; uint8 buf1[] = {0x0, 0x0}; uint8 buf2[NR_ELEMENTS]; +i2c_msg msgs[3]; + +void toggle(void) { + digitalWrite(2, HIGH); + digitalWrite(2, LOW); +} + void setup() { - i2c_msg msgs[3]; uint32 i; pinMode(BOARD_LED_PIN, OUTPUT); + pinMode(2, OUTPUT); + Serial2.begin(9600); + Serial2.println("Hello!"); + digitalWrite(2, LOW); - for (i = 0; i < sizeof buf0; i++) { - buf0[i + 2] = i & 0xFF; + for (i = 2; i < sizeof buf0; i++) { + buf0[i] = i - 2; } i2c_master_enable(I2C1, 0); @@ -31,6 +41,11 @@ void setup() { i2c_master_xfer(I2C1, msgs, 1); delay(5); +} + +void loop() { + delay(100); + toggleLED(); /* Write slave address to read */ msgs[1].addr = slave_address; msgs[1].flags = 0; @@ -45,11 +60,6 @@ void setup() { i2c_master_xfer(I2C1, msgs + 1, 2); } -void loop() { - toggleLED(); - delay(100); -} - // Force init to be called *first*, i.e. before static object allocation. // Otherwise, statically allocated object that need libmaple may fail. __attribute__(( constructor )) void premain() { diff --git a/wirish/time.c b/wirish/time.c index c0a0649..b5663b0 100644 --- a/wirish/time.c +++ b/wirish/time.c @@ -29,6 +29,7 @@ #include "libmaple.h" #include "systick.h" #include "time.h" +#include "delay.h" void delay(unsigned long ms) { uint32 i; @@ -38,15 +39,5 @@ void delay(unsigned long ms) { } void delayMicroseconds(uint32 us) { - /* So (2^32)/12 micros max, or less than 6 minutes */ - us *= 12; - - /* fudge for function call overhead */ - us--; - asm volatile(" mov r0, %[us] \n\t" - "1: subs r0, #1 \n\t" - " bhi 1b \n\t" - : - : [us] "r" (us) - : "r0"); + delay_us(us); } -- cgit v1.2.3 From c8da1c3b7b6eb450138a00af9bbbee607f596837 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Mon, 7 Mar 2011 13:11:54 -0500 Subject: [WIP] GPIO refactor: seems ok, ready for review --- Makefile | 8 +- docs/Doxyfile | 6 +- examples/test-session.cpp | 28 +-- libmaple/adc.c | 4 +- libmaple/adc.h | 38 ++-- libmaple/bitband.h | 83 +++++++++ libmaple/bkp.c | 6 +- libmaple/bkp.h | 16 +- libmaple/dac.c | 6 +- libmaple/dac.h | 10 +- libmaple/exti.c | 244 +++++++++++++++---------- libmaple/exti.h | 158 ++++------------ libmaple/fsmc.c | 89 ++++----- libmaple/fsmc.h | 5 +- libmaple/gpio.c | 165 ++++++++++++++--- libmaple/gpio.h | 391 ++++++++++++++++++++++++++++++---------- libmaple/libmaple.h | 2 +- libmaple/libmaple_types.h | 1 + libmaple/pwr.h | 9 +- libmaple/rcc.h | 3 +- libmaple/ring_buffer.h | 17 +- libmaple/spi.c | 18 +- libmaple/usb/usb.c | 33 +++- libmaple/usb/usb_callbacks.c | 2 +- libmaple/usb/usb_config.h | 7 +- libmaple/usb/usb_hardware.c | 41 ----- libmaple/usb/usb_hardware.h | 36 +--- libmaple/util.c | 6 +- libmaple/util.h | 35 ++-- notes/coding_standard.txt | 85 +++++---- notes/exti.txt | 67 +++++++ wirish/HardwareTimer.cpp | 11 +- wirish/boards.cpp | 387 +++++++++++++++++++++++++++++++++++++++ wirish/boards.h | 401 ++--------------------------------------- wirish/comm/HardwareSerial.cpp | 14 +- wirish/comm/HardwareSerial.h | 4 +- wirish/ext_interrupts.c | 79 -------- wirish/ext_interrupts.cpp | 82 +++++++++ wirish/ext_interrupts.h | 11 +- wirish/io.h | 11 +- wirish/pwm.c | 48 ----- wirish/pwm.cpp | 48 +++++ wirish/pwm.h | 13 +- wirish/rules.mk | 32 ++-- wirish/time.c | 52 ------ wirish/time.cpp | 52 ++++++ wirish/time.h | 9 - wirish/wirish.c | 81 --------- wirish/wirish.cpp | 82 +++++++++ wirish/wirish.h | 16 +- wirish/wirish_analog.c | 41 ----- wirish/wirish_analog.cpp | 41 +++++ wirish/wirish_digital.c | 142 --------------- wirish/wirish_digital.cpp | 143 +++++++++++++++ wirish/wirish_math.h | 9 +- wirish/wirish_shift.c | 40 ---- wirish/wirish_shift.cpp | 40 ++++ 57 files changed, 1928 insertions(+), 1580 deletions(-) create mode 100644 libmaple/bitband.h create mode 100644 notes/exti.txt create mode 100644 wirish/boards.cpp delete mode 100644 wirish/ext_interrupts.c create mode 100644 wirish/ext_interrupts.cpp delete mode 100644 wirish/pwm.c create mode 100644 wirish/pwm.cpp delete mode 100644 wirish/time.c create mode 100644 wirish/time.cpp delete mode 100644 wirish/wirish.c create mode 100644 wirish/wirish.cpp delete mode 100644 wirish/wirish_analog.c create mode 100644 wirish/wirish_analog.cpp delete mode 100644 wirish/wirish_digital.c create mode 100644 wirish/wirish_digital.cpp delete mode 100644 wirish/wirish_shift.c create mode 100644 wirish/wirish_shift.cpp diff --git a/Makefile b/Makefile index 01e1e72..3804421 100644 --- a/Makefile +++ b/Makefile @@ -13,21 +13,21 @@ PRODUCT_ID := 0003 ifeq ($(BOARD), maple) MCU := STM32F103RB PRODUCT_ID := 0003 - ERROR_LED_PORT := GPIOA_BASE + ERROR_LED_PORT := GPIOA ERROR_LED_PIN := 5 DENSITY := STM32_MEDIUM_DENSITY endif ifeq ($(BOARD), maple_native) MCU := STM32F103ZE PRODUCT_ID := 0003 - ERROR_LED_PORT := GPIOC_BASE + ERROR_LED_PORT := GPIOC ERROR_LED_PIN := 15 DENSITY := STM32_HIGH_DENSITY endif ifeq ($(BOARD), maple_mini) MCU := STM32F103CB PRODUCT_ID := 0003 - ERROR_LED_PORT := GPIOB_BASE + ERROR_LED_PORT := GPIOB ERROR_LED_PIN := 1 DENSITY := STM32_MEDIUM_DENSITY endif @@ -45,7 +45,7 @@ SUPPORT_PATH := $(SRCROOT)/support # Compilation flags. # FIXME remove the ERROR_LED config GLOBAL_CFLAGS := -Os -g3 -gdwarf-2 -mcpu=cortex-m3 -mthumb -march=armv7-m \ - -nostdlib \ + -nostdlib \ -ffunction-sections -fdata-sections -Wl,--gc-sections \ -DBOARD_$(BOARD) -DMCU_$(MCU) \ -DERROR_LED_PORT=$(ERROR_LED_PORT) \ diff --git a/docs/Doxyfile b/docs/Doxyfile index 3290843..9bf02fc 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -620,7 +620,9 @@ RECURSIVE = YES # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. -EXCLUDE = +# FIXME The USB thing needs to get redone (ST code stripped out, +# etc.). Until then, just ignore it. +EXCLUDE = ../libmaple/usb/ # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded @@ -1369,7 +1371,7 @@ INCLUDE_FILE_PATTERNS = # undefined via #undef or recursively expanded use the := operator # instead of the = operator. -PREDEFINED = ALWAYS_INLINE= \ +PREDEFINED = __attribute__()= \ __cplusplus # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then diff --git a/examples/test-session.cpp b/examples/test-session.cpp index 72d64d6..ea631ca 100644 --- a/examples/test-session.cpp +++ b/examples/test-session.cpp @@ -351,22 +351,22 @@ void cmd_everything(void) { // TODO } void fast_gpio(int maple_pin) { - GPIO_Port *port = PIN_MAP[maple_pin].port; + gpio_dev *dev = PIN_MAP[maple_pin].gpio_device; uint32 pin = PIN_MAP[maple_pin].pin; - gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0); - gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0); - gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0); - gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0); - gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0); - gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0); - gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0); - gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0); - gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0); - gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0); - gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0); - gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0); - gpio_write_bit(port, pin, 1); gpio_write_bit(port, pin, 0); + gpio_write_bit(dev, pin, 1); gpio_write_bit(dev, pin, 0); + gpio_write_bit(dev, pin, 1); gpio_write_bit(dev, pin, 0); + gpio_write_bit(dev, pin, 1); gpio_write_bit(dev, pin, 0); + gpio_write_bit(dev, pin, 1); gpio_write_bit(dev, pin, 0); + gpio_write_bit(dev, pin, 1); gpio_write_bit(dev, pin, 0); + gpio_write_bit(dev, pin, 1); gpio_write_bit(dev, pin, 0); + gpio_write_bit(dev, pin, 1); gpio_write_bit(dev, pin, 0); + gpio_write_bit(dev, pin, 1); gpio_write_bit(dev, pin, 0); + gpio_write_bit(dev, pin, 1); gpio_write_bit(dev, pin, 0); + gpio_write_bit(dev, pin, 1); gpio_write_bit(dev, pin, 0); + gpio_write_bit(dev, pin, 1); gpio_write_bit(dev, pin, 0); + gpio_write_bit(dev, pin, 1); gpio_write_bit(dev, pin, 0); + gpio_write_bit(dev, pin, 1); gpio_write_bit(dev, pin, 0); } void cmd_serial1_serial3(void) { diff --git a/libmaple/adc.c b/libmaple/adc.c index a464746..9626a40 100644 --- a/libmaple/adc.c +++ b/libmaple/adc.c @@ -126,8 +126,8 @@ void adc_set_sample_rate(const adc_dev *dev, adc_smp_rate smp_rate) { * @param dev adc device */ static void adc_calibrate(const adc_dev *dev) { - __io uint32 *rstcal_bit = (__io uint32*)BITBAND_PERI(&(dev->regs->CR2), 3); - __io uint32 *cal_bit = (__io uint32*)BITBAND_PERI(&(dev->regs->CR2), 2); + __io uint32 *rstcal_bit = bb_peripv(&(dev->regs->CR2), 3); + __io uint32 *cal_bit = bb_peripv(&(dev->regs->CR2), 2); *rstcal_bit = 1; while (*rstcal_bit) diff --git a/libmaple/adc.h b/libmaple/adc.h index ac386fb..4811dbc 100644 --- a/libmaple/adc.h +++ b/libmaple/adc.h @@ -30,14 +30,16 @@ #ifndef _ADC_H_ #define _ADC_H_ -#include "util.h" +#include "libmaple.h" +#include "bitband.h" #include "rcc.h" #ifdef __cplusplus extern "C"{ #endif +/** ADC register map type. */ typedef struct adc_reg_map { __io uint32 SR; ///< Status register __io uint32 CR1; ///< Control register 1 @@ -61,22 +63,30 @@ typedef struct adc_reg_map { __io uint32 DR; ///< Regular data register } adc_reg_map; +/** ADC device type. */ typedef struct adc_dev { - adc_reg_map *regs; - rcc_clk_id clk_id; + adc_reg_map *regs; /**< Register map */ + rcc_clk_id clk_id; /**< RCC clock information */ } adc_dev; +/** ADC1 device. */ extern const adc_dev *ADC1; +/** ADC2 device. */ extern const adc_dev *ADC2; #ifdef STM32_HIGH_DENSITY +/** ADC3 device. */ extern const adc_dev *ADC3; #endif /* * ADC peripheral base addresses */ + +/** ADC1 register map base pointer. */ #define ADC1_BASE ((adc_reg_map*)0x40012400) +/** ADC2 register map base pointer. */ #define ADC2_BASE ((adc_reg_map*)0x40012800) +/** ADC3 register map base pointer. */ #define ADC3_BASE ((adc_reg_map*)0x40013C00) /* @@ -138,8 +148,8 @@ void adc_set_sample_rate(const adc_dev *dev, adc_smp_rate smp_rate); /** * @brief Perform a single synchronous software triggered conversion on a - * channel - * @param regs ADC register map + * channel. + * @param dev ADC device to use for reading. * @param channel channel to convert * @return conversion result */ @@ -161,27 +171,27 @@ static inline uint32 adc_read(const adc_dev *dev, uint8 channel) { /** * @brief Set external trigger conversion mode event for regular channels - * @param dev adc device - * @param enable if 1, conversion on external events is enabled, 0 to disable + * @param dev ADC device + * @param enable If 1, conversion on external events is enabled, 0 to disable */ static inline void adc_set_exttrig(const adc_dev *dev, uint8 enable) { - __write(BITBAND_PERI(&(dev->regs->CR2), 20), enable); + *bb_peripv(&dev->regs->CR2, 20) = !!enable; } /** * @brief Enable an adc peripheral - * @param regs register map of peripheral to enable + * @param dev ADC device to enable */ static inline void adc_enable(const adc_dev *dev) { - __write(BITBAND_PERI(&(dev->regs->CR2), 0), 1); + *bb_peripv(&dev->regs->CR2, 0) = 1; } /** - * @brief Disable an adc peripheral - * @param regs register map of peripheral to disable + * @brief Disable an ADC peripheral + * @param dev ADC device to disable */ static inline void adc_disable(const adc_dev *dev) { - __write(BITBAND_PERI(&(dev->regs->CR2), 0), 0); + *bb_peripv(&dev->regs->CR2, 0) = 0; } /** @@ -198,5 +208,5 @@ static inline void adc_disable_all(void) { #ifdef __cplusplus } // extern "C" #endif -#endif +#endif diff --git a/libmaple/bitband.h b/libmaple/bitband.h new file mode 100644 index 0000000..076335f --- /dev/null +++ b/libmaple/bitband.h @@ -0,0 +1,83 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file bitband.h + * + * @brief Bit-banding utility functions + */ + +#define BB_SRAM_REF 0x20000000 +#define BB_SRAM_BASE 0x22000000 +#define BB_PERI_REF 0x40000000 +#define BB_PERI_BASE 0x42000000 + +static inline uint32* __bb_addr(void*, uint32, uint32, uint32); +static inline __io uint32* __bb_addrv(__io void*, uint32, uint32, uint32); + +/** + * @brief Obtain a pointer to the bit-band address corresponding to a + * bit in an SRAM address. + * @param address Address in the bit-banded SRAM region + * @param bit Bit in address to bit-band + */ +static inline uint32* bb_sramp(void *address, uint32 bit) { + return __bb_addr(address, bit, BB_SRAM_BASE, BB_SRAM_REF); +} + +/** + * @brief Obtain a pointer to the bit-band address corresponding to a + * bit in a volatile SRAM address. + * @param address Address in the bit-banded SRAM region + * @param bit Bit in address to bit-band + */ +static inline __io uint32* bb_srampv(__io void *address, uint32 bit) { + return __bb_addrv(address, bit, BB_SRAM_BASE, BB_SRAM_REF); +} + +/** + * @brief Obtain a pointer to the bit-band address corresponding to a + * bit in a peripheral address. + * @param address Address in the bit-banded peripheral region + * @param bit Bit in address to bit-band + */ +static inline __io uint32* bb_peripv(__io void *address, uint32 bit) { + return __bb_addrv(address, bit, BB_PERI_BASE, BB_PERI_REF); +} + +static inline uint32* __bb_addr(void *address, + uint32 bit, + uint32 bb_base, + uint32 bb_ref) { + return (uint32*)(bb_base + ((uint32)address - bb_ref) * 32 + bit * 4); +} + +static inline __io uint32* __bb_addrv(__io void *address, + uint32 bit, + uint32 bb_base, + uint32 bb_ref) { + return (__io uint32*)__bb_addr((void*)address, bit, bb_base, bb_ref); +} diff --git a/libmaple/bkp.c b/libmaple/bkp.c index ed107d8..b152069 100644 --- a/libmaple/bkp.c +++ b/libmaple/bkp.c @@ -27,7 +27,7 @@ #include "bkp.h" #include "pwr.h" #include "rcc.h" -#include "util.h" +#include "bitband.h" static inline __io uint32* data_register(uint8 reg); @@ -57,14 +57,14 @@ void bkp_init(void) { * @see bkp_init() */ void bkp_enable_writes(void) { - __write(BITBAND_PERI(&(PWR_BASE->CR), PWR_CR_DBP), 1); + *bb_peripv(&PWR_BASE->CR, PWR_CR_DBP) = 1; } /** * Disable write access to the backup registers. */ void bkp_disable_writes(void) { - __write(BITBAND_PERI(&(PWR_BASE->CR), PWR_CR_DBP), 0); + *bb_peripv(&PWR_BASE->CR, PWR_CR_DBP) = 0; } /** diff --git a/libmaple/bkp.h b/libmaple/bkp.h index 96ef8d2..cea39b6 100644 --- a/libmaple/bkp.h +++ b/libmaple/bkp.h @@ -44,6 +44,7 @@ extern "C" { #define BKP_NR_DATA_REGS 42 #endif +/** Backup peripheral register map type. */ typedef struct bkp_reg_map { const uint32 RESERVED1; __io uint32 DR1; ///< Data register 1 @@ -97,20 +98,17 @@ typedef struct bkp_reg_map { #endif } bkp_reg_map; +/** Backup peripheral register map base pointer. */ +#define BKP_BASE ((bkp_reg_map*)0x40006C00) + +/** Backup peripheral device type. */ typedef struct bkp_dev { - bkp_reg_map *regs; + bkp_reg_map *regs; /**< Register map */ } bkp_dev; -/** - * Backup device. - */ +/** Backup device. */ extern const bkp_dev *BKP; -/* - * Backup peripheral base. - */ -#define BKP_BASE ((bkp_reg_map*)0x40006C00) - void bkp_init(void); void bkp_enable_writes(void); void bkp_disable_writes(void); diff --git a/libmaple/dac.c b/libmaple/dac.c index 54b555b..ef3a9f9 100644 --- a/libmaple/dac.c +++ b/libmaple/dac.c @@ -80,15 +80,15 @@ void dac_write_channel(uint8 channel, uint16 val) { void dac_enable_channel(uint8 channel) { /* * Setup ANALOG mode on PA4 and PA5. This mapping is consistent across - * all STM32 chips with a DAC. See RM008 12.2. + * all STM32 chips with a DAC. See RM0008 12.2. */ switch (channel) { case 1: - gpio_set_mode(GPIOA_BASE, 4, GPIO_MODE_INPUT_ANALOG); + gpio_set_mode(GPIOA, 4, GPIO_INPUT_ANALOG); DAC->regs->CR |= DAC_CR_EN1; break; case 2: - gpio_set_mode(GPIOA_BASE, 5, GPIO_MODE_INPUT_ANALOG); + gpio_set_mode(GPIOA, 5, GPIO_INPUT_ANALOG); DAC->regs->CR |= DAC_CR_EN2; break; } diff --git a/libmaple/dac.h b/libmaple/dac.h index bc64324..c897bb2 100644 --- a/libmaple/dac.h +++ b/libmaple/dac.h @@ -25,9 +25,10 @@ /** * @file dac.h * @brief Digital to analog converter header file - * See notes/dac.txt for more info */ +/* See notes/dac.txt for more info */ + #ifndef _DAC_H_ #define _DAC_H_ @@ -63,16 +64,15 @@ typedef struct dac_reg_map { __io uint32 DOR2; /**< Channel 2 data output register */ } dac_reg_map; +/** DAC device type. */ typedef struct dac_dev { - dac_reg_map *regs; + dac_reg_map *regs; /**< Register map */ } dac_dev; /** DAC device. */ extern const dac_dev *DAC; -/* - * DAC peripheral base address - */ +/** DAC register map base address */ #define DAC_BASE ((dac_reg_map*)0x40007400) /* diff --git a/libmaple/exti.c b/libmaple/exti.c index e8ad52a..8177e1e 100644 --- a/libmaple/exti.c +++ b/libmaple/exti.c @@ -23,19 +23,29 @@ *****************************************************************************/ /** + * @file exti.c * @brief External interrupt control routines */ #include "libmaple.h" #include "exti.h" #include "nvic.h" +#include "bitband.h" -typedef struct ExtIChannel { +/* + * Internal state + */ + +/* Status bitmaps, for external interrupts with multiplexed IRQs */ +static uint16 exti_9_5_en = 0; +static uint16 exti_15_10_en = 0; + +typedef struct exti_channel { void (*handler)(void); uint32 irq_line; -} ExtIChannel; +} exti_channel; -static ExtIChannel exti_channels[] = { +static exti_channel exti_channels[] = { { .handler = NULL, .irq_line = NVIC_EXTI0 }, // EXTI0 { .handler = NULL, .irq_line = NVIC_EXTI1 }, // EXTI1 { .handler = NULL, .irq_line = NVIC_EXTI2 }, // EXTI2 @@ -54,63 +64,127 @@ static ExtIChannel exti_channels[] = { { .handler = NULL, .irq_line = NVIC_EXTI15_10 }, // EXTI15 }; -static inline void clear_pending(int bit) { - __set_bits(EXTI_PR, BIT(bit)); - /* If the pending bit is cleared as the last instruction in an ISR, - * it won't actually be cleared in time and the ISR will fire again. - * Insert a 2-cycle buffer to allow it to take effect. */ - asm volatile("nop"); - asm volatile("nop"); -} +/* + * Convenience routines + */ + +static inline void enable_irq(afio_exti_num exti_num); +static inline void maybe_disable_irq(afio_exti_num exti_num); + +/** + * @brief Register a handler to run upon external interrupt. + * + * This function assumes that the interrupt request corresponding to + * the given external interrupt is masked. + * + * @param num External interrupt line number. + * @param port Port to use as source input for external interrupt. + * @param handler Function handler to execute when interrupt is triggered. + * @param mode Type of transition to trigger on, one of: + * EXTI_RISING, EXTI_FALLING, EXTI_RISING_FALLING. + * @see exti_num + * @see exti_port + * @see exti_trigger_mode + */ +void exti_attach_interrupt(afio_exti_num num, + afio_exti_port port, + voidFuncPtr handler, + exti_trigger_mode mode) { + ASSERT(handler); -static inline void dispatch_handler(uint32 channel) { - ASSERT(exti_channels[channel].handler); - if (exti_channels[channel].handler) { - (exti_channels[channel].handler)(); + /* Register the handler */ + exti_channels[num].handler = handler; + + /* Set trigger mode */ + switch (mode) { + case EXTI_RISING: + *bb_peripv(&EXTI_BASE->RTSR, num) = 1; + break; + case EXTI_FALLING: + *bb_peripv(&EXTI_BASE->FTSR, num) = 1; + break; + case EXTI_RISING_FALLING: + *bb_peripv(&EXTI_BASE->RTSR, num) = 1; + *bb_peripv(&EXTI_BASE->FTSR, num) = 1; + break; } + + /* Map num to port */ + afio_exti_select(num, port); + + /* Unmask external interrupt request */ + *bb_peripv(&EXTI_BASE->IMR, num) = 1; + + /* Enable the interrupt line */ + enable_irq(num); +} + +/** + * @brief Unregister an external interrupt handler + * @param num Number of the external interrupt line to disable. + * @see exti_num + */ +void exti_detach_interrupt(afio_exti_num num) { + /* First, mask the interrupt request */ + *bb_peripv(&EXTI_BASE->IMR, num) = 0; + + /* Then, clear the trigger selection registers */ + *bb_peripv(&EXTI_BASE->FTSR, num) = 0; + *bb_peripv(&EXTI_BASE->RTSR, num) = 0; + + /* Next, disable the IRQ, unless it's multiplexed and there are + * other active external interrupts on the same IRQ line */ + maybe_disable_irq(num); + + /* Finally, unregister the user's handler */ + exti_channels[num].handler = NULL; } -/* For EXTI0 through EXTI4, only one handler - * is associated with each channel, so we - * don't have to keep track of which channel +/* + * Interrupt handlers + */ + +static inline void clear_pending(uint32 exti_num); +static inline void dispatch_handler(uint32 exti_num); + +/* For AFIO_EXTI_0 through AFIO_EXTI_4, only one handler is associated + * with each channel, so we don't have to keep track of which channel * we came from */ void __irq_exti0(void) { - dispatch_handler(EXTI0); - clear_pending(EXTI0); + dispatch_handler(AFIO_EXTI_0); + clear_pending(AFIO_EXTI_0); } void __irq_exti1(void) { - dispatch_handler(EXTI1); - clear_pending(EXTI1); + dispatch_handler(AFIO_EXTI_1); + clear_pending(AFIO_EXTI_1); } void __irq_exti2(void) { - dispatch_handler(EXTI2); - clear_pending(EXTI2); + dispatch_handler(AFIO_EXTI_2); + clear_pending(AFIO_EXTI_2); } void __irq_exti3(void) { - dispatch_handler(EXTI3); - clear_pending(EXTI3); + dispatch_handler(AFIO_EXTI_3); + clear_pending(AFIO_EXTI_3); } void __irq_exti4(void) { - dispatch_handler(EXTI4); - clear_pending(EXTI4); + dispatch_handler(AFIO_EXTI_4); + clear_pending(AFIO_EXTI_4); } void __irq_exti9_5(void) { /* Figure out which channel it came from */ - uint32 pending; + uint32 pending = GET_BITS(EXTI_BASE->PR, 5, 9); uint32 i; - pending = REG_GET(EXTI_PR); - pending = GET_BITS(pending, 5, 9); /* Dispatch every handler if the pending bit is set */ for (i = 0; i < 5; i++) { if (pending & 0x1) { - dispatch_handler(EXTI5 + i); - clear_pending(EXTI5 + i); + dispatch_handler(AFIO_EXTI_5 + i); + clear_pending(AFIO_EXTI_5 + i); } pending >>= 1; } @@ -118,89 +192,59 @@ void __irq_exti9_5(void) { void __irq_exti15_10(void) { /* Figure out which channel it came from */ - uint32 pending; + uint32 pending = GET_BITS(EXTI_BASE->PR, 10, 15); uint32 i; - pending = REG_GET(EXTI_PR); - pending = GET_BITS(pending, 10, 15); /* Dispatch every handler if the pending bit is set */ for (i = 0; i < 6; i++) { if (pending & 0x1) { - dispatch_handler(EXTI10 + i); - clear_pending(EXTI10 + i); + dispatch_handler(AFIO_EXTI_10 + i); + clear_pending(AFIO_EXTI_10 + i); } pending >>= 1; } } - -/** - * @brief Register a handler to run upon external interrupt - * @param port source port of pin (eg EXTI_CONFIG_PORTA) - * @param pin pin number on the source port - * @param handler function handler to execute - * @param mode type of transition to trigger on +/* + * Auxiliary functions */ -void exti_attach_interrupt(uint32 port, - uint32 pin, - voidFuncPtr handler, - uint32 mode) { - static uint32 afio_regs[] = { - AFIO_EXTICR1, // EXT0-3 - AFIO_EXTICR2, // EXT4-7 - AFIO_EXTICR3, // EXT8-11 - AFIO_EXTICR4, // EXT12-15 - }; - - /* Note: All of the following code assumes that EXTI0 = 0 */ - ASSERT(EXTI0 == 0); - ASSERT(handler); - - uint32 channel = pin; - /* map port to channel */ - __write(afio_regs[pin/4], (port << ((pin % 4) * 4))); - - /* Unmask appropriate interrupt line */ - __set_bits(EXTI_IMR, BIT(channel)); - - /* Set trigger mode */ - switch (mode) { - case EXTI_RISING: - __set_bits(EXTI_RTSR, BIT(channel)); - break; - - case EXTI_FALLING: - __set_bits(EXTI_FTSR, BIT(channel)); - break; +static inline void clear_pending(uint32 exti_num) { + *bb_peripv(&EXTI_BASE->PR, exti_num) = 1; + /* If the pending bit is cleared as the last instruction in an ISR, + * it won't actually be cleared in time and the ISR will fire again. + * Insert a 2-cycle buffer to allow it to take effect. */ + asm volatile("nop"); + asm volatile("nop"); +} - case EXTI_RISING_FALLING: - __set_bits(EXTI_RTSR, BIT(channel)); - __set_bits(EXTI_FTSR, BIT(channel)); - break; +static inline void dispatch_handler(uint32 exti_num) { + ASSERT(exti_channels[exti_num].handler); + if (exti_channels[exti_num].handler) { + (exti_channels[exti_num].handler)(); } - - /* Register the handler */ - exti_channels[channel].handler = handler; - - /* Configure the enable interrupt bits for the NVIC */ - nvic_irq_enable(exti_channels[channel].irq_line); } +static inline void enable_irq(afio_exti_num exti) { + /* Maybe twiddle the IRQ bitmap for extis with multiplexed IRQs */ + if (exti > 4) { + uint16 *bitmap = exti < 10 ? &exti_9_5_en : &exti_15_10_en; + *bb_sramp(bitmap, exti) = 1; + } -/** - * @brief Unregister an external interrupt handler - * @param channel channel to disable (eg EXTI0) - */ -void exti_detach_interrupt(uint32 channel) { - ASSERT(channel < NR_EXTI_CHANNELS); - ASSERT(EXTI0 == 0); - - __clear_bits(EXTI_IMR, BIT(channel)); - __clear_bits(EXTI_FTSR, BIT(channel)); - __clear_bits(EXTI_RTSR, BIT(channel)); - - nvic_irq_disable(exti_channels[channel].irq_line); + nvic_irq_enable(exti_channels[exti].irq_line); +} - exti_channels[channel].handler = NULL; +static inline void maybe_disable_irq(afio_exti_num exti) { + if (exti > 4) { + uint16 *bitmap = exti < 10 ? &exti_9_5_en : &exti_15_10_en; + *bb_sramp(bitmap, exti) = 0; + if (*bitmap == 0) { + /* All of the external interrupts which share this IRQ + * line are disabled. */ + nvic_irq_disable(exti_channels[exti].irq_line); + } + } else { + nvic_irq_disable(exti_channels[exti].irq_line); + } } diff --git a/libmaple/exti.h b/libmaple/exti.h index 806578f..e145033 100644 --- a/libmaple/exti.h +++ b/libmaple/exti.h @@ -22,145 +22,51 @@ * THE SOFTWARE. *****************************************************************************/ - /** - * @file exti.h - * - * @brief External interrupt control prototypes and defines + * @file exti.h + * @brief External interrupt control prototypes and defines */ -#ifndef _EXTI_H_ -#define _EXTI_H_ - -/* Notes: - * - * To generate the interrupt, the interrupt line should be configured - * and enabled. This is done by programming the two trigger registers - * with the desired edge detection and by enabling the interrupt - * request by writing a '1' to the corresponding bit in the interrupt - * mask register. When the selected edge occurs on the external - * interrupt line, an interrupt request is generated. The pending bit - * corresponding to the interrupt line is also set. This request is - * reset by writing a '1' in the pending register. - * - * Hardware interrupt selection: - * - * To configure the 20 lines as interrupt sources, use the following - * procedure: - * - * 1) Configure AFIO_EXTIICR[y] to select the source input for EXTIx - * external interrupt - * 2) Configure the mask bits of the 20 interrupt lines (EXTI_IMR) - * 3) Configure the trigger selection bits of the interrupt lines - * (EXTI_RTSR and EXTI_FTSR) - * 4) Configure the enable and mask bits that control the NVIC_IRQ - * channel mapped to the External - * - * Interrupt Controller (EXTI) so that an inerrupt coming from one of - * the 20 lines can be correctly acknowledged. - * - * AFIO clock must be on. - * - * RM0008, page 107: "PD0, PD1 cannot be used for external - * interrupt/event generation on 36, 48, 64-bin packages." - * - * ---------------------------------------------------------------------------- - * Pin to EXTI Line Mappings: - * EXTI0 EXTI1 EXTI2 EXTI3 EXTI4 - * -------------------------------------------------------------------------- - * D2/PA0 D3/PA1 D1/PA2 D0/A6/PA3 D10/A10/PA4 - * D26/EXT7/PB0 D27/EXT8/PB1 D16/A2/PC2 D17/A3/PC3 D18/A4/PC4 - * D14/A0/PC0 D15/PC1 D25/EXT5/PD2 - * - * EXTI5 EXTI6 EXTI7 EXTI8 EXTI9 - * ---------------------------------------------------------------------------- - * D13/A13/PA5 D12/A12/PA6 D11/A11/PA7 D6/PA8 D7/PA9 - * D4/PB5 D5/PB6 D9/PB7 D38/PB8 D23/EXT4/PB9 - * D19/A5/PC5 D34/EXTI15/PC6 D35/EXT16/PC7 D36/PC8 D37/EXT18/PC9 - * - * EXTI10 EXTI11 EXTI12 EXTI13 EXTI14 - * ---------------------------------------------------------------------------- - * D8/PA10 D29/EXT10/PB11 D30/EXTI1/PB12 D31/EXTI12/PB13 D32/EXT13/PB14 - * D28/PB10 D20/EXTI1/PC13 D21/EXT2/PC14 - * D25/PC10 - * - * EXTI15 - * ---------------------------------------------------------------------------- - * D33/EXTI14/PB15 - * D22/EXT3/PC15 - * - * - * The 16 EXTI interrupts are mapped to 7 interrupt handlers. - * - * EXTI Lines to Interrupt Mapping: - * EXTI0 -> EXTI0 - * EXTI1 -> EXTI1 - * EXTI2 -> EXTI2 - * EXTI3 -> EXTI3 - * EXTI4 -> EXTI4 - * EXTI[5-9] -> EXT9_5 - * EXTI[10-15] -> EXT15_10 - * - * */ - -#define NR_EXTI_MODES 3 -#define NR_EXTI_CHANNELS 16 -#define NR_EXTI_PORTS NR_GPIO_PORTS // board specific +/* See notes/exti.txt for more info */ -#define EXTI_RISING 0 -#define EXTI_FALLING 1 -#define EXTI_RISING_FALLING 2 +#include "libmaple.h" +#include "gpio.h" -#define EXTI_IMR 0x40010400 // Interrupt mask register -#define EXTI_EMR (EXTI_IMR + 0x04) // Event mask register -#define EXTI_RTSR (EXTI_IMR + 0x08) // Rising trigger selection register -#define EXTI_FTSR (EXTI_IMR + 0x0C) // Falling trigger selection register -#define EXTI_SWIER (EXTI_IMR + 0x10) // Software interrupt event register -#define EXTI_PR (EXTI_IMR + 0x14) // Pending register - -#define AFIO_EVCR 0x40010000 -#define AFIO_EXTICR1 (AFIO_EVCR + 0x08) -#define AFIO_EXTICR2 (AFIO_EVCR + 0x0C) -#define AFIO_EXTICR3 (AFIO_EVCR + 0x10) -#define AFIO_EXTICR4 (AFIO_EVCR + 0x14) - -#define EXTI0 0 -#define EXTI1 1 -#define EXTI2 2 -#define EXTI3 3 -#define EXTI4 4 -#define EXTI5 5 -#define EXTI6 6 -#define EXTI7 7 -#define EXTI8 8 -#define EXTI9 9 -#define EXTI10 10 -#define EXTI11 11 -#define EXTI12 12 -#define EXTI13 13 -#define EXTI14 14 -#define EXTI15 15 - -#define EXTI_CONFIG_PORTA 0 // Maple, Maple Native, Maple Mini -#define EXTI_CONFIG_PORTB 1 // Maple, Maple Native, Maple Mini -#define EXTI_CONFIG_PORTC 2 // Maple, Maple Native, Maple Mini -#define EXTI_CONFIG_PORTD 3 // Maple and Maple Native only -#define EXTI_CONFIG_PORTE 4 // Native only -#define EXTI_CONFIG_PORTF 5 // Native only -#define EXTI_CONFIG_PORTG 6 // Native only +#ifndef _EXTI_H_ +#define _EXTI_H_ #ifdef __cplusplus extern "C"{ #endif -void exti_attach_interrupt(uint32 port, uint32 pin, voidFuncPtr handler, - uint32 mode); -void exti_detach_interrupt(uint32 channel); +/** EXTI register map type */ +typedef struct exti_reg_map { + __io uint32 IMR; /**< Interrupt mask register */ + __io uint32 EMR; /**< Event mask register */ + __io uint32 RTSR; /**< Rising trigger selection register */ + __io uint32 FTSR; /**< Falling trigger selection register */ + __io uint32 SWIER; /**< Software interrupt event register */ + __io uint32 PR; /**< Pending register */ +} exti_reg_map; + +/** EXTI register map base pointer */ +#define EXTI_BASE ((exti_reg_map*)0x40010400) + +/** External interrupt trigger mode */ +typedef enum exti_trigger_mode { + EXTI_RISING, /**< Trigger on the rising edge */ + EXTI_FALLING, /**< Trigger on the falling edge */ + EXTI_RISING_FALLING /**< Trigger on both the rising and falling edges */ +} exti_trigger_mode; + +void exti_attach_interrupt(afio_exti_num num, + afio_exti_port port, + voidFuncPtr handler, + exti_trigger_mode mode); +void exti_detach_interrupt(afio_exti_num num); #ifdef __cplusplus } // extern "C" #endif - #endif - diff --git a/libmaple/fsmc.c b/libmaple/fsmc.c index 49526f4..1561add 100644 --- a/libmaple/fsmc.c +++ b/libmaple/fsmc.c @@ -31,6 +31,8 @@ #include "gpio.h" #include "fsmc.h" +#ifdef STM32_HIGH_DENSITY + /* These values determined for a particular SRAM chip by following the * calculations in the ST FSMC application note. */ #define FSMC_ADDSET 0x0 @@ -45,55 +47,55 @@ void fsmc_native_sram_init(void) { /* First we setup all the GPIO pins. */ /* Data lines... */ - gpio_set_mode(GPIOD_BASE, 0, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOD_BASE, 1, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOD_BASE, 8, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOD_BASE, 9, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOD_BASE, 10, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOD_BASE, 14, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOD_BASE, 15, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOE_BASE, 7, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOE_BASE, 8, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOE_BASE, 9, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOE_BASE, 10, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOE_BASE, 11, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOE_BASE, 12, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOE_BASE, 13, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOE_BASE, 14, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOE_BASE, 15, MODE_AF_OUTPUT_PP); + gpio_set_mode(GPIOD, 0, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOD, 1, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOD, 8, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOD, 9, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOD, 10, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOD, 14, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOD, 15, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOE, 7, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOE, 8, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOE, 9, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOE, 10, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOE, 11, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOE, 12, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOE, 13, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOE, 14, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOE, 15, GPIO_AF_OUTPUT_PP); /* Address lines... */ - gpio_set_mode(GPIOD_BASE, 11, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOD_BASE, 12, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOD_BASE, 13, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOF_BASE, 0, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOF_BASE, 1, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOF_BASE, 2, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOF_BASE, 3, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOF_BASE, 4, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOF_BASE, 5, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOF_BASE, 12, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOF_BASE, 13, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOF_BASE, 14, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOF_BASE, 15, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOG_BASE, 0, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOG_BASE, 1, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOG_BASE, 2, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOG_BASE, 3, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOG_BASE, 4, MODE_AF_OUTPUT_PP); - gpio_set_mode(GPIOG_BASE, 5, MODE_AF_OUTPUT_PP); + gpio_set_mode(GPIOD, 11, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOD, 12, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOD, 13, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOF, 0, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOF, 1, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOF, 2, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOF, 3, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOF, 4, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOF, 5, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOF, 12, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOF, 13, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOF, 14, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOF, 15, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOG, 0, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOG, 1, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOG, 2, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOG, 3, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOG, 4, GPIO_AF_OUTPUT_PP); + gpio_set_mode(GPIOG, 5, GPIO_AF_OUTPUT_PP); /* And control lines... */ - gpio_set_mode(GPIOD_BASE, 4, MODE_AF_OUTPUT_PP); // NOE - gpio_set_mode(GPIOD_BASE, 5, MODE_AF_OUTPUT_PP); // NWE + gpio_set_mode(GPIOD, 4, GPIO_AF_OUTPUT_PP); // NOE + gpio_set_mode(GPIOD, 5, GPIO_AF_OUTPUT_PP); // NWE - gpio_set_mode(GPIOD_BASE, 7, MODE_AF_OUTPUT_PP); // NE1 - gpio_set_mode(GPIOG_BASE, 9, MODE_AF_OUTPUT_PP); // NE2 - gpio_set_mode(GPIOG_BASE, 10, MODE_AF_OUTPUT_PP); // NE3 - gpio_set_mode(GPIOG_BASE, 12, MODE_AF_OUTPUT_PP); // NE4 + gpio_set_mode(GPIOD, 7, GPIO_AF_OUTPUT_PP); // NE1 + gpio_set_mode(GPIOG, 9, GPIO_AF_OUTPUT_PP); // NE2 + gpio_set_mode(GPIOG, 10, GPIO_AF_OUTPUT_PP); // NE3 + gpio_set_mode(GPIOG, 12, GPIO_AF_OUTPUT_PP); // NE4 - gpio_set_mode(GPIOE_BASE, 0, MODE_AF_OUTPUT_PP); // NBL0 - gpio_set_mode(GPIOE_BASE, 1, MODE_AF_OUTPUT_PP); // NBL1 + gpio_set_mode(GPIOE, 0, GPIO_AF_OUTPUT_PP); // NBL0 + gpio_set_mode(GPIOE, 1, GPIO_AF_OUTPUT_PP); // NBL1 /* Next enable the clock */ rcc_clk_enable(RCC_FSMC); @@ -132,3 +134,4 @@ void fsmc_native_sram_init(void) { /* (FSMC_BWTR3 not used for this simple configuration.) */ } +#endif /* STM32_HIGH_DENSITY */ diff --git a/libmaple/fsmc.h b/libmaple/fsmc.h index e83b529..fed6894 100644 --- a/libmaple/fsmc.h +++ b/libmaple/fsmc.h @@ -37,6 +37,8 @@ extern "C"{ #endif +#ifdef STM32_HIGH_DENSITY + // There are 4 FSMC chip-select devices; here are the SRAM-specific registers // for each @@ -82,9 +84,10 @@ typedef struct { void fsmc_native_sram_init(void); +#endif /* STM32_HIGH_DENSITY */ + #ifdef __cplusplus } // extern "C" #endif - #endif diff --git a/libmaple/gpio.c b/libmaple/gpio.c index 71e5230..b08be12 100644 --- a/libmaple/gpio.c +++ b/libmaple/gpio.c @@ -26,44 +26,151 @@ * @brief GPIO initialization routine */ -#include "libmaple.h" -#include "rcc.h" #include "gpio.h" +#include "rcc.h" + +/* + * GPIO devices + */ + +static gpio_dev gpioa = { + .regs = GPIOA_BASE, + .clk_id = RCC_GPIOA +}; +/** GPIO port A device. */ +gpio_dev *GPIOA = &gpioa; + +static gpio_dev gpiob = { + .regs = GPIOB_BASE, + .clk_id = RCC_GPIOB +}; +/** GPIO port B device. */ +gpio_dev *GPIOB = &gpiob; + +static gpio_dev gpioc = { + .regs = GPIOC_BASE, + .clk_id = RCC_GPIOC +}; +/** GPIO port C device. */ +gpio_dev *GPIOC = &gpioc; + +static gpio_dev gpiod = { + .regs = GPIOD_BASE, + .clk_id = RCC_GPIOD +}; +/** GPIO port D device. */ +gpio_dev *GPIOD = &gpiod; + +#ifdef STM32_HIGH_ +static gpio_dev gpioe = { + .regs = GPIOE_BASE, + .clk_id = RCC_GPIOE +}; +/** GPIO port E device. */ +gpio_dev *GPIOE = &gpioe; + +static gpio_dev gpiof = { + .regs = GPIOF_BASE, + .clk_id = RCC_GPIOF +}; +/** GPIO port F device. */ +gpio_dev *GPIOF = &gpiof; -void gpio_init(void) { - rcc_clk_enable(RCC_GPIOA); - rcc_clk_enable(RCC_GPIOB); - rcc_clk_enable(RCC_GPIOC); -#if NR_GPIO_PORTS >= 4 /* Maple, but not Maple Mini */ - rcc_clk_enable(RCC_GPIOD); -#elif NR_GPIO_PORTS >= 7 /* Maple Native (high density only) */ - rcc_clk_enable(RCC_GPIOE); - rcc_clk_enable(RCC_GPIOF); - rcc_clk_enable(RCC_GPIOG); +static gpio_dev gpiog = { + .regs = GPIOG_BASE, + .clk_id = RCC_GPIOG +}; +/** GPIO port G device. */ +gpio_dev *GPIOG = &gpiog; #endif - rcc_clk_enable(RCC_AFIO); + +/* + * GPIO convenience routines + */ + +/** + * Initialize a GPIO device. + * + * Enables the clock for and resets the given device. + * + * @param dev GPIO device to initialize. + */ +void gpio_init(gpio_dev *dev) { + rcc_clk_enable(dev->clk_id); + rcc_reset_dev(dev->clk_id); } -void gpio_set_mode(GPIO_Port* port, uint8 gpio_pin, GPIOPinMode mode) { - uint32 tmp; - uint32 shift = POS(gpio_pin % 8); - GPIOReg CR; +/** + * Initialize and reset all available GPIO devices. + */ +void gpio_init_all(void) { + gpio_init(GPIOA); + gpio_init(GPIOB); + gpio_init(GPIOC); + gpio_init(GPIOD); +#ifdef STM32_HIGH_DENSITY + gpio_init(GPIOE); + gpio_init(GPIOF); + gpio_init(GPIOG); +#endif +} - ASSERT(port); - ASSERT(gpio_pin < 16); +/** + * Set the mode of a GPIO pin. + * + * @param dev GPIO device. + * @param pin Pin on the device whose mode to set, 0--15. + * @param mode General purpose or alternate function mode to set the pin to. + * @see gpio_pin_mode + */ +void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode) { + gpio_reg_map *regs = dev->regs; + __io uint32 *cr = ®s->CRL + (pin >> 3); + uint32 shift = (pin & 0x7) * 4; + uint32 tmp = *cr; + + tmp &= ~(0xF << shift); + tmp |= (mode == GPIO_INPUT_PU ? GPIO_INPUT_PD : mode) << shift; + *cr = tmp; - if (mode == GPIO_MODE_INPUT_PU) { - port->ODR |= BIT(gpio_pin); - mode = CNF_INPUT_PD; - } else if (mode == GPIO_MODE_INPUT_PD) { - port->ODR &= ~BIT(gpio_pin); + if (mode == GPIO_INPUT_PD) { + regs->ODR &= ~BIT(pin); + } else if (mode == GPIO_INPUT_PU) { + regs->ODR |= BIT(pin); } +} + +/* + * AFIO + */ - CR = (gpio_pin < 8) ? &(port->CRL) : &(port->CRH); +/** + * Initialize the AFIO clock, and reset the AFIO registers. + */ +void afio_init(void) { + rcc_clk_enable(RCC_AFIO); + rcc_reset_dev(RCC_AFIO); +} - tmp = *CR; - tmp &= POS_MASK(shift); - tmp |= mode << shift; +#define AFIO_EXTI_SEL_MASK 0xF + +/** + * Select a source input for an external interrupt. + * + * @param exti External interrupt. One of: AFIO_EXTI_0, + * AFIO_EXTI_1, ..., AFIO_EXTI_15. + * @param gpio_port Port which contains pin to use as source input. + * One of: AFIO_EXTI_PA, AFIO_EXTI_PB, AFIO_EXTI_PC, + * AFIO_EXTI_PD, and, on high density devices, + * AFIO_EXTI_PE, AFIO_EXTI_PF, AFIO_EXTI_PG. + * @see exti_port + */ +void afio_exti_select(afio_exti_num exti, afio_exti_port gpio_port) { + __io uint32 *exti_cr = &AFIO_BASE->EXTICR1 + exti / 4; + uint32 shift = 4 * (exti % 4); + uint32 cr = *exti_cr; - *CR = tmp; + cr &= ~(AFIO_EXTI_SEL_MASK << shift); + cr |= gpio_port << shift; + *exti_cr = cr; } diff --git a/libmaple/gpio.h b/libmaple/gpio.h index 53f77c4..48dbc00 100644 --- a/libmaple/gpio.h +++ b/libmaple/gpio.h @@ -3,126 +3,331 @@ * * Copyright (c) 2010 Perry Hung. * - * 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 + * 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 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. + * 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 gpio.h * - * @brief GPIO prototypes, defines, and inlined access functions + * @brief General purpose I/0 (GPIO) and Alternate Function I/O + * (AFIO) prototypes, defines, and inlined access functions. */ -#ifndef _GPIO_H -#define _GPIO_H - -/* Each of the GPIO port bits can be in the following modes (STM32 138/995): - * Input floating - * Input pull-up - * Input pull-down - * Analog Input - * Output open-drain - * Output push-pull - * Alternate function push-pull - * Alternate function open-drain - * - * - After reset, the alternate functions are not active and IO prts - * are set to Input Floating mode, EXCEPT for the Serial Wire and JTAG - * ports, which are in alternate function mode by default. */ - -#define AFIO_MAPR ((volatile uint32*)0x40010004) - -#define GPIOA_BASE ((GPIO_Port*)0x40010800) -#define GPIOB_BASE ((GPIO_Port*)0x40010C00) -#define GPIOC_BASE ((GPIO_Port*)0x40011000) -#define GPIOD_BASE ((GPIO_Port*)0x40011400) -#define GPIOE_BASE ((GPIO_Port*)0x40011800) // High-density devices only -#define GPIOF_BASE ((GPIO_Port*)0x40011C00) // High-density devices only -#define GPIOG_BASE ((GPIO_Port*)0x40012000) // High-density devices only - -#define GPIO_SPEED_50MHZ (0x3) - -#define MODE_OUTPUT_PP ((0x00 << 2) | GPIO_SPEED_50MHZ) -#define MODE_OUTPUT_OD ((0x01 << 2) | GPIO_SPEED_50MHZ) -#define MODE_AF_OUTPUT_PP ((0x02 << 2) | GPIO_SPEED_50MHZ) -#define MODE_AF_OUTPUT_OD ((0x03 << 2) | GPIO_SPEED_50MHZ) - -#define CNF_INPUT_ANALOG (0x00 << 2) -#define CNF_INPUT_FLOATING (0x01 << 2) -#define CNF_INPUT_PD (0x02 << 2) -#define CNF_INPUT_PU (0x02 << 2) - -typedef enum GPIOPinMode { - GPIO_MODE_OUTPUT_PP = MODE_OUTPUT_PP, - GPIO_MODE_OUTPUT_OD = MODE_OUTPUT_OD, - GPIO_MODE_AF_OUTPUT_PP = MODE_AF_OUTPUT_PP, - GPIO_MODE_AF_OUTPUT_OD = MODE_AF_OUTPUT_OD, - GPIO_MODE_INPUT_ANALOG = CNF_INPUT_ANALOG, - GPIO_MODE_INPUT_FLOATING = CNF_INPUT_FLOATING, - GPIO_MODE_INPUT_PD = CNF_INPUT_PD, - GPIO_MODE_INPUT_PU, -} GPIOPinMode; - -typedef struct { - volatile uint32 CRL; // Port configuration register low - volatile uint32 CRH; // Port configuration register high - volatile uint32 IDR; // Port input data register - volatile uint32 ODR; // Port output data register - volatile uint32 BSRR; // Port bit set/reset register - volatile uint32 BRR; // Port bit reset register - volatile uint32 LCKR; // Port configuration lock register -} GPIO_Port; - -typedef volatile uint32* GPIOReg; - -#define POS_MASK(shift) (~(0xF << shift)) -#define POS(val) (val << 2) +#ifndef _GPIO_H_ +#define _GPIO_H_ + +#include "libmaple.h" +#include "rcc.h" #ifdef __cplusplus extern "C"{ #endif -void gpio_init(void); -void gpio_set_mode(GPIO_Port* port, uint8 gpio_pin, GPIOPinMode mode); +/* + * GPIO register maps and devices + */ + +/** GPIO register map type */ +typedef struct gpio_reg_map { + __io uint32 CRL; ///< Port configuration register low + __io uint32 CRH; ///< Port configuration register high + __io uint32 IDR; ///< Port input data register + __io uint32 ODR; ///< Port output data register + __io uint32 BSRR; ///< Port bit set/reset register + __io uint32 BRR; ///< Port bit reset register + __io uint32 LCKR; ///< Port configuration lock register +} gpio_reg_map; + +/** GPIO device type */ +typedef struct gpio_dev { + gpio_reg_map *regs; ///< Register map + rcc_clk_id clk_id; ///< RCC clock information +} gpio_dev; + +/** GPIO port A device */ +extern gpio_dev *GPIOA; +/** GPIO port B device */ +extern gpio_dev *GPIOB; +/** GPIO port C device */ +extern gpio_dev *GPIOC; +/** GPIO port D device */ +extern gpio_dev *GPIOD; +#ifdef STM32_HIGH_DENSITY +/** GPIO port E device */ +extern gpio_dev *GPIOE; +/** GPIO port F device */ +extern gpio_dev *GPIOF; +/** GPIO port G device */ +extern gpio_dev *GPIOG; +#endif + +/** GPIO port A register map base pointer */ +#define GPIOA_BASE ((gpio_reg_map*)0x40010800) +/** GPIO port B register map base pointer */ +#define GPIOB_BASE ((gpio_reg_map*)0x40010C00) +/** GPIO port C register map base pointer */ +#define GPIOC_BASE ((gpio_reg_map*)0x40011000) +/** GPIO port D register map base pointer */ +#define GPIOD_BASE ((gpio_reg_map*)0x40011400) +#ifdef STM32_HIGH_DENSITY +/** GPIO port E register map base pointer */ +#define GPIOE_BASE ((gpio_reg_map*)0x40011800) +/** GPIO port F register map base pointer */ +#define GPIOF_BASE ((gpio_reg_map*)0x40011C00) +/** GPIO port G register map base pointer */ +#define GPIOG_BASE ((gpio_reg_map*)0x40012000) +#endif + +/* + * GPIO register bit definitions + */ + +/* Control registers, low and high */ +#define GPIO_CR_CNF_INPUT_ANALOG (0x0 << 2) +#define GPIO_CR_CNF_INPUT_FLOATING (0x1 << 2) +#define GPIO_CR_CNF_INPUT_PU_PD (0x2 << 2) +#define GPIO_CR_CNF_OUTPUT_PP (0x0 << 2) +#define GPIO_CR_CNF_OUTPUT_OD (0x1 << 2) +#define GPIO_CR_CNF_AF_OUTPUT_PP (0x2 << 2) +#define GPIO_CR_CNF_AF_OUTPUT_OD (0x3 << 2) +#define GPIO_CR_MODE_INPUT 0x0 +#define GPIO_CR_MODE_OUTPUT_10MHZ 0x1 +#define GPIO_CR_MODE_OUTPUT_2MHZ 0x2 +#define GPIO_CR_MODE_OUTPUT_50MHZ 0x3 + +/** GPIO Pin modes. These only allow for 50MHZ max output speeds; if + * you want slower, use direct register access. */ +typedef enum gpio_pin_mode { + GPIO_OUTPUT_PP = (GPIO_CR_CNF_OUTPUT_PP | + GPIO_CR_MODE_OUTPUT_50MHZ), /**< Output push-pull. */ + GPIO_OUTPUT_OD = (GPIO_CR_CNF_OUTPUT_OD | + GPIO_CR_MODE_OUTPUT_50MHZ), /**< Output open-drain. */ + GPIO_AF_OUTPUT_PP = (GPIO_CR_CNF_AF_OUTPUT_PP | + GPIO_CR_MODE_OUTPUT_50MHZ), /**< Alternate function + output push-pull. */ + GPIO_AF_OUTPUT_OD = (GPIO_CR_CNF_AF_OUTPUT_OD | + GPIO_CR_MODE_OUTPUT_50MHZ), /**< Alternate function + output open drain. */ + GPIO_INPUT_ANALOG = (GPIO_CR_CNF_INPUT_ANALOG | + GPIO_CR_MODE_INPUT), /**< Analog input. */ + GPIO_INPUT_FLOATING = (GPIO_CR_CNF_INPUT_FLOATING | + GPIO_CR_MODE_INPUT), /**< Input floating. */ + GPIO_INPUT_PD = (GPIO_CR_CNF_INPUT_PU_PD | + GPIO_CR_MODE_INPUT), /**< Input pull-down. */ + GPIO_INPUT_PU /**< Input pull-up. */ + /* GPIO_INPUT_PU treated as a special case, for ODR twiddling */ +} gpio_pin_mode; -static inline void gpio_write_bit(GPIO_Port *port, uint8 gpio_pin, uint8 val) { - if (val){ - port->BSRR = BIT(gpio_pin); +/* + * GPIO Convenience routines + */ + +void gpio_init(gpio_dev *dev); +void gpio_init_all(void); +void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode); + +/** + * Set or reset a GPIO pin. + * + * Pin must have previously been configured to output mode. + * + * @param dev GPIO device whose pin to set. + * @param pin Pin on to set or reset + * @param val If true, set the pin. If false, reset the pin. + */ +static inline void gpio_write_bit(gpio_dev *dev, uint8 pin, uint8 val) { + if (val) { + dev->regs->BSRR = BIT(pin); } else { - port->BRR = BIT(gpio_pin); + dev->regs->BRR = BIT(pin); } } -static inline uint32 gpio_read_bit(GPIO_Port *port, uint8 gpio_pin) { - return (port->IDR & BIT(gpio_pin) ? 1 : 0); +/** + * Determine whether or not a GPIO pin is set. + * + * Pin must have previously been configured to input mode. + * + * @param dev GPIO device whose pin to test. + * @param pin Pin on dev to test. + * @return True if the pin is set, false otherwise. + */ +static inline uint32 gpio_read_bit(gpio_dev *dev, uint8 pin) { + return dev->regs->IDR & BIT(pin); } -/* For pins configured as output push-pull, reading the ODR returns - * the last value written in push-pull mode. +/** + * Toggle a pin configured as output push-pull. + * @param dev GPIO device. + * @param pin Pin on dev to toggle. */ -static inline void gpio_toggle_pin(GPIO_Port *port, uint8 gpio_pin) { - port->ODR = port->ODR ^ BIT(gpio_pin); +static inline void gpio_toggle_bit(gpio_dev *dev, uint8 pin) { + dev->regs->ODR = dev->regs->ODR ^ BIT(pin); } -#ifdef __cplusplus -} // extern "C" +/* + * AFIO register map + */ + +/** AFIO register map */ +typedef struct afio_reg_map { + __io uint32 EVCR; /**< Event control register. */ + __io uint32 MAPR; /**< AF remap and debug I/O configuration + register. */ + __io uint32 EXTICR1; /**< External interrupt configuration + register 1. */ + __io uint32 EXTICR2; /**< External interrupt configuration + register 2. */ + __io uint32 EXTICR3; /**< External interrupt configuration + register 3. */ + __io uint32 EXTICR4; /**< External interrupt configuration + register 4. */ + __io uint32 MAPR2; /**< AF remap and debug I/O configuration + register 2. */ +} afio_reg_map; + +/** AFIO register map base pointer. */ +#define AFIO_BASE ((afio_reg_map *)0x40010000) + +/* + * AFIO register bit definitions + */ + +/* Event control register */ +#define AFIO_EVCR_EVOE (0x1 << 7) +#define AFIO_EVCR_PORT_PA (0x0 << 4) +#define AFIO_EVCR_PORT_PB (0x1 << 4) +#define AFIO_EVCR_PORT_PC (0x2 << 4) +#define AFIO_EVCR_PORT_PD (0x3 << 4) +#define AFIO_EVCR_PORT_PE (0x4 << 4) +#define AFIO_EVCR_PIN_0 0x0 +#define AFIO_EVCR_PIN_1 0x1 +#define AFIO_EVCR_PIN_2 0x2 +#define AFIO_EVCR_PIN_3 0x3 +#define AFIO_EVCR_PIN_4 0x4 +#define AFIO_EVCR_PIN_5 0x5 +#define AFIO_EVCR_PIN_6 0x6 +#define AFIO_EVCR_PIN_7 0x7 +#define AFIO_EVCR_PIN_8 0x8 +#define AFIO_EVCR_PIN_9 0x9 +#define AFIO_EVCR_PIN_10 0xA +#define AFIO_EVCR_PIN_11 0xB +#define AFIO_EVCR_PIN_12 0xC +#define AFIO_EVCR_PIN_13 0xD +#define AFIO_EVCR_PIN_14 0xE +#define AFIO_EVCR_PIN_15 0xF + +/* AF remap and debug I/O configuration register */ +#define AFIO_MAPR_SWJ_FULL_SWJ (0x0 << 24) +#define AFIO_MAPR_SWJ_FULL_SWJ_NO_NJRST (0x1 << 24) +#define AFIO_MAPR_SWJ_NO_JTAG_SW (0x2 << 24) +#define AFIO_MAPR_SWJ_NO_JTAG_NO_SW (0x4 << 24) +#define AFIO_MAPR_ADC2_ETRGREG_REMAP BIT(20) +#define AFIO_MAPR_ADC2_ETRGINJ_REMAP BIT(19) +#define AFIO_MAPR_ADC1_ETRGREG_REMAP BIT(18) +#define AFIO_MAPR_ADC1_ETRGINJ_REMAP BIT(17) +#define AFIO_MAPR_TIM5CH4_IREMAP BIT(16) +#define AFIO_MAPR_PD01_REMAP BIT(15) +#define AFIO_MAPR_CAN_REMAP (BIT(14) | BIT(13)) +#define AFIO_MAPR_TIM4_REMAP_FULL BIT(12) +#define AFIO_MAPR_TIM3_REMAP (BIT(11) | BIT(10)) +#define AFIO_MAPR_TIM2_REMAP (BIT(9) | BIT(8)) +#define AFIO_MAPR_TIM1_REMAP (BIT(7) | BIT(6)) +#define AFIO_MAPR_USART3_REMAP (BIT(5) | BIT(4)) +#define AFIO_MAPR_USART2_REMAP BIT(3) +#define AFIO_MAPR_USART1_REMAP BIT(2) +#define AFIO_MAPR_I2C1_REMAP BIT(1) +#define AFIO_MAPR_SPI1_REMAP BIT(0) + +/* External interrupt configuration registers */ + +/** + * External interrupt line port selector. Used to determine which + * GPIO port to map an external interrupt line onto. */ +typedef enum { + AFIO_EXTI_PA, /**< Use PAx pin. */ + AFIO_EXTI_PB, /**< Use PBx pin. */ + AFIO_EXTI_PC, /**< Use PCx pin. */ + AFIO_EXTI_PD, /**< Use PDx pin. */ +#ifdef STM32_HIGH_DENSITY + AFIO_EXTI_PE, /**< Use PEx pin. */ + AFIO_EXTI_PF, /**< Use PFx pin. */ + AFIO_EXTI_PG, /**< Use PGx pin. */ #endif +} afio_exti_port; + +/** + * External interrupt line numbers. + */ +typedef enum { + AFIO_EXTI_0, /**< External interrupt line 0. */ + AFIO_EXTI_1, /**< External interrupt line 1. */ + AFIO_EXTI_2, /**< External interrupt line 2. */ + AFIO_EXTI_3, /**< External interrupt line 3. */ + AFIO_EXTI_4, /**< External interrupt line 4. */ + AFIO_EXTI_5, /**< External interrupt line 5. */ + AFIO_EXTI_6, /**< External interrupt line 6. */ + AFIO_EXTI_7, /**< External interrupt line 7. */ + AFIO_EXTI_8, /**< External interrupt line 8. */ + AFIO_EXTI_9, /**< External interrupt line 9. */ + AFIO_EXTI_10, /**< External interrupt line 10. */ + AFIO_EXTI_11, /**< External interrupt line 11. */ + AFIO_EXTI_12, /**< External interrupt line 12. */ + AFIO_EXTI_13, /**< External interrupt line 13. */ + AFIO_EXTI_14, /**< External interrupt line 14. */ + AFIO_EXTI_15, /**< External interrupt line 15. */ +} afio_exti_num; +/* AF remap and debug I/O configuration register 2 */ +#define AFIO_MAPR2_FSMC_NADV BIT(10) +#define AFIO_MAPR2_TIM14_REMAP BIT(9) +#define AFIO_MAPR2_TIM13_REMAP BIT(8) +#define AFIO_MAPR2_TIM11_REMAP BIT(7) +#define AFIO_MAPR2_TIM10_REMAP BIT(6) +#define AFIO_MAPR2_TIM9_REMAP BIT(5) + +/* + * AFIO convenience routines + */ + +void afio_init(void); +void afio_exti_select(afio_exti_num exti, afio_exti_port gpio_port); + +/** + * Set the SWJ_CONFIG bits in the AFIO MAPR register. + * + * @param config Desired SWJ_CONFIG bits setting. One of: + * AFIO_MAPR_SWJ_FULL_SWJ (full SWJ), + * AFIO_MAPR_SWJ_FULL_SWJ_NO_NJRST (full SWJ, no NJTRST), + * AFIO_MAPR_SWJ_NO_JTAG_SW (JTAG-DP disabled, SW-DP enabled), + * AFIO_MAPR_SWJ_NO_JTAG_NO_SW (JTAG-DP and SW-DP both disabled). + */ +static inline void afio_mapr_swj_config(uint32 config) { + __io uint32 *mapr = &AFIO_BASE->MAPR; + *mapr = (*mapr & ~(0x7 << 24)) | config; +} + +#ifdef __cplusplus +} +#endif #endif diff --git a/libmaple/libmaple.h b/libmaple/libmaple.h index 6b75c96..0bbd34e 100644 --- a/libmaple/libmaple.h +++ b/libmaple/libmaple.h @@ -36,7 +36,7 @@ /* * Where to put usercode, based on space reserved for bootloader. * - * FIXME this has no business being here + * FIXME this has no business being here */ #define USER_ADDR_ROM 0x08005000 #define USER_ADDR_RAM 0x20000C00 diff --git a/libmaple/libmaple_types.h b/libmaple/libmaple_types.h index a976a9e..54bef65 100644 --- a/libmaple/libmaple_types.h +++ b/libmaple/libmaple_types.h @@ -44,6 +44,7 @@ typedef long long int64; typedef void (*voidFuncPtr)(void); #define __io volatile +#define __attr_flash __attribute__((section (".USER_FLASH"))) #ifndef NULL #define NULL 0 diff --git a/libmaple/pwr.h b/libmaple/pwr.h index 5ff815d..5f68c34 100644 --- a/libmaple/pwr.h +++ b/libmaple/pwr.h @@ -41,20 +41,19 @@ typedef struct pwr_reg_map { __io uint32 CSR; /**< Control and status register */ } pwr_reg_map; -/* - * Power peripheral base. - */ +/** Power peripheral register map base pointer. */ #define PWR_BASE ((pwr_reg_map*)0x40007000) -/** Power interface device. */ +/** Power device type. */ typedef struct pwr_dev { - pwr_reg_map *regs; + pwr_reg_map *regs; /**< Register map */ } pwr_dev; /** * Power device. */ extern const pwr_dev *PWR; + /* * Register bit definitions */ diff --git a/libmaple/rcc.h b/libmaple/rcc.h index 410ab8b..8697e01 100644 --- a/libmaple/rcc.h +++ b/libmaple/rcc.h @@ -27,6 +27,8 @@ * @brief reset and clock control definitions and prototypes */ +#include "libmaple_types.h" + #ifndef _RCC_H_ #define _RCC_H_ @@ -182,7 +184,6 @@ typedef enum { RCC_BKP, } rcc_clk_id; - void rcc_clk_init(uint32 sysclk_src, uint32 pll_src, uint32 pll_mul); void rcc_clk_enable(rcc_clk_id device); void rcc_reset_dev(rcc_clk_id device); diff --git a/libmaple/ring_buffer.h b/libmaple/ring_buffer.h index a44088e..f7baa6c 100644 --- a/libmaple/ring_buffer.h +++ b/libmaple/ring_buffer.h @@ -13,21 +13,20 @@ extern "C"{ #endif -/* The buffer is empty when head == tail. +/** + * Ring buffer type. + * + * The buffer is empty when head == tail. * * 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 { - /** 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; + volatile uint8 *buf; /**< Buffer items are stored into */ + uint16 head; /**< Index of the next item to remove */ + uint16 tail; /**< Index where the next item will get inserted */ + uint16 size; /**< Buffer capacity minus one */ } ring_buffer; /** diff --git a/libmaple/spi.c b/libmaple/spi.c index 8bba0d6..7bdc18a 100644 --- a/libmaple/spi.c +++ b/libmaple/spi.c @@ -43,23 +43,23 @@ typedef struct spi_dev { SPI *base; - GPIO_Port *port; + gpio_dev *gpio_d; uint8 sck_pin; uint8 miso_pin; uint8 mosi_pin; } spi_dev; -static const spi_dev spi_dev1 = { +spi_dev spi_dev1 = { .base = (SPI*)SPI1_BASE, - .port = GPIOA_BASE, + .gpio_d = NULL, .sck_pin = 5, .miso_pin = 6, .mosi_pin = 7 }; -static const spi_dev spi_dev2 = { +spi_dev spi_dev2 = { .base = (SPI*)SPI2_BASE, - .port = GPIOB_BASE, + .gpio_d = NULL, .sck_pin = 13, .miso_pin = 14, .mosi_pin = 15 @@ -90,11 +90,13 @@ void spi_init(uint32 spi_num, ASSERT(prescale != CR1_BR_PRESCALE_2); spi = (SPI*)SPI1_BASE; rcc_clk_enable(RCC_SPI1); + spi_dev1.gpio_d = GPIOA; spi_gpio_cfg(&spi_dev1); break; case 2: spi = (SPI*)SPI2_BASE; rcc_clk_enable(RCC_SPI2); + spi_dev1.gpio_d = GPIOB, spi_gpio_cfg(&spi_dev2); break; } @@ -155,7 +157,7 @@ uint8 spi_tx(uint32 spi_num, uint8 *buf, uint32 len) { } static void spi_gpio_cfg(const spi_dev *dev) { - gpio_set_mode(dev->port, dev->sck_pin, GPIO_MODE_AF_OUTPUT_PP); - gpio_set_mode(dev->port, dev->miso_pin, GPIO_MODE_AF_OUTPUT_PP); - gpio_set_mode(dev->port, dev->mosi_pin, GPIO_MODE_AF_OUTPUT_PP); + gpio_set_mode(dev->gpio_d, dev->sck_pin, GPIO_AF_OUTPUT_PP); + gpio_set_mode(dev->gpio_d, dev->miso_pin, GPIO_AF_OUTPUT_PP); + gpio_set_mode(dev->gpio_d, dev->mosi_pin, GPIO_AF_OUTPUT_PP); } diff --git a/libmaple/usb/usb.c b/libmaple/usb/usb.c index 62f56fc..2fc4eb2 100644 --- a/libmaple/usb/usb.c +++ b/libmaple/usb/usb.c @@ -44,7 +44,7 @@ volatile uint32 bDeviceState = UNCONNECTED; volatile uint16 wIstr = 0; -volatile bIntPackSOF = 0; +volatile uint32 bIntPackSOF = 0; DEVICE Device_Table = {NUM_ENDPTS, @@ -99,15 +99,13 @@ struct { } ResumeS; void setupUSB (void) { - gpio_set_mode(USB_DISC_BANK, - USB_DISC_PIN, - GPIO_MODE_OUTPUT_PP); + gpio_set_mode(USB_DISC_DEV, USB_DISC_PIN, GPIO_OUTPUT_PP); /* setup the apb1 clock for USB */ pRCC->APB1ENR |= 0x00800000; /* initialize the usb application */ - gpio_write_bit(USB_DISC_BANK, USB_DISC_PIN, 0); // presents us to the host + gpio_write_bit(USB_DISC_DEV, USB_DISC_PIN, 0); // presents us to the host USB_Init(); // low level init routine provided by the ST library } @@ -115,7 +113,7 @@ void disableUSB (void) { // These are just guesses about how to do this // TODO: real disable function usbDsbISR(); - gpio_write_bit(USB_DISC_BANK,USB_DISC_PIN,1); + gpio_write_bit(USB_DISC_DEV, USB_DISC_PIN, 1); } void usbSuspend(void) { @@ -320,8 +318,29 @@ if (wIstr & ISTR_CTR & wInterrupt_Mask) { } +static void FIXME_delayMicroseconds_copy(uint32 us) { + /* So (2^32)/12 micros max, or less than 6 minutes */ + us *= 12; + + /* fudge for function call overhead */ + us--; + asm volatile(" mov r0, %[us] \n\t" + "1: subs r0, #1 \n\t" + " bhi 1b \n\t" + : + : [us] "r" (us) + : "r0"); +} + +static void FIXME_delay_copy(unsigned long ms) { + uint32 i; + for (i = 0; i < ms; i++) { + FIXME_delayMicroseconds_copy(1000); + } +} + void usbWaitReset(void) { - delay(RESET_DELAY); + FIXME_delay_copy(RESET_DELAY); systemHardReset(); } diff --git a/libmaple/usb/usb_callbacks.c b/libmaple/usb/usb_callbacks.c index ccb0fdd..8184537 100644 --- a/libmaple/usb/usb_callbacks.c +++ b/libmaple/usb/usb_callbacks.c @@ -129,7 +129,7 @@ u8* vcomGetSetLineCoding(uint16 length) { return (uint8*)&line_coding; } -vcomSetLineState(void) { +void vcomSetLineState(void) { } void usbInit(void) { diff --git a/libmaple/usb/usb_config.h b/libmaple/usb/usb_config.h index 394c580..9003da9 100644 --- a/libmaple/usb/usb_config.h +++ b/libmaple/usb/usb_config.h @@ -4,6 +4,7 @@ #define __USB_CONFIG_H #include "usb_lib.h" +#include "gpio.h" /****************************************************************************** ****************************************************************************** @@ -31,19 +32,19 @@ /* USB Identifier numbers */ #define VCOM_ID_PRODUCT 0x0004 - #define USB_DISC_BANK GPIOC_BASE + #define USB_DISC_DEV GPIOC #define USB_DISC_PIN 12 #elif defined(BOARD_maple_mini) #define VCOM_ID_PRODUCT 0x0005 - #define USB_DISC_BANK GPIOB_BASE + #define USB_DISC_DEV GPIOB #define USB_DISC_PIN 9 #elif defined(BOARD_maple_native) #define VCOM_ID_PRODUCT 0x0006 - #define USB_DISC_BANK GPIOB_BASE + #define USB_DISC_DEV GPIOB #define USB_DISC_PIN 8 #else diff --git a/libmaple/usb/usb_hardware.c b/libmaple/usb/usb_hardware.c index 505dcf1..9a7d12c 100644 --- a/libmaple/usb/usb_hardware.c +++ b/libmaple/usb/usb_hardware.c @@ -33,47 +33,6 @@ #include "usb_hardware.h" -void setPin(u32 bank, u8 pin) { - u32 pinMask = 0x1 << (pin); - SET_REG(GPIO_BSRR(bank),pinMask); -} - -void resetPin(u32 bank, u8 pin) { - u32 pinMask = 0x1 << (16+pin); - SET_REG(GPIO_BSRR(bank),pinMask); -} - -void systemReset(void) { - SET_REG(RCC_CR, GET_REG(RCC_CR) | 0x00000001); - SET_REG(RCC_CFGR, GET_REG(RCC_CFGR) & 0xF8FF0000); - SET_REG(RCC_CR, GET_REG(RCC_CR) & 0xFEF6FFFF); - SET_REG(RCC_CR, GET_REG(RCC_CR) & 0xFFFBFFFF); - SET_REG(RCC_CFGR, GET_REG(RCC_CFGR) & 0xFF80FFFF); - - SET_REG(RCC_CIR, 0x00000000); // disable all RCC interrupts -} - -void setupCLK (void) { - /* enable HSE */ - SET_REG(RCC_CR,GET_REG(RCC_CR) | 0x00010001); - /* for it to come on */ - while ((GET_REG(RCC_CR) & 0x00020000) == 0); - - /* Configure PLL */ - /* pll=72Mhz,APB1=36Mhz,AHB=72Mhz */ - SET_REG(RCC_CFGR,GET_REG(RCC_CFGR) | 0x001D0400); - /* enable the pll */ - SET_REG(RCC_CR,GET_REG(RCC_CR) | 0x01000000); - /* wait for it to come on */ - while ((GET_REG(RCC_CR) & 0x03000000) == 0); - - /* Set SYSCLK as PLL */ - SET_REG(RCC_CFGR,GET_REG(RCC_CFGR) | 0x00000002); - /* wait for it to come on */ - while ((GET_REG(RCC_CFGR) & 0x00000008) == 0); -} - - void nvicInit(NVIC_InitTypeDef* NVIC_InitStruct) { u32 tmppriority = 0x00; u32 tmpreg = 0x00; diff --git a/libmaple/usb/usb_hardware.h b/libmaple/usb/usb_hardware.h index e4a26b4..cfead1a 100644 --- a/libmaple/usb/usb_hardware.h +++ b/libmaple/usb/usb_hardware.h @@ -22,34 +22,20 @@ * THE SOFTWARE. * ****************************************************************************/ -#ifndef __HARDWARE_H -#define __HARDWARE_H - +#include "rcc.h" #include "usb_type.h" +#ifndef _USB_HARDWARE_H_ +#define _USB_HARDWARE_H_ + /* macro'd register and peripheral definitions */ #define EXC_RETURN 0xFFFFFFF9 #define DEFAULT_CPSR 0x61000000 -#define RCC ((u32)0x40021000) #define FLASH ((u32)0x40022000) -#define GPIOA ((u32)0x40010800) -#define GPIOC ((u32)0x40011000) #define USB_PACKET_BUFFER ((u32)0x40006000) -#define RCC_CR RCC -#define RCC_CFGR RCC + 0x04 -#define RCC_CIR RCC + 0x08 -#define RCC_AHBENR RCC + 0x14 -#define RCC_APB2ENR RCC + 0x18 -#define RCC_APB1ENR RCC + 0x16 - -#define GPIO_CRL(port) port -#define GPIO_CRH(port) port+0x04 -#define GPIO_ODR(port) port+0x0c -#define GPIO_BSRR(port) port+0x10 - #define SCS_BASE ((u32)0xE000E000) #define NVIC_BASE (SCS_BASE + 0x0100) #define SCB_BASE (SCS_BASE + 0x0D00) @@ -74,9 +60,8 @@ #define __PSC(__TIMCLK, __PERIOD) (((__VAL(__TIMCLK, __PERIOD)+49999UL)/50000UL) - 1) #define __ARR(__TIMCLK, __PERIOD) ((__VAL(__TIMCLK, __PERIOD)/(__PSC(__TIMCLK, __PERIOD)+1)) - 1) -/* todo, wrap in do whiles for the natural ; */ -#define SET_REG(addr,val) *(vu32*)(addr)=val -#define GET_REG(addr) *(vu32*)(addr) +#define SET_REG(addr,val) do { *(vu32*)(addr)=val; } while (0) +#define GET_REG(addr) do { *(vu32*)(addr); } while (0) #if defined(__cplusplus) extern "C" { @@ -85,7 +70,7 @@ extern "C" { /* todo: there must be some major misunderstanding in how we access regs. The direct access approach (GET_REG) causes the usb init to fail upon trying to activate RCC_APB1 |= 0x00800000. However, using the struct approach from ST, it works fine...temporarily switching to that approach */ -typedef struct +typedef struct { vu32 CR; vu32 CFGR; @@ -98,7 +83,7 @@ typedef struct vu32 BDCR; vu32 CSR; } RCC_RegStruct; -#define pRCC ((RCC_RegStruct *) RCC) +#define pRCC ((RCC_RegStruct *) RCC_BASE) typedef struct { vu32 ISER[2]; @@ -139,12 +124,7 @@ typedef struct { } SCB_TypeDef; -void setPin (u32 bank, u8 pin); -void resetPin (u32 bank, u8 pin); - void systemHardReset(void); -void systemReset (void); -void setupCLK (void); void nvicInit (NVIC_InitTypeDef*); void nvicDisableInterrupts(void); diff --git a/libmaple/util.c b/libmaple/util.c index 3408a2e..09fbecd 100644 --- a/libmaple/util.c +++ b/libmaple/util.c @@ -38,7 +38,7 @@ #ifndef ERROR_USART_NUM #define ERROR_USART_NUM USART2 #define ERROR_USART_BAUD 9600 -#define ERROR_TX_PORT GPIOA_BASE +#define ERROR_TX_PORT GPIOA #define ERROR_TX_PIN 2 #endif @@ -87,7 +87,7 @@ void __error(void) { */ void _fail(const char* file, int line, const char* exp) { /* Initialize the error usart */ - gpio_set_mode(ERROR_TX_PORT, ERROR_TX_PIN, GPIO_MODE_AF_OUTPUT_PP); + gpio_set_mode(ERROR_TX_PORT, ERROR_TX_PIN, GPIO_AF_OUTPUT_PP); usart_init(ERROR_USART_NUM, ERROR_USART_BAUD); /* Print failed assert message */ @@ -116,7 +116,7 @@ void throb(void) { uint32 TOP_CNT = 0x0200; uint32 i = 0; - gpio_set_mode(ERROR_LED_PORT, ERROR_LED_PIN, GPIO_MODE_OUTPUT_PP); + gpio_set_mode(ERROR_LED_PORT, ERROR_LED_PIN, GPIO_OUTPUT_PP); /* Error fade */ while (1) { if (CC == TOP_CNT) { diff --git a/libmaple/util.h b/libmaple/util.h index fb524c2..25dd56e 100644 --- a/libmaple/util.h +++ b/libmaple/util.h @@ -28,6 +28,8 @@ * @brief Various macros and utility procedures. */ +#include "libmaple_types.h" + /* Generally "useful" utility procedures */ #ifndef _UTIL_H_ #define _UTIL_H_ @@ -51,40 +53,29 @@ extern "C"{ /* Return bits m to n of x */ #define GET_BITS(x, m, n) ((((uint32)x) << (31 - (n))) >> ((31 - (n)) + (m))) -/* Bit-banding macros */ -/* Bitbanded Memory sections */ -#define BITBAND_SRAM_REF 0x20000000 -#define BITBAND_SRAM_BASE 0x22000000 -#define BITBAND_PERI_REF 0x40000000 -#define BITBAND_PERI_BASE 0x42000000 -/* Convert SRAM address */ -#define BITBAND_SRAM(a,b) ((BITBAND_SRAM_BASE+(a-BITBAND_SRAM_REF)*32+(b*4))) -/* Convert peripheral address */ -#define BITBAND_PERI(a, b) ((BITBAND_PERI_BASE + \ - ((uint32)a - BITBAND_PERI_REF) * 32 + (b * 4))) - -#define REG_SET(reg, val) (*(volatile uint32*)(reg) = (val)) -#define REG_SET_BIT(reg, bit) (*(volatile uint32*)(reg) |= BIT(bit)) -#define REG_CLEAR_BIT(reg, bit) (*(volatile uint32*)(reg) &= ~BIT(bit)) -#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)) +/* + * Register reads and writes + */ #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 IS_POWER_OF_TWO(v) (v && !(v & (v - 1))) + +/* + * Failure routines + */ + void __error(void); void _fail(const char*, int, const char*); void throb(void); -/* Asserts for sanity checks, redefine DEBUG_LEVEL in libmaple.h to - * compile out these checks */ +/* + * Asserts and debug levels + */ #if DEBUG_LEVEL >= DEBUG_ALL #define ASSERT(exp) \ diff --git a/notes/coding_standard.txt b/notes/coding_standard.txt index 5cb96c3..372ebf4 100644 --- a/notes/coding_standard.txt +++ b/notes/coding_standard.txt @@ -25,12 +25,11 @@ License ------- - Put an MIT license at the beginning of the file (look at any of our - source files for an example). Copyright should go to either you or - LeafLabs LLC. + source files for an example). Copyright should go either to you or + to LeafLabs, LLC. Emacs: if you don't like seeing the license, you should use - elide-head (which will hide it for you). Here is some elisp you can - modify to make this pleasant: + elide-head (which will hide it for you). You can use the following: (require 'elide-head) (setq programming-mode-hooks '(c-mode-hook c++-mode-hook)) @@ -38,7 +37,7 @@ License '("The MIT License" . "DEALINGS IN\n [*] THE SOFTWARE")) (add-to-list 'elide-head-headers-to-hide '("The MIT License" . "DEALINGS IN THE\n...SOFTWARE")) - (dolist (hook mbolivar-programming-mode-hooks) + (dolist (hook programming-mode-hooks) (add-hook hook (lambda () (elide-head)))) Whitespace/Indentation @@ -46,7 +45,8 @@ Whitespace/Indentation - 4 space indents. [Set in .dir-locals.el] -- Unix newlines. +- Unix newlines. [Some exceptions are currently grandfathered in; + these will go away in time.] - No tab characters. [Set in .dir-locals.el] @@ -76,50 +76,53 @@ Whitespace/Indentation (add-hook 'c-mode-hook c-mode-inextern-lang-hook) - Comments -------- -- Multi-line comments look like this: +- Multi-line comments are pretty flexible. Any of these is fine: - /* text starts here - * continued lines have a '*' before them - * the comment can end after the last line + /* Comment starts here. + * Continued lines have a '*' before them. + * The comment can end after the last line. */ - or this: - - /* comment starts here - * the comment can end on the same line */ + /* Comment starts here. + * The comment can end on the same line. */ -- Doxygen comments are newline comments that begin with /** instead. - It is not required that the "/**" appear on a line by itself. + /* + * You can also place a newline after the opening "/*". + */ -- Single-line comments on the same line are // in c or c++. +- Doxygen comments are multi-line comments that begin with /** instead. -- Single-line comments on their own source line are /* */ in c, but - can also be // in c++. If you think that typing out /* */ is too - slow in emacs, use M-; (comment-dwim) when you're on an empty line, - and it'll ... well... +- Single-line comments on the same line are // in C or C++. - You should be using the (super awesome) comment-dwim; it pretty - much does exactly what you want to the comment on the current - line, including "create one and put it in the right place". +- Single-line comments on their own source line should be /* */ in C, + but can also be // in C++. In Emacs, you can use M-; + (comment-dwim), and it'll Do What You Mean. Braces ------ -- 1TBS. Nothing more need be said. +- Mostly 1TBS: http://en.wikipedia.org/wiki/Indent_style#Variant:_1TBS + The only difference is that the opening brace of a function's + definition occurs exactly one space character after the closing + parenthesis in that function's parameter list. Example: + + void func(void) { + ... + } + Naming conventions ------------------ -- There's always a fight about upper and lower case vs. underscores. - We'll handle this as follows. +There's always a fight about upper and lower case vs. underscores. +We'll handle this as follows. - First, Dammit_Dont_Mix_Like_This, because It_Looks_Really_Ugly, ok? +- First, Dammit_Dont_Mix_Like_This, because It_Looks_Really_Ugly, ok? [There's been some debate about this, and some exceptions are already grandfathered in, so in order to settle it, let's call this a "recommendation" instead of "requirement".] @@ -168,7 +171,7 @@ Naming conventions Documentation ------------- -- Document your code. This should go without saying. +- Document your code! - For complicated peripherals, it would be nice if you put longer-form comments into this directory (notes/), with a comment in the @@ -176,13 +179,8 @@ Documentation example. That lets us keep the source files relatively clean while still allowing new readers to have a starting point. -- At least put a doxygen comment with a nonempty @brief for every .h - file you add. See the existing ones for examples. For now, it'd be - better if you didn't put a @brief into any .c[pp] files, since it - (currently) interferes with our documentation generator in a way - that I won't explain here (though you can look into the LeafLabs or - michaeljones breathe repos on github and potentially figure out - why). +- At least put a Doxygen comment with a nonempty @brief for every .h + file you add. See the existing ones for examples. - Doxygen comments generally just belong on types, functions, etc. that are part of the public user-facing API. This generally @@ -196,8 +194,13 @@ Documentation This should be avoided if at all possible, since it creates a maintenance burden of documenting things in two places at once, and - provides an opportunity for bad documentation to slip in, when the - code comments fall out of sync with the ReST docs. + makes it easier for documentation to go stale. + +- For libmaple proper (the pure C library under libmaple/); the + convention is to document any user-facing entity at the point where + it is defined. In particular, this means you should document an + externally-linked function defined in a .c file in that .c file, not + in the header file where it is declared to the user. General Formatting ------------------ @@ -217,7 +220,3 @@ General Formatting (require 'lineker) (dolist (hook '(c-mode-hook c++-mode-hook)) (add-hook hook (lambda () (lineker-mode 1)))) - - There are only a few exceptional situations. The most important one - is when specifying a lookup table like PIN_MAP where it'd be ugly to - split each entry over multiple lines. diff --git a/notes/exti.txt b/notes/exti.txt new file mode 100644 index 0000000..1ad49ee --- /dev/null +++ b/notes/exti.txt @@ -0,0 +1,67 @@ +External interrupt notes. + +To generate the interrupt, the interrupt line should be configured +and enabled. This is done by programming the two trigger registers +with the desired edge detection and by enabling the interrupt +request by writing a '1' to the corresponding bit in the interrupt +mask register. When the selected edge occurs on the external +interrupt line, an interrupt request is generated. The pending bit +corresponding to the interrupt line is also set. This request is +reset by writing a '1' in the pending register. + +Hardware interrupt selection: + +To configure the 20 lines as interrupt sources, use the following +procedure: + +1) Configure AFIO_EXTICR[y] to select the source input for EXTIx + external interrupt +2) Configure the mask bits of the 20 interrupt lines (EXTI_IMR) +3) Configure the trigger selection bits of the interrupt lines + (EXTI_RTSR and EXTI_FTSR) +4) Configure the enable and mask bits that control the NVIC_IRQ + channel mapped to the External Interrupt Controller (EXTI) so + that an inerrupt coming from one of the 20 lines can be + correctly acknowledged. + +AFIO clock must be on. + +RM0008, page 107: "PD0, PD1 cannot be used for external +interrupt/event generation on 36, 48, 64-bin packages." + +---------------------------------------------------------------------------- +Pin to EXTI Line Mappings: +EXTI0 EXTI1 EXTI2 EXTI3 EXTI4 +-------------------------------------------------------------------------- +D2/PA0 D3/PA1 D1/PA2 D0/A6/PA3 D10/A10/PA4 +D26/EXT7/PB0 D27/EXT8/PB1 D16/A2/PC2 D17/A3/PC3 D18/A4/PC4 +D14/A0/PC0 D15/PC1 D25/EXT5/PD2 + +EXTI5 EXTI6 EXTI7 EXTI8 EXTI9 +---------------------------------------------------------------------------- +D13/A13/PA5 D12/A12/PA6 D11/A11/PA7 D6/PA8 D7/PA9 +D4/PB5 D5/PB6 D9/PB7 D38/PB8 D23/EXT4/PB9 +D19/A5/PC5 D34/EXTI15/PC6 D35/EXT16/PC7 D36/PC8 D37/EXT18/PC9 + +EXTI10 EXTI11 EXTI12 EXTI13 EXTI14 +---------------------------------------------------------------------------- +D8/PA10 D29/EXT10/PB11 D30/EXTI1/PB12 D31/EXTI12/PB13 D32/EXT13/PB14 +D28/PB10 D20/EXTI1/PC13 D21/EXT2/PC14 +D25/PC10 + +EXTI15 +---------------------------------------------------------------------------- +D33/EXTI14/PB15 +D22/EXT3/PC15 + + +The 16 EXTI interrupts are mapped to 7 interrupt handlers. + +EXTI Lines to Interrupt Mapping: +EXTI0 -> EXTI0 +EXTI1 -> EXTI1 +EXTI2 -> EXTI2 +EXTI3 -> EXTI3 +EXTI4 -> EXTI4 +EXTI[5-9] -> EXT9_5 +EXTI[10-15] -> EXT15_10 diff --git a/wirish/HardwareTimer.cpp b/wirish/HardwareTimer.cpp index 0f8bec6..04d1c76 100644 --- a/wirish/HardwareTimer.cpp +++ b/wirish/HardwareTimer.cpp @@ -89,7 +89,7 @@ uint16 HardwareTimer::setPeriod(uint32 microseconds) { return this->getOverflow(); } -inline void HardwareTimer::setChannelMode(int channel, TimerMode mode) { +void HardwareTimer::setChannelMode(int channel, TimerMode mode) { timer_set_mode(this->timerNum, channel, mode); } @@ -109,7 +109,7 @@ void HardwareTimer::setChannel4Mode(TimerMode mode) { this->setChannelMode(4, mode); } -inline uint16 HardwareTimer::getCompare(int channel) { +uint16 HardwareTimer::getCompare(int channel) { return timer_get_compare_value(this->timerNum, channel); } @@ -129,7 +129,7 @@ uint16 HardwareTimer::getCompare4() { return this->getCompare(4); } -inline void HardwareTimer::setCompare(int channel, uint16 val) { +void HardwareTimer::setCompare(int channel, uint16 val) { uint16 ovf = this->getOverflow(); timer_set_compare_value(this->timerNum, channel, min(val, ovf)); } @@ -150,7 +150,7 @@ void HardwareTimer::setCompare4(uint16 val) { this->setCompare(4, val); } -inline void HardwareTimer::attachInterrupt(int channel, voidFuncPtr handler) { +void HardwareTimer::attachInterrupt(int channel, voidFuncPtr handler) { timer_attach_interrupt(this->timerNum, channel, handler); } @@ -170,7 +170,7 @@ void HardwareTimer::attachCompare4Interrupt(voidFuncPtr handler) { this->attachInterrupt(4, handler); } -inline void HardwareTimer::detachInterrupt(int channel) { +void HardwareTimer::detachInterrupt(int channel) { timer_detach_interrupt(this->timerNum, channel); } @@ -194,7 +194,6 @@ void HardwareTimer::generateUpdate(void) { timer_generate_update(this->timerNum); } - HardwareTimer Timer1(TIMER1); HardwareTimer Timer2(TIMER2); HardwareTimer Timer3(TIMER3); diff --git a/wirish/boards.cpp b/wirish/boards.cpp new file mode 100644 index 0000000..9276f36 --- /dev/null +++ b/wirish/boards.cpp @@ -0,0 +1,387 @@ +#include "boards.h" + +// think of the poor column numbers +#define ADCx ADC_INVALID +#define TIMERx TIMER_INVALID + +#if defined(BOARD_maple) + +PinMapping PIN_MAP[NR_GPIO_PINS] = { + /* D0/PA3 */ + {GPIOA, 3, 3, TIMER2_CH4_CCR, TIMER2, 4, AFIO_EXTI_PA}, + /* D1/PA2 */ + {GPIOA, 2, 2, TIMER2_CH3_CCR, TIMER2, 3, AFIO_EXTI_PA}, + /* D2/PA0 */ + {GPIOA, 0, 0, TIMER2_CH1_CCR, TIMER2, 1, AFIO_EXTI_PA}, + /* D3/PA1 */ + {GPIOA, 1, 1, TIMER2_CH2_CCR, TIMER2, 2, AFIO_EXTI_PA}, + /* D4/PB5 */ + {GPIOB, 5, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, + /* D5/PB6 */ + {GPIOB, 6, ADCx, TIMER4_CH1_CCR, TIMER4, 1, AFIO_EXTI_PB}, + /* D6/PA8 */ + {GPIOA, 8, ADCx, TIMER1_CH1_CCR, TIMER1, 1, AFIO_EXTI_PA}, + /* D7/PA9 */ + {GPIOA, 9, ADCx, TIMER1_CH2_CCR, TIMER1, 2, AFIO_EXTI_PA}, + /* D8/PA10 */ + {GPIOA, 10, ADCx, TIMER1_CH3_CCR, TIMER1, 3, AFIO_EXTI_PA}, + /* D9/PB7 */ + {GPIOB, 7, ADCx, TIMER4_CH2_CCR, TIMER4, 2, AFIO_EXTI_PB}, + /* D10/PA4 */ + {GPIOA, 4, 4, 0, TIMERx, TIMERx, AFIO_EXTI_PA}, + /* D11/PA7 */ + {GPIOA, 7, 7, TIMER3_CH2_CCR, TIMER3, 2, AFIO_EXTI_PA}, + /* D12/PA6 */ + {GPIOA, 6, 6, TIMER3_CH1_CCR, TIMER3, 1, AFIO_EXTI_PA}, + /* D13/PA5 */ + {GPIOA, 5, 5, 0, TIMERx, TIMERx, AFIO_EXTI_PA}, + /* D14/PB8 */ + {GPIOB, 8, ADCx, TIMER4_CH3_CCR, TIMER4, 3, AFIO_EXTI_PB}, + + /* Little header */ + + /* D15/PC0 */ + {GPIOC, 0, 10, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D16/PC1 */ + {GPIOC, 1, 11, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D17/PC2 */ + {GPIOC, 2, 12, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D18/PC3 */ + {GPIOC, 3, 13, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D19/PC4 */ + {GPIOC, 4, 14, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D20/PC5 */ + {GPIOC, 5, 15, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + + /* External header */ + + /* D21/PC13 */ + {GPIOC, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D22/PC14 */ + {GPIOC, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D23/PC15 */ + {GPIOC, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D24/PB9 */ + {GPIOB, 9, ADCx, TIMER4_CH4_CCR, TIMER4, 4, AFIO_EXTI_PB}, + /* D25/PD2 */ + {GPIOD, 2, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, + /* D26/PC10 */ + {GPIOC, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D27/PB0 */ + {GPIOB, 0, 8, TIMER3_CH3_CCR, TIMER3, 3, AFIO_EXTI_PB}, + /* D28/PB1 */ + {GPIOB, 1, 9, TIMER3_CH4_CCR, TIMER3, 4, AFIO_EXTI_PB}, + /* D29/PB10 */ + {GPIOB, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, + /* D30/PB11 */ + {GPIOB, 11, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, + /* D31/PB12 */ + {GPIOB, 12, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, + /* D32/PB13 */ + {GPIOB, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, + /* D33/PB14 */ + {GPIOB, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, + /* D34/PB15 */ + {GPIOB, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, + /* D35/PC6 */ + {GPIOC, 6, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D36/PC7 */ + {GPIOC, 7, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D37/PC8 */ + {GPIOC, 8, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D38/PC9 (BUT) */ + {GPIOC, 9, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC} +}; + +#elif defined(BOARD_maple_native) + +PinMapping PIN_MAP[NR_GPIO_PINS] = { + /* Top header */ + + /* D0/PB10 */ + {GPIOB, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, + /* D1/PB2 */ + {GPIOB, 2, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, + /* D2/PB12 */ + {GPIOB, 12, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, + /* D3/PB13 */ + {GPIOB, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, + /* D4/PB14 */ + {GPIOB, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, + /* D5/PB15 */ + {GPIOB, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, + /* D6/PC0 */ + {GPIOC, 0, 10, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D7/PC1 */ + {GPIOC, 1, 11, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D8/PC2 */ + {GPIOC, 2, 12, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D9/PC3 */ + {GPIOC, 3, 13, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D10/PC4 */ + {GPIOC, 4, 14, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D11/PC5 */ + {GPIOC, 5, 15, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D12/PC6 */ + {GPIOC, 6, ADCx, TIMER8_CH1_CCR, TIMER8, 1, AFIO_EXTI_PC}, + /* D13/PC7 */ + {GPIOC, 7, ADCx, TIMER8_CH2_CCR, TIMER8, 2, AFIO_EXTI_PC}, + /* D14/PC8 */ + {GPIOC, 8, ADCx, TIMER8_CH3_CCR, TIMER8, 3, AFIO_EXTI_PC}, + /* D15/PC9 */ + {GPIOC, 9, ADCx, TIMER8_CH4_CCR, TIMER8, 4, AFIO_EXTI_PC}, + /* D16/PC10 */ + {GPIOC, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D17/PC11 */ + {GPIOC, 11, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D18/PC12 */ + {GPIOC, 12, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D19/PC13 */ + {GPIOC, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D20/PC14 */ + {GPIOC, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D21/PC15 */ + {GPIOC, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D22/PA8 */ + {GPIOA, 8, ADCx, TIMER1_CH1_CCR, TIMER1, 1, AFIO_EXTI_PA}, + /* D23/PA9 */ + {GPIOA, 9, ADCx, TIMER1_CH2_CCR, TIMER1, 2, AFIO_EXTI_PA}, + /* D24/PA10 */ + {GPIOA, 10, ADCx, TIMER1_CH3_CCR, TIMER1, 3, AFIO_EXTI_PA}, + /* D25/PB9 */ + {GPIOB, 9, ADCx, TIMER4_CH4_CCR, TIMER4, 4, AFIO_EXTI_PB}, + + /* Bottom header */ + + /* D26/PD2 */ + {GPIOD, 2, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, + /* D27/PD3 */ + {GPIOD, 3, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, + /* D28/PD6 */ + {GPIOD, 6, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, + /* D29/PG11 */ + {GPIOG, 11, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, + /* D30/PG12 */ + {GPIOG, 12, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, + /* D31/PG13 */ + {GPIOG, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, + /* D32/PG14 */ + {GPIOG, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, + /* D33/PG8 */ + {GPIOG, 8, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, + /* D34/PG7 */ + {GPIOG, 7, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, + /* D35/PG6 */ + {GPIOG, 6, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, + /* D36/PB5 */ + {GPIOB, 5, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, + /* D37/PB6 */ + {GPIOB, 6, ADCx, TIMER4_CH1_CCR, TIMER4, 1, AFIO_EXTI_PB}, + /* D38/PB7 */ + {GPIOB, 7, ADCx, TIMER4_CH2_CCR, TIMER4, 2, AFIO_EXTI_PB}, + /* D39/PF6 */ + {GPIOF, 6, 4, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, + /* D40/PF7 */ + {GPIOF, 7, 5, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, + /* D41/PF8 */ + {GPIOF, 8, 6, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, + /* D42/PF9 */ + {GPIOF, 9, 7, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, + /* D43/PF10 */ + {GPIOF, 10, 8, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, + /* D44/PF11 */ + {GPIOF, 11, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, + /* D45/PB1 */ + {GPIOB, 1, 9, TIMER3_CH4_CCR, TIMER3, 4, AFIO_EXTI_PB}, + /* D46/PB0 */ + {GPIOB, 0, 8, TIMER3_CH3_CCR, TIMER3, 3, AFIO_EXTI_PB}, + /* D47/PA0 */ + {GPIOA, 0, 0, TIMER5_CH1_CCR, TIMER5, 1, AFIO_EXTI_PA}, + /* D48/PA1 */ /* FIXME (?) + What about D48--D50 also being TIMER2_CH[234]? */ + {GPIOA, 1, 1, TIMER5_CH2_CCR, TIMER5, 2, AFIO_EXTI_PA}, + /* D49/PA2 */ + {GPIOA, 2, 2, TIMER5_CH3_CCR, TIMER5, 3, AFIO_EXTI_PA}, + /* D50/PA3 */ + {GPIOA, 3, 3, TIMER5_CH4_CCR, TIMER5, 4, AFIO_EXTI_PA}, + /* D51/PA4 */ + {GPIOA, 4, 4, 0, TIMERx, TIMERx, AFIO_EXTI_PA}, + /* D52/PA5 */ + {GPIOA, 5, 5, 0, TIMERx, TIMERx, AFIO_EXTI_PA}, + /* D53/PA6 */ + {GPIOA, 6, 6, TIMER3_CH1_CCR, TIMER3, 1, AFIO_EXTI_PA}, + /* D54/PA7 */ + {GPIOA, 7, 7, TIMER3_CH2_CCR, TIMER3, 2, AFIO_EXTI_PA}, + + /* Right (triple) header */ + + /* D55/PF0 */ + {GPIOF, 0, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, + /* D56/PD11 */ + {GPIOD, 11, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, + /* D57/PD14 */ + {GPIOD, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, + /* D58/PF1 */ + {GPIOF, 1, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, + /* D59/PD12 */ + {GPIOD, 12, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, + /* D60/PD15 */ + {GPIOD, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, + /* D61/PF2 */ + {GPIOF, 2, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, + /* D62/PD13 */ + {GPIOD, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, + /* D63/PD0 */ + {GPIOD, 0, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, + /* D64/PF3 */ + {GPIOF, 3, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, + /* D65/PE3 */ + {GPIOE, 3, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE}, + /* D66/PD1 */ + {GPIOD, 1, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, + /* D67/PF4 */ + {GPIOF, 4, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, + /* D68/PE4 */ + {GPIOE, 4, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE}, + /* D69/PE7 */ + {GPIOE, 7, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE}, + /* D70/PF5 */ + {GPIOF, 5, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, + /* D71/PE5 */ + {GPIOE, 5, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE}, + /* D72/PE8 */ + {GPIOE, 8, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE}, + /* D73/PF12 */ + {GPIOF, 12, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, + /* D74/PE6 */ + {GPIOE, 6, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE}, + /* D75/PE9 */ + {GPIOE, 9, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE}, + /* D76/PF13 */ + {GPIOF, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, + /* D77/PE10 */ + {GPIOE, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE}, + /* D78/PF14 */ + {GPIOF, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, + /* D79/PG9 */ + {GPIOG, 9, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, + /* D80/PE11 */ + {GPIOE, 11, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE}, + /* D81/PF15 */ + {GPIOF, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, + /* D82/PG10 */ + {GPIOG, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, + /* D83/PE12 */ + {GPIOE, 12, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE}, + /* D84/PG0 */ + {GPIOG, 0, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, + /* D85/PD5 */ + {GPIOD, 5, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, + /* D86/PE13 */ + {GPIOE, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE}, + /* D87/PG1 */ + {GPIOG, 1, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, + /* D88/PD4 */ + {GPIOD, 4, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, + /* D89/PE14 */ + {GPIOE, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE}, + /* D90/PG2 */ + {GPIOG, 2, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, + /* D91/PE1 */ + {GPIOE, 1, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE}, + /* D92/PE15 */ + {GPIOE, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE}, + /* D93/PG3 */ + {GPIOG, 3, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, + /* D94/PE0 */ + {GPIOE, 0, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE}, + /* D95/PD8 */ + {GPIOD, 8, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, + /* D96/PG4 */ + {GPIOG, 4, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, + /* D97/PD9 */ + {GPIOD, 9, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, + /* D98/PG5 */ + {GPIOG, 5, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, + /* D99/PD10 */ + {GPIOD, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PDD} +}; + +#elif defined(BOARD_maple_mini) + +PinMapping PIN_MAP[NR_GPIO_PINS] = { + /* D0/PB11 */ + {GPIOB, 11, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, + /* D1/PB10 */ + {GPIOB, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, + /* D2/PB2 */ + {GPIOB, 2, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, + /* D3/PB0 */ + {GPIOB, 0, 8, TIMER3_CH3_CCR, TIMER3, 3, AFIO_EXTI_PB}, + /* D4/PA7 */ + {GPIOA, 7, 7, TIMER3_CH2_CCR, TIMER3, 2, AFIO_EXTI_PA}, + /* D5/PA6 */ + {GPIOA, 6, 6, TIMER3_CH1_CCR, TIMER3, 1, AFIO_EXTI_PA}, + /* D6/PA5 */ + {GPIOA, 5, 5, 0, TIMERx, TIMERx, AFIO_EXTI_PA}, + /* D7/PA4 */ + {GPIOA, 4, 4, 0, TIMERx, TIMERx, AFIO_EXTI_PA}, + /* D8/PA3 */ + {GPIOA, 3, 3, TIMER2_CH4_CCR, TIMER2, 4, AFIO_EXTI_PA}, + /* D9/PA2 */ + {GPIOA, 2, 2, TIMER2_CH3_CCR, TIMER2, 3, AFIO_EXTI_PA}, + /* D10/PA1 */ + {GPIOA, 1, 1, TIMER2_CH2_CCR, TIMER2, 2, AFIO_EXTI_PA}, + /* D11/PA0 */ + {GPIOA, 0, 0, TIMER2_CH1_CCR, TIMER2, 1, AFIO_EXTI_PA}, + /* D12/PC15 */ + {GPIOC, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D13/PC14 */ + {GPIOC, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D14/PC13 */ + {GPIOC, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D15/PB7 */ + {GPIOB, 7, ADCx, TIMER4_CH2_CCR, TIMER4, 2, AFIO_EXTI_PB}, + /* D16/PB6 */ + {GPIOB, 6, ADCx, TIMER4_CH1_CCR, TIMER4, 1, AFIO_EXTI_PB}, + /* D17/PB5 */ + {GPIOB, 5, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, + /* D18/PB4 */ + {GPIOB, 4, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, + /* D19/PB3 */ + {GPIOB, 3, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, + /* D20/PA15 */ + {GPIOA, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PA}, + /* D21/PA14 */ + {GPIOA, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PA}, + /* D22/PA13 */ + {GPIOA, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PA}, + /* D23/PA12 */ + {GPIOA, 12, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PA}, + /* D24/PA11 */ + {GPIOA, 11, ADCx, TIMER1_CH4_CCR, TIMER1, 4, AFIO_EXTI_PA}, + /* D25/PA10 */ + {GPIOA, 10, ADCx, TIMER1_CH3_CCR, TIMER1, 3, AFIO_EXTI_PA}, + /* D26/PA9 */ + {GPIOA, 9, ADCx, TIMER1_CH2_CCR, TIMER2, 2, AFIO_EXTI_PA}, + /* D27/PA8 */ + {GPIOA, 8, ADCx, TIMER1_CH1_CCR, TIMER1, 1, AFIO_EXTI_PA}, + /* D28/PB15 */ + {GPIOB, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, + /* D29/PB14 */ + {GPIOB, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, + /* D30/PB13 */ + {GPIOB, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, + /* D31/PB12 */ + {GPIOB, 12, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, + /* D32/PB8 */ + {GPIOB, 8, ADCx, TIMER4_CH3_CCR, TIMER4, 3, AFIO_EXTI_PB}, + /* D33/PB1 */ + {GPIOB, 1, 9, TIMER3_CH4_CCR, TIMER3, 4, AFIO_EXTI_PB}, +}; + +#else + +#error "Board type has not been selected correctly." + +#endif diff --git a/wirish/boards.h b/wirish/boards.h index ee93c5a..2941127 100644 --- a/wirish/boards.h +++ b/wirish/boards.h @@ -34,13 +34,11 @@ #include "libmaple.h" #include "gpio.h" #include "timers.h" -#include "exti.h" -#ifdef __cplusplus -extern "C" { -#endif - -/* Set of all possible digital pin names; not all boards have all these */ +/* Set of all possible pin names; not all boards have all these (note + that we use the Dx convention since all of the Maple's pins are + "digital" pins (e.g. can be used with digitalRead() and + digitalWrite()), but not all of them are connected to ADCs. */ enum { D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15, D16, D17, D18, D19, D20, D21, D22, D23, D24, D25, D26, D27, D28, D29, D30, D31, @@ -53,17 +51,20 @@ enum { #define ADC_INVALID 0xFFFFFFFF -/* Types used for the tables below */ +/* Pin mapping: pin number -> STM32 info */ typedef struct PinMapping { - GPIO_Port *port; + gpio_dev *gpio_device; uint32 pin; uint32 adc_channel; TimerCCR timer_ccr; - uint32 exti_port; timer_dev_num timer_num; uint32 timer_chan; + afio_exti_port ext_port; } PinMapping; +/* Maps every digital pin to a PinMapping */ +extern PinMapping PIN_MAP[]; + /* LeafLabs Maple rev3, rev5 */ #ifdef BOARD_maple @@ -77,93 +78,6 @@ typedef struct PinMapping { intended for general use. */ #define NR_GPIO_PINS 39 - static __attribute__ ((unused)) PinMapping PIN_MAP[NR_GPIO_PINS] = { - /* D0/PA3 */ - {GPIOA_BASE, 3, 3, TIMER2_CH4_CCR, EXTI_CONFIG_PORTA, TIMER2, 4}, - /* D1/PA2 */ - {GPIOA_BASE, 2, 2, TIMER2_CH3_CCR, EXTI_CONFIG_PORTA, TIMER2, 3}, - /* D2/PA0 */ - {GPIOA_BASE, 0, 0, TIMER2_CH1_CCR, EXTI_CONFIG_PORTA, TIMER2, 1}, - /* D3/PA1 */ - {GPIOA_BASE, 1, 1, TIMER2_CH2_CCR, EXTI_CONFIG_PORTA, TIMER2, 2}, - /* D4/PB5 */ - {GPIOB_BASE, 5, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, - /* D5/PB6 */ - {GPIOB_BASE, 6, ADC_INVALID, TIMER4_CH1_CCR, EXTI_CONFIG_PORTB, TIMER4, 1}, - /* D6/PA8 */ - {GPIOA_BASE, 8, ADC_INVALID, TIMER1_CH1_CCR, EXTI_CONFIG_PORTA, TIMER1, 1}, - /* D7/PA9 */ - {GPIOA_BASE, 9, ADC_INVALID, TIMER1_CH2_CCR, EXTI_CONFIG_PORTA, TIMER1, 2}, - /* D8/PA10 */ - {GPIOA_BASE, 10, ADC_INVALID, TIMER1_CH3_CCR, EXTI_CONFIG_PORTA, TIMER1, 3}, - /* D9/PB7 */ - {GPIOB_BASE, 7, ADC_INVALID, TIMER4_CH2_CCR, EXTI_CONFIG_PORTB, TIMER4, 2}, - /* D10/PA4 */ - {GPIOA_BASE, 4, 4, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID}, - /* D11/PA7 */ - {GPIOA_BASE, 7, 7, TIMER3_CH2_CCR, EXTI_CONFIG_PORTA, TIMER3, 2}, - /* D12/PA6 */ - {GPIOA_BASE, 6, 6, TIMER3_CH1_CCR, EXTI_CONFIG_PORTA, TIMER3, 1}, - /* D13/PA5 */ - {GPIOA_BASE, 5, 5, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID}, - /* D14/PB8 */ - {GPIOB_BASE, 8, ADC_INVALID, TIMER4_CH3_CCR, EXTI_CONFIG_PORTB, TIMER4, 3}, - - /* Little header */ - - /* D15/PC0 */ - {GPIOC_BASE, 0, 10, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, - /* D16/PC1 */ - {GPIOC_BASE, 1, 11, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, - /* D17/PC2 */ - {GPIOC_BASE, 2, 12, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, - /* D18/PC3 */ - {GPIOC_BASE, 3, 13, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, - /* D19/PC4 */ - {GPIOC_BASE, 4, 14, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, - /* D20/PC5 */ - {GPIOC_BASE, 5, 15, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, - - /* External header */ - - /* D21/PC13 */ - {GPIOC_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, - /* D22/PC14 */ - {GPIOC_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, - /* D23/PC15 */ - {GPIOC_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, - /* D24/PB9 */ - {GPIOB_BASE, 9, ADC_INVALID, TIMER4_CH4_CCR, EXTI_CONFIG_PORTB, TIMER4, 4}, - /* D25/PD2 */ - {GPIOD_BASE, 2, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, - /* D26/PC10 */ - {GPIOC_BASE, 10, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, - /* D27/PB0 */ - {GPIOB_BASE, 0, 8, TIMER3_CH3_CCR, EXTI_CONFIG_PORTB, TIMER3, 3}, - /* D28/PB1 */ - {GPIOB_BASE, 1, 9, TIMER3_CH4_CCR, EXTI_CONFIG_PORTB, TIMER3, 4}, - /* D29/PB10 */ - {GPIOB_BASE, 10, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, - /* D30/PB11 */ - {GPIOB_BASE, 11, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, - /* D31/PB12 */ - {GPIOB_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, - /* D32/PB13 */ - {GPIOB_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, - /* D33/PB14 */ - {GPIOB_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, - /* D34/PB15 */ - {GPIOB_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, - /* D35/PC6 */ - {GPIOC_BASE, 6, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, - /* D36/PC7 */ - {GPIOC_BASE, 7, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, - /* D37/PC8 */ - {GPIOC_BASE, 8, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, - /* D38/PC9 (BUT) */ - {GPIOC_BASE, 9, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID} - }; - #define BOARD_INIT do { \ } while(0) @@ -179,218 +93,6 @@ typedef struct PinMapping { #define NR_GPIO_PINS 100 - static __attribute__ ((unused)) PinMapping PIN_MAP[NR_GPIO_PINS] = { - /* Top header */ - - /* D0/PB10 */ - {GPIOB_BASE, 10, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, - /* D1/PB2 */ - {GPIOB_BASE, 2, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, - /* D2/PB12 */ - {GPIOB_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, - /* D3/PB13 */ - {GPIOB_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, - /* D4/PB14 */ - {GPIOB_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, - /* D5/PB15 */ - {GPIOB_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, - /* D6/PC0 */ - {GPIOC_BASE, 0, 10, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, - /* D7/PC1 */ - {GPIOC_BASE, 1, 11, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, - /* D8/PC2 */ - {GPIOC_BASE, 2, 12, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, - /* D9/PC3 */ - {GPIOC_BASE, 3, 13, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, - /* D10/PC4 */ - {GPIOC_BASE, 4, 14, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, - /* D11/PC5 */ - {GPIOC_BASE, 5, 15, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, - /* D12/PC6 */ - {GPIOC_BASE, 6, ADC_INVALID, TIMER8_CH1_CCR, EXTI_CONFIG_PORTC, TIMER8, 1}, - /* D13/PC7 */ - {GPIOC_BASE, 7, ADC_INVALID, TIMER8_CH2_CCR, EXTI_CONFIG_PORTC, TIMER8, 2}, - /* D14/PC8 */ - {GPIOC_BASE, 8, ADC_INVALID, TIMER8_CH3_CCR, EXTI_CONFIG_PORTC, TIMER8, 3}, - /* D15/PC9 */ - {GPIOC_BASE, 9, ADC_INVALID, TIMER8_CH4_CCR, EXTI_CONFIG_PORTC, TIMER8, 4}, - /* D16/PC10 */ - {GPIOC_BASE, 10, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, - /* D17/PC11 */ - {GPIOC_BASE, 11, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, - /* D18/PC12 */ - {GPIOC_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, - /* D19/PC13 */ - {GPIOC_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, - /* D20/PC14 */ - {GPIOC_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, - /* D21/PC15 */ - {GPIOC_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, - /* D22/PA8 */ - {GPIOA_BASE, 8, ADC_INVALID, TIMER1_CH1_CCR, EXTI_CONFIG_PORTA, TIMER1, 1}, - /* D23/PA9 */ - {GPIOA_BASE, 9, ADC_INVALID, TIMER1_CH2_CCR, EXTI_CONFIG_PORTA, TIMER1, 2}, - /* D24/PA10 */ - {GPIOA_BASE, 10, ADC_INVALID, TIMER1_CH3_CCR, EXTI_CONFIG_PORTA, TIMER1, 3}, - /* D25/PB9 */ - {GPIOB_BASE, 9, ADC_INVALID, TIMER4_CH4_CCR, EXTI_CONFIG_PORTB, TIMER4, 4}, - - /* Bottom header */ - - /* D26/PD2 */ - {GPIOD_BASE, 2, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, - /* D27/PD3 */ - {GPIOD_BASE, 3, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, - /* D28/PD6 */ - {GPIOD_BASE, 6, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, - /* D29/PG11 */ - {GPIOG_BASE, 11, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, - /* D30/PG12 */ - {GPIOG_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, - /* D31/PG13 */ - {GPIOG_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, - /* D32/PG14 */ - {GPIOG_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, - /* D33/PG8 */ - {GPIOG_BASE, 8, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, - /* D34/PG7 */ - {GPIOG_BASE, 7, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, - /* D35/PG6 */ - {GPIOG_BASE, 6, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, - /* D36/PB5 */ - {GPIOB_BASE, 5, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, - /* D37/PB6 */ - {GPIOB_BASE, 6, ADC_INVALID, TIMER4_CH1_CCR, EXTI_CONFIG_PORTB, TIMER4, 1}, - /* D38/PB7 */ - {GPIOB_BASE, 7, ADC_INVALID, TIMER4_CH2_CCR, EXTI_CONFIG_PORTB, TIMER4, 2}, - /* D39/PF6 */ - {GPIOF_BASE, 6, 4, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, - /* D40/PF7 */ - {GPIOF_BASE, 7, 5, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, - /* D41/PF8 */ - {GPIOF_BASE, 8, 6, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, - /* D42/PF9 */ - {GPIOF_BASE, 9, 7, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, - /* D43/PF10 */ - {GPIOF_BASE, 10, 8, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, - /* D44/PF11 */ - {GPIOF_BASE, 11, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, - /* D45/PB1 */ - {GPIOB_BASE, 1, 9, TIMER3_CH4_CCR, EXTI_CONFIG_PORTB, TIMER3, 4}, - /* D46/PB0 */ - {GPIOB_BASE, 0, 8, TIMER3_CH3_CCR, EXTI_CONFIG_PORTB, TIMER3, 3}, - /* D47/PA0 */ - {GPIOA_BASE, 0, 0, TIMER5_CH1_CCR, EXTI_CONFIG_PORTA, TIMER5, 1}, - /* D48/PA1 */ - {GPIOA_BASE, 1, 1, TIMER5_CH2_CCR, EXTI_CONFIG_PORTA, TIMER5, 2}, /* FIXME (?) what to do about D48--D50 - also being TIMER2_CH[2,3,4]? */ - /* D49/PA2 */ - {GPIOA_BASE, 2, 2, TIMER5_CH3_CCR, EXTI_CONFIG_PORTA, TIMER5, 3}, - /* D50/PA3 */ - {GPIOA_BASE, 3, 3, TIMER5_CH4_CCR, EXTI_CONFIG_PORTA, TIMER5, 4}, - /* D51/PA4 */ - {GPIOA_BASE, 4, 4, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID}, - /* D52/PA5 */ - {GPIOA_BASE, 5, 5, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID}, - /* D53/PA6 */ - {GPIOA_BASE, 6, 6, TIMER3_CH1_CCR, EXTI_CONFIG_PORTA, TIMER3, 1}, - /* D54/PA7 */ - {GPIOA_BASE, 7, 7, TIMER3_CH2_CCR, EXTI_CONFIG_PORTA, TIMER3, 2}, - - /* Right (triple) header */ - - /* D55/PF0 */ - {GPIOF_BASE, 0, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, - /* D56/PD11 */ - {GPIOD_BASE, 11, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, - /* D57/PD14 */ - {GPIOD_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, - /* D58/PF1 */ - {GPIOF_BASE, 1, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, - /* D59/PD12 */ - {GPIOD_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, - /* D60/PD15 */ - {GPIOD_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, - /* D61/PF2 */ - {GPIOF_BASE, 2, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, - /* D62/PD13 */ - {GPIOD_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, - /* D63/PD0 */ - {GPIOD_BASE, 0, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, - /* D64/PF3 */ - {GPIOF_BASE, 3, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, - /* D65/PE3 */ - {GPIOE_BASE, 3, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, - /* D66/PD1 */ - {GPIOD_BASE, 1, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, - /* D67/PF4 */ - {GPIOF_BASE, 4, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, - /* D68/PE4 */ - {GPIOE_BASE, 4, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, - /* D69/PE7 */ - {GPIOE_BASE, 7, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, - /* D70/PF5 */ - {GPIOF_BASE, 5, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, - /* D71/PE5 */ - {GPIOE_BASE, 5, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, - /* D72/PE8 */ - {GPIOE_BASE, 8, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, - /* D73/PF12 */ - {GPIOF_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, - /* D74/PE6 */ - {GPIOE_BASE, 6, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, - /* D75/PE9 */ - {GPIOE_BASE, 9, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, - /* D76/PF13 */ - {GPIOF_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, - /* D77/PE10 */ - {GPIOE_BASE, 10, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, - /* D78/PF14 */ - {GPIOF_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, - /* D79/PG9 */ - {GPIOG_BASE, 9, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, - /* D80/PE11 */ - {GPIOE_BASE, 11, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, - /* D81/PF15 */ - {GPIOF_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTF, TIMER_INVALID, TIMER_INVALID}, - /* D82/PG10 */ - {GPIOG_BASE, 10, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, - /* D83/PE12 */ - {GPIOE_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, - /* D84/PG0 */ - {GPIOG_BASE, 0, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, - /* D85/PD5 */ - {GPIOD_BASE, 5, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, - /* D86/PE13 */ - {GPIOE_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, - /* D87/PG1 */ - {GPIOG_BASE, 1, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, - /* D88/PD4 */ - {GPIOD_BASE, 4, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, - /* D89/PE14 */ - {GPIOE_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, - /* D90/PG2 */ - {GPIOG_BASE, 2, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, - /* D91/PE1 */ - {GPIOE_BASE, 1, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, - /* D92/PE15 */ - {GPIOE_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, - /* D93/PG3 */ - {GPIOG_BASE, 3, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, - /* D94/PE0 */ - {GPIOE_BASE, 0, ADC_INVALID, 0, EXTI_CONFIG_PORTE, TIMER_INVALID, TIMER_INVALID}, - /* D95/PD8 */ - {GPIOD_BASE, 8, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, - /* D96/PG4 */ - {GPIOG_BASE, 4, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, - /* D97/PD9 */ - {GPIOD_BASE, 9, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID}, - /* D98/PG5 */ - {GPIOG_BASE, 5, ADC_INVALID, 0, EXTI_CONFIG_PORTG, TIMER_INVALID, TIMER_INVALID}, - /* D99/PD10 */ - {GPIOD_BASE, 10, ADC_INVALID, 0, EXTI_CONFIG_PORTD, TIMER_INVALID, TIMER_INVALID} - }; - #define BOARD_INIT do { \ } while(0) @@ -404,83 +106,11 @@ typedef struct PinMapping { #define NR_GPIO_PINS 34 - static __attribute__ ((unused)) PinMapping PIN_MAP[NR_GPIO_PINS] = { - /* D0/PB11 */ - {GPIOB_BASE, 11, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, - /* D1/PB10 */ - {GPIOB_BASE, 10, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, - /* D2/PB2 */ - {GPIOB_BASE, 2, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, - /* D3/PB0 */ - {GPIOB_BASE, 0, 8, TIMER3_CH3_CCR, EXTI_CONFIG_PORTB, TIMER3, 3}, - /* D4/PA7 */ - {GPIOA_BASE, 7, 7, TIMER3_CH2_CCR, EXTI_CONFIG_PORTA, TIMER3, 2}, - /* D5/PA6 */ - {GPIOA_BASE, 6, 6, TIMER3_CH1_CCR, EXTI_CONFIG_PORTA, TIMER3, 1}, - /* D6/PA5 */ - {GPIOA_BASE, 5, 5, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID}, - /* D7/PA4 */ - {GPIOA_BASE, 4, 4, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID}, - /* D8/PA3 */ - {GPIOA_BASE, 3, 3, TIMER2_CH4_CCR, EXTI_CONFIG_PORTA, TIMER2, 4}, - /* D9/PA2 */ - {GPIOA_BASE, 2, 2, TIMER2_CH3_CCR, EXTI_CONFIG_PORTA, TIMER2, 3}, - /* D10/PA1 */ - {GPIOA_BASE, 1, 1, TIMER2_CH2_CCR, EXTI_CONFIG_PORTA, TIMER2, 2}, - /* D11/PA0 */ - {GPIOA_BASE, 0, 0, TIMER2_CH1_CCR, EXTI_CONFIG_PORTA, TIMER2, 1}, - /* D12/PC15 */ - {GPIOC_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, - /* D13/PC14 */ - {GPIOC_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, - /* D14/PC13 */ - {GPIOC_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, - /* D15/PB7 */ - {GPIOB_BASE, 7, ADC_INVALID, TIMER4_CH2_CCR, EXTI_CONFIG_PORTB, TIMER4, 1}, - /* D16/PB6 */ - {GPIOB_BASE, 6, ADC_INVALID, TIMER4_CH1_CCR, EXTI_CONFIG_PORTB, TIMER4, 1}, - /* D17/PB5 */ - {GPIOB_BASE, 5, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, - /* D18/PB4 */ - {GPIOB_BASE, 4, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, - /* D19/PB3 */ - {GPIOB_BASE, 3, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, - /* D20/PA15 */ - {GPIOA_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID}, - /* D21/PA14 */ - {GPIOA_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID}, - /* D22/PA13 */ - {GPIOA_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID}, - /* D23/PA12 */ - {GPIOA_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID}, - /* D24/PA11 */ - {GPIOA_BASE, 11, ADC_INVALID, TIMER1_CH4_CCR, EXTI_CONFIG_PORTA, TIMER1, 4}, - /* D25/PA10 */ - {GPIOA_BASE, 10, ADC_INVALID, TIMER1_CH3_CCR, EXTI_CONFIG_PORTA, TIMER1, 3}, - /* D26/PA9 */ - {GPIOA_BASE, 9, ADC_INVALID, TIMER1_CH2_CCR, EXTI_CONFIG_PORTA, TIMER2, 2}, - /* D27/PA8 */ - {GPIOA_BASE, 8, ADC_INVALID, TIMER1_CH1_CCR, EXTI_CONFIG_PORTB, TIMER1, 1}, - /* D28/PB15 */ - {GPIOB_BASE, 15, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, - /* D29/PB14 */ - {GPIOB_BASE, 14, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, - /* D30/PB13 */ - {GPIOB_BASE, 13, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, - /* D31/PB12 */ - {GPIOB_BASE, 12, ADC_INVALID, 0, EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, - /* D32/PB8 */ - {GPIOB_BASE, 8, ADC_INVALID, TIMER4_CH3_CCR, EXTI_CONFIG_PORTB, TIMER4, 3}, - /* D33/PB1 */ - {GPIOB_BASE, 1, 9, TIMER3_CH4_CCR, EXTI_CONFIG_PORTB, TIMER3, 4}, - }; - - /* since we want the Serial Wire/JTAG pins as GPIOs, disable both - SW and JTAG debug support */ - /* don't use __clear_bits here! */ + /* Since we want the Serial Wire/JTAG pins as GPIOs, disable both + * SW and JTAG debug support */ #define BOARD_INIT \ do { \ - *AFIO_MAPR = (*AFIO_MAPR | BIT(26)) & ~(BIT(25) | BIT(24)); \ + afio_mapr_swj_config(AFIO_MAPR_SWJ_NO_JTAG_NO_SW); \ } while (0) #else @@ -489,9 +119,4 @@ typedef struct PinMapping { #endif -#ifdef __cplusplus -} // extern "C" -#endif - #endif - diff --git a/wirish/comm/HardwareSerial.cpp b/wirish/comm/HardwareSerial.cpp index d6c7e82..08252d8 100644 --- a/wirish/comm/HardwareSerial.cpp +++ b/wirish/comm/HardwareSerial.cpp @@ -34,21 +34,21 @@ #include "gpio.h" #include "timers.h" -HardwareSerial Serial1(USART1, 4500000UL, GPIOA_BASE, 9,10, TIMER1, 2); -HardwareSerial Serial2(USART2, 2250000UL, GPIOA_BASE, 2, 3, TIMER2, 3); -HardwareSerial Serial3(USART3, 2250000UL, GPIOB_BASE, 10,11, TIMER_INVALID, 0); +HardwareSerial Serial1(USART1, 4500000UL, GPIOA, 9,10, TIMER1, 2); +HardwareSerial Serial2(USART2, 2250000UL, GPIOA, 2, 3, TIMER2, 3); +HardwareSerial Serial3(USART3, 2250000UL, GPIOB, 10,11, TIMER_INVALID, 0); // TODO: High density device ports HardwareSerial::HardwareSerial(uint8 usart_num, uint32 max_baud, - GPIO_Port *gpio_port, + gpio_dev *gpio_device, uint8 tx_pin, uint8 rx_pin, timer_dev_num timer_num, uint8 compare_num) { this->usart_num = usart_num; this->max_baud = max_baud; - this->gpio_port = gpio_port; + this->gpio_device = gpio_device; this->tx_pin = tx_pin; this->rx_pin = rx_pin; this->timer_num = timer_num; @@ -72,8 +72,8 @@ void HardwareSerial::begin(uint32 baud) { return; } - gpio_set_mode(gpio_port, tx_pin, GPIO_MODE_AF_OUTPUT_PP); - gpio_set_mode(gpio_port, rx_pin, GPIO_MODE_INPUT_FLOATING); + gpio_set_mode(gpio_device, tx_pin, GPIO_AF_OUTPUT_PP); + gpio_set_mode(gpio_device, rx_pin, GPIO_INPUT_FLOATING); if (timer_num != TIMER_INVALID) { /* turn off any pwm if there's a conflict on this usart */ diff --git a/wirish/comm/HardwareSerial.h b/wirish/comm/HardwareSerial.h index aad8aa7..ef19a56 100644 --- a/wirish/comm/HardwareSerial.h +++ b/wirish/comm/HardwareSerial.h @@ -46,7 +46,7 @@ class HardwareSerial : public Print { private: uint8 usart_num; uint32 max_baud; - GPIO_Port *gpio_port; + gpio_dev *gpio_device; uint8 tx_pin; uint8 rx_pin; timer_dev_num timer_num; @@ -54,7 +54,7 @@ class HardwareSerial : public Print { public: HardwareSerial(uint8 usart_num, uint32 max_baud, - GPIO_Port *gpio_port, + gpio_dev *gpio_device, uint8 tx_pin, uint8 rx_pin, timer_dev_num timer_num, diff --git a/wirish/ext_interrupts.c b/wirish/ext_interrupts.c deleted file mode 100644 index dd7c1a8..0000000 --- a/wirish/ext_interrupts.c +++ /dev/null @@ -1,79 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * 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 ext_interrupts.c - * - * @brief Wiring-like interface for external interrupts - */ - -#include "wirish.h" -#include "exti.h" -#include "ext_interrupts.h" - -/* Attach ISR handler on pin, triggering on the given mode. */ -void attachInterrupt(uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode) { - uint8 outMode; - - /* Parameter checking */ - if (pin >= NR_GPIO_PINS) { - return; - } - - if (!handler) { - return; - } - - switch (mode) { - case RISING: - outMode = EXTI_RISING; - break; - case FALLING: - outMode = EXTI_FALLING; - break; - case CHANGE: - outMode = EXTI_RISING_FALLING; - break; - default: - ASSERT(0); - return; - } - - exti_attach_interrupt(PIN_MAP[pin].exti_port, - PIN_MAP[pin].pin, - handler, - mode); - - return; -} - -/* Disable any interrupts */ -void detachInterrupt(uint8 pin) { - if (!(pin < NR_GPIO_PINS)) { - return; - } - - exti_detach_interrupt(PIN_MAP[pin].pin); -} - diff --git a/wirish/ext_interrupts.cpp b/wirish/ext_interrupts.cpp new file mode 100644 index 0000000..5b32b05 --- /dev/null +++ b/wirish/ext_interrupts.cpp @@ -0,0 +1,82 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * 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 ext_interrupts.c + * + * @brief Wiring-like interface for external interrupts + */ + +#include "boards.h" +#include "gpio.h" +#include "exti.h" +#include "ext_interrupts.h" + +static inline exti_trigger_mode exti_out_mode(ExtIntTriggerMode mode); + +/** + * @brief Attach an interrupt handler to a pin, triggering on the given mode. + * @param pin Pin to attach an interrupt handler onto. + * @param handler Function to call when the external interrupt is triggered. + * @param mode Trigger mode for the given interrupt. + * @see ExtIntTriggerMode + */ +void attachInterrupt(uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode) { + if (pin >= NR_GPIO_PINS || !handler) { + return; + } + + exti_trigger_mode outMode = exti_out_mode(mode); + + exti_attach_interrupt((afio_exti_num)(PIN_MAP[pin].pin), + PIN_MAP[pin].ext_port, + handler, + outMode); +} + +/** + * @brief Disable any external interrupt attached to a pin. + * @param pin Pin number to detach any interrupt from. + */ +void detachInterrupt(uint8 pin) { + if (pin >= NR_GPIO_PINS) { + return; + } + + exti_detach_interrupt((afio_exti_num)(PIN_MAP[pin].pin)); +} + +static inline exti_trigger_mode exti_out_mode(ExtIntTriggerMode mode) { + switch (mode) { + case RISING: + return EXTI_RISING; + case FALLING: + return EXTI_FALLING; + case CHANGE: + return EXTI_RISING_FALLING; + } + // Can't happen + ASSERT(0); + return (exti_trigger_mode)0; +} diff --git a/wirish/ext_interrupts.h b/wirish/ext_interrupts.h index 4e22c71..364bcda 100644 --- a/wirish/ext_interrupts.h +++ b/wirish/ext_interrupts.h @@ -28,7 +28,7 @@ /** * @file ext_interrupts.h * - * @brief External interrupt wiring prototypes and types + * @brief Wiring-like external interrupt prototypes and types. */ #ifndef _EXT_INTERRUPTS_H_ @@ -48,10 +48,6 @@ typedef enum ExtIntTriggerMode_ { changes). */ } ExtIntTriggerMode; -#ifdef __cplusplus -extern "C"{ -#endif - /** * @brief Registers an interrupt handler on a pin. * @@ -104,10 +100,5 @@ static inline void noInterrupts() { nvic_globalirq_disable(); } -#ifdef __cplusplus -} -#endif - - #endif diff --git a/wirish/io.h b/wirish/io.h index 2d22dcd..d2e4d2d 100644 --- a/wirish/io.h +++ b/wirish/io.h @@ -35,10 +35,6 @@ #include "adc.h" #include "time.h" -#ifdef __cplusplus -extern "C"{ -#endif - /** * Specifies a GPIO pin behavior. * @@ -68,11 +64,11 @@ typedef enum WiringPinMode { supply through a large resistor). When the pin is high, not much current flows through to ground and the line stays at positive - voltage; when the pin is low the bus + voltage; when the pin is low, the bus "drains" to ground with a small amount of current constantly flowing through the large resistor from the external supply. In this - mode no current is ever actually /sourced/ + mode, no current is ever actually sourced from the pin. */ INPUT, /**< Basic digital input. The pin voltage is sampled; when @@ -220,8 +216,5 @@ uint8 isButtonPressed(); */ uint8 waitForButtonPress(uint32 timeout_millis); -#ifdef __cplusplus -} // extern "C" -#endif #endif diff --git a/wirish/pwm.c b/wirish/pwm.c deleted file mode 100644 index 072e4cd..0000000 --- a/wirish/pwm.c +++ /dev/null @@ -1,48 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * 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. - *****************************************************************************/ - -/** - * @brief Arduino-compatible PWM implementation. - */ - -#include "wirish.h" -#include "timers.h" -#include "io.h" -#include "pwm.h" - -void pwmWrite(uint8 pin, uint16 duty_cycle) { - TimerCCR ccr; - - if (pin >= NR_GPIO_PINS) { - return; - } - - ccr = PIN_MAP[pin].timer_ccr; - - if (ccr == 0) { - return; - } - - timer_pwm_write_ccr(ccr, duty_cycle); -} diff --git a/wirish/pwm.cpp b/wirish/pwm.cpp new file mode 100644 index 0000000..072e4cd --- /dev/null +++ b/wirish/pwm.cpp @@ -0,0 +1,48 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * 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. + *****************************************************************************/ + +/** + * @brief Arduino-compatible PWM implementation. + */ + +#include "wirish.h" +#include "timers.h" +#include "io.h" +#include "pwm.h" + +void pwmWrite(uint8 pin, uint16 duty_cycle) { + TimerCCR ccr; + + if (pin >= NR_GPIO_PINS) { + return; + } + + ccr = PIN_MAP[pin].timer_ccr; + + if (ccr == 0) { + return; + } + + timer_pwm_write_ccr(ccr, duty_cycle); +} diff --git a/wirish/pwm.h b/wirish/pwm.h index d0bc9e0..a6385e9 100644 --- a/wirish/pwm.h +++ b/wirish/pwm.h @@ -28,12 +28,8 @@ * @brief Arduino-compatible PWM interface. */ -#ifndef _PWM_H -#define _PWM_H - -#ifdef __cplusplus -extern "C"{ -#endif +#ifndef _PWM_H_ +#define _PWM_H_ /** * As a convenience, analogWrite is an alias of pwmWrite to ease @@ -50,10 +46,5 @@ extern "C"{ */ void pwmWrite(uint8 pin, uint16 duty_cycle); -#ifdef __cplusplus -} -#endif - - #endif diff --git a/wirish/rules.mk b/wirish/rules.mk index cb5a69f..cea34f5 100644 --- a/wirish/rules.mk +++ b/wirish/rules.mk @@ -11,21 +11,23 @@ WIRISH_INCLUDES := -I$(d) -I$(d)/comm CFLAGS_$(d) := $(WIRISH_INCLUDES) $(LIBMAPLE_INCLUDES) # Local rules and targets -cSRCS_$(d) := wirish.c \ - wirish_shift.c \ - wirish_analog.c \ - time.c \ - pwm.c \ - ext_interrupts.c \ - wirish_digital.c - -cppSRCS_$(d) := wirish_math.cpp \ - Print.cpp \ - comm/HardwareSerial.cpp \ - comm/HardwareSPI.cpp \ - usb_serial.cpp \ - HardwareTimer.cpp \ - cxxabi-compat.cpp \ +cSRCS_$(d) := + +cppSRCS_$(d) := wirish_math.cpp \ + Print.cpp \ + comm/HardwareSerial.cpp \ + comm/HardwareSPI.cpp \ + usb_serial.cpp \ + HardwareTimer.cpp \ + cxxabi-compat.cpp \ + wirish.cpp \ + wirish_shift.cpp \ + wirish_analog.cpp \ + time.cpp \ + pwm.cpp \ + ext_interrupts.cpp \ + wirish_digital.cpp \ + boards.cpp cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%) cppFILES_$(d) := $(cppSRCS_$(d):%=$(d)/%) diff --git a/wirish/time.c b/wirish/time.c deleted file mode 100644 index c0a0649..0000000 --- a/wirish/time.c +++ /dev/null @@ -1,52 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * 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. - *****************************************************************************/ - -/** - * @brief Delay implementation. - */ - -#include "libmaple.h" -#include "systick.h" -#include "time.h" - -void delay(unsigned long ms) { - uint32 i; - for (i = 0; i < ms; i++) { - delayMicroseconds(1000); - } -} - -void delayMicroseconds(uint32 us) { - /* So (2^32)/12 micros max, or less than 6 minutes */ - us *= 12; - - /* fudge for function call overhead */ - us--; - asm volatile(" mov r0, %[us] \n\t" - "1: subs r0, #1 \n\t" - " bhi 1b \n\t" - : - : [us] "r" (us) - : "r0"); -} diff --git a/wirish/time.cpp b/wirish/time.cpp new file mode 100644 index 0000000..c0a0649 --- /dev/null +++ b/wirish/time.cpp @@ -0,0 +1,52 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * 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. + *****************************************************************************/ + +/** + * @brief Delay implementation. + */ + +#include "libmaple.h" +#include "systick.h" +#include "time.h" + +void delay(unsigned long ms) { + uint32 i; + for (i = 0; i < ms; i++) { + delayMicroseconds(1000); + } +} + +void delayMicroseconds(uint32 us) { + /* So (2^32)/12 micros max, or less than 6 minutes */ + us *= 12; + + /* fudge for function call overhead */ + us--; + asm volatile(" mov r0, %[us] \n\t" + "1: subs r0, #1 \n\t" + " bhi 1b \n\t" + : + : [us] "r" (us) + : "r0"); +} diff --git a/wirish/time.h b/wirish/time.h index 8d3d074..a0c0c82 100644 --- a/wirish/time.h +++ b/wirish/time.h @@ -35,10 +35,6 @@ #include "systick.h" #include "boards.h" -#ifdef __cplusplus -extern "C"{ -#endif - #define US_PER_MS 1000 /** @@ -99,10 +95,5 @@ void delay(unsigned long ms); */ void delayMicroseconds(uint32 us); -#ifdef __cplusplus -} // extern "C" -#endif - - #endif diff --git a/wirish/wirish.c b/wirish/wirish.c deleted file mode 100644 index 4c84d26..0000000 --- a/wirish/wirish.c +++ /dev/null @@ -1,81 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * 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. - *****************************************************************************/ - -/** - * @brief generic maple board bring up: - * - * By default, we bring up all maple boards running on the stm32 to 72mhz, - * clocked off the PLL, driven by the 8MHz external crystal. - * - * AHB and APB2 are clocked at 72MHz - * APB1 is clocked at 36MHz - */ - -#include "wirish.h" -#include "systick.h" -#include "gpio.h" -#include "nvic.h" -#include "usb.h" -#include "rcc.h" -#include "fsmc.h" -#include "dac.h" -#include "flash.h" - -void init(void) { - /* make sure the flash is ready before spinning the high speed clock up */ - flash_enable_prefetch(); - flash_set_latency(FLASH_WAIT_STATE_2); - -#ifdef STM32_HIGH_DENSITY - fsmc_native_sram_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); - rcc_set_prescaler(RCC_PRESCALER_APB1, RCC_APB1_HCLK_DIV_2); - rcc_set_prescaler(RCC_PRESCALER_APB2, RCC_APB2_HCLK_DIV_1); - - nvic_init(); - systick_init(SYSTICK_RELOAD_VAL); - gpio_init(); - - /* Initialize the ADC for slow conversions, to allow for high - impedance inputs. */ - adc_init(ADC1, 0); - adc_set_sample_rate(ADC1, ADC_SMPR_55_5); - - timer_init(TIMER1, 1); - timer_init(TIMER2, 1); - timer_init(TIMER3, 1); - timer_init(TIMER4, 1); -#ifdef STM32_HIGH_DENSITY - timer_init(TIMER5, 1); - timer_init(TIMER8, 1); -#endif - setupUSB(); - - /* include the board-specific init macro */ - BOARD_INIT; -} diff --git a/wirish/wirish.cpp b/wirish/wirish.cpp new file mode 100644 index 0000000..01f4507 --- /dev/null +++ b/wirish/wirish.cpp @@ -0,0 +1,82 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * 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. + *****************************************************************************/ + +/** + * @brief generic maple board bring up: + * + * By default, we bring up all maple boards running on the stm32 to 72mhz, + * clocked off the PLL, driven by the 8MHz external crystal. + * + * AHB and APB2 are clocked at 72MHz + * APB1 is clocked at 36MHz + */ + +#include "wirish.h" +#include "systick.h" +#include "gpio.h" +#include "nvic.h" +#include "usb.h" +#include "rcc.h" +#include "fsmc.h" +#include "dac.h" +#include "flash.h" + +void init(void) { + /* make sure the flash is ready before spinning the high speed clock up */ + flash_enable_prefetch(); + flash_set_latency(FLASH_WAIT_STATE_2); + +#ifdef STM32_HIGH_DENSITY + fsmc_native_sram_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); + rcc_set_prescaler(RCC_PRESCALER_APB1, RCC_APB1_HCLK_DIV_2); + rcc_set_prescaler(RCC_PRESCALER_APB2, RCC_APB2_HCLK_DIV_1); + + nvic_init(); + systick_init(SYSTICK_RELOAD_VAL); + gpio_init_all(); + afio_init(); + + /* Initialize the ADC for slow conversions, to allow for high + impedance inputs. */ + adc_init(ADC1, 0); + adc_set_sample_rate(ADC1, ADC_SMPR_55_5); + + timer_init(TIMER1, 1); + timer_init(TIMER2, 1); + timer_init(TIMER3, 1); + timer_init(TIMER4, 1); +#ifdef STM32_HIGH_DENSITY + timer_init(TIMER5, 1); + timer_init(TIMER8, 1); +#endif + // setupUSB(); + + /* include the board-specific init macro */ + BOARD_INIT; +} diff --git a/wirish/wirish.h b/wirish/wirish.h index 311c74f..447b2b6 100644 --- a/wirish/wirish.h +++ b/wirish/wirish.h @@ -32,25 +32,19 @@ #define _WIRISH_H_ #include "libmaple.h" -#include "boards.h" -#include "time.h" #include "timers.h" + +#include "boards.h" #include "io.h" #include "bits.h" #include "pwm.h" #include "ext_interrupts.h" #include "wirish_math.h" - -#ifdef __cplusplus +#include "time.h" #include "HardwareSPI.h" #include "HardwareSerial.h" #include "usb_serial.h" #include "HardwareTimer.h" -#endif - -#ifdef __cplusplus -extern "C"{ -#endif /* Arduino wiring macros and bit defines */ #define HIGH 0x1 @@ -77,9 +71,5 @@ typedef uint8 byte; void init(void); void shiftOut(uint8 dataPin, uint8 clockPin, uint8 bitOrder, byte val); -#ifdef __cplusplus -} // extern "C" -#endif - #endif diff --git a/wirish/wirish_analog.c b/wirish/wirish_analog.c deleted file mode 100644 index a658184..0000000 --- a/wirish/wirish_analog.c +++ /dev/null @@ -1,41 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * 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. - *****************************************************************************/ - -/** - * @brief Arduino-compatible ADC implementation. - */ - -#include "libmaple.h" -#include "wirish.h" -#include "io.h" - -/* Assumes that the ADC has been initialized and that the pin is set - * to ANALOG_INPUT */ -uint32 analogRead(uint8 pin) { - if(PIN_MAP[pin].adc_channel == ADC_INVALID) { - return 0; - } - - return adc_read(ADC1, PIN_MAP[pin].adc_channel); -} diff --git a/wirish/wirish_analog.cpp b/wirish/wirish_analog.cpp new file mode 100644 index 0000000..a658184 --- /dev/null +++ b/wirish/wirish_analog.cpp @@ -0,0 +1,41 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * 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. + *****************************************************************************/ + +/** + * @brief Arduino-compatible ADC implementation. + */ + +#include "libmaple.h" +#include "wirish.h" +#include "io.h" + +/* Assumes that the ADC has been initialized and that the pin is set + * to ANALOG_INPUT */ +uint32 analogRead(uint8 pin) { + if(PIN_MAP[pin].adc_channel == ADC_INVALID) { + return 0; + } + + return adc_read(ADC1, PIN_MAP[pin].adc_channel); +} diff --git a/wirish/wirish_digital.c b/wirish/wirish_digital.c deleted file mode 100644 index bb28f0a..0000000 --- a/wirish/wirish_digital.c +++ /dev/null @@ -1,142 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * 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. - *****************************************************************************/ - -/* - * Arduino-compatible digital I/O implementation. - */ - -#include "wirish.h" -#include "io.h" - -void pinMode(uint8 pin, WiringPinMode mode) { - uint8 outputMode; - boolean pwm = false; - - if (pin >= NR_GPIO_PINS) { - return; - } - - switch(mode) { - case OUTPUT: - outputMode = GPIO_MODE_OUTPUT_PP; - break; - case OUTPUT_OPEN_DRAIN: - outputMode = GPIO_MODE_OUTPUT_OD; - break; - case INPUT: - case INPUT_FLOATING: - outputMode = GPIO_MODE_INPUT_FLOATING; - break; - case INPUT_ANALOG: - outputMode = GPIO_MODE_INPUT_ANALOG; - break; - case INPUT_PULLUP: - outputMode = GPIO_MODE_INPUT_PU; - break; - case INPUT_PULLDOWN: - outputMode = GPIO_MODE_INPUT_PD; - break; - case PWM: - outputMode = GPIO_MODE_AF_OUTPUT_PP; - pwm = true; - break; - case PWM_OPEN_DRAIN: - outputMode = GPIO_MODE_AF_OUTPUT_OD; - pwm = true; - break; - default: - ASSERT(0); - return; - } - - gpio_set_mode(PIN_MAP[pin].port, PIN_MAP[pin].pin, outputMode); - - if (PIN_MAP[pin].timer_num != TIMER_INVALID) { - /* enable/disable timer channels if we're switching into or - out of pwm */ - if (pwm) { - timer_set_mode(PIN_MAP[pin].timer_num, - PIN_MAP[pin].timer_chan, - TIMER_PWM); - } else { - timer_set_mode(PIN_MAP[pin].timer_num, - PIN_MAP[pin].timer_chan, - TIMER_DISABLED); - } - } -} - - -uint32 digitalRead(uint8 pin) { - if (pin >= NR_GPIO_PINS) { - return 0; - } - - return gpio_read_bit(PIN_MAP[pin].port, PIN_MAP[pin].pin); -} - -void digitalWrite(uint8 pin, uint8 val) { - if (pin >= NR_GPIO_PINS) { - return; - } - - gpio_write_bit(PIN_MAP[pin].port, PIN_MAP[pin].pin, val); -} - -void togglePin(uint8 pin) { - if (pin >= NR_GPIO_PINS) { - return; - } - - gpio_toggle_pin(PIN_MAP[pin].port, PIN_MAP[pin].pin); -} - -uint8 isButtonPressed() { - if (digitalRead(BOARD_BUTTON_PIN)) { - delay(1); - while (digitalRead(BOARD_BUTTON_PIN)) - ; - return true; - } - return false; -} - -uint8 waitForButtonPress(uint32 timeout) { - uint32 start = millis(); - uint32 time; - if (timeout == 0) { - while (!isButtonPressed()) - ; - return true; - } - do { - time = millis(); - /* properly handle wrap-around */ - if ((start > time && time + (0xffffffffU - start) > timeout) || - time - start > timeout) { - return false; - } - } while (!isButtonPressed()); - return true; -} diff --git a/wirish/wirish_digital.cpp b/wirish/wirish_digital.cpp new file mode 100644 index 0000000..0c0bd85 --- /dev/null +++ b/wirish/wirish_digital.cpp @@ -0,0 +1,143 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * 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. + *****************************************************************************/ + +/* + * Arduino-compatible digital I/O implementation. + */ + +#include "wirish.h" +#include "io.h" + +void pinMode(uint8 pin, WiringPinMode mode) { + gpio_pin_mode outputMode; + boolean pwm = false; + + if (pin >= NR_GPIO_PINS) { + return; + } + + switch(mode) { + case OUTPUT: + outputMode = GPIO_OUTPUT_PP; + break; + case OUTPUT_OPEN_DRAIN: + outputMode = GPIO_OUTPUT_OD; + break; + case INPUT: + case INPUT_FLOATING: + outputMode = GPIO_INPUT_FLOATING; + break; + case INPUT_ANALOG: + outputMode = GPIO_INPUT_ANALOG; + break; + case INPUT_PULLUP: + outputMode = GPIO_INPUT_PU; + break; + case INPUT_PULLDOWN: + outputMode = GPIO_INPUT_PD; + break; + case PWM: + outputMode = GPIO_AF_OUTPUT_PP; + pwm = true; + break; + case PWM_OPEN_DRAIN: + outputMode = GPIO_AF_OUTPUT_OD; + pwm = true; + break; + default: + ASSERT(0); + return; + } + + gpio_set_mode(PIN_MAP[pin].gpio_device, PIN_MAP[pin].pin, outputMode); + + if (PIN_MAP[pin].timer_num != TIMER_INVALID) { + /* enable/disable timer channels if we're switching into or + out of pwm */ + if (pwm) { + timer_set_mode(PIN_MAP[pin].timer_num, + PIN_MAP[pin].timer_chan, + TIMER_PWM); + } else { + timer_set_mode(PIN_MAP[pin].timer_num, + PIN_MAP[pin].timer_chan, + TIMER_DISABLED); + } + } +} + + +uint32 digitalRead(uint8 pin) { + if (pin >= NR_GPIO_PINS) { + return 0; + } + + return gpio_read_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].pin) ? + HIGH : LOW; +} + +void digitalWrite(uint8 pin, uint8 val) { + if (pin >= NR_GPIO_PINS) { + return; + } + + gpio_write_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].pin, val); +} + +void togglePin(uint8 pin) { + if (pin >= NR_GPIO_PINS) { + return; + } + + gpio_toggle_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].pin); +} + +uint8 isButtonPressed() { + if (digitalRead(BOARD_BUTTON_PIN)) { + delay(1); + while (digitalRead(BOARD_BUTTON_PIN)) + ; + return true; + } + return false; +} + +uint8 waitForButtonPress(uint32 timeout) { + uint32 start = millis(); + uint32 time; + if (timeout == 0) { + while (!isButtonPressed()) + ; + return true; + } + do { + time = millis(); + /* properly handle wrap-around */ + if ((start > time && time + (0xffffffffU - start) > timeout) || + time - start > timeout) { + return false; + } + } while (!isButtonPressed()); + return true; +} diff --git a/wirish/wirish_math.h b/wirish/wirish_math.h index 14614ba..fa544a9 100644 --- a/wirish/wirish_math.h +++ b/wirish/wirish_math.h @@ -24,7 +24,7 @@ /** * @file wirish_math.h - * @brief Includes cmath; provides Arduino-compatible math routines. + * @brief Includes ; provides Arduino-compatible math routines. */ #ifndef _WIRING_MATH_H_ @@ -32,8 +32,6 @@ #include -#ifdef __cplusplus - /** * @brief Initialize the pseudo-random number generator. * @param seed the number used to initialize the seed; cannot be zero. @@ -78,8 +76,7 @@ long random(long min, long max); * @param toEnd the end of the value's mapped range. * @return the mapped value. */ -/* TODO: profile code bloat due to inlining this */ -inline long map(long value, long fromStart, long fromEnd, +static inline long map(long value, long fromStart, long fromEnd, long toStart, long toEnd) { return (value - fromStart) * (toEnd - toStart) / (fromEnd - fromStart) + toStart; @@ -105,8 +102,6 @@ inline long map(long value, long fromStart, long fromEnd, #endif #define abs(x) (((x) > 0) ? (x) : -(unsigned)(x)) -#endif - /* Following are duplicate declarations (with Doxygen comments) for * some of the math.h functions; this is for the convenience of the * Sphinx docs. diff --git a/wirish/wirish_shift.c b/wirish/wirish_shift.c deleted file mode 100644 index f67364d..0000000 --- a/wirish/wirish_shift.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * wiring_shift.c - shiftOut() function - * Part of Arduino - http://www.arduino.cc/ - * - * Copyright (c) 2005-2006 David A. Mellis - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - * - * $Id: wiring.c 248 2007-02-03 15:36:30Z mellis $ - */ - -#include "wirish.h" - -void shiftOut(uint8 dataPin, uint8 clockPin, uint8 bitOrder, uint8 val) { - int i; - - for (i = 0; i < 8; i++) { - if (bitOrder == LSBFIRST) { - digitalWrite(dataPin, !!(val & (1 << i))); - } else { - digitalWrite(dataPin, !!(val & (1 << (7 - i)))); - } - - digitalWrite(clockPin, HIGH); - digitalWrite(clockPin, LOW); - } -} diff --git a/wirish/wirish_shift.cpp b/wirish/wirish_shift.cpp new file mode 100644 index 0000000..f67364d --- /dev/null +++ b/wirish/wirish_shift.cpp @@ -0,0 +1,40 @@ +/* + * wiring_shift.c - shiftOut() function + * Part of Arduino - http://www.arduino.cc/ + * + * Copyright (c) 2005-2006 David A. Mellis + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * $Id: wiring.c 248 2007-02-03 15:36:30Z mellis $ + */ + +#include "wirish.h" + +void shiftOut(uint8 dataPin, uint8 clockPin, uint8 bitOrder, uint8 val) { + int i; + + for (i = 0; i < 8; i++) { + if (bitOrder == LSBFIRST) { + digitalWrite(dataPin, !!(val & (1 << i))); + } else { + digitalWrite(dataPin, !!(val & (1 << (7 - i)))); + } + + digitalWrite(clockPin, HIGH); + digitalWrite(clockPin, LOW); + } +} -- cgit v1.2.3 From f41c5d82be0e0cd06c82d2d6cfce2254327dd757 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Fri, 11 Mar 2011 16:37:05 -0500 Subject: Oops. --- wirish/wirish.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wirish/wirish.cpp b/wirish/wirish.cpp index 01f4507..f2fb89b 100644 --- a/wirish/wirish.cpp +++ b/wirish/wirish.cpp @@ -75,7 +75,7 @@ void init(void) { timer_init(TIMER5, 1); timer_init(TIMER8, 1); #endif - // setupUSB(); + setupUSB(); /* include the board-specific init macro */ BOARD_INIT; -- cgit v1.2.3 From 80b8f6d28f23a45a0c37275c5df775bd2e989e5e Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Fri, 11 Mar 2011 16:46:33 -0500 Subject: Cleanups; new support/gdb/gpio.gdb. --- README | 157 +++++++++++++++++++++++++++++++++------------------ docs/README | 73 ++++++++++++++---------- support/gdb/gpio.gdb | 12 ++++ 3 files changed, 158 insertions(+), 84 deletions(-) create mode 100644 support/gdb/gpio.gdb diff --git a/README b/README index b7dd521..f37999b 100644 --- a/README +++ b/README @@ -1,80 +1,127 @@ - _ _ _ _ - | (_) |__ _ __ ___ __ _ _ __ | | ___ + _ _ _ _ + | (_) |__ _ __ ___ __ _ _ __ | | ___ | | | '_ \| '_ ` _ \ / _` | '_ \| |/ _ \ | | | |_) | | | | | | (_| | |_) | | __/ |_|_|_.__/|_| |_| |_|\__,_| .__/|_|\___| - |_| by leaflabs! + |_| by LeafLabs! -The latest version of this repository can be found at: -http://github.com/leaflabs/libmaple +The latest version of this repository can be found here: -libmaple Repo Layout + http://github.com/leaflabs/libmaple + +Instructions to Compile for ARM Targets ------------------------------------------------------------------------------ -/LICENSE - Licensing and copyright information -/main.cpp.example - main.cpp is required for a successful build but is non-existant by default; - use this file as a template for building your program. By default just - blinks an LED. +A HOWTO is available in the "Unix Toolchain Quickstart" guide at: + + http://leaflabs.com/docs/unix-toolchain.html + +HTML documentation for this repository is automatically generated from +the source code and the files under the top-level /docs/ directory. +It is available online at: + + http://leaflabs.com/docs/ + +(For more information on how this documentation is generated, see +/docs/README). + +Instructions to Create a Library +------------------------------------------------------------------------------ + +TODO: fold this section into the Unix Toolchain Quickstart. + +If you have a complicated project with its own Makefile and multiple +source files, or you're using an IDE that creates its own Makefile, +you'll probably want to load libmaple from an archive (a build-time +library, not a DLL). + +To create an archive, use the "make library" target, and install +build/libmaple.a and the appropriate headers in your project's +directory. At a minimum, the header set will include libmaple.h, +util.h, and libmaple_types.h. + +Repository Layout +------------------------------------------------------------------------------ /build/ - Binary output -/libmaple/ - Lowest level definitions, routines, macros, and functions. This is the meat - of the library. + Compiler output -/wirish/ - Extra wrappers and functionality around the lower level code which is - useful for programming in the IDE. Files in here implement the "Wirish" - language, an Arduino "Wiring"-like language. +/contrib/ + + Community-contributed resources. LeafLabs doesn't maintain the + contents of this directory, so it may get stale. + +/docs/ + + Source code and build scripts for Doxygen and Sphinx + documentation. The libmaple HTML documentation is generated from + these files. It is available under http://leaflabs.com/docs/. /examples/ - What it sounds like. Copy these to /main.cpp to compile them. - -/support/ld/ - Linker scripts -/support/notes/ - Unstructured text notes that may be useful. The 45-maple.rules udev file - can be placed in /etc/udev/rules.d/ on compatible linux machines to allow - non-root access to the Maple USB device for uploading. + Example code and test programs. Copy these to /main.cpp to compile them. -Instructions to Compile for ARM Targets ------------------------------------------------------------------------------- -The best HOWTO for developing with this code is the "libmaple Unix Toolchain -Quickstart" guide at http://leaflabs.com/docs/libmaple/unix-toolchain/. +/libmaple/ -The Codesourcery g++ compiler for arm platforms is required. It is based on gcc -(they push changes into gcc a couple times a year), get the latest EABI version -from: + Lowest level definitions, routines, macros, and functions. This is + the meat of the library. The Arduino-like compatibility layer is + in /wirish/. - http://www.codesourcery.com/sgpp/lite/arm +/libraries/ -Note: grab the linux binaries for targeting the EABI platform (not to be -confused with the linux binaries /tageting/ the linux platform). + Special-purpose libraries that don't merit inclusion in the + /libmaple/ and /wirish/ directories, which are intended for + general use. Arduino-compatible libraries go here. -I unzip the archive ("TAR") version into a directory such as -~/bin/arm-gcc-codesourcery and then add the bin/ directory within that to my -$PATH in ~/.profile, resource that, then check that arm-none-eabi-gcc and -others are in my path. +/LICENSE -You will also need to have dfu-util installed and on your path (on Linux) or -compiled and placed in a folder "dfu-util/" at the same level as the -maple-library folder (macosx and windows). + Licensing and copyright information. -Write your program using /main.cpp as the entry point. Then just 'make help' -and follow the directions! +/main.cpp.example -Instructions to create a library ------------------------------------------------------------------------------- -If you have a complicated project with its own Makefile and multiple .c files, -or you're using an IDE that creates its own Makefile, you'll probably want to -load libmaple from an archive (a build-time library, not a DLL). Use the -"make library" target, and install build/libmaple.a and the appropriate headers -in your project's directory. At a minimum, the header set will include -libmaple.h, util.h, and libmaple_types.h + main.cpp is required for a successful build but is non-existent by + default; use this file as a template for building your program. By + default, just blinks an LED. + +/Makefile + + libmaple build instructions for GNU Make. + +/notes/ + + Unstructured text notes that may be useful. The 45-maple.rules + udev file can be placed in /etc/udev/rules.d/ on compatible Linux + machines to allow non-root access to the Maple USB device for + uploading. + +/README/ + + This file. + +/support/ + + Support files and scripts for various purposes. + + codeblocks/ [OBSOLETE] Config files for the Code::Blocks IDE. + gdb/ GDB scripts. + ld/ Linker scripts. + make/ Additional scripts used by the top-level Makefile. + openocd/ OpenOCD scripts for JTAG debugging. + scripts/ Miscellany. + stm32loader.py Script for uploading via the built-in USART bootloader. + +TODO + + Various undone tasks. Also see our bugtracker at + + http://code.google.com/p/leaflabs/issues/list + +/wirish/ + + Extra wrappers and functionality around the lower level code in + /libmaple/. These files implement an Arduino "Wiring"-like + library. diff --git a/docs/README b/docs/README index 326d278..7a50a54 100644 --- a/docs/README +++ b/docs/README @@ -1,16 +1,42 @@ -This directory contains the Sphinx documentation for libmaple, as well -as a Doxygen configuration file; we turn Doxygen XML output into -Sphinx documentation. You can generate HTML documentation using the -Makefile if you have make, or using make.bat from Windows. +This directory contains source files used to generate libmaple's +documentation. + +The generated documentation for the latest libmaple release is +available online in HTML form at http://leaflabs.com/docs/. The web +interface is the recommended way for users to read the documentation. + +This file contains instructions for generating the HTML files. + +About the Documentation +----------------------- + +The docs are written in Sphinx's extensions to reStructuredText +(reST). You can read more about Sphinx here: + + http://sphinx.pocoo.org/tutorial.html + +Much of the documentation is pulled out of the libmaple source code; +we use Doxygen XML output into Sphinx documentation. You can read +more about Doxygen here: + + http://doxygen.org + +We use a Sphinx plugin called Breathe to parse Doxygen's XML output +into a form usable by Sphinx. You can read more about Breathe here: + + http://michaeljones.github.com/breathe/ Documentation Build Steps ------------------------- +You first need to produce Doxygen XML output, then you can generate +the HTML documentation. + 1. You need a recent-ish version of Doxygen in your PATH: http://www.stack.nl/~dimitri/doxygen/download.html#latestsrc -2. Install breathe, which does Doxygen-to-Sphinx conversion: +2. Install Breathe, which does Doxygen-to-Sphinx conversion: Read/write version (for LeafLabs developers): @@ -37,9 +63,11 @@ Documentation Build Steps $ sudo easy_install -U Sphinx + You need Sphinx version >= 1.0.6. + 4. Before the first time you run Sphinx (and any time the Doxygen comments in the libmaple source code are changed), you'll need to - rebuild the Doxygen XML output: + build the Doxygen XML output: $ cd libmaple/docs/source $ doxygen @@ -48,36 +76,23 @@ Documentation Build Steps $ make html - (Read the Makefile for more targets). + On Windows, use the batch file make.bat instead. Reading and Modifying the Documentation --------------------------------------- -The net effect of the above is to produce Doxygen XML output (ignore -this) in libmaple/docs/doxygen/xml, and HTML documentation (this is -what you want) in libmaple/docs/build/html. - Just point your web browser at the file - libmaple/docs/build/html/index.html + /docs/build/html/index.html -it corresponds to the Sphinx file +It corresponds to the Sphinx file - libmaple/docs/source/index.rst - -All of the documentation itself lives in libmaple/docs/source/. The -directory source/_static/ is for static content (like style sheets); -source/_templates/ contains Sphinx templates (or, it would, if we had -any). - -The docs are written in Sphinx's version of reStructuredText (reST); -it's a Python thing that they use to produce the docs at -http://python.org. You can read more about Sphinx here: - - http://sphinx.pocoo.org/tutorial.html + /docs/source/index.rst -You can view the source for any generated page of documentation by -clicking the "Show Source" link in the sidebar. +The file /docs/source/conf.py is the Sphinx configuration file; you +can go read it for more information about our setup. -The file libmaple/docs/source/conf.py is the Sphinx configuration -file; you can go read it for more information about our setup. +All of the documentation which isn't pulled out of source code +comments lives in /docs/source/. The directory /docs/source/_static/ +is for static content (like style sheets); /docs/source/_templates/ +contains Sphinx templates. diff --git a/support/gdb/gpio.gdb b/support/gdb/gpio.gdb new file mode 100644 index 0000000..4376cfd --- /dev/null +++ b/support/gdb/gpio.gdb @@ -0,0 +1,12 @@ +set print pretty on + +print "GPIOA registers:" +p/x *GPIOA->regs +print "GPIOB registers:" +p/x *GPIOB->regs +print "GPIOC registers:" +p/x *GPIOC->regs +print "GPIOD registers:" +p/x *GPIOD->regs +print "AFIO registers:" +p/x *(struct afio_reg_map*)0x40010000 -- cgit v1.2.3 From c442df4d8d724076fb8cc27567c6684b91e954e8 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Fri, 11 Mar 2011 19:25:04 -0500 Subject: bitband.h cleanup --- libmaple/bitband.h | 38 ++++++++++---------------------------- 1 file changed, 10 insertions(+), 28 deletions(-) diff --git a/libmaple/bitband.h b/libmaple/bitband.h index 076335f..b817f73 100644 --- a/libmaple/bitband.h +++ b/libmaple/bitband.h @@ -35,18 +35,7 @@ #define BB_PERI_REF 0x40000000 #define BB_PERI_BASE 0x42000000 -static inline uint32* __bb_addr(void*, uint32, uint32, uint32); -static inline __io uint32* __bb_addrv(__io void*, uint32, uint32, uint32); - -/** - * @brief Obtain a pointer to the bit-band address corresponding to a - * bit in an SRAM address. - * @param address Address in the bit-banded SRAM region - * @param bit Bit in address to bit-band - */ -static inline uint32* bb_sramp(void *address, uint32 bit) { - return __bb_addr(address, bit, BB_SRAM_BASE, BB_SRAM_REF); -} +static inline __io uint32* __bb_addr(__io void*, uint32, uint32, uint32); /** * @brief Obtain a pointer to the bit-band address corresponding to a @@ -54,8 +43,8 @@ static inline uint32* bb_sramp(void *address, uint32 bit) { * @param address Address in the bit-banded SRAM region * @param bit Bit in address to bit-band */ -static inline __io uint32* bb_srampv(__io void *address, uint32 bit) { - return __bb_addrv(address, bit, BB_SRAM_BASE, BB_SRAM_REF); +static inline __io uint32* bb_sramp(__io void *address, uint32 bit) { + return __bb_addr(address, bit, BB_SRAM_BASE, BB_SRAM_REF); } /** @@ -64,20 +53,13 @@ static inline __io uint32* bb_srampv(__io void *address, uint32 bit) { * @param address Address in the bit-banded peripheral region * @param bit Bit in address to bit-band */ -static inline __io uint32* bb_peripv(__io void *address, uint32 bit) { - return __bb_addrv(address, bit, BB_PERI_BASE, BB_PERI_REF); -} - -static inline uint32* __bb_addr(void *address, - uint32 bit, - uint32 bb_base, - uint32 bb_ref) { - return (uint32*)(bb_base + ((uint32)address - bb_ref) * 32 + bit * 4); +static inline __io uint32* bb_perip(__io void *address, uint32 bit) { + return __bb_addr(address, bit, BB_PERI_BASE, BB_PERI_REF); } -static inline __io uint32* __bb_addrv(__io void *address, - uint32 bit, - uint32 bb_base, - uint32 bb_ref) { - return (__io uint32*)__bb_addr((void*)address, bit, bb_base, bb_ref); +static inline __io uint32* __bb_addr(__io void *address, + uint32 bit, + uint32 bb_base, + uint32 bb_ref) { + return (__io uint32*)(bb_base + ((uint32)address - bb_ref) * 32 + bit * 4); } -- cgit v1.2.3 From 9579e9487c2039df38cc4fd0ac2846ef07cc0947 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Fri, 11 Mar 2011 20:43:59 -0500 Subject: shiftOut(), docs fixes --- docs/source/bootloader.rst | 56 ++++++------ docs/source/lang/api/constants.rst | 8 -- docs/source/lang/api/shiftout.rst | 99 ++++++++++++++++++++ docs/source/lang/unimplemented/shiftout.rst | 136 ---------------------------- docs/source/language-index.rst | 1 - docs/source/language.rst | 9 +- wirish/io.h | 16 ++++ 7 files changed, 148 insertions(+), 177 deletions(-) create mode 100644 docs/source/lang/api/shiftout.rst delete mode 100644 docs/source/lang/unimplemented/shiftout.rst diff --git a/docs/source/bootloader.rst b/docs/source/bootloader.rst index 57833ed..cfbf545 100644 --- a/docs/source/bootloader.rst +++ b/docs/source/bootloader.rst @@ -66,7 +66,7 @@ have embedded USB support. Thus, Maple doesn’t need the extra FTDI chip. Firmware is uploaded via the standard DFU protocol (also used by iPhone and openMoko). Since DFU is a standard, there is no need for custom software running on the host to upload the firmware. Any DFU -compliant program will work. The maple ide is based around +compliant program will work. The Maple IDE is based around :command:`dfu-util`, openMoko’s DFU utility. Using DFU came at a cost, however. The USB port must additionally implement a separate serial port at the same time (we use the CDC ACM class for serial @@ -87,11 +87,11 @@ important what this means, except for two things. 1. Four drivers were necessary to make everything work. 2. IAD is not supported by OS X. -Mac, on the other hand, only supported Compound USB, a different trick -that is not supported by Windows. While a perpetual background +Mac OS X, on the other hand, only supported Compound USB, a different +trick that is not supported by Windows. While a perpetual background bootloader was attractive, it became clear, after much toiling, we -were going to have to write some custom drivers across several -platforms to make everything work this way. +were going to have to write custom drivers across several platforms to +make everything work this way. .. _bootloader-rev3: @@ -103,22 +103,21 @@ Arduino. In Rev 3, the device resets into bootloader mode, which stays alive for a few moments to receive commands, and then jumps to user code. The bootloader is implemented as a DFU device -- just a DFU device, no serial port. This requires one driver for Windows -(:file:`drivers/mapleDrv/dfu` in the Windows IDE directory). As part -of the :ref:`libmaple ` library, user code is automatically -supplied with serial support via some behind the scenes work that -happens automatically when you compile (``setupUSB()`` is appended to -``setup()``). This user mode code only implements a CDC ACM class USB -device, giving you functions like ``Usb.print()``. Separating these -two modes fixed the driver issue, required no complicated compound USB -device nonsense, and works well across platforms, requiring only two -drivers (serial and DFU) on Windows. +(:file:`drivers/mapleDrv/dfu` in the Windows IDE directory). + +As part of the :ref:`libmaple ` library, user code is +automatically supplied with serial support via some behind the scenes +work (``setupUSB()`` is called from ``init()``). This user mode code +only implements a CDC ACM class USB device, giving you functions like +:ref:`SerialUSB.read() `. Separating these two +modes fixed the driver issues and works well across platforms, +requiring only two drivers (serial and DFU) on Windows. However, it is no longer possible to upload code at will, since there -is no bootloader quietly listening in the background. Instead you have -to reset the board, then initiate a DFU transaction. This reset is -performed automatically by the IDE by sending a command over the USB -serial port. You can generate this reset on your own using a Python -script or some other scheme. All you need do is: +is no bootloader quietly listening in the background. Instead, you +must reset the board, then initiate a DFU transaction. The IDE +performs this reset automatically by performing a special sequence of +changes on the USB serial port: 1. Pulse DTR (high and then low, so that you've created a negative edge) @@ -128,15 +127,16 @@ script or some other scheme. All you need do is: negative edge, rather than just ensuring DTR is low. After the reset, the host OS takes a few moments (.5-2 seconds) to -re-enumerate the device as DFU. This delay is unpredictable, and its -the reason the bootloader on Maple Rev3 stays alive for so -long. Sometimes the bootloader was exiting before the OS had even -enumerated the device! Once in bootloader mode, however, -:command:`dfu-util` uploads your sketch into either flash or RAM (DFU -alternate setting 0 or 1, respectively) and resets the board again. -This time, however, no DFU transaction is initiated, and the -bootloader gives way to user code, closing down the DFU pipe and -bringing up the USB serial. +re-enumerate the device as DFU. This delay is unpredictable, and is +the reason the bootloader on Maple Rev 3/Rev 5 stays alive for so +long. (Sometimes, the bootloader was exiting before the OS had even +enumerated the device.) + +Once in bootloader mode, :command:`dfu-util` uploads your sketch into +either flash or RAM (DFU alternate setting 0 or 1, respectively) and +resets the board again. This time, however, no DFU transaction is +initiated, and the bootloader gives way to user code, closing down the +DFU pipe and bringing up the USB serial port. .. .. _bootloader-rev6: diff --git a/docs/source/lang/api/constants.rst b/docs/source/lang/api/constants.rst index 72738b8..2e968e7 100644 --- a/docs/source/lang/api/constants.rst +++ b/docs/source/lang/api/constants.rst @@ -61,14 +61,6 @@ pin is configured as an ``INPUT`` (using :ref:`pinMode() `, the microcontroller will report ``HIGH`` if a voltage of 3 volts or more is present at the pin. -.. TODO? Following seems false; check it out sometime, leave out for now: - -.. A pin may also be configured as an ``INPUT`` with ``pinMode()``, and -.. subsequently made ``HIGH`` with :ref:`digitalWrite() -.. `, this will set the internal pullup resistors, -.. which will *steer* the input pin to a HIGH reading unless it is pulled -.. LOW by external circuitry. - When a pin is configured to ``OUTPUT`` with pinMode, and set to ``HIGH`` with :ref:`digitalWrite() `, the pin is at 3.3 volts. In this state it can *source* current, e.g. light an LED diff --git a/docs/source/lang/api/shiftout.rst b/docs/source/lang/api/shiftout.rst new file mode 100644 index 0000000..1d9ba12 --- /dev/null +++ b/docs/source/lang/api/shiftout.rst @@ -0,0 +1,99 @@ +.. highlight:: cpp + +.. _lang-shiftout: + +shiftOut() +========== + +Shift out a byte of data, one bit at a time. + +.. contents:: Contents + :local: + +Library Documentation +--------------------- + +.. doxygenfunction:: shiftOut + +Discussion +---------- + +This is a software implementation. There is also a hardware :ref:`SPI +` library available which will be faster and consume less CPU +cycles than this function. + +Note that the ``dataPin`` and ``clockPin`` must already be configured +to :ref:`OUTPUT ` mode by a call to +:ref:`pinMode() `. + +Also note that since shiftOut() outputs 1 byte (8 bits) at a time, it +requires multiple steps to output values larger than 255. + +Examples +-------- + +To use these examples, replace ``dataPin`` and ``clockPin`` with the +numbers of the pins you want to use:: + + /* MSBFIRST example */ + + uint16 data = 500; + // shift out high byte + shiftOut(dataPin, clockPin, MSBFIRST, (data >> 8)); + // shift out low byte + shiftOut(dataPin, clockPin, MSBFIRST, data); + + /* LSBFIRST serial */ + + data = 500; + // shift out low byte + shiftOut(dataPin, clockPin, LSBFIRST, data); + // shift out high byte + shiftOut(dataPin, clockPin, LSBFIRST, (data >> 8)); + +Arduino Tutorial Example +------------------------ + +This Arduino example runs unmodified on the Maple. For accompanying +circuit, see the `tutorial on controlling a 74HC595 shift register +`_. + +:: + + //**************************************************************// + // Name : shiftOutCode, Hello World // + // Author : Carlyn Maw, Tom Igoe // + // Date : 25 Oct, 2006 // + // Version : 1.0 // + // Notes : Code for using a 74HC595 Shift Register // + // : to count from 0 to 255 // + //**************************************************************// + + // Pin connected to ST_CP of 74HC595 + int latchPin = 8; + // Pin connected to SH_CP of 74HC595 + int clockPin = 12; + // Pin connected to DS of 74HC595 + int dataPin = 11; + + void setup() { + // Set pins to output because they are addressed in the main loop + pinMode(latchPin, OUTPUT); + pinMode(clockPin, OUTPUT); + pinMode(dataPin, OUTPUT); + } + + void loop() { + // Count up routine + for (int j = 0; j < 256; j++) { + // Ground latchPin and hold low for as long as you are transmitting + digitalWrite(latchPin, LOW); + shiftOut(dataPin, clockPin, LSBFIRST, j); + // Return the latch pin high to signal chip that it + // no longer needs to listen for information + digitalWrite(latchPin, HIGH); + delay(1000); + } + } + +.. include:: /lang/cc-attribution.txt diff --git a/docs/source/lang/unimplemented/shiftout.rst b/docs/source/lang/unimplemented/shiftout.rst deleted file mode 100644 index ff3852f..0000000 --- a/docs/source/lang/unimplemented/shiftout.rst +++ /dev/null @@ -1,136 +0,0 @@ -.. _lang-shiftout: - -shiftOut() -========== - -Description ------------ - -Shifts out a byte of data one bit at a time. Starts from either the -most (i.e. the leftmost) or least (rightmost) significant bit. Each -bit is written in turn to a data pin, after which a clock pin is -pulsed to indicate that the bit is available. - - - -This is a software implementation; Arduino (as of 0019) also -provides an `SPI library `_ -that uses the hardware implementation. - - - -Syntax ------- - -shiftOut(dataPin, clockPin, bitOrder, value) - - - -Parameters ----------- - -dataPin: the pin on which to output each bit (*int*) - - - -clockPin: the pin to toggle once the **dataPin** has been set to -the correct value (*int*) - - - -bitOrder: which order to shift out the bits; either **MSBFIRST** or -**LSBFIRST**. -(Most Significant Bit First, or, Least Significant Bit First) - - - -value: the data to shift out. (*byte*) - - - -Returns -------- - -None - - - -Note ----- - -The **dataPin** and **clockPin** must already be configured as -outputs by a call to -`pinMode `_\ (). - - - -**shiftOut** is currently written to output 1 byte (8 bits) so it -requires a two step operation to output values larger than 255. - -:: - - // Do this for MSBFIRST serial - int data = 500; - // shift out highbyte - shiftOut(dataPin, clock, MSBFIRST, (data >> 8)); - // shift out lowbyte - shiftOut(data, clock, MSBFIRST, data); - - // Or do this for LSBFIRST serial - data = 500; - // shift out lowbyte - shiftOut(dataPin, clock, LSBFIRST, data); - // shift out highbyte - shiftOut(dataPin, clock, LSBFIRST, (data >> 8)); - - - -Example -------- - -*For accompanying circuit, see the `tutorial on controlling a 74HC595 shift register `_.* - - - -:: - - //**************************************************************// - // Name : shiftOutCode, Hello World // - // Author : Carlyn Maw,Tom Igoe // - // Date : 25 Oct, 2006 // - // Version : 1.0 // - // Notes : Code for using a 74HC595 Shift Register // - // : to count from 0 to 255 // - //**************************************************************** - - //Pin connected to ST_CP of 74HC595 - int latchPin = 8; - //Pin connected to SH_CP of 74HC595 - int clockPin = 12; - ////Pin connected to DS of 74HC595 - int dataPin = 11; - - void setup() { - //set pins to output because they are addressed in the main loop - pinMode(latchPin, OUTPUT); - pinMode(clockPin, OUTPUT); - pinMode(dataPin, OUTPUT); - } - - void loop() { - //count up routine - for (int j = 0; j < 256; j++) { - //ground latchPin and hold low for as long as you are transmitting - digitalWrite(latchPin, LOW); - shiftOut(dataPin, clockPin, LSBFIRST, j); - //return the latch pin high to signal chip that it - //no longer needs to listen for information - digitalWrite(latchPin, HIGH); - delay(1000); - } - } - - - - -.. include:: /lang/cc-attribution.txt diff --git a/docs/source/language-index.rst b/docs/source/language-index.rst index 3c55c33..c949988 100644 --- a/docs/source/language-index.rst +++ b/docs/source/language-index.rst @@ -33,7 +33,6 @@ programmers familiar with the Arduino language. lang/unimplemented/notone.rst lang/unimplemented/pulsein.rst - lang/unimplemented/shiftout.rst lang/unimplemented/stringclass.rst lang/unimplemented/stringobject.rst lang/unimplemented/tone.rst diff --git a/docs/source/language.rst b/docs/source/language.rst index b2f4650..d340aec 100644 --- a/docs/source/language.rst +++ b/docs/source/language.rst @@ -61,7 +61,7 @@ A more exhaustive index is available at the :ref:`language-index`. | |* :ref:`boolean ` (1 byte) | | |* :ref:`{} (curly braces) | |* noTone(): TODO | | ` |* :ref:`char ` (1 byte) | | -| | |* shiftOut(): TODO | +| | |* :ref:`shiftOut() ` | |* :ref:`// (single-line comment) |* :ref:`unsigned char | | | ` | ` (1 byte) |* pulseIn(): TODO | | | | | @@ -187,11 +187,13 @@ A more exhaustive index is available at the :ref:`language-index`. | | | | +--------------------------------------------+----------------------------------------------+---------------------------------------------------+ +.. _language-assert: + ``ASSERT(...)`` --------------- The ``ASSERT()`` function can be very useful for basic program -debugging. The function accepts a boolean; for example:: +debugging. It accepts a boolean; for example:: ASSERT(state == WAIT); @@ -255,11 +257,10 @@ Unimplemented Arduino Features The following Wiring/Arduino features are currently unimplemented on the Maple. However, they will be present in future versions: +- `tone() `_ - `noTone() `_ - `pulseIn() `_ -- `shiftOut() `_ - `String `_ -- `tone() `_ .. _our reference page: http://leaflabs.com/docs/external-interrupts/ diff --git a/wirish/io.h b/wirish/io.h index d2e4d2d..8dad1d1 100644 --- a/wirish/io.h +++ b/wirish/io.h @@ -216,5 +216,21 @@ uint8 isButtonPressed(); */ uint8 waitForButtonPress(uint32 timeout_millis); +/** + * Shift out a byte of data, one bit at a time. + * + * This function starts at either the most significant or least + * significant bit in a byte value, and shifts out each byte in order + * onto a data pin. After each bit is written to the data pin, a + * separate clock pin is pulsed to indicate that the new bit is + * available. + * + * @param dataPin Pin to shift data out on + * @param clockPin Pin to pulse after each bit is shifted out + * @param bitOrder Either MSBFIRST (big-endian) or LSBFIRST (little-endian). + * @param val Value to shift out + */ +void shiftOut(uint8 dataPin, uint8 clockPin, uint8 bitOrder, uint8 value); + #endif -- cgit v1.2.3 From e3fae0984dab4f1044ea3ffc1aa41b2df12370b2 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Sat, 12 Mar 2011 23:28:53 -0500 Subject: RCC refactor, bugfixes --- libmaple/adc.c | 4 +- libmaple/adc.h | 6 +- libmaple/bkp.c | 4 +- libmaple/dac.c | 4 + libmaple/dac.h | 4 + libmaple/exti.c | 18 +- libmaple/gpio.c | 2 +- libmaple/rcc.c | 200 ++++++++++++-------- libmaple/rcc.h | 541 +++++++++++++++++++++++++++++++++++++++++++----------- wirish/boards.cpp | 2 +- wirish/wirish.cpp | 2 +- 11 files changed, 575 insertions(+), 212 deletions(-) diff --git a/libmaple/adc.c b/libmaple/adc.c index 9626a40..3d38596 100644 --- a/libmaple/adc.c +++ b/libmaple/adc.c @@ -126,8 +126,8 @@ void adc_set_sample_rate(const adc_dev *dev, adc_smp_rate smp_rate) { * @param dev adc device */ static void adc_calibrate(const adc_dev *dev) { - __io uint32 *rstcal_bit = bb_peripv(&(dev->regs->CR2), 3); - __io uint32 *cal_bit = bb_peripv(&(dev->regs->CR2), 2); + __io uint32 *rstcal_bit = bb_perip(&(dev->regs->CR2), 3); + __io uint32 *cal_bit = bb_perip(&(dev->regs->CR2), 2); *rstcal_bit = 1; while (*rstcal_bit) diff --git a/libmaple/adc.h b/libmaple/adc.h index 4811dbc..53ef032 100644 --- a/libmaple/adc.h +++ b/libmaple/adc.h @@ -175,7 +175,7 @@ static inline uint32 adc_read(const adc_dev *dev, uint8 channel) { * @param enable If 1, conversion on external events is enabled, 0 to disable */ static inline void adc_set_exttrig(const adc_dev *dev, uint8 enable) { - *bb_peripv(&dev->regs->CR2, 20) = !!enable; + *bb_perip(&dev->regs->CR2, 20) = !!enable; } /** @@ -183,7 +183,7 @@ static inline void adc_set_exttrig(const adc_dev *dev, uint8 enable) { * @param dev ADC device to enable */ static inline void adc_enable(const adc_dev *dev) { - *bb_peripv(&dev->regs->CR2, 0) = 1; + *bb_perip(&dev->regs->CR2, 0) = 1; } /** @@ -191,7 +191,7 @@ static inline void adc_enable(const adc_dev *dev) { * @param dev ADC device to disable */ static inline void adc_disable(const adc_dev *dev) { - *bb_peripv(&dev->regs->CR2, 0) = 0; + *bb_perip(&dev->regs->CR2, 0) = 0; } /** diff --git a/libmaple/bkp.c b/libmaple/bkp.c index b152069..aaccb1f 100644 --- a/libmaple/bkp.c +++ b/libmaple/bkp.c @@ -57,14 +57,14 @@ void bkp_init(void) { * @see bkp_init() */ void bkp_enable_writes(void) { - *bb_peripv(&PWR_BASE->CR, PWR_CR_DBP) = 1; + *bb_perip(&PWR_BASE->CR, PWR_CR_DBP) = 1; } /** * Disable write access to the backup registers. */ void bkp_disable_writes(void) { - *bb_peripv(&PWR_BASE->CR, PWR_CR_DBP) = 0; + *bb_perip(&PWR_BASE->CR, PWR_CR_DBP) = 0; } /** diff --git a/libmaple/dac.c b/libmaple/dac.c index ef3a9f9..f0bdbcd 100644 --- a/libmaple/dac.c +++ b/libmaple/dac.c @@ -26,6 +26,8 @@ #include "gpio.h" #include "dac.h" +#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) + /** * @brief DAC peripheral routines. */ @@ -108,3 +110,5 @@ void dac_disable_channel(uint8 channel) { break; } } + +#endif diff --git a/libmaple/dac.h b/libmaple/dac.h index c897bb2..ee8a4e7 100644 --- a/libmaple/dac.h +++ b/libmaple/dac.h @@ -32,6 +32,8 @@ #ifndef _DAC_H_ #define _DAC_H_ +#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) + #include "rcc.h" #ifdef __cplusplus @@ -149,4 +151,6 @@ void dac_disable_channel(uint8 channel); } // extern "C" #endif +#endif /* STM32_HIGH_DENSITY, STM32_XL_DENSITY */ + #endif diff --git a/libmaple/exti.c b/libmaple/exti.c index 8177e1e..7f56712 100644 --- a/libmaple/exti.c +++ b/libmaple/exti.c @@ -98,14 +98,14 @@ void exti_attach_interrupt(afio_exti_num num, /* Set trigger mode */ switch (mode) { case EXTI_RISING: - *bb_peripv(&EXTI_BASE->RTSR, num) = 1; + *bb_perip(&EXTI_BASE->RTSR, num) = 1; break; case EXTI_FALLING: - *bb_peripv(&EXTI_BASE->FTSR, num) = 1; + *bb_perip(&EXTI_BASE->FTSR, num) = 1; break; case EXTI_RISING_FALLING: - *bb_peripv(&EXTI_BASE->RTSR, num) = 1; - *bb_peripv(&EXTI_BASE->FTSR, num) = 1; + *bb_perip(&EXTI_BASE->RTSR, num) = 1; + *bb_perip(&EXTI_BASE->FTSR, num) = 1; break; } @@ -113,7 +113,7 @@ void exti_attach_interrupt(afio_exti_num num, afio_exti_select(num, port); /* Unmask external interrupt request */ - *bb_peripv(&EXTI_BASE->IMR, num) = 1; + *bb_perip(&EXTI_BASE->IMR, num) = 1; /* Enable the interrupt line */ enable_irq(num); @@ -126,11 +126,11 @@ void exti_attach_interrupt(afio_exti_num num, */ void exti_detach_interrupt(afio_exti_num num) { /* First, mask the interrupt request */ - *bb_peripv(&EXTI_BASE->IMR, num) = 0; + *bb_perip(&EXTI_BASE->IMR, num) = 0; /* Then, clear the trigger selection registers */ - *bb_peripv(&EXTI_BASE->FTSR, num) = 0; - *bb_peripv(&EXTI_BASE->RTSR, num) = 0; + *bb_perip(&EXTI_BASE->FTSR, num) = 0; + *bb_perip(&EXTI_BASE->RTSR, num) = 0; /* Next, disable the IRQ, unless it's multiplexed and there are * other active external interrupts on the same IRQ line */ @@ -210,7 +210,7 @@ void __irq_exti15_10(void) { */ static inline void clear_pending(uint32 exti_num) { - *bb_peripv(&EXTI_BASE->PR, exti_num) = 1; + *bb_perip(&EXTI_BASE->PR, exti_num) = 1; /* If the pending bit is cleared as the last instruction in an ISR, * it won't actually be cleared in time and the ISR will fire again. * Insert a 2-cycle buffer to allow it to take effect. */ diff --git a/libmaple/gpio.c b/libmaple/gpio.c index b08be12..90be033 100644 --- a/libmaple/gpio.c +++ b/libmaple/gpio.c @@ -61,7 +61,7 @@ static gpio_dev gpiod = { /** GPIO port D device. */ gpio_dev *GPIOD = &gpiod; -#ifdef STM32_HIGH_ +#ifdef STM32_HIGH_DENSITY static gpio_dev gpioe = { .regs = GPIOE_BASE, .clk_id = RCC_GPIOE diff --git a/libmaple/rcc.c b/libmaple/rcc.c index 2841af3..e49382c 100644 --- a/libmaple/rcc.c +++ b/libmaple/rcc.c @@ -23,97 +23,115 @@ *****************************************************************************/ /** - * @brief Implements pretty much only the basic clock setup on the - * stm32, clock enable/disable and peripheral reset commands. + * @file rcc.c + * @brief Clock setup, peripheral enable and reset routines. */ #include "libmaple.h" #include "flash.h" #include "rcc.h" +#include "bitband.h" -enum { +typedef enum clock_domain { APB1, APB2, AHB -}; +} clock_domain; struct rcc_dev_info { - const uint8 clk_domain; + const clock_domain clk_domain; const uint8 line_num; }; /* device descriptor tables */ -static const struct rcc_dev_info rcc_dev_table[] = { - [RCC_GPIOA] = { .clk_domain = APB2, .line_num = 2 }, - [RCC_GPIOB] = { .clk_domain = APB2, .line_num = 3 }, - [RCC_GPIOC] = { .clk_domain = APB2, .line_num = 4 }, - [RCC_GPIOD] = { .clk_domain = APB2, .line_num = 5 }, - [RCC_GPIOE] = { .clk_domain = APB2, .line_num = 6 }, // High-density only - [RCC_GPIOF] = { .clk_domain = APB2, .line_num = 7 }, // High-density only - [RCC_GPIOG] = { .clk_domain = APB2, .line_num = 8 }, // High-density only - [RCC_AFIO] = { .clk_domain = APB2, .line_num = 0 }, - [RCC_ADC1] = { .clk_domain = APB2, .line_num = 9 }, - [RCC_ADC2] = { .clk_domain = APB2, .line_num = 10 }, - [RCC_ADC3] = { .clk_domain = APB2, .line_num = 15 }, - [RCC_USART1] = { .clk_domain = APB2, .line_num = 14 }, - [RCC_USART2] = { .clk_domain = APB1, .line_num = 17 }, - [RCC_USART3] = { .clk_domain = APB1, .line_num = 18 }, - [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 }, - [RCC_TIMER4] = { .clk_domain = APB1, .line_num = 2 }, - [RCC_TIMER5] = { .clk_domain = APB1, .line_num = 3 }, // High-density only - [RCC_TIMER6] = { .clk_domain = APB1, .line_num = 4 }, // High-density only - [RCC_TIMER7] = { .clk_domain = APB1, .line_num = 5 }, // High-density only - [RCC_TIMER8] = { .clk_domain = APB2, .line_num = 13 }, // High-density only - [RCC_SPI1] = { .clk_domain = APB2, .line_num = 12 }, - [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 = 29 }, // High-density only - [RCC_DMA1] = { .clk_domain = AHB, .line_num = 0 }, - [RCC_DMA2] = { .clk_domain = AHB, .line_num = 1 }, // High-density only - [RCC_PWR] = { .clk_domain = APB1, .line_num = 28}, - [RCC_BKP] = { .clk_domain = APB1, .line_num = 27} +static const __attr_flash struct rcc_dev_info rcc_dev_table[] = { + [RCC_SRAM] = { .clk_domain = AHB, .line_num = 2 }, + [RCC_GPIOA] = { .clk_domain = APB2, .line_num = 2 }, + [RCC_GPIOB] = { .clk_domain = APB2, .line_num = 3 }, + [RCC_GPIOC] = { .clk_domain = APB2, .line_num = 4 }, + [RCC_GPIOD] = { .clk_domain = APB2, .line_num = 5 }, + [RCC_AFIO] = { .clk_domain = APB2, .line_num = 0 }, + [RCC_ADC1] = { .clk_domain = APB2, .line_num = 9 }, + [RCC_ADC2] = { .clk_domain = APB2, .line_num = 10 }, + [RCC_USART1] = { .clk_domain = APB2, .line_num = 14 }, + [RCC_USART2] = { .clk_domain = APB1, .line_num = 17 }, + [RCC_USART3] = { .clk_domain = APB1, .line_num = 18 }, + [RCC_TIMER1] = { .clk_domain = APB2, .line_num = 11 }, + [RCC_TIMER2] = { .clk_domain = APB1, .line_num = 0 }, + [RCC_TIMER3] = { .clk_domain = APB1, .line_num = 1 }, + [RCC_TIMER4] = { .clk_domain = APB1, .line_num = 2 }, + [RCC_SPI1] = { .clk_domain = APB2, .line_num = 12 }, + [RCC_SPI2] = { .clk_domain = APB1, .line_num = 14 }, + [RCC_DMA1] = { .clk_domain = AHB, .line_num = 0 }, + [RCC_PWR] = { .clk_domain = APB1, .line_num = 28 }, + [RCC_BKP] = { .clk_domain = APB1, .line_num = 27 }, + [RCC_CAN] = { .clk_domain = APB1, .line_num = 25 }, + [RCC_USB] = { .clk_domain = APB1, .line_num = 23 }, + [RCC_I2C1] = { .clk_domain = APB1, .line_num = 22 }, + [RCC_I2C2] = { .clk_domain = APB1, .line_num = 21 }, + [RCC_CRC] = { .clk_domain = AHB, .line_num = 6 }, + [RCC_WWDG] = { .clk_domain = APB2, .line_num = 11 }, + [RCC_FLITF] = { .clk_domain = AHB, .line_num = 4 }, +#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) + [RCC_SDIO] = { .clk_domain = AHB, .line_num = 10 }, + [RCC_FSMC] = { .clk_domain = AHB, .line_num = 8 }, + [RCC_GPIOE] = { .clk_domain = APB2, .line_num = 6 }, + [RCC_GPIOF] = { .clk_domain = APB2, .line_num = 7 }, + [RCC_GPIOG] = { .clk_domain = APB2, .line_num = 8 }, + [RCC_ADC3] = { .clk_domain = APB2, .line_num = 15 }, + [RCC_UART4] = { .clk_domain = APB1, .line_num = 19 }, + [RCC_UART5] = { .clk_domain = APB1, .line_num = 20 }, + [RCC_TIMER5] = { .clk_domain = APB1, .line_num = 3 }, + [RCC_TIMER6] = { .clk_domain = APB1, .line_num = 4 }, + [RCC_TIMER7] = { .clk_domain = APB1, .line_num = 5 }, + [RCC_TIMER8] = { .clk_domain = APB2, .line_num = 13 }, + [RCC_DAC] = { .clk_domain = APB1, .line_num = 29 }, + [RCC_DMA2] = { .clk_domain = AHB, .line_num = 1 }, + [RCC_SPI3] = { .clk_domain = APB1, .line_num = 15 }, +#endif +#ifdef STM32_XL_DENSITY + [RCC_TIMER9] = { .clk_domain = APB2, .line_num = 19 }, + [RCC_TIMER10] = { .clk_domain = APB2, .line_num = 20 }, + [RCC_TIMER11] = { .clk_domain = APB2, .line_num = 21 }, + [RCC_TIMER12] = { .clk_domain = APB1, .line_num = 6 }, + [RCC_TIMER13] = { .clk_domain = APB1, .line_num = 7 }, + [RCC_TIMER14] = { .clk_domain = APB1, .line_num = 8 }, +#endif }; /** * @brief Initialize the clock control system. Initializes the system * clock source to use the PLL driven by an external oscillator * @param sysclk_src system clock source, must be PLL - * @param pll_src pll clock source, must be HSE + * @param pll_src pll clock source, must be RCC_CFGR_PLLSRC_HSE * @param pll_mul pll multiplier */ void rcc_clk_init(uint32 sysclk_src, uint32 pll_src, uint32 pll_mul) { + uint32 cfgr; + /* Assume that we're going to clock the chip off the PLL, fed by * the HSE */ ASSERT(sysclk_src == RCC_CLKSRC_PLL && - pll_src == RCC_PLLSRC_HSE); - - uint32 cfgr = 0; - uint32 cr = RCC_READ_CR(); + pll_src == RCC_CFGR_PLLSRC_HSE); - cfgr = (pll_src | pll_mul); - RCC_WRITE_CFGR(cfgr); + RCC_BASE->CFGR = pll_src | pll_mul; - /* Turn on the HSE */ - cr |= RCC_CR_HSEON; - RCC_WRITE_CR(cr); - while (!(RCC_READ_CR() & RCC_CR_HSERDY)) + /* Turn on the HSE */ + *bb_perip(&RCC_BASE->CR, RCC_CR_HSEON_BIT) = 1; + while (!(*bb_perip(&RCC_BASE->CR, RCC_CR_HSERDY_BIT))) ; - /* Now the PLL */ - cr |= RCC_CR_PLLON; - RCC_WRITE_CR(cr); - while (!(RCC_READ_CR() & RCC_CR_PLLRDY)) + /* Now the PLL */ + *bb_perip(&RCC_BASE->CR, RCC_CR_PLLON_BIT) = 1; + while (!(*bb_perip(&RCC_BASE->CR, RCC_CR_PLLRDY_BIT))) ; /* Finally, let's switch over to the PLL */ + cfgr = RCC_BASE->CFGR; cfgr &= ~RCC_CFGR_SW; cfgr |= RCC_CFGR_SW_PLL; - RCC_WRITE_CFGR(cfgr); - while ((RCC_READ_CFGR() & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) + RCC_BASE->CFGR = cfgr; + while ((RCC_BASE->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) ; } @@ -121,16 +139,23 @@ void rcc_clk_init(uint32 sysclk_src, uint32 pll_src, uint32 pll_mul) { * @brief Turn on the clock line on a device * @param device Clock ID of the device to turn on. */ -void rcc_clk_enable(rcc_clk_id device) { - static const uint32 enable_regs[] = { - [APB1] = RCC_APB1ENR, - [APB2] = RCC_APB2ENR, - [AHB] = RCC_AHBENR, - }; - - uint8 clk_domain = rcc_dev_table[device].clk_domain; - - __set_bits(enable_regs[clk_domain], BIT(rcc_dev_table[device].line_num)); +void rcc_clk_enable(rcc_clk_id id) { + uint8 lnum = rcc_dev_table[id].line_num; + __io uint32 *enr; + + switch(rcc_dev_table[id].clk_domain) { + case APB1: + enr = &RCC_BASE->APB1ENR; + break; + case APB2: + enr = &RCC_BASE->APB2ENR; + break; + case AHB: + enr = &RCC_BASE->AHBENR; + break; + } + + *bb_perip(enr, lnum) = 1; } /** @@ -138,7 +163,7 @@ void rcc_clk_enable(rcc_clk_id device) { * @param prescaler prescaler to set * @param divider prescaler divider */ -void rcc_set_prescaler(uint32 prescaler, uint32 divider) { +void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider) { static const uint32 masks[] = { [RCC_PRESCALER_AHB] = RCC_CFGR_HPRE, [RCC_PRESCALER_APB1] = RCC_CFGR_PPRE1, @@ -146,26 +171,39 @@ void rcc_set_prescaler(uint32 prescaler, uint32 divider) { [RCC_PRESCALER_USB] = RCC_CFGR_USBPRE, [RCC_PRESCALER_ADC] = RCC_CFGR_ADCPRE, }; + uint32 cfgr; - uint32 cfgr = RCC_READ_CFGR(); - + cfgr = RCC_BASE->CFGR; cfgr &= ~masks[prescaler]; cfgr |= divider; - RCC_WRITE_CFGR(cfgr); + RCC_BASE->CFGR = cfgr; } /** - * @brief reset a device - * @param device Clock ID of the device to reset. + * @brief Reset a device + * @param device Clock ID of the device to reset; the device must be + * on APB1 or APB2. */ -void rcc_reset_dev(rcc_clk_id device) { - static const uint32 reset_regs[] = { - [APB1] = RCC_APB1RSTR, - [APB2] = RCC_APB2RSTR, - }; - - uint8 clk_domain = rcc_dev_table[device].clk_domain; - - __set_bits(reset_regs[clk_domain], BIT(rcc_dev_table[device].line_num)); - __clear_bits(reset_regs[clk_domain], BIT(rcc_dev_table[device].line_num)); +void rcc_reset_dev(rcc_clk_id id) { + uint8 lnum = rcc_dev_table[id].line_num; + __io uint32 *rstr = 0; + + switch (rcc_dev_table[id].clk_domain) { + case APB1: + rstr = &RCC_BASE->APB1RSTR; + break; + case APB2: + rstr = &RCC_BASE->APB2RSTR; + break; + case AHB: + ASSERT(0); + break; + } + + if (rstr == 0) { + return; + } + + *bb_perip(rstr, lnum) = 1; + *bb_perip(rstr, lnum) = 0; } diff --git a/libmaple/rcc.h b/libmaple/rcc.h index 8697e01..83b34ed 100644 --- a/libmaple/rcc.h +++ b/libmaple/rcc.h @@ -24,7 +24,7 @@ /** * @file rcc.h - * @brief reset and clock control definitions and prototypes + * @brief Reset and clock control (RCC) definitions and prototypes */ #include "libmaple_types.h" @@ -36,78 +36,451 @@ extern "C"{ #endif -/* registers */ -#define RCC_BASE 0x40021000 -#define RCC_CR (RCC_BASE + 0x0) -#define RCC_CFGR (RCC_BASE + 0x4) -#define RCC_CIR (RCC_BASE + 0x8) -#define RCC_APB2RSTR (RCC_BASE + 0xC) -#define RCC_APB1RSTR (RCC_BASE + 0x10) -#define RCC_AHBENR (RCC_BASE + 0x14) -#define RCC_APB2ENR (RCC_BASE + 0x18) -#define RCC_APB1ENR (RCC_BASE + 0x1C) -#define RCC_BDCR (RCC_BASE + 0x20) -#define RCC_CSR (RCC_BASE + 0x24) -#define RCC_AHBSTR (RCC_BASE + 0x28) -#define RCC_CFGR2 (RCC_BASE + 0x2C) - -#define RCC_CFGR_USBPRE (0x1 << 22) -#define RCC_CFGR_ADCPRE (0x3 << 14) -#define RCC_CFGR_PPRE1 (0x7 << 8) -#define RCC_CFGR_PPRE2 (0x7 << 11) -#define RCC_CFGR_HPRE (0xF << 4) -#define RCC_CFGR_PLLSRC (0x1 << 16) - -#define RCC_CFGR_SWS (0x3 << 2) -#define RCC_CFGR_SWS_PLL (0x2 << 2) -#define RCC_CFGR_SWS_HSE (0x1 << 2) - -#define RCC_CFGR_SW (0x3 << 0) -#define RCC_CFGR_SW_PLL (0x2 << 0) -#define RCC_CFGR_SW_HSE (0x1 << 0) - -/* CR status bits */ -#define RCC_CR_HSEON (0x1 << 16) -#define RCC_CR_HSERDY (0x1 << 17) -#define RCC_CR_PLLON (0x1 << 24) -#define RCC_CR_PLLRDY (0x1 << 25) - -#define RCC_WRITE_CFGR(val) __write(RCC_CFGR, val) -#define RCC_READ_CFGR() __read(RCC_CFGR) - -#define RCC_WRITE_CR(val) __write(RCC_CR, val) -#define RCC_READ_CR() __read(RCC_CR) - -/* sysclk source */ +/** RCC register map type */ +typedef struct rcc_reg_map { + __io uint32 CR; /**< Clock control register */ + __io uint32 CFGR; /**< Clock configuration register */ + __io uint32 CIR; /**< Clock interrupt register */ + __io uint32 APB2RSTR; /**< APB2 peripheral reset register */ + __io uint32 APB1RSTR; /**< APB1 peripheral reset register */ + __io uint32 AHBENR; /**< AHB peripheral clock enable register */ + __io uint32 APB2ENR; /**< APB2 peripheral clock enable register */ + __io uint32 APB1ENR; /**< APB1 peripheral clock enable register */ + __io uint32 BDCR; /**< Backup domain control register */ + __io uint32 CSR; /**< Control/status register */ +} rcc_reg_map; + +/* + * RCC register map base address + */ + +#define RCC_BASE ((rcc_reg_map*)0x40021000) + +/* + * RCC register bit definitions + */ + +/* Clock control register */ + +#define RCC_CR_PLLRDY_BIT 25 +#define RCC_CR_PLLON_BIT 24 +#define RCC_CR_CSSON_BIT 19 +#define RCC_CR_HSEBYP_BIT 18 +#define RCC_CR_HSERDY_BIT 17 +#define RCC_CR_HSEON_BIT 16 +#define RCC_CR_HSIRDY_BIT 1 +#define RCC_CR_HSION_BIT 0 + +#define RCC_CR_PLLRDY BIT(RCC_CR_PLLRDY_BIT) +#define RCC_CR_PLLON BIT(RCC_CR_PLLON_BIT) +#define RCC_CR_CSSON BIT(RCC_CR_CSSON_BIT) +#define RCC_CR_HSEBYP BIT(RCC_CR_HSEBYP_BIT) +#define RCC_CR_HSERDY BIT(RCC_CR_HSERDY_BIT) +#define RCC_CR_HSEON BIT(RCC_CR_HSEON_BIT) +#define RCC_CR_HSICAL (0xFF << 8) +#define RCC_CR_HSITRIM (0x1F << 3) +#define RCC_CR_HSIRDY BIT(RCC_CR_HSIRDY_BIT) +#define RCC_CR_HSION BIT(RCC_CR_HSION_BIT) + +/* Clock configuration register */ + +#define RCC_CFGR_USBPRE_BIT 22 +#define RCC_CFGR_PLLXTPRE_BIT 17 +#define RCC_CFGR_PLLSRC_BIT 16 + +#define RCC_CFGR_MCO (0x7 << 24) +#define RCC_CFGR_USBPRE BIT(RCC_CFGR_USBPRE_BIT) +#define RCC_CFGR_PLLMUL (0xF << 18) +#define RCC_CFGR_PLLMUL_2 (0x0 << 18) +#define RCC_CFGR_PLLMUL_3 (0x1 << 18) +#define RCC_CFGR_PLLMUL_4 (0x2 << 18) +#define RCC_CFGR_PLLMUL_5 (0x3 << 18) +#define RCC_CFGR_PLLMUL_6 (0x4 << 18) +#define RCC_CFGR_PLLMUL_7 (0x5 << 18) +#define RCC_CFGR_PLLMUL_8 (0x6 << 18) +#define RCC_CFGR_PLLMUL_9 (0x7 << 18) +#define RCC_CFGR_PLLMUL_10 (0x8 << 18) +#define RCC_CFGR_PLLMUL_11 (0x9 << 18) +#define RCC_CFGR_PLLMUL_12 (0xA << 18) +#define RCC_CFGR_PLLMUL_13 (0xB << 18) +#define RCC_CFGR_PLLMUL_14 (0xC << 18) +#define RCC_CFGR_PLLMUL_15 (0xD << 18) +#define RCC_CFGR_PLLMUL_16 (0xE << 18) +#define RCC_CFGR_PLLXTPRE BIT(RCC_CFGR_PLLXTPRE_BIT) +#define RCC_CFGR_PLLSRC BIT(RCC_CFGR_PLLSRC_BIT) +#define RCC_CFGR_PLLSRC_HSI_DIV_2 (0 << RCC_CFGR_PLLSRC_BIT) +#define RCC_CFGR_PLLSRC_HSE (1 << RCC_CFGR_PLLSRC_BIT) +#define RCC_CFGR_ADCPRE (0x3 << 14) +#define RCC_CFGR_PPRE2 (0x7 << 11) +#define RCC_CFGR_PPRE1 (0x7 << 8) +#define RCC_CFGR_HPRE (0xF << 4) +#define RCC_CFGR_SWS (0x3 << 2) +#define RCC_CFGR_SWS_PLL (0x2 << 2) +#define RCC_CFGR_SWS_HSE (0x1 << 2) +#define RCC_CFGR_SW (0x3 << 0) +#define RCC_CFGR_SW_PLL (0x2 << 0) +#define RCC_CFGR_SW_HSE (0x1 << 0) + +/* Clock interrupt register */ + +#define RCC_CIR_CSSC_BIT 23 +#define RCC_CIR_PLLRDYC_BIT 20 +#define RCC_CIR_HSERDYC_BIT 19 +#define RCC_CIR_HSIRDYC_BIT 18 +#define RCC_CIR_LSERDYC_BIT 17 +#define RCC_CIR_LSIRDYC_BIT 16 +#define RCC_CIR_PLLRDYIE_BIT 12 +#define RCC_CIR_HSERDYIE_BIT 11 +#define RCC_CIR_HSIRDYIE_BIT 10 +#define RCC_CIR_LSERDYIE_BIT 9 +#define RCC_CIR_LSIRDYIE_BIT 8 +#define RCC_CIR_CSSF_BIT 7 +#define RCC_CIR_PLLRDYF_BIT 4 +#define RCC_CIR_HSERDYF_BIT 3 +#define RCC_CIR_HSIRDYF_BIT 2 +#define RCC_CIR_LSERDYF_BIT 1 +#define RCC_CIR_LSIRDYF_BIT 0 + +#define RCC_CIR_CSSC BIT(RCC_CIR_CSSC_BIT) +#define RCC_CIR_PLLRDYC BIT(RCC_CIR_PLLRDYC_BIT) +#define RCC_CIR_HSERDYC BIT(RCC_CIR_HSERDYC_BIT) +#define RCC_CIR_HSIRDYC BIT(RCC_CIR_HSIRDYC_BIT) +#define RCC_CIR_LSERDYC BIT(RCC_CIR_LSERDYC_BIT) +#define RCC_CIR_LSIRDYC BIT(RCC_CIR_LSIRDYC_BIT) +#define RCC_CIR_PLLRDYIE BIT(RCC_CIR_PLLRDYIE_BIT) +#define RCC_CIR_HSERDYIE BIT(RCC_CIR_HSERDYIE_BIT) +#define RCC_CIR_HSIRDYIE BIT(RCC_CIR_HSIRDYIE_BIT) +#define RCC_CIR_LSERDYIE BIT(RCC_CIR_LSERDYIE_BIT) +#define RCC_CIR_LSIRDYIE BIT(RCC_CIR_LSIRDYIE_BIT) +#define RCC_CIR_CSSF BIT(RCC_CIR_CSSF_BIT) +#define RCC_CIR_PLLRDYF BIT(RCC_CIR_PLLRDYF_BIT) +#define RCC_CIR_HSERDYF BIT(RCC_CIR_HSERDYF_BIT) +#define RCC_CIR_HSIRDYF BIT(RCC_CIR_HSIRDYF_BIT) +#define RCC_CIR_LSERDYF BIT(RCC_CIR_LSERDYF_BIT) +#define RCC_CIR_LSIRDYF BIT(RCC_CIR_LSIRDYF_BIT) + +/* APB2 peripheral reset register */ + +#define RCC_APB2RSTR_TIM11RST_BIT 21 +#define RCC_APB2RSTR_TIM10RST_BIT 20 +#define RCC_APB2RSTR_TIM9RST_BIT 19 +#define RCC_APB2RSTR_ADC3RST_BIT 15 +#define RCC_APB2RSTR_USART1RST_BIT 14 +#define RCC_APB2RSTR_TIM8RST_BIT 13 +#define RCC_APB2RSTR_SPI1RST_BIT 12 +#define RCC_APB2RSTR_TIM1RST_BIT 11 +#define RCC_APB2RSTR_ADC2RST_BIT 10 +#define RCC_APB2RSTR_ADC1RST_BIT 9 +#define RCC_APB2RSTR_IOPGRST_BIT 8 +#define RCC_APB2RSTR_IOPFRST_BIT 7 +#define RCC_APB2RSTR_IOPERST_BIT 6 +#define RCC_APB2RSTR_IOPDRST_BIT 5 +#define RCC_APB2RSTR_IOPCRST_BIT 4 +#define RCC_APB2RSTR_IOPBRST_BIT 3 +#define RCC_APB2RSTR_IOPARST_BIT 2 +#define RCC_APB2RSTR_AFIORST_BIT 0 + +#define RCC_APB2RSTR_TIM11RST BIT(RCC_APB2RSTR_TIM11RST_BIT) +#define RCC_APB2RSTR_TIM10RST BIT(RCC_APB2RSTR_TIM10RST_BIT) +#define RCC_APB2RSTR_TIM9RST BIT(RCC_APB2RSTR_TIM9RST_BIT) +#define RCC_APB2RSTR_ADC3RST BIT(RCC_APB2RSTR_ADC3RST_BIT) +#define RCC_APB2RSTR_USART1RST BIT(RCC_APB2RSTR_USART1RST_BIT) +#define RCC_APB2RSTR_TIM8RST BIT(RCC_APB2RSTR_TIM8RST_BIT) +#define RCC_APB2RSTR_SPI1RST BIT(RCC_APB2RSTR_SPI1RST_BIT) +#define RCC_APB2RSTR_TIM1RST BIT(RCC_APB2RSTR_TIM1RST_BIT) +#define RCC_APB2RSTR_ADC2RST BIT(RCC_APB2RSTR_ADC2RST_BIT) +#define RCC_APB2RSTR_ADC1RST BIT(RCC_APB2RSTR_ADC1RST_BIT) +#define RCC_APB2RSTR_IOPGRST BIT(RCC_APB2RSTR_IOPGRST_BIT) +#define RCC_APB2RSTR_IOPFRST BIT(RCC_APB2RSTR_IOPFRST_BIT) +#define RCC_APB2RSTR_IOPERST BIT(RCC_APB2RSTR_IOPERST_BIT) +#define RCC_APB2RSTR_IOPDRST BIT(RCC_APB2RSTR_IOPDRST_BIT) +#define RCC_APB2RSTR_IOPCRST BIT(RCC_APB2RSTR_IOPCRST_BIT) +#define RCC_APB2RSTR_IOPBRST BIT(RCC_APB2RSTR_IOPBRST_BIT) +#define RCC_APB2RSTR_IOPARST BIT(RCC_APB2RSTR_IOPARST_BIT) +#define RCC_APB2RSTR_AFIORST BIT(RCC_APB2RSTR_AFIORST_BIT) + +/* APB1 peripheral reset register */ + +#define RCC_APB1RSTR_DACRST_BIT 29 +#define RCC_APB1RSTR_PWRRST_BIT 28 +#define RCC_APB1RSTR_BKPRST_BIT 27 +#define RCC_APB1RSTR_CANRST_BIT 25 +#define RCC_APB1RSTR_USBRST_BIT 23 +#define RCC_APB1RSTR_I2C2RST_BIT 22 +#define RCC_APB1RSTR_I2C1RST_BIT 21 +#define RCC_APB1RSTR_UART5RST_BIT 20 +#define RCC_APB1RSTR_UART4RST_BIT 19 +#define RCC_APB1RSTR_UART3RST_BIT 18 +#define RCC_APB1RSTR_UART2RST_BIT 17 +#define RCC_APB1RSTR_SPI3RST_BIT 15 +#define RCC_APB1RSTR_SPI2RST_BIT 14 +#define RCC_APB1RSTR_WWDGRST_BIT 11 +#define RCC_APB1RSTR_TIM14RST_BIT 8 +#define RCC_APB1RSTR_TIM13RST_BIT 7 +#define RCC_APB1RSTR_TIM12RST_BIT 6 +#define RCC_APB1RSTR_TIM7RST_BIT 5 +#define RCC_APB1RSTR_TIM6RST_BIT 4 +#define RCC_APB1RSTR_TIM5RST_BIT 3 +#define RCC_APB1RSTR_TIM4RST_BIT 2 +#define RCC_APB1RSTR_TIM3RST_BIT 1 +#define RCC_APB1RSTR_TIM2RST_BIT 0 + +#define RCC_APB1RSTR_DACRST BIT(RCC_APB1RSTR_DACRST_BIT) +#define RCC_APB1RSTR_PWRRST BIT(RCC_APB1RSTR_PWRRST_BIT) +#define RCC_APB1RSTR_BKPRST BIT(RCC_APB1RSTR_BKPRST_BIT) +#define RCC_APB1RSTR_CANRST BIT(RCC_APB1RSTR_CANRST_BIT) +#define RCC_APB1RSTR_USBRST BIT(RCC_APB1RSTR_USBRST_BIT) +#define RCC_APB1RSTR_I2C2RST BIT(RCC_APB1RSTR_I2C2RST_BIT) +#define RCC_APB1RSTR_I2C1RST BIT(RCC_APB1RSTR_I2C1RST_BIT) +#define RCC_APB1RSTR_UART5RST BIT(RCC_APB1RSTR_UART5RST_BIT) +#define RCC_APB1RSTR_UART4RST BIT(RCC_APB1RSTR_UART4RST_BIT) +#define RCC_APB1RSTR_UART3RST BIT(RCC_APB1RSTR_UART3RST_BIT) +#define RCC_APB1RSTR_UART2RST BIT(RCC_APB1RSTR_UART2RST_BIT) +#define RCC_APB1RSTR_SPI3RST BIT(RCC_APB1RSTR_SPI3RST_BIT) +#define RCC_APB1RSTR_SPI2RST BIT(RCC_APB1RSTR_SPI2RST_BIT) +#define RCC_APB1RSTR_WWDGRST BIT(RCC_APB1RSTR_WWDGRST_BIT) +#define RCC_APB1RSTR_TIM14RST BIT(RCC_APB1RSTR_TIM14RST_BIT) +#define RCC_APB1RSTR_TIM13RST BIT(RCC_APB1RSTR_TIM13RST_BIT) +#define RCC_APB1RSTR_TIM12RST BIT(RCC_APB1RSTR_TIM12RST_BIT) +#define RCC_APB1RSTR_TIM7RST BIT(RCC_APB1RSTR_TIM7RST_BIT) +#define RCC_APB1RSTR_TIM6RST BIT(RCC_APB1RSTR_TIM6RST_BIT) +#define RCC_APB1RSTR_TIM5RST BIT(RCC_APB1RSTR_TIM5RST_BIT) +#define RCC_APB1RSTR_TIM4RST BIT(RCC_APB1RSTR_TIM4RST_BIT) +#define RCC_APB1RSTR_TIM3RST BIT(RCC_APB1RSTR_TIM3RST_BIT) +#define RCC_APB1RSTR_TIM2RST BIT(RCC_APB1RSTR_TIM2RST_BIT) + +/* AHB peripheral clock enable register */ + +#define RCC_AHBENR_SDIOEN_BIT 10 +#define RCC_AHBENR_FSMCEN_BIT 8 +#define RCC_AHBENR_CRCEN_BIT 6 +#define RCC_AHBENR_FLITFEN_BIT 4 +#define RCC_AHBENR_SRAMEN_BIT 2 +#define RCC_AHBENR_DMA2EN_BIT 1 +#define RCC_AHBENR_DMA1EN_BIT 0 + +#define RCC_AHBENR_SDIOEN BIT(RCC_AHBENR_SDIOEN_BIT) +#define RCC_AHBENR_FSMCEN BIT(RCC_AHBENR_FSMCEN_BIT) +#define RCC_AHBENR_CRCEN BIT(RCC_AHBENR_CRCEN_BIT) +#define RCC_AHBENR_FLITFEN BIT(RCC_AHBENR_FLITFEN_BIT) +#define RCC_AHBENR_SRAMEN BIT(RCC_AHBENR_SRAMEN_BIT) +#define RCC_AHBENR_DMA2EN BIT(RCC_AHBENR_DMA2EN_BIT) +#define RCC_AHBENR_DMA1EN BIT(RCC_AHBENR_DMA1EN_BIT) + +/* APB2 peripheral clock enable register */ + +#define RCC_APB2ENR_TIM11EN_BIT 21 +#define RCC_APB2ENR_TIM10EN_BIT 20 +#define RCC_APB2ENR_TIM9EN_BIT 19 +#define RCC_APB2ENR_ADC3EN_BIT 15 +#define RCC_APB2ENR_USART1EN_BIT 14 +#define RCC_APB2ENR_TIM8EN_BIT 13 +#define RCC_APB2ENR_SPI1EN_BIT 12 +#define RCC_APB2ENR_TIM1EN_BIT 11 +#define RCC_APB2ENR_ADC2EN_BIT 10 +#define RCC_APB2ENR_ADC1EN_BIT 9 +#define RCC_APB2ENR_IOPGEN_BIT 8 +#define RCC_APB2ENR_IOPFEN_BIT 7 +#define RCC_APB2ENR_IOPEEN_BIT 6 +#define RCC_APB2ENR_IOPDEN_BIT 5 +#define RCC_APB2ENR_IOPCEN_BIT 4 +#define RCC_APB2ENR_IOPBEN_BIT 3 +#define RCC_APB2ENR_IOPAEN_BIT 2 +#define RCC_APB2ENR_AFIOEN_BIT 0 + +#define RCC_APB2ENR_TIM11EN BIT(RCC_APB2ENR_TIM11EN_BIT) +#define RCC_APB2ENR_TIM10EN BIT(RCC_APB2ENR_TIM10EN_BIT) +#define RCC_APB2ENR_TIM9EN BIT(RCC_APB2ENR_TIM9EN_BIT) +#define RCC_APB2ENR_ADC3EN BIT(RCC_APB2ENR_ADC3EN_BIT) +#define RCC_APB2ENR_USART1EN BIT(RCC_APB2ENR_USART1EN_BIT) +#define RCC_APB2ENR_TIM8EN BIT(RCC_APB2ENR_TIM8EN_BIT) +#define RCC_APB2ENR_SPI1EN BIT(RCC_APB2ENR_SPI1EN_BIT) +#define RCC_APB2ENR_TIM1EN BIT(RCC_APB2ENR_TIM1EN_BIT) +#define RCC_APB2ENR_ADC2EN BIT(RCC_APB2ENR_ADC2EN_BIT) +#define RCC_APB2ENR_ADC1EN BIT(RCC_APB2ENR_ADC1EN_BIT) +#define RCC_APB2ENR_IOPGEN BIT(RCC_APB2ENR_IOPGEN_BIT) +#define RCC_APB2ENR_IOPFEN BIT(RCC_APB2ENR_IOPFEN_BIT) +#define RCC_APB2ENR_IOPEEN BIT(RCC_APB2ENR_IOPEEN_BIT) +#define RCC_APB2ENR_IOPDEN BIT(RCC_APB2ENR_IOPDEN_BIT) +#define RCC_APB2ENR_IOPCEN BIT(RCC_APB2ENR_IOPCEN_BIT) +#define RCC_APB2ENR_IOPBEN BIT(RCC_APB2ENR_IOPBEN_BIT) +#define RCC_APB2ENR_IOPAEN BIT(RCC_APB2ENR_IOPAEN_BIT) +#define RCC_APB2ENR_AFIOEN BIT(RCC_APB2ENR_AFIOEN_BIT) + +/* APB1 peripheral clock enable register */ + +#define RCC_APB1ENR_DACEN_BIT 29 +#define RCC_APB1ENR_BKPEN_BIT 27 +#define RCC_APB1ENR_PWREN_BIT 28 +#define RCC_APB1ENR_CANEN_BIT 25 +#define RCC_APB1ENR_USBEN_BIT 23 +#define RCC_APB1ENR_I2C2EN_BIT 22 +#define RCC_APB1ENR_I2C1EN_BIT 21 +#define RCC_APB1ENR_UART5EN_BIT 20 +#define RCC_APB1ENR_UART4EN_BIT 19 +#define RCC_APB1ENR_UART3EN_BIT 18 +#define RCC_APB1ENR_UART2EN_BIT 17 +#define RCC_APB1ENR_SPI3EN_BIT 15 +#define RCC_APB1ENR_SPI2EN_BIT 14 +#define RCC_APB1ENR_WWDGEN_BIT 11 +#define RCC_APB1ENR_TIM14EN_BIT 8 +#define RCC_APB1ENR_TIM13EN_BIT 7 +#define RCC_APB1ENR_TIM12EN_BIT 6 +#define RCC_APB1ENR_TIM7EN_BIT 5 +#define RCC_APB1ENR_TIM6EN_BIT 4 +#define RCC_APB1ENR_TIM5EN_BIT 3 +#define RCC_APB1ENR_TIM4EN_BIT 2 +#define RCC_APB1ENR_TIM3EN_BIT 1 +#define RCC_APB1ENR_TIM2EN_BIT 0 + +#define RCC_APB1ENR_DACEN BIT(RCC_APB1ENR_DACEN_BIT) +#define RCC_APB1ENR_PWREN BIT(RCC_APB1ENR_PWREN_BIT) +#define RCC_APB1ENR_BKPEN BIT(RCC_APB1ENR_BKPEN_BIT) +#define RCC_APB1ENR_CANEN BIT(RCC_APB1ENR_CANEN_BIT) +#define RCC_APB1ENR_USBEN BIT(RCC_APB1ENR_USBEN_BIT) +#define RCC_APB1ENR_I2C2EN BIT(RCC_APB1ENR_I2C2EN_BIT) +#define RCC_APB1ENR_I2C1EN BIT(RCC_APB1ENR_I2C1EN_BIT) +#define RCC_APB1ENR_UART5EN BIT(RCC_APB1ENR_UART5EN_BIT) +#define RCC_APB1ENR_UART4EN BIT(RCC_APB1ENR_UART4EN_BIT) +#define RCC_APB1ENR_UART3EN BIT(RCC_APB1ENR_UART3EN_BIT) +#define RCC_APB1ENR_UART2EN BIT(RCC_APB1ENR_UART2EN_BIT) +#define RCC_APB1ENR_SPI3EN BIT(RCC_APB1ENR_SPI3EN_BIT) +#define RCC_APB1ENR_SPI2EN BIT(RCC_APB1ENR_SPI2EN_BIT) +#define RCC_APB1ENR_WWDGEN BIT(RCC_APB1ENR_WWDGEN_BIT) +#define RCC_APB1ENR_TIM14EN BIT(RCC_APB1ENR_TIM14EN_BIT) +#define RCC_APB1ENR_TIM13EN BIT(RCC_APB1ENR_TIM13EN_BIT) +#define RCC_APB1ENR_TIM12EN BIT(RCC_APB1ENR_TIM12EN_BIT) +#define RCC_APB1ENR_TIM7EN BIT(RCC_APB1ENR_TIM7EN_BIT) +#define RCC_APB1ENR_TIM6EN BIT(RCC_APB1ENR_TIM6EN_BIT) +#define RCC_APB1ENR_TIM5EN BIT(RCC_APB1ENR_TIM5EN_BIT) +#define RCC_APB1ENR_TIM4EN BIT(RCC_APB1ENR_TIM4EN_BIT) +#define RCC_APB1ENR_TIM3EN BIT(RCC_APB1ENR_TIM3EN_BIT) +#define RCC_APB1ENR_TIM2EN BIT(RCC_APB1ENR_TIM2EN_BIT) + +/* Backup domain control register */ + +#define RCC_BDCR_BDRST_BIT 16 +#define RCC_BDCR_RTCEN_BIT 15 +#define RCC_BDCR_LSEBYP_BIT 2 +#define RCC_BDCR_LSERDY_BIT 1 +#define RCC_BDCR_LSEON_BIT 0 + +#define RCC_BDCR_BDRST BIT(RCC_BDCR_BDRST_BIT) +#define RCC_BDCR_RTCEN BIT(RCC_BDCR_RTCEN_BIT) +#define RCC_BDCR_RTCSEL (0x3 << 8) +#define RCC_BDCR_RTCSEL_LSE (0x1 << 8) +#define RCC_BDCR_RTCSEL_LSI (0x2 << 8) +#define RCC_BDCR_RTCSEL_HSE_DIV_128 (0x3 << 8) +#define RCC_BDCR_LSEBYP BIT(RCC_BDCR_LSEBYP_BIT) +#define RCC_BDCR_LSERDY BIT(RCC_BDCR_LSERDY_BIT) +#define RCC_BDCR_LSEON BIT(RCC_BDCR_LSEON_BIT) + +/* Control/status register */ + +#define RCC_CSR_LPWRRSTF_BIT 31 +#define RCC_CSR_WWDGRSTF_BIT 30 +#define RCC_CSR_IWDGRSTF_BIT 29 +#define RCC_CSR_SFTRSTF_BIT 28 +#define RCC_CSR_PORRSTF_BIT 27 +#define RCC_CSR_PINRSTF_BIT 26 +#define RCC_CSR_RMVF_BIT 25 +#define RCC_CSR_LSIRDY_BIT 1 +#define RCC_CSR_LSION_BIT 0 + +#define RCC_CSR_LPWRRSTF BIT(RCC_CSR_LPWRRSTF_BIT) +#define RCC_CSR_WWDGRSTF BIT(RCC_CSR_WWDGRSTF_BIT) +#define RCC_CSR_IWDGRSTF BIT(RCC_CSR_IWDGRSTF_BIT) +#define RCC_CSR_SFTRSTF BIT(RCC_CSR_SFTRSTF_BIT) +#define RCC_CSR_PORRSTF BIT(RCC_CSR_PORRSTF_BIT) +#define RCC_CSR_PINRSTF BIT(RCC_CSR_PINRSTF_BIT) +#define RCC_CSR_RMVF BIT(RCC_CSR_RMVF_BIT) +#define RCC_CSR_LSIRDY BIT(RCC_CSR_LSIRDY_BIT) +#define RCC_CSR_LSION BIT(RCC_CSR_LSION_BIT) + +/** + * Identifies bus and clock line for a device + */ +typedef enum { + RCC_SRAM, + RCC_GPIOA, + RCC_GPIOB, + RCC_GPIOC, + RCC_GPIOD, + RCC_AFIO, + RCC_ADC1, + RCC_ADC2, + RCC_USART1, + RCC_USART2, + RCC_USART3, + RCC_TIMER1, + RCC_TIMER2, + RCC_TIMER3, + RCC_TIMER4, + RCC_SPI1, + RCC_SPI2, + RCC_DMA1, + RCC_PWR, + RCC_BKP, + RCC_CAN, + RCC_USB, + RCC_I2C1, + RCC_I2C2, + RCC_CRC, + RCC_WWDG, + RCC_FLITF, +#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) + RCC_SDIO, + RCC_FSMC, + RCC_GPIOE, + RCC_GPIOF, + RCC_GPIOG, + RCC_ADC3, + RCC_UART4, + RCC_UART5, + RCC_TIMER5, + RCC_TIMER6, + RCC_TIMER7, + RCC_TIMER8, + RCC_DAC, + RCC_DMA2, + RCC_SPI3, +#endif +#ifdef STM32_XL_DENSITY + RCC_TIMER9, + RCC_TIMER10, + RCC_TIMER11, + RCC_TIMER12, + RCC_TIMER13, + RCC_TIMER14, +#endif +} rcc_clk_id; + +/* SYSCLK source */ #define RCC_CLKSRC_HSI (0x0) #define RCC_CLKSRC_HSE (0x1) #define RCC_CLKSRC_PLL (0x2) -/* pll entry clock source */ -#define RCC_PLLSRC_HSE (0x1 << 16) -#define RCC_PLLSRC_HSI_DIV_2 (0x0 << 16) - -/* adc prescaler dividers */ +/* ADC prescaler dividers */ #define RCC_ADCPRE_PCLK_DIV_2 (0x0 << 14) #define RCC_ADCPRE_PCLK_DIV_4 (0x1 << 14) #define RCC_ADCPRE_PCLK_DIV_6 (0x2 << 14) #define RCC_ADCPRE_PCLK_DIV_8 (0x3 << 14) -/* apb1 prescaler dividers */ +/* APB1 prescaler dividers */ #define RCC_APB1_HCLK_DIV_1 (0x0 << 8) #define RCC_APB1_HCLK_DIV_2 (0x4 << 8) #define RCC_APB1_HCLK_DIV_4 (0x5 << 8) #define RCC_APB1_HCLK_DIV_8 (0x6 << 8) #define RCC_APB1_HCLK_DIV_16 (0x7 << 8) -/* apb2 prescaler dividers */ +/* APB2 prescaler dividers */ #define RCC_APB2_HCLK_DIV_1 (0x0 << 11) #define RCC_APB2_HCLK_DIV_2 (0x4 << 11) #define RCC_APB2_HCLK_DIV_4 (0x5 << 11) #define RCC_APB2_HCLK_DIV_8 (0x6 << 11) #define RCC_APB2_HCLK_DIV_16 (0x7 << 11) -/* ahb prescaler dividers */ +/* AHB prescaler dividers */ #define RCC_AHB_SYSCLK_DIV_1 (0x0 << 4) #define RCC_AHB_SYSCLK_DIV_2 (0x8 << 4) #define RCC_AHB_SYSCLK_DIV_4 (0x9 << 4) @@ -119,75 +492,19 @@ extern "C"{ #define RCC_AHB_SYSCLK_DIV_256 (0xE << 4) #define RCC_AHB_SYSCLK_DIV_512 (0xF << 4) -/* pll multipliers */ -#define RCC_PLLMUL_2 (0x0 << 18) -#define RCC_PLLMUL_3 (0x1 << 18) -#define RCC_PLLMUL_4 (0x2 << 18) -#define RCC_PLLMUL_5 (0x3 << 18) -#define RCC_PLLMUL_6 (0x4 << 18) -#define RCC_PLLMUL_7 (0x5 << 18) -#define RCC_PLLMUL_8 (0x6 << 18) -#define RCC_PLLMUL_9 (0x7 << 18) -#define RCC_PLLMUL_10 (0x8 << 18) -#define RCC_PLLMUL_11 (0x9 << 18) -#define RCC_PLLMUL_12 (0xA << 18) -#define RCC_PLLMUL_13 (0xB << 18) -#define RCC_PLLMUL_14 (0xC << 18) -#define RCC_PLLMUL_15 (0xD << 18) -#define RCC_PLLMUL_16 (0xE << 18) - - -/* prescalers */ -enum { +/* Prescalers */ +typedef enum rcc_prescaler { RCC_PRESCALER_AHB, RCC_PRESCALER_APB1, RCC_PRESCALER_APB2, RCC_PRESCALER_USB, RCC_PRESCALER_ADC -}; - -/* - * Identifies bus and clock line for a device - */ -typedef enum { - RCC_GPIOA, - RCC_GPIOB, - RCC_GPIOC, - RCC_GPIOD, - RCC_GPIOE, // High-density devices only (Maple Native) - RCC_GPIOF, // High-density devices only (Maple Native) - RCC_GPIOG, // High-density devices only (Maple Native) - RCC_AFIO, - RCC_ADC1, - RCC_ADC2, - RCC_ADC3, - RCC_USART1, - RCC_USART2, - RCC_USART3, - RCC_UART4, // High-density devices only (Maple Native) - RCC_UART5, // High-density devices only (Maple Native) - RCC_TIMER1, - RCC_TIMER2, - RCC_TIMER3, - RCC_TIMER4, - RCC_TIMER5, // High-density devices only (Maple Native) - RCC_TIMER6, // High-density devices only (Maple Native) - RCC_TIMER7, // High-density devices only (Maple Native) - RCC_TIMER8, // High-density devices only (Maple Native) - RCC_SPI1, - 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) - RCC_PWR, - RCC_BKP, -} rcc_clk_id; +} rcc_prescaler; void rcc_clk_init(uint32 sysclk_src, uint32 pll_src, uint32 pll_mul); void rcc_clk_enable(rcc_clk_id device); void rcc_reset_dev(rcc_clk_id device); -void rcc_set_prescaler(uint32 prescaler, uint32 divider); +void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider); #ifdef __cplusplus } // extern "C" diff --git a/wirish/boards.cpp b/wirish/boards.cpp index 9276f36..440218b 100644 --- a/wirish/boards.cpp +++ b/wirish/boards.cpp @@ -304,7 +304,7 @@ PinMapping PIN_MAP[NR_GPIO_PINS] = { /* D98/PG5 */ {GPIOG, 5, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, /* D99/PD10 */ - {GPIOD, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PDD} + {GPIOD, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD} }; #elif defined(BOARD_maple_mini) diff --git a/wirish/wirish.cpp b/wirish/wirish.cpp index f2fb89b..6967489 100644 --- a/wirish/wirish.cpp +++ b/wirish/wirish.cpp @@ -52,7 +52,7 @@ void init(void) { #endif /* initialize clocks */ - rcc_clk_init(RCC_CLKSRC_PLL, RCC_PLLSRC_HSE, RCC_PLLMUL_9); + rcc_clk_init(RCC_CLKSRC_PLL, RCC_CFGR_PLLSRC_HSE, RCC_CFGR_PLLMUL_9); rcc_set_prescaler(RCC_PRESCALER_AHB, RCC_AHB_SYSCLK_DIV_1); rcc_set_prescaler(RCC_PRESCALER_APB1, RCC_APB1_HCLK_DIV_2); rcc_set_prescaler(RCC_PRESCALER_APB2, RCC_APB2_HCLK_DIV_1); -- cgit v1.2.3 From 334de50c49317f281d87f44e7b9278e08af19254 Mon Sep 17 00:00:00 2001 From: Perry Hung Date: Mon, 14 Mar 2011 18:37:56 -0400 Subject: Add rudimentary error handling for nack condition --- libmaple/i2c.c | 51 ++++++++++++++++++---------------------- libmaple/i2c.h | 43 ++++++++++++++++++++++++--------- main.cpp | 73 +++++++++++++++++++++++++++++++++++++++------------------ wirish/wirish.c | 24 +++++++++---------- 4 files changed, 117 insertions(+), 74 deletions(-) diff --git a/libmaple/i2c.c b/libmaple/i2c.c index 3e948f6..8bd252c 100644 --- a/libmaple/i2c.c +++ b/libmaple/i2c.c @@ -23,9 +23,7 @@ * ****************************************************************************/ /** - * @brief - * TODO: Rejigger hard fault handler and error throbs to turn off all - * interrupts and jump to error throb to reenable usb bootloader + * @brief */ #include "libmaple.h" @@ -36,12 +34,6 @@ #include "i2c.h" #include "string.h" -/* 2/17 Started 10pm-4am - * 2/19 Started 7pm-2am - * 2/20 Started 7pm-7pm - * 2/23 Started 8pm-8am - * 3/9 Started 11pm */ - static inline int32 wait_for_state_change(i2c_dev *dev, i2c_state state); static i2c_dev i2c_dev1 = { @@ -57,22 +49,18 @@ static i2c_dev i2c_dev1 = { i2c_dev* const I2C1 = &i2c_dev1; -/** - * @brief IRQ handler for i2c master. Handles transmission/reception. - * @param dev i2c device - */ - struct crumb { uint32 event; uint32 sr1; uint32 sr2; }; -static struct crumb crumbs[100]; +#define NR_CRUMBS 128 +static struct crumb crumbs[NR_CRUMBS]; static uint32 cur_crumb = 0; static inline void leave_big_crumb(uint32 event, uint32 sr1, uint32 sr2) { - if (cur_crumb < 100) { + if (cur_crumb < NR_CRUMBS) { struct crumb *crumb = &crumbs[cur_crumb++]; crumb->event = event; crumb->sr1 = sr1; @@ -93,8 +81,13 @@ enum { RXNE_START_SENT = 10, RXNE_STOP_SENT = 11, RXNE_DONE = 12, + ERROR_ENTRY = 13, }; +/** + * @brief IRQ handler for i2c master. Handles transmission/reception. + * @param dev i2c device + */ static void i2c_irq_handler(i2c_dev *dev) { i2c_msg *msg = dev->msg; @@ -117,6 +110,7 @@ static void i2c_irq_handler(i2c_dev *dev) { if (read) { i2c_enable_ack(dev); } + i2c_send_slave_addr(dev, msg->addr, read); sr1 = sr2 = 0; } @@ -133,8 +127,7 @@ static void i2c_irq_handler(i2c_dev *dev) { if (read) { if (msg->length == 1) { i2c_disable_ack(dev); - dev->msgs_left--; - if (dev->msgs_left) { + if (dev->msgs_left > 1) { i2c_start_condition(dev); leave_big_crumb(RX_ADDR_START, 0, 0); } else { @@ -197,9 +190,7 @@ static void i2c_irq_handler(i2c_dev *dev) { dev->msg++; } else { i2c_stop_condition(dev); -// while (dev->regs->CR1 & I2C_CR1_STOP) { -// ; -// } + /* * Turn off event interrupts to keep BTF from firing until the end * of the stop condition. Why on earth they didn't have a start/stop @@ -253,7 +244,13 @@ void __irq_i2c1_ev(void) { } static void i2c_irq_error_handler(i2c_dev *dev) { - __error(); + uint32 sr1 = dev->regs->SR1; + uint32 sr2 = dev->regs->SR2; + leave_big_crumb(ERROR_ENTRY, sr1, sr2); + + i2c_stop_condition(dev); + i2c_disable_irq(dev, I2C_IRQ_BUFFER | I2C_IRQ_EVENT | I2C_IRQ_ERROR); + dev->state = I2C_STATE_ERROR; } void __irq_i2c1_er(void) { @@ -330,7 +327,8 @@ void i2c_master_enable(i2c_dev *dev, uint32 flags) { /* Enable event and buffer interrupts */ nvic_irq_enable(dev->ev_nvic_line); - i2c_enable_irq(dev, I2C_IRQ_EVENT | I2C_IRQ_BUFFER); + nvic_irq_enable(dev->er_nvic_line); + i2c_enable_irq(dev, I2C_IRQ_EVENT | I2C_IRQ_BUFFER | I2C_IRQ_ERROR); /* * Important STM32 Errata: @@ -360,6 +358,7 @@ void i2c_master_enable(i2c_dev *dev, uint32 flags) { * been initialized to priority level 16. See nvic_init(). */ nvic_irq_set_priority(dev->ev_nvic_line, 0); + nvic_irq_set_priority(dev->er_nvic_line, 0); /* Make it go! */ i2c_peripheral_enable(dev); @@ -372,15 +371,11 @@ int32 i2c_master_xfer(i2c_dev *dev, i2c_msg *msgs, uint16 num) { dev->msg = msgs; dev->msgs_left = num; - memset(crumbs, 0, sizeof crumbs); - - dev->regs->CR2 |= I2C_CR2_ITEVTEN; - - /* Is this necessary? */ while (dev->regs->SR2 & I2C_SR2_BUSY) ; dev->state = I2C_STATE_BUSY; + i2c_enable_irq(dev, I2C_IRQ_EVENT); i2c_start_condition(dev); rc = wait_for_state_change(dev, I2C_STATE_XFER_DONE); diff --git a/libmaple/i2c.h b/libmaple/i2c.h index be05615..a9e2c7b 100644 --- a/libmaple/i2c.h +++ b/libmaple/i2c.h @@ -136,17 +136,13 @@ extern "C" { void i2c_master_enable(i2c_dev *dev, uint32 flags); int32 i2c_master_xfer(i2c_dev *dev, i2c_msg *msgs, uint16 num); -static inline void i2c_write(i2c_dev *dev, uint8 byte) { - dev->regs->DR = byte; -} - /* * Low level register twiddling functions */ /** * @brief turn on an i2c peripheral - * @param map i2c peripheral register base + * @param dev i2c device */ static inline void i2c_peripheral_enable(i2c_dev *dev) { dev->regs->CR1 |= I2C_CR1_PE; @@ -154,15 +150,25 @@ static inline void i2c_peripheral_enable(i2c_dev *dev) { /** * @brief turn off an i2c peripheral - * @param map i2c peripheral register base + * @param dev i2c device */ static inline void i2c_peripheral_disable(i2c_dev *dev) { dev->regs->CR1 &= ~I2C_CR1_PE; } +/** + * @brief Fill transmit register + * @param dev i2c device + * @param byte byte to write + */ +static inline void i2c_write(i2c_dev *dev, uint8 byte) { + dev->regs->DR = byte; +} + + /** * @brief Set input clock frequency, in mhz - * @param device to configure + * @param dev i2c * @param freq frequency in megahertz (2-36) */ static inline void i2c_set_input_clk(i2c_dev *dev, uint32 freq) { @@ -172,6 +178,13 @@ static inline void i2c_set_input_clk(i2c_dev *dev, uint32 freq) { dev->regs->CR2 = freq; } + +/** + * @brief Set i2c clock control register. See RM008 + * @param dev i2c device + * @return + * @sideeffect + */ static inline void i2c_set_clk_control(i2c_dev *dev, uint32 val) { uint32 ccr = dev->regs->CCR; ccr &= ~I2C_CCR_CCR; @@ -195,15 +208,23 @@ static inline void i2c_set_trise(i2c_dev *dev, uint32 trise) { dev->regs->TRISE = trise; } -extern void toggle(void); static inline void i2c_start_condition(i2c_dev *dev) { - uint32 cr1 = dev->regs->CR1; -// if (cr1 & (I2C_CR1_START | I2C_CR1_STOP | I2C_CR1_PEC)) { -// } + uint32 cr1; + while ((cr1 = dev->regs->CR1) & (I2C_CR1_START | + I2C_CR1_STOP | + I2C_CR1_PEC)) { + ; + } dev->regs->CR1 |= I2C_CR1_START; } static inline void i2c_stop_condition(i2c_dev *dev) { + uint32 cr1; + while ((cr1 = dev->regs->CR1) & (I2C_CR1_START | + I2C_CR1_STOP | + I2C_CR1_PEC)) { + ; + } dev->regs->CR1 |= I2C_CR1_STOP; } diff --git a/main.cpp b/main.cpp index 7771fa7..db310c0 100644 --- a/main.cpp +++ b/main.cpp @@ -1,12 +1,13 @@ // Sample i2c master example for development i2c branch. Writes 0-63 to // addresses 0-63 on a 24LC256 EEPROM, then reads them back. +#include #include "wirish.h" #include "i2c.h" static const uint8 slave_address = 0b1010001; -#define NR_ELEMENTS 4 +#define NR_ELEMENTS 64 uint8 buf0[NR_ELEMENTS + 2] = {0x0, 0x0}; uint8 buf1[] = {0x0, 0x0}; uint8 buf2[NR_ELEMENTS]; @@ -19,12 +20,15 @@ void toggle(void) { } void setup() { + uint32 bytes = 1; uint32 i; + int32 rc = -1; pinMode(BOARD_LED_PIN, OUTPUT); - pinMode(2, OUTPUT); Serial2.begin(9600); Serial2.println("Hello!"); + + pinMode(2, OUTPUT); digitalWrite(2, LOW); for (i = 2; i < sizeof buf0; i++) { @@ -33,31 +37,54 @@ void setup() { i2c_master_enable(I2C1, 0); - /* Write some bytes */ - msgs[0].addr = slave_address; - msgs[0].flags = 0; - msgs[0].length = sizeof buf0; - msgs[0].data = buf0; - i2c_master_xfer(I2C1, msgs, 1); - delay(5); - + while (bytes < 64) { + Serial2.print("Writing "); + Serial2.print(bytes); + Serial2.print(" bytes..."); + + /* Write test pattern */ + msgs[0].addr = slave_address; + msgs[0].flags = 0; + msgs[0].length = 2+ bytes; + msgs[0].data = buf0; + i2c_master_xfer(I2C1, msgs, 1); + delay(5); + + /* Read it back */ + msgs[1].addr = slave_address; + msgs[1].flags = 0; + msgs[1].length = 2; + msgs[1].data = buf1; + /* Repeated start condition */ + msgs[2].addr = slave_address; + msgs[2].flags = I2C_MSG_READ; + msgs[2].length = bytes; + msgs[2].data = buf2; + i2c_master_xfer(I2C1, msgs + 1, 2); + + /* Compare */ + rc = memcmp(&buf0[2], buf2, bytes); + if (rc == 0) { + Serial2.println("good!"); + } else { + Serial2.println("failed!"); + } + + delay(5); + bytes++; + } } +int32 rc; + void loop() { - delay(100); toggleLED(); - /* Write slave address to read */ - msgs[1].addr = slave_address; - msgs[1].flags = 0; - msgs[1].length = 2; - msgs[1].data = buf1; - - /* Repeated start condition, then read NR_ELEMENTS bytes back */ - msgs[2].addr = slave_address; - msgs[2].flags = I2C_MSG_READ; - msgs[2].length = sizeof buf2; - msgs[2].data = buf2; - i2c_master_xfer(I2C1, msgs + 1, 2); + delay(100); + rc = i2c_master_xfer(I2C1, msgs + 1, 2); + if (rc < 0) { + Serial2.println("Failed transfer!"); + i2c_master_enable(I2C1, 0); + } } // Force init to be called *first*, i.e. before static object allocation. diff --git a/wirish/wirish.c b/wirish/wirish.c index 4c84d26..2b128f1 100644 --- a/wirish/wirish.c +++ b/wirish/wirish.c @@ -63,18 +63,18 @@ void init(void) { /* Initialize the ADC for slow conversions, to allow for high impedance inputs. */ - adc_init(ADC1, 0); - adc_set_sample_rate(ADC1, ADC_SMPR_55_5); - - timer_init(TIMER1, 1); - timer_init(TIMER2, 1); - timer_init(TIMER3, 1); - timer_init(TIMER4, 1); -#ifdef STM32_HIGH_DENSITY - timer_init(TIMER5, 1); - timer_init(TIMER8, 1); -#endif - setupUSB(); +// adc_init(ADC1, 0); +// adc_set_sample_rate(ADC1, ADC_SMPR_55_5); +// +// timer_init(TIMER1, 1); +// timer_init(TIMER2, 1); +// timer_init(TIMER3, 1); +// timer_init(TIMER4, 1); +//#ifdef STM32_HIGH_DENSITY +// timer_init(TIMER5, 1); +// timer_init(TIMER8, 1); +//#endif +// setupUSB(); /* include the board-specific init macro */ BOARD_INIT; -- cgit v1.2.3 From c0cb60b3ff57f60b618433a507116aeac2c21075 Mon Sep 17 00:00:00 2001 From: Perry Hung Date: Tue, 15 Mar 2011 19:36:46 -0400 Subject: support: linker: Fix high density vector table Entries for high-density interrupt vectors were incorrectly declared to be .weak instead of .long. Thanks redfox74! --- support/ld/libcs3_stm32_high_density.a | Bin 9464 -> 9464 bytes support/ld/libcs3_stm32_src/stm32_vector_table.S | 34 +++++++++++------------ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/support/ld/libcs3_stm32_high_density.a b/support/ld/libcs3_stm32_high_density.a index 472ed28..a09d7f0 100644 Binary files a/support/ld/libcs3_stm32_high_density.a and b/support/ld/libcs3_stm32_high_density.a differ diff --git a/support/ld/libcs3_stm32_src/stm32_vector_table.S b/support/ld/libcs3_stm32_src/stm32_vector_table.S index 8c71cb5..c3f0fc7 100644 --- a/support/ld/libcs3_stm32_src/stm32_vector_table.S +++ b/support/ld/libcs3_stm32_src/stm32_vector_table.S @@ -68,23 +68,23 @@ __cs3_stm32_vector_table: .long __irq_rtcalarm .long __irq_usbwakeup #if defined (STM32_HIGH_DENSITY) - .weak __irq_tim8_brk - .weak __irq_tim8_up - .weak __irq_tim8_trg_com - .weak __irq_tim8_cc - .weak __irq_adc3 - .weak __irq_fsmc - .weak __irq_sdio - .weak __irq_tim5 - .weak __irq_spi3 - .weak __irq_uart4 - .weak __irq_uart5 - .weak __irq_tim6 - .weak __irq_tim7 - .weak __irq_dma2_channel1 - .weak __irq_dma2_channel2 - .weak __irq_dma2_channel3 - .weak __irq_dma2_channel4_5 + .long __irq_tim8_brk + .long __irq_tim8_up + .long __irq_tim8_trg_com + .long __irq_tim8_cc + .long __irq_adc3 + .long __irq_fsmc + .long __irq_sdio + .long __irq_tim5 + .long __irq_spi3 + .long __irq_uart4 + .long __irq_uart5 + .long __irq_tim6 + .long __irq_tim7 + .long __irq_dma2_channel1 + .long __irq_dma2_channel2 + .long __irq_dma2_channel3 + .long __irq_dma2_channel4_5 #endif /* STM32_HIGH_DENSITY */ .size __cs3_stm32_vector_table, . - __cs3_stm32_vector_table -- cgit v1.2.3 From c73306508820705eef4f2cb9f8542acdba599cd8 Mon Sep 17 00:00:00 2001 From: Perry Hung Date: Tue, 15 Mar 2011 19:46:47 -0400 Subject: Reenable other peripherals. --- wirish/wirish.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/wirish/wirish.c b/wirish/wirish.c index 2b128f1..4c84d26 100644 --- a/wirish/wirish.c +++ b/wirish/wirish.c @@ -63,18 +63,18 @@ void init(void) { /* Initialize the ADC for slow conversions, to allow for high impedance inputs. */ -// adc_init(ADC1, 0); -// adc_set_sample_rate(ADC1, ADC_SMPR_55_5); -// -// timer_init(TIMER1, 1); -// timer_init(TIMER2, 1); -// timer_init(TIMER3, 1); -// timer_init(TIMER4, 1); -//#ifdef STM32_HIGH_DENSITY -// timer_init(TIMER5, 1); -// timer_init(TIMER8, 1); -//#endif -// setupUSB(); + adc_init(ADC1, 0); + adc_set_sample_rate(ADC1, ADC_SMPR_55_5); + + timer_init(TIMER1, 1); + timer_init(TIMER2, 1); + timer_init(TIMER3, 1); + timer_init(TIMER4, 1); +#ifdef STM32_HIGH_DENSITY + timer_init(TIMER5, 1); + timer_init(TIMER8, 1); +#endif + setupUSB(); /* include the board-specific init macro */ BOARD_INIT; -- cgit v1.2.3 From 04ee498b46393250c31606e526c28cb3b2b870ed Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Tue, 15 Mar 2011 14:26:30 -0400 Subject: Flash refactor --- libmaple/flash.c | 39 ++++++++-------------- libmaple/flash.h | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 107 insertions(+), 30 deletions(-) diff --git a/libmaple/flash.c b/libmaple/flash.c index 1d7bfa6..c921256 100644 --- a/libmaple/flash.c +++ b/libmaple/flash.c @@ -28,41 +28,30 @@ #include "libmaple.h" #include "flash.h" - -/* flash registers */ -#define FLASH_BASE 0x40022000 -#define FLASH_ACR FLASH_BASE - -/* flash prefetcher */ -#define ACR_PRFTBE BIT(4) -#define ACR_PRFTBE_ENABLE BIT(4) - -/* flash wait states */ -#define ACR_LATENCY (0x7) - -#define FLASH_WRITE_ACR(val) __write(FLASH_ACR, val) -#define FLASH_READ_ACR() __read(FLASH_ACR) +#include "bitband.h" /** - * @brief turn on the hardware prefetcher + * @brief Turn on the hardware prefetcher. */ void flash_enable_prefetch(void) { - uint32 val = FLASH_READ_ACR(); - - val |= ACR_PRFTBE_ENABLE; - - FLASH_WRITE_ACR(val); + *bb_perip(&FLASH_BASE->ACR, FLASH_ACR_PRFTBE_BIT) = 1; } /** - * @brief set flash wait states - * @param number of wait states + * @brief Set flash wait states + * + * See ST PM0042, section 3.1 for restrictions on the acceptable value + * of wait_states for a given SYSCLK configuration. + * + * @param wait_states number of wait states (one of + * FLASH_WAIT_STATE_0, FLASH_WAIT_STATE_1, + * FLASH_WAIT_STATE_2). */ void flash_set_latency(uint32 wait_states) { - uint32 val = FLASH_READ_ACR(); + uint32 val = FLASH_BASE->ACR; - val &= ~ACR_LATENCY; + val &= ~FLASH_ACR_LATENCY; val |= wait_states; - FLASH_WRITE_ACR(val); + FLASH_BASE->ACR = val; } diff --git a/libmaple/flash.h b/libmaple/flash.h index 7b74c83..9db5015 100644 --- a/libmaple/flash.h +++ b/libmaple/flash.h @@ -25,20 +25,108 @@ /** * @file flash.h - * @brief basic stm32 flash setup routines + * @brief STM32 Medium and high density Flash register map and setup + * routines */ #ifndef _FLASH_H_ #define _FLASH_H_ -#define FLASH_WAIT_STATE_0 0x0 -#define FLASH_WAIT_STATE_1 0x1 -#define FLASH_WAIT_STATE_2 0x2 - #ifdef __cplusplus extern "C"{ #endif +/** Flash register map type */ +typedef struct flash_reg_map { + __io uint32 ACR; /**< Access control register */ + __io uint32 KEYR; /**< Key register */ + __io uint32 OPTKEYR; /**< OPTKEY register */ + __io uint32 SR; /**< Status register */ + __io uint32 CR; /**< Control register */ + __io uint32 AR; /**< Address register */ + __io uint32 OBR; /**< Option byte register */ + __io uint32 WRPR; /**< Write protection register */ +} flash_reg_map; + +/** Flash register map base pointer */ +#define FLASH_BASE ((flash_reg_map*)0x40022000) + +/* + * Register bit definitions + */ + +/* Access control register */ + +#define FLASH_ACR_PRFTBS_BIT 5 +#define FLASH_ACR_PRFTBE_BIT 4 +#define FLASH_ACR_HLFCYA_BIT 3 + +#define FLASH_ACR_PRFTBS BIT(FLASH_ACR_PRFTBS_BIT) +#define FLASH_ACR_PRFTBE BIT(FLASH_ACR_PRFTBE_BIT) +#define FLASH_ACR_HLFCYA BIT(FLASH_ACR_HLFCYA_BIT) +#define FLASH_ACR_LATENCY 0x7 + +/* Status register */ + +#define FLASH_SR_EOP_BIT 5 +#define FLASH_SR_WRPRTERR_BIT 4 +#define FLASH_SR_PGERR_BIT 2 +#define FLASH_SR_BSY_BIT 0 + +#define FLASH_SR_EOP BIT(FLASH_SR_EOP_BIT) +#define FLASH_SR_WRPRTERR BIT(FLASH_SR_WRPRTERR_BIT) +#define FLASH_SR_PGERR BIT(FLASH_SR_PGERR_BIT) +#define FLASH_SR_BSY BIT(FLASH_SR_BSY_BIT) + +/* Control register */ + +#define FLASH_CR_EOPIE_BIT 12 +#define FLASH_CR_ERRIE_BIT 10 +#define FLASH_CR_OPTWRE_BIT 9 +#define FLASH_CR_LOCK_BIT 7 +#define FLASH_CR_STRT_BIT 6 +#define FLASH_CR_OPTER_BIT 5 +#define FLASH_CR_OPTPG_BIT 4 +#define FLASH_CR_MER_BIT 2 +#define FLASH_CR_PER_BIT 1 +#define FLASH_CR_PG_BIT 0 + +#define FLASH_CR_EOPIE BIT(FLASH_CR_EOPIE_BIT) +#define FLASH_CR_ERRIE BIT(FLASH_CR_ERRIE_BIT) +#define FLASH_CR_OPTWRE BIT(FLASH_CR_OPTWRE_BIT) +#define FLASH_CR_LOCK BIT(FLASH_CR_LOCK_BIT) +#define FLASH_CR_STRT BIT(FLASH_CR_STRT_BIT) +#define FLASH_CR_OPTER BIT(FLASH_CR_OPTER_BIT) +#define FLASH_CR_OPTPG BIT(FLASH_CR_OPTPG_BIT) +#define FLASH_CR_MER BIT(FLASH_CR_MER_BIT) +#define FLASH_CR_PER BIT(FLASH_CR_PER_BIT) +#define FLASH_CR_PG BIT(FLASH_CR_PG_BIT) + +/* Option byte register */ + +#define FLASH_OBR_nRST_STDBY_BIT 4 +#define FLASH_OBR_nRST_STOP_BIT 3 +#define FLASH_OBR_WDG_SW_BIT 2 +#define FLASH_OBR_RDPRT_BIT 1 +#define FLASH_OBR_OPTERR_BIT 0 + +#define FLASH_OBR_DATA1 (0xFF << 18) +#define FLASH_OBR_DATA0 (0xFF << 10) +#define FLASH_OBR_USER 0x3FF +#define FLASH_OBR_nRST_STDBY BIT(FLASH_OBR_nRST_STDBY_BIT) +#define FLASH_OBR_nRST_STOP BIT(FLASH_OBR_nRST_STOP_BIT) +#define FLASH_OBR_WDG_SW BIT(FLASH_OBR_WDG_SW_BIT) +#define FLASH_OBR_RDPRT BIT(FLASH_OBR_RDPRT_BIT) +#define FLASH_OBR_OPTERR BIT(FLASH_OBR_OPTERR_BIT) + +/* + * Setup routines + */ + +#define FLASH_WAIT_STATE_0 0x0 +#define FLASH_WAIT_STATE_1 0x1 +#define FLASH_WAIT_STATE_2 0x2 + void flash_enable_prefetch(void); void flash_set_latency(uint32 wait_states); -- cgit v1.2.3 From 4862d1eae5813e278cfbb1d5e0a040010b92eb3f Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Wed, 16 Mar 2011 17:37:21 -0400 Subject: Maple RET6 edition support --- Makefile | 7 ++++ examples/test-session.cpp | 9 ++--- libmaple/libmaple.h | 7 +++- libmaple/pwr.c | 2 +- libmaple/rules.mk | 1 + libmaple/usb/usb_config.h | 10 ++--- support/ld/maple_RET6/flash.ld | 18 +++++++++ support/ld/maple_RET6/jtag.ld | 17 ++++++++ support/ld/maple_RET6/ram.ld | 18 +++++++++ support/ld/maple_native/ram.ld | 1 - support/scripts/copy-to-ide | 18 ++++++--- wirish/boards.cpp | 89 ++++++++++++++++++++++++++++++++++++++++++ wirish/boards.h | 15 +++++++ wirish/wirish.cpp | 2 +- 14 files changed, 194 insertions(+), 20 deletions(-) create mode 100644 support/ld/maple_RET6/flash.ld create mode 100644 support/ld/maple_RET6/jtag.ld create mode 100644 support/ld/maple_RET6/ram.ld diff --git a/Makefile b/Makefile index 3804421..d31c9ed 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,13 @@ ifeq ($(BOARD), maple_mini) ERROR_LED_PIN := 1 DENSITY := STM32_MEDIUM_DENSITY endif +ifeq ($(BOARD), maple_RET6) + MCU := STM32F103RE + PRODUCT_ID := 0003 + ERROR_LED_PORT := GPIOA + ERROR_LED_PIN := 5 + DENSITY := STM32_HIGH_DENSITY +endif # Useful paths ifeq ($(LIB_MAPLE_HOME),) diff --git a/examples/test-session.cpp b/examples/test-session.cpp index ea631ca..a147e06 100644 --- a/examples/test-session.cpp +++ b/examples/test-session.cpp @@ -20,7 +20,7 @@ int rate = 0; -#if defined(BOARD_maple) +#if defined(BOARD_maple) || defined(BOARD_maple_RET6) const uint8 pwm_pins[] = {0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 14, 24, 25, 27, 28}; const uint8 adc_pins[] = @@ -617,15 +617,14 @@ void init_all_timers(uint16 prescale) { timer_init(TIMER4, prescale); #ifdef STM32_HIGH_DENSITY timer_init(TIMER5, prescale); - timer_init(TIMER6, prescale); - timer_init(TIMER7, prescale); + // timer_init(TIMER6, prescale); + // timer_init(TIMER7, prescale); timer_init(TIMER8, prescale); #endif } - // Force init to be called *first*, i.e. before static object allocation. -// Otherwise, statically allocated object that need libmaple may fail. +// Otherwise, statically allocated objects that need libmaple may fail. __attribute__(( constructor )) void premain() { init(); } diff --git a/libmaple/libmaple.h b/libmaple/libmaple.h index 0bbd34e..7814730 100644 --- a/libmaple/libmaple.h +++ b/libmaple/libmaple.h @@ -56,7 +56,6 @@ /* e.g., LeafLabs Maple Native */ #define NR_GPIO_PORTS 7 - #define SRAM_SIZE 0x10000 #elif defined(MCU_STM32F103CB) @@ -69,6 +68,12 @@ #define SRAM_SIZE 0x5000 +#elif defined(MCU_STM32F103RE) + /* e.g., LeafLabs Maple RET6 edition */ + + #define NR_GPIO_PORTS 4 + #define SRAM_SIZE 0x10000 + #else #error "No MCU type specified. Add something like -DMCU_STM32F103RB " \ diff --git a/libmaple/pwr.c b/libmaple/pwr.c index b43193e..d63a92d 100644 --- a/libmaple/pwr.c +++ b/libmaple/pwr.c @@ -28,7 +28,7 @@ #include "rcc.h" pwr_dev pwr = { - .regs = PWR_BASE; + .regs = PWR_BASE, }; const pwr_dev *PWR = &pwr; diff --git a/libmaple/rules.mk b/libmaple/rules.mk index b87595d..b264b96 100644 --- a/libmaple/rules.mk +++ b/libmaple/rules.mk @@ -22,6 +22,7 @@ cSRCS_$(d) := adc.c \ gpio.c \ iwdg.c \ nvic.c \ + pwr.c \ rcc.c \ spi.c \ syscalls.c \ diff --git a/libmaple/usb/usb_config.h b/libmaple/usb/usb_config.h index 9003da9..0860b90 100644 --- a/libmaple/usb/usb_config.h +++ b/libmaple/usb/usb_config.h @@ -28,7 +28,7 @@ #define RESET_DELAY (100) #define USB_CONFIG_MAX_POWER (100 >> 1) -#if defined(BOARD_maple) +#if defined(BOARD_maple) || defined(BOARD_maple_RET6) /* USB Identifier numbers */ #define VCOM_ID_PRODUCT 0x0004 @@ -37,13 +37,13 @@ #elif defined(BOARD_maple_mini) - #define VCOM_ID_PRODUCT 0x0005 + #define VCOM_ID_PRODUCT 0x0004 #define USB_DISC_DEV GPIOB #define USB_DISC_PIN 9 #elif defined(BOARD_maple_native) - #define VCOM_ID_PRODUCT 0x0006 + #define VCOM_ID_PRODUCT 0x0004 #define USB_DISC_DEV GPIOB #define USB_DISC_PIN 8 @@ -51,8 +51,8 @@ #error ("Sorry! the USB stack relies on LeafLabs board-specific " \ "configuration right now. If you want, you can pretend you're one " \ - "of our boards; i.e., #define BOARD_maple, BOARD_maple_mini, or " \ - "BOARD_maple_native according to what matches your MCU best. " \ + "of our boards; i.e., #define BOARD_maple, BOARD_maple_mini, or " \ + "BOARD_maple_native according to what matches your MCU best. " \ "You should also take a look at libmaple/usb/descriptors.c; we make " \ "some assumptions there that you probably won't like.") diff --git a/support/ld/maple_RET6/flash.ld b/support/ld/maple_RET6/flash.ld new file mode 100644 index 0000000..2a4f0c7 --- /dev/null +++ b/support/ld/maple_RET6/flash.ld @@ -0,0 +1,18 @@ +/* + * STM32F103RET6 high density chip linker script for use with Maple + * bootloader. Loads to Flash. + */ + +MEMORY +{ + ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 61K + rom (rx) : ORIGIN = 0x08005000, LENGTH = 492K +} + +GROUP(libcs3_stm32_high_density.a) + +REGION_ALIAS("REGION_TEXT", rom); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); + +INCLUDE common_rom.inc diff --git a/support/ld/maple_RET6/jtag.ld b/support/ld/maple_RET6/jtag.ld new file mode 100644 index 0000000..88f45e0 --- /dev/null +++ b/support/ld/maple_RET6/jtag.ld @@ -0,0 +1,17 @@ +/* + * STM32F103RET6 high density bare metal linker script. + */ + +MEMORY +{ + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64K + rom (rx) : ORIGIN = 0x08000000, LENGTH = 512K +} + +GROUP(libcs3_stm32_high_density.a) + +REGION_ALIAS("REGION_TEXT", rom); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); + +INCLUDE common_rom.inc diff --git a/support/ld/maple_RET6/ram.ld b/support/ld/maple_RET6/ram.ld new file mode 100644 index 0000000..f09acd9 --- /dev/null +++ b/support/ld/maple_RET6/ram.ld @@ -0,0 +1,18 @@ +/* + * STM32F103RET6 high density chip linker script for use with Maple + * bootloader. Loads to RAM. + */ + +MEMORY +{ + ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 61K + rom (rx) : ORIGIN = 0x08005000, LENGTH = 0K +} + +GROUP(libcs3_stm32_high_density.a) + +REGION_ALIAS("REGION_TEXT", ram); +REGION_ALIAS("REGION_DATA", ram); +REGION_ALIAS("REGION_BSS", ram); + +INCLUDE common_ram.inc diff --git a/support/ld/maple_native/ram.ld b/support/ld/maple_native/ram.ld index 22c09cd..d5bd3b0 100644 --- a/support/ld/maple_native/ram.ld +++ b/support/ld/maple_native/ram.ld @@ -19,4 +19,3 @@ REGION_ALIAS("REGION_DATA", ram); REGION_ALIAS("REGION_BSS", ram); INCLUDE common_ram.inc - diff --git a/support/scripts/copy-to-ide b/support/scripts/copy-to-ide index 301126d..5254974 100755 --- a/support/scripts/copy-to-ide +++ b/support/scripts/copy-to-ide @@ -1,7 +1,8 @@ #!/bin/sh -# This hack copies the necessary library files into the Maple IDE -# repository. +# This hack copies libmaple's source, linker scripts, and built +# documentation into the Maple IDE repository (which is expected as +# its first argument). DEST=$1 @@ -18,14 +19,18 @@ LMAPLE_SRC="LICENSE ./libmaple/usb/usb_lib/*.h ./libmaple/usb/usb_lib/*.c ./wirish/*.h - ./wirish/*.c ./wirish/main.cxx ./wirish/*.cpp ./wirish/comm/*.cpp ./wirish/comm/*.h + ./support/ld/common_ram.inc + ./support/ld/common_rom.inc + ./support/ld/libcs3_stm32_high_density.a + ./support/ld/libcs3_stm32_med_density.a ./support/ld/maple + ./support/ld/maple_mini ./support/ld/maple_native - ./support/ld/libcs3-lanchon-stm32.a + ./support/ld/maple_RET6 ./support/ld/names.inc" LMAPLE_DOCS=./docs @@ -40,7 +45,8 @@ fi # source echo Copying libmaple source -rm -rf $DEST_CORES/*.c $DEST_CORES/*.cpp $DEST_CORES/*.h $DEST_CORES/*.cxx $DEST_CORES/*.inc $DEST_CORES/*.a $DEST_CORES/*.S $DEST_CORES/maple $DEST_CORES/maple_native +rm -rf $DEST_CORES/*.c $DEST_CORES/*.cpp $DEST_CORES/*.h $DEST_CORES/*.cxx $DEST_CORES/*.S +rm -rf $DEST_CORES/*.inc $DEST_CORES/*.a $DEST_CORES/maple $DEST_CORES/maple_* cp -R $LMAPLE_SRC $DEST_CORES echo Copying over libraries @@ -51,7 +57,7 @@ echo Deleting old reference directory contents rm -rf $DEST_REF/* echo Rebuilding documentation -( cd $LMAPLE_DOCS; doxygen && make clean 2>/dev/null 1>/dev/null && make html ) +( cd $LMAPLE_DOCS; doxygen >/dev/null 2>&1 && make clean >/dev/null 2>&1 && make html ) echo Copying over documentation cp -R $LMAPLE_DOCS_BUILD/* $DEST_REF diff --git a/wirish/boards.cpp b/wirish/boards.cpp index 440218b..66f008f 100644 --- a/wirish/boards.cpp +++ b/wirish/boards.cpp @@ -380,6 +380,95 @@ PinMapping PIN_MAP[NR_GPIO_PINS] = { {GPIOB, 1, 9, TIMER3_CH4_CCR, TIMER3, 4, AFIO_EXTI_PB}, }; +#elif defined(BOARD_maple_RET6) + +PinMapping PIN_MAP[NR_GPIO_PINS] = { + /* D0/PA3 */ + {GPIOA, 3, 3, TIMER2_CH4_CCR, TIMER2, 4, AFIO_EXTI_PA}, + /* D1/PA2 */ + {GPIOA, 2, 2, TIMER2_CH3_CCR, TIMER2, 3, AFIO_EXTI_PA}, + /* D2/PA0 */ + {GPIOA, 0, 0, TIMER2_CH1_CCR, TIMER2, 1, AFIO_EXTI_PA}, + /* D3/PA1 */ + {GPIOA, 1, 1, TIMER2_CH2_CCR, TIMER2, 2, AFIO_EXTI_PA}, + /* D4/PB5 */ + {GPIOB, 5, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, + /* D5/PB6 */ + {GPIOB, 6, ADCx, TIMER4_CH1_CCR, TIMER4, 1, AFIO_EXTI_PB}, + /* D6/PA8 */ + {GPIOA, 8, ADCx, TIMER1_CH1_CCR, TIMER1, 1, AFIO_EXTI_PA}, + /* D7/PA9 */ + {GPIOA, 9, ADCx, TIMER1_CH2_CCR, TIMER1, 2, AFIO_EXTI_PA}, + /* D8/PA10 */ + {GPIOA, 10, ADCx, TIMER1_CH3_CCR, TIMER1, 3, AFIO_EXTI_PA}, + /* D9/PB7 */ + {GPIOB, 7, ADCx, TIMER4_CH2_CCR, TIMER4, 2, AFIO_EXTI_PB}, + /* D10/PA4 */ + {GPIOA, 4, 4, 0, TIMERx, TIMERx, AFIO_EXTI_PA}, + /* D11/PA7 */ + {GPIOA, 7, 7, TIMER3_CH2_CCR, TIMER3, 2, AFIO_EXTI_PA}, + /* D12/PA6 */ + {GPIOA, 6, 6, TIMER3_CH1_CCR, TIMER3, 1, AFIO_EXTI_PA}, + /* D13/PA5 */ + {GPIOA, 5, 5, 0, TIMERx, TIMERx, AFIO_EXTI_PA}, + /* D14/PB8 */ + {GPIOB, 8, ADCx, TIMER4_CH3_CCR, TIMER4, 3, AFIO_EXTI_PB}, + + /* Little header */ + + /* D15/PC0 */ + {GPIOC, 0, 10, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D16/PC1 */ + {GPIOC, 1, 11, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D17/PC2 */ + {GPIOC, 2, 12, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D18/PC3 */ + {GPIOC, 3, 13, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D19/PC4 */ + {GPIOC, 4, 14, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D20/PC5 */ + {GPIOC, 5, 15, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + + /* External header */ + + /* D21/PC13 */ + {GPIOC, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D22/PC14 */ + {GPIOC, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D23/PC15 */ + {GPIOC, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D24/PB9 */ + {GPIOB, 9, ADCx, TIMER4_CH4_CCR, TIMER4, 4, AFIO_EXTI_PB}, + /* D25/PD2 */ + {GPIOD, 2, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, + /* D26/PC10 */ + {GPIOC, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + /* D27/PB0 */ + {GPIOB, 0, 8, TIMER3_CH3_CCR, TIMER3, 3, AFIO_EXTI_PB}, + /* D28/PB1 */ + {GPIOB, 1, 9, TIMER3_CH4_CCR, TIMER3, 4, AFIO_EXTI_PB}, + /* D29/PB10 */ + {GPIOB, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, + /* D30/PB11 */ + {GPIOB, 11, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, + /* D31/PB12 */ + {GPIOB, 12, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, + /* D32/PB13 */ + {GPIOB, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, + /* D33/PB14 */ + {GPIOB, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, + /* D34/PB15 */ + {GPIOB, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, + /* D35/PC6 */ + {GPIOC, 6, ADCx, TIMER8_CH1_CCR, TIMER8, 1, AFIO_EXTI_PC}, + /* D36/PC7 */ + {GPIOC, 7, ADCx, TIMER8_CH1_CCR, TIMER8, 2, AFIO_EXTI_PC}, + /* D37/PC8 */ + {GPIOC, 8, ADCx, TIMER8_CH1_CCR, TIMER8, 3, AFIO_EXTI_PC}, + /* D38/PC9 (BUT) */ + {GPIOC, 9, ADCx, TIMER8_CH1_CCR, TIMER8, 4, AFIO_EXTI_PC} +}; + #else #error "Board type has not been selected correctly." diff --git a/wirish/boards.h b/wirish/boards.h index 2941127..94566fa 100644 --- a/wirish/boards.h +++ b/wirish/boards.h @@ -113,6 +113,21 @@ extern PinMapping PIN_MAP[]; afio_mapr_swj_config(AFIO_MAPR_SWJ_NO_JTAG_NO_SW); \ } while (0) +#elif defined(BOARD_maple_RET6) + + #define CYCLES_PER_MICROSECOND 72 + #define SYSTICK_RELOAD_VAL 71999 /* takes a cycle to reload */ + + #define BOARD_BUTTON_PIN 38 + #define BOARD_LED_PIN 13 + + /* Total number of GPIO pins that are broken out to headers and + intended for general use. */ + #define NR_GPIO_PINS 39 + + #define BOARD_INIT do { \ + } while(0) + #else #error "Board type has not been selected correctly." diff --git a/wirish/wirish.cpp b/wirish/wirish.cpp index 6967489..6d77bc8 100644 --- a/wirish/wirish.cpp +++ b/wirish/wirish.cpp @@ -47,7 +47,7 @@ void init(void) { flash_enable_prefetch(); flash_set_latency(FLASH_WAIT_STATE_2); -#ifdef STM32_HIGH_DENSITY +#ifdef BOARD_maple_native fsmc_native_sram_init(); #endif -- cgit v1.2.3 From 9cea4517c1db13a6f16eb3854c18c7fc02cbdeda Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Tue, 15 Mar 2011 20:47:53 -0400 Subject: FSMC refactor; SRAM test code --- examples/fsmc-stress-test.cpp | 216 +++++++++++++++++++++++++++++ examples/test-fsmc.cpp | 208 ++++++++++++++-------------- libmaple/fsmc.c | 53 +------- libmaple/fsmc.h | 308 ++++++++++++++++++++++++++++++++++++------ wirish/native_sram.cpp | 45 ++++++ wirish/native_sram.h | 43 ++++++ wirish/rules.mk | 1 + wirish/wirish.cpp | 3 +- 8 files changed, 684 insertions(+), 193 deletions(-) create mode 100644 examples/fsmc-stress-test.cpp create mode 100644 wirish/native_sram.cpp create mode 100644 wirish/native_sram.h diff --git a/examples/fsmc-stress-test.cpp b/examples/fsmc-stress-test.cpp new file mode 100644 index 0000000..12e8650 --- /dev/null +++ b/examples/fsmc-stress-test.cpp @@ -0,0 +1,216 @@ +/* + + A low-level stress test of SRAM functionality. Uses slow-ish timing + by default (DATAST = ADDSET = 0xF). + + Copyright 2011 LeafLabs, LLC. + + This code is released into the public domain. + + */ + +#include +#include + +#include "wirish.h" +#include "rcc.h" +#include "fsmc.h" + +// -- SRAM config ------------------------------------------------------------- + +// Timing configuration +#define DATAST 0xF +#define ADDSET 0xF + +// Number of SRAM chips to test +#define N 1 + +// How much of each to test +#define MEM_SIZE 0x3FFF + +// Their start addresses in FSMC bank 1 +__io uint16 *const starts[N] = { + // (__io uint16 *const)FSMC_NOR_PSRAM_REGION1, + // (__io uint16 *const)FSMC_NOR_PSRAM_REGION2, + (__io uint16 *const)FSMC_NOR_PSRAM_REGION3, + // (__io uint16 *const)FSMC_NOR_PSRAM_REGION4, +}; + +// Corresponding FSMC configuration registers +__io uint32 *const bcrs[N] = { + // &FSMC_NOR_PSRAM1_BASE->BCR, + // &FSMC_NOR_PSRAM2_BASE->BCR, + &FSMC_NOR_PSRAM3_BASE->BCR, + // &FSMC_NOR_PSRAM4_BASE->BCR, +}; + +// Corresponding FSMC timing registers +__io uint32 *const btrs[N] = { + // &FSMC_NOR_PSRAM1_BASE->BTR, + // &FSMC_NOR_PSRAM2_BASE->BTR, + &FSMC_NOR_PSRAM3_BASE->BTR, + // &FSMC_NOR_PSRAM4_BASE->BTR, +}; + +// -- Pseudorandom number generation ----------------------------------------- + +const uint32 seed = 0xDEADBEEF; + +uint32 num_rand_calls = 0; + +uint32 rand(long n) { + num_rand_calls++; + return random(n); +} + +// -- Printing ---------------------------------------------------------------- + +// For snprintf() +char snprintf_buf[200]; + +#define ERR(fmt, ...) do { \ + snprintf(snprintf_buf, sizeof snprintf_buf, \ + "ERROR: " fmt " (seed %d, ncalls %d, line %d)", \ + __VA_ARGS__, seed, num_rand_calls, __LINE__); \ + Serial1.println(snprintf_buf); \ + } while (0) + +// -- setup()/loop() ---------------------------------------------------------- + +void setup() { + fsmc_sram_init_gpios(); + rcc_clk_enable(RCC_FSMC); + + for (int i = 0; i < N; i++) { + *bcrs[i] = (FSMC_BCR_WREN | + FSMC_BCR_MTYP_SRAM | + FSMC_BCR_MWID_16BITS | + FSMC_BCR_MBKEN); + *btrs[i] = (DATAST << 8) | ADDSET; + } + + Serial1.begin(115200); + randomSeed(seed); +} + +// stress_test() and simple_roundtrip() are the available test routines +bool stress_test(void); +bool simple_roundtrip(void); + +void loop() { + uint32 count = 0; + bool ok = true; + bool (*test)(void) = stress_test; + + while (true) { + count++; + bool result = test(); + ok = ok && result; + if (ok) { + snprintf(snprintf_buf, sizeof snprintf_buf, + "everything ok so far, timestamp %d ms", millis()); + Serial1.println(snprintf_buf); + } + } +} + +// -- Test routines ----------------------------------------------------------- + +bool random_trips(); +bool sequential_trips(); + +bool stress_test(void) { + static int i = 0; + i = !i; + + switch (i) { + case 0: + return random_trips(); + default: + return sequential_trips(); + } +} + +bool simple_roundtrip(void) { + uint16 wval = 0xAB; + + for (int i = 0; i < N; i++) { + __io uint16 *addr = starts[i] + 4; + snprintf(snprintf_buf, sizeof snprintf_buf, "round-trip 0x%x at %p", + wval, addr); + Serial1.println(snprintf_buf); + + *addr = wval; + uint16 rval = *addr; + + if (rval != wval) { + ERR("wrote 0x%x, read 0x%x, timestamp %d", wval, rval, millis()); + return false; + } else { + snprintf(snprintf_buf, sizeof snprintf_buf, "got back 0x%x", rval); + Serial1.println(snprintf_buf); + } + } + + return true; +} + +bool random_trips(void) { + for (int n = 0; n < N; n++) { + __io uint16 *const start = starts[n]; + + for (int i = 0; i < 1000; i++) { + uint32 offset = rand(MEM_SIZE); + uint32 wval = rand(0xFFFF); + + *(start + offset) = wval; + uint32 rval = *(start + offset); + + if (rval != wval) { + ERR("wrote 0x%x to 0x%x, read 0x%x", wval, offset, rval); + return false; + } + } + } + return true; +} + +bool sequential_trips(void) { + static const uint32 seq_length = 300; + + for (int n = 0; n < N; n++) { + __io uint16 *const start = starts[n]; + + for (int i = 0; i < 100; i++) { + uint32 start_offset = rand(MEM_SIZE - seq_length); + + for (uint32 w = 0; w < seq_length; w++) { + uint32 offset = start_offset + w; + + *(start + offset) = w; + uint32 r = *(start + offset); + + if (w != r) { + ERR("wrote 0x%x to 0x%x, read 0x%x", w, offset, r); + return false; + } + } + } + } + return true; +} + +// ---------------------------------------------------------------------------- + +__attribute__((constructor)) void premain() { + init(); +} + +int main(void) { + setup(); + while (true) { + loop(); + } + return 0; +} + diff --git a/examples/test-fsmc.cpp b/examples/test-fsmc.cpp index 4211e4d..7db3bb7 100644 --- a/examples/test-fsmc.cpp +++ b/examples/test-fsmc.cpp @@ -1,113 +1,125 @@ +#include // for ptrdiff_t + #include "wirish.h" #include "fsmc.h" -#define LED_PIN BOARD_LED_PIN - -// System control block registers -#define SCB_BASE (SCB_Reg*)(0xE000ED00) - -// This stuff should ultimately get moved to util.h or scb.h or w/e. -// Also in interactive test program and the HardFault IRQ handler. -typedef struct { - volatile uint32 CPUID; - volatile uint32 ICSR; - volatile uint32 VTOR; - volatile uint32 AIRCR; - volatile uint32 SCR; - volatile uint32 CCR; - volatile uint32 SHPR1; - volatile uint32 SHPR2; - volatile uint32 SHPR3; - volatile uint32 SHCRS; - volatile uint32 CFSR; - volatile uint32 HFSR; - uint32 pad1; - volatile uint32 MMAR; - volatile uint32 BFAR; -} SCB_Reg; - -SCB_Reg *scb; - -uint16 *ptr; -int count = 0; +#ifndef BOARD_maple_native +#error "Sorry, this example only works on Maple Native." +#endif + +// Start of FSMC SRAM bank 1 +static uint16 *const sram_start = (uint16*)0x60000000; +// End of Maple Native SRAM chip address space (512K 16-bit words) +static uint16 *const sram_end = (uint16*)0x60080000; + +void test_single_write(void); +void test_all_addresses(void); void setup() { - uint32 id; - scb = (SCB_Reg*)SCB_BASE; - - pinMode(LED_PIN, OUTPUT); - digitalWrite(LED_PIN,1); - - Serial1.begin(9600); - Serial1.println("Hello World!"); - - Serial1.print("Init... "); - fsmc_native_sram_init(); - Serial1.println("Done."); - - // Start of channel1 SRAM bank (through to 0x63FFFFFF, though only a chunk - // of this is valid) - ptr = (uint16*)(0x60000000); - - Serial1.print("Writing... "); - *ptr = 0x1234; - Serial1.println("Done."); - - Serial1.print("Reading... "); - id = *ptr; - Serial1.print("Done: "); // shouldn't be 0xFFFFFFFF - Serial1.println(id,BIN); - - Serial1.println("Dumping System Control Block Registers"); - Serial1.print("CPUID: "); - id = scb->CPUID; - Serial1.println(id,BIN); - Serial1.print("ICSR: "); - id = scb->ICSR; - Serial1.println(id,BIN); - Serial1.print("CFSR: "); - id = scb->CFSR; - Serial1.println(id,BIN); - Serial1.print("HFSR: "); - id = scb->HFSR; - Serial1.println(id,BIN); - Serial1.print("MMAR: "); - id = scb->MMAR; - Serial1.println(id,BIN); - Serial1.print("BFAR: "); - id = scb->BFAR; - Serial1.println(id,BIN); - - Serial1.println("Now testing all memory addresses... (will hardfault at the end)"); - delay(3000); + pinMode(BOARD_LED_PIN, OUTPUT); + digitalWrite(BOARD_LED_PIN, HIGH); + + Serial1.begin(115200); + Serial1.println("*** Beginning RAM chip test"); + + test_single_write(); + test_all_addresses(); + + Serial1.println("Tests pass, finished."); } void loop() { - toggleLED(); - delay(1); - - for(int i = 0; i<100; i++) { // modify this to speed things up - count++; - ptr++; - //delay(10); // tweak this to test SRAM resiliance over time - *ptr = (0x0000FFFF & count); - if(*ptr != (0x0000FFFF & count)) { - Serial1.println("ERROR: mismatch, halting"); - while(1) { } +} + +void test_single_write() { + uint16 *ptr = sram_start; + uint16 tmp; + + Serial1.print("Writing 0x1234... "); + *ptr = 0x1234; + Serial1.println("Done."); + + Serial1.print("Reading... "); + tmp = *ptr; + Serial1.print("Done: 0x"); + Serial1.println(tmp, HEX); + + if (tmp != 0x1234) { + Serial1.println("Mismatch; abort."); + ASSERT(0); + } +} + +void test_all_addresses() { + uint32 start, end; + uint16 count = 0; + uint16 *ptr; + + Serial1.println("Now writing all memory addresses (unrolled loop)"); + // Turn off the USB interrupt, as it interferes most with timing + // (don't turn off SysTick, or we won't get micros()). + SerialUSB.end(); + start = micros(); + for (ptr = sram_start; ptr < sram_end;) { + *ptr++ = count++; + *ptr++ = count++; + *ptr++ = count++; + *ptr++ = count++; + *ptr++ = count++; + *ptr++ = count++; + *ptr++ = count++; + *ptr++ = count++; + *ptr++ = count++; + *ptr++ = count++; + *ptr++ = count++; + *ptr++ = count++; + *ptr++ = count++; + *ptr++ = count++; + *ptr++ = count++; + *ptr++ = count++; + } + end = micros(); + SerialUSB.begin(); + Serial1.print("Done. Elapsed time (us): "); + Serial1.println(end - start); + + Serial1.println("Validating writes."); + for (ptr = sram_start, count = 0; ptr < sram_end; ptr++, count++) { + uint16 value = *ptr; + if (value != count) { + Serial1.print("mismatch: 0x"); + Serial1.print((uint32)ptr); + Serial1.print(" = 0x"); + Serial1.print(value, HEX); + Serial1.print(", should be 0x"); + Serial1.print(count, HEX); + Serial1.println("."); + ASSERT(0); } - } + } + Serial1.println("Done; all writes seem valid."); + + ptrdiff_t nwrites = sram_end - sram_start; + double us_per_write = double(end-start) / double(nwrites); + Serial1.print("Number of writes = "); + Serial1.print(nwrites); + Serial1.print("; avg. time per write = "); + Serial1.print(us_per_write); + Serial1.print(" us ("); + Serial1.print(1 / us_per_write); + Serial1.println(" MHz)"); +} - Serial1.print((uint32)(ptr),HEX); - Serial1.print(": "); - Serial1.println(*ptr,BIN); +__attribute__((constructor)) void premain() { + init(); } int main(void) { - init(); - setup(); + setup(); + + while (true) { + loop(); + } - while (1) { - loop(); - } - return 0; + return 0; } diff --git a/libmaple/fsmc.c b/libmaple/fsmc.c index 1561add..70d7e0d 100644 --- a/libmaple/fsmc.c +++ b/libmaple/fsmc.c @@ -33,19 +33,10 @@ #ifdef STM32_HIGH_DENSITY -/* These values determined for a particular SRAM chip by following the - * calculations in the ST FSMC application note. */ -#define FSMC_ADDSET 0x0 -#define FSMC_DATAST 0x3 - -/* Sets up the FSMC peripheral to use the SRAM chip on the maple - * native as an external segment of system memory space. This - * implementation is for the IS62WV51216BLL 8mbit chip (55ns - * timing) */ -void fsmc_native_sram_init(void) { - FSMC_Bank *bank; - - /* First we setup all the GPIO pins. */ +/** + * Configure FSMC GPIOs for use with SRAM. + */ +void fsmc_sram_init_gpios(void) { /* Data lines... */ gpio_set_mode(GPIOD, 0, GPIO_AF_OUTPUT_PP); gpio_set_mode(GPIOD, 1, GPIO_AF_OUTPUT_PP); @@ -96,42 +87,6 @@ void fsmc_native_sram_init(void) { gpio_set_mode(GPIOE, 0, GPIO_AF_OUTPUT_PP); // NBL0 gpio_set_mode(GPIOE, 1, GPIO_AF_OUTPUT_PP); // NBL1 - - /* Next enable the clock */ - rcc_clk_enable(RCC_FSMC); - - /* Then we configure channel 1 the FSMC SRAM peripheral (all SRAM - * channels are in "Bank 1" of the FSMC) */ - bank = (FSMC_Bank*)(FSMC1_BASE); - - /* Everything else is cleared (BCR1) */ - bank->BCR = 0x0000; - - /* Memory type is SRAM */ - bank->BCR &= ~(FSMC_BCR_MTYP); // '00' - - /* Databus width is 16bits */ - bank->BCR &= ~(FSMC_BCR_MWID); - bank->BCR |= 0x1 << 4; // '01' - - /* Memory is nonmultiplexed */ - bank->BCR &= ~(FSMC_BCR_MUXEN); // '0' - - /* Need write enable to write to the chip */ - bank->BCR |= FSMC_BCR_WREN; - - /* Set ADDSET */ - bank->BTR &= ~(FSMC_BTR_ADDSET); - bank->BTR |= (FSMC_BTR_ADDSET | FSMC_ADDSET); - - /* Set DATAST */ - bank->BTR &= ~(FSMC_BTR_DATAST); - bank->BTR |= (FSMC_BTR_DATAST | (FSMC_DATAST << 8)); - - /* Enable channel 1 */ - bank->BCR |= FSMC_BCR_MBKEN; // '1' - - /* (FSMC_BWTR3 not used for this simple configuration.) */ } #endif /* STM32_HIGH_DENSITY */ diff --git a/libmaple/fsmc.h b/libmaple/fsmc.h index fed6894..fccaf0b 100644 --- a/libmaple/fsmc.h +++ b/libmaple/fsmc.h @@ -39,55 +39,273 @@ extern "C"{ #ifdef STM32_HIGH_DENSITY -// There are 4 FSMC chip-select devices; here are the SRAM-specific registers -// for each - -#define FSMC1_BASE 0xA0000000 -#define FSMC2_BASE 0xA0000008 -#define FSMC3_BASE 0xA0000010 -#define FSMC4_BASE 0xA0000018 - -typedef struct { - volatile uint32 BCR; - volatile uint32 BTR; - //uint32 pad[62]; // double check this? - //__io uint32 BWTR; -} FSMC_Bank; - -// And here are the register bit ranges -#define FSMC_BCR_MBKEN 0b00000000000000000000000000000001 -#define FSMC_BCR_MUXEN 0b00000000000000000000000000000010 -#define FSMC_BCR_MTYP 0b00000000000000000000000000001100 -#define FSMC_BCR_MWID 0b00000000000000000000000000110000 -#define FSMC_BCR_FACCEN 0b00000000000000000000000001000000 -#define FSMC_BCR_BURSTEN 0b00000000000000000000000100000000 -#define FSMC_BCR_WAITPOL 0b00000000000000000000001000000000 -#define FSMC_BCR_WRAPMOD 0b00000000000000000000010000000000 -#define FSMC_BCR_WAITCFG 0b00000000000000000000100000000000 -#define FSMC_BCR_WREN 0b00000000000000000001000000000000 -#define FSMC_BCR_WAITEN 0b00000000000000000010000000000000 -#define FSMC_BCR_EXTMOD 0b00000000000000000100000000000000 -#define FSMC_BCR_CBURSTRW 0b00000000000010000000000000000000 -#define FSMC_BTR_ADDSET 0b00000000000000000000000000001111 -#define FSMC_BTR_ADDHOLD 0b00000000000000000000000011110000 -#define FSMC_BTR_DATAST 0b00000000000000001111111100000000 -#define FSMC_BTR_BUSTURN 0b00000000000011110000000000000000 -#define FSMC_BTR_CLKDIV 0b00000000111100000000000000000000 -#define FSMC_BTR_DATALAT 0b00001111000000000000000000000000 -#define FSMC_BTR_ACCMOD 0b00110000000000000000000000000000 -#define FSMC_BWTR_ADDSET 0b00000000000000000000000000001111 -#define FSMC_BWTR_ADDHLD 0b00000000000000000000000011110000 -#define FSMC_BWTR_DATAST 0b00000000000000001111111100000000 -#define FSMC_BWTR_CLKDIV 0b00000000111100000000000000000000 -#define FSMC_BWTR_DATLAT 0b00001111000000000000000000000000 -#define FSMC_BWTR_ACCMOD 0b00110000000000000000000000000000 - -void fsmc_native_sram_init(void); +/* + * Register maps and devices + */ + +/** FSMC register map type */ +typedef struct fsmc_reg_map { + __io uint32 BCR1; /**< SRAM/NOR-Flash chip-select control register 1 */ + __io uint32 BTR1; /**< SRAM/NOR-Flash chip-select timing register 1 */ + __io uint32 BCR2; /**< SRAM/NOR-Flash chip-select control register 2 */ + __io uint32 BTR2; /**< SRAM/NOR-Flash chip-select timing register 2 */ + __io uint32 BCR3; /**< SRAM/NOR-Flash chip-select control register 3 */ + __io uint32 BTR3; /**< SRAM/NOR-Flash chip-select timing register 3 */ + __io uint32 BCR4; /**< SRAM/NOR-Flash chip-select control register 4 */ + __io uint32 BTR4; /**< SRAM/NOR-Flash chip-select timing register 4 */ + const uint8 RESERVED1[64]; /**< Reserved */ + __io uint32 PCR2; /**< PC Card/NAND Flash control register 2 */ + __io uint32 SR2; /**< FIFO status and interrupt register 2 */ + __io uint32 PMEM2; /**< Common memory space timing register 2 */ + __io uint32 PATT2; /**< Attribute memory space timing register 2 */ + const uint8 RESERVED2[4]; /**< Reserved */ + __io uint32 ECCR2; /**< ECC result register 2 */ + const uint8 RESERVED3[2]; + __io uint32 PCR3; /**< PC Card/NAND Flash control register 3 */ + __io uint32 SR3; /**< FIFO status and interrupt register 3 */ + __io uint32 PMEM3; /**< Common memory space timing register 3 */ + __io uint32 PATT3; /**< Attribute memory space timing register 3 */ + const uint32 RESERVED4; /**< Reserved */ + __io uint32 ECCR3; /**< ECC result register 3 */ + const uint8 RESERVED5[8]; /**< Reserved */ + __io uint32 PCR4; /**< PC Card/NAND Flash control register 4 */ + __io uint32 SR4; /**< FIFO status and interrupt register 4 */ + __io uint32 PMEM4; /**< Common memory space timing register 4 */ + __io uint32 PATT4; /**< Attribute memory space timing register 4 */ + __io uint32 PIO4; /**< I/O space timing register 4 */ + const uint8 RESERVED6[80]; /**< Reserved */ + __io uint32 BWTR1; /**< SRAM/NOR-Flash write timing register 1 */ + const uint32 RESERVED7; /**< Reserved */ + __io uint32 BWTR2; /**< SRAM/NOR-Flash write timing register 2 */ + const uint32 RESERVED8; /**< Reserved */ + __io uint32 BWTR3; /**< SRAM/NOR-Flash write timing register 3 */ + const uint32 RESERVED9; /**< Reserved */ + __io uint32 BWTR4; /**< SRAM/NOR-Flash write timing register 4 */ +} __attribute__((packed)) fsmc_reg_map; + +#define __FSMC_B 0xA0000000 + +/** FSMC register map base pointer */ +#define FSMC_BASE ((struct fsmc_reg_map*)__FSMC_B) + +/** FSMC NOR/PSRAM register map type */ +typedef struct fsmc_nor_psram_reg_map { + __io uint32 BCR; /**< Chip-select control register */ + __io uint32 BTR; /**< Chip-select timing register */ + const uint8 RESERVED[252]; /**< Reserved */ + __io uint32 BWTR; /**< Write timing register */ +} fsmc_nor_psram_reg_map; + +/** FSMC NOR/PSRAM base pointer 1 */ +#define FSMC_NOR_PSRAM1_BASE ((struct fsmc_nor_psram_reg_map*)__FSMC_B) + +/** FSMC NOR/PSRAM base pointer 2 */ +#define FSMC_NOR_PSRAM2_BASE ((struct fsmc_nor_psram_reg_map*)(__FSMC_B + 0x8)) + +/** FSMC NOR/PSRAM base pointer 3 */ +#define FSMC_NOR_PSRAM3_BASE ((struct fsmc_nor_psram_reg_map*)(__FSMC_B+0x10)) + +/** FSMC NOR/PSRAM base pointer 4 */ +#define FSMC_NOR_PSRAM4_BASE ((struct fsmc_nor_psram_reg_map*)(__FSMC_B+0x18)) + +/* + * Register bit definitions + */ + +/* NOR/PSRAM chip-select control registers */ + +#define FSMC_BCR_CBURSTRW_BIT 19 +#define FSMC_BCR_ASYNCWAIT_BIT 15 +#define FSMC_BCR_EXTMOD_BIT 14 +#define FSMC_BCR_WAITEN_BIT 13 +#define FSMC_BCR_WREN_BIT 12 +#define FSMC_BCR_WAITCFG_BIT 11 +#define FSMC_BCR_WRAPMOD_BIT 10 +#define FSMC_BCR_WAITPOL_BIT 9 +#define FSMC_BCR_BURSTEN_BIT 8 +#define FSMC_BCR_FACCEN_BIT 6 +#define FSMC_BCR_MUXEN_BIT 1 +#define FSMC_BCR_MBKEN_BIT 0 + +#define FSMC_BCR_CBURSTRW BIT(FSMC_BCR_CBURSTRW_BIT) +#define FSMC_BCR_ASYNCWAIT BIT(FSMC_BCR_ASYNCWAIT_BIT) +#define FSMC_BCR_EXTMOD BIT(FSMC_BCR_EXTMOD_BIT) +#define FSMC_BCR_WAITEN BIT(FSMC_BCR_WAITEN_BIT) +#define FSMC_BCR_WREN BIT(FSMC_BCR_WREN_BIT) +#define FSMC_BCR_WAITCFG BIT(FSMC_BCR_WAITCFG_BIT) +#define FSMC_BCR_WRAPMOD BIT(FSMC_BCR_WRAPMOD_BIT) +#define FSMC_BCR_WAITPOL BIT(FSMC_BCR_WAITPOL_BIT) +#define FSMC_BCR_BURSTEN BIT(FSMC_BCR_BURSTEN_BIT) +#define FSMC_BCR_FACCEN BIT(FSMC_BCR_FACCEN_BIT) +#define FSMC_BCR_MWID (0x3 << 4) +#define FSMC_BCR_MWID_8BITS (0x0 << 4) +#define FSMC_BCR_MWID_16BITS (0x1 << 4) +#define FSMC_BCR_MTYP (0x3 << 2) +#define FSMC_BCR_MTYP_SRAM (0x0 << 2) +#define FSMC_BCR_MTYP_PSRAM (0x1 << 2) +#define FSMC_BCR_MTYP_NOR_FLASH (0x2 << 2) +#define FSMC_BCR_MUXEN BIT(FSMC_BCR_MUXEN_BIT) +#define FSMC_BCR_MBKEN BIT(FSMC_BCR_MBKEN_BIT) + +/* SRAM/NOR-Flash chip-select timing registers */ + +#define FSMC_BTR_ACCMOD (0x3 << 28) +#define FSMC_BTR_ACCMOD_A (0x0 << 28) +#define FSMC_BTR_ACCMOD_B (0x1 << 28) +#define FSMC_BTR_ACCMOD_C (0x2 << 28) +#define FSMC_BTR_ACCMOD_D (0x3 << 28) +#define FSMC_BTR_DATLAT (0xF << 24) +#define FSMC_BTR_CLKDIV (0xF << 20) +#define FSMC_BTR_BUSTURN (0xF << 16) +#define FSMC_BTR_DATAST (0xFF << 8) +#define FSMC_BTR_ADDHLD (0xF << 4) +#define FSMC_BTR_ADDSET 0xF + +/* SRAM/NOR-Flash write timing registers */ + +#define FSMC_BWTR_ACCMOD (0x3 << 28) +#define FSMC_BWTR_ACCMOD_A (0x0 << 28) +#define FSMC_BWTR_ACCMOD_B (0x1 << 28) +#define FSMC_BWTR_ACCMOD_C (0x2 << 28) +#define FSMC_BWTR_ACCMOD_D (0x3 << 28) +#define FSMC_BWTR_DATLAT (0xF << 24) +#define FSMC_BWTR_CLKDIV (0xF << 20) +#define FSMC_BWTR_DATAST (0xFF << 8) +#define FSMC_BWTR_ADDHLD (0xF << 4) +#define FSMC_BWTR_ADDSET 0xF + +/* NAND Flash/PC Card controller registers */ + +#define FSMC_PCR_ECCEN_BIT 6 +#define FSMC_PCR_PTYP_BIT 3 +#define FSMC_PCR_PBKEN_BIT 2 +#define FSMC_PCR_PWAITEN_BIT 1 + +#define FSMC_PCR_ECCPS (0x7 << 17) +#define FSMC_PCR_ECCPS_256B (0x0 << 17) +#define FSMC_PCR_ECCPS_512B (0x1 << 17) +#define FSMC_PCR_ECCPS_1024B (0x2 << 17) +#define FSMC_PCR_ECCPS_2048B (0x3 << 17) +#define FSMC_PCR_ECCPS_4096B (0x4 << 17) +#define FSMC_PCR_ECCPS_8192B (0x5 << 17) +#define FSMC_PCR_TAR (0xF << 13) +#define FSMC_PCR_TCLR (0xF << 9) +#define FSMC_PCR_ECCEN BIT(FSMC_PCR_ECCEN_BIT) +#define FSMC_PCR_PWID (0x3 << 4) +#define FSMC_PCR_PWID_8BITS (0x0 << 4) +#define FSMC_PCR_PWID_16BITS (0x1 << 4) +#define FSMC_PCR_PTYP BIT(FSMC_PCR_PTYP_BIT) +#define FSMC_PCR_PTYP_PC_CF_PCMCIA (0x0 << FSMC_PCR_PTYP_BIT) +#define FSMC_PCR_PTYP_NAND (0x1 << FSMC_PCR_PTYP_BIT) +#define FSMC_PCR_PBKEN BIT(FSMC_PCR_PBKEN_BIT) +#define FSMC_PCR_PWAITEN BIT(FSMC_PCR_PWAITEN_BIT) + +/* FIFO status and interrupt registers */ + +#define FSMC_SR_FEMPT_BIT 6 +#define FSMC_SR_IFEN_BIT 5 +#define FSMC_SR_ILEN_BIT 4 +#define FSMC_SR_IREN_BIT 3 +#define FSMC_SR_IFS_BIT 2 +#define FSMC_SR_ILS_BIT 1 +#define FSMC_SR_IRS_BIT 0 + +#define FSMC_SR_FEMPT BIT(FSMC_SR_FEMPT_BIT) +#define FSMC_SR_IFEN BIT(FSMC_SR_IFEN_BIT) +#define FSMC_SR_ILEN BIT(FSMC_SR_ILEN_BIT) +#define FSMC_SR_IREN BIT(FSMC_SR_IREN_BIT) +#define FSMC_SR_IFS BIT(FSMC_SR_IFS_BIT) +#define FSMC_SR_ILS BIT(FSMC_SR_ILS_BIT) +#define FSMC_SR_IRS BIT(FSMC_SR_IRS_BIT) + +/* Common memory space timing registers */ + +#define FSMC_PMEM_MEMHIZ (0xFF << 24) +#define FSMC_PMEM_MEMHOLD (0xFF << 16) +#define FSMC_PMEM_MEMWAIT (0xFF << 8) +#define FSMC_PMEM_MEMSET 0xFF + +/* Attribute memory space timing registers */ + +#define FSMC_PATT_ATTHIZ (0xFF << 24) +#define FSMC_PATT_ATTHOLD (0xFF << 16) +#define FSMC_PATT_ATTWAIT (0xFF << 8) +#define FSMC_PATT_ATTSET 0xFF + +/* I/O space timing register 4 */ + +#define FSMC_PIO_IOHIZ (0xFF << 24) +#define FSMC_PIO_IOHOLD (0xFF << 16) +#define FSMC_PIO_IOWAIT (0xFF << 8) +#define FSMC_PIO_IOSET 0xFF + +/* + * Memory bank boundary addresses + */ + +/** Pointer to base address of FSMC memory bank 1 (split into 4 + * regions, each supporting 1 NOR Flash, SRAM, or PSRAM chip) */ +#define FSMC_BANK1 ((void*)0x60000000) + +/** Pointer to base address of FSMC memory bank 1, region 1 (for NOR/PSRAM) */ +#define FSMC_NOR_PSRAM_REGION1 FSMC_BANK1 + +/** Pointer to base address of FSMC memory bank 1, region 2 (for NOR/PSRAM) */ +#define FSMC_NOR_PSRAM_REGION2 ((void*)0x64000000) + +/** Pointer to base address of FSMC memory bank 1, region 3 (for NOR/PSRAM) */ +#define FSMC_NOR_PSRAM_REGION3 ((void*)0x68000000) + +/** Pointer to base address of FSMC memory bank 1, region 4 (for NOR/PSRAM) */ +#define FSMC_NOR_PSRAM_REGION4 ((void*)0x6C000000) + +/** Pointer to base address of FSMC memory bank 2 (for NAND Flash) */ +#define FSMC_BANK2 ((void*)0x70000000) + +/** Pointer to base address of FSMC memory bank 3 (for NAND Flash) */ +#define FSMC_BANK3 ((void*)0x80000000) + +/** Pointer to base address of FSMC memory bank 4 (for PC card devices */ +#define FSMC_BANK4 ((void*)0x90000000) + +/* + * SRAM/NOR Flash routines + */ + +void fsmc_sram_init_gpios(void); + +/** + * Set the DATAST bits in the given NOR/PSRAM register map's + * chip-select timing register (FSMC_BTR). + * + * @param regs NOR Flash/PSRAM register map whose chip-select timing + * register to set. + * @param datast Value to use for DATAST bits. + */ +static inline void fsmc_nor_psram_set_datast(fsmc_nor_psram_reg_map *regs, + uint8 datast) { + regs->BTR &= ~FSMC_BTR_DATAST; + regs->BTR |= datast << 8; +} + +/** + * Set the ADDHLD bits in the given NOR/PSRAM register map's chip + * select timing register (FSMC_BTRx). + * + * @param regs NOR Flash/PSRAM register map whose chip-select timing + * register to set. + * @param addset Value to use for ADDSET bits. + */ +static inline void fsmc_nor_psram_set_addset(fsmc_nor_psram_reg_map *regs, + uint8 addset) { + regs->BTR &= ~FSMC_BTR_ADDSET; + regs->BTR |= addset & 0xF; +} #endif /* STM32_HIGH_DENSITY */ #ifdef __cplusplus -} // extern "C" +} /* extern "C" */ #endif #endif diff --git a/wirish/native_sram.cpp b/wirish/native_sram.cpp new file mode 100644 index 0000000..5e8095f --- /dev/null +++ b/wirish/native_sram.cpp @@ -0,0 +1,45 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +#include "native_sram.h" +#include "libmaple.h" +#include "fsmc.h" +#include "rcc.h" + +#ifdef BOARD_maple_native + +void initNativeSRAM(void) { + fsmc_nor_psram_reg_map *regs = FSMC_NOR_PSRAM1_BASE; + + fsmc_sram_init_gpios(); + rcc_clk_enable(RCC_FSMC); + + regs->BCR = FSMC_BCR_WREN | FSMC_BCR_MWID_16BITS | FSMC_BCR_MBKEN; + fsmc_nor_psram_set_addset(regs, 0); + fsmc_nor_psram_set_datast(regs, 3); +} + +#endif diff --git a/wirish/native_sram.h b/wirish/native_sram.h new file mode 100644 index 0000000..7724667 --- /dev/null +++ b/wirish/native_sram.h @@ -0,0 +1,43 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +#ifdef BOARD_maple_native + +#ifndef _NATIVE_SRAM_H_ +#define _NATIVE_SRAM_H_ + +/** + * Sets up the FSMC peripheral to use the SRAM chip on the Maple + * Native as an external segment of system memory space. + * + * This implementation is for the IS62WV51216BLL 8Mb chip (55ns + * timing, 512K x 16 bits). + */ +void initNativeSRAM(void); + +#endif + +#endif diff --git a/wirish/rules.mk b/wirish/rules.mk index cea34f5..3dd4b2d 100644 --- a/wirish/rules.mk +++ b/wirish/rules.mk @@ -27,6 +27,7 @@ cppSRCS_$(d) := wirish_math.cpp \ pwm.cpp \ ext_interrupts.cpp \ wirish_digital.cpp \ + native_sram.cpp \ boards.cpp cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%) diff --git a/wirish/wirish.cpp b/wirish/wirish.cpp index 6d77bc8..c5a9e30 100644 --- a/wirish/wirish.cpp +++ b/wirish/wirish.cpp @@ -41,6 +41,7 @@ #include "fsmc.h" #include "dac.h" #include "flash.h" +#include "native_sram.h" void init(void) { /* make sure the flash is ready before spinning the high speed clock up */ @@ -48,7 +49,7 @@ void init(void) { flash_set_latency(FLASH_WAIT_STATE_2); #ifdef BOARD_maple_native - fsmc_native_sram_init(); + initNativeSRAM(); #endif /* initialize clocks */ -- cgit v1.2.3 From 77a0f70e491da2a26323d24b4c1d65320996c469 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Thu, 17 Mar 2011 07:47:19 -0400 Subject: Fixing typo in libmaple/usb/descriptors.h; thanks, StephenFromNYC! http://forums.leaflabs.com/topic.php?id=687 --- libmaple/usb/descriptors.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmaple/usb/descriptors.h b/libmaple/usb/descriptors.h index 6f7d08b..460a88c 100644 --- a/libmaple/usb/descriptors.h +++ b/libmaple/usb/descriptors.h @@ -61,7 +61,7 @@ extern "C" { uint16 bString[len]; \ } -#define CDC_FUCNTIONAL_DESCRIPTOR(DataSize) \ +#define CDC_FUNCTIONAL_DESCRIPTOR(DataSize) \ struct \ { \ uint8 bLength; \ -- cgit v1.2.3 From 7a7dff5186fa1b96f15c82672fc94432196d7eb5 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Thu, 17 Mar 2011 08:20:34 -0400 Subject: Adding rb_safe_remove() to ring_buffer.h --- libmaple/ring_buffer.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/libmaple/ring_buffer.h b/libmaple/ring_buffer.h index f7baa6c..6e9b250 100644 --- a/libmaple/ring_buffer.h +++ b/libmaple/ring_buffer.h @@ -78,6 +78,17 @@ static inline uint8 rb_remove(ring_buffer *rb) { return ch; } +/** + * If the ring buffer is nonempty, removes and returns its first item. + * If it is empty, does nothing and returns a negative value. + */ +static inline int16 rb_safe_remove(ring_buffer *rb) { + if (rb_full_count(rb) == 0) { + return -1; + } + return rb_remove(rb); +} + /** * If rb is not full, appends element and returns true; otherwise, * does nothing and returns false. */ -- cgit v1.2.3 From 6245b43b26e47ece1927d28246611488c2f36e67 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Thu, 17 Mar 2011 09:10:28 -0400 Subject: Fixing inefficient rb_safe_remove() implementation; thanks, geoffreymbrown! --- libmaple/ring_buffer.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libmaple/ring_buffer.h b/libmaple/ring_buffer.h index 6e9b250..3b5d4e7 100644 --- a/libmaple/ring_buffer.h +++ b/libmaple/ring_buffer.h @@ -65,6 +65,11 @@ static inline int rb_is_full(ring_buffer *rb) { (rb->tail == rb->size && rb->head == 0); } +/** Return true if and only if the ring buffer is empty. */ +static inline int rb_is_empty(ring_buffer *rb) { + return rb->head == rb->tail; +} + /** Append element onto the end of the ring buffer. */ static inline void rb_insert(ring_buffer *rb, uint8 element) { rb->buf[rb->tail] = element; @@ -83,10 +88,7 @@ static inline uint8 rb_remove(ring_buffer *rb) { * If it is empty, does nothing and returns a negative value. */ static inline int16 rb_safe_remove(ring_buffer *rb) { - if (rb_full_count(rb) == 0) { - return -1; - } - return rb_remove(rb); + return rb_is_empty(rb) ? -1 : rb_remove(rb); } /** -- cgit v1.2.3 From 403498a28956507bb3063e6d7c190639c0279f47 Mon Sep 17 00:00:00 2001 From: Perry Hung Date: Mon, 21 Mar 2011 02:25:23 -0400 Subject: Revert "RCC refactor, bugfixes" This reverts commit e4807a5010f59ab863ad2c96dc14caf65bf1ae60. --- libmaple/adc.c | 4 +- libmaple/adc.h | 6 +- libmaple/bkp.c | 4 +- libmaple/dac.c | 4 - libmaple/dac.h | 4 - libmaple/exti.c | 18 +- libmaple/gpio.c | 2 +- libmaple/rcc.c | 200 ++++++++------------ libmaple/rcc.h | 541 +++++++++++------------------------------------------- wirish/boards.cpp | 2 +- wirish/wirish.cpp | 2 +- 11 files changed, 212 insertions(+), 575 deletions(-) diff --git a/libmaple/adc.c b/libmaple/adc.c index 3d38596..9626a40 100644 --- a/libmaple/adc.c +++ b/libmaple/adc.c @@ -126,8 +126,8 @@ void adc_set_sample_rate(const adc_dev *dev, adc_smp_rate smp_rate) { * @param dev adc device */ static void adc_calibrate(const adc_dev *dev) { - __io uint32 *rstcal_bit = bb_perip(&(dev->regs->CR2), 3); - __io uint32 *cal_bit = bb_perip(&(dev->regs->CR2), 2); + __io uint32 *rstcal_bit = bb_peripv(&(dev->regs->CR2), 3); + __io uint32 *cal_bit = bb_peripv(&(dev->regs->CR2), 2); *rstcal_bit = 1; while (*rstcal_bit) diff --git a/libmaple/adc.h b/libmaple/adc.h index 53ef032..4811dbc 100644 --- a/libmaple/adc.h +++ b/libmaple/adc.h @@ -175,7 +175,7 @@ static inline uint32 adc_read(const adc_dev *dev, uint8 channel) { * @param enable If 1, conversion on external events is enabled, 0 to disable */ static inline void adc_set_exttrig(const adc_dev *dev, uint8 enable) { - *bb_perip(&dev->regs->CR2, 20) = !!enable; + *bb_peripv(&dev->regs->CR2, 20) = !!enable; } /** @@ -183,7 +183,7 @@ static inline void adc_set_exttrig(const adc_dev *dev, uint8 enable) { * @param dev ADC device to enable */ static inline void adc_enable(const adc_dev *dev) { - *bb_perip(&dev->regs->CR2, 0) = 1; + *bb_peripv(&dev->regs->CR2, 0) = 1; } /** @@ -191,7 +191,7 @@ static inline void adc_enable(const adc_dev *dev) { * @param dev ADC device to disable */ static inline void adc_disable(const adc_dev *dev) { - *bb_perip(&dev->regs->CR2, 0) = 0; + *bb_peripv(&dev->regs->CR2, 0) = 0; } /** diff --git a/libmaple/bkp.c b/libmaple/bkp.c index aaccb1f..b152069 100644 --- a/libmaple/bkp.c +++ b/libmaple/bkp.c @@ -57,14 +57,14 @@ void bkp_init(void) { * @see bkp_init() */ void bkp_enable_writes(void) { - *bb_perip(&PWR_BASE->CR, PWR_CR_DBP) = 1; + *bb_peripv(&PWR_BASE->CR, PWR_CR_DBP) = 1; } /** * Disable write access to the backup registers. */ void bkp_disable_writes(void) { - *bb_perip(&PWR_BASE->CR, PWR_CR_DBP) = 0; + *bb_peripv(&PWR_BASE->CR, PWR_CR_DBP) = 0; } /** diff --git a/libmaple/dac.c b/libmaple/dac.c index f0bdbcd..ef3a9f9 100644 --- a/libmaple/dac.c +++ b/libmaple/dac.c @@ -26,8 +26,6 @@ #include "gpio.h" #include "dac.h" -#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) - /** * @brief DAC peripheral routines. */ @@ -110,5 +108,3 @@ void dac_disable_channel(uint8 channel) { break; } } - -#endif diff --git a/libmaple/dac.h b/libmaple/dac.h index ee8a4e7..c897bb2 100644 --- a/libmaple/dac.h +++ b/libmaple/dac.h @@ -32,8 +32,6 @@ #ifndef _DAC_H_ #define _DAC_H_ -#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) - #include "rcc.h" #ifdef __cplusplus @@ -151,6 +149,4 @@ void dac_disable_channel(uint8 channel); } // extern "C" #endif -#endif /* STM32_HIGH_DENSITY, STM32_XL_DENSITY */ - #endif diff --git a/libmaple/exti.c b/libmaple/exti.c index 7f56712..8177e1e 100644 --- a/libmaple/exti.c +++ b/libmaple/exti.c @@ -98,14 +98,14 @@ void exti_attach_interrupt(afio_exti_num num, /* Set trigger mode */ switch (mode) { case EXTI_RISING: - *bb_perip(&EXTI_BASE->RTSR, num) = 1; + *bb_peripv(&EXTI_BASE->RTSR, num) = 1; break; case EXTI_FALLING: - *bb_perip(&EXTI_BASE->FTSR, num) = 1; + *bb_peripv(&EXTI_BASE->FTSR, num) = 1; break; case EXTI_RISING_FALLING: - *bb_perip(&EXTI_BASE->RTSR, num) = 1; - *bb_perip(&EXTI_BASE->FTSR, num) = 1; + *bb_peripv(&EXTI_BASE->RTSR, num) = 1; + *bb_peripv(&EXTI_BASE->FTSR, num) = 1; break; } @@ -113,7 +113,7 @@ void exti_attach_interrupt(afio_exti_num num, afio_exti_select(num, port); /* Unmask external interrupt request */ - *bb_perip(&EXTI_BASE->IMR, num) = 1; + *bb_peripv(&EXTI_BASE->IMR, num) = 1; /* Enable the interrupt line */ enable_irq(num); @@ -126,11 +126,11 @@ void exti_attach_interrupt(afio_exti_num num, */ void exti_detach_interrupt(afio_exti_num num) { /* First, mask the interrupt request */ - *bb_perip(&EXTI_BASE->IMR, num) = 0; + *bb_peripv(&EXTI_BASE->IMR, num) = 0; /* Then, clear the trigger selection registers */ - *bb_perip(&EXTI_BASE->FTSR, num) = 0; - *bb_perip(&EXTI_BASE->RTSR, num) = 0; + *bb_peripv(&EXTI_BASE->FTSR, num) = 0; + *bb_peripv(&EXTI_BASE->RTSR, num) = 0; /* Next, disable the IRQ, unless it's multiplexed and there are * other active external interrupts on the same IRQ line */ @@ -210,7 +210,7 @@ void __irq_exti15_10(void) { */ static inline void clear_pending(uint32 exti_num) { - *bb_perip(&EXTI_BASE->PR, exti_num) = 1; + *bb_peripv(&EXTI_BASE->PR, exti_num) = 1; /* If the pending bit is cleared as the last instruction in an ISR, * it won't actually be cleared in time and the ISR will fire again. * Insert a 2-cycle buffer to allow it to take effect. */ diff --git a/libmaple/gpio.c b/libmaple/gpio.c index 90be033..b08be12 100644 --- a/libmaple/gpio.c +++ b/libmaple/gpio.c @@ -61,7 +61,7 @@ static gpio_dev gpiod = { /** GPIO port D device. */ gpio_dev *GPIOD = &gpiod; -#ifdef STM32_HIGH_DENSITY +#ifdef STM32_HIGH_ static gpio_dev gpioe = { .regs = GPIOE_BASE, .clk_id = RCC_GPIOE diff --git a/libmaple/rcc.c b/libmaple/rcc.c index e49382c..2841af3 100644 --- a/libmaple/rcc.c +++ b/libmaple/rcc.c @@ -23,115 +23,97 @@ *****************************************************************************/ /** - * @file rcc.c - * @brief Clock setup, peripheral enable and reset routines. + * @brief Implements pretty much only the basic clock setup on the + * stm32, clock enable/disable and peripheral reset commands. */ #include "libmaple.h" #include "flash.h" #include "rcc.h" -#include "bitband.h" -typedef enum clock_domain { +enum { APB1, APB2, AHB -} clock_domain; +}; struct rcc_dev_info { - const clock_domain clk_domain; + const uint8 clk_domain; const uint8 line_num; }; /* device descriptor tables */ -static const __attr_flash struct rcc_dev_info rcc_dev_table[] = { - [RCC_SRAM] = { .clk_domain = AHB, .line_num = 2 }, - [RCC_GPIOA] = { .clk_domain = APB2, .line_num = 2 }, - [RCC_GPIOB] = { .clk_domain = APB2, .line_num = 3 }, - [RCC_GPIOC] = { .clk_domain = APB2, .line_num = 4 }, - [RCC_GPIOD] = { .clk_domain = APB2, .line_num = 5 }, - [RCC_AFIO] = { .clk_domain = APB2, .line_num = 0 }, - [RCC_ADC1] = { .clk_domain = APB2, .line_num = 9 }, - [RCC_ADC2] = { .clk_domain = APB2, .line_num = 10 }, - [RCC_USART1] = { .clk_domain = APB2, .line_num = 14 }, - [RCC_USART2] = { .clk_domain = APB1, .line_num = 17 }, - [RCC_USART3] = { .clk_domain = APB1, .line_num = 18 }, - [RCC_TIMER1] = { .clk_domain = APB2, .line_num = 11 }, - [RCC_TIMER2] = { .clk_domain = APB1, .line_num = 0 }, - [RCC_TIMER3] = { .clk_domain = APB1, .line_num = 1 }, - [RCC_TIMER4] = { .clk_domain = APB1, .line_num = 2 }, - [RCC_SPI1] = { .clk_domain = APB2, .line_num = 12 }, - [RCC_SPI2] = { .clk_domain = APB1, .line_num = 14 }, - [RCC_DMA1] = { .clk_domain = AHB, .line_num = 0 }, - [RCC_PWR] = { .clk_domain = APB1, .line_num = 28 }, - [RCC_BKP] = { .clk_domain = APB1, .line_num = 27 }, - [RCC_CAN] = { .clk_domain = APB1, .line_num = 25 }, - [RCC_USB] = { .clk_domain = APB1, .line_num = 23 }, - [RCC_I2C1] = { .clk_domain = APB1, .line_num = 22 }, - [RCC_I2C2] = { .clk_domain = APB1, .line_num = 21 }, - [RCC_CRC] = { .clk_domain = AHB, .line_num = 6 }, - [RCC_WWDG] = { .clk_domain = APB2, .line_num = 11 }, - [RCC_FLITF] = { .clk_domain = AHB, .line_num = 4 }, -#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) - [RCC_SDIO] = { .clk_domain = AHB, .line_num = 10 }, - [RCC_FSMC] = { .clk_domain = AHB, .line_num = 8 }, - [RCC_GPIOE] = { .clk_domain = APB2, .line_num = 6 }, - [RCC_GPIOF] = { .clk_domain = APB2, .line_num = 7 }, - [RCC_GPIOG] = { .clk_domain = APB2, .line_num = 8 }, - [RCC_ADC3] = { .clk_domain = APB2, .line_num = 15 }, - [RCC_UART4] = { .clk_domain = APB1, .line_num = 19 }, - [RCC_UART5] = { .clk_domain = APB1, .line_num = 20 }, - [RCC_TIMER5] = { .clk_domain = APB1, .line_num = 3 }, - [RCC_TIMER6] = { .clk_domain = APB1, .line_num = 4 }, - [RCC_TIMER7] = { .clk_domain = APB1, .line_num = 5 }, - [RCC_TIMER8] = { .clk_domain = APB2, .line_num = 13 }, - [RCC_DAC] = { .clk_domain = APB1, .line_num = 29 }, - [RCC_DMA2] = { .clk_domain = AHB, .line_num = 1 }, - [RCC_SPI3] = { .clk_domain = APB1, .line_num = 15 }, -#endif -#ifdef STM32_XL_DENSITY - [RCC_TIMER9] = { .clk_domain = APB2, .line_num = 19 }, - [RCC_TIMER10] = { .clk_domain = APB2, .line_num = 20 }, - [RCC_TIMER11] = { .clk_domain = APB2, .line_num = 21 }, - [RCC_TIMER12] = { .clk_domain = APB1, .line_num = 6 }, - [RCC_TIMER13] = { .clk_domain = APB1, .line_num = 7 }, - [RCC_TIMER14] = { .clk_domain = APB1, .line_num = 8 }, -#endif +static const struct rcc_dev_info rcc_dev_table[] = { + [RCC_GPIOA] = { .clk_domain = APB2, .line_num = 2 }, + [RCC_GPIOB] = { .clk_domain = APB2, .line_num = 3 }, + [RCC_GPIOC] = { .clk_domain = APB2, .line_num = 4 }, + [RCC_GPIOD] = { .clk_domain = APB2, .line_num = 5 }, + [RCC_GPIOE] = { .clk_domain = APB2, .line_num = 6 }, // High-density only + [RCC_GPIOF] = { .clk_domain = APB2, .line_num = 7 }, // High-density only + [RCC_GPIOG] = { .clk_domain = APB2, .line_num = 8 }, // High-density only + [RCC_AFIO] = { .clk_domain = APB2, .line_num = 0 }, + [RCC_ADC1] = { .clk_domain = APB2, .line_num = 9 }, + [RCC_ADC2] = { .clk_domain = APB2, .line_num = 10 }, + [RCC_ADC3] = { .clk_domain = APB2, .line_num = 15 }, + [RCC_USART1] = { .clk_domain = APB2, .line_num = 14 }, + [RCC_USART2] = { .clk_domain = APB1, .line_num = 17 }, + [RCC_USART3] = { .clk_domain = APB1, .line_num = 18 }, + [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 }, + [RCC_TIMER4] = { .clk_domain = APB1, .line_num = 2 }, + [RCC_TIMER5] = { .clk_domain = APB1, .line_num = 3 }, // High-density only + [RCC_TIMER6] = { .clk_domain = APB1, .line_num = 4 }, // High-density only + [RCC_TIMER7] = { .clk_domain = APB1, .line_num = 5 }, // High-density only + [RCC_TIMER8] = { .clk_domain = APB2, .line_num = 13 }, // High-density only + [RCC_SPI1] = { .clk_domain = APB2, .line_num = 12 }, + [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 = 29 }, // High-density only + [RCC_DMA1] = { .clk_domain = AHB, .line_num = 0 }, + [RCC_DMA2] = { .clk_domain = AHB, .line_num = 1 }, // High-density only + [RCC_PWR] = { .clk_domain = APB1, .line_num = 28}, + [RCC_BKP] = { .clk_domain = APB1, .line_num = 27} }; /** * @brief Initialize the clock control system. Initializes the system * clock source to use the PLL driven by an external oscillator * @param sysclk_src system clock source, must be PLL - * @param pll_src pll clock source, must be RCC_CFGR_PLLSRC_HSE + * @param pll_src pll clock source, must be HSE * @param pll_mul pll multiplier */ void rcc_clk_init(uint32 sysclk_src, uint32 pll_src, uint32 pll_mul) { - uint32 cfgr; - /* Assume that we're going to clock the chip off the PLL, fed by * the HSE */ ASSERT(sysclk_src == RCC_CLKSRC_PLL && - pll_src == RCC_CFGR_PLLSRC_HSE); + pll_src == RCC_PLLSRC_HSE); + + uint32 cfgr = 0; + uint32 cr = RCC_READ_CR(); - RCC_BASE->CFGR = pll_src | pll_mul; + cfgr = (pll_src | pll_mul); + RCC_WRITE_CFGR(cfgr); - /* Turn on the HSE */ - *bb_perip(&RCC_BASE->CR, RCC_CR_HSEON_BIT) = 1; - while (!(*bb_perip(&RCC_BASE->CR, RCC_CR_HSERDY_BIT))) + /* Turn on the HSE */ + cr |= RCC_CR_HSEON; + RCC_WRITE_CR(cr); + while (!(RCC_READ_CR() & RCC_CR_HSERDY)) ; - /* Now the PLL */ - *bb_perip(&RCC_BASE->CR, RCC_CR_PLLON_BIT) = 1; - while (!(*bb_perip(&RCC_BASE->CR, RCC_CR_PLLRDY_BIT))) + /* Now the PLL */ + cr |= RCC_CR_PLLON; + RCC_WRITE_CR(cr); + while (!(RCC_READ_CR() & RCC_CR_PLLRDY)) ; /* Finally, let's switch over to the PLL */ - cfgr = RCC_BASE->CFGR; cfgr &= ~RCC_CFGR_SW; cfgr |= RCC_CFGR_SW_PLL; - RCC_BASE->CFGR = cfgr; - while ((RCC_BASE->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) + RCC_WRITE_CFGR(cfgr); + while ((RCC_READ_CFGR() & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) ; } @@ -139,23 +121,16 @@ void rcc_clk_init(uint32 sysclk_src, uint32 pll_src, uint32 pll_mul) { * @brief Turn on the clock line on a device * @param device Clock ID of the device to turn on. */ -void rcc_clk_enable(rcc_clk_id id) { - uint8 lnum = rcc_dev_table[id].line_num; - __io uint32 *enr; - - switch(rcc_dev_table[id].clk_domain) { - case APB1: - enr = &RCC_BASE->APB1ENR; - break; - case APB2: - enr = &RCC_BASE->APB2ENR; - break; - case AHB: - enr = &RCC_BASE->AHBENR; - break; - } - - *bb_perip(enr, lnum) = 1; +void rcc_clk_enable(rcc_clk_id device) { + static const uint32 enable_regs[] = { + [APB1] = RCC_APB1ENR, + [APB2] = RCC_APB2ENR, + [AHB] = RCC_AHBENR, + }; + + uint8 clk_domain = rcc_dev_table[device].clk_domain; + + __set_bits(enable_regs[clk_domain], BIT(rcc_dev_table[device].line_num)); } /** @@ -163,7 +138,7 @@ void rcc_clk_enable(rcc_clk_id id) { * @param prescaler prescaler to set * @param divider prescaler divider */ -void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider) { +void rcc_set_prescaler(uint32 prescaler, uint32 divider) { static const uint32 masks[] = { [RCC_PRESCALER_AHB] = RCC_CFGR_HPRE, [RCC_PRESCALER_APB1] = RCC_CFGR_PPRE1, @@ -171,39 +146,26 @@ void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider) { [RCC_PRESCALER_USB] = RCC_CFGR_USBPRE, [RCC_PRESCALER_ADC] = RCC_CFGR_ADCPRE, }; - uint32 cfgr; - cfgr = RCC_BASE->CFGR; + uint32 cfgr = RCC_READ_CFGR(); + cfgr &= ~masks[prescaler]; cfgr |= divider; - RCC_BASE->CFGR = cfgr; + RCC_WRITE_CFGR(cfgr); } /** - * @brief Reset a device - * @param device Clock ID of the device to reset; the device must be - * on APB1 or APB2. + * @brief reset a device + * @param device Clock ID of the device to reset. */ -void rcc_reset_dev(rcc_clk_id id) { - uint8 lnum = rcc_dev_table[id].line_num; - __io uint32 *rstr = 0; - - switch (rcc_dev_table[id].clk_domain) { - case APB1: - rstr = &RCC_BASE->APB1RSTR; - break; - case APB2: - rstr = &RCC_BASE->APB2RSTR; - break; - case AHB: - ASSERT(0); - break; - } - - if (rstr == 0) { - return; - } - - *bb_perip(rstr, lnum) = 1; - *bb_perip(rstr, lnum) = 0; +void rcc_reset_dev(rcc_clk_id device) { + static const uint32 reset_regs[] = { + [APB1] = RCC_APB1RSTR, + [APB2] = RCC_APB2RSTR, + }; + + uint8 clk_domain = rcc_dev_table[device].clk_domain; + + __set_bits(reset_regs[clk_domain], BIT(rcc_dev_table[device].line_num)); + __clear_bits(reset_regs[clk_domain], BIT(rcc_dev_table[device].line_num)); } diff --git a/libmaple/rcc.h b/libmaple/rcc.h index 83b34ed..8697e01 100644 --- a/libmaple/rcc.h +++ b/libmaple/rcc.h @@ -24,7 +24,7 @@ /** * @file rcc.h - * @brief Reset and clock control (RCC) definitions and prototypes + * @brief reset and clock control definitions and prototypes */ #include "libmaple_types.h" @@ -36,451 +36,78 @@ extern "C"{ #endif -/** RCC register map type */ -typedef struct rcc_reg_map { - __io uint32 CR; /**< Clock control register */ - __io uint32 CFGR; /**< Clock configuration register */ - __io uint32 CIR; /**< Clock interrupt register */ - __io uint32 APB2RSTR; /**< APB2 peripheral reset register */ - __io uint32 APB1RSTR; /**< APB1 peripheral reset register */ - __io uint32 AHBENR; /**< AHB peripheral clock enable register */ - __io uint32 APB2ENR; /**< APB2 peripheral clock enable register */ - __io uint32 APB1ENR; /**< APB1 peripheral clock enable register */ - __io uint32 BDCR; /**< Backup domain control register */ - __io uint32 CSR; /**< Control/status register */ -} rcc_reg_map; - -/* - * RCC register map base address - */ - -#define RCC_BASE ((rcc_reg_map*)0x40021000) - -/* - * RCC register bit definitions - */ - -/* Clock control register */ - -#define RCC_CR_PLLRDY_BIT 25 -#define RCC_CR_PLLON_BIT 24 -#define RCC_CR_CSSON_BIT 19 -#define RCC_CR_HSEBYP_BIT 18 -#define RCC_CR_HSERDY_BIT 17 -#define RCC_CR_HSEON_BIT 16 -#define RCC_CR_HSIRDY_BIT 1 -#define RCC_CR_HSION_BIT 0 - -#define RCC_CR_PLLRDY BIT(RCC_CR_PLLRDY_BIT) -#define RCC_CR_PLLON BIT(RCC_CR_PLLON_BIT) -#define RCC_CR_CSSON BIT(RCC_CR_CSSON_BIT) -#define RCC_CR_HSEBYP BIT(RCC_CR_HSEBYP_BIT) -#define RCC_CR_HSERDY BIT(RCC_CR_HSERDY_BIT) -#define RCC_CR_HSEON BIT(RCC_CR_HSEON_BIT) -#define RCC_CR_HSICAL (0xFF << 8) -#define RCC_CR_HSITRIM (0x1F << 3) -#define RCC_CR_HSIRDY BIT(RCC_CR_HSIRDY_BIT) -#define RCC_CR_HSION BIT(RCC_CR_HSION_BIT) - -/* Clock configuration register */ - -#define RCC_CFGR_USBPRE_BIT 22 -#define RCC_CFGR_PLLXTPRE_BIT 17 -#define RCC_CFGR_PLLSRC_BIT 16 - -#define RCC_CFGR_MCO (0x7 << 24) -#define RCC_CFGR_USBPRE BIT(RCC_CFGR_USBPRE_BIT) -#define RCC_CFGR_PLLMUL (0xF << 18) -#define RCC_CFGR_PLLMUL_2 (0x0 << 18) -#define RCC_CFGR_PLLMUL_3 (0x1 << 18) -#define RCC_CFGR_PLLMUL_4 (0x2 << 18) -#define RCC_CFGR_PLLMUL_5 (0x3 << 18) -#define RCC_CFGR_PLLMUL_6 (0x4 << 18) -#define RCC_CFGR_PLLMUL_7 (0x5 << 18) -#define RCC_CFGR_PLLMUL_8 (0x6 << 18) -#define RCC_CFGR_PLLMUL_9 (0x7 << 18) -#define RCC_CFGR_PLLMUL_10 (0x8 << 18) -#define RCC_CFGR_PLLMUL_11 (0x9 << 18) -#define RCC_CFGR_PLLMUL_12 (0xA << 18) -#define RCC_CFGR_PLLMUL_13 (0xB << 18) -#define RCC_CFGR_PLLMUL_14 (0xC << 18) -#define RCC_CFGR_PLLMUL_15 (0xD << 18) -#define RCC_CFGR_PLLMUL_16 (0xE << 18) -#define RCC_CFGR_PLLXTPRE BIT(RCC_CFGR_PLLXTPRE_BIT) -#define RCC_CFGR_PLLSRC BIT(RCC_CFGR_PLLSRC_BIT) -#define RCC_CFGR_PLLSRC_HSI_DIV_2 (0 << RCC_CFGR_PLLSRC_BIT) -#define RCC_CFGR_PLLSRC_HSE (1 << RCC_CFGR_PLLSRC_BIT) -#define RCC_CFGR_ADCPRE (0x3 << 14) -#define RCC_CFGR_PPRE2 (0x7 << 11) -#define RCC_CFGR_PPRE1 (0x7 << 8) -#define RCC_CFGR_HPRE (0xF << 4) -#define RCC_CFGR_SWS (0x3 << 2) -#define RCC_CFGR_SWS_PLL (0x2 << 2) -#define RCC_CFGR_SWS_HSE (0x1 << 2) -#define RCC_CFGR_SW (0x3 << 0) -#define RCC_CFGR_SW_PLL (0x2 << 0) -#define RCC_CFGR_SW_HSE (0x1 << 0) - -/* Clock interrupt register */ - -#define RCC_CIR_CSSC_BIT 23 -#define RCC_CIR_PLLRDYC_BIT 20 -#define RCC_CIR_HSERDYC_BIT 19 -#define RCC_CIR_HSIRDYC_BIT 18 -#define RCC_CIR_LSERDYC_BIT 17 -#define RCC_CIR_LSIRDYC_BIT 16 -#define RCC_CIR_PLLRDYIE_BIT 12 -#define RCC_CIR_HSERDYIE_BIT 11 -#define RCC_CIR_HSIRDYIE_BIT 10 -#define RCC_CIR_LSERDYIE_BIT 9 -#define RCC_CIR_LSIRDYIE_BIT 8 -#define RCC_CIR_CSSF_BIT 7 -#define RCC_CIR_PLLRDYF_BIT 4 -#define RCC_CIR_HSERDYF_BIT 3 -#define RCC_CIR_HSIRDYF_BIT 2 -#define RCC_CIR_LSERDYF_BIT 1 -#define RCC_CIR_LSIRDYF_BIT 0 - -#define RCC_CIR_CSSC BIT(RCC_CIR_CSSC_BIT) -#define RCC_CIR_PLLRDYC BIT(RCC_CIR_PLLRDYC_BIT) -#define RCC_CIR_HSERDYC BIT(RCC_CIR_HSERDYC_BIT) -#define RCC_CIR_HSIRDYC BIT(RCC_CIR_HSIRDYC_BIT) -#define RCC_CIR_LSERDYC BIT(RCC_CIR_LSERDYC_BIT) -#define RCC_CIR_LSIRDYC BIT(RCC_CIR_LSIRDYC_BIT) -#define RCC_CIR_PLLRDYIE BIT(RCC_CIR_PLLRDYIE_BIT) -#define RCC_CIR_HSERDYIE BIT(RCC_CIR_HSERDYIE_BIT) -#define RCC_CIR_HSIRDYIE BIT(RCC_CIR_HSIRDYIE_BIT) -#define RCC_CIR_LSERDYIE BIT(RCC_CIR_LSERDYIE_BIT) -#define RCC_CIR_LSIRDYIE BIT(RCC_CIR_LSIRDYIE_BIT) -#define RCC_CIR_CSSF BIT(RCC_CIR_CSSF_BIT) -#define RCC_CIR_PLLRDYF BIT(RCC_CIR_PLLRDYF_BIT) -#define RCC_CIR_HSERDYF BIT(RCC_CIR_HSERDYF_BIT) -#define RCC_CIR_HSIRDYF BIT(RCC_CIR_HSIRDYF_BIT) -#define RCC_CIR_LSERDYF BIT(RCC_CIR_LSERDYF_BIT) -#define RCC_CIR_LSIRDYF BIT(RCC_CIR_LSIRDYF_BIT) - -/* APB2 peripheral reset register */ - -#define RCC_APB2RSTR_TIM11RST_BIT 21 -#define RCC_APB2RSTR_TIM10RST_BIT 20 -#define RCC_APB2RSTR_TIM9RST_BIT 19 -#define RCC_APB2RSTR_ADC3RST_BIT 15 -#define RCC_APB2RSTR_USART1RST_BIT 14 -#define RCC_APB2RSTR_TIM8RST_BIT 13 -#define RCC_APB2RSTR_SPI1RST_BIT 12 -#define RCC_APB2RSTR_TIM1RST_BIT 11 -#define RCC_APB2RSTR_ADC2RST_BIT 10 -#define RCC_APB2RSTR_ADC1RST_BIT 9 -#define RCC_APB2RSTR_IOPGRST_BIT 8 -#define RCC_APB2RSTR_IOPFRST_BIT 7 -#define RCC_APB2RSTR_IOPERST_BIT 6 -#define RCC_APB2RSTR_IOPDRST_BIT 5 -#define RCC_APB2RSTR_IOPCRST_BIT 4 -#define RCC_APB2RSTR_IOPBRST_BIT 3 -#define RCC_APB2RSTR_IOPARST_BIT 2 -#define RCC_APB2RSTR_AFIORST_BIT 0 - -#define RCC_APB2RSTR_TIM11RST BIT(RCC_APB2RSTR_TIM11RST_BIT) -#define RCC_APB2RSTR_TIM10RST BIT(RCC_APB2RSTR_TIM10RST_BIT) -#define RCC_APB2RSTR_TIM9RST BIT(RCC_APB2RSTR_TIM9RST_BIT) -#define RCC_APB2RSTR_ADC3RST BIT(RCC_APB2RSTR_ADC3RST_BIT) -#define RCC_APB2RSTR_USART1RST BIT(RCC_APB2RSTR_USART1RST_BIT) -#define RCC_APB2RSTR_TIM8RST BIT(RCC_APB2RSTR_TIM8RST_BIT) -#define RCC_APB2RSTR_SPI1RST BIT(RCC_APB2RSTR_SPI1RST_BIT) -#define RCC_APB2RSTR_TIM1RST BIT(RCC_APB2RSTR_TIM1RST_BIT) -#define RCC_APB2RSTR_ADC2RST BIT(RCC_APB2RSTR_ADC2RST_BIT) -#define RCC_APB2RSTR_ADC1RST BIT(RCC_APB2RSTR_ADC1RST_BIT) -#define RCC_APB2RSTR_IOPGRST BIT(RCC_APB2RSTR_IOPGRST_BIT) -#define RCC_APB2RSTR_IOPFRST BIT(RCC_APB2RSTR_IOPFRST_BIT) -#define RCC_APB2RSTR_IOPERST BIT(RCC_APB2RSTR_IOPERST_BIT) -#define RCC_APB2RSTR_IOPDRST BIT(RCC_APB2RSTR_IOPDRST_BIT) -#define RCC_APB2RSTR_IOPCRST BIT(RCC_APB2RSTR_IOPCRST_BIT) -#define RCC_APB2RSTR_IOPBRST BIT(RCC_APB2RSTR_IOPBRST_BIT) -#define RCC_APB2RSTR_IOPARST BIT(RCC_APB2RSTR_IOPARST_BIT) -#define RCC_APB2RSTR_AFIORST BIT(RCC_APB2RSTR_AFIORST_BIT) - -/* APB1 peripheral reset register */ - -#define RCC_APB1RSTR_DACRST_BIT 29 -#define RCC_APB1RSTR_PWRRST_BIT 28 -#define RCC_APB1RSTR_BKPRST_BIT 27 -#define RCC_APB1RSTR_CANRST_BIT 25 -#define RCC_APB1RSTR_USBRST_BIT 23 -#define RCC_APB1RSTR_I2C2RST_BIT 22 -#define RCC_APB1RSTR_I2C1RST_BIT 21 -#define RCC_APB1RSTR_UART5RST_BIT 20 -#define RCC_APB1RSTR_UART4RST_BIT 19 -#define RCC_APB1RSTR_UART3RST_BIT 18 -#define RCC_APB1RSTR_UART2RST_BIT 17 -#define RCC_APB1RSTR_SPI3RST_BIT 15 -#define RCC_APB1RSTR_SPI2RST_BIT 14 -#define RCC_APB1RSTR_WWDGRST_BIT 11 -#define RCC_APB1RSTR_TIM14RST_BIT 8 -#define RCC_APB1RSTR_TIM13RST_BIT 7 -#define RCC_APB1RSTR_TIM12RST_BIT 6 -#define RCC_APB1RSTR_TIM7RST_BIT 5 -#define RCC_APB1RSTR_TIM6RST_BIT 4 -#define RCC_APB1RSTR_TIM5RST_BIT 3 -#define RCC_APB1RSTR_TIM4RST_BIT 2 -#define RCC_APB1RSTR_TIM3RST_BIT 1 -#define RCC_APB1RSTR_TIM2RST_BIT 0 - -#define RCC_APB1RSTR_DACRST BIT(RCC_APB1RSTR_DACRST_BIT) -#define RCC_APB1RSTR_PWRRST BIT(RCC_APB1RSTR_PWRRST_BIT) -#define RCC_APB1RSTR_BKPRST BIT(RCC_APB1RSTR_BKPRST_BIT) -#define RCC_APB1RSTR_CANRST BIT(RCC_APB1RSTR_CANRST_BIT) -#define RCC_APB1RSTR_USBRST BIT(RCC_APB1RSTR_USBRST_BIT) -#define RCC_APB1RSTR_I2C2RST BIT(RCC_APB1RSTR_I2C2RST_BIT) -#define RCC_APB1RSTR_I2C1RST BIT(RCC_APB1RSTR_I2C1RST_BIT) -#define RCC_APB1RSTR_UART5RST BIT(RCC_APB1RSTR_UART5RST_BIT) -#define RCC_APB1RSTR_UART4RST BIT(RCC_APB1RSTR_UART4RST_BIT) -#define RCC_APB1RSTR_UART3RST BIT(RCC_APB1RSTR_UART3RST_BIT) -#define RCC_APB1RSTR_UART2RST BIT(RCC_APB1RSTR_UART2RST_BIT) -#define RCC_APB1RSTR_SPI3RST BIT(RCC_APB1RSTR_SPI3RST_BIT) -#define RCC_APB1RSTR_SPI2RST BIT(RCC_APB1RSTR_SPI2RST_BIT) -#define RCC_APB1RSTR_WWDGRST BIT(RCC_APB1RSTR_WWDGRST_BIT) -#define RCC_APB1RSTR_TIM14RST BIT(RCC_APB1RSTR_TIM14RST_BIT) -#define RCC_APB1RSTR_TIM13RST BIT(RCC_APB1RSTR_TIM13RST_BIT) -#define RCC_APB1RSTR_TIM12RST BIT(RCC_APB1RSTR_TIM12RST_BIT) -#define RCC_APB1RSTR_TIM7RST BIT(RCC_APB1RSTR_TIM7RST_BIT) -#define RCC_APB1RSTR_TIM6RST BIT(RCC_APB1RSTR_TIM6RST_BIT) -#define RCC_APB1RSTR_TIM5RST BIT(RCC_APB1RSTR_TIM5RST_BIT) -#define RCC_APB1RSTR_TIM4RST BIT(RCC_APB1RSTR_TIM4RST_BIT) -#define RCC_APB1RSTR_TIM3RST BIT(RCC_APB1RSTR_TIM3RST_BIT) -#define RCC_APB1RSTR_TIM2RST BIT(RCC_APB1RSTR_TIM2RST_BIT) - -/* AHB peripheral clock enable register */ - -#define RCC_AHBENR_SDIOEN_BIT 10 -#define RCC_AHBENR_FSMCEN_BIT 8 -#define RCC_AHBENR_CRCEN_BIT 6 -#define RCC_AHBENR_FLITFEN_BIT 4 -#define RCC_AHBENR_SRAMEN_BIT 2 -#define RCC_AHBENR_DMA2EN_BIT 1 -#define RCC_AHBENR_DMA1EN_BIT 0 - -#define RCC_AHBENR_SDIOEN BIT(RCC_AHBENR_SDIOEN_BIT) -#define RCC_AHBENR_FSMCEN BIT(RCC_AHBENR_FSMCEN_BIT) -#define RCC_AHBENR_CRCEN BIT(RCC_AHBENR_CRCEN_BIT) -#define RCC_AHBENR_FLITFEN BIT(RCC_AHBENR_FLITFEN_BIT) -#define RCC_AHBENR_SRAMEN BIT(RCC_AHBENR_SRAMEN_BIT) -#define RCC_AHBENR_DMA2EN BIT(RCC_AHBENR_DMA2EN_BIT) -#define RCC_AHBENR_DMA1EN BIT(RCC_AHBENR_DMA1EN_BIT) - -/* APB2 peripheral clock enable register */ - -#define RCC_APB2ENR_TIM11EN_BIT 21 -#define RCC_APB2ENR_TIM10EN_BIT 20 -#define RCC_APB2ENR_TIM9EN_BIT 19 -#define RCC_APB2ENR_ADC3EN_BIT 15 -#define RCC_APB2ENR_USART1EN_BIT 14 -#define RCC_APB2ENR_TIM8EN_BIT 13 -#define RCC_APB2ENR_SPI1EN_BIT 12 -#define RCC_APB2ENR_TIM1EN_BIT 11 -#define RCC_APB2ENR_ADC2EN_BIT 10 -#define RCC_APB2ENR_ADC1EN_BIT 9 -#define RCC_APB2ENR_IOPGEN_BIT 8 -#define RCC_APB2ENR_IOPFEN_BIT 7 -#define RCC_APB2ENR_IOPEEN_BIT 6 -#define RCC_APB2ENR_IOPDEN_BIT 5 -#define RCC_APB2ENR_IOPCEN_BIT 4 -#define RCC_APB2ENR_IOPBEN_BIT 3 -#define RCC_APB2ENR_IOPAEN_BIT 2 -#define RCC_APB2ENR_AFIOEN_BIT 0 - -#define RCC_APB2ENR_TIM11EN BIT(RCC_APB2ENR_TIM11EN_BIT) -#define RCC_APB2ENR_TIM10EN BIT(RCC_APB2ENR_TIM10EN_BIT) -#define RCC_APB2ENR_TIM9EN BIT(RCC_APB2ENR_TIM9EN_BIT) -#define RCC_APB2ENR_ADC3EN BIT(RCC_APB2ENR_ADC3EN_BIT) -#define RCC_APB2ENR_USART1EN BIT(RCC_APB2ENR_USART1EN_BIT) -#define RCC_APB2ENR_TIM8EN BIT(RCC_APB2ENR_TIM8EN_BIT) -#define RCC_APB2ENR_SPI1EN BIT(RCC_APB2ENR_SPI1EN_BIT) -#define RCC_APB2ENR_TIM1EN BIT(RCC_APB2ENR_TIM1EN_BIT) -#define RCC_APB2ENR_ADC2EN BIT(RCC_APB2ENR_ADC2EN_BIT) -#define RCC_APB2ENR_ADC1EN BIT(RCC_APB2ENR_ADC1EN_BIT) -#define RCC_APB2ENR_IOPGEN BIT(RCC_APB2ENR_IOPGEN_BIT) -#define RCC_APB2ENR_IOPFEN BIT(RCC_APB2ENR_IOPFEN_BIT) -#define RCC_APB2ENR_IOPEEN BIT(RCC_APB2ENR_IOPEEN_BIT) -#define RCC_APB2ENR_IOPDEN BIT(RCC_APB2ENR_IOPDEN_BIT) -#define RCC_APB2ENR_IOPCEN BIT(RCC_APB2ENR_IOPCEN_BIT) -#define RCC_APB2ENR_IOPBEN BIT(RCC_APB2ENR_IOPBEN_BIT) -#define RCC_APB2ENR_IOPAEN BIT(RCC_APB2ENR_IOPAEN_BIT) -#define RCC_APB2ENR_AFIOEN BIT(RCC_APB2ENR_AFIOEN_BIT) - -/* APB1 peripheral clock enable register */ - -#define RCC_APB1ENR_DACEN_BIT 29 -#define RCC_APB1ENR_BKPEN_BIT 27 -#define RCC_APB1ENR_PWREN_BIT 28 -#define RCC_APB1ENR_CANEN_BIT 25 -#define RCC_APB1ENR_USBEN_BIT 23 -#define RCC_APB1ENR_I2C2EN_BIT 22 -#define RCC_APB1ENR_I2C1EN_BIT 21 -#define RCC_APB1ENR_UART5EN_BIT 20 -#define RCC_APB1ENR_UART4EN_BIT 19 -#define RCC_APB1ENR_UART3EN_BIT 18 -#define RCC_APB1ENR_UART2EN_BIT 17 -#define RCC_APB1ENR_SPI3EN_BIT 15 -#define RCC_APB1ENR_SPI2EN_BIT 14 -#define RCC_APB1ENR_WWDGEN_BIT 11 -#define RCC_APB1ENR_TIM14EN_BIT 8 -#define RCC_APB1ENR_TIM13EN_BIT 7 -#define RCC_APB1ENR_TIM12EN_BIT 6 -#define RCC_APB1ENR_TIM7EN_BIT 5 -#define RCC_APB1ENR_TIM6EN_BIT 4 -#define RCC_APB1ENR_TIM5EN_BIT 3 -#define RCC_APB1ENR_TIM4EN_BIT 2 -#define RCC_APB1ENR_TIM3EN_BIT 1 -#define RCC_APB1ENR_TIM2EN_BIT 0 - -#define RCC_APB1ENR_DACEN BIT(RCC_APB1ENR_DACEN_BIT) -#define RCC_APB1ENR_PWREN BIT(RCC_APB1ENR_PWREN_BIT) -#define RCC_APB1ENR_BKPEN BIT(RCC_APB1ENR_BKPEN_BIT) -#define RCC_APB1ENR_CANEN BIT(RCC_APB1ENR_CANEN_BIT) -#define RCC_APB1ENR_USBEN BIT(RCC_APB1ENR_USBEN_BIT) -#define RCC_APB1ENR_I2C2EN BIT(RCC_APB1ENR_I2C2EN_BIT) -#define RCC_APB1ENR_I2C1EN BIT(RCC_APB1ENR_I2C1EN_BIT) -#define RCC_APB1ENR_UART5EN BIT(RCC_APB1ENR_UART5EN_BIT) -#define RCC_APB1ENR_UART4EN BIT(RCC_APB1ENR_UART4EN_BIT) -#define RCC_APB1ENR_UART3EN BIT(RCC_APB1ENR_UART3EN_BIT) -#define RCC_APB1ENR_UART2EN BIT(RCC_APB1ENR_UART2EN_BIT) -#define RCC_APB1ENR_SPI3EN BIT(RCC_APB1ENR_SPI3EN_BIT) -#define RCC_APB1ENR_SPI2EN BIT(RCC_APB1ENR_SPI2EN_BIT) -#define RCC_APB1ENR_WWDGEN BIT(RCC_APB1ENR_WWDGEN_BIT) -#define RCC_APB1ENR_TIM14EN BIT(RCC_APB1ENR_TIM14EN_BIT) -#define RCC_APB1ENR_TIM13EN BIT(RCC_APB1ENR_TIM13EN_BIT) -#define RCC_APB1ENR_TIM12EN BIT(RCC_APB1ENR_TIM12EN_BIT) -#define RCC_APB1ENR_TIM7EN BIT(RCC_APB1ENR_TIM7EN_BIT) -#define RCC_APB1ENR_TIM6EN BIT(RCC_APB1ENR_TIM6EN_BIT) -#define RCC_APB1ENR_TIM5EN BIT(RCC_APB1ENR_TIM5EN_BIT) -#define RCC_APB1ENR_TIM4EN BIT(RCC_APB1ENR_TIM4EN_BIT) -#define RCC_APB1ENR_TIM3EN BIT(RCC_APB1ENR_TIM3EN_BIT) -#define RCC_APB1ENR_TIM2EN BIT(RCC_APB1ENR_TIM2EN_BIT) - -/* Backup domain control register */ - -#define RCC_BDCR_BDRST_BIT 16 -#define RCC_BDCR_RTCEN_BIT 15 -#define RCC_BDCR_LSEBYP_BIT 2 -#define RCC_BDCR_LSERDY_BIT 1 -#define RCC_BDCR_LSEON_BIT 0 - -#define RCC_BDCR_BDRST BIT(RCC_BDCR_BDRST_BIT) -#define RCC_BDCR_RTCEN BIT(RCC_BDCR_RTCEN_BIT) -#define RCC_BDCR_RTCSEL (0x3 << 8) -#define RCC_BDCR_RTCSEL_LSE (0x1 << 8) -#define RCC_BDCR_RTCSEL_LSI (0x2 << 8) -#define RCC_BDCR_RTCSEL_HSE_DIV_128 (0x3 << 8) -#define RCC_BDCR_LSEBYP BIT(RCC_BDCR_LSEBYP_BIT) -#define RCC_BDCR_LSERDY BIT(RCC_BDCR_LSERDY_BIT) -#define RCC_BDCR_LSEON BIT(RCC_BDCR_LSEON_BIT) - -/* Control/status register */ - -#define RCC_CSR_LPWRRSTF_BIT 31 -#define RCC_CSR_WWDGRSTF_BIT 30 -#define RCC_CSR_IWDGRSTF_BIT 29 -#define RCC_CSR_SFTRSTF_BIT 28 -#define RCC_CSR_PORRSTF_BIT 27 -#define RCC_CSR_PINRSTF_BIT 26 -#define RCC_CSR_RMVF_BIT 25 -#define RCC_CSR_LSIRDY_BIT 1 -#define RCC_CSR_LSION_BIT 0 - -#define RCC_CSR_LPWRRSTF BIT(RCC_CSR_LPWRRSTF_BIT) -#define RCC_CSR_WWDGRSTF BIT(RCC_CSR_WWDGRSTF_BIT) -#define RCC_CSR_IWDGRSTF BIT(RCC_CSR_IWDGRSTF_BIT) -#define RCC_CSR_SFTRSTF BIT(RCC_CSR_SFTRSTF_BIT) -#define RCC_CSR_PORRSTF BIT(RCC_CSR_PORRSTF_BIT) -#define RCC_CSR_PINRSTF BIT(RCC_CSR_PINRSTF_BIT) -#define RCC_CSR_RMVF BIT(RCC_CSR_RMVF_BIT) -#define RCC_CSR_LSIRDY BIT(RCC_CSR_LSIRDY_BIT) -#define RCC_CSR_LSION BIT(RCC_CSR_LSION_BIT) - -/** - * Identifies bus and clock line for a device - */ -typedef enum { - RCC_SRAM, - RCC_GPIOA, - RCC_GPIOB, - RCC_GPIOC, - RCC_GPIOD, - RCC_AFIO, - RCC_ADC1, - RCC_ADC2, - RCC_USART1, - RCC_USART2, - RCC_USART3, - RCC_TIMER1, - RCC_TIMER2, - RCC_TIMER3, - RCC_TIMER4, - RCC_SPI1, - RCC_SPI2, - RCC_DMA1, - RCC_PWR, - RCC_BKP, - RCC_CAN, - RCC_USB, - RCC_I2C1, - RCC_I2C2, - RCC_CRC, - RCC_WWDG, - RCC_FLITF, -#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) - RCC_SDIO, - RCC_FSMC, - RCC_GPIOE, - RCC_GPIOF, - RCC_GPIOG, - RCC_ADC3, - RCC_UART4, - RCC_UART5, - RCC_TIMER5, - RCC_TIMER6, - RCC_TIMER7, - RCC_TIMER8, - RCC_DAC, - RCC_DMA2, - RCC_SPI3, -#endif -#ifdef STM32_XL_DENSITY - RCC_TIMER9, - RCC_TIMER10, - RCC_TIMER11, - RCC_TIMER12, - RCC_TIMER13, - RCC_TIMER14, -#endif -} rcc_clk_id; - -/* SYSCLK source */ +/* registers */ +#define RCC_BASE 0x40021000 +#define RCC_CR (RCC_BASE + 0x0) +#define RCC_CFGR (RCC_BASE + 0x4) +#define RCC_CIR (RCC_BASE + 0x8) +#define RCC_APB2RSTR (RCC_BASE + 0xC) +#define RCC_APB1RSTR (RCC_BASE + 0x10) +#define RCC_AHBENR (RCC_BASE + 0x14) +#define RCC_APB2ENR (RCC_BASE + 0x18) +#define RCC_APB1ENR (RCC_BASE + 0x1C) +#define RCC_BDCR (RCC_BASE + 0x20) +#define RCC_CSR (RCC_BASE + 0x24) +#define RCC_AHBSTR (RCC_BASE + 0x28) +#define RCC_CFGR2 (RCC_BASE + 0x2C) + +#define RCC_CFGR_USBPRE (0x1 << 22) +#define RCC_CFGR_ADCPRE (0x3 << 14) +#define RCC_CFGR_PPRE1 (0x7 << 8) +#define RCC_CFGR_PPRE2 (0x7 << 11) +#define RCC_CFGR_HPRE (0xF << 4) +#define RCC_CFGR_PLLSRC (0x1 << 16) + +#define RCC_CFGR_SWS (0x3 << 2) +#define RCC_CFGR_SWS_PLL (0x2 << 2) +#define RCC_CFGR_SWS_HSE (0x1 << 2) + +#define RCC_CFGR_SW (0x3 << 0) +#define RCC_CFGR_SW_PLL (0x2 << 0) +#define RCC_CFGR_SW_HSE (0x1 << 0) + +/* CR status bits */ +#define RCC_CR_HSEON (0x1 << 16) +#define RCC_CR_HSERDY (0x1 << 17) +#define RCC_CR_PLLON (0x1 << 24) +#define RCC_CR_PLLRDY (0x1 << 25) + +#define RCC_WRITE_CFGR(val) __write(RCC_CFGR, val) +#define RCC_READ_CFGR() __read(RCC_CFGR) + +#define RCC_WRITE_CR(val) __write(RCC_CR, val) +#define RCC_READ_CR() __read(RCC_CR) + +/* sysclk source */ #define RCC_CLKSRC_HSI (0x0) #define RCC_CLKSRC_HSE (0x1) #define RCC_CLKSRC_PLL (0x2) -/* ADC prescaler dividers */ +/* pll entry clock source */ +#define RCC_PLLSRC_HSE (0x1 << 16) +#define RCC_PLLSRC_HSI_DIV_2 (0x0 << 16) + +/* adc prescaler dividers */ #define RCC_ADCPRE_PCLK_DIV_2 (0x0 << 14) #define RCC_ADCPRE_PCLK_DIV_4 (0x1 << 14) #define RCC_ADCPRE_PCLK_DIV_6 (0x2 << 14) #define RCC_ADCPRE_PCLK_DIV_8 (0x3 << 14) -/* APB1 prescaler dividers */ +/* apb1 prescaler dividers */ #define RCC_APB1_HCLK_DIV_1 (0x0 << 8) #define RCC_APB1_HCLK_DIV_2 (0x4 << 8) #define RCC_APB1_HCLK_DIV_4 (0x5 << 8) #define RCC_APB1_HCLK_DIV_8 (0x6 << 8) #define RCC_APB1_HCLK_DIV_16 (0x7 << 8) -/* APB2 prescaler dividers */ +/* apb2 prescaler dividers */ #define RCC_APB2_HCLK_DIV_1 (0x0 << 11) #define RCC_APB2_HCLK_DIV_2 (0x4 << 11) #define RCC_APB2_HCLK_DIV_4 (0x5 << 11) #define RCC_APB2_HCLK_DIV_8 (0x6 << 11) #define RCC_APB2_HCLK_DIV_16 (0x7 << 11) -/* AHB prescaler dividers */ +/* ahb prescaler dividers */ #define RCC_AHB_SYSCLK_DIV_1 (0x0 << 4) #define RCC_AHB_SYSCLK_DIV_2 (0x8 << 4) #define RCC_AHB_SYSCLK_DIV_4 (0x9 << 4) @@ -492,19 +119,75 @@ typedef enum { #define RCC_AHB_SYSCLK_DIV_256 (0xE << 4) #define RCC_AHB_SYSCLK_DIV_512 (0xF << 4) -/* Prescalers */ -typedef enum rcc_prescaler { +/* pll multipliers */ +#define RCC_PLLMUL_2 (0x0 << 18) +#define RCC_PLLMUL_3 (0x1 << 18) +#define RCC_PLLMUL_4 (0x2 << 18) +#define RCC_PLLMUL_5 (0x3 << 18) +#define RCC_PLLMUL_6 (0x4 << 18) +#define RCC_PLLMUL_7 (0x5 << 18) +#define RCC_PLLMUL_8 (0x6 << 18) +#define RCC_PLLMUL_9 (0x7 << 18) +#define RCC_PLLMUL_10 (0x8 << 18) +#define RCC_PLLMUL_11 (0x9 << 18) +#define RCC_PLLMUL_12 (0xA << 18) +#define RCC_PLLMUL_13 (0xB << 18) +#define RCC_PLLMUL_14 (0xC << 18) +#define RCC_PLLMUL_15 (0xD << 18) +#define RCC_PLLMUL_16 (0xE << 18) + + +/* prescalers */ +enum { RCC_PRESCALER_AHB, RCC_PRESCALER_APB1, RCC_PRESCALER_APB2, RCC_PRESCALER_USB, RCC_PRESCALER_ADC -} rcc_prescaler; +}; + +/* + * Identifies bus and clock line for a device + */ +typedef enum { + RCC_GPIOA, + RCC_GPIOB, + RCC_GPIOC, + RCC_GPIOD, + RCC_GPIOE, // High-density devices only (Maple Native) + RCC_GPIOF, // High-density devices only (Maple Native) + RCC_GPIOG, // High-density devices only (Maple Native) + RCC_AFIO, + RCC_ADC1, + RCC_ADC2, + RCC_ADC3, + RCC_USART1, + RCC_USART2, + RCC_USART3, + RCC_UART4, // High-density devices only (Maple Native) + RCC_UART5, // High-density devices only (Maple Native) + RCC_TIMER1, + RCC_TIMER2, + RCC_TIMER3, + RCC_TIMER4, + RCC_TIMER5, // High-density devices only (Maple Native) + RCC_TIMER6, // High-density devices only (Maple Native) + RCC_TIMER7, // High-density devices only (Maple Native) + RCC_TIMER8, // High-density devices only (Maple Native) + RCC_SPI1, + 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) + RCC_PWR, + RCC_BKP, +} rcc_clk_id; void rcc_clk_init(uint32 sysclk_src, uint32 pll_src, uint32 pll_mul); void rcc_clk_enable(rcc_clk_id device); void rcc_reset_dev(rcc_clk_id device); -void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider); +void rcc_set_prescaler(uint32 prescaler, uint32 divider); #ifdef __cplusplus } // extern "C" diff --git a/wirish/boards.cpp b/wirish/boards.cpp index 66f008f..1256ba1 100644 --- a/wirish/boards.cpp +++ b/wirish/boards.cpp @@ -304,7 +304,7 @@ PinMapping PIN_MAP[NR_GPIO_PINS] = { /* D98/PG5 */ {GPIOG, 5, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, /* D99/PD10 */ - {GPIOD, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD} + {GPIOD, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PDD} }; #elif defined(BOARD_maple_mini) diff --git a/wirish/wirish.cpp b/wirish/wirish.cpp index c5a9e30..65d0262 100644 --- a/wirish/wirish.cpp +++ b/wirish/wirish.cpp @@ -53,7 +53,7 @@ void init(void) { #endif /* initialize clocks */ - rcc_clk_init(RCC_CLKSRC_PLL, RCC_CFGR_PLLSRC_HSE, RCC_CFGR_PLLMUL_9); + rcc_clk_init(RCC_CLKSRC_PLL, RCC_PLLSRC_HSE, RCC_PLLMUL_9); rcc_set_prescaler(RCC_PRESCALER_AHB, RCC_AHB_SYSCLK_DIV_1); rcc_set_prescaler(RCC_PRESCALER_APB1, RCC_APB1_HCLK_DIV_2); rcc_set_prescaler(RCC_PRESCALER_APB2, RCC_APB2_HCLK_DIV_1); -- cgit v1.2.3 From ef0936df9b58a0589e68a460a7c963d05f9a1759 Mon Sep 17 00:00:00 2001 From: Perry Hung Date: Mon, 21 Mar 2011 02:27:45 -0400 Subject: Fix compiler errors after reverting broken commit. --- libmaple/adc.c | 4 ++-- libmaple/adc.h | 6 +++--- libmaple/bkp.c | 4 ++-- libmaple/exti.c | 18 +++++++++--------- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/libmaple/adc.c b/libmaple/adc.c index 9626a40..3d38596 100644 --- a/libmaple/adc.c +++ b/libmaple/adc.c @@ -126,8 +126,8 @@ void adc_set_sample_rate(const adc_dev *dev, adc_smp_rate smp_rate) { * @param dev adc device */ static void adc_calibrate(const adc_dev *dev) { - __io uint32 *rstcal_bit = bb_peripv(&(dev->regs->CR2), 3); - __io uint32 *cal_bit = bb_peripv(&(dev->regs->CR2), 2); + __io uint32 *rstcal_bit = bb_perip(&(dev->regs->CR2), 3); + __io uint32 *cal_bit = bb_perip(&(dev->regs->CR2), 2); *rstcal_bit = 1; while (*rstcal_bit) diff --git a/libmaple/adc.h b/libmaple/adc.h index 4811dbc..53ef032 100644 --- a/libmaple/adc.h +++ b/libmaple/adc.h @@ -175,7 +175,7 @@ static inline uint32 adc_read(const adc_dev *dev, uint8 channel) { * @param enable If 1, conversion on external events is enabled, 0 to disable */ static inline void adc_set_exttrig(const adc_dev *dev, uint8 enable) { - *bb_peripv(&dev->regs->CR2, 20) = !!enable; + *bb_perip(&dev->regs->CR2, 20) = !!enable; } /** @@ -183,7 +183,7 @@ static inline void adc_set_exttrig(const adc_dev *dev, uint8 enable) { * @param dev ADC device to enable */ static inline void adc_enable(const adc_dev *dev) { - *bb_peripv(&dev->regs->CR2, 0) = 1; + *bb_perip(&dev->regs->CR2, 0) = 1; } /** @@ -191,7 +191,7 @@ static inline void adc_enable(const adc_dev *dev) { * @param dev ADC device to disable */ static inline void adc_disable(const adc_dev *dev) { - *bb_peripv(&dev->regs->CR2, 0) = 0; + *bb_perip(&dev->regs->CR2, 0) = 0; } /** diff --git a/libmaple/bkp.c b/libmaple/bkp.c index b152069..aaccb1f 100644 --- a/libmaple/bkp.c +++ b/libmaple/bkp.c @@ -57,14 +57,14 @@ void bkp_init(void) { * @see bkp_init() */ void bkp_enable_writes(void) { - *bb_peripv(&PWR_BASE->CR, PWR_CR_DBP) = 1; + *bb_perip(&PWR_BASE->CR, PWR_CR_DBP) = 1; } /** * Disable write access to the backup registers. */ void bkp_disable_writes(void) { - *bb_peripv(&PWR_BASE->CR, PWR_CR_DBP) = 0; + *bb_perip(&PWR_BASE->CR, PWR_CR_DBP) = 0; } /** diff --git a/libmaple/exti.c b/libmaple/exti.c index 8177e1e..7f56712 100644 --- a/libmaple/exti.c +++ b/libmaple/exti.c @@ -98,14 +98,14 @@ void exti_attach_interrupt(afio_exti_num num, /* Set trigger mode */ switch (mode) { case EXTI_RISING: - *bb_peripv(&EXTI_BASE->RTSR, num) = 1; + *bb_perip(&EXTI_BASE->RTSR, num) = 1; break; case EXTI_FALLING: - *bb_peripv(&EXTI_BASE->FTSR, num) = 1; + *bb_perip(&EXTI_BASE->FTSR, num) = 1; break; case EXTI_RISING_FALLING: - *bb_peripv(&EXTI_BASE->RTSR, num) = 1; - *bb_peripv(&EXTI_BASE->FTSR, num) = 1; + *bb_perip(&EXTI_BASE->RTSR, num) = 1; + *bb_perip(&EXTI_BASE->FTSR, num) = 1; break; } @@ -113,7 +113,7 @@ void exti_attach_interrupt(afio_exti_num num, afio_exti_select(num, port); /* Unmask external interrupt request */ - *bb_peripv(&EXTI_BASE->IMR, num) = 1; + *bb_perip(&EXTI_BASE->IMR, num) = 1; /* Enable the interrupt line */ enable_irq(num); @@ -126,11 +126,11 @@ void exti_attach_interrupt(afio_exti_num num, */ void exti_detach_interrupt(afio_exti_num num) { /* First, mask the interrupt request */ - *bb_peripv(&EXTI_BASE->IMR, num) = 0; + *bb_perip(&EXTI_BASE->IMR, num) = 0; /* Then, clear the trigger selection registers */ - *bb_peripv(&EXTI_BASE->FTSR, num) = 0; - *bb_peripv(&EXTI_BASE->RTSR, num) = 0; + *bb_perip(&EXTI_BASE->FTSR, num) = 0; + *bb_perip(&EXTI_BASE->RTSR, num) = 0; /* Next, disable the IRQ, unless it's multiplexed and there are * other active external interrupts on the same IRQ line */ @@ -210,7 +210,7 @@ void __irq_exti15_10(void) { */ static inline void clear_pending(uint32 exti_num) { - *bb_peripv(&EXTI_BASE->PR, exti_num) = 1; + *bb_perip(&EXTI_BASE->PR, exti_num) = 1; /* If the pending bit is cleared as the last instruction in an ISR, * it won't actually be cleared in time and the ISR will fire again. * Insert a 2-cycle buffer to allow it to take effect. */ -- cgit v1.2.3 From 1591fc9e3f851327c16bbcb88e6abee1706f9cfc Mon Sep 17 00:00:00 2001 From: Perry Hung Date: Mon, 21 Mar 2011 02:32:39 -0400 Subject: modify gpio interface to expose gpio dev structs --- libmaple/gpio.c | 37 +++++++++++++++---------------------- libmaple/gpio.h | 28 ++++++++++++++-------------- 2 files changed, 29 insertions(+), 36 deletions(-) diff --git a/libmaple/gpio.c b/libmaple/gpio.c index b08be12..18b856b 100644 --- a/libmaple/gpio.c +++ b/libmaple/gpio.c @@ -33,55 +33,48 @@ * GPIO devices */ -static gpio_dev gpioa = { +gpio_dev gpioa = { .regs = GPIOA_BASE, .clk_id = RCC_GPIOA }; -/** GPIO port A device. */ -gpio_dev *GPIOA = &gpioa; +gpio_dev* const GPIOA = &gpioa; -static gpio_dev gpiob = { +gpio_dev gpiob = { .regs = GPIOB_BASE, .clk_id = RCC_GPIOB }; -/** GPIO port B device. */ -gpio_dev *GPIOB = &gpiob; +gpio_dev* const GPIOB = &gpiob; -static gpio_dev gpioc = { +gpio_dev gpioc = { .regs = GPIOC_BASE, .clk_id = RCC_GPIOC }; -/** GPIO port C device. */ -gpio_dev *GPIOC = &gpioc; +gpio_dev* const GPIOC = &gpioc; -static gpio_dev gpiod = { +gpio_dev gpiod = { .regs = GPIOD_BASE, .clk_id = RCC_GPIOD }; -/** GPIO port D device. */ -gpio_dev *GPIOD = &gpiod; +gpio_dev* const GPIOD = &gpiod; -#ifdef STM32_HIGH_ -static gpio_dev gpioe = { +#ifdef STM32_HIGH_DENSITY +gpio_dev gpioe = { .regs = GPIOE_BASE, .clk_id = RCC_GPIOE }; -/** GPIO port E device. */ -gpio_dev *GPIOE = &gpioe; +gpio_dev* const GPIOE = &gpioe; -static gpio_dev gpiof = { +gpio_dev gpiof = { .regs = GPIOF_BASE, .clk_id = RCC_GPIOF }; -/** GPIO port F device. */ -gpio_dev *GPIOF = &gpiof; +gpio_dev* const GPIOF = &gpiof; -static gpio_dev gpiog = { +gpio_dev gpiog = { .regs = GPIOG_BASE, .clk_id = RCC_GPIOG }; -/** GPIO port G device. */ -gpio_dev *GPIOG = &gpiog; +gpio_dev* const GPIOG = &gpiog; #endif /* diff --git a/libmaple/gpio.h b/libmaple/gpio.h index 48dbc00..a8a4985 100644 --- a/libmaple/gpio.h +++ b/libmaple/gpio.h @@ -62,21 +62,21 @@ typedef struct gpio_dev { rcc_clk_id clk_id; ///< RCC clock information } gpio_dev; -/** GPIO port A device */ -extern gpio_dev *GPIOA; -/** GPIO port B device */ -extern gpio_dev *GPIOB; -/** GPIO port C device */ -extern gpio_dev *GPIOC; -/** GPIO port D device */ -extern gpio_dev *GPIOD; +extern gpio_dev gpioa; +extern gpio_dev* const GPIOA; +extern gpio_dev gpiob; +extern gpio_dev* const GPIOB; +extern gpio_dev gpioc; +extern gpio_dev* const GPIOC; +extern gpio_dev gpiod; +extern gpio_dev* const GPIOD; #ifdef STM32_HIGH_DENSITY -/** GPIO port E device */ -extern gpio_dev *GPIOE; -/** GPIO port F device */ -extern gpio_dev *GPIOF; -/** GPIO port G device */ -extern gpio_dev *GPIOG; +extern gpio_dev gpioe; +extern gpio_dev* const GPIOE; +extern gpio_dev gpiof; +extern gpio_dev* const GPIOF; +extern gpio_dev gpiog; +extern gpio_dev* const GPIOG; #endif /** GPIO port A register map base pointer */ -- cgit v1.2.3 From effd2fd66f3f67e42a3fc8c0e3c7a82f30dc2e44 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Mon, 21 Mar 2011 04:21:12 -0400 Subject: More convenient bit-banding interface --- libmaple/bitband.h | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/libmaple/bitband.h b/libmaple/bitband.h index b817f73..3e02702 100644 --- a/libmaple/bitband.h +++ b/libmaple/bitband.h @@ -47,6 +47,26 @@ static inline __io uint32* bb_sramp(__io void *address, uint32 bit) { return __bb_addr(address, bit, BB_SRAM_BASE, BB_SRAM_REF); } +/** + * @brief Get a bit from an address in the SRAM bit-band region. + * @param address Address in the SRAM bit-band region to read from + * @param bit Bit in address to read + * @return bit's value in address. + */ +static inline uint8 bb_sram_get_bit(__io void *address, uint32 bit) { + return *bb_sramp(address, bit); +} + +/** + * @brief Set a bit in an address in the SRAM bit-band region. + * @param address Address in the SRAM bit-band region to write to + * @param bit Bit in address to write to + * @param val Value to write for bit, either 0 or 1. + */ +static inline void bb_sram_set_bit(__io void *address, uint32 bit, uint8 val) { + *bb_sramp(address, bit) = val; +} + /** * @brief Obtain a pointer to the bit-band address corresponding to a * bit in a peripheral address. @@ -57,6 +77,26 @@ static inline __io uint32* bb_perip(__io void *address, uint32 bit) { return __bb_addr(address, bit, BB_PERI_BASE, BB_PERI_REF); } +/** + * @brief Get a bit from an address in the peripheral bit-band region. + * @param address Address in the peripheral bit-band region to read from + * @param bit Bit in address to read + * @return bit's value in address. + */ +static inline uint8 bb_peri_get_bit(__io void *address, uint32 bit) { + return *bb_perip(address, bit); +} + +/** + * @brief Set a bit in an address in the peripheral bit-band region. + * @param address Address in the peripheral bit-band region to write to + * @param bit Bit in address to write to + * @param val Value to write for bit, either 0 or 1. + */ +static inline void bb_peri_set_bit(__io void *address, uint32 bit, uint8 val) { + *bb_perip(address, bit) = val; +} + static inline __io uint32* __bb_addr(__io void *address, uint32 bit, uint32 bb_base, -- cgit v1.2.3 From cf1f0fa96a6218739520c16bf6cd2c3df6ef97dd Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Mon, 21 Mar 2011 14:34:40 -0400 Subject: Native PIN_MAP typo --- wirish/boards.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wirish/boards.cpp b/wirish/boards.cpp index 1256ba1..66f008f 100644 --- a/wirish/boards.cpp +++ b/wirish/boards.cpp @@ -304,7 +304,7 @@ PinMapping PIN_MAP[NR_GPIO_PINS] = { /* D98/PG5 */ {GPIOG, 5, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, /* D99/PD10 */ - {GPIOD, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PDD} + {GPIOD, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD} }; #elif defined(BOARD_maple_mini) -- cgit v1.2.3 From e7c9a9109815060175e73c06d4b34809ab033193 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Mon, 21 Mar 2011 03:58:55 -0400 Subject: RCC refactor. Older refactor commit e4807a5010f59ab863ad2c96dc14caf65bf1ae60 used bit-banding in rcc_clk_init() to set RCC_CR_HSEON, which doesn't work for some reason. Not going to try to figure out why. --- libmaple/dac.c | 4 + libmaple/rcc.c | 128 +++++++----- libmaple/rcc.h | 609 +++++++++++++++++++++++++++++++++++++++++++++------------ 3 files changed, 563 insertions(+), 178 deletions(-) diff --git a/libmaple/dac.c b/libmaple/dac.c index ef3a9f9..0f44bb4 100644 --- a/libmaple/dac.c +++ b/libmaple/dac.c @@ -26,6 +26,8 @@ #include "gpio.h" #include "dac.h" +#ifdef STM32_HIGH_DENSITY + /** * @brief DAC peripheral routines. */ @@ -108,3 +110,5 @@ void dac_disable_channel(uint8 channel) { break; } } + +#endif /* STM32_HIGH_DENSITY */ diff --git a/libmaple/rcc.c b/libmaple/rcc.c index 6445958..327e3ad 100644 --- a/libmaple/rcc.c +++ b/libmaple/rcc.c @@ -30,6 +30,7 @@ #include "libmaple.h" #include "flash.h" #include "rcc.h" +#include "bitband.h" enum { APB1, @@ -42,15 +43,13 @@ struct rcc_dev_info { const uint8 line_num; }; -/* device descriptor tables */ +/* Device descriptor table, maps rcc_clk_id onto bus and enable/reset + * register bit numbers. */ static const struct rcc_dev_info rcc_dev_table[] = { [RCC_GPIOA] = { .clk_domain = APB2, .line_num = 2 }, [RCC_GPIOB] = { .clk_domain = APB2, .line_num = 3 }, [RCC_GPIOC] = { .clk_domain = APB2, .line_num = 4 }, [RCC_GPIOD] = { .clk_domain = APB2, .line_num = 5 }, - [RCC_GPIOE] = { .clk_domain = APB2, .line_num = 6 }, // High-density only - [RCC_GPIOF] = { .clk_domain = APB2, .line_num = 7 }, // High-density only - [RCC_GPIOG] = { .clk_domain = APB2, .line_num = 8 }, // High-density only [RCC_AFIO] = { .clk_domain = APB2, .line_num = 0 }, [RCC_ADC1] = { .clk_domain = APB2, .line_num = 9 }, [RCC_ADC2] = { .clk_domain = APB2, .line_num = 10 }, @@ -58,26 +57,43 @@ 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_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 }, [RCC_TIMER4] = { .clk_domain = APB1, .line_num = 2 }, - [RCC_TIMER5] = { .clk_domain = APB1, .line_num = 3 }, // High-density only - [RCC_TIMER6] = { .clk_domain = APB1, .line_num = 4 }, // High-density only - [RCC_TIMER7] = { .clk_domain = APB1, .line_num = 5 }, // High-density only - [RCC_TIMER8] = { .clk_domain = APB2, .line_num = 13 }, // High-density only [RCC_SPI1] = { .clk_domain = APB2, .line_num = 12 }, [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 = 29 }, // High-density only [RCC_DMA1] = { .clk_domain = AHB, .line_num = 0 }, - [RCC_DMA2] = { .clk_domain = AHB, .line_num = 1 }, // High-density only [RCC_PWR] = { .clk_domain = APB1, .line_num = 28}, [RCC_BKP] = { .clk_domain = APB1, .line_num = 27}, - [RCC_I2C1] = { .clk_domain = APB1, .line_num = 21 }, // High-density only - [RCC_I2C2] = { .clk_domain = APB1, .line_num = 22 }, // High-density only + [RCC_I2C1] = { .clk_domain = APB1, .line_num = 21 }, + [RCC_CRC] = { .clk_domain = AHB, .line_num = 6}, + [RCC_FLITF] = { .clk_domain = AHB, .line_num = 4}, + [RCC_SRAM] = { .clk_domain = AHB, .line_num = 2}, +#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) + [RCC_GPIOE] = { .clk_domain = APB2, .line_num = 6 }, + [RCC_GPIOF] = { .clk_domain = APB2, .line_num = 7 }, + [RCC_GPIOG] = { .clk_domain = APB2, .line_num = 8 }, + [RCC_UART4] = { .clk_domain = APB1, .line_num = 19 }, + [RCC_UART5] = { .clk_domain = APB1, .line_num = 20 }, + [RCC_TIMER5] = { .clk_domain = APB1, .line_num = 3 }, + [RCC_TIMER6] = { .clk_domain = APB1, .line_num = 4 }, + [RCC_TIMER7] = { .clk_domain = APB1, .line_num = 5 }, + [RCC_TIMER8] = { .clk_domain = APB2, .line_num = 13 }, + [RCC_FSMC] = { .clk_domain = AHB, .line_num = 8 }, + [RCC_DAC] = { .clk_domain = APB1, .line_num = 29 }, + [RCC_DMA2] = { .clk_domain = AHB, .line_num = 1 }, + [RCC_I2C2] = { .clk_domain = APB1, .line_num = 22 }, + [RCC_SDIO] = { .clk_domain = AHB, .line_num = 10 }, +#endif +#ifdef STM32_XL_DENSITY + [RCC_TIMER9] = { .clk_domain = APB2, .line_num = 19 }, + [RCC_TIMER10] = { .clk_domain = APB2, .line_num = 20 }, + [RCC_TIMER11] = { .clk_domain = APB2, .line_num = 21 }, + [RCC_TIMER12] = { .clk_domain = APB1, .line_num = 6 }, + [RCC_TIMER13] = { .clk_domain = APB1, .line_num = 7 }, + [RCC_TIMER14] = { .clk_domain = APB1, .line_num = 8 }, +#endif }; /** @@ -87,35 +103,38 @@ static const struct rcc_dev_info rcc_dev_table[] = { * @param pll_src pll clock source, must be HSE * @param pll_mul pll multiplier */ -void rcc_clk_init(uint32 sysclk_src, uint32 pll_src, uint32 pll_mul) { +void rcc_clk_init(rcc_sysclk_src sysclk_src, + rcc_pllsrc pll_src, + rcc_pll_multiplier pll_mul) { + uint32 cfgr; + uint32 cr; + /* Assume that we're going to clock the chip off the PLL, fed by * the HSE */ ASSERT(sysclk_src == RCC_CLKSRC_PLL && pll_src == RCC_PLLSRC_HSE); - uint32 cfgr = 0; - uint32 cr = RCC_READ_CR(); - - cfgr = (pll_src | pll_mul); - RCC_WRITE_CFGR(cfgr); + RCC_BASE->CFGR = pll_src | pll_mul; - /* Turn on the HSE */ + /* Turn on the HSE */ + /* FIXME WTF why doesn't bit-banding work here? */ + cr = RCC_BASE->CR; cr |= RCC_CR_HSEON; - RCC_WRITE_CR(cr); - while (!(RCC_READ_CR() & RCC_CR_HSERDY)) + RCC_BASE->CR = cr; + while (!(RCC_BASE->CR & RCC_CR_HSERDY)) ; /* Now the PLL */ cr |= RCC_CR_PLLON; - RCC_WRITE_CR(cr); - while (!(RCC_READ_CR() & RCC_CR_PLLRDY)) + RCC_BASE->CR = cr; + while (!(RCC_BASE->CR & RCC_CR_PLLRDY)) ; /* Finally, let's switch over to the PLL */ cfgr &= ~RCC_CFGR_SW; cfgr |= RCC_CFGR_SW_PLL; - RCC_WRITE_CFGR(cfgr); - while ((RCC_READ_CFGR() & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) + RCC_BASE->CFGR = cfgr; + while ((RCC_BASE->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) ; } @@ -124,15 +143,35 @@ void rcc_clk_init(uint32 sysclk_src, uint32 pll_src, uint32 pll_mul) { * @param device Clock ID of the device to turn on. */ void rcc_clk_enable(rcc_clk_id device) { - static const uint32 enable_regs[] = { - [APB1] = RCC_APB1ENR, - [APB2] = RCC_APB2ENR, - [AHB] = RCC_AHBENR, + static const __io uint32* enable_regs[] = { + [APB1] = &RCC_BASE->APB1ENR, + [APB2] = &RCC_BASE->APB2ENR, + [AHB] = &RCC_BASE->AHBENR, + }; + + uint8 clk_domain = rcc_dev_table[device].clk_domain; + __io uint32* enr = (__io uint32*)enable_regs[clk_domain]; + uint8 lnum = rcc_dev_table[device].line_num; + + bb_peri_set_bit(enr, lnum, 1); +} + +/** + * @brief reset a device + * @param device Clock ID of the device to reset. + */ +void rcc_reset_dev(rcc_clk_id device) { + static const __io uint32* reset_regs[] = { + [APB1] = &RCC_BASE->APB1RSTR, + [APB2] = &RCC_BASE->APB2RSTR, }; uint8 clk_domain = rcc_dev_table[device].clk_domain; + __io void* addr = (__io void*)reset_regs[clk_domain]; + uint8 lnum = rcc_dev_table[device].line_num; - __set_bits(enable_regs[clk_domain], BIT(rcc_dev_table[device].line_num)); + bb_peri_set_bit(addr, lnum, 1); + bb_peri_set_bit(addr, lnum, 0); } /** @@ -140,7 +179,7 @@ void rcc_clk_enable(rcc_clk_id device) { * @param prescaler prescaler to set * @param divider prescaler divider */ -void rcc_set_prescaler(uint32 prescaler, uint32 divider) { +void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider) { static const uint32 masks[] = { [RCC_PRESCALER_AHB] = RCC_CFGR_HPRE, [RCC_PRESCALER_APB1] = RCC_CFGR_PPRE1, @@ -149,25 +188,8 @@ void rcc_set_prescaler(uint32 prescaler, uint32 divider) { [RCC_PRESCALER_ADC] = RCC_CFGR_ADCPRE, }; - uint32 cfgr = RCC_READ_CFGR(); - + uint32 cfgr = RCC_BASE->CFGR; cfgr &= ~masks[prescaler]; cfgr |= divider; - RCC_WRITE_CFGR(cfgr); -} - -/** - * @brief reset a device - * @param device Clock ID of the device to reset. - */ -void rcc_reset_dev(rcc_clk_id device) { - static const uint32 reset_regs[] = { - [APB1] = RCC_APB1RSTR, - [APB2] = RCC_APB2RSTR, - }; - - uint8 clk_domain = rcc_dev_table[device].clk_domain; - - __set_bits(reset_regs[clk_domain], BIT(rcc_dev_table[device].line_num)); - __clear_bits(reset_regs[clk_domain], BIT(rcc_dev_table[device].line_num)); + RCC_BASE->CFGR = cfgr; } diff --git a/libmaple/rcc.h b/libmaple/rcc.h index dcb9ea2..e6fa196 100644 --- a/libmaple/rcc.h +++ b/libmaple/rcc.h @@ -36,127 +36,402 @@ extern "C"{ #endif -/* registers */ -#define RCC_BASE 0x40021000 -#define RCC_CR (RCC_BASE + 0x0) -#define RCC_CFGR (RCC_BASE + 0x4) -#define RCC_CIR (RCC_BASE + 0x8) -#define RCC_APB2RSTR (RCC_BASE + 0xC) -#define RCC_APB1RSTR (RCC_BASE + 0x10) -#define RCC_AHBENR (RCC_BASE + 0x14) -#define RCC_APB2ENR (RCC_BASE + 0x18) -#define RCC_APB1ENR (RCC_BASE + 0x1C) -#define RCC_BDCR (RCC_BASE + 0x20) -#define RCC_CSR (RCC_BASE + 0x24) -#define RCC_AHBSTR (RCC_BASE + 0x28) -#define RCC_CFGR2 (RCC_BASE + 0x2C) - -#define RCC_CFGR_USBPRE (0x1 << 22) -#define RCC_CFGR_ADCPRE (0x3 << 14) -#define RCC_CFGR_PPRE1 (0x7 << 8) -#define RCC_CFGR_PPRE2 (0x7 << 11) -#define RCC_CFGR_HPRE (0xF << 4) -#define RCC_CFGR_PLLSRC (0x1 << 16) - -#define RCC_CFGR_SWS (0x3 << 2) -#define RCC_CFGR_SWS_PLL (0x2 << 2) -#define RCC_CFGR_SWS_HSE (0x1 << 2) - -#define RCC_CFGR_SW (0x3 << 0) -#define RCC_CFGR_SW_PLL (0x2 << 0) -#define RCC_CFGR_SW_HSE (0x1 << 0) - -/* CR status bits */ -#define RCC_CR_HSEON (0x1 << 16) -#define RCC_CR_HSERDY (0x1 << 17) -#define RCC_CR_PLLON (0x1 << 24) -#define RCC_CR_PLLRDY (0x1 << 25) - -#define RCC_WRITE_CFGR(val) __write(RCC_CFGR, val) -#define RCC_READ_CFGR() __read(RCC_CFGR) - -#define RCC_WRITE_CR(val) __write(RCC_CR, val) -#define RCC_READ_CR() __read(RCC_CR) - -/* sysclk source */ -#define RCC_CLKSRC_HSI (0x0) -#define RCC_CLKSRC_HSE (0x1) -#define RCC_CLKSRC_PLL (0x2) - -/* pll entry clock source */ -#define RCC_PLLSRC_HSE (0x1 << 16) -#define RCC_PLLSRC_HSI_DIV_2 (0x0 << 16) - -/* adc prescaler dividers */ -#define RCC_ADCPRE_PCLK_DIV_2 (0x0 << 14) -#define RCC_ADCPRE_PCLK_DIV_4 (0x1 << 14) -#define RCC_ADCPRE_PCLK_DIV_6 (0x2 << 14) -#define RCC_ADCPRE_PCLK_DIV_8 (0x3 << 14) - -/* apb1 prescaler dividers */ -#define RCC_APB1_HCLK_DIV_1 (0x0 << 8) -#define RCC_APB1_HCLK_DIV_2 (0x4 << 8) -#define RCC_APB1_HCLK_DIV_4 (0x5 << 8) -#define RCC_APB1_HCLK_DIV_8 (0x6 << 8) -#define RCC_APB1_HCLK_DIV_16 (0x7 << 8) - -/* apb2 prescaler dividers */ -#define RCC_APB2_HCLK_DIV_1 (0x0 << 11) -#define RCC_APB2_HCLK_DIV_2 (0x4 << 11) -#define RCC_APB2_HCLK_DIV_4 (0x5 << 11) -#define RCC_APB2_HCLK_DIV_8 (0x6 << 11) -#define RCC_APB2_HCLK_DIV_16 (0x7 << 11) - -/* ahb prescaler dividers */ -#define RCC_AHB_SYSCLK_DIV_1 (0x0 << 4) -#define RCC_AHB_SYSCLK_DIV_2 (0x8 << 4) -#define RCC_AHB_SYSCLK_DIV_4 (0x9 << 4) -#define RCC_AHB_SYSCLK_DIV_8 (0xA << 4) -#define RCC_AHB_SYSCLK_DIV_16 (0xB << 4) -#define RCC_AHB_SYSCLK_DIV_32 (0xC << 4) -#define RCC_AHB_SYSCLK_DIV_64 (0xD << 4) -#define RCC_AHB_SYSCLK_DIV_128 (0xD << 4) -#define RCC_AHB_SYSCLK_DIV_256 (0xE << 4) -#define RCC_AHB_SYSCLK_DIV_512 (0xF << 4) - -/* pll multipliers */ -#define RCC_PLLMUL_2 (0x0 << 18) -#define RCC_PLLMUL_3 (0x1 << 18) -#define RCC_PLLMUL_4 (0x2 << 18) -#define RCC_PLLMUL_5 (0x3 << 18) -#define RCC_PLLMUL_6 (0x4 << 18) -#define RCC_PLLMUL_7 (0x5 << 18) -#define RCC_PLLMUL_8 (0x6 << 18) -#define RCC_PLLMUL_9 (0x7 << 18) -#define RCC_PLLMUL_10 (0x8 << 18) -#define RCC_PLLMUL_11 (0x9 << 18) -#define RCC_PLLMUL_12 (0xA << 18) -#define RCC_PLLMUL_13 (0xB << 18) -#define RCC_PLLMUL_14 (0xC << 18) -#define RCC_PLLMUL_15 (0xD << 18) -#define RCC_PLLMUL_16 (0xE << 18) - - -/* prescalers */ -enum { - RCC_PRESCALER_AHB, - RCC_PRESCALER_APB1, - RCC_PRESCALER_APB2, - RCC_PRESCALER_USB, - RCC_PRESCALER_ADC -}; +/** RCC register map type */ +typedef struct rcc_reg_map { + __io uint32 CR; /**< Clock control register */ + __io uint32 CFGR; /**< Clock configuration register */ + __io uint32 CIR; /**< Clock interrupt register */ + __io uint32 APB2RSTR; /**< APB2 peripheral reset register */ + __io uint32 APB1RSTR; /**< APB1 peripheral reset register */ + __io uint32 AHBENR; /**< AHB peripheral clock enable register */ + __io uint32 APB2ENR; /**< APB2 peripheral clock enable register */ + __io uint32 APB1ENR; /**< APB1 peripheral clock enable register */ + __io uint32 BDCR; /**< Backup domain control register */ + __io uint32 CSR; /**< Control/status register */ +} rcc_reg_map; + +/** RCC register map base pointer */ +#define RCC_BASE ((rcc_reg_map*)0x40021000) /* - * Identifies bus and clock line for a device + * Register bit definitions + */ + +/* Clock control register */ + +#define RCC_CR_PLLRDY_BIT 25 +#define RCC_CR_PLLON_BIT 24 +#define RCC_CR_CSSON_BIT 19 +#define RCC_CR_HSEBYP_BIT 18 +#define RCC_CR_HSERDY_BIT 17 +#define RCC_CR_HSEON_BIT 16 +#define RCC_CR_HSIRDY_BIT 1 +#define RCC_CR_HSION_BIT 0 + +#define RCC_CR_PLLRDY BIT(RCC_CR_PLLRDY_BIT) +#define RCC_CR_PLLON BIT(RCC_CR_PLLON_BIT) +#define RCC_CR_CSSON BIT(RCC_CR_CSSON_BIT) +#define RCC_CR_HSEBYP BIT(RCC_CR_HSEBYP_BIT) +#define RCC_CR_HSERDY BIT(RCC_CR_HSERDY_BIT) +#define RCC_CR_HSEON BIT(RCC_CR_HSEON_BIT) +#define RCC_CR_HSICAL (0xFF << 8) +#define RCC_CR_HSITRIM (0x1F << 3) +#define RCC_CR_HSIRDY BIT(RCC_CR_HSIRDY_BIT) +#define RCC_CR_HSION BIT(RCC_CR_HSION_BIT) + +/* Clock configuration register */ + +#define RCC_CFGR_USBPRE_BIT 22 +#define RCC_CFGR_PLLXTPRE_BIT 17 +#define RCC_CFGR_PLLSRC_BIT 16 + +#define RCC_CFGR_MCO (0x3 << 24) +#define RCC_CFGR_USBPRE BIT(RCC_CFGR_USBPRE_BIT) +#define RCC_CFGR_PLLMUL (0xF << 18) +#define RCC_CFGR_PLLXTPRE BIT(RCC_CFGR_PLLXTPRE_BIT) +#define RCC_CFGR_PLLSRC BIT(RCC_CFGR_PLLSRC_BIT) +#define RCC_CFGR_ADCPRE (0x3 << 14) +#define RCC_CFGR_PPRE2 (0x7 << 11) +#define RCC_CFGR_PPRE1 (0x7 << 8) +#define RCC_CFGR_HPRE (0xF << 4) +#define RCC_CFGR_SWS (0x3 << 2) +#define RCC_CFGR_SWS_PLL (0x2 << 2) +#define RCC_CFGR_SWS_HSE (0x1 << 2) +#define RCC_CFGR_SW 0x3 +#define RCC_CFGR_SW_PLL 0x2 +#define RCC_CFGR_SW_HSE 0x1 + +/* Clock interrupt register */ + +#define RCC_CIR_CSSC_BIT 23 +#define RCC_CIR_PLLRDYC_BIT 20 +#define RCC_CIR_HSERDYC_BIT 19 +#define RCC_CIR_HSIRDYC_BIT 18 +#define RCC_CIR_LSERDYC_BIT 17 +#define RCC_CIR_LSIRDYC_BIT 16 +#define RCC_CIR_PLLRDYIE_BIT 12 +#define RCC_CIR_HSERDYIE_BIT 11 +#define RCC_CIR_HSIRDYIE_BIT 10 +#define RCC_CIR_LSERDYIE_BIT 9 +#define RCC_CIR_LSIRDYIE_BIT 8 +#define RCC_CIR_CSSF_BIT 7 +#define RCC_CIR_PLLRDYF_BIT 4 +#define RCC_CIR_HSERDYF_BIT 3 +#define RCC_CIR_HSIRDYF_BIT 2 +#define RCC_CIR_LSERDYF_BIT 1 +#define RCC_CIR_LSIRDYF_BIT 0 + +#define RCC_CIR_CSSC BIT(RCC_CIR_CSSC_BIT) +#define RCC_CIR_PLLRDYC BIT(RCC_CIR_PLLRDYC_BIT) +#define RCC_CIR_HSERDYC BIT(RCC_CIR_HSERDYC_BIT) +#define RCC_CIR_HSIRDYC BIT(RCC_CIR_HSIRDYC_BIT) +#define RCC_CIR_LSERDYC BIT(RCC_CIR_LSERDYC_BIT) +#define RCC_CIR_LSIRDYC BIT(RCC_CIR_LSIRDYC_BIT) +#define RCC_CIR_PLLRDYIE BIT(RCC_CIR_PLLRDYIE_BIT) +#define RCC_CIR_HSERDYIE BIT(RCC_CIR_HSERDYIE_BIT) +#define RCC_CIR_HSIRDYIE BIT(RCC_CIR_HSIRDYIE_BIT) +#define RCC_CIR_LSERDYIE BIT(RCC_CIR_LSERDYIE_BIT) +#define RCC_CIR_LSIRDYIE BIT(RCC_CIR_LSIRDYIE_BIT) +#define RCC_CIR_CSSF BIT(RCC_CIR_CSSF_BIT) +#define RCC_CIR_PLLRDYF BIT(RCC_CIR_PLLRDYF_BIT) +#define RCC_CIR_HSERDYF BIT(RCC_CIR_HSERDYF_BIT) +#define RCC_CIR_HSIRDYF BIT(RCC_CIR_HSIRDYF_BIT) +#define RCC_CIR_LSERDYF BIT(RCC_CIR_LSERDYF_BIT) +#define RCC_CIR_LSIRDYF BIT(RCC_CIR_LSIRDYF_BIT) + +/* APB2 peripheral reset register */ + +#define RCC_APB2RSTR_TIM11RST_BIT 21 +#define RCC_APB2RSTR_TIM10RST_BIT 20 +#define RCC_APB2RSTR_TIM9RST_BIT 19 +#define RCC_APB2RSTR_ADC3RST_BIT 15 +#define RCC_APB2RSTR_USART1RST_BIT 14 +#define RCC_APB2RSTR_TIM8RST_BIT 13 +#define RCC_APB2RSTR_SPI1RST_BIT 12 +#define RCC_APB2RSTR_TIM1RST_BIT 11 +#define RCC_APB2RSTR_ADC2RST_BIT 10 +#define RCC_APB2RSTR_ADC1RST_BIT 9 +#define RCC_APB2RSTR_IOPGRST_BIT 8 +#define RCC_APB2RSTR_IOPFRST_BIT 7 +#define RCC_APB2RSTR_IOPERST_BIT 6 +#define RCC_APB2RSTR_IOPDRST_BIT 5 +#define RCC_APB2RSTR_IOPCRST_BIT 4 +#define RCC_APB2RSTR_IOPBRST_BIT 3 +#define RCC_APB2RSTR_IOPARST_BIT 2 +#define RCC_APB2RSTR_AFIORST_BIT 0 + +#define RCC_APB2RSTR_TIM11RST BIT(RCC_APB2RSTR_TIM11RST_BIT) +#define RCC_APB2RSTR_TIM10RST BIT(RCC_APB2RSTR_TIM10RST_BIT) +#define RCC_APB2RSTR_TIM9RST BIT(RCC_APB2RSTR_TIM9RST_BIT) +#define RCC_APB2RSTR_ADC3RST BIT(RCC_APB2RSTR_ADC3RST_BIT) +#define RCC_APB2RSTR_USART1RST BIT(RCC_APB2RSTR_USART1RST_BIT) +#define RCC_APB2RSTR_TIM8RST BIT(RCC_APB2RSTR_TIM8RST_BIT) +#define RCC_APB2RSTR_SPI1RST BIT(RCC_APB2RSTR_SPI1RST_BIT) +#define RCC_APB2RSTR_TIM1RST BIT(RCC_APB2RSTR_TIM1RST_BIT) +#define RCC_APB2RSTR_ADC2RST BIT(RCC_APB2RSTR_ADC2RST_BIT) +#define RCC_APB2RSTR_ADC1RST BIT(RCC_APB2RSTR_ADC1RST_BIT) +#define RCC_APB2RSTR_IOPGRST BIT(RCC_APB2RSTR_IOPGRST_BIT) +#define RCC_APB2RSTR_IOPFRST BIT(RCC_APB2RSTR_IOPFRST_BIT) +#define RCC_APB2RSTR_IOPERST BIT(RCC_APB2RSTR_IOPERST_BIT) +#define RCC_APB2RSTR_IOPDRST BIT(RCC_APB2RSTR_IOPDRST_BIT) +#define RCC_APB2RSTR_IOPCRST BIT(RCC_APB2RSTR_IOPCRST_BIT) +#define RCC_APB2RSTR_IOPBRST BIT(RCC_APB2RSTR_IOPBRST_BIT) +#define RCC_APB2RSTR_IOPARST BIT(RCC_APB2RSTR_IOPARST_BIT) +#define RCC_APB2RSTR_AFIORST BIT(RCC_APB2RSTR_AFIORST_BIT) + +/* APB1 peripheral reset register */ + +#define RCC_APB1RSTR_DACRST_BIT 29 +#define RCC_APB1RSTR_PWRRST_BIT 28 +#define RCC_APB1RSTR_BKPRST_BIT 27 +#define RCC_APB1RSTR_CANRST_BIT 25 +#define RCC_APB1RSTR_USBRST_BIT 23 +#define RCC_APB1RSTR_I2C2RST_BIT 22 +#define RCC_APB1RSTR_I2C1RST_BIT 21 +#define RCC_APB1RSTR_UART5RST_BIT 20 +#define RCC_APB1RSTR_UART4RST_BIT 19 +#define RCC_APB1RSTR_USART3RST_BIT 18 +#define RCC_APB1RSTR_USART2RST_BIT 17 +#define RCC_APB1RSTR_SPI3RST_BIT 15 +#define RCC_APB1RSTR_SPI2RST_BIT 14 +#define RCC_APB1RSTR_WWDRST_BIT 11 +#define RCC_APB1RSTR_TIM14RST_BIT 8 +#define RCC_APB1RSTR_TIM13RST_BIT 7 +#define RCC_APB1RSTR_TIM12RST_BIT 6 +#define RCC_APB1RSTR_TIM7RST_BIT 5 +#define RCC_APB1RSTR_TIM6RST_BIT 4 +#define RCC_APB1RSTR_TIM5RST_BIT 3 +#define RCC_APB1RSTR_TIM4RST_BIT 2 +#define RCC_APB1RSTR_TIM3RST_BIT 1 +#define RCC_APB1RSTR_TIM2RST_BIT 0 + +#define RCC_APB1RSTR_DACRST BIT(RCC_APB1RSTR_DACRST_BIT) +#define RCC_APB1RSTR_PWRRST BIT(RCC_APB1RSTR_PWRRST_BIT) +#define RCC_APB1RSTR_BKPRST BIT(RCC_APB1RSTR_BKPRST_BIT) +#define RCC_APB1RSTR_CANRST BIT(RCC_APB1RSTR_CANRST_BIT) +#define RCC_APB1RSTR_USBRST BIT(RCC_APB1RSTR_USBRST_BIT) +#define RCC_APB1RSTR_I2C2RST BIT(RCC_APB1RSTR_I2C2RST_BIT) +#define RCC_APB1RSTR_I2C1RST BIT(RCC_APB1RSTR_I2C1RST_BIT) +#define RCC_APB1RSTR_UART5RST BIT(RCC_APB1RSTR_UART5RST_BIT) +#define RCC_APB1RSTR_UART4RST BIT(RCC_APB1RSTR_UART4RST_BIT) +#define RCC_APB1RSTR_USART3RST BIT(RCC_APB1RSTR_USART3RST_BIT) +#define RCC_APB1RSTR_USART2RST BIT(RCC_APB1RSTR_USART2RST_BIT) +#define RCC_APB1RSTR_SPI3RST BIT(RCC_APB1RSTR_SPI3RST_BIT) +#define RCC_APB1RSTR_SPI2RST BIT(RCC_APB1RSTR_SPI2RST_BIT) +#define RCC_APB1RSTR_WWDRST BIT(RCC_APB1RSTR_WWDRST_BIT) +#define RCC_APB1RSTR_TIM14RST BIT(RCC_APB1RSTR_TIM14RST_BIT) +#define RCC_APB1RSTR_TIM13RST BIT(RCC_APB1RSTR_TIM13RST_BIT) +#define RCC_APB1RSTR_TIM12RST BIT(RCC_APB1RSTR_TIM12RST_BIT) +#define RCC_APB1RSTR_TIM7RST BIT(RCC_APB1RSTR_TIM7RST_BIT) +#define RCC_APB1RSTR_TIM6RST BIT(RCC_APB1RSTR_TIM6RST_BIT) +#define RCC_APB1RSTR_TIM5RST BIT(RCC_APB1RSTR_TIM5RST_BIT) +#define RCC_APB1RSTR_TIM4RST BIT(RCC_APB1RSTR_TIM4RST_BIT) +#define RCC_APB1RSTR_TIM3RST BIT(RCC_APB1RSTR_TIM3RST_BIT) +#define RCC_APB1RSTR_TIM2RST BIT(RCC_APB1RSTR_TIM2RST_BIT) + +/* AHB peripheral clock enable register */ + +#define RCC_AHBENR_SDIOEN_BIT 10 +#define RCC_AHBENR_FSMCEN_BIT 8 +#define RCC_AHBENR_CRCEN_BIT 7 +#define RCC_AHBENR_FLITFEN_BIT 4 +#define RCC_AHBENR_SRAMEN_BIT 2 +#define RCC_AHBENR_DMA2EN_BIT 1 +#define RCC_AHBENR_DMA1EN_BIT 0 + +#define RCC_AHBENR_SDIOEN BIT(RCC_AHBENR_SDIOEN_BIT) +#define RCC_AHBENR_FSMCEN BIT(RCC_AHBENR_FSMCEN_BIT) +#define RCC_AHBENR_CRCEN BIT(RCC_AHBENR_CRCEN_BIT) +#define RCC_AHBENR_FLITFEN BIT(RCC_AHBENR_FLITFEN_BIT) +#define RCC_AHBENR_SRAMEN BIT(RCC_AHBENR_SRAMEN_BIT) +#define RCC_AHBENR_DMA2EN BIT(RCC_AHBENR_DMA2EN_BIT) +#define RCC_AHBENR_DMA1EN BIT(RCC_AHBENR_DMA1EN_BIT) + +/* APB2 peripheral clock enable register */ + +#define RCC_APB2ENR_TIM11EN_BIT 21 +#define RCC_APB2ENR_TIM10EN_BIT 20 +#define RCC_APB2ENR_TIM9EN_BIT 19 +#define RCC_APB2ENR_ADC3EN_BIT 15 +#define RCC_APB2ENR_USART1EN_BIT 14 +#define RCC_APB2ENR_TIM8EN_BIT 13 +#define RCC_APB2ENR_SPI1EN_BIT 12 +#define RCC_APB2ENR_TIM1EN_BIT 11 +#define RCC_APB2ENR_ADC2EN_BIT 10 +#define RCC_APB2ENR_ADC1EN_BIT 9 +#define RCC_APB2ENR_IOPGEN_BIT 8 +#define RCC_APB2ENR_IOPFEN_BIT 7 +#define RCC_APB2ENR_IOPEEN_BIT 6 +#define RCC_APB2ENR_IOPDEN_BIT 5 +#define RCC_APB2ENR_IOPCEN_BIT 4 +#define RCC_APB2ENR_IOPBEN_BIT 3 +#define RCC_APB2ENR_IOPAEN_BIT 2 +#define RCC_APB2ENR_AFIOEN_BIT 0 + +#define RCC_APB2ENR_TIM11EN BIT(RCC_APB2ENR_TIM11EN_BIT) +#define RCC_APB2ENR_TIM10EN BIT(RCC_APB2ENR_TIM10EN_BIT) +#define RCC_APB2ENR_TIM9EN BIT(RCC_APB2ENR_TIM9EN_BIT) +#define RCC_APB2ENR_ADC3EN BIT(RCC_APB2ENR_ADC3EN_BIT) +#define RCC_APB2ENR_USART1EN BIT(RCC_APB2ENR_USART1EN_BIT) +#define RCC_APB2ENR_TIM8EN BIT(RCC_APB2ENR_TIM8EN_BIT) +#define RCC_APB2ENR_SPI1EN BIT(RCC_APB2ENR_SPI1EN_BIT) +#define RCC_APB2ENR_TIM1EN BIT(RCC_APB2ENR_TIM1EN_BIT) +#define RCC_APB2ENR_ADC2EN BIT(RCC_APB2ENR_ADC2EN_BIT) +#define RCC_APB2ENR_ADC1EN BIT(RCC_APB2ENR_ADC1EN_BIT) +#define RCC_APB2ENR_IOPGEN BIT(RCC_APB2ENR_IOPGEN_BIT) +#define RCC_APB2ENR_IOPFEN BIT(RCC_APB2ENR_IOPFEN_BIT) +#define RCC_APB2ENR_IOPEEN BIT(RCC_APB2ENR_IOPEEN_BIT) +#define RCC_APB2ENR_IOPDEN BIT(RCC_APB2ENR_IOPDEN_BIT) +#define RCC_APB2ENR_IOPCEN BIT(RCC_APB2ENR_IOPCEN_BIT) +#define RCC_APB2ENR_IOPBEN BIT(RCC_APB2ENR_IOPBEN_BIT) +#define RCC_APB2ENR_IOPAEN BIT(RCC_APB2ENR_IOPAEN_BIT) +#define RCC_APB2ENR_AFIOEN BIT(RCC_APB2ENR_AFIOEN_BIT) + +/* APB1 peripheral clock enable register */ + +#define RCC_APB1ENR_DACEN_BIT 29 +#define RCC_APB1ENR_PWREN_BIT 28 +#define RCC_APB1ENR_BKPEN_BIT 27 +#define RCC_APB1ENR_CANEN_BIT 25 +#define RCC_APB1ENR_USBEN_BIT 23 +#define RCC_APB1ENR_I2C2EN_BIT 22 +#define RCC_APB1ENR_I2C1EN_BIT 21 +#define RCC_APB1ENR_UART5EN_BIT 20 +#define RCC_APB1ENR_UART4EN_BIT 19 +#define RCC_APB1ENR_USART3EN_BIT 18 +#define RCC_APB1ENR_USART2EN_BIT 17 +#define RCC_APB1ENR_SPI3EN_BIT 15 +#define RCC_APB1ENR_SPI2EN_BIT 14 +#define RCC_APB1ENR_WWDEN_BIT 11 +#define RCC_APB1ENR_TIM14EN_BIT 8 +#define RCC_APB1ENR_TIM13EN_BIT 7 +#define RCC_APB1ENR_TIM12EN_BIT 6 +#define RCC_APB1ENR_TIM7EN_BIT 5 +#define RCC_APB1ENR_TIM6EN_BIT 4 +#define RCC_APB1ENR_TIM5EN_BIT 3 +#define RCC_APB1ENR_TIM4EN_BIT 2 +#define RCC_APB1ENR_TIM3EN_BIT 1 +#define RCC_APB1ENR_TIM2EN_BIT 0 + +#define RCC_APB1ENR_DACEN BIT(RCC_APB1ENR_DACEN_BIT) +#define RCC_APB1ENR_PWREN BIT(RCC_APB1ENR_PWREN_BIT) +#define RCC_APB1ENR_BKPEN BIT(RCC_APB1ENR_BKPEN_BIT) +#define RCC_APB1ENR_CANEN BIT(RCC_APB1ENR_CANEN_BIT) +#define RCC_APB1ENR_USBEN BIT(RCC_APB1ENR_USBEN_BIT) +#define RCC_APB1ENR_I2C2EN BIT(RCC_APB1ENR_I2C2EN_BIT) +#define RCC_APB1ENR_I2C1EN BIT(RCC_APB1ENR_I2C1EN_BIT) +#define RCC_APB1ENR_UART5EN BIT(RCC_APB1ENR_UART5EN_BIT) +#define RCC_APB1ENR_UART4EN BIT(RCC_APB1ENR_UART4EN_BIT) +#define RCC_APB1ENR_USART3EN BIT(RCC_APB1ENR_USART3EN_BIT) +#define RCC_APB1ENR_USART2EN BIT(RCC_APB1ENR_USART2EN_BIT) +#define RCC_APB1ENR_SPI3EN BIT(RCC_APB1ENR_SPI3EN_BIT) +#define RCC_APB1ENR_SPI2EN BIT(RCC_APB1ENR_SPI2EN_BIT) +#define RCC_APB1ENR_WWDEN BIT(RCC_APB1ENR_WWDEN_BIT) +#define RCC_APB1ENR_TIM14EN BIT(RCC_APB1ENR_TIM14EN_BIT) +#define RCC_APB1ENR_TIM13EN BIT(RCC_APB1ENR_TIM13EN_BIT) +#define RCC_APB1ENR_TIM12EN BIT(RCC_APB1ENR_TIM12EN_BIT) +#define RCC_APB1ENR_TIM7EN BIT(RCC_APB1ENR_TIM7EN_BIT) +#define RCC_APB1ENR_TIM6EN BIT(RCC_APB1ENR_TIM6EN_BIT) +#define RCC_APB1ENR_TIM5EN BIT(RCC_APB1ENR_TIM5EN_BIT) +#define RCC_APB1ENR_TIM4EN BIT(RCC_APB1ENR_TIM4EN_BIT) +#define RCC_APB1ENR_TIM3EN BIT(RCC_APB1ENR_TIM3EN_BIT) +#define RCC_APB1ENR_TIM2EN BIT(RCC_APB1ENR_TIM2EN_BIT) + +/* Backup domain control register */ + +#define RCC_BDCR_BDRST_BIT 16 +#define RCC_BDCR_RTCEN_BIT 15 +#define RCC_BDCR_LSEBYP_BIT 2 +#define RCC_BDCR_LSERDY_BIT 1 +#define RCC_BDCR_LSEON_BIT 0 + +#define RCC_BDCR_BDRST BIT(RCC_BDCR_BDRST_BIT) +#define RCC_BDCR_RTCEN BIT(RCC_BDCR_RTC_BIT) +#define RCC_BDCR_RTCSEL (0x3 << 8) +#define RCC_BDCR_RTCSEL_NONE (0x0 << 8) +#define RCC_BDCR_RTCSEL_LSE (0x1 << 8) +#define RCC_BDCR_RTCSEL_HSE (0x3 << 8) +#define RCC_BDCR_LSEBYP BIT(RCC_BDCR_LSEBYP_BIT) +#define RCC_BDCR_LSERDY BIT(RCC_BDCR_LSERDY_BIT) +#define RCC_BDCR_LSEON BIT(RCC_BDCR_LSEON_BIT) + +/* Control/status register */ + +#define RCC_CSR_LPWRRSTF_BIT 31 +#define RCC_CSR_WWDGRSTF_BIT 30 +#define RCC_CSR_IWDGRSTF_BIT 29 +#define RCC_CSR_SFTRSTF_BIT 28 +#define RCC_CSR_PORRSTF_BIT 27 +#define RCC_CSR_PINRSTF_BIT 26 +#define RCC_CSR_RMVF_BIT 24 +#define RCC_CSR_LSIRDY_BIT 1 +#define RCC_CSR_LSION_BIT 0 + +#define RCC_CSR_LPWRRSTF BIT(RCC_CSR_LPWRRSTF_BIT) +#define RCC_CSR_WWDGRSTF BIT(RCC_CSR_WWDGRSTF_BIT) +#define RCC_CSR_IWDGRSTF BIT(RCC_CSR_IWDGRSTF_BIT) +#define RCC_CSR_SFTRSTF BIT(RCC_CSR_SFTRSTF_BIT) +#define RCC_CSR_PORRSTF BIT(RCC_CSR_PORRSTF_BIT) +#define RCC_CSR_PINRSTF BIT(RCC_CSR_PINRSTF_BIT) +#define RCC_CSR_RMVF BIT(RCC_CSR_RMVF_BIT) +#define RCC_CSR_LSIRDY BIT(RCC_CSR_LSIRDY_BIT) +#define RCC_CSR_LSION BIT(RCC_CSR_LSION_BIT) + +/* + * Convenience routines + */ + +/** + * SYSCLK sources + * @see rcc_clk_init() + */ +typedef enum rcc_sysclk_src { + RCC_CLKSRC_HSI = 0x0, + RCC_CLKSRC_HSE = 0x1, + RCC_CLKSRC_PLL = 0x2, +} rcc_sysclk_src; + +/** + * PLL entry clock source + * @see rcc_clk_init() + */ +typedef enum rcc_pllsrc { + RCC_PLLSRC_HSE = (0x1 << 16), + RCC_PLLSRC_HSI_DIV_2 = (0x0 << 16) +} rcc_pllsrc; + +/** + * PLL multipliers + * @see rcc_clk_init() + */ +typedef enum rcc_pll_multiplier { + RCC_PLLMUL_2 = (0x0 << 18), + RCC_PLLMUL_3 = (0x1 << 18), + RCC_PLLMUL_4 = (0x2 << 18), + RCC_PLLMUL_5 = (0x3 << 18), + RCC_PLLMUL_6 = (0x4 << 18), + RCC_PLLMUL_7 = (0x5 << 18), + RCC_PLLMUL_8 = (0x6 << 18), + RCC_PLLMUL_9 = (0x7 << 18), + RCC_PLLMUL_10 = (0x8 << 18), + RCC_PLLMUL_11 = (0x9 << 18), + RCC_PLLMUL_12 = (0xA << 18), + RCC_PLLMUL_13 = (0xB << 18), + RCC_PLLMUL_14 = (0xC << 18), + RCC_PLLMUL_15 = (0xD << 18), + RCC_PLLMUL_16 = (0xE << 18), +} rcc_pll_multiplier; + +/** + * @brief Identifies bus and clock line for a device + * + * Also generally useful as a unique identifier for that device. */ typedef enum { RCC_GPIOA, RCC_GPIOB, RCC_GPIOC, RCC_GPIOD, - RCC_GPIOE, // High-density devices only (Maple Native) - RCC_GPIOF, // High-density devices only (Maple Native) - RCC_GPIOG, // High-density devices only (Maple Native) RCC_AFIO, RCC_ADC1, RCC_ADC2, @@ -164,32 +439,116 @@ typedef enum { RCC_USART1, RCC_USART2, RCC_USART3, - RCC_UART4, // High-density devices only (Maple Native) - RCC_UART5, // High-density devices only (Maple Native) RCC_TIMER1, RCC_TIMER2, RCC_TIMER3, RCC_TIMER4, - RCC_TIMER5, // High-density devices only (Maple Native) - RCC_TIMER6, // High-density devices only (Maple Native) - RCC_TIMER7, // High-density devices only (Maple Native) - RCC_TIMER8, // High-density devices only (Maple Native) RCC_SPI1, 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) RCC_PWR, RCC_BKP, RCC_I2C1, - RCC_I2C2 + RCC_CRC, + RCC_FLITF, + RCC_SRAM, +#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) + RCC_GPIOE, + RCC_GPIOF, + RCC_GPIOG, + RCC_UART4, + RCC_UART5, + RCC_TIMER5, + RCC_TIMER6, + RCC_TIMER7, + RCC_TIMER8, + RCC_FSMC, + RCC_DAC, + RCC_DMA2, + RCC_I2C2, + RCC_SDIO, +#endif +#ifdef STM32_XL_DENSITY + RCC_TIMER9, + RCC_TIMER10, + RCC_TIMER11, + RCC_TIMER12, + RCC_TIMER13, + RCC_TIMER14, +#endif } rcc_clk_id; -void rcc_clk_init(uint32 sysclk_src, uint32 pll_src, uint32 pll_mul); +void rcc_clk_init(rcc_sysclk_src sysclk_src, + rcc_pllsrc pll_src, + rcc_pll_multiplier pll_mul); void rcc_clk_enable(rcc_clk_id device); void rcc_reset_dev(rcc_clk_id device); -void rcc_set_prescaler(uint32 prescaler, uint32 divider); + +/** + * Prescaler identifiers + * @see rcc_set_prescaler() + */ +typedef enum rcc_prescaler { + RCC_PRESCALER_AHB, + RCC_PRESCALER_APB1, + RCC_PRESCALER_APB2, + RCC_PRESCALER_USB, + RCC_PRESCALER_ADC +} rcc_prescaler; + +/** + * ADC prescaler dividers + * @see rcc_set_prescaler() + */ +typedef enum adc_prescaler_divider { + RCC_ADCPRE_PCLK_DIV_2 = 0x0 << 14, + RCC_ADCPRE_PCLK_DIV_4 = 0x1 << 14, + RCC_ADCPRE_PCLK_DIV_6 = 0x2 << 14, + RCC_ADCPRE_PCLK_DIV_8 = 0x3 << 14, +} adc_prescaler_divider; + +/** + * APB1 prescaler dividers + * @see rcc_set_prescaler() + */ +typedef enum apb1_prescaler_divider { + RCC_APB1_HCLK_DIV_1 = 0x0 << 8, + RCC_APB1_HCLK_DIV_2 = 0x4 << 8, + RCC_APB1_HCLK_DIV_4 = 0x5 << 8, + RCC_APB1_HCLK_DIV_8 = 0x6 << 8, + RCC_APB1_HCLK_DIV_16 = 0x7 << 8, +} apb1_prescaler_divider; + +/** + * APB2 prescaler dividers + * @see rcc_set_prescaler() + */ +typedef enum apb2_prescaler_divider { + RCC_APB2_HCLK_DIV_1 = 0x0 << 11, + RCC_APB2_HCLK_DIV_2 = 0x4 << 11, + RCC_APB2_HCLK_DIV_4 = 0x5 << 11, + RCC_APB2_HCLK_DIV_8 = 0x6 << 11, + RCC_APB2_HCLK_DIV_16 = 0x7 << 11, +} apb2_prescaler_divider; + +/** + * AHB prescaler dividers + * @see rcc_set_prescaler() + */ +typedef enum ahb_prescaler_divider { + RCC_AHB_SYSCLK_DIV_1 = 0x0 << 4, + RCC_AHB_SYSCLK_DIV_2 = 0x8 << 4, + RCC_AHB_SYSCLK_DIV_4 = 0x9 << 4, + RCC_AHB_SYSCLK_DIV_8 = 0xA << 4, + RCC_AHB_SYSCLK_DIV_16 = 0xB << 4, + RCC_AHB_SYSCLK_DIV_32 = 0xC << 4, + RCC_AHB_SYSCLK_DIV_64 = 0xD << 4, + RCC_AHB_SYSCLK_DIV_128 = 0xD << 4, + RCC_AHB_SYSCLK_DIV_256 = 0xE << 4, + RCC_AHB_SYSCLK_DIV_512 = 0xF << 4, +} ahb_prescaler_divider; + +void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider); #ifdef __cplusplus } // extern "C" -- cgit v1.2.3 From 6bc8cb7c1181e8005019e4ce1f2bea956c44e044 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Thu, 17 Mar 2011 14:22:54 -0400 Subject: Adding license to ring_buffer.h --- libmaple/ring_buffer.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/libmaple/ring_buffer.h b/libmaple/ring_buffer.h index 3b5d4e7..eadb292 100644 --- a/libmaple/ring_buffer.h +++ b/libmaple/ring_buffer.h @@ -1,3 +1,29 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + /** * @file ring_buffer.h * @brief Simple circular buffer -- cgit v1.2.3 From 61db54f52f32e63c895d775982fbcdcb67f2dde6 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Tue, 22 Mar 2011 16:59:29 -0400 Subject: Initial timer refactor. Basic PWM works. Had some problems in testing that might be due to USART bugs. HardwareTimer has been removed from the build for now; I will re-implement it in terms of the new libmaple API, but consider it deprecated. Let's come up with something better. Servo is implemented in terms of HardwareTimer, so it also has been temporarily removed from the build. pwmWrite() likely got a little bit less inefficient due to indirection, but the PIN_MAPs shrank by a pointer per PinMapping. --- Makefile | 2 +- examples/test-session.cpp | 19 +- examples/test-timers.cpp | 372 ++++++++------- libmaple/bitband.h | 5 + libmaple/delay.h | 2 +- libmaple/nvic.h | 101 ++-- libmaple/rules.mk | 2 +- libmaple/spi.h | 3 + libmaple/timer.c | 449 ++++++++++++++++++ libmaple/timer.h | 1010 ++++++++++++++++++++++++++++++++++++++++ libmaple/timers.c | 526 --------------------- libmaple/timers.h | 435 ----------------- libmaple/util.c | 2 +- libraries/Servo/Servo.h | 1 + notes/portable.txt | 94 +--- notes/usb.txt | 4 + notes/vga.txt | 9 +- wirish/boards.cpp | 646 +++++++++---------------- wirish/boards.h | 9 +- wirish/comm/HardwareSPI.cpp | 4 +- wirish/comm/HardwareSerial.cpp | 20 +- wirish/comm/HardwareSerial.h | 12 +- wirish/pwm.cpp | 22 +- wirish/rules.mk | 1 - wirish/wirish.cpp | 122 +++-- wirish/wirish.h | 3 - wirish/wirish_digital.cpp | 6 +- 27 files changed, 2095 insertions(+), 1786 deletions(-) create mode 100644 libmaple/timer.c create mode 100644 libmaple/timer.h delete mode 100644 libmaple/timers.c delete mode 100644 libmaple/timers.h diff --git a/Makefile b/Makefile index d31c9ed..109a126 100644 --- a/Makefile +++ b/Makefile @@ -97,7 +97,7 @@ endif LIBMAPLE_MODULES := $(SRCROOT)/libmaple LIBMAPLE_MODULES += $(SRCROOT)/wirish # Official libraries: -LIBMAPLE_MODULES += $(SRCROOT)/libraries/Servo +# LIBMAPLE_MODULES += $(SRCROOT)/libraries/Servo LIBMAPLE_MODULES += $(SRCROOT)/libraries/LiquidCrystal LIBMAPLE_MODULES += $(SRCROOT)/libraries/Wire diff --git a/examples/test-session.cpp b/examples/test-session.cpp index a147e06..9b4bce4 100644 --- a/examples/test-session.cpp +++ b/examples/test-session.cpp @@ -15,7 +15,6 @@ //#define COMM Serial2 //#define COMM Serial3 - #define ESC ((uint8)27) int rate = 0; @@ -610,17 +609,15 @@ void cmd_servo_sweep(void) { COMM.println("(reset serial port)"); } +static uint16 init_all_timers_prescale = 0; + +static void set_prescale(timer_dev *dev) { + timer_set_prescaler(dev, init_all_timers_prescale); +} + void init_all_timers(uint16 prescale) { - timer_init(TIMER1, prescale); - timer_init(TIMER2, prescale); - timer_init(TIMER3, prescale); - timer_init(TIMER4, prescale); -#ifdef STM32_HIGH_DENSITY - timer_init(TIMER5, prescale); - // timer_init(TIMER6, prescale); - // timer_init(TIMER7, prescale); - timer_init(TIMER8, prescale); -#endif + init_all_timers_prescale = prescale; + timer_foreach(set_prescale); } // Force init to be called *first*, i.e. before static object allocation. diff --git a/examples/test-timers.cpp b/examples/test-timers.cpp index f3cfdcc..a4fbc8a 100644 --- a/examples/test-timers.cpp +++ b/examples/test-timers.cpp @@ -1,8 +1,7 @@ -// Program to test the wirish timers implementation +// Program to test the timer.h implementation's essential functionality. #include "wirish.h" - -#define LED_PIN BOARD_LED_PIN +#include "timer.h" void handler1(void); void handler2(void); @@ -27,208 +26,253 @@ uint16 val2 = 10000; uint16 val3 = 10000; uint16 val4 = 10000; -HardwareTimer Timers[] = {Timer1, Timer2, Timer3, Timer4}; +// FIXME high density timer test (especially basic timers + DAC) +timer_dev *timers[] = {TIMER1, TIMER2, TIMER3, TIMER4}; +voidFuncPtr handlers[] = {handler1, handler2, handler3, handler4}; + +void initTimer(timer_dev *dev); +void setTimerPeriod(timer_dev *dev, uint32 period_us); +void testSetTimerPeriod(uint32 period); +void testTimerChannels(timer_dev *dev); +int timerNumber(timer_dev *dev); -void setup() -{ - /* Set up the LED to blink */ - pinMode(LED_PIN, OUTPUT); +void setup() { + // Set up the LED to blink + pinMode(BOARD_LED_PIN, OUTPUT); // Setup the button as input pinMode(BOARD_BUTTON_PIN, INPUT); - // Wait for user to attach... - waitForButtonPress(0); - - // Send a message out SerialUSB - SerialUSB.println("Beginning timer test..."); - for(int t=0; t<4; t++) { - Timers[t].setChannel1Mode(TIMER_OUTPUTCOMPARE); - Timers[t].setChannel2Mode(TIMER_OUTPUTCOMPARE); - Timers[t].setChannel3Mode(TIMER_OUTPUTCOMPARE); - Timers[t].setChannel4Mode(TIMER_OUTPUTCOMPARE); - } + // Send a message out Serial2 + Serial2.begin(115200); + Serial2.println("*** Initializing timers..."); + Serial2.println("foo"); + timer_foreach(initTimer); + Serial2.println("*** Done. Beginning timer test."); } void loop() { - SerialUSB.println("-----------------------------------------------------"); - SerialUSB.println("Testing setCount/getCount"); - SerialUSB.print("Timer1.getCount() = "); SerialUSB.println(Timer1.getCount()); - SerialUSB.println("Timer1.setCount(1234)"); - Timer1.setCount(1234); - SerialUSB.print("Timer1.getCount() = "); SerialUSB.println(Timer1.getCount()); - // This tests whether the pause/resume functions work; when BUT is held - // down Timer4 is in the "pause" state and the timer doesn't increment, so - // the final counts should reflect the ratio of time that BUT was held down - SerialUSB.println("-----------------------------------------------------"); - SerialUSB.println("Testing Pause/Resume; button roughly controls Timer4"); + Serial2.println("-----------------------------------------------------"); + + Serial2.println("Testing timer_get_count()/timer_set_count()"); + Serial2.print("TIMER1 count = "); + Serial2.println(timer_get_count(TIMER1)); + Serial2.println("timer_set_count(TIMER1, 1234)"); + timer_set_count(TIMER1, 1234); + Serial2.print("timer_get_count(TIMER1) = "); + Serial2.println(timer_get_count(TIMER1)); + + Serial2.println("-----------------------------------------------------"); + Serial2.println("Testing pause/resume; button roughly controls TIMER4"); + // when BUT is held down, TIMER4 is in the "pause" state and the + // timer doesn't increment, so the final counts should reflect the + // ratio of time that BUT was held down. count3 = 0; count4 = 0; - Timer3.setChannel1Mode(TIMER_OUTPUTCOMPARE); - Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE); - Timer3.pause(); - Timer4.pause(); - Timer3.setCount(0); - Timer4.setCount(0); - Timer3.setOverflow(30000); - Timer4.setOverflow(30000); - Timer3.setCompare1(1000); - Timer4.setCompare1(1000); - Timer3.attachCompare1Interrupt(handler3b); - Timer4.attachCompare1Interrupt(handler4b); - Timer3.resume(); - Timer4.resume(); - SerialUSB.println("~4 seconds..."); - for(int i = 0; i<4000; i++) { - if(isButtonPressed()) { - Timer4.pause(); + timer_set_mode(TIMER3, TIMER_CH1, TIMER_OUTPUT_COMPARE); + timer_set_mode(TIMER4, TIMER_CH1, TIMER_OUTPUT_COMPARE); + timer_pause(TIMER3); + timer_pause(TIMER4); + timer_set_count(TIMER3, 0); + timer_set_count(TIMER4, 0); + timer_set_reload(TIMER3, 30000); + timer_set_reload(TIMER4, 30000); + timer_set_compare(TIMER3, 1, 1000); + timer_set_compare(TIMER4, 1, 1000); + timer_attach_interrupt(TIMER3, TIMER_CC1_INTERRUPT, handler3b); + timer_attach_interrupt(TIMER4, TIMER_CC1_INTERRUPT, handler4b); + timer_resume(TIMER3); + timer_resume(TIMER4); + + Serial2.println("Testing for ~4 seconds..."); + for(int i = 0; i < 4000; i++) { + if (isButtonPressed()) { + timer_pause(TIMER4); } else { - Timer4.resume(); + timer_resume(TIMER4); } delay(1); } - Timer3.setChannel1Mode(TIMER_DISABLED); - Timer4.setChannel1Mode(TIMER_DISABLED); - SerialUSB.print("Count3: "); SerialUSB.println(count3); - SerialUSB.print("Count4: "); SerialUSB.println(count4); - - // These test the setPeriod auto-configure functionality - SerialUSB.println("-----------------------------------------------------"); - SerialUSB.println("Testing setPeriod"); - Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE); - Timer4.setCompare1(1); - Timer4.setPeriod(10); - Timer4.pause(); - Timer4.setCount(0); - Timer4.attachCompare1Interrupt(handler4b); - SerialUSB.println("Period 10ms, wait 2 seconds..."); - count4 = 0; - Timer4.resume(); - delay(2000); - Timer4.pause(); - Timer4.setChannel1Mode(TIMER_DISABLED); - SerialUSB.print("Count4: "); SerialUSB.println(count4); - SerialUSB.println("(should be around 2sec/10ms = 200000)"); - Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE); - Timer4.setCompare1(1); - Timer4.pause(); - Timer4.setPeriod(30000); - Timer4.setCount(0); - Timer4.attachCompare1Interrupt(handler4b); - SerialUSB.println("Period 30000ms, wait 2 seconds..."); - count4 = 0; - Timer4.resume(); - delay(2000); - Timer4.pause(); - Timer4.setChannel1Mode(TIMER_DISABLED); - SerialUSB.print("Count4: "); SerialUSB.println(count4); - SerialUSB.println("(should be around 2sec/30000ms ~ 67)"); - - Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE); - Timer4.setPeriod(300000); - Timer4.setCompare1(1); - Timer4.pause(); - Timer4.setCount(0); - Timer4.attachCompare1Interrupt(handler4b); - SerialUSB.println("Period 300000ms, wait 2 seconds..."); - count4 = 0; - Timer4.resume(); - delay(2000); - Timer4.pause(); - Timer4.setChannel1Mode(TIMER_DISABLED); - SerialUSB.print("Count4: "); SerialUSB.println(count4); - SerialUSB.println("(should be around 2sec/300000ms ~ 6.7)"); - - Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE); - Timer4.setPrescaleFactor(33); - Timer4.setOverflow(65454); - Timer4.pause(); - Timer4.setCount(0); - Timer4.setCompare1(1); - Timer4.attachCompare1Interrupt(handler4b); - SerialUSB.println("Period 30000ms, wait 2 seconds..."); + + timer_set_mode(TIMER3, TIMER_CH1, TIMER_DISABLED); + timer_set_mode(TIMER4, TIMER_CH1, TIMER_DISABLED); + + Serial2.print("TIMER3 count: "); + Serial2.println(timer_get_count(TIMER3)); + Serial2.print("TIMER4 count: "); + Serial2.println(timer_get_count(TIMER4)); + + Serial2.println("-----------------------------------------------------"); + Serial2.println("Testing setTimerPeriod()"); + testSetTimerPeriod(10); + testSetTimerPeriod(30000); + testSetTimerPeriod(300000); + testSetTimerPeriod(30000); + + Serial2.println("Sanity check (with hand-coded reload and prescaler for " + "72 MHz timers):"); + timer_set_mode(TIMER4, TIMER_CH1, TIMER_OUTPUT_COMPARE); + timer_set_prescaler(TIMER4, 33); + timer_set_reload(TIMER4, 65454); + timer_pause(TIMER4); + timer_set_count(TIMER4, 0); + timer_set_compare(TIMER4, TIMER_CH1, 1); + timer_attach_interrupt(TIMER4, TIMER_CC1_INTERRUPT, handler4b); + Serial2.println("Period 30000ms, wait 2 seconds..."); count4 = 0; - Timer4.resume(); + timer_resume(TIMER4); delay(2000); - Timer4.pause(); - Timer4.setChannel1Mode(TIMER_DISABLED); - SerialUSB.print("Count4: "); SerialUSB.println(count4); - SerialUSB.println("(should be around 2sec/30000ms ~ 67)"); - - Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE); - Timer4.setCompare1(1); - Timer4.setPeriod(30000); - Timer4.pause(); - Timer4.setCount(0); - Timer4.attachCompare1Interrupt(handler4b); - SerialUSB.println("Period 30000ms, wait 2 seconds..."); + timer_pause(TIMER4); + timer_set_mode(TIMER4, TIMER_CH1, TIMER_DISABLED); + Serial2.print("TIMER4 count: "); + Serial2.println(count4); + Serial2.println(" (Should be around 2sec/30000ms ~ 67)"); + + // Test all the individual timer channels + timer_foreach(testTimerChannels); +} + +void initTimer(timer_dev *dev) { + switch (dev->type) { + case TIMER_ADVANCED: + case TIMER_GENERAL: + Serial2.print("Initializing timer "); + Serial2.println(timerNumber(dev)); + for (int c = 1; c <= 4; c++) { + timer_set_mode(dev, c, TIMER_OUTPUT_COMPARE); + } + Serial2.println("Done."); + break; + case TIMER_BASIC: + break; + } +} + +void testSetTimerPeriod(uint32 period) { + timer_set_mode(TIMER4, TIMER_CH1, TIMER_OUTPUT_COMPARE); + timer_set_compare(TIMER4, TIMER_CH1, 1); + setTimerPeriod(TIMER4, period); + timer_pause(TIMER4); + timer_set_count(TIMER4, 0); + timer_attach_interrupt(TIMER4, TIMER_CC1_INTERRUPT, handler4b); + Serial2.println("Period "); + Serial2.print(period); + Serial2.print(" ms. Waiting 2 seconds..."); count4 = 0; - Timer4.resume(); + timer_resume(TIMER4); delay(2000); - Timer4.pause(); - Timer4.setChannel1Mode(TIMER_DISABLED); - SerialUSB.print("Count4: "); SerialUSB.println(count4); - SerialUSB.println("(should be around 2sec/30000ms ~ 67)"); - - // This section is to touch every channel of every timer. The output - // ratios should reflect the ratios of the rate variables. Demonstrates - // that over time the actual timing rates get blown away by other system - // interrupts. - for(t=0; t<4; t++) { - toggleLED(); - delay(100); - SerialUSB.println("-----------------------------------------------------"); - SerialUSB.print("Testing Timer "); SerialUSB.println(t+1); + timer_pause(TIMER4); + timer_set_mode(TIMER4, TIMER_CH1, TIMER_DISABLED); + Serial2.print("TIMER4 count: "); + Serial2.println(timer_get_count(TIMER4)); + Serial2.print(" (Should be around 2 sec / "); + Serial2.print(period); + Serial2.print(" ms = "); + Serial2.print(double(2) / period * 1000); + Serial2.println(", modulo delays due to interrupts)"); +} + +int timerNumber(timer_dev *dev) { + switch (dev->clk_id) { + case RCC_TIMER1: + return 1; + case RCC_TIMER2: + return 2; + case RCC_TIMER3: + return 3; + case RCC_TIMER4: + return 4; +#ifdef STM32_HIGH_DENSITY + case RCC_TIMER5: + return 5; + case RCC_TIMER6: + return 6; + case RCC_TIMER7: + return 7; + case RCC_TIMER8: + return 8; +#endif + default: + ASSERT(0); + return 0; + } +} + +/* This function touches every channel of a given timer. The output + * ratios should reflect the ratios of the rate variables. It + * demonstrates that, over time, the actual timing rates get blown + * away by other system interrupts. */ +void testTimerChannels(timer_dev *dev) { + t = timerNumber(dev); + toggleLED(); + delay(100); + Serial2.println("-----------------------------------------------------"); + switch (dev->type) { + case TIMER_BASIC: + Serial2.print("NOT testing channels for basic timer "); + Serial2.println(t); + break; + case TIMER_ADVANCED: + case TIMER_GENERAL: + Serial2.print("Testing channels for timer "); + Serial2.println(t); + timer_pause(dev); count1 = count2 = count3 = count4 = 0; - Timers[t].setOverflow(0xFFFF); - Timers[t].setPrescaleFactor(1); - Timers[t].setCompare1(65535); - Timers[t].setCompare2(65535); - Timers[t].setCompare3(65535); - Timers[t].setCompare4(65535); - Timers[t].setChannel1Mode(TIMER_OUTPUTCOMPARE); - Timers[t].setChannel2Mode(TIMER_OUTPUTCOMPARE); - Timers[t].setChannel3Mode(TIMER_OUTPUTCOMPARE); - Timers[t].setChannel4Mode(TIMER_OUTPUTCOMPARE); - Timers[t].attachCompare1Interrupt(handler1); - Timers[t].attachCompare2Interrupt(handler2); - Timers[t].attachCompare3Interrupt(handler3); - Timers[t].attachCompare4Interrupt(handler4); - Timers[t].resume(); + timer_set_reload(dev, 0xFFFF); + timer_set_prescaler(dev, 1); + for (int c = 1; c <= 4; c++) { + timer_set_compare(dev, c, 65535); + timer_set_mode(dev, c, TIMER_OUTPUT_COMPARE); + timer_attach_interrupt(dev, c, handlers[c - 1]); + } + timer_resume(dev); delay(3000); - Timers[t].setChannel1Mode(TIMER_DISABLED); - Timers[t].setChannel2Mode(TIMER_DISABLED); - Timers[t].setChannel3Mode(TIMER_DISABLED); - Timers[t].setChannel4Mode(TIMER_DISABLED); - SerialUSB.print("Count1: "); SerialUSB.println(count1); - SerialUSB.print("Count2: "); SerialUSB.println(count2); - SerialUSB.print("Count3: "); SerialUSB.println(count3); - SerialUSB.print("Count4: "); SerialUSB.println(count4); + for (int c = 1; c <= 4; c++) { + timer_set_mode(dev, c, TIMER_DISABLED); + } + Serial2.print("Channel 1 count: "); Serial2.println(count1); + Serial2.print("Channel 2 count: "); Serial2.println(count2); + Serial2.print("Channel 3 count: "); Serial2.println(count3); + Serial2.print("Channel 4 count: "); Serial2.println(count4); + break; + } +} + +// FIXME move this into the new wirish timer implementation +void setTimerPeriod(timer_dev *dev, uint32 period_us) { + if (!period_us) { + // FIXME handle this case + ASSERT(0); + return; } + uint32 cycles = period_us * CYCLES_PER_MICROSECOND; + uint16 pre = (uint16)((cycles >> 16) + 1); + timer_set_prescaler(dev, pre); + timer_set_reload(dev, cycles / pre - 1); } void handler1(void) { val1 += rate1; - Timers[t].setCompare1(val1); + timer_set_compare(timers[t], TIMER_CH1, val1); count1++; } void handler2(void) { val2 += rate2; - Timers[t].setCompare2(val2); + timer_set_compare(timers[t], TIMER_CH2, val2); count2++; } void handler3(void) { val3 += rate3; - Timers[t].setCompare3(val3); + timer_set_compare(timers[t], TIMER_CH3, val3); count3++; } void handler4(void) { val4 += rate4; - Timers[t].setCompare4(val4); + timer_set_compare(timers[t], TIMER_CH4, val4); count4++; } diff --git a/libmaple/bitband.h b/libmaple/bitband.h index 3e02702..870abe9 100644 --- a/libmaple/bitband.h +++ b/libmaple/bitband.h @@ -30,6 +30,9 @@ * @brief Bit-banding utility functions */ +#ifndef _BITBAND_H_ +#define _BITBAND_H_ + #define BB_SRAM_REF 0x20000000 #define BB_SRAM_BASE 0x22000000 #define BB_PERI_REF 0x40000000 @@ -103,3 +106,5 @@ static inline __io uint32* __bb_addr(__io void *address, uint32 bb_ref) { return (__io uint32*)(bb_base + ((uint32)address - bb_ref) * 32 + bit * 4); } + +#endif /* _BITBAND_H_ */ diff --git a/libmaple/delay.h b/libmaple/delay.h index 10839c9..e4d85c5 100644 --- a/libmaple/delay.h +++ b/libmaple/delay.h @@ -1,5 +1,5 @@ /** - * @brief + * @brief Delay implementation */ #ifndef _DELAY_H_ diff --git a/libmaple/nvic.h b/libmaple/nvic.h index fe9990f..cbcd49c 100644 --- a/libmaple/nvic.h +++ b/libmaple/nvic.h @@ -53,9 +53,6 @@ extern "C"{ /* System control registers */ #define SCB_VTOR 0xE000ED08 // Vector table offset register -#define NVIC_VectTab_RAM ((u32)0x20000000) -#define NVIC_VectTab_FLASH ((u32)0x08000000) - #define NVIC_BASE 0xE000E100 #define NVIC ((nvic_reg_map*)NVIC_BASE) @@ -75,52 +72,58 @@ typedef struct nvic_reg_map { __io uint32 STIR; // Software Trigger Interrupt Registers } nvic_reg_map; -enum { - NVIC_NMI = -14, - NVIC_MEM_MANAGE = -12, - NVIC_BUS_FAULT = -11, - NVIC_USAGE_FAULT = -10, - NVIC_SVC = -5, - NVIC_DEBUG_MON = -4, - NVIC_PEND_SVC = -2, - NVIC_SYSTICK = -1, - NVIC_TIMER1 = 27, - NVIC_TIMER2 = 28, - NVIC_TIMER3 = 29, - NVIC_TIMER4 = 30, - 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_UART4 = 52, // high density only - NVIC_UART5 = 53, // high density only - - NVIC_EXTI0 = 6, - NVIC_EXTI1 = 7, - NVIC_EXTI2 = 8, - NVIC_EXTI3 = 9, - 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, - - NVIC_I2C1_EV = 31, - NVIC_I2C1_ER = 32, - NVIC_I2C2_EV = 33, - NVIC_I2C2_ER = 34 -}; - +typedef enum nvic_irq_num { + NVIC_NMI = -14, + NVIC_MEM_MANAGE = -12, + NVIC_BUS_FAULT = -11, + NVIC_USAGE_FAULT = -10, + NVIC_SVC = -5, + NVIC_DEBUG_MON = -4, + NVIC_PEND_SVC = -2, + NVIC_SYSTICK = -1, + + NVIC_TIMER1_BRK = 24, + NVIC_TIMER1_UP = 25, + NVIC_TIMER1_TRG_COM = 26, + NVIC_TIMER1_CC = 27, + NVIC_TIMER2 = 28, + NVIC_TIMER3 = 29, + NVIC_TIMER4 = 30, + NVIC_TIMER5 = 50, + NVIC_TIMER6 = 54, + NVIC_TIMER7 = 55, + NVIC_TIMER8_BRK = 43, + NVIC_TIMER8_UP = 44, + NVIC_TIMER8_TRG_COM = 45, + NVIC_TIMER8_CC = 46, + + NVIC_USART1 = 37, + NVIC_USART2 = 38, + NVIC_USART3 = 39, + NVIC_UART4 = 52, + NVIC_UART5 = 53, + + NVIC_EXTI0 = 6, + NVIC_EXTI1 = 7, + NVIC_EXTI2 = 8, + NVIC_EXTI3 = 9, + 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, + + NVIC_I2C1_EV = 31, + NVIC_I2C1_ER = 32, + NVIC_I2C2_EV = 33, + NVIC_I2C2_ER = 34 +} nvic_irq_num; #define nvic_globalirq_enable() asm volatile("cpsie i") #define nvic_globalirq_disable() asm volatile("cpsid i") diff --git a/libmaple/rules.mk b/libmaple/rules.mk index 48b5ed4..a9d7e50 100644 --- a/libmaple/rules.mk +++ b/libmaple/rules.mk @@ -28,7 +28,7 @@ cSRCS_$(d) := adc.c \ spi.c \ syscalls.c \ systick.c \ - timers.c \ + timer.c \ usart.c \ util.c \ usb/descriptors.c \ diff --git a/libmaple/spi.h b/libmaple/spi.h index db8aa9c..5ebf52d 100644 --- a/libmaple/spi.h +++ b/libmaple/spi.h @@ -31,6 +31,9 @@ #ifndef _SPI_H_ #define _SPI_H_ +#include "libmaple_types.h" +#include "util.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/libmaple/timer.c b/libmaple/timer.c new file mode 100644 index 0000000..ad0ec6f --- /dev/null +++ b/libmaple/timer.c @@ -0,0 +1,449 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file timer.c + * @author Marti Bolivar + * @brief New-style timer interface + */ + +#include "timer.h" + +#if defined(STM32_MEDIUM_DENSITY) +#define NR_TIMERS 4 +#elif defined(STM32_HIGH_DENSITY) +#define NR_TIMERS 8 +#endif + +/* Just like the corresponding DIER bits: + * [0] = Update handler; + * [1,2,3,4] = capture/compare 1,2,3,4 handlers, respectively; + * [5] = COM; + * [6] = TRG; + * [7] = BRK. */ +#define NR_ADV_HANDLERS 8 +/* Update, capture/compare 1,2,3,4; ; trigger. */ +#define NR_GEN_HANDLERS 6 +/* Update only. */ +#define NR_BAS_HANDLERS 1 + +static timer_dev timer1 = { + .regs = {.adv = TIMER1_BASE}, + .clk_id = RCC_TIMER1, + .type = TIMER_ADVANCED, + .handlers = { [NR_ADV_HANDLERS - 1] = 0 }, +}; +timer_dev *TIMER1 = &timer1; + +static timer_dev timer2 = { + .regs = {.gen = TIMER2_BASE}, + .clk_id = RCC_TIMER2, + .type = TIMER_GENERAL, + .handlers = { [NR_GEN_HANDLERS - 1] = 0 }, +}; +timer_dev *TIMER2 = &timer2; + +static timer_dev timer3 = { + .regs = {.gen = TIMER3_BASE}, + .clk_id = RCC_TIMER3, + .type = TIMER_GENERAL, + .handlers = { [NR_GEN_HANDLERS - 1] = 0 }, +}; +timer_dev *TIMER3 = &timer3; + +static timer_dev timer4 = { + .regs = {.gen = TIMER4_BASE}, + .clk_id = RCC_TIMER4, + .type = TIMER_GENERAL, + .handlers = { [NR_GEN_HANDLERS - 1] = 0 }, +}; +timer_dev *TIMER4 = &timer4; + +#ifdef STM32_HIGH_DENSITY +static timer_dev timer5 = { + .regs = {.gen = TIMER5_BASE}, + .clk_id = RCC_TIMER5, + .type = TIMER_GENERAL, + .handlers = { [NR_GEN_HANDLERS - 1] = 0 }, +}; +timer_dev *TIMER5 = &timer5; + +static timer_dev timer6 = { + .regs = {.bas = TIMER6_BASE}, + .clk_id = RCC_TIMER6, + .type = TIMER_BASIC, + .handlers = { [NR_BAS_HANDLERS - 1] = 0 }, +}; +timer_dev *TIMER6 = &timer6; + +static timer_dev timer7 = { + .regs = {.bas = TIMER7_BASE}, + .clk_id = RCC_TIMER7, + .type = TIMER_BASIC, + .handlers = { [NR_BAS_HANDLERS - 1] = 0 }, +}; +timer_dev *TIMER7 = &timer7; + +static timer_dev timer8 = { + .regs = {.adv = TIMER8_BASE}, + .clk_id = RCC_TIMER8, + .type = TIMER_ADVANCED, + .handlers = { [NR_ADV_HANDLERS - 1] = 0 }, +}; +timer_dev *TIMER8 = &timer8; +#endif + +/* + * Convenience routines + */ + +static void disable_channel(timer_dev *dev, uint8 channel); +static void pwm_mode(timer_dev *dev, uint8 channel); +static void output_compare_mode(timer_dev *dev, uint8 channel); + +static inline void enable_irq(timer_dev *dev, uint8 interrupt); + +/** + * Initialize a timer, and reset its register map. + * @param dev Timer to initialize + */ +void timer_init(timer_dev *dev) { + rcc_clk_enable(dev->clk_id); + rcc_reset_dev(dev->clk_id); +} + +/** + * @brief Disable a timer. + * + * The timer will stop counting, all DMA requests and interrupts will + * be disabled, and no state changes will be output. + * + * @param dev Timer to disable. + */ +void timer_disable(timer_dev *dev) { + (dev->regs).bas->CR1 = 0; + (dev->regs).bas->DIER = 0; + switch (dev->type) { + case TIMER_ADVANCED: /* fall-through */ + case TIMER_GENERAL: + (dev->regs).gen->CCER = 0; + break; + case TIMER_BASIC: + break; + } +} + +/** + * Sets the mode of an individual timer channel. + * + * Note that not all timers can be configured in every mode. For + * example, basic timers cannot be configured to output compare mode. + * Be sure to use a timer which is appropriate for the mode you want. + * + * @param dev Timer whose channel mode to set + * @param channel Relevant channel + * @param mode New timer mode for channel + */ +void timer_set_mode(timer_dev *dev, uint8 channel, timer_mode mode) { + ASSERT(channel > 0 && channel <= 4); + + /* TODO decide about the basic timers */ + ASSERT(dev->type != TIMER_BASIC); + if (dev->type == TIMER_BASIC) + return; + + switch (mode) { + case TIMER_DISABLED: + disable_channel(dev, channel); + break; + case TIMER_PWM: + pwm_mode(dev, channel); + break; + case TIMER_OUTPUT_COMPARE: + output_compare_mode(dev, channel); + break; + } +} + +/** + * @brief Call a given function on all timers. + * @param fn Function to call on each timer. + */ +void timer_foreach(void (*fn)(timer_dev*)) { + fn(TIMER1); + fn(TIMER2); + fn(TIMER3); + fn(TIMER4); +#ifdef STM32_HIGH_DENSITY + fn(TIMER5); + fn(TIMER6); + fn(TIMER7); + fn(TIMER8); +#endif +} + +/** + * @brief Attach a timer interrupt. + * @param dev Timer device + * @param interrupt Interrupt number to attach to; this may be any + * timer_interrupt_id or timer_channel value appropriate + * for the timer. + * @param handler Handler to attach to the given interrupt. + * @see timer_interrupt_id + * @see timer_channel + */ +void timer_attach_interrupt(timer_dev *dev, + uint8 interrupt, + voidFuncPtr handler) { + dev->handlers[interrupt] = handler; + timer_enable_interrupt(dev, interrupt); + enable_irq(dev, interrupt); +} + +/** + * @brief Detach a timer interrupt. + * @param dev Timer device + * @param interrupt Interrupt number to detach; this may be any + * timer_interrupt_id or timer_channel value appropriate + * for the timer. + * @see timer_interrupt_id + * @see timer_channel + */ +void timer_detach_interrupt(timer_dev *dev, uint8 interrupt) { + timer_disable_interrupt(dev, interrupt); + dev->handlers[interrupt] = NULL; +} + +/* + * IRQ handlers + */ + +static inline void dispatch_adv_brk(timer_dev *dev); +static inline void dispatch_adv_up(timer_dev *dev); +static inline void dispatch_adv_trg_com(timer_dev *dev); +static inline void dispatch_adv_cc(timer_dev *dev); +static inline void dispatch_general(timer_dev *dev); +static inline void dispatch_basic(timer_dev *dev); + +void __irq_tim1_brk(void) { + dispatch_adv_brk(TIMER1); +} + +void __irq_tim1_up(void) { + dispatch_adv_up(TIMER1); +} + +void __irq_tim1_trg_com(void) { + dispatch_adv_trg_com(TIMER1); +} + +void __irq_tim1_cc(void) { + dispatch_adv_cc(TIMER1); +} + +void __irq_tim2(void) { + dispatch_general(TIMER2); +} + +void __irq_tim3(void) { + dispatch_general(TIMER3); +} + +void __irq_tim4(void) { + dispatch_general(TIMER4); +} + +#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) + +void __irq_tim5(void) { + dispatch_general(TIMER5); +} + +void __irq_tim6(void) { + dispatch_basic(TIMER6); +} + +void __irq_tim7(void) { + dispatch_basic(TIMER7); +} + +void __irq_tim8_brk(void) { + dispatch_adv_brk(TIMER8); +} + +void __irq_tim8_up(void) { + dispatch_adv_up(TIMER8); +} + +void __irq_tim8_trg_com(void) { + dispatch_adv_trg_com(TIMER8); +} + +void __irq_tim8_cc(void) { + dispatch_adv_cc(TIMER8); +} +#endif + +static inline void dispatch_irq(timer_dev *dev, uint8 iid, uint8 sr_bit); +static inline void dispatch_cc_irqs(timer_dev *dev); + +static inline void dispatch_adv_brk(timer_dev *dev) { + dispatch_irq(dev, TIMER_BREAK_INTERRUPT, TIMER_SR_BIF_BIT); +} + +static inline void dispatch_adv_up(timer_dev *dev) { + dispatch_irq(dev, TIMER_UPDATE_INTERRUPT, TIMER_SR_UIF_BIT); +} + +static inline void dispatch_adv_trg_com(timer_dev *dev) { + dispatch_irq(dev, TIMER_TRG_INTERRUPT, TIMER_SR_TIF_BIT); + dispatch_irq(dev, TIMER_COM_INTERRUPT, TIMER_SR_COMIF_BIT); +} + +static inline void dispatch_adv_cc(timer_dev *dev) { + dispatch_cc_irqs(dev); +} + +static inline void dispatch_general(timer_dev *dev) { + dispatch_irq(dev, TIMER_TRG_INTERRUPT, TIMER_SR_TIF_BIT); + dispatch_cc_irqs(dev); + dispatch_irq(dev, TIMER_UPDATE_INTERRUPT, TIMER_SR_UIF_BIT); +} + +static inline void dispatch_basic(timer_dev *dev) { + dispatch_irq(dev, TIMER_UPDATE_INTERRUPT, TIMER_SR_UIF_BIT); +} + +static inline void dispatch_irq(timer_dev *dev, uint8 iid, uint8 sr_bit) { + __io uint32 *sr = &(dev->regs).bas->SR; + if (bb_peri_get_bit(sr, sr_bit)) { + if (dev->handlers[iid]) + (dev->handlers[iid])(); + bb_peri_set_bit(sr, sr_bit, 0); + } +} + +static inline void dispatch_cc_irqs(timer_dev *dev) { + uint32 sr = (dev->regs).gen->SR; + uint32 sr_clear = 0; + uint32 b; + + ASSERT(sr & (TIMER_SR_CC1IF | TIMER_SR_CC2IF | + TIMER_SR_CC3IF | TIMER_SR_CC4IF)); + + for (b = TIMER_SR_CC1IF_BIT; b <= TIMER_SR_CC4IF_BIT; b++) { + uint32 mask = BIT(b); + if (sr & mask) { + if (dev->handlers[b]) + (dev->handlers[b])(); + sr_clear |= mask; + } + } + + (dev->regs).gen->SR &= ~sr_clear; +} + +/* + * Utilities + */ + +static void disable_channel(timer_dev *dev, uint8 channel) { + timer_detach_interrupt(dev, channel); + timer_cc_disable(dev, channel); +} + +static void pwm_mode(timer_dev *dev, uint8 channel) { + timer_disable_interrupt(dev, channel); + timer_oc_set_mode(dev, channel, TIMER_OC_MODE_PWM_1, TIMER_OC_PE); + timer_cc_enable(dev, channel); +} + +static void output_compare_mode(timer_dev *dev, uint8 channel) { + timer_oc_set_mode(dev, channel, TIMER_OC_MODE_ACTIVE_ON_MATCH, 0); + timer_cc_enable(dev, channel); +} + +static void enable_advanced_irq(timer_dev *dev, timer_interrupt_id id); +static void enable_nonmuxed_irq(timer_dev *dev); + +static inline void enable_irq(timer_dev *dev, timer_interrupt_id iid) { + if (dev->type == TIMER_ADVANCED) { + enable_advanced_irq(dev, iid); + } else { + enable_nonmuxed_irq(dev); + } +} + +static void enable_advanced_irq(timer_dev *dev, timer_interrupt_id id) { + uint8 is_timer1 = dev->clk_id == RCC_TIMER1; + + switch (id) { + case TIMER_UPDATE_INTERRUPT: + nvic_irq_enable(is_timer1 ? NVIC_TIMER1_UP : NVIC_TIMER8_UP); + break; + case TIMER_CC1_INTERRUPT: + case TIMER_CC2_INTERRUPT: + case TIMER_CC3_INTERRUPT: + case TIMER_CC4_INTERRUPT: + nvic_irq_enable(is_timer1 ? NVIC_TIMER1_CC : NVIC_TIMER8_CC); + break; + case TIMER_COM_INTERRUPT: + case TIMER_TRG_INTERRUPT: + nvic_irq_enable(is_timer1 ? NVIC_TIMER1_TRG_COM : NVIC_TIMER8_TRG_COM); + break; + case TIMER_BREAK_INTERRUPT: + nvic_irq_enable(is_timer1 ? NVIC_TIMER1_BRK : NVIC_TIMER8_BRK); + break; + } +} + +static void enable_nonmuxed_irq(timer_dev *dev) { + switch (dev->clk_id) { + case RCC_TIMER2: + nvic_irq_enable(NVIC_TIMER2); + break; + case RCC_TIMER3: + nvic_irq_enable(NVIC_TIMER3); + break; + case RCC_TIMER4: + nvic_irq_enable(NVIC_TIMER4); + break; +#ifdef STM32_HIGH_DENSITY + case RCC_TIMER5: + nvic_irq_enable(NVIC_TIMER5); + break; + case RCC_TIMER6: + nvic_irq_enable(NVIC_TIMER6); + break; + case RCC_TIMER7: + nvic_irq_enable(NVIC_TIMER7); + break; +#endif + default: + ASSERT(0); + break; + } +} diff --git a/libmaple/timer.h b/libmaple/timer.h new file mode 100644 index 0000000..025bcb0 --- /dev/null +++ b/libmaple/timer.h @@ -0,0 +1,1010 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file timer.h + * @author Marti Bolivar + * @brief New-style timer interface. + * + * Replaces old timers.h implementation. + */ + +#ifndef _TIMERS_H_ +#define _TIMERS_H_ + +#include "libmaple.h" +#include "rcc.h" +#include "nvic.h" +#include "bitband.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +/* + * Register maps and devices + */ + +/** Advanced control timer register map type */ +typedef struct timer_adv_reg_map { + __io uint32 CR1; /**< Control register 1 */ + __io uint32 CR2; /**< Control register 2 */ + __io uint32 SMCR; /**< Slave mode control register */ + __io uint32 DIER; /**< DMA/Interrupt enable register */ + __io uint32 SR; /**< Status register */ + __io uint32 EGR; /**< Event generation register */ + __io uint32 CCMR1; /**< Capture/compare mode register 1 */ + __io uint32 CCMR2; /**< Capture/compare mode register 2 */ + __io uint32 CCER; /**< Capture/compare enable register */ + __io uint32 CNT; /**< Counter */ + __io uint32 PSC; /**< Prescaler */ + __io uint32 ARR; /**< Auto-reload register */ + __io uint32 RCR; /**< Repetition counter register */ + __io uint32 CCR1; /**< Capture/compare register 1 */ + __io uint32 CCR2; /**< Capture/compare register 2 */ + __io uint32 CCR3; /**< Capture/compare register 3 */ + __io uint32 CCR4; /**< Capture/compare register 4 */ + __io uint32 BDTR; /**< Break and dead-time register */ + __io uint32 DCR; /**< DMA control register */ + __io uint32 DMAR; /**< DMA address for full transfer */ +} timer_adv_reg_map; + +/** General purpose timer register map type */ +typedef struct timer_gen_reg_map { + __io uint32 CR1; /**< Control register 1 */ + __io uint32 CR2; /**< Control register 2 */ + __io uint32 SMCR; /**< Slave mode control register */ + __io uint32 DIER; /**< DMA/Interrupt enable register */ + __io uint32 SR; /**< Status register */ + __io uint32 EGR; /**< Event generation register */ + __io uint32 CCMR1; /**< Capture/compare mode register 1 */ + __io uint32 CCMR2; /**< Capture/compare mode register 2 */ + __io uint32 CCER; /**< Capture/compare enable register */ + __io uint32 CNT; /**< Counter */ + __io uint32 PSC; /**< Prescaler */ + __io uint32 ARR; /**< Auto-reload register */ + const uint32 RESERVED1; /**< Reserved */ + __io uint32 CCR1; /**< Capture/compare register 1 */ + __io uint32 CCR2; /**< Capture/compare register 2 */ + __io uint32 CCR3; /**< Capture/compare register 3 */ + __io uint32 CCR4; /**< Capture/compare register 4 */ + const uint32 RESERVED2; /**< Reserved */ + __io uint32 DCR; /**< DMA control register */ + __io uint32 DMAR; /**< DMA address for full transfer */ +} timer_gen_reg_map; + +/** Basic timer register map type */ +typedef struct timer_bas_reg_map { + __io uint32 CR1; /**< Control register 1 */ + __io uint32 CR2; /**< Control register 2 */ + const uint32 RESERVED1; /**< Reserved */ + __io uint32 DIER; /**< DMA/Interrupt enable register */ + __io uint32 SR; /**< Status register */ + __io uint32 EGR; /**< Event generation register */ + const uint32 RESERVED2; /**< Reserved */ + const uint32 RESERVED3; /**< Reserved */ + const uint32 RESERVED4; /**< Reserved */ + __io uint32 CNT; /**< Counter */ + __io uint32 PSC; /**< Prescaler */ + __io uint32 ARR; /**< Auto-reload register */ +} timer_bas_reg_map; + +/** Timer 1 register map base pointer */ +#define TIMER1_BASE ((struct timer_adv_reg_map*)0x40012C00) +/** Timer 2 register map base pointer */ +#define TIMER2_BASE ((struct timer_gen_reg_map*)0x40000000) +/** Timer 3 register map base pointer */ +#define TIMER3_BASE ((struct timer_gen_reg_map*)0x40000400) +/** Timer 4 register map base pointer */ +#define TIMER4_BASE ((struct timer_gen_reg_map*)0x40000800) +#ifdef STM32_HIGH_DENSITY +/** Timer 5 register map base pointer */ +#define TIMER5_BASE ((struct timer_gen_reg_map*)0x40000C00) +/** Timer 6 register map base pointer */ +#define TIMER6_BASE ((struct timer_bas_reg_map*)0x40001000) +/** Timer 7 register map base pointer */ +#define TIMER7_BASE ((struct timer_bas_reg_map*)0x40001400) +/** Timer 8 register map base pointer */ +#define TIMER8_BASE ((struct timer_adv_reg_map*)0x40013400) +#endif + +/* + * Timer devices + */ + +typedef union { + timer_adv_reg_map *adv; + timer_gen_reg_map *gen; + timer_bas_reg_map *bas; +} timer_reg_map_union; + +typedef enum { + TIMER_ADVANCED, + TIMER_GENERAL, + TIMER_BASIC +} timer_type; + +/** Timer device type */ +typedef struct timer_dev { + timer_reg_map_union regs; + rcc_clk_id clk_id; + timer_type type; + voidFuncPtr handlers[]; +} timer_dev; + +/** Timer 1 device (advanced) */ +extern timer_dev *TIMER1; +/** Timer 2 device (general-purpose) */ +extern timer_dev *TIMER2; +/** Timer 3 device (general-purpose) */ +extern timer_dev *TIMER3; +/** Timer 4 device (general-purpose) */ +extern timer_dev *TIMER4; +#ifdef STM32_HIGH_DENSITY +/** Timer 5 device (general-purpose) */ +extern timer_dev *TIMER5; +/** Timer 6 device (basic) */ +extern timer_dev *TIMER6; +/** Timer 7 device (basic) */ +extern timer_dev *TIMER7; +/** Timer 8 device (basic) */ +extern timer_dev *TIMER8; +#endif + +/* + * Register bit definitions + */ + +/* Control register 1 (CR1) */ + +#define TIMER_CR1_ARPE_BIT 7 +#define TIMER_CR1_DIR_BIT 4 +#define TIMER_CR1_OPM_BIT 3 +#define TIMER_CR1_URS_BIT 2 +#define TIMER_CR1_UDIS_BIT 1 +#define TIMER_CR1_CEN_BIT 0 + +#define TIMER_CR1_CKD (0x3 << 8) +#define TIMER_CR1_CKD_1TCKINT (0x0 << 8) +#define TIMER_CR1_CKD_2TCKINT (0x1 << 8) +#define TIMER_CR1_CKD_4TICKINT (0x2 << 8) +#define TIMER_CR1_ARPE BIT(TIMER_CR1_ARPE_BIT) +#define TIMER_CR1_CKD_CMS (0x3 << 5) +#define TIMER_CR1_CKD_CMS_EDGE (0x0 << 5) +#define TIMER_CR1_CKD_CMS_CENTER1 (0x1 << 5) +#define TIMER_CR1_CKD_CMS_CENTER2 (0x2 << 5) +#define TIMER_CR1_CKD_CMS_CENTER3 (0x3 << 5) +#define TIMER_CR1_DIR BIT(TIMER_CR1_DIR_BIT) +#define TIMER_CR1_OPM BIT(TIMER_CR1_OPM_BIT) +#define TIMER_CR1_URS BIT(TIMER_CR1_URS_BIT) +#define TIMER_CR1_UDIS BIT(TIMER_CR1_UDIS_BIT) +#define TIMER_CR1_CEN BIT(TIMER_CR1_CEN_BIT) + +/* Control register 2 (CR2) */ + +#define TIMER_CR2_OIS4_BIT 14 +#define TIMER_CR2_OIS3N_BIT 13 +#define TIMER_CR2_OIS3_BIT 12 +#define TIMER_CR2_OIS2N_BIT 11 +#define TIMER_CR2_OIS2_BIT 10 +#define TIMER_CR2_OIS1N_BIT 9 +#define TIMER_CR2_OIS1_BIT 8 +#define TIMER_CR2_TI1S_BIT 7 /* tills? yikes */ +#define TIMER_CR2_CCDS_BIT 3 +#define TIMER_CR2_CCUS_BIT 2 +#define TIMER_CR2_CCPC_BIT 0 + +#define TIMER_CR2_OIS4 BIT(TIMER_CR2_OIS4_BIT) +#define TIMER_CR2_OIS3N BIT(TIMER_CR2_OIS3N_BIT) +#define TIMER_CR2_OIS3 BIT(TIMER_CR2_OIS3_BIT) +#define TIMER_CR2_OIS2N BIT(TIMER_CR2_OIS2N_BIT) +#define TIMER_CR2_OIS2 BIT(TIMER_CR2_OIS2_BIT) +#define TIMER_CR2_OIS1N BIT(TIMER_CR2_OIS1N_BIT) +#define TIMER_CR2_OIS1 BIT(TIMER_CR2_OIS1_BIT) +#define TIMER_CR2_TI1S BIT(TIMER_CR2_TI1S_BIT) +#define TIMER_CR2_MMS (0x7 << 4) +#define TIMER_CR2_MMS_RESET (0x0 << 4) +#define TIMER_CR2_MMS_ENABLE (0x1 << 4) +#define TIMER_CR2_MMS_UPDATE (0x2 << 4) +#define TIMER_CR2_MMS_COMPARE_PULSE (0x3 << 4) +#define TIMER_CR2_MMS_COMPARE_OC1REF (0x4 << 4) +#define TIMER_CR2_MMS_COMPARE_OC2REF (0x5 << 4) +#define TIMER_CR2_MMS_COMPARE_OC3REF (0x6 << 4) +#define TIMER_CR2_MMS_COMPARE_OC4REF (0x7 << 4) +#define TIMER_CR2_CCDS BIT(TIMER_CR2_CCDS_BIT) +#define TIMER_CR2_CCUS BIT(TIMER_CR2_CCUS_BIT) +#define TIMER_CR2_CCPC BIT(TIMER_CR2_CCPC_BIT) + +/* Slave mode control register (SMCR) */ + +#define TIMER_SMCR_ETP_BIT 15 +#define TIMER_SMCR_ECE_BIT 14 +#define TIMER_SMCR_MSM_BIT 7 + +#define TIMER_SMCR_ETP BIT(TIMER_SMCR_ETP_BIT) +#define TIMER_SMCR_ECE BIT(TIMER_SMCR_ECE_BIT) +#define TIMER_SMCR_ETPS (0x3 << 12) +#define TIMER_SMCR_ETPS_OFF (0x0 << 12) +#define TIMER_SMCR_ETPS_DIV2 (0x1 << 12) +#define TIMER_SMCR_ETPS_DIV4 (0x2 << 12) +#define TIMER_SMCR_ETPS_DIV8 (0x3 << 12) +#define TIMER_SMCR_ETF (0xF << 12) +#define TIMER_SMCR_MSM BIT(TIMER_SMCR_MSM_BIT) +#define TIMER_SMCR_TS (0x3 << 4) +#define TIMER_SMCR_TS_ITR0 (0x0 << 4) +#define TIMER_SMCR_TS_ITR1 (0x1 << 4) +#define TIMER_SMCR_TS_ITR2 (0x2 << 4) +#define TIMER_SMCR_TS_ITR3 (0x3 << 4) +#define TIMER_SMCR_TS_TI1F_ED (0x4 << 4) +#define TIMER_SMCR_TS_TI1FP1 (0x5 << 4) +#define TIMER_SMCR_TS_TI2FP2 (0x6 << 4) +#define TIMER_SMCR_TS_ETRF (0x7 << 4) +#define TIMER_SMCR_SMS 0x3 +#define TIMER_SMCR_SMS_DISABLED 0x0 +#define TIMER_SMCR_SMS_ENCODER1 0x1 +#define TIMER_SMCR_SMS_ENCODER2 0x2 +#define TIMER_SMCR_SMS_ENCODER3 0x3 +#define TIMER_SMCR_SMS_RESET 0x4 +#define TIMER_SMCR_SMS_GATED 0x5 +#define TIMER_SMCR_SMS_TRIGGER 0x6 +#define TIMER_SMCR_SMS_EXTERNAL 0x7 + +/* DMA/Interrupt enable register (DIER) */ + +#define TIMER_DIER_TDE_BIT 14 +#define TIMER_DIER_CC4DE_BIT 12 +#define TIMER_DIER_CC3DE_BIT 11 +#define TIMER_DIER_CC2DE_BIT 10 +#define TIMER_DIER_CC1DE_BIT 9 +#define TIMER_DIER_UDE_BIT 8 +#define TIMER_DIER_TIE_BIT 6 +#define TIMER_DIER_CC4IE_BIT 4 +#define TIMER_DIER_CC3IE_BIT 3 +#define TIMER_DIER_CC2IE_BIT 2 +#define TIMER_DIER_CC1IE_BIT 1 +#define TIMER_DIER_UIE_BIT 0 + +#define TIMER_DIER_TDE BIT(TIMER_DIER_TDE_BIT) +#define TIMER_DIER_CC4DE BIT(TIMER_DIER_CC4DE_BIT) +#define TIMER_DIER_CC3DE BIT(TIMER_DIER_CC3DE_BIT) +#define TIMER_DIER_CC2DE BIT(TIMER_DIER_CC2DE_BIT) +#define TIMER_DIER_CC1DE BIT(TIMER_DIER_CC1DE_BIT) +#define TIMER_DIER_UDE BIT(TIMER_DIER_UDE_BIT) +#define TIMER_DIER_TIE BIT(TIMER_DIER_TIE_BIT) +#define TIMER_DIER_CC4IE BIT(TIMER_DIER_CC4IE_BIT) +#define TIMER_DIER_CC3IE BIT(TIMER_DIER_CC3IE_BIT) +#define TIMER_DIER_CC2IE BIT(TIMER_DIER_CC2IE_BIT) +#define TIMER_DIER_CC1IE BIT(TIMER_DIER_CC1IE_BIT) +#define TIMER_DIER_UIE BIT(TIMER_DIER_UIE_BIT) + +/* Status register (SR) */ + +#define TIMER_SR_CC4OF_BIT 12 +#define TIMER_SR_CC3OF_BIT 11 +#define TIMER_SR_CC2OF_BIT 10 +#define TIMER_SR_CC1OF_BIT 9 +#define TIMER_SR_BIF_BIT 7 +#define TIMER_SR_TIF_BIT 6 +#define TIMER_SR_COMIF_BIT 5 +#define TIMER_SR_CC4IF_BIT 4 +#define TIMER_SR_CC3IF_BIT 3 +#define TIMER_SR_CC2IF_BIT 2 +#define TIMER_SR_CC1IF_BIT 1 +#define TIMER_SR_UIF_BIT 0 + +#define TIMER_SR_CC4OF BIT(TIMER_SR_CC4OF_BIT) +#define TIMER_SR_CC3OF BIT(TIMER_SR_CC3OF_BIT) +#define TIMER_SR_CC2OF BIT(TIMER_SR_CC2OF_BIT) +#define TIMER_SR_CC1OF BIT(TIMER_SR_CC1OF_BIT) +#define TIMER_SR_BIF BIT(TIMER_SR_BIF_BIT) +#define TIMER_SR_TIF BIT(TIMER_SR_TIF_BIT) +#define TIMER_SR_COMIF BIT(TIMER_SR_COMIF_BIT) +#define TIMER_SR_CC4IF BIT(TIMER_SR_CC4IF_BIT) +#define TIMER_SR_CC3IF BIT(TIMER_SR_CC3IF_BIT) +#define TIMER_SR_CC2IF BIT(TIMER_SR_CC2IF_BIT) +#define TIMER_SR_CC1IF BIT(TIMER_SR_CC1IF_BIT) +#define TIMER_SR_UIF BIT(TIMER_SR_UIF_BIT) + +/* Event generation register (EGR) */ + +#define TIMER_EGR_TG_BIT 6 +#define TIMER_EGR_CC4G_BIT 4 +#define TIMER_EGR_CC3G_BIT 3 +#define TIMER_EGR_CC2G_BIT 2 +#define TIMER_EGR_CC1G_BIT 1 +#define TIMER_EGR_UG_BIT 0 + +#define TIMER_EGR_TG BIT(TIMER_EGR_TG_BIT) +#define TIMER_EGR_CC4G BIT(TIMER_EGR_CC4G_BIT) +#define TIMER_EGR_CC3G BIT(TIMER_EGR_CC3G_BIT) +#define TIMER_EGR_CC2G BIT(TIMER_EGR_CC2G_BIT) +#define TIMER_EGR_CC1G BIT(TIMER_EGR_CC1G_BIT) +#define TIMER_EGR_UG BIT(TIMER_EGR_UG_BIT) + +/* Capture/compare mode registers, common values */ + +#define TIMER_CCMR_CCS_OUTPUT 0x0 +#define TIMER_CCMR_CCS_INPUT_TI1 0x1 +#define TIMER_CCMR_CCS_INPUT_TI2 0x2 +#define TIMER_CCMR_CCS_INPUT_TRC 0x3 + +/* Capture/compare mode register 1 (CCMR1) */ + +#define TIMER_CCMR1_OC2CE_BIT 15 +#define TIMER_CCMR1_OC2PE_BIT 11 +#define TIMER_CCMR1_OC2FE_BIT 10 +#define TIMER_CCMR1_OC1CE_BIT 7 +#define TIMER_CCMR1_OC1PE_BIT 3 +#define TIMER_CCMR1_OC1FE_BIT 2 + +#define TIMER_CCMR1_OC2CE BIT(TIMER_CCMR1_OC2CE_BIT) +#define TIMER_CCMR1_OC2M (0x3 << 12) +#define TIMER_CCMR1_IC2F (0xF << 12) +#define TIMER_CCMR1_OC2PE BIT(TIMER_CCMR1_OC2PE_BIT) +#define TIMER_CCMR1_OC2FE BIT(TIMER_CCMR1_OC2FE_BIT) +#define TIMER_CCMR1_IC2PSC (0x3 << 10) +#define TIMER_CCMR1_CC2S (0x3 << 8) +#define TIMER_CCMR1_CC2S_OUTPUT (TIMER_CCMR_CCS_OUTPUT << 8) +#define TIMER_CCMR1_CC2S_INPUT_TI1 (TIMER_CCMR_CCS_INPUT_TI1 << 8) +#define TIMER_CCMR1_CC2S_INPUT_TI2 (TIMER_CCMR_CCS_INPUT_TI2 << 8) +#define TIMER_CCMR1_CC2S_INPUT_TRC (TIMER_CCMR_CCS_INPUT_TRC << 8) +#define TIMER_CCMR1_OC1CE BIT(TIMER_CCMR1_OC1CE_BIT) +#define TIMER_CCMR1_OC1M (0x3 << 4) +#define TIMER_CCMR1_IC1F (0xF << 4) +#define TIMER_CCMR1_OC1PE BIT(TIMER_CCMR1_OC1PE_BIT) +#define TIMER_CCMR1_OC1FE BIT(TIMER_CCMR1_OC1FE_BIT) +#define TIMER_CCMR1_IC1PSC (0x3 << 2) +#define TIMER_CCMR1_CC1S 0x3 +#define TIMER_CCMR1_CC1S_OUTPUT TIMER_CCMR_CCS_OUTPUT +#define TIMER_CCMR1_CC1S_INPUT_TI1 TIMER_CCMR_CCS_INPUT_TI1 +#define TIMER_CCMR1_CC1S_INPUT_TI2 TIMER_CCMR_CCS_INPUT_TI2 +#define TIMER_CCMR1_CC1S_INPUT_TRC TIMER_CCMR_CCS_INPUT_TRC + +/* Capture/compare mode register 2 (CCMR2) */ + +#define TIMER_CCMR2_OC4CE_BIT 15 +#define TIMER_CCMR2_OC4PE_BIT 11 +#define TIMER_CCMR2_OC4FE_BIT 10 +#define TIMER_CCMR2_OC3CE_BIT 7 +#define TIMER_CCMR2_OC3PE_BIT 3 +#define TIMER_CCMR2_OC3FE_BIT 2 + +#define TIMER_CCMR2_OC4CE BIT(TIMER_CCMR2_OC4CE_BIT) +#define TIMER_CCMR2_OC4M (0x3 << 12) +#define TIMER_CCMR2_IC2F (0xF << 12) +#define TIMER_CCMR2_OC4PE BIT(TIMER_CCMR2_OC4PE_BIT) +#define TIMER_CCMR2_OC4FE BIT(TIMER_CCMR2_OC4FE_BIT) +#define TIMER_CCMR2_IC2PSC (0x3 << 10) +#define TIMER_CCMR2_CC4S (0x3 << 8) +#define TIMER_CCMR1_CC4S_OUTPUT (TIMER_CCMR_CCS_OUTPUT << 8) +#define TIMER_CCMR1_CC4S_INPUT_TI1 (TIMER_CCMR_CCS_INPUT_TI1 << 8) +#define TIMER_CCMR1_CC4S_INPUT_TI2 (TIMER_CCMR_CCS_INPUT_TI2 << 8) +#define TIMER_CCMR1_CC4S_INPUT_TRC (TIMER_CCMR_CCS_INPUT_TRC << 8) +#define TIMER_CCMR2_OC3CE BIT(TIMER_CCMR2_OC3CE_BIT) +#define TIMER_CCMR2_OC3M (0x3 << 4) +#define TIMER_CCMR2_IC1F (0xF << 4) +#define TIMER_CCMR2_OC3PE BIT(TIMER_CCMR2_OC3PE_BIT) +#define TIMER_CCMR2_OC3FE BIT(TIMER_CCMR2_OC3FE_BIT) +#define TIMER_CCMR2_IC1PSC (0x3 << 2) +#define TIMER_CCMR2_CC3S 0x3 +#define TIMER_CCMR1_CC3S_OUTPUT TIMER_CCMR_CCS_OUTPUT +#define TIMER_CCMR1_CC3S_INPUT_TI1 TIMER_CCMR_CCS_INPUT_TI1 +#define TIMER_CCMR1_CC3S_INPUT_TI2 TIMER_CCMR_CCS_INPUT_TI2 +#define TIMER_CCMR1_CC3S_INPUT_TRC TIMER_CCMR_CCS_INPUT_TRC + +/* Capture/compare enable register (CCER) */ + +#define TIMER_CCER_CC4P_BIT 13 +#define TIMER_CCER_CC4E_BIT 12 +#define TIMER_CCER_CC3P_BIT 9 +#define TIMER_CCER_CC3E_BIT 8 +#define TIMER_CCER_CC2P_BIT 5 +#define TIMER_CCER_CC2E_BIT 4 +#define TIMER_CCER_CC1P_BIT 1 +#define TIMER_CCER_CC1E_BIT 0 + +#define TIMER_CCER_CC4P BIT(TIMER_CCER_CC4P_BIT) +#define TIMER_CCER_CC4E BIT(TIMER_CCER_CC4E_BIT) +#define TIMER_CCER_CC3P BIT(TIMER_CCER_CC3P_BIT) +#define TIMER_CCER_CC3E BIT(TIMER_CCER_CC3E_BIT) +#define TIMER_CCER_CC2P BIT(TIMER_CCER_CC2P_BIT) +#define TIMER_CCER_CC2E BIT(TIMER_CCER_CC2E_BIT) +#define TIMER_CCER_CC1P BIT(TIMER_CCER_CC1P_BIT) +#define TIMER_CCER_CC1E BIT(TIMER_CCER_CC1E_BIT) + +/* Break and dead-time register (BDTR) */ + +#define TIMER_BDTR_MOE_BIT 15 +#define TIMER_BDTR_AOE_BIT 14 +#define TIMER_BDTR_BKP_BIT 13 +#define TIMER_BDTR_BKE_BIT 12 +#define TIMER_BDTR_OSSR_BIT 11 +#define TIMER_BDTR_OSSI_BIT 10 + +#define TIMER_BDTR_MOE BIT(TIMER_BDTR_MOE_BIT) +#define TIMER_BDTR_AOE BIT(TIMER_BDTR_AOE_BIT) +#define TIMER_BDTR_BKP BIT(TIMER_BDTR_BKP_BIT) +#define TIMER_BDTR_BKE BIT(TIMER_BDTR_BKE_BIT) +#define TIMER_BDTR_OSSR BIT(TIMER_BDTR_OSSR_BIT) +#define TIMER_BDTR_OSSI BIT(TIMER_BDTR_OSSI_BIT) +#define TIMER_BDTR_LOCK (0x3 << 8) +#define TIMER_BDTR_LOCK_OFF (0x0 << 8) +#define TIMER_BDTR_LOCK_LEVEL1 (0x1 << 8) +#define TIMER_BDTR_LOCK_LEVEL2 (0x2 << 8) +#define TIMER_BDTR_LOCK_LEVEL3 (0x3 << 8) +#define TIMER_BDTR_DTG 0xFF + +/* DMA control register (DCR) */ + +#define TIMER_DCR_DBL (0x1F << 8) +#define TIMER_DCR_DBL_1BYTE (0x0 << 8) +#define TIMER_DCR_DBL_2BYTE (0x1 << 8) +#define TIMER_DCR_DBL_3BYTE (0x2 << 8) +#define TIMER_DCR_DBL_4BYTE (0x3 << 8) +#define TIMER_DCR_DBL_5BYTE (0x4 << 8) +#define TIMER_DCR_DBL_6BYTE (0x5 << 8) +#define TIMER_DCR_DBL_7BYTE (0x6 << 8) +#define TIMER_DCR_DBL_8BYTE (0x7 << 8) +#define TIMER_DCR_DBL_9BYTE (0x8 << 8) +#define TIMER_DCR_DBL_10BYTE (0x9 << 8) +#define TIMER_DCR_DBL_11BYTE (0xA << 8) +#define TIMER_DCR_DBL_12BYTE (0xB << 8) +#define TIMER_DCR_DBL_13BYTE (0xC << 8) +#define TIMER_DCR_DBL_14BYTE (0xD << 8) +#define TIMER_DCR_DBL_15BYTE (0xE << 8) +#define TIMER_DCR_DBL_16BYTE (0xF << 8) +#define TIMER_DCR_DBL_17BYTE (0x10 << 8) +#define TIMER_DCR_DBL_18BYTE (0x11 << 8) +#define TIMER_DCR_DBA 0x1F +#define TIMER_DCR_DBA_CR1 0x0 +#define TIMER_DCR_DBA_CR2 0x1 +#define TIMER_DCR_DBA_SMCR 0x2 +#define TIMER_DCR_DBA_DIER 0x3 +#define TIMER_DCR_DBA_SR 0x4 +#define TIMER_DCR_DBA_EGR 0x5 +#define TIMER_DCR_DBA_CCMR1 0x6 +#define TIMER_DCR_DBA_CCMR2 0x7 +#define TIMER_DCR_DBA_CCER 0x8 +#define TIMER_DCR_DBA_CNT 0x9 +#define TIMER_DCR_DBA_PSC 0xA +#define TIMER_DCR_DBA_ARR 0xB +#define TIMER_DCR_DBA_RCR 0xC +#define TIMER_DCR_DBA_CCR1 0xD +#define TIMER_DCR_DBA_CCR2 0xE +#define TIMER_DCR_DBA_CCR3 0xF +#define TIMER_DCR_DBA_CCR4 0x10 +#define TIMER_DCR_DBA_BDTR 0x11 +#define TIMER_DCR_DBA_DCR 0x12 +#define TIMER_DCR_DBA_DMAR 0x13 + +/* + * Convenience routines + */ + +/** + * Used to configure the behavior of a timer channel. Note that not + * all timers can be configured in every mode. + */ +/* TODO TIMER_PWM_CENTER_ALIGNED, TIMER_INPUT_CAPTURE, TIMER_ONE_PULSE */ +typedef enum timer_mode { + TIMER_DISABLED, /**< In this mode, the timer stops counting, + channel interrupts are detached, and no state + changes are output. */ + TIMER_PWM, /**< PWM output mode. This is the default mode for pins + after initialization. */ + /* TIMER_PWM_CENTER_ALIGNED, /\**< Center-aligned PWM output mode. *\/ */ + TIMER_OUTPUT_COMPARE, /**< In this mode, the timer counts from 0 + to its reload value repeatedly; every + time the counter value reaches one of + the channel compare values, the + corresponding interrupt is fired. */ + /* TIMER_INPUT_CAPTURE, /\**< In this mode, the timer can measure the */ + /* pulse lengths of input signals. *\/ */ + /* TIMER_ONE_PULSE /\**< In this mode, the timer can generate a single */ + /* pulse on a GPIO pin for a specified amount of */ + /* time. *\/ */ +} timer_mode; + +/** Timer channel numbers */ +typedef enum timer_channel { + TIMER_CH1 = 1, /**< Channel 1 */ + TIMER_CH2 = 2, /**< Channel 2 */ + TIMER_CH3 = 3, /**< Channel 3 */ + TIMER_CH4 = 4 /**< Channel 4 */ +} timer_channel; + +/* + * Note: Don't require timer_channel arguments! We want to be able to say + * + * for (int channel = 1; channel <= 4; channel++) { + * ... + * } + * + * without the compiler yelling at us. + */ + +void timer_init(timer_dev *dev); +void timer_disable(timer_dev *dev); +void timer_set_mode(timer_dev *dev, uint8 channel, timer_mode mode); +void timer_foreach(void (*fn)(timer_dev*)); + +/** + * @brief Timer interrupt number. + * + * Not all timers support all of these values; see the descriptions + * for each value. + */ +typedef enum timer_interrupt_id { + TIMER_UPDATE_INTERRUPT, /**< Update interrupt, available on all timers. */ + TIMER_CC1_INTERRUPT, /**< Capture/compare 1 interrupt, available + on general and advanced timers only. */ + TIMER_CC2_INTERRUPT, /**< Capture/compare 2 interrupt, general and + advanced timers only. */ + TIMER_CC3_INTERRUPT, /**< Capture/compare 3 interrupt, general and + advanced timers only. */ + TIMER_CC4_INTERRUPT, /**< Capture/compare 4 interrupt, general and + advanced timers only. */ + TIMER_COM_INTERRUPT, /**< COM interrupt, advanced timers only */ + TIMER_TRG_INTERRUPT, /**< Trigger interrupt, general and advanced + timers only */ + TIMER_BREAK_INTERRUPT /**< Break interrupt, advanced timers only. */ +} timer_interrupt_id; + +void timer_attach_interrupt(timer_dev *dev, + uint8 interrupt, + voidFuncPtr handler); +void timer_detach_interrupt(timer_dev *dev, uint8 interrupt); + +/** + * Initialize all timer devices on the chip. + */ +static inline void timer_init_all(void) { + timer_foreach(timer_init); +} + +/** + * Disables all timers on the device. + */ +static inline void timer_disable_all(void) { + timer_foreach(timer_disable); +} + +/** + * @brief Stop a timer's counter from changing. + * + * Does not affect the timer's mode or other settings. + * + * @param dev Device whose counter to pause. + */ +static inline void timer_pause(timer_dev *dev) { + *bb_perip(&(dev->regs).bas->CR1, TIMER_CR1_CEN_BIT) = 0; +} + +/** + * @brief Start a timer's counter. + * + * Does not affect the timer's mode or other settings. + * + * @param dev Device whose counter to resume + */ +static inline void timer_resume(timer_dev *dev) { + *bb_perip(&(dev->regs).bas->CR1, TIMER_CR1_CEN_BIT) = 1; +} + +/** + * @brief Returns the timer's counter value. + * + * This value is likely to be inaccurate if the counter is running + * with a low prescaler. + * + * @param dev Timer whose counter to return + */ +static inline uint16 timer_get_count(timer_dev *dev) { + return (uint16)(dev->regs).bas->CNT; +} + +/** + * @brief Sets the counter value for the given timer. + * @param timer_num Timer whose counter to set + * @param value New counter value + */ +static inline void timer_set_count(timer_dev *dev, uint16 value) { + (dev->regs).bas->CNT = value; +} + +/** + * @brief Returns the given timer's prescaler. + * + * Note that if the timer's prescaler is set (e.g. via + * timer_set_prescaler() or accessing a TIMx_PSC register), the value + * returned by this function will reflect the new setting, but the + * timer's counter will only reflect the new prescaler at the next + * update event. + * + * @param dev Timer whose prescaler to return + * @see timer_generate_update() + */ +static inline uint16 timer_get_prescaler(timer_dev *dev) { + return (uint16)(dev->regs).bas->PSC; +} + +/** + * @brief Set a timer's prescale value. + * + * The new value will not take effect until the next update event. + * + * @param dev Timer whose prescaler to set + * @param psc New prescaler value + * @see timer_generate_update() + */ +static inline void timer_set_prescaler(timer_dev *dev, uint16 psc) { + (dev->regs).bas->PSC = psc; +} + +/** + * @brief Returns a timer's reload value. + * @param dev Timer whose reload value to return + */ +static inline uint16 timer_get_reload(timer_dev *dev) { + return (uint16)(dev->regs).bas->ARR; +} + +/** + * @brief Set a timer's reload value. + * @param dev Timer whose reload value to set + * @param arr New reload value to use. Takes effect at next update event. + * @see timer_generate_update() + */ +static inline void timer_set_reload(timer_dev *dev, uint16 arr) { + (dev->regs).bas->ARR = arr; +} + +/** + * @brief Get the compare value for the given timer channel. + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. + * @param channel Channel whose compare value to get. + */ +static inline uint16 timer_get_compare(timer_dev *dev, uint8 channel) { + __io uint32 *ccr = &(dev->regs).gen->CCR1 + (channel - 1); + return *ccr; +} + +/** + * @brief Set the compare value for the given timer channel. + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. + * @param channel Channel whose compare value to set. + * @param value New compare value. + */ +static inline void timer_set_compare(timer_dev *dev, + uint8 channel, + uint16 value) { + __io uint32 *ccr = &(dev->regs).gen->CCR1 + (channel - 1); + *ccr = value; +} + +/** + * @brief Generate an update event for the given timer. + * + * Normally, this will cause the prescaler and auto-reload values in + * the PSC and ARR registers to take immediate effect. However, this + * function will do nothing if the UDIS bit is set in the timer's CR1 + * register (UDIS is cleared by default). + * + * @param dev Timer device to generate an update for. + */ +static inline void timer_generate_update(timer_dev *dev) { + *bb_perip(&(dev->regs).bas->EGR, TIMER_EGR_UG_BIT) = 1; +} + +/** + * @brief Enable a timer's trigger DMA request + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL + */ +static inline void timer_trigger_dma_enable_request(timer_dev *dev) { + *bb_perip(&(dev->regs).gen->DIER, TIMER_DIER_TDE_BIT) = 1; +} + +/** + * @brief Disable a timer's trigger DMA request + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL + */ +static inline void timer_trigger_dma_disable_request(timer_dev *dev) { + *bb_perip(&(dev->regs).gen->DIER, TIMER_DIER_TDE_BIT) = 0; +} + +/** + * @brief Enable a timer channel's DMA request. + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL + * @param channel Channel whose DMA request to enable. + */ +static inline void timer_dma_enable_request(timer_dev *dev, uint8 channel) { + *bb_perip(&(dev->regs).gen->DIER, channel + 8) = 1; +} + +/** + * @brief Disable a timer channel's DMA request. + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. + * @param channel Channel whose DMA request to disable. + */ +static inline void timer_dma_disable_request(timer_dev *dev, uint8 channel) { + *bb_perip(&(dev->regs).gen->DIER, channel + 8) = 0; +} + +/** + * @brief Enable a timer interrupt. + * @param dev Timer device. + * @param interrupt Interrupt number to enable; this may be any + * timer_interrupt_id value appropriate for the timer. + * @see timer_interrupt_id + * @see timer_channel + */ +static inline void timer_enable_interrupt(timer_dev *dev, uint8 interrupt) { + *bb_perip(&(dev->regs).adv->DIER, interrupt) = 1; +} + +/** + * @brief Disable a timer interrupt. + * @param dev Timer device. + * @param interrupt Interrupt number to disable; this may be any + * timer_interrupt_id value appropriate for the timer. + * @see timer_interrupt_id + * @see timer_channel + */ +static inline void timer_disable_interrupt(timer_dev *dev, uint8 interrupt) { + *bb_perip(&(dev->regs).adv->DIER, interrupt) = 0; +} + +/** + * @brief Enable a timer channel's capture/compare signal. + * + * If the channel is configured as output, the corresponding output + * compare signal will be output on the corresponding output pin. If + * the channel is configured as input, enables capture of the counter + * value into the input capture/compare register. + * + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. + * @param channel Channel to enable, from 1 to 4. + */ +static inline void timer_cc_enable(timer_dev *dev, uint8 channel) { + *bb_perip(&(dev->regs).gen->CCER, 4 * (channel - 1)) = 1; +} + +/** + * @brief Disable a timer channel's output compare or input capture signal. + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. + * @param channel Channel to disable, from 1 to 4. + * @see timer_cc_enable() + */ +static inline void timer_cc_disable(timer_dev *dev, uint8 channel) { + *bb_perip(&(dev->regs).gen->CCER, 4 * (channel - 1)) = 0; +} + +/** + * @brief Get a channel's capture/compare output polarity + * @brief dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. + * @brief channel Channel whose capture/compare output polarity to get. + * @return Polarity, either 0 or 1. + * @see timer_cc_set_polarity() + */ +static inline uint8 timer_cc_get_polarity(timer_dev *dev, uint8 channel) { + return *bb_perip(&(dev->regs).gen->CCER, 4 * (channel - 1) + 1); +} + +/** + * @brief Set a timer channel's capture/compare output polarity. + * + * If the timer channel is configured as output: polarity == 0 means + * the output channel will be active high; polarity == 1 means active + * low. + * + * If the timer channel is configured as input: polarity == 0 means + * capture is done on the rising edge of ICn; when used as an external + * trigger, ICn is non-inverted. polarity == 1 means capture is done + * on the falling edge of ICn; when used as an external trigger, ICn + * is inverted. + * + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. + * @param channel Channel whose capture/compare output polarity to set. + * @param pol New polarity, 0 or 1. + */ +static inline void timer_cc_set_polarity(timer_dev *dev, + uint8 channel, + uint8 pol) { + *bb_perip(&(dev->regs).gen->CCER, 4 * (channel - 1) + 1) = pol; +} + +/** + * @brief Get a timer's DMA burst length. + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. + * @return Number of bytes to be transferred per DMA request, from 1 to 18. + */ +static inline uint8 timer_get_dma_burst_length(timer_dev *dev) { + uint32 dbl = ((dev->regs).gen->DCR & TIMER_DCR_DBL) >> 8; + return dbl + 1; /* 0 means 1 byte, etc. */ +} + +/** + * @brief Set a timer's DMA burst length. + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. + * @param length DMA burst length; i.e., number of bytes to transfer + * per DMA request, from 1 to 18. + */ +static inline void timer_set_dma_burst_length(timer_dev *dev, uint8 length) { + uint32 tmp = (dev->regs).gen->DCR; + tmp &= ~TIMER_DCR_DBL; + tmp |= (length << 8) - 1; + (dev->regs).gen->DCR = tmp; +} + +/** + * @brief Timer DMA base address. + * + * Defines the base address for DMA transfers. + */ +typedef enum timer_dma_base_address { + TIMER_DMA_BASE_CR1 = TIMER_DCR_DBA_CR1, /**< Base is control register 1 */ + TIMER_DMA_BASE_CR2 = TIMER_DCR_DBA_CR2, /**< Base is control register 2 */ + TIMER_DMA_BASE_SMCR = TIMER_DCR_DBA_SMCR, /**< Base is slave mode + control register */ + TIMER_DMA_BASE_DIER = TIMER_DCR_DBA_DIER, /**< Base is DMA interrupt enable + register */ + TIMER_DMA_BASE_SR = TIMER_DCR_DBA_SR, /**< Base is status register */ + TIMER_DMA_BASE_EGR = TIMER_DCR_DBA_EGR, /**< Base is event generation + register */ + TIMER_DMA_BASE_CCMR1 = TIMER_DCR_DBA_CCMR1, /**< Base is capture/compare + mode register 1 */ + TIMER_DMA_BASE_CCMR2 = TIMER_DCR_DBA_CCMR2, /**< Base is capture/compare + mode register 2 */ + TIMER_DMA_BASE_CCER = TIMER_DCR_DBA_CCER, /**< Base is capture/compare + enable register */ + TIMER_DMA_BASE_CNT = TIMER_DCR_DBA_CNT, /**< Base is counter */ + TIMER_DMA_BASE_PSC = TIMER_DCR_DBA_PSC, /**< Base is prescaler */ + TIMER_DMA_BASE_ARR = TIMER_DCR_DBA_ARR, /**< Base is auto-reload + register */ + TIMER_DMA_BASE_RCR = TIMER_DCR_DBA_RCR, /**< Base is repetition + counter register */ + TIMER_DMA_BASE_CCR1 = TIMER_DCR_DBA_CCR1, /**< Base is capture/compare + register 1 */ + TIMER_DMA_BASE_CCR2 = TIMER_DCR_DBA_CCR2, /**< Base is capture/compare + register 2 */ + TIMER_DMA_BASE_CCR3 = TIMER_DCR_DBA_CCR3, /**< Base is capture/compare + register 3 */ + TIMER_DMA_BASE_CCR4 = TIMER_DCR_DBA_CCR4, /**< Base is capture/compare + register 4 */ + TIMER_DMA_BASE_BDTR = TIMER_DCR_DBA_BDTR, /**< Base is break and + dead-time register */ + TIMER_DMA_BASE_DCR = TIMER_DCR_DBA_DCR, /**< Base is DMA control + register */ + TIMER_DMA_BASE_DMAR = TIMER_DCR_DBA_DMAR /**< Base is DMA address for + full transfer */ +} timer_dma_base_address; + +/** + * @brief Get the timer's DMA base address. + * + * Some restrictions apply; see ST RM0008. + * + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. + * @return DMA base address + */ +static inline timer_dma_base_address +timer_get_dma_base_address(timer_dev *dev) { + uint32 dcr = (dev->regs).gen->DCR; + return (timer_dma_base_address)(dcr & TIMER_DCR_DBA); +} + +/** + * @brief Set the timer's DMA base address. + * + * Some restrictions apply; see ST RM0008. + * + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. + * @param dma_base DMA base address. + */ +static inline void +timer_set_dma_base_address(timer_dev *dev, timer_dma_base_address dma_base) { + uint32 tmp = (dev->regs).gen->DCR; + tmp &= ~TIMER_DCR_DBA; + tmp |= dma_base; + (dev->regs).gen->DCR = tmp; +} + +/** + * Timer output compare modes. + */ +typedef enum timer_oc_mode { + TIMER_OC_MODE_FROZEN = 0 << 4, /**< Frozen: comparison between output + compare register and counter has no + effect on the outputs. */ + TIMER_OC_MODE_ACTIVE_ON_MATCH = 1 << 4, /**< OCxREF signal is forced + high when the count matches + the channel capture/compare + register. */ + TIMER_OC_MODE_INACTIVE_ON_MATCH = 2 << 4, /**< OCxREF signal is forced + low when the counter matches + the channel capture/compare + register. */ + TIMER_OC_MODE_TOGGLE = 3 << 4, /**< OCxREF toggles when counter + matches the cannel capture/compare + register. */ + TIMER_OC_MODE_FORCE_INACTIVE = 4 << 4, /**< OCxREF is forced low. */ + TIMER_OC_MODE_FORCE_ACTIVE = 5 << 4, /**< OCxREF is forced high. */ + TIMER_OC_MODE_PWM_1 = 6 << 4, /**< PWM mode 1. In upcounting, channel is + active as long as count is less than + channel capture/compare register, else + inactive. In downcounting, channel is + inactive as long as count exceeds + capture/compare register, else + active. */ + TIMER_OC_MODE_PWM_2 = 7 << 4 /**< PWM mode 2. In upcounting, channel is + inactive as long as count is less than + capture/compare register, else active. + In downcounting, channel is active as + long as count exceeds capture/compare + register, else inactive. */ +} timer_oc_mode; + +/** + * Timer output compare mode flags. + * @see timer_oc_set_mode() + */ +typedef enum timer_oc_mode_flags { + TIMER_OC_CE = BIT(7), /**< Output compare clear enable. */ + TIMER_OC_PE = BIT(3), /**< Output compare preload enable. */ + TIMER_OC_FE = BIT(2) /**< Output compare fast enable. */ +} timer_oc_mode_flags; + +/** + * @brief Configure a channel's output compare mode. + * + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. + * @param channel Channel to configure in output compare mode. + * @param flags OR of timer_oc_mode_flags. + * @see timer_oc_mode + * @see timer_oc_mode_flags + */ +static inline void timer_oc_set_mode(timer_dev *dev, + uint8 channel, + timer_oc_mode mode, + uint8 flags) { + uint8 bit0 = channel & 1; + uint8 bit1 = (channel >> 1) & 1; + /* channel == 1,2 -> CCMR1; channel == 3,4 -> CCMR2 */ + __io uint32 *ccmr = &(dev->regs).gen->CCMR1 + bit1; + /* channel == 1,3 -> shift = 0, channel == 2,4 -> shift = 8 */ + uint8 shift = 8 * (1 - bit0); + + uint32 tmp = *ccmr; + tmp &= ~(0xFF << shift); + tmp |= (mode | flags | TIMER_CCMR_CCS_OUTPUT) << shift; + *ccmr = tmp; +} + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/libmaple/timers.c b/libmaple/timers.c deleted file mode 100644 index c561d39..0000000 --- a/libmaple/timers.c +++ /dev/null @@ -1,526 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * 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. - *****************************************************************************/ - -/** - * @brief General timer routines - */ - -/* TODO: actually support timer5 and timer8 */ - -#include "libmaple.h" -#include "rcc.h" -#include "nvic.h" -#include "timers.h" - -/* Timer descriptor table */ -struct timer_dev timer_dev_table[] = { - [TIMER1] = { - .base = (timer_port*)TIMER1_BASE, - .rcc_dev_num = RCC_TIMER1, - .nvic_dev_num = NVIC_TIMER1 - }, - [TIMER2] = { - .base = (timer_port*)TIMER2_BASE, - .rcc_dev_num = RCC_TIMER2, - .nvic_dev_num = NVIC_TIMER2 - }, - [TIMER3] = { - .base = (timer_port*)TIMER3_BASE, - .rcc_dev_num = RCC_TIMER3, - .nvic_dev_num = NVIC_TIMER3 - }, - [TIMER4] = { - .base = (timer_port*)TIMER4_BASE, - .rcc_dev_num = RCC_TIMER4, - .nvic_dev_num = NVIC_TIMER4 - }, -#ifdef STM32_HIGH_DENSITY - /* High density devices only (eg, Maple Native) */ - [TIMER5] = { - .base = (timer_port*)TIMER5_BASE, - .rcc_dev_num = RCC_TIMER5, - .nvic_dev_num = NVIC_TIMER5 - }, - [TIMER8] = { - .base = (timer_port*)TIMER8_BASE, - .rcc_dev_num = RCC_TIMER8, - .nvic_dev_num = NVIC_TIMER8 - }, -#endif -}; - -/* This function should probably be rewriten to take (timer_num, mode) - * and have prescaler set elsewhere. The mode can be passed through to - * set_mode at the end */ -void timer_init(timer_dev_num timer_num, uint16 prescale) { - /* TODO: doesn't catch 6+7 */ - - timer_port *timer = timer_dev_table[timer_num].base; - uint8 is_advanced = 0; - - if (timer_num == TIMER1) { - is_advanced = 1; - } -#ifdef STM32_HIGH_DENSITY - if (timer_num == TIMER8) { - is_advanced = 1; - } -#endif - - rcc_clk_enable(timer_dev_table[timer_num].rcc_dev_num); - - timer->CR1 = ARPE; // No clock division - // Do not buffer auto-reload preload - // Edge aligned - // Upcounter - // Do not stop counter at update event - // Update events enabled (etc, see bits [1:2]) - // Counter disabled for now - - timer->PSC = prescale; // Prescaling by prescale (duh) - timer->ARR = 0xFFFF; // Max reload cont - - /* initialize all the channels to 50% duty cycle, - * TODO: none of them actually get output unless the gpio pin - * is set, this will probably consume a bit more power but - * we'll worry about that later. */ - timer->CCR1 = 0x8FFF; // PWM start value - timer->CCMR1 |= 0x68; // PWM mode 1, enable preload register. - - timer->CCR2 = 0x8FFF; // PWM start value - timer->CCMR1 |= (0x68 << 8);// PWM mode 1, enable preload register. - - timer->CCR3 = 0x8FFF; // PWM start value - timer->CCMR2 |= 0x68; // PWM mode 1, enable preload register. - - timer->CCR4 = 0x8FFF; // PWM start value - timer->CCMR2 |= (0x68 << 8);// PWM mode 1, enable preload register. - - /* Advanced timer? */ - if (is_advanced) { - timer->BDTR = 0x8000; // moe enable - } - - timer->SR = 0; // clear it - timer->DIER = 0; // disable update interrupt - timer->EGR = 1; // Initialize update event and shadow registers - timer->CR1 |= 1; // Enable timer -} - -/* Stops the counter; the mode and settings are not modified */ -void timer_pause(timer_dev_num timer_num) { - timer_port *timer = timer_dev_table[timer_num].base; - - timer->CR1 &= ~(0x0001); // CEN -} - -/* Starts the counter; the mode and settings are not modified */ -void timer_resume(timer_dev_num timer_num) { - timer_port *timer = timer_dev_table[timer_num].base; - - timer->CR1 |= 0x0001; // CEN -} - -/* Returns the current timer counter value. Probably very inaccurate - * if the counter is running with a low prescaler. */ -uint16 timer_get_count(timer_dev_num timer_num) { - timer_port *timer = timer_dev_table[timer_num].base; - - return timer->CNT; -} - -/* This function sets the counter value via register for the specified - * timer. Can't think of specific usecases except for resetting to - * zero but it's easy to implement and allows for "creative" - * programming */ -void timer_set_count(timer_dev_num timer_num, uint16 value) { - timer_port *timer = timer_dev_table[timer_num].base; - - timer->CNT = value; -} - -/* Get the prescaler buffer value (remember, the actual prescaler - * doesn't get set until an update event). */ -uint16 timer_get_prescaler(timer_dev_num timer_num) { - timer_port *timer = timer_dev_table[timer_num].base; - return timer->PSC; -} - -/* Sets the prescaler */ -void timer_set_prescaler(timer_dev_num timer_num, uint16 prescale) { - timer_port *timer = timer_dev_table[timer_num].base; - - timer->PSC = prescale; -} - -/* Get the reload value for the entire timer. */ -uint16 timer_get_reload(timer_dev_num timer_num) { - timer_port *timer = timer_dev_table[timer_num].base; - return timer->ARR; -} - -/* This sets the "reload" or "overflow" value for the entire timer. We - * should probably settle on either "reload" or "overflow" to prevent - * confusion? */ -void timer_set_reload(timer_dev_num timer_num, uint16 max_reload) { - timer_port *timer = timer_dev_table[timer_num].base; - - timer->ARR = max_reload; -} - -/* This quickly disables all 4 timers, presumably as part of a system shutdown - * or similar to prevent interrupts and PWM output without 16 seperate function - * calls to timer_set_mode */ -void timer_disable_all(void) { - timer_port *timer; -#ifdef STM32_HIGH_DENSITY - timer_port *timers[6] = { (timer_port*)TIMER1_BASE, - (timer_port*)TIMER2_BASE, - (timer_port*)TIMER3_BASE, - (timer_port*)TIMER4_BASE, - (timer_port*)TIMER5_BASE, - (timer_port*)TIMER8_BASE, - }; - uint8 i; - for (i = 0; i < 6; i++) { - timer = timers[i]; - timer->CR1 = 0; - timer->CCER = 0; - } -#else - timer_port *timers[4] = { (timer_port*)TIMER1_BASE, - (timer_port*)TIMER2_BASE, - (timer_port*)TIMER3_BASE, - (timer_port*)TIMER4_BASE, - }; - uint8 i; - for (i = 0; i < 4; i++) { - timer = timers[i]; - timer->CR1 = 0; - timer->CCER = 0; - } -#endif -} - -/* Sets the mode of individual timer channels, including a DISABLE mode */ -void timer_set_mode(timer_dev_num timer_num, uint8 channel, TimerMode mode) { - timer_port *timer = timer_dev_table[timer_num].base; - ASSERT(channel >= 1); - - switch(mode) { - case TIMER_DISABLED: - /* Disable the channel - * Disable any interrupt - * Clear interrupt SR? (TODO) */ - timer->DIER &= ~(1 << channel); // 1-indexed compare nums - timer_detach_interrupt(timer_num, channel); - timer->CCER &= ~(1 << (4*(channel - 1))); // 0-indexed - break; - case TIMER_PWM: - /* Set CCMR mode - * Keep existing reload value - * Disable any interrupt - * Clear interrupt SR? (TODO) - * Enable channel */ - timer->DIER &= ~(1 << channel); // 1-indexed compare nums - switch (channel) { - case 1: - timer->CCMR1 &= ~(0xFF); - timer->CCMR1 |= 0x68; // PWM mode 1, enable preload register. - break; - case 2: - timer->CCMR1 &= ~(0xFF00); - timer->CCMR1 |= (0x68 << 8);// PWM mode 1, enable preload register. - break; - case 3: - timer->CCMR2 &= ~(0xFF); - timer->CCMR2 |= 0x68; // PWM mode 1, enable preload register. - break; - case 4: - timer->CCMR2 &= ~(0xFF00); - timer->CCMR2 |= (0x68 << 8);// PWM mode 1, enable preload register. - break; - default: - ASSERT(0); - } - timer->CCER |= (1 << (4*(channel - 1))); // Enable - break; - case TIMER_OUTPUTCOMPARE: - /* Set CCMR mode - * Keep existing reload value - * Don't modify interrupt (needs to be attached to enable) - * Clear interrupt SR? (TODO) - * Enable channel */ - switch (channel) { - case 1: - timer->CCMR1 &= ~(0xFF); - timer->CCMR1 |= 0x0010; // PWM mode 1, enable preload register. - break; - case 2: - timer->CCMR1 &= ~(0xFF00); - timer->CCMR1 |= 0x1000; // PWM mode 1, enable preload register. - break; - case 3: - timer->CCMR2 &= ~(0xFF); - timer->CCMR2 |= 0x0010; // PWM mode 1, enable preload register. - break; - case 4: - timer->CCMR2 &= ~(0xFF00); - timer->CCMR2 |= 0x1000; // PWM mode 1, enable preload register. - break; - default: - ASSERT(0); - } - timer->CCER |= (1 << (4*(channel - 1))); // Enable - break; - default: - ASSERT(0); - } -} - -uint16 timer_get_compare_value(timer_dev_num timer_num, uint8 channel_num) { - /* faster: just read TIMERx_CHy_CCR (see timers.h) */ - ASSERT(channel_num > 0 && channel_num <= 4); - timer_port *timer = timer_dev_table[timer_num].base; - switch(channel_num) { - case 1: - return timer->CCR1; - case 2: - return timer->CCR2; - case 3: - return timer->CCR3; - case 4: - return timer->CCR4; - default: /* in case ASSERT is disabled */ - return 0; - } -} - -/* This sets the compare value (aka the trigger) for a given timer - * channel */ -void timer_set_compare_value(timer_dev_num timer_num, - uint8 channel_num, - uint16 value) { - ASSERT(channel_num > 0 && channel_num <= 4); - - /* The faster version of this function is the inline - timer_pwm_write_ccr */ - timer_port *timer = timer_dev_table[timer_num].base; - - switch(channel_num) { - case 1: - timer->CCR1 = value; - break; - case 2: - timer->CCR2 = value; - break; - case 3: - timer->CCR3 = value; - break; - case 4: - timer->CCR4 = value; - break; - } -} - -/* Stores a pointer to the passed usercode interrupt function and configures - * the actual ISR so that it will actually be called */ -void timer_attach_interrupt(timer_dev_num timer_num, - uint8 compare_num, - voidFuncPtr handler) { - ASSERT(compare_num > 0 && compare_num <= 4); - - timer_port *timer = timer_dev_table[timer_num].base; - - timer_dev_table[timer_num].handlers[compare_num-1] = handler; - timer->DIER |= (1 << compare_num); // 1-indexed compare nums - nvic_irq_enable(timer_dev_table[timer_num].nvic_dev_num); -} - -void timer_detach_interrupt(timer_dev_num timer_num, uint8 compare_num) { - ASSERT(compare_num > 0 && compare_num <= 4); - - timer_port *timer = timer_dev_table[timer_num].base; - - timer_dev_table[timer_num].handlers[compare_num-1] = 0; - timer->DIER &= ~(1 << compare_num); // 1-indexed compare nums -} - -void timer_generate_update(timer_dev_num timer_num) { - /* cause update event by setting UG bit in EGR. updates prescaler - ratio etc. */ - timer_port *timer = timer_dev_table[timer_num].base; - timer->EGR |= 0x1; -} - -/* The following are the actual interrupt handlers; 1 for each timer which must - * determine which actual compare value (aka channel) was triggered. - * - * These ISRs get called when the timer interrupt is enabled, the - * timer is running, and the timer count equals any of the CCR - * registers /or/ has overflowed. - * - * This is a rather long implementation... */ -void __irq_tim1_cc(void) { - timer_port *timer = (timer_port*)TIMER1_BASE; - uint16 sr_buffer; - sr_buffer = timer->SR; - - /* Simply switch/case-ing here doesn't work because multiple - * CC flags may be high. */ - if(sr_buffer & 0x10){ // CC4 flag - timer->SR &= ~(0x10); - if(timer_dev_table[TIMER1].handlers[3]) { - timer_dev_table[TIMER1].handlers[3](); - } - } - if(sr_buffer & 0x8){ // CC3 flag - timer->SR &= ~(0x8); - if(timer_dev_table[TIMER1].handlers[2]) { - timer_dev_table[TIMER1].handlers[2](); - } - } - if(sr_buffer & 0x4){ // CC2 flag - timer->SR &= ~(0x4); - if(timer_dev_table[TIMER1].handlers[1]) { - timer_dev_table[TIMER1].handlers[1](); - } - } - if(sr_buffer & 0x2){ // CC1 flag - timer->SR &= ~(0x2); - if(timer_dev_table[TIMER1].handlers[0]) { - timer_dev_table[TIMER1].handlers[0](); - } - } - if(sr_buffer & 0x1){ // Update flag - timer->SR &= ~(0x1); - //timer->EGR = 1; - } -} -void __irq_tim2(void) { - /* This is a rather long implementation... */ - timer_port *timer = (timer_port*)TIMER2_BASE; - uint16 sr_buffer; - sr_buffer = timer->SR; - - if(sr_buffer & 0x10){ // CC4 flag - timer->SR &= ~(0x10); - if(timer_dev_table[TIMER2].handlers[3]) { - timer_dev_table[TIMER2].handlers[3](); - } - } - if(sr_buffer & 0x8){ // CC3 flag - timer->SR &= ~(0x8); - if(timer_dev_table[TIMER2].handlers[2]) { - timer_dev_table[TIMER2].handlers[2](); - } - } - if(sr_buffer & 0x4){ // CC2 flag - timer->SR &= ~(0x4); - if(timer_dev_table[TIMER2].handlers[1]) { - timer_dev_table[TIMER2].handlers[1](); - } - } - if(sr_buffer & 0x2){ // CC1 flag - timer->SR &= ~(0x2); - if(timer_dev_table[TIMER2].handlers[0]) { - timer_dev_table[TIMER2].handlers[0](); - } - } - if(sr_buffer & 0x1){ // Update flag - timer->SR &= ~(0x1); - //timer->EGR = 1; - } -} -void __irq_tim3(void) { - /* This is a rather long implementation... */ - timer_port *timer = (timer_port*)TIMER3_BASE; - uint16 sr_buffer; - sr_buffer = timer->SR; - - if(sr_buffer & 0x10){ // CC4 flag - timer->SR &= ~(0x10); - if(timer_dev_table[TIMER3].handlers[3]) { - timer_dev_table[TIMER3].handlers[3](); - } - } - if(sr_buffer & 0x8){ // CC3 flag - timer->SR &= ~(0x8); - if(timer_dev_table[TIMER3].handlers[2]) { - timer_dev_table[TIMER3].handlers[2](); - } - } - if(sr_buffer & 0x4){ // CC2 flag - timer->SR &= ~(0x4); - if(timer_dev_table[TIMER3].handlers[1]) { - timer_dev_table[TIMER3].handlers[1](); - } - } - if(sr_buffer & 0x2){ // CC1 flag - timer->SR &= ~(0x2); - if(timer_dev_table[TIMER3].handlers[0]) { - timer_dev_table[TIMER3].handlers[0](); - } - } - if(sr_buffer & 0x1){ // Update flag - timer->SR &= ~(0x1); - //timer->EGR = 1; - } -} - -void __irq_tim4(void) { - /* This is a rather long implementation... */ - timer_port*timer = (timer_port*)TIMER4_BASE; - uint16 sr_buffer; - sr_buffer = timer->SR; - - if(sr_buffer & 0x10){ // CC4 flag - timer->SR &= ~(0x10); - if(timer_dev_table[TIMER4].handlers[3]) { - timer_dev_table[TIMER4].handlers[3](); - } - } - if(sr_buffer & 0x8){ // CC3 flag - timer->SR &= ~(0x8); - if(timer_dev_table[TIMER4].handlers[2]) { - timer_dev_table[TIMER4].handlers[2](); - } - } - if(sr_buffer & 0x4){ // CC2 flag - timer->SR &= ~(0x4); - if(timer_dev_table[TIMER4].handlers[1]) { - timer_dev_table[TIMER4].handlers[1](); - } - } - if(sr_buffer & 0x2){ // CC1 flag - timer->SR &= ~(0x2); - if(timer_dev_table[TIMER4].handlers[0]) { - timer_dev_table[TIMER4].handlers[0](); - } - } - if(sr_buffer & 0x1){ // Update flag - timer->SR &= ~(0x1); - //timer->EGR = 1; - } -} diff --git a/libmaple/timers.h b/libmaple/timers.h deleted file mode 100644 index 1f6afcd..0000000 --- a/libmaple/timers.h +++ /dev/null @@ -1,435 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * 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 timers.h - * - * @brief Timer prototypes and various definitions - */ - -/* Note to self: - * The timer clock frequencies are automatically fixed by hardware. - * There are two cases: - * 1. if the APB prescaler is 1, the timer clock frequencies are - * set to the same frequency as that of the APB domain to which - * the timers are connected. - * 2. otherwise, they are set to twice (x2) the frequency of the - * APB domain to which the timers are connected. - * See stm32 manual, 77/995 - * - * hence, 72 mhz timers - */ - -/* Maple Timer channels: - * Timer Maple Pin STM32 Pin Type - * TIM1_CH1 D6 PA8 Advanced - * TIM1_CH2 D7 PA9 Advanced - * TIM1_CH3 D8 PA10 Advanced - * - * TIM2_CH1 D2 PA0 - * TIM2_CH2 D3 PA1 - * TIM2_CH3 D1 PA2 - * TIM2_CH4 D0 PA3 - * - * TIM3_CH1 D12 PA6 - * TIM3_CH2 D11 PA7 - * TIM3_CH3 EXT7 PB0 - * TIM3_CH4 EXT8 PB1 - * - * TIM4_CH1 EXT5 PB6 - * TIM4_CH1 EXT9 PB7 - * TIM4_CH1 EXT15 PB8 - * TIM4_CH1 EXT4 PB9 - * - * Not supported: - * TIM1_CH4 USBDM, not available PA11 Advanced - * TIM1_CH1_N EXT12 PB13 - * TIM1_CH2_N EXT13 PB14 - * TIM1_CH3_N EXT14 PB15 - * */ - -/* I don't like the Arduino API for dealing with pin modes. - * How about... - * - * pinMode(digitalPin, PWM); - * pwmWrite(digitalPin) */ - -#ifndef _TIMERS_H_ -#define _TIMERS_H_ - -#ifdef __cplusplus -extern "C"{ -#endif - -typedef volatile uint16* TimerCCR; - -#define TIMER1_BASE 0x40012C00 -#define TIMER2_BASE 0x40000000 -#define TIMER3_BASE 0x40000400 -#define TIMER4_BASE 0x40000800 -#define TIMER5_BASE 0x40000C00 // High-density devices only -#define TIMER6_BASE 0x40001000 // High-density devices only -#define TIMER7_BASE 0x40001400 // High-density devices only -#define TIMER8_BASE 0x40013400 // High-density devices only - -#define ARPE BIT(7) // Auto-reload preload enable -#define NOT_A_TIMER 0 - -#define TIMER_CCR(NUM,CHAN) (TIMER ## NUM ## _CH ## CHAN ## _CRR) - -/* Timers 1-4 are present on the entire STM32 line. */ - -#define TIMER1_CH1_CCR ((TimerCCR)(TIMER1_BASE + 0x34)) -#define TIMER1_CH2_CCR ((TimerCCR)(TIMER1_BASE + 0x38)) -#define TIMER1_CH3_CCR ((TimerCCR)(TIMER1_BASE + 0x3C)) -#define TIMER1_CH4_CCR ((TimerCCR)(TIMER1_BASE + 0x40)) - -#define TIMER2_CH1_CCR ((TimerCCR)(TIMER2_BASE + 0x34)) -#define TIMER2_CH2_CCR ((TimerCCR)(TIMER2_BASE + 0x38)) -#define TIMER2_CH3_CCR ((TimerCCR)(TIMER2_BASE + 0x3C)) -#define TIMER2_CH4_CCR ((TimerCCR)(TIMER2_BASE + 0x40)) - -#define TIMER3_CH1_CCR ((TimerCCR)(TIMER3_BASE + 0x34)) -#define TIMER3_CH2_CCR ((TimerCCR)(TIMER3_BASE + 0x38)) -#define TIMER3_CH3_CCR ((TimerCCR)(TIMER3_BASE + 0x3C)) -#define TIMER3_CH4_CCR ((TimerCCR)(TIMER3_BASE + 0x40)) - -#define TIMER4_CH1_CCR ((TimerCCR)(TIMER4_BASE + 0x34)) -#define TIMER4_CH2_CCR ((TimerCCR)(TIMER4_BASE + 0x38)) -#define TIMER4_CH3_CCR ((TimerCCR)(TIMER4_BASE + 0x3C)) -#define TIMER4_CH4_CCR ((TimerCCR)(TIMER4_BASE + 0x40)) - -/* Timers 5 and 8 are in high-density devices only (such as Maple - Native). Timers 6 and 7 in these devices have no output compare - pins. */ - -#define TIMER5_CH1_CCR ((TimerCCR)(TIMER5_BASE + 0x34)) -#define TIMER5_CH2_CCR ((TimerCCR)(TIMER5_BASE + 0x38)) -#define TIMER5_CH3_CCR ((TimerCCR)(TIMER5_BASE + 0x3C)) -#define TIMER5_CH4_CCR ((TimerCCR)(TIMER5_BASE + 0x40)) - -#define TIMER8_CH1_CCR ((TimerCCR)(TIMER8_BASE + 0x34)) -#define TIMER8_CH2_CCR ((TimerCCR)(TIMER8_BASE + 0x38)) -#define TIMER8_CH3_CCR ((TimerCCR)(TIMER8_BASE + 0x3C)) -#define TIMER8_CH4_CCR ((TimerCCR)(TIMER8_BASE + 0x40)) - -/** - * Used to configure the behavior of a timer. - */ -typedef enum TimerMode { - TIMER_DISABLED, /**< In this mode, the timer stops counting, - interrupts are not called, and no state changes - are output. */ - TIMER_PWM, /**< This is the default mode for pins after - initialization. */ - TIMER_OUTPUTCOMPARE, /**< In this mode, the timer counts from 0 to - its reload value repeatedly; every time - the counter value reaches one of the - channel compare values, the corresponding - interrupt is fired. */ -} TimerMode; - -typedef struct { - /* Fields up to ARR common to general purpose (2,3,4,5), advanced - control (1,8) and basic (6, 7) timers: */ - volatile uint16 CR1; - uint16 RESERVED0; - volatile uint16 CR2; - uint16 RESERVED1; - volatile uint16 SMCR; - uint16 RESERVED2; - volatile uint16 DIER; - uint16 RESERVED3; - volatile uint16 SR; - uint16 RESERVED4; - volatile uint16 EGR; - uint16 RESERVED5; - volatile uint16 CCMR1; - uint16 RESERVED6; - volatile uint16 CCMR2; - uint16 RESERVED7; - volatile uint16 CCER; - uint16 RESERVED8; - volatile uint16 CNT; - uint16 RESERVED9; - volatile uint16 PSC; - uint16 RESERVED10; - volatile uint16 ARR; - uint16 RESERVED11; - /* Basic timers have none of the following: */ - volatile uint16 RCR; /* Advanced control timers only */ - uint16 RESERVED12; /* Advanced control timers only */ - volatile uint16 CCR1; - uint16 RESERVED13; - volatile uint16 CCR2; - uint16 RESERVED14; - volatile uint16 CCR3; - uint16 RESERVED15; - volatile uint16 CCR4; - uint16 RESERVED16; - volatile uint16 BDTR; /* Advanced control timers only */ - uint16 RESERVED17; /* Advanced control timers only */ - volatile uint16 DCR; - uint16 RESERVED18; - volatile uint16 DMAR; - uint16 RESERVED19; -} timer_port; - -/** - * Timer device numbers. See STM32 reference manual, chapters 13-15. - */ -/* several locations depend on TIMER1=0, etc.; don't change the - enumerator values to start at 1. */ -typedef enum { - TIMER1, /*< Advanced control timer TIM1 */ - TIMER2, /*< General purpose timer TIM2 */ - TIMER3, /*< General purpose timer TIM3 */ - TIMER4, /*< General purpose timer TIM4 */ -#ifdef STM32_HIGH_DENSITY - TIMER5, /*< General purpose timer TIM5; high density only */ - /* FIXME maple native: put timers 6 and 7 back in and make the - corresponding changes to timers.c */ - /* TIMER6, /\*< Basic timer TIM6; high density only *\/ */ - /* TIMER7, /\*< Basic timer TIM7; high density only *\/ */ - TIMER8, /*< Advanced control timer TIM8; high density only */ -#endif - TIMER_INVALID /* FIXME: this is starting to seem like a bad idea */ -} timer_dev_num; - -/* timer descriptor */ -struct timer_dev { - timer_port *base; - const uint8 rcc_dev_num; - const uint8 nvic_dev_num; - volatile voidFuncPtr handlers[4]; -}; - -extern struct timer_dev timer_dev_table[]; - -/** - * Initializes timer with prescale as the clock divisor. - * - * @param timer_num Timer number. - * - * @param prescale value in the range 1--65535 to use as a prescaler - * for timer counter increment frequency. - * - * @see timer_dev_num - * @see timer_set_prescaler() - * @see timer_set_mode() - */ -void timer_init(timer_dev_num timer_num, uint16 prescale); - -/** - * Quickly disable all timers. Calling this function is faster than, - * e.g., calling timer_set_mode() for all available timers/channels. - */ -void timer_disable_all(void); - -/** - * Returns the timer's counter value. Due to function call overhead, - * this value is likely to be inaccurate if the counter is running - * with a low prescaler. - * - * @param timer_num the timer whose counter to return. - * - * @pre Timer has been initialized. - */ -uint16 timer_get_count(timer_dev_num timer_num); - -/** - * Sets the counter value for the given timer. - * - * @param timer_num the timer whose counter to set. - * - * @param value the new counter value. - * - * @pre Timer has been initialized. - */ -void timer_set_count(timer_dev_num timer_num, uint16 value); - -/** - * Stops the timer's counter from incrementing. Does not modify the - * timer's mode or settings. - * - * @param timer_num the timer to pause. - * - * @see timer_resume() - * - * @pre Timer has been initialized. - */ -void timer_pause(timer_dev_num timer_num); - -/** - * Starts the counter for the given timer. Does not modify the - * timer's mode or settings. The timer will begin counting on the - * first rising clock cycle after it has been re-enabled using this - * function. - * - * @param timer_num the timer to resume. - * - * @see timer_pause() - * - * @pre Timer has been initialized. - */ -void timer_resume(timer_dev_num timer_num); - -/** - * Returns the prescaler for the given timer. - * - * @param timer_num the timer whose prescaler to return. - * - * @see timer_set_prescaler() - * - * @pre Timer has been initialized. - */ -uint16 timer_get_prescaler(timer_dev_num timer_num); - -/** - * Sets the prescaler for the given timer. This value goes into the - * PSC register, so it's 0-based (i.e., a prescale of 0 counts 1 tick - * per clock cycle). This prescale does not take effect until the - * next update event. - * - * @param timer_num the timer whose prescaler to set. - * - * @param prescale the new prescaler. - * - * @pre Timer has been initialized. - */ -void timer_set_prescaler(timer_dev_num timer_num, uint16 prescale); - -/** - * Gets the reload value for the timer. - * - * @see timer_set_reload() - * - * @pre Timer has been initialized. - */ -uint16 timer_get_reload(timer_dev_num timer_num); - -/** - * Sets the reload value for the timer. - * - * After this function returns, the timer's counter will reset to 0 - * after it has reached the value max_reload. - * - * @pre Timer has been initialized. - */ -void timer_set_reload(timer_dev_num timer_num, uint16 max_reload); - -/* TODO: timer_get_mode */ - -/** - * Set the mode of an individual timer channel. - * - * @see timer_disable_all() - * @see TimerMode - * @see timer_dev_num - * @pre Timer has been initialized. - */ -void timer_set_mode(timer_dev_num timer_num, uint8 channel, TimerMode mode); - -/** - * Get the compare value for the given timer channel. - * @see timer_set_compare_value() - * @see timer_dev_num - * @pre Timer has been initialized. - */ -uint16 timer_get_compare_value(timer_dev_num timer_num, uint8 channel); - -/** - * Sets the compare value for a given timer channel. Useful for - * scheduling when interrupt handlers will be called. - * - * @see timer_attach_interrupt() - * @see timer_detach_interrupt() - * @see timer_set_reload() - * @see timer_dev_num - * @pre Timer has been initialized. - */ -void timer_set_compare_value(timer_dev_num timer_num, uint8 channel, - uint16 value); - -/** - * Detach the interrupt handler for the given timer channel, if any. - * After this function returns, any handler attached to the given - * channel will no longer be called. - * - * @see timer_attach_interrupt() - * @pre Timer has been initialized. - * @see timer_dev_num - */ -void timer_detach_interrupt(timer_dev_num timer_num, uint8 channel); - -/** - * Attach an interrupt handler for the given timer and channel. The - * given ISR, handler, will be called whenever the timer's counter - * reaches the compare value for the given timer and channel. - * - * @see timer_set_compare_value() - * @see timer_detach_interrupt() - * @see timer_set_mode() - * @see timer_dev_num - * @see voidFuncPtr - * @pre Timer has been initialized. - * @pre The channel's mode must be set to TIMER_OUTPUTCOMPARE, or the - * interrupt handler will not get called. - */ -void timer_attach_interrupt(timer_dev_num timer_num, uint8 channel, - voidFuncPtr handler); - -/** - * Programmatically generate an update event on the given timer. This - * updates the prescaler, reloads the compare value (in upcounting - * mode, etc.). - * - * @pre Timer has been initialized. - */ -void timer_generate_update(timer_dev_num timer_num); - -/** - * Turn on PWM with duty_cycle. - * - * @param ccr TIMERx_CHn_CCR, where x ranges over timers, and n ranges - * from 1 to 4. - * - * @param duty_cycle: A number between 0 and - * timer_get_compare_value(TIMERx, y), where x and y are as above. - * - * @pre Pin has been set to alternate function output. - * - * @pre Timer has been initialized. - */ -static inline void timer_pwm_write_ccr(TimerCCR ccr, uint16 duty_cycle) { - *ccr = duty_cycle; -} - -#ifdef __cplusplus -} // extern "C" -#endif - - -#endif - diff --git a/libmaple/util.c b/libmaple/util.c index 09fbecd..6b4f216 100644 --- a/libmaple/util.c +++ b/libmaple/util.c @@ -32,7 +32,7 @@ #include "gpio.h" #include "nvic.h" #include "adc.h" -#include "timers.h" +#include "timer.h" /* Failed asserts send out a message on this USART. */ #ifndef ERROR_USART_NUM diff --git a/libraries/Servo/Servo.h b/libraries/Servo/Servo.h index 1c75618..583312e 100644 --- a/libraries/Servo/Servo.h +++ b/libraries/Servo/Servo.h @@ -28,6 +28,7 @@ #include #include "wirish.h" /* hack for IDE compile */ +#include "HardwareTimer.h" /* Note on Arduino compatibility: diff --git a/notes/portable.txt b/notes/portable.txt index 69952d7..cc1f2ac 100644 --- a/notes/portable.txt +++ b/notes/portable.txt @@ -1,98 +1,28 @@ +Board portability is implemented in boards.h, libmaple.h, and stm32.h. -Disclaimer text: // High-density devices only (Maple Native) +At compile time, we currently expect one of STM32_MEDIUM_DENSITY or +STM32_HIGH_DENSITY to be defined. There's no support for low-density +chips. XL-density isn't in the near horizon; patches welcome. You'll +also need to define some BOARD_foo if you expect to use Wirish; this +comes along with some additional assumptions about your board's layout. +The code in usb/ is not very portable at all right now; expect this to +change in the future, but for now, we're focusing on rolling out a +more complete backend. -Board portability is implemented by adding a header file to ./libmaple with the -name of the BOARD target, and then editing libmaple.h to add this file as an -option. - -A pin maple file should be added to ./notes describing the pin numbering - -Files to check by hand: -# adc.c -# adc.h -# exc.c -# exti.c -# exti.h -# flash.c -# flash.h -# gpio.c -# gpio.h -# libmaple_types.h -# nvic.c -# nvic.h -# rcc.c -# rcc.h -# ring_buffer.h -# rules.mk -# spi.c -- spi.h -# syscalls.c -# systick.c -# systick.h -# timers.c -# timers.h -# usart.c -# usart.h -# util.c -# util.h -# libmaple.h -# usb/* - -wirish/: -# bits.h -# boards.h -# cxxabi-compat.cpp -# ext_interrupts.c -# ext_interrupts.h -# HardwareTimer.cpp -# HardwareTimer.h -# io.h -# main.cxx -# Print.cpp -# Print.h -# pwm.c -# pwm.h -# rules.mk -# time.c -# time.h -# usb_serial.cpp -# usb_serial.h -# wirish_analog.c -# wirish.c -# wirish_digital.c -# wirish.h -# wirish_math.cpp -# wirish_math.h -# wirish_shift.c -# WProgram.h -- comm/ - - - -ADC Notes: - only using ADC1? - untested - -EXTI Notes: - need to update huge table in comments? - untested +A file should be added to ./notes describing the pin numbering of any +new board you add. NVIC Notes: - I don't think NVIC_ISER3 and NVIC_ICER3 actually exist? Only CANBUS and USB OTG use interrupts above #63, but I updated the nvic code anyways RCC Notes: Added some clock stuff to all boards even though they aren't usable... blah. SPI Notes: - SPI3 is only in XL chips so didn't really handle that + SPI3 is only in XL chips, so we don't handle that. TIMER Notes: - High-density devices add an advanced timer (TIMER8) and another normal one (TIMER5). - TIMER6 and TIMER7 are much less useful. - There is some partial progress towards adding timer5/timer8 functionality, - but not much. This should probably all be rewritten. The wirish timer implementation should be refactored to use pin numbers. USART Notes: diff --git a/notes/usb.txt b/notes/usb.txt index 5e00354..9552b9f 100644 --- a/notes/usb.txt +++ b/notes/usb.txt @@ -1,3 +1,7 @@ +XXX +XXX This file may be out of date! +XXX + [NOTE: this is a long term proposal. The current implementation just does a 2ms TIMEOUT] diff --git a/notes/vga.txt b/notes/vga.txt index d75281a..43b6830 100644 --- a/notes/vga.txt +++ b/notes/vga.txt @@ -7,8 +7,7 @@ gpio_write_bit() is about 360ns (2.78MHz) Writing to GPIO?_BASE is about 60ns (16.6MHz -> 18MHz) -pwm write 0x0001 is about 30ns (33MHz) with prescaler as 1 (default) -pwm write 0x0001 is about 14ns (72MHz) with prescaler as 0 (!) +PWM write 0x0001 is about 14ns (72MHz) with prescaler as 0 (!) VGA Timing ------------------------------------------------------------------------------ @@ -34,9 +33,3 @@ Crude 640x480 directions: 11 lines front porch 2 lines Vsync (low) 31 lines back porch - -Currently, setting vs. clearing GPIO registers seems to take a different amount -of time? Or perhaps i'm not analyzing branching correctly. Regardless, if you -SET 100x times then UNSET on one line, then UNSET 100x then SET the next line, -the two changes in color will generally not line up. - diff --git a/wirish/boards.cpp b/wirish/boards.cpp index 66f008f..d99b019 100644 --- a/wirish/boards.cpp +++ b/wirish/boards.cpp @@ -1,96 +1,56 @@ #include "boards.h" -// think of the poor column numbers +// For concision #define ADCx ADC_INVALID -#define TIMERx TIMER_INVALID #if defined(BOARD_maple) PinMapping PIN_MAP[NR_GPIO_PINS] = { - /* D0/PA3 */ - {GPIOA, 3, 3, TIMER2_CH4_CCR, TIMER2, 4, AFIO_EXTI_PA}, - /* D1/PA2 */ - {GPIOA, 2, 2, TIMER2_CH3_CCR, TIMER2, 3, AFIO_EXTI_PA}, - /* D2/PA0 */ - {GPIOA, 0, 0, TIMER2_CH1_CCR, TIMER2, 1, AFIO_EXTI_PA}, - /* D3/PA1 */ - {GPIOA, 1, 1, TIMER2_CH2_CCR, TIMER2, 2, AFIO_EXTI_PA}, - /* D4/PB5 */ - {GPIOB, 5, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, - /* D5/PB6 */ - {GPIOB, 6, ADCx, TIMER4_CH1_CCR, TIMER4, 1, AFIO_EXTI_PB}, - /* D6/PA8 */ - {GPIOA, 8, ADCx, TIMER1_CH1_CCR, TIMER1, 1, AFIO_EXTI_PA}, - /* D7/PA9 */ - {GPIOA, 9, ADCx, TIMER1_CH2_CCR, TIMER1, 2, AFIO_EXTI_PA}, - /* D8/PA10 */ - {GPIOA, 10, ADCx, TIMER1_CH3_CCR, TIMER1, 3, AFIO_EXTI_PA}, - /* D9/PB7 */ - {GPIOB, 7, ADCx, TIMER4_CH2_CCR, TIMER4, 2, AFIO_EXTI_PB}, - /* D10/PA4 */ - {GPIOA, 4, 4, 0, TIMERx, TIMERx, AFIO_EXTI_PA}, - /* D11/PA7 */ - {GPIOA, 7, 7, TIMER3_CH2_CCR, TIMER3, 2, AFIO_EXTI_PA}, - /* D12/PA6 */ - {GPIOA, 6, 6, TIMER3_CH1_CCR, TIMER3, 1, AFIO_EXTI_PA}, - /* D13/PA5 */ - {GPIOA, 5, 5, 0, TIMERx, TIMERx, AFIO_EXTI_PA}, - /* D14/PB8 */ - {GPIOB, 8, ADCx, TIMER4_CH3_CCR, TIMER4, 3, AFIO_EXTI_PB}, + {GPIOA, 3, 3, TIMER2, 4, AFIO_EXTI_PA}, /* D0/PA3 */ + {GPIOA, 2, 2, TIMER2, 3, AFIO_EXTI_PA}, /* D1/PA2 */ + {GPIOA, 0, 0, TIMER2, 1, AFIO_EXTI_PA}, /* D2/PA0 */ + {GPIOA, 1, 1, TIMER2, 2, AFIO_EXTI_PA}, /* D3/PA1 */ + {GPIOB, 5, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D4/PB5 */ + {GPIOB, 6, ADCx, TIMER4, 1, AFIO_EXTI_PB}, /* D5/PB6 */ + {GPIOA, 8, ADCx, TIMER1, 1, AFIO_EXTI_PA}, /* D6/PA8 */ + {GPIOA, 9, ADCx, TIMER1, 2, AFIO_EXTI_PA}, /* D7/PA9 */ + {GPIOA, 10, ADCx, TIMER1, 3, AFIO_EXTI_PA}, /* D8/PA10 */ + {GPIOB, 7, ADCx, TIMER4, 2, AFIO_EXTI_PB}, /* D9/PB7 */ + {GPIOA, 4, 4, NULL, 0, AFIO_EXTI_PA}, /* D10/PA4 */ + {GPIOA, 7, 7, TIMER3, 2, AFIO_EXTI_PA}, /* D11/PA7 */ + {GPIOA, 6, 6, TIMER3, 1, AFIO_EXTI_PA}, /* D12/PA6 */ + {GPIOA, 5, 5, NULL, 0, AFIO_EXTI_PA}, /* D13/PA5 (LED) */ + {GPIOB, 8, ADCx, TIMER4, 3, AFIO_EXTI_PB}, /* D14/PB8 */ /* Little header */ - /* D15/PC0 */ - {GPIOC, 0, 10, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D16/PC1 */ - {GPIOC, 1, 11, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D17/PC2 */ - {GPIOC, 2, 12, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D18/PC3 */ - {GPIOC, 3, 13, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D19/PC4 */ - {GPIOC, 4, 14, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D20/PC5 */ - {GPIOC, 5, 15, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + {GPIOC, 0, 10, NULL, 0, AFIO_EXTI_PC}, /* D15/PC0 */ + {GPIOC, 1, 11, NULL, 0, AFIO_EXTI_PC}, /* D16/PC1 */ + {GPIOC, 2, 12, NULL, 0, AFIO_EXTI_PC}, /* D17/PC2 */ + {GPIOC, 3, 13, NULL, 0, AFIO_EXTI_PC}, /* D18/PC3 */ + {GPIOC, 4, 14, NULL, 0, AFIO_EXTI_PC}, /* D19/PC4 */ + {GPIOC, 5, 15, NULL, 0, AFIO_EXTI_PC}, /* D20/PC5 */ /* External header */ - /* D21/PC13 */ - {GPIOC, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D22/PC14 */ - {GPIOC, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D23/PC15 */ - {GPIOC, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D24/PB9 */ - {GPIOB, 9, ADCx, TIMER4_CH4_CCR, TIMER4, 4, AFIO_EXTI_PB}, - /* D25/PD2 */ - {GPIOD, 2, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, - /* D26/PC10 */ - {GPIOC, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D27/PB0 */ - {GPIOB, 0, 8, TIMER3_CH3_CCR, TIMER3, 3, AFIO_EXTI_PB}, - /* D28/PB1 */ - {GPIOB, 1, 9, TIMER3_CH4_CCR, TIMER3, 4, AFIO_EXTI_PB}, - /* D29/PB10 */ - {GPIOB, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, - /* D30/PB11 */ - {GPIOB, 11, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, - /* D31/PB12 */ - {GPIOB, 12, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, - /* D32/PB13 */ - {GPIOB, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, - /* D33/PB14 */ - {GPIOB, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, - /* D34/PB15 */ - {GPIOB, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, - /* D35/PC6 */ - {GPIOC, 6, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D36/PC7 */ - {GPIOC, 7, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D37/PC8 */ - {GPIOC, 8, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D38/PC9 (BUT) */ - {GPIOC, 9, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC} + {GPIOC, 13, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D21/PC13 */ + {GPIOC, 14, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D22/PC14 */ + {GPIOC, 15, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D23/PC15 */ + {GPIOB, 9, ADCx, TIMER4, 4, AFIO_EXTI_PB}, /* D24/PB9 */ + {GPIOD, 2, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D25/PD2 */ + {GPIOC, 10, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D26/PC10 */ + {GPIOB, 0, 8, TIMER3, 3, AFIO_EXTI_PB}, /* D27/PB0 */ + {GPIOB, 1, 9, TIMER3, 4, AFIO_EXTI_PB}, /* D28/PB1 */ + {GPIOB, 10, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D29/PB10 */ + {GPIOB, 11, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D30/PB11 */ + {GPIOB, 12, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D31/PB12 */ + {GPIOB, 13, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D32/PB13 */ + {GPIOB, 14, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D33/PB14 */ + {GPIOB, 15, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D34/PB15 */ + {GPIOC, 6, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D35/PC6 */ + {GPIOC, 7, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D36/PC7 */ + {GPIOC, 8, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D37/PC8 */ + {GPIOC, 9, ADCx, NULL, 0, AFIO_EXTI_PC} /* D38/PC9 (BUT) */ }; #elif defined(BOARD_maple_native) @@ -98,375 +58,207 @@ PinMapping PIN_MAP[NR_GPIO_PINS] = { PinMapping PIN_MAP[NR_GPIO_PINS] = { /* Top header */ - /* D0/PB10 */ - {GPIOB, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, - /* D1/PB2 */ - {GPIOB, 2, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, - /* D2/PB12 */ - {GPIOB, 12, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, - /* D3/PB13 */ - {GPIOB, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, - /* D4/PB14 */ - {GPIOB, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, - /* D5/PB15 */ - {GPIOB, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, - /* D6/PC0 */ - {GPIOC, 0, 10, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D7/PC1 */ - {GPIOC, 1, 11, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D8/PC2 */ - {GPIOC, 2, 12, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D9/PC3 */ - {GPIOC, 3, 13, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D10/PC4 */ - {GPIOC, 4, 14, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D11/PC5 */ - {GPIOC, 5, 15, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D12/PC6 */ - {GPIOC, 6, ADCx, TIMER8_CH1_CCR, TIMER8, 1, AFIO_EXTI_PC}, - /* D13/PC7 */ - {GPIOC, 7, ADCx, TIMER8_CH2_CCR, TIMER8, 2, AFIO_EXTI_PC}, - /* D14/PC8 */ - {GPIOC, 8, ADCx, TIMER8_CH3_CCR, TIMER8, 3, AFIO_EXTI_PC}, - /* D15/PC9 */ - {GPIOC, 9, ADCx, TIMER8_CH4_CCR, TIMER8, 4, AFIO_EXTI_PC}, - /* D16/PC10 */ - {GPIOC, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D17/PC11 */ - {GPIOC, 11, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D18/PC12 */ - {GPIOC, 12, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D19/PC13 */ - {GPIOC, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D20/PC14 */ - {GPIOC, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D21/PC15 */ - {GPIOC, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D22/PA8 */ - {GPIOA, 8, ADCx, TIMER1_CH1_CCR, TIMER1, 1, AFIO_EXTI_PA}, - /* D23/PA9 */ - {GPIOA, 9, ADCx, TIMER1_CH2_CCR, TIMER1, 2, AFIO_EXTI_PA}, - /* D24/PA10 */ - {GPIOA, 10, ADCx, TIMER1_CH3_CCR, TIMER1, 3, AFIO_EXTI_PA}, - /* D25/PB9 */ - {GPIOB, 9, ADCx, TIMER4_CH4_CCR, TIMER4, 4, AFIO_EXTI_PB}, + {GPIOB, 10, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D0/PB10 */ + {GPIOB, 2, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D1/PB2 */ + {GPIOB, 12, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D2/PB12 */ + {GPIOB, 13, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D3/PB13 */ + {GPIOB, 14, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D4/PB14 */ + {GPIOB, 15, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D5/PB15 */ + {GPIOC, 0, 10, NULL, 0, AFIO_EXTI_PC}, /* D6/PC0 */ + {GPIOC, 1, 11, NULL, 0, AFIO_EXTI_PC}, /* D7/PC1 */ + {GPIOC, 2, 12, NULL, 0, AFIO_EXTI_PC}, /* D8/PC2 */ + {GPIOC, 3, 13, NULL, 0, AFIO_EXTI_PC}, /* D9/PC3 */ + {GPIOC, 4, 14, NULL, 0, AFIO_EXTI_PC}, /* D10/PC4 */ + {GPIOC, 5, 15, NULL, 0, AFIO_EXTI_PC}, /* D11/PC5 */ + {GPIOC, 6, ADCx, TIMER8, 1, AFIO_EXTI_PC}, /* D12/PC6 */ + {GPIOC, 7, ADCx, TIMER8, 2, AFIO_EXTI_PC}, /* D13/PC7 */ + {GPIOC, 8, ADCx, TIMER8, 3, AFIO_EXTI_PC}, /* D14/PC8 */ + {GPIOC, 9, ADCx, TIMER8, 4, AFIO_EXTI_PC}, /* D15/PC9 */ + {GPIOC, 10, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D16/PC10 */ + {GPIOC, 11, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D17/PC11 */ + {GPIOC, 12, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D18/PC12 */ + {GPIOC, 13, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D19/PC13 */ + {GPIOC, 14, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D20/PC14 */ + {GPIOC, 15, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D21/PC15 */ + {GPIOA, 8, ADCx, TIMER1, 1, AFIO_EXTI_PA}, /* D22/PA8 */ + {GPIOA, 9, ADCx, TIMER1, 2, AFIO_EXTI_PA}, /* D23/PA9 */ + {GPIOA, 10, ADCx, TIMER1, 3, AFIO_EXTI_PA}, /* D24/PA10 */ + {GPIOB, 9, ADCx, TIMER4, 4, AFIO_EXTI_PB}, /* D25/PB9 */ /* Bottom header */ + /* FIXME (?) What about D48--D50 also being TIMER2_CH[234]? */ - /* D26/PD2 */ - {GPIOD, 2, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, - /* D27/PD3 */ - {GPIOD, 3, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, - /* D28/PD6 */ - {GPIOD, 6, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, - /* D29/PG11 */ - {GPIOG, 11, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, - /* D30/PG12 */ - {GPIOG, 12, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, - /* D31/PG13 */ - {GPIOG, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, - /* D32/PG14 */ - {GPIOG, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, - /* D33/PG8 */ - {GPIOG, 8, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, - /* D34/PG7 */ - {GPIOG, 7, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, - /* D35/PG6 */ - {GPIOG, 6, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, - /* D36/PB5 */ - {GPIOB, 5, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, - /* D37/PB6 */ - {GPIOB, 6, ADCx, TIMER4_CH1_CCR, TIMER4, 1, AFIO_EXTI_PB}, - /* D38/PB7 */ - {GPIOB, 7, ADCx, TIMER4_CH2_CCR, TIMER4, 2, AFIO_EXTI_PB}, - /* D39/PF6 */ - {GPIOF, 6, 4, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, - /* D40/PF7 */ - {GPIOF, 7, 5, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, - /* D41/PF8 */ - {GPIOF, 8, 6, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, - /* D42/PF9 */ - {GPIOF, 9, 7, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, - /* D43/PF10 */ - {GPIOF, 10, 8, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, - /* D44/PF11 */ - {GPIOF, 11, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, - /* D45/PB1 */ - {GPIOB, 1, 9, TIMER3_CH4_CCR, TIMER3, 4, AFIO_EXTI_PB}, - /* D46/PB0 */ - {GPIOB, 0, 8, TIMER3_CH3_CCR, TIMER3, 3, AFIO_EXTI_PB}, - /* D47/PA0 */ - {GPIOA, 0, 0, TIMER5_CH1_CCR, TIMER5, 1, AFIO_EXTI_PA}, - /* D48/PA1 */ /* FIXME (?) - What about D48--D50 also being TIMER2_CH[234]? */ - {GPIOA, 1, 1, TIMER5_CH2_CCR, TIMER5, 2, AFIO_EXTI_PA}, - /* D49/PA2 */ - {GPIOA, 2, 2, TIMER5_CH3_CCR, TIMER5, 3, AFIO_EXTI_PA}, - /* D50/PA3 */ - {GPIOA, 3, 3, TIMER5_CH4_CCR, TIMER5, 4, AFIO_EXTI_PA}, - /* D51/PA4 */ - {GPIOA, 4, 4, 0, TIMERx, TIMERx, AFIO_EXTI_PA}, - /* D52/PA5 */ - {GPIOA, 5, 5, 0, TIMERx, TIMERx, AFIO_EXTI_PA}, - /* D53/PA6 */ - {GPIOA, 6, 6, TIMER3_CH1_CCR, TIMER3, 1, AFIO_EXTI_PA}, - /* D54/PA7 */ - {GPIOA, 7, 7, TIMER3_CH2_CCR, TIMER3, 2, AFIO_EXTI_PA}, + {GPIOD, 2, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D26/PD2 */ + {GPIOD, 3, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D27/PD3 */ + {GPIOD, 6, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D28/PD6 */ + {GPIOG, 11, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D29/PG11 */ + {GPIOG, 12, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D30/PG12 */ + {GPIOG, 13, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D31/PG13 */ + {GPIOG, 14, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D32/PG14 */ + {GPIOG, 8, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D33/PG8 */ + {GPIOG, 7, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D34/PG7 */ + {GPIOG, 6, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D35/PG6 */ + {GPIOB, 5, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D36/PB5 */ + {GPIOB, 6, ADCx, TIMER4, 1, AFIO_EXTI_PB}, /* D37/PB6 */ + {GPIOB, 7, ADCx, TIMER4, 2, AFIO_EXTI_PB}, /* D38/PB7 */ + {GPIOF, 6, 4, NULL, 0, AFIO_EXTI_PF}, /* D39/PF6 */ + {GPIOF, 7, 5, NULL, 0, AFIO_EXTI_PF}, /* D40/PF7 */ + {GPIOF, 8, 6, NULL, 0, AFIO_EXTI_PF}, /* D41/PF8 */ + {GPIOF, 9, 7, NULL, 0, AFIO_EXTI_PF}, /* D42/PF9 */ + {GPIOF, 10, 8, NULL, 0, AFIO_EXTI_PF}, /* D43/PF10 */ + {GPIOF, 11, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D44/PF11 */ + {GPIOB, 1, 9, TIMER3, 4, AFIO_EXTI_PB}, /* D45/PB1 */ + {GPIOB, 0, 8, TIMER3, 3, AFIO_EXTI_PB}, /* D46/PB0 */ + {GPIOA, 0, 0, TIMER5, 1, AFIO_EXTI_PA}, /* D47/PA0 */ + {GPIOA, 1, 1, TIMER5, 2, AFIO_EXTI_PA}, /* D48/PA1 */ + {GPIOA, 2, 2, TIMER5, 3, AFIO_EXTI_PA}, /* D49/PA2 */ + {GPIOA, 3, 3, TIMER5, 4, AFIO_EXTI_PA}, /* D50/PA3 */ + {GPIOA, 4, 4, NULL, 0, AFIO_EXTI_PA}, /* D51/PA4 */ + {GPIOA, 5, 5, NULL, 0, AFIO_EXTI_PA}, /* D52/PA5 */ + {GPIOA, 6, 6, TIMER3, 1, AFIO_EXTI_PA}, /* D53/PA6 */ + {GPIOA, 7, 7, TIMER3, 2, AFIO_EXTI_PA}, /* D54/PA7 */ /* Right (triple) header */ - /* D55/PF0 */ - {GPIOF, 0, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, - /* D56/PD11 */ - {GPIOD, 11, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, - /* D57/PD14 */ - {GPIOD, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, - /* D58/PF1 */ - {GPIOF, 1, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, - /* D59/PD12 */ - {GPIOD, 12, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, - /* D60/PD15 */ - {GPIOD, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, - /* D61/PF2 */ - {GPIOF, 2, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, - /* D62/PD13 */ - {GPIOD, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, - /* D63/PD0 */ - {GPIOD, 0, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, - /* D64/PF3 */ - {GPIOF, 3, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, - /* D65/PE3 */ - {GPIOE, 3, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE}, - /* D66/PD1 */ - {GPIOD, 1, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, - /* D67/PF4 */ - {GPIOF, 4, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, - /* D68/PE4 */ - {GPIOE, 4, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE}, - /* D69/PE7 */ - {GPIOE, 7, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE}, - /* D70/PF5 */ - {GPIOF, 5, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, - /* D71/PE5 */ - {GPIOE, 5, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE}, - /* D72/PE8 */ - {GPIOE, 8, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE}, - /* D73/PF12 */ - {GPIOF, 12, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, - /* D74/PE6 */ - {GPIOE, 6, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE}, - /* D75/PE9 */ - {GPIOE, 9, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE}, - /* D76/PF13 */ - {GPIOF, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, - /* D77/PE10 */ - {GPIOE, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE}, - /* D78/PF14 */ - {GPIOF, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, - /* D79/PG9 */ - {GPIOG, 9, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, - /* D80/PE11 */ - {GPIOE, 11, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE}, - /* D81/PF15 */ - {GPIOF, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PF}, - /* D82/PG10 */ - {GPIOG, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, - /* D83/PE12 */ - {GPIOE, 12, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE}, - /* D84/PG0 */ - {GPIOG, 0, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, - /* D85/PD5 */ - {GPIOD, 5, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, - /* D86/PE13 */ - {GPIOE, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE}, - /* D87/PG1 */ - {GPIOG, 1, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, - /* D88/PD4 */ - {GPIOD, 4, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, - /* D89/PE14 */ - {GPIOE, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE}, - /* D90/PG2 */ - {GPIOG, 2, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, - /* D91/PE1 */ - {GPIOE, 1, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE}, - /* D92/PE15 */ - {GPIOE, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE}, - /* D93/PG3 */ - {GPIOG, 3, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, - /* D94/PE0 */ - {GPIOE, 0, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PE}, - /* D95/PD8 */ - {GPIOD, 8, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, - /* D96/PG4 */ - {GPIOG, 4, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, - /* D97/PD9 */ - {GPIOD, 9, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, - /* D98/PG5 */ - {GPIOG, 5, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PG}, - /* D99/PD10 */ - {GPIOD, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD} + {GPIOF, 0, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D55/PF0 */ + {GPIOD, 11, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D56/PD11 */ + {GPIOD, 14, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D57/PD14 */ + {GPIOF, 1, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D58/PF1 */ + {GPIOD, 12, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D59/PD12 */ + {GPIOD, 15, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D60/PD15 */ + {GPIOF, 2, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D61/PF2 */ + {GPIOD, 13, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D62/PD13 */ + {GPIOD, 0, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D63/PD0 */ + {GPIOF, 3, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D64/PF3 */ + {GPIOE, 3, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D65/PE3 */ + {GPIOD, 1, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D66/PD1 */ + {GPIOF, 4, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D67/PF4 */ + {GPIOE, 4, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D68/PE4 */ + {GPIOE, 7, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D69/PE7 */ + {GPIOF, 5, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D70/PF5 */ + {GPIOE, 5, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D71/PE5 */ + {GPIOE, 8, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D72/PE8 */ + {GPIOF, 12, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D73/PF12 */ + {GPIOE, 6, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D74/PE6 */ + {GPIOE, 9, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D75/PE9 */ + {GPIOF, 13, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D76/PF13 */ + {GPIOE, 10, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D77/PE10 */ + {GPIOF, 14, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D78/PF14 */ + {GPIOG, 9, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D79/PG9 */ + {GPIOE, 11, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D80/PE11 */ + {GPIOF, 15, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D81/PF15 */ + {GPIOG, 10, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D82/PG10 */ + {GPIOE, 12, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D83/PE12 */ + {GPIOG, 0, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D84/PG0 */ + {GPIOD, 5, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D85/PD5 */ + {GPIOE, 13, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D86/PE13 */ + {GPIOG, 1, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D87/PG1 */ + {GPIOD, 4, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D88/PD4 */ + {GPIOE, 14, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D89/PE14 */ + {GPIOG, 2, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D90/PG2 */ + {GPIOE, 1, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D91/PE1 */ + {GPIOE, 15, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D92/PE15 */ + {GPIOG, 3, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D93/PG3 */ + {GPIOE, 0, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D94/PE0 */ + {GPIOD, 8, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D95/PD8 */ + {GPIOG, 4, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D96/PG4 */ + {GPIOD, 9, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D97/PD9 */ + {GPIOG, 5, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D98/PG5 */ + {GPIOD, 10, ADCx, NULL, 0, AFIO_EXTI_PD} /* D99/PD10 */ }; #elif defined(BOARD_maple_mini) PinMapping PIN_MAP[NR_GPIO_PINS] = { - /* D0/PB11 */ - {GPIOB, 11, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, - /* D1/PB10 */ - {GPIOB, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, - /* D2/PB2 */ - {GPIOB, 2, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, - /* D3/PB0 */ - {GPIOB, 0, 8, TIMER3_CH3_CCR, TIMER3, 3, AFIO_EXTI_PB}, - /* D4/PA7 */ - {GPIOA, 7, 7, TIMER3_CH2_CCR, TIMER3, 2, AFIO_EXTI_PA}, - /* D5/PA6 */ - {GPIOA, 6, 6, TIMER3_CH1_CCR, TIMER3, 1, AFIO_EXTI_PA}, - /* D6/PA5 */ - {GPIOA, 5, 5, 0, TIMERx, TIMERx, AFIO_EXTI_PA}, - /* D7/PA4 */ - {GPIOA, 4, 4, 0, TIMERx, TIMERx, AFIO_EXTI_PA}, - /* D8/PA3 */ - {GPIOA, 3, 3, TIMER2_CH4_CCR, TIMER2, 4, AFIO_EXTI_PA}, - /* D9/PA2 */ - {GPIOA, 2, 2, TIMER2_CH3_CCR, TIMER2, 3, AFIO_EXTI_PA}, - /* D10/PA1 */ - {GPIOA, 1, 1, TIMER2_CH2_CCR, TIMER2, 2, AFIO_EXTI_PA}, - /* D11/PA0 */ - {GPIOA, 0, 0, TIMER2_CH1_CCR, TIMER2, 1, AFIO_EXTI_PA}, - /* D12/PC15 */ - {GPIOC, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D13/PC14 */ - {GPIOC, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D14/PC13 */ - {GPIOC, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D15/PB7 */ - {GPIOB, 7, ADCx, TIMER4_CH2_CCR, TIMER4, 2, AFIO_EXTI_PB}, - /* D16/PB6 */ - {GPIOB, 6, ADCx, TIMER4_CH1_CCR, TIMER4, 1, AFIO_EXTI_PB}, - /* D17/PB5 */ - {GPIOB, 5, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, - /* D18/PB4 */ - {GPIOB, 4, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, - /* D19/PB3 */ - {GPIOB, 3, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, - /* D20/PA15 */ - {GPIOA, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PA}, - /* D21/PA14 */ - {GPIOA, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PA}, - /* D22/PA13 */ - {GPIOA, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PA}, - /* D23/PA12 */ - {GPIOA, 12, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PA}, - /* D24/PA11 */ - {GPIOA, 11, ADCx, TIMER1_CH4_CCR, TIMER1, 4, AFIO_EXTI_PA}, - /* D25/PA10 */ - {GPIOA, 10, ADCx, TIMER1_CH3_CCR, TIMER1, 3, AFIO_EXTI_PA}, - /* D26/PA9 */ - {GPIOA, 9, ADCx, TIMER1_CH2_CCR, TIMER2, 2, AFIO_EXTI_PA}, - /* D27/PA8 */ - {GPIOA, 8, ADCx, TIMER1_CH1_CCR, TIMER1, 1, AFIO_EXTI_PA}, - /* D28/PB15 */ - {GPIOB, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, - /* D29/PB14 */ - {GPIOB, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, - /* D30/PB13 */ - {GPIOB, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, - /* D31/PB12 */ - {GPIOB, 12, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, - /* D32/PB8 */ - {GPIOB, 8, ADCx, TIMER4_CH3_CCR, TIMER4, 3, AFIO_EXTI_PB}, - /* D33/PB1 */ - {GPIOB, 1, 9, TIMER3_CH4_CCR, TIMER3, 4, AFIO_EXTI_PB}, + /* Top header */ + + {GPIOB, 11, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D0/PB11 */ + {GPIOB, 10, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D1/PB10 */ + {GPIOB, 2, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D2/PB2 */ + {GPIOB, 0, 8, TIMER3, 3, AFIO_EXTI_PB}, /* D3/PB0 */ + {GPIOA, 7, 7, TIMER3, 2, AFIO_EXTI_PA}, /* D4/PA7 */ + {GPIOA, 6, 6, TIMER3, 1, AFIO_EXTI_PA}, /* D5/PA6 */ + {GPIOA, 5, 5, NULL, 0, AFIO_EXTI_PA}, /* D6/PA5 */ + {GPIOA, 4, 4, NULL, 0, AFIO_EXTI_PA}, /* D7/PA4 */ + {GPIOA, 3, 3, TIMER2, 4, AFIO_EXTI_PA}, /* D8/PA3 */ + {GPIOA, 2, 2, TIMER2, 3, AFIO_EXTI_PA}, /* D9/PA2 */ + {GPIOA, 1, 1, TIMER2, 2, AFIO_EXTI_PA}, /* D10/PA1 */ + {GPIOA, 0, 0, TIMER2, 1, AFIO_EXTI_PA}, /* D11/PA0 */ + {GPIOC, 15, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D12/PC15 */ + {GPIOC, 14, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D13/PC14 */ + {GPIOC, 13, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D14/PC13 */ + + /* Bottom header */ + + {GPIOB, 7, ADCx, TIMER4, 2, AFIO_EXTI_PB}, /* D15/PB7 */ + {GPIOB, 6, ADCx, TIMER4, 1, AFIO_EXTI_PB}, /* D16/PB6 */ + {GPIOB, 5, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D17/PB5 */ + {GPIOB, 4, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D18/PB4 */ + {GPIOB, 3, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D19/PB3 */ + {GPIOA, 15, ADCx, NULL, 0, AFIO_EXTI_PA}, /* D20/PA15 */ + {GPIOA, 14, ADCx, NULL, 0, AFIO_EXTI_PA}, /* D21/PA14 */ + {GPIOA, 13, ADCx, NULL, 0, AFIO_EXTI_PA}, /* D22/PA13 */ + {GPIOA, 12, ADCx, NULL, 0, AFIO_EXTI_PA}, /* D23/PA12 */ + {GPIOA, 11, ADCx, TIMER1, 4, AFIO_EXTI_PA}, /* D24/PA11 */ + {GPIOA, 10, ADCx, TIMER1, 3, AFIO_EXTI_PA}, /* D25/PA10 */ + {GPIOA, 9, ADCx, TIMER2, 2, AFIO_EXTI_PA}, /* D26/PA9 */ + {GPIOA, 8, ADCx, TIMER1, 1, AFIO_EXTI_PA}, /* D27/PA8 */ + {GPIOB, 15, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D28/PB15 */ + {GPIOB, 14, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D29/PB14 */ + {GPIOB, 13, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D30/PB13 */ + {GPIOB, 12, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D31/PB12 */ + {GPIOB, 8, ADCx, TIMER4, 3, AFIO_EXTI_PB}, /* D32/PB8 */ + {GPIOB, 1, 9, TIMER3, 4, AFIO_EXTI_PB}, /* D33/PB1 */ }; #elif defined(BOARD_maple_RET6) PinMapping PIN_MAP[NR_GPIO_PINS] = { - /* D0/PA3 */ - {GPIOA, 3, 3, TIMER2_CH4_CCR, TIMER2, 4, AFIO_EXTI_PA}, - /* D1/PA2 */ - {GPIOA, 2, 2, TIMER2_CH3_CCR, TIMER2, 3, AFIO_EXTI_PA}, - /* D2/PA0 */ - {GPIOA, 0, 0, TIMER2_CH1_CCR, TIMER2, 1, AFIO_EXTI_PA}, - /* D3/PA1 */ - {GPIOA, 1, 1, TIMER2_CH2_CCR, TIMER2, 2, AFIO_EXTI_PA}, - /* D4/PB5 */ - {GPIOB, 5, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, - /* D5/PB6 */ - {GPIOB, 6, ADCx, TIMER4_CH1_CCR, TIMER4, 1, AFIO_EXTI_PB}, - /* D6/PA8 */ - {GPIOA, 8, ADCx, TIMER1_CH1_CCR, TIMER1, 1, AFIO_EXTI_PA}, - /* D7/PA9 */ - {GPIOA, 9, ADCx, TIMER1_CH2_CCR, TIMER1, 2, AFIO_EXTI_PA}, - /* D8/PA10 */ - {GPIOA, 10, ADCx, TIMER1_CH3_CCR, TIMER1, 3, AFIO_EXTI_PA}, - /* D9/PB7 */ - {GPIOB, 7, ADCx, TIMER4_CH2_CCR, TIMER4, 2, AFIO_EXTI_PB}, - /* D10/PA4 */ - {GPIOA, 4, 4, 0, TIMERx, TIMERx, AFIO_EXTI_PA}, - /* D11/PA7 */ - {GPIOA, 7, 7, TIMER3_CH2_CCR, TIMER3, 2, AFIO_EXTI_PA}, - /* D12/PA6 */ - {GPIOA, 6, 6, TIMER3_CH1_CCR, TIMER3, 1, AFIO_EXTI_PA}, - /* D13/PA5 */ - {GPIOA, 5, 5, 0, TIMERx, TIMERx, AFIO_EXTI_PA}, - /* D14/PB8 */ - {GPIOB, 8, ADCx, TIMER4_CH3_CCR, TIMER4, 3, AFIO_EXTI_PB}, + {GPIOA, 3, 3, TIMER2, 4, AFIO_EXTI_PA}, /* D0/PA3 */ + {GPIOA, 2, 2, TIMER2, 3, AFIO_EXTI_PA}, /* D1/PA2 */ + {GPIOA, 0, 0, TIMER2, 1, AFIO_EXTI_PA}, /* D2/PA0 */ + {GPIOA, 1, 1, TIMER2, 2, AFIO_EXTI_PA}, /* D3/PA1 */ + {GPIOB, 5, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D4/PB5 */ + {GPIOB, 6, ADCx, TIMER4, 1, AFIO_EXTI_PB}, /* D5/PB6 */ + {GPIOA, 8, ADCx, TIMER1, 1, AFIO_EXTI_PA}, /* D6/PA8 */ + {GPIOA, 9, ADCx, TIMER1, 2, AFIO_EXTI_PA}, /* D7/PA9 */ + {GPIOA, 10, ADCx, TIMER1, 3, AFIO_EXTI_PA}, /* D8/PA10 */ + {GPIOB, 7, ADCx, TIMER4, 2, AFIO_EXTI_PB}, /* D9/PB7 */ + {GPIOA, 4, 4, NULL, 0, AFIO_EXTI_PA}, /* D10/PA4 */ + {GPIOA, 7, 7, TIMER3, 2, AFIO_EXTI_PA}, /* D11/PA7 */ + {GPIOA, 6, 6, TIMER3, 1, AFIO_EXTI_PA}, /* D12/PA6 */ + {GPIOA, 5, 5, NULL, 0, AFIO_EXTI_PA}, /* D13/PA5 (LED) */ + {GPIOB, 8, ADCx, TIMER4, 3, AFIO_EXTI_PB}, /* D14/PB8 */ /* Little header */ - /* D15/PC0 */ - {GPIOC, 0, 10, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D16/PC1 */ - {GPIOC, 1, 11, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D17/PC2 */ - {GPIOC, 2, 12, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D18/PC3 */ - {GPIOC, 3, 13, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D19/PC4 */ - {GPIOC, 4, 14, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D20/PC5 */ - {GPIOC, 5, 15, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, + {GPIOC, 0, 10, NULL, 0, AFIO_EXTI_PC}, /* D15/PC0 */ + {GPIOC, 1, 11, NULL, 0, AFIO_EXTI_PC}, /* D16/PC1 */ + {GPIOC, 2, 12, NULL, 0, AFIO_EXTI_PC}, /* D17/PC2 */ + {GPIOC, 3, 13, NULL, 0, AFIO_EXTI_PC}, /* D18/PC3 */ + {GPIOC, 4, 14, NULL, 0, AFIO_EXTI_PC}, /* D19/PC4 */ + {GPIOC, 5, 15, NULL, 0, AFIO_EXTI_PC}, /* D20/PC5 */ /* External header */ - /* D21/PC13 */ - {GPIOC, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D22/PC14 */ - {GPIOC, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D23/PC15 */ - {GPIOC, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D24/PB9 */ - {GPIOB, 9, ADCx, TIMER4_CH4_CCR, TIMER4, 4, AFIO_EXTI_PB}, - /* D25/PD2 */ - {GPIOD, 2, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PD}, - /* D26/PC10 */ - {GPIOC, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PC}, - /* D27/PB0 */ - {GPIOB, 0, 8, TIMER3_CH3_CCR, TIMER3, 3, AFIO_EXTI_PB}, - /* D28/PB1 */ - {GPIOB, 1, 9, TIMER3_CH4_CCR, TIMER3, 4, AFIO_EXTI_PB}, - /* D29/PB10 */ - {GPIOB, 10, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, - /* D30/PB11 */ - {GPIOB, 11, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, - /* D31/PB12 */ - {GPIOB, 12, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, - /* D32/PB13 */ - {GPIOB, 13, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, - /* D33/PB14 */ - {GPIOB, 14, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, - /* D34/PB15 */ - {GPIOB, 15, ADCx, 0, TIMERx, TIMERx, AFIO_EXTI_PB}, - /* D35/PC6 */ - {GPIOC, 6, ADCx, TIMER8_CH1_CCR, TIMER8, 1, AFIO_EXTI_PC}, - /* D36/PC7 */ - {GPIOC, 7, ADCx, TIMER8_CH1_CCR, TIMER8, 2, AFIO_EXTI_PC}, - /* D37/PC8 */ - {GPIOC, 8, ADCx, TIMER8_CH1_CCR, TIMER8, 3, AFIO_EXTI_PC}, - /* D38/PC9 (BUT) */ - {GPIOC, 9, ADCx, TIMER8_CH1_CCR, TIMER8, 4, AFIO_EXTI_PC} + {GPIOC, 13, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D21/PC13 */ + {GPIOC, 14, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D22/PC14 */ + {GPIOC, 15, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D23/PC15 */ + {GPIOB, 9, ADCx, TIMER4, 4, AFIO_EXTI_PB}, /* D24/PB9 */ + {GPIOD, 2, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D25/PD2 */ + {GPIOC, 10, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D26/PC10 */ + {GPIOB, 0, 8, TIMER3, 3, AFIO_EXTI_PB}, /* D27/PB0 */ + {GPIOB, 1, 9, TIMER3, 4, AFIO_EXTI_PB}, /* D28/PB1 */ + {GPIOB, 10, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D29/PB10 */ + {GPIOB, 11, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D30/PB11 */ + {GPIOB, 12, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D31/PB12 */ + {GPIOB, 13, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D32/PB13 */ + {GPIOB, 14, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D33/PB14 */ + {GPIOB, 15, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D34/PB15 */ + {GPIOC, 6, ADCx, TIMER8, 1, AFIO_EXTI_PC}, /* D35/PC6 */ + {GPIOC, 7, ADCx, TIMER8, 2, AFIO_EXTI_PC}, /* D36/PC7 */ + {GPIOC, 8, ADCx, TIMER8, 3, AFIO_EXTI_PC}, /* D37/PC8 */ + {GPIOC, 9, ADCx, TIMER8, 4, AFIO_EXTI_PC} /* D38/PC9 (BUT) */ }; #else diff --git a/wirish/boards.h b/wirish/boards.h index 94566fa..d186dc4 100644 --- a/wirish/boards.h +++ b/wirish/boards.h @@ -33,7 +33,8 @@ #include "libmaple.h" #include "gpio.h" -#include "timers.h" +#include "timer.h" +#include "native_sram.h" /* Set of all possible pin names; not all boards have all these (note that we use the Dx convention since all of the Maple's pins are @@ -56,9 +57,8 @@ typedef struct PinMapping { gpio_dev *gpio_device; uint32 pin; uint32 adc_channel; - TimerCCR timer_ccr; - timer_dev_num timer_num; - uint32 timer_chan; + timer_dev* timer_device; + uint8 timer_chan; afio_exti_port ext_port; } PinMapping; @@ -94,6 +94,7 @@ extern PinMapping PIN_MAP[]; #define NR_GPIO_PINS 100 #define BOARD_INIT do { \ + initNativeSRAM(); } while(0) #elif defined(BOARD_maple_mini) diff --git a/wirish/comm/HardwareSPI.cpp b/wirish/comm/HardwareSPI.cpp index 20090f5..aea7734 100644 --- a/wirish/comm/HardwareSPI.cpp +++ b/wirish/comm/HardwareSPI.cpp @@ -47,8 +47,10 @@ * TODO: Do the complementary PWM outputs mess up SPI2? * */ -#include "wirish.h" #include "spi.h" +#include "timer.h" + +#include "wirish.h" #include "HardwareSPI.h" static const uint32 prescaleFactors[MAX_SPI_FREQS] = { diff --git a/wirish/comm/HardwareSerial.cpp b/wirish/comm/HardwareSerial.cpp index 08252d8..97a5ec3 100644 --- a/wirish/comm/HardwareSerial.cpp +++ b/wirish/comm/HardwareSerial.cpp @@ -31,12 +31,10 @@ #include "wirish.h" #include "HardwareSerial.h" #include "usart.h" -#include "gpio.h" -#include "timers.h" -HardwareSerial Serial1(USART1, 4500000UL, GPIOA, 9,10, TIMER1, 2); -HardwareSerial Serial2(USART2, 2250000UL, GPIOA, 2, 3, TIMER2, 3); -HardwareSerial Serial3(USART3, 2250000UL, GPIOB, 10,11, TIMER_INVALID, 0); +HardwareSerial Serial1(USART1, 4500000UL, GPIOA, 9, 10, TIMER1, 2); +HardwareSerial Serial2(USART2, 2250000UL, GPIOA, 2, 3, TIMER2, 3); +HardwareSerial Serial3(USART3, 2250000UL, GPIOB, 10, 11, NULL, 0); // TODO: High density device ports HardwareSerial::HardwareSerial(uint8 usart_num, @@ -44,15 +42,15 @@ HardwareSerial::HardwareSerial(uint8 usart_num, gpio_dev *gpio_device, uint8 tx_pin, uint8 rx_pin, - timer_dev_num timer_num, - uint8 compare_num) { + timer_dev *timer_device, + uint8 channel_num) { this->usart_num = usart_num; this->max_baud = max_baud; this->gpio_device = gpio_device; this->tx_pin = tx_pin; this->rx_pin = rx_pin; - this->timer_num = timer_num; - this->compare_num = compare_num; + this->timer_device = timer_device; + this->channel_num = channel_num; } uint8 HardwareSerial::read(void) { @@ -75,9 +73,9 @@ void HardwareSerial::begin(uint32 baud) { gpio_set_mode(gpio_device, tx_pin, GPIO_AF_OUTPUT_PP); gpio_set_mode(gpio_device, rx_pin, GPIO_INPUT_FLOATING); - if (timer_num != TIMER_INVALID) { + if (timer_device != NULL) { /* turn off any pwm if there's a conflict on this usart */ - timer_set_mode(timer_num, compare_num, TIMER_DISABLED); + timer_set_mode(timer_device, channel_num, TIMER_DISABLED); } usart_init(usart_num, baud); diff --git a/wirish/comm/HardwareSerial.h b/wirish/comm/HardwareSerial.h index ef19a56..7852d51 100644 --- a/wirish/comm/HardwareSerial.h +++ b/wirish/comm/HardwareSerial.h @@ -31,7 +31,9 @@ #ifndef _HARDWARESERIAL_H_ #define _HARDWARESERIAL_H_ -#include "timers.h" +#include "libmaple_types.h" +#include "gpio.h" +#include "timer.h" #include "Print.h" @@ -49,16 +51,16 @@ class HardwareSerial : public Print { gpio_dev *gpio_device; uint8 tx_pin; uint8 rx_pin; - timer_dev_num timer_num; - uint8 compare_num; + timer_dev *timer_device; + uint8 channel_num; public: HardwareSerial(uint8 usart_num, uint32 max_baud, gpio_dev *gpio_device, uint8 tx_pin, uint8 rx_pin, - timer_dev_num timer_num, - uint8 compare_num); + timer_dev *timer_device, + uint8 channel_num); void begin(uint32 baud); void end(void); uint32 available(void); diff --git a/wirish/pwm.cpp b/wirish/pwm.cpp index 072e4cd..6b09cef 100644 --- a/wirish/pwm.cpp +++ b/wirish/pwm.cpp @@ -23,26 +23,20 @@ *****************************************************************************/ /** - * @brief Arduino-compatible PWM implementation. + * @brief Arduino-style PWM implementation. */ -#include "wirish.h" -#include "timers.h" -#include "io.h" +#include "libmaple_types.h" +#include "timer.h" + +#include "boards.h" #include "pwm.h" void pwmWrite(uint8 pin, uint16 duty_cycle) { - TimerCCR ccr; - - if (pin >= NR_GPIO_PINS) { - return; - } - - ccr = PIN_MAP[pin].timer_ccr; - - if (ccr == 0) { + timer_dev *dev = PIN_MAP[pin].timer_device; + if (pin >= NR_GPIO_PINS || dev == NULL || dev->type == TIMER_BASIC) { return; } - timer_pwm_write_ccr(ccr, duty_cycle); + timer_set_compare(dev, PIN_MAP[pin].timer_chan, duty_cycle); } diff --git a/wirish/rules.mk b/wirish/rules.mk index 3dd4b2d..d250cb9 100644 --- a/wirish/rules.mk +++ b/wirish/rules.mk @@ -18,7 +18,6 @@ cppSRCS_$(d) := wirish_math.cpp \ comm/HardwareSerial.cpp \ comm/HardwareSPI.cpp \ usb_serial.cpp \ - HardwareTimer.cpp \ cxxabi-compat.cpp \ wirish.cpp \ wirish_shift.cpp \ diff --git a/wirish/wirish.cpp b/wirish/wirish.cpp index 65d0262..6dcb1b5 100644 --- a/wirish/wirish.cpp +++ b/wirish/wirish.cpp @@ -23,61 +23,107 @@ *****************************************************************************/ /** - * @brief generic maple board bring up: + * @brief Generic Maple board initialization. * - * By default, we bring up all maple boards running on the stm32 to 72mhz, - * clocked off the PLL, driven by the 8MHz external crystal. - * - * AHB and APB2 are clocked at 72MHz - * APB1 is clocked at 36MHz + * By default, we bring up all Maple boards to 72MHz, clocked off the + * PLL, driven by the 8MHz external crystal. AHB and APB2 are clocked + * at 72MHz. APB1 is clocked at 36MHz. */ #include "wirish.h" + +#include "flash.h" +#include "rcc.h" +#include "nvic.h" #include "systick.h" #include "gpio.h" -#include "nvic.h" +#include "adc.h" +#include "timer.h" #include "usb.h" -#include "rcc.h" -#include "fsmc.h" -#include "dac.h" -#include "flash.h" -#include "native_sram.h" +static void setupFlash(void); +static void setupClocks(void); +static void setupADC(void); +static void setupTimers(void); + +/** + * Board-wide initialization function. Called before main(). + */ void init(void) { - /* make sure the flash is ready before spinning the high speed clock up */ + setupFlash(); + setupClocks(); + nvic_init(); + systick_init(SYSTICK_RELOAD_VAL); + gpio_init_all(); + afio_init(); + setupADC(); + setupTimers(); + setupUSB(); + + BOARD_INIT; +} + +static void setupFlash(void) { flash_enable_prefetch(); flash_set_latency(FLASH_WAIT_STATE_2); +} -#ifdef BOARD_maple_native - initNativeSRAM(); -#endif - - /* initialize clocks */ +/* + * Clock setup. Note that some of this only takes effect if we're + * running bare metal and the bootloader hasn't done it for us + * already. + * + * If you change this function, you MUST change the file-level Doxygen + * comment above. + */ +static void setupClocks() { rcc_clk_init(RCC_CLKSRC_PLL, RCC_PLLSRC_HSE, RCC_PLLMUL_9); rcc_set_prescaler(RCC_PRESCALER_AHB, RCC_AHB_SYSCLK_DIV_1); rcc_set_prescaler(RCC_PRESCALER_APB1, RCC_APB1_HCLK_DIV_2); rcc_set_prescaler(RCC_PRESCALER_APB2, RCC_APB2_HCLK_DIV_1); +} - nvic_init(); - systick_init(SYSTICK_RELOAD_VAL); - gpio_init_all(); - afio_init(); - - /* Initialize the ADC for slow conversions, to allow for high - impedance inputs. */ +/* TODO initialize more ADCs on high density boards. */ +static void setupADC() { adc_init(ADC1, 0); - adc_set_sample_rate(ADC1, ADC_SMPR_55_5); - - timer_init(TIMER1, 1); - timer_init(TIMER2, 1); - timer_init(TIMER3, 1); - timer_init(TIMER4, 1); -#ifdef STM32_HIGH_DENSITY - timer_init(TIMER5, 1); - timer_init(TIMER8, 1); -#endif - setupUSB(); + adc_set_sample_rate(ADC1, ADC_SMPR_55_5); // for high impedance inputs +} - /* include the board-specific init macro */ - BOARD_INIT; +static void timerDefaultConfig(timer_dev*); + +static void setupTimers() { + timer_foreach(timerDefaultConfig); +} + +static void timerDefaultConfig(timer_dev *dev) { + timer_adv_reg_map *regs = (dev->regs).adv; + const uint16 full_overflow = 0xFFFF; + const uint16 half_duty = 0x8FFF; + + timer_init(dev); + timer_pause(dev); + + regs->CR1 = TIMER_CR1_ARPE; + regs->PSC = 1; + regs->SR = 0; + regs->DIER = 0; + regs->EGR = TIMER_EGR_UG; + + switch (dev->type) { + case TIMER_ADVANCED: + regs->BDTR = TIMER_BDTR_MOE | TIMER_BDTR_LOCK_OFF; + // fall-through + case TIMER_GENERAL: + timer_set_reload(dev, full_overflow); + + for (int channel = 1; channel <= 4; channel++) { + timer_set_compare(dev, channel, half_duty); + timer_oc_set_mode(dev, channel, TIMER_OC_MODE_PWM_1, TIMER_OC_PE); + } + // fall-through + case TIMER_BASIC: + break; + } + + timer_resume(dev); } diff --git a/wirish/wirish.h b/wirish/wirish.h index 447b2b6..319df97 100644 --- a/wirish/wirish.h +++ b/wirish/wirish.h @@ -32,7 +32,6 @@ #define _WIRISH_H_ #include "libmaple.h" -#include "timers.h" #include "boards.h" #include "io.h" @@ -44,7 +43,6 @@ #include "HardwareSPI.h" #include "HardwareSerial.h" #include "usb_serial.h" -#include "HardwareTimer.h" /* Arduino wiring macros and bit defines */ #define HIGH 0x1 @@ -69,7 +67,6 @@ typedef uint8 boolean; typedef uint8 byte; void init(void); -void shiftOut(uint8 dataPin, uint8 clockPin, uint8 bitOrder, byte val); #endif diff --git a/wirish/wirish_digital.cpp b/wirish/wirish_digital.cpp index 0c0bd85..4b68861 100644 --- a/wirish/wirish_digital.cpp +++ b/wirish/wirish_digital.cpp @@ -72,15 +72,15 @@ void pinMode(uint8 pin, WiringPinMode mode) { gpio_set_mode(PIN_MAP[pin].gpio_device, PIN_MAP[pin].pin, outputMode); - if (PIN_MAP[pin].timer_num != TIMER_INVALID) { + if (PIN_MAP[pin].timer_device != NULL) { /* enable/disable timer channels if we're switching into or out of pwm */ if (pwm) { - timer_set_mode(PIN_MAP[pin].timer_num, + timer_set_mode(PIN_MAP[pin].timer_device, PIN_MAP[pin].timer_chan, TIMER_PWM); } else { - timer_set_mode(PIN_MAP[pin].timer_num, + timer_set_mode(PIN_MAP[pin].timer_device, PIN_MAP[pin].timer_chan, TIMER_DISABLED); } -- cgit v1.2.3 From bc246609ccd44601a0564fea8da407cc500ad471 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Thu, 24 Mar 2011 07:56:29 -0400 Subject: timer_set_dma_burst_length() and TIMER8 comment bugfixes --- libmaple/timer.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libmaple/timer.h b/libmaple/timer.h index 025bcb0..fa19cc9 100644 --- a/libmaple/timer.h +++ b/libmaple/timer.h @@ -170,7 +170,7 @@ extern timer_dev *TIMER5; extern timer_dev *TIMER6; /** Timer 7 device (basic) */ extern timer_dev *TIMER7; -/** Timer 8 device (basic) */ +/** Timer 8 device (advanced) */ extern timer_dev *TIMER8; #endif @@ -855,7 +855,7 @@ static inline uint8 timer_get_dma_burst_length(timer_dev *dev) { static inline void timer_set_dma_burst_length(timer_dev *dev, uint8 length) { uint32 tmp = (dev->regs).gen->DCR; tmp &= ~TIMER_DCR_DBL; - tmp |= (length << 8) - 1; + tmp |= (length - 1) << 8; (dev->regs).gen->DCR = tmp; } -- cgit v1.2.3 From 63ea7464925b8cbeb8623d08a2bde0b1d2044047 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Thu, 24 Mar 2011 17:27:38 -0400 Subject: Adding /wirish/boards/ for easier porting; shrank PIN_MAPs. /wirish/boards/ contains xxx.h and xxx.cpp (for xxx=maple, maple_native, maple_mini, maple_RET6). The headers contain the board-specific #defines that used to live in boards.h (except BOARD_INIT, which was removed). The CPP files contain the PIN_MAP definitions that used to live in boards.cpp, and a proper boardInit() function to replace the old BOARD_INIT macro. This will make it easier to add new boards in the future. struct PinMapping was renamed struct stm32_pin_info, and was moved into a new wirish_types.h. Its external interrupt field was moved into struct gpio_dev, which saves memory by storing an afio_exti_port per port, rather than one per pin. Also rearranged the stm32_pin_info fields to improve packing. Maple's PIN_MAP is now down to below 500 bytes. --- examples/test-session.cpp | 2 +- libmaple/gpio.c | 35 +++--- libmaple/gpio.h | 59 +++++---- wirish/boards.cpp | 268 ----------------------------------------- wirish/boards.h | 144 ++++++++-------------- wirish/boards/maple.cpp | 94 +++++++++++++++ wirish/boards/maple.h | 59 +++++++++ wirish/boards/maple_RET6.cpp | 88 ++++++++++++++ wirish/boards/maple_RET6.h | 61 ++++++++++ wirish/boards/maple_mini.cpp | 87 +++++++++++++ wirish/boards/maple_mini.h | 60 +++++++++ wirish/boards/maple_native.cpp | 155 ++++++++++++++++++++++++ wirish/boards/maple_native.h | 64 ++++++++++ wirish/ext_interrupts.cpp | 6 +- wirish/rules.mk | 10 +- wirish/wirish.cpp | 3 +- wirish/wirish.h | 1 + wirish/wirish_analog.cpp | 2 +- wirish/wirish_digital.cpp | 8 +- wirish/wirish_types.h | 51 ++++++++ 20 files changed, 840 insertions(+), 417 deletions(-) delete mode 100644 wirish/boards.cpp create mode 100644 wirish/boards/maple.cpp create mode 100644 wirish/boards/maple.h create mode 100644 wirish/boards/maple_RET6.cpp create mode 100644 wirish/boards/maple_RET6.h create mode 100644 wirish/boards/maple_mini.cpp create mode 100644 wirish/boards/maple_mini.h create mode 100644 wirish/boards/maple_native.cpp create mode 100644 wirish/boards/maple_native.h create mode 100644 wirish/wirish_types.h diff --git a/examples/test-session.cpp b/examples/test-session.cpp index 9b4bce4..28c02f3 100644 --- a/examples/test-session.cpp +++ b/examples/test-session.cpp @@ -351,7 +351,7 @@ void cmd_everything(void) { // TODO void fast_gpio(int maple_pin) { gpio_dev *dev = PIN_MAP[maple_pin].gpio_device; - uint32 pin = PIN_MAP[maple_pin].pin; + uint32 pin = PIN_MAP[maple_pin].gpio_pin; gpio_write_bit(dev, pin, 1); gpio_write_bit(dev, pin, 0); gpio_write_bit(dev, pin, 1); gpio_write_bit(dev, pin, 0); diff --git a/libmaple/gpio.c b/libmaple/gpio.c index 18b856b..5484e21 100644 --- a/libmaple/gpio.c +++ b/libmaple/gpio.c @@ -34,45 +34,52 @@ */ gpio_dev gpioa = { - .regs = GPIOA_BASE, - .clk_id = RCC_GPIOA + .regs = GPIOA_BASE, + .clk_id = RCC_GPIOA, + .exti_port = AFIO_EXTI_PA, }; gpio_dev* const GPIOA = &gpioa; gpio_dev gpiob = { - .regs = GPIOB_BASE, - .clk_id = RCC_GPIOB + .regs = GPIOB_BASE, + .clk_id = RCC_GPIOB, + .exti_port = AFIO_EXTI_PB, }; gpio_dev* const GPIOB = &gpiob; gpio_dev gpioc = { - .regs = GPIOC_BASE, - .clk_id = RCC_GPIOC + .regs = GPIOC_BASE, + .clk_id = RCC_GPIOC, + .exti_port = AFIO_EXTI_PC, }; gpio_dev* const GPIOC = &gpioc; gpio_dev gpiod = { - .regs = GPIOD_BASE, - .clk_id = RCC_GPIOD + .regs = GPIOD_BASE, + .clk_id = RCC_GPIOD, + .exti_port = AFIO_EXTI_PD, }; gpio_dev* const GPIOD = &gpiod; #ifdef STM32_HIGH_DENSITY gpio_dev gpioe = { - .regs = GPIOE_BASE, - .clk_id = RCC_GPIOE + .regs = GPIOE_BASE, + .clk_id = RCC_GPIOE, + .exti_port = AFIO_EXTI_PE, }; gpio_dev* const GPIOE = &gpioe; gpio_dev gpiof = { - .regs = GPIOF_BASE, - .clk_id = RCC_GPIOF + .regs = GPIOF_BASE, + .clk_id = RCC_GPIOF, + .exti_port = AFIO_EXTI_PF, }; gpio_dev* const GPIOF = &gpiof; gpio_dev gpiog = { - .regs = GPIOG_BASE, - .clk_id = RCC_GPIOG + .regs = GPIOG_BASE, + .clk_id = RCC_GPIOG, + .exti_port = AFIO_EXTI_PG, }; gpio_dev* const GPIOG = &gpiog; #endif diff --git a/libmaple/gpio.h b/libmaple/gpio.h index a8a4985..63ba0d5 100644 --- a/libmaple/gpio.h +++ b/libmaple/gpio.h @@ -47,19 +47,37 @@ extern "C"{ /** GPIO register map type */ typedef struct gpio_reg_map { - __io uint32 CRL; ///< Port configuration register low - __io uint32 CRH; ///< Port configuration register high - __io uint32 IDR; ///< Port input data register - __io uint32 ODR; ///< Port output data register - __io uint32 BSRR; ///< Port bit set/reset register - __io uint32 BRR; ///< Port bit reset register - __io uint32 LCKR; ///< Port configuration lock register + __io uint32 CRL; /**< Port configuration register low */ + __io uint32 CRH; /**< Port configuration register high */ + __io uint32 IDR; /**< Port input data register */ + __io uint32 ODR; /**< Port output data register */ + __io uint32 BSRR; /**< Port bit set/reset register */ + __io uint32 BRR; /**< Port bit reset register */ + __io uint32 LCKR; /**< Port configuration lock register */ } gpio_reg_map; + +/** + * External interrupt line port selector. Used to determine which + * GPIO port to map an external interrupt line onto. */ +/* (See AFIO sections, below) */ +typedef enum { + AFIO_EXTI_PA, /**< Use PAx pin. */ + AFIO_EXTI_PB, /**< Use PBx pin. */ + AFIO_EXTI_PC, /**< Use PCx pin. */ + AFIO_EXTI_PD, /**< Use PDx pin. */ +#ifdef STM32_HIGH_DENSITY + AFIO_EXTI_PE, /**< Use PEx pin. */ + AFIO_EXTI_PF, /**< Use PFx pin. */ + AFIO_EXTI_PG, /**< Use PGx pin. */ +#endif +} afio_exti_port; + /** GPIO device type */ typedef struct gpio_dev { - gpio_reg_map *regs; ///< Register map - rcc_clk_id clk_id; ///< RCC clock information + gpio_reg_map *regs; /**< Register map */ + rcc_clk_id clk_id; /**< RCC clock information */ + afio_exti_port exti_port; /**< AFIO external interrupt port value */ } gpio_dev; extern gpio_dev gpioa; @@ -144,6 +162,14 @@ void gpio_init(gpio_dev *dev); void gpio_init_all(void); void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode); +/** + * @brief Get a GPIO port's corresponding afio_exti_port. + * @param dev GPIO device whose afio_exti_port to return. + */ +static inline afio_exti_port gpio_exti_port(gpio_dev *dev) { + return dev->exti_port; +} + /** * Set or reset a GPIO pin. * @@ -259,21 +285,6 @@ typedef struct afio_reg_map { /* External interrupt configuration registers */ -/** - * External interrupt line port selector. Used to determine which - * GPIO port to map an external interrupt line onto. */ -typedef enum { - AFIO_EXTI_PA, /**< Use PAx pin. */ - AFIO_EXTI_PB, /**< Use PBx pin. */ - AFIO_EXTI_PC, /**< Use PCx pin. */ - AFIO_EXTI_PD, /**< Use PDx pin. */ -#ifdef STM32_HIGH_DENSITY - AFIO_EXTI_PE, /**< Use PEx pin. */ - AFIO_EXTI_PF, /**< Use PFx pin. */ - AFIO_EXTI_PG, /**< Use PGx pin. */ -#endif -} afio_exti_port; - /** * External interrupt line numbers. */ diff --git a/wirish/boards.cpp b/wirish/boards.cpp deleted file mode 100644 index d99b019..0000000 --- a/wirish/boards.cpp +++ /dev/null @@ -1,268 +0,0 @@ -#include "boards.h" - -// For concision -#define ADCx ADC_INVALID - -#if defined(BOARD_maple) - -PinMapping PIN_MAP[NR_GPIO_PINS] = { - {GPIOA, 3, 3, TIMER2, 4, AFIO_EXTI_PA}, /* D0/PA3 */ - {GPIOA, 2, 2, TIMER2, 3, AFIO_EXTI_PA}, /* D1/PA2 */ - {GPIOA, 0, 0, TIMER2, 1, AFIO_EXTI_PA}, /* D2/PA0 */ - {GPIOA, 1, 1, TIMER2, 2, AFIO_EXTI_PA}, /* D3/PA1 */ - {GPIOB, 5, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D4/PB5 */ - {GPIOB, 6, ADCx, TIMER4, 1, AFIO_EXTI_PB}, /* D5/PB6 */ - {GPIOA, 8, ADCx, TIMER1, 1, AFIO_EXTI_PA}, /* D6/PA8 */ - {GPIOA, 9, ADCx, TIMER1, 2, AFIO_EXTI_PA}, /* D7/PA9 */ - {GPIOA, 10, ADCx, TIMER1, 3, AFIO_EXTI_PA}, /* D8/PA10 */ - {GPIOB, 7, ADCx, TIMER4, 2, AFIO_EXTI_PB}, /* D9/PB7 */ - {GPIOA, 4, 4, NULL, 0, AFIO_EXTI_PA}, /* D10/PA4 */ - {GPIOA, 7, 7, TIMER3, 2, AFIO_EXTI_PA}, /* D11/PA7 */ - {GPIOA, 6, 6, TIMER3, 1, AFIO_EXTI_PA}, /* D12/PA6 */ - {GPIOA, 5, 5, NULL, 0, AFIO_EXTI_PA}, /* D13/PA5 (LED) */ - {GPIOB, 8, ADCx, TIMER4, 3, AFIO_EXTI_PB}, /* D14/PB8 */ - - /* Little header */ - - {GPIOC, 0, 10, NULL, 0, AFIO_EXTI_PC}, /* D15/PC0 */ - {GPIOC, 1, 11, NULL, 0, AFIO_EXTI_PC}, /* D16/PC1 */ - {GPIOC, 2, 12, NULL, 0, AFIO_EXTI_PC}, /* D17/PC2 */ - {GPIOC, 3, 13, NULL, 0, AFIO_EXTI_PC}, /* D18/PC3 */ - {GPIOC, 4, 14, NULL, 0, AFIO_EXTI_PC}, /* D19/PC4 */ - {GPIOC, 5, 15, NULL, 0, AFIO_EXTI_PC}, /* D20/PC5 */ - - /* External header */ - - {GPIOC, 13, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D21/PC13 */ - {GPIOC, 14, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D22/PC14 */ - {GPIOC, 15, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D23/PC15 */ - {GPIOB, 9, ADCx, TIMER4, 4, AFIO_EXTI_PB}, /* D24/PB9 */ - {GPIOD, 2, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D25/PD2 */ - {GPIOC, 10, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D26/PC10 */ - {GPIOB, 0, 8, TIMER3, 3, AFIO_EXTI_PB}, /* D27/PB0 */ - {GPIOB, 1, 9, TIMER3, 4, AFIO_EXTI_PB}, /* D28/PB1 */ - {GPIOB, 10, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D29/PB10 */ - {GPIOB, 11, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D30/PB11 */ - {GPIOB, 12, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D31/PB12 */ - {GPIOB, 13, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D32/PB13 */ - {GPIOB, 14, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D33/PB14 */ - {GPIOB, 15, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D34/PB15 */ - {GPIOC, 6, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D35/PC6 */ - {GPIOC, 7, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D36/PC7 */ - {GPIOC, 8, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D37/PC8 */ - {GPIOC, 9, ADCx, NULL, 0, AFIO_EXTI_PC} /* D38/PC9 (BUT) */ -}; - -#elif defined(BOARD_maple_native) - -PinMapping PIN_MAP[NR_GPIO_PINS] = { - /* Top header */ - - {GPIOB, 10, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D0/PB10 */ - {GPIOB, 2, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D1/PB2 */ - {GPIOB, 12, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D2/PB12 */ - {GPIOB, 13, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D3/PB13 */ - {GPIOB, 14, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D4/PB14 */ - {GPIOB, 15, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D5/PB15 */ - {GPIOC, 0, 10, NULL, 0, AFIO_EXTI_PC}, /* D6/PC0 */ - {GPIOC, 1, 11, NULL, 0, AFIO_EXTI_PC}, /* D7/PC1 */ - {GPIOC, 2, 12, NULL, 0, AFIO_EXTI_PC}, /* D8/PC2 */ - {GPIOC, 3, 13, NULL, 0, AFIO_EXTI_PC}, /* D9/PC3 */ - {GPIOC, 4, 14, NULL, 0, AFIO_EXTI_PC}, /* D10/PC4 */ - {GPIOC, 5, 15, NULL, 0, AFIO_EXTI_PC}, /* D11/PC5 */ - {GPIOC, 6, ADCx, TIMER8, 1, AFIO_EXTI_PC}, /* D12/PC6 */ - {GPIOC, 7, ADCx, TIMER8, 2, AFIO_EXTI_PC}, /* D13/PC7 */ - {GPIOC, 8, ADCx, TIMER8, 3, AFIO_EXTI_PC}, /* D14/PC8 */ - {GPIOC, 9, ADCx, TIMER8, 4, AFIO_EXTI_PC}, /* D15/PC9 */ - {GPIOC, 10, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D16/PC10 */ - {GPIOC, 11, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D17/PC11 */ - {GPIOC, 12, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D18/PC12 */ - {GPIOC, 13, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D19/PC13 */ - {GPIOC, 14, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D20/PC14 */ - {GPIOC, 15, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D21/PC15 */ - {GPIOA, 8, ADCx, TIMER1, 1, AFIO_EXTI_PA}, /* D22/PA8 */ - {GPIOA, 9, ADCx, TIMER1, 2, AFIO_EXTI_PA}, /* D23/PA9 */ - {GPIOA, 10, ADCx, TIMER1, 3, AFIO_EXTI_PA}, /* D24/PA10 */ - {GPIOB, 9, ADCx, TIMER4, 4, AFIO_EXTI_PB}, /* D25/PB9 */ - - /* Bottom header */ - /* FIXME (?) What about D48--D50 also being TIMER2_CH[234]? */ - - {GPIOD, 2, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D26/PD2 */ - {GPIOD, 3, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D27/PD3 */ - {GPIOD, 6, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D28/PD6 */ - {GPIOG, 11, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D29/PG11 */ - {GPIOG, 12, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D30/PG12 */ - {GPIOG, 13, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D31/PG13 */ - {GPIOG, 14, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D32/PG14 */ - {GPIOG, 8, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D33/PG8 */ - {GPIOG, 7, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D34/PG7 */ - {GPIOG, 6, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D35/PG6 */ - {GPIOB, 5, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D36/PB5 */ - {GPIOB, 6, ADCx, TIMER4, 1, AFIO_EXTI_PB}, /* D37/PB6 */ - {GPIOB, 7, ADCx, TIMER4, 2, AFIO_EXTI_PB}, /* D38/PB7 */ - {GPIOF, 6, 4, NULL, 0, AFIO_EXTI_PF}, /* D39/PF6 */ - {GPIOF, 7, 5, NULL, 0, AFIO_EXTI_PF}, /* D40/PF7 */ - {GPIOF, 8, 6, NULL, 0, AFIO_EXTI_PF}, /* D41/PF8 */ - {GPIOF, 9, 7, NULL, 0, AFIO_EXTI_PF}, /* D42/PF9 */ - {GPIOF, 10, 8, NULL, 0, AFIO_EXTI_PF}, /* D43/PF10 */ - {GPIOF, 11, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D44/PF11 */ - {GPIOB, 1, 9, TIMER3, 4, AFIO_EXTI_PB}, /* D45/PB1 */ - {GPIOB, 0, 8, TIMER3, 3, AFIO_EXTI_PB}, /* D46/PB0 */ - {GPIOA, 0, 0, TIMER5, 1, AFIO_EXTI_PA}, /* D47/PA0 */ - {GPIOA, 1, 1, TIMER5, 2, AFIO_EXTI_PA}, /* D48/PA1 */ - {GPIOA, 2, 2, TIMER5, 3, AFIO_EXTI_PA}, /* D49/PA2 */ - {GPIOA, 3, 3, TIMER5, 4, AFIO_EXTI_PA}, /* D50/PA3 */ - {GPIOA, 4, 4, NULL, 0, AFIO_EXTI_PA}, /* D51/PA4 */ - {GPIOA, 5, 5, NULL, 0, AFIO_EXTI_PA}, /* D52/PA5 */ - {GPIOA, 6, 6, TIMER3, 1, AFIO_EXTI_PA}, /* D53/PA6 */ - {GPIOA, 7, 7, TIMER3, 2, AFIO_EXTI_PA}, /* D54/PA7 */ - - /* Right (triple) header */ - - {GPIOF, 0, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D55/PF0 */ - {GPIOD, 11, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D56/PD11 */ - {GPIOD, 14, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D57/PD14 */ - {GPIOF, 1, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D58/PF1 */ - {GPIOD, 12, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D59/PD12 */ - {GPIOD, 15, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D60/PD15 */ - {GPIOF, 2, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D61/PF2 */ - {GPIOD, 13, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D62/PD13 */ - {GPIOD, 0, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D63/PD0 */ - {GPIOF, 3, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D64/PF3 */ - {GPIOE, 3, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D65/PE3 */ - {GPIOD, 1, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D66/PD1 */ - {GPIOF, 4, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D67/PF4 */ - {GPIOE, 4, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D68/PE4 */ - {GPIOE, 7, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D69/PE7 */ - {GPIOF, 5, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D70/PF5 */ - {GPIOE, 5, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D71/PE5 */ - {GPIOE, 8, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D72/PE8 */ - {GPIOF, 12, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D73/PF12 */ - {GPIOE, 6, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D74/PE6 */ - {GPIOE, 9, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D75/PE9 */ - {GPIOF, 13, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D76/PF13 */ - {GPIOE, 10, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D77/PE10 */ - {GPIOF, 14, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D78/PF14 */ - {GPIOG, 9, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D79/PG9 */ - {GPIOE, 11, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D80/PE11 */ - {GPIOF, 15, ADCx, NULL, 0, AFIO_EXTI_PF}, /* D81/PF15 */ - {GPIOG, 10, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D82/PG10 */ - {GPIOE, 12, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D83/PE12 */ - {GPIOG, 0, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D84/PG0 */ - {GPIOD, 5, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D85/PD5 */ - {GPIOE, 13, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D86/PE13 */ - {GPIOG, 1, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D87/PG1 */ - {GPIOD, 4, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D88/PD4 */ - {GPIOE, 14, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D89/PE14 */ - {GPIOG, 2, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D90/PG2 */ - {GPIOE, 1, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D91/PE1 */ - {GPIOE, 15, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D92/PE15 */ - {GPIOG, 3, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D93/PG3 */ - {GPIOE, 0, ADCx, NULL, 0, AFIO_EXTI_PE}, /* D94/PE0 */ - {GPIOD, 8, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D95/PD8 */ - {GPIOG, 4, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D96/PG4 */ - {GPIOD, 9, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D97/PD9 */ - {GPIOG, 5, ADCx, NULL, 0, AFIO_EXTI_PG}, /* D98/PG5 */ - {GPIOD, 10, ADCx, NULL, 0, AFIO_EXTI_PD} /* D99/PD10 */ -}; - -#elif defined(BOARD_maple_mini) - -PinMapping PIN_MAP[NR_GPIO_PINS] = { - /* Top header */ - - {GPIOB, 11, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D0/PB11 */ - {GPIOB, 10, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D1/PB10 */ - {GPIOB, 2, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D2/PB2 */ - {GPIOB, 0, 8, TIMER3, 3, AFIO_EXTI_PB}, /* D3/PB0 */ - {GPIOA, 7, 7, TIMER3, 2, AFIO_EXTI_PA}, /* D4/PA7 */ - {GPIOA, 6, 6, TIMER3, 1, AFIO_EXTI_PA}, /* D5/PA6 */ - {GPIOA, 5, 5, NULL, 0, AFIO_EXTI_PA}, /* D6/PA5 */ - {GPIOA, 4, 4, NULL, 0, AFIO_EXTI_PA}, /* D7/PA4 */ - {GPIOA, 3, 3, TIMER2, 4, AFIO_EXTI_PA}, /* D8/PA3 */ - {GPIOA, 2, 2, TIMER2, 3, AFIO_EXTI_PA}, /* D9/PA2 */ - {GPIOA, 1, 1, TIMER2, 2, AFIO_EXTI_PA}, /* D10/PA1 */ - {GPIOA, 0, 0, TIMER2, 1, AFIO_EXTI_PA}, /* D11/PA0 */ - {GPIOC, 15, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D12/PC15 */ - {GPIOC, 14, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D13/PC14 */ - {GPIOC, 13, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D14/PC13 */ - - /* Bottom header */ - - {GPIOB, 7, ADCx, TIMER4, 2, AFIO_EXTI_PB}, /* D15/PB7 */ - {GPIOB, 6, ADCx, TIMER4, 1, AFIO_EXTI_PB}, /* D16/PB6 */ - {GPIOB, 5, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D17/PB5 */ - {GPIOB, 4, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D18/PB4 */ - {GPIOB, 3, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D19/PB3 */ - {GPIOA, 15, ADCx, NULL, 0, AFIO_EXTI_PA}, /* D20/PA15 */ - {GPIOA, 14, ADCx, NULL, 0, AFIO_EXTI_PA}, /* D21/PA14 */ - {GPIOA, 13, ADCx, NULL, 0, AFIO_EXTI_PA}, /* D22/PA13 */ - {GPIOA, 12, ADCx, NULL, 0, AFIO_EXTI_PA}, /* D23/PA12 */ - {GPIOA, 11, ADCx, TIMER1, 4, AFIO_EXTI_PA}, /* D24/PA11 */ - {GPIOA, 10, ADCx, TIMER1, 3, AFIO_EXTI_PA}, /* D25/PA10 */ - {GPIOA, 9, ADCx, TIMER2, 2, AFIO_EXTI_PA}, /* D26/PA9 */ - {GPIOA, 8, ADCx, TIMER1, 1, AFIO_EXTI_PA}, /* D27/PA8 */ - {GPIOB, 15, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D28/PB15 */ - {GPIOB, 14, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D29/PB14 */ - {GPIOB, 13, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D30/PB13 */ - {GPIOB, 12, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D31/PB12 */ - {GPIOB, 8, ADCx, TIMER4, 3, AFIO_EXTI_PB}, /* D32/PB8 */ - {GPIOB, 1, 9, TIMER3, 4, AFIO_EXTI_PB}, /* D33/PB1 */ -}; - -#elif defined(BOARD_maple_RET6) - -PinMapping PIN_MAP[NR_GPIO_PINS] = { - {GPIOA, 3, 3, TIMER2, 4, AFIO_EXTI_PA}, /* D0/PA3 */ - {GPIOA, 2, 2, TIMER2, 3, AFIO_EXTI_PA}, /* D1/PA2 */ - {GPIOA, 0, 0, TIMER2, 1, AFIO_EXTI_PA}, /* D2/PA0 */ - {GPIOA, 1, 1, TIMER2, 2, AFIO_EXTI_PA}, /* D3/PA1 */ - {GPIOB, 5, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D4/PB5 */ - {GPIOB, 6, ADCx, TIMER4, 1, AFIO_EXTI_PB}, /* D5/PB6 */ - {GPIOA, 8, ADCx, TIMER1, 1, AFIO_EXTI_PA}, /* D6/PA8 */ - {GPIOA, 9, ADCx, TIMER1, 2, AFIO_EXTI_PA}, /* D7/PA9 */ - {GPIOA, 10, ADCx, TIMER1, 3, AFIO_EXTI_PA}, /* D8/PA10 */ - {GPIOB, 7, ADCx, TIMER4, 2, AFIO_EXTI_PB}, /* D9/PB7 */ - {GPIOA, 4, 4, NULL, 0, AFIO_EXTI_PA}, /* D10/PA4 */ - {GPIOA, 7, 7, TIMER3, 2, AFIO_EXTI_PA}, /* D11/PA7 */ - {GPIOA, 6, 6, TIMER3, 1, AFIO_EXTI_PA}, /* D12/PA6 */ - {GPIOA, 5, 5, NULL, 0, AFIO_EXTI_PA}, /* D13/PA5 (LED) */ - {GPIOB, 8, ADCx, TIMER4, 3, AFIO_EXTI_PB}, /* D14/PB8 */ - - /* Little header */ - - {GPIOC, 0, 10, NULL, 0, AFIO_EXTI_PC}, /* D15/PC0 */ - {GPIOC, 1, 11, NULL, 0, AFIO_EXTI_PC}, /* D16/PC1 */ - {GPIOC, 2, 12, NULL, 0, AFIO_EXTI_PC}, /* D17/PC2 */ - {GPIOC, 3, 13, NULL, 0, AFIO_EXTI_PC}, /* D18/PC3 */ - {GPIOC, 4, 14, NULL, 0, AFIO_EXTI_PC}, /* D19/PC4 */ - {GPIOC, 5, 15, NULL, 0, AFIO_EXTI_PC}, /* D20/PC5 */ - - /* External header */ - - {GPIOC, 13, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D21/PC13 */ - {GPIOC, 14, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D22/PC14 */ - {GPIOC, 15, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D23/PC15 */ - {GPIOB, 9, ADCx, TIMER4, 4, AFIO_EXTI_PB}, /* D24/PB9 */ - {GPIOD, 2, ADCx, NULL, 0, AFIO_EXTI_PD}, /* D25/PD2 */ - {GPIOC, 10, ADCx, NULL, 0, AFIO_EXTI_PC}, /* D26/PC10 */ - {GPIOB, 0, 8, TIMER3, 3, AFIO_EXTI_PB}, /* D27/PB0 */ - {GPIOB, 1, 9, TIMER3, 4, AFIO_EXTI_PB}, /* D28/PB1 */ - {GPIOB, 10, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D29/PB10 */ - {GPIOB, 11, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D30/PB11 */ - {GPIOB, 12, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D31/PB12 */ - {GPIOB, 13, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D32/PB13 */ - {GPIOB, 14, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D33/PB14 */ - {GPIOB, 15, ADCx, NULL, 0, AFIO_EXTI_PB}, /* D34/PB15 */ - {GPIOC, 6, ADCx, TIMER8, 1, AFIO_EXTI_PC}, /* D35/PC6 */ - {GPIOC, 7, ADCx, TIMER8, 2, AFIO_EXTI_PC}, /* D36/PC7 */ - {GPIOC, 8, ADCx, TIMER8, 3, AFIO_EXTI_PC}, /* D37/PC8 */ - {GPIOC, 9, ADCx, TIMER8, 4, AFIO_EXTI_PC} /* D38/PC9 (BUT) */ -}; - -#else - -#error "Board type has not been selected correctly." - -#endif diff --git a/wirish/boards.h b/wirish/boards.h index d186dc4..b72609d 100644 --- a/wirish/boards.h +++ b/wirish/boards.h @@ -3,29 +3,37 @@ * * Copyright (c) 2010 Bryan Newbold. * - * 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 + * 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 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. + * 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. *****************************************************************************/ -/* This file contains board-specific pin mapping tables. To add a new board - * type, copy the "BOARD_maple" section below and edit it as needed, then - * update your build toolchain with a new "BOARD" type. This must match the - * separate MCU type (which determines the ../libmaple configuration). +/** + * @file boards.h + * @author Bryan Newbold , + * Marti Bolivar + * @brief Board-specific pin information. + * + * To add a new board type, add a new pair of files to + * /wirish/boards/, update the section below with a new "BOARD" type, + * and update /wirish/rules.mk to include your boards/your_board.cpp + * file in the top-level Makefile build. */ #ifndef _BOARDS_H_ @@ -34,12 +42,13 @@ #include "libmaple.h" #include "gpio.h" #include "timer.h" -#include "native_sram.h" + +#include "wirish_types.h" /* Set of all possible pin names; not all boards have all these (note - that we use the Dx convention since all of the Maple's pins are - "digital" pins (e.g. can be used with digitalRead() and - digitalWrite()), but not all of them are connected to ADCs. */ + * that we use the Dx convention since all of the Maple's pins are + * "digital" pins (e.g. can be used with digitalRead() and + * digitalWrite()), but not all of them are connected to ADCs. */ enum { D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15, D16, D17, D18, D19, D20, D21, D22, D23, D24, D25, D26, D27, D28, D29, D30, D31, @@ -50,89 +59,30 @@ enum { D92, D93, D94, D95, D96, D97, D98, D99, D100, D101, D102, D103, D104, D105, D106, D107, D108, D109, D110, D111, }; -#define ADC_INVALID 0xFFFFFFFF - -/* Pin mapping: pin number -> STM32 info */ -typedef struct PinMapping { - gpio_dev *gpio_device; - uint32 pin; - uint32 adc_channel; - timer_dev* timer_device; - uint8 timer_chan; - afio_exti_port ext_port; -} PinMapping; +/** + * @brief Maps each pin to a corresponding struct stm32_pin_info. + * @see struct stm32_pin_info + */ +extern stm32_pin_info PIN_MAP[]; -/* Maps every digital pin to a PinMapping */ -extern PinMapping PIN_MAP[]; +/** Board-specific initialization function. */ +extern void boardInit(void); -/* LeafLabs Maple rev3, rev5 */ #ifdef BOARD_maple - - #define CYCLES_PER_MICROSECOND 72 - #define SYSTICK_RELOAD_VAL 71999 /* takes a cycle to reload */ - - #define BOARD_BUTTON_PIN 38 - #define BOARD_LED_PIN 13 - - /* Total number of GPIO pins that are broken out to headers and - intended for general use. */ - #define NR_GPIO_PINS 39 - - #define BOARD_INIT do { \ - } while(0) - +#include "boards/maple.h" #elif defined(BOARD_maple_native) - - /* LeafLabs Maple Native (prototype) */ - - #define CYCLES_PER_MICROSECOND 72 - #define SYSTICK_RELOAD_VAL 71999 /* takes a cycle to reload */ - - #define BOARD_LED_PIN D21 - #define BOARD_BUTTON_PIN D18 - - #define NR_GPIO_PINS 100 - - #define BOARD_INIT do { \ - initNativeSRAM(); - } while(0) - +#include "boards/maple_native.h" #elif defined(BOARD_maple_mini) - - #define CYCLES_PER_MICROSECOND 72 - #define SYSTICK_RELOAD_VAL 71999 /* takes a cycle to reload */ - - #define BOARD_BUTTON_PIN 32 - #define BOARD_LED_PIN 33 - - #define NR_GPIO_PINS 34 - - /* Since we want the Serial Wire/JTAG pins as GPIOs, disable both - * SW and JTAG debug support */ - #define BOARD_INIT \ - do { \ - afio_mapr_swj_config(AFIO_MAPR_SWJ_NO_JTAG_NO_SW); \ - } while (0) - +#include "boards/maple_mini.h" #elif defined(BOARD_maple_RET6) - - #define CYCLES_PER_MICROSECOND 72 - #define SYSTICK_RELOAD_VAL 71999 /* takes a cycle to reload */ - - #define BOARD_BUTTON_PIN 38 - #define BOARD_LED_PIN 13 - - /* Total number of GPIO pins that are broken out to headers and - intended for general use. */ - #define NR_GPIO_PINS 39 - - #define BOARD_INIT do { \ - } while(0) - +/* + * **NOT** MAPLE REV6. This the **Maple RET6 EDITION**, which is a + * Maple with an STM32F103RET6 (...RET6) instead of an STM32F103RBT6 + * (...RBT6) on it. Maple Rev6 (as of March 2011) DOES NOT EXIST. + */ +#include "boards/maple_RET6.h" #else - #error "Board type has not been selected correctly." - #endif #endif diff --git a/wirish/boards/maple.cpp b/wirish/boards/maple.cpp new file mode 100644 index 0000000..cebd222 --- /dev/null +++ b/wirish/boards/maple.cpp @@ -0,0 +1,94 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file maple.cpp + * @author Marti Bolivar + * @brief Maple PIN_MAP and boardInit(). + */ + +#include "gpio.h" +#include "timer.h" + +#include "maple.h" + +#ifdef BOARD_maple + +void boardInit(void) { +} + +stm32_pin_info PIN_MAP[NR_GPIO_PINS] = { + + /* Top header */ + + {GPIOA, TIMER2, 3, 4, 3}, /* D0/PA3 */ + {GPIOA, TIMER2, 2, 3, 2}, /* D1/PA2 */ + {GPIOA, TIMER2, 0, 1, 0}, /* D2/PA0 */ + {GPIOA, TIMER2, 1, 2, 1}, /* D3/PA1 */ + {GPIOB, NULL, 5, 0, ADCx}, /* D4/PB5 */ + {GPIOB, TIMER4, 6, 1, ADCx}, /* D5/PB6 */ + {GPIOA, TIMER1, 8, 1, ADCx}, /* D6/PA8 */ + {GPIOA, TIMER1, 9, 2, ADCx}, /* D7/PA9 */ + {GPIOA, TIMER1, 10, 3, ADCx}, /* D8/PA10 */ + {GPIOB, TIMER4, 7, 2, ADCx}, /* D9/PB7 */ + {GPIOA, NULL, 4, 0, 4}, /* D10/PA4 */ + {GPIOA, TIMER3, 7, 2, 7}, /* D11/PA7 */ + {GPIOA, TIMER3, 6, 1, 6}, /* D12/PA6 */ + {GPIOA, NULL, 5, 0, 5}, /* D13/PA5 (LED) */ + {GPIOB, TIMER4, 8, 3, ADCx}, /* D14/PB8 */ + + /* Little header */ + + {GPIOC, NULL, 0, 0, 10}, /* D15/PC0 */ + {GPIOC, NULL, 1, 0, 11}, /* D16/PC1 */ + {GPIOC, NULL, 2, 0, 12}, /* D17/PC2 */ + {GPIOC, NULL, 3, 0, 13}, /* D18/PC3 */ + {GPIOC, NULL, 4, 0, 14}, /* D19/PC4 */ + {GPIOC, NULL, 5, 0, 15}, /* D20/PC5 */ + + /* External header */ + + {GPIOC, NULL, 13, 0, ADCx}, /* D21/PC13 */ + {GPIOC, NULL, 14, 0, ADCx}, /* D22/PC14 */ + {GPIOC, NULL, 15, 0, ADCx}, /* D23/PC15 */ + {GPIOB, TIMER4, 9, 4, ADCx}, /* D24/PB9 */ + {GPIOD, NULL, 2, 0, ADCx}, /* D25/PD2 */ + {GPIOC, NULL, 10, 0, ADCx}, /* D26/PC10 */ + {GPIOB, TIMER3, 0, 3, 8}, /* D27/PB0 */ + {GPIOB, TIMER3, 1, 4, 9}, /* D28/PB1 */ + {GPIOB, NULL, 10, 0, ADCx}, /* D29/PB10 */ + {GPIOB, NULL, 11, 0, ADCx}, /* D30/PB11 */ + {GPIOB, NULL, 12, 0, ADCx}, /* D31/PB12 */ + {GPIOB, NULL, 13, 0, ADCx}, /* D32/PB13 */ + {GPIOB, NULL, 14, 0, ADCx}, /* D33/PB14 */ + {GPIOB, NULL, 15, 0, ADCx}, /* D34/PB15 */ + {GPIOC, NULL, 6, 0, ADCx}, /* D35/PC6 */ + {GPIOC, NULL, 7, 0, ADCx}, /* D36/PC7 */ + {GPIOC, NULL, 8, 0, ADCx}, /* D37/PC8 */ + {GPIOC, NULL, 9, 0, ADCx} /* D38/PC9 (BUT) */ +}; + +#endif diff --git a/wirish/boards/maple.h b/wirish/boards/maple.h new file mode 100644 index 0000000..519698b --- /dev/null +++ b/wirish/boards/maple.h @@ -0,0 +1,59 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file maple.h + * @author Marti Bolivar + * @brief Private include file for Maple in boards.h + */ + +#include "wirish_types.h" + +#ifndef _BOARD_MAPLE_H_ +#define _BOARD_MAPLE_H_ + +#define CYCLES_PER_MICROSECOND 72 +#define SYSTICK_RELOAD_VAL 71999 /* takes a cycle to reload */ + +#define BOARD_BUTTON_PIN 38 +#define BOARD_LED_PIN 13 + +/* Number of USARTs/UARTs whose pins are broken out to headers */ +#define NR_USARTS 3 + +/* Default USART pin numbers (not considering AFIO remap) */ +#define BOARD_USART1_TX_PIN 7 +#define BOARD_USART1_RX_PIN 8 +#define BOARD_USART2_TX_PIN 1 +#define BOARD_USART2_RX_PIN 0 +#define BOARD_USART3_TX_PIN 29 +#define BOARD_USART3_RX_PIN 30 + +/* Total number of GPIO pins that are broken out to headers and + intended for general use. */ +#define NR_GPIO_PINS 39 + +#endif diff --git a/wirish/boards/maple_RET6.cpp b/wirish/boards/maple_RET6.cpp new file mode 100644 index 0000000..ae31ce3 --- /dev/null +++ b/wirish/boards/maple_RET6.cpp @@ -0,0 +1,88 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file maple_RET6.cpp + * @author Marti Bolivar + * @brief Maple RET6 Edition PIN_MAP and boardInit() + */ + +#include "maple_RET6.h" + +#ifdef BOARD_maple_RET6 + +void boardInit(void) { +} + +stm32_pin_info PIN_MAP[NR_GPIO_PINS] = { + {GPIOA, TIMER2, 3, 4, 3}, /* D0/PA3 */ + {GPIOA, TIMER2, 2, 3, 2}, /* D1/PA2 */ + {GPIOA, TIMER2, 0, 1, 0}, /* D2/PA0 */ + {GPIOA, TIMER2, 1, 2, 1}, /* D3/PA1 */ + {GPIOB, NULL, 5, 0, ADCx}, /* D4/PB5 */ + {GPIOB, TIMER4, 6, 1, ADCx}, /* D5/PB6 */ + {GPIOA, TIMER1, 8, 1, ADCx}, /* D6/PA8 */ + {GPIOA, TIMER1, 9, 2, ADCx}, /* D7/PA9 */ + {GPIOA, TIMER1, 10, 3, ADCx}, /* D8/PA10 */ + {GPIOB, TIMER4, 7, 2, ADCx}, /* D9/PB7 */ + {GPIOA, NULL, 4, 0, 4}, /* D10/PA4 */ + {GPIOA, TIMER3, 7, 2, 7}, /* D11/PA7 */ + {GPIOA, TIMER3, 6, 1, 6}, /* D12/PA6 */ + {GPIOA, NULL, 5, 0, 5}, /* D13/PA5 (LED) */ + {GPIOB, TIMER4, 8, 3, ADCx}, /* D14/PB8 */ + + /* Little header */ + + {GPIOC, NULL, 0, 0, 10}, /* D15/PC0 */ + {GPIOC, NULL, 1, 0, 11}, /* D16/PC1 */ + {GPIOC, NULL, 2, 0, 12}, /* D17/PC2 */ + {GPIOC, NULL, 3, 0, 13}, /* D18/PC3 */ + {GPIOC, NULL, 4, 0, 14}, /* D19/PC4 */ + {GPIOC, NULL, 5, 0, 15}, /* D20/PC5 */ + + /* External header */ + + {GPIOC, NULL, 13, 0, ADCx}, /* D21/PC13 */ + {GPIOC, NULL, 14, 0, ADCx}, /* D22/PC14 */ + {GPIOC, NULL, 15, 0, ADCx}, /* D23/PC15 */ + {GPIOB, TIMER4, 9, 4, ADCx}, /* D24/PB9 */ + {GPIOD, NULL, 2, 0, ADCx}, /* D25/PD2 */ + {GPIOC, NULL, 10, 0, ADCx}, /* D26/PC10 */ + {GPIOB, TIMER3, 0, 3, 8}, /* D27/PB0 */ + {GPIOB, TIMER3, 1, 4, 9}, /* D28/PB1 */ + {GPIOB, NULL, 10, 0, ADCx}, /* D29/PB10 */ + {GPIOB, NULL, 11, 0, ADCx}, /* D30/PB11 */ + {GPIOB, NULL, 12, 0, ADCx}, /* D31/PB12 */ + {GPIOB, NULL, 13, 0, ADCx}, /* D32/PB13 */ + {GPIOB, NULL, 14, 0, ADCx}, /* D33/PB14 */ + {GPIOB, NULL, 15, 0, ADCx}, /* D34/PB15 */ + {GPIOC, TIMER8, 6, 1, ADCx}, /* D35/PC6 */ + {GPIOC, TIMER8, 7, 2, ADCx}, /* D36/PC7 */ + {GPIOC, TIMER8, 8, 3, ADCx}, /* D37/PC8 */ + {GPIOC, TIMER8, 9, 4, ADCx} /* D38/PC9 (BUT) */ +}; + +#endif diff --git a/wirish/boards/maple_RET6.h b/wirish/boards/maple_RET6.h new file mode 100644 index 0000000..63510c0 --- /dev/null +++ b/wirish/boards/maple_RET6.h @@ -0,0 +1,61 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file maple_RET6.h + * @author Marti Bolivar + * @brief Private include file for Maple RET6 Edition in boards.h + * + * See maple.h for more information on these definitions. + */ + +#include "gpio.h" +#include "timer.h" + +#include "wirish_types.h" + +#ifndef _BOARDS_MAPLE_RET6_H_ +#define _BOARDS_MAPLE_RET6_H_ + +#define CYCLES_PER_MICROSECOND 72 +#define SYSTICK_RELOAD_VAL 71999 /* takes a cycle to reload */ + +#define BOARD_BUTTON_PIN 38 +#define BOARD_LED_PIN 13 + +/* Note: UART4 and UART5 have pins which aren't broken out :( */ +#define NR_USARTS 3 + +#define BOARD_USART1_TX_PIN 7 +#define BOARD_USART1_RX_PIN 8 +#define BOARD_USART2_TX_PIN 1 +#define BOARD_USART2_RX_PIN 0 +#define BOARD_USART3_TX_PIN 29 +#define BOARD_USART3_RX_PIN 30 + +#define NR_GPIO_PINS 39 + +#endif diff --git a/wirish/boards/maple_mini.cpp b/wirish/boards/maple_mini.cpp new file mode 100644 index 0000000..8c005cf --- /dev/null +++ b/wirish/boards/maple_mini.cpp @@ -0,0 +1,87 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file maple_mini.cpp + * @author Marti Bolivar + * @brief Maple Mini PIN_MAP and boardInit(). + */ + +#include "maple_mini.h" +#include "gpio.h" + +#ifdef BOARD_maple_mini + +/* Since we want the Serial Wire/JTAG pins as GPIOs, disable both SW + * and JTAG debug support */ +void boardInit(void) { + afio_mapr_swj_config(AFIO_MAPR_SWJ_NO_JTAG_NO_SW); +} + +stm32_pin_info PIN_MAP[NR_GPIO_PINS] = { + + /* Top header */ + + {GPIOB, NULL, 11, 0, ADCx}, /* D0/PB11 */ + {GPIOB, NULL, 10, 0, ADCx}, /* D1/PB10 */ + {GPIOB, NULL, 2, 0, ADCx}, /* D2/PB2 */ + {GPIOB, TIMER3, 0, 3, 8}, /* D3/PB0 */ + {GPIOA, TIMER3, 7, 2, 7}, /* D4/PA7 */ + {GPIOA, TIMER3, 6, 1, 6}, /* D5/PA6 */ + {GPIOA, NULL, 5, 0, 5}, /* D6/PA5 */ + {GPIOA, NULL, 4, 0, 4}, /* D7/PA4 */ + {GPIOA, TIMER2, 3, 4, 3}, /* D8/PA3 */ + {GPIOA, TIMER2, 2, 3, 2}, /* D9/PA2 */ + {GPIOA, TIMER2, 1, 2, 1}, /* D10/PA1 */ + {GPIOA, TIMER2, 0, 1, 0}, /* D11/PA0 */ + {GPIOC, NULL, 15, 0, ADCx}, /* D12/PC15 */ + {GPIOC, NULL, 14, 0, ADCx}, /* D13/PC14 */ + {GPIOC, NULL, 13, 0, ADCx}, /* D14/PC13 */ + + /* Bottom header */ + + {GPIOB, TIMER4, 7, 2, ADCx}, /* D15/PB7 */ + {GPIOB, TIMER4, 6, 1, ADCx}, /* D16/PB6 */ + {GPIOB, NULL, 5, 0, ADCx}, /* D17/PB5 */ + {GPIOB, NULL, 4, 0, ADCx}, /* D18/PB4 */ + {GPIOB, NULL, 3, 0, ADCx}, /* D19/PB3 */ + {GPIOA, NULL, 15, 0, ADCx}, /* D20/PA15 */ + {GPIOA, NULL, 14, 0, ADCx}, /* D21/PA14 */ + {GPIOA, NULL, 13, 0, ADCx}, /* D22/PA13 */ + {GPIOA, NULL, 12, 0, ADCx}, /* D23/PA12 */ + {GPIOA, TIMER1, 11, 4, ADCx}, /* D24/PA11 */ + {GPIOA, TIMER1, 10, 3, ADCx}, /* D25/PA10 */ + {GPIOA, TIMER2, 9, 2, ADCx}, /* D26/PA9 */ + {GPIOA, TIMER1, 8, 1, ADCx}, /* D27/PA8 */ + {GPIOB, NULL, 15, 0, ADCx}, /* D28/PB15 */ + {GPIOB, NULL, 14, 0, ADCx}, /* D29/PB14 */ + {GPIOB, NULL, 13, 0, ADCx}, /* D30/PB13 */ + {GPIOB, NULL, 12, 0, ADCx}, /* D31/PB12 */ + {GPIOB, TIMER4, 8, 3, ADCx}, /* D32/PB8 */ + {GPIOB, TIMER3, 1, 4, 9}, /* D33/PB1 */ +}; + +#endif diff --git a/wirish/boards/maple_mini.h b/wirish/boards/maple_mini.h new file mode 100644 index 0000000..bfb92a5 --- /dev/null +++ b/wirish/boards/maple_mini.h @@ -0,0 +1,60 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file maple_mini.h + * @author Marti Bolivar + * @brief Private include file for Maple Mini in boards.h + * + * See maple.h for more information on these definitions. + */ + +#include "gpio.h" +#include "timer.h" + +#include "wirish_types.h" + +#ifndef _BOARD_MAPLE_MINI_H_ +#define _BOARD_MAPLE_MINI_H_ + +#define CYCLES_PER_MICROSECOND 72 +#define SYSTICK_RELOAD_VAL 71999 /* takes a cycle to reload */ + +#define BOARD_BUTTON_PIN 32 +#define BOARD_LED_PIN 33 + +#define NR_USARTS 3 + +#define BOARD_USART1_TX_PIN 26 +#define BOARD_USART1_RX_PIN 25 +#define BOARD_USART2_TX_PIN 9 +#define BOARD_USART2_RX_PIN 8 +#define BOARD_USART3_TX_PIN 1 +#define BOARD_USART3_RX_PIN 0 + +#define NR_GPIO_PINS 34 + +#endif diff --git a/wirish/boards/maple_native.cpp b/wirish/boards/maple_native.cpp new file mode 100644 index 0000000..c04e98f --- /dev/null +++ b/wirish/boards/maple_native.cpp @@ -0,0 +1,155 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file maple_native.cpp + * @author Marti Bolivar + * @brief Maple Native PIN_MAP and boardInit(). + */ + +#include "maple_native.h" +#include "native_sram.h" + +#ifdef BOARD_maple_native + +void boardInit(void) { + initNativeSRAM(); +} + +stm32_pin_info PIN_MAP[NR_GPIO_PINS] = { + + /* Top header */ + + {GPIOB, NULL, 10, 0, ADCx}, /* D0/PB10 */ + {GPIOB, NULL, 2, 0, ADCx}, /* D1/PB2 */ + {GPIOB, NULL, 12, 0, ADCx}, /* D2/PB12 */ + {GPIOB, NULL, 13, 0, ADCx}, /* D3/PB13 */ + {GPIOB, NULL, 14, 0, ADCx}, /* D4/PB14 */ + {GPIOB, NULL, 15, 0, ADCx}, /* D5/PB15 */ + {GPIOC, NULL, 0, 0, 10}, /* D6/PC0 */ + {GPIOC, NULL, 1, 0, 11}, /* D7/PC1 */ + {GPIOC, NULL, 2, 0, 12}, /* D8/PC2 */ + {GPIOC, NULL, 3, 0, 13}, /* D9/PC3 */ + {GPIOC, NULL, 4, 0, 14}, /* D10/PC4 */ + {GPIOC, NULL, 5, 0, 15}, /* D11/PC5 */ + {GPIOC, TIMER8, 6, 1, ADCx}, /* D12/PC6 */ + {GPIOC, TIMER8, 7, 2, ADCx}, /* D13/PC7 */ + {GPIOC, TIMER8, 8, 3, ADCx}, /* D14/PC8 */ + {GPIOC, TIMER8, 9, 4, ADCx}, /* D15/PC9 */ + {GPIOC, NULL, 10, 0, ADCx}, /* D16/PC10 */ + {GPIOC, NULL, 11, 0, ADCx}, /* D17/PC11 */ + {GPIOC, NULL, 12, 0, ADCx}, /* D18/PC12 */ + {GPIOC, NULL, 13, 0, ADCx}, /* D19/PC13 */ + {GPIOC, NULL, 14, 0, ADCx}, /* D20/PC14 */ + {GPIOC, NULL, 15, 0, ADCx}, /* D21/PC15 */ + {GPIOA, TIMER1, 8, 1, ADCx}, /* D22/PA8 */ + {GPIOA, TIMER1, 9, 2, ADCx}, /* D23/PA9 */ + {GPIOA, TIMER1, 10, 3, ADCx}, /* D24/PA10 */ + {GPIOB, TIMER4, 9, 4, ADCx}, /* D25/PB9 */ + + /* Bottom header */ + /* FIXME (?) What about D48--D50 also being TIMER2_CH[234]? */ + + {GPIOD, NULL, 2, 0, ADCx}, /* D26/PD2 */ + {GPIOD, NULL, 3, 0, ADCx}, /* D27/PD3 */ + {GPIOD, NULL, 6, 0, ADCx}, /* D28/PD6 */ + {GPIOG, NULL, 11, 0, ADCx}, /* D29/PG11 */ + {GPIOG, NULL, 12, 0, ADCx}, /* D30/PG12 */ + {GPIOG, NULL, 13, 0, ADCx}, /* D31/PG13 */ + {GPIOG, NULL, 14, 0, ADCx}, /* D32/PG14 */ + {GPIOG, NULL, 8, 0, ADCx}, /* D33/PG8 */ + {GPIOG, NULL, 7, 0, ADCx}, /* D34/PG7 */ + {GPIOG, NULL, 6, 0, ADCx}, /* D35/PG6 */ + {GPIOB, NULL, 5, 0, ADCx}, /* D36/PB5 */ + {GPIOB, TIMER4, 6, 1, ADCx}, /* D37/PB6 */ + {GPIOB, TIMER4, 7, 2, ADCx}, /* D38/PB7 */ + {GPIOF, NULL, 6, 0, 4}, /* D39/PF6 */ + {GPIOF, NULL, 7, 0, 5}, /* D40/PF7 */ + {GPIOF, NULL, 8, 0, 6}, /* D41/PF8 */ + {GPIOF, NULL, 9, 0, 7}, /* D42/PF9 */ + {GPIOF, NULL, 10, 0, 8}, /* D43/PF10 */ + {GPIOF, NULL, 11, 0, ADCx}, /* D44/PF11 */ + {GPIOB, TIMER3, 1, 4, 9}, /* D45/PB1 */ + {GPIOB, TIMER3, 0, 3, 8}, /* D46/PB0 */ + {GPIOA, TIMER5, 0, 1, 0}, /* D47/PA0 */ + {GPIOA, TIMER5, 1, 2, 1}, /* D48/PA1 */ + {GPIOA, TIMER5, 2, 3, 2}, /* D49/PA2 */ + {GPIOA, TIMER5, 3, 4, 3}, /* D50/PA3 */ + {GPIOA, NULL, 4, 0, 4}, /* D51/PA4 */ + {GPIOA, NULL, 5, 0, 5}, /* D52/PA5 */ + {GPIOA, TIMER3, 6, 1, 6}, /* D53/PA6 */ + {GPIOA, TIMER3, 7, 2, 7}, /* D54/PA7 */ + + /* Right (triple) header */ + + {GPIOF, NULL, 0, 0, ADCx}, /* D55/PF0 */ + {GPIOD, NULL, 11, 0, ADCx}, /* D56/PD11 */ + {GPIOD, NULL, 14, 0, ADCx}, /* D57/PD14 */ + {GPIOF, NULL, 1, 0, ADCx}, /* D58/PF1 */ + {GPIOD, NULL, 12, 0, ADCx}, /* D59/PD12 */ + {GPIOD, NULL, 15, 0, ADCx}, /* D60/PD15 */ + {GPIOF, NULL, 2, 0, ADCx}, /* D61/PF2 */ + {GPIOD, NULL, 13, 0, ADCx}, /* D62/PD13 */ + {GPIOD, NULL, 0, 0, ADCx}, /* D63/PD0 */ + {GPIOF, NULL, 3, 0, ADCx}, /* D64/PF3 */ + {GPIOE, NULL, 3, 0, ADCx}, /* D65/PE3 */ + {GPIOD, NULL, 1, 0, ADCx}, /* D66/PD1 */ + {GPIOF, NULL, 4, 0, ADCx}, /* D67/PF4 */ + {GPIOE, NULL, 4, 0, ADCx}, /* D68/PE4 */ + {GPIOE, NULL, 7, 0, ADCx}, /* D69/PE7 */ + {GPIOF, NULL, 5, 0, ADCx}, /* D70/PF5 */ + {GPIOE, NULL, 5, 0, ADCx}, /* D71/PE5 */ + {GPIOE, NULL, 8, 0, ADCx}, /* D72/PE8 */ + {GPIOF, NULL, 12, 0, ADCx}, /* D73/PF12 */ + {GPIOE, NULL, 6, 0, ADCx}, /* D74/PE6 */ + {GPIOE, NULL, 9, 0, ADCx}, /* D75/PE9 */ + {GPIOF, NULL, 13, 0, ADCx}, /* D76/PF13 */ + {GPIOE, NULL, 10, 0, ADCx}, /* D77/PE10 */ + {GPIOF, NULL, 14, 0, ADCx}, /* D78/PF14 */ + {GPIOG, NULL, 9, 0, ADCx}, /* D79/PG9 */ + {GPIOE, NULL, 11, 0, ADCx}, /* D80/PE11 */ + {GPIOF, NULL, 15, 0, ADCx}, /* D81/PF15 */ + {GPIOG, NULL, 10, 0, ADCx}, /* D82/PG10 */ + {GPIOE, NULL, 12, 0, ADCx}, /* D83/PE12 */ + {GPIOG, NULL, 0, 0, ADCx}, /* D84/PG0 */ + {GPIOD, NULL, 5, 0, ADCx}, /* D85/PD5 */ + {GPIOE, NULL, 13, 0, ADCx}, /* D86/PE13 */ + {GPIOG, NULL, 1, 0, ADCx}, /* D87/PG1 */ + {GPIOD, NULL, 4, 0, ADCx}, /* D88/PD4 */ + {GPIOE, NULL, 14, 0, ADCx}, /* D89/PE14 */ + {GPIOG, NULL, 2, 0, ADCx}, /* D90/PG2 */ + {GPIOE, NULL, 1, 0, ADCx}, /* D91/PE1 */ + {GPIOE, NULL, 15, 0, ADCx}, /* D92/PE15 */ + {GPIOG, NULL, 3, 0, ADCx}, /* D93/PG3 */ + {GPIOE, NULL, 0, 0, ADCx}, /* D94/PE0 */ + {GPIOD, NULL, 8, 0, ADCx}, /* D95/PD8 */ + {GPIOG, NULL, 4, 0, ADCx}, /* D96/PG4 */ + {GPIOD, NULL, 9, 0, ADCx}, /* D97/PD9 */ + {GPIOG, NULL, 5, 0, ADCx}, /* D98/PG5 */ + {GPIOD, NULL, 10, 0, ADCx} /* D99/PD10 */ +}; + +#endif diff --git a/wirish/boards/maple_native.h b/wirish/boards/maple_native.h new file mode 100644 index 0000000..21fc480 --- /dev/null +++ b/wirish/boards/maple_native.h @@ -0,0 +1,64 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file maple_native.h + * @author Marti Bolivar + * @brief Private include file for Maple Native in boards.h + * + * See maple.h for more information on these definitions. + */ + +#include "gpio.h" +#include "timer.h" + +#include "wirish_types.h" + +#ifndef _BOARD_MAPLE_NATIVE_H_ +#define _BOARD_MAPLE_NATIVE_H_ + +#define CYCLES_PER_MICROSECOND 72 +#define SYSTICK_RELOAD_VAL 71999 + +#define BOARD_LED_PIN D21 +#define BOARD_BUTTON_PIN D18 + +#define NR_USARTS 5 + +#define BOARD_USART1_TX_PIN 25 +#define BOARD_USART1_RX_PIN 26 +#define BOARD_USART2_TX_PIN 51 +#define BOARD_USART2_RX_PIN 52 +#define BOARD_USART3_TX_PIN 0 +#define BOARD_USART3_RX_PIN 1 +#define BOARD_UART4_TX_PIN 18 +#define BOARD_UART4_RX_PIN 19 +#define BOARD_UART5_TX_PIN 20 +#define BOARD_UART5_RX_PIN 28 + +#define NR_GPIO_PINS 100 + +#endif diff --git a/wirish/ext_interrupts.cpp b/wirish/ext_interrupts.cpp index 5b32b05..060994f 100644 --- a/wirish/ext_interrupts.cpp +++ b/wirish/ext_interrupts.cpp @@ -49,8 +49,8 @@ void attachInterrupt(uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode) { exti_trigger_mode outMode = exti_out_mode(mode); - exti_attach_interrupt((afio_exti_num)(PIN_MAP[pin].pin), - PIN_MAP[pin].ext_port, + exti_attach_interrupt((afio_exti_num)(PIN_MAP[pin].gpio_pin), + gpio_exti_port(PIN_MAP[pin].gpio_device), handler, outMode); } @@ -64,7 +64,7 @@ void detachInterrupt(uint8 pin) { return; } - exti_detach_interrupt((afio_exti_num)(PIN_MAP[pin].pin)); + exti_detach_interrupt((afio_exti_num)(PIN_MAP[pin].gpio_pin)); } static inline exti_trigger_mode exti_out_mode(ExtIntTriggerMode mode) { diff --git a/wirish/rules.mk b/wirish/rules.mk index d250cb9..c1d59bc 100644 --- a/wirish/rules.mk +++ b/wirish/rules.mk @@ -4,8 +4,9 @@ dirstack_$(sp) := $(d) d := $(dir) BUILDDIRS += $(BUILD_PATH)/$(d) BUILDDIRS += $(BUILD_PATH)/$(d)/comm +BUILDDIRS += $(BUILD_PATH)/$(d)/boards -WIRISH_INCLUDES := -I$(d) -I$(d)/comm +WIRISH_INCLUDES := -I$(d) -I$(d)/comm -I$(d)/boards # Local flags CFLAGS_$(d) := $(WIRISH_INCLUDES) $(LIBMAPLE_INCLUDES) @@ -15,6 +16,10 @@ cSRCS_$(d) := cppSRCS_$(d) := wirish_math.cpp \ Print.cpp \ + boards/maple.cpp \ + boards/maple_mini.cpp \ + boards/maple_native.cpp \ + boards/maple_RET6.cpp \ comm/HardwareSerial.cpp \ comm/HardwareSPI.cpp \ usb_serial.cpp \ @@ -27,9 +32,8 @@ cppSRCS_$(d) := wirish_math.cpp \ ext_interrupts.cpp \ wirish_digital.cpp \ native_sram.cpp \ - boards.cpp -cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%) +cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%) cppFILES_$(d) := $(cppSRCS_$(d):%=$(d)/%) OBJS_$(d) := $(cFILES_$(d):%.c=$(BUILD_PATH)/%.o) \ diff --git a/wirish/wirish.cpp b/wirish/wirish.cpp index 6dcb1b5..aeed089 100644 --- a/wirish/wirish.cpp +++ b/wirish/wirish.cpp @@ -59,8 +59,7 @@ void init(void) { setupADC(); setupTimers(); setupUSB(); - - BOARD_INIT; + boardInit(); } static void setupFlash(void) { diff --git a/wirish/wirish.h b/wirish/wirish.h index 319df97..13b14b6 100644 --- a/wirish/wirish.h +++ b/wirish/wirish.h @@ -33,6 +33,7 @@ #include "libmaple.h" +#include "wirish_types.h" #include "boards.h" #include "io.h" #include "bits.h" diff --git a/wirish/wirish_analog.cpp b/wirish/wirish_analog.cpp index a658184..9e99aa5 100644 --- a/wirish/wirish_analog.cpp +++ b/wirish/wirish_analog.cpp @@ -33,7 +33,7 @@ /* Assumes that the ADC has been initialized and that the pin is set * to ANALOG_INPUT */ uint32 analogRead(uint8 pin) { - if(PIN_MAP[pin].adc_channel == ADC_INVALID) { + if(PIN_MAP[pin].adc_channel == ADCx) { return 0; } diff --git a/wirish/wirish_digital.cpp b/wirish/wirish_digital.cpp index 4b68861..278cf10 100644 --- a/wirish/wirish_digital.cpp +++ b/wirish/wirish_digital.cpp @@ -70,7 +70,7 @@ void pinMode(uint8 pin, WiringPinMode mode) { return; } - gpio_set_mode(PIN_MAP[pin].gpio_device, PIN_MAP[pin].pin, outputMode); + gpio_set_mode(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_pin, outputMode); if (PIN_MAP[pin].timer_device != NULL) { /* enable/disable timer channels if we're switching into or @@ -93,7 +93,7 @@ uint32 digitalRead(uint8 pin) { return 0; } - return gpio_read_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].pin) ? + return gpio_read_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_pin) ? HIGH : LOW; } @@ -102,7 +102,7 @@ void digitalWrite(uint8 pin, uint8 val) { return; } - gpio_write_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].pin, val); + gpio_write_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_pin, val); } void togglePin(uint8 pin) { @@ -110,7 +110,7 @@ void togglePin(uint8 pin) { return; } - gpio_toggle_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].pin); + gpio_toggle_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_pin); } uint8 isButtonPressed() { diff --git a/wirish/wirish_types.h b/wirish/wirish_types.h new file mode 100644 index 0000000..84591ea --- /dev/null +++ b/wirish/wirish_types.h @@ -0,0 +1,51 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file wirish_types.h + * @author Marti Bolivar + * @brief Wirish library type definitions. + */ + +#include "gpio.h" +#include "timer.h" + +#ifndef _WIRISH_TYPES_H_ +#define _WIRISH_TYPES_H_ + +/** Stores STM32-specific information related to a given pin. */ +typedef struct stm32_pin_info { + gpio_dev *gpio_device; /**< Maple pin's GPIO device */ + timer_dev *timer_device; /**< Maple pin's timer device, or NULL if none. */ + uint8 gpio_pin; /**< GPIO pin */ + uint8 timer_chan; /**< Timer channel, or 0 if none. */ + uint8 adc_channel; /**< Pin ADC channel, or ADCx if none. */ +} stm32_pin_info; + +/** Invalid adc_channel value */ +#define ADCx 0xFF + +#endif -- cgit v1.2.3 From f8081eeb04c9cb511adaf58e201c7cfbe1ddfbd4 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Fri, 25 Mar 2011 20:09:30 -0400 Subject: Final stm32_pin_info design candidate; ADC3 support on Native. Added an adc_dev to struct stm32_pin_info. This was necessary to add support for the channels on the Native which are only connected to ADC3, but it does add a bunch of NULLs to the PIN_MAPs. I don't think any other peripherals need representation on a per-pin basis. Each peripheral library will be responsible for keeping track of related GPIO ports and bits, and we can throw #defines in to boards/*.h for other things (e.g. BOARD_SPI1_MISO_PIN). Fleshed out the ADC refactor and brought it more in keeping with the new design as it evolves. A couple of other tweaks. Notably: waitForButtonPress() now takes a default argument meaning "wait forever". Removed Maple-specific documentation from core functions in io.h; this information will need to go into the individual board docs files. --- examples/test-session.cpp | 50 ++++--- libmaple/adc.c | 65 ++++++--- libmaple/adc.h | 294 +++++++++++++++++++++++++++++---------- libmaple/timer.c | 4 +- notes/coding_standard.txt | 44 ++++++ notes/native-pin-definitions.txt | 201 -------------------------- notes/pin-definitions.txt | 201 ++++++++++++++++++++++++++ wirish/boards.cpp | 145 +++++++++++++++++++ wirish/boards.h | 16 ++- wirish/boards/maple.cpp | 78 +++++------ wirish/boards/maple_RET6.cpp | 81 +++++------ wirish/boards/maple_mini.cpp | 68 ++++----- wirish/boards/maple_native.cpp | 202 +++++++++++++-------------- wirish/ext_interrupts.cpp | 4 +- wirish/io.h | 33 ++--- wirish/pwm.cpp | 2 +- wirish/rules.mk | 4 +- wirish/wirish.cpp | 128 ----------------- wirish/wirish.h | 2 - wirish/wirish_analog.cpp | 9 +- wirish/wirish_digital.cpp | 28 ++-- wirish/wirish_types.h | 26 ++-- 22 files changed, 967 insertions(+), 718 deletions(-) delete mode 100644 notes/native-pin-definitions.txt create mode 100644 notes/pin-definitions.txt create mode 100644 wirish/boards.cpp delete mode 100644 wirish/wirish.cpp diff --git a/examples/test-session.cpp b/examples/test-session.cpp index 28c02f3..110b219 100644 --- a/examples/test-session.cpp +++ b/examples/test-session.cpp @@ -27,16 +27,13 @@ const uint8 adc_pins[] = #elif defined(BOARD_maple_mini) const uint8 pwm_pins[] = {3, 4, 5, 8, 9, 10, 11, 15, 16, 25, 26, 27}; -const uint8 adc_pins[] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 33}; // NB: 33 is LED +const uint8 adc_pins[] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 33}; #elif defined(BOARD_maple_native) const uint8 pwm_pins[] = {12, 13, 14, 15, 22, 23, 24, 25, 37, 38, 45, 46, 47, 48, 49, 50, 53, 54}; -const uint8 adc_pins[] = {6, 7, 8, 9, 10, 11, - /* the following are on ADC3, which lacks support: - 39, 40, 41, 42, 43, 45, */ +const uint8 adc_pins[] = {6, 7, 8, 9, 10, 11, 39, 40, 41, 42, 43, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54}; - #else #error "Board type has not been selected correctly" @@ -351,21 +348,34 @@ void cmd_everything(void) { // TODO void fast_gpio(int maple_pin) { gpio_dev *dev = PIN_MAP[maple_pin].gpio_device; - uint32 pin = PIN_MAP[maple_pin].gpio_pin; - - gpio_write_bit(dev, pin, 1); gpio_write_bit(dev, pin, 0); - gpio_write_bit(dev, pin, 1); gpio_write_bit(dev, pin, 0); - gpio_write_bit(dev, pin, 1); gpio_write_bit(dev, pin, 0); - gpio_write_bit(dev, pin, 1); gpio_write_bit(dev, pin, 0); - gpio_write_bit(dev, pin, 1); gpio_write_bit(dev, pin, 0); - gpio_write_bit(dev, pin, 1); gpio_write_bit(dev, pin, 0); - gpio_write_bit(dev, pin, 1); gpio_write_bit(dev, pin, 0); - gpio_write_bit(dev, pin, 1); gpio_write_bit(dev, pin, 0); - gpio_write_bit(dev, pin, 1); gpio_write_bit(dev, pin, 0); - gpio_write_bit(dev, pin, 1); gpio_write_bit(dev, pin, 0); - gpio_write_bit(dev, pin, 1); gpio_write_bit(dev, pin, 0); - gpio_write_bit(dev, pin, 1); gpio_write_bit(dev, pin, 0); - gpio_write_bit(dev, pin, 1); gpio_write_bit(dev, pin, 0); + uint32 bit = PIN_MAP[maple_pin].gpio_bit; + + gpio_write_bit(dev, bit, 1); + gpio_toggle_bit(dev, bit); + gpio_toggle_bit(dev, bit); + gpio_toggle_bit(dev, bit); + gpio_toggle_bit(dev, bit); + gpio_toggle_bit(dev, bit); + gpio_toggle_bit(dev, bit); + gpio_toggle_bit(dev, bit); + gpio_toggle_bit(dev, bit); + gpio_toggle_bit(dev, bit); + gpio_toggle_bit(dev, bit); + gpio_toggle_bit(dev, bit); + gpio_toggle_bit(dev, bit); + gpio_toggle_bit(dev, bit); + gpio_toggle_bit(dev, bit); + gpio_toggle_bit(dev, bit); + gpio_toggle_bit(dev, bit); + gpio_toggle_bit(dev, bit); + gpio_toggle_bit(dev, bit); + gpio_toggle_bit(dev, bit); + gpio_toggle_bit(dev, bit); + gpio_toggle_bit(dev, bit); + gpio_toggle_bit(dev, bit); + gpio_toggle_bit(dev, bit); + gpio_toggle_bit(dev, bit); + gpio_toggle_bit(dev, bit); } void cmd_serial1_serial3(void) { diff --git a/libmaple/adc.c b/libmaple/adc.c index 3d38596..73dce0a 100644 --- a/libmaple/adc.c +++ b/libmaple/adc.c @@ -59,43 +59,44 @@ adc_dev adc3 = { const adc_dev *ADC3 = &adc3; #endif -static void adc_calibrate(const adc_dev *dev); - /** - * @brief Initialize an ADC peripheral. Only supports software triggered - * conversions. + * @brief Initialize an ADC peripheral. + * + * Initializes the RCC clock line for the given peripheral, using ADC + * prescaler RCC_ADCPRE_PCLK_DIV_6. Resets ADC device registers. + * * @param dev ADC peripheral to initialize - * @param flags unused */ -void adc_init(const adc_dev *dev, uint32 flags) { - /* Spin up the clocks */ +void adc_init(const adc_dev *dev) { rcc_set_prescaler(RCC_PRESCALER_ADC, RCC_ADCPRE_PCLK_DIV_6); rcc_clk_enable(dev->clk_id); rcc_reset_dev(dev->clk_id); - - /* Software triggers conversions, conversion on external events */ - adc_set_extsel(dev, 7); - adc_set_exttrig(dev, 1); - - /* Enable the ADC */ - adc_enable(dev); - - /* Calibrate ADC */ - adc_calibrate(dev); } /** * @brief Set external event select for regular group - * @param dev adc device - * @param trigger event to select. See ADC_CR2 EXTSEL[2:0] bits. + * @param dev ADC device + * @param event Event used to trigger the start of conversion. + * @see adc_extsel_event */ -void adc_set_extsel(const adc_dev *dev, uint8 trigger) { +void adc_set_extsel(const adc_dev *dev, adc_extsel_event event) { uint32 cr2 = dev->regs->CR2; cr2 &= ~ADC_CR2_EXTSEL; - cr2 |= (trigger & 0x7) << 17; + cr2 |= event; dev->regs->CR2 = cr2; } +/** + * @brief Call a function on all ADC devices. + * @param fn Function to call on each ADC device. + */ +void adc_foreach(void (*fn)(const adc_dev*)) { + fn(ADC1); + fn(ADC2); +#ifdef STM32_HIGH_DENSITY + fn(ADC3); +#endif +} /** * @brief Turn the given sample rate into values for ADC_SMPRx. Don't @@ -125,7 +126,7 @@ void adc_set_sample_rate(const adc_dev *dev, adc_smp_rate smp_rate) { * @brief Calibrate an ADC peripheral * @param dev adc device */ -static void adc_calibrate(const adc_dev *dev) { +void adc_calibrate(const adc_dev *dev) { __io uint32 *rstcal_bit = bb_perip(&(dev->regs->CR2), 3); __io uint32 *cal_bit = bb_perip(&(dev->regs->CR2), 2); @@ -137,3 +138,23 @@ static void adc_calibrate(const adc_dev *dev) { while (*cal_bit) ; } + +/** + * @brief Perform a single synchronous software triggered conversion on a + * channel. + * @param dev ADC device to use for reading. + * @param channel channel to convert + * @return conversion result + */ +uint16 adc_read(const adc_dev *dev, uint8 channel) { + adc_reg_map *regs = dev->regs; + + adc_set_reg_seqlen(dev, 1); + + regs->SQR3 = channel; + regs->CR2 |= ADC_CR2_SWSTART; + while(!(regs->SR & ADC_SR_EOC)) + ; + + return (uint16)(regs->DR & ADC_DR_DATA); +} diff --git a/libmaple/adc.h b/libmaple/adc.h index 53ef032..520b982 100644 --- a/libmaple/adc.h +++ b/libmaple/adc.h @@ -79,103 +79,253 @@ extern const adc_dev *ADC3; #endif /* - * ADC peripheral base addresses + * Register map base pointers */ /** ADC1 register map base pointer. */ -#define ADC1_BASE ((adc_reg_map*)0x40012400) +#define ADC1_BASE ((adc_reg_map*)0x40012400) /** ADC2 register map base pointer. */ -#define ADC2_BASE ((adc_reg_map*)0x40012800) +#define ADC2_BASE ((adc_reg_map*)0x40012800) /** ADC3 register map base pointer. */ -#define ADC3_BASE ((adc_reg_map*)0x40013C00) +#define ADC3_BASE ((adc_reg_map*)0x40013C00) /* * Register bit definitions */ /* Status register */ -#define ADC_SR_AWD BIT(0) -#define ADC_SR_EOC BIT(1) -#define ADC_SR_JEOC BIT(2) -#define ADC_SR_JSTRT BIT(3) -#define ADC_SR_STRT BIT(4) + +#define ADC_SR_AWD_BIT 0 +#define ADC_SR_EOC_BIT 1 +#define ADC_SR_JEOC_BIT 2 +#define ADC_SR_JSTRT_BIT 3 +#define ADC_SR_STRT_BIT 4 + +#define ADC_SR_AWD BIT(ADC_SR_AWD_BIT) +#define ADC_SR_EOC BIT(ADC_SR_EOC_BIT) +#define ADC_SR_JEOC BIT(ADC_SR_JEOC_BIT) +#define ADC_SR_JSTRT BIT(ADC_SR_JSTRT_BIT) +#define ADC_SR_STRT BIT(ADC_SR_STRT_BIT) /* Control register 1 */ -#define ADC_CR1_AWDCH (0x1F) -#define ADC_CR1_EOCIE BIT(5) -#define ADC_CR1_AWDIE BIT(6) -#define ADC_CR1_JEOCIE BIT(7) -#define ADC_CR1_SCAN BIT(8) -#define ADC_CR1_AWDSGL BIT(9) -#define ADC_CR1_JAUTO BIT(10) -#define ADC_CR1_DISCEN BIT(11) -#define ADC_CR1_JDISCEN BIT(12) -#define ADC_CR1_DISCNUM (0xE000) -#define ADC_CR1_JAWDEN BIT(22) -#define ADC_CR1_AWDEN BIT(23) + +#define ADC_CR1_EOCIE_BIT 5 +#define ADC_CR1_AWDIE_BIT 6 +#define ADC_CR1_JEOCIE_BIT 7 +#define ADC_CR1_SCAN_BIT 8 +#define ADC_CR1_AWDSGL_BIT 9 +#define ADC_CR1_JAUTO_BIT 10 +#define ADC_CR1_DISCEN_BIT 11 +#define ADC_CR1_JDISCEN_BIT 12 +#define ADC_CR1_JAWDEN_BIT 22 +#define ADC_CR1_AWDEN_BIT 23 + +#define ADC_CR1_AWDCH (0x1F) +#define ADC_CR1_EOCIE BIT(ADC_CR1_EOCIE_BIT) +#define ADC_CR1_AWDIE BIT(ADC_CR1_AWDIE_BIT) +#define ADC_CR1_JEOCIE BIT(ADC_CR1_JEOCIE_BIT) +#define ADC_CR1_SCAN BIT(ADC_CR1_SCAN_BIT) +#define ADC_CR1_AWDSGL BIT(ADC_CR1_AWDSGL_BIT) +#define ADC_CR1_JAUTO BIT(ADC_CR1_JAUTO_BIT) +#define ADC_CR1_DISCEN BIT(ADC_CR1_DISCEN_BIT) +#define ADC_CR1_JDISCEN BIT(ADC_CR1_JDISCEN_BIT) +#define ADC_CR1_DISCNUM (0xE000) +#define ADC_CR1_JAWDEN BIT(ADC_CR1_JAWDEN_BIT) +#define ADC_CR1_AWDEN BIT(ADC_CR1_AWDEN_BIT) /* Control register 2 */ -#define ADC_CR2_ADON BIT(0) -#define ADC_CR2_CONT BIT(1) -#define ADC_CR2_CAL BIT(2) -#define ADC_CR2_RSTCAL BIT(3) -#define ADC_CR2_DMA BIT(8) -#define ADC_CR2_ALIGN BIT(11) -#define ADC_CR2_JEXTSEL (0x7000) -#define ADC_CR2_JEXTTRIG BIT(15) -#define ADC_CR2_EXTSEL (0xE0000) -#define ADC_CR2_EXTTRIG BIT(20) -#define ADC_CR2_JSWSTART BIT(21) -#define ADC_CR2_SWSTART BIT(22) -#define ADC_CR2_TSEREFE BIT(23) - -void adc_init(const adc_dev *dev, uint32 flags); -void adc_set_extsel(const adc_dev *dev, uint8 trigger); -/** ADC per-sample conversion times, in ADC clock cycles */ -typedef enum { - ADC_SMPR_1_5, ///< 1.5 ADC cycles - ADC_SMPR_7_5, ///< 7.5 ADC cycles - ADC_SMPR_13_5, ///< 13.5 ADC cycles - ADC_SMPR_28_5, ///< 28.5 ADC cycles - ADC_SMPR_41_5, ///< 41.5 ADC cycles - ADC_SMPR_55_5, ///< 55.5 ADC cycles - ADC_SMPR_71_5, ///< 71.5 ADC cycles - ADC_SMPR_239_5 ///< 239.5 ADC cycles -} adc_smp_rate; +#define ADC_CR2_ADON_BIT 0 +#define ADC_CR2_CONT_BIT 1 +#define ADC_CR2_CAL_BIT 2 +#define ADC_CR2_RSTCAL_BIT 3 +#define ADC_CR2_DMA_BIT 8 +#define ADC_CR2_ALIGN_BIT 11 +#define ADC_CR2_JEXTTRIG_BIT 15 +#define ADC_CR2_EXTTRIG_BIT 20 +#define ADC_CR2_JSWSTART_BIT 21 +#define ADC_CR2_SWSTART_BIT 22 +#define ADC_CR2_TSEREFE_BIT 23 -void adc_set_sample_rate(const adc_dev *dev, adc_smp_rate smp_rate); +#define ADC_CR2_ADON BIT(ADC_CR2_ADON_BIT) +#define ADC_CR2_CONT BIT(ADC_CR2_CONT_BIT) +#define ADC_CR2_CAL BIT(ADC_CR2_CAL_BIT) +#define ADC_CR2_RSTCAL BIT(ADC_CR2_RSTCAL_BIT) +#define ADC_CR2_DMA BIT(ADC_CR2_DMA_BIT) +#define ADC_CR2_ALIGN BIT(ADC_CR2_ALIGN_BIT) +#define ADC_CR2_JEXTSEL (0x7000) +#define ADC_CR2_JEXTTRIG BIT(ADC_CR2_JEXTTRIG_BIT) +#define ADC_CR2_EXTSEL (0xE0000) +#define ADC_CR2_EXTTRIG BIT(ADC_CR2_EXTTRIG_BIT) +#define ADC_CR2_JSWSTART BIT(ADC_CR2_JSWSTART_BIT) +#define ADC_CR2_SWSTART BIT(ADC_CR2_SWSTART_BIT) +#define ADC_CR2_TSEREFE BIT(ADC_CR2_TSEREFE_BIT) + +/* Sample time register 1 */ + +#define ADC_SMPR1_SMP17 (0x7 << 21) +#define ADC_SMPR1_SMP16 (0x7 << 18) +#define ADC_SMPR1_SMP15 (0x7 << 15) +#define ADC_SMPR1_SMP14 (0x7 << 12) +#define ADC_SMPR1_SMP13 (0x7 << 9) +#define ADC_SMPR1_SMP12 (0x7 << 6) +#define ADC_SMPR1_SMP11 (0x7 << 3) +#define ADC_SMPR1_SMP10 0x7 + +/* Sample time register 2 */ + +#define ADC_SMPR2_SMP9 (0x7 << 27) +#define ADC_SMPR2_SMP8 (0x7 << 24) +#define ADC_SMPR2_SMP7 (0x7 << 21) +#define ADC_SMPR2_SMP6 (0x7 << 18) +#define ADC_SMPR2_SMP5 (0x7 << 15) +#define ADC_SMPR2_SMP4 (0x7 << 12) +#define ADC_SMPR2_SMP3 (0x7 << 9) +#define ADC_SMPR2_SMP2 (0x7 << 6) +#define ADC_SMPR2_SMP1 (0x7 << 3) +#define ADC_SMPR2_SMP0 0x7 + +/* Injected channel data offset register */ + +#define ADC_JOFR_JOFFSET 0x3FF + +/* Watchdog high threshold register */ + +#define ADC_HTR_HT 0x3FF + +/* Watchdog low threshold register */ + +#define ADC_LTR_LT 0x3FF + +/* Regular sequence register 1 */ + +#define ADC_SQR1_L (0x1F << 20) +#define ADC_SQR1_SQ16 (0x1F << 15) +#define ADC_SQR1_SQ15 (0x1F << 10) +#define ADC_SQR1_SQ14 (0x1F << 5) +#define ADC_SQR1_SQ13 0x1F + +/* Regular sequence register 2 */ + +#define ADC_SQR2_SQ12 (0x1F << 25) +#define ADC_SQR2_SQ11 (0x1F << 20) +#define ADC_SQR2_SQ10 (0x1F << 16) +#define ADC_SQR2_SQ9 (0x1F << 10) +#define ADC_SQR2_SQ8 (0x1F << 5) +#define ADC_SQR2_SQ7 0x1F + +/* Regular sequence register 3 */ + +#define ADC_SQR3_SQ6 (0x1F << 25) +#define ADC_SQR3_SQ5 (0x1F << 20) +#define ADC_SQR3_SQ4 (0x1F << 16) +#define ADC_SQR3_SQ3 (0x1F << 10) +#define ADC_SQR3_SQ2 (0x1F << 5) +#define ADC_SQR3_SQ1 0x1F + +/* Injected sequence register */ + +#define ADC_JSQR_JL (0x3 << 20) +#define ADC_JSQR_JL_1CONV (0x0 << 20) +#define ADC_JSQR_JL_2CONV (0x1 << 20) +#define ADC_JSQR_JL_3CONV (0x2 << 20) +#define ADC_JSQR_JL_4CONV (0x3 << 20) +#define ADC_JSQR_JSQ4 (0x1F << 15) +#define ADC_JSQR_JSQ3 (0x1F << 10) +#define ADC_JSQR_JSQ2 (0x1F << 5) +#define ADC_JSQR_JSQ1 0x1F + +/* Injected data registers */ + +#define ADC_JDR_JDATA 0xFFFF + +/* Regular data register */ + +#define ADC_DR_ADC2DATA (0xFFFF << 16) +#define ADC_DR_DATA 0xFFFF + +void adc_init(const adc_dev *dev); /** - * @brief Perform a single synchronous software triggered conversion on a - * channel. - * @param dev ADC device to use for reading. - * @param channel channel to convert - * @return conversion result + * @brief External event selector for regular group conversion. + * @see adc_set_extsel */ -static inline uint32 adc_read(const adc_dev *dev, uint8 channel) { - adc_reg_map *regs = dev->regs; +typedef enum adc_extsel_event { + ADC_ADC12_TIM1_CC1 = (0 << 17), /**< ADC1 and ADC2: Timer 1 CC1 event */ + ADC_ADC12_TIM1_CC2 = (1 << 17), /**< ADC1 and ADC2: Timer 1 CC2 event */ + ADC_ADC12_TIM1_CC3 = (2 << 17), /**< ADC1 and ADC2: Timer 1 CC3 event */ + ADC_ADC12_TIM2_CC2 = (3 << 17), /**< ADC1 and ADC2: Timer 2 CC2 event */ + ADC_ADC12_TIM3_TRGO = (4 << 17), /**< ADC1 and ADC2: Timer 3 TRGO event */ + ADC_ADC12_TIM4_CC4 = (5 << 17), /**< ADC1 and ADC2: Timer 4 CC4 event */ + ADC_ADC12_EXTI11 = (6 << 17), /**< ADC1 and ADC2: EXTI11 event */ +#ifdef STM32_HIGH_DENSITY + ADC_ADC12_TIM8_TRGO = (6 << 17), /**< ADC1 and ADC2: Timer 8 TRGO + event (high density only) */ +#endif + ADC_ADC12_SWSTART = (7 << 17), /**< ADC1 and ADC2: Software start */ +#ifdef STM32_HIGH_DENSITY + ADC_ADC3_TIM3_CC1 = (0 << 17), /**< ADC3: Timer 3 CC1 event + (high density only) */ + ADC_ADC3_TIM2_CC3 = (1 << 17), /**< ADC3: Timer 2 CC3 event + (high density only) */ + ADC_ADC3_TIM1_CC3 = (2 << 17), /**< ADC3: Timer 1 CC3 event + (high density only) */ + ADC_ADC3_TIM8_CC1 = (3 << 17), /**< ADC3: Timer 8 CC1 event + (high density only) */ + ADC_ADC3_TIM8_TRGO = (4 << 17), /**< ADC3: Timer 8 TRGO event + (high density only) */ + ADC_ADC3_TIM5_CC1 = (5 << 17), /**< ADC3: Timer 5 CC1 event + (high density only) */ + ADC_ADC3_TIM5_CC3 = (6 << 17), /**< ADC3: Timer 5 CC3 event + (high density only) */ + ADC_ADC3_SWSTART = (7 << 17), /**< ADC3: Software start (high + density only) */ +#endif + ADC_SWSTART = (7 << 17) /**< ADC1, ADC2, ADC3: Software start */ +} adc_extsel_event; - /* Set target channel */ - regs->SQR3 = channel; +void adc_set_extsel(const adc_dev *dev, adc_extsel_event event); +void adc_foreach(void (*fn)(const adc_dev*)); - /* Start the conversion */ - regs->CR2 |= ADC_CR2_SWSTART; +/** ADC per-sample conversion times, in ADC clock cycles */ +typedef enum { + ADC_SMPR_1_5, /**< 1.5 ADC cycles */ + ADC_SMPR_7_5, /**< 7.5 ADC cycles */ + ADC_SMPR_13_5, /**< 13.5 ADC cycles */ + ADC_SMPR_28_5, /**< 28.5 ADC cycles */ + ADC_SMPR_41_5, /**< 41.5 ADC cycles */ + ADC_SMPR_55_5, /**< 55.5 ADC cycles */ + ADC_SMPR_71_5, /**< 71.5 ADC cycles */ + ADC_SMPR_239_5 /**< 239.5 ADC cycles */ +} adc_smp_rate; - /* Wait for it to finish */ - while((regs->SR & ADC_SR_EOC) == 0) - ; +void adc_set_sample_rate(const adc_dev *dev, adc_smp_rate smp_rate); +void adc_calibrate(const adc_dev *dev); +uint16 adc_read(const adc_dev *dev, uint8 channel); - return regs->DR; +/** + * @brief Set the regular channel sequence length. + * + * Defines the total number of conversions in the regular channel + * conversion sequence. + * + * @param length Regular channel sequence length, from 1 to 16. + */ +static inline void adc_set_reg_seqlen(const adc_dev *dev, uint8 length) { + uint32 tmp = dev->regs->SQR1; + tmp &= ~ADC_SQR1_L; + tmp |= (length - 1) << 20; + dev->regs->SQR1 = tmp; } /** * @brief Set external trigger conversion mode event for regular channels * @param dev ADC device - * @param enable If 1, conversion on external events is enabled, 0 to disable + * @param enable If 1, conversion on external events is enabled; if 0, + * disabled. */ static inline void adc_set_exttrig(const adc_dev *dev, uint8 enable) { - *bb_perip(&dev->regs->CR2, 20) = !!enable; + *bb_perip(&dev->regs->CR2, ADC_CR2_EXTTRIG_BIT) = !!enable; } /** @@ -183,7 +333,7 @@ static inline void adc_set_exttrig(const adc_dev *dev, uint8 enable) { * @param dev ADC device to enable */ static inline void adc_enable(const adc_dev *dev) { - *bb_perip(&dev->regs->CR2, 0) = 1; + *bb_perip(&dev->regs->CR2, ADC_CR2_ADON_BIT) = 1; } /** @@ -191,18 +341,14 @@ static inline void adc_enable(const adc_dev *dev) { * @param dev ADC device to disable */ static inline void adc_disable(const adc_dev *dev) { - *bb_perip(&dev->regs->CR2, 0) = 0; + *bb_perip(&dev->regs->CR2, ADC_CR2_ADON_BIT) = 0; } /** - * @brief Disable all ADCs + * @brief Disable all ADC peripherals. */ static inline void adc_disable_all(void) { - adc_disable(ADC1); - adc_disable(ADC2); -#ifdef STM32_HIGH_DENSITY - adc_disable(ADC3); -#endif + adc_foreach(adc_disable); } #ifdef __cplusplus diff --git a/libmaple/timer.c b/libmaple/timer.c index ad0ec6f..a4e4032 100644 --- a/libmaple/timer.c +++ b/libmaple/timer.c @@ -189,8 +189,8 @@ void timer_set_mode(timer_dev *dev, uint8 channel, timer_mode mode) { } /** - * @brief Call a given function on all timers. - * @param fn Function to call on each timer. + * @brief Call a function on timer devices. + * @param fn Function to call on each timer device. */ void timer_foreach(void (*fn)(timer_dev*)) { fn(TIMER1); diff --git a/notes/coding_standard.txt b/notes/coding_standard.txt index 372ebf4..b81847d 100644 --- a/notes/coding_standard.txt +++ b/notes/coding_standard.txt @@ -220,3 +220,47 @@ General Formatting (require 'lineker) (dolist (hook '(c-mode-hook c++-mode-hook)) (add-hook hook (lambda () (lineker-mode 1)))) + +Language Features and Compiler Extensions +----------------------------------------- + +- In libmaple proper, aim for C99 compatibility. Some GCC extensions + are OK, but let's not go crazy. + +- If you'd like to get code into libmaple which uses a GCC extension + not already in use elsewhere, ask a LeafLabs developer (or another + one, if you are one) what they think about it first. + +- Explicitly approved GCC extensions: + + * asm volatile: + http://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html + + * Nested functions: + http://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html + +- In wirish, generally be very conservative when using C++ features + that aren't part of C. We are forced to use C++ for Arduino + compatibility (and the general Arduino style of pretending that an + object is a library), but it's an angry beast, and we don't want to + provoke it. The mantra is "C with classes". + +- Explicitly approved C++ features: + + * Initializers that aren't constant; e.g. the gpio_dev* values in + PIN_MAPs. + + * Default arguments: e.g., the timeout argument defaulting to 0 + (meaning to wait forever) in waitForButtonPress(). + +- Explicitly forbidden C++ features: + + * Templates + +- C++ features that are conditionally allowed, but require explicit + approval from at least two libmaple developers (one of which may be + yourself): + + * Operator overloading: Never allowed when it's just for style. + Potentially allowed when you're implementing a class that models a + mathematical structure, and you'd like to implement e.g. operator+(). diff --git a/notes/native-pin-definitions.txt b/notes/native-pin-definitions.txt deleted file mode 100644 index b871f89..0000000 --- a/notes/native-pin-definitions.txt +++ /dev/null @@ -1,201 +0,0 @@ -Maple Native (STM32F103ZE) pin definitions, by GPIO bank. - -Source: ST DOC ID 14611, Datasheet for STM32F103xC, STM32F103xD, -STM32F103xE, Table 5, pp. 30--35. - -Some peripherals and extra functionality with less/no libmaple -relevance (at time of writing) are given in "Other" following each -bank's main table. Non-default alternate functions are not listed. If -wirish will/does remap the pin's main function after reset, the main -function is listed under "Other". - -This document was prepared carefully and is believed to be complete -and correct, but the final arbiter of truth is the ST datasheet. - -*** NB: UART 4 and 5 are NOT USART (columns are labeled appropriately). - ---------------------------------------------------------------------------- -STM32 ADC Timer FSMC I2S I2C USART SPI DAC 5v? ---------------------------------------------------------------------------- -PA0 123in0 2ch1etr - - - 2cts - - - - 5ch1 - 8etr -PA1 123in1 5ch2 - - - 2rts - - - - 2ch2 -PA2 123in2 5ch3 - - - 2tx - - - - 2ch3 -PA3 123in3 5ch4 - - - 2rx - - - - 2ch4 -PA4 12in4 - - - - 2ck 1nss out1 - -PA5 12in5 - - - - - 1sck out2 - -PA6 12in6 8bkin - - - - 1miso - - - 3ch1 -PA7 12in7 8ch1n - - - - 1mosi - - - 3ch2 -PA8 - 1ch1 - - - 1ck - - Y -PA9 - 1ch2 - - - 1tx - - Y -PA10 - 1ch3 - - - 1rx - - Y -PA11 - 1ch4 - - - 1cts - - Y -PA12 - 1etr - - - 1rts - - Y -PA13 - - - - - - - - Y -PA14 - - - - - - - - Y -PA15 - - - 3ws - - 3nss - Y - -Other: - -PA0: WKUP -PA8: MCO -PA11: USBDM, CAN_RX -PA12: USBDP, CAN_TX -PA13: JTMS-SWDIO (default) -PA14: JTCK-SWCLK (default) -PA15: JTDI (default) - -------------------------------------------------------------------------------- -STM32 ADC Timer FSMC I2S I2C USART SPI DAC 5v? SDIO -------------------------------------------------------------------------------- -PB0 12in8 3ch3 - - - - - - - - - 8ch2n -PB1 12in9 3ch4 - - - - - - - - - 8ch3n -PB2 - - - - - - - - Y - -PB3 - - - 3ck - - 3sck - Y - -PB4 - - - - - - 3miso - Y - -PB5 - - - 3sd 1smba - 3mosi - - - -PB6 - 4ch1 - - 1scl - - - Y - -PB7 - 4ch2 NADV - 1sda - - - Y - -PB8 - 4ch3 - - - - - - Y D4 -PB9 - 4ch4 - - - - - - Y D5 -PB10 - - - - 2scl 3tx - - Y - -PB11 - - - - 2sda 3rx - - Y - -PB12 - 1bkin - 2ws 2smba 3ck 2nss - Y - -PB13 - 1ch1n - 2ck - 3cts 2sck - Y - -PB14 - 1ch2n - - - 3rts 2miso - Y - -PB15 - 1ch3n - 2sd - - 2mosi - Y - - -Other: - -PB2: BOOT1 -PB3: JTDO (default) -PB4: NJTRST (default) - -------------------------------------------------------------------------------- -STM32 ADC Timer FSMC I2S I2C UART SPI DAC 5v? SDIO -------------------------------------------------------------------------------- -PC0 123in10 - - - - - - - - - -PC1 123in11 - - - - - - - - - -PC2 123in12 - - - - - - - - - -PC3 123in13 - - - - - - - - - -PC4 12in14 - - - - - - - - - -PC5 12in15 - - - - - - - - - -PC6 - 8ch1 - 2mck - - - - Y D6 -PC7 - 8ch2 - 3mck - - - - Y D7 -PC8 - 8ch3 - - - - - - Y D0 -PC9 - 8ch4 - - - - - - Y D1 -PC10 - - - - - 4tx - - Y D2 -PC11 - - - - - 4rx - - Y D3 -PC12 - - - - - 5tx - - Y CK -PC13 - - - - - - - - - - -PC14 - - - - - - - - - - -PC15 - - - - - - - - - - - -Other: - -PC13: TAMPER_RTC -PC14: OSC32_IN -PC15: OSC32_OUT - -------------------------------------------------------------------------------- -STM32 ADC Timer FSMC I2S I2C UART SPI DAC 5v? SDIO -------------------------------------------------------------------------------- -PD0 - - D2 - - - - - Y - -PD1 - - D3 - - - - - Y - -PD2 - 3etr - - - 5rx - - Y CMD -PD3 - - CLK - - - - - Y - -PD4 - - NOE - - - - - Y - -PD5 - - NWE - - - - - Y - -PD6 - - NWAIT - - - - - Y - -PD7 - - NE1 - - - - - Y - - NCE2 -PD8 - - D13 - - - - - Y - -PD9 - - D14 - - - - - Y - -PD10 - - D15 - - - - - Y - -PD11 - - A16 - - - - - Y - -PD12 - - A17 - - - - - Y - -PD13 - - A18 - - - - - Y - -PD14 - - D0 - - - - - Y - -PD15 - - D1 - - - - - Y - - -Other: - -PD0: OSC_IN (default) -PD1: OSC_OUT (default) - ---------------------------------------------------------------------------- -STM32 ADC Timer FSMC I2S I2C USART SPI DAC 5v? ---------------------------------------------------------------------------- -PE0 - 4etr NBL0 - - - - - Y -PE1 - - NBL1 - - - - - Y -PE2 - - A23 - - - - - Y -PE3 - - A19 - - - - - Y -PE4 - - A20 - - - - - Y -PE5 - - A21 - - - - - Y -PE6 - - A22 - - - - - Y -PE7 - - D4 - - - - - Y -PE8 - - D5 - - - - - Y -PE9 - - D6 - - - - - Y -PE10 - - D7 - - - - - Y -PE11 - - D8 - - - - - Y -PE12 - - D9 - - - - - Y -PE13 - - D10 - - - - - Y -PE14 - - D11 - - - - - Y -PE15 - - D12 - - - - - Y - -Other: -PE2: TRACECK -PE3: TRACED0 -PE4: TRACED1 -PE5: TRACED2 -PE6: TRACED3 - ---------------------------------------------------------------------------- -STM32 ADC Timer FSMC I2S I2C USART SPI DAC 5v? ---------------------------------------------------------------------------- -PF0 - - A0 - - - - - Y -PF1 - - A1 - - - - - Y -PF2 - - A2 - - - - - Y -PF3 - - A3 - - - - - Y -PF4 - - A4 - - - - - Y -PF5 - - A5 - - - - - Y -PF6 3in4 - NIORD - - - - - - -PF7 3in5 - NREG - - - - - - -PF8 3in6 - NIOWR - - - - - - -PF9 3in7 - CD - - - - - - -PF10 3in8 - INTR - - - - - - -PF11 - - NIOS16 - - - - - Y -PF12 - - A6 - - - - - Y -PF13 - - A7 - - - - - Y -PF14 - - A8 - - - - - Y -PF15 - - A9 - - - - - Y - ---------------------------------------------------------------------------- -STM32 ADC Timer FSMC I2S I2C USART SPI DAC 5v? ---------------------------------------------------------------------------- -PG0 - - A10 - - - - - Y -PG1 - - A11 - - - - - Y -PG2 - - A12 - - - - - Y -PG3 - - A13 - - - - - Y -PG4 - - A14 - - - - - Y -PG5 - - A15 - - - - - Y -PG6 - - INT2 - - - - - Y -PG7 - - INT3 - - - - - Y -PG8 - - - - - - - - Y -PG9 - - NE2 - - - - - Y - NCE3 -PG10 - - NCE4_1 - - - - - Y - NE3 -PG11 - - NCE4_2 - - - - - Y -PG12 - - NE4 - - - - - Y -PG13 - - A24 - - - - - Y -PG14 - - A25 - - - - - Y -PG15 - - - - - - - - Y diff --git a/notes/pin-definitions.txt b/notes/pin-definitions.txt new file mode 100644 index 0000000..71572ac --- /dev/null +++ b/notes/pin-definitions.txt @@ -0,0 +1,201 @@ +Pin definitions by GPIO bank. + +Source: ST DOC ID 14611, Datasheet for STM32F103xC, STM32F103xD, +STM32F103xE, Table 5, pp. 30--35. + +Some peripherals and extra functionality with less/no libmaple +relevance (at time of writing) are given in "Other" following each +bank's main table. Non-default alternate functions are not listed. If +wirish will/does remap the pin's main function after reset, the main +function is listed under "Other". + +This document was prepared carefully and is believed to be correct, +but the final arbiter of truth is the ST datasheet. + +*** NB: UART 4 and 5 are NOT USART (columns are labeled appropriately). + +--------------------------------------------------------------------------- +GPIO ADC Timer FSMC I2S I2C USART SPI DAC 5v? +--------------------------------------------------------------------------- +PA0 123in0 2ch1etr - - - 2cts - - - + 5ch1 + 8etr +PA1 123in1 5ch2 - - - 2rts - - - + 2ch2 +PA2 123in2 5ch3 - - - 2tx - - - + 2ch3 +PA3 123in3 5ch4 - - - 2rx - - - + 2ch4 +PA4 12in4 - - - - 2ck 1nss out1 - +PA5 12in5 - - - - - 1sck out2 - +PA6 12in6 8bkin - - - - 1miso - - + 3ch1 +PA7 12in7 8ch1n - - - - 1mosi - - + 3ch2 +PA8 - 1ch1 - - - 1ck - - Y +PA9 - 1ch2 - - - 1tx - - Y +PA10 - 1ch3 - - - 1rx - - Y +PA11 - 1ch4 - - - 1cts - - Y +PA12 - 1etr - - - 1rts - - Y +PA13 - - - - - - - - Y +PA14 - - - - - - - - Y +PA15 - - - 3ws - - 3nss - Y + +Other: + +PA0: WKUP +PA8: MCO +PA11: USBDM, CAN_RX +PA12: USBDP, CAN_TX +PA13: JTMS-SWDIO (default) +PA14: JTCK-SWCLK (default) +PA15: JTDI (default) + +------------------------------------------------------------------------------- +GPIO ADC Timer FSMC I2S I2C USART SPI DAC 5v? SDIO +------------------------------------------------------------------------------- +PB0 12in8 3ch3 - - - - - - - - + 8ch2n +PB1 12in9 3ch4 - - - - - - - - + 8ch3n +PB2 - - - - - - - - Y - +PB3 - - - 3ck - - 3sck - Y - +PB4 - - - - - - 3miso - Y - +PB5 - - - 3sd 1smba - 3mosi - - - +PB6 - 4ch1 - - 1scl - - - Y - +PB7 - 4ch2 NADV - 1sda - - - Y - +PB8 - 4ch3 - - - - - - Y D4 +PB9 - 4ch4 - - - - - - Y D5 +PB10 - - - - 2scl 3tx - - Y - +PB11 - - - - 2sda 3rx - - Y - +PB12 - 1bkin - 2ws 2smba 3ck 2nss - Y - +PB13 - 1ch1n - 2ck - 3cts 2sck - Y - +PB14 - 1ch2n - - - 3rts 2miso - Y - +PB15 - 1ch3n - 2sd - - 2mosi - Y - + +Other: + +PB2: BOOT1 +PB3: JTDO (default) +PB4: NJTRST (default) + +------------------------------------------------------------------------------- +GPIO ADC Timer FSMC I2S I2C UART SPI DAC 5v? SDIO +------------------------------------------------------------------------------- +PC0 123in10 - - - - - - - - - +PC1 123in11 - - - - - - - - - +PC2 123in12 - - - - - - - - - +PC3 123in13 - - - - - - - - - +PC4 12in14 - - - - - - - - - +PC5 12in15 - - - - - - - - - +PC6 - 8ch1 - 2mck - - - - Y D6 +PC7 - 8ch2 - 3mck - - - - Y D7 +PC8 - 8ch3 - - - - - - Y D0 +PC9 - 8ch4 - - - - - - Y D1 +PC10 - - - - - 4tx - - Y D2 +PC11 - - - - - 4rx - - Y D3 +PC12 - - - - - 5tx - - Y CK +PC13 - - - - - - - - - - +PC14 - - - - - - - - - - +PC15 - - - - - - - - - - + +Other: + +PC13: TAMPER_RTC +PC14: OSC32_IN +PC15: OSC32_OUT + +------------------------------------------------------------------------------- +GPIO ADC Timer FSMC I2S I2C UART SPI DAC 5v? SDIO +------------------------------------------------------------------------------- +PD0 - - D2 - - - - - Y - +PD1 - - D3 - - - - - Y - +PD2 - 3etr - - - 5rx - - Y CMD +PD3 - - CLK - - - - - Y - +PD4 - - NOE - - - - - Y - +PD5 - - NWE - - - - - Y - +PD6 - - NWAIT - - - - - Y - +PD7 - - NE1 - - - - - Y - + NCE2 +PD8 - - D13 - - - - - Y - +PD9 - - D14 - - - - - Y - +PD10 - - D15 - - - - - Y - +PD11 - - A16 - - - - - Y - +PD12 - - A17 - - - - - Y - +PD13 - - A18 - - - - - Y - +PD14 - - D0 - - - - - Y - +PD15 - - D1 - - - - - Y - + +Other: + +PD0: OSC_IN (default) +PD1: OSC_OUT (default) + +--------------------------------------------------------------------------- +GPIO ADC Timer FSMC I2S I2C USART SPI DAC 5v? +--------------------------------------------------------------------------- +PE0 - 4etr NBL0 - - - - - Y +PE1 - - NBL1 - - - - - Y +PE2 - - A23 - - - - - Y +PE3 - - A19 - - - - - Y +PE4 - - A20 - - - - - Y +PE5 - - A21 - - - - - Y +PE6 - - A22 - - - - - Y +PE7 - - D4 - - - - - Y +PE8 - - D5 - - - - - Y +PE9 - - D6 - - - - - Y +PE10 - - D7 - - - - - Y +PE11 - - D8 - - - - - Y +PE12 - - D9 - - - - - Y +PE13 - - D10 - - - - - Y +PE14 - - D11 - - - - - Y +PE15 - - D12 - - - - - Y + +Other: +PE2: TRACECK +PE3: TRACED0 +PE4: TRACED1 +PE5: TRACED2 +PE6: TRACED3 + +--------------------------------------------------------------------------- +GPIO ADC Timer FSMC I2S I2C USART SPI DAC 5v? +--------------------------------------------------------------------------- +PF0 - - A0 - - - - - Y +PF1 - - A1 - - - - - Y +PF2 - - A2 - - - - - Y +PF3 - - A3 - - - - - Y +PF4 - - A4 - - - - - Y +PF5 - - A5 - - - - - Y +PF6 3in4 - NIORD - - - - - - +PF7 3in5 - NREG - - - - - - +PF8 3in6 - NIOWR - - - - - - +PF9 3in7 - CD - - - - - - +PF10 3in8 - INTR - - - - - - +PF11 - - NIOS16 - - - - - Y +PF12 - - A6 - - - - - Y +PF13 - - A7 - - - - - Y +PF14 - - A8 - - - - - Y +PF15 - - A9 - - - - - Y + +--------------------------------------------------------------------------- +GPIO ADC Timer FSMC I2S I2C USART SPI DAC 5v? +--------------------------------------------------------------------------- +PG0 - - A10 - - - - - Y +PG1 - - A11 - - - - - Y +PG2 - - A12 - - - - - Y +PG3 - - A13 - - - - - Y +PG4 - - A14 - - - - - Y +PG5 - - A15 - - - - - Y +PG6 - - INT2 - - - - - Y +PG7 - - INT3 - - - - - Y +PG8 - - - - - - - - Y +PG9 - - NE2 - - - - - Y + NCE3 +PG10 - - NCE4_1 - - - - - Y + NE3 +PG11 - - NCE4_2 - - - - - Y +PG12 - - NE4 - - - - - Y +PG13 - - A24 - - - - - Y +PG14 - - A25 - - - - - Y +PG15 - - - - - - - - Y diff --git a/wirish/boards.cpp b/wirish/boards.cpp new file mode 100644 index 0000000..17f47c6 --- /dev/null +++ b/wirish/boards.cpp @@ -0,0 +1,145 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * 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. + *****************************************************************************/ + +/** + * @brief Generic board initialization routines. + * + * By default, we bring up all Maple boards to 72MHz, clocked off the + * PLL, driven by the 8MHz external crystal. AHB and APB2 are clocked + * at 72MHz. APB1 is clocked at 36MHz. + */ + +#include "wirish.h" + +#include "flash.h" +#include "rcc.h" +#include "nvic.h" +#include "systick.h" +#include "gpio.h" +#include "adc.h" +#include "timer.h" +#include "usb.h" + +static void setupFlash(void); +static void setupClocks(void); +static void setupADC(void); +static void setupTimers(void); + +/** + * @brief Generic board initialization function. + * + * This function is called before main(). It ensures that the clocks + * and peripherals are configured properly for use with wirish, then + * calls boardInit(). + * + * @see boardInit() + */ +void init(void) { + setupFlash(); + setupClocks(); + nvic_init(); + systick_init(SYSTICK_RELOAD_VAL); + gpio_init_all(); + afio_init(); + setupADC(); + setupTimers(); + setupUSB(); + boardInit(); +} + +static void setupFlash(void) { + flash_enable_prefetch(); + flash_set_latency(FLASH_WAIT_STATE_2); +} + +/* + * Clock setup. Note that some of this only takes effect if we're + * running bare metal and the bootloader hasn't done it for us + * already. + * + * If you change this function, you MUST change the file-level Doxygen + * comment above. + */ +static void setupClocks() { + rcc_clk_init(RCC_CLKSRC_PLL, RCC_PLLSRC_HSE, RCC_PLLMUL_9); + rcc_set_prescaler(RCC_PRESCALER_AHB, RCC_AHB_SYSCLK_DIV_1); + rcc_set_prescaler(RCC_PRESCALER_APB1, RCC_APB1_HCLK_DIV_2); + rcc_set_prescaler(RCC_PRESCALER_APB2, RCC_APB2_HCLK_DIV_1); +} + +static void adcDefaultConfig(const adc_dev* dev); + +static void setupADC() { + adc_foreach(adcDefaultConfig); +} + +static void timerDefaultConfig(timer_dev*); + +static void setupTimers() { + timer_foreach(timerDefaultConfig); +} + +static void adcDefaultConfig(const adc_dev *dev) { + adc_init(dev); + + adc_set_extsel(dev, ADC_SWSTART); + adc_set_exttrig(dev, true); + + adc_enable(dev); + adc_calibrate(dev); + adc_set_sample_rate(dev, ADC_SMPR_55_5); +} + +static void timerDefaultConfig(timer_dev *dev) { + timer_adv_reg_map *regs = (dev->regs).adv; + const uint16 full_overflow = 0xFFFF; + const uint16 half_duty = 0x8FFF; + + timer_init(dev); + timer_pause(dev); + + regs->CR1 = TIMER_CR1_ARPE; + regs->PSC = 1; + regs->SR = 0; + regs->DIER = 0; + regs->EGR = TIMER_EGR_UG; + + switch (dev->type) { + case TIMER_ADVANCED: + regs->BDTR = TIMER_BDTR_MOE | TIMER_BDTR_LOCK_OFF; + // fall-through + case TIMER_GENERAL: + timer_set_reload(dev, full_overflow); + + for (int channel = 1; channel <= 4; channel++) { + timer_set_compare(dev, channel, half_duty); + timer_oc_set_mode(dev, channel, TIMER_OC_MODE_PWM_1, TIMER_OC_PE); + } + // fall-through + case TIMER_BASIC: + break; + } + + timer_resume(dev); +} diff --git a/wirish/boards.h b/wirish/boards.h index b72609d..3d023ae 100644 --- a/wirish/boards.h +++ b/wirish/boards.h @@ -60,12 +60,22 @@ enum { D106, D107, D108, D109, D110, D111, }; /** - * @brief Maps each pin to a corresponding struct stm32_pin_info. - * @see struct stm32_pin_info + * @brief Maps each Maple pin to a corresponding stm32_pin_info. + * @see stm32_pin_info */ extern stm32_pin_info PIN_MAP[]; -/** Board-specific initialization function. */ +void init(void); + +/** + * @brief Board-specific initialization function. + * + * This function is called from init() after all generic board + * initialization has been performed. Each board is required to + * define its own. + * + * @see init() + */ extern void boardInit(void); #ifdef BOARD_maple diff --git a/wirish/boards/maple.cpp b/wirish/boards/maple.cpp index cebd222..ba2261b 100644 --- a/wirish/boards/maple.cpp +++ b/wirish/boards/maple.cpp @@ -44,51 +44,51 @@ stm32_pin_info PIN_MAP[NR_GPIO_PINS] = { /* Top header */ - {GPIOA, TIMER2, 3, 4, 3}, /* D0/PA3 */ - {GPIOA, TIMER2, 2, 3, 2}, /* D1/PA2 */ - {GPIOA, TIMER2, 0, 1, 0}, /* D2/PA0 */ - {GPIOA, TIMER2, 1, 2, 1}, /* D3/PA1 */ - {GPIOB, NULL, 5, 0, ADCx}, /* D4/PB5 */ - {GPIOB, TIMER4, 6, 1, ADCx}, /* D5/PB6 */ - {GPIOA, TIMER1, 8, 1, ADCx}, /* D6/PA8 */ - {GPIOA, TIMER1, 9, 2, ADCx}, /* D7/PA9 */ - {GPIOA, TIMER1, 10, 3, ADCx}, /* D8/PA10 */ - {GPIOB, TIMER4, 7, 2, ADCx}, /* D9/PB7 */ - {GPIOA, NULL, 4, 0, 4}, /* D10/PA4 */ - {GPIOA, TIMER3, 7, 2, 7}, /* D11/PA7 */ - {GPIOA, TIMER3, 6, 1, 6}, /* D12/PA6 */ - {GPIOA, NULL, 5, 0, 5}, /* D13/PA5 (LED) */ - {GPIOB, TIMER4, 8, 3, ADCx}, /* D14/PB8 */ + {GPIOA, TIMER2, ADC1, 3, 4, 3}, /* D0/PA3 */ + {GPIOA, TIMER2, ADC1, 2, 3, 2}, /* D1/PA2 */ + {GPIOA, TIMER2, ADC1, 0, 1, 0}, /* D2/PA0 */ + {GPIOA, TIMER2, ADC1, 1, 2, 1}, /* D3/PA1 */ + {GPIOB, NULL, NULL, 5, 0, ADCx}, /* D4/PB5 */ + {GPIOB, TIMER4, NULL, 6, 1, ADCx}, /* D5/PB6 */ + {GPIOA, TIMER1, NULL, 8, 1, ADCx}, /* D6/PA8 */ + {GPIOA, TIMER1, NULL, 9, 2, ADCx}, /* D7/PA9 */ + {GPIOA, TIMER1, NULL, 10, 3, ADCx}, /* D8/PA10 */ + {GPIOB, TIMER4, NULL, 7, 2, ADCx}, /* D9/PB7 */ + {GPIOA, NULL, ADC1, 4, 0, 4}, /* D10/PA4 */ + {GPIOA, TIMER3, ADC1, 7, 2, 7}, /* D11/PA7 */ + {GPIOA, TIMER3, ADC1, 6, 1, 6}, /* D12/PA6 */ + {GPIOA, NULL, ADC1, 5, 0, 5}, /* D13/PA5 (LED) */ + {GPIOB, TIMER4, NULL, 8, 3, ADCx}, /* D14/PB8 */ /* Little header */ - {GPIOC, NULL, 0, 0, 10}, /* D15/PC0 */ - {GPIOC, NULL, 1, 0, 11}, /* D16/PC1 */ - {GPIOC, NULL, 2, 0, 12}, /* D17/PC2 */ - {GPIOC, NULL, 3, 0, 13}, /* D18/PC3 */ - {GPIOC, NULL, 4, 0, 14}, /* D19/PC4 */ - {GPIOC, NULL, 5, 0, 15}, /* D20/PC5 */ + {GPIOC, NULL, ADC1, 0, 0, 10}, /* D15/PC0 */ + {GPIOC, NULL, ADC1, 1, 0, 11}, /* D16/PC1 */ + {GPIOC, NULL, ADC1, 2, 0, 12}, /* D17/PC2 */ + {GPIOC, NULL, ADC1, 3, 0, 13}, /* D18/PC3 */ + {GPIOC, NULL, ADC1, 4, 0, 14}, /* D19/PC4 */ + {GPIOC, NULL, ADC1, 5, 0, 15}, /* D20/PC5 */ /* External header */ - {GPIOC, NULL, 13, 0, ADCx}, /* D21/PC13 */ - {GPIOC, NULL, 14, 0, ADCx}, /* D22/PC14 */ - {GPIOC, NULL, 15, 0, ADCx}, /* D23/PC15 */ - {GPIOB, TIMER4, 9, 4, ADCx}, /* D24/PB9 */ - {GPIOD, NULL, 2, 0, ADCx}, /* D25/PD2 */ - {GPIOC, NULL, 10, 0, ADCx}, /* D26/PC10 */ - {GPIOB, TIMER3, 0, 3, 8}, /* D27/PB0 */ - {GPIOB, TIMER3, 1, 4, 9}, /* D28/PB1 */ - {GPIOB, NULL, 10, 0, ADCx}, /* D29/PB10 */ - {GPIOB, NULL, 11, 0, ADCx}, /* D30/PB11 */ - {GPIOB, NULL, 12, 0, ADCx}, /* D31/PB12 */ - {GPIOB, NULL, 13, 0, ADCx}, /* D32/PB13 */ - {GPIOB, NULL, 14, 0, ADCx}, /* D33/PB14 */ - {GPIOB, NULL, 15, 0, ADCx}, /* D34/PB15 */ - {GPIOC, NULL, 6, 0, ADCx}, /* D35/PC6 */ - {GPIOC, NULL, 7, 0, ADCx}, /* D36/PC7 */ - {GPIOC, NULL, 8, 0, ADCx}, /* D37/PC8 */ - {GPIOC, NULL, 9, 0, ADCx} /* D38/PC9 (BUT) */ + {GPIOC, NULL, NULL, 13, 0, ADCx}, /* D21/PC13 */ + {GPIOC, NULL, NULL, 14, 0, ADCx}, /* D22/PC14 */ + {GPIOC, NULL, NULL, 15, 0, ADCx}, /* D23/PC15 */ + {GPIOB, TIMER4, NULL, 9, 4, ADCx}, /* D24/PB9 */ + {GPIOD, NULL, NULL, 2, 0, ADCx}, /* D25/PD2 */ + {GPIOC, NULL, NULL, 10, 0, ADCx}, /* D26/PC10 */ + {GPIOB, TIMER3, ADC1, 0, 3, 8}, /* D27/PB0 */ + {GPIOB, TIMER3, ADC1, 1, 4, 9}, /* D28/PB1 */ + {GPIOB, NULL, NULL, 10, 0, ADCx}, /* D29/PB10 */ + {GPIOB, NULL, NULL, 11, 0, ADCx}, /* D30/PB11 */ + {GPIOB, NULL, NULL, 12, 0, ADCx}, /* D31/PB12 */ + {GPIOB, NULL, NULL, 13, 0, ADCx}, /* D32/PB13 */ + {GPIOB, NULL, NULL, 14, 0, ADCx}, /* D33/PB14 */ + {GPIOB, NULL, NULL, 15, 0, ADCx}, /* D34/PB15 */ + {GPIOC, NULL, NULL, 6, 0, ADCx}, /* D35/PC6 */ + {GPIOC, NULL, NULL, 7, 0, ADCx}, /* D36/PC7 */ + {GPIOC, NULL, NULL, 8, 0, ADCx}, /* D37/PC8 */ + {GPIOC, NULL, NULL, 9, 0, ADCx} /* D38/PC9 (BUT) */ }; #endif diff --git a/wirish/boards/maple_RET6.cpp b/wirish/boards/maple_RET6.cpp index ae31ce3..962affc 100644 --- a/wirish/boards/maple_RET6.cpp +++ b/wirish/boards/maple_RET6.cpp @@ -38,51 +38,54 @@ void boardInit(void) { } stm32_pin_info PIN_MAP[NR_GPIO_PINS] = { - {GPIOA, TIMER2, 3, 4, 3}, /* D0/PA3 */ - {GPIOA, TIMER2, 2, 3, 2}, /* D1/PA2 */ - {GPIOA, TIMER2, 0, 1, 0}, /* D2/PA0 */ - {GPIOA, TIMER2, 1, 2, 1}, /* D3/PA1 */ - {GPIOB, NULL, 5, 0, ADCx}, /* D4/PB5 */ - {GPIOB, TIMER4, 6, 1, ADCx}, /* D5/PB6 */ - {GPIOA, TIMER1, 8, 1, ADCx}, /* D6/PA8 */ - {GPIOA, TIMER1, 9, 2, ADCx}, /* D7/PA9 */ - {GPIOA, TIMER1, 10, 3, ADCx}, /* D8/PA10 */ - {GPIOB, TIMER4, 7, 2, ADCx}, /* D9/PB7 */ - {GPIOA, NULL, 4, 0, 4}, /* D10/PA4 */ - {GPIOA, TIMER3, 7, 2, 7}, /* D11/PA7 */ - {GPIOA, TIMER3, 6, 1, 6}, /* D12/PA6 */ - {GPIOA, NULL, 5, 0, 5}, /* D13/PA5 (LED) */ - {GPIOB, TIMER4, 8, 3, ADCx}, /* D14/PB8 */ + + /* Top header */ + + {GPIOA, TIMER2, ADC1, 3, 4, 3}, /* D0/PA3 */ + {GPIOA, TIMER2, ADC1, 2, 3, 2}, /* D1/PA2 */ + {GPIOA, TIMER2, ADC1, 0, 1, 0}, /* D2/PA0 */ + {GPIOA, TIMER2, ADC1, 1, 2, 1}, /* D3/PA1 */ + {GPIOB, NULL, NULL, 5, 0, ADCx}, /* D4/PB5 */ + {GPIOB, TIMER4, NULL, 6, 1, ADCx}, /* D5/PB6 */ + {GPIOA, TIMER1, NULL, 8, 1, ADCx}, /* D6/PA8 */ + {GPIOA, TIMER1, NULL, 9, 2, ADCx}, /* D7/PA9 */ + {GPIOA, TIMER1, NULL, 10, 3, ADCx}, /* D8/PA10 */ + {GPIOB, TIMER4, NULL, 7, 2, ADCx}, /* D9/PB7 */ + {GPIOA, NULL, ADC1, 4, 0, 4}, /* D10/PA4 */ + {GPIOA, TIMER3, ADC1, 7, 2, 7}, /* D11/PA7 */ + {GPIOA, TIMER3, ADC1, 6, 1, 6}, /* D12/PA6 */ + {GPIOA, NULL, ADC1, 5, 0, 5}, /* D13/PA5 (LED) */ + {GPIOB, TIMER4, NULL, 8, 3, ADCx}, /* D14/PB8 */ /* Little header */ - {GPIOC, NULL, 0, 0, 10}, /* D15/PC0 */ - {GPIOC, NULL, 1, 0, 11}, /* D16/PC1 */ - {GPIOC, NULL, 2, 0, 12}, /* D17/PC2 */ - {GPIOC, NULL, 3, 0, 13}, /* D18/PC3 */ - {GPIOC, NULL, 4, 0, 14}, /* D19/PC4 */ - {GPIOC, NULL, 5, 0, 15}, /* D20/PC5 */ + {GPIOC, NULL, ADC1, 0, 0, 10}, /* D15/PC0 */ + {GPIOC, NULL, ADC1, 1, 0, 11}, /* D16/PC1 */ + {GPIOC, NULL, ADC1, 2, 0, 12}, /* D17/PC2 */ + {GPIOC, NULL, ADC1, 3, 0, 13}, /* D18/PC3 */ + {GPIOC, NULL, ADC1, 4, 0, 14}, /* D19/PC4 */ + {GPIOC, NULL, ADC1, 5, 0, 15}, /* D20/PC5 */ /* External header */ - {GPIOC, NULL, 13, 0, ADCx}, /* D21/PC13 */ - {GPIOC, NULL, 14, 0, ADCx}, /* D22/PC14 */ - {GPIOC, NULL, 15, 0, ADCx}, /* D23/PC15 */ - {GPIOB, TIMER4, 9, 4, ADCx}, /* D24/PB9 */ - {GPIOD, NULL, 2, 0, ADCx}, /* D25/PD2 */ - {GPIOC, NULL, 10, 0, ADCx}, /* D26/PC10 */ - {GPIOB, TIMER3, 0, 3, 8}, /* D27/PB0 */ - {GPIOB, TIMER3, 1, 4, 9}, /* D28/PB1 */ - {GPIOB, NULL, 10, 0, ADCx}, /* D29/PB10 */ - {GPIOB, NULL, 11, 0, ADCx}, /* D30/PB11 */ - {GPIOB, NULL, 12, 0, ADCx}, /* D31/PB12 */ - {GPIOB, NULL, 13, 0, ADCx}, /* D32/PB13 */ - {GPIOB, NULL, 14, 0, ADCx}, /* D33/PB14 */ - {GPIOB, NULL, 15, 0, ADCx}, /* D34/PB15 */ - {GPIOC, TIMER8, 6, 1, ADCx}, /* D35/PC6 */ - {GPIOC, TIMER8, 7, 2, ADCx}, /* D36/PC7 */ - {GPIOC, TIMER8, 8, 3, ADCx}, /* D37/PC8 */ - {GPIOC, TIMER8, 9, 4, ADCx} /* D38/PC9 (BUT) */ + {GPIOC, NULL, NULL, 13, 0, ADCx}, /* D21/PC13 */ + {GPIOC, NULL, NULL, 14, 0, ADCx}, /* D22/PC14 */ + {GPIOC, NULL, NULL, 15, 0, ADCx}, /* D23/PC15 */ + {GPIOB, TIMER4, NULL, 9, 4, ADCx}, /* D24/PB9 */ + {GPIOD, NULL, NULL, 2, 0, ADCx}, /* D25/PD2 */ + {GPIOC, NULL, NULL, 10, 0, ADCx}, /* D26/PC10 */ + {GPIOB, TIMER3, ADC1, 0, 3, 8}, /* D27/PB0 */ + {GPIOB, TIMER3, ADC1, 1, 4, 9}, /* D28/PB1 */ + {GPIOB, NULL, NULL, 10, 0, ADCx}, /* D29/PB10 */ + {GPIOB, NULL, NULL, 11, 0, ADCx}, /* D30/PB11 */ + {GPIOB, NULL, NULL, 12, 0, ADCx}, /* D31/PB12 */ + {GPIOB, NULL, NULL, 13, 0, ADCx}, /* D32/PB13 */ + {GPIOB, NULL, NULL, 14, 0, ADCx}, /* D33/PB14 */ + {GPIOB, NULL, NULL, 15, 0, ADCx}, /* D34/PB15 */ + {GPIOC, TIMER8, NULL, 6, 1, ADCx}, /* D35/PC6 */ + {GPIOC, TIMER8, NULL, 7, 2, ADCx}, /* D36/PC7 */ + {GPIOC, TIMER8, NULL, 8, 3, ADCx}, /* D37/PC8 */ + {GPIOC, TIMER8, NULL, 9, 4, ADCx} /* D38/PC9 (BUT) */ }; #endif diff --git a/wirish/boards/maple_mini.cpp b/wirish/boards/maple_mini.cpp index 8c005cf..66a0997 100644 --- a/wirish/boards/maple_mini.cpp +++ b/wirish/boards/maple_mini.cpp @@ -45,43 +45,43 @@ stm32_pin_info PIN_MAP[NR_GPIO_PINS] = { /* Top header */ - {GPIOB, NULL, 11, 0, ADCx}, /* D0/PB11 */ - {GPIOB, NULL, 10, 0, ADCx}, /* D1/PB10 */ - {GPIOB, NULL, 2, 0, ADCx}, /* D2/PB2 */ - {GPIOB, TIMER3, 0, 3, 8}, /* D3/PB0 */ - {GPIOA, TIMER3, 7, 2, 7}, /* D4/PA7 */ - {GPIOA, TIMER3, 6, 1, 6}, /* D5/PA6 */ - {GPIOA, NULL, 5, 0, 5}, /* D6/PA5 */ - {GPIOA, NULL, 4, 0, 4}, /* D7/PA4 */ - {GPIOA, TIMER2, 3, 4, 3}, /* D8/PA3 */ - {GPIOA, TIMER2, 2, 3, 2}, /* D9/PA2 */ - {GPIOA, TIMER2, 1, 2, 1}, /* D10/PA1 */ - {GPIOA, TIMER2, 0, 1, 0}, /* D11/PA0 */ - {GPIOC, NULL, 15, 0, ADCx}, /* D12/PC15 */ - {GPIOC, NULL, 14, 0, ADCx}, /* D13/PC14 */ - {GPIOC, NULL, 13, 0, ADCx}, /* D14/PC13 */ + {GPIOB, NULL, NULL, 11, 0, ADCx}, /* D0/PB11 */ + {GPIOB, NULL, NULL, 10, 0, ADCx}, /* D1/PB10 */ + {GPIOB, NULL, NULL, 2, 0, ADCx}, /* D2/PB2 */ + {GPIOB, TIMER3, ADC1, 0, 3, 8}, /* D3/PB0 */ + {GPIOA, TIMER3, ADC1, 7, 2, 7}, /* D4/PA7 */ + {GPIOA, TIMER3, ADC1, 6, 1, 6}, /* D5/PA6 */ + {GPIOA, NULL, ADC1, 5, 0, 5}, /* D6/PA5 */ + {GPIOA, NULL, ADC1, 4, 0, 4}, /* D7/PA4 */ + {GPIOA, TIMER2, ADC1, 3, 4, 3}, /* D8/PA3 */ + {GPIOA, TIMER2, ADC1, 2, 3, 2}, /* D9/PA2 */ + {GPIOA, TIMER2, ADC1, 1, 2, 1}, /* D10/PA1 */ + {GPIOA, TIMER2, ADC1, 0, 1, 0}, /* D11/PA0 */ + {GPIOC, NULL, NULL, 15, 0, ADCx}, /* D12/PC15 */ + {GPIOC, NULL, NULL, 14, 0, ADCx}, /* D13/PC14 */ + {GPIOC, NULL, NULL, 13, 0, ADCx}, /* D14/PC13 */ /* Bottom header */ - {GPIOB, TIMER4, 7, 2, ADCx}, /* D15/PB7 */ - {GPIOB, TIMER4, 6, 1, ADCx}, /* D16/PB6 */ - {GPIOB, NULL, 5, 0, ADCx}, /* D17/PB5 */ - {GPIOB, NULL, 4, 0, ADCx}, /* D18/PB4 */ - {GPIOB, NULL, 3, 0, ADCx}, /* D19/PB3 */ - {GPIOA, NULL, 15, 0, ADCx}, /* D20/PA15 */ - {GPIOA, NULL, 14, 0, ADCx}, /* D21/PA14 */ - {GPIOA, NULL, 13, 0, ADCx}, /* D22/PA13 */ - {GPIOA, NULL, 12, 0, ADCx}, /* D23/PA12 */ - {GPIOA, TIMER1, 11, 4, ADCx}, /* D24/PA11 */ - {GPIOA, TIMER1, 10, 3, ADCx}, /* D25/PA10 */ - {GPIOA, TIMER2, 9, 2, ADCx}, /* D26/PA9 */ - {GPIOA, TIMER1, 8, 1, ADCx}, /* D27/PA8 */ - {GPIOB, NULL, 15, 0, ADCx}, /* D28/PB15 */ - {GPIOB, NULL, 14, 0, ADCx}, /* D29/PB14 */ - {GPIOB, NULL, 13, 0, ADCx}, /* D30/PB13 */ - {GPIOB, NULL, 12, 0, ADCx}, /* D31/PB12 */ - {GPIOB, TIMER4, 8, 3, ADCx}, /* D32/PB8 */ - {GPIOB, TIMER3, 1, 4, 9}, /* D33/PB1 */ + {GPIOB, TIMER4, NULL, 7, 2, ADCx}, /* D15/PB7 */ + {GPIOB, TIMER4, NULL, 6, 1, ADCx}, /* D16/PB6 */ + {GPIOB, NULL, NULL, 5, 0, ADCx}, /* D17/PB5 */ + {GPIOB, NULL, NULL, 4, 0, ADCx}, /* D18/PB4 */ + {GPIOB, NULL, NULL, 3, 0, ADCx}, /* D19/PB3 */ + {GPIOA, NULL, NULL, 15, 0, ADCx}, /* D20/PA15 */ + {GPIOA, NULL, NULL, 14, 0, ADCx}, /* D21/PA14 */ + {GPIOA, NULL, NULL, 13, 0, ADCx}, /* D22/PA13 */ + {GPIOA, NULL, NULL, 12, 0, ADCx}, /* D23/PA12 */ + {GPIOA, TIMER1, NULL, 11, 4, ADCx}, /* D24/PA11 */ + {GPIOA, TIMER1, NULL, 10, 3, ADCx}, /* D25/PA10 */ + {GPIOA, TIMER2, NULL, 9, 2, ADCx}, /* D26/PA9 */ + {GPIOA, TIMER1, NULL, 8, 1, ADCx}, /* D27/PA8 */ + {GPIOB, NULL, NULL, 15, 0, ADCx}, /* D28/PB15 */ + {GPIOB, NULL, NULL, 14, 0, ADCx}, /* D29/PB14 */ + {GPIOB, NULL, NULL, 13, 0, ADCx}, /* D30/PB13 */ + {GPIOB, NULL, NULL, 12, 0, ADCx}, /* D31/PB12 */ + {GPIOB, TIMER4, NULL, 8, 3, ADCx}, /* D32/PB8 */ + {GPIOB, TIMER3, ADC1, 1, 4, 9}, /* D33/PB1 */ }; #endif diff --git a/wirish/boards/maple_native.cpp b/wirish/boards/maple_native.cpp index c04e98f..75c6a2d 100644 --- a/wirish/boards/maple_native.cpp +++ b/wirish/boards/maple_native.cpp @@ -43,113 +43,113 @@ stm32_pin_info PIN_MAP[NR_GPIO_PINS] = { /* Top header */ - {GPIOB, NULL, 10, 0, ADCx}, /* D0/PB10 */ - {GPIOB, NULL, 2, 0, ADCx}, /* D1/PB2 */ - {GPIOB, NULL, 12, 0, ADCx}, /* D2/PB12 */ - {GPIOB, NULL, 13, 0, ADCx}, /* D3/PB13 */ - {GPIOB, NULL, 14, 0, ADCx}, /* D4/PB14 */ - {GPIOB, NULL, 15, 0, ADCx}, /* D5/PB15 */ - {GPIOC, NULL, 0, 0, 10}, /* D6/PC0 */ - {GPIOC, NULL, 1, 0, 11}, /* D7/PC1 */ - {GPIOC, NULL, 2, 0, 12}, /* D8/PC2 */ - {GPIOC, NULL, 3, 0, 13}, /* D9/PC3 */ - {GPIOC, NULL, 4, 0, 14}, /* D10/PC4 */ - {GPIOC, NULL, 5, 0, 15}, /* D11/PC5 */ - {GPIOC, TIMER8, 6, 1, ADCx}, /* D12/PC6 */ - {GPIOC, TIMER8, 7, 2, ADCx}, /* D13/PC7 */ - {GPIOC, TIMER8, 8, 3, ADCx}, /* D14/PC8 */ - {GPIOC, TIMER8, 9, 4, ADCx}, /* D15/PC9 */ - {GPIOC, NULL, 10, 0, ADCx}, /* D16/PC10 */ - {GPIOC, NULL, 11, 0, ADCx}, /* D17/PC11 */ - {GPIOC, NULL, 12, 0, ADCx}, /* D18/PC12 */ - {GPIOC, NULL, 13, 0, ADCx}, /* D19/PC13 */ - {GPIOC, NULL, 14, 0, ADCx}, /* D20/PC14 */ - {GPIOC, NULL, 15, 0, ADCx}, /* D21/PC15 */ - {GPIOA, TIMER1, 8, 1, ADCx}, /* D22/PA8 */ - {GPIOA, TIMER1, 9, 2, ADCx}, /* D23/PA9 */ - {GPIOA, TIMER1, 10, 3, ADCx}, /* D24/PA10 */ - {GPIOB, TIMER4, 9, 4, ADCx}, /* D25/PB9 */ + {GPIOB, NULL, NULL, 10, 0, ADCx}, /* D0/PB10 */ + {GPIOB, NULL, NULL, 2, 0, ADCx}, /* D1/PB2 */ + {GPIOB, NULL, NULL, 12, 0, ADCx}, /* D2/PB12 */ + {GPIOB, NULL, NULL, 13, 0, ADCx}, /* D3/PB13 */ + {GPIOB, NULL, NULL, 14, 0, ADCx}, /* D4/PB14 */ + {GPIOB, NULL, NULL, 15, 0, ADCx}, /* D5/PB15 */ + {GPIOC, NULL, ADC1, 0, 0, 10}, /* D6/PC0 */ + {GPIOC, NULL, ADC1, 1, 0, 11}, /* D7/PC1 */ + {GPIOC, NULL, ADC1, 2, 0, 12}, /* D8/PC2 */ + {GPIOC, NULL, ADC1, 3, 0, 13}, /* D9/PC3 */ + {GPIOC, NULL, ADC1, 4, 0, 14}, /* D10/PC4 */ + {GPIOC, NULL, ADC1, 5, 0, 15}, /* D11/PC5 */ + {GPIOC, TIMER8, NULL, 6, 1, ADCx}, /* D12/PC6 */ + {GPIOC, TIMER8, NULL, 7, 2, ADCx}, /* D13/PC7 */ + {GPIOC, TIMER8, NULL, 8, 3, ADCx}, /* D14/PC8 */ + {GPIOC, TIMER8, NULL, 9, 4, ADCx}, /* D15/PC9 */ + {GPIOC, NULL, NULL, 10, 0, ADCx}, /* D16/PC10 */ + {GPIOC, NULL, NULL, 11, 0, ADCx}, /* D17/PC11 */ + {GPIOC, NULL, NULL, 12, 0, ADCx}, /* D18/PC12 */ + {GPIOC, NULL, NULL, 13, 0, ADCx}, /* D19/PC13 */ + {GPIOC, NULL, NULL, 14, 0, ADCx}, /* D20/PC14 */ + {GPIOC, NULL, NULL, 15, 0, ADCx}, /* D21/PC15 */ + {GPIOA, TIMER1, NULL, 8, 1, ADCx}, /* D22/PA8 */ + {GPIOA, TIMER1, NULL, 9, 2, ADCx}, /* D23/PA9 */ + {GPIOA, TIMER1, NULL, 10, 3, ADCx}, /* D24/PA10 */ + {GPIOB, TIMER4, NULL, 9, 4, ADCx}, /* D25/PB9 */ /* Bottom header */ - /* FIXME (?) What about D48--D50 also being TIMER2_CH[234]? */ + /* Note: D{48, 49, 50} are also TIMER2_CH{2, 3, 4}, respectively. */ - {GPIOD, NULL, 2, 0, ADCx}, /* D26/PD2 */ - {GPIOD, NULL, 3, 0, ADCx}, /* D27/PD3 */ - {GPIOD, NULL, 6, 0, ADCx}, /* D28/PD6 */ - {GPIOG, NULL, 11, 0, ADCx}, /* D29/PG11 */ - {GPIOG, NULL, 12, 0, ADCx}, /* D30/PG12 */ - {GPIOG, NULL, 13, 0, ADCx}, /* D31/PG13 */ - {GPIOG, NULL, 14, 0, ADCx}, /* D32/PG14 */ - {GPIOG, NULL, 8, 0, ADCx}, /* D33/PG8 */ - {GPIOG, NULL, 7, 0, ADCx}, /* D34/PG7 */ - {GPIOG, NULL, 6, 0, ADCx}, /* D35/PG6 */ - {GPIOB, NULL, 5, 0, ADCx}, /* D36/PB5 */ - {GPIOB, TIMER4, 6, 1, ADCx}, /* D37/PB6 */ - {GPIOB, TIMER4, 7, 2, ADCx}, /* D38/PB7 */ - {GPIOF, NULL, 6, 0, 4}, /* D39/PF6 */ - {GPIOF, NULL, 7, 0, 5}, /* D40/PF7 */ - {GPIOF, NULL, 8, 0, 6}, /* D41/PF8 */ - {GPIOF, NULL, 9, 0, 7}, /* D42/PF9 */ - {GPIOF, NULL, 10, 0, 8}, /* D43/PF10 */ - {GPIOF, NULL, 11, 0, ADCx}, /* D44/PF11 */ - {GPIOB, TIMER3, 1, 4, 9}, /* D45/PB1 */ - {GPIOB, TIMER3, 0, 3, 8}, /* D46/PB0 */ - {GPIOA, TIMER5, 0, 1, 0}, /* D47/PA0 */ - {GPIOA, TIMER5, 1, 2, 1}, /* D48/PA1 */ - {GPIOA, TIMER5, 2, 3, 2}, /* D49/PA2 */ - {GPIOA, TIMER5, 3, 4, 3}, /* D50/PA3 */ - {GPIOA, NULL, 4, 0, 4}, /* D51/PA4 */ - {GPIOA, NULL, 5, 0, 5}, /* D52/PA5 */ - {GPIOA, TIMER3, 6, 1, 6}, /* D53/PA6 */ - {GPIOA, TIMER3, 7, 2, 7}, /* D54/PA7 */ + {GPIOD, NULL, NULL, 2, 0, ADCx}, /* D26/PD2 */ + {GPIOD, NULL, NULL, 3, 0, ADCx}, /* D27/PD3 */ + {GPIOD, NULL, NULL, 6, 0, ADCx}, /* D28/PD6 */ + {GPIOG, NULL, NULL, 11, 0, ADCx}, /* D29/PG11 */ + {GPIOG, NULL, NULL, 12, 0, ADCx}, /* D30/PG12 */ + {GPIOG, NULL, NULL, 13, 0, ADCx}, /* D31/PG13 */ + {GPIOG, NULL, NULL, 14, 0, ADCx}, /* D32/PG14 */ + {GPIOG, NULL, NULL, 8, 0, ADCx}, /* D33/PG8 */ + {GPIOG, NULL, NULL, 7, 0, ADCx}, /* D34/PG7 */ + {GPIOG, NULL, NULL, 6, 0, ADCx}, /* D35/PG6 */ + {GPIOB, NULL, NULL, 5, 0, ADCx}, /* D36/PB5 */ + {GPIOB, TIMER4, NULL, 6, 1, ADCx}, /* D37/PB6 */ + {GPIOB, TIMER4, NULL, 7, 2, ADCx}, /* D38/PB7 */ + {GPIOF, NULL, ADC3, 6, 0, 4}, /* D39/PF6 */ + {GPIOF, NULL, ADC3, 7, 0, 5}, /* D40/PF7 */ + {GPIOF, NULL, ADC3, 8, 0, 6}, /* D41/PF8 */ + {GPIOF, NULL, ADC3, 9, 0, 7}, /* D42/PF9 */ + {GPIOF, NULL, ADC3, 10, 0, 8}, /* D43/PF10 */ + {GPIOF, NULL, NULL, 11, 0, ADCx}, /* D44/PF11 */ + {GPIOB, TIMER3, ADC1, 1, 4, 9}, /* D45/PB1 */ + {GPIOB, TIMER3, ADC1, 0, 3, 8}, /* D46/PB0 */ + {GPIOA, TIMER5, ADC1, 0, 1, 0}, /* D47/PA0 */ + {GPIOA, TIMER5, ADC1, 1, 2, 1}, /* D48/PA1 */ + {GPIOA, TIMER5, ADC1, 2, 3, 2}, /* D49/PA2 */ + {GPIOA, TIMER5, ADC1, 3, 4, 3}, /* D50/PA3 */ + {GPIOA, NULL, ADC1, 4, 0, 4}, /* D51/PA4 */ + {GPIOA, NULL, ADC1, 5, 0, 5}, /* D52/PA5 */ + {GPIOA, TIMER3, ADC1, 6, 1, 6}, /* D53/PA6 */ + {GPIOA, TIMER3, ADC1, 7, 2, 7}, /* D54/PA7 */ /* Right (triple) header */ - {GPIOF, NULL, 0, 0, ADCx}, /* D55/PF0 */ - {GPIOD, NULL, 11, 0, ADCx}, /* D56/PD11 */ - {GPIOD, NULL, 14, 0, ADCx}, /* D57/PD14 */ - {GPIOF, NULL, 1, 0, ADCx}, /* D58/PF1 */ - {GPIOD, NULL, 12, 0, ADCx}, /* D59/PD12 */ - {GPIOD, NULL, 15, 0, ADCx}, /* D60/PD15 */ - {GPIOF, NULL, 2, 0, ADCx}, /* D61/PF2 */ - {GPIOD, NULL, 13, 0, ADCx}, /* D62/PD13 */ - {GPIOD, NULL, 0, 0, ADCx}, /* D63/PD0 */ - {GPIOF, NULL, 3, 0, ADCx}, /* D64/PF3 */ - {GPIOE, NULL, 3, 0, ADCx}, /* D65/PE3 */ - {GPIOD, NULL, 1, 0, ADCx}, /* D66/PD1 */ - {GPIOF, NULL, 4, 0, ADCx}, /* D67/PF4 */ - {GPIOE, NULL, 4, 0, ADCx}, /* D68/PE4 */ - {GPIOE, NULL, 7, 0, ADCx}, /* D69/PE7 */ - {GPIOF, NULL, 5, 0, ADCx}, /* D70/PF5 */ - {GPIOE, NULL, 5, 0, ADCx}, /* D71/PE5 */ - {GPIOE, NULL, 8, 0, ADCx}, /* D72/PE8 */ - {GPIOF, NULL, 12, 0, ADCx}, /* D73/PF12 */ - {GPIOE, NULL, 6, 0, ADCx}, /* D74/PE6 */ - {GPIOE, NULL, 9, 0, ADCx}, /* D75/PE9 */ - {GPIOF, NULL, 13, 0, ADCx}, /* D76/PF13 */ - {GPIOE, NULL, 10, 0, ADCx}, /* D77/PE10 */ - {GPIOF, NULL, 14, 0, ADCx}, /* D78/PF14 */ - {GPIOG, NULL, 9, 0, ADCx}, /* D79/PG9 */ - {GPIOE, NULL, 11, 0, ADCx}, /* D80/PE11 */ - {GPIOF, NULL, 15, 0, ADCx}, /* D81/PF15 */ - {GPIOG, NULL, 10, 0, ADCx}, /* D82/PG10 */ - {GPIOE, NULL, 12, 0, ADCx}, /* D83/PE12 */ - {GPIOG, NULL, 0, 0, ADCx}, /* D84/PG0 */ - {GPIOD, NULL, 5, 0, ADCx}, /* D85/PD5 */ - {GPIOE, NULL, 13, 0, ADCx}, /* D86/PE13 */ - {GPIOG, NULL, 1, 0, ADCx}, /* D87/PG1 */ - {GPIOD, NULL, 4, 0, ADCx}, /* D88/PD4 */ - {GPIOE, NULL, 14, 0, ADCx}, /* D89/PE14 */ - {GPIOG, NULL, 2, 0, ADCx}, /* D90/PG2 */ - {GPIOE, NULL, 1, 0, ADCx}, /* D91/PE1 */ - {GPIOE, NULL, 15, 0, ADCx}, /* D92/PE15 */ - {GPIOG, NULL, 3, 0, ADCx}, /* D93/PG3 */ - {GPIOE, NULL, 0, 0, ADCx}, /* D94/PE0 */ - {GPIOD, NULL, 8, 0, ADCx}, /* D95/PD8 */ - {GPIOG, NULL, 4, 0, ADCx}, /* D96/PG4 */ - {GPIOD, NULL, 9, 0, ADCx}, /* D97/PD9 */ - {GPIOG, NULL, 5, 0, ADCx}, /* D98/PG5 */ - {GPIOD, NULL, 10, 0, ADCx} /* D99/PD10 */ + {GPIOF, NULL, NULL, 0, 0, ADCx}, /* D55/PF0 */ + {GPIOD, NULL, NULL, 11, 0, ADCx}, /* D56/PD11 */ + {GPIOD, NULL, NULL, 14, 0, ADCx}, /* D57/PD14 */ + {GPIOF, NULL, NULL, 1, 0, ADCx}, /* D58/PF1 */ + {GPIOD, NULL, NULL, 12, 0, ADCx}, /* D59/PD12 */ + {GPIOD, NULL, NULL, 15, 0, ADCx}, /* D60/PD15 */ + {GPIOF, NULL, NULL, 2, 0, ADCx}, /* D61/PF2 */ + {GPIOD, NULL, NULL, 13, 0, ADCx}, /* D62/PD13 */ + {GPIOD, NULL, NULL, 0, 0, ADCx}, /* D63/PD0 */ + {GPIOF, NULL, NULL, 3, 0, ADCx}, /* D64/PF3 */ + {GPIOE, NULL, NULL, 3, 0, ADCx}, /* D65/PE3 */ + {GPIOD, NULL, NULL, 1, 0, ADCx}, /* D66/PD1 */ + {GPIOF, NULL, NULL, 4, 0, ADCx}, /* D67/PF4 */ + {GPIOE, NULL, NULL, 4, 0, ADCx}, /* D68/PE4 */ + {GPIOE, NULL, NULL, 7, 0, ADCx}, /* D69/PE7 */ + {GPIOF, NULL, NULL, 5, 0, ADCx}, /* D70/PF5 */ + {GPIOE, NULL, NULL, 5, 0, ADCx}, /* D71/PE5 */ + {GPIOE, NULL, NULL, 8, 0, ADCx}, /* D72/PE8 */ + {GPIOF, NULL, NULL, 12, 0, ADCx}, /* D73/PF12 */ + {GPIOE, NULL, NULL, 6, 0, ADCx}, /* D74/PE6 */ + {GPIOE, NULL, NULL, 9, 0, ADCx}, /* D75/PE9 */ + {GPIOF, NULL, NULL, 13, 0, ADCx}, /* D76/PF13 */ + {GPIOE, NULL, NULL, 10, 0, ADCx}, /* D77/PE10 */ + {GPIOF, NULL, NULL, 14, 0, ADCx}, /* D78/PF14 */ + {GPIOG, NULL, NULL, 9, 0, ADCx}, /* D79/PG9 */ + {GPIOE, NULL, NULL, 11, 0, ADCx}, /* D80/PE11 */ + {GPIOF, NULL, NULL, 15, 0, ADCx}, /* D81/PF15 */ + {GPIOG, NULL, NULL, 10, 0, ADCx}, /* D82/PG10 */ + {GPIOE, NULL, NULL, 12, 0, ADCx}, /* D83/PE12 */ + {GPIOG, NULL, NULL, 0, 0, ADCx}, /* D84/PG0 */ + {GPIOD, NULL, NULL, 5, 0, ADCx}, /* D85/PD5 */ + {GPIOE, NULL, NULL, 13, 0, ADCx}, /* D86/PE13 */ + {GPIOG, NULL, NULL, 1, 0, ADCx}, /* D87/PG1 */ + {GPIOD, NULL, NULL, 4, 0, ADCx}, /* D88/PD4 */ + {GPIOE, NULL, NULL, 14, 0, ADCx}, /* D89/PE14 */ + {GPIOG, NULL, NULL, 2, 0, ADCx}, /* D90/PG2 */ + {GPIOE, NULL, NULL, 1, 0, ADCx}, /* D91/PE1 */ + {GPIOE, NULL, NULL, 15, 0, ADCx}, /* D92/PE15 */ + {GPIOG, NULL, NULL, 3, 0, ADCx}, /* D93/PG3 */ + {GPIOE, NULL, NULL, 0, 0, ADCx}, /* D94/PE0 */ + {GPIOD, NULL, NULL, 8, 0, ADCx}, /* D95/PD8 */ + {GPIOG, NULL, NULL, 4, 0, ADCx}, /* D96/PG4 */ + {GPIOD, NULL, NULL, 9, 0, ADCx}, /* D97/PD9 */ + {GPIOG, NULL, NULL, 5, 0, ADCx}, /* D98/PG5 */ + {GPIOD, NULL, NULL, 10, 0, ADCx} /* D99/PD10 */ }; #endif diff --git a/wirish/ext_interrupts.cpp b/wirish/ext_interrupts.cpp index 060994f..f9ccd39 100644 --- a/wirish/ext_interrupts.cpp +++ b/wirish/ext_interrupts.cpp @@ -49,7 +49,7 @@ void attachInterrupt(uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode) { exti_trigger_mode outMode = exti_out_mode(mode); - exti_attach_interrupt((afio_exti_num)(PIN_MAP[pin].gpio_pin), + exti_attach_interrupt((afio_exti_num)(PIN_MAP[pin].gpio_bit), gpio_exti_port(PIN_MAP[pin].gpio_device), handler, outMode); @@ -64,7 +64,7 @@ void detachInterrupt(uint8 pin) { return; } - exti_detach_interrupt((afio_exti_num)(PIN_MAP[pin].gpio_pin)); + exti_detach_interrupt((afio_exti_num)(PIN_MAP[pin].gpio_bit)); } static inline exti_trigger_mode exti_out_mode(ExtIntTriggerMode mode) { diff --git a/wirish/io.h b/wirish/io.h index 8dad1d1..7d4fab1 100644 --- a/wirish/io.h +++ b/wirish/io.h @@ -28,8 +28,8 @@ * @brief Arduino-compatible digital pin I/O interface. */ -#ifndef _IO_H -#define _IO_H +#ifndef _IO_H_ +#define _IO_H_ #include "gpio.h" #include "adc.h" @@ -45,8 +45,8 @@ * This enum specifies the complete set of possible configurations; * not every pin can have all of these modes. For example, on the * Maple, pin 15 may be configured as INPUT_ANALOG, but not as PWM. - * See your device's silkscreen and and the GPIO documentation for - * more information. + * See your board's documentation and silkscreen for more information + * on what functionality is available on each pin. * * @see pinMode() */ @@ -114,8 +114,7 @@ typedef enum WiringPinMode { /** * Configure behavior of a GPIO pin. * - * @param pin Pin to configure. One of: 0-38 (pin numbers as labeled - * on silkscreen), or D0-D38 (symbols for same) + * @param pin Number of pin to configure. * @param mode Mode corresponding to desired pin behavior. * @see WiringPinMode */ @@ -136,8 +135,7 @@ void digitalWrite(uint8 pin, uint8 value); * Read a digital value from a pin. The pin must have its mode set to * one of INPUT, INPUT_PULLUP, and INPUT_PULLDOWN. * - * @param pin Pin to read from. One of: 0-38 (pin numbers as labeled - * on silkscreen), or D0-D38 (symbols for same) + * @param pin Pin to read from. * @return LOW or HIGH. * @see pinMode() */ @@ -146,18 +144,14 @@ uint32 digitalRead(uint8 pin); /** * Read an analog value from pin. This function blocks during ADC * conversion, and has 12 bits of resolution. The pin must have its - * mode set to INPUT_ANALOG. Ignoring function call overhead, - * conversion time is 55.5 cycles. + * mode set to INPUT_ANALOG. * - * @param pin Pin to read from. One of: 0, 1, 2, 3, 10, 11, 12, 13, - * 15, 16, 17, 18, 19, 20, 27, 28. - - * @return ADC-converted voltage, in the range 0--4095, inclusive - * (i.e. a 12-bit ADC conversion). - + * @param pin Pin to read from. + * @return Converted voltage, in the range 0--4095, (i.e. a 12-bit ADC + * conversion). * @see pinMode() */ -uint32 analogRead(uint8 pin); +uint16 analogRead(uint8 pin); /** * Toggles the digital value at the given pin. @@ -207,14 +201,15 @@ uint8 isButtonPressed(); * pinMode(BOARD_BUTTON_PIN, INPUT). * * @param timeout_millis Number of milliseconds to wait until the - * button is pressed. If timeout_millis is 0, wait forever. + * button is pressed. If timeout_millis is left out (or 0), wait + * forever. * * @return true, if the button was pressed; false, if the timeout was * reached. * * @see pinMode() */ -uint8 waitForButtonPress(uint32 timeout_millis); +uint8 waitForButtonPress(uint32 timeout_millis=0); /** * Shift out a byte of data, one bit at a time. diff --git a/wirish/pwm.cpp b/wirish/pwm.cpp index 6b09cef..4c803d2 100644 --- a/wirish/pwm.cpp +++ b/wirish/pwm.cpp @@ -38,5 +38,5 @@ void pwmWrite(uint8 pin, uint16 duty_cycle) { return; } - timer_set_compare(dev, PIN_MAP[pin].timer_chan, duty_cycle); + timer_set_compare(dev, PIN_MAP[pin].timer_channel, duty_cycle); } diff --git a/wirish/rules.mk b/wirish/rules.mk index c1d59bc..7715068 100644 --- a/wirish/rules.mk +++ b/wirish/rules.mk @@ -16,6 +16,7 @@ cSRCS_$(d) := cppSRCS_$(d) := wirish_math.cpp \ Print.cpp \ + boards.cpp \ boards/maple.cpp \ boards/maple_mini.cpp \ boards/maple_native.cpp \ @@ -24,14 +25,13 @@ cppSRCS_$(d) := wirish_math.cpp \ comm/HardwareSPI.cpp \ usb_serial.cpp \ cxxabi-compat.cpp \ - wirish.cpp \ wirish_shift.cpp \ wirish_analog.cpp \ time.cpp \ pwm.cpp \ ext_interrupts.cpp \ wirish_digital.cpp \ - native_sram.cpp \ + native_sram.cpp cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%) cppFILES_$(d) := $(cppSRCS_$(d):%=$(d)/%) diff --git a/wirish/wirish.cpp b/wirish/wirish.cpp deleted file mode 100644 index aeed089..0000000 --- a/wirish/wirish.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * 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. - *****************************************************************************/ - -/** - * @brief Generic Maple board initialization. - * - * By default, we bring up all Maple boards to 72MHz, clocked off the - * PLL, driven by the 8MHz external crystal. AHB and APB2 are clocked - * at 72MHz. APB1 is clocked at 36MHz. - */ - -#include "wirish.h" - -#include "flash.h" -#include "rcc.h" -#include "nvic.h" -#include "systick.h" -#include "gpio.h" -#include "adc.h" -#include "timer.h" -#include "usb.h" - -static void setupFlash(void); -static void setupClocks(void); -static void setupADC(void); -static void setupTimers(void); - -/** - * Board-wide initialization function. Called before main(). - */ -void init(void) { - setupFlash(); - setupClocks(); - nvic_init(); - systick_init(SYSTICK_RELOAD_VAL); - gpio_init_all(); - afio_init(); - setupADC(); - setupTimers(); - setupUSB(); - boardInit(); -} - -static void setupFlash(void) { - flash_enable_prefetch(); - flash_set_latency(FLASH_WAIT_STATE_2); -} - -/* - * Clock setup. Note that some of this only takes effect if we're - * running bare metal and the bootloader hasn't done it for us - * already. - * - * If you change this function, you MUST change the file-level Doxygen - * comment above. - */ -static void setupClocks() { - rcc_clk_init(RCC_CLKSRC_PLL, RCC_PLLSRC_HSE, RCC_PLLMUL_9); - rcc_set_prescaler(RCC_PRESCALER_AHB, RCC_AHB_SYSCLK_DIV_1); - rcc_set_prescaler(RCC_PRESCALER_APB1, RCC_APB1_HCLK_DIV_2); - rcc_set_prescaler(RCC_PRESCALER_APB2, RCC_APB2_HCLK_DIV_1); -} - -/* TODO initialize more ADCs on high density boards. */ -static void setupADC() { - adc_init(ADC1, 0); - adc_set_sample_rate(ADC1, ADC_SMPR_55_5); // for high impedance inputs -} - -static void timerDefaultConfig(timer_dev*); - -static void setupTimers() { - timer_foreach(timerDefaultConfig); -} - -static void timerDefaultConfig(timer_dev *dev) { - timer_adv_reg_map *regs = (dev->regs).adv; - const uint16 full_overflow = 0xFFFF; - const uint16 half_duty = 0x8FFF; - - timer_init(dev); - timer_pause(dev); - - regs->CR1 = TIMER_CR1_ARPE; - regs->PSC = 1; - regs->SR = 0; - regs->DIER = 0; - regs->EGR = TIMER_EGR_UG; - - switch (dev->type) { - case TIMER_ADVANCED: - regs->BDTR = TIMER_BDTR_MOE | TIMER_BDTR_LOCK_OFF; - // fall-through - case TIMER_GENERAL: - timer_set_reload(dev, full_overflow); - - for (int channel = 1; channel <= 4; channel++) { - timer_set_compare(dev, channel, half_duty); - timer_oc_set_mode(dev, channel, TIMER_OC_MODE_PWM_1, TIMER_OC_PE); - } - // fall-through - case TIMER_BASIC: - break; - } - - timer_resume(dev); -} diff --git a/wirish/wirish.h b/wirish/wirish.h index 13b14b6..880157d 100644 --- a/wirish/wirish.h +++ b/wirish/wirish.h @@ -67,7 +67,5 @@ typedef uint8 boolean; typedef uint8 byte; -void init(void); - #endif diff --git a/wirish/wirish_analog.cpp b/wirish/wirish_analog.cpp index 9e99aa5..8756caf 100644 --- a/wirish/wirish_analog.cpp +++ b/wirish/wirish_analog.cpp @@ -31,11 +31,12 @@ #include "io.h" /* Assumes that the ADC has been initialized and that the pin is set - * to ANALOG_INPUT */ -uint32 analogRead(uint8 pin) { - if(PIN_MAP[pin].adc_channel == ADCx) { + * to INPUT_ANALOG */ +uint16 analogRead(uint8 pin) { + const adc_dev *dev = PIN_MAP[pin].adc_device; + if (dev == NULL) { return 0; } - return adc_read(ADC1, PIN_MAP[pin].adc_channel); + return adc_read(dev, PIN_MAP[pin].adc_channel); } diff --git a/wirish/wirish_digital.cpp b/wirish/wirish_digital.cpp index 278cf10..115e91e 100644 --- a/wirish/wirish_digital.cpp +++ b/wirish/wirish_digital.cpp @@ -70,20 +70,14 @@ void pinMode(uint8 pin, WiringPinMode mode) { return; } - gpio_set_mode(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_pin, outputMode); + gpio_set_mode(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit, outputMode); if (PIN_MAP[pin].timer_device != NULL) { - /* enable/disable timer channels if we're switching into or - out of pwm */ - if (pwm) { - timer_set_mode(PIN_MAP[pin].timer_device, - PIN_MAP[pin].timer_chan, - TIMER_PWM); - } else { - timer_set_mode(PIN_MAP[pin].timer_device, - PIN_MAP[pin].timer_chan, - TIMER_DISABLED); - } + /* Enable/disable timer channels if we're switching into or + * out of PWM. */ + timer_set_mode(PIN_MAP[pin].timer_device, + PIN_MAP[pin].timer_channel, + pwm ? TIMER_PWM : TIMER_DISABLED); } } @@ -93,7 +87,7 @@ uint32 digitalRead(uint8 pin) { return 0; } - return gpio_read_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_pin) ? + return gpio_read_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit) ? HIGH : LOW; } @@ -102,7 +96,7 @@ void digitalWrite(uint8 pin, uint8 val) { return; } - gpio_write_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_pin, val); + gpio_write_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit, val); } void togglePin(uint8 pin) { @@ -110,12 +104,14 @@ void togglePin(uint8 pin) { return; } - gpio_toggle_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_pin); + gpio_toggle_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit); } +#define BUTTON_DEBOUNCE_DELAY 10 + uint8 isButtonPressed() { if (digitalRead(BOARD_BUTTON_PIN)) { - delay(1); + delay(BUTTON_DEBOUNCE_DELAY); while (digitalRead(BOARD_BUTTON_PIN)) ; return true; diff --git a/wirish/wirish_types.h b/wirish/wirish_types.h index 84591ea..7d6e31a 100644 --- a/wirish/wirish_types.h +++ b/wirish/wirish_types.h @@ -32,20 +32,28 @@ #include "gpio.h" #include "timer.h" +#include "adc.h" #ifndef _WIRISH_TYPES_H_ #define _WIRISH_TYPES_H_ -/** Stores STM32-specific information related to a given pin. */ +/** + * Invalid stm32_pin_info adc_channel value. + * @see stm32_pin_info + */ +#define ADCx 0xFF + +/** + * @brief Stores STM32-specific information related to a given Maple pin. + * @see PIN_MAP + */ typedef struct stm32_pin_info { - gpio_dev *gpio_device; /**< Maple pin's GPIO device */ - timer_dev *timer_device; /**< Maple pin's timer device, or NULL if none. */ - uint8 gpio_pin; /**< GPIO pin */ - uint8 timer_chan; /**< Timer channel, or 0 if none. */ - uint8 adc_channel; /**< Pin ADC channel, or ADCx if none. */ + gpio_dev *gpio_device; /**< Maple pin's GPIO device */ + timer_dev *timer_device; /**< Pin's timer device, if any. */ + const adc_dev *adc_device; /**< ADC device, if any. */ + uint8 gpio_bit; /**< Pin's GPIO port bit. */ + uint8 timer_channel; /**< Timer channel, or 0 if none. */ + uint8 adc_channel; /**< Pin ADC channel, or ADCx if none. */ } stm32_pin_info; -/** Invalid adc_channel value */ -#define ADCx 0xFF - #endif -- cgit v1.2.3 From 09de1019a60125f3f5932a21377670d3cb030121 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Wed, 30 Mar 2011 03:44:57 -0400 Subject: Nitpicks --- libmaple/scb.h | 4 ++++ wirish/io.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/libmaple/scb.h b/libmaple/scb.h index f851a08..8bfdda3 100644 --- a/libmaple/scb.h +++ b/libmaple/scb.h @@ -29,6 +29,8 @@ #ifndef _SCB_H_ #define _SCB_H_ +/* FIXME this definition is missing doxygen comments */ + typedef struct scb_reg_map { __io uint32 CPUID; // CPU ID Base Register __io uint32 ICSR; // Interrupt Control State Register @@ -51,6 +53,8 @@ typedef struct scb_reg_map { __io uint32 ISAR[5]; // ISA Feature Register } scb_reg_map; +/* FIXME these names violate the libmaple naming conventions */ + #define SCB_BASE 0xE000ED00 #define SCB ((scb_reg_map*)(SCB_BASE)) diff --git a/wirish/io.h b/wirish/io.h index 7d4fab1..0ffbd10 100644 --- a/wirish/io.h +++ b/wirish/io.h @@ -223,7 +223,7 @@ uint8 waitForButtonPress(uint32 timeout_millis=0); * @param dataPin Pin to shift data out on * @param clockPin Pin to pulse after each bit is shifted out * @param bitOrder Either MSBFIRST (big-endian) or LSBFIRST (little-endian). - * @param val Value to shift out + * @param value Value to shift out */ void shiftOut(uint8 dataPin, uint8 clockPin, uint8 bitOrder, uint8 value); -- cgit v1.2.3 From efbc87c64d89bbb367b6d8face6c50edf0eb5e5c Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Wed, 30 Mar 2011 05:58:58 -0400 Subject: Removed Maple-specific information from digitalWrite() doxygen comment. --- wirish/io.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/wirish/io.h b/wirish/io.h index 0ffbd10..4e415b5 100644 --- a/wirish/io.h +++ b/wirish/io.h @@ -122,10 +122,9 @@ void pinMode(uint8 pin, WiringPinMode mode); /** * Writes a (digital) value to a pin. The pin must have its - * mode set to OUTPUT or OUTPUT_OPEN_DRAIN. + * mode set to OUTPUT or OUTPUT_OPEN_DRAIN. * - * @param pin Pin to write to. One of: 0-38 (pin numbers as labeled - * on silkscreen), or D0-D38 (symbols for same) + * @param pin Pin to write to. * @param value Either LOW (write a 0) or HIGH (write a 1). * @see pinMode() */ -- cgit v1.2.3 From b13926073f47012d6654b0236f195c4356831fc2 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Wed, 30 Mar 2011 00:55:51 -0400 Subject: Board-specific values; corresponding QA test generalizations. Various board-specific #defines and arrays of pins added. For the changelog (some of this information predates this commit): * wirish/boards.h now declares the following arrays of pin numbers: * boardPWMPins - PWM-capable pins * boardADCPins - ADC-capable pins * boardUsedPins - pins already in use, e.g. BOARD_BUTTON_PIN It also declares a bool boardUsesPin(uint8 pin) function for convenient testing of whether a pin is in use. * wirish/boards/*.h now define: * BOARD_USART1_TX_PIN * BOARD_USART1_RX_PIN * BOARD_USART2_TX_PIN * BOARD_USART2_RX_PIN * BOARD_USART3_TX_PIN * BOARD_USART3_RX_PIN * BOARD_NR_GPIO_PINS (renamed from NR_GPIO_PINS) * BOARD_NR_USARTS (renamed from NR_USARTS) * BOARD_NR_PWM_PINS * BOARD_NR_ADC_PINS * BOARD_NR_USED_PINS * wirish/boards/maple_native.h now defines: * BOARD_UART4_TX_PIN * BOARD_UART4_RX_PIN * BOARD_UART5_TX_PIN * BOARD_UART5_RX_PIN (Unfortunately, wirish/boards/maple_RET6.h cannot, since at least one of the UART4/UART5 pins are used already; this will require layout changes for a wide-release Maple form factor RET6 board). * wirish/boards/*.cpp all include the corresponding array definitions. They all live in flash by default, thanks to the new __FLASH__ macro in wirish/wirish_types.h, which is a synonym for the existing __attr_flash #define in libmaple/libmaple_types.h. The documentation was updated to include this information. It also gained various FIXME/TODO comments related to its generalization across boards. The quality assurance-related examples (examples/qa-slave-shield.cpp and examples/test-session.cpp) now make heavy use of board-specific values to ensure portability. --- docs/source/arm-gcc.rst | 53 +- docs/source/compatibility.rst | 2 + docs/source/gpio.rst | 2 + docs/source/i2c.rst | 19 +- docs/source/index.rst | 1 + docs/source/lang/api/analogread.rst | 33 +- docs/source/lang/api/board-values.rst | 155 +++++ docs/source/lang/api/boardusespin.rst | 27 + docs/source/lang/api/constants.rst | 26 +- docs/source/lang/api/hardwaretimer.rst | 6 + docs/source/lang/api/isbuttonpressed.rst | 5 +- docs/source/lang/api/pwmwrite.rst | 2 + docs/source/lang/api/toggleled.rst | 2 +- docs/source/lang/api/waitforbuttonpress.rst | 2 + docs/source/language-index.rst | 4 +- docs/source/language.rst | 46 +- docs/source/libmaple.rst | 12 +- examples/qa-slave-shield.cpp | 48 +- examples/test-session.cpp | 847 ++++++++++++++++------------ wirish/boards.cpp | 22 +- wirish/boards.h | 43 +- wirish/boards/maple.cpp | 14 +- wirish/boards/maple.h | 16 +- wirish/boards/maple_RET6.cpp | 14 +- wirish/boards/maple_RET6.h | 8 +- wirish/boards/maple_mini.cpp | 17 +- wirish/boards/maple_mini.h | 8 +- wirish/boards/maple_native.cpp | 16 +- wirish/boards/maple_native.h | 15 +- wirish/comm/HardwareSerial.cpp | 4 +- wirish/ext_interrupts.cpp | 4 +- wirish/pwm.cpp | 2 +- wirish/wirish_digital.cpp | 10 +- wirish/wirish_types.h | 3 + 34 files changed, 985 insertions(+), 503 deletions(-) create mode 100644 docs/source/lang/api/board-values.rst create mode 100644 docs/source/lang/api/boardusespin.rst diff --git a/docs/source/arm-gcc.rst b/docs/source/arm-gcc.rst index ef745f5..7ecb5d4 100644 --- a/docs/source/arm-gcc.rst +++ b/docs/source/arm-gcc.rst @@ -4,12 +4,11 @@ GCC for Maple ============= -This document provides notes on the current usage of -``arm-none-eabi-gcc``, the `CodeSourcery `_ -version of the GNU `GCC `_ compilers used to -compile programs for the Maple. It is not intended as a reference -manual for GCC; such manuals are available `elsewhere -`_. +This document provides notes on using of ``arm-none-eabi-gcc``, the +`CodeSourcery `_ version of the GNU `GCC +`_ compilers used for the Maple boards. It is +not intended as a reference manual for GCC; such manuals are available +`elsewhere `_. Obtaining ``arm-none-eabi-gcc`` ------------------------------- @@ -17,21 +16,24 @@ Obtaining ``arm-none-eabi-gcc`` Recent versions of ``arm-none-eabi-gcc`` and associated tools are included with the :ref:`Maple IDE `. -Users who wish to use ``arm-none-eabi-gcc`` in concert with a standard -Unix toolchain are referred to our :ref:`unix-toolchain` reference, -which describes how to set up such an environment. +Users who wish to use ``arm-none-eabi-gcc`` directly, along with a +standard Unix Make-based toolchain, should read the +:ref:`unix-toolchain`, which describes how to set up such an +environment. -LeafLabs mirrors some of the more recent versions of the compiler -under http://static.leaflabs.com/pub/codesourcery/\ , including -versions for OS X, win32, and 32-bit Linux. +LeafLabs maintains `mirrors +`_ for some of the more +recent versions of the compiler, including versions for OS X, Win32, +and 32-bit Linux. Compiler Flags Used by libmaple ------------------------------- This section documents the flags passed to ``arm-none-eabi-gcc`` by -the :ref:`Maple IDE ` and the default Makefile provided with -:ref:`libmaple `. The information in this section is -subject to change without notice. +the :ref:`Maple IDE ` and the default Makefile provided with the +:ref:`Unix toolchain `. The information in this +section is subject to change between :ref:`libmaple ` +releases. .. highlight:: sh @@ -40,7 +42,8 @@ The following flags are among those passed to the C compiler:: -Os -g -mcpu=cortex-m3 -mthumb -march=armv7-m -nostdlib -ffunction-sections -fdata-sections -Wl,--gc-sections -The following flags are among those passed to the C++ compiler:: +In addition to those flags just given for the C compiler, the +following flags are among those passed to the C++ compiler:: -fno-rtti -fno-exceptions -Wall @@ -52,6 +55,15 @@ The following flags are among those passed to the assembler:: .. _arm-gcc-avr-gcc: +Using the C Standard Library +---------------------------- + +By default (under both the :ref:`Maple IDE ` and the :ref:`Unix +toolchain `), ``arm-none-eabi-gcc`` is configured to +link against `newlib `_, a C standard +library intended for use with embedded applications. You are free to +include of any of its headers. + Switching from AVR-GCC ---------------------- @@ -63,8 +75,11 @@ including Arduino) for use on the Maple. .. _arm-gcc-attribute-flash: - Replacing ``PROGMEM``: You can direct the linker script provided - with libmaple to store a variable in flash by using - ``__attribute__((section (".USER_FLASH")))``, like so:: + with libmaple to store a variable in Flash (instead of RAM) by using + the libmaple macro ``__FLASH__``, like so:: - uint32 arr[] __attribute__((section (".USER_FLASH"))) = {...}; + uint32 array[] __FLASH__ = {0, 1, 2}; + Be aware, however, that if you do that, you can only store values + which are compile-time constants, and that if you attempt to change + a variable stored in Flash, your program will crash. diff --git a/docs/source/compatibility.rst b/docs/source/compatibility.rst index 0d6319f..eb28ad2 100644 --- a/docs/source/compatibility.rst +++ b/docs/source/compatibility.rst @@ -41,6 +41,8 @@ means that programs aren't much larger (or are even smaller). Header Numbering and Incompatibilities -------------------------------------- +.. FIXME generalize Maple-specific information + The numbering of headers is different; on the Maple each GPIO has a unique number: D0, D1, D2, all the way up to D37 (actually, there are :ref:`a few more `...). On the Arduino, the analog pins are diff --git a/docs/source/gpio.rst b/docs/source/gpio.rst index cebb402..5daf43c 100644 --- a/docs/source/gpio.rst +++ b/docs/source/gpio.rst @@ -3,6 +3,8 @@ GPIO ==== +.. FIXME generalize this maple-specific information + The Maple features 38 ready-to-use general purpose input/output (GPIO) pins for digital input/output, numbered D0 through D37. These numbers correspond to the numeric values next to each header on the Maple diff --git a/docs/source/i2c.rst b/docs/source/i2c.rst index b4a996b..e2a7a04 100644 --- a/docs/source/i2c.rst +++ b/docs/source/i2c.rst @@ -4,11 +4,16 @@ |i2c| ===== +.. FIXME update this documentation once you write the Wire library on +.. top of libmaple i2c. + +.. FIXME generalize Maple-specific documentation + .. note:: - The |i2c| interface is currently only available from the 'i2c' branch - of the github `libmaple `_ - repository. + The |i2c| interface is currently only available from the 'refactor' + branch of the github `libmaple + `_ repository. |i2c| is a crude and easy-to-hack serial protocol that requires only two wires/channels for communication between many devices. Every @@ -56,10 +61,8 @@ Function Reference ------------------ The function API for |i2c| is not finished! See the `source code -`_ for -now. - -.. TODO link to libmaple I2C docs once (1) finished, (2) in master +`_ +for now. SMBus ----- @@ -68,8 +71,6 @@ The STM32 microcontroller has hardware support for SMBus; we simply have not written software for it. The SMBAL line for i2c1 is on header D4 and for i2c2 is on D31. -.. TODO link to libmaple SMBus docs once (1) finished, (2) in master - .. _i2c-recommended-reading: Recommended Reading diff --git a/docs/source/index.rst b/docs/source/index.rst index 4369fbd..de71411 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -38,6 +38,7 @@ Have fun! Bootloader Troubleshooting Known Problems + Notes on GCC's ARM target .. _index-hardware: diff --git a/docs/source/lang/api/analogread.rst b/docs/source/lang/api/analogread.rst index 35c6fbc..7099b69 100644 --- a/docs/source/lang/api/analogread.rst +++ b/docs/source/lang/api/analogread.rst @@ -35,6 +35,8 @@ have to do this once, so it's usually done in :ref:`lang-setup`\ ). Parameter Discussion -------------------- +.. FIXME generalize Maple-specific information + The pin parameter is the number of the analog input pin to read from. Header pins on the Maple with ADC functionality (marked as "AIN" on the silkscreen) are: @@ -49,24 +51,25 @@ Note ---- If the analog input pin is not connected to anything, the value -returned by analogRead() will fluctuate based on a number of factors -(e.g. the values of the other analog inputs, how close your hand is to -the board, etc.) in a seemingly random way. +returned by ``analogRead()`` will fluctuate due to a number of reasons +(like the values of the other analog inputs, how close your hand is to +the board, etc.) in a "random" way. Example ------- - :: +:: + int analogPin = 3; // Potentiometer wiper (middle terminal) connected + // to analog pin 3. outside leads to ground and +3.3V. + // You may have to change this value if your board + // cannot perform ADC conversion on pin 3. - int analogPin = 3; // potentiometer wiper (middle terminal) connected - // to analog pin 3. outside leads to ground and +3.3V int val = 0; // variable to store the value read void setup() { pinMode(analogPin, INPUT_ANALOG); // set up pin for analog input - SerialUSB.begin(); // set up usb virtual COM port } void loop() { @@ -97,23 +100,27 @@ shift ` the value of a Maple readout by 2, like so:: // be aware that you're losing a lot of precision if you do this int adc_reading = analogRead(pin) >> 2; +.. FIXME Mention Native can do analogReference(), when it's time + On the Arduino, the input range and resolution can be changed using their implementation of `analogReference() `_\ . Because of the way its hardware (as of Rev 5) was designed, it's not possible to implement analogReference on the Maple, so this function doesn't exist. If your inputs lie in a different voltage range than 0V--3.3V, -you'll need to bring them into that range before using analogRead. -Some basic tools to accomplish this are `resistor dividers -`_ and `Zener diodes +you'll need to bring them into that range before using +``analogRead()``. Some basic tools to accomplish this are `resistor +dividers `_ and `Zener +diodes `_\ -. However, opamps and other powered components can also be used if -greater precision is required. +. However, `operational amplifiers +`_ and other +powered components can also be used if greater precision is required. See also -------- -- :ref:`ADC note ` +- :ref:`ADC tutorial ` - `(Arduino) Tutorial: Analog Input Pins `_ .. include:: cc-attribution.txt diff --git a/docs/source/lang/api/board-values.rst b/docs/source/lang/api/board-values.rst new file mode 100644 index 0000000..367adbb --- /dev/null +++ b/docs/source/lang/api/board-values.rst @@ -0,0 +1,155 @@ +.. _lang-board-values: + +Board-Specific Constants +======================== + +There are a number of board-specific values: constants or variables +which are different depending on which LeafLabs board you have. + +This page lists and documents the board-specific values. You should +use these when appropriate in your own programs. This will help make +it easier to share your code with other people who have different +boards. Some example usages are given :ref:`below +`. + +.. contents:: Contents + :local: + +Constants +--------- + +- ``CYCLES_PER_MICROSECOND``: Number of CPU cycles per microsecond on + your board. + +.. _lang-board-values-but: + +- ``BOARD_BUTTON_PIN``: Pin connected to the built-in button (labeled + "BUT" on your board's silkscreen). + +.. _lang-board-values-led: + +- ``BOARD_LED_PIN``: Pin connected to the built-in LED. + +- ``BOARD_NR_GPIO_PINS``: Total number of :ref:`GPIO pins ` that + are broken out to headers. Some of these might already be connected + to external hardware (like the built-in LED and button). To find + out if a pin is in use, see :ref:`boardUsesPin() + ` (and also :ref:`boardUsedPins + `). + +.. _lang-board-values-nr-pwm-pins: + +- ``BOARD_NR_PWM_PINS``: Total *number* of GPIO pins that can be used + for :ref:`PWM `. The actual *pins* that can do PWM are in the + :ref:`boardPWMPins ` array. + +.. _lang-board-values-nr-adc-pins: + +- ``BOARD_NR_ADC_PINS``: Total number of GPIO pins that can be used + for :ref:`analog-to-digital conversion `. The actual pins that + can do ADC conversion are in the :ref:`boardADCPins + ` array. + +.. _lang-board-values-nr-used-pins: + +- ``BOARD_NR_USED_PINS``: Total number of GPIO pins that are already + connected to some external hardware (like a built-in LED) on the + board. The actual pins that that are already used are in the + :ref:`boardUsedPins ` array. To see if + a pin is already in use, use the :ref:`boardUsesPin() + ` function. + +.. _lang-board-values-usart: + +- USART (serial port) related constants: + + * ``BOARD_USART1_TX_PIN``, ``BOARD_USART2_TX_PIN``, ``BOARD_USART3_TX_PIN``: + TX pins for the 3 USARTS. + + * ``BOARD_USART1_RX_PIN``, ``BOARD_USART2_RX_PIN``, ``BOARD_USART3_RX_PIN``: + RX pins for the 3 USARTS. + + * ``BOARD_UART4_TX_PIN``, ``BOARD_UART5_TX_PIN``: TX pins for + UARTs 4 and 5 (high-density boards like Maple Native only). + + * ``BOARD_UART4_RX_PIN``, ``BOARD_UART5_RX_PIN``: RX pins for + UARTs 4 and 5 (high-density boards like Maple Native only). + + * ``BOARD_NR_USARTS``: Number of serial ports on the board. This + number includes UARTs 4 and 5 if they are available. + +.. _lang-board-values-pwm-pins: +.. _lang-board-values-adc-pins: +.. _lang-board-values-used-pins: + +Pin Arrays +---------- + +Some :ref:`arrays ` of pin numbers are available which you +can use to find out certain important information about a given pin. + +.. TODO add links to the board-specific hardware information on what +.. are in these arrays + +- ``boardPWMPins``: Pin numbers of each pin capable of :ref:`PWM + ` output, using :ref:`pwmWrite() `. The total + number of these pins is :ref:`BOARD_NR_PWM_PINS + `. + +- ``boardADCPins``: Pin numbers of each pin capable of :ref:`ADC + ` conversion, using :ref:`analogRead() `. The + total number of these pins is :ref:`BOARD_NR_ADC_PINS + `. + +- ``boardUsedPins``: Pin numbers of each pin that, by default, is used + for some special purpose by the board. The total number of these + pins is :ref:`BOARD_NR_USED_PINS `. + To check if a pin is used for a special purpose, use + :ref:`boardUsesPin() `. + +.. _lang-board-values-examples: + +Examples +-------- + +:ref:`BOARD_LED_PIN ` On the Maple, the +built-in LED is connected to pin 13. On the Maple Mini, however, it +is connected to pin 33. You can write a "blinky" program that works +on all LeafLabs boards using ``BOARD_LED_PIN`` and :ref:`toggleLED() +`:: + + void setup() { + pinMode(BOARD_LED_PIN, OUTPUT); + } + + void loop() { + toggleLED(); + delay(100); + } + +:ref:`BOARD_BUTTON_PIN `: Similarly, you can +write a single program that prints a message whenever the button is +pressed which will work on all LeafLabs boards using +``BOARD_BUTTON_PIN`` and :ref:`isButtonPressed() +`:: + + void setup() { + pinMode(BOARD_BUTTON_PIN, INPUT); + } + + void loop() { + if (isButtonPressed()) { + SerialUSB.println("You pressed the button!"); + } + } + +See Also +-------- + +- :ref:`lang-boardusespin` +- :ref:`lang-isbuttonpressed` +- :ref:`lang-waitforbuttonpress` +- :ref:`lang-pinmode` +- :ref:`lang-toggleled` +- :ref:`lang-analogread` +- :ref:`lang-pwmwrite` diff --git a/docs/source/lang/api/boardusespin.rst b/docs/source/lang/api/boardusespin.rst new file mode 100644 index 0000000..8dc4c64 --- /dev/null +++ b/docs/source/lang/api/boardusespin.rst @@ -0,0 +1,27 @@ +.. highlight:: cpp + +.. _lang-boardusespin: + +boardUsesPin() +============== + +Each LeafLabs board connects some pins to external hardware. The most +important examples of this are the built-in LED and button. You can +check if a board uses a particular pin using this function. + +Library Documentation +--------------------- + +.. doxygenfunction:: boardUsesPin + +See Also +-------- + +- :ref:`Board-specific values ` +- :ref:`boardUsedPins ` +- :ref:`BOARD_LED_PIN ` +- :ref:`toggleLED() ` +- :ref:`BOARD_BUTTON_PIN ` +- :ref:`isButtonPressed() ` +- :ref:`waitForButtonPress() ` + diff --git a/docs/source/lang/api/constants.rst b/docs/source/lang/api/constants.rst index 2e968e7..c5a7c0c 100644 --- a/docs/source/lang/api/constants.rst +++ b/docs/source/lang/api/constants.rst @@ -293,23 +293,16 @@ exponent indicators. Some examples are given in the following table: Board-Specific Constants ------------------------ -This section documents constants whose value might change across -different LeafLabs boards. You can use these constants to help ensure -that your code will be portable across different boards. +There are several :ref:`board-specific constants ` +whose value depends on which LeafLabs board you have. If you use +them, it will help make sure that your code will work well on all +LeafLabs boards, not just the one you have. This will make it much +easier to share your code with others. -.. TODO replace "upcoming" when Mini, Native come out - -.. _lang-constants-led: - -- ``BOARD_LED_PIN``: the number of the pin which connects to the - built-in LED. On the Maple, this is pin 13, but it's not guaranteed - to be the same in upcoming boards like the Maple Mini. - -.. _lang-constants-but: - -- ``BOARD_BUTTON_PIN``: the number of the pin which connects to the - built-in button (labeled "BUT"). On the Maple, this is pin 38, but - it's not guaranteed to be the same in other boards. +For example, the pin number connected to the board's built-in LED is +different on the different boards, but the board-specific constant +:ref:`BOARD_LED_PIN ` will always be the +correct value for each board. See Also -------- @@ -325,5 +318,6 @@ See Also - :ref:`unsigned long long ` - :ref:`float ` - :ref:`double ` +- :ref:`Board-Specific Values ` .. include:: cc-attribution.txt diff --git a/docs/source/lang/api/hardwaretimer.rst b/docs/source/lang/api/hardwaretimer.rst index c7a630d..3f086ca 100644 --- a/docs/source/lang/api/hardwaretimer.rst +++ b/docs/source/lang/api/hardwaretimer.rst @@ -10,6 +10,12 @@ built-in timer peripherals. More information on these peripherals (including code examples) is available in the :ref:`timers reference `. +.. FIXME update HardwareTimer documentation after redoing it in terms +.. of the new timer interface. + +.. warning:: This class has been deprecated. It is not available in + the current build. + Library Documentation --------------------- diff --git a/docs/source/lang/api/isbuttonpressed.rst b/docs/source/lang/api/isbuttonpressed.rst index dbff0c9..8c350b9 100644 --- a/docs/source/lang/api/isbuttonpressed.rst +++ b/docs/source/lang/api/isbuttonpressed.rst @@ -4,7 +4,8 @@ isButtonPressed() ================= Check whether the board's built-in button (labeled BUT on the -silkscreen) is pressed. +silkscreen) is pressed. The pin number of the built-in button is +given by the constant ``BOARD_BUTTON_PIN``. Library Documentation --------------------- @@ -14,4 +15,6 @@ Library Documentation See Also -------- +- :ref:`Board-specific values ` +- :ref:`BOARD_BUTTON_PIN ` - :ref:`lang-waitforbuttonpress` diff --git a/docs/source/lang/api/pwmwrite.rst b/docs/source/lang/api/pwmwrite.rst index 9d50077..cea602b 100644 --- a/docs/source/lang/api/pwmwrite.rst +++ b/docs/source/lang/api/pwmwrite.rst @@ -11,6 +11,8 @@ pwmWrite(), the pin will output a steady square wave with the given duty cycle. You can change the duty cycle later by calling pwmWrite() again with the same pin and a different duty. +.. FIXME board-specific information + On the Maple, the pins which support PWM are: 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 14, 24, 27, and 28. diff --git a/docs/source/lang/api/toggleled.rst b/docs/source/lang/api/toggleled.rst index 0cc20c2..54a7d64 100644 --- a/docs/source/lang/api/toggleled.rst +++ b/docs/source/lang/api/toggleled.rst @@ -13,5 +13,5 @@ Library Documentation See Also -------- -- :ref:`BOARD_LED_PIN ` +- :ref:`BOARD_LED_PIN ` - :ref:`togglePin() ` diff --git a/docs/source/lang/api/waitforbuttonpress.rst b/docs/source/lang/api/waitforbuttonpress.rst index 34c5066..a5bd45c 100644 --- a/docs/source/lang/api/waitforbuttonpress.rst +++ b/docs/source/lang/api/waitforbuttonpress.rst @@ -14,4 +14,6 @@ Library Documentation See Also -------- +- :ref:`Board-specific values ` +- :ref:`BOARD_BUTTON_PIN ` - :ref:`lang-isbuttonpressed` diff --git a/docs/source/language-index.rst b/docs/source/language-index.rst index c949988..531e72c 100644 --- a/docs/source/language-index.rst +++ b/docs/source/language-index.rst @@ -26,13 +26,13 @@ programmers familiar with the Arduino language. | | | +----------------------------------+------------------------------------+ -.. Unimplemented in libmaple or not part of current release: +.. Unimplemented or not part of current release: .. toctree:: :hidden: + lang/unimplemented/tone.rst lang/unimplemented/notone.rst lang/unimplemented/pulsein.rst lang/unimplemented/stringclass.rst lang/unimplemented/stringobject.rst - lang/unimplemented/tone.rst diff --git a/docs/source/language.rst b/docs/source/language.rst index d340aec..ea841f5 100644 --- a/docs/source/language.rst +++ b/docs/source/language.rst @@ -10,6 +10,9 @@ The Maple can be programmed in the `Wiring `_ language, which is the same language used to program the `Arduino `_ boards. +.. TODO Wiring tutorial -- just describe setup()/loop(), then link to +.. some of the the bajillion external tutorials + C or C++ programmers curious about the differences between the Wiring language and C++ may wish to skip to the :ref:`arduino_c_for_c_hackers`. @@ -25,6 +28,21 @@ Maple Language Reference The following table summarizes the available core language features. A more exhaustive index is available at the :ref:`language-index`. +**Looking for something else?** + +- See the :ref:`libraries` for extra built-in libraries for dealing + with different kinds of hardware. + +.. FIXME mention Maple Native supports malloc(), free(), operator +.. new(), and operator delete(), when that is a true thing to say. + +- If you're looking for something from the C standard library (like + ``atoi()``, for instance): the :ref:`CodeSourcery GCC compiler + ` used to compile your programs is configured to link + against `newlib `_, and allows the + use of any of its header files. However, dynamic memory allocation + (``malloc()``, etc.) is not available. + +--------------------------------------------+----------------------------------------------+---------------------------------------------------+ | Structure | Variables | Functions | | | | | @@ -40,13 +58,13 @@ A more exhaustive index is available at the :ref:`language-index`. | |* :ref:`true ` | |* :ref:`togglePin() ` | |* :ref:`for ` | :ref:`false ` | | | | |* :ref:`toggleLED() ` | -|* :ref:`switch/case ` |* :ref:`BOARD_LED_PIN ` | | | -| | :ref:`BOARD_BUTTON_PIN `|* :ref:`isButtonPressed() ` | -|* :ref:`while ` | | | -| |* :ref:`Constants |* :ref:`waitForButtonPress() | -|* :ref:`do...while ` | ` (:ref:`integers | ` | -| | `, :ref:`floating | | -|* :ref:`break ` | point `) |**Analog I/O** | +|* :ref:`switch/case ` |* :ref:`Constants | | +| | ` (:ref:`integers |* :ref:`isButtonPressed() ` | +|* :ref:`while ` | `, :ref:`floating | | +| | point `) |* :ref:`waitForButtonPress() | +|* :ref:`do...while ` | | ` | +| |* :ref:`Board-specific values | | +|* :ref:`break ` | ` |**Analog I/O** | | | | | |* :ref:`continue ` |**Data Types** |* :ref:`analogRead() ` | | | | | @@ -76,7 +94,7 @@ A more exhaustive index is available at the :ref:`language-index`. |**Arithmetic Operators** | ` | | | | |* :ref:`delayMicroseconds() | |* :ref:`= ` |* ``unsigned long`` (4 bytes), synonym for | ` | -| (assignment operator) | :ref:`unsigned int ` | | +| (assignment) | :ref:`unsigned int ` | | | | | | |* :ref:`+ ` (addition) |* :ref:`long long ` (8 bytes) |**Math** | | | | | @@ -153,13 +171,13 @@ A more exhaustive index is available at the :ref:`language-index`. | | | | |* :ref:`++ ` | |* :ref:`Serial ` | | (increment) | | | -| | |**Looking for something else?** | +| | | | |* :ref:`- - ` | | | -| (decrement) | | See the :ref:`libraries` page for interfacing with| -| | | particular types of hardware. Maple links | -|* :ref:`+= ` | | against `newlib `_ | -| (compound add) | | and allows the use of any of its functions; see | -| | | its documentation for more details. | +| (decrement) | | | +| | | | +|* :ref:`+= ` | | | +| (compound add) | | | +| | | | |* :ref:`-= | | | | ` (compound | | | | subtract) | | | diff --git a/docs/source/libmaple.rst b/docs/source/libmaple.rst index 8cc39a3..9faca03 100644 --- a/docs/source/libmaple.rst +++ b/docs/source/libmaple.rst @@ -30,12 +30,12 @@ wrappers and code to imitate the Arduino programming library. git clone git://github.com/leaflabs/libmaple.git -**Table of contents:** +.. TODO after finishing refactor: create, style, and host a pure +.. Doxygen libmaple reference docs. This implies determining a stable +.. API. -.. toctree:: - :maxdepth: 2 +.. **Table of contents:** - Guide to using GCC's ARM target +.. .. toctree:: +.. :maxdepth: 2 -.. TODO LATER create, style, and host a pure Doxygen libmaple -.. reference docs. This implies determining a stable API. diff --git a/examples/qa-slave-shield.cpp b/examples/qa-slave-shield.cpp index 178b780..2da1c04 100644 --- a/examples/qa-slave-shield.cpp +++ b/examples/qa-slave-shield.cpp @@ -1,22 +1,20 @@ -// Slave mode for QA shield +// Slave mode for Quality Assurance test #include "wirish.h" -// FIXME generalize for Maple Native, Maple Mini (NUM_GPIO, Mini USB -// breakout pins, etc.) +#define INTER_TOGGLE_DELAY_NORMAL 5 +#define INTER_TOGGLE_DELAY_SLOW 80 -#define LED_PIN BOARD_LED_PIN -#define NUM_GPIO 38 // Ignore JTAG pins. +void interToggleDelay(void); void setup() { - /* Set up the LED to blink */ - pinMode(LED_PIN, OUTPUT); - digitalWrite(LED_PIN, HIGH); + pinMode(BOARD_LED_PIN, OUTPUT); + pinMode(BOARD_BUTTON_PIN, INPUT); - for(int i = 0; i < NUM_GPIO; i++) { - if (i == BOARD_LED_PIN) { + // All unused pins start out low. + for (int i = 0; i < BOARD_NR_GPIO_PINS; i++) { + if (boardUsesPin(i)) continue; - } pinMode(i, OUTPUT); digitalWrite(i, LOW); } @@ -28,17 +26,29 @@ void loop() { delay(100); toggleLED(); - for(int i = 0; i < NUM_GPIO; i++) { - if (i == BOARD_LED_PIN) { + for (int i = 0; i < BOARD_NR_GPIO_PINS; i++) { + if (boardUsesPin(i)) continue; - } - togglePin(i); - delay(5); - togglePin(i); - delay(5); + + // Bring just this pin high. + digitalWrite(i, HIGH); + // Give the master time to detect if any other pins also went high. + interToggleDelay(); + // Bring this pin back low again; all pins should now be low. + digitalWrite(i, LOW); + // Give the master time to detect if any pins are still high. + interToggleDelay(); } } +void interToggleDelay(void) { + if (digitalRead(BOARD_BUTTON_PIN)) { // don't pay the debouncing time + delay(INTER_TOGGLE_DELAY_SLOW); + } else { + delay(INTER_TOGGLE_DELAY_NORMAL); + } + } + // Force init to be called *first*, i.e. before static object allocation. // Otherwise, statically allocated objects that need libmaple may fail. __attribute__((constructor)) void premain() { @@ -48,7 +58,7 @@ __attribute__((constructor)) void premain() { int main(void) { setup(); - while (1) { + while (true) { loop(); } return 0; diff --git a/examples/test-session.cpp b/examples/test-session.cpp index 110b219..a4128ac 100644 --- a/examples/test-session.cpp +++ b/examples/test-session.cpp @@ -1,49 +1,23 @@ // Interactive Test Session for LeafLabs Maple // Copyright (c) 2010 LeafLabs LLC. // -// Useful for testing Maple features and troubleshooting. Select a COMM port -// (SerialUSB or Serial2) before compiling and then enter 'h' at the prompt -// for a list of commands. +// Useful for testing Maple features and troubleshooting. +// Communicates over SerialUSB. #include "wirish.h" -#define LED_PIN BOARD_LED_PIN -#define PWM_PIN 3 - -// choose your weapon -#define COMM SerialUSB -//#define COMM Serial2 -//#define COMM Serial3 - +// ASCII escape character #define ESC ((uint8)27) -int rate = 0; - -#if defined(BOARD_maple) || defined(BOARD_maple_RET6) -const uint8 pwm_pins[] = - {0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 14, 24, 25, 27, 28}; -const uint8 adc_pins[] = - {0, 1, 2, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 27, 28}; - -#elif defined(BOARD_maple_mini) -const uint8 pwm_pins[] = {3, 4, 5, 8, 9, 10, 11, 15, 16, 25, 26, 27}; -const uint8 adc_pins[] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 33}; +// Default USART baud rate +#define BAUD 9600 -#elif defined(BOARD_maple_native) -const uint8 pwm_pins[] = {12, 13, 14, 15, 22, 23, 24, 25, 37, 38, 45, - 46, 47, 48, 49, 50, 53, 54}; -const uint8 adc_pins[] = {6, 7, 8, 9, 10, 11, 39, 40, 41, 42, 43, 45, - 46, 47, 48, 49, 50, 51, 52, 53, 54}; -#else -#error "Board type has not been selected correctly" +uint8 gpio_state[BOARD_NR_GPIO_PINS]; -#endif - -uint8 gpio_state[NR_GPIO_PINS]; - -const char* const dummy_dat = ("qwertyuiopasdfghjklzxcvbnmmmmmm,./1234567890-=" - "qwertyuiopasdfghjklzxcvbnm,./1234567890"); +const char* dummy_data = ("qwertyuiopasdfghjklzxcvbnmmmmmm,./1234567890-=" + "qwertyuiopasdfghjklzxcvbnm,./1234567890"); +// Commands void cmd_print_help(void); void cmd_adc_stats(void); void cmd_stressful_adc_stats(void); @@ -55,37 +29,43 @@ void cmd_gpio_qa(void); void cmd_sequential_gpio_writes(void); void cmd_gpio_toggling(void); void cmd_sequential_pwm_test(void); -void cmd_pwm_sweep(void); void cmd_servo_sweep(void); +void cmd_board_info(void); +// Helper functions void measure_adc_noise(uint8 pin); void fast_gpio(int pin); -void do_serials(HardwareSerial **serials, int n, unsigned baud); +void usart_baud_test(HardwareSerial **serials, int n, unsigned baud); void init_all_timers(uint16 prescale); +void enable_usarts(void); +void disable_usarts(void); +void print_board_array(const char* msg, const uint8 arr[], int len); + +// -- setup() and loop() ------------------------------------------------------ void setup() { // Set up the LED to blink pinMode(BOARD_LED_PIN, OUTPUT); // Start up the serial ports - Serial1.begin(9600); - Serial2.begin(9600); - Serial3.begin(9600); - - // Send a message out over COMM interface - COMM.println(" "); - COMM.println(" __ __ _ _"); - COMM.println(" | \\/ | __ _ _ __ | | ___| |"); - COMM.println(" | |\\/| |/ _` | '_ \\| |/ _ \\ |"); - COMM.println(" | | | | (_| | |_) | | __/_|"); - COMM.println(" |_| |_|\\__,_| .__/|_|\\___(_)"); - COMM.println(" |_|"); - COMM.println(" by leaflabs"); - COMM.println(""); - COMM.println(""); - COMM.println("Maple interactive test program (type '?' for help)"); - COMM.println("----------------------------------------------------------"); - COMM.print("> "); + Serial1.begin(BAUD); + Serial2.begin(BAUD); + Serial3.begin(BAUD); + + // Send a message out over SerialUSB interface + SerialUSB.println(" "); + SerialUSB.println(" __ __ _ _"); + SerialUSB.println(" | \\/ | __ _ _ __ | | ___| |"); + SerialUSB.println(" | |\\/| |/ _` | '_ \\| |/ _ \\ |"); + SerialUSB.println(" | | | | (_| | |_) | | __/_|"); + SerialUSB.println(" |_| |_|\\__,_| .__/|_|\\___(_)"); + SerialUSB.println(" |_|"); + SerialUSB.println(" by leaflabs"); + SerialUSB.println(""); + SerialUSB.println(""); + SerialUSB.println("Maple interactive test program (type '?' for help)"); + SerialUSB.println("----------------------------------------------------------"); + SerialUSB.print("> "); } @@ -93,16 +73,16 @@ void loop () { toggleLED(); delay(100); - while(COMM.available()) { - uint8 input = COMM.read(); - COMM.println(input); + while (SerialUSB.available()) { + uint8 input = SerialUSB.read(); + SerialUSB.println(input); switch(input) { case '\r': break; case ' ': - COMM.println("spacebar, nice!"); + SerialUSB.println("spacebar, nice!"); break; case '?': @@ -125,7 +105,7 @@ void loop () { break; case '.': - while(!COMM.available()) { + while (!SerialUSB.available()) { Serial1.print("."); Serial2.print("."); Serial3.print("."); @@ -146,17 +126,17 @@ void loop () { break; case 'W': - while(!COMM.available()) { - Serial1.print(dummy_dat); - Serial2.print(dummy_dat); - Serial3.print(dummy_dat); + while (!SerialUSB.available()) { + Serial1.print(dummy_data); + Serial2.print(dummy_data); + Serial3.print(dummy_data); } break; case 'U': - COMM.println("Dumping data to USB. Press any key."); - while(!COMM.available()) { - SerialUSB.print(dummy_dat); + SerialUSB.println("Dumping data to USB. Press any key."); + while (!SerialUSB.available()) { + SerialUSB.print(dummy_data); } break; @@ -169,10 +149,10 @@ void loop () { break; case 'f': - COMM.println("Wiggling D4 as fast as possible in bursts. " + SerialUSB.println("Wiggling D4 as fast as possible in bursts. " "Press any key."); - pinMode(4,OUTPUT); - while(!COMM.available()) { + pinMode(4, OUTPUT); + while (!SerialUSB.available()) { fast_gpio(4); delay(1); } @@ -182,19 +162,19 @@ void loop () { cmd_sequential_pwm_test(); break; - case 'P': - cmd_pwm_sweep(); - break; - case '_': - COMM.println("Delaying for 5 seconds..."); + SerialUSB.println("Delaying for 5 seconds..."); delay(5000); break; + // Be sure to update cmd_print_help() if you implement these: + case 't': // TODO + SerialUSB.println("Unimplemented."); break; case 'T': // TODO + SerialUSB.println("Unimplemented."); break; case 's': @@ -202,26 +182,30 @@ void loop () { break; case 'd': - COMM.println("Pulling down D4, D22. Press any key."); - pinMode(22,INPUT_PULLDOWN); - pinMode(4,INPUT_PULLDOWN); - while(!COMM.available()) { + SerialUSB.println("Pulling down D4, D22. Press any key."); + pinMode(22, INPUT_PULLDOWN); + pinMode(4, INPUT_PULLDOWN); + while (!SerialUSB.available()) { continue; } - COMM.println("Pulling up D4, D22. Press any key."); - pinMode(22,INPUT_PULLUP); - pinMode(4,INPUT_PULLUP); - while(!COMM.available()) { + SerialUSB.println("Pulling up D4, D22. Press any key."); + pinMode(22, INPUT_PULLUP); + pinMode(4, INPUT_PULLUP); + while (!SerialUSB.available()) { continue; } - COMM.read(); - pinMode(4,OUTPUT); + SerialUSB.read(); + pinMode(4, OUTPUT); break; + // Be sure to update cmd_print_help() if you implement these: + case 'i': // TODO + SerialUSB.println("Unimplemented."); break; case 'I': // TODO + SerialUSB.println("Unimplemented."); break; case 'r': @@ -232,391 +216,496 @@ void loop () { cmd_sequential_adc_reads(); break; + case 'b': + cmd_board_info(); + break; + case '+': cmd_gpio_qa(); break; default: // ------------------------------- - COMM.print("Unexpected: "); - COMM.print(input); - COMM.println(", press h for help."); + SerialUSB.print("Unexpected: "); + SerialUSB.print(input); + SerialUSB.println(", press h for help."); } - COMM.print("> "); + SerialUSB.print("> "); } } -void cmd_print_help(void) { - COMM.println(""); - //COMM.println("Command Listing\t(# means any digit)"); - COMM.println("Command Listing"); - COMM.println("\t?: print this menu"); - COMM.println("\th: print this menu"); - COMM.println("\tw: print Hello World on all 3 USARTS"); - COMM.println("\tn: measure noise and do statistics"); - COMM.println("\tN: measure noise and do statistics with background stuff"); - COMM.println("\ta: show realtime ADC info"); - COMM.println("\t.: echo '.' until new input"); - COMM.println("\tu: print Hello World on USB"); - COMM.println("\t_: do as little as possible for a couple seconds (delay)"); - COMM.println("\tp: test all PWM channels sequentially"); - COMM.println("\tW: dump data as fast as possible on all 3 USARTS"); - COMM.println("\tU: dump data as fast as possible on USB"); - COMM.println("\tg: toggle all GPIOs sequentialy"); - COMM.println("\tG: toggle all GPIOs at the same time"); - COMM.println("\tf: toggle GPIO D4 as fast as possible in bursts"); - COMM.println("\tP: simultaneously test all PWM channels with different " - "speeds/sweeps"); - COMM.println("\tr: Monitor and print GPIO status changes"); - COMM.println("\ts: output a sweeping servo PWM on all PWM channels"); - COMM.println("\tm: output data on USART1 and USART3 with various rates"); - COMM.println("\t+: test shield mode (for QA, will disrupt Serial2!)"); - - COMM.println("Unimplemented:"); - COMM.println("\te: do everything all at once until new input"); - COMM.println("\tt: output a 1khz squarewave on all GPIOs"); - COMM.println("\tT: output a 1hz squarewave on all GPIOs"); - COMM.println("\ti: print out a bunch of info about system state"); - COMM.println("\tI: print out status of all headers"); -} - -void measure_adc_noise(uint8 pin) { // TODO - uint16 data[100]; - float mean = 0; - //float stddev = 0; - float delta = 0; - float M2 = 0; - pinMode(pin, INPUT_ANALOG); - - // variance algorithm from knuth; see wikipedia - // checked against python - for(int i = 0; i<100; i++) { - data[i] = analogRead(pin); - delta = data[i] - mean; - mean = mean + delta/(i+1); - M2 = M2 + delta*(data[i] - mean); - } +// -- Commands ---------------------------------------------------------------- - //sqrt is broken? - //stddev = sqrt(variance); - COMM.print("header: D"); COMM.print(pin,DEC); - COMM.print("\tn: "); COMM.print(100,DEC); - COMM.print("\tmean: "); COMM.print(mean); - COMM.print("\tvariance: "); COMM.println(M2/99.0); - pinMode(pin, OUTPUT); +void cmd_print_help(void) { + SerialUSB.println(""); + SerialUSB.println("Command Listing"); + SerialUSB.println("\t?: print this menu"); + SerialUSB.println("\th: print this menu"); + SerialUSB.println("\tw: print Hello World on all 3 USARTS"); + SerialUSB.println("\tn: measure noise and do statistics"); + SerialUSB.println("\tN: measure noise and do statistics with background stuff"); + SerialUSB.println("\ta: show realtime ADC info"); + SerialUSB.println("\t.: echo '.' until new input"); + SerialUSB.println("\tu: print Hello World on USB"); + SerialUSB.println("\t_: do as little as possible for a couple seconds (delay)"); + SerialUSB.println("\tp: test all PWM channels sequentially"); + SerialUSB.println("\tW: dump data as fast as possible on all 3 USARTS"); + SerialUSB.println("\tU: dump data as fast as possible on USB"); + SerialUSB.println("\tg: toggle GPIOs sequentially"); + SerialUSB.println("\tG: toggle GPIOs at the same time"); + SerialUSB.println("\tf: toggle pin 4 as fast as possible in bursts"); + SerialUSB.println("\tr: monitor and print GPIO status changes"); + SerialUSB.println("\ts: output a sweeping servo PWM on all PWM channels"); + SerialUSB.println("\tm: output data on USART1 and USART3 with various rates"); + SerialUSB.println("\tb: print information about the board."); + SerialUSB.println("\t+: test shield mode (for quality assurance testing)"); + + SerialUSB.println("Unimplemented:"); + SerialUSB.println("\te: do everything all at once until new input"); + SerialUSB.println("\tt: output a 1khz squarewave on all GPIOs"); + SerialUSB.println("\tT: output a 1hz squarewave on all GPIOs"); + SerialUSB.println("\ti: print out a bunch of info about system state"); + SerialUSB.println("\tI: print out status of all headers"); } void cmd_adc_stats(void) { - COMM.println("Taking ADC noise stats..."); + SerialUSB.println("Taking ADC noise stats."); digitalWrite(BOARD_LED_PIN, 0); - for(uint32 i = 0; ibegin(9600); - } - while (!COMM.available()) { - for (int i = 0; i < n; i++) { - serials[i]->println(dummy_dat); - if (serials[i]->available()) { - serials[i]->println(serials[i]->read()); - delay(1000); - } - } - } + SerialUSB.println("Resetting USART1 and USART3..."); + Serial1.begin(BAUD); + Serial3.begin(BAUD); } void cmd_gpio_monitoring(void) { - COMM.println("Monitoring GPIO read state changes. Press any key."); - digitalWrite(BOARD_LED_PIN, 0); - // make sure to skip the TX/RX headers - for(int i = 2; i= j) COMM.print("#"); - else COMM.print(" "); + SerialUSB.print("Sequentially reading most ADC ports."); + SerialUSB.println("Press any key for next port, or ESC to stop."); + + for (uint32 i = 0; i < BOARD_NR_ADC_PINS; i++) { + if (boardUsesPin(i)) + continue; + + SerialUSB.print("Reading pin "); + SerialUSB.print(boardADCPins[i], DEC); + SerialUSB.println("..."); + pinMode(boardADCPins[i], INPUT_ANALOG); + while (!SerialUSB.available()) { + int sample = analogRead(boardADCPins[i]); + SerialUSB.print(boardADCPins[i], DEC); + SerialUSB.print("\t"); + SerialUSB.print(sample, DEC); + SerialUSB.print("\t"); + SerialUSB.print("|"); + for (int j = 0; j < 4096; j += 100) { + if (sample >= j) { + SerialUSB.print("#"); + } else { + SerialUSB.print(" "); + } } - COMM.print("| "); - for(int j = 0; j<12; j++) { - if(sample & (1 << (11-j))) COMM.print("1"); - else COMM.print("0"); + SerialUSB.print("| "); + for (int j = 0; j < 12; j++) { + if (sample & (1 << (11 - j))) { + SerialUSB.print("1"); + } else { + SerialUSB.print("0"); + } } - COMM.println(""); + SerialUSB.println(""); + } + pinMode(boardADCPins[i], OUTPUT); + digitalWrite(boardADCPins[i], 0); + if (SerialUSB.read() == ESC) + break; + } +} + +bool test_single_pin_is_high(int high_pin, const char* err_msg) { + bool ok = true; + for (int i = 0; i < BOARD_NR_GPIO_PINS; i++) { + if (boardUsesPin(i)) continue; + + if (digitalRead(i) == HIGH && i != high_pin) { + SerialUSB.println(); + SerialUSB.print("\t*** FAILURE! pin "); + SerialUSB.print(i, DEC); + SerialUSB.print(' '); + SerialUSB.println(err_msg); + ok = false; } - pinMode(adc_pins[i], OUTPUT); - digitalWrite(adc_pins[i], 0); - if((uint8)COMM.read() == ESC) break; } + return ok; +} + +bool wait_for_low_transition(uint8 pin) { + uint32 start = millis(); + while (millis() - start < 2000) { + if (digitalRead(pin) == LOW) { + return true; + } + } + return false; } void cmd_gpio_qa(void) { - COMM.println("Doing QA testing for most GPIO pins..."); - digitalWrite(BOARD_LED_PIN, 0); - for(int i = 0; i 65500) rate = 0; - for(uint32 i = 2; i 5734) rate = 4096; - for(uint32 i = 2; i 5734) + rate = 4096; + for (uint32 i = 0; i < BOARD_NR_PWM_PINS; i++) { + if (boardUsesPin(i)) + continue; + pwmWrite(boardPWMPins[i], rate); } delay(20); } - for(uint32 i = 2; ibegin(baud); + } + while (!SerialUSB.available()) { + for (int i = 0; i < n; i++) { + serials[i]->println(dummy_data); + if (serials[i]->available()) { + serials[i]->println(serials[i]->read()); + delay(1000); + } + } + } } static uint16 init_all_timers_prescale = 0; @@ -630,14 +719,42 @@ void init_all_timers(uint16 prescale) { timer_foreach(set_prescale); } +void enable_usarts(void) { + // FIXME generalize after USART refactor + Serial1.begin(BAUD); + Serial2.begin(BAUD); + Serial3.begin(BAUD); +} + +void disable_usarts(void) { + // FIXME generalize after USART refactor + Serial1.end(); + Serial2.end(); + Serial3.end(); +} + +void print_board_array(const char* msg, const uint8 arr[], int len) { + SerialUSB.print("\t"); + SerialUSB.print(msg); + SerialUSB.print(" ("); + SerialUSB.print(len); + SerialUSB.print("): "); + for (int i = 0; i < len; i++) { + SerialUSB.print(arr[i], DEC); + if (i < len - 1) SerialUSB.print(", "); + } + SerialUSB.println(); +} + +// -- premain() and main() ---------------------------------------------------- + // Force init to be called *first*, i.e. before static object allocation. // Otherwise, statically allocated objects that need libmaple may fail. -__attribute__(( constructor )) void premain() { +__attribute__((constructor)) void premain() { init(); } -int main(void) -{ +int main(void) { setup(); while (1) { diff --git a/wirish/boards.cpp b/wirish/boards.cpp index 17f47c6..1c2b1c7 100644 --- a/wirish/boards.cpp +++ b/wirish/boards.cpp @@ -30,7 +30,7 @@ * at 72MHz. APB1 is clocked at 36MHz. */ -#include "wirish.h" +#include "boards.h" #include "flash.h" #include "rcc.h" @@ -46,15 +46,6 @@ static void setupClocks(void); static void setupADC(void); static void setupTimers(void); -/** - * @brief Generic board initialization function. - * - * This function is called before main(). It ensures that the clocks - * and peripherals are configured properly for use with wirish, then - * calls boardInit(). - * - * @see boardInit() - */ void init(void) { setupFlash(); setupClocks(); @@ -68,6 +59,17 @@ void init(void) { boardInit(); } +/* You could farm this out to the files in boards/ if e.g. it takes + * too long to test on Maple Native (all those FSMC pins...). */ +bool boardUsesPin(uint8 pin) { + for (int i = 0; i < BOARD_NR_USED_PINS; i++) { + if (pin == boardUsedPins[i]) { + return true; + } + } + return false; +} + static void setupFlash(void) { flash_enable_prefetch(); flash_set_latency(FLASH_WAIT_STATE_2); diff --git a/wirish/boards.h b/wirish/boards.h index 3d023ae..cec844f 100644 --- a/wirish/boards.h +++ b/wirish/boards.h @@ -63,8 +63,39 @@ enum { * @brief Maps each Maple pin to a corresponding stm32_pin_info. * @see stm32_pin_info */ -extern stm32_pin_info PIN_MAP[]; +extern const stm32_pin_info PIN_MAP[]; +/** + * @brief Pins capable of PWM output. + * + * Its length is BOARD_NR_PWM_PINS. + */ +extern const uint8 boardPWMPins[]; + +/** + * @brief Array of pins capable of analog input. + * + * Its length is BOARD_NR_ADC_PINS. + */ +extern const uint8 boardADCPins[]; + +/** + * @brief Pins which are connected to external hardware. + * + * For example, on Maple boards, it always at least includes + * BOARD_LED_PIN. Its length is BOARD_NR_USED_PINS. + */ +extern const uint8 boardUsedPins[]; + +/** + * @brief Generic board initialization function. + * + * This function is called before main(). It ensures that the clocks + * and peripherals are configured properly for use with wirish, then + * calls boardInit(). + * + * @see boardInit() + */ void init(void); /** @@ -78,6 +109,16 @@ void init(void); */ extern void boardInit(void); +/** + * @brief Test if a pin is used for a special purpose on your board. + * @param pin Pin to test + * @return true if the given pin is in boardUsedPins, and false otherwise. + * @see boardUsedPins + */ +bool boardUsesPin(uint8 pin); + +/* Include the appropriate private header from boards/: */ + #ifdef BOARD_maple #include "boards/maple.h" #elif defined(BOARD_maple_native) diff --git a/wirish/boards/maple.cpp b/wirish/boards/maple.cpp index ba2261b..5122290 100644 --- a/wirish/boards/maple.cpp +++ b/wirish/boards/maple.cpp @@ -40,7 +40,7 @@ void boardInit(void) { } -stm32_pin_info PIN_MAP[NR_GPIO_PINS] = { +extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { /* Top header */ @@ -91,4 +91,16 @@ stm32_pin_info PIN_MAP[NR_GPIO_PINS] = { {GPIOC, NULL, NULL, 9, 0, ADCx} /* D38/PC9 (BUT) */ }; +extern const uint8 boardPWMPins[] __FLASH__ = { + 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 14, 24, 25, 27, 28 +}; + +extern const uint8 boardADCPins[] __FLASH__ = { + 0, 1, 2, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 27, 28 +}; + +extern const uint8 boardUsedPins[] __FLASH__ = { + BOARD_LED_PIN, BOARD_BUTTON_PIN +}; + #endif diff --git a/wirish/boards/maple.h b/wirish/boards/maple.h index 519698b..1867de8 100644 --- a/wirish/boards/maple.h +++ b/wirish/boards/maple.h @@ -42,7 +42,7 @@ #define BOARD_LED_PIN 13 /* Number of USARTs/UARTs whose pins are broken out to headers */ -#define NR_USARTS 3 +#define BOARD_NR_USARTS 3 /* Default USART pin numbers (not considering AFIO remap) */ #define BOARD_USART1_TX_PIN 7 @@ -53,7 +53,17 @@ #define BOARD_USART3_RX_PIN 30 /* Total number of GPIO pins that are broken out to headers and - intended for general use. */ -#define NR_GPIO_PINS 39 + * intended for general use. */ +#define BOARD_NR_GPIO_PINS 39 + +/* Number of pins capable of PWM output */ +#define BOARD_NR_PWM_PINS 16 + +/* Number of pins capable of ADC conversion */ +#define BOARD_NR_ADC_PINS 15 + +/* Number of pins already connected to external hardware. For Maple, + * these are just BOARD_LED_PIN and BOARD_BUTTON_PIN. */ +#define BOARD_NR_USED_PINS 2 #endif diff --git a/wirish/boards/maple_RET6.cpp b/wirish/boards/maple_RET6.cpp index 962affc..fd67459 100644 --- a/wirish/boards/maple_RET6.cpp +++ b/wirish/boards/maple_RET6.cpp @@ -37,7 +37,7 @@ void boardInit(void) { } -stm32_pin_info PIN_MAP[NR_GPIO_PINS] = { +extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { /* Top header */ @@ -88,4 +88,16 @@ stm32_pin_info PIN_MAP[NR_GPIO_PINS] = { {GPIOC, TIMER8, NULL, 9, 4, ADCx} /* D38/PC9 (BUT) */ }; +extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { + 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 14, 24, 25, 27, 28 +}; + +extern const uint8 boardADCPins[BOARD_NR_ADC_PINS] __FLASH__ = { + 0, 1, 2, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 27, 28 +}; + +extern const uint8 boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = { + BOARD_LED_PIN, BOARD_BUTTON_PIN +}; + #endif diff --git a/wirish/boards/maple_RET6.h b/wirish/boards/maple_RET6.h index 63510c0..d91a4de 100644 --- a/wirish/boards/maple_RET6.h +++ b/wirish/boards/maple_RET6.h @@ -47,8 +47,7 @@ #define BOARD_LED_PIN 13 /* Note: UART4 and UART5 have pins which aren't broken out :( */ -#define NR_USARTS 3 - +#define BOARD_NR_USARTS 3 #define BOARD_USART1_TX_PIN 7 #define BOARD_USART1_RX_PIN 8 #define BOARD_USART2_TX_PIN 1 @@ -56,6 +55,9 @@ #define BOARD_USART3_TX_PIN 29 #define BOARD_USART3_RX_PIN 30 -#define NR_GPIO_PINS 39 +#define BOARD_NR_GPIO_PINS 39 +#define BOARD_NR_PWM_PINS 16 +#define BOARD_NR_ADC_PINS 15 +#define BOARD_NR_USED_PINS 2 #endif diff --git a/wirish/boards/maple_mini.cpp b/wirish/boards/maple_mini.cpp index 66a0997..cd2827d 100644 --- a/wirish/boards/maple_mini.cpp +++ b/wirish/boards/maple_mini.cpp @@ -41,7 +41,7 @@ void boardInit(void) { afio_mapr_swj_config(AFIO_MAPR_SWJ_NO_JTAG_NO_SW); } -stm32_pin_info PIN_MAP[NR_GPIO_PINS] = { +extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { /* Top header */ @@ -84,4 +84,19 @@ stm32_pin_info PIN_MAP[NR_GPIO_PINS] = { {GPIOB, TIMER3, ADC1, 1, 4, 9}, /* D33/PB1 */ }; +extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { + 3, 4, 5, 8, 9, 10, 11, 15, 16, 25, 26, 27 +}; + +extern const uint8 boardADCPins[BOARD_NR_ADC_PINS] __FLASH__ = { + 3, 4, 5, 6, 7, 8, 9, 10, 11, 33 // NB 33 is LED +}; + +#define USB_DP 23 +#define USB_DM 24 + +extern const uint8 boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = { + BOARD_LED_PIN, BOARD_BUTTON_PIN, USB_DP, USB_DM +}; + #endif diff --git a/wirish/boards/maple_mini.h b/wirish/boards/maple_mini.h index bfb92a5..8b7ae64 100644 --- a/wirish/boards/maple_mini.h +++ b/wirish/boards/maple_mini.h @@ -46,8 +46,7 @@ #define BOARD_BUTTON_PIN 32 #define BOARD_LED_PIN 33 -#define NR_USARTS 3 - +#define BOARD_NR_USARTS 3 #define BOARD_USART1_TX_PIN 26 #define BOARD_USART1_RX_PIN 25 #define BOARD_USART2_TX_PIN 9 @@ -55,6 +54,9 @@ #define BOARD_USART3_TX_PIN 1 #define BOARD_USART3_RX_PIN 0 -#define NR_GPIO_PINS 34 +#define BOARD_NR_GPIO_PINS 34 +#define BOARD_NR_PWM_PINS 12 +#define BOARD_NR_ADC_PINS 10 +#define BOARD_NR_USED_PINS 4 #endif diff --git a/wirish/boards/maple_native.cpp b/wirish/boards/maple_native.cpp index 75c6a2d..2813e91 100644 --- a/wirish/boards/maple_native.cpp +++ b/wirish/boards/maple_native.cpp @@ -39,7 +39,7 @@ void boardInit(void) { initNativeSRAM(); } -stm32_pin_info PIN_MAP[NR_GPIO_PINS] = { +extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { /* Top header */ @@ -152,4 +152,18 @@ stm32_pin_info PIN_MAP[NR_GPIO_PINS] = { {GPIOD, NULL, NULL, 10, 0, ADCx} /* D99/PD10 */ }; +extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { + 12, 13, 14, 15, 22, 23, 24, 25, 37, 38, 45, 46, 47, 48, 49, 50, 53, 54 +}; + +extern const uint8 boardADCPins[BOARD_NR_ADC_PINS] __FLASH__ = { + 6, 7, 8, 9, 10, 11, 39, 40, 41, 42, 43, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54 +}; + +/* FIXME! see comment by BOARD_NR_USED_PINS in maple_native.h */ +extern const uint8 boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = { + BOARD_LED_PIN, BOARD_BUTTON_PIN +}; + #endif diff --git a/wirish/boards/maple_native.h b/wirish/boards/maple_native.h index 21fc480..4e3ee82 100644 --- a/wirish/boards/maple_native.h +++ b/wirish/boards/maple_native.h @@ -43,11 +43,10 @@ #define CYCLES_PER_MICROSECOND 72 #define SYSTICK_RELOAD_VAL 71999 -#define BOARD_LED_PIN D21 -#define BOARD_BUTTON_PIN D18 - -#define NR_USARTS 5 +#define BOARD_LED_PIN 21 +#define BOARD_BUTTON_PIN 18 +#define BOARD_NR_USARTS 5 #define BOARD_USART1_TX_PIN 25 #define BOARD_USART1_RX_PIN 26 #define BOARD_USART2_TX_PIN 51 @@ -59,6 +58,12 @@ #define BOARD_UART5_TX_PIN 20 #define BOARD_UART5_RX_PIN 28 -#define NR_GPIO_PINS 100 +#define BOARD_NR_GPIO_PINS 100 +#define BOARD_NR_PWM_PINS 18 +#define BOARD_NR_ADC_PINS 21 +/* FIXME! this isn't true at all; almost all of the triple header pins + * are used by the FSMC by default. Fix this (and the corresponding + * boardUsedPins definition in maple_native.cpp) by QA time. */ +#define BOARD_NR_USED_PINS 2 #endif diff --git a/wirish/comm/HardwareSerial.cpp b/wirish/comm/HardwareSerial.cpp index 97a5ec3..8398878 100644 --- a/wirish/comm/HardwareSerial.cpp +++ b/wirish/comm/HardwareSerial.cpp @@ -32,10 +32,12 @@ #include "HardwareSerial.h" #include "usart.h" +// FIXME: High density device ports, usages of BOARD_USARTx_yX_PIN +// instead of holding onto a gpio_dev, tx_pin, rx_pin, timer_dev, and +// channel_num -- that stuff is all in the PIN_MAP. HardwareSerial Serial1(USART1, 4500000UL, GPIOA, 9, 10, TIMER1, 2); HardwareSerial Serial2(USART2, 2250000UL, GPIOA, 2, 3, TIMER2, 3); HardwareSerial Serial3(USART3, 2250000UL, GPIOB, 10, 11, NULL, 0); -// TODO: High density device ports HardwareSerial::HardwareSerial(uint8 usart_num, uint32 max_baud, diff --git a/wirish/ext_interrupts.cpp b/wirish/ext_interrupts.cpp index f9ccd39..557fffd 100644 --- a/wirish/ext_interrupts.cpp +++ b/wirish/ext_interrupts.cpp @@ -43,7 +43,7 @@ static inline exti_trigger_mode exti_out_mode(ExtIntTriggerMode mode); * @see ExtIntTriggerMode */ void attachInterrupt(uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode) { - if (pin >= NR_GPIO_PINS || !handler) { + if (pin >= BOARD_NR_GPIO_PINS || !handler) { return; } @@ -60,7 +60,7 @@ void attachInterrupt(uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode) { * @param pin Pin number to detach any interrupt from. */ void detachInterrupt(uint8 pin) { - if (pin >= NR_GPIO_PINS) { + if (pin >= BOARD_NR_GPIO_PINS) { return; } diff --git a/wirish/pwm.cpp b/wirish/pwm.cpp index 4c803d2..bf69bfb 100644 --- a/wirish/pwm.cpp +++ b/wirish/pwm.cpp @@ -34,7 +34,7 @@ void pwmWrite(uint8 pin, uint16 duty_cycle) { timer_dev *dev = PIN_MAP[pin].timer_device; - if (pin >= NR_GPIO_PINS || dev == NULL || dev->type == TIMER_BASIC) { + if (pin >= BOARD_NR_GPIO_PINS || dev == NULL || dev->type == TIMER_BASIC) { return; } diff --git a/wirish/wirish_digital.cpp b/wirish/wirish_digital.cpp index 115e91e..9b9f175 100644 --- a/wirish/wirish_digital.cpp +++ b/wirish/wirish_digital.cpp @@ -33,7 +33,7 @@ void pinMode(uint8 pin, WiringPinMode mode) { gpio_pin_mode outputMode; boolean pwm = false; - if (pin >= NR_GPIO_PINS) { + if (pin >= BOARD_NR_GPIO_PINS) { return; } @@ -83,7 +83,7 @@ void pinMode(uint8 pin, WiringPinMode mode) { uint32 digitalRead(uint8 pin) { - if (pin >= NR_GPIO_PINS) { + if (pin >= BOARD_NR_GPIO_PINS) { return 0; } @@ -92,7 +92,7 @@ uint32 digitalRead(uint8 pin) { } void digitalWrite(uint8 pin, uint8 val) { - if (pin >= NR_GPIO_PINS) { + if (pin >= BOARD_NR_GPIO_PINS) { return; } @@ -100,14 +100,14 @@ void digitalWrite(uint8 pin, uint8 val) { } void togglePin(uint8 pin) { - if (pin >= NR_GPIO_PINS) { + if (pin >= BOARD_NR_GPIO_PINS) { return; } gpio_toggle_bit(PIN_MAP[pin].gpio_device, PIN_MAP[pin].gpio_bit); } -#define BUTTON_DEBOUNCE_DELAY 10 +#define BUTTON_DEBOUNCE_DELAY 1 uint8 isButtonPressed() { if (digitalRead(BOARD_BUTTON_PIN)) { diff --git a/wirish/wirish_types.h b/wirish/wirish_types.h index 7d6e31a..475f470 100644 --- a/wirish/wirish_types.h +++ b/wirish/wirish_types.h @@ -30,6 +30,7 @@ * @brief Wirish library type definitions. */ +#include "libmaple_types.h" #include "gpio.h" #include "timer.h" #include "adc.h" @@ -56,4 +57,6 @@ typedef struct stm32_pin_info { uint8 adc_channel; /**< Pin ADC channel, or ADCx if none. */ } stm32_pin_info; +#define __FLASH__ __attr_flash + #endif -- cgit v1.2.3 From 300fa7122a9b896f507f637415c0fcd8effe2b88 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Wed, 30 Mar 2011 08:06:42 -0400 Subject: Hacks to get things to compile in the IDE. --- support/scripts/copy-to-ide | 7 +++- wirish/boards.h | 11 +++-- wirish/io.h | 3 +- wirish/time.cpp | 43 -------------------- wirish/time.h | 99 --------------------------------------------- wirish/wirish.h | 2 +- wirish/wirish_time.cpp | 43 ++++++++++++++++++++ wirish/wirish_time.h | 99 +++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 158 insertions(+), 149 deletions(-) delete mode 100644 wirish/time.cpp delete mode 100644 wirish/time.h create mode 100644 wirish/wirish_time.cpp create mode 100644 wirish/wirish_time.h diff --git a/support/scripts/copy-to-ide b/support/scripts/copy-to-ide index 5254974..674615e 100755 --- a/support/scripts/copy-to-ide +++ b/support/scripts/copy-to-ide @@ -23,6 +23,8 @@ LMAPLE_SRC="LICENSE ./wirish/*.cpp ./wirish/comm/*.cpp ./wirish/comm/*.h + ./wirish/boards/*.h + ./wirish/boards/*.cpp ./support/ld/common_ram.inc ./support/ld/common_rom.inc ./support/ld/libcs3_stm32_high_density.a @@ -52,6 +54,10 @@ cp -R $LMAPLE_SRC $DEST_CORES echo Copying over libraries cp -R libraries/* $DEST_LIBS +# libmaple version +echo Creating libmaple-version.txt +git show-ref HEAD | cut -c 1-10 > $DEST/libmaple-version.txt + # docs echo Deleting old reference directory contents rm -rf $DEST_REF/* @@ -62,5 +68,4 @@ echo Rebuilding documentation echo Copying over documentation cp -R $LMAPLE_DOCS_BUILD/* $DEST_REF - echo Done. diff --git a/wirish/boards.h b/wirish/boards.h index cec844f..8df7028 100644 --- a/wirish/boards.h +++ b/wirish/boards.h @@ -119,19 +119,22 @@ bool boardUsesPin(uint8 pin); /* Include the appropriate private header from boards/: */ +/* FIXME put boards/ before these paths once you stick make into the + * IDE; current situation is a hack. */ + #ifdef BOARD_maple -#include "boards/maple.h" +#include "maple.h" #elif defined(BOARD_maple_native) -#include "boards/maple_native.h" +#include "maple_native.h" #elif defined(BOARD_maple_mini) -#include "boards/maple_mini.h" +#include "maple_mini.h" #elif defined(BOARD_maple_RET6) /* * **NOT** MAPLE REV6. This the **Maple RET6 EDITION**, which is a * Maple with an STM32F103RET6 (...RET6) instead of an STM32F103RBT6 * (...RBT6) on it. Maple Rev6 (as of March 2011) DOES NOT EXIST. */ -#include "boards/maple_RET6.h" +#include "maple_RET6.h" #else #error "Board type has not been selected correctly." #endif diff --git a/wirish/io.h b/wirish/io.h index 4e415b5..137377d 100644 --- a/wirish/io.h +++ b/wirish/io.h @@ -33,7 +33,8 @@ #include "gpio.h" #include "adc.h" -#include "time.h" + +#include "wirish_time.h" /** * Specifies a GPIO pin behavior. diff --git a/wirish/time.cpp b/wirish/time.cpp deleted file mode 100644 index b5663b0..0000000 --- a/wirish/time.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * 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. - *****************************************************************************/ - -/** - * @brief Delay implementation. - */ - -#include "libmaple.h" -#include "systick.h" -#include "time.h" -#include "delay.h" - -void delay(unsigned long ms) { - uint32 i; - for (i = 0; i < ms; i++) { - delayMicroseconds(1000); - } -} - -void delayMicroseconds(uint32 us) { - delay_us(us); -} diff --git a/wirish/time.h b/wirish/time.h deleted file mode 100644 index a0c0c82..0000000 --- a/wirish/time.h +++ /dev/null @@ -1,99 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2010 Perry Hung. - * - * 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 time.h - * @brief Timing and delay functions. - */ - -#ifndef _TIME_H -#define _TIME_H - -#include "libmaple.h" -#include "nvic.h" -#include "systick.h" -#include "boards.h" - -#define US_PER_MS 1000 - -/** - * Returns time (in milliseconds) since the beginning of program - * execution. On overflow, restarts at 0. - * @see micros() - */ -static inline uint32 millis(void) { - return systick_timer_millis; -} - -/** - * Returns time (in microseconds) since the beginning of program - * execution. On overflow, restarts at 0. - * @see millis() - */ -static inline uint32 micros(void) { - uint32 ms; - uint32 cycle_cnt; - uint32 res; - - nvic_globalirq_disable(); - - cycle_cnt = systick_get_count(); - ms = millis(); - - nvic_globalirq_enable(); - - /* SYSTICK_RELOAD_VAL is 1 less than the number of cycles it - actually takes to complete a SysTick reload */ - res = (ms * US_PER_MS) + - (SYSTICK_RELOAD_VAL + 1 - cycle_cnt)/CYCLES_PER_MICROSECOND; - - return res; -} - -/** - * Delay for at least the given number of milliseconds. - * - * Interrupts, etc. may cause the actual number of milliseconds to - * exceed ms. However, this function will return no less than ms - * milliseconds from the time it is called. - * - * @param ms the number of milliseconds to delay. - * @see delayMicroseconds() - */ -void delay(unsigned long ms); - -/** - * Delay for at least the given number of microseconds. - * - * Interrupts, etc. may cause the actual number of microseconds to - * exceed us. However, this function will return no less than us - * microseconds from the time it is called. - * - * @param us the number of microseconds to delay. - * @see delay() - */ -void delayMicroseconds(uint32 us); - -#endif - diff --git a/wirish/wirish.h b/wirish/wirish.h index 880157d..4cc142d 100644 --- a/wirish/wirish.h +++ b/wirish/wirish.h @@ -40,7 +40,7 @@ #include "pwm.h" #include "ext_interrupts.h" #include "wirish_math.h" -#include "time.h" +#include "wirish_time.h" #include "HardwareSPI.h" #include "HardwareSerial.h" #include "usb_serial.h" diff --git a/wirish/wirish_time.cpp b/wirish/wirish_time.cpp new file mode 100644 index 0000000..2771e95 --- /dev/null +++ b/wirish/wirish_time.cpp @@ -0,0 +1,43 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * 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. + *****************************************************************************/ + +/** + * @brief Delay implementation. + */ + +#include "libmaple.h" +#include "systick.h" +#include "wirish_time.h" +#include "delay.h" + +void delay(unsigned long ms) { + uint32 i; + for (i = 0; i < ms; i++) { + delayMicroseconds(1000); + } +} + +void delayMicroseconds(uint32 us) { + delay_us(us); +} diff --git a/wirish/wirish_time.h b/wirish/wirish_time.h new file mode 100644 index 0000000..a0c0c82 --- /dev/null +++ b/wirish/wirish_time.h @@ -0,0 +1,99 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * + * 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 time.h + * @brief Timing and delay functions. + */ + +#ifndef _TIME_H +#define _TIME_H + +#include "libmaple.h" +#include "nvic.h" +#include "systick.h" +#include "boards.h" + +#define US_PER_MS 1000 + +/** + * Returns time (in milliseconds) since the beginning of program + * execution. On overflow, restarts at 0. + * @see micros() + */ +static inline uint32 millis(void) { + return systick_timer_millis; +} + +/** + * Returns time (in microseconds) since the beginning of program + * execution. On overflow, restarts at 0. + * @see millis() + */ +static inline uint32 micros(void) { + uint32 ms; + uint32 cycle_cnt; + uint32 res; + + nvic_globalirq_disable(); + + cycle_cnt = systick_get_count(); + ms = millis(); + + nvic_globalirq_enable(); + + /* SYSTICK_RELOAD_VAL is 1 less than the number of cycles it + actually takes to complete a SysTick reload */ + res = (ms * US_PER_MS) + + (SYSTICK_RELOAD_VAL + 1 - cycle_cnt)/CYCLES_PER_MICROSECOND; + + return res; +} + +/** + * Delay for at least the given number of milliseconds. + * + * Interrupts, etc. may cause the actual number of milliseconds to + * exceed ms. However, this function will return no less than ms + * milliseconds from the time it is called. + * + * @param ms the number of milliseconds to delay. + * @see delayMicroseconds() + */ +void delay(unsigned long ms); + +/** + * Delay for at least the given number of microseconds. + * + * Interrupts, etc. may cause the actual number of microseconds to + * exceed us. However, this function will return no less than us + * microseconds from the time it is called. + * + * @param us the number of microseconds to delay. + * @see delay() + */ +void delayMicroseconds(uint32 us); + +#endif + -- cgit v1.2.3 From 88e3ec703947a78a7f50b4ae38a8cabbd60dc8db Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Fri, 1 Apr 2011 00:52:58 -0400 Subject: Broke the build with previous commit; sorry. --- wirish/rules.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wirish/rules.mk b/wirish/rules.mk index 7715068..02906c7 100644 --- a/wirish/rules.mk +++ b/wirish/rules.mk @@ -27,7 +27,7 @@ cppSRCS_$(d) := wirish_math.cpp \ cxxabi-compat.cpp \ wirish_shift.cpp \ wirish_analog.cpp \ - time.cpp \ + wirish_time.cpp \ pwm.cpp \ ext_interrupts.cpp \ wirish_digital.cpp \ -- cgit v1.2.3 From 83e240f25035e34e4a43273122cb17d3f4725dac Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Fri, 1 Apr 2011 01:01:22 -0400 Subject: Redid Servo in terms of new timer.h. --- Makefile | 2 +- examples/test-servo.cpp | 152 +++++++++++++++++++++++++++++++++ libraries/Servo/Servo.cpp | 148 +++++++++++++++++--------------- libraries/Servo/Servo.h | 213 ++++++++++++++++++++++++++++++++-------------- libraries/Servo/rules.mk | 12 +-- 5 files changed, 384 insertions(+), 143 deletions(-) create mode 100644 examples/test-servo.cpp diff --git a/Makefile b/Makefile index 109a126..d31c9ed 100644 --- a/Makefile +++ b/Makefile @@ -97,7 +97,7 @@ endif LIBMAPLE_MODULES := $(SRCROOT)/libmaple LIBMAPLE_MODULES += $(SRCROOT)/wirish # Official libraries: -# LIBMAPLE_MODULES += $(SRCROOT)/libraries/Servo +LIBMAPLE_MODULES += $(SRCROOT)/libraries/Servo LIBMAPLE_MODULES += $(SRCROOT)/libraries/LiquidCrystal LIBMAPLE_MODULES += $(SRCROOT)/libraries/Wire diff --git a/examples/test-servo.cpp b/examples/test-servo.cpp new file mode 100644 index 0000000..b6b8cd5 --- /dev/null +++ b/examples/test-servo.cpp @@ -0,0 +1,152 @@ +/* + * Basic Servo library test program. + * + * Setup: + * + * - Connect a potentiometer to POT_PIN (default pin 15) + * - Connect an oscilloscope to SERVO_PIN1 (default pin 5) and + * SERVO_PIN2 (default pin 6). + * - Connect a serial monitor to SerialUSB + * + * The potentiometer controls the target angle for each of two Servo + * objects, one with angles in [-90, 90], and another in [0, 180]. + * Servo pulse width range is [1000, 2000]. + * + * Serial2 will tell you what inputs it's giving to each servo object, + * and some information it gets back. Pressing the button + * detaches/reattaches the Servo objects. + * + * Tests you should perform: + * + * - Check calculated pulse widths for each servo's target angle + * - Check that calculated pulse widths match actual pulse widths + * - Check that the period of the pulse train is roughly 20 ms + * - Check that the pulses stop when detached, and resume when reattached + * - Check that Servo::write() and Servo::read() round-trip properly + * + * This file is released into the public domain. + */ + +#include + +#include "wirish.h" + +#include "libraries/Servo/Servo.h" + +#define POT_PIN 15 + +#define MIN_PW 1000 +#define MAX_PW 2000 + +#define SERVO_PIN1 5 +#define MIN_ANGLE1 0 +#define MAX_ANGLE1 180 + +#define SERVO_PIN2 6 +#define MIN_ANGLE2 (-90) +#define MAX_ANGLE2 90 + +Servo servo1; +Servo servo2; + +#define BUF_SIZE 100 +char buf[BUF_SIZE]; + +#define print_buf(fmt, ...) do { \ + snprintf(buf, BUF_SIZE, fmt, __VA_ARGS__); \ + Serial2.println(buf); } while (0) + +int averageAnalogReads(int); +void attach(); +void detach(); + +void setup() { + pinMode(POT_PIN, INPUT_ANALOG); + pinMode(BOARD_BUTTON_PIN, INPUT); + pinMode(BOARD_LED_PIN, OUTPUT); + + Serial2.begin(9600); + + servo1.attach(SERVO_PIN1, MIN_PW, MAX_PW, MIN_ANGLE1, MAX_ANGLE1); + servo2.attach(SERVO_PIN2, MIN_PW, MAX_PW, MIN_ANGLE2, MAX_ANGLE2); + + ASSERT(servo1.attachedPin() == SERVO_PIN1); + ASSERT(servo2.attachedPin() == SERVO_PIN2); +} + +void loop() { + delay(250); + toggleLED(); + + if (isButtonPressed()) { + if (servo1.attached()) detach(); + else attach(); + } + + if (!servo1.attached()) return; + + int32 average = averageAnalogReads(250); + int16 angle1 = (int16)map(average, 0, 4095, MIN_ANGLE1, MAX_ANGLE1); + int16 angle2 = (int16)map(average, 0, 4095, MIN_ANGLE2, MAX_ANGLE2); + + print_buf("pot reading = %d, angle 1 = %d, angle 2 = %d.", + average, angle1, angle2); + + servo1.write(angle1); + servo2.write(angle2); + + int16 read1 = servo1.read(); + int16 read2 = servo2.read(); + + print_buf("write/read angle 1: %d/%d, angle 2: %d/%d", + angle1, read1, angle2, read2); + + ASSERT(abs(angle1 - read1) <= 1); + ASSERT(abs(angle2 - read2) <= 1); + + print_buf("pulse width 1: %d, pulse width 2: %d", + servo1.readMicroseconds(), servo2.readMicroseconds()); + + Serial2.println("\n--------------------------\n"); +} + +int32 averageAnalogReads(int n) { + uint64 total = 0; + + for (int i = 0; i < n; i++) { + total += analogRead(POT_PIN); + } + + return (int32)(total / n); +} + +void attach() { + Serial2.println("attaching"); + servo1.attach(SERVO_PIN1); + servo2.attach(SERVO_PIN2); + ASSERT(servo1.attachedPin() == SERVO_PIN1); + ASSERT(servo2.attachedPin() == SERVO_PIN2); +} + +void detach() { + Serial2.println("detaching"); + servo1.detach(); + servo2.detach(); + ASSERT(!servo1.attached()); + ASSERT(!servo2.attached()); +} + +// Force init to be called *first*, i.e. before static object allocation. +// Otherwise, statically allocated objects that need libmaple may fail. +__attribute__((constructor)) void premain() { + init(); +} + +int main(void) { + setup(); + + while (true) { + loop(); + } + return 0; +} diff --git a/libraries/Servo/Servo.cpp b/libraries/Servo/Servo.cpp index ae87b63..5122391 100644 --- a/libraries/Servo/Servo.cpp +++ b/libraries/Servo/Servo.cpp @@ -29,110 +29,120 @@ #include "pwm.h" #include "wirish_math.h" -// Configure prescaler and overflow for a 20msec period (could just -// use HardwareTimer::setPeriod(), but this lets conversions below -// happen more statically, in combination with an inlined map() -- a -// premature optimization? TODO profile speed/size tradeoff) -#define CYC_20MSEC (20000 * CYCLES_PER_MICROSECOND) -#define SERVO_PRE ((uint16)((CYC_20MSEC >> 16) + 1)) -#define SERVO_OVF ((uint16)((CYC_20MSEC / SERVO_PRE) - 1)) -#define SERVO_TAU_USEC \ - ((uint32)(((double)SERVO_OVF) * SERVO_PRE / CYCLES_PER_MICROSECOND + 0.5)) - -#define US_TO_COMPARE(us) ((uint16)map(us, 0, SERVO_TAU_USEC, 0, SERVO_OVF)) -#define COMPARE_TO_US(c) ((uint32)map(c, 0, SERVO_OVF, 0, SERVO_TAU_USEC)) - -#define ANGLE_TO_US(a) ((uint16)(map(a, 0, 180, this->min, this->max))) -#define US_TO_ANGLE(us) ((uint8)(map(us, this->min, this->max, 0, 180))) +// 20 millisecond period config. For a 1-based prescaler, +// +// (prescaler * overflow / CYC_MSEC) msec = 1 timer cycle = 20 msec +// => prescaler * overflow = 20 * CYC_MSEC +// +// This picks the smallest prescaler that allows an overflow < 2^16. +#define MAX_OVERFLOW ((1 << 16) - 1) +#define CYC_MSEC (1000 * CYCLES_PER_MICROSECOND) +#define TAU_MSEC 20 +#define TAU_USEC (TAU_MSEC * 1000) +#define TAU_CYC (TAU_MSEC * CYC_MSEC) +#define SERVO_PRESCALER (TAU_CYC / MAX_OVERFLOW + 1) +#define SERVO_OVERFLOW ((uint16)round((double)TAU_CYC / SERVO_PRESCALER)) + +// Unit conversions +#define US_TO_COMPARE(us) ((uint16)map((us), 0, TAU_USEC, 0, SERVO_OVERFLOW)) +#define COMPARE_TO_US(c) ((uint32)map((c), 0, SERVO_OVERFLOW, 0, TAU_USEC)) +#define ANGLE_TO_US(a) ((uint16)(map((a), this->minAngle, this->maxAngle, \ + this->minPW, this->maxPW))) +#define US_TO_ANGLE(us) ((int16)(map((us), this->minPW, this->maxPW, \ + this->minAngle, this->maxAngle))) Servo::Servo() { - this->pin = NOT_ATTACHED; - this->timer = 0; - this->channel = TIMER_INVALID; - this->min = SERVO_DEFAULT_MIN_PW; - this->max = SERVO_DEFAULT_MAX_PW; + this->resetFields(); } -bool Servo::attach(uint8_t pin) { - return this->attach(pin, SERVO_DEFAULT_MIN_PW, SERVO_DEFAULT_MAX_PW); -} +bool Servo::attach(uint8 pin, + uint16 minPW, + uint16 maxPW, + int16 minAngle, + int16 maxAngle) { + timer_dev *tdev = PIN_MAP[pin].timer_device; -bool Servo::attach(uint8_t pin, uint16_t min, uint16_t max) { - timer_dev_num timer_num = PIN_MAP[pin].timer_num; - uint32_t channel = PIN_MAP[pin].timer_chan; - if (timer_num == TIMER_INVALID) { - // don't reset any members or ASSERT(0), to keep driving any + if (tdev == NULL) { + // don't reset any fields or ASSERT(0), to keep driving any // previously attach()ed servo. return false; } + + if (this->attached()) { + this->detach(); + } + this->pin = pin; - this->timer = getTimer(timer_num); - this->channel = channel; - this->min = min; - this->max = max; + this->minPW = minPW; + this->maxPW = maxPW; + this->minAngle = minAngle; + this->maxAngle = maxAngle; pinMode(pin, PWM); - this->timer->pause(); - this->timer->setPrescaleFactor(SERVO_PRE); - this->timer->setOverflow(SERVO_OVF); - this->timer->generateUpdate(); - this->timer->resume(); + timer_pause(tdev); + timer_set_prescaler(tdev, SERVO_PRESCALER - 1); // prescaler is 1-based + timer_set_reload(tdev, SERVO_OVERFLOW); + timer_generate_update(tdev); + timer_resume(tdev); + return true; } bool Servo::detach() { - if (this->pin == NOT_ATTACHED) return false; + if (!this->attached()) { + return false; + } - this->timer->setChannelMode(this->channel, TIMER_DISABLED); + timer_dev *tdev = PIN_MAP[this->pin].timer_device; + uint8 tchan = PIN_MAP[this->pin].timer_channel; + timer_set_mode(tdev, tchan, TIMER_DISABLED); - this->pin = NOT_ATTACHED; - this->timer = 0; - this->channel = TIMER_INVALID; - this->min = SERVO_DEFAULT_MIN_PW; - this->max = SERVO_DEFAULT_MAX_PW; + this->resetFields(); return true; } -void Servo::write(unsigned int value) { - if (value < SERVO_MAX_WRITE_ANGLE) { - this->writeMicroseconds(ANGLE_TO_US(value)); - } else { - this->writeMicroseconds(value); - } +void Servo::write(int degrees) { + degrees = constrain(degrees, this->minAngle, this->maxAngle); + this->writeMicroseconds(ANGLE_TO_US(degrees)); } -void Servo::writeMicroseconds(uint16_t pulseWidth) { - if (this->pin == NOT_ATTACHED) { +int Servo::read() const { + int a = US_TO_ANGLE(this->readMicroseconds()); + // map() round-trips in a weird way we mostly correct for here; + // the round-trip is still sometimes off-by-one for write(1) and + // write(179). + return a == this->minAngle || a == this->maxAngle ? a : a + 1; +} + +void Servo::writeMicroseconds(uint16 pulseWidth) { + if (!this->attached()) { ASSERT(0); return; } - pulseWidth = constrain(pulseWidth, this->min, this->max); + pulseWidth = constrain(pulseWidth, this->minPW, this->maxPW); pwmWrite(this->pin, US_TO_COMPARE(pulseWidth)); } -int Servo::read() const { - if (this->pin == NOT_ATTACHED) { +uint16 Servo::readMicroseconds() const { + if (!this->attached()) { ASSERT(0); return 0; } - unsigned int pw = this->readMicroseconds(); - int a = US_TO_ANGLE(pw); - // map() round-trips in a weird way we correct for here - return a == 0 || a == 180 ? a : a + 1; -} + stm32_pin_info pin_info = PIN_MAP[this->pin]; + uint16 compare = timer_get_compare(pin_info.timer_device, + pin_info.timer_channel); -uint16_t Servo::readMicroseconds() const { - if (this->pin == NOT_ATTACHED) { - ASSERT(0); - return 0; - } + return COMPARE_TO_US(compare); +} - unsigned int compare = this->timer->getCompare(this->channel); - uint16_t c = COMPARE_TO_US(compare); - // map() round-trips in a weird way we correct for here - return c == 0 || c == 180 ? c : c + 1; +void Servo::resetFields(void) { + this->pin = NOT_ATTACHED; + this->minAngle = SERVO_DEFAULT_MIN_ANGLE; + this->maxAngle = SERVO_DEFAULT_MAX_ANGLE; + this->minPW = SERVO_DEFAULT_MIN_PW; + this->maxPW = SERVO_DEFAULT_MAX_PW; } diff --git a/libraries/Servo/Servo.h b/libraries/Servo/Servo.h index 583312e..f80339e 100644 --- a/libraries/Servo/Servo.h +++ b/libraries/Servo/Servo.h @@ -25,93 +25,178 @@ #ifndef _SERVO_H_ #define _SERVO_H_ -#include +#include "libmaple_types.h" +#include "timer.h" -#include "wirish.h" /* hack for IDE compile */ -#include "HardwareTimer.h" - -/* Note on Arduino compatibility: - - In the Arduino implementation, PWM is done "by hand" in the sense - that timer channels are hijacked in groups and an ISR is set which - toggles Servo::attach()ed pins using digitalWrite(). +#include "wirish_types.h" - While this scheme allows any pin to drive a servo, it chews up - cycles and complicates the programmer's notion of when a particular - timer channel will be in use. - - This implementation only allows Servo instances to Servo::attach() - to pins that already have a timer channel associated with them, and - just uses pwmWrite() to drive the wave. - - This introduces an incompatibility: while the Arduino - implementation of attach() returns the affected channel on success - and 0 on failure, this one returns true on success and false on - failure. +#ifdef MAPLE_IDE +#include "wirish.h" /* hack for IDE compile */ +#endif - RC Servos expect a pulse every 20ms. Since periods are set for - entire timers, rather than individual channels, attach()ing a Servo - to a pin can interfere with other pins associated with the same - timer. As always, the pin mapping mega table is your friend. +/* + * Note on Arduino compatibility: + * + * In the Arduino implementation, PWM is done "by hand" in the sense + * that timer channels are hijacked in groups and an ISR is set which + * toggles Servo::attach()ed pins using digitalWrite(). + * + * While this scheme allows any pin to drive a servo, it chews up + * cycles and complicates the programmer's notion of when a particular + * timer channel will be in use. + * + * This implementation only allows Servo instances to attach() to pins + * that already have a timer channel associated with them, and just + * uses pwmWrite() to drive the wave. + * + * This introduces an incompatibility: while the Arduino + * implementation of attach() returns the affected channel on success + * and 0 on failure, this one returns true on success and false on + * failure. + * + * RC Servos expect a pulse every 20ms. Since periods are set for + * entire timers, rather than individual channels, attach()ing a Servo + * to a pin can interfere with other pins associated with the same + * timer. As always, your board's pin map is your friend. */ // Pin number of unattached pins -#define NOT_ATTACHED (-1) +#define NOT_ATTACHED (-1) // Maximum angle in degrees you can write(), exclusive. Value chosen -// for Arduino compatibility. -#define SERVO_MAX_WRITE_ANGLE (200) - -// Default min (0 deg)/max(180 deg) pulse widths, in microseconds. -// Value chosen for Arduino compatibility. -#define SERVO_DEFAULT_MIN_PW (544) -#define SERVO_DEFAULT_MAX_PW (2400) +// for Arduino compatibility. This value is part of the public API; +// DO NOT CHANGE IT. +#define SERVO_MAX_WRITE_ANGLE 200 + +// Default min/max pulse widths (in microseconds) and angles (in +// degrees). Values chosen for Arduino compatibility. These values +// are part of the public API; DO NOT CHANGE THEM. +#define SERVO_DEFAULT_MIN_PW 544 +#define SERVO_DEFAULT_MAX_PW 2400 +#define SERVO_DEFAULT_MIN_ANGLE 0 +#define SERVO_DEFAULT_MAX_ANGLE 180 class Servo { public: + /** + * @brief Construct a new Servo instance. + * + * The new instance will not be attached to any pin. + */ Servo(); - /* Pin has to have a timer channel associated with it already; - * sets pinMode to PWM and returns true iff successful (failure - * when pin doesn't support PWM). doesn't detach any ISRs - * associated with timer channel. */ - bool attach(uint8_t pin); - - /* Like attach(int), but with (inclusive) min (0 degree) and max - * (180 degree) pulse widths, in microseconds. + /** + * @brief Associate this instance with a servomotor whose input is + * connected to pin. + * + * If this instance is already attached to a pin, it will be + * detached before being attached to the new pin. This function + * doesn't detach any interrupt attached with the pin's timer + * channel. + * + * @param pin Pin connected to the servo pulse wave input. This + * pin must be capable of PWM output. + * + * @param minPulseWidth Minimum pulse width to write to pin, in + * microseconds. This will be associated + * with a minAngle degree angle. Defaults to + * SERVO_DEFAULT_MIN_PW = 544. + * + * @param maxPulseWidth Maximum pulse width to write to pin, in + * microseconds. This will be associated + * with a maxAngle degree angle. Defaults to + * SERVO_DEFAULT_MAX_PW = 2400. + * + * @param minAngle Target angle (in degrees) associated with + * minPulseWidth. Defaults to + * SERVO_DEFAULT_MIN_ANGLE = 0. + * + * @param maxAngle Target angle (in degrees) associated with + * maxPulseWidth. Defaults to + * SERVO_DEFAULT_MAX_ANGLE = 180. + * + * @sideeffect May set pinMode(pin, PWM). + * + * @return true if successful, false when pin doesn't support PWM. */ - bool attach(uint8_t pin, uint16_t min, uint16_t max); - - /* Return pin number if currently attach()ed to a pin, - NOT_ATTACHED otherwise. */ - int attached() const { return pin; } + bool attach(uint8 pin, + uint16 minPulseWidth=SERVO_DEFAULT_MIN_PW, + uint16 maxPulseWidth=SERVO_DEFAULT_MAX_PW, + int16 minAngle=SERVO_DEFAULT_MIN_ANGLE, + int16 maxAngle=SERVO_DEFAULT_MAX_ANGLE); + + /** + * @brief Check if this instance is attached to a servo. + * @return true if this instance is attached to a servo, false otherwise. + * @see Servo::attachedPin() + */ + bool attached() const { return this->pin != NOT_ATTACHED; } - /* Stop driving the wave by disabling the output compare - interrupt. Returns true if this call did anything. */ + /** + * @brief Get the pin this instance is attached to. + * @return Pin number if currently attached to a pin, NOT_ATTACHED + * otherwise. + * @see Servo::attach() + */ + int attachedPin() const { return this->pin; } + + /** + * @brief Stop driving the servo pulse train. + * + * If not currently attached to a motor, this function has no effect. + * + * @return true if this call did anything, false otherwise. + */ bool detach(); - /* If value < MAX_WRITE_ANGLE, treated as an angle in degrees. - Otherwise, it's treated as a pulse width. */ - void write(unsigned int value); + /** + * @brief Set the servomotor target angle. + * + * @param angle Target angle, in degrees. If the target angle is + * outside the range specified at attach() time, it + * will be clamped to lie in that range. + * + * @see Servo::attach() + */ + void write(int angle); - /* If outside of [min, max] determined by attach(), it is clamped - to lie in that range. */ - void writeMicroseconds(uint16_t pulseWidth); - /* Return servo target angle, in degrees. This will lie between 0 - and 180. */ + /** + * Get the servomotor's target angle, in degrees. This will + * lie inside the range specified at attach() time. + * + * @see Servo::attach() + */ int read() const; - /* Returns the current pulse width, in microseconds. This will - lie within the [min, max] range. */ - uint16_t readMicroseconds() const; + /** + * @brief Set the pulse width, in microseconds. + * + * @param pulseWidth Pulse width to send to the servomotor, in + * microseconds. If outside of the range + * specified at attach() time, it is clamped to + * lie in that range. + * + * @see Servo::attach() + */ + void writeMicroseconds(uint16 pulseWidth); + + /** + * Get the current pulse width, in microseconds. This will + * lie within the range specified at attach() time. + * + * @see Servo::attach() + */ + uint16 readMicroseconds() const; private: - int8_t pin; - HardwareTimer *timer; - int channel; - uint16_t min; - uint16_t max; + int16 pin; + uint16 minPW; + uint16 maxPW; + int16 minAngle; + int16 maxAngle; + + void resetFields(void); }; #endif /* _SERVO_H_ */ diff --git a/libraries/Servo/rules.mk b/libraries/Servo/rules.mk index 13cd364..e013754 100644 --- a/libraries/Servo/rules.mk +++ b/libraries/Servo/rules.mk @@ -5,27 +5,21 @@ d := $(dir) BUILDDIRS += $(BUILD_PATH)/$(d) # Local flags -CFLAGS_$(d) := $(WIRISH_INCLUDES) $(LIBMAPLE_INCLUDES) +CXXFLAGS_$(d) := $(WIRISH_INCLUDES) $(LIBMAPLE_INCLUDES) # Local rules and targets cSRCS_$(d) := -# examples/UDPApp/udpapp.c \ -# examples/SocketApp/socketapp.c \ -# examples/WebClient/webclient.c \ -# examples/WebServer/webserver.c \ -# examples/Flash/webserver.c \ - cppSRCS_$(d) := Servo.cpp cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%) cppFILES_$(d) := $(cppSRCS_$(d):%=$(d)/%) OBJS_$(d) := $(cFILES_$(d):%.c=$(BUILD_PATH)/%.o) \ - $(cppFILES_$(d):%.cpp=$(BUILD_PATH)/%.o) + $(cppFILES_$(d):%.cpp=$(BUILD_PATH)/%.o) DEPS_$(d) := $(OBJS_$(d):%.o=%.d) -$(OBJS_$(d)): TGT_CFLAGS := $(CFLAGS_$(d)) +$(OBJS_$(d)): TGT_CXXFLAGS := $(CXXFLAGS_$(d)) TGT_BIN += $(OBJS_$(d)) -- cgit v1.2.3 From fb5a1612bcadf14460a88de08a065f4a5229f02f Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Mon, 4 Apr 2011 13:40:25 -0400 Subject: ring_buffer tweaks. Adding basic ring_buffer test (cherry-pick from master). Changing rb_safe_insert()'s type to match that of rb_push_insert(). (Makes it easier to pass around insertion functions.) --- examples/test-ring-buffer-insertion.cpp | 114 ++++++++++++++++++++++++++++++++ libmaple/ring_buffer.h | 8 ++- 2 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 examples/test-ring-buffer-insertion.cpp diff --git a/examples/test-ring-buffer-insertion.cpp b/examples/test-ring-buffer-insertion.cpp new file mode 100644 index 0000000..8372a96 --- /dev/null +++ b/examples/test-ring-buffer-insertion.cpp @@ -0,0 +1,114 @@ +/* + * Simple ring_buffer test. + * + * Does a basic test of functionality on rb_full_count(), rb_reset(), + * rb_push_insert(), and rb_safe_insert(). + * + * To test (no external hardware required): + * + * - Connect a serial monitor to SerialUSB + * - Press any key + * + * This file is released into the public domain. + */ + +#include "wirish.h" + +#include "ring_buffer.h" + +#define BUF_SIZE 64 +ring_buffer ring_buf; +ring_buffer *rb; +uint8 rb_buffer[BUF_SIZE]; + +void test_rb_push_insert(int num_bytes_to_insert); +void test_rb_safe_insert(int num_bytes_to_insert); +void test_rb_insertion_function(int num_bytes_to_insert, + int (*insertion_fn)(ring_buffer*, uint8), + const char insertion_fn_name[]); +void print_rb_contents(void); + +void setup() { + rb = &ring_buf; + rb_init(rb, BUF_SIZE, rb_buffer); + + while (!SerialUSB.available()) + ; + + SerialUSB.println("Beginning test."); + SerialUSB.println(); +} + +void loop() { + test_rb_push_insert(63); + SerialUSB.println("------------------------------"); + test_rb_push_insert(64); + SerialUSB.println("------------------------------"); + test_rb_safe_insert(63); + SerialUSB.println("------------------------------"); + test_rb_safe_insert(64); + SerialUSB.println("------------------------------"); + + SerialUSB.println(); + SerialUSB.println("Test finished."); + while (true) + ; +} + +void test_rb_push_insert(int num_bytes_to_insert) { + test_rb_insertion_function(num_bytes_to_insert, + rb_push_insert, + "rb_push_insert()"); +} + +void test_rb_safe_insert(int num_bytes_to_insert) { + test_rb_insertion_function(num_bytes_to_insert, + rb_safe_insert, + "rb_safe_insert()"); +} + +void test_rb_insertion_function(int num_bytes_to_insert, + int (*insertion_fn)(ring_buffer *, uint8), + const char insertion_fn_name[]) { + SerialUSB.println("resetting ring buffer."); + rb_reset(rb); + print_rb_contents(); + + SerialUSB.print(insertion_fn_name); + SerialUSB.print("-ing "); + SerialUSB.print(num_bytes_to_insert); + SerialUSB.println(" bytes."); + for (uint8 i = 1; i <= num_bytes_to_insert; i++) + insertion_fn(rb, i); + + uint16 count = rb_full_count(rb); + SerialUSB.print("rb_full_count(rb) = "); + SerialUSB.println(count); + + print_rb_contents(); +} + +void print_rb_contents() { + uint16 count = rb_full_count(rb); + SerialUSB.print("ring buffer contents: "); + for (uint16 i = 0; i < count; i++) { + SerialUSB.print((int)rb_remove(rb)); + if (i < count - 1) SerialUSB.print(", "); + } + SerialUSB.println(); +} + +// Force init to be called *first*, i.e. before static object allocation. +// Otherwise, statically allocated objects that need libmaple may fail. +__attribute__((constructor)) void premain() { + init(); +} + +int main(void) { + setup(); + + while (true) { + loop(); + } + return 0; +} diff --git a/libmaple/ring_buffer.h b/libmaple/ring_buffer.h index eadb292..9f35d3d 100644 --- a/libmaple/ring_buffer.h +++ b/libmaple/ring_buffer.h @@ -118,8 +118,12 @@ static inline int16 rb_safe_remove(ring_buffer *rb) { } /** - * If rb is not full, appends element and returns true; otherwise, - * does nothing and returns false. */ + * @brief Attempt to insert an element into a ring buffer. + * + * @brief rb Buffer to insert into. + * @brief element Value to insert into rb. + * @sideeffect If rb is not full, appends element onto buffer. + * @return If element was appended, then true; otherwise, false. */ static inline int rb_safe_insert(ring_buffer *rb, uint8 element) { if (rb_is_full(rb)) { return 0; -- cgit v1.2.3 From cf4322804a94ab81b057ec1c0e2f397338b5ab69 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Fri, 1 Apr 2011 01:16:35 -0400 Subject: ring_buffer.h function comments converted to Doxygen --- libmaple/ring_buffer.h | 52 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/libmaple/ring_buffer.h b/libmaple/ring_buffer.h index 9f35d3d..101f010 100644 --- a/libmaple/ring_buffer.h +++ b/libmaple/ring_buffer.h @@ -67,15 +67,17 @@ typedef struct ring_buffer { * * @param buf Buffer to store items into */ -__attribute__((unused)) -static void rb_init(ring_buffer *rb, uint16 size, uint8 *buf) { +static inline void rb_init(ring_buffer *rb, uint16 size, uint8 *buf) { rb->head = 0; rb->tail = 0; rb->size = size - 1; rb->buf = buf; } -/** Return the number of elements stored in the ring buffer. */ +/** + * @brief Return the number of elements stored in the ring buffer. + * @param rb Buffer whose elements to count. + */ static inline uint16 rb_full_count(ring_buffer *rb) { volatile ring_buffer *arb = rb; int32 size = arb->tail - arb->head; @@ -85,24 +87,37 @@ static inline uint16 rb_full_count(ring_buffer *rb) { return (uint16)size; } -/** Return true if and only if the ring buffer is full. */ +/** + * @brief Returns true if and only if the ring buffer is full. + * @brief rb Buffer to test. + */ static inline int rb_is_full(ring_buffer *rb) { return (rb->tail + 1 == rb->head) || (rb->tail == rb->size && rb->head == 0); } -/** Return true if and only if the ring buffer is empty. */ +/** + * @brief Returns true if and only if the ring buffer is empty. + * @param rb Buffer to test. + */ static inline int rb_is_empty(ring_buffer *rb) { return rb->head == rb->tail; } -/** Append element onto the end of the ring buffer. */ +/** + * Append element onto the end of a ring buffer. + * @param rb Buffer to append onto. + * @param element Value to append. + */ static inline void rb_insert(ring_buffer *rb, uint8 element) { 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. */ +/** + * @brief Remove and return the first item from a ring buffer. + * @param rb Buffer to remove from, must contain at least one element. + */ static inline uint8 rb_remove(ring_buffer *rb) { uint8 ch = rb->buf[rb->head]; rb->head = (rb->head == rb->size) ? 0 : rb->head + 1; @@ -110,8 +125,12 @@ static inline uint8 rb_remove(ring_buffer *rb) { } /** + * @brief Attempt to remove the first item from a ring buffer. + * * If the ring buffer is nonempty, removes and returns its first item. * If it is empty, does nothing and returns a negative value. + * + * @param rb Buffer to attempt to remove from. */ static inline int16 rb_safe_remove(ring_buffer *rb) { return rb_is_empty(rb) ? -1 : rb_remove(rb); @@ -133,12 +152,16 @@ static inline int rb_safe_insert(ring_buffer *rb, uint8 element) { } /** - * 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 + * @brief 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. */ + * @param rb Ring buffer to insert into. + * @param element Value to insert into ring buffer. + * @return 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)) { @@ -148,7 +171,10 @@ static inline int rb_push_insert(ring_buffer *rb, uint8 element) { return ret; } -/** Discard all items from the buffer */ +/** + * @brief Discard all items from a ring buffer. + * @param rb Ring buffer to discard all items from. + */ static inline void rb_reset(ring_buffer *rb) { rb->tail = rb->head; } @@ -157,7 +183,5 @@ static inline void rb_reset(ring_buffer *rb) { } // extern "C" #endif - - #endif -- cgit v1.2.3 From 6229da7a3ec40fb7d87c0c4edd38bc32da36ef13 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Fri, 1 Apr 2011 02:33:53 -0400 Subject: NVIC and SCB refactor --- Makefile | 49 +++++------ libmaple/nvic.c | 83 ++++++------------- libmaple/nvic.h | 239 +++++++++++++++++++++++++++++++++--------------------- libmaple/rules.mk | 2 +- libmaple/scb.h | 48 ++++++----- libmaple/util.c | 4 +- wirish/boards.cpp | 15 +++- 7 files changed, 232 insertions(+), 208 deletions(-) diff --git a/Makefile b/Makefile index d31c9ed..d0cead4 100644 --- a/Makefile +++ b/Makefile @@ -39,6 +39,20 @@ ifeq ($(BOARD), maple_RET6) DENSITY := STM32_HIGH_DENSITY endif +# Some target specific things +ifeq ($(MEMORY_TARGET), ram) + LDSCRIPT := $(BOARD)/ram.ld + VECT_BASE_ADDR := VECT_TAB_RAM +endif +ifeq ($(MEMORY_TARGET), flash) + LDSCRIPT := $(BOARD)/flash.ld + VECT_BASE_ADDR := VECT_TAB_FLASH +endif +ifeq ($(MEMORY_TARGET), jtag) + LDSCRIPT := $(BOARD)/jtag.ld + VECT_BASE_ADDR := VECT_TAB_BASE +endif + # Useful paths ifeq ($(LIB_MAPLE_HOME),) SRCROOT := . @@ -51,24 +65,17 @@ SUPPORT_PATH := $(SRCROOT)/support # Compilation flags. # FIXME remove the ERROR_LED config -GLOBAL_CFLAGS := -Os -g3 -gdwarf-2 -mcpu=cortex-m3 -mthumb -march=armv7-m \ - -nostdlib \ - -ffunction-sections -fdata-sections -Wl,--gc-sections \ - -DBOARD_$(BOARD) -DMCU_$(MCU) \ - -DERROR_LED_PORT=$(ERROR_LED_PORT) \ - -DERROR_LED_PIN=$(ERROR_LED_PIN) \ - -D$(DENSITY) -GLOBAL_CXXFLAGS := -fno-rtti -fno-exceptions -Wall \ +GLOBAL_FLAGS := -D$(VECT_BASE_ADDR) \ -DBOARD_$(BOARD) -DMCU_$(MCU) \ -DERROR_LED_PORT=$(ERROR_LED_PORT) \ -DERROR_LED_PIN=$(ERROR_LED_PIN) \ - -D$(DENSITY) + -D$(DENSITY) +GLOBAL_CFLAGS := -Os -g3 -gdwarf-2 -mcpu=cortex-m3 -mthumb -march=armv7-m \ + -nostdlib -ffunction-sections -fdata-sections \ + -Wl,--gc-sections $(GLOBAL_FLAGS) +GLOBAL_CXXFLAGS := -fno-rtti -fno-exceptions -Wall $(GLOBAL_FLAGS) GLOBAL_ASFLAGS := -mcpu=cortex-m3 -march=armv7-m -mthumb \ - -x assembler-with-cpp \ - -DBOARD_$(BOARD) -DMCU_$(MCU) \ - -DERROR_LED_PORT=$(ERROR_LED_PORT) \ - -DERROR_LED_PIN=$(ERROR_LED_PIN) \ - -D$(DENSITY) + -x assembler-with-cpp $(GLOBAL_FLAGS) LDDIR := $(SUPPORT_PATH)/ld LDFLAGS = -T$(LDDIR)/$(LDSCRIPT) -L$(LDDIR) \ @@ -79,20 +86,6 @@ LDFLAGS = -T$(LDDIR)/$(LDSCRIPT) -L$(LDDIR) \ include $(SUPPORT_PATH)/make/build-rules.mk include $(SUPPORT_PATH)/make/build-templates.mk -# Some target specific things -ifeq ($(MEMORY_TARGET), ram) - LDSCRIPT := $(BOARD)/ram.ld - VECT_BASE_ADDR := VECT_TAB_RAM -endif -ifeq ($(MEMORY_TARGET), flash) - LDSCRIPT := $(BOARD)/flash.ld - VECT_BASE_ADDR := VECT_TAB_FLASH -endif -ifeq ($(MEMORY_TARGET), jtag) - LDSCRIPT := $(BOARD)/jtag.ld - VECT_BASE_ADDR := VECT_TAB_BASE -endif - # Set all submodules here LIBMAPLE_MODULES := $(SRCROOT)/libmaple LIBMAPLE_MODULES += $(SRCROOT)/wirish diff --git a/libmaple/nvic.c b/libmaple/nvic.c index 28ca169..28db96a 100644 --- a/libmaple/nvic.c +++ b/libmaple/nvic.c @@ -26,89 +26,54 @@ * @brief Nested interrupt controller routines */ -#include "libmaple.h" -#include "scb.h" #include "nvic.h" -#include "systick.h" - -void nvic_set_vector_table(uint32 addr, uint32 offset) { - __write(SCB_VTOR, (uint32)addr | (offset & 0x1FFFFF80)); -} - -/** - * @brief turn on interrupt number n - * @param n interrupt number - */ -void nvic_irq_enable(uint32 n) { - uint32 *iser = &((uint32*)NVIC_ISER0)[(n/32)]; - __write(iser, BIT(n % 32)); -} - -/** - * @brief turn off interrupt number n - * @param n interrupt number - */ -void nvic_irq_disable(uint32 n) { - uint32 *icer = &((uint32*)NVIC_ICER0)[(n/32)]; - __write(icer, BIT(n % 32)); -} - -void nvic_irq_disable_all(void) { - /* 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); -} - +#include "scb.h" +#include "stm32.h" /** * @brief Set interrupt priority for an interrupt line - * Note: The STM32 only implements 4 bits of priority, ignoring - * the lower 4 bits. This means there are only 16 levels of priority. - * Bits[3:0] read as zero and ignore writes. + * + * Note: The STM32 only implements 4 bits of priority, ignoring the + * lower 4 bits. This means there are only 16 levels of priority. + * Bits[3:0] read as zero and ignore writes. + * * @param irqn device to set - * @param priority priority to set, 0 being highest priority and 15 being - * lowest. + * @param priority Priority to set, 0 being highest priority and 15 + * being lowest. */ -void nvic_irq_set_priority(int32 irqn, uint8 priority) { +void nvic_irq_set_priority(nvic_irq_num irqn, uint8 priority) { if (irqn < 0) { /* This interrupt is in the system handler block */ - SCB->SHP[((uint32)irqn & 0xF) - 4] = (priority & 0xF) << 4; + SCB_BASE->SHP[((uint32)irqn & 0xF) - 4] = (priority & 0xF) << 4; } else { - NVIC->IP[irqn] = (priority & 0xF) << 4; + NVIC_BASE->IP[irqn] = (priority & 0xF) << 4; } } /** - * @brief Initialize the NVIC according to VECT_TAB_FLASH, - * VECT_TAB_RAM, or VECT_TAB_BASE. + * @brief Initialize the NVIC + * @param vect_table_address Vector table base address. */ -void nvic_init(void) { +void nvic_init(uint32 vector_table_address, uint32 offset) { uint32 i; -#ifdef VECT_TAB_FLASH - nvic_set_vector_table(USER_ADDR_ROM, 0x0); -#elif defined VECT_TAB_RAM - nvic_set_vector_table(USER_ADDR_RAM, 0x0); -#elif defined VECT_TAB_BASE - nvic_set_vector_table(((uint32)0x08000000), 0x0); -#else -#error "You must set a base address for the vector table!" -#endif + nvic_set_vector_table(vector_table_address, offset); /* * Lower priority level for all peripheral interrupts to lowest * possible. */ for (i = 0; i < NR_INTERRUPTS; i++) { - nvic_irq_set_priority(i, 0xF); + nvic_irq_set_priority((nvic_irq_num)i, 0xF); } /* Lower systick interrupt priority to lowest level */ nvic_irq_set_priority(NVIC_SYSTICK, 0xF); } + +/** + * Reset the vector table address. + */ +void nvic_set_vector_table(uint32 addr, uint32 offset) { + SCB_BASE->VTOR = addr | (offset & 0x1FFFFF80); +} diff --git a/libmaple/nvic.h b/libmaple/nvic.h index cbcd49c..a889f4b 100644 --- a/libmaple/nvic.h +++ b/libmaple/nvic.h @@ -24,115 +24,170 @@ /** * @file nvic.h - * @brief Nested interrupt controller defines and prototypes + * @brief Nested vector interrupt controller support. */ #ifndef _NVIC_H_ #define _NVIC_H_ +#include "libmaple_types.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 -/* NVIC_ISER2 only on connectivity line */ +/** NVIC register map type. */ +typedef struct nvic_reg_map { + __io uint32 ISER[8]; /**< Interrupt Set Enable Registers */ + uint32 RESERVED0[24]; /**< Reserved */ + __io uint32 ICER[8]; /**< Interrupt Clear Enable Registers */ + uint32 RSERVED1[24]; /**< Reserved */ + __io uint32 ISPR[8]; /**< Interrupt Set Pending Registers */ + uint32 RESERVED2[24]; /**< Reserved */ + __io uint32 ICPR[8]; /**< Interrupt Clear Pending Registers */ + uint32 RESERVED3[24]; /**< Reserved */ + __io uint32 IABR[8]; /**< Interrupt Active bit Registers */ + uint32 RESERVED4[56]; /**< Reserved */ + __io uint8 IP[240]; /**< Interrupt Priority Registers */ + uint32 RESERVED5[644]; /**< Reserved */ + __io uint32 STIR; /**< Software Trigger Interrupt Registers */ +} nvic_reg_map; -/* NVIC Interrupt Clear registers */ -#define NVIC_ICER0 0xE000E180 -#define NVIC_ICER1 0xE000E184 -/* NVIC_ICER2 only on connectivity line */ +/** NVIC register map base pointer. */ +#define NVIC_BASE ((nvic_reg_map*)0xE000E100) -/* NVIC Priority */ -#define NVIC_PRI_BASE 0xE000E400 +/** + * Interrupt vector table interrupt numbers. Each enumerator is the + * position of the corresponding interrupt in the vector table. */ +typedef enum nvic_irq_num { + NVIC_NMI = -14, /**< Non-maskable interrupt */ + NVIC_HARDFAULT = -13, /**< Hard fault (all class of fault) */ + NVIC_MEM_MANAGE = -12, /**< Memory management */ + NVIC_BUS_FAULT = -11, /**< Bus fault: prefetch fault, memory + access fault. */ + NVIC_USAGE_FAULT = -10, /**< Usage fault: Undefined instruction or + illegal state. */ + NVIC_SVC = -5, /**< System service call via SWI insruction */ + NVIC_DEBUG_MON = -4, /**< Debug monitor */ + NVIC_PEND_SVC = -2, /**< Pendable request for system service */ + NVIC_SYSTICK = -1, /**< System tick timer */ + NVIC_WWDG = 0, /**< Window watchdog interrupt */ + NVIC_PVD = 1, /**< PVD through EXTI line detection */ + NVIC_TAMPER = 2, /**< Tamper */ + NVIC_RTC = 3, /**< Real-time clock */ + NVIC_FLASH = 4, /**< Flash */ + NVIC_RCC = 5, /**< Reset and clock control */ + NVIC_EXTI0 = 6, /**< EXTI line 0 */ + NVIC_EXTI1 = 7, /**< EXTI line 1 */ + NVIC_EXTI2 = 8, /**< EXTI line 2 */ + NVIC_EXTI3 = 9, /**< EXTI line 3 */ + NVIC_EXTI4 = 10, /**< EXTI line 4 */ + NVIC_DMA_CH1 = 11, /**< DMA1 channel 1 */ + NVIC_DMA_CH2 = 12, /**< DMA1 channel 2 */ + NVIC_DMA_CH3 = 13, /**< DMA1 channel 3 */ + NVIC_DMA_CH4 = 14, /**< DMA1 channel 4 */ + NVIC_DMA_CH5 = 15, /**< DMA1 channel 5 */ + NVIC_DMA_CH6 = 16, /**< DMA1 channel 6 */ + NVIC_DMA_CH7 = 17, /**< DMA1 channel 7 */ + NVIC_ADC1_2 = 18, /**< ADC1 and ADC2 */ + NVIC_USB_HP_CAN_TX = 19, /**< USB high priority or CAN TX */ + NVIC_USB_LP_CAN_RX0 = 20, /**< USB low priority or CAN RX0 */ + NVIC_CAN_RX1 = 21, /**< CAN RX1 */ + NVIC_CAN_SCE = 22, /**< CAN SCE */ + NVIC_EXTI9_5 = 23, /**< EXTI line [9:5] */ + NVIC_TIMER1_BRK = 24, /**< Timer 1 break */ + NVIC_TIMER1_UP = 25, /**< Timer 1 update */ + NVIC_TIMER1_TRG_COM = 26, /**< Timer 1 trigger and commutation */ + NVIC_TIMER1_CC = 27, /**< Timer 1 capture/compare */ + NVIC_TIMER2 = 28, /**< Timer 2 */ + NVIC_TIMER3 = 29, /**< Timer 3 */ + NVIC_TIMER4 = 30, /**< Timer 4 */ + NVIC_I2C1_EV = 31, /**< I2C1 event */ + NVIC_I2C1_ER = 32, /**< I2C1 error */ + NVIC_I2C2_EV = 33, /**< I2C2 event */ + NVIC_I2C2_ER = 34, /**< I2C2 error */ + NVIC_SPI1 = 35, /**< SPI1 */ + NVIC_SPI2 = 36, /**< SPI2 */ + NVIC_USART1 = 37, /**< USART1 */ + NVIC_USART2 = 38, /**< USART2 */ + NVIC_USART3 = 39, /**< USART3 */ + NVIC_EXTI15_10 = 40, /**< EXTI line [15:10] */ + NVIC_RTCALARM = 41, /**< RTC alarm through EXTI line */ + NVIC_USBWAKEUP = 42, /**< USB wakeup from suspend through + EXTI line */ + NVIC_TIMER8_BRK = 43, /**< Timer 8 break */ + NVIC_TIMER8_UP = 44, /**< Timer 8 update */ + NVIC_TIMER8_TRG_COM = 45, /**< Timer 8 trigger and commutation */ + NVIC_TIMER8_CC = 46, /**< Timer 8 capture/compare */ +#ifdef STM32_HIGH_DENSITY + NVIC_ADC3 = 47, /**< ADC3 */ + NVIC_FSMC = 48, /**< FSMC */ + NVIC_SDIO = 49, /**< SDIO */ + NVIC_TIMER5 = 50, /**< Timer 5 */ + NVIC_SPI3 = 51, /**< SPI3 */ + NVIC_UART4 = 52, /**< UART4 */ + NVIC_UART5 = 53, /**< UART5 */ + NVIC_TIMER6 = 54, /**< Timer 6 */ + NVIC_TIMER7 = 55, /**< Timer 7 */ + NVIC_DMA2_CH1 = 56, /**< DMA2 channel 1 */ + NVIC_DMA2_CH2 = 57, /**< DMA2 channel 2 */ + NVIC_DMA2_CH3 = 58, /**< DMA2 channel 3 */ + NVIC_DMA2_CH4_5 = 59, /**< DMA2 channels 4 and 5 */ +#endif +} nvic_irq_num; -/* System control registers */ -#define SCB_VTOR 0xE000ED08 // Vector table offset register +void nvic_init(uint32 vector_table_address, uint32 offset); +void nvic_set_vector_table(uint32 address, uint32 offset); +void nvic_set_priority(nvic_irq_num irqn, uint8 priority); -#define NVIC_BASE 0xE000E100 -#define NVIC ((nvic_reg_map*)NVIC_BASE) +/** + * Enables interrupts and configurable fault handlers (clear PRIMASK). + */ +static inline void nvic_globalirq_enable() { + asm volatile("cpsie i"); +} -typedef struct nvic_reg_map { - __io uint32 ISER[8]; // Interrupt Set Enable Registers - uint32 RESERVED0[24]; - __io uint32 ICER[8]; // Interrupt Clear Enable Registers - uint32 RSERVED1[24]; - __io uint32 ISPR[8]; // Interrupt Set Pending Registers - uint32 RESERVED2[24]; - __io uint32 ICPR[8]; // Interrupt Clear Pending Registers - uint32 RESERVED3[24]; - __io uint32 IABR[8]; // Interrupt Active bit Registers - uint32 RESERVED4[56]; - __io uint8 IP[240]; // Interrupt Priority Registers - uint32 RESERVED5[644]; - __io uint32 STIR; // Software Trigger Interrupt Registers -} nvic_reg_map; +/** + * Disable interrupts and configurable fault handlers (set PRIMASK). + */ +static inline void nvic_globalirq_disable() { + asm volatile("cpsid i"); +} -typedef enum nvic_irq_num { - NVIC_NMI = -14, - NVIC_MEM_MANAGE = -12, - NVIC_BUS_FAULT = -11, - NVIC_USAGE_FAULT = -10, - NVIC_SVC = -5, - NVIC_DEBUG_MON = -4, - NVIC_PEND_SVC = -2, - NVIC_SYSTICK = -1, - - NVIC_TIMER1_BRK = 24, - NVIC_TIMER1_UP = 25, - NVIC_TIMER1_TRG_COM = 26, - NVIC_TIMER1_CC = 27, - NVIC_TIMER2 = 28, - NVIC_TIMER3 = 29, - NVIC_TIMER4 = 30, - NVIC_TIMER5 = 50, - NVIC_TIMER6 = 54, - NVIC_TIMER7 = 55, - NVIC_TIMER8_BRK = 43, - NVIC_TIMER8_UP = 44, - NVIC_TIMER8_TRG_COM = 45, - NVIC_TIMER8_CC = 46, - - NVIC_USART1 = 37, - NVIC_USART2 = 38, - NVIC_USART3 = 39, - NVIC_UART4 = 52, - NVIC_UART5 = 53, - - NVIC_EXTI0 = 6, - NVIC_EXTI1 = 7, - NVIC_EXTI2 = 8, - NVIC_EXTI3 = 9, - 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, - - NVIC_I2C1_EV = 31, - NVIC_I2C1_ER = 32, - NVIC_I2C2_EV = 33, - NVIC_I2C2_ER = 34 -} nvic_irq_num; +/** + * @brief Enable interrupt irq_num + * @param irq_num Interrupt to enable + */ +static inline void nvic_irq_enable(nvic_irq_num irq_num) { + NVIC_BASE->ISER[irq_num / 32] = BIT(irq_num % 32); +} -#define nvic_globalirq_enable() asm volatile("cpsie i") -#define nvic_globalirq_disable() asm volatile("cpsid i") +/** + * @brief Disable interrupt irq_num + * @param irq_num Interrupt to disable + */ +static inline void nvic_irq_disable(nvic_irq_num irq_num) { + NVIC_BASE->ICER[irq_num / 32] = BIT(irq_num % 32); +} -void nvic_init(void); -void nvic_irq_enable(uint32 device); -void nvic_irq_disable(uint32 device); -void nvic_irq_disable_all(void); -void nvic_set_priority(int32 irqn, uint8 priority); +/** + * @brief Quickly disable all interrupts. + * + * Calling this function is significantly faster than calling + * nvic_irq_disable() in a loop. + */ +static inline void nvic_irq_disable_all(void) { + /* Note: This only works up to XL density. The fix for + * connectivity line is: + * + * NVIC_BASE->ICER[2] = 0xF; + * + * We don't support connectivity line devices (yet), so leave it + * alone for now. + */ + NVIC_BASE->ICER[0] = 0xFFFFFFFF; + NVIC_BASE->ICER[1] = 0xFFFFFFFF; +} #ifdef __cplusplus } diff --git a/libmaple/rules.mk b/libmaple/rules.mk index a9d7e50..2eaea55 100644 --- a/libmaple/rules.mk +++ b/libmaple/rules.mk @@ -9,7 +9,7 @@ BUILDDIRS += $(BUILD_PATH)/$(d)/usb/usb_lib LIBMAPLE_INCLUDES := -I$(LIBMAPLE_PATH) -I$(LIBMAPLE_PATH)/usb -I$(LIBMAPLE_PATH)/usb/usb_lib # Local flags -CFLAGS_$(d) = -I$(d) $(LIBMAPLE_INCLUDES) -D$(VECT_BASE_ADDR) +CFLAGS_$(d) = -I$(d) $(LIBMAPLE_INCLUDES) # Local rules and targets cSRCS_$(d) := adc.c \ diff --git a/libmaple/scb.h b/libmaple/scb.h index 8bfdda3..1911435 100644 --- a/libmaple/scb.h +++ b/libmaple/scb.h @@ -29,34 +29,32 @@ #ifndef _SCB_H_ #define _SCB_H_ -/* FIXME this definition is missing doxygen comments */ - +/** System control block register map */ typedef struct scb_reg_map { - __io uint32 CPUID; // CPU ID Base Register - __io uint32 ICSR; // Interrupt Control State Register - __io uint32 VTOR; // Vector Table Offset Register - __io uint32 AIRCR; // Application Interrupt / Reset Control Register - __io uint32 SCR; // System Control Register - __io uint32 CCR; // Configuration Control Register - __io uint8 SHP[12]; // System Handlers Priority Registers (4-7, 8-11, 12-15) - __io uint32 SHCSR; // System Handler Control and State Register - __io uint32 CFSR; // Configurable Fault Status Register - __io uint32 HFSR; // Hard Fault Status Register - __io uint32 DFSR; // Debug Fault Status Register - __io uint32 MMFAR; // Mem Manage Address Register - __io uint32 BFAR; // Bus Fault Address Register - __io uint32 AFSR; // Auxiliary Fault Status Register - __io uint32 PFR[2]; // Processor Feature Register - __io uint32 DFR; // Debug Feature Register - __io uint32 ADR; // Auxiliary Feature Register - __io uint32 MMFR[4]; // Memory Model Feature Register - __io uint32 ISAR[5]; // ISA Feature Register + __io uint32 CPUID; /**< CPU ID Base Register */ + __io uint32 ICSR; /**< Interrupt Control State Register */ + __io uint32 VTOR; /**< Vector Table Offset Register */ + __io uint32 AIRCR; /**< Application Interrupt / Reset Control Register */ + __io uint32 SCR; /**< System Control Register */ + __io uint32 CCR; /**< Configuration Control Register */ + __io uint8 SHP[12]; /**< System Handlers Priority Registers + (4-7, 8-11, 12-15) */ + __io uint32 SHCSR; /**< System Handler Control and State Register */ + __io uint32 CFSR; /**< Configurable Fault Status Register */ + __io uint32 HFSR; /**< Hard Fault Status Register */ + __io uint32 DFSR; /**< Debug Fault Status Register */ + __io uint32 MMFAR; /**< Mem Manage Address Register */ + __io uint32 BFAR; /**< Bus Fault Address Register */ + __io uint32 AFSR; /**< Auxiliary Fault Status Register */ + __io uint32 PFR[2]; /**< Processor Feature Register */ + __io uint32 DFR; /**< Debug Feature Register */ + __io uint32 ADR; /**< Auxiliary Feature Register */ + __io uint32 MMFR[4]; /**< Memory Model Feature Register */ + __io uint32 ISAR[5]; /**< ISA Feature Register */ } scb_reg_map; -/* FIXME these names violate the libmaple naming conventions */ - -#define SCB_BASE 0xE000ED00 -#define SCB ((scb_reg_map*)(SCB_BASE)) +/** System control block register map base pointer */ +#define SCB_BASE ((struct scb_reg_map*)0xE000ED00) #endif diff --git a/libmaple/util.c b/libmaple/util.c index 6b4f216..77af5b8 100644 --- a/libmaple/util.c +++ b/libmaple/util.c @@ -69,8 +69,8 @@ void __error(void) { usart_disable_all(); /* Turn the USB interrupt back on so the bootloader keeps on functioning */ - nvic_irq_enable(NVIC_INT_USBHP); - nvic_irq_enable(NVIC_INT_USBLP); + nvic_irq_enable(NVIC_USB_HP_CAN_TX); + nvic_irq_enable(NVIC_USB_LP_CAN_RX0); /* Reenable global interrupts */ nvic_globalirq_enable(); diff --git a/wirish/boards.cpp b/wirish/boards.cpp index 1c2b1c7..9e25eeb 100644 --- a/wirish/boards.cpp +++ b/wirish/boards.cpp @@ -43,13 +43,14 @@ static void setupFlash(void); static void setupClocks(void); +static void setupNVIC(void); static void setupADC(void); static void setupTimers(void); void init(void) { setupFlash(); setupClocks(); - nvic_init(); + setupNVIC(); systick_init(SYSTICK_RELOAD_VAL); gpio_init_all(); afio_init(); @@ -90,6 +91,18 @@ static void setupClocks() { rcc_set_prescaler(RCC_PRESCALER_APB2, RCC_APB2_HCLK_DIV_1); } +static void setupNVIC() { +#ifdef VECT_TAB_FLASH + nvic_init(USER_ADDR_ROM, 0); +#elif defined VECT_TAB_RAM + nvic_init(USER_ADDR_RAM, 0); +#elif defined VECT_TAB_BASE + nvic_init((uint32)0x08000000, 0); +#else +#error "You must select a base address for the vector table." +#endif +} + static void adcDefaultConfig(const adc_dev* dev); static void setupADC() { -- cgit v1.2.3 From b835b9864d7fa17de8eeaaafbb1b17f2252e68a5 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Fri, 1 Apr 2011 03:15:27 -0400 Subject: SysTick refactor. For the changelog: * util.h is free of __read(), __write(), etc. macros. * systick_resume() was renamed systick_enable(). --- examples/test-systick.cpp | 2 +- libmaple/systick.c | 54 ++++++++++++++++++++++++----------------------- libmaple/systick.h | 46 +++++++++++++++++++++++++++++++++------- libmaple/util.h | 37 +++++++++++++------------------- 4 files changed, 82 insertions(+), 57 deletions(-) diff --git a/examples/test-systick.cpp b/examples/test-systick.cpp index c7b5529..bbf0adf 100644 --- a/examples/test-systick.cpp +++ b/examples/test-systick.cpp @@ -30,7 +30,7 @@ void loop() { SerialUSB.println("Disabling SysTick"); } else { SerialUSB.println("Re-enabling SysTick"); - systick_resume(); + systick_enable(); } disable = !disable; } diff --git a/libmaple/systick.c b/libmaple/systick.c index b9a52c1..c04f4f3 100644 --- a/libmaple/systick.c +++ b/libmaple/systick.c @@ -26,44 +26,46 @@ * @brief System timer interrupt handler and initialization routines */ -#include "libmaple.h" #include "systick.h" -#define SYSTICK_RELOAD 0xE000E014 // Reload value register -#define SYSTICK_CNT 0xE000E018 // Current value register -#define SYSTICK_CALIB 0xE000E01C // Calibration value register - -#define SYSTICK_SRC_HCLK BIT(2) // Use core clock -#define SYSTICK_TICKINT BIT(1) // Interrupt on systick countdown -#define SYSTICK_ENABLE BIT(0) // Turn on the counter - volatile uint32 systick_timer_millis; +/** + * @brief Initialize and enable SysTick. + * + * Clocks the system timer with the core clock, turns it on, and + * enables interrupts. + * + * @param reload_val Appropriate reload counter to tick every 1 ms. + */ void systick_init(uint32 reload_val) { - /* Set the reload counter to tick every 1ms */ - __write(SYSTICK_RELOAD, reload_val); - - /* Clock the system timer with the core clock and turn it on, - * interrrupt every 1ms to keep track of millis() */ - __write(SYSTICK_CSR, SYSTICK_SRC_HCLK | - SYSTICK_ENABLE | - SYSTICK_TICKINT); + SYSTICK_BASE->RVR = reload_val; + systick_enable(); } +/** + * Clock the system timer with the core clock, but don't turn it + * on or enable interrupt. + */ void systick_disable() { - /* clock the system timer with the core clock, but don't turn it - on or enable interrupt. */ - __write(SYSTICK_CSR, SYSTICK_SRC_HCLK); + SYSTICK_BASE->CSR = SYSTICK_CSR_CLKSOURCE_CORE; } -void systick_resume() { - /* re-enable init registers without changing reload val */ - __write(SYSTICK_CSR, SYSTICK_SRC_HCLK | - SYSTICK_ENABLE | - SYSTICK_TICKINT); +/** + * Clock the system timer with the core clock and turn it on; + * interrupt every 1 ms, for systick_timer_millis. + */ +void systick_enable() { + /* re-enables init registers without changing reload val */ + SYSTICK_BASE->CSR = (SYSTICK_CSR_CLKSOURCE_CORE | + SYSTICK_CSR_ENABLE | + SYSTICK_CSR_TICKINT_PEND); } -/** SysTick interrupt handler. Bumps up the tick counter. */ +/* + * SysTick ISR + */ + void __exc_systick(void) { systick_timer_millis++; } diff --git a/libmaple/systick.h b/libmaple/systick.h index 33a3cf8..35b4cb9 100644 --- a/libmaple/systick.h +++ b/libmaple/systick.h @@ -31,30 +31,60 @@ #ifndef _SYSTICK_H_ #define _SYSTICK_H_ -#include "libmaple.h" +#include "libmaple_types.h" +#include "util.h" #ifdef __cplusplus extern "C"{ #endif -#define SYSTICK_CSR 0xE000E010 // Control and status register -#define SYSTICK_CNT 0xE000E018 // Current value register +/** SysTick register map type */ +typedef struct systick_reg_map { + __io uint32 CSR; /**< Control and status register */ + __io uint32 RVR; /**< Reload value register */ + __io uint32 CNT; /**< Current value register ("count") */ + __io uint32 CVR; /**< Calibration value register */ +} systick_reg_map; -#define SYSTICK_CSR_COUNTFLAG BIT(16) +/** SysTick register map base pointer */ +#define SYSTICK_BASE ((struct systick_reg_map*)0xE000E010) -/** System elapsed time in milliseconds */ +/* + * Register bit definitions. + */ + +/* Control and status register */ + +#define SYSTICK_CSR_COUNTFLAG BIT(16) +#define SYSTICK_CSR_CLKSOURCE BIT(2) +#define SYSTICK_CSR_CLKSOURCE_EXTERNAL 0 +#define SYSTICK_CSR_CLKSOURCE_CORE BIT(2) +#define SYSTICK_CSR_TICKINT BIT(1) +#define SYSTICK_CSR_TICKINT_PEND BIT(1) +#define SYSTICK_CSR_TICKINT_NO_PEND 0 +#define SYSTICK_CSR_ENABLE BIT(0) +#define SYSTICK_CSR_ENABLE_MULTISHOT BIT(0) +#define SYSTICK_CSR_ENABLE_DISABLED 0 + +/* Calibration value register */ + +#define SYSTICK_CVR_NOREF BIT(31) +#define SYSTICK_CVR_SKEW BIT(30) +#define SYSTICK_CVR_TENMS 0xFFFFFF + +/** System elapsed time, in milliseconds */ extern volatile uint32 systick_timer_millis; void systick_init(uint32 reload_val); void systick_disable(); -void systick_resume(); +void systick_enable(); static inline uint32 systick_get_count(void) { - return __read(SYSTICK_CNT); + return SYSTICK_BASE->CNT; } static inline uint32 systick_check_underflow(void) { - return (__read(SYSTICK_CSR) & SYSTICK_CSR_COUNTFLAG); + return SYSTICK_BASE->CSR & SYSTICK_CSR_COUNTFLAG; } #ifdef __cplusplus diff --git a/libmaple/util.h b/libmaple/util.h index 25dd56e..aff70e1 100644 --- a/libmaple/util.h +++ b/libmaple/util.h @@ -23,14 +23,12 @@ *****************************************************************************/ /** - * @file util.h - * - * @brief Various macros and utility procedures. + * @file util.h + * @brief Miscellaneous utility macros and procedures. */ #include "libmaple_types.h" -/* Generally "useful" utility procedures */ #ifndef _UTIL_H_ #define _UTIL_H_ @@ -38,33 +36,23 @@ extern "C"{ #endif -/* Debug configuration */ -#define DEBUG_NONE 0 -#define DEBUG_FAULT 1 -#define DEBUG_ALL 2 - -#ifndef DEBUG_LEVEL -#define DEBUG_LEVEL DEBUG_ALL -#endif +/* + * Bit manipulation + */ #define BIT(shift) (1UL << (shift)) #define BIT_MASK_SHIFT(mask, shift) ((mask) << (shift)) - -/* Return bits m to n of x */ +/* Bits m to n of x */ #define GET_BITS(x, m, n) ((((uint32)x) << (31 - (n))) >> ((31 - (n)) + (m))) +#define IS_POWER_OF_TWO(v) (v && !(v & (v - 1))) /* * Register reads and writes */ -#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 IS_POWER_OF_TWO(v) (v && !(v & (v - 1))) - /* * Failure routines */ @@ -77,13 +65,20 @@ void throb(void); * Asserts and debug levels */ +#define DEBUG_NONE 0 +#define DEBUG_FAULT 1 +#define DEBUG_ALL 2 + +#ifndef DEBUG_LEVEL +#define DEBUG_LEVEL DEBUG_ALL +#endif + #if DEBUG_LEVEL >= DEBUG_ALL #define ASSERT(exp) \ if (exp) { \ } else { \ _fail(__FILE__, __LINE__, #exp); \ } - #else #define ASSERT(exp) (void)((0)) #endif @@ -94,7 +89,6 @@ void throb(void); } else { \ _fail(__FILE__, __LINE__, #exp); \ } - #else #define ASSERT_FAULT(exp) (void)((0)) #endif @@ -104,4 +98,3 @@ void throb(void); #endif #endif - -- cgit v1.2.3 From 012d9ba1c2069d4d072685b990cbd01b611bb751 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Wed, 6 Apr 2011 11:51:57 -0400 Subject: Updated coding standard. --- notes/coding_standard.txt | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/notes/coding_standard.txt b/notes/coding_standard.txt index b81847d..0accda7 100644 --- a/notes/coding_standard.txt +++ b/notes/coding_standard.txt @@ -122,7 +122,7 @@ Naming conventions There's always a fight about upper and lower case vs. underscores. We'll handle this as follows. -- First, Dammit_Dont_Mix_Like_This, because It_Looks_Really_Ugly, ok? +- First, Dont_Mix_Like_This, because It_Looks_Really_Ugly, ok? [There's been some debate about this, and some exceptions are already grandfathered in, so in order to settle it, let's call this a "recommendation" instead of "requirement".] @@ -140,11 +140,9 @@ We'll handle this as follows. - Functions: C functions are all lowercase, and words are separated by underscores. C++ method names are camel cased (thisIsAnExample). -- Structs: pick a style from "Variables" or "Classes" depending on how - you mean it (since it might be either a simple record type, in which - case do like c variables, or you might be faking an object in c, in - which case do like classes). If it's in a typedef, don't feel - obliged to put "_t" at the end of the name; we don't. +- Structs: Usually like variables (adc_dev, adc_reg_map, etc.), but + it's not crucial. If it's in a typedef, don't feel obliged to put + "_t" at the end of the name; we don't. - Macros and constants: all caps, separated by underscores. Variables with the "const" qualifier aren't considered "constants" for the @@ -196,6 +194,10 @@ Documentation maintenance burden of documenting things in two places at once, and makes it easier for documentation to go stale. + If you do have to document something manually, put a comment in the + source file informing future maintainers about it, so they'll pay + extra attention when making changes. + - For libmaple proper (the pure C library under libmaple/); the convention is to document any user-facing entity at the point where it is defined. In particular, this means you should document an -- cgit v1.2.3 From 552b8882ef04cb0028ec30a04b5464b1a17bccad Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Wed, 6 Apr 2011 13:57:30 -0400 Subject: USART refactor. --- docs/source/lang/api/serial.rst | 5 +- examples/test-serial-flush.cpp | 29 ++-- examples/test-session.cpp | 62 ++++++-- libmaple/usart.c | 302 +++++++++++++++++++------------------- libmaple/usart.h | 315 ++++++++++++++++++++++++++++++++-------- libmaple/util.c | 53 ++++--- wirish/comm/HardwareSerial.cpp | 86 ++++++----- wirish/comm/HardwareSerial.h | 50 +++---- 8 files changed, 582 insertions(+), 320 deletions(-) diff --git a/docs/source/lang/api/serial.rst b/docs/source/lang/api/serial.rst index 58002e3..29c70a2 100644 --- a/docs/source/lang/api/serial.rst +++ b/docs/source/lang/api/serial.rst @@ -12,6 +12,9 @@ devices. Introduction ------------ +.. FIXME remove Maple-specific documentation +.. FIXME Serial4, Serial5 updates for high-density devices + The Maple has three serial ports (also known as a UARTs or USARTs): ``Serial1``, ``Serial2``, and ``Serial3``. They communicate using the pins summarized in the following table: @@ -221,7 +224,7 @@ Arduino Compatibility Note Unlike the Arduino, none of the Maple's serial ports is connected to the USB port on the Maple board (for that, use :ref:`SerialUSB `). Thus, to use these pins to communicate with your -personal computer, you will need an additional USB-to-serial adaptor. +personal computer, you will need an additional USB-to-serial adapter. .. TODO LATER port these examples over diff --git a/examples/test-serial-flush.cpp b/examples/test-serial-flush.cpp index 1cd82b6..6c4e100 100644 --- a/examples/test-serial-flush.cpp +++ b/examples/test-serial-flush.cpp @@ -1,21 +1,26 @@ -// Tests the "flush" Serial function +/* + * Tests the "flush" Serial function. + */ #include "wirish.h" +#define COMM Serial1 + void setup() { - /* Send a message out USART2 */ - Serial2.begin(9600); - Serial2.println("Hello world!"); + COMM.begin(9600); + COMM.println("Hello world!"); } void loop() { - Serial2.println("Waiting for multiple input..."); - while(Serial2.available() < 5) { } - Serial2.println(Serial2.read()); - Serial2.println(Serial2.read()); - Serial2.flush(); - if(Serial2.available()) { - Serial2.println("FAIL! Still had junk in the buffer..."); + COMM.println("Waiting for multiple input..."); + while (COMM.available() < 5) + ; + COMM.println(COMM.read()); + COMM.println(COMM.read()); + COMM.flush(); + + if (COMM.available()) { + COMM.println("FAIL! Still had junk in the buffer..."); } } @@ -28,7 +33,7 @@ __attribute__((constructor)) void premain() { int main(void) { setup(); - while (1) { + while (true) { loop(); } return 0; diff --git a/examples/test-session.cpp b/examples/test-session.cpp index a4128ac..01d0fe9 100644 --- a/examples/test-session.cpp +++ b/examples/test-session.cpp @@ -23,6 +23,7 @@ void cmd_adc_stats(void); void cmd_stressful_adc_stats(void); void cmd_everything(void); void cmd_serial1_serial3(void); +void cmd_serial1_echo(void); void cmd_gpio_monitoring(void); void cmd_sequential_adc_reads(void); void cmd_gpio_qa(void); @@ -35,7 +36,8 @@ void cmd_board_info(void); // Helper functions void measure_adc_noise(uint8 pin); void fast_gpio(int pin); -void usart_baud_test(HardwareSerial **serials, int n, unsigned baud); +void serial_baud_test(HardwareSerial **serials, int n, unsigned baud); +void serial_echo_test(HardwareSerial *serial, unsigned baud); void init_all_timers(uint16 prescale); void enable_usarts(void); void disable_usarts(void); @@ -104,6 +106,10 @@ void loop () { cmd_serial1_serial3(); break; + case 'E': + cmd_serial1_echo(); + break; + case '.': while (!SerialUSB.available()) { Serial1.print("."); @@ -225,8 +231,8 @@ void loop () { break; default: // ------------------------------- - SerialUSB.print("Unexpected: "); - SerialUSB.print(input); + SerialUSB.print("Unexpected byte: 0x"); + SerialUSB.print((int)input, HEX); SerialUSB.println(", press h for help."); } @@ -243,11 +249,13 @@ void cmd_print_help(void) { SerialUSB.println("\th: print this menu"); SerialUSB.println("\tw: print Hello World on all 3 USARTS"); SerialUSB.println("\tn: measure noise and do statistics"); - SerialUSB.println("\tN: measure noise and do statistics with background stuff"); + SerialUSB.println("\tN: measure noise and do statistics with background " + "stuff"); SerialUSB.println("\ta: show realtime ADC info"); SerialUSB.println("\t.: echo '.' until new input"); SerialUSB.println("\tu: print Hello World on USB"); - SerialUSB.println("\t_: do as little as possible for a couple seconds (delay)"); + SerialUSB.println("\t_: do as little as possible for a couple seconds " + "(delay)"); SerialUSB.println("\tp: test all PWM channels sequentially"); SerialUSB.println("\tW: dump data as fast as possible on all 3 USARTS"); SerialUSB.println("\tU: dump data as fast as possible on USB"); @@ -256,7 +264,9 @@ void cmd_print_help(void) { SerialUSB.println("\tf: toggle pin 4 as fast as possible in bursts"); SerialUSB.println("\tr: monitor and print GPIO status changes"); SerialUSB.println("\ts: output a sweeping servo PWM on all PWM channels"); - SerialUSB.println("\tm: output data on USART1 and USART3 with various rates"); + SerialUSB.println("\tm: output data on USART1 and USART3 at various " + "baud rates"); + SerialUSB.println("\tE: echo data on USART1 at various baud rates"); SerialUSB.println("\tb: print information about the board."); SerialUSB.println("\t+: test shield mode (for quality assurance testing)"); @@ -316,17 +326,17 @@ void cmd_serial1_serial3(void) { SerialUSB.println("Testing 57600 baud on USART1 and USART3. " "Press any key to stop."); - usart_baud_test(serial_1_and_3, 2, 57600); + serial_baud_test(serial_1_and_3, 2, 57600); SerialUSB.read(); SerialUSB.println("Testing 115200 baud on USART1 and USART3. " "Press any key to stop."); - usart_baud_test(serial_1_and_3, 2, 115200); + serial_baud_test(serial_1_and_3, 2, 115200); SerialUSB.read(); SerialUSB.println("Testing 9600 baud on USART1 and USART3. " "Press any key to stop."); - usart_baud_test(serial_1_and_3, 2, 9600); + serial_baud_test(serial_1_and_3, 2, 9600); SerialUSB.read(); SerialUSB.println("Resetting USART1 and USART3..."); @@ -334,6 +344,27 @@ void cmd_serial1_serial3(void) { Serial3.begin(BAUD); } +void cmd_serial1_echo(void) { + SerialUSB.println("Testing serial echo at various baud rates. " + "Press any key for next baud rate, or ESC to quit " + "early."); + while (!SerialUSB.available()) + ; + SerialUSB.read(); + + SerialUSB.println("Testing 115200 baud on USART1."); + serial_echo_test(&Serial1, 115200); + if (SerialUSB.read() == ESC) return; + + SerialUSB.println("Testing 57600 baud on USART1."); + serial_echo_test(&Serial1, 57600); + if (SerialUSB.read() == ESC) return; + + SerialUSB.println("Testing 9600 baud on USART1."); + serial_echo_test(&Serial1, 9600); + if (SerialUSB.read() == ESC) return; +} + void cmd_gpio_monitoring(void) { SerialUSB.println("Monitoring pin state changes. Press any key to stop."); @@ -615,7 +646,7 @@ void cmd_board_info(void) { // TODO print more information SerialUSB.println("Board information"); SerialUSB.println("================="); - SerialUSB.print("* Clock speed (cycles/us): "); + SerialUSB.print("* Clock speed (MHz): "); SerialUSB.println(CYCLES_PER_MICROSECOND); SerialUSB.print("* BOARD_LED_PIN: "); @@ -693,7 +724,7 @@ void fast_gpio(int maple_pin) { gpio_toggle_bit(dev, bit); } -void usart_baud_test(HardwareSerial **serials, int n, unsigned baud) { +void serial_baud_test(HardwareSerial **serials, int n, unsigned baud) { for (int i = 0; i < n; i++) { serials[i]->begin(baud); } @@ -708,6 +739,15 @@ void usart_baud_test(HardwareSerial **serials, int n, unsigned baud) { } } +void serial_echo_test(HardwareSerial *serial, unsigned baud) { + serial->begin(baud); + while (!SerialUSB.available()) { + if (!serial->available()) + continue; + serial->print(serial->read()); + } +} + static uint16 init_all_timers_prescale = 0; static void set_prescale(timer_dev *dev) { diff --git a/libmaple/usart.c b/libmaple/usart.c index 494a29f..df5e2c5 100644 --- a/libmaple/usart.c +++ b/libmaple/usart.c @@ -23,212 +23,214 @@ *****************************************************************************/ /** + * @file usart.c * @brief USART control routines */ -#include "libmaple.h" -#include "rcc.h" -#include "nvic.h" #include "usart.h" -#define USART1_BASE 0x40013800 -#define USART2_BASE 0x40004400 -#define USART3_BASE 0x40004800 -#define UART4_BASE 0x40004C00 // High-density devices only (Maple Native) -#define UART5_BASE 0x40005000 // High-density devices only (Maple Native) - -#define USART_UE BIT(13) -#define USART_M BIT(12) -#define USART_TE BIT(3) -#define USART_RE BIT(2) -#define USART_RXNEIE BIT(5) // read data register not empty interrupt enable -#define USART_TC BIT(6) - -/* usart descriptor table */ -struct usart_dev usart_dev_table[] = { - [USART1] = { - .base = (usart_port*)USART1_BASE, - .rcc_dev_num = RCC_USART1, - .nvic_dev_num = NVIC_USART1 - }, - [USART2] = { - .base = (usart_port*)USART2_BASE, - .rcc_dev_num = RCC_USART2, - .nvic_dev_num = NVIC_USART2 - }, - [USART3] = { - .base = (usart_port*)USART3_BASE, - .rcc_dev_num = RCC_USART3, - .nvic_dev_num = NVIC_USART3 - }, -#ifdef STM32_HIGH_DENSITY - /* 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. + * Devices */ -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 __irq_usart1(void) { - usart_irq(USART1); -} - -void __irq_usart2(void) { - usart_irq(USART2); -} - -void __irq_usart3(void) { - usart_irq(USART3); -} +static ring_buffer usart1_rb; +static usart_dev usart1 = { + .regs = USART1_BASE, + .rb = &usart1_rb, + .max_baud = 4500000UL, + .clk_id = RCC_USART1, + .irq_num = NVIC_USART1 +}; +usart_dev *USART1 = &usart1; + +static ring_buffer usart2_rb; +static usart_dev usart2 = { + .regs = USART2_BASE, + .rb = &usart2_rb, + .max_baud = 2250000UL, + .clk_id = RCC_USART2, + .irq_num = NVIC_USART2 +}; +usart_dev *USART2 = &usart2; + +static ring_buffer usart3_rb; +static usart_dev usart3 = { + .regs = USART3_BASE, + .rb = &usart3_rb, + .max_baud = 2250000UL, + .clk_id = RCC_USART3, + .irq_num = NVIC_USART3 +}; +usart_dev *USART3 = &usart3; #ifdef STM32_HIGH_DENSITY -void __irq_uart4(void) { - usart_irq(UART4); -} - -void __irq_uart5(void) { - usart_irq(UART5); -} +static ring_buffer uart4_rb; +static usart_dev uart4 = { + .regs = UART4_BASE, + .rb = &uart4_rb, + .max_baud = 2250000UL, + .clk_id = RCC_UART4, + .irq_num = NVIC_UART4 +}; +usart_dev *UART4 = &uart4; + +static ring_buffer uart5_rb; +static usart_dev uart5 = { + .regs = UART5_BASE, + .rb = &uart5_rb, + .max_baud = 2250000UL, + .clk_id = RCC_UART5, + .irq_num = NVIC_UART5 +}; +usart_dev *UART5 = &uart5; #endif /** - * @brief Enable a USART in single buffer transmission mode, multibuffer - * receiver mode. - * @param usart_num USART to be initialized - * @param baud Baud rate to be set at + * @brief Initialize a serial port. + * @param dev Serial port to be initialized */ -void usart_init(uint8 usart_num, uint32 baud) { -#ifdef STM32_HIGH_DENSITY - ASSERT(usart_num <= UART5); -#else - ASSERT(usart_num <= USART3); -#endif - usart_port *port; - ring_buffer *ring_buf; +void usart_init(usart_dev *dev) { + rb_init(dev->rb, USART_RX_BUF_SIZE, dev->rx_buf); + rcc_clk_enable(dev->clk_id); + nvic_irq_enable(dev->irq_num); +} - uint32 clk_speed; +/** + * @brief Configure a serial port's baud rate. + * + * @param dev Serial port to be configured + * @param clock_speed MCU clock speed, in megahertz. + * @param baud Baud rate for transmit/receive. + */ +void usart_set_baud_rate(usart_dev *dev, uint32 clock_speed, uint32 baud) { uint32 integer_part; uint32 fractional_part; uint32 tmp; - port = usart_dev_table[usart_num].base; - rcc_clk_enable(usart_dev_table[usart_num].rcc_dev_num); - nvic_irq_enable(usart_dev_table[usart_num].nvic_dev_num); - - /* usart1 is mad fast */ - clk_speed = (usart_num == USART1) ? 72000000UL : 36000000UL; - - /* Initialize rx ring buffer */ - rb_init(&usart_dev_table[usart_num].rb, - sizeof (usart_dev_table[usart_num].rx_buf), - usart_dev_table[usart_num].rx_buf); - - /* Set baud rate */ - integer_part = ((25 * clk_speed) / (4 * baud)); + /* See ST RM0008 for the details on configuring the baud rate register */ + integer_part = (25 * clock_speed) / (4 * baud); tmp = (integer_part / 100) << 4; - fractional_part = integer_part - (100 * (tmp >> 4)); tmp |= (((fractional_part * 16) + 50) / 100) & ((uint8)0x0F); - port->BRR = (uint16)tmp; - - port->CR1 = USART_TE | // transmitter enable - USART_RE | // receiver enable - USART_RXNEIE; // receive interrupt enable - - - /* Enable the USART and set mode to 8n1 */ - port->CR1 |= USART_UE; + dev->regs->BRR = (uint16)tmp; } /** - * @brief Turn off all USARTs. + * @brief Enable a serial port. + * + * USART is enabled in single buffer transmission mode, multibuffer + * receiver mode, at the given baud rate, 8n1. + * + * Serial port must have a baud rate configured to work properly. + * + * @param dev Serial port to enable. + * @see usart_set_baud_rate() */ -void usart_disable_all() { - usart_disable(USART1); - usart_disable(USART2); - usart_disable(USART3); -#ifdef STM32_HIGH_DENSITY - usart_disable(UART4); - usart_disable(UART5); -#endif +void usart_enable(usart_dev *dev) { + usart_reg_map *regs = dev->regs; + regs->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE; + regs->CR1 |= USART_CR1_UE; } /** - * @brief Turn off a USART. - * @param USART to be disabled + * @brief Turn off a serial port. + * @param dev Serial port to be disabled */ -void usart_disable(uint8 usart_num) { - usart_port *port = usart_dev_table[usart_num].base; +void usart_disable(usart_dev *dev) { + /* FIXME this misbehaves if you try to use PWM on TX afterwards */ + usart_reg_map *regs = dev->regs; - /* TC bit must be high before disabling the usart */ - while((port->CR1 & USART_UE) && !(port->SR & USART_TC)) + /* TC bit must be high before disabling the USART */ + while((regs->CR1 & USART_CR1_UE) && !(regs->SR & USART_SR_TC)) ; /* Disable UE */ - port->CR1 = 0; + regs->CR1 = 0; /* Clean up buffer */ - usart_reset_rx(usart_num); + usart_reset_rx(dev); } +/** + * @brief Call a function on each USART. + * @param fn Function to call. + */ +void usart_foreach(void (*fn)(usart_dev *dev)) { + fn(USART1); + fn(USART2); + fn(USART3); +#ifdef STM32_HIGH_DENSITY + fn(UART4); + fn(UART5); +#endif +} /** - * @brief Print a null terminated string to the specified USART - * - * @param usart_num usart to send on - * @param str string to send + * @brief Print a null-terminated string to the specified serial port. + * @param dev Serial port to send the string on + * @param str String to send */ -void usart_putstr(uint8 usart_num, const char* str) { +void usart_putstr(usart_dev *dev, const char* str) { char ch; - while((ch = *(str++)) != '\0') { - usart_putc(usart_num, ch); + while ((ch = *(str++)) != '\0') { + usart_putc(dev, ch); } } /** - * @brief Print an unsigned integer to the specified usart + * @brief Print an unsigned integer to the specified serial port. * - * @param usart_num usart to send on - * @param val number to print + * @param dev Serial port to send on + * @param val Number to print */ -void usart_putudec(uint8 usart_num, uint32 val) { +void usart_putudec(usart_dev *dev, uint32 val) { char digits[12]; - int i; + int i = 0; - i = 0; do { digits[i++] = val % 10 + '0'; val /= 10; } while (val > 0); + while (--i >= 0) { - usart_putc(usart_num, digits[i]); + usart_putc(dev, digits[i]); } } + +/* + * Interrupt handlers. + */ + +static inline void usart_irq(usart_dev *dev) { +#ifdef USART_SAFE_INSERT + /* Ignore new bytes if the user defines USART_SAFE_INSERT. */ + rb_safe_insert(dev->rb, (uint8)dev->regs->DR); +#else + /* By default, push bytes around in the ring buffer. */ + rb_push_insert(dev->rb, (uint8)dev->regs->DR); +#endif +} + +void __irq_usart1(void) { + usart_irq(USART1); +} + +void __irq_usart2(void) { + usart_irq(USART2); +} + +void __irq_usart3(void) { + usart_irq(USART3); +} + +#ifdef STM32_HIGH_DENSITY +void __irq_uart4(void) { + usart_irq(UART4); +} + +void __irq_uart5(void) { + usart_irq(UART5); +} +#endif diff --git a/libmaple/usart.h b/libmaple/usart.h index 90b3415..7a93da0 100644 --- a/libmaple/usart.h +++ b/libmaple/usart.h @@ -30,94 +30,293 @@ #ifndef _USART_H_ #define _USART_H_ +#include "libmaple_types.h" +#include "util.h" +#include "rcc.h" +#include "nvic.h" #include "ring_buffer.h" #ifdef __cplusplus extern "C"{ #endif -#define USART_TXE BIT(7) +/* + * Register maps and devices + */ + +/** USART register map type */ +typedef struct usart_reg_map { + __io uint32 SR; /**< Status register */ + __io uint32 DR; /**< Data register */ + __io uint32 BRR; /**< Baud rate register */ + __io uint32 CR1; /**< Control register 1 */ + __io uint32 CR2; /**< Control register 2 */ + __io uint32 CR3; /**< Control register 3 */ + __io uint32 GTPR; /**< Guard time and prescaler register */ +} usart_reg_map; -/* usart device numbers */ -enum { - USART1, - USART2, - USART3, +/** USART1 register map base pointer */ +#define USART1_BASE ((struct usart_reg_map*)0x40013800) +/** USART2 register map base pointer */ +#define USART2_BASE ((struct usart_reg_map*)0x40004400) +/** USART3 register map base pointer */ +#define USART3_BASE ((struct usart_reg_map*)0x40004800) #ifdef STM32_HIGH_DENSITY - UART4, - UART5, +/** UART4 register map base pointer */ +#define UART4_BASE ((struct usart_reg_map*)0x40004C00) +/** UART5 register map base pointer */ +#define UART5_BASE ((struct usart_reg_map*)0x40005000) #endif -}; - -/* peripheral register struct */ -typedef struct usart_port { - volatile uint32 SR; // Status register - volatile uint32 DR; // Data register - volatile uint32 BRR; // Baud rate register - volatile uint32 CR1; // Control register 1 - volatile uint32 CR2; // Control register 2 - volatile uint32 CR3; // Control register 3 - volatile uint32 GTPR; // Guard time and prescaler register -} usart_port; - -/* usart descriptor */ -struct usart_dev { - usart_port *base; - ring_buffer rb; - uint8 rx_buf[64]; - const uint8 rcc_dev_num; - const uint8 nvic_dev_num; -}; - -extern struct usart_dev usart_dev_table[]; + +/* + * Register bit definitions + */ + +/* Status register */ + +#define USART_SR_CTS_BIT 9 +#define USART_SR_LBD_BIT 8 +#define USART_SR_TXE_BIT 7 +#define USART_SR_TC_BIT 6 +#define USART_SR_RXNE_BIT 5 +#define USART_SR_IDLE_BIT 4 +#define USART_SR_ORE_BIT 3 +#define USART_SR_NE_BIT 2 +#define USART_SR_FE_BIT 1 +#define USART_SR_PE_BIT 0 + +#define USART_SR_CTS BIT(USART_SR_CTS_BIT) +#define USART_SR_LBD BIT(USART_SR_LBD_BIT) +#define USART_SR_TXE BIT(USART_SR_TXE_BIT) +#define USART_SR_TC BIT(USART_SR_TC_BIT) +#define USART_SR_RXNE BIT(USART_SR_RXNE_BIT) +#define USART_SR_IDLE BIT(USART_SR_IDLE_BIT) +#define USART_SR_ORE BIT(USART_SR_ORE_BIT) +#define USART_SR_NE BIT(USART_SR_NE_BIT) +#define USART_SR_FE BIT(USART_SR_FE_BIT) +#define USART_SR_PE BIT(USART_SR_PE_BIT) + +/* Data register */ + +#define USART_DR_DR 0xFF + +/* Baud rate register */ + +#define USART_BRR_DIV_MANTISSA (0xFFF << 4) +#define USART_BRR_DIV_FRACTION 0xF + +/* Control register 1 */ + +#define USART_CR1_UE_BIT 13 +#define USART_CR1_M_BIT 12 +#define USART_CR1_WAKE_BIT 11 +#define USART_CR1_PCE_BIT 10 +#define USART_CR1_PS_BIT 9 +#define USART_CR1_PEIE_BIT 8 +#define USART_CR1_TXEIE_BIT 7 +#define USART_CR1_TCIE_BIT 6 +#define USART_CR1_RXNEIE_BIT 5 +#define USART_CR1_IDLEIE_BIT 4 +#define USART_CR1_TE_BIT 3 +#define USART_CR1_RE_BIT 2 +#define USART_CR1_RWU_BIT 1 +#define USART_CR1_SBK_BIT 0 + +#define USART_CR1_UE BIT(USART_CR1_UE_BIT) +#define USART_CR1_M BIT(USART_CR1_M_BIT) +#define USART_CR1_WAKE BIT(USART_CR1_WAKE_BIT) +#define USART_CR1_WAKE_IDLE (0 << USART_CR1_WAKE_BIT) +#define USART_CR1_WAKE_ADDR (1 << USART_CR1_WAKE_BIT) +#define USART_CR1_PCE BIT(USART_CR1_PCE_BIT) +#define USART_CR1_PS BIT(USART_CR1_PS_BIT) +#define USART_CR1_PS_EVEN (0 << USART_CR1_PS_BIT) +#define USART_CR1_PS_ODD (1 << USART_CR1_PS_BIT) +#define USART_CR1_PEIE BIT(USART_CR1_PEIE_BIT) +#define USART_CR1_TXEIE BIT(USART_CR1_TXEIE_BIT) +#define USART_CR1_TCIE BIT(USART_CR1_TCIE_BIT) +#define USART_CR1_RXNEIE BIT(USART_CR1_RXNEIE_BIT) +#define USART_CR1_IDLEIE BIT(USART_CR1_IDLEIE_BIT) +#define USART_CR1_TE BIT(USART_CR1_TE_BIT) +#define USART_CR1_RE BIT(USART_CR1_RE_BIT) +#define USART_CR1_RWU BIT(USART_CR1_RWU_BIT) +#define USART_CR1_RWU_ACTIVE (0 << USART_CR1_RWU_BIT) +#define USART_CR1_RWU_MUTE (1 << USART_CR1_RWU_BIT) +#define USART_CR1_SBK BIT(USART_CR1_SBK_BIT) + +/* Control register 2 */ + +#define USART_CR2_LINEN_BIT 14 +#define USART_CR2_CLKEN_BIT 11 +#define USART_CR2_CPOL_BIT 10 +#define USART_CR2_CPHA_BIT 9 +#define USART_CR2_LBCL_BIT 8 +#define USART_CR2_LBDIE_BIT 6 +#define USART_CR2_LBDL_BIT 5 + +#define USART_CR2_LINEN BIT(USART_CR2_LINEN_BIT) +#define USART_CR2_STOP (0x3 << 12) +#define USART_CR2_STOP_BITS_1 (0x0 << 12) +/* Not on UART4, UART5 */ +#define USART_CR2_STOP_BITS_POINT_5 (0x1 << 12) +/* Not on UART4, UART5 */ +#define USART_CR2_STOP_BITS_1_POINT_5 (0x3 << 12) +#define USART_CR2_STOP_BITS_2 (0x2 << 12) +#define USART_CR2_CLKEN BIT(USART_CR2_CLKEN_BIT) +/* Not on UART4, UART5 */ +#define USART_CR2_CPOL BIT(USART_CR2_CPOL_BIT) +#define USART_CR2_CPOL_LOW (0x0 << USART_CR2_CLKEN_BIT) +#define USART_CR2_CPOL_HIGH (0x1 << USART_CR2_CLKEN_BIT) +/* Not on UART4, UART5 */ +#define USART_CR2_CPHA BIT(USART_CR2_CPHA_BIT) +#define USART_CR2_CPHA_FIRST (0x0 << USART_CR2_CPHA_BIT) +#define USART_CR2_CPHA_SECOND (0x1 << USART_CR2_CPHA_BIT) +/* Not on UART4, UART5 */ +#define USART_CR2_LBCL BIT(USART_CR2_LBCL_BIT) +#define USART_CR2_LBDIE BIT(USART_CR2_LBDIE_BIT) +#define USART_CR2_LBDL BIT(USART_CR2_LBDL_BIT) +#define USART_CR2_LBDL_10_BIT (0 << USART_CR2_LBDL_BIT) +#define USART_CR2_LBDL_11_BIT (1 << USART_CR2_LBDL_BIT) +#define USART_CR2_ADD 0xF + +/* Control register 3 */ + +#define USART_CR3_CTSIE_BIT 10 +#define USART_CR3_CTSE_BIT 9 +#define USART_CR3_RTSE_BIT 8 +#define USART_CR3_DMAT_BIT 7 +#define USART_CR3_DMAR_BIT 6 +#define USART_CR3_SCEN_BIT 5 +#define USART_CR3_NACK_BIT 4 +#define USART_CR3_HDSEL_BIT 3 +#define USART_CR3_IRLP_BIT 2 +#define USART_CR3_IREN_BIT 1 +#define USART_CR3_EIE_BIT 0 + +/* Not on UART4, UART5 */ +#define USART_CR3_CTSIE BIT(USART_CR3_CTSIE_BIT) +/* Not on UART4, UART5 */ +#define USART_CR3_CTSE BIT(USART_CR3_CTSE_BIT) +/* Not on UART4, UART5 */ +#define USART_CR3_RTSE BIT(USART_CR3_RTSE_BIT) +/* Not on UART5 */ +#define USART_CR3_DMAT BIT(USART_CR3_DMAT_BIT) +/* Not on UART5 */ +#define USART_CR3_DMAR BIT(USART_CR3_DMAR_BIT) +/* Not on UART4, UART5 */ +#define USART_CR3_SCEN BIT(USART_CR3_SCEN_BIT) +/* Not on UART4, UART5 */ +#define USART_CR3_NACK BIT(USART_CR3_NACK_BIT) +#define USART_CR3_HDSEL BIT(USART_CR3_HDSEL_BIT) +#define USART_CR3_IRLP BIT(USART_CR3_IRLP_BIT) +#define USART_CR3_IRLP_NORMAL (0 << USART_CR3_IRLP_BIT) +#define USART_CR3_IRLP_LOW_POWER (1 << USART_CR3_IRLP_BIT) +#define USART_CR3_IREN BIT(USART_CR3_IREN_BIT) +#define USART_CR3_EIE BIT(USART_CR3_EIE_BIT) + +/* Guard time and prescaler register */ + +/* Not on UART4, UART5 */ +#define USART_GTPR_GT (0xFF << 8) +/* Not on UART4, UART5 */ +#define USART_GTPR_PSC 0xFF + +/* + * Devices + */ + +#define USART_RX_BUF_SIZE 64 + +/** USART device type */ +typedef struct usart_dev { + usart_reg_map *regs; + ring_buffer *rb; + uint32 max_baud; + uint8 rx_buf[USART_RX_BUF_SIZE]; + rcc_clk_id clk_id; + nvic_irq_num irq_num; +} usart_dev; + +/** USART1 device */ +extern usart_dev *USART1; +/** USART2 device */ +extern usart_dev *USART2; +/** USART3 device */ +extern usart_dev *USART3; +#ifdef STM32_HIGH_DENSITY +/** UART4 device */ +extern usart_dev *UART4; +/** UART5 device */ +extern usart_dev *UART5; +#endif + +#ifdef STM32_MEDIUM_DENSITY +#define NR_USARTS 3 +#elif defined(STM32_HIGH_DENSITY) +#define NR_USARTS 5 +#else +#warn "Only medium and high density devices are currently supported" +#endif + +void usart_init(usart_dev *dev); +void usart_set_baud_rate(usart_dev *dev, uint32 clock_speed, uint32 baud); +void usart_enable(usart_dev *dev); +void usart_disable(usart_dev *dev); +void usart_foreach(void (*fn)(usart_dev *dev)); +void usart_putstr(usart_dev *dev, const char*); +void usart_putudec(usart_dev *dev, uint32 val); /** - * @brief send one character on a usart - * @param usart_num usart to send on - * @param byte byte to send + * @brief Disable all serial ports. */ -static inline void usart_putc(uint8 usart_num, uint8 byte) { - usart_port *port = usart_dev_table[usart_num].base; +static inline void usart_disable_all(void) { + usart_foreach(usart_disable); +} - /* Wait for the buffer to empty */ - while ((port->SR & USART_TXE) == 0) +/** + * @brief Transmit one character on a serial port. + * @param dev Serial port to send on. + * @param byte Byte to transmit. + */ +static inline void usart_putc(usart_dev* dev, uint8 byte) { + usart_reg_map *regs = dev->regs; + + while ((regs->SR & USART_SR_TXE) == 0) ; - port->DR = byte; + regs->DR = byte; } /** - * @brief read one character from a usart - * @param usart_num usart to read from + * @brief Read one character from a serial port. + * + * It's not safe to call this function if the serial port has no data + * available. + * + * @param dev Serial port to read from * @return byte read + * @see usart_data_available() */ -static inline uint8 usart_getc(uint8 usart_num) { - return rb_remove(&usart_dev_table[usart_num].rb); +static inline uint8 usart_getc(usart_dev *dev) { + return rb_remove(dev->rb); } /** - * @brief return the amount of data available in the rx buffer - * @param usart_num which usart to check - * @return number of bytes in the rx buffer + * @brief Return the amount of data available in a serial port's RX buffer. + * @param dev Serial port to check + * @return Number of bytes in dev's RX buffer. */ -static inline uint32 usart_data_available(uint8 usart_num) { - return rb_full_count(&usart_dev_table[usart_num].rb); +static inline uint32 usart_data_available(usart_dev *dev) { + return rb_full_count(dev->rb); } /** - * @brief removes the contents of the rx fifo - * @param usart_num which usart to reset + * @brief Discard the contents of a serial port's RX buffer. + * @param dev Serial port whose buffer to empty. */ -static inline void usart_reset_rx(uint8 usart_num) { - rb_reset(&usart_dev_table[usart_num].rb); +static inline void usart_reset_rx(usart_dev *dev) { + rb_reset(dev->rb); } -void usart_init(uint8 usart_num, uint32 baud); -void usart_disable(uint8 usart_num); -void usart_disable_all(); -void usart_putstr(uint8 usart_num, const char*); -void usart_putudec(uint8 usart_num, uint32 val); - #ifdef __cplusplus } // extern "C" #endif diff --git a/libmaple/util.c b/libmaple/util.c index 77af5b8..4a234ae 100644 --- a/libmaple/util.c +++ b/libmaple/util.c @@ -24,7 +24,7 @@ /** * @brief Utility procedures for debugging, mostly an error LED fade - * and messages dumped over a uart for failed asserts. + * and messages dumped over a UART for failed asserts. */ #include "libmaple.h" @@ -34,38 +34,38 @@ #include "adc.h" #include "timer.h" -/* Failed asserts send out a message on this USART. */ -#ifndef ERROR_USART_NUM -#define ERROR_USART_NUM USART2 +/* Failed ASSERT()s send out a message using this USART config. */ +#ifndef ERROR_USART +#define ERROR_USART USART2 +#define ERROR_USART_CLK_SPEED 72000000UL #define ERROR_USART_BAUD 9600 #define ERROR_TX_PORT GPIOA #define ERROR_TX_PIN 2 #endif /* If you define ERROR_LED_PORT and ERROR_LED_PIN, then a failed - assert will also throb an LED connected to that port an pin. - FIXME this should work together with wirish somehow. */ + * ASSERT() will also throb() an LED connected to that port and pin. + */ #if defined(ERROR_LED_PORT) && defined(ERROR_LED_PIN) #define HAVE_ERROR_LED #endif /** * @brief Disables all peripheral interrupts except USB and fades the - * error LED. - * - * Called from exc.S with global interrupts disabled. + * error LED. */ +/* (Called from exc.S with global interrupts disabled.) */ void __error(void) { /* Turn off peripheral interrupts */ nvic_irq_disable_all(); - /* Turn off timers */ + /* Turn off timers */ timer_disable_all(); /* Turn off ADC */ adc_disable_all(); - /* Turn off all usarts */ + /* Turn off all USARTs */ usart_disable_all(); /* Turn the USB interrupt back on so the bootloader keeps on functioning */ @@ -78,33 +78,33 @@ void __error(void) { } /** - * @brief Prints an error message on a uart upon a failed assertion - * and error throbs. + * @brief Print an error message on a UART upon a failed assertion + * and throb the error LED, if there is one defined. * @param file Source file of failed assertion * @param line Source line of failed assertion * @param exp String representation of failed assertion * @sideeffect Turns of all peripheral interrupts except USB. */ void _fail(const char* file, int line, const char* exp) { - /* Initialize the error usart */ + /* Initialize the error USART */ gpio_set_mode(ERROR_TX_PORT, ERROR_TX_PIN, GPIO_AF_OUTPUT_PP); - usart_init(ERROR_USART_NUM, ERROR_USART_BAUD); + usart_init(ERROR_USART); + usart_set_baud_rate(ERROR_USART, ERROR_USART_CLK_SPEED, ERROR_USART_BAUD); /* Print failed assert message */ - usart_putstr(ERROR_USART_NUM, "ERROR: FAILED ASSERT("); - usart_putstr(ERROR_USART_NUM, exp); - usart_putstr(ERROR_USART_NUM, "): "); - usart_putstr(ERROR_USART_NUM, file); - usart_putstr(ERROR_USART_NUM, ": "); - usart_putudec(ERROR_USART_NUM, line); - usart_putc(ERROR_USART_NUM, '\n'); - usart_putc(ERROR_USART_NUM, '\r'); + usart_putstr(ERROR_USART, "ERROR: FAILED ASSERT("); + usart_putstr(ERROR_USART, exp); + usart_putstr(ERROR_USART, "): "); + usart_putstr(ERROR_USART, file); + usart_putstr(ERROR_USART, ": "); + usart_putudec(ERROR_USART, line); + usart_putc(ERROR_USART, '\n'); + usart_putc(ERROR_USART, '\r'); /* Error fade */ __error(); } - /** * @brief Fades the error LED on and off * @sideeffect Sets output push-pull on ERROR_LED_PIN. @@ -117,7 +117,7 @@ void throb(void) { uint32 i = 0; gpio_set_mode(ERROR_LED_PORT, ERROR_LED_PIN, GPIO_OUTPUT_PP); - /* Error fade */ + /* Error fade. */ while (1) { if (CC == TOP_CNT) { slope = -1; @@ -138,9 +138,8 @@ void throb(void) { i++; } #else - /* No error LED is connected; do nothing. */ + /* No error LED is defined; do nothing. */ while (1) ; #endif } - diff --git a/wirish/comm/HardwareSerial.cpp b/wirish/comm/HardwareSerial.cpp index 8398878..aa8855b 100644 --- a/wirish/comm/HardwareSerial.cpp +++ b/wirish/comm/HardwareSerial.cpp @@ -24,69 +24,85 @@ /** * @file HardwareSerial.cpp - * - * @brief Wiring-like serial api + * @brief Wirish serial port implementation. */ -#include "wirish.h" +#include "gpio.h" +#include "timer.h" + #include "HardwareSerial.h" -#include "usart.h" - -// FIXME: High density device ports, usages of BOARD_USARTx_yX_PIN -// instead of holding onto a gpio_dev, tx_pin, rx_pin, timer_dev, and -// channel_num -- that stuff is all in the PIN_MAP. -HardwareSerial Serial1(USART1, 4500000UL, GPIOA, 9, 10, TIMER1, 2); -HardwareSerial Serial2(USART2, 2250000UL, GPIOA, 2, 3, TIMER2, 3); -HardwareSerial Serial3(USART3, 2250000UL, GPIOB, 10, 11, NULL, 0); - -HardwareSerial::HardwareSerial(uint8 usart_num, - uint32 max_baud, - gpio_dev *gpio_device, +#include "boards.h" + +#define TX1 BOARD_USART1_TX_PIN +#define RX1 BOARD_USART1_RX_PIN +#define TX2 BOARD_USART2_TX_PIN +#define RX2 BOARD_USART2_RX_PIN +#define TX3 BOARD_USART3_TX_PIN +#define RX3 BOARD_USART3_RX_PIN +#if defined STM32_HIGH_DENSITY && !defined(BOARD_maple_RET6) +#define TX4 BOARD_UART4_TX_PIN +#define RX4 BOARD_UART4_RX_PIN +#define TX5 BOARD_UART5_TX_PIN +#define RX5 BOARD_UART5_RX_PIN +#endif + +HardwareSerial Serial1(USART1, TX1, RX1); +HardwareSerial Serial2(USART2, TX2, RX2); +HardwareSerial Serial3(USART3, TX3, RX3); +#if defined(STM32_HIGH_DENSITY) && !defined(BOARD_maple_RET6) +HardwareSerial Serial4(UART4, TX4, RX4); +HardwareSerial Serial5(UART5, TX5, RX5); +#endif + +HardwareSerial::HardwareSerial(usart_dev *usart_device, uint8 tx_pin, - uint8 rx_pin, - timer_dev *timer_device, - uint8 channel_num) { - this->usart_num = usart_num; - this->max_baud = max_baud; - this->gpio_device = gpio_device; + uint8 rx_pin) { + this->usart_device = usart_device; this->tx_pin = tx_pin; this->rx_pin = rx_pin; - this->timer_device = timer_device; - this->channel_num = channel_num; } uint8 HardwareSerial::read(void) { - return usart_getc(usart_num); + return usart_getc(usart_device); } uint32 HardwareSerial::available(void) { - return usart_data_available(usart_num); + return usart_data_available(usart_device); } void HardwareSerial::write(unsigned char ch) { - usart_putc(usart_num, ch); + usart_putc(usart_device, ch); } void HardwareSerial::begin(uint32 baud) { - if (baud > max_baud) { + ASSERT(baud <= usart_device->max_baud); + + if (baud > usart_device->max_baud) { return; } - gpio_set_mode(gpio_device, tx_pin, GPIO_AF_OUTPUT_PP); - gpio_set_mode(gpio_device, rx_pin, GPIO_INPUT_FLOATING); + const stm32_pin_info *txi = &PIN_MAP[tx_pin]; + const stm32_pin_info *rxi = &PIN_MAP[rx_pin]; + + gpio_set_mode(txi->gpio_device, txi->gpio_bit, GPIO_AF_OUTPUT_PP); + gpio_set_mode(rxi->gpio_device, rxi->gpio_bit, GPIO_INPUT_FLOATING); - if (timer_device != NULL) { - /* turn off any pwm if there's a conflict on this usart */ - timer_set_mode(timer_device, channel_num, TIMER_DISABLED); + if (txi->timer_device != NULL) { + /* Turn off any PWM if there's a conflict on this GPIO bit. */ + timer_set_mode(txi->timer_device, txi->timer_channel, TIMER_DISABLED); } - usart_init(usart_num, baud); + usart_init(usart_device); + usart_set_baud_rate(usart_device, + CYCLES_PER_MICROSECOND * 1000000UL, + baud); + usart_enable(usart_device); } void HardwareSerial::end(void) { - usart_disable(usart_num); + usart_disable(usart_device); } void HardwareSerial::flush(void) { - usart_reset_rx(usart_num); + usart_reset_rx(usart_device); } diff --git a/wirish/comm/HardwareSerial.h b/wirish/comm/HardwareSerial.h index 7852d51..5e86f79 100644 --- a/wirish/comm/HardwareSerial.h +++ b/wirish/comm/HardwareSerial.h @@ -24,43 +24,33 @@ /** * @file HardwareSerial.h - * - * @brief Wirish interface to hardware serial communications. + * @brief Wirish serial port interface. */ #ifndef _HARDWARESERIAL_H_ #define _HARDWARESERIAL_H_ #include "libmaple_types.h" -#include "gpio.h" -#include "timer.h" +#include "usart.h" #include "Print.h" -/* NB: this class documented "by hand" (i.e., not using Doxygen) in: - - libmaple/docs/source/lang/serial.rst - - If you alter the public HardwareSerial interface, you must update - the documentation accordingly. */ +/* + * IMPORTANT: + * + * This class documented "by hand" (i.e., not using Doxygen) in: + * + * libmaple/docs/source/lang/api/serial.rst + * + * If you alter the public HardwareSerial interface, you MUST update + * the documentation accordingly. + */ class HardwareSerial : public Print { - private: - uint8 usart_num; - uint32 max_baud; - gpio_dev *gpio_device; - uint8 tx_pin; - uint8 rx_pin; - timer_dev *timer_device; - uint8 channel_num; - public: - HardwareSerial(uint8 usart_num, - uint32 max_baud, - gpio_dev *gpio_device, +public: + HardwareSerial(usart_dev *usart_device, uint8 tx_pin, - uint8 rx_pin, - timer_dev *timer_device, - uint8 channel_num); + uint8 rx_pin); void begin(uint32 baud); void end(void); uint32 available(void); @@ -68,10 +58,18 @@ class HardwareSerial : public Print { void flush(void); virtual void write(unsigned char); using Print::write; +private: + usart_dev *usart_device; + uint8 tx_pin; + uint8 rx_pin; }; + extern HardwareSerial Serial1; extern HardwareSerial Serial2; extern HardwareSerial Serial3; -// TODO: high density device ports +#if defined(STM32_HIGH_DENSITY) && !defined(BOARD_maple_RET6) +extern HardwareSerial Serial4; +extern HardwareSerial Serial5; #endif +#endif -- cgit v1.2.3 From a2b2ddb50b16400f17d8d36dfc9f4996f466ad94 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Thu, 7 Apr 2011 14:43:00 -0400 Subject: Coding standard updates. --- notes/coding_standard.txt | 60 ++++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/notes/coding_standard.txt b/notes/coding_standard.txt index 0accda7..f762e98 100644 --- a/notes/coding_standard.txt +++ b/notes/coding_standard.txt @@ -95,11 +95,13 @@ Comments - Doxygen comments are multi-line comments that begin with /** instead. -- Single-line comments on the same line are // in C or C++. +- Single-line comments on the same line are // in C++. (That's OK in C + as well). - Single-line comments on their own source line should be /* */ in C, but can also be // in C++. In Emacs, you can use M-; - (comment-dwim), and it'll Do What You Mean. + (comment-dwim), and it'll Do What You Mean. This isn't of great + importance. Braces ------ @@ -131,23 +133,27 @@ We'll handle this as follows. int some_example_name; - It is strongly advised to do it this way in C++ too, but it's not - [yet] mandatory. + User-facing C++ variables should be camel cased (thisIsAnExample, + boardPWMPins, etc.), for consistency with the Arduino style. It's + probably a good idea for you to case non-user facing C++ variables + in the C style; this will help disambiguate what's part of the + Wirish API and what's not. - Classes: Pascal case. So ThisIsAClassName, but thisIsNot, this_is_not, and like I said, Dont_You_DareTryANYTHING_STUPID. - Functions: C functions are all lowercase, and words are separated by - underscores. C++ method names are camel cased (thisIsAnExample). + underscores. C++ method names are camel cased. - Structs: Usually like variables (adc_dev, adc_reg_map, etc.), but - it's not crucial. If it's in a typedef, don't feel obliged to put - "_t" at the end of the name; we don't. + it's not crucial. Don't feel obliged to put "_t" at the end of the + type name; we don't. - Macros and constants: all caps, separated by underscores. Variables with the "const" qualifier aren't considered "constants" for the purposes of this rule; i.e., case them according to the rules for - variables. + variables. (We make an exception for PIN_MAP, but that's because + it's the central data structure for all of Wirish). - foo.h gets #ifdef'ed to _FOO_H_. @@ -157,28 +163,30 @@ We'll handle this as follows. void usb_func() { ... } + void frob_usb_disc() { ... } + class SomethingUSB { void usbInit(); void initUSB(); }; - Never do this: + DON'T do this: class BadUsb { ... }; // say "GoodUSB" instead + void swizzle_USB_disc() { ... } // say "swizzle_usb_disc" instead + Documentation ------------- -- Document your code! - -- For complicated peripherals, it would be nice if you put longer-form - comments into this directory (notes/), with a comment in the - corresponding .h file referring to it. See libmaple/dac.h for an - example. That lets us keep the source files relatively clean while - still allowing new readers to have a starting point. +- You must document your code. At a bare minimum, this means Doxygen + comments on every user-facing function and type. Additionally, you + need to individually document the fields and enumerator values of + structs and enums. See any register map type's definition for an + example. -- At least put a Doxygen comment with a nonempty @brief for every .h - file you add. See the existing ones for examples. +- For libmaple proper, you don't need comments for each register bit + definition (for now). - Doxygen comments generally just belong on types, functions, etc. that are part of the public user-facing API. This generally @@ -198,6 +206,15 @@ Documentation source file informing future maintainers about it, so they'll pay extra attention when making changes. +- For complicated peripherals, it would be nice if you put longer-form + comments into the libmaple notes/ directory, with a comment in the + corresponding .h file referring to it. See libmaple/dac.h for an + example. + + This lets us keep the source files relatively clean while still + allowing new readers to have a starting point. These longer-form + notes also have a habit of turning into user-facing documentation. + - For libmaple proper (the pure C library under libmaple/); the convention is to document any user-facing entity at the point where it is defined. In particular, this means you should document an @@ -208,16 +225,15 @@ General Formatting ------------------ - Keep it 80-column clean. That means Emacs says the largest column - number=79. If you haven't already, you should turn on column - numbers to help you out: + number=79. You should turn on column number mode to help you out: (column-number-mode 1) - You can get more help from lineker-mode. Download it here: + You can get more help from lineker-mode: http://www.helsinki.fi/~sjpaavol/programs/lineker.el - Then put the file somewhere in your load-path, and: + Just put lineker.el somewhere in your load-path, and: (require 'lineker) (dolist (hook '(c-mode-hook c++-mode-hook)) -- cgit v1.2.3 From f044b9af59a5db69ae8dbf8f9a1097c82c716f7f Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Thu, 7 Apr 2011 15:04:06 -0400 Subject: Renaming some nvic_irq_num enumerators for better readability. --- libmaple/exti.c | 32 ++++++++++++++++---------------- libmaple/nvic.h | 8 ++++---- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/libmaple/exti.c b/libmaple/exti.c index 7f56712..38d3bba 100644 --- a/libmaple/exti.c +++ b/libmaple/exti.c @@ -46,22 +46,22 @@ typedef struct exti_channel { } exti_channel; static exti_channel exti_channels[] = { - { .handler = NULL, .irq_line = NVIC_EXTI0 }, // EXTI0 - { .handler = NULL, .irq_line = NVIC_EXTI1 }, // EXTI1 - { .handler = NULL, .irq_line = NVIC_EXTI2 }, // EXTI2 - { .handler = NULL, .irq_line = NVIC_EXTI3 }, // EXTI3 - { .handler = NULL, .irq_line = NVIC_EXTI4 }, // EXTI4 - { .handler = NULL, .irq_line = NVIC_EXTI9_5 }, // EXTI5 - { .handler = NULL, .irq_line = NVIC_EXTI9_5 }, // EXTI6 - { .handler = NULL, .irq_line = NVIC_EXTI9_5 }, // EXTI7 - { .handler = NULL, .irq_line = NVIC_EXTI9_5 }, // EXTI8 - { .handler = NULL, .irq_line = NVIC_EXTI9_5 }, // EXTI9 - { .handler = NULL, .irq_line = NVIC_EXTI15_10 }, // EXTI10 - { .handler = NULL, .irq_line = NVIC_EXTI15_10 }, // EXTI11 - { .handler = NULL, .irq_line = NVIC_EXTI15_10 }, // EXTI12 - { .handler = NULL, .irq_line = NVIC_EXTI15_10 }, // EXTI13 - { .handler = NULL, .irq_line = NVIC_EXTI15_10 }, // EXTI14 - { .handler = NULL, .irq_line = NVIC_EXTI15_10 }, // EXTI15 + { .handler = NULL, .irq_line = NVIC_EXTI0 }, // EXTI0 + { .handler = NULL, .irq_line = NVIC_EXTI1 }, // EXTI1 + { .handler = NULL, .irq_line = NVIC_EXTI2 }, // EXTI2 + { .handler = NULL, .irq_line = NVIC_EXTI3 }, // EXTI3 + { .handler = NULL, .irq_line = NVIC_EXTI4 }, // EXTI4 + { .handler = NULL, .irq_line = NVIC_EXTI_9_5 }, // EXTI5 + { .handler = NULL, .irq_line = NVIC_EXTI_9_5 }, // EXTI6 + { .handler = NULL, .irq_line = NVIC_EXTI_9_5 }, // EXTI7 + { .handler = NULL, .irq_line = NVIC_EXTI_9_5 }, // EXTI8 + { .handler = NULL, .irq_line = NVIC_EXTI_9_5 }, // EXTI9 + { .handler = NULL, .irq_line = NVIC_EXTI_15_10 }, // EXTI10 + { .handler = NULL, .irq_line = NVIC_EXTI_15_10 }, // EXTI11 + { .handler = NULL, .irq_line = NVIC_EXTI_15_10 }, // EXTI12 + { .handler = NULL, .irq_line = NVIC_EXTI_15_10 }, // EXTI13 + { .handler = NULL, .irq_line = NVIC_EXTI_15_10 }, // EXTI14 + { .handler = NULL, .irq_line = NVIC_EXTI_15_10 }, // EXTI15 }; /* diff --git a/libmaple/nvic.h b/libmaple/nvic.h index a889f4b..df3461b 100644 --- a/libmaple/nvic.h +++ b/libmaple/nvic.h @@ -89,12 +89,12 @@ typedef enum nvic_irq_num { NVIC_DMA_CH5 = 15, /**< DMA1 channel 5 */ NVIC_DMA_CH6 = 16, /**< DMA1 channel 6 */ NVIC_DMA_CH7 = 17, /**< DMA1 channel 7 */ - NVIC_ADC1_2 = 18, /**< ADC1 and ADC2 */ + NVIC_ADC_1_2 = 18, /**< ADC1 and ADC2 */ NVIC_USB_HP_CAN_TX = 19, /**< USB high priority or CAN TX */ NVIC_USB_LP_CAN_RX0 = 20, /**< USB low priority or CAN RX0 */ NVIC_CAN_RX1 = 21, /**< CAN RX1 */ NVIC_CAN_SCE = 22, /**< CAN SCE */ - NVIC_EXTI9_5 = 23, /**< EXTI line [9:5] */ + NVIC_EXTI_9_5 = 23, /**< EXTI line [9:5] */ NVIC_TIMER1_BRK = 24, /**< Timer 1 break */ NVIC_TIMER1_UP = 25, /**< Timer 1 update */ NVIC_TIMER1_TRG_COM = 26, /**< Timer 1 trigger and commutation */ @@ -111,7 +111,7 @@ typedef enum nvic_irq_num { NVIC_USART1 = 37, /**< USART1 */ NVIC_USART2 = 38, /**< USART2 */ NVIC_USART3 = 39, /**< USART3 */ - NVIC_EXTI15_10 = 40, /**< EXTI line [15:10] */ + NVIC_EXTI_15_10 = 40, /**< EXTI line [15:10] */ NVIC_RTCALARM = 41, /**< RTC alarm through EXTI line */ NVIC_USBWAKEUP = 42, /**< USB wakeup from suspend through EXTI line */ @@ -132,7 +132,7 @@ typedef enum nvic_irq_num { NVIC_DMA2_CH1 = 56, /**< DMA2 channel 1 */ NVIC_DMA2_CH2 = 57, /**< DMA2 channel 2 */ NVIC_DMA2_CH3 = 58, /**< DMA2 channel 3 */ - NVIC_DMA2_CH4_5 = 59, /**< DMA2 channels 4 and 5 */ + NVIC_DMA2_CH_4_5 = 59, /**< DMA2 channels 4 and 5 */ #endif } nvic_irq_num; -- cgit v1.2.3 From b04fc94cfc991855544625af7e67ecf07c02f542 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Thu, 7 Apr 2011 16:24:25 -0400 Subject: Timer tweaks. --- libmaple/timer.c | 30 +++++------ notes/timers.txt | 152 ++++++++++++++++++++++++++++--------------------------- 2 files changed, 90 insertions(+), 92 deletions(-) diff --git a/libmaple/timer.c b/libmaple/timer.c index a4e4032..b22ffb4 100644 --- a/libmaple/timer.c +++ b/libmaple/timer.c @@ -32,12 +32,6 @@ #include "timer.h" -#if defined(STM32_MEDIUM_DENSITY) -#define NR_TIMERS 4 -#elif defined(STM32_HIGH_DENSITY) -#define NR_TIMERS 8 -#endif - /* Just like the corresponding DIER bits: * [0] = Update handler; * [1,2,3,4] = capture/compare 1,2,3,4 handlers, respectively; @@ -51,7 +45,7 @@ #define NR_BAS_HANDLERS 1 static timer_dev timer1 = { - .regs = {.adv = TIMER1_BASE}, + .regs = { .adv = TIMER1_BASE }, .clk_id = RCC_TIMER1, .type = TIMER_ADVANCED, .handlers = { [NR_ADV_HANDLERS - 1] = 0 }, @@ -59,7 +53,7 @@ static timer_dev timer1 = { timer_dev *TIMER1 = &timer1; static timer_dev timer2 = { - .regs = {.gen = TIMER2_BASE}, + .regs = { .gen = TIMER2_BASE }, .clk_id = RCC_TIMER2, .type = TIMER_GENERAL, .handlers = { [NR_GEN_HANDLERS - 1] = 0 }, @@ -67,7 +61,7 @@ static timer_dev timer2 = { timer_dev *TIMER2 = &timer2; static timer_dev timer3 = { - .regs = {.gen = TIMER3_BASE}, + .regs = { .gen = TIMER3_BASE }, .clk_id = RCC_TIMER3, .type = TIMER_GENERAL, .handlers = { [NR_GEN_HANDLERS - 1] = 0 }, @@ -75,7 +69,7 @@ static timer_dev timer3 = { timer_dev *TIMER3 = &timer3; static timer_dev timer4 = { - .regs = {.gen = TIMER4_BASE}, + .regs = { .gen = TIMER4_BASE }, .clk_id = RCC_TIMER4, .type = TIMER_GENERAL, .handlers = { [NR_GEN_HANDLERS - 1] = 0 }, @@ -84,7 +78,7 @@ timer_dev *TIMER4 = &timer4; #ifdef STM32_HIGH_DENSITY static timer_dev timer5 = { - .regs = {.gen = TIMER5_BASE}, + .regs = { .gen = TIMER5_BASE }, .clk_id = RCC_TIMER5, .type = TIMER_GENERAL, .handlers = { [NR_GEN_HANDLERS - 1] = 0 }, @@ -92,7 +86,7 @@ static timer_dev timer5 = { timer_dev *TIMER5 = &timer5; static timer_dev timer6 = { - .regs = {.bas = TIMER6_BASE}, + .regs = { .bas = TIMER6_BASE }, .clk_id = RCC_TIMER6, .type = TIMER_BASIC, .handlers = { [NR_BAS_HANDLERS - 1] = 0 }, @@ -100,7 +94,7 @@ static timer_dev timer6 = { timer_dev *TIMER6 = &timer6; static timer_dev timer7 = { - .regs = {.bas = TIMER7_BASE}, + .regs = { .bas = TIMER7_BASE }, .clk_id = RCC_TIMER7, .type = TIMER_BASIC, .handlers = { [NR_BAS_HANDLERS - 1] = 0 }, @@ -108,7 +102,7 @@ static timer_dev timer7 = { timer_dev *TIMER7 = &timer7; static timer_dev timer8 = { - .regs = {.adv = TIMER8_BASE}, + .regs = { .adv = TIMER8_BASE }, .clk_id = RCC_TIMER8, .type = TIMER_ADVANCED, .handlers = { [NR_ADV_HANDLERS - 1] = 0 }, @@ -168,7 +162,7 @@ void timer_disable(timer_dev *dev) { * @param mode New timer mode for channel */ void timer_set_mode(timer_dev *dev, uint8 channel, timer_mode mode) { - ASSERT(channel > 0 && channel <= 4); + ASSERT_FAULT(channel > 0 && channel <= 4); /* TODO decide about the basic timers */ ASSERT(dev->type != TIMER_BASIC); @@ -351,8 +345,8 @@ static inline void dispatch_cc_irqs(timer_dev *dev) { uint32 sr_clear = 0; uint32 b; - ASSERT(sr & (TIMER_SR_CC1IF | TIMER_SR_CC2IF | - TIMER_SR_CC3IF | TIMER_SR_CC4IF)); + ASSERT_FAULT(sr & (TIMER_SR_CC1IF | TIMER_SR_CC2IF | + TIMER_SR_CC3IF | TIMER_SR_CC4IF)); for (b = TIMER_SR_CC1IF_BIT; b <= TIMER_SR_CC4IF_BIT; b++) { uint32 mask = BIT(b); @@ -443,7 +437,7 @@ static void enable_nonmuxed_irq(timer_dev *dev) { break; #endif default: - ASSERT(0); + ASSERT_FAULT(0); break; } } diff --git a/notes/timers.txt b/notes/timers.txt index 3f5b9f4..647e92e 100644 --- a/notes/timers.txt +++ b/notes/timers.txt @@ -1,82 +1,87 @@ +Timers +====== -Each timer (1-4) has 4 capture/compare channels (1-4). These are directly used -by PWM but have a ton of other possible functionality. The STM32 implementation -is particularly complicated with, eg, the ability to chain together timers - -Timer1 is an "advanced timer" with many more features. I think if we use just -the "Capture and compare interrupt", and enable MOE during initialization -everything will be ok. There are seperate Break, Update, and Trigger interrupts -as well that we will ignore for now. - -Timer2,Ch 3+4 are D0 and D1, which conflict with Serial2. USART should work -fine as long as pins aren't in output mode? and timers should work fine if -Serial2 isn't in use? - -Caveats ------------------------------------------------------------------------------- -There are probably subtle bugs with the way register settings get read in; eg, -it is often required to have the counter fully overflow before new settings -come into effect? -Getting really good timing is still an art, not a science here... usually you -need to fiddle with an oscilloscope and the exact overflow/compare numbers to -get just the right time values. -Any other interrupts (SysTick, USB, Serial, etc) can blow away all the nice -timing stuff. - -Misc Notes ------------------------------------------------------------------------------- -Implementation with case/switch in the interrupt handlers doesn't work; a lot -of the time multiple interrupt flags are active at the same time (or become -active?) +Medium-density chips have timers 1 through 4. High- and XL-density +chips additionally have timers 5 through 8. XL-density chips +additionally have timers 9--14, which we don't support yet. + +Timer Capabilities +------------------ + +Each of timers 1--4 has 4 capture/compare (C/C) channels (also numbered +1--4). These are directly used by PWM, but may serve other purposes as +well (including handling user-specified periodic interrupts). The +STM32 implementation is particularly featureful, with, e.g., the +ability to chain together timers. + +Timers 1 and 8 are an advanced timers, with many more features. +Wirish just uses just their capture/compare interrupts and enables MOE +during initialization, essentially treating them as general purpose +timers (like timers 2--5). Advanced timers also have separate break, +update, and trigger interrupts that we only provide low-level +(i.e. libmaple proper) support for. + +Timers 6 and 7 are basic timers, without C/C channels. They are still +useful for interrupts (via NVIC_TIMER6, NVIC_TIMER7 IRQs, which can +fire upon an update event), but they're most useful for controlling +periodic DAC output. + +Known Issues and Other Caveats +------------------------------ + +There are some conflicts between timer C/C outputs and USART 1 and 2 +TX/RX. Wirish tries to handle this gracefully, but (as of 7 April +2011) not all the bugs are sorted yet. In particular, if you call +HardwareSerial::disable(), then try to use PWM, the USART TX pins +don't cooperate. + +Resetting the prescaler or reload value only takes effect at the next +update event. You can use timer_generate_update() to generate an +update event via software. + +Other interrupts (SysTick, USB, Serial, etc.) can interfere with +timing-critical applications. If your program requires precise +timing, you should probably at least disable USB and SysTick. Note +that this also disables the bootloader and stops millis()/micros() +from counting. + +Getting really good timing is a bit of an art. If things don't work +at first, you need to fiddle with an oscilloscope and the exact +overflow/compare numbers to get precise behavior. TODO ------------------------------------------------------------------------------- -- document carefully (eg, determine clock-wise and overflow-wise behavior for - each function) -- track down and handle all pin conflicts -- implement the update interrupt as a "5th channel" -- "pulse in" stuff, both c and c++ -- function to read out CCR registers -- allow comparison output to the pin (a la PWM) -- additional modes and configuration (up, down, up/down, etc) - -Possible Wirish implementation ------------------------------------------------------------------------------- -Inspired by Timer1 Library for arduino -http://arduino.cc/pipermail/developers_arduino.cc/2010-June/002845.html +---- + +- Document more carefully (e.g., determine clock-wise and + overflow-wise behavior for each function). - class HardwareTimer { - - public: - - void pause(); - void resume(); - void setPrescaleFactor(uint8 factor); - void setOverflow(uint16 val); // truncates to overflow - void setCount(uint16 val); // truncates to overflow - uint16 getCount(); - uint16 setPeriod(uint32 microseconds); // tries to set prescaler and overflow wisely; returns overflow - void setMode(uint8 mode); - void setCompare1(uint16 val); // truncates to overflow - void setCompare2(uint16 val); // truncates to overflow - void setCompare3(uint16 val); // truncates to overflow - void setCompare4(uint16 val); // truncates to overflow - void attachCompare1Interrupt(void (*f)(void)); - void attachCompare2Interrupt(void (*f)(void)); - void attachCompare3Interrupt(void (*f)(void)); - void attachCompare4Interrupt(void (*f)(void)); - void detachCompare1Interrupt(); - void detachCompare2Interrupt(); - void detachCompare3Interrupt(); - void detachCompare4Interrupt(); - }; - - HardwareTimer Timer1 = HardwareTimer(1); - HardwareTimer Timer2 = HardwareTimer(2); - HardwareTimer Timer3 = HardwareTimer(3); - HardwareTimer Timer4 = HardwareTimer(4); +- Track down and handle pin conflicts. + +- Input capture interface. DON'T WRITE pulseIn() IN TERMS OF THIS. + Do that as a simple, Arduino style implementation that just + busy-waits and uses micros(), to allow a pulseIn() on arbitrary + pins. Eventually, expose the more precise/harder to use timer-based + API via a convenience library. + +- Complementary outputs, with convenient break/dead time interface. + +- Additional modes (center-aligned PWM, one pulse mode, etc.) and + count configuration (down, up/down). + +Alternative Wirish Implementations +---------------------------------- + +The current Wirish API is big and clunky. Its inclusion by default +also threatens making everyone's sketches bigger unnecessarily. We +need to deprecate the parts of it that are bad for 0.0.10, and remove +them when 0.1.0 comes out. + +Current implementation was inspired by Timer1 Library for Arduino: + +http://arduino.cc/pipermail/developers_arduino.cc/2010-June/002845.html Here's one of the more standard libaries out there: + http://www.arduino.cc/playground/Code/Timer1 void initialize(long microseconds=1000000); @@ -89,4 +94,3 @@ http://www.arduino.cc/playground/Code/Timer1 void disablePwm(char pin); void attachInterrupt(void (*isr)(), long microseconds=-1); void detachInterrupt(); - -- cgit v1.2.3 From 686f12ad6728fec15129a98f5d1ec182bab4c6b9 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Thu, 7 Apr 2011 21:57:15 -0400 Subject: Coding standard tweaks. --- notes/coding_standard.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/notes/coding_standard.txt b/notes/coding_standard.txt index f762e98..5b258f7 100644 --- a/notes/coding_standard.txt +++ b/notes/coding_standard.txt @@ -149,11 +149,11 @@ We'll handle this as follows. it's not crucial. Don't feel obliged to put "_t" at the end of the type name; we don't. -- Macros and constants: all caps, separated by underscores. Variables - with the "const" qualifier aren't considered "constants" for the - purposes of this rule; i.e., case them according to the rules for - variables. (We make an exception for PIN_MAP, but that's because - it's the central data structure for all of Wirish). +- Macros and constants: all caps, separated by underscores. C++ + variables with the "const" qualifier generally aren't considered + "constants" for the purposes of this rule; i.e., they are cased + according to the rules for variables. We make an exception for + PIN_MAP, because it's the central Wirish data structure. - foo.h gets #ifdef'ed to _FOO_H_. @@ -216,7 +216,7 @@ Documentation notes also have a habit of turning into user-facing documentation. - For libmaple proper (the pure C library under libmaple/); the - convention is to document any user-facing entity at the point where + convention is to document any user-facing function at the point where it is defined. In particular, this means you should document an externally-linked function defined in a .c file in that .c file, not in the header file where it is declared to the user. -- cgit v1.2.3 From 308b5c8f36f517f5c62cd037124982a45e7b5fa1 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Thu, 7 Apr 2011 23:10:50 -0400 Subject: USART fixups. * usart_enable(): Doxygen comment bugfix. * usart_disable(): previously, usart_disable() would nuke the entire CR1 register just to clear the UE bit. --- libmaple/usart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libmaple/usart.c b/libmaple/usart.c index df5e2c5..de808a7 100644 --- a/libmaple/usart.c +++ b/libmaple/usart.c @@ -120,7 +120,7 @@ void usart_set_baud_rate(usart_dev *dev, uint32 clock_speed, uint32 baud) { * @brief Enable a serial port. * * USART is enabled in single buffer transmission mode, multibuffer - * receiver mode, at the given baud rate, 8n1. + * receiver mode, 8n1. * * Serial port must have a baud rate configured to work properly. * @@ -146,7 +146,7 @@ void usart_disable(usart_dev *dev) { ; /* Disable UE */ - regs->CR1 = 0; + regs->CR1 &= ~USART_CR1_UE; /* Clean up buffer */ usart_reset_rx(dev); -- cgit v1.2.3 From 5329ec3089b4fb6b3023d7f6a44eabcc30e3c9dd Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Fri, 8 Apr 2011 12:53:28 -0400 Subject: Trivial main.cpp.example cleanup. --- main.cpp.example | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/main.cpp.example b/main.cpp.example index 3ae114b..23d5540 100644 --- a/main.cpp.example +++ b/main.cpp.example @@ -28,15 +28,16 @@ void loop() { // Force init to be called *first*, i.e. before static object allocation. // Otherwise, statically allocated objects that need libmaple may fail. -__attribute__(( constructor )) void premain() { +__attribute__((constructor)) void premain() { init(); } int main(void) { setup(); - while (1) { + while (true) { loop(); } + return 0; } -- cgit v1.2.3 From fe8fb8a931306a9701a7f7fa96e1880e1c3123bc Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Fri, 8 Apr 2011 15:56:14 -0400 Subject: Adding CLOCK_SPEED_MHZ and CLOCK_SPEED_HZ as derived board-specific values. --- docs/source/lang/api/board-values.rst | 6 ++++++ wirish/boards.h | 17 +++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/docs/source/lang/api/board-values.rst b/docs/source/lang/api/board-values.rst index 367adbb..d6d78f6 100644 --- a/docs/source/lang/api/board-values.rst +++ b/docs/source/lang/api/board-values.rst @@ -18,6 +18,12 @@ boards. Some example usages are given :ref:`below Constants --------- +- ``CLOCK_SPEED_MHZ``: Clock speed of your board, in megahertz + (MHz). This is the same as ``CYCLES_PER_MICROSECOND``. + +- ``CLOCK_SPEED_HZ``: Clock speed of your board, in hertz (Hz). This + is the same as ``CLOCK_SPEED_MHZ * 1000000``. + - ``CYCLES_PER_MICROSECOND``: Number of CPU cycles per microsecond on your board. diff --git a/wirish/boards.h b/wirish/boards.h index 8df7028..2515c00 100644 --- a/wirish/boards.h +++ b/wirish/boards.h @@ -119,8 +119,7 @@ bool boardUsesPin(uint8 pin); /* Include the appropriate private header from boards/: */ -/* FIXME put boards/ before these paths once you stick make into the - * IDE; current situation is a hack. */ +/* FIXME HACK put boards/ before these paths once IDE uses make. */ #ifdef BOARD_maple #include "maple.h" @@ -136,7 +135,21 @@ bool boardUsesPin(uint8 pin); */ #include "maple_RET6.h" #else +/* + * TODO turn this into a warning so people can: + * + * #include "my_board_config.h" + * #include "wirish.h" + * + * This will enable third-party board support without requiring that + * anybody hack around in libmaple itself. + */ #error "Board type has not been selected correctly." #endif +/* Set derived definitions */ + +#define CLOCK_SPEED_MHZ CYCLES_PER_MICROSECOND +#define CLOCK_SPEED_HZ (CLOCK_SPEED_MHZ * 1000000UL) + #endif -- cgit v1.2.3 From 5e094ea3f219df403a67be8a85bf95591990b05e Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Fri, 8 Apr 2011 18:47:34 -0400 Subject: stm32loader.py prints more information about what it's doing. --- support/stm32loader.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/support/stm32loader.py b/support/stm32loader.py index 874d278..b0df7c0 100755 --- a/support/stm32loader.py +++ b/support/stm32loader.py @@ -294,6 +294,10 @@ class CommandInterface: def writeMemory(self, addr, data): lng = len(data) + + mdebug(5, "Writing %(lng)d bytes to start address 0x%(addr)X" % + { 'lng': lng, 'addr': addr}) + if usepbar: widgets = ['Writing: ', Percentage(),' ', ETA(), ' ', Bar()] pbar = ProgressBar(widgets=widgets, maxval=lng, term_width=79).start() @@ -316,12 +320,6 @@ class CommandInterface: self.cmdWriteMemory(addr, data[offs:offs+lng] + ([0xFF] * (256-lng)) ) - - - def __init__(self) : - pass - - def usage(): print """Usage: %s [-hqVewvr] [-l length] [-p port] [-b baud] [-a addr] [file.bin] -h This help @@ -452,6 +450,7 @@ if __name__ == "__main__": 'baud':conf['baud']}) try: if (conf['write'] or conf['verify']): + mdebug(5, "Reading data from %s" % args[0]) data = read(args[0]) try: -- cgit v1.2.3 From 479601b98c888f863f54dc53b85c29893ae4a4e7 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Fri, 8 Apr 2011 18:49:50 -0400 Subject: Documentation improvements. Simplified and clarified "flashing your own bootloader" documentation. Also made Windows 7 IDE workaround link directly to the forum post with the workaround, instead of the start of the thread. --- docs/source/bootloader.rst | 113 ++++++++++++++++++++++++-------------- docs/source/maple-ide-install.rst | 4 +- 2 files changed, 75 insertions(+), 42 deletions(-) diff --git a/docs/source/bootloader.rst b/docs/source/bootloader.rst index cfbf545..917a1b7 100644 --- a/docs/source/bootloader.rst +++ b/docs/source/bootloader.rst @@ -4,8 +4,6 @@ Maple Bootloader(s) ===================== -.. TODO: add a section on flashing your own bootloader - The firmware which allows the Maple to be reprogrammed via a USB connection. Every Maple board comes programmed with this by default, and it is not overwritten by regular programs (it lives lower in the @@ -585,20 +583,25 @@ DFU pipe and bringing up the USB serial port. Flashing A Custom Bootloader ---------------------------- -The STM32 microprocessor on the Maple comes with a built-in hardware +.. warning:: This section is for users who want to put a fresh or + custom bootloader on their board. It's possible to make a mistake + in this process and e.g. render your Maple unable to communicate + with the IDE. Know what you're doing, and proceed with caution. + +The STM32 microprocessor on the Maple comes with a built-in serial bootloader that can be used to flash a new (software) bootloader onto -the chip. This section describes how to go about this, using a Maple -Rev 3 or higher (if you have a Maple Rev 1; you don't have a BUT -button, and won't be able to follow these directions. A workaround is -detailed in `this forum posting -`_). - -.. warning:: This section is directed at users wishing to write a - custom bootloader for the Maple, or update their bootloader to a - more recent version. It's generally not necessary to do so, and it - is possible to make a mistake and e.g. render your Maple unable to - communicate with the IDE. Know what you're doing, and proceed with - caution. +the chip. While the Maple bootloader is just a program, the built-in +serial bootloader is part of the STM32 hardware, so it's always +available. + +This means that you can **always** follow these instructions to put a +new bootloader program on your board; it **doesn't matter** if there's +already a copy of the Maple bootloader on it or not. + +This section applies to Maple Rev 3 or higher. If you have a Maple +Rev 1; you don't have a BUT button, and won't be able to follow these +directions. A workaround is detailed in `this forum posting +`_. .. highlight:: sh @@ -615,10 +618,20 @@ In order to follow these instructions, you will need: **Step 1: Obtain a bootloader binary**. The first thing you'll need to do is to compile your bootloader binary. Note that an ASCII -representation of the binary, such as the Intel .hex format, will not -suffice. For example, you can run (on a :ref:`suitably configured -system `) the following to obtain a binary of the -bootloader currently used on the Maple:: +representation of the binary, such as the Intel .hex format, won't +work. + +.. FIXME [Mini, Native] links to precompiled bootloaders + +If you just want to flash the default Maple bootloader (the one that +was installed on your Maple when it arrived), we host a `pre-compiled +copy +`_, +which works on all Maple Revs. + +To obtain the latest development version, you can run (on a +:ref:`suitably configured system `) the following to +obtain a binary of the bootloader currently used on the Maple:: $ git checkout git://github.com/leaflabs/maple-bootloader.git $ cd maple-bootloader @@ -632,15 +645,20 @@ could use another Maple, an Arduino, etc. -- anything that allows your computer to communicate with the Maple you want to reprogram over a serial interface. +.. FIXME [Maple-specific values] + If you do use an FTDI breakout board, first make sure your Maple is disconnected from an external power source, be it battery, USB, or barrel jack. Then, connect the FTDI board's TX pin to ``Serial1``\ 's RX pin (pin 8), FTDI RX to ``Serial1`` TX (pin 7), FTDI ground to Maple's GND, and its 3.3V pin to Maple's Vin (use the Maple's -silkscreen for help locating these pins). At this point, you're ready -to plug the FTDI board into your computer (via USB). +silkscreen for help locating these pins). -The ``Serial1`` pins are documented :ref:`here `. +More information on ``Serial1`` is available :ref:`here +`. + +At this point, you're ready to plug the FTDI board into your computer +(via USB). **Step 3: Put your Maple into serial bootloader mode**. Do this by pressing the RESET button, then *while RESET is held down*, pressing @@ -648,35 +666,50 @@ and holding the BUT button. Next, *making sure to keep BUT held down*, release the RESET button and wait for a few seconds before releasing BUT. -**Step 4: Obtain stm32loader.py**. The -script ``stm32loader.py`` is provided with libmaple. If you have set -up the :ref:`Unix toolchain `, it is available in -libmaple/support/stm32loader.py. Otherwise, you can download it -directly from `github +**Step 4: Get stm32loader.py**. You can download it directly from +`libmaple's github page `_ -(click the link, then save the file somewhere on your system). +(click the link, then save the file somewhere on your system). If you +have set up the :ref:`Unix toolchain `, it's the file +libmaple/support/stm32loader.py. Flashing the new Bootloader ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -We'll use ``new-boot.bin``, ``ser-port``, and ``stm32loader.py`` to -respectively refer to the absolute paths to the bootloader binary -(from Step 1), the serial port device file or COMM port (from Steps 2 -and 3), and the stm32loader.py script. +We'll use ``maple_boot.bin`` as the path to the bootloader binary from +Step 1, and ``ser-port`` as the Maple's serial port device file or COM +port. + +* On **Linux**, ``ser-port`` will probably be something like + ``/dev/ttyUSB0``, although the exact number could be different (it + could be ``/dev/ttyUSB1``, ``/dev/ttyUSB2``, etc.). + +* On **OS X**, ``ser-port`` will probably look like + ``/dev/tty.usbserialXXXX``, where ``XXXX`` is some random string of + characters. + +* On **Windows**, ``ser-port`` will be something like ``COM1``, ``COM2``, etc. .. highlight:: sh -You can run :: +To upload a bootloader binary, run this command from the Unix shell:: + + python stm32loader.py -p ser-port -evw maple_boot.bin + +Or this command from the Windows command prompt:: + + python.exe stm32loader.py -p ser-port -evw maple_boot.bin - $ python stm32loader.py -h +You can also run the following to get usage information:: -to obtain usage information. The incantation for uploading a -bootloader binary ``new-bootloader.bin`` is :: + # Unix: + python stm32loader.py -h - $ python stm32loader.py -p ser-port -evw new-boot.bin + # Windows: + python.exe stm32loader.py -h If all goes well, you'll see a bunch of output, then "Verification OK". If something goes wrong, the `forum`_ is probably your best bet -for obtaining help, with IRC (irc.freenode.net, #leafblowers) being -another option. If all else fails, you can always `contact us -directly`_! +for obtaining help, with IRC (server irc.freenode.net, channel +#leafblowers) being another option. If all else fails, you can always +`contact us directly`_! diff --git a/docs/source/maple-ide-install.rst b/docs/source/maple-ide-install.rst index 92d1a96..f439abe 100644 --- a/docs/source/maple-ide-install.rst +++ b/docs/source/maple-ide-install.rst @@ -65,8 +65,8 @@ some drivers. Sorry! changes in Windows 7 mean that you won't be able to install the IDE without disabling driver signing on your computer. We're working on resolving this situation. For now, `users on the forum have - reported some workarounds - `_. + reported a workaround + `_. First, install DFU drivers (for uploading code to your Maple) using the following steps. -- cgit v1.2.3 From 79d1ee686324b92036792986c733f733345c38fb Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Fri, 8 Apr 2011 19:35:21 -0400 Subject: Coding standard updates. Added some content, converted document to .rst. --- notes/coding_standard.rst | 422 ++++++++++++++++++++++++++++++++++++++++++++++ notes/coding_standard.txt | 284 ------------------------------- 2 files changed, 422 insertions(+), 284 deletions(-) create mode 100644 notes/coding_standard.rst delete mode 100644 notes/coding_standard.txt diff --git a/notes/coding_standard.rst b/notes/coding_standard.rst new file mode 100644 index 0000000..1deed03 --- /dev/null +++ b/notes/coding_standard.rst @@ -0,0 +1,422 @@ +libmaple Coding Standards +========================= + +Author: Marti Bolivar (mbolivar@leaflabs.com) + +LeafLabs team members are required to follow these when producing new +code. Community contributors to libmaple are strongly encouraged to +do so; following these rules will greatly increase the probability +that your patches will be folded in. + +In general, do it like this unless there's a really good reason why +not. You being lazy doesn't count as a good reason. Most, if not +all, of these decisions are entirely arbitrary, but it's important for +readability that we be consistent. + +The file ``.dir-locals.el`` in the libmaple root directory already +ensures that many of these standards are followed by default in Emacs +(but not on Windows, where it would need to be named +``_dir_locals.el``, and no way, man). There's also some elisp +scattered about this file which will provide you additional help. + +Vim customizations to do the same thing would be nice (hint, hint)! + +License +------- + +- Put an MIT license at the beginning of the file (look at any of our + source files for an example). Copyright should go either to you or + to LeafLabs, LLC. + +.. highlight:: scheme + + Emacs: if you don't like seeing the license, you should use + elide-head (which will hide it for you). You can use the following:: + + (require 'elide-head) + (setq programming-mode-hooks '(c-mode-hook c++-mode-hook)) + (add-to-list 'elide-head-headers-to-hide + '("The MIT License" . "DEALINGS IN\n [*] THE SOFTWARE")) + (add-to-list 'elide-head-headers-to-hide + '("The MIT License" . "DEALINGS IN THE\n...SOFTWARE")) + (dolist (hook programming-mode-hooks) + (add-hook hook (lambda () (elide-head)))) + +Whitespace/Indentation +---------------------- + +- 4 space indents. [Set in ``.dir-locals.el``] + +- Unix newlines. [Some exceptions are currently grandfathered in; + these will go away in time.] + +- No tab characters. [Set in ``.dir-locals.el``] + +- No trailing whitespace. For help getting this (and no tab + characters) done automatically in Emacs, you can use this: + + http://github.com/mbolivar/code-fascism + + I hear tell you can get something similar in Vim; ask around, I + guess. + +- Files end in exactly one newline. [The presence of a newline at EOF + is already done by ``c-require-final-newline`` in recent versions of + Emacs.] + +- Exactly two newlines separate source paragraphs (you do separate + your code into paragraphs, don't you?). + +- The first line in a function is non-blank. + +.. highlight:: cpp + +- Exactly one space after ``if``, ``else``, ``for``, and ``while``, + before the following ``{`` or ``(``. One space before ``else``, + after the preceding ``}``. For example:: + + // This is good; we like this: + if (foo) { + while (quux) { + bar(); + } + } else { + baz(); + } + + // THIS IS BAD! DON'T DO THIS: + if(foo){ + while(quux){ + bar(); + } + }else{ + baz(); + } + +- Exactly one space in between binary arithmetic, logical, and + comparison operators and their operands, except for the . and -> + operators. Examples:: + + // This is good: + int x = a + b * (c - d); + if (x != 0 && a > 7) { + SerialUSB.println(x); + } + + // THIS IS BAD! + int x = a+b*(c-d); + if (x!=0 && a>7) { + SerialUSB.println(x); + } + + // This is good: + uint32 adc_data = ADC1_BASE->DR; + SerialUSB.println(adc_data); + + // THIS IS BAD! + uint32 adc_data = ADC1_BASE -> DR; + SerialUSB . println(adc_data); + +- No space between a unary operator and its operand. Examples:: + + // Good: + x++; + + // BAD! + x ++; + + // Good: + y = -x; + + // BAD! + y = - x; + +- If you need to break up a long line: + + * Prefer to break up long expressions after a binary operator. Example:: + + // Good: + if (some_really_long_conditional_wow_this_really_goes_on_forever || + maybe_something_else_could_happen_too) { + ... + } + + // BAD! + if (some_really_long_conditional_wow_this_really_goes_on_forever + || maybe_something_else_could_happen_too) { + ... + } + + * When breaking up a function's arguments over multiple lines, align + the arguments on subsequent lines with the first argument. + Example:: + + // Good: + return_type value_i_got = function_with_a_really_long_name(argument1, + argument2, + argument3); + + // BAD! + return_type value_i_got = function_with_a_really_long_name(argument1, + argument2, + argument3); + + // BAD! + return_type value_i_got = function_with_a_really_long_name(argument1, + argument2, + argument3); + +- In function invocations, no space in between the function name and + the opening parenthesis. Example:: + + // Good: + SerialUSB.println("Hello, world!"); + + // BAD! + SerialUSB.println ("Hello, world!"); + +- Don't indent C code within a conditionally-compiled ``extern "C"`` + block. Example:: + + // Good: + #ifdef __cplusplus + extern "C"{ + #endif + + void some_c_function(void); + + #ifdef __cplusplus + } // extern "C" + #endif + + // BAD! + #ifdef __cplusplus + extern "C"{ + #endif + + void some_c_function(void); + + #ifdef __cplusplus + } // extern "C" + #endif + +.. highlight:: scheme + + Emacs does the "bad" behavior by default, which can be very + annoying. You can turn this off with:: + + (defun c-mode-inextern-lang-hook () + (setcdr (assq 'inextern-lang c-offsets-alist) '-)) + (add-hook 'c-mode-hook c-mode-inextern-lang-hook) + +Comments +-------- + +.. highlight:: c++ + +- Multi-line comments are pretty flexible. Any of these is fine:: + + /* Comment starts here. + * Continued lines have a '*' before them. + * The comment can end after the last line. + */ + + /* Comment starts here. + * The comment can end on the same line. */ + + /* + * You can also place a newline after the opening "/*". + */ + +- Doxygen comments are multi-line comments that begin with ``/**`` + instead. + +- Single-line comments on the same line are ``//`` in C++. (That's OK + in C as well). + +- Single-line comments on their own source line should be ``/* */`` in + C, but can also be ``//`` in C++. (This isn't of great importance). + In Emacs, you can use M-; (comment-dwim), and it'll Do What You + Mean. + +Braces +------ + +- Mostly 1TBS: + + http://en.wikipedia.org/wiki/Indent_style#Variant:_1TBS + + The only difference is that the opening brace of a function's + definition occurs exactly one space character after the closing + parenthesis in that function's parameter list. Example:: + + void func(void) { + ... + } + +Naming conventions +------------------ + +There's always a fight about upper and lower case vs. underscores. +We'll handle this as follows. + +- First, ``Dont_Mix_Like_This``, because ``It_Looks_Really_Ugly``, ok? + [There's been some debate about this, and some exceptions are + already grandfathered in, so in order to settle it, let's call this + a "recommendation" instead of "requirement".] + +- Variables: Use underscores to separate words in C identifiers:: + + int some_example_name; + + User-facing C++ variables should be camel cased + (``thisIsAnExample``, ``boardPWMPins``, etc.), for consistency with + the Arduino style. It's probably a good idea for you to case + non-user facing C++ variables in the C style; this will help + disambiguate what's part of the Wirish API and what's not. + +- Classes: Pascal case. So ``ThisIsAClassName``, but ``thisIsNot``, + ``this_is_not``, and like I said, + ``Dont_You_DareTryANYTHING_STUPID``. + +- Functions: C functions are all lowercase, and words are separated by + underscores. C++ method names are camel cased. + +- Structs: Usually like variables (``adc_dev``, ``adc_reg_map``, + etc.), but it's not crucial. Don't feel obliged to put ``_t`` at + the end of the type name; we don't. + +- Macros and constants: all caps, separated by underscores. C++ + variables with the ``const`` qualifier generally aren't considered + "constants" for the purposes of this rule; i.e., they are cased + according to the rules for variables. We make an exception for + ``PIN_MAP``, because it's the central Wirish data structure. + +- foo.h gets ``#ifdef``\ 'ed to ``_FOO_H_``. + +- Acronyms: The case of letters in an acronym is determined by the + case of the first letter in the acronym, which is determined by + following the above rules. Examples:: + + // Good: + void usb_func() { ... } + void frob_usb_disc() { ... } + class SomethingUSB { + void usbInit(); + void initUSB(); + }; + + // BAD: + class BadUsb { ... }; // say "GoodUSB" instead + void swizzle_USB_disc() { ... } // say "swizzle_usb_disc" instead + +Documentation +------------- + +- You **must** document your code. At a bare minimum, this means + Doxygen comments on every user-facing function and type. + Additionally, you need to individually document the fields and + enumerator values of ``struct``\ s and ``enum``\ s. See any + register map type's definition for an example. + +- For libmaple proper, you don't need comments for each register bit + definition (for now). + +- Doxygen comments generally just belong on types, functions, + etc. that are part of the public user-facing API. This generally + means that if there's ReST documentation for it under docs/source/, + it needs Doxygen comments, and that ReST should use Breathe to pull + that Doxygen comment out. (For more info on this, see docs/README). + + There are some exceptions to this rule since Breathe isn't totally + mature yet and Sphinx's C++ domain is still in flux. In these + cases, document the code "manually" in ReST. + + This should be avoided if at all possible, since it creates a + maintenance burden of documenting things in two places at once, and + makes it easier for documentation to go stale. + + If you do have to document something manually, put a comment in the + source file informing future maintainers about it, so they'll pay + extra attention when making changes. + +- When adding peripheral support, it would be nice if you put + longer-form comments into the /notes/ directory, with a comment in + the corresponding .h file referring to it. See /libmaple/dac.h for + an example. + + This lets us keep the source files relatively free of "introductory" + material, while allowing new readers a convenient starting point. + These longer-form notes also have a habit of turning into + user-facing documentation. + +- For libmaple proper (the pure C library under libmaple/); the + convention is to document any user-facing function at the point where + it is defined. In particular, this means you should document an + externally-linked function defined in a .c file in that .c file, not + in the header file where it is declared to the user. + +General Formatting +------------------ + +- Keep it 80-column clean. That means Emacs says the largest column + number=79. You should turn on column number mode to help you out: + +.. highlight:: scheme + + (column-number-mode 1) + + You can get more help from lineker-mode: + + http://www.helsinki.fi/~sjpaavol/programs/lineker.el + + Just put lineker.el somewhere in your load-path, and: + + (require 'lineker) + (dolist (hook '(c-mode-hook c++-mode-hook)) + (add-hook hook (lambda () (lineker-mode 1)))) + +Language Features and Compiler Extensions +----------------------------------------- + +- In libmaple proper, aim for C99 compatibility. Some GCC extensions + are OK, but let's not go crazy. + +- If you'd like to get code into libmaple which uses a GCC extension + not already in use elsewhere, ask a LeafLabs developer (or another + one, if you are one) what they think about it first. + +- Explicitly approved GCC extensions: + + * asm volatile: + http://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html + + * Nested functions: + http://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html + +- In wirish, generally be very conservative when using C++ features + that aren't part of C. We are forced to use C++ for Arduino + compatibility (and the general Arduino style of pretending that an + object is a library), but it's an angry beast, and we don't want to + provoke it. The mantra is "C with classes". + +- Explicitly approved C++ features: + + * Initializers that aren't constant; e.g. the ``gpio_dev*`` values + in a ``PIN_MAP``. + + * Default arguments: e.g., the timeout argument defaulting to 0 + (meaning to wait forever) in ``waitForButtonPress()``. + +- Explicitly forbidden C++ features: + + * Templates + +- C++ features that are conditionally allowed, but require explicit + approval from at least two libmaple developers (one of which may be + yourself): + + * Operator overloading: Never allowed when it's just for style. + Potentially allowed when you're implementing a class that models a + mathematical structure, and you'd like to implement + e.g. ``operator+()``. diff --git a/notes/coding_standard.txt b/notes/coding_standard.txt deleted file mode 100644 index 5b258f7..0000000 --- a/notes/coding_standard.txt +++ /dev/null @@ -1,284 +0,0 @@ -libmaple Coding Standards -========================= - -Author: Marti Bolivar (mbolivar@leaflabs.com) - -LeafLabs team members are required to follow these when producing new -code. Community contributors to libmaple are strongly encouraged to -do so; following these rules will greatly increase the probability -that your patches will be folded in. - -In general, do it like this unless there's a really good reason why -not. You being lazy doesn't count as a good reason. Most, if not -all, of these decisions are entirely arbitrary, but it's important for -readability that we be consistent. - -The file .dir-locals.el in the libmaple root directory already ensures -that many of these standards are followed by default in Emacs (but not -on Windows, where it would need to be named _dir_locals.el, and no -way, man). There's also some elisp scattered about this file which -will provide you additional help. - -Vim customizations to do the same thing would be nice (hint, hint)! - -License -------- - -- Put an MIT license at the beginning of the file (look at any of our - source files for an example). Copyright should go either to you or - to LeafLabs, LLC. - - Emacs: if you don't like seeing the license, you should use - elide-head (which will hide it for you). You can use the following: - - (require 'elide-head) - (setq programming-mode-hooks '(c-mode-hook c++-mode-hook)) - (add-to-list 'elide-head-headers-to-hide - '("The MIT License" . "DEALINGS IN\n [*] THE SOFTWARE")) - (add-to-list 'elide-head-headers-to-hide - '("The MIT License" . "DEALINGS IN THE\n...SOFTWARE")) - (dolist (hook programming-mode-hooks) - (add-hook hook (lambda () (elide-head)))) - -Whitespace/Indentation ----------------------- - -- 4 space indents. [Set in .dir-locals.el] - -- Unix newlines. [Some exceptions are currently grandfathered in; - these will go away in time.] - -- No tab characters. [Set in .dir-locals.el] - -- No trailing whitespace. For help getting this (and no tab - characters) done automatically in Emacs, you can use this: - - http://github.com/mbolivar/code-fascism - - I hear tell you can get something similar in vim; ask around, I - guess. - -- Files end in exactly one newline. [The presence of a newline at EOF - is already done by `c-require-final-newline' in recent versions of - Emacs.] - -- Exactly two newlines separate source paragraphs (you do separate - your code into paragraphs, don't you?). - -- The first line in a function is non-blank. - -- Don't indent C code within a conditionally-compiled extern "C" - block. Emacs does this by default, which can be very annoying; you - can turn this behavior off with - - (defun c-mode-inextern-lang-hook () - (setcdr (assq 'inextern-lang c-offsets-alist) '-)) - - (add-hook 'c-mode-hook c-mode-inextern-lang-hook) - -Comments --------- - -- Multi-line comments are pretty flexible. Any of these is fine: - - /* Comment starts here. - * Continued lines have a '*' before them. - * The comment can end after the last line. - */ - - /* Comment starts here. - * The comment can end on the same line. */ - - /* - * You can also place a newline after the opening "/*". - */ - -- Doxygen comments are multi-line comments that begin with /** instead. - -- Single-line comments on the same line are // in C++. (That's OK in C - as well). - -- Single-line comments on their own source line should be /* */ in C, - but can also be // in C++. In Emacs, you can use M-; - (comment-dwim), and it'll Do What You Mean. This isn't of great - importance. - -Braces ------- - -- Mostly 1TBS: - - http://en.wikipedia.org/wiki/Indent_style#Variant:_1TBS - - The only difference is that the opening brace of a function's - definition occurs exactly one space character after the closing - parenthesis in that function's parameter list. Example: - - void func(void) { - ... - } - -Naming conventions ------------------- - -There's always a fight about upper and lower case vs. underscores. -We'll handle this as follows. - -- First, Dont_Mix_Like_This, because It_Looks_Really_Ugly, ok? - [There's been some debate about this, and some exceptions are - already grandfathered in, so in order to settle it, let's call this - a "recommendation" instead of "requirement".] - -- Variables: Use underscores to separate words in C identifiers: - - int some_example_name; - - User-facing C++ variables should be camel cased (thisIsAnExample, - boardPWMPins, etc.), for consistency with the Arduino style. It's - probably a good idea for you to case non-user facing C++ variables - in the C style; this will help disambiguate what's part of the - Wirish API and what's not. - -- Classes: Pascal case. So ThisIsAClassName, but thisIsNot, - this_is_not, and like I said, Dont_You_DareTryANYTHING_STUPID. - -- Functions: C functions are all lowercase, and words are separated by - underscores. C++ method names are camel cased. - -- Structs: Usually like variables (adc_dev, adc_reg_map, etc.), but - it's not crucial. Don't feel obliged to put "_t" at the end of the - type name; we don't. - -- Macros and constants: all caps, separated by underscores. C++ - variables with the "const" qualifier generally aren't considered - "constants" for the purposes of this rule; i.e., they are cased - according to the rules for variables. We make an exception for - PIN_MAP, because it's the central Wirish data structure. - -- foo.h gets #ifdef'ed to _FOO_H_. - -- Acronyms: The case of letters in an acronym is determined by the - case of the first letter in the acronym, which is determined by - following the above rules. Examples: - - void usb_func() { ... } - - void frob_usb_disc() { ... } - - class SomethingUSB { - void usbInit(); - void initUSB(); - }; - - DON'T do this: - - class BadUsb { ... }; // say "GoodUSB" instead - - void swizzle_USB_disc() { ... } // say "swizzle_usb_disc" instead - -Documentation -------------- - -- You must document your code. At a bare minimum, this means Doxygen - comments on every user-facing function and type. Additionally, you - need to individually document the fields and enumerator values of - structs and enums. See any register map type's definition for an - example. - -- For libmaple proper, you don't need comments for each register bit - definition (for now). - -- Doxygen comments generally just belong on types, functions, - etc. that are part of the public user-facing API. This generally - means that if there's ReST documentation for it under docs/source/, - it needs Doxygen comments, and that ReST should use Breathe to pull - that Doxygen comment out. (For more info on this, see docs/README). - - There are some exceptions to this rule since Breathe isn't totally - mature yet and Sphinx's C++ domain is still in flux. In these - cases, document the code "manually" in ReST. - - This should be avoided if at all possible, since it creates a - maintenance burden of documenting things in two places at once, and - makes it easier for documentation to go stale. - - If you do have to document something manually, put a comment in the - source file informing future maintainers about it, so they'll pay - extra attention when making changes. - -- For complicated peripherals, it would be nice if you put longer-form - comments into the libmaple notes/ directory, with a comment in the - corresponding .h file referring to it. See libmaple/dac.h for an - example. - - This lets us keep the source files relatively clean while still - allowing new readers to have a starting point. These longer-form - notes also have a habit of turning into user-facing documentation. - -- For libmaple proper (the pure C library under libmaple/); the - convention is to document any user-facing function at the point where - it is defined. In particular, this means you should document an - externally-linked function defined in a .c file in that .c file, not - in the header file where it is declared to the user. - -General Formatting ------------------- - -- Keep it 80-column clean. That means Emacs says the largest column - number=79. You should turn on column number mode to help you out: - - (column-number-mode 1) - - You can get more help from lineker-mode: - - http://www.helsinki.fi/~sjpaavol/programs/lineker.el - - Just put lineker.el somewhere in your load-path, and: - - (require 'lineker) - (dolist (hook '(c-mode-hook c++-mode-hook)) - (add-hook hook (lambda () (lineker-mode 1)))) - -Language Features and Compiler Extensions ------------------------------------------ - -- In libmaple proper, aim for C99 compatibility. Some GCC extensions - are OK, but let's not go crazy. - -- If you'd like to get code into libmaple which uses a GCC extension - not already in use elsewhere, ask a LeafLabs developer (or another - one, if you are one) what they think about it first. - -- Explicitly approved GCC extensions: - - * asm volatile: - http://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html - - * Nested functions: - http://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html - -- In wirish, generally be very conservative when using C++ features - that aren't part of C. We are forced to use C++ for Arduino - compatibility (and the general Arduino style of pretending that an - object is a library), but it's an angry beast, and we don't want to - provoke it. The mantra is "C with classes". - -- Explicitly approved C++ features: - - * Initializers that aren't constant; e.g. the gpio_dev* values in - PIN_MAPs. - - * Default arguments: e.g., the timeout argument defaulting to 0 - (meaning to wait forever) in waitForButtonPress(). - -- Explicitly forbidden C++ features: - - * Templates - -- C++ features that are conditionally allowed, but require explicit - approval from at least two libmaple developers (one of which may be - yourself): - - * Operator overloading: Never allowed when it's just for style. - Potentially allowed when you're implementing a class that models a - mathematical structure, and you'd like to implement e.g. operator+(). -- cgit v1.2.3 From be4f7904584da06a5971616034dd3839e433edf8 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Mon, 11 Apr 2011 12:05:37 -0400 Subject: Coding standard tweaks. It's mostly ready for inclusion in the main body of documentation. --- notes/coding_standard.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/notes/coding_standard.rst b/notes/coding_standard.rst index 1deed03..ced946d 100644 --- a/notes/coding_standard.rst +++ b/notes/coding_standard.rst @@ -21,6 +21,9 @@ scattered about this file which will provide you additional help. Vim customizations to do the same thing would be nice (hint, hint)! +.. contents:: Contents + :local: + License ------- @@ -94,8 +97,8 @@ Whitespace/Indentation } - Exactly one space in between binary arithmetic, logical, and - comparison operators and their operands, except for the . and -> - operators. Examples:: + comparison operators and their operands. This doesn't apply to the + . and -> operators. Examples:: // This is good: int x = a + b * (c - d); -- cgit v1.2.3 From 33f8df7aabe627f0343c5aa30c0147a8b567652c Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Mon, 11 Apr 2011 12:32:09 -0400 Subject: Adding button test to examples/test-session.cpp. --- examples/test-session.cpp | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/examples/test-session.cpp b/examples/test-session.cpp index 01d0fe9..03fb248 100644 --- a/examples/test-session.cpp +++ b/examples/test-session.cpp @@ -29,6 +29,7 @@ void cmd_sequential_adc_reads(void); void cmd_gpio_qa(void); void cmd_sequential_gpio_writes(void); void cmd_gpio_toggling(void); +void cmd_but_test(void); void cmd_sequential_pwm_test(void); void cmd_servo_sweep(void); void cmd_board_info(void); @@ -73,7 +74,7 @@ void setup() { void loop () { toggleLED(); - delay(100); + delay(250); while (SerialUSB.available()) { uint8 input = SerialUSB.read(); @@ -154,6 +155,10 @@ void loop () { cmd_gpio_toggling(); break; + case 'B': + cmd_but_test(); + break; + case 'f': SerialUSB.println("Wiggling D4 as fast as possible in bursts. " "Press any key."); @@ -261,6 +266,7 @@ void cmd_print_help(void) { SerialUSB.println("\tU: dump data as fast as possible on USB"); SerialUSB.println("\tg: toggle GPIOs sequentially"); SerialUSB.println("\tG: toggle GPIOs at the same time"); + SerialUSB.println("\tB: test the built-in button"); SerialUSB.println("\tf: toggle pin 4 as fast as possible in bursts"); SerialUSB.println("\tr: monitor and print GPIO status changes"); SerialUSB.println("\ts: output a sweeping servo PWM on all PWM channels"); @@ -577,6 +583,20 @@ void cmd_gpio_toggling(void) { } } +void cmd_but_test(void) { + SerialUSB.println("Press the button to test. Press any key to stop."); + pinMode(BOARD_BUTTON_PIN, INPUT); + + while (!SerialUSB.available()) { + if (isButtonPressed()) { + uint32 tstamp = millis(); + SerialUSB.print("Button press detected, timestamp: "); + SerialUSB.println(tstamp); + } + } + SerialUSB.read(); +} + void cmd_sequential_pwm_test(void) { SerialUSB.println("Sequentially testing PWM on all unused pins. " "Press any key for next pin, ESC to stop."); -- cgit v1.2.3 From 9ef9a63da80d79352d1029397865893a78e918fb Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Mon, 11 Apr 2011 15:52:48 -0400 Subject: USART bugfix. USART refactor commit f6f9a1122706ed336c52c984d76219dee0594487 only worked for USART1. --- libmaple/usart.c | 2 +- wirish/comm/HardwareSerial.cpp | 19 ++++++++++--------- wirish/comm/HardwareSerial.h | 4 +++- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/libmaple/usart.c b/libmaple/usart.c index de808a7..7fe4f53 100644 --- a/libmaple/usart.c +++ b/libmaple/usart.c @@ -99,7 +99,7 @@ void usart_init(usart_dev *dev) { * @brief Configure a serial port's baud rate. * * @param dev Serial port to be configured - * @param clock_speed MCU clock speed, in megahertz. + * @param clock_speed Clock speed, in megahertz. * @param baud Baud rate for transmit/receive. */ void usart_set_baud_rate(usart_dev *dev, uint32 clock_speed, uint32 baud) { diff --git a/wirish/comm/HardwareSerial.cpp b/wirish/comm/HardwareSerial.cpp index aa8855b..5c9bff6 100644 --- a/wirish/comm/HardwareSerial.cpp +++ b/wirish/comm/HardwareSerial.cpp @@ -46,18 +46,21 @@ #define RX5 BOARD_UART5_RX_PIN #endif -HardwareSerial Serial1(USART1, TX1, RX1); -HardwareSerial Serial2(USART2, TX2, RX2); -HardwareSerial Serial3(USART3, TX3, RX3); +// TODO Put these magic numbers into boards.h #defines +HardwareSerial Serial1(USART1, TX1, RX1, 72000000UL); +HardwareSerial Serial2(USART2, TX2, RX2, 36000000UL); +HardwareSerial Serial3(USART3, TX3, RX3, 36000000UL); #if defined(STM32_HIGH_DENSITY) && !defined(BOARD_maple_RET6) -HardwareSerial Serial4(UART4, TX4, RX4); -HardwareSerial Serial5(UART5, TX5, RX5); +HardwareSerial Serial4(UART4, TX4, RX4, 36000000UL); +HardwareSerial Serial5(UART5, TX5, RX5, 36000000UL); #endif HardwareSerial::HardwareSerial(usart_dev *usart_device, uint8 tx_pin, - uint8 rx_pin) { + uint8 rx_pin, + uint32 clock_speed) { this->usart_device = usart_device; + this->clock_speed = clock_speed; this->tx_pin = tx_pin; this->rx_pin = rx_pin; } @@ -93,9 +96,7 @@ void HardwareSerial::begin(uint32 baud) { } usart_init(usart_device); - usart_set_baud_rate(usart_device, - CYCLES_PER_MICROSECOND * 1000000UL, - baud); + usart_set_baud_rate(usart_device, clock_speed, baud); usart_enable(usart_device); } diff --git a/wirish/comm/HardwareSerial.h b/wirish/comm/HardwareSerial.h index 5e86f79..934db23 100644 --- a/wirish/comm/HardwareSerial.h +++ b/wirish/comm/HardwareSerial.h @@ -50,7 +50,8 @@ class HardwareSerial : public Print { public: HardwareSerial(usart_dev *usart_device, uint8 tx_pin, - uint8 rx_pin); + uint8 rx_pin, + uint32 clock_speed); void begin(uint32 baud); void end(void); uint32 available(void); @@ -62,6 +63,7 @@ private: usart_dev *usart_device; uint8 tx_pin; uint8 rx_pin; + uint32 clock_speed; }; extern HardwareSerial Serial1; -- cgit v1.2.3 From 57b59731b712e8edb89e65de6f7b02555d0832d9 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Mon, 11 Apr 2011 19:00:32 -0400 Subject: Adding delay_us() TODO. --- libmaple/delay.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libmaple/delay.h b/libmaple/delay.h index e4d85c5..5372ac1 100644 --- a/libmaple/delay.h +++ b/libmaple/delay.h @@ -6,6 +6,8 @@ #define _DELAY_H_ static inline void delay_us(uint32 us) { + /* TODO this makes unwarranted assumptions about the RCC + * config; add a hook so users can make their own decisions. */ /* So (2^32)/12 micros max, or less than 6 minutes */ us *= 12; -- cgit v1.2.3 From 4a56b462cfa7c54c623374f966b853a7b0790613 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Mon, 11 Apr 2011 20:45:35 -0400 Subject: Resolving some FIXMEs. --- examples/test-session.cpp | 10 ++++++++-- examples/vga-scope.cpp | 7 ++++++- libmaple/usb/usb.c | 24 ++---------------------- libmaple/usb/usb_config.h | 2 +- 4 files changed, 17 insertions(+), 26 deletions(-) diff --git a/examples/test-session.cpp b/examples/test-session.cpp index 03fb248..01dd184 100644 --- a/examples/test-session.cpp +++ b/examples/test-session.cpp @@ -780,17 +780,23 @@ void init_all_timers(uint16 prescale) { } void enable_usarts(void) { - // FIXME generalize after USART refactor Serial1.begin(BAUD); Serial2.begin(BAUD); Serial3.begin(BAUD); +#ifdef STM32_HIGH_DENSITY + Serial4.begin(BAUD); + Serial5.begin(BAUD); +#endif } void disable_usarts(void) { - // FIXME generalize after USART refactor Serial1.end(); Serial2.end(); Serial3.end(); +#ifdef STM32_HIGH_DENSITY + Serial4.end(); + Serial5.end(); +#endif } void print_board_array(const char* msg, const uint8 arr[], int len) { diff --git a/examples/vga-scope.cpp b/examples/vga-scope.cpp index 9c6dca5..66e72e9 100644 --- a/examples/vga-scope.cpp +++ b/examples/vga-scope.cpp @@ -28,12 +28,17 @@ - http://www.epanorama.net/documents/pc/vga_timing.html This code is released into the public domain. + + Authors: + + Bryan Newbold + Marti Bolivar */ #include "wirish.h" #include "systick.h" -// FIXME generalize for Native and Mini +// FIXME: generalize for Native and Mini #define LED_PIN BOARD_LED_PIN #define ANALOG_PIN 18 diff --git a/libmaple/usb/usb.c b/libmaple/usb/usb.c index 2fc4eb2..7b1dd4c 100644 --- a/libmaple/usb/usb.c +++ b/libmaple/usb/usb.c @@ -35,6 +35,7 @@ #include "usb_lib.h" #include "gpio.h" #include "usb_hardware.h" +#include "delay.h" #include "usb_config.h" #include "usb_callbacks.h" @@ -318,29 +319,8 @@ if (wIstr & ISTR_CTR & wInterrupt_Mask) { } -static void FIXME_delayMicroseconds_copy(uint32 us) { - /* So (2^32)/12 micros max, or less than 6 minutes */ - us *= 12; - - /* fudge for function call overhead */ - us--; - asm volatile(" mov r0, %[us] \n\t" - "1: subs r0, #1 \n\t" - " bhi 1b \n\t" - : - : [us] "r" (us) - : "r0"); -} - -static void FIXME_delay_copy(unsigned long ms) { - uint32 i; - for (i = 0; i < ms; i++) { - FIXME_delayMicroseconds_copy(1000); - } -} - void usbWaitReset(void) { - FIXME_delay_copy(RESET_DELAY); + delay_us(RESET_DELAY); systemHardReset(); } diff --git a/libmaple/usb/usb_config.h b/libmaple/usb/usb_config.h index 0860b90..23b49ee 100644 --- a/libmaple/usb/usb_config.h +++ b/libmaple/usb/usb_config.h @@ -25,7 +25,7 @@ *****************************************************************************/ #define VCOM_ID_VENDOR 0x1EAF -#define RESET_DELAY (100) +#define RESET_DELAY (100000) #define USB_CONFIG_MAX_POWER (100 >> 1) #if defined(BOARD_maple) || defined(BOARD_maple_RET6) -- cgit v1.2.3 From d74098913a9ff210b3f53e6881a38c864892c6af Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Thu, 7 Apr 2011 22:23:01 -0400 Subject: DMA checkpoint; dma_attach_interrupt() is broken. Simple USART receiver to SRAM buffer demo partially working. Interrupting when buffer is full fails mysteriously. GDB thinks we ended up in an STM32 reserved exception. --- examples/test-usart-dma.cpp | 127 +++++++++++++ libmaple/dma.c | 397 ++++++++++++++++++++++++++++++--------- libmaple/dma.h | 445 ++++++++++++++++++++++++++++++++++++++------ libmaple/nvic.h | 1 + notes/dma.txt | 99 ++++++++++ 5 files changed, 921 insertions(+), 148 deletions(-) create mode 100644 examples/test-usart-dma.cpp create mode 100644 notes/dma.txt diff --git a/examples/test-usart-dma.cpp b/examples/test-usart-dma.cpp new file mode 100644 index 0000000..b9c03f1 --- /dev/null +++ b/examples/test-usart-dma.cpp @@ -0,0 +1,127 @@ +/** + * @file test-usart-dma.cpp + * @author Marti Bolivar + * + * Simple test of DMA used with a USART receiver. + * + * Configures a USART receiver for use with DMA. Received bytes are + * placed into a buffer, with an interrupt firing when the buffer is + * full. At that point, the USART transmitter will print the contents + * of the byte buffer. The buffer is continually filled and refilled + * in this manner. + * + * This example isn't very robust; don't use it in production. In + * particular, since the buffer keeps filling (DMA_CIRC_MODE is set), + * if you keep typing after filling the buffer, you'll overwrite + * earlier bytes; this may happen before those earlier bytes are done + * printing. + * + * This code is released into the public domain. + */ + +#include "dma.h" +#include "usart.h" +#include "gpio.h" + +#include "wirish.h" + +#define BAUD 9600 + +#define USART USART2 +#define USART_HWSER Serial2 +#define USART_DMA_DEV DMA1 +#define USART_RX_DMA_CHANNEL DMA_CH6 +#define USART_TX BOARD_USART2_TX_PIN +#define USART_RX BOARD_USART2_RX_PIN + +#define BUF_SIZE 8 +uint8 rx_buf[BUF_SIZE]; + +dma_irq_cause irq_cause; + +__io uint32 irq_fired = 0; + +void init_usart(void); +void init_dma_xfer(void); +void rx_dma_irq(void); + +void setup(void) { + pinMode(BOARD_LED_PIN, OUTPUT); + + init_dma_xfer(); + init_usart(); +} + +void loop(void) { + toggleLED(); + delay(100); + + dma_channel_reg_map *ch_regs = dma_channel_regs(USART_DMA_DEV, + USART_RX_DMA_CHANNEL); + if (irq_fired) { + USART_HWSER.println("** IRQ **"); + while (true) + ; + } + USART_HWSER.print("["); + USART_HWSER.print(millis()); + USART_HWSER.print("]\tISR bits: 0x"); + uint8 isr_bits = dma_get_isr_bits(USART_DMA_DEV, USART_RX_DMA_CHANNEL); + USART_HWSER.print((int32)isr_bits, HEX); + USART_HWSER.print("\tCCR: 0x"); + USART_HWSER.print((int64)ch_regs->CCR, HEX); + USART_HWSER.print("\tCNDTR: 0x"); + USART_HWSER.print((int64)ch_regs->CNDTR, HEX); + USART_HWSER.print("\tBuffer contents: "); + for (int i = 0; i < BUF_SIZE; i++) { + USART_HWSER.print('\''); + USART_HWSER.print(rx_buf[i]); + USART_HWSER.print('\''); + if (i < BUF_SIZE - 1) USART_HWSER.print(", "); + } + USART_HWSER.println(); + if (isr_bits == 0x7) { + USART_HWSER.println("** Clearing ISR bits."); + dma_clear_isr_bits(USART_DMA_DEV, USART_RX_DMA_CHANNEL); + } + + irq_fired = 0; +} + +/* Configure USART receiver for use with DMA */ +void init_usart(void) { + USART_HWSER.begin(BAUD); + USART->regs->CR3 = USART_CR3_DMAR; +} + +/* Configure DMA transmission */ +void init_dma_xfer(void) { + dma_init(USART_DMA_DEV); + dma_setup_transfer(USART_DMA_DEV, USART_RX_DMA_CHANNEL, + &USART->regs->DR, DMA_SIZE_8BITS, + rx_buf, DMA_SIZE_8BITS, + (DMA_MINC_MODE | DMA_CIRC_MODE | DMA_TRNS_CMPLT + )); + dma_set_num_transfers(USART_DMA_DEV, USART_RX_DMA_CHANNEL, BUF_SIZE); + // Currently not working: + // dma_attach_interrupt(USART_DMA_DEV, USART_RX_DMA_CHANNEL, rx_dma_irq); + dma_enable(USART_DMA_DEV, USART_RX_DMA_CHANNEL); +} + +void rx_dma_irq(void) { +} + +// Force init to be called *first*, i.e. before static object allocation. +// Otherwise, statically allocated objects that need libmaple may fail. +__attribute__((constructor)) void premain() { + init(); +} + +int main(void) { + setup(); + + while (true) { + loop(); + } + return 0; +} diff --git a/libmaple/dma.c b/libmaple/dma.c index c71e52c..6ddabcc 100644 --- a/libmaple/dma.c +++ b/libmaple/dma.c @@ -23,126 +23,351 @@ *****************************************************************************/ /** - * @file dma.c - * - * @brief Direct Memory Access peripheral support + * @file dma.c + * @author Marti Bolivar ; + * Original implementation by Michael Hope + * @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 } +#include "bitband.h" +#include "util.h" + +/* + * Devices + */ + +static dma_dev dma1 = { + .regs = DMA1_BASE, + .clk_id = RCC_DMA1, + .handlers = {{ .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 }} +}; +dma_dev *DMA1 = &dma1; + +#ifdef STM32_HIGH_DENSITY +static dma_dev dma2 = { + .regs = DMA2_BASE, + .clk_id = RCC_DMA2, + .handlers = {{ .handler = NULL, .irq_line = NVIC_DMA2_CH1 }, + { .handler = NULL, .irq_line = NVIC_DMA2_CH2 }, + { .handler = NULL, .irq_line = NVIC_DMA2_CH3 }, + { .handler = NULL, .irq_line = NVIC_DMA2_CH_4_5 }, + { .handler = NULL, .irq_line = NVIC_DMA2_CH_4_5 }} /* !@#$ */ }; +dma_dev *DMA2 = &dma2; +#endif -/** Get the base address of the given channel, asserting and returning - * NULL on illegal +/* + * Convenience routines */ -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; - } + +/** + * @brief Initialize a DMA device. + * @param dev Device to initialize. + */ +void dma_init(dma_dev *dev) { + rcc_clk_enable(dev->clk_id); } -/* 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)(); - } +/** + * @brief Set up a DMA transfer. + * + * The channel will be disabled before being reconfigured. The + * transfer will have low priority by default. You may choose another + * priority before the transfer begins using dma_set_priority(), as + * well as performing any other configuration you desire. When the + * channel is configured to your liking, enable it using dma_enable(). + * + * @param dev DMA device. + * @param channel DMA channel. + * @param peripheral_address Base address of peripheral data register + * involved in the transfer. + * @param peripheral_size Peripheral data transfer size. + * @param memory_address Base memory address involved in the transfer. + * @param memory_size Memory data transfer size. + * @param mode Logical OR of dma_mode_flags + * @sideeffect Disables the given DMA channel. + * @see dma_xfer_size + * @see dma_mode_flags + * @see dma_set_num_transfers() + * @see dma_set_priority() + * @see dma_attach_interrupt() + * @see dma_enable() + */ +void dma_setup_transfer(dma_dev *dev, + dma_channel channel, + __io void *peripheral_address, + dma_xfer_size peripheral_size, + __io void *memory_address, + dma_xfer_size memory_size, + uint32 mode) { + dma_channel_reg_map *channel_regs = dma_channel_regs(dev, channel); + + dma_disable(dev, channel); /* can't write to CMAR/CPAR otherwise */ + channel_regs->CCR = (memory_size << 10) | (peripheral_size << 8) | mode; + channel_regs->CMAR = (uint32)memory_address; + channel_regs->CPAR = (uint32)peripheral_address; +} + +/** + * @brief Set the number of data to be transferred on a DMA channel. + * + * You may not call this function while the channel is enabled. + * + * @param dev DMA device + * @param channel Channel through which the transfer occurs. + * @param num_transfers + */ +void dma_set_num_transfers(dma_dev *dev, + dma_channel channel, + uint16 num_transfers) { + dma_channel_reg_map *channel_regs; + + ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); + + channel_regs = dma_channel_regs(dev, channel); + channel_regs->CNDTR = num_transfers; } -void __irq_dma1_channel1(void) { - dispatch_handler(0); +/** + * @brief Set the priority of a DMA transfer. + * + * You may not call this function while the channel is enabled. + * + * @param dev DMA device + * @param channel DMA channel + * @param priority priority to set. + */ +void dma_set_priority(dma_dev *dev, + dma_channel channel, + dma_priority priority) { + dma_channel_reg_map *channel_regs; + uint32 ccr; + + ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); + + channel_regs = dma_channel_regs(dev, channel); + ccr = channel_regs->CCR; + ccr &= ~DMA_CCR_PL; + ccr |= priority; + channel_regs->CCR = ccr; } -void __irq_dma1_channel2(void) { - dispatch_handler(1); +/** + * @brief Attach an interrupt to a DMA transfer. + * + * Interrupts are enabled using appropriate mode flags in + * dma_setup_transfer(). + * + * @param dev DMA device + * @param channel Channel to attach handler to + * @param handler Interrupt handler to call when channel interrupt fires. + * @see dma_setup_transfer() + * @see dma_get_irq_cause() + * @see dma_detach_interrupt() + */ +void dma_attach_interrupt(dma_dev *dev, + dma_channel channel, + void (*handler)(void)) { + dev->handlers[channel - 1].handler = handler; + nvic_irq_enable(dev->handlers[channel - 1].irq_line); } -void __irq_dma2_channel3(void) { - dispatch_handler(2); +/** + * @brief Detach a DMA transfer interrupt handler. + * + * After calling this function, the given channel's interrupts will be + * disabled. + * + * @param dev DMA device + * @param channel Channel whose handler to detach + * @sideffect Clears interrupt enable bits in the channel's CCR register. + * @see dma_attach_interrupt() + */ +void dma_detach_interrupt(dma_dev *dev, dma_channel channel) { + /* Don't use nvic_irq_disable()! Think about DMA2 channels 4 and 5. */ + dma_channel_regs(dev, channel)->CCR &= ~0xF; + dev->handlers[channel - 1].handler = NULL; } -void __irq_dma2_channel4(void) { - dispatch_handler(3); +/** + * @brief Discover the reason why a DMA interrupt was called. + * + * You may only call this function within an attached interrupt + * handler for the given channel. + * + * This function resets the internal DMA register state which encodes + * the cause of the interrupt; consequently, it can only be called + * once per interrupt handler invocation. + * + * @brief dev DMA device + * @brief channel Channel whose interrupt is being handled. + * @return Reason why the interrupt fired. + * @sideeffect Clears channel status flags in dev->regs->ISR. + * @see dma_attach_interrupt() + * @see dma_irq_cause + */ +dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_channel channel) { + uint8 status_bits = dma_get_isr_bits(dev, channel); + + /* If the channel global interrupt flag is cleared, then + * something's very wrong. */ + ASSERT(status_bits & BIT(0)); + + dma_clear_isr_bits(dev, channel); + + /* ISR flags get set even if the corresponding interrupt enable + * bits in the channel's configuration register are cleared, so we + * can't use a switch here. + * + * Don't change the order of these if statements. */ + if (status_bits & BIT(3)) { + return DMA_TRANSFER_ERROR; + } else if (status_bits & BIT(1)) { + return DMA_TRANSFER_COMPLETE; + } else if (status_bits & BIT(2)) { + return DMA_TRANSFER_HALF_COMPLETE; + } else if (status_bits & BIT(0)) { + /* Shouldn't happen (unless someone messed up an IFCR write). */ + throb(); + } +#if DEBUG_LEVEL < DEBUG_ALL + else { + /* We shouldn't have been called, but the debug level is too + * low for the above ASSERT() to have had any effect. In + * order to fail fast, mimic the DMA controller's behavior + * when an error occurs. */ + dma_disable(dev, channel); + return DMA_TRANSFER_ERROR; + } +#endif } -void __irq_dma2_channel5(void) { - dispatch_handler(4); +/** + * @brief Enable a DMA channel. + * @param dev DMA device + * @param channel Channel to enable + */ +void dma_enable(dma_dev *dev, dma_channel channel) { + dma_channel_reg_map *chan_regs = dma_channel_regs(dev, channel); + bb_peri_set_bit(&chan_regs->CCR, DMA_CCR_EN_BIT, 1); } -void __irq_dma2_channel6(void) { - dispatch_handler(5); +/** + * @brief Disable a DMA channel. + * @param dev DMA device + * @param channel Channel to disable + */ +void dma_disable(dma_dev *dev, dma_channel channel) { + dma_channel_reg_map *chan_regs = dma_channel_regs(dev, channel); + bb_peri_set_bit(&chan_regs->CCR, DMA_CCR_EN_BIT, 0); } -void __irq_dma2_channel7(void) { - dispatch_handler(6); +/** + * @brief Set the base memory address where data will be read from or + * written to. + * + * You must not call this function while the channel is enabled. + * + * If the DMA memory size is 16 bits, the address is automatically + * aligned to a half-word. If the DMA memory size is 32 bits, the + * address is aligned to a word. + * + * @param dev DMA Device + * @param channel Channel whose base memory address to set. + */ +void dma_set_mem_addr(dma_dev *dev, dma_channel channel, __io void *addr) { + dma_channel_reg_map *chan_regs; + + ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); + + chan_regs = dma_channel_regs(dev, channel); + chan_regs->CMAR = (uint32)addr; } -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); +/** + * @brief Set the base peripheral address where data will be read from + * or written to. + * + * You must not call this function while the channel is enabled. + * + * If the DMA peripheral size is 16 bits, the address is automatically + * aligned to a half-word. If the DMA peripheral size is 32 bits, the + * address is aligned to a word. + * + * @param dev DMA Device + * @param channel Channel whose peripheral data register base address to set. + */ +void dma_set_per_addr(dma_dev *dev, dma_channel channel, __io void *addr) { + dma_channel_reg_map *chan_regs; + + ASSERT_FAULT(!dma_is_channel_enabled(dev, channel)); - if (regs != NULL) { - rcc_clk_enable(RCC_DMA1); + chan_regs = dma_channel_regs(dev, channel); + chan_regs->CPAR = (uint32)addr; +} - regs->CCR = ((0 << 12) /* Low priority */ - | (msize << 10) - | (psize << 8) - | (0 << 0) /* Disabled (until started) */ - | mode); +/* + * IRQ handlers + */ - regs->CPAR = (uint32)paddr; +static inline void dispatch_handler(dma_dev *dev, dma_channel channel) { + void (*handler)(void) = dev->handlers[channel - 1].handler; + if (handler) { + handler(); + dma_clear_isr_bits(dev, channel); /* in case handler doesn't */ } } -void dma_start(uint8 channel, volatile void *buffer, uint16 count) { - volatile dma_regs *regs = dma_get_regs(channel); +void __irq_dma_channel1(void) { + dispatch_handler(DMA1, DMA_CH1); +} - if (regs != NULL) { - regs->CCR &= ~DMA_EN; /* CMAR may not be written with EN set */ - regs->CMAR = (uint32)buffer; - regs->CNDTR = count; +void __irq_dma_channel2(void) { + dispatch_handler(DMA1, DMA_CH2); +} - regs->CCR |= DMA_EN; - } +void __irq_dma_channel3(void) { + dispatch_handler(DMA1, DMA_CH3); } -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 __irq_dma_channel4(void) { + dispatch_handler(DMA1, DMA_CH4); +} + +void __irq_dma_channel5(void) { + dispatch_handler(DMA1, DMA_CH5); +} + +void __irq_dma_channel6(void) { + dispatch_handler(DMA1, DMA_CH6); +} + +void __irq_dma_channel7(void) { + dispatch_handler(DMA1, DMA_CH7); +} + +#ifdef STM32_HIGH_DENSITY +void __irq_dma2_channel1(void) { + dispatch_handler(DMA2, DMA_CH1); +} + +void __irq_dma2_channel2(void) { + dispatch_handler(DMA2, DMA_CH2); +} + +void __irq_dma2_channel3(void) { + dispatch_handler(DMA2, DMA_CH3); } -void dma_detach_interrupt(uint8 channel) { - channel--; - nvic_irq_disable(dma_channels[channel].irq_line); - dma_channels[channel].handler = NULL; +void __irq_dma2_channel4_5(void) { + dispatch_handler(DMA2, DMA_CH4); + dispatch_handler(DMA2, DMA_CH5); } +#endif diff --git a/libmaple/dma.h b/libmaple/dma.h index 3417f02..c763672 100644 --- a/libmaple/dma.h +++ b/libmaple/dma.h @@ -23,97 +23,418 @@ *****************************************************************************/ /** - * @file dma.h + * @file dma.h * - * @brief Direct Memory Access peripheral support + * @author Marti Bolivar ; + * Original implementation by Michael Hope * - * TODO: add DMA2 support for high-density devices. + * @brief Direct Memory Access peripheral support + */ + +/* + * See /notes/dma.txt for more information. */ #ifndef _DMA_H_ #define _DMA_H_ #include "libmaple_types.h" +#include "rcc.h" +#include "nvic.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 +/* + * Register maps + */ + +/** + * @brief DMA register map type. + * + * Note that DMA controller 2 (register map base pointer DMA2_BASE) + * only supports channels 1--5. + */ +typedef struct dma_reg_map { + __io uint32 ISR; /**< Interrupt status register */ + __io uint32 IFCR; /**< Interrupt flag clear register */ + __io uint32 CCR1; /**< Channel 1 configuration register */ + __io uint32 CNDTR1; /**< Channel 1 number of data register */ + __io uint32 CPAR1; /**< Channel 1 peripheral address register */ + __io uint32 CMAR1; /**< Channel 1 memory address register */ + const uint32 RESERVED1; /**< Reserved. */ + __io uint32 CCR2; /**< Channel 2 configuration register */ + __io uint32 CNDTR2; /**< Channel 2 number of data register */ + __io uint32 CPAR2; /**< Channel 2 peripheral address register */ + __io uint32 CMAR2; /**< Channel 2 memory address register */ + const uint32 RESERVED2; /**< Reserved. */ + __io uint32 CCR3; /**< Channel 3 configuration register */ + __io uint32 CNDTR3; /**< Channel 3 number of data register */ + __io uint32 CPAR3; /**< Channel 3 peripheral address register */ + __io uint32 CMAR3; /**< Channel 3 memory address register */ + const uint32 RESERVED3; /**< Reserved. */ + __io uint32 CCR4; /**< Channel 4 configuration register */ + __io uint32 CNDTR4; /**< Channel 4 number of data register */ + __io uint32 CPAR4; /**< Channel 4 peripheral address register */ + __io uint32 CMAR4; /**< Channel 4 memory address register */ + const uint32 RESERVED4; /**< Reserved. */ + __io uint32 CCR5; /**< Channel 5 configuration register */ + __io uint32 CNDTR5; /**< Channel 5 number of data register */ + __io uint32 CPAR5; /**< Channel 5 peripheral address register */ + __io uint32 CMAR5; /**< Channel 5 memory address register */ + const uint32 RESERVED5; /**< Reserved. */ + __io uint32 CCR6; /**< Channel 6 configuration register */ + __io uint32 CNDTR6; /**< Channel 6 number of data register */ + __io uint32 CPAR6; /**< Channel 6 peripheral address register */ + __io uint32 CMAR6; /**< Channel 6 memory address register */ + const uint32 RESERVED6; /**< Reserved. */ + __io uint32 CCR7; /**< Channel 7 configuration register */ + __io uint32 CNDTR7; /**< Channel 7 number of data register */ + __io uint32 CPAR7; /**< Channel 7 peripheral address register */ + __io uint32 CMAR7; /**< Channel 7 memory address register */ + const uint32 RESERVED7; /**< Reserved. */ +} dma_reg_map; + +/** DMA controller 1 register map base pointer */ +#define DMA1_BASE ((struct dma_reg_map*)0x40020000) + +#ifdef STM32_HIGH_DENSITY +/** DMA controller 2 register map base pointer */ +#define DMA2_BASE ((struct dma_reg_map*)0x40020400) +#endif + +/* + * Register bit definitions + */ + +/* Interrupt status register */ + +#define DMA_ISR_TEIF7_BIT 27 +#define DMA_ISR_HTIF7_BIT 26 +#define DMA_ISR_TCIF7_BIT 25 +#define DMA_ISR_GIF7_BIT 24 +#define DMA_ISR_TEIF6_BIT 23 +#define DMA_ISR_HTIF6_BIT 22 +#define DMA_ISR_TCIF6_BIT 21 +#define DMA_ISR_GIF6_BIT 20 +#define DMA_ISR_TEIF5_BIT 19 +#define DMA_ISR_HTIF5_BIT 18 +#define DMA_ISR_TCIF5_BIT 17 +#define DMA_ISR_GIF5_BIT 16 +#define DMA_ISR_TEIF4_BIT 15 +#define DMA_ISR_HTIF4_BIT 14 +#define DMA_ISR_TCIF4_BIT 13 +#define DMA_ISR_GIF4_BIT 12 +#define DMA_ISR_TEIF3_BIT 11 +#define DMA_ISR_HTIF3_BIT 10 +#define DMA_ISR_TCIF3_BIT 9 +#define DMA_ISR_GIF3_BIT 8 +#define DMA_ISR_TEIF2_BIT 7 +#define DMA_ISR_HTIF2_BIT 6 +#define DMA_ISR_TCIF2_BIT 5 +#define DMA_ISR_GIF2_BIT 4 +#define DMA_ISR_TEIF1_BIT 3 +#define DMA_ISR_HTIF1_BIT 2 +#define DMA_ISR_TCIF1_BIT 1 +#define DMA_ISR_GIF1_BIT 0 + +#define DMA_ISR_TEIF7 BIT(DMA_ISR_TEIF7_BIT) +#define DMA_ISR_HTIF7 BIT(DMA_ISR_HTIF7_BIT) +#define DMA_ISR_TCIF7 BIT(DMA_ISR_TCIF7_BIT) +#define DMA_ISR_GIF7 BIT(DMA_ISR_GIF7_BIT) +#define DMA_ISR_TEIF6 BIT(DMA_ISR_TEIF6_BIT) +#define DMA_ISR_HTIF6 BIT(DMA_ISR_HTIF6_BIT) +#define DMA_ISR_TCIF6 BIT(DMA_ISR_TCIF6_BIT) +#define DMA_ISR_GIF6 BIT(DMA_ISR_GIF6_BIT) +#define DMA_ISR_TEIF5 BIT(DMA_ISR_TEIF5_BIT) +#define DMA_ISR_HTIF5 BIT(DMA_ISR_HTIF5_BIT) +#define DMA_ISR_TCIF5 BIT(DMA_ISR_TCIF5_BIT) +#define DMA_ISR_GIF5 BIT(DMA_ISR_GIF5_BIT) +#define DMA_ISR_TEIF4 BIT(DMA_ISR_TEIF4_BIT) +#define DMA_ISR_HTIF4 BIT(DMA_ISR_HTIF4_BIT) +#define DMA_ISR_TCIF4 BIT(DMA_ISR_TCIF4_BIT) +#define DMA_ISR_GIF4 BIT(DMA_ISR_GIF4_BIT) +#define DMA_ISR_TEIF3 BIT(DMA_ISR_TEIF3_BIT) +#define DMA_ISR_HTIF3 BIT(DMA_ISR_HTIF3_BIT) +#define DMA_ISR_TCIF3 BIT(DMA_ISR_TCIF3_BIT) +#define DMA_ISR_GIF3 BIT(DMA_ISR_GIF3_BIT) +#define DMA_ISR_TEIF2 BIT(DMA_ISR_TEIF2_BIT) +#define DMA_ISR_HTIF2 BIT(DMA_ISR_HTIF2_BIT) +#define DMA_ISR_TCIF2 BIT(DMA_ISR_TCIF2_BIT) +#define DMA_ISR_GIF2 BIT(DMA_ISR_GIF2_BIT) +#define DMA_ISR_TEIF1 BIT(DMA_ISR_TEIF1_BIT) +#define DMA_ISR_HTIF1 BIT(DMA_ISR_HTIF1_BIT) +#define DMA_ISR_TCIF1 BIT(DMA_ISR_TCIF1_BIT) +#define DMA_ISR_GIF1 BIT(DMA_ISR_GIF1_BIT) + +/* Interrupt flag clear register */ + +#define DMA_IFCR_CTEIF7_BIT 27 +#define DMA_IFCR_CHTIF7_BIT 26 +#define DMA_IFCR_CTCIF7_BIT 25 +#define DMA_IFCR_CGIF7_BIT 24 +#define DMA_IFCR_CTEIF6_BIT 23 +#define DMA_IFCR_CHTIF6_BIT 22 +#define DMA_IFCR_CTCIF6_BIT 21 +#define DMA_IFCR_CGIF6_BIT 20 +#define DMA_IFCR_CTEIF5_BIT 19 +#define DMA_IFCR_CHTIF5_BIT 18 +#define DMA_IFCR_CTCIF5_BIT 17 +#define DMA_IFCR_CGIF5_BIT 16 +#define DMA_IFCR_CTEIF4_BIT 15 +#define DMA_IFCR_CHTIF4_BIT 14 +#define DMA_IFCR_CTCIF4_BIT 13 +#define DMA_IFCR_CGIF4_BIT 12 +#define DMA_IFCR_CTEIF3_BIT 11 +#define DMA_IFCR_CHTIF3_BIT 10 +#define DMA_IFCR_CTCIF3_BIT 9 +#define DMA_IFCR_CGIF3_BIT 8 +#define DMA_IFCR_CTEIF2_BIT 7 +#define DMA_IFCR_CHTIF2_BIT 6 +#define DMA_IFCR_CTCIF2_BIT 5 +#define DMA_IFCR_CGIF2_BIT 4 +#define DMA_IFCR_CTEIF1_BIT 3 +#define DMA_IFCR_CHTIF1_BIT 2 +#define DMA_IFCR_CTCIF1_BIT 1 +#define DMA_IFCR_CGIF1_BIT 0 + +#define DMA_IFCR_CTEIF7 BIT(DMA_IFCR_CTEIF7_BIT) +#define DMA_IFCR_CHTIF7 BIT(DMA_IFCR_CHTIF7_BIT) +#define DMA_IFCR_CTCIF7 BIT(DMA_IFCR_CTCIF7_BIT) +#define DMA_IFCR_CGIF7 BIT(DMA_IFCR_CGIF7_BIT) +#define DMA_IFCR_CTEIF6 BIT(DMA_IFCR_CTEIF6_BIT) +#define DMA_IFCR_CHTIF6 BIT(DMA_IFCR_CHTIF6_BIT) +#define DMA_IFCR_CTCIF6 BIT(DMA_IFCR_CTCIF6_BIT) +#define DMA_IFCR_CGIF6 BIT(DMA_IFCR_CGIF6_BIT) +#define DMA_IFCR_CTEIF5 BIT(DMA_IFCR_CTEIF5_BIT) +#define DMA_IFCR_CHTIF5 BIT(DMA_IFCR_CHTIF5_BIT) +#define DMA_IFCR_CTCIF5 BIT(DMA_IFCR_CTCIF5_BIT) +#define DMA_IFCR_CGIF5 BIT(DMA_IFCR_CGIF5_BIT) +#define DMA_IFCR_CTEIF4 BIT(DMA_IFCR_CTEIF4_BIT) +#define DMA_IFCR_CHTIF4 BIT(DMA_IFCR_CHTIF4_BIT) +#define DMA_IFCR_CTCIF4 BIT(DMA_IFCR_CTCIF4_BIT) +#define DMA_IFCR_CGIF4 BIT(DMA_IFCR_CGIF4_BIT) +#define DMA_IFCR_CTEIF3 BIT(DMA_IFCR_CTEIF3_BIT) +#define DMA_IFCR_CHTIF3 BIT(DMA_IFCR_CHTIF3_BIT) +#define DMA_IFCR_CTCIF3 BIT(DMA_IFCR_CTCIF3_BIT) +#define DMA_IFCR_CGIF3 BIT(DMA_IFCR_CGIF3_BIT) +#define DMA_IFCR_CTEIF2 BIT(DMA_IFCR_CTEIF2_BIT) +#define DMA_IFCR_CHTIF2 BIT(DMA_IFCR_CHTIF2_BIT) +#define DMA_IFCR_CTCIF2 BIT(DMA_IFCR_CTCIF2_BIT) +#define DMA_IFCR_CGIF2 BIT(DMA_IFCR_CGIF2_BIT) +#define DMA_IFCR_CTEIF1 BIT(DMA_IFCR_CTEIF1_BIT) +#define DMA_IFCR_CHTIF1 BIT(DMA_IFCR_CHTIF1_BIT) +#define DMA_IFCR_CTCIF1 BIT(DMA_IFCR_CTCIF1_BIT) +#define DMA_IFCR_CGIF1 BIT(DMA_IFCR_CGIF1_BIT) + +/* Channel configuration register */ + +#define DMA_CCR_MEM2MEM_BIT 14 +#define DMA_CCR_MINC_BIT 7 +#define DMA_CCR_PINC_BIT 6 +#define DMA_CCR_CIRC_BIT 5 +#define DMA_CCR_DIR_BIT 4 +#define DMA_CCR_TEIE_BIT 3 +#define DMA_CCR_HTIE_BIT 2 +#define DMA_CCR_TCIE_BIT 1 +#define DMA_CCR_EN_BIT 0 + +#define DMA_CCR_MEM2MEM BIT(DMA_CCR_MEM2MEM_BIT) +#define DMA_CCR_PL (0x3 << 12) +#define DMA_CCR_PL_LOW (0x0 << 12) +#define DMA_CCR_PL_MEDIUM (0x1 << 12) +#define DMA_CCR_PL_HIGH (0x2 << 12) +#define DMA_CCR_PL_VERY_HIGH (0x3 << 12) +#define DMA_CCR_MSIZE (0x3 << 10) +#define DMA_CCR_MSIZE_8BITS (0x0 << 10) +#define DMA_CCR_MSIZE_16BITS (0x1 << 10) +#define DMA_CCR_MSIZE_32BITS (0x2 << 10) +#define DMA_CCR_PSIZE (0x3 << 8) +#define DMA_CCR_PSIZE_8BITS (0x0 << 8) +#define DMA_CCR_PSIZE_16BITS (0x1 << 8) +#define DMA_CCR_PSIZE_32BITS (0x2 << 8) +#define DMA_CCR_MINC BIT(DMA_CCR_MINC_BIT) +#define DMA_CCR_PINC BIT(DMA_CCR_PINC_BIT) +#define DMA_CCR_CIRC BIT(DMA_CCR_CIRC_BIT) +#define DMA_CCR_DIR BIT(DMA_CCR_DIR_BIT) +#define DMA_CCR_TEIE BIT(DMA_CCR_TEIE_BIT) +#define DMA_CCR_HTIE BIT(DMA_CCR_HTIE_BIT) +#define DMA_CCR_TCIE BIT(DMA_CCR_TCIE_BIT) +#define DMA_CCR_EN BIT(DMA_CCR_EN_BIT) + +/* + * Devices + */ + +/** Encapsulates state related to a DMA channel interrupt. */ +typedef struct dma_handler_config { + void (*handler)(void); + nvic_irq_num irq_line; +} dma_handler_config; + +/** DMA device type */ +typedef struct dma_dev { + dma_reg_map *regs; /**< Register map */ + rcc_clk_id clk_id; /**< Clock ID */ + dma_handler_config handlers[]; /**< IRQ handlers and NVIC numbers. */ +} dma_dev; + +/** DMA1 device */ +extern dma_dev *DMA1; +#ifdef STM32_HIGH_DENSITY +/** DMA2 device */ +extern dma_dev *DMA2; +#endif + +/* + * Convenience functions + */ + +void dma_init(dma_dev *dev); /** 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_MEM_2_MEM = 1 << 14, /**< Memory to memory mode */ + 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; +typedef enum dma_xfer_size { + DMA_SIZE_8BITS = 0, /**< 8-bit transfers */ + DMA_SIZE_16BITS = 1, /**< 16-bit transfers */ + DMA_SIZE_32BITS = 2 /**< 32-bit transfers */ +} dma_xfer_size; + +/** DMA channel */ +typedef enum dma_channel { + DMA_CH1 = 1, /**< Channel 1 */ + DMA_CH2 = 2, /**< Channel 2 */ + DMA_CH3 = 3, /**< Channel 3 */ + DMA_CH4 = 4, /**< Channel 4 */ + DMA_CH5 = 5, /**< Channel 5 */ + DMA_CH6 = 6, /**< Channel 6 */ + DMA_CH7 = 7, /**< Channel 7 */ +} dma_channel; + +void dma_setup_transfer(dma_dev *dev, + dma_channel channel, + __io void *peripheral_address, + dma_xfer_size peripheral_size, + __io void *memory_address, + dma_xfer_size memory_size, + uint32 mode); + +void dma_set_num_transfers(dma_dev *dev, + dma_channel channel, + uint16 num_transfers); + +/** DMA transfer priority. */ +typedef enum dma_priority { + DMA_PRIORITY_LOW = DMA_CCR_PL_LOW, /**< Low priority */ + DMA_PRIORITY_MEDIUM = DMA_CCR_PL_MEDIUM, /**< Medium priority */ + DMA_PRIORITY_HIGH = DMA_CCR_PL_HIGH, /**< High priority */ + DMA_PRIORITY_VERY_HIGH = DMA_CCR_PL_VERY_HIGH /**< Very high priority */ +} dma_priority; + +void dma_set_priority(dma_dev *dev, + dma_channel channel, + dma_priority priority); + +void dma_attach_interrupt(dma_dev *dev, + dma_channel channel, + void (*handler)(void)); +void dma_detach_interrupt(dma_dev *dev, dma_channel channel); + +/** + * Encodes the reason why a DMA interrupt was called. + * @see dma_get_irq_cause() + */ +typedef enum dma_irq_cause { + DMA_TRANSFER_COMPLETE, /**< Transfer is complete. */ + DMA_TRANSFER_HALF_COMPLETE, /**< Transfer is half complete. */ + DMA_TRANSFER_ERROR, /**< Error occurred during transfer. */ +} dma_irq_cause; + +dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_channel channel); + +void dma_enable(dma_dev *dev, dma_channel channel); +void dma_disable(dma_dev *dev, dma_channel channel); + +void dma_set_mem_addr(dma_dev *dev, dma_channel channel, __io void *address); +void dma_set_per_addr(dma_dev *dev, dma_channel channel, __io void *address); /** - * Initialize a DMA channel. If desired, attach an interrupt handler - * using dma_attach_interrupt(). Start the transfer using - * dma_start(). + * @brief DMA channel register map type. * - * @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); + * Provides access to an individual channel's registers. + */ +typedef struct dma_channel_reg_map { + __io uint32 CCR; /**< Channel configuration register */ + __io uint32 CNDTR; /**< Channel number of data register */ + __io uint32 CPAR; /**< Channel peripheral address register */ + __io uint32 CMAR; /**< Channel memory address register */ +} dma_channel_reg_map; + +#define DMA_CHANNEL_NREGS 5 /** - * Begin a DMA transfer initialized with dma_init(). + * @brief Obtain a pointer to an individual DMA channel's registers. * - * @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); + * For example, dma_channel_regs(DMA1, DMA_CH1)->CCR is DMA1_BASE->CCR1. + * + * @param dev DMA device + * @param channel DMA channel whose channel register map to obtain. + */ +static inline dma_channel_reg_map* dma_channel_regs(dma_dev *dev, + dma_channel channel) { + __io uint32 *ccr1 = &dev->regs->CCR1; + return (dma_channel_reg_map*)(ccr1 + DMA_CHANNEL_NREGS * (channel - 1)); +} + +/** + * @brief Check if a DMA channel is enabled + * @param dev DMA device + * @param channel Channel whose enabled bit to check. + */ +static inline uint8 dma_is_channel_enabled(dma_dev *dev, dma_channel channel) { + return (uint8)(dma_channel_regs(dev, channel)->CCR & DMA_CCR_EN); +} /** - * 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); + * @brief Get the ISR status bits for a DMA channel. + * + * The bits are returned right-aligned, in the following order: + * transfer error flag, half-transfer flag, transfer complete flag, + * global interrupt flag. + * + * If you're attempting to figure out why a DMA interrupt fired; you + * may find dma_get_irq_cause() more convenient. + * + * @see dma_get_irq_cause(). + */ +static inline uint8 dma_get_isr_bits(dma_dev *dev, dma_channel channel) { + uint8 shift = (channel - 1) * 4; + return (dev->regs->ISR >> shift) & 0xF; +} /** - * Detach any handler associated with the given DMA channel. - * @param channel Channel whose interrupt handler to detach. */ -void dma_detach_interrupt(uint8 channel); + * @brief Clear the ISR status bits for a given DMA channel. + * + * If you're attempting to clean up after yourself in a DMA interrupt, + * you may find dma_get_irq_cause() more convenient. + * + * @see dma_get_irq_cause() + */ +static inline void dma_clear_isr_bits(dma_dev *dev, dma_channel channel) { + dev->regs->IFCR = BIT(4 * (channel - 1)); +} #ifdef __cplusplus } // extern "C" diff --git a/libmaple/nvic.h b/libmaple/nvic.h index df3461b..2e98c9f 100644 --- a/libmaple/nvic.h +++ b/libmaple/nvic.h @@ -31,6 +31,7 @@ #define _NVIC_H_ #include "libmaple_types.h" +#include "util.h" #ifdef __cplusplus extern "C"{ diff --git a/notes/dma.txt b/notes/dma.txt new file mode 100644 index 0000000..97b23a0 --- /dev/null +++ b/notes/dma.txt @@ -0,0 +1,99 @@ +DMA Notes +========= + +Medium-density devices have one DMA controller, DMA1. High-density +devices and up also have DMA2. DMA1 has 7 channels; DMA2 has 5. Each +channel multiplexes DMA requests from various peripherals, like so: + +Channel Capabilities +-------------------- + +DMA1: + + * Channel 1: ADC1, TIM2_CH3, TIM4_CH1 + * Channel 2: USART3_TX, TIM1_CH1, TIM2_UP, TIM3_CH3, SPI1_RX + * Channel 3: USART3_RX, TIM1_CH2, TIM3_CH4, TIM3_UP, SPI1_TX + * Channel 4: USART1_TX, TIM1_CH4, TIM1_TRIG, TIM1_COM, TIM4_CH2, + SPI2/I2S2_RX, I2C2_TX + * Channel 5: USART1_RX, TIM1_UP, TIM2_CH1, TIM4_CH3, + SPI2/I2S2_TX, I2C2_RX + * Channel 6: USART2_RX, TIM1_CH3, TIM3_CH1, TIM3_TRIG, I2C1_TX + * Channel 7: USART2_TX, TIM2_CH2, TIM2_CH4, TIM4_UP, I2C1_RX + +DMA2: + + * Channel 1: TIM5_CH4, TIM5_TRIG, TIM8_CH3, TIM8_UP, SPI/I2S3_RX + * Channel 2: TIM8_CH4, TIM8_TRIG, TIM8_COM, TIM5_CH3, TIM5_UP, SPI/I2S3_TX + * Channel 3: TIM8_CH1, UART4_RX, TIM6_UP/DAC_CH1 + * Channel 4: TIM5_CH2, SDIO, TIM7_UP/DAC_CH2 + * Channel 5: ADC3, TIM8_CH2, TIM5_CH1, UART4_TX + +An example usage: via DMA1, channel 1, you can have ADC1 periodically +dump converted data into an array in memory. The DMA controller can +then interrupt you when the array is half-full and full, and if any +error occurred. + +Since channels are multiplexed in hardware, you can't simultaneously +use the same DMA channel to serve requests from two of its peripherals +at the same time. For example, if you are using DMA 1 channel 1 to +serve DMA requests from ADC1, you can't also serve requests from Timer +2 channel 3. + +Channel Priority +---------------- + +An arbiter prioritizes simultaneous channel DMA requests. Channel +priority levels are configurable (4 levels of priority). Ties within +a DMA controller are broken by choosing the lower channel number; +between the controllers, DMA1 has higher priority than DMA2. + +Interrupts +---------- + +You can cause an interrupt to fire once half the transfers are +complete, when all the transfers are complete, if an error occurs +during transfer, or any combination of the three. + +If an error occurs, the transfer is automatically disabled. + +Configuration +------------- + +In order to configure a DMA transfer for DMA controller n, channel x, +ST RM0008 says you should do the following: + + A. Set the peripheral register address in DMAn_BASE->CPARx. + B. Set the memory address in DMAn_BASE->CMARx. + C. Set the number of data to be transferred in DMAn_BASE->CNDTRx. + D. Set the channel priority via the PL bits in DMAn_BASE->CCRx. + E. Configure various other things (e.g. data transfer sizes, what + events cause channel interrupts) in DMAn_BASE->CCRx as desired. + F. Activate the channel by setting ENABLE bit in DMAn_BASE->CCRx. + +The channel will start serving DMA requests as soon as it's activated. + +The DMA library lets you accomplish these tasks as follows: + + **Setup transfer** + + Do (A), (B), and (E) using dma_setup_transfer(). + + This also does (D), but chooses the lowest priority by default. + + **Perform any other desired configuration** + + You can do (C) using dma_set_num_transfers(). + + You can do (D) using dma_set_priority(). + + You can attach interrupt handlers with dma_attach_interrupt(). + + **Activate the channel** + + Do (F) with dma_enable(). + +Once you're all done, you can dma_disable() the channel. If you +dma_detach_interrupt() an interrupt handler, the channel interrupts +will stop firing, but the transfer itself won't stop until it's done +(which never happens if you set the DMA_CIRC_MODE flag when you called +dma_setup_transfer()). -- cgit v1.2.3 From 5020d432d712f29d616a93d6597bedb40f2fc601 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Mon, 11 Apr 2011 23:46:28 -0400 Subject: Merging in changes from 0.0.9-maintenance. --- docs/source/maple-ide-install.rst | 15 ++++++++++----- docs/source/usb.rst | 5 ++++- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/docs/source/maple-ide-install.rst b/docs/source/maple-ide-install.rst index f439abe..5c79d41 100644 --- a/docs/source/maple-ide-install.rst +++ b/docs/source/maple-ide-install.rst @@ -17,7 +17,8 @@ us directly`_\ ! Download -------- -Choose the correct version for your operating system: +The current release of the Maple IDE is version 0.0.9. Choose the +correct version for your operating system: .. list-table:: :widths: 15 30 50 @@ -28,15 +29,15 @@ Choose the correct version for your operating system: - IDE Package * - Windows - Tested on 32bit Windows XP - - `maple-ide-LATEST-windowsxp32.zip `_ (about 75mb) + - `maple-ide-0.0.9-windowsxp32.zip `_ (about 75mb) * - Linux - Tested on Ubuntu 9.10 (64bit) and 10.04 (32bit) - - `maple-ide-LATEST-linux32.tgz `_ (about 30mb) + - `maple-ide-0.0.9-linux32.tgz `_ (about 30mb) - `maple-ide-LATEST-linux64.tgz `_ (about 30mb) + `maple-ide-0.0.9-linux64.tgz `_ (about 30mb) * - Mac OSX - Tested on Snow Leopard 10.6 (64bit and 32bit) - - `maple-ide-LATEST-macosx-10_6.dmg `_ (about 40mb) + - `maple-ide-0.0.9-macosx-10_6.dmg `_ (about 40mb) The package bundles together a compiler, an upload utility, a software library, and a simple GUI text editor. All this software is `free and @@ -46,6 +47,10 @@ open `_; we are grateful to the `Arduino `OpenMoko `_ developers, as well as many others, who allow us to reuse their software. +**Looking for something older?** `Source archives and binaries +`_ are available +for previously-released versions. + Installation ------------ diff --git a/docs/source/usb.rst b/docs/source/usb.rst index f502f31..0468618 100644 --- a/docs/source/usb.rst +++ b/docs/source/usb.rst @@ -34,7 +34,10 @@ second problem is the use of :ref:`perpetual bootloader mode Recommended Reading ------------------- -* `USB in a NutShell `_ overview from Beyond Logic +* `USB in a Nutshell `_, an overview from Beyond Logic +* `USB made simple `_, an illustrated series of articles on USB +* The `USB 2.0 Specification `_ (`direct link `_) +* `Embedded USB - a brief tutorial `_ * `Wikipedia article on Universal Serial Bus (USB) `_ * Linux Kernel documentation for `USB ACM `_ and `USB Serial `_ * STMicro documentation for STM32F103RB microcontroller: -- cgit v1.2.3 From d3949203fe053249d35e0c4125f3ed21818e8c32 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Mon, 11 Apr 2011 23:46:44 -0400 Subject: Coding standard. --- notes/coding_standard.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/notes/coding_standard.rst b/notes/coding_standard.rst index ced946d..b0fa91b 100644 --- a/notes/coding_standard.rst +++ b/notes/coding_standard.rst @@ -27,12 +27,12 @@ Vim customizations to do the same thing would be nice (hint, hint)! License ------- +.. highlight:: scheme + - Put an MIT license at the beginning of the file (look at any of our source files for an example). Copyright should go either to you or to LeafLabs, LLC. -.. highlight:: scheme - Emacs: if you don't like seeing the license, you should use elide-head (which will hide it for you). You can use the following:: -- cgit v1.2.3 From 7b14b950363f707c40732b4387f2f50711907673 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Tue, 12 Apr 2011 00:08:54 -0400 Subject: Doxygen bugfixes. Fixed various Doxygen comment errors. --- libmaple/adc.h | 1 + libmaple/bkp.h | 6 +++--- libmaple/dma.h | 4 ++++ libmaple/ring_buffer.h | 6 +++--- libmaple/timer.h | 9 +++++---- wirish/pwm.h | 3 +++ wirish/wirish_time.h | 2 +- wirish/wirish_types.h | 3 +++ 8 files changed, 23 insertions(+), 11 deletions(-) diff --git a/libmaple/adc.h b/libmaple/adc.h index 520b982..c6a67a0 100644 --- a/libmaple/adc.h +++ b/libmaple/adc.h @@ -309,6 +309,7 @@ uint16 adc_read(const adc_dev *dev, uint8 channel); * Defines the total number of conversions in the regular channel * conversion sequence. * + * @param dev ADC device. * @param length Regular channel sequence length, from 1 to 16. */ static inline void adc_set_reg_seqlen(const adc_dev *dev, uint8 length) { diff --git a/libmaple/bkp.h b/libmaple/bkp.h index cea39b6..97edd2a 100644 --- a/libmaple/bkp.h +++ b/libmaple/bkp.h @@ -46,7 +46,7 @@ extern "C" { /** Backup peripheral register map type. */ typedef struct bkp_reg_map { - const uint32 RESERVED1; + const uint32 RESERVED1; ///< Reserved __io uint32 DR1; ///< Data register 1 __io uint32 DR2; ///< Data register 2 __io uint32 DR3; ///< Data register 3 @@ -61,8 +61,8 @@ typedef struct bkp_reg_map { __io uint32 CR; ///< Control register __io uint32 CSR; ///< Control and status register #ifdef STM32_HIGH_DENSITY - const uint32 RESERVED2; - const uint32 RESERVED3; + const uint32 RESERVED2; ///< Reserved + const uint32 RESERVED3; ///< Reserved __io uint32 DR11; ///< Data register 11 __io uint32 DR12; ///< Data register 12 __io uint32 DR13; ///< Data register 13 diff --git a/libmaple/dma.h b/libmaple/dma.h index c763672..7c380d0 100644 --- a/libmaple/dma.h +++ b/libmaple/dma.h @@ -417,6 +417,8 @@ static inline uint8 dma_is_channel_enabled(dma_dev *dev, dma_channel channel) { * If you're attempting to figure out why a DMA interrupt fired; you * may find dma_get_irq_cause() more convenient. * + * @param dev DMA device + * @param channel Channel whose ISR bits to return. * @see dma_get_irq_cause(). */ static inline uint8 dma_get_isr_bits(dma_dev *dev, dma_channel channel) { @@ -430,6 +432,8 @@ static inline uint8 dma_get_isr_bits(dma_dev *dev, dma_channel channel) { * If you're attempting to clean up after yourself in a DMA interrupt, * you may find dma_get_irq_cause() more convenient. * + * @param dev DMA device + * @param channel Channel whose ISR bits to clear. * @see dma_get_irq_cause() */ static inline void dma_clear_isr_bits(dma_dev *dev, dma_channel channel) { diff --git a/libmaple/ring_buffer.h b/libmaple/ring_buffer.h index 101f010..ad6ad96 100644 --- a/libmaple/ring_buffer.h +++ b/libmaple/ring_buffer.h @@ -89,7 +89,7 @@ static inline uint16 rb_full_count(ring_buffer *rb) { /** * @brief Returns true if and only if the ring buffer is full. - * @brief rb Buffer to test. + * @param rb Buffer to test. */ static inline int rb_is_full(ring_buffer *rb) { return (rb->tail + 1 == rb->head) || @@ -139,8 +139,8 @@ static inline int16 rb_safe_remove(ring_buffer *rb) { /** * @brief Attempt to insert an element into a ring buffer. * - * @brief rb Buffer to insert into. - * @brief element Value to insert into rb. + * @param rb Buffer to insert into. + * @param element Value to insert into rb. * @sideeffect If rb is not full, appends element onto buffer. * @return If element was appended, then true; otherwise, false. */ static inline int rb_safe_insert(ring_buffer *rb, uint8 element) { diff --git a/libmaple/timer.h b/libmaple/timer.h index fa19cc9..befc026 100644 --- a/libmaple/timer.h +++ b/libmaple/timer.h @@ -628,8 +628,8 @@ static inline uint16 timer_get_count(timer_dev *dev) { /** * @brief Sets the counter value for the given timer. - * @param timer_num Timer whose counter to set - * @param value New counter value + * @param dev Timer whose counter to set + * @param value New counter value */ static inline void timer_set_count(timer_dev *dev, uint16 value) { (dev->regs).bas->CNT = value; @@ -804,8 +804,8 @@ static inline void timer_cc_disable(timer_dev *dev, uint8 channel) { /** * @brief Get a channel's capture/compare output polarity - * @brief dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. - * @brief channel Channel whose capture/compare output polarity to get. + * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. + * @param channel Channel whose capture/compare output polarity to get. * @return Polarity, either 0 or 1. * @see timer_cc_set_polarity() */ @@ -982,6 +982,7 @@ typedef enum timer_oc_mode_flags { * * @param dev Timer device, must have type TIMER_ADVANCED or TIMER_GENERAL. * @param channel Channel to configure in output compare mode. + * @param mode Timer mode to set. * @param flags OR of timer_oc_mode_flags. * @see timer_oc_mode * @see timer_oc_mode_flags diff --git a/wirish/pwm.h b/wirish/pwm.h index a6385e9..4ce4bb4 100644 --- a/wirish/pwm.h +++ b/wirish/pwm.h @@ -43,6 +43,9 @@ * * User code is expected to determine and honor the maximum value * (based on the configured period). + * + * @param pin PWM output pin + * @param duty_cycle Duty cycle to set. */ void pwmWrite(uint8 pin, uint16 duty_cycle); diff --git a/wirish/wirish_time.h b/wirish/wirish_time.h index a0c0c82..a0b1c11 100644 --- a/wirish/wirish_time.h +++ b/wirish/wirish_time.h @@ -23,7 +23,7 @@ *****************************************************************************/ /** - * @file time.h + * @file wirish_time.h * @brief Timing and delay functions. */ diff --git a/wirish/wirish_types.h b/wirish/wirish_types.h index 475f470..39efae0 100644 --- a/wirish/wirish_types.h +++ b/wirish/wirish_types.h @@ -57,6 +57,9 @@ typedef struct stm32_pin_info { uint8 adc_channel; /**< Pin ADC channel, or ADCx if none. */ } stm32_pin_info; +/** + * Variable attribute, instructs the linker to place the marked + * variable in Flash instead of RAM. */ #define __FLASH__ __attr_flash #endif -- cgit v1.2.3 From ee1d13d27d6e6be7f9babce655f697fe7f224c77 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Tue, 12 Apr 2011 00:43:12 -0400 Subject: Adding guards for negative nvic_irq_num enumerators. nvic_irq_enable() and nvic_irq_disable() previously didn't protect against negative arguments. --- libmaple/nvic.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libmaple/nvic.h b/libmaple/nvic.h index 2e98c9f..496c41b 100644 --- a/libmaple/nvic.h +++ b/libmaple/nvic.h @@ -160,6 +160,9 @@ static inline void nvic_globalirq_disable() { * @param irq_num Interrupt to enable */ static inline void nvic_irq_enable(nvic_irq_num irq_num) { + if (irq_num < 0) { + return; + } NVIC_BASE->ISER[irq_num / 32] = BIT(irq_num % 32); } @@ -168,6 +171,9 @@ static inline void nvic_irq_enable(nvic_irq_num irq_num) { * @param irq_num Interrupt to disable */ static inline void nvic_irq_disable(nvic_irq_num irq_num) { + if (irq_num < 0) { + return; + } NVIC_BASE->ICER[irq_num / 32] = BIT(irq_num % 32); } -- cgit v1.2.3 From 2ffc87ca9b47bd605e5630a33b36f83e5e8486da Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Tue, 12 Apr 2011 00:44:05 -0400 Subject: Changing usages of "volatile" to "__io". --- libmaple/i2c.h | 2 +- libmaple/ring_buffer.h | 6 ++++-- libmaple/systick.c | 2 +- libmaple/systick.h | 2 +- libmaple/util.h | 4 ++-- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/libmaple/i2c.h b/libmaple/i2c.h index 21c17c1..a17e144 100644 --- a/libmaple/i2c.h +++ b/libmaple/i2c.h @@ -66,7 +66,7 @@ typedef struct i2c_dev { uint8 clk_line; uint8 ev_nvic_line; uint8 er_nvic_line; - volatile uint8 state; + __io uint8 state; uint16 msgs_left; i2c_msg *msg; } i2c_dev; diff --git a/libmaple/ring_buffer.h b/libmaple/ring_buffer.h index ad6ad96..04f6499 100644 --- a/libmaple/ring_buffer.h +++ b/libmaple/ring_buffer.h @@ -35,6 +35,8 @@ #ifndef _RING_BUFFER_H_ #define _RING_BUFFER_H_ +#include "libmaple_types.h" + #ifdef __cplusplus extern "C"{ #endif @@ -49,7 +51,7 @@ extern "C"{ * * One byte is left free to distinguish empty from full. */ typedef struct ring_buffer { - volatile uint8 *buf; /**< Buffer items are stored into */ + __io uint8 *buf; /**< Buffer items are stored into */ uint16 head; /**< Index of the next item to remove */ uint16 tail; /**< Index where the next item will get inserted */ uint16 size; /**< Buffer capacity minus one */ @@ -79,7 +81,7 @@ static inline void rb_init(ring_buffer *rb, uint16 size, uint8 *buf) { * @param rb Buffer whose elements to count. */ static inline uint16 rb_full_count(ring_buffer *rb) { - volatile ring_buffer *arb = rb; + __io ring_buffer *arb = rb; int32 size = arb->tail - arb->head; if (arb->tail < arb->head) { size += arb->size + 1; diff --git a/libmaple/systick.c b/libmaple/systick.c index c04f4f3..103893e 100644 --- a/libmaple/systick.c +++ b/libmaple/systick.c @@ -28,7 +28,7 @@ #include "systick.h" -volatile uint32 systick_timer_millis; +__io uint32 systick_timer_millis; /** * @brief Initialize and enable SysTick. diff --git a/libmaple/systick.h b/libmaple/systick.h index 35b4cb9..4654c5f 100644 --- a/libmaple/systick.h +++ b/libmaple/systick.h @@ -73,7 +73,7 @@ typedef struct systick_reg_map { #define SYSTICK_CVR_TENMS 0xFFFFFF /** System elapsed time, in milliseconds */ -extern volatile uint32 systick_timer_millis; +extern __io uint32 systick_timer_millis; void systick_init(uint32 reload_val); void systick_disable(); diff --git a/libmaple/util.h b/libmaple/util.h index aff70e1..4c47764 100644 --- a/libmaple/util.h +++ b/libmaple/util.h @@ -50,8 +50,8 @@ extern "C"{ * Register reads and writes */ -#define __read(reg) (*(volatile uint32*)(reg)) -#define __write(reg, value) (*(volatile uint32*)(reg) = (value)) +#define __read(reg) (*(__io uint32*)(reg)) +#define __write(reg, value) (*(__io uint32*)(reg) = (value)) /* * Failure routines -- cgit v1.2.3 From 1d97a8e7c55db7d9d52acefa90f66c19b3908b2d Mon Sep 17 00:00:00 2001 From: Anton Eltchaninov Date: Mon, 11 Apr 2011 18:17:09 +0700 Subject: Adding i2c2 and i2c fast mode Signed-off-by: Anton Eltchaninov --- libmaple/i2c.c | 54 +++++++++++++++++++++++++++++++++++++++++++----------- libmaple/i2c.h | 5 +++-- libmaple/rcc.c | 2 +- libmaple/rcc.h | 2 +- 4 files changed, 48 insertions(+), 15 deletions(-) diff --git a/libmaple/i2c.c b/libmaple/i2c.c index a6638be..efe4dce 100644 --- a/libmaple/i2c.c +++ b/libmaple/i2c.c @@ -49,6 +49,19 @@ static i2c_dev i2c_dev1 = { i2c_dev* const I2C1 = &i2c_dev1; +static i2c_dev i2c_dev2 = { + .regs = I2C2_BASE, + .gpio_port = &gpiob, + .sda_pin = 11, + .scl_pin = 10, + .clk_line = RCC_I2C2, + .ev_nvic_line = NVIC_I2C2_EV, + .er_nvic_line = NVIC_I2C2_ER, + .state = I2C_STATE_IDLE +}; + +i2c_dev* const I2C2 = &i2c_dev2; + struct crumb { uint32 event; uint32 sr1; @@ -140,7 +153,8 @@ static void i2c_irq_handler(i2c_dev *dev) { * Master transmitter: write first byte to fill shift register. * We should get another TXE interrupt immediately to fill DR again. */ - i2c_write(dev, msg->data[msg->xferred++]); + if (msg->length != 1) + i2c_write(dev, msg->data[msg->xferred++]); } sr1 = sr2 = 0; } @@ -243,6 +257,10 @@ void __irq_i2c1_ev(void) { i2c_irq_handler(&i2c_dev1); } +void __irq_i2c2_ev(void) { + i2c_irq_handler(&i2c_dev2); +} + static void i2c_irq_error_handler(i2c_dev *dev) { uint32 sr1 = dev->regs->SR1; uint32 sr2 = dev->regs->SR2; @@ -257,6 +275,10 @@ void __irq_i2c1_er(void) { i2c_irq_error_handler(&i2c_dev1); } +void __irq_i2c2_er(void) { + i2c_irq_error_handler(&i2c_dev2); +} + static void i2c_bus_reset(const i2c_dev *dev) { /* Release both lines */ gpio_write_bit(dev->gpio_port, dev->scl_pin, 1); @@ -301,8 +323,11 @@ static void i2c_bus_reset(const i2c_dev *dev) { * I2C_10BIT_ADDRESSING: Enable 10-bit addressing */ void i2c_master_enable(i2c_dev *dev, uint32 flags) { +#define I2C_CLK (PCLK1/1000000) #define STANDARD_CCR (PCLK1/(100000*2)) -#define STANDARD_TRISE 37 +#define STANDARD_TRISE (I2C_CLK+1) +#define FAST_CCR (I2C_CLK/10) +#define FAST_TRISE ((I2C_CLK*3)/10+1) /* Reset the bus. Clock out any hung slaves. */ i2c_bus_reset(dev); @@ -313,17 +338,24 @@ void i2c_master_enable(i2c_dev *dev, uint32 flags) { gpio_set_mode(dev->gpio_port, dev->scl_pin, GPIO_AF_OUTPUT_OD); /* I2C1 and I2C2 are fed from APB1, clocked at 36MHz */ - i2c_set_input_clk(dev, 36); + i2c_set_input_clk(dev, I2C_CLK); - /* 100 khz only for now */ - i2c_set_clk_control(dev, STANDARD_CCR); + if(flags & I2C_FAST_MODE) { - /* - * Set scl rise time, standard mode for now. - * Max rise time in standard mode: 1000 ns - * Max rise time in fast mode: 300ns - */ - i2c_set_trise(dev, STANDARD_TRISE); + /* 400 kHz for fast mode, set DUTY and F/S bits */ + i2c_set_clk_control(dev, FAST_CCR|I2C_CCR_DUTY|I2C_CCR_FS); + + /* Set scl rise time, max rise time in fast mode: 300ns */ + i2c_set_trise(dev, FAST_TRISE); + + } else { + + /* 100 kHz for standard mode */ + i2c_set_clk_control(dev, STANDARD_CCR); + + /* Max rise time in standard mode: 1000 ns */ + i2c_set_trise(dev, STANDARD_TRISE); + } /* Enable event and buffer interrupts */ nvic_irq_enable(dev->ev_nvic_line); diff --git a/libmaple/i2c.h b/libmaple/i2c.h index a17e144..07ee260 100644 --- a/libmaple/i2c.h +++ b/libmaple/i2c.h @@ -71,8 +71,8 @@ typedef struct i2c_dev { i2c_msg *msg; } i2c_dev; - extern i2c_dev* const I2C1; +extern i2c_dev* const I2C2; #define I2C1_BASE (i2c_reg_map*)0x40005400 #define I2C2_BASE (i2c_reg_map*)0x40005800 @@ -100,7 +100,8 @@ extern i2c_dev* const I2C1; #define I2C_CR2_FREQ 0xFFF // Peripheral input frequency /* Clock control register bits */ -#define I2C_CCR_FS BIT(15) // Master mode selection +#define I2C_CCR_FS BIT(15) // Fast mode selection +#define I2C_CCR_DUTY BIT(14) // 16/9 duty ratio #define I2C_CCR_CCR 0xFFF // Clock control bits /* Status register 1 bits */ diff --git a/libmaple/rcc.c b/libmaple/rcc.c index 327e3ad..78abbcf 100644 --- a/libmaple/rcc.c +++ b/libmaple/rcc.c @@ -67,6 +67,7 @@ static const struct rcc_dev_info rcc_dev_table[] = { [RCC_PWR] = { .clk_domain = APB1, .line_num = 28}, [RCC_BKP] = { .clk_domain = APB1, .line_num = 27}, [RCC_I2C1] = { .clk_domain = APB1, .line_num = 21 }, + [RCC_I2C2] = { .clk_domain = APB1, .line_num = 22 }, [RCC_CRC] = { .clk_domain = AHB, .line_num = 6}, [RCC_FLITF] = { .clk_domain = AHB, .line_num = 4}, [RCC_SRAM] = { .clk_domain = AHB, .line_num = 2}, @@ -83,7 +84,6 @@ static const struct rcc_dev_info rcc_dev_table[] = { [RCC_FSMC] = { .clk_domain = AHB, .line_num = 8 }, [RCC_DAC] = { .clk_domain = APB1, .line_num = 29 }, [RCC_DMA2] = { .clk_domain = AHB, .line_num = 1 }, - [RCC_I2C2] = { .clk_domain = APB1, .line_num = 22 }, [RCC_SDIO] = { .clk_domain = AHB, .line_num = 10 }, #endif #ifdef STM32_XL_DENSITY diff --git a/libmaple/rcc.h b/libmaple/rcc.h index e6fa196..91f77d0 100644 --- a/libmaple/rcc.h +++ b/libmaple/rcc.h @@ -449,6 +449,7 @@ typedef enum { RCC_PWR, RCC_BKP, RCC_I2C1, + RCC_I2C2, RCC_CRC, RCC_FLITF, RCC_SRAM, @@ -465,7 +466,6 @@ typedef enum { RCC_FSMC, RCC_DAC, RCC_DMA2, - RCC_I2C2, RCC_SDIO, #endif #ifdef STM32_XL_DENSITY -- cgit v1.2.3 From 834fa46360b7c4a714e0067a84948582b0dfa0c4 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Tue, 12 Apr 2011 15:41:59 -0400 Subject: Making 1c05ac8497222a12a675ba31564e7c4864107de9 comply with coding standard. Whitespace corrections only. --- libmaple/i2c.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/libmaple/i2c.c b/libmaple/i2c.c index efe4dce..5fbafad 100644 --- a/libmaple/i2c.c +++ b/libmaple/i2c.c @@ -153,7 +153,7 @@ static void i2c_irq_handler(i2c_dev *dev) { * Master transmitter: write first byte to fill shift register. * We should get another TXE interrupt immediately to fill DR again. */ - if (msg->length != 1) + if (msg->length != 1) i2c_write(dev, msg->data[msg->xferred++]); } sr1 = sr2 = 0; @@ -325,7 +325,7 @@ static void i2c_bus_reset(const i2c_dev *dev) { void i2c_master_enable(i2c_dev *dev, uint32 flags) { #define I2C_CLK (PCLK1/1000000) #define STANDARD_CCR (PCLK1/(100000*2)) -#define STANDARD_TRISE (I2C_CLK+1) +#define STANDARD_TRISE (I2C_CLK+1) #define FAST_CCR (I2C_CLK/10) #define FAST_TRISE ((I2C_CLK*3)/10+1) /* Reset the bus. Clock out any hung slaves. */ @@ -340,9 +340,8 @@ void i2c_master_enable(i2c_dev *dev, uint32 flags) { /* I2C1 and I2C2 are fed from APB1, clocked at 36MHz */ i2c_set_input_clk(dev, I2C_CLK); - if(flags & I2C_FAST_MODE) { - - /* 400 kHz for fast mode, set DUTY and F/S bits */ + if(flags & I2C_FAST_MODE) { + /* 400 kHz for fast mode, set DUTY and F/S bits */ i2c_set_clk_control(dev, FAST_CCR|I2C_CCR_DUTY|I2C_CCR_FS); /* Set scl rise time, max rise time in fast mode: 300ns */ @@ -350,7 +349,7 @@ void i2c_master_enable(i2c_dev *dev, uint32 flags) { } else { - /* 100 kHz for standard mode */ + /* 100 kHz for standard mode */ i2c_set_clk_control(dev, STANDARD_CCR); /* Max rise time in standard mode: 1000 ns */ -- cgit v1.2.3 From 298661aa1c189400f27328fa77d5b3a10f1ba3ef Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Tue, 12 Apr 2011 15:50:18 -0400 Subject: Reverting some "volatile" -> "__io" changes. See https://github.com/leaflabs/libmaple/commit/c57d760676b97a0fc9cb51db99c8400bae2cb3b7#commitcomment-338822 --- libmaple/i2c.h | 2 +- libmaple/ring_buffer.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libmaple/i2c.h b/libmaple/i2c.h index 07ee260..394fd57 100644 --- a/libmaple/i2c.h +++ b/libmaple/i2c.h @@ -66,7 +66,7 @@ typedef struct i2c_dev { uint8 clk_line; uint8 ev_nvic_line; uint8 er_nvic_line; - __io uint8 state; + volatile uint8 state; uint16 msgs_left; i2c_msg *msg; } i2c_dev; diff --git a/libmaple/ring_buffer.h b/libmaple/ring_buffer.h index 04f6499..2536617 100644 --- a/libmaple/ring_buffer.h +++ b/libmaple/ring_buffer.h @@ -51,7 +51,7 @@ extern "C"{ * * One byte is left free to distinguish empty from full. */ typedef struct ring_buffer { - __io uint8 *buf; /**< Buffer items are stored into */ + volatile uint8 *buf; /**< Buffer items are stored into */ uint16 head; /**< Index of the next item to remove */ uint16 tail; /**< Index where the next item will get inserted */ uint16 size; /**< Buffer capacity minus one */ -- cgit v1.2.3 From 686b7d5a2d72e71bac76bd7ad9f4aae4e95039c5 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Tue, 12 Apr 2011 17:17:12 -0400 Subject: Fixing brain-damaged abs() implementation. --- wirish/wirish_math.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wirish/wirish_math.h b/wirish/wirish_math.h index fa544a9..f9062af 100644 --- a/wirish/wirish_math.h +++ b/wirish/wirish_math.h @@ -100,7 +100,7 @@ static inline long map(long value, long fromStart, long fromEnd, #ifdef abs #undef abs #endif -#define abs(x) (((x) > 0) ? (x) : -(unsigned)(x)) +#define abs(x) (((x) > 0) ? (x) : -(x)) /* Following are duplicate declarations (with Doxygen comments) for * some of the math.h functions; this is for the convenience of the -- cgit v1.2.3 From 08007e45924c15d4930f13c5f8e3bbe627c1a1bc Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Tue, 12 Apr 2011 17:25:12 -0400 Subject: Coding standard. Fixes for github .rst display. --- notes/coding_standard.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/notes/coding_standard.rst b/notes/coding_standard.rst index b0fa91b..f761db7 100644 --- a/notes/coding_standard.rst +++ b/notes/coding_standard.rst @@ -362,11 +362,11 @@ Documentation General Formatting ------------------ +.. highlight:: scheme + - Keep it 80-column clean. That means Emacs says the largest column number=79. You should turn on column number mode to help you out: -.. highlight:: scheme - (column-number-mode 1) You can get more help from lineker-mode: @@ -379,6 +379,8 @@ General Formatting (dolist (hook '(c-mode-hook c++-mode-hook)) (add-hook hook (lambda () (lineker-mode 1)))) +.. highlight:: cpp + Language Features and Compiler Extensions ----------------------------------------- @@ -391,10 +393,10 @@ Language Features and Compiler Extensions - Explicitly approved GCC extensions: - * asm volatile: + * ``asm volatile``: http://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html - * Nested functions: + * ``Nested functions``: http://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html - In wirish, generally be very conservative when using C++ features -- cgit v1.2.3 From cdd7bb7a13442160fea29e10ddc61402f56f4bd1 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Tue, 12 Apr 2011 01:07:59 -0400 Subject: Reverting "Rewrote Print class." This reverts commit 8bd3cebbee62e2dd7e961b149cc8bb0e980eaf88. --- docs/source/lang/api/serial.rst | 35 ++---- docs/source/lang/api/serialusb.rst | 35 ++---- wirish/Print.cpp | 245 ++++++++++++++++--------------------- wirish/Print.h | 87 +++++++------ 4 files changed, 167 insertions(+), 235 deletions(-) diff --git a/docs/source/lang/api/serial.rst b/docs/source/lang/api/serial.rst index 29c70a2..fadac34 100644 --- a/docs/source/lang/api/serial.rst +++ b/docs/source/lang/api/serial.rst @@ -116,34 +116,25 @@ means that you can use any of these functions on any of ``Serial1``, Print the argument's digits over the USART, in decimal format. -.. cpp:function:: HardwareSerial::print(long long n) +.. cpp:function:: HardwareSerial::print(long n) Print the argument's digits over the USART, in decimal format. Negative values will be prefixed with a ``'-'`` character. -.. cpp:function:: HardwareSerial::print(unsigned long long n) +.. cpp:function:: HardwareSerial::print(unsigned long n) Print the argument's digits over the USART, in decimal format. -.. _lang-serial-print-n-base: +.. cpp:function:: HardwareSerial::print(long n, int base) -.. cpp:function:: HardwareSerial::print(int n, int base) - - Print the digits of ``n`` over the USART, in base ``base``. The - ``base`` value 2 corresponds to binary, 8 to octal, 10 to decimal, - and 16 to hexadecimal (you can also use the symbolic constants - ``BIN``, ``OCT``, ``DEC``, ``HEX``). If ``base`` is 10, negative - values will be prefixed with a ``'-'`` character (otherwise, ``n`` - will be interpreted as an unsigned quantity). - -.. cpp:function:: HardwareSerial::print(long long n, int base) - - Same behavior as the above :ref:`print(int n, int base) - `, except with 64-bit values. + Print the digits of ``n`` over the USART, in base ``base`` (which + may be between 2 and 16). The ``base`` value 2 corresponds to + binary, 8 to octal, 10 to decimal, and 16 to hexadecimal. Negative + values will be prefixed with a ``'-'`` character. .. cpp:function:: HardwareSerial::print(double n) - Print ``n``, accurate to 6 digits after the decimal point. + Print ``n``, accurate to 2 digits after the decimal point. .. _lang-serial-println: @@ -167,19 +158,15 @@ means that you can use any of these functions on any of ``Serial1``, Like ``print(n)``, followed by ``"\r\n"``. -.. cpp:function:: HardwareSerial::println(long long n) +.. cpp:function:: HardwareSerial::println(long n) Like ``print(n)``, followed by ``"\r\n"``. -.. cpp:function:: HardwareSerial::println(unsigned long long n) +.. cpp:function:: HardwareSerial::println(unsigned long n) Like ``print(n)``, followed by ``"\r\n"``. -.. cpp:function:: HardwareSerial::println(int n, int base) - - Like ``print(n, b)``, followed by ``"\r\n"``. - -.. cpp:function:: HardwareSerial::println(long long n, int base) +.. cpp:function:: HardwareSerial::println(long n, int base) Like ``print(n, b)``, followed by ``"\r\n"``. diff --git a/docs/source/lang/api/serialusb.rst b/docs/source/lang/api/serialusb.rst index 4ddfa4a..ee7146e 100644 --- a/docs/source/lang/api/serialusb.rst +++ b/docs/source/lang/api/serialusb.rst @@ -109,35 +109,26 @@ world!")``. Print the argument's digits over the USB connection, in decimal format. -.. cpp:function:: USBSerial::print(long long n) +.. cpp:function:: USBSerial::print(long n) Print the argument's digits over the USB connection, in decimal format. Negative values will be prefixed with a ``'-'`` character. -.. cpp:function:: USBSerial::print(unsigned long long n) +.. cpp:function:: USBSerial::print(unsigned long n) Print the argument's digits over the USB connection, in decimal format. -.. _lang-serial-print-n-base: +.. cpp:function:: USBSerial::print(long n, int base) -.. cpp:function:: USBSerial::print(int n, int base) - - Print the digits of ``n`` over USB, in base ``base``. The ``base`` - value 2 corresponds to binary, 8 to octal, 10 to decimal, and 16 to - hexadecimal (you can also use the symbolic constants ``BIN``, - ``OCT``, ``DEC``, ``HEX``). If ``base`` is 10, negative values - will be prefixed with a ``'-'`` character (otherwise, ``n`` will be - interpreted as an unsigned quantity). - -.. cpp:function:: HardwareSerial::print(long long n, int base) - - Same behavior as the above :ref:`print(int n, int base) - `, except with 64-bit values. + Print the digits of ``n`` over the USB connection, in base ``base`` + (which may be between 2 and 16). The ``base`` value 2 corresponds + to binary, 8 to octal, 10 to decimal, and 16 to hexadecimal. + Negative values will be prefixed with a ``'-'`` character. .. cpp:function:: USBSerial::print(double n) - Print ``n``, accurate to 6 digits after the decimal point. + Print ``n``, accurate to 2 digits after the decimal point. .. _lang-serialusb-println: @@ -161,19 +152,15 @@ world!")``. Like ``print(n)``, followed by ``"\r\n"``. -.. cpp:function:: USBSerial::println(long long n) +.. cpp:function:: USBSerial::println(long n) Like ``print(n)``, followed by ``"\r\n"``. -.. cpp:function:: USBSerial::println(unsigned long long n) +.. cpp:function:: USBSerial::println(unsigned long n) Like ``print(n)``, followed by ``"\r\n"``. -.. cpp:function:: USBSerial::println(int n, int base) - - Like ``print(n, b)``, followed by ``"\r\n"``. - -.. cpp:function:: USBSerial::println(long long n, int base) +.. cpp:function:: USBSerial::println(long n, int base) Like ``print(n, b)``, followed by ``"\r\n"``. diff --git a/wirish/Print.cpp b/wirish/Print.cpp index 9c52321..c66ca61 100644 --- a/wirish/Print.cpp +++ b/wirish/Print.cpp @@ -1,127 +1,91 @@ -/****************************************************************************** - * The MIT License +/* + * Print.cpp - Base class that provides print() and println() + * Copyright (c) 2008 David A. Mellis. All right reserved. * - * Copyright (c) 2011 LeafLabs, LLC. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. * - * 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: + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA * - * 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. - *****************************************************************************/ + * Modified 23 November 2006 by David A. Mellis + */ +#include "wirish.h" #include "Print.h" -#include -#include -#include - -// We'll allocate character buffers of size INT_BUF_SIZE to hold the -// string representations of numbers; this value ensures that they're -// big enough to accomodate the biggest integral value + null byte. -// -// E.g., consider -(2^63-1) = -9223372036854775807, which is 20 -// characters long, including the minus sign. The other edge cases -// are similar. -// -// (Nonetheless, use snprintf everywhere, just in case of error). -#define INT_BUF_SIZE 21 - -// An IEEE-754 double buys you about 16 digits of precision; there's -// the possibility of minus signs, a decimal point, 'e+'/'e-', etc. -// While the Right Thing is to follow Steele and White, I'm just going -// to double what I consider a safe number of bytes and hope for the -// best. -#define DOUBLE_BUF_SIZE 40 - -static void fillBase(char *buf, int buf_size, int64 n, - uint8 n_real_bits, int base); -static void fillBinary(char *buf, int64 n, int start_bit); -static char baseToFmtSpec(int base); +//------------------------------ Public Methods ------------------------------- void Print::write(const char *str) { - for (const char *c = str; *c != '\0'; c++) { - write(*c); - } + while (*str) + write(*str++); } void Print::write(void *buffer, uint32 size) { - for (uint32 i = 0; i < size; i++) { - write(*((uint8*)buffer + i)); + uint8 *ch = (uint8*)buffer; + while (size--) { + write(*ch++); } } +void Print::print(uint8 b) { + this->write(b); +} + void Print::print(char c) { - print((uint8) c); + print((byte) c); } void Print::print(const char str[]) { write(str); } -void Print::print(uint8 b) { - write(b); -} - -void Print::print(int32 n) { - print(n, DEC); +void Print::print(int n) { + print((long) n); } -void Print::print(uint32 n) { - print((uint64) n); +void Print::print(unsigned int n) { + print((unsigned long) n); } -void Print::print(int64 n) { - print(n, DEC); -} - -void Print::print(uint64 n) { - char buf[INT_BUF_SIZE]; - snprintf(buf, INT_BUF_SIZE, "%llu", n); - write(buf); +void Print::print(long n) { + if (n < 0) { + print('-'); + n = -n; + } + printNumber(n, 10); } -void Print::print(int32 n, int base) { - // Worst case: sign bit set && base == BIN: 32 bytes for digits + - // 1 null (base == BIN means no minus sign). - char buf[33]; - fillBase(buf, sizeof(buf), (int64)n, 32, base); - write(buf); +void Print::print(unsigned long n) { + printNumber(n, 10); } -void Print::print(int64 n, int base) { - // As above, but now 64 bytes for bits + 1 null - char buf[65]; - fillBase(buf, sizeof(buf), n, 64, base); - write(buf); +void Print::print(long n, int base) { + if (base == 0) { + print((char) n); + } else if (base == 10) { + print(n); + } else { + printNumber(n, base); + } } void Print::print(double n) { - char buf[DOUBLE_BUF_SIZE]; - // This breaks strict compliance with the Arduino library behavior - // (which is equivalent to using "%.2f"), but that's really not - // enough. According to Stroustrup, "%f" without precision is - // equivalent to ".6f", which is much better. - snprintf(buf, DOUBLE_BUF_SIZE, "%f", n); - write(buf); + printFloat(n, 2); } void Print::println(void) { - print("\r\n"); + print('\r'); + print('\n'); } void Print::println(char c) { @@ -139,32 +103,27 @@ void Print::println(uint8 b) { println(); } -void Print::println(int32 n) { +void Print::println(int n) { print(n); println(); } -void Print::println(uint32 n) { +void Print::println(unsigned int n) { print(n); println(); } -void Print::println(int64 n) { +void Print::println(long n) { print(n); println(); } -void Print::println(uint64 n) { +void Print::println(unsigned long n) { print(n); println(); } -void Print::println(int32 n, int base) { - print(n, base); - println(); -} - -void Print::println(int64 n, int base) { +void Print::println(long n, int base) { print(n, base); println(); } @@ -174,54 +133,58 @@ void Print::println(double n) { println(); } -// -- Auxiliary functions ----------------------------------------------------- +//------------------------------ Private Methods ------------------------------ -static void fillBase(char *buf, int buf_size, int64 n, - uint8 n_real_bits, int base) { - if (base == BIN) { - fillBinary(buf, n, n_real_bits - 1); - } else { - char spec = baseToFmtSpec(base); - char fmt[5]; - - if (base == BYTE) - n = (uint8)n; - - if (n_real_bits == 32) { - snprintf(fmt, sizeof(fmt), "%%l%c", spec); - snprintf(buf, buf_size, fmt, (int32)n); - } else { - snprintf(fmt, sizeof(fmt), "%%ll%c", spec); - snprintf(buf, buf_size, fmt, n); - } +void Print::printNumber(unsigned long n, uint8 base) { + unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars. + unsigned long i = 0; + + if (n == 0) { + print('0'); + return; } + + while (n > 0) { + buf[i++] = n % base; + n /= base; + } + + for (; i > 0; i--) + print((char) (buf[i - 1] < 10 ? + '0' + buf[i - 1] : + 'A' + buf[i - 1] - 10)); } -// Assumes sizeof(buf) > start_bit. -static void fillBinary(char *buf, int64 n, int start_bit) { - int b = 0; // position in buf - int i = start_bit; // position in n's bits - while(!(n & (1 << i))) { - i--; +void Print::printFloat(double number, uint8 digits) { + // Handle negative numbers + if (number < 0.0) { + print('-'); + number = -number; } - for(; i >= 0; i--) { - buf[b++] = '0' + ((n >> i) & 0x1); + + // Round correctly so that print(1.999, 2) prints as "2.00" + double rounding = 0.5; + for (uint8 i=0; i 0) { + print("."); } - buf[b] = '\0'; -} - -static char baseToFmtSpec(int base) { - switch (base) { - case DEC: - return 'd'; - case HEX: - return 'x'; - case OCT: - return 'o'; - case BYTE: - return 'd'; - default: - // Shouldn't happen, but give a sensible default - return 'd'; + + // Extract digits from the remainder one at a time + while (digits-- > 0) { + remainder *= 10.0; + int toPrint = int(remainder); + print(toPrint); + remainder -= toPrint; } } diff --git a/wirish/Print.h b/wirish/Print.h index 4527948..dc21183 100644 --- a/wirish/Print.h +++ b/wirish/Print.h @@ -1,67 +1,62 @@ -/****************************************************************************** - * The MIT License +/* + * Print.h - Base class that provides print() and println() + * Copyright (c) 2008 David A. Mellis. All right reserved. * - * Copyright (c) 2011 LeafLabs, LLC. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. * - * 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: + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * 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. - *****************************************************************************/ + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA. + */ -#ifndef _PRINT_H_ -#define _PRINT_H_ +#ifndef Print_h +#define Print_h -#include "libmaple_types.h" +#include +#include // for size_t -#define DEC 10 -#define HEX 16 -#define OCT 8 -#define BIN 2 -#define BYTE 0 // yuck +#define DEC 10 +#define HEX 16 +#define OCT 8 +#define BIN 2 +#define BYTE 0 -class Print { +class Print +{ + private: + void printNumber(unsigned long, uint8); + void printFloat(double, uint8); public: virtual void write(uint8) = 0; virtual void write(const char *str); - virtual void write(void *buf, uint32 size); - + virtual void write(void *, uint32); void print(char); void print(const char[]); void print(uint8); - void print(int32); - void print(uint32); - void print(int64); - void print(uint64); - void print(int32, int); - void print(int64, int); + void print(int); + void print(unsigned int); + void print(long); + void print(unsigned long); + void print(long, int); void print(double); - void println(void); void println(char); void println(const char[]); void println(uint8); - void println(int32); - void println(uint32); - void println(int64); - void println(uint64); - void println(int32, int); - void println(int64, int); + void println(int); + void println(unsigned int); + void println(long); + void println(unsigned long); + void println(long, int); void println(double); }; -- cgit v1.2.3 From fc3126378e0c13b03b3c5dd886bebb2014878717 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Tue, 12 Apr 2011 01:13:52 -0400 Subject: Compromise Print implementation. The users really hated the code size requirements for an snprintf()-based Print implementation, but I really hated how bad the old implementation was. Revised version fixes bugs related to printing 64-bit values and has some improved behavior when it comes to printing doubles. Now, instead of happily printing garbage values when large doubles are printed, we try printing "" or "-" (depending on sign) when the argument is too big for the old strategy to accommodate. --- wirish/Print.cpp | 119 +++++++++++++++++++++++++++++++++++++++++++------------ wirish/Print.h | 40 +++++++++++-------- 2 files changed, 117 insertions(+), 42 deletions(-) diff --git a/wirish/Print.cpp b/wirish/Print.cpp index c66ca61..3d7e836 100644 --- a/wirish/Print.cpp +++ b/wirish/Print.cpp @@ -18,16 +18,38 @@ * 02110-1301 USA * * Modified 23 November 2006 by David A. Mellis + * Modified 12 April 2011 by Marti Bolivar */ +#include +#include + +#ifndef LLONG_MAX +/* + * Note: + * + * At time of writing (12 April 2011), the limits.h that came with the + * newlib we distributed didn't include LLONG_MAX. Because we're + * staying away from using templates (see /notes/coding_standard.rst, + * "Language Features and Compiler Extensions"), this value was + * copy-pasted from a println() of the value + * + * std::numeric_limits::max(). + */ +#define LLONG_MAX 9223372036854775807LL +#endif + #include "wirish.h" #include "Print.h" -//------------------------------ Public Methods ------------------------------- +/* + * Public methods + */ void Print::write(const char *str) { - while (*str) + while (*str) { write(*str++); + } } void Print::write(void *buffer, uint32 size) { @@ -42,7 +64,7 @@ void Print::print(uint8 b) { } void Print::print(char c) { - print((byte) c); + print((byte)c); } void Print::print(const char str[]) { @@ -50,14 +72,22 @@ void Print::print(const char str[]) { } void Print::print(int n) { - print((long) n); + print((long long)n); } void Print::print(unsigned int n) { - print((unsigned long) n); + print((unsigned long long)n); } void Print::print(long n) { + print((long long)n); +} + +void Print::print(unsigned long n) { + print((unsigned long long)n); +} + +void Print::print(long long n) { if (n < 0) { print('-'); n = -n; @@ -65,13 +95,13 @@ void Print::print(long n) { printNumber(n, 10); } -void Print::print(unsigned long n) { +void Print::print(unsigned long long n) { printNumber(n, 10); } -void Print::print(long n, int base) { +void Print::print(unsigned long long n, int base) { if (base == 0) { - print((char) n); + print((char)n); } else if (base == 10) { print(n); } else { @@ -114,16 +144,26 @@ void Print::println(unsigned int n) { } void Print::println(long n) { - print(n); + print((long long)n); println(); } void Print::println(unsigned long n) { + print((unsigned long long)n); + println(); +} + +void Print::println(long long n) { print(n); println(); } -void Print::println(long n, int base) { +void Print::println(unsigned long long n) { + print(n); + println(); +} + +void Print::println(unsigned long long n, int base) { print(n, base); println(); } @@ -133,10 +173,12 @@ void Print::println(double n) { println(); } -//------------------------------ Private Methods ------------------------------ +/* + * Private methods + */ -void Print::printNumber(unsigned long n, uint8 base) { - unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars. +void Print::printNumber(unsigned long long n, uint8 base) { + unsigned char buf[CHAR_BIT * sizeof(long long)]; unsigned long i = 0; if (n == 0) { @@ -149,30 +191,57 @@ void Print::printNumber(unsigned long n, uint8 base) { n /= base; } - for (; i > 0; i--) - print((char) (buf[i - 1] < 10 ? - '0' + buf[i - 1] : - 'A' + buf[i - 1] - 10)); + for (; i > 0; i--) { + print((char)(buf[i - 1] < 10 ? + '0' + buf[i - 1] : + 'A' + buf[i - 1] - 10)); + } } +/* According to snprintf(), + * + * nextafter((double)numeric_limits::max(), 0.0) ~= 9.22337e+18 + * + * This slightly smaller value was picked semi-arbitrarily. */ +#define LARGE_DOUBLE_TRESHOLD (9.1e18) + +/* THIS FUNCTION SHOULDN'T BE USED IF YOU NEED ACCURATE RESULTS. + * + * This implementation is meant to be simple and not occupy too much + * code size. However, printing floating point values accurately is a + * subtle task, best left to a well-tested library function. + * + * See Steele and White 2003 for more details: + * + * http://kurtstephens.com/files/p372-steele.pdf + */ void Print::printFloat(double number, uint8 digits) { + // Hackish fail-fast behavior for large-magnitude doubles + if (abs(number) >= LARGE_DOUBLE_TRESHOLD) { + if (number < 0.0) { + print('-'); + } + print(""); + return; + } + // Handle negative numbers if (number < 0.0) { print('-'); number = -number; } - // Round correctly so that print(1.999, 2) prints as "2.00" + // Simplistic rounding strategy so that e.g. print(1.999, 2) + // prints as "2.00" double rounding = 0.5; - for (uint8 i=0; i 0) { remainder *= 10.0; - int toPrint = int(remainder); - print(toPrint); - remainder -= toPrint; + int to_print = (int)remainder; + print(to_print); + remainder -= to_print; } } diff --git a/wirish/Print.h b/wirish/Print.h index dc21183..a4a93bf 100644 --- a/wirish/Print.h +++ b/wirish/Print.h @@ -16,29 +16,28 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA. + * + * Modified 12 April 2011 by Marti Bolivar */ -#ifndef Print_h -#define Print_h +#ifndef _PRINT_H_ +#define _PRINT_H_ #include -#include // for size_t -#define DEC 10 -#define HEX 16 -#define OCT 8 -#define BIN 2 -#define BYTE 0 +enum { + BYTE = 0, + BIN = 2, + OCT = 8, + DEC = 10, + HEX = 16 +}; -class Print -{ - private: - void printNumber(unsigned long, uint8); - void printFloat(double, uint8); - public: +class Print { +public: virtual void write(uint8) = 0; virtual void write(const char *str); - virtual void write(void *, uint32); + virtual void write(void*, uint32); void print(char); void print(const char[]); void print(uint8); @@ -46,7 +45,9 @@ class Print void print(unsigned int); void print(long); void print(unsigned long); - void print(long, int); + void print(long long); + void print(unsigned long long); + void print(unsigned long long, int); void print(double); void println(void); void println(char); @@ -56,8 +57,13 @@ class Print void println(unsigned int); void println(long); void println(unsigned long); - void println(long, int); + void println(long long); + void println(unsigned long long); + void println(unsigned long long, int); void println(double); +private: + void printNumber(unsigned long long, uint8); + void printFloat(double, uint8); }; #endif -- cgit v1.2.3 From 8aa66748fdfd682c5df45634c30a24be3f0984de Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Tue, 12 Apr 2011 17:48:59 -0400 Subject: Adding examples/test-print.cpp. This uses templates, which I don't like, but it's not going into the core library, so I'm okay with it for now. --- examples/test-print.cpp | 181 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 examples/test-print.cpp diff --git a/examples/test-print.cpp b/examples/test-print.cpp new file mode 100644 index 0000000..ff3c219 --- /dev/null +++ b/examples/test-print.cpp @@ -0,0 +1,181 @@ +/* + * print-test.cpp + * + * Tests the various Print methods. (For USBSerial; assuming that + * writing a single character works, this should generalize to + * HardwareSerial). + * + * This file is released into the public domain. + */ + +#include "wirish.h" +#undef min +#undef max + +// For snprintf() +#include +// The that comes with newlib is missing LLONG_MAX, etc. +#include + +using namespace std; + +#define BUF_SIZE 100 +char buf[BUF_SIZE]; + +void test_numbers(void); +void test_base_arithmetic(void); +void test_floating_point(void); + +void print_separator(void); + +void setup() { + while (!SerialUSB.available()) + continue; + SerialUSB.read(); +} + +void loop() { + SerialUSB.println("Testing Print methods."); + print_separator(); + + test_numbers(); + print_separator(); + + test_base_arithmetic(); + print_separator(); + + test_floating_point(); + print_separator(); + + SerialUSB.println("Test finished."); + while (true) { + continue; + } +} + +void test_numbers(void) { + SerialUSB.println("Numeric types:"); + + SerialUSB.println("unsigned char: "); + // prevent Print from treating it as an (extended) ASCII character: + SerialUSB.println((uint32)numeric_limits::max()); + + SerialUSB.print("int: "); + SerialUSB.print(numeric_limits::min()); + SerialUSB.print(" -- "); + SerialUSB.println(numeric_limits::max()); + + SerialUSB.print("unsigned int: "); + SerialUSB.print(numeric_limits::max()); + SerialUSB.println(); + + SerialUSB.print("long: "); + SerialUSB.print(numeric_limits::min()); + SerialUSB.print(" -- "); + SerialUSB.println(numeric_limits::max()); + + SerialUSB.print("long long: "); + SerialUSB.print(numeric_limits::min()); + SerialUSB.print(" -- "); + SerialUSB.println(numeric_limits::max()); + + SerialUSB.print("unsigned long long: "); + SerialUSB.println(numeric_limits::max()); +} + +void test_base_arithmetic(void) { + SerialUSB.println("Base arithmetic:"); + + SerialUSB.print("Binary: "); + SerialUSB.print(numeric_limits::max(), BIN); + SerialUSB.print(", "); + SerialUSB.println(numeric_limits::max(), BIN); + + SerialUSB.print("Octal: "); + SerialUSB.print(numeric_limits::max(), OCT); + SerialUSB.print(", "); + SerialUSB.println(numeric_limits::max(), OCT); + + SerialUSB.print("Decimal: "); + SerialUSB.print(numeric_limits::max(), DEC); + SerialUSB.print(", "); + SerialUSB.println(numeric_limits::max(), DEC); + + SerialUSB.print("Hexadecimal: "); + SerialUSB.print(numeric_limits::max(), HEX); + SerialUSB.print(", "); + SerialUSB.println(numeric_limits::max(), HEX); +} + +void test_floating_point(void) { + double dmax = numeric_limits::max(); + + SerialUSB.println("Floating point:"); + + SerialUSB.print("sizeof double: "); + SerialUSB.println(sizeof(double)); + SerialUSB.print("println(-5.67): "); + SerialUSB.println(-5.67); + SerialUSB.print("println((double)(LLONG_MAX - 10)): "); + SerialUSB.println((double)(numeric_limits::max() - 10)); + SerialUSB.print("println((double)(LLONG_MAX - 10)) from snprintf(): "); + snprintf(buf, BUF_SIZE, "%.2f", + (double)(numeric_limits::max() - 10)); + SerialUSB.println(buf); + SerialUSB.print("println((double)LLONG_MAX / 2): "); + SerialUSB.println((double)(numeric_limits::max()) / 2); + SerialUSB.print("println((double)LLONG_MAX / 2) from snprintf(): "); + snprintf(buf, BUF_SIZE, "%.2f", + (double)(numeric_limits::max()) / 2); + SerialUSB.println(buf); + SerialUSB.print("DBL_MAX: "); + SerialUSB.println(dmax); + SerialUSB.print("DBL_MAX from snprintf(): "); + snprintf(buf, BUF_SIZE, "%g", dmax); + SerialUSB.println(buf); + SerialUSB.print("-DBL_MAX / 2: "); + SerialUSB.println(-dmax / 2.0); + SerialUSB.print("-DBL_MAX / 2 from snprintf(): "); + snprintf(buf, BUF_SIZE, "%g", -dmax / 2.0); + SerialUSB.println(buf); + SerialUSB.print("Double epsilon, round error: "); + SerialUSB.print(numeric_limits::epsilon()); + SerialUSB.print(", "); + SerialUSB.println(numeric_limits::round_error()); + + SerialUSB.println(); + + float fmax = numeric_limits::max(); + + SerialUSB.print("sizeof float: "); + SerialUSB.println(sizeof(float)); + SerialUSB.print("println(-5.67f): "); + SerialUSB.println(-5.67f); + SerialUSB.print("Float max: "); + SerialUSB.println(fmax); + SerialUSB.print("Float epsilon, round error: "); + SerialUSB.print(numeric_limits::epsilon()); + SerialUSB.print(", "); + SerialUSB.println(numeric_limits::round_error()); +} + +void print_separator(void) { + SerialUSB.println(); + SerialUSB.println(" ** "); + SerialUSB.println(); +} + +// Force init to be called *first*, i.e. before static object allocation. +// Otherwise, statically allocated objects that need libmaple may fail. +__attribute__((constructor)) void premain() { + init(); +} + +int main(void) { + setup(); + + while (1) { + loop(); + } + return 0; +} -- cgit v1.2.3 From de528cc466b39ba05dca170c9a6ed7474c47fbcf Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Wed, 13 Apr 2011 15:43:59 -0400 Subject: Updating Maple Native pins for prototype C. --- wirish/boards/maple_native.cpp | 197 +++++++++++++++++++++-------------------- wirish/boards/maple_native.h | 22 ++--- 2 files changed, 110 insertions(+), 109 deletions(-) diff --git a/wirish/boards/maple_native.cpp b/wirish/boards/maple_native.cpp index 2813e91..adc9497 100644 --- a/wirish/boards/maple_native.cpp +++ b/wirish/boards/maple_native.cpp @@ -49,116 +49,117 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { {GPIOB, NULL, NULL, 13, 0, ADCx}, /* D3/PB13 */ {GPIOB, NULL, NULL, 14, 0, ADCx}, /* D4/PB14 */ {GPIOB, NULL, NULL, 15, 0, ADCx}, /* D5/PB15 */ - {GPIOC, NULL, ADC1, 0, 0, 10}, /* D6/PC0 */ - {GPIOC, NULL, ADC1, 1, 0, 11}, /* D7/PC1 */ - {GPIOC, NULL, ADC1, 2, 0, 12}, /* D8/PC2 */ - {GPIOC, NULL, ADC1, 3, 0, 13}, /* D9/PC3 */ - {GPIOC, NULL, ADC1, 4, 0, 14}, /* D10/PC4 */ - {GPIOC, NULL, ADC1, 5, 0, 15}, /* D11/PC5 */ - {GPIOC, TIMER8, NULL, 6, 1, ADCx}, /* D12/PC6 */ - {GPIOC, TIMER8, NULL, 7, 2, ADCx}, /* D13/PC7 */ - {GPIOC, TIMER8, NULL, 8, 3, ADCx}, /* D14/PC8 */ - {GPIOC, TIMER8, NULL, 9, 4, ADCx}, /* D15/PC9 */ - {GPIOC, NULL, NULL, 10, 0, ADCx}, /* D16/PC10 */ - {GPIOC, NULL, NULL, 11, 0, ADCx}, /* D17/PC11 */ - {GPIOC, NULL, NULL, 12, 0, ADCx}, /* D18/PC12 */ - {GPIOC, NULL, NULL, 13, 0, ADCx}, /* D19/PC13 */ - {GPIOC, NULL, NULL, 14, 0, ADCx}, /* D20/PC14 */ - {GPIOC, NULL, NULL, 15, 0, ADCx}, /* D21/PC15 */ - {GPIOA, TIMER1, NULL, 8, 1, ADCx}, /* D22/PA8 */ - {GPIOA, TIMER1, NULL, 9, 2, ADCx}, /* D23/PA9 */ - {GPIOA, TIMER1, NULL, 10, 3, ADCx}, /* D24/PA10 */ - {GPIOB, TIMER4, NULL, 9, 4, ADCx}, /* D25/PB9 */ + {GPIOG, NULL, NULL, 15, 0, ADCx}, /* D6/PG15 (BUT) */ + {GPIOC, NULL, ADC1, 0, 0, 10}, /* D7/PC0 */ + {GPIOC, NULL, ADC1, 1, 0, 11}, /* D8/PC1 */ + {GPIOC, NULL, ADC1, 2, 0, 12}, /* D9/PC2 */ + {GPIOC, NULL, ADC1, 3, 0, 13}, /* D10/PC3 */ + {GPIOC, NULL, ADC1, 4, 0, 14}, /* D11/PC4 */ + {GPIOC, NULL, ADC1, 5, 0, 15}, /* D12/PC5 */ + {GPIOC, TIMER8, NULL, 6, 1, ADCx}, /* D13/PC6 */ + {GPIOC, TIMER8, NULL, 7, 2, ADCx}, /* D14/PC7 */ + {GPIOC, TIMER8, NULL, 8, 3, ADCx}, /* D15/PC8 */ + {GPIOC, TIMER8, NULL, 9, 4, ADCx}, /* D16/PC9 */ + {GPIOC, NULL, NULL, 10, 0, ADCx}, /* D17/PC10 */ + {GPIOC, NULL, NULL, 11, 0, ADCx}, /* D18/PC11 */ + {GPIOC, NULL, NULL, 12, 0, ADCx}, /* D19/PC12 */ + {GPIOC, NULL, NULL, 13, 0, ADCx}, /* D20/PC13 */ + {GPIOC, NULL, NULL, 14, 0, ADCx}, /* D21/PC14 */ + {GPIOC, NULL, NULL, 15, 0, ADCx}, /* D22/PC15 (LED) */ + {GPIOA, TIMER1, NULL, 8, 1, ADCx}, /* D23/PA8 */ + {GPIOA, TIMER1, NULL, 9, 2, ADCx}, /* D24/PA9 */ + {GPIOA, TIMER1, NULL, 10, 3, ADCx}, /* D25/PA10 */ + {GPIOB, TIMER4, NULL, 9, 4, ADCx}, /* D26/PB9 */ /* Bottom header */ - /* Note: D{48, 49, 50} are also TIMER2_CH{2, 3, 4}, respectively. */ + /* Note: D{49, 50, 51} are also TIMER2_CH{2, 3, 4}, respectively. */ - {GPIOD, NULL, NULL, 2, 0, ADCx}, /* D26/PD2 */ - {GPIOD, NULL, NULL, 3, 0, ADCx}, /* D27/PD3 */ - {GPIOD, NULL, NULL, 6, 0, ADCx}, /* D28/PD6 */ - {GPIOG, NULL, NULL, 11, 0, ADCx}, /* D29/PG11 */ - {GPIOG, NULL, NULL, 12, 0, ADCx}, /* D30/PG12 */ - {GPIOG, NULL, NULL, 13, 0, ADCx}, /* D31/PG13 */ - {GPIOG, NULL, NULL, 14, 0, ADCx}, /* D32/PG14 */ - {GPIOG, NULL, NULL, 8, 0, ADCx}, /* D33/PG8 */ - {GPIOG, NULL, NULL, 7, 0, ADCx}, /* D34/PG7 */ - {GPIOG, NULL, NULL, 6, 0, ADCx}, /* D35/PG6 */ - {GPIOB, NULL, NULL, 5, 0, ADCx}, /* D36/PB5 */ - {GPIOB, TIMER4, NULL, 6, 1, ADCx}, /* D37/PB6 */ - {GPIOB, TIMER4, NULL, 7, 2, ADCx}, /* D38/PB7 */ - {GPIOF, NULL, ADC3, 6, 0, 4}, /* D39/PF6 */ - {GPIOF, NULL, ADC3, 7, 0, 5}, /* D40/PF7 */ - {GPIOF, NULL, ADC3, 8, 0, 6}, /* D41/PF8 */ - {GPIOF, NULL, ADC3, 9, 0, 7}, /* D42/PF9 */ - {GPIOF, NULL, ADC3, 10, 0, 8}, /* D43/PF10 */ - {GPIOF, NULL, NULL, 11, 0, ADCx}, /* D44/PF11 */ - {GPIOB, TIMER3, ADC1, 1, 4, 9}, /* D45/PB1 */ - {GPIOB, TIMER3, ADC1, 0, 3, 8}, /* D46/PB0 */ - {GPIOA, TIMER5, ADC1, 0, 1, 0}, /* D47/PA0 */ - {GPIOA, TIMER5, ADC1, 1, 2, 1}, /* D48/PA1 */ - {GPIOA, TIMER5, ADC1, 2, 3, 2}, /* D49/PA2 */ - {GPIOA, TIMER5, ADC1, 3, 4, 3}, /* D50/PA3 */ - {GPIOA, NULL, ADC1, 4, 0, 4}, /* D51/PA4 */ - {GPIOA, NULL, ADC1, 5, 0, 5}, /* D52/PA5 */ - {GPIOA, TIMER3, ADC1, 6, 1, 6}, /* D53/PA6 */ - {GPIOA, TIMER3, ADC1, 7, 2, 7}, /* D54/PA7 */ + {GPIOD, NULL, NULL, 2, 0, ADCx}, /* D27/PD2 */ + {GPIOD, NULL, NULL, 3, 0, ADCx}, /* D28/PD3 */ + {GPIOD, NULL, NULL, 6, 0, ADCx}, /* D29/PD6 */ + {GPIOG, NULL, NULL, 11, 0, ADCx}, /* D30/PG11 */ + {GPIOG, NULL, NULL, 12, 0, ADCx}, /* D31/PG12 */ + {GPIOG, NULL, NULL, 13, 0, ADCx}, /* D32/PG13 */ + {GPIOG, NULL, NULL, 14, 0, ADCx}, /* D33/PG14 */ + {GPIOG, NULL, NULL, 8, 0, ADCx}, /* D34/PG8 */ + {GPIOG, NULL, NULL, 7, 0, ADCx}, /* D35/PG7 */ + {GPIOG, NULL, NULL, 6, 0, ADCx}, /* D36/PG6 */ + {GPIOB, NULL, NULL, 5, 0, ADCx}, /* D37/PB5 */ + {GPIOB, TIMER4, NULL, 6, 1, ADCx}, /* D38/PB6 */ + {GPIOB, TIMER4, NULL, 7, 2, ADCx}, /* D39/PB7 */ + {GPIOF, NULL, ADC3, 6, 0, 4}, /* D40/PF6 */ + {GPIOF, NULL, ADC3, 7, 0, 5}, /* D41/PF7 */ + {GPIOF, NULL, ADC3, 8, 0, 6}, /* D42/PF8 */ + {GPIOF, NULL, ADC3, 9, 0, 7}, /* D43/PF9 */ + {GPIOF, NULL, ADC3, 10, 0, 8}, /* D44/PF10 */ + {GPIOF, NULL, NULL, 11, 0, ADCx}, /* D45/PF11 */ + {GPIOB, TIMER3, ADC1, 1, 4, 9}, /* D46/PB1 */ + {GPIOB, TIMER3, ADC1, 0, 3, 8}, /* D47/PB0 */ + {GPIOA, TIMER5, ADC1, 0, 1, 0}, /* D48/PA0 */ + {GPIOA, TIMER5, ADC1, 1, 2, 1}, /* D49/PA1 */ + {GPIOA, TIMER5, ADC1, 2, 3, 2}, /* D50/PA2 */ + {GPIOA, TIMER5, ADC1, 3, 4, 3}, /* D51/PA3 */ + {GPIOA, NULL, ADC1, 4, 0, 4}, /* D52/PA4 */ + {GPIOA, NULL, ADC1, 5, 0, 5}, /* D53/PA5 */ + {GPIOA, TIMER3, ADC1, 6, 1, 6}, /* D54/PA6 */ + {GPIOA, TIMER3, ADC1, 7, 2, 7}, /* D55/PA7 */ /* Right (triple) header */ - {GPIOF, NULL, NULL, 0, 0, ADCx}, /* D55/PF0 */ - {GPIOD, NULL, NULL, 11, 0, ADCx}, /* D56/PD11 */ - {GPIOD, NULL, NULL, 14, 0, ADCx}, /* D57/PD14 */ - {GPIOF, NULL, NULL, 1, 0, ADCx}, /* D58/PF1 */ - {GPIOD, NULL, NULL, 12, 0, ADCx}, /* D59/PD12 */ - {GPIOD, NULL, NULL, 15, 0, ADCx}, /* D60/PD15 */ - {GPIOF, NULL, NULL, 2, 0, ADCx}, /* D61/PF2 */ - {GPIOD, NULL, NULL, 13, 0, ADCx}, /* D62/PD13 */ - {GPIOD, NULL, NULL, 0, 0, ADCx}, /* D63/PD0 */ - {GPIOF, NULL, NULL, 3, 0, ADCx}, /* D64/PF3 */ - {GPIOE, NULL, NULL, 3, 0, ADCx}, /* D65/PE3 */ - {GPIOD, NULL, NULL, 1, 0, ADCx}, /* D66/PD1 */ - {GPIOF, NULL, NULL, 4, 0, ADCx}, /* D67/PF4 */ - {GPIOE, NULL, NULL, 4, 0, ADCx}, /* D68/PE4 */ - {GPIOE, NULL, NULL, 7, 0, ADCx}, /* D69/PE7 */ - {GPIOF, NULL, NULL, 5, 0, ADCx}, /* D70/PF5 */ - {GPIOE, NULL, NULL, 5, 0, ADCx}, /* D71/PE5 */ - {GPIOE, NULL, NULL, 8, 0, ADCx}, /* D72/PE8 */ - {GPIOF, NULL, NULL, 12, 0, ADCx}, /* D73/PF12 */ - {GPIOE, NULL, NULL, 6, 0, ADCx}, /* D74/PE6 */ - {GPIOE, NULL, NULL, 9, 0, ADCx}, /* D75/PE9 */ - {GPIOF, NULL, NULL, 13, 0, ADCx}, /* D76/PF13 */ - {GPIOE, NULL, NULL, 10, 0, ADCx}, /* D77/PE10 */ - {GPIOF, NULL, NULL, 14, 0, ADCx}, /* D78/PF14 */ - {GPIOG, NULL, NULL, 9, 0, ADCx}, /* D79/PG9 */ - {GPIOE, NULL, NULL, 11, 0, ADCx}, /* D80/PE11 */ - {GPIOF, NULL, NULL, 15, 0, ADCx}, /* D81/PF15 */ - {GPIOG, NULL, NULL, 10, 0, ADCx}, /* D82/PG10 */ - {GPIOE, NULL, NULL, 12, 0, ADCx}, /* D83/PE12 */ - {GPIOG, NULL, NULL, 0, 0, ADCx}, /* D84/PG0 */ - {GPIOD, NULL, NULL, 5, 0, ADCx}, /* D85/PD5 */ - {GPIOE, NULL, NULL, 13, 0, ADCx}, /* D86/PE13 */ - {GPIOG, NULL, NULL, 1, 0, ADCx}, /* D87/PG1 */ - {GPIOD, NULL, NULL, 4, 0, ADCx}, /* D88/PD4 */ - {GPIOE, NULL, NULL, 14, 0, ADCx}, /* D89/PE14 */ - {GPIOG, NULL, NULL, 2, 0, ADCx}, /* D90/PG2 */ - {GPIOE, NULL, NULL, 1, 0, ADCx}, /* D91/PE1 */ - {GPIOE, NULL, NULL, 15, 0, ADCx}, /* D92/PE15 */ - {GPIOG, NULL, NULL, 3, 0, ADCx}, /* D93/PG3 */ - {GPIOE, NULL, NULL, 0, 0, ADCx}, /* D94/PE0 */ - {GPIOD, NULL, NULL, 8, 0, ADCx}, /* D95/PD8 */ - {GPIOG, NULL, NULL, 4, 0, ADCx}, /* D96/PG4 */ - {GPIOD, NULL, NULL, 9, 0, ADCx}, /* D97/PD9 */ - {GPIOG, NULL, NULL, 5, 0, ADCx}, /* D98/PG5 */ - {GPIOD, NULL, NULL, 10, 0, ADCx} /* D99/PD10 */ + {GPIOF, NULL, NULL, 0, 0, ADCx}, /* D56/PF0 */ + {GPIOD, NULL, NULL, 11, 0, ADCx}, /* D57/PD11 */ + {GPIOD, NULL, NULL, 14, 0, ADCx}, /* D58/PD14 */ + {GPIOF, NULL, NULL, 1, 0, ADCx}, /* D59/PF1 */ + {GPIOD, NULL, NULL, 12, 0, ADCx}, /* D60/PD12 */ + {GPIOD, NULL, NULL, 15, 0, ADCx}, /* D61/PD15 */ + {GPIOF, NULL, NULL, 2, 0, ADCx}, /* D62/PF2 */ + {GPIOD, NULL, NULL, 13, 0, ADCx}, /* D63/PD13 */ + {GPIOD, NULL, NULL, 0, 0, ADCx}, /* D64/PD0 */ + {GPIOF, NULL, NULL, 3, 0, ADCx}, /* D65/PF3 */ + {GPIOE, NULL, NULL, 3, 0, ADCx}, /* D66/PE3 */ + {GPIOD, NULL, NULL, 1, 0, ADCx}, /* D67/PD1 */ + {GPIOF, NULL, NULL, 4, 0, ADCx}, /* D68/PF4 */ + {GPIOE, NULL, NULL, 4, 0, ADCx}, /* D69/PE4 */ + {GPIOE, NULL, NULL, 7, 0, ADCx}, /* D70/PE7 */ + {GPIOF, NULL, NULL, 5, 0, ADCx}, /* D71/PF5 */ + {GPIOE, NULL, NULL, 5, 0, ADCx}, /* D72/PE5 */ + {GPIOE, NULL, NULL, 8, 0, ADCx}, /* D73/PE8 */ + {GPIOF, NULL, NULL, 12, 0, ADCx}, /* D74/PF12 */ + {GPIOE, NULL, NULL, 6, 0, ADCx}, /* D75/PE6 */ + {GPIOE, NULL, NULL, 9, 0, ADCx}, /* D76/PE9 */ + {GPIOF, NULL, NULL, 13, 0, ADCx}, /* D77/PF13 */ + {GPIOE, NULL, NULL, 10, 0, ADCx}, /* D78/PE10 */ + {GPIOF, NULL, NULL, 14, 0, ADCx}, /* D79/PF14 */ + {GPIOG, NULL, NULL, 9, 0, ADCx}, /* D80/PG9 */ + {GPIOE, NULL, NULL, 11, 0, ADCx}, /* D81/PE11 */ + {GPIOF, NULL, NULL, 15, 0, ADCx}, /* D82/PF15 */ + {GPIOG, NULL, NULL, 10, 0, ADCx}, /* D83/PG10 */ + {GPIOE, NULL, NULL, 12, 0, ADCx}, /* D84/PE12 */ + {GPIOG, NULL, NULL, 0, 0, ADCx}, /* D85/PG0 */ + {GPIOD, NULL, NULL, 5, 0, ADCx}, /* D86/PD5 */ + {GPIOE, NULL, NULL, 13, 0, ADCx}, /* D87/PE13 */ + {GPIOG, NULL, NULL, 1, 0, ADCx}, /* D88/PG1 */ + {GPIOD, NULL, NULL, 4, 0, ADCx}, /* D89/PD4 */ + {GPIOE, NULL, NULL, 14, 0, ADCx}, /* D90/PE14 */ + {GPIOG, NULL, NULL, 2, 0, ADCx}, /* D91/PG2 */ + {GPIOE, NULL, NULL, 1, 0, ADCx}, /* D92/PE1 */ + {GPIOE, NULL, NULL, 15, 0, ADCx}, /* D93/PE15 */ + {GPIOG, NULL, NULL, 3, 0, ADCx}, /* D94/PG3 */ + {GPIOE, NULL, NULL, 0, 0, ADCx}, /* D95/PE0 */ + {GPIOD, NULL, NULL, 8, 0, ADCx}, /* D96/PD8 */ + {GPIOG, NULL, NULL, 4, 0, ADCx}, /* D97/PG4 */ + {GPIOD, NULL, NULL, 9, 0, ADCx}, /* D98/PD9 */ + {GPIOG, NULL, NULL, 5, 0, ADCx}, /* D99/PG5 */ + {GPIOD, NULL, NULL, 10, 0, ADCx} /* D100/PD10 */ }; extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { - 12, 13, 14, 15, 22, 23, 24, 25, 37, 38, 45, 46, 47, 48, 49, 50, 53, 54 + 13, 14, 15, 16, 23, 24, 25, 26, 38, 39, 46, 47, 48, 49, 50, 51, 54, 54 }; extern const uint8 boardADCPins[BOARD_NR_ADC_PINS] __FLASH__ = { - 6, 7, 8, 9, 10, 11, 39, 40, 41, 42, 43, 45, 46, 47, 48, 49, 50, 51, 52, 53, - 54 + 7, 8, 9, 10, 11, 12, 40, 41, 42, 43, 44, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55 }; /* FIXME! see comment by BOARD_NR_USED_PINS in maple_native.h */ diff --git a/wirish/boards/maple_native.h b/wirish/boards/maple_native.h index 4e3ee82..10dafa6 100644 --- a/wirish/boards/maple_native.h +++ b/wirish/boards/maple_native.h @@ -43,22 +43,22 @@ #define CYCLES_PER_MICROSECOND 72 #define SYSTICK_RELOAD_VAL 71999 -#define BOARD_LED_PIN 21 -#define BOARD_BUTTON_PIN 18 +#define BOARD_LED_PIN 22 +#define BOARD_BUTTON_PIN 6 #define BOARD_NR_USARTS 5 -#define BOARD_USART1_TX_PIN 25 -#define BOARD_USART1_RX_PIN 26 -#define BOARD_USART2_TX_PIN 51 -#define BOARD_USART2_RX_PIN 52 +#define BOARD_USART1_TX_PIN 26 +#define BOARD_USART1_RX_PIN 27 +#define BOARD_USART2_TX_PIN 52 +#define BOARD_USART2_RX_PIN 53 #define BOARD_USART3_TX_PIN 0 #define BOARD_USART3_RX_PIN 1 -#define BOARD_UART4_TX_PIN 18 -#define BOARD_UART4_RX_PIN 19 -#define BOARD_UART5_TX_PIN 20 -#define BOARD_UART5_RX_PIN 28 +#define BOARD_UART4_TX_PIN 19 +#define BOARD_UART4_RX_PIN 20 +#define BOARD_UART5_TX_PIN 21 +#define BOARD_UART5_RX_PIN 29 -#define BOARD_NR_GPIO_PINS 100 +#define BOARD_NR_GPIO_PINS 101 #define BOARD_NR_PWM_PINS 18 #define BOARD_NR_ADC_PINS 21 /* FIXME! this isn't true at all; almost all of the triple header pins -- cgit v1.2.3 From bc2f4fe005d4ed00ca14f42850701f64265d50ba Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Thu, 14 Apr 2011 13:52:32 -0400 Subject: Moving external interrupts docs to "Hardware Peripherals" index section. --- docs/source/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/index.rst b/docs/source/index.rst index de71411..1d1a5be 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -34,7 +34,6 @@ Have fun! Libraries Arduino Compatibility libmaple - External Interrupts Bootloader Troubleshooting Known Problems @@ -48,6 +47,7 @@ Have fun! :maxdepth: 1 adc + external-interrupts gpio i2c jtag -- cgit v1.2.3 From 7b43ce42bdf590509c18aecdc1a001477be8585f Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Thu, 14 Apr 2011 14:00:47 -0400 Subject: i2c cleanups. Whitespace and column width changes only. --- libmaple/i2c.c | 55 +++++++++++++------------ libmaple/i2c.h | 126 ++++++++++++++++++++++++++++----------------------------- 2 files changed, 90 insertions(+), 91 deletions(-) diff --git a/libmaple/i2c.c b/libmaple/i2c.c index 5fbafad..3a1082a 100644 --- a/libmaple/i2c.c +++ b/libmaple/i2c.c @@ -1,29 +1,32 @@ -/* ***************************************************************************** +/****************************************************************************** * The MIT License * * Copyright (c) 2010 Perry Hung. * - * 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 + * 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 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. - * ****************************************************************************/ + * 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. + *****************************************************************************/ /** - * @brief + * @file i2c.c + * @brief Inter-Integrated Circuit (I2C) support. */ #include "libmaple.h" @@ -150,8 +153,9 @@ static void i2c_irq_handler(i2c_dev *dev) { } } else { /* - * Master transmitter: write first byte to fill shift register. - * We should get another TXE interrupt immediately to fill DR again. + * Master transmitter: write first byte to fill shift + * register. We should get another TXE interrupt + * immediately to fill DR again. */ if (msg->length != 1) i2c_write(dev, msg->data[msg->xferred++]); @@ -206,9 +210,10 @@ static void i2c_irq_handler(i2c_dev *dev) { i2c_stop_condition(dev); /* - * Turn off event interrupts to keep BTF from firing until the end - * of the stop condition. Why on earth they didn't have a start/stop - * condition request clear BTF is beyond me. + * Turn off event interrupts to keep BTF from firing until + * the end of the stop condition. Why on earth they didn't + * have a start/stop condition request clear BTF is beyond + * me. */ i2c_disable_irq(dev, I2C_IRQ_EVENT); leave_big_crumb(STOP_SENT, 0, 0); @@ -395,7 +400,6 @@ void i2c_master_enable(i2c_dev *dev, uint32 flags) { i2c_peripheral_enable(dev); } - int32 i2c_master_xfer(i2c_dev *dev, i2c_msg *msgs, uint16 num) { int32 rc; @@ -431,8 +435,3 @@ static inline int32 wait_for_state_change(i2c_dev *dev, i2c_state state) { } } } - - - - - diff --git a/libmaple/i2c.h b/libmaple/i2c.h index 394fd57..27e24b2 100644 --- a/libmaple/i2c.h +++ b/libmaple/i2c.h @@ -1,29 +1,32 @@ -/* ***************************************************************************** +/****************************************************************************** * The MIT License * * Copyright (c) 2010 Perry Hung. * - * 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 + * 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 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. - * ****************************************************************************/ + * 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. + *****************************************************************************/ /** - * @brief libmaple i2c header + * @file i2c.h + * @brief Inter-Integrated Circuit (I2C) peripheral support */ #ifndef _I2C_H_ @@ -78,57 +81,57 @@ extern i2c_dev* const I2C2; #define I2C2_BASE (i2c_reg_map*)0x40005800 /* i2c enable options */ -#define I2C_FAST_MODE 0x1 // 400 khz -#define I2C_DUTY_16_9 0x2 // 16/9 duty ratio +#define I2C_FAST_MODE 0x1 // 400 khz +#define I2C_DUTY_16_9 0x2 // 16/9 duty ratio /* Control register 1 bits */ -#define I2C_CR1_SWRST BIT(15) // Software reset -#define I2C_CR1_ALERT BIT(13) // SMBus alert -#define I2C_CR1_PEC BIT(12) // Packet error checking -#define I2C_CR1_POS BIT(11) // Acknowledge/PEC position -#define I2C_CR1_ACK BIT(10) // Acknowledge enable -#define I2C_CR1_START BIT(8) // Start generation -#define I2C_CR1_STOP BIT(9) // Stop generation -#define I2C_CR1_PE BIT(0) // Peripheral Enable +#define I2C_CR1_SWRST BIT(15) // Software reset +#define I2C_CR1_ALERT BIT(13) // SMBus alert +#define I2C_CR1_PEC BIT(12) // Packet error checking +#define I2C_CR1_POS BIT(11) // Acknowledge/PEC position +#define I2C_CR1_ACK BIT(10) // Acknowledge enable +#define I2C_CR1_START BIT(8) // Start generation +#define I2C_CR1_STOP BIT(9) // Stop generation +#define I2C_CR1_PE BIT(0) // Peripheral Enable /* Control register 2 bits */ -#define I2C_CR2_LAST BIT(12) // DMA last transfer -#define I2C_CR2_DMAEN BIT(11) // DMA requests enable -#define I2C_CR2_ITBUFEN BIT(10) // Buffer interrupt enable -#define I2C_CR2_ITEVTEN BIT(9) // Event interupt enable -#define I2C_CR2_ITERREN BIT(8) // Error interupt enable -#define I2C_CR2_FREQ 0xFFF // Peripheral input frequency +#define I2C_CR2_LAST BIT(12) // DMA last transfer +#define I2C_CR2_DMAEN BIT(11) // DMA requests enable +#define I2C_CR2_ITBUFEN BIT(10) // Buffer interrupt enable +#define I2C_CR2_ITEVTEN BIT(9) // Event interupt enable +#define I2C_CR2_ITERREN BIT(8) // Error interupt enable +#define I2C_CR2_FREQ 0xFFF // Peripheral input frequency /* Clock control register bits */ -#define I2C_CCR_FS BIT(15) // Fast mode selection -#define I2C_CCR_DUTY BIT(14) // 16/9 duty ratio -#define I2C_CCR_CCR 0xFFF // Clock control bits - -/* Status register 1 bits */ -#define I2C_SR1_SB BIT(0) // Start bit -#define I2C_SR1_ADDR BIT(1) // Address sent/matched -#define I2C_SR1_BTF BIT(2) // Byte transfer finished -#define I2C_SR1_ADD10 BIT(3) // 10-bit header sent -#define I2C_SR1_STOPF BIT(4) // Stop detection -#define I2C_SR1_RXNE BIT(6) // Data register not empty -#define I2C_SR1_TXE BIT(7) // Data register empty -#define I2C_SR1_BERR BIT(8) // Bus error -#define I2C_SR1_ARLO BIT(9) // Arbitration lost -#define I2C_SR1_AF BIT(10) // Acknowledge failure -#define I2C_SR1_OVR BIT(11) // Overrun/underrun -#define I2C_SR1_PECERR BIT(12) // PEC Error in reception -#define I2C_SR1_TIMEOUT BIT(14) // Timeout or Tlow error -#define I2C_SR1_SMBALERT BIT(15) // SMBus alert +#define I2C_CCR_FS BIT(15) // Fast mode selection +#define I2C_CCR_DUTY BIT(14) // 16/9 duty ratio +#define I2C_CCR_CCR 0xFFF // Clock control bits + +/* Status register 1 bits */ +#define I2C_SR1_SB BIT(0) // Start bit +#define I2C_SR1_ADDR BIT(1) // Address sent/matched +#define I2C_SR1_BTF BIT(2) // Byte transfer finished +#define I2C_SR1_ADD10 BIT(3) // 10-bit header sent +#define I2C_SR1_STOPF BIT(4) // Stop detection +#define I2C_SR1_RXNE BIT(6) // Data register not empty +#define I2C_SR1_TXE BIT(7) // Data register empty +#define I2C_SR1_BERR BIT(8) // Bus error +#define I2C_SR1_ARLO BIT(9) // Arbitration lost +#define I2C_SR1_AF BIT(10) // Acknowledge failure +#define I2C_SR1_OVR BIT(11) // Overrun/underrun +#define I2C_SR1_PECERR BIT(12) // PEC Error in reception +#define I2C_SR1_TIMEOUT BIT(14) // Timeout or Tlow error +#define I2C_SR1_SMBALERT BIT(15) // SMBus alert /* Status register 2 bits */ -#define I2C_SR2_MSL BIT(0) // Master/slave -#define I2C_SR2_BUSY BIT(1) // Bus busy -#define I2C_SR2_TRA BIT(2) // Transmitter/receiver -#define I2C_SR2_GENCALL BIT(4) // General call address -#define I2C_SR2_SMBDEFAULT BIT(5) // SMBus device default address -#define I2C_SR2_SMBHOST BIT(6) // SMBus host header -#define I2C_SR2_DUALF BIT(7) // Dual flag -#define I2C_SR2_PEC 0xFF00 // Packet error checking register +#define I2C_SR2_MSL BIT(0) // Master/slave +#define I2C_SR2_BUSY BIT(1) // Bus busy +#define I2C_SR2_TRA BIT(2) // Transmitter/receiver +#define I2C_SR2_GENCALL BIT(4) // General call address +#define I2C_SR2_SMBDEFAULT BIT(5) // SMBus device default address +#define I2C_SR2_SMBHOST BIT(6) // SMBus host header +#define I2C_SR2_DUALF BIT(7) // Dual flag +#define I2C_SR2_PEC 0xFF00 // Packet error checking register #ifdef __cplusplus extern "C" { @@ -166,7 +169,6 @@ static inline void i2c_write(i2c_dev *dev, uint8 byte) { dev->regs->DR = byte; } - /** * @brief Set input clock frequency, in mhz * @param dev i2c @@ -179,7 +181,6 @@ static inline void i2c_set_input_clk(i2c_dev *dev, uint32 freq) { dev->regs->CR2 = freq; } - /** * @brief Set i2c clock control register. See RM008 * @param dev i2c device @@ -257,4 +258,3 @@ static inline void i2c_disable_ack(i2c_dev *dev) { #endif #endif - -- cgit v1.2.3 From 351f9a097fb8e005e9465a8a883b2f063e5c5160 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Thu, 14 Apr 2011 14:28:23 -0400 Subject: Ancillary file cleanups. --- README | 32 ++-- TODO | 56 +------ support/codeblocks/libmaple.cbp | 300 ------------------------------------ support/codeblocks/program_flash.sh | 4 - support/codeblocks/program_ram.sh | 4 - support/gdb/gpio.gdb | 12 -- support/gdb/gpio/gpio.gdb | 12 ++ support/gdb/i2c/test.gdb | 112 ++++++++++++++ test.gdb | 112 -------------- 9 files changed, 141 insertions(+), 503 deletions(-) delete mode 100644 support/codeblocks/libmaple.cbp delete mode 100755 support/codeblocks/program_flash.sh delete mode 100755 support/codeblocks/program_ram.sh delete mode 100644 support/gdb/gpio.gdb create mode 100644 support/gdb/gpio/gpio.gdb create mode 100644 support/gdb/i2c/test.gdb delete mode 100644 test.gdb diff --git a/README b/README index f37999b..6e4c400 100644 --- a/README +++ b/README @@ -12,21 +12,25 @@ The latest version of this repository can be found here: http://github.com/leaflabs/libmaple -Instructions to Compile for ARM Targets +General information ------------------------------------------------------------------------------ -A HOWTO is available in the "Unix Toolchain Quickstart" guide at: +A HOWTO on setting up this library for use in a Unix environment is +available in our online HTML documentation: http://leaflabs.com/docs/unix-toolchain.html -HTML documentation for this repository is automatically generated from -the source code and the files under the top-level /docs/ directory. -It is available online at: +The HTML docs for this repository are automatically generated from the +source code and the files under the top-level /docs/ directory. For +more information, see /docs/README. - http://leaflabs.com/docs/ +Our bugtracker is available at: -(For more information on how this documentation is generated, see -/docs/README). + http://code.google.com/p/leaflabs/issues/list + +For changes that block official releases, see our wiki: + + http://wiki.leaflabs.com/index.php?title=Blocking_Changes Instructions to Create a Library ------------------------------------------------------------------------------ @@ -93,10 +97,7 @@ Repository Layout /notes/ - Unstructured text notes that may be useful. The 45-maple.rules - udev file can be placed in /etc/udev/rules.d/ on compatible Linux - machines to allow non-root access to the Maple USB device for - uploading. + Unstructured text notes that may be useful. /README/ @@ -106,7 +107,6 @@ Repository Layout Support files and scripts for various purposes. - codeblocks/ [OBSOLETE] Config files for the Code::Blocks IDE. gdb/ GDB scripts. ld/ Linker scripts. make/ Additional scripts used by the top-level Makefile. @@ -114,12 +114,6 @@ Repository Layout scripts/ Miscellany. stm32loader.py Script for uploading via the built-in USART bootloader. -TODO - - Various undone tasks. Also see our bugtracker at - - http://code.google.com/p/leaflabs/issues/list - /wirish/ Extra wrappers and functionality around the lower level code in diff --git a/TODO b/TODO index af8ef80..7c2f6e8 100644 --- a/TODO +++ b/TODO @@ -1,55 +1,7 @@ -Quick TODO -------------------------------------------------------------------- +Bugtracker: -- write language unit test -- more maple-specific example programs -- maple mini serial bootloader HOWTO -- maple and mini jtag HOWTO +http://code.google.com/p/leaflabs/issues/list -Peripherals ------------------------------------------------------------------- - -- I2C wrap up -- SPI wrap up - -Arduino Library functions to port (these are LGPL) ---------------------------- - -EEPROM: - functions: - uint8 read(int) - void write(int, uint8) - -Firmata: - edit Firmata.h for capabilities - -Matrix: - soft spi port stuff - -SoftwareSerial: - clockCyclesToMicroseconds(int) - -Sprite: - all good? - -LiquidCrystal: - timing on soft serial send() commands - -Stepper: - requires millis() - -Wire: - reimplementation of the utility/twi.{c/h} code: - void twi_init(void); - void twi_setAddress(uint8_t); - uint8_t twi_readFrom(uint8_t, uint8_t*, uint8_t); - uint8_t twi_writeTo(uint8_t, uint8_t*, uint8_t, uint8_t); - uint8_t twi_transmit(uint8_t*, uint8_t); - void twi_attachSlaveRxEvent( void (*)(uint8_t*, int) ); - void twi_attachSlaveTxEvent( void (*)(void) ); - void twi_reply(uint8_t); - void twi_stop(void); - void twi_releaseBus(void); - -Ethernet: - ho baby... - uses avr/interrupt.h - reimplement utility/spi stuff +Blocking changes for official releases: +http://wiki.leaflabs.com/index.php?title=Blocking_Changes diff --git a/support/codeblocks/libmaple.cbp b/support/codeblocks/libmaple.cbp deleted file mode 100644 index 4766275..0000000 --- a/support/codeblocks/libmaple.cbp +++ /dev/null @@ -1,300 +0,0 @@ - - - - - - diff --git a/support/codeblocks/program_flash.sh b/support/codeblocks/program_flash.sh deleted file mode 100755 index 9dfe9f1..0000000 --- a/support/codeblocks/program_flash.sh +++ /dev/null @@ -1,4 +0,0 @@ -#/usr/bin/env sh - -cd ../.. -make MAPLE_TARGET=flash install diff --git a/support/codeblocks/program_ram.sh b/support/codeblocks/program_ram.sh deleted file mode 100755 index 55fe73d..0000000 --- a/support/codeblocks/program_ram.sh +++ /dev/null @@ -1,4 +0,0 @@ -#/usr/bin/env sh - -cd ../.. -make MAPLE_TARGET=ram install diff --git a/support/gdb/gpio.gdb b/support/gdb/gpio.gdb deleted file mode 100644 index 4376cfd..0000000 --- a/support/gdb/gpio.gdb +++ /dev/null @@ -1,12 +0,0 @@ -set print pretty on - -print "GPIOA registers:" -p/x *GPIOA->regs -print "GPIOB registers:" -p/x *GPIOB->regs -print "GPIOC registers:" -p/x *GPIOC->regs -print "GPIOD registers:" -p/x *GPIOD->regs -print "AFIO registers:" -p/x *(struct afio_reg_map*)0x40010000 diff --git a/support/gdb/gpio/gpio.gdb b/support/gdb/gpio/gpio.gdb new file mode 100644 index 0000000..4376cfd --- /dev/null +++ b/support/gdb/gpio/gpio.gdb @@ -0,0 +1,12 @@ +set print pretty on + +print "GPIOA registers:" +p/x *GPIOA->regs +print "GPIOB registers:" +p/x *GPIOB->regs +print "GPIOC registers:" +p/x *GPIOC->regs +print "GPIOD registers:" +p/x *GPIOD->regs +print "AFIO registers:" +p/x *(struct afio_reg_map*)0x40010000 diff --git a/support/gdb/i2c/test.gdb b/support/gdb/i2c/test.gdb new file mode 100644 index 0000000..8b71320 --- /dev/null +++ b/support/gdb/i2c/test.gdb @@ -0,0 +1,112 @@ +define i2c_sr1_flags +set $s = $arg0 +printf "SR1: " + +if (($s & (1 << 15))) + printf "SMBALERT " +end + +if (($s & (1 << 14))) + printf "TIMEOUT " +end + +if (($s & (1 << 12))) + printf "PECERR " +end + +if (($s & (1 << 11))) + printf "OVR " +end + +if (($s & (1 << 10))) + printf "AF " +end + +if (($s & (1 << 9))) + printf "ARLO " +end + +if (($s & (1 << 8))) + printf "BERR " +end + +if (($s & (1 << 7))) + printf "TXE " +end + +if (($s & (1 << 6))) + printf "RXNE " +end + +if (($s & (1 << 4))) + printf "STOPF " +end + +if (($s & (1 << 3))) + printf "ADD10 " +end + +if (($s & (1 << 2))) + printf "BTF " +end + +if (($s & (1 << 1))) + printf "ADDR " +end + +if (($s & (1 << 0))) + printf "SB " +end +end + +define i2c_sr2_flags +set $s = $arg0 +printf "SR2: " + +if (($s & (1 << 7))) + printf "DUALF " +end + +if (($s & (1 << 6))) + printf "SMBHOST " +end + +if (($s & (1 << 5))) + printf "SMBDEFAULT " +end + +if (($s & (1 << 4))) + printf "GENCALL " +end + + +if (($s & (1 << 2))) + printf "TRA " +end + +if (($s & (1 << 1))) + printf "BUSY " +end + +if (($s & (1 << 0))) + printf "MSL " +end + +end + +define pbc +set $c = crumbs +while ($c->event) + if ($c->event != 0) + printf "Event: %d ", $c->event + if ($c->event == 1) + i2c_sr1_flags $c->sr1 + printf "\t" + i2c_sr2_flags $c->sr2 + end + printf "\n" + end + set $c = $c + 1 +end + + diff --git a/test.gdb b/test.gdb deleted file mode 100644 index 8b71320..0000000 --- a/test.gdb +++ /dev/null @@ -1,112 +0,0 @@ -define i2c_sr1_flags -set $s = $arg0 -printf "SR1: " - -if (($s & (1 << 15))) - printf "SMBALERT " -end - -if (($s & (1 << 14))) - printf "TIMEOUT " -end - -if (($s & (1 << 12))) - printf "PECERR " -end - -if (($s & (1 << 11))) - printf "OVR " -end - -if (($s & (1 << 10))) - printf "AF " -end - -if (($s & (1 << 9))) - printf "ARLO " -end - -if (($s & (1 << 8))) - printf "BERR " -end - -if (($s & (1 << 7))) - printf "TXE " -end - -if (($s & (1 << 6))) - printf "RXNE " -end - -if (($s & (1 << 4))) - printf "STOPF " -end - -if (($s & (1 << 3))) - printf "ADD10 " -end - -if (($s & (1 << 2))) - printf "BTF " -end - -if (($s & (1 << 1))) - printf "ADDR " -end - -if (($s & (1 << 0))) - printf "SB " -end -end - -define i2c_sr2_flags -set $s = $arg0 -printf "SR2: " - -if (($s & (1 << 7))) - printf "DUALF " -end - -if (($s & (1 << 6))) - printf "SMBHOST " -end - -if (($s & (1 << 5))) - printf "SMBDEFAULT " -end - -if (($s & (1 << 4))) - printf "GENCALL " -end - - -if (($s & (1 << 2))) - printf "TRA " -end - -if (($s & (1 << 1))) - printf "BUSY " -end - -if (($s & (1 << 0))) - printf "MSL " -end - -end - -define pbc -set $c = crumbs -while ($c->event) - if ($c->event != 0) - printf "Event: %d ", $c->event - if ($c->event == 1) - i2c_sr1_flags $c->sr1 - printf "\t" - i2c_sr2_flags $c->sr2 - end - printf "\n" - end - set $c = $c + 1 -end - - -- cgit v1.2.3 From 7e1b03e701291e887dadcc0bef4c9221e30e1049 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Thu, 14 Apr 2011 16:00:39 -0400 Subject: Unix toolchain docs improvements. Folded information in the README about the library Makefile target into docs/source/unix-toolchain.rst. Added a pointer to the JTAG HOWTO page on the wiki. Made some other miscellaneous cleanups, updates and improvements. --- README | 17 +-- docs/source/unix-toolchain.rst | 306 ++++++++++++++++++++++------------------- 2 files changed, 168 insertions(+), 155 deletions(-) diff --git a/README b/README index 6e4c400..456ea2f 100644 --- a/README +++ b/README @@ -32,21 +32,6 @@ For changes that block official releases, see our wiki: http://wiki.leaflabs.com/index.php?title=Blocking_Changes -Instructions to Create a Library ------------------------------------------------------------------------------- - -TODO: fold this section into the Unix Toolchain Quickstart. - -If you have a complicated project with its own Makefile and multiple -source files, or you're using an IDE that creates its own Makefile, -you'll probably want to load libmaple from an archive (a build-time -library, not a DLL). - -To create an archive, use the "make library" target, and install -build/libmaple.a and the appropriate headers in your project's -directory. At a minimum, the header set will include libmaple.h, -util.h, and libmaple_types.h. - Repository Layout ------------------------------------------------------------------------------ @@ -99,7 +84,7 @@ Repository Layout Unstructured text notes that may be useful. -/README/ +/README This file. diff --git a/docs/source/unix-toolchain.rst b/docs/source/unix-toolchain.rst index d49b642..a173146 100644 --- a/docs/source/unix-toolchain.rst +++ b/docs/source/unix-toolchain.rst @@ -7,20 +7,21 @@ =========================== This is a tutorial for using the Maple with a standard Unix toolchain -(make, gcc, etc.). It's not necessary to do this in order to program -the Maple; you can always :ref:`install the Maple IDE +(``make``, ``gcc``, etc.). It's not necessary to do this in order to +program the Maple; you can always :ref:`install the Maple IDE ` instead. You'll need a Maple board, a Mini-B USB cable, a functional computer, -and root access to that computer. This guide assumes you've had -success with the IDE on your machine and that you are fairly -comfortable with the Unix command line; some previous experience with -editing your shell startup script (.bashrc, .tcshrc, etc.) and using -`make `_ is recommended. For -generic installation/setup issues, the :ref:`IDE installation -` and :ref:`troubleshooting` pages may be -helpful. If all else fails, try our `forum`_, or `contact us -directly`_\ ! +and root (or Administrator) access to that computer. This guide +assumes you've had success with the IDE on your machine and that you +are fairly comfortable with the Unix command line. Some previous +experience with editing your shell startup script (.bashrc, .tcshrc, +etc.) and using `GCC `_ and `make +`_ is recommended. + +For generic installation and setup issues, see the :ref:`IDE +installation ` and :ref:`troubleshooting` pages. If +all else fails, try our `forum`_, or `contact us directly`_\ ! We currently have instructions for 32- and 64-bit Linux and OS X Snow Leopard. If you're on another Unix platform, Windows, or an earlier @@ -54,36 +55,40 @@ First I'll give the commands to run, then explain:: $ sudo aptitude install build-essential git-core wget screen dfu-util \ openocd python python-serial -You'll want to install a bunch of developer "basics" like -:command:`make`, :command:`tar`, etc. A good catch-all for these -tools is the "build-essential" meta-package on most Debian platforms: -installing this fake package will pull in dozens of useful tools -without bogging your system down too much. ``git-core`` is the name of -the git package; `Git `_ is a distributed code -versioning system we use to track changes in our source -code. :command:`wget` is a simple tool to download files over http -from the command line, and is optional (you could pull in the required -downloads using a browser). :command:`screen` is a really cool virtual -terminal program; in the context of Maple, we use it to connect to -serial port devices. - -:command:`dfu-util` is a tool from the `OpenMoko`_ project that we use -to upload programs to the Maple over USB. +You'll want to install a bunch of developer "basics" like ``make``, +``tar``, etc. A good catch-all for these tools is the +``build-essential`` meta-package on most Debian platforms: installing +this fake package will pull in dozens of useful tools without bogging +your system down too much. + +`Git `_ is a distributed code versioning system +we use to track changes in our source code; ``git-core`` is the +corresponding package. + +``wget`` is a simple tool to download files over http from the command +line; installing it is optional (you could pull in the required +downloads using a browser). + +``screen`` is a screen manager; in the context of Maple, we use it to +connect to serial port devices. + +``dfu-util`` is a tool from the `OpenMoko`_ project that we use to +upload programs to the Maple over USB. .. _OpenMoko: http://openmoko.com/ -:command:`openocd` is a `JTAG +``openocd`` is a `JTAG `_ control program used in conjunction with an ARM JTAG device to do in circuit debugging (pause/resume program execution, upload and download code, -read out register status, etc). (optional) +read out register status, etc). It's also optional. Lastly, our reset script (which sends control signals over the USB-serial connection to restart and enter the bootloader) is written -in Python and requires the `PySerial -`_ library (the ``python-serial`` -package; this could also be installed with `easy_install -`_). +in `Python `_, and requires the `PySerial +`_ library available in the +``python-serial`` package. This can also be installed with +`easy_install `_. **2. Fetch libmaple and Compiler Toolchain** :: @@ -100,10 +105,10 @@ then download and extract the ARM compiler toolchain. The :file:`arm/bin/` directory will need to be added to ``PATH``; you can check that this worked by entering ``arm-none-`` and hitting tab -to auto-complete (bash should show a bunch of results). Regardless of -where you put the toolchain, make sure to preserve its internal -directory layout, as the binaries make relative path calls and -references. +to auto-complete (your shell should show a bunch of results). +Regardless of where you put the toolchain, make sure to preserve its +internal directory layout, as the binaries make relative path calls +and references. After you're done, you'll probably want to update your shell startup script so :file:`~/libmaple/arm/bin` stays in your ``PATH``. @@ -118,12 +123,12 @@ From the libmaple directory, :: $ sudo cp support/scripts/45-maple.rules /etc/udev/rules.d/45-maple.rules $ sudo /etc/init.d/udev restart -As a security precaution on linux, unknown USB devices can only be -accessed by the superuser. This udev script identifies the Maple based -on its vendor and product IDs, mounts it to :file:`/dev/maple`, and -grants read/write permissions to the ``plugdev`` group. After -restarting :command:`udev` you'll need to fully unplug or power cycle -any Maples connected to the computer. +As a security precaution on Linux, unknown USB devices can only be +accessed by root. This udev script identifies the Maple based on its +vendor and product IDs, mounts it to :file:`/dev/maple`, and grants +read/write permissions to the ``plugdev`` group. After restarting +``udev`` you'll need to fully unplug or power cycle any Maples +connected to the computer. **So far, so good?** @@ -140,38 +145,40 @@ stated previously, this document assumes a general level of Unix aptitude on the part of the reader; if you're uncomfortable using Terminal (or if you don't know what that means), then you should probably stick with using the `Maple IDE -`_ to develop programs. +`_ to write programs. **1. Collect and Install Tools** -You will need the following tools\ [#fmacports]_ to get started: +You will need the following tools\ [#fpackman]_ to get started: 1. `XCode `_: If you're reading this, you've probably already got this. Provides - compilers and other basic tools of the trade. It's a free download, - but requires registration (gross, we know). + compilers and other basic tools of the trade. While XCode was once + free of charge, Apple has since begun charging for it; if you'd + rather not pay, you can probably get by with just a `make + `_ binary. 2. `Git `_: All of our code is tracked by a - distributed versioning system called git. A `Mac installer + distributed versioning system called Git. A `Mac installer `_ is available. - 3. :command:`dfu-util`: A tool from `OpenMoko`_ that we use to upload - programs to the Maple over USB. If you're feeling masochistic, there - are instructions for `building dfu-util from source + 3. ``dfu-util``: A tool from `OpenMoko`_ that we use to upload + programs to the Maple over USB. If you prefer to compile from + source, OpenMoko provides instructions for `building dfu-util `_. - However, if you've got better things to do, you can steal a dfu-util - binary from a program called `Openmoko Flasher + If you're in a hurry, you can steal a dfu-util binary from a program + called `Openmoko Flasher `_. To do this, first `download Openmoko Flasher `_, then copy - the .app into your :file:`/Applications` folder (or wherever you - like). Let's pretend you saved the .app to the directory + the OpenMoko application into your :file:`/Applications` folder (or + wherever you like). Let's pretend you saved the .app to the directory :file:`/Applications/OpenMoko Flasher.app` - Then the :command:`dfu-util` binary resides in + Then the ``dfu-util`` binary resides in :file:`/Applications/OpenMoko Flasher.app/Contents/Mac OS/dfu-util` @@ -188,8 +195,9 @@ You will need the following tools\ [#fmacports]_ to get started: .app, but you're on your own. To make sure this worked, try plugging in your Maple, making sure - it's in bootloader mode (you can do this by pressing RESET, then - quickly pressing BUT and holding it for several seconds), then + it's in :ref:`perpetual bootloader mode + ` (do this by pressing RESET, + then quickly pressing BUT and holding it for several seconds), then running :: $ dfu-util -l @@ -212,8 +220,8 @@ You will need the following tools\ [#fmacports]_ to get started: $ python setup.py build $ sudo python setup.py install - The package is also available via :command:`easy_install`, so if - you're comfortable using that, you could also install it with :: + The package is also available via ``easy_install``, so if you're + comfortable using that, you could also install it with :: $ easy_install pyserial @@ -288,20 +296,20 @@ Woo! It worked. The ``dec`` field at the end gives the total program size in bytes. The long listing of object files above the ``Final Size`` helps to identify bloated code. As you write larger projects, you may find that they use too much space. If that happens, the -file-by-file listing will help you track down the fatties porking up -your program. +file-by-file listing will help you track down the culprits. .. _toolchain-upload: Upload a program ---------------- -Ok, let's blow away the little example program and upload the -interactive test session to your Maple. This will let you interact -textually with the Maple via USB-serial. If you're on Linux, then -before executing :command:`make install`, you'll want to have the udev -rules setup :ref:`as described above `. Plug in your Maple -using the mini-b USB cable; then run :: +Let's blow away the little example program and upload the interactive +test session to your Maple. This will let you interact with the Maple +over a :ref:`USB serial port `. If you're on Linux, then before +executing ``make install``, you'll want to have the udev rules setup +:ref:`as described above `. + +Plug in your Maple using the Mini-B USB cable; then run :: $ cd ~/libmaple $ cp examples/test-session.cpp main.cpp @@ -312,91 +320,106 @@ using the mini-b USB cable; then run :: A number of things can go wrong at this stage. Simple debugging steps include using :ref:`perpetual bootloader mode `, restarting the Maple a couple -times, :command:`make clean`, etc. If nothing works, the `forum`_ is -your friend. +times, ``make clean``, etc. If nothing works, the `forum`_ is your +friend. .. _toolchain-serialusb: -Communicate over USB-serial interface +Communicate over USB-Serial interface ------------------------------------- -Okay, now that we've flashed the interactive test session to the -Maple, let's test it out. The device for the maple should look -something like :file:`/dev/ttyACMXXX` on Linux or -:file:`/dev/tty.usbmodemXXX` on OS X, but it might have a slightly -different name on your system. To open up a session, run :: +Now let's try out the interactive test session. The serial port +device file should look something like :file:`/dev/ttyACMXXX` on Linux +or :file:`/dev/tty.usbmodemXXX` on OS X, but ``XXX`` will vary +depending on your system. Try using one of these to find out which it +is:: + + # Linux + $ ls /dev/ttyACM* + + # OS X + $ ls /dev/tty.usbmodem* + +To open up a session, run :: $ screen /dev/ttyXXX -If the interactive test program built and uploaded correctly, you -should be able to connect without any errors reported by -:command:`screen`. Type ``h`` or hit the space bar to get a response; -there are a number of commands which demonstrate Maple peripheral -features. As of October 2010, the HardwareSerial library is blocking, -so using any commands which would write to the USART Serial ports will -cause the program to hang. To exit the screen session, type :kbd:`C-a -C-\\` (control-a, followed by control-backslash) on Mac, or :kbd:`C-a -k` (control-a k) on Linux, and type ``y`` when prompted if you're -sure. +If the interactive test program built and uploaded correctly, +``screen`` won't report any errors, and will present you an empty +terminal. Your board is now waiting for you to send it a command. +Type ``h`` to print a list of commands which demonstrate various +features; type any command's letter to run it. + +To exit the screen session, type :kbd:`C-a C-\\` (control-a, followed +by control-backslash) on Mac, or :kbd:`C-a k` (control-a k) on Linux, +and type ``y`` when prompted if you're sure. .. note:: - Using :command:`screen` in this way sometimes messes up your - terminal session on OS X. If your shell starts acting up after you - exit screen, you should be able to fix it with :: + Using ``screen`` sometimes messes up your terminal session on OS X. + If your shell starts acting funny after you exit ``screen``, you + should be able to fix it with :: $ reset && clear + If that doesn't work, just close the Terminal window and open up a + new one. + .. _toolchain-projects: Starting your own projects -------------------------- -.. TODO fix the build-targets.mk mess, note the "library" target - So everything worked, and you want to start your own project? Great! -It's easy. Just set the environment variable ``LIB_MAPLE_HOME`` in -your shell startup script to point to the libmaple repository you -cloned (this tutorial assumes you put it in :file:`~/libmaple`). For -example, if you use bash as your shell, just put this line in your -:file:`~/.bashrc` or :file:`~/.bash_profile`:: - - export LIB_MAPLE_HOME=~/libmaple - -Now, in order to start your own projects, just grab a copy of the -:file:`Makefile` and skeleton :file:`main.cpp` we provided in the -libmaple repository, and you're good to go:: - - $ cd - $ mkdir my-awesome-project - $ cp ~/libmaple/Makefile ~/libmaple/build-targets.mk my-awesome-project - $ cp ~/libmaple/main.cpp.example my-awesome-project/main.cpp - -(TEMPORARY: The file :file:`build-targets.mk` is where the rule to -build the object file for :file:`main.cpp` lives. If you have multiple -source files, you'll probably need to look at it and edit as -appropriate. We're sorry about that and will update the Makefile -structure later to remove this pain point.) Then hack away! You can -:command:`make`, :command:`make clean`, and :command:`make install` -from your new directory :file:`my-awesome-project` just like you did -in the libmaple repository. - -.. note:: - - We update the libmaple repository fairly frequently with bugfixes - and other improvements. In order get access to these in your local - copy of the repository, you should periodically update it with:: - - $ cd $LIB_MAPLE_HOME - $ git pull - - The `commits page - `_ for the - github repository is a good place to watch for bleeding-edge - updates; our `blog `_ is the place to - watch for major releases. We keep releases of libmaple and the - Maple IDE in lockstep, so any IDE updates will have corresponding - library updates. +There are two ways to go about it. + +If your project is small, all you have to do is replace +:file:`~/libmaple/main.cpp` with your own code, and you're free to use +``make`` and ``make install`` in the same way you did when you first +:ref:`uploaded a program `. + +If you have a more complicated project, with its own Makefile and +multiple source files, or if you're using an IDE that creates its own +Makefile, you'll probably want to load libmaple from an archive (a +build-time library, not a DLL). + +To create an archive, use the ``library`` Makefile target:: + + $ cd ~/libmaple + $ make library + +This will produce a build-time library in the file +:file:`~/libmaple/build/libmaple.a`. To use it, make sure that you +link against that library, and that the libmaple sources are in your +include path. + +At a minimum, your include path should contain the directories +:file:`~/libmaple/libmaple` and :file:`~/libmaple/wirish/`. If you +want to use one of the officially supported :ref:`libraries +`, those live under :file:`~/libmaple/libraries/`. The +main include file for the Wirish library is +:file:`~/libmaple/wirish/wirish.h`. + +Getting Updates +--------------- + +We update libmaple fairly frequently with bugfixes and other +improvements. In order get access to these in your local copy of +the repository, you should periodically update it with:: + + $ cd ~/libmaple + $ git pull + +We keep releases of libmaple and the Maple IDE in lockstep, so any +IDE updates will have corresponding library updates. Our `blog +`_ is the place to watch for major +releases; an `RSS feed `_ is +available. + +You can sign up for a free `Github `_ +account and `watch libmaple +`_ to receive +notifications about bleeding-edge development. .. _toolchain-openocd: @@ -405,20 +428,25 @@ Debug with OpenOCD TODO. For now see `this great guide `_ from fun-tech.se, and -the ``jtag`` Makefile target. +the ``jtag`` Makefile target. There is also a `JTAG How-To +`_ page on +our `wiki `_ which you may find useful. .. _toolchain-exuberantly: Go forth exuberantly! --------------------- -Let us know what you come up with! Use #leaflabs on Twitter, post in -the `forum`_, track us down in the real world, whatever. We love -projects! +Let us know what you come up with! Use #leaflabs on `Twitter +`_, post in the `forum`_, join the the +#leafblowers IRC channel on `freenode +`_, whatever. We love projects! .. rubric:: Footnotes -.. [#fmacports] Some of these software packages might be available on - `MacPorts `_. The author had some bad +.. [#fpackman] Some of these software packages might be available on + `MacPorts `_ or `Homebrew + `_. The author had some bad experiences with MacPorts a few years ago, though, and hasn't - touched it since. Of course, your mileage may vary. + touched a package manager on OS X since. Of course, your mileage + may vary. -- cgit v1.2.3 From c258d9c6c86efdb74a28b87f49c4b6fd0e517904 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Fri, 15 Apr 2011 16:42:57 -0400 Subject: Making usart.h license header 80-column clean. --- libmaple/usart.h | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/libmaple/usart.h b/libmaple/usart.h index 7a93da0..02f23da 100644 --- a/libmaple/usart.h +++ b/libmaple/usart.h @@ -3,23 +3,25 @@ * * Copyright (c) 2010 Perry Hung. * - * 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 + * 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 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. + * 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. *****************************************************************************/ /** -- cgit v1.2.3 From 7fdb4c986452756801eb8ba5eec94f9823e0b1c0 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Fri, 15 Apr 2011 16:43:57 -0400 Subject: usart.c comment fixes. License header made 80-column clean. usart_irq() comment for the USART_SAFE_INSERT case made easier to understand. --- libmaple/usart.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/libmaple/usart.c b/libmaple/usart.c index 7fe4f53..22542fd 100644 --- a/libmaple/usart.c +++ b/libmaple/usart.c @@ -3,23 +3,25 @@ * * Copyright (c) 2010 Perry Hung. * - * 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 + * 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 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. + * 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. *****************************************************************************/ /** @@ -205,7 +207,8 @@ void usart_putudec(usart_dev *dev, uint32 val) { static inline void usart_irq(usart_dev *dev) { #ifdef USART_SAFE_INSERT - /* Ignore new bytes if the user defines USART_SAFE_INSERT. */ + /* If the buffer is full and the user defines USART_SAFE_INSERT, + * ignore new bytes. */ rb_safe_insert(dev->rb, (uint8)dev->regs->DR); #else /* By default, push bytes around in the ring buffer. */ -- cgit v1.2.3 From d64c13caf100c7fa638596bd568cce3ce2ffce0a Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Thu, 21 Apr 2011 17:24:57 -0400 Subject: Requiring dac_dev* argument in DAC convenience functions. --- examples/test-dac.cpp | 89 +++++++++++++++++++++++++++------------------------ libmaple/dac.c | 28 +++++++++------- libmaple/dac.h | 31 +++++++++++++----- 3 files changed, 87 insertions(+), 61 deletions(-) diff --git a/examples/test-dac.cpp b/examples/test-dac.cpp index af98030..ba766a4 100644 --- a/examples/test-dac.cpp +++ b/examples/test-dac.cpp @@ -1,41 +1,48 @@ -#include "wirish.h" -#include "dac.h" - -uint16 count = 0; - -void setup() { - - pinMode(BOARD_LED_PIN, OUTPUT); - digitalWrite(BOARD_LED_PIN,1); - - Serial1.begin(9600); - Serial1.println("**** Beginning DAC test"); - - Serial1.print("Init... "); - dac_init(DAC_CH1 | DAC_CH2); - Serial1.println("Done."); -} - -void loop() { - toggleLED(); - delay(100); - - count += 100; - if(count > 4095) { - count = 0; - } - - dac_write_channel(1, 4095 - count); - dac_write_channel(2, count); -} - -int main(void) { - init(); - setup(); - - while (1) { - loop(); - } - return 0; -} - +/* + * Simple DAC test. + * + * Author: Marti Bolivar + * + * This file is released into the public domain. + */ + +#include "wirish.h" +#include "dac.h" + +uint16 count = 0; + +void setup() { + pinMode(BOARD_LED_PIN, OUTPUT); + digitalWrite(BOARD_LED_PIN,1); + + Serial1.begin(9600); + Serial1.println("**** Beginning DAC test"); + + Serial1.print("Init... "); + dac_init(DAC, DAC_CH1 | DAC_CH2); + Serial1.println("Done."); +} + +void loop() { + toggleLED(); + delay(100); + + count += 100; + if (count > 4095) { + count = 0; + } + + dac_write_channel(DAC, 1, 4095 - count); + dac_write_channel(DAC, 2, count); +} + +int main(void) { + init(); + setup(); + + while (1) { + loop(); + } + return 0; +} + diff --git a/libmaple/dac.c b/libmaple/dac.c index 0f44bb4..1726d19 100644 --- a/libmaple/dac.c +++ b/libmaple/dac.c @@ -39,47 +39,50 @@ const dac_dev *DAC = &dac; /** * @brief Initialize the digital to analog converter + * @param dev DAC device * @param flags Flags: * DAC_CH1: Enable channel 1 * DAC_CH2: Enable channel 2 * @sideeffect May set PA4 or PA5 to INPUT_ANALOG */ -void dac_init(uint32 flags) { +void dac_init(const dac_dev *dev, uint32 flags) { /* First turn on the clock */ rcc_clk_enable(RCC_DAC); rcc_reset_dev(RCC_DAC); if (flags & DAC_CH1) { - dac_enable_channel(1); + dac_enable_channel(dev, 1); } if (flags & DAC_CH2) { - dac_enable_channel(2); + dac_enable_channel(dev, 2); } } /** * @brief Write a 12-bit value to the DAC to output + * @param dev DAC device * @param channel channel to select (1 or 2) * @param val value to write */ -void dac_write_channel(uint8 channel, uint16 val) { +void dac_write_channel(const dac_dev *dev, uint8 channel, uint16 val) { switch(channel) { case 1: - DAC->regs->DHR12R1 = DAC_DHR12R1_DACC1DHR & val; + dev->regs->DHR12R1 = DAC_DHR12R1_DACC1DHR & val; break; case 2: - DAC->regs->DHR12R2 = DAC_DHR12R2_DACC2DHR & val; + dev->regs->DHR12R2 = DAC_DHR12R2_DACC2DHR & val; break; } } /** * @brief Enable a DAC channel + * @param dev DAC device * @param channel channel to enable, either 1 or 2 * @sideeffect May change pin mode of PA4 or PA5 */ -void dac_enable_channel(uint8 channel) { +void dac_enable_channel(const dac_dev *dev, uint8 channel) { /* * Setup ANALOG mode on PA4 and PA5. This mapping is consistent across * all STM32 chips with a DAC. See RM0008 12.2. @@ -87,26 +90,27 @@ void dac_enable_channel(uint8 channel) { switch (channel) { case 1: gpio_set_mode(GPIOA, 4, GPIO_INPUT_ANALOG); - DAC->regs->CR |= DAC_CR_EN1; + dev->regs->CR |= DAC_CR_EN1; break; case 2: gpio_set_mode(GPIOA, 5, GPIO_INPUT_ANALOG); - DAC->regs->CR |= DAC_CR_EN2; + dev->regs->CR |= DAC_CR_EN2; break; } } /** * @brief Disable a DAC channel + * @param dev DAC device * @param channel channel to disable, either 1 or 2 */ -void dac_disable_channel(uint8 channel) { +void dac_disable_channel(const dac_dev *dev, uint8 channel) { switch (channel) { case 1: - DAC->regs->CR &= ~DAC_CR_EN1; + dev->regs->CR &= ~DAC_CR_EN1; break; case 2: - DAC->regs->CR &= ~DAC_CR_EN2; + dev->regs->CR &= ~DAC_CR_EN2; break; } } diff --git a/libmaple/dac.h b/libmaple/dac.h index c897bb2..cf4fe85 100644 --- a/libmaple/dac.h +++ b/libmaple/dac.h @@ -38,6 +38,10 @@ extern "C"{ #endif +/* + * Register maps + */ + /** DAC register map. */ typedef struct dac_reg_map { __io uint32 CR; /**< Control register */ @@ -64,6 +68,13 @@ typedef struct dac_reg_map { __io uint32 DOR2; /**< Channel 2 data output register */ } dac_reg_map; +/** DAC register map base address */ +#define DAC_BASE ((dac_reg_map*)0x40007400) + +/* + * Devices + */ + /** DAC device type. */ typedef struct dac_dev { dac_reg_map *regs; /**< Register map */ @@ -72,11 +83,8 @@ typedef struct dac_dev { /** DAC device. */ extern const dac_dev *DAC; -/** DAC register map base address */ -#define DAC_BASE ((dac_reg_map*)0x40007400) - /* - * Register bit definitions and masks + * Register bit definitions */ /* Control register */ @@ -137,13 +145,20 @@ extern const dac_dev *DAC; /* Channel 1 data output register */ #define DAC_DOR2_DACC2DOR 0x00000FFF +/* + * Convenience functions + */ + +/* We take the dev argument in these convenience functions for + * future-proofing */ + #define DAC_CH1 0x1 #define DAC_CH2 0x2 -void dac_init(uint32 flags); +void dac_init(const dac_dev *dev, uint32 flags); -void dac_write_channel(uint8 channel, uint16 val); -void dac_enable_channel(uint8 channel); -void dac_disable_channel(uint8 channel); +void dac_write_channel(const dac_dev *dev, uint8 channel, uint16 val); +void dac_enable_channel(const dac_dev *dev, uint8 channel); +void dac_disable_channel(const dac_dev *dev, uint8 channel); #ifdef __cplusplus } // extern "C" -- cgit v1.2.3 From d6bb86b9e458bbf4f5a376caf05b2bc796a53aea Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Mon, 25 Apr 2011 16:07:38 -0400 Subject: 0.0.10 documentation checkpoint. Merging in the standalone refactor docs, etc. The individual libmaple API pages are going to need to get redone. --- docs/Doxyfile | 7 +- .../_static/img/libmaple-screenshot-small.png | Bin 38023 -> 0 bytes docs/source/adc.rst | 7 +- docs/source/arduino-compatibility.rst | 270 ++++++++++++++ docs/source/arm-gcc.rst | 2 +- docs/source/bootloader.rst | 4 +- docs/source/compatibility.rst | 270 -------------- docs/source/errata.rst | 140 ------- docs/source/gpio.rst | 2 +- docs/source/hardware/maple.rst | 200 +++++++++- docs/source/i2c.rst | 27 +- docs/source/index.rst | 22 +- docs/source/lang/cpp/arithmetic.rst | 5 +- docs/source/language-index.rst | 3 + docs/source/language.rst | 77 ++-- docs/source/libmaple.rst | 64 ++-- docs/source/libmaple/api/adc.rst | 12 + docs/source/libmaple/api/bitband.rst | 12 + docs/source/libmaple/api/bkp.rst | 12 + docs/source/libmaple/api/dac.rst | 12 + docs/source/libmaple/api/delay.rst | 12 + docs/source/libmaple/api/dma.rst | 12 + docs/source/libmaple/api/exti.rst | 12 + docs/source/libmaple/api/flash.rst | 12 + docs/source/libmaple/api/fsmc.rst | 12 + docs/source/libmaple/api/gpio.rst | 12 + docs/source/libmaple/api/i2c.rst | 12 + docs/source/libmaple/api/iwdg.rst | 12 + docs/source/libmaple/api/libmaple.rst | 12 + docs/source/libmaple/api/libmaple_types.rst | 12 + docs/source/libmaple/api/nvic.rst | 12 + docs/source/libmaple/api/pwr.rst | 12 + docs/source/libmaple/api/rcc.rst | 12 + docs/source/libmaple/api/ring_buffer.rst | 12 + docs/source/libmaple/api/scb.rst | 12 + docs/source/libmaple/api/spi.rst | 12 + docs/source/libmaple/api/stm32.rst | 12 + docs/source/libmaple/api/systick.rst | 12 + docs/source/libmaple/api/timer.rst | 12 + docs/source/libmaple/api/usart.rst | 12 + docs/source/libmaple/api/util.rst | 12 + docs/source/libmaple/apis.rst | 14 + docs/source/libmaple/coding-standard.rst | 412 +++++++++++++++++++++ docs/source/libmaple/contributing.rst | 113 ++++++ docs/source/libmaple/overview.rst | 342 +++++++++++++++++ docs/source/maple-ide-install.rst | 4 +- docs/source/pwm.rst | 2 +- docs/source/specs.rst | 29 -- docs/source/troubleshooting.rst | 14 +- docs/source/unix-toolchain.rst | 22 +- docs/source/usb.rst | 2 +- 51 files changed, 1762 insertions(+), 592 deletions(-) delete mode 100644 docs/source/_static/img/libmaple-screenshot-small.png create mode 100644 docs/source/arduino-compatibility.rst delete mode 100644 docs/source/compatibility.rst delete mode 100644 docs/source/errata.rst create mode 100644 docs/source/libmaple/api/adc.rst create mode 100644 docs/source/libmaple/api/bitband.rst create mode 100644 docs/source/libmaple/api/bkp.rst create mode 100644 docs/source/libmaple/api/dac.rst create mode 100644 docs/source/libmaple/api/delay.rst create mode 100644 docs/source/libmaple/api/dma.rst create mode 100644 docs/source/libmaple/api/exti.rst create mode 100644 docs/source/libmaple/api/flash.rst create mode 100644 docs/source/libmaple/api/fsmc.rst create mode 100644 docs/source/libmaple/api/gpio.rst create mode 100644 docs/source/libmaple/api/i2c.rst create mode 100644 docs/source/libmaple/api/iwdg.rst create mode 100644 docs/source/libmaple/api/libmaple.rst create mode 100644 docs/source/libmaple/api/libmaple_types.rst create mode 100644 docs/source/libmaple/api/nvic.rst create mode 100644 docs/source/libmaple/api/pwr.rst create mode 100644 docs/source/libmaple/api/rcc.rst create mode 100644 docs/source/libmaple/api/ring_buffer.rst create mode 100644 docs/source/libmaple/api/scb.rst create mode 100644 docs/source/libmaple/api/spi.rst create mode 100644 docs/source/libmaple/api/stm32.rst create mode 100644 docs/source/libmaple/api/systick.rst create mode 100644 docs/source/libmaple/api/timer.rst create mode 100644 docs/source/libmaple/api/usart.rst create mode 100644 docs/source/libmaple/api/util.rst create mode 100644 docs/source/libmaple/apis.rst create mode 100644 docs/source/libmaple/coding-standard.rst create mode 100644 docs/source/libmaple/contributing.rst create mode 100644 docs/source/libmaple/overview.rst delete mode 100644 docs/source/specs.rst diff --git a/docs/Doxyfile b/docs/Doxyfile index 9bf02fc..5fbb079 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -608,7 +608,7 @@ INPUT_ENCODING = UTF-8 # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 -FILE_PATTERNS = *.h +FILE_PATTERNS = *.h *.c # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. @@ -1372,7 +1372,10 @@ INCLUDE_FILE_PATTERNS = # instead of the = operator. PREDEFINED = __attribute__()= \ - __cplusplus + __cplusplus \ + STM32_MEDIUM_DENSITY + STM32_HIGH_DENSITY + STM32_XL_DENSITY # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. diff --git a/docs/source/_static/img/libmaple-screenshot-small.png b/docs/source/_static/img/libmaple-screenshot-small.png deleted file mode 100644 index f2be783..0000000 Binary files a/docs/source/_static/img/libmaple-screenshot-small.png and /dev/null differ diff --git a/docs/source/adc.rst b/docs/source/adc.rst index 6bbbac2..b943808 100644 --- a/docs/source/adc.rst +++ b/docs/source/adc.rst @@ -71,11 +71,10 @@ Recommended Reading ------------------- * `Wikipedia article on Analog-to-digital converter `_ + * `Arduino Analog Input Tutorial `_ -* STMicro documentation for STM32F103RB microcontroller: - * `All `_ - * `Datasheet `_ (pdf) - * `Reference Manual `_ (pdf) +* STMicro documentation: + * `Application Note on ADC Modes (pdf) `_ * `Application Note on ADC Oversampling (pdf) `_ diff --git a/docs/source/arduino-compatibility.rst b/docs/source/arduino-compatibility.rst new file mode 100644 index 0000000..e6852a0 --- /dev/null +++ b/docs/source/arduino-compatibility.rst @@ -0,0 +1,270 @@ +.. highlight:: cpp + +.. _arduino-compatibility: + +============================= + Maple-Arduino Compatibility +============================= + +.. contents:: Contents + :local: + +Overview +-------- + +The biggest difference between the Maple and most Arduino boards is +that the Maple uses a 32-bit ARM Cortex-M3 architecture chip, while +the Arduinos have 8-bit Atmel AVR chips. The different instruction set +means that machine code (which makes up executable binary program) is +incompatible between the two, and a different compiler (actually just +a different version of `gcc `_) is required. + +The compiler for the regular Arduino IDE is the popular `avr-gcc +`_ package; the compiler for the +Maple version of the IDE is CodeSourcery's edition of gcc for the ARM +EABI target (:command:`arm-non-eabi-gcc`). A (preliminary) reference +on :ref:`using arm-none-eabi-gcc ` is available. + +The bitwidth of the processor means that the Maple can process 32-bit +operations (like adding two 32-bit integers) in a single instruction, +while an Arduino processor would have to split up large operations +into several smaller ones. In a lot of cases 8-bit operations are +plenty (integers 0-255, single characters of text, etc.), but if +you're dealing with higher resolution data, the speed up could be +significant. + +A trade-off is that code could be larger as well; program instructions +and memory locations can be up to 32 bits each. However, removal of +extra instructions and fancy packing together of simple instructions +means that programs aren't much larger (or are even smaller). + +Header Numbering and Incompatibilities +-------------------------------------- + +.. FIXME [Maple-specific values] + +The numbering of headers is different; on the Maple each GPIO has a +unique number: 0, 1, 2, all the way up to 37 (actually, there are +:ref:`a few more `...). On the Arduino, the analog pins are +numbered separately (A0-A5) from the digital pins (D0\ -D13). + +The incompatible hardware differences are: + +* :ref:`I2C ` **port**: on most Arduinos, the |i2c| port is Analog + Input 4 (SDA) and Analog Input 5 (SCL); on the Maple, |i2c| port 1 + is D5 (SCL) and D9 (SDA), and |i2c| port 2 is D29 (SCL) and D30 + (SDA). + + It should be possible to skywire, sacrificing signal quality (due to + increased capacitance). Alternatively, |i2c| can be bit-banged + reasonably well in software. This peripheral could potentially be + rerouted internally, but we haven't looked into it. + +* :ref:`PWM ` **on D10**: all the other standard Arduino PWM + headers have PWM functionality on the Maple (D2,D3,D6,D9,D11), but + not D10. + +* **No External Voltage Reference**: The Arduino has an AREF pin which + allows the use of an external ADC voltage reference; the Maple has + an extra GPIO pin (D14) with PWM capability in this spot, and does + not allow an external voltage reference to be configured. + +* **EEPROM**: the Maple does not have any internal EEPROM. This + functionality can be emulated with regular persistent flash memory, + or with an external EEPROM chip. + +* **ISP Programming**: the Maple does not use an ISP/ICSP bus for + debugging; it uses :ref:`JTAG `. + + +Software Language/Library Changes +--------------------------------- + +With :ref:`a few exceptions `, the entire +Wiring/Arduino language is supported. However, there are some subtle +differences, most of which are improvements: + +* **32-bit integers**: many standard functions either expect or return + full 32-bit (4 byte) integer values instead of the regular 16-bit (2 + byte) Arduino values. + +* **64-bit doubles**: The :ref:`double ` type is a full + double-precision floating point type on the Maple; it is a + single-precision floating point value on the Arduino. + +* :ref:`pinMode() ` **types**: any :ref:`GPIO ` + (including analog pins) can be configured into one of the following + modes with a single call to ``pinMode()``: ``OUTPUT``, + ``OUTPUT_OPEN_DRAIN``, ``INPUT_FLOATING``, ``INPUT_PULLUP``, + ``INPUT_PULLDOWN``. Additionally, the PWM pins (labeled "PWM" on the + silkscreen) can be configured in ``PWM`` and ``PWM_OPEN_DRAIN`` + modes, and the analog input pins (labeled "AIN") can be configured + in ``INPUT_ANALOG`` mode. See the :ref:`GPIO documentation ` + for more information. + +* :ref:`Serial port ` **syntax**: like the `Arduino Mega + `_, the Maple has + multiple :ref:`USART ports `. By default, ``Serial`` + is not mapped to any of them. Use ``Serial1`` through ``Serial3`` + instead. + +* **16-bit** :ref:`PWM `: Arduino boards support 8-bit PWM, which + means that calls to :ref:`analogWrite() ` take + values between 0 (always off) and 255 (always on). The Maple + supports 16-bit PWM, so the corresponding values should be between 0 + (always off) and 65535 (always on). + +* **12-bit** :ref:`ADC `: Arduino boards support 10-bit ADC, which + means that calls to :ref:`analogRead() ` will + return values between 0 and 1023. The Maple supports 12-bit ADC, so + the same call will instead return values between 0 and 4095. + +Shield and Device Compatibility +------------------------------- + +.. list-table:: + :header-rows: 1 + + * - Shield/Device + - Compatible? + - Notes + + * - Ethernet shield + - Yes! + - Tested; no library yet + + * - WiFi Shield + - Yes! + - Tested; preliminary library support + + * - MIDI shield + - Yes! + - Tested; no library yet + + * - XBee shield + - Unknown + - + + * - Bluetooth shield + - Unknown + - Some Bluetooth <-> UART boards have been tested and are known + to work. + + * - Cellular shield + - Unknown + - + +Library Porting Status +---------------------- + +The state of currently ported Arduino libraries is the +:ref:`libraries`. + +.. TODO Update as libraries are ported. + +.. list-table:: + :header-rows: 1 + + + * - Library + - Ported? + - Notes + + * - Wire + - Preliminary + - In progress; see :ref:`library reference `. + + * - LiquidCrystal + - **Yes** + - :ref:`Included since IDE 0.0.7 ` + + * - Ethernet + - Not yet + - Planned + + * - EEPROM + - (Unsupported) third-party emulation + - The Maple doesn't have EEPROM; it uses flash instead. There is + an `EEPROM emulation library + `_ by + `x893 `_, but we haven't tested it. + + * - Firmata + - Not yet + - Planned + + * - Matrix + - Not yet + - Planned + + * - Servo + - **Yes** + - :ref:`Included since IDE 0.0.9 ` + + * - SoftwareSerial + - Not yet + - Planned + + * - Sprite + - Not yet + - Planned + + * - Stepper + - Not yet + - Planned + +Sketch and Library Porting HOWTO +-------------------------------- + +In addition to the suggestions in this section, you may find many of +the individual :ref:`language reference ` pages useful. As +appropriate, these have "Arduino Compatibility" sections; one good +example is the :ref:`analogWrite() ` +function. + +- Check the hardware and header differences above, and see if your + project or shield needs to be modified (eg, add 3.3V level + converters or reroute PWM to header D10). + +- Check for ported library functionality. We intend to port all of the + core and popular libraries (like Wire, Ethernet, and the LCD screen + driver), but this task is not yet finished. (:ref:`Patches are + welcome! `). + +- Check for peripheral conflicts; changing the configuration of timers + and bus speeds for a feature on one header may impact all the + features on that hardware "port". For example, changing the timer + prescaler to do long PWM pulses could impact |i2c| communications on + nearby headers. + +- Rewrite any low-level code. This could potentially be very + difficult, but hopefully you've used the Arduino libraries to + abstract away the registers and other hardware-specific + details. Your sketch probably doesn't have any low-level code; a + library which wraps a particular peripheral very well may. Some + help is available in the :ref:`arm-gcc` reference. + +- Redeclare variable sizes if necessary: generics like ``int`` will + probably work unless you depend on side-effects like rollover. + +- Check every ``pinMode()``: the Maple has more modes for GPIO + pins. For example, make sure to set analog pins to ``INPUT_ANALOG`` + before reading and PWM pins to ``PWM`` before writing. The full set + of pin modes is documented in the :ref:`lang-pinmode` reference. + +- Modify PWM writes: ``pinMode()`` must be set to ``PWM``, the + frequency of the PWM pulse configured, and the duty cycle written + with up to 16-bit resolution. + +- Modify ADC reads: :ref:`lang-analogread` takes the full pin number + (not 0-5) and returns a full 12-bit reading. The ADC pin must have + its ``pinMode()`` set to ``INPUT_ANALOG``. + +- Possibly convert all Serial-over-USB communications to use + :ref:`lang-serialusb` instead of a USART :ref:`serial port + `. The Maple has a dedicated USB port which is not + connected to the USART TX/RX pins in any way. + +- Check timing: Maple clock cycles are just 13.9 nanoseconds, though + the peripheral bus speeds (which limit GPIO output) are clocked + slower. diff --git a/docs/source/arm-gcc.rst b/docs/source/arm-gcc.rst index 7ecb5d4..e97bb2f 100644 --- a/docs/source/arm-gcc.rst +++ b/docs/source/arm-gcc.rst @@ -5,7 +5,7 @@ GCC for Maple ============= This document provides notes on using of ``arm-none-eabi-gcc``, the -`CodeSourcery `_ version of the GNU `GCC +`CodeSourcery `_ version of the GNU `GCC `_ compilers used for the Maple boards. It is not intended as a reference manual for GCC; such manuals are available `elsewhere `_. diff --git a/docs/source/bootloader.rst b/docs/source/bootloader.rst index 917a1b7..85b2674 100644 --- a/docs/source/bootloader.rst +++ b/docs/source/bootloader.rst @@ -13,7 +13,7 @@ Flash memory and only runs when the chip is reset). git clone git://github.com/leaflabs/maple-bootloader.git -**Visit the github development project**: http://github.com/leaflabs/maple-bootloader +**Visit the github development project**: https://github.com/leaflabs/maple-bootloader .. contents:: Contents :local: @@ -34,7 +34,7 @@ likely only interesting to a few. If you just want to get the rough idea, skim this article. If you want to start hacking on the bootloader, get in touch with us to get even more info on how this all works. And finally, you can always `check out the code at github -`_! +`_! Arduino ------- diff --git a/docs/source/compatibility.rst b/docs/source/compatibility.rst deleted file mode 100644 index eb28ad2..0000000 --- a/docs/source/compatibility.rst +++ /dev/null @@ -1,270 +0,0 @@ -.. highlight:: cpp - -.. _compatibility: - -============================= - Maple-Arduino Compatibility -============================= - -.. contents:: Contents - :local: - -Overview --------- - -The biggest difference between the Maple and most Arduino boards is -that the Maple uses a 32-bit ARM Cortex-M3 architecture chip, while -the Arduinos have 8-bit Atmel AVR chips. The different instruction set -means that machine code (which makes up executable binary program) is -incompatible between the two, and a different compiler (actually just -a different version of `gcc `_) is required. - -The compiler for the regular Arduino IDE is the popular `avr-gcc -`_ package; the compiler for the -Maple version of the IDE is CodeSourcery's edition of gcc for the ARM -EABI target (:command:`arm-non-eabi-gcc`). A (preliminary) reference -on :ref:`using arm-none-eabi-gcc ` is available. - -The bitwidth of the processor means that the Maple can process 32-bit -operations (like adding two 32-bit integers) in a single instruction, -while an Arduino processor would have to split up large operations -into several smaller ones. In a lot of cases 8-bit operations are -plenty (integers 0-255, single characters of text, etc.), but if -you're dealing with higher resolution data, the speed up could be -significant. - -A trade-off is that code could be larger as well; program instructions -and memory locations can be up to 32 bits each. However, removal of -extra instructions and fancy packing together of simple instructions -means that programs aren't much larger (or are even smaller). - -Header Numbering and Incompatibilities --------------------------------------- - -.. FIXME generalize Maple-specific information - -The numbering of headers is different; on the Maple each GPIO has a -unique number: D0, D1, D2, all the way up to D37 (actually, there are -:ref:`a few more `...). On the Arduino, the analog pins are -numbered separately (A0-A5) from the digital pins (D0\ -D13). - -The incompatible hardware differences are: - -* **I2C port**: on most Arduinos, the |i2c| port is Analog Input 4 - (SDA) and Analog Input 5 (SCL); on the Maple, |i2c| port 1 is D5 - (SCL) and D9 (SDA), and |i2c| port 2 is D29 (SCL) and D30 (SDA). - - It should be possible to skywire, sacrificing signal quality (due to - increased capacitance). Alternatively, |i2c| can be bit-banged - reasonably well in software. This peripheral could potentially be - rerouted internally, but we haven't looked into it. - -* :ref:`PWM ` **on D10**: all the other standard Arduino PWM - headers have PWM functionality on the Maple (D2,D3,D6,D9,D11), but - not D10. We did our best! It may be possible to reroute this - peripheral internally using low level configuration, but we haven't - looked in to it. - -* **No External Voltage Reference**: The Arduino has an AREF pin which - allows the use of an external ADC voltage reference; the Maple has - an extra GPIO pin (D14) with PWM capability in this spot, and does - not allow an external voltage reference to be configured. - -* **EEPROM**: the Maple does not have any internal EEPROM. This - functionality can be emulated with regular persistent flash memory, - or with an external EEPROM chip. - -* **ISP Programming**: the Maple does not use an ISP/ICSP bus for - debugging; it uses :ref:`JTAG `. - - -Software Language/Library Changes ---------------------------------- - -With :ref:`a few exceptions `, the entire -Wiring/Arduino language is supported. However, there are some subtle -differences, most of which are improvements: - -* **32-bit integers**: many standard functions either expect or return - full 32-bit (4 byte) integer values instead of the regular 16-bit (2 - byte) Arduino values. - -* **64-bit doubles**: The :ref:`double ` type is a full - double-precision floating point type on the Maple; it is a - single-precision floating point value on the Arduino. - -* :ref:`pinMode() ` **types**: any :ref:`GPIO ` - (including analog pins) can be configured into one of the following - modes with a single call to ``pinMode()``: ``OUTPUT``, - ``OUTPUT_OPEN_DRAIN``, ``INPUT_FLOATING``, ``INPUT_PULLUP``, - ``INPUT_PULLDOWN``. Additionally, the PWM pins (labeled "PWM" on the - Maple's silkscreen) can be configured in ``PWM`` and - ``PWM_OPEN_DRAIN`` modes, and the analog input pins (labeled "AIN") - can be configured in ``INPUT_ANALOG`` mode. See the :ref:`GPIO - documentation ` for more information. - -* :ref:`Serial port ` **syntax**: like the `Arduino Mega - `_, the Maple has - multiple :ref:`USART ports `. By default, ``Serial`` - is not mapped to any of them, use ``Serial1`` through ``Serial3`` - instead. - -* **16-bit** :ref:`PWM `: Arduino boards support 8-bit PWM, which - means that calls to :ref:`analogWrite() ` take - values between 0 (always off) and 255 (always on). The Maple - supports 16-bit PWM, so the corresponding values should be between 0 - (always off) and 65535 (always on). - -* **12-bit** :ref:`ADC `: Arduino boards support 10-bit ADC, which - means that calls to :ref:`analogRead() ` will - return values between 0 and 1023. The Maple supports 12-bit ADC, so - the same call will instead return values between 0 and 4095. - -Shield and Device Compatibility -------------------------------- - -.. list-table:: - :header-rows: 1 - - * - Shield/Device - - Compatible? - - Notes - - * - Ethernet shield - - Yes! - - Tested; no library yet - - * - WiFi Shield - - Yes! - - Tested; preliminary library support - - * - MIDI shield - - Yes! - - Tested; no library yet - - * - XBee shield - - Unknown - - - - * - Bluetooth shield - - Unknown - - Some Bluetooth <-> UART boards have been tested and are known - to work. - - * - Cellular shield - - Unknown - - - -Library Porting Status ----------------------- - -The state of currently ported Arduino libraries is the -:ref:`libraries`. - -.. TODO Update as libraries are ported. - -.. list-table:: - :header-rows: 1 - - - * - Library - - Ported? - - Notes - - * - Wire - - Preliminary - - In progress; see :ref:`library reference `. - - * - LiquidCrystal - - **Yes** - - :ref:`Included since IDE 0.0.7 ` - - * - Ethernet - - Not yet - - Planned - - * - EEPROM - - (Unsupported) third-party emulation - - The Maple doesn't have EEPROM; it uses flash instead. There is - an `EEPROM emulation library - `_ by - `x893 `_, but we haven't tested it. - - * - Firmata - - Not yet - - Planned - - * - Matrix - - Not yet - - Planned - - * - Servo - - **Yes** - - :ref:`Included since IDE 0.0.9 ` - - * - SoftwareSerial - - Not yet - - Planned - - * - Sprite - - Not yet - - Planned - - * - Stepper - - Not yet - - Planned - -Sketch and Library Porting HOWTO --------------------------------- - -In addition to the suggestions in this section, you may find many of -the individual :ref:`language reference ` pages useful. As -appropriate, these have "Arduino Compatibility" sections; one good -example is the :ref:`analogWrite() ` -function. - -- Check the hardware and header differences above, and see if your - project or shield needs to be modified (eg, add 3.3V level - converters or reroute PWM to header D10). - -- Check for ported library functionality. We intend to port all of the - core and popular libraries (like Wire, Ethernet, and the LCD screen - driver), but this task is not yet finished. (Patches are welcome!) - -- Check for peripheral conflicts; changing the configuration of timers - and bus speeds for a feature on one header may impact all the - features on that hardware "port". For example, changing the timer - prescaler to do long PWM pulses could impact |i2c| communications on - nearby headers. - -- Rewrite any low-level code. This could potentially be very - difficult, but hopefully you've used the Arduino libraries to - abstract away the registers and other hardware-specific - details. Your sketch probably doesn't have any low-level code; a - library which wraps a particular peripheral very well may. Some - help is available in the :ref:`arm-gcc` reference. - -- Redeclare variable sizes if necessary: generics like ``int`` will - probably work unless you depend on side-effects like rollover. - -- Check every ``pinMode()``: the Maple has more modes for GPIO - pins. For example, make sure to set analog pins to ``INPUT_ANALOG`` - before reading and PWM pins to ``PWM`` before writing. The full set - of pin modes is documented in the :ref:`lang-pinmode` reference. - -- Modify PWM writes: ``pinMode()`` must be set to ``PWM``, the - frequency of the PWM pulse configured, and the duty cycle written - with up to 16-bit resolution. - -- Modify ADC reads: :ref:`lang-analogread` takes the full pin number - (not 0-5) and returns a full 12-bit reading. The ADC pin must have - its ``pinMode()`` set to ``INPUT_ANALOG``. - -- Possibly convert all Serial-over-USB communications to use - :ref:`lang-serialusb` instead of a USART :ref:`serial port - `. The Maple has a dedicated USB port which is not - connected to the USART TX/RX pins in any way. - -- Check timing: Maple clock cycles are just 13.9 nanoseconds, though - the peripheral bus speeds (which limit GPIO output) are clocked - slower. diff --git a/docs/source/errata.rst b/docs/source/errata.rst deleted file mode 100644 index 657abd9..0000000 --- a/docs/source/errata.rst +++ /dev/null @@ -1,140 +0,0 @@ -.. _errata: - -======== - Errata -======== - -This page is a collection of known issues and warnings for each -revision of the Maple board. The failure modes aren't design errors, -but are easy ways to break or damage your board permanently. For a -list of differences between the Maple and Arduinos, see the -:ref:`compatibility reference `. - -The errata are grouped by Maple version ("Rev"). Rev 5 is currently -on sale. If you are unsure which version you own, the :ref:`Maple -hardware page ` has pictures and -descriptions of each version. - -.. contents:: Contents - :local: - -Maple Rev 5 ------------ - -Known issues: - -* **Pin 3 AIN missing**: Pin 3 is capable of analog input, but the - corresponding "AIN" is missing from its silkscreen. - -* **GPIO 39-43 not configured**: this is really more of a software - "TODO" item. Some of the JTAG header pins are numbered 39-43. These - STM32 pins are indeed fully functional :ref:`GPIO ` when a - :ref:`JTAG ` device is not connected, but we have not enabled - them in software and thus they can not be accessed with the regular - :ref:`lang-pinmode` or :ref:`lang-digitalwrite` functions. - -Potential failure modes: - -* **High voltage on non-tolerant pins**: not all header pins are 5V - compatible; so e.g. connecting certain serial devices in the wrong - way could over-voltage the pins. The :ref:`Pin-Mapping Mega Table - ` details which pins are 5V-tolerant. - -Maple Rev 3 ------------ - -Known issues: - -* **Bad/Sticky Buttons**: a number of Rev 3 boards sold in May-June 2010 - have questionable RESET and BUT buttons. - - What seems to have happened is that the flux remover we used to - clean the boards before shipping eroded the plastic internals, which - resulted in intermittent functionality. All buttons on all shipped - boards did function in testing, but some may have been unreliable in - regular use. - - If you have this problem, we will be happy to ship you new buttons - if you think you can re-solder them yourself, or you can ship us - your board and we will swap out that part. - - For reference, the button part number is KMR211GLFS and the flux - remover we used is "Precision Electronics Cleaner" from RadioShack, - which is "Safe on most plastics" and contains Dipropylene glycol - monomethyl ether, hydrotreated heavy naphtha, dipropylene glycol - methyl ether acetate (really?), and carbon dioxide. - -* **Resistors on pins 0 and 1**: these header pins, which are RX/TX on - USART2 (:ref:`Serial2 `), have resistors in-line - between the STM32 and the headers. These resistors increase the - impedance of the lines for ADC reads and affect the open drain GPIO - functionality of the pins. - - These resistors were accidentally copied over from older Arduino USB - designs, where they appear to protect the USB-Serial converter from - TTL voltage on the headers. - -* **GPIO 39-43 not configured**: this is really more of a software - "TODO" item. Some of the JTAG header pins are numbered 39-43. These - STM32 pins are indeed fully functional :ref:`GPIO ` when the a - :ref:`JTAG ` device is not connected, but we have not enabled - them in software and thus they can not be accessed with the regular - :ref:`lang-pinmode` or :ref:`lang-digitalwrite` functions. - -* **Silkscreen Errors**: the silkscreen on the bottom indicated PWM - functionality on pin 25 and listen the external header GND pin as - number 38 (actually 38 is connected to the BUT button). We manually - sharpied over both of these mistakes. - -* **PWM Marketing Mistake**: We originally sold the Maple advertising - 22 channels of 16-bit hardware PWM; actually the Maple only has 15. - -Potential failure modes: - -* **TTL voltage on non-tolerant pins**: not all header pins are 5V - compatible; connecting certain serial devices in the wrong way could - over voltage the pins. The :ref:`Pin-Mapping Mega Table - ` details which pins are 5V-tolerant. - -Maple Rev 1 ------------ - -Known issues: - -* **ADC noise**: generally very high, in particular when the USB port - is being used for communications (including keep-alive pings when - connected to a computer). - - This issue was resolved in Rev 3 with a 4-layer design and a - geometrically isolated ADC V\ :sub:`ref` plane. - -* **Resistors on pins 0 and 1**: these header pins, which are RX/TX on - USART2 (:ref:`Serial2 `), have resistors in-line - between the STM32 and the headers. These resistors increase the - impedance of the lines for ADC reads and affect the open drain GPIO - functionality of the pins. - - These resistors were accidentally copied over from older Arduino USB - designs, where they appear to protect the USB-Serial converter from - TTL voltage on the headers. - -* **Silkscreen Differences**: the pin numbering scheme on Rev 1 is - different from Rev 3, and thus Rev 3 software is difficult to use - with Rev 1 boards. Notably, the analog input bank is labeled A0-A4 - on Rev 1 but 15-20 on Rev 3, and the extra header bank does not have - a pinout table on the bottom. - -* **No BUT Button**: the BUT button, useful for serial bootloading, - was only added in Rev 3. As a workaround, you can directly short the - appropriate MCU pin to Vcc; see `this forum posting - `_. - -* **PWM Marketing Mistake**: We originally sold the Maple advertising - 22 channels of 16-bit hardware PWM; actually the Maple only has 15. - -Potential failure modes: - -* **TTL voltage on non-tolerant pins**: not all header pins are 5v - compatible; connecting certain serial devices in the wrong way could - over voltage the pins. The :ref:`Pin-Mapping Mega Table - ` details which pins are 5V-tolerant. diff --git a/docs/source/gpio.rst b/docs/source/gpio.rst index 5daf43c..0f9f4df 100644 --- a/docs/source/gpio.rst +++ b/docs/source/gpio.rst @@ -3,7 +3,7 @@ GPIO ==== -.. FIXME generalize this maple-specific information +.. FIXME [Maple-specific values] The Maple features 38 ready-to-use general purpose input/output (GPIO) pins for digital input/output, numbered D0 through D37. These numbers diff --git a/docs/source/hardware/maple.rst b/docs/source/hardware/maple.rst index 874ee82..44a5238 100644 --- a/docs/source/hardware/maple.rst +++ b/docs/source/hardware/maple.rst @@ -8,6 +8,30 @@ Maple .. contents:: Contents :local: +Technical Specifications +------------------------ + + * MCU: **STM32F103RBT6**, a 32-bit ARM Cortex M3 microprocessor + * Clock Speed: **72 MHz** + * Operating Voltage: 3.3V + * Input Voltage (recommended): 3V-12V + * 39 Digital I/O Pins (:ref:`GPIO `) + * 16 Analog Input Pins + * 12-bit **ADC** resolution (:ref:`ADC `) + * 15 **PWM** pins at 16-bit resolution (:ref:`PWM `) + * Dedicated **USB** port for programming and communications (:ref:`USB`) + * External **JTAG** interface (:ref:`USB `) + * **128 Flash** and **20KB SRAM** + * 64 Channel nested vector interrupt handler (including external interrupt on GPIOs) + * Integrated **SPI** (:ref:`SPI`) + * Integrated **I2C** (:ref:`I2C`) + * 7 Channels of Direct Memory Access (**DMA**) + * 3 **USART** divices (:ref:`USART `) + * Four 4-channel **timers** (:ref:`Timers `) + * Supplies up to 800mA @ 3.3v + * Support for low power and sleep modes (<500uA) + * Dimensions are 2.05″x2.1″ + .. _maple-hardware-identify-rev: Identifying your Rev @@ -16,17 +40,22 @@ Identifying your Rev We went through three versions ("Revs") of the Maple hardware: Rev 1, Rev 3, and Rev 5 [#frev2_4]_; Rev 5, the final design, is currently on sale. The following sections will help you to help you identify your -Rev. Known issues are listed in the :ref:`errata `. +Rev. Known issues are listed in the :ref:`errata `. -Rev 1 +Rev 5 ^^^^^ -A small number of Maple Rev 1 boards went on sale in late 2009. They -have a light red silkscreen and a single pixelated leaf as a logo. +These boards went on sale in November 2010. They have white buttons, +and "r5" in small print near the "LeafLabs Maple" text next to the +"infinity leaf" logo. The Maple Rev 5 repositioned the double header +on the right hand side to better fit 0.1 inch pitch breadboard. This +necessitated the removal of pins 21 and 22 from the double header; +they are still available, but don't have any headers installed on +them. -.. figure:: /_static/img/maple_rev1.png +.. figure:: /_static/img/maple_rev5.png :align: center - :alt: Maple Rev 1 + :alt: Maple Rev 5 Rev 3 ^^^^^ @@ -40,20 +69,15 @@ It also includes a built-in LiPo battery charger. :align: center :alt: Maple Rev 3 -Rev 5 +Rev 1 ^^^^^ -These boards went on sale in November 2010. They have white buttons, -and "r5" in small print near the "LeafLabs Maple" text next to the -"infinity leaf" logo. The Maple Rev 5 repositioned the double header -on the right hand side to better fit 0.1 inch pitch breadboard. This -necessitated the removal of pins 21 and 22 from the double header; -they are still available, but don't have any headers installed on -them. +A small number of Maple Rev 1 boards went on sale in late 2009. They +have a light red silkscreen and a single pixelated leaf as a logo. -.. figure:: /_static/img/maple_rev5.png +.. figure:: /_static/img/maple_rev1.png :align: center - :alt: Maple Rev 5 + :alt: Maple Rev 1 .. _hardware-maple-powering: @@ -99,8 +123,150 @@ at the command line with :: $ git clone git://github.com/leaflabs/maple.git +.. _maple-errata: + +Errata +------ + +This section lists known issues and warnings for each revision of the +Maple board. The failure modes aren't design errors, but are easy ways +to break or damage your board permanently. For a list of differences +between the Maple and Arduinos, see the :ref:`Arduino Compatibility +reference `. + +The errata are grouped by Maple version ("Rev"). + +Maple Rev 5 +^^^^^^^^^^^ + +Known issues: + +* **Pin 3 AIN missing**: Pin 3 is capable of analog input, but the + corresponding "AIN" is missing from its silkscreen. + +* **GPIO 39-43 not configured**: this is really more of a software + "TODO" item. Some of the JTAG header pins are numbered 39-43. These + STM32 pins are indeed fully functional :ref:`GPIO ` when a + :ref:`JTAG ` device is not connected, but we have not enabled + them in software and thus they can not be accessed with the regular + :ref:`lang-pinmode` or :ref:`lang-digitalwrite` functions. + +Potential failure modes: + +* **High voltage on non-tolerant pins**: not all header pins are 5V + compatible; so e.g. connecting certain serial devices in the wrong + way could over-voltage the pins. The :ref:`Pin-Mapping Mega Table + ` details which pins are 5V-tolerant. + +Maple Rev 3 +^^^^^^^^^^^ + +Known issues: + +* **Bad/Sticky Buttons**: a number of Rev 3 boards sold in May-June 2010 + have questionable RESET and BUT buttons. + + What seems to have happened is that the flux remover we used to + clean the boards before shipping eroded the plastic internals, which + resulted in intermittent functionality. All buttons on all shipped + boards did function in testing, but some may have been unreliable in + regular use. + + If you have this problem, we will be happy to ship you new buttons + if you think you can re-solder them yourself, or you can ship us + your board and we will swap out that part. + + For reference, the button part number is KMR211GLFS and the flux + remover we used is "Precision Electronics Cleaner" from RadioShack, + which is "Safe on most plastics" and contains Dipropylene glycol + monomethyl ether, hydrotreated heavy naphtha, dipropylene glycol + methyl ether acetate (really?), and carbon dioxide. + +* **Resistors on pins 0 and 1**: these header pins, which are RX/TX on + USART2 (:ref:`Serial2 `), have resistors in-line + between the STM32 and the headers. These resistors increase the + impedance of the lines for ADC reads and affect the open drain GPIO + functionality of the pins. + + These resistors were accidentally copied over from older Arduino USB + designs, where they appear to protect the USB-Serial converter from + TTL voltage on the headers. + +* **GPIO 39-43 not configured**: this is really more of a software + "TODO" item. Some of the JTAG header pins are numbered 39-43. These + STM32 pins are indeed fully functional :ref:`GPIO ` when the a + :ref:`JTAG ` device is not connected, but we have not enabled + them in software and thus they can not be accessed with the regular + :ref:`lang-pinmode` or :ref:`lang-digitalwrite` functions. + +* **Silkscreen Errors**: the silkscreen on the bottom indicated PWM + functionality on pin 25 and listen the external header GND pin as + number 38 (actually 38 is connected to the BUT button). We manually + sharpied over both of these mistakes. + +* **PWM Marketing Mistake**: We originally sold the Maple advertising + 22 channels of 16-bit hardware PWM; actually the Maple only has 15. + +Potential failure modes: + +* **TTL voltage on non-tolerant pins**: not all header pins are 5V + compatible; connecting certain serial devices in the wrong way could + over voltage the pins. The :ref:`Pin-Mapping Mega Table + ` details which pins are 5V-tolerant. + +Maple Rev 1 +^^^^^^^^^^^ + +Known issues: + +* **ADC noise**: generally very high, in particular when the USB port + is being used for communications (including keep-alive pings when + connected to a computer). + + This issue was resolved in Rev 3 with a 4-layer design and a + geometrically isolated ADC V\ :sub:`ref` plane. + +* **Resistors on pins 0 and 1**: these header pins, which are RX/TX on + USART2 (:ref:`Serial2 `), have resistors in-line + between the STM32 and the headers. These resistors increase the + impedance of the lines for ADC reads and affect the open drain GPIO + functionality of the pins. + + These resistors were accidentally copied over from older Arduino USB + designs, where they appear to protect the USB-Serial converter from + TTL voltage on the headers. + +* **Silkscreen Differences**: the pin numbering scheme on Rev 1 is + different from Rev 3, and thus Rev 3 software is difficult to use + with Rev 1 boards. Notably, the analog input bank is labeled A0-A4 + on Rev 1 but 15-20 on Rev 3, and the extra header bank does not have + a pinout table on the bottom. + +* **No BUT Button**: the BUT button, useful for serial bootloading, + was only added in Rev 3. As a workaround, you can directly short the + appropriate MCU pin to Vcc; see `this forum posting + `_. + +* **PWM Marketing Mistake**: We originally sold the Maple advertising + 22 channels of 16-bit hardware PWM; actually the Maple only has 15. + +Potential failure modes: + +* **TTL voltage on non-tolerant pins**: not all header pins are 5v + compatible; connecting certain serial devices in the wrong way could + over voltage the pins. The :ref:`Pin-Mapping Mega Table + ` details which pins are 5V-tolerant. + +Recommended Reading +------------------- + +* STMicro documentation for STM32F103RB microcontroller: + + * `Datasheet `_ (pdf) + * `Reference Manual `_ (pdf) + * `Programming Manual `_ (assembly language and register reference) + .. rubric:: Footnotes .. [#frev2_4] Revs 2 and 4 were prototypes that didn't pass internal testing. - diff --git a/docs/source/i2c.rst b/docs/source/i2c.rst index e2a7a04..15190a8 100644 --- a/docs/source/i2c.rst +++ b/docs/source/i2c.rst @@ -1,20 +1,8 @@ .. _i2c: -===== |i2c| ===== -.. FIXME update this documentation once you write the Wire library on -.. top of libmaple i2c. - -.. FIXME generalize Maple-specific documentation - -.. note:: - - The |i2c| interface is currently only available from the 'refactor' - branch of the github `libmaple - `_ repository. - |i2c| is a crude and easy-to-hack serial protocol that requires only two wires/channels for communication between many devices. Every message passed on the bus is between a *master* (who initiates the @@ -26,6 +14,8 @@ Higher level functionality, such as reading a particular register value, is achieved by writing to set the memory location then reading to pull out the data. +.. FIXME [Maple-specific values] + Note that the master/slave designation is on a message-by-message basis. The Maple can act as both a master (messages initiated by user code) and slave device (responding to requests via configurable @@ -37,8 +27,8 @@ interrupt handlers) at the same time. Hardware/Circuit Design ----------------------- -The Maple has two |i2c| ports. Port 1 (i2c1) has SDA on header D9 and -SCL on D5; Port 2 (i2c2) has SDA on D30 and SCL on D29. +The Maple has two |i2c| ports. Port 1 (I2C1) has SDA on header D9 and +SCL on D5; Port 2 (I2C2) has SDA on D30 and SCL on D29. The Maple reliably communicates with up to a 400kHz clock speed; this doesn't translate into a 400kbps data rate except in extreme cases @@ -60,16 +50,15 @@ oscilloscope to debug any issues. Function Reference ------------------ -The function API for |i2c| is not finished! See the `source code -`_ -for now. +Currently, only low-level support in :ref:`libmaple-i2c` exists. A +Wiring-style library is planned for a future release. SMBus ----- The STM32 microcontroller has hardware support for SMBus; we simply -have not written software for it. The SMBAL line for i2c1 is on header -D4 and for i2c2 is on D31. +have not written software for it. The SMBAL line for I2C1 is on header +D4 and for I2C2 is on D31. .. _i2c-recommended-reading: diff --git a/docs/source/index.rst b/docs/source/index.rst index 1d1a5be..9db5ff0 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -3,11 +3,13 @@ Maple Documentation Contents ============================ +.. FIXME [Maple-specific values] errata page links to Maple + Welcome! This is the Maple documentation index. If you just bought a Maple, you probably want to head to the :ref:`quickstart `. If you're having problems, check out the -:ref:`troubleshooting ` and :ref:`known problems -` pages. +:ref:`troubleshooting ` :ref:`known problems +` pages. Have fun! @@ -32,12 +34,12 @@ Have fun! Language Libraries - Arduino Compatibility + Arduino Compatibility libmaple Bootloader Troubleshooting - Known Problems Notes on GCC's ARM target + Complete Language Index .. _index-hardware: @@ -73,15 +75,3 @@ Have fun! .. hardware/maple-mini.rst .. hardware/maple-native.rst - -.. _index-reference: - -**Reference:** - -.. toctree:: - :maxdepth: 1 - - Technical Specifications - Complete Language Index - - diff --git a/docs/source/lang/cpp/arithmetic.rst b/docs/source/lang/cpp/arithmetic.rst index 7e8c3fc..26e2811 100644 --- a/docs/source/lang/cpp/arithmetic.rst +++ b/docs/source/lang/cpp/arithmetic.rst @@ -117,11 +117,8 @@ See Also -------- - The individual sizes (in bits) of various available types are - defined in `libmaple_types.h - `_\ - . + defined in :ref:`libmaple_types.h `. - :ref:`sizeof `\ () - .. include:: cc-attribution.txt diff --git a/docs/source/language-index.rst b/docs/source/language-index.rst index 531e72c..a064b3e 100644 --- a/docs/source/language-index.rst +++ b/docs/source/language-index.rst @@ -10,6 +10,9 @@ API references for documented libmaple functionality. The "C++ for Maple" pages are intended as a minimal reference/refresher for programmers familiar with the Arduino language. +**Looking for something else?** The low-level :ref:`libmaple library +interfaces ` are documented separately. + .. _index-language-index-cpp: .. _index-language-index-api: diff --git a/docs/source/language.rst b/docs/source/language.rst index ea841f5..111a1f1 100644 --- a/docs/source/language.rst +++ b/docs/source/language.rst @@ -28,14 +28,14 @@ Maple Language Reference The following table summarizes the available core language features. A more exhaustive index is available at the :ref:`language-index`. +.. FIXME mention Maple Native supports malloc(), free(), operator +.. new(), and operator delete(), when that is a true thing to say. + **Looking for something else?** - See the :ref:`libraries` for extra built-in libraries for dealing with different kinds of hardware. -.. FIXME mention Maple Native supports malloc(), free(), operator -.. new(), and operator delete(), when that is a true thing to say. - - If you're looking for something from the C standard library (like ``atoi()``, for instance): the :ref:`CodeSourcery GCC compiler ` used to compile your programs is configured to link @@ -43,6 +43,9 @@ A more exhaustive index is available at the :ref:`language-index`. use of any of its header files. However, dynamic memory allocation (``malloc()``, etc.) is not available. +- If you're looking for low-level details, see the :ref:`libmaple + ` reference page. + +--------------------------------------------+----------------------------------------------+---------------------------------------------------+ | Structure | Variables | Functions | | | | | @@ -273,7 +276,7 @@ Unimplemented Arduino Features ------------------------------ The following Wiring/Arduino features are currently unimplemented on -the Maple. However, they will be present in future versions: +the Maple. - `tone() `_ - `noTone() `_ @@ -299,16 +302,18 @@ programming ideas and C++. Note for C/C++ Hackers ---------------------- -This is a note for programmers comfortable with C or C++ (although, -you C programmers should remember that `C++ is not a superset of C -`_) who -want a better understanding of the differences between C++ and the -Wiring language. The good news is that the differences are relatively -few; Wiring is just a thin wrapper around C++. +This is a note for programmers comfortable with C or C++ who want a +better understanding of the differences between C++ and the Wiring +language. -Some potentially better news is that the Maple can be programmed using -a :ref:`standard Unix toolchain `, so if you'd rather -stick with :command:`gcc`, :command:`make`, and friends, you can. +The good news is that the differences are relatively few; Wiring is +just a thin wrapper around C++. Some potentially better news is that +the Maple can be programmed using a :ref:`standard Unix toolchain +`, so if you'd rather stick with :command:`gcc`, +:command:`make`, and friends, you can. If you're using the Unix +toolchain and want to skip past the Wiring conveniences and get +straight to registers, you are encouraged to move on to the +:ref:`libmaple` documentation. A *sketch* is the IDE's notion of a project; it consists of one or more files written in the Wiring language, which is mostly the same as @@ -334,9 +339,9 @@ work. As of |today|, Maple only has 20 KB RAM, anyway, so it's doubtful that static allocation is not what you want. The Wiring language also does not require you to define your own -``main`` method (in fact, it forbids you from doing so). Instead, you -are required to define two functions, ``setup`` and ``loop``, with -type signatures :: +``main`` method (in fact, we currently forbid you from doing so). +Instead, you are required to define two functions, ``setup`` and +``loop``, with type signatures :: void setup(void); void loop(void); @@ -351,26 +356,33 @@ parses the result to produce a list of all functions defined in the global scope. (We borrow this stage from the Arduino IDE, which in turn borrows it from Wiring. It uses regular expressions to parse C++, which is, of course, `Bad and Wrong -`_. An -upcoming rewrite of the IDE performs this preprocessing step -correctly, using a real parser. Until then, you have our apologies.) -The order in which the individual sketch files are concatenated is not -defined; it is unwise to write code that depends on a particular -ordering. +`_. In the +future, we'll do this correctly, using a better parser. Until then, +you have our apologies.) The order in which the individual sketch +files are concatenated is not defined; it is unwise to write code that +depends on a particular ordering. The concatenated sketch files are then appended onto a file which includes `WProgram.h -`_ +`_ (which includes the wirish and libmaple libraries, and declares ``setup()`` and ``loop()``), and then provides declarations for all the function definitions found in the previous step. At this point, -we have a file that is a valid C++ translation unit, but lacks a -``main()`` method. The final step of compilation provides this -method, which behaves roughly like:: +we have a file that is a valid C++ translation unit, but lacks +``main()``. The final step of compilation provides ``main()``, which +behaves roughly like:: int main(void) { + // Call libmaple's built-in initialization routines + init(); + + // Perform the user's initialization setup(); - while (true) loop(); + + // Call user loop() forever. + while (true) { + loop(); + } } (The truth is a little bit more complicated, but not by much). @@ -441,20 +453,19 @@ Which could plausibly be turned into the final source file :: } int main() { + init(); setup(); while (true) loop(); } -(Recall that it's legal C++ for a function to be declared multiple -times, as long as it's defined exactly once). - - Recommended Reading ------------------- * `newlib Documentation `_ -* STMicro documentation for STM32F103RB microcontroller: - * `Datasheet `_ (pdf) +* :ref:`libmaple Documentation ` + +* ST documentation: + * `Reference Manual `_ (pdf) * `Programming Manual `_ (assembly language and register reference) diff --git a/docs/source/libmaple.rst b/docs/source/libmaple.rst index 9faca03..375e821 100644 --- a/docs/source/libmaple.rst +++ b/docs/source/libmaple.rst @@ -5,37 +5,35 @@ ``libmaple`` ============ -.. image:: /_static/img/libmaple-screenshot-small.png - :align: center - :alt: libmaple screenshot - -`LeafLabs libmaple `_ is the low level library we -have developed for for the ARM Cortex-M3 chips manufactured by -STMicroelectronics used in the Maple boards (the `STM32F103x`_ -series). We found the generic peripheral libraries too painful to -build on top of, and reimplemented the functionality we needed in a -simpler (and less general) form. - -.. _libmaple-libmaple: http://github.com/leaflabs/libmaple -.. _STM32F103x: http://www.st.com/stonline/stappl/productcatalog/app?path=/pages/stcom/PcStComPartNumberSearch.searchPartNumber&search=stm32f103 - -This library is transparently included in the `Maple IDE -`_, but we develop it separately -using good old Unix command line tools and release it for advanced -users who might chafe at the "sketch" programming model of the -IDE. Included are some examples, a Makefile, and the compatibility -wrappers and code to imitate the Arduino programming library. - -**Check out the latest source**:: - - git clone git://github.com/leaflabs/libmaple.git - -.. TODO after finishing refactor: create, style, and host a pure -.. Doxygen libmaple reference docs. This implies determining a stable -.. API. - -.. **Table of contents:** - -.. .. toctree:: -.. :maxdepth: 2 +LeafLabs' libmaple (`source code on Github +`_) is the library we have +developed for the `STM32 `_ line of ARM Cortex M3 +microcontrollers. Its high-level interfaces are :ref:`largely +compatible ` with the AVR libraries written for +the `Arduino `_ and `Wiring +`_ development boards. + +libmaple is split into two pieces: a lower level layer written in pure +C, which we call *libmaple proper* (in the `libmaple/ +`_ +directory of the source repository), and the Wiring-style C++ API +written on top of it, called *Wirish* (in `wirish/ +`_). + +libmaple is bundled with the :ref:`Maple IDE `. However, we +develop it separately, and :ref:`release it standalone +` for advanced users who might chafe at the "sketch" +programming model of the IDE. + +As always, :ref:`patches are welcome `. + +**Contents:** + +.. toctree:: + :maxdepth: 1 + + libmaple/overview + libmaple/apis + libmaple/contributing + libmaple/coding-standard diff --git a/docs/source/libmaple/api/adc.rst b/docs/source/libmaple/api/adc.rst new file mode 100644 index 0000000..8817055 --- /dev/null +++ b/docs/source/libmaple/api/adc.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-adc: + +``adc.h`` +========= + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: adc.h diff --git a/docs/source/libmaple/api/bitband.rst b/docs/source/libmaple/api/bitband.rst new file mode 100644 index 0000000..fd57944 --- /dev/null +++ b/docs/source/libmaple/api/bitband.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-bitband: + +``bitband.h`` +============= + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: bitband.h diff --git a/docs/source/libmaple/api/bkp.rst b/docs/source/libmaple/api/bkp.rst new file mode 100644 index 0000000..9a697c7 --- /dev/null +++ b/docs/source/libmaple/api/bkp.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-bkp: + +``bkp.h`` +========= + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: bkp.h diff --git a/docs/source/libmaple/api/dac.rst b/docs/source/libmaple/api/dac.rst new file mode 100644 index 0000000..038753b --- /dev/null +++ b/docs/source/libmaple/api/dac.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-dac: + +``dac.h`` +========= + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: dac.h diff --git a/docs/source/libmaple/api/delay.rst b/docs/source/libmaple/api/delay.rst new file mode 100644 index 0000000..a0d013a --- /dev/null +++ b/docs/source/libmaple/api/delay.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-delay: + +``delay.h`` +=========== + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: delay.h diff --git a/docs/source/libmaple/api/dma.rst b/docs/source/libmaple/api/dma.rst new file mode 100644 index 0000000..1512d0c --- /dev/null +++ b/docs/source/libmaple/api/dma.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-dma: + +``dma.h`` +========= + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: dma.h diff --git a/docs/source/libmaple/api/exti.rst b/docs/source/libmaple/api/exti.rst new file mode 100644 index 0000000..2909aa7 --- /dev/null +++ b/docs/source/libmaple/api/exti.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-exti: + +``exti.h`` +========== + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: exti.h diff --git a/docs/source/libmaple/api/flash.rst b/docs/source/libmaple/api/flash.rst new file mode 100644 index 0000000..6f2f9d3 --- /dev/null +++ b/docs/source/libmaple/api/flash.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-flash: + +``flash.h`` +=========== + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: flash.h diff --git a/docs/source/libmaple/api/fsmc.rst b/docs/source/libmaple/api/fsmc.rst new file mode 100644 index 0000000..cecfc99 --- /dev/null +++ b/docs/source/libmaple/api/fsmc.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-fsmc: + +``fsmc.h`` +========== + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: fsmc.h diff --git a/docs/source/libmaple/api/gpio.rst b/docs/source/libmaple/api/gpio.rst new file mode 100644 index 0000000..2cfec23 --- /dev/null +++ b/docs/source/libmaple/api/gpio.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-gpio: + +``gpio.h`` +========== + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: gpio.h diff --git a/docs/source/libmaple/api/i2c.rst b/docs/source/libmaple/api/i2c.rst new file mode 100644 index 0000000..14dd304 --- /dev/null +++ b/docs/source/libmaple/api/i2c.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-i2c: + +``i2c.h`` +========= + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: i2c.h diff --git a/docs/source/libmaple/api/iwdg.rst b/docs/source/libmaple/api/iwdg.rst new file mode 100644 index 0000000..3911ece --- /dev/null +++ b/docs/source/libmaple/api/iwdg.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-iwdg: + +``iwdg.h`` +========== + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: iwdg.h diff --git a/docs/source/libmaple/api/libmaple.rst b/docs/source/libmaple/api/libmaple.rst new file mode 100644 index 0000000..d4f28f0 --- /dev/null +++ b/docs/source/libmaple/api/libmaple.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-libmaple: + +``libmaple.h`` +============== + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: libmaple.h diff --git a/docs/source/libmaple/api/libmaple_types.rst b/docs/source/libmaple/api/libmaple_types.rst new file mode 100644 index 0000000..bbea2c1 --- /dev/null +++ b/docs/source/libmaple/api/libmaple_types.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-libmaple_types: + +``libmaple_types.h`` +==================== + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: libmaple_types.h diff --git a/docs/source/libmaple/api/nvic.rst b/docs/source/libmaple/api/nvic.rst new file mode 100644 index 0000000..b94dc31 --- /dev/null +++ b/docs/source/libmaple/api/nvic.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-nvic: + +``nvic.h`` +========== + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: nvic.h diff --git a/docs/source/libmaple/api/pwr.rst b/docs/source/libmaple/api/pwr.rst new file mode 100644 index 0000000..82e4864 --- /dev/null +++ b/docs/source/libmaple/api/pwr.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-pwr: + +``pwr.h`` +========= + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: pwr.h diff --git a/docs/source/libmaple/api/rcc.rst b/docs/source/libmaple/api/rcc.rst new file mode 100644 index 0000000..81dc604 --- /dev/null +++ b/docs/source/libmaple/api/rcc.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-rcc: + +``rcc.h`` +========= + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: rcc.h diff --git a/docs/source/libmaple/api/ring_buffer.rst b/docs/source/libmaple/api/ring_buffer.rst new file mode 100644 index 0000000..a014fa4 --- /dev/null +++ b/docs/source/libmaple/api/ring_buffer.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-ring_buffer: + +``ring_buffer.h`` +================= + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: ring_buffer.h diff --git a/docs/source/libmaple/api/scb.rst b/docs/source/libmaple/api/scb.rst new file mode 100644 index 0000000..78cc7eb --- /dev/null +++ b/docs/source/libmaple/api/scb.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-scb: + +``scb.h`` +========= + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: scb.h diff --git a/docs/source/libmaple/api/spi.rst b/docs/source/libmaple/api/spi.rst new file mode 100644 index 0000000..b0c7e86 --- /dev/null +++ b/docs/source/libmaple/api/spi.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-spi: + +``spi.h`` +========= + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: spi.h diff --git a/docs/source/libmaple/api/stm32.rst b/docs/source/libmaple/api/stm32.rst new file mode 100644 index 0000000..2784540 --- /dev/null +++ b/docs/source/libmaple/api/stm32.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-stm32: + +``stm32.h`` +=========== + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: stm32.h diff --git a/docs/source/libmaple/api/systick.rst b/docs/source/libmaple/api/systick.rst new file mode 100644 index 0000000..5ec906c --- /dev/null +++ b/docs/source/libmaple/api/systick.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-systick: + +``systick.h`` +============= + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: systick.h diff --git a/docs/source/libmaple/api/timer.rst b/docs/source/libmaple/api/timer.rst new file mode 100644 index 0000000..3acbf4f --- /dev/null +++ b/docs/source/libmaple/api/timer.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-timer: + +``timer.h`` +=========== + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: timer.h diff --git a/docs/source/libmaple/api/usart.rst b/docs/source/libmaple/api/usart.rst new file mode 100644 index 0000000..26e6b9c --- /dev/null +++ b/docs/source/libmaple/api/usart.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-usart: + +``usart.h`` +=========== + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: usart.h diff --git a/docs/source/libmaple/api/util.rst b/docs/source/libmaple/api/util.rst new file mode 100644 index 0000000..50ffe76 --- /dev/null +++ b/docs/source/libmaple/api/util.rst @@ -0,0 +1,12 @@ +.. highlight:: c +.. _libmaple-util: + +``util.h`` +========== + +[Stub] support. + +Library Documentation +--------------------- + +.. doxygenfile:: util.h diff --git a/docs/source/libmaple/apis.rst b/docs/source/libmaple/apis.rst new file mode 100644 index 0000000..f493406 --- /dev/null +++ b/docs/source/libmaple/apis.rst @@ -0,0 +1,14 @@ +.. _libmaple-apis: + +APIs +==== + +This is the master index for libmaple proper's APIs. + +**Contents** + +.. toctree:: + :maxdepth: 1 + :glob: + + api/* diff --git a/docs/source/libmaple/coding-standard.rst b/docs/source/libmaple/coding-standard.rst new file mode 100644 index 0000000..23d20f8 --- /dev/null +++ b/docs/source/libmaple/coding-standard.rst @@ -0,0 +1,412 @@ +.. _libmaple-coding-standard: + +Coding Standard +=============== + +This page documents the coding standard for :ref:`libmaple`. It's +intended as a guide for how you should structure any code you would +like included into the LeafLabs releases of libmaple. + +LeafLabs team members are required to follow these when producing new +code. Community contributors to libmaple are strongly encouraged to +do so; following these rules will greatly increase the probability +that your patches will be folded in. + +In general, follow this guide unless there's a very good reason not +to. Laziness doesn't count as a good reason. Most, if not all, of +these decisions are entirely arbitrary, but it's important for +readability that we be consistent. (If you notice an inconsistency, +you should fix it). + +Note that the file ``.dir-locals.el`` in the libmaple root directory +already ensures that many of these standards are followed by default +in Emacs (but not on Windows, where it would need to be named +``_dir_locals.el``, and no way, man). There's also some elisp +scattered about this file which will provide you additional help. + +Vim customizations to do the same thing would be nice! + +.. contents:: Contents + :local: + +License +------- + +.. highlight:: scheme + +Put an MIT license at the beginning of the file (look at any of our +source files for an example). Copyright should go either to you or to +LeafLabs, LLC. + +Emacs: if you don't like seeing the license, you should use elide-head +(which will hide it for you). You can use the following:: + + (require 'elide-head) + (setq programming-mode-hooks '(c-mode-hook c++-mode-hook)) + (add-to-list 'elide-head-headers-to-hide + '("The MIT License" . "DEALINGS IN\n [*] THE SOFTWARE")) + (add-to-list 'elide-head-headers-to-hide + '("The MIT License" . "DEALINGS IN THE\n...SOFTWARE")) + (dolist (hook programming-mode-hooks) + (add-hook hook (lambda () (elide-head)))) + +Whitespace +---------- + +- 4 space indents (set in ``.dir-locals.el``). + +- Unix newlines. Some exceptions are currently grandfathered in; these + will go away in time. + +- No tab characters (set in ``.dir-locals.el``). + +- No trailing whitespace. For help getting this (and no tab + characters) done automatically in Emacs, you can use + `code-fascism.el `_. + +- Files end in exactly one newline. The presence of a newline at EOF + is already done by ``c-require-final-newline`` in recent versions of + Emacs. + +- Exactly two newlines separate source paragraphs (you do separate + your code into paragraphs, don't you?). + +- The first line in a function is non-blank. + +.. highlight:: cpp + +- Exactly one space after ``if``, ``else``, ``for``, and ``while``, + before the following ``{`` or ``(``. One space before ``else``, + after the preceding ``}``. For example:: + + // This is good; we like this: + if (foo) { + while (quux) { + bar(); + } + } else { + baz(); + } + + // THIS IS BAD! DON'T DO THIS: + if(foo){ + while(quux){ + bar(); + } + }else{ + baz(); + } + +- Exactly one space in between binary arithmetic, logical, and + comparison operators and their operands. Examples:: + + // This is good: + int x = a + b * (c - d); + if (x != 0 && a > 7) { + SerialUSB.println(x); + } + + // THIS IS BAD! + int x = a+b*(c-d); + if (x!=0 && a>7) { + SerialUSB.println(x); + } + + // This is good: + uint32 adc_data = ADC1_BASE->DR; + SerialUSB.println(adc_data); + + // THIS IS BAD! + uint32 adc_data = ADC1_BASE -> DR; + SerialUSB . println(adc_data); + +- No space between a unary operator and its operand. Examples:: + + // Good: + x++; + + // BAD! + x ++; + + // Good: + y = -x; + + // BAD! + y = - x; + +- If you need to break up a long line: + + * Prefer to break up long expressions after a binary operator. Example:: + + // Good: + if (some_really_long_conditional_wow_this_really_goes_on_forever || + maybe_something_else_could_happen_too) { + ... + } + + // BAD! + if (some_really_long_conditional_wow_this_really_goes_on_forever + || maybe_something_else_could_happen_too) { + ... + } + + * When breaking up a function's arguments over multiple lines, align + the arguments on subsequent lines with the first argument. + Example:: + + // Good: + return_type value_i_got = function_with_a_really_long_name(argument1, + argument2, + argument3); + + // BAD! + return_type value_i_got = function_with_a_really_long_name(argument1, + argument2, + argument3); + + // BAD! + return_type value_i_got = function_with_a_really_long_name(argument1, + argument2, + argument3); + +- In function invocations, no space in between the function name and + the opening parenthesis. Example:: + + // Good: + SerialUSB.println("Hello, world!"); + + // BAD! + SerialUSB.println ("Hello, world!"); + +- Don't indent C code within a conditionally-compiled ``extern "C"`` + block. Example:: + + // Good: + #ifdef __cplusplus + extern "C"{ + #endif + + void some_c_function(void); + + #ifdef __cplusplus + } // extern "C" + #endif + + // BAD! + #ifdef __cplusplus + extern "C"{ + #endif + + void some_c_function(void); + + #ifdef __cplusplus + } // extern "C" + #endif + + Emacs does the "bad" behavior by default, which can be very + annoying. You can turn this off with :: + + (defun c-mode-inextern-lang-hook () + (setcdr (assq 'inextern-lang c-offsets-alist) '-)) + (add-hook 'c-mode-hook c-mode-inextern-lang-hook) + +Comments +-------- + +.. highlight:: c++ + +- Multi-line comments are pretty flexible. Any of these is fine:: + + /* Comment starts here. + * Continued lines have a '*' before them. + * The comment can end after the last line. + */ + + /* Comment starts here. + * The comment can end on the same line. */ + + /* + * You can also place a newline after the opening "/*". + */ + +- Doxygen comments are multi-line comments that begin with ``/**`` + instead. + +- Single-line comments are up to you. + +Braces +------ + +- Mostly `1TBS + `_. The + only difference is that the opening brace of a function's definition + occurs exactly one space character after the closing parenthesis in + that function's parameter list. Example:: + + void func(void) { + ... + } + +Naming conventions +------------------ + +We'll handle the usual casing/underscore debate as follows. + +- First, ``Dont_Mix_Like_This``, because ``It_Looks_Really_Ugly``, ok? + [There's been some debate about this, and some exceptions are + already grandfathered in, so in order to settle it, let's call this + a "recommendation" instead of "requirement".] + +- Variables: Use underscores to separate words in C identifiers:: + + int some_example_name; + + User-facing C++ variables should be camel cased + (``thisIsAnExample``, ``boardPWMPins``, etc.), for consistency with + the Arduino style. It's probably a good idea for you to case + non-user facing C++ variables in the C style; this will help + disambiguate what's part of the Wirish API and what's not. + +- Classes: Pascal case. So ``ThisIsAClassName``, but ``thisIsNot``, + ``this_is_not``, and ``Dont_You_DareTryANYTHING_STUPID``. + +- Functions: C functions are all lowercase, and words are separated by + underscores. C++ method names are camel cased. + +- Structs: Usually like variables (``adc_dev``, ``adc_reg_map``, + etc.), but it's not crucial. Don't feel obliged to put ``_t`` at + the end of the type name; we don't. + +- Macros and constants: all caps, separated by underscores. C++ + variables with the ``const`` qualifier generally aren't considered + "constants" for the purposes of this rule; i.e., they are cased + according to the rules for variables. We make an exception for + ``PIN_MAP``, because it's the central Wirish data structure. + +- foo.h gets ``#ifdef``\ 'ed to ``_FOO_H_``. + +- Acronyms: The case of letters in an acronym is determined by the + case of the first letter in the acronym, which is determined by + following the above rules. Examples:: + + // Good: + void usb_func() { ... } + void frob_usb_disc() { ... } + class SomethingUSB { + void usbInit(); + void initUSB(); + }; + + // BAD: + class BadUsb { ... }; // say "GoodUSB" instead + void swizzle_USB_disc() { ... } // say "swizzle_usb_disc" instead + +Documentation +------------- + +- Doxygen comments on every user-facing function and type. + Additionally, individually document the fields and enumerator values + of nontrivial user-facing structs and enums. See any register map + type's definition for an example. + +- For libmaple proper, you don't need comments for each register bit + definition, since that's just repeating information better obtained + by reading ST RM0008. + +- Doxygen comments generally only belong on types, functions, + etc. that are part of the public user-facing API. This generally + means that if there's ReST documentation for it under libmaple's + ``docs/source/``, it needs Doxygen comments, and that ReST should + use Breathe to pull that Doxygen comment out. (For more information + on this, see libmaple file ``docs/README``). + + There are some exceptions to this rule since Breathe isn't totally + mature yet and Sphinx's C++ domain is still in flux. In these + cases, document the code "manually" in ReST. + + This should be avoided if at all possible, since it creates a + maintenance burden of documenting things in two places at once, and + makes it easier for documentation to go stale. + + If you do have to document something manually, put a comment in the + source file informing future maintainers about it, so they'll pay + extra attention when making changes. + +- When adding peripheral support, it would be nice if you put + longer-form comments into the libmaple ``notes/`` directory, with a + comment in the corresponding .h file referring to it. See the + :ref:`dac.h ` source for an example. + + This lets us keep the source files relatively free of "introductory" + material, while allowing new readers a convenient starting point. + These longer-form notes also have a habit of turning into official, + user-facing documentation. + +- **For libmaple proper**, the convention is to document any + user-facing function at the point where it is defined. In + particular, this means you should document an externally-linked + function defined in a .c file in that .c file, not in the header + file where it is declared to the user. + + **For Wirish**, the convention is to put the documentation in the + header file where the function is declared. + +General Formatting +------------------ + +.. highlight:: scheme + +- Keep it 80-column clean. + + Emacs users: this means that the largest column number is 79. You + should turn on column number mode to help you out:: + + (column-number-mode 1) + + You can get more help from `lineker-mode + `_. Just put + lineker.el somewhere in your load-path, and:: + + (require 'lineker) + (dolist (hook '(c-mode-hook c++-mode-hook)) + (add-hook hook (lambda () (lineker-mode 1)))) + +.. highlight:: cpp + +Language Features +----------------- + +In libmaple proper, aim for C99 compatibility. Some GCC extensions +are OK, but `don't get crazy `_. + +Explicitly approved GCC extensions: + + * `asm volatile `_ + + * `Nested functions `_ + +In Wirish, generally be very conservative when using C++ features that +aren't part of C. We are forced to use C++ for Arduino compatibility +(and the general Arduino style of conflating objects and libraries), +but it's an angry beast, and we don't want to provoke it. **The +mantra is "C with classes"**. + +Explicitly approved C++ features: + + * Initializers that aren't constant; e.g. the ``gpio_dev*`` values + in a ``PIN_MAP``. + + * Default arguments: e.g., the timeout argument in + :ref:`lang-waitforbuttonpress`. + +Explicitly forbidden C++ features: + + * Templates + +Conditionally allowed C++ features: + + * Operator overloading: Never allowed when it's just for style. + Probably fine when you're implementing a class that models a + mathematical structure, and you'd like to implement + e.g. ``operator+()``. + diff --git a/docs/source/libmaple/contributing.rst b/docs/source/libmaple/contributing.rst new file mode 100644 index 0000000..724605b --- /dev/null +++ b/docs/source/libmaple/contributing.rst @@ -0,0 +1,113 @@ +.. _libmaple-contributing: + +Contributing to libmaple +======================== + +First of all, thanks! Community contributions are what makes open +source great. + +If your patch is minor (you've found a typo, you've added a new +function, etc.), feel free to just make a `forum post +`_ describing your changes. + +If your changes are larger (you wrote a new library, you added support +for a new peripheral, etc.), we'd prefer you submit a pull request on +Github or send us a nicely-formatted patch via email. + +.. contents:: Contents + :local: + +.. _libmaple-faq-patches-preparing: + +Preparing Your Patch +-------------------- + +Before submitting a patch, please make sure it complies with the +:ref:`coding standard `. Consistent style throughout +the source tree is an important implementation objective for us, and a +patch that doesn't comply with the coding standard we've set forth is +likely to be sent back until it follows the standard. + +We would prefer if you release each new file you submit under the `MIT +license `_. See +e.g. `bkp.h +`_ +for an example, and the coding standard for more details. Code +released under the `Lesser GPL +`_ may be accepted for +Wirish, but will almost certainly be rejected for libmaple proper. We +will not accept patches released under the `GPL +`_. + +**We're not against the GPL**! It just doesn't suit our purposes for +libmaple. If you're interested in a GPLed library for ST +microcontrollers, check out `libopenstm32 +`_. +Also note that :ref:`libraries ` released under the GPL are +fine, we just don't want any core libmaple or Wirish code to be GPLed. + +.. _libmaple-faq-patches-github: + +Submitting Via Github Pull Request (Preferred) +---------------------------------------------- + +The most convenient way for you to contribute patches is to submit a +pull request on `Github `_. Github provides +excellent code review interfaces, which will make it easy for us at +LeafLabs to communicate with you (and each other) about your patch. +It also makes it easy for us to merge your patch into the libmaple +source tree when the time comes. + +The steps to submit a pull request are as follows: + +1. If you don't already have one, get a `Github account + `_ (free). + +2. Fork libmaple, then clone your fork to the computer you code on. + Github provides detailed instructions on `forking and cloning a + repository `_. + +3. Push your commits to your Github libmaple fork (see instructions + linked in Step 2 for a step-by-step walkthrough on how to do this). + +4. `Submit a pull request `_ to + the LeafLabs version of libmaple. + +.. _libmaple-faq-patches-email: + +Submitting Via Email +-------------------- + +If you're unfamiliar with Git or would prefer not to use Github, you +can always send us a patch via email at info@leaflabs.com. We'd love +it if you used the `Linux kernel patch format +`_, but please at least include +the following information in your email: + +1. How you generated your patch (arguments to ``diff``, etc.) + +2. What git branch/commit or libmaple version your patch applies to + +3. A one-line summary of your changes, along with any other details + you think we should know. + +4. A sign-off line certifying your `developer certificate of origin + `_. + +That said, we'd really prefer a pull request. If you'd like to learn +more about Git, we recommend the following resources: + +* `The Git Community Book `_: A + collaboratively edited book on Git. + +* `Pro Git `_: despite its title, this is a + fairly beginner-friendly source of information. + +* `Understanding Git Conceptually + `_: a good, + introductory tutorial on Git's fundamental concepts. + +* `Git for Computer Scientists + `_: if + you're comfortable with directed acyclic graphs, this resource + explains Git's functionality in graph-theoretic terms. diff --git a/docs/source/libmaple/overview.rst b/docs/source/libmaple/overview.rst new file mode 100644 index 0000000..9bce564 --- /dev/null +++ b/docs/source/libmaple/overview.rst @@ -0,0 +1,342 @@ +.. highlight:: c + +.. _libmaple-overview: + +Overview +======== + +This page is a general overview of the low-level aspects of libmaple +proper. It provides a general perspective of the library's goals and +design. Examples are given from the libmaple sources. + +.. contents:: Contents + :local: + +Design Goals +------------ + +The central goal of the libmaple project is to provide a pleasant, +consistent set of interfaces for dealing with the various peripherals +on the STM32 line. + +Let's start with the basics. If you're interested in low-level details +on the STM32, then you're going to spend a lot of quality time wading +through `ST RM0008 +`_. +RM0008 is the single most important tool in your toolbox. It is the +authoritative documentation for the capabilities and low-level +programming interfaces of ST's line of ARM Cortex M3 microcontrollers. + +Perhaps you haven't read it in detail, but maybe you've at least +thumbed through a few of the sections, trying to gain some +understanding of what's going on. If you've done that (and if you +haven't, just take our word for it), then you know that underneath the +covers, *everything* is controlled by messing with bits in the +seemingly endless collections of registers specific to every +peripheral. The `USARTs `_ have +data registers; (some of the) the `timers +`_ have capture/compare +registers, the `GPIOs `_ have +output data registers, etc. + +For the most part, Wirish does everything it can to hide this truth +from you. That's because when you really just want to get your robot +to fly, your LEDs to blink, or your `FM synthesizer +`_ to, well, `synthesize +`_, you probably couldn't care +less about messing with registers. + +That's fine! In fact, it's our explicit goal for Wirish to be good +enough that most people never need to know libmaple proper even +exists. We want to make programming our boards as easy as possible, +after all. But the day may come when you want to add a library for an +as-yet unsupported peripheral, or you want to do something we didn't +anticipate, or you'd like to squeeze a little more speed out of a +critical section in your program. Or maybe you're just curious! + +If anything in the above paragraph describes you, then you'll find +that you need a way to translate your knowledge of RM0008 into +software. We imagine (if you're anything like us) you want to spend +the least amount of time you possibly can doing that +translation. Ideally, once you've finished your design, you want some +way to start reading and writing code right away, without having to +bushwhack your way through a thicket of clunky APIs. + +The central abstractions we've chosen to accomplish the above goals +are *register maps* and *devices*. Register maps are just structs +which encapsulate the layout of the IO-mapped memory regions +corresponding to a peripheral's registers. Devices encapsulate a +peripheral's register map as well as any other necessary information +needed to operate on it. Peripheral support routines generally +operate on devices rather than register maps. + +Devices +------- + +At the highest level, you'll be dealing with *devices*, where a +"device" is a general term for any particular piece of hardware you +might encounter. So, for example, an analog to digital converter is a +device. So is a USART. So is a GPIO port. In this section, we'll +consider some hypothetical "xxx" device. + +The first thing you need to know is that the header file for dealing +with xxx devices is, naturally enough, called ``xxx.h``. So if you +want to interface with the :ref:`ADCs `, just ``#include +"adc.h"``. + +Inside of ``xxx.h``, there will be a declaration for a ``struct +xxx_dev`` type. This type encapsulates all of the information we keep +track of for that xxx. So, for example, in ``adc.h``, there's a +``struct adc_dev``:: + + /** ADC device type. */ + typedef struct adc_dev { + adc_reg_map *regs; /**< Register map */ + rcc_clk_id clk_id; /**< RCC clock information */ + } adc_dev; + +The ADCs aren't particularly complicated. All we keep track of for an +ADC device is a pointer to its register map (which keeps track of all +of its registers' bits; see :ref:`below ` +for more details), and an identifying piece of information which tells +the RCC (reset and clock control) interface how to turn the ADC on and +reset its registers to their default values. + +The timers on the STM32 line are more involved than the ADCs, so a +``timer_dev`` has to keep track of a bit more information:: + + /** Timer device type */ + typedef struct timer_dev { + timer_reg_map_union regs; + rcc_clk_id clk_id; + timer_type type; + voidFuncPtr handlers[]; + } timer_dev; + +However, as you can see, both ADC and timer devices are named +according to a single scheme, and store similar information. + +``xxx.h`` will also declare pointers to the actual devices you need to +deal with, called ``XXX1``, ``XXX2``, etc. (or just ``XXX``, if +there's only one) [#fgpio]_. For instance, on the Maple's +microcontroller (the STM32F103RBT6), there are two ADCs. +Consequently, in ``adc.h``, there are declarations for dealing with +ADC devices one and two:: + + extern const adc_dev *ADC1; + extern const adc_dev *ADC2; + +In general, each device needs to be initialized before it can be used. +libmaple provides this initialization routine for each peripheral +``xxx``; its name is ``xxx_init()``. These initialization routines +turn on the clock to a device, and restore its register values to +their default settings. Here are a few examples:: + + /* From dma.h */ + void dma_init(dma_dev *dev); + + /* From gpio.h */ + void gpio_init(gpio_dev *dev); + void gpio_init_all(void); + +Note that, sometimes, there will be an additional initialization +routine for all available peripherals of a certain kind. + +Many peripherals also need additional configuration before they can be +used. These functions are usually called something along the lines of +``xxx_enable()``, and often take additional arguments which specify a +particular configuration for the peripheral. Some examples:: + + /* From usart.h */ + void usart_enable(usart_dev *dev); + + /* From i2c.h */ + void i2c_master_enable(i2c_dev *dev, uint32 flags); + +After you've initialized, and potentially enabled, your peripheral, it +is now time to begin using it. The file ``xxx.h`` contains other +convenience functions for dealing with xxx devices. For instance, +here are a few from ``adc.h``:: + + void adc_set_sample_rate(const adc_dev *dev, adc_smp_rate smp_rate); + uint32 adc_read(const adc_dev *dev, uint8 channel); + +We aim to enable libmaple's users to interact with peripherals through +devices as much as possible, rather than having to break the +abstraction and consider individual registers. However, there will +always be a need for low-level access. To allow for that, libmaple +provides *register maps* as a consistent set of names and abstractions +for dealing with registers and their bits. + +.. _libmaple-overview-regmaps: + +Register Maps +------------- + +A *register map* is just a C struct which names and provides access to +a peripheral's registers. These registers are usually mapped to +contiguous regions of memory (though at times unusable or reserved +regions exist between a peripheral's registers). Here's an example +register map, from ``dac.h`` (``__io`` is just libmaple's way of +saying ``volatile`` when referring to register values):: + + /** DAC register map. */ + typedef struct dac_reg_map { + __io uint32 CR; /**< Control register */ + __io uint32 SWTRIGR; /**< Software trigger register */ + __io uint32 DHR12R1; /**< Channel 1 12-bit right-aligned data + holding register */ + __io uint32 DHR12L1; /**< Channel 1 12-bit left-aligned data + holding register */ + __io uint32 DHR8R1; /**< Channel 1 8-bit left-aligned data + holding register */ + __io uint32 DHR12R2; /**< Channel 2 12-bit right-aligned data + holding register */ + __io uint32 DHR12L2; /**< Channel 2 12-bit left-aligned data + holding register */ + __io uint32 DHR8R2; /**< Channel 2 8-bit left-aligned data + holding register */ + __io uint32 DHR12RD; /**< Dual DAC 12-bit right-aligned data + holding register */ + __io uint32 DHR12LD; /**< Dual DAC 12-bit left-aligned data + holding register */ + __io uint32 DHR8RD; /**< Dual DAC 8-bit left-aligned data holding + register */ + __io uint32 DOR1; /**< Channel 1 data output register */ + __io uint32 DOR2; /**< Channel 2 data output register */ + } dac_reg_map; + + +There are two things to notice here. First, if RM0008 names a +register ``DAC_FOO``, then ``dac_reg_map`` has a field named ``FOO``. +So, the Channel 1 12-bit right-aligned data register (RM0008: +DAC_DHR12R1) is the ``DHR12R1`` field in a ``dac_reg_map``. Second, +if RM0008 describes a register as "Foo bar register", the +documentation for the corresponding field has the same description. +This consistency makes it easy to search for a particular register, +and, if you see one used in a source file, to feel sure about what's +going on just based on its name. + +So let's say you've included ``xxx.h``, and you want to mess with some +particular register. What's the name of the ``xxx_reg_map`` variable +you want? That depends on if there's more than one xxx or not. If +there's only one xxx, then libmaple guarantees there will be a +``#define`` that looks like like this:: + + #define XXX_BASE ((xxx_reg_map*)0xDEADBEEF) + +That is, you're guaranteed there will be a pointer to the (only) +``xxx_reg_map`` you want, and it will be called +``XXX_BASE``. (``0xDEADBEEF`` is the register map's *base address*, or +the fixed location in memory where the register map begins). Here's a +concrete example from ``dac.h``:: + + #define DAC_BASE ((dac_reg_map*)0x40007400) + +How can you use these? This is perhaps best explained by example. + +* In order to write 2048 to the channel 1 12-bit left-aligned data + holding register (RM0008: DAC_DHR12L1), you could write:: + + DAC_BASE->DHR12L1 = 2048; + +* In order to read the DAC control register, you could write:: + + uint32 cr = DAC_BASE->CR; + +The microcontroller takes care of converting reads and writes from a +register's IO-mapped memory regions into reads and writes to the +corresponding hardware registers. + +That covers the case where there's a single xxx peripheral. If +there's more than one (say, if there are *n*), then ``xxx.h`` provides +the following:: + + #define XXX1_BASE ((xxx_reg_map*)0xDEADBEEF) + #define XXX2_BASE ((xxx_reg_map*)0xF00DF00D) + ... + #define XXXn_BASE ((xxx_reg_map*)0x13AF1AB5) + +Here's a concrete example from ``adc.h``:: + + /** ADC1 register map base pointer. */ + #define ADC1_BASE ((adc_reg_map*)0x40012400) + /** ADC2 register map base pointer. */ + #define ADC2_BASE ((adc_reg_map*)0x40012800) + /** ADC3 register map base pointer. */ + #define ADC3_BASE ((adc_reg_map*)0x40013C00) + +In order to read from the ADC1's regular data register (where the +results of ADC conversion are stored), you might write:: + + uint32 converted_result = ADC1->DR; + +Register Bit Definitions +------------------------ + +In ``xxx.h``, there will also be a variety of #defines for dealing +with interesting bits in the xxx registers, called *register bit +definitions*. These are named according to the scheme +``XXX_REG_FIELD``, where "``REG``" refers to the register, and +"``FIELD``" refers to the bit or bits in ``REG`` that are special. + +.. TODO image of the bit layout of a DMA_CCR register + +Again, this is probably best explained by example. Each Direct Memory +Access (DMA) controller's register map has a certain number of channel +configuration registers (RM0008: DMA_CCRx). In each of these channel +configuration registers, bit 14 is called the ``MEM2MEM`` bit, and +bits 13 and 12 are the priority level (``PL``) bits. Here are the +register bit definitions for those fields:: + + /* From dma.h */ + + #define DMA_CCR_MEM2MEM_BIT 14 + #define DMA_CCR_MEM2MEM BIT(DMA_CCR_MEM2MEM_BIT) + #define DMA_CCR_PL (0x3 << 12) + #define DMA_CCR_PL_LOW (0x0 << 12) + #define DMA_CCR_PL_MEDIUM (0x1 << 12) + #define DMA_CCR_PL_HIGH (0x2 << 12) + #define DMA_CCR_PL_VERY_HIGH (0x3 << 12) + +Thus, to check if the ``MEM2MEM`` bit is set in DMA controller 1's +channel configuration register 2 (RM0008: DMA_CCR2), you can write:: + + if (DMA1_BASE->CCR2 & DMA_CCR_MEM2MEM) { + /* MEM2MEM is set */ + } + +Certain register values occupy multiple bits. For example, the +priority level (PL) of a DMA channel is determined by bits 13 and 12 +of the corresponding channel configuration register. As shown above, +libmaple provides several register bit definitions for masking out the +individual PL bits and determining their meaning. For example, to +check the priority level of a DMA transfer, you can write:: + + switch (DMA1_BASE->CCR2 & DMA_CCR_PL) { + case DMA_CCR_PL_LOW: + /* handle low priority case */ + case DMA_CCR_PL_MEDIUM: + /* handle medium priority case */ + case DMA_CCR_PL_HIGH: + /* handle high priority case */ + case DMA_CCR_PL_VERY_HIGH: + /* handle very high priority case */ + } + +Of course, before doing that, you should check to make sure there's +not already a device-level function for performing the same task! + +What Next? +---------- + +After you've read this page, you can proceed to the :ref:`libmaple API +listing `. From there, you can read documentation and +follow links to the current source code for those files on `libmaple's +Github page `_. + +.. rubric:: Footnotes + +.. [#fgpio] For consistency with RM0008, GPIO ports are given letters + instead of numbers (``GPIOA`` and ``GPIOB`` instead of + ``GPIO1`` and ``GPIO2``, etc.). diff --git a/docs/source/maple-ide-install.rst b/docs/source/maple-ide-install.rst index 5c79d41..beba54d 100644 --- a/docs/source/maple-ide-install.rst +++ b/docs/source/maple-ide-install.rst @@ -41,9 +41,9 @@ correct version for your operating system: The package bundles together a compiler, an upload utility, a software library, and a simple GUI text editor. All this software is `free and -open `_; we are grateful to the `Arduino +open `_; we are grateful to the `Arduino `_, `CodeSourcery -`_, `GNU `_, and +`_, `GNU `_, and `OpenMoko `_ developers, as well as many others, who allow us to reuse their software. diff --git a/docs/source/pwm.rst b/docs/source/pwm.rst index 1a8f4df..1144d55 100644 --- a/docs/source/pwm.rst +++ b/docs/source/pwm.rst @@ -26,7 +26,7 @@ documentation ` for more information. Note that unlike the Arduino, the Maple does not have PWM functionality on pin D10; all other pins are :ref:`compatible -`. +`. The following table shows which timer can generate which PWM outputs. See the :ref:`pin mapping table ` to diff --git a/docs/source/specs.rst b/docs/source/specs.rst deleted file mode 100644 index 4972a83..0000000 --- a/docs/source/specs.rst +++ /dev/null @@ -1,29 +0,0 @@ -.. _specs: - -.. _specs-Technical-Specifications: - -================================ -Maple's Technical Specifications -================================ - - * STM32 F103RB: a **32-bit** ARM Cortex M3 microprocessor - * Clock Speed: **72 MHz** - * Operating Voltage: 3.3V - * Input Voltage (recommended): 3.0V-12V - * 39 Digital I/O Pins (:ref:`GPIO `) - * 16 Analog Input Pins - * 12-bit **ADC** resolution (:ref:`ADC `) - * 15 **PWM** pins at 16-bit resolution (:ref:`PWM `) - * Dedicated **USB** port for programming and communications (:ref:`USB`) - * External **JTAG** interface (:ref:`USB `) - * **128 Flash** and **20KB SRAM** - * 64 Channel nested vector interrupt handler (including external interrupt on GPIO’s) - * Integrated **SPI** (:ref:`SPI`) - * Integrated **I2C** (:ref:`I2C`) - * 7 Channels of Direct Memory Access (DMA) - * 3 **USART** divices (:ref:`USART `) - * Four 4-channel Timers (:ref:`Timers `) - * Supplies up to 800mA @ 3.3v - * Support for low power and sleep modes (<500uA) - * Dimensions are 2.05″x2.1″ - diff --git a/docs/source/troubleshooting.rst b/docs/source/troubleshooting.rst index 9146ebe..2151171 100644 --- a/docs/source/troubleshooting.rst +++ b/docs/source/troubleshooting.rst @@ -40,17 +40,17 @@ My 5v peripheral doesn't work! (I2C, SPI, USART, etc) ----------------------------------------------------- Yup, the Maple is a 3.3v board. You may need to use a level -converter. See the :ref:`compatibility `, :ref:`GPIO -`, or other :ref:`hardware specific documentation -` for more information. +converter. See the :ref:`Arduino Compatibility +`, :ref:`GPIO `, or other :ref:`hardware +specific documentation ` for more information. The reset and D38/serial buttons don't seem to work reliably! ------------------------------------------------------------- -A few rev3 boards shipped in May-June 2010 may have had unreliable -buttons; see the :ref:`errata page ` for details. `We're -happy to replace these for you `_\ ! - +A few Maple Rev3 boards shipped in May-June 2010 may have had +unreliable buttons; see the :ref:`errata page ` for +details. `We're happy to replace these for you +`_\ ! .. _troubleshooting-ide-install: diff --git a/docs/source/unix-toolchain.rst b/docs/source/unix-toolchain.rst index a173146..8b81e75 100644 --- a/docs/source/unix-toolchain.rst +++ b/docs/source/unix-toolchain.rst @@ -9,7 +9,9 @@ This is a tutorial for using the Maple with a standard Unix toolchain (``make``, ``gcc``, etc.). It's not necessary to do this in order to program the Maple; you can always :ref:`install the Maple IDE -` instead. +` instead. This document is intended for users who +are comfortable using C or C++ and would like to use :ref:`libmaple` +directly. You'll need a Maple board, a Mini-B USB cable, a functional computer, and root (or Administrator) access to that computer. This guide @@ -100,7 +102,7 @@ in `Python `_, and requires the `PySerial $ export PATH=$PATH:~/libmaple/arm/bin # or wherever these tools ended up This step is fairly straightforward: do a git clone of the `libmaple -repository `_ to some directory, +repository `_ to some directory, then download and extract the ARM compiler toolchain. The :file:`arm/bin/` directory will need to be added to ``PATH``; you @@ -169,9 +171,9 @@ You will need the following tools\ [#fpackman]_ to get started: `_. If you're in a hurry, you can steal a dfu-util binary from a program - called `Openmoko Flasher - `_. To - do this, first `download Openmoko Flasher + called `OpenMoko Flasher + `_. To + do this, first `download OpenMoko Flasher `_, then copy the OpenMoko application into your :file:`/Applications` folder (or wherever you like). Let's pretend you saved the .app to the directory @@ -292,11 +294,11 @@ If it all works out, you should end up seeing something like this:: 21824 200 552 22576 5830 build/maple.out Flash build -Woo! It worked. The ``dec`` field at the end gives the total program -size in bytes. The long listing of object files above the ``Final -Size`` helps to identify bloated code. As you write larger projects, -you may find that they use too much space. If that happens, the -file-by-file listing will help you track down the culprits. +The ``dec`` field at the end gives the total program size in +bytes. The long listing of object files above the ``Final Size`` helps +to identify bloated code. As you write larger projects, you may find +that they use too much space. If that happens, the file-by-file +listing will help you track down the culprits. .. _toolchain-upload: diff --git a/docs/source/usb.rst b/docs/source/usb.rst index 0468618..f040034 100644 --- a/docs/source/usb.rst +++ b/docs/source/usb.rst @@ -34,7 +34,7 @@ second problem is the use of :ref:`perpetual bootloader mode Recommended Reading ------------------- -* `USB in a Nutshell `_, an overview from Beyond Logic +* `USB in a Nutshell `_, an overview from Beyond Logic * `USB made simple `_, an illustrated series of articles on USB * The `USB 2.0 Specification `_ (`direct link `_) * `Embedded USB - a brief tutorial `_ -- cgit v1.2.3 From fb6cf96a4657e4d7ba462f457d9e8e4258b604bb Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Mon, 25 Apr 2011 16:12:57 -0400 Subject: I2C fixup. Added i2c_init() for consistency with rest of libmaple. --- libmaple/i2c.c | 17 +++++++++++++---- libmaple/i2c.h | 1 + 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/libmaple/i2c.c b/libmaple/i2c.c index 3a1082a..f4cb522 100644 --- a/libmaple/i2c.c +++ b/libmaple/i2c.c @@ -320,10 +320,20 @@ static void i2c_bus_reset(const i2c_dev *dev) { gpio_write_bit(dev->gpio_port, dev->sda_pin, 1); } +/** + * @brief Initialize an I2C device and reset its registers to their + * default values. + * @param dev Device to enable. + */ +void i2c_init(i2c_dev *dev) { + rcc_reset_dev(dev->clk_line); + rcc_clk_enable(dev->clk_line); +} + /** * @brief Initialize an i2c device as bus master - * @param device to enable - * @param flags bitwise or of the following I2C options: + * @param dev Device to enable + * @param flags Bitwise or of the following I2C options: * I2C_FAST_MODE: 400 khz operation * I2C_10BIT_ADDRESSING: Enable 10-bit addressing */ @@ -337,8 +347,7 @@ void i2c_master_enable(i2c_dev *dev, uint32 flags) { i2c_bus_reset(dev); /* Turn on clock and set GPIO modes */ - rcc_reset_dev(dev->clk_line); - rcc_clk_enable(dev->clk_line); + i2c_init(dev); gpio_set_mode(dev->gpio_port, dev->sda_pin, GPIO_AF_OUTPUT_OD); gpio_set_mode(dev->gpio_port, dev->scl_pin, GPIO_AF_OUTPUT_OD); diff --git a/libmaple/i2c.h b/libmaple/i2c.h index 27e24b2..3f351b2 100644 --- a/libmaple/i2c.h +++ b/libmaple/i2c.h @@ -137,6 +137,7 @@ extern i2c_dev* const I2C2; extern "C" { #endif +void i2c_init(i2c_dev *dev); void i2c_master_enable(i2c_dev *dev, uint32 flags); int32 i2c_master_xfer(i2c_dev *dev, i2c_msg *msgs, uint16 num); -- cgit v1.2.3 From b00ed99f4d231643d1975c4e90f67d48c1570c19 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Mon, 25 Apr 2011 16:13:09 -0400 Subject: gpio.h whitespace cleanup. --- libmaple/gpio.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libmaple/gpio.h b/libmaple/gpio.h index 63ba0d5..ec31cc0 100644 --- a/libmaple/gpio.h +++ b/libmaple/gpio.h @@ -56,7 +56,6 @@ typedef struct gpio_reg_map { __io uint32 LCKR; /**< Port configuration lock register */ } gpio_reg_map; - /** * External interrupt line port selector. Used to determine which * GPIO port to map an external interrupt line onto. */ -- cgit v1.2.3 From f82577c56f8525fc56aa6a0b71ec62435a4c13ba Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Mon, 25 Apr 2011 17:58:37 -0400 Subject: Minor test-session.cpp fixup --- examples/test-session.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/examples/test-session.cpp b/examples/test-session.cpp index 01dd184..d97d0ca 100644 --- a/examples/test-session.cpp +++ b/examples/test-session.cpp @@ -356,19 +356,18 @@ void cmd_serial1_echo(void) { "early."); while (!SerialUSB.available()) ; - SerialUSB.read(); + if (SerialUSB.read() == ESC) return; SerialUSB.println("Testing 115200 baud on USART1."); serial_echo_test(&Serial1, 115200); - if (SerialUSB.read() == ESC) return; + if (SerialUSB.read() == ESC) return; SerialUSB.println("Testing 57600 baud on USART1."); serial_echo_test(&Serial1, 57600); - if (SerialUSB.read() == ESC) return; + if (SerialUSB.read() == ESC) return; SerialUSB.println("Testing 9600 baud on USART1."); serial_echo_test(&Serial1, 9600); - if (SerialUSB.read() == ESC) return; } void cmd_gpio_monitoring(void) { -- cgit v1.2.3 From fd26797490c9c78cce4d4a1894f9413f3c858f2d Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Mon, 25 Apr 2011 18:00:34 -0400 Subject: Adding nonblocking USART transmit, usart_tx(). Other USART transmission functions are still blocking, but are now implemented in terms of usart_tx(). --- libmaple/usart.c | 29 +++++++++++++++++++---------- libmaple/usart.h | 36 +++++++++++++++++++++++------------- 2 files changed, 42 insertions(+), 23 deletions(-) diff --git a/libmaple/usart.c b/libmaple/usart.c index 22542fd..fbd4d70 100644 --- a/libmaple/usart.c +++ b/libmaple/usart.c @@ -26,6 +26,8 @@ /** * @file usart.c + * @author Marti Bolivar * @brief USART control routines */ @@ -158,7 +160,7 @@ void usart_disable(usart_dev *dev) { * @brief Call a function on each USART. * @param fn Function to call. */ -void usart_foreach(void (*fn)(usart_dev *dev)) { +void usart_foreach(void (*fn)(usart_dev*)) { fn(USART1); fn(USART2); fn(USART3); @@ -169,20 +171,27 @@ void usart_foreach(void (*fn)(usart_dev *dev)) { } /** - * @brief Print a null-terminated string to the specified serial port. - * @param dev Serial port to send the string on - * @param str String to send + * @brief Nonblocking USART transmit + * @param dev Serial port to transmit over + * @param buf Buffer to transmit + * @param len Maximum number of bytes to transmit + * @return Number of bytes transmitted */ -void usart_putstr(usart_dev *dev, const char* str) { - char ch; - - while ((ch = *(str++)) != '\0') { - usart_putc(dev, ch); +uint32 usart_tx(usart_dev *dev, const uint8 *buf, uint32 len) { + usart_reg_map *regs = dev->regs; + uint32 txed = 0; + while ((regs->SR & USART_SR_TXE) && (txed < len)) { + regs->DR = buf[txed++]; } + return txed; } /** - * @brief Print an unsigned integer to the specified serial port. + * @brief Transmit an unsigned integer to the specified serial port in + * decimal format. + * + * This function blocks until the integer's digits have been + * completely transmitted. * * @param dev Serial port to send on * @param val Number to print diff --git a/libmaple/usart.h b/libmaple/usart.h index 02f23da..b2bb034 100644 --- a/libmaple/usart.h +++ b/libmaple/usart.h @@ -26,6 +26,8 @@ /** * @file usart.h + * @author Marti Bolivar , + * Perry Hung * @brief USART definitions and prototypes */ @@ -251,20 +253,12 @@ extern usart_dev *UART4; extern usart_dev *UART5; #endif -#ifdef STM32_MEDIUM_DENSITY -#define NR_USARTS 3 -#elif defined(STM32_HIGH_DENSITY) -#define NR_USARTS 5 -#else -#warn "Only medium and high density devices are currently supported" -#endif - void usart_init(usart_dev *dev); void usart_set_baud_rate(usart_dev *dev, uint32 clock_speed, uint32 baud); void usart_enable(usart_dev *dev); void usart_disable(usart_dev *dev); void usart_foreach(void (*fn)(usart_dev *dev)); -void usart_putstr(usart_dev *dev, const char*); +uint32 usart_tx(usart_dev *dev, const uint8 *buf, uint32 len); void usart_putudec(usart_dev *dev, uint32 val); /** @@ -276,16 +270,32 @@ static inline void usart_disable_all(void) { /** * @brief Transmit one character on a serial port. + * + * This function blocks until the character has been successfully + * transmitted. + * * @param dev Serial port to send on. * @param byte Byte to transmit. */ static inline void usart_putc(usart_dev* dev, uint8 byte) { - usart_reg_map *regs = dev->regs; - - while ((regs->SR & USART_SR_TXE) == 0) + uint8 buf[] = {byte}; + while (!usart_tx(dev, buf, 1)) ; +} - regs->DR = byte; +/** + * @brief Transmit a character string on a serial port. + * + * This function blocks until str is completely transmitted. + * + * @param dev Serial port to send on + * @param str String to send + */ +static inline void usart_putstr(usart_dev *dev, const char* str) { + uint32 i = 0; + while (str[i] != '\0') { + usart_putc(dev, str[i]); + } } /** -- cgit v1.2.3 From ac509ea796f907dc27841a1e4cfa74c2a3285d6a Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Mon, 25 Apr 2011 18:02:10 -0400 Subject: Minor Print cleanups. --- wirish/Print.cpp | 8 ++++---- wirish/Print.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/wirish/Print.cpp b/wirish/Print.cpp index 3d7e836..cfb2cda 100644 --- a/wirish/Print.cpp +++ b/wirish/Print.cpp @@ -21,7 +21,8 @@ * Modified 12 April 2011 by Marti Bolivar */ -#include +#include "Print.h" + #include #ifndef LLONG_MAX @@ -39,8 +40,7 @@ #define LLONG_MAX 9223372036854775807LL #endif -#include "wirish.h" -#include "Print.h" +#include "wirish_math.h" /* * Public methods @@ -64,7 +64,7 @@ void Print::print(uint8 b) { } void Print::print(char c) { - print((byte)c); + print((uint8)c); } void Print::print(const char str[]) { diff --git a/wirish/Print.h b/wirish/Print.h index a4a93bf..ec7b163 100644 --- a/wirish/Print.h +++ b/wirish/Print.h @@ -23,7 +23,7 @@ #ifndef _PRINT_H_ #define _PRINT_H_ -#include +#include "libmaple_types.h" enum { BYTE = 0, -- cgit v1.2.3 From 0d2f2ac040706acd164e5c6296ce6ae9bd5da20f Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Mon, 25 Apr 2011 18:13:47 -0400 Subject: Docs tweaks. Blocking fixes for 0.0.10; other changes. --- docs/source/conf.py | 2 +- docs/source/lang/api/serial.rst | 8 ++++---- docs/source/libs/servo.rst | 2 ++ 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index f232b7c..baadccb 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -59,7 +59,7 @@ copyright = u'2010, LeafLabs, LLC' # The short X.Y version. version = '0.0' # The full version, including alpha/beta/rc tags. -release = '0.0.9' +release = '0.0.10' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/source/lang/api/serial.rst b/docs/source/lang/api/serial.rst index fadac34..417063d 100644 --- a/docs/source/lang/api/serial.rst +++ b/docs/source/lang/api/serial.rst @@ -12,8 +12,8 @@ devices. Introduction ------------ -.. FIXME remove Maple-specific documentation -.. FIXME Serial4, Serial5 updates for high-density devices +.. FIXME [Maple-specific values] +.. FIXME [0.0.10] Serial4, Serial5 updates for high-density devices The Maple has three serial ports (also known as a UARTs or USARTs): ``Serial1``, ``Serial2``, and ``Serial3``. They communicate using the @@ -90,7 +90,7 @@ means that you can use any of these functions on any of ``Serial1``, .. cpp:function:: HardwareSerial::flush() - Removes the contents of the Serial's associated USART RX FIFO. + Throw away the contents of the serial port's receiver (RX) buffer. That is, clears any buffered characters, so that the next character read is guaranteed to be new. @@ -213,7 +213,7 @@ the USB port on the Maple board (for that, use :ref:`SerialUSB `). Thus, to use these pins to communicate with your personal computer, you will need an additional USB-to-serial adapter. -.. TODO LATER port these examples over +.. FIXME [0.1.0] port these examples over .. Examples .. -------- diff --git a/docs/source/libs/servo.rst b/docs/source/libs/servo.rst index f92fd91..475f7dd 100644 --- a/docs/source/libs/servo.rst +++ b/docs/source/libs/servo.rst @@ -6,6 +6,8 @@ Servo ======= +.. FIXME [0.0.10] this is out of date + This documents the Servo library for controlling RC servomotors. It is implemented as a thin layer over the built-in :ref:`timer peripherals `. -- cgit v1.2.3 From bf72983543f446026556e13f62d63aad2092f1ec Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Mon, 25 Apr 2011 18:53:42 -0400 Subject: Trivial pin-definitions.txt updates. No corrections made to the pin definitions themselves. --- notes/pin-definitions.txt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/notes/pin-definitions.txt b/notes/pin-definitions.txt index 71572ac..30f5056 100644 --- a/notes/pin-definitions.txt +++ b/notes/pin-definitions.txt @@ -3,11 +3,8 @@ Pin definitions by GPIO bank. Source: ST DOC ID 14611, Datasheet for STM32F103xC, STM32F103xD, STM32F103xE, Table 5, pp. 30--35. -Some peripherals and extra functionality with less/no libmaple -relevance (at time of writing) are given in "Other" following each -bank's main table. Non-default alternate functions are not listed. If -wirish will/does remap the pin's main function after reset, the main -function is listed under "Other". +Some additional peripheral GPIO information is given in the "Other" +section following each bank's main table. This document was prepared carefully and is believed to be correct, but the final arbiter of truth is the ST datasheet. -- cgit v1.2.3 From 95af192c99459c56bb30763afd93582a524efc3a Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Mon, 25 Apr 2011 21:23:00 -0400 Subject: Better debug port support. - gpio.h: afio_mapr_swj_config() renamed afio_cfg_debug_ports() - [new] wirish_debug.h: disableDebugPorts(), enableDebugPorts() - Maple, Maple Native, and Maple RET6 PIN_MAPs are now larger by 5, have mappings for the extra JTAG/SW pins. Documentation was updated appropriately. --- docs/source/hardware/maple.rst | 83 ++++++++++-------------------- docs/source/jtag.rst | 37 +++++++------ docs/source/lang/api/board-values.rst | 22 +++++++- docs/source/lang/api/disabledebugports.rst | 31 +++++++++++ docs/source/lang/api/enabledebugports.rst | 31 +++++++++++ examples/test-session.cpp | 79 ++++++++++++++++++++++++++-- libmaple/gpio.h | 54 ++++++++++++------- wirish/boards/maple.cpp | 13 ++++- wirish/boards/maple.h | 13 ++++- wirish/boards/maple_mini.cpp | 5 +- wirish/boards/maple_mini.h | 6 +++ wirish/boards/maple_native.cpp | 16 ++++-- wirish/boards/maple_native.h | 10 +++- wirish/wirish.h | 1 + wirish/wirish_debug.h | 54 +++++++++++++++++++ 15 files changed, 347 insertions(+), 108 deletions(-) create mode 100644 docs/source/lang/api/disabledebugports.rst create mode 100644 docs/source/lang/api/enabledebugports.rst create mode 100644 wirish/wirish_debug.h diff --git a/docs/source/hardware/maple.rst b/docs/source/hardware/maple.rst index 44a5238..1fa4f3f 100644 --- a/docs/source/hardware/maple.rst +++ b/docs/source/hardware/maple.rst @@ -40,7 +40,7 @@ Identifying your Rev We went through three versions ("Revs") of the Maple hardware: Rev 1, Rev 3, and Rev 5 [#frev2_4]_; Rev 5, the final design, is currently on sale. The following sections will help you to help you identify your -Rev. Known issues are listed in the :ref:`errata `. +Rev. Rev 5 ^^^^^ @@ -123,46 +123,38 @@ at the command line with :: $ git clone git://github.com/leaflabs/maple.git -.. _maple-errata: +.. _maple-failure-modes: -Errata ------- - -This section lists known issues and warnings for each revision of the -Maple board. The failure modes aren't design errors, but are easy ways -to break or damage your board permanently. For a list of differences -between the Maple and Arduinos, see the :ref:`Arduino Compatibility -reference `. - -The errata are grouped by Maple version ("Rev"). - -Maple Rev 5 -^^^^^^^^^^^ - -Known issues: +Failure Modes +------------- -* **Pin 3 AIN missing**: Pin 3 is capable of analog input, but the - corresponding "AIN" is missing from its silkscreen. - -* **GPIO 39-43 not configured**: this is really more of a software - "TODO" item. Some of the JTAG header pins are numbered 39-43. These - STM32 pins are indeed fully functional :ref:`GPIO ` when a - :ref:`JTAG ` device is not connected, but we have not enabled - them in software and thus they can not be accessed with the regular - :ref:`lang-pinmode` or :ref:`lang-digitalwrite` functions. - -Potential failure modes: +The following known failure modes apply to all Maple versions. The +failure modes aren't design errors, but are easy ways to break or +damage your board permanently. * **High voltage on non-tolerant pins**: not all header pins are 5V compatible; so e.g. connecting certain serial devices in the wrong way could over-voltage the pins. The :ref:`Pin-Mapping Mega Table ` details which pins are 5V-tolerant. -Maple Rev 3 -^^^^^^^^^^^ +Errata +------ + +This section lists known issues and warnings for each revision of the +Maple board. +Rev 5 +^^^^^ Known issues: +* **Pin 3 AIN missing**: Pin 3 is capable of analog input, but on + boards sold in during Fall 2010, the corresponding "AIN" is missing + from its silkscreen. This mistake was fixed in later manufacturing + runs. + +Rev 3 +^^^^^ + * **Bad/Sticky Buttons**: a number of Rev 3 boards sold in May-June 2010 have questionable RESET and BUT buttons. @@ -180,7 +172,7 @@ Known issues: remover we used is "Precision Electronics Cleaner" from RadioShack, which is "Safe on most plastics" and contains Dipropylene glycol monomethyl ether, hydrotreated heavy naphtha, dipropylene glycol - methyl ether acetate (really?), and carbon dioxide. + methyl ether acetate, and carbon dioxide. * **Resistors on pins 0 and 1**: these header pins, which are RX/TX on USART2 (:ref:`Serial2 `), have resistors in-line @@ -192,13 +184,6 @@ Known issues: designs, where they appear to protect the USB-Serial converter from TTL voltage on the headers. -* **GPIO 39-43 not configured**: this is really more of a software - "TODO" item. Some of the JTAG header pins are numbered 39-43. These - STM32 pins are indeed fully functional :ref:`GPIO ` when the a - :ref:`JTAG ` device is not connected, but we have not enabled - them in software and thus they can not be accessed with the regular - :ref:`lang-pinmode` or :ref:`lang-digitalwrite` functions. - * **Silkscreen Errors**: the silkscreen on the bottom indicated PWM functionality on pin 25 and listen the external header GND pin as number 38 (actually 38 is connected to the BUT button). We manually @@ -207,17 +192,8 @@ Known issues: * **PWM Marketing Mistake**: We originally sold the Maple advertising 22 channels of 16-bit hardware PWM; actually the Maple only has 15. -Potential failure modes: - -* **TTL voltage on non-tolerant pins**: not all header pins are 5V - compatible; connecting certain serial devices in the wrong way could - over voltage the pins. The :ref:`Pin-Mapping Mega Table - ` details which pins are 5V-tolerant. - -Maple Rev 1 -^^^^^^^^^^^ - -Known issues: +Rev 1 +^^^^^ * **ADC noise**: generally very high, in particular when the USB port is being used for communications (including keep-alive pings when @@ -248,14 +224,7 @@ Known issues: `_. * **PWM Marketing Mistake**: We originally sold the Maple advertising - 22 channels of 16-bit hardware PWM; actually the Maple only has 15. - -Potential failure modes: - -* **TTL voltage on non-tolerant pins**: not all header pins are 5v - compatible; connecting certain serial devices in the wrong way could - over voltage the pins. The :ref:`Pin-Mapping Mega Table - ` details which pins are 5V-tolerant. + 22 channels of 16-bit hardware PWM; the correct number is 15. Recommended Reading ------------------- diff --git a/docs/source/jtag.rst b/docs/source/jtag.rst index 858021e..cc6d34a 100644 --- a/docs/source/jtag.rst +++ b/docs/source/jtag.rst @@ -1,11 +1,12 @@ +.. highlight:: cpp + .. _jtag: ====== JTAG ====== -.. TODO update adapter schematic, add information on using it with our -.. devices. +.. FIXME update adapter schematic, add better information JTAG is an interface for low-level debugging of digital devices. It gives instruction by instruction control over the microprocessor and @@ -37,32 +38,36 @@ Wiring Diagram to connect a standard 20-pin ARM JTAG device to the 8-pin JTAG port on the Maple. -The Maple has holes for a 8-pin JTAG header but that header is not -soldered on by default. If you know ahead of time that you'll be -needing it, and you order `straight from LeafLabs -`_, add a comment to your order and we can -probably solder one on for no charge. Otherwise, you can simply -attach standard 0.1" pitch male header pins (either the exact 4x2 -block or two 4-pin pieces of breakaway straight header). For a one-off -usage hack, the header can be jammed in the holes and twisted to -ensure electrical contact. +The Maple has holes for a 8-pin JTAG header, but that header is not +soldered on. To use JTAG, simply solder on standard 0.1" pitch male +header pins (either the exact 4 by 2 block, or two 4-pin pieces of +straight breakaway header). Compatible Devices ------------------ We have had good experience with the `Olimex ARM-USB-OCD `_ device, which costs -about 55 euro plus shipping (as of November 2010). +about €55 plus shipping (as of April 2011). + +Function Reference +------------------ + +You can disable or enable the JTAG and Serial Wire debugging ports in +software using the ``disableDebugPorts()`` and ``enableDebugPorts()`` +functions. + +* :ref:`lang-disabledebugports` +* :ref:`lang-enabledebugports` Recommended Reading ------------------- * `Wikipedia Article on Joint Test Action Group (JTAG) `_ -* `STM32/gdb/OpenOCD HOWTO `_ +* `STM32, GDB, OpenOCD How To `_ * STMicro documentation for STM32F103RB microcontroller: * `Datasheet `_ (pdf) * `Reference Manual `_ (pdf) -* There's a `thread on JTAG - `_ in our `forum`_ - which you may find useful. +* `LeafLabs Wiki JTAG How To `_ +* `Forum thread on JTAG `_ diff --git a/docs/source/lang/api/board-values.rst b/docs/source/lang/api/board-values.rst index d6d78f6..e274163 100644 --- a/docs/source/lang/api/board-values.rst +++ b/docs/source/lang/api/board-values.rst @@ -84,8 +84,25 @@ Constants * ``BOARD_NR_USARTS``: Number of serial ports on the board. This number includes UARTs 4 and 5 if they are available. +.. _lang-board-values-debug: + +- Debug (JTAG, SW-Debug) related constants: ``BOARD_JTMS_SWDIO_PIN``, + ``BOARD_JTCK_SWCLK_PIN``, ``BOARD_JTDI_PIN``, ``BOARD_JTDO_PIN``, + and ``BOARD_NJTRST_PIN``. + + These constants are the pin numbers for :ref:`GPIOs ` used by + the :ref:`jtag` and Serial-Wire Debug peripherals. Except for the + Maple Mini, these pins are usually reserved for special purposes by + default (i.e., they are in :ref:`boardUsedPins + `). However, they can be used as + ordinary GPIOs if you call the :ref:`lang-disabledebugports` + function. (Be careful with this on the Maple, as writing to + ``BOARD_NJTRST_PIN`` may cause your board to reset!). + .. _lang-board-values-pwm-pins: + .. _lang-board-values-adc-pins: + .. _lang-board-values-used-pins: Pin Arrays @@ -94,8 +111,7 @@ Pin Arrays Some :ref:`arrays ` of pin numbers are available which you can use to find out certain important information about a given pin. -.. TODO add links to the board-specific hardware information on what -.. are in these arrays +.. TODO [0.1.0] links to board-specific hardware information - ``boardPWMPins``: Pin numbers of each pin capable of :ref:`PWM ` output, using :ref:`pwmWrite() `. The total @@ -159,3 +175,5 @@ See Also - :ref:`lang-toggleled` - :ref:`lang-analogread` - :ref:`lang-pwmwrite` +- :ref:`lang-enabledebugports` +- :ref:`lang-disabledebugports` diff --git a/docs/source/lang/api/disabledebugports.rst b/docs/source/lang/api/disabledebugports.rst new file mode 100644 index 0000000..43ac337 --- /dev/null +++ b/docs/source/lang/api/disabledebugports.rst @@ -0,0 +1,31 @@ +.. highlight:: cpp + +.. _lang-disabledebugports: + +disableDebugPorts() +=================== + +Used to disable the JTAG and Serial Wire debugging ports. + +Library Documentation +--------------------- + +.. doxygenfunction:: disableDebugPorts + +Example +------- + + :: + + void setup() { + disableDebugPorts(); + } + + void loop() { + // Now you can use the debug port pins as ordinary pins + } + +See Also +-------- + +* :ref:`lang-enabledebugports` diff --git a/docs/source/lang/api/enabledebugports.rst b/docs/source/lang/api/enabledebugports.rst new file mode 100644 index 0000000..bee2b0a --- /dev/null +++ b/docs/source/lang/api/enabledebugports.rst @@ -0,0 +1,31 @@ +.. highlight:: cpp + +.. _lang-enabledebugports: + +enableDebugPorts() +================== + +Used to enable the JTAG and Serial Wire debugging ports. + +Library Documentation +--------------------- + +.. doxygenfunction:: enableDebugPorts + +Example +------- + + :: + + void setup() { + enableDebugPorts(); + // Now you can debug using JTAG and SW-Debug + } + + void loop() { + } + +See Also +-------- + +* :ref:`lang-disabledebugports` diff --git a/examples/test-session.cpp b/examples/test-session.cpp index d97d0ca..1d9daf0 100644 --- a/examples/test-session.cpp +++ b/examples/test-session.cpp @@ -27,8 +27,10 @@ void cmd_serial1_echo(void); void cmd_gpio_monitoring(void); void cmd_sequential_adc_reads(void); void cmd_gpio_qa(void); -void cmd_sequential_gpio_writes(void); +void cmd_sequential_gpio_toggling(void); void cmd_gpio_toggling(void); +void cmd_sequential_debug_gpio_toggling(void); +void cmd_debug_gpio_toggling(void); void cmd_but_test(void); void cmd_sequential_pwm_test(void); void cmd_servo_sweep(void); @@ -148,13 +150,21 @@ void loop () { break; case 'g': - cmd_sequential_gpio_writes(); + cmd_sequential_gpio_toggling(); break; case 'G': cmd_gpio_toggling(); break; + case 'j': + cmd_sequential_debug_gpio_toggling(); + break; + + case 'J': + cmd_debug_gpio_toggling(); + break; + case 'B': cmd_but_test(); break; @@ -266,6 +276,8 @@ void cmd_print_help(void) { SerialUSB.println("\tU: dump data as fast as possible on USB"); SerialUSB.println("\tg: toggle GPIOs sequentially"); SerialUSB.println("\tG: toggle GPIOs at the same time"); + SerialUSB.println("\tj: toggle debug port GPIOs sequentially"); + SerialUSB.println("\tJ: toggle debug port GPIOs simultaneously"); SerialUSB.println("\tB: test the built-in button"); SerialUSB.println("\tf: toggle pin 4 as fast as possible in bursts"); SerialUSB.println("\tr: monitor and print GPIO status changes"); @@ -534,7 +546,7 @@ void cmd_gpio_qa(void) { } } -void cmd_sequential_gpio_writes(void) { +void cmd_sequential_gpio_toggling(void) { SerialUSB.println("Sequentially toggling all unused pins. " "Press any key for next pin, ESC to stop."); @@ -582,6 +594,67 @@ void cmd_gpio_toggling(void) { } } +uint8 debugGPIOPins[] = {BOARD_JTMS_SWDIO_PIN, + BOARD_JTCK_SWCLK_PIN, + BOARD_JTDI_PIN, + BOARD_JTDO_PIN, + BOARD_NJTRST_PIN}; + +#define N_DEBUG_PINS 5 + +void cmd_sequential_debug_gpio_toggling(void) { + SerialUSB.println("Toggling all debug (JTAG/SWD) pins sequentially. " + "This will permanently disable debug port " + "functionality."); + disableDebugPorts(); + + for (int i = 0; i < N_DEBUG_PINS; i++) { + pinMode(debugGPIOPins[i], OUTPUT); + } + + for (int i = 0; i < N_DEBUG_PINS; i++) { + int pin = debugGPIOPins[i]; + SerialUSB.print("Toggling pin "); + SerialUSB.print(pin, DEC); + SerialUSB.println("..."); + + pinMode(pin, OUTPUT); + do { + togglePin(pin); + } while (!SerialUSB.available()); + + digitalWrite(pin, LOW); + if (SerialUSB.read() == ESC) + break; + } + + for (int i = 0; i < N_DEBUG_PINS; i++) { + digitalWrite(debugGPIOPins[i], 0); + } +} + +void cmd_debug_gpio_toggling(void) { + SerialUSB.println("Toggling debug GPIO simultaneously. " + "This will permanently disable JTAG and Serial Wire " + "debug port functionality. " + "Press any key to stop."); + disableDebugPorts(); + + for (uint32 i = 0; i < N_DEBUG_PINS; i++) { + pinMode(debugGPIOPins[i], OUTPUT); + } + + while (!SerialUSB.available()) { + for (uint32 i = 0; i < N_DEBUG_PINS; i++) { + togglePin(debugGPIOPins[i]); + } + } + + for (uint32 i = 0; i < N_DEBUG_PINS; i++) { + digitalWrite(debugGPIOPins[i], LOW); + } +} + void cmd_but_test(void) { SerialUSB.println("Press the button to test. Press any key to stop."); pinMode(BOARD_BUTTON_PIN, INPUT); diff --git a/libmaple/gpio.h b/libmaple/gpio.h index ec31cc0..353f965 100644 --- a/libmaple/gpio.h +++ b/libmaple/gpio.h @@ -22,7 +22,7 @@ * 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 gpio.h @@ -261,22 +261,23 @@ typedef struct afio_reg_map { #define AFIO_EVCR_PIN_15 0xF /* AF remap and debug I/O configuration register */ -#define AFIO_MAPR_SWJ_FULL_SWJ (0x0 << 24) -#define AFIO_MAPR_SWJ_FULL_SWJ_NO_NJRST (0x1 << 24) -#define AFIO_MAPR_SWJ_NO_JTAG_SW (0x2 << 24) -#define AFIO_MAPR_SWJ_NO_JTAG_NO_SW (0x4 << 24) +#define AFIO_MAPR_SWJ_CFG (0x7 << 24) +#define AFIO_MAPR_SWJ_CFG_FULL_SWJ (0x0 << 24) +#define AFIO_MAPR_SWJ_CFG_FULL_SWJ_NO_NJRST (0x1 << 24) +#define AFIO_MAPR_SWJ_CFG_NO_JTAG_SW (0x2 << 24) +#define AFIO_MAPR_SWJ_CFG_NO_JTAG_NO_SW (0x4 << 24) #define AFIO_MAPR_ADC2_ETRGREG_REMAP BIT(20) #define AFIO_MAPR_ADC2_ETRGINJ_REMAP BIT(19) #define AFIO_MAPR_ADC1_ETRGREG_REMAP BIT(18) #define AFIO_MAPR_ADC1_ETRGINJ_REMAP BIT(17) #define AFIO_MAPR_TIM5CH4_IREMAP BIT(16) #define AFIO_MAPR_PD01_REMAP BIT(15) -#define AFIO_MAPR_CAN_REMAP (BIT(14) | BIT(13)) -#define AFIO_MAPR_TIM4_REMAP_FULL BIT(12) -#define AFIO_MAPR_TIM3_REMAP (BIT(11) | BIT(10)) -#define AFIO_MAPR_TIM2_REMAP (BIT(9) | BIT(8)) -#define AFIO_MAPR_TIM1_REMAP (BIT(7) | BIT(6)) -#define AFIO_MAPR_USART3_REMAP (BIT(5) | BIT(4)) +#define AFIO_MAPR_CAN_REMAP (0x3 << 13) +#define AFIO_MAPR_TIM4_REMAP BIT(12) +#define AFIO_MAPR_TIM3_REMAP (0x3 << 10) +#define AFIO_MAPR_TIM2_REMAP (0x3 << 8) +#define AFIO_MAPR_TIM1_REMAP (0x3 << 6) +#define AFIO_MAPR_USART3_REMAP (0x3 << 4) #define AFIO_MAPR_USART2_REMAP BIT(3) #define AFIO_MAPR_USART1_REMAP BIT(2) #define AFIO_MAPR_I2C1_REMAP BIT(1) @@ -322,17 +323,32 @@ void afio_init(void); void afio_exti_select(afio_exti_num exti, afio_exti_port gpio_port); /** - * Set the SWJ_CONFIG bits in the AFIO MAPR register. + * @brief Debug port configuration * - * @param config Desired SWJ_CONFIG bits setting. One of: - * AFIO_MAPR_SWJ_FULL_SWJ (full SWJ), - * AFIO_MAPR_SWJ_FULL_SWJ_NO_NJRST (full SWJ, no NJTRST), - * AFIO_MAPR_SWJ_NO_JTAG_SW (JTAG-DP disabled, SW-DP enabled), - * AFIO_MAPR_SWJ_NO_JTAG_NO_SW (JTAG-DP and SW-DP both disabled). + * Used to configure the behavior of JTAG and Serial Wire (SW) debug + * ports and their associated GPIO pins. */ -static inline void afio_mapr_swj_config(uint32 config) { +typedef enum afio_debug_cfg { + AFIO_DEBUG_FULL_SWJ = AFIO_MAPR_SWJ_CFG_FULL_SWJ, /**< + Full Serial Wire and JTAG debug */ + AFIO_DEBUG_FULL_SWJ_NO_NJRST = AFIO_MAPR_SWJ_CFG_FULL_SWJ_NO_NJRST, /**< + Full Serial Wire and JTAG, but no NJTRST. */ + AFIO_DEBUG_SW_ONLY = AFIO_MAPR_SWJ_CFG_NO_JTAG_SW, /**< + Serial Wire debug only (JTAG-DP disabled, + SW-DP enabled) */ + AFIO_DEBUG_NONE = AFIO_MAPR_SWJ_CFG_NO_JTAG_NO_SW /**< + No debug; all JTAG and SW pins are free + for use as GPIOs. */ +} afio_debug_cfg; + +/** + * @brief Enable or disable the JTAG and SW debug ports. + * @param config Desired debug port configuration + * @see afio_debug_cfg + */ +static inline void afio_cfg_debug_ports(afio_debug_cfg config) { __io uint32 *mapr = &AFIO_BASE->MAPR; - *mapr = (*mapr & ~(0x7 << 24)) | config; + *mapr = (*mapr & ~AFIO_MAPR_SWJ_CFG) | config; } #ifdef __cplusplus diff --git a/wirish/boards/maple.cpp b/wirish/boards/maple.cpp index 5122290..2d35e7b 100644 --- a/wirish/boards/maple.cpp +++ b/wirish/boards/maple.cpp @@ -88,7 +88,15 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { {GPIOC, NULL, NULL, 6, 0, ADCx}, /* D35/PC6 */ {GPIOC, NULL, NULL, 7, 0, ADCx}, /* D36/PC7 */ {GPIOC, NULL, NULL, 8, 0, ADCx}, /* D37/PC8 */ - {GPIOC, NULL, NULL, 9, 0, ADCx} /* D38/PC9 (BUT) */ + {GPIOC, NULL, NULL, 9, 0, ADCx}, /* D38/PC9 (BUT) */ + + /* JTAG header */ + + {GPIOA, NULL, NULL, 13, 0, ADCx}, /* D39/PA13 */ + {GPIOA, NULL, NULL, 14, 0, ADCx}, /* D40/PA14 */ + {GPIOA, NULL, NULL, 15, 0, ADCx}, /* D41/PA15 */ + {GPIOB, NULL, NULL, 3, 0, ADCx}, /* D42/PB3 */ + {GPIOB, NULL, NULL, 4, 0, ADCx}, /* D43/PB4 */ }; extern const uint8 boardPWMPins[] __FLASH__ = { @@ -100,7 +108,8 @@ extern const uint8 boardADCPins[] __FLASH__ = { }; extern const uint8 boardUsedPins[] __FLASH__ = { - BOARD_LED_PIN, BOARD_BUTTON_PIN + BOARD_LED_PIN, BOARD_BUTTON_PIN, BOARD_JTMS_SWDIO_PIN, + BOARD_JTCK_SWCLK_PIN, BOARD_JTDI_PIN, BOARD_JTDO_PIN, BOARD_NJTRST_PIN }; #endif diff --git a/wirish/boards/maple.h b/wirish/boards/maple.h index 1867de8..4a4465c 100644 --- a/wirish/boards/maple.h +++ b/wirish/boards/maple.h @@ -54,7 +54,7 @@ /* Total number of GPIO pins that are broken out to headers and * intended for general use. */ -#define BOARD_NR_GPIO_PINS 39 +#define BOARD_NR_GPIO_PINS 44 /* Number of pins capable of PWM output */ #define BOARD_NR_PWM_PINS 16 @@ -64,6 +64,15 @@ /* Number of pins already connected to external hardware. For Maple, * these are just BOARD_LED_PIN and BOARD_BUTTON_PIN. */ -#define BOARD_NR_USED_PINS 2 +#define BOARD_NR_USED_PINS 7 + +/* + * Debug port pins + */ +#define BOARD_JTMS_SWDIO_PIN 39 +#define BOARD_JTCK_SWCLK_PIN 40 +#define BOARD_JTDI_PIN 41 +#define BOARD_JTDO_PIN 42 +#define BOARD_NJTRST_PIN 43 #endif diff --git a/wirish/boards/maple_mini.cpp b/wirish/boards/maple_mini.cpp index cd2827d..02d62c7 100644 --- a/wirish/boards/maple_mini.cpp +++ b/wirish/boards/maple_mini.cpp @@ -32,13 +32,14 @@ #include "maple_mini.h" #include "gpio.h" +#include "wirish_debug.h" #ifdef BOARD_maple_mini /* Since we want the Serial Wire/JTAG pins as GPIOs, disable both SW * and JTAG debug support */ void boardInit(void) { - afio_mapr_swj_config(AFIO_MAPR_SWJ_NO_JTAG_NO_SW); + disableDebugPorts(); } extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { @@ -89,7 +90,7 @@ extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { }; extern const uint8 boardADCPins[BOARD_NR_ADC_PINS] __FLASH__ = { - 3, 4, 5, 6, 7, 8, 9, 10, 11, 33 // NB 33 is LED + 3, 4, 5, 6, 7, 8, 9, 10, 11, 33 // NB: 33 is BOARD_LED_PIN }; #define USB_DP 23 diff --git a/wirish/boards/maple_mini.h b/wirish/boards/maple_mini.h index 8b7ae64..3df1da8 100644 --- a/wirish/boards/maple_mini.h +++ b/wirish/boards/maple_mini.h @@ -59,4 +59,10 @@ #define BOARD_NR_ADC_PINS 10 #define BOARD_NR_USED_PINS 4 +#define BOARD_JTMS_SWDIO_PIN 22 +#define BOARD_JTCK_SWCLK_PIN 21 +#define BOARD_JTDI_PIN 20 +#define BOARD_JTDO_PIN 19 +#define BOARD_NJTRST_PIN 18 + #endif diff --git a/wirish/boards/maple_native.cpp b/wirish/boards/maple_native.cpp index adc9497..0b25bd4 100644 --- a/wirish/boards/maple_native.cpp +++ b/wirish/boards/maple_native.cpp @@ -72,7 +72,8 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { {GPIOB, TIMER4, NULL, 9, 4, ADCx}, /* D26/PB9 */ /* Bottom header */ - /* Note: D{49, 50, 51} are also TIMER2_CH{2, 3, 4}, respectively. */ + /* Note: D{48, 49, 50, 51} are also TIMER2_CH{1, 2, 3, 4}, respectively. */ + /* TODO remap timer 2 in boardInit(); make the appropriate changes here */ {GPIOD, NULL, NULL, 2, 0, ADCx}, /* D27/PD2 */ {GPIOD, NULL, NULL, 3, 0, ADCx}, /* D28/PD3 */ @@ -150,7 +151,15 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { {GPIOG, NULL, NULL, 4, 0, ADCx}, /* D97/PG4 */ {GPIOD, NULL, NULL, 9, 0, ADCx}, /* D98/PD9 */ {GPIOG, NULL, NULL, 5, 0, ADCx}, /* D99/PG5 */ - {GPIOD, NULL, NULL, 10, 0, ADCx} /* D100/PD10 */ + {GPIOD, NULL, NULL, 10, 0, ADCx}, /* D100/PD10 */ + + /* JTAG header */ + + {GPIOA, NULL, NULL, 13, 0, ADCx}, /* D101/PA13 */ + {GPIOA, NULL, NULL, 14, 0, ADCx}, /* D102/PA14 */ + {GPIOA, NULL, NULL, 15, 0, ADCx}, /* D103/PA15 */ + {GPIOB, NULL, NULL, 3, 0, ADCx}, /* D104/PB3 */ + {GPIOB, NULL, NULL, 4, 0, ADCx} /* D105/PB4 */ }; extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { @@ -164,7 +173,8 @@ extern const uint8 boardADCPins[BOARD_NR_ADC_PINS] __FLASH__ = { /* FIXME! see comment by BOARD_NR_USED_PINS in maple_native.h */ extern const uint8 boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = { - BOARD_LED_PIN, BOARD_BUTTON_PIN + BOARD_LED_PIN, BOARD_BUTTON_PIN, BOARD_JTMS_SWDIO_PIN, + BOARD_JTCK_SWCLK_PIN, BOARD_JTDI_PIN, BOARD_JTDO_PIN, BOARD_NJTRST_PIN }; #endif diff --git a/wirish/boards/maple_native.h b/wirish/boards/maple_native.h index 10dafa6..13df153 100644 --- a/wirish/boards/maple_native.h +++ b/wirish/boards/maple_native.h @@ -58,12 +58,18 @@ #define BOARD_UART5_TX_PIN 21 #define BOARD_UART5_RX_PIN 29 -#define BOARD_NR_GPIO_PINS 101 +#define BOARD_NR_GPIO_PINS 106 #define BOARD_NR_PWM_PINS 18 #define BOARD_NR_ADC_PINS 21 /* FIXME! this isn't true at all; almost all of the triple header pins * are used by the FSMC by default. Fix this (and the corresponding * boardUsedPins definition in maple_native.cpp) by QA time. */ -#define BOARD_NR_USED_PINS 2 +#define BOARD_NR_USED_PINS 7 + +#define BOARD_JTMS_SWDIO_PIN 101 +#define BOARD_JTCK_SWCLK_PIN 102 +#define BOARD_JTDI_PIN 103 +#define BOARD_JTDO_PIN 104 +#define BOARD_NJTRST_PIN 105 #endif diff --git a/wirish/wirish.h b/wirish/wirish.h index 4cc142d..d30ad20 100644 --- a/wirish/wirish.h +++ b/wirish/wirish.h @@ -39,6 +39,7 @@ #include "bits.h" #include "pwm.h" #include "ext_interrupts.h" +#include "wirish_debug.h" #include "wirish_math.h" #include "wirish_time.h" #include "HardwareSPI.h" diff --git a/wirish/wirish_debug.h b/wirish/wirish_debug.h new file mode 100644 index 0000000..d4c0bab --- /dev/null +++ b/wirish/wirish_debug.h @@ -0,0 +1,54 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file wirish_debug.h + * @brief High level debug port configuration + */ + +/** + * @brief Disable the JTAG and Serial Wire (SW) debug ports. + * + * You can call this function in order to use the JTAG and SW debug + * pins as ordinary GPIOs. + * + * @see enableDebugPorts() + */ +static inline void disableDebugPorts(void) { + afio_cfg_debug_ports(AFIO_DEBUG_NONE); +} + +/** + * @brief Enable the JTAG and Serial Wire (SW) debug ports. + * + * After you call this function, the JTAG and SW debug pins will no + * longer be usable as GPIOs. + * + * @see disableDebugPorts() + */ +static inline void enableDebugPorts(void) { + afio_cfg_debug_ports(AFIO_DEBUG_FULL_SWJ); +} -- cgit v1.2.3 From d5ee5fef3e33c7fe634a0b416394be9a5aacaf60 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Mon, 25 Apr 2011 22:08:30 -0400 Subject: Adding rcc_dev_clk(), an accessor for a peripheral's clock line. --- libmaple/rcc.c | 23 +++++++++++++++-------- libmaple/rcc.h | 8 ++++++++ 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/libmaple/rcc.c b/libmaple/rcc.c index 78abbcf..efb2599 100644 --- a/libmaple/rcc.c +++ b/libmaple/rcc.c @@ -32,14 +32,12 @@ #include "rcc.h" #include "bitband.h" -enum { - APB1, - APB2, - AHB -}; +#define APB1 RCC_APB1 +#define APB2 RCC_APB2 +#define AHB RCC_AHB struct rcc_dev_info { - const uint8 clk_domain; + const rcc_clk_domain clk_domain; const uint8 line_num; }; @@ -149,7 +147,7 @@ void rcc_clk_enable(rcc_clk_id device) { [AHB] = &RCC_BASE->AHBENR, }; - uint8 clk_domain = rcc_dev_table[device].clk_domain; + rcc_clk_domain clk_domain = rcc_dev_clk(device); __io uint32* enr = (__io uint32*)enable_regs[clk_domain]; uint8 lnum = rcc_dev_table[device].line_num; @@ -166,7 +164,7 @@ void rcc_reset_dev(rcc_clk_id device) { [APB2] = &RCC_BASE->APB2RSTR, }; - uint8 clk_domain = rcc_dev_table[device].clk_domain; + rcc_clk_domain clk_domain = rcc_dev_clk(device); __io void* addr = (__io void*)reset_regs[clk_domain]; uint8 lnum = rcc_dev_table[device].line_num; @@ -174,6 +172,15 @@ void rcc_reset_dev(rcc_clk_id device) { bb_peri_set_bit(addr, lnum, 0); } +/** + * @brief Get a device's clock domain + * @param device Device whose clock domain to return + * @return Device's clock source + */ +rcc_clk_domain rcc_dev_clk(rcc_clk_id device) { + return rcc_dev_table[device].clk_domain; +} + /** * @brief Set the divider on a device prescaler * @param prescaler prescaler to set diff --git a/libmaple/rcc.h b/libmaple/rcc.h index 91f77d0..08f8977 100644 --- a/libmaple/rcc.h +++ b/libmaple/rcc.h @@ -484,6 +484,14 @@ void rcc_clk_init(rcc_sysclk_src sysclk_src, void rcc_clk_enable(rcc_clk_id device); void rcc_reset_dev(rcc_clk_id device); +typedef enum rcc_clk_domain { + RCC_APB1, + RCC_APB2, + RCC_AHB +} rcc_clk_domain; + +rcc_clk_domain rcc_dev_clk(rcc_clk_id device); + /** * Prescaler identifiers * @see rcc_set_prescaler() -- cgit v1.2.3 From 621706150fc55b8266229131cc7fb6db6b2f7cd9 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Mon, 25 Apr 2011 22:29:48 -0400 Subject: Fixing usart_putstr() atrocity. --- libmaple/usart.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmaple/usart.h b/libmaple/usart.h index b2bb034..0743c53 100644 --- a/libmaple/usart.h +++ b/libmaple/usart.h @@ -294,7 +294,7 @@ static inline void usart_putc(usart_dev* dev, uint8 byte) { static inline void usart_putstr(usart_dev *dev, const char* str) { uint32 i = 0; while (str[i] != '\0') { - usart_putc(dev, str[i]); + usart_putc(dev, str[i++]); } } -- cgit v1.2.3 From 1f98566c939c84a986ee8b60fde6aa601c3521da Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Tue, 26 Apr 2011 03:27:10 -0400 Subject: 0.0.10 Documentation checkpoint. The vast majority of the Maple-specific values have been pulled out of the higher-level overview pages and replaced with refs into documents under /docs/source/hardware/. Much of the work that's left to be done in this regard is labeled with versioned TODO and FIXME comments. Suggestions from StephenFromNYC and gbulmer were incorporated from this forum thread: http://forums.leaflabs.com/topic.php?id=703 --- docs/source/adc.rst | 65 ++++--- docs/source/arduino-cc-attribution.txt | 9 + docs/source/bootloader.rst | 7 +- docs/source/external-interrupts.rst | 119 ++++-------- docs/source/gpio.rst | 114 +++++------- docs/source/hardware/maple-ret6.rst | 276 ++++++++++++++++++++++++++++ docs/source/hardware/maple.rst | 210 ++++++++++++++++++--- docs/source/i2c.rst | 40 ++-- docs/source/index.rst | 12 +- docs/source/jtag.rst | 26 ++- docs/source/lang/api/abs.rst | 3 +- docs/source/lang/api/analogread.rst | 65 +++---- docs/source/lang/api/analogwrite.rst | 23 ++- docs/source/lang/api/attachinterrupt.rst | 57 ++---- docs/source/lang/api/bit.rst | 12 +- docs/source/lang/api/bitclear.rst | 13 +- docs/source/lang/api/bitread.rst | 11 +- docs/source/lang/api/bitset.rst | 9 +- docs/source/lang/api/bitwrite.rst | 7 +- docs/source/lang/api/board-values.rst | 5 +- docs/source/lang/api/cc-attribution.txt | 9 - docs/source/lang/api/constants.rst | 2 +- docs/source/lang/api/constrain.rst | 5 +- docs/source/lang/api/cos.rst | 6 +- docs/source/lang/api/delay.rst | 6 +- docs/source/lang/api/delaymicroseconds.rst | 11 +- docs/source/lang/api/detachinterrupt.rst | 8 +- docs/source/lang/api/digitalread.rst | 39 ++-- docs/source/lang/api/digitalwrite.rst | 39 ++-- docs/source/lang/api/hardwaretimer.rst | 95 +++++++++- docs/source/lang/api/highbyte.rst | 6 +- docs/source/lang/api/loop.rst | 3 +- docs/source/lang/api/lowbyte.rst | 2 +- docs/source/lang/api/map.rst | 2 +- docs/source/lang/api/max.rst | 5 +- docs/source/lang/api/micros.rst | 2 +- docs/source/lang/api/millis.rst | 2 +- docs/source/lang/api/min.rst | 3 +- docs/source/lang/api/pinmode.rst | 8 +- docs/source/lang/api/pow.rst | 5 +- docs/source/lang/api/pwmwrite.rst | 14 +- docs/source/lang/api/random.rst | 6 +- docs/source/lang/api/randomseed.rst | 2 +- docs/source/lang/api/serial.rst | 50 ++--- docs/source/lang/api/setup.rst | 2 +- docs/source/lang/api/sin.rst | 3 +- docs/source/lang/api/sq.rst | 3 +- docs/source/lang/api/tan.rst | 3 +- docs/source/lang/api/volatile.rst | 8 +- docs/source/lang/cc-attribution.txt | 9 +- docs/source/lang/cpp/arithmetic.rst | 2 +- docs/source/lang/cpp/array.rst | 6 +- docs/source/lang/cpp/assignment.rst | 2 +- docs/source/lang/cpp/bitshift.rst | 3 +- docs/source/lang/cpp/bitwisemath.rst | 3 +- docs/source/lang/cpp/boolean.rst | 3 +- docs/source/lang/cpp/booleanvariables.rst | 6 +- docs/source/lang/cpp/break.rst | 5 +- docs/source/lang/cpp/byte.rst | 3 +- docs/source/lang/cpp/bytecast.rst | 8 +- docs/source/lang/cpp/char.rst | 10 +- docs/source/lang/cpp/charcast.rst | 6 +- docs/source/lang/cpp/comments.rst | 5 +- docs/source/lang/cpp/comparison.rst | 3 +- docs/source/lang/cpp/compoundarithmetic.rst | 3 +- docs/source/lang/cpp/compoundbitwise.rst | 1 - docs/source/lang/cpp/const.rst | 6 +- docs/source/lang/cpp/continue.rst | 4 +- docs/source/lang/cpp/curly-braces.rst | 5 +- docs/source/lang/cpp/define.rst | 6 +- docs/source/lang/cpp/double.rst | 4 +- docs/source/lang/cpp/doublecast.rst | 2 +- docs/source/lang/cpp/dowhile.rst | 3 +- docs/source/lang/cpp/float.rst | 2 +- docs/source/lang/cpp/floatcast.rst | 2 +- docs/source/lang/cpp/for.rst | 4 +- docs/source/lang/cpp/goto.rst | 3 +- docs/source/lang/cpp/if.rst | 2 +- docs/source/lang/cpp/include.rst | 4 +- docs/source/lang/cpp/increment.rst | 2 +- docs/source/lang/cpp/intcast.rst | 5 +- docs/source/lang/cpp/longcast.rst | 2 +- docs/source/lang/cpp/longlong.rst | 2 +- docs/source/lang/cpp/modulo.rst | 2 +- docs/source/lang/cpp/pointer.rst | 2 +- docs/source/lang/cpp/return.rst | 3 +- docs/source/lang/cpp/scope.rst | 2 +- docs/source/lang/cpp/semicolon.rst | 5 +- docs/source/lang/cpp/sizeof.rst | 2 +- docs/source/lang/cpp/sqrt.rst | 3 +- docs/source/lang/cpp/static.rst | 3 +- docs/source/lang/cpp/string.rst | 3 +- docs/source/lang/cpp/switchcase.rst | 4 +- docs/source/lang/cpp/unsignedchar.rst | 5 +- docs/source/lang/cpp/unsignedint.rst | 2 +- docs/source/lang/cpp/unsignedlonglong.rst | 2 +- docs/source/lang/cpp/variables.rst | 3 +- docs/source/lang/cpp/void.rst | 4 +- docs/source/lang/cpp/while.rst | 2 +- docs/source/lang/unimplemented/notone.rst | 17 +- docs/source/lang/unimplemented/tone.rst | 27 +-- docs/source/language-index.rst | 17 +- docs/source/language.rst | 65 ++++--- docs/source/libmaple/api/systick.rst | 8 + docs/source/libraries.rst | 176 ++++-------------- docs/source/libs/servo.rst | 59 +++++- docs/source/libs/wire.rst | 104 +++++++++++ docs/source/maple-quickstart.rst | 14 +- docs/source/pwm.rst | 31 +--- docs/source/spi.rst | 10 +- docs/source/timers.rst | 206 ++++++--------------- docs/source/troubleshooting.rst | 4 - docs/source/usart.rst | 19 +- docs/source/usb.rst | 54 +++--- 114 files changed, 1307 insertions(+), 1119 deletions(-) create mode 100644 docs/source/arduino-cc-attribution.txt create mode 100644 docs/source/hardware/maple-ret6.rst delete mode 100644 docs/source/lang/api/cc-attribution.txt create mode 100644 docs/source/libs/wire.rst diff --git a/docs/source/adc.rst b/docs/source/adc.rst index b943808..af613cc 100644 --- a/docs/source/adc.rst +++ b/docs/source/adc.rst @@ -6,23 +6,12 @@ Analog-Digital Conversion is the process of reading a physical voltage as a number. The Maple has a large number of pins which are capable of -taking 12-bit ADC measurements, which means that voltages from ground -to +3.3v are read as numbers from 0 to 4095; this corresponds to a +taking 12-bit ADC measurements, which means that voltages from 0 to +3.3V are read as numbers from 0 to 4095. This corresponds to a theoretical sensitivity of just under 1 millivolt. In reality, a -number of factors introduce noise and bias into this reading and a +number of factors introduce noise and bias into this reading, and a number of techniques must be used to get good precision and accuracy. -.. compound:: - - The header pins with ADC functionality (marked as "AIN" on the - silkscreen) are: - - D0, D1, D2, D3, D10, D11, D12, D13, D15, D16, D17, D18, D19, D20, D27, D28 - - Note that pins 3, 27, and 28 are not marked AIN on the silkscreen - for Maple revisions through Rev 5, however, they **do work** as - analog input pins. - .. contents:: Contents :local: @@ -31,13 +20,15 @@ number of techniques must be used to get good precision and accuracy. Noise and Bias -------------- +.. FIXME [0.0.10, Maple-specific] + The biggest issues with analog-digital conversion are noise and bias. With the Maple, we have tried to isolate the ADC pins and traces from -strong noise sources but there are always trade--offs between noise, +strong noise sources, but there are always trade--offs between noise, additional functionality, cost, and package size. The 6 ADC pins in a bank (D15--D20) generally have the least -noise and should be used for fine measurements. If the input voltage +noise, and should be used for fine measurements. If the input voltage changes relatively slowly, a number of samples can be taken in succession and averaged together, or the same voltage can even be sampled by multiple ADC pins at the same time. @@ -47,34 +38,40 @@ voltages that the sample is being compared against. In the case of the Maple, the high reference is |vcc| and the low reference is ground. This means that noise or fluctuations on either |vcc| or ground will affect the measurement. It also means that the voltage you are trying -to sample must be between ground and 3.3V. In the case of a variable -reading, it is best if the voltage varies over the entire range of -0--3.3V; otherwise, only a fraction of the sensitivity is being -leveraged. Resistor dividers and constant voltage diodes are basic -tools which can help bring a given voltage signal into the appropriate -range; opamps and other powered components can also be used. +to sample must be between ground and 3.3V. + +.. _adc-range: + +In the case of a variable reading, it is best if the voltage varies +over the entire range of 0--3.3V; otherwise, only a fraction of the +sensitivity is being leveraged. Some basic tools to accomplish this +are `resistor dividers +`_ and `Zener diodes +`_\ +. However, `operational amplifiers +`_ and other +powered components can also be used if greater precision is required. .. _adc-function-reference: Function Reference ------------------ -.. doxygenfunction:: analogRead - -.. doxygenfunction:: pinMode - -.. doxygenenum:: WiringPinMode +* :ref:`lang-analogread` +* :ref:`lang-pinmode` .. _adc-recommended-reading: Recommended Reading ------------------- -* `Wikipedia article on Analog-to-digital converter `_ - -* `Arduino Analog Input Tutorial `_ - -* STMicro documentation: +* `Wikipedia: Analog-to-Digital Converter + `_ +* `Arduino Analog Input Tutorial + `_ +* ST documentation: - * `Application Note on ADC Modes (pdf) `_ - * `Application Note on ADC Oversampling (pdf) `_ + * `Application Note on ADC Modes + `_ (PDF) + * `Application Note on ADC Oversampling + `_ (PDF) diff --git a/docs/source/arduino-cc-attribution.txt b/docs/source/arduino-cc-attribution.txt new file mode 100644 index 0000000..ad1c1e0 --- /dev/null +++ b/docs/source/arduino-cc-attribution.txt @@ -0,0 +1,9 @@ +.. Included in all relevant files in order to satisfy the Arduino +.. CC Attribution-ShareAlike 3.0 License + +.. admonition:: License and Attribution + + Portions of this page were adapted from the `Arduino Reference + Documentation `_\ , which + is released under a `Creative Commons Attribution-ShareAlike 3.0 + License `_. diff --git a/docs/source/bootloader.rst b/docs/source/bootloader.rst index 85b2674..ec4fe73 100644 --- a/docs/source/bootloader.rst +++ b/docs/source/bootloader.rst @@ -1,8 +1,9 @@ .. highlight:: sh -===================== - Maple Bootloader(s) -===================== +.. _bootloader: + +Maple Bootloader(s) +=================== The firmware which allows the Maple to be reprogrammed via a USB connection. Every Maple board comes programmed with this by default, diff --git a/docs/source/external-interrupts.rst b/docs/source/external-interrupts.rst index b2cbbb1..ac065a4 100644 --- a/docs/source/external-interrupts.rst +++ b/docs/source/external-interrupts.rst @@ -6,73 +6,42 @@ External Interrupts =================== External interrupts can be used to trigger routines to run in response -to changes in voltage on a pin. Each GPIO pin on the Maple can be used -to detect transitions such as when the voltage goes from low to high, -or from high to low. This technique can be used to avoid unnecessary -polling of the state of a pin. +to changes in voltage on a pin. Each :ref:`GPIO pin ` can be +used to detect transitions, such as when the voltage goes from +:ref:`LOW ` to :ref:`HIGH `, +or from ``HIGH`` to ``LOW``. This can be used to avoid checking for +changes on a pin "manually" by waiting in a loop until the pin +changes. .. _contents: Contents :local: - Overview -------- External interrupts are often used to detect when events happen -outside of the microcontroller. These can be used to tell the Maple -when events happen, such as when a sensor has data ready to be read, -or when a button has been pushed. When such an event happens, an -interrupt is raised and the Maple can react to it with a preset -*interrupt handler*. - -Every GPIO pin on the Maple can be used as an external interrupt, -subject to certain constraints; there can be a maximum of 16 different -external interrupts set up at a time on the Maple. This is because the -external interrupt lines on the STM32 are multiplexed between GPIO -ports. In effect, this means that every pin on the Maple maps to a -certain EXTI line, and within that EXTI line, only one of the pins -that maps to it can be used as an external interrupt at a time. - -The following table shows which pins can be used on which lines. - -.. list-table:: - :widths: 1 1 - :header-rows: 1 - - * - EXTI Line - - Maple pins - * - EXTI0 - - 2, 15, 27 - * - EXTI1 - - 3, 16, 28 - * - EXTI2 - - 1, 17, 25 - * - EXTI3 - - 0, 18 - * - EXTI4 - - 10, 19 - * - EXTI5 - - 4, 13, 20 - * - EXTI6 - - 5, 12, 35 - * - EXTI7 - - 9, 11, 36 - * - EXTI8 - - 6, 14, 37 - * - EXTI9 - - 7, 25, 28 - * - EXTI10 - - 8, 26, 29 - * - EXTI11 - - 30 - * - EXTI12 - - 31 - * - EXTI13 - - 21, 32 - * - EXTI14 - - 22, 33 - * - EXTI15 - - 23, 34 +outside of the microcontroller. These can be used to tell Maple when +events happen, such as when a sensor has data ready to be read, or +when a button has been pushed. When such an event happens, an +interrupt is raised, and the Maple can react to it with a preset +*interrupt handler*, which is a function that gets called whenever the +event occurs. + +.. _external-interrupts-exti-line: + +Every GPIO pin can generate an external interrupt, subject to certain +constraints. There can be a maximum of 16 different external +interrupts set up at a time. This is because the external interrupt +lines on the STM32 are shared between GPIO ports. In effect, this +means that every pin on the Maple connects to what is called an *EXTI +line*, and within an EXTI line, only one of the pins that connects to +it can be used to detect external interrupts at a time. + +The EXTI Line Pin Map for your board lists which pins connect to which +EXTI lines: + +* :ref:`Maple ` +* :ref:`Maple RET6 Edition ` .. note:: @@ -80,40 +49,16 @@ The following table shows which pins can be used on which lines. desired pin to an input mode (e.g ``INPUT`` or ``INPUT_FLOATING``, ``INPUT_PULLUP``, ``INPUT_PULLDOWN``). - Function Reference ------------------ - :ref:`attachInterrupt() ` - :ref:`detachInterrupt() ` -Code example ------------- - -Blink the LED on every transition:: - - int pin = 13; - volatile int state = LOW; - - void setup() { - pinMode(pin, OUTPUT); - pinMode(0, INPUT_FLOATING); - attachInterrupt(0, blink, CHANGE); - } - - void loop() { - digitalWrite(pin, state); - } - - void blink() { - state = !state; - } - - Recommended Reading ------------------- -* STMicro documentation for STM32F103RB microcontroller: - - * `Datasheet `_ (pdf) - * `Reference Manual `_ (pdf) +* ST manual `RM0008 + `_ + (PDF), Chapter 9, "General-purpose and alternate-function I/Os", and + Chapter 10, "Interrupts and Events". diff --git a/docs/source/gpio.rst b/docs/source/gpio.rst index 0f9f4df..74be3d4 100644 --- a/docs/source/gpio.rst +++ b/docs/source/gpio.rst @@ -3,86 +3,54 @@ GPIO ==== -.. FIXME [Maple-specific values] +Each LeafLabs board comes with ready-to-use General Purpose +Input/Output (GPIO) pins, which are numbered starting from zero. +These numbers are listed on your board's silkscreen, next to where the +pin is broken out to a header. Many pins may additionally be used for +special features or peripheral functions. -The Maple features 38 ready-to-use general purpose input/output (GPIO) -pins for digital input/output, numbered D0 through D37. These numbers -correspond to the numeric values next to each header on the Maple -silkscreen. +.. contents:: Contents + :local: -Many of these pins may additionally be used for special features or -peripheral functions. This page documents those capabilities, by pin. +.. _gpio-pin-maps: -The current and voltage limitations have been copied over from the -STM32 datasheet (see the :ref:`Recommended Reading -` for a link). In particular, a number of -GPIO pins are 5V tolerant (which means that applying 5 volts to a pin -and reading it as input or allowing it to drain to ground will not -damage that pin), while some are not. +Pin Maps +-------- -.. contents:: Contents - :local: +The hardware documentation for your board lists each pin's +capabilities, by pin number: + +.. TODO [0.1.0] Uncomment Mini and Native GPIO links + +* :ref:`Maple ` +* :ref:`Maple RET6 Edition ` -.. _pin-mapping-mega-table: - -Pin Mapping Mega Table ----------------------- - -This table shows the available functionality on every GPIO pin, by -peripheral type. The "STM32" column refers to the port and number that -the header is connected to on the microcontroller. The "5V?" column -documents whether or not the pin is 5 volt tolerant (see above). - -.. TODO silkscreen pictures which let you know what each abbreviation -.. means, with links to the relevant documentation. - -.. csv-table:: - :header: "Pin", "STM32", ":ref:`ADC `", ":ref:`Timer `", ":ref:`I2C `", ":ref:`UART `", ":ref:`SPI `", "5v?" - - "D0", "PA3", "ADC3", "TIM2_CH4", "-", "USART2_RX", "-", "No" - "D1", "PA2", "ADC2", "TIM2_CH3", "-", "USART2_TX", "-", "No" - "D2", "PA0", "ADC0", "TIM2_CH1_ETR", "-", "USART2_CTS", "-", "No" - "D3", "PA1", "ADC1", "TIM2_CH2", "-", "USART2_RTS", "-", "No" - "D4", "PB5", "-", "-", "ISC1_SMBA", "-", "-", "No" - "D5", "PB6", "-", "TIM4_CH1", "I2C1_SCL", "-", "-", "Yes" - "D6", "PA8", "-", "TIM1_CH1", "-", "USART1_CK", "-", "Yes" - "D7", "PA9", "-", "TIM1_CH2", "-", "USART1_TX", "-", "Yes" - "D8", "PA10", "-", "TIM1_CH3", "-", "USART1_RX", "-", "Yes" - "D9", "PB7", "-", "TIM4_CH2", "I2C1_SDA", "-", "-", "Yes" - "D10", "PA4", "ADC4", "-", "-", "USART2_CK", "SPI1_NSS", "No" - "D11", "PA7", "ADC7", "TIM3_CH2", "-", "-", "SPI1_MOSI", "No" - "D12", "PA6", "ADC6", "TIM3_CH1", "-", "-", "SPI1_MISO", "No" - "D13", "PA5", "ADC5", "-", "-", "-", "SPI1_SCK", "No" - "D14", "PB8", "-", "TIM4_CH3", "-", "-", "-", "Yes" - "D15", "PC0", "ADC10", "-", "-", "-", "-", "No" - "D16", "PC1", "ADC11", "-", "-", "-", "-", "No" - "D17", "PC2", "ADC12", "-", "-", "-", "-", "No" - "D18", "PC3", "ADC13", "-", "-", "-", "-", "No" - "D19", "PC4", "ADC14", "-", "-", "-", "-", "No" - "D20", "PC5", "ADC15", "-", "-", "-", "-", "No" - "D21", "PC13", "-", "-", "-", "-", "-", "No" - "D22", "PC14", "-", "-", "-", "-", "-", "No" - "D23", "PC15", "-", "-", "-", "-", "-", "No" - "D24", "PB9", "-", "TIM4_CH4", "-", "-", "-", "Yes" - "D25", "PD2", "-", "TIM3_ETR", "-", "-", "-", "Yes" - "D26", "PC10", "-", "-", "-", "-", "-", "Yes" - "D27", "PB0", "ADC8", "TIM3_CH3", "-", "-", "-", "No" - "D28", "PB1", "ADC9", "TIM3_CH4", "-", "-", "-", "No" - "D29", "PB10", "-", "-", "I2C2_SCL", "USART3_TX", "-", "Yes" - "D30", "PB11", "-", "-", "I2C2_SDA", "USART3_RX", "-", "Yes" - "D31", "PB12", "-", "TIM1_BKIN", "I2C2_SMBAL", "USART3_CK", "SPI2_NSS", "Yes" - "D32", "PB13", "-", "TIM1_CH1N", "-", "USART3_CTS", "SPI2_SCK", "Yes" - "D33", "PB14", "-", "TIM1_CH2N", "-", "USART3_RTS", "SPI2_MISO", "Yes" - "D34", "PB15", "-", "TIM1_CH3N", "-", "-", "SPI2_MOSI", "Yes" - "D35", "PC6", "-", "-", "-", "-", "-", "Yes" - "D36", "PC7", "-", "-", "-", "-", "-", "Yes" - "D37", "PC8", "-", "-", "-", "-", "-", "Yes" +.. * :ref:`Maple Mini ` +.. * :ref:`Maple Native ` + +The current and voltage limitations were determined using the STM32 +datasheets. In particular, only some GPIO pins are **5V tolerant**, +which means that applying 5 volts to a pin and reading it as input or +allowing it to drain to ground will not damage that pin. Connecting a +voltage higher than 3.3V to a non-5V tolerant pin may damage your +board. .. _gpio-modes: GPIO Modes ---------- +Each of the GPIO pins on a Maple board may be configured using +pinMode() to behave in a number of ways: as a digital output pin, +or as an analog input pin, etc., depending on the particular pin. + +A ``WiringPinMode`` value specifies the complete set of possible +configurations; not every pin can have all of these modes. For +example, on the Maple, pin 15 may have mode ``INPUT_ANALOG``, but not +``PWM``. See your :ref:`board's pin maps ` and its +silkscreen for more information on what functionality is available on +each pin. + .. doxygenenum:: WiringPinMode Function Reference @@ -105,7 +73,11 @@ Function Reference Recommended Reading ------------------- -STMicro documentation for STM32F103RB microcontroller: +* ST Documentation for the STM32F103 series of microcontrollers: - * `Datasheet `_ (pdf) * `Reference Manual `_ (pdf) + + * `Programming Manual + `_ + (PDF; assembly language and register reference) + diff --git a/docs/source/hardware/maple-ret6.rst b/docs/source/hardware/maple-ret6.rst new file mode 100644 index 0000000..06dcaff --- /dev/null +++ b/docs/source/hardware/maple-ret6.rst @@ -0,0 +1,276 @@ +.. highlight:: sh + +.. _maple-ret6: + +Maple RET6 Edition +================== + +.. contents:: Contents + :local: + +Technical Specifications +------------------------ + + * MCU: **STM32F103RET6**, a 32-bit ARM Cortex M3 microprocessor + * Clock Speed: **72 MHz** + * Operating Voltage: 3.3V + * Input Voltage (recommended): 3V-12V + * 39 Digital I/O Pins (:ref:`GPIO `) + * 16 Analog Input pins, 12 bit **ADC** resolution (:ref:`ADC `) + * 15 **PWM** pins at 16-bit resolution (:ref:`PWM `) + * Dedicated **USB** port for programming and communications (:ref:`USB`) + * External **JTAG** interface (:ref:`JTAG `) + * **512KB Flash** and **64KB SRAM** + * 64 Channel nested vector interrupt handler (including external interrupt on GPIOs) + * Integrated **SPI** (:ref:`SPI `) + * Integrated **I2C** (:ref:`I2C `) + * 12 Channels of Direct Memory Access (**DMA**) + * 3 **USART** and 2 **UART** devices (:ref:`USART `) + * Six 4-channel and two basic **timers** (:ref:`Timers `) + * Supplies up to 800mA @ 3.3v + * Support for low power and sleep modes (<500uA) + * Dimensions are 2.05″x2.1″ + +.. _maple-ret6-powering: + +Powering the Maple RET6 Edition +------------------------------- + +The Maple RET6 Edition's power source is determined by the header to +the left of the "LeafLabs" label on the silkscreen. The RET6 Edition +can be powered from the barrel jack connector, USB, or a LiPo battery. +We ship the RET6 Edition with a jumper on the USB selector. In order +to power it off of an alternative source, unplug the board, then move +the jumper to the desired selector before reconnecting power. + +You can also power the Maple via the pin labeled "Vin" on the lower +header. However, don't do this while simultaneously powering the +board from another source, or you could damage the it. + +Using the Built-in Battery Charger +---------------------------------- + +The RET6 Edition has a built-in LiPo battery charger. In order to use +it, put a jumper across the CHRG header on the power selection header +and across the USB, or EXT selectors, depending on whether you're +charging the battery via USB cable or barrel jack connector. The LED +labeled CHRG will light up while the battery is being charged. When +the battery is finished charging, the LED labeled DONE will also light +up. + +.. _maple-ret6-gpios: + +GPIO Information +---------------- + +The RET6 Edition features 38 ready-to-use general purpose input/output +(GPIO) pins for digital input/output, numbered ``D0`` through ``D37``. +These numbers correspond to the numeric values next to each header on +the Maple silkscreen. More GPIOs (numbered ``D39``\ --``43``) are +available through use in combination with the +:ref:`lang-disabledebugports` function; see the :ref:`board-specific +debug pin constants ` for more information. + +.. TODO [0.1.0] silkscreen pictures which expand abbreviations + +.. _maple-ret6-pin-map-master: + +Master Pin Map +^^^^^^^^^^^^^^ + +.. TODO [0.0.10] Update from base Maple information + +This table shows the available functionality on every GPIO pin, by +peripheral type. The "STM32" column refers to the port and number that +the header is connected to on the microcontroller. The "5V?" column +documents whether or not the pin is 5 volt tolerant. + +.. csv-table:: + :header: "Pin", "STM32", ":ref:`ADC `", ":ref:`Timer `", ":ref:`I2C `", ":ref:`UART `", ":ref:`SPI `", "5v?" + + "D0", "PA3", "ADC3", "TIM2_CH4", "-", "USART2_RX", "-", "No" + "D1", "PA2", "ADC2", "TIM2_CH3", "-", "USART2_TX", "-", "No" + "D2", "PA0", "ADC0", "TIM2_CH1_ETR", "-", "USART2_CTS", "-", "No" + "D3", "PA1", "ADC1", "TIM2_CH2", "-", "USART2_RTS", "-", "No" + "D4", "PB5", "-", "-", "ISC1_SMBA", "-", "-", "No" + "D5", "PB6", "-", "TIM4_CH1", "I2C1_SCL", "-", "-", "Yes" + "D6", "PA8", "-", "TIM1_CH1", "-", "USART1_CK", "-", "Yes" + "D7", "PA9", "-", "TIM1_CH2", "-", "USART1_TX", "-", "Yes" + "D8", "PA10", "-", "TIM1_CH3", "-", "USART1_RX", "-", "Yes" + "D9", "PB7", "-", "TIM4_CH2", "I2C1_SDA", "-", "-", "Yes" + "D10", "PA4", "ADC4", "-", "-", "USART2_CK", "SPI1_NSS", "No" + "D11", "PA7", "ADC7", "TIM3_CH2", "-", "-", "SPI1_MOSI", "No" + "D12", "PA6", "ADC6", "TIM3_CH1", "-", "-", "SPI1_MISO", "No" + "D13", "PA5", "ADC5", "-", "-", "-", "SPI1_SCK", "No" + "D14", "PB8", "-", "TIM4_CH3", "-", "-", "-", "Yes" + "D15", "PC0", "ADC10", "-", "-", "-", "-", "No" + "D16", "PC1", "ADC11", "-", "-", "-", "-", "No" + "D17", "PC2", "ADC12", "-", "-", "-", "-", "No" + "D18", "PC3", "ADC13", "-", "-", "-", "-", "No" + "D19", "PC4", "ADC14", "-", "-", "-", "-", "No" + "D20", "PC5", "ADC15", "-", "-", "-", "-", "No" + "D21", "PC13", "-", "-", "-", "-", "-", "No" + "D22", "PC14", "-", "-", "-", "-", "-", "No" + "D23", "PC15", "-", "-", "-", "-", "-", "No" + "D24", "PB9", "-", "TIM4_CH4", "-", "-", "-", "Yes" + "D25", "PD2", "-", "TIM3_ETR", "-", "-", "-", "Yes" + "D26", "PC10", "-", "-", "-", "-", "-", "Yes" + "D27", "PB0", "ADC8", "TIM3_CH3", "-", "-", "-", "No" + "D28", "PB1", "ADC9", "TIM3_CH4", "-", "-", "-", "No" + "D29", "PB10", "-", "-", "I2C2_SCL", "USART3_TX", "-", "Yes" + "D30", "PB11", "-", "-", "I2C2_SDA", "USART3_RX", "-", "Yes" + "D31", "PB12", "-", "TIM1_BKIN", "I2C2_SMBA", "USART3_CK", "SPI2_NSS", "Yes" + "D32", "PB13", "-", "TIM1_CH1N", "-", "USART3_CTS", "SPI2_SCK", "Yes" + "D33", "PB14", "-", "TIM1_CH2N", "-", "USART3_RTS", "SPI2_MISO", "Yes" + "D34", "PB15", "-", "TIM1_CH3N", "-", "-", "SPI2_MOSI", "Yes" + "D35", "PC6", "-", "-", "-", "-", "-", "Yes" + "D36", "PC7", "-", "-", "-", "-", "-", "Yes" + "D37", "PC8", "-", "-", "-", "-", "-", "Yes" + +.. TODO [0.0.10] Another table for the JTAG pins + +Timer Pin Map +^^^^^^^^^^^^^ + +.. TODO [0.0.10] Add Timer 5,6,7,8 information + +The following table shows what pins are associated with a particular +timer's capture/compare channels. + +.. csv-table:: + :header: Timer, Ch. 1, Ch. 2, Ch. 3, Ch. 4 + :delim: | + + 1 | D6 | D7 | D8 | - + 2 | D2 | D3 | D1 | D0 + 3 | D12 | D11 | D27 | D28 + 4 | D5 | D9 | D14 | D24 + +.. _maple-ret6-exti-map: + +EXTI Line Pin Map +^^^^^^^^^^^^^^^^^ + +The following table shows which pins connect to which :ref:`EXTI lines +` on the Maple RET6 Edition. + +.. list-table:: + :widths: 1 1 + :header-rows: 1 + + * - EXTI Line + - Pins + * - EXTI0 + - 2, 15, 27 + * - EXTI1 + - 3, 16, 28 + * - EXTI2 + - 1, 17, 25 + * - EXTI3 + - 0, 18 + * - EXTI4 + - 10, 19 + * - EXTI5 + - 4, 13, 20 + * - EXTI6 + - 5, 12, 35 + * - EXTI7 + - 9, 11, 36 + * - EXTI8 + - 6, 14, 37 + * - EXTI9 + - 7, 25, 28 + * - EXTI10 + - 8, 26, 29 + * - EXTI11 + - 30 + * - EXTI12 + - 31 + * - EXTI13 + - 21, 32 + * - EXTI14 + - 22, 33 + * - EXTI15 + - 23, 34 + +.. _maple-ret6-usart-map: + +USART Pin Map +^^^^^^^^^^^^^ + +.. FIXME [0.0.10] UART4 and UART5 information + +The Maple RET6 Edition has three serial ports (also known as a UARTs +or USARTs): ``Serial1``, ``Serial2``, and ``Serial3``. They +communicate using the pins summarized in the following table: + +.. csv-table:: + :header: Serial Port, TX, RX, CK, CTS, RTS + :delim: | + + ``Serial1`` | 7 | 8 | 6 | - | - + ``Serial2`` | 1 | 0 | 10 | 2 | 3 + ``Serial3`` | 29 | 30 | 31 | 32 | 33 + +Board-Specific Values +--------------------- + +.. TODO [0.0.10] + +Stub. + +Hardware Design Files +--------------------- + +The hardware schematics and board layout files are available in the +`Maple Github repository `_. Other +than the processor used, the design files for the Maple RET6 edition +are identical to the Maple Rev 5, which are in the ``maple-r5`` +subdirectory of the Maple repository. A schematic for a JTAG adapter +suitable for use with Maple is available in the ``jtagadapter`` +directory. + +From the Github repository main page, you can download the entire +repository by clicking the "Download" button. If you are familiar +with `git `_, you can also clone the repository +at the command line with :: + + $ git clone git://github.com/leaflabs/maple.git + +.. _maple-ret6-failure-modes: + +Failure Modes +------------- + +The following known failure modes apply to all Maple boards. The +failure modes aren't design errors, but are easy ways to break or +damage your board permanently. + +* **High voltage on non-tolerant pins**: not all header pins are 5V + compatible; so e.g. connecting certain serial devices in the wrong + way could over-voltage the pins. The :ref:`pin-mapping master table + ` details which pins are 5V-tolerant. + +Errata +------ + +This section lists known issues and warnings for the Maple RET6 Edition. + +* **DAC, UART4, UART5 GPIOs unavailable**: Pins related to the digital + to analog converter (DAC) and UARTs 4 and 5 are not broken out to + headers. The RET6 Edition's hardware layout is identical to that of + the Maple Rev 5, which wasn't designed for use with these + STM32F103RET6-only peripherals. + +Recommended Reading +------------------- + +* STMicro documentation for STM32F103RE microcontroller: + + * `Datasheet + `_ (PDF) + * `Reference Manual + `_ (PDF) + * `Programming Manual + `_ + (PDF; assembly language and register reference) diff --git a/docs/source/hardware/maple.rst b/docs/source/hardware/maple.rst index 1fa4f3f..44848a7 100644 --- a/docs/source/hardware/maple.rst +++ b/docs/source/hardware/maple.rst @@ -1,6 +1,6 @@ .. highlight:: sh -.. _hardware-maple: +.. _maple: Maple ===== @@ -16,15 +16,14 @@ Technical Specifications * Operating Voltage: 3.3V * Input Voltage (recommended): 3V-12V * 39 Digital I/O Pins (:ref:`GPIO `) - * 16 Analog Input Pins - * 12-bit **ADC** resolution (:ref:`ADC `) + * 16 Analog Input Pins, 12-bit **ADC** resolution (:ref:`ADC `) * 15 **PWM** pins at 16-bit resolution (:ref:`PWM `) - * Dedicated **USB** port for programming and communications (:ref:`USB`) - * External **JTAG** interface (:ref:`USB `) - * **128 Flash** and **20KB SRAM** + * Dedicated **USB** port for programming and communications (:ref:`USB `) + * External **JTAG** interface (:ref:`JTAG `) + * **128KB Flash** and **20KB SRAM** * 64 Channel nested vector interrupt handler (including external interrupt on GPIOs) - * Integrated **SPI** (:ref:`SPI`) - * Integrated **I2C** (:ref:`I2C`) + * Integrated **SPI** (:ref:`SPI `) + * Integrated **I2C** (:ref:`I2C `) * 7 Channels of Direct Memory Access (**DMA**) * 3 **USART** divices (:ref:`USART `) * Four 4-channel **timers** (:ref:`Timers `) @@ -32,7 +31,7 @@ Technical Specifications * Support for low power and sleep modes (<500uA) * Dimensions are 2.05″x2.1″ -.. _maple-hardware-identify-rev: +.. _maple-identify-rev: Identifying your Rev -------------------- @@ -79,7 +78,7 @@ have a light red silkscreen and a single pixelated leaf as a logo. :align: center :alt: Maple Rev 1 -.. _hardware-maple-powering: +.. _maple-powering: Powering the Maple ------------------ @@ -106,17 +105,174 @@ connector. The LED labeled CHRG will light up while the battery is being charged. When the battery is finished charging, the LED labeled DONE will also light up. +.. _maple-gpios: + +GPIO Information +---------------- + +The Maple features 38 ready-to-use general purpose input/output (GPIO) +pins for digital input/output, numbered ``D0`` through ``D37``. These +numbers correspond to the numeric values next to each header on the +Maple silkscreen. More GPIOs (numbered ``D39``\ --``43``) are +available through use in combination with the +:ref:`lang-disabledebugports` function; see the :ref:`board-specific +debug pin constants ` for more information. + +.. TODO [0.1.0] silkscreen pictures which expand abbreviations + +.. _maple-pin-map-master: + +Master Pin Map +^^^^^^^^^^^^^^ + +This table shows the available functionality on every GPIO pin, by +peripheral type. The "STM32" column refers to the port and number that +the header is connected to on the microcontroller. The "5V?" column +documents whether or not the pin is 5 volt tolerant. + +.. csv-table:: + :header: "Pin", "STM32", ":ref:`ADC `", ":ref:`Timer `", ":ref:`I2C `", ":ref:`UART `", ":ref:`SPI `", "5v?" + + "D0", "PA3", "ADC3", "TIM2_CH4", "-", "USART2_RX", "-", "No" + "D1", "PA2", "ADC2", "TIM2_CH3", "-", "USART2_TX", "-", "No" + "D2", "PA0", "ADC0", "TIM2_CH1_ETR", "-", "USART2_CTS", "-", "No" + "D3", "PA1", "ADC1", "TIM2_CH2", "-", "USART2_RTS", "-", "No" + "D4", "PB5", "-", "-", "ISC1_SMBA", "-", "-", "No" + "D5", "PB6", "-", "TIM4_CH1", "I2C1_SCL", "-", "-", "Yes" + "D6", "PA8", "-", "TIM1_CH1", "-", "USART1_CK", "-", "Yes" + "D7", "PA9", "-", "TIM1_CH2", "-", "USART1_TX", "-", "Yes" + "D8", "PA10", "-", "TIM1_CH3", "-", "USART1_RX", "-", "Yes" + "D9", "PB7", "-", "TIM4_CH2", "I2C1_SDA", "-", "-", "Yes" + "D10", "PA4", "ADC4", "-", "-", "USART2_CK", "SPI1_NSS", "No" + "D11", "PA7", "ADC7", "TIM3_CH2", "-", "-", "SPI1_MOSI", "No" + "D12", "PA6", "ADC6", "TIM3_CH1", "-", "-", "SPI1_MISO", "No" + "D13", "PA5", "ADC5", "-", "-", "-", "SPI1_SCK", "No" + "D14", "PB8", "-", "TIM4_CH3", "-", "-", "-", "Yes" + "D15", "PC0", "ADC10", "-", "-", "-", "-", "No" + "D16", "PC1", "ADC11", "-", "-", "-", "-", "No" + "D17", "PC2", "ADC12", "-", "-", "-", "-", "No" + "D18", "PC3", "ADC13", "-", "-", "-", "-", "No" + "D19", "PC4", "ADC14", "-", "-", "-", "-", "No" + "D20", "PC5", "ADC15", "-", "-", "-", "-", "No" + "D21", "PC13", "-", "-", "-", "-", "-", "No" + "D22", "PC14", "-", "-", "-", "-", "-", "No" + "D23", "PC15", "-", "-", "-", "-", "-", "No" + "D24", "PB9", "-", "TIM4_CH4", "-", "-", "-", "Yes" + "D25", "PD2", "-", "TIM3_ETR", "-", "-", "-", "Yes" + "D26", "PC10", "-", "-", "-", "-", "-", "Yes" + "D27", "PB0", "ADC8", "TIM3_CH3", "-", "-", "-", "No" + "D28", "PB1", "ADC9", "TIM3_CH4", "-", "-", "-", "No" + "D29", "PB10", "-", "-", "I2C2_SCL", "USART3_TX", "-", "Yes" + "D30", "PB11", "-", "-", "I2C2_SDA", "USART3_RX", "-", "Yes" + "D31", "PB12", "-", "TIM1_BKIN", "I2C2_SMBA", "USART3_CK", "SPI2_NSS", "Yes" + "D32", "PB13", "-", "TIM1_CH1N", "-", "USART3_CTS", "SPI2_SCK", "Yes" + "D33", "PB14", "-", "TIM1_CH2N", "-", "USART3_RTS", "SPI2_MISO", "Yes" + "D34", "PB15", "-", "TIM1_CH3N", "-", "-", "SPI2_MOSI", "Yes" + "D35", "PC6", "-", "-", "-", "-", "-", "Yes" + "D36", "PC7", "-", "-", "-", "-", "-", "Yes" + "D37", "PC8", "-", "-", "-", "-", "-", "Yes" + +.. TODO [0.0.10] JTAG pins + +Timer Pin Map +^^^^^^^^^^^^^ + +The following table shows what pins are associated with a particular +timer's capture/compare channels. + +.. csv-table:: + :header: Timer, Ch. 1, Ch. 2, Ch. 3, Ch. 4 + :delim: | + + 1 | D6 | D7 | D8 | - + 2 | D2 | D3 | D1 | D0 + 3 | D12 | D11 | D27 | D28 + 4 | D5 | D9 | D14 | D24 + +.. _maple-exti-map: + +EXTI Line Pin Map +^^^^^^^^^^^^^^^^^ + +The following table shows which pins connect to which :ref:`EXTI lines +` on the Maple. + +.. list-table:: + :widths: 1 1 + :header-rows: 1 + + * - EXTI Line + - Pins + * - EXTI0 + - 2, 15, 27 + * - EXTI1 + - 3, 16, 28 + * - EXTI2 + - 1, 17, 25 + * - EXTI3 + - 0, 18 + * - EXTI4 + - 10, 19 + * - EXTI5 + - 4, 13, 20 + * - EXTI6 + - 5, 12, 35 + * - EXTI7 + - 9, 11, 36 + * - EXTI8 + - 6, 14, 37 + * - EXTI9 + - 7, 25, 28 + * - EXTI10 + - 8, 26, 29 + * - EXTI11 + - 30 + * - EXTI12 + - 31 + * - EXTI13 + - 21, 32 + * - EXTI14 + - 22, 33 + * - EXTI15 + - 23, 34 + +.. _maple-usart-map: + +USART Pin Map +^^^^^^^^^^^^^ + +.. FIXME [0.0.10] UART4, UART5 + +The Maple has three serial ports (also known as a UARTs or USARTs): +``Serial1``, ``Serial2``, and ``Serial3``. They communicate using the +pins summarized in the following table: + +.. csv-table:: + :header: Serial Port, TX, RX, CK, CTS, RTS + :delim: | + + ``Serial1`` | 7 | 8 | 6 | - | - + ``Serial2`` | 1 | 0 | 10 | 2 | 3 + ``Serial3`` | 29 | 30 | 31 | 32 | 33 + +Board-Specific Values +--------------------- + +.. TODO [0.0.10] + +Stub. + Hardware Design Files --------------------- The hardware schematics and board layout files are available in the -`Maple github repository `_. The +`Maple Github repository `_. The design files for Rev 1, Rev 3, and Rev 5 are respectively in the ``maple-r1``, ``maple-r3``, and ``maple-r5`` subdirectories. A schematic for a JTAG adapter suitable for use with Maple is available in the ``jtagadapter`` directory. -From the github repository main page, you can download the entire +From the Github repository main page, you can download the entire repository by clicking the "Download" button. If you are familiar with `git `_, you can also clone the repository at the command line with :: @@ -128,14 +284,14 @@ at the command line with :: Failure Modes ------------- -The following known failure modes apply to all Maple versions. The -failure modes aren't design errors, but are easy ways to break or -damage your board permanently. +The following are known failure modes. The failure modes aren't +design errors, but are easy ways to break or damage your board +permanently. * **High voltage on non-tolerant pins**: not all header pins are 5V compatible; so e.g. connecting certain serial devices in the wrong - way could over-voltage the pins. The :ref:`Pin-Mapping Mega Table - ` details which pins are 5V-tolerant. + way could over-voltage the pins. The :ref:`pin-mapping master table + ` details which pins are 5V-tolerant. Errata ------ @@ -145,16 +301,18 @@ Maple board. Rev 5 ^^^^^ -Known issues: -* **Pin 3 AIN missing**: Pin 3 is capable of analog input, but on - boards sold in during Fall 2010, the corresponding "AIN" is missing +* **Pin 3 AIN missing**: Pin 3 is capable of analog input, but on Rev + 5s manufactured during Fall 2010, the corresponding "AIN" is missing from its silkscreen. This mistake was fixed in later manufacturing runs. Rev 3 ^^^^^ +* **Pin 3 AIN missing**: Pin 3 is capable of analog input, but the + corresponding "AIN" is missing from the Rev 3 silkscreen. + * **Bad/Sticky Buttons**: a number of Rev 3 boards sold in May-June 2010 have questionable RESET and BUT buttons. @@ -231,9 +389,15 @@ Recommended Reading * STMicro documentation for STM32F103RB microcontroller: - * `Datasheet `_ (pdf) - * `Reference Manual `_ (pdf) - * `Programming Manual `_ (assembly language and register reference) + * `Datasheet + `_ + (PDF) + * `Reference Manual + `_ + (PDF) + * `Programming Manual + `_ + (PDF; assembly language and register reference) .. rubric:: Footnotes diff --git a/docs/source/i2c.rst b/docs/source/i2c.rst index 15190a8..e3d68c0 100644 --- a/docs/source/i2c.rst +++ b/docs/source/i2c.rst @@ -14,10 +14,8 @@ Higher level functionality, such as reading a particular register value, is achieved by writing to set the memory location then reading to pull out the data. -.. FIXME [Maple-specific values] - Note that the master/slave designation is on a message-by-message -basis. The Maple can act as both a master (messages initiated by user +basis. Maple can act as both a master (messages initiated by user code) and slave device (responding to requests via configurable interrupt handlers) at the same time. @@ -27,15 +25,15 @@ interrupt handlers) at the same time. Hardware/Circuit Design ----------------------- -The Maple has two |i2c| ports. Port 1 (I2C1) has SDA on header D9 and -SCL on D5; Port 2 (I2C2) has SDA on D30 and SCL on D29. +.. FIXME [0.0.10 add links to board-specific values] -The Maple reliably communicates with up to a 400kHz clock speed; this -doesn't translate into a 400kbps data rate except in extreme cases -because of addressing and protocol overhead. We have tested clock -speeds up to a megahertz and have had mixed results; in theory it -could be possible to achieve even higher rates, but signal quality -degrades rapidly and the bus becomes unreliable. +Maple boards have two |i2c| ports. Maples reliably communicate with +up to a 400kHz clock speed; this doesn't translate into a 400kbps data +rate except in extreme cases because of addressing and protocol +overhead. We have tested clock speeds up to a megahertz and have had +mixed results; in theory it could be possible to achieve even higher +rates, but signal quality degrades rapidly, and the bus becomes +unreliable. Proper wiring and pull-up resistor selection are essential when incorporating |i2c| into a circuit, especially with data rates above @@ -56,22 +54,16 @@ Wiring-style library is planned for a future release. SMBus ----- -The STM32 microcontroller has hardware support for SMBus; we simply -have not written software for it. The SMBAL line for I2C1 is on header -D4 and for I2C2 is on D31. +The STM32 microcontroller has hardware support for SMBus, but software +for it is not yet implemented. .. _i2c-recommended-reading: Recommended Reading ------------------- -* `i2c-bus.org `_ -* `Wikipedia Article on i2c `_ -* `Arduino i2c/TWI reference `_ -* STMicro documentation for STM32F103RB microcontroller: - - * `Datasheet `_ (pdf) - * `Reference Manual `_ (pdf) - * `Application Note on Advanced I2C Usage - `_ - (pdf) +* `I2C Bus `_ +* `Wikipedia: I2C `_ +* `Arduino I2C/TWI reference `_ +* ST `Application Note on Advanced I2C Usage + `_ (PDF) diff --git a/docs/source/index.rst b/docs/source/index.rst index 9db5ff0..8c7ac84 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,15 +1,12 @@ .. _index: -Maple Documentation Contents +LeafLabs Documentation Index ============================ -.. FIXME [Maple-specific values] errata page links to Maple - Welcome! This is the Maple documentation index. If you just bought a -Maple, you probably want to head to the :ref:`quickstart +Maple board, you probably want to head to the :ref:`quickstart `. If you're having problems, check out the -:ref:`troubleshooting ` :ref:`known problems -` pages. +:ref:`troubleshooting ` page. Have fun! @@ -59,7 +56,7 @@ Have fun! usb usart -.. _index-schematics: +.. _index-boards: **Board Hardware Documentation:** @@ -67,6 +64,7 @@ Have fun! :maxdepth: 1 hardware/maple.rst + hardware/maple-ret6.rst .. TODO write/include these upon Mini and Native release diff --git a/docs/source/jtag.rst b/docs/source/jtag.rst index cc6d34a..4151a53 100644 --- a/docs/source/jtag.rst +++ b/docs/source/jtag.rst @@ -6,7 +6,7 @@ JTAG ====== -.. FIXME update adapter schematic, add better information +.. FIXME [0.1.0] Updated adapter schematic, better information JTAG is an interface for low-level debugging of digital devices. It gives instruction by instruction control over the microprocessor and @@ -63,11 +63,21 @@ functions. Recommended Reading ------------------- -* `Wikipedia Article on Joint Test Action Group (JTAG) `_ -* `STM32, GDB, OpenOCD How To `_ -* STMicro documentation for STM32F103RB microcontroller: +* `Wikipedia Article on Joint Test Action Group (JTAG) + `_ - * `Datasheet `_ (pdf) - * `Reference Manual `_ (pdf) -* `LeafLabs Wiki JTAG How To `_ -* `Forum thread on JTAG `_ +* `STM32, GDB, OpenOCD How To + `_ + +* `LeafLabs Wiki JTAG How To + `_ + +* `LeafLabs forum thread on JTAG + `_ + +* ST documentation: + + * Reference Manual `RM0008 + `_ + (PDF), Chapter 31, "Debug support", and Chapter 9, + "General-purpose and alternate function I/Os". diff --git a/docs/source/lang/api/abs.rst b/docs/source/lang/api/abs.rst index 0cc6c23..d9f1ca3 100644 --- a/docs/source/lang/api/abs.rst +++ b/docs/source/lang/api/abs.rst @@ -45,5 +45,4 @@ Arduino Compatibility Maple's implementation of ``abs()`` is compatible with Arduino. - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/analogread.rst b/docs/source/lang/api/analogread.rst index 7099b69..6665a94 100644 --- a/docs/source/lang/api/analogread.rst +++ b/docs/source/lang/api/analogread.rst @@ -20,32 +20,33 @@ Library Documentation Discussion ---------- -Reads the value from the specified analog pin. The Maple board -contains a 16-channel, 12-bit analog to digital converter. This means -that it will map input voltages between 0 and 3.3 volts into integer -values between 0 and 4095. This yields a resolution between readings -of 3.3V / 4096 units, or 0.8 millivolts. However, a number of factors +Reads the value from the specified analog pin. The Maple boards +contain 16-channel, 12-bit analog to digital converters. This means +that a converter will map input voltages between 0 and 3.3 volts into +integer values between 0 and 4095. However, a number of factors interfere with getting full accuracy and precision. For more information, see :ref:`adc`. Before calling analogRead() on a pin, that pin must first be -configured for analog input, using :ref:`lang-pinMode` (you only -have to do this once, so it's usually done in :ref:`lang-setup`\ ). +configured for analog input, using :ref:`lang-pinMode`. You only have +to do this once, so it's usually done in :ref:`lang-setup`\ . Parameter Discussion -------------------- -.. FIXME generalize Maple-specific information - The pin parameter is the number of the analog input pin to read from. -Header pins on the Maple with ADC functionality (marked as "AIN" on -the silkscreen) are: - - 0, 1, 2, 3, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 27, 28 - -Note that pins 3, 27, and 28 are not marked AIN on the silkscreen -for Maple revisions through Rev 5, however, they **do work** as -analog input pins. +The pins which support analog to digital conversion have ``AIN`` +listed underneath their number on your board's silkscreen. These pin +numbers are available to your program in the :ref:`boardADCPins +` board-specific array. The number of +pins which are capable of analog to digital conversion on your board +is given by the ``BOARD_NR_ADC_PINS`` constant. These values are +documented for each board in the :ref:`Board Hardware Documentation +` pages. + +.. note:: Pin 3 is not marked ``AIN`` on the silkscreen for Maple + revisions through Rev 5; however **it does work** as an analog + input pin. Note ---- @@ -55,7 +56,6 @@ returned by ``analogRead()`` will fluctuate due to a number of reasons (like the values of the other analog inputs, how close your hand is to the board, etc.) in a "random" way. - Example ------- @@ -78,7 +78,6 @@ Example // a serial monitor } - Arduino Compatibility --------------------- @@ -100,27 +99,21 @@ shift ` the value of a Maple readout by 2, like so:: // be aware that you're losing a lot of precision if you do this int adc_reading = analogRead(pin) >> 2; -.. FIXME Mention Native can do analogReference(), when it's time +.. FIXME [0.1.0] Mention that Native can do analogReference() On the Arduino, the input range and resolution can be changed using -their implementation of `analogReference() -`_\ . Because of the -way its hardware (as of Rev 5) was designed, it's not possible to -implement analogReference on the Maple, so this function doesn't -exist. If your inputs lie in a different voltage range than 0V--3.3V, -you'll need to bring them into that range before using -``analogRead()``. Some basic tools to accomplish this are `resistor -dividers `_ and `Zener -diodes -`_\ -. However, `operational amplifiers -`_ and other -powered components can also be used if greater precision is required. - -See also +the `analogReference() +`_ function. Because +of hardware restrictions, this function is not available on the Maple +and Maple RET6 Edition. If your inputs lie in a different voltage +range than 0V--3.3V, you'll need to bring them into that range before +using ``analogRead()``. See the :ref:`ADC reference ` for +more information. + +See Also -------- - :ref:`ADC tutorial ` - `(Arduino) Tutorial: Analog Input Pins `_ -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/analogwrite.rst b/docs/source/lang/api/analogwrite.rst index 9147b96..e789305 100644 --- a/docs/source/lang/api/analogwrite.rst +++ b/docs/source/lang/api/analogwrite.rst @@ -65,12 +65,12 @@ This will convert values in the range 0-255 to values in the range which control PWM output. See the :ref:`timers reference ` for more information. -Another fix is to consult the :ref:`pin mapping mega table -` to find the timer which controls PWM on the -pin you're using, then set that Timer's overflow to 255. Subsequent -calls to analogWrite() should work as on the Arduino (with the same -loss of precision). Note, however, that that affects the overflow for -the **entire timer**, so other code relying on that timer (such as any +Another fix is to consult your board's :ref:`pin maps ` +to find the timer which controls PWM on the pin you're using, then set +that Timer's overflow to 255. Subsequent calls to analogWrite() +should work as on the Arduino (with the same loss of precision). +Note, however, that that affects the overflow for the **entire +timer**, so other code relying on that timer (such as any :ref:`interrupts ` the timer controls) will likely need to be modified as well. @@ -140,9 +140,9 @@ If your application definitely requires Arduino's PWM frequency, then the steps are: 1. Figure out which :ref:`timer ` controls PWM - output on your pin (\ :ref:`this table ` is your - friend here). Let's say it's ``Timern``\ , where ``n`` is some - number 1, 2, 3, or 4. + output on your pin (\ :ref:`your board's Timer Pin Map + ` is your friend here). Let's say it's ``Timern``\ + , where ``n`` is some number 1, 2, 3, or 4. 2. Call ``Timern.setPeriod(2041)``\ . This will set the timer's period to approximately 2041 microseconds, which is a frequency of @@ -154,7 +154,7 @@ timer. The important examples are :ref:`timer interrupts ` and :ref:`PWM `\ . -See also +See Also -------- - :ref:`Maple PWM tutorial ` @@ -169,5 +169,4 @@ See also Maple uses 2 bytes of memory, and an unsigned (i.e., nonnegative) integer with size 2 bytes can hold the values between 0 and 65,535. - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/attachinterrupt.rst b/docs/source/lang/api/attachinterrupt.rst index 7c5a6c7..39902ac 100644 --- a/docs/source/lang/api/attachinterrupt.rst +++ b/docs/source/lang/api/attachinterrupt.rst @@ -5,9 +5,8 @@ attachInterrupt() ================= -Used to specify a function to call when an external interrupt (like an -GPIO changing from LOW to HIGH, a button getting pressed, etc.) -occurs. +Used to specify a function to call when an :ref:`external interrupt +` occurs. .. contents:: Contents :local: @@ -15,9 +14,9 @@ occurs. Library Documentation --------------------- -.. FIXME once breathe knows how to get the correct attachInterupt -.. (right now it's copying from HardwareTimer), replace with a -.. doxygenfunction directive +.. FIXME [doxygenfunction] once Breathe knows how to get the correct +.. attachInterupt (right now it's copying from HardwareTimer), replace +.. with a doxygenfunction directive .. cpp:function:: void attachInterrupt(uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode) @@ -47,49 +46,29 @@ Discussion Because the function will run in interrupt context, inside of it, :ref:`lang-delay` won't work, and the value returned by -:ref:`lang-millis` will not increment. Serial data received while -in the function may be lost. You should declare as ``volatile`` any +:ref:`lang-millis` will not increment. Serial data received while in +the function may be lost. You should declare as ``volatile`` any global variables that you modify within the attached function. -There are a few constraints you should be aware of if you're using -more than one interrupt at a time; the :ref:`external-interrupts` page -has the details. - -Using Interrupts ----------------- - -Interrupts are useful for making things happen automatically in -microcontroller programs, and can help solve timing problems. A -good task for using an interrupt might be reading a rotary encoder, -or monitoring user input. - -If you wanted to insure that a program always caught the pulses -from a rotary encoder, never missing a pulse, it would make it very -tricky to write a program to do anything else, because the program -would need to constantly poll the sensor lines for the encoder, in -order to catch pulses when they occurred. Other sensors have a -similar interface dynamic too, such as trying to read a sound -sensor that is trying to catch a click, or an infrared slot sensor -(photo-interrupter) trying to catch a coin drop. In all of these -situations, using an interrupt can free the microcontroller to get -some other work done while not missing the doorbell. +There are a few limits you should be aware of if you're using more +than one interrupt at a time; the :ref:`External Interrupts +` page has more information. Example ------- -:: + :: - int maple_led_pin = 13; volatile int state = LOW; // must declare volatile, since it's - // modified within the blink handler + // modified within the blink() handler void setup() { - pinMode(maple_led_pin, OUTPUT); + pinMode(BOARD_LED_PIN, OUTPUT); attachInterrupt(0, blink, CHANGE); } void loop() { - digitalWrite(maple_led_pin, state); + digitalWrite(BOARD_LED_PIN, state); } void blink() { @@ -106,10 +85,10 @@ additional four: numbers 2 (pin 21), 3 (pin 20), 4 (pin 19), and 5 number goes with which pin -- just tell ``attachInterrupt()`` the pin you want. -See also +See Also -------- -- :ref:`detachInterrupt ` -- :ref:`external-interrupts` +- :ref:`lang-detachinterrupt` +- :ref:`external-interrupts` -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/bit.rst b/docs/source/lang/api/bit.rst index dd5c050..3df042c 100644 --- a/docs/source/lang/api/bit.rst +++ b/docs/source/lang/api/bit.rst @@ -12,33 +12,27 @@ Syntax ``bit(n)`` - Parameters ---------- * **n** the bit to set. - Value ----- The value of an integer with the given bit set. - Arduino Compatibility --------------------- -The Maple implementation of bit is compatible with Arduino. +The Maple implementation of ``bit()`` is compatible with Arduino. - -See also +See Also -------- - - :ref:`lang-bitread` - :ref:`lang-bitwrite` - :ref:`lang-bitset` - :ref:`lang-bitclear` - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/bitclear.rst b/docs/source/lang/api/bitclear.rst index 941f912..f487059 100644 --- a/docs/source/lang/api/bitclear.rst +++ b/docs/source/lang/api/bitclear.rst @@ -10,7 +10,6 @@ Syntax ``bitClear(x, n)`` - Parameters ---------- @@ -19,20 +18,17 @@ Parameters * **n** which bit to clear, starting at 0 for the least-significant (rightmost) bit - Returns ------- -None. - +Nothing. Arduino Compatibility --------------------- -This implementation is compatible with that of Arduino. +The Maple implementation of ``bitClear()`` is compatible with Arduino. - -See also +See Also -------- - :ref:`bit `\ () @@ -40,5 +36,4 @@ See also - :ref:`bitWrite `\ () - :ref:`bitSet `\ () - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/bitread.rst b/docs/source/lang/api/bitread.rst index 46b4478..fd9fbbe 100644 --- a/docs/source/lang/api/bitread.rst +++ b/docs/source/lang/api/bitread.rst @@ -5,13 +5,11 @@ bitRead() (Macro) Gets the value of a bit in a number. - Syntax ------ ``bitRead(x, n)`` - Parameters ---------- @@ -20,27 +18,22 @@ Parameters * **n** which bit to read, starting at 0 for the least-significant (rightmost) bit - Value ----- The value of the bit (0 or 1). - Arduino Compatibility --------------------- The Maple implementation of ``bitRead`` is compatible with Arduino. - -See also +See Also -------- - - :ref:`lang-bit` - :ref:`lang-bitwrite` - :ref:`lang-bitset` - :ref:`lang-bitclear` - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/bitset.rst b/docs/source/lang/api/bitset.rst index ccd76de..83ab5f8 100644 --- a/docs/source/lang/api/bitset.rst +++ b/docs/source/lang/api/bitset.rst @@ -5,13 +5,11 @@ bitSet() (Macro) Sets (writes a 1 to) a bit of a numeric variable. - Syntax ------ ``bitSet(x, n)`` - Parameters ---------- @@ -20,19 +18,16 @@ Parameters * **n** which bit to set, starting at 0 for the least-significant (rightmost) bit - Value ----- None. - Arduino Compatibility --------------------- The Maple implementation of bitSet is compatible with Arduino. - See Also -------- @@ -41,6 +36,4 @@ See Also - :ref:`lang-bitwrite` - :ref:`lang-bitclear` - - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/bitwrite.rst b/docs/source/lang/api/bitwrite.rst index b3feff2..6106545 100644 --- a/docs/source/lang/api/bitwrite.rst +++ b/docs/source/lang/api/bitwrite.rst @@ -32,9 +32,9 @@ Nothing. Arduino Compatibility --------------------- -Maple's version of ``bitWrite()`` is compatible with Arduino. +Maple's implementation of ``bitWrite()`` is compatible with Arduino. -See also +See Also -------- - :ref:`bit() ` @@ -42,5 +42,4 @@ See also - :ref:`bitSet() ` - :ref:`bitClear() ` - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/board-values.rst b/docs/source/lang/api/board-values.rst index e274163..05e3837 100644 --- a/docs/source/lang/api/board-values.rst +++ b/docs/source/lang/api/board-values.rst @@ -12,6 +12,9 @@ it easier to share your code with other people who have different boards. Some example usages are given :ref:`below `. +The actual values for each board are given in the :ref:`Board Hardware +Documentation `. + .. contents:: Contents :local: @@ -111,8 +114,6 @@ Pin Arrays Some :ref:`arrays ` of pin numbers are available which you can use to find out certain important information about a given pin. -.. TODO [0.1.0] links to board-specific hardware information - - ``boardPWMPins``: Pin numbers of each pin capable of :ref:`PWM ` output, using :ref:`pwmWrite() `. The total number of these pins is :ref:`BOARD_NR_PWM_PINS diff --git a/docs/source/lang/api/cc-attribution.txt b/docs/source/lang/api/cc-attribution.txt deleted file mode 100644 index e100140..0000000 --- a/docs/source/lang/api/cc-attribution.txt +++ /dev/null @@ -1,9 +0,0 @@ -.. Included in all this directory's files in order to satisfy the -.. Arduino CC Attribution-ShareAlike 3.0 License - -.. admonition:: License and Attribution - - This documentation page was adapted from the `Arduino Reference - Documentation `_\ , which - is released under a `Creative Commons Attribution-ShareAlike 3.0 - License `_. diff --git a/docs/source/lang/api/constants.rst b/docs/source/lang/api/constants.rst index c5a7c0c..00c1a5c 100644 --- a/docs/source/lang/api/constants.rst +++ b/docs/source/lang/api/constants.rst @@ -320,4 +320,4 @@ See Also - :ref:`double ` - :ref:`Board-Specific Values ` -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/constrain.rst b/docs/source/lang/api/constrain.rst index d19b61c..28af1e3 100644 --- a/docs/source/lang/api/constrain.rst +++ b/docs/source/lang/api/constrain.rst @@ -59,11 +59,10 @@ Arduino Compatibility Maple's implementation of ``constrain()`` is compatible with Arduino. -See also +See Also -------- - :ref:`min() ` - :ref:`max() ` - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/cos.rst b/docs/source/lang/api/cos.rst index 3fbb0af..c340f09 100644 --- a/docs/source/lang/api/cos.rst +++ b/docs/source/lang/api/cos.rst @@ -19,14 +19,12 @@ Note that the Maple implementation comes from `newlib `_\ , while Arduino's is that of `avr-libc `_\ . -See also +See Also -------- - - :ref:`sin() ` - :ref:`tan() ` - :ref:`float ` - :ref:`double ` - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/delay.rst b/docs/source/lang/api/delay.rst index 90ca268..9ef06a0 100644 --- a/docs/source/lang/api/delay.rst +++ b/docs/source/lang/api/delay.rst @@ -57,10 +57,9 @@ Example .. _lang-delay-seealso: -See also +See Also -------- - - :ref:`millis() ` - :ref:`micros() ` - :ref:`delayMicroseconds() ` @@ -68,5 +67,4 @@ See also `_ example (works unmodified on Maple) - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/delaymicroseconds.rst b/docs/source/lang/api/delaymicroseconds.rst index 24a8286..7078660 100644 --- a/docs/source/lang/api/delaymicroseconds.rst +++ b/docs/source/lang/api/delaymicroseconds.rst @@ -48,9 +48,9 @@ Arduino Compatibility --------------------- While we have made every effort we could to ensure that the timing of -delayMicroseconds is as accurate as possible, we cannot guarantee it -will behave as the Arduino implementation down to the microsecond, -especially for smaller values of ``us``. +``delayMicroseconds()`` is as accurate as possible, we cannot +guarantee it will behave as the Arduino implementation down to the +microsecond, especially for smaller values of ``us``. See Also -------- @@ -59,7 +59,4 @@ See Also - :ref:`micros ` - :ref:`delay ` - - - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/detachinterrupt.rst b/docs/source/lang/api/detachinterrupt.rst index 41642a7..82ce974 100644 --- a/docs/source/lang/api/detachinterrupt.rst +++ b/docs/source/lang/api/detachinterrupt.rst @@ -9,9 +9,8 @@ Used to disable an interrupt specified with Library Documentation --------------------- -.. FIXME once breathe knows how to get the correct detachInterupt -.. (right now it's copying from HardwareTimer), replace with a -.. doxygenfunction directive +.. FIXME [Breathe] once we can get the correct detachInterupt(), +.. replace with doxygenfunction. .. cpp:function:: void detachInterrupt(uint8 pin) @@ -39,5 +38,6 @@ See Also -------- - :ref:`attachInterrupt() ` +- :ref:`external-interrupts` -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/digitalread.rst b/docs/source/lang/api/digitalread.rst index 3502587..ccf4a4c 100644 --- a/docs/source/lang/api/digitalread.rst +++ b/docs/source/lang/api/digitalread.rst @@ -8,51 +8,44 @@ digitalRead() Reads the value from a specified digital pin, either :ref:`HIGH ` or :ref:`LOW `. - Library Documentation --------------------- .. doxygenfunction:: digitalRead +Discussion +---------- + +If the pin isn't connected to anything, ``digitalRead()`` can return +either HIGH or LOW (and this will change in a way that seems random). Example ------- -The following example turns the LED on when the button is pressed:: - - int ledPin = 13; // LED connected to Maple pin 13 - int buttonPin = 38; // BUT connected to Maple pin 38 +The following example turns the LED on or off when the button is pressed:: void setup() { - pinMode(ledPin, OUTPUT); - pinMode(buttonPin, INPUT); + pinMode(BOARD_LED_PIN, OUTPUT); + pinMode(BOARD_BUTTON_PIN, INPUT); } void loop() { - int val = digitalRead(buttonPin); // reads the input pin - digitalWrite(ledPin, val); + int val = digitalRead(BOARD_BUTTON_PIN); // reads the input pin + togglePin(BOARD_LED_PIN, val); } -Note ----- - -If the pin isn't connected to anything, ``digitalRead()`` can return -either HIGH or LOW (and this can change in a way that seems random). - Arduino Compatibility --------------------- The Maple version of ``digitalRead()`` is compatible with Arduino. - See Also -------- -- :ref:`pinMode ` -- :ref:`digitalWrite ` - - - - +- :ref:`BOARD_BUTTON_PIN ` +- :ref:`lang-isButtonPressed` +- :ref:`lang-pinmode` +- :ref:`lang-digitalWrite` +- :ref:`lang-togglepin` -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/digitalwrite.rst b/docs/source/lang/api/digitalwrite.rst index 6124d5f..376cbc3 100644 --- a/docs/source/lang/api/digitalwrite.rst +++ b/docs/source/lang/api/digitalwrite.rst @@ -21,42 +21,26 @@ If the pin has been configured as an ``OUTPUT`` with :ref:`pinMode() ` its voltage will be set to the corresponding value: 3.3V for ``HIGH``, and 0V (ground) for ``LOW``. -.. TODO make the following paragraphs true, but refer the reader to -.. INPUT_PULLUP and INPUT_PULLDOWN: - -If the pin is configured as an ``INPUT``, writing a ``HIGH`` value -with ``digitalWrite()`` will enable an internal pullup resistor. -Writing ``LOW`` will disable the pullup. The pullup resistor is enough -to light an LED dimly, so if LEDs appear to work, but very dimly, this -is a likely cause. The remedy is to set the pin to an output with the -:ref:`pinMode() ` function. - -.. note:: Pin 13 is harder to use as an input than the other pins - because it has an LED and resistor soldered to it in series. If you - enable its internal pull-up resistor, it will likely hang at around - 1.1V instead of the expected 3.3V because the onboard LED and - series resistor pull the voltage level down. If you must use pin 13 - as a digital input, use an external pull-down resistor. +Because it is soldered to an LED and resistor in series, your board's +:ref:`BOARD_LED_PIN ` will respond slightly +more slowly as an output than the other pins. Example ------- The following example sets pin 13 to ``HIGH``, makes a one-second-long delay, sets the pin back to ``LOW``, and delays again, causing a -blinking pattern:: - - - int ledPin = 13; // LED connected to digital pin 13 +blinking pattern (you could also use :ref:`lang-toggleled`):: void setup() { - pinMode(ledPin, OUTPUT); // sets the digital pin as output + pinMode(BOARD_LED_PIN, OUTPUT); // sets the digital pin as output } void loop() { - digitalWrite(ledPin, HIGH); // sets the LED on - delay(1000); // waits for a second - digitalWrite(ledPin, LOW); // sets the LED off - delay(1000); // waits for a second + digitalWrite(BOARD_LED_PIN, HIGH); // sets the LED on + delay(1000); // waits for a second + digitalWrite(BOARD_LED_PIN, LOW); // sets the LED off + delay(1000); // waits for a second } See Also @@ -64,5 +48,8 @@ See Also - :ref:`pinMode ` - :ref:`digitalRead ` +- :ref:`BOARD_LED_PIN ` +- :ref:`lang-toggleled` +- :ref:`lang-togglepin` -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/hardwaretimer.rst b/docs/source/lang/api/hardwaretimer.rst index 3f086ca..526beb6 100644 --- a/docs/source/lang/api/hardwaretimer.rst +++ b/docs/source/lang/api/hardwaretimer.rst @@ -10,8 +10,7 @@ built-in timer peripherals. More information on these peripherals (including code examples) is available in the :ref:`timers reference `. -.. FIXME update HardwareTimer documentation after redoing it in terms -.. of the new timer interface. +.. FIXME [0.0.10] Updated HardwareTimer documentation, with deprecation .. warning:: This class has been deprecated. It is not available in the current build. @@ -27,8 +26,7 @@ documented below on one of the predefined ``HardwareTimer`` instances. For example, to set the prescale factor on timer 1 to 5, call ``Timer1.setPrescaleFactor(5)``. -.. TODO add code examples that people can copy and paste in case -.. they're unfamiliar with namespace syntax +.. TODO add tutorial-style examples .. cpp:class:: HardwareTimer @@ -92,9 +90,8 @@ For example, to set the prescale factor on timer 1 to 5, call Set the given channel of this timer to the given :ref:`mode `. The parameter ``channel`` is one of 1, 2, 3, and 4, and corresponds to the compare channel you would - like to set. Refer to the full :ref:`pin mapping table - ` to match up timer channels and pin - numbers. + like to set. Refer to your board's :ref:`master pin map + ` to match up timer channels and pin numbers. .. cpp:function:: void HardwareTimer::setChannel1Mode(TimerMode mode) @@ -377,3 +374,87 @@ different. Other Functions ^^^^^^^^^^^^^^^ .. doxygenfunction:: getTimer + +Examples +^^^^^^^^ + +**LED blink**:: + + #define LED_RATE 500000 // in microseconds; should give 0.5Hz toggles + + void handler_led(void); + + void setup() + { + // Set up the LED to blink + pinMode(BOARD_LED_PIN, OUTPUT); + + // Setup Timer + Timer2.setChannel1Mode(TIMER_OUTPUTCOMPARE); + Timer2.setPeriod(LED_RATE); // in microseconds + Timer2.setCompare1(1); // overflow might be small + Timer2.attachCompare1Interrupt(handler_led); + } + + void loop() { + // Nothing! It's all in the interrupts + } + + void handler_led(void) { + toggleLED(); + } + +**Racing Counters**:: + + void handler_count1(void); + void handler_count2(void); + + int count1 = 0; + int count2 = 0; + + void setup() + { + // Set up BUT for input + pinMode(BOARD_BUTTON_PIN, INPUT_PULLUP); + + // Setup Counting Timers + Timer3.setChannel1Mode(TIMER_OUTPUTCOMPARE); + Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE); + Timer3.pause(); + Timer4.pause(); + Timer3.setCount(0); + Timer4.setCount(0); + Timer3.setOverflow(30000); + Timer4.setOverflow(30000); + Timer3.setCompare1(1000); // somewhere in the middle + Timer4.setCompare1(1000); + Timer3.attachCompare1Interrupt(handler1); + Timer4.attachCompare1Interrupt(handler2); + Timer3.resume(); + Timer4.resume(); + } + + void loop() { + // Display the running counts + SerialUSB.print("Count 1: "); + SerialUSB.print(count1); + SerialUSB.print("\t\tCount 2: "); + SerialUSB.println(count2); + + // Run... while BUT is held, pause Count2 + for(int i = 0; i<1000; i++) { + if(digitalRead(BOARD_BUTTON_PIN)) { + Timer4.pause(); + } else { + Timer4.resume(); + } + delay(1); + } + } + + void handler1(void) { + count1++; + } + void handler2(void) { + count2++; + } diff --git a/docs/source/lang/api/highbyte.rst b/docs/source/lang/api/highbyte.rst index 50a1fa6..4cb6f9b 100644 --- a/docs/source/lang/api/highbyte.rst +++ b/docs/source/lang/api/highbyte.rst @@ -52,8 +52,4 @@ See Also - :ref:`lowByte() ` - - - - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/loop.rst b/docs/source/lang/api/loop.rst index d8f6183..c2a5097 100644 --- a/docs/source/lang/api/loop.rst +++ b/docs/source/lang/api/loop.rst @@ -15,7 +15,6 @@ Example :: - int buttonPin = 38; // setup initializes serial and the button pin @@ -42,4 +41,4 @@ See Also - :ref:`setup() ` -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/lowbyte.rst b/docs/source/lang/api/lowbyte.rst index 58e622f..c513711 100644 --- a/docs/source/lang/api/lowbyte.rst +++ b/docs/source/lang/api/lowbyte.rst @@ -22,4 +22,4 @@ Returns The low byte's value (this will be between 0 and 255). -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/map.rst b/docs/source/lang/api/map.rst index 79122b3..69661a0 100644 --- a/docs/source/lang/api/map.rst +++ b/docs/source/lang/api/map.rst @@ -65,4 +65,4 @@ See Also - :ref:`constrain() ` -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/max.rst b/docs/source/lang/api/max.rst index d38eebe..d356f08 100644 --- a/docs/source/lang/api/max.rst +++ b/docs/source/lang/api/max.rst @@ -53,7 +53,7 @@ functions inside the parentheses. It may lead to incorrect results:: Arduino Compatibility --------------------- -The Maple version of ``max()`` is compatible with Arduino. +The Maple implementation of ``max()`` is compatible with Arduino. See Also -------- @@ -61,5 +61,4 @@ See Also - :ref:`min() ` - :ref:`constrain() ` - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/micros.rst b/docs/source/lang/api/micros.rst index f12976b..de85303 100644 --- a/docs/source/lang/api/micros.rst +++ b/docs/source/lang/api/micros.rst @@ -43,4 +43,4 @@ See Also - :ref:`delay() ` - :ref:`delayMicroseconds() ` -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/millis.rst b/docs/source/lang/api/millis.rst index 0288c56..db0531c 100644 --- a/docs/source/lang/api/millis.rst +++ b/docs/source/lang/api/millis.rst @@ -49,4 +49,4 @@ See Also - :ref:`delay ` - :ref:`delayMicroseconds ` -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/min.rst b/docs/source/lang/api/min.rst index 1245f6f..3307105 100644 --- a/docs/source/lang/api/min.rst +++ b/docs/source/lang/api/min.rst @@ -62,5 +62,4 @@ See Also - :ref:`max() ` - :ref:`constrain() ` - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/pinmode.rst b/docs/source/lang/api/pinmode.rst index 03cbcfa..8cee3e5 100644 --- a/docs/source/lang/api/pinmode.rst +++ b/docs/source/lang/api/pinmode.rst @@ -60,13 +60,13 @@ set up a pin for these purposes before a call to, e.g., :ref:`lang-analogRead`. In practice, this should only add a few lines to your :ref:`lang-setup` function. -.. TODO verify following before putting it in: +.. TODO [0.1.0] verify following before putting it in: .. ``OUTPUT_OPEN_DRAIN``, ``INPUT_PULLUP``, ``INPUT_PULLDOWN``, and .. ``PWM_OPEN_DRAIN`` modes represent functionality not currently .. available on Arduino boards. -See also +See Also -------- - :ref:`lang-constants` @@ -74,6 +74,4 @@ See also - :ref:`lang-digitalread` - Maple :ref:`GPIO ` reference page - - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/pow.rst b/docs/source/lang/api/pow.rst index 4280400..219a866 100644 --- a/docs/source/lang/api/pow.rst +++ b/docs/source/lang/api/pow.rst @@ -10,8 +10,6 @@ Library Documentation .. doxygenfunction:: pow -.. TODO LATER some examples - See Also -------- @@ -19,5 +17,4 @@ See Also - :ref:`float ` - :ref:`double ` - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/pwmwrite.rst b/docs/source/lang/api/pwmwrite.rst index cea602b..5cc112e 100644 --- a/docs/source/lang/api/pwmwrite.rst +++ b/docs/source/lang/api/pwmwrite.rst @@ -11,10 +11,13 @@ pwmWrite(), the pin will output a steady square wave with the given duty cycle. You can change the duty cycle later by calling pwmWrite() again with the same pin and a different duty. -.. FIXME board-specific information - -On the Maple, the pins which support PWM are: 0, 1, 2, 3, 5, 6, 7, 8, -9, 11, 12, 14, 24, 27, and 28. +The pins which support PWM have ``PWM`` listed underneath their number +on your board's silkscreen. These pin numbers are available to your +program in the :ref:`boardPWMPins ` +board-specific array. The number of pins which are capable of PWM on +your board is given by the ``BOARD_NR_PWM_PINS`` constant. These +values are documented for each board in the :ref:`Board Hardware +Documentation ` pages. The Arduino function :ref:`analogWrite() ` is an alias for ``pwmWrite()``, but it is badly named, and its use is @@ -54,4 +57,5 @@ potentiometer:: See Also -------- -- :ref:`Maple PWM tutorial ` +- :ref:`Maple PWM tutorial ` +- :ref:`boardPWMPins ` diff --git a/docs/source/lang/api/random.rst b/docs/source/lang/api/random.rst index dd8871d..9875ee6 100644 --- a/docs/source/lang/api/random.rst +++ b/docs/source/lang/api/random.rst @@ -10,9 +10,7 @@ The ``random()`` function generates pseudo-random numbers. Library Documentation --------------------- -.. FIXME keep tracking Sphinx/Breathe's ability to reference -.. overloaded functions so we can use doxygenfunction instead of -.. manually documenting. +.. FIXME [Breathe] use doxygenfunction when possible .. cpp:function:: random(long max) @@ -70,4 +68,4 @@ See Also - :ref:`randomSeed() ` -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/randomseed.rst b/docs/source/lang/api/randomseed.rst index d0a15b7..ca7b75f 100644 --- a/docs/source/lang/api/randomseed.rst +++ b/docs/source/lang/api/randomseed.rst @@ -57,4 +57,4 @@ See Also - :ref:`random() ` -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/serial.rst b/docs/source/lang/api/serial.rst index 417063d..0821f43 100644 --- a/docs/source/lang/api/serial.rst +++ b/docs/source/lang/api/serial.rst @@ -12,49 +12,20 @@ devices. Introduction ------------ -.. FIXME [Maple-specific values] -.. FIXME [0.0.10] Serial4, Serial5 updates for high-density devices +.. FIXME [0.0.10] UART4, UART5 -The Maple has three serial ports (also known as a UARTs or USARTs): -``Serial1``, ``Serial2``, and ``Serial3``. They communicate using the -pins summarized in the following table: - -.. list-table:: - :header-rows: 1 - - * - Serial port - - TX, RX, CK - - CTS, RTS (if present) - - * - ``Serial1`` - - 7, 8, 6 - - - - * - ``Serial2`` - - 1, 0, 10 - - 2, 3 - - * - ``Serial3`` - - 29, 30, 31 - - 32, 33 - -Thus, if you use a particular serial port, you cannot also use its -communication pins for other purposes at the same time. - -If you want to communicate with the Maple using the provided USB port, -use :ref:`SerialUSB ` instead. - -To use them to communicate with an external TTL serial device, connect -the TX pin to your device's RX pin, the RX to your device's TX pin, -and the ground of your Maple to your device's ground. +To use a serial port to communicate with an external serial device, +connect the TX pin to your device's RX pin, the RX to your device's TX +pin, and your Maple board's ground to your device's ground. .. warning:: Don't connect these pins directly to an RS232 serial port; they operate at +/- 12V and can damage your board. - Library Documentation --------------------- +.. FIXME [0.1.0] Tutorial-style usage introduction + All of the ``Serial[1,2,3]`` objects are instances of the ``HardwareSerial`` class, which is documented in this section. (This means that you can use any of these functions on any of ``Serial1``, @@ -209,9 +180,10 @@ Arduino Compatibility Note -------------------------- Unlike the Arduino, none of the Maple's serial ports is connected to -the USB port on the Maple board (for that, use :ref:`SerialUSB -`). Thus, to use these pins to communicate with your -personal computer, you will need an additional USB-to-serial adapter. +the USB port on the Maple board. If you want to communicate using the +built-in USB port, use :ref:`SerialUSB ` instead. You +will need an additional USB-to-serial adapter to communicate between a +USART and your computer. .. FIXME [0.1.0] port these examples over @@ -226,4 +198,4 @@ personal computer, you will need an additional USB-to-serial adapter. .. - `Serial Call Response `_ .. - `Serial Call Response ASCII `_ -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/setup.rst b/docs/source/lang/api/setup.rst index 837ddd6..1e8e3b8 100644 --- a/docs/source/lang/api/setup.rst +++ b/docs/source/lang/api/setup.rst @@ -26,4 +26,4 @@ Example // ... } -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/sin.rst b/docs/source/lang/api/sin.rst index 398b8f3..3e28c0b 100644 --- a/docs/source/lang/api/sin.rst +++ b/docs/source/lang/api/sin.rst @@ -28,5 +28,4 @@ See Also - :ref:`float ` - :ref:`double ` - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/sq.rst b/docs/source/lang/api/sq.rst index bd32648..96724d3 100644 --- a/docs/source/lang/api/sq.rst +++ b/docs/source/lang/api/sq.rst @@ -42,5 +42,4 @@ Arduino Compatibility Maple's implementation of ``sq()`` is compatible with Arduino. - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/tan.rst b/docs/source/lang/api/tan.rst index 4bbe0db..b1aed31 100644 --- a/docs/source/lang/api/tan.rst +++ b/docs/source/lang/api/tan.rst @@ -22,10 +22,9 @@ Note that the Maple implementation comes from `newlib See Also -------- - - :ref:`sin ` - :ref:`cos ` - :ref:`float ` - :ref:`double ` -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/api/volatile.rst b/docs/source/lang/api/volatile.rst index 276bb6a..1b72897 100644 --- a/docs/source/lang/api/volatile.rst +++ b/docs/source/lang/api/volatile.rst @@ -24,8 +24,8 @@ for efficiency). A variable should be declared ``volatile`` whenever its value can be changed by something beyond the control of the code section in which it appears, such as an :ref:`external interrupt -`. On the Maple, the only place that this is -likely to occur is in sections of code associated with interrupts. +`. (The only place that this is likely to occur +in most programs is inside of code called by interrupts). Example ------- @@ -55,11 +55,11 @@ Example } } -See also +See Also -------- - :ref:`External Interrupts ` - :ref:`lang-attachinterrupt` - :ref:`lang-detachinterrupt` -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cc-attribution.txt b/docs/source/lang/cc-attribution.txt index e100140..11302b2 100644 --- a/docs/source/lang/cc-attribution.txt +++ b/docs/source/lang/cc-attribution.txt @@ -3,7 +3,8 @@ .. admonition:: License and Attribution - This documentation page was adapted from the `Arduino Reference - Documentation `_\ , which - is released under a `Creative Commons Attribution-ShareAlike 3.0 - License `_. + Some information in this page was adapted from the `Arduino + Reference Documentation + `_\ , which is released + under a `Creative Commons Attribution-ShareAlike 3.0 License + `_. diff --git a/docs/source/lang/cpp/arithmetic.rst b/docs/source/lang/cpp/arithmetic.rst index 26e2811..cef3954 100644 --- a/docs/source/lang/cpp/arithmetic.rst +++ b/docs/source/lang/cpp/arithmetic.rst @@ -121,4 +121,4 @@ See Also - :ref:`sizeof `\ () -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/array.rst b/docs/source/lang/cpp/array.rst index 30a818f..39d4d91 100644 --- a/docs/source/lang/cpp/array.rst +++ b/docs/source/lang/cpp/array.rst @@ -113,11 +113,9 @@ Arduino Compatibility Arrays on Maple are identical those on Arduino. -See also +See Also -------- - :ref:`Storing arrays in FLASH memory ` - - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/assignment.rst b/docs/source/lang/cpp/assignment.rst index f9430b4..6379298 100644 --- a/docs/source/lang/cpp/assignment.rst +++ b/docs/source/lang/cpp/assignment.rst @@ -57,4 +57,4 @@ See Also `_ for more information. -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/bitshift.rst b/docs/source/lang/cpp/bitshift.rst index e1c8de0..47413f2 100644 --- a/docs/source/lang/cpp/bitshift.rst +++ b/docs/source/lang/cpp/bitshift.rst @@ -140,5 +140,4 @@ See Also - :ref:`lang-bitwrite` - :ref:`lang-bitclear` - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/bitwisemath.rst b/docs/source/lang/cpp/bitwisemath.rst index 28fe6bf..59794ba 100644 --- a/docs/source/lang/cpp/bitwisemath.rst +++ b/docs/source/lang/cpp/bitwisemath.rst @@ -182,5 +182,4 @@ See Also - :ref:`Compound bitwise operations ` (``&=``, ``|=``, ``^=``). - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/boolean.rst b/docs/source/lang/cpp/boolean.rst index 8d6aa5c..f09345e 100644 --- a/docs/source/lang/cpp/boolean.rst +++ b/docs/source/lang/cpp/boolean.rst @@ -87,5 +87,4 @@ See Also ``|=``, ``^=``). - :ref:`if statement ` - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/booleanvariables.rst b/docs/source/lang/cpp/booleanvariables.rst index 6051b8c..0d76a12 100644 --- a/docs/source/lang/cpp/booleanvariables.rst +++ b/docs/source/lang/cpp/booleanvariables.rst @@ -42,13 +42,11 @@ Example } } -See also +See Also -------- - - :ref:`Boolean constants ` - :ref:`Boolean operators ` - :ref:`Variables ` - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/break.rst b/docs/source/lang/cpp/break.rst index ce8ac17..f367b99 100644 --- a/docs/source/lang/cpp/break.rst +++ b/docs/source/lang/cpp/break.rst @@ -29,7 +29,4 @@ Example delay(50); } - - - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/byte.rst b/docs/source/lang/cpp/byte.rst index 45c9d5f..4634594 100644 --- a/docs/source/lang/cpp/byte.rst +++ b/docs/source/lang/cpp/byte.rst @@ -30,5 +30,4 @@ See Also - :ref:`byte() ` (casting a value to a byte) - :ref:`Variables ` - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/bytecast.rst b/docs/source/lang/cpp/bytecast.rst index b3f0de2..24c3b9e 100644 --- a/docs/source/lang/cpp/bytecast.rst +++ b/docs/source/lang/cpp/bytecast.rst @@ -24,13 +24,11 @@ Syntax ``byte(x)`` - Parameters ---------- **x**: a value of any integer type - Returns ------- @@ -38,13 +36,9 @@ The value, converted to a ``byte``. Note, however, that if the value is larger than the maximum value you can store in a byte (255), then the results might be strange and unexpected. - See Also -------- - :ref:`lang-byte` - - - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/char.rst b/docs/source/lang/cpp/char.rst index b8747f3..686c0d1 100644 --- a/docs/source/lang/cpp/char.rst +++ b/docs/source/lang/cpp/char.rst @@ -10,7 +10,6 @@ value from -128 to 127). Character literals are written in single quotes, like this: ``'A'`` (for multiple characters - strings - use double quotes: ``"ABC"``). - Just like everything else on a computer, characters are stored as numbers. You can see the specific encoding in the `ASCII chart `_\ @@ -25,26 +24,21 @@ The ``char`` datatype is a signed type, meaning that it encodes numbers from -128 to 127. For an unsigned type, which stores values from 0 to 255, just use the type ``unsigned char`` (two words). - Example ------- :: - // the following two lines are equivalent, using the ASCII + // The following two lines are equivalent, using the ASCII // character encoding: char c = 'A'; char c = 65; - -See also +See Also -------- - - :ref:`lang-int` - :ref:`lang-array` (a string is just an array of ``char``\ s) - :ref:`Serial.println() ` - - .. include:: cc-attribution.txt diff --git a/docs/source/lang/cpp/charcast.rst b/docs/source/lang/cpp/charcast.rst index a480dec..640ad85 100644 --- a/docs/source/lang/cpp/charcast.rst +++ b/docs/source/lang/cpp/charcast.rst @@ -12,13 +12,11 @@ Syntax ``char(x)`` - Parameters ---------- **x**: a value of any type - Returns ------- @@ -26,11 +24,9 @@ The value, converted to a ``char``. Note, however, that if the value is outside the range of a ``char`` (-128 to 127), then the results might be strange and unexpected. - See Also -------- - :ref:`char ` - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/comments.rst b/docs/source/lang/cpp/comments.rst index c5f118a..1428dc3 100644 --- a/docs/source/lang/cpp/comments.rst +++ b/docs/source/lang/cpp/comments.rst @@ -61,7 +61,4 @@ just ignores them. This can be especially useful when trying to locate a problem, or when a program refuses to compile and the compiler error is cryptic or unhelpful. - - - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/comparison.rst b/docs/source/lang/cpp/comparison.rst index b24355f..9cd0a9f 100644 --- a/docs/source/lang/cpp/comparison.rst +++ b/docs/source/lang/cpp/comparison.rst @@ -83,5 +83,4 @@ Comparison operators, along with :ref:`boolean operators appears within a conditional doesn't mean it's automatically wrong. Be careful to know what you mean.) - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/compoundarithmetic.rst b/docs/source/lang/cpp/compoundarithmetic.rst index 420f1db..d70a43c 100644 --- a/docs/source/lang/cpp/compoundarithmetic.rst +++ b/docs/source/lang/cpp/compoundarithmetic.rst @@ -40,5 +40,4 @@ See Also - :ref:`Arithmetic operators ` - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/compoundbitwise.rst b/docs/source/lang/cpp/compoundbitwise.rst index 8231130..4efe5df 100644 --- a/docs/source/lang/cpp/compoundbitwise.rst +++ b/docs/source/lang/cpp/compoundbitwise.rst @@ -226,5 +226,4 @@ See Also - :ref:`Boolean operations ` (``&&``, ``||``) - :ref:`Bitwise operators ` (``&``, ``|``, ``^``, ``~``) - .. include:: cc-attribution.txt diff --git a/docs/source/lang/cpp/const.rst b/docs/source/lang/cpp/const.rst index 52de85f..ad0c580 100644 --- a/docs/source/lang/cpp/const.rst +++ b/docs/source/lang/cpp/const.rst @@ -21,7 +21,7 @@ method for defining constants than ``#define``. Example ------- -:: + :: // this defines a variable called "pi", which cannot be changed: const float pi = 3.14; @@ -33,7 +33,6 @@ Example pi = 7; // illegal - you can't write to (modify) a constant - **#define** or **const** ------------------------ @@ -48,5 +47,4 @@ See Also - :ref:`#define ` - :ref:`volatile ` - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/continue.rst b/docs/source/lang/cpp/continue.rst index 13d1815..2a694f6 100644 --- a/docs/source/lang/cpp/continue.rst +++ b/docs/source/lang/cpp/continue.rst @@ -27,6 +27,4 @@ Example delay(50); } - - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/curly-braces.rst b/docs/source/lang/cpp/curly-braces.rst index a4bd3dc..df2fe2a 100644 --- a/docs/source/lang/cpp/curly-braces.rst +++ b/docs/source/lang/cpp/curly-braces.rst @@ -99,11 +99,8 @@ reference page for more information):: .. rubric:: Footnotes -.. TODO remove this once IDE 0.1.0 released - .. [#fbug] At present this feature is slightly buggy as the IDE will often find (incorrectly) a brace in text that has been commented out. - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/define.rst b/docs/source/lang/cpp/define.rst index 677390d..bdf7283 100644 --- a/docs/source/lang/cpp/define.rst +++ b/docs/source/lang/cpp/define.rst @@ -13,7 +13,6 @@ defined value at compile time. This can have some unwanted side effects. In general, the :ref:`const ` keyword is preferred for defining constants. - Syntax ------ @@ -42,7 +41,7 @@ is, **don't do this, either**:: Example ------- -:: + :: #define LED_PIN 13 // The compiler will replace any mention of LED_PIN with @@ -52,5 +51,4 @@ See Also -------- - :ref:`const ` - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/double.rst b/docs/source/lang/cpp/double.rst index 1527778..59422eb 100644 --- a/docs/source/lang/cpp/double.rst +++ b/docs/source/lang/cpp/double.rst @@ -43,6 +43,4 @@ See Also - :ref:`float ` - - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/doublecast.rst b/docs/source/lang/cpp/doublecast.rst index 16a9907..d3f32ce 100644 --- a/docs/source/lang/cpp/doublecast.rst +++ b/docs/source/lang/cpp/doublecast.rst @@ -24,4 +24,4 @@ See Also - :ref:`float ` - :ref:`float() ` -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/dowhile.rst b/docs/source/lang/cpp/dowhile.rst index fe92226..d229122 100644 --- a/docs/source/lang/cpp/dowhile.rst +++ b/docs/source/lang/cpp/dowhile.rst @@ -23,5 +23,4 @@ Example:: x = readSensors(); // check the sensors } while (x < 100); - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/float.rst b/docs/source/lang/cpp/float.rst index 6937c8c..5195fac 100644 --- a/docs/source/lang/cpp/float.rst +++ b/docs/source/lang/cpp/float.rst @@ -47,4 +47,4 @@ See Also - :ref:`double ` - :ref:`Variables ` -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/floatcast.rst b/docs/source/lang/cpp/floatcast.rst index 4766478..af92543 100644 --- a/docs/source/lang/cpp/floatcast.rst +++ b/docs/source/lang/cpp/floatcast.rst @@ -25,4 +25,4 @@ See Also - :ref:`double ` - :ref:`double() ` -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/for.rst b/docs/source/lang/cpp/for.rst index 71c5aca..78ea562 100644 --- a/docs/source/lang/cpp/for.rst +++ b/docs/source/lang/cpp/for.rst @@ -123,7 +123,7 @@ questions (answers are in footnote [#fanswers]_\ ): 2. Why does it stop at 64? -See also +See Also -------- - :ref:`while ` loops @@ -139,4 +139,4 @@ See also false, and the loop stops. -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/goto.rst b/docs/source/lang/cpp/goto.rst index ff2f248..2c0b3b0 100644 --- a/docs/source/lang/cpp/goto.rst +++ b/docs/source/lang/cpp/goto.rst @@ -126,5 +126,4 @@ See Also - Knuth, Donald. `Structured Programming with go to Statements `_ (PDF) - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/if.rst b/docs/source/lang/cpp/if.rst index bef89e2..d57b9f1 100644 --- a/docs/source/lang/cpp/if.rst +++ b/docs/source/lang/cpp/if.rst @@ -118,4 +118,4 @@ See Also - :ref:`boolean operators ` - :ref:`comparison operators ` -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/include.rst b/docs/source/lang/cpp/include.rst index 74fe7af..163509d 100644 --- a/docs/source/lang/cpp/include.rst +++ b/docs/source/lang/cpp/include.rst @@ -67,6 +67,4 @@ root `_ of a number:: SerialUSB.println(cubeRootOf3); } - - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/increment.rst b/docs/source/lang/cpp/increment.rst index 6dffa80..c423d1a 100644 --- a/docs/source/lang/cpp/increment.rst +++ b/docs/source/lang/cpp/increment.rst @@ -34,4 +34,4 @@ See Also - :ref:`lang-compoundarithmetic` -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/intcast.rst b/docs/source/lang/cpp/intcast.rst index 386fe14..da838c7 100644 --- a/docs/source/lang/cpp/intcast.rst +++ b/docs/source/lang/cpp/intcast.rst @@ -23,7 +23,4 @@ See Also - :ref:`int ` - - - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/longcast.rst b/docs/source/lang/cpp/longcast.rst index f588fc6..493ad67 100644 --- a/docs/source/lang/cpp/longcast.rst +++ b/docs/source/lang/cpp/longcast.rst @@ -24,4 +24,4 @@ See Also - :ref:`long ` - :ref:`long long ` -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/longlong.rst b/docs/source/lang/cpp/longlong.rst index 0ba56ed..d942cb4 100644 --- a/docs/source/lang/cpp/longlong.rst +++ b/docs/source/lang/cpp/longlong.rst @@ -53,4 +53,4 @@ See Also - :ref:`Integer Constants ` - :ref:`Variables ` -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/modulo.rst b/docs/source/lang/cpp/modulo.rst index 289fba0..013d07e 100644 --- a/docs/source/lang/cpp/modulo.rst +++ b/docs/source/lang/cpp/modulo.rst @@ -67,4 +67,4 @@ See Also - :ref:`Arithmetic ` -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/pointer.rst b/docs/source/lang/cpp/pointer.rst index 0a42270..ff4ec32 100644 --- a/docs/source/lang/cpp/pointer.rst +++ b/docs/source/lang/cpp/pointer.rst @@ -28,4 +28,4 @@ See Also - http://xkcd.com/138/ -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/return.rst b/docs/source/lang/cpp/return.rst index b4ef5fd..d9aecbe 100644 --- a/docs/source/lang/cpp/return.rst +++ b/docs/source/lang/cpp/return.rst @@ -57,5 +57,4 @@ See Also - :ref:`comments ` - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/scope.rst b/docs/source/lang/cpp/scope.rst index 7b65bab..a270428 100644 --- a/docs/source/lang/cpp/scope.rst +++ b/docs/source/lang/cpp/scope.rst @@ -117,4 +117,4 @@ See Also - `C++ programming Wikibook `_. - Wikipedia article on `scope `_ -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/semicolon.rst b/docs/source/lang/cpp/semicolon.rst index 8164616..05e6218 100644 --- a/docs/source/lang/cpp/semicolon.rst +++ b/docs/source/lang/cpp/semicolon.rst @@ -19,7 +19,4 @@ compiler error comes up, one of the first things to check is a missing semicolon, in the immediate vicinity, preceding the line at which the compiler complained. - - - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/sizeof.rst b/docs/source/lang/cpp/sizeof.rst index eae509c..ec2dea6 100644 --- a/docs/source/lang/cpp/sizeof.rst +++ b/docs/source/lang/cpp/sizeof.rst @@ -60,5 +60,5 @@ would look something like this:: standard guarantees, however, is that a ``char`` occupies at *least* 8 bits. -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/sqrt.rst b/docs/source/lang/cpp/sqrt.rst index 956a754..fbabf82 100644 --- a/docs/source/lang/cpp/sqrt.rst +++ b/docs/source/lang/cpp/sqrt.rst @@ -21,5 +21,4 @@ See Also - :ref:`pow ` - :ref:`sq ` - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/static.rst b/docs/source/lang/cpp/static.rst index 5d1802e..8c52ba0 100644 --- a/docs/source/lang/cpp/static.rst +++ b/docs/source/lang/cpp/static.rst @@ -53,5 +53,4 @@ then incremented, so it starts out at one. Subsequent calls to it was declared ``static``. Thus, ``numSensorReadings`` is a count of the number of times that ``readSensors()`` has been called. - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/string.rst b/docs/source/lang/cpp/string.rst index 0a270da..84917c1 100644 --- a/docs/source/lang/cpp/string.rst +++ b/docs/source/lang/cpp/string.rst @@ -124,5 +124,4 @@ See Also - :ref:`__attribute__ ` - :ref:`Variables ` - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/switchcase.rst b/docs/source/lang/cpp/switchcase.rst index b484bc5..e31ccf3 100644 --- a/docs/source/lang/cpp/switchcase.rst +++ b/docs/source/lang/cpp/switchcase.rst @@ -110,9 +110,9 @@ value as the variable to compare. In this case, you can write down all of the values the ``enum`` takes as ``case`` statements, and be sure you've covered all the possibilities. -See also: +See Also: --------- - :ref:`if/else ` -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/unsignedchar.rst b/docs/source/lang/cpp/unsignedchar.rst index 5b946ed..45fedeb 100644 --- a/docs/source/lang/cpp/unsignedchar.rst +++ b/docs/source/lang/cpp/unsignedchar.rst @@ -16,18 +16,17 @@ won't store negative numbers; it is also subject to the same Example ------- -:: + :: unsigned char c = 240; See Also -------- - - :ref:`byte ` - :ref:`int ` - :ref:`array ` - :ref:`SerialUSB.println() ` - :ref:`Serial.println() ` -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/unsignedint.rst b/docs/source/lang/cpp/unsignedint.rst index ad3e2f2..b7d9716 100644 --- a/docs/source/lang/cpp/unsignedint.rst +++ b/docs/source/lang/cpp/unsignedint.rst @@ -56,4 +56,4 @@ See Also - :ref:`Integer Constants ` - :ref:`Variables ` -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/unsignedlonglong.rst b/docs/source/lang/cpp/unsignedlonglong.rst index 910b7e4..a1143f0 100644 --- a/docs/source/lang/cpp/unsignedlonglong.rst +++ b/docs/source/lang/cpp/unsignedlonglong.rst @@ -40,4 +40,4 @@ See Also - :ref:`Integer Constants ` - :ref:`Variables ` -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/variables.rst b/docs/source/lang/cpp/variables.rst index 336d5ab..9ffdd1d 100644 --- a/docs/source/lang/cpp/variables.rst +++ b/docs/source/lang/cpp/variables.rst @@ -165,6 +165,5 @@ See Also (usually) stored `_ on computers. - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/void.rst b/docs/source/lang/cpp/void.rst index 88c9c64..7af0acd 100644 --- a/docs/source/lang/cpp/void.rst +++ b/docs/source/lang/cpp/void.rst @@ -28,6 +28,4 @@ Example // ... } -.. TODO doc page on function declaration? - -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/cpp/while.rst b/docs/source/lang/cpp/while.rst index 9047d05..e66e0aa 100644 --- a/docs/source/lang/cpp/while.rst +++ b/docs/source/lang/cpp/while.rst @@ -35,4 +35,4 @@ Example var++; } -.. include:: cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/lang/unimplemented/notone.rst b/docs/source/lang/unimplemented/notone.rst index 485c9c5..8af878b 100644 --- a/docs/source/lang/unimplemented/notone.rst +++ b/docs/source/lang/unimplemented/notone.rst @@ -10,41 +10,28 @@ Stops the generation of a square wave triggered by `tone `_\ (). Has no effect if no tone is being generated. - - **NOTE:** if you want to play different pitches on multiple pins, you need to call noTone() on one pin before calling tone() on the next pin. - - Syntax ------ noTone(pin) - - Parameters ---------- pin: the pin on which to stop generating the tone - - Returns ------- -nothing - - +Nothing. -See also +See Also -------- - - `tone `_ () - - .. include:: /lang/cc-attribution.txt diff --git a/docs/source/lang/unimplemented/tone.rst b/docs/source/lang/unimplemented/tone.rst index f83bf6b..13d581e 100644 --- a/docs/source/lang/unimplemented/tone.rst +++ b/docs/source/lang/unimplemented/tone.rst @@ -12,70 +12,47 @@ continues until a call to `noTone `_\ (). The pin can be connected to a piezo buzzer or other speaker to play tones. - - Only one tone can be generated at a time. If a tone is already playing on a different pin, the call to tone() will have no effect. If the tone is playing on the same pin, the call will set its frequency. - - Use of the tone() function will interfere with PWM output on pins 3 and 11 (on boards other than the Mega). - - **NOTE:** if you want to play different pitches on multiple pins, you need to call noTone() on one pin before calling tone() on the next pin. - - Syntax ------ tone(pin, frequency) tone(pin, frequency, duration) - - Parameters ---------- pin: the pin on which to generate the tone - - frequency: the frequency of the tone in hertz - - duration: the duration of the tone in milliseconds (optional) - - Returns ------- nothing - - -See also +See Also -------- - - `noTone `_\ () - `analogWrite `_\ () - `Tutorial:Tone `_ - `Tutorial:Pitch follower `_ - `Tutorial:Simple Keyboard `_ - `Tutorial: multiple tones `_ - - - `Tutorial: PWM `_ - - -.. include:: /lang/cc-attribution.txt +.. include:: /arduino-cc-attribution.txt diff --git a/docs/source/language-index.rst b/docs/source/language-index.rst index a064b3e..225a9ae 100644 --- a/docs/source/language-index.rst +++ b/docs/source/language-index.rst @@ -10,8 +10,21 @@ API references for documented libmaple functionality. The "C++ for Maple" pages are intended as a minimal reference/refresher for programmers familiar with the Arduino language. -**Looking for something else?** The low-level :ref:`libmaple library -interfaces ` are documented separately. +.. admonition:: **Looking for Something Else?** + + - See the :ref:`libraries` for extra built-in libraries for dealing + with different kinds of hardware. + + - If you're looking for something from the C standard library (like + ``atoi()``, for instance): the :ref:`CodeSourcery GCC compiler + ` used to compile your programs is configured to link + against `newlib `_, and allows the + use of any of its header files. However, dynamic memory allocation + (``malloc()``, etc.) is not available. + + - If you're looking for pointers to low-level details, see the + :ref:`Language Recommended Reading + `. .. _index-language-index-cpp: .. _index-language-index-api: diff --git a/docs/source/language.rst b/docs/source/language.rst index 111a1f1..3ecbe43 100644 --- a/docs/source/language.rst +++ b/docs/source/language.rst @@ -10,8 +10,7 @@ The Maple can be programmed in the `Wiring `_ language, which is the same language used to program the `Arduino `_ boards. -.. TODO Wiring tutorial -- just describe setup()/loop(), then link to -.. some of the the bajillion external tutorials +.. TODO [0.2.0?] Wiring tutorial C or C++ programmers curious about the differences between the Wiring language and C++ may wish to skip to the @@ -20,31 +19,29 @@ language and C++ may wish to skip to the .. contents:: Contents :local: -.. _language-lang-docs: - -Maple Language Reference ------------------------- +.. admonition:: **Looking for Something Else?** -The following table summarizes the available core language features. -A more exhaustive index is available at the :ref:`language-index`. + - See the :ref:`libraries` for extra built-in libraries for dealing + with different kinds of hardware. -.. FIXME mention Maple Native supports malloc(), free(), operator -.. new(), and operator delete(), when that is a true thing to say. + - If you're looking for something from the C standard library (like + ``atoi()``, for instance): the :ref:`CodeSourcery GCC compiler + ` used to compile your programs is configured to link + against `newlib `_, and allows the + use of any of its header files. However, dynamic memory allocation + (``malloc()``, etc.) is not available. -**Looking for something else?** + - If you're looking for pointers to low-level details, see this page's + :ref:`Recommended Reading `. -- See the :ref:`libraries` for extra built-in libraries for dealing - with different kinds of hardware. +.. _language-lang-docs: -- If you're looking for something from the C standard library (like - ``atoi()``, for instance): the :ref:`CodeSourcery GCC compiler - ` used to compile your programs is configured to link - against `newlib `_, and allows the - use of any of its header files. However, dynamic memory allocation - (``malloc()``, etc.) is not available. +Maple Language Reference +------------------------ -- If you're looking for low-level details, see the :ref:`libmaple - ` reference page. +The following table summarizes the most important core language +features. An exhaustive index is available at the +:ref:`language-index`. +--------------------------------------------+----------------------------------------------+---------------------------------------------------+ | Structure | Variables | Functions | @@ -458,14 +455,26 @@ Which could plausibly be turned into the final source file :: while (true) loop(); } +.. _language-recommended-reading: + Recommended Reading ------------------- -* `newlib Documentation `_ - * :ref:`libmaple Documentation ` - -* ST documentation: - - * `Reference Manual `_ (pdf) - * `Programming Manual `_ (assembly language and register reference) +* Your board's :ref:`Board Hardware Documentation ` page +* ST Documentation: + * Reference Manual `RM0008 + `_ + (PDF). This is the most important reference work on the STM32 + line, and covers the low-level hardware capabilities and + interfaces in great detail. + * `Programming Manual + `_ + (PDF). This is an assembly language and register reference for + the STM32 line. +* ARM Documentation: + * `Cortex-M3 Technical Reference Manual, Revision r1p1 + `_ + (PDF). This ARM manual specifies much of the the Cortex M3 + Architecture, including instruction timings. +* `newlib Documentation `_ diff --git a/docs/source/libmaple/api/systick.rst b/docs/source/libmaple/api/systick.rst index 5ec906c..a02b8e4 100644 --- a/docs/source/libmaple/api/systick.rst +++ b/docs/source/libmaple/api/systick.rst @@ -1,6 +1,14 @@ .. highlight:: c + + .. _libmaple-systick: +.. FIXME [0.0.10] move these to the right places: + +.. _libmaple-systick_disable: + +.. _libmaple-systick_resume: + ``systick.h`` ============= diff --git a/docs/source/libraries.rst b/docs/source/libraries.rst index 7623963..2bc8b11 100644 --- a/docs/source/libraries.rst +++ b/docs/source/libraries.rst @@ -10,13 +10,13 @@ .. Note: if you port an Arduino library and document it here, be sure .. to update compatibility.rst to reflect that fact. -This page briefly summarizes the Arduino libraries that have been -ported to Maple. You can use a library from within a sketch by going -to Sketch > Import Library... from within the IDE, then choosing the -library you want. +This page lists the extra libraries that are part of the :ref:`Maple +IDE ` (along with the rest of :ref:`libmaple `). You +can use a library from within a sketch by going to Sketch > Import +Library... from within the IDE, then choosing the library you want. -Any incompatibilities between the Maple and Arduino versions are noted -in the description of the library. +Any incompatibilities between the Maple and Arduino versions of a +library are noted in the library's documentation. .. contents:: Contents :local: @@ -25,70 +25,47 @@ in the description of the library. :hidden: libs/servo.rst + libs/wire.rst -.. _libraries-servo: - -Servo ------ - -The Servo library is provided for convenient control of RC -servomotors. For more information, see the :ref:`Servo ` -reference. +.. admonition:: **Looking for Something Else?** -**Compatibility Note** + - See the :ref:`language` for information on the core functions + used for programming a Maple board. -The Servo class provides a public interface identical to the Arduino -version's documented functionality (as of Arduino 0021), so in most -cases, this library will be a drop-in replacement. + - If you're looking for something from the C standard library (like + ``atoi()``, for instance): the :ref:`CodeSourcery GCC compiler + ` used to compile your programs is configured to link + against `newlib `_, and allows the + use of any of its header files. However, dynamic memory allocation + (``malloc()``, etc.) is not available. -However, there are some differences, essentially at the level of -implementation details. + - If you're looking for low-level hardware support libraries, see + the :ref:`libmaple Reference`. -The major difference is that while the Arduino implementation drives -the servos with "bit-banged" :ref:`PWM `, the Maple -implementation uses :ref:`timers ` to drive the PWM directly. - -Consequently, **the Maple implementation only allows Servo instances -to** :ref:`attach ` **to pins that support PWM**. - -To determine if a pin supports PWM (15 Maple pins do), you can either -check if "PWM" appears next to its number on the Maple silkscreen, or -consult the :ref:`pwmWrite() ` documentation. - -RC Servos expect a pulse approximately every 20ms. In the Maple -implementation, :ref:`periods ` are set -for entire timers, rather than individual channels. Thus, -``attach()``\ ing a Servo to a pin can interfere with other pins -associated with the same timer\ [#fard-servo]_. +.. _libraries-servo: -Because of this, we recommend connecting multiple servomotors to pins -which share a timer, in order to keep as many timers free for other -purposes as possible. Consult the :ref:`table provided in the timers -reference ` to match up pins and timer -channels. +Servo +----- -Another difference: although it is not publicly documented to do so, -the Arduino implementation of `attach() -`_ returns the timer -channel associated with the newly-attached pin, or 0 on failure (as of -Arduino 0021). The Maple implementation returns true on success, and -false on failure (and this is its documented behavior). +The :ref:`Servo ` library is provided for convenient +control of RC servomotors. .. _libraries-liquid-crystal: LiquidCrystal ------------- -.. TODO 0.0.10 make our own LiquidCrystal docs +.. TODO [0.1.0] LiquidCrystal docs under libs/liquidcrystal.rst The LiquidCrystal library allows Maple to control LCD screens. For more information, see the `Arduino LiquidCrystal documentation `_. -**Compatibility Note** +**Arduino Compatibility** At this time, no incompatibilities between the Maple and Arduino -versions are known. Any observed differences should be considered +versions are known (although the Maple version should perform +significantly faster). Any observed differences should be considered bugs, and reported on the forums. .. _libraries-wire: @@ -96,99 +73,8 @@ bugs, and reported on the forums. Wire ---- -We provide a soft (bit-banged) implementation of the `Wire I2C library -`_. - -**Compatibility Note** - -This implementation is synchronous, and thus supports only a subset of -the full Wire interface (however, the functionality which is supported -is fully compatible with Arduino). For now, please use the function -reference which follows when developing projects using our -implementation. - -Please note that the current implementation only supports master mode -using a bit-banged (software) protocol. Future enhancements will use -the hardware i2c peripheral on the stm32 as well as the DMA for -performance. Support for slave, smBUS, and multimaster modes are also -slated for inclusion in the enhanced Wire port. - -.. TODO 0.0.10 Wire docs in the cpp domain in own page under /libs/ - -Wire Function Reference -^^^^^^^^^^^^^^^^^^^^^^^ - -``Wire.begin()`` - Joins the i2c bus as master, using pin 20 as SDA and pin 21 as SCL - (this is compatible with the pin settings on the Arduino Mega). - -``Wire.begin(sda, scl)`` - Like ``Wire.begin()``, but with the given pins as SDA and - SCL. - -``Wire.beginTransmission(slave_address)`` - Set up a transmission to a slave device with the given (7-bit) - address. Bytes subsequently queued for transmission (using - ``Wire.send``) will be sent to ``slave_address`` when ``void - Wire.endTransmission()`` is called. - -``void Wire.send(byte)`` - Queues the given byte (``uint8`` or ``int``) to the slave address - previously specified by a call to ``Wire.beginTransmission``. At - most 32 bytes may be queued in a single transmission. - -``Wire.send(string)`` - Queues a given string (``char*``) for transmission. The characters - of the string are individually queued for transmission as - bytes. At most 32 bytes may be queued in a single transmission. - -``Wire.send(buffer, length)`` - Queues a byte buffer ``buffer`` (``uint8*`` or ``int*``), with - ``length`` elements, for transmission. At most 32 bytes may be - queued in a single transmission. - -``Wire.endTransmission()`` - Ends a transmission (begun by ``Wire.beginTransmission(uint8)``), - and actually sends the bytes queued by calls to Wire.send. - - The return value is one of the following status codes: - - * ``SUCCESS``: All bytes were transmitted successfully. - - * ``EDATA``: More than 32 bytes were queued for transmission. No - bytes are actually sent when this happens. - - * ``ENACKADDR``: Did not receive ACK on transmit of address. No - bytes are actually sent when this happens. - - * ``ENACKTRNS``: Did not receive ACK during transmit of data. Some - bytes may have been sent when this happens; however, the - transmission is aborted after the first byte of data which is - not ACKed by the slave device. - - * ``EOTHER``: Other error occurred. - -``Wire.requestFrom(address, num_bytes)`` - Requests ``num_bytes`` bytes from 7-bit slave address - address. Returns the actual number of bytes read. These bytes may - subsequently be read one at a time using ``Wire.receive()``. - - Note: if ``num_bytes`` exceeds the size of the transmit/receive - buffer (currently 32), it will be truncated to 32. - -``Wire.receive()`` - Get and return the next byte read during the previous call to - ``Wire.requestFrom(uint8, int)``. You can check how many bytes are - left to read using ``uint8 Wire.available()``. - -``Wire.available()`` - Returns the number of bytes which are still available for reading - (with ``Wire.receive()``) from the last call to - ``Wire.requestFrom(uint8, int)``. - -.. rubric:: Footnotes +.. FIXME [0.1.0] Update with hard Wire implementation info -.. [#fard-servo] The Arduino implementation also captures timer - channels in groups as more Servo objects are attached, but the - details of which channels have their periods reset when are - slightly different. +We currently provide a soft (bit-banged) implementation of the +:ref:`Wire ` I2C library. A hardware version is planned +for Maple IDE release 0.1.0. diff --git a/docs/source/libs/servo.rst b/docs/source/libs/servo.rst index 475f7dd..891f151 100644 --- a/docs/source/libs/servo.rst +++ b/docs/source/libs/servo.rst @@ -2,9 +2,8 @@ .. _libs-servo: -======= - Servo -======= +Servo +===== .. FIXME [0.0.10] this is out of date @@ -16,7 +15,8 @@ You can use this library in the :ref:`IDE ` by choosing the Servo item under the Sketch > Import Library... menu. If you are using the :ref:`Unix toolchain `, the -library is located in ``$LIB_MAPLE_HOME/libraries/Servo/``. +library is located in the ``/libraries/Servo/`` :ref:`libmaple` +directory. Servo Class Reference --------------------- @@ -108,3 +108,54 @@ servomotor attached to pin 9, you could write :: microseconds. This will be clamped to lie in the [``min``, ``max``\ ] pulse width range set during :ref:`attach() `. + +Arduino Compatibility +--------------------- + +The Servo class provides a public interface identical to the Arduino +version's documented functionality (as of Arduino 0021), so in most +cases, this library will be a drop-in replacement. + +However, there are some differences, essentially at the level of +implementation details. + +The major difference is that while the Arduino implementation drives +the servos with "bit-banged" :ref:`PWM `, the Maple +implementation uses :ref:`timers ` to drive the PWM directly. + +Consequently, **the Maple implementation only allows Servo instances +to** :ref:`attach ` **to pins that support PWM**. + +To determine if a pin supports PWM (15 Maple pins do), you can either +check if "PWM" appears next to its number on the Maple silkscreen, or +consult the :ref:`pwmWrite() ` documentation. + +RC Servos expect a pulse approximately every 20ms. In the Maple +implementation, :ref:`periods ` are set +for entire timers, rather than individual channels. Thus, +``attach()``\ ing a Servo to a pin can interfere with other pins +associated with the same timer\ [#fard-servo]_. + +Because of this, we recommend connecting multiple servomotors to pins +which share a timer, in order to keep as many timers free for other +purposes as possible. Consult your board's :ref:`Timer Pin Map +` to match up pins and timer channels. + +Another difference: although it is not publicly documented to do so, +the Arduino implementation of `attach() +`_ returns the timer +channel associated with the newly-attached pin, or 0 on failure (as of +Arduino 0021). The Maple implementation returns :ref:`true +` on success, and :ref:`false +` on failure (and this is its documented +behavior). + +We currently provide a soft (bit-banged) implementation of the +:ref:`Wire ` I2C library. + +.. rubric:: Footnotes + +.. [#fard-servo] The Arduino implementation also captures timer + channels in groups as more Servo objects are attached, but the + details of which channels have their periods reset when are + slightly different. diff --git a/docs/source/libs/wire.rst b/docs/source/libs/wire.rst new file mode 100644 index 0000000..2c5bed9 --- /dev/null +++ b/docs/source/libs/wire.rst @@ -0,0 +1,104 @@ +.. highlight:: cpp + +.. _libs-wire: + +Wire +==== + +.. TODO [0.1.0] Format this correctly, using Breathe + +This page documents the Wire library for the :ref:`i2c` protocol. You +can use this library in the :ref:`Maple IDE ` by choosing the +Wire item under the Sketch > Import Library... menu. + +If you are using the :ref:`Unix toolchain `, the +library is located in the ``/libraries/Wire/`` :ref:`libmaple` +directory. + +Wire Function Reference +----------------------- + +``Wire.begin()`` + Joins the i2c bus as master, using pin 20 as SDA and pin 21 as SCL + (this is compatible with the pin settings on the Arduino Mega). + +``Wire.begin(sda, scl)`` + Like ``Wire.begin()``, but with the given pins as SDA and + SCL. + +``Wire.beginTransmission(slave_address)`` + Set up a transmission to a slave device with the given (7-bit) + address. Bytes subsequently queued for transmission (using + ``Wire.send``) will be sent to ``slave_address`` when ``void + Wire.endTransmission()`` is called. + +``void Wire.send(byte)`` + Queues the given byte (``uint8`` or ``int``) to the slave address + previously specified by a call to ``Wire.beginTransmission``. At + most 32 bytes may be queued in a single transmission. + +``Wire.send(string)`` + Queues a given string (``char*``) for transmission. The characters + of the string are individually queued for transmission as + bytes. At most 32 bytes may be queued in a single transmission. + +``Wire.send(buffer, length)`` + Queues a byte buffer ``buffer`` (``uint8*`` or ``int*``), with + ``length`` elements, for transmission. At most 32 bytes may be + queued in a single transmission. + +``Wire.endTransmission()`` + Ends a transmission (begun by ``Wire.beginTransmission(uint8)``), + and actually sends the bytes queued by calls to Wire.send. + + The return value is one of the following status codes: + + * ``SUCCESS``: All bytes were transmitted successfully. + + * ``EDATA``: More than 32 bytes were queued for transmission. No + bytes are actually sent when this happens. + + * ``ENACKADDR``: Did not receive ACK on transmit of address. No + bytes are actually sent when this happens. + + * ``ENACKTRNS``: Did not receive ACK during transmit of data. Some + bytes may have been sent when this happens; however, the + transmission is aborted after the first byte of data which is + not ACKed by the slave device. + + * ``EOTHER``: Other error occurred. + +``Wire.requestFrom(address, num_bytes)`` + Requests ``num_bytes`` bytes from 7-bit slave address + address. Returns the actual number of bytes read. These bytes may + subsequently be read one at a time using ``Wire.receive()``. + + Note: if ``num_bytes`` exceeds the size of the transmit/receive + buffer (currently 32), it will be truncated to 32. + +``Wire.receive()`` + Get and return the next byte read during the previous call to + ``Wire.requestFrom(uint8, int)``. You can check how many bytes are + left to read using ``uint8 Wire.available()``. + +``Wire.available()`` + Returns the number of bytes which are still available for reading + (with ``Wire.receive()``) from the last call to + ``Wire.requestFrom(uint8, int)``. + +Arduino Compatibility +--------------------- + +.. FIXME [0.1.0] Replace this section when i2c Wire wrapper is done + +This implementation is synchronous, and thus supports only a subset of +the full Wire interface (however, the functionality which is supported +is fully compatible with Arduino). For now, please use the function +reference which follows when developing projects using our +implementation. + +Please note that the current implementation only supports master mode +using a bit-banged (software) protocol. For now, use of the hardware +:ref:`i2c` peripheral is only available through :ref:`libmaple-i2c`. + + diff --git a/docs/source/maple-quickstart.rst b/docs/source/maple-quickstart.rst index 899f720..c7596ce 100644 --- a/docs/source/maple-quickstart.rst +++ b/docs/source/maple-quickstart.rst @@ -6,7 +6,7 @@ Maple Quickstart Guide ======================== -.. TODO update the images since we changed "to FLASH" -> "to Flash" +.. TODO [0.1.0] Update the images; we've changed "to FLASH" -> "to Flash" You'll need a `Maple board `_, a `Mini-B USB cable `_, a @@ -73,12 +73,14 @@ window, and then a confirmation message will appear: Upload that program! -------------------- +.. FIXME [0.1.0 Maple-specific image; add one for Native] + Now it's time to plug in your Maple. Use a Mini-B cable, making sure -that the :ref:`power source jumper ` is on -the USB header first. We ship the Maple with the power source jumper -configured that way, so you shouldn't have to do anything. For -reference, it should look like this (don't worry if a jumper is -hanging half off of the CHRG header): +that the :ref:`power source jumper ` is on the USB +header first. We ship Maples with the power source jumper configured +that way, so you shouldn't have to do anything. For reference, it +should look like this (don't worry if a jumper is hanging half off of +the CHRG header): .. image:: /_static/img/plugged-in-maple.png :align: center diff --git a/docs/source/pwm.rst b/docs/source/pwm.rst index 1144d55..ac67689 100644 --- a/docs/source/pwm.rst +++ b/docs/source/pwm.rst @@ -19,29 +19,14 @@ filtering) generate audio waveforms. Overview -------- -The Maple has a large number of 16-bit PWM outputs, each connected to -one of 4 timers. Some configuration, such as the clock rate or -prescaling, must be common to the entire timer; see the :ref:`timer -documentation ` for more information. - -Note that unlike the Arduino, the Maple does not have PWM -functionality on pin D10; all other pins are :ref:`compatible -`. - -The following table shows which timer can generate which PWM -outputs. See the :ref:`pin mapping table ` to -track down exactly which timer *channel* corresponds to each pin. - -.. _pwm-timer-table: - -.. csv-table:: - :header: Timer, PWM Headers - :delim: | - - Timer1 | D6,D7,D8 - Timer2 | D0,D1,D2,D3 - Timer3 | D11,D12,D27,D28 - Timer4 | D5,D9,D14,D24 +.. FIXME [0.1.0] More information about how timer channels drive PWM + +Each PWM output is driven by an output channel connected to one of 4 +timers. Some configuration, such as the clock rate or prescaling, +must be common to the entire timer; see the :ref:`timer documentation +` for more information. See your board's :ref:`pin mapping +tables ` to track down the correspondence +between timer channels and GPIO pins. Background ---------- diff --git a/docs/source/spi.rst b/docs/source/spi.rst index ba43eef..2da4bf8 100644 --- a/docs/source/spi.rst +++ b/docs/source/spi.rst @@ -20,11 +20,15 @@ Recommended Reading * `Wikipedia Article on Serial Peripheral Interface Bus (SPI) `_ + * `Arduino reference on SPI `_ + * `Hardcore SPI on Arduino `_ by kik64 -* STMicro documentation for STM32F103RB microcontroller: - * `Datasheet `_ (pdf) - * `Reference Manual `_ (pdf) +* ST Documentation: + + * Reference Manual `RM0008 + `_ + (PDF), Chapter 25, "Serial Peripheral Interface" diff --git a/docs/source/timers.rst b/docs/source/timers.rst index 56dd686..cb30081 100644 --- a/docs/source/timers.rst +++ b/docs/source/timers.rst @@ -5,6 +5,8 @@ Timers ====== +.. FIXME [0.0.10] links to systick.h in a few places on this page + There are four general purpose timers in the Maple microcontroller that can be configured to generate periodic or delayed events with minimal work done by the microcontroller. For example, the :ref:`PWM @@ -43,164 +45,66 @@ event" interrupt is generated. You can configure the Maple to notify you when this takes place, by registering an interrupt handler, which is a function that will be called when the update event occurs. -libmaple Reference +Function Reference ------------------ -The libmaple API for interacting with timers is documented at the -:ref:`HardwareTimer reference `. +* :ref:`HardwareTimer ` Caveats ------- +Working with timers and interrupts can be tricky; they are a somewhat +"advanced" topic. The following subsections explain some common +problems associated with using timers and timer interrupts. + +In general: start simple, test with :ref:`ASSERT() `, +and don't try to do too much in your interrupt handlers! Make sure +that what you're trying to do in a handler isn't going to block other +interrupts from firing, if those other interrupts are important for +your program. + .. _timers-pwm-conflicts: -**PWM Conflicts:** Because PWM functionality on a given pin depends on +PWM Conflicts +^^^^^^^^^^^^^ + +Because PWM functionality on a given pin depends on the configuration of the timer and channel, you must chose your channels carefully if you want to use both timer interrupts and PWM in -the same program. Refer to the following table to match up timer -channels and Maple header pin numbers: - -.. _timers-pin-channel-map: - -.. csv-table:: - :header: Timer, Ch. 1 pin, Ch. 2 pin, Ch. 3 pin, Ch. 4 pin - - ``Timer1``, 6, 7, 8, -- - ``Timer2``, 2, 3, 1, 0 - ``Timer3``, 12, 11, 27, 28 - ``Timer4``, 5, 9, 14, 24 - -**Overhead:** there is some overhead associated with function and -interrupt calls (loading and unloading the stack, preparing state, -etc.) and this overhead can fudge your timing. Imperfect code -branching also means that, e.g., channel 1 interrupts may get called a -couple clock cycles sooner than a channel 4 interrupt, all other -configuration being the same. - -.. compound:: - - **Jitter:** other interrupts (USB, Serial, SysTick, or other - timers) can and will get called before or during the timer - interrupt routines, causing pseudorandom delays and other - frustrations. - - Disabling the USB port (by calling ``SerialUSB.end()``, or just - running off a battery) helps a lot, but then you lose the - auto-reset and communications functionality. This will require - that you put your Maple into :ref:`perpetual bootloader mode - ` before uploading a new - program to it (or somehow causing your program to re-enable serial - over USB using :ref:`SerialUSB.begin() `). - - Disabling SysTick with ``systick_disable()`` helps as well. - However, calling this function will break the ``micros()`` and - ``millis()`` functions. - -**General:** working with timers and interrupts can be tricky and hard -to debug; they are a somewhat "advanced" topic. Start simple, test -with :ref:`ASSERT() `, and don't try to do too much -in your interrupt handlers! Make sure that what you're trying to do in -a handler isn't going to block other interrupts from firing (e.g. USB, -Serial, SysTick) if those other interrupts are important for your -program. - -SysTick Peripheral ------------------- - -The SysTick peripheral allows another, simple way to perform periodic -or delayed events. This separate timer does not conflict with any -other peripherals, but the associated 1kHz interrupt can jitter the -general purpose timer interrupts; this is clearly seen when running -VGA code, where the timing jitters are transformed into visual jags in -the image. The SysTick peripheral can be disabled by calling -``systick_disable()``, and re-enabled using ``systick_resume()``. - -Code Examples -------------- - -LED blink -^^^^^^^^^ - -:: - - #define LED_RATE 500000 // in microseconds; should give 0.5Hz toggles - - void handler_led(void); - - void setup() - { - // Set up the LED to blink - pinMode(BOARD_LED_PIN, OUTPUT); - - // Setup Timer - Timer2.setChannel1Mode(TIMER_OUTPUTCOMPARE); - Timer2.setPeriod(LED_RATE); // in microseconds - Timer2.setCompare1(1); // overflow might be small - Timer2.attachCompare1Interrupt(handler_led); - } - - void loop() { - // Nothing! It's all in the interrupts - } - - void handler_led(void) { - toggleLED(); - } - -Racing Counters -^^^^^^^^^^^^^^^ - -:: - - void handler_count1(void); - void handler_count2(void); - - int count1 = 0; - int count2 = 0; - - void setup() - { - // Set up BUT for input - pinMode(BOARD_BUTTON_PIN, INPUT_PULLUP); - - // Setup Counting Timers - Timer3.setChannel1Mode(TIMER_OUTPUTCOMPARE); - Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE); - Timer3.pause(); - Timer4.pause(); - Timer3.setCount(0); - Timer4.setCount(0); - Timer3.setOverflow(30000); - Timer4.setOverflow(30000); - Timer3.setCompare1(1000); // somewhere in the middle - Timer4.setCompare1(1000); - Timer3.attachCompare1Interrupt(handler1); - Timer4.attachCompare1Interrupt(handler2); - Timer3.resume(); - Timer4.resume(); - } - - void loop() { - // Display the running counts - SerialUSB.print("Count 1: "); - SerialUSB.print(count1); - SerialUSB.print("\t\tCount 2: "); - SerialUSB.println(count2); - - // Run... while BUT is held, pause Count2 - for(int i = 0; i<1000; i++) { - if(digitalRead(BOARD_BUTTON_PIN)) { - Timer4.pause(); - } else { - Timer4.resume(); - } - delay(1); - } - } - - void handler1(void) { - count1++; - } - void handler2(void) { - count2++; - } +the same program. Refer to your board's :ref:`Timer Pin Map +` to match up timer channels and pin numbers. + +Overhead +^^^^^^^^ + +There is some overhead associated with function and interrupt calls +(loading and unloading the stack, preparing state, etc.) and this +overhead can fudge your timing. Imperfect code branching also means +that, e.g., channel 1 interrupts may get called a couple clock cycles +sooner than a channel 4 interrupt, all other configuration being the +same. + +Jitter +^^^^^^ + +Other interrupts can and will get called before or during the timer +interrupt routines, causing pseudorandom delays and other +frustrations. + +Disabling the :ref:`USB ` port (by calling ``SerialUSB.end()``, +or just running off a battery) helps a lot, but then you lose the +auto-reset and communications functionality. This will require that +you put your Maple into :ref:`perpetual bootloader mode +` before uploading a new program +to it (or somehow causing your program to re-enable serial over USB +using :ref:`SerialUSB.begin() `). + +The SysTick peripheral another way to perform periodic or delayed +events. Its separate timer does not conflict with any other +peripherals, but the associated 1 kHz interrupt can jitter the general +purpose timer interrupts. The SysTick peripheral can be disabled by +calling :ref:`systick_disable() `, and +re-enabled using :ref:`systick_resume() `. +However, be aware that calling ``systick_disable()`` will stop the +values coming from :ref:`lang-micros` and :ref:`lang-millis` from +increasing. diff --git a/docs/source/troubleshooting.rst b/docs/source/troubleshooting.rst index 2151171..f49580c 100644 --- a/docs/source/troubleshooting.rst +++ b/docs/source/troubleshooting.rst @@ -100,8 +100,6 @@ a board selected. The work-around is to restart the IDE. Mysterious! A classic! Make sure you have selected a board from the pulldown menu. -.. TODO: remove when Python version is released - ``undefined reference to setup()/loop()`` ----------------------------------------- @@ -133,8 +131,6 @@ There is an intermittent bug with the temporary directory build system that on occasion will lose many of the ``#include``\ d libmaple files. If you recompile everything, it should be fine. -.. TODO remove when the Python version is released - .. _troubleshooting-upload: ======================== diff --git a/docs/source/usart.rst b/docs/source/usart.rst index 3beb3fc..9506cc8 100644 --- a/docs/source/usart.rst +++ b/docs/source/usart.rst @@ -4,23 +4,34 @@ USART ======= -.. contents:: +.. contents:: Contents :local: Hardware/Circuit Design ----------------------- +.. FIXME [0.0.10] UART4 and UART5 +.. FIXME [0.1.0] Maple Native and Mini info and links + The Maple has 3 separate USART devices. In the most simple use case, the RX and TX pins are used to send data at a predetermined baudrate with the line voltage level relative to ground. Their usage is documented in the :ref:`Serial Ports ` language reference -page. +page. Which pins correspond to the USART TX and RX pins are given on +your board's silkscreen, and also in the board-specific USART pin maps +available here: + +* :ref:`Maple ` +* :ref:`Maple RET6 Edition ` + +If you use a particular serial port, you cannot also use its +communication pins for other purposes at the same time. Compatible Devices and Specifications ------------------------------------- -We have successfully used the Maple USART ports with an FT232R-based -USB-serial converter at up to 115200 baud; higher speeds should +We have successfully used the USART ports with an FT232R-based +USB-serial converter at up to 115200 baud. Higher speeds should certainly be possible. Recommended Reading diff --git a/docs/source/usb.rst b/docs/source/usb.rst index f040034..a67d710 100644 --- a/docs/source/usb.rst +++ b/docs/source/usb.rst @@ -2,34 +2,32 @@ .. _usb: -===== - USB -===== +USB +=== -The Maple STM32 microprocessor includes a dedicated USB peripheral -which can be configured to act as a general USB slave device with -transfer rates up to 12Mbps (it unfortunately can't be configured as a -host or on-the-go device). By default, the peripheral is configured -for two uses: first, to receive sketch/program uploads from the IDE, -and second, to emulate a regular serial port for use as a terminal -(text read/write). +The STM32 microprocessors include a dedicated USB peripheral which can +be configured to act as a general USB slave device with transfer rates +up to 12Mbps. (It unfortunately can't be configured as a host or +on-the-go device). By default, the peripheral is configured for two +uses: first, to receive sketch/program uploads from the :ref:`IDE +`, and second, to emulate a regular serial port for use as a +terminal (text read/write). The emulated terminal is relatively slow and inefficient; it is best for transferring data at regular serial speeds (kilobaud). Library support for accessing the emulated terminal is available at the :ref:`SerialUSB ` reference. -The SerialUSB channel is used as part of the auto-reset feature of the -IDE to program the board on Maple Rev 3 and Rev 5: a :ref:`magic -sequence of control line toggles and transmitted data -` causes the Maple to reset itself and enter -bootloader mode. As an unfortunate consequence, the auto-reset will -not work if the IDE can not access the serial port, either due to a -conflict with another program (serial monitor) or because the -interface has been disabled from the Maple side (through -:ref:`SerialUSB.end() `). A solution to the -second problem is the use of :ref:`perpetual bootloader mode -`. +The SerialUSB channel is used with the :ref:`Maple bootloader +` to reprogram the board: a :ref:`magic sequence of +control line toggles and transmitted data ` causes a +Maple to reset itself and enter bootloader mode. As an unfortunate +consequence, the auto-reset will not work if the IDE can not access +the serial port, either due to a conflict with another program (serial +monitor) or because the interface has been disabled from the Maple +side (through :ref:`SerialUSB.end() `). A +solution to the second problem is the use of :ref:`perpetual +bootloader mode `. Recommended Reading ------------------- @@ -40,9 +38,11 @@ Recommended Reading * `Embedded USB - a brief tutorial `_ * `Wikipedia article on Universal Serial Bus (USB) `_ * Linux Kernel documentation for `USB ACM `_ and `USB Serial `_ -* STMicro documentation for STM32F103RB microcontroller: - - * `Datasheet `_ (pdf) - * `Reference Manual `_ (pdf) - * `Programming Manual `_ (pdf; assembly - language and register reference) +* ST documentation: + * Reference Manual `RM0008 + `_ + (PDF), Chapter 23, "Universal serial bus full-speed device + interface" + * `Programming Manual + `_ + (PDF; assembly language and register reference) -- cgit v1.2.3 From 90c649c4b36dfc0c80d41878721c06187ada6b90 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Tue, 26 Apr 2011 03:27:33 -0400 Subject: Removing Maple-specific values from WirinPinMode doxygen comment. Comment changes only. --- wirish/io.h | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/wirish/io.h b/wirish/io.h index 137377d..ace40f2 100644 --- a/wirish/io.h +++ b/wirish/io.h @@ -38,17 +38,6 @@ /** * Specifies a GPIO pin behavior. - * - * Each of the GPIO pins on a Maple board may be configured using - * pinMode() to behave in a number of ways: as a digital output pin, - * or as an analog input pin, etc., depending on the particular pin. - * - * This enum specifies the complete set of possible configurations; - * not every pin can have all of these modes. For example, on the - * Maple, pin 15 may be configured as INPUT_ANALOG, but not as PWM. - * See your board's documentation and silkscreen for more information - * on what functionality is available on each pin. - * * @see pinMode() */ typedef enum WiringPinMode { -- cgit v1.2.3 From 033bf3f26290c41074cf487549233ea2c25120f0 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Wed, 27 Apr 2011 15:32:31 -0400 Subject: RET6 fixes --- examples/test-session.cpp | 4 ++-- wirish/boards/maple_RET6.cpp | 13 +++++++++++-- wirish/boards/maple_RET6.h | 10 ++++++++-- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/examples/test-session.cpp b/examples/test-session.cpp index 1d9daf0..ad3cacb 100644 --- a/examples/test-session.cpp +++ b/examples/test-session.cpp @@ -855,7 +855,7 @@ void enable_usarts(void) { Serial1.begin(BAUD); Serial2.begin(BAUD); Serial3.begin(BAUD); -#ifdef STM32_HIGH_DENSITY +#if defined(STM32_HIGH_DENSITY) && !defined(BOARD_maple_RET6) Serial4.begin(BAUD); Serial5.begin(BAUD); #endif @@ -865,7 +865,7 @@ void disable_usarts(void) { Serial1.end(); Serial2.end(); Serial3.end(); -#ifdef STM32_HIGH_DENSITY +#if defined(STM32_HIGH_DENSITY) && !defined(BOARD_maple_RET6) Serial4.end(); Serial5.end(); #endif diff --git a/wirish/boards/maple_RET6.cpp b/wirish/boards/maple_RET6.cpp index fd67459..d5d3d32 100644 --- a/wirish/boards/maple_RET6.cpp +++ b/wirish/boards/maple_RET6.cpp @@ -85,7 +85,15 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { {GPIOC, TIMER8, NULL, 6, 1, ADCx}, /* D35/PC6 */ {GPIOC, TIMER8, NULL, 7, 2, ADCx}, /* D36/PC7 */ {GPIOC, TIMER8, NULL, 8, 3, ADCx}, /* D37/PC8 */ - {GPIOC, TIMER8, NULL, 9, 4, ADCx} /* D38/PC9 (BUT) */ + {GPIOC, TIMER8, NULL, 9, 4, ADCx}, /* D38/PC9 (BUT) */ + + /* JTAG header */ + + {GPIOA, NULL, NULL, 13, 0, ADCx}, /* D39/PA13 */ + {GPIOA, NULL, NULL, 14, 0, ADCx}, /* D40/PA14 */ + {GPIOA, NULL, NULL, 15, 0, ADCx}, /* D41/PA15 */ + {GPIOB, NULL, NULL, 3, 0, ADCx}, /* D42/PB3 */ + {GPIOB, NULL, NULL, 4, 0, ADCx}, /* D43/PB4 */ }; extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { @@ -97,7 +105,8 @@ extern const uint8 boardADCPins[BOARD_NR_ADC_PINS] __FLASH__ = { }; extern const uint8 boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = { - BOARD_LED_PIN, BOARD_BUTTON_PIN + BOARD_LED_PIN, BOARD_BUTTON_PIN, BOARD_JTMS_SWDIO_PIN, + BOARD_JTCK_SWCLK_PIN, BOARD_JTDI_PIN, BOARD_JTDO_PIN, BOARD_NJTRST_PIN }; #endif diff --git a/wirish/boards/maple_RET6.h b/wirish/boards/maple_RET6.h index d91a4de..97e609d 100644 --- a/wirish/boards/maple_RET6.h +++ b/wirish/boards/maple_RET6.h @@ -55,9 +55,15 @@ #define BOARD_USART3_TX_PIN 29 #define BOARD_USART3_RX_PIN 30 -#define BOARD_NR_GPIO_PINS 39 +#define BOARD_NR_GPIO_PINS 44 #define BOARD_NR_PWM_PINS 16 #define BOARD_NR_ADC_PINS 15 -#define BOARD_NR_USED_PINS 2 +#define BOARD_NR_USED_PINS 7 + +#define BOARD_JTMS_SWDIO_PIN 39 +#define BOARD_JTCK_SWCLK_PIN 40 +#define BOARD_JTDI_PIN 41 +#define BOARD_JTDO_PIN 42 +#define BOARD_NJTRST_PIN 43 #endif -- cgit v1.2.3 From f7298dc9875d8d680502269492ba47f16c86a9fb Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Wed, 27 Apr 2011 17:38:33 -0400 Subject: Trivial test-session.cpp bugfix --- examples/test-session.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/test-session.cpp b/examples/test-session.cpp index ad3cacb..959c1b8 100644 --- a/examples/test-session.cpp +++ b/examples/test-session.cpp @@ -423,7 +423,7 @@ void cmd_sequential_adc_reads(void) { SerialUSB.println("Press any key for next port, or ESC to stop."); for (uint32 i = 0; i < BOARD_NR_ADC_PINS; i++) { - if (boardUsesPin(i)) + if (boardUsesPin(boardADCPins[i])) continue; SerialUSB.print("Reading pin "); -- cgit v1.2.3 From ea6cf3e622350963e25dae21b03b01b13af53ebc Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Wed, 27 Apr 2011 17:38:55 -0400 Subject: maple_native.cpp updates/fixes. --- wirish/boards/maple_native.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/wirish/boards/maple_native.cpp b/wirish/boards/maple_native.cpp index 0b25bd4..ab8b282 100644 --- a/wirish/boards/maple_native.cpp +++ b/wirish/boards/maple_native.cpp @@ -44,7 +44,7 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { /* Top header */ {GPIOB, NULL, NULL, 10, 0, ADCx}, /* D0/PB10 */ - {GPIOB, NULL, NULL, 2, 0, ADCx}, /* D1/PB2 */ + {GPIOB, NULL, NULL, 11, 0, ADCx}, /* D1/PB11 */ {GPIOB, NULL, NULL, 12, 0, ADCx}, /* D2/PB12 */ {GPIOB, NULL, NULL, 13, 0, ADCx}, /* D3/PB13 */ {GPIOB, NULL, NULL, 14, 0, ADCx}, /* D4/PB14 */ @@ -88,12 +88,12 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { {GPIOB, NULL, NULL, 5, 0, ADCx}, /* D37/PB5 */ {GPIOB, TIMER4, NULL, 6, 1, ADCx}, /* D38/PB6 */ {GPIOB, TIMER4, NULL, 7, 2, ADCx}, /* D39/PB7 */ - {GPIOF, NULL, ADC3, 6, 0, 4}, /* D40/PF6 */ - {GPIOF, NULL, ADC3, 7, 0, 5}, /* D41/PF7 */ - {GPIOF, NULL, ADC3, 8, 0, 6}, /* D42/PF8 */ - {GPIOF, NULL, ADC3, 9, 0, 7}, /* D43/PF9 */ - {GPIOF, NULL, ADC3, 10, 0, 8}, /* D44/PF10 */ - {GPIOF, NULL, NULL, 11, 0, ADCx}, /* D45/PF11 */ + {GPIOF, NULL, NULL, 11, 0, ADCx}, /* D40/PF11 */ + {GPIOF, NULL, ADC3, 6, 0, 4}, /* D41/PF6 */ + {GPIOF, NULL, ADC3, 7, 0, 5}, /* D42/PF7 */ + {GPIOF, NULL, ADC3, 8, 0, 6}, /* D43/PF8 */ + {GPIOF, NULL, ADC3, 9, 0, 7}, /* D44/PF9 */ + {GPIOF, NULL, ADC3, 10, 0, 8}, /* D45/PF10 */ {GPIOB, TIMER3, ADC1, 1, 4, 9}, /* D46/PB1 */ {GPIOB, TIMER3, ADC1, 0, 3, 8}, /* D47/PB0 */ {GPIOA, TIMER5, ADC1, 0, 1, 0}, /* D48/PA0 */ @@ -163,11 +163,11 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { }; extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = { - 13, 14, 15, 16, 23, 24, 25, 26, 38, 39, 46, 47, 48, 49, 50, 51, 54, 54 + 13, 14, 15, 16, 23, 24, 25, 26, 38, 39, 46, 47, 48, 49, 50, 51, 54, 55 }; extern const uint8 boardADCPins[BOARD_NR_ADC_PINS] __FLASH__ = { - 7, 8, 9, 10, 11, 12, 40, 41, 42, 43, 44, 46, 47, 48, 49, 50, 51, 52, 53, + 7, 8, 9, 10, 11, 12, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55 }; -- cgit v1.2.3 From e6d44c187435c53b262c5336929db4aafb812811 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Thu, 28 Apr 2011 13:27:30 -0400 Subject: boardUsesPin() docs tweak. --- docs/source/lang/api/boardusespin.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/lang/api/boardusespin.rst b/docs/source/lang/api/boardusespin.rst index 8dc4c64..126c4a0 100644 --- a/docs/source/lang/api/boardusespin.rst +++ b/docs/source/lang/api/boardusespin.rst @@ -6,8 +6,9 @@ boardUsesPin() ============== Each LeafLabs board connects some pins to external hardware. The most -important examples of this are the built-in LED and button. You can -check if a board uses a particular pin using this function. +important examples of this are the pins connected to the built-in LED +and button. You can check if a board uses a particular pin using this +function. Library Documentation --------------------- @@ -24,4 +25,3 @@ See Also - :ref:`BOARD_BUTTON_PIN ` - :ref:`isButtonPressed() ` - :ref:`waitForButtonPress() ` - -- cgit v1.2.3 From 7cd5350622f5c7c84662beaee5b92a362be0f59b Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Thu, 28 Apr 2011 13:52:58 -0400 Subject: SPI refactor. Still a polling driver, but the libmaple proper interface exposes enough that users enable the various interrupts and define their own IRQ handlers if they feel like it. Wirish HardwareSPI interface was largely redone; it's more like the Arduino implementation now, although there are some differences when I didn't like their API. The old methods are still there, but are deprecated and slated for deletion in 0.1.0. New board-specific values: BOARD_NR_SPI, BOARD_SPIx_NSS_PIN, BOARD_SPIx_MOSI_PIN, BOARD_SPIx_MISO_PIN, and BOARD_SPIx_SCK_PIN, for x from 1 to BOARD_NR_SPI. Documentation was updated appropriately. --- docs/source/lang/api/hardwarespi.rst | 215 +++++++-------- docs/source/spi.rst | 6 +- examples/test-spi-roundtrip.cpp | 197 ++++++++++++++ libmaple/spi.c | 333 ++++++++++++++--------- libmaple/spi.h | 495 +++++++++++++++++++++++++++++------ wirish/boards/maple.h | 13 + wirish/boards/maple_RET6.h | 10 + wirish/boards/maple_mini.h | 10 + wirish/boards/maple_native.cpp | 2 +- wirish/boards/maple_native.h | 21 +- wirish/comm/HardwareSPI.cpp | 335 ++++++++++++++++++------ wirish/comm/HardwareSPI.h | 178 +++++++++++-- 12 files changed, 1389 insertions(+), 426 deletions(-) create mode 100644 examples/test-spi-roundtrip.cpp diff --git a/docs/source/lang/api/hardwarespi.rst b/docs/source/lang/api/hardwarespi.rst index 53a225d..289ded5 100644 --- a/docs/source/lang/api/hardwarespi.rst +++ b/docs/source/lang/api/hardwarespi.rst @@ -5,160 +5,161 @@ HardwareSPI =========== -This class is used for creating objects to manage the Maple's built-in -SPI ports. The Maple has two SPI ports. The relevant pins -corresponding to each port's logic signals are documented in the -following table (and on the Maple silkscreen): +This page describes how to use the built-in SPI ports. It does not +describe the SPI protocol itself. For more information about SPI, see +the :ref:`SPI reference `. -.. _lang-hardwarespi-pinout: +.. contents:: Contents + :local: -.. list-table:: - :header-rows: 1 +Getting Started +--------------- - * - Port number - - NSS - - MOSI - - MISO - - SCK +.. TODO [0.1.0] Add a note about calling disableDebugPorts() when +.. using SPI3 on Maple Native - * - 1 - - 10 - - 11 - - 12 - - 13 +In order to get started, you'll first need to define a ``HardwareSPI`` +variable, which you'll use to control the SPI port. Do this by +putting the line "``HardwareSPI spi(number);``" with your variables, +where ``number`` is the SPI port's number. - * - 2 - - 31 - - 32 - - 33 - - 34 +Here's an example (we'll fill in :ref:`setup() ` and +:ref:`loop() ` later):: -If you use a SPI port, you cannot simultaneously use its associated -pins for other purposes. + // Use SPI port number 1 + HardwareSPI spi(1); -Library Documentation ---------------------- + void setup() { + // Your setup code + } + + void loop() { + // Do stuff with SPI + } -Using the SPI Class -^^^^^^^^^^^^^^^^^^^ +Turning the SPI Port On +----------------------- -You can declare that you want to use SPI in your sketch by putting -``HardwareSPI Spi(number);`` with your variables, where ``number`` is -1 or 2, depending on which SPI you want to use. Then you can use the -functions described in the next section. For example:: +Now it's time to turn your SPI port on. Do this with the ``begin()`` +function (an example is given below). - // Use SPI 1 - HardwareSpi Spi(1); +.. FIXME [0.0.10] Breathe doesn't include the class; fix & submit pull req + +.. doxygenfunction:: HardwareSPI::begin + +The speed at which the SPI port communicates is configured using a +``SPIFrequency`` value: + +.. FIXME [0.1.0] Breathe's enum output is enormous; shrink & submit pull req + +.. doxygenenum:: SPIFrequency + +.. note:: Due to hardware issues, you can't use the frequency + ``SPI_140_625KHz`` with SPI port 1. + +You'll need to determine the correct values for ``frequency``, +``bitOrder``, and ``mode`` yourself, by consulting the datasheet for +the device you're communicating with. Continuing our example from +before, we'll add a call to ``begin()`` to our ``setup()``:: + + // Use SPI port number 1 + HardwareSPI spi(1); void setup() { - Spi.begin(SPI_18MHZ); + // Turn on the SPI port + spi.begin(SPI_18MHZ, MSBFIRST, 0); } void loop() { - // Get the next byte from the peripheral - uint8 byte = Spi.recv(); + // Do stuff with SPI } -HardwareSPI Class Reference -^^^^^^^^^^^^^^^^^^^^^^^^^^^ +If you call ``begin()`` with no arguments (as in "``spi.begin();``"), +it's the same as if you wrote "``spi.begin(SPI_1_125MHZ, MSBFIRST, +0);``". -.. cpp:class:: HardwareSPI +Communicating Over SPI +---------------------- - Class for interacting with SPI. +Now that you've got your SPI port set up, it's time to start +communicating. You can send data using ``HardwareSPI::write()``, +receive data using ``HardwareSPI::read()``, and do both using +``HardwareSPI::transfer()``. -.. cpp:function:: HardwareSPI::HardwareSPI(uint32 spi_num) +.. cpp:function:: void HardwareSPI::write(byte data) - Construct an object for managing a SPI peripheral. ``spi_num`` - must be 1 or 2; see the :ref:`table above - ` for pinout information. + Send a single byte of data. -.. cpp:function:: void HardwareSPI::begin(SPIFrequency freq, uint32 endianness, uint32 mode) + **Parameters**: - Configure the baudrate of the given SPI port and set up the header - pins appropriately. + - ``data``: Byte to send - Parameters: +.. cpp:function:: byte HardwareSPI::read() - - ``freq``: one of the ``SPIFrequency`` values, given :ref:`below - `. + Get the next available, unread byte. If there aren't any unread + bytes, this function will wait until one is received. - - ``endianness``: either ``LSBFIRST`` (little-endian) or - ``MSBFIRST`` (big-endian). +.. cpp:function:: byte HardwareSPI::transmit(byte data) - - ``mode``: one of 0, 1, 2, or 3, and specifies which SPI mode is - used. The mode number determines a combination of polarity and - phase according to the following table: + Send a byte, then return the next byte received. - .. list-table:: - :header-rows: 1 + **Parameters:** - * - Mode - - Polarity - - Phase + - ``data``: Byte to send - * - 0 - - 0 - - 0 + **Returns:** Next unread byte - * - 1 - - 0 - - 1 +Continuing our example from before, let's send a number over SPI and +print out whatever we get back over :ref:`lang-serialusb`:: - * - 2 - - 1 - - 0 + // Use SPI port number 1 + HardwareSPI spi(1); - * - 3 - - 1 - - 1 + void setup() { + // Turn on the SPI port + spi.begin(SPI_18MHZ, MSBFIRST, 0); + } - For more information on polarity and phase, see the - :ref:`external references, below `. + void loop() { + // Send 245 over SPI, and wait for a response. + spi.write(245); + byte response = spi.read(); + // Print out the response received. + SerialUSB.print("response: "); + SerialUSB.println(response, DEC); + } + +HardwareSPI Class Reference +--------------------------- + +There are a number of other things you can accomplish with your +``spi`` object. A full function listing follows. -.. cpp:function:: void HardwareSPI::begin() +.. doxygenclass:: HardwareSPI + :members: HardwareSPI, begin, beginSlave, end, read, write, transfer - A convenience ``begin()``, equivalent to ``begin(SPI_1_125MHZ, - MSBFIRST, 0)``. +Deprecated Functions +-------------------- -.. cpp:function:: uint8 HardwareSpi::send(uint8 *data, uint32 length) +The following functions are defined for now, but they have been +deprecated, and will be removed in a future Maple IDE release. You +shouldn't use them in new programs, and you should change any of your +programs which do use them to the up-to-date functions discussed +above. + +.. cpp:function:: uint8 HardwareSPI::send(uint8 *data, uint32 length) Writes ``data`` into the port buffer to be transmitted as soon as possible, where ``length`` is the number of bytes to send from ``data``. Returns the last byte shifted back from slave. -.. cpp:function:: uint8 HardwareSpi::send(uint8 data) +.. cpp:function:: uint8 HardwareSPI::send(uint8 data) Writes the single byte ``data`` into the port buffer to be transmitted as soon as possible. Returns the data byte shifted back from the slave. -.. cpp:function:: uint8 HardwareSpi::recv() +.. cpp:function:: uint8 HardwareSPI::recv() Reads a byte from the peripheral. Returns the next byte in the buffer. - -SPI Speeds -^^^^^^^^^^ - -.. _lang-hardwarespi-spifrequency: - -The possible SPI speeds are configured using the ``SPIFrequency`` enum: - -.. doxygenenum:: SPIFrequency - -.. _lang-hardwarespi-seealso: - -See Also --------- - -* `Wikipedia Article on Serial Peripheral Interface Bus (SPI) - `_ -* `Arduino reference on SPI - `_ -* `Hardcore SPI on Arduino `_ by kik64 -* STMicro documentation for STM32F103RB microcontroller: - - * `Datasheet `_ (pdf) - * `Reference Manual `_ (pdf) - - diff --git a/docs/source/spi.rst b/docs/source/spi.rst index 2da4bf8..dd9f1f5 100644 --- a/docs/source/spi.rst +++ b/docs/source/spi.rst @@ -8,12 +8,8 @@ The Serial Peripheral Interface Bus (SPI) is a serial data transfer protocol useful for interacting with a wide variety of hardware peripherals. -The Maple has two SPI ports. The first has NSS on D10, MOSI on -D11, MISO on D12, and SCK on D13. The second has NSS on D31, SCK on -D32, MISO on D33, and MOSI on D34. - The public libmaple API for managing the SPI ports is the -:ref:`HardwareSpi ` class. +:ref:`HardwareSPI ` class. Recommended Reading ------------------- diff --git a/examples/test-spi-roundtrip.cpp b/examples/test-spi-roundtrip.cpp new file mode 100644 index 0000000..257303b --- /dev/null +++ b/examples/test-spi-roundtrip.cpp @@ -0,0 +1,197 @@ +/* + * Polling SPI loopback test. + * + * Bob is nowhere to be found, so Alice decides to talk to herself. + * + * Instructions: Connect SPI2 (Alice) to herself (i.e., MISO to MOSI). + * Connect to Alice via Serial2 at 115200 baud. Press any key to start. + * + * Alice will talk to herself for a little while. The sketch will + * report if Alice can't hear anything she says. She'll then start + * talking forever at various frequencies, bit orders, and modes. Use + * an oscilloscope to make sure she's not trying to lie about any of + * those things. + * + * This file is released into the public domain. + * + * Author: Marti Bolivar + */ + +#include "wirish.h" + +HardwareSPI alice(2); + +#define NFREQS 8 +const SPIFrequency spi_freqs[] = { + SPI_140_625KHZ, + SPI_281_250KHZ, + SPI_562_500KHZ, + SPI_1_125MHZ, + SPI_2_25MHZ, + SPI_4_5MHZ, + SPI_9MHZ, + SPI_18MHZ, +}; + +#define TEST_BUF_SIZE 10 +uint8 test_buf[TEST_BUF_SIZE] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + +void bad_assert(const char* file, int line, const char* exp) { + Serial2.println(); + Serial2.print("ERROR: FAILED ASSERT("); + Serial2.print(exp); + Serial2.print("): "); + Serial2.print(file); + Serial2.print(": "); + Serial2.println(line); + throb(); +} + +#undef ASSERT +#define ASSERT(exp) \ + if (exp) { \ + } else { \ + bad_assert(__FILE__, __LINE__, #exp); \ + } + +void haveConversation(uint32 bitOrder); +void soliloquies(uint32 bitOrder); + +void setup() { + pinMode(BOARD_LED_PIN, OUTPUT); + Serial2.begin(115200); + Serial2.println(); + Serial2.print("** SPI test ready. Press any key to start."); + while (!Serial2.available()) + ; + Serial2.read(); +} + +void loop() { + Serial2.println("** Having a conversation, MSB first"); + haveConversation(MSBFIRST); + + Serial2.println("** Having a conversation, LSB first"); + haveConversation(LSBFIRST); + + Serial2.println(); + Serial2.println("*** All done! It looks like everything worked."); + Serial2.println(); + + Serial2.println("** Alice will now wax eloquent in various styles. " + "Press any key for the next configuration."); + soliloquies(MSBFIRST); + soliloquies(LSBFIRST); + + while (true) + ; +} + +void printFrequencyString(SPIFrequency frequency); +void chat(SPIFrequency frequency, uint32 bitOrder, uint32 mode); + +void haveConversation(uint32 bitOrder) { + for (int f = 0; f < NFREQS; f++) { + for (int mode = 0; mode < 4; mode++) { + chat(spi_freqs[f], bitOrder, mode); + delay(10); + } + } +} + +void chat(SPIFrequency frequency, uint32 bitOrder, uint32 mode) { + Serial2.print("Having a chat.\tFrequency: "); + printFrequencyString(frequency); + Serial2.print(",\tbitOrder: "); + Serial2.print(bitOrder == MSBFIRST ? "MSB" : "LSB"); + Serial2.print(",\tmode: "); + Serial2.print(mode); + Serial2.print("."); + + Serial2.print(" [1] "); + alice.begin(frequency, bitOrder, mode); + + Serial2.print(" [2] "); + uint32 txed = 0; + while (txed < TEST_BUF_SIZE) { + ASSERT(alice.transfer(test_buf[txed]) == test_buf[txed]); + txed++; + } + + Serial2.print(" [3] "); + alice.end(); + + Serial2.println(" ok."); +} + +void soliloquy(SPIFrequency freq, uint32 bitOrder, uint32 mode); + +void soliloquies(uint32 bitOrder) { + for (int f = 0; f < NFREQS; f++) { + for (int mode = 0; mode < 4; mode++) { + soliloquy(spi_freqs[f], bitOrder, mode); + } + } +} + +void soliloquy(SPIFrequency frequency, uint32 bitOrder, uint32 mode) { + const uint8 repeat = 0xAE; + Serial2.print("Alice is giving a soliloquy (repeating 0x"); + Serial2.print(repeat, HEX); + Serial2.print("). Frequency: "); + printFrequencyString(frequency); + Serial2.print(", bitOrder: "); + Serial2.print(bitOrder == MSBFIRST ? "big-endian" : "little-endian"); + Serial2.print(", SPI mode: "); + Serial2.println(mode); + + alice.begin(frequency, bitOrder, mode); + while (!Serial2.available()) { + alice.write(repeat); + delayMicroseconds(200); + } + Serial2.read(); +} + +void printFrequencyString(SPIFrequency frequency) { + switch (frequency) { + case SPI_18MHZ: + Serial2.print("18 MHz"); + break; + case SPI_9MHZ: + Serial2.print("9 MHz"); + break; + case SPI_4_5MHZ: + Serial2.print("4.5 MHz"); + break; + case SPI_2_25MHZ: + Serial2.print("2.25 MHZ"); + break; + case SPI_1_125MHZ: + Serial2.print("1.125 MHz"); + break; + case SPI_562_500KHZ: + Serial2.print("562.500 KHz"); + break; + case SPI_281_250KHZ: + Serial2.print("281.250 KHz"); + break; + case SPI_140_625KHZ: + Serial2.print("140.625 KHz"); + break; + } +} + +// Force init to be called *first*, i.e. before static object allocation. +// Otherwise, statically allocated objects that need libmaple may fail. +__attribute__((constructor)) void premain() { + init(); +} + +int main(void) { + setup(); + while (true) { + loop(); + } + return 0; +} diff --git a/libmaple/spi.c b/libmaple/spi.c index 7bdc18a..2fbc2ac 100644 --- a/libmaple/spi.c +++ b/libmaple/spi.c @@ -3,161 +3,250 @@ * * Copyright (c) 2010 Perry Hung. * - * 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 + * 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 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. + * 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. *****************************************************************************/ /** - * @brief libmaple serial peripheral interface (SPI) definitions - * - * Initial implementation for the SPI interface. - * - * This driver implements only the bare essentials of a polling driver at the - * moment. Master mode only, 8-bit data frames, and polling. - * - * The caller is responsible for controlling the chip select line. - * - * TODO: interrupt based driver, DMA. - * + * @file spi.c + * @author Marti Bolivar + * @brief Serial Peripheral Interface (SPI) support. + * Currently, there is no Integrated Interchip Sound (I2S) support. */ -#include "libmaple.h" -#include "gpio.h" -#include "rcc.h" #include "spi.h" +#include "bitband.h" -typedef struct spi_dev { - SPI *base; - gpio_dev *gpio_d; - uint8 sck_pin; - uint8 miso_pin; - uint8 mosi_pin; -} spi_dev; - -spi_dev spi_dev1 = { - .base = (SPI*)SPI1_BASE, - .gpio_d = NULL, - .sck_pin = 5, - .miso_pin = 6, - .mosi_pin = 7 -}; +/* + * SPI devices + */ -spi_dev spi_dev2 = { - .base = (SPI*)SPI2_BASE, - .gpio_d = NULL, - .sck_pin = 13, - .miso_pin = 14, - .mosi_pin = 15 +static spi_dev spi1 = { + .regs = SPI1_BASE, + .clk_id = RCC_SPI1, + .irq_num = NVIC_SPI1, }; +spi_dev *SPI1 = &spi1; -static void spi_gpio_cfg(const spi_dev *dev); +static spi_dev spi2 = { + .regs = SPI2_BASE, + .clk_id = RCC_SPI2, + .irq_num = NVIC_SPI2, +}; +spi_dev *SPI2 = &spi2; -/** - * @brief Initialize a spi peripheral - * @param spi_num which spi to turn on, SPI1 or SPI2? - * @param prescale prescale factor on the input clock. - * @param endian data frame format (LSBFIRST?) - * @param mode SPI mode number - */ -void spi_init(uint32 spi_num, - uint32 prescale, - uint32 endian, - uint32 mode) { - ASSERT(spi_num == 1 || spi_num == 2); - ASSERT(mode < 4); - - SPI *spi; - uint32 cr1 = 0; - - switch (spi_num) { - case 1: - /* limit to 18 mhz max speed */ - ASSERT(prescale != CR1_BR_PRESCALE_2); - spi = (SPI*)SPI1_BASE; - rcc_clk_enable(RCC_SPI1); - spi_dev1.gpio_d = GPIOA; - spi_gpio_cfg(&spi_dev1); - break; - case 2: - spi = (SPI*)SPI2_BASE; - rcc_clk_enable(RCC_SPI2); - spi_dev1.gpio_d = GPIOB, - spi_gpio_cfg(&spi_dev2); - break; - } +#ifdef STM32_HIGH_DENSITY +static spi_dev spi3 = { + .regs = SPI3_BASE, + .clk_id = RCC_SPI3, + .irq_num = NVIC_SPI3, +}; +spi_dev *SPI3 = &spi3; +#endif - cr1 = prescale | endian | mode | CR1_MSTR | CR1_SSI | CR1_SSM; - spi->CR1 = cr1; +/* + * SPI convenience routines + */ - /* Peripheral enable */ - spi->CR1 |= CR1_SPE; +/** + * @brief Initialize and reset a SPI device. + * @param dev Device to initialize and reset. + */ +void spi_init(spi_dev *dev) { + rcc_clk_enable(dev->clk_id); + rcc_reset_dev(dev->clk_id); } /** - * @brief SPI synchronous 8-bit write, blocking. - * @param spi_num which spi to send on - * @return data shifted back from the slave + * @brief Configure GPIO bit modes for use as a SPI bus master's pins. + * @param nss_dev NSS pin's GPIO device + * @param comm_dev SCK, MISO, MOSI pins' GPIO device + * @param nss_bit NSS pin's GPIO bit on nss_dev + * @param sck_bit SCK pin's GPIO bit on comm_dev + * @param miso_bit MISO pin's GPIO bit on comm_dev + * @param mosi_bit MOSI pin's GPIO bit on comm_dev */ -uint8 spi_tx_byte(uint32 spi_num, uint8 data) { - SPI *spi; +void spi_master_gpio_cfg(gpio_dev *nss_dev, + gpio_dev *comm_dev, + uint8 nss_bit, + uint8 sck_bit, + uint8 miso_bit, + uint8 mosi_bit) { + gpio_set_mode(nss_dev, nss_bit, GPIO_AF_OUTPUT_PP); + gpio_set_mode(comm_dev, sck_bit, GPIO_AF_OUTPUT_PP); + gpio_set_mode(comm_dev, miso_bit, GPIO_INPUT_FLOATING); + gpio_set_mode(comm_dev, mosi_bit, GPIO_AF_OUTPUT_PP); +} - spi = (spi_num == 1) ? (SPI*)SPI1_BASE : (SPI*)SPI2_BASE; +/** + * @brief Configure GPIO bit modes for use as a SPI bus slave's pins. + * @param nss_dev NSS pin's GPIO device + * @param comm_dev SCK, MISO, MOSI pins' GPIO device + * @param nss_bit NSS pin's GPIO bit on nss_dev + * @param sck_bit SCK pin's GPIO bit on comm_dev + * @param miso_bit MISO pin's GPIO bit on comm_dev + * @param mosi_bit MOSI pin's GPIO bit on comm_dev + */ +void spi_slave_gpio_cfg(gpio_dev *nss_dev, + gpio_dev *comm_dev, + uint8 nss_bit, + uint8 sck_bit, + uint8 miso_bit, + uint8 mosi_bit) { + gpio_set_mode(nss_dev, nss_bit, GPIO_INPUT_FLOATING); + gpio_set_mode(comm_dev, sck_bit, GPIO_INPUT_FLOATING); + gpio_set_mode(comm_dev, miso_bit, GPIO_AF_OUTPUT_PP); + gpio_set_mode(comm_dev, mosi_bit, GPIO_INPUT_FLOATING); +} - while (!(spi->SR & SR_TXE)) - ; +static void spi_reconfigure(spi_dev *dev, uint32 cr1_config); - spi->DR = data; +/** + * @brief Configure and enable a SPI device as bus master. + * + * The device's peripheral will be disabled before being reconfigured. + * + * @param dev Device to configure as bus master + * @param baud Bus baud rate + * @param mode SPI mode + * @param flags Logical OR of spi_cfg_flag values. + * @see spi_cfg_flag + */ +void spi_master_enable(spi_dev *dev, + spi_baud_rate baud, + spi_mode mode, + uint32 flags) { + spi_reconfigure(dev, baud | flags | SPI_CR1_MSTR | mode); +} - while (!(spi->SR & SR_RXNE)) - ; +/** + * @brief Configure and enable a SPI device as a bus slave. + * + * The device's peripheral will be disabled before being reconfigured. + * + * @param dev Device to configure as a bus slave + * @param mode SPI mode + * @param flags Logical OR of spi_cfg_flag values. + * @see spi_cfg_flag + */ +void spi_slave_enable(spi_dev *dev, spi_mode mode, uint32 flags) { + spi_reconfigure(dev, flags | mode); +} - return spi->DR; +/** + * @brief Nonblocking SPI transmit. + * @param dev SPI port to use for transmission + * @param buf Buffer to transmit. The sizeof buf's elements are + * inferred from the dev's data frame format (i.e., are + * correctly treated as 8-bit or 16-bit quantities). + * @param len Maximum number of elements to transmit. + * @return Number of elements transmitted. + */ +uint32 spi_tx(spi_dev *dev, const void *buf, uint32 len) { + spi_reg_map *regs = dev->regs; + uint32 txed = 0; + if (spi_dff(dev) == SPI_DFF_16_BIT) { + const uint8 *buf8 = (const uint8*)buf; + while ((regs->SR & SPI_SR_TXE) && (txed < len)) { + regs->DR = buf8[txed++]; + } + } else { + const uint16 *buf16 = (const uint16*)buf; + while ((regs->SR & SPI_SR_TXE) && (txed < len)) { + regs->DR = buf16[txed++]; + } + } + return txed; } -uint8 spi_tx(uint32 spi_num, uint8 *buf, uint32 len) { - SPI *spi; - uint32 i = 0; - uint8 rc; +/** + * @brief Call a function on each SPI port + * @param fn Function to call. + */ +void spi_foreach(void (*fn)(spi_dev*)) { + fn(SPI1); + fn(SPI2); +#ifdef STM32_HIGH_DENSITY + fn(SPI3); +#endif +} - ASSERT(spi_num == 1 || spi_num == 2); - spi = (spi_num == 1) ? (SPI*)SPI1_BASE : (SPI*)SPI2_BASE; +/** + * @brief Enable a SPI peripheral + * @param dev Device to enable + */ +void spi_peripheral_enable(spi_dev *dev) { + bb_peri_set_bit(&dev->regs->CR1, SPI_CR1_SPE_BIT, 1); +} - if (!len) { - return 0; - } +/** + * @brief Disable a SPI peripheral + * @param dev Device to disable + */ +void spi_peripheral_disable(spi_dev *dev) { + bb_peri_set_bit(&dev->regs->CR1, SPI_CR1_SPE_BIT, 0); +} - while (i < len) { - while (!(spi->SR & SR_TXE)) - ; +/** + * @brief Enable DMA requests whenever the transmit buffer is empty + * @param dev SPI device on which to enable TX DMA requests + */ +void spi_tx_dma_enable(spi_dev *dev) { + bb_peri_set_bit(&dev->regs->CR2, SPI_CR2_TXDMAEN_BIT, 1); +} - spi->DR = buf[i]; +/** + * @brief Disable DMA requests whenever the transmit buffer is empty + * @param dev SPI device on which to disable TX DMA requests + */ +void spi_tx_dma_disable(spi_dev *dev) { + bb_peri_set_bit(&dev->regs->CR2, SPI_CR2_TXDMAEN_BIT, 0); +} - while (!(spi->SR & SR_RXNE)) - ; +/** + * @brief Enable DMA requests whenever the receive buffer is empty + * @param dev SPI device on which to enable RX DMA requests + */ +void spi_rx_dma_enable(spi_dev *dev) { + bb_peri_set_bit(&dev->regs->CR2, SPI_CR2_RXDMAEN_BIT, 1); +} - rc = spi->DR; - i++; - } - return rc; +/** + * @brief Disable DMA requests whenever the receive buffer is empty + * @param dev SPI device on which to disable RX DMA requests + */ +void spi_rx_dma_disable(spi_dev *dev) { + bb_peri_set_bit(&dev->regs->CR2, SPI_CR2_RXDMAEN_BIT, 0); } -static void spi_gpio_cfg(const spi_dev *dev) { - gpio_set_mode(dev->gpio_d, dev->sck_pin, GPIO_AF_OUTPUT_PP); - gpio_set_mode(dev->gpio_d, dev->miso_pin, GPIO_AF_OUTPUT_PP); - gpio_set_mode(dev->gpio_d, dev->mosi_pin, GPIO_AF_OUTPUT_PP); +/* + * SPI auxiliary routines + */ + +static void spi_reconfigure(spi_dev *dev, uint32 cr1_config) { + spi_irq_disable(dev, SPI_INTERRUPTS_ALL); + spi_peripheral_disable(dev); + dev->regs->CR1 = cr1_config; + spi_peripheral_enable(dev); } + +/* + * IRQ handlers (TODO) + */ diff --git a/libmaple/spi.h b/libmaple/spi.h index 5ebf52d..e2820dd 100644 --- a/libmaple/spi.h +++ b/libmaple/spi.h @@ -24,99 +24,440 @@ /** * @file spi.h - * @brief libmaple serial peripheral interface (SPI) prototypes and - * declarations + * @author Marti Bolivar + * @brief Serial Peripheral Interface (SPI) and Integrated + * Interchip Sound (I2S) peripheral support. + * + * I2S support is currently limited to register maps and bit definitions. */ #ifndef _SPI_H_ #define _SPI_H_ #include "libmaple_types.h" +#include "rcc.h" +#include "nvic.h" +#include "gpio.h" #include "util.h" #ifdef __cplusplus extern "C" { #endif -/* peripheral addresses */ -#define SPI1_BASE 0x40013000 -#define SPI2_BASE 0x40003800 -#define SPI3_BASE 0x40003C00 - -/* baud rate prescaler bits */ -#define CR1_BR 0x00000038 -#define CR1_BR_PRESCALE_2 0x00000000 -#define CR1_BR_PRESCALE_4 0x00000008 -#define CR1_BR_PRESCALE_8 0x00000010 -#define CR1_BR_PRESCALE_16 0x00000018 -#define CR1_BR_PRESCALE_32 0x00000020 -#define CR1_BR_PRESCALE_64 0x00000028 -#define CR1_BR_PRESCALE_128 0x00000030 -#define CR1_BR_PRESCALE_256 0x00000038 - -#define CR1_LSBFIRST BIT(7) // data frame format -#define CR1_MSTR BIT(2) // master selection -#define CR1_SSM BIT(9) // software slave management -#define CR1_SSI BIT(8) // internal slave select -#define CR1_SPE BIT(6) // peripheral enable - -/* Status register bits */ -#define SR_RXNE BIT(0) // rx buffer not empty -#define SR_TXE BIT(1) // transmit buffer empty -#define SR_BSY BIT(7) // busy flag - -typedef struct SPI { - __io uint16 CR1; - uint16 pad0; - __io uint8 CR2; - uint8 pad1[3]; - __io uint8 SR; - uint8 pad2[3]; - __io uint16 DR; - uint16 pad3; - __io uint16 CRCPR; - uint16 pad4; - __io uint16 RXCRCR; - uint16 pad5; - __io uint16 TXCRCR; - uint16 pad6; -} SPI; - -enum { - SPI_MSBFIRST = 0, - SPI_LSBFIRST = BIT(7), -}; - -enum { - SPI_PRESCALE_2 = (0x0 << 3), - SPI_PRESCALE_4 = (0x1 << 3), - SPI_PRESCALE_8 = (0x2 << 3), - SPI_PRESCALE_16 = (0x3 << 3), - SPI_PRESCALE_32 = (0x4 << 3), - SPI_PRESCALE_64 = (0x5 << 3), - SPI_PRESCALE_128 = (0x6 << 3), - SPI_PRESCALE_256 = (0x7 << 3) -}; - -void spi_init(uint32 spi_num, - uint32 prescale, - uint32 endian, - uint32 mode); -uint8 spi_tx_byte(uint32 spi_num, uint8 data); -uint8 spi_tx(uint32 spi_num, uint8 *buf, uint32 len); - -static inline uint8 spi_rx(uint32 spi_num) { - SPI *spi; - - ASSERT(spi_num == 1 || spi_num == 2); - spi = (spi_num == 1) ? (SPI*)SPI1_BASE : (SPI*)SPI2_BASE; - - return spi->DR; +/* + * Register maps + */ + +/** SPI register map type. */ +typedef struct spi_reg_map { + __io uint32 CR1; /**< Control register 1 */ + __io uint32 CR2; /**< Control register 2 */ + __io uint32 SR; /**< Status register */ + __io uint32 DR; /**< Data register */ + __io uint32 CRCPR; /**< CRC polynomial register */ + __io uint32 RXCRCR; /**< RX CRC register */ + __io uint32 TXCRCR; /**< TX CRC register */ + __io uint32 I2SCFGR; /**< I2S configuration register */ + __io uint32 I2SPR; /**< I2S prescaler register */ +} spi_reg_map; + +/** SPI1 register map base pointer */ +#define SPI1_BASE ((struct spi_reg_map*)0x40013000) +/** SPI2 register map base pointer */ +#define SPI2_BASE ((struct spi_reg_map*)0x40003800) +/** SPI3 register map base pointer */ +#define SPI3_BASE ((struct spi_reg_map*)0x40003C00) + +/* + * Register bit definitions + */ + +/* Control register 1 */ + +#define SPI_CR1_BIDIMODE_BIT 15 +#define SPI_CR1_BIDIOE_BIT 14 +#define SPI_CR1_CRCEN_BIT 13 +#define SPI_CR1_CRCNEXT_BIT 12 +#define SPI_CR1_DFF_BIT 11 +#define SPI_CR1_RXONLY_BIT 10 +#define SPI_CR1_SSM_BIT 9 +#define SPI_CR1_SSI_BIT 8 +#define SPI_CR1_LSBFIRST_BIT 7 +#define SPI_CR1_SPE_BIT 6 +#define SPI_CR1_MSTR_BIT 2 +#define SPI_CR1_CPOL_BIT 1 +#define SPI_CR1_CPHA_BIT 0 + +#define SPI_CR1_BIDIMODE BIT(SPI_CR1_BIDIMODE_BIT) +#define SPI_CR1_BIDIMODE_2_LINE (0x0 << SPI_CR1_BIDIMODE_BIT) +#define SPI_CR1_BIDIMODE_1_LINE (0x1 << SPI_CR1_BIDIMODE_BIT) +#define SPI_CR1_BIDIOE BIT(SPI_CR1_BIDIOE_BIT) +#define SPI_CR1_CRCEN BIT(SPI_CR1_CRCEN_BIT) +#define SPI_CR1_CRCNEXT BIT(SPI_CR1_CRCNEXT_BIT) +#define SPI_CR1_DFF BIT(SPI_CR1_DFF_BIT) +#define SPI_CR1_DFF_8_BIT (0x0 << SPI_CR1_DFF_BIT) +#define SPI_CR1_DFF_16_BIT (0x1 << SPI_CR1_DFF_BIT) +#define SPI_CR1_RXONLY BIT(SPI_CR1_RXONLY_BIT) +#define SPI_CR1_SSM BIT(SPI_CR1_SSM_BIT) +#define SPI_CR1_SSI BIT(SPI_CR1_SSI_BIT) +#define SPI_CR1_LSBFIRST BIT(SPI_CR1_LSBFIRST_BIT) +#define SPI_CR1_SPE BIT(SPI_CR1_SPE_BIT) +#define SPI_CR1_BR (0x7 << 3) +#define SPI_CR1_BR_PCLK_DIV_2 (0x0 << 3) +#define SPI_CR1_BR_PCLK_DIV_4 (0x1 << 3) +#define SPI_CR1_BR_PCLK_DIV_8 (0x2 << 3) +#define SPI_CR1_BR_PCLK_DIV_16 (0x3 << 3) +#define SPI_CR1_BR_PCLK_DIV_32 (0x4 << 3) +#define SPI_CR1_BR_PCLK_DIV_64 (0x5 << 3) +#define SPI_CR1_BR_PCLK_DIV_128 (0x6 << 3) +#define SPI_CR1_BR_PCLK_DIV_256 (0x7 << 3) +#define SPI_CR1_MSTR BIT(SPI_CR1_MSTR_BIT) +#define SPI_CR1_CPOL BIT(SPI_CR1_CPOL_BIT) +#define SPI_CR1_CPOL_LOW (0x0 << SPI_CR1_CPOL_BIT) +#define SPI_CR1_CPOL_HIGH (0x1 << SPI_CR1_CPOL_BIT) +#define SPI_CR1_CPHA BIT(SPI_CR1_CPHA_BIT) + +/* Control register 2 */ + +/* RM0008-ism: SPI CR2 has "TXDMAEN" and "RXDMAEN" bits, while the + * USARTs have CR3 "DMAR" and "DMAT" bits. */ + +#define SPI_CR2_TXEIE_BIT 7 +#define SPI_CR2_RXNEIE_BIT 6 +#define SPI_CR2_ERRIE_BIT 5 +#define SPI_CR2_SSOE_BIT 2 +#define SPI_CR2_TXDMAEN_BIT 1 +#define SPI_CR2_RXDMAEN_BIT 0 + +#define SPI_CR2_TXEIE BIT(SPI_CR2_TXEIE_BIT) +#define SPI_CR2_RXNEIE BIT(SPI_CR2_RXNEIE_BIT) +#define SPI_CR2_ERRIE BIT(SPI_CR2_ERRIE_BIT) +#define SPI_CR2_SSOE BIT(SPI_CR2_SSOE_BIT) +#define SPI_CR2_TXDMAEN BIT(SPI_CR2_TXDMAEN_BIT) +#define SPI_CR2_RXDMAEN BIT(SPI_CR2_RXDMAEN_BIT) + +/* Status register */ + +#define SPI_SR_BSY_BIT 7 +#define SPI_SR_OVR_BIT 6 +#define SPI_SR_MODF_BIT 5 +#define SPI_SR_CRCERR_BIT 4 +#define SPI_SR_UDR_BIT 3 +#define SPI_SR_CHSIDE_BIT 2 +#define SPI_SR_TXE_BIT 1 +#define SPI_SR_RXNE_BIT 0 + +#define SPI_SR_BSY BIT(SPI_SR_BSY_BIT) +#define SPI_SR_OVR BIT(SPI_SR_OVR_BIT) +#define SPI_SR_MODF BIT(SPI_SR_MODF_BIT) +#define SPI_SR_CRCERR BIT(SPI_SR_CRCERR_BIT) +#define SPI_SR_UDR BIT(SPI_SR_UDR_BIT) +#define SPI_SR_CHSIDE BIT(SPI_SR_CHSIDE_BIT) +#define SPI_SR_CHSIDE_LEFT (0x0 << SPI_SR_CHSIDE_BIT) +#define SPI_SR_CHSIDE_RIGHT (0x1 << SPI_SR_CHSIDE_BIT) +#define SPI_SR_TXE BIT(SPI_SR_TXE_BIT) +#define SPI_SR_RXNE BIT(SPI_SR_RXNE_BIT) + +/* I2S configuration register */ + +/* RM0008-ism: CR1 has "CPOL", I2SCFGR has "CKPOL". */ + +#define SPI_I2SCFGR_I2SMOD_BIT 11 +#define SPI_I2SCFGR_I2SE_BIT 10 +#define SPI_I2SCFGR_PCMSYNC_BIT 7 +#define SPI_I2SCFGR_CKPOL_BIT 3 +#define SPI_I2SCFGR_CHLEN_BIT 0 + +#define SPI_I2SCFGR_I2SMOD BIT(SPI_I2SCFGR_I2SMOD_BIT) +#define SPI_I2SCFGR_I2SMOD_SPI (0x0 << SPI_I2SCFGR_I2SMOD_BIT) +#define SPI_I2SCFGR_I2SMOD_I2S (0x1 << SPI_I2SCFGR_I2SMOD_BIT) +#define SPI_I2SCFGR_I2SE BIT(SPI_I2SCFGR_I2SE_BIT) +#define SPI_I2SCFGR_I2SCFG (0x3 << 8) +#define SPI_I2SCFGR_I2SCFG_SLAVE_TX (0x0 << 8) +#define SPI_I2SCFGR_I2SCFG_SLAVE_RX (0x1 << 8) +#define SPI_I2SCFGR_I2SCFG_MASTER_TX (0x2 << 8) +#define SPI_I2SCFGR_I2SCFG_MASTER_RX (0x3 << 8) +#define SPI_I2SCFGR_PCMSYNC BIT(SPI_I2SCFGR_PCMSYNC_BIT) +#define SPI_I2SCFGR_PCMSYNC_SHORT (0x0 << SPI_I2SCFGR_PCMSYNC_BIT) +#define SPI_I2SCFGR_PCMSYNC_LONG (0x1 << SPI_I2SCFGR_PCMSYNC_BIT) +#define SPI_I2SCFGR_I2SSTD (0x3 << 4) +#define SPI_I2SCFGR_I2SSTD_PHILLIPS (0x0 << 4) +#define SPI_I2SCFGR_I2SSTD_MSB (0x1 << 4) +#define SPI_I2SCFGR_I2SSTD_LSB (0x2 << 4) +#define SPI_I2SCFGR_I2SSTD_PCM (0x3 << 4) +#define SPI_I2SCFGR_CKPOL BIT(SPI_I2SCFGR_CKPOL_BIT) +#define SPI_I2SCFGR_CKPOL_LOW (0x0 << SPI_I2SCFGR_CKPOL_BIT) +#define SPI_I2SCFGR_CKPOL_HIGH (0x1 << SPI_I2SCFGR_CKPOL_BIT) +#define SPI_I2SCFGR_DATLEN (0x3 << 1) +#define SPI_I2SCFGR_DATLEN_16_BIT (0x0 << 1) +#define SPI_I2SCFGR_DATLEN_24_BIT (0x1 << 1) +#define SPI_I2SCFGR_DATLEN_32_BIT (0x2 << 1) +#define SPI_I2SCFGR_CHLEN BIT(SPI_I2SCFGR_CHLEN_BIT) +#define SPI_I2SCFGR_CHLEN_16_BIT (0x0 << SPI_I2SCFGR_CHLEN_BIT) +#define SPI_I2SCFGR_CHLEN_32_BIT (0x1 << SPI_I2SCFGR_CHLEN_BIT) + +/* + * Devices + */ + +/** SPI device type */ +typedef struct spi_dev { + spi_reg_map *regs; + rcc_clk_id clk_id; + nvic_irq_num irq_num; +} spi_dev; + +/** SPI device 1 */ +extern spi_dev *SPI1; +/** SPI device 2 */ +extern spi_dev *SPI2; +#ifdef STM32_HIGH_DENSITY +/** SPI device 3 */ +extern spi_dev *SPI3; +#endif + +/* + * SPI Convenience functions + */ + +void spi_init(spi_dev *dev); + +void spi_master_gpio_cfg(gpio_dev *nss_dev, + gpio_dev *comm_dev, + uint8 nss_bit, + uint8 sck_bit, + uint8 miso_bit, + uint8 mosi_bit); + +void spi_slave_gpio_cfg(gpio_dev *nss_dev, + gpio_dev *comm_dev, + uint8 nss_bit, + uint8 sck_bit, + uint8 miso_bit, + uint8 mosi_bit); + +/** + * @brief SPI mode configuration. + * + * Determines a combination of clock polarity (CPOL), which determines + * idle state of the clock line, and clock phase (CPHA), which + * determines which clock edge triggers data capture. + */ +typedef enum { + SPI_MODE_0, /**< Clock line idles low (0), data capture on first + clock transition. */ + SPI_MODE_1, /**< Clock line idles low (0), data capture on second + clock transition */ + SPI_MODE_2, /**< Clock line idles high (1), data capture on first + clock transition. */ + SPI_MODE_3 /**< Clock line idles high (1), data capture on + second clock transition. */ +} spi_mode; + +/** + * @brief SPI baud rate configuration, as a divisor of f_PCLK, the + * PCLK clock frequency. + */ +typedef enum { + SPI_BAUD_PCLK_DIV_2 = SPI_CR1_BR_PCLK_DIV_2, /**< f_PCLK/2 */ + SPI_BAUD_PCLK_DIV_4 = SPI_CR1_BR_PCLK_DIV_4, /**< f_PCLK/4 */ + SPI_BAUD_PCLK_DIV_8 = SPI_CR1_BR_PCLK_DIV_8, /**< f_PCLK/8 */ + SPI_BAUD_PCLK_DIV_16 = SPI_CR1_BR_PCLK_DIV_16, /**< f_PCLK/16 */ + SPI_BAUD_PCLK_DIV_32 = SPI_CR1_BR_PCLK_DIV_32, /**< f_PCLK/32 */ + SPI_BAUD_PCLK_DIV_64 = SPI_CR1_BR_PCLK_DIV_64, /**< f_PCLK/64 */ + SPI_BAUD_PCLK_DIV_128 = SPI_CR1_BR_PCLK_DIV_128, /**< f_PCLK/128 */ + SPI_BAUD_PCLK_DIV_256 = SPI_CR1_BR_PCLK_DIV_256, /**< f_PCLK/256 */ +} spi_baud_rate; + +/** + * @brief SPI initialization flags. + * @see spi_master_enable() + * @see spi_slave_enable() + */ +typedef enum { + SPI_BIDIMODE = SPI_CR1_BIDIMODE, /**< Bidirectional mode enable */ + SPI_BIDIOE = SPI_CR1_BIDIOE, /**< Output enable in bidirectional + mode */ + SPI_CRCEN = SPI_CR1_CRCEN, /**< Cyclic redundancy check (CRC) + enable */ + SPI_DFF_8_BIT = SPI_CR1_DFF_8_BIT, /**< 8-bit data frame format (this is + the default) */ + SPI_DFF_16_BIT = SPI_CR1_DFF_16_BIT, /**< 16-bit data frame format */ + SPI_RX_ONLY = SPI_CR1_RXONLY, /**< Receive only */ + SPI_SW_SLAVE = SPI_CR1_SSM, /**< Software slave management */ + SPI_SOFT_SS = SPI_CR1_SSI, /**< Software (internal) slave + select. This flag only has an + effect when used in combination + with SPI_SW_SLAVE. */ + SPI_FRAME_LSB = SPI_CR1_LSBFIRST, /**< LSB-first (little-endian) frame + format */ + SPI_FRAME_MSB = 0, /**< MSB-first (big-endian) frame + format (this is the default) */ +} spi_cfg_flag; + +void spi_master_enable(spi_dev *dev, + spi_baud_rate baud, + spi_mode mode, + uint32 flags); + +void spi_slave_enable(spi_dev *dev, + spi_mode mode, + uint32 flags); + +uint32 spi_tx(spi_dev *dev, const void *buf, uint32 len); + +void spi_foreach(void (*fn)(spi_dev (*dev))); + +void spi_peripheral_enable(spi_dev *dev); +void spi_peripheral_disable(spi_dev *dev); + +void spi_tx_dma_enable(spi_dev *dev); +void spi_tx_dma_disable(spi_dev *dev); + +void spi_rx_dma_enable(spi_dev *dev); +void spi_rx_dma_disable(spi_dev *dev); + +/** + * @brief Determine if a SPI peripheral is enabled. + * @parm dev SPI device + * @return True, if and only if dev's peripheral is enabled. + */ +static inline uint8 spi_is_enabled(spi_dev *dev) { + return dev->regs->CR1 & SPI_CR1_SPE_BIT; +} + +/** + * @brief Disable all SPI peripherals + */ +static inline void spi_peripheral_disable_all(void) { + spi_foreach(spi_peripheral_disable); +} + +/** Available SPI interrupts */ +typedef enum { + SPI_TXE_INTERRUPT = SPI_CR2_TXEIE, /**< TX buffer empty interrupt */ + SPI_RXNE_INTERRUPT = SPI_CR2_RXNEIE, /**< RX buffer not empty interrupt */ + SPI_ERR_INTERRUPT = SPI_CR2_ERRIE /**< + * Error interrupt (CRC, overrun, + * and mode fault errors for SPI; + * underrun, overrun errors for I2S) + */ +} spi_interrupt; + +/** + * @brief Mask for all spi_interrupt values + * @see spi_interrupt + */ +#define SPI_INTERRUPTS_ALL (SPI_TXE_INTERRUPT | \ + SPI_RXNE_INTERRUPT | \ + SPI_ERR_INTERRUPT) + +/** + * @brief Enable SPI interrupt requests + * @param dev SPI device + * @param interrupt_flags Bitwise OR of spi_interrupt values to enable + * @see spi_interrupt + */ +static inline void spi_irq_enable(spi_dev *dev, uint32 interrupt_flags) { + dev->regs->CR2 |= interrupt_flags; + nvic_irq_enable(dev->irq_num); +} + +/** + * @brief Disable SPI interrupt requests + * @param dev SPI device + * @param interrupt_flags Bitwise OR of spi_interrupt values to disable + * @see spi_interrupt + */ +static inline void spi_irq_disable(spi_dev *dev, uint32 interrupt_flags) { + dev->regs->CR2 &= ~interrupt_flags; +} + +/** + * @brief Get the data frame format flags with which a SPI port is + * configured. + * @param dev SPI device whose data frame format to get. + * @return SPI_DFF_8_BIT, if dev has an 8-bit data frame format. + * Otherwise, SPI_DFF_16_BIT. + */ +static inline spi_cfg_flag spi_dff(spi_dev *dev) { + return ((dev->regs->CR1 & SPI_CR1_DFF) == SPI_CR1_DFF_8_BIT ? + SPI_DFF_8_BIT : + SPI_DFF_16_BIT); +} + +/** + * @brief Determine whether the device's peripheral receive (RX) + * register is empty. + * @param dev SPI device + * @return true, iff dev's RX register is empty. + */ +static inline uint8 spi_is_rx_nonempty(spi_dev *dev) { + return dev->regs->SR & SPI_SR_RXNE; +} + +/** + * @brief Retrieve the contents of the device's peripheral receive + * (RX) register. + * + * You may only call this function when the RX register is nonempty. + * Calling this function clears the contents of the RX register. + * + * @param dev SPI device + * @return Contents of dev's peripheral RX register + * @see spi_is_rx_reg_nonempty() + */ +static inline uint16 spi_rx_reg(spi_dev *dev) { + return (uint16)dev->regs->DR; +} + +/** + * @brief Determine whether the device's peripheral transmit (TX) + * register is empty. + * @param dev SPI device + * @return true, iff dev's TX register is empty. + */ +static inline uint8 spi_is_tx_empty(spi_dev *dev) { + return dev->regs->SR & SPI_SR_TXE; +} + +/** + * @brief Load a value into the device's peripheral transmit (TX) register. + * + * You may only call this function when the TX register is empty. + * Calling this function loads val into the peripheral's TX register. + * If the device is properly configured, this will initiate a + * transmission, the completion of which will cause the TX register to + * be empty again. + * + * @param dev SPI device + * @param val Value to load into the TX register. If the SPI data + * frame format is 8 bit, the value must be right-aligned. + * @see spi_is_tx_reg_empty() + * @see spi_init() + * @see spi_master_enable() + * @see spi_slave_enable() + */ +static inline void spi_tx_reg(spi_dev *dev, uint16 val) { + dev->regs->DR = val; +} + +/** + * @brief Determine whether the device's peripheral busy (SPI_SR_BSY) + * flag is set. + * @param dev SPI device + * @return true, iff dev's BSY flag is set. + */ +static inline uint8 spi_is_busy(spi_dev *dev) { + return dev->regs->SR & SPI_SR_BSY; } +/* + * I2S convenience functions (TODO) + */ + #ifdef __cplusplus } #endif #endif - diff --git a/wirish/boards/maple.h b/wirish/boards/maple.h index 4a4465c..4b55f7a 100644 --- a/wirish/boards/maple.h +++ b/wirish/boards/maple.h @@ -52,6 +52,19 @@ #define BOARD_USART3_TX_PIN 29 #define BOARD_USART3_RX_PIN 30 +/* Number of SPI ports */ +#define BOARD_NR_SPI 2 + +/* Default SPI pin numbers (not considering AFIO remap) */ +#define BOARD_SPI1_NSS_PIN 10 +#define BOARD_SPI1_MOSI_PIN 11 +#define BOARD_SPI1_MISO_PIN 12 +#define BOARD_SPI1_SCK_PIN 13 +#define BOARD_SPI2_NSS_PIN 31 +#define BOARD_SPI2_MOSI_PIN 34 +#define BOARD_SPI2_MISO_PIN 33 +#define BOARD_SPI2_SCK_PIN 32 + /* Total number of GPIO pins that are broken out to headers and * intended for general use. */ #define BOARD_NR_GPIO_PINS 44 diff --git a/wirish/boards/maple_RET6.h b/wirish/boards/maple_RET6.h index 97e609d..4195857 100644 --- a/wirish/boards/maple_RET6.h +++ b/wirish/boards/maple_RET6.h @@ -55,6 +55,16 @@ #define BOARD_USART3_TX_PIN 29 #define BOARD_USART3_RX_PIN 30 +#define BOARD_NR_SPI 2 +#define BOARD_SPI1_NSS_PIN 10 +#define BOARD_SPI1_MOSI_PIN 11 +#define BOARD_SPI1_MISO_PIN 12 +#define BOARD_SPI1_SCK_PIN 13 +#define BOARD_SPI2_NSS_PIN 31 +#define BOARD_SPI2_MOSI_PIN 34 +#define BOARD_SPI2_MISO_PIN 33 +#define BOARD_SPI2_SCK_PIN 32 + #define BOARD_NR_GPIO_PINS 44 #define BOARD_NR_PWM_PINS 16 #define BOARD_NR_ADC_PINS 15 diff --git a/wirish/boards/maple_mini.h b/wirish/boards/maple_mini.h index 3df1da8..fde7f98 100644 --- a/wirish/boards/maple_mini.h +++ b/wirish/boards/maple_mini.h @@ -54,6 +54,16 @@ #define BOARD_USART3_TX_PIN 1 #define BOARD_USART3_RX_PIN 0 +#define BOARD_NR_SPI 2 +#define BOARD_SPI1_NSS_PIN 7 +#define BOARD_SPI1_MOSI_PIN 4 +#define BOARD_SPI1_MISO_PIN 5 +#define BOARD_SPI1_SCK_PIN 6 +#define BOARD_SPI2_NSS_PIN 31 +#define BOARD_SPI2_MOSI_PIN 28 +#define BOARD_SPI2_MISO_PIN 29 +#define BOARD_SPI2_SCK_PIN 30 + #define BOARD_NR_GPIO_PINS 34 #define BOARD_NR_PWM_PINS 12 #define BOARD_NR_ADC_PINS 10 diff --git a/wirish/boards/maple_native.cpp b/wirish/boards/maple_native.cpp index ab8b282..c1f8d5c 100644 --- a/wirish/boards/maple_native.cpp +++ b/wirish/boards/maple_native.cpp @@ -171,7 +171,7 @@ extern const uint8 boardADCPins[BOARD_NR_ADC_PINS] __FLASH__ = { 54, 55 }; -/* FIXME! see comment by BOARD_NR_USED_PINS in maple_native.h */ +/* FIXME [0.0.10] see comment by BOARD_NR_USED_PINS in maple_native.h */ extern const uint8 boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = { BOARD_LED_PIN, BOARD_BUTTON_PIN, BOARD_JTMS_SWDIO_PIN, BOARD_JTCK_SWCLK_PIN, BOARD_JTDI_PIN, BOARD_JTDO_PIN, BOARD_NJTRST_PIN diff --git a/wirish/boards/maple_native.h b/wirish/boards/maple_native.h index 13df153..2cbd406 100644 --- a/wirish/boards/maple_native.h +++ b/wirish/boards/maple_native.h @@ -58,12 +58,27 @@ #define BOARD_UART5_TX_PIN 21 #define BOARD_UART5_RX_PIN 29 +#define BOARD_NR_SPI 3 +#define BOARD_SPI1_NSS_PIN 52 +#define BOARD_SPI1_MOSI_PIN 55 +#define BOARD_SPI1_MISO_PIN 54 +#define BOARD_SPI1_SCK_PIN 53 +#define BOARD_SPI2_NSS_PIN 2 +#define BOARD_SPI2_MOSI_PIN 5 +#define BOARD_SPI2_MISO_PIN 4 +#define BOARD_SPI2_SCK_PIN 3 +#define BOARD_SPI3_NSS_PIN 103 +#define BOARD_SPI3_MOSI_PIN 37 +#define BOARD_SPI3_MISO_PIN 105 +#define BOARD_SPI3_SCK_PIN 104 + #define BOARD_NR_GPIO_PINS 106 #define BOARD_NR_PWM_PINS 18 #define BOARD_NR_ADC_PINS 21 -/* FIXME! this isn't true at all; almost all of the triple header pins - * are used by the FSMC by default. Fix this (and the corresponding - * boardUsedPins definition in maple_native.cpp) by QA time. */ +/* FIXME [0.0.10] this isn't true at all; almost all of the triple + * header pins are used by the FSMC by default. Fix this (and the + * corresponding boardUsedPins definition in maple_native.cpp) by QA + * time. */ #define BOARD_NR_USED_PINS 7 #define BOARD_JTMS_SWDIO_PIN 101 diff --git a/wirish/comm/HardwareSPI.cpp b/wirish/comm/HardwareSPI.cpp index aea7734..1b36d21 100644 --- a/wirish/comm/HardwareSPI.cpp +++ b/wirish/comm/HardwareSPI.cpp @@ -23,120 +23,283 @@ *****************************************************************************/ /** - * @brief HardwareSPI "wiring-like" api for SPI + * @author Marti Bolivar + * @brief Wirish SPI implementation. */ -/* NOTES: - * - * Speeds: - * ----------------------------------- - * Interface num: SPI1 SPI2 - * Bus APB2 APB1 - * ----------------------------------- - * Prescaler Frequencies - * ----------------------------------- - * 2: N/A 18 000 000 - * 4: 18 000 000 9 000 000 - * 8: 9 000 000 4 500 000 - * 16: 4 500 000 2 250 000 - * 32: 2 250 000 1 125 000 - * 64: 1 125 000 562 500 - * 128: 562 500 281 250 - * 256: 281 250 140 625 - * - * TODO: Do the complementary PWM outputs mess up SPI2? - * */ +#include "HardwareSPI.h" -#include "spi.h" #include "timer.h" +#include "util.h" #include "wirish.h" -#include "HardwareSPI.h" +#include "boards.h" -static const uint32 prescaleFactors[MAX_SPI_FREQS] = { - SPI_PRESCALE_2, // SPI_18MHZ - SPI_PRESCALE_4, // SPI_9MHZ - SPI_PRESCALE_8, // SPI_4_5MHZ - SPI_PRESCALE_16, // SPI_2_25MHZ - SPI_PRESCALE_32, // SPI_1_125MHZ - SPI_PRESCALE_64, // SPI_562_500KHZ - SPI_PRESCALE_128, // SPI_281_250KHZ - SPI_PRESCALE_256, // SPI_140_625KHZ -}; +static void enable_device(spi_dev *dev, + bool as_master, + SPIFrequency frequency, + spi_cfg_flag endianness, + spi_mode mode); -/** - * @brief Initialize a SPI peripheral - * @param freq frequency to run at, must one of the following values: - * - SPI_18MHZ - * - SPI_9MHZ - * - SPI_4_5MHZ - * - SPI_2_25MHZ - * - SPI_1_125MHZ - * - SPI_562_500KHZ - * - SPI_281_250KHZ - * - SPI_140_625KHZ - * @param endianness endianness of the data frame, must be either LSBFIRST - * or MSBFIRST - * @param mode SPI standard CPOL and CPHA levels +/* + * Constructor, public methods */ -void HardwareSPI::begin(SPIFrequency freq, uint32 endianness, uint32 mode) { - uint32 spi_num = this->spi_num; - uint32 prescale; - - if ((freq >= MAX_SPI_FREQS) || - !((endianness == LSBFIRST) || - (endianness == MSBFIRST)) || - (mode >= 4)) { + +HardwareSPI::HardwareSPI(uint32 spi_num) { + switch (spi_num) { + case 1: + this->spi_d = SPI1; + break; + case 2: + this->spi_d = SPI2; + break; +#ifdef STM32_HIGH_DENSITY + case 3: + this->spi_d = SPI3; + break; +#endif + default: + ASSERT(0); + } +} + +void HardwareSPI::begin(SPIFrequency frequency, uint32 bitOrder, uint32 mode) { + if (mode >= 4) { + ASSERT(0); return; } + spi_cfg_flag end = bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB; + spi_mode m = (spi_mode)mode; + enable_device(this->spi_d, true, frequency, end, m); +} - if (spi_num == 1) { - /* SPI1 is too fast for 140625 */ - if (freq == SPI_140_625KHZ) { - return; - } +void HardwareSPI::begin(void) { + this->begin(SPI_1_125MHZ, MSBFIRST, 0); +} - /* Turn off PWM on shared pins */ - timer_set_mode(TIMER3, 2, TIMER_DISABLED); - timer_set_mode(TIMER3, 1, TIMER_DISABLED); +void HardwareSPI::beginSlave(uint32 bitOrder, uint32 mode) { + if (mode >= 4) { + ASSERT(0); + return; } + spi_cfg_flag end = bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB; + spi_mode m = (spi_mode)mode; + enable_device(this->spi_d, false, (SPIFrequency)0, end, m); +} - endianness = (endianness == LSBFIRST) ? SPI_LSBFIRST : SPI_MSBFIRST; - prescale = (spi_num == 1) ? - prescaleFactors[freq + 1] : - prescaleFactors[freq]; +void HardwareSPI::beginSlave(void) { + this->beginSlave(MSBFIRST, 0); +} - spi_init(spi_num, prescale, endianness, mode); +void HardwareSPI::end(void) { + if (!spi_is_enabled(this->spi_d)) { + return; + } + + // Follows RM0008's sequence for disabling a SPI in master/slave + // full duplex mode. + while (spi_is_rx_nonempty(this->spi_d)) { + // FIXME [0.1.0] remove this once you have an interrupt based driver + volatile uint16 rx __attribute__((unused)) = spi_rx_reg(this->spi_d); + } + while (!spi_is_tx_empty(this->spi_d)) + ; + while (spi_is_busy(this->spi_d)) + ; + spi_peripheral_disable(this->spi_d); } -/** - * @brief Initialize a SPI peripheral with a default speed of 1.125 - * MHZ, MSBFIRST, mode 0 - */ -void HardwareSPI::begin(void) { - begin(SPI_1_125MHZ, MSBFIRST, 0); +uint8 HardwareSPI::read(void) { + uint8 buf[1]; + this->read(buf, 1); + return buf[0]; } -/** - * @brief send a byte out the spi peripheral - * @param data byte to send +void HardwareSPI::read(uint8 *buf, uint32 len) { + uint32 rxed = 0; + while (rxed < len) { + while (!spi_is_rx_nonempty(this->spi_d)) + ; + buf[rxed++] = (uint8)spi_rx_reg(this->spi_d); + } +} + +void HardwareSPI::write(uint8 byte) { + uint8 buf[] = {byte}; + this->write(buf, 1); +} + +void HardwareSPI::write(uint8 *data, uint32 length) { + uint32 txed = 0; + while (txed < length) { + txed += spi_tx(this->spi_d, data + txed, length - txed); + } +} + +uint8 HardwareSPI::transfer(uint8 byte) { + this->write(byte); + return this->read(); +} + +/* + * Deprecated functions */ + uint8 HardwareSPI::send(uint8 data) { - return spi_tx_byte(this->spi_num, data); + uint8 buf[] = {data}; + return this->send(buf, 1); } uint8 HardwareSPI::send(uint8 *buf, uint32 len) { - return spi_tx(this->spi_num, buf, len); + if (len == 0) { + ASSERT(0); + return 0; + } + uint32 txed = 0; + uint8 ret = 0; // shut up, GCC + while (txed < len) { + this->write(buf[txed++]); + ret = this->read(); + } + return ret; } -/** - * @brief read a byte from the spi peripheral - * @return byte in the buffer - */ uint8 HardwareSPI::recv(void) { - return spi_rx(this->spi_num); + return this->read(); } -HardwareSPI::HardwareSPI(uint32 spi_num) { - this->spi_num = spi_num; +/* + * Auxiliary functions + */ + +static void configure_gpios(spi_dev *dev, bool as_master); +static spi_baud_rate determine_baud_rate(spi_dev *dev, SPIFrequency freq); + +/* Enables the device in master or slave full duplex mode. If you + * change this code, you must ensure that appropriate changes are made + * to HardwareSPI::end(). */ +static void enable_device(spi_dev *dev, + bool as_master, + SPIFrequency freq, + spi_cfg_flag endianness, + spi_mode mode) { + if (freq >= MAX_SPI_FREQS) { + ASSERT(0); + return; + } + + spi_baud_rate baud = determine_baud_rate(dev, freq); + uint32 cfg_flags = (endianness | SPI_DFF_8_BIT | SPI_SW_SLAVE | + (as_master ? SPI_SOFT_SS : 0)); + + spi_init(dev); + configure_gpios(dev, as_master); + if (as_master) { + spi_master_enable(dev, baud, mode, cfg_flags); + } else { + spi_slave_enable(dev, mode, cfg_flags); + } +} + +static void disable_pwm(const stm32_pin_info *i) { + if (i->timer_device) { + timer_set_mode(i->timer_device, i->timer_channel, TIMER_DISABLED); + } +} + +typedef struct spi_pins { + uint8 nss; + uint8 sck; + uint8 miso; + uint8 mosi; +} spi_pins; + +static void configure_gpios(spi_dev *dev, bool as_master) { + const spi_pins spi_pin_config[] = { + {BOARD_SPI1_NSS_PIN, + BOARD_SPI1_SCK_PIN, + BOARD_SPI1_MISO_PIN, + BOARD_SPI1_MOSI_PIN}, + {BOARD_SPI2_NSS_PIN, + BOARD_SPI2_SCK_PIN, + BOARD_SPI2_MISO_PIN, + BOARD_SPI2_MOSI_PIN}, +#ifdef STM32_HIGH_DENSITY + {BOARD_SPI3_NSS_PIN, + BOARD_SPI3_SCK_PIN, + BOARD_SPI3_MISO_PIN, + BOARD_SPI3_MOSI_PIN}, +#endif + }; + + const spi_pins *pins; + + switch (dev->clk_id) { + case RCC_SPI1: + pins = &spi_pin_config[0]; + break; + case RCC_SPI2: + pins = &spi_pin_config[1]; + break; +#ifdef STM32_HIGH_DENSITY + case RCC_SPI3: + pins = &spi_pin_config[2]; + break; +#endif + default: + ASSERT(0); + return; + } + + const stm32_pin_info *nssi = &PIN_MAP[pins->nss]; + const stm32_pin_info *scki = &PIN_MAP[pins->sck]; + const stm32_pin_info *misoi = &PIN_MAP[pins->miso]; + const stm32_pin_info *mosii = &PIN_MAP[pins->mosi]; + + disable_pwm(nssi); + disable_pwm(scki); + disable_pwm(misoi); + disable_pwm(mosii); + + if (as_master) { + spi_master_gpio_cfg(nssi->gpio_device, + scki->gpio_device, + nssi->gpio_bit, + scki->gpio_bit, + misoi->gpio_bit, + mosii->gpio_bit); + } else { + spi_slave_gpio_cfg(nssi->gpio_device, + scki->gpio_device, + nssi->gpio_bit, + scki->gpio_bit, + misoi->gpio_bit, + mosii->gpio_bit); + } +} + +static const spi_baud_rate baud_rates[MAX_SPI_FREQS] __FLASH__ = { + SPI_BAUD_PCLK_DIV_2, + SPI_BAUD_PCLK_DIV_4, + SPI_BAUD_PCLK_DIV_8, + SPI_BAUD_PCLK_DIV_16, + SPI_BAUD_PCLK_DIV_32, + SPI_BAUD_PCLK_DIV_64, + SPI_BAUD_PCLK_DIV_128, + SPI_BAUD_PCLK_DIV_256, +}; + +/* + * Note: This assumes you're on a LeafLabs-style board + * (CYCLES_PER_MICROSECOND == 72, APB2 at 72MHz, APB1 at 36MHz). + */ +static spi_baud_rate determine_baud_rate(spi_dev *dev, SPIFrequency freq) { + if (rcc_dev_clk(dev->clk_id) == RCC_APB2 && freq == SPI_140_625KHZ) { + /* APB2 peripherals are too fast for 140.625 KHz */ + ASSERT(0); + return (spi_baud_rate)~0; + } + return (rcc_dev_clk(dev->clk_id) == RCC_APB2 ? + baud_rates[freq + 1] : + baud_rates[freq]); } diff --git a/wirish/comm/HardwareSPI.h b/wirish/comm/HardwareSPI.h index 7241d0b..1b2a966 100644 --- a/wirish/comm/HardwareSPI.h +++ b/wirish/comm/HardwareSPI.h @@ -3,60 +3,188 @@ * * Copyright (c) 2010 Perry Hung. * - * 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 + * 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 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. + * 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. *****************************************************************************/ /** - * @brief HardwareSPI definitions + * @file HardwareSPI.h + * @brief High-level SPI interface + * + * This is a "bare essentials" polling driver for now. */ +/* TODO [0.1.0] Remove deprecated methods. */ + +#include "libmaple_types.h" +#include "spi.h" + +#include "boards.h" + #ifndef _HARDWARESPI_H_ #define _HARDWARESPI_H_ /** - * Defines the possible SPI communication speeds. + * @brief Defines the possible SPI communication speeds. */ typedef enum SPIFrequency { SPI_18MHZ = 0, /**< 18 MHz */ SPI_9MHZ = 1, /**< 9 MHz */ SPI_4_5MHZ = 2, /**< 4.5 MHz */ - SPI_2_25MHZ = 3, /**< 2.25 MHZ */ + SPI_2_25MHZ = 3, /**< 2.25 MHz */ SPI_1_125MHZ = 4, /**< 1.125 MHz */ SPI_562_500KHZ = 5, /**< 562.500 KHz */ SPI_281_250KHZ = 6, /**< 281.250 KHz */ SPI_140_625KHZ = 7, /**< 140.625 KHz */ - MAX_SPI_FREQS = 8, /**< The number of SPI frequencies. */ } SPIFrequency; -/* Documented by hand in docs/source/lang/api/hardwarespi.rst; if you - make any changes, make sure to update this document. */ +#define MAX_SPI_FREQS 8 + +#if CYCLES_PER_MICROSECOND != 72 +/* TODO [0.2.0?] something smarter than this */ +#warn "Unexpected clock speed; SPI frequency calculation will be incorrect" +#endif + +/** + * @brief Wirish SPI interface. + * + * This implementation uses software slave management, so the caller + * is responsible for controlling the slave select line. + */ class HardwareSPI { - private: - uint32 spi_num; +public: + /** + * @param spiPortNumber Number of the SPI port to manage. + */ + HardwareSPI(uint32 spiPortNumber); + + /** + * @brief Turn on a SPI port and set its GPIO pin modes for use as master. + * + * SPI port is enabled in full duplex mode, with software slave management. + * + * @param frequency Communication frequency + * @param bitOrder Either LSBFIRST (little-endian) or MSBFIRST (big-endian) + * @param mode SPI mode to use, one of SPI_MODE_0, SPI_MODE_1, + * SPI_MODE_2, and SPI_MODE_3. + */ + void begin(SPIFrequency frequency, uint32 bitOrder, uint32 mode); - public: - HardwareSPI(uint32 spi_num); + /** + * @brief Equivalent to begin(SPI_1_125MHZ, MSBFIRST, 0). + */ void begin(void); - void begin(SPIFrequency freq, uint32 endianness, uint32 mode); + + /** + * @brief Turn on a SPI port and set its GPIO pin modes for use as a slave. + * + * SPI port is enabled in full duplex mode, with software slave management. + * + * @param bitOrder Either LSBFIRST (little-endian) or MSBFIRST(big-endian) + * @param mode SPI mode to use + */ + void beginSlave(uint32 bitOrder, uint32 mode); + + /** + * @brief Equivalent to beginSlave(MSBFIRST, 0). + */ + void beginSlave(void); + + /** + * @brief Disables the SPI port, but leaves its GPIO pin modes unchanged. + */ + void end(void); + + /** + * @brief Return the next unread byte. + * + * If there is no unread byte waiting, this function will block + * until one is received. + */ + uint8 read(void); + + /** + * @brief Read length bytes, storing them into buffer. + * @param buffer Buffer to store received bytes into. + * @param length Number of bytes to store in buffer. This + * function will block until the desired number of + * bytes have been read. + */ + void read(uint8 *buffer, uint32 length); + + /** + * @brief Transmit a byte. + * @param data Byte to transmit. + */ + void write(uint8 data); + + /** + * @brief Transmit multiple bytes. + * @param buffer Bytes to transmit. + * @param length Number of bytes in buffer to transmit. + */ + void write(uint8 *buffer, uint32 length); + + /** + * @brief Transmit a byte, then return the next unread byte. + * + * This function transmits before receiving. + * + * @param data Byte to transmit. + * @return Next unread byte. + */ + uint8 transfer(uint8 data); + + /* -- The following methods are deprecated --------------------------- */ + + /** + * @brief Deprecated. + * + * Use HardwareSPI::transfer() instead. + * + * @see HardwareSPI::transfer() + */ uint8 send(uint8 data); + + /** + * @brief Deprecated. + * + * Use HardwareSPI::write() in combination with + * HardwareSPI::read() (or HardwareSPI::transfer()) instead. + * + * @see HardwareSPI::write() + * @see HardwareSPI::read() + * @see HardwareSPI::transfer() + */ uint8 send(uint8 *data, uint32 length); + + /** + * @brief Deprecated. + * + * Use HardwareSPI::read() instead. + * + * @see HardwareSPI::read() + */ uint8 recv(void); +private: + spi_dev *spi_d; }; #endif -- cgit v1.2.3 From 13faed75ea1366c14995aa6649b4262029822516 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Fri, 29 Apr 2011 12:02:51 -0400 Subject: Adding RCC_SPI3 for high density devices. --- libmaple/rcc.c | 1 + libmaple/rcc.h | 1 + 2 files changed, 2 insertions(+) diff --git a/libmaple/rcc.c b/libmaple/rcc.c index efb2599..37c1ec4 100644 --- a/libmaple/rcc.c +++ b/libmaple/rcc.c @@ -83,6 +83,7 @@ static const struct rcc_dev_info rcc_dev_table[] = { [RCC_DAC] = { .clk_domain = APB1, .line_num = 29 }, [RCC_DMA2] = { .clk_domain = AHB, .line_num = 1 }, [RCC_SDIO] = { .clk_domain = AHB, .line_num = 10 }, + [RCC_SPI3] = { .clk_domain = APB1, .line_num = 15 }, #endif #ifdef STM32_XL_DENSITY [RCC_TIMER9] = { .clk_domain = APB2, .line_num = 19 }, diff --git a/libmaple/rcc.h b/libmaple/rcc.h index 08f8977..f0f026b 100644 --- a/libmaple/rcc.h +++ b/libmaple/rcc.h @@ -467,6 +467,7 @@ typedef enum { RCC_DAC, RCC_DMA2, RCC_SDIO, + RCC_SPI3, #endif #ifdef STM32_XL_DENSITY RCC_TIMER9, -- cgit v1.2.3 From 7caa5711c3f2d03870cba71d175a057e573aff8d Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Fri, 29 Apr 2011 12:28:30 -0400 Subject: Native and FSMC cleanups. Got rid of native_sram.h (and native_sram.cpp), and pushed their functionality into maple_native.cpp. Fixed includes in maple_native.h. Fixed includes in fsmc.h. --- libmaple/fsmc.c | 4 +--- libmaple/fsmc.h | 14 +++++++------ wirish/boards/maple_native.cpp | 23 +++++++++++++++++++-- wirish/boards/maple_native.h | 5 ----- wirish/native_sram.cpp | 45 ------------------------------------------ wirish/native_sram.h | 43 ---------------------------------------- wirish/rules.mk | 3 +-- 7 files changed, 31 insertions(+), 106 deletions(-) delete mode 100644 wirish/native_sram.cpp delete mode 100644 wirish/native_sram.h diff --git a/libmaple/fsmc.c b/libmaple/fsmc.c index 70d7e0d..356e1e5 100644 --- a/libmaple/fsmc.c +++ b/libmaple/fsmc.c @@ -26,10 +26,8 @@ * @brief */ -#include "libmaple.h" -#include "rcc.h" -#include "gpio.h" #include "fsmc.h" +#include "gpio.h" #ifdef STM32_HIGH_DENSITY diff --git a/libmaple/fsmc.h b/libmaple/fsmc.h index fccaf0b..8b6cac5 100644 --- a/libmaple/fsmc.h +++ b/libmaple/fsmc.h @@ -26,6 +26,8 @@ * See ../notes/fsmc.txt for more info */ +#include "libmaple_types.h" + /** * @file fsmc.h */ @@ -83,10 +85,10 @@ typedef struct fsmc_reg_map { __io uint32 BWTR4; /**< SRAM/NOR-Flash write timing register 4 */ } __attribute__((packed)) fsmc_reg_map; -#define __FSMC_B 0xA0000000 +#define __FSMCB 0xA0000000 /** FSMC register map base pointer */ -#define FSMC_BASE ((struct fsmc_reg_map*)__FSMC_B) +#define FSMC_BASE ((struct fsmc_reg_map*)__FSMCB) /** FSMC NOR/PSRAM register map type */ typedef struct fsmc_nor_psram_reg_map { @@ -97,16 +99,16 @@ typedef struct fsmc_nor_psram_reg_map { } fsmc_nor_psram_reg_map; /** FSMC NOR/PSRAM base pointer 1 */ -#define FSMC_NOR_PSRAM1_BASE ((struct fsmc_nor_psram_reg_map*)__FSMC_B) +#define FSMC_NOR_PSRAM1_BASE ((struct fsmc_nor_psram_reg_map*)__FSMCB) /** FSMC NOR/PSRAM base pointer 2 */ -#define FSMC_NOR_PSRAM2_BASE ((struct fsmc_nor_psram_reg_map*)(__FSMC_B + 0x8)) +#define FSMC_NOR_PSRAM2_BASE ((struct fsmc_nor_psram_reg_map*)(__FSMCB + 0x8)) /** FSMC NOR/PSRAM base pointer 3 */ -#define FSMC_NOR_PSRAM3_BASE ((struct fsmc_nor_psram_reg_map*)(__FSMC_B+0x10)) +#define FSMC_NOR_PSRAM3_BASE ((struct fsmc_nor_psram_reg_map*)(__FSMCB + 0x10)) /** FSMC NOR/PSRAM base pointer 4 */ -#define FSMC_NOR_PSRAM4_BASE ((struct fsmc_nor_psram_reg_map*)(__FSMC_B+0x18)) +#define FSMC_NOR_PSRAM4_BASE ((struct fsmc_nor_psram_reg_map*)(__FSMCB + 0x18)) /* * Register bit definitions diff --git a/wirish/boards/maple_native.cpp b/wirish/boards/maple_native.cpp index c1f8d5c..fa36240 100644 --- a/wirish/boards/maple_native.cpp +++ b/wirish/boards/maple_native.cpp @@ -31,12 +31,20 @@ */ #include "maple_native.h" -#include "native_sram.h" + +#include "fsmc.h" +#include "gpio.h" +#include "rcc.h" +#include "timer.h" + +#include "wirish_types.h" #ifdef BOARD_maple_native +void initSRAMChip(void); + void boardInit(void) { - initNativeSRAM(); + initSRAMChip(); } extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { @@ -177,4 +185,15 @@ extern const uint8 boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = { BOARD_JTCK_SWCLK_PIN, BOARD_JTDI_PIN, BOARD_JTDO_PIN, BOARD_NJTRST_PIN }; +void initSRAMChip(void) { + fsmc_nor_psram_reg_map *regs = FSMC_NOR_PSRAM1_BASE; + + fsmc_sram_init_gpios(); + rcc_clk_enable(RCC_FSMC); + + regs->BCR = FSMC_BCR_WREN | FSMC_BCR_MWID_16BITS | FSMC_BCR_MBKEN; + fsmc_nor_psram_set_addset(regs, 0); + fsmc_nor_psram_set_datast(regs, 3); +} + #endif diff --git a/wirish/boards/maple_native.h b/wirish/boards/maple_native.h index 2cbd406..b573d72 100644 --- a/wirish/boards/maple_native.h +++ b/wirish/boards/maple_native.h @@ -32,11 +32,6 @@ * See maple.h for more information on these definitions. */ -#include "gpio.h" -#include "timer.h" - -#include "wirish_types.h" - #ifndef _BOARD_MAPLE_NATIVE_H_ #define _BOARD_MAPLE_NATIVE_H_ diff --git a/wirish/native_sram.cpp b/wirish/native_sram.cpp deleted file mode 100644 index 5e8095f..0000000 --- a/wirish/native_sram.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2011 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -#include "native_sram.h" -#include "libmaple.h" -#include "fsmc.h" -#include "rcc.h" - -#ifdef BOARD_maple_native - -void initNativeSRAM(void) { - fsmc_nor_psram_reg_map *regs = FSMC_NOR_PSRAM1_BASE; - - fsmc_sram_init_gpios(); - rcc_clk_enable(RCC_FSMC); - - regs->BCR = FSMC_BCR_WREN | FSMC_BCR_MWID_16BITS | FSMC_BCR_MBKEN; - fsmc_nor_psram_set_addset(regs, 0); - fsmc_nor_psram_set_datast(regs, 3); -} - -#endif diff --git a/wirish/native_sram.h b/wirish/native_sram.h deleted file mode 100644 index 7724667..0000000 --- a/wirish/native_sram.h +++ /dev/null @@ -1,43 +0,0 @@ -/****************************************************************************** - * The MIT License - * - * Copyright (c) 2011 LeafLabs, LLC. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - *****************************************************************************/ - -#ifdef BOARD_maple_native - -#ifndef _NATIVE_SRAM_H_ -#define _NATIVE_SRAM_H_ - -/** - * Sets up the FSMC peripheral to use the SRAM chip on the Maple - * Native as an external segment of system memory space. - * - * This implementation is for the IS62WV51216BLL 8Mb chip (55ns - * timing, 512K x 16 bits). - */ -void initNativeSRAM(void); - -#endif - -#endif diff --git a/wirish/rules.mk b/wirish/rules.mk index 02906c7..c3608e3 100644 --- a/wirish/rules.mk +++ b/wirish/rules.mk @@ -30,8 +30,7 @@ cppSRCS_$(d) := wirish_math.cpp \ wirish_time.cpp \ pwm.cpp \ ext_interrupts.cpp \ - wirish_digital.cpp \ - native_sram.cpp + wirish_digital.cpp cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%) cppFILES_$(d) := $(cppSRCS_$(d):%=$(d)/%) -- cgit v1.2.3 From 11a0da5c63faffd45bde43da2777a9771cfdf5e9 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Mon, 2 May 2011 14:33:05 -0400 Subject: /examples/ cleanups. --- examples/blinky.cpp | 9 ++--- examples/debug-dtrrts.cpp | 5 +-- examples/spi_master.cpp | 65 +++++++++++++++++---------------- examples/test-dac.cpp | 9 +++-- examples/test-ring-buffer-insertion.cpp | 2 +- examples/test-serial-flush.cpp | 20 +++++----- examples/test-serialusb.cpp | 31 +++++++--------- examples/test-systick.cpp | 15 +++----- examples/test-timers.cpp | 9 ++--- examples/vga-leaf.cpp | 21 ++++------- examples/vga-scope.cpp | 17 ++++----- 11 files changed, 91 insertions(+), 112 deletions(-) diff --git a/examples/blinky.cpp b/examples/blinky.cpp index 209a6e6..91d1a47 100644 --- a/examples/blinky.cpp +++ b/examples/blinky.cpp @@ -2,11 +2,8 @@ #include "wirish.h" -// Use the pin attached to the built-in LED -#define PIN BOARD_LED_PIN - void setup() { - pinMode(PIN, OUTPUT); + pinMode(BOARD_LED_PIN, OUTPUT); } int toggle = 1; @@ -14,7 +11,7 @@ int toggle = 1; void loop() { // You could just use toggleLED() instead, but this illustrates // the use of digitalWrite(): - digitalWrite(PIN, toggle); + digitalWrite(BOARD_LED_PIN, toggle); toggle ^= 1; delay(100); } @@ -28,7 +25,7 @@ __attribute__((constructor)) void premain() { int main(void) { setup(); - while (1) { + while (true) { loop(); } return 0; diff --git a/examples/debug-dtrrts.cpp b/examples/debug-dtrrts.cpp index 61c061a..3829208 100644 --- a/examples/debug-dtrrts.cpp +++ b/examples/debug-dtrrts.cpp @@ -3,12 +3,9 @@ #include "wirish.h" #include "usb.h" -#define LED_PIN BOARD_LED_PIN -#define PWM_PIN 2 - void setup() { /* Set up the LED to blink */ - pinMode(LED_PIN, OUTPUT); + pinMode(BOARD_LED_PIN, OUTPUT); /* Send a message out USART2 */ Serial2.begin(9600); diff --git a/examples/spi_master.cpp b/examples/spi_master.cpp index 06cad02..af3e709 100644 --- a/examples/spi_master.cpp +++ b/examples/spi_master.cpp @@ -1,61 +1,62 @@ -/* ***************************************************************************** +/****************************************************************************** * 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 + * 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 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. - * ****************************************************************************/ + * 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. + *****************************************************************************/ /** - * @brief Sample main.cpp file. Sends "Hello world!" out SPI1. + * @brief Sample main.cpp file. Sends "Hello world!" out SPI1. * - * SPI1 is set up to be a master transmitter at 4.5MHz, little endianness, - * and SPI mode 0. - * - * Pin 10 is used as Chip Select + * SPI1 is set up to be a master transmitter at 4.5MHz, little + * endianness, and SPI mode 0. * + * Pin 10 is used as slave select. */ #include "wirish.h" -#define CS 10 +#define NSS 10 byte buf[] = "Hello world!"; HardwareSPI spi1(1); void setup() { - /* Set up chip select as output */ - pinMode(CS, OUTPUT); + /* Set up chip select as output */ + pinMode(NSS, OUTPUT); - /* CS is usually active low, so initialize it high */ - digitalWrite(CS, HIGH); + /* NSS is usually active LOW, so initialize it HIGH */ + digitalWrite(NSS, HIGH); - /* Initialize SPI */ + /* Initialize SPI */ spi1.begin(SPI_4_5MHZ, LSBFIRST, 0); } void loop() { - /* Send message */ - digitalWrite(CS, LOW); - spi1.send(buf, sizeof buf); - digitalWrite(CS,HIGH); + /* Send message */ + digitalWrite(NSS, LOW); + spi1.write(buf, sizeof buf); + digitalWrite(NSS, HIGH); delay(1000); } @@ -68,7 +69,7 @@ __attribute__((constructor)) void premain() { int main(void) { setup(); - while (1) { + while (true) { loop(); } return 0; diff --git a/examples/test-dac.cpp b/examples/test-dac.cpp index ba766a4..40ae5d5 100644 --- a/examples/test-dac.cpp +++ b/examples/test-dac.cpp @@ -13,7 +13,7 @@ uint16 count = 0; void setup() { pinMode(BOARD_LED_PIN, OUTPUT); - digitalWrite(BOARD_LED_PIN,1); + digitalWrite(BOARD_LED_PIN, HIGH); Serial1.begin(9600); Serial1.println("**** Beginning DAC test"); @@ -36,11 +36,14 @@ void loop() { dac_write_channel(DAC, 2, count); } -int main(void) { +__attribute__((constructor)) void premain() { init(); +} + +int main(void) { setup(); - while (1) { + while (true) { loop(); } return 0; diff --git a/examples/test-ring-buffer-insertion.cpp b/examples/test-ring-buffer-insertion.cpp index 8372a96..e86372a 100644 --- a/examples/test-ring-buffer-insertion.cpp +++ b/examples/test-ring-buffer-insertion.cpp @@ -4,7 +4,7 @@ * Does a basic test of functionality on rb_full_count(), rb_reset(), * rb_push_insert(), and rb_safe_insert(). * - * To test (no external hardware required): + * To test: * * - Connect a serial monitor to SerialUSB * - Press any key diff --git a/examples/test-serial-flush.cpp b/examples/test-serial-flush.cpp index 6c4e100..adc9c3e 100644 --- a/examples/test-serial-flush.cpp +++ b/examples/test-serial-flush.cpp @@ -4,23 +4,21 @@ #include "wirish.h" -#define COMM Serial1 - void setup() { - COMM.begin(9600); - COMM.println("Hello world!"); + Serial1.begin(9600); + Serial1.println("Hello world!"); } void loop() { - COMM.println("Waiting for multiple input..."); - while (COMM.available() < 5) + Serial1.println("Waiting for multiple input..."); + while (Serial1.available() < 5) ; - COMM.println(COMM.read()); - COMM.println(COMM.read()); - COMM.flush(); + Serial1.println(Serial1.read()); + Serial1.println(Serial1.read()); + Serial1.flush(); - if (COMM.available()) { - COMM.println("FAIL! Still had junk in the buffer..."); + if (Serial1.available()) { + Serial1.println("FAIL! Still had junk in the buffer..."); } } diff --git a/examples/test-serialusb.cpp b/examples/test-serialusb.cpp index 678c2b9..15ab913 100644 --- a/examples/test-serialusb.cpp +++ b/examples/test-serialusb.cpp @@ -3,27 +3,24 @@ #include "wirish.h" #include "usb.h" -#define LED_PIN BOARD_LED_PIN -#define BUT_PIN BOARD_BUTTON_PIN - -uint32 state = 0; #define QUICKPRINT 0 #define BIGSTUFF 1 #define NUMBERS 2 #define SIMPLE 3 #define ONOFF 4 +uint32 state = 0; + void setup() { /* Set up the LED to blink */ - pinMode(LED_PIN, OUTPUT); - - /* Set up the Button */ - pinMode(BUT_PIN, INPUT); + pinMode(BOARD_LED_PIN, OUTPUT); + /* Set up Serial2 for use as a debug channel */ Serial2.begin(9600); - Serial2.println("This is the debug channel. Press BUT."); - - waitForButtonPress(0); + Serial2.println("This is the debug channel. Press any key."); + while (!Serial2.available()) + ; + Serial2.read(); } uint8 c1 = '-'; @@ -32,14 +29,15 @@ void loop() { toggleLED(); delay(1000); - if(isButtonPressed()) { + if (Serial2.available()) { + Serial2.read(); state++; } - switch(state) { + switch (state) { case QUICKPRINT: - for(int i = 0; i<30; i++) { - usbSendBytes(&c1,1); + for (int i = 0; i < 30; i++) { + usbSendBytes(&c1, 1); SerialUSB.print('.'); SerialUSB.print('|'); } @@ -121,9 +119,8 @@ __attribute__((constructor)) void premain() { int main(void) { setup(); - while (1) { + while (true) { loop(); } return 0; } - diff --git a/examples/test-systick.cpp b/examples/test-systick.cpp index bbf0adf..78c7307 100644 --- a/examples/test-systick.cpp +++ b/examples/test-systick.cpp @@ -1,16 +1,11 @@ // Tests the SysTick enable/disable functions -// + #include "wirish.h" #include "systick.h" -#define LED_PIN BOARD_LED_PIN -#define PWM_PIN 2 -#define BUT BOARD_BUTTON_PIN - void setup() { - /* Set up the LED to blink */ - pinMode(LED_PIN, OUTPUT); - pinMode(BUT, INPUT); + pinMode(BOARD_LED_PIN, OUTPUT); + pinMode(BOARD_BUTTON_PIN, INPUT); } bool disable = true; @@ -24,7 +19,7 @@ void loop() { for(i = 0; i < 150000; i++) ; - if(isButtonPressed()) { + if (isButtonPressed()) { if (disable) { systick_disable(); SerialUSB.println("Disabling SysTick"); @@ -47,7 +42,7 @@ __attribute__((constructor)) void premain() { int main(void) { setup(); - while (1) { + while (true) { loop(); } return 0; diff --git a/examples/test-timers.cpp b/examples/test-timers.cpp index a4fbc8a..545597f 100644 --- a/examples/test-timers.cpp +++ b/examples/test-timers.cpp @@ -26,7 +26,7 @@ uint16 val2 = 10000; uint16 val3 = 10000; uint16 val4 = 10000; -// FIXME high density timer test (especially basic timers + DAC) +// FIXME [0.1.0] high density timer test (especially basic timers + DAC) timer_dev *timers[] = {TIMER1, TIMER2, TIMER3, TIMER4}; voidFuncPtr handlers[] = {handler1, handler2, handler3, handler4}; @@ -46,7 +46,6 @@ void setup() { // Send a message out Serial2 Serial2.begin(115200); Serial2.println("*** Initializing timers..."); - Serial2.println("foo"); timer_foreach(initTimer); Serial2.println("*** Done. Beginning timer test."); } @@ -110,7 +109,7 @@ void loop() { testSetTimerPeriod(30000); Serial2.println("Sanity check (with hand-coded reload and prescaler for " - "72 MHz timers):"); + "72 MHz timers):"); timer_set_mode(TIMER4, TIMER_CH1, TIMER_OUTPUT_COMPARE); timer_set_prescaler(TIMER4, 33); timer_set_reload(TIMER4, 65454); @@ -238,7 +237,7 @@ void testTimerChannels(timer_dev *dev) { } } -// FIXME move this into the new wirish timer implementation +// FIXME [0.0.10] move this into the new wirish timer implementation void setTimerPeriod(timer_dev *dev, uint32 period_us) { if (!period_us) { // FIXME handle this case @@ -291,7 +290,7 @@ __attribute__((constructor)) void premain() { int main(void) { setup(); - while (1) { + while (true) { loop(); } return 0; diff --git a/examples/vga-leaf.cpp b/examples/vga-leaf.cpp index 9d9fce2..e663639 100644 --- a/examples/vga-leaf.cpp +++ b/examples/vga-leaf.cpp @@ -28,18 +28,12 @@ Created 20 July 2010 By Bryan Newbold for LeafLabs This code is released with no strings attached. - - Modified 4 March 2011 - By Marti Bolivar - Disabled SysTick, kept up-to-date with libmaple. */ // FIXME: generalize for Native and Mini #include "wirish.h" -#define LED_PIN BOARD_LED_PIN - // Pinouts -- you also must change the GPIO macros below if you change // these #define VGA_R 6 // STM32: A8 @@ -110,7 +104,7 @@ uint32 logo[y_max][x_max] = { void setup() { // Setup our pins - pinMode(LED_PIN, OUTPUT); + pinMode(BOARD_LED_PIN, OUTPUT); pinMode(VGA_R, OUTPUT); pinMode(VGA_G, OUTPUT); pinMode(VGA_B, OUTPUT); @@ -166,7 +160,6 @@ void loop() { // Everything happens in the interrupts! } - // This ISR will end horizontal sync for most of the image and // setup the vertical sync for higher line counts void isr_porch(void) { @@ -174,22 +167,22 @@ void isr_porch(void) { y++; logo_y = map(y, 0, 478, 0, y_max); // Back to the top - if(y >= 523) { + if (y >= 523) { y = 1; logo_y = 0; v_active = true; return; } // Other vsync stuff below the image - if(y >= 492) { + if (y >= 492) { VGA_V_HIGH; return; } - if(y >= 490) { + if (y >= 490) { VGA_V_LOW; return; } - if(y >= 479) { + if (y >= 479) { v_active = false; return; } @@ -207,7 +200,7 @@ void isr_start(void) { VGA_R_HIGH; // For each "pixel", go ON_COLOR or OFF_COLOR - for(x = 0; x < 16; x++) { + for (x = 0; x < 16; x++) { // setting the color several times is just an easy way to // delay, so the image is wider. if you only do the following // once, you'll be able to make the logo array a lot wider: @@ -242,7 +235,7 @@ __attribute__((constructor)) void premain() { int main(void) { setup(); - while (1) { + while (true) { loop(); } return 0; diff --git a/examples/vga-scope.cpp b/examples/vga-scope.cpp index 66e72e9..9aa8bcb 100644 --- a/examples/vga-scope.cpp +++ b/examples/vga-scope.cpp @@ -40,7 +40,6 @@ // FIXME: generalize for Native and Mini -#define LED_PIN BOARD_LED_PIN #define ANALOG_PIN 18 // Pinouts -- you also must change the GPIO macros below if you change @@ -90,9 +89,9 @@ void isr_stop(void); void isr_update(void); void setup() { - pinMode(LED_PIN, OUTPUT); + pinMode(BOARD_LED_PIN, OUTPUT); pinMode(ANALOG_PIN, INPUT_ANALOG); - digitalWrite(LED_PIN, 1); + digitalWrite(BOARD_LED_PIN, 1); pinMode(VGA_R, OUTPUT); pinMode(VGA_G, OUTPUT); pinMode(VGA_B, OUTPUT); @@ -138,26 +137,26 @@ void setup() { uint16 y = 0; uint16 val = 0; bool v_active = true; -const uint16 x_max = 60; // empirically (and lazily) determined +const uint16 x_max = 60; // empirically (and sloppily) determined void isr_porch(void) { VGA_H_HIGH; y++; val = map(analogRead(ANALOG_PIN), 0, 4095, 0, x_max); - if(y >= 523) { + if (y >= 523) { y = 1; v_active = true; return; } - if(y >= 492) { + if (y >= 492) { VGA_V_HIGH; return; } - if(y >= 490) { + if (y >= 490) { VGA_V_LOW; return; } - if(y >= 479) { + if (y >= 479) { v_active = false; return; } @@ -199,7 +198,7 @@ __attribute__((constructor)) void premain() { int main(void) { setup(); - while (1) { + while (true) { loop(); } return 0; -- cgit v1.2.3 From 9ad170c63ddac17301566e69fe6a0e7a8d0d4639 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Mon, 2 May 2011 14:35:58 -0400 Subject: Fixing USBSerial::read(void*, uint32). --- wirish/usb_serial.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wirish/usb_serial.cpp b/wirish/usb_serial.cpp index e2cdee3..e2751a2 100644 --- a/wirish/usb_serial.cpp +++ b/wirish/usb_serial.cpp @@ -103,18 +103,18 @@ uint32 USBSerial::available(void) { /* blocks forever until len_bytes is received */ uint32 USBSerial::read(void *buf, uint32 len) { - if (!buf) { + if (buf == 0) { return 0; } uint32 bytes_in = 0; while (len > 0) { - uint32 new_bytes = usbReceiveBytes((uint8*)((uint8*)buf+bytes_in), len); + uint32 new_bytes = usbReceiveBytes((uint8*)buf + bytes_in, len); len -= new_bytes; bytes_in += new_bytes; } - return len; + return bytes_in; } /* blocks forever until 1 byte is received */ -- cgit v1.2.3 From f3bcdd18d8f0b64cd8f17410b480b49315791544 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Wed, 4 May 2011 13:15:33 -0400 Subject: SerialUSB fixups. --- docs/source/lang/api/serialusb.rst | 15 +++-- libmaple/usb/usb.c | 12 ++-- libmaple/usb/usb.h | 2 +- libmaple/usb/usb_lib/usb_mem.c | 4 +- libmaple/usb/usb_lib/usb_mem.h | 2 +- wirish/Print.cpp | 2 +- wirish/Print.h | 4 +- wirish/usb_serial.cpp | 117 ++++++++++++++----------------------- wirish/usb_serial.h | 8 ++- 9 files changed, 67 insertions(+), 99 deletions(-) diff --git a/docs/source/lang/api/serialusb.rst b/docs/source/lang/api/serialusb.rst index ee7146e..ed466f2 100644 --- a/docs/source/lang/api/serialusb.rst +++ b/docs/source/lang/api/serialusb.rst @@ -16,9 +16,8 @@ Introduction In addition to three :ref:`serial ports `, the Maple's STM32 microprocessor includes a dedicated USB peripheral. This peripheral is used to emulate a regular serial port for use as a -terminal (text read/write). The emulated terminal is relatively slow -and inefficient; it is best for transferring data at regular serial -speeds (kilobaud). +terminal. The emulated terminal is relatively slow; it is best for +transferring data at regular serial speeds (kilobaud). Library access to the emulated serial port is provided through the ``SerialUSB`` object. You can mostly use ``SerialUSB`` as a drop-in @@ -30,14 +29,14 @@ replacement for ``Serial1``, ``Serial2``, and ``Serial3``. This means that if you have a number of calls to one of the ``SerialUSB`` ``write()`` or ``print()`` functions in your code, - and you are not monitoring the emulated on a computer, your program - will run much, much slower than if it is being monitored or totally - disconnected (run off of a battery). + and you are not monitoring ``SerialUSB`` on a computer, your + program will run much slower than if it is being monitored or + totally disconnected (run off of a battery). You can avoid this behavior by :ref:`deciphering the port status - using the DTR and RTS line status `; the + using the DTR and RTS line status ` (the behavior of these control lines is platform dependent and we no - longer interpret them by default. + longer interpret them by default). Library Documentation --------------------- diff --git a/libmaple/usb/usb.c b/libmaple/usb/usb.c index 7b1dd4c..b34c4b6 100644 --- a/libmaple/usb/usb.c +++ b/libmaple/usb/usb.c @@ -343,23 +343,21 @@ void usbBlockingSendByte(char ch) { countTx = 1; while (countTx); } -uint32 usbSendBytes(uint8* sendBuf, uint32 len) { - /* any checks on connection (via dtr/rts) done upstream in wirish or - by user */ - /* last xmit hasnt finished, abort */ +uint32 usbSendBytes(const uint8* sendBuf, uint32 len) { + /* Last transmission hasn't finished, abort */ if (countTx) { return 0; } // We can only put VCOM_TX_EPSIZE bytes in the buffer - if(len > VCOM_TX_EPSIZE/2) { - len = VCOM_TX_EPSIZE/2; + if (len > VCOM_TX_EPSIZE / 2) { + len = VCOM_TX_EPSIZE / 2; } // Try to load some bytes if we can if (len) { - UserToPMABufferCopy(sendBuf,VCOM_TX_ADDR, len); + UserToPMABufferCopy(sendBuf, VCOM_TX_ADDR, len); _SetEPTxCount(VCOM_TX_ENDP, len); countTx += len; _SetEPTxValid(VCOM_TX_ENDP); diff --git a/libmaple/usb/usb.h b/libmaple/usb/usb.h index 92f606c..c724c54 100644 --- a/libmaple/usb/usb.h +++ b/libmaple/usb/usb.h @@ -74,7 +74,7 @@ void usbWaitReset(void); /* blocking functions for send/receive */ void usbBlockingSendByte(char ch); -uint32 usbSendBytes(uint8* sendBuf,uint32 len); +uint32 usbSendBytes(const uint8* sendBuf,uint32 len); uint32 usbBytesAvailable(void); uint32 usbReceiveBytes(uint8* recvBuf, uint32 len); uint8 usbGetDTR(void); diff --git a/libmaple/usb/usb_lib/usb_mem.c b/libmaple/usb/usb_lib/usb_mem.c index ee698c5..90ffc62 100644 --- a/libmaple/usb/usb_lib/usb_mem.c +++ b/libmaple/usb/usb_lib/usb_mem.c @@ -30,9 +30,9 @@ * - wPMABufAddr: address into PMA. * - wNBytes: no. of bytes to be copied. * Output : None. -* Return : None . +* Return : None . *******************************************************************************/ -void UserToPMABufferCopy(u8 *pbUsrBuf, u16 wPMABufAddr, u16 wNBytes) +void UserToPMABufferCopy(const u8 *pbUsrBuf, u16 wPMABufAddr, u16 wNBytes) { u32 n = (wNBytes + 1) >> 1; /* n = (wNBytes + 1) / 2 */ u32 i, temp1, temp2; diff --git a/libmaple/usb/usb_lib/usb_mem.h b/libmaple/usb/usb_lib/usb_mem.h index a3d7927..60ff9f1 100644 --- a/libmaple/usb/usb_lib/usb_mem.h +++ b/libmaple/usb/usb_lib/usb_mem.h @@ -26,7 +26,7 @@ extern "C" { #endif -void UserToPMABufferCopy(u8 *pbUsrBuf, u16 wPMABufAddr, u16 wNBytes); +void UserToPMABufferCopy(const u8 *pbUsrBuf, u16 wPMABufAddr, u16 wNBytes); void PMAToUserBufferCopy(u8 *pbUsrBuf, u16 wPMABufAddr, u16 wNBytes); #if defined(__cplusplus) diff --git a/wirish/Print.cpp b/wirish/Print.cpp index cfb2cda..9130c9c 100644 --- a/wirish/Print.cpp +++ b/wirish/Print.cpp @@ -52,7 +52,7 @@ void Print::write(const char *str) { } } -void Print::write(void *buffer, uint32 size) { +void Print::write(const void *buffer, uint32 size) { uint8 *ch = (uint8*)buffer; while (size--) { write(*ch++); diff --git a/wirish/Print.h b/wirish/Print.h index ec7b163..73d82e7 100644 --- a/wirish/Print.h +++ b/wirish/Print.h @@ -35,9 +35,9 @@ enum { class Print { public: - virtual void write(uint8) = 0; + virtual void write(uint8 ch) = 0; virtual void write(const char *str); - virtual void write(void*, uint32); + virtual void write(const void *buf, uint32 len); void print(char); void print(const char[]); void print(uint8); diff --git a/wirish/usb_serial.cpp b/wirish/usb_serial.cpp index e2751a2..0a2be43 100644 --- a/wirish/usb_serial.cpp +++ b/wirish/usb_serial.cpp @@ -3,28 +3,29 @@ * * Copyright (c) 2010 Perry Hung. * - * 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 + * 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 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. + * 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. *****************************************************************************/ /** - * @brief Wirish USB class for easy communication, uses libmaple's - * virtual com port implementation + * @brief USB virtual serial terminal */ #include @@ -34,7 +35,7 @@ #define USB_TIMEOUT 50 -USBSerial :: USBSerial(void) { +USBSerial::USBSerial(void) { } void USBSerial::begin(void) { @@ -46,54 +47,29 @@ void USBSerial::end(void) { } void USBSerial::write(uint8 ch) { - if(!(usbIsConnected() && usbIsConfigured())) { - return; - } - - uint16 status = 0; - uint32 start = millis(); - - while(status == 0 && (millis() - start <= USB_TIMEOUT)) { - status = usbSendBytes(&ch, 1); - } + const uint8 buf[] = {ch}; + this->write(buf, 1); } void USBSerial::write(const char *str) { - if(!(usbIsConnected() && usbIsConfigured())) { - return; - } - - uint32 len = strlen(str); - uint16 status = 0; - uint16 oldstatus = 0; - uint32 start = millis(); - - while(status < len && (millis() - start < USB_TIMEOUT)) { - status += usbSendBytes((uint8*)str+status, len-status); - if(oldstatus != status) - start = millis(); - oldstatus = status; - } + this->write(str, strlen(str)); } -void USBSerial::write(void *buf, uint32 size) { - if(!(usbIsConnected() && usbIsConfigured())) { +void USBSerial::write(const void *buf, uint32 len) { + if (!(usbIsConnected() && usbIsConfigured()) || !buf) { return; } - if (!buf) { - return; - } - - uint16 status = 0; - uint16 oldstatus = 0; + uint32 txed = 0; + uint32 old_txed = 0; uint32 start = millis(); - while(status < size && (millis() - start < USB_TIMEOUT)) { - status += usbSendBytes((uint8*)buf+status, size-status); - if(oldstatus != status) + while (txed < len && (millis() - start < USB_TIMEOUT)) { + txed += usbSendBytes((const uint8*)buf + txed, len - txed); + if (old_txed != txed) { start = millis(); - oldstatus = status; + } + old_txed = txed; } } @@ -101,47 +77,40 @@ uint32 USBSerial::available(void) { return usbBytesAvailable(); } -/* blocks forever until len_bytes is received */ uint32 USBSerial::read(void *buf, uint32 len) { - if (buf == 0) { + if (!buf) { return 0; } - uint32 bytes_in = 0; - while (len > 0) { - uint32 new_bytes = usbReceiveBytes((uint8*)buf + bytes_in, len); - len -= new_bytes; - bytes_in += new_bytes; + uint32 rxed = 0; + while (rxed < len) { + rxed += usbReceiveBytes((uint8*)buf + rxed, len - rxed); } - return bytes_in; + return rxed; } -/* blocks forever until 1 byte is received */ +/* Blocks forever until 1 byte is received */ uint8 USBSerial::read(void) { - uint8 ch; - - while (usbReceiveBytes(&ch, 1) == 0); - return ch; + uint8 buf[1]; + this->read(buf, 1); + return buf[0]; } uint8 USBSerial::pending(void) { return usbGetPending(); } -// TODO deprecate the crap out of this +uint8 USBSerial::isConnected(void) { + return usbIsConnected() && usbIsConfigured(); +} + uint8 USBSerial::getDTR(void) { return usbGetDTR(); } -// TODO deprecate the crap out of this uint8 USBSerial::getRTS(void) { return usbGetRTS(); } -uint8 USBSerial::isConnected(void) { - return (usbIsConnected() && usbIsConfigured()); -} - USBSerial SerialUSB; - diff --git a/wirish/usb_serial.h b/wirish/usb_serial.h index c228837..ba9e18c 100644 --- a/wirish/usb_serial.h +++ b/wirish/usb_serial.h @@ -23,8 +23,7 @@ *****************************************************************************/ /** - * @brief wirish usb class for easy goin communication, uses libmaple's - * virtual com port implementation + * @brief Wirish virtual serial port */ #ifndef _USB_SERIAL_H_ @@ -32,6 +31,9 @@ #include "Print.h" +/** + * @brief Virtual serial terminal. + */ class USBSerial : public Print { public: USBSerial(void); @@ -46,7 +48,7 @@ public: void write(uint8); void write(const char *str); - void write(void *, uint32); + void write(const void*, uint32); uint8 getRTS(); uint8 getDTR(); -- cgit v1.2.3 From 55323faebe0abb6b8900fc7b1344d383abe08a9d Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Wed, 4 May 2011 13:20:20 -0400 Subject: systick_timer_millis is volatile, not IO-mapped. --- libmaple/systick.c | 2 +- libmaple/systick.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libmaple/systick.c b/libmaple/systick.c index 103893e..c04f4f3 100644 --- a/libmaple/systick.c +++ b/libmaple/systick.c @@ -28,7 +28,7 @@ #include "systick.h" -__io uint32 systick_timer_millis; +volatile uint32 systick_timer_millis; /** * @brief Initialize and enable SysTick. diff --git a/libmaple/systick.h b/libmaple/systick.h index 4654c5f..35b4cb9 100644 --- a/libmaple/systick.h +++ b/libmaple/systick.h @@ -73,7 +73,7 @@ typedef struct systick_reg_map { #define SYSTICK_CVR_TENMS 0xFFFFFF /** System elapsed time, in milliseconds */ -extern __io uint32 systick_timer_millis; +extern volatile uint32 systick_timer_millis; void systick_init(uint32 reload_val); void systick_disable(); -- cgit v1.2.3 From 8ea79ddf6ab35ca48415d46f8c2ab09ed493b464 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Wed, 4 May 2011 13:22:00 -0400 Subject: Making micros() counter underrun safe. Thanks, ala42! --- wirish/wirish_time.h | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/wirish/wirish_time.h b/wirish/wirish_time.h index a0b1c11..d5349e3 100644 --- a/wirish/wirish_time.h +++ b/wirish/wirish_time.h @@ -27,8 +27,8 @@ * @brief Timing and delay functions. */ -#ifndef _TIME_H -#define _TIME_H +#ifndef _TIME_H_ +#define _TIME_H_ #include "libmaple.h" #include "nvic.h" @@ -56,17 +56,15 @@ static inline uint32 micros(void) { uint32 cycle_cnt; uint32 res; - nvic_globalirq_disable(); - - cycle_cnt = systick_get_count(); - ms = millis(); - - nvic_globalirq_enable(); + do { + cycle_cnt = systick_get_count(); + ms = millis(); + } while (ms != millis()); /* SYSTICK_RELOAD_VAL is 1 less than the number of cycles it actually takes to complete a SysTick reload */ res = (ms * US_PER_MS) + - (SYSTICK_RELOAD_VAL + 1 - cycle_cnt)/CYCLES_PER_MICROSECOND; + (SYSTICK_RELOAD_VAL + 1 - cycle_cnt) / CYCLES_PER_MICROSECOND; return res; } @@ -96,4 +94,3 @@ void delay(unsigned long ms); void delayMicroseconds(uint32 us); #endif - -- cgit v1.2.3 From dde41df8c16fd92aa1b267383ae689c678e7758d Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Wed, 4 May 2011 13:36:52 -0400 Subject: Maple Mini pin map fix. Thanks, Xavier! --- wirish/boards/maple_mini.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wirish/boards/maple_mini.cpp b/wirish/boards/maple_mini.cpp index 02d62c7..3bc250b 100644 --- a/wirish/boards/maple_mini.cpp +++ b/wirish/boards/maple_mini.cpp @@ -75,7 +75,7 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { {GPIOA, NULL, NULL, 12, 0, ADCx}, /* D23/PA12 */ {GPIOA, TIMER1, NULL, 11, 4, ADCx}, /* D24/PA11 */ {GPIOA, TIMER1, NULL, 10, 3, ADCx}, /* D25/PA10 */ - {GPIOA, TIMER2, NULL, 9, 2, ADCx}, /* D26/PA9 */ + {GPIOA, TIMER1, NULL, 9, 2, ADCx}, /* D26/PA9 */ {GPIOA, TIMER1, NULL, 8, 1, ADCx}, /* D27/PA8 */ {GPIOB, NULL, NULL, 15, 0, ADCx}, /* D28/PB15 */ {GPIOB, NULL, NULL, 14, 0, ADCx}, /* D29/PB14 */ -- cgit v1.2.3 From f35c9f71385ba0629e1e3744d08da2cf442b3e9d Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Wed, 4 May 2011 17:23:54 -0400 Subject: SPI fixups. Initial post-review changes based on thread here: https://github.com/leaflabs/libmaple/commit/77f707d7b87fce284945fc9fe21c824c18c4c93d#comments --- libmaple/spi.c | 75 ++++++++++++++++++--------------------------- libmaple/spi.h | 20 +++++------- wirish/comm/HardwareSPI.cpp | 33 ++++++-------------- wirish/comm/HardwareSPI.h | 2 +- 4 files changed, 47 insertions(+), 83 deletions(-) diff --git a/libmaple/spi.c b/libmaple/spi.c index 2fbc2ac..e58ae91 100644 --- a/libmaple/spi.c +++ b/libmaple/spi.c @@ -34,6 +34,8 @@ #include "spi.h" #include "bitband.h" +static void spi_reconfigure(spi_dev *dev, uint32 cr1_config); + /* * SPI devices */ @@ -75,28 +77,9 @@ void spi_init(spi_dev *dev) { } /** - * @brief Configure GPIO bit modes for use as a SPI bus master's pins. - * @param nss_dev NSS pin's GPIO device - * @param comm_dev SCK, MISO, MOSI pins' GPIO device - * @param nss_bit NSS pin's GPIO bit on nss_dev - * @param sck_bit SCK pin's GPIO bit on comm_dev - * @param miso_bit MISO pin's GPIO bit on comm_dev - * @param mosi_bit MOSI pin's GPIO bit on comm_dev - */ -void spi_master_gpio_cfg(gpio_dev *nss_dev, - gpio_dev *comm_dev, - uint8 nss_bit, - uint8 sck_bit, - uint8 miso_bit, - uint8 mosi_bit) { - gpio_set_mode(nss_dev, nss_bit, GPIO_AF_OUTPUT_PP); - gpio_set_mode(comm_dev, sck_bit, GPIO_AF_OUTPUT_PP); - gpio_set_mode(comm_dev, miso_bit, GPIO_INPUT_FLOATING); - gpio_set_mode(comm_dev, mosi_bit, GPIO_AF_OUTPUT_PP); -} - -/** - * @brief Configure GPIO bit modes for use as a SPI bus slave's pins. + * @brief Configure GPIO bit modes for use as a SPI port's pins. + * @param as_master If true, configure bits for use as a bus master. + * Otherwise, configure bits for use as slave. * @param nss_dev NSS pin's GPIO device * @param comm_dev SCK, MISO, MOSI pins' GPIO device * @param nss_bit NSS pin's GPIO bit on nss_dev @@ -104,20 +87,26 @@ void spi_master_gpio_cfg(gpio_dev *nss_dev, * @param miso_bit MISO pin's GPIO bit on comm_dev * @param mosi_bit MOSI pin's GPIO bit on comm_dev */ -void spi_slave_gpio_cfg(gpio_dev *nss_dev, - gpio_dev *comm_dev, - uint8 nss_bit, - uint8 sck_bit, - uint8 miso_bit, - uint8 mosi_bit) { - gpio_set_mode(nss_dev, nss_bit, GPIO_INPUT_FLOATING); - gpio_set_mode(comm_dev, sck_bit, GPIO_INPUT_FLOATING); - gpio_set_mode(comm_dev, miso_bit, GPIO_AF_OUTPUT_PP); - gpio_set_mode(comm_dev, mosi_bit, GPIO_INPUT_FLOATING); +void spi_gpio_cfg(uint8 as_master, + gpio_dev *nss_dev, + uint8 nss_bit, + gpio_dev *comm_dev, + uint8 sck_bit, + uint8 miso_bit, + uint8 mosi_bit) { + if (as_master) { + gpio_set_mode(nss_dev, nss_bit, GPIO_AF_OUTPUT_PP); + gpio_set_mode(comm_dev, sck_bit, GPIO_AF_OUTPUT_PP); + gpio_set_mode(comm_dev, miso_bit, GPIO_INPUT_FLOATING); + gpio_set_mode(comm_dev, mosi_bit, GPIO_AF_OUTPUT_PP); + } else { + gpio_set_mode(nss_dev, nss_bit, GPIO_INPUT_FLOATING); + gpio_set_mode(comm_dev, sck_bit, GPIO_INPUT_FLOATING); + gpio_set_mode(comm_dev, miso_bit, GPIO_AF_OUTPUT_PP); + gpio_set_mode(comm_dev, mosi_bit, GPIO_INPUT_FLOATING); + } } -static void spi_reconfigure(spi_dev *dev, uint32 cr1_config); - /** * @brief Configure and enable a SPI device as bus master. * @@ -154,23 +143,19 @@ void spi_slave_enable(spi_dev *dev, spi_mode mode, uint32 flags) { * @brief Nonblocking SPI transmit. * @param dev SPI port to use for transmission * @param buf Buffer to transmit. The sizeof buf's elements are - * inferred from the dev's data frame format (i.e., are + * inferred from dev's data frame format (i.e., are * correctly treated as 8-bit or 16-bit quantities). * @param len Maximum number of elements to transmit. * @return Number of elements transmitted. */ uint32 spi_tx(spi_dev *dev, const void *buf, uint32 len) { - spi_reg_map *regs = dev->regs; uint32 txed = 0; - if (spi_dff(dev) == SPI_DFF_16_BIT) { - const uint8 *buf8 = (const uint8*)buf; - while ((regs->SR & SPI_SR_TXE) && (txed < len)) { - regs->DR = buf8[txed++]; - } - } else { - const uint16 *buf16 = (const uint16*)buf; - while ((regs->SR & SPI_SR_TXE) && (txed < len)) { - regs->DR = buf16[txed++]; + uint8 byte_frame = spi_dff(dev) == SPI_DFF_8_BIT; + while (spi_is_tx_empty(dev) && (txed < len)) { + if (byte_frame) { + dev->regs->DR = ((const uint8*)buf)[txed++]; + } else { + dev->regs->DR = ((const uint16*)buf)[txed++]; } } return txed; diff --git a/libmaple/spi.h b/libmaple/spi.h index e2820dd..5c8728f 100644 --- a/libmaple/spi.h +++ b/libmaple/spi.h @@ -222,19 +222,13 @@ extern spi_dev *SPI3; void spi_init(spi_dev *dev); -void spi_master_gpio_cfg(gpio_dev *nss_dev, - gpio_dev *comm_dev, - uint8 nss_bit, - uint8 sck_bit, - uint8 miso_bit, - uint8 mosi_bit); - -void spi_slave_gpio_cfg(gpio_dev *nss_dev, - gpio_dev *comm_dev, - uint8 nss_bit, - uint8 sck_bit, - uint8 miso_bit, - uint8 mosi_bit); +void spi_gpio_cfg(uint8 as_master, + gpio_dev *nss_dev, + uint8 nss_bit, + gpio_dev *comm_dev, + uint8 sck_bit, + uint8 miso_bit, + uint8 mosi_bit); /** * @brief SPI mode configuration. diff --git a/wirish/comm/HardwareSPI.cpp b/wirish/comm/HardwareSPI.cpp index 1b36d21..54b7ab3 100644 --- a/wirish/comm/HardwareSPI.cpp +++ b/wirish/comm/HardwareSPI.cpp @@ -125,11 +125,10 @@ void HardwareSPI::read(uint8 *buf, uint32 len) { } void HardwareSPI::write(uint8 byte) { - uint8 buf[] = {byte}; - this->write(buf, 1); + this->write(&byte, 1); } -void HardwareSPI::write(uint8 *data, uint32 length) { +void HardwareSPI::write(const uint8 *data, uint32 length) { uint32 txed = 0; while (txed < length) { txed += spi_tx(this->spi_d, data + txed, length - txed); @@ -152,7 +151,6 @@ uint8 HardwareSPI::send(uint8 data) { uint8 HardwareSPI::send(uint8 *buf, uint32 len) { if (len == 0) { - ASSERT(0); return 0; } uint32 txed = 0; @@ -183,11 +181,6 @@ static void enable_device(spi_dev *dev, SPIFrequency freq, spi_cfg_flag endianness, spi_mode mode) { - if (freq >= MAX_SPI_FREQS) { - ASSERT(0); - return; - } - spi_baud_rate baud = determine_baud_rate(dev, freq); uint32 cfg_flags = (endianness | SPI_DFF_8_BIT | SPI_SW_SLAVE | (as_master ? SPI_SOFT_SS : 0)); @@ -261,21 +254,13 @@ static void configure_gpios(spi_dev *dev, bool as_master) { disable_pwm(misoi); disable_pwm(mosii); - if (as_master) { - spi_master_gpio_cfg(nssi->gpio_device, - scki->gpio_device, - nssi->gpio_bit, - scki->gpio_bit, - misoi->gpio_bit, - mosii->gpio_bit); - } else { - spi_slave_gpio_cfg(nssi->gpio_device, - scki->gpio_device, - nssi->gpio_bit, - scki->gpio_bit, - misoi->gpio_bit, - mosii->gpio_bit); - } + spi_gpio_cfg(as_master, + nssi->gpio_device, + nssi->gpio_bit, + scki->gpio_device, + scki->gpio_bit, + misoi->gpio_bit, + mosii->gpio_bit); } static const spi_baud_rate baud_rates[MAX_SPI_FREQS] __FLASH__ = { diff --git a/wirish/comm/HardwareSPI.h b/wirish/comm/HardwareSPI.h index 1b2a966..3a6def5 100644 --- a/wirish/comm/HardwareSPI.h +++ b/wirish/comm/HardwareSPI.h @@ -140,7 +140,7 @@ public: * @param buffer Bytes to transmit. * @param length Number of bytes in buffer to transmit. */ - void write(uint8 *buffer, uint32 length); + void write(const uint8 *buffer, uint32 length); /** * @brief Transmit a byte, then return the next unread byte. -- cgit v1.2.3 From f76e9746041b91150bf9c8997c47178a8100f5ae Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Wed, 4 May 2011 17:24:47 -0400 Subject: examples/test-spi-roundtrip.cpp now uses SerialUSB instead of Serial2. --- examples/test-spi-roundtrip.cpp | 89 ++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 46 deletions(-) diff --git a/examples/test-spi-roundtrip.cpp b/examples/test-spi-roundtrip.cpp index 257303b..8fe97b9 100644 --- a/examples/test-spi-roundtrip.cpp +++ b/examples/test-spi-roundtrip.cpp @@ -4,7 +4,7 @@ * Bob is nowhere to be found, so Alice decides to talk to herself. * * Instructions: Connect SPI2 (Alice) to herself (i.e., MISO to MOSI). - * Connect to Alice via Serial2 at 115200 baud. Press any key to start. + * Connect to Alice via SerialUSB. Press any key to start. * * Alice will talk to herself for a little while. The sketch will * report if Alice can't hear anything she says. She'll then start @@ -37,13 +37,13 @@ const SPIFrequency spi_freqs[] = { uint8 test_buf[TEST_BUF_SIZE] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; void bad_assert(const char* file, int line, const char* exp) { - Serial2.println(); - Serial2.print("ERROR: FAILED ASSERT("); - Serial2.print(exp); - Serial2.print("): "); - Serial2.print(file); - Serial2.print(": "); - Serial2.println(line); + SerialUSB.println(); + SerialUSB.print("ERROR: FAILED ASSERT("); + SerialUSB.print(exp); + SerialUSB.print("): "); + SerialUSB.print(file); + SerialUSB.print(": "); + SerialUSB.println(line); throb(); } @@ -59,26 +59,23 @@ void soliloquies(uint32 bitOrder); void setup() { pinMode(BOARD_LED_PIN, OUTPUT); - Serial2.begin(115200); - Serial2.println(); - Serial2.print("** SPI test ready. Press any key to start."); - while (!Serial2.available()) + while (!SerialUSB.available()) ; - Serial2.read(); + SerialUSB.read(); } void loop() { - Serial2.println("** Having a conversation, MSB first"); + SerialUSB.println("** Having a conversation, MSB first"); haveConversation(MSBFIRST); - Serial2.println("** Having a conversation, LSB first"); + SerialUSB.println("** Having a conversation, LSB first"); haveConversation(LSBFIRST); - Serial2.println(); - Serial2.println("*** All done! It looks like everything worked."); - Serial2.println(); + SerialUSB.println(); + SerialUSB.println("*** All done! It looks like everything worked."); + SerialUSB.println(); - Serial2.println("** Alice will now wax eloquent in various styles. " + SerialUSB.println("** Alice will now wax eloquent in various styles. " "Press any key for the next configuration."); soliloquies(MSBFIRST); soliloquies(LSBFIRST); @@ -100,28 +97,28 @@ void haveConversation(uint32 bitOrder) { } void chat(SPIFrequency frequency, uint32 bitOrder, uint32 mode) { - Serial2.print("Having a chat.\tFrequency: "); + SerialUSB.print("Having a chat.\tFrequency: "); printFrequencyString(frequency); - Serial2.print(",\tbitOrder: "); - Serial2.print(bitOrder == MSBFIRST ? "MSB" : "LSB"); - Serial2.print(",\tmode: "); - Serial2.print(mode); - Serial2.print("."); + SerialUSB.print(",\tbitOrder: "); + SerialUSB.print(bitOrder == MSBFIRST ? "MSB" : "LSB"); + SerialUSB.print(",\tmode: "); + SerialUSB.print(mode); + SerialUSB.print("."); - Serial2.print(" [1] "); + SerialUSB.print(" [1] "); alice.begin(frequency, bitOrder, mode); - Serial2.print(" [2] "); + SerialUSB.print(" [2] "); uint32 txed = 0; while (txed < TEST_BUF_SIZE) { ASSERT(alice.transfer(test_buf[txed]) == test_buf[txed]); txed++; } - Serial2.print(" [3] "); + SerialUSB.print(" [3] "); alice.end(); - Serial2.println(" ok."); + SerialUSB.println(" ok."); } void soliloquy(SPIFrequency freq, uint32 bitOrder, uint32 mode); @@ -136,48 +133,48 @@ void soliloquies(uint32 bitOrder) { void soliloquy(SPIFrequency frequency, uint32 bitOrder, uint32 mode) { const uint8 repeat = 0xAE; - Serial2.print("Alice is giving a soliloquy (repeating 0x"); - Serial2.print(repeat, HEX); - Serial2.print("). Frequency: "); + SerialUSB.print("Alice is giving a soliloquy (repeating 0x"); + SerialUSB.print(repeat, HEX); + SerialUSB.print("). Frequency: "); printFrequencyString(frequency); - Serial2.print(", bitOrder: "); - Serial2.print(bitOrder == MSBFIRST ? "big-endian" : "little-endian"); - Serial2.print(", SPI mode: "); - Serial2.println(mode); + SerialUSB.print(", bitOrder: "); + SerialUSB.print(bitOrder == MSBFIRST ? "big-endian" : "little-endian"); + SerialUSB.print(", SPI mode: "); + SerialUSB.println(mode); alice.begin(frequency, bitOrder, mode); - while (!Serial2.available()) { + while (!SerialUSB.available()) { alice.write(repeat); delayMicroseconds(200); } - Serial2.read(); + SerialUSB.read(); } void printFrequencyString(SPIFrequency frequency) { switch (frequency) { case SPI_18MHZ: - Serial2.print("18 MHz"); + SerialUSB.print("18 MHz"); break; case SPI_9MHZ: - Serial2.print("9 MHz"); + SerialUSB.print("9 MHz"); break; case SPI_4_5MHZ: - Serial2.print("4.5 MHz"); + SerialUSB.print("4.5 MHz"); break; case SPI_2_25MHZ: - Serial2.print("2.25 MHZ"); + SerialUSB.print("2.25 MHZ"); break; case SPI_1_125MHZ: - Serial2.print("1.125 MHz"); + SerialUSB.print("1.125 MHz"); break; case SPI_562_500KHZ: - Serial2.print("562.500 KHz"); + SerialUSB.print("562.500 KHz"); break; case SPI_281_250KHZ: - Serial2.print("281.250 KHz"); + SerialUSB.print("281.250 KHz"); break; case SPI_140_625KHZ: - Serial2.print("140.625 KHz"); + SerialUSB.print("140.625 KHz"); break; } } -- cgit v1.2.3 From fc30aa62ecb544a43828cd5dceb1696518b77acf Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Thu, 5 May 2011 02:39:37 -0400 Subject: Changing integration date of function in examples/test-timer.cpp. It would be nice to have something like a timer_set_period() in libmaple proper that takes the period and the clock rate as parameters, much the same as usart_set_baud_rate() does. No time for that now, though, so punt to 0.1.0. --- examples/test-timers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/test-timers.cpp b/examples/test-timers.cpp index 545597f..247cc57 100644 --- a/examples/test-timers.cpp +++ b/examples/test-timers.cpp @@ -237,7 +237,7 @@ void testTimerChannels(timer_dev *dev) { } } -// FIXME [0.0.10] move this into the new wirish timer implementation +// FIXME [0.1.0] move some incarnation of this into timer.h void setTimerPeriod(timer_dev *dev, uint32 period_us) { if (!period_us) { // FIXME handle this case -- cgit v1.2.3 From 8fc5225a70c55be4e62b3a4eb9ce92f61e7e843f Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Thu, 5 May 2011 04:34:56 -0400 Subject: Doxygen syntax bugfixes. --- libmaple/dma.c | 4 +++- libmaple/nvic.c | 5 ++++- libmaple/spi.h | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/libmaple/dma.c b/libmaple/dma.c index 6ddabcc..04cdcea 100644 --- a/libmaple/dma.c +++ b/libmaple/dma.c @@ -187,7 +187,7 @@ void dma_attach_interrupt(dma_dev *dev, * * @param dev DMA device * @param channel Channel whose handler to detach - * @sideffect Clears interrupt enable bits in the channel's CCR register. + * @sideeffect Clears interrupt enable bits in the channel's CCR register. * @see dma_attach_interrupt() */ void dma_detach_interrupt(dma_dev *dev, dma_channel channel) { @@ -281,6 +281,7 @@ void dma_disable(dma_dev *dev, dma_channel channel) { * * @param dev DMA Device * @param channel Channel whose base memory address to set. + * @param addr Memory base address to use. */ void dma_set_mem_addr(dma_dev *dev, dma_channel channel, __io void *addr) { dma_channel_reg_map *chan_regs; @@ -303,6 +304,7 @@ void dma_set_mem_addr(dma_dev *dev, dma_channel channel, __io void *addr) { * * @param dev DMA Device * @param channel Channel whose peripheral data register base address to set. + * @param addr Peripheral memory base address to use. */ void dma_set_per_addr(dma_dev *dev, dma_channel channel, __io void *addr) { dma_channel_reg_map *chan_regs; diff --git a/libmaple/nvic.c b/libmaple/nvic.c index 28db96a..a7a6d8e 100644 --- a/libmaple/nvic.c +++ b/libmaple/nvic.c @@ -52,7 +52,10 @@ void nvic_irq_set_priority(nvic_irq_num irqn, uint8 priority) { /** * @brief Initialize the NVIC - * @param vect_table_address Vector table base address. + * @param vector_table_address Vector table base address. + * @param offset Offset from vector_table_address. Some restrictions + * apply to the use of nonzero offsets; see ST RM0008 + * and the ARM Cortex M3 Technical Reference Manual. */ void nvic_init(uint32 vector_table_address, uint32 offset) { uint32 i; diff --git a/libmaple/spi.h b/libmaple/spi.h index 5c8728f..37ca6ef 100644 --- a/libmaple/spi.h +++ b/libmaple/spi.h @@ -313,7 +313,7 @@ void spi_rx_dma_disable(spi_dev *dev); /** * @brief Determine if a SPI peripheral is enabled. - * @parm dev SPI device + * @param dev SPI device * @return True, if and only if dev's peripheral is enabled. */ static inline uint8 spi_is_enabled(spi_dev *dev) { -- cgit v1.2.3 From ef8c58b96ea8d1e503362c5d18a74cd5d0101e0c Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Thu, 5 May 2011 15:38:58 -0400 Subject: Renaming "enum ExtIntTriggerMode_" -> "enum ExtIntTriggerMode". Done for consistency the rest of the source. Doesn't affect any documented features. --- wirish/ext_interrupts.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wirish/ext_interrupts.h b/wirish/ext_interrupts.h index 364bcda..7d20801 100644 --- a/wirish/ext_interrupts.h +++ b/wirish/ext_interrupts.h @@ -38,7 +38,7 @@ * The kind of transition on an external pin which should trigger an * interrupt. */ -typedef enum ExtIntTriggerMode_ { +typedef enum ExtIntTriggerMode { RISING, /**< To trigger an interrupt when the pin transitions LOW to HIGH */ FALLING, /**< To trigger an interrupt when the pin transitions -- cgit v1.2.3 From 7904a5921a75ee4f99fb2662d7b540b56d6a7cb3 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Thu, 5 May 2011 16:17:16 -0400 Subject: Documentation link fixes. Fixing some Sphinx error messages. --- docs/source/hardware/maple.rst | 2 ++ docs/source/lang/cpp/built-in-types.rst | 31 ++++++++++++++++++------------- docs/source/libraries.rst | 2 +- docs/source/pwm.rst | 2 +- docs/source/troubleshooting.rst | 6 +++--- 5 files changed, 25 insertions(+), 18 deletions(-) diff --git a/docs/source/hardware/maple.rst b/docs/source/hardware/maple.rst index 44848a7..f4fcaf4 100644 --- a/docs/source/hardware/maple.rst +++ b/docs/source/hardware/maple.rst @@ -313,6 +313,8 @@ Rev 3 * **Pin 3 AIN missing**: Pin 3 is capable of analog input, but the corresponding "AIN" is missing from the Rev 3 silkscreen. +.. _maple-rev3-bad-buttons: + * **Bad/Sticky Buttons**: a number of Rev 3 boards sold in May-June 2010 have questionable RESET and BUT buttons. diff --git a/docs/source/lang/cpp/built-in-types.rst b/docs/source/lang/cpp/built-in-types.rst index a7349e6..28e8cdc 100644 --- a/docs/source/lang/cpp/built-in-types.rst +++ b/docs/source/lang/cpp/built-in-types.rst @@ -41,55 +41,60 @@ Integral types .. cpp:type:: int8 - Synonym for ``char``. + 8-bit integer value. Synonym for ``signed char``. .. cpp:type:: uint8 - Synonym for ``unsigned char``. + 8-bit unsigned integer value. Synonym for ``unsigned char``. + +.. cpp:type:: byte + + 8-bit unsigned integer value. Synonym for ``unsigned char``. .. cpp:type:: int16 - Synonym for ``short``. + 16-bit integer value. Synonym for ``short``. .. cpp:type:: uint16 - Synonym for ``unsigned short``. + 16-bit unsigned integer value. Synonym for ``unsigned short``. .. cpp:type:: int32 - Synonym for ``int``. + 32-bit integer value. Synonym for ``int``. .. cpp:type:: uint32 - Synonym for ``unsigned int`` + Unsigned 32-bit integer value. Synonym for ``unsigned int`` .. cpp:type:: int64 - Synonym for ``long long`` + 64-bit integer value. Synonym for ``long long`` .. cpp:type:: uint64 - Synonym for ``unsigned long long``. + Unsigned 64-bit integer value. Synonym for ``unsigned long long``. Floating-Point Types -------------------- .. cpp:type:: float - 32-bit, IEEE 754 single-precision floating-point type. + 32-bit, IEEE-754 single-precision floating-point type. .. cpp:type:: double - 64-bit, IEEE 754 double-precision floating-point type. + 64-bit, IEEE-754 double-precision floating-point type. Other Types ----------- .. cpp:type:: voidFuncPtr - Pointer to a function that takes no arguments and returns nothing, i.e. - - :: + Pointer to a function that takes no arguments and returns nothing, i.e. :: typedef void (*voidFuncPtr)(void); +.. cpp:type:: bool + + Boolean type. diff --git a/docs/source/libraries.rst b/docs/source/libraries.rst index 2bc8b11..44a72f7 100644 --- a/docs/source/libraries.rst +++ b/docs/source/libraries.rst @@ -40,7 +40,7 @@ library are noted in the library's documentation. (``malloc()``, etc.) is not available. - If you're looking for low-level hardware support libraries, see - the :ref:`libmaple Reference`. + the :ref:`libmaple Reference `. .. _libraries-servo: diff --git a/docs/source/pwm.rst b/docs/source/pwm.rst index ac67689..34ad508 100644 --- a/docs/source/pwm.rst +++ b/docs/source/pwm.rst @@ -25,7 +25,7 @@ Each PWM output is driven by an output channel connected to one of 4 timers. Some configuration, such as the clock rate or prescaling, must be common to the entire timer; see the :ref:`timer documentation ` for more information. See your board's :ref:`pin mapping -tables ` to track down the correspondence +tables ` to track down the correspondence between timer channels and GPIO pins. Background diff --git a/docs/source/troubleshooting.rst b/docs/source/troubleshooting.rst index f49580c..bf1b129 100644 --- a/docs/source/troubleshooting.rst +++ b/docs/source/troubleshooting.rst @@ -48,9 +48,9 @@ The reset and D38/serial buttons don't seem to work reliably! ------------------------------------------------------------- A few Maple Rev3 boards shipped in May-June 2010 may have had -unreliable buttons; see the :ref:`errata page ` for -details. `We're happy to replace these for you -`_\ ! +unreliable buttons; see the :ref:`Maple Errata +` for details. `We're happy to replace these +for you `_\ ! .. _troubleshooting-ide-install: -- cgit v1.2.3 From 6765e0eaf8da078195373e297acc9dff6dde7b9e Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Thu, 5 May 2011 17:18:25 -0400 Subject: Putting updated HardwareTimer back into the build. HardwareTimer was removed from the build when the timer refactor was done; this redoes it in terms of the new timer.h interface. A variety of conflicting or badly designed bits were deprecated or removed. I'm still not satisfied with this interface, as it's going to make life difficult moving forward to high-density chips, where the addition of basic timers means that the capture/compare methods won't apply in some cases. However, we need to get 0.0.10 out the door, so it'll have to do for now. The docs are up to date, and contain a warning that the Wirish API isn't stable and a recommendation to use libmaple proper. --- docs/source/lang/api/analogwrite.rst | 24 +- docs/source/lang/api/hardwaretimer.rst | 579 +++++++++++++-------------------- docs/source/timers.rst | 10 + wirish/HardwareTimer.cpp | 217 ++++-------- wirish/HardwareTimer.h | 430 ++++++++++-------------- wirish/rules.mk | 1 + wirish/wirish.h | 1 + 7 files changed, 500 insertions(+), 762 deletions(-) diff --git a/docs/source/lang/api/analogwrite.rst b/docs/source/lang/api/analogwrite.rst index e789305..dd2192a 100644 --- a/docs/source/lang/api/analogwrite.rst +++ b/docs/source/lang/api/analogwrite.rst @@ -52,7 +52,7 @@ you much more precise control over the duty cycle of your PWM output. If you're porting code from the Arduino and want a quick-and-dirty fix, one solution is to :ref:`map ` the argument to -analogWrite into the right range:: +analogWrite() into the right range:: // Arduino code: analogWrite(pin, duty); @@ -71,8 +71,8 @@ that Timer's overflow to 255. Subsequent calls to analogWrite() should work as on the Arduino (with the same loss of precision). Note, however, that that affects the overflow for the **entire timer**, so other code relying on that timer (such as any -:ref:`interrupts ` the timer controls) will -likely need to be modified as well. +:ref:`interrupts ` the timer controls) +will likely need to be modified as well. Difference 2: You must use pinMode() to set up PWM ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -141,23 +141,27 @@ the steps are: 1. Figure out which :ref:`timer ` controls PWM output on your pin (\ :ref:`your board's Timer Pin Map - ` is your friend here). Let's say it's ``Timern``\ - , where ``n`` is some number 1, 2, 3, or 4. + ` is your friend here). -2. Call ``Timern.setPeriod(2041)``\ . This will set the timer's - period to approximately 2041 microseconds, which is a frequency of - approximately 490 Hz. +2. Let's say it's timer ``n``, where ``n`` is some number. You'll + then need to put "``HardwareTimer timer(n);``" with your variables, + as described in the :ref:`HardwareTimer + ` reference. + +3. In your :ref:`lang-setup`, put "``timer.setPeriod(2041);``". This + will set the timer's period to approximately 2041 microseconds, + which is a frequency of approximately 490 Hz. Be aware that this will change the period for the **entire timer**\ , and will affect anything else in your program that depends on that timer. The important examples are :ref:`timer interrupts -` and :ref:`PWM +` and :ref:`PWM `\ . See Also -------- -- :ref:`Maple PWM tutorial ` +- :ref:`pwm` .. rubric:: Footnotes diff --git a/docs/source/lang/api/hardwaretimer.rst b/docs/source/lang/api/hardwaretimer.rst index 526beb6..09245f0 100644 --- a/docs/source/lang/api/hardwaretimer.rst +++ b/docs/source/lang/api/hardwaretimer.rst @@ -5,456 +5,341 @@ HardwareTimer ============= -This class defines the public API for interfacing with the STM32's -built-in timer peripherals. More information on these peripherals -(including code examples) is available in the :ref:`timers reference -`. +This page describes how to control the built-in timers. It does not +describe how the timers work on your board. For more information on +that, the :ref:`timers reference `. -.. FIXME [0.0.10] Updated HardwareTimer documentation, with deprecation +.. warning:: The timer interface is still taking shape, and is + expected to change significantly between releases. Because of + that, the functionality described in this page shouldn't be + considered stable. -.. warning:: This class has been deprecated. It is not available in - the current build. + If you want a timer API that will be consistent between releases of + the Maple IDE, your best bet for now is to use the low-level + support in :ref:`libmaple-timer`. -Library Documentation ---------------------- +.. contents:: Contents + :local: -HardwareTimer Class Reference -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. _lang-hardwaretimer-getting-started: -To interact with a particular timer, call one of the methods -documented below on one of the predefined ``HardwareTimer`` instances. -For example, to set the prescale factor on timer 1 to 5, call -``Timer1.setPrescaleFactor(5)``. +Getting Started +--------------- -.. TODO add tutorial-style examples +You'll first need to define a ``HardwareTimer`` variable, which you'll +use to control the timer. Do this by putting the line +"``HardwareTimer timer(number);``" with your variables, where +``number`` is the timer's number. -.. cpp:class:: HardwareTimer +Here's an example (we'll fill in :ref:`setup() ` and +:ref:`loop() ` later):: - Class for interacting with a timer. There are four predefined - instances available on the Maple: ``Timer1``, ``Timer2``, - ``Timer3``, and ``Timer4``. + // Use timer 1 + HardwareTimer timer(1); -.. _lang-hardwaretimer-attachinterrupt: + void setup() { + // Your setup code + } -.. cpp:function:: void HardwareTimer::attachInterrupt(int channel, voidFuncPtr handler) + void loop() { + // ... + } - Attach an interrupt handler to the given ``channel``. This - interrupt handler will be called when the timer's counter reaches - the given channel :ref:`compare ` - value. +Configuring the Prescaler and Overflow +-------------------------------------- - ``handler`` should be a function which takes no arguments and has - :ref:`void ` value; i.e. it should have signature :: +After defining your ``timer`` variable, you'll probably want to +configure how fast your timer's counter changes (using the prescaler) +and when it gets reset to zero (using the overflow value). You can do +that with the ``setPrescaleFactor()`` and ``setOverflow()`` functions. - void handler(void); - - You can later detach the interrupt using :ref:`detachInterrupt() - `. - - .. note:: The function (often called an *interrupt service - routine*, or ISR) should attempt to return as quickly as - possible. :ref:`Blinking the LED `, some - logic, :ref:`PWM ` updates, and :ref:`Serial - ` writes are fine; writing to - :ref:`SerialUSB ` or :ref:`waiting - ` for user input can take a long - time and prevent other interrupts from firing on time. - - Tip: if you have a :ref:`delay() ` in your - ISR, you're probably doing it wrong. - -.. cpp:function:: void HardwareTimer::attachCompare1Interrupt(voidFuncPtr handler) - - Equivalent to :ref:`attachInterrupt - `\ ``(1, handler)``. - -.. cpp:function:: void HardwareTimer::attachCompare2Interrupt(voidFuncPtr handler) - - Equivalent to :ref:`attachInterrupt - `\ ``(2, handler)``. - -.. cpp:function:: void HardwareTimer::attachCompare3Interrupt(voidFuncPtr handler) - - Equivalent to :ref:`attachInterrupt - `\ ``(3, handler)``. - -.. cpp:function:: void HardwareTimer::attachCompare4Interrupt(voidFuncPtr handler) - - Equivalent to :ref:`attachInterrupt - `\ ``(4, handler)``. - -.. _lang-hardwaretimer-setchannelmode: - -.. cpp:function:: void HardwareTimer::setChannelMode(int channel, TimerMode mode) - - Set the given channel of this timer to the given :ref:`mode - `. The parameter ``channel`` is one of - 1, 2, 3, and 4, and corresponds to the compare channel you would - like to set. Refer to your board's :ref:`master pin map - ` to match up timer channels and pin numbers. - -.. cpp:function:: void HardwareTimer::setChannel1Mode(TimerMode mode) - - Equivalent to :ref:`setChannelMode `\ - ``(1, mode)``. - -.. cpp:function:: void HardwareTimer::setChannel2Mode(TimerMode mode) - - Equivalent to :ref:`setChannelMode `\ - ``(2, mode)``. - -.. cpp:function:: void HardwareTimer::setChannel3Mode(TimerMode mode) - - Equivalent to :ref:`setChannelMode `\ - ``(3, mode)``. - -.. cpp:function:: void HardwareTimer::setChannel4Mode(TimerMode mode) - - Equivalent to :ref:`setChannelMode `\ - ``(4, mode)``. - -.. _lang-hardwaretimer-getcompare: - -.. cpp:function:: uint16 HardwareTimer::getCompare(int channel) - - Gets the compare value for the given ``channel``, from 1 to 4. See - :ref:`setCompare() `. - -.. cpp:function:: uint16 HardwareTimer::getCompare1() - - Equivalent to :ref:`getCompare `\ - ``(1, mode)``. - -.. cpp:function:: uint16 HardwareTimer::getCompare2() - - Equivalent to :ref:`getCompare `\ - ``(2, mode)``. - -.. cpp:function:: uint16 HardwareTimer::getCompare3() - - Equivalent to :ref:`getCompare `\ - ``(3, mode)``. - -.. cpp:function:: uint16 HardwareTimer::getCompare4() +.. _lang-hardwaretimer-setprescalefactor: - Equivalent to :ref:`getCompare `\ - ``(4, mode)``. +.. doxygenfunction:: HardwareTimer::setPrescaleFactor + :no-link: -.. _lang-hardwaretimer-setcompare: +.. _lang-hardwaretimer-setoverflow: -.. cpp:function:: void HardwareTimer::setCompare(int channel, uint16 compare) +.. doxygenfunction:: HardwareTimer::setOverflow + :no-link: - Sets the compare value for the given ``channel`` to ``compare``. - If ``compare`` is greater than this timer's overflow value, it will - be truncated to the overflow value. The default compare value is - 65,535 (the largest unsigned 16-bit integer value). +For example:: - When the counter reaches this value the interrupt for this channel - will fire if the given ``channel`` :ref:`mode - ` is ``TIMER_OUTPUTCOMPARE`` and - an interrupt is :ref:`attached - `. + // Use timer 1 + HardwareTimer timer(1); - By default, this only changes the relative offsets between events - on a single timer ("phase"); they don't control the frequency with - which they occur. However, a common trick is to increment the - compare value manually in the interrupt handler so that the event - will fire again after the increment period. There can be a - different increment value for each channel, so this trick allows - events to be programmed at 4 different rates on a single - timer. Note that function call overheads mean that the smallest - increment rate is at least a few microseconds. + void setup() { + timer.setPrescaleFactor(5); + timer.setOverflow(255); + } -.. cpp:function:: void HardwareTimer::setCompare1(uint16 compare) + void loop() { + // ... + } - Equivalent to :ref:`setCompare `\ - ``(1, compare)``. +You may also find the ``setPeriod()`` function useful: -.. cpp:function:: void HardwareTimer::setCompare2(uint16 compare) +.. _lang-hardwaretimer-setperiod: - Equivalent to :ref:`setCompare `\ - ``(2, compare)``. +.. doxygenfunction:: HardwareTimer::setPeriod + :no-link: -.. cpp:function:: void HardwareTimer::setCompare3(uint16 compare) +For example:: - Equivalent to :ref:`setCompare `\ - ``(3, compare)``. + // Use timer 1 + HardwareTimer timer(1); -.. cpp:function:: void HardwareTimer::setCompare4(uint16 compare) + void setup() { + // Have the timer repeat every 20 milliseconds + int microseconds_per_millisecond = 1000; + timer.setPeriod(20 * microseconds_per_millisecond); + } - Equivalent to :ref:`setCompare `\ - ``(4, compare)``. + void loop() { + // ... + } -.. cpp:function:: uint16 HardwareTimer::getCount() +.. _lang-hardwaretimer-interrupts: - Gets the current timer count. Due to function call overhead, the - return value will be increasingly accurate with smaller prescale - values. Also see :ref:`setCount() `. +Using Timer Interrupts +---------------------- -.. _lang-hardwaretimer-setcount: +.. TODO [0.2.0] Improve the interrupts section, here or in timers.rst -.. cpp:function:: void HardwareTimer::setCount(uint16 val) +In order to use timer interrupts, we recommend the following sequence: - Set the timer's current count to ``val``. +* Pause the timer. +* Configure the prescaler and overflow. +* Pick a timer channel to handle the interrupt and set the channel's + :ref:`mode ` to ``TIMER_OUTPUT_COMPARE``. +* Set the channel compare value appropriately (this controls what counter value, + from 0 to overflow - 1). If you just want to make the interrupt fire once + every time the timer overflows, and you don't care what the timer count is, + the channel compare value can just be 1. +* Attach an interrupt handler to the channel. +* Refresh the timer. +* Resume the timer. - Note that there is some function call overhead associated with - calling this method, so using it is not a robust way to get - multiple timers to share a count value. +Here are two complete examples. - If ``val`` exceeds the timer's :ref:`overflow value - `, it is truncated to the overflow - value. +**LED blink**: This example blinks the built-in LED without doing +anything in ``loop()``. :: + #define LED_RATE 500000 // in microseconds; should give 0.5Hz toggles -.. _lang-hardwaretimer-detachinterrupt: - -.. cpp:function:: void HardwareTimer::detachInterrupt(int channel) + // We'll use timer 2 + HardwareTimer timer(2); - Remove the interrupt handler attached to the given ``channel``, if - any. The handler will no longer be called by this timer. + void setup() { + // Set up the LED to blink + pinMode(BOARD_LED_PIN, OUTPUT); -.. cpp:function:: void HardwareTimer::detachCompare1Interrupt() + // Pause the timer while we're configuring it + timer.pause(); - Equivalent to :ref:`detachInterrupt - `\ ``(1)``. + // Set up period + timer.setPeriod(LED_RATE); // in microseconds -.. cpp:function:: void HardwareTimer::detachCompare2Interrupt() + // Set up an interrupt on channel 1 + timer.setChannel1Mode(TIMER_OUTPUT_COMPARE); + timer.setCompare(TIMER_CH1, 1); // Interrupt 1 count after each update + timer.attachCompare1Interrupt(handler_led); - Equivalent to :ref:`detachInterrupt - `\ ``(2)``. + // Refresh the timer's count, prescale, and overflow + timer.refresh(); -.. cpp:function:: void HardwareTimer::detachCompare3Interrupt() + // Start the timer counting + timer.resume(); + } - Equivalent to :ref:`detachInterrupt - `\ ``(3)``. + void loop() { + // Nothing! It's all in the handler_led() interrupt: + } -.. cpp:function:: void HardwareTimer::detachCompare4Interrupt() + void handler_led(void) { + toggleLED(); + } - Equivalent to :ref:`detachInterrupt - `\ ``(4)``. +**Racing Counters**: This example shows how to use multiple timers at +the same time. :: -.. _lang-hardwaretimer-generateupdate: + int count3 = 0; + int count4 = 0; -.. cpp:function:: void HardwareTimer::generateUpdate() + // We'll use timers 3 and 4 + HardwareTimer timer3(3); + HardwareTimer timer4(4); - Re-initializes the counter (to 0 in upcounting mode, which is the - default), and generates an update of the prescale and overflow - registers. + void setup() { + // Set up the button for input + pinMode(BOARD_BUTTON_PIN, INPUT_PULLUP); -.. _lang-hardwaretimer-getoverflow: + // Set up timers to add 1 to their counts each time + // their interrupts fire. + timer3.setMode(TIMER_CH1, TIMER_OUTPUT_COMPARE); + timer4.setMode(TIMER_CH1, TIMER_OUTPUT_COMPARE); + timer3.pause(); + timer4.pause(); + timer3.setCount(0); + timer4.setCount(0); + timer3.setOverflow(30000); + timer4.setOverflow(30000); + timer3.setCompare(TIMER_CH1, 1000); // somewhere in the middle + timer4.setCompare(TIMER_CH1, 1000); + timer3.attachCompare1Interrupt(handler3); + timer4.attachCompare1Interrupt(handler4); + timer3.refresh(); + timer4.refresh(); + timer3.resume(); + timer4.resume(); + } -.. cpp:function:: uint16 HardwareTimer::getOverflow() + void loop() { + // Display the running counts + SerialUSB.print("Count 3: "); + SerialUSB.print(count3); + SerialUSB.print("\t\tCount 4: "); + SerialUSB.println(count4); + + // While the button is held down, pause timer 4 + for (int i = 0; i < 1000; i++) { + if (digitalRead(BOARD_BUTTON_PIN)) { + timer4.pause(); + } else { + timer4.resume(); + } + delay(1); + } + } - Gets the timer's overflow value. See :ref:`setOverflow() - `. + void handler3(void) { + count3++; + } -.. _lang-hardwaretimer-setoverflow: + void handler4(void) { + count4++; + } -.. cpp:function:: void HardwareTimer::setOverflow(uint16 val) +``HardwareTimer`` Class Reference +--------------------------------- - Sets the timer overflow (or "reload") value to ``val``. +This section gives a full listing of the capabilities of a +``HardwareTimer``. - When the timer's counter reaches this, value it resets to - zero. Its default value is 65535 (the largest unsigned 16-bit - integer); setting the overflow to anything lower will cause - interrupts to be called more frequently (see :ref:`setPeriod() - ` function for a shortcut). +.. doxygenclass:: HardwareTimer + :members: HardwareTimer, pause, resume, getPrescaleFactor, setPrescaleFactor, getOverflow, setOverflow, getCount, setCount, setPeriod, setMode, getCompare, setCompare, attachInterrupt, detachInterrupt, refresh - After the next :ref:`timer update - `, this number will be the - maximum value for the timer's channel compare values. +.. _lang-hardwaretimer-timermode: -.. _lang-hardwaretimer-pause: +.. doxygenenum:: timer_mode -.. cpp:function:: void HardwareTimer::pause() +Deprecated Functionality +------------------------ - Stop the timer's counter, without affecting its configuration. +The following functionality exists for now, but it has been +deprecated, and will be removed in a future Maple IDE release. You +shouldn't use it in new programs, and you should change any of your +programs which do use them to use the up-to-date features described +above. - The timer will no longer count or fire interrupts after this - function is called, until it is resumed. This function is useful - during timer setup periods, in order to prevent interrupts from - firing before the timer is fully configured. +The ``TimerMode`` type from previous releases has been renamed +``timer_mode``. The mode ``TIMER_OUTPUTCOMPARE`` is still present, +but will be removed in a future release. Use ``TIMER_OUTPUT_COMPARE`` +instead. - Note that there is some function call overhead associated with this - method, so using it in concert with :ref:`resume() - ` is not a robust way to align multiple - timers to the same count value. +.. cpp:function:: void HardwareTimer::attachCompare1Interrupt(voidFuncPtr handler) -.. _lang-hardwaretimer-setperiod: + Use ``attachInterrupt(1, handler)`` instead. -.. cpp:function:: uint16 HardwareTimer::setPeriod(uint32 microseconds) +.. cpp:function:: void HardwareTimer::attachCompare2Interrupt(voidFuncPtr handler) - Configure the :ref:`prescaler - ` and :ref:`overflow - ` values to generate a timer reload - with a period as close to the given number of ``microseconds`` as - possible. + Use ``attachInterrupt(2, handler)`` instead. - The return value is the new overflow value, which may be used to - set channel compare values. However, if a clock that fires an - interrupt every given number of microseconds is all that is - desired, and the relative "phases" are unimportant, channel compare - values may all be set to 1. +.. cpp:function:: void HardwareTimer::attachCompare3Interrupt(voidFuncPtr handler) -.. _lang-hardwaretimer-getprescalefactor: + Use ``attachInterrupt(3, handler)`` instead. -.. cpp:function:: uint16 HardwareTimer::getPrescaleFactor() +.. cpp:function:: void HardwareTimer::attachCompare4Interrupt(voidFuncPtr handler) - Returns the timer's prescale factor. See - :ref:`setPrescaleFactor() `. + Use ``attachInterrupt(4, handler)`` instead. -.. _lang-hardwaretimer-setprescalefactor: +.. _lang-hardwaretimer-setchannelmode: -.. cpp:function:: void HardwareTimer::setPrescaleFactor(uint16 factor) +.. cpp:function:: void HardwareTimer::setChannelMode(int channel, timer_mode mode) - Set the timer's prescale factor to ``factor``. + Use ``setMode(channel, mode)`` instead. - The prescaler acts as a clock divider to slow down the rate at - which the counter increments. +.. cpp:function:: void HardwareTimer::setChannel1Mode(timer_mode mode) - For example, the system clock rate is 72MHz, so the counter will - reach 65535 in (13.89 nanoseconds) × (65535 counts) = (910.22 - microseconds), or about a thousand times a second. If the - prescaler equals 1098, then the clock rate is effectively 72MHz / - 1098 = 65.56KHz, and the counter will reach 65536 in (15.25 - microseconds) × (65536 counts) = (0.999 seconds), or about once - per second. + Use ``setMode(1, mode)`` instead. - The :ref:`setPeriod() ` method may - also be used as a convenient alternative. +.. cpp:function:: void HardwareTimer::setChannel2Mode(timer_mode mode) -.. _lang-hardwaretimer-resume: + Use ``setMode(2, mode)`` instead. -.. cpp:function:: void HardwareTimer::resume() +.. cpp:function:: void HardwareTimer::setChannel3Mode(timer_mode mode) - Resume a paused timer, without affecting its configuration. + Use ``setMode(3, mode)`` instead. - The timer will resume counting and firing interrupts as - appropriate. +.. cpp:function:: void HardwareTimer::setChannel4Mode(timer_mode mode) - Note that there is some function call overhead associated with - using this method, so using it in concert with :ref:`pause() - ` is not a robust way to align multiple - timers to the same count value. + Use ``setMode(4, mode)`` instead. -.. cpp:function:: timer_dev_num HardwareTimer::getTimerNum() +.. cpp:function:: uint16 HardwareTimer::getCompare1() - Returns the :ref:`timer device number - ` associated with the timer. For - example, ``Timer1.getTimerNum()`` would return ``TIMER1``. + Use ``getCompare(1, mode)`` instead. - In most cases, you should not need to use this function. If you do - use it, be careful; the constant ``TIMER1`` is *not equal* to the - number 1; similarly, ``TIMER2`` is *not* the number 2, etc. Be - sure to refer to the timer device number by name. +.. cpp:function:: uint16 HardwareTimer::getCompare2() -.. _lang-hardwaretimer-modes: + Use ``getCompare(2, mode)`` instead. -Timer Modes -^^^^^^^^^^^ -.. doxygenenum:: TimerMode +.. cpp:function:: uint16 HardwareTimer::getCompare3() -.. _lang-hardwaretimer-timer-dev-num: + Use ``getCompare(3, mode)`` instead. -Timer Device Numbers -^^^^^^^^^^^^^^^^^^^^ +.. cpp:function:: uint16 HardwareTimer::getCompare4() -These provide a lower-level interface for interacting with timers. -They are mostly useful in context with the :ref:`getTimer() -` function. **Be careful** when using -these not to confuse e.g. ``TIMER1`` with the number 1; they are -different. + Use ``getCompare(4, mode)`` instead. -.. doxygenenum:: timer_dev_num +.. cpp:function:: void HardwareTimer::setCompare1(uint16 compare) -.. _lang-hardwaretimer-convenience: + Use ``setCompare(1, compare)`` instead. -.. _lang-hardwaretimer-gettimer: +.. cpp:function:: void HardwareTimer::setCompare2(uint16 compare) -Other Functions -^^^^^^^^^^^^^^^ -.. doxygenfunction:: getTimer + Use ``setCompare(2, compare)`` instead. -Examples -^^^^^^^^ +.. cpp:function:: void HardwareTimer::setCompare3(uint16 compare) -**LED blink**:: + Use ``setCompare(3, compare)`` instead. - #define LED_RATE 500000 // in microseconds; should give 0.5Hz toggles +.. cpp:function:: void HardwareTimer::setCompare4(uint16 compare) - void handler_led(void); + Use ``setCompare(4, compare)`` instead. - void setup() - { - // Set up the LED to blink - pinMode(BOARD_LED_PIN, OUTPUT); +.. cpp:function:: void HardwareTimer::detachCompare1Interrupt() - // Setup Timer - Timer2.setChannel1Mode(TIMER_OUTPUTCOMPARE); - Timer2.setPeriod(LED_RATE); // in microseconds - Timer2.setCompare1(1); // overflow might be small - Timer2.attachCompare1Interrupt(handler_led); - } + Use ``detachInterrupt(1)`` instead. - void loop() { - // Nothing! It's all in the interrupts - } +.. cpp:function:: void HardwareTimer::detachCompare2Interrupt() - void handler_led(void) { - toggleLED(); - } + Use ``detachInterrupt(2)`` instead. -**Racing Counters**:: +.. cpp:function:: void HardwareTimer::detachCompare3Interrupt() - void handler_count1(void); - void handler_count2(void); + Use ``detachInterrupt(3)`` instead. - int count1 = 0; - int count2 = 0; +.. cpp:function:: void HardwareTimer::detachCompare4Interrupt() - void setup() - { - // Set up BUT for input - pinMode(BOARD_BUTTON_PIN, INPUT_PULLUP); + Use ``detachInterrupt(4)`` instead. - // Setup Counting Timers - Timer3.setChannel1Mode(TIMER_OUTPUTCOMPARE); - Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE); - Timer3.pause(); - Timer4.pause(); - Timer3.setCount(0); - Timer4.setCount(0); - Timer3.setOverflow(30000); - Timer4.setOverflow(30000); - Timer3.setCompare1(1000); // somewhere in the middle - Timer4.setCompare1(1000); - Timer3.attachCompare1Interrupt(handler1); - Timer4.attachCompare1Interrupt(handler2); - Timer3.resume(); - Timer4.resume(); - } +.. cpp:function:: void HardwareTimer::generateUpdate() - void loop() { - // Display the running counts - SerialUSB.print("Count 1: "); - SerialUSB.print(count1); - SerialUSB.print("\t\tCount 2: "); - SerialUSB.println(count2); - - // Run... while BUT is held, pause Count2 - for(int i = 0; i<1000; i++) { - if(digitalRead(BOARD_BUTTON_PIN)) { - Timer4.pause(); - } else { - Timer4.resume(); - } - delay(1); - } - } + Use ``refresh()`` instead. - void handler1(void) { - count1++; - } - void handler2(void) { - count2++; - } +In previous releases, to interact with a particular timers, you would +use one of the predefined ``HardwareTimer`` instances ``Timer1``, +``Timer2``, ``Timer3``, and ``Timer4``. These are still available for +now, but they are also deprecated, and will be removed in a future +release. As detailed in :ref:`lang-hardwaretimer-getting-started`, +you should define your own ``HardwareTimer`` variables. diff --git a/docs/source/timers.rst b/docs/source/timers.rst index cb30081..9163e69 100644 --- a/docs/source/timers.rst +++ b/docs/source/timers.rst @@ -45,6 +45,16 @@ event" interrupt is generated. You can configure the Maple to notify you when this takes place, by registering an interrupt handler, which is a function that will be called when the update event occurs. +By default, different compare values only change the relative offsets +between events on a single timer ("phase"). They don't control the +frequency with which they occur. However, a common trick is to +increment the compare value manually in the interrupt handler so that +the event will fire again after the increment period. There can be a +different increment value for each channel, so this trick allows +events to be programmed at 4 different rates on a single timer. Note +that function call overheads mean that the smallest increment rate is +at least a few microseconds. + Function Reference ------------------ diff --git a/wirish/HardwareTimer.cpp b/wirish/HardwareTimer.cpp index 04d1c76..d0e32c3 100644 --- a/wirish/HardwareTimer.cpp +++ b/wirish/HardwareTimer.cpp @@ -22,204 +22,125 @@ * THE SOFTWARE. *****************************************************************************/ -/* - * wirish timer class to manage the four 16-bit timer peripherals - */ - -#include "wirish.h" #include "HardwareTimer.h" +#include "boards.h" // for CYCLES_PER_MICROSECOND +#include "wirish_math.h" -HardwareTimer::HardwareTimer(timer_dev_num timerNum) { - ASSERT(timerNum != TIMER_INVALID); +// TODO [0.1.0] Remove deprecated pieces - this->timerNum = timerNum; -} +#ifdef STM32_MEDIUM_DENSITY +#define NR_TIMERS 4 +#elif defined(STM32_HIGH_DENSITY) +#define NR_TIMERS 8 +#else +#error "Unsupported density" +#endif -void HardwareTimer::resume(void) { - timer_resume(this->timerNum); +#define MAX_RELOAD ((1 << 16) - 1) + +HardwareTimer::HardwareTimer(uint8 timerNum) { + if (timerNum > NR_TIMERS) { + ASSERT(0); + } + timer_dev *devs[] = { + TIMER1, + TIMER2, + TIMER3, + TIMER4, +#ifdef STM32_HIGH_DENSITY + TIMER5, + TIMER6, + TIMER7, + TIMER8, +#endif + }; + this->dev = devs[timerNum - 1]; } void HardwareTimer::pause(void) { - timer_pause(this->timerNum); + timer_pause(this->dev); } -uint16 HardwareTimer::getPrescaleFactor(void) { - return timer_get_prescaler(this->timerNum) + 1; +void HardwareTimer::resume(void) { + timer_resume(this->dev); +} + +uint32 HardwareTimer::getPrescaleFactor(void) { + return timer_get_prescaler(this->dev) + 1; } -void HardwareTimer::setPrescaleFactor(uint16 factor) { - // The prescaler register is zero-indexed - timer_set_prescaler(this->timerNum, factor-1); +void HardwareTimer::setPrescaleFactor(uint32 factor) { + timer_set_prescaler(this->dev, (uint16)(factor - 1)); } uint16 HardwareTimer::getOverflow() { - return timer_get_reload(this->timerNum); + return timer_get_reload(this->dev); } void HardwareTimer::setOverflow(uint16 val) { - timer_set_reload(this->timerNum, val); + timer_set_reload(this->dev, val); } uint16 HardwareTimer::getCount(void) { - return timer_get_count(this->timerNum); + return timer_get_count(this->dev); } void HardwareTimer::setCount(uint16 val) { uint16 ovf = this->getOverflow(); - timer_set_count(this->timerNum, min(val, ovf)); + timer_set_count(this->dev, min(val, ovf)); } +// FIXME [0.0.10 beta] test! uint16 HardwareTimer::setPeriod(uint32 microseconds) { // Not the best way to handle this edge case? - if(!microseconds) { - setPrescaleFactor(1); - setOverflow(1); + if (!microseconds) { + this->setPrescaleFactor(1); + this->setOverflow(1); return this->getOverflow(); } - uint32 cycles = microseconds * CYCLES_PER_MICROSECOND; - - // With a prescale factor of 1, there are CYCLES_PER_MICROSECOND - // counts/ms - uint16 ps = (uint16)((cycles >> 16) + 1); - setPrescaleFactor(ps); - - // Finally, this overflow will always be less than 65536 - setOverflow((cycles/ps) - 1); - - return this->getOverflow(); -} -void HardwareTimer::setChannelMode(int channel, TimerMode mode) { - timer_set_mode(this->timerNum, channel, mode); + uint32 period_cyc = microseconds * CYCLES_PER_MICROSECOND; + uint16 prescaler = (uint16)(period_cyc / MAX_RELOAD); + uint16 overflow = (uint16)round(period_cyc / prescaler); + this->setPrescaleFactor(prescaler); + this->setOverflow(overflow); + return overflow; } -void HardwareTimer::setChannel1Mode(TimerMode mode) { - this->setChannelMode(1, mode); -} - -void HardwareTimer::setChannel2Mode(TimerMode mode) { - this->setChannelMode(2, mode); -} - -void HardwareTimer::setChannel3Mode(TimerMode mode) { - this->setChannelMode(3, mode); -} - -void HardwareTimer::setChannel4Mode(TimerMode mode) { - this->setChannelMode(4, mode); +void HardwareTimer::setMode(int channel, timer_mode mode) { + timer_set_mode(this->dev, (uint8)channel, (timer_mode)mode); } uint16 HardwareTimer::getCompare(int channel) { - return timer_get_compare_value(this->timerNum, channel); -} - -uint16 HardwareTimer::getCompare1() { - return this->getCompare(1); -} - -uint16 HardwareTimer::getCompare2() { - return this->getCompare(2); -} - -uint16 HardwareTimer::getCompare3() { - return this->getCompare(3); -} - -uint16 HardwareTimer::getCompare4() { - return this->getCompare(4); + return timer_get_compare(this->dev, (uint8)channel); } void HardwareTimer::setCompare(int channel, uint16 val) { uint16 ovf = this->getOverflow(); - timer_set_compare_value(this->timerNum, channel, min(val, ovf)); -} - -void HardwareTimer::setCompare1(uint16 val) { - this->setCompare(1, val); -} - -void HardwareTimer::setCompare2(uint16 val) { - this->setCompare(2, val); -} - -void HardwareTimer::setCompare3(uint16 val) { - this->setCompare(3, val); -} - -void HardwareTimer::setCompare4(uint16 val) { - this->setCompare(4, val); + timer_set_compare(this->dev, (uint8)channel, min(val, ovf)); } void HardwareTimer::attachInterrupt(int channel, voidFuncPtr handler) { - timer_attach_interrupt(this->timerNum, channel, handler); -} - -void HardwareTimer::attachCompare1Interrupt(voidFuncPtr handler) { - this->attachInterrupt(1, handler); -} - -void HardwareTimer::attachCompare2Interrupt(voidFuncPtr handler) { - this->attachInterrupt(2, handler); -} - -void HardwareTimer::attachCompare3Interrupt(voidFuncPtr handler) { - this->attachInterrupt(3, handler); -} - -void HardwareTimer::attachCompare4Interrupt(voidFuncPtr handler) { - this->attachInterrupt(4, handler); + timer_attach_interrupt(this->dev, (uint8)channel, handler); } void HardwareTimer::detachInterrupt(int channel) { - timer_detach_interrupt(this->timerNum, channel); -} - -void HardwareTimer::detachCompare1Interrupt(void) { - this->detachInterrupt(1); -} - -void HardwareTimer::detachCompare2Interrupt(void) { - this->detachInterrupt(2); -} - -void HardwareTimer::detachCompare3Interrupt(void) { - this->detachInterrupt(3); + timer_detach_interrupt(this->dev, (uint8)channel); } -void HardwareTimer::detachCompare4Interrupt(void) { - this->detachInterrupt(4); +void HardwareTimer::refresh(void) { + timer_generate_update(this->dev); } -void HardwareTimer::generateUpdate(void) { - timer_generate_update(this->timerNum); -} +/* -- Deprecated predefined instances -------------------------------------- */ -HardwareTimer Timer1(TIMER1); -HardwareTimer Timer2(TIMER2); -HardwareTimer Timer3(TIMER3); -HardwareTimer Timer4(TIMER4); +HardwareTimer Timer1(1); +HardwareTimer Timer2(2); +HardwareTimer Timer3(3); +HardwareTimer Timer4(4); #ifdef STM32_HIGH_DENSITY -HardwareTimer Timer5(TIMER5); // High-density devices only -HardwareTimer Timer8(TIMER8); // High-density devices only +HardwareTimer Timer5(5); +HardwareTimer Timer6(6); +HardwareTimer Timer7(7); +HardwareTimer Timer8(8); #endif - -HardwareTimer* getTimer(timer_dev_num timerNum) { - switch (timerNum) { - case TIMER1: - return &Timer1; - case TIMER2: - return &Timer2; - case TIMER3: - return &Timer3; - case TIMER4: - return &Timer4; -#ifdef STM32_HIGH_DENSITY - case TIMER5: - return &Timer5; - case TIMER8: - return &Timer8; -#endif - default: - return 0; - } -} diff --git a/wirish/HardwareTimer.h b/wirish/HardwareTimer.h index 4030adc..fd8ca9a 100644 --- a/wirish/HardwareTimer.h +++ b/wirish/HardwareTimer.h @@ -23,66 +23,45 @@ *****************************************************************************/ /** - * @brief wirish timer class to manage the four 16-bit timer peripherals + * @brief Wirish timer class. */ #ifndef _HARDWARETIMER_H_ #define _HARDWARETIMER_H_ -#include "timers.h" +// TODO [0.1.0] Remove deprecated pieces, pick a better API + +#include "timer.h" + +/** Timer mode. */ +typedef timer_mode TimerMode; + +/** @brief Deprecated; use TIMER_OUTPUT_COMPARE instead. */ +#define TIMER_OUTPUTCOMPARE TIMER_OUTPUT_COMPARE /** - * Interface to one of the 16-bit timer peripherals. - * - * User code should not instantiate this class directly; instead, use - * one of the predefined Timer instances (Timer1, Timer2, etc.). - * - * HardwareTimer instances can be configured to generate periodic or - * delayed events with minimal work done by the microcontroller. Each - * timer maintains a single 16-bit count that can be configured with a - * prescaler and overflow value. - * - * By default, a timer's counter is incremented once per clock cycle. - * The prescaler acts as a divider of the 72MHz Maple system clock; - * without prescaling, the timer's count would reach 65535 (2**16-1) - * and roll over over 1000 times per second. - * - * The overflow value is the maximum value the counter will reach. It - * defaults to 65535; smaller values will cause the counter to reset - * more frequently. + * @brief Interface to one of the 16-bit timer peripherals. */ class HardwareTimer { - private: - timer_dev_num timerNum; - - public: - HardwareTimer(timer_dev_num timer_num); +private: + timer_dev *dev; +public: /** - * Return this timer's device number. For example, - * Timer1.getTimerNum() == TIMER1 + * @brief Construct a new HardwareTimer instance. + * @param timerNum number of the timer to control. */ - timer_dev_num getTimerNum() { return timerNum; } + HardwareTimer(uint8 timerNum); /** - * Stop the counter, without affecting its configuration. - * - * The timer will no longer count or fire interrupts after this - * function is called, until it is resumed. This function is - * useful during timer setup periods, in order to prevent - * interrupts from firing before the timer is fully configured. - * - * Note that there is some function call overhead associated with - * this method, so using it in concert with - * HardwareTimer::resume() is not a robust way to align multiple - * timers to the same count value. + * @brief Stop the counter, without affecting its configuration. * * @see HardwareTimer::resume() */ void pause(void); /** - * Resume a paused timer, without affecting its configuration. + * @brief Resume a paused timer, without affecting its configuration. * * The timer will resume counting and firing interrupts as * appropriate. @@ -97,66 +76,51 @@ class HardwareTimer { void resume(void); /** - * Returns the timer's prescale factor. + * @brief Get the timer's prescale factor. + * @return Timer prescaler, from 1 to 65,536. * @see HardwareTimer::setPrescaleFactor() */ - uint16 getPrescaleFactor(); + uint32 getPrescaleFactor(); /** - * Set the timer's prescale factor. + * @brief Set the timer's prescale factor. * - * The prescaler acts as a clock divider to slow down the rate at - * which the counter increments. + * The new value won't take effect until the next time the counter + * overflows. You can force the counter to reset using + * HardwareTimer::refresh(). * - * For example, the system clock rate is 72MHz, so the counter - * will reach 65535 in (13.89 nanoseconds) * (65535 counts) = - * (910.22 microseconds), or about a thousand times a second. If - * the prescaler equals 1098, then the clock rate is effectively - * 65.56KHz, and the counter will reach 65536 in (15.25 - * microseconds) * (65536 counts) = (0.999 seconds), or about once - * per second. - * - * The HardwareTimer::setPeriod() method may also be used as a - * convenient alternative. - * - * @param factor The new prescale value to set. - * @see HardwareTimer::setPeriod() + * @param factor The new prescale value to set, from 1 to 65,536. + * @see HardwareTimer::refresh() */ - void setPrescaleFactor(uint16 factor); + void setPrescaleFactor(uint32 factor); /** - * Gets the timer overflow value. + * @brief Get the timer overflow value. * @see HardwareTimer::setOverflow() */ uint16 getOverflow(); /** - * Sets the timer overflow (or "reload") value. + * @brief Set the timer overflow (or "reload") value. * - * When the timer's counter reaches this, value it resets to - * zero. Its default value is 65535 (the largest unsigned 16-bit - * integer); setting the overflow to anything lower will cause - * interrupts to be called more frequently (see the setPeriod() - * function below for a shortcut). This number sets the maximum - * value for the channel compare values. + * The new value won't take effect until the next time the counter + * overflows. You can force the counter to reset using + * HardwareTimer::refresh(). * * @param val The new overflow value to set + * @see HardwareTimer::refresh() */ void setOverflow(uint16 val); /** - * Retrieve the current timer count. + * @brief Get the current timer count. * * @return The timer's current count value */ uint16 getCount(void); /** - * Set the current timer count. - * - * Note that there is some function call overhead associated with - * calling this method, so using it is not a robust way to get - * multiple timers to share a count value. + * @brief Set the current timer count. * * @param val The new count value to set. If this value exceeds * the timer's overflow value, it is truncated to the @@ -165,143 +129,50 @@ class HardwareTimer { void setCount(uint16 val); /** - * Configure the prescaler and overflow values to generate a timer + * @brief Set the timer's period in microseconds. + * + * Configures the prescaler and overflow values to generate a timer * reload with a period as close to the given number of * microseconds as possible. * - * The return value is the overflow, which may be used to set - * channel compare values. However, if a clock that fires an - * interrupt every given number of microseconds is all that is - * desired, and the relative "phases" are unimportant, channel - * compare values may all be set to 1. - * - * @param microseconds the desired period of the timer. - * @return the overflow value (and thus, the largest value that can be - * set as a compare). + * @param microseconds The desired period of the timer. This must be + * greater than zero. + * @return The new overflow value. */ uint16 setPeriod(uint32 microseconds); /** - * Set the given channel of this timer to the given mode. - * + * @brief Configure a timer channel's mode. * @param channel Timer channel, from 1 to 4 * @param mode Mode to set */ - void setChannelMode(int channel, TimerMode mode); - - /** - * Set channel 1 of this timer to the given mode. - * - * Note: Timer1.setChannel1Mode(TIMER_PWM) may not work as - * expected; if you want PWM functionality on a channel make sure - * you don't set it to something else! - * - * @see TimerMode - */ - void setChannel1Mode(TimerMode mode); - - /** - * Set channel 2 of this timer to the given mode. - * @see TimerMode - */ - void setChannel2Mode(TimerMode mode); - - /** - * Set channel 3 of this timer to the given mode. - * @see TimerMode - */ - void setChannel3Mode(TimerMode mode); - - /** - * Set channel 4 of this timer to the given mode. - * @see TimerMode - */ - void setChannel4Mode(TimerMode mode); + void setMode(int channel, timer_mode mode); /** - * Gets the compare value for the given channel. + * @brief Get the compare value for the given channel. * @see HardwareTimer::setCompare() */ uint16 getCompare(int channel); - /** Equivalent to getCompare(1) */ - uint16 getCompare1(); - - /** Equivalent to getCompare(2) */ - uint16 getCompare2(); - - /** Equivalent to getCompare(3) */ - uint16 getCompare3(); - - /** Equivalent to getCompare(4) */ - uint16 getCompare4(); - /** - * Sets the compare value for the given channel. - * - * When the counter reaches this value the interrupt for this - * channel will fire if the channel mode is TIMER_OUTPUTCOMPARE - * and an interrupt is attached. - * - * By default, this only changes the relative offsets between - * events on a single timer ("phase"); they don't control the - * frequency with which they occur. However, a common trick is to - * increment the compare value manually in the interrupt handler - * so that the event will fire again after the increment - * period. There can be a different increment value for each - * channel, so this trick allows events to be programmed at 4 - * different rates on a single timer. Note that function call - * overheads mean that the smallest increment rate is at least a - * few microseconds. + * @brief Set the compare value for the given channel. * * @param channel the channel whose compare to set, from 1 to 4. * @param compare The compare value to set. If greater than this * timer's overflow value, it will be truncated to * the overflow value. * - * @see TimerMode - * @see HardwareTimer::setChannelMode() + * @see timer_mode + * @see HardwareTimer::setMode() * @see HardwareTimer::attachInterrupt() */ void setCompare(int channel, uint16 compare); /** - * Equivalent to setCompare(1, compare). - */ - void setCompare1(uint16 compare); - - /** - * Equivalent to setCompare(2, compare). - */ - void setCompare2(uint16 compare); - - /** - * Equivalent to setCompare(3, compare). - */ - void setCompare3(uint16 compare); - - /** - * Equivalent to setCompare(4, compare). - */ - void setCompare4(uint16 compare); - - /** - * Attach an interrupt handler to the given channel. This - * interrupt handler will be called when the timer's counter - * reaches the given channel compare value. - * - * The argument should be a function which takes no arguments and - * has no return value; i.e. it should have signature + * @brief Attach an interrupt handler to the given channel. * - * void (*handler)(void); - * - * Note: The function (often called an interrupt service routine, - * or ISR) should attempt to return as quickly as possible. - * Blinking the LED, some logic, PWM updates, and Serial writes - * are fine; writing to SerialUSB or waiting for user input can - * take a long time and other compare interrupts won't fire. Tip: - * if you have a delay() in your interrupt routine, you're probably - * doing it wrong. + * This interrupt handler will be called when the timer's counter + * reaches the given channel compare value. * * @param channel the channel to attach the ISR to, from 1 to 4. * @param handler The ISR to attach to the given channel. @@ -310,32 +181,10 @@ class HardwareTimer { void attachInterrupt(int channel, voidFuncPtr handler); /** - * Equivalent to attachCompareInterrupt(1, handler). - * @see HardwareTimer::attachCompareInterrupt() - */ - void attachCompare1Interrupt(voidFuncPtr handler); - - /** - * Equivalent to attachCompareInterrupt(2, handler). - * @see HardwareTimer::attachCompareInterrupt() - */ - void attachCompare2Interrupt(voidFuncPtr handler); - - /** - * Equivalent to attachCompareInterrupt(3, handler). - * @see HardwareTimer::attachCompareInterrupt() - */ - void attachCompare3Interrupt(voidFuncPtr handler); - - /** - * Equivalent to attachCompareInterrupt(4, handler). - * @see HardwareTimer::attachCompareInterrupt() - */ - void attachCompare4Interrupt(voidFuncPtr handler); - - /** - * Remove the interrupt handler attached to the given channel, if - * any. The handler will no longer be called by this timer. + * @brief Remove the interrupt handler attached to the given + * channel, if any. + * + * The handler will no longer be called by this timer. * * @param channel the channel whose interrupt to detach, from 1 to 4. * @see HardwareTimer::attachInterrupt() @@ -343,71 +192,138 @@ class HardwareTimer { void detachInterrupt(int channel); /** - * Equivalent to detachInterrupt(1). - * @see HardwareTimer::detachInterrupt() + * @brief Reset the counter, and update the prescaler and overflow + * values. + * + * This will reset the counter to 0 in upcounting mode (the + * default). It will also update the timer's prescaler and + * overflow, if you have set them up to be changed using + * HardwareTimer::setPrescaleFactor() or + * HardwareTimer::setOverflow(). + * + * @see HardwareTimer::setPrescaleFactor() + * @see HardwareTimer::setOverflow() */ - void detachCompare1Interrupt(void); + void refresh(void); - /** - * Equivalent to detachInterrupt(2). - * @see HardwareTimer::detachInterrupt() - */ - void detachCompare2Interrupt(void); + /* -- Deprecated methods ----------------------------------------------- */ - /** - * Equivalent to detachInterrupt(3). - * @see HardwareTimer::detachInterrupt() - */ - void detachCompare3Interrupt(void); + /** @brief Deprecated; use setMode(channel, mode) instead. */ + void setChannelMode(int channel, timer_mode mode) { + setMode(channel, mode); + } - /** - * Equivalent to detachInterrupt(4). - * @see HardwareTimer::detachInterrupt() - */ - void detachCompare4Interrupt(void); + /** @brief Deprecated; use setMode(TIMER_CH1, mode) instead. */ + void setChannel1Mode(timer_mode mode) { setMode(TIMER_CH1, mode); } - /** - * Re-initializes the counter (to 0 in upcounting mode, which is - * the default), and generates an update of the prescale and - * overflow registers. - */ - void generateUpdate(void); + /** @brief Deprecated; use setMode(TIMER_CH2, mode) instead. */ + void setChannel2Mode(timer_mode mode) { setMode(TIMER_CH2, mode); } + + /** @brief Deprecated; use setMode(TIMER_CH3, mode) instead. */ + void setChannel3Mode(timer_mode mode) { setMode(TIMER_CH3, mode); } + + /** @brief Deprecated; use setMode(TIMER_CH4, mode) instead. */ + void setChannel4Mode(timer_mode mode) { setMode(TIMER_CH4, mode); } + + /** @brief Deprecated; use return getCompare(TIMER_CH1) instead. */ + uint16 getCompare1() { return getCompare(TIMER_CH1); } + + /** @brief Deprecated; use return getCompare(TIMER_CH2) instead. */ + uint16 getCompare2() { return getCompare(TIMER_CH2); } + + /** @brief Deprecated; use return getCompare(TIMER_CH3) instead. */ + uint16 getCompare3() { return getCompare(TIMER_CH3); } + + /** @brief Deprecated; use return getCompare(TIMER_CH4) instead. */ + uint16 getCompare4() { return getCompare(TIMER_CH4); } + + /** @brief Deprecated; use setCompare(TIMER_CH1, compare) instead. */ + void setCompare1(uint16 compare) { setCompare(TIMER_CH1, compare); } + + /** @brief Deprecated; use setCompare(TIMER_CH2, compare) instead. */ + void setCompare2(uint16 compare) { setCompare(TIMER_CH2, compare); } + + /** @brief Deprecated; use setCompare(TIMER_CH3, compare) instead. */ + void setCompare3(uint16 compare) { setCompare(TIMER_CH3, compare); } + + /** @brief Deprecated; use setCompare(TIMER_CH4, compare) instead. */ + void setCompare4(uint16 compare) { setCompare(TIMER_CH4, compare); } + + /** @brief Deprecated; use attachInterrupt(TIMER_CH1, handler) instead. */ + void attachCompare1Interrupt(voidFuncPtr handler) { + attachInterrupt(TIMER_CH1, handler); + } + + /** @brief Deprecated; use attachInterrupt(TIMER_CH2, handler) instead. */ + void attachCompare2Interrupt(voidFuncPtr handler) { + attachInterrupt(TIMER_CH2, handler); + } + + /** @brief Deprecated; use attachInterrupt(TIMER_CH3, handler) instead. */ + void attachCompare3Interrupt(voidFuncPtr handler) { + attachInterrupt(TIMER_CH3, handler); + } + + /** @brief Deprecated; use attachInterrupt(TIMER_CH4, handler) instead. */ + void attachCompare4Interrupt(voidFuncPtr handler) { + attachInterrupt(TIMER_CH4, handler); + } + + /** @brief Deprecated; use detachInterrupt(TIMER_CH1) instead. */ + void detachCompare1Interrupt(void) { detachInterrupt(TIMER_CH1); } + + /** @brief Deprecated; use detachInterrupt(TIMER_CH2) instead. */ + void detachCompare2Interrupt(void) { detachInterrupt(TIMER_CH2); } + + /** @brief Deprecated; use detachInterrupt(TIMER_CH3) instead. */ + void detachCompare3Interrupt(void) { detachInterrupt(TIMER_CH3); } + + /** @brief Deprecated; use detachInterrupt(TIMER_CH4) instead. */ + void detachCompare4Interrupt(void) { detachInterrupt(TIMER_CH4); } + + /** @brief Deprecated; use refresh() instead. */ + void generateUpdate(void) { refresh(); } }; -/** Pre-instantiated timer for use by user code. */ +/* -- The rest of this file is deprecated. --------------------------------- */ + +/** + * @brief Deprecated. + * + * Pre-instantiated timer. + */ extern HardwareTimer Timer1; -/** Pre-instantiated timer for use by user code. */ +/** + * @brief Deprecated. + * + * Pre-instantiated timer. + */ extern HardwareTimer Timer2; -/** Pre-instantiated timer for use by user code. */ +/** + * @brief Deprecated. + * + * Pre-instantiated timer. + */ extern HardwareTimer Timer3; -/** Pre-instantiated timer for use by user code. */ +/** + * @brief Deprecated. + * + * Pre-instantiated timer. + */ extern HardwareTimer Timer4; #ifdef STM32_HIGH_DENSITY -/** Pre-instantiated timer for use by user code, on devices with - more than four timers (this does not include the Maple). */ -extern HardwareTimer Timer5; -/** Pre-instantiated timer for use by user code, on devices with - more than four timers (this does not include the Maple). */ -extern HardwareTimer Timer8; -#endif - /** - * Get one of the pre-instantiated HardwareTimer instances, given a - * timer device number. - * - * Be careful not to pass an actual number to this function. For - * example, getTimer(1) will not return Timer1. Use a real - * timer_dev_num, e.g. TIMER1, TIMER2, etc. + * @brief Deprecated. * - * @param timerNum the timer device number, e.g. TIMER1. - * - * @return Pointer to the HardwareTimer instance corresponding to the - * given timer device number. If timerNum is TIMER_INVALID, returns a - * null pointer. + * Pre-instantiated timer. + */ +extern HardwareTimer Timer5; +/** + * @brief Deprecated. * - * @see timer_dev_num + * Pre-instantiated timer. */ -HardwareTimer* getTimer(timer_dev_num timerNum); - +extern HardwareTimer Timer8; #endif +#endif diff --git a/wirish/rules.mk b/wirish/rules.mk index c3608e3..6999288 100644 --- a/wirish/rules.mk +++ b/wirish/rules.mk @@ -23,6 +23,7 @@ cppSRCS_$(d) := wirish_math.cpp \ boards/maple_RET6.cpp \ comm/HardwareSerial.cpp \ comm/HardwareSPI.cpp \ + HardwareTimer.cpp \ usb_serial.cpp \ cxxabi-compat.cpp \ wirish_shift.cpp \ diff --git a/wirish/wirish.h b/wirish/wirish.h index d30ad20..82a9897 100644 --- a/wirish/wirish.h +++ b/wirish/wirish.h @@ -44,6 +44,7 @@ #include "wirish_time.h" #include "HardwareSPI.h" #include "HardwareSerial.h" +#include "HardwareTimer.h" #include "usb_serial.h" /* Arduino wiring macros and bit defines */ -- cgit v1.2.3 From f432df24764cee2f7d1590650eeac4f3a121f25e Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Fri, 6 May 2011 20:11:48 -0400 Subject: Updating VGA examples for use with new timer API. --- examples/vga-leaf.cpp | 42 ++++++++++++++++++++++-------------------- examples/vga-scope.cpp | 18 +++++++++--------- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/examples/vga-leaf.cpp b/examples/vga-leaf.cpp index e663639..f31dc87 100644 --- a/examples/vga-leaf.cpp +++ b/examples/vga-leaf.cpp @@ -102,6 +102,8 @@ uint32 logo[y_max][x_max] = { {0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, }; +HardwareTimer timer(4); + void setup() { // Setup our pins pinMode(BOARD_LED_PIN, OUTPUT); @@ -132,25 +134,25 @@ void setup() { systick_disable(); // Configure - Timer4.pause(); // while we configure - Timer4.setPrescaleFactor(1); // Full speed - Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE); - Timer4.setChannel2Mode(TIMER_OUTPUTCOMPARE); - Timer4.setChannel3Mode(TIMER_OUTPUTCOMPARE); - Timer4.setChannel4Mode(TIMER_OUTPUTCOMPARE); - Timer4.setOverflow(2287); // Total line time - - Timer4.setCompare1(200); - Timer4.attachCompare1Interrupt(isr_porch); - Timer4.setCompare2(300); - Timer4.attachCompare2Interrupt(isr_start); - Timer4.setCompare3(2170); - Timer4.attachCompare3Interrupt(isr_stop); - Timer4.setCompare4(1); // Could be zero I guess - Timer4.attachCompare4Interrupt(isr_update); - - Timer4.setCount(0); // Ready... - Timer4.resume(); // Go! + timer.pause(); // while we configure + timer.setPrescaleFactor(1); // Full speed + timer.setMode(TIMER_CH1, TIMER_OUTPUT_COMPARE); + timer.setMode(TIMER_CH2, TIMER_OUTPUT_COMPARE); + timer.setMode(TIMER_CH3, TIMER_OUTPUT_COMPARE); + timer.setMode(TIMER_CH4, TIMER_OUTPUT_COMPARE); + timer.setOverflow(2287); // Total line time + + timer.setCompare(TIMER_CH1, 200); + timer.attachInterrupt(TIMER_CH1, isr_porch); + timer.setCompare(TIMER_CH2, 300); + timer.attachInterrupt(TIMER_CH2, isr_start); + timer.setCompare(TIMER_CH3, 2170); + timer.attachInterrupt(TIMER_CH3, isr_stop); + timer.setCompare(TIMER_CH4, 1); // Could be zero, I guess + timer.attachInterrupt(TIMER_CH4, isr_update); + + timer.setCount(0); // Ready... + timer.resume(); // Go! } void loop() { @@ -203,7 +205,7 @@ void isr_start(void) { for (x = 0; x < 16; x++) { // setting the color several times is just an easy way to // delay, so the image is wider. if you only do the following - // once, you'll be able to make the logo array a lot wider: + // once, you'll be able to make the logo array bigger: VGA_COLOR(logo[logo_y][x]); VGA_COLOR(logo[logo_y][x]); VGA_COLOR(logo[logo_y][x]); diff --git a/examples/vga-scope.cpp b/examples/vga-scope.cpp index 9aa8bcb..b5fa8a5 100644 --- a/examples/vga-scope.cpp +++ b/examples/vga-scope.cpp @@ -76,7 +76,7 @@ // set has priority, so clear every bit and set some given bits: #define VGA_COLOR(c) (*ABSRR = c | \ - BIT(RBIT+16) | BIT(GBIT+16) | BIT(BBIT+16)) + BIT(RBIT + 16) | BIT(GBIT + 16) | BIT(BBIT + 16)) #define VGA_V_HIGH *ABSRR = BIT(6) #define VGA_V_LOW *ABRR = BIT(6) @@ -116,15 +116,15 @@ void setup() { timer_pause(TIMER4); timer_set_prescaler(TIMER4, 0); - timer_set_mode(TIMER4, 1, TIMER_OUTPUTCOMPARE); - timer_set_mode(TIMER4, 2, TIMER_OUTPUTCOMPARE); - timer_set_mode(TIMER4, 3, TIMER_OUTPUTCOMPARE); - timer_set_mode(TIMER4, 4, TIMER_OUTPUTCOMPARE); + timer_set_mode(TIMER4, 1, TIMER_OUTPUT_COMPARE); + timer_set_mode(TIMER4, 2, TIMER_OUTPUT_COMPARE); + timer_set_mode(TIMER4, 3, TIMER_OUTPUT_COMPARE); + timer_set_mode(TIMER4, 4, TIMER_OUTPUT_COMPARE); timer_set_reload(TIMER4, 2287); - timer_set_compare_value(TIMER4, 1, 200); - timer_set_compare_value(TIMER4, 2, 250); - timer_set_compare_value(TIMER4, 3, 2170); // 2219 max... - timer_set_compare_value(TIMER4, 4, 1); + timer_set_compare(TIMER4, 1, 200); + timer_set_compare(TIMER4, 2, 250); + timer_set_compare(TIMER4, 3, 2170); // 2219 max... + timer_set_compare(TIMER4, 4, 1); timer_attach_interrupt(TIMER4, 1, isr_porch); timer_attach_interrupt(TIMER4, 2, isr_start); timer_attach_interrupt(TIMER4, 3, isr_stop); -- cgit v1.2.3 From b0a0002b2e4b9dd795afc571748d91353df15fa6 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Fri, 6 May 2011 20:11:57 -0400 Subject: Independent watchdog refactor. --- libmaple/iwdg.c | 41 +++++++++++++++------------- libmaple/iwdg.h | 85 ++++++++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 88 insertions(+), 38 deletions(-) diff --git a/libmaple/iwdg.c b/libmaple/iwdg.c index 82a0151..3d67ee8 100644 --- a/libmaple/iwdg.c +++ b/libmaple/iwdg.c @@ -23,34 +23,37 @@ *****************************************************************************/ /** - * @file iwdg.c - * - * @brief Independent watchdog support + * @file iwdg.c + * @brief Independent watchdog (IWDG) 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 + * @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. * - * 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. + * @param prescaler Prescaler for the 40 KHz IWDG clock. + * @param reload Independent watchdog counter reload value. */ -void iwdg_init(uint8 prescaler, uint16 reload) { - __write(IWDG_KR, IWDG_UNLOCK); - __write(IWDG_PR, prescaler); - __write(IWDG_RLR, reload); +void iwdg_init(iwdg_prescaler prescaler, uint16 reload) { + IWDG_BASE->KR = IWDG_KR_UNLOCK; + IWDG_BASE->PR = prescaler; + IWDG_BASE->RLR = reload; - /* Start things off */ - __write(IWDG_KR, IWDG_START); - __write(IWDG_KR, IWDG_FEED); + /* Start things off */ + IWDG_BASE->KR = IWDG_KR_START; + iwdg_feed(); } +/** + * @brief Reset the IWDG counter. + * + * Calling this function will cause the IWDG counter to be reset to + * its reload value. + */ void iwdg_feed(void) { - __write(IWDG_KR, IWDG_FEED); + IWDG_BASE->KR = IWDG_KR_FEED; } diff --git a/libmaple/iwdg.h b/libmaple/iwdg.h index 4ab0ddf..81f0fdb 100644 --- a/libmaple/iwdg.h +++ b/libmaple/iwdg.h @@ -23,35 +23,82 @@ *****************************************************************************/ /** - * @file iwdg.h + * @file iwdg.h + * @author Michael Hope, Marti Bolivar + * @brief Independent watchdog support. * - * @brief Independent watchdog support + * To use the independent watchdog, first call iwdg_init() with the + * appropriate prescaler and IWDG counter reload values for your + * application. Afterwards, you must periodically call iwdg_feed() + * before the IWDG counter reaches 0 to reset the counter to its + * reload value. If you do not, the chip will reset. + * + * Once started, the independent watchdog cannot be turned off. */ #ifndef _IWDG_H_ #define _IWDG_H_ +#include "libmaple_types.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); +/* + * Register map + */ + +/** Independent watchdog register map type. */ +typedef struct iwdg_reg_map { + __io uint32 KR; /**< Key register. */ + __io uint32 PR; /**< Prescaler register. */ + __io uint32 RLR; /**< Reload register. */ + __io uint32 SR; /**< Status register */ +} iwdg_reg_map; + +#define IWDG_BASE ((struct iwdg_reg_map*)0x40003000) + +/* + * Register bit definitions + */ + +/* Key register */ + +#define IWDG_KR_UNLOCK 0x5555 +#define IWDG_KR_FEED 0xAAAA +#define IWDG_KR_START 0xCCCC + +/* Prescaler register */ + +#define IWDG_PR_DIV_4 0x0 +#define IWDG_PR_DIV_8 0x1 +#define IWDG_PR_DIV_16 0x2 +#define IWDG_PR_DIV_32 0x3 +#define IWDG_PR_DIV_64 0x4 +#define IWDG_PR_DIV_128 0x5 +#define IWDG_PR_DIV_256 0x6 + +/* Status register */ + +#define IWDG_SR_RVU_BIT 1 +#define IWDG_SR_PVU_BIT 0 + +#define IWDG_SR_RVU BIT(IWDG_SR_RVU_BIT) +#define IWDG_SR_PVU BIT(IWDG_SR_PVU_BIT) + +/** Independent watchdog prescalers */ +typedef enum { + IWDG_PRE_4 = IWDG_PR_DIV_4, + IWDG_PRE_8 = IWDG_PR_DIV_8, + IWDG_PRE_16 = IWDG_PR_DIV_16, + IWDG_PRE_32 = IWDG_PR_DIV_32, + IWDG_PRE_64 = IWDG_PR_DIV_64, + IWDG_PRE_128 = IWDG_PR_DIV_128, + IWDG_PRE_256 = IWDG_PR_DIV_256 +} iwdg_prescaler; + +void iwdg_init(iwdg_prescaler prescaler, uint16 reload); void iwdg_feed(void); #ifdef __cplusplus -- cgit v1.2.3 From 9016d46134324cdb6b44d52f3adf639bc9c4c186 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Fri, 6 May 2011 20:17:41 -0400 Subject: IWDG include fixup. --- libmaple/iwdg.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libmaple/iwdg.h b/libmaple/iwdg.h index 81f0fdb..e0a2d62 100644 --- a/libmaple/iwdg.h +++ b/libmaple/iwdg.h @@ -40,6 +40,7 @@ #define _IWDG_H_ #include "libmaple_types.h" +#include "util.h" #ifdef __cplusplus extern "C"{ -- cgit v1.2.3 From 1e2e177f6dae62e040c674b617744c73be187062 Mon Sep 17 00:00:00 2001 From: Marti Bolivar Date: Fri, 6 May 2011 20:19:44 -0400 Subject: Finally getting rid of __read() and __write(). This brings util.h down to some bit manipulation macros, failure routines, and asserts. --- libmaple/util.h | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/libmaple/util.h b/libmaple/util.h index 4c47764..f54f3fd 100644 --- a/libmaple/util.h +++ b/libmaple/util.h @@ -42,17 +42,10 @@ extern "C"{ #define BIT(shift) (1UL << (shift)) #define BIT_MASK_SHIFT(mask, shift) ((mask) << (shift)) -/* Bits m to n of x */ +/** Bits m to n of x */ #define GET_BITS(x, m, n) ((((uint32)x) << (31 - (n))) >> ((31 - (n)) + (m))) #define IS_POWER_OF_TWO(v) (v && !(v & (v - 1))) -/* - * Register reads and writes - */ - -#define __read(reg) (*(__io uint32*)(reg)) -#define __write(reg, value) (*(__io uint32*)(reg) = (value)) - /* * Failure routines */ -- cgit v1.2.3