Merge branch 'master' of git://github.com/libopencm3/libopencm3 into upstream-merge

This commit is contained in:
Jeff Ciesielski
2012-11-13 11:06:21 -08:00
188 changed files with 9883 additions and 6293 deletions

View File

@@ -23,6 +23,9 @@ ifneq ($(V),1)
Q := @
endif
# common objects
OBJS += vector.o systick.o scb.o nvic.o assert.o
all: $(SRCLIBDIR)/$(LIBNAME).a
$(SRCLIBDIR)/$(LIBNAME).a: $(SRCLIBDIR)/$(LIBNAME).ld $(OBJS)

View File

@@ -1,31 +1,9 @@
/** @defgroup STM32F_nvic_file NVIC
@ingroup STM32F_files
@brief <b>libopencm3 STM32F Nested Vectored Interrupt Controller</b>
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2010 Thomas Otto <tommi@viadmin.org>
@author @htmlonly &copy; @endhtmlonly 2012 Fergus Noble <fergusnoble@gmail.com>
@date 18 August 2012
The STM32F series provides up to 68 maskable user interrupts for the STM32F10x
series, and 87 for the STM32F2xx and STM32F4xx series.
The NVIC registers are defined by the ARM standards but the STM32F series have some
additional limitations
@see Cortex-M3 Devices Generic User Guide
@see STM32F10xxx Cortex-M3 programming manual
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
* Copyright (C) 2012 Fergus Noble <fergusnoble@gmail.com>
* Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -40,10 +18,32 @@ LGPL License Terms @ref lgpl_license
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/** @defgroup CM3_nvic_file NVIC
@ingroup CM3_files
@brief <b>libopencm3 Cortex Nested Vectored Interrupt Controller</b>
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2010 Thomas Otto <tommi@viadmin.org>
@author @htmlonly &copy; @endhtmlonly 2012 Fergus Noble <fergusnoble@gmail.com>
@date 18 August 2012
Cortex processors provide 14 cortex-defined interrupts (NMI, usage faults,
systicks etc.) and varying numbers of implementation defined interrupts
(typically peripherial interrupts and DMA).
@see Cortex-M3 Devices Generic User Guide
@see STM32F10xxx Cortex-M3 programming manual
LGPL License Terms @ref lgpl_license
*/
/**@{*/
#include <libopencm3/stm32/nvic.h>
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/cm3/scs.h>
/*-----------------------------------------------------------------------------*/
/** @brief NVIC Enable Interrupt
@@ -153,7 +153,18 @@ Control Register (SCB_AIRCR), as done in @ref scb_set_priority_grouping.
void nvic_set_priority(u8 irqn, u8 priority)
{
NVIC_IPR(irqn) = priority;
/* code from lpc43xx/nvic.c -- this is quite a hack and alludes to the
* negative interrupt numbers assigned to the system interrupts. better
* handling would mean signed integers. */
if(irqn>=NVIC_IRQ_COUNT)
{
/* Cortex-M system interrupts */
SCS_SHPR( (irqn&0xF)-4 ) = priority;
}else
{
/* Device specific interrupts */
NVIC_IPR(irqn) = priority;
}
}
/*-----------------------------------------------------------------------------*/
@@ -171,4 +182,3 @@ void nvic_generate_software_interrupt(u16 irqn)
NVIC_STIR |= irqn;
}
/**@}*/

View File

@@ -17,7 +17,7 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/stm32/f1/scb.h>
#include <libopencm3/cm3/scb.h>
void scb_reset_core(void)
{

View File

@@ -1,27 +1,8 @@
/** @defgroup STM32F_systick_file SysTick
@ingroup STM32F_files
@brief <b>libopencm3 STM32Fxx System Tick Timer</b>
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2010 Thomas Otto <tommi@viadmin.org>
@date 19 August 2012
This library supports the System Tick timer in the
STM32F series of ARM Cortex Microcontrollers by ST Microelectronics.
The System Tick timer is part of the ARM Cortex core. It is a 24 bit
down counter that can be configured with an automatical reload value.
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
* Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -36,9 +17,28 @@ LGPL License Terms @ref lgpl_license
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/** @defgroup CM3_systick_file SysTick
@ingroup CM3_files
@brief <b>libopencm3 Cortex System Tick Timer</b>
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2010 Thomas Otto <tommi@viadmin.org>
@date 19 August 2012
This library supports the System Tick timer in ARM Cortex Microcontrollers.
The System Tick timer is part of the ARM Cortex core. It is a 24 bit
down counter that can be configured with an automatical reload value.
LGPL License Terms @ref lgpl_license
*/
/**@{*/
#include <libopencm3/stm32/systick.h>
#include <libopencm3/cm3/systick.h>
/*-----------------------------------------------------------------------------*/
/** @brief SysTick Set the Automatic Reload Value.
@@ -135,5 +135,15 @@ u8 systick_get_countflag(void)
else
return 0;
}
/*-----------------------------------------------------------------------------*/
/** @brief SysTick Get Calibration Value
@returns Current calibration value
*/
u32 systick_get_calib(void)
{
return (STK_CALIB&0x00FFFFFF);
}
/**@}*/

View File

@@ -1,7 +1,8 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Piotr Esden-Tempski <piotr@esden.net>
* Copyright (C) 2010 Piotr Esden-Tempski <piotr@esden.net>,
* Copyright (C) 2012 chrysn <chrysn@fsfe.org>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -14,19 +15,26 @@
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/cm3/vector.h>
/* load optional platform dependent initialization routines */
#include "../dispatch/vector_chipset.c"
/* load the weak symbols for IRQ_HANDLERS */
#include "../dispatch/vector_nvic.c"
#define WEAK __attribute__ ((weak))
/* Symbols exported by the linker script(s): */
extern unsigned _data_loadaddr, _data, _edata, _ebss, _stack;
void main(void);
void reset_handler(void);
void blocking_handler(void);
void null_handler(void);
void WEAK reset_handler(void);
void WEAK nmi_handler(void);
void WEAK hard_fault_handler(void);
void WEAK mem_manage_handler(void);
@@ -37,27 +45,25 @@ void WEAK debug_monitor_handler(void);
void WEAK pend_sv_handler(void);
void WEAK sys_tick_handler(void);
/* TODO: Interrupt handler prototypes */
__attribute__ ((section(".vectors")))
void (*const vector_table[]) (void) = {
(void*)&_stack, /* Addr: 0x0000_0000 */
reset_handler, /* Addr: 0x0000_0004 */
nmi_handler, /* Addr: 0x0000_0008 */
hard_fault_handler, /* Addr: 0x0000_000C */
mem_manage_handler, /* Addr: 0x0000_0010 */
bus_fault_handler, /* Addr: 0x0000_0014 */
usage_fault_handler, /* Addr: 0x0000_0018 */
0, 0, 0, 0, /* Reserved Addr: 0x0000_001C - 0x0000_002B */
sv_call_handler, /* Addr: 0x0000_002C */
debug_monitor_handler, /* Addr: 0x0000_0030 */
0, /* Reserved Addr: 0x0000_00034 */
pend_sv_handler, /* Addr: 0x0000_0038 */
sys_tick_handler, /* Addr: 0x0000_003C */
vector_table_t vector_table = {
.initial_sp_value = &_stack,
.reset = reset_handler,
.nmi = nmi_handler,
.hard_fault = hard_fault_handler,
.memory_manage_fault = mem_manage_handler,
.bus_fault = bus_fault_handler,
.usage_fault = usage_fault_handler,
.debug_monitor = debug_monitor_handler,
.sv_call = sv_call_handler,
.pend_sv = pend_sv_handler,
.systick = sys_tick_handler,
.irq = {
IRQ_HANDLERS
}
};
void reset_handler(void)
void WEAK reset_handler(void)
{
volatile unsigned *src, *dest;
@@ -69,6 +75,9 @@ void reset_handler(void)
while (dest < &_ebss)
*dest++ = 0;
/* might be provided by platform specific vector.c */
pre_main();
/* Call the application's entry point. */
main();
}
@@ -92,4 +101,3 @@ void null_handler(void)
#pragma weak debug_monitor_handler = null_handler
#pragma weak pend_sv_handler = null_handler
#pragma weak sys_tick_handler = null_handler
/* TODO: Interrupt handler weak aliases */

View File

@@ -0,0 +1,11 @@
#if defined(STM32F4)
# include "../stm32/f4/vector_chipset.c"
#elif defined(LPC43XX)
# include "../lpc43xx/vector_chipset.c"
#else
static void pre_main(void) {}
#endif

View File

@@ -0,0 +1,34 @@
#if defined(STM32F1)
# include "../stm32/f1/vector_nvic.c"
#elif defined(STM32F2)
# include "../stm32/f2/vector_nvic.c"
#elif defined(STM32F4)
# include "../stm32/f4/vector_nvic.c"
#elif defined(STM32L1)
# include "../stm32/l1/vector_nvic.c"
#elif defined(EFM32TG)
# include "../efm32/efm32tg/vector_nvic.c"
#elif defined(EFM32G)
# include "../efm32/efm32g/vector_nvic.c"
#elif defined(EFM32LG)
# include "../efm32/efm32lg/vector_nvic.c"
#elif defined(EFM32GG)
# include "../efm32/efm32gg/vector_nvic.c"
#elif defined(LPC13XX)
# include "../lpc13xx/vector_nvic.c"
#elif defined(LPC17XX)
# include "../lpc17xx/vector_nvic.c"
#elif defined(LPC43XX)
# include "../lpc43xx/vector_nvic.c"
#elif defined(LM3S)
# include "../lm3s/vector_nvic.c"
#else
# warning"no interrupts defined for chipset; not allocating space in the vector table"
#define IRQ_HANDLERS
#endif

38
lib/efm32/efm32g/Makefile Normal file
View File

@@ -0,0 +1,38 @@
##
## This file is part of the libopencm3 project.
##
## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
## Copyright (C) 2012 chrysn <chrysn@fsfe.org>
##
## This library is free software: you can redistribute it and/or modify
## it under the terms of the GNU Lesser General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This library is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public License
## along with this library. If not, see <http://www.gnu.org/licenses/>.
##
LIBNAME = libopencm3_efm32g
FAMILY = EFM32G
PREFIX ?= arm-none-eabi
#PREFIX ?= arm-elf
CC = $(PREFIX)-gcc
AR = $(PREFIX)-ar
CFLAGS = -Os -g -Wall -Wextra -I../../../include -fno-common \
-mcpu=cortex-m3 -mthumb -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD -D$(FAMILY)
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS =
VPATH += ../:../../cm3
include ../../Makefile.include

View File

@@ -0,0 +1,79 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>,
* Copyright (C) 2012 chrysn <chrysn@fsfe.org>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/* Generic linker script for EFM32 targets using libopencm3. */
/* Memory regions must be defined in the ld script which includes this one. */
/* Enforce emmition of the vector table. */
EXTERN (vector_table)
/* Define the entry point of the output file. */
ENTRY(reset_handler)
/* Define sections. */
SECTIONS
{
. = ORIGIN(rom);
.text : {
*(.vectors) /* Vector table */
*(.text*) /* Program code */
. = ALIGN(4);
*(.rodata*) /* Read-only data */
. = ALIGN(4);
_etext = .;
} >rom
. = ORIGIN(ram);
.data : AT(_etext) {
_data = .;
*(.data*) /* Read-write initialized data */
. = ALIGN(4);
_edata = .;
} >ram
.bss : {
*(.bss*) /* Read-write zero initialized data */
*(COMMON)
. = ALIGN(4);
_ebss = .;
} >ram AT >rom
_data_loadaddr = LOADADDR(.data);
/*
* The .eh_frame section appears to be used for C++ exception handling.
* You may need to fix this if you're using C++.
*/
/DISCARD/ : { *(.eh_frame) }
/*
* Another section used by C++ stuff, appears when using newlib with
* 64bit (long long) printf support - discard it for now.
*/
/DISCARD/ : { *(.ARM.exidx) }
. = ALIGN(4);
end = .;
}
PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));

View File

@@ -0,0 +1,15 @@
/* lengths from d011_efm32tg840_datasheet.pdf table 1.1, offset from
* d0034_efm32tg_reference_manual.pdf figure 5.2.
*
* the origins and memory structure are constant over all tinygeckos, but the
* MEMORY section requires the use of constants, and has thus to be duplicated
* over the chip variants.
* */
MEMORY
{
rom (rx) : ORIGIN = 0, LENGTH = 128k
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 16k
}
INCLUDE libopencm3_efm32g.ld;

View File

@@ -0,0 +1,38 @@
##
## This file is part of the libopencm3 project.
##
## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
## Copyright (C) 2012 chrysn <chrysn@fsfe.org>
##
## This library is free software: you can redistribute it and/or modify
## it under the terms of the GNU Lesser General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This library is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public License
## along with this library. If not, see <http://www.gnu.org/licenses/>.
##
LIBNAME = libopencm3_efm32gg
FAMILY = EFM32GG
PREFIX ?= arm-none-eabi
#PREFIX ?= arm-elf
CC = $(PREFIX)-gcc
AR = $(PREFIX)-ar
CFLAGS = -Os -g -Wall -Wextra -I../../../include -fno-common \
-mcpu=cortex-m3 -mthumb -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD -D$(FAMILY)
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS =
VPATH += ../:../../cm3
include ../../Makefile.include

View File

@@ -0,0 +1,79 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>,
* Copyright (C) 2012 chrysn <chrysn@fsfe.org>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/* Generic linker script for EFM32 targets using libopencm3. */
/* Memory regions must be defined in the ld script which includes this one. */
/* Enforce emmition of the vector table. */
EXTERN (vector_table)
/* Define the entry point of the output file. */
ENTRY(reset_handler)
/* Define sections. */
SECTIONS
{
. = ORIGIN(rom);
.text : {
*(.vectors) /* Vector table */
*(.text*) /* Program code */
. = ALIGN(4);
*(.rodata*) /* Read-only data */
. = ALIGN(4);
_etext = .;
} >rom
. = ORIGIN(ram);
.data : AT(_etext) {
_data = .;
*(.data*) /* Read-write initialized data */
. = ALIGN(4);
_edata = .;
} >ram
.bss : {
*(.bss*) /* Read-write zero initialized data */
*(COMMON)
. = ALIGN(4);
_ebss = .;
} >ram AT >rom
_data_loadaddr = LOADADDR(.data);
/*
* The .eh_frame section appears to be used for C++ exception handling.
* You may need to fix this if you're using C++.
*/
/DISCARD/ : { *(.eh_frame) }
/*
* Another section used by C++ stuff, appears when using newlib with
* 64bit (long long) printf support - discard it for now.
*/
/DISCARD/ : { *(.ARM.exidx) }
. = ALIGN(4);
end = .;
}
PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));

View File

@@ -0,0 +1,38 @@
##
## This file is part of the libopencm3 project.
##
## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
## Copyright (C) 2012 chrysn <chrysn@fsfe.org>
##
## This library is free software: you can redistribute it and/or modify
## it under the terms of the GNU Lesser General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This library is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public License
## along with this library. If not, see <http://www.gnu.org/licenses/>.
##
LIBNAME = libopencm3_efm32lg
FAMILY = EFM32LG
PREFIX ?= arm-none-eabi
#PREFIX ?= arm-elf
CC = $(PREFIX)-gcc
AR = $(PREFIX)-ar
CFLAGS = -Os -g -Wall -Wextra -I../../../include -fno-common \
-mcpu=cortex-m3 -mthumb -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD -D$(FAMILY)
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS =
VPATH += ../:../../cm3
include ../../Makefile.include

View File

@@ -0,0 +1,79 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>,
* Copyright (C) 2012 chrysn <chrysn@fsfe.org>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/* Generic linker script for EFM32 targets using libopencm3. */
/* Memory regions must be defined in the ld script which includes this one. */
/* Enforce emmition of the vector table. */
EXTERN (vector_table)
/* Define the entry point of the output file. */
ENTRY(reset_handler)
/* Define sections. */
SECTIONS
{
. = ORIGIN(rom);
.text : {
*(.vectors) /* Vector table */
*(.text*) /* Program code */
. = ALIGN(4);
*(.rodata*) /* Read-only data */
. = ALIGN(4);
_etext = .;
} >rom
. = ORIGIN(ram);
.data : AT(_etext) {
_data = .;
*(.data*) /* Read-write initialized data */
. = ALIGN(4);
_edata = .;
} >ram
.bss : {
*(.bss*) /* Read-write zero initialized data */
*(COMMON)
. = ALIGN(4);
_ebss = .;
} >ram AT >rom
_data_loadaddr = LOADADDR(.data);
/*
* The .eh_frame section appears to be used for C++ exception handling.
* You may need to fix this if you're using C++.
*/
/DISCARD/ : { *(.eh_frame) }
/*
* Another section used by C++ stuff, appears when using newlib with
* 64bit (long long) printf support - discard it for now.
*/
/DISCARD/ : { *(.ARM.exidx) }
. = ALIGN(4);
end = .;
}
PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));

View File

@@ -0,0 +1,38 @@
##
## This file is part of the libopencm3 project.
##
## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
## Copyright (C) 2012 chrysn <chrysn@fsfe.org>
##
## This library is free software: you can redistribute it and/or modify
## it under the terms of the GNU Lesser General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This library is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public License
## along with this library. If not, see <http://www.gnu.org/licenses/>.
##
LIBNAME = libopencm3_efm32tg
FAMILY = EFM32TG
PREFIX ?= arm-none-eabi
#PREFIX ?= arm-elf
CC = $(PREFIX)-gcc
AR = $(PREFIX)-ar
CFLAGS = -Os -g -Wall -Wextra -I../../../include -fno-common \
-mcpu=cortex-m3 -mthumb -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD -D$(FAMILY)
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS =
VPATH += ../:../../cm3
include ../../Makefile.include

View File

@@ -0,0 +1,79 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>,
* Copyright (C) 2012 chrysn <chrysn@fsfe.org>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/* Generic linker script for EFM32 targets using libopencm3. */
/* Memory regions must be defined in the ld script which includes this one. */
/* Enforce emmition of the vector table. */
EXTERN (vector_table)
/* Define the entry point of the output file. */
ENTRY(reset_handler)
/* Define sections. */
SECTIONS
{
. = ORIGIN(rom);
.text : {
*(.vectors) /* Vector table */
*(.text*) /* Program code */
. = ALIGN(4);
*(.rodata*) /* Read-only data */
. = ALIGN(4);
_etext = .;
} >rom
. = ORIGIN(ram);
.data : AT(_etext) {
_data = .;
*(.data*) /* Read-write initialized data */
. = ALIGN(4);
_edata = .;
} >ram
.bss : {
*(.bss*) /* Read-write zero initialized data */
*(COMMON)
. = ALIGN(4);
_ebss = .;
} >ram AT >rom
_data_loadaddr = LOADADDR(.data);
/*
* The .eh_frame section appears to be used for C++ exception handling.
* You may need to fix this if you're using C++.
*/
/DISCARD/ : { *(.eh_frame) }
/*
* Another section used by C++ stuff, appears when using newlib with
* 64bit (long long) printf support - discard it for now.
*/
/DISCARD/ : { *(.ARM.exidx) }
. = ALIGN(4);
end = .;
}
PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));

View File

@@ -0,0 +1,15 @@
/* lengths from d011_efm32tg840_datasheet.pdf table 1.1, offset from
* d0034_efm32tg_reference_manual.pdf figure 5.2.
*
* the origins and memory structure are constant over all tinygeckos, but the
* MEMORY section requires the use of constants, and has thus to be duplicated
* over the chip variants.
* */
MEMORY
{
rom (rx) : ORIGIN = 0, LENGTH = 32k
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 4k
}
INCLUDE libopencm3_efm32tg.ld;

View File

@@ -25,7 +25,7 @@ CC = $(PREFIX)-gcc
AR = $(PREFIX)-ar
CFLAGS = -Os -g -Wall -Wextra -I../../include -fno-common \
-mcpu=cortex-m3 -mthumb -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD
-ffunction-sections -fdata-sections -MD -DLM3S
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS = gpio.o vector.o assert.o

View File

@@ -1,454 +0,0 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#define WEAK __attribute__ ((weak))
/* Symbols exported by the linker script(s): */
extern unsigned _data_loadaddr, _data, _edata, _ebss, _stack;
void main(void);
void reset_handler(void);
void blocking_handler(void);
void null_handler(void);
void WEAK nmi_handler(void);
void WEAK hard_fault_handler(void);
void WEAK mem_manage_handler(void);
void WEAK bus_fault_handler(void);
void WEAK usage_fault_handler(void);
void WEAK sv_call_handler(void);
void WEAK debug_monitor_handler(void);
void WEAK pend_sv_handler(void);
void WEAK sys_tick_handler(void);
void WEAK gpioa_handler(void);
void WEAK gpiob_handler(void);
void WEAK gpioc_handler(void);
void WEAK gpiod_handler(void);
void WEAK gpioe_handler(void);
void WEAK uart0_handler(void);
void WEAK uart1_handler(void);
void WEAK ssi0_handler(void);
void WEAK i2c0_handler(void);
void WEAK pwm0_fault_handler(void);
void WEAK pwm0_0_handler(void);
void WEAK pwm0_1_handler(void);
void WEAK pwm0_2_handler(void);
void WEAK qei0_handler(void);
void WEAK adc0ss0_handler(void);
void WEAK adc0ss1_handler(void);
void WEAK adc0ss2_handler(void);
void WEAK adc0ss3_handler(void);
void WEAK watchdog_handler(void);
void WEAK timer0a_handler(void);
void WEAK timer0b_handler(void);
void WEAK timer1a_handler(void);
void WEAK timer1b_handler(void);
void WEAK timer2a_handler(void);
void WEAK timer2b_handler(void);
void WEAK comp0_handler(void);
void WEAK comp1_handler(void);
void WEAK comp2_handler(void);
void WEAK sysctl_handler(void);
void WEAK flash_handler(void);
void WEAK gpiof_handler(void);
void WEAK gpiog_handler(void);
void WEAK gpioh_handler(void);
void WEAK uart2_handler(void);
void WEAK ssi1_handler(void);
void WEAK timer3a_handler(void);
void WEAK timer3b_handler(void);
void WEAK i2c1_handler(void);
void WEAK qei1_handler(void);
void WEAK can0_handler(void);
void WEAK can1_handler(void);
void WEAK can2_handler(void);
void WEAK eth_handler(void);
void WEAK hibernate_handler(void);
void WEAK usb0_handler(void);
void WEAK pwm0_3_handler(void);
void WEAK udma_handler(void);
void WEAK udmaerr_handler(void);
void WEAK adc1ss0_handler(void);
void WEAK adc1ss1_handler(void);
void WEAK adc1ss2_handler(void);
void WEAK adc1ss3_handler(void);
void WEAK i2s0_handler(void);
void WEAK epi0_handler(void);
void WEAK gpioj_handler(void);
void WEAK gpiok_handler(void);
void WEAK gpiol_handler(void);
void WEAK ssi2_handler(void);
void WEAK ssi3_handler(void);
void WEAK uart3_handler(void);
void WEAK uart4_handler(void);
void WEAK uart5_handler(void);
void WEAK uart6_handler(void);
void WEAK uart7_handler(void);
void WEAK i2c2_handler(void);
void WEAK i2c3_handler(void);
void WEAK timer4a_handler(void);
void WEAK timer4b_handler(void);
void WEAK timer5a_handler(void);
void WEAK timer5b_handler(void);
void WEAK wtimer0a_handler(void);
void WEAK wtimer0b_handler(void);
void WEAK wtimer1a_handler(void);
void WEAK wtimer1b_handler(void);
void WEAK wtimer2a_handler(void);
void WEAK wtimer2b_handler(void);
void WEAK wtimer3a_handler(void);
void WEAK wtimer3b_handler(void);
void WEAK wtimer4a_handler(void);
void WEAK wtimer4b_handler(void);
void WEAK wtimer5a_handler(void);
void WEAK wtimer5b_handler(void);
void WEAK sysexc_handler(void);
void WEAK peci0_handler(void);
void WEAK lpc0_handler(void);
void WEAK i2c4_handler(void);
void WEAK i2c5_handler(void);
void WEAK gpiom_handler(void);
void WEAK gpion_handler(void);
void WEAK fan0_handler(void);
void WEAK gpiop0_handler(void);
void WEAK gpiop1_handler(void);
void WEAK gpiop2_handler(void);
void WEAK gpiop3_handler(void);
void WEAK gpiop4_handler(void);
void WEAK gpiop5_handler(void);
void WEAK gpiop6_handler(void);
void WEAK gpiop7_handler(void);
void WEAK gpioq0_handler(void);
void WEAK gpioq1_handler(void);
void WEAK gpioq2_handler(void);
void WEAK gpioq3_handler(void);
void WEAK gpioq4_handler(void);
void WEAK gpioq5_handler(void);
void WEAK gpioq6_handler(void);
void WEAK gpioq7_handler(void);
void WEAK pwm1_0_handler(void);
void WEAK pwm1_1_handler(void);
void WEAK pwm1_2_handler(void);
void WEAK pwm1_3_handler(void);
void WEAK pwm1_fault_handler(void);
__attribute__ ((section(".vectors")))
void (*const vector_table[]) (void) = {
(void *)&_stack,
reset_handler,
nmi_handler,
hard_fault_handler,
mem_manage_handler,
bus_fault_handler,
usage_fault_handler,
0, 0, 0, 0, /* Reserved */
sv_call_handler,
debug_monitor_handler,
0, /* Reserved */
pend_sv_handler,
sys_tick_handler,
gpioa_handler, /* 16 */
gpiob_handler, /* 17 */
gpioc_handler, /* 18 */
gpiod_handler, /* 19 */
gpioe_handler, /* 20 */
uart0_handler, /* 21 */
uart1_handler, /* 22 */
ssi0_handler, /* 23 */
i2c0_handler, /* 24 */
pwm0_fault_handler, /* 25 */
pwm0_0_handler, /* 26 */
pwm0_1_handler, /* 27 */
pwm0_2_handler, /* 28 */
qei0_handler, /* 29 */
adc0ss0_handler, /* 30 */
adc0ss1_handler, /* 31 */
adc0ss2_handler, /* 32 */
adc0ss3_handler, /* 33 */
watchdog_handler, /* 34 */
timer0a_handler, /* 35 */
timer0b_handler, /* 36 */
timer1a_handler, /* 37 */
timer1b_handler, /* 38 */
timer2a_handler, /* 39 */
timer2b_handler, /* 40 */
comp0_handler, /* 41 */
comp1_handler, /* 42 */
comp2_handler, /* 43 */
sysctl_handler, /* 44 */
flash_handler, /* 45 */
gpiof_handler, /* 46 */
gpiog_handler, /* 47 */
gpioh_handler, /* 48 */
uart2_handler, /* 49 */
ssi1_handler, /* 50 */
timer3a_handler, /* 51 */
timer3b_handler, /* 52 */
i2c1_handler, /* 53 */
qei1_handler, /* 54 */
can0_handler, /* 55 */
can1_handler, /* 56 */
can2_handler, /* 57 */
eth_handler, /* 58 */
hibernate_handler, /* 59 */
usb0_handler, /* 60 */
pwm0_3_handler, /* 61 */
udma_handler, /* 62 */
udmaerr_handler, /* 63 */
adc1ss0_handler, /* 64 */
adc1ss1_handler, /* 65 */
adc1ss2_handler, /* 66 */
adc1ss3_handler, /* 67 */
i2s0_handler, /* 68 */
epi0_handler, /* 69 */
gpioj_handler, /* 70 */
gpiok_handler, /* 71 */
gpiol_handler, /* 72 */
ssi2_handler, /* 73 */
ssi3_handler, /* 74 */
uart3_handler, /* 75 */
uart4_handler, /* 76 */
uart5_handler, /* 77 */
uart6_handler, /* 78 */
uart7_handler, /* 79 */
0, /* 80 */
0, /* 81 */
0, /* 82 */
0, /* 83 */
i2c2_handler, /* 84 */
i2c3_handler, /* 85 */
timer4a_handler, /* 86 */
timer4b_handler, /* 87 */
0, /* 88 */
0, /* 89 */
0, /* 90 */
0, /* 91 */
0, /* 92 */
0, /* 93 */
0, /* 94 */
0, /* 95 */
0, /* 96 */
0, /* 97 */
0, /* 98 */
0, /* 99 */
0, /* 100 */
0, /* 101 */
0, /* 102 */
0, /* 103 */
0, /* 104 */
0, /* 105 */
0, /* 106 */
0, /* 107 */
timer5a_handler, /* 108 */
timer5b_handler, /* 109 */
wtimer0a_handler, /* 110 */
wtimer0b_handler, /* 111 */
wtimer1a_handler, /* 112 */
wtimer1b_handler, /* 113 */
wtimer2a_handler, /* 114 */
wtimer2b_handler, /* 115 */
wtimer3a_handler, /* 116 */
wtimer3b_handler, /* 117 */
wtimer4a_handler, /* 118 */
wtimer4b_handler, /* 119 */
wtimer5a_handler, /* 120 */
wtimer5b_handler, /* 121 */
sysexc_handler, /* 122 */
peci0_handler, /* 123 */
lpc0_handler, /* 124 */
i2c4_handler, /* 125 */
i2c5_handler, /* 126 */
gpiom_handler, /* 127 */
gpion_handler, /* 128 */
0, /* 129 */
fan0_handler, /* 130 */
0, /* 131 */
gpiop0_handler, /* 132 */
gpiop1_handler, /* 133 */
gpiop2_handler, /* 134 */
gpiop3_handler, /* 135 */
gpiop4_handler, /* 136 */
gpiop5_handler, /* 137 */
gpiop6_handler, /* 138 */
gpiop7_handler, /* 139 */
gpioq0_handler, /* 140 */
gpioq1_handler, /* 141 */
gpioq2_handler, /* 142 */
gpioq3_handler, /* 143 */
gpioq4_handler, /* 144 */
gpioq5_handler, /* 145 */
gpioq6_handler, /* 146 */
gpioq7_handler, /* 147 */
0, /* 148 */
0, /* 149 */
pwm1_0_handler, /* 150 */
pwm1_1_handler, /* 151 */
pwm1_2_handler, /* 152 */
pwm1_3_handler, /* 153 */
pwm1_fault_handler, /* 154 */
};
void reset_handler(void)
{
volatile unsigned *src, *dest;
__asm__("MSR msp, %0" : : "r"(&_stack));
for (src = &_data_loadaddr, dest = &_data; dest < &_edata; src++, dest++)
*dest = *src;
while (dest < &_ebss)
*dest++ = 0;
/* Call the application's entry point. */
main();
}
void blocking_handler(void)
{
while (1) ;
}
void null_handler(void)
{
/* Do nothing. */
}
#pragma weak nmi_handler = null_handler
#pragma weak hard_fault_handler = blocking_handler
#pragma weak mem_manage_handler = blocking_handler
#pragma weak bus_fault_handler = blocking_handler
#pragma weak usage_fault_handler = blocking_handler
#pragma weak sv_call_handler = null_handler
#pragma weak debug_monitor_handler = null_handler
#pragma weak pend_sv_handler = null_handler
#pragma weak sys_tick_handler = null_handler
#pragma weak gpioa_handler = null_handler
#pragma weak gpiob_handler = null_handler
#pragma weak gpioc_handler = null_handler
#pragma weak gpiod_handler = null_handler
#pragma weak gpioe_handler = null_handler
#pragma weak uart0_handler = null_handler
#pragma weak uart1_handler = null_handler
#pragma weak ssi0_handler = null_handler
#pragma weak i2c0_handler = null_handler
#pragma weak pwm0_fault_handler = null_handler
#pragma weak pwm0_0_handler = null_handler
#pragma weak pwm0_1_handler = null_handler
#pragma weak pwm0_2_handler = null_handler
#pragma weak qei0_handler = null_handler
#pragma weak adc0ss0_handler = null_handler
#pragma weak adc0ss1_handler = null_handler
#pragma weak adc0ss2_handler = null_handler
#pragma weak adc0ss3_handler = null_handler
#pragma weak watchdog_handler = null_handler
#pragma weak timer0a_handler = null_handler
#pragma weak timer0b_handler = null_handler
#pragma weak timer1a_handler = null_handler
#pragma weak timer1b_handler = null_handler
#pragma weak timer2a_handler = null_handler
#pragma weak timer2b_handler = null_handler
#pragma weak comp0_handler = null_handler
#pragma weak comp1_handler = null_handler
#pragma weak comp2_handler = null_handler
#pragma weak sysctl_handler = null_handler
#pragma weak flash_handler = null_handler
#pragma weak gpiof_handler = null_handler
#pragma weak gpiog_handler = null_handler
#pragma weak gpioh_handler = null_handler
#pragma weak uart2_handler = null_handler
#pragma weak ssi1_handler = null_handler
#pragma weak timer3a_handler = null_handler
#pragma weak timer3b_handler = null_handler
#pragma weak i2c1_handler = null_handler
#pragma weak qei1_handler = null_handler
#pragma weak can0_handler = null_handler
#pragma weak can1_handler = null_handler
#pragma weak can2_handler = null_handler
#pragma weak eth_handler = null_handler
#pragma weak hibernate_handler = null_handler
#pragma weak usb0_handler = null_handler
#pragma weak pwm0_3_handler = null_handler
#pragma weak udma_handler = null_handler
#pragma weak udmaerr_handler = null_handler
#pragma weak adc1ss0_handler = null_handler
#pragma weak adc1ss1_handler = null_handler
#pragma weak adc1ss2_handler = null_handler
#pragma weak adc1ss3_handler = null_handler
#pragma weak i2s0_handler = null_handler
#pragma weak epi0_handler = null_handler
#pragma weak gpioj_handler = null_handler
#pragma weak gpiok_handler = null_handler
#pragma weak gpiol_handler = null_handler
#pragma weak ssi2_handler = null_handler
#pragma weak ssi3_handler = null_handler
#pragma weak uart3_handler = null_handler
#pragma weak uart4_handler = null_handler
#pragma weak uart5_handler = null_handler
#pragma weak uart6_handler = null_handler
#pragma weak uart7_handler = null_handler
#pragma weak i2c2_handler = null_handler
#pragma weak i2c3_handler = null_handler
#pragma weak timer4a_handler = null_handler
#pragma weak timer4b_handler = null_handler
#pragma weak timer5a_handler = null_handler
#pragma weak timer5b_handler = null_handler
#pragma weak wtimer0a_handler = null_handler
#pragma weak wtimer0b_handler = null_handler
#pragma weak wtimer1a_handler = null_handler
#pragma weak wtimer1b_handler = null_handler
#pragma weak wtimer2a_handler = null_handler
#pragma weak wtimer2b_handler = null_handler
#pragma weak wtimer3a_handler = null_handler
#pragma weak wtimer3b_handler = null_handler
#pragma weak wtimer4a_handler = null_handler
#pragma weak wtimer4b_handler = null_handler
#pragma weak wtimer5a_handler = null_handler
#pragma weak wtimer5b_handler = null_handler
#pragma weak sysexc_handler = null_handler
#pragma weak peci0_handler = null_handler
#pragma weak lpc0_handler = null_handler
#pragma weak i2c4_handler = null_handler
#pragma weak i2c5_handler = null_handler
#pragma weak gpiom_handler = null_handler
#pragma weak gpion_handler = null_handler
#pragma weak fan0_handler = null_handler
#pragma weak gpiop0_handler = null_handler
#pragma weak gpiop1_handler = null_handler
#pragma weak gpiop2_handler = null_handler
#pragma weak gpiop3_handler = null_handler
#pragma weak gpiop4_handler = null_handler
#pragma weak gpiop5_handler = null_handler
#pragma weak gpiop6_handler = null_handler
#pragma weak gpiop7_handler = null_handler
#pragma weak gpioq0_handler = null_handler
#pragma weak gpioq1_handler = null_handler
#pragma weak gpioq2_handler = null_handler
#pragma weak gpioq3_handler = null_handler
#pragma weak gpioq4_handler = null_handler
#pragma weak gpioq5_handler = null_handler
#pragma weak gpioq6_handler = null_handler
#pragma weak gpioq7_handler = null_handler
#pragma weak pwm1_0_handler = null_handler
#pragma weak pwm1_1_handler = null_handler
#pragma weak pwm1_2_handler = null_handler
#pragma weak pwm1_3_handler = null_handler
#pragma weak pwm1_fault_handler = null_handler

