Add microduino variant as copy of maple_mini

This commit is contained in:
Ian Harvey 2014-12-23 10:21:28 +00:00
parent c2d5ac0a1f
commit c5c58e253d
62 changed files with 9260 additions and 0 deletions

View File

@ -313,3 +313,32 @@ maple_STM32.build.error_led_pin=1
maple_STM32.build.gcc_ver=gcc-arm-none-eabi-4.8.3-2014q1
##############################################################
microduino32_flash.name=Microduino Core STM32 to Flash
microduino32_flash.upload.tool=maple_upload
microduino32_flash.upload.protocol=maple_dfu
microduino32_flash.upload.maximum_size=108000
microduino32_flash.upload.use_1200bps_touch=false
microduino32_flash.upload.file_type=bin
microduino32_flash.upload.ram.maximum_size=17000
microduino32_flash.upload.flash.maximum_size=108000
microduino32_flash.upload.usbID=1EAF:0003
microduino32_flash.upload.altID=0
microduino32_flash.upload.auto_reset=true
microduino32_flash.build.mcu=cortex-m3
microduino32_flash.build.f_cpu=72000000L
microduino32_flash.build.core=maple
microduino32_flash.build.extra_flags=-DMCU_STM32F103CB -mthumb -MD -DSTM32_MEDIUM_DENSITY -DBOOTLOADER_maple -march=armv7-m -D__STM32F1XX__
microduino32_flash.build.ldscript=ld/flash.ld
microduino32_flash.build.variant=microduino
microduino32_flash.build.variant_system_lib=libmaple.a
microduino32_flash.build.vect=VECT_TAB_FLASH
microduino32_flash.build.density=STM32_MEDIUM_DENSITY
# FIXME!
microduino32_flash.build.error_led_port=GPIOB
microduino32_flash.build.error_led_pin=1
microduino32_flash.build.gcc_ver=gcc-arm-none-eabi-4.8.3-2014q1

View File

@ -0,0 +1,105 @@
/******************************************************************************
* 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/boards/maple_mini/board.cpp
* @author Marti Bolivar <mbolivar@leaflabs.com>
* @brief Maple Mini board file.
*/
#include <board/board.h>
#include <libmaple/gpio.h>
#include <libmaple/timer.h>
#include <wirish_debug.h>
#include <wirish_types.h>
/* Since we want the Serial Wire/JTAG pins as GPIOs, disable both SW
* and JTAG debug support, unless configured otherwise. */
void boardInit(void) {
#ifndef CONFIG_MAPLE_MINI_NO_DISABLE_DEBUG
disableDebugPorts();
#endif
}
extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = {
/* Top header */
{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, 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, 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 */
{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 */
};
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
};
#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
};

View File

@ -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 wirish/boards/maple_mini/include/board/board.h
* @author Marti Bolivar <mbolivar@leaflabs.com>
* @brief Maple Mini board header.
*
* See wirish/boards/maple/include/board/board.h for more information
* on these definitions.
*/
#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 BOARD_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 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 9
#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
#define BOARD_USB_DISC_DEV GPIOB
#define BOARD_USB_DISC_BIT 9
enum {
PB11, PB10, PB2, PB0, PA7, PA6, PA5, PA4, PA3, PA2, PA1, PA0, PC15, PC14,
PC13, PB7, PB6, PB5, PB4, PB3, PA15, PA14, PA13, PA12, PA11, PA10, PA9,
PA8, PB15, PB14, PB13, PB12, PB8, PB1
};
#endif

View File

@ -0,0 +1,219 @@
/*
* Linker script for libmaple.
*
* Original author "lanchon" from ST forums, with modifications by LeafLabs.
*/
OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
/*
* Configure other libraries we want in the link.
*
* libgcc, libc, and libm are common across supported toolchains.
* However, some toolchains require additional archives which aren't
* present everywhere (e.g. ARM's gcc-arm-embedded releases).
*
* To hack around this, we let the build system specify additional
* archives by putting the right extra_libs.inc (in a directory under
* toolchains/) in our search path.
*/
GROUP(libgcc.a libc.a libm.a)
INCLUDE extra_libs.inc
/*
* These force the linker to search for vector table symbols.
*
* These symbols vary by STM32 family (and also within families).
* It's up to the build system to configure the link's search path
* properly for the target MCU.
*/
INCLUDE vector_symbols.inc
/* STM32 vector table. */
EXTERN(__stm32_vector_table)
/* C runtime initialization function. */
EXTERN(start_c)
/* main entry point */
EXTERN(main)
/* Initial stack pointer value. */
EXTERN(__msp_init)
PROVIDE(__msp_init = ORIGIN(ram) + LENGTH(ram));
/* Reset vector and chip reset entry point */
EXTERN(__start__)
ENTRY(__start__)
PROVIDE(__exc_reset = __start__);
/* Heap boundaries, for libmaple */
EXTERN(_lm_heap_start);
EXTERN(_lm_heap_end);
SECTIONS
{
.text :
{
__text_start__ = .;
/*
* STM32 vector table. Leave this here. Yes, really.
*/
*(.stm32.interrupt_vector)
/*
* Program code and vague linking
*/
*(.text .text.* .gnu.linkonce.t.*)
*(.plt)
*(.gnu.warning)
*(.glue_7t) *(.glue_7) *(.vfp11_veneer)
*(.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))
} > REGION_TEXT
/*
* End of text
*/
.text.align :
{
. = ALIGN(8);
__text_end__ = .;
} > REGION_TEXT
/*
* .ARM.exidx exception unwinding; mandated by ARM's C++ ABI
*/
__exidx_start = .;
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > REGION_RODATA
__exidx_end = .;
/*
* .data
*/
.data :
{
. = ALIGN(8);
__data_start__ = .;
*(.got.plt) *(.got)
*(.data .data.* .gnu.linkonce.d.*)
. = ALIGN(8);
__data_end__ = .;
} > REGION_DATA AT> REGION_RODATA
/*
* Read-only data
*/
.rodata :
{
*(.rodata .rodata.* .gnu.linkonce.r.*)
/* .USER_FLASH: We allow users to allocate into Flash here */
*(.USER_FLASH)
/* ROM image configuration; for C startup */
. = ALIGN(4);
_lm_rom_img_cfgp = .;
LONG(LOADADDR(.data));
/*
* Heap: Linker scripts may choose a custom heap by overriding
* _lm_heap_start and _lm_heap_end. Otherwise, the heap is in
* internal SRAM, beginning after .bss, and growing towards
* the stack.
*
* I'm shoving these here naively; there's probably a cleaner way
* to go about this. [mbolivar]
*/
_lm_heap_start = DEFINED(_lm_heap_start) ? _lm_heap_start : _end;
_lm_heap_end = DEFINED(_lm_heap_end) ? _lm_heap_end : __msp_init;
} > REGION_RODATA
/*
* .bss
*/
.bss :
{
. = ALIGN(8);
__bss_start__ = .;
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
. = ALIGN (8);
__bss_end__ = .;
_end = __bss_end__;
} > REGION_BSS
/*
* 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) }
}

View File

@ -0,0 +1,7 @@
/*
* Extra archives needed by ARM's GCC ARM Embedded arm-none-eabi-
* releases (https://launchpad.net/gcc-arm-embedded/).
*/
/* This is for the provided newlib. */
GROUP(libnosys.a)

View File

@ -0,0 +1,26 @@
/*
* libmaple linker script for "Flash" builds.
*
* A Flash build puts .text (and .rodata) in Flash, and
* .data/.bss/heap (of course) in SRAM, but offsets the sections by
* enough space to store the Maple bootloader, which lives in low
* Flash and uses low memory.
*/
/*
* This pulls in the appropriate MEMORY declaration from the right
* subdirectory of stm32/mem/ (the environment must call ld with the
* right include directory flags to make this happen). Boards can also
* use this file to use any of libmaple's memory-related hooks (like
* where the heap should live).
*/
INCLUDE mem-flash.inc
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", rom);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", rom);
/* Let common.inc handle the real work. */
INCLUDE common.inc

View File

@ -0,0 +1,33 @@
/*
* libmaple linker script for "Flash" builds.
*
* A Flash build puts .text (and .rodata) in Flash, and
* .data/.bss/heap (of course) in SRAM, but offsets the sections by
* enough space to store the Maple bootloader, which lives in low
* Flash and uses low memory.
*/
/*
* This pulls in the appropriate MEMORY declaration from the right
* subdirectory of stm32/mem/ (the environment must call ld with the
* right include directory flags to make this happen). Boards can also
* use this file to use any of libmaple's memory-related hooks (like
* where the heap should live).
*/
/*INCLUDE mem-flash.inc*/
MEMORY
{
ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K
rom (rx) : ORIGIN = 0x08005000, LENGTH = 44K
}
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", rom);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", rom);
/* Let common.inc handle the real work. */
INCLUDE common.inc

View File

@ -0,0 +1,31 @@
/*
* libmaple linker script for "JTAG" builds.
*
* A "JTAG" build puts .text (and .rodata) in Flash, and
* .data/.bss/heap (of course) in SRAM, but links starting at the
* Flash and SRAM starting addresses (0x08000000 and 0x20000000
* respectively). This will wipe out a Maple bootloader if there's one
* on the board, so only use this if you know what you're doing.
*
* Of course, a "JTAG" build is perfectly usable for upload over SWD,
* the system memory bootloader, etc. The name is just a historical
* artifact.
*/
/*
* This pulls in the appropriate MEMORY declaration from the right
* subdirectory of stm32/mem/ (the environment must call ld with the
* right include directory flags to make this happen). Boards can also
* use this file to use any of libmaple's memory-related hooks (like
* where the heap should live).
*/
INCLUDE mem-jtag.inc
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", rom);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", rom);
/* Let common.inc handle the real work. */
INCLUDE common.inc

View File

@ -0,0 +1,37 @@
/*
* libmaple linker script for "JTAG" builds.
*
* A "JTAG" build puts .text (and .rodata) in Flash, and
* .data/.bss/heap (of course) in SRAM, but links starting at the
* Flash and SRAM starting addresses (0x08000000 and 0x20000000
* respectively). This will wipe out a Maple bootloader if there's one
* on the board, so only use this if you know what you're doing.
*
* Of course, a "JTAG" build is perfectly usable for upload over SWD,
* the system memory bootloader, etc. The name is just a historical
* artifact.
*/
/*
* This pulls in the appropriate MEMORY declaration from the right
* subdirectory of stm32/mem/ (the environment must call ld with the
* right include directory flags to make this happen). Boards can also
* use this file to use any of libmaple's memory-related hooks (like
* where the heap should live).
*/
/*INCLUDE mem-jtag.inc*/
MEMORY
{
ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 20K
rom (rx) : ORIGIN = 0x08005000, LENGTH = 64K
}
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", rom);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", rom);
/* Let common.inc handle the real work. */
INCLUDE common.inc

View File

@ -0,0 +1,5 @@
MEMORY
{
ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K
rom (rx) : ORIGIN = 0x08005000, LENGTH = 108K
}

View File

@ -0,0 +1,5 @@
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K
}

View File

@ -0,0 +1,5 @@
MEMORY
{
ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K
rom (rx) : ORIGIN = 0x08005000, LENGTH = 0K
}

View File

@ -0,0 +1,25 @@
/*
* libmaple linker script for RAM builds.
*
* A Flash build puts .text, .rodata, and .data/.bss/heap (of course)
* in SRAM, but offsets the sections by enough space to store the
* Maple bootloader, which uses low memory.
*/
/*
* This pulls in the appropriate MEMORY declaration from the right
* subdirectory of stm32/mem/ (the environment must call ld with the
* right include directory flags to make this happen). Boards can also
* use this file to use any of libmaple's memory-related hooks (like
* where the heap should live).
*/
INCLUDE mem-ram.inc
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", ram);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", ram);
/* Let common.inc handle the real work. */
INCLUDE common.inc

View File

@ -0,0 +1,31 @@
/*
* libmaple linker script for RAM builds.
*
* A Flash build puts .text, .rodata, and .data/.bss/heap (of course)
* in SRAM, but offsets the sections by enough space to store the
* Maple bootloader, which uses low memory.
*/
/*
* This pulls in the appropriate MEMORY declaration from the right
* subdirectory of stm32/mem/ (the environment must call ld with the
* right include directory flags to make this happen). Boards can also
* use this file to use any of libmaple's memory-related hooks (like
* where the heap should live).
*/
/*INCLUDE mem-ram.inc*/
MEMORY
{
ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K
rom (rx) : ORIGIN = 0x08005000, LENGTH = 0
}
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", ram);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", ram);
/* Let common.inc handle the real work. */
INCLUDE common.inc

View File

@ -0,0 +1,78 @@
EXTERN(__msp_init)
EXTERN(__exc_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(__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_dma1_channel1)
EXTERN(__irq_dma1_channel2)
EXTERN(__irq_dma1_channel3)
EXTERN(__irq_dma1_channel4)
EXTERN(__irq_dma1_channel5)
EXTERN(__irq_dma1_channel6)
EXTERN(__irq_dma1_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)

View File

@ -0,0 +1,109 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 Perry Hung.
* Copyright (c) 2011, 2012 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 libmaple/adc.c
* @author Marti Bolivar <mbolivar@leaflabs.com>,
* Perry Hung <perry@leaflabs.com>
* @brief Analog to digital converter routines
*/
#include <libmaple/adc.h>
#include <libmaple/libmaple.h>
#include <libmaple/rcc.h>
/**
* @brief Initialize an ADC peripheral.
*
* Initializes the RCC clock line for the given peripheral. Resets
* ADC device registers.
*
* @param dev ADC peripheral to initialize
*/
void adc_init(const adc_dev *dev) {
rcc_clk_enable(dev->clk_id);
rcc_reset_dev(dev->clk_id);
}
/**
* @brief Set external event select for regular group
* @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, adc_extsel_event event) {
uint32 cr2 = dev->regs->CR2;
cr2 &= ~ADC_CR2_EXTSEL;
cr2 |= event;
dev->regs->CR2 = cr2;
}
/**
* @brief Set the sample rate for all channels on an ADC device.
*
* Don't call this during conversion.
*
* @param dev adc device
* @param smp_rate sample rate to set
* @see adc_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] */
adc_smpr1_val |= smp_rate << (i * 3);
}
/* ADC_SMPR2 determines sample time for channels [0,9] */
adc_smpr2_val |= smp_rate << (i * 3);
}
dev->regs->SMPR1 = adc_smpr1_val;
dev->regs->SMPR2 = adc_smpr2_val;
}
/**
* @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);
}

View File

@ -0,0 +1,115 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2012 LeafLabs, LLC.
* 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 libmaple/stm32f1/adc.c
* @author Marti Bolivar <mbolivar@leaflabs.com>,
* Perry Hung <perry@leaflabs.com>
* @brief STM32F1 ADC support.
*/
#include <libmaple/adc.h>
#include <libmaple/gpio.h>
/*
* Devices
*/
static adc_dev adc1 = {
.regs = ADC1_BASE,
.clk_id = RCC_ADC1,
};
/** ADC1 device. */
const adc_dev *ADC1 = &adc1;
static adc_dev adc2 = {
.regs = ADC2_BASE,
.clk_id = RCC_ADC2,
};
/** ADC2 device. */
const adc_dev *ADC2 = &adc2;
#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
static adc_dev adc3 = {
.regs = ADC3_BASE,
.clk_id = RCC_ADC3,
};
/** ADC3 device. */
const adc_dev *ADC3 = &adc3;
#endif
/*
* STM32F1 routines
*/
/**
* @brief Calibrate an ADC peripheral
*
* Availability: STM32F1.
*
* @param dev adc device
*/
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);
*rstcal_bit = 1;
while (*rstcal_bit)
;
*cal_bit = 1;
while (*cal_bit)
;
}
/*
* Common routines
*/
void adc_set_prescaler(adc_prescaler pre) {
rcc_set_prescaler(RCC_PRESCALER_ADC, (uint32)pre);
}
void adc_foreach(void (*fn)(const adc_dev*)) {
fn(ADC1);
fn(ADC2);
#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
fn(ADC3);
#endif
}
void adc_config_gpio(const adc_dev *ignored, gpio_dev *gdev, uint8 bit) {
gpio_set_mode(gdev, bit, GPIO_INPUT_ANALOG);
}
void adc_enable_single_swstart(const adc_dev *dev) {
adc_init(dev);
adc_set_extsel(dev, ADC_SWSTART);
adc_set_exttrig(dev, 1);
adc_enable(dev);
adc_calibrate(dev);
}

View File

@ -0,0 +1,129 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 LeafLabs, LLC.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*****************************************************************************/
/**
* @file libmaple/stm32f1/bkp.c
* @brief STM32F1 Backup register support.
*/
#include <libmaple/bkp.h>
#include <libmaple/pwr.h>
#include <libmaple/rcc.h>
#include <libmaple/bitband.h>
static inline __io uint32* data_register(uint8 reg);
bkp_dev bkp = {
.regs = BKP_BASE,
};
/** Backup device. */
const bkp_dev *BKP = &bkp;
/**
* @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) {
*bb_perip(&PWR_BASE->CR, PWR_CR_DBP_BIT) = 1;
}
/**
* Disable write access to the backup registers.
*/
void bkp_disable_writes(void) {
*bb_perip(&PWR_BASE->CR, PWR_CR_DBP_BIT) = 0;
}
/**
* Read a value from given backup data register.
* @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);
if (!dr) {
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 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()
*/
void bkp_write(uint8 reg, uint16 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)--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 > BKP_NR_DATA_REGS) {
return 0;
}
#if BKP_NR_DATA_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);
}
#endif
}

View File

