subrepo:
  subdir:   "libopencm3"
  merged:   "88e91c9a7cce"
upstream:
  origin:   "https://github.com/libopencm3/libopencm3.git"
  branch:   "master"
  commit:   "88e91c9a7cce"
git-subrepo:
  version:  "0.4.3"
  origin:   "???"
  commit:   "???"
This commit is contained in:
2023-01-21 21:54:42 +02:00
parent f01f2a30fa
commit 054740c5de
1205 changed files with 191912 additions and 0 deletions

View File

@@ -0,0 +1,49 @@
##
## This file is part of the libopencm3 project.
##
## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
## Copyright (C) 2012 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 dwt.o
# Slightly bigger .elf files but gains the ability to decode macros
DEBUG_FLAGS ?= -ggdb3
STANDARD_FLAGS ?= -std=c99
all: $(SRCLIBDIR)/$(LIBNAME).a
$(SRCLIBDIR)/$(LIBNAME).a: $(OBJS)
@printf " AR $(LIBNAME).a\n"
$(Q)$(AR) $(ARFLAGS) "$@" $(OBJS)
%.o: %.c
@printf " CC $(<F)\n"
$(Q)$(CC) $(TGT_CFLAGS) $(CFLAGS) -o $@ -c $<
clean:
$(Q)rm -f *.o *.d ../*.o ../*.d
$(Q)rm -f $(SRCLIBDIR)/$(LIBNAME).a
.PHONY: clean
-include $(OBJS:.o=.d)

View File

@@ -0,0 +1,34 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Tomaz Solc <tomaz.solc@tablix.org>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/cm3/assert.h>
void __attribute__((weak)) cm3_assert_failed(void)
{
while (1);
}
void __attribute__((weak)) cm3_assert_failed_verbose(
const char *file __attribute__((unused)),
int line __attribute__((unused)),
const char *func __attribute__((unused)),
const char *assert_expr __attribute__((unused)))
{
cm3_assert_failed();
}

105
libopencm3/lib/cm3/dwt.c Normal file
View File

@@ -0,0 +1,105 @@
/** @defgroup CM3_dwt_file DWT
*
* @ingroup CM3_files
*
* @brief <b>libopencm3 Cortex-M Data Watchpoint and Trace unit</b>
*
* The DWT provides
* * Comparators, that support
* * watch points
* * data tracing
* * signalling to ETM
* * PC value tracing
* * cycle count matching
* * extra PC sampling
* * Sampling as a result of a clock count
* * external access for sampling
* * exception trace
* * performance profiling counters.
*
* Which of these features are available is unfortunately implementation defined.
*
* @see ARMv7m Architecture Reference Manual (Chapter ARMv7-M Debug)
*
* LGPL License Terms @ref lgpl_license
* @{
*/
/*
* 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/cm3/scs.h>
#include <libopencm3/cm3/dwt.h>
/*---------------------------------------------------------------------------*/
/** @brief DebugTrace Enable the CPU cycle counter
*
* This function will try to enable the CPU cycle counter that is intended for
* benchmarking performance of the code. If function fails, the cycle counter
* isn't available on this architecture.
*
* @return true, if success
*/
bool dwt_enable_cycle_counter(void)
{
#if defined(__ARM_ARCH_6M__)
return false; /* Not supported on ARMv6M */
#endif /* defined(__ARM_ARCH_6M__) */
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
/* Note TRCENA is for 7M and above*/
SCS_DEMCR |= SCS_DEMCR_TRCENA;
if (DWT_CTRL & DWT_CTRL_NOCYCCNT) {
return false; /* Not supported in implementation */
}
DWT_CYCCNT = 0;
DWT_CTRL |= DWT_CTRL_CYCCNTENA;
return true;
#endif /* defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) */
/* not supported on other architectures */
return false;
}
/*---------------------------------------------------------------------------*/
/** @brief DebugTrace Read the CPU cycle counter
*
* This function reads the core cycle counter if it is enabled. It is the
* fastest clock running on the system.
*
* @note The CPU cycle counter must be enabled by @ref dwt_enable_cycle_counter
*
* @returns 0 if cycle counter is not supported or enabled, the cycle counter
* value otherwise.
*/
uint32_t dwt_read_cycle_counter(void)
{
#if defined(__ARM_ARCH_6M__)
return 0; /* Not supported on ARMv6M */
#endif /* defined(__ARM_ARCH_6M__) */
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
if (DWT_CTRL & DWT_CTRL_CYCCNTENA) {
return DWT_CYCCNT;
} else {
return 0; /* not supported or enabled */
}
#endif /* defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) */
}
/**@}*/

216
libopencm3/lib/cm3/nvic.c Normal file
View File

@@ -0,0 +1,216 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
* Copyright (C) 2012 Fergus Noble <fergusnoble@gmail.com>
* Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/** @defgroup CM3_nvic_file NVIC
*
* @ingroup CM3_files
*
* @brief <b>libopencm3 Cortex Nested Vectored Interrupt Controller</b>
*
* @version 1.0.0
*
* @author @htmlonly &copy; @endhtmlonly 2010 Thomas Otto <tommi@viadmin.org>
* @author @htmlonly &copy; @endhtmlonly 2012 Fergus Noble
* <fergusnoble@gmail.com>
*
* @date 18 August 2012
*
* Cortex processors provide 14 cortex-defined interrupts (NMI, usage faults,
* systicks etc.) and varying numbers of implementation defined interrupts
* (typically peripherial interrupts and DMA).
*
* @see Cortex-M3 Devices Generic User Guide
* @see STM32F10xxx Cortex-M3 programming manual
*
* LGPL License Terms @ref lgpl_license
*/
/**@{*/
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/cm3/scb.h>
/*---------------------------------------------------------------------------*/
/** @brief NVIC Enable Interrupt
*
* Enables a user interrupt.
*
* @param[in] irqn Unsigned int8. Interrupt number @ref CM3_nvic_defines_irqs
*/
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 CM3_nvic_defines_irqs
*/
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 CM3_nvic_defines_irqs
* @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 CM3_nvic_defines_irqs
*/
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 CM3_nvic_defines_irqs
*/
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 CM3_nvic_defines_irqs
* @return Boolean. Interrupt enabled.
*/
uint8_t nvic_get_irq_enabled(uint8_t irqn)
{
return NVIC_ISER(irqn / 32) & (1 << (irqn % 32)) ? 1 : 0;
}
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
/** @brief NVIC Set Interrupt Priority
*
* 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,
* @param[in] irqn Interrupt number @ref CM3_nvic_defines_irqs
* @param[in] priority Interrupt priority (0 ... 255 in steps of 16)
*/
#else
/** NVIC Set Interrupt Priority.
*
* 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 Interrupt number @ref CM3_nvic_defines_irqs
* @param[in] priority Interrupt priority (0 ... 255 in steps of 16)
*/
#endif
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 */
#if defined(__ARM_ARCH_6M__)
/* ARM6M supports only 32bit word access to SHPR registers */
irqn = (irqn & 0xF) - 4;
uint8_t shift = (irqn & 0x3) << 3;
uint8_t reg = irqn >> 2;
SCB_SHPR32(reg) = ((SCB_SHPR32(reg) & ~(0xFFUL << shift)) |
((uint32_t) priority) << shift);
#else
SCB_SHPR((irqn & 0xF) - 4) = priority;
#endif
} else {
/* Device specific interrupts */
#if defined(__ARM_ARCH_6M__)
/* ARM6M supports only 32bit word access to IPR registers */
uint8_t shift = (irqn & 0x3) << 3;
uint8_t reg = irqn >> 2;
NVIC_IPR32(reg) = ((NVIC_IPR32(reg) & ~(0xFFUL << shift)) |
((uint32_t) priority) << shift);
#else
NVIC_IPR(irqn) = priority;
#endif
}
}
/* 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 CM3_nvic_defines_irqs
* @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
/**@}*/

69
libopencm3/lib/cm3/scb.c Normal file
View File

@@ -0,0 +1,69 @@
/** @defgroup CM3_scb_file SCB
*
* @ingroup CM3_files
*
* @brief <b>libopencm3 Cortex-M System Control Block</b>
*
* The System Control Block (SCB) is a section of the System Control Space
* which provides status information and control features for the processor core.
* It allows, amongst other:
* * software reset control
* * exception management and grouping
* * fault information
* * power management
* * debug status information
*
* @see ARMv7m Architecture Reference Manual (Chapter B3.2.1 About the SCB)
*
* LGPL License Terms @ref lgpl_license
* @{
*/
/*
* 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
/**@}*/

79
libopencm3/lib/cm3/sync.c Normal file
View File

@@ -0,0 +1,79 @@
/*
* 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_7M__) || defined(__ARM_ARCH_7EM__)
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)
{
while (!mutex_trylock(m));
}
/* returns 1 if the lock was acquired */
uint32_t mutex_trylock(mutex_t *m)
{
uint32_t status = 1;
/* If the mutex is unlocked. */
if (__ldrex(m) == MUTEX_UNLOCKED) {
/* Try to lock it. */
status = __strex(MUTEX_LOCKED, m);
}
/* Execute the mysterious Data Memory Barrier instruction! */
__dmb();
/* Did we get the lock? If not then try again
* by calling this function once more. */
return status == 0;
}
void mutex_unlock(mutex_t *m)
{
/* Ensure accesses to protected resource are finished */
__dmb();
/* Free the lock. */
*m = MUTEX_UNLOCKED;
}
#endif

View File

@@ -0,0 +1,203 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
* Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/** @defgroup CM3_systick_file SysTick
*
* @ingroup CM3_files
*
* @brief <b>libopencm3 Cortex System Tick Timer</b>
*
* @version 1.0.0
*
* @author @htmlonly &copy; @endhtmlonly 2010 Thomas Otto <tommi@viadmin.org>
*
* @date 19 August 2012
*
* This library supports the System Tick timer in ARM Cortex Microcontrollers.
*
* The System Tick timer is part of the ARM Cortex core. It is a 24 bit
* down counter that can be configured with an automatical reload value.
*
* LGPL License Terms @ref lgpl_license
*/
/**@{*/
#include <libopencm3/cm3/systick.h>
/*---------------------------------------------------------------------------*/
/** @brief SysTick Set the Automatic Reload Value.
*
* The counter is set to the reload value when the counter starts and after it
* reaches zero.
*
* @note The systick counter value might be undefined upon startup. To get
* predictable behavior, it is a good idea to set or clear the counter after
* set reload. @sa systick_clear
*
* @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 SysTick Set clock and frequency of overflow
*
* This function sets the systick to AHB clock source, and the prescaler to
* generate interrupts with the desired frequency. The function fails, if
* the frequency is too low.
*
* @param[in] freq uint32_t The desired frequency in Hz
* @param[in] ahb uint32_t The current AHB frequency in Hz
* @returns true, if success, false if the desired frequency cannot be set.
*/
bool systick_set_frequency(uint32_t freq, uint32_t ahb)
{
uint32_t ratio = ahb / freq;
#if defined(__ARM_ARCH_6M__)
systick_set_clocksource(STK_CSR_CLKSOURCE_AHB);
#else
if (ratio >= (STK_RVR_RELOAD * 8)) {
/* This frequency is too slow */
return false;
} else if (ratio >= STK_RVR_RELOAD) {
ratio /= 8;
systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8);
} else {
systick_set_clocksource(STK_CSR_CLKSOURCE_AHB);
}
#endif
systick_set_reload(ratio - 1);
return true;
}
/*---------------------------------------------------------------------------*/
/** @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);
}
/*---------------------------------------------------------------------------*/
/** @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 Clear counter Value.
*
* The counter value is cleared. Useful for well defined startup.
*/
void systick_clear(void)
{
STK_CVR = 0;
}
/*---------------------------------------------------------------------------*/
/** @brief SysTick Get Calibration Value
*
* @returns Current calibration value
*/
uint32_t systick_get_calib(void)
{
return STK_CALIB & STK_CALIB_TENMS;
}
/**@}*/

125
libopencm3/lib/cm3/vector.c Normal file
View File

@@ -0,0 +1,125 @@
/*
* 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/scb.h>
#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"
/* Less common symbols exported by the linker script(s): */
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;
int 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 __attribute__ ((weak)) reset_handler(void)
{
volatile unsigned *src, *dest;
funcp_t *fp;
for (src = &_data_loadaddr, dest = &_data;
dest < &_edata;
src++, dest++) {
*dest = *src;
}
while (dest < &_ebss) {
*dest++ = 0;
}
/* Ensure 8-byte alignment of stack pointer on interrupts */
/* Enabled by default on most Cortex-M parts, but not M3 r1 */
SCB_CCR |= SCB_CCR_STKALIGN;
/* might be provided by platform specific vector.c */
pre_main();
/* Constructors. */
for (fp = &__preinit_array_start; fp < &__preinit_array_end; fp++) {
(*fp)();
}
for (fp = &__init_array_start; fp < &__init_array_end; fp++) {
(*fp)();
}
/* Call the application's entry point. */
(void)main();
/* Destructors. */
for (fp = &__fini_array_start; fp < &__fini_array_end; fp++) {
(*fp)();
}
}
void blocking_handler(void)
{
while (1);
}
void null_handler(void)
{
/* Do nothing. */
}
#pragma weak nmi_handler = null_handler
#pragma weak hard_fault_handler = blocking_handler
#pragma weak sv_call_handler = null_handler
#pragma weak pend_sv_handler = null_handler
#pragma weak sys_tick_handler = null_handler
/* Those are defined only on CM3 or CM4 */
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
#pragma weak mem_manage_handler = blocking_handler
#pragma weak bus_fault_handler = blocking_handler
#pragma weak usage_fault_handler = blocking_handler
#pragma weak debug_monitor_handler = null_handler
#endif

View File

@@ -0,0 +1,125 @@
/*
* 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/>.
*/
/*
* This is a generic linker script for Cortex-M targets using libopencm3.
*
* Memory regions MUST be defined in the ld script which includes this one!
* Example:
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 256K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 16K
}
INCLUDE cortex-m-generic.ld
*/
/* 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 = .;
/* ram, but not cleared on reset, eg boot/app comms */
.noinit (NOLOAD) : {
*(.noinit*)
} >ram
. = ALIGN(4);
.data : {
_data = .;
*(.data*) /* Read-write initialized data */
*(.ramtext*) /* "text" functions to run in ram */
. = ALIGN(4);
_edata = .;
} >ram AT >rom
_data_loadaddr = LOADADDR(.data);
.bss : {
*(.bss*) /* Read-write zero initialized data */
*(COMMON)
. = ALIGN(4);
_ebss = .;
} >ram
/*
* The .eh_frame section appears to be used for C++ exception handling.
* You may need to fix this if you're using C++.
*/
/DISCARD/ : { *(.eh_frame) }
. = ALIGN(4);
end = .;
}
PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));

View File

@@ -0,0 +1,29 @@
#if defined(STM32F3)
# include "../stm32/f3/vector_chipset.c"
#elif defined(STM32F4)
# include "../stm32/f4/vector_chipset.c"
#elif defined(STM32F7)
# include "../stm32/f7/vector_chipset.c"
#elif defined(STM32G4)
# include "../stm32/g4/vector_chipset.c"
#elif defined(STM32H7)
# include "../stm32/h7/vector_chipset.c"
#elif defined(STM32L4)
# include "../stm32/l4/vector_chipset.c"
#elif defined(LM4F)
# include "../lm4f/vector_chipset.c"
#elif defined(LPC43XX_M4)
# include "../lpc43xx/m4/vector_chipset.c"
#elif defined(VF6XX)
# include "../vf6xx/vector_chipset.c"
#elif defined(EFM32WG)
# include "../efm32/wg/vector_chipset.c"
#elif defined(EZR32WG)
# include "../efm32/ezr32wg/vector_chipset.c"
#elif defined(PAC55XX)
# include "../pac55xx/vector_chipset.c"
#else
static void pre_main(void) {}
#endif

View File

@@ -0,0 +1,96 @@
#if defined(STM32F0)
# include "../stm32/f0/vector_nvic.c"
#elif defined(STM32F1)
# include "../stm32/f1/vector_nvic.c"
#elif defined(STM32F2)
# include "../stm32/f2/vector_nvic.c"
#elif defined(STM32F3)
# include "../stm32/f3/vector_nvic.c"
#elif defined(STM32F4)
# include "../stm32/f4/vector_nvic.c"
#elif defined(STM32F7)
# include "../stm32/f7/vector_nvic.c"
#elif defined(STM32L0)
# include "../stm32/l0/vector_nvic.c"
#elif defined(STM32L1)
# include "../stm32/l1/vector_nvic.c"
#elif defined(STM32L4)
# include "../stm32/l4/vector_nvic.c"
#elif defined(STM32G0)
# include "../stm32/g0/vector_nvic.c"
#elif defined(STM32G4)
# include "../stm32/g4/vector_nvic.c"
#elif defined(STM32H7)
# include "../stm32/h7/vector_nvic.c"
#elif defined(GD32F1X0)
# include "../gd32/f1x0/vector_nvic.c"
#elif defined(EFM32TG)
# include "../efm32/tg/vector_nvic.c"
#elif defined(EFM32G)
# include "../efm32/g/vector_nvic.c"
#elif defined(EFM32LG)
# include "../efm32/lg/vector_nvic.c"
#elif defined(EFM32GG)
# include "../efm32/gg/vector_nvic.c"
#elif defined(EFM32HG)
# include "../efm32/hg/vector_nvic.c"
#elif defined(EFM32WG)
# include "../efm32/wg/vector_nvic.c"
#elif defined(EZR32WG)
# include "../efm32/ezr32wg/vector_nvic.c"
#elif defined(LPC13XX)
# include "../lpc13xx/vector_nvic.c"
#elif defined(LPC17XX)
# include "../lpc17xx/vector_nvic.c"
#elif defined(LPC43XX_M4)
# include "../lpc43xx/m4/vector_nvic.c"
#elif defined(LPC43XX_M0)
# include "../lpc43xx/m0/vector_nvic.c"
#elif defined(NRF51)
# include "../nrf/51/vector_nvic.c"
#elif defined(NRF52)
# include "../nrf/52/vector_nvic.c"
#elif defined(SAM3A)
# include "../sam/3a/vector_nvic.c"
#elif defined(SAM3N)
# include "../sam/3n/vector_nvic.c"
#elif defined(SAM3S)
# include "../sam/3s/vector_nvic.c"
#elif defined(SAM3U)
# include "../sam/3u/vector_nvic.c"
#elif defined(SAM3X)
# include "../sam/3x/vector_nvic.c"
#elif defined(SAM4L)
# include "../sam/4l/vector_nvic.c"
#elif defined(SAMD)
# include "../sam/d/vector_nvic.c"
#elif defined(VF6XX)
# include "../vf6xx/vector_nvic.c"
#elif defined(PAC55XX)
# include "../pac55xx/vector_nvic.c"
#elif defined(LM3S) || defined(LM4F)
/* Yes, we use the same interrupt table for both LM3S and LM4F */
# include "../lm3s/vector_nvic.c"
#elif defined(MSP432E4)
# include "../msp432/e4/vector_nvic.c"
#elif defined(SWM050)
# include "../swm050/vector_nvic.c"
#else
# warning "no interrupts defined for chipset;"\
"not allocating space in the vector table"
#define IRQ_HANDLERS
#endif

View File

@@ -0,0 +1,15 @@
/** @addtogroup acmp_file ACMP peripheral API
* @ingroup peripheral_apis
* @brief Analog Comparator helper functions.
*
* <b>NO</b> helper functions exist. Only header definitions are available.
* Delete these lines if/when you add actual helper APIs.
* @copyright See @ref lgpl_license
*/
#include <libopencm3/efm32/acmp.h>
/**@{*/
/**@}*/

View File

@@ -0,0 +1,678 @@
/** @addtogroup adc_file ADC peripheral API
* @ingroup peripheral_apis
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2015 Kuldeep Singh Dhaka <kuldeepdhaka9@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/efm32/adc.h>
/**@{*/
/**
* Set ADC over sampling
* @param[in] adc ADC (use ADCx)
* @param[in] oversamp Oversampling (use ADC_CTRL_OVERSEL_Xx)
*/
void adc_set_oversampling(uint32_t adc, uint32_t oversamp)
{
ADC_CTRL(adc) = (ADC_CTRL(adc) & ~ADC_CTRL_OVERSEL_MASK) | oversamp;
}
/**
* Set ADC warm up
* @param[in] adc ADC (use ADCx)
* @param[in] clocks Clock cycles (1 - 128)
* @note warm-up-time = (@a clocks / HFPERCLK)
*/
void adc_set_warm_up(uint32_t adc, uint8_t clocks)
{
uint32_t timebase = ADC_CTRL_TIMEBASE(clocks - 1);
ADC_CTRL(adc) = (ADC_CTRL(adc) & ~ADC_CTRL_TIMEBASE_MASK) | timebase;
}
/** Clock division factor
* @param[in] adc ADC (use ADCx)
* @param[in] factor Factor (1 - 128)
* @note output-clock = input-clock / @a factor
*/
void adc_set_clock_prescaler(uint32_t adc, uint8_t factor)
{
uint32_t presc = ADC_CTRL_PRESC(factor - 1);
ADC_CTRL(adc) = (ADC_CTRL(adc) & ~ADC_CTRL_PRESC_MASK) | presc;
}
/**
* Set low pass filter mode
* @param[in] adc ADC (use ADCx)
* @param[in] lpfmode Low pass filter mode (use ADC_CTRL_LPFMODE_*)
*/
void adc_set_lowpass_filter(uint32_t adc, uint32_t lpfmode)
{
ADC_CTRL(adc) = (ADC_CTRL(adc) & ~ADC_CTRL_LPFMODE_MASK) | lpfmode;
}
/**
* Enable tail gating
* @param[in] adc ADC (use ADCx)
*/
void adc_enable_tailgating(uint32_t adc)
{
ADC_CTRL(adc) |= ADC_CTRL_TAILGATE;
}
/**
* Disable tail gating
* @param[in] adc ADC (use ADCx)
*/
void adc_disable_tailgating(uint32_t adc)
{
ADC_CTRL(adc) &= ~ADC_CTRL_TAILGATE;
}
/**
* Set warm up mode
* @param[in] adc ADC (use ADCx)
* @param[in] warmupmode Warm Up Mode (use ADC_CTRL_WARMUPMODE_*)
*/
void adc_set_warm_up_mode(uint32_t adc, uint32_t warmupmode)
{
ADC_CTRL(adc) = (ADC_CTRL(adc) & ~ADC_CTRL_WARMUPMODE_MASK)
| warmupmode;
}
/**
* Start ADC in single acquisition
* @param[in] adc ADC (use ADCx)
*/
void adc_single_start(uint32_t adc)
{
ADC_CMD(adc) = ADC_CMD_SINGLESTART;
}
/**
* Stop ADC in single acquisition
* @param[in] adc ADC (use ADCx)
*/
void adc_single_stop(uint32_t adc)
{
ADC_CMD(adc) = ADC_CMD_SINGLESTOP;
}
/**
* Start ADC in scan acquisition
* @param[in] adc ADC (use ADCx)
*/
void adc_scan_start(uint32_t adc)
{
ADC_CMD(adc) = ADC_CMD_SCANSTART;
}
/**
* Stop ADC in scan acquisition
* @param[in] adc ADC (use ADCx)
*/
void adc_scan_stop(uint32_t adc)
{
ADC_CMD(adc) = ADC_CMD_SCANSTOP;
}
/* Single ----------------------------------------------------------- */
/**
* Set single PRS trigger
* @param[in] adc ADC (use ADCx)
* @param[in] prssel PRS Selected (use PRS_CHx)
*/
void adc_set_single_prs_trigger(uint32_t adc, uint8_t prssel)
{
ADC_SINGLECTRL(adc) =
(ADC_SINGLECTRL(adc) & ~ADC_SINGLECTRL_PRSSEL_MASK) |
(ADC_SINGLECTRL_PRSSEL_PRSCHx(prssel));
}
/**
* Enable single PRS Triggering
* @param[in] adc ADC (use ADCx)
*/
void adc_enable_single_prs_trigger(uint32_t adc)
{
ADC_SINGLECTRL(adc) |= ADC_SINGLECTRL_PRSEN;
}
/**
* Disable single PRS Triggering
* @param[in] adc ADC (use ADCx)
*/
void adc_disable_single_prs_trigger(uint32_t adc)
{
ADC_SINGLECTRL(adc) &= ~ADC_SINGLECTRL_PRSEN;
}
/**
* Set single acquisition cycle
* @param[in] adc ADC (use ADCx)
* @param[in] at Acquisition time (use ADC_SINGLECTRL_AT_x)
*/
void adc_set_single_acquisition_cycle(uint32_t adc, uint32_t at)
{
ADC_SINGLECTRL(adc) =
(ADC_SINGLECTRL(adc) & ~ADC_SINGLECTRL_AT_MASK) | at;
}
/**
* Set single reference for acquisition
* @param[in] adc ADC (use ADCx)
* @param[in] ref Reference (use ADC_SINGLECTRL_REF_x)
*/
void adc_set_single_reference(uint32_t adc, uint32_t ref)
{
ADC_SINGLECTRL(adc) =
(ADC_SINGLECTRL(adc) & ~ADC_SINGLECTRL_REF_MASK) | ref;
}
/**
* Set single channel
* @param[in] adc ADC (use ADCx)
* @param[in] ch Channel (use ADC_CHx and ADC_CH_*)
*/
void adc_set_single_channel(uint32_t adc, uint8_t ch)
{
ADC_SINGLECTRL(adc) =
(ADC_SINGLECTRL(adc) & ~ADC_SINGLECTRL_INPUTSEL_MASK) |
ADC_SINGLECTRL_INPUTSEL(ch);
}
/**
* Set single resolution of conversion
* @param[in] adc ADC (use ADCx)
* @param[in] res Resolution (use ADC_SINGLECTRL_RES_*)
*/
void adc_set_single_resolution(uint32_t adc, uint32_t res)
{
ADC_SINGLECTRL(adc) =
(ADC_SINGLECTRL(adc) & ~ADC_SINGLECTRL_RES_MASK) | res;
}
/**
* Set single left aligned output
* @param[in] adc ADC (use ADCx)
*/
void adc_set_single_left_aligned(uint32_t adc)
{
ADC_SINGLECTRL(adc) |= ADC_SINGLECTRL_ADJ;
}
/**
* Set single right aligned output
* @param[in] adc ADC (use ADCx)
*/
void adc_set_single_right_aligned(uint32_t adc)
{
ADC_SINGLECTRL(adc) &= ~ADC_SINGLECTRL_ADJ;
}
/**
* Set single single-ended conversion
* @param[in] adc ADC (use ADCx)
*/
void adc_set_single_single_ended(uint32_t adc)
{
ADC_SINGLECTRL(adc) &= ~ADC_SINGLECTRL_DIFF;
}
/**
* Set single differential conversion
* @param[in] adc ADC (use ADCx)
*/
void adc_set_single_differential(uint32_t adc)
{
ADC_SINGLECTRL(adc) |= ADC_SINGLECTRL_DIFF;
}
/**
* Enable single channel repeated conversion
* @param[in] adc ADC (use ADCx)
*/
void adc_enable_single_repeat_conv(uint32_t adc)
{
ADC_SINGLECTRL(adc) |= ADC_SINGLECTRL_REP;
}
/**
* Disable single repeated conversion
* @param[in] adc ADC (use ADCx)
*/
void adc_disable_single_repeat_conv(uint32_t adc)
{
ADC_SINGLECTRL(adc) &= ~ADC_SINGLECTRL_REP;
}
/* Scan ------------------------------------------------------------- */
/**
* Set scan PRS trigger
* @param[in] adc ADC (use ADCx)
* @param[in] prssel PRS Selected (use PRS_CHx)
*/
void adc_set_scan_prs_trigger(uint32_t adc, uint8_t prssel)
{
ADC_SCANCTRL(adc) =
(ADC_SCANCTRL(adc) & ~ADC_SCANCTRL_PRSSEL_MASK) |
ADC_SCANCTRL_PRSSEL_PRSCHx(prssel);
}
/**
* Enable scan PRS Triggering
* @param[in] adc ADC (use ADCx)
*/
void adc_enable_scan_prs_trigger(uint32_t adc)
{
ADC_SCANCTRL(adc) |= ADC_SCANCTRL_PRSEN;
}
/**
* Disable scan PRS Triggering
* @param[in] adc ADC (use ADCx)
*/
void adc_disable_scan_prs_trigger(uint32_t adc)
{
ADC_SCANCTRL(adc) &= ~ADC_SCANCTRL_PRSEN;
}
/**
* Set scan acquisition cycle
* @param[in] adc ADC (use ADCx)
* @param[in] at Acquisition time (use ADC_SCANCTRL_AT_x)
*/
void adc_set_scan_acquisition_cycle(uint32_t adc, uint32_t at)
{
ADC_SCANCTRL(adc) =
(ADC_SCANCTRL(adc) & ~ADC_SCANCTRL_AT_MASK) | at;
}
/**
* Set scan reference for acquisition
* @param[in] adc ADC (use ADCx)
* @param[in] ref Reference (use ADC_SCANCTRL_REF_x)
*/
void adc_set_scan_reference(uint32_t adc, uint32_t ref)
{
ADC_SCANCTRL(adc) =
(ADC_SCANCTRL(adc) & ~ADC_SCANCTRL_REF_MASK) | ref;
}
/**
* Set scan channel list
* @param[in] adc ADC (use ADCx)
* @param[in] length Length of @a channel
* @param[in] channel channel list (use ADC_CHx)
* @note channel[0] is used as single acuqisition
*/
void adc_set_scan_channel(uint32_t adc, uint8_t length, uint8_t channel[])
{
unsigned i;
uint32_t val = 0;
for (i = 0; i < length; i++) {
val |= 1 << (channel[i] + ADC_SCANCTRL_INPUTSEL_SHIFT);
}
ADC_SCANCTRL(adc) =
(ADC_SCANCTRL(adc) & ~ADC_SCANCTRL_INPUTSEL_MASK) |
(val & ADC_SCANCTRL_INPUTSEL_MASK);
}
/**
* Set scan resolution of conversion
* @param[in] adc ADC (use ADCx)
* @param[in] res Resolution (use ADC_SCANCTRL_RES_*)
*/
void adc_set_scan_resolution(uint32_t adc, uint32_t res)
{
ADC_SCANCTRL(adc) =
(ADC_SCANCTRL(adc) & ~ADC_SCANCTRL_RES_MASK) | res;
}
/**
* Set scan left aligned output
* @param[in] adc ADC (use ADCx)
*/
void adc_set_scan_left_aligned(uint32_t adc)
{
ADC_SCANCTRL(adc) |= ADC_SCANCTRL_ADJ;
}
/**
* Set scan right aligned output
* @param[in] adc ADC (use ADCx)
*/
void adc_set_scan_right_aligned(uint32_t adc)
{
ADC_SCANCTRL(adc) &= ~ADC_SCANCTRL_ADJ;
}
/**
* Set scan single ended conversion
* @param[in] adc ADC (use ADCx)
*/
void adc_set_scan_single_ended(uint32_t adc)
{
ADC_SCANCTRL(adc) &= ~ADC_SCANCTRL_DIFF;
}
/**
* Set scan differential conversion
* @param[in] adc ADC (use ADCx)
*/
void adc_set_scan_differential(uint32_t adc)
{
ADC_SCANCTRL(adc) |= ADC_SCANCTRL_DIFF;
}
/**
* Enable scan repeated conversion
* @param[in] adc ADC (use ADCx)
* @note In SINGLE mode, channel is repeated
* @note In SCAN mode, channel sequence is repeated
*/
void adc_enable_scan_repeat_conv(uint32_t adc)
{
ADC_SCANCTRL(adc) |= ADC_SCANCTRL_REP;
}
/**
* Disable scan repeated conversion
* @param[in] adc ADC (use ADCx)
*/
void adc_disable_scan_repeat_conv(uint32_t adc)
{
ADC_SCANCTRL(adc) &= ~ADC_SCANCTRL_REP;
}
/**
* Enable single result overflow interrupt
* @param[in] adc ADC (use ADCx)
*/
void adc_enable_single_result_overflow_interrupt(uint32_t adc)
{
ADC_IEN(adc) |= ADC_IEN_SINGLEOF;
}
/**
* Disable single result overflow interrupt
* @param[in] adc ADC (use ADCx)
*/
void adc_disable_single_result_overflow_interrupt(uint32_t adc)
{
ADC_IEN(adc) &= ~ADC_IEN_SINGLEOF;
}
/**
* Enable single conversion complete interrupt
* @param[in] adc ADC (use ADCx)
*/
void adc_enable_single_conversion_complete_interrupt(uint32_t adc)
{
ADC_IEN(adc) |= ADC_IEN_SINGLE;
}
/**
* Disable single conversion complete interrupt
* @param[in] adc ADC (use ADCx)
*/
void adc_disable_single_conversion_complete_interrupt(uint32_t adc)
{
ADC_IEN(adc) &= ~ADC_IEN_SINGLE;
}
/**
* Enable scan result overflow interrupt
* @param[in] adc ADC (use ADCx)
*/
void adc_enable_scan_result_overflow_interrupt(uint32_t adc)
{
ADC_IEN(adc) |= ADC_IEN_SCANOF;
}
/**
* Disable scan result overflow interrupt
* @param[in] adc ADC (use ADCx)
*/
void adc_disable_scan_result_overflow_interrupt(uint32_t adc)
{
ADC_IEN(adc) &= ~ADC_IEN_SCANOF;
}
/**
* Disable scan conversion complete interrupt
* @param[in] adc ADC (use ADCx)
*/
void adc_enable_scan_conversion_complete_interrupt(uint32_t adc)
{
ADC_IEN(adc) |= ADC_IEN_SCAN;
}
/**
* Disable scan conversion complete interrupt
* @param[in] adc ADC (use ADCx)
*/
void adc_disable_scan_conversion_complete_interrupt(uint32_t adc)
{
ADC_IEN(adc) &= ~ADC_IEN_SCAN;
}
/**
* Get single result overflow flag
* @param[in] adc ADC (use ADCx)
* @retval true if flag set
* @retval false if flag is not set
*/
bool adc_get_single_result_overflow_flag(uint32_t adc)
{
return (ADC_IF(adc) & ADC_IF_SCANOF) != 0;
}
/**
* Get single conversion complete flag
* @param[in] adc ADC (use ADCx)
* @retval true if flag set
* @retval false if flag is not set
*/
bool adc_get_single_conversion_complete_flag(uint32_t adc)
{
return (ADC_IF(adc) & ADC_IF_SINGLE) != 0;
}
/**
* Get scan result overflow flag
* @param[in] adc ADC (use ADCx)
* @retval true if flag set
* @retval false if flag is not set
*/
bool adc_get_scan_result_overflow_flag(uint32_t adc)
{
return (ADC_IF(adc) & ADC_IF_SCANOF) != 0;
}
/**
* Get scan conversion complete flag
* @param[in] adc ADC (use ADCx)
* @retval true if flag is set
* @retval false if flag is not set
*/
bool adc_get_scan_conversion_complete_flag(uint32_t adc)
{
return (ADC_IF(adc) & ADC_IF_SCAN) != 0;
}
/**
* Set single result overflow flag
* @param[in] adc ADC (use ADCx)
*/
void adc_set_single_result_overflow_flag(uint32_t adc)
{
ADC_IFS(adc) = ADC_IFS_SINGLEOF;
}
/**
* Set single conversion complete flag
* @param[in] adc ADC (use ADCx)
*/
void adc_set_single_conversion_complete_flag(uint32_t adc)
{
ADC_IFS(adc) = ADC_IFS_SINGLE;
}
/**
* Set scan result overflow flag
* @param[in] adc ADC (use ADCx)
*/
void adc_set_scan_result_overflow_flag(uint32_t adc)
{
ADC_IFS(adc) = ADC_IFS_SCANOF;
}
/**
* Set scan conversion complete flag
* @param[in] adc ADC (use ADCx)
*/
void adc_set_scan_conversion_complete_flag(uint32_t adc)
{
ADC_IFS(adc) = ADC_IFS_SCAN;
}
/**
* Clear single result overflow flag
* @param[in] adc ADC (use ADCx)
*/
void adc_clear_single_result_overflow_flag(uint32_t adc)
{
ADC_IFC(adc) = ADC_IFC_SINGLEOF;
}
/**
* Clear single conversion complete flag
* @param[in] adc ADC (use ADCx)
*/
void adc_clear_single_conversion_complete_flag(uint32_t adc)
{
ADC_IFC(adc) = ADC_IFC_SINGLE;
}
/**
* Clear scan result overflow flag
* @param[in] adc ADC (use ADCx)
*/
void adc_clear_scan_result_overflow_flag(uint32_t adc)
{
ADC_IFC(adc) = ADC_IFC_SCANOF;
}
/**
* Clear scan conversion complete flag
* @param[in] adc ADC (use ADCx)
*/
void adc_clear_scan_conversion_complete_flag(uint32_t adc)
{
ADC_IFC(adc) = ADC_IFC_SCAN;
}
/**
* Get result from last scan conversion
* @param[in] adc ADC (use ADCx)
* @return result
*/
uint32_t adc_single_data(uint32_t adc)
{
return ADC_SINGLEDATA(adc);
}
/**
* Get result from last scan conversion
* @param[in] adc ADC (use ADCx)
* @return result
*/
uint32_t adc_scan_data(uint32_t adc)
{
return ADC_SCANDATA(adc);
}
/**
* Get result from last single conversion (peak)
* Reading result using this function will not clear
* SINGLEDV in ADC_STATUS or SINGLE DMA request.
* @param[in] adc ADC (use ADCx)
* @return result
*/
uint32_t adc_single_data_peak(uint32_t adc)
{
return ADC_SINGLEDATAP(adc);
}
/**
* Get result from last scan conversion (peak)
* Reading result using this function will not clear
* SCANDV in ADC_STATUS or SCAN DMA request.
* @param[in] adc ADC (use ADCx)
* @return result
*/
uint32_t adc_scan_data_peak(uint32_t adc)
{
return ADC_SCANDATAP(adc);
}
/**
* Set ADC scan gain calibration
* @param[in] adc ADC (use ADCx)
* @param scan_gain calibration of gain for internal ref
*/
void adc_set_calibration_scan_gain(uint32_t adc, uint8_t scan_gain)
{
ADC_CAL(adc) = (ADC_CAL(adc) & ADC_CAL_SCANGAIN_MASK) | scan_gain;
}
/**
* Set ADC scan offset calibration
* @param[in] adc ADC (use ADCx)
* @param scan_offset calibration of offset for internal ref
*/
void adc_set_calibration_scan_offset(uint32_t adc, uint8_t scan_offset)
{
ADC_CAL(adc) = (ADC_CAL(adc) & ADC_CAL_SCANOFF_MASK) | scan_offset;
}
/**
* Set ADC single gain calibration
* @param[in] adc ADC (use ADCx)
* @param single_gain calibration of gain for internal ref
*/
void adc_set_calibration_single_gain(uint32_t adc, uint8_t single_gain)
{
ADC_CAL(adc) = (ADC_CAL(adc) & ADC_CAL_SINGLEGAIN_MASK) | single_gain;
}
/**
* Set ADC single offset calibration
* @param[in] adc ADC (use ADCx)
* @param single_offset calibration of offset for internal ref
*/
void adc_set_calibration_single_offset(uint32_t adc, uint8_t single_offset)
{
ADC_CAL(adc) = (ADC_CAL(adc) & ADC_CAL_SINGLEOFF_MASK) | single_offset;
}
/**@}*/

