Add software

This commit is contained in:
RocketGod
2022-09-22 09:26:57 -07:00
parent fee0ab05fd
commit 957ea3d712
4511 changed files with 1943182 additions and 0 deletions

View File

@ -0,0 +1,52 @@
##
## This file is part of the libopencm3 project.
##
## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
## Copyright (C) 2012 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/>.
##
# Be silent per default, but 'make V=1' will show all compiler calls.
ifneq ($(V),1)
Q := @
endif
# common objects
OBJS += vector.o systick.o scb.o nvic.o assert.o sync.o
all: $(SRCLIBDIR)/$(LIBNAME).a
$(SRCLIBDIR)/$(LIBNAME).a: $(SRCLIBDIR)/$(LIBNAME).ld $(OBJS)
@printf " AR $(@F)\n"
$(Q)$(AR) $(ARFLAGS) $@ $(OBJS)
$(SRCLIBDIR)/$(LIBNAME).ld: $(LIBNAME).ld
@printf " CP $(@F)\n"
$(Q)cp $^ $@
$(Q)if [ -f $(LIBNAME)_rom_to_ram.ld ]; then cp $(LIBNAME)_rom_to_ram.ld $(SRCLIBDIR); fi
%.o: %.c
@printf " CC $(<F)\n"
$(Q)$(CC) $(CFLAGS) -o $@ -c $<
clean:
$(Q)rm -f *.o *.d ../*.o ../*.d
$(Q)rm -f $(SRCLIBDIR)/$(LIBNAME).a
$(Q)rm -f $(SRCLIBDIR)/$(LIBNAME).ld
$(Q)rm -f $(SRCLIBDIR)/$(LIBNAME)_rom_to_ram.ld
.PHONY: clean
-include $(OBJS:.o=.d)

View File

@ -0,0 +1,34 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Tomaz Solc <tomaz.solc@tablix.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/>.
*/
#include <libopencm3/cm3/assert.h>
void __attribute__((weak)) cm3_assert_failed(void)
{
while (1);
}
void __attribute__((weak)) cm3_assert_failed_verbose(
const char *file __attribute__((unused)),
int line __attribute__((unused)),
const char *func __attribute__((unused)),
const char *assert_expr __attribute__((unused)))
{
cm3_assert_failed();
}

View File

@ -0,0 +1,199 @@
/*
* 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/>.
*/
/** @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/cm3/nvic.h>
#include <libopencm3/cm3/scs.h>
/*---------------------------------------------------------------------------*/
/** @brief NVIC Enable Interrupt
*
* Enables a user interrupt.
*
* @param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
*/
void nvic_enable_irq(uint8_t irqn)
{
NVIC_ISER(irqn / 32) = (1 << (irqn % 32));
}
/*---------------------------------------------------------------------------*/
/** @brief NVIC Disable Interrupt
*
* Disables a user interrupt.
*
* @param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
*/
void nvic_disable_irq(uint8_t irqn)
{
NVIC_ICER(irqn / 32) = (1 << (irqn % 32));
}
/*---------------------------------------------------------------------------*/
/** @brief NVIC Return Pending Interrupt
*
* True if the interrupt has occurred and is waiting for service.
*
* @param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
* @return Boolean. Interrupt pending.
*/
uint8_t nvic_get_pending_irq(uint8_t irqn)
{
return NVIC_ISPR(irqn / 32) & (1 << (irqn % 32)) ? 1 : 0;
}
/*---------------------------------------------------------------------------*/
/** @brief NVIC Set Pending Interrupt
*
* Force a user interrupt to a pending state. This has no effect if the
* interrupt is already pending.
*
* @param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
*/
void nvic_set_pending_irq(uint8_t irqn)
{
NVIC_ISPR(irqn / 32) = (1 << (irqn % 32));
}
/*---------------------------------------------------------------------------*/
/** @brief NVIC Clear Pending Interrupt
*
* Force remove a user interrupt from a pending state. This has no effect if
* the interrupt is actively being serviced.
*
* @param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
*/
void nvic_clear_pending_irq(uint8_t irqn)
{
NVIC_ICPR(irqn / 32) = (1 << (irqn % 32));
}
/*---------------------------------------------------------------------------*/
/** @brief NVIC Return Enabled Interrupt
*
* @param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
* @return Boolean. Interrupt enabled.
*/
uint8_t nvic_get_irq_enabled(uint8_t irqn)
{
return NVIC_ISER(irqn / 32) & (1 << (irqn % 32)) ? 1 : 0;
}
/*---------------------------------------------------------------------------*/
/** @brief NVIC Set Interrupt Priority
*
* CM3, CM4:
*
* There are 16 priority levels only, given by the upper four bits of the
* priority byte, as required by ARM standards. The priority levels are
* interpreted according to the pre-emptive priority grouping set in the
* SCB Application Interrupt and Reset Control Register (SCB_AIRCR), as done
* in @ref scb_set_priority_grouping.
*
* CM0:
*
* There are 4 priority levels only, given by the upper two bits of the
* priority byte, as required by ARM standards. No grouping available.
*
* @param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
* @param[in] priority Unsigned int8. Interrupt priority (0 ... 255 in steps of
* 16)
*/
void nvic_set_priority(uint8_t irqn, uint8_t 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;
}
}
/* Those are defined only on CM3 or CM4 */
#if defined(__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__)
/*---------------------------------------------------------------------------*/
/** @brief NVIC Return Active Interrupt
*
* Interrupt has occurred and is currently being serviced.
*
* @param[in] irqn Unsigned int8. Interrupt number @ref nvic_stm32f1_userint
* @return Boolean. Interrupt active.
*/
uint8_t nvic_get_active_irq(uint8_t irqn)
{
return NVIC_IABR(irqn / 32) & (1 << (irqn % 32)) ? 1 : 0;
}
/*---------------------------------------------------------------------------*/
/** @brief NVIC Software Trigger Interrupt
*
* Generate an interrupt from software. This has no effect for unprivileged
* access unless the privilege level has been elevated through the System
* Control Registers.
*
* @param[in] irqn Unsigned int16. Interrupt number (0 ... 239)
*/
void nvic_generate_software_interrupt(uint16_t irqn)
{
if (irqn <= 239) {
NVIC_STIR |= irqn;
}
}
#endif
/**@}*/

View File

@ -0,0 +1,47 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 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 <stdlib.h>
#include <libopencm3/cm3/scb.h>
/* Those are defined only on CM3 or CM4 */
#if defined(__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__)
void scb_reset_core(void)
{
SCB_AIRCR = SCB_AIRCR_VECTKEY | SCB_AIRCR_VECTRESET;
while (1);
}
#endif
void scb_reset_system(void)
{
SCB_AIRCR = SCB_AIRCR_VECTKEY | SCB_AIRCR_SYSRESETREQ;
while (1);
}
/* Those are defined only on CM3 or CM4 */
#if defined(__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__)
void scb_set_priority_grouping(uint32_t prigroup)
{
SCB_AIRCR = SCB_AIRCR_VECTKEY | prigroup;
}
#endif

View File

@ -0,0 +1,75 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 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/sync.h>
/* DMB is supported on CM0 */
void __dmb()
{
__asm__ volatile ("dmb");
}
/* Those are defined only on CM3 or CM4 */
#if defined(__ARM_ARCH_6M__)
#warning "sync not supported on ARMv6-M arch"
#else
uint32_t __ldrex(volatile uint32_t *addr)
{
uint32_t res;
__asm__ volatile ("ldrex %0, [%1]" : "=r" (res) : "r" (addr));
return res;
}
uint32_t __strex(uint32_t val, volatile uint32_t *addr)
{
uint32_t res;
__asm__ volatile ("strex %0, %2, [%1]"
: "=&r" (res) : "r" (addr), "r" (val));
return res;
}
void mutex_lock(mutex_t *m)
{
uint32_t status = 0;
do {
/* Wait until the mutex is unlocked. */
while (__ldrex(m) != MUTEX_UNLOCKED);
/* Try to acquire it. */
status = __strex(MUTEX_LOCKED, m);
/* Did we get it? If not then try again. */
} while (status != 0);
/* Execute the mysterious Data Memory Barrier instruction! */
__dmb();
}
void mutex_unlock(mutex_t *m)
{
/* Ensure accesses to protected resource are finished */
__dmb();
/* Free the lock. */
*m = MUTEX_UNLOCKED;
}
#endif

View File

@ -0,0 +1,156 @@
/*
* 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/>.
*/
/** @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/cm3/systick.h>
/*---------------------------------------------------------------------------*/
/** @brief SysTick Set the Automatic Reload Value.
*
* The counter is set to the reload value when the counter starts and after it
* reaches zero.
*
* @param[in] value uint32_t. 24 bit reload value.
*/
void systick_set_reload(uint32_t value)
{
STK_RVR = (value & STK_RVR_RELOAD);
}
/*---------------------------------------------------------------------------*/
/** @brief SysTick Read the Automatic Reload Value.
*
* @returns 24 bit reload value as uint32_t.
*/
uint32_t systick_get_reload(void)
{
return STK_RVR & STK_RVR_RELOAD;
}
/*---------------------------------------------------------------------------*/
/** @brief Get the current SysTick counter value.
*
* @returns 24 bit current value as uint32_t.
*/
uint32_t systick_get_value(void)
{
return STK_CVR & STK_CVR_CURRENT;
}
/*---------------------------------------------------------------------------*/
/** @brief Set the SysTick Clock Source.
*
* The clock source can be either the AHB clock or the same clock divided by 8.
*
* @param[in] clocksource uint8_t. Clock source from @ref systick_clksource.
*/
void systick_set_clocksource(uint8_t clocksource)
{
STK_CSR = (STK_CSR & (~STK_CSR_CLKSOURCE)) | (clocksource << STK_CSR_CLKSOURCE_LSB);
}
/*---------------------------------------------------------------------------*/
/** @brief Enable SysTick Interrupt.
*
*/
void systick_interrupt_enable(void)
{
STK_CSR |= STK_CSR_TICKINT;
}
/*---------------------------------------------------------------------------*/
/** @brief Disable SysTick Interrupt.
*
*/
void systick_interrupt_disable(void)
{
STK_CSR &= ~STK_CSR_TICKINT;
}
/*---------------------------------------------------------------------------*/
/** @brief Enable SysTick Counter.
*
*/
void systick_counter_enable(void)
{
STK_CSR |= STK_CSR_ENABLE;
}
/*---------------------------------------------------------------------------*/
/** @brief Disable SysTick Counter.
*
*/
void systick_counter_disable(void)
{
STK_CSR &= ~STK_CSR_ENABLE;
}
/*---------------------------------------------------------------------------*/
/** @brief SysTick Read the Counter Flag.
*
* The count flag is set when the timer count becomes zero, and is cleared when
* the flag is read.
*
* @returns Boolean if flag set.
*/
uint8_t systick_get_countflag(void)
{
return (STK_CSR & STK_CSR_COUNTFLAG) ? 1 : 0;
}
/*---------------------------------------------------------------------------*/
/** @brief SysTick Get Calibration Value
*
* @returns Current calibration value
*/
uint32_t systick_get_calib(void)
{
return STK_CALIB & STK_CALIB_TENMS;
}
/**@}*/

View File

@ -0,0 +1,121 @@
/*
* This file is part of the libopencm3 project.
*
* 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
* 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/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"
/* Symbols exported by the linker script(s): */
extern unsigned _data_loadaddr, _data, _edata, _bss, _ebss, _stack;
typedef void (*funcp_t) (void);
extern funcp_t __preinit_array_start, __preinit_array_end;
extern funcp_t __init_array_start, __init_array_end;
extern funcp_t __fini_array_start, __fini_array_end;
void main(void);
void blocking_handler(void);
void null_handler(void);
__attribute__ ((section(".vectors")))
vector_table_t vector_table = {
.initial_sp_value = &_stack,
.reset = reset_handler,
.nmi = nmi_handler,
.hard_fault = hard_fault_handler,
/* Those are defined only on CM3 or CM4 */
#if defined(__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__)
.memory_manage_fault = mem_manage_handler,
.bus_fault = bus_fault_handler,
.usage_fault = usage_fault_handler,
.debug_monitor = debug_monitor_handler,
#endif
.sv_call = sv_call_handler,
.pend_sv = pend_sv_handler,
.systick = sys_tick_handler,
.irq = {
IRQ_HANDLERS
}
};
void WEAK __attribute__ ((naked)) reset_handler(void)
{
volatile unsigned *src, *dest;
funcp_t *fp;
for (src = &_data_loadaddr, dest = &_data;
dest < &_edata;
src++, dest++) {
*dest = *src;
}
for (dest = &_bss; dest < &_ebss; ) {
*dest++ = 0;
}
/* Constructors. */
for (fp = &__preinit_array_start; fp < &__preinit_array_end; fp++) {
(*fp)();
}
for (fp = &__init_array_start; fp < &__init_array_end; fp++) {
(*fp)();
}
/* might be provided by platform specific vector.c */
pre_main();
/* Call the application's entry point. */
main();
/* Destructors. */
for (fp = &__fini_array_start; fp < &__fini_array_end; fp++) {
(*fp)();
}
}
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 sv_call_handler = null_handler
#pragma weak pend_sv_handler = null_handler
#pragma weak sys_tick_handler = null_handler
/* Those are defined only on CM3 or CM4 */
#if defined(__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__)
#pragma weak mem_manage_handler = blocking_handler
#pragma weak bus_fault_handler = blocking_handler
#pragma weak usage_fault_handler = blocking_handler
#pragma weak debug_monitor_handler = null_handler
#endif

View File

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

View File

@ -0,0 +1,42 @@
##
## 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 -Wimplicit-function-declaration \
-Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
-Wundef -Wshadow \
-I../../../include -fno-common \
-mcpu=cortex-m3 $(FP_FLAGS) -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,106 @@
/*
* 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 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
{
.text : {
*(.vectors) /* Vector table */
*(.text*) /* Program code */
. = ALIGN(4);
*(.rodata*) /* Read-only data */
. = ALIGN(4);
} >rom
/* C++ Static constructors/destructors, also used for __attribute__
* ((constructor)) and the likes */
.preinit_array : {
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
} >rom
.init_array : {
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
} >rom
.fini_array : {
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
} >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));

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,42 @@
##
## 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 -Wimplicit-function-declaration \
-Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
-Wundef -Wshadow \
-I../../../include -fno-common \
-mcpu=cortex-m3 $(FP_FLAGS) -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,106 @@
/*
* 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 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
{
.text : {
*(.vectors) /* Vector table */
*(.text*) /* Program code */
. = ALIGN(4);
*(.rodata*) /* Read-only data */
. = ALIGN(4);
} >rom
/* C++ Static constructors/destructors, also used for __attribute__
* ((constructor)) and the likes */
.preinit_array : {
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
} >rom
.init_array : {
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
} >rom
.fini_array : {
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
} >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));

View File

@ -0,0 +1,15 @@
/* lengths from d046_efm32gg990_datasheet.pdf table 1.1, offset from
* d0034_efm32tg_reference_manual.pdf figure 5.2.
*
* the origins and memory structure are constant over all giantgeckos, 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 = 1024k
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128k
}
INCLUDE libopencm3_efm32gg.ld;

View File

@ -0,0 +1,42 @@
##
## 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 -Wimplicit-function-declaration \
-Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
-Wundef -Wshadow \
-I../../../include -fno-common \
-mcpu=cortex-m3 $(FP_FLAGS) -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,106 @@
/*
* 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 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
{
.text : {
*(.vectors) /* Vector table */
*(.text*) /* Program code */
. = ALIGN(4);
*(.rodata*) /* Read-only data */
. = ALIGN(4);
} >rom
/* C++ Static constructors/destructors, also used for __attribute__
* ((constructor)) and the likes */
.preinit_array : {
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
} >rom
.init_array : {
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
} >rom
.fini_array : {
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
} >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));

View File

@ -0,0 +1,42 @@
##
## 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 -Wimplicit-function-declaration \
-Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
-Wundef -Wshadow \
-I../../../include -fno-common \
-mcpu=cortex-m3 $(FP_FLAGS) -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,106 @@
/*
* 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 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
{
.text : {
*(.vectors) /* Vector table */
*(.text*) /* Program code */
. = ALIGN(4);
*(.rodata*) /* Read-only data */
. = ALIGN(4);
} >rom
/* C++ Static constructors/destructors, also used for __attribute__
* ((constructor)) and the likes */
.preinit_array : {
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
} >rom
.init_array : {
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
} >rom
.fini_array : {
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
} >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));

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

@ -0,0 +1,180 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
* Copyright (C) 2013 Frantisek Burian <BuFran@seznam.cz>
*
* 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 all targets using libopencm3. */
/* Enforce emmition of the vector table. */
EXTERN(vector_table)
/* Define the entry point of the output file. */
ENTRY(reset_handler)
/* Define memory regions. */
MEMORY
{
/* RAM is always used */
ram (rwx) : ORIGIN = RAM_OFF, LENGTH = RAM
#if defined(ROM)
rom (rx) : ORIGIN = ROM_OFF, LENGTH = ROM
#endif
#if defined(ROM2)
rom2 (rx) : ORIGIN = ROM2_OFF, LENGTH = ROM2
#endif
#if defined(RAM1)
ram1 (rwx) : ORIGIN = RAM1_OFF, LENGTH = RAM1
#endif
#if defined(RAM2)
ram2 (rwx) : ORIGIN = RAM2_OFF, LENGTH = RAM2
#endif
#if defined(CCM)
ccm (rwx) : ORIGIN = CCM_OFF, LENGTH = CCM
#endif
#if defined(EEP)
eep (r) : ORIGIN = EEP_OFF, LENGTH = EEP
#endif
#if defined(XSRAM)
xsram (rw) : ORIGIN = XSRAM_OFF, LENGTH = XSRAM
#endif
#if defined(XDRAM)
xdram (rw) : ORIGIN = XDRAM_OFF, LENGTH = XDRAM
#endif
}
/* Define sections. */
SECTIONS
{
.text : {
*(.vectors) /* Vector table */
*(.text*) /* Program code */
. = ALIGN(4);
*(.rodata*) /* Read-only data */
. = ALIGN(4);
} >rom
/* C++ Static constructors/destructors, also used for
* __attribute__((constructor)) and the likes.
*/
.preinit_array : {
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
} >rom
.init_array : {
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
} >rom
.fini_array : {
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
} >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
#if defined(EEP)
.eep : {
*(.eeprom*)
. = ALIGN(4);
} >eep
#endif
#if defined(CCM)
.ccm : {
*(.ccmram*)
. = ALIGN(4);
} >ccm
#endif
#if defined(RAM1)
.ram1 : {
*(.ram1*)
. = ALIGN(4);
} >ram1
#endif
#if defined(RAM2)
.ram2 : {
*(.ram2*)
. = ALIGN(4);
} >ram2
#endif
#if defined(XSRAM)
.xsram : {
*(.xsram*)
. = ALIGN(4);
} >xsram
#endif
#if defined(XDRAM)
.xdram : {
*(.xdram*)
. = ALIGN(4);
} >xdram
#endif
/*
* 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));

View File

@ -0,0 +1,39 @@
##
## 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_lm3s
PREFIX ?= arm-none-eabi
CC = $(PREFIX)-gcc
AR = $(PREFIX)-ar
CFLAGS = -Os -g \
-Wall -Wextra -Wimplicit-function-declaration \
-Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
-Wundef -Wshadow \
-I../../include -fno-common \
-mcpu=cortex-m3 -mthumb $(FP_FLAGS) -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD -DLM3S
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS = gpio.o vector.o assert.o
VPATH += ../cm3
include ../Makefile.include

View File

@ -0,0 +1,52 @@
/** @defgroup gpio_file General Purpose I/O
@brief <b>LM3S General Purpose I/O</b>
@ingroup LM3Sxx
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2011
Gareth McMullin <gareth@blacksphere.co.nz>
@date 10 March 2013
LGPL License Terms @ref lgpl_license
*/
/*
* 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 <libopencm3/lm3s/gpio.h>
void gpio_set(uint32_t gpioport, uint8_t gpios)
{
/* ipaddr[9:2] mask the bits to be set, hence the array index */
GPIO_DATA(gpioport)[gpios] = 0xff;
}
void gpio_clear(uint32_t gpioport, uint8_t gpios)
{
GPIO_DATA(gpioport)[gpios] = 0;
}
/**@}*/

View File

@ -0,0 +1,106 @@
/*
* 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 LM3S 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
/* C++ Static constructors/destructors, also used for __attribute__
* ((constructor)) and the likes */
.preinit_array : {
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
} >rom
.init_array : {
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
} >rom
.fini_array : {
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
} >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));

View File

@ -0,0 +1,42 @@
##
## This file is part of the libopencm3 project.
##
## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
## Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@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/>.
##
LIBNAME = libopencm3_lm4f
FP_FLAGS ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16
PREFIX ?= arm-none-eabi
CC = $(PREFIX)-gcc
AR = $(PREFIX)-ar
CFLAGS = -Os -g \
-Wall -Wextra -Wimplicit-function-declaration \
-Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
-Wundef -Wshadow \
-I../../include -fno-common \
-mcpu=cortex-m4 -mthumb $(FP_FLAGS) -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD -DLM4F
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS = gpio.o vector.o assert.o systemcontrol.o rcc.o uart.o \
usb_lm4f.o usb.o usb_control.o usb_standard.o
VPATH += ../usb:../cm3
include ../Makefile.include

View File

@ -0,0 +1,598 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz>
* Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@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/>.
*/
/** @defgroup gpio_file GPIO
*
*
* @ingroup LM4Fxx
*
* @version 1.0.0
*
* @author @htmlonly &copy; @endhtmlonly 2011
* Gareth McMullin <gareth@blacksphere.co.nz>
* @author @htmlonly &copy; @endhtmlonly 2013
* Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* @date 16 March 2013
*
* LGPL License Terms @ref lgpl_license
*
* @brief <b>libopencm3 LM4F General Purpose I/O</b>
*
* The LM4F GPIO API provides functionality for accessing the GPIO pins of the
* LM4F.
*
* @attention @code An important aspect to consider is that libopencm3 uses the
* AHB aperture for accessing the GPIO registers on the LM4F. The AHB must be
* explicitly enabled with a call to gpio_enable_ahb_aperture() before accessing
* any GPIO functionality.
* @endcode
*
* Please see the individual GPIO modules for more details. To use the GPIO, the
* gpio.h header needs to be included:
* @code{.c}
* #include <libopencm3/lm4f/gpio.h>
* @endcode
*/
/**@{*/
#include <libopencm3/lm4f/gpio.h>
#include <libopencm3/lm4f/systemcontrol.h>
/* Value we need to write to unlock the GPIO commit register */
#define GPIO_LOCK_UNLOCK_CODE 0x4C4F434B
/** @defgroup gpio_config GPIO pin configuration
* @ingroup gpio_file
*
* \brief <b>Enabling and configuring GPIO pins</b>
*
* @section gpio_api_enable Enabling GPIO ports
* @attention
* Before accessing GPIO functionality through this API, the AHB aperture for
* GPIO ports must be enabled via a call to @ref gpio_enable_ahb_aperture().
* Failing to do so will cause a hard fault.
*
* @note
* Once the AHB aperture is enabled, GPIO registers can no longer be accessed
* via the APB aperture. The two apertures are mutually exclusive.
*
* Enabling the AHB aperture only needs to be done once. However, in order to
* access a certain GPIO port, its clock must also be enabled. Enabling the
* GPIO clock needs to be done for every port that will be used.
*
* For example, to enable GPIOA and GPIOD:
* @code{.c}
* // Make sure we can access the GPIO via the AHB aperture
* gpio_enable_ahb_aperture();
* ...
* // Enable GPIO ports A and D
* periph_clock_enable(RCC_GPIOA);
* periph_clock_enable(RCC_GPIOD);
* @endcode
*
* On reset all ports are configured as digital floating inputs (no pull-up or
* pull-down), except for special function pins.
*
*
* @section gpio_api_in Configuring pins as inputs
*
* Configuring GPIO pins as inputs is done with @ref gpio_mode_setup(), with
* @ref GPIO_MODE_INPUT for the mode parameter. The direction of the pull-up
* must be specified with the same call
*
* For example, PA2, PA3, and PA4 as inputs, with pull-up on PA4:
* @code{.c}
* gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO2 | GPIO3);
* gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO4);
* @endcode
*
*
* @section gpio_api_out Configuring pins as outputs
*
* Output pins have more configuration options than input pins. LM4F pins can be
* configured as either push-pull, or open drain. The drive strength of each pin
* can be adjusted between 2mA, 4mA, or 8mA. Slew-rate control is available when
* the pins are configured to drive 8mA. These extra options can be specified
* with @ref gpio_set_output_config().
* The default is push-pull configuration with 2mA drive capability.
*
* @note
* @ref gpio_set_output_config() controls different capabilities than the
* similar sounding gpio_set_output_options() from the STM GPIO API. They are
* intentionally named differently to prevent confusion between the two. They
* are API incompatible.
*
* For example, to set PA2 to output push-pull with a drive strength of 8mA:
* @code{.c}
* gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO2);
* gpio_set_output_config(GPIOA, GPIO_OTYPE_PP, GPIO_DRIVE_8MA, GPIO2);
* @endcode
*
*
* @section gpio_api_analog Configuring pins as analog function
*
* Configuring GPIO pins to their analog function is done with
* @ref gpio_mode_setup(), with @ref GPIO_MODE_ANALOG for the mode parameter.
*
* Suppose PD4 and PD5 are the USB pins. To enable their analog functionality
* (USB D+ and D- in this case), use:
* @code
* // Mux USB pins to their analog function
* gpio_mode_setup(GPIOD, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO4 | GPIO5);
* @endcode
*
* @section gpio_api_alf_func Configuring pins as alternate functions
*
* Most pins have alternate functions associated with them. When a pin is set to
* an alternate function, it is multiplexed to one of the dedicated hardware
* peripheral in the chip. The alternate function mapping can be found in the
* part's datasheet, and usually varies between arts of the same family.
*
* Multiplexing a pin, or group of pins to an alternate function is done with
* @ref gpio_set_af(). Because AF0 is not used on the LM4F, passing 0 as the
* alt_func_num parameter will disable the alternate function of the given pins.
*
* @code
* // Mux PB0 and PB1 to AF1 (UART1 TX/RX in this case)
* gpio_set_af(GPIOB, 1, GPIO0 | GPIO1);
* @endcode
*
* @section gpio_api_sfpins Changing configuration of special function pins
*
* On the LM4F, the NMI and JTAG/SWD default to their alternate function. These
* pins cannot normally be committed to GPIO usage. To enable these special
* function pins to be used as GPIO, they must be unlocked. This may be achieved
* via @ref gpio_unlock_commit. Once a special function pin is unlocked, its
* settings may be altered in the usual way.
*
* For example, to unlock the PF0 pin (NMI on the LM4F120):
* @code
* // PF0 is an NMI pin, and needs to be unlocked
* gpio_unlock_commit(GPIOF, GPIO0);
* // Now the pin can be configured
* gpio_mode_setup(RGB_PORT, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, btnpins);
* @endcode
*/
/**@{*/
/**
* \brief Enable access to GPIO registers via the AHB aperture
*
* All GPIO registers are accessed in libopencm3 via the AHB aperture. It
* provides faster control over the older APB aperture. This aperture must be
* enabled before calling any other gpio_*() function.
*
*/
void gpio_enable_ahb_aperture(void)
{
SYSCTL_GPIOHBCTL = 0xffffffff;
}
/**
* \brief Configure a group of pins
*
* Sets the Pin direction, analog/digital mode, and pull-up configuration of
* or a set of GPIO pins on a given GPIO port.
*
* @param[in] gpioport GPIO block register address base @ref gpio_reg_base
* @param[in] mode Pin mode (@ref gpio_mode) \n
* - GPIO_MODE_OUTPUT -- Configure pin as output \n
* - GPIO_MODE_INPUT -- Configure pin as input \n
* - GPIO_MODE_ANALOG -- Configure pin as analog function
* @param[in] pullup Pin pullup/pulldown configuration (@ref gpio_pullup) \n
* - GPIO_PUPD_NONE -- Do not pull the pin high or low \n
* - GPIO_PUPD_PULLUP -- Pull the pin high \n
* - GPIO_PUPD_PULLDOWN -- Pull the pin low
* @param[in] gpios @ref gpio_pin_id. Any combination of pins may be specified
* by OR'ing then together
*/
void gpio_mode_setup(uint32_t gpioport, enum gpio_mode mode,
enum gpio_pullup pullup, uint8_t gpios)
{
switch (mode) {
case GPIO_MODE_OUTPUT:
GPIO_DIR(gpioport) |= gpios;
GPIO_DEN(gpioport) |= gpios;
GPIO_AMSEL(gpioport) &= ~gpios;
break;
case GPIO_MODE_INPUT:
GPIO_DIR(gpioport) &= ~gpios;
GPIO_DEN(gpioport) |= gpios;
GPIO_AMSEL(gpioport) &= ~gpios;
break;
case GPIO_MODE_ANALOG:
GPIO_DEN(gpioport) &= ~gpios;
GPIO_AMSEL(gpioport) |= gpios;
break;
default:
/* Don't do anything */
break;
}
/*
* Setting a bit in the GPIO_PDR register clears the corresponding bit
* in the GPIO_PUR register, and vice-versa.
*/
switch (pullup) {
case GPIO_PUPD_PULLUP:
GPIO_PUR(gpioport) |= gpios;
break;
case GPIO_PUPD_PULLDOWN:
GPIO_PDR(gpioport) |= gpios;
break;
case GPIO_PUPD_NONE: /* Fall through */
default:
GPIO_PUR(gpioport) &= ~gpios;
GPIO_PDR(gpioport) &= ~gpios;
break;
}
}
/**
* \brief Configure output parameters of a group of pins
*
* Sets the output configuration and drive strength, of or a set of GPIO pins
* for a set of GPIO pins in output mode.
*
* @param[in] gpioport GPIO block register address base @ref gpio_reg_base
* @param[in] otype Output driver configuration (@ref gpio_output_type) \n
* - GPIO_OTYPE_PP -- Configure pin driver as push-pull \n
* - GPIO_OTYPE_OD -- Configure pin driver as open drain
* @param[in] drive Pin drive strength (@ref gpio_drive_strength) \n
* - GPIO_DRIVE_2MA -- 2mA drive \n
* - GPIO_DRIVE_4MA -- 4mA drive \n
* - GPIO_DRIVE_8MA -- 8mA drive \n
* - GPIO_DRIVE_8MA_SLEW_CTL -- 8mA drive with slew rate
* control
* @param[in] gpios @ref gpio_pin_id. Any combination of pins may be specified
* by OR'ing then together
*/
void gpio_set_output_config(uint32_t gpioport, enum gpio_output_type otype,
enum gpio_drive_strength drive, uint8_t gpios)
{
if (otype == GPIO_OTYPE_OD) {
GPIO_ODR(gpioport) |= gpios;
} else {
GPIO_ODR(gpioport) &= ~gpios;
}
/*
* Setting a bit in the GPIO_DRxR register clears the corresponding bit
* in the other GPIO_DRyR registers, and vice-versa.
*/
switch (drive) {
case GPIO_DRIVE_8MA_SLEW_CTL:
GPIO_DR8R(gpioport) |= gpios;
GPIO_SLR(gpioport) |= gpios;
break;
case GPIO_DRIVE_8MA:
GPIO_DR8R(gpioport) |= gpios;
GPIO_SLR(gpioport) &= ~gpios;
break;
case GPIO_DRIVE_4MA:
GPIO_DR4R(gpioport) |= gpios;
break;
case GPIO_DRIVE_2MA: /* Fall through */
default:
GPIO_DR2R(gpioport) |= gpios;
break;
}
}
#define PCTL_AF(pin, af) (af << (pin << 2))
#define PCTL_MASK(pin) PCTL_AF(pin, 0xf)
/**
* \brief Multiplex group of pins to the given alternate function
*
* Mux the pin or group of pins to the given alternate function. Note that a
* number of pins may be set but only with a single AF number. This is useful
* when one or more of a peripheral's pins are assigned to the same alternate
* function.
*
* Because AF0 is not used on the LM4F, passing 0 as the alt_func_num parameter
* will disable the alternate function of the given pins.
*
* @param[in] gpioport GPIO block register address base @ref gpio_reg_base
* @param[in] alt_func_num Pin alternate function number or 0 to disable the
* alternate function multiplexing.
* @param[in] gpios @ref gpio_pin_id. Any combination of pins may be specified
* by OR'ing then together
*/
void gpio_set_af(uint32_t gpioport, uint8_t alt_func_num, uint8_t gpios)
{
uint32_t pctl32;
uint8_t pin_mask;
int i;
/* Did we mean to disable the alternate function? */
if (alt_func_num == 0) {
GPIO_AFSEL(gpioport) &= ~gpios;
return;
}
/* Enable the alternate function */
GPIO_AFSEL(gpioport) |= gpios;
/* Alternate functions are digital */
GPIO_DEN(gpioport) |= gpios;
/* Now take care of the actual multiplexing */
pctl32 = GPIO_PCTL(gpioport);
for (i = 0; i < 8; i++) {
pin_mask = (1 << i);
if (!(gpios & pin_mask)) {
continue;
}
pctl32 &= ~PCTL_MASK(i);
pctl32 |= PCTL_AF(i, (alt_func_num & 0xf));
}
GPIO_PCTL(gpioport) = pctl32;
}
/**
* \brief Unlock the commit control of a special function pin
*
* Unlocks the commit control of the given pin or group of pins. If a pin is a
* JTAG/SWD or NMI, the pin may then be reconfigured as a GPIO pin. If the pin
* is not locked by default, this has no effect.
*
* @param[in] gpioport GPIO block register address base @ref gpio_reg_base
* @param[in] gpios @ref gpio_pin_id. Any combination of pins may be specified
* by OR'ing then together.
*/
void gpio_unlock_commit(uint32_t gpioport, uint8_t gpios)
{
/* Unlock the GPIO_CR register */
GPIO_LOCK(gpioport) = GPIO_LOCK_UNLOCK_CODE;
/* Enable committing changes */
GPIO_CR(gpioport) |= gpios;
/* Lock the GPIO_CR register */
GPIO_LOCK(gpioport) = ~GPIO_LOCK_UNLOCK_CODE;
}
/**@}*/
/** @defgroup gpio_control GPIO pin control
* @ingroup gpio_file
*
* \brief <b>Controlling GPIO pins</b>
*
* Each I/O port has 8 individually configurable bits. When reading and writing
* data to the GPIO ports, address bits [9:2] mask the pins to be read or
* written. This mechanism makes all GPIO port reads and writes on the LM4F
* atomic operations. The GPIO API takes full advantage of this fact to preserve
* the atomicity of these operations.
*
* Setting or clearing a group of bits can be accomplished with @ref gpio_set()
* and @ref gpio_clear() respectively. These operation use the masking mechanism
* described above to only affect the specified pins.
*
* Sometimes it is more appropriate to read or set the level of a group of pins
* on a port, in one atomic operation. Reading the status can be accomplished
* with @ref gpio_read(). The result is equivalent to reading all the pins, then
* masking only the desired pins; however, the masking is done in hardware, and
* does not require an extra hardware operation.
*
* Writing a group of pins can be accomplished with @ref gpio_write(). The mask
* ('gpios' parameter) is applied in hardware, and the masked pins are not
* affected, regardless of the value of the respective bits written to the GPIO
* port.
*
* Two extra functions are provided, @ref gpio_port_read() and
* @ref gpio_port_write(). They are functionally identical to
* @ref gpio_read (port, GPIO_ALL) and @ref gpio_write (port, GPIO_ALL, val)
* respectively. Hence, they are also atomic.
*
* GPIO pins may be toggled with @ref gpio_toggle(). This function does not
* translate to an atomic operation.
*
* @note
* The @ref gpio_toggle() operation is the only GPIO port operation which is not
* atomic. It involves a read-modify-write cycle.
*
* Suppose PA0, PA1, PA2, and PA3 are to be modified without affecting the other
* pins on port A. This is common when controlling, for example, a 4-bit bus:
* @code{.c}
* // Pins 4,5,6, and 7 are unaffected, regardless of the bits in val
* gpio_write(GPIOA, GPIO0 | GPIO1 | GPIO2 | GPIO3, val);
* // Wait a bit then send the other 4 bits
* wait_a_bit();
* gpio_write(GPIOA, GPIO0 | GPIO1 | GPIO2 | GPIO3, val >> 4);
* @endcode
*
* Suppose a LED is connected to PD4, and we want to flash the LED for a brief
* period of time:
* @code
* gpio_set(GPIOD, GPIO4);
* wait_a_bit();
* gpio_set(GPIOD, GPIO4);
* @endcode
*/
/**@{*/
/**
* \brief Toggle a Group of Pins
*
* Toggle one or more pins of the given GPIO port.
*
* @param[in] gpioport GPIO block register address base @ref gpio_reg_base
* @param[in] gpios Pin identifiers. @ref gpio_pin_id
*/
void gpio_toggle(uint32_t gpioport, uint8_t gpios)
{
/* The mask makes sure we only toggle the GPIOs we want to */
GPIO_DATA(gpioport)[gpios] ^= GPIO_ALL;
}
/**@}*/
/** @defgroup gpio_irq GPIO Interrupt control
* @ingroup gpio_file
*
* \brief <b>Configuring interrupts from GPIO pins</b>
*
* GPIO pins can trigger interrupts on either edges or levels. The type of
* trigger can be configured with @ref gpio_configure_int_trigger(). To have an
* event on the given pin generate an interrupt, its interrupt source must be
* unmasked. This can be achieved with @ref gpio_enable_interrupts(). Interrupts
* which are no longer needed can be disabled through
* @ref gpio_disable_interrupts().
*
* In order for the interrupt to generate an IRQ and a call to the interrupt
* service routine, the interrupt for the GPIO port must be routed through the
* NVIC with @ref nvic_enable_irq(). For this last step, the nvic.h header is
* needed:
* @code{.c}
* #include <libopencm3/lm4f/nvic.h>
* @endcode
*
* Enabling an interrupt is as simple as configuring the desired trigger,
* unmasking the desired interrupt, and routing the desired GPIO port's
* interrupt through the NVIC.
* @code{.c}
* // Trigger interrupt on each rising edge
* gpio_configure_trigger(GPIOF, GPIO_TRIG_EDGE_RISE, GPIO0 | GPIO4);
* // Unmask the interrupt on those pins
* gpio_enable_interrupts(GPIOF, GPIO0 | GPIO4);
* // Enable the interrupt in the NVIC as well
* nvic_enable_irq(NVIC_GPIOF_IRQ);
* @endcode
*
* After interrupts are properly enabled and routed through the NVIC, when an
* event occurs, the appropriate IRQ flag is set by hardware, and execution
* jumps to the GPIO ISR. The ISR should query the IRQ flags to determine which
* event caused the interrupt. For this, use @ref gpio_is_interrupt_source(),
* with the desired GPIO flag. After one or more interrupt sources are
* serviced, the IRQ flags must be cleared by the ISR. This can be done with
* @ref gpio_clear_interrupt_flag().
*
* A typical GPIO ISR may look like the following:
* @code{.c}
* void gpiof_isr(void)
* {
* uint8_t serviced_irqs = 0;
*
* // Process individual IRQs
* if (gpio_is_interrupt_source(GPIOF, GPIO0)) {
* process_gpio0_event();
* serviced_irq |= GPIO0;
* }
* if (gpio_is_interrupt_source(GPIOF, GPIO4)) {
* process_gpio4_event();
* serviced_irq |= GPIO4;
* }
*
* // Clear the interupt flag for the processed IRQs
* gpio_clear_interrupt_flag(GPIOF, serviced_irqs);
* }
* @endcode
*/
/**@{*/
/**
* \brief Configure the interrupt trigger on the given GPIO pins
*
* Sets the Pin direction, analog/digital mode, and pull-up configuration of
* or a set of GPIO pins on a given GPIO port.
*
* @param[in] gpioport GPIO block register address base @ref gpio_reg_base
* @param[in] trigger Trigger configuration (@ref gpio_trigger) \n
* - GPIO_TRIG_LVL_LOW -- Trigger on low level \n
* - GPIO_TRIG_LVL_HIGH -- Trigger on high level \n
* - GPIO_TRIG_EDGE_FALL -- Trigger on falling edges \n
* - GPIO_TRIG_EDGE_RISE -- Trigger on rising edges \n
* - GPIO_TRIG_EDGE_BOTH -- Trigger on all edges
* @param[in] gpios @ref gpio_pin_id. Any combination of pins may be specified
* by OR'ing then together
*/
void gpio_configure_trigger(uint32_t gpioport, enum gpio_trigger trigger,
uint8_t gpios)
{
switch (trigger) {
case GPIO_TRIG_LVL_LOW:
GPIO_IS(gpioport) |= gpios;
GPIO_IEV(gpioport) &= ~gpios;
break;
case GPIO_TRIG_LVL_HIGH:
GPIO_IS(gpioport) |= gpios;
GPIO_IEV(gpioport) |= gpios;
break;
case GPIO_TRIG_EDGE_FALL:
GPIO_IS(gpioport) &= ~gpios;
GPIO_IBE(gpioport) &= ~gpios;
GPIO_IEV(gpioport) &= ~gpios;
break;
case GPIO_TRIG_EDGE_RISE:
GPIO_IS(gpioport) &= ~gpios;
GPIO_IBE(gpioport) &= ~gpios;
GPIO_IEV(gpioport) |= gpios;
break;
case GPIO_TRIG_EDGE_BOTH:
GPIO_IS(gpioport) &= ~gpios;
GPIO_IBE(gpioport) |= gpios;
break;
default:
/* Don't do anything */
break;
}
}
/**
* \brief Enable interrupts on specified GPIO pins
*
* Enable interrupts on the specified GPIO pins
*
* Note that the NVIC must be enabled and properly configured for the interrupt
* to be routed to the CPU.
*
* @param[in] gpioport GPIO block register address base @ref gpio_reg_base
* @param[in] gpios @ref gpio_pin_id. Pins whose interrupts to enable. Any
* combination of pins may be specified by OR'ing them
* together.
*/
void gpio_enable_interrupts(uint32_t gpioport, uint8_t gpios)
{
GPIO_IM(gpioport) |= gpios;
}
/**
* \brief Disable interrupts on specified GPIO pins
*
* Disable interrupts on the specified GPIO pins
*
* Note that the NVIC must be enabled and properly configured for the interrupt
* to be routed to the CPU.
*
* @param[in] gpioport GPIO block register address base @ref gpio_reg_base
* @param[in] gpios @ref gpio_pin_id. Pins whose interrupts to disable. Any
* combination of pins may be specified by OR'ing them
* together.
*/
void gpio_disable_interrupts(uint32_t gpioport, uint8_t gpios)
{
GPIO_IM(gpioport) |= gpios;
}
/**@}*/
/**@}*/