@ -0,0 +1,120 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 Bryan Newbold.
* Copyright (c) 2011, 2012 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 libmaple/dac.c
* @brief Digital to analog converter support.
*/
#include <libmaple/dac.h>
#include <libmaple/libmaple.h>
#include <libmaple/gpio.h>
#if STM32_HAVE_DAC
dac_dev dac = {
.regs = DAC_BASE,
};
const dac_dev *DAC = &dac;
#endif
/**
* @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(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(dev, 1);
}
if (flags & DAC_CH2) {
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(const dac_dev *dev, uint8 channel, uint16 val) {
switch(channel) {
case 1:
dev->regs->DHR12R1 = DAC_DHR12R1_DACC1DHR & val;
break;
case 2:
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(const dac_dev *dev, uint8 channel) {
/*
* Setup ANALOG mode on PA4 and PA5. This mapping is consistent
* across all supported STM32s with a DAC.
*/
switch (channel) {
case 1:
gpio_set_mode(GPIOA, 4, GPIO_MODE_ANALOG);
dev->regs->CR |= DAC_CR_EN1;
break;
case 2:
gpio_set_mode(GPIOA, 5, GPIO_MODE_ANALOG);
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(const dac_dev *dev, uint8 channel) {
switch (channel) {
case 1:
dev->regs->CR &= ~DAC_CR_EN1;
break;
case 2:
dev->regs->CR &= ~DAC_CR_EN2;
break;
}
}

View File

@ -0,0 +1,82 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 Michael Hope.
* Copyright (c) 2012 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 libmaple/dma.c
* @author Marti Bolivar <mbolivar@leaflabs.com>;
* Original implementation by Michael Hope
* @brief Portable DMA routines.
*/
#include <libmaple/dma.h>
#include "dma_private.h"
#include "stm32_private.h"
/*
* Convenience routines
*/
/**
* @brief Initialize a DMA device.
* @param dev Device to initialize.
*/
void dma_init(dma_dev *dev) {
rcc_clk_enable(dev->clk_id);
}
/*
* Private API
*/
enum dma_atype _dma_addr_type(__io void *addr) {
switch (stm32_block_purpose((void*)addr)) {
/* Notice we're treating the code block as memory here. That's
* correct for addresses in Flash and in [0x0, 0x7FFFFFF]
* (provided that those addresses are aliased to Flash, SRAM, or
* FSMC, depending on BOOT[01] and possibly SYSCFG_MEMRMP). It's
* not correct for other addresses in the code block, but those
* will (hopefully) just fail-fast with transfer or bus errors. If
* lots of people get confused, it might be worth being more
* careful here. */
case STM32_BLOCK_CODE: /* Fall through */
case STM32_BLOCK_SRAM: /* ... */
case STM32_BLOCK_FSMC_1_2: /* ... */
case STM32_BLOCK_FSMC_3_4:
return DMA_ATYPE_MEM;
case STM32_BLOCK_PERIPH:
return DMA_ATYPE_PER;
case STM32_BLOCK_FSMC_REG: /* Fall through */
/* Is this right? I can't think of a reason to DMA into or out
* of the FSMC registers. [mbolivar] */
case STM32_BLOCK_UNUSED: /* ... */
case STM32_BLOCK_CORTEX_INTERNAL: /* ... */
return DMA_ATYPE_OTHER;
default:
ASSERT(0); /* Can't happen */
return DMA_ATYPE_OTHER;
}
}

View File

@ -0,0 +1,413 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 Michael Hope.
* Copyright (c) 2012 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 libmaple/stm32f1/dma.c
* @author Marti Bolivar <mbolivar@leaflabs.com>;
* Original implementation by Michael Hope
* @brief STM32F1 DMA support.
*/
#include <libmaple/dma.h>
#include <libmaple/bitband.h>
/* Hack to ensure inlining in dma_irq_handler() */
#define DMA_GET_HANDLER(dev, tube) (dev->handlers[tube - 1].handler)
#include "dma_private.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 }},
};
/** STM32F1 DMA1 device */
dma_dev *DMA1 = &dma1;
#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_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 }}, /* !@#$ */
};
/** STM32F1 DMA2 device */
dma_dev *DMA2 = &dma2;
#endif
/*
* Auxiliary routines
*/
/* Can channel serve cfg->tube_req_src? */
static int cfg_req_ok(dma_channel channel, dma_tube_config *cfg) {
return (cfg->tube_req_src & 0x7) == channel;
}
/* Can dev serve cfg->tube_req_src? */
static int cfg_dev_ok(dma_dev *dev, dma_tube_config *cfg) {
return (rcc_clk_id)(cfg->tube_req_src >> 3) == dev->clk_id;
}
/* Is addr acceptable for use as DMA src/dst? */
static int cfg_mem_ok(__io void *addr) {
enum dma_atype atype = _dma_addr_type(addr);
return atype == DMA_ATYPE_MEM || atype == DMA_ATYPE_PER;
}
/* Is the direction implied by src->dst supported? */
static int cfg_dir_ok(dma_tube_config *cfg) {
/* We can't do peripheral->peripheral transfers. */
return ((_dma_addr_type(cfg->tube_src) == DMA_ATYPE_MEM) ||
(_dma_addr_type(cfg->tube_dst) == DMA_ATYPE_MEM));
}
static int preconfig_check(dma_dev *dev, dma_channel channel,
dma_tube_config *cfg) {
if (!cfg_req_ok(channel, cfg)) {
return -DMA_TUBE_CFG_EREQ;
}
if (cfg->tube_nr_xfers > 65535) {
return -DMA_TUBE_CFG_ENDATA;
}
if (!cfg_dev_ok(dev, cfg)) {
return -DMA_TUBE_CFG_EDEV;
}
if (!cfg_mem_ok(cfg->tube_src)) {
return -DMA_TUBE_CFG_ESRC;
}
if (!cfg_mem_ok(cfg->tube_dst)) {
return -DMA_TUBE_CFG_EDST;
}
if (!cfg_dir_ok(cfg)) {
return -DMA_TUBE_CFG_EDIR;
}
return DMA_TUBE_CFG_SUCCESS;
}
static inline void set_ccr(dma_tube_reg_map *chregs,
dma_xfer_size msize, int minc,
dma_xfer_size psize, int pinc,
uint32 other_flags) {
chregs->CCR = ((msize << 10) | (psize << 8) |
(minc ? DMA_CCR_MINC : 0) | (pinc ? DMA_CCR_PINC : 0) |
other_flags);
}
static inline uint32 cfg_ccr_flags(unsigned tube_flags) {
/* DMA_CFG_SRC_INC and DMA_CFG_DST_INC are special */
return tube_flags & ~(DMA_CFG_SRC_INC | DMA_CFG_DST_INC);
}
/* Configure chregs according to cfg, where cfg->tube_dst is peripheral. */
static int config_to_per(dma_tube_reg_map *chregs, dma_tube_config *cfg) {
/* Check that ->tube_src is memory (if it's anything else, we
* shouldn't have been called). */
ASSERT(_dma_addr_type(cfg->tube_src) == DMA_ATYPE_MEM);
set_ccr(chregs,
cfg->tube_src_size, cfg->tube_flags & DMA_CFG_SRC_INC,
cfg->tube_dst_size, cfg->tube_flags & DMA_CFG_DST_INC,
(cfg_ccr_flags(cfg->tube_flags) | DMA_CCR_DIR_FROM_MEM));
chregs->CNDTR = cfg->tube_nr_xfers;
chregs->CMAR = (uint32)cfg->tube_src;
chregs->CPAR = (uint32)cfg->tube_dst;
return DMA_TUBE_CFG_SUCCESS;
}
/* Configure chregs according to cfg, where cfg->tube_dst is memory. */
static int config_to_mem(dma_tube_reg_map *chregs, dma_tube_config *cfg) {
uint32 mem2mem;
if ((_dma_addr_type(cfg->tube_src) == DMA_ATYPE_MEM) &&
(cfg->tube_flags & DMA_CFG_CIRC)) {
/* Can't do mem-to-mem and circular mode */
return -DMA_TUBE_CFG_ECFG;
}
mem2mem = (_dma_addr_type(cfg->tube_src) == DMA_ATYPE_MEM ?
DMA_CCR_MEM2MEM : 0);
set_ccr(chregs,
cfg->tube_dst_size, cfg->tube_flags & DMA_CFG_DST_INC,
cfg->tube_src_size, cfg->tube_flags & DMA_CFG_SRC_INC,
(cfg_ccr_flags(cfg->tube_flags) |
DMA_CCR_DIR_FROM_PER |
mem2mem));
chregs->CNDTR = cfg->tube_nr_xfers;
chregs->CMAR = (uint32)cfg->tube_dst;
chregs->CPAR = (uint32)cfg->tube_src;
return DMA_TUBE_CFG_SUCCESS;
}
/*
* Routines
*/
int dma_tube_cfg(dma_dev *dev, dma_channel channel, dma_tube_config *cfg) {
dma_tube_reg_map *chregs;
int ret = preconfig_check(dev, channel, cfg);
if (ret < 0) {
return ret;
}
dma_disable(dev, channel); /* Must disable before reconfiguring */
dma_clear_isr_bits(dev, channel); /* For sanity and consistency
* with STM32F2. */
chregs = dma_tube_regs(dev, channel);
switch (_dma_addr_type(cfg->tube_dst)) {
case DMA_ATYPE_PER:
ret = config_to_per(chregs, cfg);
break;
case DMA_ATYPE_MEM:
ret = config_to_mem(chregs, cfg);
break;
default:
/* Can't happen */
ASSERT(0);
return -DMA_TUBE_CFG_ECFG;
}
if (ret < 0) {
return ret;
}
chregs->CNDTR = cfg->tube_nr_xfers;
return DMA_TUBE_CFG_SUCCESS;
}
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 << 12);
channel_regs->CCR = ccr;
}
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 dma_attach_interrupt(dma_dev *dev, dma_channel channel,
void (*handler)(void)) {
DMA_GET_HANDLER(dev, channel) = handler;
nvic_irq_enable(dev->handlers[channel - 1].irq_line);
}
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;
DMA_GET_HANDLER(dev, channel) = NULL;
}
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 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);
}
dma_irq_cause dma_get_irq_cause(dma_dev *dev, dma_channel channel) {
/* Grab and clear the ISR bits. */
uint8 status_bits = dma_get_isr_bits(dev, channel);
dma_clear_isr_bits(dev, channel);
/* If the channel global interrupt flag is cleared, then
* something's very wrong. */
ASSERT(status_bits & 0x1);
/* If GIF is set, then some other flag should be set, barring
* something unexpected (e.g. the user making an unforeseen IFCR
* write). */
ASSERT(status_bits != 0x1);
/* 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 & 0x8) {
return DMA_TRANSFER_ERROR;
} else if (status_bits & 0x2) {
return DMA_TRANSFER_COMPLETE;
} else if (status_bits & 0x4) {
return DMA_TRANSFER_HALF_COMPLETE;
}
/* If we get here, one of our assumptions has been violated, but
* the debug level is too low for the above ASSERTs() 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;
}
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_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));
chan_regs = dma_channel_regs(dev, channel);
chan_regs->CPAR = (uint32)addr;
}
/**
* @brief Deprecated. Use dma_tube_cfg() instead.
*
* 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
*
* @see dma_tube_cfg()
*
* @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()
*/
__deprecated
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;
}
/*
* IRQ handlers
*/
void __irq_dma1_channel1(void) {
dma_irq_handler(DMA1, DMA_CH1);
}
void __irq_dma1_channel2(void) {
dma_irq_handler(DMA1, DMA_CH2);
}
void __irq_dma1_channel3(void) {
dma_irq_handler(DMA1, DMA_CH3);
}
void __irq_dma1_channel4(void) {
dma_irq_handler(DMA1, DMA_CH4);
}
void __irq_dma1_channel5(void) {
dma_irq_handler(DMA1, DMA_CH5);
}
void __irq_dma1_channel6(void) {
dma_irq_handler(DMA1, DMA_CH6);
}
void __irq_dma1_channel7(void) {
dma_irq_handler(DMA1, DMA_CH7);
}
#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
void __irq_dma2_channel1(void) {
dma_irq_handler(DMA2, DMA_CH1);
}
void __irq_dma2_channel2(void) {
dma_irq_handler(DMA2, DMA_CH2);
}
void __irq_dma2_channel3(void) {
dma_irq_handler(DMA2, DMA_CH3);
}
void __irq_dma2_channel4_5(void) {
if ((DMA2_BASE->CCR4 & DMA_CCR_EN) && (DMA2_BASE->ISR & DMA_ISR_GIF4)) {
dma_irq_handler(DMA2, DMA_CH4);
}
if ((DMA2_BASE->CCR5 & DMA_CCR_EN) && (DMA2_BASE->ISR & DMA_ISR_GIF5)) {
dma_irq_handler(DMA2, DMA_CH5);
}
}
#endif

View File

@ -0,0 +1,101 @@
/* *****************************************************************************
* 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.
* ****************************************************************************/
# On an exception, push a fake stack thread mode stack frame and redirect
# thread execution to a thread mode error handler
# From RM008:
# The SP is decremented by eight words by the completion of the stack push.
# Figure 5-1 shows the contents of the stack after an exception pre-empts the
# current program flow.
#
# Old SP--> <previous>
# xPSR
# PC
# LR
# r12
# r3
# r2
# r1
# SP--> r0
.text
.globl __exc_hardfault
.globl __exc_nmi
.globl __exc_hardfault
.globl __exc_memmanage
.globl __exc_busfault
.globl __exc_usagefault
.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
.thumb_func
__default_exc:
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
mov r1, #0
str r1, [r2]
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
SYSTICK_CSR: .word 0xE000E010 @ Systick control register

View File

@ -0,0 +1,292 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 Perry Hung.
* Copyright (c) 2011, 2012 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 libmaple/exti.c
* @brief External interrupt control routines
*/
#include <libmaple/exti.h>
#include <libmaple/libmaple.h>
#include <libmaple/nvic.h>
#include <libmaple/bitband.h>
static inline void dispatch_single_exti(uint32 exti_num);
static inline void dispatch_extis(uint32 start, uint32 stop);
/*
* Internal state
*/
typedef struct exti_channel {
void (*handler)(void *);
void *arg;
} exti_channel;
static exti_channel exti_channels[] = {
{ .handler = NULL, .arg = NULL }, // EXTI0
{ .handler = NULL, .arg = NULL }, // EXTI1
{ .handler = NULL, .arg = NULL }, // EXTI2
{ .handler = NULL, .arg = NULL }, // EXTI3
{ .handler = NULL, .arg = NULL }, // EXTI4
{ .handler = NULL, .arg = NULL }, // EXTI5
{ .handler = NULL, .arg = NULL }, // EXTI6
{ .handler = NULL, .arg = NULL }, // EXTI7
{ .handler = NULL, .arg = NULL }, // EXTI8
{ .handler = NULL, .arg = NULL }, // EXTI9
{ .handler = NULL, .arg = NULL }, // EXTI10
{ .handler = NULL, .arg = NULL }, // EXTI11
{ .handler = NULL, .arg = NULL }, // EXTI12
{ .handler = NULL, .arg = NULL }, // EXTI13
{ .handler = NULL, .arg = NULL }, // EXTI14
{ .handler = NULL, .arg = NULL }, // EXTI15
};
/*
* Portable routines
*/
/**
* @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_cfg
* @see voidFuncPtr
* @see exti_trigger_mode
*/
void exti_attach_interrupt(exti_num num,
exti_cfg port,
voidFuncPtr handler,
exti_trigger_mode mode) {
// Call callback version with arg being null
exti_attach_callback(num, port, (voidArgumentFuncPtr)handler, NULL, mode);
}
/**
* @brief Register a handler with an argument 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 arg Argument to pass to the interrupt handler.
* @param mode Type of transition to trigger on, one of:
* EXTI_RISING, EXTI_FALLING, EXTI_RISING_FALLING.
* @see exti_num
* @see exti_cfg
* @see voidFuncPtr
* @see exti_trigger_mode
*/
void exti_attach_callback(exti_num num,
exti_cfg port,
voidArgumentFuncPtr handler,
void *arg,
exti_trigger_mode mode) {
ASSERT(handler);
/* Register the handler */
exti_channels[num].handler = handler;
exti_channels[num].arg = arg;
/* Set trigger mode */
switch (mode) {
case EXTI_RISING:
bb_peri_set_bit(&EXTI_BASE->RTSR, num, 1);
break;
case EXTI_FALLING:
bb_peri_set_bit(&EXTI_BASE->FTSR, num, 1);
break;
case EXTI_RISING_FALLING:
bb_peri_set_bit(&EXTI_BASE->RTSR, num, 1);
bb_peri_set_bit(&EXTI_BASE->FTSR, num, 1);
break;
}
/* Use the chip-specific exti_select() to map num to port */
exti_select(num, port);
/* Unmask external interrupt request */
bb_peri_set_bit(&EXTI_BASE->IMR, num, 1);
/* Enable the interrupt line */
switch(num)
{
case EXTI0:
nvic_irq_enable(NVIC_EXTI0);
break;
case EXTI1:
nvic_irq_enable(NVIC_EXTI1);
break;
case EXTI2:
nvic_irq_enable(NVIC_EXTI2);
break;
case EXTI3:
nvic_irq_enable(NVIC_EXTI3);
break;
case EXTI4:
nvic_irq_enable(NVIC_EXTI4);
break;
case EXTI5:
case EXTI6:
case EXTI7:
case EXTI8:
case EXTI9:
nvic_irq_enable(NVIC_EXTI_9_5);
break;
case EXTI10:
case EXTI11:
case EXTI12:
case EXTI13:
case EXTI14:
case EXTI15:
nvic_irq_enable(NVIC_EXTI_15_10);
break;
}
}
/**
* @brief Unregister an external interrupt handler
* @param num External interrupt line to disable.
* @see exti_num
*/
void exti_detach_interrupt(exti_num num) {
/* First, mask the interrupt request */
bb_peri_set_bit(&EXTI_BASE->IMR, num, 0);
/* Then, clear the trigger selection registers */
bb_peri_set_bit(&EXTI_BASE->FTSR, num, 0);
bb_peri_set_bit(&EXTI_BASE->RTSR, num, 0);
/* Finally, unregister the user's handler */
exti_channels[num].handler = NULL;
exti_channels[num].arg = NULL;
}
/*
* Private routines
*/
void exti_do_select(__io uint32 *exti_cr, exti_num num, exti_cfg port) {
uint32 shift = 4 * (num % 4);
uint32 cr = *exti_cr;
cr &= ~(0xF << shift);
cr |= port << shift;
*exti_cr = cr;
}
/*
* Interrupt handlers
*/
void __irq_exti0(void) {
dispatch_single_exti(EXTI0);
}
void __irq_exti1(void) {
dispatch_single_exti(EXTI1);
}
void __irq_exti2(void) {
dispatch_single_exti(EXTI2);
}
void __irq_exti3(void) {
dispatch_single_exti(EXTI3);
}
void __irq_exti4(void) {
dispatch_single_exti(EXTI4);
}
void __irq_exti9_5(void) {
dispatch_extis(5, 9);
}
void __irq_exti15_10(void) {
dispatch_extis(10, 15);
}
/*
* Auxiliary functions
*/
/* Clear the pending bits for EXTIs whose bits are set in exti_msk.
*
* If a 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. To
* compensate, this function NOPs for 2 cycles after clearing the
* pending bits to ensure it takes effect. */
static __always_inline void clear_pending_msk(uint32 exti_msk) {
EXTI_BASE->PR = exti_msk;
asm volatile("nop");
asm volatile("nop");
}
/* This dispatch routine is for non-multiplexed EXTI lines only; i.e.,
* it doesn't check EXTI_PR. */
static __always_inline void dispatch_single_exti(uint32 exti) {
voidArgumentFuncPtr handler = exti_channels[exti].handler;
if (!handler) {
return;
}
handler(exti_channels[exti].arg);
clear_pending_msk(1U << exti);
}
/* Dispatch routine for EXTIs which share an IRQ. */
static __always_inline void dispatch_extis(uint32 start, uint32 stop) {
uint32 pr = EXTI_BASE->PR;
uint32 handled_msk = 0;
uint32 exti;
/* Dispatch user handlers for pending EXTIs. */
for (exti = start; exti <= stop; exti++) {
uint32 eb = (1U << exti);
if (pr & eb) {
voidArgumentFuncPtr handler = exti_channels[exti].handler;
if (handler) {
handler(exti_channels[exti].arg);
handled_msk |= eb;
}
}
}
/* Clear the pending bits for handled EXTIs. */
clear_pending_msk(handled_msk);
}

View File

@ -0,0 +1,32 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2012 LeafLabs, LLC.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*****************************************************************************/
#include <libmaple/gpio.h>
#include "exti_private.h"
void exti_select(exti_num num, exti_cfg port) {
exti_do_select(&AFIO_BASE->EXTICR1 + num / 4, num, port);
}

View File

@ -0,0 +1,55 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 Perry Hung.
* Copyright (c) 2011, 2012 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 libmaple/flash.c
* @brief Flash management functions
*/
#include <libmaple/libmaple_types.h>
#include <libmaple/flash.h>
/**
* @brief Set flash wait states
*
* Note that not all wait states are available on every MCU. See the
* Flash programming manual for your MCU for restrictions on the
* allowed value of wait_states for a given system clock (SYSCLK)
* frequency.
*
* @param wait_states number of wait states (one of
* FLASH_WAIT_STATE_0, FLASH_WAIT_STATE_1,
* ..., FLASH_WAIT_STATE_7).
*/
void flash_set_latency(uint32 wait_states) {
uint32 val = FLASH_BASE->ACR;
val &= ~FLASH_ACR_LATENCY;
val |= wait_states;
FLASH_BASE->ACR = val;
}

View File

@ -0,0 +1,95 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2012 LeafLabs, LLC.
* 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
* 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 libmaple/stm32f1/fsmc.c
* @author Marti Bolivar <mbolivar@leaflabs.com>,
* Bryan Newbold <bnewbold@robocracy.org>
* @brief STM32F1 FSMC support.
*/
#include <libmaple/stm32.h>
#if STM32_HAVE_FSMC /* Don't try building the rest for MCUs without FSMC */
#include <libmaple/fsmc.h>
#include <libmaple/gpio.h>
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);
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, 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, 4, GPIO_AF_OUTPUT_PP); // NOE
gpio_set_mode(GPIOD, 5, GPIO_AF_OUTPUT_PP); // NWE
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, 0, GPIO_AF_OUTPUT_PP); // NBL0
gpio_set_mode(GPIOE, 1, GPIO_AF_OUTPUT_PP); // NBL1
}
#endif /* STM32_HAVE_FSMC */

View File

@ -0,0 +1,50 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 Perry Hung.
* Copyright (c) 2011, 2012 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 libmaple/gpio.c
* @brief Generic STM32 GPIO support.
*/
#include <libmaple/gpio.h>
#include <libmaple/rcc.h>
/*
* GPIO 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);
}

View File

@ -0,0 +1,166 @@
/******************************************************************************
* 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 libmaple/stm32f1/gpio.c
* @brief STM32F1 GPIO support.
*/
#include <libmaple/gpio.h>
#include <libmaple/rcc.h>
/*
* GPIO devices
*/
gpio_dev gpioa = {
.regs = GPIOA_BASE,
.clk_id = RCC_GPIOA,
.exti_port = EXTI_PA,
};
/** GPIO port A device. */
gpio_dev* const GPIOA = &gpioa;
gpio_dev gpiob = {
.regs = GPIOB_BASE,
.clk_id = RCC_GPIOB,
.exti_port = EXTI_PB,
};
/** GPIO port B device. */
gpio_dev* const GPIOB = &gpiob;
gpio_dev gpioc = {
.regs = GPIOC_BASE,
.clk_id = RCC_GPIOC,
.exti_port = EXTI_PC,
};
/** GPIO port C device. */
gpio_dev* const GPIOC = &gpioc;
gpio_dev gpiod = {
.regs = GPIOD_BASE,
.clk_id = RCC_GPIOD,
.exti_port = EXTI_PD,
};
/** GPIO port D device. */
gpio_dev* const GPIOD = &gpiod;
#ifdef STM32_HIGH_DENSITY
gpio_dev gpioe = {
.regs = GPIOE_BASE,
.clk_id = RCC_GPIOE,
.exti_port = EXTI_PE,
};
/** GPIO port E device. */
gpio_dev* const GPIOE = &gpioe;
gpio_dev gpiof = {
.regs = GPIOF_BASE,
.clk_id = RCC_GPIOF,
.exti_port = EXTI_PF,
};
/** GPIO port F device. */
gpio_dev* const GPIOF = &gpiof;
gpio_dev gpiog = {
.regs = GPIOG_BASE,
.clk_id = RCC_GPIOG,
.exti_port = EXTI_PG,
};
/** GPIO port G device. */
gpio_dev* const GPIOG = &gpiog;
#endif
/*
* GPIO routines
*/
/**
* 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
}
/**
* 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 = &regs->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_INPUT_PD) {
regs->ODR &= ~(1U << pin);
} else if (mode == GPIO_INPUT_PU) {
regs->ODR |= (1U << pin);
}
}
/*
* AFIO
*/
/**
* @brief Initialize the AFIO clock, and reset the AFIO registers.
*/
void afio_init(void) {
rcc_clk_enable(RCC_AFIO);
rcc_reset_dev(RCC_AFIO);
}
#define AFIO_EXTI_SEL_MASK 0xF
/**
* @brief Perform an alternate function remap.
* @param remapping Remapping to perform.
*/
void afio_remap(afio_remap_peripheral remapping) {
if (remapping & AFIO_REMAP_USE_MAPR2) {
remapping &= ~AFIO_REMAP_USE_MAPR2;
AFIO_BASE->MAPR2 |= remapping;
} else {
AFIO_BASE->MAPR |= remapping;
}
}