View File

@@ -25,10 +25,10 @@ CC = $(PREFIX)-gcc
AR = $(PREFIX)-ar
CFLAGS = -Os -g -Wall -Wextra -I../../include -fno-common \
-mcpu=cortex-m3 -mthumb -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD
-ffunction-sections -fdata-sections -MD -DLPC13XX
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS = gpio.o assert.o
OBJS = gpio.o
VPATH += ../cm3

View File

@@ -25,10 +25,10 @@ CC = $(PREFIX)-gcc
AR = $(PREFIX)-ar
CFLAGS = -O0 -g -Wall -Wextra -I../../include -fno-common \
-mcpu=cortex-m3 -mthumb -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD
-ffunction-sections -fdata-sections -MD -DLPC17XX
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS = gpio.o vector.o assert.o
OBJS = gpio.o
VPATH += ../cm3

View File

@@ -28,11 +28,10 @@ AR = $(PREFIX)-ar
CFLAGS = -O2 -g3 -Wall -Wextra -I../../include -fno-common \
-mcpu=cortex-m4 -mthumb -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD \
-mfloat-abi=hard -mfpu=fpv4-sp-d16
-mfloat-abi=hard -mfpu=fpv4-sp-d16 -DLPC43XX
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS = gpio.o vector.o scu.o i2c.o ssp.o nvic.o systick.o \
assert.o
OBJS = gpio.o scu.o i2c.o ssp.o
VPATH += ../cm3

View File

@@ -1,76 +0,0 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
* Copyright (C) 2012 Fergus Noble <fergusnoble@gmail.com>
* Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/cm3/scs.h>
#include <libopencm3/lpc43xx/nvic.h>
void nvic_enable_irq(u8 irqn)
{
NVIC_ISER(irqn / 32) = (1 << (irqn % 32));
}
void nvic_disable_irq(u8 irqn)
{
NVIC_ICER(irqn / 32) = (1 << (irqn % 32));
}
u8 nvic_get_pending_irq(u8 irqn)
{
return NVIC_ISPR(irqn / 32) & (1 << (irqn % 32)) ? 1 : 0;
}
void nvic_set_pending_irq(u8 irqn)
{
NVIC_ISPR(irqn / 32) = (1 << (irqn % 32));
}
void nvic_clear_pending_irq(u8 irqn)
{
NVIC_ICPR(irqn / 32) = (1 << (irqn % 32));
}
u8 nvic_get_active_irq(u8 irqn)
{
return NVIC_IABR(irqn / 32) & (1 << (irqn % 32)) ? 1 : 0;
}
u8 nvic_get_irq_enabled(u8 irqn)
{
return NVIC_ISER(irqn / 32) & (1 << (irqn % 32)) ? 1 : 0;
}
void nvic_set_priority(u8 irqn, u8 priority)
{
if(irqn>NVIC_M4_QEI_IRQ)
{
/* Cortex-M system interrupts */
SCS_SHPR( (irqn&0xF)-4 ) = priority;
}else
{
/* Device specific interrupts */
NVIC_IPR(irqn) = priority;
}
}
void nvic_generate_software_interrupt(u8 irqn)
{
if (irqn <= 239)
NVIC_STIR |= irqn;
}

View File

@@ -1,69 +0,0 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
* Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/lpc43xx/systick.h>
void systick_set_reload(u32 value)
{
STK_LOAD = (value & 0x00FFFFFF);
}
u32 systick_get_value(void)
{
return STK_VAL;
}
void systick_set_clocksource(u8 clocksource)
{
STK_CTRL |= clocksource;
}
void systick_interrupt_enable(void)
{
STK_CTRL |= STK_CTRL_TICKINT;
}
void systick_interrupt_disable(void)
{
STK_CTRL &= ~STK_CTRL_TICKINT;
}
void systick_counter_enable(void)
{
STK_CTRL |= STK_CTRL_ENABLE;
}
void systick_counter_disable(void)
{
STK_CTRL &= ~STK_CTRL_ENABLE;
}
u8 systick_get_countflag(void)
{
if (STK_CTRL & STK_CTRL_COUNTFLAG)
return 1;
else
return 0;
}
u32 systick_get_calib(void)
{
return (STK_CALIB&0x00FFFFFF);
}

View File

@@ -1,264 +0,0 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Piotr Esden-Tempski <piotr@esden.net>
* Copyright (C) 2012 Michael Ossmann <mike@ossmann.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#define WEAK __attribute__ ((weak))
/* Symbols exported by the linker script(s): */
extern unsigned _data_loadaddr, _data, _edata, _ebss, _stack;
extern unsigned _etext_ram, _text_ram, _etext_rom;
void main(void);
void reset_handler(void);
void blocking_handler(void);
void null_handler(void);
void WEAK nmi_handler(void);
void WEAK hard_fault_handler(void);
void WEAK mem_manage_handler(void);
void WEAK bus_fault_handler(void);
void WEAK usage_fault_handler(void);
void WEAK sv_call_handler(void);
void WEAK debug_monitor_handler(void);
void WEAK pend_sv_handler(void);
void WEAK sys_tick_handler(void);
void WEAK dac_irqhandler(void);
void WEAK m0core_irqhandler(void);
void WEAK dma_irqhandler(void);
void WEAK ethernet_irqhandler(void);
void WEAK sdio_irqhandler(void);
void WEAK lcd_irqhandler(void);
void WEAK usb0_irqhandler(void);
void WEAK usb1_irqhandler(void);
void WEAK sct_irqhandler(void);
void WEAK ritimer_irqhandler(void);
void WEAK timer0_irqhandler(void);
void WEAK timer1_irqhandler(void);
void WEAK timer2_irqhandler(void);
void WEAK timer3_irqhandler(void);
void WEAK mcpwm_irqhandler(void);
void WEAK adc0_irqhandler(void);
void WEAK i2c0_irqhandler(void);
void WEAK i2c1_irqhandler(void);
void WEAK spi_irqhandler(void);
void WEAK adc1_irqhandler(void);
void WEAK ssp0_irqhandler(void);
void WEAK ssp1_irqhandler(void);
void WEAK usart0_irqhandler(void);
void WEAK uart1_irqhandler(void);
void WEAK usart2_irqhandler(void);
void WEAK usart3_irqhandler(void);
void WEAK i2s0_irqhandler(void);
void WEAK i2s1_irqhandler(void);
void WEAK spifi_irqhandler(void);
void WEAK sgpio_irqhandler(void);
void WEAK pin_int0_irqhandler(void);
void WEAK pin_int1_irqhandler(void);
void WEAK pin_int2_irqhandler(void);
void WEAK pin_int3_irqhandler(void);
void WEAK pin_int4_irqhandler(void);
void WEAK pin_int5_irqhandler(void);
void WEAK pin_int6_irqhandler(void);
void WEAK pin_int7_irqhandler(void);
void WEAK gint0_irqhandler(void);
void WEAK gint1_irqhandler(void);
void WEAK eventrouter_irqhandler(void);
void WEAK c_can1_irqhandler(void);
void WEAK atimer_irqhandler(void);
void WEAK rtc_irqhandler(void);
void WEAK wwdt_irqhandler(void);
void WEAK c_can0_irqhandler(void);
void WEAK qei_irqhandler(void);
__attribute__ ((section(".vectors")))
void (*const vector_table[]) (void) = {
/* Cortex-M4 interrupts */
(void*)&_stack,
reset_handler,
nmi_handler,
hard_fault_handler,
mem_manage_handler,
bus_fault_handler,
usage_fault_handler,
0, 0, 0, 0, /* reserved */
sv_call_handler,
debug_monitor_handler,
0, /* reserved */
pend_sv_handler,
sys_tick_handler,
/* LPC43xx interrupts */
dac_irqhandler,
m0core_irqhandler,
dma_irqhandler,
0, /* reserved */
0, /* reserved */
ethernet_irqhandler,
sdio_irqhandler,
lcd_irqhandler,
usb0_irqhandler,
usb1_irqhandler,
sct_irqhandler,
ritimer_irqhandler,
timer0_irqhandler,
timer1_irqhandler,
timer2_irqhandler,
timer3_irqhandler,
mcpwm_irqhandler,
adc0_irqhandler,
i2c0_irqhandler,
i2c1_irqhandler,
spi_irqhandler,
adc1_irqhandler,
ssp0_irqhandler,
ssp1_irqhandler,
usart0_irqhandler,
uart1_irqhandler,
usart2_irqhandler,
usart3_irqhandler,
i2s0_irqhandler,
i2s1_irqhandler,
spifi_irqhandler,
sgpio_irqhandler,
pin_int0_irqhandler,
pin_int1_irqhandler,
pin_int2_irqhandler,
pin_int3_irqhandler,
pin_int4_irqhandler,
pin_int5_irqhandler,
pin_int6_irqhandler,
pin_int7_irqhandler,
gint0_irqhandler,
gint1_irqhandler,
eventrouter_irqhandler,
c_can1_irqhandler,
0, /* reserved */
0, /* reserved */
atimer_irqhandler,
rtc_irqhandler,
0, /* reserved */
wwdt_irqhandler,
0, /* reserved */
c_can0_irqhandler,
qei_irqhandler,
};
#define MMIO32(addr) (*(volatile unsigned long*)(addr))
#define CREG_M4MEMMAP MMIO32( (0x40043000 + 0x100) )
void reset_handler(void)
{
volatile unsigned *src, *dest;
__asm__("MSR msp, %0" : : "r"(&_stack));
/* Copy the code from ROM to Real RAM (if enabled) */
if( (&_etext_ram-&_text_ram) > 0 )
{
src = &_etext_rom-(&_etext_ram-&_text_ram);
/* Change Shadow memory to ROM (for Debug Purpose in case Boot has not set correctly the M4MEMMAP because of debug) */
CREG_M4MEMMAP = (unsigned long)src;
for(dest = &_text_ram; dest < &_etext_ram; )
{
*dest++ = *src++;
}
/* Change Shadow memory to Real RAM */
CREG_M4MEMMAP = (unsigned long)&_text_ram;
/* Continue Execution in RAM */
}
for (src = &_data_loadaddr, dest = &_data; dest < &_edata; src++, dest++)
*dest = *src;
while (dest < &_ebss)
*dest++ = 0;
/* Call the application's entry point. */
main();
}
void blocking_handler(void)
{
while (1) ;
}
void null_handler(void)
{
/* Do nothing. */
}
#pragma weak nmi_handler = null_handler
#pragma weak hard_fault_handler = blocking_handler
#pragma weak mem_manage_handler = blocking_handler
#pragma weak bus_fault_handler = blocking_handler
#pragma weak usage_fault_handler = blocking_handler
#pragma weak sv_call_handler = null_handler
#pragma weak debug_monitor_handler = null_handler
#pragma weak pend_sv_handler = null_handler
#pragma weak sys_tick_handler = null_handler
#pragma weak dac_irqhandler = null_handler
#pragma weak m0core_irqhandler = null_handler
#pragma weak dma_irqhandler = null_handler
#pragma weak ethernet_irqhandler = null_handler
#pragma weak sdio_irqhandler = null_handler
#pragma weak lcd_irqhandler = null_handler
#pragma weak usb0_irqhandler = null_handler
#pragma weak usb1_irqhandler = null_handler
#pragma weak sct_irqhandler = null_handler
#pragma weak ritimer_irqhandler = null_handler
#pragma weak timer0_irqhandler = null_handler
#pragma weak timer1_irqhandler = null_handler
#pragma weak timer2_irqhandler = null_handler
#pragma weak timer3_irqhandler = null_handler
#pragma weak mcpwm_irqhandler = null_handler
#pragma weak adc0_irqhandler = null_handler
#pragma weak i2c0_irqhandler = null_handler
#pragma weak i2c1_irqhandler = null_handler
#pragma weak spi_irqhandler = null_handler
#pragma weak adc1_irqhandler = null_handler
#pragma weak ssp0_irqhandler = null_handler
#pragma weak ssp1_irqhandler = null_handler
#pragma weak usart0_irqhandler = null_handler
#pragma weak uart1_irqhandler = null_handler
#pragma weak usart2_irqhandler = null_handler
#pragma weak usart3_irqhandler = null_handler
#pragma weak i2s0_irqhandler = null_handler
#pragma weak i2s1_irqhandler = null_handler
#pragma weak spifi_irqhandler = null_handler
#pragma weak sgpio_irqhandler = null_handler
#pragma weak pin_int0_irqhandler = null_handler
#pragma weak pin_int1_irqhandler = null_handler
#pragma weak pin_int2_irqhandler = null_handler
#pragma weak pin_int3_irqhandler = null_handler
#pragma weak pin_int4_irqhandler = null_handler
#pragma weak pin_int5_irqhandler = null_handler
#pragma weak pin_int6_irqhandler = null_handler
#pragma weak pin_int7_irqhandler = null_handler
#pragma weak gint0_irqhandler = null_handler
#pragma weak gint1_irqhandler = null_handler
#pragma weak eventrouter_irqhandler = null_handler
#pragma weak c_can1_irqhandler = null_handler
#pragma weak atimer_irqhandler = null_handler
#pragma weak rtc_irqhandler = null_handler
#pragma weak wwdt_irqhandler = null_handler
#pragma weak c_can0_irqhandler = null_handler
#pragma weak qei_irqhandler = null_handler

View File

@@ -0,0 +1,48 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Piotr Esden-Tempski <piotr@esden.net>
* Copyright (C) 2012 Michael Ossmann <mike@ossmann.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/cm3/common.h>
extern unsigned _etext_ram, _text_ram, _etext_rom;
#define CREG_M4MEMMAP MMIO32( (0x40043000 + 0x100) )
static void pre_main(void)
{
volatile unsigned *src, *dest;
/* Copy the code from ROM to Real RAM (if enabled) */
if( (&_etext_ram-&_text_ram) > 0 )
{
src = &_etext_rom-(&_etext_ram-&_text_ram);
/* Change Shadow memory to ROM (for Debug Purpose in case Boot has not set correctly the M4MEMMAP because of debug) */
CREG_M4MEMMAP = (unsigned long)src;
for(dest = &_text_ram; dest < &_etext_ram; )
{
*dest++ = *src++;
}
/* Change Shadow memory to Real RAM */
CREG_M4MEMMAP = (unsigned long)&_text_ram;
/* Continue Execution in RAM */
}
}

View File

