Add software
This commit is contained in:
@ -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)
|
@ -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();
|
||||
}
|
@ -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 © @endhtmlonly 2010 Thomas Otto <tommi@viadmin.org>
|
||||
* @author @htmlonly © @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
|
||||
/**@}*/
|
@ -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
|
@ -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
|
@ -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 © @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;
|
||||
}
|
||||
/**@}*/
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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;
|
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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;
|
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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;
|
@ -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));
|
||||
|
@ -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
|
@ -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 © @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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
@ -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));
|
||||
|
@ -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
|
@ -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 © @endhtmlonly 2011
|
||||
* Gareth McMullin <gareth@blacksphere.co.nz>
|
||||
* @author @htmlonly © @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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
||||
/**@}*/
|
||||
|
@ -0,0 +1,2 @@
|
||||
/* Yes, we can simply use the lm3s linker script */
|
||||
INCLUDE "libopencm3_lm3s.ld"
|
@ -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 © @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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
@ -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));
|
||||
}
|
@ -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 © @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;
|
||||
}
|
||||
/**@}*/
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
@ -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 © @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
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
@ -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
|
@ -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 © @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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
@ -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));
|
||||
|
@ -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
|
@ -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 © @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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
@ -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));
|
||||
|
@ -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 © @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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
@ -0,0 +1,203 @@
|
||||
/** @defgroup i2c_file I2C
|
||||
|
||||
@ingroup LPC43xx
|
||||
|
||||
@brief <b>libopencm3 LPC43xx I2C</b>
|
||||
|
||||
@version 1.0.0
|
||||
|
||||
@author @htmlonly © @endhtmlonly 2012 Michael Ossmann <mike@ossmann.com>
|
||||
@author @htmlonly © @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);
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
@ -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);
|
||||
}
|
@ -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
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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 © @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 */
|
||||
|
||||
/**@}*/
|
||||
|
@ -0,0 +1,146 @@
|
||||
/** @defgroup ssp_file SSP
|
||||
|
||||
@ingroup LPC43xx
|
||||
|
||||
@brief <b>libopencm3 LPC43xx SSP</b>
|
||||
|
||||
@version 1.0.0
|
||||
|
||||
@author @htmlonly © @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);
|
||||
}
|
||||
|
||||
|
||||
/**@}*/
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
@ -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)
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
@ -0,0 +1,557 @@
|
||||
/** @defgroup can_file CAN
|
||||
|
||||
@ingroup STM32F_files
|
||||
|
||||
@brief <b>libopencm3 STM32Fxxx CAN</b>
|
||||
|
||||
@version 1.0.0
|
||||
|
||||
@author @htmlonly © @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);
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/** @addtogroup crc_file
|
||||
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
/**@}*/
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**@}*/
|
@ -0,0 +1,500 @@
|
||||
/** @addtogroup dac_file
|
||||
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
}
|
||||
/**@}*/
|
||||
|
@ -0,0 +1,794 @@
|
||||
/** @addtogroup dma_file
|
||||
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
/**@}*/
|
||||
|
@ -0,0 +1,435 @@
|
||||
/** @addtogroup dma_file
|
||||
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
/**@}*/
|
||||
|
@ -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
|
||||
};
|
||||
}
|
@ -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);
|
||||
}
|
@ -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();
|
||||
}
|
@ -0,0 +1,151 @@
|
||||
/** @addtogroup gpio_file
|
||||
|
||||
@author @htmlonly © @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. */
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
@ -0,0 +1,206 @@
|
||||
/** @addtogroup gpio_file
|
||||
|
||||
@author @htmlonly © @endhtmlonly 2009
|
||||
Uwe Hermann <uwe@hermann-uwe.de>
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
/**@}*/
|
||||
|
@ -0,0 +1,161 @@
|
||||
/** @addtogroup hash_file
|
||||
|
||||
@author @htmlonly © @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];
|
||||
}
|
||||
}
|
@ -0,0 +1,412 @@
|
||||
/** @addtogroup i2c_file
|
||||
|
||||
@author @htmlonly © @endhtmlonly 2010
|
||||
Thomas Otto <tommi@viadmin.org>
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
|
||||
/**@}*/
|
@ -0,0 +1,149 @@
|
||||
/** @addtogroup iwdg_file
|
||||
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
/**@}*/
|
||||
|
@ -0,0 +1,205 @@
|
||||
/** @addtogroup pwr_file PWR
|
||||
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
/**@}*/
|
@ -0,0 +1,123 @@
|
||||
/** @addtogroup rtc_file
|
||||
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
|
||||
/**@}*/
|
@ -0,0 +1,698 @@
|
||||
/** @addtogroup spi_file
|
||||
|
||||
@author @htmlonly © @endhtmlonly 2009
|
||||
Uwe Hermann <uwe@hermann-uwe.de>
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
|
||||
/**@}*/
|
@ -0,0 +1,137 @@
|
||||
/** @addtogroup spi_file
|
||||
|
||||
@author @htmlonly © @endhtmlonly 2009
|
||||
Uwe Hermann <uwe@hermann-uwe.de>
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
|
||||
/**@}*/
|
File diff suppressed because it is too large
Load Diff
@ -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));
|
||||
}
|
||||
}
|
||||
/**@}*/
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
||||
|
@ -0,0 +1,367 @@
|
||||
/** @addtogroup usart_file
|
||||
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
@ -0,0 +1,143 @@
|
||||
/** @addtogroup usart_file
|
||||
|
||||
@author @htmlonly © @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;
|
||||
}
|
||||
|
||||
/**@}*/
|
@ -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';
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/**@}*/
|
@ -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;
|
||||
}
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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. */
|
||||
}
|
@ -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>
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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));
|
||||
|
@ -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>
|
||||
|
||||
/**@}*/
|
||||
|
@ -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
|
||||
|
||||
/**@}*/
|
||||
|
@ -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>
|
@ -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;
|
||||
}
|
@ -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
Reference in New Issue
Block a user