View File

@ -0,0 +1,509 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 Perry Hung.
* Copyright (c) 2012 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 libmaple/i2c.c
* @author Perry Hung <perry@leaflabs.com>
* @brief Inter-Integrated Circuit (I2C) support.
*
* Currently, only master mode is supported.
*/
#include "i2c_private.h"
#include <libmaple/libmaple.h>
#include <libmaple/rcc.h>
#include <libmaple/gpio.h>
#include <libmaple/nvic.h>
#include <libmaple/i2c.h>
#include <libmaple/systick.h>
#include <string.h>
static inline int32 wait_for_state_change(i2c_dev *dev,
i2c_state state,
uint32 timeout);
static void set_ccr_trise(i2c_dev *dev, uint32 flags);
/**
* @brief Fill data register with slave address
* @param dev I2C device
* @param addr Slave address
* @param rw Read/write bit
*/
static inline void i2c_send_slave_addr(i2c_dev *dev, uint32 addr, uint32 rw) {
dev->regs->DR = (addr << 1) | rw;
}
/*
* Simple debugging trail. Define I2C_DEBUG to turn on.
*/
#ifdef I2C_DEBUG
#define NR_CRUMBS 128
static struct crumb crumbs[NR_CRUMBS];
static uint32 cur_crumb = 0;
static inline void i2c_drop_crumb(uint32 event, uint32 arg0, uint32 arg1) {
if (cur_crumb < NR_CRUMBS) {
struct crumb *crumb = &crumbs[cur_crumb++];
crumb->event = event;
crumb->arg0 = arg0;
crumb->arg1 = arg1;
}
}
#define I2C_CRUMB(event, arg0, arg1) i2c_drop_crumb(event, arg0, arg1)
#else
#define I2C_CRUMB(event, arg0, arg1)
#endif
struct crumb {
uint32 event;
uint32 arg0;
uint32 arg1;
};
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,
ERROR_ENTRY = 13,
};
/**
* @brief Reset an I2C bus.
*
* Reset is accomplished by clocking out pulses until any hung slaves
* release SDA and SCL, then generating a START condition, then a STOP
* condition.
*
* @param dev I2C device
*/
void i2c_bus_reset(const i2c_dev *dev) {
/* Release both lines */
i2c_master_release_bus(dev);
/*
* Make sure the bus is free by clocking it until any slaves release the
* bus.
*/
while (!gpio_read_bit(sda_port(dev), dev->sda_pin)) {
/* Wait for any clock stretching to finish */
while (!gpio_read_bit(scl_port(dev), dev->scl_pin))
;
delay_us(10);
/* Pull low */
gpio_write_bit(scl_port(dev), dev->scl_pin, 0);
delay_us(10);
/* Release high again */
gpio_write_bit(scl_port(dev), dev->scl_pin, 1);
delay_us(10);
}
/* Generate start then stop condition */
gpio_write_bit(sda_port(dev), dev->sda_pin, 0);
delay_us(10);
gpio_write_bit(scl_port(dev), dev->scl_pin, 0);
delay_us(10);
gpio_write_bit(scl_port(dev), dev->scl_pin, 1);
delay_us(10);
gpio_write_bit(sda_port(dev), dev->sda_pin, 1);
}
/**
* @brief Initialize an I2C device and reset its registers to their
* default values.
* @param dev Device to initialize.
*/
void i2c_init(i2c_dev *dev) {
rcc_reset_dev(dev->clk_id);
rcc_clk_enable(dev->clk_id);
}
/* Hack for deprecated bit of STM32F1 functionality */
#ifndef _I2C_HAVE_DEPRECATED_I2C_REMAP
#define _i2c_handle_remap(dev, flags) ((void)0)
#endif
/**
* @brief Initialize an I2C device as bus master
* @param dev Device to enable
* @param flags Bitwise or of the following I2C options:
* I2C_FAST_MODE: 400 khz operation,
* I2C_DUTY_16_9: 16/9 Tlow/Thigh duty cycle (only applicable for
* fast mode),
* I2C_BUS_RESET: Reset the bus and clock out any hung slaves on
* initialization,
* I2C_10BIT_ADDRESSING: Enable 10-bit addressing,
* I2C_REMAP: (deprecated, STM32F1 only) Remap I2C1 to SCL/PB8
* SDA/PB9.
*/
void i2c_master_enable(i2c_dev *dev, uint32 flags) {
/* PE must be disabled to configure the device */
ASSERT(!(dev->regs->CR1 & I2C_CR1_PE));
/* Ugh */
_i2c_handle_remap(dev, flags);
/* Reset the bus. Clock out any hung slaves. */
if (flags & I2C_BUS_RESET) {
i2c_bus_reset(dev);
}
/* Turn on clock and set GPIO modes */
i2c_init(dev);
i2c_config_gpios(dev);
/* Configure clock and rise time */
set_ccr_trise(dev, flags);
/* Enable event and buffer interrupts */
nvic_irq_enable(dev->ev_nvic_line);
nvic_irq_enable(dev->er_nvic_line);
i2c_enable_irq(dev, I2C_IRQ_EVENT | I2C_IRQ_BUFFER | I2C_IRQ_ERROR);
/* Make it go! */
i2c_peripheral_enable(dev);
dev->state = I2C_STATE_IDLE;
}
/**
* @brief Process an i2c transaction.
*
* Transactions are composed of one or more i2c_msg's, and may be read
* or write tranfers. Multiple i2c_msg's will generate a repeated
* start in between messages.
*
* @param dev I2C device
* @param msgs Messages to send/receive
* @param num Number of messages to send/receive
* @param timeout Bus idle timeout in milliseconds before aborting the
* transfer. 0 denotes no timeout.
* @return 0 on success,
* I2C_ERROR_PROTOCOL if there was a protocol error,
* I2C_ERROR_TIMEOUT if the transfer timed out.
*/
int32 i2c_master_xfer(i2c_dev *dev,
i2c_msg *msgs,
uint16 num,
uint32 timeout) {
int32 rc;
ASSERT(dev->state == I2C_STATE_IDLE);
dev->msg = msgs;
dev->msgs_left = num;
dev->timestamp = systick_uptime();
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, timeout);
if (rc < 0) {
goto out;
}
dev->state = I2C_STATE_IDLE;
out:
return rc;
}
/**
* @brief Wait for an I2C event, or time out in case of error.
* @param dev I2C device
* @param state I2C_state state to wait for
* @param timeout Timeout, in milliseconds
* @return 0 if target state is reached, a negative value on error.
*/
static inline int32 wait_for_state_change(i2c_dev *dev,
i2c_state state,
uint32 timeout) {
i2c_state tmp;
while (1) {
tmp = dev->state;
if (tmp == I2C_STATE_ERROR) {
return I2C_STATE_ERROR;
}
if (tmp == state) {
return 0;
}
if (timeout) {
if (systick_uptime() > (dev->timestamp + timeout)) {
/* TODO: overflow? */
/* TODO: racy? */
return I2C_ERROR_TIMEOUT;
}
}
}
}
/*
* Private API
*/
/*
* IRQ handler for I2C master. Handles transmission/reception.
*/
void _i2c_irq_handler(i2c_dev *dev) {
/* WTFs:
* - Where is I2C_MSG_10BIT_ADDR handled?
*/
i2c_msg *msg = dev->msg;
uint8 read = msg->flags & I2C_MSG_READ;
uint32 sr1 = dev->regs->SR1;
uint32 sr2 = dev->regs->SR2;
I2C_CRUMB(IRQ_ENTRY, sr1, sr2);
/*
* Reset timeout counter
*/
dev->timestamp = systick_uptime();
/*
* EV5: Start condition sent
*/
if (sr1 & I2C_SR1_SB) {
msg->xferred = 0;
i2c_enable_irq(dev, I2C_IRQ_BUFFER);
/*
* Master receiver
*/
if (read) {
i2c_enable_ack(dev);
}
i2c_send_slave_addr(dev, 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);
if (dev->msgs_left > 1) {
i2c_start_condition(dev);
I2C_CRUMB(RX_ADDR_START, 0, 0);
} else {
i2c_stop_condition(dev);
I2C_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.
*/
if (msg->length != 1) {
i2c_write(dev, 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)) {
I2C_CRUMB(TXE_ONLY, 0, 0);
if (dev->msgs_left) {
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, I2C_IRQ_BUFFER);
dev->msgs_left--;
}
} else {
/*
* This should be impossible...
*/
ASSERT(0);
}
sr1 = sr2 = 0;
}
/*
* EV8_2: Master transmitter
* Last byte sent, program repeated start/stop
*/
if ((sr1 & I2C_SR1_TXE) && (sr1 & I2C_SR1_BTF)) {
I2C_CRUMB(TXE_BTF, 0, 0);
if (dev->msgs_left) {
I2C_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);
while (!(dev->regs->SR1 & I2C_SR1_SB))
;
dev->msg++;
} else {
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.
*/
i2c_disable_irq(dev, I2C_IRQ_EVENT);
I2C_CRUMB(STOP_SENT, 0, 0);
dev->state = I2C_STATE_XFER_DONE;
}
sr1 = sr2 = 0;
}
/*
* EV7: Master Receiver
*/
if (sr1 & I2C_SR1_RXNE) {
I2C_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);
if (dev->msgs_left > 2) {
i2c_start_condition(dev);
I2C_CRUMB(RXNE_START_SENT, 0, 0);
} else {
i2c_stop_condition(dev);
I2C_CRUMB(RXNE_STOP_SENT, 0, 0);
}
} else if (msg->xferred == msg->length) {
dev->msgs_left--;
if (dev->msgs_left == 0) {
/*
* We're done.
*/
I2C_CRUMB(RXNE_DONE, 0, 0);
dev->state = I2C_STATE_XFER_DONE;
} else {
dev->msg++;
}
}
}
}
/*
* Interrupt handler for I2C error conditions. Aborts any pending I2C
* transactions.
*/
void _i2c_irq_error_handler(i2c_dev *dev) {
I2C_CRUMB(ERROR_ENTRY, dev->regs->SR1, dev->regs->SR2);
dev->error_flags = dev->regs->SR2 & (I2C_SR1_BERR |
I2C_SR1_ARLO |
I2C_SR1_AF |
I2C_SR1_OVR);
/* Clear flags */
dev->regs->SR1 = 0;
dev->regs->SR2 = 0;
i2c_stop_condition(dev);
i2c_disable_irq(dev, I2C_IRQ_BUFFER | I2C_IRQ_EVENT | I2C_IRQ_ERROR);
dev->state = I2C_STATE_ERROR;
}
/*
* CCR/TRISE configuration helper
*/
static void set_ccr_trise(i2c_dev *dev, uint32 flags) {
uint32 ccr = 0;
uint32 trise = 0;
uint32 clk_mhz = _i2c_bus_clk(dev);
uint32 clk_hz = clk_mhz * (1000 * 1000);
i2c_set_input_clk(dev, clk_mhz);
if (flags & I2C_FAST_MODE) {
ccr |= I2C_CCR_FS;
if (flags & I2C_DUTY_16_9) {
/* Tlow/Thigh = 16/9 */
ccr |= I2C_CCR_DUTY_16_9;
ccr |= clk_hz / (400000 * 25);
} else {
/* Tlow/Thigh = 2 */
ccr |= clk_hz / (400000 * 3);
}
trise = (300 * clk_mhz / 1000) + 1;
} else {
/* Tlow/Thigh = 1 */
ccr = clk_hz / (100000 * 2);
trise = clk_mhz + 1;
}
/* Set minimum required value if CCR < 1*/
if ((ccr & I2C_CCR_CCR) == 0) {
ccr |= 0x1;
}
i2c_set_clk_control(dev, ccr);
i2c_set_trise(dev, trise);
}

View File

@ -0,0 +1,129 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2012 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 libmaple/stm32f1/i2c.c
* @brief STM32F1 I2C support
*/
#include "i2c_private.h"
#include <libmaple/i2c.h>
/*
* Devices
*/
static i2c_dev i2c1 = I2C_DEV_OLD(1, &gpiob, 7, 6);
static i2c_dev i2c2 = I2C_DEV_OLD(2, &gpiob, 11, 10);
/** STM32F1 I2C device 1 */
i2c_dev* const I2C1 = &i2c1;
/** STM32F1 I2C device 2 */
i2c_dev* const I2C2 = &i2c2;
/*
* Routines
*/
static int i2c1_wants_remap(const i2c_dev *dev) {
/* Check if we've got I2C1 configured for SDA/SCL remap on PB9/PB8 */
return (dev->clk_id == RCC_I2C1) &&
(scl_port(dev)->clk_id == RCC_GPIOB) &&
(sda_port(dev)->clk_id == RCC_GPIOB) &&
(dev->sda_pin == 9) &&
(dev->scl_pin == 8);
}
void i2c_config_gpios(const i2c_dev *dev) {
if (i2c1_wants_remap(dev)) {
afio_remap(AFIO_REMAP_I2C1);
}
gpio_set_mode(sda_port(dev), dev->sda_pin, GPIO_AF_OUTPUT_OD);
gpio_set_mode(scl_port(dev), dev->scl_pin, GPIO_AF_OUTPUT_OD);
}
void i2c_master_release_bus(const i2c_dev *dev) {
gpio_write_bit(scl_port(dev), dev->scl_pin, 1);
gpio_write_bit(sda_port(dev), dev->sda_pin, 1);
gpio_set_mode(scl_port(dev), dev->scl_pin, GPIO_OUTPUT_OD);
gpio_set_mode(sda_port(dev), dev->sda_pin, GPIO_OUTPUT_OD);
}
/*
* IRQ handlers
*/
void __irq_i2c1_ev(void) {
_i2c_irq_handler(I2C1);
}
void __irq_i2c2_ev(void) {
_i2c_irq_handler(I2C2);
}
void __irq_i2c1_er(void) {
_i2c_irq_error_handler(I2C1);
}
void __irq_i2c2_er(void) {
_i2c_irq_error_handler(I2C2);
}
/*
* Internal APIs
*/
void _i2c_irq_priority_fixup(i2c_dev *dev) {
/*
* 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);
nvic_irq_set_priority(dev->er_nvic_line, 0);
}

View File

@ -0,0 +1,62 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 Michael Hope.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*****************************************************************************/
/**
* @file libmaple/iwdg.c
* @brief Independent watchdog (IWDG) support
*/
#include <libmaple/iwdg.h>
/**
* @brief Initialise and start the watchdog
*
* The prescaler and reload set the timeout. For example, a prescaler
* of IWDG_PRE_32 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(iwdg_prescaler prescaler, uint16 reload) {
IWDG_BASE->KR = IWDG_KR_UNLOCK;
IWDG_BASE->PR = prescaler;
IWDG_BASE->RLR = reload;
/* 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) {
IWDG_BASE->KR = IWDG_KR_FEED;
}

View File

@ -0,0 +1,103 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 Perry Hung.
* 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 libmaple/nvic.c
* @brief Nested vector interrupt controller support.
*/
#include <libmaple/nvic.h>
#include <libmaple/scb.h>
#include <libmaple/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.
*
* @param irqn device to set
* @param priority Priority to set, 0 being highest priority and 15
* being lowest.
*/
void nvic_irq_set_priority(nvic_irq_num irqn, uint8 priority) {
if (irqn < 0) {
/* This interrupt is in the system handler block */
SCB_BASE->SHP[((uint32)irqn & 0xF) - 4] = (priority & 0xF) << 4;
} else {
NVIC_BASE->IP[irqn] = (priority & 0xF) << 4;
}
}
/**
* @brief Initialize the NVIC, setting interrupts to a default priority.
*/
void nvic_init(uint32 address, uint32 offset) {
uint32 i;
nvic_set_vector_table(address, offset);
/*
* Lower priority level for all peripheral interrupts to lowest
* possible.
*/
for (i = 0; i < STM32_NR_INTERRUPTS; i++) {
nvic_irq_set_priority((nvic_irq_num)i, 0xF);
}
/* Lower systick interrupt priority to lowest level */
nvic_irq_set_priority(NVIC_SYSTICK, 0xF);
}
/**
* @brief Set the vector table base address.
*
* For stand-alone products, the vector table base address is normally
* the start of Flash (0x08000000).
*
* @param address Vector table base address.
* @param offset Offset from address. Some restrictions apply to the
* use of nonzero offsets; see the ARM Cortex M3
* Technical Reference Manual.
*/
void nvic_set_vector_table(uint32 address, uint32 offset) {
SCB_BASE->VTOR = address | (offset & 0x1FFFFF80);
}
/**
* @brief Force a system reset.
*
* Resets all major system components, excluding debug.
*/
void nvic_sys_reset() {
uint32 prigroup = SCB_BASE->AIRCR & SCB_AIRCR_PRIGROUP;
SCB_BASE->AIRCR = SCB_AIRCR_VECTKEY | SCB_AIRCR_SYSRESETREQ | prigroup;
asm volatile("dsb");
while (1)
;
}

View File

@ -0,0 +1,41 @@
/******************************************************************************
* 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 libmaple/pwr.c
* @brief Power control (PWR) support.
*/
#include <libmaple/pwr.h>
#include <libmaple/rcc.h>
/**
* Enables the power interface clock, and resets the power device.
*/
void pwr_init(void) {
rcc_clk_enable(RCC_PWR);
rcc_reset_dev(RCC_PWR);
}

View File

@ -0,0 +1,169 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 Perry Hung.
* 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 libmaple/rcc.c
* @brief Portable RCC routines.
*/
#include <libmaple/rcc.h>
#include "rcc_private.h"
/**
* @brief Get a peripheral's clock domain
* @param id Clock ID of the peripheral whose clock domain to return
* @return Clock source for the given clock ID
*/
rcc_clk_domain rcc_dev_clk(rcc_clk_id id) {
return rcc_dev_table[id].clk_domain;
}
/**
* @brief Switch the clock used as the source of the system clock.
*
* After switching the source, this function blocks until the new
* clock source is in use.
*
* @param sysclk_src New system clock source.
* @see rcc_sysclk_src
*/
void rcc_switch_sysclk(rcc_sysclk_src sysclk_src) {
uint32 cfgr = RCC_BASE->CFGR;
cfgr &= ~RCC_CFGR_SW;
cfgr |= sysclk_src;
/* Switch SYSCLK source. */
RCC_BASE->CFGR = cfgr;
/* Wait for new source to come into use. */
while ((RCC_BASE->CFGR & RCC_CFGR_SWS) != (sysclk_src << 2))
;
}
/*
* Turning clocks off and on, querying their status.
*/
/* IMPORTANT NOTE FOR IMPLEMENTORS:
*
* libmaple assumes that enum rcc_clk enumerators are two-byte
* values, stored in a uint16, in the following way:
*
* - The high-order byte is the byte offset (from RCC_BASE) of the register
* to touch when turning on or off the given clock.
*
* - The low-order byte is the bit in that register that turns the
* clock on or off.
*
* Example for STM32F1: Turning on the high-speed external clock (HSE)
* involves setting HSEON, bit 16, of RCC_CR. The high-order byte is
* then offsetof(struct rcc_reg_map, CR) = 0, and the low-order byte
* is 16.
*
* The corresponding value of RCC_CLK_HSE is thus (0 << 8) | 16 = 16.
*
* On all known STM32 series, this encoding has the property that
* adding one to the low byte also gives the bit to check to determine
* if the clock is ready. For example, on STM32F1, RCC_CR_HSERDY is
* bit 17. If that's not the case on your series, rcc_is_clk_ready()
* won't work for you. */
/* Returns the RCC register which controls the clock source. */
static inline __io uint32* rcc_clk_reg(rcc_clk clock) {
return (__io uint32*)((__io uint8*)RCC_BASE + (clock >> 8));
}
/* Returns a mask in rcc_clk_reg(clock) to be used for turning the
* clock on and off */
static inline uint32 rcc_clk_on_mask(rcc_clk clock) {
return 1 << (clock & 0xFF);
}
/* Returns a mask in rcc_clk_reg(clock) to be used when checking the
* readiness of the clock. */
static inline uint32 rcc_clk_ready_mask(rcc_clk clock) {
return rcc_clk_on_mask(clock) << 1;
}
/**
* @brief Turn on a clock source.
*
* After this routine exits, callers should ensure that the clock
* source is ready by waiting until rcc_is_clk_ready(clock) returns
* true.
*
* @param clock Clock to turn on.
* @see rcc_turn_off_clk()
* @see rcc_is_clk_ready()
*/
void rcc_turn_on_clk(rcc_clk clock) {
*rcc_clk_reg(clock) |= rcc_clk_on_mask(clock);
}
/**
* @brief Turn off a clock source.
*
* In certain configurations, certain clock sources cannot be safely
* turned off. (For example, the main PLL on STM32F1 devices cannot be
* turned off if it has been selected as the SYSCLK source). Consult
* the reference material for your MCU to ensure it is safe to call
* this function.
*
* @param clock Clock to turn off.
* @see rcc_turn_on_clk()
* @see rcc_is_clk_ready()
*/
void rcc_turn_off_clk(rcc_clk clock) {
*rcc_clk_reg(clock) &= ~rcc_clk_on_mask(clock);
}
/**
* @brief Check if a clock is on.
* @param clock Clock to check.
* @return 1 if the clock is on, 0 if the clock is off.
*/
int rcc_is_clk_on(rcc_clk clock) {
return !!(*rcc_clk_reg(clock) & rcc_clk_on_mask(clock));
}
/**
* @brief Check if a clock source is ready.
*
* In general, it is not safe to rely on a clock source unless this
* function returns nonzero. Also note that this function may return
* nonzero for a short period of time after a clock has been turned
* off. Consult the reference material for your MCU for more details.
*
* @param clock Clock whose readiness to check for.
* @return Nonzero if the clock is ready, zero otherwise.
* @see rcc_turn_on_clk()
* @see rcc_turn_off_clk()
*/
int rcc_is_clk_ready(rcc_clk clock) {
return (int)(*rcc_clk_reg(clock) & rcc_clk_ready_mask(clock));
}

View File

@ -0,0 +1,164 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 Perry Hung.
* 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 libmaple/stm32f1/rcc.c
* @brief STM32F1 RCC.
*/
#include <libmaple/rcc.h>
#include <libmaple/libmaple.h>
#include <libmaple/bitband.h>
#include "rcc_private.h"
#define APB1 RCC_APB1
#define APB2 RCC_APB2
#define AHB RCC_AHB
/* Device descriptor table, maps rcc_clk_id onto bus and enable/reset
* register bit numbers. */
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_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_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_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},
[RCC_USB] = { .clk_domain = APB1, .line_num = 23},
#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_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 },
[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
};
__deprecated
void rcc_clk_init(rcc_sysclk_src sysclk_src,
rcc_pllsrc pll_src,
rcc_pll_multiplier pll_mul) {
/* 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);
RCC_BASE->CFGR = pll_src | pll_mul;
/* Turn on, and wait for, HSE. */
rcc_turn_on_clk(RCC_CLK_HSE);
while (!rcc_is_clk_ready(RCC_CLK_HSE))
;
/* Do the same for the main PLL. */
rcc_turn_on_clk(RCC_CLK_PLL);
while(!rcc_is_clk_ready(RCC_CLK_PLL))
;
/* Finally, switch over to the PLL. */
rcc_switch_sysclk(RCC_CLKSRC_PLL);
}
/* pll_cfg->data must point to a valid struct stm32f1_rcc_pll_data. */
void rcc_configure_pll(rcc_pll_cfg *pll_cfg) {
stm32f1_rcc_pll_data *data = pll_cfg->data;
rcc_pll_multiplier pll_mul = data->pll_mul;
uint32 cfgr;
/* Check that the PLL is disabled. */
ASSERT_FAULT(!rcc_is_clk_on(RCC_CLK_PLL));
cfgr = RCC_BASE->CFGR;
cfgr &= ~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLMUL);
cfgr |= pll_cfg->pllsrc | pll_mul;
RCC_BASE->CFGR = cfgr;
}
void rcc_clk_enable(rcc_clk_id id) {
static __io uint32* enable_regs[] = {
[APB1] = &RCC_BASE->APB1ENR,
[APB2] = &RCC_BASE->APB2ENR,
[AHB] = &RCC_BASE->AHBENR,
};
rcc_do_clk_enable(enable_regs, id);
}
void rcc_reset_dev(rcc_clk_id id) {
static __io uint32* reset_regs[] = {
[APB1] = &RCC_BASE->APB1RSTR,
[APB2] = &RCC_BASE->APB2RSTR,
};
rcc_do_reset_dev(reset_regs, id);
}
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,
[RCC_PRESCALER_APB2] = RCC_CFGR_PPRE2,
[RCC_PRESCALER_USB] = RCC_CFGR_USBPRE,
[RCC_PRESCALER_ADC] = RCC_CFGR_ADCPRE,
};
rcc_do_set_prescaler(masks, prescaler, divider);
}