View File

@@ -0,0 +1,15 @@
/** @addtogroup burtc_file BURTC peripheral API
* @ingroup peripheral_apis
* @brief Backup RTC helper functions.
*
* <b>NO</b> helper functions exist. Only header definitions are available.
* Delete these lines if/when you add actual helper APIs.
* @copyright See @ref lgpl_license
*/
#include <libopencm3/efm32/burtc.h>
/**@{*/
/**@}*/

View File

@@ -0,0 +1,279 @@
/** @addtogroup cmu_file CMU peripheral API
* @ingroup peripheral_apis
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2015 Kuldeep Singh Dhaka <kuldeepdhaka9@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/efm32/cmu.h>
#include <libopencm3/efm32/msc.h>
/**@{*/
/**
* Enable CMU registers lock.
*/
void cmu_enable_lock(void)
{
CMU_LOCK = CMU_LOCK_LOCKKEY_LOCK;
}
/**
* Disable CMU registers lock
*/
void cmu_disable_lock(void)
{
CMU_LOCK = CMU_LOCK_LOCKKEY_UNLOCK;
}
/**
* Get CMU register lock flag
* @retval true if flag is set
* @retval false if flag is not set
*/
bool cmu_get_lock_flag(void)
{
return (CMU_LOCK & CMU_LOCK_LOCKKEY_MASK) == CMU_LOCK_LOCKKEY_LOCKED;
}
#define _CMU_REG(i) MMIO32(CMU_BASE + ((i) >> 5))
#define _CMU_BIT(i) (1 << ((i) & 0x1f))
/**
* @brief Enable Peripheral Clock in running mode.
*
* Enable the clock on particular peripheral.
*
* @param[in] clken Peripheral Name
*
* For available constants, see @a enum::cmu_periph_clken (CMU_LEUART1 for
* example)
*/
void cmu_periph_clock_enable(enum cmu_periph_clken clken)
{
_CMU_REG(clken) |= _CMU_BIT(clken);
}
/**
* @brief Disable Peripheral Clock in running mode.
* Disable the clock on particular peripheral.
*
* @param[in] clken Peripheral Name
*
* For available constants, see @a enum::cmu_periph_clken (CMU_LEUART1 for
* example)
*/
void cmu_periph_clock_disable(enum cmu_periph_clken clken)
{
_CMU_REG(clken) &= ~_CMU_BIT(clken);
}
/**
* Turn on Oscillator
* @param[in] osc enum cmu_osc Oscillator name
*/
void cmu_osc_on(enum cmu_osc osc)
{
switch (osc) {
case HFRCO:
CMU_OSCENCMD = CMU_OSCENCMD_HFRCOEN;
break;
case LFRCO:
CMU_OSCENCMD = CMU_OSCENCMD_LFRCOEN;
break;
case ULFRCO:
/* TODO: but how? */
break;
case HFXO:
CMU_OSCENCMD = CMU_OSCENCMD_HFXOEN;
break;
case LFXO:
CMU_OSCENCMD = CMU_OSCENCMD_LFXOEN;
break;
case AUXHFRCO:
CMU_OSCENCMD = CMU_OSCENCMD_AUXHFRCOEN;
break;
}
}
/**
* Turn off Oscillator
* @param[in] osc enum cmu_osc Oscillator name
*/
void cmu_osc_off(enum cmu_osc osc)
{
switch (osc) {
case HFRCO:
CMU_OSCENCMD = CMU_OSCENCMD_HFRCODIS;
break;
case LFRCO:
CMU_OSCENCMD = CMU_OSCENCMD_LFRCODIS;
break;
case ULFRCO:
/* TODO: but how? */
break;
case HFXO:
CMU_OSCENCMD = CMU_OSCENCMD_HFXODIS;
break;
case LFXO:
CMU_OSCENCMD = CMU_OSCENCMD_LFXODIS;
break;
case AUXHFRCO:
CMU_OSCENCMD = CMU_OSCENCMD_AUXHFRCODIS;
break;
}
}
/**
* Get Oscillator read flag
* @param[in] osc enum cmu_osc Oscillator name
* @retval true if flag is set
* @retval false if flag is not set
*/
bool cmu_osc_ready_flag(enum cmu_osc osc)
{
switch (osc) {
case HFRCO:
return (CMU_STATUS & CMU_STATUS_HFRCORDY) != 0;
break;
case LFRCO:
return (CMU_STATUS & CMU_STATUS_LFRCORDY) != 0;
break;
case ULFRCO:
/* TODO: but how? */
break;
case HFXO:
return (CMU_STATUS & CMU_STATUS_HFXORDY) != 0;
break;
case LFXO:
return (CMU_STATUS & CMU_STATUS_LFXORDY) != 0;
break;
case AUXHFRCO:
return (CMU_STATUS & CMU_STATUS_AUXHFRCORDY) != 0;
break;
}
return false;
}
/**
* Wait till oscillator is not ready
* @param[in] osc enum cmu_osc Oscillator name
*/
void cmu_wait_for_osc_ready(enum cmu_osc osc)
{
switch (osc) {
case HFRCO:
while ((CMU_STATUS & CMU_STATUS_HFRCORDY) == 0);
break;
case LFRCO:
while ((CMU_STATUS & CMU_STATUS_LFRCORDY) == 0);
break;
case ULFRCO:
/* TODO: but how? */
break;
case HFXO:
while ((CMU_STATUS & CMU_STATUS_HFXORDY) == 0);
break;
case LFXO:
while ((CMU_STATUS & CMU_STATUS_LFXORDY) == 0);
break;
case AUXHFRCO:
while ((CMU_STATUS & CMU_STATUS_AUXHFRCORDY) == 0);
break;
}
}
/**
* Set HFCLK clock source
* @param[in] osc enum cmu_osc Oscillator name
* @note calling cmu_set_hfclk_source() do not set source immediately, use
* @a cmu_get_hfclk_source() to verify that the source has been set.
* @see cmu_get_hfclk_source()
*/
void cmu_set_hfclk_source(enum cmu_osc osc)
{
switch (osc) {
case HFXO:
CMU_CMD = CMU_CMD_HFCLKSEL_HFXO;
break;
case HFRCO:
CMU_CMD = CMU_CMD_HFCLKSEL_HFRCO;
break;
case LFXO:
CMU_CMD = CMU_CMD_HFCLKSEL_LFXO;
break;
case LFRCO:
CMU_CMD = CMU_CMD_HFCLKSEL_LFRCO;
break;
default:
/* not applicable */
return;
}
}
enum cmu_osc cmu_get_hfclk_source(void)
{
uint32_t status = CMU_STATUS;
if (status & CMU_STATUS_LFXOSEL) {
return LFXO;
} else if (status & CMU_STATUS_LFRCOSEL) {
return LFRCO;
} else if (status & CMU_STATUS_HFXOSEL) {
return HFXO;
} else if (status & CMU_STATUS_HFRCOSEL) {
return HFRCO;
}
/* never reached */
return (enum cmu_osc) -1;
}
/**
* HFXO output 48Mhz and core running at 48Mhz
*/
void cmu_clock_setup_in_hfxo_out_48mhz(void)
{
/* configure HFXO and prescaler */
CMU_HFCORECLKDIV = CMU_HFCORECLKDIV_HFCORECLKDIV_NODIV
| CMU_HFCORECLKDIV_HFCORECLKLEDIV;
CMU_CTRL = (CMU_CTRL
& ~(CMU_CTRL_HFCLKDIV_MASK | CMU_CTRL_HFXOBUFCUR_MASK))
| (CMU_CTRL_HFCLKDIV_NODIV
| CMU_CTRL_HFXOBUFCUR_BOOSTABOVE32MHZ);
/* enable HFXO */
cmu_osc_on(HFXO);
/* wait for HFXO */
cmu_wait_for_osc_ready(HFXO);
/* set flash wait state */
MSC_READCTRL = (MSC_READCTRL & ~MSC_READCTRL_MODE_MASK)
| MSC_READCTRL_MODE_WS2;
/* switch to HFXO */
cmu_set_hfclk_source(HFXO);
/* wait till HFXO not selected */
while (cmu_get_hfclk_source() != HFXO);
}
/**@}*/

View File

@@ -0,0 +1,175 @@
/** @addtogroup dac_file DAC peripheral API
* @ingroup peripheral_apis
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2015 Kuldeep Singh Dhaka <kuldeepdhaka9@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/efm32/dac.h>
/**@{*/
/**
* Set DAC refresh cycle
* @param[in] dac DAC (use DACx)
* @param[in] refrsel (use DAC_CTRL_REFRSEL_*CYCLES)
* @see dac_disable_auto_refresh()
* @see dac_enable_auto_refresh()
*/
void dac_set_refresh_cycle(uint32_t dac, uint32_t refrsel)
{
DAC_CTRL(dac) = (DAC_CTRL(dac) & ~DAC_CTRL_REFRSEL_MASK) | refrsel;
}
/**
* Set DAC clock prescaler
* @param[in] dac DAC (use DACx)
* @param[in] presc Prescaler (use DAC_CTRL_PRESC_*)
*/
void dac_set_clock_prescaler(uint32_t dac, uint32_t presc)
{
DAC_CTRL(dac) = (DAC_CTRL(dac) & ~DAC_CTRL_PRESC_MASK) | presc;
}
/**
* Set DAC reference
* @param[in] dac DAC (use DACx)
* @param[in] refsel Reference (DAC_CTRL_REFSEL_*)
*/
void dac_set_reference(uint32_t dac, uint32_t refsel)
{
DAC_CTRL(dac) = (DAC_CTRL(dac) & ~DAC_CTRL_REFSEL_MASK) | refsel;
}
/**
* Set DAC output mode
* @param[in] dac DAC (use DACx)
* @param[in] outmode Output mode (DAC_CTRL_OUTMODE_*)
*/
void dac_set_out_mode(uint32_t dac, uint32_t outmode)
{
DAC_CTRL(dac) = (DAC_CTRL(dac) & ~DAC_CTRL_OUTMODE_MASK) | outmode;
}
/**
* Set conversion mode
* @param[in] dac DAC (use DACx)
* @param[in] convmode Conversion mode (use DAC_CTRL_CONVMODE_*)
*/
void dac_set_conversion_mode(uint32_t dac, uint32_t convmode)
{
DAC_CTRL(dac) = (DAC_CTRL(dac) & ~DAC_CTRL_CONVMODE_MASK) | convmode;
}
/**
* Enable Sine wave on output
* @param[in] dac DAC (use DACx)
*/
void dac_enable_sine(uint32_t dac)
{
DAC_CTRL(dac) |= DAC_CTRL_SINMODE;
}
/**
* Disable Sine wave on output
* @param[in] dac DAC (use DACx)
*/
void dac_disable_sine(uint32_t dac)
{
DAC_CTRL(dac) &= ~DAC_CTRL_SINMODE;
}
/**
* Set PRS trigger source on DAC channel
* @param[in] dac DAC (use DACx)
* @param[in] dac_chan DAC Channel (use DAC_CHx)
* @param[in] prs_chan PRS Channel (use PRS_CHx)
*/
void dac_set_prs_trigger(uint32_t dac, enum dac_ch dac_chan,
enum prs_ch prs_chan)
{
uint32_t ch_ctrl = DAC_CHx_CTRL(dac, dac_chan);
ch_ctrl &= DAC_CH_CTRL_PRSSEL_MASK;
ch_ctrl |= DAC_CH_CTRL_PRSSEL(prs_chan);
DAC_CHx_CTRL(dac, dac_chan) = ch_ctrl;
}
/**
* Enable PRS triggerring
* @param[in] dac DAC (use DACx)
* @param[in] ch DAC Channel (use DAC_CHx)
*/
void dac_enable_prs_trigger(uint32_t dac, enum dac_ch ch)
{
DAC_CHx_CTRL(dac, ch) |= DAC_CH_CTRL_PRSEN;
}
/**
* Disable PRS triggerring
* @param[in] dac DAC (use DACx)
* @param[in] ch DAC Channel (use DAC_CHx)
*/
void dac_disable_prs_trigger(uint32_t dac, enum dac_ch ch)
{
DAC_CHx_CTRL(dac, ch) &= ~DAC_CH_CTRL_PRSEN;
}
/**
* Enable auto refresh
* @param[in] dac DAC (use DACx)
* @param[in] ch DAC Channel (use DAC_CHx)
*/
void dac_enable_auto_refresh(uint32_t dac, enum dac_ch ch)
{
DAC_CHx_CTRL(dac, ch) |= DAC_CH_CTRL_REFREN;
}
/**
* Disable auto refresh
* @param[in] dac DAC (use DACx)
* @param[in] ch DAC Channel (use DAC_CHx)
*/
void dac_disable_auto_refresh(uint32_t dac, enum dac_ch ch)
{
DAC_CHx_CTRL(dac, ch) &= ~DAC_CH_CTRL_REFREN;
}
/**
* Enable channel
* @param[in] dac DAC (use DACx)
* @param[in] ch DAC Channel (use DAC_CHx)
*/
void dac_enable_channel(uint32_t dac, enum dac_ch ch)
{
DAC_CHx_CTRL(dac, ch) |= DAC_CH_CTRL_EN;
}
/**
* Disable channel
* @param[in] dac DAC (use DACx)
* @param[in] ch DAC Channel (use DAC_CHx)
*/
void dac_disable_channel(uint32_t dac, enum dac_ch ch)
{
DAC_CHx_CTRL(dac, ch) &= ~DAC_CH_CTRL_REFREN;
}
/**@}*/

View File

@@ -0,0 +1,627 @@
/** @addtogroup dma_file DMA peripheral API
* @ingroup peripheral_apis
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2015 Kuldeep Singh Dhaka <kuldeepdhaka9@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/efm32/dma.h>
/**@{*/
#define CHANNEL_SUPPORT_LOOP(ch) (((ch) == DMA_CH0) || ((ch) == DMA_CH1))
/**
* Enable DMA with privileged access
* @see dma_enable_with_unprivileged_access()
*/
void dma_enable_with_privileged_access(void)
{
DMA_CONFIG = DMA_CONFIG_EN | DMA_CONFIG_CHPROT;
}
/**
* Enable DMA with un-privileged access
* @see dma_enable_with_privileged_access()
*/
void dma_enable_with_unprivileged_access(void)
{
DMA_CONFIG = DMA_CONFIG_EN;
}
/**
* same as @a dma_enable_with_unprivileged_access()
* @see dma_enable_with_unprivileged_access()
*/
void dma_enable(void)
{
dma_enable_with_unprivileged_access();
}
/**
* Disable DMA
*/
void dma_disable(void)
{
DMA_CONFIG = 0;
}
/**
* Set channel's descriptor address
* @param[in] desc_base Address of channel's descriptor address
* @note @a desc_base 8LSB's should be 0x00
*/
void dma_set_desc_address(uint32_t desc_base)
{
if (desc_base & 0xFF) {
return;
}
DMA_CTRLBASE = desc_base;
}
/**
* Get channel wait on request status flag
* @retval true if flag is set
* @retval false if flag is not set
*/
bool dma_get_wait_on_request_flag(enum dma_ch ch)
{
uint32_t mask = DMA_CHWAITSTATUS_CHxWAITSTATUS(ch);
return (DMA_CHWAITSTATUS & mask) != 0;
}
/**
* Generate a software request on channel
* @param[in] ch Channel (use DMA_CHx)
*/
void dma_generate_software_request(enum dma_ch ch)
{
DMA_CHSWREQ = DMA_CHSWREQ_CHxSWREQ(ch);
}
/**
* Enable channel burst only
* @param[in] ch Channel (use DMA_CHx)
*/
void dma_enable_burst_only(enum dma_ch ch)
{
DMA_CHUSEBURSTS = DMA_CHUSEBURSTS_CHxSUSEBURSTS(ch);
}
/**
* Enable channel single and burst
* @param[in] ch Channel (use DMA_CHx)
*/
void dma_enable_single_and_burst(enum dma_ch ch)
{
DMA_CHUSEBURSTC = DMA_CHUSEBURSTC_CHxSUSEBURSTC(ch);
}
/**
* Enable channel peripherial request
* @param[in] ch Channel (use DMA_CHx)
*/
void dma_enable_periph_request(enum dma_ch ch)
{
DMA_CHREQMASKC = DMA_CHREQMASKC_CHxSREQMASKC(ch);
}
/**
* Disable channel peripherial request
* @param[in] ch Channel (use DMA_CHx)
*/
void dma_disable_periph_request(enum dma_ch ch)
{
DMA_CHREQMASKS = DMA_CHREQMASKS_CHxSREQMASKS(ch);
}
/**
* Enable channel
* @param[in] ch Channel (use DMA_CHx)
*/
void dma_enable_channel(enum dma_ch ch)
{
DMA_CHENS = DMA_CHENS_CHxSENS(ch);
}
/**
* Disable channel
* @param[in] ch Channel (use DMA_CHx)
*/
void dma_disable_channel(enum dma_ch ch)
{
DMA_CHENC = DMA_CHENC_CHxSENC(ch);
}
/**
* Disable channel alternate structure
* @param[in] ch Channel (use DMA_CHx)
*/
void dma_disable_alternate_structure(enum dma_ch ch)
{
DMA_CHALTC = DMA_CHALTC_CHxSALTC(ch);
}
/**
* Enable channel alternate structure
* @param[in] ch Channel (use DMA_CHx)
*/
void dma_enable_alternate_structure(enum dma_ch ch)
{
DMA_CHALTS = DMA_CHALTS_CHxSALTS(ch);
}
/**
* Enable channel high priority
* @param[in] ch Channel (use DMA_CHx)
*/
void dma_enable_priority(enum dma_ch ch)
{
DMA_CHPRIS = DMA_CHPRIS_CHxSPRIC(ch);
}
/**
* Disable channel high priority
* @param[in] ch Channel (use DMA_CHx)
*/
void dma_disable_priority(enum dma_ch ch)
{
DMA_CHPRIC = DMA_CHPRIC_CHxSPRIC(ch);
}
/**
* Get bus error flag
* @retval true if flag is set
* @retval false if flag is not set
*/
bool dma_get_bus_error_flag(void)
{
return (DMA_ERRORC & DMA_ERRORC_ERRORC) != 0;
}
/**
* Clear bus error flag
*/
void dma_clear_bus_error_flag(void)
{
DMA_ERRORC = DMA_ERRORC_ERRORC;
}
/**
* Get channel request flag
* @param[in] ch Channel (use DMA_CHx)
* @retval true if flag is set
* @retval false if flag is not set
*/
bool dma_get_request_flag(enum dma_ch ch)
{
uint32_t mask = DMA_CHREQSTATUS_CHxSREQSTATUS(ch);
return (DMA_CHREQSTATUS & mask) != 0;
}
/**
* Get bus error interrupt flag
* @retval true if flag is set
* @retval false if flag is not set
*/
bool dma_get_bus_error_interrupt_flag(void)
{
return (DMA_IF & DMA_IF_ERR) != 0;
}
/**
* Get channel done interrupt flag
* @param[in] ch Channel (use DMA_CHx)
* @retval true if flag is set
* @retval false if flag is not set
*
*/
bool dma_get_done_interrupt_flag(enum dma_ch ch)
{
return (DMA_IF & DMA_IF_CHxDONE(ch)) != 0;
}
/**
* Set bus error interrupt flag
*/
void dma_set_bus_error_interrupt_flag(void)
{
DMA_IFS = DMA_IFS_ERR;
}
/**
* Set channel done interrupt flag
* @param[in] ch Channel (use DMA_CHx)
*/
void dma_set_done_interrupt_flag(enum dma_ch ch)
{
DMA_IFS = DMA_IFS_CHxDONE(ch);
}
/**
* Clear bus error interrupt flag
*/
void dma_clear_bus_error_interrupt_flag(void)
{
DMA_IFC = DMA_IFC_ERR;
}
/**
* Clear channel done interrupt flag
* @param[in] ch Channel (use DMA_CHx)
*/
void dma_clear_done_interrupt_flag(enum dma_ch ch)
{
DMA_IFC = DMA_IFC_CHxDONE(ch);
}
/**
* Enable bus error interrupt
*/
void dma_enable_bus_error_interrupt(void)
{
DMA_IEN |= DMA_IEN_ERR;
}
/**
* Disable bus error interrupt
*/
void dma_disable_bus_error_interrupt(void)
{
DMA_IEN &= ~DMA_IEN_ERR;
}
/**
* Enable channel done interrupt
* @param[in] ch Channel (use DMA_CHx)
*/
void dma_enable_done_interrupt(enum dma_ch ch)
{
DMA_IEN |= DMA_IEN_CHxDONE(ch);
}
/**
* Disable channel done interrupt
* @param[in] ch Channel (use DMA_CHx)
*/
void dma_disable_done_interrupt(enum dma_ch ch)
{
DMA_IEN &= ~DMA_IEN_CHxDONE(ch);
}
/**
* Set channel source
* @param[in] ch Channel (use DMA_CHx)
* @param[in] source Source (use DMA_CH_CTRL_SOURCESEL_*)
*/
void dma_set_source(enum dma_ch ch, uint32_t source)
{
DMA_CHx_CTRL(ch) = (DMA_CHx_CTRL(ch) & ~DMA_CH_CTRL_SOURCESEL_MASK)
| source;
}
/**
* Set channel source signal
* @param[in] ch Channel (use DMA_CHx)
* @param[in] signal Signal (use DMA_CH_CTRL_SIGSEL_*)
*/
void dma_set_signal(enum dma_ch ch, uint32_t signal)
{
DMA_CHx_CTRL(ch) = (DMA_CHx_CTRL(ch) & ~DMA_CH_CTRL_SIGSEL_MASK)
| signal;
}
/**
* Reset channel
* @param[in] ch Channel (use DMA_CHx)
*/
void dma_channel_reset(enum dma_ch ch)
{
/* Disable channel */
DMA_CHENC = DMA_CHENC_CHxSENC(ch);
/* reset channel alternate desc */
DMA_CHALTC = DMA_CHALTC_CHxSALTC(ch);
/* reset channel priority */
DMA_CHPRIC = DMA_CHPRIC_CHxSPRIC(ch);
/* clear channel interrupt */
DMA_IFC = DMA_IFC_CHxDONE(ch);
/* disable loop */
if (CHANNEL_SUPPORT_LOOP(ch)) {
DMA_LOOPx(ch) = 0;
}
/* reset signal {source, select} */
DMA_CHx_CTRL(ch) = 0;
}
/**
* Set channel loop width to ( @a count + 1)
* @param[in] ch Channel (use DMA_CHx)
* @param[in] count Count
* @note @a count is expected to be equal to (n_minus_1 + 1)
*/
void dma_set_loop_count(enum dma_ch ch, uint16_t count)
{
if (!CHANNEL_SUPPORT_LOOP(ch)) {
return;
}
DMA_LOOPx(ch) = (DMA_LOOPx(ch) & ~DMA_LOOP_WIDTH_MASK)
| DMA_LOOP_WIDTH(count - 1);
}
/**
* Enable channel loop
* @param[in] ch Channel (use DMA_CHx)
*/
void dma_enable_loop(enum dma_ch ch)
{
if (!CHANNEL_SUPPORT_LOOP(ch)) {
return;
}
DMA_LOOPx(ch) |= DMA_LOOP_EN;
}
/**
* Disable channel loop
* @param[in] ch Channel (use DMA_CHx)
*/
void dma_disable_loop(enum dma_ch ch)
{
if (!CHANNEL_SUPPORT_LOOP(ch)) {
return;
}
DMA_LOOPx(ch) &= ~DMA_LOOP_EN;
}
/**
* Set desination size
* @param[in] desc_base start of memory location that contain channel
* descriptor
* @param[in] ch Channel (use DMA_CHx)
* @param[in] size Size (use DMA_MEM_*)
*/
void dma_desc_set_dest_size(uint32_t desc_base, enum dma_ch ch,
enum dma_mem size)
{
uint32_t cfg = DMA_DESC_CHx_CFG(desc_base, ch);
cfg &= ~DMA_DESC_CH_CFG_DEST_SIZE_MASK;
cfg |= DMA_DESC_CH_CFG_DEST_SIZE(size);
DMA_DESC_CHx_CFG(desc_base, ch) = cfg;
}
/**
* Set destination increment
* @param[in] desc_base start of memory location that contain channel
* descriptor
* @param[in] ch Channel (use DMA_CHx)
* @param[in] inc Increment (use DMA_MEM_*)
*/
void dma_desc_set_dest_inc(uint32_t desc_base, enum dma_ch ch,
enum dma_mem inc)
{
uint32_t cfg = DMA_DESC_CHx_CFG(desc_base, ch);
cfg &= ~DMA_DESC_CH_CFG_DEST_INC_MASK;
cfg |= DMA_DESC_CH_CFG_DEST_INC(inc);
DMA_DESC_CHx_CFG(desc_base, ch) = cfg;
}
/**
* Set source size
* @param[in] desc_base start of memory location that contain channel
* descriptor
* @param[in] ch Channel (use DMA_CHx)
* @param[in] size Size (use DMA_MEM_*)
*/
void dma_desc_set_src_size(uint32_t desc_base, enum dma_ch ch,
enum dma_mem size)
{
uint32_t cfg = DMA_DESC_CHx_CFG(desc_base, ch);
cfg &= ~DMA_DESC_CH_CFG_SRC_SIZE_MASK;
cfg |= DMA_DESC_CH_CFG_SRC_SIZE(size);
DMA_DESC_CHx_CFG(desc_base, ch) = cfg;
}
/**
* Set source increment
* @param[in] desc_base start of memory location that contain channel
* descriptor
* @param[in] ch Channel (use DMA_CHx)
* @param[in] inc Increment (use DMA_MEM_*)
*/
void dma_desc_set_src_inc(uint32_t desc_base, enum dma_ch ch, enum dma_mem inc)
{
uint32_t cfg = DMA_DESC_CHx_CFG(desc_base, ch);
cfg &= ~DMA_DESC_CH_CFG_SRC_INC_MASK;
cfg |= DMA_DESC_CH_CFG_SRC_INC(inc);
DMA_DESC_CHx_CFG(desc_base, ch) = cfg;
}
/**
* Set R Power
* @param[in] desc_base start of memory location that contain channel
* descriptor
* @param[in] ch Channel (use DMA_CHx)
* @param[in] r_power R Power (Use DMA_R_POWER_*)
*/
void dma_desc_set_r_power(uint32_t desc_base, enum dma_ch ch,
enum dma_r_power r_power)
{
uint32_t cfg = DMA_DESC_CHx_CFG(desc_base, ch);
cfg &= ~DMA_DESC_CH_CFG_R_POWER_MASK;
cfg |= DMA_DESC_CH_CFG_R_POWER(r_power);
DMA_DESC_CHx_CFG(desc_base, ch) = cfg;
}
/**
* Enable next useburst
* @param[in] desc_base start of memory location that contain channel
* descriptor
* @param[in] ch Channel (use DMA_CHx)
*/
void dma_desc_enable_next_useburst(uint32_t desc_base, enum dma_ch ch)
{
DMA_DESC_CHx_CFG(desc_base, ch) &= ~DMA_DESC_CH_CFG_NEXT_USEBURST;
}
/**
* Disable next useburst
* @param[in] desc_base start of memory location that contain channel
* descriptor
* @param[in] ch Channel (use DMA_CHx)
*/
void dma_desc_disable_next_useburst(uint32_t desc_base, enum dma_ch ch)
{
DMA_DESC_CHx_CFG(desc_base, ch) |= DMA_DESC_CH_CFG_NEXT_USEBURST;
}
/**
* Set number (count) of transfer to be performed
* @param[in] desc_base start of memory location that contain channel
* descriptor
* @param[in] ch Channel (use DMA_CHx)
* @param[in] count Count
*/
void dma_desc_set_count(uint32_t desc_base, enum dma_ch ch, uint16_t count)
{
uint32_t cfg = DMA_DESC_CHx_CFG(desc_base, ch);
cfg &= ~DMA_DESC_CH_CFG_N_MINUS_1_MASK;
cfg |= DMA_DESC_CH_CFG_N_MINUS_1(count - 1);
DMA_DESC_CHx_CFG(desc_base, ch) = cfg;
}
/**
* Store user data field in channel descriptor
* @param[in] desc_base start of memory location that contain channel
* descriptor
* @param[in] ch Channel (use DMA_CHx)
* @param[in] user_data User data
*/
void dma_desc_set_user_data(uint32_t desc_base, enum dma_ch ch,
uint32_t user_data)
{
DMA_DESC_CHx_USER_DATA(desc_base, ch) = user_data;
}
/**
* Extract user data field from channel descriptor
* @param[in] desc_base start of memory location that contain channel
* descriptor
* @param[in] ch Channel (use DMA_CHx)
* @return user data
*/
uint32_t dma_desc_get_user_data(uint32_t desc_base, enum dma_ch ch)
{
return DMA_DESC_CHx_USER_DATA(desc_base, ch);
}
/**
* Calculate end from start address.
*
* @details
* See "8.4.3.4 Address calculation" p68, EFM32LG-RM "d0183_Rev1.10"
*
* @param[in] start address to start of memory
* @param[in] inc Increment (use DMA_MEM_*)
* @param[in] n_minus_1 the number of transfers minus 1 (ie count - 1)
* @return the calculate end address
* @note can be used to calculate {source, destination} end address
*/
static inline uint32_t dma_calc_end_from_start(uint32_t start, uint8_t inc,
uint16_t n_minus_1)
{
switch (inc) {
case DMA_MEM_BYTE:
return start + n_minus_1;
case DMA_MEM_HALF_WORD:
return start + (n_minus_1 << 1);
case DMA_MEM_WORD:
return start + (n_minus_1 << 2);
case DMA_MEM_NONE:
return start;
}
return 0;
}
/**
* Assign Source address to DMA Channel
* @param[in] desc_base start of memory location that contain channel
* descriptor
* @param[in] ch Channel (use DMA_CHx)
* @param[in] src_start Source data start address
* this function uses @ref dma_calc_end_from_start to calculate the
* src data end address from @a src_start
* @note dma_desc_set_count() should be called first.
* @note dma_desc_set_src_inc() should be called first.
*/
void dma_desc_set_src_address(uint32_t desc_base, enum dma_ch ch,
uint32_t src_start)
{
uint32_t cfg = DMA_DESC_CHx_CFG(desc_base, ch);
uint8_t inc = (cfg & DMA_DESC_CH_CFG_SRC_INC_MASK)
>> DMA_DESC_CH_CFG_SRC_INC_SHIFT;
uint16_t n_minus_1 = (cfg & DMA_DESC_CH_CFG_N_MINUS_1_MASK)
>> DMA_DESC_CH_CFG_N_MINUS_1_SHIFT;
uint32_t src_end = dma_calc_end_from_start(src_start, inc, n_minus_1);
DMA_DESC_CHx_SRC_DATA_END_PTR(desc_base, ch) = src_end;
}
/**
* Assign Destination address to DMA Channel
* @param[in] desc_base start of memory location that contain channel
* descriptor
* @param[in] ch Channel (use DMA_CHx)
* @param[in] dest_start Destination data start address
* this function uses @ref dma_calc_end_from_start to calculate the
* dest data end address from @a dest_start
* @note dma_desc_set_count() should be called first.
* @note dma_desc_set_dest_inc() should be called first.
*/
void dma_desc_set_dest_address(uint32_t desc_base, enum dma_ch ch,
uint32_t dest_start)
{
uint32_t cfg = DMA_DESC_CHx_CFG(desc_base, ch);
uint8_t inc = (cfg & DMA_DESC_CH_CFG_DEST_INC_MASK)
>> DMA_DESC_CH_CFG_DEST_INC_SHIFT;
uint16_t n_minus_1 = (cfg & DMA_DESC_CH_CFG_N_MINUS_1_MASK)
>> DMA_DESC_CH_CFG_N_MINUS_1_SHIFT;
uint32_t dest_end = dma_calc_end_from_start(dest_start, inc,
n_minus_1);
DMA_DESC_CHx_DEST_DATA_END_PTR(desc_base, ch) = dest_end;
}
/**
* Set the channel mode ("Cycle control")
* @param[in] desc_base start of memory location that contain channel
* descriptor
* @param[in] ch Channel (use DMA_CHx)
* @param[in] mode Mode (use DMA_MODE_*)
*/
void dma_desc_set_mode(uint32_t desc_base, enum dma_ch ch, enum dma_mode mode)
{
uint32_t cfg = DMA_DESC_CHx_CFG(desc_base, ch);
cfg &= ~DMA_DESC_CH_CFG_CYCLE_CTRL_MASK;
cfg |= DMA_DESC_CH_CFG_CYCLE_CTRL(mode);
DMA_DESC_CHx_CFG(desc_base, ch) = cfg;
}
/**@}*/

View File

@@ -0,0 +1,15 @@
/** @addtogroup emu_file EMU peripheral API
* @ingroup peripheral_apis
* @brief Energy Management Unit helper functions.
*
* <b>NO</b> helper functions exist. Only header definitions are available.
* Delete these lines if/when you add actual helper APIs.
* @copyright See @ref lgpl_license
*/
#include <libopencm3/efm32/emu.h>
/**@{*/
/**@}*/

View File