View File

@ -0,0 +1,2 @@
/* Yes, we can simply use the lm3s linker script */
INCLUDE "libopencm3_lm3s.ld"

View File

@ -0,0 +1,499 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@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/>.
*
*/
/**
* @defgroup rcc_file RCC
*
* @ingroup LM4Fxx
*
@author @htmlonly &copy; @endhtmlonly 2012
Alexandru Gagniuc <mr.nuke.me@gmail.com>
* \brief <b>libopencm3 LM4F Clock control API</b>
*
* The LM$F clock API provides functionaliity for manipulating the system clock,
* oscillator, and PLL. Functions are provided for fine-grained control of clock
* control registers, while also providing higher level functionality to easily
* configure the main system clock source.
*
* The following code snippet uses fine-grained mechanisms to configures the
* chip to run off an external 16MHz crystal, and use the PLL to derive a clock
* frequency of 80MHz.
* @code{.c}
* // A divisor of 5 gives us a clock of 400/5 = 80MHz
* #define PLLDIV_80MHZ 5
*
* // Enable the main oscillator
* rcc_enable_main_osc();
*
* // Make RCC2 override RCC
* rcc_enable_rcc2();
*
* // Set XTAL value to 16MHz
* rcc_configure_xtal(XTAL_16M);
* // Set the oscillator source as the main oscillator
* rcc_set_osc_source(OSCSRC_MOSC);
* // Enable the PLL
* rcc_pll_on();
*
* // Change the clock divisor
* rcc_set_pll_divisor(PLLDIV_80MHZ);
*
* // We cannot use the PLL as a clock source until it locks
* rcc_wait_for_pll_ready();
* // Disable PLL bypass to derive the system clock from the PLL clock
* rcc_pll_bypass_disable();
*
* // Keep track of frequency
* lm4f_rcc_sysclk_freq = 80E6;
* @endcode
*
* The same can be achieved by a simple call to high-level routines:
* @code
* // A divisor of 5 gives us a clock of 400/5 = 80MHz
* #define PLLDIV_80MHZ 5
*
* rcc_sysclk_config(OSCSRC_MOSC, XTAL_16M, PLLDIV_80MHZ);
* @endcode
*
* @{
*/
#include <libopencm3/lm4f/rcc.h>
/**
* @defgroup rcc_low_level Low-level clock control API
@ingroup rcc_file
* @{
*/
/**
* \brief System clock frequency
*
* This variable is provided to keep track of the system clock frequency. It
* should be updated every time the system clock is changed via the fine-grained
* mechanisms. The initial value is 16MHz, which corresponds to the clock of the
* internal 16MHz oscillator.
*
* High-level routines update the system clock automatically.
* For read access, it is recommended to acces this variable via
* @code
* rcc_get_system_clock_frequency();
* @endcode
*
* If write access is desired (i.e. when changing the system clock via the
* fine-grained mechanisms), then include the following line in your code:
* @code
* extern uint32_t lm4f_rcc_sysclk_freq;
* @endcode
*/
uint32_t lm4f_rcc_sysclk_freq = 16000000;
/**
* \brief Configure the crystal type connected to the device.
*
* Configure the crystal type connected between the OSCO and OSCI pins by
* writing the appropriate value to the XTAL field in SYSCTL_RCC. The PLL
* parameters are automatically adjusted in hardware to provide a PLL clock of
* 400MHz.
*
* @param[in] xtal predefined crystal type @see xtal_t
*/
void rcc_configure_xtal(enum xtal_t xtal)
{
uint32_t reg32;
reg32 = SYSCTL_RCC;
reg32 &= ~SYSCTL_RCC_XTAL_MASK;
reg32 |= (xtal & SYSCTL_RCC_XTAL_MASK);
SYSCTL_RCC = reg32;
}
/**
* \brief Disable the main oscillator
*
* Sets the IOSCDIS bit in SYSCTL_RCC, disabling the main oscillator.
*/
void rcc_disable_main_osc(void)
{
SYSCTL_RCC |= SYSCTL_RCC_MOSCDIS;
}
/**
* \brief Disable the internal oscillator
*
* Sets the IOSCDIS bit in SYSCTL_RCC, disabling the internal oscillator.
*/
void rcc_disable_interal_osc(void)
{
SYSCTL_RCC |= SYSCTL_RCC_IOSCDIS;
}
/**
* \brief Enable the main oscillator
*
* Clears the MOSCDIS bit in SYSCTL_RCC, enabling the main oscillator.
*/
void rcc_enable_main_osc(void)
{
SYSCTL_RCC &= ~SYSCTL_RCC_MOSCDIS;
}
/**
* \brief Enable the internal oscillator
*
* Clears the IOSCDIS bit in SYSCTL_RCC, enabling the internal oscillator.
*/
void rcc_enable_interal_osc(void)
{
SYSCTL_RCC &= ~SYSCTL_RCC_IOSCDIS;
}
/**
* \brief Enable the use of SYSCTL_RCC2 register for clock control
*
* Enables the USERCC2 bit in SYSCTTL_RCC2. Settings in SYSCTL_RCC2 will
* override settings in SYSCTL_RCC.
* This function must be called before other calls to manipulate the clock, as
* libopencm3 uses the SYSCTL_RCC2 register.
*/
void rcc_enable_rcc2(void)
{
SYSCTL_RCC2 |= SYSCTL_RCC2_USERCC2;
}
/**
* \brief Power down the main PLL
*
* Sets the SYSCTL_RCC2_PWRDN2 in SYSCTL_RCC2 to power down the PLL.
*
* USERCC2 must have been set by a call to rcc_enable_rcc2() before calling this
* function.
*/
void rcc_pll_off(void)
{
SYSCTL_RCC2 |= SYSCTL_RCC2_PWRDN2;
}
/**
* \brief Power up the main PLL
*
* Clears the PWRDN2 in SYSCTL_RCC2 to power on the PLL.
*
* USERCC2 must have been set by a call to rcc_enable_rcc2() before calling this
* function.
*/
void rcc_pll_on(void)
{
SYSCTL_RCC2 &= ~SYSCTL_RCC2_PWRDN2;
}
/**
* \brief Set the oscillator source to be used by the system clock
*
* Set the clock source for the system clock.
*
* USERCC2 must have been set by a call to rcc_enable_rcc2() before calling this
* function.
*/
void rcc_set_osc_source(enum osc_src src)
{
uint32_t reg32;
reg32 = SYSCTL_RCC2;
reg32 &= ~SYSCTL_RCC2_OSCSRC2_MASK;
reg32 |= (src & SYSCTL_RCC2_OSCSRC2_MASK);
SYSCTL_RCC2 = reg32;
}
/**
* \brief Disable the PLL bypass and use the PLL clock
*
* Clear BYPASS2 in SYSCTL_RCC2. The system clock is derived from the PLL
* clock divided by the divisor specified in SYSDIV2.
*
* USERCC2 must have been set by a call to rcc_enable_rcc2() before calling this
* function.
*/
void rcc_pll_bypass_disable(void)
{
SYSCTL_RCC2 &= ~SYSCTL_RCC2_BYPASS2;
}
/**
* \brief Enable the PLL bypass and use the oscillator clock
*
* Set BYPASS2 in SYSCTL_RCC2. The system clock is derived from the oscillator
* clock divided by the divisor specified in SYSDIV2.
*
* USERCC2 must have been set by a call to rcc_enable_rcc2() before calling this
* function.
*/
void rcc_pll_bypass_enable(void)
{
SYSCTL_RCC2 |= SYSCTL_RCC2_BYPASS2;
}
/**
* \brief Set the PLL clock divisor (from 400MHz)
*
* Set the binary divisor used to predivide the system clock down for use as the
* timing reference for the PWM module. The divisor is expected to be a divisor
* from 400MHz, not 200MHz. The DIV400 is also set.
*
* Specifies the divisor that used to generate the system clock from either the
* PLL output or the oscillator source (depending on the BYPASS2 bit in
* SYSCTL_RCC2). SYSDIV2 is used for the divisor when both the USESYSDIV bit in
* SYSCTL_RCC is set.
*
* USERCC2 must have been set by a call to rcc_enable_rcc2() before calling this
* function.
*
* @param[in] div clock divisor to apply to the 400MHz PLL clock. It is the
* caller's responsibility to ensure that the divisor will not create
* a system clock that is out of spec.
*/
void rcc_set_pll_divisor(uint8_t div400)
{
uint32_t reg32;
SYSCTL_RCC |= SYSCTL_RCC_USESYSDIV;
reg32 = SYSCTL_RCC2;
reg32 &= ~SYSCTL_RCC2_SYSDIV400_MASK;
reg32 |= ((div400 - 1) << 22) & SYSCTL_RCC2_SYSDIV400_MASK;
/* We are expecting a divider from 400MHz */
reg32 |= SYSCTL_RCC2_DIV400;
SYSCTL_RCC2 = reg32;
}
/**
* \brief Set the PWM unit clock divisor
*
* Set the binary divisor used to predivide the system clock down for use as the
* timing reference for the PWM module.
*
* @param[in] div clock divisor to use @see pwm_clkdiv_t
*/
void rcc_set_pwm_divisor(enum pwm_clkdiv div)
{
uint32_t reg32;
reg32 = SYSCTL_RCC;
reg32 &= ~SYSCTL_RCC_PWMDIV_MASK;
reg32 |= (div & SYSCTL_RCC_PWMDIV_MASK);
SYSCTL_RCC = reg32;
}
/**
* \brief Power down the USB PLL
*
* Sets the USBPWRDN in SYSCTL_RCC2 to power down the USB PLL.
*
* USERCC2 must have been set by a call to rcc_enable_rcc2() before calling this
* function.
*/
void rcc_usb_pll_off(void)
{
SYSCTL_RCC2 |= SYSCTL_RCC2_USBPWRDN;
}
/**
* \brief Power up the USB PLL
*
* Clears the USBPWRDN in SYSCTL_RCC2 to power on the USB PLL.
*
* USERCC2 must have been set by a call to rcc_enable_rcc2() before calling this
* function.
*/
void rcc_usb_pll_on(void)
{
SYSCTL_RCC2 &= ~SYSCTL_RCC2_USBPWRDN;
}
/**
* \brief Wait for main PLL to lock
*
* Waits until the LOCK bit in SYSCTL_PLLSTAT is set. This guarantees that the
* PLL is locked, and ready to use.
*/
void rcc_wait_for_pll_ready(void)
{
while (!(SYSCTL_PLLSTAT & SYSCTL_PLLSTAT_LOCK));
}
/**
* @}
*/
/**
* @defgroup rcc_high_level High-level clock control API
@ingroup rcc_file
* @{
*/
/**
* \brief Change the PLL divisor
*
* Changes the divisor applied to the 400MHz PLL clock. The PLL must have
* previously been configured by selecting an appropriate XTAL value, and
* turning on the PLL. This function does not reconfigure the XTAL value or
* oscillator source. It only changes the PLL divisor.
*
* The PLL is bypassed before modifying the divisor, and the function blocks
* until the PLL is locked, then the bypass is disabled, before returning.
*
* @param [in] pll_div400 The clock divisor to apply to the 400MHz PLL clock.
*/
void rcc_change_pll_divisor(uint8_t pll_div400)
{
/* Bypass the PLL while its settings are modified */
rcc_pll_bypass_enable();
/* Change the clock divisor */
rcc_set_pll_divisor(pll_div400);
/* We cannot use the PLL as a clock source until it locks */
rcc_wait_for_pll_ready();
/* Disable PLL bypass to derive the system clock from the PLL clock */
rcc_pll_bypass_disable();
/* Update the system clock frequency for housekeeping */
lm4f_rcc_sysclk_freq = (uint32_t)400E6 / pll_div400;
}
/**
* \brief Get the system clock frequency
*
* @return System clock frequency in Hz
*/
uint32_t rcc_get_system_clock_frequency(void)
{
return lm4f_rcc_sysclk_freq;
}
/* Get the clock frequency corresponding to a given XTAL value */
static uint32_t xtal_to_freq(enum xtal_t xtal)
{
const uint32_t freqs[] = {
4000000, /* XTAL_4M */
4096000, /* XTAL_4M_096 */
4915200, /* XTAL_4M_9152 */
5000000, /* ,XTAL_5M */
5120000, /* XTAL_5M_12 */
6000000, /* XTAL_6M */
6144000, /* XTAL_6M_144 */
7372800, /* XTAL_7M_3728 */
8000000, /* XTAL_8M */
8192000, /* XTAL_8M_192 */
10000000, /* XTAL_10M */
12000000, /* XTAL_12M */
12288000, /* XTAL_12M_288 */
13560000, /* XTAL_13M_56 */
14318180, /* XTAL_14M_31818 */
16000000, /* XTAL_16M */
16384000, /* XTAL_16M_384 */
18000000, /* XTAL_18M */
20000000, /* XTAL_20M */
24000000, /* XTAL_24M */
25000000, /* XTAL_25M */
};
return freqs[xtal - XTAL_4M];
}
/**
* \brief Configure the system clock source
*
* Sets up the system clock, including configuring the oscillator source, and
* PLL to acheve the desired system clock frequency. Where applicable, The LM4F
* clock API uses the new RCC2 register to configure clock parameters.
*
* Enables the main oscillator if the clock source is OSCSRC_MOSC. If the main
* oscillator was previously enabled, it will not be disabled. If desired, it
* can be separately disabled by a call to rcc_disable_main_osc().
*
* Configures the system clock to run from the 400MHz PLL with a divisor of
* pll_div400 applied. If pll_div400 is 0, then the PLL is disabled, and the
* system clock is configured to run off a "raw" clock. If the PLL was
* previously powered on, it will not be disabled. If desired, it can de powered
* off by a call to rcc_pll_off().
*
* @param [in] osc_src Oscillator from where to derive the system clock.
* @param [in] xtal Type of crystal connected to the OSCO/OSCI pins
* @param [in] pll_div400 The clock divisor to apply to the 400MHz PLL clock.
* If 0, then the PLL is disabled, and the system runs
* off a "raw" clock.
*
* @return System clock frequency in Hz
*/
void rcc_sysclk_config(enum osc_src src, enum xtal_t xtal, uint8_t pll_div400)
{
/*
* We could be using the PLL at this point, or we could be running of a
* raw clock. Either way, it is safer to bypass the PLL now.
*/
rcc_pll_bypass_enable();
/* Enable the main oscillator, if needed */
if (src == OSCSRC_MOSC) {
rcc_enable_main_osc();
}
/* Make RCC2 override RCC */
rcc_enable_rcc2();
/* Set XTAL value to 16MHz */
rcc_configure_xtal(xtal);
/* Set the oscillator source */
rcc_set_osc_source(src);
if (pll_div400) {
/* Enable the PLL */
rcc_pll_on();
/* Configure the PLL to the divisor we want */
rcc_change_pll_divisor(pll_div400);
} else {
/* We are running off a raw clock */
switch (src) {
case OSCSRC_PIOSC:
lm4f_rcc_sysclk_freq = 16000000;
break;
case OSCSRC_PIOSC_D4:
lm4f_rcc_sysclk_freq = 4000000;
break;
case OSCSRC_MOSC:
lm4f_rcc_sysclk_freq = xtal_to_freq(xtal);
break;
case OSCSRC_32K_EXT:
lm4f_rcc_sysclk_freq = 32768;
break;
case OSCSRC_30K_INT: /* Fall through. */
default:
/*
* We either are running off the internal 30KHz
* oscillator, which is +- 50% imprecise, or we got a
* bad osc_src parameter.
*/
lm4f_rcc_sysclk_freq = 0;
}
}
}
/**
* @}
* @}
*/

View File

@ -0,0 +1,40 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@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/lm4f/systemcontrol.h>
/**
* \brief Enable the clock source for the peripheral
*
* @param[in] periph peripheral and clock type to enable @see lm4f_clken
*/
void periph_clock_enable(enum lm4f_clken periph)
{
MMIO32(SYSCTL_BASE + (periph >> 5)) |= 1 << (periph & 0x1f);
}
/**
* \brief Disable the clock source for the peripheral
*
* @param[in] periph peripheral and clock type to enable @see lm4f_clken
*/
void periph_clock_disable(enum lm4f_clken periph)
{
MMIO32(SYSCTL_BASE + (periph >> 5)) &= ~(1 << (periph & 0x1f));
}

View File

@ -0,0 +1,627 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@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/>.
*/
/**
* @defgroup uart_file UART
*
* @ingroup LM4Fxx
*
* @author @htmlonly &copy; @endhtmlonly 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* \brief <b>libopencm3 LM4F Universal Asynchronous Receiver Transmitter</b>
*
* The LM4F UART API provides functionality for accessing the UART hardware of
* the LM4F.
*
* Please see the individual UART modules for more details. To use the UART, the
* uart.h header needs to be included:
* @code{.c}
* #include <libopencm3/lm4f/uart.h>
* @endcode
*
* @{
*/
#include <libopencm3/lm4f/uart.h>
#include <libopencm3/lm4f/systemcontrol.h>
#include <libopencm3/lm4f/rcc.h>
/** @defgroup uart_config UART configuration
* @ingroup uart_file
*
* \brief <b>Enabling and configuring the UART</b>
*
* Enabling the UART is a two step process. The GPIO on which the UART resides
* must be enabled, and the UART pins must be configured as alternate function,
* digital pins. Pins must also be muxed to the appropriate alternate function.
* This is done with the GPIO API.
*
* The second step involves enabling and the UART itself. The UART should be
* disabled while it is being configured.
* -# The UART clock must be enabled with @ref periph_clock_enable().
* -# The UART must be disabled with @ref uart_disable().
* -# The UART clock source should be chosen before setting the baudrate.
* -# Baudrate, data bits, stop bit length, and parity can be configured.
* -# If needed, enable CTS or RTS lines via the @ref uart_set_flow_control().
* -# The UART can now be enabled with @ref uart_enable().
*
* For example, to enable UART1 at 115200 8n1 with hardware flow control:
* @code{.c}
* // Enable the UART clock
* periph_clock_enable(RCC_UART1);
* // We need a brief delay before we can access UART config registers
* __asm__("nop"); __asm__("nop"); __asm__("nop");
* // Disable the UART while we mess with its settings
* uart_disable(UART1);
* // Configure the UART clock source as precision internal oscillator
* uart_clock_from_piosc();
* // Set communication parameters
* uart_set_baudrate(UART1, 115200);
* uart_set_databits(UART1, 8);
* uart_set_parity(UART1, UART_PARITY_NONE);
* uart_set_stopbits(UART1, 1);
* // Enable RTC and CTS lines
* uart_set_flow_control(UART1, UART_FLOWCTL_HARD_RTS_CTS);
* // Now that we're done messing with the settings, enable the UART
* uart_enable(UART1);
* @endcode
*/
/**@{*/
/**
* \brief Enable the UART
*
* Enable the UART. The Rx and Tx lines are also enabled.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_enable(uint32_t uart)
{
UART_CTL(uart) |= (UART_CTL_UARTEN | UART_CTL_RXE | UART_CTL_TXE);
}
/**
* \brief Disable the UART
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_disable(uint32_t uart)
{
UART_CTL(uart) &= ~UART_CTL_UARTEN;
}
/**
* \brief Set UART baudrate
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] baud Baud rate in bits per second (bps).*
*/
void uart_set_baudrate(uint32_t uart, uint32_t baud)
{
uint32_t clock;
/* Are we running off the internal clock or system clock? */
if (UART_CC(uart) == UART_CC_CS_PIOSC) {
clock = 16000000;
} else {
clock = rcc_get_system_clock_frequency();
}
/* Find the baudrate divisor */
uint32_t div = (((clock * 8) / baud) + 1) / 2;
/* Set the baudrate divisors */
UART_IBRD(uart) = div / 64;
UART_FBRD(uart) = div % 64;
}
/**
* \brief Set UART databits
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] databits number of data bits per transmission.
*/
void uart_set_databits(uint32_t uart, uint8_t databits)
{
uint32_t reg32, bitint32_t;
/* This has the same effect as using UART_LCRH_WLEN_5/6/7/8 directly */
bitint32_t = (databits - 5) << 5;
/* TODO: What about 9 data bits? */
reg32 = UART_LCRH(uart);
reg32 &= ~UART_LCRH_WLEN_MASK;
reg32 |= bitint32_t;
UART_LCRH(uart) = reg32;
}
/**
* \brief Set UART stopbits
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] bits the requested number of stopbits, either 1 or 2.
*/
void uart_set_stopbits(uint32_t uart, uint8_t stopbits)
{
if (stopbits == 2) {
UART_LCRH(uart) |= UART_LCRH_STP2;
} else {
UART_LCRH(uart) &= ~UART_LCRH_STP2;
}
}
/**
* \brief Set UART parity
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] bits the requested parity scheme.
*/
void uart_set_parity(uint32_t uart, enum uart_parity parity)
{
uint32_t reg32;
reg32 = UART_LCRH(uart);
reg32 |= UART_LCRH_PEN;
reg32 &= ~(UART_LCRH_SPS | UART_LCRH_EPS);
switch (parity) {
case UART_PARITY_NONE:
/* Once we disable parity the other bits are meaningless */
UART_LCRH(uart) &= ~UART_LCRH_PEN;
return;
case UART_PARITY_ODD:
break;
case UART_PARITY_EVEN:
reg32 |= UART_LCRH_EPS;
break;
case UART_PARITY_STICK_0:
reg32 |= (UART_LCRH_SPS | UART_LCRH_EPS);
break;
case UART_PARITY_STICK_1:
reg32 |= UART_LCRH_SPS;
break;
}
UART_LCRH(uart) = reg32;
}
/**
* \brief Set the flow control scheme
*
* Set the flow control scheme by enabling or disabling RTS and CTS lines. This
* will only have effect if the given UART supports the RTS and CTS lines.
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] flow The flow control scheme to use (none, RTS, CTS or both) \n
* UART_FLOWCTL_RTS -- enable the RTS line \n
* UART_FLOWCTL_CTS -- enable the CTS line \n
* UART_FLOWCTL_RTS_CTS -- enable both RTS and CTS lines
*/
void uart_set_flow_control(uint32_t uart, enum uart_flowctl flow)
{
uint32_t reg32 = UART_CTL(uart);
reg32 &= ~(UART_CTL_RTSEN | UART_CTL_CTSEN);
if (flow == UART_FLOWCTL_RTS) {
reg32 |= UART_CTL_RTSEN;
} else if (flow == UART_FLOWCTL_CTS) {
reg32 |= UART_CTL_CTSEN;
} else if (flow == UART_FLOWCTL_RTS_CTS) {
reg32 |= (UART_CTL_RTSEN | UART_CTL_CTSEN);
}
UART_CTL(uart) = reg32;
}
/**
* \brief Clock the UART module from the internal oscillator
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_clock_from_piosc(uint32_t uart)
{
UART_CC(uart) = UART_CC_CS_PIOSC;
}
/**
* \brief Clock the UART module from the system clock
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_clock_from_sysclk(uint32_t uart)
{
UART_CC(uart) = UART_CC_CS_SYSCLK;
}
/**@}*/
/** @defgroup uart_send_recv UART transmission and reception
* @ingroup uart_file
*
* \brief <b>Sending and receiving data through the UART</b>
*
* Primitives for sending and recieving data are provided, @ref uart_send() and
* @ref uart_recv(). These primitives do not check if data can be transmitted
* or wait for data. If waiting until data is available or can be transmitted is
* desired, blocking primitives are also available, @ref uart_send_blocking()
* and @ref uart_recv_blocking().
*
* These primitives only handle one byte at at time, and thus may be unsuited
* for some applications. You may also consider using @ref uart_dma.
*/
/**@{*/
/**
* \brief UART Send a Data Word.
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] data data to send.
*/
void uart_send(uint32_t uart, uint16_t data)
{
data &= 0xFF;
UART_DR(uart) = data;
}
/**
* \brief UART Read a Received Data Word.
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @return data from the Rx FIFO.
*/
uint16_t uart_recv(uint32_t uart)
{
return UART_DR(uart) & UART_DR_DATA_MASK;
}
/**
* \brief UART Wait for Transmit Data Buffer Not Full
*
* Blocks until the transmit data FIFO is not empty and can accept the next data
* word.
* \n
* Even if the FIFO is not empty, this function will return as long as there is
* room for at least one more word.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_wait_send_ready(uint32_t uart)
{
/* Wait until the Tx FIFO is no longer full */
while (UART_FR(uart) & UART_FR_TXFF);
}
/**
* \brief UART Wait for Received Data Available
*
* Blocks until the receive data FIFO holds a at least valid received data word.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_wait_recv_ready(uint32_t uart)
{
/* Wait until the Tx FIFO is no longer empty */
while (UART_FR(uart) & UART_FR_RXFE);
}
/**
* \brief UART Send Data Word with Blocking
*
* Blocks until the transmit data FIFO can accept the next data word for
* transmission.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_send_blocking(uint32_t uart, uint16_t data)
{
uart_wait_send_ready(uart);
uart_send(uart, data);
}
/**
* \brief UART Read a Received Data Word with Blocking.
*
* Wait until a data word has been received then return the word.
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @return data from the Rx FIFO.
*/
uint16_t uart_recv_blocking(uint32_t uart)
{
uart_wait_recv_ready(uart);
return uart_recv(uart);
}
/**@}*/
/** @defgroup uart_irq UART Interrupt control
* @ingroup uart_file
*
* \brief <b>Configuring interrupts from the UART</b>
*
* To have an event generate an interrupt, its interrupt source must be
* unmasked. This can be achieved with @ref uart_enable_interrupts(). Interrupts
* which are no longer needed can be disabled through
* @ref uart_disable_interrupts().
*
* In order for the interrupt to generate an IRQ and a call to the interrupt
* service routine, the interrupt for the target UART must be routed through the
* NVIC with @ref nvic_enable_irq(). For this last step, the nvic.h header is
* needed:
* @code{.c}
* #include <libopencm3/lm4f/nvic.h>
* @endcode
*
* Enabling an interrupt is as simple as unmasking the desired interrupt, and
* routing the desired UART's interrupt through the NVIC.
* @code{.c}
* // Unmask receive interrupt
* uart_enable_rx_interrupt(UART0);
* // Make sure the interrupt is routed through the NVIC
* nvic_enable_irq(NVIC_UART0_IRQ);
* @endcode
*
* If a more than one interrupt is to be enabled at one time, the interrupts
* can be enabled by a single call to @ref uart_enable_interrupts().
* For example:
* @code{.c}
* // Unmask receive, CTS, and RI, interrupts
* uart_enable_interrupts(UART0, UART_INT_RX | UART_INT_RI | UART_INT_CTS);
* @endcode
*
* After interrupts are properly enabled and routed through the NVIC, when an
* event occurs, the appropriate IRQ flag is set by hardware, and execution
* jumps to the UART ISR. The ISR should query the IRQ flags to determine which
* event caused the interrupt. For this, use @ref uart_is_interrupt_source(),
* with the desired UART_INT flag. After one or more interrupt sources are
* serviced, the IRQ flags must be cleared by the ISR. This can be done with
* @ref uart_clear_interrupt_flag().
*
* A typical UART ISR may look like the following:
* @code{.c}
* void uart0_isr(void)
* {
* uint32_t serviced_irqs = 0;
*
* // Process individual IRQs
* if (uart_is_interrupt_source(UART0, UART_INT_RX)) {
* process_rx_event();
* serviced_irq |= UART_INT_RX;
* }
* if (uart_is_interrupt_source(UART0, UART_INT_CTS)) {
* process_cts_event();
* serviced_irq |= UART_INT_CTS;
* }
*
* // Clear the interupt flag for the processed IRQs
* uart_clear_interrupt_flag(UART0, serviced_irqs);
* }
* @endcode
*/
/**@{*/
/**
* \brief Enable Specific UART Interrupts
*
* Enable any combination of interrupts. Interrupts may be OR'ed together to
* enable them with one call. For example, to enable both the RX and CTS
* interrupts, pass (UART_INT_RX | UART_INT_CTS)
*
* Note that the NVIC must be enabled and properly configured for the interrupt
* to be routed to the CPU.
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] ints Interrupts which to enable. Any combination of interrupts may
* be specified by OR'ing then together
*/
void uart_enable_interrupts(uint32_t uart, enum uart_interrupt_flag ints)
{
UART_IM(uart) |= ints;
}
/**
* \brief Enable Specific UART Interrupts
*
* Disabe any combination of interrupts. Interrupts may be OR'ed together to
* disable them with one call. For example, to disable both the RX and CTS
* interrupts, pass (UART_INT_RX | UART_INT_CTS)
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] ints Interrupts which to disable. Any combination of interrupts
* may be specified by OR'ing then together
*/
void uart_disable_interrupts(uint32_t uart, enum uart_interrupt_flag ints)
{
UART_IM(uart) &= ~ints;
}
/**
* \brief Enable the UART Receive Interrupt.
*
* Note that the NVIC must be enabled and properly configured for the interrupt
* to be routed to the CPU.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_enable_rx_interrupt(uint32_t uart)
{
uart_enable_interrupts(uart, UART_INT_RX);
}
/**
* \brief Disable the UART Receive Interrupt.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_disable_rx_interrupt(uint32_t uart)
{
uart_disable_interrupts(uart, UART_INT_RX);
}
/**
* \brief Enable the UART Transmit Interrupt.
*
* Note that the NVIC must be enabled and properly configured for the interrupt
* to be routed to the CPU.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_enable_tx_interrupt(uint32_t uart)
{
uart_enable_interrupts(uart, UART_INT_TX);
}
/**
* \brief Disable the UART Transmit Interrupt.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_disable_tx_interrupt(uint32_t uart)
{
uart_disable_interrupts(uart, UART_INT_TX);
}
/**
* \brief Mark interrupt as serviced
*
* After an interrupt is services, its flag must be cleared. If the flag is not
* cleared, then execution will jump back to the start of the ISR after the ISR
* returns.
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] ints Interrupts which to clear. Any combination of interrupts may
* be specified by OR'ing then together
*/
void uart_clear_interrupt_flag(uint32_t uart, enum uart_interrupt_flag ints)
{
UART_ICR(uart) |= ints;
}
/**@}*/
/** @defgroup uart_dma UART DMA control
* @ingroup uart_file
*
* \brief <b>Enabling Direct Memory Access transfers for the UART</b>
*
*/
/**@{*/
/**
* \brief Enable the UART Receive DMA.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_enable_rx_dma(uint32_t uart)
{
UART_DMACTL(uart) |= UART_DMACTL_RXDMAE;
}
/**
* \brief Disable the UART Receive DMA.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_disable_rx_dma(uint32_t uart)
{
UART_DMACTL(uart) &= ~UART_DMACTL_RXDMAE;
}
/**
* \brief Enable the UART Transmit DMA.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_enable_tx_dma(uint32_t uart)
{
UART_DMACTL(uart) |= UART_DMACTL_TXDMAE;
}
/**
* \brief Disable the UART Transmit DMA.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_disable_tx_dma(uint32_t uart)
{
UART_DMACTL(uart) &= ~UART_DMACTL_TXDMAE;
}
/**@}*/
/** @defgroup uart_fifo UART FIFO control
* @ingroup uart_file
*
* \brief <b>Enabling and controlling UART FIFO</b>
*
* The UART on the LM4F can either be used with a single character TX and RX
* buffer, or with a 8 character TX and RX FIFO. In order to use the FIFO it
* must be enabled, this is done with uart_enable_fifo() and can be disabled
* again with uart_disable_fifo(). On reset the FIFO is disabled, and it must
* be explicitly be enabled.
*
* When enabling the UART FIFOs, RX and TX interrupts are triggered according
* to the amount of data in the FIFOs. For the RX FIFO the trigger level is
* defined by how full the FIFO is. The TX FIFO trigger level is defined by
* how empty the FIFO is instead.
*
* For example, to enable the FIFOs and trigger interrupts for a single
* received and single transmitted character:
* @code{.c}
* uart_enable_fifo(UART0);
* uart_set_fifo_trigger_levels(UART0, UART_FIFO_RX_TRIG_1_8,
* UART_FIFO_TX_TRIG_7_8);
* @endcode
*/
/**@{*/
/**
* \brief Enable FIFO for the UART.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_enable_fifo(uint32_t uart)
{
UART_LCRH(uart) |= UART_LCRH_FEN;
}
/**
* \brief Disable FIFO for the UART.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_disable_fifo(uint32_t uart)
{
UART_LCRH(uart) &= ~UART_LCRH_FEN;
}
/**
* \brief Set the FIFO trigger levels.
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] rx_level Trigger level for RX FIFO
* @param[in] tx_level Trigger level for TX FIFO
*/
void uart_set_fifo_trigger_levels(uint32_t uart,
enum uart_fifo_rx_trigger_level rx_level,
enum uart_fifo_tx_trigger_level tx_level)
{
UART_IFLS(uart) = rx_level | tx_level;
}
/**@}*/
/**
* @}
*/

View File