View File

@ -0,0 +1,164 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2011, 2012 LeafLabs, LLC.
* 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 libmaple/spi.c
* @author Marti Bolivar <mbolivar@leaflabs.com>
* @brief Serial Peripheral Interface (SPI) support.
* Currently, there is no Integrated Interchip Sound (I2S) support.
*/
#include <libmaple/spi.h>
#include <libmaple/bitband.h>
static void spi_reconfigure(spi_dev *dev, uint32 cr1_config);
/*
* SPI convenience routines
*/
/**
* @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 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);
}
/**
* @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);
}
/**
* @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 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) {
uint32 txed = 0;
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;
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/*
* 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);
}

View File

@ -0,0 +1,84 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2011, 2012 LeafLabs, LLC.
* 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 libmaple/stm32f1/spi.c
* @author Marti Bolivar <mbolivar@leaflabs.com>
* @brief STM32F1 SPI/I2S.
*/
#include <libmaple/spi.h>
#include <libmaple/gpio.h>
#include "spi_private.h"
/*
* Devices
*/
static spi_dev spi1 = SPI_DEV(1);
static spi_dev spi2 = SPI_DEV(2);
spi_dev *SPI1 = &spi1;
spi_dev *SPI2 = &spi2;
#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
static spi_dev spi3 = SPI_DEV(3);
spi_dev *SPI3 = &spi3;
#endif
/*
* Routines
*/
void spi_config_gpios(spi_dev *ignored,
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);
}
}
void spi_foreach(void (*fn)(spi_dev*)) {
fn(SPI1);
fn(SPI2);
#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
fn(SPI3);
#endif
}

View File

@ -0,0 +1,263 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2011 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.
*****************************************************************************/
/* STM32F1 performance line ISR weak declarations */
#include <libmaple/stm32.h>
.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 */

View File

@ -0,0 +1,118 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2011 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.
*****************************************************************************/
/* STM32F1 performance line vector table */
#include <libmaple/stm32.h>
.section ".stm32.interrupt_vector"
.globl __stm32_vector_table
.type __stm32_vector_table, %object
__stm32_vector_table:
/* CM3 core interrupts */
.long __msp_init
.long __exc_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)
.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 __stm32_vector_table, . - __stm32_vector_table

View File

@ -0,0 +1,88 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 Perry Hung.
* Copyright (c) 2010, 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 libmaple/systick.c
* @brief System timer (SysTick).
*/
#include <libmaple/systick.h>
volatile uint32 systick_uptime_millis;
static void (*systick_user_callback)(void);
/**
* @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) {
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() {
SYSTICK_BASE->CSR = SYSTICK_CSR_CLKSOURCE_CORE;
}
/**
* 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);
}
/**
* @brief Attach a callback to be called from the SysTick exception handler.
*
* To detach a callback, call this function again with a null argument.
*/
void systick_attach_callback(void (*callback)(void)) {
systick_user_callback = callback;
}
/*
* SysTick ISR
*/
void __exc_systick(void) {
systick_uptime_millis++;
if (systick_user_callback) {
systick_user_callback();
}
}

View File

@ -0,0 +1,412 @@
/******************************************************************************
* 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 libmaple/timer.c
* @author Marti Bolivar <mbolivar@leaflabs.com>
* @brief Portable timer routines.
*/
#include <libmaple/timer.h>
#include <libmaple/stm32.h>
#include "timer_private.h"
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, timer_interrupt_id iid);
/*
* Devices
*
* Defer to the timer_private API for declaring these.
*/
#if STM32_HAVE_TIMER(1)
static timer_dev timer1 = ADVANCED_TIMER(1);
/** Timer 1 device (advanced) */
timer_dev *TIMER1 = &timer1;
#endif
#if STM32_HAVE_TIMER(2)
static timer_dev timer2 = GENERAL_TIMER(2);
/** Timer 2 device (general-purpose) */
timer_dev *TIMER2 = &timer2;
#endif
#if STM32_HAVE_TIMER(3)
static timer_dev timer3 = GENERAL_TIMER(3);
/** Timer 3 device (general-purpose) */
timer_dev *TIMER3 = &timer3;
#endif
#if STM32_HAVE_TIMER(4)
static timer_dev timer4 = GENERAL_TIMER(4);
/** Timer 4 device (general-purpose) */
timer_dev *TIMER4 = &timer4;
#endif
#if STM32_HAVE_TIMER(5)
static timer_dev timer5 = GENERAL_TIMER(5);
/** Timer 5 device (general-purpose) */
timer_dev *TIMER5 = &timer5;
#endif
#if STM32_HAVE_TIMER(6)
static timer_dev timer6 = BASIC_TIMER(6);
/** Timer 6 device (basic) */
timer_dev *TIMER6 = &timer6;
#endif
#if STM32_HAVE_TIMER(7)
static timer_dev timer7 = BASIC_TIMER(7);
/** Timer 7 device (basic) */
timer_dev *TIMER7 = &timer7;
#endif
#if STM32_HAVE_TIMER(8)
static timer_dev timer8 = ADVANCED_TIMER(8);
/** Timer 8 device (advanced) */
timer_dev *TIMER8 = &timer8;
#endif
#if STM32_HAVE_TIMER(9)
static timer_dev timer9 = RESTRICTED_GENERAL_TIMER(9, TIMER_DIER_TIE_BIT);
/** Timer 9 device (general-purpose) */
timer_dev *TIMER9 = &timer9;
#endif
#if STM32_HAVE_TIMER(10)
static timer_dev timer10 = RESTRICTED_GENERAL_TIMER(10, TIMER_DIER_CC1IE_BIT);
/** Timer 10 device (general-purpose) */
timer_dev *TIMER10 = &timer10;
#endif
#if STM32_HAVE_TIMER(11)
static timer_dev timer11 = RESTRICTED_GENERAL_TIMER(11, TIMER_DIER_CC1IE_BIT);
/** Timer 11 device (general-purpose) */
timer_dev *TIMER11 = &timer11;
#endif
#if STM32_HAVE_TIMER(12)
static timer_dev timer12 = RESTRICTED_GENERAL_TIMER(12, TIMER_DIER_TIE_BIT);
/** Timer 12 device (general-purpose) */
timer_dev *TIMER12 = &timer12;
#endif
#if STM32_HAVE_TIMER(13)
static timer_dev timer13 = RESTRICTED_GENERAL_TIMER(13, TIMER_DIER_CC1IE_BIT);
/** Timer 13 device (general-purpose) */
timer_dev *TIMER13 = &timer13;
#endif
#if STM32_HAVE_TIMER(14)
static timer_dev timer14 = RESTRICTED_GENERAL_TIMER(14, TIMER_DIER_CC1IE_BIT);
/** Timer 14 device (general-purpose) */
timer_dev *TIMER14 = &timer14;
#endif
/*
* Routines
*/
/**
* @brief Call a function on timer devices.
* @param fn Function to call on each timer device.
*/
void timer_foreach(void (*fn)(timer_dev*)) {
#if STM32_HAVE_TIMER(1)
fn(TIMER1);
#endif
#if STM32_HAVE_TIMER(2)
fn(TIMER2);
#endif
#if STM32_HAVE_TIMER(3)
fn(TIMER3);
#endif
#if STM32_HAVE_TIMER(4)
fn(TIMER4);
#endif
#if STM32_HAVE_TIMER(5)
fn(TIMER5);
#endif
#if STM32_HAVE_TIMER(6)
fn(TIMER6);
#endif
#if STM32_HAVE_TIMER(7)
fn(TIMER7);
#endif
#if STM32_HAVE_TIMER(8)
fn(TIMER8);
#endif
#if STM32_HAVE_TIMER(9)
fn(TIMER9);
#endif
#if STM32_HAVE_TIMER(10)
fn(TIMER10);
#endif
#if STM32_HAVE_TIMER(11)
fn(TIMER11);
#endif
#if STM32_HAVE_TIMER(12)
fn(TIMER12);
#endif
#if STM32_HAVE_TIMER(13)
fn(TIMER13);
#endif
#if STM32_HAVE_TIMER(14)
fn(TIMER14);
#endif
}
/**
* 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_FAULT(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 Determine whether a timer has a particular capture/compare channel.
*
* Different timers have different numbers of capture/compare channels
* (and some have none at all). Use this function to test whether a
* given timer/channel combination will work.
*
* @param dev Timer device
* @param channel Capture/compare channel, from 1 to 4
* @return Nonzero if dev has channel, zero otherwise.
*/
int timer_has_cc_channel(timer_dev *dev, uint8 channel) {
/* On all currently supported series: advanced and "full-featured"
* general purpose timers have all four channels. Of the
* restricted general timers, timers 9 and 12 have channels 1 and
* 2; the others have channel 1 only. Basic timers have none. */
rcc_clk_id id = dev->clk_id;
ASSERT((1 <= channel) && (channel <= 4));
if (id <= RCC_TIMER5 || id == RCC_TIMER8) {
return 1; /* 1 and 8 are advanced, 2-5 are "full" general */
} else if (id <= RCC_TIMER7) {
return 0; /* 6 and 7 are basic */
}
/* The rest are restricted general. */
return (((id == RCC_TIMER9 || id == RCC_TIMER12) && channel <= 2) ||
channel == 1);
}
/**
* @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_irq(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_irq(dev, interrupt);
dev->handlers[interrupt] = NULL;
}
/*
* 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_irq(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_adv_irq(timer_dev *dev, timer_interrupt_id id);
static void enable_bas_gen_irq(timer_dev *dev);
static inline void enable_irq(timer_dev *dev, timer_interrupt_id iid) {
if (dev->type == TIMER_ADVANCED) {
enable_adv_irq(dev, iid);
} else {
enable_bas_gen_irq(dev);
}
}
/* Advanced control timers have several IRQ lines corresponding to
* different timer interrupts.
*
* Note: This function assumes that the only advanced timers are TIM1
* and TIM8, and needs the obvious changes if that assumption is
* violated by a later STM32 series. */
static void enable_adv_irq(timer_dev *dev, timer_interrupt_id id) {
uint8 is_tim1 = dev->clk_id == RCC_TIMER1;
nvic_irq_num irq_num;
switch (id) {
case TIMER_UPDATE_INTERRUPT:
irq_num = (is_tim1 ?
NVIC_TIMER1_UP_TIMER10 :
NVIC_TIMER8_UP_TIMER13);
break;
case TIMER_CC1_INTERRUPT: /* Fall through */
case TIMER_CC2_INTERRUPT: /* ... */
case TIMER_CC3_INTERRUPT: /* ... */
case TIMER_CC4_INTERRUPT:
irq_num = is_tim1 ? NVIC_TIMER1_CC : NVIC_TIMER8_CC;
break;
case TIMER_COM_INTERRUPT: /* Fall through */
case TIMER_TRG_INTERRUPT:
irq_num = (is_tim1 ?
NVIC_TIMER1_TRG_COM_TIMER11 :
NVIC_TIMER8_TRG_COM_TIMER14);
break;
case TIMER_BREAK_INTERRUPT:
irq_num = (is_tim1 ?
NVIC_TIMER1_BRK_TIMER9 :
NVIC_TIMER8_BRK_TIMER12);
break;
default:
/* Can't happen, but placate the compiler */
ASSERT(0);
return;
}
nvic_irq_enable(irq_num);
}
/* Basic and general purpose timers have a single IRQ line, which is
* shared by all interrupts supported by a particular timer. */
static void enable_bas_gen_irq(timer_dev *dev) {
nvic_irq_num irq_num;
switch (dev->clk_id) {
case RCC_TIMER2:
irq_num = NVIC_TIMER2;
break;
case RCC_TIMER3:
irq_num = NVIC_TIMER3;
break;
case RCC_TIMER4:
irq_num = NVIC_TIMER4;
break;
case RCC_TIMER5:
irq_num = NVIC_TIMER5;
break;
case RCC_TIMER6:
irq_num = NVIC_TIMER6;
break;
case RCC_TIMER7:
irq_num = NVIC_TIMER7;
break;
case RCC_TIMER9:
irq_num = NVIC_TIMER1_BRK_TIMER9;
break;
case RCC_TIMER10:
irq_num = NVIC_TIMER1_UP_TIMER10;
break;
case RCC_TIMER11:
irq_num = NVIC_TIMER1_TRG_COM_TIMER11;
break;
case RCC_TIMER12:
irq_num = NVIC_TIMER8_BRK_TIMER12;
break;
case RCC_TIMER13:
irq_num = NVIC_TIMER8_UP_TIMER13;
break;
case RCC_TIMER14:
irq_num = NVIC_TIMER8_TRG_COM_TIMER14;
break;
default:
ASSERT_FAULT(0);
return;
}
nvic_irq_enable(irq_num);
}

View File

@ -0,0 +1,124 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2011, 2012 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 libmaple/stm32f1/timer.c
* @author Marti Bolivar <mbolivar@leaflabs.com>
* @brief STM32F1 timer.
*/
#include <libmaple/timer.h>
#include <libmaple/stm32.h>
#include "timer_private.h"
/*
* IRQ handlers
*
* Defer to the timer_private dispatch API.
*
* FIXME: The names of these handlers are inaccurate since XL-density
* devices came out. Update these to match the STM32F2 names, maybe
* using some weak symbol magic to preserve backwards compatibility if
* possible. Once that's done, we can just move the IRQ handlers into
* the top-level libmaple/timer.c, and there will be no need for this
* file.
*/
void __irq_tim1_brk(void) {
dispatch_adv_brk(TIMER1);
#if STM32_HAVE_TIMER(9)
dispatch_tim_9_12(TIMER9);
#endif
}
void __irq_tim1_up(void) {
dispatch_adv_up(TIMER1);
#if STM32_HAVE_TIMER(10)
dispatch_tim_10_11_13_14(TIMER10);
#endif
}
void __irq_tim1_trg_com(void) {
dispatch_adv_trg_com(TIMER1);
#if STM32_HAVE_TIMER(11)
dispatch_tim_10_11_13_14(TIMER11);
#endif
}
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);
#if STM32_HAVE_TIMER(12)
dispatch_tim_9_12(TIMER12);
#endif
}
void __irq_tim8_up(void) {
dispatch_adv_up(TIMER8);
#if STM32_HAVE_TIMER(13)
dispatch_tim_10_11_13_14(TIMER13);
#endif
}
void __irq_tim8_trg_com(void) {
dispatch_adv_trg_com(TIMER8);
#if STM32_HAVE_TIMER(14)
dispatch_tim_10_11_13_14(TIMER14);
#endif
}
void __irq_tim8_cc(void) {
dispatch_adv_cc(TIMER8);
}
#endif /* defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) */

View File

@ -0,0 +1,138 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 Perry Hung.
* 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 libmaple/usart.c
* @author Marti Bolivar <mbolivar@leaflabs.com>,
* Perry Hung <perry@leaflabs.com>
* @brief Portable USART routines
*/
#include <libmaple/usart.h>
/**
* @brief Initialize a serial port.
* @param dev Serial port to be initialized
*/
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);
}
/**
* @brief Enable a serial port.
*
* USART is enabled in single buffer transmission mode, multibuffer
* receiver mode, 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_enable(usart_dev *dev) {
usart_reg_map *regs = dev->regs;
regs->CR1 = (USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE |
USART_CR1_M_8N1);
regs->CR1 |= USART_CR1_UE;
}
/**
* @brief Turn off a serial port.
* @param dev Serial port to be disabled
*/
void usart_disable(usart_dev *dev) {
/* FIXME this misbehaves (on F1) 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((regs->CR1 & USART_CR1_UE) && !(regs->SR & USART_SR_TC))
;
/* Disable UE */
regs->CR1 &= ~USART_CR1_UE;
/* Clean up buffer */
usart_reset_rx(dev);
}
/**
* @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
*/
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 Nonblocking USART receive.
* @param dev Serial port to receive bytes from
* @param buf Buffer to store received bytes into
* @param len Maximum number of bytes to store
* @return Number of bytes received
*/
uint32 usart_rx(usart_dev *dev, uint8 *buf, uint32 len) {
uint32 rxed = 0;
while (usart_data_available(dev) && rxed < len) {
*buf++ = usart_getc(dev);
rxed++;
}
return rxed;
}
/**
* @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
*/
void usart_putudec(usart_dev *dev, uint32 val) {
char digits[12];
int i = 0;
do {
digits[i++] = val % 10 + '0';
val /= 10;
} while (val > 0);
while (--i >= 0) {
usart_putc(dev, digits[i]);
}
}

View File