@@ -0,0 +1,182 @@
/** @addtogroup gpio_file GPIO peripheral API
* @ingroup peripheral_apis
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2015 Kuldeep Singh Dhaka <kuldeepdhaka9@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/efm32/gpio.h>
/**@{*/
/**
* Enable GPIO registers lock.
* @see gpio_disable_lock()
* @see gpio_get_lock_flag()
*/
void gpio_enable_lock(void)
{
GPIO_LOCK = GPIO_LOCK_LOCKKEY_LOCK;
}
/**
* Disable GPIO registers lock.
* @see gpio_enable_lock()
* @see gpio_get_lock_flag()
*/
void gpio_disable_lock(void)
{
GPIO_LOCK = GPIO_LOCK_LOCKKEY_UNLOCK;
}
/**
* Get GPIO register lock flag
* @retval true if flag is set
* @retval false if flag is not set
* @see gpio_enable_lock()
* @see gpio_disable_lock()
*/
bool gpio_get_lock_flag(void)
{
return (GPIO_LOCK & GPIO_LOCK_LOCKKEY_MASK)
== GPIO_LOCK_LOCKKEY_LOCKED;
}
/**
* Set port pins drive strength
* @param[in] gpio_port GPIO Port (use GPIO* ex. GPIOA, GPIOB, ....)
* @param[in] drive_stength Driver Stength (use GPIO_STENGTH_*)
*/
void gpio_set_drive_strength(uint32_t gpio_port,
enum gpio_drive_strength drive_stength)
{
GPIO_P_CTRL(gpio_port) = GPIO_P_CTRL_DRIVEMODE(drive_stength);
}
/**
* Set port pins mode
* @param[in] gpio_port GPIO Port (use GPIO* ex. GPIOA, GPIOB, ....)
* @param[in] mode Mode (use GPIO_MODE_*)
* @param[in] gpios (pins mask (use GPIO* ex . GPIO0, GPIO1 .... GPIO_ALL,
* use bitwise OR '|' to separate)
*/
void gpio_mode_setup(uint32_t gpio_port, enum gpio_mode mode, uint16_t gpios)
{
unsigned i;
uint32_t high = GPIO_P_MODEH(gpio_port);
uint32_t low = GPIO_P_MODEL(gpio_port);
for (i = 0; i < 8; i++) {
if (gpios & (1 << i)) {
low &= ~GPIO_P_MODE_MODEx_MASK(i);
low |= GPIO_P_MODE_MODEx(i, mode);
}
if (gpios & (1 << (i + 8))) {
high &= ~GPIO_P_MODE_MODEx_MASK(i);
high |= GPIO_P_MODE_MODEx(i, mode);
}
}
GPIO_P_MODEL(gpio_port) = low;
GPIO_P_MODEH(gpio_port) = high;
}
/**
* Set port pins output value (Atomic)
* @param[in] gpio_port GPIO Port (use GPIO* ex. GPIOA, GPIOB, ....)
* @param[in] gpios (pins mask (use GPIO* ex . GPIO0, GPIO1 .... GPIO_ALL,
* use bitwise OR '|' to separate)
*/
void gpio_set(uint32_t gpio_port, uint16_t gpios)
{
GPIO_P_DOUTSET(gpio_port) = gpios;
}
/**
* Set port pins output value (Atomic)
* @param[in] gpio_port GPIO Port (use GPIO* ex. GPIOA, GPIOB, ....)
* @param[in] gpios (pins mask (use GPIO* ex . GPIO0, GPIO1 .... GPIO_ALL,
* use bitwise OR '|' to separate)
*/
void gpio_clear(uint32_t gpio_port, uint16_t gpios)
{
GPIO_P_DOUTCLR(gpio_port) = gpios;
}
/**
* Get port pins input value
* @param[in] gpio_port GPIO Port (use GPIO* ex. GPIOA, GPIOB, ....)
* @param[in] gpios (pins mask (use GPIO* ex . GPIO0, GPIO1 .... GPIO_ALL,
* use bitwise OR '|' to separate)
* @return masked pins value (separated by bitwise OR '|')
*/
uint16_t gpio_get(uint32_t gpio_port, uint16_t gpios)
{
return GPIO_P_DIN(gpio_port) & gpios;
}
/**
* Toggle port pins output value (Atomic)
* @param[in] gpio_port GPIO Port (use GPIO* ex. GPIOA, GPIOB, ....)
* @param[in] gpios (pins mask (use GPIO* ex . GPIO0, GPIO1 .... GPIO_ALL,
* use bitwise OR '|' to separate)
*/
void gpio_toggle(uint32_t gpio_port, uint16_t gpios)
{
GPIO_P_DOUTTGL(gpio_port) = gpios;
}
/**
* Get port (all) input value's
* @param[in] gpio_port GPIO Port (use GPIO* ex. GPIOA, GPIOB, ....)
* @return all pins input value
*/
uint16_t gpio_port_read(uint32_t gpio_port)
{
return GPIO_P_DIN(gpio_port);
}
/**
* Set port (all) output value's
* @param[in] gpio_port GPIO Port (use GPIO* ex. GPIOA, GPIOB, ....)
* @param[in] data Data (all pins output value)
*/
void gpio_port_write(uint32_t gpio_port, uint16_t data)
{
GPIO_P_DOUT(gpio_port) = 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] gpio_port GPIO Port (use GPIO* ex. GPIOA, GPIOB, ....)
* @param[in] gpios (pins mask (use GPIO* ex . GPIO0, GPIO1 .... GPIO_ALL,
* use bitwise OR '|' to separate)
*/
void gpio_port_config_lock(uint32_t gpio_port, uint16_t gpios)
{
GPIO_P_PINLOCKN(gpio_port) = ~gpios;
}
/**@}*/

View File

@@ -0,0 +1,15 @@
/** @addtogroup i2c_file I2C peripheral API
* @ingroup peripheral_apis
* @brief I²C helper functions.
*
* <b>NO</b> helper functions exist. Only header definitions are available.
* Delete these lines if/when you add actual helper APIs.
* @copyright See @ref lgpl_license
*/
#include <libopencm3/efm32/i2c.h>
/**@{*/
/**@}*/

View File

@@ -0,0 +1,15 @@
/** @addtogroup letimer_file LETIMER peripheral API
* @ingroup peripheral_apis
* @brief Low Energy Timer helper functions.
*
* <b>NO</b> helper functions exist. Only header definitions are available.
* Delete these lines if/when you add actual helper APIs.
* @copyright See @ref lgpl_license
*/
#include <libopencm3/efm32/letimer.h>
/**@{*/
/**@}*/

View File

@@ -0,0 +1,15 @@
/** @addtogroup msc_file MSC peripheral API
* @ingroup peripheral_apis
* @brief Memory Systems Controller helper functions.
*
* <b>NO</b> helper functions exist. Only header definitions are available.
* Delete these lines if/when you add actual helper APIs.
* @copyright See @ref lgpl_license
*/
#include <libopencm3/efm32/msc.h>
/**@{*/
/**@}*/

View File

@@ -0,0 +1,151 @@
/** @addtogroup prs_file PRS peripheral API
* @ingroup peripheral_apis
* @brief EFM32 Peripheral Reflex System (PRS).
* The Peripheral Reflex System (PRS) system is a network which allows the
* different peripheral modules to communicate directly with each other
* without involving the CPU.
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2015 Kuldeep Singh Dhaka <kuldeepdhaka9@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/efm32/prs.h>
/**@{*/
/**
* Enable PRS output to GPIO.
* @param[in] ch Channel (use PRS_CHx)
* @see prs_set_output_loc()
*/
void prs_enable_gpio_output(enum prs_ch ch)
{
PRS_ROUTE |= PRS_ROUTE_CHxPEN(ch);
}
/**
* Disable PRS output to GPIO.
* @param[in] ch Channel (use PRS_CHx)
* @see prs_set_output_loc()
*/
void prs_disable_gpio_output(enum prs_ch ch)
{
PRS_ROUTE &= ~PRS_ROUTE_CHxPEN(ch);
}
/**
* Location of the PRS to be output on GPIO.
* @param[in] loc location (use PRS_ROUTE_LOCATION_LOCx)
* @see prs_set_output_loc()
*/
void prs_set_output_loc(uint32_t loc)
{
PRS_ROUTE = (PRS_ROUTE & ~PRS_ROUTE_LOCATION_MASK) | loc;
}
/**
* Generate software pulse.
* @param[in] ch Channel (use PRS_CHx)
* @note the final output is dependent on "software level" value of the channel
* @see prs_software_level_high()
* @see prs_software_level_low()
*/
void prs_software_pulse(enum prs_ch ch)
{
PRS_SWPULSE = PRS_SWPULSE_CHxPULSE(ch);
}
/**
* HIGH is XOR'ed with the corresponding bit in the software-pulse and
* the PRS input signal to generate.
* @param[in] ch Channel (use PRS_CHx)
* @see prs_software_level_low()
* @see prs_software_pulse()
*/
void prs_software_level_high(enum prs_ch ch)
{
PRS_SWLEVEL |= PRS_SWLEVEL_CHxLEVEL(ch);
}
/**
* LOW is XOR'ed with the corresponding bit in the software-pulse and
* the PRS input signal to generate.
* @param[in] ch Channel (use PRS_CHx)
* @see prs_software_level_high()
* @see prs_software_pulse()
*/
void prs_software_level_low(enum prs_ch ch)
{
PRS_SWLEVEL &= ~PRS_SWLEVEL_CHxLEVEL(ch);
}
/**
* disable synchronization of this channel reflex signal
* @param[in] ch Channel (use PRS_CHx)
* @see prs_disable_async()
*/
void prs_enable_async(enum prs_ch ch)
{
PRS_CHx_CTRL(ch) |= PRS_CH_CTRL_ASYNC;
}
/**
* enable synchronization of this channel reflex signal
* @param[in] ch Channel (use PRS_CHx)
* @see prs_disable_async()
*/
void prs_disable_async(enum prs_ch ch)
{
PRS_CHx_CTRL(ch) &= ~PRS_CH_CTRL_ASYNC;
}
/**
* Edge detection for the channel
* @param[in] ch Channel (use PRS_CHx)
* @param[in] edge Edge (use PRS_CH_CTRL_EDSEL_*)
*/
void prs_set_edge(enum prs_ch ch, uint32_t edge)
{
PRS_CHx_CTRL(ch) = (PRS_CHx_CTRL(ch) & ~PRS_CH_CTRL_EDSEL_MASK) | edge;
}
/**
* Source for the channel
* @param[in] ch Channel (use PRS_CHx)
* @param[in] source Source (use PRS_CH_CTRL_SOURCESEL_*)
* @see prs_set_signal()
*/
void prs_set_source(enum prs_ch ch, uint32_t source)
{
PRS_CHx_CTRL(ch) = (PRS_CHx_CTRL(ch) & ~PRS_CH_CTRL_SOURCESEL_MASK)
| source;
}
/**
* Source for the channel
* @param[in] ch Channel (use PRS_CHx)
* @param[in] signal Signal (use PRS_CH_CTRL_SIGSEL_*)
* @see prs_set_source()
*/
void prs_set_signal(enum prs_ch ch, uint32_t signal)
{
PRS_CHx_CTRL(ch) = (PRS_CHx_CTRL(ch) & ~PRS_CH_CTRL_SIGSEL_MASK)
| signal;
}
/**@}*/

View File

@@ -0,0 +1,15 @@
/** @addtogroup rmu_file RMU peripheral API
* @ingroup peripheral_apis
* @brief Reset Management Unit helper functions.
*
* <b>NO</b> helper functions exist. Only header definitions are available.
* Delete these lines if/when you add actual helper APIs.
* @copyright See @ref lgpl_license
*/
#include <libopencm3/efm32/rmu.h>
/**@{*/
/**@}*/

View File

@@ -0,0 +1,16 @@
/** @addtogroup rtc_file RTC peripheral API
* @ingroup peripheral_apis
* @brief Real Time Clock helper functions.
*
* <b>NO</b> helper functions exist. Only header definitions are available.
* Delete these lines if/when you add actual helper APIs.
* @sa rtc_defines
* @copyright See @ref lgpl_license
*/
#include <libopencm3/efm32/rtc.h>
/**@{*/
/**@}*/

View File

@@ -0,0 +1,69 @@
/** @addtogroup timer_file TIMER peripheral API
* @ingroup peripheral_apis
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2015 Kuldeep Singh Dhaka <kuldeepdhaka9@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/efm32/timer.h>
/**@{*/
#define HAS_DEAD_TIME_INSERTION(timer) (timer == TIMER0)
/**
* Start timer
* @param[in] timer Timer (use TIMERx)
*/
void timer_start(uint32_t timer)
{
TIMER_CMD(timer) = TIMER_CMD_START;
}
/**
* Stop timer
* @param[in] timer Timer (use TIMERx)
*/
void timer_stop(uint32_t timer)
{
TIMER_CMD(timer) = TIMER_CMD_STOP;
}
/** Clock division factor
* @param[in] timer Timer (use TIMERx)
* @param[in] presc Factor (use TIMER_CTRL_PRESC_DIV*)
* @note output-clock = input-clock / @a presc
*/
void timer_set_clock_prescaler(uint32_t timer, uint32_t presc)
{
TIMER_CTRL(timer) = (TIMER_CTRL(timer) & ~TIMER_CTRL_PRESC_MASK)
| TIMER_CTRL_PRESC(presc);
}
/**
* Start timer top value
* the timer reload after it reaches top value
* @param[in] timer Timer (use TIMERx)
* @param[in] top Top value
*/
void timer_set_top(uint32_t timer, uint32_t top)
{
TIMER_TOP(timer) = top;
}
/**@}*/

View File

@@ -0,0 +1,18 @@
/** @addtogroup usart_file UART/USART peripheral API
* @ingroup peripheral_apis
* @brief UART/USART helper functions.
*
* <b>NO</b> helper functions exist. Only header definitions are available.
* Delete these lines if/when you add actual helper APIs.
* @sa usart_defines
* @sa uart_defines
* @copyright See @ref lgpl_license
*/
#include <libopencm3/efm32/uart.h>
#include <libopencm3/efm32/usart.h>
/**@{*/
/**@}*/

View File

@@ -0,0 +1,15 @@
/** @addtogroup wdog_file WDOG peripheral API
* @ingroup peripheral_apis
* @brief Watchdog Module helper functions.
*
* <b>NO</b> helper functions exist. Only header definitions are available.
* Delete these lines if/when you add actual helper APIs.
* @copyright See @ref lgpl_license
*/
#include <libopencm3/efm32/wdog.h>
/**@{*/
/**@}*/

View File

@@ -0,0 +1,65 @@
##
## This file is part of the libopencm3 project.
##
## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
## Copyright (C) 2012 chrysn <chrysn@fsfe.org>
## Copyright (C) 2015 Kuldeep Singh Dhaka <kuldeepdhaka9@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_ezr32wg
SRCLIBDIR ?= ../..
FAMILY = EZR32WG
FP_FLAGS ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16
CC = $(PREFIX)gcc
AR = $(PREFIX)ar
TGT_CFLAGS = -Os \
-Wall -Wextra -Wimplicit-function-declaration \
-Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
-Wundef -Wshadow \
-I../../../include -fno-common \
-mcpu=cortex-m4 $(FP_FLAGS) -mthumb -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD -D$(FAMILY)
TGT_CFLAGS += $(DEBUG_FLAGS)
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS += acmp_common.o
OBJS += adc_common.o
OBJS += burtc_common.o
OBJS += cmu_common.o
OBJS += dac_common.o
OBJS += dma_common.o
OBJS += emu_common.o
OBJS += gpio_common.o
OBJS += i2c_common.o
OBJS += letimer_common.o
OBJS += msc_common.o
OBJS += prs_common.o
OBJS += rmu_common.o
OBJS += rtc_common.o
OBJS += timer_common.o
OBJS += usart_common.o
OBJS += wdog_common.o
OBJS += usb.o usb_control.o usb_standard.o usb_msc.o
OBJS += usb_hid.o
OBJS += usb_audio.o usb_cdc.o usb_midi.o
OBJS += usb_efm32.o
VPATH += ../../usb:../:../../cm3:../common
include ../../Makefile.include

View File

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

View File

@@ -0,0 +1,43 @@
##
## 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
SRCLIBDIR ?= ../..
FAMILY = EFM32G
CC = $(PREFIX)gcc
AR = $(PREFIX)ar
TGT_CFLAGS = -Os \
-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)
TGT_CFLAGS += $(DEBUG_FLAGS)
TGT_CFLAGS += $(STANDARD_FLAGS)
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS =
VPATH += ../:../../cm3
include ../../Makefile.include

View File

@@ -0,0 +1,43 @@
##
## 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
SRCLIBDIR ?= ../..
FAMILY = EFM32GG
CC = $(PREFIX)gcc
AR = $(PREFIX)ar
TGT_CFLAGS = -Os \
-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)
TGT_CFLAGS += $(DEBUG_FLAGS)
TGT_CFLAGS += $(STANDARD_FLAGS)
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS =
VPATH += ../:../../cm3
include ../../Makefile.include

View File

@@ -0,0 +1,52 @@
##
## This file is part of the libopencm3 project.
##
## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
## Copyright (C) 2012 chrysn <chrysn@fsfe.org>
## Copyright (C) 2015 Kuldeep Singh Dhaka <kuldeepdhaka9@gmail.com>
## Copyright (C) 2018 Seb Holzapfel <schnommus@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_efm32hg
SRCLIBDIR ?= ../..
FAMILY = EFM32HG
CC = $(PREFIX)gcc
AR = $(PREFIX)ar
TGT_CFLAGS = -Os \
-Wall -Wextra -Wimplicit-function-declaration \
-Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
-Wundef -Wshadow \
-I../../../include -fno-common \
-mcpu=cortex-m0plus $(FP_FLAGS) -mthumb -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD -D$(FAMILY)
TGT_CFLAGS += $(DEBUG_FLAGS)
TGT_CFLAGS += $(STANDARD_FLAGS)
ARFLAGS = rcs
OBJS += cmu.o
OBJS += gpio_common.o
OBJS += timer_common.o
OBJS += usb.o usb_control.o usb_standard.o usb_msc.o
OBJS += usb_hid.o
OBJS += usb_audio.o usb_cdc.o usb_midi.o
OBJS += usb_dwc_common.o usb_efm32hg.o
VPATH += ../../usb:../:../../cm3:../common
include ../../Makefile.include

View File

@@ -0,0 +1,314 @@
/** @addtogroup cmu_file CMU peripheral API
* @ingroup peripheral_apis
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2015 Kuldeep Singh Dhaka <kuldeepdhaka9@gmail.com>
* Copyright (C) 2018 Seb Holzapfel <schnommus@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/efm32/cmu.h>
/**@{*/
/**
* Enable CMU registers lock.
*/
void cmu_enable_lock(void)
{
CMU_LOCK = CMU_LOCK_LOCKKEY_LOCK;
}
/**
* Disable CMU registers lock
*/
void cmu_disable_lock(void)
{
CMU_LOCK = CMU_LOCK_LOCKKEY_UNLOCK;
}
/**
* Get CMU register lock flag
* @retval true if flag is set
* @retval false if flag is not set
*/
bool cmu_get_lock_flag(void)
{
return (CMU_LOCK & CMU_LOCK_LOCKKEY_MASK) == CMU_LOCK_LOCKKEY_LOCKED;
}
#define _CMU_REG(i) MMIO32(CMU_BASE + ((i) >> 5))
#define _CMU_BIT(i) (1 << ((i) & 0x1f))
/**
* @brief Enable Peripheral Clock in running mode.
*
* Enable the clock on particular peripheral.
*
* @param[in] clken Peripheral Name
*
* For available constants, see @a enum::cmu_periph_clken (CMU_LEUART1 for
* example)
*/
void cmu_periph_clock_enable(enum cmu_periph_clken clken)
{
_CMU_REG(clken) |= _CMU_BIT(clken);
}
/**
* @brief Disable Peripheral Clock in running mode.
* Disable the clock on particular peripheral.
*
* @param[in] clken Peripheral Name
*
* For available constants, see @a enum::cmu_periph_clken (CMU_LEUART1 for
* example)
*/
void cmu_periph_clock_disable(enum cmu_periph_clken clken)
{
_CMU_REG(clken) &= ~_CMU_BIT(clken);
}
/**
* Turn on Oscillator
* @param[in] osc enum cmu_osc Oscillator name
*/
void cmu_osc_on(enum cmu_osc osc)
{
switch (osc) {
case HFRCO:
CMU_OSCENCMD = CMU_OSCENCMD_HFRCOEN;
break;
case LFRCO:
CMU_OSCENCMD = CMU_OSCENCMD_LFRCOEN;
break;
case USHFRCO:
CMU_OSCENCMD = CMU_OSCENCMD_USHFRCOEN;
break;
case HFXO:
CMU_OSCENCMD = CMU_OSCENCMD_HFXOEN;
break;
case LFXO:
CMU_OSCENCMD = CMU_OSCENCMD_LFXOEN;
break;
case AUXHFRCO:
CMU_OSCENCMD = CMU_OSCENCMD_AUXHFRCOEN;
break;
default:
/* not applicable */
break;
}
}
/**
* Turn off Oscillator
* @param[in] osc enum cmu_osc Oscillator name
*/
void cmu_osc_off(enum cmu_osc osc)
{
switch (osc) {
case HFRCO:
CMU_OSCENCMD = CMU_OSCENCMD_HFRCODIS;
break;
case LFRCO:
CMU_OSCENCMD = CMU_OSCENCMD_LFRCODIS;
break;
case USHFRCO:
CMU_OSCENCMD = CMU_OSCENCMD_USHFRCODIS;
break;
case HFXO:
CMU_OSCENCMD = CMU_OSCENCMD_HFXODIS;
break;
case LFXO:
CMU_OSCENCMD = CMU_OSCENCMD_LFXODIS;
break;
case AUXHFRCO:
CMU_OSCENCMD = CMU_OSCENCMD_AUXHFRCODIS;
break;
default:
/* not applicable */
break;
}
}
/**
* Get Oscillator read flag
* @param[in] osc enum cmu_osc Oscillator name
* @retval true if flag is set
* @retval false if flag is not set
*/
bool cmu_osc_ready_flag(enum cmu_osc osc)
{
switch (osc) {
case HFRCO:
return (CMU_STATUS & CMU_STATUS_HFRCORDY) != 0;
break;
case LFRCO:
return (CMU_STATUS & CMU_STATUS_LFRCORDY) != 0;
break;
case USHFRCO:
return (CMU_STATUS & CMU_STATUS_USHFRCORDY) != 0;
break;
case HFXO:
return (CMU_STATUS & CMU_STATUS_HFXORDY) != 0;
break;
case LFXO:
return (CMU_STATUS & CMU_STATUS_LFXORDY) != 0;
break;
case AUXHFRCO:
return (CMU_STATUS & CMU_STATUS_AUXHFRCORDY) != 0;
break;
default:
/* not applicable */
break;
}
return false;
}
/**
* Wait while oscillator is not ready
* @param[in] osc enum cmu_osc Oscillator name
*/
void cmu_wait_for_osc_ready(enum cmu_osc osc)
{
switch (osc) {
case HFRCO:
while ((CMU_STATUS & CMU_STATUS_HFRCORDY) == 0);
break;
case LFRCO:
while ((CMU_STATUS & CMU_STATUS_LFRCORDY) == 0);
break;
case USHFRCO:
while ((CMU_STATUS & CMU_STATUS_USHFRCORDY) == 0);
break;
case HFXO:
while ((CMU_STATUS & CMU_STATUS_HFXORDY) == 0);
break;
case LFXO:
while ((CMU_STATUS & CMU_STATUS_LFXORDY) == 0);
break;
case AUXHFRCO:
while ((CMU_STATUS & CMU_STATUS_AUXHFRCORDY) == 0);
break;
default:
/* not applicable */
break;
}
}
/**
* Set HFCLK clock source
* @param[in] osc enum cmu_osc Oscillator name
* @note calling cmu_set_hfclk_source() do not set source immediately, use
* @a cmu_get_hfclk_source() to verify that the source has been set.
* @see cmu_get_hfclk_source()
*/
void cmu_set_hfclk_source(enum cmu_osc osc)
{
switch (osc) {
case HFXO:
CMU_CMD = CMU_CMD_HFCLKSEL_HFXO;
break;
case HFRCO:
CMU_CMD = CMU_CMD_HFCLKSEL_HFRCO;
break;
case LFXO:
CMU_CMD = CMU_CMD_HFCLKSEL_LFXO;
break;
case LFRCO:
CMU_CMD = CMU_CMD_HFCLKSEL_LFRCO;
break;
case USHFRCODIV2:
CMU_CMD = CMU_CMD_HFCLKSEL_USHFRCODIV2;
break;
default:
/* not applicable */
return;
}
}
/**
* Get HFCLK clock source
* @retval enum cmu_osc Oscillator name
*/
enum cmu_osc cmu_get_hfclk_source(void)
{
uint32_t status = CMU_STATUS;
if (status & CMU_STATUS_LFXOSEL) {
return LFXO;
} else if (status & CMU_STATUS_LFRCOSEL) {
return LFRCO;
} else if (status & CMU_STATUS_HFXOSEL) {
return HFXO;
} else if (status & CMU_STATUS_HFRCOSEL) {
return HFRCO;
} else if (status & CMU_STATUS_USHFRCODIV2SEL) {
return USHFRCODIV2;
}
/* never reached */
return (enum cmu_osc) -1;
}
/**
* Set USBCLK clock source
* @param osc Oscillator name
*/
void cmu_set_usbclk_source(enum cmu_osc osc)
{
switch (osc) {
case LFXO:
CMU_CMD = CMU_CMD_USBCCLKSEL_LFXO;
break;
case LFRCO:
CMU_CMD = CMU_CMD_USBCCLKSEL_LFRCO;
break;
case USHFRCO:
CMU_CMD = CMU_CMD_USBCCLKSEL_USHFRCO;
break;
default:
/* not applicable */
return;
}
}
/**
* Wait while USBCLK is not selected
* @param[in] osc enum cmu_osc Oscillator name
*/
void cmu_wait_for_usbclk_selected(enum cmu_osc osc)
{
switch (osc) {
case LFXO:
while ((CMU_STATUS & CMU_STATUS_USBCLFXOSEL) == 0);
break;
case LFRCO:
while ((CMU_STATUS & CMU_STATUS_USBCLFRCOSEL) == 0);
break;
case USHFRCO:
while ((CMU_STATUS & CMU_STATUS_USBCUSHFRCOSEL) == 0);
break;
default:
/* not applicable */
return;
}
}
/**@}*/

View File

@@ -0,0 +1,66 @@
##
## This file is part of the libopencm3 project.
##
## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
## Copyright (C) 2012 chrysn <chrysn@fsfe.org>
## Copyright (C) 2015 Kuldeep Singh Dhaka <kuldeepdhaka9@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_efm32lg
SRCLIBDIR ?= ../..
FAMILY = EFM32LG
CC = $(PREFIX)gcc
AR = $(PREFIX)ar
TGT_CFLAGS = -Os \
-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)
TGT_CFLAGS += $(DEBUG_FLAGS)
TGT_CFLAGS += $(STANDARD_FLAGS)
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS += acmp_common.o
OBJS += adc_common.o
OBJS += burtc_common.o
OBJS += cmu_common.o
OBJS += dac_common.o
OBJS += dma_common.o
OBJS += emu_common.o
OBJS += gpio_common.o
OBJS += i2c_common.o
OBJS += letimer_common.o
OBJS += msc_common.o
OBJS += prs_common.o
OBJS += rmu_common.o
OBJS += rtc_common.o
OBJS += timer_common.o
OBJS += usart_common.o
OBJS += wdog_common.o
OBJS += usb.o usb_control.o usb_standard.o usb_msc.o
OBJS += usb_hid.o
OBJS += usb_audio.o usb_cdc.o usb_midi.o
OBJS += usb_efm32.o
VPATH += ../../usb:../:../../cm3:../common
include ../../Makefile.include

View File

@@ -0,0 +1,43 @@
##
## 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
SRCLIBDIR ?= ../..
FAMILY = EFM32TG
CC = $(PREFIX)gcc
AR = $(PREFIX)ar
TGT_CFLAGS = -Os \
-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)
TGT_CFLAGS += $(DEBUG_FLAGS)
TGT_CFLAGS += $(STANDARD_FLAGS)
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS =
VPATH += ../:../../cm3
include ../../Makefile.include

View File

@@ -0,0 +1,65 @@
##
## This file is part of the libopencm3 project.
##
## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
## Copyright (C) 2012 chrysn <chrysn@fsfe.org>
## Copyright (C) 2015 Kuldeep Singh Dhaka <kuldeepdhaka9@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_efm32wg
SRCLIBDIR ?= ../..
FAMILY = EFM32WG
FP_FLAGS ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16
CC = $(PREFIX)gcc
AR = $(PREFIX)ar
TGT_CFLAGS = -Os \
-Wall -Wextra -Wimplicit-function-declaration \
-Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
-Wundef -Wshadow \
-I../../../include -fno-common \
-mcpu=cortex-m4 $(FP_FLAGS) -mthumb -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD -D$(FAMILY)
TGT_CFLAGS += $(DEBUG_FLAGS)
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS += acmp_common.o
OBJS += adc_common.o
OBJS += burtc_common.o
OBJS += cmu_common.o
OBJS += dac_common.o
OBJS += dma_common.o
OBJS += emu_common.o
OBJS += gpio_common.o
OBJS += i2c_common.o
OBJS += letimer_common.o
OBJS += msc_common.o
OBJS += prs_common.o
OBJS += rmu_common.o
OBJS += rtc_common.o
OBJS += timer_common.o
OBJS += usart_common.o
OBJS += wdog_common.o
OBJS += usb.o usb_control.o usb_standard.o usb_msc.o
OBJS += usb_hid.o
OBJS += usb_audio.o usb_cdc.o usb_midi.o
OBJS += usb_efm32.o
VPATH += ../../usb:../:../../cm3:../common
include ../../Makefile.include

View File

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

View File

@@ -0,0 +1,43 @@
/** @defgroup ethernet_mac_file MAC Generic Drivers
*
* @ingroup ETH
*
* @brief <b>Ethernet MAC Generic Drivers</b>
*
* @version 1.0.0
* @author @htmlonly &copy; @endhtmlonly 2013 Frantisek Burian <BuFran@seznam.cz>
*
* @date 1 September 2013
*
*
* LGPL License Terms @ref lgpl_license
*/
/*
* 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/ethernet/mac.h>
#include <libopencm3/ethernet/phy.h>
/**@{*/
/*---------------------------------------------------------------------------*/
/**@}*/

View File

@@ -0,0 +1,384 @@
/** @defgroup ethernet_mac_stm32fxx7_file MAC STM32Fxx7
*
* @ingroup ETH
*
* @brief <b>Ethernet MAC STM32Fxx7 Drivers</b>
*
* @version 1.0.0
* @author @htmlonly &copy; @endhtmlonly 2013 Frantisek Burian <BuFran@seznam.cz>
*
* @date 1 September 2013
*
*
* LGPL License Terms @ref lgpl_license
*/
/*
* 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 <string.h>
#include <libopencm3/ethernet/mac.h>
#include <libopencm3/ethernet/phy.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/cm3/nvic.h>
/**@{*/
uint32_t TxBD;
uint32_t RxBD;
/*---------------------------------------------------------------------------*/
/** @brief Set MAC to the PHY
*
* @param[in] mac uint8_t* Desired MAC
*/
void eth_set_mac(const uint8_t *mac)
{
ETH_MACAHR(0) = ((uint32_t)mac[5] << 8) | (uint32_t)mac[4] |
ETH_MACA0HR_MACA0H;
ETH_MACALR(0) = ((uint32_t)mac[3] << 24) | ((uint32_t)mac[2] << 16) |
((uint32_t)mac[1] << 8) | mac[0];
}
/*---------------------------------------------------------------------------*/
/** @brief Initialize buffers and descriptors.
*
* @param[in] buf uint8_t* Memory area for the descriptors and data buffers
* @param[in] nTx uint32_t Count of transmit descriptors (equal to count of buffers)
* @param[in] nRx uint32_t Count of receive descriptors (equal to count of buffers)
* @param[in] cTx uint32_t Bytes in each transmit buffer, must be a
* multiple of 4
* @param[in] cRx uint32_t Bytes in each receive buffer, must be a
* multiple of 4
* @param[in] isext bool true if extended descriptors should be used
*
* Note, the space passed via buf pointer must be large enough to
* hold all the buffers and one descriptor per buffer.
*/
void eth_desc_init(uint8_t *buf, uint32_t nTx, uint32_t nRx, uint32_t cTx,
uint32_t cRx, bool isext)
{
uint32_t bd = (uint32_t)buf;
uint32_t sz = isext ? ETH_DES_EXT_SIZE : ETH_DES_STD_SIZE;
memset(buf, 0, nTx * (cTx + sz) + nRx * (cRx + sz));
/* enable / disable extended frames */
if (isext) {
ETH_DMABMR |= ETH_DMABMR_EDFE;
} else {
ETH_DMABMR &= ~ETH_DMABMR_EDFE;
}
TxBD = bd;
while (--nTx > 0) {
ETH_DES0(bd) = ETH_TDES0_TCH;
ETH_DES2(bd) = bd + sz;
ETH_DES3(bd) = bd + sz + cTx;
bd = ETH_DES3(bd);
}
ETH_DES0(bd) = ETH_TDES0_TCH;
ETH_DES2(bd) = bd + sz;
ETH_DES3(bd) = TxBD;
bd += sz + cTx;
RxBD = bd;
while (--nRx > 0) {
ETH_DES0(bd) = ETH_RDES0_OWN;
ETH_DES1(bd) = ETH_RDES1_RCH | cRx;
ETH_DES2(bd) = bd + sz;
ETH_DES3(bd) = bd + sz + cRx;
bd = ETH_DES3(bd);
}
ETH_DES0(bd) = ETH_RDES0_OWN;
ETH_DES1(bd) = ETH_RDES1_RCH | cRx;
ETH_DES2(bd) = bd + sz;
ETH_DES3(bd) = RxBD;
ETH_DMARDLAR = (uint32_t) RxBD;
ETH_DMATDLAR = (uint32_t) TxBD;
}
/*---------------------------------------------------------------------------*/
/** @brief Transmit packet
*
* @param[in] ppkt uint8_t* Pointer to the beginning of the packet
* @param[in] n uint32_t Size of the packet
* @returns bool true, if success
*/
bool eth_tx(uint8_t *ppkt, uint32_t n)
{
if (ETH_DES0(TxBD) & ETH_TDES0_OWN) {
return false;
}
memcpy((void *)ETH_DES2(TxBD), ppkt, n);
ETH_DES1(TxBD) = n & ETH_TDES1_TBS1;
ETH_DES0(TxBD) |= ETH_TDES0_LS | ETH_TDES0_FS | ETH_TDES0_OWN;
TxBD = ETH_DES3(TxBD);
if (ETH_DMASR & ETH_DMASR_TBUS) {
ETH_DMASR = ETH_DMASR_TBUS;
ETH_DMATPDR = 0;
}
return true;
}
/*---------------------------------------------------------------------------*/
/** @brief Receive packet
*
* @param[inout] ppkt uint8_t* Pointer to the data buffer where to store data
* @param[inout] len uint32_t* Pointer to the variable with the packet length
* @param[in] maxlen uint32_t Maximum length of the packet
* @returns bool true, if the buffer contains readed packet data
*/
bool eth_rx(uint8_t *ppkt, uint32_t *len, uint32_t maxlen)
{
bool fs = false;
bool ls = false;
bool overrun = false;
uint32_t l = 0;
while (!(ETH_DES0(RxBD) & ETH_RDES0_OWN) && !ls) {
l = (ETH_DES0(RxBD) & ETH_RDES0_FL) >> ETH_RDES0_FL_SHIFT;
fs |= ETH_DES0(RxBD) & ETH_RDES0_FS;
ls |= ETH_DES0(RxBD) & ETH_RDES0_LS;
/* frame buffer overrun ?*/
overrun |= fs && (maxlen < l);
if (fs && !overrun) {
memcpy(ppkt, (void *)ETH_DES2(RxBD), l);
ppkt += l;
*len += l;
maxlen -= l;
}
ETH_DES0(RxBD) = ETH_RDES0_OWN;
RxBD = ETH_DES3(RxBD);
}
if (ETH_DMASR & ETH_DMASR_RBUS) {
ETH_DMASR = ETH_DMASR_RBUS;
ETH_DMARPDR = 0;
}
return fs && ls && !overrun;
}
/*---------------------------------------------------------------------------*/
/** @brief Start the Ethernet DMA processing
*/
void eth_start(void)
{
ETH_MACCR |= ETH_MACCR_TE;
ETH_DMAOMR |= ETH_DMAOMR_FTF;
ETH_MACCR |= ETH_MACCR_RE;
ETH_DMAOMR |= ETH_DMAOMR_ST;
ETH_DMAOMR |= ETH_DMAOMR_SR;
}
/*---------------------------------------------------------------------------*/
/** @brief Initialize ethernet
*
* This function will initialize ethernet, set up clocks, and initialize DMA.
*
* @param[in] phy phy id
* @param[in] clock enum eth_clk Core clock speed
*/
void eth_init(uint8_t phy, enum eth_clk clock)
{
ETH_MACMIIAR = clock;
phy_reset(phy);
ETH_MACCR = ETH_MACCR_CSTF | ETH_MACCR_FES | ETH_MACCR_DM |
ETH_MACCR_APCS | ETH_MACCR_RD;
ETH_MACFFR = ETH_MACFFR_RA | ETH_MACFFR_PM;
ETH_MACHTHR = 0; /* pass all frames */
ETH_MACHTLR = 0;
ETH_MACFCR = (0x100 << ETH_MACFCR_PT_SHIFT);
ETH_MACVLANTR = 0;
ETH_DMAOMR = ETH_DMAOMR_DTCEFD | ETH_DMAOMR_RSF | ETH_DMAOMR_DFRF |
ETH_DMAOMR_TSF | ETH_DMAOMR_FEF | ETH_DMAOMR_OSF;
ETH_DMABMR = ETH_DMABMR_AAB | ETH_DMABMR_FB |
(32 << ETH_DMABMR_RDP_SHIFT) | (32 << ETH_DMABMR_PBL_SHIFT) |
ETH_DMABMR_PM_2_1 | ETH_DMABMR_USP;
}
/*---------------------------------------------------------------------------*/
/** @brief Enable the Ethernet IRQ
*
* @param[in] reason uint32_t Which irq will be enabled
*/
void eth_irq_enable(uint32_t reason)
{
ETH_DMAIER |= reason;
}
/*---------------------------------------------------------------------------*/
/** @brief Disable the Ethernet IRQ
*
* @param[in] reason uint32_t Which irq will be disabled
*/
void eth_irq_disable(uint32_t reason)
{
ETH_DMAIER &= ~reason;
}
/*---------------------------------------------------------------------------*/
/** @brief Check if IRQ is pending
*
* @param[in] reason uint32_t Which irq type has to be tested
* @returns bool true, if IRQ is pending
*/
bool eth_irq_is_pending(uint32_t reason)
{
return (ETH_DMASR & reason) != 0;
}
/*---------------------------------------------------------------------------*/
/** @brief Check if IRQ is pending, and acknowledge it
*
* @param[in] reason uint32_t Which irq type has to be tested
* @returns bool true, if IRQ is pending
*/
bool eth_irq_ack_pending(uint32_t reason)
{
reason &= ETH_DMASR;
ETH_DMASR = reason;
return reason != 0;
}
/*---------------------------------------------------------------------------*/
/** @brief Enable checksum offload feature
*
* This function will enable the Checksum offload feature for all of the
* transmit descriptors. Note to use this feature, descriptors must be in
* extended format.
*/
void eth_enable_checksum_offload(void)
{
uint32_t tab = TxBD;
do {
ETH_DES0(tab) |= ETH_TDES0_CIC_IPPLPH;
tab = ETH_DES3(tab);
}
while (tab != TxBD);
ETH_MACCR |= ETH_MACCR_IPCO;
}
/*---------------------------------------------------------------------------*/
/** @brief Process pending SMI transaction and wait to be done.
*/
static void eth_smi_transact(void)
{
/* Begin transaction. */
ETH_MACMIIAR |= ETH_MACMIIAR_MB;
/* Wait for not busy. */
while (ETH_MACMIIAR & ETH_MACMIIAR_MB);
}
/*---------------------------------------------------------------------------*/
/** @brief Write 16-bit register to the PHY
*
* @param[in] phy uint8_t ID of the PHY (defaults to 1)
* @param[in] reg uint8_t Register address
* @param[in] data uint16_t Data to write
*/
void eth_smi_write(uint8_t phy, uint8_t reg, uint16_t data)
{
/* Write operation MW=1*/
ETH_MACMIIAR = (ETH_MACMIIAR & ETH_MACMIIAR_CR) | /* save clocks */
(phy << ETH_MACMIIAR_PA_SHIFT) |
(reg << ETH_MACMIIAR_MR_SHIFT) |
ETH_MACMIIAR_MW;
ETH_MACMIIDR = data & ETH_MACMIIDR_MD;
eth_smi_transact();
}
/*---------------------------------------------------------------------------*/
/** @brief Read the 16-bit register from the PHY
*
* @param[in] phy uint8_t ID of the PHY (defaults to 1)
* @param[in] reg uint8_t Register address
* @returns uint16_t Readed data
*/
uint16_t eth_smi_read(uint8_t phy, uint8_t reg)
{
/* Read operation MW=0*/
ETH_MACMIIAR = (ETH_MACMIIAR & ETH_MACMIIAR_CR) | /* save clocks */
(phy << ETH_MACMIIAR_PA_SHIFT) |
(reg << ETH_MACMIIAR_MR_SHIFT);
eth_smi_transact();
return (uint16_t)(ETH_MACMIIDR & ETH_MACMIIDR_MD);
}
/*---------------------------------------------------------------------------*/
/** @brief Process the bit-operation on PHY register
*
* @param[in] phy uint8_t ID of the PHY (defaults to 1)
* @param[in] reg uint8_t Register address
* @param[in] bits uint16_t Bits that have to be set (or'ed)
* @param[in] mask uint16_t Bits that have to be clear (and'ed)
*/
void eth_smi_bit_op(uint8_t phy, uint8_t reg, uint16_t bits, uint16_t mask)
{
uint16_t val = eth_smi_read(phy, reg);
eth_smi_write(phy, reg, (val & mask) | bits);
}
/*---------------------------------------------------------------------------*/
/** @brief Clear bits in the register
*
* @param[in] phy uint8_t ID of the PHY (defaults to 1)
* @param[in] reg uint8_t Register address
* @param[in] clearbits uint16_t Bits that have to be cleared
*/
void eth_smi_bit_clear(uint8_t phy, uint8_t reg, uint16_t clearbits)
{
uint16_t val = eth_smi_read(phy, reg);
eth_smi_write(phy, reg, val & (uint16_t)~(clearbits));
}
/*---------------------------------------------------------------------------*/
/** @brief Set bits in the register
*
* @param[in] phy uint8_t ID of the PHY (defaults to 1)
* @param[in] reg uint8_t Register address
* @param[in] setbits uint16_t Bits that have to be set (or'ed)
*/
void eth_smi_bit_set(uint8_t phy, uint8_t reg, uint16_t setbits)
{
uint16_t val = eth_smi_read(phy, reg);
eth_smi_write(phy, reg, val | setbits);
}
/*---------------------------------------------------------------------------*/
/**@}*/