@@ -18,7 +18,16 @@
*/
#include <libopencm3/stm32/can.h>
#include <libopencm3/stm32/f1/rcc.h>
#if defined(STM32F1)
# include <libopencm3/stm32/f1/rcc.h>
#elif defined(STM32F2)
# include <libopencm3/stm32/f2/rcc.h>
#elif defined(STM32F4)
# include <libopencm3/stm32/f4/rcc.h>
#else
# error "stm32 family not defined."
#endif
void can_reset(u32 canport)
{
@@ -314,7 +323,7 @@ void can_receive(u32 canport, u8 fifo, bool release, u32 *id, bool *ext,
/* Release the FIFO. */
if (release)
can_fifo_release(CAN1, 0);
can_fifo_release(canport, fifo);
}
bool can_available_mailbox(u32 canport)

View File

@@ -17,7 +17,7 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/stm32/f1/desig.h>
#include <libopencm3/stm32/desig.h>
u16 desig_get_flash_size(void)
{

View File

@@ -2,6 +2,7 @@
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Mark Butler <mbutler@physics.otago.ac.nz>
* Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -15,11 +16,22 @@
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* This provides the code for the "next gen" EXTI block provided in F2/F4/L1
* devices. (differences only in the source selection)
*/
#include <libopencm3/stm32/exti.h>
#include <libopencm3/stm32/f2/syscfg.h>
#include <libopencm3/stm32/syscfg.h>
#if defined(STM32F2)
#include <libopencm3/stm32/f2/gpio.h>
#elif defined(STM32F4)
#include <libopencm3/stm32/f4/gpio.h>
#elif defined(STM32L1)
#include <libopencm3/stm32/l1/gpio.h>
#else
#error "invalid/unknown stm32 family for this code"
#endif
void exti_set_trigger(u32 extis, exti_trigger_type trig)
{
@@ -121,12 +133,24 @@ void exti_select_source(u32 exti, u32 gpioport)
case GPIOE:
bits = 0xb;
break;
#if defined(STM32L1)
#else
case GPIOF:
bits = 0xa;
break;
case GPIOG:
bits = 0x9;
break;
#endif
case GPIOH:
bits = 0x8;
break;
#if defined(STM32L1)
#else
case GPIOI:
bits = 0x7;
break;
#endif
}
/* Ensure that only valid EXTI lines are used. */

View File

@@ -28,10 +28,11 @@ CFLAGS = -Os -g -Wall -Wextra -I../../../include -fno-common \
-ffunction-sections -fdata-sections -MD -DSTM32F1
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS = vector.o rcc.o gpio.o usart.o adc.o spi.o flash.o nvic.o \
rtc.o i2c.o dma.o systick.o exti.o scb.o ethernet.o \
OBJS = rcc.o gpio.o usart.o adc.o spi.o flash.o \
rtc.o i2c.o dma.o exti.o ethernet.o \
usb_f103.o usb.o usb_control.o usb_standard.o can.o \
timer.o usb_f107.o desig.o crc.o assert.o dac.o iwdg.o pwr.o
timer.o usb_f107.o desig.o crc.o dac.o iwdg.o pwr.o \
usb_fx07_common.o
VPATH += ../../usb:../:../../cm3

View File

@@ -10,12 +10,18 @@
@date 18 August 2012
This library supports the DMA
Control System in the STM32F1xx series of ARM Cortex Microcontrollers
by ST Microelectronics. It can provide for two DMA controllers,
one with 7 channels and one with 5. Channels are hardware dedicated
and each is shared with a number of different sources (only one can be
used at a time, under the responsibility of the programmer).
This library supports the DMA Control System in the STM32 series of ARM Cortex
Microcontrollers by ST Microelectronics.
Up to two DMA controllers are supported. 12 DMA channels are allocated 7 to
the first DMA controller and 5 to the second. Each channel is connected to
between 3 and 6 hardware peripheral DMA signals in a logical OR arrangement.
DMA transfers can be configured to occur between peripheral and memory in
any combination including memory to memory. Circular mode transfers are
also supported in transfers involving a peripheral. An arbiter is provided
to resolve priority DMA requests. Transfers can be made with 8, 16 or 32 bit
words.
LGPL License Terms @ref lgpl_license
*/
@@ -67,6 +73,42 @@ void dma_channel_reset(u32 dma, u8 channel)
DMA_IFCR(dma) |= DMA_IFCR_CIF(channel);
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Channel Clear Interrupt Flag
The interrupt flag for the channel is cleared. More than one interrupt for the
same channel may be cleared by using the logical OR of the interrupt flags.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: @ref dma_st_number
@param[in] interrupts unsigned int32. Logical OR of interrupt numbers: @ref dma_if_offset
*/
void dma_clear_interrupt_flags(u32 dma, u8 channel, u32 interrupts)
{
/* Get offset to interrupt flag location in channel field */
u32 flags = (interrupts << DMA_FLAG_OFFSET(channel));
DMA_IFCR(dma) = flags;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Channel Read Interrupt Flag
The interrupt flag for the channel is returned.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: @ref dma_st_number
@param[in] interrupt unsigned int32. Interrupt number: @ref dma_st_number
@returns bool interrupt flag is set.
*/
bool dma_get_interrupt_flag(u32 dma, u8 channel, u32 interrupt)
{
/* get offset to interrupt flag location in channel field. */
u32 flag = (interrupt << DMA_FLAG_OFFSET(channel));
return ((DMA_ISR(dma) & flag) > 0);
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Channel Enable Memory to Memory Transfers
@@ -160,11 +202,39 @@ void dma_enable_memory_increment_mode(u32 dma, u8 channel)
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_disable_memory_increment_mode(u32 dma, u8 channel)
{
DMA_CCR(dma, channel) &= ~DMA_CCR_MINC;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Channel Enable Peripheral Increment after Transfer
Following each transfer the current peripheral address is incremented by
1, 2 or 4 depending on the data size set in @ref dma_set_peripheral_size. The
value held by the base peripheral address register is unchanged.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_enable_peripheral_increment_mode(u32 dma, u8 channel)
{
DMA_CCR(dma, channel) |= DMA_CCR_PINC;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Channel Disable Peripheral Increment after Transfer
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2
*/
void dma_disable_peripheral_increment_mode(u32 dma, u8 channel)
{
DMA_CCR(dma, channel) &= ~DMA_CCR_PINC;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Channel Enable Memory Circular Mode

View File

@@ -1,316 +0,0 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Piotr Esden-Tempski <piotr@esden.net>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#define WEAK __attribute__ ((weak))
#define NAKED __attribute__((naked))
#include <stdint.h>
/* Symbols exported by the linker script(s): */
extern unsigned _data_loadaddr, _data, _edata, _ebss, _stack;
void main(void);
void reset_handler(void);
void blocking_handler(void);
void null_handler(void);
void WEAK nmi_handler(void);
void WEAK hard_fault_handler(void);
void WEAK mem_manage_handler(void);
void WEAK bus_fault_handler(void);
void WEAK usage_fault_handler(void);
void WEAK sv_call_handler(void);
void WEAK debug_monitor_handler(void);
void WEAK pend_sv_handler(void);
void WEAK sys_tick_handler(void);
void WEAK wwdg_isr(void);
void WEAK pvd_isr(void);
void WEAK tamper_isr(void);
void WEAK rtc_isr(void);
void WEAK flash_isr(void);
void WEAK rcc_isr(void);
void WEAK exti0_isr(void);
void WEAK exti1_isr(void);
void WEAK exti2_isr(void);
void WEAK exti3_isr(void);
void WEAK exti4_isr(void);
void WEAK dma1_channel1_isr(void);
void WEAK dma1_channel2_isr(void);
void WEAK dma1_channel3_isr(void);
void WEAK dma1_channel4_isr(void);
void WEAK dma1_channel5_isr(void);
void WEAK dma1_channel6_isr(void);
void WEAK dma1_channel7_isr(void);
void WEAK adc1_2_isr(void);
void WEAK usb_hp_can_tx_isr(void);
void WEAK usb_lp_can_rx0_isr(void);
void WEAK can_rx1_isr(void);
void WEAK can_sce_isr(void);
void WEAK exti9_5_isr(void);
void WEAK tim1_brk_isr(void);
void WEAK tim1_up_isr(void);
void WEAK tim1_trg_com_isr(void);
void WEAK tim1_cc_isr(void);
void WEAK tim2_isr(void);
void WEAK tim3_isr(void);
void WEAK tim4_isr(void);
void WEAK i2c1_ev_isr(void);
void WEAK i2c1_er_isr(void);
void WEAK i2c2_ev_isr(void);
void WEAK i2c2_er_isr(void);
void WEAK spi1_isr(void);
void WEAK spi2_isr(void);
void WEAK usart1_isr(void);
void WEAK usart2_isr(void);
void WEAK usart3_isr(void);
void WEAK exti15_10_isr(void);
void WEAK rtc_alarm_isr(void);
void WEAK usb_wakeup_isr(void);
void WEAK tim8_brk_isr(void);
void WEAK tim8_up_isr(void);
void WEAK tim8_trg_com_isr(void);
void WEAK tim8_cc_isr(void);
void WEAK adc3_isr(void);
void WEAK fsmc_isr(void);
void WEAK sdio_isr(void);
void WEAK tim5_isr(void);
void WEAK spi3_isr(void);
void WEAK uart4_isr(void);
void WEAK uart5_isr(void);
void WEAK tim6_isr(void);
void WEAK tim7_isr(void);
void WEAK dma2_channel1_isr(void);
void WEAK dma2_channel2_isr(void);
void WEAK dma2_channel3_isr(void);
void WEAK dma2_channel4_5_isr(void);
void WEAK dma2_channel5_isr(void);
void WEAK eth_isr(void);
void WEAK eth_wkup_isr(void);
void WEAK can2_tx_isr(void);
void WEAK can2_rx0_isr(void);
void WEAK can2_rx1_isr(void);
void WEAK can2_sce_isr(void);
void WEAK otg_fs_isr(void);
__attribute__ ((section(".vectors")))
void (*const vector_table[]) (void) = {
(void*)&_stack, /* Addr: 0x0000_0000 */
reset_handler, /* Addr: 0x0000_0004 */
nmi_handler, /* Addr: 0x0000_0008 */
hard_fault_handler, /* Addr: 0x0000_000C */
mem_manage_handler, /* Addr: 0x0000_0010 */
bus_fault_handler, /* Addr: 0x0000_0014 */
usage_fault_handler, /* Addr: 0x0000_0018 */
0, 0, 0, 0, /* Reserved Addr: 0x0000_001C - 0x0000_002B */
sv_call_handler, /* Addr: 0x0000_002C */
debug_monitor_handler, /* Addr: 0x0000_0030*/
0, /* Reserved Addr: 0x0000_00034 */
pend_sv_handler, /* Addr: 0x0000_0038 */
sys_tick_handler, /* Addr: 0x0000_003C */
wwdg_isr, /* Addr: 0x0000_0040 */
pvd_isr, /* Addr: 0x0000_0044 */
tamper_isr, /* Addr: 0x0000_0048 */
rtc_isr, /* Addr: 0x0000_004C */
flash_isr, /* Addr: 0x0000_0050 */
rcc_isr, /* Addr: 0x0000_0054 */
exti0_isr, /* Addr: 0x0000_0058 */
exti1_isr, /* Addr: 0x0000_005C */
exti2_isr, /* Addr: 0x0000_0060 */
exti3_isr, /* Addr: 0x0000_0064 */
exti4_isr, /* Addr: 0x0000_0068 */
dma1_channel1_isr, /* Addr: 0x0000_006C */
dma1_channel2_isr, /* Addr: 0x0000_0070 */
dma1_channel3_isr, /* Addr: 0x0000_0074 */
dma1_channel4_isr, /* Addr: 0x0000_0078 */
dma1_channel5_isr, /* Addr: 0x0000_007C */
dma1_channel6_isr, /* Addr: 0x0000_0080 */
dma1_channel7_isr, /* Addr: 0x0000_0084 */
adc1_2_isr, /* Addr: 0x0000_0088 */
usb_hp_can_tx_isr, /* Addr: 0x0000_008C */
usb_lp_can_rx0_isr, /* Addr: 0x0000_0090 */
can_rx1_isr, /* Addr: 0x0000_0094 */
can_sce_isr, /* Addr: 0x0000_0098 */
exti9_5_isr, /* Addr: 0x0000_009C */
tim1_brk_isr, /* Addr: 0x0000_00A0 */
tim1_up_isr, /* Addr: 0x0000_00A4 */
tim1_trg_com_isr, /* Addr: 0x0000_00A8 */
tim1_cc_isr, /* Addr: 0x0000_00AC */
tim2_isr, /* Addr: 0x0000_00B0 */
tim3_isr, /* Addr: 0x0000_00B4 */
tim4_isr, /* Addr: 0x0000_00B8 */
i2c1_ev_isr, /* Addr: 0x0000_00BC */
i2c1_er_isr, /* Addr: 0x0000_00C0 */
i2c2_ev_isr, /* Addr: 0x0000_00C4 */
i2c2_er_isr, /* Addr: 0x0000_00C8 */
spi1_isr, /* Addr: 0x0000_00CC */
spi2_isr, /* Addr: 0x0000_00D0 */
usart1_isr, /* Addr: 0x0000_00D4 */
usart2_isr, /* Addr: 0x0000_00D8 */
usart3_isr, /* Addr: 0x0000_00DC */
exti15_10_isr, /* Addr: 0x0000_00E0 */
rtc_alarm_isr, /* Addr: 0x0000_00E4 */
usb_wakeup_isr, /* Addr: 0x0000_00E8 */
tim8_brk_isr, /* Addr: 0x0000_00EC */
tim8_up_isr, /* Addr: 0x0000_00F0 */
tim8_trg_com_isr, /* Addr: 0x0000_00F4 */
tim8_cc_isr, /* Addr: 0x0000_00F8 */
adc3_isr, /* Addr: 0x0000_00FC */
fsmc_isr, /* Addr: 0x0000_0100 */
sdio_isr, /* Addr: 0x0000_0104 */
tim5_isr, /* Addr: 0x0000_0108 */
spi3_isr, /* Addr: 0x0000_010C */
uart4_isr, /* Addr: 0x0000_0110 */
uart5_isr, /* Addr: 0x0000_0114 */
tim6_isr, /* Addr: 0x0000_0118 */
tim7_isr, /* Addr: 0x0000_011C */
dma2_channel1_isr, /* Addr: 0x0000_0120 */
dma2_channel2_isr, /* Addr: 0x0000_0124 */
dma2_channel3_isr, /* Addr: 0x0000_0128 */
dma2_channel4_5_isr, /* Addr: 0x0000_012C */
dma2_channel5_isr, /* Addr: 0x0000_0130 */
eth_isr, /* Addr: 0x0000_0134 */
eth_wkup_isr, /* Addr: 0x0000_0138 */
can2_tx_isr, /* Addr: 0x0000_013C */
can2_rx0_isr, /* Addr: 0x0000_0140 */
can2_rx1_isr, /* Addr: 0x0000_0144 */
can2_sce_isr, /* Addr: 0x0000_0148 */
otg_fs_isr, /* Addr: 0x0000_014C */
};
void WEAK user_reset_hook(void);
void handle_dfu_bootloader(void)
{
uint32_t reset_str = *((uint32_t *)0x2000FFF0);
if (reset_str == 0xDEADBEEF) {
*((uint32_t *)0x2000FFF0) = 0x00;
asm("ldr r0, =0x1fffb000");
asm("ldr sp, [r0, #0]");
asm("ldr r0, [r0, #4]");
asm("bx r0");
}
}
void NAKED reset_handler(void)
{
volatile unsigned *src, *dest;
__asm__("MSR msp, %0" : : "r"(&_stack));
user_reset_hook();
for (src = &_data_loadaddr, dest = &_data; dest < &_edata; src++, dest++)
*dest = *src;
while (dest < &_ebss)
*dest++ = 0;
/* Call the application's entry point. */
main();
}
void blocking_handler(void)
{
while (1) ;
}
void null_handler(void)
{
/* Do nothing. */
}
#pragma weak user_reset_hook = handle_dfu_bootloader
#pragma weak nmi_handler = null_handler
#pragma weak hard_fault_handler = blocking_handler
#pragma weak mem_manage_handler = blocking_handler
#pragma weak bus_fault_handler = blocking_handler
#pragma weak usage_fault_handler = blocking_handler
#pragma weak sv_call_handler = null_handler
#pragma weak debug_monitor_handler = null_handler
#pragma weak pend_sv_handler = null_handler
#pragma weak sys_tick_handler = null_handler
#pragma weak wwdg_isr = null_handler
#pragma weak pvd_isr = null_handler
#pragma weak tamper_isr = null_handler
#pragma weak rtc_isr = null_handler
#pragma weak flash_isr = null_handler
#pragma weak rcc_isr = null_handler
#pragma weak exti0_isr = null_handler
#pragma weak exti1_isr = null_handler
#pragma weak exti2_isr = null_handler
#pragma weak exti3_isr = null_handler
#pragma weak exti4_isr = null_handler
#pragma weak dma1_channel1_isr = null_handler
#pragma weak dma1_channel2_isr = null_handler
#pragma weak dma1_channel3_isr = null_handler
#pragma weak dma1_channel4_isr = null_handler
#pragma weak dma1_channel5_isr = null_handler
#pragma weak dma1_channel6_isr = null_handler
#pragma weak dma1_channel7_isr = null_handler
#pragma weak adc1_2_isr = null_handler
#pragma weak usb_hp_can_tx_isr = null_handler
#pragma weak usb_lp_can_rx0_isr = null_handler
#pragma weak can_rx1_isr = null_handler
#pragma weak can_sce_isr = null_handler
#pragma weak exti9_5_isr = null_handler
#pragma weak tim1_brk_isr = null_handler
#pragma weak tim1_up_isr = null_handler
#pragma weak tim1_trg_com_isr = null_handler
#pragma weak tim1_cc_isr = null_handler
#pragma weak tim2_isr = null_handler
#pragma weak tim3_isr = null_handler
#pragma weak tim4_isr = null_handler
#pragma weak i2c1_ev_isr = null_handler
#pragma weak i2c1_er_isr = null_handler
#pragma weak i2c2_ev_isr = null_handler
#pragma weak i2c2_er_isr = null_handler
#pragma weak spi1_isr = null_handler
#pragma weak spi2_isr = null_handler
#pragma weak usart1_isr = null_handler
#pragma weak usart2_isr = null_handler
#pragma weak usart3_isr = null_handler
#pragma weak exti15_10_isr = null_handler
#pragma weak rtc_alarm_isr = null_handler
#pragma weak usb_wakeup_isr = null_handler
#pragma weak tim8_brk_isr = null_handler
#pragma weak tim8_up_isr = null_handler
#pragma weak tim8_trg_com_isr = null_handler
#pragma weak tim8_cc_isr = null_handler
#pragma weak adc3_isr = null_handler
#pragma weak fsmc_isr = null_handler
#pragma weak sdio_isr = null_handler
#pragma weak tim5_isr = null_handler
#pragma weak spi3_isr = null_handler
#pragma weak uart4_isr = null_handler
#pragma weak uart5_isr = null_handler
#pragma weak tim6_isr = null_handler
#pragma weak tim7_isr = null_handler
#pragma weak dma2_channel1_isr = null_handler
#pragma weak dma2_channel2_isr = null_handler
#pragma weak dma2_channel3_isr = null_handler
#pragma weak dma2_channel4_5_isr = null_handler
#pragma weak dma2_channel5_isr
#pragma weak eth_isr = null_handler
#pragma weak eth_wkup_isr = null_handler
#pragma weak can2_tx_isr = null_handler
#pragma weak can2_rx0_isr = null_handler
#pragma weak can2_rx1_isr = null_handler
#pragma weak can2_sce_isr = null_handler
#pragma weak otg_fs_isr = null_handler

View File

@@ -28,8 +28,8 @@ CFLAGS = -Os -g -Wall -Wextra -I../../../include -fno-common \
-ffunction-sections -fdata-sections -MD -DSTM32F2
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS = vector.o rcc.o gpio.o usart.o spi.o flash.o nvic.o \
i2c.o systick.o exti.o scb.o timer.o assert.o
OBJS = rcc.o gpio2.o usart.o spi.o flash.o \
i2c.o exti2.o timer.o
VPATH += ../../usb:../:../../cm3

View File

@@ -1,142 +0,0 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2011 Fergus Noble <fergusnoble@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/stm32/f2/gpio.h>
void gpio_mode_setup(u32 gpioport, u8 mode, u8 pull_up_down, u16 gpios)
{
u16 i;
u32 moder, pupd;
/*
* We want to set the config only for the pins mentioned in gpios,
* but keeping the others, so read out the actual config first.
*/
moder = GPIO_MODER(gpioport);
pupd = GPIO_PUPDR(gpioport);
for (i = 0; i < 16; i++) {
if (!((1 << i) & gpios))
continue;
moder &= ~GPIO_MODE_MASK(i);
moder |= GPIO_MODE(i, mode);
pupd &= ~GPIO_PUPD_MASK(i);
pupd |= GPIO_PUPD(i, pull_up_down);
}
/* Set mode and pull up/down control registers. */
GPIO_MODER(gpioport) = moder;
GPIO_PUPDR(gpioport) = pupd;
}
void gpio_set_output_options(u32 gpioport, u8 otype, u8 speed, u16 gpios)
{
u16 i;
u32 ospeedr;
if (otype == 0x1)
GPIO_OTYPER(gpioport) |= gpios;
else
GPIO_OTYPER(gpioport) &= ~gpios;
ospeedr = GPIO_OSPEEDR(gpioport);
for (i = 0; i < 16; i++) {
if (!((1 << i) & gpios))
continue;
ospeedr &= ~GPIO_OSPEED_MASK(i);
ospeedr |= GPIO_OSPEED(i, speed);
}
GPIO_OSPEEDR(gpioport) = ospeedr;
}
void gpio_set_af(u32 gpioport, u8 alt_func_num, u16 gpios)
{
u16 i;
u32 afrl, afrh;
afrl = GPIO_AFRL(gpioport);
afrh = GPIO_AFRH(gpioport);
for (i = 0; i < 8; i++) {
if (!((1 << i) & gpios))
continue;
afrl &= ~GPIO_AFR_MASK(i);
afrl |= GPIO_AFR(i, alt_func_num);
}
for (i = 8; i < 16; i++) {
if (!((1 << i) & gpios))
continue;
afrl &= ~GPIO_AFR_MASK(i - 8);
afrh |= GPIO_AFR(i - 8, alt_func_num);
}
GPIO_AFRL(gpioport) = afrl;
GPIO_AFRH(gpioport) = afrh;
}
void gpio_set(u32 gpioport, u16 gpios)
{
GPIO_BSRR(gpioport) = gpios;
}
void gpio_clear(u32 gpioport, u16 gpios)
{
GPIO_BSRR(gpioport) = gpios << 16;
}
u16 gpio_get(u32 gpioport, u16 gpios)
{
return gpio_port_read(gpioport) & gpios;
}
void gpio_toggle(u32 gpioport, u16 gpios)
{
GPIO_ODR(gpioport) ^= gpios;
}
u16 gpio_port_read(u32 gpioport)
{
return (u16)GPIO_IDR(gpioport);
}
void gpio_port_write(u32 gpioport, u16 data)
{
GPIO_ODR(gpioport) = data;
}
void gpio_port_config_lock(u32 gpioport, u16 gpios)
{
u32 reg32;
/* Special "Lock Key Writing Sequence", see datasheet. */
GPIO_LCKR(gpioport) = GPIO_LCKK | gpios; /* Set LCKK. */
GPIO_LCKR(gpioport) = ~GPIO_LCKK & gpios; /* Clear LCKK. */
GPIO_LCKR(gpioport) = GPIO_LCKK | gpios; /* Set LCKK. */
reg32 = GPIO_LCKR(gpioport); /* Read LCKK. */
reg32 = GPIO_LCKR(gpioport); /* Read LCKK again. */
/* Tell the compiler the variable is actually used. It will get optimized out anyways. */
reg32 = reg32;
/* If (reg32 & GPIO_LCKK) is true, the lock is now active. */
}

View File

@@ -1,928 +0,0 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Edward Cheeseman <evbuilder@users.sourceforge.org>
* Copyright (C) 2011 Stephen Caudle <scaudle@doceme.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Basic TIMER handling API.
*
* Examples:
* timer_set_mode(TIM1, TIM_CR1_CKD_CK_INT_MUL_2,
* TIM_CR1_CMS_CENTRE_3, TIM_CR1_DIR_UP);
*/
#include <libopencm3/stm32/f2/timer.h>
#include <libopencm3/stm32/f2/rcc.h>
void timer_reset(u32 timer_peripheral)
{
switch (timer_peripheral) {
case TIM1:
rcc_peripheral_reset(&RCC_APB2RSTR, RCC_APB2RSTR_TIM1RST);
rcc_peripheral_clear_reset(&RCC_APB2RSTR, RCC_APB2RSTR_TIM1RST);
break;
case TIM2:
rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM2RST);
rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM2RST);
break;
case TIM3:
rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM3RST);
rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM3RST);
break;
case TIM4:
rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM4RST);
rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM4RST);
break;
case TIM5:
rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM5RST);
rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM5RST);
break;
case TIM6:
rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM6RST);
rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM6RST);
break;
case TIM7:
rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM7RST);
rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM7RST);
break;
case TIM8:
rcc_peripheral_reset(&RCC_APB2RSTR, RCC_APB2RSTR_TIM8RST);
rcc_peripheral_clear_reset(&RCC_APB2RSTR, RCC_APB2RSTR_TIM8RST);
break;
/* These timers are not supported in libopencm3 yet */
/*
case TIM9:
rcc_peripheral_reset(&RCC_APB2RSTR, RCC_APB2RSTR_TIM9RST);
rcc_peripheral_clear_reset(&RCC_APB2RSTR, RCC_APB2RSTR_TIM9RST);
break;
case TIM10:
rcc_peripheral_reset(&RCC_APB2RSTR, RCC_APB2RSTR_TIM10RST);
rcc_peripheral_clear_reset(&RCC_APB2RSTR, RCC_APB2RSTR_TIM10RST);
break;
case TIM11:
rcc_peripheral_reset(&RCC_APB2RSTR, RCC_APB2RSTR_TIM11RST);
rcc_peripheral_clear_reset(&RCC_APB2RSTR, RCC_APB2RSTR_TIM11RST);
break;
case TIM12:
rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM12RST);
rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM12RST);
break;
case TIM13:
rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM13RST);
rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM13RST);
break;
case TIM14:
rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM14RST);
rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM14RST);
break;
*/
}
}
void timer_enable_irq(u32 timer_peripheral, u32 irq)
{
TIM_DIER(timer_peripheral) |= irq;
}
void timer_disable_irq(u32 timer_peripheral, u32 irq)
{
TIM_DIER(timer_peripheral) &= ~irq;
}
bool timer_get_flag(u32 timer_peripheral, u32 flag)
{
if (((TIM_SR(timer_peripheral) & flag) != 0) &&
((TIM_DIER(timer_peripheral) & flag) != 0)) {
return true;
}
return false;
}
void timer_clear_flag(u32 timer_peripheral, u32 flag)
{
TIM_SR(timer_peripheral) &= ~flag;
}
void timer_set_mode(u32 timer_peripheral, u32 clock_div,
u32 alignment, u32 direction)
{
u32 cr1;
cr1 = TIM_CR1(timer_peripheral);
cr1 &= ~(TIM_CR1_CKD_CK_INT_MASK | TIM_CR1_CMS_MASK | TIM_CR1_DIR_DOWN);
cr1 |= clock_div | alignment | direction;
TIM_CR1(timer_peripheral) = cr1;
}
void timer_set_clock_division(u32 timer_peripheral, u32 clock_div)
{
clock_div &= TIM_CR1_CKD_CK_INT_MASK;
TIM_CR1(timer_peripheral) &= ~TIM_CR1_CKD_CK_INT_MASK;
TIM_CR1(timer_peripheral) |= clock_div;
}
void timer_enable_preload(u32 timer_peripheral)
{
TIM_CR1(timer_peripheral) |= TIM_CR1_ARPE;
}
void timer_disable_preload(u32 timer_peripheral)
{
TIM_CR1(timer_peripheral) &= ~TIM_CR1_ARPE;
}
void timer_set_alignment(u32 timer_peripheral, u32 alignment)
{
alignment &= TIM_CR1_CMS_MASK;
TIM_CR1(timer_peripheral) &= ~TIM_CR1_CMS_MASK;
TIM_CR1(timer_peripheral) |= alignment;
}
void timer_direction_up(u32 timer_peripheral)
{
TIM_CR1(timer_peripheral) &= ~TIM_CR1_DIR_DOWN;
}
void timer_direction_down(u32 timer_peripheral)
{
TIM_CR1(timer_peripheral) |= TIM_CR1_DIR_DOWN;
}
void timer_one_shot_mode(u32 timer_peripheral)
{
TIM_CR1(timer_peripheral) |= TIM_CR1_OPM;
}
void timer_continuous_mode(u32 timer_peripheral)
{
TIM_CR1(timer_peripheral) &= ~TIM_CR1_OPM;
}
void timer_update_on_any(u32 timer_peripheral)
{
TIM_CR1(timer_peripheral) &= ~TIM_CR1_URS;
}
void timer_update_on_overflow(u32 timer_peripheral)
{
TIM_CR1(timer_peripheral) |= TIM_CR1_URS;
}
void timer_enable_update_event(u32 timer_peripheral)
{
TIM_CR1(timer_peripheral) &= ~TIM_CR1_UDIS;
}
void timer_disable_update_event(u32 timer_peripheral)
{
TIM_CR1(timer_peripheral) |= TIM_CR1_UDIS;
}
void timer_enable_counter(u32 timer_peripheral)
{
TIM_CR1(timer_peripheral) |= TIM_CR1_CEN;
}
void timer_disable_counter(u32 timer_peripheral)
{
TIM_CR1(timer_peripheral) &= ~TIM_CR1_CEN;
}
void timer_set_output_idle_state(u32 timer_peripheral, u32 outputs)
{
TIM_CR2(timer_peripheral) |= outputs & TIM_CR2_OIS_MASK;
}
void timer_reset_output_idle_state(u32 timer_peripheral, u32 outputs)
{
TIM_CR2(timer_peripheral) &= ~(outputs & TIM_CR2_OIS_MASK);
}
void timer_set_ti1_ch123_xor(u32 timer_peripheral)
{
TIM_CR2(timer_peripheral) |= TIM_CR2_TI1S;
}
void timer_set_ti1_ch1(u32 timer_peripheral)
{
TIM_CR2(timer_peripheral) &= ~TIM_CR2_TI1S;
}
void timer_set_master_mode(u32 timer_peripheral, u32 mode)
{
TIM_CR2(timer_peripheral) &= ~TIM_CR2_MMS_MASK;
TIM_CR2(timer_peripheral) |= mode;
}
void timer_set_dma_on_compare_event(u32 timer_peripheral)
{
TIM_CR2(timer_peripheral) &= ~TIM_CR2_CCDS;
}
void timer_set_dma_on_update_event(u32 timer_peripheral)
{
TIM_CR2(timer_peripheral) |= TIM_CR2_CCDS;
}
void timer_enable_compare_control_update_on_trigger(u32 timer_peripheral)
{
TIM_CR2(timer_peripheral) |= TIM_CR2_CCUS;
}
void timer_disable_compare_control_update_on_trigger(u32 timer_peripheral)
{
TIM_CR2(timer_peripheral) &= ~TIM_CR2_CCUS;
}
void timer_enable_preload_complementry_enable_bits(u32 timer_peripheral)
{
TIM_CR2(timer_peripheral) |= TIM_CR2_CCPC;
}
void timer_disable_preload_complementry_enable_bits(u32 timer_peripheral)
{
TIM_CR2(timer_peripheral) &= ~TIM_CR2_CCPC;
}
void timer_set_prescaler(u32 timer_peripheral, u32 value)
{
TIM_PSC(timer_peripheral) = value;
}
void timer_set_repetition_counter(u32 timer_peripheral, u32 value)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_RCR(timer_peripheral) = value;
}
void timer_set_period(u32 timer_peripheral, u32 period)
{
TIM_ARR(timer_peripheral) = period;
}
void timer_enable_oc_clear(u32 timer_peripheral, enum tim_oc_id oc_id)
{
switch (oc_id) {
case TIM_OC1:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1CE;
break;
case TIM_OC2:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2CE;
break;
case TIM_OC3:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3CE;
break;
case TIM_OC4:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4CE;
break;
case TIM_OC1N:
case TIM_OC2N:
case TIM_OC3N:
/* Ignoring as fast enable only applies to the whole channel. */
break;
}
}
void timer_disable_oc_clear(u32 timer_peripheral, enum tim_oc_id oc_id)
{
switch (oc_id) {
case TIM_OC1:
TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC1CE;
break;
case TIM_OC2:
TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC2CE;
break;
case TIM_OC3:
TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC3CE;
break;
case TIM_OC4:
TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC4CE;
break;
case TIM_OC1N:
case TIM_OC2N:
case TIM_OC3N:
/* Ignoring as fast enable only applies to the whole channel. */
break;
}
}
void timer_set_oc_fast_mode(u32 timer_peripheral, enum tim_oc_id oc_id)
{
switch (oc_id) {
case TIM_OC1:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1FE;
break;
case TIM_OC2:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2FE;
break;
case TIM_OC3:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3FE;
break;
case TIM_OC4:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4FE;
break;
case TIM_OC1N:
case TIM_OC2N:
case TIM_OC3N:
/* Ignoring as fast enable only applies to the whole channel. */
break;
}
}
void timer_set_oc_slow_mode(u32 timer_peripheral, enum tim_oc_id oc_id)
{
switch (oc_id) {
case TIM_OC1:
TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC1FE;
break;
case TIM_OC2:
TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC2FE;
break;
case TIM_OC3:
TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC3FE;
break;
case TIM_OC4:
TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC4FE;
break;
case TIM_OC1N:
case TIM_OC2N:
case TIM_OC3N:
/* Ignoring as this option applies to the whole channel. */
break;
}
}
void timer_set_oc_mode(u32 timer_peripheral, enum tim_oc_id oc_id,
enum tim_oc_mode oc_mode)
{
switch (oc_id) {
case TIM_OC1:
TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_CC1S_MASK;
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_CC1S_OUT;
TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC1M_MASK;
switch (oc_mode) {
case TIM_OCM_FROZEN:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_FROZEN;
break;
case TIM_OCM_ACTIVE:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_ACTIVE;
break;
case TIM_OCM_INACTIVE:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_INACTIVE;
break;
case TIM_OCM_TOGGLE:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_TOGGLE;
break;
case TIM_OCM_FORCE_LOW:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_FORCE_LOW;
break;
case TIM_OCM_FORCE_HIGH:
TIM_CCMR1(timer_peripheral) |=
TIM_CCMR1_OC1M_FORCE_HIGH;
break;
case TIM_OCM_PWM1:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_PWM1;
break;
case TIM_OCM_PWM2:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_PWM2;
break;
}
break;
case TIM_OC2:
TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_CC2S_MASK;
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_CC2S_OUT;
TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC2M_MASK;
switch (oc_mode) {
case TIM_OCM_FROZEN:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_FROZEN;
break;
case TIM_OCM_ACTIVE:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_ACTIVE;
break;
case TIM_OCM_INACTIVE:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_INACTIVE;
break;
case TIM_OCM_TOGGLE:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_TOGGLE;
break;
case TIM_OCM_FORCE_LOW:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_FORCE_LOW;
break;
case TIM_OCM_FORCE_HIGH:
TIM_CCMR1(timer_peripheral) |=
TIM_CCMR1_OC2M_FORCE_HIGH;
break;
case TIM_OCM_PWM1:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_PWM1;
break;
case TIM_OCM_PWM2:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_PWM2;
break;
}
break;
case TIM_OC3:
TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR2_CC3S_MASK;
TIM_CCMR1(timer_peripheral) |= TIM_CCMR2_CC3S_OUT;
TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC3M_MASK;
switch (oc_mode) {
case TIM_OCM_FROZEN:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_FROZEN;
break;
case TIM_OCM_ACTIVE:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR2_OC3M_ACTIVE;
break;
case TIM_OCM_INACTIVE:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_INACTIVE;
break;
case TIM_OCM_TOGGLE:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_TOGGLE;
break;
case TIM_OCM_FORCE_LOW:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_FORCE_LOW;
break;
case TIM_OCM_FORCE_HIGH:
TIM_CCMR2(timer_peripheral) |=
TIM_CCMR2_OC3M_FORCE_HIGH;
break;
case TIM_OCM_PWM1:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_PWM1;
break;
case TIM_OCM_PWM2:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_PWM2;
break;
}
break;
case TIM_OC4:
TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR2_CC4S_MASK;
TIM_CCMR1(timer_peripheral) |= TIM_CCMR2_CC4S_OUT;
TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC4M_MASK;
switch (oc_mode) {
case TIM_OCM_FROZEN:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_FROZEN;
break;
case TIM_OCM_ACTIVE:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR2_OC4M_ACTIVE;
break;
case TIM_OCM_INACTIVE:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_INACTIVE;
break;
case TIM_OCM_TOGGLE:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_TOGGLE;
break;
case TIM_OCM_FORCE_LOW:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_FORCE_LOW;
break;
case TIM_OCM_FORCE_HIGH:
TIM_CCMR2(timer_peripheral) |=
TIM_CCMR2_OC4M_FORCE_HIGH;
break;
case TIM_OCM_PWM1:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_PWM1;
break;
case TIM_OCM_PWM2:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_PWM2;
break;
}
break;
case TIM_OC1N:
case TIM_OC2N:
case TIM_OC3N:
/* Ignoring as this option applies to the whole channel. */
break;
}
}
void timer_enable_oc_preload(u32 timer_peripheral, enum tim_oc_id oc_id)
{
switch (oc_id) {
case TIM_OC1:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1PE;
break;
case TIM_OC2:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2PE;
break;
case TIM_OC3:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3PE;
break;
case TIM_OC4:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4PE;
break;
case TIM_OC1N:
case TIM_OC2N:
case TIM_OC3N:
/* Ignoring as this option applies to the whole channel. */
break;
}
}
void timer_disable_oc_preload(u32 timer_peripheral, enum tim_oc_id oc_id)
{
switch (oc_id) {
case TIM_OC1:
TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC1PE;
break;
case TIM_OC2:
TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC2PE;
break;
case TIM_OC3:
TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC3PE;
break;
case TIM_OC4:
TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC4PE;
break;
case TIM_OC1N:
case TIM_OC2N:
case TIM_OC3N:
/* Ignoring as this option applies to the whole channel. */
break;
}
}
void timer_set_oc_polarity_high(u32 timer_peripheral, enum tim_oc_id oc_id)
{
switch (oc_id) {
case TIM_OC1:
TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC1P;
break;
case TIM_OC2:
TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC2P;
break;
case TIM_OC3:
TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC3P;
break;
case TIM_OC4:
TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC4P;
break;
case TIM_OC1N:
case TIM_OC2N:
case TIM_OC3N:
/* Ignoring as this option applies to TIM1 and TIM8 only. */
break;
}
/* Acting for TIM1 and TIM8 only from here onwards. */
if ((timer_peripheral != TIM1) && (timer_peripheral != TIM8))
return;
switch (oc_id) {
case TIM_OC1N:
TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC1NP;
break;
case TIM_OC2N:
TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC2NP;
break;
case TIM_OC3N:
TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC3NP;
break;
case TIM_OC1:
case TIM_OC2:
case TIM_OC3:
case TIM_OC4:
/* Ignoring as this option was already set above. */
break;
}
}
void timer_set_oc_polarity_low(u32 timer_peripheral, enum tim_oc_id oc_id)
{
switch (oc_id) {
case TIM_OC1:
TIM_CCER(timer_peripheral) |= TIM_CCER_CC1P;
break;
case TIM_OC2:
TIM_CCER(timer_peripheral) |= TIM_CCER_CC2P;
break;
case TIM_OC3:
TIM_CCER(timer_peripheral) |= TIM_CCER_CC3P;
break;
case TIM_OC4:
TIM_CCER(timer_peripheral) |= TIM_CCER_CC4P;
break;
case TIM_OC1N:
case TIM_OC2N:
case TIM_OC3N:
/* Ignoring as this option applies to TIM1 and TIM8 only. */
break;
}
/* Acting for TIM1 and TIM8 only from here onwards. */
if ((timer_peripheral != TIM1) && (timer_peripheral != TIM8))
return;
switch (oc_id) {
case TIM_OC1N:
TIM_CCER(timer_peripheral) |= TIM_CCER_CC1NP;
break;
case TIM_OC2N:
TIM_CCER(timer_peripheral) |= TIM_CCER_CC2NP;
break;
case TIM_OC3N:
TIM_CCER(timer_peripheral) |= TIM_CCER_CC3NP;
break;
case TIM_OC1:
case TIM_OC2:
case TIM_OC3:
case TIM_OC4:
/* Ignoring as this option was already set above. */
break;
}
}
void timer_enable_oc_output(u32 timer_peripheral, enum tim_oc_id oc_id)
{
switch (oc_id) {
case TIM_OC1:
TIM_CCER(timer_peripheral) |= TIM_CCER_CC1E;
break;
case TIM_OC2:
TIM_CCER(timer_peripheral) |= TIM_CCER_CC2E;
break;
case TIM_OC3:
TIM_CCER(timer_peripheral) |= TIM_CCER_CC3E;
break;
case TIM_OC4:
TIM_CCER(timer_peripheral) |= TIM_CCER_CC4E;
break;
case TIM_OC1N:
case TIM_OC2N:
case TIM_OC3N:
/* Ignoring as this option applies to TIM1 and TIM8 only. */
break;
}
/* Acting for TIM1 and TIM8 only from here onwards. */
if ((timer_peripheral != TIM1) && (timer_peripheral != TIM8))
return;
switch (oc_id) {
case TIM_OC1N:
TIM_CCER(timer_peripheral) |= TIM_CCER_CC1NE;
break;
case TIM_OC2N:
TIM_CCER(timer_peripheral) |= TIM_CCER_CC2NE;
break;
case TIM_OC3N:
TIM_CCER(timer_peripheral) |= TIM_CCER_CC3NE;
break;
case TIM_OC1:
case TIM_OC2:
case TIM_OC3:
case TIM_OC4:
/* Ignoring as this option was already set above. */
break;
}
}
void timer_disable_oc_output(u32 timer_peripheral, enum tim_oc_id oc_id)
{
switch (oc_id) {
case TIM_OC1:
TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC1E;
break;
case TIM_OC2:
TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC2E;
break;
case TIM_OC3:
TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC3E;
break;
case TIM_OC4:
TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC4E;
break;
case TIM_OC1N:
case TIM_OC2N:
case TIM_OC3N:
/* Ignoring as this option applies to TIM1 and TIM8 only. */
break;
}
/* Acting for TIM1 and TIM8 only from here onwards. */
if ((timer_peripheral != TIM1) && (timer_peripheral != TIM8))
return;
switch (oc_id) {
case TIM_OC1N:
TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC1NE;
break;
case TIM_OC2N:
TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC2NE;
break;
case TIM_OC3N:
TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC3NE;
break;
case TIM_OC1:
case TIM_OC2:
case TIM_OC3:
case TIM_OC4:
/* Ignoring as this option was already set above. */
break;
}
}
void timer_set_oc_idle_state_set(u32 timer_peripheral, enum tim_oc_id oc_id)
{
/* Acting for TIM1 and TIM8 only. */
if ((timer_peripheral != TIM1) && (timer_peripheral != TIM8))
return;
switch (oc_id) {
case TIM_OC1:
TIM_CR2(timer_peripheral) |= TIM_CR2_OIS1;
break;
case TIM_OC1N:
TIM_CR2(timer_peripheral) |= TIM_CR2_OIS1N;
break;
case TIM_OC2:
TIM_CR2(timer_peripheral) |= TIM_CR2_OIS2;
break;
case TIM_OC2N:
TIM_CR2(timer_peripheral) |= TIM_CR2_OIS2N;
break;
case TIM_OC3:
TIM_CR2(timer_peripheral) |= TIM_CR2_OIS3;
break;
case TIM_OC3N:
TIM_CR2(timer_peripheral) |= TIM_CR2_OIS3N;
break;
case TIM_OC4:
TIM_CR2(timer_peripheral) |= TIM_CR2_OIS4;
break;
}
}
void timer_set_oc_idle_state_unset(u32 timer_peripheral, enum tim_oc_id oc_id)
{
/* Acting for TIM1 and TIM8 only. */
if ((timer_peripheral != TIM1) && (timer_peripheral != TIM8))
return;
switch (oc_id) {
case TIM_OC1:
TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS1;
break;
case TIM_OC1N:
TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS1N;
break;
case TIM_OC2:
TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS2;
break;
case TIM_OC2N:
TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS2N;
break;
case TIM_OC3:
TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS3;
break;
case TIM_OC3N:
TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS3N;
break;
case TIM_OC4:
TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS4;
break;
}
}
void timer_set_oc_value(u32 timer_peripheral, enum tim_oc_id oc_id, u32 value)
{
switch (oc_id) {
case TIM_OC1:
TIM_CCR1(timer_peripheral) = value;
break;
case TIM_OC2:
TIM_CCR2(timer_peripheral) = value;
break;
case TIM_OC3:
TIM_CCR3(timer_peripheral) = value;
break;
case TIM_OC4:
TIM_CCR4(timer_peripheral) = value;
break;
case TIM_OC1N:
case TIM_OC2N:
case TIM_OC3N:
/* Ignoring as this option applies to the whole channel. */
break;
}
}
void timer_enable_break_main_output(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) |= TIM_BDTR_MOE;
}
void timer_disable_break_main_output(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_MOE;
}
void timer_enable_break_automatic_output(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) |= TIM_BDTR_AOE;
}
void timer_disable_break_automatic_output(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_AOE;
}
void timer_set_break_polarity_high(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) |= TIM_BDTR_BKP;
}
void timer_set_break_polarity_low(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_BKP;
}
void timer_enable_break(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) |= TIM_BDTR_BKE;
}
void timer_disable_break(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_BKE;
}
void timer_set_enabled_off_state_in_run_mode(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) |= TIM_BDTR_OSSR;
}
void timer_set_disabled_off_state_in_run_mode(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_OSSR;
}
void timer_set_enabled_off_state_in_idle_mode(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) |= TIM_BDTR_OSSI;
}
void timer_set_disabled_off_state_in_idle_mode(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_OSSI;
}
void timer_set_break_lock(u32 timer_peripheral, u32 lock)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) |= lock;
}
void timer_set_deadtime(u32 timer_peripheral, u32 deadtime)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) |= deadtime;
}
void timer_generate_event(u32 timer_peripheral, u32 event)
{
TIM_EGR(timer_peripheral) |= event;
}
u32 timer_get_counter(u32 timer_peripheral)
{
return TIM_CNT(timer_peripheral);
}
void timer_set_option(u32 timer_peripheral, u32 option)
{
if (timer_peripheral == TIM2) {
TIM_OR(timer_peripheral) &= ~TIM2_OR_ITR1_RMP_MASK;
TIM_OR(timer_peripheral) |= option;
} else if (timer_peripheral == TIM5) {
TIM_OR(timer_peripheral) &= ~TIM5_OR_TI4_RMP_MASK;
TIM_OR(timer_peripheral) |= option;
}
}

View File