@ -0,0 +1,651 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@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/>.
*/
/**
* @defgroup usb_file USB
*
* @ingroup LM4Fxx
*
* @author @htmlonly &copy; @endhtmlonly 2013
* Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* \brief <b>libopencm3 LM4F Universal Serial Bus controller </b>
*
* The LM4F USB driver is integrated with the libopencm3 USB stack. You should
* use the generic stack.
*
* To use this driver, tell the linker to look for it:
* @code{.c}
* extern usbd_driver lm4f_usb_driver;
* @endcode
*
* And pass this driver as an argument when initializing the USB stack:
* @code{.c}
* usbd_device *usbd_dev;
* usbd_dev = usbd_init(&lm4f_usb_driver, ...);
* @endcode
*
* <b>Polling or interrupt-driven? </b>
*
* The LM4F USB driver will work fine regardless of whether it is called from an
* interrupt service routine, or from the main program loop.
*
* Polling USB from the main loop requires calling @ref usbd_poll() from the
* main program loop.
* For example:
* @code{.c}
* // Main program loop
* while(1) {
* usbd_poll(usb_dev);
* do_other_stuff();
* ...
* @endcode
*
* Running @ref usbd_poll() from an interrupt has the advantage that it is only
* called when needed, saving CPU cycles for the main program.
*
* RESET, DISCON, RESUME, and SUSPEND interrupts must be enabled, along with the
* interrupts for any endpoint that is used. The EP0_TX interrupt must be
* enabled for the control endpoint to function correctly.
* For example, if EP1IN and EP2OUT are used, then the EP0_TX, EP1_TX, and
* EP2_RX interrupts should be enabled:
* @code{.c}
* // Enable USB interrupts for EP0, EP1IN, and EP2OUT
* ints = USB_INT_RESET | USB_INT_DISCON | USB_INT_RESUME |
* USB_INT_SUSPEND;
* usb_enable_interrupts(ints, USB_EP2_INT, USB_EP0_INT | USB_EP1_INT);
* // Route the interrupts through the NVIC
* nvic_enable_irq(NVIC_USB0_IRQ);
* @endcode
*
* The USB ISR only has to call @ref usbd_poll().
*
* @code{.c}
* void usb0_isr(void)
* {
* usbd_poll(usb_dev);
* }
* @endcode
* @{
*/
/*
* TODO list:
*
* 1) Driver works by reading and writing to the FIFOs one byte at a time. It
* has no knowledge of DMA.
* 2) Double-buffering is supported. How can we take advantage of it to speed
* up endpoint transfers.
* 3) No benchmarks as to the endpoint's performance has been done.
*/
/*
* The following are resources referenced in comments:
* [1] http://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/t/238784.aspx
*/
#include <libopencm3/cm3/common.h>
#include <libopencm3/lm4f/usb.h>
#include <libopencm3/lm4f/rcc.h>
#include <libopencm3/usb/usbd.h>
#include "../../lib/usb/usb_private.h"
#include <stdbool.h>
#define MAX_FIFO_RAM (4 * 1024)
const struct _usbd_driver lm4f_usb_driver;
/**
* \brief Enable Specific USB Interrupts
*
* Enable any combination of interrupts. Interrupts may be OR'ed together to
* enable them with one call. For example, to enable both the RESUME and RESET
* interrupts, pass (USB_INT_RESUME | USB_INT_RESET)
*
* Note that the NVIC must be enabled and properly configured for the interrupt
* to be routed to the CPU.
*
* @param[in] ints Interrupts which to enable. Any combination of interrupts may
* be specified by OR'ing then together
* @param[in] rx_ints Endpoints for which to generate an interrupt when a packet
* packet is received.
* @param[in] tx_ints Endpoints for which to generate an interrupt when a packet
* packet is finished transmitting.
*/
void usb_enable_interrupts(enum usb_interrupt ints,
enum usb_ep_interrupt rx_ints,
enum usb_ep_interrupt tx_ints)
{
USB_IE |= ints;
USB_RXIE |= rx_ints;
USB_TXIE |= tx_ints;
}
/**
* \brief Disable Specific USB Interrupts
*
* Disable any combination of interrupts. Interrupts may be OR'ed together to
* enable them with one call. For example, to disable both the RESUME and RESET
* interrupts, pass (USB_INT_RESUME | USB_INT_RESET)
*
* Note that the NVIC must be enabled and properly configured for the interrupt
* to be routed to the CPU.
*
* @param[in] ints Interrupts which to disable. Any combination of interrupts
* may be specified by OR'ing then together
* @param[in] rx_ints Endpoints for which to stop generating an interrupt when a
* packet packet is received.
* @param[in] tx_ints Endpoints for which to stop generating an interrupt when a
* packet packet is finished transmitting.
*/
void usb_disable_interrupts(enum usb_interrupt ints,
enum usb_ep_interrupt rx_ints,
enum usb_ep_interrupt tx_ints)
{
USB_IE &= ~ints;
USB_RXIE &= ~rx_ints;
USB_TXIE &= ~tx_ints;
}
/**
* @cond private
*/
static inline void lm4f_usb_soft_disconnect(void)
{
USB_POWER &= ~USB_POWER_SOFTCONN;
}
static inline void lm4f_usb_soft_connect(void)
{
USB_POWER |= USB_POWER_SOFTCONN;
}
static void lm4f_set_address(usbd_device *usbd_dev, uint8_t addr)
{
(void)usbd_dev;
USB_FADDR = addr & USB_FADDR_FUNCADDR_MASK;
}
static void lm4f_ep_setup(usbd_device *usbd_dev, uint8_t addr, uint8_t type,
uint16_t max_size,
void (*callback) (usbd_device *usbd_dev, uint8_t ep))
{
(void)usbd_dev;
(void)type;
uint8_t reg8;
uint16_t fifo_size;
const bool dir_tx = addr & 0x80;
const uint8_t ep = addr & 0x0f;
/*
* We do not mess with the maximum packet size, but we can only allocate
* the FIFO in power-of-two increments.
*/
if (max_size > 1024) {
fifo_size = 2048;
reg8 = USB_FIFOSZ_SIZE_2048;
} else if (max_size > 512) {
fifo_size = 1024;
reg8 = USB_FIFOSZ_SIZE_1024;
} else if (max_size > 256) {
fifo_size = 512;
reg8 = USB_FIFOSZ_SIZE_512;
} else if (max_size > 128) {
fifo_size = 256;
reg8 = USB_FIFOSZ_SIZE_256;
} else if (max_size > 64) {
fifo_size = 128;
reg8 = USB_FIFOSZ_SIZE_128;
} else if (max_size > 32) {
fifo_size = 64;
reg8 = USB_FIFOSZ_SIZE_64;
} else if (max_size > 16) {
fifo_size = 32;
reg8 = USB_FIFOSZ_SIZE_32;
} else if (max_size > 8) {
fifo_size = 16;
reg8 = USB_FIFOSZ_SIZE_16;
} else {
fifo_size = 8;
reg8 = USB_FIFOSZ_SIZE_8;
}
/* Endpoint 0 is more special */
if (addr == 0) {
USB_EPIDX = 0;
if (reg8 > USB_FIFOSZ_SIZE_64) {
reg8 = USB_FIFOSZ_SIZE_64;
}
/* The RX and TX FIFOs are shared for EP0 */
USB_RXFIFOSZ = reg8;
USB_TXFIFOSZ = reg8;
/*
* Regardless of how much we allocate, the first 64 bytes
* are always reserved for EP0.
*/
usbd_dev->fifo_mem_top_ep0 = 64;
return;
}
/* Are we out of FIFO space? */
if (usbd_dev->fifo_mem_top + fifo_size > MAX_FIFO_RAM) {
return;
}
USB_EPIDX = addr & USB_EPIDX_MASK;
/* FIXME: What about double buffering? */
if (dir_tx) {
USB_TXMAXP(ep) = max_size;
USB_TXFIFOSZ = reg8;
USB_TXFIFOADD = ((usbd_dev->fifo_mem_top) >> 3);
if (callback) {
usbd_dev->user_callback_ctr[ep][USB_TRANSACTION_IN] =
(void *)callback;
}
if (type == USB_ENDPOINT_ATTR_ISOCHRONOUS) {
USB_TXCSRH(ep) |= USB_TXCSRH_ISO;
} else {
USB_TXCSRH(ep) &= ~USB_TXCSRH_ISO;
}
} else {
USB_RXMAXP(ep) = max_size;
USB_RXFIFOSZ = reg8;
USB_RXFIFOADD = ((usbd_dev->fifo_mem_top) >> 3);
if (callback) {
usbd_dev->user_callback_ctr[ep][USB_TRANSACTION_OUT] =
(void *)callback;
}
if (type == USB_ENDPOINT_ATTR_ISOCHRONOUS) {
USB_RXCSRH(ep) |= USB_RXCSRH_ISO;
} else {
USB_RXCSRH(ep) &= ~USB_RXCSRH_ISO;
}
}
usbd_dev->fifo_mem_top += fifo_size;
}
static void lm4f_endpoints_reset(usbd_device *usbd_dev)
{
/*
* The core resets the endpoints automatically on reset.
* The first 64 bytes are always reserved for EP0
*/
usbd_dev->fifo_mem_top = 64;
}
static void lm4f_ep_stall_set(usbd_device *usbd_dev, uint8_t addr,
uint8_t stall)
{
(void)usbd_dev;
const uint8_t ep = addr & 0x0f;
const bool dir_tx = addr & 0x80;
if (ep == 0) {
if (stall) {
USB_CSRL0 |= USB_CSRL0_STALL;
} else {
USB_CSRL0 &= ~USB_CSRL0_STALL;
}
return;
}
if (dir_tx) {
if (stall) {
(USB_TXCSRL(ep)) |= USB_TXCSRL_STALL;
} else {
(USB_TXCSRL(ep)) &= ~USB_TXCSRL_STALL;
}
} else {
if (stall) {
(USB_RXCSRL(ep)) |= USB_RXCSRL_STALL;
} else {
(USB_RXCSRL(ep)) &= ~USB_RXCSRL_STALL;
}
}
}
static uint8_t lm4f_ep_stall_get(usbd_device *usbd_dev, uint8_t addr)
{
(void)usbd_dev;
const uint8_t ep = addr & 0x0f;
const bool dir_tx = addr & 0x80;
if (ep == 0) {
return USB_CSRL0 & USB_CSRL0_STALLED;
}
if (dir_tx) {
return USB_TXCSRL(ep) & USB_TXCSRL_STALLED;
} else {
return USB_RXCSRL(ep) & USB_RXCSRL_STALLED;
}
}
static void lm4f_ep_nak_set(usbd_device *usbd_dev, uint8_t addr, uint8_t nak)
{
(void)usbd_dev;
(void)addr;
(void)nak;
/* NAK's are handled automatically by hardware. Move along. */
}
static uint16_t lm4f_ep_write_packet(usbd_device *usbd_dev, uint8_t addr,
const void *buf, uint16_t len)
{
const uint8_t ep = addr & 0xf;
uint16_t i;
(void)usbd_dev;
/* Don't touch the FIFO if there is still a packet being transmitted */
if (ep == 0 && (USB_CSRL0 & USB_CSRL0_TXRDY)) {
return 0;
} else if (USB_TXCSRL(ep) & USB_TXCSRL_TXRDY) {
return 0;
}
/*
* We don't need to worry about buf not being aligned. If it's not,
* the reads are downgraded to 8-bit in hardware. We lose a bit of
* performance, but we don't crash.
*/
for (i = 0; i < (len & ~0x3); i += 4) {
USB_FIFO32(ep) = *((uint32_t *)(buf + i));
}
if (len & 0x2) {
USB_FIFO16(ep) = *((uint16_t *)(buf + i));
i += 2;
}
if (len & 0x1) {
USB_FIFO8(ep) = *((uint8_t *)(buf + i));
i += 1;
}
if (ep == 0) {
/*
* EP0 is very special. We should only set DATAEND when we
* transmit the last packet in the transaction. A transaction
* that is a multiple of 64 bytes will end with a zero-length
* packet, so our check is sane.
*/
if (len != 64) {
USB_CSRL0 |= USB_CSRL0_TXRDY | USB_CSRL0_DATAEND;
} else {
USB_CSRL0 |= USB_CSRL0_TXRDY;
}
} else {
USB_TXCSRL(ep) |= USB_TXCSRL_TXRDY;
}
return i;
}
static uint16_t lm4f_ep_read_packet(usbd_device *usbd_dev, uint8_t addr,
void *buf, uint16_t len)
{
(void)usbd_dev;
uint16_t rlen;
uint8_t ep = addr & 0xf;
uint16_t fifoin = USB_RXCOUNT(ep);
rlen = (fifoin > len) ? len : fifoin;
/*
* We don't need to worry about buf not being aligned. If it's not,
* the writes are downgraded to 8-bit in hardware. We lose a bit of
* performance, but we don't crash.
*/
for (len = 0; len < (rlen & ~0x3); len += 4) {
*((uint32_t *)(buf + len)) = USB_FIFO32(ep);
}
if (rlen & 0x2) {
*((uint16_t *)(buf + len)) = USB_FIFO16(ep);
len += 2;
}
if (rlen & 0x1) {
*((uint8_t *)(buf + len)) = USB_FIFO8(ep);
}
if (ep == 0) {
/*
* Clear RXRDY
* Datasheet says that DATAEND must also be set when clearing
* RXRDY. We don't do that. If did this when transmitting a
* packet larger than 64 bytes, only the first 64 bytes would
* be transmitted, followed by a handshake. The host would only
* get 64 bytes, seeing it as a malformed packet. Usually, we
* would not get past enumeration.
*/
USB_CSRL0 |= USB_CSRL0_RXRDYC;
} else {
USB_RXCSRL(ep) &= ~USB_RXCSRL_RXRDY;
}
return rlen;
}
static void lm4f_poll(usbd_device *usbd_dev)
{
void (*tx_cb)(usbd_device *usbd_dev, uint8_t ea);
void (*rx_cb)(usbd_device *usbd_dev, uint8_t ea);
int i;
/*
* The initial state of these registers might change, as we process the
* interrupt, but we need the initial state in order to decide how to
* handle events.
*/
const uint8_t usb_is = USB_IS;
const uint8_t usb_rxis = USB_RXIS;
const uint8_t usb_txis = USB_TXIS;
const uint8_t usb_csrl0 = USB_CSRL0;
if ((usb_is & USB_IM_SUSPEND) && (usbd_dev->user_callback_suspend)) {
usbd_dev->user_callback_suspend();
}
if ((usb_is & USB_IM_RESUME) && (usbd_dev->user_callback_resume)) {
usbd_dev->user_callback_resume();
}
if (usb_is & USB_IM_RESET) {
_usbd_reset(usbd_dev);
}
if ((usb_is & USB_IM_SOF) && (usbd_dev->user_callback_sof)) {
usbd_dev->user_callback_sof();
}
if (usb_txis & USB_EP0) {
/*
* The EP0 bit in USB_TXIS is special. It tells us that
* something happened on EP0, but does not tell us what. This
* bit does not necessarily tell us that a packet was
* transmitted, so we have to go through all the possibilities
* to figure out exactly what did. Only after we've exhausted
* all other possibilities, can we assume this is a EPO
* "transmit complete" interrupt.
*/
if (usb_csrl0 & USB_CSRL0_RXRDY) {
enum _usbd_transaction type;
type = (usbd_dev->control_state.state != DATA_OUT &&
usbd_dev->control_state.state != LAST_DATA_OUT)
? USB_TRANSACTION_SETUP :
USB_TRANSACTION_OUT;
if (usbd_dev->user_callback_ctr[0][type]) {
usbd_dev->
user_callback_ctr[0][type](usbd_dev, 0);
}
} else {
tx_cb = usbd_dev->user_callback_ctr[0]
[USB_TRANSACTION_IN];
/*
* EP0 bit in TXIS is set not only when a packet is
* finished transmitting, but also when RXRDY is set, or
* when we set TXRDY to transmit a packet. If any of
* those are the case, then we do not want to call our
* IN callback, since the state machine will be in the
* wrong state, and we'll just stall our control
* endpoint.
* In fact, the only way to know if it's time to call
* our TX callback is to know what to expect. The
* hardware does not tell us what sort of transaction
* this is. We need to work with the state machine to
* figure it all out. See [1] for details.
*/
if ((usbd_dev->control_state.state != DATA_IN) &&
(usbd_dev->control_state.state != LAST_DATA_IN) &&
(usbd_dev->control_state.state != STATUS_IN)) {
return;
}
if (tx_cb) {
tx_cb(usbd_dev, 0);
}
}
}
/* See which interrupt occurred */
for (i = 1; i < 8; i++) {
tx_cb = usbd_dev->user_callback_ctr[i][USB_TRANSACTION_IN];
rx_cb = usbd_dev->user_callback_ctr[i][USB_TRANSACTION_OUT];
if ((usb_txis & (1 << i)) && tx_cb) {
tx_cb(usbd_dev, i);
}
if ((usb_rxis & (1 << i)) && rx_cb) {
rx_cb(usbd_dev, i);
}
}
}
static void lm4f_disconnect(usbd_device *usbd_dev, bool disconnected)
{
(void)usbd_dev;
/*
* This is all it takes:
* usbd_disconnect(dev, 1) followed by usbd_disconnect(dev, 0)
* causes the device to re-enumerate and re-configure properly.
*/
if (disconnected) {
lm4f_usb_soft_disconnect();
} else {
lm4f_usb_soft_connect();
}
}
/*
* A static struct works as long as we have only one USB peripheral. If we
* meet LM4Fs with more than one USB, then we need to rework this approach.
*/
static struct _usbd_device usbd_dev;
/** Initialize the USB device controller hardware of the LM4F. */
static usbd_device *lm4f_usbd_init(void)
{
int i;
/* Start the USB clock */
periph_clock_enable(RCC_USB0);
/* Enable the USB PLL interrupts - used to assert PLL lock */
SYSCTL_IMC |= (SYSCTL_IMC_USBPLLLIM | SYSCTL_IMC_PLLLIM);
rcc_usb_pll_on();
/* Make sure we're disconnected. We'll reconnect later */
lm4f_usb_soft_disconnect();
/* Software reset USB */
SYSCTL_SRUSB = 1;
for (i = 0; i < 1000; i++) {
__asm__("nop");
}
SYSCTL_SRUSB = 0;
/*
* Wait for the PLL to lock before soft connecting
* This will result in a deadlock if the system clock is not setup
* correctly (clock from main oscillator).
*/
/* Wait for it */
i = 0;
while ((SYSCTL_RIS & SYSCTL_RIS_USBPLLLRIS) == 0) {
i++;
if (i > 0xffff) {
return 0;
}
}
/* Now connect to USB */
lm4f_usb_soft_connect();
/* No FIFO allocated yet, but the first 64 bytes are still reserved */
usbd_dev.fifo_mem_top = 64;
return &usbd_dev;
}
/* What is this thing even good for */
#define RX_FIFO_SIZE 512
const struct _usbd_driver lm4f_usb_driver = {
.init = lm4f_usbd_init,
.set_address = lm4f_set_address,
.ep_setup = lm4f_ep_setup,
.ep_reset = lm4f_endpoints_reset,
.ep_stall_set = lm4f_ep_stall_set,
.ep_stall_get = lm4f_ep_stall_get,
.ep_nak_set = lm4f_ep_nak_set,
.ep_write_packet = lm4f_ep_write_packet,
.ep_read_packet = lm4f_ep_read_packet,
.poll = lm4f_poll,
.disconnect = lm4f_disconnect,
.base_address = USB_BASE,
.set_address_before_status = false,
.rx_fifo_size = RX_FIFO_SIZE,
};
/**
* @endcond
*/
/**
* @}
*/

View File

@ -0,0 +1,39 @@
##
## 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_lpc13xx
PREFIX ?= arm-none-eabi
CC = $(PREFIX)-gcc
AR = $(PREFIX)-ar
CFLAGS = -Os -g \
-Wall -Wextra -Wimplicit-function-declaration \
-Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
-Wundef -Wshadow \
-I../../include -fno-common \
-mcpu=cortex-m3 -mthumb $(FP_FLAGS) -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD -DLPC13XX
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS = gpio.o
VPATH += ../cm3
include ../Makefile.include

View File

@ -0,0 +1,42 @@
/** @defgroup gpio_file GPIO
@ingroup LPC13xx
@brief <b>libopencm3 LPC13xx General Purpose I/O</b>
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2009 Uwe Hermann <uwe@hermann-uwe.de>
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 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/>.
*/
/**@{*/
#include <libopencm3/lpc13xx/gpio.h>
void gpio_set(uint32_t gpioport, uint16_t gpios)
{
GPIO_DATA(gpioport) = gpios;
}
/**@}*/

View File

@ -0,0 +1,106 @@
/*
* 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 LPC13XX 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
/* C++ Static constructors/destructors, also used for __attribute__
* ((constructor)) and the likes */
.preinit_array : {
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
} >rom
.init_array : {
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
} >rom
.fini_array : {
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
} >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));

View File

@ -0,0 +1,39 @@
##
## 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_lpc17xx
PREFIX ?= arm-none-eabi
CC = $(PREFIX)-gcc
AR = $(PREFIX)-ar
CFLAGS = -O0 -g \
-Wall -Wextra -Wimplicit-function-declaration \
-Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
-Wundef -Wshadow \
-I../../include -fno-common \
-mcpu=cortex-m3 -mthumb $(FP_FLAGS) -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD -DLPC17XX
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS = gpio.o
VPATH += ../cm3
include ../Makefile.include

View File

@ -0,0 +1,48 @@
/** @defgroup gpio_file GPIO
@ingroup LPC17xx
@brief <b>libopencm3 LPC17xx General Purpose I/O</b>
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2009 Uwe Hermann <uwe@hermann-uwe.de>
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 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/>.
*/
/**@{*/
#include <libopencm3/lpc17xx/gpio.h>
void gpio_set(uint32_t gpioport, uint32_t gpios)
{
GPIO_SET(gpioport) = gpios;
}
void gpio_clear(uint32_t gpioport, uint32_t gpios)
{
GPIO_CLR(gpioport) = gpios;
}
/**@}*/

View File

@ -0,0 +1,106 @@
/*
* 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 LPC13XX 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
/* C++ Static constructors/destructors, also used for __attribute__
* ((constructor)) and the likes */
.preinit_array : {
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
} >rom
.init_array : {
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
} >rom
.fini_array : {
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
} >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));

View File

@ -0,0 +1,58 @@
/** @defgroup gpio_file GPIO
@ingroup LPC43xx
@brief <b>libopencm3 LPC43xx General Purpose I/O</b>
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2009 Uwe Hermann <uwe@hermann-uwe.de>
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 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/>.
*/
/**@{*/
#include <libopencm3/lpc43xx/gpio.h>
void gpio_set(uint32_t gpioport, uint32_t gpios)
{
GPIO_SET(gpioport) = gpios;
}
void gpio_clear(uint32_t gpioport, uint32_t gpios)
{
GPIO_CLR(gpioport) = gpios;
}
void gpio_toggle(uint32_t gpioport, uint32_t gpios)
{
GPIO_NOT(gpioport) = gpios;
}
uint32_t gpio_get(uint32_t gpioport, uint32_t gpios)
{
return (GPIO_PIN(gpioport) & gpios) != 0;
}
/**@}*/

View File

@ -0,0 +1,203 @@
/** @defgroup i2c_file I2C
@ingroup LPC43xx
@brief <b>libopencm3 LPC43xx I2C</b>
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2012 Michael Ossmann <mike@ossmann.com>
@author @htmlonly &copy; @endhtmlonly 2014 Jared Boone <jared@sharebrained.com>
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Michael Ossmann <mike@ossmann.com>
* Copyright (C) 2014 Benjamin Vernoux <bvernoux@gmail.com>
* Copyright (C) 2014 Jared Boone <jared@sharebrained.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/>.
*/
/*
* This is a very minimal I2C driver just to make sure we can get the
* peripheral working.
*/
/**@{*/
#include <libopencm3/lpc43xx/i2c.h>
#include <libopencm3/lpc43xx/scu.h>
#include <libopencm3/lpc43xx/cgu.h>
#define I2C_TIMEOUT (10000)
#define SFSP_I2C1_SDA_SCL (0x00000001 | SCU_CONF_ZIF_DIS_IN_GLITCH_FILT | SCU_CONF_EZI_EN_IN_BUFFER)
void i2c_init(i2c_port_t port, const uint16_t duty_cycle_count)
{
I2C_SCLH(port) = duty_cycle_count;
I2C_SCLL(port) = duty_cycle_count;
/* clear the control bits */
I2C_CONCLR(port) = (I2C_CONCLR_AAC | I2C_CONCLR_SIC
| I2C_CONCLR_STAC | I2C_CONCLR_I2ENC);
/* enable I2C0 */
I2C_CONSET(port) = I2C_CONSET_I2EN;
}
void i2c_disable(i2c_port_t port) {
I2C_CONCLR(port) = I2C_CONCLR_I2ENC;
}
/* transmit start bit */
void i2c_tx_start(i2c_port_t port)
{
uint32_t timeout;
I2C_CONCLR(port) = I2C_CONCLR_SIC;
I2C_CONSET(port) = I2C_CONSET_STA;
timeout = 0;
while( (!(I2C_CONSET(port) & I2C_CONSET_SI)) && (timeout < I2C_TIMEOUT) )
{
timeout++;
}
I2C_CONCLR(port) = I2C_CONCLR_STAC;
}
/* transmit data byte */
void i2c_tx_byte(i2c_port_t port, uint8_t byte)
{
uint32_t timeout;
if (I2C_CONSET(port) & I2C_CONSET_STA) {
I2C_CONCLR(port) = I2C_CONCLR_STAC;
}
I2C_DAT(port) = byte;
I2C_CONCLR(port) = I2C_CONCLR_SIC;
timeout = 0;
while( (!(I2C_CONSET(port) & I2C_CONSET_SI)) && (timeout < I2C_TIMEOUT) )
{
timeout++;
}
}
/* receive data byte */
uint8_t i2c_rx_byte(i2c_port_t port, bool ack)
{
uint32_t timeout;
if (I2C_CONSET(port) & I2C_CONSET_STA) {
I2C_CONCLR(port) = I2C_CONCLR_STAC;
}
I2C_CONCLR(port) = I2C_CONCLR_SIC;
if (ack) {
I2C_CONSET(port) = I2C_CONSET_AA;
} else {
I2C_CONCLR(port) = I2C_CONCLR_AAC;
}
timeout = 0;
while( (!(I2C_CONSET(port) & I2C_CONSET_SI)) && (timeout < I2C_TIMEOUT) )
{
timeout++;
}
return I2C_DAT(port);
}
/* transmit stop bit */
void i2c_stop(i2c_port_t port)
{
if (I2C_CONSET(port) & I2C_CONSET_STA) {
I2C_CONCLR(port) = I2C_CONCLR_STAC;
}
I2C_CONSET(port) = I2C_CONSET_STO;
I2C_CONCLR(port) = I2C_CONCLR_SIC;
}
/* I2C0 wrappers for compatibility with old code */
void i2c0_init(const uint16_t duty_cycle_count)
{
/* enable input on SCL and SDA pins */
SCU_SFSI2C0 = SCU_I2C0_NOMINAL;
i2c_init(I2C0, duty_cycle_count);
}
void i2c1_init(const uint16_t duty_cycle_count)
{
/* Configure pin function for I2C1*/
SCU_SFSP2_3 = SFSP_I2C1_SDA_SCL;
SCU_SFSP2_4 = SFSP_I2C1_SDA_SCL;
i2c_init(I2C1, duty_cycle_count);
}
/* transmit start bit */
void i2c0_tx_start(void)
{
i2c_tx_start(I2C0);
}
/* transmit start bit */
void i2c1_tx_start(void)
{
i2c_tx_start(I2C1);
}
/* transmit data byte */
void i2c0_tx_byte(uint8_t byte)
{
i2c_tx_byte(I2C0, byte);
}
/* transmit data byte */
void i2c1_tx_byte(uint8_t byte)
{
i2c_tx_byte(I2C1, byte);
}
/* receive data byte */
uint8_t i2c0_rx_byte(bool ack) {
return i2c_rx_byte(I2C0, ack);
}
/* receive data byte */
uint8_t i2c1_rx_byte(bool ack) {
return i2c_rx_byte(I2C1, ack);
}
/* transmit stop bit */
void i2c0_stop(void)
{
i2c_stop(I2C0);
}
/* transmit stop bit */
void i2c1_stop(void)
{
i2c_stop(I2C1);
}
/**@}*/

View File

@ -0,0 +1,61 @@
/*
* This file is part of the libopencm3 project.
*
* 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/ipc.h>
#include <libopencm3/lpc43xx/creg.h>
#include <libopencm3/lpc43xx/rgu.h>
/* Set M0 in reset mode */
void ipc_halt_m0(void)
{
volatile uint32_t rst_active_status1;
/* Check if M0 is reset by reading status */
rst_active_status1 = RESET_ACTIVE_STATUS1;
/* If the M0 has reset not asserted, halt it... */
while (rst_active_status1 & RESET_CTRL1_M0APP_RST) {
RESET_CTRL1 = ((~rst_active_status1) | RESET_CTRL1_M0APP_RST);
rst_active_status1 = RESET_ACTIVE_STATUS1;
}
}
void ipc_start_m0(uint32_t cm0_baseaddr)
{
volatile uint32_t rst_active_status1;
/* Set M0 memory mapping to point to start of M0 image */
CREG_M0APPMEMMAP = cm0_baseaddr;
/* Start/run M0 core */
/* Release Slave from reset, first read status */
rst_active_status1 = RESET_ACTIVE_STATUS1;
/* If the M0 is being held in reset, release it */
/* 1 = no reset, 0 = reset */
while (!(rst_active_status1 & RESET_CTRL1_M0APP_RST)) {
RESET_CTRL1 = ((~rst_active_status1) & ~RESET_CTRL1_M0APP_RST);
rst_active_status1 = RESET_ACTIVE_STATUS1;
}
}
void ipc_m0apptxevent_clear(void) {
CREG_M0TXEVENT &= ~CREG_M0TXEVENT_TXEVCLR;
}

View File

@ -0,0 +1,42 @@
##
## This file is part of the libopencm3 project.
##
## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
## Copyright (C) 2012 Michael Ossmann <mike@ossmann.com>
## Copyright (C) 2012/2013 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/>.
##
LIBNAME = libopencm3_lpc43xx_m0
PREFIX ?= arm-none-eabi
#PREFIX ?= arm-elf
CC = $(PREFIX)-gcc
AR = $(PREFIX)-ar
CFLAGS = -O2 -g3 -Wall -Wextra -I../../../include -fno-common \
-mcpu=cortex-m0 -mthumb -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD -DLPC43XX -DLPC43XX_M0
# ARFLAGS = rcsv
ARFLAGS = rcs
# LPC43xx common files for M4 / M0
OBJ_LPC43XX = gpio.o scu.o i2c.o ssp.o uart.o timer.o
#LPC43xx M0 specific file + Generic LPC43xx M4/M0 files
OBJS = $(OBJ_LPC43XX)
VPATH += ../:../../cm3
include ../../Makefile.include

View File

@ -0,0 +1,121 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
* Copyright (C) 2012 Michael Ossmann <mike@ossmann.com>
* Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
* Copyright (C) 2012 Jared Boone <jared@sharebrained.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/>.
*/
/* Generic linker script for LPC43XX 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(ram);
.text : {
. = ALIGN(0x400);
*(.vectors) /* Vector table */
*(.text*) /* Program code */
. = ALIGN(4);
*(.rodata*) /* Read-only data */
. = ALIGN(4);
} >ram
/* C++ Static constructors/destructors, also used for __attribute__
* ((constructor)) and the likes */
.preinit_array : {
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
} >ram
.init_array : {
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
} >ram
.fini_array : {
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
} >ram
/*
* Another section used by C++ stuff, appears when using newlib with
* 64bit (long long) printf support
*/
.ARM.extab : {
*(.ARM.extab*)
} >ram
/* exception index - required due to libgcc.a issuing /0 exceptions */
.ARM.exidx : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >ram
. = ALIGN(4);
_etext = .;
.data : {
_data = .;
*(.data*) /* Read-write initialized data */
. = ALIGN(4);
_edata = .;
} >ram
_data_loadaddr = _data; /* Force src and dest equal (no-op) */
_edata = _data; /* Prevent copying data */
.bss : {
_bss = .;
*(.bss*) /* Read-write zero initialized data */
*(COMMON)
. = ALIGN(4);
_ebss = .;
} >ram
/* exception unwind data - required due to libgcc.a issuing /0 exceptions */
.ARM.extab : {
*(.ARM.extab*)
} >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 = .;
__StackTop = ORIGIN(ram) + LENGTH(ram);
PROVIDE(_stack = __StackTop);
}

View File

@ -0,0 +1,49 @@
##
## This file is part of the libopencm3 project.
##
## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
## Copyright (C) 2012 Michael Ossmann <mike@ossmann.com>
## Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
## Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@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/>.
##
LIBNAME = libopencm3_lpc43xx
FP_FLAGS ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16
PREFIX ?= arm-none-eabi
CC = $(PREFIX)-gcc
AR = $(PREFIX)-ar
CFLAGS = -O2 -g3 \
-Wall -Wextra -Wimplicit-function-declaration \
-Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
-Wundef -Wshadow \
-I../../../include -fno-common \
-mcpu=cortex-m4 -mthumb -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD \
$(FP_FLAGS) -DLPC43XX -DLPC43XX_M4
ARFLAGS = rcs
# LPC43xx common files for M4 / M0
OBJ_LPC43XX = gpio.o scu.o i2c.o ssp.o uart.o timer.o wwdt.o
#LPC43xx M4 specific file + Generic LPC43xx M4/M0 files
OBJS = $(OBJ_LPC43XX) ipc.o
VPATH += ../:../../cm3
include ../../Makefile.include

View File

@ -0,0 +1,127 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
* Copyright (C) 2012 Michael Ossmann <mike@ossmann.com>
* Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
* Copyright (C) 2012 Jared Boone <jared@sharebrained.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/>.
*/
/* Generic linker script for LPC43XX 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 : {
. = ALIGN(0x400);
_text_ram = 0; /* Start of Code in RAM NULL because Copy of Code from ROM to RAM disabled */
*(.vectors) /* Vector table */
*(.text*) /* Program code */
. = ALIGN(4);
*(.rodata*) /* Read-only data */
. = ALIGN(4);
} >rom
/* C++ Static constructors/destructors, also used for __attribute__
* ((constructor)) and the likes */
.preinit_array : {
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
} >rom
.init_array : {
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
} >rom
.fini_array : {
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
} >rom
/*
* Another section used by C++ stuff, appears when using newlib with
* 64bit (long long) printf support
*/
.ARM.extab : {
*(.ARM.extab*)
} >rom
/* exception index - required due to libgcc.a issuing /0 exceptions */
.ARM.exidx : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >rom
. = ALIGN(4);
_etext = .;
_etext_ram = 0; /* Start of Code in RAM NULL because Copy of Code from ROM to RAM disabled */
_etext_rom = 0; /* Start of Code in RAM NULL because Copy of Code from ROM to RAM disabled */
. = ORIGIN(ram_local2);
.data : {
_data = .;
*(.data*) /* Read-write initialized data */
. = ALIGN(4);
_edata = .;
} >ram_local2 AT >rom
_data_loadaddr = LOADADDR(.data);
_data_rom = LOADADDR (.data) + ORIGIN(rom);
_edata_rom = _data_rom + SIZEOF (.data);
.bss : {
_bss = .;
*(.bss*) /* Read-write zero initialized data */
*(COMMON)
. = ALIGN(4);
_ebss = .;
} >ram_local2
/* exception unwind data - required due to libgcc.a issuing /0 exceptions */
.ARM.extab : {
*(.ARM.extab*)
} >ram_local2
/*
* 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 = .;
/* Leave room above stack for IAP to run. */
__StackTop = ORIGIN(ram_local2) + LENGTH(ram_local2) - 32;
PROVIDE(_stack = __StackTop);
}

View File

@ -0,0 +1,139 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
* Copyright (C) 2012 Michael Ossmann <mike@ossmann.com>
* Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
* Copyright (C) 2012 Jared Boone <jared@sharebrained.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/>.
*/
/* Generic linker script for LPC43XX 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(ram_local1);
.text : {
. = ALIGN(0x400);
_text_ram = 0; /* Start of Code in RAM NULL because Copy of Code from ROM to RAM disabled */
*(.vectors) /* Vector table */
*(.text*) /* Program code */
. = ALIGN(4);
*(.rodata*) /* Read-only data */
. = ALIGN(4);
} >ram_local1
/* C++ Static constructors/destructors, also used for __attribute__
* ((constructor)) and the likes */
.preinit_array : {
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
} >ram_local1
.init_array : {
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
} >ram_local1
.fini_array : {
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
} >ram_local1
/*
* Another section used by C++ stuff, appears when using newlib with
* 64bit (long long) printf support
*/
.ARM.extab : {
*(.ARM.extab*)
} >ram_local1
/* exception index - required due to libgcc.a issuing /0 exceptions */
__exidx_start = .;
.ARM.exidx : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} > ram_local1
. = ALIGN(4);
_etext = .;
_etext_ram = 0; /* Start of Code in RAM NULL because Copy of Code from ROM to RAM disabled */
_etext_rom = 0; /* Start of Code in RAM NULL because Copy of Code from ROM to RAM disabled */
. = ORIGIN(ram_local2);
.data : {
_data = .;
*(.data*) /* Read-write initialized data */
. = ALIGN(4);
_edata = .;
} >ram_local2
_data_loadaddr = LOADADDR(.data);
/* Running from RAM only, loading the .elf will initialize data for us. */
_data_rom = .;
_edata_rom = .;
_data = .;
_edata = .;
.bss : {
_bss = .;
*(.bss*) /* Read-write zero initialized data */
*(COMMON)
. = ALIGN(4);
_ebss = .;
} >ram_local2
/* exception unwind data - required due to libgcc.a issuing /0 exceptions */
.ARM.extab : {
*(.ARM.extab*)
} >ram_local2
/*
* 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) }
end = .;
/* Leave room above stack for IAP to run. */
__StackTop = ORIGIN(ram_local2) + LENGTH(ram_local2) - 32;
PROVIDE(_stack = __StackTop);
}

View File

@ -0,0 +1,128 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
* Copyright (C) 2012 Michael Ossmann <mike@ossmann.com>
* Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
* Copyright (C) 2012 Jared Boone <jared@sharebrained.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/>.
*/
/* Generic linker script for LPC43XX 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 : {
. = ALIGN(0x400);
_text_ram = (. - ORIGIN(rom)) + ORIGIN(ram_local1); /* Start of Code in RAM */
*(.vectors) /* Vector table */
*(.text*) /* Program code */
. = ALIGN(4);
*(.rodata*) /* Read-only data */
. = ALIGN(4);
} >rom
/* C++ Static constructors/destructors, also used for __attribute__
* ((constructor)) and the likes */
.preinit_array : {
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
} >rom
.init_array : {
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
} >rom
.fini_array : {
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
} >rom
/*
* Another section used by C++ stuff, appears when using newlib with
* 64bit (long long) printf support
*/
.ARM.extab : {
*(.ARM.extab*)
} >rom
/* exception index - required due to libgcc.a issuing /0 exceptions */
.ARM.exidx : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >rom
. = ALIGN(4);
_etext = .;
_etext_ram = (. - ORIGIN(rom)) + ORIGIN(ram_local1);
_etext_rom = (. - ORIGIN(rom)) + ORIGIN(rom_flash);
. = ORIGIN(ram_local2);
.data : {
_data = .;
*(.data*) /* Read-write initialized data */
. = ALIGN(4);
_edata = .;
} >ram_local2 AT >rom
_data_loadaddr = LOADADDR(.data);
_data_rom = LOADADDR (.data) + ORIGIN(rom_flash);
_edata_rom = _data_rom + SIZEOF (.data);
.bss : {
_bss = .;
*(.bss*) /* Read-write zero initialized data */
*(COMMON)
. = ALIGN(4);
_ebss = .;
} >ram_local2
/* exception unwind data - required due to libgcc.a issuing /0 exceptions */
.ARM.extab : {
*(.ARM.extab*)
} >ram_local2
/*
* 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 = .;
/* Leave room above stack for IAP to run. */
__StackTop = ORIGIN(ram_local2) + LENGTH(ram_local2) - 32;
PROVIDE(_stack = __StackTop);
}

View File

@ -0,0 +1,52 @@
/*
* 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>
#include <libopencm3/cm3/scb.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 */
}
/* Enable access to Floating-Point coprocessor. */
SCB_CPACR |= SCB_CPACR_FULL * (SCB_CPACR_CP10 | SCB_CPACR_CP11);
}

View File

@ -0,0 +1,52 @@
/** @defgroup scu_file System Control Unit
@ingroup LPC43xx
@brief <b>libopencm3 LPC43xx System Control Unit</b>
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2012 Benjamin Vernoux <titanmkd@gmail.com>
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* 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/scu.h>
/* For pin_conf_normal value see scu.h define SCU_CONF_XXX or Configuration for
* different I/O pins types
*/
void scu_pinmux(scu_grp_pin_t group_pin, uint32_t scu_conf)
{
MMIO32(group_pin) = scu_conf;
}
/* For other special SCU register USB1, I2C0, ADC0/1, DAC, EMC clock delay See
* scu.h
*/
/* For Pin interrupt select register see scu.h SCU_PINTSEL0 & SCU_PINTSEL1 */
/**@}*/

View File