65
libopencm3/lib/ethernet/phy.c Executable file
View File

@@ -0,0 +1,65 @@
/** @defgroup ethernet_phy_file PHY Generic Drivers
*
* @ingroup ETH
*
* @brief <b>Ethernet PHY Generic Drivers</b>
*
* @version 1.0.0
* @author @htmlonly &copy; @endhtmlonly 2013 Frantisek Burian <BuFran@seznam.cz>
*
* @date 1 September 2013
*
*
* LGPL License Terms @ref lgpl_license
*/
/*
* 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/ethernet/mac.h>
#include <libopencm3/ethernet/phy.h>
/**@{*/
/*---------------------------------------------------------------------------*/
/** @brief Is the link up ?
*
* @param[in] phy uint8_t phy ID of the PHY
* @returns bool true, if link is up
*/
bool phy_link_isup(uint8_t phy)
{
return eth_smi_read(phy, PHY_REG_BSR) & PHY_REG_BSR_UP;
}
/*---------------------------------------------------------------------------*/
/** @brief Reset the PHY
*
* Reset the PHY chip and wait for done
* @param[in] phy uint8_t phy ID of the PHY
*/
void phy_reset(uint8_t phy)
{
eth_smi_write(phy, PHY_REG_BCR, PHY_REG_BCR_RESET);
while (eth_smi_read(phy, PHY_REG_BCR) & PHY_REG_BCR_RESET);
}
/*---------------------------------------------------------------------------*/
/**@}*/

View File

@@ -0,0 +1,93 @@
/** @defgroup ethernet_phy_ksz8051mll_file PHY KSZ8051MLL
*
* @ingroup ETH
*
* @brief <b>Ethernet PHY STM32Fxx7 Drivers</b>
*
* @version 1.0.0
* @author @htmlonly &copy; @endhtmlonly 2013 Frantisek Burian <BuFran@seznam.cz>
*
* @date 1 September 2013
*
* LGPL License Terms @ref lgpl_license
*/
/*
* 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/ethernet/mac.h>
#include <libopencm3/ethernet/phy.h>
#include <libopencm3/ethernet/phy_ksz80x1.h>
/**@{*/
/*---------------------------------------------------------------------------*/
/** @brief Get the current link status
*
* Retrieve the link speed and duplex status of the link.
*
* @param[in] phy uint8_t phy ID of the PHY
* @returns ::phy_status Link status
*/
enum phy_status phy_link_status(uint8_t phy)
{
return eth_smi_read(phy, KSZ80X1_CR1) & 0x07;
}
/*---------------------------------------------------------------------------*/
/** @brief Force autonegotiation
*
* Force the autonegotiation and set link speed and duplex mode of the link
*
* @param[in] phy uint8_t phy ID of the PHY
* @param[in] mode enum phy_status Desired link status
*/
void phy_autoneg_force(uint8_t phy, enum phy_status mode)
{
uint16_t bst = 0;
if ((mode == LINK_FD_10M) || (mode == LINK_FD_100M) ||
(mode == LINK_FD_1000M) || (mode == LINK_FD_10000M)) {
bst |= PHY_REG_BCR_FD;
}
if ((mode == LINK_FD_100M) || (mode == LINK_HD_100M)) {
bst |= PHY_REG_BCR_100M;
}
eth_smi_bit_op(phy, PHY_REG_BCR, bst,
~(PHY_REG_BCR_AN | PHY_REG_BCR_100M | PHY_REG_BCR_FD));
}
/*---------------------------------------------------------------------------*/
/** @brief Enable the autonegotiation
*
* Enable the autonegotiation of the link speed and duplex mode
*
* @param[in] phy uint8_t phy ID of the PHY
*/
void phy_autoneg_enable(uint8_t phy)
{
eth_smi_bit_set(phy, PHY_REG_BCR, PHY_REG_BCR_AN | PHY_REG_BCR_ANRST);
}
/*---------------------------------------------------------------------------*/
/**@}*/

View File

@@ -0,0 +1,42 @@
##
## This file is part of the libopencm3 project.
##
## Copyright (C) 2019 Icenowy Zheng <icenowy@aosc.io>
##
## 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_gd32f1x0
SRCLIBDIR ?= ../..
CC = $(PREFIX)gcc
AR = $(PREFIX)ar
TGT_CFLAGS = -Os \
-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 -DGD32F1X0
TGT_CFLAGS += $(DEBUG_FLAGS)
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS += flash.o flash_common_all.o flash_common_f.o flash_common_f01.o
OBJS += gpio_common_all.o gpio_common_f0234.o
OBJS += rcc.o rcc_common_all.o
VPATH += ../:../../cm3:../common:../../stm32/common
include ../../Makefile.include

View File

@@ -0,0 +1,153 @@
/** @defgroup flash_file FLASH peripheral API
*
* @ingroup peripheral_apis
*
* @brief <b>libopencm3 GD32F1x0 FLASH</b>
*
* @version 1.0.0
*
* @author @htmlonly &copy; @endhtmlonly 2013
* Frantisek Burian <BuFran@seznam.cz>
*
* @date 14 January 2014
*
* FLASH memory may be used for data storage as well as code, and may be
* programmatically modified. Note that for firmware upload the GD32F1x0
* provides a built-in bootloader in system memory that can be entered from a
* running program.
*
* FLASH must first be unlocked before programming. In this module a write to
* FLASH is a blocking operation until the end-of-operation flag is asserted.
*
* @note: don't forget to lock it again when all operations are complete.
*
* LGPL License Terms @ref lgpl_license
*/
/*
* 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/gd32/flash.h>
/*---------------------------------------------------------------------------*/
/** @brief Clear All Status Flags
Program error, end of operation, write protect error, busy.
*/
void flash_clear_status_flags(void)
{
flash_clear_pgerr_flag();
flash_clear_eop_flag();
flash_clear_wrprterr_flag();
}
/*---------------------------------------------------------------------------*/
/** @brief Read All Status Flags
The programming error, end of operation, write protect error and busy flags
are returned in the order of appearance in the status register.
@returns uint32_t. bit 0: busy, bit 2: programming error, bit 4: write protect
error, bit 5: end of operation.
*/
uint32_t flash_get_status_flags(void)
{
return FLASH_SR & (FLASH_SR_PGERR |
FLASH_SR_EOP |
FLASH_SR_WRPRTERR |
FLASH_SR_BSY);
}
/*---------------------------------------------------------------------------*/
/** @brief Program a Half Word to FLASH
This performs all operations necessary to program a 16 bit word to FLASH memory.
The program error flag should be checked separately for the event that memory
was not properly erased.
Status bit polling is used to detect end of operation.
@param[in] address Full address of flash half word to be programmed.
@param[in] data half word to write
*/
void flash_program_half_word(uint32_t address, uint16_t data)
{
flash_wait_for_last_operation();
FLASH_CR |= FLASH_CR_PG;
MMIO16(address) = data;
flash_wait_for_last_operation();
FLASH_CR &= ~FLASH_CR_PG;
}
/*---------------------------------------------------------------------------*/
/** @brief Erase a Page of FLASH
This performs all operations necessary to erase a page in FLASH memory.
The page should be checked to ensure that it was properly erased. A page must
first be fully erased before attempting to program it.
Note that the page sizes differ between devices. See the reference manual or
the FLASH programming manual for details.
@param[in] page_address Full address of flash page to be erased.
*/
void flash_erase_page(uint32_t page_address)
{
flash_wait_for_last_operation();
FLASH_CR |= FLASH_CR_PER;
FLASH_AR = page_address;
FLASH_CR |= FLASH_CR_STRT;
flash_wait_for_last_operation();
FLASH_CR &= ~FLASH_CR_PER;
}
/*---------------------------------------------------------------------------*/
/** @brief Erase All FLASH
This performs all operations necessary to erase all user pages in the FLASH
memory. The information block is unaffected.
*/
void flash_erase_all_pages(void)
{
flash_wait_for_last_operation();
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. */
}
/**@}*/

View File