@ -0,0 +1,170 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2012 LeafLabs, LLC.
* 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 libmaple/stm32f1/usart.c
* @author Marti Bolivar <mbolivar@leaflabs.com>,
* Perry Hung <perry@leaflabs.com>
* @brief STM32F1 USART.
*/
#include <libmaple/usart.h>
#include <libmaple/gpio.h>
#include "usart_private.h"
/*
* Devices
*/
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,
};
/** USART1 device */
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,
};
/** USART2 device */
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,
};
/** USART3 device */
usart_dev *USART3 = &usart3;
#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
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,
};
/** UART4 device */
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,
};
/** UART5 device */
usart_dev *UART5 = &uart5;
#endif
/*
* Routines
*/
void usart_config_gpios_async(usart_dev *udev,
gpio_dev *rx_dev, uint8 rx,
gpio_dev *tx_dev, uint8 tx,
unsigned flags) {
gpio_set_mode(rx_dev, rx, GPIO_INPUT_FLOATING);
gpio_set_mode(tx_dev, tx, GPIO_AF_OUTPUT_PP);
}
void usart_set_baud_rate(usart_dev *dev, uint32 clock_speed, uint32 baud) {
uint32 integer_part;
uint32 fractional_part;
uint32 tmp;
/* Figure out the clock speed, if the user doesn't give one. */
if (clock_speed == 0) {
clock_speed = _usart_clock_freq(dev);
}
ASSERT(clock_speed);
/* Convert desired baud rate to baud rate register setting. */
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);
dev->regs->BRR = (uint16)tmp;
}
/**
* @brief Call a function on each USART.
* @param fn Function to call.
*/
void usart_foreach(void (*fn)(usart_dev*)) {
fn(USART1);
fn(USART2);
fn(USART3);
#ifdef STM32_HIGH_DENSITY
fn(UART4);
fn(UART5);
#endif
}
/*
* Interrupt handlers.
*/
void __irq_usart1(void) {
usart_irq(&usart1_rb, USART1_BASE);
}
void __irq_usart2(void) {
usart_irq(&usart2_rb, USART2_BASE);
}
void __irq_usart3(void) {
usart_irq(&usart3_rb, USART3_BASE);
}
#ifdef STM32_HIGH_DENSITY
void __irq_uart4(void) {
usart_irq(&uart4_rb, UART4_BASE);
}
void __irq_uart5(void) {
usart_irq(&uart5_rb, UART5_BASE);
}
#endif

View File

@ -0,0 +1,41 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2012 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 libmaple/usart_private.c
* @author Marti Bolivar <mbolivar@leaflabs.com>
* @brief Private USART routines.
*/
#include "usart_private.h"
#include <libmaple/rcc.h>
#include <libmaple/stm32.h>
uint32 _usart_clock_freq(usart_dev *dev) {
rcc_clk_domain domain = rcc_dev_clk(dev->clk_id);
return (domain == RCC_APB1 ? STM32_PCLK1 :
(domain == RCC_APB2 ? STM32_PCLK2 : 0));
}

View File

@ -0,0 +1,63 @@
The USB submodule of libmaple is a separate piece of the codebase for
reasons that are largely historical.
Current Status:
There's only support for the USB device peripheral found on
STM32F103s.
We rely on the low level core library provided by ST to implement
the USB transfer protocol for control endpoint transfers.
The virtual com port (which is exposed via
<libmaple/usb_cdcacm.h>) serves two important purposes.
1) It allows serial data transfers between user sketches an a
host computer.
2) It allows the host PC to issue a system reset into the DFU
bootloader with the DTR + RTS + "1EAF" sequence (see
leaflabs.com/docs/bootloader.html for more information on
this).
After reset, Maple will run the DFU bootloader for a few seconds,
during which the user can begin a DFU upload operation (uploads
application binary into RAM/FLASH). Thus, without this virtual com
port, it would be necessary to find an alternative means to reset
the chip in order to enable the bootloader.
If you would like to develop your own USB application for whatever
reason (e.g. to use faster isochronous enpoints for streaming
audio, or implement the USB HID or Mass Storage specs), then
ensure that you leave some hook for resetting Maple remotely in
order to spin up the DFU bootloader. Please make sure to get
yourself a unique vendor/product ID pair for your application, as
some operating systems will assign a host-side driver based on
these tags.
It would be possible to build a compound USB device, that
implements endpoints for both the virtual COM port as well as some
other components (mass storage etc.). However, this turns out to
be a burden from the host driver side, as Windows and *nix handle
compound USB devices quite differently.
Be mindful that enabling the USB peripheral isn't "free." The
device must respond to periodic bus activity (every few
milliseconds) by servicing an ISR. Therefore, the USB application
should be disabled inside of timing critical applications.
In order to disconnect the device from the host, a USB_DISC pin is
asserted (e.g. on Maple, this is PC12). Alternatively, the NVIC
can be directly configured to disable the USB LP/HP IRQ's.
The files inside of usb_lib were provided by ST and are subject to
their own license, all other files were written by the LeafLabs
team and fall under the MIT license.
TODO:
- Generic USB driver core with series-provided backends, like
libopencm3 has.
- Strip out ST code.
- Integration with a high level USB library (like LUFA/MyUSB) to
allow users to write custom USB applications.

View File

@ -0,0 +1,45 @@
# Standard things
sp := $(sp).x
dirstack_$(sp) := $(d)
d := $(dir)
BUILDDIRS += $(BUILD_PATH)/$(d)
# Local flags
CFLAGS_$(d) = -I$(d) -I$(d)/$(MCU_SERIES) -I$(d)/usb_lib $(LIBMAPLE_INCLUDES) $(LIBMAPLE_PRIVATE_INCLUDES) -Wall
# Add usblib and series subdirectory to BUILDDIRS.
BUILDDIRS += $(BUILD_PATH)/$(d)/$(MCU_SERIES)
BUILDDIRS += $(BUILD_PATH)/$(d)/usb_lib
# Local rules and targets
sSRCS_$(d) :=
cSRCS_$(d) :=
# We currently only have F1 performance line support. Sigh.
ifeq ($(MCU_SERIES), stm32f1)
ifeq ($(MCU_F1_LINE), performance)
cSRCS_$(d) += $(MCU_SERIES)/usb.c
cSRCS_$(d) += $(MCU_SERIES)/usb_reg_map.c
cSRCS_$(d) += $(MCU_SERIES)/usb_cdcacm.c
cSRCS_$(d) += usb_lib/usb_core.c
cSRCS_$(d) += usb_lib/usb_init.c
cSRCS_$(d) += usb_lib/usb_mem.c
cSRCS_$(d) += usb_lib/usb_regs.c
endif
endif
sFILES_$(d) := $(sSRCS_$(d):%=$(d)/%)
cFILES_$(d) := $(cSRCS_$(d):%=$(d)/%)
OBJS_$(d) := $(sFILES_$(d):%.S=$(BUILD_PATH)/%.o) \
$(cFILES_$(d):%.c=$(BUILD_PATH)/%.o)
DEPS_$(d) := $(OBJS_$(d):%.o=%.d)
$(OBJS_$(d)): TGT_CFLAGS := $(CFLAGS_$(d))
$(OBJS_$(d)): TGT_ASFLAGS :=
TGT_BIN += $(OBJS_$(d))
# Standard things
-include $(DEPS_$(d))
d := $(dirstack_$(sp))
sp := $(basename $(sp))

View File

@ -0,0 +1,387 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 LeafLabs LLC.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*****************************************************************************/
/**
* @file libmaple/usb/stm32f1/usb.c
* @brief USB support.
*
* This is a mess.
*/
#include <libmaple/usb.h>
#include <libmaple/libmaple.h>
#include <libmaple/rcc.h>
/* Private headers */
#include "usb_reg_map.h"
#include "usb_lib_globals.h"
/* usb_lib headers */
#include "usb_type.h"
#include "usb_core.h"
static void dispatch_ctr_lp(void);
/*
* usb_lib/ globals
*/
uint16 SaveTState; /* caches TX status for later use */
uint16 SaveRState; /* caches RX status for later use */
/*
* Other state
*/
typedef enum {
RESUME_EXTERNAL,
RESUME_INTERNAL,
RESUME_LATER,
RESUME_WAIT,
RESUME_START,
RESUME_ON,
RESUME_OFF,
RESUME_ESOF
} RESUME_STATE;
struct {
volatile RESUME_STATE eState;
volatile uint8 bESOFcnt;
} ResumeS;
static usblib_dev usblib = {
.irq_mask = USB_ISR_MSK,
.state = USB_UNCONNECTED,
.prevState = USB_UNCONNECTED,
.clk_id = RCC_USB,
};
usblib_dev *USBLIB = &usblib;
/*
* Routines
*/
void usb_init_usblib(usblib_dev *dev,
void (**ep_int_in)(void),
void (**ep_int_out)(void)) {
rcc_clk_enable(dev->clk_id);
dev->ep_int_in = ep_int_in;
dev->ep_int_out = ep_int_out;
/* usb_lib/ declares both and then assumes that pFoo points to Foo
* (even though the names don't always match), which is stupid for
* all of the obvious reasons, but whatever. Here we are. */
pInformation = &Device_Info;
pProperty = &Device_Property;
pUser_Standard_Requests = &User_Standard_Requests;
pInformation->ControlState = 2; /* FIXME [0.0.12] use
CONTROL_STATE enumerator */
pProperty->Init();
}
static void usb_suspend(void) {
uint16 cntr;
/* TODO decide if read/modify/write is really what we want
* (e.g. usb_resume_init() reconfigures CNTR). */
cntr = USB_BASE->CNTR;
cntr |= USB_CNTR_FSUSP;
USB_BASE->CNTR = cntr;
cntr |= USB_CNTR_LP_MODE;
USB_BASE->CNTR = cntr;
USBLIB->prevState = USBLIB->state;
USBLIB->state = USB_SUSPENDED;
}
static void usb_resume_init(void) {
uint16 cntr;
cntr = USB_BASE->CNTR;
cntr &= ~USB_CNTR_LP_MODE;
USB_BASE->CNTR = cntr;
/* Enable interrupt lines */
USB_BASE->CNTR = USB_ISR_MSK;
}
static void usb_resume(RESUME_STATE eResumeSetVal) {
uint16 cntr;
if (eResumeSetVal != RESUME_ESOF) {
ResumeS.eState = eResumeSetVal;
}
switch (ResumeS.eState) {
case RESUME_EXTERNAL:
usb_resume_init();
ResumeS.eState = RESUME_OFF;
USBLIB->state = USBLIB->prevState;
break;
case RESUME_INTERNAL:
usb_resume_init();
ResumeS.eState = RESUME_START;
break;
case RESUME_LATER:
ResumeS.bESOFcnt = 2;
ResumeS.eState = RESUME_WAIT;
break;
case RESUME_WAIT:
ResumeS.bESOFcnt--;
if (ResumeS.bESOFcnt == 0) {
ResumeS.eState = RESUME_START;
}
break;
case RESUME_START:
cntr = USB_BASE->CNTR;
cntr |= USB_CNTR_RESUME;
USB_BASE->CNTR = cntr;
ResumeS.eState = RESUME_ON;
ResumeS.bESOFcnt = 10;
break;
case RESUME_ON:
ResumeS.bESOFcnt--;
if (ResumeS.bESOFcnt == 0) {
cntr = USB_BASE->CNTR;
cntr &= ~USB_CNTR_RESUME;
USB_BASE->CNTR = cntr;
USBLIB->state = USBLIB->prevState;
ResumeS.eState = RESUME_OFF;
}
break;
case RESUME_OFF:
case RESUME_ESOF:
default:
ResumeS.eState = RESUME_OFF;
break;
}
}
#define SUSPEND_ENABLED 1
void __irq_usb_lp_can_rx0(void) {
uint16 istr = USB_BASE->ISTR;
/* Use USB_ISR_MSK to only include code for bits we care about. */
#if (USB_ISR_MSK & USB_ISTR_RESET)
if (istr & USB_ISTR_RESET & USBLIB->irq_mask) {
USB_BASE->ISTR = ~USB_ISTR_RESET;
pProperty->Reset();
}
#endif
#if (USB_ISR_MSK & USB_ISTR_PMAOVR)
if (istr & ISTR_PMAOVR & USBLIB->irq_mask) {
USB_BASE->ISTR = ~USB_ISTR_PMAOVR;
}
#endif
#if (USB_ISR_MSK & USB_ISTR_ERR)
if (istr & USB_ISTR_ERR & USBLIB->irq_mask) {
USB_BASE->ISTR = ~USB_ISTR_ERR;
}
#endif
#if (USB_ISR_MSK & USB_ISTR_WKUP)
if (istr & USB_ISTR_WKUP & USBLIB->irq_mask) {
USB_BASE->ISTR = ~USB_ISTR_WKUP;
usb_resume(RESUME_EXTERNAL);
}
#endif
#if (USB_ISR_MSK & USB_ISTR_SUSP)
if (istr & USB_ISTR_SUSP & USBLIB->irq_mask) {
/* check if SUSPEND is possible */
if (SUSPEND_ENABLED) {
usb_suspend();
} else {
/* if not possible then resume after xx ms */
usb_resume(RESUME_LATER);
}
/* clear of the ISTR bit must be done after setting of CNTR_FSUSP */
USB_BASE->ISTR = ~USB_ISTR_SUSP;
}
#endif
#if (USB_ISR_MSK & USB_ISTR_SOF)
if (istr & USB_ISTR_SOF & USBLIB->irq_mask) {
USB_BASE->ISTR = ~USB_ISTR_SOF;
}
#endif
#if (USB_ISR_MSK & USB_ISTR_ESOF)
if (istr & USB_ISTR_ESOF & USBLIB->irq_mask) {
USB_BASE->ISTR = ~USB_ISTR_ESOF;
/* resume handling timing is made with ESOFs */
usb_resume(RESUME_ESOF); /* request without change of the machine state */
}
#endif
/*
* Service the correct transfer interrupt.
*/
#if (USB_ISR_MSK & USB_ISTR_CTR)
if (istr & USB_ISTR_CTR & USBLIB->irq_mask) {
dispatch_ctr_lp();
}
#endif
}
/*
* Auxiliary routines
*/
static inline uint8 dispatch_endpt_zero(uint16 istr_dir);
static inline void dispatch_endpt(uint8 ep);
static inline void set_rx_tx_status0(uint16 rx, uint16 tx);
static void handle_setup0(void);
static void handle_in0(void);
static void handle_out0(void);
static void dispatch_ctr_lp() {
uint16 istr;
while (((istr = USB_BASE->ISTR) & USB_ISTR_CTR) != 0) {
/* TODO WTF, figure this out: RM0008 says CTR is read-only,
* but ST's firmware claims it's clear-only, and emphasizes
* the importance of clearing it in more than one place. */
USB_BASE->ISTR = ~USB_ISTR_CTR;
uint8 ep_id = istr & USB_ISTR_EP_ID;
if (ep_id == 0) {
/* TODO figure out why it's OK to break out of the loop
* once we're done serving endpoint zero, but not okay if
* there are multiple nonzero endpoint transfers to
* handle. */
if (dispatch_endpt_zero(istr & USB_ISTR_DIR)) {
return;
}
} else {
dispatch_endpt(ep_id);
}
}
}
/* FIXME Dataflow on endpoint 0 RX/TX status is based off of ST's
* code, and is ugly/confusing in its use of SaveRState/SaveTState.
* Fixing this requires filling in handle_in0(), handle_setup0(),
* handle_out0(). */
static inline uint8 dispatch_endpt_zero(uint16 istr_dir) {
uint32 epr = (uint16)USB_BASE->EP[0];
if (!(epr & (USB_EP_CTR_TX | USB_EP_SETUP | USB_EP_CTR_RX))) {
return 0;
}
/* Cache RX/TX statuses in SaveRState/SaveTState, respectively.
* The various handle_foo0() may clobber these values
* before we reset them at the end of this routine. */
SaveRState = epr & USB_EP_STAT_RX;
SaveTState = epr & USB_EP_STAT_TX;
/* Set actual RX/TX statuses to NAK while we're thinking */
set_rx_tx_status0(USB_EP_STAT_RX_NAK, USB_EP_STAT_TX_NAK);
if (istr_dir == 0) {
/* ST RM0008: "If DIR bit=0, CTR_TX bit is set in the USB_EPnR
* register related to the interrupting endpoint. The
* interrupting transaction is of IN type (data transmitted by
* the USB peripheral to the host PC)." */
ASSERT_FAULT(epr & USB_EP_CTR_TX);
usb_clear_ctr_tx(USB_EP0);
handle_in0();
} else {
/* RM0008: "If DIR bit=1, CTR_RX bit or both CTR_TX/CTR_RX
* are set in the USB_EPnR register related to the
* interrupting endpoint. The interrupting transaction is of
* OUT type (data received by the USB peripheral from the host
* PC) or two pending transactions are waiting to be
* processed."
*
* [mbolivar] Note how the following control flow (which
* replicates ST's) doesn't seem to actually handle both
* interrupts that are ostensibly pending when both CTR_RX and
* CTR_TX are set.
*
* TODO sort this mess out.
*/
if (epr & USB_EP_CTR_TX) {
usb_clear_ctr_tx(USB_EP0);
handle_in0();
} else { /* SETUP or CTR_RX */
/* SETUP is held constant while CTR_RX is set, so clear it
* either way */
usb_clear_ctr_rx(USB_EP0);
if (epr & USB_EP_SETUP) {
handle_setup0();
} else { /* CTR_RX */
handle_out0();
}
}
}
set_rx_tx_status0(SaveRState, SaveTState);
return 1;
}
static inline void dispatch_endpt(uint8 ep) {
uint32 epr = USB_BASE->EP[ep];
/* If ISTR_CTR is set and the ISTR gave us this EP_ID to handle,
* then presumably at least one of CTR_RX and CTR_TX is set, but
* again, ST's control flow allows for the possibility of neither.
*
* TODO try to find out if neither being set is possible. */
if (epr & USB_EP_CTR_RX) {
usb_clear_ctr_rx(ep);
(USBLIB->ep_int_out[ep - 1])();
}
if (epr & USB_EP_CTR_TX) {
usb_clear_ctr_tx(ep);
(USBLIB->ep_int_in[ep - 1])();
}
}
static inline void set_rx_tx_status0(uint16 rx, uint16 tx) {
usb_set_ep_rx_stat(USB_EP0, rx);
usb_set_ep_tx_stat(USB_EP0, tx);
}
/* TODO Rip out usb_lib/ dependency from the following functions: */
static void handle_setup0(void) {
Setup0_Process();
}
static void handle_in0(void) {
In0_Process();
}
static void handle_out0(void) {
Out0_Process();
}

View File