@ -0,0 +1,146 @@
/** @defgroup ssp_file SSP
@ingroup LPC43xx
@brief <b>libopencm3 LPC43xx SSP</b>
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2012/2014 Benjamin Vernoux <bvernoux@gmail.com>
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Benjamin Vernoux <bvernoux@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/ssp.h>
#include <libopencm3/lpc43xx/ccu.h>
#include <libopencm3/lpc43xx/cgu.h>
/* Disable SSP */
void ssp_disable(ssp_num_t ssp_num)
{
uint32_t ssp_port;
if (ssp_num == SSP0_NUM) {
ssp_port = SSP0;
} else {
ssp_port = SSP1;
}
/* Disable SSP */
SSP_CR1(ssp_port) = 0x0;
}
/*
* SSP Init function
*/
void ssp_init(ssp_num_t ssp_num,
ssp_datasize_t data_size,
ssp_frame_format_t frame_format,
ssp_cpol_cpha_t cpol_cpha_format,
uint8_t serial_clock_rate,
uint8_t clk_prescale,
ssp_mode_t mode,
ssp_master_slave_t master_slave,
ssp_slave_option_t slave_option)
{
uint32_t ssp_port;
uint32_t clock;
if (ssp_num == SSP0_NUM)
{
ssp_port = SSP0;
CGU_BASE_SSP0_CLK = CGU_BASE_SSP0_CLK_CLK_SEL(CGU_SRC_PLL1)
| CGU_BASE_SSP0_CLK_AUTOBLOCK(1);
CCU1_CLK_M4_SSP0_CFG |= 1; /* Enable SSP0 Clock */
/* use PLL1 as clock source for SSP0 */
} else
{
ssp_port = SSP1;
/* use PLL1 as clock source for SSP1 */
CGU_BASE_SSP1_CLK = CGU_BASE_SSP1_CLK_CLK_SEL(CGU_SRC_PLL1)
| CGU_BASE_SSP1_CLK_AUTOBLOCK(1);
CCU1_CLK_M4_SSP1_CFG |= 1; /* Enable SSP1 Clock */
}
/* Disable SSP before to configure it */
SSP_CR1(ssp_port) = 0x0;
/* Configure SSP */
clock = serial_clock_rate;
SSP_CPSR(ssp_port) = clk_prescale;
SSP_CR0(ssp_port) =
(data_size | frame_format | cpol_cpha_format | (clock<<8));
/* Enable SSP */
SSP_CR1(ssp_port) = (SSP_ENABLE | mode | master_slave | slave_option);
}
static void ssp_wait_until_not_busy(ssp_num_t ssp_num)
{
uint32_t ssp_port;
if (ssp_num == SSP0_NUM) {
ssp_port = SSP0;
} else {
ssp_port = SSP1;
}
while ((SSP_SR(ssp_port) & SSP_SR_BSY));
}
/* This Function Wait Data TX Ready, and Write Data to SSP */
uint16_t ssp_transfer(ssp_num_t ssp_num, uint16_t data)
{
uint32_t ssp_port;
if (ssp_num == SSP0_NUM) {
ssp_port = SSP0;
} else {
ssp_port = SSP1;
}
/* Wait Until FIFO not full */
while ((SSP_SR(ssp_port) & SSP_SR_TNF) == 0);
SSP_DR(ssp_port) = data;
/* Wait for not busy, since we're controlling CS# of
* devices manually and need to wait for the data to
* be sent. It may also be important to wait here
* in case we're configuring devices via SPI and also
* with GPIO control -- we need to know when SPI
* commands are effective before altering a device's
* state with GPIO. I'm thinking the MAX2837, for
* example...
*/
ssp_wait_until_not_busy(ssp_num);
/* Wait Until Data Received (Rx FIFO not Empty) */
while ((SSP_SR(ssp_port) & SSP_SR_RNE) == 0);
return SSP_DR(ssp_port);
}
/**@}*/

View File

@ -0,0 +1,72 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2013 Ben Gamari <bgamari@physics.umass.edu>
*
* 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/>.
*
* This provides the code for the "next gen" EXTI block provided in F2/F4/L1
* devices. (differences only in the source selection)
*/
#include <libopencm3/lpc43xx/timer.h>
void timer_reset(uint32_t timer_peripheral)
{
TIMER_TCR(timer_peripheral) |= TIMER_TCR_CRST;
TIMER_TCR(timer_peripheral) &= ~TIMER_TCR_CRST;
}
void timer_enable_counter(uint32_t timer_peripheral)
{
TIMER_TCR(timer_peripheral) |= TIMER_TCR_CEN;
}
void timer_disable_counter(uint32_t timer_peripheral)
{
TIMER_TCR(timer_peripheral) &= ~TIMER_TCR_CEN;
}
void timer_set_counter(uint32_t timer_peripheral, uint32_t count)
{
TIMER_TC(timer_peripheral) = count;
}
uint32_t timer_get_counter(uint32_t timer_peripheral)
{
return TIMER_TC(timer_peripheral);
}
uint32_t timer_get_prescaler(uint32_t timer_peripheral)
{
return TIMER_PR(timer_peripheral);
}
void timer_set_prescaler(uint32_t timer_peripheral, uint32_t prescaler)
{
TIMER_PR(timer_peripheral) = prescaler;
}
void timer_set_mode(uint32_t timer_peripheral, uint32_t mode)
{
TIMER_CTCR(timer_peripheral) = mode |
(TIMER_CTCR(timer_peripheral) & TIMER_CTCR_MODE_MASK);
}
void timer_set_count_input(uint32_t timer_peripheral, uint32_t input)
{
TIMER_CTCR(timer_peripheral) = input |
(TIMER_CTCR(timer_peripheral) & TIMER_CTCR_CINSEL_MASK);
}

View File

@ -0,0 +1,243 @@
/*
* This file is part of the libopencm3 project.
*
* 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/uart.h>
#include <libopencm3/lpc43xx/cgu.h>
#define UART_SRC_32K 0x00
#define UART_SRC_IRC 0x01
#define UART_SRC_ENET_RX 0x02
#define UART_SRC_ENET_TX 0x03
#define UART_SRC_GP_CLKIN 0x04
#define UART_SRC_XTAL 0x06
#define UART_SRC_PLL0USB 0x07
#define UART_SRC_PLL0AUDIO 0x08
#define UART_SRC_PLL1 0x09
#define UART_SRC_IDIVA 0x0C
#define UART_SRC_IDIVB 0x0D
#define UART_SRC_IDIVC 0x0E
#define UART_SRC_IDIVD 0x0F
#define UART_SRC_IDIVE 0x10
#define UART_CGU_AUTOBLOCK_CLOCK_BIT 11
/* clock source selection (5 bits) */
#define UART_CGU_BASE_CLK_SEL_SHIFT 24
uint32_t dummy_read;
/*
* UART Init function
*/
void uart_init(uart_num_t uart_num, uart_databit_t data_nb_bits,
uart_stopbit_t data_nb_stop, uart_parity_t data_parity,
uint16_t uart_divisor, uint8_t uart_divaddval, uint8_t uart_mulval)
{
uint32_t lcr_config;
uint32_t uart_port;
uart_port = uart_num;
switch (uart_num) {
case UART0_NUM:
/* use PLL1 as clock source for UART0 */
CGU_BASE_UART0_CLK = (1<<UART_CGU_AUTOBLOCK_CLOCK_BIT) |
(CGU_SRC_PLL1<<UART_CGU_BASE_CLK_SEL_SHIFT);
break;
case UART1_NUM:
/* use PLL1 as clock source for UART1 */
CGU_BASE_UART1_CLK = (1<<UART_CGU_AUTOBLOCK_CLOCK_BIT) |
(CGU_SRC_PLL1<<UART_CGU_BASE_CLK_SEL_SHIFT);
break;
case UART2_NUM:
/* use PLL1 as clock source for UART2 */
CGU_BASE_UART2_CLK = (1<<UART_CGU_AUTOBLOCK_CLOCK_BIT) |
(CGU_SRC_PLL1<<UART_CGU_BASE_CLK_SEL_SHIFT);
break;
case UART3_NUM:
/* use PLL1 as clock source for UART3 */
CGU_BASE_UART3_CLK = (1<<UART_CGU_AUTOBLOCK_CLOCK_BIT) |
(CGU_SRC_PLL1<<UART_CGU_BASE_CLK_SEL_SHIFT);
break;
default:
return; /* error */
}
/* FIFOs RX/TX Enabled and Reset RX/TX FIFO (DMA Mode is also cleared)*/
UART_FCR(uart_port) = (UART_FCR_FIFO_EN | UART_FCR_RX_RS |
UART_FCR_TX_RS);
/* Disable FIFO */
UART_FCR(uart_port) = 0;
/* Dummy read (to clear existing data) */
while (UART_LSR(uart_port) & UART_LSR_RDR) {
dummy_read = UART_RBR(uart_port);
}
/* Wait end of TX & disable TX */
UART_TER(uart_port) = UART_TER_TXEN;
/* Wait for current transmit complete */
while (!(UART_LSR(uart_port) & UART_LSR_THRE));
/* Disable Tx */
UART_TER(uart_port) = 0;
/* Disable interrupt */
UART_IER(uart_port) = 0;
/* Set LCR to default state */
UART_LCR(uart_port) = 0;
/* Set ACR to default state */
UART_ACR(uart_port) = 0;
/* Dummy Read to Clear Status */
dummy_read = UART_LSR(uart_port);
/*
Table 835. USART Fractional Divider Register:
UARTbaudrate = PCLK / ( 16* (((256*DLM)+ DLL)*(1+(DivAddVal/MulVal))) )
The value of MULVAL and DIVADDVAL should comply to the following
conditions:
1. 1 <= MULVAL <= 15
2. 0 <= DIVADDVAL <= 14
3. DIVADDVAL < MULVAL
*/
/* Set DLAB Bit */
UART_LCR(uart_port) |= UART_LCR_DLAB_EN;
UART_DLM(uart_port) = UART_LOAD_DLM(uart_divisor);
UART_DLL(uart_port) = UART_LOAD_DLL(uart_divisor);
/* Clear DLAB Bit */
UART_LCR(uart_port) &= (~UART_LCR_DLAB_EN) & UART_LCR_BITMASK;
UART_FDR(uart_port) = UART_FDR_BITMASK &
(UART_FDR_MULVAL(uart_mulval) | UART_FDR_DIVADDVAL(uart_divaddval));
/* Read LCR config & Force Enable of Divisor Latches Access */
lcr_config = (UART_LCR(uart_port) & UART_LCR_DLAB_EN) &
UART_LCR_BITMASK;
lcr_config |= data_nb_bits; /* Set Nb Data Bits */
lcr_config |= data_nb_stop; /* Set Nb Stop Bits */
lcr_config |= data_parity; /* Set Data Parity */
/* Write LCR (only 8bits) */
UART_LCR(uart_port) = (lcr_config & UART_LCR_BITMASK);
/* Enable TX */
UART_TER(uart_port) = UART_TER_TXEN;
}
/*
* This Function return if data are received or not received.
*/
uart_rx_data_ready_t uart_rx_data_ready(uart_num_t uart_num)
{
uint32_t uart_port;
uint8_t uart_status;
uart_rx_data_ready_t data_ready;
uart_port = uart_num;
uart_status = UART_LSR(uart_port) & 0xFF;
/* Check Error */
if ((uart_status & UART_LSR_ERROR_MASK) == 0) {
/* No errors check if data is ready */
if ((uart_status & UART_LSR_RDR) == 0) {
data_ready = UART_RX_NO_DATA;
} else {
data_ready = UART_RX_DATA_READY;
}
} else {
/* UART Error */
data_ready = UART_RX_DATA_ERROR;
}
return data_ready;
}
/*
* This Function Wait until Data RX Ready, and return Data Read from UART.
*/
uint8_t uart_read(uart_num_t uart_num)
{
uint32_t uart_port;
uint8_t uart_val;
uart_port = uart_num;
/* Wait Until Data Received (Rx Data Not Ready) */
while ((UART_LSR(uart_port) & UART_LSR_RDR) == 0);
uart_val = (UART_RBR(uart_port) & UART_RBR_MASKBIT);
return uart_val;
}
/*
* This Function Wait until Data RX Ready, and return Data Read from UART.
*/
uint8_t uart_read_timeout(uart_num_t uart_num, uint32_t rx_timeout_nb_cycles,
uart_error_t *error)
{
uint32_t uart_port;
uint8_t uart_val;
uint32_t counter;
uart_port = uart_num;
/* Wait Until Data Received (Rx Data Not Ready) */
counter = 0;
while ((UART_LSR(uart_port) & UART_LSR_RDR) == 0) {
if (rx_timeout_nb_cycles > 0) {
counter++;
if (counter >= rx_timeout_nb_cycles) {
*error = UART_TIMEOUT_ERROR;
return 0;
}
}
}
uart_val = (UART_RBR(uart_port) & UART_RBR_MASKBIT);
/* Clear error */
*error = UART_NO_ERROR;
return uart_val;
}
/* This Function Wait Data TX Ready, and Write Data to UART
if rx_timeout_nb_cycles = 0 Infinite wait
*/
void uart_write(uart_num_t uart_num, uint8_t data)
{
uint32_t uart_port;
uart_port = uart_num;
/* Wait Until FIFO not full */
while ((UART_LSR(uart_port) & UART_LSR_THRE) == 0);
UART_THR(uart_port) = data;
}

View File

@ -0,0 +1,27 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2016 Dominic Spill <dominicgs@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/wwdt.h>
void wwdt_reset(uint32_t timeout) {
WWDT_MOD = WWDT_MOD_WDEN | WWDT_MOD_WDRESET;
timeout &= 0xFFFFFF;
WWDT_TC = timeout;
WWDT_FEED_SEQUENCE;
}

View File

@ -0,0 +1,69 @@
##
## This file is part of the libopencm3 project.
##
## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
## Copyright (C) 2012 Michael Ossmann <mike@ossmann.com>
## Copyright (C) 2012/2013 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/>.
##
LIBNAME = libopencm3_lpc43xx_m0
PREFIX ?= arm-none-eabi
#PREFIX ?= arm-elf
CC = $(PREFIX)-gcc
AR = $(PREFIX)-ar
CFLAGS = -O2 -g3 -Wall -Wextra -I../../include -fno-common \
-mcpu=cortex-m0 -mthumb -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD
# ARFLAGS = rcsv
ARFLAGS = rcs
# LPC43xx common files for M4 / M0
OBJ_LPC43XX = gpio.o scu.o i2c.o ssp.o nvic.o uart.o
#LPC43xx M0 specific file + Generic LPC43xx M4/M0 files
OBJS = vector.o $(OBJ_LPC43XX)
# VPATH += ../usb
# Be silent per default, but 'make V=1' will show all compiler calls.
ifneq ($(V),1)
Q := @
endif
all: $(LIBNAME).a
$(LIBNAME).a: $(OBJS)
@printf " AR $(subst $(shell pwd)/,,$(@))\n"
$(Q)$(AR) $(ARFLAGS) $@ $^
%.o: %.c
@printf " CC $(subst $(shell pwd)/,,$(@))\n"
$(Q)$(CC) $(CFLAGS) -o $@ -c $<
%.o: ../lpc43xx/%.c
@printf " CC $(subst $(shell pwd)/,,$(@))\n"
$(Q)$(CC) $(CFLAGS) -o $@ -c $<
clean:
@printf " CLEAN lib/lpc43xx_m0\n"
$(Q)rm -f *.o *.d
$(Q)rm -f $(LIBNAME).a
.PHONY: clean
-include $(OBJS:.o=.d)

View File

@ -0,0 +1,191 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Piotr Esden-Tempski <piotr@esden.net>,
* Copyright (C) 2012 chrysn <chrysn@fsfe.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/>.
*/
#define WEAK __attribute__ ((weak))
/* Symbols exported by the linker script(s): */
extern unsigned _bss, _ebss, _stack;
void main(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 m0_rtc_isr(void);
void WEAK m0_m4core_isr(void);
void WEAK m0_dma_isr(void);
void WEAK m0_ethernet_isr(void);
void WEAK m0_flasheepromat_isr(void);
void WEAK m0_sdio_isr(void);
void WEAK m0_lcd_isr(void);
void WEAK m0_usb0_isr(void);
void WEAK m0_usb1_isr(void);
void WEAK m0_sct_isr(void);
void WEAK m0_ritimer_or_wwdt_isr(void);
void WEAK m0_timer0_isr(void);
void WEAK m0_gint1_isr(void);
void WEAK m0_pin_int4_isr(void);
void WEAK m0_timer3_isr(void);
void WEAK m0_mcpwm_isr(void);
void WEAK m0_adc0_isr(void);
void WEAK m0_i2c0_or_i2c1_isr(void);
void WEAK m0_sgpio_isr(void);
void WEAK m0_spi_or_dac_isr(void);
void WEAK m0_adc1_isr(void);
void WEAK m0_ssp0_or_ssp1_isr(void);
void WEAK m0_eventrouter_isr(void);
void WEAK m0_usart0_isr(void);
void WEAK m0_uart1_isr(void);
void WEAK m0_usart2_or_c_can1_isr(void);
void WEAK m0_usart3_isr(void);
void WEAK m0_i2s0_or_i2s1_isr(void);
void WEAK m0_c_can0_isr(void);
/* Initialization template for the interrupt vector table. This definition is
* used by the startup code generator (vector.c) to set the initial values for
* the interrupt handling routines to the chip family specific _isr weak
* symbols. */
/* See UserManual LPC43xx rev1_4 UM10503 Table 26. Connection of interrupt sources to the Cortex-M0 NVIC */
__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,
0, /* sys_tick_handler not supported on LPC4330 M0 */
/* IrqID 0 , ExcNo 16 */ m0_rtc_isr,
/* IrqID 1 , ExcNo 17 */ m0_m4core_isr,
/* IrqID 2 , ExcNo 18 */ m0_dma_isr,
/* IrqID 3 , ExcNo 19 */ 0,
/* IrqID 4 , ExcNo 20 */ m0_flasheepromat_isr,
/* IrqID 5 , ExcNo 21 */ m0_ethernet_isr,
/* IrqID 6 , ExcNo 22 */ m0_sdio_isr,
/* IrqID 7 , ExcNo 23 */ m0_lcd_isr,
/* IrqID 8 , ExcNo 24 */ m0_usb0_isr,
/* IrqID 9 , ExcNo 25 */ m0_usb1_isr,
/* IrqID 10, ExcNo 26 */ m0_sct_isr,
/* IrqID 11, ExcNo 27 */ m0_ritimer_or_wwdt_isr,
/* IrqID 12, ExcNo 28 */ m0_timer0_isr,
/* IrqID 13, ExcNo 29 */ m0_gint1_isr,
/* IrqID 14, ExcNo 30 */ m0_pin_int4_isr,
/* IrqID 15, ExcNo 31 */ m0_timer3_isr,
/* IrqID 16, ExcNo 32 */ m0_mcpwm_isr,
/* IrqID 17, ExcNo 33 */ m0_adc0_isr,
/* IrqID 18, ExcNo 34 */ m0_i2c0_or_i2c1_isr,
/* IrqID 19, ExcNo 35 */ m0_sgpio_isr,
/* IrqID 20, ExcNo 36 */ m0_spi_or_dac_isr,
/* IrqID 21, ExcNo 37 */ m0_adc1_isr,
/* IrqID 22, ExcNo 38 */ m0_ssp0_or_ssp1_isr,
/* IrqID 23, ExcNo 39 */ m0_eventrouter_isr,
/* IrqID 24, ExcNo 40 */ m0_usart0_isr,
/* IrqID 25, ExcNo 41 */ m0_uart1_isr,
/* IrqID 26, ExcNo 42 */ m0_usart2_or_c_can1_isr,
/* IrqID 27, ExcNo 43 */ m0_usart3_isr,
/* IrqID 28, ExcNo 44 */ m0_i2s0_or_i2s1_isr,
/* IrqID 29, ExcNo 45 */ m0_c_can0_isr,
/* IrqID 30, ExcNo 46 */ 0,
/* IrqID 31, ExcNo 47 */ 0
};
void WEAK reset_handler(void)
{
volatile unsigned long *dest;
__asm__("MSR msp, %0" : : "r"(&_stack));
/* Data does not need to be copied as M4 have already copied the whole bin including code+data */
/* Set BSS */
for (dest = (unsigned long*)(&_bss); dest < (unsigned long*)(&_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
/* M0 */
#pragma weak m0_rtc_isr = blocking_handler
#pragma weak m0_m4core_isr = blocking_handler
#pragma weak m0_dma_isr = blocking_handler
#pragma weak m0_flasheepromat_isr = blocking_handler
#pragma weak m0_ethernet_isr = blocking_handler
#pragma weak m0_sdio_isr = blocking_handler
#pragma weak m0_lcd_isr = blocking_handler
#pragma weak m0_usb0_isr = blocking_handler
#pragma weak m0_usb1_isr = blocking_handler
#pragma weak m0_sct_isr = blocking_handler
#pragma weak m0_ritimer_or_wwdt_isr = blocking_handler
#pragma weak m0_timer0_isr = blocking_handler
#pragma weak m0_gint1_isr = blocking_handler
#pragma weak m0_pin_int4_isr = blocking_handler
#pragma weak m0_timer3_isr = blocking_handler
#pragma weak m0_mcpwm_isr = blocking_handler
#pragma weak m0_adc0_isr = blocking_handler
#pragma weak m0_i2c0_or_i2c1_isr = blocking_handler
#pragma weak m0_sgpio_isr = blocking_handler
#pragma weak m0_spi_or_dac_isr = blocking_handler
#pragma weak m0_adc1_isr = blocking_handler
#pragma weak m0_ssp0_or_ssp1_isr = blocking_handler
#pragma weak m0_eventrouter_isr = blocking_handler
#pragma weak m0_usart0_isr = blocking_handler
#pragma weak m0_uart1_isr = blocking_handler
#pragma weak m0_usart2_or_c_can1_isr = blocking_handler
#pragma weak m0_usart3_isr = blocking_handler
#pragma weak m0_i2s0_or_i2s1_isr = blocking_handler
#pragma weak m0_c_can0_isr = blocking_handler

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_sam3n
PREFIX ?= arm-none-eabi
CC = $(PREFIX)-gcc
AR = $(PREFIX)-ar
CFLAGS = -Os -g -Wall -Wextra -I../../../include -fno-common \
-mcpu=cortex-m3 -mthumb $(FP_FLAGS) -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD -DSAM3N
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS = gpio.o pmc.o usart.o
VPATH += ../../cm3:../common
include ../../Makefile.include

View File

@ -0,0 +1,106 @@
/*
* 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
/* C++ Static constructors/destructors, also used for __attribute__
* ((constructor)) and the likes */
.preinit_array : {
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
} >rom
.init_array : {
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
} >rom
.fini_array : {
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
} >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));

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_sam3x
PREFIX ?= arm-none-eabi
CC = $(PREFIX)-gcc
AR = $(PREFIX)-ar
CFLAGS = -Os -g -Wall -Wextra -I../../../include -fno-common \
-mcpu=cortex-m3 -mthumb $(FP_FLAGS) -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD -DSAM3X
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS = gpio.o pmc.o usart.o
VPATH += ../../usb:../../cm3:../common
include ../../Makefile.include

View File

@ -0,0 +1,106 @@
/*
* 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
/* C++ Static constructors/destructors, also used for __attribute__
* ((constructor)) and the likes */
.preinit_array : {
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
} >rom
.init_array : {
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
} >rom
.fini_array : {
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
} >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));

View File

@ -0,0 +1,64 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 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 <libopencm3/sam/gpio.h>
void gpio_init(uint32_t port, uint32_t pins, enum gpio_flags flags)
{
switch (flags & 3) {
case GPIO_FLAG_GPINPUT:
/* input mode doesn't really exist, so we make a high
* output in open-drain mode
*/
PIO_SODR(port) = pins;
flags |= GPIO_FLAG_OPEN_DRAIN;
/* fall through */
case GPIO_FLAG_GPOUTPUT:
PIO_OER(port) = pins;
PIO_PER(port) = pins;
break;
case GPIO_FLAG_PERIPHA:
PIO_ABSR(port) &= ~pins;
PIO_PDR(port) = pins;
break;
case GPIO_FLAG_PERIPHB:
PIO_ABSR(port) |= pins;
PIO_PDR(port) = pins;
}
if (flags & GPIO_FLAG_OPEN_DRAIN) {
PIO_MDER(port) = pins;
} else {
PIO_MDDR(port) = pins;
}
if (flags & GPIO_FLAG_PULL_UP) {
PIO_PUER(port) = pins;
} else {
PIO_PUDR(port) = pins;
}
}
void gpio_toggle(uint32_t gpioport, uint32_t gpios)
{
uint32_t odsr = PIO_ODSR(gpioport);
PIO_CODR(gpioport) = odsr & gpios;
PIO_SODR(gpioport) = ~odsr & gpios;
}

View File

@ -0,0 +1,97 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2013 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 <libopencm3/sam/pmc.h>
#include <libopencm3/sam/eefc.h>
/** Default peripheral clock frequency after reset. */
uint32_t pmc_mck_frequency = 4000000;
void pmc_xtal_enable(bool en, uint8_t startup_time)
{
if (en) {
CKGR_MOR = (CKGR_MOR & ~CKGR_MOR_MOSCXTST_MASK) |
CKGR_MOR_KEY | CKGR_MOR_MOSCXTEN |
(startup_time << 8);
while (!(PMC_SR & PMC_SR_MOSCXTS));
} else {
CKGR_MOR = CKGR_MOR_KEY | (CKGR_MOR & ~CKGR_MOR_MOSCXTEN);
}
}
void pmc_plla_config(uint8_t mul, uint8_t div)
{
CKGR_PLLAR = CKGR_PLLAR_ONE | ((mul - 1) << 16) |
CKGR_PLLAR_PLLACOUNT_MASK | div;
while (!(PMC_SR & PMC_SR_LOCKA));
}
void pmc_peripheral_clock_enable(uint8_t pid)
{
if (pid < 32) {
PMC_PCER0 = 1 << pid;
} else {
PMC_PCER1 = 1 << (pid & 31);
}
}
void pmc_peripheral_clock_disable(uint8_t pid)
{
if (pid < 32) {
PMC_PCDR0 = 1 << pid;
} else {
PMC_PCDR1 = 1 << (pid & 31);
}
}
void pmc_mck_set_source(enum mck_src src)
{
PMC_MCKR = (PMC_MCKR & ~PMC_MCKR_CSS_MASK) | src;
while (!(PMC_SR & PMC_SR_MCKRDY));
}
void pmc_clock_setup_in_xtal_12mhz_out_84mhz(void)
{
eefc_set_latency(4);
/* 12MHz external xtal, maximum possible startup time */
pmc_xtal_enable(true, 0xff);
/* Select as main oscillator */
CKGR_MOR |= CKGR_MOR_KEY | CKGR_MOR_MOSCSEL;
/* Multiply by 7 for 84MHz */
pmc_plla_config(7, 1);
pmc_mck_set_source(MCK_SRC_PLLA);
pmc_mck_frequency = 84000000;
}
void pmc_clock_setup_in_rc_4mhz_out_84mhz(void)
{
eefc_set_latency(4);
/* Select as main oscillator */
CKGR_MOR = CKGR_MOR_KEY |
(CKGR_MOR & ~(CKGR_MOR_MOSCSEL | CKGR_MOR_MOSCRCF_MASK));
/* Multiply by 21 for 84MHz */
pmc_plla_config(21, 1);
pmc_mck_set_source(MCK_SRC_PLLA);
pmc_mck_frequency = 84000000;
}

View File

@ -0,0 +1,108 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2013 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 <libopencm3/sam/usart.h>
#include <libopencm3/sam/pmc.h>
void usart_set_baudrate(uint32_t usart, uint32_t baud)
{
USART_BRGR(usart) = pmc_mck_frequency / (16 * baud);
}
void usart_set_databits(uint32_t usart, int bits)
{
USART_MR(usart) = (USART_MR(usart) & ~USART_MR_CHRL_MASK) |
((bits - 5) << 6);
}
void usart_set_stopbits(uint32_t usart, enum usart_stopbits sb)
{
USART_MR(usart) = (USART_MR(usart) & ~USART_MR_NBSTOP_MASK) |
(sb << 12);
}
void usart_set_parity(uint32_t usart, enum usart_parity par)
{
USART_MR(usart) = (USART_MR(usart) & ~USART_MR_PAR_MASK) | (par << 9);
}
void usart_set_mode(uint32_t usart, enum usart_mode mode)
{
USART_CR(usart) =
(mode & USART_MODE_RX) ? USART_CR_RXEN : USART_CR_RXDIS;
USART_CR(usart) = (mode & USART_MODE_TX) ? USART_CR_TXEN
: USART_CR_TXDIS;
}
void usart_set_flow_control(uint32_t usart, enum usart_flowcontrol fc)
{
USART_MR(usart) = (USART_MR(usart) & ~USART_MR_MODE_MASK) |
(fc ? USART_MR_MODE_HW_HANDSHAKING : 0);
}
void usart_enable(uint32_t usart)
{
}
void usart_disable(uint32_t usart)
{
}
void usart_send(uint32_t usart, uint16_t data)
{
USART_THR(usart) = data;
}
uint16_t usart_recv(uint32_t usart)
{
return USART_RHR(usart) & 0x1f;
}
void usart_wait_send_ready(uint32_t usart)
{
while ((USART_CSR(usart) & USART_CSR_TXRDY) == 0);
}
void usart_wait_recv_ready(uint32_t usart)
{
while ((USART_CSR(usart) & USART_CSR_RXRDY) == 0);
}
void usart_send_blocking(uint32_t usart, uint16_t data)
{
usart_wait_send_ready(usart);
usart_send(usart, data);
}
uint16_t usart_recv_blocking(uint32_t usart)
{
usart_wait_recv_ready(usart);
return usart_recv(usart);
}
void usart_enable_rx_interrupt(uint32_t usart)
{
USART_IER(usart) = USART_CSR_RXRDY;
}
void usart_disable_rx_interrupt(uint32_t usart)
{
USART_IDR(usart) = USART_CSR_RXRDY;
}

View File