@@ -0,0 +1,654 @@
/** @defgroup rcc_file RCC peripheral API
@ingroup peripheral_apis
@brief <b>libopencm3 GD32F1x0 Reset and Clock Control</b>
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2009
Federico Ruiz-Ugalde \<memeruiz at gmail dot com\>
@author @htmlonly &copy; @endhtmlonly 2009 Uwe Hermann <uwe@hermann-uwe.de>
@author @htmlonly &copy; @endhtmlonly 2010 Thomas Otto <tommi@viadmin.org>
@date 18 August 2012
This library supports the Reset and Clock Control System in the GD32F1x0
series of ARM Cortex Microcontrollers by GigaDevice.
@note Full support for F170 and F190 devices is not yet provided.
Clock settings and resets for many peripherals are given here rather than in
the corresponding peripheral library.
The library also provides a number of common configurations for the processor
system clock. Not all possible configurations are included.
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2019 Icenowy Zheng <icenowy@aosc.io>
* 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/gd32/rcc.h>
#include <libopencm3/gd32/flash.h>
/** Set the default clock frequencies */
uint32_t rcc_apb1_frequency = 8000000;
uint32_t rcc_apb2_frequency = 8000000;
uint32_t rcc_ahb_frequency = 8000000;
const struct rcc_clock_scale rcc_hsi_configs[] = {
{ /* 48MHz */
.pllmul = RCC_CFGR_PLLMUL_PLL_CLK_MUL12,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_DIV2,
.ppre2 = RCC_CFGR_PPRE_NODIV,
.adcpre = RCC_CFGR_ADCPRE_DIV8,
.use_hse = false,
.ahb_frequency = 48000000,
.apb1_frequency = 24000000,
.apb2_frequency = 48000000,
},
{ /* 64MHz */
.pllmul = RCC_CFGR_PLLMUL_PLL_CLK_MUL16,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_DIV2,
.ppre2 = RCC_CFGR_PPRE_NODIV,
.adcpre = RCC_CFGR_ADCPRE_DIV8,
.use_hse = false,
.ahb_frequency = 64000000,
.apb1_frequency = 32000000,
.apb2_frequency = 64000000,
}
};
const struct rcc_clock_scale rcc_hse8_configs[] = {
{ /* 72MHz */
.pllmul = RCC_CFGR_PLLMUL_PLL_CLK_MUL9,
.hpre = RCC_CFGR_HPRE_NODIV,
.ppre1 = RCC_CFGR_PPRE_DIV2,
.ppre2 = RCC_CFGR_PPRE_NODIV,
.adcpre = RCC_CFGR_ADCPRE_DIV8,
.usbpre = RCC_CFGR_USBPRE_PLL_CLK_DIV1_5,
.use_hse = true,
.pll_hse_prediv = RCC_CFGR2_PREDIV_NODIV,
.ahb_frequency = 72000000,
.apb1_frequency = 36000000,
.apb2_frequency = 72000000,
},
};
/*---------------------------------------------------------------------------*/
/** @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 Oscillator ID
*/
void rcc_osc_ready_int_clear(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
RCC_CIR |= RCC_CIR_PLLRDYC;
break;
case RCC_HSE:
RCC_CIR |= RCC_CIR_HSERDYC;
break;
case RCC_HSI:
RCC_CIR |= RCC_CIR_HSIRDYC;
break;
case RCC_LSE:
RCC_CIR |= RCC_CIR_LSERDYC;
break;
case RCC_LSI:
RCC_CIR |= RCC_CIR_LSIRDYC;
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Enable the Oscillator Ready Interrupt
@param[in] osc Oscillator ID
*/
void rcc_osc_ready_int_enable(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
RCC_CIR |= RCC_CIR_PLLRDYIE;
break;
case RCC_HSE:
RCC_CIR |= RCC_CIR_HSERDYIE;
break;
case RCC_HSI:
RCC_CIR |= RCC_CIR_HSIRDYIE;
break;
case RCC_LSE:
RCC_CIR |= RCC_CIR_LSERDYIE;
break;
case RCC_LSI:
RCC_CIR |= RCC_CIR_LSIRDYIE;
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Disable the Oscillator Ready Interrupt
@param[in] osc Oscillator ID
*/
void rcc_osc_ready_int_disable(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
RCC_CIR &= ~RCC_CIR_PLLRDYIE;
break;
case RCC_HSE:
RCC_CIR &= ~RCC_CIR_HSERDYIE;
break;
case RCC_HSI:
RCC_CIR &= ~RCC_CIR_HSIRDYIE;
break;
case RCC_LSE:
RCC_CIR &= ~RCC_CIR_LSERDYIE;
break;
case RCC_LSI:
RCC_CIR &= ~RCC_CIR_LSIRDYIE;
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Read the Oscillator Ready Interrupt Flag
@param[in] osc Oscillator ID
@returns int. Boolean value for flag set.
*/
int rcc_osc_ready_int_flag(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
return ((RCC_CIR & RCC_CIR_PLLRDYF) != 0);
break;
case RCC_HSE:
return ((RCC_CIR & RCC_CIR_HSERDYF) != 0);
break;
case RCC_HSI:
return ((RCC_CIR & RCC_CIR_HSIRDYF) != 0);
break;
case RCC_LSE:
return ((RCC_CIR & RCC_CIR_LSERDYF) != 0);
break;
case RCC_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 Oscillator ID
*/
void rcc_wait_for_osc_ready(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
while ((RCC_CR & RCC_CR_PLLRDY) == 0);
break;
case RCC_HSE:
while ((RCC_CR & RCC_CR_HSERDY) == 0);
break;
case RCC_HSI:
while ((RCC_CR & RCC_CR_HSIRDY) == 0);
break;
case RCC_LSE:
while ((RCC_BDCR & RCC_BDCR_LSERDY) == 0);
break;
case RCC_LSI:
while ((RCC_CSR & RCC_CSR_LSIRDY) == 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).
@note The LSE clock is in the backup domain and cannot be enabled until the
backup domain write protection has been removed (see @ref
pwr_disable_backup_domain_write_protect).
@param[in] osc Oscillator ID
*/
void rcc_osc_on(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
RCC_CR |= RCC_CR_PLLON;
break;
case RCC_HSE:
RCC_CR |= RCC_CR_HSEON;
break;
case RCC_HSI:
RCC_CR |= RCC_CR_HSION;
break;
case RCC_LSE:
RCC_BDCR |= RCC_BDCR_LSEON;
break;
case RCC_LSI:
RCC_CSR |= RCC_CSR_LSION;
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.
@note The LSE clock is in the backup domain and cannot be disabled until the
backup domain write protection has been removed (see
@ref pwr_disable_backup_domain_write_protect) or the backup domain has been
(see reset @ref rcc_backupdomain_reset).
@param[in] osc Oscillator ID
*/
void rcc_osc_off(enum rcc_osc osc)
{
switch (osc) {
case RCC_PLL:
RCC_CR &= ~RCC_CR_PLLON;
break;
case RCC_HSE:
RCC_CR &= ~RCC_CR_HSEON;
break;
case RCC_HSI:
RCC_CR &= ~RCC_CR_HSION;
break;
case RCC_LSE:
RCC_BDCR &= ~RCC_BDCR_LSEON;
break;
case RCC_LSI:
RCC_CSR &= ~RCC_CSR_LSION;
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 Set the Source for the System Clock.
@param[in] clk System Clock Selection @ref rcc_cfgr_scs
*/
void rcc_set_sysclk_source(uint32_t clk)
{
RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_SW) |
(clk << RCC_CFGR_SW_SHIFT);
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Set the PLL Multiplication Factor.
@note This only has effect when the PLL is disabled.
@param[in] mul PLL multiplication factor @ref rcc_cfgr_pmf
*/
void rcc_set_pll_multiplication_factor(uint32_t mul)
{
RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_PLLMUL_0_3 & ~RCC_CFGR_PLLMUL_4) |
((mul & 0xf) << RCC_CFGR_PLLMUL_0_3_SHIFT) |
((!!(mul & 0x10)) << RCC_CFGR_PLLMUL_4_SHIFT);
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Set the PLL Clock Source.
@note This only has effect when the PLL is disabled.
@param[in] pllsrc PLL clock source @ref rcc_cfgr_pcs
*/
void rcc_set_pll_source(uint32_t pllsrc)
{
RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_PLLSRC) |
(pllsrc << 16);
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Set the HSE Frequency Divider used as PLL Clock Source.
@note This only has effect when the PLL is disabled.
@param[in] pllxtpre HSE division factor @ref rcc_cfgr_hsepre
*/
void rcc_set_pllxtpre(uint32_t pllxtpre)
{
RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_PLLXTPRE) |
(pllxtpre << 17);
}
/*---------------------------------------------------------------------------*/
/** @brief RCC RTC Clock Enabled Flag
@returns uint32_t. Nonzero if the RTC Clock is enabled.
*/
uint32_t rcc_rtc_clock_enabled_flag(void)
{
return RCC_BDCR & RCC_BDCR_RTCEN;
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Enable the RTC clock
*/
void rcc_enable_rtc_clock(void)
{
RCC_BDCR |= RCC_BDCR_RTCEN;
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Set the Source for the RTC clock
@param[in] clock_source RTC clock source. Only HSE/128, LSE and LSI.
*/
void rcc_set_rtc_clock_source(enum rcc_osc clock_source)
{
uint32_t reg32;
switch (clock_source) {
case RCC_LSE:
/* Turn the LSE on and wait while it stabilises. */
RCC_BDCR |= RCC_BDCR_LSEON;
while ((reg32 = (RCC_BDCR & RCC_BDCR_LSERDY)) == 0);
/* Choose LSE as the RTC clock source. */
RCC_BDCR &= ~((1 << 8) | (1 << 9));
RCC_BDCR |= (1 << 8);
break;
case RCC_LSI:
/* Turn the LSI on and wait while it stabilises. */
RCC_CSR |= RCC_CSR_LSION;
while ((reg32 = (RCC_CSR & RCC_CSR_LSIRDY)) == 0);
/* Choose LSI as the RTC clock source. */
RCC_BDCR &= ~((1 << 8) | (1 << 9));
RCC_BDCR |= (1 << 9);
break;
case RCC_HSE:
/* Turn the HSE on and wait while it stabilises. */
RCC_CR |= RCC_CR_HSEON;
while ((reg32 = (RCC_CR & RCC_CR_HSERDY)) == 0);
/* Choose HSE as the RTC clock source. */
RCC_BDCR &= ~((1 << 8) | (1 << 9));
RCC_BDCR |= (1 << 9) | (1 << 8);
break;
case RCC_PLL:
case RCC_HSI:
/* Unusable clock source, here to prevent warnings. */
/* Turn off clock sources to RTC. */
RCC_BDCR &= ~((1 << 8) | (1 << 9));
break;
}
}
/*---------------------------------------------------------------------------*/
/** @brief ADC Setup the A/D Clock
The ADC's have a common clock prescale setting.
@param[in] adcpre Prescale divider taken from @ref rcc_cfgr_adcpre
*/
void rcc_set_adcpre(uint32_t adcpre)
{
RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_ADCPRE) |
(adcpre << RCC_CFGR_ADCPRE_SHIFT);
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Set the APB2 Prescale Factor.
@param[in] ppre2 APB2 prescale factor @ref rcc_cfgr_apb2pre
*/
void rcc_set_ppre2(uint32_t ppre2)
{
RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_PPRE2) |
(ppre2 << RCC_CFGR_PPRE2_SHIFT);
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Set the APB1 Prescale Factor.
@note The APB1 clock frequency must not exceed 36MHz.
@param[in] ppre1 APB1 prescale factor @ref rcc_cfgr_apb1pre
*/
void rcc_set_ppre1(uint32_t ppre1)
{
RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_PPRE1) |
(ppre1 << RCC_CFGR_PPRE1_SHIFT);
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Set the AHB Prescale Factor.
@param[in] hpre AHB prescale factor @ref rcc_cfgr_ahbpre
*/
void rcc_set_hpre(uint32_t hpre)
{
RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_HPRE) |
(hpre << RCC_CFGR_HPRE_SHIFT);
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Set the USB Prescale Factor.
The prescale factor can be set to 1 (no prescale) for use when the PLL clock is
48MHz, or 1.5 to generate the 48MHz USB clock from a 64MHz PLL clock.
@note This bit cannot be reset while the USB clock is enabled.
@param[in] usbpre USB prescale factor @ref rcc_cfgr_usbpre
*/
void rcc_set_usbpre(uint32_t usbpre)
{
RCC_CFGR = (RCC_CFGR & ~RCC_CFGR_USBPRE) | usbpre;
}
void rcc_set_prediv(uint32_t prediv)
{
RCC_CFGR2 = (RCC_CFGR2 & ~RCC_CFGR2_PREDIV) | prediv;
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Get the System Clock Source.
@returns Unsigned int32. System clock source:
@li 00 indicates HSE
@li 01 indicates LSE
@li 02 indicates PLL
*/
uint32_t rcc_system_clock_source(void)
{
/* Return the clock source which is used as system clock. */
return (RCC_CFGR & RCC_CFGR_SWS) >> RCC_CFGR_SWS_SHIFT;
}
/*---------------------------------------------------------------------------*/
/*
* These functions are setting up the whole clock system for the most common
* input clock and output clock configurations.
*/
/*---------------------------------------------------------------------------*/
/**
* Setup clocks to run from PLL.
* The arguments provide the pll source, multipliers, dividers, all that's
* needed to establish a system clock.
* @param clock clock information structure
*/
void rcc_clock_setup_pll(const struct rcc_clock_scale *clock)
{
if (clock->use_hse) {
/* Enable external high-speed oscillator. */
rcc_osc_on(RCC_HSE);
rcc_wait_for_osc_ready(RCC_HSE);
rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSECLK);
} else {
/* Enable internal high-speed oscillator. */
rcc_osc_on(RCC_HSI);
rcc_wait_for_osc_ready(RCC_HSI);
rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSICLK);
}
/*
* Set prescalers for AHB, ADC, APB1, APB2 and USB.
* Do this before touching the PLL (TODO: why?).
*/
rcc_set_hpre(clock->hpre);
rcc_set_ppre1(clock->ppre1);
rcc_set_ppre2(clock->ppre2);
rcc_set_adcpre(clock->adcpre);
if (clock->use_hse)
rcc_set_usbpre(clock->usbpre);
/* Set the PLL multiplication factor. */
rcc_set_pll_multiplication_factor(clock->pllmul);
if (clock->use_hse) {
/* Select HSE as PLL source. */
rcc_set_pll_source(RCC_CFGR_PLLSRC_HSE_CLK);
/*
* External frequency undivided before entering PLL
* (only valid/needed for HSE).
*/
rcc_set_prediv(clock->pll_hse_prediv);
} else {
/* Select HSI/2 as PLL source. */
rcc_set_pll_source(RCC_CFGR_PLLSRC_HSI_CLK_DIV2);
}
/* Enable PLL oscillator and wait for it to stabilize. */
rcc_osc_on(RCC_PLL);
rcc_wait_for_osc_ready(RCC_PLL);
/* Select PLL as SYSCLK source. */
rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_PLLCLK);
/* Set the peripheral clock frequencies used */
rcc_ahb_frequency = clock->ahb_frequency;
rcc_apb1_frequency = clock->apb1_frequency;
rcc_apb2_frequency = clock->apb2_frequency;
}
/*---------------------------------------------------------------------------*/
/** @brief RCC Reset the Backup Domain
The backup domain registers are reset to disable RTC controls and clear user
data.
*/
void rcc_backupdomain_reset(void)
{
/* Set the backup domain software reset. */
RCC_BDCR |= RCC_BDCR_BDRST;
/* Clear the backup domain software reset. */
RCC_BDCR &= ~RCC_BDCR_BDRST;
}
/**@}*/

View File

@@ -0,0 +1,45 @@
##
## 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
SRCLIBDIR ?= ..
CC = $(PREFIX)gcc
AR = $(PREFIX)ar
TGT_CFLAGS = -Os \
-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
TGT_CFLAGS += $(DEBUG_FLAGS)
TGT_CFLAGS += $(STANDARD_FLAGS)
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS += assert.o
OBJS += gpio.o
OBJS += rcc.o
OBJS += usart.o
OBJS += vector.o
VPATH += ../cm3
include ../Makefile.include

View File

@@ -0,0 +1,52 @@
/** @defgroup gpio_file General Purpose I/O
@brief <b>LM3S General Purpose I/O</b>
@ingroup LM3Sxx
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2011
Gareth McMullin <gareth@blacksphere.co.nz>
@date 10 March 2013
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/lm3s/gpio.h>
void gpio_set(uint32_t gpioport, uint8_t gpios)
{
/* ipaddr[9:2] mask the bits to be set, hence the array index */
GPIO_DATA(gpioport)[gpios] = 0xff;
}
void gpio_clear(uint32_t gpioport, uint8_t gpios)
{
GPIO_DATA(gpioport)[gpios] = 0;
}
/**@}*/

77
libopencm3/lib/lm3s/rcc.c Normal file
View File

@@ -0,0 +1,77 @@
/** @defgroup rcc_file RCC Controller
@brief <b>LM3S RCC Controller</b>
@ingroup LM3Sxx
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2015
Daniele Lacamera \<root at danielinux dot net\>
@date 21 November 2015
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2015 Daniele Lacamera <root@danielinux.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 <stdint.h>
#include <libopencm3/lm3s/rcc.h>
#include <libopencm3/cm3/sync.h>
int rcc_clock_setup_in_xtal_8mhz_out_50mhz(void)
{
uint32_t rcc = RCC_RESET_VALUE;
uint32_t rcc2 = RCC2_RESET_VALUE;
/* Stage 0: Reset values applied */
RCC_CR = rcc;
RCC2_CR = rcc2;
__dmb();
/* Stage 1: Reset Oscillators and select configured values */
RCC_CR = RCC_SYSDIV_50MHZ | RCC_PWMDIV_64 | RCC_XTAL_8MHZ_400MHZ | RCC_USEPWMDIV;
RCC2_CR = (4 - 1) << RCC2_SYSDIV2_SHIFT;
__dmb();
/* Stage 2: Power on oscillators */
rcc &= ~RCC_OFF;
rcc2 &= ~RCC2_OFF;
RCC_CR = rcc;
RCC2_CR = rcc2;
__dmb();
/* Stage 3: Set USESYSDIV */
rcc |= RCC_BYPASS | RCC_USESYSDIV;
RCC_CR = rcc;
__dmb();
/* Stage 4: Wait for PLL raw interrupt */
while ((RCC_RIS & RIS_PLLLRIS) == 0)
;
/* Stage 5: Disable bypass */
rcc &= ~RCC_BYPASS;
rcc2 &= ~RCC2_BYPASS;
RCC_CR = rcc;
RCC2_CR = rcc2;
__dmb();
return 0;
}

View File

@@ -0,0 +1,88 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2013 Gareth McMullin <gareth@blacksphere.co.nz>
* Copyright (C) 2015 Daniele Lacamera <root at danielinux.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/lm3s/usart.h>
void usart_send(uint32_t usart, uint16_t data)
{
USART_DR(usart) = data;
}
uint16_t usart_recv(uint32_t usart)
{
return USART_DR(usart) & 0xff;
}
void usart_send_blocking(uint32_t usart, uint16_t data)
{
while (!usart_is_send_ready(usart));
usart_send(usart, data);
}
bool usart_is_recv_ready(uint32_t usart)
{
return ((USART_FR(usart) & USART_FR_RXFE) == 0);
}
bool usart_is_send_ready(uint32_t usart)
{
return ((USART_FR(usart) & USART_FR_BUSY) == 0);
}
uint16_t usart_recv_blocking(uint32_t usart)
{
while (!usart_is_recv_ready(usart));
return usart_recv(usart);
}
void usart_enable_rx_interrupt(uint32_t usart)
{
USART_IM(usart) |= USART_IM_RX;
}
void usart_enable_tx_interrupt(uint32_t usart)
{
USART_IM(usart) |= USART_IM_TX;
}
void usart_disable_rx_interrupt(uint32_t usart)
{
USART_IM(usart) &= (~USART_IM_RX);
}
void usart_disable_tx_interrupt(uint32_t usart)
{
USART_IM(usart) &= (~USART_IM_TX);
}
void usart_clear_rx_interrupt(uint32_t usart)
{
USART_IC(usart) |= USART_IC_RX;
}
void usart_clear_tx_interrupt(uint32_t usart)
{
USART_IC(usart) |= USART_IC_TX;
}
bool usart_get_interrupt_source(uint32_t usart, uint32_t flag)
{
return ((USART_RIS(usart) & flag) != 0);
}

View File

@@ -0,0 +1,53 @@
##
## 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
SRCLIBDIR ?= ..
FP_FLAGS ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16
CC = $(PREFIX)gcc
AR = $(PREFIX)ar
TGT_CFLAGS = -Os \
-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
TGT_CFLAGS += $(DEBUG_FLAGS)
TGT_CFLAGS += $(STANDARD_FLAGS)
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS += assert.o
OBJS += gpio.o
OBJS += rcc.o
OBJS += systemcontrol.o
OBJS += uart.o
OBJS += vector.o
OBJS += usb.o usb_control.o usb_standard.o usb_msc.o
OBJS += usb_hid.o
OBJS += usb_audio.o usb_cdc.o usb_midi.o
OBJS += usb_lm4f.o
VPATH += ../usb:../cm3
include ../Makefile.include

598
libopencm3/lib/lm4f/gpio.c Normal file
View File

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

499
libopencm3/lib/lm4f/rcc.c Normal file
View File

@@ -0,0 +1,499 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
/**
* @defgroup rcc_file RCC
*
* @ingroup LM4Fxx
*
@author @htmlonly &copy; @endhtmlonly 2012
Alexandru Gagniuc <mr.nuke.me@gmail.com>
* \brief <b>libopencm3 LM4F Clock control API</b>
*
* The LM4F clock API provides functionality 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 access 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 achieve the desired system clock frequency. Where applicable, The LM4F
* clock API uses the new RCC2 register to configure clock parameters.
*
* Enables the main oscillator if the clock source is OSCSRC_MOSC. If the main
* oscillator was previously enabled, it will not be disabled. If desired, it
* can be separately disabled by a call to rcc_disable_main_osc().
*
* Configures the system clock to run from the 400MHz PLL with a divisor of
* pll_div400 applied. If pll_div400 is 0, then the PLL is disabled, and the
* system clock is configured to run off a "raw" clock. If the PLL was
* previously powered on, it will not be disabled. If desired, it can de powered
* off by a call to rcc_pll_off().
*
* @param [in] osc_src Oscillator from where to derive the system clock.
* @param [in] xtal Type of crystal connected to the OSCO/OSCI pins
* @param [in] pll_div400 The clock divisor to apply to the 400MHz PLL clock.
* If 0, then the PLL is disabled, and the system runs
* off a "raw" clock.
*
* @return System clock frequency in Hz
*/
void rcc_sysclk_config(enum osc_src src, enum xtal_t xtal, uint8_t pll_div400)
{
/*
* We could be using the PLL at this point, or we could be running of a
* raw clock. Either way, it is safer to bypass the PLL now.
*/
rcc_pll_bypass_enable();
/* Enable the main oscillator, if needed */
if (src == OSCSRC_MOSC) {
rcc_enable_main_osc();
}
/* Make RCC2 override RCC */
rcc_enable_rcc2();
/* Set XTAL value to 16MHz */
rcc_configure_xtal(xtal);
/* Set the oscillator source */
rcc_set_osc_source(src);
if (pll_div400) {
/* Enable the PLL */
rcc_pll_on();
/* Configure the PLL to the divisor we want */
rcc_change_pll_divisor(pll_div400);
} else {
/* We are running off a raw clock */
switch (src) {
case OSCSRC_PIOSC:
lm4f_rcc_sysclk_freq = 16000000;
break;
case OSCSRC_PIOSC_D4:
lm4f_rcc_sysclk_freq = 4000000;
break;
case OSCSRC_MOSC:
lm4f_rcc_sysclk_freq = xtal_to_freq(xtal);
break;
case OSCSRC_32K_EXT:
lm4f_rcc_sysclk_freq = 32768;
break;
case OSCSRC_30K_INT: /* Fall through. */
default:
/*
* We either are running off the internal 30KHz
* oscillator, which is +- 50% imprecise, or we got a
* bad osc_src parameter.
*/
lm4f_rcc_sysclk_freq = 0;
}
}
}
/**
* @}
* @}
*/

View File

@@ -0,0 +1,40 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/lm4f/systemcontrol.h>
/**
* \brief Enable the clock source for the peripheral
*
* @param[in] periph peripheral and clock type to enable @see lm4f_clken
*/
void periph_clock_enable(enum lm4f_clken periph)
{
MMIO32(SYSCTL_BASE + (periph >> 5)) |= 1 << (periph & 0x1f);
}
/**
* \brief Disable the clock source for the peripheral
*
* @param[in] periph peripheral and clock type to enable @see lm4f_clken
*/
void periph_clock_disable(enum lm4f_clken periph)
{
MMIO32(SYSCTL_BASE + (periph >> 5)) &= ~(1 << (periph & 0x1f));
}

627
libopencm3/lib/lm4f/uart.c Normal file
View File

@@ -0,0 +1,627 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @defgroup uart_file UART
*
* @ingroup LM4Fxx
*
* @author @htmlonly &copy; @endhtmlonly 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* \brief <b>libopencm3 LM4F Universal Asynchronous Receiver Transmitter</b>
*
* The LM4F UART API provides functionality for accessing the UART hardware of
* the LM4F.
*
* Please see the individual UART modules for more details. To use the UART, the
* uart.h header needs to be included:
* @code{.c}
* #include <libopencm3/lm4f/uart.h>
* @endcode
*
* @{
*/
#include <libopencm3/lm4f/uart.h>
#include <libopencm3/lm4f/systemcontrol.h>
#include <libopencm3/lm4f/rcc.h>
/** @defgroup uart_config UART configuration
* @ingroup uart_file
*
* \brief <b>Enabling and configuring the UART</b>
*
* Enabling the UART is a two step process. The GPIO on which the UART resides
* must be enabled, and the UART pins must be configured as alternate function,
* digital pins. Pins must also be muxed to the appropriate alternate function.
* This is done with the GPIO API.
*
* The second step involves enabling and the UART itself. The UART should be
* disabled while it is being configured.
* -# The UART clock must be enabled with @ref periph_clock_enable().
* -# The UART must be disabled with @ref uart_disable().
* -# The UART clock source should be chosen before setting the baudrate.
* -# Baudrate, data bits, stop bit length, and parity can be configured.
* -# If needed, enable CTS or RTS lines via the @ref uart_set_flow_control().
* -# The UART can now be enabled with @ref uart_enable().
*
* For example, to enable UART1 at 115200 8n1 with hardware flow control:
* @code{.c}
* // Enable the UART clock
* periph_clock_enable(RCC_UART1);
* // We need a brief delay before we can access UART config registers
* __asm__("nop"); __asm__("nop"); __asm__("nop");
* // Disable the UART while we mess with its settings
* uart_disable(UART1);
* // Configure the UART clock source as precision internal oscillator
* uart_clock_from_piosc();
* // Set communication parameters
* uart_set_baudrate(UART1, 115200);
* uart_set_databits(UART1, 8);
* uart_set_parity(UART1, UART_PARITY_NONE);
* uart_set_stopbits(UART1, 1);
* // Enable RTC and CTS lines
* uart_set_flow_control(UART1, UART_FLOWCTL_HARD_RTS_CTS);
* // Now that we're done messing with the settings, enable the UART
* uart_enable(UART1);
* @endcode
*/
/**@{*/
/**
* \brief Enable the UART
*
* Enable the UART. The Rx and Tx lines are also enabled.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_enable(uint32_t uart)
{
UART_CTL(uart) |= (UART_CTL_UARTEN | UART_CTL_RXE | UART_CTL_TXE);
}
/**
* \brief Disable the UART
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_disable(uint32_t uart)
{
UART_CTL(uart) &= ~UART_CTL_UARTEN;
}
/**
* \brief Set UART baudrate
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] baud Baud rate in bits per second (bps).*
*/
void uart_set_baudrate(uint32_t uart, uint32_t baud)
{
uint32_t clock;
/* Are we running off the internal clock or system clock? */
if (UART_CC(uart) == UART_CC_CS_PIOSC) {
clock = 16000000;
} else {
clock = rcc_get_system_clock_frequency();
}
/* Find the baudrate divisor */
uint32_t div = (((clock * 8) / baud) + 1) / 2;
/* Set the baudrate divisors */
UART_IBRD(uart) = div / 64;
UART_FBRD(uart) = div % 64;
}
/**
* \brief Set UART databits
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] databits number of data bits per transmission.
*/
void uart_set_databits(uint32_t uart, uint8_t databits)
{
uint32_t reg32, bitint32_t;
/* This has the same effect as using UART_LCRH_WLEN_5/6/7/8 directly */
bitint32_t = (databits - 5) << 5;
/* TODO: What about 9 data bits? */
reg32 = UART_LCRH(uart);
reg32 &= ~UART_LCRH_WLEN_MASK;
reg32 |= bitint32_t;
UART_LCRH(uart) = reg32;
}
/**
* \brief Set UART stopbits
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] bits the requested number of stopbits, either 1 or 2.
*/
void uart_set_stopbits(uint32_t uart, uint8_t stopbits)
{
if (stopbits == 2) {
UART_LCRH(uart) |= UART_LCRH_STP2;
} else {
UART_LCRH(uart) &= ~UART_LCRH_STP2;
}
}
/**
* \brief Set UART parity
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] bits the requested parity scheme.
*/
void uart_set_parity(uint32_t uart, enum uart_parity parity)
{
uint32_t reg32;
reg32 = UART_LCRH(uart);
reg32 |= UART_LCRH_PEN;
reg32 &= ~(UART_LCRH_SPS | UART_LCRH_EPS);
switch (parity) {
case UART_PARITY_NONE:
/* Once we disable parity the other bits are meaningless */
UART_LCRH(uart) &= ~UART_LCRH_PEN;
return;
case UART_PARITY_ODD:
break;
case UART_PARITY_EVEN:
reg32 |= UART_LCRH_EPS;
break;
case UART_PARITY_STICK_0:
reg32 |= (UART_LCRH_SPS | UART_LCRH_EPS);
break;
case UART_PARITY_STICK_1:
reg32 |= UART_LCRH_SPS;
break;
}
UART_LCRH(uart) = reg32;
}
/**
* \brief Set the flow control scheme
*
* Set the flow control scheme by enabling or disabling RTS and CTS lines. This
* will only have effect if the given UART supports the RTS and CTS lines.
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] flow The flow control scheme to use (none, RTS, CTS or both) \n
* UART_FLOWCTL_RTS -- enable the RTS line \n
* UART_FLOWCTL_CTS -- enable the CTS line \n
* UART_FLOWCTL_RTS_CTS -- enable both RTS and CTS lines
*/
void uart_set_flow_control(uint32_t uart, enum uart_flowctl flow)
{
uint32_t reg32 = UART_CTL(uart);
reg32 &= ~(UART_CTL_RTSEN | UART_CTL_CTSEN);
if (flow == UART_FLOWCTL_RTS) {
reg32 |= UART_CTL_RTSEN;
} else if (flow == UART_FLOWCTL_CTS) {
reg32 |= UART_CTL_CTSEN;
} else if (flow == UART_FLOWCTL_RTS_CTS) {
reg32 |= (UART_CTL_RTSEN | UART_CTL_CTSEN);
}
UART_CTL(uart) = reg32;
}
/**
* \brief Clock the UART module from the internal oscillator
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_clock_from_piosc(uint32_t uart)
{
UART_CC(uart) = UART_CC_CS_PIOSC;
}
/**
* \brief Clock the UART module from the system clock
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_clock_from_sysclk(uint32_t uart)
{
UART_CC(uart) = UART_CC_CS_SYSCLK;
}
/**@}*/
/** @defgroup uart_send_recv UART transmission and reception
* @ingroup uart_file
*
* \brief <b>Sending and receiving data through the UART</b>
*
* Primitives for sending and receiving 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 interrupt flag for the processed IRQs
* uart_clear_interrupt_flag(UART0, serviced_irqs);
* }
* @endcode
*/
/**@{*/
/**
* \brief Enable Specific UART Interrupts
*
* Enable any combination of interrupts. Interrupts may be OR'ed together to
* enable them with one call. For example, to enable both the RX and CTS
* interrupts, pass (UART_INT_RX | UART_INT_CTS)
*
* Note that the NVIC must be enabled and properly configured for the interrupt
* to be routed to the CPU.
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] ints Interrupts which to enable. Any combination of interrupts may
* be specified by OR'ing then together
*/
void uart_enable_interrupts(uint32_t uart, enum uart_interrupt_flag ints)
{
UART_IM(uart) |= ints;
}
/**
* \brief Enable Specific UART Interrupts
*
* Disabe any combination of interrupts. Interrupts may be OR'ed together to
* disable them with one call. For example, to disable both the RX and CTS
* interrupts, pass (UART_INT_RX | UART_INT_CTS)
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] ints Interrupts which to disable. Any combination of interrupts
* may be specified by OR'ing then together
*/
void uart_disable_interrupts(uint32_t uart, enum uart_interrupt_flag ints)
{
UART_IM(uart) &= ~ints;
}
/**
* \brief Enable the UART Receive Interrupt.
*
* Note that the NVIC must be enabled and properly configured for the interrupt
* to be routed to the CPU.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_enable_rx_interrupt(uint32_t uart)
{
uart_enable_interrupts(uart, UART_INT_RX);
}
/**
* \brief Disable the UART Receive Interrupt.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_disable_rx_interrupt(uint32_t uart)
{
uart_disable_interrupts(uart, UART_INT_RX);
}
/**
* \brief Enable the UART Transmit Interrupt.
*
* Note that the NVIC must be enabled and properly configured for the interrupt
* to be routed to the CPU.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_enable_tx_interrupt(uint32_t uart)
{
uart_enable_interrupts(uart, UART_INT_TX);
}
/**
* \brief Disable the UART Transmit Interrupt.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_disable_tx_interrupt(uint32_t uart)
{
uart_disable_interrupts(uart, UART_INT_TX);
}
/**
* \brief Mark interrupt as serviced
*
* After an interrupt is services, its flag must be cleared. If the flag is not
* cleared, then execution will jump back to the start of the ISR after the ISR
* returns.
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] ints Interrupts which to clear. Any combination of interrupts may
* be specified by OR'ing then together
*/
void uart_clear_interrupt_flag(uint32_t uart, enum uart_interrupt_flag ints)
{
UART_ICR(uart) |= ints;
}
/**@}*/
/** @defgroup uart_dma UART DMA control
* @ingroup uart_file
*
* \brief <b>Enabling Direct Memory Access transfers for the UART</b>
*
*/
/**@{*/
/**
* \brief Enable the UART Receive DMA.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_enable_rx_dma(uint32_t uart)
{
UART_DMACTL(uart) |= UART_DMACTL_RXDMAE;
}
/**
* \brief Disable the UART Receive DMA.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_disable_rx_dma(uint32_t uart)
{
UART_DMACTL(uart) &= ~UART_DMACTL_RXDMAE;
}
/**
* \brief Enable the UART Transmit DMA.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_enable_tx_dma(uint32_t uart)
{
UART_DMACTL(uart) |= UART_DMACTL_TXDMAE;
}
/**
* \brief Disable the UART Transmit DMA.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_disable_tx_dma(uint32_t uart)
{
UART_DMACTL(uart) &= ~UART_DMACTL_TXDMAE;
}
/**@}*/
/** @defgroup uart_fifo UART FIFO control
* @ingroup uart_file
*
* \brief <b>Enabling and controlling UART FIFO</b>
*
* The UART on the LM4F can either be used with a single character TX and RX
* buffer, or with a 8 character TX and RX FIFO. In order to use the FIFO it
* must be enabled, this is done with uart_enable_fifo() and can be disabled
* again with uart_disable_fifo(). On reset the FIFO is disabled, and it must
* be explicitly be enabled.
*
* When enabling the UART FIFOs, RX and TX interrupts are triggered according
* to the amount of data in the FIFOs. For the RX FIFO the trigger level is
* defined by how full the FIFO is. The TX FIFO trigger level is defined by
* how empty the FIFO is instead.
*
* For example, to enable the FIFOs and trigger interrupts for a single
* received and single transmitted character:
* @code{.c}
* uart_enable_fifo(UART0);
* uart_set_fifo_trigger_levels(UART0, UART_FIFO_RX_TRIG_1_8,
* UART_FIFO_TX_TRIG_7_8);
* @endcode
*/
/**@{*/
/**
* \brief Enable FIFO for the UART.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_enable_fifo(uint32_t uart)
{
UART_LCRH(uart) |= UART_LCRH_FEN;
}
/**
* \brief Disable FIFO for the UART.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_disable_fifo(uint32_t uart)
{
UART_LCRH(uart) &= ~UART_LCRH_FEN;
}
/**
* \brief Set the FIFO trigger levels.
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] rx_level Trigger level for RX FIFO
* @param[in] tx_level Trigger level for TX FIFO
*/
void uart_set_fifo_trigger_levels(uint32_t uart,
enum uart_fifo_rx_trigger_level rx_level,
enum uart_fifo_tx_trigger_level tx_level)
{
UART_IFLS(uart) = rx_level | tx_level;
}
/**@}*/
/**
* @}
*/

View File

@@ -0,0 +1,24 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2016 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/>.
*/
static void pre_main(void)
{
/* Enable FPU */
SCB_CPACR |= SCB_CPACR_FULL * (SCB_CPACR_CP10 | SCB_CPACR_CP11);
}

View File

@@ -0,0 +1,41 @@
##
## 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
SRCLIBDIR ?= ..
CC = $(PREFIX)gcc
AR = $(PREFIX)ar
TGT_CFLAGS = -Os \
-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
TGT_CFLAGS += $(DEBUG_FLAGS)
TGT_CFLAGS += $(STANDARD_FLAGS)
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS += gpio.o
VPATH += ../cm3
include ../Makefile.include

View File

@@ -0,0 +1,42 @@
/** @defgroup gpio_file GPIO
@ingroup LPC13xx
@brief <b>libopencm3 LPC13xx General Purpose I/O</b>
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2009 Uwe Hermann <uwe@hermann-uwe.de>
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/lpc13xx/gpio.h>
void gpio_set(uint32_t gpioport, uint16_t gpios)
{
GPIO_DATA(gpioport) = gpios;
}
/**@}*/

View File

@@ -0,0 +1,42 @@
##
## 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
SRCLIBDIR ?= ..
CC = $(PREFIX)gcc
AR = $(PREFIX)ar
TGT_CFLAGS = -Os \
-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
TGT_CFLAGS += $(DEBUG_FLAGS)
TGT_CFLAGS += $(STANDARD_FLAGS)
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS += gpio.o
OBJS += pwr.o
VPATH += ../cm3
include ../Makefile.include

View File

@@ -0,0 +1,48 @@
/** @defgroup gpio_file GPIO
@ingroup LPC17xx
@brief <b>libopencm3 LPC17xx General Purpose I/O</b>
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2009 Uwe Hermann <uwe@hermann-uwe.de>
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/lpc17xx/gpio.h>
void gpio_set(uint32_t gpioport, uint32_t gpios)
{
GPIO_SET(gpioport) = gpios;
}
void gpio_clear(uint32_t gpioport, uint32_t gpios)
{
GPIO_CLR(gpioport) = gpios;
}
/**@}*/

View File

@@ -0,0 +1,48 @@
/** @defgroup pwr-file PWR
@ingroup LPC17xx
@brief <b>libopencm3 LPC17xx Power Control</b>
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2013 Silvio Gissi <silvio.gissi@outlook.com>
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2013 Silvio Gissi <silvio.gissi@outlook.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/lpc17xx/pwr.h>
void pwr_enable_peripherals(uint32_t peripherals)
{
PWR_PCONP |= peripherals;
}
void pwr_disable_peripherals(uint32_t peripherals)
{
PWR_PCONP &= ~peripherals;
}
/**@}*/

View File

@@ -0,0 +1,53 @@
/** @defgroup gpio_file GPIO
@ingroup LPC43xx
@brief <b>libopencm3 LPC43xx General Purpose I/O</b>
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2009 Uwe Hermann <uwe@hermann-uwe.de>
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/lpc43xx/gpio.h>
void gpio_set(uint32_t gpioport, uint32_t gpios)
{
GPIO_SET(gpioport) = gpios;
}
void gpio_clear(uint32_t gpioport, uint32_t gpios)
{
GPIO_CLR(gpioport) = gpios;
}
void gpio_toggle(uint32_t gpioport, uint32_t gpios)
{
GPIO_NOT(gpioport) = gpios;
}
/**@}*/

View File

@@ -0,0 +1,102 @@
/** @defgroup i2c_file I2C
@ingroup LPC43xx
@brief <b>libopencm3 LPC43xx I2C</b>
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2012 Michael Ossmann <mike@ossmann.com>
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* 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/>.
*/
/*
* 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>
void i2c0_init(const uint16_t duty_cycle_count)
{
/* enable input on SCL and SDA pins */
SCU_SFSI2C0 = SCU_I2C0_NOMINAL;
I2C0_SCLH = duty_cycle_count;
I2C0_SCLL = duty_cycle_count;
/* clear the control bits */
I2C0_CONCLR = (I2C_CONCLR_AAC | I2C_CONCLR_SIC
| I2C_CONCLR_STAC | I2C_CONCLR_I2ENC);
/* enable I2C0 */
I2C0_CONSET = I2C_CONSET_I2EN;
}
/* transmit start bit */
void i2c0_tx_start(void)
{
I2C0_CONCLR = I2C_CONCLR_SIC;
I2C0_CONSET = I2C_CONSET_STA;
while (!(I2C0_CONSET & I2C_CONSET_SI));
I2C0_CONCLR = I2C_CONCLR_STAC;
}
/* transmit data byte */
void i2c0_tx_byte(uint8_t byte)
{
if (I2C0_CONSET & I2C_CONSET_STA) {
I2C0_CONCLR = I2C_CONCLR_STAC;
}
I2C0_DAT = byte;
I2C0_CONCLR = I2C_CONCLR_SIC;
while (!(I2C0_CONSET & I2C_CONSET_SI));
}
/* receive data byte */
uint8_t i2c0_rx_byte(void)
{
if (I2C0_CONSET & I2C_CONSET_STA) {
I2C0_CONCLR = I2C_CONCLR_STAC;
}
I2C0_CONCLR = I2C_CONCLR_SIC;
while (!(I2C0_CONSET & I2C_CONSET_SI));
return I2C0_DAT;
}
/* transmit stop bit */
void i2c0_stop(void)
{
if (I2C0_CONSET & I2C_CONSET_STA) {
I2C0_CONCLR = I2C_CONCLR_STAC;
}
I2C0_CONSET = I2C_CONSET_STO;
I2C0_CONCLR = I2C_CONCLR_SIC;
}
/**@}*/

View File

@@ -0,0 +1,58 @@
/*
* 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;
}
}

View File

@@ -0,0 +1,43 @@
##
## 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
SRCLIBDIR ?= ../..
CC = $(PREFIX)gcc
AR = $(PREFIX)ar
TGT_CFLAGS = -O2 -Wall -Wextra -I../../../include -fno-common \
-mcpu=cortex-m0 -mthumb -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD -DLPC43XX -DLPC43XX_M0
TGT_CFLAGS += $(DEBUG_FLAGS)
TGT_CFLAGS += $(STANDARD_FLAGS)
# ARFLAGS = rcsv
ARFLAGS = rcs
# LPC43xx common files for M4 / M0
OBJ_LPC43XX = gpio.o scu.o i2c.o ssp.o uart.o timer.o
#LPC43xx M0 specific file + Generic LPC43xx M4/M0 files
OBJS = $(OBJ_LPC43XX)
VPATH += ../:../../cm3
include ../../Makefile.include

View File

@@ -0,0 +1,50 @@
##
## 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
SRCLIBDIR ?= ../..
FP_FLAGS ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16
CC = $(PREFIX)gcc
AR = $(PREFIX)ar
TGT_CFLAGS = -O2 \
-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
TGT_CFLAGS += $(DEBUG_FLAGS)
TGT_CFLAGS += $(STANDARD_FLAGS)
ARFLAGS = rcs
# LPC43xx common files for M4 / M0
OBJ_LPC43XX = gpio.o scu.o i2c.o ssp.o uart.o timer.o
#LPC43xx M4 specific file + Generic LPC43xx M4/M0 files
OBJS = $(OBJ_LPC43XX) ipc.o
VPATH += ../:../../cm3
include ../../Makefile.include

View File

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

View File

@@ -0,0 +1,52 @@
/** @defgroup scu_file System Control Unit
@ingroup LPC43xx
@brief <b>libopencm3 LPC43xx System Control Unit</b>
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2012 Benjamin Vernoux <titanmkd@gmail.com>
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/lpc43xx/scu.h>
/* For pin_conf_normal value see scu.h define SCU_CONF_XXX or Configuration for
* different I/O pins types
*/
void scu_pinmux(scu_grp_pin_t group_pin, uint32_t scu_conf)
{
MMIO32(group_pin) = scu_conf;
}
/* For other special SCU register USB1, I2C0, ADC0/1, DAC, EMC clock delay See
* scu.h
*/
/* For Pin interrupt select register see scu.h SCU_PINTSEL0 & SCU_PINTSEL1 */
/**@}*/

View File

@@ -0,0 +1,140 @@
/** @defgroup ssp_file SSP
@ingroup LPC43xx
@brief <b>libopencm3 LPC43xx SSP</b>
@version 1.0.0
@author @htmlonly &copy; @endhtmlonly 2012 Benjamin Vernoux <titanmkd@gmail.com>
LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**@{*/
#include <libopencm3/lpc43xx/ssp.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;
} 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;
/* Disable SSP before to configure it */
SSP_CR1(ssp_port) = 0x0;
/* Configure SSP */
clock = serial_clock_rate;
SSP_CPSR(ssp_port) = clk_prescale;
SSP_CR0(ssp_port) =
(data_size | frame_format | cpol_cpha_format | (clock<<8));
/* Enable SSP */
SSP_CR1(ssp_port) = (SSP_ENABLE | mode | master_slave | slave_option);
}
static void ssp_wait_until_not_busy(ssp_num_t ssp_num)
{
uint32_t ssp_port;
if (ssp_num == SSP0_NUM) {
ssp_port = SSP0;
} else {
ssp_port = SSP1;
}
while ((SSP_SR(ssp_port) & SSP_SR_BSY));
}
/* This Function Wait Data TX Ready, and Write Data to SSP */
uint16_t ssp_transfer(ssp_num_t ssp_num, uint16_t data)
{
uint32_t ssp_port;
if (ssp_num == SSP0_NUM) {
ssp_port = SSP0;
} else {
ssp_port = SSP1;
}
/* Wait Until FIFO not full */
while ((SSP_SR(ssp_port) & SSP_SR_TNF) == 0);
SSP_DR(ssp_port) = data;
/* Wait for not busy, since we're controlling CS# of
* devices manually and need to wait for the data to
* be sent. It may also be important to wait here
* in case we're configuring devices via SPI and also
* with GPIO control -- we need to know when SPI
* commands are effective before altering a device's
* state with GPIO. I'm thinking the MAX2837, for
* example...
*/
ssp_wait_until_not_busy(ssp_num);
/* Wait Until Data Received (Rx FIFO not Empty) */
while ((SSP_SR(ssp_port) & SSP_SR_RNE) == 0);
return SSP_DR(ssp_port);
}
/**@}*/

View File

@@ -0,0 +1,72 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2013 Ben Gamari <bgamari@physics.umass.edu>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* This provides the code for the "next gen" EXTI block provided in F2/F4/L1
* devices. (differences only in the source selection)
*/
#include <libopencm3/lpc43xx/timer.h>
void timer_reset(uint32_t timer_peripheral)
{
TIMER_TCR(timer_peripheral) |= TIMER_TCR_CRST;
TIMER_TCR(timer_peripheral) &= ~TIMER_TCR_CRST;
}
void timer_enable_counter(uint32_t timer_peripheral)
{
TIMER_TCR(timer_peripheral) |= TIMER_TCR_CEN;
}
void timer_disable_counter(uint32_t timer_peripheral)
{
TIMER_TCR(timer_peripheral) &= ~TIMER_TCR_CEN;
}
void timer_set_counter(uint32_t timer_peripheral, uint32_t count)
{
TIMER_TC(timer_peripheral) = count;
}
uint32_t timer_get_counter(uint32_t timer_peripheral)
{
return TIMER_TC(timer_peripheral);
}
uint32_t timer_get_prescaler(uint32_t timer_peripheral)
{
return TIMER_PR(timer_peripheral);
}
void timer_set_prescaler(uint32_t timer_peripheral, uint32_t prescaler)
{
TIMER_PR(timer_peripheral) = prescaler;
}
void timer_set_mode(uint32_t timer_peripheral, uint32_t mode)
{
TIMER_CTCR(timer_peripheral) = mode |
(TIMER_CTCR(timer_peripheral) & TIMER_CTCR_MODE_MASK);
}
void timer_set_count_input(uint32_t timer_peripheral, uint32_t input)
{
TIMER_CTCR(timer_peripheral) = input |
(TIMER_CTCR(timer_peripheral) & TIMER_CTCR_CINSEL_MASK);
}

View File

@@ -0,0 +1,243 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Benjamin Vernoux <titanmkd@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/lpc43xx/uart.h>
#include <libopencm3/lpc43xx/cgu.h>
#define UART_SRC_32K 0x00
#define UART_SRC_IRC 0x01
#define UART_SRC_ENET_RX 0x02
#define UART_SRC_ENET_TX 0x03
#define UART_SRC_GP_CLKIN 0x04
#define UART_SRC_XTAL 0x06
#define UART_SRC_PLL0USB 0x07
#define UART_SRC_PLL0AUDIO 0x08
#define UART_SRC_PLL1 0x09
#define UART_SRC_IDIVA 0x0C
#define UART_SRC_IDIVB 0x0D
#define UART_SRC_IDIVC 0x0E
#define UART_SRC_IDIVD 0x0F
#define UART_SRC_IDIVE 0x10
#define UART_CGU_AUTOBLOCK_CLOCK_BIT 11
/* clock source selection (5 bits) */
#define UART_CGU_BASE_CLK_SEL_SHIFT 24
uint32_t dummy_read;
/*
* UART Init function
*/
void uart_init(uart_num_t uart_num, uart_databit_t data_nb_bits,
uart_stopbit_t data_nb_stop, uart_parity_t data_parity,
uint16_t uart_divisor, uint8_t uart_divaddval, uint8_t uart_mulval)
{
uint32_t lcr_config;
uint32_t uart_port;
uart_port = uart_num;
switch (uart_num) {
case UART0_NUM:
/* use PLL1 as clock source for UART0 */
CGU_BASE_UART0_CLK = (1<<UART_CGU_AUTOBLOCK_CLOCK_BIT) |
(CGU_SRC_PLL1<<UART_CGU_BASE_CLK_SEL_SHIFT);
break;
case UART1_NUM:
/* use PLL1 as clock source for UART1 */
CGU_BASE_UART1_CLK = (1<<UART_CGU_AUTOBLOCK_CLOCK_BIT) |
(CGU_SRC_PLL1<<UART_CGU_BASE_CLK_SEL_SHIFT);
break;
case UART2_NUM:
/* use PLL1 as clock source for UART2 */
CGU_BASE_UART2_CLK = (1<<UART_CGU_AUTOBLOCK_CLOCK_BIT) |
(CGU_SRC_PLL1<<UART_CGU_BASE_CLK_SEL_SHIFT);
break;
case UART3_NUM:
/* use PLL1 as clock source for UART3 */
CGU_BASE_UART3_CLK = (1<<UART_CGU_AUTOBLOCK_CLOCK_BIT) |
(CGU_SRC_PLL1<<UART_CGU_BASE_CLK_SEL_SHIFT);
break;
default:
return; /* error */
}
/* FIFOs RX/TX Enabled and Reset RX/TX FIFO (DMA Mode is also cleared)*/
UART_FCR(uart_port) = (UART_FCR_FIFO_EN | UART_FCR_RX_RS |
UART_FCR_TX_RS);
/* Disable FIFO */
UART_FCR(uart_port) = 0;
/* Dummy read (to clear existing data) */
while (UART_LSR(uart_port) & UART_LSR_RDR) {
dummy_read = UART_RBR(uart_port);
}
/* Wait end of TX & disable TX */
UART_TER(uart_port) = UART_TER_TXEN;
/* Wait for current transmit complete */
while (!(UART_LSR(uart_port) & UART_LSR_THRE));
/* Disable Tx */
UART_TER(uart_port) = 0;
/* Disable interrupt */
UART_IER(uart_port) = 0;
/* Set LCR to default state */
UART_LCR(uart_port) = 0;
/* Set ACR to default state */
UART_ACR(uart_port) = 0;
/* Dummy Read to Clear Status */
dummy_read = UART_LSR(uart_port);
/*
Table 835. USART Fractional Divider Register:
UARTbaudrate = PCLK / ( 16* (((256*DLM)+ DLL)*(1+(DivAddVal/MulVal))) )
The value of MULVAL and DIVADDVAL should comply to the following
conditions:
1. 1 <= MULVAL <= 15
2. 0 <= DIVADDVAL <= 14
3. DIVADDVAL < MULVAL
*/
/* Set DLAB Bit */
UART_LCR(uart_port) |= UART_LCR_DLAB_EN;
UART_DLM(uart_port) = UART_LOAD_DLM(uart_divisor);
UART_DLL(uart_port) = UART_LOAD_DLL(uart_divisor);
/* Clear DLAB Bit */
UART_LCR(uart_port) &= (~UART_LCR_DLAB_EN) & UART_LCR_BITMASK;
UART_FDR(uart_port) = UART_FDR_BITMASK &
(UART_FDR_MULVAL(uart_mulval) | UART_FDR_DIVADDVAL(uart_divaddval));
/* Read LCR config & Force Enable of Divisor Latches Access */
lcr_config = (UART_LCR(uart_port) & UART_LCR_DLAB_EN) &
UART_LCR_BITMASK;
lcr_config |= data_nb_bits; /* Set Nb Data Bits */
lcr_config |= data_nb_stop; /* Set Nb Stop Bits */
lcr_config |= data_parity; /* Set Data Parity */
/* Write LCR (only 8bits) */
UART_LCR(uart_port) = (lcr_config & UART_LCR_BITMASK);
/* Enable TX */
UART_TER(uart_port) = UART_TER_TXEN;
}
/*
* This Function return if data are received or not received.
*/
uart_rx_data_ready_t uart_rx_data_ready(uart_num_t uart_num)
{
uint32_t uart_port;
uint8_t uart_status;
uart_rx_data_ready_t data_ready;
uart_port = uart_num;
uart_status = UART_LSR(uart_port) & 0xFF;
/* Check Error */
if ((uart_status & UART_LSR_ERROR_MASK) == 0) {
/* No errors check if data is ready */
if ((uart_status & UART_LSR_RDR) == 0) {
data_ready = UART_RX_NO_DATA;
} else {
data_ready = UART_RX_DATA_READY;
}
} else {
/* UART Error */
data_ready = UART_RX_DATA_ERROR;
}
return data_ready;
}
/*
* This Function Wait until Data RX Ready, and return Data Read from UART.
*/
uint8_t uart_read(uart_num_t uart_num)
{
uint32_t uart_port;
uint8_t uart_val;
uart_port = uart_num;
/* Wait Until Data Received (Rx Data Not Ready) */
while ((UART_LSR(uart_port) & UART_LSR_RDR) == 0);
uart_val = (UART_RBR(uart_port) & UART_RBR_MASKBIT);
return uart_val;
}
/*
* This Function Wait until Data RX Ready, and return Data Read from UART.
*/
uint8_t uart_read_timeout(uart_num_t uart_num, uint32_t rx_timeout_nb_cycles,
uart_error_t *error)
{
uint32_t uart_port;
uint8_t uart_val;
uint32_t counter;
uart_port = uart_num;
/* Wait Until Data Received (Rx Data Not Ready) */
counter = 0;
while ((UART_LSR(uart_port) & UART_LSR_RDR) == 0) {
if (rx_timeout_nb_cycles > 0) {
counter++;
if (counter >= rx_timeout_nb_cycles) {
*error = UART_TIMEOUT_ERROR;
return 0;
}
}
}
uart_val = (UART_RBR(uart_port) & UART_RBR_MASKBIT);
/* Clear error */
*error = UART_NO_ERROR;
return uart_val;
}
/* This Function Wait Data TX Ready, and Write Data to UART
if rx_timeout_nb_cycles = 0 Infinite wait
*/
void uart_write(uart_num_t uart_num, uint8_t data)
{
uint32_t uart_port;
uart_port = uart_num;
/* Wait Until FIFO not full */
while ((UART_LSR(uart_port) & UART_LSR_THRE) == 0);
UART_THR(uart_port) = data;
}

View File

@@ -0,0 +1,46 @@
##
## 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>
## Copyright (C) 2018 Dmitry Rezvanov <dmitry.rezvanov@yandex.ru>
##
## 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_msp432e4
SRCLIBDIR ?= ../..
FP_FLAGS ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16
CC = $(PREFIX)gcc
AR = $(PREFIX)ar
TGT_CFLAGS = -Os \
-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 -DMSP432E4
TGT_CFLAGS += $(DEBUG_FLAGS)
TGT_CFLAGS += $(STANDARD_FLAGS)
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS += gpio.o
OBJS += systemcontrol.o
VPATH += ../:../../cm3:../common
include ../../Makefile.include

View File

@@ -0,0 +1,448 @@
/** @defgroup gpio_file General-Purpose I/O
*
* @ingroup MSP432E4xx
*
* @brief libopencm3 MSP432E4xx General Purpose Input/Outputs
*
* @version 1.0.0
*
* @date 23 September 2018
*
* LGPL License Terms @ref lgpl_license
*/
/*
* 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>
* Copyright (C) 2018 Dmitry Rezvanov <dmitry.rezvanov@yandex.ru>
*
* 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/msp432/e4/gpio.h>
#include <libopencm3/msp432/e4/systemcontrol.h>
/** @brief General Purpose Input/Outputs Set Pin Mode
*
* Sets the Pin Direction, Analog/Digital Mode and Output Pin Pull,
* for 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
* - GPIO_MODE_OUTPUT -- Configure pin as output
* - GPIO_MODE_INPUT -- Configure pin as input
* - GPIO_MODE_ANALOG -- Configure pin as analog function
* @param[in] pull_up_down Pin pull up/down configuration @ref gpio_pull_up_down
* - GPIO_PUPD_NONE -- Do not pull the pin high or low
* - GPIO_PUPD_PULLUP -- Pull the pin high
* - GPIO_PUPD_PULLDOWN -- Pull the pin low
* @param[in] gpios 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, enum gpio_mode mode,
enum gpio_pull_up_down pull_up_down, uint8_t gpios)
{
GPIO_AFSEL(gpioport) &= ~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_AFSEL(gpioport) |= gpios;
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 (pull_up_down) {
case GPIO_PUPD_PULLUP:
GPIO_PDR(gpioport) &= ~gpios;
GPIO_PUR(gpioport) |= gpios;
break;
case GPIO_PUPD_PULLDOWN:
GPIO_PUR(gpioport) &= ~gpios;
GPIO_PDR(gpioport) |= gpios;
break;
case GPIO_PUPD_NONE: /* Fall through */
default:
GPIO_PUR(gpioport) &= ~gpios;
GPIO_PDR(gpioport) &= ~gpios;
break;
}
}
/** @brief General Purpose Input/Outputs Set Output Options
*
* When the pin is set to output mode, this sets the configuration
* (open drain/push pull), drive strength, speed and slew rate control,
* for a set of GPIO pins on a given GPIO port.
*
* @param[in] gpioport GPIO block register address base @ref gpio_reg_base
* @param[in] otype Output driver configuration @ref gpio_output_type
* - 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
* - GPIO_DRIVE_2MA -- 2mA drive \n
* - GPIO_DRIVE_4MA -- 4mA drive \n
* - GPIO_DRIVE_6MA -- 4mA drive \n
* - GPIO_DRIVE_8MA -- 8mA drive \n
* - GPIO_DRIVE_10MA -- 10mA drive \n
* - GPIO_DRIVE_12MA -- 12mA drive
* @param[in] slewctl Pin slew rate control select @ref gpio_slew_ctl
* @note Available only for 8, 10 and 12-ma drive strength.
* - GPIO_SLEW_CTL_ENABLE -- Slew rate control enable
* - GPIO_SLEW_CTL_DISABLE -- Slew rate control disable
* @param[in] gpios 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,
enum gpio_output_type otype,
enum gpio_drive_strength drive,
enum gpio_slew_ctl slewctl,
uint8_t gpios)
{
uint8_t i;
uint8_t pin_mask;
if (otype == GPIO_OTYPE_OD) {
GPIO_ODR(gpioport) |= gpios;
} else {
GPIO_ODR(gpioport) &= ~gpios;
}
GPIO_PP(gpioport) |= GPIO_PP_EDE;
for (i = 0; i < 8; i++) {
pin_mask = (1 << i);
if (!(gpios & pin_mask)) {
continue;
}
GPIO_PC(gpioport) &= ~GPIO_PC_EDM_MASK(i);
GPIO_PC(gpioport) |= GPIO_PC_EDM(i, GPIO_PC_EDM_FULL_RANGE);
}
GPIO_DR4R(gpioport) &= ~gpios;
GPIO_DR8R(gpioport) &= ~gpios;
GPIO_DR12R(gpioport) &= ~gpios;
switch (drive) {
case GPIO_DRIVE_4MA:
GPIO_DR4R(gpioport) |= gpios;
break;
case GPIO_DRIVE_6MA:
GPIO_DR8R(gpioport) |= gpios;
break;
case GPIO_DRIVE_8MA:
GPIO_DR4R(gpioport) |= gpios;
GPIO_DR8R(gpioport) |= gpios;
break;
case GPIO_DRIVE_10MA:
GPIO_DR8R(gpioport) |= gpios;
GPIO_DR12R(gpioport) |= gpios;
break;
case GPIO_DRIVE_12MA:
GPIO_DR4R(gpioport) |= gpios;
GPIO_DR8R(gpioport) |= gpios;
GPIO_DR12R(gpioport) |= gpios;
break;
case GPIO_DRIVE_2MA: /* Fall through */
default:
/* don't anything */
break;
}
if ((slewctl == GPIO_SLEW_CTL_ENABLE) &&
((drive == GPIO_DRIVE_8MA) || (drive == GPIO_DRIVE_10MA) ||
(drive == GPIO_DRIVE_12MA))) {
GPIO_SLR(gpioport) |= gpios;
} else {
GPIO_SLR(gpioport) &= ~gpios;
}
}
/** @brief General Purpose Input/Outputs Set Alternate Function Selection
*
* 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.
*
* Because AF0 is not used on the MSP432E4,
* passing GPIO_AF_DISABLE 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 GPIO_AF_DISABLE to
* disable the alternate function multiplexing.
* @param[in] gpios 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, uint8_t gpios)
{
uint32_t pctl32;
uint8_t pin_mask;
uint8_t 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;
/* 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 &= ~GPIO_PCTL_MASK(i);
pctl32 |= GPIO_PCTL_AF(i, (alt_func_num & 0xf));
}
GPIO_PCTL(gpioport) = pctl32;
}
/** @brief General Purpose Input/Outputs Configure Interrupt Trigger
*
* Sets the trigger level/edge, for 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
* - GPIO_TRIG_LVL_LOW -- Trigger on low level
* - GPIO_TRIG_LVL_HIGH -- Trigger on high level
* - GPIO_TRIG_EDGE_FALL -- Trigger on falling edges
* - GPIO_TRIG_EDGE_RISE -- Trigger on rising edges
* - GPIO_TRIG_EDGE_BOTH -- Trigger on all edges
* @param[in] gpios Pin identifiers @ref gpio_pin_id. If multiple pins are
* to be configure, use bitwise OR '|' to separate them.
*/
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 General Purpose Input/Outputs 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 GPIO block register address base @ref gpio_reg_base
* @param[in] gpios Pin identifiers @ref gpio_pin_id. If multiple pins are
* to be changed, use bitwise OR '|' to separate them.
*/
void gpio_set(uint32_t gpioport, uint8_t gpios)
{
GPIO_DATA(gpioport)[gpios] = 0xFF;
}
/** @brief General Purpose Input/Outputs 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 GPIO block register address base @ref gpio_reg_base
* @param[in] gpios Pin identifiers @ref gpio_pin_id. If multiple pins are
* to be changed, use bitwise OR '|' to separate them.
*/
void gpio_clear(uint32_t gpioport, uint8_t gpios)
{
GPIO_DATA(gpioport)[gpios] = 0x0;
}
/** @brief General Purpose Input/Outputs Read a Group of Pins
*
* @param[in] gpioport GPIO block register address base @ref gpio_reg_base
* @param[in] gpios Pin identifiers @ref gpio_pin_id. If multiple pins are
* to be read, use bitwise OR '|' to separate them.
*
* @return Unsigned int8 value of the pin values. The bit position of the pin
value returned corresponds to the pin number.
*/
uint8_t gpio_get(uint32_t gpioport, uint8_t gpios)
{
return (uint8_t)GPIO_DATA(gpioport)[gpios];
}
/** @brief General Purpose Input/Outputs Toggle a Group of Pins
*
* Toggle one or more pins of the given GPIO port.
* The non-toggled pins are not affected.
*
* @param[in] gpioport GPIO block register address base @ref gpio_reg_base
* @param[in] gpios Pin identifiers @ref gpio_pin_id. If multiple pins are
* to be changed, use bitwise OR '|' to separate them.
*/
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;
}
/** @brief General Purpose Input/Outputs Read from a Port
*
* Read the current value of the given GPIO port.
*
* @param[in] gpioport GPIO block register address base @ref gpio_reg_base
*
* @return Unsigned int8. The value held in the specified GPIO port.
*/
uint8_t gpio_port_read(uint32_t gpioport)
{
return (uint8_t)GPIO_DATA(gpioport)[GPIO_ALL];
}
/** @brief General Purpose Input/Outputs Write to a Port
*
* Write a value to the given GPIO port.
*
* @param[in] gpioport GPIO block register address base @ref gpio_reg_base
* @param[in] data Unsigned int8. The value to be written to the GPIO port.
*/
void gpio_port_write(uint32_t gpioport, uint8_t data)
{
GPIO_DATA(gpioport)[GPIO_ALL] = data;
}
/** @brief General Purpose Input/Outputs Enable Interrupts on specified pins
*
* Enable interrupts on the specified GPIO pins.
*
* @note 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 Pin identifiers @ref gpio_pin_id.
* Pins whose interrupts to enable.
* If multiple pins are to be enable interrupt,
* use bitwise OR '|' to separate them.
*/
void gpio_enable_interrupts(uint32_t gpioport, uint8_t gpios)
{
GPIO_IM(gpioport) |= gpios;
}
/** @brief General Purpose Input/Outputs Disable interrupts on specified pins
*
* Disable interrupts on the specified GPIO pins.
*
* @param[in] gpioport GPIO block register address base @ref gpio_reg_base
* @param[in] gpios Pin identifiers @ref gpio_pin_id.
* Pins whose interrupts to disable.
* If multiple pins are to be disable interrupt,
* use bitwise OR '|' to separate them.
*/
void gpio_disable_interrupts(uint32_t gpioport, uint8_t gpios)
{
GPIO_IM(gpioport) &= ~gpios;
}
/** @brief General Purpose Input/Outputs Unlock The Commit Control
*
* 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 Pin identifiers @ref gpio_pin_id.
* If multiple pins are to be unlock,
* use bitwise OR '|' to separate them.
*/
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;
}
/** @brief General Purpose Input/Outputs Determine if interrupt is generated
* by the given pin
*
* @param[in] gpioport GPIO block register address base @ref gpio_reg_base
* @param[in] gpios Source pin identifiers @ref gpio_pin_id.
* If multiple pins are to be check,
* use bitwise OR '|' to separate them.
*
* @return Unsigned int8. The bit position of the pin
value returned corresponds to the pin number.
*/
uint8_t gpio_is_interrupt_source(uint32_t gpioport, uint8_t gpios)
{
return GPIO_MIS(gpioport) & gpios;
}
/** @brief General Purpose Input/Outputs 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] gpioport GPIO block register address base @ref gpio_reg_base
* @param[in] gpios Pin identifiers @ref gpio_pin_id. If multiple pins are
* to be clear interrupt flag, use bitwise OR '|' to separate them.
*/
void gpio_clear_interrupt_flag(uint32_t gpioport, uint8_t gpios)
{
GPIO_ICR(gpioport) |= gpios;
}