@@ -1,336 +0,0 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Piotr Esden-Tempski <piotr@esden.net>
* Copyright (C) 2011 Fergus Noble <fergusnoble@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#define WEAK __attribute__ ((weak))
/* Symbols exported by the linker script(s): */
extern unsigned _data_loadaddr, _data, _edata, _ebss, _stack;
void main(void);
void reset_handler(void);
void blocking_handler(void);
void null_handler(void);
void WEAK reset_handler(void);
void WEAK nmi_handler(void);
void WEAK hard_fault_handler(void);
void WEAK mem_manage_handler(void);
void WEAK bus_fault_handler(void);
void WEAK usage_fault_handler(void);
void WEAK sv_call_handler(void);
void WEAK debug_monitor_handler(void);
void WEAK pend_sv_handler(void);
void WEAK sys_tick_handler(void);
void WEAK wwdg_isr(void);
void WEAK pvd_isr(void);
void WEAK tamp_stamp_isr(void);
void WEAK rtc_wkup_isr(void);
void WEAK flash_isr(void);
void WEAK rcc_isr(void);
void WEAK exti0_isr(void);
void WEAK exti1_isr(void);
void WEAK exti2_isr(void);
void WEAK exti3_isr(void);
void WEAK exti4_isr(void);
void WEAK dma1_stream0_isr(void);
void WEAK dma1_stream1_isr(void);
void WEAK dma1_stream2_isr(void);
void WEAK dma1_stream3_isr(void);
void WEAK dma1_stream4_isr(void);
void WEAK dma1_stream5_isr(void);
void WEAK dma1_stream6_isr(void);
void WEAK adc_isr(void);
void WEAK can1_tx_isr(void);
void WEAK can1_rx0_isr(void);
void WEAK can1_rx1_isr(void);
void WEAK can1_sce_isr(void);
void WEAK exti9_5_isr(void);
void WEAK tim1_brk_tim9_isr(void);
void WEAK tim1_up_tim10_isr(void);
void WEAK tim1_trg_com_tim11_isr(void);
void WEAK tim1_cc_isr(void);
void WEAK tim2_isr(void);
void WEAK tim3_isr(void);
void WEAK tim4_isr(void);
void WEAK i2c1_ev_isr(void);
void WEAK i2c1_er_isr(void);
void WEAK i2c2_ev_isr(void);
void WEAK i2c2_er_isr(void);
void WEAK spi1_isr(void);
void WEAK spi2_isr(void);
void WEAK usart1_isr(void);
void WEAK usart2_isr(void);
void WEAK usart3_isr(void);
void WEAK exti15_10_isr(void);
void WEAK rtc_alarm_isr(void);
void WEAK usb_fs_wkup_isr(void);
void WEAK tim8_brk_tim12_isr(void);
void WEAK tim8_up_tim13_isr(void);
void WEAK tim8_trg_com_tim14_isr(void);
void WEAK tim8_cc_isr(void);
void WEAK dma1_stream7_isr(void);
void WEAK fsmc_isr(void);
void WEAK sdio_isr(void);
void WEAK tim5_isr(void);
void WEAK spi3_isr(void);
void WEAK uart4_isr(void);
void WEAK uart5_isr(void);
void WEAK tim6_dac_isr(void);
void WEAK tim7_isr(void);
void WEAK dma2_stream0_isr(void);
void WEAK dma2_stream1_isr(void);
void WEAK dma2_stream2_isr(void);
void WEAK dma2_stream3_isr(void);
void WEAK dma2_stream4_isr(void);
void WEAK eth_isr(void);
void WEAK eth_wkup_isr(void);
void WEAK can2_tx_isr(void);
void WEAK can2_rx0_isr(void);
void WEAK can2_rx1_isr(void);
void WEAK can2_sce_isr(void);
void WEAK otg_fs_isr(void);
void WEAK dma2_stream5_isr(void);
void WEAK dma2_stream6_isr(void);
void WEAK dma2_stream7_isr(void);
void WEAK usart6_isr(void);
void WEAK i2c3_ev_isr(void);
void WEAK i2c3_er_isr(void);
void WEAK otg_hs_ep1_out_isr(void);
void WEAK otg_hs_ep1_in_isr(void);
void WEAK otg_hs_wkup_isr(void);
void WEAK otg_hs_isr(void);
void WEAK dcmi_isr(void);
void WEAK cryp_isr(void);
void WEAK hash_rng_isr(void);
__attribute__ ((section(".vectors")))
void (*const vector_table[]) (void) = {
(void *)&_stack,
reset_handler,
nmi_handler,
hard_fault_handler,
mem_manage_handler,
bus_fault_handler,
usage_fault_handler,
0, 0, 0, 0, /* Reserved */
sv_call_handler,
debug_monitor_handler,
0, /* Reserved */
pend_sv_handler,
sys_tick_handler,
wwdg_isr,
pvd_isr,
tamp_stamp_isr,
rtc_wkup_isr,
flash_isr,
rcc_isr,
exti0_isr,
exti1_isr,
exti2_isr,
exti3_isr,
exti4_isr,
dma1_stream0_isr,
dma1_stream1_isr,
dma1_stream2_isr,
dma1_stream3_isr,
dma1_stream4_isr,
dma1_stream5_isr,
dma1_stream6_isr,
adc_isr,
can1_tx_isr,
can1_rx0_isr,
can1_rx1_isr,
can1_sce_isr,
exti9_5_isr,
tim1_brk_tim9_isr,
tim1_up_tim10_isr,
tim1_trg_com_tim11_isr,
tim1_cc_isr,
tim2_isr,
tim3_isr,
tim4_isr,
i2c1_ev_isr,
i2c1_er_isr,
i2c2_ev_isr,
i2c2_er_isr,
spi1_isr,
spi2_isr,
usart1_isr,
usart2_isr,
usart3_isr,
exti15_10_isr,
rtc_alarm_isr,
usb_fs_wkup_isr,
tim8_brk_tim12_isr,
tim8_up_tim13_isr,
tim8_trg_com_tim14_isr,
tim8_cc_isr,
dma1_stream7_isr,
fsmc_isr,
sdio_isr,
tim5_isr,
spi3_isr,
uart4_isr,
uart5_isr,
tim6_dac_isr,
tim7_isr,
dma2_stream0_isr,
dma2_stream1_isr,
dma2_stream2_isr,
dma2_stream3_isr,
dma2_stream4_isr,
eth_isr,
eth_wkup_isr,
can2_tx_isr,
can2_rx0_isr,
can2_rx1_isr,
can2_sce_isr,
otg_fs_isr,
dma2_stream5_isr,
dma2_stream6_isr,
dma2_stream7_isr,
usart6_isr,
i2c3_ev_isr,
i2c3_er_isr,
otg_hs_ep1_out_isr,
otg_hs_ep1_in_isr,
otg_hs_wkup_isr,
otg_hs_isr,
dcmi_isr,
cryp_isr,
hash_rng_isr,
};
void reset_handler(void)
{
volatile unsigned *src, *dest;
__asm__("MSR msp, %0" : : "r"(&_stack));
for (src = &_data_loadaddr, dest = &_data; dest < &_edata; src++, dest++)
*dest = *src;
while (dest < &_ebss)
*dest++ = 0;
/* Call the application's entry point. */
main();
}
void blocking_handler(void)
{
while (1) ;
}
void null_handler(void)
{
/* Do nothing. */
}
#pragma weak nmi_handler = null_handler
#pragma weak hard_fault_handler = blocking_handler
#pragma weak mem_manage_handler = blocking_handler
#pragma weak bus_fault_handler = blocking_handler
#pragma weak usage_fault_handler = blocking_handler
#pragma weak sv_call_handler = null_handler
#pragma weak debug_monitor_handler = null_handler
#pragma weak pend_sv_handler = null_handler
#pragma weak sys_tick_handler = null_handler
#pragma weak wwdg_isr = null_handler
#pragma weak pvd_isr = null_handler
#pragma weak tamp_stamp_isr = null_handler
#pragma weak rtc_wkup_isr = null_handler
#pragma weak flash_isr = null_handler
#pragma weak rcc_isr = null_handler
#pragma weak exti0_isr = null_handler
#pragma weak exti1_isr = null_handler
#pragma weak exti2_isr = null_handler
#pragma weak exti3_isr = null_handler
#pragma weak exti4_isr = null_handler
#pragma weak dma1_stream0_isr = null_handler
#pragma weak dma1_stream1_isr = null_handler
#pragma weak dma1_stream2_isr = null_handler
#pragma weak dma1_stream3_isr = null_handler
#pragma weak dma1_stream4_isr = null_handler
#pragma weak dma1_stream5_isr = null_handler
#pragma weak dma1_stream6_isr = null_handler
#pragma weak adc_isr = null_handler
#pragma weak can1_tx_isr = null_handler
#pragma weak can1_rx0_isr = null_handler
#pragma weak can1_rx1_isr = null_handler
#pragma weak can1_sce_isr = null_handler
#pragma weak exti9_5_isr = null_handler
#pragma weak tim1_brk_tim9_isr = null_handler
#pragma weak tim1_up_tim10_isr = null_handler
#pragma weak tim1_trg_com_tim11_isr = null_handler
#pragma weak tim1_cc_isr = null_handler
#pragma weak tim2_isr = null_handler
#pragma weak tim3_isr = null_handler
#pragma weak tim4_isr = null_handler
#pragma weak i2c1_ev_isr = null_handler
#pragma weak i2c1_er_isr = null_handler
#pragma weak i2c2_ev_isr = null_handler
#pragma weak i2c2_er_isr = null_handler
#pragma weak spi1_isr = null_handler
#pragma weak spi2_isr = null_handler
#pragma weak usart1_isr = null_handler
#pragma weak usart2_isr = null_handler
#pragma weak usart3_isr = null_handler
#pragma weak exti15_10_isr = null_handler
#pragma weak rtc_alarm_isr = null_handler
#pragma weak usb_fs_wkup_isr = null_handler
#pragma weak tim8_brk_tim12_isr = null_handler
#pragma weak tim8_up_tim13_isr = null_handler
#pragma weak tim8_trg_com_tim14_isr = null_handler
#pragma weak tim8_cc_isr = null_handler
#pragma weak dma1_stream7_isr = null_handler
#pragma weak fsmc_isr = null_handler
#pragma weak sdio_isr = null_handler
#pragma weak tim5_isr = null_handler
#pragma weak spi3_isr = null_handler
#pragma weak uart4_isr = null_handler
#pragma weak uart5_isr = null_handler
#pragma weak tim6_dac_isr = null_handler
#pragma weak tim7_isr = null_handler
#pragma weak dma2_stream0_isr = null_handler
#pragma weak dma2_stream1_isr = null_handler
#pragma weak dma2_stream2_isr = null_handler
#pragma weak dma2_stream3_isr = null_handler
#pragma weak dma2_stream4_isr = null_handler
#pragma weak eth_isr = null_handler
#pragma weak eth_wkup_isr = null_handler
#pragma weak can2_tx_isr = null_handler
#pragma weak can2_rx0_isr = null_handler
#pragma weak can2_rx1_isr = null_handler
#pragma weak can2_sce_isr = null_handler
#pragma weak otg_fs_isr = null_handler
#pragma weak dma2_stream5_isr = null_handler
#pragma weak dma2_stream6_isr = null_handler
#pragma weak dma2_stream7_isr = null_handler
#pragma weak usart6_isr = null_handler
#pragma weak i2c3_ev_isr = null_handler
#pragma weak i2c3_er_isr = null_handler
#pragma weak otg_hs_ep1_out_isr = null_handler
#pragma weak otg_hs_ep1_in_isr = null_handler
#pragma weak otg_hs_wkup_isr = null_handler
#pragma weak otg_hs_isr = null_handler
#pragma weak dcmi_isr = null_handler
#pragma weak cryp_isr = null_handler
#pragma weak hash_rng_isr = null_handler

View File

@@ -29,10 +29,10 @@ CFLAGS = -Os -g -Wall -Wextra -I../../../include -fno-common \
-ffunction-sections -fdata-sections -MD -DSTM32F4
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS = vector.o rcc.o gpio.o usart.o spi.o flash.o nvic.o \
i2c.o systick.o exti.o scb.o pwr.o timer.o \
usb.o usb_standard.o usb_control.o usb_f107.o \
assert.o
OBJS = rcc.o gpio2.o usart.o spi.o flash.o \
i2c.o exti2.o pwr.o timer.o \
usb.o usb_standard.o usb_control.o usb_fx07_common.o usb_f107.o \
usb_f207.o adc.o dma.o
VPATH += ../../usb:../:../../cm3

1027
lib/stm32/f4/adc.c Normal file

File diff suppressed because it is too large Load Diff

772
lib/stm32/f4/dma.c Normal file
View File