@ -0,0 +1,711 @@
/******************************************************************************
* 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 libmaple/usb/stm32f1/usb_cdcacm.c
* @brief USB CDC ACM (a.k.a. virtual serial terminal, VCOM).
*
* FIXME: this works on the STM32F1 USB peripherals, and probably no
* place else. Nonportable bits really need to be factored out, and
* the result made cleaner.
*/
#include <libmaple/usb_cdcacm.h>
#include <libmaple/usb.h>
#include <libmaple/nvic.h>
#include <libmaple/delay.h>
/* Private headers */
#include "usb_lib_globals.h"
#include "usb_reg_map.h"
/* usb_lib headers */
#include "usb_type.h"
#include "usb_core.h"
#include "usb_def.h"
/******************************************************************************
******************************************************************************
***
*** HACK ALERT! FIXME FIXME FIXME FIXME!
***
*** A bunch of LeafLabs-specific configuration lives in here for
*** now. This mess REALLY needs to get teased apart, with
*** appropriate pieces moved into Wirish.
***
******************************************************************************
*****************************************************************************/
#if !(defined(BOARD_maple) || defined(BOARD_maple_RET6) || \
defined(BOARD_maple_mini) || defined(BOARD_maple_native))
#warning USB CDC ACM relies on LeafLabs board-specific configuration.\
You may have problems on non-LeafLabs boards.
#endif
static void vcomDataTxCb(void);
static void vcomDataRxCb(void);
static uint8* vcomGetSetLineCoding(uint16);
static void usbInit(void);
static void usbReset(void);
static RESULT usbDataSetup(uint8 request);
static RESULT usbNoDataSetup(uint8 request);
static RESULT usbGetInterfaceSetting(uint8 interface, uint8 alt_setting);
static uint8* usbGetDeviceDescriptor(uint16 length);
static uint8* usbGetConfigDescriptor(uint16 length);
static uint8* usbGetStringDescriptor(uint16 length);
static void usbSetConfiguration(void);
static void usbSetDeviceAddress(void);
/*
* Descriptors
*/
/* FIXME move to Wirish */
#define LEAFLABS_ID_VENDOR 0x1EAF
#define MAPLE_ID_PRODUCT 0x0004
static const usb_descriptor_device usbVcomDescriptor_Device =
USB_CDCACM_DECLARE_DEV_DESC(LEAFLABS_ID_VENDOR, MAPLE_ID_PRODUCT);
typedef struct {
usb_descriptor_config_header Config_Header;
usb_descriptor_interface CCI_Interface;
CDC_FUNCTIONAL_DESCRIPTOR(2) CDC_Functional_IntHeader;
CDC_FUNCTIONAL_DESCRIPTOR(2) CDC_Functional_CallManagement;
CDC_FUNCTIONAL_DESCRIPTOR(1) CDC_Functional_ACM;
CDC_FUNCTIONAL_DESCRIPTOR(2) CDC_Functional_Union;
usb_descriptor_endpoint ManagementEndpoint;
usb_descriptor_interface DCI_Interface;
usb_descriptor_endpoint DataOutEndpoint;
usb_descriptor_endpoint DataInEndpoint;
} __packed usb_descriptor_config;
#define MAX_POWER (100 >> 1)
static const usb_descriptor_config usbVcomDescriptor_Config = {
.Config_Header = {
.bLength = sizeof(usb_descriptor_config_header),
.bDescriptorType = USB_DESCRIPTOR_TYPE_CONFIGURATION,
.wTotalLength = sizeof(usb_descriptor_config),
.bNumInterfaces = 0x02,
.bConfigurationValue = 0x01,
.iConfiguration = 0x00,
.bmAttributes = (USB_CONFIG_ATTR_BUSPOWERED |
USB_CONFIG_ATTR_SELF_POWERED),
.bMaxPower = MAX_POWER,
},
.CCI_Interface = {
.bLength = sizeof(usb_descriptor_interface),
.bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE,
.bInterfaceNumber = 0x00,
.bAlternateSetting = 0x00,
.bNumEndpoints = 0x01,
.bInterfaceClass = USB_INTERFACE_CLASS_CDC,
.bInterfaceSubClass = USB_INTERFACE_SUBCLASS_CDC_ACM,
.bInterfaceProtocol = 0x01, /* Common AT Commands */
.iInterface = 0x00,
},
.CDC_Functional_IntHeader = {
.bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(2),
.bDescriptorType = 0x24,
.SubType = 0x00,
.Data = {0x01, 0x10},
},
.CDC_Functional_CallManagement = {
.bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(2),
.bDescriptorType = 0x24,
.SubType = 0x01,
.Data = {0x03, 0x01},
},
.CDC_Functional_ACM = {
.bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(1),
.bDescriptorType = 0x24,
.SubType = 0x02,
.Data = {0x06},
},
.CDC_Functional_Union = {
.bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(2),
.bDescriptorType = 0x24,
.SubType = 0x06,
.Data = {0x00, 0x01},
},
.ManagementEndpoint = {
.bLength = sizeof(usb_descriptor_endpoint),
.bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT,
.bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_IN |
USB_CDCACM_MANAGEMENT_ENDP),
.bmAttributes = USB_EP_TYPE_INTERRUPT,
.wMaxPacketSize = USB_CDCACM_MANAGEMENT_EPSIZE,
.bInterval = 0xFF,
},
.DCI_Interface = {
.bLength = sizeof(usb_descriptor_interface),
.bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE,
.bInterfaceNumber = 0x01,
.bAlternateSetting = 0x00,
.bNumEndpoints = 0x02,
.bInterfaceClass = USB_INTERFACE_CLASS_DIC,
.bInterfaceSubClass = 0x00, /* None */
.bInterfaceProtocol = 0x00, /* None */
.iInterface = 0x00,
},
.DataOutEndpoint = {
.bLength = sizeof(usb_descriptor_endpoint),
.bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT,
.bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_OUT |
USB_CDCACM_RX_ENDP),
.bmAttributes = USB_EP_TYPE_BULK,
.wMaxPacketSize = USB_CDCACM_RX_EPSIZE,
.bInterval = 0x00,
},
.DataInEndpoint = {
.bLength = sizeof(usb_descriptor_endpoint),
.bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT,
.bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_IN | USB_CDCACM_TX_ENDP),
.bmAttributes = USB_EP_TYPE_BULK,
.wMaxPacketSize = USB_CDCACM_TX_EPSIZE,
.bInterval = 0x00,
},
};
/*
String Descriptors:
we may choose to specify any or none of the following string
identifiers:
iManufacturer: LeafLabs
iProduct: Maple
iSerialNumber: NONE
iConfiguration: NONE
iInterface(CCI): NONE
iInterface(DCI): NONE
*/
/* Unicode language identifier: 0x0409 is US English */
/* FIXME move to Wirish */
static const usb_descriptor_string usbVcomDescriptor_LangID = {
.bLength = USB_DESCRIPTOR_STRING_LEN(1),
.bDescriptorType = USB_DESCRIPTOR_TYPE_STRING,
.bString = {0x09, 0x04},
};
/* FIXME move to Wirish */
static const usb_descriptor_string usbVcomDescriptor_iManufacturer = {
.bLength = USB_DESCRIPTOR_STRING_LEN(8),
.bDescriptorType = USB_DESCRIPTOR_TYPE_STRING,
.bString = {'L', 0, 'e', 0, 'a', 0, 'f', 0,
'L', 0, 'a', 0, 'b', 0, 's', 0},
};
/* FIXME move to Wirish */
static const usb_descriptor_string usbVcomDescriptor_iProduct = {
.bLength = USB_DESCRIPTOR_STRING_LEN(5),
.bDescriptorType = USB_DESCRIPTOR_TYPE_STRING,
.bString = {'M', 0, 'a', 0, 'p', 0, 'l', 0, 'e', 0},
};
static ONE_DESCRIPTOR Device_Descriptor = {
(uint8*)&usbVcomDescriptor_Device,
sizeof(usb_descriptor_device)
};
static ONE_DESCRIPTOR Config_Descriptor = {
(uint8*)&usbVcomDescriptor_Config,
sizeof(usb_descriptor_config)
};
#define N_STRING_DESCRIPTORS 3
static ONE_DESCRIPTOR String_Descriptor[N_STRING_DESCRIPTORS] = {
{(uint8*)&usbVcomDescriptor_LangID, USB_DESCRIPTOR_STRING_LEN(1)},
{(uint8*)&usbVcomDescriptor_iManufacturer,USB_DESCRIPTOR_STRING_LEN(8)},
{(uint8*)&usbVcomDescriptor_iProduct, USB_DESCRIPTOR_STRING_LEN(5)}
};
/*
* Etc.
*/
/* I/O state */
/* Received data */
static volatile uint8 vcomBufferRx[USB_CDCACM_RX_EPSIZE];
/* Read index into vcomBufferRx */
static volatile uint32 rx_offset = 0;
/* Number of bytes left to transmit */
static volatile uint32 n_unsent_bytes = 0;
/* Are we currently sending an IN packet? */
static volatile uint8 transmitting = 0;
/* Number of unread bytes */
static volatile uint32 n_unread_bytes = 0;
/* Other state (line coding, DTR/RTS) */
static volatile usb_cdcacm_line_coding line_coding = {
/* This default is 115200 baud, 8N1. */
.dwDTERate = 115200,
.bCharFormat = USB_CDCACM_STOP_BITS_1,
.bParityType = USB_CDCACM_PARITY_NONE,
.bDataBits = 8,
};
/* DTR in bit 0, RTS in bit 1. */
static volatile uint8 line_dtr_rts = 0;
/*
* Endpoint callbacks
*/
static void (*ep_int_in[7])(void) =
{vcomDataTxCb,
NOP_Process,
NOP_Process,
NOP_Process,
NOP_Process,
NOP_Process,
NOP_Process};
static void (*ep_int_out[7])(void) =
{NOP_Process,
NOP_Process,
vcomDataRxCb,
NOP_Process,
NOP_Process,
NOP_Process,
NOP_Process};
/*
* Globals required by usb_lib/
*
* Mark these weak so they can be overriden to implement other USB
* functionality.
*/
#define NUM_ENDPTS 0x04
__weak DEVICE Device_Table = {
.Total_Endpoint = NUM_ENDPTS,
.Total_Configuration = 1
};
#define MAX_PACKET_SIZE 0x40 /* 64B, maximum for USB FS Devices */
__weak DEVICE_PROP Device_Property = {
.Init = usbInit,
.Reset = usbReset,
.Process_Status_IN = NOP_Process,
.Process_Status_OUT = NOP_Process,
.Class_Data_Setup = usbDataSetup,
.Class_NoData_Setup = usbNoDataSetup,
.Class_Get_Interface_Setting = usbGetInterfaceSetting,
.GetDeviceDescriptor = usbGetDeviceDescriptor,
.GetConfigDescriptor = usbGetConfigDescriptor,
.GetStringDescriptor = usbGetStringDescriptor,
.RxEP_buffer = NULL,
.MaxPacketSize = MAX_PACKET_SIZE
};
__weak USER_STANDARD_REQUESTS User_Standard_Requests = {
.User_GetConfiguration = NOP_Process,
.User_SetConfiguration = usbSetConfiguration,
.User_GetInterface = NOP_Process,
.User_SetInterface = NOP_Process,
.User_GetStatus = NOP_Process,
.User_ClearFeature = NOP_Process,
.User_SetEndPointFeature = NOP_Process,
.User_SetDeviceFeature = NOP_Process,
.User_SetDeviceAddress = usbSetDeviceAddress
};
/*
* User hooks
*/
static void (*rx_hook)(unsigned, void*) = 0;
static void (*iface_setup_hook)(unsigned, void*) = 0;
void usb_cdcacm_set_hooks(unsigned hook_flags, void (*hook)(unsigned, void*)) {
if (hook_flags & USB_CDCACM_HOOK_RX) {
rx_hook = hook;
}
if (hook_flags & USB_CDCACM_HOOK_IFACE_SETUP) {
iface_setup_hook = hook;
}
}
/*
* CDC ACM interface
*/
void usb_cdcacm_enable(gpio_dev *disc_dev, uint8 disc_bit) {
/* Present ourselves to the host. Writing 0 to "disc" pin must
* pull USB_DP pin up while leaving USB_DM pulled down by the
* transceiver. See USB 2.0 spec, section 7.1.7.3. */
gpio_set_mode(disc_dev, disc_bit, GPIO_OUTPUT_PP);
gpio_write_bit(disc_dev, disc_bit, 0);
/* Initialize the USB peripheral. */
usb_init_usblib(USBLIB, ep_int_in, ep_int_out);
}
void usb_cdcacm_disable(gpio_dev *disc_dev, uint8 disc_bit) {
/* Turn off the interrupt and signal disconnect (see e.g. USB 2.0
* spec, section 7.1.7.3). */
nvic_irq_disable(NVIC_USB_LP_CAN_RX0);
gpio_write_bit(disc_dev, disc_bit, 1);
}
void usb_cdcacm_putc(char ch) {
while (!usb_cdcacm_tx((uint8*)&ch, 1))
;
}
/* This function is non-blocking.
*
* It copies data from a usercode buffer into the USB peripheral TX
* buffer, and returns the number of bytes copied. */
uint32 usb_cdcacm_tx(const uint8* buf, uint32 len) {
/* Last transmission hasn't finished, so abort. */
if (usb_cdcacm_is_transmitting()) {
return 0;
}
/* We can only put USB_CDCACM_TX_EPSIZE bytes in the buffer. */
if (len > USB_CDCACM_TX_EPSIZE) {
len = USB_CDCACM_TX_EPSIZE;
}
/* Queue bytes for sending. */
if (len) {
usb_copy_to_pma(buf, len, USB_CDCACM_TX_ADDR);
}
// We still need to wait for the interrupt, even if we're sending
// zero bytes. (Sending zero-size packets is useful for flushing
// host-side buffers.)
usb_set_ep_tx_count(USB_CDCACM_TX_ENDP, len);
n_unsent_bytes = len;
transmitting = 1;
usb_set_ep_tx_stat(USB_CDCACM_TX_ENDP, USB_EP_STAT_TX_VALID);
return len;
}
uint32 usb_cdcacm_data_available(void) {
return n_unread_bytes;
}
uint8 usb_cdcacm_is_transmitting(void) {
return transmitting;
}
uint16 usb_cdcacm_get_pending(void) {
return n_unsent_bytes;
}
/* Nonblocking byte receive.
*
* Copies up to len bytes from our private data buffer (*NOT* the PMA)
* into buf and deq's the FIFO. */
uint32 usb_cdcacm_rx(uint8* buf, uint32 len) {
/* Copy bytes to buffer. */
uint32 n_copied = usb_cdcacm_peek(buf, len);
/* Mark bytes as read. */
n_unread_bytes -= n_copied;
rx_offset += n_copied;
/* If all bytes have been read, re-enable the RX endpoint, which
* was set to NAK when the current batch of bytes was received. */
if (n_unread_bytes == 0) {
usb_set_ep_rx_count(USB_CDCACM_RX_ENDP, USB_CDCACM_RX_EPSIZE);
usb_set_ep_rx_stat(USB_CDCACM_RX_ENDP, USB_EP_STAT_RX_VALID);
rx_offset = 0;
}
return n_copied;
}
/* Nonblocking byte lookahead.
*
* Looks at unread bytes without marking them as read. */
uint32 usb_cdcacm_peek(uint8* buf, uint32 len) {
int i;
if (len > n_unread_bytes) {
len = n_unread_bytes;
}
for (i = 0; i < len; i++) {
buf[i] = vcomBufferRx[i + rx_offset];
}
return len;
}
uint8 usb_cdcacm_get_dtr() {
return ((line_dtr_rts & USB_CDCACM_CONTROL_LINE_DTR) != 0);
}
uint8 usb_cdcacm_get_rts() {
return ((line_dtr_rts & USB_CDCACM_CONTROL_LINE_RTS) != 0);
}
void usb_cdcacm_get_line_coding(usb_cdcacm_line_coding *ret) {
ret->dwDTERate = line_coding.dwDTERate;
ret->bCharFormat = line_coding.bCharFormat;
ret->bParityType = line_coding.bParityType;
ret->bDataBits = line_coding.bDataBits;
}
int usb_cdcacm_get_baud(void) {
return line_coding.dwDTERate;
}
int usb_cdcacm_get_stop_bits(void) {
return line_coding.bCharFormat;
}
int usb_cdcacm_get_parity(void) {
return line_coding.bParityType;
}
int usb_cdcacm_get_n_data_bits(void) {
return line_coding.bDataBits;
}
/*
* Callbacks
*/
static void vcomDataTxCb(void) {
n_unsent_bytes = 0;
transmitting = 0;
}
static void vcomDataRxCb(void) {
usb_set_ep_rx_stat(USB_CDCACM_RX_ENDP, USB_EP_STAT_RX_NAK);
n_unread_bytes = usb_get_ep_rx_count(USB_CDCACM_RX_ENDP);
/* This copy won't overwrite unread bytes, since we've set the RX
* endpoint to NAK, and will only set it to VALID when all bytes
* have been read. */
usb_copy_from_pma((uint8*)vcomBufferRx, n_unread_bytes,
USB_CDCACM_RX_ADDR);
if (n_unread_bytes == 0) {
usb_set_ep_rx_count(USB_CDCACM_RX_ENDP, USB_CDCACM_RX_EPSIZE);
usb_set_ep_rx_stat(USB_CDCACM_RX_ENDP, USB_EP_STAT_RX_VALID);
rx_offset = 0;
}
if (rx_hook) {
rx_hook(USB_CDCACM_HOOK_RX, 0);
}
}
static uint8* vcomGetSetLineCoding(uint16 length) {
if (length == 0) {
pInformation->Ctrl_Info.Usb_wLength = sizeof(struct usb_cdcacm_line_coding);
}
return (uint8*)&line_coding;
}
static void usbInit(void) {
pInformation->Current_Configuration = 0;
USB_BASE->CNTR = USB_CNTR_FRES;
USBLIB->irq_mask = 0;
USB_BASE->CNTR = USBLIB->irq_mask;
USB_BASE->ISTR = 0;
USBLIB->irq_mask = USB_CNTR_RESETM | USB_CNTR_SUSPM | USB_CNTR_WKUPM;
USB_BASE->CNTR = USBLIB->irq_mask;
USB_BASE->ISTR = 0;
USBLIB->irq_mask = USB_ISR_MSK;
USB_BASE->CNTR = USBLIB->irq_mask;
nvic_irq_enable(NVIC_USB_LP_CAN_RX0);
USBLIB->state = USB_UNCONNECTED;
}
#define BTABLE_ADDRESS 0x00
static void usbReset(void) {
pInformation->Current_Configuration = 0;
/* current feature is current bmAttributes */
pInformation->Current_Feature = (USB_CONFIG_ATTR_BUSPOWERED |
USB_CONFIG_ATTR_SELF_POWERED);
USB_BASE->BTABLE = BTABLE_ADDRESS;
/* setup control endpoint 0 */
usb_set_ep_type(USB_EP0, USB_EP_EP_TYPE_CONTROL);
usb_set_ep_tx_stat(USB_EP0, USB_EP_STAT_TX_STALL);
usb_set_ep_rx_addr(USB_EP0, USB_CDCACM_CTRL_RX_ADDR);
usb_set_ep_tx_addr(USB_EP0, USB_CDCACM_CTRL_TX_ADDR);
usb_clear_status_out(USB_EP0);
usb_set_ep_rx_count(USB_EP0, pProperty->MaxPacketSize);
usb_set_ep_rx_stat(USB_EP0, USB_EP_STAT_RX_VALID);
/* setup management endpoint 1 */
usb_set_ep_type(USB_CDCACM_MANAGEMENT_ENDP, USB_EP_EP_TYPE_INTERRUPT);
usb_set_ep_tx_addr(USB_CDCACM_MANAGEMENT_ENDP,
USB_CDCACM_MANAGEMENT_ADDR);
usb_set_ep_tx_stat(USB_CDCACM_MANAGEMENT_ENDP, USB_EP_STAT_TX_NAK);
usb_set_ep_rx_stat(USB_CDCACM_MANAGEMENT_ENDP, USB_EP_STAT_RX_DISABLED);
/* TODO figure out differences in style between RX/TX EP setup */
/* set up data endpoint OUT (RX) */
usb_set_ep_type(USB_CDCACM_RX_ENDP, USB_EP_EP_TYPE_BULK);
usb_set_ep_rx_addr(USB_CDCACM_RX_ENDP, USB_CDCACM_RX_ADDR);
usb_set_ep_rx_count(USB_CDCACM_RX_ENDP, USB_CDCACM_RX_EPSIZE);
usb_set_ep_rx_stat(USB_CDCACM_RX_ENDP, USB_EP_STAT_RX_VALID);
/* set up data endpoint IN (TX) */
usb_set_ep_type(USB_CDCACM_TX_ENDP, USB_EP_EP_TYPE_BULK);
usb_set_ep_tx_addr(USB_CDCACM_TX_ENDP, USB_CDCACM_TX_ADDR);
usb_set_ep_tx_stat(USB_CDCACM_TX_ENDP, USB_EP_STAT_TX_NAK);
usb_set_ep_rx_stat(USB_CDCACM_TX_ENDP, USB_EP_STAT_RX_DISABLED);
USBLIB->state = USB_ATTACHED;
SetDeviceAddress(0);
/* Reset the RX/TX state */
n_unread_bytes = 0;
n_unsent_bytes = 0;
rx_offset = 0;
transmitting = 0;
}
static RESULT usbDataSetup(uint8 request) {
uint8* (*CopyRoutine)(uint16) = 0;
if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) {
switch (request) {
case USB_CDCACM_GET_LINE_CODING:
CopyRoutine = vcomGetSetLineCoding;
break;
case USB_CDCACM_SET_LINE_CODING:
CopyRoutine = vcomGetSetLineCoding;
break;
default:
break;
}
/* Call the user hook. */
if (iface_setup_hook) {
uint8 req_copy = request;
iface_setup_hook(USB_CDCACM_HOOK_IFACE_SETUP, &req_copy);
}
}
if (CopyRoutine == NULL) {
return USB_UNSUPPORT;
}
pInformation->Ctrl_Info.CopyData = CopyRoutine;
pInformation->Ctrl_Info.Usb_wOffset = 0;
(*CopyRoutine)(0);
return USB_SUCCESS;
}
static RESULT usbNoDataSetup(uint8 request) {
RESULT ret = USB_UNSUPPORT;
if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) {
switch (request) {
case USB_CDCACM_SET_COMM_FEATURE:
/* We support set comm. feature, but don't handle it. */
ret = USB_SUCCESS;
break;
case USB_CDCACM_SET_CONTROL_LINE_STATE:
/* Track changes to DTR and RTS. */
line_dtr_rts = (pInformation->USBwValues.bw.bb0 &
(USB_CDCACM_CONTROL_LINE_DTR |
USB_CDCACM_CONTROL_LINE_RTS));
ret = USB_SUCCESS;
break;
}
/* Call the user hook. */
if (iface_setup_hook) {
uint8 req_copy = request;
iface_setup_hook(USB_CDCACM_HOOK_IFACE_SETUP, &req_copy);
}
}
return ret;
}
static RESULT usbGetInterfaceSetting(uint8 interface, uint8 alt_setting) {
if (alt_setting > 0) {
return USB_UNSUPPORT;
} else if (interface > 1) {
return USB_UNSUPPORT;
}
return USB_SUCCESS;
}
static uint8* usbGetDeviceDescriptor(uint16 length) {
return Standard_GetDescriptorData(length, &Device_Descriptor);
}
static uint8* usbGetConfigDescriptor(uint16 length) {
return Standard_GetDescriptorData(length, &Config_Descriptor);
}
static uint8* usbGetStringDescriptor(uint16 length) {
uint8 wValue0 = pInformation->USBwValue0;
if (wValue0 > N_STRING_DESCRIPTORS) {
return NULL;
}
return Standard_GetDescriptorData(length, &String_Descriptor[wValue0]);
}
static void usbSetConfiguration(void) {
if (pInformation->Current_Configuration != 0) {
USBLIB->state = USB_CONFIGURED;
}
}
static void usbSetDeviceAddress(void) {
USBLIB->state = USB_ADDRESSED;
}

View File