View File

@@ -0,0 +1,130 @@
/** @defgroup systemcontrol_file System Control
*
* @ingroup MSP432E4xx
*
* @brief libopencm3 MSP432E4xx System Control
*
* @version 1.0.0
*
* @date 22 July 2018
*
* LGPL License Terms @ref lgpl_license
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
* Copyright (C) 2018 Dmitry Rezvanov <dmitry.rezvanov@yandex.ru>
*
* 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/msp432/e4/systemcontrol.h>
#include <stdbool.h>
#define _SYSCTL_REG(base, i) MMIO32((base) + ((i) >> 5))
#define _SYSCTL_BIT(i) (1 << ((i) & 0x1f))
/*----------------------------------------------------------------------------*/
/** @brief System Control Enable Peripheral Clock
*
* @param[in] clock_mode ::msp432_clock_mode Clock mode
* @param[in] periph ::msp432_periph Peripheral block
*/
void sysctl_periph_clock_enable(enum msp432_clock_mode clock_mode,
enum msp432_periph periph)
{
_SYSCTL_REG(SYSCTL_BASE + clock_mode, periph) |= _SYSCTL_BIT(periph);
}
/*----------------------------------------------------------------------------*/
/** @brief System Control Disable Peripheral Clock
*
* @param[in] clock_mode ::msp432_clock_mode Clock mode
* @param[in] periph ::msp432_periph Peripheral block
*/
void sysctl_periph_clock_disable(enum msp432_clock_mode clock_mode,
enum msp432_periph periph)
{
_SYSCTL_REG(SYSCTL_BASE + clock_mode, periph) &= ~_SYSCTL_BIT(periph);
}
/*----------------------------------------------------------------------------*/
/** @brief System Control Peripheral Software Reset
*
* @param[in] periph ::msp432_periph Peripheral block
*/
void sysctl_periph_reset(enum msp432_periph periph)
{
_SYSCTL_REG((uint32_t) &SYSCTL_SRWD, periph) |= _SYSCTL_BIT(periph);
}
/*----------------------------------------------------------------------------*/
/** @brief System Control Peripheral Clear Software Reset
*
* @param[in] periph ::msp432_periph Peripheral block
*/
void sysctl_periph_clear_reset(enum msp432_periph periph)
{
_SYSCTL_REG((uint32_t) &SYSCTL_SRWD, periph) &= ~_SYSCTL_BIT(periph);
}
/*----------------------------------------------------------------------------*/
/** @brief System Control Peripheral Is Present
*
* @param[in] periph ::msp432_periph Peripheral block
*/
bool sysctl_periph_is_present(enum msp432_periph periph)
{
uint32_t reg32 = _SYSCTL_REG((uint32_t) &SYSCTL_PPWD, periph);
uint32_t mask = _SYSCTL_BIT(periph);
return((reg32 & mask) != 0);
}
/*----------------------------------------------------------------------------*/
/** @brief System Control Peripheral Is Ready
*
* @param[in] periph ::msp432_periph Peripheral block
*/
bool sysctl_periph_is_ready(enum msp432_periph periph)
{
uint32_t reg32 = _SYSCTL_REG((uint32_t) &SYSCTL_PRWD, periph);
uint32_t mask = _SYSCTL_BIT(periph);
return((reg32 & mask) != 0);
}
/*----------------------------------------------------------------------------*/
/** @brief System Control Peripheral Set Power State
*
* @param[in] power_mode ::msp432_power_mode Power mode
* @param[in] periph ::msp432_periph Peripheral block
*
* @note If the module is in run, sleep or deep-sleep mode - the module
* is powered and receives a clock regardless of the value of power mode.
*/
void sysctl_periph_set_power_state(enum msp432_power_mode power_mode,
enum msp432_periph periph)
{
if (power_mode == POWER_ENABLE) {
_SYSCTL_REG((uint32_t) &SYSCTL_PCWD, periph) |= _SYSCTL_BIT(periph);
} else {
_SYSCTL_REG((uint32_t) &SYSCTL_PCWD, periph) &= ~_SYSCTL_BIT(periph);
}
}
#undef _SYSCTL_REG
#undef _SYSCTL_BIT

View File

@@ -0,0 +1,50 @@
##
## This file is part of the libopencm3 project.
## Copyright (C) 2017-2018 Unicore MX project<dev(at)lists(dot)unicore-mx(dot)org>
## Copyright (C) 2021 Eduard Drusa <ventyl86(at)netkosice(dot)sk>
##
## 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_nrf51
SRCLIBDIR ?= ../..
CC = $(PREFIX)gcc
AR = $(PREFIX)ar
FP_FLAGS ?= -msoft-float
TGT_CFLAGS = -Os -Wall -Wextra -I../../../include -fno-common \
-mcpu=cortex-m0 -mthumb $(FP_FLAGS) \
-Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD -DNRF51
TGT_CFLAGS += $(DEBUG_FLAGS)
TGT_CFLAGS += $(STANDARD_FLAGS)
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS += clock_common.o clock.o
OBJS += gpio.o
OBJS += i2c_common.o
OBJS += ppi.o
OBJS += rtc.o
OBJS += radio_common.o ./radio.o
OBJS += timer.o
OBJS += uart.o
VPATH += ../../cm3:../common
include ../../Makefile.include

View File

@@ -0,0 +1,45 @@
/** @addtogroup clock_file CLOCK peripheral API
*
* @brief <b>Access functions for the NRF51 Clock Controller </b>
*
* @ingroup peripheral_apis
* LGPL License Terms @ref lgpl_license
* @author @htmlonly &copy; @endhtmlonly 2016
* Roel Postelmans
*
*/
/*
* This file is part of the unicore-mx 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/nrf/clock.h>
#include <libopencm3/nrf/periph.h>
/**@{*/
/** @brief Select nominal frequency of external crystal for HFCLK.
*
* @details This register has to match the actual crystal used in design to
* enable correct behaviour.
*
* @param[in] freq enum clock_xtal_freq
* */
void clock_set_xtal_freq(enum clock_xtal_freq freq)
{
CLOCK_XTALFREQ = freq;
}
/**@}*/

View File

@@ -0,0 +1,66 @@
/** @addtogroup radio_file RADIO peripheral API
*
* @brief <b>Access functions for the NRF51 2.4 GHz Radio </b>
* @ingroup peripheral_apis
* LGPL License Terms @ref lgpl_license
* @author @htmlonly &copy; @endhtmlonly 2016
* Maxim Sloyko <maxims@google.com>
*
*/
/*
* This file is part of the unicore-mx 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/nrf/ficr.h>
#include <libopencm3/nrf/radio.h>
/**@{*/
/** @brief Set radio mode.
*
* @details The function also performs all required overrides for BLE and NRF mode.
*
* @param[in] mode the new mode.
* */
void radio_set_mode(enum radio_mode mode)
{
/* This is alias to memory register, thus volatile */
volatile uint32_t *override_pos = 0;
if ((RADIO_MODE_BLE_1MBIT == mode)
&& (FICR_OVERRIDEEN & ~FICR_OVERRIDEEN_BLE_1MBIT)) {
/* Need to use Override */
override_pos = &FICR_BLE_1MBIT0;
} else if ((RADIO_MODE_NRF_1MBIT == mode)
&& (FICR_OVERRIDEEN & ~FICR_OVERRIDEEN_NRF_1MBIT)) {
override_pos = &FICR_NRF_1MBIT0;
}
if (override_pos) {
uint8_t i;
for (i = 0; i <= 4; ++i, ++override_pos) {
RADIO_OVERRIDE(i) = *override_pos;
}
RADIO_OVERRIDE(4) |= RADIO_OVERRIDE4_ENABLE;
} else {
RADIO_OVERRIDE(4) &= ~RADIO_OVERRIDE4_ENABLE;
}
RADIO_MODE = mode;
}
/**@}*/

View File

@@ -0,0 +1,50 @@
##
## This file is part of the libopencm3 project.
##
## Copyright (C) 2017-2018 Unicore MX project<dev(at)lists(dot)unicore-mx(dot)org>
## Copyright (C) 2021 Eduard Drusa <ventyl86(at)netkosice(dot)sk>
##
## 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_nrf52
SRCLIBDIR ?= ../..
CC = $(PREFIX)gcc
AR = $(PREFIX)ar
FP_FLAGS ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16
TGT_CFLAGS = -Os -Wall -Wextra -I../../../include -fno-common \
-mcpu=cortex-m4 -mthumb $(FP_FLAGS) \
-Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD -DNRF52
TGT_CFLAGS += $(DEBUG_FLAGS)
TGT_CFLAGS += $(STANDARD_FLAGS)
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS += clock_common.o
OBJS += gpio.o
OBJS += i2c.o i2c_common.o
OBJS += ppi.o
OBJS += radio_common.o
OBJS += rtc.o
OBJS += timer.o
OBJS += uart.o
VPATH += ../../cm3:../common
include ../../Makefile.include

View File

@@ -0,0 +1,62 @@
/** @addtogroup i2c_file I2C peripheral API
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2022 Eduard Drusa <ventyl86(at)netkosice(dot)sk>
*
* 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/nrf/52/i2c.h>
/**@{*/
/** Configure I2C transmit buffer properties
*
* Configures transmit buffer for EasyDMA transaction. This API
* is only available if @ref I2C_MODE_MASTER mode is activated.
*
* Configures linear TX buffer for EasyDMA transmission.
* @param[in] i2c i2c peripheral base, see @ref i2c_block
* @param[in] buffer address of buffer start
* @param[in] len length of data in the buffer
*/
void i2c_set_tx_buffer(uint32_t i2c, const uint8_t *buffer, uint8_t len)
{
I2C_TXDPTR(i2c) = (uint32_t) buffer;
I2C_TXDMAXCNT(i2c) = len;
I2C_TXDLIST(i2c) = 0;
}
/** Configure I2C receive buffer properties
*
* Configures receive buffer for EasyDMA transaction. This API
* is only available if @ref I2C_MODE_MASTER mode is activated.
*
* Configures linear RX buffer for EasyDMA transmission.
* @param[in] i2c i2c peripheral base, see @ref i2c_block
* @param[in] buffer address of buffer start
* @param[in] len length of the buffer
*/
void i2c_set_rx_buffer(uint32_t i2c, uint8_t *buffer, uint8_t len)
{
I2C_RXDPTR(i2c) = (uint32_t) buffer;
I2C_RXDMAXCNT(i2c) = len;
I2C_RXDLIST(i2c) = 0;
}
/** @} */

View File

@@ -0,0 +1,83 @@
/** @addtogroup clock_file CLOCK peripheral API
*
* @brief <b>Access functions for the Clock Controller</b>
*
* @ingroup peripheral_apis
* LGPL License Terms @ref lgpl_license
* @author @htmlonly &copy; @endhtmlonly 2016 Maxim Sloyko <maxims@google.com>
* @author @htmlonly &copy; @endhtmlonly 2021 Eduard Drusa <ventyl86 at netkosice dot sk>
*
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2017-2018 Unicore MX project<dev(at)lists(dot)unicore-mx(dot)org>
* Copyright (C) 2021 Eduard Drusa <ventyl86(at)netkosice(dot)sk>
*
* 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/nrf/clock.h>
#include <libopencm3/nrf/periph.h>
/**@{*/
/** @brief Start Low Frequency Clock
*
* @param[in] wait bool: If true, will busy wait for the clock to start.
*/
void clock_start_lfclk(bool wait)
{
PERIPH_TRIGGER_TASK(CLOCK_TASK_LFCLKSTART);
if (wait) {
while (!(CLOCK_LFCLKSTAT & CLOCK_LFCLKSTAT_STATE));
}
}
/** @brief Stop Low Frequency Clock */
void clock_stop_lfclk()
{
PERIPH_TRIGGER_TASK(CLOCK_TASK_LFCLKSTOP);
}
/** @brief Start High Frequency Crystal Oscillator.
*
* @details Oscillator needs to be running for the radio to work.
*
* @param[in] wait bool If true, will busy wait for the clock to start.
*/
void clock_start_hfclk(bool wait)
{
PERIPH_TRIGGER_TASK(CLOCK_TASK_HFCLKSTART);
if (wait) {
while (!(CLOCK_HFCLKSTAT & CLOCK_HFCLKSTAT_STATE));
}
}
/** @brief Stop High Frequency Crystal Oscillator */
void clock_stop_hfclk()
{
PERIPH_TRIGGER_TASK(CLOCK_TASK_HFCLKSTOP);
}
/** @brief Low Frequency Clock Source.
*
* @param[in] lfclk_src enum clock_lfclk_src
*/
void clock_set_lfclk_src(enum clock_lfclk_src lfclk_src)
{
CLOCK_LFCLKSRC = lfclk_src;
}
/**@}*/

View File

@@ -0,0 +1,208 @@
/** @addtogroup gpio_file GPIO peripheral API
*
* @brief <b>Access functions for the I/O Controller</b>
*
* @ingroup peripheral_apis
* LGPL License Terms @ref lgpl_license
* @author @htmlonly &copy; @endhtmlonly 2016
* Maxim Sloyko <maxims@google.com>
*
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2017-2018 Unicore MX project<dev(at)lists(dot)unicore-mx(dot)org>
* Copyright (C) 2021 Eduard Drusa <ventyl86(at)netkosice(dot)sk>
*
* 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/nrf/gpio.h>
/** @brief Atomic set output
*
* @param[in] gpioport Port identifier @ref gpio_port_id
* @param[in] gpios Pin identifiers @ref gpio_pin_id
*/
void gpio_set(uint32_t gpioport, uint32_t gpios)
{
(void) gpioport;
GPIO_OUTSET = gpios;
}
/** @brief Atomic clear output
*
* @param[in] gpioport Port identifier @ref gpio_port_id
* @param[in] gpios Pin identifiers @ref gpio_pin_id
*/
void gpio_clear(uint32_t gpioport, uint32_t gpios)
{
(void) gpioport;
GPIO_OUTCLR = gpios;
}
/** @brief Toggle output
*
* @param[in] gpioport Port identifier @ref gpio_port_id
* @param[in] gpios Pin identifiers @ref gpio_pin_id
*/
void gpio_toggle(uint32_t gpioport, uint32_t gpios)
{
(void) gpioport;
uint32_t reg_val = GPIO_OUT;
GPIO_OUTCLR = reg_val & gpios;
GPIO_OUTSET = (~reg_val) & gpios;
}
/** @brief Read GPIO values
*
* @param[in] gpioport Port identifier @ref gpio_port_id
* @param[in] gpios Pin identifiers @ref gpio_pin_id
*/
uint32_t gpio_get(uint32_t gpioport, uint32_t gpios)
{
(void) gpioport;
return GPIO_IN & gpios;
}
/** @brief Set GPIO Pin Mode
*
* Sets the mode (input/output) and configuration (analog/digitial and
* open drain/push pull), for a set of GPIO pins on a given GPIO port.
*
* @param[in] gpioport Port identifier @ref gpio_port_id
* @param[in] mode Pin mode @ref gpio_mode
* @param[in] pull_up_down Pull up / pull down configuration @ref gpio_pupd
* @param[in] gpios 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, uint32_t mode, uint32_t pull_up_down,
uint32_t gpios)
{
(void) gpioport;
uint8_t i = 0;
while (gpios) {
if (gpios & 1) {
GPIO_PIN_CNF(i) = (
GPIO_PIN_CNF(i) &
~((GPIO_CNF_MODE_MASK << GPIO_CNF_MODE_SHIFT)
| (GPIO_CNF_PUPD_MASK << GPIO_CNF_PUPD_SHIFT)
)
) | (mode << GPIO_CNF_MODE_SHIFT)
| (pull_up_down << GPIO_CNF_PUPD_SHIFT);
}
++i;
gpios >>= 1;
}
}
/** Configure GPIO pin input and output specifics.
*
* Configure drive strength and input sensing for given GPIO port.
* @param [in] gpioport GPIO port identifier, see @ref gpio_port_id
* @param [in] drive Drive schema used to drive pin, see @ref gpio_drive
* @param [in] sense Pin sensing mechanism, see @ref gpio_sense
* @param[in] gpios Pin identifiers @ref gpio_pin_id
* If multiple pins are to be set, use bitwise OR '|' to separate
* them.
*/
void gpio_set_options(uint32_t gpioport, uint32_t drive, uint32_t sense,
uint32_t gpios)
{
(void) gpioport;
uint8_t i = 0;
while (gpios) {
if (gpios & 1) {
GPIO_PIN_CNF(i) = (GPIO_PIN_CNF(i) &
~((GPIO_CNF_DRIVE_MASK << GPIO_CNF_DRIVE_SHIFT)
| (GPIO_CNF_SENSE_MASK << GPIO_CNF_SENSE_SHIFT)
)
) | (drive << GPIO_CNF_DRIVE_SHIFT)
| (sense << GPIO_CNF_SENSE_SHIFT);
}
++i;
gpios >>= 1;
}
}
/** @brief Configure Task in GPIO TE Module
*
* @param[in] task_num uint8_t Task number (0-3)
* @param[in] pin_num uint8_t GPIO Pin number (0-31)
* @param[in] polarity uint8_t polarity Operation to perform when task is triggered.
* @param[in] init uint8_t Initial state of the pin, non-zero means initially active,
* zero means initially inactive
*/
void gpio_configure_task(uint8_t task_num,
uint8_t pin_num, uint8_t polarity, uint32_t init)
{
/* any non-zero value means, that pin is active */
if (init) {
init = GPIO_TE_CONFIG_OUTINIT;
}
GPIO_TE_CONFIG(task_num) = (GPIO_TE_MODE_TASK << GPIO_TE_CONFIG_MODE_SHIFT)
| (pin_num << GPIO_TE_CONFIG_PSEL_SHIFT)
| (polarity << GPIO_TE_CONFIG_POLARITY_SHIFT)
| init;
}
/** @brief Configure Event in GPIO TE Module
*
* @param[in] event_num Event number (0-3)
* @param[in] pin_num GPIO Pin number (0-31)
* @param[in] polarity Operation to perform when task is triggered.
*/
void gpio_configure_event(uint8_t event_num, uint8_t pin_num, uint8_t polarity)
{
GPIO_TE_CONFIG(event_num) = (GPIO_TE_MODE_EVENT << GPIO_TE_CONFIG_MODE_SHIFT)
| (pin_num << GPIO_TE_CONFIG_PSEL_SHIFT)
| (polarity << GPIO_TE_CONFIG_POLARITY_SHIFT);
}
/** @brief Enable GPIO interrupts
*
* @param[in] mask interrupts to enable.
*/
void gpio_enable_interrupts(uint32_t mask)
{
GPIO_INTENSET = mask;
}
/** @brief Disable GPIO interrupts
*
* @param[in] mask interrupts to disable.
*/
void gpio_disable_interrupts(uint32_t mask)
{
GPIO_INTENCLR = mask;
}
/** @brief Disable all GPIO interrupts
*
*/
void gpio_clear_interrupts(void)
{
GPIO_INTENCLR = 0xffffffff;
}
/** @} */

View File

@@ -0,0 +1,206 @@
/** @addtogroup i2c_file I2C peripheral API
*
* @brief <b>Access functions for the I2C Controller</b>
*
* @ingroup peripheral_apis
* LGPL License Terms @ref lgpl_license
* @author @htmlonly &copy; @endhtmlonly 2016
* Maxim Sloyko <maxims@google.com>
* @author @htmlonly &copy; @endhtmlonly 2021 - 2022
* Eduard Drusa <ventyl86(at)netkosice(dot)sk>
*
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2017-2018 Unicore MX project<dev(at)lists(dot)unicore-mx(dot)org>
* Copyright (C) 2021 Eduard Drusa <ventyl86(at)netkosice(dot)sk>
*
* 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/nrf/i2c.h>
/**@{*/
/** @brief Enable I2C peripheral
*
* @param[in] i2c i2c peripheral base, see @ref i2c_block
* @param[in] mode i2c @ref i2c_mode
*/
void i2c_enable(uint32_t i2c, uint32_t mode)
{
I2C_ENABLE(i2c) = mode;
}
/** @brief Disable I2C peripheral
*
* @param[in] i2c i2c peripheral base, see @ref i2c_block
*/
void i2c_disable(uint32_t i2c)
{
I2C_ENABLE(i2c) = 0;
}
/** @brief Start I2C transmission.
*
* Starts STARTTX task, which generates start condition on I2C bus and
* transmits address previously configured by @ref i2c_set_address.
*
* @param[in] i2c i2c peripheral base, see @ref i2c_block.
*/
void i2c_start_tx(uint32_t i2c)
{
I2C_TASK_STARTTX(i2c) = 1;
}
/** @brief Start I2C reception.
*
* @param[in] i2c i2c peripheral base, see @ref i2c_block.
*/
void i2c_start_rx(uint32_t i2c)
{
I2C_TASK_STARTRX(i2c) = 1;
}
/** @brief Signal stop on I2C line.
*
* @param[in] i2c i2c peripheral base, see @ref i2c_block.
*/
void i2c_send_stop(uint32_t i2c)
{
I2C_TASK_STOP(i2c) = 1;
}
/** @brief Select Fast (400kHz) mode.
*
* @param[in] i2c i2c peripheral base, see @ref i2c_block.
*/
void i2c_set_fast_mode(uint32_t i2c)
{
I2C_FREQUENCY(i2c) = I2C_FREQUENCY_400K;
}
/** @brief Select Standard (100kHz) mode.
*
* @param[in] i2c i2c peripheral base, see @ref i2c_block.
*/
void i2c_set_standard_mode(uint32_t i2c)
{
I2C_FREQUENCY(i2c) = I2C_FREQUENCY_100K;
}
/** @brief Set I2C frequency.
*
* In addition to Standard (100kHz) and Fast (400kHz) modes
* this peripheral also supports 250kHz mode.
*
* @param[in] i2c i2c peripheral base, see @ref i2c_block
* @param[in] freq frequency constant. See @ref i2c_freq_const for details
* and note that this is not actually a frequency in Hz or kHz.
*/
void i2c_set_frequency(uint32_t i2c, uint32_t freq)
{
I2C_FREQUENCY(i2c) = freq;
}
/** @brief Write Data to TXD register to be sent.
*
* Writes one byte into transmission buffer. This API is only
* available if @ref I2C_MODE_LEGACY is activated.
*
* @param[in] i2c i2c peripheral base, see @ref i2c_block
* @param[in] data byte to send next.
*/
void i2c_send_data(uint32_t i2c, uint8_t data)
{
I2C_TXD(i2c) = data;
}
/** @brief Read Data from RXD register.
*
* Reads one byte from reception buffer. This API is only
* available if @ref I2C_MODE_LEGACY is activated.
*
* @param[in] i2c i2c peripheral base, see @ref i2c_block
* @returns data from RXD register.
*/
uint8_t i2c_get_data(uint32_t i2c)
{
return (uint8_t)I2C_RXD(i2c);
}
/** @brief Select GPIO pins to be used by this peripheral.
*
* Configures GPIO pins assigned to SCL and SDA signals. These pins are only occupied
* by I2C peripheral whenever it is enabled using @ref i2c_enable. It is possible to
* ignore any given signal and not map it to pin by using special value of
* @ref GPIO_UNCONNECTED instead of @ref gpio_pin_id values.
*
* This needs to be configured when no transaction is in progress.
*
* @param[in] i2c i2c peripheral base, see @ref i2c_block
* @param[in] scl_pin GPIO pin used for SCL signal
* @param[in] sda_pin GPIO pin used for SDA signal
*/
void i2c_select_pins(uint32_t i2c, uint32_t scl_pin, uint32_t sda_pin)
{
if (scl_pin != GPIO_UNCONNECTED) {
I2C_PSELSCL(i2c) = __GPIO2PIN(scl_pin);
} else {
I2C_PSELSCL(i2c) = scl_pin;
}
if (sda_pin != GPIO_UNCONNECTED) {
I2C_PSELSDA(i2c) = __GPIO2PIN(sda_pin);
} else {
I2C_PSELSDA(i2c) = sda_pin;
}
}
/** @brief Set 7bit I2C address of the device you wish to communicate with.
*
* @param[in] i2c i2c peripheral base, see @ref i2c_block
* @param[in] addr device address (7bit).
*/
void i2c_set_address(uint32_t i2c, uint8_t addr)
{
I2C_ADDRESS(i2c) = addr;
}
/** @brief Resume I2C transaction.
*
* This function is unusual, but required to implement
* i2c exchange with this peripheral.
*
* @param[in] i2c i2c peripheral base, see @ref i2c_block
*/
void i2c_resume(uint32_t i2c)
{
PERIPH_TRIGGER_TASK(I2C_TASK_RESUME(i2c));
}
/** Configure event -> task shortcuts
*
* Sets new shortcut configuration bitmask for I2C peripheral.
*
* @param[in] i2c i2c peripheral base, see @ref i2c_block
* @param[in] shorts @ref i2c_shorts activated
*/
void i2c_set_shorts(uint32_t i2c, uint32_t shorts)
{
I2C_SHORTS(i2c) = shorts;
}
/**@}*/

View File

@@ -0,0 +1,145 @@
/** @addtogroup ppi_file PPI peripheral API
*
* @brief <b>Access functions for the Programmable Peripheral Interconnect </b>
*
* @ingroup peripheral_apis
* LGPL License Terms @ref lgpl_license
* @author @htmlonly &copy; @endhtmlonly 2016
* Maxim Sloyko <maxims@google.com>
*
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2017-2018 Unicore MX project<dev(at)lists(dot)unicore-mx(dot)org>
* Copyright (C) 2021 Eduard Drusa <ventyl86(at)netkosice(dot)sk>
*
* 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 <stdint.h>
#include <libopencm3/nrf/ppi.h>
/**@{*/
/** @brief Configure PPI Channel.
*
* @param[in] chan_num uint8_t Channel number (0-15).
* @param[in] eep uint32_t Event endpoint. Memory address of the event endpoint.
* @param[in] tep uint32_t Task endpoint. Memory address of the task endpoint.
*/
void ppi_configure_channel(uint8_t chan_num, uint32_t eep, uint32_t tep)
{
PPI_CH_EEP(chan_num) = eep;
PPI_CH_TEP(chan_num) = tep;
}
/** @brief Enable PPI channels, given the channels mask.
*
* @param[in] channels uint32_t mask of the channels to enable.
*/
void ppi_enable_channels(uint32_t channels)
{
PPI_CHENSET = channels;
}
/** @brief Disable PPI channels, given the channels mask.
*
* @param[in] channels uint32_t mask of the channels to disable.
*/
void ppi_disable_channels(uint32_t channels)
{
PPI_CHENCLR = channels;
}
/** @brief Set channels group, given channels mask.
*
* @param[in] group uint8_t group number (0-3)
* @param[in] channels uint32_t mask of the channels to group together.
*/
void ppi_set_group(uint8_t group, uint32_t channels)
{
PPI_CHG(group) = channels;
}
/** @brief Enable previously configured group of channels.
*
* @param[in] group uint8_t group number (0-3)
*/
void ppi_enable_group(uint8_t group)
{
PPI_TASK_CHG_EN(group) = 1;
}
/** @brief Disable previously configured group of channels.
*
* @param[in] group uint8_t group number (0-3)
*/
void ppi_disable_group(uint8_t group)
{
PPI_TASK_CHG_DIS(group) = 1;
}
/** @brief Configure new channel.
*
* This is the alternative API, which requires the caller to store the mask of used channels.
*
* @param chan_map uint32_t* The mask of channels that are already in use.
* For the first call initialize with zero and pass in.
* @param[in] eep uint32_t Event endpoint.
* @param[in] tep uint32_t Task endpoint.
* @param enable bool If true, enable the channel immediately.
* @return The number of the new channel. If there are no channels available, returns 0xff.
*/
uint8_t ppi_add_channel(uint32_t *chan_map, uint32_t eep, uint32_t tep, bool enable)
{
/* Find a free channel */
uint8_t i;
uint32_t chan_bit;
for (i = 0, chan_bit = 1; i <= PPI_MAX_PROG_CHANNEL; ++i, chan_bit <<= 1) {
if (!(chan_bit & *chan_map)) {
*chan_map |= chan_bit;
break;
}
}
/* If all channels are taken, return error. */
if (i > PPI_MAX_PROG_CHANNEL) {
return 0xff;
}
ppi_configure_channel(i, eep, tep);
if (enable) {
ppi_enable_channels(chan_bit);
}
return i;
}
/** @brief Disable channel and remove it from the map of used channels.
*
* This is the alternative API, which requires the caller to store the mask of used channels.
*
* @param chan_map uint32_t* The mask of channels that are already in use.
* For the first call initialize with zero and pass in.
* @param[in] chan_num uint8_t the number of the channel to remove from the map.
*/
void ppi_remove_channel(uint32_t *chan_map, uint8_t chan_num)
{
ppi_disable_channels(PPI_CH(chan_num));
*chan_map &= ~(PPI_CH(chan_num));
}
/**@}*/

View File

