Merge branch 'master' of https://github.com/IanHarvey/Arduino_STM32
This commit is contained in:
commit
f70c503d2f
|
@ -313,3 +313,32 @@ maple_STM32.build.error_led_pin=1
|
||||||
maple_STM32.build.gcc_ver=gcc-arm-none-eabi-4.8.3-2014q1
|
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=1
|
||||||
|
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
|
||||||
|
|
||||||
|
|
|
@ -97,10 +97,12 @@ recipe.size.regex.data=^(?:\.data|\.bss|\.noinit)\s+([0-9]+).*
|
||||||
# Uploader tools
|
# Uploader tools
|
||||||
# -------------------
|
# -------------------
|
||||||
|
|
||||||
|
# Upload using Maple bootloader over DFU
|
||||||
tools.maple_upload.cmd=maple_upload
|
tools.maple_upload.cmd=maple_upload
|
||||||
tools.maple_upload.cmd.windows=maple_upload.bat
|
tools.maple_upload.cmd.windows=maple_upload.bat
|
||||||
#tools.maple_upload.cmd.linux=
|
#tools.maple_upload.cmd.linux=
|
||||||
tools.maple_upload.path={runtime.hardware.path}/tools/win
|
tools.maple_upload.path={runtime.hardware.path}/tools/win
|
||||||
|
tools.maple_upload.path.macosx={runtime.hardware.path}/tools/macosx
|
||||||
|
|
||||||
tools.maple_upload.upload.params.verbose=-d
|
tools.maple_upload.upload.params.verbose=-d
|
||||||
tools.maple_upload.upload.params.quiet=
|
tools.maple_upload.upload.params.quiet=
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* The MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011 LeafLabs, LLC.
|
||||||
|
* Modifications Copyright (c) 2014 Ian Harvey
|
||||||
|
*
|
||||||
|
* 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 variants/microduino/board.cpp
|
||||||
|
* @author Ian Harvey
|
||||||
|
* @brief Board pin definitions for Microduino STM32
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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] = {
|
||||||
|
|
||||||
|
|
||||||
|
{GPIOA, TIMER1, NULL, 10, 3, ADCx}, /* D0(RxD0)/PA10 */
|
||||||
|
{GPIOA, TIMER1, NULL, 9, 2, ADCx}, /* D1(TxD1)/PA9 */
|
||||||
|
{GPIOB, NULL, NULL, 11, 0, ADCx}, /* D2/PB11 */
|
||||||
|
{GPIOB, NULL, NULL, 10, 0, ADCx}, /* D3/PB10 */
|
||||||
|
{GPIOA, TIMER1, NULL, 8, 1, ADCx}, /* D4/PA8 */
|
||||||
|
{GPIOA, NULL, NULL, 13, 0, ADCx}, /* D5/PA13 */
|
||||||
|
{GPIOA, NULL, NULL, 14, 0, ADCx}, /* D6/PA14 */
|
||||||
|
{GPIOA, NULL, NULL, 15, 0, ADCx}, /* D7/PA15 */
|
||||||
|
{GPIOB, NULL, NULL, 3, 0, ADCx}, /* D8/PB3 */
|
||||||
|
{GPIOB, NULL, NULL, 4, 0, ADCx}, /* D9/PB4 */
|
||||||
|
{GPIOA, NULL, ADC1, 4, 0, 4}, /* D10/PA4 */
|
||||||
|
{GPIOA, TIMER3, ADC1, 7, 2, 7}, /* D11/PA7 */
|
||||||
|
{GPIOA, TIMER3, ADC1, 6, 1, 6}, /* D12/PA6 */
|
||||||
|
{GPIOA, NULL, ADC1, 5, 0, 5}, /* D13/PA5 */
|
||||||
|
|
||||||
|
{GPIOA, TIMER2, ADC1, 0, 1, 0}, /* D14(A0)/PA0 */
|
||||||
|
{GPIOA, TIMER2, ADC1, 1, 2, 1}, /* D15(A1)/PA1 */
|
||||||
|
{GPIOA, TIMER2, ADC1, 2, 3, 2}, /* D16(A2)/PA2 */
|
||||||
|
{GPIOA, TIMER2, ADC1, 3, 4, 3}, /* D17(A3)/PA3 */
|
||||||
|
{GPIOB, TIMER4, NULL, 7, 2, ADCx}, /* D18(A4)/PB7 */
|
||||||
|
{GPIOB, TIMER4, NULL, 6, 1, ADCx}, /* D19(A5)/PB6 */
|
||||||
|
{GPIOB, TIMER3, ADC1, 0, 3, 8}, /* D20(A6)/PB0 */
|
||||||
|
{GPIOB, TIMER3, ADC1, 1, 4, 9}, /* D21(A7)/PB1 */
|
||||||
|
|
||||||
|
{GPIOA, NULL, NULL, 12, 0, ADCx}, /* D22/PA12/USB D+ */
|
||||||
|
{GPIOA, TIMER1, NULL, 11, 4, ADCx}, /* D23/PA11/USB D- */
|
||||||
|
|
||||||
|
// FIXME: find out which pin is the button, if any
|
||||||
|
{GPIOB, NULL, NULL, 8, 0, ADCx}, /* D24/PB8??/Button */
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = {
|
||||||
|
0, 1, 4, 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 23
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const uint8 boardADCPins[BOARD_NR_ADC_PINS] __FLASH__ = {
|
||||||
|
14, 15, 16, 17, 18, 19, 20, 21, 10, 11, 12, 13
|
||||||
|
};
|
||||||
|
|
||||||
|
#define USB_DP 22
|
||||||
|
#define USB_DM 23
|
||||||
|
|
||||||
|
extern const uint8 boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = {
|
||||||
|
BOARD_LED_PIN, BOARD_BUTTON_PIN, USB_DP, USB_DM
|
||||||
|
};
|
|
@ -0,0 +1,82 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* The MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011 LeafLabs, LLC.
|
||||||
|
* Modifications Copyright (c) 2014 Ian Harvey
|
||||||
|
*
|
||||||
|
* 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 variants/microduino/board/board.h
|
||||||
|
* @author Ian Harvey
|
||||||
|
* @brief Private include file for Microduino STM32
|
||||||
|
*
|
||||||
|
* See wirish/boards/maple/include/board/board.h for more information
|
||||||
|
* on these definitions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _BOARD_MICRODUINO_STM32_H_
|
||||||
|
#define _BOARD_MICRODUINO_STM32_H_
|
||||||
|
|
||||||
|
#define CYCLES_PER_MICROSECOND 72
|
||||||
|
#define SYSTICK_RELOAD_VAL 71999 /* takes a cycle to reload */
|
||||||
|
|
||||||
|
#define BOARD_BUTTON_PIN 24
|
||||||
|
#define BOARD_LED_PIN 4
|
||||||
|
|
||||||
|
#define BOARD_NR_USARTS 3
|
||||||
|
#define BOARD_USART1_TX_PIN 1
|
||||||
|
#define BOARD_USART1_RX_PIN 0
|
||||||
|
#define BOARD_USART2_TX_PIN 16
|
||||||
|
#define BOARD_USART2_RX_PIN 17
|
||||||
|
#define BOARD_USART3_TX_PIN 3
|
||||||
|
#define BOARD_USART3_RX_PIN 2
|
||||||
|
|
||||||
|
#define BOARD_NR_SPI 1
|
||||||
|
#define BOARD_SPI1_NSS_PIN 10
|
||||||
|
#define BOARD_SPI1_MOSI_PIN 11
|
||||||
|
#define BOARD_SPI1_MISO_PIN 12
|
||||||
|
#define BOARD_SPI1_SCK_PIN 13
|
||||||
|
|
||||||
|
#define BOARD_NR_GPIO_PINS 25
|
||||||
|
#define BOARD_NR_PWM_PINS 14
|
||||||
|
#define BOARD_NR_ADC_PINS 12
|
||||||
|
#define BOARD_NR_USED_PINS 4
|
||||||
|
|
||||||
|
#define BOARD_JTMS_SWDIO_PIN 5
|
||||||
|
#define BOARD_JTCK_SWCLK_PIN 6
|
||||||
|
#define BOARD_JTDI_PIN 7
|
||||||
|
#define BOARD_JTDO_PIN 8
|
||||||
|
#define BOARD_NJTRST_PIN 9
|
||||||
|
|
||||||
|
#define BOARD_USB_DISC_DEV GPIOB // FIXME
|
||||||
|
#define BOARD_USB_DISC_BIT 9 // FIXME
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PA10, PA9, PB11, PB10, PA8, PA13, PA14, PA15,
|
||||||
|
PB3, PB4, PA4, PA7, PA6, PA5,
|
||||||
|
|
||||||
|
PA0, PA1, PA2, PA3, PB7, PB6, PB0,
|
||||||
|
PA12, PA11 //FIXME - button pin
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -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) }
|
||||||
|
}
|
|
@ -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)
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,5 @@
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K
|
||||||
|
rom (rx) : ORIGIN = 0x08005000, LENGTH = 108K
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
|
||||||
|
rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K
|
||||||
|
rom (rx) : ORIGIN = 0x08005000, LENGTH = 0K
|
||||||
|
}
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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 */
|
|
@ -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);
|
||||||
|
}
|
|
@ -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 = ®s->CRL + (pin >> 3);
|
||||||
|
uint32 shift = (pin & 0x7) * 4;
|
||||||
|
uint32 tmp = *cr;
|
||||||
|
|
||||||
|
tmp &= ~(0xF << shift);
|
||||||
|
tmp |= (mode == GPIO_INPUT_PU ? GPIO_INPUT_PD : mode) << shift;
|
||||||
|
*cr = tmp;
|
||||||
|
|
||||||
|
if (mode == GPIO_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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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)
|
||||||
|
;
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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));
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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 */
|
|
@ -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
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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) */
|
|
@ -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]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -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));
|
||||||
|
}
|
|
@ -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.
|
|
@ -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))
|
|
@ -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();
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
@ -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****/
|
|
@ -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****/
|
|
@ -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****/
|
|
@ -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
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// API compatibility
|
||||||
|
#include "variant.h"
|
|
@ -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_ */
|
|
@ -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);
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
|
@ -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)
|
||||||
|
;
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ $# -lt 4 ]; then
|
||||||
|
echo "Usage: $0 $# <dummy_port> <altID> <usbID> <binfile>" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
dummy_port=$1; altID=$2; usbID=$3; binfile=$4
|
||||||
|
|
||||||
|
DFU_UTIL=/opt/local/bin/dfu-util
|
||||||
|
if [ ! -x ${DFU_UTIL} ]; then
|
||||||
|
echo "$0: error: cannot find ${DFU_UTIL}" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
${DFU_UTIL} -d ${usbID} -a ${altID} -D ${binfile}
|
Loading…
Reference in New Issue