@ -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.
*****************************************************************************/
#include "usb_reg_map.h"
/* TODO these could use some improvement; they're fairly
* straightforward ports of the analogous ST code. The PMA blit
* routines in particular are obvious targets for performance
* measurement and tuning. */
void usb_copy_to_pma(const uint8 *buf, uint16 len, uint16 pma_offset) {
uint16 *dst = (uint16*)usb_pma_ptr(pma_offset);
uint16 n = len >> 1;
uint16 i;
for (i = 0; i < n; i++) {
*dst = (uint16)(*buf) | *(buf + 1) << 8;
buf += 2;
dst += 2;
}
if (len & 1) {
*dst = *buf;
}
}
void usb_copy_from_pma(uint8 *buf, uint16 len, uint16 pma_offset) {
uint32 *src = (uint32*)usb_pma_ptr(pma_offset);
uint16 *dst = (uint16*)buf;
uint16 n = len >> 1;
uint16 i;
for (i = 0; i < n; i++) {
*dst++ = *src++;
}
if (len & 1) {
*dst = *src & 0xFF;
}
}
static void usb_set_ep_rx_count_common(uint32 *rxc, uint16 count) {
uint16 nblocks;
if (count > 62) {
/* use 32-byte memory block size */
nblocks = count >> 5;
if ((count & 0x1F) == 0) {
nblocks--;
}
*rxc = (nblocks << 10) | 0x8000;
} else {
/* use 2-byte memory block size */
nblocks = count >> 1;
if ((count & 0x1) != 0) {
nblocks++;
}
*rxc = nblocks << 10;
}
}
void usb_set_ep_rx_buf0_count(uint8 ep, uint16 count) {
uint32 *rxc = usb_ep_rx_buf0_count_ptr(ep);
usb_set_ep_rx_count_common(rxc, count);
}
void usb_set_ep_rx_count(uint8 ep, uint16 count) {
uint32 *rxc = usb_ep_rx_count_ptr(ep);
usb_set_ep_rx_count_common(rxc, count);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,64 @@
/******************** (C) COPYRIGHT 2008 STMicroelectronics ********************
* File Name : usb_init.c
* Author : MCD Application Team
* Version : V2.2.1
* Date : 09/22/2008
* Description : Initialization routines & global variables
********************************************************************************
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "usb_lib.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* The number of current endpoint, it will be used to specify an endpoint */
u8 EPindex;
/* The number of current device, it is an index to the Device_Table */
/* u8 Device_no; */
/* Points to the DEVICE_INFO structure of current device */
/* The purpose of this register is to speed up the execution */
DEVICE_INFO *pInformation;
/* Points to the DEVICE_PROP structure of current device */
/* The purpose of this register is to speed up the execution */
DEVICE_PROP *pProperty;
/* Temporary save the state of Rx & Tx status. */
/* Whenever the Rx or Tx state is changed, its value is saved */
/* in this variable first and will be set to the EPRB or EPRA */
/* at the end of interrupt process */
u16 SaveState ;
u16 wInterrupt_Mask;
DEVICE_INFO Device_Info;
USER_STANDARD_REQUESTS *pUser_Standard_Requests;
/* Extern variables ----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/*******************************************************************************
* Function Name : USB_Init
* Description : USB system initialization
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
void USB_Init(void)
{
pInformation = &Device_Info;
pInformation->ControlState = 2;
pProperty = &Device_Property;
pUser_Standard_Requests = &User_Standard_Requests;
/* Initialize devices one by one */
pProperty->Init();
}
/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/

View File

@ -0,0 +1,73 @@
/******************** (C) COPYRIGHT 2008 STMicroelectronics ********************
* File Name : usb_mem.c
* Author : MCD Application Team
* Version : V2.2.1
* Date : 09/22/2008
* Description : Utility functions for memory transfers to/from PMA
********************************************************************************
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "usb_lib.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Extern variables ----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/*******************************************************************************
* Function Name : UserToPMABufferCopy
* Description : Copy a buffer from user memory area to packet memory area (PMA)
* Input : - pbUsrBuf: pointer to user memory area.
* - wPMABufAddr: address into PMA.
* - wNBytes: no. of bytes to be copied.
* Output : None.
* Return : None .
*******************************************************************************/
void UserToPMABufferCopy(const u8 *pbUsrBuf, u16 wPMABufAddr, u16 wNBytes)
{
u32 n = (wNBytes + 1) >> 1; /* n = (wNBytes + 1) / 2 */
u32 i, temp1, temp2;
u16 *pdwVal;
pdwVal = (u16 *)(wPMABufAddr * 2 + PMAAddr);
for (i = n; i != 0; i--)
{
temp1 = (u16) * pbUsrBuf;
pbUsrBuf++;
temp2 = temp1 | (u16) * pbUsrBuf << 8;
*pdwVal++ = temp2;
pdwVal++;
pbUsrBuf++;
}
}
/*******************************************************************************
* Function Name : PMAToUserBufferCopy
* Description : Copy a buffer from user memory area to packet memory area (PMA)
* Input : - pbUsrBuf = pointer to user memory area.
* - wPMABufAddr = address into PMA.
* - wNBytes = no. of bytes to be copied.
* Output : None.
* Return : None.
*******************************************************************************/
void PMAToUserBufferCopy(u8 *pbUsrBuf, u16 wPMABufAddr, u16 wNBytes)
{
u32 n = (wNBytes + 1) >> 1;/* /2*/
u32 i;
u32 *pdwVal;
pdwVal = (u32 *)(wPMABufAddr * 2 + PMAAddr);
for (i = n; i != 0; i--)
{
*(u16*)pbUsrBuf++ = *pdwVal++;
pbUsrBuf++;
}
}
/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/

View File

@ -0,0 +1,748 @@
/******************** (C) COPYRIGHT 2008 STMicroelectronics ********************
* File Name : usb_regs.c
* Author : MCD Application Team
* Version : V2.2.1
* Date : 09/22/2008
* Description : Interface functions to USB cell registers
********************************************************************************
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "usb_lib.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Extern variables ----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/*******************************************************************************
* Function Name : SetCNTR.
* Description : Set the CNTR register value.
* Input : wRegValue: new register value.
* Output : None.
* Return : None.
*******************************************************************************/
void SetCNTR(u16 wRegValue)
{
_SetCNTR(wRegValue);
}
/*******************************************************************************
* Function Name : GetCNTR.
* Description : returns the CNTR register value.
* Input : None.
* Output : None.
* Return : CNTR register Value.
*******************************************************************************/
u16 GetCNTR(void)
{
return(_GetCNTR());
}
/*******************************************************************************
* Function Name : SetISTR.
* Description : Set the ISTR register value.
* Input : wRegValue: new register value.
* Output : None.
* Return : None.
*******************************************************************************/
void SetISTR(u16 wRegValue)
{
_SetISTR(wRegValue);
}
/*******************************************************************************
* Function Name : GetISTR
* Description : Returns the ISTR register value.
* Input : None.
* Output : None.
* Return : ISTR register Value
*******************************************************************************/
u16 GetISTR(void)
{
return(_GetISTR());
}
/*******************************************************************************
* Function Name : GetFNR
* Description : Returns the FNR register value.
* Input : None.
* Output : None.
* Return : FNR register Value
*******************************************************************************/
u16 GetFNR(void)
{
return(_GetFNR());
}
/*******************************************************************************
* Function Name : SetDADDR
* Description : Set the DADDR register value.
* Input : wRegValue: new register value.
* Output : None.
* Return : None.
*******************************************************************************/
void SetDADDR(u16 wRegValue)
{
_SetDADDR(wRegValue);
}
/*******************************************************************************
* Function Name : GetDADDR
* Description : Returns the DADDR register value.
* Input : None.
* Output : None.
* Return : DADDR register Value
*******************************************************************************/
u16 GetDADDR(void)
{
return(_GetDADDR());
}
/*******************************************************************************
* Function Name : SetBTABLE
* Description : Set the BTABLE.
* Input : wRegValue: New register value.
* Output : None.
* Return : None.
*******************************************************************************/
void SetBTABLE(u16 wRegValue)
{
_SetBTABLE(wRegValue);
}
/*******************************************************************************
* Function Name : GetBTABLE.
* Description : Returns the BTABLE register value.
* Input : None.
* Output : None.
* Return : BTABLE address.
*******************************************************************************/
u16 GetBTABLE(void)
{
return(_GetBTABLE());
}
/*******************************************************************************
* Function Name : SetENDPOINT
* Description : Setthe Endpoint register value.
* Input : bEpNum: Endpoint Number.
* wRegValue.
* Output : None.
* Return : None.
*******************************************************************************/
void SetENDPOINT(u8 bEpNum, u16 wRegValue)
{
_SetENDPOINT(bEpNum, wRegValue);
}
/*******************************************************************************
* Function Name : GetENDPOINT
* Description : Return the Endpoint register value.
* Input : bEpNum: Endpoint Number.
* Output : None.
* Return : Endpoint register value.
*******************************************************************************/
u16 GetENDPOINT(u8 bEpNum)
{
return(_GetENDPOINT(bEpNum));
}
/*******************************************************************************
* Function Name : SetEPType
* Description : sets the type in the endpoint register.
* Input : bEpNum: Endpoint Number.
* wType: type definition.
* Output : None.
* Return : None.
*******************************************************************************/
void SetEPType(u8 bEpNum, u16 wType)
{
_SetEPType(bEpNum, wType);
}
/*******************************************************************************
* Function Name : GetEPType
* Description : Returns the endpoint type.
* Input : bEpNum: Endpoint Number.
* Output : None.
* Return : Endpoint Type
*******************************************************************************/
u16 GetEPType(u8 bEpNum)
{
return(_GetEPType(bEpNum));
}
/*******************************************************************************
* Function Name : SetEPTxStatus
* Description : Set the status of Tx endpoint.
* Input : bEpNum: Endpoint Number.
* wState: new state.
* Output : None.
* Return : None.
*******************************************************************************/
void SetEPTxStatus(u8 bEpNum, u16 wState)
{
_SetEPTxStatus(bEpNum, wState);
}
/*******************************************************************************
* Function Name : SetEPRxStatus
* Description : Set the status of Rx endpoint.
* Input : bEpNum: Endpoint Number.
* wState: new state.
* Output : None.
* Return : None.
*******************************************************************************/
void SetEPRxStatus(u8 bEpNum, u16 wState)
{
_SetEPRxStatus(bEpNum, wState);
}
/*******************************************************************************
* Function Name : SetDouBleBuffEPStall
* Description : sets the status for Double Buffer Endpoint to STALL
* Input : bEpNum: Endpoint Number.
* bDir: Endpoint direction.
* Output : None.
* Return : None.
*******************************************************************************/
void SetDouBleBuffEPStall(u8 bEpNum, u8 bDir)
{
u16 Endpoint_DTOG_Status;
Endpoint_DTOG_Status = GetENDPOINT(bEpNum);
if (bDir == EP_DBUF_OUT)
{ /* OUT double buffered endpoint */
_SetENDPOINT(bEpNum, Endpoint_DTOG_Status & ~EPRX_DTOG1);
}
else if (bDir == EP_DBUF_IN)
{ /* IN double buffered endpoint */
_SetENDPOINT(bEpNum, Endpoint_DTOG_Status & ~EPTX_DTOG1);
}
}
/*******************************************************************************
* Function Name : GetEPTxStatus
* Description : Returns the endpoint Tx status.
* Input : bEpNum: Endpoint Number.
* Output : None.
* Return : Endpoint TX Status
*******************************************************************************/
u16 GetEPTxStatus(u8 bEpNum)
{
return(_GetEPTxStatus(bEpNum));
}
/*******************************************************************************
* Function Name : GetEPRxStatus
* Description : Returns the endpoint Rx status.
* Input : bEpNum: Endpoint Number.
* Output : None.
* Return : Endpoint RX Status
*******************************************************************************/
u16 GetEPRxStatus(u8 bEpNum)
{
return(_GetEPRxStatus(bEpNum));
}
/*******************************************************************************
* Function Name : SetEPTxValid
* Description : Valid the endpoint Tx Status.
* Input : bEpNum: Endpoint Number.
* Output : None.
* Return : None.
*******************************************************************************/
void SetEPTxValid(u8 bEpNum)
{
_SetEPTxStatus(bEpNum, EP_TX_VALID);
}
/*******************************************************************************
* Function Name : SetEPRxValid
* Description : Valid the endpoint Rx Status.
* Input : bEpNum: Endpoint Number.
* Output : None.
* Return : None.
*******************************************************************************/
void SetEPRxValid(u8 bEpNum)
{
_SetEPRxStatus(bEpNum, EP_RX_VALID);
}
/*******************************************************************************
* Function Name : SetEP_KIND
* Description : Clear the EP_KIND bit.
* Input : bEpNum: Endpoint Number.
* Output : None.
* Return : None.
*******************************************************************************/
void SetEP_KIND(u8 bEpNum)
{
_SetEP_KIND(bEpNum);
}
/*******************************************************************************
* Function Name : ClearEP_KIND
* Description : set the EP_KIND bit.
* Input : bEpNum: Endpoint Number.
* Output : None.
* Return : None.
*******************************************************************************/
void ClearEP_KIND(u8 bEpNum)
{
_ClearEP_KIND(bEpNum);
}
/*******************************************************************************
* Function Name : Clear_Status_Out
* Description : Clear the Status Out of the related Endpoint
* Input : bEpNum: Endpoint Number.
* Output : None.
* Return : None.
*******************************************************************************/
void Clear_Status_Out(u8 bEpNum)
{
_ClearEP_KIND(bEpNum);
}
/*******************************************************************************
* Function Name : Set_Status_Out
* Description : Set the Status Out of the related Endpoint
* Input : bEpNum: Endpoint Number.
* Output : None.
* Return : None.
*******************************************************************************/
void Set_Status_Out(u8 bEpNum)
{
_SetEP_KIND(bEpNum);
}
/*******************************************************************************
* Function Name : SetEPDoubleBuff
* Description : Enable the double buffer feature for the endpoint.
* Input : bEpNum: Endpoint Number.
* Output : None.
* Return : None.
*******************************************************************************/
void SetEPDoubleBuff(u8 bEpNum)
{
_SetEP_KIND(bEpNum);
}
/*******************************************************************************
* Function Name : ClearEPDoubleBuff
* Description : Disable the double buffer feature for the endpoint.
* Input : bEpNum: Endpoint Number.
* Output : None.
* Return : None.
*******************************************************************************/
void ClearEPDoubleBuff(u8 bEpNum)
{
_ClearEP_KIND(bEpNum);
}
/*******************************************************************************
* Function Name : GetTxStallStatus
* Description : Returns the Stall status of the Tx endpoint.
* Input : bEpNum: Endpoint Number.
* Output : None.
* Return : Tx Stall status.
*******************************************************************************/
u16 GetTxStallStatus(u8 bEpNum)
{
return(_GetTxStallStatus(bEpNum));
}
/*******************************************************************************
* Function Name : GetRxStallStatus
* Description : Returns the Stall status of the Rx endpoint.
* Input : bEpNum: Endpoint Number.
* Output : None.
* Return : Rx Stall status.
*******************************************************************************/
u16 GetRxStallStatus(u8 bEpNum)
{
return(_GetRxStallStatus(bEpNum));
}
/*******************************************************************************
* Function Name : ClearEP_CTR_RX
* Description : Clear the CTR_RX bit.
* Input : bEpNum: Endpoint Number.
* Output : None.
* Return : None.
*******************************************************************************/
void ClearEP_CTR_RX(u8 bEpNum)
{
_ClearEP_CTR_RX(bEpNum);
}
/*******************************************************************************
* Function Name : ClearEP_CTR_TX
* Description : Clear the CTR_TX bit.
* Input : bEpNum: Endpoint Number.
* Output : None.
* Return : None.
*******************************************************************************/
void ClearEP_CTR_TX(u8 bEpNum)
{
_ClearEP_CTR_TX(bEpNum);
}
/*******************************************************************************
* Function Name : ToggleDTOG_RX
* Description : Toggle the DTOG_RX bit.
* Input : bEpNum: Endpoint Number.
* Output : None.
* Return : None.
*******************************************************************************/
void ToggleDTOG_RX(u8 bEpNum)
{
_ToggleDTOG_RX(bEpNum);
}
/*******************************************************************************
* Function Name : ToggleDTOG_TX
* Description : Toggle the DTOG_TX bit.
* Input : bEpNum: Endpoint Number.
* Output : None.
* Return : None.
*******************************************************************************/
void ToggleDTOG_TX(u8 bEpNum)
{
_ToggleDTOG_TX(bEpNum);
}
/*******************************************************************************
* Function Name : ClearDTOG_RX.
* Description : Clear the DTOG_RX bit.
* Input : bEpNum: Endpoint Number.
* Output : None.
* Return : None.
*******************************************************************************/
void ClearDTOG_RX(u8 bEpNum)
{
_ClearDTOG_RX(bEpNum);
}
/*******************************************************************************
* Function Name : ClearDTOG_TX.
* Description : Clear the DTOG_TX bit.
* Input : bEpNum: Endpoint Number.
* Output : None.
* Return : None.
*******************************************************************************/
void ClearDTOG_TX(u8 bEpNum)
{
_ClearDTOG_TX(bEpNum);
}
/*******************************************************************************
* Function Name : SetEPAddress
* Description : Set the endpoint address.
* Input : bEpNum: Endpoint Number.
* bAddr: New endpoint address.
* Output : None.
* Return : None.
*******************************************************************************/
void SetEPAddress(u8 bEpNum, u8 bAddr)
{
_SetEPAddress(bEpNum, bAddr);
}
/*******************************************************************************
* Function Name : GetEPAddress
* Description : Get the endpoint address.
* Input : bEpNum: Endpoint Number.
* Output : None.
* Return : Endpoint address.
*******************************************************************************/
u8 GetEPAddress(u8 bEpNum)
{
return(_GetEPAddress(bEpNum));
}
/*******************************************************************************
* Function Name : SetEPTxAddr
* Description : Set the endpoint Tx buffer address.
* Input : bEpNum: Endpoint Number.
* wAddr: new address.
* Output : None.
* Return : None.
*******************************************************************************/
void SetEPTxAddr(u8 bEpNum, u16 wAddr)
{
_SetEPTxAddr(bEpNum, wAddr);
}
/*******************************************************************************
* Function Name : SetEPRxAddr
* Description : Set the endpoint Rx buffer address.
* Input : bEpNum: Endpoint Number.
* wAddr: new address.
* Output : None.
* Return : None.
*******************************************************************************/
void SetEPRxAddr(u8 bEpNum, u16 wAddr)
{
_SetEPRxAddr(bEpNum, wAddr);
}
/*******************************************************************************
* Function Name : GetEPTxAddr
* Description : Returns the endpoint Tx buffer address.
* Input : bEpNum: Endpoint Number.
* Output : None.
* Return : Rx buffer address.
*******************************************************************************/
u16 GetEPTxAddr(u8 bEpNum)
{
return(_GetEPTxAddr(bEpNum));
}
/*******************************************************************************
* Function Name : GetEPRxAddr.
* Description : Returns the endpoint Rx buffer address.
* Input : bEpNum: Endpoint Number.
* Output : None.
* Return : Rx buffer address.
*******************************************************************************/
u16 GetEPRxAddr(u8 bEpNum)
{
return(_GetEPRxAddr(bEpNum));
}
/*******************************************************************************
* Function Name : SetEPTxCount.
* Description : Set the Tx count.
* Input : bEpNum: Endpoint Number.
* wCount: new count value.
* Output : None.
* Return : None.
*******************************************************************************/
void SetEPTxCount(u8 bEpNum, u16 wCount)
{
_SetEPTxCount(bEpNum, wCount);
}
/*******************************************************************************
* Function Name : SetEPCountRxReg.
* Description : Set the Count Rx Register value.
* Input : *pdwReg: point to the register.
* wCount: the new register value.
* Output : None.
* Return : None.
*******************************************************************************/
void SetEPCountRxReg(u32 *pdwReg, u16 wCount)
{
_SetEPCountRxReg(dwReg, wCount);
}
/*******************************************************************************
* Function Name : SetEPRxCount
* Description : Set the Rx count.
* Input : bEpNum: Endpoint Number.
* wCount: the new count value.
* Output : None.
* Return : None.
*******************************************************************************/
void SetEPRxCount(u8 bEpNum, u16 wCount)
{
_SetEPRxCount(bEpNum, wCount);
}
/*******************************************************************************
* Function Name : GetEPTxCount
* Description : Get the Tx count.
* Input : bEpNum: Endpoint Number.
* Output : None
* Return : Tx count value.
*******************************************************************************/
u16 GetEPTxCount(u8 bEpNum)
{
return(_GetEPTxCount(bEpNum));
}
/*******************************************************************************
* Function Name : GetEPRxCount
* Description : Get the Rx count.
* Input : bEpNum: Endpoint Number.
* Output : None.
* Return : Rx count value.
*******************************************************************************/
u16 GetEPRxCount(u8 bEpNum)
{
return(_GetEPRxCount(bEpNum));
}
/*******************************************************************************
* Function Name : SetEPDblBuffAddr
* Description : Set the addresses of the buffer 0 and 1.
* Input : bEpNum: Endpoint Number.
* wBuf0Addr: new address of buffer 0.
* wBuf1Addr: new address of buffer 1.
* Output : None.
* Return : None.
*******************************************************************************/
void SetEPDblBuffAddr(u8 bEpNum, u16 wBuf0Addr, u16 wBuf1Addr)
{
_SetEPDblBuffAddr(bEpNum, wBuf0Addr, wBuf1Addr);
}
/*******************************************************************************
* Function Name : SetEPDblBuf0Addr
* Description : Set the Buffer 1 address.
* Input : bEpNum: Endpoint Number
* wBuf0Addr: new address.
* Output : None.
* Return : None.
*******************************************************************************/
void SetEPDblBuf0Addr(u8 bEpNum, u16 wBuf0Addr)
{
_SetEPDblBuf0Addr(bEpNum, wBuf0Addr);
}
/*******************************************************************************
* Function Name : SetEPDblBuf1Addr
* Description : Set the Buffer 1 address.
* Input : bEpNum: Endpoint Number
* wBuf1Addr: new address.
* Output : None.
* Return : None.
*******************************************************************************/
void SetEPDblBuf1Addr(u8 bEpNum, u16 wBuf1Addr)
{
_SetEPDblBuf1Addr(bEpNum, wBuf1Addr);
}
/*******************************************************************************
* Function Name : GetEPDblBuf0Addr
* Description : Returns the address of the Buffer 0.
* Input : bEpNum: Endpoint Number.
* Output : None.
* Return : None.
*******************************************************************************/
u16 GetEPDblBuf0Addr(u8 bEpNum)
{
return(_GetEPDblBuf0Addr(bEpNum));
}
/*******************************************************************************
* Function Name : GetEPDblBuf1Addr
* Description : Returns the address of the Buffer 1.
* Input : bEpNum: Endpoint Number.
* Output : None.
* Return : Address of the Buffer 1.
*******************************************************************************/
u16 GetEPDblBuf1Addr(u8 bEpNum)
{
return(_GetEPDblBuf1Addr(bEpNum));
}
/*******************************************************************************
* Function Name : SetEPDblBuffCount
* Description : Set the number of bytes for a double Buffer
* endpoint.
* Input : bEpNum,bDir, wCount
* Output : None.
* Return : None.
*******************************************************************************/
void SetEPDblBuffCount(u8 bEpNum, u8 bDir, u16 wCount)
{
_SetEPDblBuffCount(bEpNum, bDir, wCount);
}
/*******************************************************************************
* Function Name : SetEPDblBuf0Count
* Description : Set the number of bytes in the buffer 0 of a double Buffer
* endpoint.
* Input : bEpNum, bDir, wCount
* Output : None.
* Return : None.
*******************************************************************************/
void SetEPDblBuf0Count(u8 bEpNum, u8 bDir, u16 wCount)
{
_SetEPDblBuf0Count(bEpNum, bDir, wCount);
}
/*******************************************************************************
* Function Name : SetEPDblBuf1Count
* Description : Set the number of bytes in the buffer 0 of a double Buffer
* endpoint.
* Input : bEpNum, bDir, wCount
* Output : None.
* Return : None.
*******************************************************************************/
void SetEPDblBuf1Count(u8 bEpNum, u8 bDir, u16 wCount)
{
_SetEPDblBuf1Count(bEpNum, bDir, wCount);
}
/*******************************************************************************
* Function Name : GetEPDblBuf0Count
* Description : Returns the number of byte received in the buffer 0 of a double
* Buffer endpoint.
* Input : bEpNum: Endpoint Number.
* Output : None.
* Return : Endpoint Buffer 0 count
*******************************************************************************/
u16 GetEPDblBuf0Count(u8 bEpNum)
{
return(_GetEPDblBuf0Count(bEpNum));
}
/*******************************************************************************
* Function Name : GetEPDblBuf1Count
* Description : Returns the number of data received in the buffer 1 of a double
* Buffer endpoint.
* Input : bEpNum: Endpoint Number.
* Output : None.
* Return : Endpoint Buffer 1 count.
*******************************************************************************/
u16 GetEPDblBuf1Count(u8 bEpNum)
{
return(_GetEPDblBuf1Count(bEpNum));
}
/*******************************************************************************
* Function Name : GetEPDblBufDir
* Description : gets direction of the double buffered endpoint
* Input : bEpNum: Endpoint Number.
* Output : None.
* Return : EP_DBUF_OUT, EP_DBUF_IN,
* EP_DBUF_ERR if the endpoint counter not yet programmed.
*******************************************************************************/
EP_DBUF_DIR GetEPDblBufDir(u8 bEpNum)
{
if ((u16)(*_pEPRxCount(bEpNum) & 0xFC00) != 0)
return(EP_DBUF_OUT);
else if (((u16)(*_pEPTxCount(bEpNum)) & 0x03FF) != 0)
return(EP_DBUF_IN);
else
return(EP_DBUF_ERR);
}
/*******************************************************************************
* Function Name : FreeUserBuffer
* Description : free buffer used from the application realizing it to the line
toggles bit SW_BUF in the double buffered endpoint register
* Input : bEpNum, bDir
* Output : None.
* Return : None.
*******************************************************************************/
void FreeUserBuffer(u8 bEpNum, u8 bDir)
{
if (bDir == EP_DBUF_OUT)
{ /* OUT double buffered endpoint */
_ToggleDTOG_TX(bEpNum);
}
else if (bDir == EP_DBUF_IN)
{ /* IN double buffered endpoint */
_ToggleDTOG_RX(bEpNum);
}
}
/*******************************************************************************
* Function Name : ToWord
* Description : merge two byte in a word.
* Input : bh: byte high, bl: bytes low.
* Output : None.
* Return : resulted word.
*******************************************************************************/
u16 ToWord(u8 bh, u8 bl)
{
u16 wRet;
wRet = (u16)bl | ((u16)bh << 8);
return(wRet);
}
/*******************************************************************************
* Function Name : ByteSwap
* Description : Swap two byte in a word.
* Input : wSwW: word to Swap.
* Output : None.
* Return : resulted word.
*******************************************************************************/
u16 ByteSwap(u16 wSwW)
{
u8 bTemp;
u16 wRet;
bTemp = (u8)(wSwW & 0xff);
wRet = (wSwW >> 8) | ((u16)bTemp << 8);
return(wRet);
}
/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/