@@ -0,0 +1,250 @@
/** @addtogroup radio_file RADIO peripheral API
*
* @brief <b>Access functions for the 2.4 GHz Radio </b>
*
* @ingroup peripheral_apis
* LGPL License Terms @ref lgpl_license
* @author @htmlonly &copy; @endhtmlonly 2016
* Maxim Sloyko <maxims@google.com>
*
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2017-2018 Unicore MX project<dev(at)lists(dot)unicore-mx(dot)org>
* Copyright (C) 2021 Eduard Drusa <ventyl86(at)netkosice(dot)sk>
*
* 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/nrf/ficr.h>
#include <libopencm3/nrf/radio.h>
/**@{*/
/** @brief Set radio transmission power.
*
* @details Note, not all supported power levels are BLE compliant.
*
* @param[in] txpower enum radio_txpower
* */
void radio_set_txpower(enum radio_txpower txpower)
{
RADIO_TXPOWER = txpower;
}
/** @brief Set bit transmission order to LSB first. */
void radio_set_lsbfirst(void)
{
RADIO_PCNF1 &= ~RADIO_PCNF1_ENDIAN_BIG;
}
/** @brief Set bit transmission order to MSB first. */
void radio_set_msbfirst(void)
{
RADIO_PCNF1 |= RADIO_PCNF1_ENDIAN_BIG;
}
/** @brief Enable on the air data whitening
*
* @details the in-memory data will remain unwhitened.
* */
void radio_enable_whitening(void)
{
RADIO_PCNF1 |= RADIO_PCNF1_WHITEEN;
}
/** @brief Disable on the air data whitening. */
void radio_disable_whitening(void)
{
RADIO_PCNF1 &= ~RADIO_PCNF1_WHITEEN;
}
/** @brief Set CRC length in number of bytes.
*
* @param[in] crc_len uint8_t CRC length in number of bytes (1-3), 0 = CRC disabled.
*/
void radio_set_crclen(uint8_t crc_len)
{
uint32_t reg_crc = RADIO_CRCCNF;
reg_crc &= ~RADIO_CRCCNF_LEN_MASK;
RADIO_CRCCNF = reg_crc | RADIO_CRCCNF_LEN_MASKED(crc_len);
}
/** @brief Disable CRC calculation. */
void radio_disable_crc(void)
{
RADIO_CRCCNF &= ~RADIO_CRCCNF_LEN_MASK;
}
/** @brief Enable the peripheral. */
void radio_enable(void)
{
RADIO_POWER = RADIO_POWER_ENABLED;
}
/** @brief Disable the peripheral. */
void radio_disable(void)
{
RADIO_POWER = RADIO_POWER_DISABLED;
}
/** @brief Set Base Address length.
*
* @param[in] ba_len uint8_t Base Address length in number of bytes (2-4).
*/
void radio_set_balen(uint8_t ba_len)
{
uint32_t reg_pcnf1 = RADIO_PCNF1;
reg_pcnf1 &= ~RADIO_PCNF1_BALEN_MASK;
RADIO_PCNF1 = reg_pcnf1 | RADIO_PCNF1_BALEN_MASKED(ba_len);
}
/** @brief Set maximum transmission length in number of bytes.
*
* @param[in] maxlen uint8_t maximum transmission length.
*/
void radio_set_maxlen(uint8_t maxlen)
{
uint32_t reg_pcnf1 = RADIO_PCNF1;
reg_pcnf1 &= ~RADIO_PCNF1_MAXLEN_MASK;
RADIO_PCNF1 = reg_pcnf1 | RADIO_PCNF1_MAXLEN_MASKED(maxlen);
}
/** @brief Exclude access address from CRC calculation.
*
* @param[in] is_skip_addr bool If true, CRC will be calculated over PDU only,
* if false, it will also include the Access Address.
*/
void radio_set_crc_skipaddr(bool is_skip_addr)
{
if (is_skip_addr) {
RADIO_CRCCNF |= RADIO_CRCCNF_SKIPADDR;
} else {
RADIO_CRCCNF &= ~RADIO_CRCCNF_SKIPADDR;
}
}
/** @brief Configure the radio to be used in BLE mode.
*
* @details This needs to be called before the radio can be used in BLE mode.
* It will set som BLE standard parameters, like Inter-Frame Spacing time,
* LSB first, enable whitening, properly configure CRC (for advertising) and address length.
*/
void radio_configure_ble(void)
{
#ifdef NRF51
radio_set_mode(RADIO_MODE_BLE_1MBIT);
#endif
RADIO_TIFS = RADIO_BLE_TIFS;
radio_set_lsbfirst();
radio_enable_whitening();
radio_set_crclen(RADIO_BLE_CRCLEN);
RADIO_CRCPOLY = RADIO_BLE_CRCPOLY;
RADIO_CRCINIT = RADIO_BLE_CRCINIT;
radio_set_crc_skipaddr(true);
radio_set_balen(3);
}
/** @brief Configure the packet.
*
* @details See the data sheet for details.
*/
void radio_configure_packet(uint8_t lf_len_bits, uint8_t s0_len_bytes, uint8_t s1_len_bits)
{
RADIO_PCNF0 = RADIO_PCNF0_LFLEN_MASKED(lf_len_bits)
| RADIO_PCNF0_S0LEN_MASKED(s0_len_bytes)
| RADIO_PCNF0_S1LEN_MASKED(s1_len_bits);
}
/** @brief Set radio frequency.
*
* @param[in] freq uint8_t Frequency offset from 2.4GHz in MHz, for example "29" will
* tune the radio to 2429MHz
*/
void radio_set_frequency(uint8_t freq)
{
RADIO_FREQUENCY = freq;
}
/** @brief Set Data Whitening Initialization Vector.
*
* @param[in] iv uint8_t Initialization Vector. For BLE, this is channel index.
*/
void radio_set_datawhiteiv(uint8_t iv)
{
RADIO_DATAWHITEIV = iv;
}
/* @brief Set Address (base and prefix)
*
* @details Note that bases are shared between addresses 1-7,
* so changing one of them will change others too.
*
* @param[in] addr_index uint8_t address index (0-7)
* @param[in] base uint32_t base part of the address. If balen < 4, appropriate number
* of LSBs will be thrown away.
* @param[in] prefix uint8_t Address prefix.
*/
void radio_set_addr(uint8_t addr_index, uint32_t base, uint8_t prefix)
{
if (addr_index == 0) {
RADIO_BASE0 = base;
} else {
RADIO_BASE1 = base;
}
uint32_t reg_prefix = RADIO_PREFIX_AP(addr_index);
reg_prefix &= ~RADIO_PREFIX_AP_MASK(addr_index);
RADIO_PREFIX_AP_SET(addr_index, reg_prefix | RADIO_PREFIX_AP_MASKED(addr_index, prefix));
}
/* @brief Set TX address index
*
* @details The address needs to be previously configured with radio_set_addr()
*
* @param[in] address_index uint8_t address index (0-7)
*/
void radio_set_tx_address(uint8_t addr_index)
{
RADIO_TXADDRESS = addr_index;
}
/* @brief Set pointer for RX/TX data
*
* @param[in] packet_ptr uint8_t* packet buffer address.
*/
void radio_set_packet_ptr(uint8_t *packet_ptr)
{
RADIO_PACKETPTR = (uint32_t)packet_ptr;
}
/* @brief Enable radio Transmitter */
void radio_enable_tx(void)
{
PERIPH_TRIGGER_TASK(RADIO_TASK_TXEN);
}
/* @brief Enable radio Receiver */
void radio_enable_rx(void)
{
PERIPH_TRIGGER_TASK(RADIO_TASK_RXEN);
}
/**@}*/

View File

@@ -0,0 +1,116 @@
/** @addtogroup rtc_file RTC peripheral API
*
* @brief <b>Access functions for the Real Time Counter Controller </b>
*
* @ingroup peripheral_apis
* LGPL License Terms @ref lgpl_license
* @author @htmlonly &copy; @endhtmlonly 2016
* Maxim Sloyko <maxims@google.com>
*
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2017-2018 Unicore MX project<dev(at)lists(dot)unicore-mx(dot)org>
* Copyright (C) 2021 Eduard Drusa <ventyl86(at)netkosice(dot)sk>
*
* 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/nrf/rtc.h>
/**@{*/
/** @brief RTC set Prescaler value.
*
* @details The clock needs to be stopped for this to have any effect.
*
* @param[in] rtc uint32_t RTC base
* @param[in] presc uint16_t 12 bit prescaler value.
*/
void rtc_set_prescaler(uint32_t rtc, uint16_t presc)
{
RTC_PRESCALER(rtc) = presc & 0xfff;
}
/** @brief RTC get Counter value.
*
* @param[in] rtc uint32_t RTC base
*/
uint32_t rtc_get_counter(uint32_t rtc)
{
return RTC_COUNTER(rtc);
}
/** @brief Enable events
*
* @param[in] rtc uint32_t RTC base
* @param[in] mask uint32_t which events to enable
*/
void rtc_enable_events(uint32_t rtc, uint32_t mask)
{
RTC_EVTENSET(rtc) = mask;
}
/** @brief Disable events
*
* @param[in] rtc uint32_t RTC base
* @param[in] mask uint32_t which events to disable
*/
void rtc_disable_events(uint32_t rtc, uint32_t mask)
{
RTC_EVTENCLR(rtc) = mask;
}
/** @brief Start the RTC
*
* @param[in] rtc uint32_t RTC base
*/
void rtc_start(uint32_t rtc)
{
PERIPH_TRIGGER_TASK(RTC_TASK_START(rtc));
}
/** @brief Stop the RTC
*
* @param[in] rtc uint32_t RTC base
*/
void rtc_stop(uint32_t rtc)
{
PERIPH_TRIGGER_TASK(RTC_TASK_STOP(rtc));
}
/** @brief Clear the RTC
*
* @param[in] rtc uint32_t RTC base
*/
void rtc_clear(uint32_t rtc)
{
PERIPH_TRIGGER_TASK(RTC_TASK_CLEAR(rtc));
}
/** @brief Set compare register
*
* @param[in] rtc uint32_t RTC base
* @param[in] cmp uint8_t compare number (0-3)
* @param[in] value uint32_t compare value
*/
void rtc_set_compare(uint32_t rtc, uint8_t cmp, uint32_t value)
{
if (cmp < 4) {
RTC_CC(rtc, cmp) = value;
}
}
/**@}*/

View File

@@ -0,0 +1,147 @@
/** @addtogroup timer_file TIMER peripheral API
*
* @brief <b>Access functions for the Timer/Counter </b>
*
* @ingroup peripheral_apis
* LGPL License Terms @ref lgpl_license
* @author @htmlonly &copy; @endhtmlonly 2016
* Maxim Sloyko <maxims@google.com>
*
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2017-2018 Unicore MX project<dev(at)lists(dot)unicore-mx(dot)org>
* Copyright (C) 2021 Eduard Drusa <ventyl86(at)netkosice(dot)sk>
*
* 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/nrf/timer.h>
#include <libopencm3/nrf/clock.h>
/**@{*/
/** @brief Get timer ticks
*
* @param[in] timer uint32_t timer base
* @returns current ticks value
*/
uint32_t timer_get_ticks(uint32_t timer)
{
uint32_t ticks;
uint32_t cc;
/* TODO: Check WTF is this doing? */
cc = TIMER_CC(0, 0);
TIMER_TASK_CAPTURE(timer, 0) = 1;
ticks = TIMER_CC(timer, 0);
TIMER_CC(timer, 0) = cc;
return ticks;
}
/** @brief Set timer mode (counter/timer)
*
* @param[in] timer uint32_t timer base
* @param[in] mode enum timer_mode
*/
void timer_set_mode(uint32_t timer, enum timer_mode mode)
{
TIMER_MODE(timer) = mode;
}
/** @brief Set timer bit mode (width)
*
* @param[in] timer uint32_t timer base
* @param[in] bitmode enum timer_bitmode
*/
void timer_set_bitmode(uint32_t timer, enum timer_bitmode bitmode)
{
TIMER_BITMODE(timer) = bitmode;
}
/** @brief Start the timer
*
* @param[in] timer uint32_t timer base
*/
void timer_start(uint32_t timer)
{
PERIPH_TRIGGER_TASK(TIMER_TASK_START(timer));
}
/** @brief Stop the timer
*
* @param[in] timer uint32_t timer base
*/
void timer_stop(uint32_t timer)
{
PERIPH_TRIGGER_TASK(TIMER_TASK_STOP(timer));
}
/** @brief Clear the timer
*
* @param[in] timer uint32_t timer base
*/
void timer_clear(uint32_t timer)
{
PERIPH_TRIGGER_TASK(TIMER_TASK_CLEAR(timer));
}
/** @brief Set prescaler value
*
* @param[in] timer uint32_t timer base
* @param[in] presc uint8_t prescaler value
*/
void timer_set_prescaler(uint32_t timer, uint8_t presc)
{
TIMER_PRESCALER(timer) = presc & TIMER_PRESCALER_MASK;
}
/** @brief Set compare register
*
* @param[in] timer uint32_t timer base
* @param[in] compare_num uint8_t compare number (0-3)
* @param[in] compare_val uint32_t compare value
*/
void timer_set_compare(uint32_t timer, uint8_t compare_num, uint32_t compare_val)
{
if (compare_num > 3) {
return;
}
TIMER_CC(timer, compare_num) = compare_val;
}
/** @brief Get the timer tick frequency
*
* @param[in] timer uint32_t timer base
* @returns frequency of ticking
*/
uint32_t timer_get_freq(uint32_t timer)
{
return CLOCK_PCLK/(1<<TIMER_PRESCALER(timer));
}
/** @brief Get compare register
*
* @param[in] timer uint32_t timer base
* @param[in] compare_num uint8_t compare number (0-3)
* @returns compare register value
*/
uint32_t timer_get_cc(uint32_t timer, uint8_t compare_num)
{
return TIMER_CC(timer, compare_num);
}
/**@}*/

View File

@@ -0,0 +1,171 @@
/** @addtogroup uart_file UART peripheral API
*
* @brief <b>Access functions for the UART controller</b>
*
* @ingroup peripheral_apis
* LGPL License Terms @ref lgpl_license
* @author @htmlonly &copy; @endhtmlonly 2016
* Maxim Sloyko <maxims@google.com>
*
*/
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2017-2018 Unicore MX project<dev(at)lists(dot)unicore-mx(dot)org>
* Copyright (C) 2021 Eduard Drusa <ventyl86(at)netkosice(dot)sk>
*
* 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/nrf/uart.h>
#include <libopencm3/nrf/gpio.h>
/**@{*/
/** @brief Enable the peripheral
*
* @param[in] uart uint32_t uart base
*/
void uart_enable(uint32_t uart)
{
UART_ENABLE(uart) = UART_ENABLE_ENABLED;
}
/** @brief Disable the peripheral
*
* @param[in] uart uint32_t uart base
*/
void uart_disable(uint32_t uart)
{
UART_ENABLE(uart) = UART_ENABLE_DISABLED;
}
/** @brief Configure UART parameters in single call
*
* @details Any pin number can be set to 0xff (or any number larger than UART_MAX_PIN)
* to disconnect that pin.
*
* @param[in] uart uint32_t uart base
* @param[in] tx_pin uint8_t TX pin number
* @param[in] rx_pin uint8_t RX pin number
* @param[in] rts_pin uint8_t RTS pin number
* @param[in] cts_pin uint8_t CTS pin number
* @param[in] br enum uart_baud baud rate
* @param[in] enable_parity bool If true, enable parity bit
*/
void uart_configure(uint32_t uart,
uint32_t tx_pin, uint32_t rx_pin, uint32_t rts_pin, uint32_t cts_pin,
enum uart_baud br, bool enable_parity)
{
uart_set_pins(uart, rx_pin, tx_pin, cts_pin, rts_pin);
uint32_t reg_config = enable_parity ? UART_CONFIG_PARITY : 0;
if (rts_pin <= UART_MAX_PIN || cts_pin <= UART_MAX_PIN) {
reg_config |= UART_CONFIG_HWFC;
}
UART_CONFIG(uart) = reg_config;
uart_set_baudrate(uart, br);
}
/** @brief Select GPIO pins to be used by this peripheral.
*
* This needs to be configured while UART peripheral is disabled.
*
* @param[in] uart uart peripheral base.
* @param[in] rx RX pin. Use GPIO defines in @ref gpio_pin_id or GPIO_UNCONNECTED
* if signal shall not be connected to any pin.
* @param[in] tx TX pin. Use GPIO defines in @ref gpio_pin_id or GPIO_UNCONNECTED
* if signal shall not be connected to any pin.
* @param[in] cts CTS pin. Use GPIO defines in @ref gpio_pin_id or GPIO_UNCONNECTED
* if signal shall not be connected to any pin.
* @param[in] rts RTS pin. Use GPIO defines in @ref gpio_pin_id or GPIO_UNCONNECTED
* if signal shall not be connected to any pin.
*/
void uart_set_pins(uint32_t uart, uint32_t rx, uint32_t tx, uint32_t cts, uint32_t rts)
{
if (rx != GPIO_UNCONNECTED) {
UART_PSELRXD(uart) = __GPIO2PIN(rx);
} else {
UART_PSELRXD(uart) = rx;
}
if (tx != GPIO_UNCONNECTED) {
UART_PSELTXD(uart) = __GPIO2PIN(tx);
} else {
UART_PSELTXD(uart) = tx;
}
if (cts != GPIO_UNCONNECTED) {
UART_PSELCTS(uart) = __GPIO2PIN(cts);
} else {
UART_PSELCTS(uart) = cts;
}
if (rts != GPIO_UNCONNECTED) {
UART_PSELRTS(uart) = __GPIO2PIN(rts);
} else {
UART_PSELRTS(uart) = rts;
}
}
#undef _LOG2
void uart_set_baudrate(uint32_t uart, enum uart_baud br)
{
UART_BAUDRATE(uart) = br;
}
void uart_set_parity(uint32_t uart, int parity)
{
UART_CONFIG(uart) |= parity ? UART_CONFIG_PARITY : 0;
}
void uart_set_flow_control(uint32_t uart, int flow)
{
UART_CONFIG(uart) |= flow ? UART_CONFIG_HWFC : 0;
}
void uart_start_tx(uint32_t uart)
{
PERIPH_TRIGGER_TASK(UART_TASK_STARTTX((uart)));
}
void uart_send(uint32_t uart, uint16_t byte)
{
UART_TXD((uart)) = byte;
}
void uart_stop_tx(uint32_t uart)
{
PERIPH_TRIGGER_TASK(UART_TASK_STOPTX((uart)));
}
void uart_start_rx(uint32_t uart)
{
PERIPH_TRIGGER_TASK(UART_TASK_STARTRX((uart)));
}
uint16_t uart_recv(uint32_t uart)
{
return UART_RXD(uart);
}
void uart_stop_rx(uint32_t uart)
{
PERIPH_TRIGGER_TASK(UART_TASK_STOPRX((uart)));
}
/**@}*/

View File

@@ -0,0 +1,47 @@
##
## This file is part of the libopencm3 project.
##
## Copyright (C) 2019 Brian Viele <vielster@allocor.tech>
##
## 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/>.
##
## The PAC55xx by Qorvo (formerly ActiveSemi) is a Cortex-M4F based device
## which is specialized for motor control and PSC applications.
LIBNAME = libopencm3_pac55xx
SRCLIBDIR ?= ..
FP_FLAGS ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16
CC = $(PREFIX)gcc
AR = $(PREFIX)ar
TGT_CFLAGS = -Os \
-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 -DPAC55XX
TGT_CFLAGS += $(DEBUG_FLAGS)
TGT_CFLAGS += $(STANDARD_FLAGS)
ARFLAGS = rcs
OBJS += can.o
OBJS += ccs.o
OBJS += gpio.o
OBJS += memctl.o
OBJS += usart.o
VPATH += ../cm3
include ../Makefile.include

View File