@ -0,0 +1,557 @@
/** @defgroup can_file CAN
@ingroup STM32F_files
@brief <b>libopencm3 STM32Fxxx CAN</b>
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2010 Piotr Esden-Tempski <piotr@esden.net>
@date 12 November 2012
Devices can have up to two CAN peripherals. The peripherals support up to 1MBit
transmission rate. The peripheral has several filters for incoming messages that
can be distributed between two FIFOs and three transmit mailboxes.
LGPL License Terms @ref lgpl_license
*/
/*
* 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/>.
*/
#include <libopencm3/stm32/can.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
/* Timeout for CAN INIT acknowledge
* this value is difficult to define.
* INIT is set latest after finishing the current transfer.
* Assuming the lowest CAN speed of 100kbps one CAN frame may take about 1.6ms
* WAIT loop timeout varies on compiler switches, optimization, CPU architecture
* and CPU speed
*
* The same timeout value is used for leaving INIT where the longest time is
* 11 bits(110 us on 100 kbps).
*/
#define CAN_MSR_INAK_TIMEOUT 0x0000FFFF
/*---------------------------------------------------------------------------*/
/** @brief CAN Reset
The CAN peripheral and all its associated configuration registers are placed in
the reset condition. The reset is effective via the RCC peripheral reset
system.
@param[in] canport Unsigned int32. CAN block register address base @ref
can_reg_base.
*/
void can_reset(uint32_t canport)
{
if (canport == CAN1) {
rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_CAN1RST);
rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_CAN1RST);
} else {
rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_CAN2RST);
rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_CAN2RST);
}
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Init
Initialize the selected CAN peripheral block.
@param[in] canport Unsigend int32. CAN register base address @ref can_reg_base.
@param[in] ttcm bool. Time triggered communication mode.
@param[in] abom bool. Automatic bus-off management.
@param[in] awum bool. Automatic wakeup mode.
@param[in] nart bool. No automatic retransmission.
@param[in] rflm bool. Receive FIFO locked mode.
@param[in] txfp bool. Transmit FIFO priority.
@param[in] sjw Unsigned int32. Resynchronization time quanta jump width.
@param[in] ts1 Unsigned int32. Time segment 1 time quanta width.
@param[in] ts2 Unsigned int32. Time segment 2 time quanta width.
@param[in] brp Unsigned int32. Baud rate prescaler.
@returns int 0 on success, 1 on initialization failure.
*/
int can_init(uint32_t canport, bool ttcm, bool abom, bool awum, bool nart,
bool rflm, bool txfp, uint32_t sjw, uint32_t ts1, uint32_t ts2,
uint32_t brp, bool loopback, bool silent)
{
volatile uint32_t wait_ack;
int ret = 0;
/* Exit from sleep mode. */
CAN_MCR(canport) &= ~CAN_MCR_SLEEP;
/* Request initialization "enter". */
CAN_MCR(canport) |= CAN_MCR_INRQ;
/* Wait for acknowledge. */
wait_ack = CAN_MSR_INAK_TIMEOUT;
while ((--wait_ack) &&
((CAN_MSR(canport) & CAN_MSR_INAK) != CAN_MSR_INAK));
/* Check the acknowledge. */
if ((CAN_MSR(canport) & CAN_MSR_INAK) != CAN_MSR_INAK) {
return 1;
}
/* clear can timing bits */
CAN_BTR(canport) = 0;
/* Set the automatic bus-off management. */
if (ttcm) {
CAN_MCR(canport) |= CAN_MCR_TTCM;
} else {
CAN_MCR(canport) &= ~CAN_MCR_TTCM;
}
if (abom) {
CAN_MCR(canport) |= CAN_MCR_ABOM;
} else {
CAN_MCR(canport) &= ~CAN_MCR_ABOM;
}
if (awum) {
CAN_MCR(canport) |= CAN_MCR_AWUM;
} else {
CAN_MCR(canport) &= ~CAN_MCR_AWUM;
}
if (nart) {
CAN_MCR(canport) |= CAN_MCR_NART;
} else {
CAN_MCR(canport) &= ~CAN_MCR_NART;
}
if (rflm) {
CAN_MCR(canport) |= CAN_MCR_RFLM;
} else {
CAN_MCR(canport) &= ~CAN_MCR_RFLM;
}
if (txfp) {
CAN_MCR(canport) |= CAN_MCR_TXFP;
} else {
CAN_MCR(canport) &= ~CAN_MCR_TXFP;
}
if (silent) {
CAN_BTR(canport) |= CAN_BTR_SILM;
} else {
CAN_BTR(canport) &= ~CAN_BTR_SILM;
}
if (loopback) {
CAN_BTR(canport) |= CAN_BTR_LBKM;
} else {
CAN_BTR(canport) &= ~CAN_BTR_LBKM;
}
/* Set bit timings. */
CAN_BTR(canport) |= sjw | ts2 | ts1 |
((brp - 1ul) & CAN_BTR_BRP_MASK);
/* Request initialization "leave". */
CAN_MCR(canport) &= ~CAN_MCR_INRQ;
/* Wait for acknowledge. */
wait_ack = CAN_MSR_INAK_TIMEOUT;
while ((--wait_ack) &&
((CAN_MSR(canport) & CAN_MSR_INAK) == CAN_MSR_INAK));
if ((CAN_MSR(canport) & CAN_MSR_INAK) == CAN_MSR_INAK) {
ret = 1;
}
return ret;
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Filter Init
Initialize incoming message filter and assign to FIFO.
@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base.
@param[in] nr Unsigned int32. ID number of the filter.
@param[in] scale_32bit bool. 32-bit scale for the filter?
@param[in] id_list_mode bool. ID list filter mode?
@param[in] fr1 Unsigned int32. First filter register content.
@param[in] fr2 Unsigned int32. Second filter register content.
@param[in] fifo Unsigned int32. FIFO id.
@param[in] enable bool. Enable filter?
*/
void can_filter_init(uint32_t canport, uint32_t nr, bool scale_32bit,
bool id_list_mode, uint32_t fr1, uint32_t fr2,
uint32_t fifo, bool enable)
{
uint32_t filter_select_bit = 0x00000001 << nr;
/* Request initialization "enter". */
CAN_FMR(canport) |= CAN_FMR_FINIT;
/* Deactivate the filter. */
CAN_FA1R(canport) &= ~filter_select_bit;
if (scale_32bit) {
/* Set 32-bit scale for the filter. */
CAN_FS1R(canport) |= filter_select_bit;
} else {
/* Set 16-bit scale for the filter. */
CAN_FS1R(canport) &= ~filter_select_bit;
}
if (id_list_mode) {
/* Set filter mode to ID list mode. */
CAN_FM1R(canport) |= filter_select_bit;
} else {
/* Set filter mode to id/mask mode. */
CAN_FM1R(canport) &= ~filter_select_bit;
}
/* Set the first filter register. */
CAN_FiR1(canport, nr) = fr1;
/* Set the second filter register. */
CAN_FiR2(canport, nr) = fr2;
/* Select FIFO0 or FIFO1 as filter assignement. */
if (fifo) {
CAN_FFA1R(canport) |= filter_select_bit; /* FIFO1 */
} else {
CAN_FFA1R(canport) &= ~filter_select_bit; /* FIFO0 */
}
if (enable) {
CAN_FA1R(canport) |= filter_select_bit; /* Activate filter. */
}
/* Request initialization "leave". */
CAN_FMR(canport) &= ~CAN_FMR_FINIT;
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Initialize a 16bit Message ID Mask Filter
@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base.
@param[in] nr Unsigned int32. ID number of the filter.
@param[in] id1 Unsigned int16. First message ID to filter.
@param[in] mask1 Unsigned int16. First message ID bit mask.
@param[in] id2 Unsigned int16. Second message ID to filter.
@param[in] mask2 Unsigned int16. Second message ID bit mask.
@param[in] fifo Unsigned int32. FIFO id.
@param[in] enable bool. Enable filter?
*/
void can_filter_id_mask_16bit_init(uint32_t canport, uint32_t nr, uint16_t id1,
uint16_t mask1, uint16_t id2,
uint16_t mask2, uint32_t fifo, bool enable)
{
can_filter_init(canport, nr, false, false,
((uint32_t)id1 << 16) | (uint32_t)mask1,
((uint32_t)id2 << 16) | (uint32_t)mask2, fifo, enable);
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Initialize a 32bit Message ID Mask Filter
@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base.
@param[in] nr Unsigned int32. ID number of the filter.
@param[in] id Unsigned int32. Message ID to filter.
@param[in] mask Unsigned int32. Message ID bit mask.
@param[in] fifo Unsigned int32. FIFO id.
@param[in] enable bool. Enable filter?
*/
void can_filter_id_mask_32bit_init(uint32_t canport, uint32_t nr, uint32_t id,
uint32_t mask, uint32_t fifo, bool enable)
{
can_filter_init(canport, nr, true, false, id, mask, fifo, enable);
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Initialize a 16bit Message ID List Filter
@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base.
@param[in] nr Unsigned int32. ID number of the filter.
@param[in] id1 Unsigned int16. First message ID to match.
@param[in] id2 Unsigned int16. Second message ID to match.
@param[in] id3 Unsigned int16. Third message ID to match.
@param[in] id4 Unsigned int16. Fourth message ID to match.
@param[in] fifo Unsigned int32. FIFO id.
@param[in] enable bool. Enable filter?
*/
void can_filter_id_list_16bit_init(uint32_t canport, uint32_t nr,
uint16_t id1, uint16_t id2,
uint16_t id3, uint16_t id4,
uint32_t fifo, bool enable)
{
can_filter_init(canport, nr, false, true,
((uint32_t)id1 << 16) | (uint32_t)id2,
((uint32_t)id3 << 16) | (uint32_t)id4, fifo, enable);
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Initialize a 32bit Message ID List Filter
@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base.
@param[in] nr Unsigned int32. ID number of the filter.
@param[in] id1 Unsigned int32. First message ID to match.
@param[in] id2 Unsigned int32. Second message ID to match.
@param[in] fifo Unsigned int32. FIFO id.
@param[in] enable bool. Enable filter?
*/
void can_filter_id_list_32bit_init(uint32_t canport, uint32_t nr,
uint32_t id1, uint32_t id2,
uint32_t fifo, bool enable)
{
can_filter_init(canport, nr, true, true, id1, id2, fifo, enable);
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Enable IRQ
@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base.
@param[in] irq Unsigned int32. IRQ bit(s).
*/
void can_enable_irq(uint32_t canport, uint32_t irq)
{
CAN_IER(canport) |= irq;
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Disable IRQ
@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base.
@param[in] irq Unsigned int32. IRQ bit(s).
*/
void can_disable_irq(uint32_t canport, uint32_t irq)
{
CAN_IER(canport) &= ~irq;
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Transmit Message
@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base.
@param[in] id Unsigned int32. Message ID.
@param[in] ext bool. Extended message ID?
@param[in] rtr bool. Request transmit?
@param[in] length Unsigned int8. Message payload length.
@param[in] data Unsigned int8[]. Message payload data.
@returns int 0, 1 or 2 on success and depending on which outgoing mailbox got
selected. -1 if no mailbox was available and no transmission got queued.
*/
int can_transmit(uint32_t canport, uint32_t id, bool ext, bool rtr,
uint8_t length, uint8_t *data)
{
int ret = 0;
uint32_t mailbox = 0;
union {
uint8_t data8[4];
uint32_t data32;
} tdlxr, tdhxr;
/* Check which transmit mailbox is empty if any. */
if ((CAN_TSR(canport) & CAN_TSR_TME0) == CAN_TSR_TME0) {
ret = 0;
mailbox = CAN_MBOX0;
} else if ((CAN_TSR(canport) & CAN_TSR_TME1) == CAN_TSR_TME1) {
ret = 1;
mailbox = CAN_MBOX1;
} else if ((CAN_TSR(canport) & CAN_TSR_TME2) == CAN_TSR_TME2) {
ret = 2;
mailbox = CAN_MBOX2;
} else {
ret = -1;
}
/* If we have no empty mailbox return with an error. */
if (ret == -1) {
return ret;
}
if (ext) {
/* Set extended ID. */
CAN_TIxR(canport, mailbox) = (id << CAN_TIxR_EXID_SHIFT) |
CAN_TIxR_IDE;
} else {
/* Set standard ID. */
CAN_TIxR(canport, mailbox) = id << CAN_TIxR_STID_SHIFT;
}
/* Set/clear remote transmission request bit. */
if (rtr) {
CAN_TIxR(canport, mailbox) |= CAN_TIxR_RTR; /* Set */
}
/* Set the DLC. */
CAN_TDTxR(canport, mailbox) &= ~CAN_TDTxR_DLC_MASK;
CAN_TDTxR(canport, mailbox) |= (length & CAN_TDTxR_DLC_MASK);
switch (length) {
case 8:
tdhxr.data8[3] = data[7];
/* no break */
case 7:
tdhxr.data8[2] = data[6];
/* no break */
case 6:
tdhxr.data8[1] = data[5];
/* no break */
case 5:
tdhxr.data8[0] = data[4];
/* no break */
case 4:
tdlxr.data8[3] = data[3];
/* no break */
case 3:
tdlxr.data8[2] = data[2];
/* no break */
case 2:
tdlxr.data8[1] = data[1];
/* no break */
case 1:
tdlxr.data8[0] = data[0];
/* no break */
default:
break;
}
/* Set the data. */
CAN_TDLxR(canport, mailbox) = tdlxr.data32;
CAN_TDHxR(canport, mailbox) = tdhxr.data32;
/* Request transmission. */
CAN_TIxR(canport, mailbox) |= CAN_TIxR_TXRQ;
return ret;
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Release FIFO
@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base.
@param[in] fifo Unsigned int8. FIFO id.
*/
void can_fifo_release(uint32_t canport, uint8_t fifo)
{
if (fifo == 0) {
CAN_RF0R(canport) |= CAN_RF1R_RFOM1;
} else {
CAN_RF1R(canport) |= CAN_RF1R_RFOM1;
}
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Receive Message
@param[in] canport Unsigned int32. CAN block register base @ref can_reg_base.
@param[in] fifo Unsigned int8. FIFO id.
@param[in] release bool. Release the FIFO automatically after coping data out.
@param[out] id Unsigned int32 pointer. Message ID.
@param[out] ext bool pointer. The message ID is extended?
@param[out] rtr bool pointer. Request of transmission?
@param[out] fmi Unsigned int32 pointer. ID of the matched filter.
@param[out] length Unsigned int8 pointer. Length of message payload.
@param[out] data Unsigned int8[]. Message payload data.
*/
void can_receive(uint32_t canport, uint8_t fifo, bool release, uint32_t *id,
bool *ext, bool *rtr, uint32_t *fmi, uint8_t *length,
uint8_t *data)
{
uint32_t fifo_id = 0;
union {
uint8_t data8[4];
uint32_t data32;
} rdlxr, rdhxr;
const uint32_t fifoid_array[2] = {CAN_FIFO0, CAN_FIFO1};
fifo_id = fifoid_array[fifo];
/* Get type of CAN ID and CAN ID. */
if (CAN_RIxR(canport, fifo_id) & CAN_RIxR_IDE) {
*ext = true;
/* Get extended CAN ID. */
*id = (CAN_RIxR(canport, fifo_id) >> CAN_RIxR_EXID_SHIFT) &
CAN_RIxR_EXID_MASK;
} else {
*ext = false;
/* Get standard CAN ID. */
*id = (CAN_RIxR(canport, fifo_id) >> CAN_RIxR_STID_SHIFT) &
CAN_RIxR_STID_MASK;
}
/* Get remote transmit flag. */
if (CAN_RIxR(canport, fifo_id) & CAN_RIxR_RTR) {
*rtr = true;
} else {
*rtr = false;
}
/* Get filter match ID. */
*fmi = ((CAN_RDTxR(canport, fifo_id) & CAN_RDTxR_FMI_MASK) >>
CAN_RDTxR_FMI_SHIFT);
/* Get data length. */
*length = CAN_RDTxR(canport, fifo_id) & CAN_RDTxR_DLC_MASK;
/* accelerate reception by copying the CAN data from the controller
* memory to the fast internal RAM
*/
rdlxr.data32 = CAN_RDLxR(canport, fifo_id);
rdhxr.data32 = CAN_RDHxR(canport, fifo_id);
/* */
/* Get data.
* Byte wise copy is needed because we do not know the alignment
* of the input buffer.
* Here copying 8 bytes unconditionally is faster than using loop
*
* It is OK to copy all 8 bytes because the upper layer must be
* prepared for data length bigger expected.
* In contrary the driver has no information about the intended size.
* This could be different if the max length would be handed over
* to the function, but it is not the case
*/
data[0] = rdlxr.data8[0];
data[1] = rdlxr.data8[1];
data[2] = rdlxr.data8[2];
data[3] = rdlxr.data8[3];
data[4] = rdhxr.data8[0];
data[5] = rdhxr.data8[1];
data[6] = rdhxr.data8[2];
data[7] = rdhxr.data8[3];
/* Release the FIFO. */
if (release) {
can_fifo_release(canport, fifo);
}
}
bool can_available_mailbox(uint32_t canport)
{
return CAN_TSR(canport) & (CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2);
}

View File

@ -0,0 +1,81 @@
/** @addtogroup crc_file
@author @htmlonly &copy; @endhtmlonly 2012 Karl Palsson <karlp@remake.is>
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Karl Palsson <karlp@remake.is>
*
* 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/crc.h>
/**@{*/
/*---------------------------------------------------------------------------*/
/** @brief CRC Reset.
Reset the CRC unit and forces the data register to all 1s.
*/
void crc_reset(void)
{
CRC_CR |= CRC_CR_RESET;
}
/*---------------------------------------------------------------------------*/
/** @brief CRC Calculate.
Writes a data word to the register, the write operation stalling until the
computation is complete.
@param[in] data Unsigned int32.
@returns int32 Computed CRC result
*/
uint32_t crc_calculate(uint32_t data)
{
CRC_DR = data;
/* Data sheet says this blocks until it's ready.... */
return CRC_DR;
}
/*---------------------------------------------------------------------------*/
/** @brief CRC Calculate of a Block of Data.
Writes data words consecutively to the register, the write operation stalling
until the computation of each word is complete.
@param[in] datap Unsigned int32. pointer to an array of 32 bit data words.
@param[in] size int. Size of the array.
@returns int32 Final computed CRC result
*/
uint32_t crc_calculate_block(uint32_t *datap, int size)
{
int i;
for (i = 0; i < size; i++) {
CRC_DR = datap[i];
}
return CRC_DR;
}
/**@}*/

View File

@ -0,0 +1,175 @@
/** @addtogroup crypto_file
*
* @brief <b>libopencm3 STM32 Cryptographic controller</b>
*
* @version 1.0.0
*
* @date 17 Jun 2013
*
* This library supports the cryptographic coprocessor system for the
* STM32 series of ARM Cortex Microcontrollers
*
* LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* 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/>.
*/
/**@{*/
#include <libopencm3/stm32/crypto.h>
#define CRYP_CR_ALGOMODE_MASK ((1 << 19) | CRYP_CR_ALGOMODE)
/**
* @brief Wait, if the Controller is busy
*/
void crypto_wait_busy(void)
{
while (CRYP_SR & CRYP_SR_BUSY);
}
/**
* @brief Set key value to the controller
* @param[in] keysize enum crypto_keysize Specified size of the key.
* @param[in] key uint64_t[] Key value (array of 4 items)
*/
void crypto_set_key(enum crypto_keysize keysize, uint64_t key[])
{
int i;
crypto_wait_busy();
CRYP_CR = (CRYP_CR & ~CRYP_CR_KEYSIZE) |
(keysize << CRYP_CR_KEYSIZE_SHIFT);
for (i = 0; i < 4; i++) {
CRYP_KR(i) = key[i];
}
}
/**
* @brief Set Initialization Vector
*
* @param[in] iv uint64_t[] Initialization vector (array of 4 items)
* @note Cryptographic controller must be in disabled state
*/
void crypto_set_iv(uint64_t iv[])
{
int i;
crypto_wait_busy();
for (i = 0; i < 4; i++) {
CRYP_IVR(i) = iv[i];
}
}
/**
* @brief Set the order of the data to be crypted
*
* @param[in] datatype enum crypto_datatype Specified datatype of the key.
*/
void crypto_set_datatype(enum crypto_datatype datatype)
{
CRYP_CR = (CRYP_CR & ~CRYP_CR_DATATYPE) |
(datatype << CRYP_CR_DATATYPE_SHIFT);
}
/**
* @brief Set the algoritm for Encryption/decryption
*
*@param[in] mode enum crypto_mode Mode of execution
*/
void crypto_set_algorithm(enum crypto_mode mode)
{
mode &= ~CRYP_CR_ALGOMODE_MASK;
if ((mode == DECRYPT_AES_ECB) || (mode == DECRYPT_AES_CBC)) {
/* Unroll keys for the AES encoder for the user automatically */
CRYP_CR = (CRYP_CR & ~CRYP_CR_ALGOMODE_MASK) |
CRYP_CR_ALGOMODE_AES_PREP;
crypto_start();
crypto_wait_busy();
/* module switches to DISABLE automatically */
}
/* set algo mode */
CRYP_CR = (CRYP_CR & ~CRYP_CR_ALGOMODE_MASK) | mode;
/* flush buffers */
CRYP_CR |= CRYP_CR_FFLUSH;
}
/**
* @brief Enable the cryptographic controller and start processing
*/
void crypto_start(void)
{
CRYP_CR |= CRYP_CR_CRYPEN;
}
/**
* @brief Disable the cryptographic controller and stop processing
*/
void crypto_stop(void)
{
CRYP_CR &= ~CRYP_CR_CRYPEN;
}
/**
* @brief Start of encryption or decryption on data buffers
*
* This blocking method transfers input buffer of specified length to the
* cryptographic coprocessor, and instructs him to begin of ciphering or
* deciphering. It waits for data to be ready, and then fills the processed
* data to output buffer.
*
* @param[in] inp uint32_t* Input array to crypt/decrypt.
* @param[in] outp uint32_t* Output array with crypted/encrypted data.
* @param[in] length uint32_t Length of the arrays
*
* @returns uint32_t Number of written words
*/
uint32_t crypto_process_block(uint32_t *inp, uint32_t *outp, uint32_t length)
{
uint32_t rd = 0, wr = 0;
/* Transfer the data */
while (rd != length) {
if ((wr < length) && (CRYP_SR & CRYP_SR_IFNF)) {
CRYP_DIN = *inp++;
wr++;
}
if (CRYP_SR & CRYP_SR_OFNE) {
*outp++ = CRYP_DOUT;
rd++;
}
}
/* Wait to finish - Not needed ? */
crypto_wait_busy();
return wr;
}
/**@}*/

View File

@ -0,0 +1,500 @@
/** @addtogroup dac_file
@author @htmlonly &copy; @endhtmlonly 2012 Ken Sarkies ksarkies@internode.on.net
This library supports the Digital to Analog Conversion System in the
STM32F series of ARM Cortex Microcontrollers by ST Microelectronics.
The DAC is present only in a limited set of devices, notably some
of the connection line, high density and XL devices.
Two DAC channels are available, however unlike the ADC channels these
are separate DAC devices controlled by the same register block.
The DAC is on APB1. Its clock must be enabled in RCC and the GPIO
ports set to alternate function output before it can be used.
The digital output driver is disabled so the output driver mode
(push-pull/open drain) is arbitrary.
The DAC has a holding (buffer) register and an output register from
which the analog output is derived. The holding register must be
loaded first. If triggering is enabled the output register is loaded
from the holding register after a trigger occurs. If triggering is
not enabled the holding register contents are transferred directly
to the output register.
@note To avoid nonlinearities, do not allow outputs to range close
to zero or V_analog.
@section dac_api_dual Dual Channel Conversion
There are dual modes in which both DACs are used to output data
simultaneously or independently on both channels. The data must be
presented according to the formats described in the datasheets. A
convenience function @ref dac_load_data_buffer_dual is provided
for software controlled use.
A variety of modes are available depending on whether independent
or simultaneous output is desired, and whether waveforms are to be
superimposed. Refer to the datasheets.
If DMA is used, only enable it for one of the channels. The DMA
requests will then serve data in dual format to the data register
dedicated to dual mode. The data will then be split and loaded to the
appropriate DAC following the next trigger. There are three registers
available, one for each of the formats: 12 bit right-aligned, 12 bit
left-aligned and 8 bit right-aligned. The desired format is determined
by specifying the appropriate register to the DMA controller.
@section dac_api_basic_ex Basic DAC handling API.
Set the DAC's GPIO port to any alternate function output mode. Enable the
DAC clock. Enable the DAC, set a trigger source and load the buffer
with the first value. After the DAC is triggered, load the buffer with
the next value. This example uses software triggering and added noise.
The trigger and further buffer load calls are made when data is to be
sent out.
@code
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO4);
rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_DACEN);
dac_disable(CHANNEL_1);
dac_set_waveform_characteristics(DAC_CR_MAMP1_8);
dac_set_waveform_generation(DAC_CR_WAVE1_NOISE);
dac_enable(CHANNEL_1);
dac_set_trigger_source(DAC_CR_TSEL1_SW);
dac_load_data_buffer_single(0, RIGHT12, CHANNEL_1);
....
dac_software_trigger(CHANNEL_1);
dac_load_data_buffer_single(value, RIGHT12, CHANNEL_1);
@endcode
@section dac_api_dma_ex Simultaneous Dual DAC with DMA.
This example in part sets up the DAC channel 1 DMA (DMA2 channel 3) to read
16 bit data from memory into the right-aligned 8 bit dual register DAC_DHR8RD.
Both DAC channels are enabled, and both triggers are set to the same timer
2 input as required for simultaneous operation. DMA is enabled for DAC channel
1 only to ensure that only one DMA request is generated.
@code
dma_set_memory_size(DMA2,DMA_CHANNEL3,DMA_CCR_MSIZE_16BIT);
dma_set_peripheral_size(DMA2,DMA_CHANNEL3,DMA_CCR_PSIZE_16BIT);
dma_set_read_from_memory(DMA2,DMA_CHANNEL3);
dma_set_peripheral_address(DMA2,DMA_CHANNEL3,(uint32_t) &DAC_DHR8RD);
dma_enable_channel(DMA2,DMA_CHANNEL3);
...
dac_trigger_enable(CHANNEL_D);
dac_set_trigger_source(DAC_CR_TSEL1_T2 | DAC_CR_TSEL2_T2);
dac_dma_enable(CHANNEL_1);
dac_enable(CHANNEL_D);
@endcode
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Ken Sarkies
*
* 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/dac.h>
#define MASK8 0xFF
#define MASK12 0xFFF
/*---------------------------------------------------------------------------*/
/** @brief DAC Channel Enable.
Enable a digital to analog converter channel. After setting this enable, the
DAC requires a t<sub>wakeup</sub> time typically around 10 microseconds before
it actually wakes up.
@param[in] dac_channel enum ::data_channel.
*/
void dac_enable(data_channel dac_channel)
{
switch (dac_channel) {
case CHANNEL_1:
DAC_CR |= DAC_CR_EN1;
break;
case CHANNEL_2:
DAC_CR |= DAC_CR_EN2;
break;
case CHANNEL_D:
DAC_CR |= (DAC_CR_EN1 | DAC_CR_EN2);
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief DAC Channel Disable.
Disable a digital to analog converter channel.
@param[in] dac_channel enum ::data_channel.
*/
void dac_disable(data_channel dac_channel)
{
switch (dac_channel) {
case CHANNEL_1:
DAC_CR &= ~DAC_CR_EN1;
break;
case CHANNEL_2:
DAC_CR &= ~DAC_CR_EN2;
break;
case CHANNEL_D:
DAC_CR &= ~(DAC_CR_EN1 | DAC_CR_EN2);
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief DAC Channel Output Buffer Enable.
Enable a digital to analog converter channel output drive buffer. This is an
optional amplifying buffer that provides additional drive for the output
signal. The buffer is enabled by default after a reset and needs to be
explicitly disabled if required.
@param[in] dac_channel enum ::data_channel.
*/
void dac_buffer_enable(data_channel dac_channel)
{
switch (dac_channel) {
case CHANNEL_1:
DAC_CR |= DAC_CR_BOFF1;
break;
case CHANNEL_2:
DAC_CR |= DAC_CR_BOFF2;
break;
case CHANNEL_D:
DAC_CR |= (DAC_CR_BOFF1 | DAC_CR_BOFF2);
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief DAC Channel Output Buffer Disable.
Disable a digital to analog converter channel output drive buffer. Disabling
this will reduce power consumption slightly and will increase the output
impedance of the DAC. The buffers are enabled by default after a reset.
@param[in] dac_channel enum ::data_channel.
*/
void dac_buffer_disable(data_channel dac_channel)
{
switch (dac_channel) {
case CHANNEL_1:
DAC_CR &= ~DAC_CR_BOFF1;
break;
case CHANNEL_2:
DAC_CR &= ~DAC_CR_BOFF2;
break;
case CHANNEL_D:
DAC_CR &= ~(DAC_CR_BOFF1 | DAC_CR_BOFF2);
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief DAC Channel DMA Enable.
Enable a digital to analog converter channel DMA mode (connected to DMA2 channel
3 for DAC channel 1 and DMA2 channel 4 for DAC channel 2). A DMA request is
generated following an external trigger.
@param[in] dac_channel enum ::data_channel.
*/
void dac_dma_enable(data_channel dac_channel)
{
switch (dac_channel) {
case CHANNEL_1:
DAC_CR |= DAC_CR_DMAEN1;
break;
case CHANNEL_2:
DAC_CR |= DAC_CR_DMAEN2;
break;
case CHANNEL_D:
DAC_CR |= (DAC_CR_DMAEN1 | DAC_CR_DMAEN2);
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief DAC Channel DMA Disable.
Disable a digital to analog converter channel DMA mode.
@param[in] dac_channel enum ::data_channel.
*/
void dac_dma_disable(data_channel dac_channel)
{
switch (dac_channel) {
case CHANNEL_1:
DAC_CR &= ~DAC_CR_DMAEN1;
break;
case CHANNEL_2:
DAC_CR &= ~DAC_CR_DMAEN2;
break;
case CHANNEL_D:
DAC_CR &= ~(DAC_CR_DMAEN1 | DAC_CR_DMAEN2);
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief DAC Channel Trigger Enable.
Enable a digital to analog converter channel external trigger mode. This allows
an external trigger to initiate register transfers from the buffer register to
the DAC output register, followed by a DMA transfer to the buffer register if
DMA is enabled. The trigger source must also be selected.
@param[in] dac_channel enum ::data_channel.
*/
void dac_trigger_enable(data_channel dac_channel)
{
switch (dac_channel) {
case CHANNEL_1:
DAC_CR |= DAC_CR_TEN1;
break;
case CHANNEL_2:
DAC_CR |= DAC_CR_TEN2;
break;
case CHANNEL_D:
DAC_CR |= (DAC_CR_TEN1 | DAC_CR_TEN2);
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief DAC Channel Trigger Disable.
Disable a digital to analog converter channel external trigger.
@param[in] dac_channel enum ::data_channel.
*/
void dac_trigger_disable(data_channel dac_channel)
{
switch (dac_channel) {
case CHANNEL_1:
DAC_CR &= ~DAC_CR_TEN1;
break;
case CHANNEL_2:
DAC_CR &= ~DAC_CR_TEN2;
break;
case CHANNEL_D:
DAC_CR &= ~(DAC_CR_TEN1 | DAC_CR_TEN2);
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief Set DAC Channel Trigger Source.
Sets the digital to analog converter trigger source, which can be taken from
various timers, an external trigger or a software trigger.
@param[in] dac_trig_src uint32_t. Taken from @ref dac_trig2_sel or @ref
dac_trig1_sel or a logical OR of one of each of these to set both channels
simultaneously.
*/
void dac_set_trigger_source(uint32_t dac_trig_src)
{
DAC_CR |= dac_trig_src;
}
/*---------------------------------------------------------------------------*/
/** @brief Enable and Set DAC Channel Waveform Generation.
Enable the digital to analog converter waveform generation as either
pseudo-random noise or triangular wave. These signals are superimposed on
existing output values in the DAC output registers.
@note The DAC trigger must be enabled for this to work.
@param[in] dac_wave_ens uint32_t. Taken from @ref dac_wave1_en or @ref
dac_wave2_en or a logical OR of one of each of these to set both channels
simultaneously.
*/
void dac_set_waveform_generation(uint32_t dac_wave_ens)
{
DAC_CR |= dac_wave_ens;
}
/*---------------------------------------------------------------------------*/
/** @brief Disable DAC Channel Waveform Generation.
Disable a digital to analog converter channel superimposed waveform generation.
@param[in] dac_channel enum ::data_channel.
*/
void dac_disable_waveform_generation(data_channel dac_channel)
{
switch (dac_channel) {
case CHANNEL_1:
DAC_CR &= ~DAC_CR_WAVE1_DIS;
break;
case CHANNEL_2:
DAC_CR &= ~DAC_CR_WAVE2_DIS;
break;
case CHANNEL_D:
DAC_CR &= ~(DAC_CR_WAVE1_DIS | DAC_CR_WAVE2_DIS);
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief Set DAC Channel LFSR Mask or Triangle Wave Amplitude.
Sets the digital to analog converter superimposed waveform generation
characteristics. @li If the noise generation mode is set, this sets the length
of the PRBS sequence and hence the amplitude of the output noise signal.
Default setting is length 1. @li If the triangle wave generation mode is set,
this sets the amplitude of the output signal as 2^(n)-1 where n is the
parameter value. Default setting is 1.
@note High amplitude levels of these waveforms can overload the DAC and distort
the signal output.
@note This must be called before enabling the DAC as the settings will then
become read-only.
@note The DAC trigger must be enabled for this to work.
@param[in] dac_mamp uint32_t. Taken from @ref dac_mamp2 or @ref dac_mamp1 or a
logical OR of one of each of these to set both channels simultaneously.
*/
void dac_set_waveform_characteristics(uint32_t dac_mamp)
{
DAC_CR |= dac_mamp;
}
/*---------------------------------------------------------------------------*/
/** @brief Load DAC Data Register.
Loads the appropriate digital to analog converter data register with 12 or 8 bit
data to be converted on a channel. The data can be aligned as follows:
@li right-aligned 8 bit data in bits 0-7
@li right-aligned 12 bit data in bits 0-11
@li left aligned 12 bit data in bits 4-15
@param[in] dac_data uint16_t with appropriate alignment.
@param[in] dac_data_format enum ::data_align. Alignment and size.
@param[in] dac_channel enum ::data_channel.
*/
void dac_load_data_buffer_single(uint16_t dac_data, data_align dac_data_format,
data_channel dac_channel)
{
if (dac_channel == CHANNEL_1) {
switch (dac_data_format) {
case RIGHT8:
DAC_DHR8R1 = dac_data;
break;
case RIGHT12:
DAC_DHR12R1 = dac_data;
break;
case LEFT12:
DAC_DHR12L1 = dac_data;
break;
}
} else if (dac_channel == CHANNEL_2) {
switch (dac_data_format) {
case RIGHT8:
DAC_DHR8R2 = dac_data;
break;
case RIGHT12:
DAC_DHR12R2 = dac_data;
break;
case LEFT12:
DAC_DHR12L2 = dac_data;
break;
}
}
}
/*---------------------------------------------------------------------------*/
/** @brief Load DAC Dual Data Register.
Loads the appropriate digital to analog converter dual data register with 12 or
8 bit data to be converted for both channels. This allows high bandwidth
simultaneous or independent analog output. The data in both channels are aligned
identically.
@param[in] dac_data1 uint16_t for channel 1 with appropriate alignment.
@param[in] dac_data2 uint16_t for channel 2 with appropriate alignment.
@param[in] dac_data_format enum ::data_align. Right or left aligned, and 8 or
12 bit.
*/
void dac_load_data_buffer_dual(uint16_t dac_data1, uint16_t dac_data2,
data_align dac_data_format)
{
switch (dac_data_format) {
case RIGHT8:
DAC_DHR8RD = ((dac_data1 & MASK8) | ((dac_data2 & MASK8) << 8));
break;
case RIGHT12:
DAC_DHR12RD = ((dac_data1 & MASK12) |
((dac_data2 & MASK12) << 16));
break;
case LEFT12:
DAC_DHR12LD = ((dac_data1 & MASK12) |
((dac_data2 & MASK12) << 16));
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief Trigger the DAC by a Software Trigger.
If the trigger source is set to be a software trigger, cause a trigger to occur.
The trigger is cleared by hardware after conversion.
@param[in] dac_channel enum ::data_channel.
*/
void dac_software_trigger(data_channel dac_channel)
{
switch (dac_channel) {
case CHANNEL_1:
DAC_SWTRIGR |= DAC_SWTRIGR_SWTRIG1;
break;
case CHANNEL_2:
DAC_SWTRIGR |= DAC_SWTRIGR_SWTRIG2;
break;
case CHANNEL_D:
DAC_SWTRIGR |= (DAC_SWTRIGR_SWTRIG1 | DAC_SWTRIGR_SWTRIG2);
break;
}
}
/**@}*/

View File

@ -0,0 +1,794 @@
/** @addtogroup dma_file
@author @htmlonly &copy; @endhtmlonly 2012
Ken Sarkies <ksarkies@internode.on.net>
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 instead of the DMA controller to
control the flow of data. This limits the functionality but is useful 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/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(uint32_t dma, uint8_t stream)
{
/* Disable stream (must be done before register is otherwise changed). */
DMA_SCR(dma, stream) &= ~DMA_SxCR_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. */
uint32_t 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 bitwise 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. Bitwise OR of interrupt numbers: @ref
dma_if_offset
*/
void dma_clear_interrupt_flags(uint32_t dma, uint8_t stream,
uint32_t interrupts)
{
/* Get offset to interrupt flag location in stream field */
uint32_t 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(uint32_t dma, uint8_t stream, uint32_t interrupt)
{
/* get offset to interrupt flag location in stream field. Assumes
* stream and interrupt parameters are integers.
*/
uint32_t 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(uint32_t dma, uint8_t stream, uint32_t direction)
{
uint32_t reg32 = (DMA_SCR(dma, stream) & ~DMA_SxCR_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_SxCR_DIR_MEM_TO_MEM) {
reg32 &= ~(DMA_SxCR_CIRC | DMA_SxCR_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(uint32_t dma, uint8_t stream, uint32_t prio)
{
DMA_SCR(dma, stream) &= ~(DMA_SxCR_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(uint32_t dma, uint8_t stream, uint32_t mem_size)
{
DMA_SCR(dma, stream) &= ~(DMA_SxCR_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(uint32_t dma, uint8_t stream,
uint32_t peripheral_size)
{
DMA_SCR(dma, stream) &= ~(DMA_SxCR_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(uint32_t dma, uint8_t stream)
{
DMA_SCR(dma, stream) |= DMA_SxCR_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(uint32_t dma, uint8_t stream)
{
DMA_SCR(dma, stream) &= ~DMA_SxCR_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(uint32_t dma, uint8_t stream)
{
uint32_t reg32 = (DMA_SCR(dma, stream) | DMA_SxCR_PINC);
DMA_SCR(dma, stream) = (reg32 & ~DMA_SxCR_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(uint32_t dma, uint8_t stream)
{
DMA_SCR(dma, stream) &= ~DMA_SxCR_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(uint32_t dma, uint8_t stream)
{
DMA_SCR(dma, stream) |= (DMA_SxCR_PINC | DMA_SxCR_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(uint32_t dma, uint8_t stream)
{
DMA_SCR(dma, stream) |= DMA_SxCR_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(uint32_t dma, uint8_t stream, uint32_t 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(uint32_t dma, uint8_t stream, uint32_t burst)
{
uint32_t reg32 = (DMA_SCR(dma, stream) & ~DMA_SxCR_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(uint32_t dma, uint8_t stream, uint32_t burst)
{
uint32_t reg32 = (DMA_SCR(dma, stream) & ~DMA_SxCR_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(uint32_t dma, uint8_t stream, uint8_t memory)
{
uint32_t reg32 = (DMA_SCR(dma, stream) & ~DMA_SxCR_CT);
if (memory == 1) {
reg32 |= DMA_SxCR_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
*/
uint8_t dma_get_target(uint32_t dma, uint8_t stream)
{
if (DMA_SCR(dma, stream) & DMA_SxCR_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(uint32_t dma, uint8_t stream)
{
DMA_SCR(dma, stream) |= DMA_SxCR_DBM;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Stream Disable Double Buffer 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_disable_double_buffer_mode(uint32_t dma, uint8_t stream)
{
DMA_SCR(dma, stream) &= ~DMA_SxCR_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(uint32_t dma, uint8_t stream)
{
DMA_SCR(dma, stream) |= DMA_SxCR_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(uint32_t dma, uint8_t stream)
{
DMA_SCR(dma, stream) &= ~DMA_SxCR_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(uint32_t dma, uint8_t stream)
{
dma_clear_interrupt_flags(dma, stream, DMA_TEIF);
DMA_SCR(dma, stream) |= DMA_SxCR_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(uint32_t dma, uint8_t stream)
{
DMA_SCR(dma, stream) &= ~DMA_SxCR_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(uint32_t dma, uint8_t stream)
{
dma_clear_interrupt_flags(dma, stream, DMA_HTIF);
DMA_SCR(dma, stream) |= DMA_SxCR_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(uint32_t dma, uint8_t stream)
{
DMA_SCR(dma, stream) &= ~DMA_SxCR_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(uint32_t dma, uint8_t stream)
{
dma_clear_interrupt_flags(dma, stream, DMA_TCIF);
DMA_SCR(dma, stream) |= DMA_SxCR_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(uint32_t dma, uint8_t stream)
{
DMA_SCR(dma, stream) &= ~DMA_SxCR_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(uint32_t dma, uint8_t stream)
{
dma_clear_interrupt_flags(dma, stream, DMA_DMEIF);
DMA_SCR(dma, stream) |= DMA_SxCR_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(uint32_t dma, uint8_t stream)
{
DMA_SCR(dma, stream) &= ~DMA_SxCR_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(uint32_t dma, uint8_t stream)
{
dma_clear_interrupt_flags(dma, stream, DMA_FEIF);
DMA_SFCR(dma, stream) |= DMA_SxFCR_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(uint32_t dma, uint8_t stream)
{
DMA_SFCR(dma, stream) &= ~DMA_SxFCR_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 uint32_t FIFO Status @ref dma_fifo_status
*/
uint32_t dma_fifo_status(uint32_t dma, uint8_t stream)
{
return DMA_SFCR(dma, stream) & DMA_SxFCR_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(uint32_t dma, uint8_t stream)
{
DMA_SFCR(dma, stream) &= ~DMA_SxFCR_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(uint32_t dma, uint8_t stream)
{
DMA_SFCR(dma, stream) |= DMA_SxFCR_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(uint32_t dma, uint8_t stream, uint32_t threshold)
{
uint32_t reg32 = (DMA_SFCR(dma, stream) & ~DMA_SxFCR_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(uint32_t dma, uint8_t stream)
{
DMA_SCR(dma, stream) |= DMA_SxCR_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(uint32_t dma, uint8_t stream)
{
DMA_SCR(dma, stream) &= ~DMA_SxCR_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(uint32_t dma, uint8_t stream, uint32_t address)
{
if (!(DMA_SCR(dma, stream) & DMA_SxCR_EN)) {
DMA_SPAR(dma, stream) = (uint32_t *) 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(uint32_t dma, uint8_t stream, uint32_t address)
{
uint32_t reg32 = DMA_SCR(dma, stream);
if (!(reg32 & DMA_SxCR_EN) ||
((reg32 & DMA_SxCR_CT) && (reg32 & DMA_SxCR_DBM))) {
DMA_SM0AR(dma, stream) = (uint32_t *) 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(uint32_t dma, uint8_t stream, uint32_t address)
{
uint32_t reg32 = DMA_SCR(dma, stream);
if (!(reg32 & DMA_SxCR_EN) ||
(!(reg32 & DMA_SxCR_CT) && (reg32 & DMA_SxCR_DBM))) {
DMA_SM1AR(dma, stream) = (uint32_t *) 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(uint32_t dma, uint8_t stream, uint16_t number)
{
DMA_SNDTR(dma, stream) = number;
}
/**@}*/

View File

@ -0,0 +1,435 @@
/** @addtogroup dma_file
@author @htmlonly &copy; @endhtmlonly 2010 Thomas Otto <tommi@viadmin.org>
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
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.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/>.
*/
/**@{*/
#include <libopencm3/stm32/dma.h>
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Reset
The channel is disabled and configuration registers are cleared.
@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_channel_reset(uint32_t dma, uint8_t channel)
{
/* Disable channel and reset config bits. */
DMA_CCR(dma, channel) = 0;
/* Reset data transfer number. */
DMA_CNDTR(dma, channel) = 0;
/* Reset peripheral address. */
DMA_CPAR(dma, channel) = 0;
/* Reset memory address. */
DMA_CMAR(dma, channel) = 0;
/* Reset interrupt flags. */
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_ch
@param[in] interrupts unsigned int32. Logical OR of interrupt numbers: @ref
dma_if_offset
*/
void dma_clear_interrupt_flags(uint32_t dma, uint8_t channel,
uint32_t interrupts)
{
/* Get offset to interrupt flag location in channel field */
uint32_t 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_ch
@param[in] interrupt unsigned int32. Interrupt number: @ref dma_if_offset
@returns bool interrupt flag is set.
*/
bool dma_get_interrupt_flag(uint32_t dma, uint8_t channel, uint32_t interrupt)
{
/* get offset to interrupt flag location in channel field. */
uint32_t flag = (interrupt << DMA_FLAG_OFFSET(channel));
return ((DMA_ISR(dma) & flag) > 0);
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Enable Memory to Memory Transfers
Memory to memory transfers do not require a trigger to activate each transfer.
Transfers begin immediately the channel has been enabled, and proceed without
intervention.
@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_mem2mem_mode(uint32_t dma, uint8_t channel)
{
DMA_CCR(dma, channel) |= DMA_CCR_MEM2MEM;
DMA_CCR(dma, channel) &= ~DMA_CCR_CIRC;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Set Priority
Channel Priority has four levels: low to very high. This has precedence over the
hardware priority.
@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
@param[in] prio unsigned int32. Priority level @ref dma_ch_pri.
*/
void dma_set_priority(uint32_t dma, uint8_t channel, uint32_t prio)
{
DMA_CCR(dma, channel) &= ~(DMA_CCR_PL_MASK);
DMA_CCR(dma, channel) |= prio;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel 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.
@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
@param[in] mem_size unsigned int32. Memory word width @ref dma_ch_memwidth.
*/
void dma_set_memory_size(uint32_t dma, uint8_t channel, uint32_t mem_size)
{
DMA_CCR(dma, channel) &= ~(DMA_CCR_MSIZE_MASK);
DMA_CCR(dma, channel) |= mem_size;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel 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.
@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
@param[in] peripheral_size unsigned int32. Peripheral word width @ref
dma_ch_perwidth.
*/
void dma_set_peripheral_size(uint32_t dma, uint8_t channel,
uint32_t peripheral_size)
{
DMA_CCR(dma, channel) &= ~(DMA_CCR_PSIZE_MASK);
DMA_CCR(dma, channel) |= peripheral_size;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel 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.
@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_memory_increment_mode(uint32_t dma, uint8_t channel)
{
DMA_CCR(dma, channel) |= DMA_CCR_MINC;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Disable Memory 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_memory_increment_mode(uint32_t dma, uint8_t 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(uint32_t dma, uint8_t 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(uint32_t dma, uint8_t channel)
{
DMA_CCR(dma, channel) &= ~DMA_CCR_PINC;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel 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.
@note This cannot be used with memory to memory mode, which is explictly
disabled here.
@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_circular_mode(uint32_t dma, uint8_t channel)
{
DMA_CCR(dma, channel) |= DMA_CCR_CIRC;
DMA_CCR(dma, channel) &= ~DMA_CCR_MEM2MEM;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Enable Transfers from a Peripheral
The data direction is set to read from a peripheral.
@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_set_read_from_peripheral(uint32_t dma, uint8_t channel)
{
DMA_CCR(dma, channel) &= ~DMA_CCR_DIR;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Enable Transfers from Memory
The data direction is set to read from memory.
@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_set_read_from_memory(uint32_t dma, uint8_t channel)
{
DMA_CCR(dma, channel) |= DMA_CCR_DIR;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Enable Interrupt on Transfer Error
@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_transfer_error_interrupt(uint32_t dma, uint8_t channel)
{
DMA_CCR(dma, channel) |= DMA_CCR_TEIE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Disable Interrupt on Transfer Error
@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_transfer_error_interrupt(uint32_t dma, uint8_t channel)
{
DMA_CCR(dma, channel) &= ~DMA_CCR_TEIE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Enable Interrupt on Transfer Half Complete
@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_half_transfer_interrupt(uint32_t dma, uint8_t channel)
{
DMA_CCR(dma, channel) |= DMA_CCR_HTIE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Disable Interrupt on Transfer Half Complete
@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_half_transfer_interrupt(uint32_t dma, uint8_t channel)
{
DMA_CCR(dma, channel) &= ~DMA_CCR_HTIE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Enable Interrupt on Transfer Complete
@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_transfer_complete_interrupt(uint32_t dma, uint8_t channel)
{
DMA_CCR(dma, channel) |= DMA_CCR_TCIE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Disable Interrupt on Transfer Complete
@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_transfer_complete_interrupt(uint32_t dma, uint8_t channel)
{
DMA_CCR(dma, channel) &= ~DMA_CCR_TCIE;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Enable
@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_channel(uint32_t dma, uint8_t channel)
{
DMA_CCR(dma, channel) |= DMA_CCR_EN;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Disable
@note The DMA channel registers retain their values when the channel is
disabled.
@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_channel(uint32_t dma, uint8_t channel)
{
DMA_CCR(dma, channel) &= ~DMA_CCR_EN;
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel 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 channel must be disabled before setting this address. This
function has no effect if the channel is enabled.
@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
@param[in] address unsigned int32. Peripheral Address.
*/
void dma_set_peripheral_address(uint32_t dma, uint8_t channel, uint32_t address)
{
if (!(DMA_CCR(dma, channel) & DMA_CCR_EN)) {
DMA_CPAR(dma, channel) = (uint32_t) address;
}
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Set the Base Memory Address
@note The DMA channel must be disabled before setting this address. This
function has no effect if the channel is enabled.
@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
@param[in] address unsigned int32. Memory Initial Address.
*/
void dma_set_memory_address(uint32_t dma, uint8_t channel, uint32_t address)
{
if (!(DMA_CCR(dma, channel) & DMA_CCR_EN)) {
DMA_CMAR(dma, channel) = (uint32_t) address;
}
}
/*---------------------------------------------------------------------------*/
/** @brief DMA Channel Set the Transfer Block Size
@note The DMA channel must be disabled before setting this count value. The
count is not changed if the channel is enabled.
@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
@param[in] number unsigned int16. Number of data words to transfer (65535
maximum).
*/
void dma_set_number_of_data(uint32_t dma, uint8_t channel, uint16_t number)
{
DMA_CNDTR(dma, channel) = number;
}
/**@}*/

View File

@ -0,0 +1,151 @@
/*
* 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
* 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/>.
*
* 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/memorymap.h>
#include <libopencm3/stm32/exti.h>
#include <libopencm3/stm32/gpio.h>
#if !defined(AFIO_BASE)
# include <libopencm3/stm32/syscfg.h>
#endif
void exti_set_trigger(uint32_t extis, enum 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(uint32_t extis)
{
/* Enable interrupts. */
EXTI_IMR |= extis;
/* Enable events. */
EXTI_EMR |= extis;
}
void exti_disable_request(uint32_t 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(uint32_t extis)
{
EXTI_PR = extis;
}
/*
* Check the flag of a given EXTI interrupt.
* */
uint32_t exti_get_flag_status(uint32_t exti)
{
return EXTI_PR & exti;
}
/*
* 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(uint32_t exti, uint32_t gpioport)
{
uint32_t line;
for (line = 0; line < 16; line++) {
if (!(exti & (1 << line))) {
continue;
}
uint32_t bits = 0, mask = 0x0F;
switch (gpioport) {
case GPIOA:
bits = 0;
break;
case GPIOB:
bits = 1;
break;
case GPIOC:
bits = 2;
break;
case GPIOD:
bits = 3;
break;
#if defined(GPIOE) && defined(GPIO_PORT_E_BASE)
case GPIOE:
bits = 4;
break;
#endif
#if defined(GPIOF) && defined(GPIO_PORT_F_BASE)
case GPIOF:
bits = 5;
break;
#endif
#if defined(GPIOG) && defined(GPIO_PORT_G_BASE)
case GPIOG:
bits = 6;
break;
#endif
#if defined(GPIOH) && defined(GPIO_PORT_H_BASE)
case GPIOH:
bits = 7;
break;
#endif
#if defined(GPIOI) && defined(GPIO_PORT_I_BASE)
case GPIOI:
bits = 8;
break;
#endif
}
uint8_t shift = (uint8_t)(4 * (line % 4));
uint32_t reg = line / 4;
bits <<= shift;
mask <<= shift;
#if defined(AFIO_BASE)
AFIO_EXTICR(reg) = (AFIO_EXTICR(reg) & ~mask) | bits;
#else
SYSCFG_EXTICR(reg) = (SYSCFG_EXTICR(reg) & ~mask) | bits;
#endif
};
}

View File

@ -0,0 +1,67 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
* 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/flash.h>
void flash_set_ws(uint32_t ws)
{
uint32_t reg32;
reg32 = FLASH_ACR;
reg32 &= ~((1 << 0) | (1 << 1) | (1 << 2));
reg32 |= ws;
FLASH_ACR = reg32;
}
void flash_unlock(void)
{
/* Clear the unlock sequence state. */
FLASH_CR |= FLASH_CR_LOCK;
/* Authorize the FPEC access. */
FLASH_KEYR = FLASH_KEYR_KEY1;
FLASH_KEYR = FLASH_KEYR_KEY2;
}
void flash_lock(void)
{
FLASH_CR |= FLASH_CR_LOCK;
}
void flash_clear_pgperr_flag(void)
{
FLASH_SR |= FLASH_SR_PGPERR;
}
void flash_clear_eop_flag(void)
{
FLASH_SR |= FLASH_SR_EOP;
}
void flash_clear_bsy_flag(void)
{
FLASH_SR &= ~FLASH_SR_BSY;
}
void flash_wait_for_last_operation(void)
{
while ((FLASH_SR & FLASH_SR_BSY) == FLASH_SR_BSY);
}

View File

@ -0,0 +1,224 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
* 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/flash.h>
static inline void flash_set_program_size(uint32_t psize)
{
FLASH_CR &= ~(((1 << 0) | (1 << 1)) << 8);
FLASH_CR |= psize;
}
void flash_dcache_enable(void)
{
FLASH_ACR |= FLASH_ACR_DCE;
}
void flash_dcache_disable(void)
{
FLASH_ACR &= ~FLASH_ACR_DCE;
}
void flash_icache_enable(void)
{
FLASH_ACR |= FLASH_ACR_ICE;
}
void flash_icache_disable(void)
{
FLASH_ACR &= ~FLASH_ACR_ICE;
}
void flash_prefetch_enable(void)
{
FLASH_ACR |= FLASH_ACR_PRFTEN;
}
void flash_prefetch_disable(void)
{
FLASH_ACR &= ~FLASH_ACR_PRFTEN;
}
void flash_dcache_reset(void)
{
FLASH_ACR |= FLASH_ACR_DCRST;
}
void flash_icache_reset(void)
{
FLASH_ACR |= FLASH_ACR_ICRST;
}
void flash_clear_pgserr_flag(void)
{
FLASH_SR |= FLASH_SR_PGSERR;
}
void flash_clear_pgaerr_flag(void)
{
FLASH_SR |= FLASH_SR_PGAERR;
}
void flash_clear_wrperr_flag(void)
{
FLASH_SR |= FLASH_SR_WRPERR;
}
void flash_clear_status_flags(void)
{
flash_clear_pgserr_flag();
flash_clear_pgaerr_flag();
flash_clear_wrperr_flag();
flash_clear_pgperr_flag();
flash_clear_eop_flag();
flash_clear_bsy_flag();
}
void flash_unlock_option_bytes(void)
{
/* Clear the unlock state. */
FLASH_OPTCR |= FLASH_OPTCR_OPTLOCK;
/* Unlock option bytes. */
FLASH_OPTKEYR = FLASH_OPTKEYR_KEY1;
FLASH_OPTKEYR = FLASH_OPTKEYR_KEY2;
}
void flash_lock_option_bytes(void)
{
FLASH_OPTCR |= FLASH_OPTCR_OPTLOCK;
}
void flash_program_double_word(uint32_t address, uint64_t data)
{
/* Ensure that all flash operations are complete. */
flash_wait_for_last_operation();
flash_set_program_size(FLASH_CR_PROGRAM_X64);
/* Enable writes to flash. */
FLASH_CR |= FLASH_CR_PG;
/* Program the first half of the word. */
MMIO64(address) = data;
/* Wait for the write to complete. */
flash_wait_for_last_operation();
/* Disable writes to flash. */
FLASH_CR &= ~FLASH_CR_PG;
}
void flash_program_word(uint32_t address, uint32_t data)
{
/* Ensure that all flash operations are complete. */
flash_wait_for_last_operation();
flash_set_program_size(FLASH_CR_PROGRAM_X32);
/* Enable writes to flash. */
FLASH_CR |= FLASH_CR_PG;
/* Program the first half of the word. */
MMIO32(address) = data;
/* Wait for the write to complete. */
flash_wait_for_last_operation();
/* Disable writes to flash. */
FLASH_CR &= ~FLASH_CR_PG;
}
void flash_program_half_word(uint32_t address, uint16_t data)
{
flash_wait_for_last_operation();
flash_set_program_size(FLASH_CR_PROGRAM_X16);
FLASH_CR |= FLASH_CR_PG;
MMIO16(address) = data;
flash_wait_for_last_operation();
FLASH_CR &= ~FLASH_CR_PG; /* Disable the PG bit. */
}
void flash_program_byte(uint32_t address, uint8_t data)
{
flash_wait_for_last_operation();
flash_set_program_size(FLASH_CR_PROGRAM_X8);
FLASH_CR |= FLASH_CR_PG;
MMIO8(address) = data;
flash_wait_for_last_operation();
FLASH_CR &= ~FLASH_CR_PG; /* Disable the PG bit. */
}
void flash_program(uint32_t address, uint8_t *data, uint32_t len)
{
/* TODO: Use dword and word size program operations where possible for
* turbo speed.
*/
uint32_t i;
for (i = 0; i < len; i++) {
flash_program_byte(address+i, data[i]);
}
}
void flash_erase_sector(uint8_t sector, uint32_t program_size)
{
flash_wait_for_last_operation();
flash_set_program_size(program_size);
FLASH_CR &= ~(0xF << 3);
FLASH_CR |= (sector << 3) & 0x78;
FLASH_CR |= FLASH_CR_SER;
FLASH_CR |= FLASH_CR_STRT;
flash_wait_for_last_operation();
FLASH_CR &= ~FLASH_CR_SER;
FLASH_CR &= ~(0xF << 3);
}
void flash_erase_all_sectors(uint32_t program_size)
{
flash_wait_for_last_operation();
flash_set_program_size(program_size);
FLASH_CR |= FLASH_CR_MER; /* Enable mass erase. */
FLASH_CR |= FLASH_CR_STRT; /* Trigger the erase. */
flash_wait_for_last_operation();
FLASH_CR &= ~FLASH_CR_MER; /* Disable mass erase. */
}
void flash_program_option_bytes(uint32_t data)
{
flash_wait_for_last_operation();
if (FLASH_OPTCR & FLASH_OPTCR_OPTLOCK) {
flash_unlock_option_bytes();
}
FLASH_OPTCR = data & ~0x3;
FLASH_OPTCR |= FLASH_OPTCR_OPTSTRT; /* Enable option byte prog. */
flash_wait_for_last_operation();
}

View File

@ -0,0 +1,151 @@
/** @addtogroup gpio_file
@author @htmlonly &copy; @endhtmlonly 2009 Uwe Hermann <uwe@hermann-uwe.de>
*/
/*
* 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/>.
*/
#define WEAK __attribute__((weak))
#include <libopencm3/stm32/gpio.h>
/**@{*/
/*---------------------------------------------------------------------------*/
/** @brief Set a Group of Pins Atomic
Set one or more pins of the given GPIO port to 1 in an atomic operation.
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
If multiple pins are to be changed, use logical OR '|' to separate
them.
*/
void gpio_set(uint32_t gpioport, uint16_t gpios)
{
GPIO_BSRR(gpioport) = gpios;
}
/*---------------------------------------------------------------------------*/
/** @brief Clear a Group of Pins Atomic
Clear one or more pins of the given GPIO port to 0 in an atomic operation.
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
If multiple pins are to be changed, use logical OR '|' to separate
them.
*/
void gpio_clear(uint32_t gpioport, uint16_t gpios)
{
GPIO_BSRR(gpioport) = (gpios << 16);
}
/*---------------------------------------------------------------------------*/
/** @brief Read a Group of Pins.
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
If multiple pins are to be read, use logical OR '|' to separate
them.
@return Unsigned int16 value of the pin values. The bit position of the pin
value returned corresponds to the pin number.
*/
uint16_t gpio_get(uint32_t gpioport, uint16_t gpios)
{
return gpio_port_read(gpioport) & gpios;
}
/*---------------------------------------------------------------------------*/
/** @brief Toggle a Group of Pins
Toggle one or more pins of the given GPIO port. This is not an atomic operation.
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
If multiple pins are to be changed, use logical OR '|' to separate
them.
*/
void gpio_toggle(uint32_t gpioport, uint16_t gpios)
{
GPIO_ODR(gpioport) ^= gpios;
}
/*---------------------------------------------------------------------------*/
/** @brief Read from a Port
Read the current value of the given GPIO port. Only the lower 16 bits contain
valid pin data.
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
@return Unsigned int16. The value held in the specified GPIO port.
*/
uint16_t gpio_port_read(uint32_t gpioport)
{
return (uint16_t)GPIO_IDR(gpioport);
}
/*---------------------------------------------------------------------------*/
/** @brief Write to a Port
Write a value to the given GPIO port.
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
@param[in] data Unsigned int16. The value to be written to the GPIO port.
*/
void gpio_port_write(uint32_t gpioport, uint16_t data)
{
GPIO_ODR(gpioport) = data;
}
/*---------------------------------------------------------------------------*/
/** @brief Lock the Configuration of a Group of Pins
The configuration of one or more pins of the given GPIO port is locked. There
is no mechanism to unlock these via software. Unlocking occurs at the next
reset.
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
If multiple pins are to be locked, use logical OR '|' to separate
them.
*/
void gpio_port_config_lock(uint32_t gpioport, uint16_t gpios)
{
uint32_t 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

@ -0,0 +1,206 @@
/** @addtogroup gpio_file
@author @htmlonly &copy; @endhtmlonly 2009
Uwe Hermann <uwe@hermann-uwe.de>
@author @htmlonly &copy; @endhtmlonly 2012
Ken Sarkies <ksarkies@internode.on.net>
Each I/O port has 16 individually configurable bits. Many I/O pins share GPIO
functionality with a number of alternate functions and must be configured to
the alternate function mode if these are to be accessed. A feature is available
to remap alternative functions to a limited set of alternative pins in the
event of a clash of requirements.
The data registers associated with each port for input and output are 32 bit
with the upper 16 bits unused. The output buffer must be written as a 32 bit
word, but individual bits may be set or reset separately in atomic operations
to avoid race conditions during interrupts. Bits may also be individually
locked to prevent accidental configuration changes. Once locked the
configuration cannot be changed until after the next reset.
Each port bit can be configured as analog or digital input, the latter can be
floating or pulled up or down. As outputs they can be configured as either
push-pull or open drain, digital I/O or alternate function, and with maximum
output speeds of 2MHz, 10MHz, or 50MHz.
On reset all ports are configured as digital floating input.
@section gpio_api_ex Basic GPIO Handling API.
Example 1: Push-pull digital output actions with pullup on ports C2 and C9
@code
gpio_mode_setup(GPIOC, GPIO_MODE_OUTPUT,
GPIO_PUPD_PULLUP, GPIO2 | GPIO9);
gpio_output_options(GPIOC, GPIO_OTYPE_PP,
GPIO_OSPEED_25MHZ, GPIO2 | GPIO9);
gpio_set(GPIOC, GPIO2 | GPIO9);
gpio_clear(GPIOC, GPIO2);
gpio_toggle(GPIOC, GPIO2 | GPIO9);
gpio_port_write(GPIOC, 0x204);
@endcode
Example 2: Digital input on port C12 with pullup
@code
gpio_mode_setup(GPIOC, GPIO_MODE_INPUT,
GPIO_PUPD_PULLUP, GPIO12);
reg16 = gpio_port_read(GPIOC);
@endcode
*/
/*
* 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/gpio.h>
/*---------------------------------------------------------------------------*/
/** @brief Set GPIO Pin Mode
Sets the Pin Direction and Analog/Digital Mode, and Output Pin Pullup,
for a set of GPIO pins on a given GPIO port.
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
@param[in] mode Unsigned int8. Pin mode @ref gpio_mode
@param[in] pull_up_down Unsigned int8. Pin pullup/pulldown configuration @ref
gpio_pup
@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
If multiple pins are to be set, use bitwise OR '|' to separate
them.
*/
void gpio_mode_setup(uint32_t gpioport, uint8_t mode, uint8_t pull_up_down,
uint16_t gpios)
{
uint16_t i;
uint32_t 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;
}
/*---------------------------------------------------------------------------*/
/** @brief Set GPIO Output Options
When the pin is set to output mode, this sets the configuration (analog/digital
and open drain/push pull) and speed, for a set of GPIO pins on a given GPIO
port.
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
@param[in] otype Unsigned int8. Pin output type @ref gpio_output_type
@param[in] speed Unsigned int8. Pin speed @ref gpio_speed
@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
If multiple pins are to be set, use bitwise OR '|' to separate
them.
*/
void gpio_set_output_options(uint32_t gpioport, uint8_t otype, uint8_t speed,
uint16_t gpios)
{
uint16_t i;
uint32_t 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;
}
/*---------------------------------------------------------------------------*/
/** @brief Set GPIO Alternate Function Selection
Set the alternate function mapping number for each pin. Most pins have
alternate functions associated with them. When set to AF mode, a pin may be
used for one of its allocated alternate functions selected by the number given
here. To determine the number to be used for the desired function refer to the
individual datasheet for the particular device. A table is given under the Pin
Selection chapter.
Note that a number of pins may be set but only with a single AF number. In
practice this would rarely be useful as each pin is likely to require a
different number.
@param[in] gpioport Unsigned int32. Port identifier @ref gpio_port_id
@param[in] alt_func_num Unsigned int8. Pin alternate function number @ref
gpio_af_num
@param[in] gpios Unsigned int16. Pin identifiers @ref gpio_pin_id
If multiple pins are to be set, use bitwise OR '|' to separate
them.
*/
void gpio_set_af(uint32_t gpioport, uint8_t alt_func_num, uint16_t gpios)
{
uint16_t i;
uint32_t 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;
}
afrh &= ~GPIO_AFR_MASK(i - 8);
afrh |= GPIO_AFR(i - 8, alt_func_num);
}
GPIO_AFRL(gpioport) = afrl;
GPIO_AFRH(gpioport) = afrh;
}
/**@}*/

View File

@ -0,0 +1,161 @@
/** @addtogroup hash_file
@author @htmlonly &copy; @endhtmlonly 2013
Mikhail Avkhimenia <mikhail@avkhimenia.net>
This library supports the HASH processor in the STM32F2 and STM32F4
series of ARM Cortex Microcontrollers by ST Microelectronics.
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2013 Mikhail Avkhimenia <mikhail@avkhimenia.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/hash.h>
/*---------------------------------------------------------------------------*/
/** @brief HASH Set Mode
Sets up the specified mode - either HASH or HMAC.
@param[in] mode unsigned int8. Hash processor mode: @ref hash_mode
*/
void hash_set_mode(uint8_t mode)
{
HASH_CR &= ~HASH_CR_MODE;
HASH_CR |= mode;
}
/*---------------------------------------------------------------------------*/
/** @brief HASH Set Algorithm
Sets up the specified algorithm - either MD5 or SHA1.
@param[in] algorithm unsigned int8. Hash algorithm: @ref hash_algorithm
*/
void hash_set_algorithm(uint8_t algorithm)
{
HASH_CR &= ~HASH_CR_ALGO;
HASH_CR |= algorithm;
}
/*---------------------------------------------------------------------------*/
/** @brief HASH Set Data Type
Sets up the specified data type: 32Bit, 16Bit, 8Bit, Bitstring.
@param[in] datatype unsigned int8. Hash data type: @ref hash_data_type
*/
void hash_set_data_type(uint8_t datatype)
{
HASH_CR &= ~HASH_CR_DATATYPE;
HASH_CR |= datatype;
}
/*---------------------------------------------------------------------------*/
/** @brief HASH Set Key Length
Sets up the specified key length: Long, Short.
@param[in] keylength unsigned int8. Hash data type: @ref hash_key_length
*/
void hash_set_key_length(uint8_t keylength)
{
HASH_CR &= ~HASH_CR_LKEY;
HASH_CR |= keylength;
}
/*---------------------------------------------------------------------------*/
/** @brief HASH Set Last Word Valid Bits
Specifies the number of valid bits in the last word.
@param[in] validbits unsigned int8. Number of valid bits.
*/
void hash_set_last_word_valid_bits(uint8_t validbits)
{
HASH_STR &= ~(HASH_STR_NBW);
HASH_STR |= 32 - validbits;
}
/*---------------------------------------------------------------------------*/
/** @brief HASH Init
Initializes the HASH processor.
*/
void hash_init()
{
HASH_CR |= HASH_CR_INIT;
}
/*---------------------------------------------------------------------------*/
/** @brief HASH Add data
Puts data into the HASH processor's queue.
@param[in] data unsigned int32. Hash input data.
*/
void hash_add_data(uint32_t data)
{
HASH_DIN = data;
}
/*---------------------------------------------------------------------------*/
/** @brief HASH Digest
Starts the processing of the last data block.
*/
void hash_digest()
{
HASH_STR |= HASH_STR_DCAL;
}
/*---------------------------------------------------------------------------*/
/** @brief HASH Get Hash Result
Makes a copy of the resulting hash.
@param[out] data unsigned int32. Hash 4\5 words long depending on the algorithm.
@param[in] algorithm unsigned int8. Hash algorithm: @ref hash_algorithm
*/
void hash_get_result(uint32_t *data)
{
data[0] = HASH_HR[0];
data[1] = HASH_HR[1];
data[2] = HASH_HR[2];
data[3] = HASH_HR[3];
if ((HASH_CR & HASH_CR_ALGO) == HASH_ALGO_SHA1) {
data[4] = HASH_HR[4];
}
}

View File

@ -0,0 +1,412 @@
/** @addtogroup i2c_file
@author @htmlonly &copy; @endhtmlonly 2010
Thomas Otto <tommi@viadmin.org>
@author @htmlonly &copy; @endhtmlonly 2012
Ken Sarkies <ksarkies@internode.on.net>
Devices can have up to two I2C peripherals. The peripherals support SMBus and
PMBus variants.
A peripheral begins after reset in Slave mode. To become a Master a start
condition must be generated. The peripheral will remain in Master mode unless
a multimaster contention is lost or a stop condition is generated.
@todo all sorts of lovely stuff like DMA, Interrupts, SMBus variant, Status
register access, Error conditions
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.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/>.
*/
#include <libopencm3/stm32/i2c.h>
#include <libopencm3/stm32/rcc.h>
/**@{*/
/*---------------------------------------------------------------------------*/
/** @brief I2C Reset.
The I2C peripheral and all its associated configuration registers are placed in
the reset condition. The reset is effected via the RCC peripheral reset system.
@param[in] i2c Unsigned int32. I2C peripheral identifier @ref i2c_reg_base.
*/
void i2c_reset(uint32_t i2c)
{
switch (i2c) {
case I2C1:
rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_I2C1RST);
rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_I2C1RST);
break;
case I2C2:
rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_I2C2RST);
rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_I2C2RST);
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Peripheral Enable.
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_peripheral_enable(uint32_t i2c)
{
I2C_CR1(i2c) |= I2C_CR1_PE;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Peripheral Disable.
This must not be reset while in Master mode until a communication has finished.
In Slave mode, the peripheral is disabled only after communication has ended.
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_peripheral_disable(uint32_t i2c)
{
I2C_CR1(i2c) &= ~I2C_CR1_PE;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Send Start Condition.
If in Master mode this will cause a restart condition to occur at the end of the
current transmission. If in Slave mode, this will initiate a start condition
when the current bus activity is completed.
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_send_start(uint32_t i2c)
{
I2C_CR1(i2c) |= I2C_CR1_START;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Send Stop Condition.
After the current byte transfer this will initiate a stop condition if in Master
mode, or simply release the bus if in Slave mode.
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_send_stop(uint32_t i2c)
{
I2C_CR1(i2c) |= I2C_CR1_STOP;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Clear Stop Flag.
Clear the "Send Stop" flag in the I2C config register
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_clear_stop(uint32_t i2c)
{
I2C_CR1(i2c) &= ~I2C_CR1_STOP;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Set the 7 bit Slave Address for the Peripheral.
This sets an address for Slave mode operation, in 7 bit form.
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
@param[in] slave Unsigned int8. Slave address 0...127.
*/
void i2c_set_own_7bit_slave_address(uint32_t i2c, uint8_t slave)
{
I2C_OAR1(i2c) = (uint16_t)(slave << 1);
I2C_OAR1(i2c) &= ~I2C_OAR1_ADDMODE;
I2C_OAR1(i2c) |= (1 << 14); /* Datasheet: always keep 1 by software. */
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Set the 10 bit Slave Address for the Peripheral.
This sets an address for Slave mode operation, in 10 bit form.
@todo add "I2C_OAR1(i2c) |= (1 << 14);" as above
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
@param[in] slave Unsigned int16. Slave address 0...1023.
*/
void i2c_set_own_10bit_slave_address(uint32_t i2c, uint16_t slave)
{
I2C_OAR1(i2c) = (uint16_t)(I2C_OAR1_ADDMODE | slave);
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Set Peripheral Clock Frequency.
Set the peripheral clock frequency: 2MHz to 36MHz (the APB frequency). Note
that this is <b> not </b> the I2C bus clock. This is set in conjunction with
the Clock Control register to generate the Master bus clock, see @ref
i2c_set_ccr
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
@param[in] freq Unsigned int8. Clock Frequency Setting @ref i2c_clock.
*/
void i2c_set_clock_frequency(uint32_t i2c, uint8_t freq)
{
uint16_t reg16;
reg16 = I2C_CR2(i2c) & 0xffc0; /* Clear bits [5:0]. */
reg16 |= freq;
I2C_CR2(i2c) = reg16;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Send Data.
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
@param[in] data Unsigned int8. Byte to send.
*/
void i2c_send_data(uint32_t i2c, uint8_t data)
{
I2C_DR(i2c) = data;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Set Fast Mode.
Set the clock frequency to the high clock rate mode (up to 400kHz). The actual
clock frequency must be set with @ref i2c_set_clock_frequency
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_set_fast_mode(uint32_t i2c)
{
I2C_CCR(i2c) |= I2C_CCR_FS;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Set Standard Mode.
Set the clock frequency to the standard clock rate mode (up to 100kHz). The
actual clock frequency must be set with @ref i2c_set_clock_frequency
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_set_standard_mode(uint32_t i2c)
{
I2C_CCR(i2c) &= ~I2C_CCR_FS;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Set Bus Clock Frequency.
Set the bus clock frequency. This is a 12 bit number (0...4095) calculated
from the formulae given in the STM32F1 reference manual in the description
of the CCR field. It is a divisor of the peripheral clock frequency
@ref i2c_set_clock_frequency modified by the fast mode setting
@ref i2c_set_fast_mode
@todo provide additional API assitance to set the clock, eg macros
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
@param[in] freq Unsigned int16. Bus Clock Frequency Setting 0...4095.
*/
void i2c_set_ccr(uint32_t i2c, uint16_t freq)
{
uint16_t reg16;
reg16 = I2C_CCR(i2c) & 0xf000; /* Clear bits [11:0]. */
reg16 |= freq;
I2C_CCR(i2c) = reg16;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Set the Rise Time.
Set the maximum rise time on the bus according to the I2C specification, as 1
more than the specified rise time in peripheral clock cycles. This is a 6 bit
number.
@todo provide additional APIP assistance.
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
@param[in] trise Unsigned int16. Rise Time Setting 0...63.
*/
void i2c_set_trise(uint32_t i2c, uint16_t trise)
{
I2C_TRISE(i2c) = trise;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Send the 7-bit Slave Address.
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
@param[in] slave Unsigned int16. Slave address 0...1023.
@param[in] readwrite Unsigned int8. Single bit to instruct slave to receive or
send @ref i2c_rw.
*/
void i2c_send_7bit_address(uint32_t i2c, uint8_t slave, uint8_t readwrite)
{
I2C_DR(i2c) = (uint8_t)((slave << 1) | readwrite);
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Get Data.
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
uint8_t i2c_get_data(uint32_t i2c)
{
return I2C_DR(i2c) & 0xff;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Enable Interrupt
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
@param[in] interrupt Unsigned int32. Interrupt to enable.
*/
void i2c_enable_interrupt(uint32_t i2c, uint32_t interrupt)
{
I2C_CR2(i2c) |= interrupt;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Disable Interrupt
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
@param[in] interrupt Unsigned int32. Interrupt to disable.
*/
void i2c_disable_interrupt(uint32_t i2c, uint32_t interrupt)
{
I2C_CR2(i2c) &= ~interrupt;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Enable ACK
Enables acking of own 7/10 bit address
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_enable_ack(uint32_t i2c)
{
I2C_CR1(i2c) |= I2C_CR1_ACK;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Disable ACK
Disables acking of own 7/10 bit address
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_disable_ack(uint32_t i2c)
{
I2C_CR1(i2c) &= ~I2C_CR1_ACK;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C NACK Next Byte
Causes the I2C controller to NACK the reception of the next byte
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_nack_next(uint32_t i2c)
{
I2C_CR1(i2c) |= I2C_CR1_POS;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C NACK Next Byte
Causes the I2C controller to NACK the reception of the current byte
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_nack_current(uint32_t i2c)
{
I2C_CR1(i2c) &= ~I2C_CR1_POS;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Set clock duty cycle
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
@param[in] dutycycle Unsigned int32. I2C duty cycle @ref i2c_duty_cycle.
*/
void i2c_set_dutycycle(uint32_t i2c, uint32_t dutycycle)
{
if (dutycycle == I2C_CCR_DUTY_DIV2) {
I2C_CCR(i2c) &= ~I2C_CCR_DUTY;
} else {
I2C_CCR(i2c) |= I2C_CCR_DUTY;
}
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Enable DMA
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_enable_dma(uint32_t i2c)
{
I2C_CR2(i2c) |= I2C_CR2_DMAEN;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Disable DMA
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_disable_dma(uint32_t i2c)
{
I2C_CR2(i2c) &= ~I2C_CR2_DMAEN;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Set DMA last transfer
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_set_dma_last_transfer(uint32_t i2c)
{
I2C_CR2(i2c) |= I2C_CR2_LAST;
}
/*---------------------------------------------------------------------------*/
/** @brief I2C Clear DMA last transfer
@param[in] i2c Unsigned int32. I2C register base address @ref i2c_reg_base.
*/
void i2c_clear_dma_last_transfer(uint32_t i2c)
{
I2C_CR2(i2c) &= ~I2C_CR2_LAST;
}
/**@}*/

View File

@ -0,0 +1,149 @@
/** @addtogroup iwdg_file
@author @htmlonly &copy; @endhtmlonly 2012 Ken Sarkies ksarkies@internode.on.net
This library supports the Independent Watchdog Timer System in the STM32F1xx
series of ARM Cortex Microcontrollers by ST Microelectronics.
The watchdog timer uses the LSI (low speed internal) clock which is low power
and continues to operate during stop and standby modes. Its frequency is
nominally 32kHz (40kHz for the STM32F1xx series) but can vary from as low
as 17kHz up to 60kHz (refer to datasheet electrical characteristics).
Note that the User Configuration option byte provides a means of automatically
enabling the IWDG timer at power on (with counter value 0xFFF). If the
relevant bit is not set, the IWDG timer must be enabled by software.
@note: Tested: CPU STM32F103RET6, Board ET-ARM Stamp STM32
*/
/*
* This file is part of the libopencm3 project.
*
* 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/iwdg.h>
#define LSI_FREQUENCY 32000
#define COUNT_LENGTH 12
#define COUNT_MASK ((1 << COUNT_LENGTH)-1)
/*---------------------------------------------------------------------------*/
/** @brief IWDG Enable Watchdog Timer
The watchdog timer is started. The timeout period defaults to 512 milliseconds
unless it has been previously defined.
*/
void iwdg_start(void)
{
IWDG_KR = IWDG_KR_START;
}
/*---------------------------------------------------------------------------*/
/** @brief IWDG Set Period in Milliseconds
The countdown period is converted into count and prescale values. The maximum
period is 32.76 seconds; values above this are truncated. Periods less than 1ms
are not supported by this library.
A delay of up to 5 clock cycles of the LSI clock (about 156 microseconds)
can occasionally occur if the prescale or preload registers are currently busy
loading a previous value.
@param[in] period uint32_t Period in milliseconds (< 32760) from a watchdog
reset until a system reset is issued.
*/
void iwdg_set_period_ms(uint32_t period)
{
uint32_t count, prescale, reload, exponent;
/* Set the count to represent ticks of the 32kHz LSI clock */
count = (period << 5);
/* Strip off the first 12 bits to get the prescale value required */
prescale = (count >> 12);
if (prescale > 256) {
exponent = IWDG_PR_DIV256; reload = COUNT_MASK;
} else if (prescale > 128) {
exponent = IWDG_PR_DIV256; reload = (count >> 8);
} else if (prescale > 64) {
exponent = IWDG_PR_DIV128; reload = (count >> 7);
} else if (prescale > 32) {
exponent = IWDG_PR_DIV64; reload = (count >> 6);
} else if (prescale > 16) {
exponent = IWDG_PR_DIV32; reload = (count >> 5);
} else if (prescale > 8) {
exponent = IWDG_PR_DIV16; reload = (count >> 4);
} else if (prescale > 4) {
exponent = IWDG_PR_DIV8; reload = (count >> 3);
} else {
exponent = IWDG_PR_DIV4; reload = (count >> 2);
}
/* Avoid the undefined situation of a zero count */
if (count == 0) {
count = 1;
}
while (iwdg_prescaler_busy());
IWDG_KR = IWDG_KR_UNLOCK;
IWDG_PR = exponent;
while (iwdg_reload_busy());
IWDG_KR = IWDG_KR_UNLOCK;
IWDG_RLR = (reload & COUNT_MASK);
}
/*---------------------------------------------------------------------------*/
/** @brief IWDG Get Reload Register Status
@returns boolean: TRUE if the reload register is busy and unavailable for
loading a new count value.
*/
bool iwdg_reload_busy(void)
{
return IWDG_SR & IWDG_SR_RVU;
}
/*---------------------------------------------------------------------------*/
/** @brief IWDG Get Prescaler Register Status
@returns boolean: TRUE if the prescaler register is busy and unavailable for
loading a new period value.
*/
bool iwdg_prescaler_busy(void)
{
return IWDG_SR & IWDG_SR_PVU;
}
/*---------------------------------------------------------------------------*/
/** @brief IWDG reset Watchdog Timer
The watchdog timer is reset. The counter restarts from the value in the reload
register.
*/
void iwdg_reset(void)
{
IWDG_KR = IWDG_KR_RESET;
}
/**@}*/

View File

@ -0,0 +1,205 @@
/** @addtogroup pwr_file PWR
@author @htmlonly &copy; @endhtmlonly 2012
Ken Sarkies <ksarkies@internode.on.net>
*/
/*
* 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/pwr.h>
/*---------------------------------------------------------------------------*/
/** @brief Disable Backup Domain Write Protection.
This allows backup domain registers to be changed. These registers are write
protected after a reset.
*/
void pwr_disable_backup_domain_write_protect(void)
{
PWR_CR |= PWR_CR_DBP;
}
/*---------------------------------------------------------------------------*/
/** @brief Re-enable Backup Domain Write Protection.
This protects backup domain registers from inadvertent change.
*/
void pwr_enable_backup_domain_write_protect(void)
{
PWR_CR &= ~PWR_CR_DBP;
}
/*---------------------------------------------------------------------------*/
/** @brief Enable Power Voltage Detector.
This provides voltage level threshold detection. The result of detection is
provided in the power voltage detector output flag (see @ref pwr_voltage_high)
or by setting the EXTI16 interrupt (see datasheet for configuration details).
@param[in] pvd_level uint32_t. Taken from @ref pwr_pls.
*/
void pwr_enable_power_voltage_detect(uint32_t pvd_level)
{
PWR_CR &= ~PWR_CR_PLS_MASK;
PWR_CR |= (PWR_CR_PVDE | pvd_level);
}
/*---------------------------------------------------------------------------*/
/** @brief Disable Power Voltage Detector.
*/
void pwr_disable_power_voltage_detect(void)
{
PWR_CR &= ~PWR_CR_PVDE;
}
/*---------------------------------------------------------------------------*/
/** @brief Clear the Standby Flag.
This is set when the processor returns from a standby mode.
*/
void pwr_clear_standby_flag(void)
{
PWR_CR |= PWR_CR_CSBF;
}
/*---------------------------------------------------------------------------*/
/** @brief Clear the Wakeup Flag.
This is set when the processor receives a wakeup signal.
*/
void pwr_clear_wakeup_flag(void)
{
PWR_CR |= PWR_CR_CWUF;
}
/*---------------------------------------------------------------------------*/
/** @brief Set Standby Mode in Deep Sleep.
*/
void pwr_set_standby_mode(void)
{
PWR_CR |= PWR_CR_PDDS;
}
/*---------------------------------------------------------------------------*/
/** @brief Set Stop Mode in Deep Sleep.
*/
void pwr_set_stop_mode(void)
{
PWR_CR &= ~PWR_CR_PDDS;
}
/*---------------------------------------------------------------------------*/
/** @brief Voltage Regulator On in Stop Mode.
*/
void pwr_voltage_regulator_on_in_stop(void)
{
PWR_CR &= ~PWR_CR_LPDS;
}
/*---------------------------------------------------------------------------*/
/** @brief Voltage Regulator Low Power in Stop Mode.
*/
void pwr_voltage_regulator_low_power_in_stop(void)
{
PWR_CR |= PWR_CR_LPDS;
}
/*---------------------------------------------------------------------------*/
/** @brief Enable Wakeup Pin.
The wakeup pin is used for waking the processor from standby mode.
*/
void pwr_enable_wakeup_pin(void)
{
PWR_CSR |= PWR_CSR_EWUP;
}
/*---------------------------------------------------------------------------*/
/** @brief Release Wakeup Pin.
The wakeup pin is used for general purpose I/O.
*/
void pwr_disable_wakeup_pin(void)
{
PWR_CSR &= ~PWR_CSR_EWUP;
}
/*---------------------------------------------------------------------------*/
/** @brief Get Voltage Detector Output.
The voltage detector threshold must be set when the power voltage detector is
enabled, see @ref pwr_enable_power_voltage_detect.
@returns boolean: TRUE if the power voltage is above the preset voltage
threshold.
*/
bool pwr_voltage_high(void)
{
return PWR_CSR & PWR_CSR_PVDO;
}
/*---------------------------------------------------------------------------*/
/** @brief Get Standby Flag.
The standby flag is set when the processor returns from a standby state. It is
cleared by software (see @ref pwr_clear_standby_flag).
@returns boolean: TRUE if the processor was in standby state.
*/
bool pwr_get_standby_flag(void)
{
return PWR_CSR & PWR_CSR_SBF;
}
/*---------------------------------------------------------------------------*/
/** @brief Get Wakeup Flag.
The wakeup flag is set when a wakeup event has been received. It is
cleared by software (see @ref pwr_clear_wakeup_flag).
@returns boolean: TRUE if a wakeup event was received.
*/
bool pwr_get_wakeup_flag(void)
{
return PWR_CSR & PWR_CSR_WUF;
}
/**@}*/

View File

@ -0,0 +1,123 @@
/** @addtogroup rtc_file
@author @htmlonly &copy; @endhtmlonly 2012 Karl Palsson <karlp@tweak.net.au>
*/
/*
* This file is part of the libopencm3 project.
*
* 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/>.
*/
/**@{*/
#include <libopencm3/stm32/rtc.h>
/*---------------------------------------------------------------------------*/
/** @brief Set RTC prescalars.
This sets the RTC synchronous and asynchronous prescalars.
*/
void rtc_set_prescaler(uint32_t sync, uint32_t async)
{
/*
* Even if only one of the two fields needs to be changed,
* 2 separate write accesses must be performed to the RTC_PRER register.
*/
RTC_PRER = (sync & RTC_PRER_PREDIV_S_MASK);
RTC_PRER |= (async << RTC_PRER_PREDIV_A_SHIFT);
}
/*---------------------------------------------------------------------------*/
/** @brief Wait for RTC registers to be synchronised with the APB1 bus
Time and Date are accessed through shadow registers which must be synchronized
*/
void rtc_wait_for_synchro(void)
{
/* Unlock RTC registers */
RTC_WPR = 0xca;
RTC_WPR = 0x53;
RTC_ISR &= ~(RTC_ISR_RSF);
while (!(RTC_ISR & RTC_ISR_RSF));
/* disable write protection again */
RTC_WPR = 0xff;
}
/*---------------------------------------------------------------------------*/
/** @brief Unlock write access to the RTC registers
*/
void rtc_unlock(void)
{
RTC_WPR = 0xca;
RTC_WPR = 0x53;
}
/*---------------------------------------------------------------------------*/
/** @brief Lock write access to the RTC registers
*/
void rtc_lock(void)
{
RTC_WPR = 0xff;
}
/*---------------------------------------------------------------------------*/
/** @brief Sets the wakeup time auto-reload value
*/
void rtc_set_wakeup_time(uint16_t wkup_time, uint8_t rtc_cr_wucksel)
{
/* FTFM:
* The following sequence is required to configure or change the wakeup
* timer auto-reload value (WUT[15:0] in RTC_WUTR):
* 1. Clear WUTE in RTC_CR to disable the wakeup timer.
*/
RTC_CR &= ~RTC_CR_WUTE;
/* 2. Poll WUTWF until it is set in RTC_ISR to make sure the access to
* wakeup auto-reload counter and to WUCKSEL[2:0] bits is allowed.
* It takes around 2 RTCCLK clock cycles (due to clock
* synchronization).
*/
while (!((RTC_ISR) & (RTC_ISR_WUTWF)));
/* 3. Program the wakeup auto-reload value WUT[15:0], and the wakeup
* clock selection (WUCKSEL[2:0] bits in RTC_CR).Set WUTE in RTC_CR
* to enable the timer again. The wakeup timer restarts
* down-counting.
*/
RTC_WUTR = wkup_time;
RTC_CR |= (rtc_cr_wucksel << RTC_CR_WUCLKSEL_SHIFT);
RTC_CR |= RTC_CR_WUTE;
}
/*---------------------------------------------------------------------------*/
/** @brief Clears the wakeup flag
@details This function should be called first in the rtc_wkup_isr()
*/
void rtc_clear_wakeup_flag(void)
{
RTC_ISR &= ~RTC_ISR_WUTF;
}
/**@}*/

View File

@ -0,0 +1,698 @@
/** @addtogroup spi_file
@author @htmlonly &copy; @endhtmlonly 2009
Uwe Hermann <uwe@hermann-uwe.de>
@author @htmlonly &copy; @endhtmlonly 2012
Ken Sarkies <ksarkies@internode.on.net>
Devices can have up to three SPI peripherals. The common 4-wire full-duplex
mode of operation is supported, along with 3-wire variants using unidirectional
communication modes or half-duplex bidirectional communication. A variety of
options allows many of the SPI variants to be supported. Multimaster operation
is also supported. A CRC can be generated and checked in hardware.
@note Some JTAG pins need to be remapped if SPI is to be used.
@note The I2S protocol shares the SPI hardware so the two protocols cannot be
used at the same time on the same peripheral.
Example: 1Mbps, positive clock polarity, leading edge trigger, 8-bit words,
LSB first.
@code
spi_init_master(SPI1, 1000000, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,
SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT,
SPI_CR1_LSBFIRST);
spi_write(SPI1, 0x55); // 8-bit write
spi_write(SPI1, 0xaa88); // 16-bit write
reg8 = spi_read(SPI1); // 8-bit read
reg16 = spi_read(SPI1); // 16-bit read
@endcode
@todo need additional functions to aid ISRs in retrieving status
*/
/*
* 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/>.
*/
#include <libopencm3/stm32/spi.h>
#include <libopencm3/stm32/rcc.h>
/*
* SPI and I2S code.
*
* Examples:
* spi_init_master(SPI1, 1000000, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,
* SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT,
* SPI_CR1_LSBFIRST);
* spi_write(SPI1, 0x55); // 8-bit write
* spi_write(SPI1, 0xaa88); // 16-bit write
* reg8 = spi_read(SPI1); // 8-bit read
* reg16 = spi_read(SPI1); // 16-bit read
*/
/**@{*/
/*---------------------------------------------------------------------------*/
/** @brief SPI Reset.
The SPI peripheral and all its associated configuration registers are placed in
the reset condition. The reset is effected via the RCC peripheral reset system.
@param[in] spi_peripheral Unsigned int32. SPI peripheral identifier @ref
spi_reg_base.
*/
void spi_reset(uint32_t spi_peripheral)
{
/* there is another way of resetting mechanism on F0. It will be extended to all
families of stm32 and this function will be deprecated and deleted in the
future.*/
#if !defined(STM32F0)
switch (spi_peripheral) {
case SPI1:
rcc_peripheral_reset(&RCC_APB2RSTR, RCC_APB2RSTR_SPI1RST);
rcc_peripheral_clear_reset(&RCC_APB2RSTR, RCC_APB2RSTR_SPI1RST);
break;
case SPI2:
rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_SPI2RST);
rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_SPI2RST);
break;
#if defined(STM32F1) || defined(STM32F2) || defined(STM32F3) || defined(STM32F4)
case SPI3:
rcc_peripheral_reset(&RCC_APB1RSTR, RCC_APB1RSTR_SPI3RST);
rcc_peripheral_clear_reset(&RCC_APB1RSTR, RCC_APB1RSTR_SPI3RST);
break;
#endif
}
#endif
}
/* TODO: Error handling? */
/*---------------------------------------------------------------------------*/
/** @brief SPI Enable.
The SPI peripheral is enabled.
@todo Error handling?
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_enable(uint32_t spi)
{
SPI_CR1(spi) |= SPI_CR1_SPE; /* Enable SPI. */
}
/* TODO: Error handling? */
/*---------------------------------------------------------------------------*/
/** @brief SPI Disable.
The SPI peripheral is disabled.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_disable(uint32_t spi)
{
uint32_t reg32;
reg32 = SPI_CR1(spi);
reg32 &= ~(SPI_CR1_SPE); /* Disable SPI. */
SPI_CR1(spi) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Clean Disable.
Disable the SPI peripheral according to the procedure in section 23.3.8 of the
reference manual. This prevents corruption of any ongoing transfers and
prevents the BSY flag from becoming unreliable.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
@returns data Unsigned int16. 8 or 16 bit data from final read.
*/
uint16_t spi_clean_disable(uint32_t spi)
{
/* Wait to receive last data */
while (!(SPI_SR(spi) & SPI_SR_RXNE));
uint16_t data = SPI_DR(spi);
/* Wait to transmit last data */
while (!(SPI_SR(spi) & SPI_SR_TXE));
/* Wait until not busy */
while (SPI_SR(spi) & SPI_SR_BSY);
SPI_CR1(spi) &= ~SPI_CR1_SPE;
return data;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Data Write.
Data is written to the SPI interface.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
@param[in] data Unsigned int16. 8 or 16 bit data to be written.
*/
void spi_write(uint32_t spi, uint16_t data)
{
/* Write data (8 or 16 bits, depending on DFF) into DR. */
SPI_DR(spi) = data;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Data Write with Blocking.
Data is written to the SPI interface after the previous write transfer has
finished.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
@param[in] data Unsigned int16. 8 or 16 bit data to be written.
*/
void spi_send(uint32_t spi, uint16_t data)
{
/* Wait for transfer finished. */
while (!(SPI_SR(spi) & SPI_SR_TXE));
/* Write data (8 or 16 bits, depending on DFF) into DR. */
SPI_DR(spi) = data;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Data Read.
Data is read from the SPI interface after the incoming transfer has finished.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
@returns data Unsigned int16. 8 or 16 bit data.
*/
uint16_t spi_read(uint32_t spi)
{
/* Wait for transfer finished. */
while (!(SPI_SR(spi) & SPI_SR_RXNE));
/* Read the data (8 or 16 bits, depending on DFF bit) from DR. */
return SPI_DR(spi);
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Data Write and Read Exchange.
Data is written to the SPI interface, then a read is done after the incoming
transfer has finished.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
@param[in] data Unsigned int16. 8 or 16 bit data to be written.
@returns data Unsigned int16. 8 or 16 bit data.
*/
uint16_t spi_xfer(uint32_t spi, uint16_t data)
{
spi_write(spi, data);
/* Wait for transfer finished. */
while (!(SPI_SR(spi) & SPI_SR_RXNE));
/* Read the data (8 or 16 bits, depending on DFF bit) from DR. */
return SPI_DR(spi);
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set Bidirectional Simplex Mode.
The SPI peripheral is set for bidirectional transfers in two-wire simplex mode
(using a clock wire and a bidirectional data wire).
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_bidirectional_mode(uint32_t spi)
{
SPI_CR1(spi) |= SPI_CR1_BIDIMODE;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set Unidirectional Mode.
The SPI peripheral is set for unidirectional transfers. This is used in full
duplex mode or when the SPI is placed in two-wire simplex mode that uses a
clock wire and a unidirectional data wire.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_unidirectional_mode(uint32_t spi)
{
SPI_CR1(spi) &= ~SPI_CR1_BIDIMODE;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set Bidirectional Simplex Receive Only Mode.
The SPI peripheral is set for bidirectional transfers in two-wire simplex mode
(using a clock wire and a bidirectional data wire), and is placed in a receive
state.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_bidirectional_receive_only_mode(uint32_t spi)
{
SPI_CR1(spi) |= SPI_CR1_BIDIMODE;
SPI_CR1(spi) &= ~SPI_CR1_BIDIOE;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set Bidirectional Simplex Receive Only Mode.
The SPI peripheral is set for bidirectional transfers in two-wire simplex mode
(using a clock wire and a bidirectional data wire), and is placed in a transmit
state.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_bidirectional_transmit_only_mode(uint32_t spi)
{
SPI_CR1(spi) |= SPI_CR1_BIDIMODE;
SPI_CR1(spi) |= SPI_CR1_BIDIOE;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Enable the CRC.
The SPI peripheral is set to use a CRC field for transmit and receive.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_enable_crc(uint32_t spi)
{
SPI_CR1(spi) |= SPI_CR1_CRCEN;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Disable the CRC.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_disable_crc(uint32_t spi)
{
SPI_CR1(spi) &= ~SPI_CR1_CRCEN;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Next Transmit is a Data Word
The next transmission to take place is a data word from the transmit buffer.
This must be called before transmission to distinguish between sending
of a data or CRC word.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_next_tx_from_buffer(uint32_t spi)
{
SPI_CR1(spi) &= ~SPI_CR1_CRCNEXT;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Next Transmit is a CRC Word
The next transmission to take place is a crc word from the hardware crc unit.
This must be called before transmission to distinguish between sending
of a data or CRC word.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_next_tx_from_crc(uint32_t spi)
{
SPI_CR1(spi) |= SPI_CR1_CRCNEXT;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set Full Duplex (3-wire) Mode
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_full_duplex_mode(uint32_t spi)
{
SPI_CR1(spi) &= ~SPI_CR1_RXONLY;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set Receive Only Mode for Simplex (2-wire) Unidirectional
Transfers
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_receive_only_mode(uint32_t spi)
{
SPI_CR1(spi) |= SPI_CR1_RXONLY;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Enable Slave Management by Hardware
In slave mode the NSS hardware input is used as a select enable for the slave.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_disable_software_slave_management(uint32_t spi)
{
SPI_CR1(spi) &= ~SPI_CR1_SSM;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Enable Slave Management by Software
In slave mode the NSS hardware input is replaced by an internal software
enable/disable of the slave (@ref spi_set_nss_high).
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_enable_software_slave_management(uint32_t spi)
{
SPI_CR1(spi) |= SPI_CR1_SSM;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set the Software NSS Signal High
In slave mode, and only when software slave management is used, this replaces
the NSS signal with a slave select enable signal.
@todo these should perhaps be combined with an SSM enable as it is meaningless
otherwise
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_nss_high(uint32_t spi)
{
SPI_CR1(spi) |= SPI_CR1_SSI;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set the Software NSS Signal Low
In slave mode, and only when software slave management is used, this replaces
the NSS signal with a slave select disable signal.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_nss_low(uint32_t spi)
{
SPI_CR1(spi) &= ~SPI_CR1_SSI;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set to Send LSB First
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_send_lsb_first(uint32_t spi)
{
SPI_CR1(spi) |= SPI_CR1_LSBFIRST;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set to Send MSB First
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_send_msb_first(uint32_t spi)
{
SPI_CR1(spi) &= ~SPI_CR1_LSBFIRST;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set the Baudrate Prescaler
@todo Why is this specification different to the spi_init_master baudrate
values?
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
@param[in] baudrate Unsigned int8. Baudrate prescale value @ref spi_br_pre.
*/
void spi_set_baudrate_prescaler(uint32_t spi, uint8_t baudrate)
{
uint32_t reg32;
if (baudrate > 7) {
return;
}
reg32 = (SPI_CR1(spi) & 0xffc7); /* Clear bits [5:3]. */
reg32 |= (baudrate << 3);
SPI_CR1(spi) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set to Master Mode
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_master_mode(uint32_t spi)
{
SPI_CR1(spi) |= SPI_CR1_MSTR;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set to Slave Mode
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_slave_mode(uint32_t spi)
{
SPI_CR1(spi) &= ~SPI_CR1_MSTR;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set the Clock Polarity to High when Idle
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_clock_polarity_1(uint32_t spi)
{
SPI_CR1(spi) |= SPI_CR1_CPOL;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set the Clock Polarity to Low when Idle
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_clock_polarity_0(uint32_t spi)
{
SPI_CR1(spi) &= ~SPI_CR1_CPOL;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set the Clock Phase to Capture on Trailing Edge
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_clock_phase_1(uint32_t spi)
{
SPI_CR1(spi) |= SPI_CR1_CPHA;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set the Clock Phase to Capture on Leading Edge
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_clock_phase_0(uint32_t spi)
{
SPI_CR1(spi) &= ~SPI_CR1_CPHA;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Enable the Transmit Buffer Empty Interrupt
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_enable_tx_buffer_empty_interrupt(uint32_t spi)
{
SPI_CR2(spi) |= SPI_CR2_TXEIE;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Disable the Transmit Buffer Empty Interrupt
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_disable_tx_buffer_empty_interrupt(uint32_t spi)
{
SPI_CR2(spi) &= ~SPI_CR2_TXEIE;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Enable the Receive Buffer Ready Interrupt
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_enable_rx_buffer_not_empty_interrupt(uint32_t spi)
{
SPI_CR2(spi) |= SPI_CR2_RXNEIE;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Disable the Receive Buffer Ready Interrupt
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_disable_rx_buffer_not_empty_interrupt(uint32_t spi)
{
SPI_CR2(spi) &= ~SPI_CR2_RXNEIE;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Enable the Error Interrupt
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_enable_error_interrupt(uint32_t spi)
{
SPI_CR2(spi) |= SPI_CR2_ERRIE;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Disable the Error Interrupt
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_disable_error_interrupt(uint32_t spi)
{
SPI_CR2(spi) &= ~SPI_CR2_ERRIE;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set the NSS Pin as an Output
Normally used in master mode to allows the master to place all devices on the
SPI bus into slave mode. Multimaster mode is not possible.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_enable_ss_output(uint32_t spi)
{
SPI_CR2(spi) |= SPI_CR2_SSOE;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set the NSS Pin as an Input
In master mode this allows the master to sense the presence of other masters. If
NSS is then pulled low the master is placed into slave mode. In slave mode NSS
becomes a slave enable.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_disable_ss_output(uint32_t spi)
{
SPI_CR2(spi) &= ~SPI_CR2_SSOE;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Enable Transmit Transfers via DMA
This allows transmissions to proceed unattended using DMA to move data to the
transmit buffer as it becomes available. The DMA channels provided for each
SPI peripheral are given in the Technical Manual DMA section.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_enable_tx_dma(uint32_t spi)
{
SPI_CR2(spi) |= SPI_CR2_TXDMAEN;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Disable Transmit Transfers via DMA
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_disable_tx_dma(uint32_t spi)
{
SPI_CR2(spi) &= ~SPI_CR2_TXDMAEN;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Enable Receive Transfers via DMA
This allows received data streams to proceed unattended using DMA to move data
from the receive buffer as data becomes available. The DMA channels provided
for each SPI peripheral are given in the Technical Manual DMA section.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_enable_rx_dma(uint32_t spi)
{
SPI_CR2(spi) |= SPI_CR2_RXDMAEN;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Disable Receive Transfers via DMA
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_disable_rx_dma(uint32_t spi)
{
SPI_CR2(spi) &= ~SPI_CR2_RXDMAEN;
}
/**@}*/

View File

@ -0,0 +1,137 @@
/** @addtogroup spi_file
@author @htmlonly &copy; @endhtmlonly 2009
Uwe Hermann <uwe@hermann-uwe.de>
@author @htmlonly &copy; @endhtmlonly 2012
Ken Sarkies <ksarkies@internode.on.net>
Devices can have up to three SPI peripherals. The common 4-wire full-duplex
mode of operation is supported, along with 3-wire variants using unidirectional
communication modes or half-duplex bidirectional communication. A variety of
options allows many of the SPI variants to be supported. Multimaster operation
is also supported. A CRC can be generated and checked in hardware.
@note Some JTAG pins need to be remapped if SPI is to be used.
@note The I2S protocol shares the SPI hardware so the two protocols cannot be
used at the same time on the same peripheral.
Example: 1Mbps, positive clock polarity, leading edge trigger, 8-bit words,
LSB first.
@code
spi_init_master(SPI1, 1000000, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,
SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT,
SPI_CR1_LSBFIRST);
spi_write(SPI1, 0x55); // 8-bit write
spi_write(SPI1, 0xaa88); // 16-bit write
reg8 = spi_read(SPI1); // 8-bit read
reg16 = spi_read(SPI1); // 16-bit read
@endcode
@todo need additional functions to aid ISRs in retrieving status
*/
/*
* 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/>.
*/
#include <libopencm3/stm32/spi.h>
#include <libopencm3/stm32/rcc.h>
/*
* SPI and I2S code.
*
* Examples:
* spi_init_master(SPI1, 1000000, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,
* SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT,
* SPI_CR1_LSBFIRST);
* spi_write(SPI1, 0x55); // 8-bit write
* spi_write(SPI1, 0xaa88); // 16-bit write
* reg8 = spi_read(SPI1); // 8-bit read
* reg16 = spi_read(SPI1); // 16-bit read
*/
/**@{*/
/*---------------------------------------------------------------------------*/
/** @brief Configure the SPI as Master.
The SPI peripheral is configured as a master with communication parameters
baudrate, data format 8/16 bits, frame format lsb/msb first, clock polarity
and phase. The SPI enable, CRC enable and CRC next controls are not affected.
These must be controlled separately.
@todo NSS pin handling.
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
@param[in] br Unsigned int32. Baudrate @ref spi_baudrate.
@param[in] cpol Unsigned int32. Clock polarity @ref spi_cpol.
@param[in] cpha Unsigned int32. Clock Phase @ref spi_cpha.
@param[in] dff Unsigned int32. Data frame format 8/16 bits @ref spi_dff.
@param[in] lsbfirst Unsigned int32. Frame format lsb/msb first @ref
spi_lsbfirst.
@returns int. Error code.
*/
int spi_init_master(uint32_t spi, uint32_t br, uint32_t cpol, uint32_t cpha,
uint32_t dff, uint32_t lsbfirst)
{
uint32_t reg32 = SPI_CR1(spi);
/* Reset all bits omitting SPE, CRCEN and CRCNEXT bits. */
reg32 &= SPI_CR1_SPE | SPI_CR1_CRCEN | SPI_CR1_CRCNEXT;
reg32 |= SPI_CR1_MSTR; /* Configure SPI as master. */
reg32 |= br; /* Set baud rate bits. */
reg32 |= cpol; /* Set CPOL value. */
reg32 |= cpha; /* Set CPHA value. */
reg32 |= dff; /* Set data format (8 or 16 bits). */
reg32 |= lsbfirst; /* Set frame format (LSB- or MSB-first). */
/* TODO: NSS pin handling. */
SPI_CR1(spi) = reg32;
return 0; /* TODO */
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set Data Frame Format to 8 bits
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_dff_8bit(uint32_t spi)
{
SPI_CR1(spi) &= ~SPI_CR1_DFF;
}
/*---------------------------------------------------------------------------*/
/** @brief SPI Set Data Frame Format to 16 bits
@param[in] spi Unsigned int32. SPI peripheral identifier @ref spi_reg_base.
*/
void spi_set_dff_16bit(uint32_t spi)
{
SPI_CR1(spi) |= SPI_CR1_DFF;
}
/**@}*/

View File

@ -0,0 +1,58 @@
/** @addtogroup timer_file
*/
/*
* 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/>.
*/
/**@{*/
#include <libopencm3/stm32/timer.h>
/*---------------------------------------------------------------------------*/
/** @brief Set Input Polarity
The timer channel must be set to input capture mode.
@param[in] timer_peripheral Unsigned int32. Timer register address base
@param[in] ic ::tim_ic_id. Input Capture channel designator.
@param[in] pol ::tim_ic_pol. Input Capture polarity control.
*/
void timer_ic_set_polarity(uint32_t timer_peripheral, enum tim_ic_id ic,
enum tim_ic_pol pol)
{
/* Clear CCxP and CCxNP to zero. For both edge trigger both fields are
* set. Case 10 is invalid.
*/
TIM_CCER(timer_peripheral) &= ~(0x6 << (ic * 4));
switch (pol) {
case TIM_IC_RISING: /* 00 */
break;
case TIM_IC_BOTH: /* 11 */
TIM_CCER(timer_peripheral) |= (0x6 << (ic * 4));
break;
case TIM_IC_FALLING: /* 01 */
TIM_CCER(timer_peripheral) |= (0x2 << (ic * 4));
}
}
/**@}*/

View File

@ -0,0 +1,53 @@
/** @addtogroup timer_file
*/
/*
* 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/>.
*/
/**@{*/
#include <libopencm3/stm32/timer.h>
/*---------------------------------------------------------------------------*/
/** @brief Set Timer Option
Set timer options register on TIM2 or TIM5, used for trigger remapping on TIM2,
and similarly for TIM5 for oscillator calibration purposes.
@param[in] timer_peripheral Unsigned int32. Timer register address base
@returns Unsigned int32. Option flags TIM2: @ref tim2_opt_trigger_remap, TIM5:
@ref tim5_opt_trigger_remap.
*/
void timer_set_option(uint32_t timer_peripheral, uint32_t 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

@ -0,0 +1,367 @@
/** @addtogroup usart_file
@author @htmlonly &copy; @endhtmlonly 2009 Uwe Hermann <uwe@hermann-uwe.de>
This library supports the USART/UART in the STM32F series
of ARM Cortex Microcontrollers by ST Microelectronics.
Devices can have up to 3 USARTs and 2 UARTs.
*/
/*
* 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/>.
*/
/**@{*/
#include <libopencm3/stm32/usart.h>
#include <libopencm3/stm32/rcc.h>
/*---------------------------------------------------------------------------*/
/** @brief USART Set Baudrate.
The baud rate is computed from the APB high-speed prescaler clock (for
USART1/6) or the APB low-speed prescaler clock (for other USARTs). These values
must be correctly set before calling this function (refer to the
rcc_clock_setup-* functions in RCC).
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
@param[in] baud unsigned 32 bit. Baud rate specified in Hz.
*/
void usart_set_baudrate(uint32_t usart, uint32_t baud)
{
uint32_t clock = rcc_ppre1_frequency;
#if defined STM32F2 || defined STM32F4
if ((usart == USART1) ||
(usart == USART6)) {
clock = rcc_ppre2_frequency;
}
#else
if (usart == USART1) {
clock = rcc_ppre2_frequency;
}
#endif
/*
* Yes it is as simple as that. The reference manual is
* talking about fractional calculation but it seems to be only
* marketting babble to sound awesome. It is nothing else but a
* simple divider to generate the correct baudrate.
*
* Note: We round() the value rather than floor()ing it, for more
* accurate divisor selection.
*/
USART_BRR(usart) = ((2 * clock) + baud) / (2 * baud);
}
/*---------------------------------------------------------------------------*/
/** @brief USART Set Word Length.
The word length is set to 8 or 9 bits. Note that the last bit will be a parity
bit if parity is enabled, in which case the data length will be 7 or 8 bits
respectively.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
@param[in] bits unsigned 32 bit. Word length in bits 8 or 9.
*/
void usart_set_databits(uint32_t usart, uint32_t bits)
{
if (bits == 8) {
USART_CR1(usart) &= ~USART_CR1_M; /* 8 data bits */
} else {
USART_CR1(usart) |= USART_CR1_M; /* 9 data bits */
}
}
/*---------------------------------------------------------------------------*/
/** @brief USART Set Stop Bit(s).
The stop bits are specified as 0.5, 1, 1.5 or 2.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
@param[in] stopbits unsigned 32 bit. Stop bits @ref usart_cr2_stopbits.
*/
void usart_set_stopbits(uint32_t usart, uint32_t stopbits)
{
uint32_t reg32;
reg32 = USART_CR2(usart);
reg32 = (reg32 & ~USART_CR2_STOPBITS_MASK) | stopbits;
USART_CR2(usart) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Set Parity.
The parity bit can be selected as none, even or odd.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
@param[in] parity unsigned 32 bit. Parity @ref usart_cr1_parity.
*/
void usart_set_parity(uint32_t usart, uint32_t parity)
{
uint32_t reg32;
reg32 = USART_CR1(usart);
reg32 = (reg32 & ~USART_PARITY_MASK) | parity;
USART_CR1(usart) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Set Rx/Tx Mode.
The mode can be selected as Rx only, Tx only or Rx+Tx.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
@param[in] mode unsigned 32 bit. Mode @ref usart_cr1_mode.
*/
void usart_set_mode(uint32_t usart, uint32_t mode)
{
uint32_t reg32;
reg32 = USART_CR1(usart);
reg32 = (reg32 & ~USART_MODE_MASK) | mode;
USART_CR1(usart) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Set Hardware Flow Control.
The flow control bit can be selected as none, RTS, CTS or RTS+CTS.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
@param[in] flowcontrol unsigned 32 bit. Flowcontrol @ref usart_cr3_flowcontrol.
*/
void usart_set_flow_control(uint32_t usart, uint32_t flowcontrol)
{
uint32_t reg32;
reg32 = USART_CR3(usart);
reg32 = (reg32 & ~USART_FLOWCONTROL_MASK) | flowcontrol;
USART_CR3(usart) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Enable.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_enable(uint32_t usart)
{
USART_CR1(usart) |= USART_CR1_UE;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Disable.
At the end of the current frame, the USART is disabled to reduce power.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_disable(uint32_t usart)
{
USART_CR1(usart) &= ~USART_CR1_UE;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Send Data Word with Blocking
Blocks until the transmit data buffer becomes empty then writes the next data
word for transmission.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
@param[in] data unsigned 16 bit.
*/
void usart_send_blocking(uint32_t usart, uint16_t data)
{
usart_wait_send_ready(usart);
usart_send(usart, data);
}
/*---------------------------------------------------------------------------*/
/** @brief USART Read a Received Data Word with Blocking.
Wait until a data word has been received then return the word.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
@returns unsigned 16 bit data word.
*/
uint16_t usart_recv_blocking(uint32_t usart)
{
usart_wait_recv_ready(usart);
return usart_recv(usart);
}
/*---------------------------------------------------------------------------*/
/** @brief USART Receiver DMA Enable.
DMA is available on:
@li USART1 Rx DMA1 channel 5.
@li USART2 Rx DMA1 channel 6.
@li USART3 Rx DMA1 channel 3.
@li UART4 Rx DMA2 channel 3.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_enable_rx_dma(uint32_t usart)
{
USART_CR3(usart) |= USART_CR3_DMAR;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Receiver DMA Disable.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_disable_rx_dma(uint32_t usart)
{
USART_CR3(usart) &= ~USART_CR3_DMAR;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Transmitter DMA Enable.
DMA is available on:
@li USART1 Tx DMA1 channel 4.
@li USART2 Tx DMA1 channel 7.
@li USART3 Tx DMA1 channel 2.
@li UART4 Tx DMA2 channel 5.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_enable_tx_dma(uint32_t usart)
{
USART_CR3(usart) |= USART_CR3_DMAT;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Transmitter DMA Disable.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_disable_tx_dma(uint32_t usart)
{
USART_CR3(usart) &= ~USART_CR3_DMAT;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Receiver Interrupt Enable.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_enable_rx_interrupt(uint32_t usart)
{
USART_CR1(usart) |= USART_CR1_RXNEIE;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Receiver Interrupt Disable.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_disable_rx_interrupt(uint32_t usart)
{
USART_CR1(usart) &= ~USART_CR1_RXNEIE;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Transmitter Interrupt Enable.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_enable_tx_interrupt(uint32_t usart)
{
USART_CR1(usart) |= USART_CR1_TXEIE;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Transmitter Interrupt Disable.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_disable_tx_interrupt(uint32_t usart)
{
USART_CR1(usart) &= ~USART_CR1_TXEIE;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Error Interrupt Enable.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_enable_error_interrupt(uint32_t usart)
{
USART_CR3(usart) |= USART_CR3_EIE;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Error Interrupt Disable.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_disable_error_interrupt(uint32_t usart)
{
USART_CR3(usart) &= ~USART_CR3_EIE;
}
/**@}*/

View File

@ -0,0 +1,143 @@
/** @addtogroup usart_file
@author @htmlonly &copy; @endhtmlonly 2009 Uwe Hermann <uwe@hermann-uwe.de>
This library supports the USART/UART in the STM32F series
of ARM Cortex Microcontrollers by ST Microelectronics.
Devices can have up to 3 USARTs and 2 UARTs.
*/
/*
* 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/>.
*/
/**@{*/
#include <libopencm3/stm32/usart.h>
#include <libopencm3/stm32/rcc.h>
/*---------------------------------------------------------------------------*/
/** @brief USART Send a Data Word.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
@param[in] data unsigned 16 bit.
*/
void usart_send(uint32_t usart, uint16_t data)
{
/* Send data. */
USART_DR(usart) = (data & USART_DR_MASK);
}
/*---------------------------------------------------------------------------*/
/** @brief USART Read a Received Data Word.
If parity is enabled the MSB (bit 7 or 8 depending on the word length) is the
parity bit.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
@returns unsigned 16 bit data word.
*/
uint16_t usart_recv(uint32_t usart)
{
/* Receive data. */
return USART_DR(usart) & USART_DR_MASK;
}
/*---------------------------------------------------------------------------*/
/** @brief USART Wait for Transmit Data Buffer Empty
Blocks until the transmit data buffer becomes empty and is ready to accept the
next data word.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_wait_send_ready(uint32_t usart)
{
/* Wait until the data has been transferred into the shift register. */
while ((USART_SR(usart) & USART_SR_TXE) == 0);
}
/*---------------------------------------------------------------------------*/
/** @brief USART Wait for Received Data Available
Blocks until the receive data buffer holds a valid received data word.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
*/
void usart_wait_recv_ready(uint32_t usart)
{
/* Wait until the data is ready to be received. */
while ((USART_SR(usart) & USART_SR_RXNE) == 0);
}
/*---------------------------------------------------------------------------*/
/** @brief USART Read a Status Flag.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
@param[in] flag Unsigned int32. Status register flag @ref usart_sr_flags.
@returns boolean: flag set.
*/
bool usart_get_flag(uint32_t usart, uint32_t flag)
{
return ((USART_SR(usart) & flag) != 0);
}
/*---------------------------------------------------------------------------*/
/** @brief USART Return Interrupt Source.
Returns true if the specified interrupt flag (IDLE, RXNE, TC, TXE or OE) was
set and the interrupt was enabled. If the specified flag is not an interrupt
flag, the function returns false.
@todo These are the most important interrupts likely to be used. Others
relating to LIN break, and error conditions in multibuffer communication, need
to be added for completeness.
@param[in] usart unsigned 32 bit. USART block register address base @ref
usart_reg_base
@param[in] flag Unsigned int32. Status register flag @ref usart_sr_flags.
@returns boolean: flag and interrupt enable both set.
*/
bool usart_get_interrupt_source(uint32_t usart, uint32_t flag)
{
uint32_t flag_set = (USART_SR(usart) & flag);
/* IDLE, RXNE, TC, TXE interrupts */
if ((flag >= USART_SR_IDLE) && (flag <= USART_SR_TXE)) {
return ((flag_set & USART_CR1(usart)) != 0);
/* Overrun error */
} else if (flag == USART_SR_ORE) {
return flag_set && (USART_CR3(usart) & USART_CR3_CTSIE);
}
return false;
}
/**@}*/

View File

@ -0,0 +1,60 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Karl Palsson <karlp@ŧweak.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/>.
*/
#include <libopencm3/stm32/desig.h>
uint16_t desig_get_flash_size(void)
{
return DESIG_FLASH_SIZE;
}
void desig_get_unique_id(uint32_t result[])
{
/* Could also just return a pointer to the start? read it as they wish?
*/
uint16_t bits15_0 = DESIG_UID_15_0;
uint32_t bits31_16 = DESIG_UID_31_16;
uint32_t bits63_32 = DESIG_UID_63_32;
uint32_t bits95_64 = DESIG_UID_95_64;
result[0] = bits95_64;
result[1] = bits63_32;
result[2] = bits31_16 << 16 | bits15_0;
}
void desig_get_unique_id_as_string(char *string,
unsigned int string_len)
{
int i, len;
uint8_t device_id[12];
static const char chars[] = "0123456789ABCDEF";
desig_get_unique_id((uint32_t *)device_id);
/* Each byte produces two characters */
len = (2 * sizeof(device_id) < string_len) ?
2 * sizeof(device_id) : string_len - 1;
for (i = 0; i < len; i += 2) {
string[i] = chars[(device_id[i / 2] >> 0) & 0x0F];
string[i + 1] = chars[(device_id[i / 2] >> 4) & 0x0F];
}
string[len] = '\0';
}

View File

@ -0,0 +1,46 @@
##
## This file is part of the libopencm3 project.
##
## Copyright (C) 2013 Frantisek Burian <BuFran@seznam.cz>
##
## 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_stm32f0
PREFIX ?= arm-none-eabi
#PREFIX ?= arm-elf
CC = $(PREFIX)-gcc
AR = $(PREFIX)-ar
CFLAGS = -Os -g \
-Wall -Wextra -Wimplicit-function-declaration \
-Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
-Wundef -Wshadow \
-I../../../include -fno-common \
-mcpu=cortex-m0 $(FP_FLAGS) -mthumb -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD -DSTM32F0
ARFLAGS = rcs
OBJS = flash.o rcc.o usart.o dma.o rtc.o comparator.o spi.o crc.o \
dac.o i2c.o iwdg.o pwr.o gpio.o timer.o adc.o
OBJS += gpio_common_all.o gpio_common_f0234.o crc_common_all.o \
pwr_common_all.o iwdg_common_all.o rtc_common_l1f024.o \
dma_common_l1f013.o exti_common_all.o spi_common_all.o
VPATH += ../../usb:../:../../cm3:../common
include ../../Makefile.include

View File

@ -0,0 +1,835 @@
/** @defgroup adc_file ADC
*
* @ingroup STM32F0xx
*
* @brief <b>libopencm3 STM32F0xx Analog to Digital Converters</b>
*
* based on F3 file
*
* @date 14 July 2013
*
* 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/cm3/assert.h>
#include <libopencm3/stm32/adc.h>
/**@{*/
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/**
* @defgroup adc_api_opmode ADC Operation mode API
* @ingroup adc_file
*
* @brief ADC Result API
*
*@{*/
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Continuous Conversion Mode
*
* In this mode the ADC starts a new conversion of a single channel or a channel
* group immediately following completion of the previous channel group
* conversion.
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_set_continuous_conversion_mode(uint32_t adc)
{
ADC_CFGR1(adc) |= ADC_CFGR1_CONT;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Single Conversion Mode
*
* In this mode the ADC performs a conversion of one channel or a channel group
* and stops.
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_set_single_conversion_mode(uint32_t adc)
{
ADC_CFGR1(adc) &= ~ADC_CFGR1_CONT;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Discontinuous Mode for Regular Conversions
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_enable_discontinuous_mode(uint32_t adc)
{
ADC_CFGR1(adc) |= ADC_CFGR1_DISCEN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable Discontinuous Mode for Regular Conversions
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_disable_discontinuous_mode(uint32_t adc)
{
ADC_CFGR1(adc) &= ~ADC_CFGR1_DISCEN;
}
/*---------------------------------------------------------------------------*/
/** ADC Set operation mode
*
* There are some operation modes, common for entire stm32 branch. In the text
* the braces are describing result to single trigger event. The trigger event
* is described by character T in the description. The ADC is configured to
* convert list of inputs [0, 1, 2, 3]. In Grouped modes, there is used group
* size of 2 conversions in the examples
*
* @li @c ADC_MODE_SEQUENTIAL: T(0) T(1) T(2) T(3)[EOSEQ] T(0) T(1) T(2) ...
*
* In this mode, after the trigger event a single channel is converted and the
* next channel in the list is prepared to convert on next trigger edge.
*
* @note This mode can be emulated by ADC_MODE_GROUPED with group size
* of 1. @par
*
* @li @c ADC_MODE_SCAN: T(0123)[EOSEQ] T(0123)[EOSEQ] T(0123)[EOSEQ]
*
* In this mode, after the trigger event, all channels will be converted once,
* storing results sequentially.
*
* @note The DMA must be configured properly for more than single channel to
* convert. @par
*
* @li @c ADC_MODE_SCAN_INFINITE: T(0123[EOSEQ]0123[EOSEQ]0123[EOSEQ]...)
*
* In this mode, after the trigger event, all channels from the list are
* converted. At the end of list, the conversion continues from the beginning.
*
* @note The DMA must be configured properly to operate in this mode.@par
*
* @li @c ADC_MODE_GROUPED: T(12) T(34)[EOSEQ] T(12) T(34)[EOSEQ] T(12)
*
* In this mode, after the trigger event, a specified group size of channels
* are converted. If the end of channel list occurs, the EOSEQ is generated
* and on the next trigger it wraps to the beginning.
*
* @note The DMA must be configured properly to operate on more than single
* channel conversion groups.@par
*
* @warning not all families supports all modes of operation of ADC.
*
* @par
*
*/
/*---------------------------------------------------------------------------*/
/** @brief ADC Set conversion operation mode
*
* @note on SEQUENTIAL mode, the trigger event is neccesary to start conversion.
* @par
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
* @param[in] adc ::adc_opmode. ADC operation mode (@ref adc_opmode)
*/
void adc_set_operation_mode(uint32_t adc, enum adc_opmode opmode)
{
switch (opmode) {
case ADC_MODE_SEQUENTIAL:
ADC_CFGR1(adc) &= ~ADC_CFGR1_CONT;
ADC_CFGR1(adc) |= ADC_CFGR1_DISCEN;
break;
case ADC_MODE_SCAN:
ADC_CFGR1(adc) &= ~(ADC_CFGR1_CONT | ADC_CFGR1_DISCEN);
break;
case ADC_MODE_SCAN_INFINITE:
ADC_CFGR1(adc) &= ~ADC_CFGR1_DISCEN;
ADC_CFGR1(adc) |= ADC_CFGR1_CONT;
break;
}
}
/**@}*/
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/**
* @defgroup adc_api_result ADC Result API
* @ingroup adc_file
*
* @brief ADC Result API
*
*@{*/
/*---------------------------------------------------------------------------*/
/** @brief ADC Software Triggered Conversion on Regular Channels
*
* This starts conversion on a set of defined regular channels. It is cleared
* by hardware once conversion starts.
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_start_conversion_regular(uint32_t adc)
{
/* Start conversion on regular channels. */
ADC_CR(adc) |= ADC_CR_ADSTART;
/* Wait until the ADC starts the conversion. */
while (ADC_CR(adc) & ADC_CR_ADSTART);
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Read the End-of-Conversion Flag
*
* This flag is set after all channels of a regular or injected group have been
* converted.
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
* @returns bool. End of conversion flag.
*/
bool adc_eoc(uint32_t adc)
{
return ((ADC_ISR(adc) & ADC_ISR_EOC) != 0);
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Read from the Regular Conversion Result Register
*
* The result read back is 12 bits, right or left aligned within the first
* 16 bits. For ADC1 only, the higher 16 bits will hold the result from ADC2 if
* an appropriate dual mode has been set @see adc_set_dual_mode.
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
* @returns Unsigned int32 conversion result.
*/
uint32_t adc_read_regular(uint32_t adc)
{
return ADC_DR(adc);
}
/**@}*/
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/**
* @defgroup adc_api_trigger ADC Trigger API
* @ingroup adc_file
*
* @brief ADC Trigger API
*
*@{*/
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable an External Trigger for Regular Channels
*
* This enables an external trigger for set of defined regular channels, and
* sets the polarity of the trigger event: rising or falling edge or both. Note
* that if the trigger polarity is zero, triggering is disabled.
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
* @param[in] trigger Unsigned int32. Trigger identifier
* @ref adc_trigger_regular
* @param[in] polarity Unsigned int32. Trigger polarity @ref
* adc_trigger_polarity_regular
*/
void adc_enable_external_trigger_regular(uint32_t adc, uint32_t trigger,
uint32_t polarity)
{
ADC_CFGR1(adc) = (ADC_CFGR1(adc) & ~ADC_CFGR1_EXTSEL) | trigger;
ADC_CFGR1(adc) = (ADC_CFGR1(adc) & ~ADC_CFGR1_EXTEN) | polarity;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable an External Trigger for Regular Channels
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_disable_external_trigger_regular(uint32_t adc)
{
ADC_CFGR1(adc) &= ~ADC_CFGR1_EXTEN;
}
/**@}*/
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/**
* @defgroup adc_api_interrupts ADC Interrupt configuration API
* @ingroup adc_file
*
* @brief ADC Interrupt configuration API
*
*@{*/
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Analog Watchdog Interrupt
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_enable_watchdog_interrupt(uint32_t adc)
{
ADC_IER(adc) |= ADC_IER_AWDIE;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable Regular End-Of-Conversion Interrupt
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_disable_watchdog_interrupt(uint32_t adc)
{
ADC_IER(adc) &= ~ADC_IER_AWDIE;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Read the Analog Watchdog Flag
*
* This flag is set when the converted voltage crosses the high or low
* thresholds.
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
* @returns bool true, if the signal is out of defined analog range.
*/
bool adc_get_watchdog_flag(uint32_t adc)
{
return ADC_ISR(adc) & ADC_ISR_AWD;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Clear Analog Watchdog Flag
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_clear_watchdog_flag(uint32_t adc)
{
ADC_ISR(adc) = ADC_ISR_AWD;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable the Overrun Interrupt
*
* The overrun interrupt is generated when data is not read from a result
* register before the next conversion is written. If DMA is enabled, all
* transfers are terminated and any conversion sequence is aborted.
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_enable_overrun_interrupt(uint32_t adc)
{
ADC_IER(adc) |= ADC_IER_OVRIE;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable the Overrun Interrupt
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_disable_overrun_interrupt(uint32_t adc)
{
ADC_IER(adc) &= ~ADC_IER_OVRIE;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Read the Overrun Flag
*
* The overrun flag is set when data is not read from a result register before
* the next conversion is written. If DMA is enabled, all transfers are
* terminated and any conversion sequence is aborted.
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
bool adc_get_overrun_flag(uint32_t adc)
{
return ADC_ISR(adc) & ADC_ISR_OVR;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Clear Overrun Flags
*
* The overrun flag is cleared. Note that if an overrun occurs, DMA is
* terminated.
* The flag must be cleared and the DMA stream and ADC reinitialised to resume
* conversions (see the reference manual).
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_clear_overrun_flag(uint32_t adc)
{
ADC_ISR(adc) = ADC_ISR_OVR;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Regular End-Of-Conversion Sequence Interrupt
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_enable_eoc_sequence_interrupt(uint32_t adc)
{
ADC_IER(adc) |= ADC_IER_EOSEQIE;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable Regular End-Of-Conversion Sequence Interrupt
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_disable_eoc_sequence_interrupt(uint32_t adc)
{
ADC_IER(adc) &= ~ADC_IER_EOSEQIE;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Read the Regular End-Of-Conversion Sequence Flag
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
bool adc_get_eoc_sequence_flag(uint32_t adc)
{
return ADC_ISR(adc) & ADC_ISR_EOSEQ;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Regular End-Of-Conversion Interrupt
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_enable_eoc_interrupt(uint32_t adc)
{
ADC_IER(adc) |= ADC_IER_EOCIE;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable Regular End-Of-Conversion Interrupt
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_disable_eoc_interrupt(uint32_t adc)
{
ADC_IER(adc) &= ~ADC_IER_EOCIE;
}
/**@}*/
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/**
* @defgroup adc_api_config ADC Basic configuration API
* @ingroup adc_file
*
* @brief ADC Basic configuration API
*
*@{*/
/*---------------------------------------------------------------------------*/
/** @brief ADC Power Off
*
* Turn off the ADC to reduce power consumption to a few microamps.
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_power_off(uint32_t adc)
{
ADC_CR(adc) &= ~ADC_CR_ADEN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Power On
*
* If the ADC is in power-down mode then it is powered up. The application
* needs to wait a time of about 3 microseconds for stabilization before using
* the ADC. If the ADC is already on this function call will have no effect.
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_power_on(uint32_t adc)
{
ADC_CR(adc) |= ADC_CR_ADEN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Set Clock Prescale
*
* The ADC clock taken from the many sources.
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
* @param[in] prescale Unsigned int32. Prescale value (@ref adc_api_clksource)
*/
void adc_set_clk_source(uint32_t adc, uint32_t source)
{
ADC_CFGR2(adc) = ((ADC_CFGR2(adc) & ~ADC_CFGR2_CKMODE) | source);
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Set a Regular Channel Conversion Sequence
*
* Define a sequence of channels to be converted as a regular group with a
* length from 1 to 18 channels. If this is called during conversion, the
* current conversion is reset and conversion begins again with the newly
* defined group.
*
* @warning This core doesn't support the random order of ADC conversions.
* The channel list must be ordered by channel number.
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
* @param[in] length Unsigned int8. Number of channels in the group.
* @param[in] channel Unsigned int8[]. Set of channels to convert, integers
* 0..18.
*/
void adc_set_regular_sequence(uint32_t adc, uint8_t length, uint8_t channel[])
{
uint32_t reg32 = 0;
uint8_t i = 0;
bool stepup = false, stepdn = false;
if (length == 0) {
ADC_CHSELR(adc) = 0;
return;
}
reg32 |= (1 << channel[0]);
for (i = 1; i < length; i++) {
reg32 |= (1 << channel[i]);
stepup |= channel[i-1] < channel[i];
stepdn |= channel[i-1] > channel[i];
}
/* Check, if the channel list is in order */
if (stepup && stepdn) {
cm3_assert_not_reached();
}
/* Update the scan direction flag */
if (stepdn) {
ADC_CFGR1(adc) |= ADC_CFGR1_SCANDIR;
} else {
ADC_CFGR1(adc) &= ~ADC_CFGR1_SCANDIR;
}
ADC_CHSELR(adc) = reg32;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Set the Sample Time for All Channels
*
* The sampling time can be selected in ADC clock cycles from 1.5 to 239.5,
* same for all channels.
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
* @param[in] time Unsigned int8. Sampling time selection (@ref adc_api_smptime)
*/
void adc_set_sample_time_on_all_channels(uint32_t adc, uint8_t time)
{
ADC_SMPR(adc) = time & ADC_SMPR_SMP;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Set Resolution
*
* ADC Resolution can be reduced from 12 bits to 10, 8 or 6 bits for a
* corresponding reduction in conversion time.
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
* @param[in] resolution Unsigned int16. Resolution value (@ref adc_api_res)
*/
void adc_set_resolution(uint32_t adc, uint16_t resolution)
{
ADC_CFGR1(adc) = (ADC_CFGR1(adc) & ~ADC_CFGR1_RES) | resolution;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Set the Data as Left Aligned
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_set_left_aligned(uint32_t adc)
{
ADC_CFGR1(adc) |= ADC_CFGR1_ALIGN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Set the Data as Right Aligned
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_set_right_aligned(uint32_t adc)
{
ADC_CFGR1(adc) &= ~ADC_CFGR1_ALIGN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable DMA Transfers
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_enable_dma(uint32_t adc)
{
ADC_CFGR1(adc) |= ADC_CFGR1_DMAEN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable DMA Transfers
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_disable_dma(uint32_t adc)
{
ADC_CFGR1(adc) &= ~ADC_CFGR1_DMAEN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable The Temperature Sensor
*
* This enables the sensor on channel 16
*/
void adc_enable_temperature_sensor(void)
{
ADC_CCR |= ADC_CCR_TSEN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable The Temperature Sensor
*
* Disabling this will reduce power consumption from the temperature sensor
* measurement.
*/
void adc_disable_temperature_sensor(void)
{
ADC_CCR &= ~ADC_CCR_TSEN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable The VRef Sensor
*
* This enables the reference voltage measurements on channel 17.
*/
void adc_enable_vref_sensor(void)
{
ADC_CCR |= ADC_CCR_VREFEN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable The VRef Sensor
*
* Disabling this will reduce power consumption from the reference voltage
* measurement.
*/
void adc_disable_vref_sensor(void)
{
ADC_CCR &= ~ADC_CCR_VREFEN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable The VBat Sensor
*
* This enables the battery voltage measurements on channel 17.
*/
void adc_enable_vbat_sensor(void)
{
ADC_CCR |= ADC_CCR_VBATEN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable The VBat Sensor
*
* Disabling this will reduce power consumption from the battery voltage
* measurement.
*/
void adc_disable_vbat_sensor(void)
{
ADC_CCR &= ~ADC_CCR_VBATEN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Start the calibration procedure
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_calibrate_start(uint32_t adc)
{
ADC_CR(adc) = ADC_CR_ADCAL;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Wait to finish the ADC calibration procedure
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_calibrate_wait_finish(uint32_t adc)
{
while (ADC_CR(adc) & ADC_CR_ADCAL);
}
/**@}*/
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/**
* @defgroup adc_api_wdg ADC Analog watchdog API
* @ingroup adc_file
*
* @brief ADC analog watchdog API definitions.
*
* The analog watchdog allows the monitoring of an analog signal between two
* threshold levels. The thresholds must be preset. Analog watchdog is disabled
* by default.
*
* @warning Comparison is done before data alignment takes place, so the
* thresholds are left-aligned.
*
* Example 1: Enable watchdog checking on all channels
*
* @code
* // in configuration
* adc_enable_analog_watchdog_on_all_channels(ADC1);
* adc_set_watchdog_high_threshold(ADC1, 0xE00);
* adc_set_watchdog_low_threshold(ADC1, 0x200);
*
* // in the main application thread
* if (adc_get_watchdog_flag(ADC1)) {
* // the converted signal is out of AWD ranges
* adc_clear_watchdog_flag(ADC1);
* }
* @endcode
*
* Example 2: Enable watchdog checking on channel 5
*
* @code
* // in configuration
* adc_enable_analog_watchdog_on_selected_channel(ADC1,5);
* adc_set_watchdog_high_threshold(ADC1, 0xE00);
* adc_set_watchdog_low_threshold(ADC1, 0x200);
*
* // in the main application thread
* if (adc_get_watchdog_flag(ADC1)) {
* // the converted signal is out of AWD ranges
* adc_clear_watchdog_flag(ADC1);
* }
* @endcode
*@{*/
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Analog Watchdog for All Channels
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_enable_analog_watchdog_on_all_channels(uint32_t adc)
{
ADC_CFGR1(adc) |= ADC_CFGR1_AWDEN;
ADC_CFGR1(adc) &= ~ADC_CFGR1_AWDSGL;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Enable Analog Watchdog for a Selected Channel
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
* @param[in] chan Unsigned int8. ADC channel number @ref adc_api_channel
*/
void adc_enable_analog_watchdog_on_selected_channel(uint32_t adc, uint8_t chan)
{
ADC_CFGR1(adc) = (ADC_CFGR1(adc) & ~ADC_CFGR1_AWDCH) | \
ADC_CFGR1_AWDCH_VAL(chan);
ADC_CFGR1(adc) |= ADC_CFGR1_AWDEN | ADC_CFGR1_AWDSGL;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Disable Analog Watchdog
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
*/
void adc_disable_analog_watchdog(uint32_t adc)
{
ADC_CFGR1(adc) &= ~ADC_CFGR1_AWDEN;
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Set Analog Watchdog Upper Threshold
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
* @param[in] threshold Unsigned int8. Upper threshold value
*/
void adc_set_watchdog_high_threshold(uint32_t adc, uint8_t threshold)
{
ADC_TR(adc) = (ADC_TR(adc) & ~ADC_TR_HT) | ADC_TR_HT_VAL(threshold);
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Set Analog Watchdog Lower Threshold
*
* @param[in] adc Unsigned int32. ADC base address (@ref adc_reg_base)
* @param[in] threshold Unsigned int8. Lower threshold value
*/
void adc_set_watchdog_low_threshold(uint32_t adc, uint8_t threshold)
{
ADC_TR(adc) = (ADC_TR(adc) & ~ADC_TR_LT) | ADC_TR_LT_VAL(threshold);
}
/**@}*/
/*---------------------------------------------------------------------------*/
/**@}*/

View File

@ -0,0 +1,61 @@
/** @defgroup comp_file COMP
*
* @ingroup STM32F0xx
*
* @brief <b>libopencm3 STM32F0xx COMP</b>
*
* @version 1.0.0
*
* @date 10 July 2013
*
* LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* 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/comparator.h>
void comp_enable(uint8_t id)
{
COMP_CSR(id) |= COMP_CSR_EN;
}
void comp_disable(uint8_t id)
{
COMP_CSR(id) &= ~COMP_CSR_EN;
}
void comp_select_input(uint8_t id, uint32_t input)
{
COMP_CSR(id) = (COMP_CSR(id) & ~COMP_CSR_INSEL) | input;
}
void comp_select_output(uint8_t id, uint32_t output)
{
COMP_CSR(id) = (COMP_CSR(id) & ~COMP_CSR_OUTSEL) | output;
}
void comp_select_hyst(uint8_t id, uint32_t hyst)
{
COMP_CSR(id) = (COMP_CSR(id) & ~COMP_CSR_HYST) | hyst;
}
void comp_select_speed(uint8_t id, uint32_t speed)
{
COMP_CSR(id) = (COMP_CSR(id) & ~COMP_CSR_SPEED) | speed;
}

View File

@ -0,0 +1,33 @@
/** @defgroup crc_file CRC
*
* @ingroup STM32F0xx
*
* @brief <b>libopencm3 STM32F0xx CRC</b>
*
* @version 1.0.0
*
* @date 11 July 2013
*
* LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* 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/crc.h>
#include <libopencm3/stm32/common/crc_common_all.h>

View File

@ -0,0 +1,33 @@
/** @defgroup dac_file DAC
*
* @ingroup STM32F0xx
*
* @brief <b>libopencm3 STM32F0xx DAC</b>
*
* @version 1.0.0
*
* @date 11 July 2013
*
* LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* 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/dac.h>
#include <libopencm3/stm32/common/dac_common_all.h>

View File

@ -0,0 +1,33 @@
/** @defgroup dma_file DMA
*
* @ingroup STM32F0xx
*
* @brief <b>libopencm3 STM32F0xx DMA</b>
*
* @version 1.0.0
*
* @date 10 July 2013
*
* LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* 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/dma.h>
#include <libopencm3/stm32/common/dma_common_l1f013.h>

View File

@ -0,0 +1,93 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2013 Frantisek Burian <BuFran@seznam.cz>
*
* 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/flash.h>
void flash_prefetch_buffer_enable(void)
{
FLASH_ACR |= FLASH_ACR_PRFTBE;
}
void flash_prefetch_buffer_disable(void)
{
FLASH_ACR &= ~FLASH_ACR_PRFTBE;
}
void flash_set_ws(uint32_t ws)
{
FLASH_ACR = (FLASH_ACR & ~FLASH_ACR_LATENCY) | ws;
}
void flash_wait_busy(void)
{
while ((FLASH_SR & FLASH_SR_BSY) != 0);
}
void flash_program_u32(uint32_t address, uint32_t data)
{
flash_wait_busy();
FLASH_CR |= FLASH_CR_PG;
MMIO16(address) = (uint16_t)data;
flash_wait_busy();
MMIO16(address + 2) = data >> 16;
flash_wait_busy();
FLASH_CR &= ~FLASH_CR_PG;
}
void flash_program_u16(uint32_t address, uint16_t data)
{
flash_wait_busy();
FLASH_CR |= FLASH_CR_PG;
MMIO16(address) = data;
flash_wait_busy();
FLASH_CR &= ~FLASH_CR_PG;
}
void flash_erase_page(uint32_t page_address)
{
flash_wait_busy();
FLASH_CR |= FLASH_CR_PER;
FLASH_AR = page_address;
FLASH_CR |= FLASH_CR_STRT;
flash_wait_busy();
FLASH_CR &= ~FLASH_CR_PER;
}
void flash_erase_all_pages(void)
{
flash_wait_busy();
FLASH_CR |= FLASH_CR_MER; /* Enable mass erase. */
FLASH_CR |= FLASH_CR_STRT; /* Trigger the erase. */
flash_wait_busy();
FLASH_CR &= ~FLASH_CR_MER; /* Disable mass erase. */
}

View File

@ -0,0 +1,31 @@
/** @defgroup gpio_file GPIO
*
* @ingroup STM32F0xx
*
* @brief <b>libopencm3 STM32F0xx General Purpose I/O</b>
*
* @version 1.0.0
*
* @date 18 August 2012
*
* LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* 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/gpio.h>

View File

@ -0,0 +1,32 @@
/** @defgroup i2c_file I2C
*
* @ingroup STM32F0xx
*
* @brief <b>libopencm3 STM32F0xx I2C</b>
*
* @version 1.0.0
*
* @date 11 July 2013
*
* LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* 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/i2c.h>

View File

@ -0,0 +1,33 @@
/** @defgroup iwdg_file IWDG
*
* @ingroup STM32F0xx
*
* @brief <b>libopencm3 STM32F0xx Independent Watchdog Timer</b>
*
* @version 1.0.0
*
* @date 11 July 2013
*
* LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* 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/iwdg.h>
#include <libopencm3/stm32/common/iwdg_common_all.h>

View File

@ -0,0 +1,106 @@
/*
* 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
/* C++ Static constructors/destructors, also used for __attribute__
* ((constructor)) and the likes */
.preinit_array : {
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
} >rom
.init_array : {
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
} >rom
.fini_array : {
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
} >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));

View File

@ -0,0 +1,38 @@
/** @defgroup pwr-file PWR
*
* @ingroup STM32F0xx
*
* @brief <b>libopencm3 STM32F0xx Power Control</b>
*
* @version 1.0.0
*
* @date 11 July 2013
*
* This library supports the power control system for the
* STM32F0 series of ARM Cortex Microcontrollers by ST Microelectronics.
*
* LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* 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/pwr.h>
/**@}*/

View File

@ -0,0 +1,637 @@
/** @defgroup STM32F0xx-rcc-file RCC
*
* @ingroup STM32F0xx
*
* @brief <b>libopencm3 STM32F0xx Reset and Clock Control</b>
*
* @version 1.0.0
*
* @date 29 Jun 2013
*
* This library supports the Reset and Clock Control System in the STM32F0xx
* series of ARM Cortex Microcontrollers by ST Microelectronics.
*
* LGPL License Terms @ref lgpl_license
*/
/*
* 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>
*
* 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/assert.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/flash.h>
uint32_t rcc_core_frequency = 8000000; /* 8MHz after reset */
uint32_t rcc_ppre_frequency = 8000000; /* 8MHz after reset */
/*---------------------------------------------------------------------------*/
/** @brief RCC Clear the Oscillator Ready Interrupt Flag
*
* Clear the interrupt flag that was set when a clock oscillator became ready
* to use.
*
* @param[in] osc enum ::osc_t. Oscillator ID
*/
void rcc_osc_ready_int_clear(enum rcc_osc osc)
{
switch (osc) {
case HSI14:
RCC_CIR |= RCC_CIR_HSI14RDYC;
break;
case HSI:
RCC_CIR |= RCC_CIR_HSIRDYC;
break;
case HSE:
RCC_CIR |= RCC_CIR_HSERDYC;
break;
case PLL:
RCC_CIR |= RCC_CIR_PLLRDYC;
break;
case LSE:
RCC_CIR |= RCC_CIR_LSERDYC;
break;
case LSI:
RCC_CIR |= RCC_CIR_LSIRDYC;
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Enable the Oscillator Ready Interrupt
*
* @param[in] osc enum ::osc_t. Oscillator ID
*/
void rcc_osc_ready_int_enable(enum rcc_osc osc)
{
switch (osc) {
case HSI14:
RCC_CIR |= RCC_CIR_HSI14RDYIE;
break;
case HSI:
RCC_CIR |= RCC_CIR_HSIRDYIE;
break;
case HSE:
RCC_CIR |= RCC_CIR_HSERDYIE;
break;
case PLL:
RCC_CIR |= RCC_CIR_PLLRDYIE;
break;
case LSE:
RCC_CIR |= RCC_CIR_LSERDYIE;
break;
case LSI:
RCC_CIR |= RCC_CIR_LSIRDYIE;
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Disable the Oscillator Ready Interrupt
*
* @param[in] osc enum ::osc_t. Oscillator ID
*/
void rcc_osc_ready_int_disable(enum rcc_osc osc)
{
switch (osc) {
case HSI14:
RCC_CIR &= ~RCC_CIR_HSI14RDYC;
break;
case HSI:
RCC_CIR &= ~RCC_CIR_HSIRDYC;
break;
case HSE:
RCC_CIR &= ~RCC_CIR_HSERDYC;
break;
case PLL:
RCC_CIR &= ~RCC_CIR_PLLRDYC;
break;
case LSE:
RCC_CIR &= ~RCC_CIR_LSERDYC;
break;
case LSI:
RCC_CIR &= ~RCC_CIR_LSIRDYC;
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Read the Oscillator Ready Interrupt Flag
*
* @param[in] osc enum ::osc_t. Oscillator ID
* @returns int. Boolean value for flag set.
*/
int rcc_osc_ready_int_flag(enum rcc_osc osc)
{
switch (osc) {
case HSI14:
return (RCC_CIR & RCC_CIR_HSI14RDYF) != 0;
break;
case HSI:
return (RCC_CIR & RCC_CIR_HSIRDYF) != 0;
break;
case HSE:
return (RCC_CIR & RCC_CIR_HSERDYF) != 0;
break;
case PLL:
return (RCC_CIR & RCC_CIR_PLLRDYF) != 0;
break;
case LSE:
return (RCC_CIR & RCC_CIR_LSERDYF) != 0;
break;
case LSI:
return (RCC_CIR & RCC_CIR_LSIRDYF) != 0;
break;
}
cm3_assert_not_reached();
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Clear the Clock Security System Interrupt Flag
*/
void rcc_css_int_clear(void)
{
RCC_CIR |= RCC_CIR_CSSC;
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Read the Clock Security System Interrupt Flag
*
* @returns int. Boolean value for flag set.
*/
int rcc_css_int_flag(void)
{
return ((RCC_CIR & RCC_CIR_CSSF) != 0);
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Wait for Oscillator Ready.
*
* @param[in] osc enum ::osc_t. Oscillator ID
*/
void rcc_wait_for_osc_ready(enum rcc_osc osc)
{
switch (osc) {
case HSI14:
while ((RCC_CIR & RCC_CIR_HSI14RDYF) != 0);
break;
case HSI:
while ((RCC_CIR & RCC_CIR_HSIRDYF) != 0);
break;
case HSE:
while ((RCC_CIR & RCC_CIR_HSERDYF) != 0);
break;
case PLL:
while ((RCC_CIR & RCC_CIR_PLLRDYF) != 0);
break;
case LSE:
while ((RCC_CIR & RCC_CIR_LSERDYF) != 0);
break;
case LSI:
while ((RCC_CIR & RCC_CIR_LSIRDYF) != 0);
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Turn on an Oscillator.
*
* Enable an oscillator and power on. Each oscillator requires an amount of
* time to settle to a usable state. Refer to datasheets for time delay
* information. A status flag is available to indicate when the oscillator
* becomes ready (see @ref rcc_osc_ready_int_flag and @ref
* rcc_wait_for_osc_ready).
*
* @param[in] osc enum ::osc_t. Oscillator ID
*/
void rcc_osc_on(enum rcc_osc osc)
{
switch (osc) {
case HSI14:
RCC_CR2 |= RCC_CR2_HSI14ON;
break;
case HSI:
RCC_CR |= RCC_CR_HSION;
break;
case HSE:
RCC_CR |= RCC_CR_HSEON;
break;
case LSE:
RCC_BDCR |= RCC_BDCR_LSEON;
break;
case LSI:
RCC_CSR |= RCC_CSR_LSION;
break;
case PLL:
/* don't do anything */
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Turn off an Oscillator.
*
* Disable an oscillator and power off.
*
* @note An oscillator cannot be turned off if it is selected as the system
* clock.
*
* @param[in] osc enum ::osc_t. Oscillator ID
*/
void rcc_osc_off(enum rcc_osc osc)
{
switch (osc) {
case HSI14:
RCC_CR2 &= ~RCC_CR2_HSI14ON;
break;
case HSI:
RCC_CR &= ~RCC_CR_HSION;
break;
case HSE:
RCC_CR &= ~RCC_CR_HSEON;
break;
case LSE:
RCC_BDCR &= ~RCC_BDCR_LSEON;
break;
case LSI:
RCC_CSR &= ~RCC_CSR_LSION;
break;
case PLL:
/* don't do anything */
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Enable the Clock Security System.
*/
void rcc_css_enable(void)
{
RCC_CR |= RCC_CR_CSSON;
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Disable the Clock Security System.
*/
void rcc_css_disable(void)
{
RCC_CR &= ~RCC_CR_CSSON;
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Enable Bypass.
*
* Enable an external clock to bypass the internal clock (high speed and low
* speed clocks only). The external clock must be enabled (see @ref rcc_osc_on)
* and the internal clock must be disabled (see @ref rcc_osc_off) for this to
* have effect.
*
* @param[in] osc enum ::osc_t. Oscillator ID. Only HSE and LSE have effect.
*/
void rcc_osc_bypass_enable(enum rcc_osc osc)
{
switch (osc) {
case HSE:
RCC_CR |= RCC_CR_HSEBYP;
break;
case LSE:
RCC_BDCR |= RCC_BDCR_LSEBYP;
break;
case HSI14:
case HSI:
case LSI:
case PLL:
/* Do nothing */
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Disable Bypass.
*
* Re-enable the internal clock (high speed and low speed clocks only). The
* internal clock must be disabled (see @ref rcc_osc_off) for this to have
* effect.
*
*
* @param[in] osc enum ::osc_t. Oscillator ID. Only HSE and LSE have effect.
*/
void rcc_osc_bypass_disable(enum rcc_osc osc)
{
switch (osc) {
case HSE:
RCC_CR &= ~RCC_CR_HSEBYP;
break;
case LSE:
RCC_BDCR &= ~RCC_BDCR_LSEBYP;
break;
case HSI14:
case PLL:
case HSI:
case LSI:
/* Do nothing */
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Set the Source for the System Clock.
*
* @param[in] osc enum ::osc_t. Oscillator ID. Only HSE, LSE and PLL have
* effect.
*/
void rcc_set_sysclk_source(enum rcc_osc clk)
{
switch (clk) {
case HSI:
RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_HSI;
break;
case HSE:
RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_HSE;
break;
case PLL:
RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_PLL;
break;
case LSI:
case LSE:
case HSI14:
/* do nothing */
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Set the PLL Multiplication Factor.
*
* @note This only has effect when the PLL is disabled.
*
* @param[in] mul Unsigned int32. PLL multiplication factor @ref rcc_cfgr_pmf
*/
void rcc_set_pll_multiplication_factor(uint32_t mul)
{
RCC_CFGR = (RCC_CFGR & RCC_CFGR_PLLMUL) | mul;
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Set the APB Prescale Factor.
*
* @note The APB1 clock frequency must not exceed 36MHz.
*
* @param[in] ppre1 Unsigned int32. APB prescale factor @ref rcc_cfgr_apb1pre
*/
void rcc_set_ppre(uint32_t ppre)
{
RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_PPRE) | ppre;
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Set the AHB Prescale Factor.
*
* @param[in] hpre Unsigned int32. AHB prescale factor @ref rcc_cfgr_ahbpre
*/
void rcc_set_hpre(uint32_t hpre)
{
RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_HPRE) | hpre;
}
void rcc_set_prediv(uint32_t prediv)
{
RCC_CFGR2 = (RCC_CFGR2 & ~RCC_CFGR2_PREDIV) | prediv;
}
void rcc_set_mco(uint32_t mcosrc)
{
RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_MCO) | mcosrc;
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Get the System Clock Source.
*
* @returns ::osc_t System clock source:
*/
enum rcc_osc rcc_system_clock_source(void)
{
/* Return the clock source which is used as system clock. */
switch (RCC_CFGR & RCC_CFGR_SWS) {
case RCC_CFGR_SWS_HSI:
return HSI;
case RCC_CFGR_SWS_HSE:
return HSE;
case RCC_CFGR_SWS_PLL:
return PLL;
}
cm3_assert_not_reached();
}
void rcc_clock_setup_in_hsi_out_8mhz(void)
{
rcc_osc_on(HSI);
rcc_wait_for_osc_ready(HSI);
rcc_set_sysclk_source(HSI);
rcc_set_hpre(RCC_CFGR_HPRE_NODIV);
rcc_set_ppre(RCC_CFGR_PPRE_NODIV);
flash_set_ws(FLASH_ACR_LATENCY_000_024MHZ);
rcc_ppre_frequency = 8000000;
rcc_core_frequency = 8000000;
}
void rcc_clock_setup_in_hsi_out_16mhz(void)
{
rcc_osc_on(HSI);
rcc_wait_for_osc_ready(HSI);
rcc_set_sysclk_source(HSI);
rcc_set_hpre(RCC_CFGR_HPRE_NODIV);
rcc_set_ppre(RCC_CFGR_PPRE_NODIV);
flash_set_ws(FLASH_ACR_LATENCY_000_024MHZ);
/* 8MHz * 4 / 2 = 16MHz */
rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_MUL4);
RCC_CFGR &= RCC_CFGR_PLLSRC;
rcc_osc_on(PLL);
rcc_wait_for_osc_ready(PLL);
rcc_set_sysclk_source(PLL);
rcc_ppre_frequency = 16000000;
rcc_core_frequency = 16000000;
}
void rcc_clock_setup_in_hsi_out_24mhz(void)
{
rcc_osc_on(HSI);
rcc_wait_for_osc_ready(HSI);
rcc_set_sysclk_source(HSI);
rcc_set_hpre(RCC_CFGR_HPRE_NODIV);
rcc_set_ppre(RCC_CFGR_PPRE_NODIV);
flash_set_ws(FLASH_ACR_LATENCY_000_024MHZ);
/* 8MHz * 6 / 2 = 24MHz */
rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_MUL6);
RCC_CFGR &= RCC_CFGR_PLLSRC;
rcc_osc_on(PLL);
rcc_wait_for_osc_ready(PLL);
rcc_set_sysclk_source(PLL);
rcc_ppre_frequency = 24000000;
rcc_core_frequency = 24000000;
}
void rcc_clock_setup_in_hsi_out_32mhz(void)
{
rcc_osc_on(HSI);
rcc_wait_for_osc_ready(HSI);
rcc_set_sysclk_source(HSI);
rcc_set_hpre(RCC_CFGR_HPRE_NODIV);
rcc_set_ppre(RCC_CFGR_PPRE_NODIV);
flash_set_ws(FLASH_ACR_LATENCY_024_048MHZ);
/* 8MHz * 8 / 2 = 32MHz */
rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_MUL8);
RCC_CFGR &= RCC_CFGR_PLLSRC;
rcc_osc_on(PLL);
rcc_wait_for_osc_ready(PLL);
rcc_set_sysclk_source(PLL);
rcc_ppre_frequency = 32000000;
rcc_core_frequency = 32000000;
}
void rcc_clock_setup_in_hsi_out_40mhz(void)
{
rcc_osc_on(HSI);
rcc_wait_for_osc_ready(HSI);
rcc_set_sysclk_source(HSI);
rcc_set_hpre(RCC_CFGR_HPRE_NODIV);
rcc_set_ppre(RCC_CFGR_PPRE_NODIV);
flash_set_ws(FLASH_ACR_LATENCY_024_048MHZ);
/* 8MHz * 10 / 2 = 40MHz */
rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_MUL10);
RCC_CFGR &= RCC_CFGR_PLLSRC;
rcc_osc_on(PLL);
rcc_wait_for_osc_ready(PLL);
rcc_set_sysclk_source(PLL);
rcc_ppre_frequency = 32000000;
rcc_core_frequency = 32000000;
}
void rcc_clock_setup_in_hsi_out_48mhz(void)
{
rcc_osc_on(HSI);
rcc_wait_for_osc_ready(HSI);
rcc_set_sysclk_source(HSI);
rcc_set_hpre(RCC_CFGR_HPRE_NODIV);
rcc_set_ppre(RCC_CFGR_PPRE_NODIV);
flash_set_ws(FLASH_ACR_LATENCY_024_048MHZ);
/* 8MHz * 12 / 2 = 24MHz */
rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_MUL16);
RCC_CFGR &= RCC_CFGR_PLLSRC;
rcc_osc_on(PLL);
rcc_wait_for_osc_ready(PLL);
rcc_set_sysclk_source(PLL);
rcc_ppre_frequency = 48000000;
rcc_core_frequency = 48000000;
}
#define _RCC_REG(i) MMIO32(RCC_BASE + ((i) >> 5))
#define _RCC_BIT(i) (1 << ((i) & 0x1f))
void rcc_periph_clock_enable(enum rcc_periph_clken periph)
{
_RCC_REG(periph) |= _RCC_BIT(periph);
}
void rcc_periph_clock_disable(enum rcc_periph_clken periph)
{
_RCC_REG(periph) &= ~_RCC_BIT(periph);
}
void rcc_periph_reset_pulse(enum rcc_periph_rst periph)
{
_RCC_REG(periph) |= _RCC_BIT(periph);
_RCC_REG(periph) &= ~_RCC_BIT(periph);
}
void rcc_periph_reset_hold(enum rcc_periph_rst periph)
{
_RCC_REG(periph) |= _RCC_BIT(periph);
}
void rcc_periph_reset_release(enum rcc_periph_rst periph)
{
_RCC_REG(periph) &= ~_RCC_BIT(periph);
}
#undef _RCC_REG
#undef _RCC_BIT
/**@}*/

View File

@ -0,0 +1,32 @@
/** @defgroup rtc_file RTC
*
* @ingroup STM32F0xx
*
* @brief <b>libopencm3 STM32F0xx RTC</b>
*
* @version 1.0.0
*
* @date 10 July 2013
*
* LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* 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/rtc.h>
#include <libopencm3/stm32/common/rtc_common_l1f024.h>

View File

@ -0,0 +1,54 @@
/** @defgroup spi_file SPI
*
* @ingroup STM32F0xx
*
* @brief <b>libopencm3 STM32F0xx Serial Peripheral Interface</b>
*
* @version 1.0.0
*
* @date 11 July 2013
*
* LGPL License Terms @ref lgpl_license
*/
/*
* 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/>.
*/
#include <libopencm3/stm32/spi.h>
#include <libopencm3/stm32/rcc.h>
void spi_set_data_size(uint32_t spi, uint16_t data_s)
{
SPI_CR2(spi) = (SPI_CR2(spi) & ~SPI_CR2_DS_MASK) |
(data_s & SPI_CR2_DS_MASK);
}
void spi_fifo_reception_threshold_8bit(uint32_t spi)
{
SPI_CR2(spi) |= SPI_CR2_FRXTH;
}
void spi_fifo_reception_threshold_16bit(uint32_t spi)
{
SPI_CR2(spi) &= ~SPI_CR2_FRXTH;
}
void spi_i2s_mode_spi_mode(uint32_t spi)
{
SPI_I2SCFGR(spi) &= ~SPI_I2SCFGR_I2SMOD;
}

View File

@ -0,0 +1,31 @@
/** @defgroup syscfg_file SYSCFG
*
* @ingroup STM32F0xx
*
* @brief <b>libopencm3 STM32F0xx SYSCFG</b>
*
* @version 1.0.0
*
* @date 10 July 2013
*
* LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* 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/syscfg.h>

Some files were not shown because too many files have changed in this diff Show More