@@ -0,0 +1,772 @@
/** @defgroup STM32F4xx-dma-file DMA
@ingroup STM32F4xx
@brief <b>libopencm3 STM32F4xx DMA Controller</b>
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2012 Ken Sarkies <ksarkies@internode.on.net>
@date 18 October 2012
This library supports the DMA Control System in the STM32F2 and STM32F4
series of ARM Cortex Microcontrollers by ST Microelectronics.
Up to two DMA controllers are supported each with 8 streams, and each stream
having up to 8 channels hardware dedicated to various peripheral DMA signals.
DMA transfers can be configured to occur between peripheral and memory in
either direction, and memory to memory. Peripheral to peripheral transfer
is not supported. Circular mode transfers are also supported in transfers
involving a peripheral. An arbiter is provided to resolve priority DMA
requests. Transfers can be made with 8, 16 or 32 bit words.
Each stream has access to a 4 word deep FIFO and can use double buffering
by means of two memory pointers. When using the FIFO it is possible to
configure transfers to occur in indivisible bursts.
It is also possible to select a peripheral to control the flow of data rather
than the DMA controller. This limits the functionality but is udeful when the
number of transfers is unknown.
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Ken Sarkies <ksarkies@internode.on.net>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/stm32/f4/dma.h>
/*-----------------------------------------------------------------------------*/
/** @brief DMA Stream Reset
The specified stream is disabled and configuration registers are cleared.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_stream_reset(u32 dma, u8 stream)
{
/* Disable stream (must be done before register is otherwise changed). */
DMA_SCR(dma, stream) &= ~DMA_SCR_EN;
/* Reset all config bits. */
DMA_SCR(dma, stream) = 0;
/* Reset data transfer number. */
DMA_SNDTR(dma, stream) = 0;
/* Reset peripheral and memory addresses. */
DMA_SPAR(dma, stream) = 0;
DMA_SM0AR(dma, stream) = 0;
DMA_SM1AR(dma, stream) = 0;
/* This is the default setting */
DMA_SFCR(dma, stream) = 0x21;
/* Reset all stream interrupt flags using the interrupt flag clear register. */
u32 mask = DMA_ISR_MASK(stream);
if (stream < 4)
{
DMA_LIFCR(dma) |= mask;
}
else
{
DMA_HIFCR(dma) |= mask;
}
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Stream Clear Interrupt Flag
The interrupt flag for the stream is cleared. More than one interrupt for the
same stream may be cleared by using the logical OR of the interrupt flags.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@param[in] interrupts unsigned int32. Logical OR of interrupt numbers: @ref dma_if_offset
*/
void dma_clear_interrupt_flags(u32 dma, u8 stream, u32 interrupts)
{
/* Get offset to interrupt flag location in stream field */
u32 flags = (interrupts << DMA_ISR_OFFSET(stream));
/* First four streams are in low register. Flag clear must be set then reset. */
if (stream < 4)
{
DMA_LIFCR(dma) = flags;
}
else
{
DMA_HIFCR(dma) = flags;
}
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Stream Read Interrupt Flag
The interrupt flag for the stream is returned.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@param[in] interrupt unsigned int32. Interrupt number: @ref dma_if_offset
@returns bool interrupt flag is set.
*/
bool dma_get_interrupt_flag(u32 dma, u8 stream, u32 interrupt)
{
/* get offset to interrupt flag location in stream field.
Assumes stream and interrupt parameters are integers */
u32 flag = (interrupt << DMA_ISR_OFFSET(stream));
/* First four streams are in low register */
if (stream < 4) return ((DMA_LISR(dma) & flag) > 0);
else return ((DMA_HISR(dma) & flag) > 0);
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Stream Enable Transfer Direction
Set peripheral to memory, memory to peripheral or memory to memory. If memory
to memory mode is selected, circular mode and double buffer modes are disabled.
Ensure that these modes are not enabled at a later time.
Ensure that the stream is disabled otherwise the setting will not be changed.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@param[in] direction unsigned int32. Data transfer direction @ref dma_st_dir
*/
void dma_set_transfer_mode(u32 dma, u8 stream, u32 direction)
{
u32 reg32 = (DMA_SCR(dma, stream) & ~DMA_SCR_DIR_MASK);
/* Disable circular and double buffer modes if memory to memory transfers
are in effect (Direct Mode is automatically disabled by hardware) */
if (direction == DMA_SCR_DIR_MEM2MEM)
{
reg32 &= ~(DMA_SCR_CIRC | DMA_SCR_DBM);
}
DMA_SCR(dma, stream) = (reg32 | direction);
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Stream Set Priority
Stream Priority has four levels: low to very high. This has precedence over the
hardware priority. In the event of equal software priority the lower numbered
stream has priority.
Ensure that the stream is disabled otherwise the setting will not be changed.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@param[in] prio unsigned int32. Priority level @ref dma_st_pri.
*/
void dma_set_priority(u32 dma, u8 stream, u32 prio)
{
DMA_SCR(dma, stream) &= ~(DMA_SCR_PL_MASK);
DMA_SCR(dma, stream) |= prio;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Stream Set Memory Word Width
Set the memory word width 8 bits, 16 bits, or 32 bits. Refer to datasheet for
alignment information if the source and destination widths do not match.
Ensure that the stream is disabled otherwise the setting will not be changed.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@param[in] mem_size unsigned int32. Memory word width @ref dma_st_memwidth.
*/
void dma_set_memory_size(u32 dma, u8 stream, u32 mem_size)
{
DMA_SCR(dma, stream) &= ~(DMA_SCR_MSIZE_MASK);
DMA_SCR(dma, stream) |= mem_size;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Stream Set Peripheral Word Width
Set the peripheral word width 8 bits, 16 bits, or 32 bits. Refer to datasheet for
alignment information if the source and destination widths do not match, or
if the peripheral does not support byte or half-word writes.
Ensure that the stream is disabled otherwise the setting will not be changed.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@param[in] peripheral_size unsigned int32. Peripheral word width @ref dma_st_perwidth.
*/
void dma_set_peripheral_size(u32 dma, u8 stream, u32 peripheral_size)
{
DMA_SCR(dma, stream) &= ~(DMA_SCR_PSIZE_MASK);
DMA_SCR(dma, stream) |= peripheral_size;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Stream Enable Memory Increment after Transfer
Following each transfer the current memory address is incremented by
1, 2 or 4 depending on the data size set in @ref dma_set_memory_size. The
value held by the base memory address register is unchanged.
Ensure that the stream is disabled otherwise the setting will not be changed.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_enable_memory_increment_mode(u32 dma, u8 stream)
{
DMA_SCR(dma, stream) |= DMA_SCR_MINC;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Channel Disable Memory Increment after Transfer
Ensure that the stream is disabled otherwise the setting will not be changed.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_disable_memory_increment_mode(u32 dma, u8 stream)
{
DMA_SCR(dma, stream) &= ~DMA_SCR_MINC;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Channel Enable Variable Sized Peripheral Increment after Transfer
Following each transfer the current peripheral address is incremented by
1, 2 or 4 depending on the data size set in @ref dma_set_peripheral_size. The
value held by the base peripheral address register is unchanged.
Ensure that the stream is disabled otherwise the setting will not be changed.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_enable_peripheral_increment_mode(u32 dma, u8 stream)
{
u32 reg32 = (DMA_SCR(dma, stream) | DMA_SCR_PINC);
DMA_SCR(dma, stream) = (reg32 & ~DMA_SCR_PINCOS);
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Channel Disable Peripheral Increment after Transfer
Ensure that the stream is disabled otherwise the setting will not be changed.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_disable_peripheral_increment_mode(u32 dma, u8 stream)
{
DMA_SCR(dma, stream) &= ~DMA_SCR_PINC;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Channel Enable Fixed Sized Peripheral Increment after Transfer
Following each transfer the current peripheral address is incremented by
4 regardless of the data size. The value held by the base peripheral address
register is unchanged.
Ensure that the stream is disabled otherwise the setting will not be changed.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_enable_fixed_peripheral_increment_mode(u32 dma, u8 stream)
{
DMA_SCR(dma, stream) |= (DMA_SCR_PINC | DMA_SCR_PINCOS);
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Stream Enable Memory Circular Mode
After the number of bytes/words to be transferred has been completed, the
original transfer block size, memory and peripheral base addresses are
reloaded and the process repeats.
Ensure that the stream is disabled otherwise the setting will not be changed.
@note This cannot be used with memory to memory mode. It is disabled
automatically if the peripheral is selected as the flow controller.
It is enabled automatically if double buffered mode is selected.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_enable_circular_mode(u32 dma, u8 stream)
{
DMA_SCR(dma, stream) |= DMA_SCR_CIRC;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Stream Channel Select
Associate an input channel to the stream. Not every channel is allocated to a
hardware DMA request signal. The allocations for each stream are given in the
STM32F4 Reference Manual.
Ensure that the stream is disabled otherwise the setting will not be changed.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@param[in] channel unsigned int8. Channel selection @ref dma_ch_sel
*/
void dma_channel_select(u32 dma, u8 stream, u32 channel)
{
DMA_SCR(dma, stream) |= channel;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Stream Set Memory Burst Configuration
Set the memory burst type to none, 4 8 or 16 word length. This is forced to none
if direct mode is used.
Ensure that the stream is disabled otherwise the setting will not be changed.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@param[in] burst unsigned int8. Memory Burst selection @ref dma_mburst
*/
void dma_set_memory_burst(u32 dma, u8 stream, u32 burst)
{
u32 reg32 = (DMA_SCR(dma, stream) & ~DMA_SCR_MBURST_MASK);
DMA_SCR(dma, stream) = (reg32 | burst);
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Stream Set Peripheral Burst Configuration
Set the memory burst type to none, 4 8 or 16 word length. This is forced to none
if direct mode is used.
Ensure that the stream is disabled otherwise the setting will not be changed.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@param[in] burst unsigned int8. Peripheral Burst selection @ref dma_pburst
*/
void dma_set_peripheral_burst(u32 dma, u8 stream, u32 burst)
{
u32 reg32 = (DMA_SCR(dma, stream) & ~DMA_SCR_PBURST_MASK);
DMA_SCR(dma, stream) = (reg32 | burst);
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Stream Set Initial Target Memory
In double buffered mode, set the target memory (M0 or M1) to be used for the first
transfer.
Ensure that the stream is disabled otherwise the setting will not be changed.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@param[in] memory unsigned int8. Initial memory pointer to use: 0 or 1
*/
void dma_set_initial_target(u32 dma, u8 stream, u8 memory)
{
u32 reg32 = (DMA_SCR(dma, stream) & ~DMA_SCR_CT);
if (memory == 1) reg32 |= DMA_SCR_CT;
DMA_SCR(dma, stream) = reg32;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Stream Read Current Memory Target
In double buffer mode, return the current memory target (M0 or M1). It is possible
to update the memory pointer in the register that is <b> not </b> currently in
use. An attempt to change the register currently in use will cause the stream
to be disabled and the transfer error flag to be set.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@returns unsigned int8. Memory buffer in use: 0 or 1
*/
u8 dma_get_target(u32 dma, u8 stream)
{
if (DMA_SCR(dma, stream) & DMA_SCR_CT) return 1;
return 0;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Stream Enable Double Buffer Mode
Double buffer mode is used for memory to/from peripheral transfers only, and in
circular mode which is automatically enabled. Two memory buffers must be
established with pointers stored in the memory pointer registers.
Ensure that the stream is disabled otherwise the setting will not be changed.
@note This cannot be used with memory to memory mode.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_enable_double_buffer_mode(u32 dma, u8 stream)
{
DMA_SCR(dma, stream) |= DMA_SCR_DBM;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Stream Set Peripheral Flow Control
Set the peripheral to control DMA flow. Useful when the number of transfers is
unknown. This is forced off when memory to memory mode is selected.
Ensure that the stream is disabled otherwise the setting will not be changed.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_set_peripheral_flow_control(u32 dma, u8 stream)
{
DMA_SCR(dma, stream) |= DMA_SCR_PFCTRL;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Stream Set DMA Flow Control
Set the DMA controller to control DMA flow. This is the default.
Ensure that the stream is disabled otherwise the setting will not be changed.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_set_dma_flow_control(u32 dma, u8 stream)
{
DMA_SCR(dma, stream) &= ~DMA_SCR_PFCTRL;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Stream Enable Interrupt on Transfer Error
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_enable_transfer_error_interrupt(u32 dma, u8 stream)
{
dma_clear_interrupt_flags(dma, stream, DMA_ISR_TEIF);
DMA_SCR(dma, stream) |= DMA_SCR_TEIE;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Stream Disable Interrupt on Transfer Error
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_disable_transfer_error_interrupt(u32 dma, u8 stream)
{
DMA_SCR(dma, stream) &= ~DMA_SCR_TEIE;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Stream Enable Interrupt on Transfer Half Complete
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_enable_half_transfer_interrupt(u32 dma, u8 stream)
{
dma_clear_interrupt_flags(dma, stream, DMA_ISR_HTIF);
DMA_SCR(dma, stream) |= DMA_SCR_HTIE;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Stream Disable Interrupt on Transfer Half Complete
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_disable_half_transfer_interrupt(u32 dma, u8 stream)
{
DMA_SCR(dma, stream) &= ~DMA_SCR_HTIE;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Stream Enable Interrupt on Transfer Complete
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_enable_transfer_complete_interrupt(u32 dma, u8 stream)
{
dma_clear_interrupt_flags(dma, stream, DMA_ISR_TCIF);
DMA_SCR(dma, stream) |= DMA_SCR_TCIE;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Stream Disable Interrupt on Transfer Complete
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_disable_transfer_complete_interrupt(u32 dma, u8 stream)
{
DMA_SCR(dma, stream) &= ~DMA_SCR_TCIE;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Stream Enable Interrupt on Direct Mode Error
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_enable_direct_mode_error_interrupt(u32 dma, u8 stream)
{
dma_clear_interrupt_flags(dma, stream, DMA_ISR_DMEIF);
DMA_SCR(dma, stream) |= DMA_SCR_DMEIE;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Stream Disable Interrupt on Direct Mode Error
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_disable_direct_mode_error_interrupt(u32 dma, u8 stream)
{
DMA_SCR(dma, stream) &= ~DMA_SCR_DMEIE;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Enable Interrupt on FIFO Error
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_enable_fifo_error_interrupt(u32 dma, u8 stream)
{
dma_clear_interrupt_flags(dma, stream, DMA_ISR_FEIF);
DMA_SFCR(dma, stream) |= DMA_FCR_FEIE;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Disable Interrupt on FIFO Error
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_disable_fifo_error_interrupt(u32 dma, u8 stream)
{
DMA_SFCR(dma, stream) &= ~DMA_FCR_FEIE;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Get FIFO Status
Status of FIFO (empty. full or partial filled states) is returned. This has no
meaning if direct mode is enabled (as the FIFO is not used).
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@returns u32 FIFO Status @ref dma_fifo_status
*/
u32 dma_fifo_status(u32 dma, u8 stream)
{
return (DMA_SFCR(dma, stream) & DMA_FCR_FS_MASK);
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Enable Direct Mode
Direct mode is the default. Data is transferred as soon as a DMA request is
received. The FIFO is not used. This must not be set when memory to memory
mode is selected.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_enable_direct_mode(u32 dma, u8 stream)
{
DMA_SFCR(dma, stream) &= ~DMA_FCR_DMDIS;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Enable FIFO Mode
Data is transferred via a FIFO.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_enable_fifo_mode(u32 dma, u8 stream)
{
DMA_SFCR(dma, stream) |= DMA_FCR_DMDIS;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Set FIFO Threshold
This is the filled level at which data is transferred out of the FIFO to the
destination.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@param[in] threshold unsigned int8. Threshold setting @ref dma_fifo_thresh
*/
void dma_set_fifo_threshold(u32 dma, u8 stream, u32 threshold)
{
u32 reg32 = (DMA_SFCR(dma, stream) & ~DMA_FCR_FTH_MASK);
DMA_SFCR(dma, stream) = (reg32 | threshold);
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Stream Enable
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_enable_stream(u32 dma, u8 stream)
{
DMA_SCR(dma, stream) |= DMA_SCR_EN;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Stream Disable
@note The DMA stream registers retain their values when the stream is disabled.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
*/
void dma_disable_stream(u32 dma, u8 stream)
{
DMA_SCR(dma, stream) &= ~DMA_SCR_EN;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Stream Set the Peripheral Address
Set the address of the peripheral register to or from which data is to be transferred.
Refer to the documentation for the specific peripheral.
@note The DMA stream must be disabled before setting this address. This function
has no effect if the stream is enabled.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@param[in] address unsigned int32. Peripheral Address.
*/
void dma_set_peripheral_address(u32 dma, u8 stream, u32 address)
{
if (!(DMA_SCR(dma, stream) & DMA_SCR_EN))
DMA_SPAR(dma, stream) = (u32) address;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Stream Set the Base Memory Address 0
Set the address pointer to the memory location for DMA transfers. The DMA stream
must normally be disabled before setting this address, however it is possible
to change this in double buffer mode when the current target is memory area 1
(see @ref dma_get_target).
This is the default base memory address used in direct mode.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@param[in] address unsigned int32. Memory Initial Address.
*/
void dma_set_memory_address(u32 dma, u8 stream, u32 address)
{
u32 reg32 = DMA_SCR(dma, stream);
if ( !(reg32 & DMA_SCR_EN) || ((reg32 & DMA_SCR_CT) && (reg32 & DMA_SCR_DBM)) )
DMA_SM0AR(dma, stream) = (u32) address;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Stream Set the Base Memory Address 1
Set the address pointer to the memory location for DMA transfers. The DMA stream
must normally be disabled before setting this address, however it is possible
to change this in double buffer mode when the current target is memory area 0
(see @ref dma_get_target).
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@param[in] address unsigned int32. Memory Initial Address.
*/
void dma_set_memory_address_1(u32 dma, u8 stream, u32 address)
{
u32 reg32 = DMA_SCR(dma, stream);
if ( !(reg32 & DMA_SCR_EN) || (!(reg32 & DMA_SCR_CT) && (reg32 & DMA_SCR_DBM)) )
DMA_SM1AR(dma, stream) = (u32) address;
}
/*-----------------------------------------------------------------------------*/
/** @brief DMA Stream Set the Transfer Block Size
@note The DMA stream must be disabled before setting this count value. The count
is not changed if the stream is enabled.
@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2
@param[in] stream unsigned int8. Stream number: @ref dma_st_number
@param[in] number unsigned int16. Number of data words to transfer (65535 maximum).
*/
void dma_set_number_of_data(u32 dma, u8 stream, u16 number)
{
DMA_SNDTR(dma, stream) = number;
}
/**@}*/

View File

@@ -1,146 +0,0 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Mark Butler <mbutler@physics.otago.ac.nz>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/stm32/exti.h>
#include <libopencm3/stm32/f4/syscfg.h>
#include <libopencm3/stm32/f4/gpio.h>
void exti_set_trigger(u32 extis, exti_trigger_type trig)
{
switch (trig) {
case EXTI_TRIGGER_RISING:
EXTI_RTSR |= extis;
EXTI_FTSR &= ~extis;
break;
case EXTI_TRIGGER_FALLING:
EXTI_RTSR &= ~extis;
EXTI_FTSR |= extis;
break;
case EXTI_TRIGGER_BOTH:
EXTI_RTSR |= extis;
EXTI_FTSR |= extis;
break;
}
}
void exti_enable_request(u32 extis)
{
/* Enable interrupts. */
EXTI_IMR |= extis;
/* Enable events. */
EXTI_EMR |= extis;
}
void exti_disable_request(u32 extis)
{
/* Disable interrupts. */
EXTI_IMR &= ~extis;
/* Disable events. */
EXTI_EMR &= ~extis;
}
/*
* Reset the interrupt request by writing a 1 to the corresponding
* pending bit register.
*/
void exti_reset_request(u32 extis)
{
EXTI_PR = extis;
}
/*
* Remap an external interrupt line to the corresponding pin on the
* specified GPIO port.
*
* TODO: This could be rewritten in fewer lines of code.
*/
void exti_select_source(u32 exti, u32 gpioport)
{
u8 shift, bits;
shift = bits = 0;
switch (exti) {
case EXTI0:
case EXTI4:
case EXTI8:
case EXTI12:
shift = 0;
break;
case EXTI1:
case EXTI5:
case EXTI9:
case EXTI13:
shift = 4;
break;
case EXTI2:
case EXTI6:
case EXTI10:
case EXTI14:
shift = 8;
break;
case EXTI3:
case EXTI7:
case EXTI11:
case EXTI15:
shift = 12;
break;
}
switch (gpioport) {
case GPIOA:
bits = 0xf;
break;
case GPIOB:
bits = 0xe;
break;
case GPIOC:
bits = 0xd;
break;
case GPIOD:
bits = 0xc;
break;
case GPIOE:
bits = 0xb;
break;
case GPIOF:
bits = 0xa;
break;
case GPIOG:
bits = 0x9;
break;
}
/* Ensure that only valid EXTI lines are used. */
if (exti < EXTI4) {
SYSCFG_EXTICR1 &= ~(0x000F << shift);
SYSCFG_EXTICR1 |= (~bits << shift);
} else if (exti < EXTI8) {
SYSCFG_EXTICR2 &= ~(0x000F << shift);
SYSCFG_EXTICR2 |= (~bits << shift);
} else if (exti < EXTI12) {
SYSCFG_EXTICR3 &= ~(0x000F << shift);
SYSCFG_EXTICR3 |= (~bits << shift);
} else if (exti < EXTI16) {
SYSCFG_EXTICR4 &= ~(0x000F << shift);
SYSCFG_EXTICR4 |= (~bits << shift);
}
}

View File

@@ -1,928 +0,0 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Edward Cheeseman <evbuilder@users.sourceforge.org>
* Copyright (C) 2011 Stephen Caudle <scaudle@doceme.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Basic TIMER handling API.
*
* Examples:
* timer_set_mode(TIM1, TIM_CR1_CKD_CK_INT_MUL_2,
* TIM_CR1_CMS_CENTRE_3, TIM_CR1_DIR_UP);
*/
#include <libopencm3/stm32/f4/timer.h>
#include <libopencm3/stm32/f4/rcc.h>
void timer_reset(u32 timer_peripheral)
{
switch (timer_peripheral) {
case TIM1:
rcc_peripheral_reset(&RCC_APB2RSTR, RCC_APB2RSTR_TIM1RST);
rcc_peripheral_clear_reset(&RCC_APB2RSTR, RCC_APB2RSTR_TIM1RST);
break;
case TIM2:
rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM2RST);
rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM2RST);
break;
case TIM3:
rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM3RST);
rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM3RST);
break;
case TIM4:
rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM4RST);
rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM4RST);
break;
case TIM5:
rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM5RST);
rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM5RST);
break;
case TIM6:
rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM6RST);
rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM6RST);
break;
case TIM7:
rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM7RST);
rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM7RST);
break;
case TIM8:
rcc_peripheral_reset(&RCC_APB2RSTR, RCC_APB2RSTR_TIM8RST);
rcc_peripheral_clear_reset(&RCC_APB2RSTR, RCC_APB2RSTR_TIM8RST);
break;
/* These timers are not supported in libopencm3 yet */
/*
case TIM9:
rcc_peripheral_reset(&RCC_APB2RSTR, RCC_APB2RSTR_TIM9RST);
rcc_peripheral_clear_reset(&RCC_APB2RSTR, RCC_APB2RSTR_TIM9RST);
break;
case TIM10:
rcc_peripheral_reset(&RCC_APB2RSTR, RCC_APB2RSTR_TIM10RST);
rcc_peripheral_clear_reset(&RCC_APB2RSTR, RCC_APB2RSTR_TIM10RST);
break;
case TIM11:
rcc_peripheral_reset(&RCC_APB2RSTR, RCC_APB2RSTR_TIM11RST);
rcc_peripheral_clear_reset(&RCC_APB2RSTR, RCC_APB2RSTR_TIM11RST);
break;
case TIM12:
rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM12RST);
rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM12RST);
break;
case TIM13:
rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM13RST);
rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM13RST);
break;
case TIM14:
rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM14RST);
rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_TIM14RST);
break;
*/
}
}
void timer_enable_irq(u32 timer_peripheral, u32 irq)
{
TIM_DIER(timer_peripheral) |= irq;
}
void timer_disable_irq(u32 timer_peripheral, u32 irq)
{
TIM_DIER(timer_peripheral) &= ~irq;
}
bool timer_get_flag(u32 timer_peripheral, u32 flag)
{
if (((TIM_SR(timer_peripheral) & flag) != 0) &&
((TIM_DIER(timer_peripheral) & flag) != 0)) {
return true;
}
return false;
}
void timer_clear_flag(u32 timer_peripheral, u32 flag)
{
TIM_SR(timer_peripheral) &= ~flag;
}
void timer_set_mode(u32 timer_peripheral, u32 clock_div,
u32 alignment, u32 direction)
{
u32 cr1;
cr1 = TIM_CR1(timer_peripheral);
cr1 &= ~(TIM_CR1_CKD_CK_INT_MASK | TIM_CR1_CMS_MASK | TIM_CR1_DIR_DOWN);
cr1 |= clock_div | alignment | direction;
TIM_CR1(timer_peripheral) = cr1;
}
void timer_set_clock_division(u32 timer_peripheral, u32 clock_div)
{
clock_div &= TIM_CR1_CKD_CK_INT_MASK;
TIM_CR1(timer_peripheral) &= ~TIM_CR1_CKD_CK_INT_MASK;
TIM_CR1(timer_peripheral) |= clock_div;
}
void timer_enable_preload(u32 timer_peripheral)
{
TIM_CR1(timer_peripheral) |= TIM_CR1_ARPE;
}
void timer_disable_preload(u32 timer_peripheral)
{
TIM_CR1(timer_peripheral) &= ~TIM_CR1_ARPE;
}
void timer_set_alignment(u32 timer_peripheral, u32 alignment)
{
alignment &= TIM_CR1_CMS_MASK;
TIM_CR1(timer_peripheral) &= ~TIM_CR1_CMS_MASK;
TIM_CR1(timer_peripheral) |= alignment;
}
void timer_direction_up(u32 timer_peripheral)
{
TIM_CR1(timer_peripheral) &= ~TIM_CR1_DIR_DOWN;
}
void timer_direction_down(u32 timer_peripheral)
{
TIM_CR1(timer_peripheral) |= TIM_CR1_DIR_DOWN;
}
void timer_one_shot_mode(u32 timer_peripheral)
{
TIM_CR1(timer_peripheral) |= TIM_CR1_OPM;
}
void timer_continuous_mode(u32 timer_peripheral)
{
TIM_CR1(timer_peripheral) &= ~TIM_CR1_OPM;
}
void timer_update_on_any(u32 timer_peripheral)
{
TIM_CR1(timer_peripheral) &= ~TIM_CR1_URS;
}
void timer_update_on_overflow(u32 timer_peripheral)
{
TIM_CR1(timer_peripheral) |= TIM_CR1_URS;
}
void timer_enable_update_event(u32 timer_peripheral)
{
TIM_CR1(timer_peripheral) &= ~TIM_CR1_UDIS;
}
void timer_disable_update_event(u32 timer_peripheral)
{
TIM_CR1(timer_peripheral) |= TIM_CR1_UDIS;
}
void timer_enable_counter(u32 timer_peripheral)
{
TIM_CR1(timer_peripheral) |= TIM_CR1_CEN;
}
void timer_disable_counter(u32 timer_peripheral)
{
TIM_CR1(timer_peripheral) &= ~TIM_CR1_CEN;
}
void timer_set_output_idle_state(u32 timer_peripheral, u32 outputs)
{
TIM_CR2(timer_peripheral) |= outputs & TIM_CR2_OIS_MASK;
}
void timer_reset_output_idle_state(u32 timer_peripheral, u32 outputs)
{
TIM_CR2(timer_peripheral) &= ~(outputs & TIM_CR2_OIS_MASK);
}
void timer_set_ti1_ch123_xor(u32 timer_peripheral)
{
TIM_CR2(timer_peripheral) |= TIM_CR2_TI1S;
}
void timer_set_ti1_ch1(u32 timer_peripheral)
{
TIM_CR2(timer_peripheral) &= ~TIM_CR2_TI1S;
}
void timer_set_master_mode(u32 timer_peripheral, u32 mode)
{
TIM_CR2(timer_peripheral) &= ~TIM_CR2_MMS_MASK;
TIM_CR2(timer_peripheral) |= mode;
}
void timer_set_dma_on_compare_event(u32 timer_peripheral)
{
TIM_CR2(timer_peripheral) &= ~TIM_CR2_CCDS;
}
void timer_set_dma_on_update_event(u32 timer_peripheral)
{
TIM_CR2(timer_peripheral) |= TIM_CR2_CCDS;
}
void timer_enable_compare_control_update_on_trigger(u32 timer_peripheral)
{
TIM_CR2(timer_peripheral) |= TIM_CR2_CCUS;
}
void timer_disable_compare_control_update_on_trigger(u32 timer_peripheral)
{
TIM_CR2(timer_peripheral) &= ~TIM_CR2_CCUS;
}
void timer_enable_preload_complementry_enable_bits(u32 timer_peripheral)
{
TIM_CR2(timer_peripheral) |= TIM_CR2_CCPC;
}
void timer_disable_preload_complementry_enable_bits(u32 timer_peripheral)
{
TIM_CR2(timer_peripheral) &= ~TIM_CR2_CCPC;
}
void timer_set_prescaler(u32 timer_peripheral, u32 value)
{
TIM_PSC(timer_peripheral) = value;
}
void timer_set_repetition_counter(u32 timer_peripheral, u32 value)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_RCR(timer_peripheral) = value;
}
void timer_set_period(u32 timer_peripheral, u32 period)
{
TIM_ARR(timer_peripheral) = period;
}
void timer_enable_oc_clear(u32 timer_peripheral, enum tim_oc_id oc_id)
{
switch (oc_id) {
case TIM_OC1:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1CE;
break;
case TIM_OC2:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2CE;
break;
case TIM_OC3:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3CE;
break;
case TIM_OC4:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4CE;
break;
case TIM_OC1N:
case TIM_OC2N:
case TIM_OC3N:
/* Ignoring as fast enable only applies to the whole channel. */
break;
}
}
void timer_disable_oc_clear(u32 timer_peripheral, enum tim_oc_id oc_id)
{
switch (oc_id) {
case TIM_OC1:
TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC1CE;
break;
case TIM_OC2:
TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC2CE;
break;
case TIM_OC3:
TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC3CE;
break;
case TIM_OC4:
TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC4CE;
break;
case TIM_OC1N:
case TIM_OC2N:
case TIM_OC3N:
/* Ignoring as fast enable only applies to the whole channel. */
break;
}
}
void timer_set_oc_fast_mode(u32 timer_peripheral, enum tim_oc_id oc_id)
{
switch (oc_id) {
case TIM_OC1:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1FE;
break;
case TIM_OC2:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2FE;
break;
case TIM_OC3:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3FE;
break;
case TIM_OC4:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4FE;
break;
case TIM_OC1N:
case TIM_OC2N:
case TIM_OC3N:
/* Ignoring as fast enable only applies to the whole channel. */
break;
}
}
void timer_set_oc_slow_mode(u32 timer_peripheral, enum tim_oc_id oc_id)
{
switch (oc_id) {
case TIM_OC1:
TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC1FE;
break;
case TIM_OC2:
TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC2FE;
break;
case TIM_OC3:
TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC3FE;
break;
case TIM_OC4:
TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC4FE;
break;
case TIM_OC1N:
case TIM_OC2N:
case TIM_OC3N:
/* Ignoring as this option applies to the whole channel. */
break;
}
}
void timer_set_oc_mode(u32 timer_peripheral, enum tim_oc_id oc_id,
enum tim_oc_mode oc_mode)
{
switch (oc_id) {
case TIM_OC1:
TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_CC1S_MASK;
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_CC1S_OUT;
TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC1M_MASK;
switch (oc_mode) {
case TIM_OCM_FROZEN:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_FROZEN;
break;
case TIM_OCM_ACTIVE:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_ACTIVE;
break;
case TIM_OCM_INACTIVE:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_INACTIVE;
break;
case TIM_OCM_TOGGLE:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_TOGGLE;
break;
case TIM_OCM_FORCE_LOW:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_FORCE_LOW;
break;
case TIM_OCM_FORCE_HIGH:
TIM_CCMR1(timer_peripheral) |=
TIM_CCMR1_OC1M_FORCE_HIGH;
break;
case TIM_OCM_PWM1:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_PWM1;
break;
case TIM_OCM_PWM2:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1M_PWM2;
break;
}
break;
case TIM_OC2:
TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_CC2S_MASK;
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_CC2S_OUT;
TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC2M_MASK;
switch (oc_mode) {
case TIM_OCM_FROZEN:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_FROZEN;
break;
case TIM_OCM_ACTIVE:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_ACTIVE;
break;
case TIM_OCM_INACTIVE:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_INACTIVE;
break;
case TIM_OCM_TOGGLE:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_TOGGLE;
break;
case TIM_OCM_FORCE_LOW:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_FORCE_LOW;
break;
case TIM_OCM_FORCE_HIGH:
TIM_CCMR1(timer_peripheral) |=
TIM_CCMR1_OC2M_FORCE_HIGH;
break;
case TIM_OCM_PWM1:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_PWM1;
break;
case TIM_OCM_PWM2:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2M_PWM2;
break;
}
break;
case TIM_OC3:
TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR2_CC3S_MASK;
TIM_CCMR1(timer_peripheral) |= TIM_CCMR2_CC3S_OUT;
TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC3M_MASK;
switch (oc_mode) {
case TIM_OCM_FROZEN:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_FROZEN;
break;
case TIM_OCM_ACTIVE:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR2_OC3M_ACTIVE;
break;
case TIM_OCM_INACTIVE:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_INACTIVE;
break;
case TIM_OCM_TOGGLE:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_TOGGLE;
break;
case TIM_OCM_FORCE_LOW:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_FORCE_LOW;
break;
case TIM_OCM_FORCE_HIGH:
TIM_CCMR2(timer_peripheral) |=
TIM_CCMR2_OC3M_FORCE_HIGH;
break;
case TIM_OCM_PWM1:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_PWM1;
break;
case TIM_OCM_PWM2:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3M_PWM2;
break;
}
break;
case TIM_OC4:
TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR2_CC4S_MASK;
TIM_CCMR1(timer_peripheral) |= TIM_CCMR2_CC4S_OUT;
TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC4M_MASK;
switch (oc_mode) {
case TIM_OCM_FROZEN:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_FROZEN;
break;
case TIM_OCM_ACTIVE:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR2_OC4M_ACTIVE;
break;
case TIM_OCM_INACTIVE:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_INACTIVE;
break;
case TIM_OCM_TOGGLE:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_TOGGLE;
break;
case TIM_OCM_FORCE_LOW:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_FORCE_LOW;
break;
case TIM_OCM_FORCE_HIGH:
TIM_CCMR2(timer_peripheral) |=
TIM_CCMR2_OC4M_FORCE_HIGH;
break;
case TIM_OCM_PWM1:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_PWM1;
break;
case TIM_OCM_PWM2:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4M_PWM2;
break;
}
break;
case TIM_OC1N:
case TIM_OC2N:
case TIM_OC3N:
/* Ignoring as this option applies to the whole channel. */
break;
}
}
void timer_enable_oc_preload(u32 timer_peripheral, enum tim_oc_id oc_id)
{
switch (oc_id) {
case TIM_OC1:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC1PE;
break;
case TIM_OC2:
TIM_CCMR1(timer_peripheral) |= TIM_CCMR1_OC2PE;
break;
case TIM_OC3:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC3PE;
break;
case TIM_OC4:
TIM_CCMR2(timer_peripheral) |= TIM_CCMR2_OC4PE;
break;
case TIM_OC1N:
case TIM_OC2N:
case TIM_OC3N:
/* Ignoring as this option applies to the whole channel. */
break;
}
}
void timer_disable_oc_preload(u32 timer_peripheral, enum tim_oc_id oc_id)
{
switch (oc_id) {
case TIM_OC1:
TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC1PE;
break;
case TIM_OC2:
TIM_CCMR1(timer_peripheral) &= ~TIM_CCMR1_OC2PE;
break;
case TIM_OC3:
TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC3PE;
break;
case TIM_OC4:
TIM_CCMR2(timer_peripheral) &= ~TIM_CCMR2_OC4PE;
break;
case TIM_OC1N:
case TIM_OC2N:
case TIM_OC3N:
/* Ignoring as this option applies to the whole channel. */
break;
}
}
void timer_set_oc_polarity_high(u32 timer_peripheral, enum tim_oc_id oc_id)
{
switch (oc_id) {
case TIM_OC1:
TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC1P;
break;
case TIM_OC2:
TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC2P;
break;
case TIM_OC3:
TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC3P;
break;
case TIM_OC4:
TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC4P;
break;
case TIM_OC1N:
case TIM_OC2N:
case TIM_OC3N:
/* Ignoring as this option applies to TIM1 and TIM8 only. */
break;
}
/* Acting for TIM1 and TIM8 only from here onwards. */
if ((timer_peripheral != TIM1) && (timer_peripheral != TIM8))
return;
switch (oc_id) {
case TIM_OC1N:
TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC1NP;
break;
case TIM_OC2N:
TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC2NP;
break;
case TIM_OC3N:
TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC3NP;
break;
case TIM_OC1:
case TIM_OC2:
case TIM_OC3:
case TIM_OC4:
/* Ignoring as this option was already set above. */
break;
}
}
void timer_set_oc_polarity_low(u32 timer_peripheral, enum tim_oc_id oc_id)
{
switch (oc_id) {
case TIM_OC1:
TIM_CCER(timer_peripheral) |= TIM_CCER_CC1P;
break;
case TIM_OC2:
TIM_CCER(timer_peripheral) |= TIM_CCER_CC2P;
break;
case TIM_OC3:
TIM_CCER(timer_peripheral) |= TIM_CCER_CC3P;
break;
case TIM_OC4:
TIM_CCER(timer_peripheral) |= TIM_CCER_CC4P;
break;
case TIM_OC1N:
case TIM_OC2N:
case TIM_OC3N:
/* Ignoring as this option applies to TIM1 and TIM8 only. */
break;
}
/* Acting for TIM1 and TIM8 only from here onwards. */
if ((timer_peripheral != TIM1) && (timer_peripheral != TIM8))
return;
switch (oc_id) {
case TIM_OC1N:
TIM_CCER(timer_peripheral) |= TIM_CCER_CC1NP;
break;
case TIM_OC2N:
TIM_CCER(timer_peripheral) |= TIM_CCER_CC2NP;
break;
case TIM_OC3N:
TIM_CCER(timer_peripheral) |= TIM_CCER_CC3NP;
break;
case TIM_OC1:
case TIM_OC2:
case TIM_OC3:
case TIM_OC4:
/* Ignoring as this option was already set above. */
break;
}
}
void timer_enable_oc_output(u32 timer_peripheral, enum tim_oc_id oc_id)
{
switch (oc_id) {
case TIM_OC1:
TIM_CCER(timer_peripheral) |= TIM_CCER_CC1E;
break;
case TIM_OC2:
TIM_CCER(timer_peripheral) |= TIM_CCER_CC2E;
break;
case TIM_OC3:
TIM_CCER(timer_peripheral) |= TIM_CCER_CC3E;
break;
case TIM_OC4:
TIM_CCER(timer_peripheral) |= TIM_CCER_CC4E;
break;
case TIM_OC1N:
case TIM_OC2N:
case TIM_OC3N:
/* Ignoring as this option applies to TIM1 and TIM8 only. */
break;
}
/* Acting for TIM1 and TIM8 only from here onwards. */
if ((timer_peripheral != TIM1) && (timer_peripheral != TIM8))
return;
switch (oc_id) {
case TIM_OC1N:
TIM_CCER(timer_peripheral) |= TIM_CCER_CC1NE;
break;
case TIM_OC2N:
TIM_CCER(timer_peripheral) |= TIM_CCER_CC2NE;
break;
case TIM_OC3N:
TIM_CCER(timer_peripheral) |= TIM_CCER_CC3NE;
break;
case TIM_OC1:
case TIM_OC2:
case TIM_OC3:
case TIM_OC4:
/* Ignoring as this option was already set above. */
break;
}
}
void timer_disable_oc_output(u32 timer_peripheral, enum tim_oc_id oc_id)
{
switch (oc_id) {
case TIM_OC1:
TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC1E;
break;
case TIM_OC2:
TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC2E;
break;
case TIM_OC3:
TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC3E;
break;
case TIM_OC4:
TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC4E;
break;
case TIM_OC1N:
case TIM_OC2N:
case TIM_OC3N:
/* Ignoring as this option applies to TIM1 and TIM8 only. */
break;
}
/* Acting for TIM1 and TIM8 only from here onwards. */
if ((timer_peripheral != TIM1) && (timer_peripheral != TIM8))
return;
switch (oc_id) {
case TIM_OC1N:
TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC1NE;
break;
case TIM_OC2N:
TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC2NE;
break;
case TIM_OC3N:
TIM_CCER(timer_peripheral) &= ~TIM_CCER_CC3NE;
break;
case TIM_OC1:
case TIM_OC2:
case TIM_OC3:
case TIM_OC4:
/* Ignoring as this option was already set above. */
break;
}
}
void timer_set_oc_idle_state_set(u32 timer_peripheral, enum tim_oc_id oc_id)
{
/* Acting for TIM1 and TIM8 only. */
if ((timer_peripheral != TIM1) && (timer_peripheral != TIM8))
return;
switch (oc_id) {
case TIM_OC1:
TIM_CR2(timer_peripheral) |= TIM_CR2_OIS1;
break;
case TIM_OC1N:
TIM_CR2(timer_peripheral) |= TIM_CR2_OIS1N;
break;
case TIM_OC2:
TIM_CR2(timer_peripheral) |= TIM_CR2_OIS2;
break;
case TIM_OC2N:
TIM_CR2(timer_peripheral) |= TIM_CR2_OIS2N;
break;
case TIM_OC3:
TIM_CR2(timer_peripheral) |= TIM_CR2_OIS3;
break;
case TIM_OC3N:
TIM_CR2(timer_peripheral) |= TIM_CR2_OIS3N;
break;
case TIM_OC4:
TIM_CR2(timer_peripheral) |= TIM_CR2_OIS4;
break;
}
}
void timer_set_oc_idle_state_unset(u32 timer_peripheral, enum tim_oc_id oc_id)
{
/* Acting for TIM1 and TIM8 only. */
if ((timer_peripheral != TIM1) && (timer_peripheral != TIM8))
return;
switch (oc_id) {
case TIM_OC1:
TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS1;
break;
case TIM_OC1N:
TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS1N;
break;
case TIM_OC2:
TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS2;
break;
case TIM_OC2N:
TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS2N;
break;
case TIM_OC3:
TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS3;
break;
case TIM_OC3N:
TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS3N;
break;
case TIM_OC4:
TIM_CR2(timer_peripheral) &= ~TIM_CR2_OIS4;
break;
}
}
void timer_set_oc_value(u32 timer_peripheral, enum tim_oc_id oc_id, u32 value)
{
switch (oc_id) {
case TIM_OC1:
TIM_CCR1(timer_peripheral) = value;
break;
case TIM_OC2:
TIM_CCR2(timer_peripheral) = value;
break;
case TIM_OC3:
TIM_CCR3(timer_peripheral) = value;
break;
case TIM_OC4:
TIM_CCR4(timer_peripheral) = value;
break;
case TIM_OC1N:
case TIM_OC2N:
case TIM_OC3N:
/* Ignoring as this option applies to the whole channel. */
break;
}
}
void timer_enable_break_main_output(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) |= TIM_BDTR_MOE;
}
void timer_disable_break_main_output(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_MOE;
}
void timer_enable_break_automatic_output(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) |= TIM_BDTR_AOE;
}
void timer_disable_break_automatic_output(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_AOE;
}
void timer_set_break_polarity_high(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) |= TIM_BDTR_BKP;
}
void timer_set_break_polarity_low(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_BKP;
}
void timer_enable_break(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) |= TIM_BDTR_BKE;
}
void timer_disable_break(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_BKE;
}
void timer_set_enabled_off_state_in_run_mode(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) |= TIM_BDTR_OSSR;
}
void timer_set_disabled_off_state_in_run_mode(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_OSSR;
}
void timer_set_enabled_off_state_in_idle_mode(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) |= TIM_BDTR_OSSI;
}
void timer_set_disabled_off_state_in_idle_mode(u32 timer_peripheral)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) &= ~TIM_BDTR_OSSI;
}
void timer_set_break_lock(u32 timer_peripheral, u32 lock)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) |= lock;
}
void timer_set_deadtime(u32 timer_peripheral, u32 deadtime)
{
if ((timer_peripheral == TIM1) || (timer_peripheral == TIM8))
TIM_BDTR(timer_peripheral) |= deadtime;
}
void timer_generate_event(u32 timer_peripheral, u32 event)
{
TIM_EGR(timer_peripheral) |= event;
}
u32 timer_get_counter(u32 timer_peripheral)
{
return TIM_CNT(timer_peripheral);
}
void timer_set_option(u32 timer_peripheral, u32 option)
{
if (timer_peripheral == TIM2) {
TIM_OR(timer_peripheral) &= ~TIM2_OR_ITR1_RMP_MASK;
TIM_OR(timer_peripheral) |= option;
} else if (timer_peripheral == TIM5) {
TIM_OR(timer_peripheral) &= ~TIM5_OR_TI4_RMP_MASK;
TIM_OR(timer_peripheral) |= option;
}
}

View File

@@ -1,341 +0,0 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Piotr Esden-Tempski <piotr@esden.net>
* Copyright (C) 2011 Fergus Noble <fergusnoble@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/stm32/f4/scb.h>
#define WEAK __attribute__ ((weak))
/* Symbols exported by the linker script(s): */
extern unsigned _data_loadaddr, _data, _edata, _ebss, _stack;
void main(void);
void reset_handler(void);
void blocking_handler(void);
void null_handler(void);
void WEAK reset_handler(void);
void WEAK nmi_handler(void);
void WEAK hard_fault_handler(void);
void WEAK mem_manage_handler(void);
void WEAK bus_fault_handler(void);
void WEAK usage_fault_handler(void);
void WEAK sv_call_handler(void);
void WEAK debug_monitor_handler(void);
void WEAK pend_sv_handler(void);
void WEAK sys_tick_handler(void);
void WEAK wwdg_isr(void);
void WEAK pvd_isr(void);
void WEAK tamp_stamp_isr(void);
void WEAK rtc_wkup_isr(void);
void WEAK flash_isr(void);
void WEAK rcc_isr(void);
void WEAK exti0_isr(void);
void WEAK exti1_isr(void);
void WEAK exti2_isr(void);
void WEAK exti3_isr(void);
void WEAK exti4_isr(void);
void WEAK dma1_stream0_isr(void);
void WEAK dma1_stream1_isr(void);
void WEAK dma1_stream2_isr(void);
void WEAK dma1_stream3_isr(void);
void WEAK dma1_stream4_isr(void);
void WEAK dma1_stream5_isr(void);
void WEAK dma1_stream6_isr(void);
void WEAK adc_isr(void);
void WEAK can1_tx_isr(void);
void WEAK can1_rx0_isr(void);
void WEAK can1_rx1_isr(void);
void WEAK can1_sce_isr(void);
void WEAK exti9_5_isr(void);
void WEAK tim1_brk_tim9_isr(void);
void WEAK tim1_up_tim10_isr(void);
void WEAK tim1_trg_com_tim11_isr(void);
void WEAK tim1_cc_isr(void);
void WEAK tim2_isr(void);
void WEAK tim3_isr(void);
void WEAK tim4_isr(void);
void WEAK i2c1_ev_isr(void);
void WEAK i2c1_er_isr(void);
void WEAK i2c2_ev_isr(void);
void WEAK i2c2_er_isr(void);
void WEAK spi1_isr(void);
void WEAK spi2_isr(void);
void WEAK usart1_isr(void);
void WEAK usart2_isr(void);
void WEAK usart3_isr(void);
void WEAK exti15_10_isr(void);
void WEAK rtc_alarm_isr(void);
void WEAK usb_fs_wkup_isr(void);
void WEAK tim8_brk_tim12_isr(void);
void WEAK tim8_up_tim13_isr(void);
void WEAK tim8_trg_com_tim14_isr(void);
void WEAK tim8_cc_isr(void);
void WEAK dma1_stream7_isr(void);
void WEAK fsmc_isr(void);
void WEAK sdio_isr(void);
void WEAK tim5_isr(void);
void WEAK spi3_isr(void);
void WEAK uart4_isr(void);
void WEAK uart5_isr(void);
void WEAK tim6_dac_isr(void);
void WEAK tim7_isr(void);
void WEAK dma2_stream0_isr(void);
void WEAK dma2_stream1_isr(void);
void WEAK dma2_stream2_isr(void);
void WEAK dma2_stream3_isr(void);
void WEAK dma2_stream4_isr(void);
void WEAK eth_isr(void);
void WEAK eth_wkup_isr(void);
void WEAK can2_tx_isr(void);
void WEAK can2_rx0_isr(void);
void WEAK can2_rx1_isr(void);
void WEAK can2_sce_isr(void);
void WEAK otg_fs_isr(void);
void WEAK dma2_stream5_isr(void);
void WEAK dma2_stream6_isr(void);
void WEAK dma2_stream7_isr(void);
void WEAK usart6_isr(void);
void WEAK i2c3_ev_isr(void);
void WEAK i2c3_er_isr(void);
void WEAK otg_hs_ep1_out_isr(void);
void WEAK otg_hs_ep1_in_isr(void);
void WEAK otg_hs_wkup_isr(void);
void WEAK otg_hs_isr(void);
void WEAK dcmi_isr(void);
void WEAK cryp_isr(void);
void WEAK hash_rng_isr(void);
__attribute__ ((section(".vectors")))
void (*const vector_table[]) (void) = {
(void *)&_stack,
reset_handler,
nmi_handler,
hard_fault_handler,
mem_manage_handler,
bus_fault_handler,
usage_fault_handler,
0, 0, 0, 0, /* Reserved */
sv_call_handler,
debug_monitor_handler,
0, /* Reserved */
pend_sv_handler,
sys_tick_handler,
wwdg_isr,
pvd_isr,
tamp_stamp_isr,
rtc_wkup_isr,
flash_isr,
rcc_isr,
exti0_isr,
exti1_isr,
exti2_isr,
exti3_isr,
exti4_isr,
dma1_stream0_isr,
dma1_stream1_isr,
dma1_stream2_isr,
dma1_stream3_isr,
dma1_stream4_isr,
dma1_stream5_isr,
dma1_stream6_isr,
adc_isr,
can1_tx_isr,
can1_rx0_isr,
can1_rx1_isr,
can1_sce_isr,
exti9_5_isr,
tim1_brk_tim9_isr,
tim1_up_tim10_isr,
tim1_trg_com_tim11_isr,
tim1_cc_isr,
tim2_isr,
tim3_isr,
tim4_isr,
i2c1_ev_isr,
i2c1_er_isr,
i2c2_ev_isr,
i2c2_er_isr,
spi1_isr,
spi2_isr,
usart1_isr,
usart2_isr,
usart3_isr,
exti15_10_isr,
rtc_alarm_isr,
usb_fs_wkup_isr,
tim8_brk_tim12_isr,
tim8_up_tim13_isr,
tim8_trg_com_tim14_isr,
tim8_cc_isr,
dma1_stream7_isr,
fsmc_isr,
sdio_isr,
tim5_isr,
spi3_isr,
uart4_isr,
uart5_isr,
tim6_dac_isr,
tim7_isr,
dma2_stream0_isr,
dma2_stream1_isr,
dma2_stream2_isr,
dma2_stream3_isr,
dma2_stream4_isr,
eth_isr,
eth_wkup_isr,
can2_tx_isr,
can2_rx0_isr,
can2_rx1_isr,
can2_sce_isr,
otg_fs_isr,
dma2_stream5_isr,
dma2_stream6_isr,
dma2_stream7_isr,
usart6_isr,
i2c3_ev_isr,
i2c3_er_isr,
otg_hs_ep1_out_isr,
otg_hs_ep1_in_isr,
otg_hs_wkup_isr,
otg_hs_isr,
dcmi_isr,
cryp_isr,
hash_rng_isr,
};
void reset_handler(void)
{
volatile unsigned *src, *dest;
__asm__("MSR msp, %0" : : "r"(&_stack));
/* Enable access to Floating-Point coprocessor. */
SCB_CPACR |= SCB_CPACR_FULL * (SCB_CPACR_CP10 | SCB_CPACR_CP11);
for (src = &_data_loadaddr, dest = &_data; dest < &_edata; src++, dest++)
*dest = *src;
while (dest < &_ebss)
*dest++ = 0;
/* Call the application's entry point. */
main();
}
void blocking_handler(void)
{
while (1) ;
}
void null_handler(void)
{
/* Do nothing. */
}
#pragma weak nmi_handler = null_handler
#pragma weak hard_fault_handler = blocking_handler
#pragma weak mem_manage_handler = blocking_handler
#pragma weak bus_fault_handler = blocking_handler
#pragma weak usage_fault_handler = blocking_handler
#pragma weak sv_call_handler = null_handler
#pragma weak debug_monitor_handler = null_handler
#pragma weak pend_sv_handler = null_handler
#pragma weak sys_tick_handler = null_handler
#pragma weak wwdg_isr = null_handler
#pragma weak pvd_isr = null_handler
#pragma weak tamp_stamp_isr = null_handler
#pragma weak rtc_wkup_isr = null_handler
#pragma weak flash_isr = null_handler
#pragma weak rcc_isr = null_handler
#pragma weak exti0_isr = null_handler
#pragma weak exti1_isr = null_handler
#pragma weak exti2_isr = null_handler
#pragma weak exti3_isr = null_handler
#pragma weak exti4_isr = null_handler
#pragma weak dma1_stream0_isr = null_handler
#pragma weak dma1_stream1_isr = null_handler
#pragma weak dma1_stream2_isr = null_handler
#pragma weak dma1_stream3_isr = null_handler
#pragma weak dma1_stream4_isr = null_handler
#pragma weak dma1_stream5_isr = null_handler
#pragma weak dma1_stream6_isr = null_handler
#pragma weak adc_isr = null_handler
#pragma weak can1_tx_isr = null_handler
#pragma weak can1_rx0_isr = null_handler
#pragma weak can1_rx1_isr = null_handler
#pragma weak can1_sce_isr = null_handler
#pragma weak exti9_5_isr = null_handler
#pragma weak tim1_brk_tim9_isr = null_handler
#pragma weak tim1_up_tim10_isr = null_handler
#pragma weak tim1_trg_com_tim11_isr = null_handler
#pragma weak tim1_cc_isr = null_handler
#pragma weak tim2_isr = null_handler
#pragma weak tim3_isr = null_handler
#pragma weak tim4_isr = null_handler
#pragma weak i2c1_ev_isr = null_handler
#pragma weak i2c1_er_isr = null_handler
#pragma weak i2c2_ev_isr = null_handler
#pragma weak i2c2_er_isr = null_handler
#pragma weak spi1_isr = null_handler
#pragma weak spi2_isr = null_handler
#pragma weak usart1_isr = null_handler
#pragma weak usart2_isr = null_handler
#pragma weak usart3_isr = null_handler
#pragma weak exti15_10_isr = null_handler
#pragma weak rtc_alarm_isr = null_handler
#pragma weak usb_fs_wkup_isr = null_handler
#pragma weak tim8_brk_tim12_isr = null_handler
#pragma weak tim8_up_tim13_isr = null_handler
#pragma weak tim8_trg_com_tim14_isr = null_handler
#pragma weak tim8_cc_isr = null_handler
#pragma weak dma1_stream7_isr = null_handler
#pragma weak fsmc_isr = null_handler
#pragma weak sdio_isr = null_handler
#pragma weak tim5_isr = null_handler
#pragma weak spi3_isr = null_handler
#pragma weak uart4_isr = null_handler
#pragma weak uart5_isr = null_handler
#pragma weak tim6_dac_isr = null_handler
#pragma weak tim7_isr = null_handler
#pragma weak dma2_stream0_isr = null_handler
#pragma weak dma2_stream1_isr = null_handler
#pragma weak dma2_stream2_isr = null_handler
#pragma weak dma2_stream3_isr = null_handler
#pragma weak dma2_stream4_isr = null_handler
#pragma weak eth_isr = null_handler
#pragma weak eth_wkup_isr = null_handler
#pragma weak can2_tx_isr = null_handler
#pragma weak can2_rx0_isr = null_handler
#pragma weak can2_rx1_isr = null_handler
#pragma weak can2_sce_isr = null_handler
#pragma weak otg_fs_isr = null_handler
#pragma weak dma2_stream5_isr = null_handler
#pragma weak dma2_stream6_isr = null_handler
#pragma weak dma2_stream7_isr = null_handler
#pragma weak usart6_isr = null_handler
#pragma weak i2c3_ev_isr = null_handler
#pragma weak i2c3_er_isr = null_handler
#pragma weak otg_hs_ep1_out_isr = null_handler
#pragma weak otg_hs_ep1_in_isr = null_handler
#pragma weak otg_hs_wkup_isr = null_handler
#pragma weak otg_hs_isr = null_handler
#pragma weak dcmi_isr = null_handler
#pragma weak cryp_isr = null_handler
#pragma weak hash_rng_isr = null_handler

View File

@@ -0,0 +1,27 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Piotr Esden-Tempski <piotr@esden.net>
* Copyright (C) 2011 Fergus Noble <fergusnoble@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/cm3/scb.h>
static void pre_main(void)
{
/* Enable access to Floating-Point coprocessor. */
SCB_CPACR |= SCB_CPACR_FULL * (SCB_CPACR_CP10 | SCB_CPACR_CP11);
}

View File

@@ -17,7 +17,15 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#if defined(STM32F2)
#include <libopencm3/stm32/f2/gpio.h>
#elif defined(STM32F4)
#include <libopencm3/stm32/f4/gpio.h>
#elif defined(STM32L1)
#include <libopencm3/stm32/l1/gpio.h>
#else
#error "invalid/unknown stm32 family for this code"
#endif
void gpio_mode_setup(u32 gpioport, u8 mode, u8 pull_up_down, u16 gpios)
{
@@ -86,7 +94,7 @@ void gpio_set_af(u32 gpioport, u8 alt_func_num, u16 gpios)
for (i = 8; i < 16; i++) {
if (!((1 << i) & gpios))
continue;
afrl &= ~GPIO_AFR_MASK(i - 8);
afrh &= ~GPIO_AFR_MASK(i - 8);
afrh |= GPIO_AFR(i - 8, alt_func_num);
}

36
lib/stm32/l1/Makefile Normal file
View File

@@ -0,0 +1,36 @@
##
## This file is part of the libopencm3 project.
##
## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
##
## This library is free software: you can redistribute it and/or modify
## it under the terms of the GNU Lesser General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This library is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public License
## along with this library. If not, see <http://www.gnu.org/licenses/>.
##
LIBNAME = libopencm3_stm32l1
PREFIX ?= arm-none-eabi
#PREFIX ?= arm-elf
CC = $(PREFIX)-gcc
AR = $(PREFIX)-ar
CFLAGS = -Os -g -Wall -Wextra -I../../../include -fno-common \
-mcpu=cortex-m3 -mthumb -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD -DSTM32L1
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS = rcc.o gpio2.o desig.o crc.o usart.o exti2.o
VPATH += ../../usb:../:../../cm3
include ../../Makefile.include

View File

@@ -0,0 +1,83 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/* Generic linker script for STM32 targets using libopencm3. */
/* Memory regions must be defined in the ld script which includes this one. */
/* Enforce emmition of the vector table. */
EXTERN (vector_table)
/* Define the entry point of the output file. */
ENTRY(reset_handler)
/* Define sections. */
SECTIONS
{
.text : {
*(.vectors) /* Vector table */
*(.text*) /* Program code */
. = ALIGN(4);
*(.rodata*) /* Read-only data */
. = ALIGN(4);
} >rom
/*
* Another section used by C++ stuff, appears when using newlib with
* 64bit (long long) printf support
*/
.ARM.extab : {
*(.ARM.extab*)
} >rom
.ARM.exidx : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >rom
. = ALIGN(4);
_etext = .;
.data : {
_data = .;
*(.data*) /* Read-write initialized data */
. = ALIGN(4);
_edata = .;
} >ram AT >rom
_data_loadaddr = LOADADDR(.data);
.bss : {
*(.bss*) /* Read-write zero initialized data */
*(COMMON)
. = ALIGN(4);
_ebss = .;
} >ram
/*
* The .eh_frame section appears to be used for C++ exception handling.
* You may need to fix this if you're using C++.
*/
/DISCARD/ : { *(.eh_frame) }
. = ALIGN(4);
end = .;
}
PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));

357
lib/stm32/l1/rcc.c Normal file
View File

@@ -0,0 +1,357 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2009 Federico Ruiz-Ugalde <memeruiz at gmail dot com>
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
* Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
* Based on the F4 code...
*/
#include <libopencm3/stm32/l1/rcc.h>
/* Set the default ppre1 and ppre2 peripheral clock frequencies after reset. */
u32 rcc_ppre1_frequency = 2097000;
u32 rcc_ppre2_frequency = 2097000;
void rcc_osc_ready_int_clear(osc_t osc)
{
switch (osc) {
case PLL:
RCC_CIR |= RCC_CIR_PLLRDYC;
break;
case HSE:
RCC_CIR |= RCC_CIR_HSERDYC;
break;
case HSI:
RCC_CIR |= RCC_CIR_HSIRDYC;
break;
case LSE:
RCC_CIR |= RCC_CIR_LSERDYC;
break;
case LSI:
RCC_CIR |= RCC_CIR_LSIRDYC;
break;
case MSI:
RCC_CIR |= RCC_CIR_MSIRDYC;
break;
}
}
void rcc_osc_ready_int_enable(osc_t osc)
{
switch (osc) {
case PLL:
RCC_CIR |= RCC_CIR_PLLRDYIE;
break;
case HSE:
RCC_CIR |= RCC_CIR_HSERDYIE;
break;
case HSI:
RCC_CIR |= RCC_CIR_HSIRDYIE;
break;
case LSE:
RCC_CIR |= RCC_CIR_LSERDYIE;
break;
case LSI:
RCC_CIR |= RCC_CIR_LSIRDYIE;
break;
case MSI:
RCC_CIR |= RCC_CIR_MSIRDYIE;
break;
}
}
void rcc_osc_ready_int_disable(osc_t osc)
{
switch (osc) {
case PLL:
RCC_CIR &= ~RCC_CIR_PLLRDYIE;
break;
case HSE:
RCC_CIR &= ~RCC_CIR_HSERDYIE;
break;
case HSI:
RCC_CIR &= ~RCC_CIR_HSIRDYIE;
break;
case LSE:
RCC_CIR &= ~RCC_CIR_LSERDYIE;
break;
case LSI:
RCC_CIR &= ~RCC_CIR_LSIRDYIE;
break;
case MSI:
RCC_CIR &= ~RCC_CIR_MSIRDYIE;
break;
}
}
int rcc_osc_ready_int_flag(osc_t osc)
{
switch (osc) {
case PLL:
return ((RCC_CIR & RCC_CIR_PLLRDYF) != 0);
break;
case HSE:
return ((RCC_CIR & RCC_CIR_HSERDYF) != 0);
break;
case HSI:
return ((RCC_CIR & RCC_CIR_HSIRDYF) != 0);
break;
case LSE:
return ((RCC_CIR & RCC_CIR_LSERDYF) != 0);
break;
case LSI:
return ((RCC_CIR & RCC_CIR_LSIRDYF) != 0);
break;
case MSI:
return ((RCC_CIR & RCC_CIR_MSIRDYF) != 0);
break;
}
/* Shouldn't be reached. */
return -1;
}
void rcc_css_int_clear(void)
{
RCC_CIR |= RCC_CIR_CSSC;
}
int rcc_css_int_flag(void)
{
return ((RCC_CIR & RCC_CIR_CSSF) != 0);
}
void rcc_wait_for_osc_ready(osc_t osc)
{
switch (osc) {
case PLL:
while ((RCC_CR & RCC_CR_PLLRDY) == 0);
break;
case HSE:
while ((RCC_CR & RCC_CR_HSERDY) == 0);
break;
case HSI:
while ((RCC_CR & RCC_CR_HSIRDY) == 0);
break;
case MSI:
while ((RCC_CR & RCC_CR_MSIRDY) == 0);
break;
case LSE:
while ((RCC_CSR & RCC_CSR_LSERDY) == 0);
break;
case LSI:
while ((RCC_CSR & RCC_CSR_LSIRDY) == 0);
break;
}
}
void rcc_wait_for_sysclk_status(osc_t osc)
{
switch (osc) {
case PLL:
while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != RCC_CFGR_SWS_SYSCLKSEL_PLLCLK);
break;
case HSE:
while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != RCC_CFGR_SWS_SYSCLKSEL_HSECLK);
break;
case HSI:
while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != RCC_CFGR_SWS_SYSCLKSEL_HSICLK);
break;
case MSI:
while ((RCC_CFGR & ((1 << 1) | (1 << 0))) != RCC_CFGR_SWS_SYSCLKSEL_MSICLK);
break;
default:
/* Shouldn't be reached. */
break;
}
}
void rcc_osc_on(osc_t osc)
{
switch (osc) {
case PLL:
RCC_CR |= RCC_CR_PLLON;
break;
case MSI:
RCC_CR |= RCC_CR_MSION;
break;
case HSE:
RCC_CR |= RCC_CR_HSEON;
break;
case HSI:
RCC_CR |= RCC_CR_HSION;
break;
case LSE:
RCC_CSR |= RCC_CSR_LSEON;
break;
case LSI:
RCC_CSR |= RCC_CSR_LSION;
break;
}
}
void rcc_osc_off(osc_t osc)
{
switch (osc) {
case PLL:
RCC_CR &= ~RCC_CR_PLLON;
break;
case MSI:
RCC_CR &= ~RCC_CR_MSION;
break;
case HSE:
RCC_CR &= ~RCC_CR_HSEON;
break;
case HSI:
RCC_CR &= ~RCC_CR_HSION;
break;
case LSE:
RCC_CSR &= ~RCC_CSR_LSEON;
break;
case LSI:
RCC_CSR &= ~RCC_CSR_LSION;
break;
}
}
void rcc_css_enable(void)
{
RCC_CR |= RCC_CR_CSSON;
}
void rcc_css_disable(void)
{
RCC_CR &= ~RCC_CR_CSSON;
}
void rcc_osc_bypass_enable(osc_t osc)
{
switch (osc) {
case HSE:
RCC_CR |= RCC_CR_HSEBYP;
break;
case LSE:
RCC_CSR |= RCC_CSR_LSEBYP;
break;
case PLL:
case HSI:
case LSI:
case MSI:
/* Do nothing, only HSE/LSE allowed here. */
break;
}
}
void rcc_osc_bypass_disable(osc_t osc)
{
switch (osc) {
case HSE:
RCC_CR &= ~RCC_CR_HSEBYP;
break;
case LSE:
RCC_CSR &= ~RCC_CSR_LSEBYP;
break;
case PLL:
case HSI:
case LSI:
case MSI:
/* Do nothing, only HSE/LSE allowed here. */
break;
}
}
void rcc_peripheral_enable_clock(volatile u32 *reg, u32 en)
{
*reg |= en;
}
void rcc_peripheral_disable_clock(volatile u32 *reg, u32 en)
{
*reg &= ~en;
}
void rcc_peripheral_reset(volatile u32 *reg, u32 reset)
{
*reg |= reset;
}
void rcc_peripheral_clear_reset(volatile u32 *reg, u32 clear_reset)
{
*reg &= ~clear_reset;
}
void rcc_set_sysclk_source(u32 clk)
{
u32 reg32;
reg32 = RCC_CFGR;
reg32 &= ~((1 << 1) | (1 << 0));
RCC_CFGR = (reg32 | clk);
}
void rcc_set_pll_source(u32 pllsrc)
{
u32 reg32;
reg32 = RCC_CFGR;
reg32 &= ~(1 << 16);
RCC_CFGR = (reg32 | (pllsrc << 16));
}
void rcc_set_ppre2(u32 ppre2)
{
u32 reg32;
reg32 = RCC_CFGR;
reg32 &= ~((1 << 13) | (1 << 12) | (1 << 11));
RCC_CFGR = (reg32 | (ppre2 << 11));
}
void rcc_set_ppre1(u32 ppre1)
{
u32 reg32;
reg32 = RCC_CFGR;
reg32 &= ~((1 << 10) | (1 << 9) | (1 << 8));
RCC_CFGR = (reg32 | (ppre1 << 8));
}
void rcc_set_hpre(u32 hpre)
{
u32 reg32;
reg32 = RCC_CFGR;
reg32 &= ~((1 << 4) | (1 << 5) | (1 << 6) | (1 << 7));
RCC_CFGR = (reg32 | (hpre << 4));
}
void rcc_set_rtcpre(u32 rtcpre)
{
u32 reg32;
reg32 = RCC_CR;
reg32 &= ~((1 << 30) | (1 << 29));
RCC_CR = (reg32 | (rtcpre << 29));
}
u32 rcc_system_clock_source(void)
{
/* Return the clock source which is used as system clock. */
return ((RCC_CFGR & 0x000c) >> 2);
}

View File

@@ -1,7 +1,7 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Gareth McMullin <gareth@blacksphere.co.nz>
* Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -17,19 +17,15 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/stm32/f2/scb.h>
/* Linker script for STM32L15xx8, 64K flash, 10K RAM. */
void scb_reset_core(void)
/* Define memory regions. */
MEMORY
{
SCB_AIRCR = SCB_AIRCR_VECTKEY | SCB_AIRCR_VECTRESET;
rom (rx) : ORIGIN = 0x08000000, LENGTH = 64K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 10K
}
void scb_reset_system(void)
{
SCB_AIRCR = SCB_AIRCR_VECTKEY | SCB_AIRCR_SYSRESETREQ;
}
/* Include the common ld script. */
INCLUDE libopencm3_stm32l1.ld
void scb_set_priority_grouping(u32 prigroup)
{
SCB_AIRCR = SCB_AIRCR_VECTKEY | prigroup;
}

View File

@@ -1,7 +1,7 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Gareth McMullin <gareth@blacksphere.co.nz>
* Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -17,19 +17,15 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/stm32/f4/scb.h>
/* Linker script for STM32L15xxB, 128K flash, 16K RAM. */
void scb_reset_core(void)
/* Define memory regions. */
MEMORY
{
SCB_AIRCR = SCB_AIRCR_VECTKEY | SCB_AIRCR_VECTRESET;
rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 16K
}
void scb_reset_system(void)
{
SCB_AIRCR = SCB_AIRCR_VECTKEY | SCB_AIRCR_SYSRESETREQ;
}
/* Include the common ld script. */
INCLUDE libopencm3_stm32l1.ld
void scb_set_priority_grouping(u32 prigroup)
{
SCB_AIRCR = SCB_AIRCR_VECTKEY | prigroup;
}

View File

@@ -2,7 +2,7 @@
@ingroup STM32F1xx
@brief <b>libopencm3 STM32F1xx Timers</b>
@brief <b>libopencm3 STM32 Timers</b>
@version 1.0.0
@@ -11,9 +11,9 @@
@date 18 August 2012
This library supports the General Purpose and Advanced Control Timers for
the STM32F1xx series of ARM Cortex Microcontrollers by ST Microelectronics.
the STM32 series of ARM Cortex Microcontrollers by ST Microelectronics.
The STM32F1xx series have four general purpose timers (2-5), while some have
The STM32 series have four general purpose timers (2-5), while some have
an additional two advanced timers (1,8), and some have two basic timers (6,7).
Some of the larger devices have additional general purpose timers (9-14).
@@ -70,6 +70,7 @@ push-pull outputs where the PWM output will appear.
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Edward Cheeseman <evbuilder@users.sourceforge.org>
* Copyright (C) 2011 Stephen Caudle <scaudle@doceme.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -96,7 +97,18 @@ push-pull outputs where the PWM output will appear.
/**@{*/
#include <libopencm3/stm32/timer.h>
#include <libopencm3/stm32/f1/rcc.h>
#if defined(STM32F1)
# include <libopencm3/stm32/f1/rcc.h>
#elif defined(STM32F2)
# include <libopencm3/stm32/f2/timer.h>
# include <libopencm3/stm32/f2/rcc.h>
#elif defined(STM32F4)
# include <libopencm3/stm32/f4/timer.h>
# include <libopencm3/stm32/f4/rcc.h>
#else
# error "stm32 family not defined."
#endif
/*---------------------------------------------------------------------------*/
/** @brief Reset a Timer.
@@ -1696,6 +1708,29 @@ u32 timer_get_counter(u32 timer_peripheral)
return TIM_CNT(timer_peripheral);
}
/*---------------------------------------------------------------------------*/
/** @brief Set Timer Option
Set timer options register on TIM2 or TIM5, used for oscillator calibration
on TIM5 and trigger remapping on TIM2. Only available on F4 and F2.
@param[in] timer_peripheral Unsigned int32. Timer register address base
@returns Unsigned int32. Option flags.
*/
#if (defined(STM32F4) || defined(STM32F2))
void timer_set_option(u32 timer_peripheral, u32 option)
{
if (timer_peripheral == TIM2) {
TIM_OR(timer_peripheral) &= ~TIM2_OR_ITR1_RMP_MASK;
TIM_OR(timer_peripheral) |= option;
} else if (timer_peripheral == TIM5) {
TIM_OR(timer_peripheral) &= ~TIM5_OR_TI4_RMP_MASK;
TIM_OR(timer_peripheral) |= option;
}
}
#endif
/*---------------------------------------------------------------------------*/
/** @brief Set Counter

View File

@@ -46,6 +46,8 @@ LGPL License Terms @ref lgpl_license
# include <libopencm3/stm32/f2/rcc.h>
#elif defined(STM32F4)
# include <libopencm3/stm32/f4/rcc.h>
#elif defined(STM32L1)
# include <libopencm3/stm32/l1/rcc.h>
#else
# error "stm32 family not defined."
#endif

View File

@@ -21,8 +21,6 @@
#include <libopencm3/usb/usbd.h>
#include "usb_private.h"
struct _usbd_device _usbd_device;
u8 usbd_control_buffer[128] __attribute__((weak));
/**
@@ -43,106 +41,112 @@ u8 usbd_control_buffer[128] __attribute__((weak));
* @param strings TODO
* @return Zero on success (currently cannot fail).
*/
int usbd_init(const usbd_driver *driver,
const struct usb_device_descriptor *dev,
const struct usb_config_descriptor *conf,
const char **strings, int num_strings)
usbd_device *usbd_init(const usbd_driver *driver,
const struct usb_device_descriptor *dev,
const struct usb_config_descriptor *conf,
const char **strings, int num_strings)
{
_usbd_device.driver = driver;
_usbd_device.desc = dev;
_usbd_device.config = conf;
_usbd_device.strings = strings;
_usbd_device.num_strings = num_strings;
_usbd_device.ctrl_buf = usbd_control_buffer;
_usbd_device.ctrl_buf_len = sizeof(usbd_control_buffer);
usbd_device *usbd_dev;
_usbd_hw_init();
usbd_dev = driver->init();
_usbd_device.user_callback_ctr[0][USB_TRANSACTION_SETUP] =
usbd_dev->driver = driver;
usbd_dev->desc = dev;
usbd_dev->config = conf;
usbd_dev->strings = strings;
usbd_dev->num_strings = num_strings;
usbd_dev->ctrl_buf = usbd_control_buffer;
usbd_dev->ctrl_buf_len = sizeof(usbd_control_buffer);
usbd_dev->user_callback_ctr[0][USB_TRANSACTION_SETUP] =
_usbd_control_setup;
_usbd_device.user_callback_ctr[0][USB_TRANSACTION_OUT] =
usbd_dev->user_callback_ctr[0][USB_TRANSACTION_OUT] =
_usbd_control_out;
_usbd_device.user_callback_ctr[0][USB_TRANSACTION_IN] =
usbd_dev->user_callback_ctr[0][USB_TRANSACTION_IN] =
_usbd_control_in;
return 0;
return usbd_dev;
}
void usbd_register_reset_callback(void (*callback)(void))
void usbd_register_reset_callback(usbd_device *usbd_dev, void (*callback)(void))
{
_usbd_device.user_callback_reset = callback;
usbd_dev->user_callback_reset = callback;
}
void usbd_register_suspend_callback(void (*callback)(void))
void usbd_register_suspend_callback(usbd_device *usbd_dev,
void (*callback)(void))
{
_usbd_device.user_callback_suspend = callback;
usbd_dev->user_callback_suspend = callback;
}
void usbd_register_resume_callback(void (*callback)(void))
void usbd_register_resume_callback(usbd_device *usbd_dev,
void (*callback)(void))
{
_usbd_device.user_callback_resume = callback;
usbd_dev->user_callback_resume = callback;
}
void usbd_register_sof_callback(void (*callback)(void))
void usbd_register_sof_callback(usbd_device *usbd_dev, void (*callback)(void))
{
_usbd_device.user_callback_sof = callback;
usbd_dev->user_callback_sof = callback;
}
void usbd_set_control_buffer_size(u16 size)
void usbd_set_control_buffer_size(usbd_device *usbd_dev, u16 size)
{
_usbd_device.ctrl_buf_len = size;
usbd_dev->ctrl_buf_len = size;
}
void _usbd_reset(void)
void _usbd_reset(usbd_device *usbd_dev)
{
_usbd_device.current_address = 0;
_usbd_device.current_config = 0;
usbd_ep_setup(0, USB_ENDPOINT_ATTR_CONTROL, 64, NULL);
_usbd_hw_set_address(0);
usbd_dev->current_address = 0;
usbd_dev->current_config = 0;
usbd_ep_setup(usbd_dev, 0, USB_ENDPOINT_ATTR_CONTROL, 64, NULL);
usbd_dev->driver->set_address(usbd_dev, 0);
if (_usbd_device.user_callback_reset)
_usbd_device.user_callback_reset();
if (usbd_dev->user_callback_reset)
usbd_dev->user_callback_reset();
}
/* Functions to wrap the low-level driver */
void usbd_poll(void)
void usbd_poll(usbd_device *usbd_dev)
{
_usbd_device.driver->poll();
usbd_dev->driver->poll(usbd_dev);
}
void usbd_disconnect(bool disconnected)
void usbd_disconnect(usbd_device *usbd_dev, bool disconnected)
{
/* not all drivers support disconnection */
if (_usbd_device.driver->disconnect)
_usbd_device.driver->disconnect(disconnected);
if (usbd_dev->driver->disconnect)
usbd_dev->driver->disconnect(usbd_dev, disconnected);
}
void usbd_ep_setup(u8 addr, u8 type, u16 max_size, void (*callback)(u8 ep))
void usbd_ep_setup(usbd_device *usbd_dev, u8 addr, u8 type, u16 max_size,
void (*callback)(usbd_device *usbd_dev, u8 ep))
{
_usbd_device.driver->ep_setup(addr, type, max_size, callback);
usbd_dev->driver->ep_setup(usbd_dev, addr, type, max_size, callback);
}
u16 usbd_ep_write_packet(u8 addr, const void *buf, u16 len)
u16 usbd_ep_write_packet(usbd_device *usbd_dev, u8 addr,
const void *buf, u16 len)
{
return _usbd_device.driver->ep_write_packet(addr, buf, len);
return usbd_dev->driver->ep_write_packet(usbd_dev, addr, buf, len);
}
u16 usbd_ep_read_packet(u8 addr, void *buf, u16 len)
u16 usbd_ep_read_packet(usbd_device *usbd_dev, u8 addr, void *buf, u16 len)
{
return _usbd_device.driver->ep_read_packet(addr, buf, len);
return usbd_dev->driver->ep_read_packet(usbd_dev, addr, buf, len);
}
void usbd_ep_stall_set(u8 addr, u8 stall)
void usbd_ep_stall_set(usbd_device *usbd_dev, u8 addr, u8 stall)
{
_usbd_device.driver->ep_stall_set(addr, stall);
usbd_dev->driver->ep_stall_set(usbd_dev, addr, stall);
}
u8 usbd_ep_stall_get(u8 addr)
u8 usbd_ep_stall_get(usbd_device *usbd_dev, u8 addr)
{
return _usbd_device.driver->ep_stall_get(addr);
return usbd_dev->driver->ep_stall_get(usbd_dev, addr);
}
void usbd_ep_nak_set(u8 addr, u8 nak)
void usbd_ep_nak_set(usbd_device *usbd_dev, u8 addr, u8 nak)
{
_usbd_device.driver->ep_nak_set(addr, nak);
usbd_dev->driver->ep_nak_set(usbd_dev, addr, nak);
}

View File

@@ -21,77 +21,73 @@
#include <libopencm3/usb/usbd.h>
#include "usb_private.h"
static struct usb_control_state {
enum {
IDLE, STALLED,
DATA_IN, LAST_DATA_IN, STATUS_IN,
DATA_OUT, LAST_DATA_OUT, STATUS_OUT,
} state;
struct usb_setup_data req;
u8 *ctrl_buf;
u16 ctrl_len;
void (*complete)(struct usb_setup_data *req);
} control_state;
/* Register application callback function for handling USB control requests. */
int usbd_register_control_callback(u8 type, u8 type_mask,
int usbd_register_control_callback(usbd_device *usbd_dev, u8 type, u8 type_mask,
usbd_control_callback callback)
{
int i;
for (i = 0; i < MAX_USER_CONTROL_CALLBACK; i++) {
if (_usbd_device.user_control_callback[i].cb)
if (usbd_dev->user_control_callback[i].cb)
continue;
_usbd_device.user_control_callback[i].type = type;
_usbd_device.user_control_callback[i].type_mask = type_mask;
_usbd_device.user_control_callback[i].cb = callback;
usbd_dev->user_control_callback[i].type = type;
usbd_dev->user_control_callback[i].type_mask = type_mask;
usbd_dev->user_control_callback[i].cb = callback;
return 0;
}
return -1;
}
static void usb_control_send_chunk(void)
static void usb_control_send_chunk(usbd_device *usbd_dev)
{
if (_usbd_device.desc->bMaxPacketSize0 < control_state.ctrl_len) {
if (usbd_dev->desc->bMaxPacketSize0 < usbd_dev->control_state.ctrl_len) {
/* Data stage, normal transmission */
usbd_ep_write_packet(0, control_state.ctrl_buf,
_usbd_device.desc->bMaxPacketSize0);
control_state.state = DATA_IN;
control_state.ctrl_buf += _usbd_device.desc->bMaxPacketSize0;
control_state.ctrl_len -= _usbd_device.desc->bMaxPacketSize0;
usbd_ep_write_packet(usbd_dev, 0,
usbd_dev->control_state.ctrl_buf,
usbd_dev->desc->bMaxPacketSize0);
usbd_dev->control_state.state = DATA_IN;
usbd_dev->control_state.ctrl_buf +=
usbd_dev->desc->bMaxPacketSize0;
usbd_dev->control_state.ctrl_len -=
usbd_dev->desc->bMaxPacketSize0;
} else {
/* Data stage, end of transmission */
usbd_ep_write_packet(0, control_state.ctrl_buf,
control_state.ctrl_len);
control_state.state = LAST_DATA_IN;
control_state.ctrl_len = 0;
control_state.ctrl_buf = NULL;
usbd_ep_write_packet(usbd_dev, 0,
usbd_dev->control_state.ctrl_buf,
usbd_dev->control_state.ctrl_len);
usbd_dev->control_state.state = LAST_DATA_IN;
usbd_dev->control_state.ctrl_len = 0;
usbd_dev->control_state.ctrl_buf = NULL;
}
}
static int usb_control_recv_chunk(void)
static int usb_control_recv_chunk(usbd_device *usbd_dev)
{
u16 packetsize = MIN(_usbd_device.desc->bMaxPacketSize0,
control_state.req.wLength - control_state.ctrl_len);
u16 size = usbd_ep_read_packet(0, control_state.ctrl_buf +
control_state.ctrl_len, packetsize);
u16 packetsize = MIN(usbd_dev->desc->bMaxPacketSize0,
usbd_dev->control_state.req.wLength -
usbd_dev->control_state.ctrl_len);
u16 size = usbd_ep_read_packet(usbd_dev, 0,
usbd_dev->control_state.ctrl_buf +
usbd_dev->control_state.ctrl_len,
packetsize);
if (size != packetsize) {
usbd_ep_stall_set(0, 1);
usbd_ep_stall_set(usbd_dev, 0, 1);
return -1;
}
control_state.ctrl_len += size;
usbd_dev->control_state.ctrl_len += size;
return packetsize;
}
static int usb_control_request_dispatch(struct usb_setup_data *req)
static int usb_control_request_dispatch(usbd_device *usbd_dev,
struct usb_setup_data *req)
{
int i, result = 0;
struct user_control_callback *cb = _usbd_device.user_control_callback;
struct user_control_callback *cb = usbd_dev->user_control_callback;
/* Call user command hook function. */
for (i = 0; i < MAX_USER_CONTROL_CALLBACK; i++) {
@@ -99,141 +95,149 @@ static int usb_control_request_dispatch(struct usb_setup_data *req)
break;
if ((req->bmRequestType & cb[i].type_mask) == cb[i].type) {
result = cb[i].cb(req, &control_state.ctrl_buf,
&control_state.ctrl_len,
&control_state.complete);
result = cb[i].cb(usbd_dev, req,
&(usbd_dev->control_state.ctrl_buf),
&(usbd_dev->control_state.ctrl_len),
&(usbd_dev->control_state.complete));
if (result == USBD_REQ_HANDLED ||
result == USBD_REQ_NOTSUPP)
return result;
}
}
/* Try standard request if not already handled. */
return _usbd_standard_request(req, &control_state.ctrl_buf,
&control_state.ctrl_len);
return _usbd_standard_request(usbd_dev, req,
&(usbd_dev->control_state.ctrl_buf),
&(usbd_dev->control_state.ctrl_len));
}
/* Handle commands and read requests. */
static void usb_control_setup_read(struct usb_setup_data *req)
static void usb_control_setup_read(usbd_device *usbd_dev,
struct usb_setup_data *req)
{
control_state.ctrl_buf = _usbd_device.ctrl_buf;
control_state.ctrl_len = req->wLength;
usbd_dev->control_state.ctrl_buf = usbd_dev->ctrl_buf;
usbd_dev->control_state.ctrl_len = req->wLength;
if (usb_control_request_dispatch(req)) {
if (control_state.ctrl_len) {
if (usb_control_request_dispatch(usbd_dev, req)) {
if (usbd_dev->control_state.ctrl_len) {
/* Go to data out stage if handled. */
usb_control_send_chunk();
usb_control_send_chunk(usbd_dev);
} else {
/* Go to status stage if handled. */
usbd_ep_write_packet(0, NULL, 0);
control_state.state = STATUS_IN;
usbd_ep_write_packet(usbd_dev, 0, NULL, 0);
usbd_dev->control_state.state = STATUS_IN;
}
} else {
/* Stall endpoint on failure. */
usbd_ep_stall_set(0, 1);
usbd_ep_stall_set(usbd_dev, 0, 1);
}
}
static void usb_control_setup_write(struct usb_setup_data *req)
static void usb_control_setup_write(usbd_device *usbd_dev,
struct usb_setup_data *req)
{
if (req->wLength > _usbd_device.ctrl_buf_len) {
usbd_ep_stall_set(0, 1);
if (req->wLength > usbd_dev->ctrl_buf_len) {
usbd_ep_stall_set(usbd_dev, 0, 1);
return;
}
/* Buffer into which to write received data. */
control_state.ctrl_buf = _usbd_device.ctrl_buf;
control_state.ctrl_len = 0;
usbd_dev->control_state.ctrl_buf = usbd_dev->ctrl_buf;
usbd_dev->control_state.ctrl_len = 0;
/* Wait for DATA OUT stage. */
if (req->wLength > _usbd_device.desc->bMaxPacketSize0)
control_state.state = DATA_OUT;
if (req->wLength > usbd_dev->desc->bMaxPacketSize0)
usbd_dev->control_state.state = DATA_OUT;
else
control_state.state = LAST_DATA_OUT;
usbd_dev->control_state.state = LAST_DATA_OUT;
}
void _usbd_control_setup(u8 ea)
void _usbd_control_setup(usbd_device *usbd_dev, u8 ea)
{
struct usb_setup_data *req = &control_state.req;
struct usb_setup_data *req = &usbd_dev->control_state.req;
(void)ea;
control_state.complete = NULL;
usbd_dev->control_state.complete = NULL;
if (usbd_ep_read_packet(0, req, 8) != 8) {
usbd_ep_stall_set(0, 1);
if (usbd_ep_read_packet(usbd_dev, 0, req, 8) != 8) {
usbd_ep_stall_set(usbd_dev, 0, 1);
return;
}
if (req->wLength == 0) {
usb_control_setup_read(req);
usb_control_setup_read(usbd_dev, req);
} else if (req->bmRequestType & 0x80) {
usb_control_setup_read(req);
usb_control_setup_read(usbd_dev, req);
} else {
usb_control_setup_write(req);
usb_control_setup_write(usbd_dev, req);
}
}
void _usbd_control_out(u8 ea)
void _usbd_control_out(usbd_device *usbd_dev, u8 ea)
{
(void)ea;
switch (control_state.state) {
switch (usbd_dev->control_state.state) {
case DATA_OUT:
if (usb_control_recv_chunk() < 0)
if (usb_control_recv_chunk(usbd_dev) < 0)
break;
if ((control_state.req.wLength - control_state.ctrl_len) <=
_usbd_device.desc->bMaxPacketSize0)
control_state.state = LAST_DATA_OUT;
if ((usbd_dev->control_state.req.wLength -
usbd_dev->control_state.ctrl_len) <=
usbd_dev->desc->bMaxPacketSize0)
usbd_dev->control_state.state = LAST_DATA_OUT;
break;
case LAST_DATA_OUT:
if (usb_control_recv_chunk() < 0)
if (usb_control_recv_chunk(usbd_dev) < 0)
break;
/*
* We have now received the full data payload.
* Invoke callback to process.
*/
if (usb_control_request_dispatch(&control_state.req)) {
if (usb_control_request_dispatch(usbd_dev,
&(usbd_dev->control_state.req))) {
/* Got to status stage on success. */
usbd_ep_write_packet(0, NULL, 0);
control_state.state = STATUS_IN;
usbd_ep_write_packet(usbd_dev, 0, NULL, 0);
usbd_dev->control_state.state = STATUS_IN;
} else {
usbd_ep_stall_set(0, 1);
usbd_ep_stall_set(usbd_dev, 0, 1);
}
break;
case STATUS_OUT:
usbd_ep_read_packet(0, NULL, 0);
control_state.state = IDLE;
if (control_state.complete)
control_state.complete(&control_state.req);
control_state.complete = NULL;
usbd_ep_read_packet(usbd_dev, 0, NULL, 0);
usbd_dev->control_state.state = IDLE;
if (usbd_dev->control_state.complete)
usbd_dev->control_state.complete(usbd_dev,
&(usbd_dev->control_state.req));
usbd_dev->control_state.complete = NULL;
break;
default:
usbd_ep_stall_set(0, 1);
usbd_ep_stall_set(usbd_dev, 0, 1);
}
}
void _usbd_control_in(u8 ea)
void _usbd_control_in(usbd_device *usbd_dev, u8 ea)
{
(void)ea;
struct usb_setup_data *req = &control_state.req;
struct usb_setup_data *req = &(usbd_dev->control_state.req);
switch (control_state.state) {
switch (usbd_dev->control_state.state) {
case DATA_IN:
usb_control_send_chunk();
usb_control_send_chunk(usbd_dev);
break;
case LAST_DATA_IN:
control_state.state = STATUS_OUT;
usbd_dev->control_state.state = STATUS_OUT;
break;
case STATUS_IN:
if (control_state.complete)
control_state.complete(&control_state.req);
if (usbd_dev->control_state.complete)
usbd_dev->control_state.complete(usbd_dev,
&(usbd_dev->control_state.req));
/* Exception: Handle SET ADDRESS function here... */
if ((req->bmRequestType == 0) &&
(req->bRequest == USB_REQ_SET_ADDRESS))
_usbd_hw_set_address(req->wValue);
control_state.state = IDLE;
usbd_dev->driver->set_address(usbd_dev, req->wValue);
usbd_dev->control_state.state = IDLE;
break;
default:
usbd_ep_stall_set(0, 1);
usbd_ep_stall_set(usbd_dev, 0, 1);
}
}

View File

@@ -24,19 +24,23 @@
#include <libopencm3/usb/usbd.h>
#include "usb_private.h"
static void stm32f103_usbd_init(void);
static void stm32f103_set_address(u8 addr);
static void stm32f103_ep_setup(u8 addr, u8 type, u16 max_size,
void (*callback) (u8 ep));
static void stm32f103_endpoints_reset(void);
static void stm32f103_ep_stall_set(u8 addr, u8 stall);
static u8 stm32f103_ep_stall_get(u8 addr);
static void stm32f103_ep_nak_set(u8 addr, u8 nak);
static u16 stm32f103_ep_write_packet(u8 addr, const void *buf, u16 len);
static u16 stm32f103_ep_read_packet(u8 addr, void *buf, u16 len);
static void stm32f103_poll(void);
static usbd_device *stm32f103_usbd_init(void);
static void stm32f103_set_address(usbd_device *usbd_dev, u8 addr);
static void stm32f103_ep_setup(usbd_device *usbd_dev, u8 addr, u8 type,
u16 max_size,
void (*callback) (usbd_device *usbd_dev, u8 ep));
static void stm32f103_endpoints_reset(usbd_device *usbd_dev);
static void stm32f103_ep_stall_set(usbd_device *usbd_dev, u8 addr, u8 stall);
static u8 stm32f103_ep_stall_get(usbd_device *usbd_dev, u8 addr);
static void stm32f103_ep_nak_set(usbd_device *usbd_dev, u8 addr, u8 nak);
static u16 stm32f103_ep_write_packet(usbd_device *usbd_dev, u8 addr,
const void *buf, u16 len);
static u16 stm32f103_ep_read_packet(usbd_device *usbd_dev, u8 addr, void *buf,
u16 len);
static void stm32f103_poll(usbd_device *usbd_dev);
static u8 force_nak[8];
static struct _usbd_device usbd_dev;
const struct _usbd_driver stm32f103_usb_driver = {
.init = stm32f103_usbd_init,
@@ -52,7 +56,7 @@ const struct _usbd_driver stm32f103_usb_driver = {
};
/** Initialize the USB device controller hardware of the STM32. */
static void stm32f103_usbd_init(void)
static usbd_device *stm32f103_usbd_init(void)
{
rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_USBEN);
SET_REG(USB_CNTR_REG, 0);
@@ -62,10 +66,12 @@ static void stm32f103_usbd_init(void)
/* Enable RESET, SUSPEND, RESUME and CTR interrupts. */
SET_REG(USB_CNTR_REG, USB_CNTR_RESETM | USB_CNTR_CTRM |
USB_CNTR_SUSPM | USB_CNTR_WKUPM);
return &usbd_dev;
}
static void stm32f103_set_address(u8 addr)
static void stm32f103_set_address(usbd_device *usbd_dev, u8 addr)
{
(void)usbd_dev;
/* Set device address and enable. */
SET_REG(USB_DADDR_REG, (addr & USB_DADDR_ADDR) | USB_DADDR_ENABLE);
}
@@ -76,8 +82,9 @@ static void stm32f103_set_address(u8 addr)
* @param ep Index of endpoint to configure.
* @param size Size in bytes of the RX buffer.
*/
static void usb_set_ep_rx_bufsize(u8 ep, u32 size)
static void usb_set_ep_rx_bufsize(usbd_device *usbd_dev, u8 ep, u32 size)
{
(void)usbd_dev;
if (size > 62) {
if (size & 0x1f)
size -= 32;
@@ -89,8 +96,9 @@ static void usb_set_ep_rx_bufsize(u8 ep, u32 size)
}
}
static void stm32f103_ep_setup(u8 addr, u8 type, u16 max_size,
void (*callback) (u8 ep))
static void stm32f103_ep_setup(usbd_device *usbd_dev, u8 addr, u8 type,
u16 max_size,
void (*callback) (usbd_device *usbd_dev, u8 ep))
{
/* Translate USB standard type codes to STM32. */
const u16 typelookup[] = {
@@ -107,32 +115,30 @@ static void stm32f103_ep_setup(u8 addr, u8 type, u16 max_size,
USB_SET_EP_TYPE(addr, typelookup[type]);
if (dir || (addr == 0)) {
USB_SET_EP_TX_ADDR(addr, _usbd_device.pm_top);
USB_SET_EP_TX_ADDR(addr, usbd_dev->pm_top);
if (callback) {
_usbd_device.
user_callback_ctr[addr][USB_TRANSACTION_IN] =
usbd_dev->user_callback_ctr[addr][USB_TRANSACTION_IN] =
(void *)callback;
}
USB_CLR_EP_TX_DTOG(addr);
USB_SET_EP_TX_STAT(addr, USB_EP_TX_STAT_NAK);
_usbd_device.pm_top += max_size;
usbd_dev->pm_top += max_size;
}
if (!dir) {
USB_SET_EP_RX_ADDR(addr, _usbd_device.pm_top);
usb_set_ep_rx_bufsize(addr, max_size);
USB_SET_EP_RX_ADDR(addr, usbd_dev->pm_top);
usb_set_ep_rx_bufsize(usbd_dev, addr, max_size);
if (callback) {
_usbd_device.
user_callback_ctr[addr][USB_TRANSACTION_OUT] =
usbd_dev->user_callback_ctr[addr][USB_TRANSACTION_OUT] =
(void *)callback;
}
USB_CLR_EP_RX_DTOG(addr);
USB_SET_EP_RX_STAT(addr, USB_EP_RX_STAT_VALID);
_usbd_device.pm_top += max_size;
usbd_dev->pm_top += max_size;
}
}
static void stm32f103_endpoints_reset(void)
static void stm32f103_endpoints_reset(usbd_device *usbd_dev)
{
int i;
@@ -141,11 +147,12 @@ static void stm32f103_endpoints_reset(void)
USB_SET_EP_TX_STAT(i, USB_EP_TX_STAT_DISABLED);
USB_SET_EP_RX_STAT(i, USB_EP_RX_STAT_DISABLED);
}
_usbd_device.pm_top = 0x40 + (2 * _usbd_device.desc->bMaxPacketSize0);
usbd_dev->pm_top = 0x40 + (2 * usbd_dev->desc->bMaxPacketSize0);
}
static void stm32f103_ep_stall_set(u8 addr, u8 stall)
static void stm32f103_ep_stall_set(usbd_device *usbd_dev, u8 addr, u8 stall)
{
(void)usbd_dev;
if (addr == 0)
USB_SET_EP_TX_STAT(addr, stall ? USB_EP_TX_STAT_STALL :
USB_EP_TX_STAT_NAK);
@@ -169,8 +176,9 @@ static void stm32f103_ep_stall_set(u8 addr, u8 stall)
}
}
static u8 stm32f103_ep_stall_get(u8 addr)
static u8 stm32f103_ep_stall_get(usbd_device *usbd_dev, u8 addr)
{
(void)usbd_dev;
if (addr & 0x80) {
if ((*USB_EP_REG(addr & 0x7F) & USB_EP_TX_STAT) ==
USB_EP_TX_STAT_STALL)
@@ -183,8 +191,9 @@ static u8 stm32f103_ep_stall_get(u8 addr)
return 0;
}
static void stm32f103_ep_nak_set(u8 addr, u8 nak)
static void stm32f103_ep_nak_set(usbd_device *usbd_dev, u8 addr, u8 nak)
{
(void)usbd_dev;
/* It does not make sence to force NAK on IN endpoints. */
if (addr & 0x80)
return;
@@ -213,8 +222,10 @@ static void usb_copy_to_pm(volatile void *vPM, const void *buf, u16 len)
*PM = *lbuf;
}
static u16 stm32f103_ep_write_packet(u8 addr, const void *buf, u16 len)
static u16 stm32f103_ep_write_packet(usbd_device *usbd_dev, u8 addr,
const void *buf, u16 len)
{
(void)usbd_dev;
addr &= 0x7F;
if ((*USB_EP_REG(addr) & USB_EP_TX_STAT) == USB_EP_TX_STAT_VALID)
@@ -247,8 +258,10 @@ static void usb_copy_from_pm(void *buf, const volatile void *vPM, u16 len)
*(u8 *) lbuf = *(u8 *) PM;
}
static u16 stm32f103_ep_read_packet(u8 addr, void *buf, u16 len)
static u16 stm32f103_ep_read_packet(usbd_device *usbd_dev, u8 addr, void *buf,
u16 len)
{
(void)usbd_dev;
if ((*USB_EP_REG(addr) & USB_EP_RX_STAT) == USB_EP_RX_STAT_VALID)
return 0;
@@ -262,13 +275,13 @@ static u16 stm32f103_ep_read_packet(u8 addr, void *buf, u16 len)
return len;
}
static void stm32f103_poll(void)
static void stm32f103_poll(usbd_device *usbd_dev)
{
u16 istr = *USB_ISTR_REG;
if (istr & USB_ISTR_RESET) {
_usbd_device.pm_top = 0x40;
_usbd_reset();
usbd_dev->pm_top = 0x40;
_usbd_reset(usbd_dev);
USB_CLR_ISTR_RESET();
return;
}
@@ -282,27 +295,27 @@ static void stm32f103_poll(void)
else /* IN transaction */
USB_CLR_EP_TX_CTR(ep);
if (_usbd_device.user_callback_ctr[ep][type])
_usbd_device.user_callback_ctr[ep][type] (ep);
if (usbd_dev->user_callback_ctr[ep][type])
usbd_dev->user_callback_ctr[ep][type] (usbd_dev, ep);
else
USB_CLR_EP_RX_CTR(ep);
}
if (istr & USB_ISTR_SUSP) {
USB_CLR_ISTR_SUSP();
if (_usbd_device.user_callback_suspend)
_usbd_device.user_callback_suspend();
if (usbd_dev->user_callback_suspend)
usbd_dev->user_callback_suspend();
}
if (istr & USB_ISTR_WKUP) {
USB_CLR_ISTR_WKUP();
if (_usbd_device.user_callback_resume)
_usbd_device.user_callback_resume();
if (usbd_dev->user_callback_resume)
usbd_dev->user_callback_resume();
}
if (istr & USB_ISTR_SOF) {
if (_usbd_device.user_callback_sof)
_usbd_device.user_callback_sof();
if (usbd_dev->user_callback_sof)
usbd_dev->user_callback_sof();
USB_CLR_ISTR_SOF();
}
}

View File

@@ -23,49 +23,34 @@
#include <libopencm3/stm32/otg_fs.h>
#include <libopencm3/usb/usbd.h>
#include "usb_private.h"
#include "usb_fx07_common.h"
/* Receive FIFO size in 32-bit words. */
#define RX_FIFO_SIZE 128
static uint16_t fifo_mem_top;
static uint16_t fifo_mem_top_ep0;
static u8 force_nak[4];
static usbd_device *stm32f107_usbd_init(void);
static void stm32f107_usbd_init(void);
static void stm32f107_set_address(u8 addr);
static void stm32f107_ep_setup(u8 addr, u8 type, u16 max_size,
void (*callback)(u8 ep));
static void stm32f107_endpoints_reset(void);
static void stm32f107_ep_stall_set(u8 addr, u8 stall);
static u8 stm32f107_ep_stall_get(u8 addr);
static void stm32f107_ep_nak_set(u8 addr, u8 nak);
static u16 stm32f107_ep_write_packet(u8 addr, const void *buf, u16 len);
static u16 stm32f107_ep_read_packet(u8 addr, void *buf, u16 len);
static void stm32f107_poll(void);
static void stm32f107_disconnect(bool disconnected);
/*
* We keep a backup copy of the out endpoint size registers to restore them
* after a transaction.
*/
static u32 doeptsiz[4];
static struct _usbd_device usbd_dev;
const struct _usbd_driver stm32f107_usb_driver = {
.init = stm32f107_usbd_init,
.set_address = stm32f107_set_address,
.ep_setup = stm32f107_ep_setup,
.ep_reset = stm32f107_endpoints_reset,
.ep_stall_set = stm32f107_ep_stall_set,
.ep_stall_get = stm32f107_ep_stall_get,
.ep_nak_set = stm32f107_ep_nak_set,
.ep_write_packet = stm32f107_ep_write_packet,
.ep_read_packet = stm32f107_ep_read_packet,
.poll = stm32f107_poll,
.disconnect = stm32f107_disconnect,
.set_address = stm32fx07_set_address,
.ep_setup = stm32fx07_ep_setup,
.ep_reset = stm32fx07_endpoints_reset,
.ep_stall_set = stm32fx07_ep_stall_set,
.ep_stall_get = stm32fx07_ep_stall_get,
.ep_nak_set = stm32fx07_ep_nak_set,
.ep_write_packet = stm32fx07_ep_write_packet,
.ep_read_packet = stm32fx07_ep_read_packet,
.poll = stm32fx07_poll,
.disconnect = stm32fx07_disconnect,
.base_address = USB_OTG_FS_BASE,
.set_address_before_status = 1,
.rx_fifo_size = RX_FIFO_SIZE,
};
/** Initialize the USB device controller hardware of the STM32. */
static void stm32f107_usbd_init(void)
static usbd_device *stm32f107_usbd_init(void)
{
OTG_FS_GINTSTS = OTG_FS_GINTSTS_MMIS;
@@ -88,8 +73,8 @@ static void stm32f107_usbd_init(void)
/* Restart the PHY clock. */
OTG_FS_PCGCCTL = 0;
OTG_FS_GRXFSIZ = RX_FIFO_SIZE;
fifo_mem_top = RX_FIFO_SIZE;
OTG_FS_GRXFSIZ = stm32f107_usb_driver.rx_fifo_size;
usbd_dev.fifo_mem_top = stm32f107_usb_driver.rx_fifo_size;
/* Unmask interrupts for TX and RX. */
OTG_FS_GAHBCFG |= OTG_FS_GAHBCFG_GINT;
@@ -101,289 +86,6 @@ static void stm32f107_usbd_init(void)
OTG_FS_GINTMSK_SOFM;
OTG_FS_DAINTMSK = 0xF;
OTG_FS_DIEPMSK = OTG_FS_DIEPMSK_XFRCM;
}
static void stm32f107_set_address(u8 addr)
{
OTG_FS_DCFG = (OTG_FS_DCFG & ~OTG_FS_DCFG_DAD) | (addr << 4);
}
static void stm32f107_ep_setup(u8 addr, u8 type, u16 max_size,
void (*callback) (u8 ep))
{
/*
* Configure endpoint address and type. Allocate FIFO memory for
* endpoint. Install callback funciton.
*/
u8 dir = addr & 0x80;
addr &= 0x7f;
if (addr == 0) { /* For the default control endpoint */
/* Configure IN part. */
if (max_size >= 64) {
OTG_FS_DIEPCTL0 = OTG_FS_DIEPCTL0_MPSIZ_64;
} else if (max_size >= 32) {
OTG_FS_DIEPCTL0 = OTG_FS_DIEPCTL0_MPSIZ_32;
} else if (max_size >= 16) {
OTG_FS_DIEPCTL0 = OTG_FS_DIEPCTL0_MPSIZ_16;
} else {
OTG_FS_DIEPCTL0 = OTG_FS_DIEPCTL0_MPSIZ_8;
}
OTG_FS_DIEPTSIZ0 = (max_size & OTG_FS_DIEPSIZ0_XFRSIZ_MASK);
OTG_FS_DIEPCTL0 |= OTG_FS_DIEPCTL0_EPENA | OTG_FS_DIEPCTL0_SNAK;
/* Configure OUT part. */
doeptsiz[0] = OTG_FS_DIEPSIZ0_STUPCNT_1 | (1 << 19) |
(max_size & OTG_FS_DIEPSIZ0_XFRSIZ_MASK);
OTG_FS_DOEPTSIZ(0) = doeptsiz[0];
OTG_FS_DOEPCTL(0) |=
OTG_FS_DOEPCTL0_EPENA | OTG_FS_DIEPCTL0_SNAK;
OTG_FS_GNPTXFSIZ = ((max_size / 4) << 16) | RX_FIFO_SIZE;
fifo_mem_top += max_size / 4;
fifo_mem_top_ep0 = fifo_mem_top;
return;
}
if (dir) {
OTG_FS_DIEPTXF(addr) = ((max_size / 4) << 16) | fifo_mem_top;
fifo_mem_top += max_size / 4;
OTG_FS_DIEPTSIZ(addr) =
(max_size & OTG_FS_DIEPSIZ0_XFRSIZ_MASK);
OTG_FS_DIEPCTL(addr) |=
OTG_FS_DIEPCTL0_EPENA | OTG_FS_DIEPCTL0_SNAK | (type << 18)
| OTG_FS_DIEPCTL0_USBAEP | OTG_FS_DIEPCTLX_SD0PID
| (addr << 22) | max_size;
if (callback) {
_usbd_device.
user_callback_ctr[addr][USB_TRANSACTION_IN] =
(void *)callback;
}
}
if (!dir) {
doeptsiz[addr] = (1 << 19) |
(max_size & OTG_FS_DIEPSIZ0_XFRSIZ_MASK);
OTG_FS_DOEPTSIZ(addr) = doeptsiz[addr];
OTG_FS_DOEPCTL(addr) |= OTG_FS_DOEPCTL0_EPENA |
OTG_FS_DOEPCTL0_USBAEP | OTG_FS_DIEPCTL0_CNAK |
OTG_FS_DOEPCTLX_SD0PID | (type << 18) | max_size;
if (callback) {
_usbd_device.
user_callback_ctr[addr][USB_TRANSACTION_OUT] =
(void *)callback;
}
}
}
static void stm32f107_endpoints_reset(void)
{
/* The core resets the endpoints automatically on reset. */
fifo_mem_top = fifo_mem_top_ep0;
}
static void stm32f107_ep_stall_set(u8 addr, u8 stall)
{
if (addr == 0) {
if (stall)
OTG_FS_DIEPCTL(addr) |= OTG_FS_DIEPCTL0_STALL;
else
OTG_FS_DIEPCTL(addr) &= ~OTG_FS_DIEPCTL0_STALL;
}
if (addr & 0x80) {
addr &= 0x7F;
if (stall) {
OTG_FS_DIEPCTL(addr) |= OTG_FS_DIEPCTL0_STALL;
} else {
OTG_FS_DIEPCTL(addr) &= ~OTG_FS_DIEPCTL0_STALL;
OTG_FS_DIEPCTL(addr) |= OTG_FS_DIEPCTLX_SD0PID;
}
} else {
if (stall) {
OTG_FS_DOEPCTL(addr) |= OTG_FS_DOEPCTL0_STALL;
} else {
OTG_FS_DOEPCTL(addr) &= ~OTG_FS_DOEPCTL0_STALL;
OTG_FS_DOEPCTL(addr) |= OTG_FS_DOEPCTLX_SD0PID;
}
}
}
static u8 stm32f107_ep_stall_get(u8 addr)
{
/* Return non-zero if STALL set. */
if (addr & 0x80)
return
(OTG_FS_DIEPCTL(addr & 0x7f) & OTG_FS_DIEPCTL0_STALL) ? 1 : 0;
else
return (OTG_FS_DOEPCTL(addr) & OTG_FS_DOEPCTL0_STALL) ? 1 : 0;
}
static void stm32f107_ep_nak_set(u8 addr, u8 nak)
{
/* It does not make sence to force NAK on IN endpoints. */
if (addr & 0x80)
return;
force_nak[addr] = nak;
if (nak)
OTG_FS_DOEPCTL(addr) |= OTG_FS_DOEPCTL0_SNAK;
else
OTG_FS_DOEPCTL(addr) |= OTG_FS_DOEPCTL0_CNAK;
}
static u16 stm32f107_ep_write_packet(u8 addr, const void *buf, u16 len)
{
const u32 *buf32 = buf;
int i;
addr &= 0x7F;
/* Return if endpoint is already enabled. */
if (OTG_FS_DIEPTSIZ(addr) & OTG_FS_DIEPSIZ0_PKTCNT)
return 0;
/* Enable endpoint for transmission. */
OTG_FS_DIEPTSIZ(addr) = (1 << 19) | len;
OTG_FS_DIEPCTL(addr) |= OTG_FS_DIEPCTL0_EPENA | OTG_FS_DIEPCTL0_CNAK;
/* Copy buffer to endpoint FIFO. */
volatile u32 *fifo = OTG_FS_FIFO(addr);
for (i = len; i > 0; i -= 4)
*fifo++ = *buf32++;
return len;
}
/*
* Received packet size for each endpoint. This is assigned in
* stm32f107_poll() which reads the packet status push register GRXSTSP
* for use in stm32f107_ep_read_packet().
*/
static uint16_t rxbcnt;
static u16 stm32f107_ep_read_packet(u8 addr, void *buf, u16 len)
{
int i;
u32 *buf32 = buf;
u32 extra;
len = MIN(len, rxbcnt);
rxbcnt -= len;
volatile u32 *fifo = OTG_FS_FIFO(addr);
for (i = len; i >= 4; i -= 4)
*buf32++ = *fifo++;
if (i) {
extra = *fifo++;
memcpy(buf32, &extra, i);
}
OTG_FS_DOEPTSIZ(addr) = doeptsiz[addr];
OTG_FS_DOEPCTL(addr) |= OTG_FS_DOEPCTL0_EPENA |
(force_nak[addr] ? OTG_FS_DOEPCTL0_SNAK : OTG_FS_DOEPCTL0_CNAK);
return len;
}
static void stm32f107_poll(void)
{
/* Read interrupt status register. */
u32 intsts = OTG_FS_GINTSTS;
int i;
if (intsts & OTG_FS_GINTSTS_ENUMDNE) {
/* Handle USB RESET condition. */
OTG_FS_GINTSTS = OTG_FS_GINTSTS_ENUMDNE;
fifo_mem_top = RX_FIFO_SIZE;
_usbd_reset();
return;
}
/* Note: RX and TX handled differently in this device. */
if (intsts & OTG_FS_GINTSTS_RXFLVL) {
/* Receive FIFO non-empty. */
u32 rxstsp = OTG_FS_GRXSTSP;
u32 pktsts = rxstsp & OTG_FS_GRXSTSP_PKTSTS_MASK;
if ((pktsts != OTG_FS_GRXSTSP_PKTSTS_OUT) &&
(pktsts != OTG_FS_GRXSTSP_PKTSTS_SETUP))
return;
u8 ep = rxstsp & OTG_FS_GRXSTSP_EPNUM_MASK;
u8 type;
if (pktsts == OTG_FS_GRXSTSP_PKTSTS_SETUP)
type = USB_TRANSACTION_SETUP;
else
type = USB_TRANSACTION_OUT;
/* Save packet size for stm32f107_ep_read_packet(). */
rxbcnt = (rxstsp & OTG_FS_GRXSTSP_BCNT_MASK) >> 4;
/*
* FIXME: Why is a delay needed here?
* This appears to fix a problem where the first 4 bytes
* of the DATA OUT stage of a control transaction are lost.
*/
for (i = 0; i < 1000; i++)
__asm__("nop");
if (_usbd_device.user_callback_ctr[ep][type])
_usbd_device.user_callback_ctr[ep][type] (ep);
/* Discard unread packet data. */
for (i = 0; i < rxbcnt; i += 4)
(void)*OTG_FS_FIFO(ep);
rxbcnt = 0;
}
/*
* There is no global interrupt flag for transmit complete.
* The XFRC bit must be checked in each OTG_FS_DIEPINT(x).
*/
for (i = 0; i < 4; i++) { /* Iterate over endpoints. */
if (OTG_FS_DIEPINT(i) & OTG_FS_DIEPINTX_XFRC) {
/* Transfer complete. */
if (_usbd_device.
user_callback_ctr[i][USB_TRANSACTION_IN]) {
_usbd_device.
user_callback_ctr[i][USB_TRANSACTION_IN](i);
}
OTG_FS_DIEPINT(i) = OTG_FS_DIEPINTX_XFRC;
}
}
if (intsts & OTG_FS_GINTSTS_USBSUSP) {
if (_usbd_device.user_callback_suspend)
_usbd_device.user_callback_suspend();
OTG_FS_GINTSTS = OTG_FS_GINTSTS_USBSUSP;
}
if (intsts & OTG_FS_GINTSTS_WKUPINT) {
if (_usbd_device.user_callback_resume)
_usbd_device.user_callback_resume();
OTG_FS_GINTSTS = OTG_FS_GINTSTS_WKUPINT;
}
if (intsts & OTG_FS_GINTSTS_SOF) {
if (_usbd_device.user_callback_sof)
_usbd_device.user_callback_sof();
OTG_FS_GINTSTS = OTG_FS_GINTSTS_SOF;
}
}
static void stm32f107_disconnect(bool disconnected)
{
if (disconnected) {
OTG_FS_DCTL |= OTG_FS_DCTL_SDIS;
} else {
OTG_FS_DCTL &= ~OTG_FS_DCTL_SDIS;
}
return &usbd_dev;
}

91
lib/usb/usb_f207.c Normal file
View File

@@ -0,0 +1,91 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <libopencm3/cm3/common.h>
#include <libopencm3/stm32/tools.h>
#include <libopencm3/stm32/otg_hs.h>
#include <libopencm3/usb/usbd.h>
#include "usb_private.h"
#include "usb_fx07_common.h"
/* Receive FIFO size in 32-bit words. */
#define RX_FIFO_SIZE 512
static usbd_device *stm32f207_usbd_init(void);
static struct _usbd_device usbd_dev;
const struct _usbd_driver stm32f207_usb_driver = {
.init = stm32f207_usbd_init,
.set_address = stm32fx07_set_address,
.ep_setup = stm32fx07_ep_setup,
.ep_reset = stm32fx07_endpoints_reset,
.ep_stall_set = stm32fx07_ep_stall_set,
.ep_stall_get = stm32fx07_ep_stall_get,
.ep_nak_set = stm32fx07_ep_nak_set,
.ep_write_packet = stm32fx07_ep_write_packet,
.ep_read_packet = stm32fx07_ep_read_packet,
.poll = stm32fx07_poll,
.disconnect = stm32fx07_disconnect,
.base_address = USB_OTG_HS_BASE,
.set_address_before_status = 1,
.rx_fifo_size = RX_FIFO_SIZE,
};
/** Initialize the USB device controller hardware of the STM32. */
static usbd_device *stm32f207_usbd_init(void)
{
OTG_HS_GINTSTS = OTG_HS_GINTSTS_MMIS;
OTG_HS_GUSBCFG |= OTG_HS_GUSBCFG_PHYSEL;
/* Enable VBUS sensing in device mode and power down the PHY. */
OTG_HS_GCCFG |= OTG_HS_GCCFG_VBUSBSEN | OTG_HS_GCCFG_PWRDWN;
/* Wait for AHB idle. */
while (!(OTG_HS_GRSTCTL & OTG_HS_GRSTCTL_AHBIDL)) ;
/* Do core soft reset. */
OTG_HS_GRSTCTL |= OTG_HS_GRSTCTL_CSRST;
while (OTG_HS_GRSTCTL & OTG_HS_GRSTCTL_CSRST) ;
/* Force peripheral only mode. */
OTG_HS_GUSBCFG |= OTG_HS_GUSBCFG_FDMOD | OTG_HS_GUSBCFG_TRDT_MASK;
/* Full speed device. */
OTG_HS_DCFG |= OTG_HS_DCFG_DSPD;
/* Restart the PHY clock. */
OTG_HS_PCGCCTL = 0;
OTG_HS_GRXFSIZ = stm32f207_usb_driver.rx_fifo_size;
usbd_dev.fifo_mem_top = stm32f207_usb_driver.rx_fifo_size;
/* Unmask interrupts for TX and RX. */
OTG_HS_GAHBCFG |= OTG_HS_GAHBCFG_GINT;
OTG_HS_GINTMSK = OTG_HS_GINTMSK_ENUMDNEM |
OTG_HS_GINTMSK_RXFLVLM |
OTG_HS_GINTMSK_IEPINT |
OTG_HS_GINTMSK_USBSUSPM |
OTG_HS_GINTMSK_WUIM |
OTG_HS_GINTMSK_SOFM;
OTG_HS_DAINTMSK = 0xF;
OTG_HS_DIEPMSK = OTG_HS_DIEPMSK_XFRCM;
return &usbd_dev;
}

318
lib/usb/usb_fx07_common.c Normal file
View File

@@ -0,0 +1,318 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <libopencm3/cm3/common.h>
#include <libopencm3/stm32/tools.h>
#include <libopencm3/stm32/otg_fs.h>
#include <libopencm3/stm32/otg_hs.h>
#include <libopencm3/usb/usbd.h>
#include "usb_private.h"
#include "usb_fx07_common.h"
/* The FS core and the HS core have the same register layout.
* As the code can be used on both cores, the registers offset is modified
* according to the selected cores base address. */
#define dev_base_address (usbd_dev->driver->base_address)
#define REBASE(x) MMIO32((x)+(dev_base_address))
#define REBASE_FIFO(x) ((volatile u32*)((dev_base_address) + (OTG_FIFO(x))))
void stm32fx07_set_address(usbd_device *usbd_dev, u8 addr)
{
REBASE(OTG_DCFG) = (REBASE(OTG_DCFG) & ~OTG_FS_DCFG_DAD) | (addr << 4);
}
void stm32fx07_ep_setup(usbd_device *usbd_dev, u8 addr, u8 type, u16 max_size,
void (*callback) (usbd_device *usbd_dev, u8 ep))
{
/*
* Configure endpoint address and type. Allocate FIFO memory for
* endpoint. Install callback funciton.
*/
u8 dir = addr & 0x80;
addr &= 0x7f;
if (addr == 0) { /* For the default control endpoint */
/* Configure IN part. */
if (max_size >= 64) {
REBASE(OTG_DIEPCTL0) = OTG_FS_DIEPCTL0_MPSIZ_64;
} else if (max_size >= 32) {
REBASE(OTG_DIEPCTL0) = OTG_FS_DIEPCTL0_MPSIZ_32;
} else if (max_size >= 16) {
REBASE(OTG_DIEPCTL0) = OTG_FS_DIEPCTL0_MPSIZ_16;
} else {
REBASE(OTG_DIEPCTL0) = OTG_FS_DIEPCTL0_MPSIZ_8;
}
REBASE(OTG_DIEPTSIZ0) =
(max_size & OTG_FS_DIEPSIZ0_XFRSIZ_MASK);
REBASE(OTG_DIEPCTL0) |=
OTG_FS_DIEPCTL0_EPENA | OTG_FS_DIEPCTL0_SNAK;
/* Configure OUT part. */
usbd_dev->doeptsiz[0] = OTG_FS_DIEPSIZ0_STUPCNT_1 |
OTG_FS_DIEPSIZ0_PKTCNT |
(max_size & OTG_FS_DIEPSIZ0_XFRSIZ_MASK);
REBASE(OTG_DOEPTSIZ(0)) = usbd_dev->doeptsiz[0];
REBASE(OTG_DOEPCTL(0)) |=
OTG_FS_DOEPCTL0_EPENA | OTG_FS_DIEPCTL0_SNAK;
REBASE(OTG_GNPTXFSIZ) = ((max_size / 4) << 16) |
usbd_dev->driver->rx_fifo_size;
usbd_dev->fifo_mem_top += max_size / 4;
usbd_dev->fifo_mem_top_ep0 = usbd_dev->fifo_mem_top;
return;
}
if (dir) {
REBASE(OTG_DIEPTXF(addr)) = ((max_size / 4) << 16) |
usbd_dev->fifo_mem_top;
usbd_dev->fifo_mem_top += max_size / 4;
REBASE(OTG_DIEPTSIZ(addr)) =
(max_size & OTG_FS_DIEPSIZ0_XFRSIZ_MASK);
REBASE(OTG_DIEPCTL(addr)) |=
OTG_FS_DIEPCTL0_EPENA | OTG_FS_DIEPCTL0_SNAK | (type << 18)
| OTG_FS_DIEPCTL0_USBAEP | OTG_FS_DIEPCTLX_SD0PID
| (addr << 22) | max_size;
if (callback) {
usbd_dev->user_callback_ctr[addr][USB_TRANSACTION_IN] =
(void *)callback;
}
}
if (!dir) {
usbd_dev->doeptsiz[addr] = OTG_FS_DIEPSIZ0_PKTCNT |
(max_size & OTG_FS_DIEPSIZ0_XFRSIZ_MASK);
REBASE(OTG_DOEPTSIZ(addr)) = usbd_dev->doeptsiz[addr];
REBASE(OTG_DOEPCTL(addr)) |= OTG_FS_DOEPCTL0_EPENA |
OTG_FS_DOEPCTL0_USBAEP | OTG_FS_DIEPCTL0_CNAK |
OTG_FS_DOEPCTLX_SD0PID | (type << 18) | max_size;
if (callback) {
usbd_dev->user_callback_ctr[addr][USB_TRANSACTION_OUT] =
(void *)callback;
}
}
}
void stm32fx07_endpoints_reset(usbd_device *usbd_dev)
{
/* The core resets the endpoints automatically on reset. */
usbd_dev->fifo_mem_top = usbd_dev->fifo_mem_top_ep0;
}
void stm32fx07_ep_stall_set(usbd_device *usbd_dev, u8 addr, u8 stall)
{
if (addr == 0) {
if (stall)
REBASE(OTG_DIEPCTL(addr)) |= OTG_FS_DIEPCTL0_STALL;
else
REBASE(OTG_DIEPCTL(addr)) &= ~OTG_FS_DIEPCTL0_STALL;
}
if (addr & 0x80) {
addr &= 0x7F;
if (stall) {
REBASE(OTG_DIEPCTL(addr)) |= OTG_FS_DIEPCTL0_STALL;
} else {
REBASE(OTG_DIEPCTL(addr)) &= ~OTG_FS_DIEPCTL0_STALL;
REBASE(OTG_DIEPCTL(addr)) |= OTG_FS_DIEPCTLX_SD0PID;
}
} else {
if (stall) {
REBASE(OTG_DOEPCTL(addr)) |= OTG_FS_DOEPCTL0_STALL;
} else {
REBASE(OTG_DOEPCTL(addr)) &= ~OTG_FS_DOEPCTL0_STALL;
REBASE(OTG_DOEPCTL(addr)) |= OTG_FS_DOEPCTLX_SD0PID;
}
}
}
u8 stm32fx07_ep_stall_get(usbd_device *usbd_dev, u8 addr)
{
/* Return non-zero if STALL set. */
if (addr & 0x80)
return (REBASE(OTG_DIEPCTL(addr & 0x7f)) &
OTG_FS_DIEPCTL0_STALL) ? 1 : 0;
else
return (REBASE(OTG_DOEPCTL(addr)) &
OTG_FS_DOEPCTL0_STALL) ? 1 : 0;
}
void stm32fx07_ep_nak_set(usbd_device *usbd_dev, u8 addr, u8 nak)
{
/* It does not make sence to force NAK on IN endpoints. */
if (addr & 0x80)
return;
usbd_dev->force_nak[addr] = nak;
if (nak)
REBASE(OTG_DOEPCTL(addr)) |= OTG_FS_DOEPCTL0_SNAK;
else
REBASE(OTG_DOEPCTL(addr)) |= OTG_FS_DOEPCTL0_CNAK;
}
u16 stm32fx07_ep_write_packet(usbd_device *usbd_dev, u8 addr,
const void *buf, u16 len)
{
const u32 *buf32 = buf;
int i;
addr &= 0x7F;
/* Return if endpoint is already enabled. */
if (REBASE(OTG_DIEPTSIZ(addr)) & OTG_FS_DIEPSIZ0_PKTCNT)
return 0;
/* Enable endpoint for transmission. */
REBASE(OTG_DIEPTSIZ(addr)) = OTG_FS_DIEPSIZ0_PKTCNT | len;
REBASE(OTG_DIEPCTL(addr)) |= OTG_FS_DIEPCTL0_EPENA |
OTG_FS_DIEPCTL0_CNAK;
volatile u32 *fifo = REBASE_FIFO(addr);
/* Copy buffer to endpoint FIFO, note - memcpy does not work */
for (i = len; i > 0; i -= 4)
*fifo++ = *buf32++;
return len;
}
u16 stm32fx07_ep_read_packet(usbd_device *usbd_dev, u8 addr, void *buf, u16 len)
{
int i;
u32 *buf32 = buf;
u32 extra;
len = MIN(len, usbd_dev->rxbcnt);
usbd_dev->rxbcnt -= len;
volatile u32 *fifo = REBASE_FIFO(addr);
for (i = len; i >= 4; i -= 4)
*buf32++ = *fifo++;
if (i) {
extra = *fifo++;
memcpy(buf32, &extra, i);
}
REBASE(OTG_DOEPTSIZ(addr)) = usbd_dev->doeptsiz[addr];
REBASE(OTG_DOEPCTL(addr)) |= OTG_FS_DOEPCTL0_EPENA |
(usbd_dev->force_nak[addr] ?
OTG_FS_DOEPCTL0_SNAK : OTG_FS_DOEPCTL0_CNAK);
return len;
}
void stm32fx07_poll(usbd_device *usbd_dev)
{
/* Read interrupt status register. */
u32 intsts = REBASE(OTG_GINTSTS);
int i;
if (intsts & OTG_FS_GINTSTS_ENUMDNE) {
/* Handle USB RESET condition. */
REBASE(OTG_GINTSTS) = OTG_FS_GINTSTS_ENUMDNE;
usbd_dev->fifo_mem_top = usbd_dev->driver->rx_fifo_size;
_usbd_reset(usbd_dev);
return;
}
/* Note: RX and TX handled differently in this device. */
if (intsts & OTG_FS_GINTSTS_RXFLVL) {
/* Receive FIFO non-empty. */
u32 rxstsp = REBASE(OTG_GRXSTSP);
u32 pktsts = rxstsp & OTG_FS_GRXSTSP_PKTSTS_MASK;
if ((pktsts != OTG_FS_GRXSTSP_PKTSTS_OUT) &&
(pktsts != OTG_FS_GRXSTSP_PKTSTS_SETUP))
return;
u8 ep = rxstsp & OTG_FS_GRXSTSP_EPNUM_MASK;
u8 type;
if (pktsts == OTG_FS_GRXSTSP_PKTSTS_SETUP)
type = USB_TRANSACTION_SETUP;
else
type = USB_TRANSACTION_OUT;
/* Save packet size for stm32f107_ep_read_packet(). */
usbd_dev->rxbcnt = (rxstsp & OTG_FS_GRXSTSP_BCNT_MASK) >> 4;
/*
* FIXME: Why is a delay needed here?
* This appears to fix a problem where the first 4 bytes
* of the DATA OUT stage of a control transaction are lost.
*/
for (i = 0; i < 1000; i++)
__asm__("nop");
if (usbd_dev->user_callback_ctr[ep][type])
usbd_dev->user_callback_ctr[ep][type] (usbd_dev, ep);
/* Discard unread packet data. */
for (i = 0; i < usbd_dev->rxbcnt; i += 4)
(void)*REBASE_FIFO(ep);
usbd_dev->rxbcnt = 0;
}
/*
* There is no global interrupt flag for transmit complete.
* The XFRC bit must be checked in each OTG_FS_DIEPINT(x).
*/
for (i = 0; i < 4; i++) { /* Iterate over endpoints. */
if (REBASE(OTG_DIEPINT(i)) & OTG_FS_DIEPINTX_XFRC) {
/* Transfer complete. */
if (usbd_dev->user_callback_ctr[i][USB_TRANSACTION_IN])
usbd_dev->user_callback_ctr[i]
[USB_TRANSACTION_IN](usbd_dev, i);
REBASE(OTG_DIEPINT(i)) = OTG_FS_DIEPINTX_XFRC;
}
}
if (intsts & OTG_FS_GINTSTS_USBSUSP) {
if (usbd_dev->user_callback_suspend)
usbd_dev->user_callback_suspend();
REBASE(OTG_GINTSTS) = OTG_FS_GINTSTS_USBSUSP;
}
if (intsts & OTG_FS_GINTSTS_WKUPINT) {
if (usbd_dev->user_callback_resume)
usbd_dev->user_callback_resume();
REBASE(OTG_GINTSTS) = OTG_FS_GINTSTS_WKUPINT;
}
if (intsts & OTG_FS_GINTSTS_SOF) {
if (usbd_dev->user_callback_sof)
usbd_dev->user_callback_sof();
REBASE(OTG_GINTSTS) = OTG_FS_GINTSTS_SOF;
}
}
void stm32fx07_disconnect(usbd_device *usbd_dev, bool disconnected)
{
if (disconnected) {
REBASE(OTG_DCTL) |= OTG_FS_DCTL_SDIS;
} else {
REBASE(OTG_DCTL) &= ~OTG_FS_DCTL_SDIS;
}
}

38
lib/usb/usb_fx07_common.h Normal file
View File

@@ -0,0 +1,38 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __USB_FX07_COMMON_H_
#define __USB_FX07_COMMON_H_
void stm32fx07_set_address(usbd_device *usbd_dev, u8 addr);
void stm32fx07_ep_setup(usbd_device *usbd_dev, u8 addr, u8 type, u16 max_size,
void (*callback)(usbd_device *usbd_dev, u8 ep));
void stm32fx07_endpoints_reset(usbd_device *usbd_dev);
void stm32fx07_ep_stall_set(usbd_device *usbd_dev, u8 addr, u8 stall);
u8 stm32fx07_ep_stall_get(usbd_device *usbd_dev, u8 addr);
void stm32fx07_ep_nak_set(usbd_device *usbd_dev, u8 addr, u8 nak);
u16 stm32fx07_ep_write_packet(usbd_device *usbd_dev, u8 addr, const void *buf,
u16 len);
u16 stm32fx07_ep_read_packet(usbd_device *usbd_dev, u8 addr, void *buf,
u16 len);
void stm32fx07_poll(usbd_device *usbd_dev);
void stm32fx07_disconnect(usbd_device *usbd_dev, bool disconnected);
#endif /* __USB_FX07_COMMON_H_ */

View File

@@ -25,7 +25,7 @@
#define MIN(a, b) ((a)<(b) ? (a) : (b))
/** Internal collection of device information. */
extern struct _usbd_device {
struct _usbd_device {
const struct usb_device_descriptor *desc;
const struct usb_config_descriptor *config;
const char **strings;
@@ -45,19 +45,49 @@ extern struct _usbd_device {
void (*user_callback_resume)(void);
void (*user_callback_sof)(void);
struct usb_control_state {
enum {
IDLE, STALLED,
DATA_IN, LAST_DATA_IN, STATUS_IN,
DATA_OUT, LAST_DATA_OUT, STATUS_OUT,
} state;
struct usb_setup_data req __attribute__((aligned(4)));
u8 *ctrl_buf;
u16 ctrl_len;
void (*complete)(usbd_device *usbd_dev,
struct usb_setup_data *req);
} control_state;
struct user_control_callback {
usbd_control_callback cb;
u8 type;
u8 type_mask;
} user_control_callback[MAX_USER_CONTROL_CALLBACK];
void (*user_callback_ctr[8][3])(u8 ea);
void (*user_callback_ctr[8][3])(usbd_device *usbd_dev, u8 ea);
/* User callback function for some standard USB function hooks */
void (*user_callback_set_config)(u16 wValue);
void (*user_callback_set_config)(usbd_device *usbd_dev, u16 wValue);
const struct _usbd_driver *driver;
} _usbd_device;
/* private driver data */
uint16_t fifo_mem_top;
uint16_t fifo_mem_top_ep0;
u8 force_nak[4];
/*
* We keep a backup copy of the out endpoint size registers to restore them
* after a transaction.
*/
u32 doeptsiz[4];
/*
* Received packet size for each endpoint. This is assigned in
* stm32f107_poll() which reads the packet status push register GRXSTSP
* for use in stm32f107_ep_read_packet().
*/
uint16_t rxbcnt;
};
enum _usbd_transaction {
USB_TRANSACTION_IN,
@@ -65,31 +95,34 @@ enum _usbd_transaction {
USB_TRANSACTION_SETUP,
};
void _usbd_control_in(u8 ea);
void _usbd_control_out(u8 ea);
void _usbd_control_setup(u8 ea);
void _usbd_control_in(usbd_device *usbd_dev, u8 ea);
void _usbd_control_out(usbd_device *usbd_dev, u8 ea);
void _usbd_control_setup(usbd_device *usbd_dev, u8 ea);
int _usbd_standard_request(struct usb_setup_data *req, u8 **buf, u16 *len);
int _usbd_standard_request(usbd_device *usbd_dev, struct usb_setup_data *req,
u8 **buf, u16 *len);
void _usbd_reset(void);
void _usbd_reset(usbd_device *usbd_dev);
/* Functions provided by the hardware abstraction. */
struct _usbd_driver {
void (*init)(void);
void (*set_address)(u8 addr);
void (*ep_setup)(u8 addr, u8 type, u16 max_size, void (*cb)(u8 ep));
void (*ep_reset)(void);
void (*ep_stall_set)(u8 addr, u8 stall);
void (*ep_nak_set)(u8 addr, u8 nak);
u8 (*ep_stall_get)(u8 addr);
u16 (*ep_write_packet)(u8 addr, const void *buf, u16 len);
u16 (*ep_read_packet)(u8 addr, void *buf, u16 len);
void (*poll)(void);
void (*disconnect)(bool disconnected);
usbd_device *(*init)(void);
void (*set_address)(usbd_device *usbd_dev, u8 addr);
void (*ep_setup)(usbd_device *usbd_dev, u8 addr, u8 type, u16 max_size,
void (*cb)(usbd_device *usbd_dev, u8 ep));
void (*ep_reset)(usbd_device *usbd_dev);
void (*ep_stall_set)(usbd_device *usbd_dev, u8 addr, u8 stall);
void (*ep_nak_set)(usbd_device *usbd_dev, u8 addr, u8 nak);
u8 (*ep_stall_get)(usbd_device *usbd_dev, u8 addr);
u16 (*ep_write_packet)(usbd_device *usbd_dev, u8 addr, const void *buf,
u16 len);
u16 (*ep_read_packet)(usbd_device *usbd_dev, u8 addr, void *buf,
u16 len);
void (*poll)(usbd_device *usbd_dev);
void (*disconnect)(usbd_device *usbd_dev, bool disconnected);
u32 base_address;
bool set_address_before_status;
u16 rx_fifo_size;
};
#define _usbd_hw_init() _usbd_device.driver->init()
#define _usbd_hw_set_address(addr) _usbd_device.driver->set_address(addr)
#define _usbd_hw_endpoints_reset() _usbd_device.driver->ep_reset()
#endif

View File

@@ -21,15 +21,18 @@
#include <libopencm3/usb/usbd.h>
#include "usb_private.h"
void usbd_register_set_config_callback(void (*callback)(u16 wValue))
void usbd_register_set_config_callback(usbd_device *usbd_dev,
void (*callback)(usbd_device *usbd_dev,
u16 wValue))
{
_usbd_device.user_callback_set_config = callback;
usbd_dev->user_callback_set_config = callback;
}
static u16 build_config_descriptor(u8 index, u8 *buf, u16 len)
static u16 build_config_descriptor(usbd_device *usbd_dev,
u8 index, u8 *buf, u16 len)
{
u8 *tmpbuf = buf;
const struct usb_config_descriptor *cfg = &_usbd_device.config[index];
const struct usb_config_descriptor *cfg = &usbd_dev->config[index];
u16 count, total = 0, totallen = 0;
u16 i, j, k;
@@ -43,7 +46,7 @@ static u16 build_config_descriptor(u8 index, u8 *buf, u16 len)
for (i = 0; i < cfg->bNumInterfaces; i++) {
/* Interface Association Descriptor, if any */
if (cfg->interface[i].iface_assoc) {
const struct usb_iface_assoc_descriptor *assoc =
const struct usb_iface_assoc_descriptor *assoc =
cfg->interface[i].iface_assoc;
memcpy(buf, assoc, count = MIN(len, assoc->bLength));
buf += count;
@@ -97,7 +100,8 @@ static int usb_descriptor_index(u16 wValue)
return wValue & 0xFF;
}
static int usb_standard_get_descriptor(struct usb_setup_data *req,
static int usb_standard_get_descriptor(usbd_device *usbd_dev,
struct usb_setup_data *req,
u8 **buf, u16 *len)
{
int i, array_idx, descr_idx;
@@ -107,15 +111,15 @@ static int usb_standard_get_descriptor(struct usb_setup_data *req,
switch (usb_descriptor_type(req->wValue)) {
case USB_DT_DEVICE:
*buf = (u8 *) _usbd_device.desc;
*len = MIN(*len, _usbd_device.desc->bLength);
*buf = (u8 *) usbd_dev->desc;
*len = MIN(*len, usbd_dev->desc->bLength);
return USBD_REQ_HANDLED;
case USB_DT_CONFIGURATION:
*buf = _usbd_device.ctrl_buf;
*len = build_config_descriptor(descr_idx, *buf, *len);
*buf = usbd_dev->ctrl_buf;
*len = build_config_descriptor(usbd_dev, descr_idx, *buf, *len);
return USBD_REQ_HANDLED;
case USB_DT_STRING:
sd = (struct usb_string_descriptor *)_usbd_device.ctrl_buf;
sd = (struct usb_string_descriptor *)usbd_dev->ctrl_buf;
if (descr_idx == 0) {
/* Send sane Language ID descriptor... */
@@ -127,10 +131,10 @@ static int usb_standard_get_descriptor(struct usb_setup_data *req,
} else {
array_idx = descr_idx - 1;
if (!_usbd_device.strings)
if (!usbd_dev->strings)
return USBD_REQ_NOTSUPP; /* Device doesn't support strings. */
/* Check that string index is in range. */
if (array_idx >= _usbd_device.num_strings)
if (array_idx >= usbd_dev->num_strings)
return USBD_REQ_NOTSUPP;
/* Strings with Language ID differnet from
@@ -139,14 +143,14 @@ static int usb_standard_get_descriptor(struct usb_setup_data *req,
return USBD_REQ_NOTSUPP;
/* Ths string is returned as UTF16, hence the multiplication */
sd->bLength = strlen(_usbd_device.strings[array_idx]) * 2 +
sd->bLength = strlen(usbd_dev->strings[array_idx]) * 2 +
sizeof(sd->bLength) + sizeof(sd->bDescriptorType);
*len = MIN(*len, sd->bLength);
for (i = 0; i < (*len / 2) - 1; i++)
sd->wData[i] =
_usbd_device.strings[array_idx][i];
usbd_dev->strings[array_idx][i];
}
sd->bDescriptorType = USB_DT_STRING;
@@ -157,7 +161,8 @@ static int usb_standard_get_descriptor(struct usb_setup_data *req,
return USBD_REQ_NOTSUPP;
}
static int usb_standard_set_address(struct usb_setup_data *req, u8 **buf,
static int usb_standard_set_address(usbd_device *usbd_dev,
struct usb_setup_data *req, u8 **buf,
u16 *len)
{
(void)req;
@@ -168,19 +173,20 @@ static int usb_standard_set_address(struct usb_setup_data *req, u8 **buf,
if ((req->bmRequestType != 0) || (req->wValue >= 128))
return 0;
_usbd_device.current_address = req->wValue;
usbd_dev->current_address = req->wValue;
/*
* Special workaround for STM32F10[57] that require the address
* to be set here. This is undocumented!
*/
if (_usbd_device.driver == &stm32f107_usb_driver)
_usbd_device.driver->set_address(req->wValue);
if ( usbd_dev->driver->set_address_before_status)
usbd_dev->driver->set_address(usbd_dev, req->wValue);
return 1;
}
static int usb_standard_set_configuration(struct usb_setup_data *req,
static int usb_standard_set_configuration(usbd_device *usbd_dev,
struct usb_setup_data *req,
u8 **buf, u16 *len)
{
int i;
@@ -190,43 +196,46 @@ static int usb_standard_set_configuration(struct usb_setup_data *req,
(void)len;
/* Is this correct, or should we reset alternate settings. */
if (req->wValue == _usbd_device.current_config)
if (req->wValue == usbd_dev->current_config)
return 1;
_usbd_device.current_config = req->wValue;
usbd_dev->current_config = req->wValue;
/* Reset all endpoints. */
_usbd_hw_endpoints_reset();
usbd_dev->driver->ep_reset(usbd_dev);
if (_usbd_device.user_callback_set_config) {
if (usbd_dev->user_callback_set_config) {
/*
* Flush control callbacks. These will be reregistered
* by the user handler.
*/
for (i = 0; i < MAX_USER_CONTROL_CALLBACK; i++)
_usbd_device.user_control_callback[i].cb = NULL;
usbd_dev->user_control_callback[i].cb = NULL;
_usbd_device.user_callback_set_config(req->wValue);
usbd_dev->user_callback_set_config(usbd_dev, req->wValue);
}
return 1;
}
static int usb_standard_get_configuration(struct usb_setup_data *req,
static int usb_standard_get_configuration(usbd_device *usbd_dev,
struct usb_setup_data *req,
u8 **buf, u16 *len)
{
(void)req;
if (*len > 1)
*len = 1;
(*buf)[0] = _usbd_device.current_config;
(*buf)[0] = usbd_dev->current_config;
return 1;
}
static int usb_standard_set_interface(struct usb_setup_data *req,
static int usb_standard_set_interface(usbd_device *usbd_dev,
struct usb_setup_data *req,
u8 **buf, u16 *len)
{
(void)usbd_dev;
(void)req;
(void)buf;
@@ -238,9 +247,11 @@ static int usb_standard_set_interface(struct usb_setup_data *req,
return 1;
}
static int usb_standard_get_interface(struct usb_setup_data *req,
static int usb_standard_get_interface(usbd_device *usbd_dev,
struct usb_setup_data *req,
u8 **buf, u16 *len)
{
(void)usbd_dev;
(void)req;
(void)buf;
@@ -251,9 +262,11 @@ static int usb_standard_get_interface(struct usb_setup_data *req,
return 1;
}
static int usb_standard_device_get_status(struct usb_setup_data *req,
static int usb_standard_device_get_status(usbd_device *usbd_dev,
struct usb_setup_data *req,
u8 **buf, u16 *len)
{
(void)usbd_dev;
(void)req;
/* bit 0: self powered */
@@ -266,9 +279,11 @@ static int usb_standard_device_get_status(struct usb_setup_data *req,
return 1;
}
static int usb_standard_interface_get_status(struct usb_setup_data *req,
static int usb_standard_interface_get_status(usbd_device *usbd_dev,
struct usb_setup_data *req,
u8 **buf, u16 *len)
{
(void)usbd_dev;
(void)req;
/* not defined */
@@ -280,45 +295,50 @@ static int usb_standard_interface_get_status(struct usb_setup_data *req,
return 1;
}
static int usb_standard_endpoint_get_status(struct usb_setup_data *req,
static int usb_standard_endpoint_get_status(usbd_device *usbd_dev,
struct usb_setup_data *req,
u8 **buf, u16 *len)
{
(void)req;
if (*len > 2)
*len = 2;
(*buf)[0] = usbd_ep_stall_get(req->wIndex) ? 1 : 0;
(*buf)[0] = usbd_ep_stall_get(usbd_dev, req->wIndex) ? 1 : 0;
(*buf)[1] = 0;
return 1;
}
static int usb_standard_endpoint_stall(struct usb_setup_data *req,
static int usb_standard_endpoint_stall(usbd_device *usbd_dev,
struct usb_setup_data *req,
u8 **buf, u16 *len)
{
(void)buf;
(void)len;
usbd_ep_stall_set(req->wIndex, 1);
usbd_ep_stall_set(usbd_dev, req->wIndex, 1);
return 1;
}
static int usb_standard_endpoint_unstall(struct usb_setup_data *req,
static int usb_standard_endpoint_unstall(usbd_device *usbd_dev,
struct usb_setup_data *req,
u8 **buf, u16 *len)
{
(void)buf;
(void)len;
usbd_ep_stall_set(req->wIndex, 0);
usbd_ep_stall_set(usbd_dev, req->wIndex, 0);
return 1;
}
int _usbd_standard_request_device(struct usb_setup_data *req, u8 **buf,
int _usbd_standard_request_device(usbd_device *usbd_dev,
struct usb_setup_data *req, u8 **buf,
u16 *len)
{
int (*command)(struct usb_setup_data *req, u8 **buf, u16 *len) = NULL;
int (*command)(usbd_device *usbd_dev, struct usb_setup_data *req, u8
**buf, u16 *len) = NULL;
switch (req->bRequest) {
case USB_REQ_CLEAR_FEATURE:
@@ -361,13 +381,15 @@ int _usbd_standard_request_device(struct usb_setup_data *req, u8 **buf,
if (!command)
return 0;
return command(req, buf, len);
return command(usbd_dev, req, buf, len);
}
int _usbd_standard_request_interface(struct usb_setup_data *req, u8 **buf,
int _usbd_standard_request_interface(usbd_device *usbd_dev,
struct usb_setup_data *req, u8 **buf,
u16 *len)
{
int (*command)(struct usb_setup_data *req, u8 **buf, u16 *len) = NULL;
int (*command)(usbd_device *usbd_dev, struct usb_setup_data *req,
u8 **buf, u16 *len) = NULL;
switch (req->bRequest) {
case USB_REQ_CLEAR_FEATURE:
@@ -388,13 +410,15 @@ int _usbd_standard_request_interface(struct usb_setup_data *req, u8 **buf,
if (!command)
return 0;
return command(req, buf, len);
return command(usbd_dev, req, buf, len);
}
int _usbd_standard_request_endpoint(struct usb_setup_data *req, u8 **buf,
int _usbd_standard_request_endpoint(usbd_device *usbd_dev,
struct usb_setup_data *req, u8 **buf,
u16 *len)
{
int (*command) (struct usb_setup_data *req, u8 **buf, u16 *len) = NULL;
int (*command) (usbd_device *usbd_dev, struct usb_setup_data *req,
u8 **buf, u16 *len) = NULL;
switch (req->bRequest) {
case USB_REQ_CLEAR_FEATURE:
@@ -420,10 +444,11 @@ int _usbd_standard_request_endpoint(struct usb_setup_data *req, u8 **buf,
if (!command)
return 0;
return command(req, buf, len);
return command(usbd_dev, req, buf, len);
}
int _usbd_standard_request(struct usb_setup_data *req, u8 **buf, u16 *len)
int _usbd_standard_request(usbd_device *usbd_dev,
struct usb_setup_data *req, u8 **buf, u16 *len)
{
/* FIXME: Have class/vendor requests as well. */
if ((req->bmRequestType & USB_REQ_TYPE_TYPE) != USB_REQ_TYPE_STANDARD)
@@ -431,11 +456,12 @@ int _usbd_standard_request(struct usb_setup_data *req, u8 **buf, u16 *len)
switch (req->bmRequestType & USB_REQ_TYPE_RECIPIENT) {
case USB_REQ_TYPE_DEVICE:
return _usbd_standard_request_device(req, buf, len);
return _usbd_standard_request_device(usbd_dev, req, buf, len);
case USB_REQ_TYPE_INTERFACE:
return _usbd_standard_request_interface(req, buf, len);
return _usbd_standard_request_interface(usbd_dev, req,
buf, len);
case USB_REQ_TYPE_ENDPOINT:
return _usbd_standard_request_endpoint(req, buf, len);
return _usbd_standard_request_endpoint(usbd_dev, req, buf, len);
default:
return 0;
}