@@ -0,0 +1,460 @@
/**
* @addtogroup can_api CAN Peripheral API
* @ingroup peripheral_apis
* @brief <b>PAC55xxxx CAN Driver</b>
* @author @htmlonly &copy; @endhtmlonly 2020 Kevin Stefanik <kevin@allocor.tech>
* @date February 13, 2020
*
* This library supports the CAN module in the PAC55xx SoC from Qorvo.
*
* Note: Acceptance Code Mask Register values of 1 indicate the filter is to
* ignore the bit. However, standard CAN driver APIs use a positive logic for the
* mask. The implementations in this file inverts masks as appropriate to
* the mask to make this more portable/intuitive.
*
* 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/pac55xx/can.h>
#include <libopencm3/cm3/common.h>
/*---------------------------------------------------------------------------*/
/** @brief CAN Enable
Enable the CAN peripheral and its associated FIFOs/counters/interrupts.
@param[in] canport Unsigned int32. CAN block register base address.
*/
void can_enable(uint32_t canport) {
CAN_ISR_SR_CMR_MR_CLEAR(canport, CAN_MR_RM);
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Disable
Disable the CAN peripheral and all associated FIFOs/counters/interrupts.
@param[in] canport Unsigned int32. CAN block register base address.
*/
void can_disable(uint32_t canport) {
CAN_ISR_SR_CMR_MR_SET(canport, CAN_MR_RM);
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Init
Initialize the selected CAN peripheral block.
@param[in] canport Unsigned int32. CAN block register base address.
@param[in] listen_only bool. Enable listen only mode.
@param[in] sjw Unsigned int32. Resynchronization time quanta jump width.
@param[in] tseg1 Unsigned int32. Time segment 1 time quanta width.
@param[in] tseg2 Unsigned int32. Time segment 2 time quanta width.
@param[in] sam3 bool. Use best 2 out of 3 samples.
@param[in] brp Unsigned int32. Baud rate prescaler.
*/
void can_init(uint32_t canport, bool listen_only, uint32_t sjw,
uint32_t tseg1, uint32_t tseg2,
bool sam3, uint32_t brp) {
/* Put CAN module in reset and clear out ISR/SR/CMR/MR */
CAN_ISR_SR_CMR_MR(canport) = CAN_MR_RM;
/* Setup single filter scheme */
CAN_ISR_SR_CMR_MR_SET(canport, CAN_MR_AFM);
/* enable listen-only mode */
if (listen_only) {
CAN_ISR_SR_CMR_MR_SET(canport, CAN_MR_LOM);
}
/* Set Baud Rate Prescaler, sync jump width, tseg1/2 */
CAN_BTR1_BTR0_RMC_IMR(canport) = CAN_BTR0_BRP(brp) | CAN_BTR0_SJW(sjw)
| CAN_BTR1_TSEG1(tseg1) | CAN_BTR1_TSEG2(tseg2);
if (sam3) {
/* enable sample bus 3 times */
CAN_BTR1_BTR0_RMC_IMR(canport) |= CAN_BTR1_SAM;
}
/* Filter: Accept incoming messages with any identifier */
CAN_ACR(canport) = 0;
/* Note: when mask bits are 1, the bits are ignored */
CAN_AMR(canport) = 0xFFFFFFFFu;
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Filter Clear
Clear the message filters to receive all messages.
@param[in] canport Unsigned int32. CAN block register base address.
*/
void can_filter_clear(uint32_t canport) {
/* Filter: Accept incoming messages with any identifier */
CAN_ACR(canport) = 0;
/* Note: when mask bits are 1, the bits are ignored */
CAN_AMR(canport) = 0xFFFFFFFFu;
/* Setup single filter scheme */
CAN_ISR_SR_CMR_MR_SET(canport, CAN_MR_AFM);
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Dual Filter Standard Frame
Notes:
- Acceptance Code Mask Register values of 1 indicate the filter is to ignore
the bit. However standard CAN driver APIs use a positive logic for the mask.
So this function inverts the mask to make this more portable/intuitive.
- Register definition byte order is opposite what is shown in Rev 1.23 of
the PAC55XX Family User Guide. Since both data and ID values cross byte
boundaries, the bswap32 function is used to correct for the discrepancy.
@param[in] canport Unsigned int32. CAN block register base address.
@param[in] id1 Unsigned int32. CAN ID 1. Only bits 10:0 are used.
@param[in] id1_mask Unsigned int32. CAN ID 1 mask. Only bits 10:0 are used.
@param[in] id2 Unsigned int32. CAN ID 2. Only bits 10:0 are used.
@param[in] id2_mask Unsigned int32. CAN ID 2 mask. Only bits 10:0 are used.
@param[in] db bool. CAN first data byte value.
@param[in] db_mask bool. CAN first data byte mask.
*/
void can_filter_dual(uint32_t canport, uint32_t id1, uint32_t id1_mask,
uint32_t id2, uint32_t id2_mask,
uint8_t db, uint8_t db_mask) {
/* set value */
uint32_t word = ((id1 << 21) & CAN_ACR_DUAL_ID1)
| ((id2 << 5) & CAN_ACR_DUAL_ID2)
| ((db << 12) & CAN_ACR_DUAL_DB_UPPER) | (db & CAN_ACR_DUAL_DB_LOWER);
CAN_ACR(canport) = __builtin_bswap32(word);
/* set mask */
word = ((~id1_mask << 21) & CAN_ACR_DUAL_ID1)
| ((~id2_mask << 5) & CAN_ACR_DUAL_ID2)
| ((~db_mask << 12) & CAN_ACR_DUAL_DB_UPPER)
| ((~db_mask) & CAN_ACR_DUAL_DB_LOWER)
| CAN_ACR_DUAL_RTR1 | CAN_ACR_DUAL_RTR2;
CAN_AMR(canport) = __builtin_bswap32(word);
/* 0: dual filter */
CAN_ISR_SR_CMR_MR_CLEAR(canport, CAN_MR_AFM);
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Filter Single Standard Frame
Notes:
- Acceptance Code Mask Register values of 1 indicate the filter is to ignore
the bit. However standard CAN driver APIs use a positive logic for the mask.
So this function inverts the mask to make this more portable/intuitive.
- Register definition byte order is opposite what is shown in Rev 1.23 of
the PAC55XX Family User Guide. Since both data and ID values cross byte
boundaries, the bswap32 function is used to correct for the discrepancy.
@param[in] canport Unsigned int32. CAN block register base address.
@param[in] id Unsigned int32. CAN ID. Only bits 10:0 are used.
@param[in] id_mask Unsigned int32. CAN ID mask. Only bits 10:0 are used.
@param[in] db1 bool. CAN first data byte value.
@param[in] db1_mask bool. CAN first data byte mask.
@param[in] db2 bool. CAN second data byte value.
@param[in] db2_mask bool. CAN second data byte mask.
*/
void can_filter_single_std(uint32_t canport, uint32_t id, uint32_t id_mask,
uint8_t db1, uint8_t db1_mask,
uint8_t db2, uint8_t db2_mask) {
/* set value */
uint32_t word = ((id << 21) & CAN_ACR_SINGLE_STD_ID)
| ((db1 << 8) & CAN_ACR_SINGLE_STD_DB1)
| ((db2 << 0) & CAN_ACR_SINGLE_STD_DB2);
CAN_ACR(canport) = __builtin_bswap32(word);
/* set mask */
word = ((~id_mask << 21) & CAN_ACR_SINGLE_STD_ID)
| CAN_ACR_SINGLE_STD_RTR | CAN_ACR_DUAL_DB_UPPER
| ((~db1_mask << 8) & CAN_ACR_SINGLE_STD_DB1)
| ((~db2_mask << 0) & CAN_ACR_SINGLE_STD_DB2);
CAN_AMR(canport) = __builtin_bswap32(word);
/* 1: single filter */
CAN_ISR_SR_CMR_MR_SET(canport, CAN_MR_AFM);
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Filter Single Standard Frame w/RTR set
Notes:
- Acceptance Code Mask Register values of 1 indicate the filter is to ignore
the bit. However standard CAN driver APIs use a positive logic for the mask.
So this function inverts the mask to make this more portable/intuitive.
- Register definition byte order is opposite what is shown in Rev 1.23 of
the PAC55XX Family User Guide. Since both data and ID values cross byte
boundaries, the bswap32 function is used to correct for the discrepancy.
@param[in] canport Unsigned int32. CAN block register base address.
@param[in] id Unsigned int32. CAN ID. Only bits 10:0 are used.
@param[in] id_mask Unsigned int32. CAN ID mask. Only bits 10:0 are used.
@param[in] db1 bool. CAN first data byte value.
@param[in] db1_mask bool. CAN first data byte mask.
@param[in] db2 bool. CAN second data byte value.
@param[in] db2_mask bool. CAN second data byte mask.
*/
void can_filter_single_std_rtr(uint32_t canport, uint32_t id, uint32_t id_mask,
uint8_t db1, uint8_t db1_mask,
uint8_t db2, uint8_t db2_mask) {
/* set value */
uint32_t word = ((id << 21) & CAN_ACR_SINGLE_STD_ID)
| CAN_ACR_SINGLE_STD_RTR | ((db1 << 8) & CAN_ACR_SINGLE_STD_DB1)
| ((db2 << 0) & CAN_ACR_SINGLE_STD_DB2);
CAN_ACR(canport) = __builtin_bswap32(word);
/* set mask */
word = ((~id_mask << 21) & CAN_ACR_SINGLE_STD_ID)
| ((~db1_mask << 8) & CAN_ACR_SINGLE_STD_DB1)
| ((~db2_mask << 0) & CAN_ACR_SINGLE_STD_DB2);
CAN_AMR(canport) = __builtin_bswap32(word);
/* 1: single filter */
CAN_ISR_SR_CMR_MR_SET(canport, CAN_MR_AFM);
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Filter Single Extended Frame
Notes:
- Acceptance Code Mask Register values of 1 indicate the filter is to ignore
the bit. However standard CAN driver APIs use a positive logic for the mask.
So this function inverts the mask to make this more portable/intuitive.
- Register definition byte order is opposite what is shown in Rev 1.23 of
the PAC55XX Family User Guide. Since both data and ID values cross byte
boundaries, the bswap32 function is used to correct for the discrepancy.
@param[in] canport Unsigned int32. CAN block register base address.
@param[in] id Unsigned int32. CAN ID. Only bits 28:0 are used.
@param[in] id_mask Unsigned int32. CAN ID mask. Only bits 28:0 are used.
*/
void can_filter_single_ext(uint32_t canport, uint32_t id, uint32_t id_mask) {
/* set value */
uint32_t word = ((id << 3) & CAN_ACR_SINGLE_EXT_ID);
CAN_ACR(canport) = __builtin_bswap32(word);
/* set mask */
word = ((~id_mask << 3) & CAN_ACR_SINGLE_EXT_ID) | CAN_ACR_SINGLE_EXT_RTR;
CAN_AMR(canport) = __builtin_bswap32(word);
/* 1: single filter */
CAN_ISR_SR_CMR_MR_SET(canport, CAN_MR_AFM);
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Filter Single Extended Frame w/RTR set
Notes:
- Acceptance Code Mask Register values of 1 indicate the filter is to ignore
the bit. However standard CAN driver APIs use a positive logic for the mask.
So this function inverts the mask to make this more portable/intuitive.
- Register definition byte order is opposite what is shown in Rev 1.23 of
the PAC55XX Family User Guide. Since both data and ID values cross byte
boundaries, the bswap32 function is used to correct for the discrepancy.
@param[in] canport Unsigned int32. CAN block register base address.
@param[in] id Unsigned int32. CAN ID. Only bits 28:0 are used.
@param[in] id_mask Unsigned int32. CAN ID mask. Only bits 28:0 are used.
*/
void can_filter_single_ext_rtr(uint32_t canport, uint32_t id, uint32_t id_mask) {
/* set value */
uint32_t word = ((id << 3) & CAN_ACR_SINGLE_EXT_ID) | CAN_ACR_SINGLE_EXT_RTR;
CAN_ACR(canport) = __builtin_bswap32(word);
/* set mask */
word = ((~id_mask << 3) & CAN_ACR_SINGLE_EXT_ID);
CAN_AMR(canport) = __builtin_bswap32(word);
/* 1: single filter */
CAN_ISR_SR_CMR_MR_SET(canport, CAN_MR_AFM);
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Enable IRQ
@param[in] canport Unsigned int32. CAN block register base address.
@param[in] irq Unsigned int8. IRQ bit(s).
*/
void can_enable_irq(uint32_t canport, uint8_t irq) {
/* set to 1 (not masked) to enable */
CAN_BTR1_BTR0_RMC_IMR(canport) |= (uint32_t)irq;
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Disable IRQ
@param[in] canport Unsigned int32. CAN block register base address.
@param[in] irq Unsigned int8. IRQ bit(s).
*/
void can_disable_irq(uint32_t canport, uint8_t irq) {
/* set to 0 (masked) to disable */
CAN_BTR1_BTR0_RMC_IMR(canport) &= ~(uint32_t)irq;
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Transmit Standard Frame
@param[in] canport Unsigned int32. CAN block register base address.
@param[in] id Unsigned int32. Message ID bits 10:0 used.
@param[in] rtr bool. Remote Request bit value.
@param[in] length Unsigned int8. Message payload length.
@param[in] data Unsigned int8[]. Message payload data.
@returns true if able to transmit, false otherwise.
*/
bool can_transmit_std(uint32_t canport, uint32_t id, bool rtr, uint8_t length,
const uint8_t *data) {
/* if TBS is 0, then not ready to transmit */
if ((CAN_ISR_SR_CMR_MR(canport) & CAN_SR_TBS) == 0) {
return false;
}
uint32_t word = (length & CAN_BITS_3_0)
| (rtr ? BIT6 : 0) /* DLC/RTR/FF ==> 7:0 */
| ((id & CAN_BITS_10_3) << 5) /* ID 10:3 ==> 15:8 */
| ((id & CAN_BITS_2_0) << 21) /* ID 2:0 ==> 23:21 */
| (((length > 0) ? data[0] : 0) << 24);
CAN_TXBUF(canport) = word;
if (length > 1) {
word = (data[1] << 0) | (data[2] << 8)
| (data[3] << 16) | (data[4] << 24);
CAN_TXBUF(canport) = word;
}
if (length > 5) {
word = (data[5] << 0) | (data[6] << 8) | (data[7] << 16);
CAN_TXBUF(canport) = word;
}
/* Request transmit */
CAN_ISR_SR_CMR_MR_SET(canport, CAN_CMR_TR);
return true;
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Transmit Extended Frame
@param[in] canport Unsigned int32. CAN block register base address.
@param[in] id Unsigned int32. Message ID bits 28:0 used.
@param[in] rtr bool. Remote Request bit value.
@param[in] length Unsigned int8. Message payload length, 0-8.
@param[in] data Unsigned int8[]. Message payload data.
@returns true if able to transmit, false otherwise.
*/
bool can_transmit_ext(uint32_t canport, uint32_t id, bool rtr, uint8_t length,
const uint8_t *data) {
/* if TBS is 0, then not ready to transmit */
if ((CAN_ISR_SR_CMR_MR(canport) & CAN_SR_TBS) == 0) {
return false;
}
uint32_t word = (length & CAN_BITS_3_0)
| (rtr ? BIT6 : 0) | BIT7 /* DLC/RTR/FF ==> 7:0 */
| ((id & CAN_BITS_28_21) >> 13) /* ID 28:21 ==> 15:8 */
| ((id & CAN_BITS_20_13) << 3) /* ID 20:13 ==> 23:16 */
| ((id & CAN_BITS_12_5) << 19); /* ID 12:5 ==> 31:24 */
CAN_TXBUF(canport) = word; /* write first 32-bit word to FIFO */
word = ((id & CAN_BITS_4_0) << 3); /* ID 4:0 ==> 7:3 */
if (length > 0) {
word |= (data[0] << 8) | (data[1] << 16) | (data[2] << 24);
}
/* for extended frame, always write second 32-bit word to FIFO */
CAN_TXBUF(canport) = word;
if (length > 3) {
word = (data[3] << 0) | (data[4] << 8)
| (data[5] << 16) | (data[6] << 24);
CAN_TXBUF(canport) = word;
}
if (length > 7) {
word = data[7];
CAN_TXBUF(canport) = word;
}
/* Request transmit */
CAN_ISR_SR_CMR_MR_SET(canport, CAN_CMR_TR);
return true;
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Abort Transmit
Aborts the current transmission.
@param[in] canport Unsigned int32. CAN block register base address.
*/
void can_abort_transmit(uint32_t canport) {
CAN_ISR_SR_CMR_MR_SET(canport, CAN_CMR_AT);
}
/*---------------------------------------------------------------------------*/
/** @brief CAN Receive Message
If no data is in the RX buffer, id and length are set to 0.
@param[in] canport Unsigned int32. CAN block register base address.
@param[out] id Unsigned int32 pointer. Message ID.
@param[out] ext bool pointer. The message ID is extended.
@param[out] rtr bool pointer. Remote Request bit value.
@param[out] length Unsigned int8 pointer. Length of message payload.
@param[out] data Unsigned int8[]. Message payload data, min length 8.
*/
void can_receive(uint32_t canport, uint32_t *id, bool *ext, bool *rtr, uint8_t *length,
uint8_t *data) {
if ((CAN_ISR_SR_CMR_MR(canport) & CAN_ISR_RI) == 0 || CAN_RMC(canport) == 0) {
*id = 0;
*length = 0;
return; /* empty RX FIFO */
}
uint32_t can_buffer = CAN_RXBUF(canport); /* read 32-bit word */
uint8_t rx_length = can_buffer & CAN_BITS_3_0;
bool is_extended = can_buffer & BIT7;
if (ext) {
*ext = is_extended;
}
if (rtr) {
*rtr = can_buffer & BIT6;
}
if (length) {
*length = rx_length;
}
uint32_t _id;
if (is_extended) {
/* Parse extended message ID from RXBUF */
_id = ((can_buffer & CAN_BITS_15_8) << 13) /* ID 28:21 <== 15:8 */
| ((can_buffer & CAN_BITS_23_16) >> 3) /* ID 20:13 <== 23:16 */
| ((can_buffer & CAN_BITS_31_24) >> 19); /* ID 12:5 <== 31:24 */
can_buffer = CAN_RXBUF(canport);
_id |= ((can_buffer & CAN_BITS_7_3) >> 3); /* ID 4:0 <== 7:3 */
/* Parse extended message data from RXBUF */
data[0] = can_buffer >> 8;
data[1] = can_buffer >> 16;
data[2] = can_buffer >> 24;
if (rx_length > 3) {
can_buffer = CAN_RXBUF(canport);
data[3] = can_buffer;
data[4] = can_buffer >> 8;
data[5] = can_buffer >> 16;
data[6] = can_buffer >> 24;
}
if (rx_length > 7) {
can_buffer = CAN_RXBUF(canport);
data[7] = can_buffer;
}
} else {
/* Parse standard message ID from RXBUF */
_id = ((can_buffer & CAN_BITS_15_8) >> 5) /* ID 10:3 <== 15:8 */
| ((can_buffer & CAN_BITS_23_21) >> 21); /* ID 2:0 <== 23:21 */
/* Parse standard message data from RXBUF */
data[0] = can_buffer >> 24;
if (rx_length > 1) {
can_buffer = CAN_RXBUF(canport);
data[1] = can_buffer;
data[2] = can_buffer >> 8;
data[3] = can_buffer >> 16;
data[4] = can_buffer >> 24;
if (rx_length > 5) {
/* buffer contains data5,data6,data7 */
can_buffer = CAN_RXBUF(canport);
data[5] = can_buffer;
data[6] = can_buffer >> 8;
data[7] = can_buffer >> 16;
}
}
}
if (id) {
*id = _id;
}
/*
* Write 1 to acknowledge/clear the interrupt
* Note: ensure not to let the other interrupt masks be written as 1, so as
* to avoid acknowledging them.
* Note: CAN_ISR_RI is already high, but we still write '1' to it to clear it.
*/
CAN_ISR_ACKNOWLEDGE(canport, CAN_ISR_RI);
return;
}

View File

@@ -0,0 +1,261 @@
/**
* @brief <b>PAC55xxxx CCS Driver</b>
* @author @htmlonly &copy; @endhtmlonly 2020 Kevin Stefanik <kevin@allocor.tech>
* @date March 7, 2020
*
* This library supports the CCS module in the PAC55xx SoC from Qorvo.
*
* 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/pac55xx/ccs.h>
#include <libopencm3/pac55xx/memorymap.h>
#include <libopencm3/pac55xx/memctl.h>
#include <libopencm3/cm3/assert.h>
static volatile uint32_t ccs_extclk_frequency = 0;
static volatile uint32_t ccs_frclk_frequency = CCS_ROSC_FREQ;
static volatile uint32_t ccs_sclk_frequency = CCS_ROSC_FREQ;
static volatile uint32_t ccs_pll_clk_frequency = 0;
static volatile uint32_t ccs_hclk_frequency = CCS_ROSC_FREQ;
static volatile uint32_t ccs_aclk_frequency = CCS_ROSC_FREQ;
static volatile uint32_t ccs_pclk_frequency = CCS_ROSC_FREQ;
void ccs_frclkmux_select(uint32_t sel) {
CCSCTL = (CCSCTL & ~CCS_CTL_FRCLKMUXSEL(CCS_CTL_FRCLKMUXSEL_MASK)) | CCS_CTL_FRCLKMUXSEL(sel);
}
void ccs_rosc_enable(void) {
CCSCTL |= CCS_CTL_ROSCEN;
}
void ccs_rosc_disable(void) {
CCSCTL &= ~CCS_CTL_ROSCEN;
}
void ccs_sclkmux_select_frclk(void) {
CCSCTL &= ~CCS_CTL_SCLKMUXSEL;
}
void ccs_sclkmux_select_pllclk(void) {
CCSCTL |= CCS_CTL_SCLKMUXSEL;
}
void ccs_clkfail_enable(void) {
CCSCTL |= CCS_CTL_CLKFAILEN;
}
void ccs_clkfail_disable(void) {
CCSCTL &= ~CCS_CTL_CLKFAILEN;
}
void ccs_clkfailmux_select_frclk(void) {
CCSCTL &= ~CCS_CTL_CLKFAILMUXSEL;
}
void ccs_clkfailmux_select_pllclk(void) {
CCSCTL |= CCS_CTL_CLKFAILMUXSEL;
}
void ccs_ldo_enable(void) {
CCSCTL |= CCS_CTL_LDOEN;
}
void ccs_ldo_disable(void) {
CCSCTL &= ~CCS_CTL_LDOEN;
}
void ccs_pclk_enable(void) {
CCSCTL |= CCS_CTL_PCLKEN;
}
void ccs_pclk_disable(void) {
CCSCTL &= ~CCS_CTL_PCLKEN;
}
void ccs_aclk_enable(void) {
CCSCTL |= CCS_CTL_ACLKEN;
}
void ccs_aclk_disable(void) {
CCSCTL &= ~CCS_CTL_ACLKEN;
}
void ccs_adcclk_enable(void) {
CCSCTL |= CCS_CTL_ADCCLKEN;
}
void ccs_adcclk_disable(void) {
CCSCTL &= ~CCS_CTL_ADCCLKEN;
}
void ccs_stclk_sleep_enable(void) {
CCSCTL |= CCS_CTL_STCLKSLPEN;
}
void ccs_stclk_sleep_disable(void) {
CCSCTL &= ~CCS_CTL_STCLKSLPEN;
}
void ccs_set_pclkdiv(uint32_t div) {
CCSCTL = (CCSCTL & ~CCS_CTL_PCLKDIV(8)) | CCS_CTL_PCLKDIV(div);
}
void ccs_set_aclkdiv(uint32_t div) {
CCSCTL = (CCSCTL & ~CCS_CTL_ACLKDIV(8)) | CCS_CTL_ACLKDIV(div);
}
void ccs_set_hclkdiv(uint32_t div) {
CCSCTL = (CCSCTL & ~CCS_CTL_HCLKDIV(8)) | CCS_CTL_HCLKDIV(div);
}
void ccs_pll_enable(void) {
CCSPLLCTL |= CCS_PLLCTL_PLLEN;
}
void ccs_pll_disable(void) {
CCSPLLCTL &= ~CCS_PLLCTL_PLLEN;
}
bool ccs_pll_locked(void) {
return (CCSPLLCTL & CCS_PLLCTL_PLLLOCK) == CCS_PLLCTL_PLLLOCK;
}
void ccs_pll_bypass_enable(void) {
CCSPLLCTL |= CCS_PLLCTL_PLLBP;
}
void ccs_pll_bypass_disable(void) {
CCSPLLCTL &= ~CCS_PLLCTL_PLLBP;
}
void ccs_pll_set_outdiv(uint32_t div) {
CCSPLLCTL = (CCSPLLCTL & ~CCS_PLLCTL_PLLOUTDIV(CCS_PLLCTL_PLLOUTDIV_MASK)) | CCS_PLLCTL_PLLOUTDIV(div);
}
void ccs_pll_set_indiv(uint32_t div) {
if (div <= 15 && div >= 1) {
CCSPLLCTL = (CCSPLLCTL & ~CCS_PLLCTL_PLLINDIV(CCS_PLLCTL_PLLINDIV_MASK)) | CCS_PLLCTL_PLLINDIV(div);
} else {
cm3_assert_not_reached();
}
}
void ccs_pll_set_fbdiv(uint32_t div) {
if (div <= 16383 && div >= 4) {
CCSPLLCTL = (CCSPLLCTL & ~CCS_PLLCTL_PLLFBDIV(CCS_PLLCTL_PLLFBDIV_MASK)) | CCS_PLLCTL_PLLFBDIV(div);
} else {
cm3_assert_not_reached();
}
}
void css_pll_config_enable(uint32_t indiv, uint32_t fbdiv, uint32_t outdiv) {
ccs_pll_disable();
ccs_pll_set_fbdiv(fbdiv);
ccs_pll_set_outdiv(outdiv);
ccs_pll_set_indiv(indiv);
ccs_pll_enable();
while (!ccs_pll_locked()) ; /* Wait for PLL lock ~500us */
}
uint32_t ccs_get_peripheral_clk_freq(uint32_t periph, uint32_t select) {
switch (periph) {
case ADC_BASE:
return ccs_sclk_frequency;
case I2C_BASE: /* fall through */
case USARTA_BASE: /* fall through */
case USARTB_BASE: /* fall through */
case USARTC_BASE: /* fall through */
case USARTD_BASE: /* fall through */
case CAN_BASE: /* fall through */
case GPTIMERA_BASE: /* fall through */
case GPTIMERB_BASE:
return ccs_pclk_frequency;
case TIMERA_BASE: /* fall through */
case TIMERB_BASE: /* fall through */
case TIMERC_BASE: /* fall through */
case TIMERD_BASE:
return (select == 0) ? ccs_pclk_frequency : ccs_aclk_frequency;
case MEMCTL_BASE:
return (select == 0) ? CCS_ROSC_FREQ : ccs_hclk_frequency;
case WWDT_BASE:
return (select == 0) ? ccs_frclk_frequency : CCS_ROSC_FREQ;
case RTC_BASE:
return ccs_frclk_frequency;
case CRC_BASE: /* fall through */
case SYS_TICK_BASE:
return ccs_hclk_frequency;
default:
cm3_assert_not_reached();
}
}
void ccs_reset_clocks(void) {
CCSCTL = CCS_CTL_LDOEN | CCS_CTL_ROSCEN |
CCS_CTL_PCLKEN | CCS_CTL_ACLKEN |
CCS_CTL_ADCCLKEN | CCS_CTL_STCLKSLPEN;
CCSPLLCTL = 0;
}
void ccs_configure_clocks(const struct ccs_clk_config *config) {
MEMCTL_FLASHLOCK = MEMCTL_FLASHLOCK_ALLOW_MEMCTL_WRITE;
ccs_reset_clocks(); /* set safe defaults */
ccs_frclkmux_select(CCS_CTL_FRCLKMUXSEL_ROSC);
ccs_sclkmux_select_frclk();
memctl_flash_select_roscclk();
if (config->mem_enable_cache) {
memctl_flash_cache_enable();
} else {
memctl_flash_cache_disable();
}
ccs_frclkmux_select(CCS_CTL_FRCLKMUXSEL_CLKREF); /* switch frclk to 4MHz CLKREF */
switch (config->frclk_source) {
case CCS_CTL_FRCLKMUXSEL_ROSC:
ccs_frclkmux_select(CCS_CTL_FRCLKMUXSEL_ROSC);
ccs_frclk_frequency = CCS_ROSC_FREQ;
break;
case CCS_CTL_FRCLKMUXSEL_CLKREF:
ccs_frclkmux_select(CCS_CTL_FRCLKMUXSEL_CLKREF);
ccs_frclk_frequency = CCS_CLKREF_FREQ;
break;
case CCS_CTL_FRCLKMUXSEL_EXTCLK:
if (config->extclk_frequency > CCS_EXTCLK_MAX_FREQ
|| config->extclk_frequency == 0) {
cm3_assert_not_reached();
}
ccs_frclkmux_select(CCS_CTL_FRCLKMUXSEL_EXTCLK);
ccs_frclk_frequency = ccs_extclk_frequency = config->extclk_frequency;
break;
default:
cm3_assert_not_reached();
}
if (config->sclk_source == CCS_CTL_SCLKMUXSEL_FRCLK) {
ccs_set_hclkdiv(config->hclkdiv);
ccs_set_aclkdiv(config->aclkdiv);
memctl_flash_set_wstate(config->mem_wstate);
ccs_sclkmux_select_frclk();
memctl_flash_set_mclkdiv(config->mem_mclkdiv);
if (config->mem_mclksel == false) {
memctl_flash_select_roscclk();
} else {
memctl_flash_select_mclk();
}
ccs_sclk_frequency = ccs_frclk_frequency;
} else if (config->sclk_source == CCS_CTL_SCLKMUXSEL_PLLCLK) {
css_pll_config_enable(config->pll_indiv, config->pll_fbdiv, config->pll_outdiv);
ccs_set_hclkdiv(config->hclkdiv);
ccs_set_aclkdiv(config->aclkdiv);
memctl_flash_set_wstate(config->mem_wstate);
ccs_sclkmux_select_pllclk();
memctl_flash_set_mclkdiv(config->mem_mclkdiv);
if (config->mem_mclksel == false) {
memctl_flash_select_roscclk();
} else {
memctl_flash_select_mclk();
}
ccs_pll_clk_frequency = ((ccs_frclk_frequency * config->pll_fbdiv) / config->pll_indiv) >> config->pll_outdiv;
ccs_sclk_frequency = ccs_pll_clk_frequency;
} else {
cm3_assert_not_reached();
}
ccs_set_pclkdiv(config->pclkdiv);
ccs_pclk_enable();
ccs_aclk_enable();
ccs_adcclk_enable();
ccs_stclk_sleep_disable();
ccs_hclk_frequency = ccs_sclk_frequency / config->hclkdiv;
ccs_aclk_frequency = ccs_sclk_frequency / config->aclkdiv;
ccs_pclk_frequency = ccs_hclk_frequency / config->pclkdiv;
MEMCTL_FLASHLOCK = MEMCTL_FLASHLOCK_CLEAR;
}

View File

@@ -0,0 +1,163 @@
/**
* @ingroup PAC55xx_gpio
* @brief <b>PAC55xxxx General-Purpose Input/Output (GPIO)</b>
* @author @htmlonly &copy; @endhtmlonly 2019 Brian Viele <vielster@allocor.tech>
* @date December 1, 2019
*
* This library supports the GPIO module in the PAC55xx SoC from Qorvo.
*
* 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/pac55xx/gpio.h>
static uint32_t get_ccs_port_base(uint32_t gpioport) {
switch (gpioport) {
case GPIOA:
return CCS_PORTA;
case GPIOB:
return CCS_PORTB;
case GPIOC:
return CCS_PORTC;
case GPIOD:
return CCS_PORTD;
case GPIOE:
return CCS_PORTE;
case GPIOF:
return CCS_PORTF;
case GPIOG:
return CCS_PORTG;
default:
return 0U;
}
}
void gpio_mode_setup(uint32_t gpioport, gpio_mode_t mode,
ccs_pull_updown_t pull_up_down, uint16_t gpios) {
/* Read the current value of the register. */
uint32_t reg = GPIO_MODER(gpioport);
uint32_t port = get_ccs_port_base(gpioport);
/* Loop through only set bits, utilize built-ins for optimized assembly. */
int ffs = __builtin_ffs(gpios);
while (ffs) {
const int pin = ffs - 1;
const int bit = (1 << pin);
/* Update the cached mode value by clearing then setting values. */
reg &= ~GPIO_MODER_MASK_PIN(pin);
reg |= GPIO_MODER_MODE(pin, mode);
/* Set the pinmux configurations for the pull-up / pull-down. */
if (pull_up_down == CCS_IO_PULL_UP) {
CCS_PDENR(port) &= ~bit;
CCS_PUENR(port) |= bit;
} else if (pull_up_down == CCS_IO_PULL_DOWN) {
CCS_PUENR(port) &= ~bit;
CCS_PDENR(port) |= bit;
} else {
CCS_PDENR(port) &= ~bit;
CCS_PUENR(port) &= ~bit;
}
gpios ^= bit; /* Clear the bit we just serviced. */
ffs = __builtin_ffs(gpios);
}
GPIO_MODER(gpioport) = reg;
}
void gpio_set_outmask(uint32_t gpioport, bool enable, uint16_t gpios) {
uint32_t reg = GPIO_OUTMASKR(gpioport);
if (enable) {
reg |= gpios;
} else {
reg &= ~gpios;
}
GPIO_OUTMASKR(gpioport) = reg;
}
void gpio_set(uint32_t gpioport, uint16_t gpios) {
GPIO_DOSETR(gpioport) = gpios;
}
void gpio_clear(uint32_t gpioport, uint16_t gpios) {
GPIO_DOCLEARR(gpioport) = gpios;
}
uint16_t gpio_get(uint32_t gpioport, uint16_t gpios) {
return GPIO_INR(gpioport) & gpios;
}
void gpio_set_af(uint32_t gpioport, ccs_muxsel_func_t muxsel, uint16_t gpios) {
uint32_t port = get_ccs_port_base(gpioport);
/* Update each of the pin configs. */
uint32_t reg = CCS_MUXSELR(port);
int ffs = __builtin_ffs(gpios);
while (ffs) {
const int pin = ffs - 1;
reg &= ~CCS_MUXSELR_MASK_PIN(pin);
reg |= CCS_MUXSELR_VAL(pin, muxsel);
/* Set the pinmux configurations for the pull-up / pull-down. */
gpios ^= (1 << pin); /* Clear the bit we just serviced. */
ffs = __builtin_ffs(gpios);
}
CCS_MUXSELR(port) = reg;
}
void gpio_set_output_options(uint32_t gpioport, ccs_drive_strength_t strength,
uint16_t gpios) {
uint32_t port = get_ccs_port_base(gpioport);
/* Update each of the pin configs. */
uint32_t reg = CCS_DSR(port);
int ffs = __builtin_ffs(gpios);
while (ffs) {
const int pin = ffs - 1;
reg &= ~CCS_DSR_MASK_PIN(pin);
reg |= CCS_DSR_DS_VAL(pin, strength);
/* Set the pinmux configurations for the pull-up / pull-down. */
gpios ^= (1 << pin); /* Clear the bit we just serviced. */
ffs = __builtin_ffs(gpios);
}
CCS_DSR(port) = reg;
}
void gpio_set_schmidt_trigger(uint32_t gpioport, bool enable, uint16_t gpios) {
uint32_t port = get_ccs_port_base(gpioport);
/* Update each of the pin configs. */
uint32_t reg = CCS_DSR(port);
int ffs = __builtin_ffs(gpios);
while (ffs) {
const int pin = ffs - 1;
if (enable) {
reg |= CCS_DSR_SCHMIDT_PIN(pin);
} else {
reg &= ~CCS_DSR_SCHMIDT_PIN(pin);
}
/* Set the pinmux configurations for the pull-up / pull-down. */
gpios ^= (1 << pin); /* Clear the bit we just serviced. */
ffs = __builtin_ffs(gpios);
}
CCS_DSR(port) = reg;
}

View File

@@ -0,0 +1,78 @@
/**
* @brief <b>PAC55xxxx Memory Controller Driver</b>
* @author @htmlonly &copy; @endhtmlonly 2020 Kevin Stefanik <kevin@allocor.tech>
* @date April 1, 2020
*
* This library supports the Memory Controller in the PAC55xx SoC from Qorvo.
*
* 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/pac55xx/memctl.h>
void memctl_flash_set_wstate(uint32_t wstate) {
MEMCTL_MEMCTLR = (MEMCTL_MEMCTLR & ~MEMCTL_MEMCTLR_WSTATE(MEMCTL_MEMCTLR_WSTATE_MASK)) | MEMCTL_MEMCTLR_WSTATE(wstate);
}
void memctl_flash_set_mclkdiv(uint32_t div) {
MEMCTL_MEMCTLR = (MEMCTL_MEMCTLR & ~MEMCTL_MEMCTLR_MCLKDIV(16)) | MEMCTL_MEMCTLR_MCLKDIV(div);
}
void memctl_flash_reset_write_buffer(void) {
MEMCTL_MEMCTLR = (MEMCTL_MEMCTLR & ~MEMCTL_MEMCTLR_WRITEWORDCNT(MEMCTL_MEMCTLR_WRITEWORDCNT_MASK));
}
void memctl_flash_standby_mode_enable(void) {
MEMCTL_MEMCTLR |= MEMCTL_MEMCTLR_STBY;
}
void memctl_flash_standby_mode_disable(void) {
MEMCTL_MEMCTLR &= ~MEMCTL_MEMCTLR_STBY;
}
void memctl_flash_cache_enable(void) {
MEMCTL_MEMCTLR &= ~MEMCTL_MEMCTLR_CACHEDIS;
}
void memctl_flash_cache_disable(void) {
MEMCTL_MEMCTLR |= MEMCTL_MEMCTLR_CACHEDIS;
}
void memctl_flash_select_roscclk(void) {
MEMCTL_MEMCTLR &= ~MEMCTL_MEMCTLR_MCLKSEL;
}
void memctl_flash_select_mclk(void) {
MEMCTL_MEMCTLR |= MEMCTL_MEMCTLR_MCLKSEL;
}
void memctl_sram_ecc_enable(void) {
MEMCTL_MEMCTLR &= ~MEMCTL_MEMCTLR_ECCDIS;
}
void memctl_sram_ecc_disable(void) {
MEMCTL_MEMCTLR |= MEMCTL_MEMCTLR_ECCDIS;
}
void memctl_sram_ecc_single_bit_interrupt_enable(void) {
MEMCTL_MEMCTLR |= MEMCTL_MEMCTLR_SEIE;
}
void memctl_sram_ecc_single_bit_interrupt_disable(void) {
MEMCTL_MEMCTLR &= ~MEMCTL_MEMCTLR_SEIE;
}
void memctl_sram_ecc_dual_bit_interrupt_enable(void) {
MEMCTL_MEMCTLR |= MEMCTL_MEMCTLR_DEIE;
}
void memctl_sram_ecc_dual_bit_interrupt_disable(void) {
MEMCTL_MEMCTLR &= ~MEMCTL_MEMCTLR_DEIE;
}
void memctl_invaddr_interrupt_enable(void) {
MEMCTL_MEMCTLR |= MEMCTL_MEMCTLR_INVADDRIE;
}
void memctl_invaddr_interrupt_disable(void) {
MEMCTL_MEMCTLR &= ~MEMCTL_MEMCTLR_INVADDRIE;
}

View File

@@ -0,0 +1,200 @@
/**
* @defgroup usart_api USART peripheral API
* @ingroup peripheral_apis
* @brief <b>PAC55xxxx USART Driver</b>
* @author @htmlonly &copy; @endhtmlonly 2020 Kevin Stefanik <kevin@allocor.tech>
* @date February 25, 2020
*
* This library supports the USART module in the PAC55xx SoC from Qorvo.
*
* 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/pac55xx/usart.h>
#include <libopencm3/cm3/common.h>
/**@{*/
/** @brief USART Set Baudrate
The baud rate is computed assuming a peripheral clock of 150MHz.
@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.
@return Actual baud rate.
*/
uint32_t usart_set_baudrate(uint32_t usart, uint32_t baud) {
/* TODO Assumes 150MHz PCLK. Update this to ccs_get_peripheral_freq() like on other platforms */
const uint32_t pclk = 150000000;
uint32_t denom = (baud << 4); /* denominator is baud * 16. */
uint32_t dlr = 0xFFFFu & ((pclk + denom / 2) / denom);
USART_DLR(usart) = dlr;
return pclk / (dlr << 4); /* Baud Rate = PCLK / (16 * UARTADLR) */
}
/** @brief USART Configure Line Control Register
This register sets the data bits, stop bits, and parity
@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base
@param[in] data_bits unsigned 8 bit. One of USART_DATABITS_5/6/7/8.
@param[in] stop_bits unsigned 8 bit. One of USART_STOPBITS_1/1P5/2.
@param[in] parity unsigned 8 bit. One of USART_PARITY_DISABLE/ODD/EVEN/FORCE1/FORCE0
*/
void usart_configure_lcr(uint32_t usart, uint8_t data_bits, uint8_t stop_bits,
uint8_t parity) {
USART_LCR(usart) = USART_LCR_WLS(data_bits)
| ((stop_bits==USART_STOPBITS_2) ? USART_LCR_SBS : 0)
| USART_LCR_PSELPEN(parity);
}
/** @brief Enable Break Control
Enables break control bit that forces TX pin to logic low.
@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base
*/
void usart_break_enable(uint32_t usart) {
USART_LCR(usart) |= USART_LCR_BCON;
}
/** @brief Disable Break Control
Disables break control bit that forces TX pin to logic low.
@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base
*/
void usart_break_disable(uint32_t usart) {
USART_LCR(usart) &= ~USART_LCR_BCON;
}
/** @brief Enable Enhanced Mode
Enable enhanced mode to generate interrupts when FIFO thresholds in FCR are reached.
@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base
*/
void usart_enhanced_enable(uint32_t usart) {
USART_EFR(usart) = USART_EFR_ENMODE;
}
/** @brief Disable Enhanced Mode
Disable enhanced mode to generate interrupts when FIFO thresholds in FCR are reached.
@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base
*/
void usart_enhanced_disable(uint32_t usart) {
USART_EFR(usart) &= ~USART_EFR_ENMODE;
}
/** @brief Enable FIFOs
Enable both TX and RX FIFOs. This must be set before setting the trigger levels.
@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base
*/
void usart_fifo_enable(uint32_t usart) {
USART_FCR(usart) |= USART_FCR_FIFOEN;
}
/** @brief Disable FIFOs
Disable both TX and RX FIFOs.
@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base
*/
void usart_fifo_disable(uint32_t usart) {
USART_FCR(usart) &= ~USART_FCR_FIFOEN;
}
/** Set the TX and RX FIFO depth. This function also enables the FIFOs if not already.
@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base
@param[in] tx_depth unsigned 8 bit. One of USART_FIFO_TRIG_1/2/4/14CHAR.
@param[in] rx_depth unsigned 8 bit. One of USART_FIFO_TRIG_1/2/4/14CHAR.
*/
void usart_set_fifo_depth(uint32_t usart, uint8_t tx_depth, uint8_t rx_depth) {
USART_FCR(usart) |= USART_FCR_FIFOEN;
USART_FCR(usart) = USART_FCR_TXTL(tx_depth) | USART_FCR_RXTL(rx_depth) | USART_FCR_FIFOEN;
}
/** @brief Write byte to TX FIFO
@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base
@param[in] data unsigned 8 bit. Data to write to the TX FIFO.
*/
void usart_send(uint32_t usart, uint8_t data) {
USART_THR(usart) = (uint32_t)data;
}
/** @brief Read byte from the RX FIFO
@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base
@return Data read from the RX FIFO.
*/
uint8_t usart_recv(uint32_t usart) {
return (uint8_t)USART_RBR(usart);
}
/** @brief Enable RX Interrupts
Enable both the Receive Data Available and Character Timeout interrupts.
@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base
*/
void usart_enable_rx_interrupt(uint32_t usart) {
USART_IER(usart) |= USART_IER_RBRIE;
}
/** @brief Disable RX Interrupts
Disable both the Receive Data Available and Character Timeout interrupts.
@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base
*/
void usart_disable_rx_interrupt(uint32_t usart) {
USART_IER(usart) &= ~USART_IER_RBRIE;
}
/** @brief Enable TX Interrupt
Enable the TX Holding Register Empty interrupt.
@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base
*/
void usart_enable_tx_interrupt(uint32_t usart) {
USART_IER(usart) |= USART_IER_THRIE;
}
/** @brief Disable TX Interrupt
Disable the TX Holding Register Empty interrupt.
@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base
*/
void usart_disable_tx_interrupt(uint32_t usart) {
USART_IER(usart) &= ~USART_IER_THRIE;
}
/** @brief Enable RX Line Status Interrupt
Enable the RX Line Status interrupt.
@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base
*/
void usart_enable_rls_interrupt(uint32_t usart) {
USART_IER(usart) |= USART_IER_RLSIE;
}
/** @brief Disable RX Line Status Interrupt
Disable the RX Line Status interrupt.
@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base
*/
void usart_disable_rls_interrupt(uint32_t usart) {
USART_IER(usart) &= ~USART_IER_RLSIE;
}
/** @brief Clear the TX FIFO
Clears the TX FIFO. The bit is self-clearing.
@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base
*/
void usart_clear_tx_fifo(uint32_t usart) {
USART_FCR(usart) |= USART_FCR_TXFIFORST;
}
/** @brief Clear the RX FIFO
Clears the RX FIFO. The bit is self-clearing.
@param[in] usart unsigned 32 bit. USART block register address base @ref usart_reg_base
*/
void usart_clear_rx_fifo(uint32_t usart) {
USART_FCR(usart) |= USART_FCR_RXFIFORST;
}
/**@}*/

View File

@@ -0,0 +1,24 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2019 Brian Viele <vielster@allocor.tech>
*
* 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/>.
*/
/* Standard Cortex-M4F initialization of FPU. */
static void pre_main(void) {
/* Enable FPU */
SCB_CPACR |= SCB_CPACR_FULL * (SCB_CPACR_CP10 | SCB_CPACR_CP11);
}

View File

@@ -0,0 +1,40 @@
##
## 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_sam3a
SRCLIBDIR ?= ../..
CC = $(PREFIX)gcc
AR = $(PREFIX)ar
TGT_CFLAGS = -Os -Wall -Wextra -I../../../include -fno-common \
-mcpu=cortex-m3 -mthumb $(FP_FLAGS) -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD -DSAM3A
TGT_CFLAGS += $(DEBUG_FLAGS)
TGT_CFLAGS += $(STANDARD_FLAGS)
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS += gpio_common_all.o gpio_common_3a3u3x.o
OBJS += pmc.o
OBJS += usart_common_all.o usart_common_3.o
VPATH += ../../usb:../../cm3:../common
include ../../Makefile.include

View File

@@ -0,0 +1,40 @@
##
## 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
SRCLIBDIR ?= ../..
CC = $(PREFIX)gcc
AR = $(PREFIX)ar
TGT_CFLAGS = -Os -Wall -Wextra -I../../../include -fno-common \
-mcpu=cortex-m3 -mthumb $(FP_FLAGS) -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD -DSAM3N
TGT_CFLAGS += $(DEBUG_FLAGS)
TGT_CFLAGS += $(STANDARD_FLAGS)
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS += gpio_common_all.o gpio_common_3n3s.o
OBJS += pmc.o
OBJS += usart_common_all.o usart_common_3.o
VPATH += ../../cm3:../common
include ../../Makefile.include

View File

@@ -0,0 +1,41 @@
##
## This file is part of the libopencm3 project.
##
## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
## Copyright (C) 2014 Felix Held <felix-libopencm3@felixheld.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_sam3s
SRCLIBDIR ?= ../..
CC = $(PREFIX)gcc
AR = $(PREFIX)ar
TGT_CFLAGS = -Os -Wall -Wextra -I../../../include -fno-common \
-mcpu=cortex-m3 -mthumb $(FP_FLAGS) -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD -DSAM3S
TGT_CFLAGS += $(DEBUG_FLAGS)
TGT_CFLAGS += $(STANDARD_FLAGS)
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS += gpio_common_all.o gpio_common_3n3s.o
OBJS += pmc.o
OBJS += usart_common_all.o usart_common_3.o
VPATH += ../../usb:../../cm3:../common
include ../../Makefile.include

View File

@@ -0,0 +1,41 @@
##
## This file is part of the libopencm3 project.
##
## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
## Copyright (C) 2014 Felix Held <felix-libopencm3@felixheld.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_sam3u
SRCLIBDIR ?= ../..
CC = $(PREFIX)gcc
AR = $(PREFIX)ar
TGT_CFLAGS = -Os -Wall -Wextra -I../../../include -fno-common \
-mcpu=cortex-m3 -mthumb $(FP_FLAGS) -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD -DSAM3U
TGT_CFLAGS += $(DEBUG_FLAGS)
TGT_CFLAGS += $(STANDARD_FLAGS)
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS += gpio_common_all.o gpio_common_3a3u3x.o
OBJS += pmc.o
OBJS += usart_common_all.o usart_common_3.o
VPATH += ../../usb:../../cm3:../common
include ../../Makefile.include

View File

@@ -0,0 +1,40 @@
##
## 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
SRCLIBDIR ?= ../..
CC = $(PREFIX)gcc
AR = $(PREFIX)ar
TGT_CFLAGS = -Os -Wall -Wextra -I../../../include -fno-common \
-mcpu=cortex-m3 -mthumb $(FP_FLAGS) -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD -DSAM3X
TGT_CFLAGS += $(DEBUG_FLAGS)
TGT_CFLAGS += $(STANDARD_FLAGS)
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS += gpio_common_all.o gpio_common_3a3u3x.o
OBJS += pmc.o
OBJS += usart_common_all.o usart_common_3.o
VPATH += ../../usb:../../cm3:../common
include ../../Makefile.include

View File

@@ -0,0 +1,40 @@
##
## 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/>.
##
LIBNAME = libopencm3_sam4l
SRCLIBDIR ?= ../..
FP_FLAGS ?= -msoft-float
CC = $(PREFIX)gcc
AR = $(PREFIX)ar
TGT_CFLAGS = -Os -Wall -Wextra -I../../../include -fno-common \
-mcpu=cortex-m4 -mthumb $(FP_FLAGS) -Wstrict-prototypes \
-ffunction-sections -fdata-sections -MD -DSAM4L
TGT_CFLAGS += $(DEBUG_FLAGS)
# ARFLAGS = rcsv
ARFLAGS = rcs
OBJS += adcife.o
OBJS += gpio.o
OBJS += pm.o
OBJS += scif.o
OBJS += usart_common_all.o usart.o
VPATH += ../../usb:../../cm3:../common
include ../../Makefile.include

View File

@@ -0,0 +1,121 @@
/** @addtogroup scif
*
* @brief <b>Access functions for the SAM4 Analog to Digital Converter Interface (ADCIFE)</b>
* @ingroup SAM4
* LGPL License Terms @ref lgpl_license
* @author @htmlonly &copy; @endhtmlonly 2016
* Maxim Sloyko <maxims@google.com>
*
*/
#include <libopencm3/sam/adcife.h>
/** @brief Enable ADC interface. Must be done before any other configuration.
*
* This function does it synchronously and returns only when the interface is
* actually enabled.
*/
void adcife_enable_sync(void)
{
ADCIFE_CR = ADCIFE_CR_EN;
while (!(ADCIFE_SR & ADCIFE_SR_EN));
}
void adcife_configure(
enum adcife_refsel ref,
enum adcife_speed speed,
enum adcife_clk clk,
enum adcife_prescal prescal)
{
ADCIFE_CFG = ADCIFE_CFG_REFSEL_MASKED(ref)
| ADCIFE_CFG_SPEED_MASKED(speed)
| ADCIFE_CFG_PRESCAL_MASKED(prescal)
| clk;
}
void adcife_select_channel(enum adcife_channel ad)
{
ADCIFE_SEQCFG |= ADCIFE_SEQCFG_MUXPOS_MASKED(ad);
}
void adcife_set_resolution(enum adcife_resolution res)
{
if (ADCIFE_RESOLUTION_12BITS == res) {
ADCIFE_SEQCFG &= ~ADCIFE_SEQCFG_RES;
} else {
ADCIFE_SEQCFG |= ADCIFE_SEQCFG_RES;
}
}
void adcife_select_trigger(enum adcife_trigger trig)
{
ADCIFE_SEQCFG &= ~ADCIFE_SEQCFG_TRGSEL_MASK;
ADCIFE_SEQCFG |= ADCIFE_SEQCFG_TRGSEL_MASKED(trig);
}
void adcife_set_gain(enum adcife_gain gain)
{
ADCIFE_SEQCFG &= ~ADCIFE_SEQCFG_GAIN_MASK;
ADCIFE_SEQCFG |= ADCIFE_SEQCFG_GAIN_MASKED(gain);
}
void adcife_set_bipolar(bool enable)
{
if (enable) {
ADCIFE_SEQCFG |= ADCIFE_SEQCFG_BIPOLAR;
} else {
ADCIFE_SEQCFG &= ~ADCIFE_SEQCFG_BIPOLAR;
}
}
void adcife_set_left_adjust(bool enable)
{
if (enable) {
ADCIFE_SEQCFG |= ADCIFE_SEQCFG_HWLA;
} else {
ADCIFE_SEQCFG &= ~ADCIFE_SEQCFG_HWLA;
}
}
void adcife_start_conversion(void)
{
ADCIFE_CR = ADCIFE_CR_STRIG;
}
void adcife_wait_conversion(void)
{
while (!(ADCIFE_SR & ADCIFE_SR_SEOC));
ADCIFE_SCR = ADCIFE_SR_SEOC;
}
struct adcife_lcv adcife_get_lcv(void)
{
struct adcife_lcv res;
res._lc_u.lcv = ADCIFE_LCV;
return res;
}
void adcife_enable_interrupts(uint32_t imask)
{
ADCIFE_IER = imask;
}
void adcife_disable_interrupts(uint32_t imask)
{
ADCIFE_IDR = imask;
}
void adcife_timer_start(void)
{
ADCIFE_CR = ADCIFE_CR_TSTART;
}
void adcife_timer_stop(void)
{
ADCIFE_CR = ADCIFE_CR_TSTOP;
}
void adcife_timer_set_timeout(uint16_t timeout)
{
ADCIFE_TIM = timeout;
}

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