diff options
| -rw-r--r-- | Makefile | 4 | ||||
| -rw-r--r-- | libmaple/adc.h | 11 | ||||
| -rw-r--r-- | libmaple/exti.h | 8 | ||||
| -rw-r--r-- | libmaple/libmaple.h | 6 | ||||
| -rw-r--r-- | libmaple/timers.c | 2 | ||||
| -rw-r--r-- | libmaple/timers.h | 18 | ||||
| -rw-r--r-- | support/ld/maple_mini/flash.ld | 211 | ||||
| -rw-r--r-- | support/ld/maple_mini/jtag.ld | 186 | ||||
| -rw-r--r-- | support/ld/maple_mini/ram.ld | 220 | ||||
| -rw-r--r-- | wirish/HardwareTimer.cpp | 18 | ||||
| -rw-r--r-- | wirish/HardwareTimer.h | 285 | ||||
| -rw-r--r-- | wirish/boards.h | 79 | ||||
| -rw-r--r-- | wirish/ext_interrupts.c | 20 | ||||
| -rw-r--r-- | wirish/ext_interrupts.h | 41 | ||||
| -rw-r--r-- | wirish/io.h | 149 | ||||
| -rw-r--r-- | wirish/pwm.h | 11 | ||||
| -rw-r--r-- | wirish/wirish_digital.c | 7 | 
17 files changed, 1175 insertions, 101 deletions
| @@ -17,6 +17,10 @@ ifeq ($(BOARD), maple_native)     MCU := STM32F103ZE     PRODUCT_ID := 0003  endif +ifeq ($(BOARD), maple_mini) +   MCU := STM32F103CB +   PRODUCT_ID := 0003 +endif  # Useful paths  ifeq ($(LIB_MAPLE_HOME),) diff --git a/libmaple/adc.h b/libmaple/adc.h index 9b61821..ce67116 100644 --- a/libmaple/adc.h +++ b/libmaple/adc.h @@ -43,7 +43,8 @@ extern "C"{   *   * Need to up the sample time if otherwise... see datasheet */ -/* TODO: We'll only use ADC1 for now...  */ +/* TODO: We'll only use ADC1 for now.  See page 41 of the manual for +   ADC2 and ADC3's real addresses.  */  #define ADC1_BASE                 0x40012400  #define ADC2_BASE                 0x40012400  #define ADC3_BASE                 0x40012400 @@ -73,17 +74,17 @@ extern "C"{  void adc_init(void);  void adc_disable(void); -/* Perform a single conversion on ADC[0-16], +/* Perform a single conversion on ADC[0-15],   * PRECONDITIONS:   *   adc initialized */  static inline int adc_read(int channel) { -    /* Set channel  */ +    /* Set channel */      ADC_SQR3 = channel; -    /* Start the conversion  */ +    /* Start the conversion */      CR2_SWSTART_BIT = 1; -    /* Wait for it to finish  */ +    /* Wait for it to finish */      while(SR_EOC_BIT == 0)          ; diff --git a/libmaple/exti.h b/libmaple/exti.h index 89cd986..cab2963 100644 --- a/libmaple/exti.h +++ b/libmaple/exti.h @@ -141,10 +141,10 @@  #define EXTI14 14  #define EXTI15 15 -#define EXTI_CONFIG_PORTA 0 -#define EXTI_CONFIG_PORTB 1 -#define EXTI_CONFIG_PORTC 2 -#define EXTI_CONFIG_PORTD 3 +#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 diff --git a/libmaple/libmaple.h b/libmaple/libmaple.h index 0b0494f..74488ab 100644 --- a/libmaple/libmaple.h +++ b/libmaple/libmaple.h @@ -168,6 +168,12 @@      #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  #endif  /* Make sure MCU-specific settings were defined */ diff --git a/libmaple/timers.c b/libmaple/timers.c index 334ec0b..c369d1f 100644 --- a/libmaple/timers.c +++ b/libmaple/timers.c @@ -211,7 +211,7 @@ void timer_disable_all(void) {  }  /* Sets the mode of individual timer channels, including a DISABLE mode */ -void timer_set_mode(uint8 timer_num, uint8 channel, uint8 mode) { +void timer_set_mode(uint8 timer_num, uint8 channel, TimerMode mode) {      timer_port *timer = timer_dev_table[timer_num].base;      ASSERT(channel >= 1); diff --git a/libmaple/timers.h b/libmaple/timers.h index ba8245c..d180bab 100644 --- a/libmaple/timers.h +++ b/libmaple/timers.h @@ -132,9 +132,21 @@ typedef volatile uint32* TimerCCR;  #define TIMER8_CH3_CCR     TIMER8_BASE + 0x3C  #define TIMER8_CH4_CCR     TIMER8_BASE + 0x40 -#define TIMER_DISABLED          0 -#define TIMER_PWM               1 -#define TIMER_OUTPUTCOMPARE     2 +/** + * 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 +                            the overflow value repeatedly; every time +                            the counter value reaches one of the +                            channel compare values, the corresponding +                            interrupt is fired. */ +} TimerMode;  typedef struct {      volatile uint16 CR1; diff --git a/support/ld/maple_mini/flash.ld b/support/ld/maple_mini/flash.ld new file mode 100644 index 0000000..2d40100 --- /dev/null +++ b/support/ld/maple_mini/flash.ld @@ -0,0 +1,211 @@ +/* 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. */
 +
 +/* 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
 + */
 +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 = .;
 +
 +    . = 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
 +
 +/* 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_mini/jtag.ld b/support/ld/maple_mini/jtag.ld new file mode 100644 index 0000000..435e3f0 --- /dev/null +++ b/support/ld/maple_mini/jtag.ld @@ -0,0 +1,186 @@ +/* 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. */
 +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
 + */
 +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 = .;
 +
 +    . = 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_mini/ram.ld b/support/ld/maple_mini/ram.ld new file mode 100644 index 0000000..1fbecc5 --- /dev/null +++ b/support/ld/maple_mini/ram.ld @@ -0,0 +1,220 @@ +/* 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. */
 +
 +/* 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
 + */
 +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 = .;
 +
 +    . = 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) }
 +}
 +
 diff --git a/wirish/HardwareTimer.cpp b/wirish/HardwareTimer.cpp index 6fbad8b..5b80ec1 100644 --- a/wirish/HardwareTimer.cpp +++ b/wirish/HardwareTimer.cpp @@ -22,10 +22,8 @@   * THE SOFTWARE.   *****************************************************************************/ -/** - *  @brief wirish timer class to manage the four 16-bit timer peripherals - * - *  This implementation is not very efficient (lots of duplicated functions) +/* + * wirish timer class to manage the four 16-bit timer peripherals   */  #include "wirish.h" @@ -69,10 +67,6 @@ uint16 HardwareTimer::getCount(void) {      return timer_get_count(this->timerNum);  } -/* This function will set the prescaler and overflow to get a period - * of the given length with the most resolution; the return value is - * the overflow value and thus the largest value that can be set as a - * compare. */  uint16 HardwareTimer::setPeriod(uint32 microseconds) {      // XXX: 72MHz shouldn't be hard coded in here... global define? @@ -92,19 +86,19 @@ uint16 HardwareTimer::setPeriod(uint32 microseconds) {      return this->overflow;  } -void HardwareTimer::setChannel1Mode(uint8 mode) { +void HardwareTimer::setChannel1Mode(TimerMode mode) {      timer_set_mode(this->timerNum,1,mode);  } -void HardwareTimer::setChannel2Mode(uint8 mode) { +void HardwareTimer::setChannel2Mode(TimerMode mode) {      timer_set_mode(this->timerNum,2,mode);  } -void HardwareTimer::setChannel3Mode(uint8 mode) { +void HardwareTimer::setChannel3Mode(TimerMode mode) {      timer_set_mode(this->timerNum,3,mode);  } -void HardwareTimer::setChannel4Mode(uint8 mode) { +void HardwareTimer::setChannel4Mode(TimerMode mode) {      timer_set_mode(this->timerNum,4,mode);  } diff --git a/wirish/HardwareTimer.h b/wirish/HardwareTimer.h index c6e11c8..b05085f 100644 --- a/wirish/HardwareTimer.h +++ b/wirish/HardwareTimer.h @@ -29,6 +29,26 @@  #ifndef _TIMER_H_  #define _TIMER_H_ +/** + * Interface to one of the 16-bit timer peripherals. + * + * User code should not instantiate this class directly; instead, use + * one of the predefined Timer<n> 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. + */  class HardwareTimer {   private:      uint16 overflow; @@ -37,39 +57,282 @@ class HardwareTimer {   public:      HardwareTimer(uint8 timer_num); +    /** +     * 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. +     * +     * @see HardwareTimer::resume() +     */      void pause(void); + +    /** +     * Resume a paused timer, without affecting its configuration. +     * +     * The timer will resume counting and firing interrupts as +     * appropriate. +     * +     * Note that there is some function call overhead associated with +     * using this method, so using it in concert with +     * HardwareTimer::resume() is not a robust way to align multiple +     * timers to the same count value. +     * +     * @see HardwareTimer::pause() +     */      void resume(void); + +    /** +     * Set the timer prescale. +     * +     * The prescaler acts as a clock divider to slow down the rate at +     * which the counter increments. +     * +     * 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() +     */      void setPrescaleFactor(uint16 factor); -    void setOverflow(uint16 val); // truncates to overflow -    void setCount(uint16 val);    // truncates to overflow + +    /** +     * Sets 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. +     * +     * @param val The new overflow value to set +     * @see HardwareTimer::setOverflow() +     */ +    void setOverflow(uint16 val); + +    /** +     * Set the current timer count. +     * +     * Note that there is some function call overhead associated with +     * callign this method, so using it is not a robust way to get +     * multiple timers to share a count value. +     * +     * @param val The new count value to set.  If this value exceeds +     *            the timer's overflow value, it is truncated to the +     *            overflow value. +     */ +    void setCount(uint16 val); + +    /** +     * Retrieve the current timer count. +     * +     * @return The timer's current count value +     */      uint16 getCount(void); -    // tries to set prescaler and overflow wisely; returns overflow +    /** +     * Configure 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). +     */      uint16 setPeriod(uint32 microseconds); -    void setChannel1Mode(uint8 mode); -    void setChannel2Mode(uint8 mode); -    void setChannel3Mode(uint8 mode); -    void setChannel4Mode(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 + +    /** +     * 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); + +    /** +     * Sets the compare value for channel 1. +     * +     * When the counter reaches this value the interrupt for this +     * channel will fire if channel 1 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. +     * +     * @param val 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::setChannel1Mode() +     */ +    void setCompare1(uint16 val); + +    /** +     * Sets the compare value for channel 2. +     * +     * @param val The compare value to set.  If greater than this +     *            timer's overflow value, it will be truncated to the +     *            overflow value. +     * @see HardwareTimer::setCompare1() +     */ +    void setCompare2(uint16 val); + +    /** +     * Sets the compare value for channel 3. +     * +     * @param val The compare value to set.  If greater than this +     *            timer's overflow value, it will be truncated to the +     *            overflow value. +     * @see HardwareTimer::setCompare1() +     */ +    void setCompare3(uint16 val); + +    /** +     * Sets the compare value for channel 4. +     * +     * @param val The compare value to set.  If greater than this +     *            timer's overflow value, it will be truncated to the +     *            overflow value. +     * @see HardwareTimer::setCompare1() +     */ +    void setCompare4(uint16 val); + +    /** +     * Attach an interrupt handler to this timer's channel 1. This +     * interrupt handler will be called when the timer's counter +     * reaches its channel 1 compare value. +     * +     * The argument should be a function which takes no arguments and +     * has no return value; i.e. it should have signature +     * +     *     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. +     * +     * @param handler The ISR to attach to channel 1. +     * @see voidFuncPtr +     */      void attachCompare1Interrupt(voidFuncPtr handler); + +    /** +     * Like attachCompare1Interrupt(), but for channel 2. +     * @see HardwareTimer::attachCompare1Interrupt() +     */      void attachCompare2Interrupt(voidFuncPtr handler); + +    /** +     * Like attachCompare1Interrupt(), but for channel 3. +     * @see HardwareTimer::attachCompare1Interrupt() +     */      void attachCompare3Interrupt(voidFuncPtr handler); + +    /** +     * Like attachCompare1Interrupt(), but for channel 4. +     * @see HardwareTimer::attachCompare1Interrupt() +     */      void attachCompare4Interrupt(voidFuncPtr handler); + +    /** +     * Remove the interrupt handler attached to channel 1, if any. +     * The handler will no longer be called by this timer. +     * @see HardwareTimer::attachCompare1Interrupt() +     */      void detachCompare1Interrupt(void); + +    /** +     * Remove the interrupt handler attached to channel 2, if any. +     * The handler will no longer be called by this timer. +     * @see HardwareTimer::attachCompare1Interrupt() +     */      void detachCompare2Interrupt(void); + +    /** +     * Remove the interrupt handler attached to channel 3, if any. +     * The handler will no longer be called by this timer. +     * @see HardwareTimer::attachCompare1Interrupt() +     */      void detachCompare3Interrupt(void); + +    /** +     * Remove the interrupt handler attached to channel 4, if any. +     * The handler will no longer be called by this timer. +     * @see HardwareTimer::attachCompare1Interrupt() +     */      void detachCompare4Interrupt(void);  }; +/** Pre-instantiated timer for use by user code. */  extern HardwareTimer Timer1; +/** Pre-instantiated timer for use by user code. */  extern HardwareTimer Timer2; +/** Pre-instantiated timer for use by user code. */  extern HardwareTimer Timer3; +/** Pre-instantiated timer for use by user code. */  extern HardwareTimer Timer4;  #if NR_TIMERS >= 8 +/** 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 diff --git a/wirish/boards.h b/wirish/boards.h index fed5ead..0625d0a 100644 --- a/wirish/boards.h +++ b/wirish/boards.h @@ -292,6 +292,85 @@ typedef struct PinMapping {      };  #endif +#ifdef BOARD_maple_mini + +    #define CYCLES_PER_MICROSECOND 72 +    #define MAPLE_RELOAD_VAL       71999 /* takes a cycle to reload */ + +    static __attribute__ ((unused)) PinMapping PIN_MAP[NR_GPIO_PINS] = { +        /* D0/PC15 */ +        {GPIOC_BASE, 15,  ADC_INVALID, TIMER_INVALID,  EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, +        /* D1/PA0 */ +        {GPIOA_BASE,  0,  ADC0,        TIMER2_CH1_CCR, EXTI_CONFIG_PORTA, TIMER2,        1}, +        /* D2/PA1 */ +        {GPIOA_BASE,  1,  ADC1,        TIMER2_CH2_CCR, EXTI_CONFIG_PORTA, TIMER2,        2}, +        /* D3/PA2 */ +        {GPIOA_BASE,  2,  ADC2,        TIMER2_CH3_CCR, EXTI_CONFIG_PORTA, TIMER2,        3}, +        /* D4/PA3 */ +        {GPIOA_BASE,  3,  ADC3,        TIMER2_CH4_CCR, EXTI_CONFIG_PORTA, TIMER2,        4}, +        /* D5/PA4 */ +        {GPIOA_BASE,  4,  ADC4,        TIMER_INVALID,  EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID}, +        /* D6/PA5 */ +        {GPIOA_BASE,  5,  ADC5,        TIMER_INVALID,  EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID}, +        /* D7/PA6 */ +        {GPIOA_BASE,  6,  ADC6,        TIMER3_CH1_CCR, EXTI_CONFIG_PORTA, TIMER3,        1}, +        /* D8/PA7 */ +        {GPIOA_BASE,  7,  ADC7,        TIMER3_CH2_CCR, EXTI_CONFIG_PORTA, TIMER3,        2}, +        /* D9/PB0 */ +        {GPIOB_BASE,  0,  ADC8,        TIMER3_CH3_CCR, EXTI_CONFIG_PORTB, TIMER3,        3}, +        /* D10/PB1 */ +        {GPIOB_BASE,  1,  ADC9,        TIMER3_CH4_CCR, EXTI_CONFIG_PORTB, TIMER3,        4}, +        /* D11/PB2 */ +        {GPIOB_BASE,  2,  ADC_INVALID, TIMER_INVALID,  EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, +        /* D12/PB10 */ +        {GPIOB_BASE, 10,  ADC_INVALID, TIMER_INVALID,  EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, +        /* D13/PB11 */ +        {GPIOB_BASE, 11,  ADC_INVALID, TIMER_INVALID,  EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, +        /* D14/PB13 */ +        {GPIOB_BASE, 13,  ADC_INVALID, TIMER_INVALID,  EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, +        /* D15/PB14 */ +        {GPIOB_BASE, 14,  ADC_INVALID, TIMER_INVALID,  EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, +        /* D16/PB15 */ +        {GPIOB_BASE, 15,  ADC_INVALID, TIMER_INVALID,  EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, +        /* D17/PA8 */ +        {GPIOA_BASE,  8,  ADC_INVALID, TIMER1_CH1_CCR, EXTI_CONFIG_PORTB, TIMER1,        1}, +        /* D18/PA9 */ +        {GPIOA_BASE,  9,  ADC_INVALID, TIMER1_CH2_CCR, EXTI_CONFIG_PORTA, TIMER2,        2}, +        /* D19/PA10 */ +        {GPIOA_BASE, 10,  ADC_INVALID, TIMER1_CH3_CCR, EXTI_CONFIG_PORTA, TIMER1,        3}, +        /* D20/PA11 */ +        {GPIOA_BASE, 11,  ADC_INVALID, TIMER1_CH4_CCR, EXTI_CONFIG_PORTA, TIMER1,        4}, +        /* D21/PA12 */ +        {GPIOA_BASE, 12,  ADC_INVALID, TIMER_INVALID,  EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID}, +        /* D22/PA13 */ +        {GPIOA_BASE, 13,  ADC_INVALID, TIMER_INVALID,  EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID}, +        /* D23/PA14 */ +        {GPIOA_BASE, 14,  ADC_INVALID, TIMER_INVALID,  EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID}, +        /* D24/PA15 */ +        {GPIOA_BASE, 15,  ADC_INVALID, TIMER_INVALID,  EXTI_CONFIG_PORTA, TIMER_INVALID, TIMER_INVALID}, +        /* D25/PB3 */ +        {GPIOB_BASE,  3,  ADC_INVALID, TIMER_INVALID,  EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, +        /* D26/PB4 */ +        {GPIOB_BASE,  4,  ADC_INVALID, TIMER_INVALID,  EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, +        /* D27/PB5 */ +        {GPIOB_BASE,  5,  ADC_INVALID, TIMER_INVALID,  EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, +        /* D28/PB6 */ +        {GPIOB_BASE,  6,  ADC_INVALID, TIMER4_CH1_CCR, EXTI_CONFIG_PORTB, TIMER4,        1}, +        /* D29/PB7 */ +        {GPIOB_BASE,  7,  ADC_INVALID, TIMER4_CH2_CCR, EXTI_CONFIG_PORTB, TIMER4,        1}, +        /* D30/PC13 */ +        {GPIOC_BASE, 13,  ADC_INVALID, TIMER_INVALID,  EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, +        /* D31/PC14 */ +        {GPIOC_BASE, 14,  ADC_INVALID, TIMER_INVALID,  EXTI_CONFIG_PORTC, TIMER_INVALID, TIMER_INVALID}, +        /* D32/PB8 */ +        {GPIOB_BASE,  8,  ADC_INVALID, TIMER4_CH3_CCR, EXTI_CONFIG_PORTB, TIMER4,        3}, +        /* D33/PB12 */ +        {GPIOB_BASE, 12,  ADC_INVALID, TIMER_INVALID,  EXTI_CONFIG_PORTB, TIMER_INVALID, TIMER_INVALID}, +    }; + + +#endif +  #ifndef CYCLES_PER_MICROSECOND  #error "Board type has not been selected correctly."  #endif diff --git a/wirish/ext_interrupts.c b/wirish/ext_interrupts.c index f02cdc5..dd7c1a8 100644 --- a/wirish/ext_interrupts.c +++ b/wirish/ext_interrupts.c @@ -32,17 +32,8 @@  #include "exti.h"  #include "ext_interrupts.h" -/** - *  @brief Attach an interrupt handler to be triggered on a given - *  transition on the pin. Runs in interrupt context - * - *  @param pin Maple pin number - *  @param handler Function to run upon external interrupt trigger. - *  @param mode Type of transition to trigger on, eg falling, rising, etc. - * - *  @sideeffect Registers a handler - */ -void attachInterrupt(uint8 pin, voidFuncPtr handler, uint32 mode) { +/* Attach ISR handler on pin, triggering on the given mode. */ +void attachInterrupt(uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode) {      uint8 outMode;      /* Parameter checking */ @@ -65,6 +56,7 @@ void attachInterrupt(uint8 pin, voidFuncPtr handler, uint32 mode) {          outMode = EXTI_RISING_FALLING;          break;      default: +        ASSERT(0);          return;      } @@ -76,11 +68,7 @@ void attachInterrupt(uint8 pin, voidFuncPtr handler, uint32 mode) {      return;  } -/** - * @brief Disable an external interrupt - * @param pin maple pin number - * @sideeffect unregisters external interrupt handler - */ +/* Disable any interrupts */  void detachInterrupt(uint8 pin) {      if (!(pin < NR_GPIO_PINS)) {          return; diff --git a/wirish/ext_interrupts.h b/wirish/ext_interrupts.h index fef8c8f..80e2e9e 100644 --- a/wirish/ext_interrupts.h +++ b/wirish/ext_interrupts.h @@ -22,6 +22,8 @@   * THE SOFTWARE.   *****************************************************************************/ +#include "libmaple_types.h" +  /**   *  @file ext_interrupts.h   * @@ -31,17 +33,44 @@  #ifndef _EXT_INTERRUPTS_H_  #define _EXT_INTERRUPTS_H_ -enum { -    RISING, -    FALLING, -    CHANGE -}; +/** + * The kind transition on an external pin which should trigger an + * interrupt. + */ +typedef enum ExtIntTriggerMode_ { +    RISING, /**< To trigger an interrupt when the pin transitions LOW +               to HIGH */ +    FALLING, /**< To trigger an interrupt when the pin transitions +                HIGH to LOW */ +    CHANGE /**< To trigger an interrupt when the pin transitions from +              LOW to HIGH or HIGH to LOW (i.e., when the pin +              changes). */ +} ExtIntTriggerMode;  #ifdef __cplusplus  extern "C"{  #endif -void attachInterrupt(uint8 pin, voidFuncPtr, uint32 mode); +/** + *  @brief Registers an interrupt handler on a pin. + * + *  The interrupt will be triggered on a given transition on the pin, + *  as specified by the mode parameter.  The handler runs in interrupt + *  context. + * + *  @param pin Maple pin number + *  @param handler Function to run upon external interrupt trigger. + *  @param mode Type of transition to trigger on, e.g. falling, rising, etc. + * + *  @sideeffect Registers a handler + */ +void attachInterrupt(uint8 pin, voidFuncPtr handler, ExtIntTriggerMode mode); + +/** + * @brief Disable any registered external interrupt. + * @param pin Maple pin number + * @sideeffect unregisters external interrupt handler + */  void detachInterrupt(uint8 pin);  #ifdef __cplusplus diff --git a/wirish/io.h b/wirish/io.h index 647e79c..f82e414 100644 --- a/wirish/io.h +++ b/wirish/io.h @@ -38,54 +38,125 @@  extern "C"{  #endif +/** + * 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 device's silkscreen and and the GPIO documentation for + * more information. + * + * @see pinMode() + */  typedef enum WiringPinMode { -    OUTPUT, -    OUTPUT_OPEN_DRAIN, -    INPUT, -    INPUT_ANALOG, -    INPUT_PULLUP, -    INPUT_PULLDOWN, -    INPUT_FLOATING, -    PWM, -    PWM_OPEN_DRAIN, +    OUTPUT, /**< Basic digital output: when the pin is HIGH, the +               voltage is held at +3.3v (Vcc) and when it is LOW, it +               is pulled down to ground. */ + +    OUTPUT_OPEN_DRAIN, /**< In open drain mode, the pin indicates +                          "low" by accepting current flow to ground +                          and "high" by providing increased +                          impedance. An example use would be to +                          connect a pin to a bus line (which is pulled +                          up to a positive voltage by a separate +                          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 +                          "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/ +                          from the pin. */ + +    INPUT, /**< Basic digital input. The pin voltage is sampled; when +              it is closer to 3.3v (Vcc) the pin status is high, and +              when it is closer to 0v (ground) it is low. If no +              external circuit is pulling the pin voltage to high or +              low, it will tend to randomly oscillate and be very +              sensitive to noise (eg a breath of air across the pin +              will cause the state to flip). */ + +    INPUT_ANALOG, /**< This is a special mode for when the pin will be +                     used for analog (not digital) reads.  Enables ADC +                     conversion to be performed on the voltage at the +                     pin. */ + +    INPUT_PULLUP, /**< The state of the pin in this mode is reported +                     the same way as with INPUT, but the pin voltage +                     is gently "pulled up" towards +3.3v. This means +                     the state will be high unless an external device +                     is specifically pulling the pin down to ground, +                     in which case the "gentle" pull up will not +                     affect the state of the input. */ + +    INPUT_PULLDOWN, /**< The state of the pin in this mode is reported +                       the same way as with INPUT, but the pin voltage +                       is gently "pulled down" towards 0v. This means +                       the state will be low unless an external device +                       is specifically pulling the pin up to 3.3v, in +                       which case the "gentle" pull down will not +                       effect the state of the input. */ + +    INPUT_FLOATING, /**< Synonym for INPUT. */ + +    PWM, /**< This is a special mode for when the pin will be used for +            PWM output (a special case of digital output). */ + +    PWM_OPEN_DRAIN, /**< Like PWM, except that instead of alternating +                       cycles of LOW and HIGH, the voltage on the pin +                       consists of alternating cycles of LOW and +                       floating (disconnected). */  } 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 mode Mode corresponding to desired pin behavior. + * @see WiringPinMode + */ +void pinMode(uint8 pin, WiringPinMode mode); -/* Set pin to mode - * pinMode(pin, mode): - *     pin -> {0-38, D0-D39, A0-16} - *     mode -> { - *         INPUT/INPUT_DIGITAL - *         INPUT_PULLUP - *         INPUT_PULLDOWN - *         INPUT_ANALOG - *         OUTPUT/OUTPUT_PP - *         OUTPUT_OPEN_DRAIN - *     } +/** + * Writes a (digital) value to a pin.  The pin must have its + * mode set to <code>OUTPUT</code> or <code>OUTPUT_OPEN_DRAIN</code>. + * + * @param pin Pin to write to. One of: 0-38 (pin numbers as labeled + *            on silkscreen), or D0-D38 (symbols for same) + * @param value Either LOW (write a 0) or HIGH (write a 1). + * @see pinMode()   */ -void pinMode(uint8, uint8); - -/* - * Writes VALUE to digital pin[0-38] - * digitalWrite(pin, value): - *     pin -> {0-38, D0-D39, A0-16} - *     value -> LOW, HIGH; -*/ -void digitalWrite(uint8, uint8); - -/* Read a digital value from pin, the pin mode must be set to - * {INPUT, INPUT_PULLUP, INPUT_PULLDOWN} - * digitalRead(pin) - *     pin -> {0-38, D0-D39, A0-16} +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) + * @return LOW or HIGH. + * @see pinMode()   */  uint32 digitalRead(uint8); -/* Read an analog value from pin, the pin mode must be set - * to INPUT_ANALOG - * analogRead(pin) - *     pin -> {A0-A16} +/** + * Read an analog value from pin.  This function blocks during ADC + * conversion.  The pin must have its mode set to INPUT_ANALOG. + * + * @param pin Pin to read from. One of: 0-38 (pin numbers as labeled + *            on silkscreen), or D0-D38 (symbols for same) + * @return ADC-converted voltage, in the range 0--4095, inclusive. + * @see pinMode() + * @see analogReference()   */ -uint32 analogRead(uint8); +uint32 analogRead(uint8 pin);  #ifdef __cplusplus  } // extern "C" diff --git a/wirish/pwm.h b/wirish/pwm.h index fe170cd..6d0ddaf 100644 --- a/wirish/pwm.h +++ b/wirish/pwm.h @@ -36,7 +36,16 @@ extern "C"{  #endif  #define analogWrite pwmWrite -void pwmWrite(uint8, uint16); + +/** + * Set the PWM duty. + * + * User code is expected to determine and honor the maximum value + * (based on the configured period). As a convenience, analogWrite is + * an alias of pwmWrite to ease porting Arduino code, though period + * and duty will have to be recalibrated + */ +void pwmWrite(uint8 pin, uint16 duty_cycle);  #ifdef __cplusplus  } diff --git a/wirish/wirish_digital.c b/wirish/wirish_digital.c index 9298b60..aa22196 100644 --- a/wirish/wirish_digital.c +++ b/wirish/wirish_digital.c @@ -22,8 +22,8 @@   * THE SOFTWARE.   *****************************************************************************/ -/** - *  @brief Arduino-compatible digital I/O implementation. +/* + * Arduino-compatible digital I/O implementation.   */  #include "wirish.h" @@ -73,7 +73,8 @@ void pinMode(uint8 pin, WiringPinMode mode) {      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  */ +        /* 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, | 