View File

@ -0,0 +1,150 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 Perry Hung.
* Copyright (c) 2011, 2012 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 libmaple/util.c
* @brief Utility procedures for debugging
*/
#include <libmaple/libmaple.h>
#include <libmaple/usart.h>
#include <libmaple/gpio.h>
#include <libmaple/nvic.h>
/* (Undocumented) hooks used by Wirish to direct our behavior here */
extern __weak void __lm_error(void);
extern __weak usart_dev* __lm_enable_error_usart(void);
/* If you define ERROR_LED_PORT and ERROR_LED_PIN, then a failed
* 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
/* (Called from exc.S with global interrupts disabled.) */
__attribute__((noreturn)) void __error(void) {
if (__lm_error) {
__lm_error();
}
/* Reenable global interrupts */
nvic_globalirq_enable();
throb();
}
/*
* Print an error message on a UART upon a failed assertion (if one is
* available), and punt to __error().
*
* @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) {
if (__lm_enable_error_usart) {
/* Initialize the error USART */
usart_dev *err_usart = __lm_enable_error_usart();
/* Print failed assert message */
usart_putstr(err_usart, "ERROR: FAILED ASSERT(");
usart_putstr(err_usart, exp);
usart_putstr(err_usart, "): ");
usart_putstr(err_usart, file);
usart_putstr(err_usart, ": ");
usart_putudec(err_usart, line);
usart_putc(err_usart, '\n');
usart_putc(err_usart, '\r');
}
/* Shutdown and error fade */
__error();
}
/*
* Provide an __assert_func handler to libc so that calls to assert()
* get redirected to _fail.
*/
void __assert_func(const char* file, int line, const char* method,
const char* expression) {
_fail(file, line, expression);
}
/*
* Provide an abort() implementation that aborts execution and punts
* to __error().
*/
void abort() {
if (__lm_enable_error_usart) {
/* Initialize the error USART */
usart_dev *err_usart = __lm_enable_error_usart();
/* Print abort message. */
usart_putstr(err_usart, "ERROR: PROGRAM ABORTED VIA abort()\r\n");
}
/* Shutdown and error fade */
__error();
}
/* This was public as of v0.0.12, so we've got to keep it public. */
/**
* @brief Fades the error LED on and off
* @sideeffect Sets output push-pull on ERROR_LED_PIN.
*/
__attribute__((noreturn)) void throb(void) {
#ifdef HAVE_ERROR_LED
int32 slope = 1;
uint32 CC = 0x0000;
uint32 TOP_CNT = 0x0200;
uint32 i = 0;
gpio_set_mode(ERROR_LED_PORT, ERROR_LED_PIN, GPIO_MODE_OUTPUT);
/* Error fade. */
while (1) {
if (CC == TOP_CNT) {
slope = -1;
} else if (CC == 0) {
slope = 1;
}
if (i == TOP_CNT) {
CC += slope;
i = 0;
}
if (i < CC) {
gpio_write_bit(ERROR_LED_PORT, ERROR_LED_PIN, 1);
} else {
gpio_write_bit(ERROR_LED_PORT, ERROR_LED_PIN, 0);
}
i++;
}
#else
/* No error LED is defined; do nothing. */
while (1)
;
#endif
}

View File

@ -0,0 +1,6 @@
// API compatibility
#include "variant.h"

View File

@ -0,0 +1,12 @@
#ifndef _VARIANT_ARDUINO_STM32_
#define _VARIANT_ARDUINO_STM32_
// From SAM implementation #define digitalPinToBitMask(P) ( g_APinDescription[P].ulPin )
#warning "TO DO. IMPLEMENT digitalPinToBitMask in variant.h"
// Its likely that this function has no meaning with reference to the STM32 GPIO
// But its required by some libraries.
#define digitalPinToBitMask(P) ( 1 )
#endif /* _VARIANT_ARDUINO_STM32_ */

View File

@ -0,0 +1,223 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 Perry Hung.
* Copyright (c) 2011, 2012 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/boards.cpp
* @brief init() and board routines.
*
* This file is mostly interesting for the init() function, which
* configures Flash, the core clocks, and a variety of other available
* peripherals on the board so the rest of Wirish doesn't have to turn
* things on before using them.
*
* Prior to returning, init() calls boardInit(), which allows boards
* to perform any initialization they need to. This file includes a
* weak no-op definition of boardInit(), so boards that don't need any
* special initialization don't have to define their own.
*
* How init() works is chip-specific. See the boards_setup.cpp files
* under e.g. wirish/stm32f1/, wirish/stmf32f2 for the details, but be
* advised: their contents are unstable, and can/will change without
* notice.
*/
#include <boards.h>
#include <libmaple/libmaple_types.h>
#include <libmaple/flash.h>
#include <libmaple/nvic.h>
#include <libmaple/systick.h>
#include "boards_private.h"
static void setup_flash(void);
static void setup_clocks(void);
static void setup_nvic(void);
static void setup_adcs(void);
static void setup_timers(void);
/*
* Exported functions
*/
void init(void) {
setup_flash();
setup_clocks();
setup_nvic();
systick_init(SYSTICK_RELOAD_VAL);
wirish::priv::board_setup_gpio();
setup_adcs();
setup_timers();
wirish::priv::board_setup_usb();
wirish::priv::series_init();
boardInit();
}
/* Provide a default no-op boardInit(). */
__weak void boardInit(void) {
}
/* You could farm this out to the files in boards/ if e.g. it takes
* too long to test on boards with lots of pins. */
bool boardUsesPin(uint8 pin) {
for (int i = 0; i < BOARD_NR_USED_PINS; i++) {
if (pin == boardUsedPins[i]) {
return true;
}
}
return false;
}
/*
* Auxiliary routines
*/
static void setup_flash(void) {
// Turn on as many Flash "go faster" features as
// possible. flash_enable_features() just ignores any flags it
// can't support.
flash_enable_features(FLASH_PREFETCH | FLASH_ICACHE | FLASH_DCACHE);
// Configure the wait states, assuming we're operating at "close
// enough" to 3.3V.
flash_set_latency(FLASH_SAFE_WAIT_STATES);
}
static void setup_clocks(void) {
// Turn on HSI. We'll switch to and run off of this while we're
// setting up the main PLL.
rcc_turn_on_clk(RCC_CLK_HSI);
// Turn off and reset the clock subsystems we'll be using, as well
// as the clock security subsystem (CSS). Note that resetting CFGR
// to its default value of 0 implies a switch to HSI for SYSCLK.
RCC_BASE->CFGR = 0x00000000;
rcc_disable_css();
rcc_turn_off_clk(RCC_CLK_PLL);
rcc_turn_off_clk(RCC_CLK_HSE);
wirish::priv::board_reset_pll();
// Clear clock readiness interrupt flags and turn off clock
// readiness interrupts.
RCC_BASE->CIR = 0x00000000;
// Enable HSE, and wait until it's ready.
rcc_turn_on_clk(RCC_CLK_HSE);
while (!rcc_is_clk_ready(RCC_CLK_HSE))
;
// Configure AHBx, APBx, etc. prescalers and the main PLL.
wirish::priv::board_setup_clock_prescalers();
rcc_configure_pll(&wirish::priv::w_board_pll_cfg);
// Enable the PLL, and wait until it's ready.
rcc_turn_on_clk(RCC_CLK_PLL);
while(!rcc_is_clk_ready(RCC_CLK_PLL))
;
// Finally, switch to the now-ready PLL as the main clock source.
rcc_switch_sysclk(RCC_CLKSRC_PLL);
}
/*
* These addresses are where usercode starts when a bootloader is
* present. If no bootloader is present, the user NVIC usually starts
* at the Flash base address, 0x08000000.
*/
#if defined(BOOTLOADER_maple)
#define USER_ADDR_ROM 0x08005000
#else
#if defined(BOOTLOADER_robotis)
#define USER_ADDR_ROM 0x08003000
#else
#define USER_ADDR_ROM 0x08000000
#endif
#endif
#define USER_ADDR_RAM 0x20000C00
extern char __text_start__;
static void setup_nvic(void) {
#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);
#elif defined VECT_TAB_ADDR
// A numerically supplied value
nvic_init((uint32)VECT_TAB_ADDR, 0);
#else
// Use the __text_start__ value from the linker script; this
// should be the start of the vector table.
nvic_init((uint32)&__text_start__, 0);
#endif
}
static void adc_default_config(const adc_dev *dev) {
adc_enable_single_swstart(dev);
adc_set_sample_rate(dev, wirish::priv::w_adc_smp);
}
static void setup_adcs(void) {
adc_set_prescaler(wirish::priv::w_adc_pre);
adc_foreach(adc_default_config);
}
static void timer_default_config(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 (uint8 channel = 1; channel <= 4; channel++) {
if (timer_has_cc_channel(dev, 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_generate_update(dev);
timer_resume(dev);
}
static void setup_timers(void) {
timer_foreach(timer_default_config);
}

View File

@ -0,0 +1,92 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2012 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/stm32f1/boards_setup.cpp
* @author Marti Bolivar <mbolivar@leaflabs.com>
* @brief STM32F1 chip setup.
*
* This file controls how init() behaves on the STM32F1. Be very
* careful when changing anything here. Many of these values depend
* upon each other.
*/
#include "boards_private.h"
#include <libmaple/gpio.h>
#include <libmaple/timer.h>
#include <boards.h>
#include <usb_serial.h>
// Allow boards to provide a PLL multiplier. This is useful for
// e.g. STM32F100 value line MCUs, which use slower multipliers.
// (We're leaving the default to RCC_PLLMUL_9 for now, since that
// works for F103 performance line MCUs, which is all that LeafLabs
// currently officially supports).
#ifndef BOARD_RCC_PLLMUL
#define BOARD_RCC_PLLMUL RCC_PLLMUL_9
#endif
namespace wirish {
namespace priv {
static stm32f1_rcc_pll_data pll_data = {BOARD_RCC_PLLMUL};
__weak rcc_pll_cfg w_board_pll_cfg = {RCC_PLLSRC_HSE, &pll_data};
__weak adc_prescaler w_adc_pre = ADC_PRE_PCLK2_DIV_6;
__weak adc_smp_rate w_adc_smp = ADC_SMPR_55_5;
__weak void board_reset_pll(void) {
// TODO
}
__weak void board_setup_clock_prescalers(void) {
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);
}
__weak void board_setup_gpio(void) {
gpio_init_all();
}
__weak void board_setup_usb(void) {
#if BOARD_HAVE_SERIALUSB
#ifdef BOOTLOADER_maple
// SerialUSB.begin();
Serial.begin();// Roger Clark. Changed SerialUSB to Serial for Arduino sketch compatibility
#endif
#endif
}
__weak void series_init(void) {
// Initialize AFIO here, too, so peripheral remaps and external
// interrupts work out of the box.
afio_init();
}
}
}

View File

@ -0,0 +1,57 @@
/******************************************************************************
* 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.
*****************************************************************************/
/*
* This file is a modified version of a file obtained from
* CodeSourcery Inc. (now part of Mentor Graphics Corp.), in which the
* following text appeared:
*
* 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,=__msp_init
mov sp,r1
ldr r1,=start_c
bx r1
.pool
.cantunwind
.fnend

View File

@ -0,0 +1,95 @@
/******************************************************************************
* 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.
*****************************************************************************/
/*
* This file is a modified version of a file obtained from
* CodeSourcery Inc. (now part of Mentor Graphics Corp.), in which the
* following text appeared:
*
* 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 <stddef.h>
extern void __libc_init_array(void);
extern int main(int, char**, char**);
extern void exit(int) __attribute__((noreturn, weak));
/* The linker must ensure that these are at least 4-byte aligned. */
extern char __data_start__, __data_end__;
extern char __bss_start__, __bss_end__;
struct rom_img_cfg {
int *img_start;
};
extern char _lm_rom_img_cfgp;
void __attribute__((noreturn)) start_c(void) {
struct rom_img_cfg *img_cfg = (struct rom_img_cfg*)&_lm_rom_img_cfgp;
int *src = img_cfg->img_start;
int *dst = (int*)&__data_start__;
int exit_code;
/* Initialize .data, if necessary. */
if (src != dst) {
int *end = (int*)&__data_end__;
while (dst < end) {
*dst++ = *src++;
}
}
/* Zero .bss. */
dst = (int*)&__bss_start__;
while (dst < (int*)&__bss_end__) {
*dst++ = 0;
}
/* Run initializers. */
__libc_init_array();
/* Jump to main. */
exit_code = main(0, 0, 0);
if (exit) {
exit(exit_code);
}
/* If exit is NULL, make sure we don't return. */
for (;;)
continue;
}

View File

@ -0,0 +1,176 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 Perry Hung.
* Copyright (c) 2011, 2012 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/syscalls.c
* @brief newlib stubs
*
* Low level system routines used by newlib for basic I/O and memory
* allocation. You can override most of these.
*/
#include <libmaple/libmaple.h>
#include <sys/stat.h>
#include <errno.h>
#include <stddef.h>
/* If CONFIG_HEAP_START (or CONFIG_HEAP_END) isn't defined, then
* assume _lm_heap_start (resp. _lm_heap_end) is appropriately set by
* the linker */
#ifndef CONFIG_HEAP_START
extern char _lm_heap_start;
#define CONFIG_HEAP_START ((void *)&_lm_heap_start)
#endif
#ifndef CONFIG_HEAP_END
extern char _lm_heap_end;
#define CONFIG_HEAP_END ((void *)&_lm_heap_end)
#endif
/*
* _sbrk -- Increment the program break.
*
* Get incr bytes more RAM (for use by the heap). malloc() and
* friends call this function behind the scenes.
*/
void *_sbrk(int incr) {
static void * pbreak = NULL; /* current program break */
void * ret;
if (pbreak == NULL) {
pbreak = CONFIG_HEAP_START;
}
if ((CONFIG_HEAP_END - pbreak < incr) ||
(pbreak - CONFIG_HEAP_START < -incr)) {
errno = ENOMEM;
return (void *)-1;
}
ret = pbreak;
pbreak += incr;
return ret;
}
__weak int _open(const char *path, int flags, ...) {
return 1;
}
__weak int _close(int fd) {
return 0;
}
__weak int _fstat(int fd, struct stat *st) {
st->st_mode = S_IFCHR;
return 0;
}
__weak int _isatty(int fd) {
return 1;
}
__weak int isatty(int fd) {
return 1;
}
__weak int _lseek(int fd, off_t pos, int whence) {
return -1;
}
__weak unsigned char getch(void) {
return 0;
}
__weak int _read(int fd, char *buf, size_t cnt) {
*buf = getch();
return 1;
}
__weak void putch(unsigned char c) {
}
__weak void cgets(char *s, int bufsize) {
char *p;
int c;
int i;
for (i = 0; i < bufsize; i++) {
*(s+i) = 0;
}
// memset(s, 0, bufsize);
p = s;
for (p = s; p < s + bufsize-1;) {
c = getch();
switch (c) {
case '\r' :
case '\n' :
putch('\r');
putch('\n');
*p = '\n';
return;
case '\b' :
if (p > s) {
*p-- = 0;
putch('\b');
putch(' ');
putch('\b');
}
break;
default :
putch(c);
*p++ = c;
break;
}
}
return;
}
__weak int _write(int fd, const char *buf, size_t cnt) {
int i;
for (i = 0; i < cnt; i++)
putch(buf[i]);
return cnt;
}
/* Override fgets() in newlib with a version that does line editing */
__weak char *fgets(char *s, int bufsize, void *f) {
cgets(s, bufsize);
return s;
}
__weak void _exit(int exitcode) {
while (1)
;
}