Such commit. Many change.

GPS now seems to be alive on the dev board, using UBX mode. SAM D20 drivers coming along.

Timepulse next. And then radio
rocketry
Richard Eoin Meadows 2014-08-23 22:18:49 +01:00
rodzic 72b5f7a23e
commit 4c908d1448
66 zmienionych plików z 14417 dodań i 80 usunięć

Wyświetl plik

@ -27,6 +27,6 @@
;; Keep this directory as the default directory when navigating subdirectoies
((nil
(gud-gdb-command-name . "arm-none-eabi-gdb -i=mi")
(gud-gdb-command-name . "arm-none-eabi-gdb --annotate=3")
(eval setq default-directory
(locate-dominating-file buffer-file-name ".dir-locals.el"))))

Wyświetl plik

@ -1 +0,0 @@
LICENSE-samd20-gcc-blackmagic.md

Wyświetl plik

Wyświetl plik

@ -244,7 +244,7 @@ etags: $(TAGFILES)
#
.PHONY: emacs
emacs:
@emacs $(TAGFILES) Makefile config.mk README.md
@emacs23 $(TAGFILES) Makefile config.mk README.md
# Makes the verification tool
#

Wyświetl plik

@ -1 +0,0 @@
README-samd20-gcc-blackmagic.md

63
firmware/README.md 100644
Wyświetl plik

@ -0,0 +1,63 @@
## Bristol Longshot ##
Firmware for the Bristol Longshot tracker. Gets its GPS position home
by whatever means possible, come hell or high water.
(Actually, come low temperatures, long paths, geopolitical
restrictions, low power etc.)
## Technical Description ##
The firmware is written in C and targeted at the highly configurable
Atmel SAMD20 series of ARM Cortex M0+ micromontrollers. The code can
be built using
[GNU Tools for ARM Embedded Processors](https://launchpad.net/gcc-arm-embedded/).
See [README-samd20-gcc-blackmagic.md](README-samd20-gcc-blackmagic.md)
for more details.
## Developement Framework ##
Separate developement hardware exists, this has a separate MCU for
current and voltage measurement, as well controling the voltage at the
step-up input.
This is part of the development framework.
The other part of the framework is several 'development scripts' that allow
## Verification Framework ##
The verification suite ultimately allows a single command to return a
PASS/FAIL vertict on the readiness of the system to fly. There should
be no user input required during the tests - A test case that requires user
input is actually a development script.
#### REAL_HARDWARE
If this flag is set, the test scripts can presume the MCU has full
access to real flight hardware.
Otherwise the tests must presume that their target is just the MCU on
a developement board and set-up any required test harnesses as appropriate.
#### DYNAMIC_TESTS
If this flag is set, then the test cases may use dynamic data from
the internet or other sources to test the tracker's performance in
current real-world conditions. This may even include uploading the
resulting test data to habhub or similar.
Otherwise test cases must be perfectly deterministic and
repeatable. Using psudo-random sequences to generate test data is
acceptable, as long as a constant seed is used.
### LONG_TEST
If this flag is set, then the test case may make as many iterations it
feels it needs for a full and thorough test.
Otherwise test cases must take less than 1 second of real world runtime
## Sources & Licensing ##
See [LICENSE.md](LICENSE.md)

Wyświetl plik

@ -201,5 +201,6 @@ void Reset_Handler(void)
*/
void Dummy_Handler(void)
{
while (1);
}

Wyświetl plik

@ -24,11 +24,11 @@
#
# This is used to define the name of the build artifact
#
PROJECT_NAME := blinky
PROJECT_NAME := longshot
# The exact chip being built for.
#
TARGET_CHIP := SAMD20J18
TARGET_CHIP := SAMD20E17
# Compiliation Flags
#
@ -51,4 +51,4 @@ LINKER_FLAGS := -Wl,--gc-sections
# port. When this field is specified GDB will attempt to connect to
# this debugger on startup.
#
BLACKMAGIC_PATH :=
BLACKMAGIC_PATH := /dev/serial/by-id/usb-Black_Sphere_Technologies_Black_Magic_Probe_E1D399E0-if00

BIN
firmware/core 100644

Plik binarny nie jest wyświetlany.

Plik diff jest za duży Load Diff

Wyświetl plik

@ -0,0 +1,179 @@
/**
* \file
*
* \brief SAM D20/D21/R21 Peripheral Analog-to-Digital Converter Driver
*
* Copyright (C) 2012-2014 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#ifndef ADC_CALLBACK_H_INCLUDED
#define ADC_CALLBACK_H_INCLUDED
#ifdef __cplusplus
extern "C" {
#endif
/**
* \addtogroup asfdoc_sam0_adc_group
*
* @{
*/
#include <adc.h>
/**
* Enum for the possible types of ADC asynchronous jobs that may be issued to
* the driver.
*/
enum adc_job_type {
/** Asynchronous ADC read into a user provided buffer */
ADC_JOB_READ_BUFFER,
};
/**
* \name Callback Management
* @{
*/
void adc_register_callback(
struct adc_module *const module,
adc_callback_t callback_func,
enum adc_callback callback_type);
void adc_unregister_callback(
struct adc_module *module,
enum adc_callback callback_type);
/**
* \brief Enables callback
*
* Enables the callback function registered by \ref
* adc_register_callback. The callback function will be called from the
* interrupt handler when the conditions for the callback type are met.
*
* \param[in] module Pointer to ADC software instance struct
* \param[in] callback_type Callback type given by an enum
*
* \returns Status of the operation
* \retval STATUS_OK If operation was completed
* \retval STATUS_ERR_INVALID If operation was not completed,
* due to invalid callback_type
*
*/
static inline void adc_enable_callback(
struct adc_module *const module,
enum adc_callback callback_type)
{
/* Sanity check arguments */
Assert(module);
/* Enable callback */
module->enabled_callback_mask |= (1 << callback_type);
/* Enable window interrupt if this is a window callback */
if (callback_type == ADC_CALLBACK_WINDOW) {
adc_enable_interrupt(module, ADC_INTERRUPT_WINDOW);
}
/* Enable overrun interrupt if error callback is registered */
if (callback_type == ADC_CALLBACK_ERROR) {
adc_enable_interrupt(module, ADC_INTERRUPT_OVERRUN);
}
}
/**
* \brief Disables callback
*
* Disables the callback function registered by the \ref
* adc_register_callback.
*
* \param[in] module Pointer to ADC software instance struct
* \param[in] callback_type Callback type given by an enum
*
* \returns Status of the operation
* \retval STATUS_OK If operation was completed
* \retval STATUS_ERR_INVALID If operation was not completed,
* due to invalid callback_type
*
*/
static inline void adc_disable_callback(
struct adc_module *const module,
enum adc_callback callback_type)
{
/* Sanity check arguments */
Assert(module);
/* Disable callback */
module->enabled_callback_mask &= ~(1 << callback_type);
/* Disable window interrupt if this is a window callback */
if (callback_type == ADC_CALLBACK_WINDOW) {
adc_disable_interrupt(module, ADC_INTERRUPT_WINDOW);
}
/* Disable overrun interrupt if this is the error callback */
if (callback_type == ADC_CALLBACK_ERROR) {
adc_disable_interrupt(module, ADC_INTERRUPT_OVERRUN);
}
}
/** @} */
/**
* \name Job Management
* @{
*/
enum status_code adc_read_buffer_job(
struct adc_module *const module_inst,
uint16_t *buffer,
uint16_t samples);
enum status_code adc_get_job_status(
struct adc_module *module_inst,
enum adc_job_type type);
void adc_abort_job(
struct adc_module *module_inst,
enum adc_job_type type);
/** @} */
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* ADC_CALLBACK_H_INCLUDED */

115
firmware/inc/gps.h 100644
Wyświetl plik

@ -0,0 +1,115 @@
/*
* Functions for the UBLOX 6 GPS
* Copyright (C) 2014 Richard Meadows <richardeoin>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef GPS_H
#define GPS_H
/* We use the packed attribute so we can copy direct to structs */
#define __PACKED__ __attribute__((packed))
/**
* UBX CFG ANT Antenna Control Settings
*/
volatile struct ubx_cfg_ant {
uint16_t flags;
uint16_t pins;
} __PACKED__ ubx_cfg_ant;
/**
* UBX CFG NAV5 Navigation Engine Settings
*/
volatile struct ubx_cfg_nav5 {
uint16_t mask;
uint8_t dynModel;
uint8_t fixMode;
int32_t fixedAlt;
uint32_t fixedAltVar;
int8_t minElev;
uint8_t drLimit;
uint16_t pDop;
uint16_t tDop;
uint16_t pAcc;
uint16_t tAcc;
uint8_t staticHoldThresh;
uint8_t dgpsTimeOut;
uint32_t res2;
uint32_t res3;
uint32_t res4;
} __PACKED__ ubx_cfg_nav5;
/**
* UBX NAV POSLLH Geodetic Position Solution
*/
volatile struct ubx_nav_posllh {
uint32_t iTOW;
int32_t lon;
int32_t lat;
int32_t height;
int32_t hMSL;
uint32_t hAcc;
uint32_t vAcc;
} __PACKED__ ubx_nav_posllh;
/**
* UBX NAV TIMEUTC
*/
volatile struct ubx_nav_timeutc {
uint32_t iTOW;
uint32_t tAcc;
int32_t nano;
uint16_t year;
uint8_t month;
uint8_t day;
uint8_t hour;
uint8_t min;
uint8_t sec;
uint8_t valid;
} __PACKED__ ubx_nav_timeutc;
/**
* UBX NAV SOL Navigation Solution Information
*/
volatile struct ubx_nav_sol {
uint32_t iTOW;
int32_t fTOW;
uint16_t week;
uint8_t gpsFix;
uint8_t flags;
int32_t ecefX;
int32_t ecefY;
int32_t ecefZ;
uint32_t pAcc;
int32_t ecefVX;
int32_t ecefVY;
int32_t ecefVZ;
uint32_t sAcc;
uint16_t pDOP;
uint8_t res1;
uint8_t numSV;
uint32_t res2;
} __PACKED__ ubx_nav_sol;
void usart_loopback_test(void);
char* gps_get_frame(void);
void gps_init(void);
#endif /* GPS_H */

Wyświetl plik

@ -0,0 +1,137 @@
/*
* Hardware definitions and configuations
* Copyright (C) 2014 Richard Meadows <richardeoin>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef HW_CONFIG_H
#define HW_CONFIG_H
#include "port.h"
#include "samd20.h"
/*
* Convenience definitions for available GPIO modules
*/
#if (PORT_GROUPS > 0)
#define PORTA PORT->Group[0]
#endif
#if (PORT_GROUPS > 1)
#define PORTB PORT->Group[1]
#endif
#if (PORT_GROUPS > 2)
#define PORTC PORT->Group[2]
#endif
#if (PORT_GROUPS > 3)
#define PORTD PORT->Group[3]
#endif
//#define XPLAINED
/**
* LED
*/
#ifdef XPLAINED
#define LED0_PIN PIN_PA14
#else
#define LED0_PIN PIN_PA25 /* Shared with Radio GPIO */
#endif
/**
* Reset
*/
#define RESET_DUMMY1_PIN PIN_PA05
#define RESET_DUMMY2_PIN PIN_PA15
/**
* GPS
*/
#define GPS_SERCOM (SercomUsart*)SERCOM1
#define GPS_SERCOM_MOGI_PIN PIN_PA00
#define GPS_SERCOM_MOGI_PINMUX PINMUX_PA00D_SERCOM1_PAD0
#define GPS_SERCOM_MIGO_PIN PIN_PA01
#define GPS_SERCOM_MIGO_PINMUX PINMUX_PA01D_SERCOM1_PAD1
#define GPS_TIME_PIN PIN_PA28
#define GPS_TIME_PINMUX PINMUX_PA28H_GCLK_IO0
#define GPS_SERCOM_MUX USART_RX_1_TX_0_XCK_1
/* Loopback Testing */
#define USART_MUX_LOOPBACK USART_RX_0_TX_0_XCK_1
/**
* Flash Memory
*/
#define FLASH_SERCOM (SercomSpi*)SERCOM0
#define FLASH_SERCOM_MOSI_PIN PIN_PA06
#define FLASH_SERCOM_MOSI_PINMUX PINMUX_PA06D_SERCOM0_PAD2
#define FLASH_SERCOM_MISO_PIN PIN_PA09
#define FLASH_SERCOM_MISO_PINMUX PINMUX_PA09C_SERCOM0_PAD1
#define FLASH_SERCOM_SCK_PIN PIN_PA07
#define FLASH_SERCOM_SCK_PINMUX PINMUX_PA07D_SERCOM0_PAD3
#define FLASH_CSN_PIN PIN_PA10
#define FLASH_WPN_PIN PIN_PA08
/**
* Battery ADC
*/
#define BATTERY_ADC_PIN PIN_PA11
#define BATTERY_ADC_PINMUX PINMUX_PA11B_ADC_AIN19
/**
* Radio
*/
#define RADIO_SERCOM (SercomSpi*)SERCOM3
#define RADIO_SERCOM_MOSI_PIN PIN_PA19
#define RADIO_SERCOM_MOSI_PINMUX PINMUX_PA19D_SERCOM3_PAD3
#define RADIO_SERCOM_MISO_PIN PIN_PA22
#define RADIO_SERCOM_MISO_PINMUX PINMUX_PA22C_SERCOM3_PAD0
#define RADIO_SERCOM_SCK_PIN PIN_PA23
#define RADIO_SERCOM_SCK_PINMUX PINMUX_PA23C_SERCOM3_PAD1
#define RADIO_SEL_PIN PIN_PA18
#define RADIO_IRQ_PIN PIN_PA24
#define RADIO_IRQ_PINMUX PINMUX_PA24A_EIC_EXTINT12
#define RADIO_HF_CLK_PIN PIN_PA17
#define RADIO_HF_CLK_PINMUX PINMUX_PA17H_GCLK_IO3
#define RADIO_SDN_PIN PIN_PA16
#define RADIO_GPIO0_PIN PIN_PA27
#define RADIO_GPIO1_PIN PIN_PA25 /* Shared with LED */
/**
* SWD
*/
#define SWD_SWDCLK_PIN PIN_PA30
#define SWD_SWDCLK_PINMUX PINMUX_PA30G_CORE_SWCLK
#define SWD_SWDIO_PIN PIN_PA31
/**
* NC - Pins not connected externally
*/
#define NC1_PIN PIN_PA02
#define NC2_PIN PIN_PA03
#define NC3_PIN PIN_PA04
#define NC4_PIN PIN_PA14
#endif /* HW_CONFIG_H */

Wyświetl plik

@ -1,51 +0,0 @@
/*
* Definitions for all things pin related
* Copyright (C) 2014 Richard Meadows <richardeoin>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef PINDEFS_H
#define PINDEFS_H
#include "port.h"
/*
* Convenience definitions for available GPIO modules
*/
#if (PORT_GROUPS > 0)
#define PORTA PORT->Group[0]
#endif
#if (PORT_GROUPS > 1)
#define PORTB PORT->Group[1]
#endif
#if (PORT_GROUPS > 2)
#define PORTC PORT->Group[2]
#endif
#if (PORT_GROUPS > 3)
#define PORTD PORT->Group[3]
#endif
/*
* Definitions for the SAM D20 Xplained Pro Board
*/
#define LED0_PIN PIN_PA14
#endif /* PINDEFS_H */

Wyświetl plik

@ -0,0 +1,127 @@
/**
* SAM D20/D21/R21 Serial Peripheral Interface Driver
*
* Copyright (C) 2012-2014 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#ifndef SERCOM_H_INCLUDED
#define SERCOM_H_INCLUDED
#include "system/system.h"
#include "system/clock.h"
#include "sercom/sercom_pinout.h"
#if (SERCOM0_GCLK_ID_SLOW == SERCOM1_GCLK_ID_SLOW && \
SERCOM0_GCLK_ID_SLOW == SERCOM2_GCLK_ID_SLOW && \
SERCOM0_GCLK_ID_SLOW == SERCOM3_GCLK_ID_SLOW)
# define SERCOM_GCLK_ID SERCOM0_GCLK_ID_SLOW
#else
# error "SERCOM modules must share the same slow GCLK channel ID."
#endif
#if (0x1ff >= REV_SERCOM)
# define FEATURE_SERCOM_SYNCBUSY_SCHEME_VERSION_1
#elif (0x2ff >= REV_SERCOM)
# define FEATURE_SERCOM_SYNCBUSY_SCHEME_VERSION_2
#else
# error "Unknown SYNCBUSY scheme for this SERCOM revision"
#endif
/**
* Status Codes
*/
enum sercom_status_t {
SERCOM_STATUS_OK = 1,
SERCOM_STATUS_BAUDRATE_UNAVAILABLE,
SERCOM_STATUS_TIMEOUT,
SERCOM_STATUS_PACKET_COLLISION,
SERCOM_STATUS_BUSY,
SERCOM_STATUS_DENIED,
SERCOM_STATUS_BAD_FORMAT,
SERCOM_STATUS_BAD_DATA,
SERCOM_STATUS_OVERFLOW,
SERCOM_STATUS_IO,
SERCOM_STATUS_INVALID_ARG,
SERCOM_STATUS_ABORTED,
SERCOM_STATUS_UNSUPPORTED_DEV
};
/**
* Select sercom asynchronous operation mode
*/
enum sercom_asynchronous_operation_mode {
SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC = 0,
SERCOM_ASYNC_OPERATION_MODE_FRACTIONAL,
};
/**
* Select number of samples per bit
*/
enum sercom_asynchronous_sample_num {
SERCOM_ASYNC_SAMPLE_NUM_3 = 3,
SERCOM_ASYNC_SAMPLE_NUM_8 = 8,
SERCOM_ASYNC_SAMPLE_NUM_16 = 16,
};
/**
* Type used for registering interrupt handlers
*/
typedef void (*sercom_handler_t)(Sercom* const sercom_instance,
uint8_t instance_index);
uint8_t _sercom_get_sercom_inst_index(Sercom *const sercom_instance);
void _sercom_set_handler(Sercom* const sercom_instance,
const sercom_handler_t interrupt_handler);
void _sercom_set_gclk_generator(const enum gclk_generator generator_source);
enum sercom_status_t _sercom_get_sync_baud_val(const uint32_t baudrate,
const uint32_t external_clock,
uint16_t *const baudval);
enum sercom_status_t _sercom_get_async_baud_val(const uint32_t baudrate,
const uint32_t peripheral_clock,
uint16_t *const baudval,
enum sercom_asynchronous_operation_mode mode,
enum sercom_asynchronous_sample_num sample_num);
uint32_t _sercom_get_default_pad(Sercom *const sercom_module,
const uint8_t pad);
#endif /* SERCOM_H_INCLUDED */

Wyświetl plik

@ -0,0 +1,82 @@
/**
* SAM D20/D21/R21 SERCOM Module Pinout Definitions
*
* Copyright (C) 2012-2014 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#ifndef SERCOM_PINOUT_H_INCLUDED
#define SERCOM_PINOUT_H_INCLUDED
#include "sercom/sercom.h"
/* SERCOM0 */
#define SERCOM0_PAD0_DEFAULT PINMUX_PA04D_SERCOM0_PAD0
#define SERCOM0_PAD1_DEFAULT PINMUX_PA05D_SERCOM0_PAD1
#define SERCOM0_PAD2_DEFAULT PINMUX_PA06D_SERCOM0_PAD2
#define SERCOM0_PAD3_DEFAULT PINMUX_PA07D_SERCOM0_PAD3
/* SERCOM1 */
#define SERCOM1_PAD0_DEFAULT PINMUX_PA00D_SERCOM1_PAD0
#define SERCOM1_PAD1_DEFAULT PINMUX_PA01D_SERCOM1_PAD1
#define SERCOM1_PAD2_DEFAULT PINMUX_PA30D_SERCOM1_PAD2
#define SERCOM1_PAD3_DEFAULT PINMUX_PA31D_SERCOM1_PAD3
/* SERCOM2 */
#define SERCOM2_PAD0_DEFAULT PINMUX_PA08D_SERCOM2_PAD0
#define SERCOM2_PAD1_DEFAULT PINMUX_PA09D_SERCOM2_PAD1
#define SERCOM2_PAD2_DEFAULT PINMUX_PA10D_SERCOM2_PAD2
#define SERCOM2_PAD3_DEFAULT PINMUX_PA11D_SERCOM2_PAD3
/* SERCOM3 */
#define SERCOM3_PAD0_DEFAULT PINMUX_PA16D_SERCOM3_PAD0
#define SERCOM3_PAD1_DEFAULT PINMUX_PA17D_SERCOM3_PAD1
#define SERCOM3_PAD2_DEFAULT PINMUX_PA18D_SERCOM3_PAD2
#define SERCOM3_PAD3_DEFAULT PINMUX_PA19D_SERCOM3_PAD3
/* SERCOM4 */
#define SERCOM4_PAD0_DEFAULT PINMUX_PA12D_SERCOM4_PAD0
#define SERCOM4_PAD1_DEFAULT PINMUX_PA13D_SERCOM4_PAD1
#define SERCOM4_PAD2_DEFAULT PINMUX_PA14D_SERCOM4_PAD2
#define SERCOM4_PAD3_DEFAULT PINMUX_PA15D_SERCOM4_PAD3
/* SERCOM5 */
#define SERCOM5_PAD0_DEFAULT PINMUX_PA22D_SERCOM5_PAD0
#define SERCOM5_PAD1_DEFAULT PINMUX_PA23D_SERCOM5_PAD1
#define SERCOM5_PAD2_DEFAULT PINMUX_PA24D_SERCOM5_PAD2
#define SERCOM5_PAD3_DEFAULT PINMUX_PA25D_SERCOM5_PAD3
#endif /* SERCOM_PINOUT_H_INCLUDED */

Plik diff jest za duży Load Diff

Wyświetl plik

@ -0,0 +1,568 @@
/**
* SAM D20/D21/R21 SERCOM USART Driver
*
* Copyright (C) 2012-2014 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#ifndef USART_H_INCLUDED
#define USART_H_INCLUDED
/**
* This driver for SAM D20/D21/R21 devices provides an interface for the configuration
* and management of the SERCOM module in its USART mode to transfer or receive
* USART data frames.
*
* The following peripherals are used by this module:
*
* - SERCOM (Serial Communication Interface)
*
* Prerequisites
*
* To use the USART you need to have a GCLK generator enabled and running
* that can be used as the SERCOM clock source. This can either be configured
* in conf_clocks.h or by using the system clock driver.
*
* Module Overview
*
* This driver will use one (or more) SERCOM interfaces on the system
* and configure it to run as a USART interface in either synchronous
* or asynchronous mode.
*
* Frame Format
*
* Communication is based on frames, where the frame format can be customized
* to accommodate a wide range of standards. A frame consists of a start bit,
* a number of data bits, an optional parity bit for error detection as well
* as a configurable length stop bit(s) - see
* \ref asfdoc_sam0_sercom_usart_frame_diagram "the figure below".
* \ref asfdoc_sam0_sercom_usart_frame_params "The table below" shows the
* available parameters you can change in a frame.
*
* \anchor asfdoc_sam0_sercom_usart_frame_params
* <table>
* <caption>USART Frame Parameters</caption>
* <tr>
* <th>Parameter</th>
* <th>Options</th>
* </tr>
* <tr>
* <td>Start bit</td>
* <td>1</td>
* </tr>
* <tr>
* <td>Data bits</td>
* <td>5, 6, 7, 8, 9</td>
* </tr>
* <tr>
* <td>Parity bit</td>
* <td>None, Even, Odd</td>
* </tr>
* <tr>
* <td>Stop bits</td>
* <td>1, 2</td>
* </tr>
* </table>
*
* Synchronous mode
*
* In synchronous mode a dedicated clock line is provided; either by the USART
* itself if in master mode, or by an external master if in slave mode.
* Maximum transmission speed is the same as the GCLK clocking the USART
* peripheral when in slave mode, and the GCLK divided by two if in
* master mode. In synchronous mode the interface needs three lines to
* communicate:
* - TX (Transmit pin)
* - RX (Receive pin)
* - XCK (Clock pin)
*
* Data sampling
* In synchronous mode the data is sampled on either the rising or falling edge
* of the clock signal. This is configured by setting the clock polarity in the
* configuration struct.
*
* Asynchronous mode
*
* In asynchronous mode no dedicated clock line is used, and the
* communication is based on matching the clock speed on the
* transmitter and receiver. The clock is generated from the internal
* SERCOM baudrate generator, and the frames are synchronized by using
* the frame start bits. Maximum transmission speed is limited to the
* SERCOM GCLK divided by 16.
* In asynchronous mode the interface only needs two lines to communicate:
* - TX (Transmit pin)
* - RX (Receive pin)
*
* Transmitter/receiver clock matching
*
* For successful transmit and receive using the asynchronous mode the
* receiver and transmitter clocks needs to be closely matched. When
* receiving a frame that does not match the selected baud rate
* closely enough the receiver will be unable to synchronize the
* frame(s), and garbage transmissions will result.
*
* Parity
*
* Parity can be enabled to detect if a transmission was in
* error. This is done by counting the number of "1" bits in the
* frame. When using Even parity the parity bit will be set if the
* total number of "1"s in the frame are an even number. If using Odd
* parity the parity bit will be set if the total number of "1"s are
* Odd.
*
* When receiving a character the receiver will count the number of
* "1"s in the frame and give an error if the received frame and
* parity bit disagree.
*
* GPIO configuration
*
* The SERCOM module has four internal pads; the RX pin can be placed
* freely on any one of the four pads, and the TX and XCK pins have
* two predefined positions that can be selected as a pair. The pads
* can then be routed to an external GPIO pin using the normal pin
* multiplexing scheme on the SAM D20/D21/R21.
*
* Special Considerations
*
* Never execute large portions of code in the callbacks. These
* are run from the interrupt routine, and thus having long callbacks will
* keep the processor in the interrupt handler for an equally long time.
* A common way to handle this is to use global flags signaling the
* main application that an interrupt event has happened, and only do the
* minimal needed processing in the callback.
*/
#include "sercom/sercom.h"
#include "system/pinmux.h"
#include "samd20.h"
#define USART_WAIT_FOR_SYNC(hw) \
while(hw->STATUS.reg & SERCOM_USART_STATUS_SYNCBUSY)
/**
* Define SERCOM USART features set according to different device family.
*/
#if (SAMD21) || (SAMR21)
/** Usart sync scheme version 2. */
# define FEATURE_USART_SYNC_SCHEME_V2
/** Usart over sampling. */
# define FEATURE_USART_OVER_SAMPLE
/** Usart hardware control flow. */
# define FEATURE_USART_HARDWARE_FLOW_CONTROL
/** IrDA mode. */
# define FEATURE_USART_IRDA
/** LIN slave mode. */
# define FEATURE_USART_LIN_SLAVE
/** Usart collision detection. */
# define FEATURE_USART_COLLISION_DECTION
/** Usart start frame detection. */
# define FEATURE_USART_START_FRAME_DECTION
/** Usart start buffer overflow notification. */
# define FEATURE_USART_IMMEDIATE_BUFFER_OVERFLOW_NOTIFICATION
#endif
#ifndef PINMUX_DEFAULT
/** Default pin mux. */
# define PINMUX_DEFAULT 0
#endif
#ifndef PINMUX_UNUSED
/** Unused PIN mux. */
# define PINMUX_UNUSED 0xFFFFFFFF
#endif
#ifndef USART_TIMEOUT
/** USART timeout value. */
# define USART_TIMEOUT 0xFFFF
#endif
/**
* Callbacks for the Asynchronous USART driver
*/
enum usart_callback {
/** Callback for buffer transmitted */
USART_CALLBACK_BUFFER_TRANSMITTED,
/** Callback for buffer received */
USART_CALLBACK_BUFFER_RECEIVED,
/** Callback for error */
USART_CALLBACK_ERROR,
#ifdef FEATURE_USART_LIN_SLAVE
/** Callback for break character is received. */
USART_CALLBACK_BREAK_RECEIVED,
#endif
#ifdef FEATURE_USART_HARDWARE_FLOW_CONTROL
/** Callback for a change is detected on the CTS pin. */
USART_CALLBACK_CTS_INPUT_CHANGE,
#endif
#ifdef FEATURE_USART_START_FRAME_DECTION
/** Callback for a start condition is detected on the RxD line. */
USART_CALLBACK_START_RECEIVED,
#endif
# if !defined(__DOXYGEN__)
/** Number of available callbacks. */
USART_CALLBACK_N,
# endif
};
/**
* The data order decides which of MSB or LSB is shifted out first when data is
* transferred
*/
enum usart_dataorder {
/** The MSB will be shifted out first during transmission,
* and shifted in first during reception */
USART_DATAORDER_MSB = 0,
/** The LSB will be shifted out first during transmission,
* and shifted in first during reception */
USART_DATAORDER_LSB = SERCOM_USART_CTRLA_DORD,
};
/**
* Select USART transfer mode
*/
enum usart_transfer_mode {
/** Transfer of data is done synchronously */
USART_TRANSFER_SYNCHRONOUSLY = (SERCOM_USART_CTRLA_CMODE),
/** Transfer of data is done asynchronously */
USART_TRANSFER_ASYNCHRONOUSLY = 0
};
/*
* Select parity USART parity mode
*/
enum usart_parity {
/** For odd parity checking, the parity bit will be set if number of
* ones being transferred is even */
USART_PARITY_ODD = SERCOM_USART_CTRLB_PMODE,
/** For even parity checking, the parity bit will be set if number of
* ones being received is odd */
USART_PARITY_EVEN = 0,
/** No parity checking will be executed, and there will be no parity bit
* in the received frame */
USART_PARITY_NONE = 0xFF,
};
/**
* Set the functionality of the SERCOM pins.
*
* See \ref asfdoc_sam0_sercom_usart_mux_settings for a description of the
* various MUX setting options.
*/
enum usart_signal_mux_settings {
#ifdef FEATURE_USART_HARDWARE_FLOW_CONTROL
/** MUX setting RX_0_TX_0_XCK_1 */
USART_RX_0_TX_0_XCK_1 = (SERCOM_USART_CTRLA_RXPO(0) | SERCOM_USART_CTRLA_TXPO(0)),
/** MUX setting RX_0_TX_2_XCK_3 */
USART_RX_0_TX_2_XCK_3 = (SERCOM_USART_CTRLA_RXPO(0) | SERCOM_USART_CTRLA_TXPO(1)),
/** MUX setting USART_RX_0_TX_0_RTS_2_CTS_3 */
USART_RX_0_TX_0_RTS_2_CTS_3 = (SERCOM_USART_CTRLA_RXPO(0) | SERCOM_USART_CTRLA_TXPO(2)),
/** MUX setting RX_1_TX_0_XCK_1 */
USART_RX_1_TX_0_XCK_1 = (SERCOM_USART_CTRLA_RXPO(1) | SERCOM_USART_CTRLA_TXPO(0)),
/** MUX setting RX_1_TX_2_XCK_3 */
USART_RX_1_TX_2_XCK_3 = (SERCOM_USART_CTRLA_RXPO(1) | SERCOM_USART_CTRLA_TXPO(1)),
/** MUX setting USART_RX_1_TX_0_RTS_2_CTS_3 */
USART_RX_1_TX_0_RTS_2_CTS_3 = (SERCOM_USART_CTRLA_RXPO(1) | SERCOM_USART_CTRLA_TXPO(2)),
/** MUX setting RX_2_TX_0_XCK_1 */
USART_RX_2_TX_0_XCK_1 = (SERCOM_USART_CTRLA_RXPO(2) | SERCOM_USART_CTRLA_TXPO(0)),
/** MUX setting RX_2_TX_2_XCK_3 */
USART_RX_2_TX_2_XCK_3 = (SERCOM_USART_CTRLA_RXPO(2) | SERCOM_USART_CTRLA_TXPO(1)),
/** MUX setting USART_RX_2_TX_0_RTS_2_CTS_3 */
USART_RX_2_TX_0_RTS_2_CTS_3 = (SERCOM_USART_CTRLA_RXPO(2) | SERCOM_USART_CTRLA_TXPO(2)),
/** MUX setting RX_3_TX_0_XCK_1 */
USART_RX_3_TX_0_XCK_1 = (SERCOM_USART_CTRLA_RXPO(3) | SERCOM_USART_CTRLA_TXPO(0)),
/** MUX setting RX_3_TX_2_XCK_3 */
USART_RX_3_TX_2_XCK_3 = (SERCOM_USART_CTRLA_RXPO(3) | SERCOM_USART_CTRLA_TXPO(1)),
/** MUX setting USART_RX_3_TX_0_RTS_2_CTS_3 */
USART_RX_3_TX_0_RTS_2_CTS_3 = (SERCOM_USART_CTRLA_RXPO(3) | SERCOM_USART_CTRLA_TXPO(2)),
#else
/** MUX setting RX_0_TX_0_XCK_1 */
USART_RX_0_TX_0_XCK_1 = (SERCOM_USART_CTRLA_RXPO(0)),
/** MUX setting RX_0_TX_2_XCK_3 */
USART_RX_0_TX_2_XCK_3 = (SERCOM_USART_CTRLA_RXPO(0) | SERCOM_USART_CTRLA_TXPO),
/** MUX setting RX_1_TX_0_XCK_1 */
USART_RX_1_TX_0_XCK_1 = (SERCOM_USART_CTRLA_RXPO(1)),
/** MUX setting RX_1_TX_2_XCK_3 */
USART_RX_1_TX_2_XCK_3 = (SERCOM_USART_CTRLA_RXPO(1) | SERCOM_USART_CTRLA_TXPO),
/** MUX setting RX_2_TX_0_XCK_1 */
USART_RX_2_TX_0_XCK_1 = (SERCOM_USART_CTRLA_RXPO(2)),
/** MUX setting RX_2_TX_2_XCK_3 */
USART_RX_2_TX_2_XCK_3 = (SERCOM_USART_CTRLA_RXPO(2) | SERCOM_USART_CTRLA_TXPO),
/** MUX setting RX_3_TX_0_XCK_1 */
USART_RX_3_TX_0_XCK_1 = (SERCOM_USART_CTRLA_RXPO(3)),
/** MUX setting RX_3_TX_2_XCK_3 */
USART_RX_3_TX_2_XCK_3 = (SERCOM_USART_CTRLA_RXPO(3) | SERCOM_USART_CTRLA_TXPO),
#endif
};
/**
* Number of stop bits for a frame.
*/
enum usart_stopbits {
/** Each transferred frame contains 1 stop bit */
USART_STOPBITS_1 = 0,
/** Each transferred frame contains 2 stop bits */
USART_STOPBITS_2 = SERCOM_USART_CTRLB_SBMODE,
};
/**
* Number of bits for the character sent in a frame.
*/
enum usart_character_size {
/** The char being sent in a frame is 5 bits long */
USART_CHARACTER_SIZE_5BIT = SERCOM_USART_CTRLB_CHSIZE(5),
/** The char being sent in a frame is 6 bits long */
USART_CHARACTER_SIZE_6BIT = SERCOM_USART_CTRLB_CHSIZE(6),
/** The char being sent in a frame is 7 bits long */
USART_CHARACTER_SIZE_7BIT = SERCOM_USART_CTRLB_CHSIZE(7),
/** The char being sent in a frame is 8 bits long */
USART_CHARACTER_SIZE_8BIT = SERCOM_USART_CTRLB_CHSIZE(0),
/** The char being sent in a frame is 9 bits long */
USART_CHARACTER_SIZE_9BIT = SERCOM_USART_CTRLB_CHSIZE(1),
};
#ifdef FEATURE_USART_OVER_SAMPLE
/**
* The value of sample rate and baud rate generation mode.
*/
enum usart_sample_rate {
/** 16x over-sampling using arithmetic baud rate generation */
USART_SAMPLE_RATE_16X_ARITHMETIC = SERCOM_USART_CTRLA_SAMPR(0),
/** 16x over-sampling using fractional baud rate generation */
USART_SAMPLE_RATE_16X_FRACTIONAL = SERCOM_USART_CTRLA_SAMPR(1),
/** 8x over-sampling using arithmetic baud rate generation */
USART_SAMPLE_RATE_8X_ARITHMETIC = SERCOM_USART_CTRLA_SAMPR(2),
/** 8x over-sampling using fractional baud rate generation */
USART_SAMPLE_RATE_8X_FRACTIONAL = SERCOM_USART_CTRLA_SAMPR(3),
/** 3x over-sampling using arithmetic baud rate generation */
USART_SAMPLE_RATE_3X_ARITHMETIC = SERCOM_USART_CTRLA_SAMPR(4),
};
/**
* The value of sample number used for majority voting
*/
enum usart_sample_adjustment {
/** The first, middle and last sample number used for majority voting is 7-8-9 */
USART_SAMPLE_ADJUSTMENT_7_8_9 = SERCOM_USART_CTRLA_SAMPA(0),
/** The first, middle and last sample number used for majority voting is 9-10-11 */
USART_SAMPLE_ADJUSTMENT_9_10_11 = SERCOM_USART_CTRLA_SAMPA(1),
/** The first, middle and last sample number used for majority voting is 11-12-13 */
USART_SAMPLE_ADJUSTMENT_11_12_13 = SERCOM_USART_CTRLA_SAMPA(2),
/** The first, middle and last sample number used for majority voting is 13-14-15 */
USART_SAMPLE_ADJUSTMENT_13_14_15 = SERCOM_USART_CTRLA_SAMPA(3),
};
#endif
/**
* Select Receiver or Transmitter
*/
enum usart_transceiver_type {
/** The parameter is for the Receiver */
USART_TRANSCEIVER_RX,
/** The parameter is for the Transmitter */
USART_TRANSCEIVER_TX,
};
/**
* Enables the USART module
*
* \param[in] module Pointer to USART software instance struct
*/
static inline void usart_enable(SercomUsart* const hw)
{
/* Sanity check arguments */
assert(hw);
/* Wait until synchronization is complete */
USART_WAIT_FOR_SYNC(hw);
/* Enable USART module */
hw->CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE;
}
/**
* Disables the USART module
*
* \param[in] module Pointer to USART software instance struct
*/
static inline void usart_disable(SercomUsart* const hw)
{
/* Sanity check arguments */
assert(hw);
/* Wait until synchronization is complete */
USART_WAIT_FOR_SYNC(hw);
/* Disable USART module */
hw->CTRLA.reg &= ~SERCOM_USART_CTRLA_ENABLE;
}
/**
* Disables and resets the USART module.
*
* \param[in] module Pointer to the USART software instance struct
*/
static inline void usart_reset(SercomUsart* const hw)
{
/* Sanity check arguments */
assert(hw);
usart_disable(hw);
/* Wait until synchronization is complete */
USART_WAIT_FOR_SYNC(hw);
/* Reset module */
hw->CTRLA.reg = SERCOM_USART_CTRLA_SWRST;
}
/**
* Enable the given transceiver. Either RX or TX.
*
* \param[in] module Pointer to USART software instance struct
* \param[in] transceiver_type Transceiver type.
*/
static inline void usart_enable_transceiver(SercomUsart* const hw,
enum usart_transceiver_type transceiver_type)
{
/* Sanity check arguments */
assert(hw);
/* Wait until synchronization is complete */
USART_WAIT_FOR_SYNC(hw);
switch (transceiver_type) {
case USART_TRANSCEIVER_RX:
/* Enable RX */
hw->CTRLB.reg |= SERCOM_USART_CTRLB_RXEN;
break;
case USART_TRANSCEIVER_TX:
/* Enable TX */
hw->CTRLB.reg |= SERCOM_USART_CTRLB_TXEN;
break;
}
}
/**
* Disable the given transceiver (RX or TX).
*
* \param[in] module Pointer to USART software instance struct
* \param[in] transceiver_type Transceiver type.
*/
static inline void usart_disable_transceiver(SercomUsart* const hw,
enum usart_transceiver_type transceiver_type)
{
/* Sanity check arguments */
assert(hw);
/* Wait until synchronization is complete */
USART_WAIT_FOR_SYNC(hw);
switch (transceiver_type) {
case USART_TRANSCEIVER_RX:
/* Disable RX */
hw->CTRLB.reg &= ~SERCOM_USART_CTRLB_RXEN;
break;
case USART_TRANSCEIVER_TX:
/* Disable TX */
hw->CTRLB.reg &= ~SERCOM_USART_CTRLB_TXEN;
break;
}
}
enum sercom_status_t usart_init(SercomUsart* const hw,
enum usart_dataorder data_order,
enum usart_transfer_mode transfer_mode,
enum usart_parity parity,
enum usart_stopbits stopbits,
enum usart_character_size character_size,
enum usart_signal_mux_settings mux_setting,
#ifdef FEATURE_USART_OVER_SAMPLE
enum usart_sample_rate sample_rate,
enum usart_sample_adjustment sample_adjustment,
#endif
bool immediate_buffer_overflow_notification,
bool encoding_format_enable,
uint8_t receive_pulse_length,
bool lin_slave_enable,
bool start_frame_detection_enable,
bool collision_detection_enable,
uint32_t baudrate,
bool receiver_enable,
bool transmitter_enable,
bool clock_polarity_inverted,
bool use_external_clock,
uint32_t ext_clock_freq,
bool run_in_standby,
enum gclk_generator generator_source,
uint32_t pinmux_pad0,
uint32_t pinmux_pad1,
uint32_t pinmux_pad2,
uint32_t pinmux_pad3);
enum sercom_status_t usart_write_wait(SercomUsart* const hw,
const uint16_t tx_data);
enum sercom_status_t usart_read_wait(SercomUsart* const hw,
uint16_t *const rx_data);
enum sercom_status_t usart_write_buffer_wait(SercomUsart* const hw,
const uint8_t *tx_data,
uint16_t length);
enum sercom_status_t usart_read_buffer_wait(SercomUsart* const hw,
uint8_t *rx_data,
uint16_t length);
/**
* -------------------------------- Interrupts -------------------------------
*/
/**
* Rx Callback type for usart
*/
typedef void (*usart_rx_callback_t)(SercomUsart* const sercom_instance,
uint16_t data);
void usart_register_rx_callback(SercomUsart* const hw,
usart_rx_callback_t callback,
uint32_t priority);
#endif /* USART_H_INCLUDED */

Wyświetl plik

@ -0,0 +1,844 @@
/**
* SAM D20/D21/R21 Clock Driver
*
* Copyright (C) 2012-2014 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#ifndef SYSTEM_CLOCK_H_INCLUDED
#define SYSTEM_CLOCK_H_INCLUDED
/**
* SAM D20/D21/R21 System Clock Management Driver (SYSTEM CLOCK)
*
* This driver for SAM D20/D21/R21 devices provides an interface for
* the configuration and management of the device's clocking related
* functions. This includes the various clock sources, bus clocks and
* generic clocks within the device, with functions to manage the
* enabling, disabling, source selection and prescaling of clocks to
* various internal peripherals.
*
* The following peripherals are used by this module:
*
* - GCLK (Generic Clock Management)
* - PM (Power Management)
* - SYSCTRL (Clock Source Control)
*
* Module Overview
*
* The SAM D20/D21/R21 devices contain a sophisticated clocking
* system, which is designed to give the maximum flexibility to the
* user application. This system allows a system designer to tune the
* performance and power consumption of the device in a dynamic
* manner, to achieve the best trade-off between the two for a
* particular application.
*
* This driver provides a set of functions for the configuration and
* management of the various clock related functionality within the
* device.
*
* Clock Sources
*
* The SAM D20/D21/R21 devices have a number of master clock source
* modules, each of which being capable of producing a stabilized
* output frequency which can then be fed into the various peripherals
* and modules within the device.
*
* Possible clock source modules include internal R/C oscillators,
* internal DFLL modules, as well as external crystal oscillators
* and/or clock inputs.
*
* CPU / Bus Clocks
*
* The CPU and AHB/APBx buses are clocked by the same physical clock
* source (referred in this module as the Main Clock), however the
* APBx buses may have additional prescaler division ratios set to
* give each peripheral bus a different clock speed.
*
* Clock Masking
*
* To save power, the input clock to one or more peripherals on the AHB and APBx
* buses can be masked away - when masked, no clock is passed into the module.
* Disabling of clocks of unused modules will prevent all access to the masked
* module, but will reduce the overall device power consumption.
*
* Generic Clocks
*
* Within the SAM D20/D21/R21 devices are a number of Generic Clocks;
* these are used to provide clocks to the various peripheral clock
* domains in the device in a standardized manner. One or more master
* source clocks can be selected as the input clock to a Generic Clock
* Generator, which can prescale down the input frequency to a slower
* rate for use in a peripheral.
*
* Additionally, a number of individually selectable Generic Clock
* Channels are provided, which multiplex and gate the various
* generator outputs for one or more peripherals within the
* device. This setup allows for a single common generator to feed one
* or more channels, which can then be enabled or disabled
* individually as required.
*
* Generic Clock Generators
*
* Each Generic Clock generator within the device can source its input clock
* from one of the provided Source Clocks, and prescale the output for one or
* more Generic Clock Channels in a one-to-many relationship. The generators
* thus allow for several clocks to be generated of different frequencies,
* power usages and accuracies, which can be turned on and off individually to
* disable the clocks to multiple peripherals as a group.
*
* Generic Clock Channels
*
* To connect a Generic Clock Generator to a peripheral within the
* device, a Generic Clock Channel is used. Each peripheral or
* peripheral group has an associated Generic Clock Channel, which serves as the
* clock input for the peripheral(s). To supply a clock to the peripheral
* module(s), the associated channel must be connected to a running Generic
* Clock Generator and the channel enabled.
*
*/
#include <assert.h>
#include "samd20.h"
#include "system/gclk.h"
/**
* Define system clock features set according to different device family.
*/
#if (SAMD21) || (SAMR21)
/** Digital Phase Locked Loop (DPLL) feature support */
# define FEATURE_SYSTEM_CLOCK_DPLL
#endif
/**
* Clock status type
*/
enum clock_status_t {
CLOCK_STATUS_OK = 0,
CLOCK_STATUS_INVALID_ARG,
};
/**
* Available external 32KHz oscillator start-up times, as a number of external
* clock cycles.
*/
enum system_xosc32k_startup {
/** Wait 0 clock cycles until the clock source is considered stable */
SYSTEM_XOSC32K_STARTUP_0,
/** Wait 32 clock cycles until the clock source is considered stable */
SYSTEM_XOSC32K_STARTUP_32,
/** Wait 2048 clock cycles until the clock source is considered stable */
SYSTEM_XOSC32K_STARTUP_2048,
/** Wait 4096 clock cycles until the clock source is considered stable */
SYSTEM_XOSC32K_STARTUP_4096,
/** Wait 16384 clock cycles until the clock source is considered stable */
SYSTEM_XOSC32K_STARTUP_16384,
/** Wait 32768 clock cycles until the clock source is considered stable */
SYSTEM_XOSC32K_STARTUP_32768,
/** Wait 65536 clock cycles until the clock source is considered stable */
SYSTEM_XOSC32K_STARTUP_65536,
/** Wait 131072 clock cycles until the clock source is considered stable */
SYSTEM_XOSC32K_STARTUP_131072,
};
/**
* Available external oscillator start-up times, as a number of external clock
* cycles.
*/
enum system_xosc_startup {
/** Wait 1 clock cycles until the clock source is considered stable */
SYSTEM_XOSC_STARTUP_1,
/** Wait 2 clock cycles until the clock source is considered stable */
SYSTEM_XOSC_STARTUP_2,
/** Wait 4 clock cycles until the clock source is considered stable */
SYSTEM_XOSC_STARTUP_4,
/** Wait 8 clock cycles until the clock source is considered stable */
SYSTEM_XOSC_STARTUP_8,
/** Wait 16 clock cycles until the clock source is considered stable */
SYSTEM_XOSC_STARTUP_16,
/** Wait 32 clock cycles until the clock source is considered stable */
SYSTEM_XOSC_STARTUP_32,
/** Wait 64 clock cycles until the clock source is considered stable */
SYSTEM_XOSC_STARTUP_64,
/** Wait 128 clock cycles until the clock source is considered stable */
SYSTEM_XOSC_STARTUP_128,
/** Wait 256 clock cycles until the clock source is considered stable */
SYSTEM_XOSC_STARTUP_256,
/** Wait 512 clock cycles until the clock source is considered stable */
SYSTEM_XOSC_STARTUP_512,
/** Wait 1024 clock cycles until the clock source is considered stable */
SYSTEM_XOSC_STARTUP_1024,
/** Wait 2048 clock cycles until the clock source is considered stable */
SYSTEM_XOSC_STARTUP_2048,
/** Wait 4096 clock cycles until the clock source is considered stable */
SYSTEM_XOSC_STARTUP_4096,
/** Wait 8192 clock cycles until the clock source is considered stable */
SYSTEM_XOSC_STARTUP_8192,
/** Wait 16384 clock cycles until the clock source is considered stable */
SYSTEM_XOSC_STARTUP_16384,
/** Wait 32768 clock cycles until the clock source is considered stable */
SYSTEM_XOSC_STARTUP_32768,
};
/**
* Available internal 32KHz oscillator start-up times, as a number of internal
* OSC32K clock cycles.
*/
enum system_osc32k_startup {
/** Wait 3 clock cycles until the clock source is considered stable */
SYSTEM_OSC32K_STARTUP_3,
/** Wait 4 clock cycles until the clock source is considered stable */
SYSTEM_OSC32K_STARTUP_4,
/** Wait 6 clock cycles until the clock source is considered stable */
SYSTEM_OSC32K_STARTUP_6,
/** Wait 10 clock cycles until the clock source is considered stable */
SYSTEM_OSC32K_STARTUP_10,
/** Wait 18 clock cycles until the clock source is considered stable */
SYSTEM_OSC32K_STARTUP_18,
/** Wait 34 clock cycles until the clock source is considered stable */
SYSTEM_OSC32K_STARTUP_34,
/** Wait 66 clock cycles until the clock source is considered stable */
SYSTEM_OSC32K_STARTUP_66,
/** Wait 130 clock cycles until the clock source is considered stable */
SYSTEM_OSC32K_STARTUP_130,
};
/**
* Available prescalers for the internal 8MHz (nominal) system clock.
*/
enum system_osc8m_div {
/** Do not divide the 8MHz RC oscillator output */
SYSTEM_OSC8M_DIV_1,
/** Divide the 8MHz RC oscillator output by 2 */
SYSTEM_OSC8M_DIV_2,
/** Divide the 8MHz RC oscillator output by 4 */
SYSTEM_OSC8M_DIV_4,
/** Divide the 8MHz RC oscillator output by 8 */
SYSTEM_OSC8M_DIV_8,
};
/**
* Internal 8Mhz RC oscillator frequency range setting
*/
enum system_osc8m_frequency_range {
/** Frequency range 4 Mhz to 6 Mhz */
SYSTEM_OSC8M_FREQUENCY_RANGE_4_TO_6,
/** Frequency range 6 Mhz to 8 Mhz */
SYSTEM_OSC8M_FREQUENCY_RANGE_6_TO_8,
/** Frequency range 8 Mhz to 11 Mhz */
SYSTEM_OSC8M_FREQUENCY_RANGE_8_TO_11,
/** Frequency range 11 Mhz to 15 Mhz */
SYSTEM_OSC8M_FREQUENCY_RANGE_11_TO_15,
};
/**
* Available division ratios for the CPU and APB/AHB bus clocks.
*/
enum system_main_clock_div {
/** Divide Main clock by 1 */
SYSTEM_MAIN_CLOCK_DIV_1,
/** Divide Main clock by 2 */
SYSTEM_MAIN_CLOCK_DIV_2,
/** Divide Main clock by 4 */
SYSTEM_MAIN_CLOCK_DIV_4,
/** Divide Main clock by 8 */
SYSTEM_MAIN_CLOCK_DIV_8,
/** Divide Main clock by 16 */
SYSTEM_MAIN_CLOCK_DIV_16,
/** Divide Main clock by 32 */
SYSTEM_MAIN_CLOCK_DIV_32,
/** Divide Main clock by 64 */
SYSTEM_MAIN_CLOCK_DIV_64,
/** Divide Main clock by 128 */
SYSTEM_MAIN_CLOCK_DIV_128,
};
/**
* Available external clock source types.
*/
enum system_clock_external {
/** The external clock source is a crystal oscillator */
SYSTEM_CLOCK_EXTERNAL_CRYSTAL,
/** The connected clock source is an external logic level clock signal */
SYSTEM_CLOCK_EXTERNAL_CLOCK,
};
/**
* Available operating modes of the DFLL clock source module,
*/
enum system_clock_dfll_loop_mode {
/** The DFLL is operating in open loop mode with no feedback */
SYSTEM_CLOCK_DFLL_LOOP_MODE_OPEN,
/** The DFLL is operating in closed loop mode with frequency feedback from
* a low frequency reference clock
*/
SYSTEM_CLOCK_DFLL_LOOP_MODE_CLOSED = SYSCTRL_DFLLCTRL_MODE,
/** The DFLL is operating in USB recovery mode with frequency feedback
* from USB SOF
*/
};
/**
* DFLL lock behavior modes on device wake-up from sleep.
*/
enum system_clock_dfll_wakeup_lock {
/** Keep DFLL lock when the device wakes from sleep */
SYSTEM_CLOCK_DFLL_WAKEUP_LOCK_KEEP,
/** Lose DFLL lock when the devices wakes from sleep */
SYSTEM_CLOCK_DFLL_WAKEUP_LOCK_LOSE = SYSCTRL_DFLLCTRL_LLAW,
};
/**
* DFLL fine tracking behavior modes after a lock has been acquired.
*/
enum system_clock_dfll_stable_tracking {
/** Keep tracking after the DFLL has gotten a fine lock */
SYSTEM_CLOCK_DFLL_STABLE_TRACKING_TRACK_AFTER_LOCK,
/** Stop tracking after the DFLL has gotten a fine lock */
SYSTEM_CLOCK_DFLL_STABLE_TRACKING_FIX_AFTER_LOCK = SYSCTRL_DFLLCTRL_STABLE,
};
/**
* DFLL chill-cycle behavior modes of the DFLL module. A chill cycle is a period
* of time when the DFLL output frequency is not measured by the unit, to allow
* the output to stabilize after a change in the input clock source.
*/
enum system_clock_dfll_chill_cycle {
/** Enable a chill cycle, where the DFLL output frequency is not measured */
SYSTEM_CLOCK_DFLL_CHILL_CYCLE_ENABLE,
/** Disable a chill cycle, where the DFLL output frequency is not measured */
SYSTEM_CLOCK_DFLL_CHILL_CYCLE_DISABLE = SYSCTRL_DFLLCTRL_CCDIS,
};
/**
* DFLL QuickLock settings for the DFLL module, to allow for a faster lock of
* the DFLL output frequency at the expense of accuracy.
*/
enum system_clock_dfll_quick_lock {
/** Enable the QuickLock feature for looser lock requirements on the DFLL */
SYSTEM_CLOCK_DFLL_QUICK_LOCK_ENABLE,
/** Disable the QuickLock feature for strict lock requirements on the DFLL */
SYSTEM_CLOCK_DFLL_QUICK_LOCK_DISABLE = SYSCTRL_DFLLCTRL_QLDIS,
};
/**
* Clock sources available to the GCLK generators
*/
enum system_clock_source {
/** Internal 8MHz RC oscillator */
SYSTEM_CLOCK_SOURCE_OSC8M = GCLK_SOURCE_OSC8M,
/** Internal 32kHz RC oscillator */
SYSTEM_CLOCK_SOURCE_OSC32K = GCLK_SOURCE_OSC32K,
/** External oscillator */
SYSTEM_CLOCK_SOURCE_XOSC = GCLK_SOURCE_XOSC ,
/** External 32kHz oscillator */
SYSTEM_CLOCK_SOURCE_XOSC32K = GCLK_SOURCE_XOSC32K,
/** Digital Frequency Locked Loop (DFLL) */
SYSTEM_CLOCK_SOURCE_DFLL = GCLK_SOURCE_DFLL48M,
/** Internal Ultra Low Power 32kHz oscillator */
SYSTEM_CLOCK_SOURCE_ULP32K = GCLK_SOURCE_OSCULP32K,
/** Generator input pad */
SYSTEM_CLOCK_SOURCE_GCLKIN = GCLK_SOURCE_GCLKIN,
/** Generic clock generator 1 output */
SYSTEM_CLOCK_SOURCE_GCLKGEN1 = GCLK_SOURCE_GCLKGEN1,
#ifdef FEATURE_SYSTEM_CLOCK_DPLL
/** Digital Phase Locked Loop (DPLL). */
SYSTEM_CLOCK_SOURCE_DPLL = GCLK_SOURCE_FDPLL,
#endif
};
/**
* Available bus clock domains on the APB bus.
*/
enum system_clock_apb_bus {
/** Peripheral bus A on the APB bus. */
SYSTEM_CLOCK_APB_APBA,
/** Peripheral bus B on the APB bus. */
SYSTEM_CLOCK_APB_APBB,
/** Peripheral bus C on the APB bus. */
SYSTEM_CLOCK_APB_APBC,
};
void system_clock_source_osc8m_set_config(enum system_osc8m_div prescaler,
bool run_in_standby,
bool on_demand);
void system_clock_source_osc8m_set_config_default(void);
void system_clock_source_osc32k_set_config(enum system_osc32k_startup startup_time,
bool enable_1khz_output,
bool enable_32khz_output,
bool run_in_standby,
bool on_demand,
bool write_once);
void system_clock_source_osc32k_set_config_default(void);
void system_clock_source_xosc_set_config(enum system_clock_external external_clock,
enum system_xosc_startup startup_time,
bool auto_gain_control,
uint32_t frequency,
bool run_in_standby,
bool on_demand);
void system_clock_source_xosc_set_config_default(void);
void system_clock_source_xosc32k_set_config(enum system_clock_external external_clock,
enum system_xosc32k_startup startup_time,
bool auto_gain_control,
bool enable_1khz_output,
bool enable_32khz_output,
bool run_in_standby,
bool on_demand,
bool write_once);
void system_clock_source_xosc32k_set_config_default(void);
void system_clock_source_dfll_set_config(
enum system_clock_dfll_loop_mode loop_mode,
bool on_demand,
enum system_clock_dfll_quick_lock quick_lock,
enum system_clock_dfll_chill_cycle chill_cycle,
enum system_clock_dfll_wakeup_lock wakeup_lock,
enum system_clock_dfll_stable_tracking stable_tracking,
uint8_t coarse_value,
uint16_t fine_value,
uint8_t coarse_max_step,
uint16_t fine_max_step,
uint16_t multiply_factor);
void system_clock_source_dfll_set_config_default(void);
enum clock_status_t system_clock_source_write_calibration(
const enum system_clock_source system_clock_source,
const uint16_t calibration_value,
const uint8_t freq_range);
enum clock_status_t system_clock_source_enable(
const enum system_clock_source system_clock_source);
enum clock_status_t system_clock_source_disable(
const enum system_clock_source clk_source);
bool system_clock_source_is_ready(
const enum system_clock_source clk_source);
uint32_t system_clock_source_get_hz(
const enum system_clock_source clk_source);
/**
* Enable or disable the main clock failure detection.
*
* This mechanism allows switching automatically the main clock to the safe
* RCSYS clock, when the main clock source is considered off.
*
* This may happen for instance when an external crystal is selected as the
* clock source of the main clock and the crystal dies. The mechanism is to
* detect, during a RCSYS period, at least one rising edge of the main clock.
* If no rising edge is seen the clock is considered failed.
* As soon as the detector is enabled, the clock failure detector
* CFD) will monitor the divided main clock. When a clock failure is detected,
* the main clock automatically switches to the RCSYS clock and the CFD
* interrupt is generated if enabled.
*
* \note The failure detect must be disabled if the system clock is the same or
* slower than 32kHz as it will believe the system clock has failed with
* a too-slow clock.
*
* \param[in] enable Boolean \c true to enable, \c false to disable detection
*/
static inline void system_main_clock_set_failure_detect(const bool enable)
{
if (enable) {
// PM->CTRL.reg |= PM_CTRL_CFDEN;
} else {
// PM->CTRL.reg &= ~PM_CTRL_CFDEN;
}
}
/**
* Sets the clock divider used on the main clock to provide the CPU clock.
*
* \param[in] divider CPU clock divider to set
*/
static inline void system_cpu_clock_set_divider(
const enum system_main_clock_div divider)
{
assert(((uint32_t)divider & PM_CPUSEL_CPUDIV_Msk) == divider);
PM->CPUSEL.reg = (uint32_t)divider;
}
/**
* Retrieves the operating frequency of the CPU core, obtained from the main
* generic clock and the set CPU bus divider.
*
* \return Current CPU frequency in Hz.
*/
static inline uint32_t system_cpu_clock_get_hz(void)
{
return (system_gclk_gen_get_hz(GCLK_GENERATOR_0) >> PM->CPUSEL.reg);
}
/**
* Set APBx clock divider.
*
* Set the clock divider used on the main clock to provide the clock for the
* given APBx bus.
*
* \param[in] divider APBx bus divider to set
* \param[in] bus APBx bus to set divider for
*
* \returns Status of the clock division change operation.
*
* \retval STATUS_ERR_INVALID_ARG Invalid bus ID was given
* \retval STATUS_OK The APBx clock was set successfully
*/
static inline enum clock_status_t system_apb_clock_set_divider(
const enum system_clock_apb_bus bus,
const enum system_main_clock_div divider)
{
switch (bus) {
case SYSTEM_CLOCK_APB_APBA:
PM->APBASEL.reg = (uint32_t)divider;
break;
case SYSTEM_CLOCK_APB_APBB:
PM->APBBSEL.reg = (uint32_t)divider;
break;
case SYSTEM_CLOCK_APB_APBC:
PM->APBCSEL.reg = (uint32_t)divider;
break;
default:
assert(false);
return CLOCK_STATUS_INVALID_ARG;
}
return CLOCK_STATUS_OK;
}
/**
* Retrieves the operating frequency of an APBx bus, obtained from the main
* generic clock and the set APBx bus divider.
*
* \return Current APBx bus frequency in Hz.
*/
static inline uint32_t system_apb_clock_get_hz(
const enum system_clock_apb_bus bus)
{
uint16_t bus_divider = 0;
switch (bus) {
case SYSTEM_CLOCK_APB_APBA:
bus_divider = PM->APBASEL.reg;
break;
case SYSTEM_CLOCK_APB_APBB:
bus_divider = PM->APBBSEL.reg;
break;
case SYSTEM_CLOCK_APB_APBC:
bus_divider = PM->APBCSEL.reg;
break;
default:
assert(false);
return 0;
}
return (system_gclk_gen_get_hz(GCLK_GENERATOR_0) >> bus_divider);
}
/**
* Set bits in the clock mask for the AHB bus.
*
* This function will set bits in the clock mask for the AHB bus.
* Any bits set to 1 will enable that clock, 0 bits in the mask
* will be ignored
*
* \param[in] ahb_mask AHB clock mask to enable
*/
static inline void system_ahb_clock_set_mask(const uint32_t ahb_mask)
{
PM->AHBMASK.reg |= ahb_mask;
}
/**
* Clear bits in the clock mask for the AHB bus.
*
* This function will clear bits in the clock mask for the AHB bus.
* Any bits set to 1 will disable that clock, 0 bits in the mask
* will be ignored.
*
* \param[in] ahb_mask AHB clock mask to disable
*/
static inline void system_ahb_clock_clear_mask(const uint32_t ahb_mask)
{
PM->AHBMASK.reg &= ~ahb_mask;
}
/**
* Set bits in the clock mask for an APBx bus.
*
* This function will set bits in the clock mask for an APBx bus.
* Any bits set to 1 will enable the corresponding module clock, zero bits in
* the mask will be ignored.
*
* \param[in] mask APBx clock mask, a \c SYSTEM_CLOCK_APB_APBx constant from
* the device header files
* \param[in] bus Bus to set clock mask bits for, a mask of \c PM_APBxMASK_*
* constants from the device header files
*
* \returns Status indicating the result of the clock mask change operation.
*
* \retval STATUS_ERR_INVALID_ARG Invalid bus given
* \retval STATUS_OK The clock mask was set successfully
*/
static inline enum clock_status_t system_apb_clock_set_mask(
const enum system_clock_apb_bus bus,
const uint32_t mask)
{
switch (bus) {
case SYSTEM_CLOCK_APB_APBA:
PM->APBAMASK.reg |= mask;
break;
case SYSTEM_CLOCK_APB_APBB:
PM->APBBMASK.reg |= mask;
break;
case SYSTEM_CLOCK_APB_APBC:
PM->APBCMASK.reg |= mask;
break;
default:
assert(false);
return CLOCK_STATUS_INVALID_ARG;
}
return CLOCK_STATUS_OK;
}
/**
* Clear bits in the clock mask for an APBx bus.
*
* This function will clear bits in the clock mask for an APBx bus.
* Any bits set to 1 will disable the corresponding module clock, zero bits in
* the mask will be ignored.
*
* \param[in] mask APBx clock mask, a \c SYSTEM_CLOCK_APB_APBx constant from
* the device header files
* \param[in] bus Bus to clear clock mask bits for
*
* \returns Status indicating the result of the clock mask change operation.
*
* \retval STATUS_ERR_INVALID_ARG Invalid bus ID was given.
* \retval STATUS_OK The clock mask was changed successfully.
*/
static inline enum clock_status_t system_apb_clock_clear_mask(
const enum system_clock_apb_bus bus,
const uint32_t mask)
{
switch (bus) {
case SYSTEM_CLOCK_APB_APBA:
PM->APBAMASK.reg &= ~mask;
break;
case SYSTEM_CLOCK_APB_APBB:
PM->APBBMASK.reg &= ~mask;
break;
case SYSTEM_CLOCK_APB_APBC:
PM->APBCMASK.reg &= ~mask;
break;
default:
assert(false);
return CLOCK_STATUS_INVALID_ARG;
}
return CLOCK_STATUS_OK;
}
#ifdef FEATURE_SYSTEM_CLOCK_DPLL
/**
* Reference clock source of the DPLL module
*/
enum system_clock_source_dpll_reference_clock {
/** Select CLK_DPLL_REF0 as clock reference */
SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_REF0,
/** Select CLK_DPLL_REF1 as clock reference */
SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_REF1,
/** Select GCLK_DPLL as clock reference */
SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_GCLK,
};
/**
* Lock time-out value of the DPLL module
*/
enum system_clock_source_dpll_lock_time {
/** Set no time-out as default */
SYSTEM_CLOCK_SOURCE_DPLL_LOCK_TIME_DEFAULT,
/** Set time-out if no lock within 8 ms */
SYSTEM_CLOCK_SOURCE_DPLL_LOCK_TIME_8MS = 0x04,
/** Set time-out if no lock within 9 ms */
SYSTEM_CLOCK_SOURCE_DPLL_LOCK_TIME_9MS,
/** Set time-out if no lock within 10 ms */
SYSTEM_CLOCK_SOURCE_DPLL_LOCK_TIME_10MS,
/** Set time-out if no lock within 11 ms */
SYSTEM_CLOCK_SOURCE_DPLL_LOCK_TIME_11MS,
};
/**
* Filter type of the DPLL module
*/
enum system_clock_source_dpll_filter {
/** Default filter mode */
SYSTEM_CLOCK_SOURCE_DPLL_FILTER_DEFAULT,
/** Low bandwidth filter */
SYSTEM_CLOCK_SOURCE_DPLL_FILTER_LOW_BANDWIDTH_FILTER,
/** High bandwidth filter */
SYSTEM_CLOCK_SOURCE_DPLL_FILTER_HIGH_BANDWIDTH_FILTER,
/** High damping filter */
SYSTEM_CLOCK_SOURCE_DPLL_FILTER_HIGH_DAMPING_FILTER,
};
/**
* Configuration structure for DPLL
*
* DPLL oscillator configuration structure.
*/
struct system_clock_source_dpll_config {
/** Run On Demand. If this is set the DPLL won't run
* until requested by a peripheral */
bool on_demand;
/** Keep the DPLL enabled in standby sleep mode */
bool run_in_standby;
/** Bypass lock signal */
bool lock_bypass;
/** Wake up fast. If this is set DPLL output clock is enabled after
* the startup time */
bool wake_up_fast;
/** Enable low power mode */
bool low_power_enable;
/** Output frequency of the clock */
uint32_t output_frequency;
/** Reference frequency of the clock */
uint32_t reference_frequency;
/** Devider of reference clock */
uint16_t reference_divider;
/** Filter type of the DPLL module */
enum system_clock_source_dpll_filter filter;
/** Lock time-out value of the DPLL module */
enum system_clock_source_dpll_lock_time lock_time;
/** Reference clock source of the DPLL module */
enum system_clock_source_dpll_reference_clock reference_clock;
};
/**
* \brief Retrieve the default configuration for DPLL
*
* Fills a configuration structure with the default configuration for a
* DPLL oscillator module:
* - Run only when requested by peripheral (on demand)
* - Don't run in STANDBY sleep mode
* - Lock bypass disabled
* - Fast wake up disabled
* - Low power mode disabled
* - Output frequency is 48MHz
* - Reference clock frequency is 32768Hz
* - Not divide reference clock
* - Select REF0 as reference clock
* - Set lock time to default mode
* - Use default filter
*
* \param[out] config Configuration structure to fill with default values
*/
static inline void system_clock_source_dpll_get_config_defaults(
struct system_clock_source_dpll_config *const config)
{
config->on_demand = true;
config->run_in_standby = false;
config->lock_bypass = false;
config->wake_up_fast = false;
config->low_power_enable = false;
config->output_frequency = 48000000;
config->reference_frequency = 32768;
config->reference_divider = 1;
config->reference_clock = SYSTEM_CLOCK_SOURCE_DPLL_REFERENCE_CLOCK_REF0;
config->lock_time = SYSTEM_CLOCK_SOURCE_DPLL_LOCK_TIME_DEFAULT;
config->filter = SYSTEM_CLOCK_SOURCE_DPLL_FILTER_DEFAULT;
};
void system_clock_source_dpll_set_config(
struct system_clock_source_dpll_config *const config);
#endif
void system_clock_init(void);
/**
* Set flash controller wait states
*
* Will set the number of wait states that are used by the onboard
* flash memory. The number of wait states depend on both device
* supply voltage and CPU speed. The required number of wait states
* can be found in the electrical characteristics of the device.
*
* \param[in] wait_states Number of wait states to use for internal flash
*/
static inline void system_flash_set_waitstates(uint8_t wait_states)
{
assert(NVMCTRL_CTRLB_RWS((uint32_t)wait_states) ==
((uint32_t)wait_states << NVMCTRL_CTRLB_RWS_Pos));
NVMCTRL->CTRLB.bit.RWS = wait_states;
}
/**
* - This driver implements workaround for errata 10558
*
* "Several reset values of SYSCTRL.INTFLAG are wrong (BOD and DFLL)"
* When system_init is called it will reset these interrupts flags before they are used.
*
* - This driver implements experimental workaround for errata 9905
*
* "The DFLL clock must be requested before being configured otherwise a
* write access to a DFLL register can freeze the device."
* This driver will enable and configure the DFLL before the ONDEMAND bit is set.
*
*/
#endif /* SYSTEM_CLOCK_H_INCLUDED */

Wyświetl plik

@ -0,0 +1,373 @@
/**
* SAM D20 Clock Driver
*
* Copyright (C) 2012-2014 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#ifndef CLOCK_CONFIG_CHECK_H
#define CLOCK_CONFIG_CHECK_H
#if !defined(CONF_CLOCK_FLASH_WAIT_STATES)
# error CONF_CLOCK_FLASH_WAIT_STATES not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_CPU_DIVIDER)
# error CONF_CLOCK_CPU_DIVIDER not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_APBA_DIVIDER)
# error CONF_CLOCK_APBA_DIVIDER not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_APBB_DIVIDER)
# error CONF_CLOCK_APBB_DIVIDER not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_OSC8M_PRESCALER)
# error CONF_CLOCK_OSC8M_PRESCALER not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_OSC8M_ON_DEMAND)
# error CONF_CLOCK_OSC8M_ON_DEMAND not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_OSC8M_RUN_IN_STANDBY)
# error CONF_CLOCK_OSC8M_RUN_IN_STANDBY not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_XOSC_ENABLE)
# error CONF_CLOCK_XOSC_ENABLE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_XOSC_EXTERNAL_CRYSTAL)
# error CONF_CLOCK_XOSC_EXTERNAL_CRYSTAL not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_XOSC_EXTERNAL_FREQUENCY)
# error CONF_CLOCK_XOSC_EXTERNAL_FREQUENCY not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_XOSC_STARTUP_TIME)
# error CONF_CLOCK_XOSC_STARTUP_TIME not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_XOSC_AUTO_GAIN_CONTROL)
# error CONF_CLOCK_XOSC_AUTO_GAIN_CONTROL not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_XOSC_ON_DEMAND)
# error CONF_CLOCK_XOSC_ON_DEMAND not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_XOSC_RUN_IN_STANDBY)
# error CONF_CLOCK_XOSC_RUN_IN_STANDBY not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_XOSC32K_ENABLE)
# error CONF_CLOCK_XOSC32K_ENABLE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_XOSC32K_EXTERNAL_CRYSTAL)
# error CONF_CLOCK_XOSC32K_EXTERNAL_CRYSTAL not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_XOSC32K_STARTUP_TIME)
# error CONF_CLOCK_XOSC32K_STARTUP_TIME not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_XOSC32K_AUTO_AMPLITUDE_CONTROL)
# error CONF_CLOCK_XOSC32K_AUTO_AMPLITUDE_CONTROL not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_XOSC32K_ENABLE_1KHZ_OUPUT)
# error CONF_CLOCK_XOSC32K_ENABLE_1KHZ_OUPUT not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_XOSC32K_ENABLE_32KHZ_OUTPUT)
# error CONF_CLOCK_XOSC32K_ENABLE_32KHZ_OUTPUT not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_XOSC32K_ON_DEMAND)
# error CONF_CLOCK_XOSC32K_ON_DEMAND not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_XOSC32K_RUN_IN_STANDBY)
# error CONF_CLOCK_XOSC32K_RUN_IN_STANDBY not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_OSC32K_ENABLE)
# error CONF_CLOCK_OSC32K_ENABLE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_OSC32K_STARTUP_TIME)
# error CONF_CLOCK_OSC32K_STARTUP_TIME not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_OSC32K_ENABLE_1KHZ_OUTPUT)
# error CONF_CLOCK_OSC32K_ENABLE_1KHZ_OUTPUT not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_OSC32K_ENABLE_32KHZ_OUTPUT)
# error CONF_CLOCK_OSC32K_ENABLE_32KHZ_OUTPUT not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_OSC32K_ON_DEMAND)
# error CONF_CLOCK_OSC32K_ON_DEMAND not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_OSC32K_RUN_IN_STANDBY)
# error CONF_CLOCK_OSC32K_RUN_IN_STANDBY not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_DFLL_ENABLE)
# error CONF_CLOCK_DFLL_ENABLE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_DFLL_LOOP_MODE)
# error CONF_CLOCK_DFLL_LOOP_MODE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_DFLL_ON_DEMAND)
# error CONF_CLOCK_DFLL_ON_DEMAND not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_DFLL_COARSE_VALUE)
# error CONF_CLOCK_DFLL_COARSE_VALUE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_DFLL_FINE_VALUE)
# error CONF_CLOCK_DFLL_FINE_VALUE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_DFLL_SOURCE_GCLK_GENERATOR)
# error CONF_CLOCK_DFLL_SOURCE_GCLK_GENERATOR not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_DFLL_MULTIPLY_FACTOR)
# error CONF_CLOCK_DFLL_MULTIPLY_FACTOR not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_DFLL_QUICK_LOCK)
# error CONF_CLOCK_DFLL_QUICK_LOCK not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_DFLL_TRACK_AFTER_FINE_LOCK)
# error CONF_CLOCK_DFLL_TRACK_AFTER_FINE_LOCK not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_DFLL_KEEP_LOCK_ON_WAKEUP)
# error CONF_CLOCK_DFLL_KEEP_LOCK_ON_WAKEUP not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_DFLL_ENABLE_CHILL_CYCLE)
# error CONF_CLOCK_DFLL_ENABLE_CHILL_CYCLE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_DFLL_MAX_COARSE_STEP_SIZE)
# error CONF_CLOCK_DFLL_MAX_COARSE_STEP_SIZE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_DFLL_MAX_FINE_STEP_SIZE)
# error CONF_CLOCK_DFLL_MAX_FINE_STEP_SIZE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_CONFIGURE_GCLK)
# error CONF_CLOCK_CONFIGURE_GCLK not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_0_ENABLE)
# error CONF_CLOCK_GCLK_0_ENABLE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_0_RUN_IN_STANDBY)
# error CONF_CLOCK_GCLK_0_RUN_IN_STANDBY not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_0_CLOCK_SOURCE)
# error CONF_CLOCK_GCLK_0_CLOCK_SOURCE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_0_PRESCALER)
# error CONF_CLOCK_GCLK_0_PRESCALER not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_0_OUTPUT_ENABLE)
# error CONF_CLOCK_GCLK_0_OUTPUT_ENABLE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_1_ENABLE)
# error CONF_CLOCK_GCLK_1_ENABLE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_1_RUN_IN_STANDBY)
# error CONF_CLOCK_GCLK_1_RUN_IN_STANDBY not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_1_CLOCK_SOURCE)
# error CONF_CLOCK_GCLK_1_CLOCK_SOURCE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_1_PRESCALER)
# error CONF_CLOCK_GCLK_1_PRESCALER not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_1_OUTPUT_ENABLE)
# error CONF_CLOCK_GCLK_1_OUTPUT_ENABLE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_2_ENABLE)
# error CONF_CLOCK_GCLK_2_ENABLE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_2_RUN_IN_STANDBY)
# error CONF_CLOCK_GCLK_2_RUN_IN_STANDBY not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_2_CLOCK_SOURCE)
# error CONF_CLOCK_GCLK_2_CLOCK_SOURCE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_2_PRESCALER)
# error CONF_CLOCK_GCLK_2_PRESCALER not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_2_OUTPUT_ENABLE)
# error CONF_CLOCK_GCLK_2_OUTPUT_ENABLE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_3_ENABLE)
# error CONF_CLOCK_GCLK_3_ENABLE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_3_RUN_IN_STANDBY)
# error CONF_CLOCK_GCLK_3_RUN_IN_STANDBY not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_3_CLOCK_SOURCE)
# error CONF_CLOCK_GCLK_3_CLOCK_SOURCE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_3_PRESCALER)
# error CONF_CLOCK_GCLK_3_PRESCALER not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_3_OUTPUT_ENABLE)
# error CONF_CLOCK_GCLK_3_OUTPUT_ENABLE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_4_ENABLE)
# error CONF_CLOCK_GCLK_4_ENABLE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_4_RUN_IN_STANDBY)
# error CONF_CLOCK_GCLK_4_RUN_IN_STANDBY not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_4_CLOCK_SOURCE)
# error CONF_CLOCK_GCLK_4_CLOCK_SOURCE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_4_PRESCALER)
# error CONF_CLOCK_GCLK_4_PRESCALER not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_4_OUTPUT_ENABLE)
# error CONF_CLOCK_GCLK_4_OUTPUT_ENABLE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_5_ENABLE)
# error CONF_CLOCK_GCLK_5_ENABLE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_5_RUN_IN_STANDBY)
# error CONF_CLOCK_GCLK_5_RUN_IN_STANDBY not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_5_CLOCK_SOURCE)
# error CONF_CLOCK_GCLK_5_CLOCK_SOURCE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_5_PRESCALER)
# error CONF_CLOCK_GCLK_5_PRESCALER not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_5_OUTPUT_ENABLE)
# error CONF_CLOCK_GCLK_5_OUTPUT_ENABLE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_6_ENABLE)
# error CONF_CLOCK_GCLK_6_ENABLE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_6_RUN_IN_STANDBY)
# error CONF_CLOCK_GCLK_6_RUN_IN_STANDBY not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_6_CLOCK_SOURCE)
# error CONF_CLOCK_GCLK_6_CLOCK_SOURCE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_6_PRESCALER)
# error CONF_CLOCK_GCLK_6_PRESCALER not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_6_OUTPUT_ENABLE)
# error CONF_CLOCK_GCLK_6_OUTPUT_ENABLE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_7_ENABLE)
# error CONF_CLOCK_GCLK_7_ENABLE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_7_RUN_IN_STANDBY)
# error CONF_CLOCK_GCLK_7_RUN_IN_STANDBY not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_7_CLOCK_SOURCE)
# error CONF_CLOCK_GCLK_7_CLOCK_SOURCE not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_7_PRESCALER)
# error CONF_CLOCK_GCLK_7_PRESCALER not defined in conf_clock.h
#endif
#if !defined(CONF_CLOCK_GCLK_7_OUTPUT_ENABLE)
# error CONF_CLOCK_GCLK_7_OUTPUT_ENABLE not defined in conf_clock.h
#endif
#endif /* CLOCK_CONFIG_CHECK_H */

Wyświetl plik

@ -0,0 +1,164 @@
/**
* SAM D20 Clock configuration
*
* Copyright (C) 2012-2014 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#include <system/clock.h>
#ifndef CONF_CLOCKS_H_INCLUDED
#define CONF_CLOCKS_H_INCLUDED
/* System clock bus configuration */
# define CONF_CLOCK_FLASH_WAIT_STATES 0
# define CONF_CLOCK_CPU_DIVIDER SYSTEM_MAIN_CLOCK_DIV_1
# define CONF_CLOCK_APBA_DIVIDER SYSTEM_MAIN_CLOCK_DIV_1
# define CONF_CLOCK_APBB_DIVIDER SYSTEM_MAIN_CLOCK_DIV_1
/* SYSTEM_CLOCK_SOURCE_OSC8M configuration - Internal 8MHz oscillator */
# define CONF_CLOCK_OSC8M_PRESCALER SYSTEM_OSC8M_DIV_1
# define CONF_CLOCK_OSC8M_ON_DEMAND true
# define CONF_CLOCK_OSC8M_RUN_IN_STANDBY false
/* SYSTEM_CLOCK_SOURCE_XOSC configuration - External clock/oscillator */
# define CONF_CLOCK_XOSC_ENABLE false
# define CONF_CLOCK_XOSC_EXTERNAL_CRYSTAL SYSTEM_CLOCK_EXTERNAL_CRYSTAL
# define CONF_CLOCK_XOSC_EXTERNAL_FREQUENCY 12000000UL
# define CONF_CLOCK_XOSC_STARTUP_TIME SYSTEM_XOSC_STARTUP_32768
# define CONF_CLOCK_XOSC_AUTO_GAIN_CONTROL true
# define CONF_CLOCK_XOSC_ON_DEMAND true
# define CONF_CLOCK_XOSC_RUN_IN_STANDBY false
/* SYSTEM_CLOCK_SOURCE_XOSC32K configuration - External 32KHz crystal/clock oscillator */
# define CONF_CLOCK_XOSC32K_ENABLE false
# define CONF_CLOCK_XOSC32K_EXTERNAL_CRYSTAL SYSTEM_CLOCK_EXTERNAL_CRYSTAL
# define CONF_CLOCK_XOSC32K_STARTUP_TIME SYSTEM_XOSC32K_STARTUP_65536
# define CONF_CLOCK_XOSC32K_AUTO_AMPLITUDE_CONTROL false
# define CONF_CLOCK_XOSC32K_ENABLE_1KHZ_OUPUT false
# define CONF_CLOCK_XOSC32K_ENABLE_32KHZ_OUTPUT true
# define CONF_CLOCK_XOSC32K_ON_DEMAND true
# define CONF_CLOCK_XOSC32K_RUN_IN_STANDBY false
/* SYSTEM_CLOCK_SOURCE_OSC32K configuration - Internal 32KHz oscillator */
# define CONF_CLOCK_OSC32K_ENABLE false
# define CONF_CLOCK_OSC32K_STARTUP_TIME SYSTEM_OSC32K_STARTUP_130
# define CONF_CLOCK_OSC32K_ENABLE_1KHZ_OUTPUT true
# define CONF_CLOCK_OSC32K_ENABLE_32KHZ_OUTPUT true
# define CONF_CLOCK_OSC32K_ON_DEMAND true
# define CONF_CLOCK_OSC32K_RUN_IN_STANDBY false
/* SYSTEM_CLOCK_SOURCE_DFLL configuration - Digital Frequency Locked Loop */
# define CONF_CLOCK_DFLL_ENABLE true
# define CONF_CLOCK_DFLL_LOOP_MODE SYSTEM_CLOCK_DFLL_LOOP_MODE_OPEN
# define CONF_CLOCK_DFLL_ON_DEMAND false
/* DFLL open loop mode configuration */
# define CONF_CLOCK_DFLL_COARSE_VALUE (0x1f / 4)
# define CONF_CLOCK_DFLL_FINE_VALUE (0xff / 4)
/* DFLL closed loop mode configuration */
# define CONF_CLOCK_DFLL_SOURCE_GCLK_GENERATOR GCLK_GENERATOR_1
# define CONF_CLOCK_DFLL_MULTIPLY_FACTOR 6
# define CONF_CLOCK_DFLL_QUICK_LOCK true
# define CONF_CLOCK_DFLL_TRACK_AFTER_FINE_LOCK true
# define CONF_CLOCK_DFLL_KEEP_LOCK_ON_WAKEUP true
# define CONF_CLOCK_DFLL_ENABLE_CHILL_CYCLE true
# define CONF_CLOCK_DFLL_MAX_COARSE_STEP_SIZE (0x1f / 4)
# define CONF_CLOCK_DFLL_MAX_FINE_STEP_SIZE (0xff / 4)
/* Set this to true to configure the GCLK when running clocks_init. If set to
* false, none of the GCLK generators will be configured in clocks_init(). */
# define CONF_CLOCK_CONFIGURE_GCLK true
/* Configure GCLK generator 0 (Main Clock) */
# define CONF_CLOCK_GCLK_0_ENABLE true
# define CONF_CLOCK_GCLK_0_RUN_IN_STANDBY false
# define CONF_CLOCK_GCLK_0_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_OSC8M
# define CONF_CLOCK_GCLK_0_PRESCALER 1
# define CONF_CLOCK_GCLK_0_OUTPUT_ENABLE false
/* Configure GCLK generator 1 */
# define CONF_CLOCK_GCLK_1_ENABLE false
# define CONF_CLOCK_GCLK_1_RUN_IN_STANDBY false
# define CONF_CLOCK_GCLK_1_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_OSC8M
# define CONF_CLOCK_GCLK_1_PRESCALER 1
# define CONF_CLOCK_GCLK_1_OUTPUT_ENABLE false
/* Configure GCLK generator 2 (RTC) */
# define CONF_CLOCK_GCLK_2_ENABLE false
# define CONF_CLOCK_GCLK_2_RUN_IN_STANDBY false
# define CONF_CLOCK_GCLK_2_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_OSC32K
# define CONF_CLOCK_GCLK_2_PRESCALER 32
# define CONF_CLOCK_GCLK_2_OUTPUT_ENABLE false
/* Configure GCLK generator 3 */
# define CONF_CLOCK_GCLK_3_ENABLE false
# define CONF_CLOCK_GCLK_3_RUN_IN_STANDBY false
# define CONF_CLOCK_GCLK_3_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_OSC8M
# define CONF_CLOCK_GCLK_3_PRESCALER 1
# define CONF_CLOCK_GCLK_3_OUTPUT_ENABLE false
/* Configure GCLK generator 4 */
# define CONF_CLOCK_GCLK_4_ENABLE false
# define CONF_CLOCK_GCLK_4_RUN_IN_STANDBY false
# define CONF_CLOCK_GCLK_4_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_OSC8M
# define CONF_CLOCK_GCLK_4_PRESCALER 1
# define CONF_CLOCK_GCLK_4_OUTPUT_ENABLE false
/* Configure GCLK generator 5 */
# define CONF_CLOCK_GCLK_5_ENABLE false
# define CONF_CLOCK_GCLK_5_RUN_IN_STANDBY false
# define CONF_CLOCK_GCLK_5_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_OSC8M
# define CONF_CLOCK_GCLK_5_PRESCALER 1
# define CONF_CLOCK_GCLK_5_OUTPUT_ENABLE false
/* Configure GCLK generator 6 */
# define CONF_CLOCK_GCLK_6_ENABLE false
# define CONF_CLOCK_GCLK_6_RUN_IN_STANDBY false
# define CONF_CLOCK_GCLK_6_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_OSC8M
# define CONF_CLOCK_GCLK_6_PRESCALER 1
# define CONF_CLOCK_GCLK_6_OUTPUT_ENABLE false
/* Configure GCLK generator 7 */
# define CONF_CLOCK_GCLK_7_ENABLE false
# define CONF_CLOCK_GCLK_7_RUN_IN_STANDBY false
# define CONF_CLOCK_GCLK_7_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_OSC8M
# define CONF_CLOCK_GCLK_7_PRESCALER 1
# define CONF_CLOCK_GCLK_7_OUTPUT_ENABLE false
#endif /* CONF_CLOCKS_H_INCLUDED */

Wyświetl plik

@ -0,0 +1,145 @@
/**
* SAM D20/D21/R21 Generic Clock Driver
*
* Copyright (C) 2012-2014 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#ifndef SYSTEM_CLOCK_GCLK_H_INCLUDED
#define SYSTEM_CLOCK_GCLK_H_INCLUDED
#include <stdbool.h>
#include "samd20.h"
/**
* List of Available GCLK generators. This enum is used in the peripheral
* device drivers to select the GCLK generator to be used for its operation.
*
* The number of GCLK generators available is device dependent.
*/
enum gclk_generator {
/** GCLK generator channel 0. */
GCLK_GENERATOR_0,
#if (GCLK_GEN_NUM_MSB > 0)
/** GCLK generator channel 1. */
GCLK_GENERATOR_1,
#endif
#if (GCLK_GEN_NUM_MSB > 1)
/** GCLK generator channel 2. */
GCLK_GENERATOR_2,
#endif
#if (GCLK_GEN_NUM_MSB > 2)
/** GCLK generator channel 3. */
GCLK_GENERATOR_3,
#endif
#if (GCLK_GEN_NUM_MSB > 3)
/** GCLK generator channel 4. */
GCLK_GENERATOR_4,
#endif
#if (GCLK_GEN_NUM_MSB > 4)
/** GCLK generator channel 5. */
GCLK_GENERATOR_5,
#endif
#if (GCLK_GEN_NUM_MSB > 5)
/** GCLK generator channel 6. */
GCLK_GENERATOR_6,
#endif
#if (GCLK_GEN_NUM_MSB > 6)
/** GCLK generator channel 7. */
GCLK_GENERATOR_7,
#endif
#if (GCLK_GEN_NUM_MSB > 7)
/** GCLK generator channel 8. */
GCLK_GENERATOR_8,
#endif
#if (GCLK_GEN_NUM_MSB > 8)
/** GCLK generator channel 9. */
GCLK_GENERATOR_9,
#endif
#if (GCLK_GEN_NUM_MSB > 9)
/** GCLK generator channel 10. */
GCLK_GENERATOR_10,
#endif
#if (GCLK_GEN_NUM_MSB > 10)
/** GCLK generator channel 11. */
GCLK_GENERATOR_11,
#endif
#if (GCLK_GEN_NUM_MSB > 11)
/** GCLK generator channel 12. */
GCLK_GENERATOR_12,
#endif
#if (GCLK_GEN_NUM_MSB > 12)
/** GCLK generator channel 13. */
GCLK_GENERATOR_13,
#endif
#if (GCLK_GEN_NUM_MSB > 13)
/** GCLK generator channel 14. */
GCLK_GENERATOR_14,
#endif
#if (GCLK_GEN_NUM_MSB > 14)
/** GCLK generator channel 15. */
GCLK_GENERATOR_15,
#endif
#if (GCLK_GEN_NUM_MSB > 15)
/** GCLK generator channel 16. */
GCLK_GENERATOR_16,
#endif
};
/* Generators */
void system_gclk_init (void);
void system_gclk_gen_set_config (const uint8_t generator,
const uint8_t source_clock,
const bool high_when_disabled,
const uint32_t division_factor,
const bool run_in_standby,
const bool output_enable);
void system_gclk_gen_enable (const uint8_t generator);
void system_gclk_gen_disable (const uint8_t generator);
bool system_gclk_gen_is_enabled (const uint8_t generator);
uint32_t system_gclk_gen_get_hz (const uint8_t generator);
/* Channels */
void system_gclk_chan_set_config(const uint8_t channel,
enum gclk_generator source_generator);
void system_gclk_chan_enable (const uint8_t channel);
void system_gclk_chan_disable (const uint8_t channel);
bool system_gclk_chan_is_enabled(const uint8_t channel);
void system_gclk_chan_lock (const uint8_t channel);
bool system_gclk_chan_is_locked (const uint8_t channel);
uint32_t system_gclk_chan_get_hz(const uint8_t channel);
#endif

Wyświetl plik

@ -0,0 +1,75 @@
/**
* Global interrupt management for SAM D20, SAM3 and SAM4 (NVIC based)
*
* Copyright (c) 2012-2014 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#ifndef SYSTEM_INTERRUPT_H
#define SYSTEM_INTERRUPT_H
#include "samd20.h"
/**
* Registers an interupt with the NVIC
*/
#define irq_register_handler(int_num, int_prio) \
do { \
NVIC_ClearPendingIRQ((IRQn_Type)int_num); \
NVIC_SetPriority( (IRQn_Type)int_num, int_prio); \
NVIC_EnableIRQ( (IRQn_Type)int_num); \
} while (0)
/**
* Safe global IRQ enable / disable
*/
#define cpu_irq_enable() \
do { \
__DMB(); \
__enable_irq(); \
} while (0)
#define cpu_irq_disable() \
do { \
__disable_irq(); \
__DMB(); \
} while (0)
#define cpu_irq_is_enabled() (__get_PRIMASK() == 0)
void cpu_irq_enter_critical(void);
void cpu_irq_leave_critical(void);
#endif /* SYSTEM_INTERRUPT_H */

Wyświetl plik

@ -0,0 +1,222 @@
/**
* SAM D20/D21/R21 Pin Multiplexer Driver
*
* Copyright (C) 2012-2014 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#ifndef PINMUX_H_INCLUDED
#define PINMUX_H_INCLUDED
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>
#include "samd20.h"
/*
* This driver for SAM D20/D21/R21 devices provides an interface for
* the configuration and management of the device's physical I/O Pins,
* to alter the direction and input/drive characteristics as well as
* to configure the pin peripheral multiplexer selection.
*
* The following peripherals are used by this module:
*
* - PORT (Port I/O Management)
*
* Module Overview
*
* The SAM D20/D21/R21 devices contain a number of General Purpose I/O
* pins, used to interface the user application logic and internal
* hardware peripherals to an external system. The Pin Multiplexer
* (PINMUX) driver provides a method of configuring the individual pin
* peripheral multiplexers to select alternate pin functions.
*
* Physical and Logical GPIO Pins
*
* SAM D20/D21/R21 devices use two naming conventions for the I/O pins
* in the device; one physical, and one logical. Each physical pin on
* a device package is assigned both a physical port and pin
* identifier (e.g. "PORTA.0") as well as a monotonically incrementing
* logical GPIO number (e.g. "GPIO0"). While the former is used to map
* physical pins to their physical internal device module
* counterparts, for simplicity the design of this driver uses the
* logical GPIO numbers instead.
*
* Peripheral Multiplexing
*
* SAM D20/D21/R21 devices contain a peripheral MUX, which is
* individually controllable for each I/O pin of the device. The
* peripheral MUX allows you to select the function of a physical
* package pin - whether it will be controlled as a user controllable
* GPIO pin, or whether it will be connected internally to one of
* several peripheral modules (such as an I<SUP>2</SUP>C module). When
* a pin is configured in GPIO mode, other peripherals connected to
* the same pin will be disabled.
*
* Special Pad Characteristics
*
* There are several special modes that can be selected on one or more
* I/O pins of the device, which alter the input and output
* characteristics of the pad:
*
* Drive Strength
*
* The Drive Strength configures the strength of the output driver on
* the pad. Normally, there is a fixed current limit that each I/O pin
* can safely drive, however some I/O pads offer a higher drive mode
* which increases this limit for that I/O pin at the expense of an
* increased power.
*
* Slew Rate
*
* The Slew Rate configures the slew rate of the output driver,
* limiting the rate at which the pad output voltage can change with
* time.
*
* Input Sample Mode
*
* The Input Sample Mode configures the input sampler buffer of the
* pad. By default, the input buffer is only sampled "on-demand",
* i.e. when the user application attempts to read from the input
* buffer. This mode is the most power efficient, but increases the
* latency of the input sample by two clock cycles of the port
* clock. To reduce latency, the input sampler can instead be
* configured to always sample the input buffer on each port clock
* cycle, at the expense of an increased power consumption.
*
* Special Considerations
*
* The SAM D20/D21/R21 port pin input sampling mode is set in groups
* of four physical pins; setting the sampling mode of any pin in a
* sub-group of eight I/O pins will configure the sampling mode of the
* entire sub-group.
*
* High Drive Strength output driver mode is not available on all device pins -
* refer to your device specific datasheet.
*/
/** Peripheral multiplexer index to select GPIO mode for a pin. */
#define SYSTEM_PINMUX_GPIO (1 << 7)
/**
* Enum for the possible pin direction settings of the port pin configuration
* structure, to indicate the direction the pin should use.
*/
enum system_pinmux_pin_dir {
/** The pin's input buffer should be enabled, so that the pin state can
* be read. */
SYSTEM_PINMUX_PIN_DIR_INPUT,
/** The pin's output buffer should be enabled, so that the pin state can
* be set (but not read back). */
SYSTEM_PINMUX_PIN_DIR_OUTPUT,
/** The pin's output and input buffers should both be enabled, so that the
* pin state can be set and read back. */
SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK,
};
/**
* Enum for the possible pin pull settings of the port pin
* configuration structure, to indicate the type of logic level pull
* the pin should use.
*/
enum system_pinmux_pin_pull {
/** No logical pull should be applied to the pin. */
SYSTEM_PINMUX_PIN_PULL_NONE,
/** Pin should be pulled up when idle. */
SYSTEM_PINMUX_PIN_PULL_UP,
/** Pin should be pulled down when idle. */
SYSTEM_PINMUX_PIN_PULL_DOWN,
};
/**
* Enum for the possible input sampling modes for the port pin
* configuration structure, to indicate the type of sampling a port
* pin should use.
*/
enum system_pinmux_pin_sample {
/** Pin input buffer should continuously sample the pin state. */
SYSTEM_PINMUX_PIN_SAMPLE_CONTINUOUS,
/** Pin input buffer should be enabled when the IN register is read. */
SYSTEM_PINMUX_PIN_SAMPLE_ONDEMAND,
};
void system_pinmux_pin_set_config(const uint8_t gpio_pin,
const uint8_t mux_position,
const enum system_pinmux_pin_dir direction,
const enum system_pinmux_pin_pull input_pull,
bool powersave);
void system_pinmux_group_set_config(PortGroup *const port,
const uint32_t mask,
const uint8_t mux_position,
const enum system_pinmux_pin_dir direction,
const enum system_pinmux_pin_pull input_pull,
bool powersave);
/**
* Retrieves the PORT module group instance associated with a given
* logical GPIO pin number.
*
* \param[in] gpio_pin Index of the GPIO pin to convert.
*
* \return Base address of the associated PORT module.
*/
static inline PortGroup* system_pinmux_get_group_from_gpio_pin(
const uint8_t gpio_pin)
{
uint8_t port_index = (gpio_pin / 128);
uint8_t group_index = (gpio_pin / 32);
/* Array of available ports. */
Port *const ports[PORT_INST_NUM] = PORT_INSTS;
if (port_index < PORT_INST_NUM) {
return &(ports[port_index]->Group[group_index]);
} else {
assert(false);
return NULL;
}
}
void system_pinmux_group_set_input_sample_mode(PortGroup *const port,
const uint32_t mask,
const enum system_pinmux_pin_sample mode);
#endif

Wyświetl plik

@ -0,0 +1,307 @@
/**
* SAM D20/D21/R21 GPIO Port Driver
*
* Copyright (C) 2012-2014 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#ifndef PORT_H_INCLUDED
#define PORT_H_INCLUDED
/**
* Port Driver (PORT)
*
* This driver for SAM D20/D21/R21 devices provides an interface for
* the configuration and management of the device's General Purpose
* Input/Output (GPIO) pin functionality, for manual pin state reading
* and writing.
*
* The following peripherals are used by this module:
*
* - PORT (GPIO Management)
*
* Module Overview
*
* The device GPIO (PORT) module provides an interface between the
* user application logic and external hardware peripherals, when
* general pin state manipulation is required. This driver provides an
* easy-to-use interface to the physical pin input samplers and output
* drivers, so that pins can be read from or written to for general
* purpose external hardware control.
*
* Physical and Logical GPIO Pins
*
* SAM D20/D21/R21 devices use two naming conventions for the I/O pins
* in the device; one physical, and one logical. Each physical pin on
* a device package is assigned both a physical port and pin
* identifier (e.g. "PORTA.0") as well as a monotonically incrementing
* logical GPIO number (e.g. "GPIO0"). While the former is used to map
* physical pins to their physical internal device module
* counterparts, for simplicity the design of this driver uses the
* logical GPIO numbers instead.
*
* Special Considerations
*
* The SAM D20/D21/R21 port pin input sampler can be disabled when the pin is configured
* in pure output mode to save power; reading the pin state of a pin configured
* in output-only mode will read the logical output state that was last set.
*
*/
#include "system/pinmux.h"
/** Convenience definition for GPIO module group A on the device (if
* available). */
#if (PORT_GROUPS > 0)
# define PORTA PORT->Group[0]
#endif
#if (PORT_GROUPS > 1)
/** Convenience definition for GPIO module group B on the device (if
* available). */
# define PORTB PORT->Group[1]
#endif
#if (PORT_GROUPS > 2)
/** Convenience definition for GPIO module group C on the device (if
* available). */
# define PORTC PORT->Group[2]
#endif
#if (PORT_GROUPS > 3)
/** Convenience definition for GPIO module group D on the device (if
* available). */
# define PORTD PORT->Group[3]
#endif
/**
* Enum for the possible pin direction settings of the port pin configuration
* structure, to indicate the direction the pin should use.
*/
enum port_pin_dir {
/** The pin's input buffer should be enabled, so that the pin state can
* be read. */
PORT_PIN_DIR_INPUT = SYSTEM_PINMUX_PIN_DIR_INPUT,
/** The pin's output buffer should be enabled, so that the pin state can
* be set. */
PORT_PIN_DIR_OUTPUT = SYSTEM_PINMUX_PIN_DIR_OUTPUT,
/** The pin's output and input buffers should be enabled, so that the pin
* state can be set and read back. */
PORT_PIN_DIR_OUTPUT_WTH_READBACK = SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK,
};
/**
* Enum for the possible pin pull settings of the port pin configuration
* structure, to indicate the type of logic level pull the pin should use.
*/
enum port_pin_pull {
/** No logical pull should be applied to the pin. */
PORT_PIN_PULL_NONE = SYSTEM_PINMUX_PIN_PULL_NONE,
/** Pin should be pulled up when idle. */
PORT_PIN_PULL_UP = SYSTEM_PINMUX_PIN_PULL_UP,
/** Pin should be pulled down when idle. */
PORT_PIN_PULL_DOWN = SYSTEM_PINMUX_PIN_PULL_DOWN,
};
/**
* Retrieves the PORT module group instance from a given GPIO pin number.
*
* Retrieves the PORT module group instance associated with a given
* logical GPIO pin number.
*
* \param[in] gpio_pin Index of the GPIO pin to convert.
*
* \return Base address of the associated PORT module.
*/
static inline PortGroup* port_get_group_from_gpio_pin(const uint8_t gpio_pin)
{
return system_pinmux_get_group_from_gpio_pin(gpio_pin);
}
/**
* Retrieves the state of a group of port pins that are configured as inputs.
*
* Reads the current logic level of a port module's pins and returns
* the current levels as a bitmask.
*
* \param[in] port Base of the PORT module to read from.
* \param[in] mask Mask of the port pin(s) to read.
*
* \return Status of the port pin(s) input buffers.
*/
static inline uint32_t port_group_get_input_level(const PortGroup *const port,
const uint32_t mask)
{
/* Sanity check arguments */
assert(port);
return (port->IN.reg & mask);
}
/**
* Retrieves the state of a group of port pins that are configured as outputs.
*
* Reads the current logical output level of a port module's pins and
* returns the current levels as a bitmask.
*
* \param[in] port Base of the PORT module to read from.
* \param[in] mask Mask of the port pin(s) to read.
*
* \return Status of the port pin(s) output buffers.
*/
static inline uint32_t port_group_get_output_level(const PortGroup *const port,
const uint32_t mask)
{
/* Sanity check arguments */
assert(port);
return (port->OUT.reg & mask);
}
/**
* Sets the state of a group of port pins that are configured as outputs.
*
* \param[out] port Base of the PORT module to write to.
* \param[in] mask Mask of the port pin(s) to change.
* \param[in] level_mask Mask of the port level(s) to set.
*/
static inline void port_group_set_output_level(PortGroup *const port,
const uint32_t mask,
const uint32_t level_mask)
{
/* Sanity check arguments */
assert(port);
port->OUTSET.reg = (mask & level_mask);
port->OUTCLR.reg = (mask & ~level_mask);
}
/**
* Toggles the state of a group of port pins that are configured as an outputs.
*
* \param[out] port Base of the PORT module to write to.
* \param[in] mask Mask of the port pin(s) to toggle.
*/
static inline void port_group_toggle_output_level(PortGroup *const port,
const uint32_t mask)
{
/* Sanity check arguments */
assert(port);
port->OUTTGL.reg = mask;
}
void port_pin_set_config(const uint8_t gpio_pin,
enum port_pin_dir direction,
enum port_pin_pull input_pull,
bool powersave);
void port_pin_set_config_default(const uint8_t gpio_pin);
void port_group_set_config(PortGroup *const port,
const uint32_t mask,
enum port_pin_dir direction,
enum port_pin_pull input_pull,
bool powersave);
void port_group_set_config_default(PortGroup *const port,
const uint32_t mask);
/**
* Reads the current logic level of a port pin and returns the current
* level as a boolean value.
*
* \param[in] gpio_pin Index of the GPIO pin to read.
*
* \return Status of the port pin's input buffer.
*/
static inline bool port_pin_get_input_level(const uint8_t gpio_pin)
{
PortGroup *const port_base = port_get_group_from_gpio_pin(gpio_pin);
uint32_t pin_mask = (1UL << (gpio_pin % 32));
return (port_base->IN.reg & pin_mask);
}
/**
* Reads the current logical output level of a port pin and returns the current
* level as a boolean value.
*
* \param[in] gpio_pin Index of the GPIO pin to read.
*
* \return Status of the port pin's output buffer.
*/
static inline bool port_pin_get_output_level(const uint8_t gpio_pin)
{
PortGroup *const port_base = port_get_group_from_gpio_pin(gpio_pin);
uint32_t pin_mask = (1UL << (gpio_pin % 32));
return (port_base->OUT.reg & pin_mask);
}
/**
* Sets the current output level of a port pin to a given logic level.
*
* \param[in] gpio_pin Index of the GPIO pin to write to.
* \param[in] level Logical level to set the given pin to.
*/
static inline void port_pin_set_output_level(const uint8_t gpio_pin,
const bool level)
{
PortGroup *const port_base = port_get_group_from_gpio_pin(gpio_pin);
uint32_t pin_mask = (1UL << (gpio_pin % 32));
/* Set the pin to high or low atomically based on the requested level */
if (level) {
port_base->OUTSET.reg = pin_mask;
} else {
port_base->OUTCLR.reg = pin_mask;
}
}
/**
* Toggles the current output level of a port pin.
*
* \param[in] gpio_pin Index of the GPIO pin to toggle.
*/
static inline void port_pin_toggle_output_level(const uint8_t gpio_pin)
{
PortGroup *const port_base = port_get_group_from_gpio_pin(gpio_pin);
uint32_t pin_mask = (1UL << (gpio_pin % 32));
/* Toggle pin output level */
port_base->OUTTGL.reg = pin_mask;
}
#endif

Wyświetl plik

@ -0,0 +1,358 @@
/**
* \file
*
* \brief SAM D20/D21/R21 System related functionality
*
* Copyright (C) 2012-2014 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#ifndef SYSTEM_H_INCLUDED
#define SYSTEM_H_INCLUDED
#include "system/clock.h"
#include "system/gclk.h"
#include "system/pinmux.h"
/**
* SAM D20/D21/R21 System Driver (SYSTEM)
*
* This driver for SAM D20/D21/R21 devices provides an interface for
* the configuration and management of the device's system relation
* functionality, necessary for the basic device operation. This is
* not limited to a single peripheral, but extends across multiple
* hardware peripherals,
*
* The following peripherals are used by this module:
*
* - SYSCTRL (System Control)
* - PM (Power Manager)
*
* Module Overview
*
* The System driver provides a collection of interfaces between the
* user application logic, and the core device functionality (such as
* clocks, reset cause determination, etc.) that is required for all
* applications.
*
* Voltage References
*
* The various analog modules within the SAM D20/D21/R21 devices (such
* as AC, ADC and DAC) require a voltage reference to be configured to
* act as a reference point for comparisons and conversions.
*
* The SAM D20/D21/R21 devices contain multiple references, including
* an internal temperature sensor, and a fixed band-gap voltage
* source. When enabled, the associated voltage reference can be
* selected within the desired peripheral where applicable.
*
* System Reset Cause
*
* In some application there may be a need to execute a different
* program flow based on how the device was reset. For example, if the
* cause of reset was the Watchdog timer (WDT), this might indicate an
* error in the application and a form of error handling or error
* logging might be needed.
*
* For this reason, an API is provided to retrieve the cause of the
* last system reset, so that appropriate action can be taken.
*
* Sleep Modes
*
* The SAM D20/D21/R21 devices have several sleep modes, where the sleep mode controls
* which clock systems on the device will remain enabled or disabled when the
* device enters a low power sleep mode.
* \ref asfdoc_sam0_system_module_sleep_mode_table "The table below" lists the
* clock settings of the different sleep modes.
*
* \anchor asfdoc_sam0_system_module_sleep_mode_table
* <table>
* <caption>SAM D20/D21/R21 Device Sleep Modes</caption>
* <tr>
* <th>Sleep mode</th>
* <th>CPU clock</th>
* <th>AHB clock</th>
* <th>APB clocks</th>
* <th>Clock sources</th>
* <th>System clock</th>
* <th>32KHz</th>
* <th>Reg mode</th>
* <th>RAM mode</th>
* </tr>
* <tr>
* <td>IDLE 0</td>
* <td>Stop</td>
* <td>Run</td>
* <td>Run</td>
* <td>Run</td>
* <td>Run</td>
* <td>Run</td>
* <td>Normal</td>
* <td>Normal</td>
* </tr>
* <tr>
* <td>IDLE 1</td>
* <td>Stop</td>
* <td>Stop</td>
* <td>Run</td>
* <td>Run</td>
* <td>Run</td>
* <td>Run</td>
* <td>Normal</td>
* <td>Normal</td>
* </tr>
* <tr>
* <td>IDLE 2</td>
* <td>Stop</td>
* <td>Stop</td>
* <td>Stop</td>
* <td>Run</td>
* <td>Run</td>
* <td>Run</td>
* <td>Normal</td>
* <td>Normal</td>
* </tr>
* <tr>
* <td>STANDBY</td>
* <td>Stop</td>
* <td>Stop</td>
* <td>Stop</td>
* <td>Stop</td>
* <td>Stop</td>
* <td>Stop</td>
* <td>Low Power</td>
* <td>Source/Drain biasing</td>
* </tr>
* </table>
*
* To enter device sleep, one of the available sleep modes must be set, and the
* function to enter sleep called. The device will automatically wake up in
* response to an interrupt being generated or other device event.
*
* Some peripheral clocks will remain enabled during sleep, depending on their
* configuration; if desired, modules can remain clocked during sleep to allow
* them to continue to operate while other parts of the system are powered down
* to save power.
*
*/
/**
* List of available voltage references (VREF) that may be used within
* the device.
*/
enum system_voltage_reference {
/** Temperature sensor voltage reference. */
SYSTEM_VOLTAGE_REFERENCE_TEMPSENSE,
/** Bandgap voltage reference. */
SYSTEM_VOLTAGE_REFERENCE_BANDGAP,
};
/**
* List of available sleep modes in the device. A table of clocks
* available in different sleep modes can be found in \ref
* asfdoc_sam0_system_module_overview_sleep_mode.
*/
enum system_sleepmode {
/** IDLE 0 sleep mode. */
SYSTEM_SLEEPMODE_IDLE_0,
/** IDLE 1 sleep mode. */
SYSTEM_SLEEPMODE_IDLE_1,
/** IDLE 2 sleep mode. */
SYSTEM_SLEEPMODE_IDLE_2,
/** Standby sleep mode. */
SYSTEM_SLEEPMODE_STANDBY,
};
/**
* List of possible reset causes of the system.
*/
enum system_reset_cause {
/** The system was last reset by a software reset. */
SYSTEM_RESET_CAUSE_SOFTWARE = PM_RCAUSE_SYST,
/** The system was last reset by the watchdog timer. */
SYSTEM_RESET_CAUSE_WDT = PM_RCAUSE_WDT,
/** The system was last reset because the external reset line was pulled low. */
SYSTEM_RESET_CAUSE_EXTERNAL_RESET = PM_RCAUSE_EXT,
/** The system was last reset by the BOD33. */
SYSTEM_RESET_CAUSE_BOD33 = PM_RCAUSE_BOD33,
/** The system was last reset by the BOD12. */
SYSTEM_RESET_CAUSE_BOD12 = PM_RCAUSE_BOD12,
/** The system was last reset by the POR (Power on reset). */
SYSTEM_RESET_CAUSE_POR = PM_RCAUSE_POR,
};
/**
* Retrieves the signature of the current device.
*
* \return Device ID signature as a 32-bit integer.
*/
static inline uint32_t system_get_device_id(void)
{
return DSU->DID.reg;
}
/**
* Enables the selected voltage reference source, making the voltage reference
* available on a pin as well as an input source to the analog peripherals.
*
* \param[in] vref Voltage reference to enable
*/
static inline void system_voltage_reference_enable(
const enum system_voltage_reference vref)
{
switch (vref) {
case SYSTEM_VOLTAGE_REFERENCE_TEMPSENSE:
SYSCTRL->VREF.reg |= SYSCTRL_VREF_TSEN;
break;
case SYSTEM_VOLTAGE_REFERENCE_BANDGAP:
SYSCTRL->VREF.reg |= SYSCTRL_VREF_BGOUTEN;
break;
default:
assert(false);
return;
}
}
/**
* Disables the selected voltage reference source.
*
* \param[in] vref Voltage reference to disable
*/
static inline void system_voltage_reference_disable(
const enum system_voltage_reference vref)
{
switch (vref) {
case SYSTEM_VOLTAGE_REFERENCE_TEMPSENSE:
SYSCTRL->VREF.reg &= ~SYSCTRL_VREF_TSEN;
break;
case SYSTEM_VOLTAGE_REFERENCE_BANDGAP:
SYSCTRL->VREF.reg &= ~SYSCTRL_VREF_BGOUTEN;
break;
default:
assert(false);
return;
}
}
/**
* Set the sleep mode of the device
*
* Sets the sleep mode of the device; the configured sleep mode will be entered
* upon the next call of the \ref system_sleep() function.
*
* For an overview of which systems are disabled in sleep for the different
* sleep modes, see \ref asfdoc_sam0_system_module_overview_sleep_mode.
*
* \param[in] sleep_mode Sleep mode to configure for the next sleep operation
*
* \retval STATUS_OK Operation completed successfully
* \retval STATUS_ERR_INVALID_ARG The requested sleep mode was invalid or not
* available
*/
static inline void system_set_sleepmode(
const enum system_sleepmode sleep_mode)
{
switch (sleep_mode) {
case SYSTEM_SLEEPMODE_IDLE_0:
case SYSTEM_SLEEPMODE_IDLE_1:
case SYSTEM_SLEEPMODE_IDLE_2:
SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
PM->SLEEP.reg = sleep_mode;
break;
case SYSTEM_SLEEPMODE_STANDBY:
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
break;
default:
break;
// return STATUS_ERR_INVALID_ARG;
}
}
/**
* Executes a device DSB (Data Synchronization Barrier) instruction to ensure
* all ongoing memory accesses have completed, then a WFI (Wait For Interrupt)
* instruction to place the device into the sleep mode specified by
* \ref system_set_sleepmode until woken by an interrupt.
*/
static inline void system_sleep(void)
{
__DSB();
__WFI();
}
/**
* Check if debugger is connected to the onboard debug system (DAP)
*
* \return A bool identifying if a debugger is present
*
* \retval true Debugger is connected to the system
* \retval false Debugger is not connected to the system
*
*/
static inline bool system_is_debugger_present(void)
{
return DSU->STATUSB.reg & DSU_STATUSB_DBGPRES;
}
/**
* Resets the MCU and all associated peripherals and registers, except
* RTC, all 32kHz sources, WDT (if ALWAYSON is set) and GCLK (if
* WRTLOCK is set).
*
*/
static inline void system_reset(void)
{
NVIC_SystemReset();
}
/**
* Retrieves the cause of the last system reset.
*
* \return An enum value indicating the cause of the last system reset.
*/
static inline enum system_reset_cause system_get_reset_cause(void)
{
return (enum system_reset_cause)PM->RCAUSE.reg;
}
#endif /* SYSTEM_H_INCLUDED */

Wyświetl plik

@ -0,0 +1,221 @@
/**
* SAM D20/D21/R21 Watchdog Driver
*
* Copyright (C) 2012-2014 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#ifndef WDT_H_INCLUDED
#define WDT_H_INCLUDED
/**
* SAM D20/D21/R21 Watchdog Driver (WDT)
*
* This driver for SAM D20/D21/R21 devices provides an interface for
* the configuration and management of the device's Watchdog Timer
* module, including the enabling, disabling and kicking within the
* device. The following driver API modes are covered by this manual:
*
* - Polled APIs
*
* The following peripherals are used by this module:
*
* - WDT (Watchdog Timer)
*
* Module Overview
*
* The Watchdog module (WDT) is designed to give an added level of
* safety in critical systems, to ensure a system reset is triggered
* in the case of a deadlock or other software malfunction that
* prevents normal device operation.
*
* At a basic level, the Watchdog is a system timer with a fixed
* period; once enabled, it will continue to count ticks of its
* asynchronous clock until it is periodically reset, or the timeout
* period is reached. In the event of a Watchdog timeout, the module
* will trigger a system reset identical to a pulse of the device's
* reset pin, resetting all peripherals to their power-on default
* states and restarting the application software from the reset
* vector.
*
* In many systems, there is an obvious upper bound to the amount of
* time each iteration of the main application loop can be expected to
* run, before a malfunction can be assumed (either due to a deadlock
* waiting on hardware or software, or due to other means). When the
* Watchdog is configured with a timeout period equal to this upper
* bound, a malfunction in the system will force a full system reset
* to allow for a graceful recovery.
*
* Locked Mode
*
* The Watchdog configuration can be set in the device fuses and
* locked in hardware, so that no software changes can be made to the
* Watchdog configuration. Additionally, the Watchdog can be locked on
* in software if it is not already locked, so that the module
* configuration cannot be modified until a power on reset of the
* device.
*
* The locked configuration can be used to ensure that faulty software
* does not cause the Watchdog configuration to be changed, preserving
* the level of safety given by the module.
*
* Window Mode
*
* Just as there is a reasonable upper bound to the time the main
* program loop should take for each iteration, there is also in many
* applications a lower bound, i.e. a minimum time for which each loop
* iteration should run for under normal circumstances. To guard
* against a system failure resetting the Watchdog in a tight loop (or
* a failure in the system application causing the main loop to run
* faster than expected) a "Window" mode can be enabled to disallow
* resetting of the Watchdog counter before a certain period of time.
* If the Watchdog is not reset after the window opens but not before
* the Watchdog expires, the system will reset.
*
* Early Warning
*
* In some cases it is desirable to receive an early warning that the
* Watchdog is about to expire, so that some system action (such as
* saving any system configuration data for failure analysis purposes)
* can be performed before the system reset occurs. The Early Warning
* feature of the Watchdog module allows such a notification to be
* requested; after the configured early warning time (but before the
* expiry of the Watchdog counter) the Early Warning flag will become
* set, so that the user application can take an appropriate action.
*
* \note It is important to note that the purpose of the Early Warning feature
* is not to allow the user application to reset the Watchdog; doing
* so will defeat the safety the module gives to the user application.
* Instead, this feature should be used purely to perform any tasks that
* need to be undertaken before the system reset occurs.
*
* Special Considerations
*
* On some devices the Watchdog configuration can be fused to be always on in
* a particular configuration; if this mode is enabled the Watchdog is not
* software configurable and can have its count reset and early warning state
* checked/cleared only.
*
*/
#include "system/clock.h"
#include "system/gclk.h"
/**
* Enum for the possible period settings of the Watchdog timer module, for
* values requiring a period as a number of Watchdog timer clock ticks.
*/
enum wdt_period {
/** No Watchdog period. This value can only be used when setting the
* Window and Early Warning periods; its use as the Watchdog Reset
* Period is invalid. */
WDT_PERIOD_NONE = 0,
/** Watchdog period of 8 clocks of the Watchdog Timer Generic Clock. */
WDT_PERIOD_8CLK = 1,
/** Watchdog period of 16 clocks of the Watchdog Timer Generic Clock. */
WDT_PERIOD_16CLK = 2,
/** Watchdog period of 32 clocks of the Watchdog Timer Generic Clock. */
WDT_PERIOD_32CLK = 3,
/** Watchdog period of 64 clocks of the Watchdog Timer Generic Clock. */
WDT_PERIOD_64CLK = 4,
/** Watchdog period of 128 clocks of the Watchdog Timer Generic Clock. */
WDT_PERIOD_128CLK = 5,
/** Watchdog period of 256 clocks of the Watchdog Timer Generic Clock. */
WDT_PERIOD_256CLK = 6,
/** Watchdog period of 512 clocks of the Watchdog Timer Generic Clock. */
WDT_PERIOD_512CLK = 7,
/** Watchdog period of 1024 clocks of the Watchdog Timer Generic Clock. */
WDT_PERIOD_1024CLK = 8,
/** Watchdog period of 2048 clocks of the Watchdog Timer Generic Clock. */
WDT_PERIOD_2048CLK = 9,
/** Watchdog period of 4096 clocks of the Watchdog Timer Generic Clock. */
WDT_PERIOD_4096CLK = 10,
/** Watchdog period of 8192 clocks of the Watchdog Timer Generic Clock. */
WDT_PERIOD_8192CLK = 11,
/** Watchdog period of 16384 clocks of the Watchdog Timer Generic Clock. */
WDT_PERIOD_16384CLK = 12,
};
void wdt_set_config(bool always_on,
bool enable,
enum gclk_generator clock_source,
enum wdt_period timeout_period,
enum wdt_period window_period,
enum wdt_period early_warning_period);
void wdt_set_config_default(void);
/**
* Determines if the Watchdog timer is currently enabled and locked, so that
* it cannot be disabled or otherwise reconfigured.
*
* \return Current Watchdog lock state.
*/
static inline bool wdt_is_locked(void)
{
Wdt *const WDT_module = WDT;
return (WDT_module->CTRL.reg & WDT_CTRL_ALWAYSON);
}
/**
* Clears the Watchdog timer Early Warning period elapsed flag, so that a new
* early warning period can be detected.
*/
static inline void wdt_clear_early_warning(void)
{
Wdt *const WDT_module = WDT;
WDT_module->INTFLAG.reg = WDT_INTFLAG_EW;
}
/**
* Determines if the Watchdog timer Early Warning period has elapsed.
*
* \note If no early warning period was configured, the value returned by this
* function is invalid.
*
* \return Current Watchdog Early Warning state.
*/
static inline bool wdt_is_early_warning(void)
{
Wdt *const WDT_module = WDT;
return (WDT_module->INTFLAG.reg & WDT_INTFLAG_EW);
}
void wdt_reset_count(void);
#endif /* WDT_H_INCLUDED */

Wyświetl plik

@ -0,0 +1,569 @@
/**
* SAM D20/D21/R21 TC - Timer Counter Driver
*
* Copyright (C) 2013-2014 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#ifndef TC_H_INCLUDED
#define TC_H_INCLUDED
/**
* SAM D20/D21/R21 Timer/Counter Driver (TC)
*
* Module Overview
*
* The Timer/Counter (TC) module provides a set of timing and counting related
* functionality, such as the generation of periodic waveforms, the capturing
* of a periodic waveform's frequency/duty cycle, and software timekeeping for
* periodic operations. TC modules can be configured to use an 8-, 16-, or
* 32-bit counter size.
*
* This TC module for the SAM D20/D21/R21 is capable of the following functions:
*
* - Generation of PWM signals
* - Generation of timestamps for events
* - General time counting
* - Waveform period capture
* - Waveform frequency capture
*
* Functional Description
*
* Independent of the configured counter size, each TC module can be set up
* in one of two different modes; capture and compare.
*
* In capture mode, the counter value is stored when a configurable event
* occurs. This mode can be used to generate timestamps used in event capture,
* or it can be used for the measurement of a periodic input signal's
* frequency/duty cycle.
*
* In compare mode, the counter value is compared against one or more of the
* configured channel compare values. When the counter value coincides with a
* compare value an action can be taken automatically by the module, such as
* generating an output event or toggling a pin when used for frequency or PWM
* signal generation.
*
* Note: The connection of events between modules requires the use of
* the SAM D20/D21/R21 Event System Driver (EVENTS) to route
* output event of one module to the the input event of another.
* For more information on event routing, refer to the event
* driver documentation.
*
* Timer/Counter Size
* Each timer module can be configured in one of three different counter
* sizes; 8-, 16-, and 32-bits. The size of the counter determines the maximum
* value it can count to before an overflow occurs and the count is reset back
* to zero.
*
* When using the counter in 16- or 32-bit count mode, Compare Capture
* register 0 (CC0) is used to store the period value when running in PWM
* generation match mode.
*
* When using 32-bit counter size, two 16-bit counters are chained together
* in a cascade formation. Even numbered TC modules (e.g. TC0, TC2) can be
* configured as 32-bit counters. The odd numbered counters will act as slaves
* to the even numbered masters, and will not be reconfigurable until the
* master timer is disabled.
*
* Clock Settings
*
* Clock Selection
* Each TC peripheral is clocked asynchronously to the
* system clock by a GCLK (Generic Clock) channel. The GCLK channel
* connects to any of the GCLK generators. The GCLK generators are
* configured to use one of the available clock sources on the system
* such as internal oscillator, external crystals etc.
*
* Prescaler
* Each TC module in the SAM D20/D21/R21 has its own
* individual clock prescaler, which can be used to divide the input
* clock frequency used in the counter. This prescaler only scales the
* clock used to provide clock pulses for the counter to count, and
* does not affect the digital register interface portion of the
* module, thus the timer registers will synchronized to the raw GCLK
* frequency input to the module.
*
* As a result of this, when selecting a GCLK frequency and timer prescaler
* value the user application should consider both the timer resolution
* required and the synchronization frequency, to avoid lengthy
* synchronization times of the module if a very slow GCLK frequency is fed
* into the TC module. It is preferable to use a higher module GCLK frequency
* as the input to the timer and prescale this down as much as possible to
* obtain a suitable counter frequency in latency-sensitive applications.
*
* Reloading
* Timer modules also contain a configurable reload action, used when a
* re-trigger event occurs. Examples of a re-trigger event are the counter
* reaching the max value when counting up, or when an event from the event
* system tells the counter to re-trigger. The reload action determines if the
* prescaler should be reset, and when this should happen. The counter will
* always be reloaded with the value it is set to start counting from.
*
* <table>
* <caption>TC module reload actions</caption>
* <tr>
* <th>Reload Action</th>
* <th>Description</th>
* </tr>
* <tr>
* <td>\ref TC_RELOAD_ACTION_GCLK </td>
* <td>Reload TC counter value on next GCLK cycle. Leave prescaler
* as-is.</td>
* </tr>
* <tr>
* <td>\ref TC_RELOAD_ACTION_PRESC </td>
* <td>Reloads TC counter value on next prescaler clock. Leave prescaler
* as-is.</td>
* </tr>
* <tr>
* <td> \ref TC_RELOAD_ACTION_RESYNC </td>
* <td>Reload TC counter value on next GCLK cycle. Clear prescaler to
* zero.</td>
* </tr>
* </table>
*
* The reload action to use will depend on the specific application being
* implemented. One example is when an external trigger for a reload occurs; if
* the TC uses the prescaler, the counter in the prescaler should not have a
* value between zero and the division factor. The TC counter and the counter
* in the prescaler should both start at zero. When the counter is set to
* re-trigger when it reaches the max value on the other hand, this is not the
* right option to use. In such a case it would be better if the prescaler is
* left unaltered when the re-trigger happens, letting the counter reset on the
* next GCLK cycle.
*
* Compare Match Operations
* In compare match operation, Compare/Capture registers are used in comparison
* with the counter value. When the timer's count value matches the value of a
* compare channel, a user defined action can be taken.
*
* Basic Timer
*
* A Basic Timer is a simple application where compare match operations is used
* to determine when a specific period has elapsed. In Basic Timer operations,
* one or more values in the module's Compare/Capture registers are used to
* specify the time (as a number of prescaled GCLK cycles) when an action should
* be taken by the microcontroller. This can be an Interrupt Service Routine
* (ISR), event generator via the event system, or a software flag that is
* polled via the user application.
*
* Waveform Generation
*
* Waveform generation enables the TC module to generate square waves, or if
* combined with an external passive low-pass filter, analog waveforms.
*
* Waveform Generation - PWM
*
* Pulse width modulation is a form of waveform generation and a signalling
* technique that can be useful in many situations. When PWM mode is used,
* a digital pulse train with a configurable frequency and duty cycle can be
* generated by the TC module and output to a GPIO pin of the device.
*
* Often PWM is used to communicate a control or information parameter to an
* external circuit or component. Differing impedances of the source generator
* and sink receiver circuits is less of an issue when using PWM compared to
* using an analog voltage value, as noise will not generally affect the
* signal's integrity to a meaningful extent.
*
* Frequency Generation mode is in many ways identical to PWM
* generation. However, in Frequency Generation a toggle only occurs
* on the output when a match on a capture channels occurs. When the
* match is made, the timer value is reset, resulting in a variable
* frequency square wave with a fixed 50% duty cycle.
*
* Capture Operations
*
* In capture operations, any event from the event system or a pin change can
* trigger a capture of the counter value. This captured counter value can be
* used as a timestamp for the event, or it can be used in frequency and pulse
* width capture.
*
* Capture Operations - Event
*
* Event capture is a simple use of the capture functionality,
* designed to create timestamps for specific events. When the TC
* module's input capture pin is externally toggled, the current timer
* count value is copied into a buffered register which can then be
* read out by the user application.
*
* Note that when performing any capture operation, there is a risk that the
* counter reaches its top value (MAX) when counting up, or the bottom value
* (zero) when counting down, before the capture event occurs. This can distort
* the result, making event timestamps to appear shorter than reality; the
* user application should check for timer overflow when reading a capture
* result in order to detect this situation and perform an appropriate
* adjustment.
*
* Before checking for a new capture, TC_STATUS_COUNT_OVERFLOW should
* be checked. The response to an overflow error is left to the user
* application, however it may be necessary to clear both the capture
* overflow flag and the capture flag upon each capture reading.
*
* Capture Operations - Pulse Width
*
* Pulse Width Capture mode makes it possible to measure the pulse width and
* period of PWM signals. This mode uses two capture channels of the counter.
* This means that the counter module used for Pulse Width Capture can not be
* used for any other purpose. There are two modes for pulse width capture;
* Pulse Width Period (PWP) and Period Pulse Width (PPW). In PWP mode, capture
* channel 0 is used for storing the pulse width and capture channel 1 stores
* the observed period. While in PPW mode, the roles of the two capture channels
* is reversed.
*
* As in the above example it is necessary to poll on interrupt flags to see
* if a new capture has happened and check that a capture overflow error has
* not occurred.
*
* One-shot Mode
*
* TC modules can be configured into a one-shot mode. When configured in this
* manner, starting the timer will cause it to count until the next overflow
* or underflow condition before automatically halting, waiting to be manually
* triggered by the user application software or an event signal from the event
* system.
*
* Wave Generation Output Inversion
*
* The output of the wave generation can be inverted by hardware if desired,
* resulting in the logically inverted value being output to the configured
* device GPIO pin.
*
*
* Special Considerations
*
* The number of capture compare registers in each TC module is dependent on
* the specific SAM D20/D21/R21 device being used, and in some cases the counter size.
*
* The maximum amount of capture compare registers available in any SAM D20/D21/R21
* device is two when running in 32-bit mode and four in 8-, and 16-bit modes.
*/
//#include <clock.h>
//#include <gclk.h>
//#include <pinmux.h>
#include "samd20.h"
#include "tc.h"
#include <stdbool.h>
/* Same number for 8-, 16- and 32-bit TC and all TC instances */
#define NUMBER_OF_COMPARE_CAPTURE_CHANNELS TC0_CC8_NUM
/**
* TC status type
*/
enum tc_status_t {
TC_STATUS_OK = 0,
TC_STATUS_BUSY,
TC_STATUS_DENIED
};
/**
* TC error type
*/
enum tc_error_t {
TC_ERROR_INVALID_ARG = 1,
TC_ERROR_INVALID_STATE,
TC_ERROR_INVALID_DEVICE,
TC_ERROR_NO_32BIT_SLAVE_EXISTS
};
/**
* Module status flags
*/
/** Timer channel 0 has matched against its compare value, or has captured a
* new value.
*/
#define TC_STATUS_CHANNEL_0_MATCH (1UL << 0)
/** Timer channel 1 has matched against its compare value, or has captured a
* new value.
*/
#define TC_STATUS_CHANNEL_1_MATCH (1UL << 1)
/** Timer register synchronization has completed, and the synchronized count
* value may be read.
*/
#define TC_STATUS_SYNC_READY (1UL << 2)
/** A new value was captured before the previous value was read, resulting in
* lost data.
*/
#define TC_STATUS_CAPTURE_OVERFLOW (1UL << 3)
/** The timer count value has overflowed from its maximum value to its minimum
* when counting upward, or from its minimum value to its maximum when
* counting downward.
*/
#define TC_STATUS_COUNT_OVERFLOW (1UL << 4)
/**
* Index of the compare capture channels
*
* This enum is used to specify which capture/compare channel to do
* operations on.
*/
enum tc_compare_capture_channel {
/** Index of compare capture channel 0 */
TC_COMPARE_CAPTURE_CHANNEL_0,
/** Index of compare capture channel 1 */
TC_COMPARE_CAPTURE_CHANNEL_1,
};
/**
* TC wave generation mode enum
*
* This enum is used to select which mode to run the wave
* generation in.
*/
enum tc_wave_generation {
/** Top is max, except in 8-bit counter size where it is the PER
* register
*/
TC_WAVE_GENERATION_NORMAL_FREQ = TC_CTRLA_WAVEGEN_NFRQ,
/** Top is CC0, except in 8-bit counter size where it is the PER
* register
*/
TC_WAVE_GENERATION_MATCH_FREQ = TC_CTRLA_WAVEGEN_MFRQ,
/** Top is max, except in 8-bit counter size where it is the PER
* register
*/
TC_WAVE_GENERATION_NORMAL_PWM = TC_CTRLA_WAVEGEN_NPWM,
/** Top is CC0, except in 8-bit counter size where it is the PER
* register
*/
TC_WAVE_GENERATION_MATCH_PWM = TC_CTRLA_WAVEGEN_MPWM,
};
/**
* Specifies if the counter is 8-, 16-, or 32-bits.
*
* This enum specifies the maximum value it is possible to count to.
*/
enum tc_counter_size {
/** The counter's max value is 0xFF, the period register is
* available to be used as top value.
*/
TC_COUNTER_SIZE_8BIT = TC_CTRLA_MODE_COUNT8,
/** The counter's max value is 0xFFFF. There is no separate
* period register, to modify top one of the capture compare
* registers has to be used. This limits the amount of
* available channels.
*/
TC_COUNTER_SIZE_16BIT = TC_CTRLA_MODE_COUNT16,
/** The counter's max value is 0xFFFFFFFF. There is no separate
* period register, to modify top one of the capture compare
* registers has to be used. This limits the amount of
* available channels.
*/
TC_COUNTER_SIZE_32BIT = TC_CTRLA_MODE_COUNT32,
};
/**
* TC Counter reload action enum
*
* This enum specify how the counter and prescaler should reload.
*/
enum tc_reload_action {
/** The counter is reloaded/reset on the next GCLK and starts
* counting on the prescaler clock.
*/
TC_RELOAD_ACTION_GCLK = TC_CTRLA_PRESCSYNC_GCLK,
/** The counter is reloaded/reset on the next prescaler clock
*/
TC_RELOAD_ACTION_PRESC = TC_CTRLA_PRESCSYNC_PRESC,
/** The counter is reloaded/reset on the next GCLK, and the
* prescaler is restarted as well.
*/
TC_RELOAD_ACTION_RESYNC = TC_CTRLA_PRESCSYNC_RESYNC,
};
/**
* TC clock prescaler values
*/
enum tc_clock_prescaler {
/** Divide clock by 1 */
TC_CLOCK_PRESCALER_DIV1 = TC_CTRLA_PRESCALER(0),
/** Divide clock by 2 */
TC_CLOCK_PRESCALER_DIV2 = TC_CTRLA_PRESCALER(1),
/** Divide clock by 4 */
TC_CLOCK_PRESCALER_DIV4 = TC_CTRLA_PRESCALER(2),
/** Divide clock by 8 */
TC_CLOCK_PRESCALER_DIV8 = TC_CTRLA_PRESCALER(3),
/** Divide clock by 16 */
TC_CLOCK_PRESCALER_DIV16 = TC_CTRLA_PRESCALER(4),
/** Divide clock by 64 */
TC_CLOCK_PRESCALER_DIV64 = TC_CTRLA_PRESCALER(5),
/** Divide clock by 256 */
TC_CLOCK_PRESCALER_DIV256 = TC_CTRLA_PRESCALER(6),
/** Divide clock by 1024 */
TC_CLOCK_PRESCALER_DIV1024 = TC_CTRLA_PRESCALER(7),
};
/**
* TC module count direction.
*/
enum tc_count_direction {
/** Timer should count upward from zero to MAX. */
TC_COUNT_DIRECTION_UP,
/** Timer should count downward to zero from MAX. */
TC_COUNT_DIRECTION_DOWN,
};
/**
* Waveform inversion mode.
*/
enum tc_waveform_invert_output {
/** No inversion of the waveform output. */
TC_WAVEFORM_INVERT_OUTPUT_NONE = 0,
/** Invert output from compare channel 0. */
TC_WAVEFORM_INVERT_OUTPUT_CHANNEL_0 = TC_CTRLC_INVEN(1),
/** Invert output from compare channel 1. */
TC_WAVEFORM_INVERT_OUTPUT_CHANNEL_1 = TC_CTRLC_INVEN(2),
};
/**
* Action to perform when the TC module is triggered by an event.
*/
enum tc_event_action {
/** No event action. */
TC_EVENT_ACTION_OFF = TC_EVCTRL_EVACT_OFF,
/** Re-trigger on event. */
TC_EVENT_ACTION_RETRIGGER = TC_EVCTRL_EVACT_RETRIGGER,
/** Increment counter on event. */
TC_EVENT_ACTION_INCREMENT_COUNTER = TC_EVCTRL_EVACT_COUNT,
/** Start counter on event. */
TC_EVENT_ACTION_START = TC_EVCTRL_EVACT_START,
/** Store period in capture register 0, pulse width in capture
* register 1.
*/
TC_EVENT_ACTION_PPW = TC_EVCTRL_EVACT_PPW,
/** Store pulse width in capture register 0, period in capture
* register 1.
*/
TC_EVENT_ACTION_PWP = TC_EVCTRL_EVACT_PWP,
};
/**
* TC event enable/disable structure.
*/
struct tc_events {
/** Generate an output event on a compare channel match. */
bool generate_event_on_compare_channel
[NUMBER_OF_COMPARE_CAPTURE_CHANNELS];
/** Generate an output event on counter overflow. */
bool generate_event_on_overflow;
/** Perform the configured event action when an incoming event is signalled. */
bool on_event_perform_action;
/** Specifies if the input event source is inverted, when used in PWP or
* PPW event action modes.
*/
bool invert_event_input;
/** Specifies which event to trigger if an event is triggered. */
enum tc_event_action event_action;
};
/**
* \brief Configuration struct for TC module in 32-bit size counter mode.
*/
struct tc_pwm_channel {
/** When \c true, PWM output for the given channel is enabled. */
bool enabled;
/** Specifies pin output for each channel. */
uint32_t pin_out;
/** Specifies MUX setting for each output channel pin. */
uint32_t pin_mux;
};
static inline void tc_enable(Tc* const hw);
static inline void tc_disable(Tc* const hw);
static inline void tc_start_counter(Tc* const hw);
static inline void tc_stop_counter(Tc* const hw);
static inline uint32_t tc_get_status(Tc* const hw);
static inline void tc_clear_status(Tc* const hw,
const uint32_t status_flags);
void tc_set_count_value(Tc* const hw, const uint32_t count);
uint32_t tc_get_count_value(Tc* const hw);
uint32_t tc_get_capture_value(Tc* const hw,
const enum tc_compare_capture_channel channel_index);
void tc_set_compare_value(Tc* const hw,
const enum tc_compare_capture_channel channel_index,
const uint32_t compare);
const Tc* tc_get_slave_instance(Tc* const hw);
void tc_reset(Tc* const hw);
void tc_set_top_value (Tc* const hw,
const uint32_t top_value);
static inline void tc_enable_events(Tc* const hw,
struct tc_events *const events);
static inline void tc_disable_events(Tc* const hw,
struct tc_events *const events);
enum tc_status_t tc_init(Tc* const hw,
enum gclk_generator source_clock,
enum tc_counter_size counter_size, /* 8, 16 or 32bit */
enum tc_clock_prescaler clock_prescaler,
enum tc_wave_generation wave_generation,
enum tc_reload_action reload_action,
enum tc_count_direction count_direction,
uint8_t waveform_invert_output,
bool oneshot,
bool run_in_standby,
uint32_t value,
uint32_t top_value,
bool* enable_capture_channels,
uint32_t* compare_channel_values);
#endif /* TC_H_INCLUDED */

Wyświetl plik

@ -0,0 +1,73 @@
/*
* Macros for defining and operating on double buffers
* Copyright (C) 2014 Richard Meadows <richardeoin>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef DBUFFER_H
#define DBUFFER_H
/**
* Double buffer implementation for single types
*/
#define DBUFFER_T(t) \
struct { \
t buffers[2]; \
uint8_t index; \
}
#define DBUFFER_INIT(db_ptr) do{ \
(db_ptr)->index = 0; } while (0)
#define DBUFFER_WRITE(db_ptr, val) do { \
(db_ptr)->buffers[(db_ptr)->index] = val; } while (0)
#define DBUFFER_SWAP(db_ptr) do { \
(db_ptr)->index ^= 0x1; } while (0)
#define DBUFFER_READ(db_ptr) \
(db_ptr)->buffers[(db_ptr)->index ^ 0x1]
/**
* Double buffer implementation for arrays
*/
#define ARRAY_DBUFFER_T(t, n) \
struct { \
t buffers[2][n]; \
uint8_t index; \
}
#define ARRAY_DBUFFER_INIT DBUFFER_INIT
/**
* Functions for the data source. The data source owns the pointer
* returned by ARRAY_DBUFFER_WRITE_PTR until it calls
* ARRAY_DBUFFER_SWAP.
*/
#define ARRAY_DBUFFER_WRITE_PTR(db_ptr) \
(db_ptr)->buffers[(db_ptr)->index]
#define ARRAY_DBUFFER_SWAP DBUFFER_SWAP
/**
* Functions for the data sink. The pointer returned by
* ARRAY_DBUFFER_READ_PTR is immediately invalid unless called in a
* critical section. This is as the data source could be operating in
* a higher IRQ context.
*/
#define ARRAY_DBUFFER_READ_PTR(db_ptr) \
(db_ptr)->buffers[(db_ptr)->index ^ 0x1]
#endif /* DBUFFER_H */

Wyświetl plik

@ -0,0 +1,581 @@
/**
* Preprocessor macro recursion utils.
*
* Copyright (C) 2013-2014 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#ifndef _MRECURSION_H_
#define _MRECURSION_H_
#define DEC_256 255
#define DEC_255 254
#define DEC_254 253
#define DEC_253 252
#define DEC_252 251
#define DEC_251 250
#define DEC_250 249
#define DEC_249 248
#define DEC_248 247
#define DEC_247 246
#define DEC_246 245
#define DEC_245 244
#define DEC_244 243
#define DEC_243 242
#define DEC_242 241
#define DEC_241 240
#define DEC_240 239
#define DEC_239 238
#define DEC_238 237
#define DEC_237 236
#define DEC_236 235
#define DEC_235 234
#define DEC_234 233
#define DEC_233 232
#define DEC_232 231
#define DEC_231 230
#define DEC_230 229
#define DEC_229 228
#define DEC_228 227
#define DEC_227 226
#define DEC_226 225
#define DEC_225 224
#define DEC_224 223
#define DEC_223 222
#define DEC_222 221
#define DEC_221 220
#define DEC_220 219
#define DEC_219 218
#define DEC_218 217
#define DEC_217 216
#define DEC_216 215
#define DEC_215 214
#define DEC_214 213
#define DEC_213 212
#define DEC_212 211
#define DEC_211 210
#define DEC_210 209
#define DEC_209 208
#define DEC_208 207
#define DEC_207 206
#define DEC_206 205
#define DEC_205 204
#define DEC_204 203
#define DEC_203 202
#define DEC_202 201
#define DEC_201 200
#define DEC_200 199
#define DEC_199 198
#define DEC_198 197
#define DEC_197 196
#define DEC_196 195
#define DEC_195 194
#define DEC_194 193
#define DEC_193 192
#define DEC_192 191
#define DEC_191 190
#define DEC_190 189
#define DEC_189 188
#define DEC_188 187
#define DEC_187 186
#define DEC_186 185
#define DEC_185 184
#define DEC_184 183
#define DEC_183 182
#define DEC_182 181
#define DEC_181 180
#define DEC_180 179
#define DEC_179 178
#define DEC_178 177
#define DEC_177 176
#define DEC_176 175
#define DEC_175 174
#define DEC_174 173
#define DEC_173 172
#define DEC_172 171
#define DEC_171 170
#define DEC_170 169
#define DEC_169 168
#define DEC_168 167
#define DEC_167 166
#define DEC_166 165
#define DEC_165 164
#define DEC_164 163
#define DEC_163 162
#define DEC_162 161
#define DEC_161 160
#define DEC_160 159
#define DEC_159 158
#define DEC_158 157
#define DEC_157 156
#define DEC_156 155
#define DEC_155 154
#define DEC_154 153
#define DEC_153 152
#define DEC_152 151
#define DEC_151 150
#define DEC_150 149
#define DEC_149 148
#define DEC_148 147
#define DEC_147 146
#define DEC_146 145
#define DEC_145 144
#define DEC_144 143
#define DEC_143 142
#define DEC_142 141
#define DEC_141 140
#define DEC_140 139
#define DEC_139 138
#define DEC_138 137
#define DEC_137 136
#define DEC_136 135
#define DEC_135 134
#define DEC_134 133
#define DEC_133 132
#define DEC_132 131
#define DEC_131 130
#define DEC_130 129
#define DEC_129 128
#define DEC_128 127
#define DEC_127 126
#define DEC_126 125
#define DEC_125 124
#define DEC_124 123
#define DEC_123 122
#define DEC_122 121
#define DEC_121 120
#define DEC_120 119
#define DEC_119 118
#define DEC_118 117
#define DEC_117 116
#define DEC_116 115
#define DEC_115 114
#define DEC_114 113
#define DEC_113 112
#define DEC_112 111
#define DEC_111 110
#define DEC_110 109
#define DEC_109 108
#define DEC_108 107
#define DEC_107 106
#define DEC_106 105
#define DEC_105 104
#define DEC_104 103
#define DEC_103 102
#define DEC_102 101
#define DEC_101 100
#define DEC_100 99
#define DEC_99 98
#define DEC_98 97
#define DEC_97 96
#define DEC_96 95
#define DEC_95 94
#define DEC_94 93
#define DEC_93 92
#define DEC_92 91
#define DEC_91 90
#define DEC_90 89
#define DEC_89 88
#define DEC_88 87
#define DEC_87 86
#define DEC_86 85
#define DEC_85 84
#define DEC_84 83
#define DEC_83 82
#define DEC_82 81
#define DEC_81 80
#define DEC_80 79
#define DEC_79 78
#define DEC_78 77
#define DEC_77 76
#define DEC_76 75
#define DEC_75 74
#define DEC_74 73
#define DEC_73 72
#define DEC_72 71
#define DEC_71 70
#define DEC_70 69
#define DEC_69 68
#define DEC_68 67
#define DEC_67 66
#define DEC_66 65
#define DEC_65 64
#define DEC_64 63
#define DEC_63 62
#define DEC_62 61
#define DEC_61 60
#define DEC_60 59
#define DEC_59 58
#define DEC_58 57
#define DEC_57 56
#define DEC_56 55
#define DEC_55 54
#define DEC_54 53
#define DEC_53 52
#define DEC_52 51
#define DEC_51 50
#define DEC_50 49
#define DEC_49 48
#define DEC_48 47
#define DEC_47 46
#define DEC_46 45
#define DEC_45 44
#define DEC_44 43
#define DEC_43 42
#define DEC_42 41
#define DEC_41 40
#define DEC_40 39
#define DEC_39 38
#define DEC_38 37
#define DEC_37 36
#define DEC_36 35
#define DEC_35 34
#define DEC_34 33
#define DEC_33 32
#define DEC_32 31
#define DEC_31 30
#define DEC_30 29
#define DEC_29 28
#define DEC_28 27
#define DEC_27 26
#define DEC_26 25
#define DEC_25 24
#define DEC_24 23
#define DEC_23 22
#define DEC_22 21
#define DEC_21 20
#define DEC_20 19
#define DEC_19 18
#define DEC_18 17
#define DEC_17 16
#define DEC_16 15
#define DEC_15 14
#define DEC_14 13
#define DEC_13 12
#define DEC_12 11
#define DEC_11 10
#define DEC_10 9
#define DEC_9 8
#define DEC_8 7
#define DEC_7 6
#define DEC_6 5
#define DEC_5 4
#define DEC_4 3
#define DEC_3 2
#define DEC_2 1
#define DEC_1 0
#define DEC_(n) DEC_##n
/** Maximal number of repetitions supported by MRECURSION. */
#define MRECURSION_LIMIT 256
/** \brief Macro recursion.
*
* This macro represents a horizontal repetition construct.
*
* \param[in] count The number of repetitious calls to macro. Valid values
* range from 0 to MRECURSION_LIMIT.
* \param[in] macro A binary operation of the form macro(data, n). This macro
* is expanded by MRECURSION with the current repetition number
* and the auxiliary data argument.
* \param[in] data A recursive threshold, building on this to decline by times
* defined with param count.
*
* \return <tt>macro(data-count+1,0) macro(data-count+2,1)...macro(data,count-1)</tt>
*/
#define TPASTE2(a, b) a##b
#define MRECURSION(count, macro, data) TPASTE2(MRECURSION, count) (macro, data)
#define MRECURSION0( macro, data)
#define MRECURSION1( macro, data) MRECURSION0( macro, DEC_(data)) macro(data, 0)
#define MRECURSION2( macro, data) MRECURSION1( macro, DEC_(data)) macro(data, 1)
#define MRECURSION3( macro, data) MRECURSION2( macro, DEC_(data)) macro(data, 2)
#define MRECURSION4( macro, data) MRECURSION3( macro, DEC_(data)) macro(data, 3)
#define MRECURSION5( macro, data) MRECURSION4( macro, DEC_(data)) macro(data, 4)
#define MRECURSION6( macro, data) MRECURSION5( macro, DEC_(data)) macro(data, 5)
#define MRECURSION7( macro, data) MRECURSION6( macro, DEC_(data)) macro(data, 6)
#define MRECURSION8( macro, data) MRECURSION7( macro, DEC_(data)) macro(data, 7)
#define MRECURSION9( macro, data) MRECURSION8( macro, DEC_(data)) macro(data, 8)
#define MRECURSION10( macro, data) MRECURSION9( macro, DEC_(data)) macro(data, 9)
#define MRECURSION11( macro, data) MRECURSION10( macro, DEC_(data)) macro(data, 10)
#define MRECURSION12( macro, data) MRECURSION11( macro, DEC_(data)) macro(data, 11)
#define MRECURSION13( macro, data) MRECURSION12( macro, DEC_(data)) macro(data, 12)
#define MRECURSION14( macro, data) MRECURSION13( macro, DEC_(data)) macro(data, 13)
#define MRECURSION15( macro, data) MRECURSION14( macro, DEC_(data)) macro(data, 14)
#define MRECURSION16( macro, data) MRECURSION15( macro, DEC_(data)) macro(data, 15)
#define MRECURSION17( macro, data) MRECURSION16( macro, DEC_(data)) macro(data, 16)
#define MRECURSION18( macro, data) MRECURSION17( macro, DEC_(data)) macro(data, 17)
#define MRECURSION19( macro, data) MRECURSION18( macro, DEC_(data)) macro(data, 18)
#define MRECURSION20( macro, data) MRECURSION19( macro, DEC_(data)) macro(data, 19)
#define MRECURSION21( macro, data) MRECURSION20( macro, DEC_(data)) macro(data, 20)
#define MRECURSION22( macro, data) MRECURSION21( macro, DEC_(data)) macro(data, 21)
#define MRECURSION23( macro, data) MRECURSION22( macro, DEC_(data)) macro(data, 22)
#define MRECURSION24( macro, data) MRECURSION23( macro, DEC_(data)) macro(data, 23)
#define MRECURSION25( macro, data) MRECURSION24( macro, DEC_(data)) macro(data, 24)
#define MRECURSION26( macro, data) MRECURSION25( macro, DEC_(data)) macro(data, 25)
#define MRECURSION27( macro, data) MRECURSION26( macro, DEC_(data)) macro(data, 26)
#define MRECURSION28( macro, data) MRECURSION27( macro, DEC_(data)) macro(data, 27)
#define MRECURSION29( macro, data) MRECURSION28( macro, DEC_(data)) macro(data, 28)
#define MRECURSION30( macro, data) MRECURSION29( macro, DEC_(data)) macro(data, 29)
#define MRECURSION31( macro, data) MRECURSION30( macro, DEC_(data)) macro(data, 30)
#define MRECURSION32( macro, data) MRECURSION31( macro, DEC_(data)) macro(data, 31)
#define MRECURSION33( macro, data) MRECURSION32( macro, DEC_(data)) macro(data, 32)
#define MRECURSION34( macro, data) MRECURSION33( macro, DEC_(data)) macro(data, 33)
#define MRECURSION35( macro, data) MRECURSION34( macro, DEC_(data)) macro(data, 34)
#define MRECURSION36( macro, data) MRECURSION35( macro, DEC_(data)) macro(data, 35)
#define MRECURSION37( macro, data) MRECURSION36( macro, DEC_(data)) macro(data, 36)
#define MRECURSION38( macro, data) MRECURSION37( macro, DEC_(data)) macro(data, 37)
#define MRECURSION39( macro, data) MRECURSION38( macro, DEC_(data)) macro(data, 38)
#define MRECURSION40( macro, data) MRECURSION39( macro, DEC_(data)) macro(data, 39)
#define MRECURSION41( macro, data) MRECURSION40( macro, DEC_(data)) macro(data, 40)
#define MRECURSION42( macro, data) MRECURSION41( macro, DEC_(data)) macro(data, 41)
#define MRECURSION43( macro, data) MRECURSION42( macro, DEC_(data)) macro(data, 42)
#define MRECURSION44( macro, data) MRECURSION43( macro, DEC_(data)) macro(data, 43)
#define MRECURSION45( macro, data) MRECURSION44( macro, DEC_(data)) macro(data, 44)
#define MRECURSION46( macro, data) MRECURSION45( macro, DEC_(data)) macro(data, 45)
#define MRECURSION47( macro, data) MRECURSION46( macro, DEC_(data)) macro(data, 46)
#define MRECURSION48( macro, data) MRECURSION47( macro, DEC_(data)) macro(data, 47)
#define MRECURSION49( macro, data) MRECURSION48( macro, DEC_(data)) macro(data, 48)
#define MRECURSION50( macro, data) MRECURSION49( macro, DEC_(data)) macro(data, 49)
#define MRECURSION51( macro, data) MRECURSION50( macro, DEC_(data)) macro(data, 50)
#define MRECURSION52( macro, data) MRECURSION51( macro, DEC_(data)) macro(data, 51)
#define MRECURSION53( macro, data) MRECURSION52( macro, DEC_(data)) macro(data, 52)
#define MRECURSION54( macro, data) MRECURSION53( macro, DEC_(data)) macro(data, 53)
#define MRECURSION55( macro, data) MRECURSION54( macro, DEC_(data)) macro(data, 54)
#define MRECURSION56( macro, data) MRECURSION55( macro, DEC_(data)) macro(data, 55)
#define MRECURSION57( macro, data) MRECURSION56( macro, DEC_(data)) macro(data, 56)
#define MRECURSION58( macro, data) MRECURSION57( macro, DEC_(data)) macro(data, 57)
#define MRECURSION59( macro, data) MRECURSION58( macro, DEC_(data)) macro(data, 58)
#define MRECURSION60( macro, data) MRECURSION59( macro, DEC_(data)) macro(data, 59)
#define MRECURSION61( macro, data) MRECURSION60( macro, DEC_(data)) macro(data, 60)
#define MRECURSION62( macro, data) MRECURSION61( macro, DEC_(data)) macro(data, 61)
#define MRECURSION63( macro, data) MRECURSION62( macro, DEC_(data)) macro(data, 62)
#define MRECURSION64( macro, data) MRECURSION63( macro, DEC_(data)) macro(data, 63)
#define MRECURSION65( macro, data) MRECURSION64( macro, DEC_(data)) macro(data, 64)
#define MRECURSION66( macro, data) MRECURSION65( macro, DEC_(data)) macro(data, 65)
#define MRECURSION67( macro, data) MRECURSION66( macro, DEC_(data)) macro(data, 66)
#define MRECURSION68( macro, data) MRECURSION67( macro, DEC_(data)) macro(data, 67)
#define MRECURSION69( macro, data) MRECURSION68( macro, DEC_(data)) macro(data, 68)
#define MRECURSION70( macro, data) MRECURSION69( macro, DEC_(data)) macro(data, 69)
#define MRECURSION71( macro, data) MRECURSION70( macro, DEC_(data)) macro(data, 70)
#define MRECURSION72( macro, data) MRECURSION71( macro, DEC_(data)) macro(data, 71)
#define MRECURSION73( macro, data) MRECURSION72( macro, DEC_(data)) macro(data, 72)
#define MRECURSION74( macro, data) MRECURSION73( macro, DEC_(data)) macro(data, 73)
#define MRECURSION75( macro, data) MRECURSION74( macro, DEC_(data)) macro(data, 74)
#define MRECURSION76( macro, data) MRECURSION75( macro, DEC_(data)) macro(data, 75)
#define MRECURSION77( macro, data) MRECURSION76( macro, DEC_(data)) macro(data, 76)
#define MRECURSION78( macro, data) MRECURSION77( macro, DEC_(data)) macro(data, 77)
#define MRECURSION79( macro, data) MRECURSION78( macro, DEC_(data)) macro(data, 78)
#define MRECURSION80( macro, data) MRECURSION79( macro, DEC_(data)) macro(data, 79)
#define MRECURSION81( macro, data) MRECURSION80( macro, DEC_(data)) macro(data, 80)
#define MRECURSION82( macro, data) MRECURSION81( macro, DEC_(data)) macro(data, 81)
#define MRECURSION83( macro, data) MRECURSION82( macro, DEC_(data)) macro(data, 82)
#define MRECURSION84( macro, data) MRECURSION83( macro, DEC_(data)) macro(data, 83)
#define MRECURSION85( macro, data) MRECURSION84( macro, DEC_(data)) macro(data, 84)
#define MRECURSION86( macro, data) MRECURSION85( macro, DEC_(data)) macro(data, 85)
#define MRECURSION87( macro, data) MRECURSION86( macro, DEC_(data)) macro(data, 86)
#define MRECURSION88( macro, data) MRECURSION87( macro, DEC_(data)) macro(data, 87)
#define MRECURSION89( macro, data) MRECURSION88( macro, DEC_(data)) macro(data, 88)
#define MRECURSION90( macro, data) MRECURSION89( macro, DEC_(data)) macro(data, 89)
#define MRECURSION91( macro, data) MRECURSION90( macro, DEC_(data)) macro(data, 90)
#define MRECURSION92( macro, data) MRECURSION91( macro, DEC_(data)) macro(data, 91)
#define MRECURSION93( macro, data) MRECURSION92( macro, DEC_(data)) macro(data, 92)
#define MRECURSION94( macro, data) MRECURSION93( macro, DEC_(data)) macro(data, 93)
#define MRECURSION95( macro, data) MRECURSION94( macro, DEC_(data)) macro(data, 94)
#define MRECURSION96( macro, data) MRECURSION95( macro, DEC_(data)) macro(data, 95)
#define MRECURSION97( macro, data) MRECURSION96( macro, DEC_(data)) macro(data, 96)
#define MRECURSION98( macro, data) MRECURSION97( macro, DEC_(data)) macro(data, 97)
#define MRECURSION99( macro, data) MRECURSION98( macro, DEC_(data)) macro(data, 98)
#define MRECURSION100(macro, data) MRECURSION99( macro, DEC_(data)) macro(data, 99)
#define MRECURSION101(macro, data) MRECURSION100( macro, DEC_(data)) macro(data, 100)
#define MRECURSION102(macro, data) MRECURSION101( macro, DEC_(data)) macro(data, 101)
#define MRECURSION103(macro, data) MRECURSION102( macro, DEC_(data)) macro(data, 102)
#define MRECURSION104(macro, data) MRECURSION103( macro, DEC_(data)) macro(data, 103)
#define MRECURSION105(macro, data) MRECURSION104( macro, DEC_(data)) macro(data, 104)
#define MRECURSION106(macro, data) MRECURSION105( macro, DEC_(data)) macro(data, 105)
#define MRECURSION107(macro, data) MRECURSION106( macro, DEC_(data)) macro(data, 106)
#define MRECURSION108(macro, data) MRECURSION107( macro, DEC_(data)) macro(data, 107)
#define MRECURSION109(macro, data) MRECURSION108( macro, DEC_(data)) macro(data, 108)
#define MRECURSION110(macro, data) MRECURSION109( macro, DEC_(data)) macro(data, 109)
#define MRECURSION111(macro, data) MRECURSION110( macro, DEC_(data)) macro(data, 110)
#define MRECURSION112(macro, data) MRECURSION111( macro, DEC_(data)) macro(data, 111)
#define MRECURSION113(macro, data) MRECURSION112( macro, DEC_(data)) macro(data, 112)
#define MRECURSION114(macro, data) MRECURSION113( macro, DEC_(data)) macro(data, 113)
#define MRECURSION115(macro, data) MRECURSION114( macro, DEC_(data)) macro(data, 114)
#define MRECURSION116(macro, data) MRECURSION115( macro, DEC_(data)) macro(data, 115)
#define MRECURSION117(macro, data) MRECURSION116( macro, DEC_(data)) macro(data, 116)
#define MRECURSION118(macro, data) MRECURSION117( macro, DEC_(data)) macro(data, 117)
#define MRECURSION119(macro, data) MRECURSION118( macro, DEC_(data)) macro(data, 118)
#define MRECURSION120(macro, data) MRECURSION119( macro, DEC_(data)) macro(data, 119)
#define MRECURSION121(macro, data) MRECURSION120( macro, DEC_(data)) macro(data, 120)
#define MRECURSION122(macro, data) MRECURSION121( macro, DEC_(data)) macro(data, 121)
#define MRECURSION123(macro, data) MRECURSION122( macro, DEC_(data)) macro(data, 122)
#define MRECURSION124(macro, data) MRECURSION123( macro, DEC_(data)) macro(data, 123)
#define MRECURSION125(macro, data) MRECURSION124( macro, DEC_(data)) macro(data, 124)
#define MRECURSION126(macro, data) MRECURSION125( macro, DEC_(data)) macro(data, 125)
#define MRECURSION127(macro, data) MRECURSION126( macro, DEC_(data)) macro(data, 126)
#define MRECURSION128(macro, data) MRECURSION127( macro, DEC_(data)) macro(data, 127)
#define MRECURSION129(macro, data) MRECURSION128( macro, DEC_(data)) macro(data, 128)
#define MRECURSION130(macro, data) MRECURSION129( macro, DEC_(data)) macro(data, 129)
#define MRECURSION131(macro, data) MRECURSION130( macro, DEC_(data)) macro(data, 130)
#define MRECURSION132(macro, data) MRECURSION131( macro, DEC_(data)) macro(data, 131)
#define MRECURSION133(macro, data) MRECURSION132( macro, DEC_(data)) macro(data, 132)
#define MRECURSION134(macro, data) MRECURSION133( macro, DEC_(data)) macro(data, 133)
#define MRECURSION135(macro, data) MRECURSION134( macro, DEC_(data)) macro(data, 134)
#define MRECURSION136(macro, data) MRECURSION135( macro, DEC_(data)) macro(data, 135)
#define MRECURSION137(macro, data) MRECURSION136( macro, DEC_(data)) macro(data, 136)
#define MRECURSION138(macro, data) MRECURSION137( macro, DEC_(data)) macro(data, 137)
#define MRECURSION139(macro, data) MRECURSION138( macro, DEC_(data)) macro(data, 138)
#define MRECURSION140(macro, data) MRECURSION139( macro, DEC_(data)) macro(data, 139)
#define MRECURSION141(macro, data) MRECURSION140( macro, DEC_(data)) macro(data, 140)
#define MRECURSION142(macro, data) MRECURSION141( macro, DEC_(data)) macro(data, 141)
#define MRECURSION143(macro, data) MRECURSION142( macro, DEC_(data)) macro(data, 142)
#define MRECURSION144(macro, data) MRECURSION143( macro, DEC_(data)) macro(data, 143)
#define MRECURSION145(macro, data) MRECURSION144( macro, DEC_(data)) macro(data, 144)
#define MRECURSION146(macro, data) MRECURSION145( macro, DEC_(data)) macro(data, 145)
#define MRECURSION147(macro, data) MRECURSION146( macro, DEC_(data)) macro(data, 146)
#define MRECURSION148(macro, data) MRECURSION147( macro, DEC_(data)) macro(data, 147)
#define MRECURSION149(macro, data) MRECURSION148( macro, DEC_(data)) macro(data, 148)
#define MRECURSION150(macro, data) MRECURSION149( macro, DEC_(data)) macro(data, 149)
#define MRECURSION151(macro, data) MRECURSION150( macro, DEC_(data)) macro(data, 150)
#define MRECURSION152(macro, data) MRECURSION151( macro, DEC_(data)) macro(data, 151)
#define MRECURSION153(macro, data) MRECURSION152( macro, DEC_(data)) macro(data, 152)
#define MRECURSION154(macro, data) MRECURSION153( macro, DEC_(data)) macro(data, 153)
#define MRECURSION155(macro, data) MRECURSION154( macro, DEC_(data)) macro(data, 154)
#define MRECURSION156(macro, data) MRECURSION155( macro, DEC_(data)) macro(data, 155)
#define MRECURSION157(macro, data) MRECURSION156( macro, DEC_(data)) macro(data, 156)
#define MRECURSION158(macro, data) MRECURSION157( macro, DEC_(data)) macro(data, 157)
#define MRECURSION159(macro, data) MRECURSION158( macro, DEC_(data)) macro(data, 158)
#define MRECURSION160(macro, data) MRECURSION159( macro, DEC_(data)) macro(data, 159)
#define MRECURSION161(macro, data) MRECURSION160( macro, DEC_(data)) macro(data, 160)
#define MRECURSION162(macro, data) MRECURSION161( macro, DEC_(data)) macro(data, 161)
#define MRECURSION163(macro, data) MRECURSION162( macro, DEC_(data)) macro(data, 162)
#define MRECURSION164(macro, data) MRECURSION163( macro, DEC_(data)) macro(data, 163)
#define MRECURSION165(macro, data) MRECURSION164( macro, DEC_(data)) macro(data, 164)
#define MRECURSION166(macro, data) MRECURSION165( macro, DEC_(data)) macro(data, 165)
#define MRECURSION167(macro, data) MRECURSION166( macro, DEC_(data)) macro(data, 166)
#define MRECURSION168(macro, data) MRECURSION167( macro, DEC_(data)) macro(data, 167)
#define MRECURSION169(macro, data) MRECURSION168( macro, DEC_(data)) macro(data, 168)
#define MRECURSION170(macro, data) MRECURSION169( macro, DEC_(data)) macro(data, 169)
#define MRECURSION171(macro, data) MRECURSION170( macro, DEC_(data)) macro(data, 170)
#define MRECURSION172(macro, data) MRECURSION171( macro, DEC_(data)) macro(data, 171)
#define MRECURSION173(macro, data) MRECURSION172( macro, DEC_(data)) macro(data, 172)
#define MRECURSION174(macro, data) MRECURSION173( macro, DEC_(data)) macro(data, 173)
#define MRECURSION175(macro, data) MRECURSION174( macro, DEC_(data)) macro(data, 174)
#define MRECURSION176(macro, data) MRECURSION175( macro, DEC_(data)) macro(data, 175)
#define MRECURSION177(macro, data) MRECURSION176( macro, DEC_(data)) macro(data, 176)
#define MRECURSION178(macro, data) MRECURSION177( macro, DEC_(data)) macro(data, 177)
#define MRECURSION179(macro, data) MRECURSION178( macro, DEC_(data)) macro(data, 178)
#define MRECURSION180(macro, data) MRECURSION179( macro, DEC_(data)) macro(data, 179)
#define MRECURSION181(macro, data) MRECURSION180( macro, DEC_(data)) macro(data, 180)
#define MRECURSION182(macro, data) MRECURSION181( macro, DEC_(data)) macro(data, 181)
#define MRECURSION183(macro, data) MRECURSION182( macro, DEC_(data)) macro(data, 182)
#define MRECURSION184(macro, data) MRECURSION183( macro, DEC_(data)) macro(data, 183)
#define MRECURSION185(macro, data) MRECURSION184( macro, DEC_(data)) macro(data, 184)
#define MRECURSION186(macro, data) MRECURSION185( macro, DEC_(data)) macro(data, 185)
#define MRECURSION187(macro, data) MRECURSION186( macro, DEC_(data)) macro(data, 186)
#define MRECURSION188(macro, data) MRECURSION187( macro, DEC_(data)) macro(data, 187)
#define MRECURSION189(macro, data) MRECURSION188( macro, DEC_(data)) macro(data, 188)
#define MRECURSION190(macro, data) MRECURSION189( macro, DEC_(data)) macro(data, 189)
#define MRECURSION191(macro, data) MRECURSION190( macro, DEC_(data)) macro(data, 190)
#define MRECURSION192(macro, data) MRECURSION191( macro, DEC_(data)) macro(data, 191)
#define MRECURSION193(macro, data) MRECURSION192( macro, DEC_(data)) macro(data, 192)
#define MRECURSION194(macro, data) MRECURSION193( macro, DEC_(data)) macro(data, 193)
#define MRECURSION195(macro, data) MRECURSION194( macro, DEC_(data)) macro(data, 194)
#define MRECURSION196(macro, data) MRECURSION195( macro, DEC_(data)) macro(data, 195)
#define MRECURSION197(macro, data) MRECURSION196( macro, DEC_(data)) macro(data, 196)
#define MRECURSION198(macro, data) MRECURSION197( macro, DEC_(data)) macro(data, 197)
#define MRECURSION199(macro, data) MRECURSION198( macro, DEC_(data)) macro(data, 198)
#define MRECURSION200(macro, data) MRECURSION199( macro, DEC_(data)) macro(data, 199)
#define MRECURSION201(macro, data) MRECURSION200( macro, DEC_(data)) macro(data, 200)
#define MRECURSION202(macro, data) MRECURSION201( macro, DEC_(data)) macro(data, 201)
#define MRECURSION203(macro, data) MRECURSION202( macro, DEC_(data)) macro(data, 202)
#define MRECURSION204(macro, data) MRECURSION203( macro, DEC_(data)) macro(data, 203)
#define MRECURSION205(macro, data) MRECURSION204( macro, DEC_(data)) macro(data, 204)
#define MRECURSION206(macro, data) MRECURSION205( macro, DEC_(data)) macro(data, 205)
#define MRECURSION207(macro, data) MRECURSION206( macro, DEC_(data)) macro(data, 206)
#define MRECURSION208(macro, data) MRECURSION207( macro, DEC_(data)) macro(data, 207)
#define MRECURSION209(macro, data) MRECURSION208( macro, DEC_(data)) macro(data, 208)
#define MRECURSION210(macro, data) MRECURSION209( macro, DEC_(data)) macro(data, 209)
#define MRECURSION211(macro, data) MRECURSION210( macro, DEC_(data)) macro(data, 210)
#define MRECURSION212(macro, data) MRECURSION211( macro, DEC_(data)) macro(data, 211)
#define MRECURSION213(macro, data) MRECURSION212( macro, DEC_(data)) macro(data, 212)
#define MRECURSION214(macro, data) MRECURSION213( macro, DEC_(data)) macro(data, 213)
#define MRECURSION215(macro, data) MRECURSION214( macro, DEC_(data)) macro(data, 214)
#define MRECURSION216(macro, data) MRECURSION215( macro, DEC_(data)) macro(data, 215)
#define MRECURSION217(macro, data) MRECURSION216( macro, DEC_(data)) macro(data, 216)
#define MRECURSION218(macro, data) MRECURSION217( macro, DEC_(data)) macro(data, 217)
#define MRECURSION219(macro, data) MRECURSION218( macro, DEC_(data)) macro(data, 218)
#define MRECURSION220(macro, data) MRECURSION219( macro, DEC_(data)) macro(data, 219)
#define MRECURSION221(macro, data) MRECURSION220( macro, DEC_(data)) macro(data, 220)
#define MRECURSION222(macro, data) MRECURSION221( macro, DEC_(data)) macro(data, 221)
#define MRECURSION223(macro, data) MRECURSION222( macro, DEC_(data)) macro(data, 222)
#define MRECURSION224(macro, data) MRECURSION223( macro, DEC_(data)) macro(data, 223)
#define MRECURSION225(macro, data) MRECURSION224( macro, DEC_(data)) macro(data, 224)
#define MRECURSION226(macro, data) MRECURSION225( macro, DEC_(data)) macro(data, 225)
#define MRECURSION227(macro, data) MRECURSION226( macro, DEC_(data)) macro(data, 226)
#define MRECURSION228(macro, data) MRECURSION227( macro, DEC_(data)) macro(data, 227)
#define MRECURSION229(macro, data) MRECURSION228( macro, DEC_(data)) macro(data, 228)
#define MRECURSION230(macro, data) MRECURSION229( macro, DEC_(data)) macro(data, 229)
#define MRECURSION231(macro, data) MRECURSION230( macro, DEC_(data)) macro(data, 230)
#define MRECURSION232(macro, data) MRECURSION231( macro, DEC_(data)) macro(data, 231)
#define MRECURSION233(macro, data) MRECURSION232( macro, DEC_(data)) macro(data, 232)
#define MRECURSION234(macro, data) MRECURSION233( macro, DEC_(data)) macro(data, 233)
#define MRECURSION235(macro, data) MRECURSION234( macro, DEC_(data)) macro(data, 234)
#define MRECURSION236(macro, data) MRECURSION235( macro, DEC_(data)) macro(data, 235)
#define MRECURSION237(macro, data) MRECURSION236( macro, DEC_(data)) macro(data, 236)
#define MRECURSION238(macro, data) MRECURSION237( macro, DEC_(data)) macro(data, 237)
#define MRECURSION239(macro, data) MRECURSION238( macro, DEC_(data)) macro(data, 238)
#define MRECURSION240(macro, data) MRECURSION239( macro, DEC_(data)) macro(data, 239)
#define MRECURSION241(macro, data) MRECURSION240( macro, DEC_(data)) macro(data, 240)
#define MRECURSION242(macro, data) MRECURSION241( macro, DEC_(data)) macro(data, 241)
#define MRECURSION243(macro, data) MRECURSION242( macro, DEC_(data)) macro(data, 242)
#define MRECURSION244(macro, data) MRECURSION243( macro, DEC_(data)) macro(data, 243)
#define MRECURSION245(macro, data) MRECURSION244( macro, DEC_(data)) macro(data, 244)
#define MRECURSION246(macro, data) MRECURSION245( macro, DEC_(data)) macro(data, 245)
#define MRECURSION247(macro, data) MRECURSION246( macro, DEC_(data)) macro(data, 246)
#define MRECURSION248(macro, data) MRECURSION247( macro, DEC_(data)) macro(data, 247)
#define MRECURSION249(macro, data) MRECURSION248( macro, DEC_(data)) macro(data, 248)
#define MRECURSION250(macro, data) MRECURSION249( macro, DEC_(data)) macro(data, 249)
#define MRECURSION251(macro, data) MRECURSION250( macro, DEC_(data)) macro(data, 250)
#define MRECURSION252(macro, data) MRECURSION251( macro, DEC_(data)) macro(data, 251)
#define MRECURSION253(macro, data) MRECURSION252( macro, DEC_(data)) macro(data, 252)
#define MRECURSION254(macro, data) MRECURSION253( macro, DEC_(data)) macro(data, 253)
#define MRECURSION255(macro, data) MRECURSION254( macro, DEC_(data)) macro(data, 254)
#define MRECURSION256(macro, data) MRECURSION255( macro, DEC_(data)) macro(data, 255)
#endif /* _MRECURSION_H_ */

Wyświetl plik

@ -44,6 +44,9 @@
#ifndef _SAMD20E14_
#define _SAMD20E14_
#define SAMD20
#define SAMD20E
/**
* \ingroup SAMD20_definitions
* \addtogroup SAMD20E14_definitions SAMD20E14 definitions
@ -209,7 +212,7 @@ void PTC_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#define LITTLE_ENDIAN 1
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

Wyświetl plik

@ -44,6 +44,9 @@
#ifndef _SAMD20E15_
#define _SAMD20E15_
#define SAMD20
#define SAMD20E
/**
* \ingroup SAMD20_definitions
* \addtogroup SAMD20E15_definitions SAMD20E15 definitions
@ -209,7 +212,7 @@ void PTC_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#define LITTLE_ENDIAN 1
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

Wyświetl plik

@ -44,6 +44,9 @@
#ifndef _SAMD20E16_
#define _SAMD20E16_
#define SAMD20
#define SAMD20E
/**
* \ingroup SAMD20_definitions
* \addtogroup SAMD20E16_definitions SAMD20E16 definitions
@ -209,7 +212,7 @@ void PTC_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#define LITTLE_ENDIAN 1
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

Wyświetl plik

@ -44,6 +44,9 @@
#ifndef _SAMD20E17_
#define _SAMD20E17_
#define SAMD20
#define SAMD20E
/**
* \ingroup SAMD20_definitions
* \addtogroup SAMD20E17_definitions SAMD20E17 definitions
@ -209,7 +212,7 @@ void PTC_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#define LITTLE_ENDIAN 1
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

Wyświetl plik

@ -44,6 +44,9 @@
#ifndef _SAMD20E18_
#define _SAMD20E18_
#define SAMD20
#define SAMD20E
/**
* \ingroup SAMD20_definitions
* \addtogroup SAMD20E18_definitions SAMD20E18 definitions
@ -209,7 +212,7 @@ void PTC_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#define LITTLE_ENDIAN 1
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

Wyświetl plik

@ -44,6 +44,9 @@
#ifndef _SAMD20G14_
#define _SAMD20G14_
#define SAMD20
#define SAMD20G
/**
* \ingroup SAMD20_definitions
* \addtogroup SAMD20G14_definitions SAMD20G14 definitions
@ -217,7 +220,7 @@ void PTC_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#define LITTLE_ENDIAN 1
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

Wyświetl plik

@ -44,6 +44,9 @@
#ifndef _SAMD20G15_
#define _SAMD20G15_
#define SAMD20
#define SAMD20G
/**
* \ingroup SAMD20_definitions
* \addtogroup SAMD20G15_definitions SAMD20G15 definitions
@ -217,7 +220,7 @@ void PTC_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#define LITTLE_ENDIAN 1
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

Wyświetl plik

@ -44,6 +44,9 @@
#ifndef _SAMD20G16_
#define _SAMD20G16_
#define SAMD20
#define SAMD20G
/**
* \ingroup SAMD20_definitions
* \addtogroup SAMD20G16_definitions SAMD20G16 definitions
@ -217,7 +220,7 @@ void PTC_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#define LITTLE_ENDIAN 1
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

Wyświetl plik

@ -44,6 +44,9 @@
#ifndef _SAMD20G17_
#define _SAMD20G17_
#define SAMD20
#define SAMD20G
/**
* \ingroup SAMD20_definitions
* \addtogroup SAMD20G17_definitions SAMD20G17 definitions
@ -217,7 +220,7 @@ void PTC_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#define LITTLE_ENDIAN 1
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

Wyświetl plik

@ -44,6 +44,9 @@
#ifndef _SAMD20G18_
#define _SAMD20G18_
#define SAMD20
#define SAMD20G
/**
* \ingroup SAMD20_definitions
* \addtogroup SAMD20G18_definitions SAMD20G18 definitions
@ -217,7 +220,7 @@ void PTC_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#define LITTLE_ENDIAN 1
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

Wyświetl plik

@ -44,6 +44,9 @@
#ifndef _SAMD20J14_
#define _SAMD20J14_
#define SAMD20
#define SAMD20J
/**
* \ingroup SAMD20_definitions
* \addtogroup SAMD20J14_definitions SAMD20J14 definitions
@ -217,7 +220,7 @@ void PTC_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#define LITTLE_ENDIAN 1
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

Wyświetl plik

@ -44,6 +44,9 @@
#ifndef _SAMD20J15_
#define _SAMD20J15_
#define SAMD20
#define SAMD20J
/**
* \ingroup SAMD20_definitions
* \addtogroup SAMD20J15_definitions SAMD20J15 definitions
@ -217,7 +220,7 @@ void PTC_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#define LITTLE_ENDIAN 1
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

Wyświetl plik

@ -44,6 +44,9 @@
#ifndef _SAMD20J16_
#define _SAMD20J16_
#define SAMD20
#define SAMD20J
/**
* \ingroup SAMD20_definitions
* \addtogroup SAMD20J16_definitions SAMD20J16 definitions
@ -217,7 +220,7 @@ void PTC_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#define LITTLE_ENDIAN 1
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

Wyświetl plik

@ -44,6 +44,9 @@
#ifndef _SAMD20J17_
#define _SAMD20J17_
#define SAMD20
#define SAMD20J
/**
* \ingroup SAMD20_definitions
* \addtogroup SAMD20J17_definitions SAMD20J17 definitions
@ -217,7 +220,7 @@ void PTC_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#define LITTLE_ENDIAN 1
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

Wyświetl plik

@ -44,6 +44,9 @@
#ifndef _SAMD20J18_
#define _SAMD20J18_
#define SAMD20
#define SAMD20J
/**
* \ingroup SAMD20_definitions
* \addtogroup SAMD20J18_definitions SAMD20J18 definitions
@ -217,7 +220,7 @@ void PTC_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#define LITTLE_ENDIAN 1
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

383
firmware/src/gps.c 100644
Wyświetl plik

@ -0,0 +1,383 @@
/*
* Functions for the UBLOX 6 GPS
* Copyright (C) 2014 Richard Meadows <richardeoin>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <string.h>
#include "samd20.h"
#include "semihosting.h"
#include "hw_config.h"
#include "system/system.h"
#include "system/interrupt.h"
#include "sercom/sercom.h"
#include "sercom/usart.h"
#include "util/dbuffer.h"
#include "gps.h"
/**
* UBX Constants
*/
const uint16_t ubx_header = (0xB5 | (0x62 << 8));
/**
* UBX Class Types
*/
enum {
UBX_NAV = 0x01,
UBX_RXM = 0x02,
UBX_INF = 0x04,
UBX_ACK = 0x05,
UBX_CFG = 0x06,
UBX_MON = 0x0A,
UBX_AID = 0x0B,
UBX_TIM = 0x0D,
UBX_ESF = 0x10,
};
/**
* UBX NAV Message Types
*/
enum {
UBX_NAV_POSLLH = (UBX_NAV | (0x02 << 8)),
UBX_NAV_SOL = (UBX_NAV | (0x06 << 8)),
UBX_NAV_TIMEGPS = (UBX_NAV | (0x20 << 8)),
UBX_NAV_TIMEUTC = (UBX_NAV | (0x21 << 8)),
};
/**
* UBX CFG Message Types
*/
enum {
UBX_CFG_PRT = (UBX_CFG | (0x00 << 8)),
UBX_CFG_ANT = (UBX_CFG | (0x13 << 8)),
UBX_CFG_NAV5 = (UBX_CFG | (0x24 << 8)),
};
/**
* UBX ACK Message Types
*/
enum {
UBX_ACK_NACK = (UBX_ACK | (0x00 << 8)),
UBX_ACK_ACK = (UBX_ACK | (0x01 << 8)),
};
/**
* UBX Dynamic Platform Model
*/
enum {
UBX_PLATFORM_MODEL_PORTABLE = 0,
UBX_PLATFORM_MODEL_STATIONARY = 2,
UBX_PLATFORM_MODEL_PEDESTRIAN = 3,
UBX_PLATFORM_MODEL_AUTOMOTIVE = 4,
UBX_PLATFORM_MODEL_SEA = 5,
UBX_PLATFORM_MODEL_AIRBORNE_1G = 6,
UBX_PLATFORM_MODEL_AIRBORNE_2G = 7,
UBX_PLATFORM_MODEL_AIRBORNE_4G = 8,
};
#define UBX_BUFFER_LEN 0x80
#define SFD1 0xB5
#define SFD2 0x62
enum sfd_state {
SFD_WAITING = -1,
SFD_GOT1,
} sfd_state = SFD_WAITING;
int32_t ubx_index = SFD_WAITING;
uint16_t ubx_payload_length = 0;
uint8_t ubx_irq_buffer[UBX_BUFFER_LEN];
#define _send_buffer(tx_data, length) \
usart_write_buffer_wait(GPS_SERCOM, tx_data, length)
#define _get_buffer(rx_data, length) \
usart_read_buffer_wait(GPS_SERCOM, rx_data, length)
/**
* Macro for the function below
*/
#define UBX_POPULATE_STRUCT(ubx_type) \
if (payload_length == sizeof(ubx_type)) { \
memcpy((void*)&ubx_type, frame + 4, payload_length); \
}
/**
* Process a single ubx frame. Runs in the IRQ so should be short and sweet.
*/
void ubx_process_frame(uint8_t* frame)
{
uint16_t* frame16 = (uint16_t*)frame;
uint16_t payload_length = frame16[1];
/* Checksum.. */
switch (frame[0]) { /* Switch by Class */
case UBX_NAV:
switch (frame16[0]) {
case UBX_NAV_SOL: /* Navigation Solution Information */
UBX_POPULATE_STRUCT(ubx_nav_sol);
break;
case UBX_NAV_TIMEUTC: /* UTC Time Solution */
UBX_POPULATE_STRUCT(ubx_nav_timeutc);
break;
case UBX_NAV_POSLLH: /* Geodetic Position Solution */
UBX_POPULATE_STRUCT(ubx_nav_posllh);
break;
}
break;
case UBX_CFG:
switch (frame16[0]) {
case UBX_CFG_NAV5: /* Navigation Engine Settings */
UBX_POPULATE_STRUCT(ubx_cfg_nav5);
break;
case UBX_CFG_ANT: /* Antenna Control Settings */
UBX_POPULATE_STRUCT(ubx_cfg_ant);
}
break;
case UBX_ACK:
switch (frame16[0]) {
case UBX_ACK_ACK:
break;
case UBX_ACK_NACK:
break;
}
break;
default:
break;
}
}
/**
* Rx Callback. Processes a stream of
*/
void gps_rx_callback(SercomUsart* const hw, uint16_t data)
{
(void)hw;
/* Start of Frame Delimeter 1 */
if (data == SFD1) {
sfd_state = SFD_GOT1;
} else {
/* SFD2 preceeded by SFD1 */
if (sfd_state == SFD_GOT1 && data == SFD2) {
/* Start a new frame */
ubx_index = 0;
ubx_payload_length = 0;
sfd_state = SFD_WAITING;
return;
}
sfd_state = SFD_WAITING;
}
/**
* If we have a valid index. That is:
* We're in a frame
* And we've not reached class/message + length + payload + checksum
* And we've not reached the end of the buffer
*/
if (ubx_index != SFD_WAITING &&
ubx_index < (4 + ubx_payload_length + 2) &&
ubx_index < UBX_BUFFER_LEN) {
/* Data in */
ubx_irq_buffer[ubx_index++] = data;
/* Extract length */
if (ubx_index == 4) {
ubx_payload_length = ((uint16_t*)ubx_irq_buffer)[1];
}
/* Complete Frame? */
if (ubx_index >= (4 + ubx_payload_length + 2)) {
/* Process it */
ubx_process_frame(ubx_irq_buffer);
}
}
}
/**
* Calculate a UBX checksum using 8-bit Fletcher (RFC1145)
*/
uint16_t _ubx_checksum(uint8_t* data, uint8_t len)
{
uint16_t ck = 0;
uint8_t* cka = (uint8_t*)&ck;
uint8_t* ckb = (cka + 1);
for(uint8_t i = 0; i < len; i++) {
*cka += *data;
*ckb += *cka;
data++;
}
return ck;
}
/**
* Sends a standard UBX message
*/
void _ubx_send_message(uint16_t message, uint8_t* payload, uint16_t length)
{
uint8_t ubx[UBX_BUFFER_LEN];
uint8_t* ubx_buffer = ubx;
/* Copy little endian */
memcpy(ubx_buffer, &ubx_header, 2); ubx_buffer += 2; /* Header */
memcpy(ubx_buffer, &message, 2); ubx_buffer += 2; /* Message Type */
memcpy(ubx_buffer, &length, 2); ubx_buffer += 2; /* Length */
memcpy(ubx_buffer, payload, length); ubx_buffer += length; /* Payload*/
uint16_t checksum = _ubx_checksum(ubx + 2, length + 4);
memcpy(ubx_buffer, &checksum, 2); ubx_buffer += 2; /* Checksum */
_send_buffer(ubx, length + 8);
}
/**
* Sends a UBX Poll Request
*/
void _ubx_poll(uint16_t message) {
_ubx_send_message(message, NULL, 0);
}
/**
* Disable NMEA messages on the uBlox
*/
void gps_disable_nmea(void)
{
for (int i = 0; i < 1000*100; i++);
uint8_t setNMEAoff[] = {
0x01, 0x00, 0x00, 0x00, 0xD0, 0x08, 0x00, 0x00, 0x80, 0x25,
0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
};
_ubx_send_message(UBX_CFG_PRT, setNMEAoff, sizeof(setNMEAoff)/sizeof(uint8_t));
for (int i = 0; i < 1000*100; i++);
}
/**
* Check the navigation status to determine the quality of the
* fix currently held by the receiver with a NAV-STATUS message.
*/
void gps_check_lock()
{
/* Send the poll request */
_ubx_poll(UBX_NAV_SOL);
}
/**
* Verify that the uBlox 6 GPS receiver is set to the <1g airborne
* navigaion mode.
*/
void gps_check_nav(void)
{
/* Send the poll request */
_ubx_poll(UBX_CFG_NAV5);
}
/**
* Init
*/
void gps_init(void)
{
/* USART */
usart_init(GPS_SERCOM,
USART_DATAORDER_LSB, /** Bit order (MSB or LSB first) */
USART_TRANSFER_ASYNCHRONOUSLY, /** Asynchronous or synchronous mode */
USART_PARITY_NONE, /** USART parity */
USART_STOPBITS_1, /** Number of stop bits */
USART_CHARACTER_SIZE_8BIT, /** USART character size */
GPS_SERCOM_MUX, /** USART pinout */
false, /** Immediate buffer overflow notification */
false, /** Enable IrDA encoding format */
19, /** Minimum pulse length required for IrDA rx */
false, /** Enable LIN Slave Support */
false, /** Enable start of frame dection */
false, /** Enable collision dection */
9600, /** USART Baud rate */
true, /** Enable receiver */
true, /** Enable transmitter */
false, /** Sample on the rising edge of XLCK */
false, /** Use the external clock applied to the XCK pin. */
0, /** External clock frequency in synchronous mode. */
true, /** Run in standby */
GCLK_GENERATOR_0, /** GCLK generator source */
GPS_SERCOM_MOGI_PINMUX, /** PAD0 pinmux */
GPS_SERCOM_MIGO_PINMUX, /** PAD1 pinmux */
PINMUX_UNUSED, /** PAD2 pinmux */
PINMUX_UNUSED); /** PAD3 pinmux */
usart_enable(GPS_SERCOM);
/* We use ubx protocol */
gps_disable_nmea();
/* Incoming ubx messages are handled in an irq */
usart_register_rx_callback(GPS_SERCOM, gps_rx_callback, 0);
gps_check_nav();
gps_check_lock();
_ubx_poll(UBX_CFG_ANT);
}
/**
* Quick and dirty loopback test. Should print 0x34
*/
void usart_loopback_test(void)
{
uint16_t data;
usart_init(GPS_SERCOM,
USART_DATAORDER_LSB, /** Bit order (MSB or LSB first) */
USART_TRANSFER_ASYNCHRONOUSLY, /** Asynchronous or synchronous mode */
USART_PARITY_NONE, /** USART parity */
USART_STOPBITS_1, /** Number of stop bits */
USART_CHARACTER_SIZE_8BIT, /** USART character size */
USART_MUX_LOOPBACK, /** USART pin out */
false, /** Immediate buffer overflow notification */
false, /** Enable IrDA encoding format */
19, /** Minimum pulse length required for IrDA rx */
false, /** Enable LIN Slave Support */
false, /** Enable start of frame dection */
false, /** Enable collision dection */
9600, /** USART Baud rate */
true, /** Enable receiver */
true, /** Enable transmitter */
false, /** Sample on the rising edge of XLCK */
false, /** Use the external clock applied to the XCK pin. */
0, /** External clock frequency in synchronous mode. */
false, /** Run in standby */
GCLK_GENERATOR_0, /** GCLK generator source */
PINMUX_DEFAULT, /** PAD0 pinmux */
PINMUX_DEFAULT, /** PAD1 pinmux */
PINMUX_UNUSED, /** PAD2 pinmux */
PINMUX_UNUSED); /** PAD3 pinmux */
usart_enable(GPS_SERCOM);
usart_write_wait(GPS_SERCOM, 0x34);
usart_read_wait(GPS_SERCOM, &data);
semihost_printf("Rx'ed: 0x%02x\n", data);
}

Wyświetl plik

@ -1,5 +1,5 @@
/*
* Sample application for the SAM D20
* Bristol Longshot
* Copyright (C) 2014 Richard Meadows <richardeoin>
*
* Permission is hereby granted, free of charge, to any person obtaining
@ -23,25 +23,37 @@
*/
#include "samd20.h"
#include "pindefs.h"
#include <stdio.h>
#include <math.h>
#include "semihosting.h"
#include "hw_config.h"
#include "system/system.h"
#include "sercom/usart.h"
#include "gps.h"
int main(void)
{
SystemInit();
system_clock_source_osc8m_set_config(SYSTEM_OSC8M_DIV_1, /* Prescaler */
false, /* Run in Standby */
false); /* Run on Demand */
/* Update the value of SystemCoreClock */
SystemCoreClockUpdate();
/* Set LED0 as output */
PORTA.DIRSET.reg = (1 << LED0_PIN);
/* Configure the SysTick for 50ms interrupts */
SysTick_Config(SystemCoreClock / 20);
/* Configure Sleep Mode */
system_set_sleepmode(SYSTEM_SLEEPMODE_IDLE_0);
//TODO: system_set_sleepmode(SYSTEM_SLEEPMODE_STANDBY);
volatile double d, dd;
d = 2;
@ -49,7 +61,14 @@ int main(void)
semihost_printf("Hello World %f\n", dd);
while (1);
gps_init();
while (1) {
//system_sleep();
for (int i = 0; i < 1000*1000; i++);
gps_check_lock();
}
}
void SysTick_Handler(void)

Wyświetl plik

@ -0,0 +1,298 @@
/**
* SAM D20/D21/R21 Serial Peripheral Interface Driver
*
* Copyright (C) 2012-2014 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#include "samd20.h"
#include "semihosting.h"
#include "sercom/sercom.h"
#include "util/mrecursion.h"
/**
* Sercom Configuration
*/
#define SHIFT 32
#define BAUD_INT_MAX 8192
#define BAUD_FP_MAX 8
/**
* Find index of given instance.
*/
uint8_t _sercom_get_sercom_inst_index(Sercom *const sercom_instance)
{
/* Save all available SERCOM instances for compare. */
Sercom *sercom_instances[SERCOM_INST_NUM] = SERCOM_INSTS;
/* Find index for sercom instance. */
for (uint32_t i = 0; i < SERCOM_INST_NUM; i++) {
if ((uintptr_t)sercom_instance == (uintptr_t)sercom_instances[i]) {
return i;
}
}
/* Invalid data given. */
assert(false);
return 0;
}
/** Error callback for unregistered sercom interrupt handlers */
void sercom_unregistered_handler(Sercom* const sercom_instance, uint8_t instance_index) {
(void)sercom_instance;
/* Print error message */
semihost_printf("Unregisted Handler for Sercom %d called! HALT", instance_index);
while (1);
}
/** Void pointers for sercom interrupt handlers */
static void (*_sercom_interrupt_handlers[SERCOM_INST_NUM])(Sercom* const sercom_instance,
uint8_t instance_index) = {
#if SERCOM_INST_NUM > 0
sercom_unregistered_handler,
#endif
#if SERCOM_INST_NUM > 1
sercom_unregistered_handler,
#endif
#if SERCOM_INST_NUM > 2
sercom_unregistered_handler,
#endif
#if SERCOM_INST_NUM > 3
sercom_unregistered_handler,
#endif
#if SERCOM_INST_NUM > 4
sercom_unregistered_handler,
#endif
#if SERCOM_INST_NUM > 5
sercom_unregistered_handler,
#endif
};
/** Sercom interrupt handlers */
#define SERCOM_INTERRUPT_HANDLER(n) \
void SERCOM##n##_Handler(void) \
{ \
_sercom_interrupt_handlers[n](SERCOM##n, n); \
}
#if SERCOM_INST_NUM > 0
SERCOM_INTERRUPT_HANDLER(0)
#endif
#if SERCOM_INST_NUM > 1
SERCOM_INTERRUPT_HANDLER(1)
#endif
#if SERCOM_INST_NUM > 2
SERCOM_INTERRUPT_HANDLER(2)
#endif
#if SERCOM_INST_NUM > 3
SERCOM_INTERRUPT_HANDLER(3)
#endif
#if SERCOM_INST_NUM > 4
SERCOM_INTERRUPT_HANDLER(4)
#endif
#if SERCOM_INST_NUM > 5
SERCOM_INTERRUPT_HANDLER(5)
#endif
/**
* Sets an interrupt handler
*/
void _sercom_set_handler(Sercom* const sercom_instance,
const sercom_handler_t interrupt_handler)
{
/* Retrieve the index of the SERCOM being requested */
uint8_t instance_index = _sercom_get_sercom_inst_index(sercom_instance);
/* Set the interrupt handler */
_sercom_interrupt_handlers[instance_index] = interrupt_handler;
}
/**
* Calculate synchronous baudrate value (SPI/UART)
*/
enum sercom_status_t _sercom_get_sync_baud_val(const uint32_t baudrate,
const uint32_t external_clock,
uint16_t *const baudvalue)
{
/* Baud value variable */
uint16_t baud_calculated = 0;
/* Check if baudrate is outside of valid range. */
if (baudrate > (external_clock / 2)) {
/* Return with error code */
return SERCOM_STATUS_BAUDRATE_UNAVAILABLE;
}
/* Calculate BAUD value from clock frequency and baudrate */
baud_calculated = (external_clock / (2 * baudrate)) - 1;
/* Check if BAUD value is more than 255, which is maximum
* for synchronous mode */
if (baud_calculated > 0xFF) {
/* Return with an error code */
return SERCOM_STATUS_BAUDRATE_UNAVAILABLE;
} else {
*baudvalue = baud_calculated;
return SERCOM_STATUS_OK;
}
}
/**
* Calculate asynchronous baudrate value (UART)
*/
enum sercom_status_t _sercom_get_async_baud_val(const uint32_t baudrate,
const uint32_t peripheral_clock,
uint16_t *const baudval,
enum sercom_asynchronous_operation_mode mode,
enum sercom_asynchronous_sample_num sample_num)
{
/* Temporary variables */
uint64_t ratio = 0;
uint64_t scale = 0;
uint64_t baud_calculated = 0;
uint8_t baud_fp;
uint32_t baud_int;
/* Check if the baudrate is outside of valid range */
if ((baudrate * sample_num) >= peripheral_clock) {
/* Return with error code */
return SERCOM_STATUS_BAUDRATE_UNAVAILABLE;
}
if(mode == SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC) {
/* Calculate the BAUD value */
ratio = ((sample_num * (uint64_t)baudrate) << SHIFT) / peripheral_clock;
scale = ((uint64_t)1 << SHIFT) - ratio;
baud_calculated = (65536 * scale) >> SHIFT;
} else if(mode == SERCOM_ASYNC_OPERATION_MODE_FRACTIONAL) {
for(baud_fp = 0; baud_fp < BAUD_FP_MAX; baud_fp++) {
baud_int = BAUD_FP_MAX *
(uint64_t)peripheral_clock / ((uint64_t)baudrate * sample_num)
- baud_fp;
baud_int = baud_int / BAUD_FP_MAX;
if(baud_int < BAUD_INT_MAX) {
break;
}
}
if(baud_fp == BAUD_FP_MAX) {
return SERCOM_STATUS_BAUDRATE_UNAVAILABLE;
}
baud_calculated = baud_int | (baud_fp << 13);
}
*baudval = baud_calculated;
return SERCOM_STATUS_OK;
}
/**
* Set GCLK channel to generator.
*
* This will set the appropriate GCLK channel to the requested GCLK generator.
*
* \param[in] generator_source The generator to use for SERCOM.
*/
void _sercom_set_gclk_generator(const enum gclk_generator generator_source)
{
system_gclk_chan_set_config(SERCOM_GCLK_ID, generator_source);
system_gclk_chan_enable(SERCOM_GCLK_ID);
}
/**
* Convert a SERCOM instance and pad index to the default SERCOM pad
* MUX setting.
*/
#define SERCOM_PAD_DEFAULT(n, pad) \
switch (pad) { \
case 0: \
return SERCOM##n##_PAD0_DEFAULT; \
case 1: \
return SERCOM##n##_PAD1_DEFAULT; \
case 2: \
return SERCOM##n##_PAD2_DEFAULT; \
case 3: \
return SERCOM##n##_PAD3_DEFAULT; \
}
/**
* Returns the PINMUX settings for the given SERCOM and pad. This is used
* for default configuration of pins.
*
* \param[in] sercom_module Pointer to the SERCOM module
* \param[in] pad PAD to get default pinout for
*
* \returns The default PINMUX for the given SERCOM instance and PAD
*
*/
uint32_t _sercom_get_default_pad(Sercom* const sercom_module,
const uint8_t pad)
{
switch((uintptr_t)sercom_module) {
#if SERCOM_INST_NUM > 0
case (uintptr_t)SERCOM0:
SERCOM_PAD_DEFAULT(0, pad); break;
#endif
#if SERCOM_INST_NUM > 1
case (uintptr_t)SERCOM1:
SERCOM_PAD_DEFAULT(1, pad); break;
#endif
#if SERCOM_INST_NUM > 2
case (uintptr_t)SERCOM2:
SERCOM_PAD_DEFAULT(2, pad); break;
#endif
#if SERCOM_INST_NUM > 3
case (uintptr_t)SERCOM3:
SERCOM_PAD_DEFAULT(3, pad); break;
#endif
#if SERCOM_INST_NUM > 4
case (uintptr_t)SERCOM4:
SERCOM_PAD_DEFAULT(4, pad); break;
#endif
#if SERCOM_INST_NUM > 5
case (uintptr_t)SERCOM5:
SERCOM_PAD_DEFAULT(5, pad); break;
#endif
}
assert(false);
return 0;
}

Plik diff jest za duży Load Diff

Wyświetl plik

@ -0,0 +1,796 @@
/**
* SAM D20/D21/R21 SERCOM USART Driver
*
* Copyright (C) 2012-2014 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#include "sercom/sercom.h"
#include "sercom/usart.h"
#include "system/pinmux.h"
#include "system/interrupt.h"
/**
* Initializes the USART device.
*
* \param[in] hw Pointer to USART hardware instance
*
* \return Status of the initialization
*
* \retval STATUS_OK The initialization was successful
* \retval STATUS_BUSY The USART module is busy
* resetting
* \retval STATUS_ERR_DENIED The USART have not been disabled in
* advance of initialization
* \retval STATUS_ERR_INVALID_ARG The configuration struct contains
* invalid configuration
* \retval STATUS_ERR_ALREADY_INITIALIZED The SERCOM instance has already been
* initialized with different clock
* configuration
* \retval STATUS_ERR_BAUD_UNAVAILABLE The BAUD rate given by the
* configuration
* struct cannot be reached with
* the current clock configuration
*/
enum sercom_status_t usart_init(SercomUsart* const hw,
enum usart_dataorder data_order,
enum usart_transfer_mode transfer_mode,
enum usart_parity parity,
enum usart_stopbits stopbits,
enum usart_character_size character_size,
enum usart_signal_mux_settings mux_setting,
#ifdef FEATURE_USART_OVER_SAMPLE
enum usart_sample_rate sample_rate,
enum usart_sample_adjustment sample_adjustment,
#endif
bool immediate_buffer_overflow_notification,
bool encoding_format_enable,
uint8_t receive_pulse_length,
bool lin_slave_enable,
bool start_frame_detection_enable,
bool collision_detection_enable,
uint32_t baudrate,
bool receiver_enable,
bool transmitter_enable,
bool clock_polarity_inverted,
bool use_external_clock,
uint32_t ext_clock_freq,
bool run_in_standby,
enum gclk_generator generator_source,
uint32_t pinmux_pad0,
uint32_t pinmux_pad1,
uint32_t pinmux_pad2,
uint32_t pinmux_pad3)
{
/* Sanity check arguments */
assert(hw);
enum sercom_status_t status_code = SERCOM_STATUS_OK;
uint32_t sercom_index = _sercom_get_sercom_inst_index((Sercom*)hw);
uint32_t pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos;
uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
/* Cache new register values to minimize the number of register writes */
uint32_t ctrla = 0;
uint32_t ctrlb = 0;
uint16_t baud = 0;
enum sercom_asynchronous_operation_mode mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC;
enum sercom_asynchronous_sample_num sample_num = SERCOM_ASYNC_SAMPLE_NUM_16;
if (hw->CTRLA.reg & SERCOM_USART_CTRLA_SWRST) {
/* The module is busy resetting itself */
return SERCOM_STATUS_BUSY;
}
if (hw->CTRLA.reg & SERCOM_USART_CTRLA_ENABLE) {
/* Check the module is enabled */
return SERCOM_STATUS_DENIED;
}
/* Turn on module in PM */
system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index);
/* Set up the GCLK for the module */
system_gclk_chan_set_config(gclk_index, generator_source);
system_gclk_chan_enable(gclk_index);
_sercom_set_gclk_generator(generator_source);
#ifdef FEATURE_USART_OVER_SAMPLE
switch (sample_rate) {
case USART_SAMPLE_RATE_16X_ARITHMETIC:
mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC;
sample_num = SERCOM_ASYNC_SAMPLE_NUM_16;
break;
case USART_SAMPLE_RATE_8X_ARITHMETIC:
mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC;
sample_num = SERCOM_ASYNC_SAMPLE_NUM_8;
break;
case USART_SAMPLE_RATE_3X_ARITHMETIC:
mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC;
sample_num = SERCOM_ASYNC_SAMPLE_NUM_3;
break;
case USART_SAMPLE_RATE_16X_FRACTIONAL:
mode = SERCOM_ASYNC_OPERATION_MODE_FRACTIONAL;
sample_num = SERCOM_ASYNC_SAMPLE_NUM_16;
break;
case USART_SAMPLE_RATE_8X_FRACTIONAL:
mode = SERCOM_ASYNC_OPERATION_MODE_FRACTIONAL;
sample_num = SERCOM_ASYNC_SAMPLE_NUM_8;
break;
}
#endif
/* Set data order, internal muxing, and clock polarity */
ctrla =
(uint32_t)data_order |
(uint32_t)mux_setting |
#ifdef FEATURE_USART_OVER_SAMPLE
sample_adjustment |
sample_rate |
#endif
(immediate_buffer_overflow_notification << SERCOM_USART_CTRLA_IBON_Pos) |
(clock_polarity_inverted << SERCOM_USART_CTRLA_CPOL_Pos);
/* Get baud value from mode and clock */
switch (transfer_mode)
{
case USART_TRANSFER_SYNCHRONOUSLY:
if (!use_external_clock) {
status_code = _sercom_get_sync_baud_val(baudrate,
system_gclk_chan_get_hz(gclk_index), &baud);
}
break;
case USART_TRANSFER_ASYNCHRONOUSLY:
if (use_external_clock) {
status_code =
_sercom_get_async_baud_val(baudrate,
ext_clock_freq, &baud, mode, sample_num);
} else {
status_code =
_sercom_get_async_baud_val(baudrate,
system_gclk_chan_get_hz(gclk_index), &baud, mode, sample_num);
}
break;
}
/* Check if calculating the baud rate failed */
if (status_code != SERCOM_STATUS_OK) {
/* Abort */
return SERCOM_STATUS_BAUDRATE_UNAVAILABLE;
}
// if(encoding_format_enable) {
// hw->RXPL.reg = receive_pulse_length;
// }
/* Wait until synchronization is complete */
USART_WAIT_FOR_SYNC(hw);
/* Set baud val */
hw->BAUD.reg = baud;
/* Set sample mode */
ctrla |= transfer_mode;
if (use_external_clock == false) {
ctrla |= SERCOM_USART_CTRLA_MODE_USART_INT_CLK;
}
else {
ctrla |= SERCOM_USART_CTRLA_MODE_USART_EXT_CLK;
}
/* Set stopbits, character size and enable transceivers */
ctrlb = (uint32_t)stopbits | (uint32_t)character_size |
// (encoding_format_enable << SERCOM_USART_CTRLB_ENC_Pos) |
(start_frame_detection_enable << SERCOM_USART_CTRLB_SFDE_Pos) |
// (collision_detection_enable << SERCOM_USART_CTRLB_COLDEN_Pos) |
(receiver_enable << SERCOM_USART_CTRLB_RXEN_Pos) |
(transmitter_enable << SERCOM_USART_CTRLB_TXEN_Pos);
/* Check parity mode bits */
if (parity != USART_PARITY_NONE) {
if(lin_slave_enable) {
ctrla |= SERCOM_USART_CTRLA_FORM(0x5);
}
ctrla |= SERCOM_USART_CTRLA_FORM(1);
ctrlb |= parity;
} else {
if(lin_slave_enable) {
ctrla |= SERCOM_USART_CTRLA_FORM(0x4);
}
ctrla |= SERCOM_USART_CTRLA_FORM(0);
}
/* Set whether module should run in standby. */
if (run_in_standby || system_is_debugger_present()) {
ctrla |= SERCOM_USART_CTRLA_RUNSTDBY;
}
/* Wait until synchronization is complete */
USART_WAIT_FOR_SYNC(hw);
/* Write configuration to CTRLB */
hw->CTRLB.reg = ctrlb;
/* Wait until synchronization is complete */
USART_WAIT_FOR_SYNC(hw);
/* Write configuration to CTRLA */
hw->CTRLA.reg = ctrla;
uint32_t pad_pinmuxes[] = { pinmux_pad0, pinmux_pad1,
pinmux_pad2, pinmux_pad3 };
/* Configure the SERCOM pins according to the user configuration */
for (uint8_t pad = 0; pad < 4; pad++) {
uint32_t current_pinmux = pad_pinmuxes[pad];
if (current_pinmux == PINMUX_DEFAULT) {
current_pinmux = _sercom_get_default_pad((Sercom* const)hw, pad);
}
if (current_pinmux != PINMUX_UNUSED) {
system_pinmux_pin_set_config(current_pinmux >> 16, /* GPIO Pin */
current_pinmux & 0xFFFF, /* Mux Position */
SYSTEM_PINMUX_PIN_DIR_INPUT, /* Direction */
SYSTEM_PINMUX_PIN_PULL_NONE, /* Pull */
false); /* Powersave */
}
}
return status_code;
}
/**
* Initialize the USART device to predefined defaults:
* - 8-bit asynchronous USART
* - No parity
* - 1 stop bit
* - 9600 baud
* - Transmitter enabled
* - Receiver enabled
* - GCLK generator 0 as clock source
* - Default pin configuration
*/
enum sercom_status_t usart_init_default(SercomUsart* const hw)
{
return usart_init(hw,
USART_DATAORDER_LSB, /** Bit order (MSB or LSB first) */
USART_TRANSFER_ASYNCHRONOUSLY, /** Asynchronous or synchronous mode */
USART_PARITY_NONE, /** USART parity */
USART_STOPBITS_1, /** Number of stop bits */
USART_CHARACTER_SIZE_8BIT, /** USART character size */
USART_RX_1_TX_2_XCK_3, /** USART pin out */
#ifdef FEATURE_USART_OVER_SAMPLE
USART_SAMPLE_RATE_16X_ARITHMETIC, /** USART sample rate */
USART_SAMPLE_ADJUSTMENT_7_8_9, /** USART sample adjustment */
#endif
false, /** Immediate buffer overflow notification */
false, /** Enable IrDA encoding format */
19, /** Minimum pulse length required for IrDA rx */
false, /** Enable LIN Slave Support */
false, /** Enable start of frame dection */
false, /** Enable collision dection */
9600, /** USART Baud rate */
true, /** Enable receiver */
true, /** Enable transmitter */
false, /** Sample on the rising edge of XLCK */
false, /** Use the external clock applied to the XCK pin. */
0, /** External clock frequency in synchronous mode. */
false, /** Run in standby */
GCLK_GENERATOR_0, /** GCLK generator source */
PINMUX_DEFAULT, /** PAD0 pinmux */
PINMUX_DEFAULT, /** PAD1 pinmux */
PINMUX_DEFAULT, /** PAD2 pinmux */
PINMUX_DEFAULT); /** PAD3 pinmux */
}
/**
* This blocking function will transmit a single character via the
* USART.
*
* \param[in] module Pointer to the software instance struct
* \param[in] tx_data Data to transfer
*
* \return Status of the operation
* \retval STATUS_OK If the operation was completed
* \retval STATUS_BUSY If the operation was not completed, due to the USART
* module being busy.
* \retval STATUS_ERR_DENIED If the transmitter is not enabled
*/
enum sercom_status_t usart_write_wait(SercomUsart* const hw,
const uint16_t tx_data)
{
/* Sanity check arguments */
assert(hw);
/* Check if USART is ready for new data */
if (!(hw->INTFLAG.reg & SERCOM_USART_INTFLAG_DRE)) {
/* Return error code */
return SERCOM_STATUS_BUSY;
}
/* Wait until synchronization is complete */
USART_WAIT_FOR_SYNC(hw);
/* Write data to USART module */
hw->DATA.reg = tx_data;
while (!(hw->INTFLAG.reg & SERCOM_USART_INTFLAG_TXC)) {
/* Wait until data is sent */
}
return SERCOM_STATUS_OK;
}
/**
* Receive a character via the USART
*
* This blocking function will receive a character via the USART.
*
* \param[in] module Pointer to the software instance struct
* \param[out] rx_data Pointer to received data
*
* \return Status of the operation
* \retval STATUS_OK If the operation was completed
* \retval STATUS_BUSY If the operation was not completed,
* due to the USART module being busy
* \retval STATUS_ERR_BAD_FORMAT If the operation was not completed,
* due to configuration mismatch between USART
* and the sender
* \retval STATUS_ERR_BAD_OVERFLOW If the operation was not completed,
* due to the baud rate being too low or the
* system frequency being too high
* \retval STATUS_ERR_BAD_DATA If the operation was not completed, due to
* data being corrupted
* \retval STATUS_ERR_DENIED If the receiver is not enabled
*/
enum sercom_status_t usart_read_wait(SercomUsart* const hw,
uint16_t *const rx_data)
{
/* Sanity check arguments */
assert(hw);
/* Error variable */
uint8_t error_code;
/* If USART has no new data, abort */
if (!(hw->INTFLAG.reg & SERCOM_USART_INTFLAG_RXC)) {
/* Return error code */
return SERCOM_STATUS_BUSY;
}
/* Wait until synchronization is complete */
USART_WAIT_FOR_SYNC(hw);
/* Read out the status code and mask away all but the 3 LSBs*/
error_code = (uint8_t)(hw->STATUS.reg & SERCOM_USART_STATUS_MASK);
/* Check if an error has occurred during the receiving */
if (error_code) {
/* Check which error occurred */
if (error_code & SERCOM_USART_STATUS_FERR) {
/* Clear flag by writing a 1 to it and
* return with an error code */
hw->STATUS.reg = SERCOM_USART_STATUS_FERR;
return SERCOM_STATUS_BAD_FORMAT;
} else if (error_code & SERCOM_USART_STATUS_BUFOVF) {
/* Clear flag by writing a 1 to it and
* return with an error code */
hw->STATUS.reg = SERCOM_USART_STATUS_BUFOVF;
return SERCOM_STATUS_OVERFLOW;
} else if (error_code & SERCOM_USART_STATUS_PERR) {
/* Clear flag by writing a 1 to it and
* return with an error code */
hw->STATUS.reg = SERCOM_USART_STATUS_PERR;
return SERCOM_STATUS_BAD_DATA;
// } else if (error_code & SERCOM_USART_STATUS_ISF) {
/* Clear flag by writing 1 to it and
* return with an error code */
// hw->STATUS.reg |= SERCOM_USART_STATUS_ISF;
// return STATUS_ERR_PROTOCOL;
// } else if (error_code & SERCOM_USART_STATUS_COLL) {
/* Clear flag by writing 1 to it
* return with an error code */
// hw->STATUS.reg |= SERCOM_USART_STATUS_COLL;
// return SERCOM_STATUS_PACKET_COLLISION;
}
}
/* Read data from USART module */
*rx_data = hw->DATA.reg;
return SERCOM_STATUS_OK;
}
/**
* Transmit a buffer of characters via the USART
*
* This blocking function will transmit a block of \c length characters
* via the USART
*
* \note Using this function in combination with the interrupt (\c _job) functions is
* not recommended as it has no functionality to check if there is an
* ongoing interrupt driven operation running or not.
*
* \param[in] module Pointer to USART software instance struct
* \param[in] tx_data Pointer to data to transmit
* \param[in] length Number of characters to transmit
*
* \return Status of the operation
* \retval STATUS_OK If operation was completed
* \retval STATUS_ERR_INVALID_ARG If operation was not completed, due to invalid
* arguments
* \retval STATUS_ERR_TIMEOUT If operation was not completed, due to USART
* module timing out
* \retval STATUS_ERR_DENIED If the transmitter is not enabled
*/
enum sercom_status_t usart_write_buffer_wait(SercomUsart* const hw,
const uint8_t *tx_data,
uint16_t length)
{
/* Sanity check arguments */
assert(hw);
/* Wait until synchronization is complete */
USART_WAIT_FOR_SYNC(hw);
uint16_t tx_pos = 0;
/* Blocks while buffer is being transferred */
while (length--) {
/* Wait for the USART to be ready for new data and abort
* operation if it doesn't get ready within the timeout*/
for (uint32_t i = 0; i <= USART_TIMEOUT; i++) {
if (hw->INTFLAG.reg & SERCOM_USART_INTFLAG_DRE) {
break;
} else if (i == USART_TIMEOUT) {
return SERCOM_STATUS_TIMEOUT;
}
}
/* Data to send is at least 8 bits long */
uint16_t data_to_send = tx_data[tx_pos++];
/* Check if the character size exceeds 8 bit */
// if (module->character_size == USART_CHARACTER_SIZE_9BIT) {
// data_to_send |= (tx_data[tx_pos++] << 8);
// }
/* Send the data through the USART module */
usart_write_wait(hw, data_to_send);
}
/* Wait until Transmit is complete or timeout */
for (uint32_t i = 0; i <= USART_TIMEOUT; i++) {
if (hw->INTFLAG.reg & SERCOM_USART_INTFLAG_TXC) {
break;
} else if (i == USART_TIMEOUT) {
return SERCOM_STATUS_TIMEOUT;
}
}
return SERCOM_STATUS_OK;
}
/**
* Receive a buffer of \c length characters via the USART
*
* This blocking function will receive a block of \c length characters
* via the USART.
*
* \note Using this function in combination with the interrupt (\c *_job)
* functions is not recommended as it has no functionality to check if
* there is an ongoing interrupt driven operation running or not.
*
* \param[in] module Pointer to USART software instance struct
* \param[out] rx_data Pointer to receive buffer
* \param[in] length Number of characters to receive
*
* \return Status of the operation.
* \retval STATUS_OK If operation was completed
* \retval STATUS_ERR_INVALID_ARG If operation was not completed, due to an
* invalid argument being supplied
* \retval STATUS_ERR_TIMEOUT If operation was not completed, due
* to USART module timing out
* \retval STATUS_ERR_BAD_FORMAT If the operation was not completed,
* due to a configuration mismatch
* between USART and the sender
* \retval STATUS_ERR_BAD_OVERFLOW If the operation was not completed,
* due to the baud rate being too low or the
* system frequency being too high
* \retval STATUS_ERR_BAD_DATA If the operation was not completed, due
* to data being corrupted
* \retval STATUS_ERR_DENIED If the receiver is not enabled
*/
enum sercom_status_t usart_read_buffer_wait(SercomUsart* hw,
uint8_t *rx_data,
uint16_t length)
{
/* Sanity check arguments */
assert(hw);
uint16_t rx_pos = 0;
/* Blocks while buffer is being received */
while (length--) {
/* Wait for the USART to have new data and abort operation if it
* doesn't get ready within the timeout*/
for (uint32_t i = 0; i <= USART_TIMEOUT; i++) {
if (hw->INTFLAG.reg & SERCOM_USART_INTFLAG_RXC) {
break;
} else if (i == USART_TIMEOUT) {
return SERCOM_STATUS_TIMEOUT;
}
}
enum sercom_status_t retval;
uint16_t received_data = 0;
retval = usart_read_wait(hw, &received_data);
if (retval != SERCOM_STATUS_OK) {
/* Overflow, abort */
return retval;
}
/* Read value will be at least 8-bits long */
rx_data[rx_pos++] = received_data;
/* If 9-bit data, write next received byte to the buffer */
// if (module->character_size == USART_CHARACTER_SIZE_9BIT) {
// rx_data[rx_pos++] = (received_data >> 8);
// }
}
return SERCOM_STATUS_OK;
}
/**
* -------------------------------- Interrupts -------------------------------
*/
/**
* Rx Callbacks for all instances
*/
static usart_rx_callback_t _usart_rx_callbacks[SERCOM_INST_NUM] = {
#if SERCOM_INST_NUM > 0
NULL,
#endif
#if SERCOM_INST_NUM > 1
NULL,
#endif
#if SERCOM_INST_NUM > 2
NULL,
#endif
#if SERCOM_INST_NUM > 3
NULL,
#endif
#if SERCOM_INST_NUM > 4
NULL,
#endif
#if SERCOM_INST_NUM > 5
NULL,
#endif
};
/**
* Handles interrupts as they occur, and it will run registered
* callback functions
*/
void _usart_interrupt_handler(Sercom* const sercom_instance, uint8_t instance_index)
{
/* Hardware instance */
SercomUsart* const hw = (SercomUsart*)SERCOM1; //sercom_instance;
/* Temporary variables */
uint16_t interrupt_status;
uint8_t error_code;
/* Wait for the synchronization to complete */
USART_WAIT_FOR_SYNC(hw);
/* Read and mask interrupt flag register */
interrupt_status = hw->INTFLAG.reg;
interrupt_status &= hw->INTENSET.reg;
/* Check if a DATA READY interrupt has occurred,
* and if there is more to transfer */
if (interrupt_status & SERCOM_USART_INTFLAG_DRE) {
/* if (module->remaining_tx_buffer_length) { */
/* /\* Write value will be at least 8-bits long *\/ */
/* uint16_t data_to_send = *(module->tx_buffer_ptr); */
/* /\* Increment 8-bit pointer *\/ */
/* (module->tx_buffer_ptr)++; */
/* if (module->character_size == USART_CHARACTER_SIZE_9BIT) { */
/* data_to_send |= (*(module->tx_buffer_ptr) << 8); */
/* /\* Increment 8-bit pointer *\/ */
/* (module->tx_buffer_ptr)++; */
/* } */
/* /\* Write the data to send *\/ */
/* hw->DATA.reg = (data_to_send & SERCOM_USART_DATA_MASK); */
/* if (--(module->remaining_tx_buffer_length) == 0) { */
/* /\* Disable the Data Register Empty Interrupt *\/ */
/* hw->INTENCLR.reg = SERCOM_USART_INTFLAG_DRE; */
/* /\* Enable Transmission Complete interrupt *\/ */
/* hw->INTENSET.reg = SERCOM_USART_INTFLAG_TXC; */
/* TODO: Turn off data ready interrupt */
hw->INTENCLR.reg = SERCOM_USART_INTFLAG_DRE;
}
/* Check if the Transmission Complete interrupt has occurred and
* that the transmit buffer is empty */
if (interrupt_status & SERCOM_USART_INTFLAG_TXC) {
/* Disable TX Complete Interrupt, and set STATUS_OK */
hw->INTENCLR.reg = SERCOM_USART_INTFLAG_TXC;
/* TODO: Callback */
}
/* Check if the Receive Complete interrupt has occurred, and that
* there's more data to receive */
while ((hw->INTFLAG.reg & hw->INTENSET.reg) & SERCOM_USART_INTFLAG_RXC) {
/* Read out the status code and mask away all but the 4 LSBs */
error_code = (uint8_t)(hw->STATUS.reg & SERCOM_USART_STATUS_MASK);
#ifndef SAMD20
/* CTS status should not be considered as an error */
if(error_code & SERCOM_USART_STATUS_CTS) {
error_code &= ~SERCOM_USART_STATUS_CTS;
}
#endif
/* Check if an error has occurred during the receiving */
if (error_code) {
/* Check which error occurred */
if (error_code & SERCOM_USART_STATUS_FERR) {
/* Store the error code and clear flag by writing 1 to it */
//module->rx_status = STATUS_ERR_BAD_FORMAT;
hw->STATUS.reg |= SERCOM_USART_STATUS_FERR;
} else if (error_code & SERCOM_USART_STATUS_BUFOVF) {
/* Store the error code and clear flag by writing 1 to it */
//module->rx_status = STATUS_ERR_OVERFLOW;
hw->STATUS.reg |= SERCOM_USART_STATUS_BUFOVF;
} else if (error_code & SERCOM_USART_STATUS_PERR) {
/* Store the error code and clear flag by writing 1 to it */
//module->rx_status = STATUS_ERR_BAD_DATA;
hw->STATUS.reg |= SERCOM_USART_STATUS_PERR;
}
#ifdef FEATURE_USART_LIN_SLAVE
else if (error_code & SERCOM_USART_STATUS_ISF) {
/* Store the error code and clear flag by writing 1 to it */
//module->rx_status = STATUS_ERR_PROTOCOL;
hw->STATUS.reg |= SERCOM_USART_STATUS_ISF;
}
#endif
#ifdef FEATURE_USART_COLLISION_DECTION
else if (error_code & SERCOM_USART_STATUS_COLL) {
/* Store the error code and clear flag by writing 1 to it */
// module->rx_status = STATUS_ERR_PACKET_COLLISION;
hw->STATUS.reg |= SERCOM_USART_STATUS_COLL;
}
#endif
/* TODO: Error callback */
} else { /* No Error code occoured */
/* Read current packet from DATA register,
* increment buffer pointer and decrement buffer length */
uint16_t received_data = (hw->DATA.reg & SERCOM_USART_DATA_MASK);
/* Rx Callback */
if (_usart_rx_callbacks[instance_index]) {
_usart_rx_callbacks[instance_index](hw, received_data);
}
/* TODO: Disable this Rx interrupt at some point */
//hw->INTENCLR.reg = SERCOM_USART_INTFLAG_RXC;
}
}
#ifdef FEATURE_USART_HARDWARE_FLOW_CONTROL
if (interrupt_status & SERCOM_USART_INTFLAG_CTSIC) {
/* Disable interrupts */
hw->INTENCLR.reg = SERCOM_USART_INTENCLR_CTSIC;
/* Clear interrupt flag */
hw->INTFLAG.reg = SERCOM_USART_INTFLAG_CTSIC;
/* TODO: Callback here */
}
#endif
#ifdef FEATURE_USART_LIN_SLAVE
if (interrupt_status & SERCOM_USART_INTFLAG_RXBRK) {
/* Disable interrupts */
hw->INTENCLR.reg = SERCOM_USART_INTENCLR_RXBRK;
/* Clear interrupt flag */
hw->INTFLAG.reg = SERCOM_USART_INTFLAG_RXBRK;
/* TODO: Callback here */
}
#endif
#ifdef FEATURE_USART_START_FRAME_DECTION
if (interrupt_status & SERCOM_USART_INTFLAG_RXS) {
/* Disable interrupts */
hw->INTENCLR.reg = SERCOM_USART_INTENCLR_RXS;
/* Clear interrupt flag */
hw->INTFLAG.reg = SERCOM_USART_INTFLAG_RXS;
/* TODO: Callback here */
}
#endif
}
/**
* Register a callback for received bytes
*/
void usart_register_rx_callback(SercomUsart* const hw,
usart_rx_callback_t callback,
uint32_t priority)
{
/* Get instance index */
uint8_t instance_index = _sercom_get_sercom_inst_index((Sercom*)hw);
/* Enable the Rx interrupt */
hw->INTENSET.reg = SERCOM_USART_INTFLAG_RXC;
/* Set the rx handler */
_usart_rx_callbacks[instance_index] = callback;
/* Set our out interrupt handler with the main sercom module */
_sercom_set_handler((Sercom*)hw, _usart_interrupt_handler);
/* And enable this interrupt in the NVIC */
irq_register_handler(SERCOM0_IRQn + instance_index, priority);
}

Wyświetl plik

@ -0,0 +1,854 @@
/**
* SAM D20 Clock Driver
*
* Copyright (C) 2012-2014 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#include "system/clock.h"
#include "system/conf_clocks.h"
#include "system/system.h"
#include "samd20.h"
/* Syncronisation Macros */
#define DFLL_WAIT_FOR_SYNC() \
while (!(SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY))
#define OSC32K_WAIT_FOR_SYNC() \
while (!(SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_OSC32KRDY))
/**
* Determines the current operating frequency of a given clock source.
*
* \param[in] clock_source Clock source to get the frequency of
*
* \returns Frequency of the given clock source, in Hz
*/
uint32_t system_clock_source_get_hz(const enum system_clock_source clock_source)
{
switch (clock_source) {
case SYSTEM_CLOCK_SOURCE_XOSC:
return 0;//TODO _system_clock_inst.xosc.frequency;
case SYSTEM_CLOCK_SOURCE_OSC8M:
return 8000000UL >> SYSCTRL->OSC8M.bit.PRESC;
case SYSTEM_CLOCK_SOURCE_OSC32K:
return 32768UL;
case SYSTEM_CLOCK_SOURCE_ULP32K:
return 32768UL;
case SYSTEM_CLOCK_SOURCE_XOSC32K:
return 0;//TODO _system_clock_inst.xosc32k.frequency;
case SYSTEM_CLOCK_SOURCE_DFLL:
/* Check if the DFLL has been configured */
if (!(SYSCTRL->DFLLCTRL.reg & SYSCTRL_DFLLCTRL_ENABLE)) {
return 0; /* Not configured */
}
/* Make sure that the DFLL module is ready */
DFLL_WAIT_FOR_SYNC();
/* Check if operating in closed loop mode */
if (SYSCTRL->DFLLCTRL.reg & SYSCTRL_DFLLCTRL_MODE) {
return system_gclk_chan_get_hz(SYSCTRL_GCLK_ID_DFLL48) *
(SYSCTRL->DFLLMUL.reg & 0xffff);
}
return 48000000UL;
default:
return 0;
}
}
/**
* Configures the 8MHz (nominal) internal RC oscillator with the given
* configuration settings.
*
* \param[in] config OSC8M configuration structure containing the new config
*/
void system_clock_source_osc8m_set_config(enum system_osc8m_div prescaler,
bool run_in_standby,
bool on_demand)
{
SYSCTRL_OSC8M_Type temp = SYSCTRL->OSC8M;
/* Use temporary struct to reduce register access */
temp.bit.PRESC = prescaler;
temp.bit.ONDEMAND = on_demand;
temp.bit.RUNSTDBY = run_in_standby;
SYSCTRL->OSC8M = temp;
}
/**
* Configures the 8MHz (nominal) internal RC oscillator with the
* default configuation settings.
*
* - Clock output frequency divided by a factor of 8
* - Don't run in STANDBY sleep mode
* - Run only when requested by peripheral (on demand)
*/
void system_clock_source_osc8m_set_config_default(void)
{
system_clock_source_osc8m_set_config(SYSTEM_OSC8M_DIV_8, /* Prescaler */
false, /* Run in Standby */
false); /* Run on Demand */
}
/**
* Configures the 32KHz (nominal) internal RC oscillator with the given
* configuration settings.
*
* \param[in] config OSC32K configuration structure containing the new config
*/
void system_clock_source_osc32k_set_config(enum system_osc32k_startup startup_time,
bool enable_1khz_output,
bool enable_32khz_output,
bool run_in_standby,
bool on_demand,
bool write_once)
{
SYSCTRL_OSC32K_Type temp = SYSCTRL->OSC32K;
/* Update settings via a temporary struct to reduce register access */
temp.bit.EN1K = enable_1khz_output;
temp.bit.EN32K = enable_32khz_output;
temp.bit.STARTUP = startup_time;
temp.bit.ONDEMAND = on_demand;
temp.bit.RUNSTDBY = run_in_standby;
temp.bit.WRTLOCK = write_once;
SYSCTRL->OSC32K = temp;
}
/**
* Configures the 32KHz (nominal) internal RC oscillator with the
* default configuration settings.
*
* - 1KHz clock output enabled
* - 32KHz clock output enabled
* - Don't run in STANDBY sleep mode
* - Run only when requested by peripheral (on demand)
* - Set startup time to 130 cycles
* - Don't lock registers after configuration has been written
*/
void system_clock_source_osc32k_set_config_default(void)
{
system_clock_source_osc32k_set_config(SYSTEM_OSC32K_STARTUP_130, /* Startup Cyles */
true, /* 1KHz output enable */
true, /* 32KHz output enable */
false, /* Run in Standby */
true, /* Run on demand */
false); /* Lock registers */
}
/**
* Configures the external oscillator clock source with the given configuration
* settings.
*
* \param[in] config External oscillator configuration structure containing
* the new config
*/
void system_clock_source_xosc_set_config(enum system_clock_external external_clock,
enum system_xosc_startup startup_time,
bool auto_gain_control,
uint32_t frequency,
bool run_in_standby,
bool on_demand)
{
SYSCTRL_XOSC_Type temp = SYSCTRL->XOSC;
/* Update settings via a temporary struct to reduce register access */
temp.bit.STARTUP = startup_time;
if (external_clock == SYSTEM_CLOCK_EXTERNAL_CRYSTAL) {
temp.bit.XTALEN = 1;
} else {
temp.bit.XTALEN = 0;
}
temp.bit.AMPGC = auto_gain_control;
/* Set gain if automatic gain control is not selected */
if (!auto_gain_control) {
if (frequency <= 2000000) {
temp.bit.GAIN = 0;
} else if (frequency <= 4000000) {
temp.bit.GAIN = 1;
} else if (frequency <= 8000000) {
temp.bit.GAIN = 2;
} else if (frequency <= 16000000) {
temp.bit.GAIN = 3;
} else if (frequency <= 30000000) {
temp.bit.GAIN = 4;
}
}
temp.bit.ONDEMAND = on_demand;
temp.bit.RUNSTDBY = run_in_standby;
SYSCTRL->XOSC = temp;
}
/**
* Configures the external oscillator clock source with the default
* configuration settings.
*
* - External Crystal
* - Start-up time of 16384 external clock cycles
* - Automatic crystal gain control mode enabled
* - Frequency of 12MHz
* - Don't run in STANDBY sleep mode
* - Run only when requested by peripheral (on demand)
*/
void system_clock_source_xosc_set_config_default(void)
{
/* void system_clock_source_xosc_set_config(SYSTEM_CLOCK_EXTERNAL_CRYSTAL, */
/* SYSTEM_XOSC_STARTUP_16384, */
/* true, /\* Auto gain control *\/ */
/* 12000000UL, /\* Frequency *\/ */
/* false, /\* Run in Standby *\/ */
/* true); /\* Run on demand *\/ */
}
/**
* Configures the external 32KHz oscillator clock source with the given
* configuration settings.
*
* \param[in] config XOSC32K configuration structure containing the new config
*/
void system_clock_source_xosc32k_set_config(enum system_clock_external external_clock,
enum system_xosc32k_startup startup_time,
bool auto_gain_control,
bool enable_1khz_output,
bool enable_32khz_output,
bool run_in_standby,
bool on_demand,
bool write_once)
{
SYSCTRL_XOSC32K_Type temp = SYSCTRL->XOSC32K;
/* Update settings via a temporary struct to reduce register access */
temp.bit.STARTUP = startup_time;
if (external_clock == SYSTEM_CLOCK_EXTERNAL_CRYSTAL) {
temp.bit.XTALEN = 1;
} else {
temp.bit.XTALEN = 0;
}
temp.bit.AAMPEN = auto_gain_control;
temp.bit.EN1K = enable_1khz_output;
temp.bit.EN32K = enable_32khz_output;
temp.bit.ONDEMAND = on_demand;
temp.bit.RUNSTDBY = run_in_standby;
temp.bit.WRTLOCK = write_once;
SYSCTRL->XOSC32K = temp;
}
/**
* Configures the external 32KHz oscillator clock source with the
* default configuration settings.
*
* - External Crystal
* - Start-up time of 16384 external clock cycles
* - Automatic crystal gain control mode disabled
* - 1KHz clock output disabled
* - 32KHz clock output enabled
* - Don't run in STANDBY sleep mode
* - Run only when requested by peripheral (on demand)
* - Don't lock registers after configuration has been written
*/
void system_clock_source_xosc32k_set_config_default(void)
{
system_clock_source_xosc32k_set_config(SYSTEM_CLOCK_EXTERNAL_CRYSTAL,
SYSTEM_XOSC32K_STARTUP_16384,
false, /* Auto gain control */
false, /* Enable 1KHz output */
false, /* Enable 32KHz output */
false, /* Run in standby */
true, /* Run on demand */
false); /* Write once */
}
/**
* Header file macro copies for runtime support of different revisions
*
* These macros are copied from the header file to be able to support
* both new and old register layout runtime.
*/
#define _SYSTEM_OLD_DFLLVAL_FINE_Pos 0
#define _SYSTEM_OLD_DFLLVAL_FINE_Msk (0xFFu << _SYSTEM_OLD_DFLLVAL_FINE_Pos)
#define _SYSTEM_OLD_DFLLVAL_FINE(value) ((_SYSTEM_OLD_DFLLVAL_FINE_Msk & ((value) << _SYSTEM_OLD_DFLLVAL_FINE_Pos)))
#define _SYSTEM_OLD_DFLLVAL_COARSE_Pos 8
#define _SYSTEM_OLD_DFLLVAL_COARSE_Msk (0x1Fu << _SYSTEM_OLD_DFLLVAL_COARSE_Pos)
#define _SYSTEM_OLD_DFLLVAL_COARSE(value) ((_SYSTEM_OLD_DFLLVAL_COARSE_Msk & ((value) << _SYSTEM_OLD_DFLLVAL_COARSE_Pos)))
#define _SYSTEM_NEW_DFLLVAL_FINE_Pos 0
#define _SYSTEM_NEW_DFLLVAL_FINE_Msk (0x3FFu << _SYSTEM_NEW_DFLLVAL_FINE_Pos)
#define _SYSTEM_NEW_DFLLVAL_FINE(value) ((_SYSTEM_NEW_DFLLVAL_FINE_Msk & ((value) << _SYSTEM_NEW_DFLLVAL_FINE_Pos)))
#define _SYSTEM_NEW_DFLLVAL_COARSE_Pos 10
#define _SYSTEM_NEW_DFLLVAL_COARSE_Msk (0x3Fu << _SYSTEM_NEW_DFLLVAL_COARSE_Pos)
#define _SYSTEM_NEW_DFLLVAL_COARSE(value) ((_SYSTEM_NEW_DFLLVAL_COARSE_Msk & ((value) << _SYSTEM_NEW_DFLLVAL_COARSE_Pos)))
#define _SYSTEM_OLD_DFLLMUL_FSTEP_Pos 16
#define _SYSTEM_OLD_DFLLMUL_FSTEP_Msk (0xFFu << _SYSTEM_OLD_DFLLMUL_FSTEP_Pos)
#define _SYSTEM_OLD_DFLLMUL_FSTEP(value) ((_SYSTEM_OLD_DFLLMUL_FSTEP_Msk & ((value) << _SYSTEM_OLD_DFLLMUL_FSTEP_Pos)))
#define _SYSTEM_OLD_DFLLMUL_CSTEP_Pos 24
#define _SYSTEM_OLD_DFLLMUL_CSTEP_Msk (0x1Fu << _SYSTEM_OLD_DFLLMUL_CSTEP_Pos)
#define _SYSTEM_OLD_DFLLMUL_CSTEP(value) ((_SYSTEM_OLD_DFLLMUL_CSTEP_Msk & ((value) << _SYSTEM_OLD_DFLLMUL_CSTEP_Pos)))
#define _SYSTEM_NEW_DFLLMUL_FSTEP_Pos 16
#define _SYSTEM_NEW_DFLLMUL_FSTEP_Msk (0x3FFu << _SYSTEM_NEW_DFLLMUL_FSTEP_Pos)
#define _SYSTEM_NEW_DFLLMUL_FSTEP(value) ((_SYSTEM_NEW_DFLLMUL_FSTEP_Msk & ((value) << _SYSTEM_NEW_DFLLMUL_FSTEP_Pos)))
#define _SYSTEM_NEW_DFLLMUL_CSTEP_Pos 26
#define _SYSTEM_NEW_DFLLMUL_CSTEP_Msk (0x3Fu << _SYSTEM_NEW_DFLLMUL_CSTEP_Pos)
#define _SYSTEM_NEW_DFLLMUL_CSTEP(value) ((_SYSTEM_NEW_DFLLMUL_CSTEP_Msk & ((value) << _SYSTEM_NEW_DFLLMUL_CSTEP_Pos)))
#define _SYSTEM_MCU_REVISION_D 3
/**
* Configures the Digital Frequency Locked Loop clock source with the given
* configuration settings.
*
* \note The DFLL will be running when this function returns, as the DFLL module
* needs to be enabled in order to perform the module configuration.
*
* \param[in] config DFLL configuration structure containing the new config
*/
void system_clock_source_dfll_set_config(
enum system_clock_dfll_loop_mode loop_mode,
bool on_demand,
enum system_clock_dfll_quick_lock quick_lock,
enum system_clock_dfll_chill_cycle chill_cycle,
enum system_clock_dfll_wakeup_lock wakeup_lock,
enum system_clock_dfll_stable_tracking stable_tracking,
uint8_t coarse_value,
uint16_t fine_value,
uint8_t coarse_max_step,
uint16_t fine_max_step,
uint16_t multiply_factor)
{
uint32_t control, val, mul;
/* Get MCU revision */
uint32_t rev = system_get_device_id();
rev &= DSU_DID_REVISION_Msk;
rev = rev >> DSU_DID_REVISION_Pos;
if (rev < _SYSTEM_MCU_REVISION_D) {
val =
_SYSTEM_OLD_DFLLVAL_COARSE(coarse_value) |
_SYSTEM_OLD_DFLLVAL_FINE(fine_value);
} else {
val =
_SYSTEM_NEW_DFLLVAL_COARSE(coarse_value) |
_SYSTEM_NEW_DFLLVAL_FINE(fine_value);
}
control =
(uint32_t)wakeup_lock |
(uint32_t)stable_tracking |
(uint32_t)quick_lock |
(uint32_t)chill_cycle |
((uint32_t)on_demand << SYSCTRL_DFLLCTRL_ONDEMAND_Pos);
if (loop_mode == SYSTEM_CLOCK_DFLL_LOOP_MODE_CLOSED) {
if(rev < _SYSTEM_MCU_REVISION_D) {
mul =
_SYSTEM_OLD_DFLLMUL_CSTEP(coarse_max_step) |
_SYSTEM_OLD_DFLLMUL_FSTEP(fine_max_step) |
SYSCTRL_DFLLMUL_MUL(multiply_factor);
} else {
mul =
_SYSTEM_NEW_DFLLMUL_CSTEP(coarse_max_step) |
_SYSTEM_NEW_DFLLMUL_FSTEP(fine_max_step) |
SYSCTRL_DFLLMUL_MUL(multiply_factor);
}
/* Enable the closed loop mode */
control |= loop_mode;
}
/* Workaround for errata 9905 */
SYSCTRL->DFLLCTRL.reg = control & ~SYSCTRL_DFLLCTRL_ONDEMAND;
DFLL_WAIT_FOR_SYNC();
SYSCTRL->DFLLMUL.reg = mul;
SYSCTRL->DFLLVAL.reg = val;
/* Write full configuration to DFLL control register */
SYSCTRL->DFLLCTRL.reg = control;
}
/**
* Configures the Digital Frequency Locked Loop clock source with the
* default configuration settings.
*
* - Open loop mode
* - QuickLock mode enabled
* - Chill cycle enabled
* - Output frequency lock maintained during device wake-up
* - Continuous tracking of the output frequency
* - Default tracking values at the mid-points for both coarse and fine
* tracking parameters
* - Don't run in STANDBY sleep mode
* - Run only when requested by peripheral (on demand)
*/
void system_clock_source_dfll_set_config_default(void)
{
system_clock_source_dfll_set_config(
SYSTEM_CLOCK_DFLL_LOOP_MODE_OPEN, /* Loop Mode */
true, /* On demand */
SYSTEM_CLOCK_DFLL_QUICK_LOCK_ENABLE, /* Quick Lock */
SYSTEM_CLOCK_DFLL_CHILL_CYCLE_ENABLE, /* Chill Cycle */
SYSTEM_CLOCK_DFLL_WAKEUP_LOCK_KEEP, /* Lock during wakeup */
SYSTEM_CLOCK_DFLL_STABLE_TRACKING_TRACK_AFTER_LOCK,
0x1f / 4, /* Open Loop - Coarse calibration value */
0xff / 4, /* Open Loop - Fine calibration value */
1, /* Closed Loop - Coarse Maximum step */
1, /* Closed Loop - Fine Maximum step */
6); /* Frequency Multiplication Factor */
}
/**
* Writes an oscillator calibration value to the given oscillator control
* registers. The acceptable ranges are:
*
* For OSC32K:
* - 7 bits (max value 128)
* For OSC8MHZ:
* - 8 bits (Max value 255)
* For OSCULP:
* - 5 bits (Max value 32)
*
* \note The frequency range parameter applies only when configuring the 8MHz
* oscillator and will be ignored for the other oscillators.
*
* \param[in] clock_source Clock source to calibrate
* \param[in] calibration_value Calibration value to write
* \param[in] freq_range Frequency range (8MHz oscillator only)
*
* \retval STATUS_OK The calibration value was written
* successfully.
* \retval STATUS_ERR_INVALID_ARG The setting is not valid for selected clock
* source.
*/
enum clock_status_t system_clock_source_write_calibration(
const enum system_clock_source clock_source,
const uint16_t calibration_value,
const uint8_t freq_range)
{
switch (clock_source) {
case SYSTEM_CLOCK_SOURCE_OSC8M:
if (calibration_value > 0xfff || freq_range > 4) {
return CLOCK_STATUS_INVALID_ARG;
}
SYSCTRL->OSC8M.bit.CALIB = calibration_value;
SYSCTRL->OSC8M.bit.FRANGE = freq_range;
break;
case SYSTEM_CLOCK_SOURCE_OSC32K:
if (calibration_value > 128) {
return CLOCK_STATUS_INVALID_ARG;
}
OSC32K_WAIT_FOR_SYNC();
SYSCTRL->OSC32K.bit.CALIB = calibration_value;
break;
case SYSTEM_CLOCK_SOURCE_ULP32K:
if (calibration_value > 32) {
return CLOCK_STATUS_INVALID_ARG;
}
SYSCTRL->OSCULP32K.bit.CALIB = calibration_value;
break;
default:
assert(false);
return CLOCK_STATUS_INVALID_ARG;
break;
}
return CLOCK_STATUS_OK;
}
/**
* Enables a clock source which has been previously configured.
*
* \param[in] clock_source Clock source to enable
*
* \retval STATUS_OK Clock source was enabled successfully and
* is ready
* \retval STATUS_ERR_INVALID_ARG The clock source is not available on this
* device
*/
enum clock_status_t system_clock_source_enable(
const enum system_clock_source clock_source)
{
switch (clock_source) {
case SYSTEM_CLOCK_SOURCE_OSC8M:
SYSCTRL->OSC8M.reg |= SYSCTRL_OSC8M_ENABLE;
return CLOCK_STATUS_OK;
case SYSTEM_CLOCK_SOURCE_OSC32K:
SYSCTRL->OSC32K.reg |= SYSCTRL_OSC32K_ENABLE;
break;
case SYSTEM_CLOCK_SOURCE_XOSC:
SYSCTRL->XOSC.reg |= SYSCTRL_XOSC_ENABLE;
break;
case SYSTEM_CLOCK_SOURCE_XOSC32K:
SYSCTRL->XOSC32K.reg |= SYSCTRL_XOSC32K_ENABLE;
break;
case SYSTEM_CLOCK_SOURCE_DFLL:
SYSCTRL->DFLLCTRL.reg |= SYSCTRL_DFLLCTRL_ENABLE;
break;
case SYSTEM_CLOCK_SOURCE_ULP32K:
/* Always enabled */
return CLOCK_STATUS_OK;
default:
assert(false);
return CLOCK_STATUS_INVALID_ARG;
}
return CLOCK_STATUS_OK;
}
/**
* Disables a clock source that was previously enabled.
*
* \param[in] clock_source Clock source to disable
*
* \retval STATUS_OK Clock source was disabled successfully
* \retval STATUS_ERR_INVALID_ARG An invalid or unavailable clock source was
* given
*/
enum clock_status_t system_clock_source_disable(
const enum system_clock_source clock_source)
{
switch (clock_source) {
case SYSTEM_CLOCK_SOURCE_OSC8M:
SYSCTRL->OSC8M.reg &= ~SYSCTRL_OSC8M_ENABLE;
break;
case SYSTEM_CLOCK_SOURCE_OSC32K:
SYSCTRL->OSC32K.reg &= ~SYSCTRL_OSC32K_ENABLE;
break;
case SYSTEM_CLOCK_SOURCE_XOSC:
SYSCTRL->XOSC.reg &= ~SYSCTRL_XOSC_ENABLE;
break;
case SYSTEM_CLOCK_SOURCE_XOSC32K:
SYSCTRL->XOSC32K.reg &= ~SYSCTRL_XOSC32K_ENABLE;
break;
case SYSTEM_CLOCK_SOURCE_DFLL:
SYSCTRL->DFLLCTRL.reg &= +SYSCTRL_DFLLCTRL_ENABLE;
break;
case SYSTEM_CLOCK_SOURCE_ULP32K:
/* Not possible to disable */
default:
assert(false);
return CLOCK_STATUS_INVALID_ARG;
}
return CLOCK_STATUS_OK;
}
/**
* Checks if a given clock source is ready to be used.
*
* \param[in] clock_source Clock source to check if ready
*
* \returns Ready state of the given clock source.
*
* \retval true Clock source is enabled and ready
* \retval false Clock source is disabled or not yet ready
*/
bool system_clock_source_is_ready(
const enum system_clock_source clock_source)
{
uint32_t mask = 0;
switch (clock_source) {
case SYSTEM_CLOCK_SOURCE_OSC8M:
mask = SYSCTRL_PCLKSR_OSC8MRDY;
break;
case SYSTEM_CLOCK_SOURCE_OSC32K:
mask = SYSCTRL_PCLKSR_OSC32KRDY;
break;
case SYSTEM_CLOCK_SOURCE_XOSC:
mask = SYSCTRL_PCLKSR_XOSCRDY;
break;
case SYSTEM_CLOCK_SOURCE_XOSC32K:
mask = SYSCTRL_PCLKSR_XOSC32KRDY;
break;
case SYSTEM_CLOCK_SOURCE_DFLL:
if (CONF_CLOCK_DFLL_LOOP_MODE == SYSTEM_CLOCK_DFLL_LOOP_MODE_CLOSED) {
mask = (SYSCTRL_PCLKSR_DFLLRDY |
SYSCTRL_PCLKSR_DFLLLCKF | SYSCTRL_PCLKSR_DFLLLCKC);
} else {
mask = SYSCTRL_PCLKSR_DFLLRDY;
}
break;
case SYSTEM_CLOCK_SOURCE_ULP32K:
/* Not possible to disable */
return true;
default:
return false;
}
return ((SYSCTRL->PCLKSR.reg & mask) == mask);
}
/* Include some checks for conf_clocks.h validation */
#include "system/clock_config_check.h"
/**
* Configures a Generic Clock Generator with the configuration from \c conf_clocks.h.
*/
#define _CONF_CLOCK_GCLK_CONFIG(n) \
if (CONF_CLOCK_GCLK_##n##_ENABLE == true) { \
system_gclk_gen_set_config( \
GCLK_GENERATOR_##n, \
CONF_CLOCK_GCLK_##n##_CLOCK_SOURCE, /* Source Clock */ \
false, /* High When Disabled*/ \
CONF_CLOCK_GCLK_##n##_PRESCALER, /* Division Factor */ \
CONF_CLOCK_GCLK_##n##_RUN_IN_STANDBY, /* Run in standby */ \
CONF_CLOCK_GCLK_##n##_OUTPUT_ENABLE); /* Output Pin Enable */ \
\
system_gclk_gen_enable(GCLK_GENERATOR_##n); \
}
/**
* Initialize clock system based on the configuration in conf_clocks.h
*
* This function will apply the settings in conf_clocks.h when run from the user
* application. All clock sources and GCLK generators are running when this function
* returns.
*/
void system_clock_init(void)
{
/* Various bits in the INTFLAG register can be set to one at startup.
This will ensure that these bits are cleared */
SYSCTRL->INTFLAG.reg = SYSCTRL_INTFLAG_BOD33RDY | SYSCTRL_INTFLAG_BOD33DET |
SYSCTRL_INTFLAG_DFLLRDY;
system_flash_set_waitstates(CONF_CLOCK_FLASH_WAIT_STATES);
/* XOSC */
#if CONF_CLOCK_XOSC_ENABLE == true
struct system_clock_source_xosc_config xosc_conf;
system_clock_source_xosc_get_config_defaults(&xosc_conf);
xosc_conf.external_clock = CONF_CLOCK_XOSC_EXTERNAL_CRYSTAL;
xosc_conf.startup_time = CONF_CLOCK_XOSC_STARTUP_TIME;
xosc_conf.auto_gain_control = CONF_CLOCK_XOSC_AUTO_GAIN_CONTROL;
xosc_conf.frequency = CONF_CLOCK_XOSC_EXTERNAL_FREQUENCY;
xosc_conf.on_demand = CONF_CLOCK_XOSC_ON_DEMAND;
xosc_conf.run_in_standby = CONF_CLOCK_XOSC_RUN_IN_STANDBY;
system_clock_source_xosc_set_config(&xosc_conf);
system_clock_source_enable(SYSTEM_CLOCK_SOURCE_XOSC);
#endif
/* XOSC32K */
#if CONF_CLOCK_XOSC32K_ENABLE == true
struct system_clock_source_xosc32k_config xosc32k_conf;
system_clock_source_xosc32k_get_config_defaults(&xosc32k_conf);
xosc32k_conf.frequency = 32768UL;
xosc32k_conf.external_clock = CONF_CLOCK_XOSC32K_EXTERNAL_CRYSTAL;
xosc32k_conf.startup_time = CONF_CLOCK_XOSC32K_STARTUP_TIME;
xosc32k_conf.auto_gain_control = CONF_CLOCK_XOSC32K_AUTO_AMPLITUDE_CONTROL;
xosc32k_conf.enable_1khz_output = CONF_CLOCK_XOSC32K_ENABLE_1KHZ_OUPUT;
xosc32k_conf.enable_32khz_output = CONF_CLOCK_XOSC32K_ENABLE_32KHZ_OUTPUT;
xosc32k_conf.on_demand = false;
xosc32k_conf.run_in_standby = CONF_CLOCK_XOSC32K_RUN_IN_STANDBY;
system_clock_source_xosc32k_set_config(&xosc32k_conf);
system_clock_source_enable(SYSTEM_CLOCK_SOURCE_XOSC32K);
while(!system_clock_source_is_ready(SYSTEM_CLOCK_SOURCE_XOSC32K));
if (CONF_CLOCK_XOSC32K_ON_DEMAND) {
SYSCTRL->XOSC32K.bit.ONDEMAND = 1;
}
#endif
/* OSCK32K */
#if CONF_CLOCK_OSC32K_ENABLE == true
SYSCTRL->OSC32K.bit.CALIB =
(*(uint32_t *)SYSCTRL_FUSES_OSC32KCAL_ADDR >> SYSCTRL_FUSES_OSC32KCAL_Pos);
struct system_clock_source_osc32k_config osc32k_conf;
system_clock_source_osc32k_get_config_defaults(&osc32k_conf);
osc32k_conf.startup_time = CONF_CLOCK_OSC32K_STARTUP_TIME;
osc32k_conf.enable_1khz_output = CONF_CLOCK_OSC32K_ENABLE_1KHZ_OUTPUT;
osc32k_conf.enable_32khz_output = CONF_CLOCK_OSC32K_ENABLE_32KHZ_OUTPUT;
osc32k_conf.on_demand = CONF_CLOCK_OSC32K_ON_DEMAND;
osc32k_conf.run_in_standby = CONF_CLOCK_OSC32K_RUN_IN_STANDBY;
system_clock_source_osc32k_set_config(&osc32k_conf);
system_clock_source_enable(SYSTEM_CLOCK_SOURCE_OSC32K);
#endif
/* DFLL Config (Open and Closed Loop) */
#if CONF_CLOCK_DFLL_ENABLE == true
system_clock_source_dfll_set_config(
CONF_CLOCK_DFLL_LOOP_MODE, /* Loop Mode */
CONF_CLOCK_DFLL_ON_DEMAND, /* On demand */
# if CONF_CLOCK_DFLL_QUICK_LOCK == true
SYSTEM_CLOCK_DFLL_QUICK_LOCK_ENABLE, /* Quick Lock */
# else
SYSTEM_CLOCK_DFLL_QUICK_LOCK_DISABLE, /* Quick Lock */
# endif
# if CONF_CLOCK_DFLL_ENABLE_CHILL_CYCLE == true
SYSTEM_CLOCK_DFLL_CHILL_CYCLE_ENABLE, /* Chill Cycle */
# else
SYSTEM_CLOCK_DFLL_CHILL_CYCLE_DISABLE, /* Chill Cycle */
# endif
# if CONF_CLOCK_DFLL_KEEP_LOCK_ON_WAKEUP == true
SYSTEM_CLOCK_DFLL_WAKEUP_LOCK_KEEP, /* Lock during wakeup */
# else
SYSTEM_CLOCK_DFLL_WAKEUP_LOCK_LOSE, /* Lock during wakeup */
# endif
# if CONF_CLOCK_DFLL_TRACK_AFTER_FINE_LOCK == true
SYSTEM_CLOCK_DFLL_STABLE_TRACKING_TRACK_AFTER_LOCK,
# else
SYSTEM_CLOCK_DFLL_STABLE_TRACKING_FIX_AFTER_LOCK,
# endif
CONF_CLOCK_DFLL_COARSE_VALUE, /* Open Loop - Coarse calib */
CONF_CLOCK_DFLL_FINE_VALUE, /* Open Loop - Fine calib */
CONF_CLOCK_DFLL_MAX_COARSE_STEP_SIZE, /* Closed Loop - Coarse Max step */
CONF_CLOCK_DFLL_MAX_FINE_STEP_SIZE, /* Closed Loop - Fine Max step */
CONF_CLOCK_DFLL_MULTIPLY_FACTOR); /* Frequency Multiplication */
#endif
/* OSC8M */
system_clock_source_osc8m_set_config(CONF_CLOCK_OSC8M_PRESCALER,
CONF_CLOCK_OSC8M_ON_DEMAND,
CONF_CLOCK_OSC8M_RUN_IN_STANDBY);
system_clock_source_enable(SYSTEM_CLOCK_SOURCE_OSC8M);
/* GCLK */
#if CONF_CLOCK_CONFIGURE_GCLK == true
system_gclk_init();
/* Configure all GCLK generators except for the main generator, which
* is configured later after all other clock systems are set up */
_CONF_CLOCK_GCLK_CONFIG(1);
_CONF_CLOCK_GCLK_CONFIG(2);
_CONF_CLOCK_GCLK_CONFIG(3);
_CONF_CLOCK_GCLK_CONFIG(4);
_CONF_CLOCK_GCLK_CONFIG(5);
_CONF_CLOCK_GCLK_CONFIG(6);
_CONF_CLOCK_GCLK_CONFIG(7);
# if CONF_CLOCK_DFLL_ENABLE == true
/* Enable DFLL reference clock if in closed loop mode */
if (CONF_CLOCK_DFLL_LOOP_MODE == SYSTEM_CLOCK_DFLL_LOOP_MODE_CLOSED) {
system_gclk_chan_set_config(SYSCTRL_GCLK_ID_DFLL48,
CONF_CLOCK_DFLL_SOURCE_GCLK_GENERATOR);
system_gclk_chan_enable(SYSCTRL_GCLK_ID_DFLL48);
}
# endif
#endif
/* DFLL Enable (Open and Closed Loop) */
#if CONF_CLOCK_DFLL_ENABLE == true
system_clock_source_enable(SYSTEM_CLOCK_SOURCE_DFLL);
while(!system_clock_source_is_ready(SYSTEM_CLOCK_SOURCE_DFLL));
if (CONF_CLOCK_DFLL_ON_DEMAND) {
SYSCTRL->DFLLCTRL.bit.ONDEMAND = 1;
}
#endif
/* CPU and BUS clocks */
system_cpu_clock_set_divider(CONF_CLOCK_CPU_DIVIDER);
#ifdef FEATURE_SYSTEM_CLOCK_FAILURE_DETECT
system_main_clock_set_failure_detect(CONF_CLOCK_CPU_CLOCK_FAILURE_DETECT);
#endif
system_apb_clock_set_divider(SYSTEM_CLOCK_APB_APBA, CONF_CLOCK_APBA_DIVIDER);
system_apb_clock_set_divider(SYSTEM_CLOCK_APB_APBB, CONF_CLOCK_APBB_DIVIDER);
/* GCLK 0 */
#if CONF_CLOCK_CONFIGURE_GCLK == true
/* Configure the main GCLK last as it might depend on other generators */
_CONF_CLOCK_GCLK_CONFIG(0);
#endif
}

Wyświetl plik

@ -0,0 +1,450 @@
/**
* SAM D20 Generic Clock Driver
*
* Copyright (C) 2012-2014 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#include "system/gclk.h"
#include "system/clock.h"
#include "system/interrupt.h"
#define GCLK_WAIT_FOR_SYNC() while(GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY)
/**
* Initializes the Generic Clock module, disabling and resetting all active
* Generic Clock Generators and Channels to their power-on default values.
*/
void system_gclk_init(void)
{
/* Turn on the digital interface clock */
system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBA, PM_APBAMASK_GCLK);
/* Software reset the module to ensure it is re-initialized correctly */
GCLK->CTRL.reg = GCLK_CTRL_SWRST;
/* Wait for reset to complete */
while (GCLK->CTRL.reg & GCLK_CTRL_SWRST);
}
/**
* Writes out a given configuration of a Generic Clock Generator configuration
* to the hardware module.
*
* \note Changing the clock source on the fly (on a running
* generator) can take additional time if the clock source is configured
* to only run on-demand (ONDEMAND bit is set) and it is not currently
* running (no peripheral is requesting the clock source). In this case
* the GCLK will request the new clock while still keeping a request to
* the old clock source until the new clock source is ready.
*
* \note This function will not start a generator that is not already running;
* to start the generator, call system_gclk_gen_enable()
* after configuring a generator.
*
* \param[in] generator Generic Clock Generator index to configure
*/
void system_gclk_gen_set_config(const uint8_t generator,
const uint8_t source_clock,
const bool high_when_disabled,
const uint32_t division_factor,
const bool run_in_standby,
const bool output_enable)
{
/* Cache new register configurations to minimize sync requirements. */
uint32_t new_genctrl_config = (generator << GCLK_GENCTRL_ID_Pos);
uint32_t new_gendiv_config = (generator << GCLK_GENDIV_ID_Pos);
/* Select the requested source clock for the generator */
new_genctrl_config |= source_clock << GCLK_GENCTRL_SRC_Pos;
/* Configure the clock to be either high or low when disabled */
if (high_when_disabled) {
new_genctrl_config |= GCLK_GENCTRL_OOV;
}
/* Configure if the clock output to I/O pin should be enabled. */
if (output_enable) {
new_genctrl_config |= GCLK_GENCTRL_OE;
}
/* Set division factor */
if (division_factor > 1) {
/* Check if division is a power of two */
if (((division_factor & (division_factor - 1)) == 0)) {
/* Determine the index of the highest bit set to get the
* division factor that must be loaded into the division
* register */
uint32_t div2_count = 0;
uint32_t mask;
for (mask = (1UL << 1); mask < division_factor; mask <<= 1) {
div2_count++;
}
/* Set binary divider power of 2 division factor */
new_gendiv_config |= (div2_count << GCLK_GENDIV_DIV_Pos);
new_genctrl_config |= GCLK_GENCTRL_DIVSEL;
} else {
/* Set integer division factor */
new_gendiv_config |= (division_factor << GCLK_GENDIV_DIV_Pos);
/* Enable non-binary division with increased duty cycle accuracy */
new_genctrl_config |= GCLK_GENCTRL_IDC;
}
}
/* Enable or disable the clock in standby mode */
if (run_in_standby) {
new_genctrl_config |= GCLK_GENCTRL_RUNSTDBY;
}
GCLK_WAIT_FOR_SYNC();
cpu_irq_enter_critical();
/* Select the correct generator */
*((uint8_t*)&GCLK->GENDIV.reg) = generator;
/* Write the new generator configuration */
GCLK_WAIT_FOR_SYNC();
GCLK->GENDIV.reg = new_gendiv_config;
GCLK->GENCTRL.reg = new_genctrl_config | (GCLK->GENCTRL.reg & GCLK_GENCTRL_GENEN);
cpu_irq_leave_critical();
}
void system_gclk_gen_set_config_defaults(const uint8_t generator)
{
system_gclk_gen_set_config(generator,
GCLK_SOURCE_OSC8M, /* Source Clock */
false, /* High When Disabled */
1, /* Division Factor */
false, /* Run in standby */
false); /* Output Pin Enable */
}
/**
* Starts the clock generation of a Generic Clock Generator that was previously
* configured via a call to system_gclk_gen_set_config().
*
* \param[in] generator Generic Clock Generator index to enable
*/
void system_gclk_gen_enable(const uint8_t generator)
{
GCLK_WAIT_FOR_SYNC();
cpu_irq_enter_critical();
/* Select the requested generator */
*((uint8_t*)&GCLK->GENCTRL.reg) = generator;
GCLK_WAIT_FOR_SYNC();
/* Enable generator */
GCLK->GENCTRL.reg |= GCLK_GENCTRL_GENEN;
cpu_irq_leave_critical();
}
/**
* Stops the clock generation of a Generic Clock Generator that was previously
* started via a call to system_gclk_gen_enable().
*
* \param[in] generator Generic Clock Generator index to disable
*/
void system_gclk_gen_disable(const uint8_t generator)
{
GCLK_WAIT_FOR_SYNC();
cpu_irq_enter_critical();
/* Select the requested generator */
*((uint8_t*)&GCLK->GENCTRL.reg) = generator;
GCLK_WAIT_FOR_SYNC();
/* Disable generator */
GCLK->GENCTRL.reg &= ~GCLK_GENCTRL_GENEN;
/* Wait for clock to become disabled */
while (GCLK->GENCTRL.reg & GCLK_GENCTRL_GENEN);
cpu_irq_leave_critical();
}
/**
* Determines if the specified Generic Clock Generator is enabled
*
* \param[in] generator Generic Clock Generator index to check
*
* \return The enabled status.
* \retval true The Generic Clock Generator is enabled;
* \retval false The Generic Clock Generator is disabled.
*/
bool system_gclk_gen_is_enabled(const uint8_t generator)
{
bool enabled;
cpu_irq_enter_critical();
/* Select the requested generator */
*((uint8_t*)&GCLK->GENCTRL.reg) = generator;
/* Obtain the enabled status */
enabled = (GCLK->GENCTRL.reg & GCLK_GENCTRL_GENEN);
cpu_irq_leave_critical();
return enabled;
}
/**
* \brief Retrieves the clock frequency of a Generic Clock generator.
*
* Determines the clock frequency (in Hz) of a specified Generic Clock
* generator, used as a source to a Generic Clock Channel module.
*
* \param[in] generator Generic Clock Generator index
*
* \return The frequency of the generic clock generator, in Hz.
*/
uint32_t system_gclk_gen_get_hz(const uint8_t generator)
{
GCLK_WAIT_FOR_SYNC();
cpu_irq_enter_critical();
/* Select the appropriate generator */
*((uint8_t*)&GCLK->GENCTRL.reg) = generator;
GCLK_WAIT_FOR_SYNC();
/* Get the frequency of the source connected to the GCLK generator */
uint32_t gen_input_hz = system_clock_source_get_hz(
(enum system_clock_source)GCLK->GENCTRL.bit.SRC);
*((uint8_t*)&GCLK->GENCTRL.reg) = generator;
uint8_t divsel = GCLK->GENCTRL.bit.DIVSEL;
/* Select the appropriate generator division register */
*((uint8_t*)&GCLK->GENDIV.reg) = generator;
GCLK_WAIT_FOR_SYNC();
uint32_t divider = GCLK->GENDIV.bit.DIV;
cpu_irq_leave_critical();
/* Check if the generator is using fractional or binary division */
if (!divsel && divider > 1) {
gen_input_hz /= divider;
} else if (divsel) {
gen_input_hz >>= (divider+1);
}
return gen_input_hz;
}
/**
* Writes out a given configuration of a Generic Clock Channel
* configuration to the hardware module. If the clock is currently
* running, it will be stopped.
*
* \note Once called the clock will not be running; to start the clock,
* call system_gclk_chan_enable() after configuring a clock channel.
*
* \param[in] channel Generic Clock channel to configure
* \param[in] source_generator Generator to source clock from
*
*/
void system_gclk_chan_set_config(const uint8_t channel,
enum gclk_generator source_generator)
{
/* Cache the new config to reduce sync requirements */
uint32_t new_clkctrl_config = (channel << GCLK_CLKCTRL_ID_Pos);
/* Select the desired generic clock generator */
new_clkctrl_config |= source_generator << GCLK_CLKCTRL_GEN_Pos;
/* Disable generic clock channel */
system_gclk_chan_disable(channel);
/* Write the new configuration */
GCLK->CLKCTRL.reg = new_clkctrl_config;
}
void system_gclk_chan_set_config_default(const uint8_t channel)
{
system_gclk_chan_set_config(channel, GCLK_GENERATOR_0);
}
/**
* \brief Enables a Generic Clock that was previously configured.
*
* Starts the clock generation of a Generic Clock that was previously
* configured via a call to \ref system_gclk_chan_set_config().
*
* \param[in] channel Generic Clock channel to enable
*/
void system_gclk_chan_enable(const uint8_t channel)
{
cpu_irq_enter_critical();
/* Select the requested generator channel */
*((uint8_t*)&GCLK->CLKCTRL.reg) = channel;
/* Enable the generic clock */
GCLK->CLKCTRL.reg |= GCLK_CLKCTRL_CLKEN;
cpu_irq_leave_critical();
}
/**
* Stops the clock generation of a Generic Clock that was previously started
* via a call to \ref system_gclk_chan_enable().
*
* \param[in] channel Generic Clock channel to disable
*/
void system_gclk_chan_disable(const uint8_t channel)
{
cpu_irq_enter_critical();
/* Select the requested generator channel */
*((uint8_t*)&GCLK->CLKCTRL.reg) = channel;
/* Sanity check WRTLOCK */
assert(!GCLK->CLKCTRL.bit.WRTLOCK);
/* Switch to known-working source so that the channel can be disabled */
uint32_t prev_gen_id = GCLK->CLKCTRL.bit.GEN;
GCLK->CLKCTRL.bit.GEN = 0;
/* Disable the generic clock */
GCLK->CLKCTRL.reg &= ~GCLK_CLKCTRL_CLKEN;
while (GCLK->CLKCTRL.reg & GCLK_CLKCTRL_CLKEN) {
/* Wait for clock to become disabled */
}
/* Restore previous configured clock generator */
GCLK->CLKCTRL.bit.GEN = prev_gen_id;
cpu_irq_leave_critical();
}
/**
* Determines if the specified Generic Clock channel is enabled
*
* \param[in] channel Generic Clock Channel index
*
* \return The enabled status.
* \retval true The Generic Clock channel is enabled;
* \retval false The Generic Clock channel is disabled.
*/
bool system_gclk_chan_is_enabled(const uint8_t channel)
{
bool enabled;
cpu_irq_enter_critical();
/* Select the requested generic clock channel */
*((uint8_t*)&GCLK->CLKCTRL.reg) = channel;
enabled = GCLK->CLKCTRL.bit.CLKEN;
cpu_irq_leave_critical();
return enabled;
}
/**
* Locks a generic clock channel from further configuration writes. It is only
* possible to unlock the channel configuration through a power on reset.
*
* \param[in] channel Generic Clock channel to enable
*/
void system_gclk_chan_lock(const uint8_t channel)
{
cpu_irq_enter_critical();
/* Select the requested generator channel */
*((uint8_t*)&GCLK->CLKCTRL.reg) = channel;
/* Enable the generic clock */
GCLK->CLKCTRL.reg |= GCLK_CLKCTRL_CLKEN;
cpu_irq_leave_critical();
}
/**
* Determines if the specified Generic Clock channel is locked
*
* \param[in] channel Generic Clock Channel index
*
* \return The lock status.
* \retval true The Generic Clock channel is locked;
* \retval false The Generic Clock channel is not locked.
*/
bool system_gclk_chan_is_locked(const uint8_t channel)
{
bool locked;
cpu_irq_enter_critical();
/* Select the requested generic clock channel */
*((uint8_t*)&GCLK->CLKCTRL.reg) = channel;
locked = GCLK->CLKCTRL.bit.WRTLOCK;
cpu_irq_leave_critical();
return locked;
}
/**
* Determines the clock frequency (in Hz) of a specified Generic Clock
* channel, used as a source to a device peripheral module.
*
* \param[in] channel Generic Clock Channel index
*
* \return The frequency of the generic clock channel, in Hz.
*/
uint32_t system_gclk_chan_get_hz(const uint8_t channel)
{
uint8_t gen_id;
cpu_irq_enter_critical();
/* Select the requested generic clock channel */
*((uint8_t*)&GCLK->CLKCTRL.reg) = channel;
gen_id = GCLK->CLKCTRL.bit.GEN;
cpu_irq_leave_critical();
/* Return the clock speed of the associated GCLK generator */
return system_gclk_gen_get_hz(gen_id);
}

Wyświetl plik

@ -0,0 +1,77 @@
/**
* Global interrupt management for SAM D20, SAM3 and SAM4 (NVIC based)
*
* Copyright (c) 2012-2013 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#include "system/interrupt.h"
#include <stdbool.h>
#include <assert.h>
static volatile uint32_t cpu_irq_critical_section_counter;
static volatile bool cpu_irq_prev_interrupt_state;
void cpu_irq_enter_critical(void)
{
if (cpu_irq_critical_section_counter == 0) {
if (cpu_irq_is_enabled()) {
cpu_irq_disable();
cpu_irq_prev_interrupt_state = true;
} else {
/* Make sure the to save the prev state as false */
cpu_irq_prev_interrupt_state = false;
}
}
cpu_irq_critical_section_counter++;
}
void cpu_irq_leave_critical(void)
{
/* Check if the user is trying to leave a critical section when not
* in a critical section */
assert(cpu_irq_critical_section_counter > 0);
cpu_irq_critical_section_counter--;
/* Only enable global interrupts when the counter reaches 0 and the
state of the global interrupt flag was enabled when entering
critical state */
if ((cpu_irq_critical_section_counter == 0) && (cpu_irq_prev_interrupt_state)) {
cpu_irq_enable();
}
}

Wyświetl plik

@ -0,0 +1,223 @@
/**
* SAM D20/D21/R21 Pin Multiplexer Driver
*
* Copyright (C) 2012-2014 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#include <stdbool.h>
#include "samd20.h"
#include "system/pinmux.h"
/**
* Writes out a given configuration of a Port pin configuration to the
* hardware module.
*
* \note If the pin direction is set as an output, the pull-up/pull-down input
* configuration setting is ignored.
*
* \param[in] port Base of the PORT module to configure.
* \param[in] pin_mask Mask of the port pin to configure.
* \param[in] config Configuration settings for the pin.
*/
static void _system_pinmux_config(PortGroup *const port,
const uint32_t pin_mask,
const uint8_t mux_position,
const enum system_pinmux_pin_dir direction,
const enum system_pinmux_pin_pull input_pull,
bool powersave)
{
assert(port);
/* Track the configuration bits into a temporary variable before writing */
uint32_t pin_cfg = 0;
/* Enabled powersave mode, don't create configuration */
if (!powersave) {
/* Enable the pin peripheral mux flag if non-GPIO selected (pin mux will
* be written later) and store the new mux mask */
if (mux_position != SYSTEM_PINMUX_GPIO) {
pin_cfg |= PORT_WRCONFIG_PMUXEN;
pin_cfg |= (mux_position << PORT_WRCONFIG_PMUX_Pos);
}
/* Check if the user has requested that the input buffer be enabled */
if ((direction == SYSTEM_PINMUX_PIN_DIR_INPUT) ||
(direction == SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK)) {
/* Enable input buffer flag */
pin_cfg |= PORT_WRCONFIG_INEN;
/* Enable pull-up/pull-down control flag if requested */
if (input_pull != SYSTEM_PINMUX_PIN_PULL_NONE) {
pin_cfg |= PORT_WRCONFIG_PULLEN;
}
/* Clear the port DIR bits to disable the output buffer */
port->DIRCLR.reg = pin_mask;
}
/* Check if the user has requested that the output buffer be enabled */
if ((direction == SYSTEM_PINMUX_PIN_DIR_OUTPUT) ||
(direction == SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK)) {
/* Cannot use a pullup if the output driver is enabled,
* if requested the input buffer can only sample the current
* output state */
pin_cfg &= ~PORT_WRCONFIG_PULLEN;
}
}
/* The Write Configuration register (WRCONFIG) requires the
* pins to to grouped into two 16-bit half-words - split them out here */
uint32_t lower_pin_mask = (pin_mask & 0xFFFF);
uint32_t upper_pin_mask = (pin_mask >> 16);
/* Configure the lower 16-bits of the port to the desired configuration,
* including the pin peripheral multiplexer just in case it is enabled */
port->WRCONFIG.reg
= (lower_pin_mask << PORT_WRCONFIG_PINMASK_Pos) |
pin_cfg | PORT_WRCONFIG_WRPMUX | PORT_WRCONFIG_WRPINCFG;
/* Configure the upper 16-bits of the port to the desired configuration,
* including the pin peripheral multiplexer just in case it is enabled */
port->WRCONFIG.reg
= (upper_pin_mask << PORT_WRCONFIG_PINMASK_Pos) |
pin_cfg | PORT_WRCONFIG_WRPMUX | PORT_WRCONFIG_WRPINCFG |
PORT_WRCONFIG_HWSEL;
if(!powersave) {
/* Set the pull-up state once the port pins are configured if one was
* requested and it does not violate the valid set of port
* configurations */
if (pin_cfg & PORT_WRCONFIG_PULLEN) {
/* Set the OUT register bits to enable the pullup if requested,
* clear to enable pull-down */
if (input_pull == SYSTEM_PINMUX_PIN_PULL_UP) {
port->OUTSET.reg = pin_mask;
} else {
port->OUTCLR.reg = pin_mask;
}
}
/* Check if the user has requested that the output buffer be enabled */
if ((direction == SYSTEM_PINMUX_PIN_DIR_OUTPUT) ||
(direction == SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK)) {
/* Set the port DIR bits to enable the output buffer */
port->DIRSET.reg = pin_mask;
}
}
}
static void _system_pinmux_config_default(PortGroup *const port,
const uint32_t pin_mask)
{
_system_pinmux_config(port, pin_mask,
SYSTEM_PINMUX_GPIO, /* Mux position */
SYSTEM_PINMUX_PIN_DIR_INPUT, /* Direction */
SYSTEM_PINMUX_PIN_PULL_UP, /* Pull-up/down */
false); /* Powersave */
}
/**
* Writes out a given configuration of a Port pin configuration to the hardware
* module.
*
* \note If the pin direction is set as an output, the pull-up/pull-down input
* configuration setting is ignored.
*
* \param[in] gpio_pin Index of the GPIO pin to configure.
* \param[in] config Configuration settings for the pin.
*/
void system_pinmux_pin_set_config(const uint8_t gpio_pin,
const uint8_t mux_position,
const enum system_pinmux_pin_dir direction,
const enum system_pinmux_pin_pull input_pull,
bool powersave)
{
PortGroup *const port = system_pinmux_get_group_from_gpio_pin(gpio_pin);
uint32_t pin_mask = (1UL << (gpio_pin % 32));
_system_pinmux_config(port, pin_mask,
mux_position, direction, input_pull, powersave);
}
/**
* Writes out a given configuration of a Port pin group configuration to the
* hardware module.
*
* \note If the pin direction is set as an output, the pull-up/pull-down input
* configuration setting is ignored.
*
* \param[in] port Base of the PORT module to configure.
* \param[in] mask Mask of the port pin(s) to configure.
*/
void system_pinmux_group_set_config(PortGroup *const port,
const uint32_t mask,
const uint8_t mux_position,
const enum system_pinmux_pin_dir direction,
const enum system_pinmux_pin_pull input_pull,
bool powersave)
{
assert(port);
for (int i = 0; i < 32; i++) {
if (mask & (1UL << i)) {
_system_pinmux_config(port, (1UL << i),
mux_position, direction, input_pull, powersave);
}
}
}
/**
* Configures the input sampling mode for a group of pins, to
* control when the physical I/O pin value is sampled and
* stored inside the microcontroller.
*
* \param[in] port Base of the PORT module to configure.
* \param[in] mask Mask of the port pin(s) to configure.
*/
void system_pinmux_group_set_input_sample_mode(PortGroup *const port,
const uint32_t mask,
const enum system_pinmux_pin_sample mode)
{
assert(port);
if (mode == SYSTEM_PINMUX_PIN_SAMPLE_ONDEMAND) {
port->CTRL.reg |= mask;
} else {
port->CTRL.reg &= ~mask;
}
}

Wyświetl plik

@ -0,0 +1,125 @@
/**
* SAM D20/D21/R21 GPIO Port Driver
*
* Copyright (C) 2012-2014 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#include "system/port.h"
/**
* Writes out a given configuration of a Port pin configuration to the hardware
* module.
*
* \note If the pin direction is set as an output, the pull-up/pull-down input
* configuration setting is ignored.
*
* \param[in] gpio_pin Index of the GPIO pin to configure.
*/
void port_pin_set_config(const uint8_t gpio_pin,
enum port_pin_dir direction,
enum port_pin_pull input_pull,
bool powersave)
{
system_pinmux_pin_set_config(gpio_pin,
SYSTEM_PINMUX_GPIO,
direction,
input_pull,
powersave);
}
/**
* Writes out the default configuration of a Port pin to the hardware
* module.
*
* \note If the pin direction is set as an output, the pull-up/pull-down input
* configuration setting is ignored.
*
* \param[in] gpio_pin Index of the GPIO pin to configure.
*
* - Input mode with internal pullup enabled
*/
void port_pin_set_config_default(const uint8_t gpio_pin)
{
port_pin_set_config(gpio_pin,
PORT_PIN_DIR_INPUT, /* Direction */
PORT_PIN_PULL_UP, /* Pull */
false); /* Powersave */
}
/**
* Writes out a given configuration of a Port group configuration to the
* hardware module.
*
* \note If the pin direction is set as an output, the pull-up/pull-down input
* configuration setting is ignored.
*
* \param[out] port Base of the PORT module to write to.
* \param[in] mask Mask of the port pin(s) to configure.
*/
void port_group_set_config(PortGroup *const port,
const uint32_t mask,
enum port_pin_dir direction,
enum port_pin_pull input_pull,
bool powersave)
{
system_pinmux_group_set_config(port, mask,
SYSTEM_PINMUX_GPIO,
direction,
input_pull,
powersave);
}
/**
* Writes out a given configuration of a Port group configuration to the
* hardware module.
*
* \note If the pin direction is set as an output, the pull-up/pull-down input
* configuration setting is ignored.
*
* \param[out] port Base of the PORT module to write to.
* \param[in] mask Mask of the port pin(s) to configure.
*
* - Input mode with internal pullup enabled
*/
void port_group_set_config_default(PortGroup *const port,
const uint32_t mask)
{
port_group_set_config(port, mask,
PORT_PIN_DIR_INPUT,
PORT_PIN_PULL_UP,
false);
}

Wyświetl plik

@ -0,0 +1,170 @@
/**
* SAM D20/D21/R21 Watchdog Driver
*
* Copyright (C) 2012-2014 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#include "system/wdt.h"
#include "system/system.h"
#define WDT_WAIT_FOR_SYNC(hw) while (hw->STATUS.reg & WDT_STATUS_SYNCBUSY)
/**
* Writes a given configuration of a WDT configuration to the
* hardware module
*/
void wdt_set_config(bool always_on,
bool enable,
enum gclk_generator clock_source,
enum wdt_period timeout_period,
enum wdt_period window_period,
enum wdt_period early_warning_period)
{
Wdt *const hw = WDT;
/* Turn on the digital interface clock */
system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBA, PM_APBAMASK_WDT);
/* Check of the Watchdog has been locked to be always on, if so, abort */
if (wdt_is_locked()) {
return;// STATUS_ERR_IO;
}
/* Check for an invalid timeout period, abort if found */
if (timeout_period == WDT_PERIOD_NONE) {
return;// STATUS_ERR_INVALID_ARG;
}
/* Make sure the Window and Early Warning periods are not more than the
* reset period, abort if either is invalid */
if ((timeout_period < window_period) ||
(timeout_period < early_warning_period)) {
return;// STATUS_ERR_INVALID_ARG;
}
/* Disable the Watchdog module */
hw->CTRL.reg &= ~WDT_CTRL_ENABLE;
if(enable == false) {
return;// STATUS_OK;
}
/* Configure GCLK channel and enable clock */
system_gclk_chan_set_config(WDT_GCLK_ID, clock_source);
system_gclk_chan_enable(WDT_GCLK_ID);
if (always_on) {
system_gclk_chan_lock(WDT_GCLK_ID);
}
WDT_WAIT_FOR_SYNC(hw);
uint32_t new_config = 0;
/* Update the timeout period value with the requested period */
new_config |= (timeout_period - 1) << WDT_CONFIG_PER_Pos;
/* Check if the user has requested a reset window period */
if (window_period != WDT_PERIOD_NONE) {
hw->CTRL.reg |= WDT_CTRL_WEN;
/* Update and enable the timeout period value */
new_config |= (window_period - 1) << WDT_CONFIG_WINDOW_Pos;
} else {
/* Ensure the window enable control flag is cleared */
hw->CTRL.reg &= ~WDT_CTRL_WEN;
}
WDT_WAIT_FOR_SYNC(hw);
/* Write the new Watchdog configuration */
hw->CONFIG.reg = new_config;
/* Check if the user has requested an early warning period */
if (early_warning_period != WDT_PERIOD_NONE) {
WDT_WAIT_FOR_SYNC(hw);
/* Set the Early Warning period */
hw->EWCTRL.reg
= (early_warning_period - 1) << WDT_EWCTRL_EWOFFSET_Pos;
}
WDT_WAIT_FOR_SYNC(hw);
/* Either enable or lock-enable the Watchdog timer depending on the user
* settings */
if (always_on) {
hw->CTRL.reg |= WDT_CTRL_ALWAYSON;
} else {
hw->CTRL.reg |= WDT_CTRL_ENABLE;
}
}
/**
* Writes the default configuration of thw WDT to the hardware module
*
* - Not locked, to allow for further (re-)configuration
* - Enable WDT
* - Watchdog timer sourced from Generic Clock Channel 4
* - A timeout period of 16384 clocks of the Watchdog module clock
* - No window period, so that the Watchdog count can be reset at any time
* - No early warning period to indicate the Watchdog will soon expire
*/
void wdt_set_config_default(void)
{
wdt_set_config(false, /* Lock WDT */
true, /* Enable WDT */
GCLK_GENERATOR_4, /* Clock Source */
WDT_PERIOD_16384CLK, /* Timeout Period */
WDT_PERIOD_NONE, /* Window Period */
WDT_PERIOD_NONE); /* Early Warning Period */
}
/**
* Resets the current count of the Watchdog Timer, restarting the timeout
* period count elapsed. This function should be called after the window
* period (if one was set in the module configuration) but before the timeout
* period to prevent a reset of the system.
*/
void wdt_reset_count(void)
{
Wdt *const hw = WDT;
WDT_WAIT_FOR_SYNC(hw);
/* Disable the Watchdog module */
hw->CLEAR.reg = WDT_CLEAR_CLEAR_KEY;
}

Wyświetl plik

@ -0,0 +1,720 @@
/**
* SAM D20/D21/R21 TC - Timer Counter Driver
*
* Copyright (C) 2013-2014 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#include <assert.h>
#include "system/clock.h"
#include "tc/tc_driver.h"
#include "samd20.h"
#define WAIT_FOR_SYNC(tc) while (tc->COUNT8.STATUS.reg & TC_STATUS_SYNCBUSY)
#define TC_INST_APBCMASKS { \
PM_APBCMASK_TC0, \
PM_APBCMASK_TC1, \
PM_APBCMASK_TC2, \
PM_APBCMASK_TC3, \
PM_APBCMASK_TC4, \
PM_APBCMASK_TC5, \
}
#define TC_INST_GCLK_IDS { \
TC0_GCLK_ID, \
TC1_GCLK_ID, \
TC2_GCLK_ID, \
TC3_GCLK_ID, \
TC4_GCLK_ID, \
TC5_GCLK_ID, \
}
/**
* Enables a TC module that has been previously initialized. The counter will
* start when the counter is enabled.
*
* \note When the counter is configured to re-trigger on an event, the counter
* will not start until the start function is used.
*/
static inline void tc_enable(Tc* const hw)
{
assert(hw);
WAIT_FOR_SYNC(hw);
/* Enable TC module */
hw->COUNT8.CTRLA.reg |= TC_CTRLA_ENABLE;
}
/**
* Disables a TC module and stops the counter.
*/
static inline void tc_disable(Tc* const hw)
{
assert(hw);
WAIT_FOR_SYNC(hw);
/* Disable TC module */
hw->COUNT8.CTRLA.reg &= ~TC_CTRLA_ENABLE;
}
/**
* Starts or restarts an initialized TC module's counter.
*/
static inline void tc_start_counter(Tc* const hw)
{
assert(hw);
/* Make certain that there are no conflicting commands in the register */
WAIT_FOR_SYNC(hw);
hw->COUNT8.CTRLBCLR.reg = TC_CTRLBCLR_CMD_NONE;
/* Write command to execute */
WAIT_FOR_SYNC(hw);
hw->COUNT8.CTRLBSET.reg = TC_CTRLBSET_CMD(1);
}
/**
* Stops the counter. When the counter is stopped
* the value in the count value is set to 0 if the counter was
* counting up, or max or the top value if the counter was counting
* down when stopped.
*/
static inline void tc_stop_counter(Tc* const hw)
{
assert(hw);
WAIT_FOR_SYNC(hw);
/* Write command to execute */
hw->COUNT8.CTRLBSET.reg = TC_CTRLBSET_CMD(2);
}
/**
* Retrieves the status of the module, giving overall state information.
*
* \return Bitmask of \c TC_STATUS_* flags
*
* \retval TC_STATUS_CHANNEL_0_MATCH Timer channel 0 compare/capture match
* \retval TC_STATUS_CHANNEL_1_MATCH Timer channel 1 compare/capture match
* \retval TC_STATUS_SYNC_READY Timer read synchronization has completed
* \retval TC_STATUS_CAPTURE_OVERFLOW Timer capture data has overflowed
* \retval TC_STATUS_COUNT_OVERFLOW Timer count value has overflowed
*/
static inline uint32_t tc_get_status(Tc* const hw)
{
assert(hw);
uint32_t int_flags = hw->COUNT8.INTFLAG.reg;
uint32_t status_flags = 0;
/* Check for TC channel 0 match */
if (int_flags & TC_INTFLAG_MC(1)) {
status_flags |= TC_STATUS_CHANNEL_0_MATCH;
}
/* Check for TC channel 1 match */
if (int_flags & TC_INTFLAG_MC(2)) {
status_flags |= TC_STATUS_CHANNEL_1_MATCH;
}
/* Check for TC read synchronization ready */
if (int_flags & TC_INTFLAG_SYNCRDY) {
status_flags |= TC_STATUS_SYNC_READY;
}
/* Check for TC capture overflow */
if (int_flags & TC_INTFLAG_ERR) {
status_flags |= TC_STATUS_CAPTURE_OVERFLOW;
}
/* Check for TC count overflow */
if (int_flags & TC_INTFLAG_OVF) {
status_flags |= TC_STATUS_COUNT_OVERFLOW;
}
return status_flags;
}
/**
* Clears the given status flag of the module.
*
* \param[in] status_flags Bitmask of \c TC_STATUS_* flags to clear
*/
static inline void tc_clear_status(Tc* const hw,
const uint32_t status_flags)
{
assert(hw);
uint32_t int_flags = 0;
/* Check for TC channel 0 match */
if (status_flags & TC_STATUS_CHANNEL_0_MATCH) {
int_flags |= TC_INTFLAG_MC(1);
}
/* Check for TC channel 1 match */
if (status_flags & TC_STATUS_CHANNEL_1_MATCH) {
int_flags |= TC_INTFLAG_MC(2);
}
/* Check for TC read synchronization ready */
if (status_flags & TC_STATUS_SYNC_READY) {
int_flags |= TC_INTFLAG_SYNCRDY;
}
/* Check for TC capture overflow */
if (status_flags & TC_STATUS_CAPTURE_OVERFLOW) {
int_flags |= TC_INTFLAG_ERR;
}
/* Check for TC count overflow */
if (status_flags & TC_STATUS_COUNT_OVERFLOW) {
int_flags |= TC_INTFLAG_OVF;
}
/* Clear interrupt flag */
hw->COUNT8.INTFLAG.reg = int_flags;
}
/**
* Sets the current timer count value of a initialized TC module. The
* specified TC module may be started or stopped.
*
* \param[in] count New timer count value to set
*
* \return Status of the count update procedure.
*/
void tc_set_count_value(Tc* const hw, const uint32_t count)
{
assert(hw);
WAIT_FOR_SYNC(hw);
/* Write to based on the TC counter_size */
switch (hw->COUNT8.CTRLA.reg & TC_CTRLA_MODE_Msk) {
case TC_COUNTER_SIZE_8BIT:
assert((count & ~0xFF) == 0);
hw->COUNT8.COUNT.reg = (uint8_t)count;
return;
case TC_COUNTER_SIZE_16BIT:
assert((count & ~0xFFFF) == 0);
hw->COUNT16.COUNT.reg = (uint16_t)count;
return;
case TC_COUNTER_SIZE_32BIT:
hw->COUNT32.COUNT.reg = (uint32_t)count;
return;
default:
assert(TC_ERROR_INVALID_STATE);
}
}
/**
* Retrieves the current count value of a TC module. The specified TC module
* may be started or stopped.
*
* \param[in] module_inst Pointer to the software module instance struct
*
* \return Count value of the specified TC module.
*/
uint32_t tc_get_count_value(Tc* const hw)
{
assert(hw);
WAIT_FOR_SYNC(hw);
/* Read from based on the TC counter size */
switch (hw->COUNT8.CTRLA.reg & TC_CTRLA_MODE_Msk) {
case TC_COUNTER_SIZE_8BIT:
return (uint32_t)hw->COUNT8.COUNT.reg;
case TC_COUNTER_SIZE_16BIT:
return (uint32_t)hw->COUNT16.COUNT.reg;
case TC_COUNTER_SIZE_32BIT:
return hw->COUNT32.COUNT.reg;
default:
assert(TC_ERROR_INVALID_STATE);
return 0;
}
}
/**
* Retrieves the capture value in the indicated TC module capture channel.
*
* \param[in] module_inst Pointer to the software module instance struct
* \param[in] channel_index Index of the Compare Capture channel to read
*
* \return Capture value stored in the specified timer channel.
*/
uint32_t tc_get_capture_value(Tc* const hw,
const enum tc_compare_capture_channel channel_index)
{
assert(hw);
WAIT_FOR_SYNC(hw);
/* Read out based on the TC counter size */
switch (hw->COUNT8.CTRLA.reg & TC_CTRLA_MODE_Msk) {
case TC_COUNTER_SIZE_8BIT:
if (channel_index < NUMBER_OF_COMPARE_CAPTURE_CHANNELS) {
return hw->COUNT8.CC[channel_index].reg;
}
case TC_COUNTER_SIZE_16BIT:
if (channel_index < NUMBER_OF_COMPARE_CAPTURE_CHANNELS) {
return hw->COUNT16.CC[channel_index].reg;
}
case TC_COUNTER_SIZE_32BIT:
if (channel_index < NUMBER_OF_COMPARE_CAPTURE_CHANNELS) {
return hw->COUNT32.CC[channel_index].reg;
}
default:
assert(TC_ERROR_INVALID_STATE);
return 0;
}
assert(TC_ERROR_INVALID_ARG);
return 0;
}
/**
* Writes a compare value to the given TC module compare/capture channel.
*
* \param[in] module_inst Pointer to the software module instance struct
* \param[in] channel_index Index of the compare channel to write to
* \param[in] compare New compare value to set
*
* \return Status of the compare update procedure.
*
* \retval STATUS_OK The compare value was updated successfully
* \retval STATUS_ERR_INVALID_ARG An invalid channel index was supplied
*/
void tc_set_compare_value(Tc* const hw,
const enum tc_compare_capture_channel channel_index,
const uint32_t compare)
{
assert(hw);
assert(compare);
WAIT_FOR_SYNC(hw);
/* Read out based on the TC counter size */
switch (hw->COUNT8.CTRLA.reg & TC_CTRLA_MODE_Msk) {
case TC_COUNTER_SIZE_8BIT:
if (channel_index < NUMBER_OF_COMPARE_CAPTURE_CHANNELS) {
hw->COUNT8.CC[channel_index].reg = (uint8_t)compare;
return;
}
case TC_COUNTER_SIZE_16BIT:
if (channel_index < NUMBER_OF_COMPARE_CAPTURE_CHANNELS) {
hw->COUNT16.CC[channel_index].reg = (uint16_t)compare;
return;
}
case TC_COUNTER_SIZE_32BIT:
if (channel_index < NUMBER_OF_COMPARE_CAPTURE_CHANNELS) {
hw->COUNT32.CC[channel_index].reg = (uint32_t)compare;
return;
}
default:
assert(TC_ERROR_INVALID_STATE);
return;
}
/* Channel index was wrong */
assert(TC_ERROR_INVALID_ARG);
return;
}
/**
* Returns the instance number
*/
static inline uint32_t tc_get_instance_number(Tc* const hw)
{
uint32_t i;
Tc* const tc_instances[] = TC_INSTS;
for (i = 0; i < TC_INST_NUM; i++) {
if (tc_instances[i] == hw) {
return i;
}
}
assert(TC_ERROR_INVALID_DEVICE);
return 0;
}
/**
* Gets the slave instance of a given TC instance. Asserts if no such
* instance exists.
*/
const Tc* tc_get_slave_instance(Tc* const hw) {
uint32_t i;
/* Search through all even numbered TC instances, excluding the last
* instance (which should be odd anyway) */
Tc* const tc_instances[] = TC_INSTS;
for (i = 0; i < TC_INST_NUM - 1; i += 2) {
/* Match with the current */
if (tc_instances[i] == hw) {
return tc_instances[i + 1];
}
}
assert(TC_ERROR_NO_32BIT_SLAVE_EXISTS);
return 0;
}
/**
* Resets the TC module, restoring all hardware module registers to their
* default values and disabling the module. The TC module will not be
* accessible while the reset is being performed.
*
* \note When resetting a 32-bit counter only the master TC module's instance
* structure should be passed to the function.
*
* \param[in] module_inst Pointer to the software module instance struct
*
* \return Status of the procedure
* \retval STATUS_OK The module was reset successfully
* \retval STATUS_ERR_UNSUPPORTED_DEV A 32-bit slave TC module was passed to
* the function. Only use reset on master
* TC.
*/
void tc_reset(Tc* const hw)
{
if (hw->COUNT8.STATUS.reg & TC_STATUS_SLAVE) {
assert(TC_ERROR_INVALID_DEVICE);
return;
}
/* Disable this module if it is running */
if (hw->COUNT8.CTRLA.reg & TC_CTRLA_ENABLE) {
tc_disable(hw);
WAIT_FOR_SYNC(hw);
}
/* Reset this TC module */
hw->COUNT8.CTRLA.reg |= TC_CTRLA_SWRST;
return;
}
/**
* \brief Set the timer TOP/period value.
*
* For 8-bit counter size this function writes the top value to the period
* register.
*
* For 16- and 32-bit counter size this function writes the top value to
* Capture Compare register 0. The value in this register can not be used for
* any other purpose.
*
* \note This function is designed to be used in PWM or frequency
* match modes only. When the counter is set to 16- or 32-bit counter
* size. In 8-bit counter size it will always be possible to change the
* top value even in normal mode.
*
* \param[in] top_value New timer TOP value to set
*
* \return Status of the TOP set procedure.
*
* \retval STATUS_OK The timer TOP value was updated successfully
* \retval STATUS_ERR_INVALID_ARG The configured TC module counter size in the
* module instance is invalid.
*/
void tc_set_top_value(Tc* const hw,
const uint32_t top_value)
{
WAIT_FOR_SYNC(hw);
switch (hw->COUNT8.CTRLA.reg & TC_CTRLA_MODE_Msk) {
case TC_COUNTER_SIZE_8BIT:
assert((top_value & ~0xFF) == 0);
hw->COUNT8.PER.reg = (uint8_t)top_value;
return;
case TC_COUNTER_SIZE_16BIT:
assert((top_value & ~0xFFFF) == 0);
hw->COUNT16.CC[0].reg = (uint16_t)top_value;
return;
case TC_COUNTER_SIZE_32BIT:
hw->COUNT32.CC[0].reg = (uint32_t)top_value;
return;
default:
assert(TC_ERROR_INVALID_STATE);
}
return;
}
/**
* \brief Enables a TC module event input or output.
*
* Enables one or more input or output events to or from the TC module.
* See \ref tc_events for a list of events this module supports.
*
* \note Events cannot be altered while the module is enabled.
*
* \param[in] events Struct containing flags of events to enable
*/
static inline void tc_enable_events(Tc* const hw,
struct tc_events *const events)
{
/* Sanity check arguments */
assert(hw);
assert(events);
uint32_t event_mask = 0;
if (events->invert_event_input == true) {
event_mask |= TC_EVCTRL_TCINV;
}
if (events->on_event_perform_action == true) {
event_mask |= TC_EVCTRL_TCEI;
}
if (events->generate_event_on_overflow == true) {
event_mask |= TC_EVCTRL_OVFEO;
}
for (uint8_t i = 0; i < NUMBER_OF_COMPARE_CAPTURE_CHANNELS; i++) {
if (events->generate_event_on_compare_channel[i] == true) {
event_mask |= (TC_EVCTRL_MCEO(1) << i);
}
}
hw->COUNT8.EVCTRL.reg |= event_mask | events->event_action;
}
/**
* \brief Disables a TC module event input or output.
*
* Disables one or more input or output events to or from the TC module.
* See \ref tc_events for a list of events this module supports.
*
* \note Events cannot be altered while the module is enabled.
*
* \param[in] events Struct containing flags of events to disable
*/
static inline void tc_disable_events(Tc* const hw,
struct tc_events *const events)
{
assert(hw);
assert(events);
uint32_t event_mask = 0;
if (events->invert_event_input == true) {
event_mask |= TC_EVCTRL_TCINV;
}
if (events->on_event_perform_action == true) {
event_mask |= TC_EVCTRL_TCEI;
}
if (events->generate_event_on_overflow == true) {
event_mask |= TC_EVCTRL_OVFEO;
}
for (uint8_t i = 0; i < NUMBER_OF_COMPARE_CAPTURE_CHANNELS; i++) {
if (events->generate_event_on_compare_channel[i] == true) {
event_mask |= (TC_EVCTRL_MCEO(1) << i);
}
}
hw->COUNT8.EVCTRL.reg &= ~event_mask;
}
/**
* Enables the clock and initializes the TC module, based on the given
* configuration values.
*
* \param[in] hw Pointer to the TC hardware module
*/
enum tc_status_t tc_init(Tc* const hw,
enum gclk_generator source_clock,
enum tc_counter_size counter_size, /* 8, 16 or 32bit */
enum tc_clock_prescaler clock_prescaler,
enum tc_wave_generation wave_generation,
enum tc_reload_action reload_action,
enum tc_count_direction count_direction,
uint8_t waveform_invert_output,
bool oneshot,
bool run_in_standby,
uint32_t value,
uint32_t top_value,
bool* enable_capture_channels,
uint32_t* compare_channel_values)
{
assert(hw);
const Tc* slave;
uint16_t ctrla_tmp = 0;
uint8_t ctrlbset_tmp = 0;
uint8_t ctrlc_tmp = 0;
uint8_t tc_instance_n = tc_get_instance_number(hw);
uint32_t const tc_apbcmasks[] = TC_INST_APBCMASKS;
uint8_t tc_gclk_ids[] = TC_INST_GCLK_IDS;
if (hw->COUNT8.CTRLA.reg & TC_CTRLA_SWRST) {
/* We are in the middle of a reset. Abort. */
return TC_STATUS_BUSY;
}
if (hw->COUNT8.STATUS.reg & TC_STATUS_SLAVE) {
/* Module is used as a slave */
return TC_STATUS_DENIED;
}
if (hw->COUNT8.CTRLA.reg & TC_CTRLA_ENABLE) {
/* Module must be disabled before initialization. Abort. */
return TC_STATUS_DENIED;
}
/* Enable the user interface clock in the PM */
system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC,
tc_apbcmasks[tc_instance_n]);
/* Enable the slave counter if counter_size is 32 bit */
if (counter_size == TC_COUNTER_SIZE_32BIT)
{
if ((slave = tc_get_slave_instance(hw))) {
/* Enable the user interface clock in the PM */
system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC,
tc_apbcmasks[tc_instance_n + 1]);
}
}
/* Setup clock for module */
system_gclk_chan_set_config(tc_gclk_ids[tc_instance_n], source_clock);
system_gclk_chan_enable(tc_gclk_ids[tc_instance_n]);
/* Set ctrla register */
ctrla_tmp = (uint32_t)counter_size | (uint32_t)wave_generation |
(uint32_t)reload_action | (uint32_t)clock_prescaler;
if (run_in_standby) {
ctrla_tmp |= TC_CTRLA_RUNSTDBY;
}
/* Write configuration to register */
WAIT_FOR_SYNC(hw);
hw->COUNT8.CTRLA.reg = ctrla_tmp;
/* Set ctrlb register */
if (oneshot) {
ctrlbset_tmp = TC_CTRLBSET_ONESHOT;
}
if (count_direction) {
ctrlbset_tmp |= TC_CTRLBSET_DIR;
}
/* Clear old ctrlb configuration */
WAIT_FOR_SYNC(hw);
hw->COUNT8.CTRLBCLR.reg = 0xFF;
/* Check if we actually need to go into a wait state. */
if (ctrlbset_tmp) {
WAIT_FOR_SYNC(hw);
/* Write configuration to register */
hw->COUNT8.CTRLBSET.reg = ctrlbset_tmp;
}
/* Set ctrlc register */
ctrlc_tmp = waveform_invert_output;
for (uint8_t i = 0; i < NUMBER_OF_COMPARE_CAPTURE_CHANNELS; i++) {
if (enable_capture_channels[i] == true) {
ctrlc_tmp |= (TC_CTRLC_CPTEN(1) << i);
}
}
/* Write configuration to register */
WAIT_FOR_SYNC(hw);
hw->COUNT8.CTRLC.reg = ctrlc_tmp;
/* Write Start Value */
tc_set_count_value(hw, value);
/* Write Top Value - Only cool for 8 bit!*/
tc_set_top_value(hw, top_value);
/* Write Compare Values */
for (uint8_t i = 0; i < NUMBER_OF_COMPARE_CAPTURE_CHANNELS; i++) {
tc_set_compare_value(hw, i, compare_channel_values[i]);
}
return TC_STATUS_OK;
}
/**
* Enables the clock and initializes the TC module, based on default
* values.
*
* \param[in] hw Pointer to the TC hardware module
*/
enum tc_status_t tc_init_default(Tc* const hw)
{
bool capture_channel_enables[] = {false, false};
uint32_t capture_channel_values[] = {0x0000, 0x0000};
return tc_init(hw,
GCLK_GENERATOR_0,
TC_COUNTER_SIZE_16BIT,
TC_CLOCK_PRESCALER_DIV1,
TC_WAVE_GENERATION_NORMAL_FREQ,
TC_RELOAD_ACTION_GCLK,
TC_COUNT_DIRECTION_UP,
TC_WAVEFORM_INVERT_OUTPUT_NONE,
false, /* Oneshot = false */
false, /* Run in standby = false */
0x0000, /* Initial value */
0x0000, /* Top value */
capture_channel_enables, /* Capture Channel Enables */
capture_channel_values); /* Compare Channels Values */
}

Wyświetl plik

@ -91,8 +91,13 @@ typedef void (*tc_ptr_type)(void);
volatile tc_ptr_type tc_ptr;
/**
*
* Runs a test case
*/
__verification__ void tc_run() {
(*tc_ptr)();
}
/**
* Called to trigger the test case run
@ -101,6 +106,6 @@ __verification__ void tc_main(void) {
/* Wait forever while test cases execute */
while (1) {
(*tc_ptr)();
tc_run();
}
}

Wyświetl plik

@ -1,7 +1,7 @@
'''Wrapper for verification_tc.c
Generated with:
tools/verification/ctypesgen/ctypesgen.py -o tools/verification/verification_tc.py --cpp=arm-none-eabi-gcc -E -DCTYPESGEN -g3 -ggdb -Wall -Wextra -std=gnu99 -ffunction-sections -fdata-sections -mcpu=cortex-m0plus -mthumb -DSAMD20J18 -D__SAMD20J18__ -Iinc/ -Ichip/ -Ichip/cmsis/ -Isamd20/ -Isamd20/component/ tools/verification/verification_tc.c
tools/verification/ctypesgen/ctypesgen.py -o tools/verification/verification_tc.py --cpp=arm-none-eabi-gcc -E -DCTYPESGEN -g3 -ggdb -Wall -Wextra -std=gnu99 -ffunction-sections -fdata-sections -mcpu=cortex-m0plus -mthumb -DSAMD20E17 -D__SAMD20E17__ -D__SEMIHOSTING__ -Iinc/ -Ichip/ -Ichip/cmsis/ -Isamd20/ -Isamd20/component/ tools/verification/verification_tc.c
Do not modify this file.
'''

Wyświetl plik

@ -6,7 +6,7 @@
<setting alwaysvectorfont="no"/>
<setting verticaltext="up"/>
</settings>
<grid distance="0.125" unitdist="mm" unit="mm" style="lines" multiple="1" display="yes" altdistance="0.025" altunitdist="inch" altunit="inch"/>
<grid distance="1" unitdist="mm" unit="mm" style="lines" multiple="1" display="yes" altdistance="0.025" altunitdist="inch" altunit="inch"/>
<layers>
<layer number="1" name="Top" color="4" fill="1" visible="yes" active="yes"/>
<layer number="2" name="Route2" color="1" fill="3" visible="no" active="no"/>

Wyświetl plik

@ -10494,6 +10494,7 @@ package type OT</description>
<part name="U$100" library="microbuilder_v3" deviceset="GND" device=""/>
<part name="R22" library="microbuilder_v3" deviceset="RESISTOR" device="_0402" value="1Ω"/>
<part name="R23" library="microbuilder_v3" deviceset="RESISTOR" device="_0402" value="1Ω"/>
<part name="FRAME5" library="SparkFun" deviceset="FRAME-LETTER" device=""/>
</parts>
<sheets>
<sheet>
@ -10538,6 +10539,70 @@ a bourns CVH252009-3R3M with 0.1Ω ESR max in a 1008 package</text>
<text x="381" y="284.48" size="1.778" layer="97" font="vector" ratio="12">TLV70033</text>
<text x="10.16" y="345.44" size="2.54" layer="97" font="vector" ratio="11">Busses</text>
<text x="391.16" y="360.68" size="2.54" layer="97" font="vector" ratio="11">USB Interface</text>
<wire x1="12.7" y1="542.29" x2="60.96" y2="542.29" width="0.6096" layer="97"/>
<wire x1="60.96" y1="542.29" x2="60.96" y2="533.4" width="0.6096" layer="97"/>
<wire x1="60.96" y1="533.4" x2="60.96" y2="523.24" width="0.6096" layer="97"/>
<wire x1="60.96" y1="523.24" x2="12.7" y2="523.24" width="0.6096" layer="97"/>
<wire x1="12.7" y1="523.24" x2="12.7" y2="542.29" width="0.6096" layer="97"/>
<text x="20.32" y="530.86" size="5.08" layer="97" font="vector" ratio="11">USB 5.0V</text>
<wire x1="81.28" y1="511.81" x2="111.76" y2="511.81" width="0.6096" layer="97"/>
<wire x1="111.76" y1="511.81" x2="111.76" y2="502.92" width="0.6096" layer="97"/>
<wire x1="111.76" y1="502.92" x2="111.76" y2="492.76" width="0.6096" layer="97"/>
<wire x1="111.76" y1="492.76" x2="81.28" y2="492.76" width="0.6096" layer="97"/>
<wire x1="81.28" y1="492.76" x2="81.28" y2="502.92" width="0.6096" layer="97"/>
<text x="88.9" y="500.38" size="5.08" layer="97" font="vector" ratio="11">1.2V</text>
<wire x1="81.28" y1="502.92" x2="81.28" y2="511.81" width="0.6096" layer="97"/>
<wire x1="60.96" y1="533.4" x2="71.12" y2="533.4" width="0.6096" layer="97"/>
<wire x1="71.12" y1="533.4" x2="71.12" y2="502.92" width="0.6096" layer="97"/>
<wire x1="71.12" y1="502.92" x2="81.28" y2="502.92" width="0.6096" layer="97"/>
<wire x1="81.28" y1="481.33" x2="111.76" y2="481.33" width="0.6096" layer="97"/>
<wire x1="111.76" y1="481.33" x2="111.76" y2="472.44" width="0.6096" layer="97"/>
<wire x1="111.76" y1="472.44" x2="111.76" y2="462.28" width="0.6096" layer="97"/>
<wire x1="111.76" y1="462.28" x2="81.28" y2="462.28" width="0.6096" layer="97"/>
<wire x1="81.28" y1="462.28" x2="81.28" y2="472.44" width="0.6096" layer="97"/>
<text x="88.9" y="469.9" size="5.08" layer="97" font="vector" ratio="11">ADJ</text>
<wire x1="81.28" y1="472.44" x2="81.28" y2="481.33" width="0.6096" layer="97"/>
<wire x1="71.12" y1="502.92" x2="71.12" y2="472.44" width="0.6096" layer="97"/>
<wire x1="71.12" y1="472.44" x2="81.28" y2="472.44" width="0.6096" layer="97"/>
<wire x1="81.28" y1="542.29" x2="111.76" y2="542.29" width="0.6096" layer="97"/>
<wire x1="111.76" y1="542.29" x2="111.76" y2="533.4" width="0.6096" layer="97"/>
<wire x1="111.76" y1="533.4" x2="111.76" y2="523.24" width="0.6096" layer="97"/>
<wire x1="111.76" y1="523.24" x2="81.28" y2="523.24" width="0.6096" layer="97"/>
<wire x1="81.28" y1="523.24" x2="81.28" y2="533.4" width="0.6096" layer="97"/>
<text x="88.9" y="530.86" size="5.08" layer="97" font="vector" ratio="11">3.3V</text>
<wire x1="81.28" y1="533.4" x2="81.28" y2="542.29" width="0.6096" layer="97"/>
<wire x1="71.12" y1="533.4" x2="81.28" y2="533.4" width="0.6096" layer="97"/>
<wire x1="111.76" y1="533.4" x2="124.46" y2="533.4" width="0.6096" layer="97"/>
<text x="149.86" y="530.86" size="5.08" layer="97" font="vector" ratio="11">STM</text>
<wire x1="124.46" y1="533.4" x2="147.32" y2="533.4" width="0.6096" layer="97"/>
<wire x1="111.76" y1="472.44" x2="129.54" y2="472.44" width="0.6096" layer="97"/>
<wire x1="134.62" y1="472.44" x2="149.86" y2="472.44" width="0.6096" layer="97"/>
<wire x1="129.54" y1="472.44" x2="132.08" y2="474.98" width="0.6096" layer="97"/>
<wire x1="111.76" y1="502.92" x2="119.38" y2="502.92" width="0.6096" layer="97"/>
<wire x1="119.38" y1="502.92" x2="119.38" y2="482.6" width="0.6096" layer="97"/>
<wire x1="119.38" y1="482.6" x2="129.54" y2="482.6" width="0.6096" layer="97"/>
<wire x1="129.54" y1="482.6" x2="132.08" y2="485.14" width="0.6096" layer="97"/>
<wire x1="124.46" y1="533.4" x2="124.46" y2="492.76" width="0.6096" layer="97"/>
<wire x1="124.46" y1="492.76" x2="129.54" y2="492.76" width="0.6096" layer="97"/>
<wire x1="129.54" y1="492.76" x2="132.08" y2="495.3" width="0.6096" layer="97"/>
<wire x1="134.62" y1="492.76" x2="149.86" y2="492.76" width="0.6096" layer="97"/>
<wire x1="134.62" y1="482.6" x2="149.86" y2="482.6" width="0.6096" layer="97"/>
<wire x1="149.86" y1="492.76" x2="149.86" y2="472.44" width="0.6096" layer="97"/>
<wire x1="162.56" y1="481.33" x2="193.04" y2="481.33" width="0.6096" layer="97"/>
<wire x1="193.04" y1="481.33" x2="193.04" y2="472.44" width="0.6096" layer="97"/>
<wire x1="193.04" y1="472.44" x2="193.04" y2="462.28" width="0.6096" layer="97"/>
<wire x1="193.04" y1="462.28" x2="162.56" y2="462.28" width="0.6096" layer="97"/>
<wire x1="162.56" y1="462.28" x2="162.56" y2="472.44" width="0.6096" layer="97"/>
<text x="170.18" y="469.9" size="5.08" layer="97" font="vector" ratio="11">1.8V</text>
<wire x1="162.56" y1="472.44" x2="162.56" y2="481.33" width="0.6096" layer="97"/>
<wire x1="149.86" y1="472.44" x2="157.48" y2="472.44" width="0.6096" layer="97"/>
<wire x1="157.48" y1="472.44" x2="162.56" y2="472.44" width="0.6096" layer="97"/>
<wire x1="193.04" y1="472.44" x2="200.66" y2="472.44" width="0.6096" layer="97"/>
<wire x1="200.66" y1="472.44" x2="210.82" y2="472.44" width="0.6096" layer="97"/>
<wire x1="157.48" y1="472.44" x2="154.94" y2="474.98" width="0.6096" layer="97"/>
<wire x1="157.48" y1="472.44" x2="154.94" y2="469.9" width="0.6096" layer="97"/>
<wire x1="200.66" y1="472.44" x2="198.12" y2="474.98" width="0.6096" layer="97"/>
<wire x1="200.66" y1="472.44" x2="198.12" y2="469.9" width="0.6096" layer="97"/>
</plain>
<instances>
<instance part="FRAME1" gate="G$1" x="0" y="0"/>
@ -10748,6 +10813,8 @@ a bourns CVH252009-3R3M with 0.1Ω ESR max in a 1008 package</text>
<instance part="U$100" gate="G$1" x="111.76" y="203.2"/>
<instance part="R22" gate="G$1" x="91.44" y="215.9" rot="R90"/>
<instance part="R23" gate="G$1" x="83.82" y="215.9" rot="R90"/>
<instance part="FRAME5" gate="G$1" x="0" y="375.92"/>
<instance part="FRAME5" gate="G$2" x="147.32" y="375.92"/>
</instances>
<busses>
</busses>

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 3.0 MiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 38 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 15 KiB

Wyświetl plik

@ -0,0 +1,20 @@
## Design of the Si TX Spectral Shaping Filter
It's a 17-tap digital FIR filter. No idea what the sample rate is, but
it could be the IF? That's 400kHz or so..
## Python Usage
`ipython --pylab`
`%run test.ipy`
## Calcuating new coefficients
There's an awesome calculator here
[here](http://t-filter.appspot.com/fir/index.html)
## Sources
The python script is from
[here](http://nbviewer.ipython.org/github/unpingco/Python-for-Signal-Processing/blob/master/Filtering.ipynb)

Wyświetl plik

@ -0,0 +1,57 @@
from __future__ import division
from scipy import signal
fig, axs = subplots(2,1,sharex=True)
subplots_adjust( hspace = .2 )
fig.set_size_inches((5,5))
t_fir_coeff = [0.01665389596732681,
0.07353658710395161,
0.10040345335534452,
0.04751332314075821,
-0.06317967799551721,
-0.09143711477971043,
0.06319322564548596,
0.31257963657965065,
0.43524399610103215,
0.31257963657965065,
0.06319322564548596,
-0.09143711477971043,
-0.06317967799551721,
0.04751332314075821,
0.10040345335534452,
0.07353658710395161,
0.01665389596732681]
# Default si coefficients
si_default_fir_coeff = [0x1, 0x3, 0x8, 0x11, 0x21, 0x36, 0x4d, 0x60, 0x67]
# Reflects an array of coefficients about the last element
def sym_fir_coeff(coeff):
for i in range(len(coeff)-2, -1, -1):
coeff.append(coeff[i])
return coeff
# Normalises the si's 8-bit coefficients to 0 - 1
def si_normalise_coeff(coeff):
return [x / 0x300 for x in coeff]
si_default = si_normalise_coeff(sym_fir_coeff(si_default_fir_coeff))
print si_default
print len(si_default)
fir_coeff = si_default
ax=axs[0]
w,h=signal.freqz(fir_coeff,1) # Compute impulse response
ax.plot(w,20*log10(abs(h)))
ax.set_ylabel(r"$20 \log_{10} |H(\omega)| $",fontsize=18)
ax.grid()
ax=axs[1]
ax.plot(w,angle(h)/pi*180)
ax.set_xlabel(r'$\omega$ (radians/s)',fontsize=18)
ax.set_ylabel(r"$\phi $ (deg)",fontsize=18)
ax.set_xlim(xmax = pi)
ax.grid()

535
temp/adc.c 100644
Wyświetl plik

@ -0,0 +1,535 @@
/**
* \file
*
* \brief SAM D20/D21/R21 Peripheral Analog-to-Digital Converter Driver
*
* Copyright (C) 2012-2014 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#include "adc.h"
#if SAMD20
/* The Die revision D number */
#define REVISON_D_NUM 3
#endif
/**
* \internal Configure MUX settings for the analog pins
*
* This function will set the given ADC input pins
* to the analog function in the pin mux, giving
* the ADC access to the analog signal
*
* \param [in] pin AINxx pin to configure
*/
static inline void _adc_configure_ain_pin(uint32_t pin)
{
#define PIN_INVALID_ADC_AIN 0xFFFFUL
/* Pinmapping table for AINxx -> GPIO pin number */
const uint32_t pinmapping[] = {
#if (SAMD20E | SAMD21E)
PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1,
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5,
PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7,
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17,
PIN_PA10B_ADC_AIN18, PIN_PA11B_ADC_AIN19,
#elif (SAMD20G | SAMD21G)
PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1,
PIN_PB08B_ADC_AIN2, PIN_PB09B_ADC_AIN3,
PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5,
PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7,
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
PIN_PB02B_ADC_AIN10, PIN_PB03B_ADC_AIN11,
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17,
PIN_PA10B_ADC_AIN18, PIN_PA11B_ADC_AIN19,
#elif (SAMD20J | SAMD21J)
PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1,
PIN_PB08B_ADC_AIN2, PIN_PB09B_ADC_AIN3,
PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5,
PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7,
PIN_PB00B_ADC_AIN8, PIN_PB01B_ADC_AIN9,
PIN_PB02B_ADC_AIN10, PIN_PB03B_ADC_AIN11,
PIN_PB04B_ADC_AIN12, PIN_PB05B_ADC_AIN13,
PIN_PB06B_ADC_AIN14, PIN_PB07B_ADC_AIN15,
PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17,
PIN_PA10B_ADC_AIN18, PIN_PA11B_ADC_AIN19,
#elif SAMR21E
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7,
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17,
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
#elif SAMR21G
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5,
PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7,
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
PIN_PB02B_ADC_AIN10, PIN_PB03B_ADC_AIN11,
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17,
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
#else
# error ADC pin mappings are not defined for this device.
#endif
};
uint32_t pin_map_result = PIN_INVALID_ADC_AIN;
if (pin <= ADC_EXTCHANNEL_MSB) {
pin_map_result = pinmapping[pin >> ADC_INPUTCTRL_MUXPOS_Pos];
Assert(pin_map_result != PIN_INVALID_ADC_AIN);
struct system_pinmux_config config;
system_pinmux_get_config_defaults(&config);
/* Analog functions are all on MUX setting B */
config.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE;
config.mux_position = 1;
system_pinmux_pin_set_config(pin_map_result, &config);
}
}
/**
* \internal Writes an ADC configuration to the hardware module
*
* Writes out a given ADC module configuration to the hardware module.
*
* \param[out] module_inst Pointer to the ADC software instance struct
* \param[in] config Pointer to configuration struct
*
* \return Status of the configuration procedure
* \retval STATUS_OK The configuration was successful
* \retval STATUS_ERR_INVALID_ARG Invalid argument(s) were provided
*/
static enum status_code _adc_set_config(
struct adc_module *const module_inst,
struct adc_config *const config)
{
uint8_t adjres = 0;
uint32_t resolution = ADC_RESOLUTION_16BIT;
enum adc_accumulate_samples accumulate = ADC_ACCUMULATE_DISABLE;
#if SAMD20
uint8_t revision_num = ((REG_DSU_DID & DSU_DID_DIE_Msk) >> DSU_DID_DIE_Pos);
#endif
/* Get the hardware module pointer */
Adc *const adc_module = module_inst->hw;
/* Configure GCLK channel and enable clock */
struct system_gclk_chan_config gclk_chan_conf;
system_gclk_chan_get_config_defaults(&gclk_chan_conf);
gclk_chan_conf.source_generator = config->clock_source;
system_gclk_chan_set_config(ADC_GCLK_ID, &gclk_chan_conf);
system_gclk_chan_enable(ADC_GCLK_ID);
/* Setup pinmuxing for analog inputs */
if (config->pin_scan.inputs_to_scan != 0) {
uint8_t offset = config->pin_scan.offset_start_scan;
uint8_t start_pin =
offset +(uint8_t)config->positive_input;
uint8_t end_pin =
start_pin + config->pin_scan.inputs_to_scan;
while (start_pin < end_pin) {
_adc_configure_ain_pin((offset % 16)+(uint8_t)config->positive_input);
start_pin++;
offset++;
}
_adc_configure_ain_pin(config->negative_input);
} else {
_adc_configure_ain_pin(config->positive_input);
_adc_configure_ain_pin(config->negative_input);
}
/* Configure run in standby */
adc_module->CTRLA.reg = (config->run_in_standby << ADC_CTRLA_RUNSTDBY_Pos);
/* Configure reference */
adc_module->REFCTRL.reg =
(config->reference_compensation_enable << ADC_REFCTRL_REFCOMP_Pos) |
(config->reference);
/* Set adjusting result and number of samples */
switch (config->resolution) {
case ADC_RESOLUTION_CUSTOM:
adjres = config->divide_result;
accumulate = config->accumulate_samples;
/* 16-bit result register */
resolution = ADC_RESOLUTION_16BIT;
break;
case ADC_RESOLUTION_13BIT:
/* Increase resolution by 1 bit */
adjres = ADC_DIVIDE_RESULT_2;
accumulate = ADC_ACCUMULATE_SAMPLES_4;
/* 16-bit result register */
resolution = ADC_RESOLUTION_16BIT;
break;
case ADC_RESOLUTION_14BIT:
/* Increase resolution by 2 bit */
adjres = ADC_DIVIDE_RESULT_4;
accumulate = ADC_ACCUMULATE_SAMPLES_16;
/* 16-bit result register */
resolution = ADC_RESOLUTION_16BIT;
break;
#if SAMD20
/* Please see $35.1.8 for ADC errata of SAM D20.
The revisions before D have this issue.*/
case ADC_RESOLUTION_15BIT:
/* Increase resolution by 3 bit */
if(revision_num < REVISON_D_NUM) {
adjres = ADC_DIVIDE_RESULT_8;
} else {
adjres = ADC_DIVIDE_RESULT_2;
}
accumulate = ADC_ACCUMULATE_SAMPLES_64;
/* 16-bit result register */
resolution = ADC_RESOLUTION_16BIT;
break;
case ADC_RESOLUTION_16BIT:
if(revision_num < REVISON_D_NUM) {
/* Increase resolution by 4 bit */
adjres = ADC_DIVIDE_RESULT_16;
} else {
adjres = ADC_DIVIDE_RESULT_DISABLE;
}
accumulate = ADC_ACCUMULATE_SAMPLES_256;
/* 16-bit result register */
resolution = ADC_RESOLUTION_16BIT;
break;
#else
case ADC_RESOLUTION_15BIT:
/* Increase resolution by 3 bit */
adjres = ADC_DIVIDE_RESULT_2;
accumulate = ADC_ACCUMULATE_SAMPLES_64;
/* 16-bit result register */
resolution = ADC_RESOLUTION_16BIT;
break;
case ADC_RESOLUTION_16BIT:
/* Increase resolution by 4 bit */
adjres = ADC_DIVIDE_RESULT_DISABLE;
accumulate = ADC_ACCUMULATE_SAMPLES_256;
/* 16-bit result register */
resolution = ADC_RESOLUTION_16BIT;
break;
#endif
case ADC_RESOLUTION_8BIT:
/* 8-bit result register */
resolution = ADC_RESOLUTION_8BIT;
break;
case ADC_RESOLUTION_10BIT:
/* 10-bit result register */
resolution = ADC_RESOLUTION_10BIT;
break;
case ADC_RESOLUTION_12BIT:
/* 12-bit result register */
resolution = ADC_RESOLUTION_12BIT;
break;
default:
/* Unknown. Abort. */
return STATUS_ERR_INVALID_ARG;
}
adc_module->AVGCTRL.reg = ADC_AVGCTRL_ADJRES(adjres) | accumulate;
/* Check validity of sample length value */
if (config->sample_length > 63) {
return STATUS_ERR_INVALID_ARG;
} else {
/* Configure sample length */
adc_module->SAMPCTRL.reg =
(config->sample_length << ADC_SAMPCTRL_SAMPLEN_Pos);
}
while (adc_is_syncing(module_inst)) {
/* Wait for synchronization */
}
/* Configure CTRLB */
adc_module->CTRLB.reg =
config->clock_prescaler |
resolution |
(config->correction.correction_enable << ADC_CTRLB_CORREN_Pos) |
(config->freerunning << ADC_CTRLB_FREERUN_Pos) |
(config->left_adjust << ADC_CTRLB_LEFTADJ_Pos) |
(config->differential_mode << ADC_CTRLB_DIFFMODE_Pos);
/* Check validity of window thresholds */
if (config->window.window_mode != ADC_WINDOW_MODE_DISABLE) {
switch (resolution) {
case ADC_RESOLUTION_8BIT:
if (config->differential_mode &&
(config->window.window_lower_value > 127 ||
config->window.window_lower_value < -128 ||
config->window.window_upper_value > 127 ||
config->window.window_upper_value < -128)) {
/* Invalid value */
return STATUS_ERR_INVALID_ARG;
} else if (config->window.window_lower_value > 255 ||
config->window.window_upper_value > 255){
/* Invalid value */
return STATUS_ERR_INVALID_ARG;
}
break;
case ADC_RESOLUTION_10BIT:
if (config->differential_mode &&
(config->window.window_lower_value > 511 ||
config->window.window_lower_value < -512 ||
config->window.window_upper_value > 511 ||
config->window.window_upper_value > -512)) {
/* Invalid value */
return STATUS_ERR_INVALID_ARG;
} else if (config->window.window_lower_value > 1023 ||
config->window.window_upper_value > 1023){
/* Invalid value */
return STATUS_ERR_INVALID_ARG;
}
break;
case ADC_RESOLUTION_12BIT:
if (config->differential_mode &&
(config->window.window_lower_value > 2047 ||
config->window.window_lower_value < -2048 ||
config->window.window_upper_value > 2047 ||
config->window.window_upper_value < -2048)) {
/* Invalid value */
return STATUS_ERR_INVALID_ARG;
} else if (config->window.window_lower_value > 4095 ||
config->window.window_upper_value > 4095){
/* Invalid value */
return STATUS_ERR_INVALID_ARG;
}
break;
case ADC_RESOLUTION_16BIT:
if (config->differential_mode &&
(config->window.window_lower_value > 32767 ||
config->window.window_lower_value < -32768 ||
config->window.window_upper_value > 32767 ||
config->window.window_upper_value < -32768)) {
/* Invalid value */
return STATUS_ERR_INVALID_ARG;
} else if (config->window.window_lower_value > 65535 ||
config->window.window_upper_value > 65535){
/* Invalid value */
return STATUS_ERR_INVALID_ARG;
}
break;
}
}
while (adc_is_syncing(module_inst)) {
/* Wait for synchronization */
}
/* Configure window mode */
adc_module->WINCTRL.reg = config->window.window_mode;
while (adc_is_syncing(module_inst)) {
/* Wait for synchronization */
}
/* Configure lower threshold */
adc_module->WINLT.reg =
config->window.window_lower_value << ADC_WINLT_WINLT_Pos;
while (adc_is_syncing(module_inst)) {
/* Wait for synchronization */
}
/* Configure lower threshold */
adc_module->WINUT.reg = config->window.window_upper_value <<
ADC_WINUT_WINUT_Pos;
uint8_t inputs_to_scan = config->pin_scan.inputs_to_scan;
if (inputs_to_scan > 0) {
/*
* Number of input sources included is the value written to INPUTSCAN
* plus 1.
*/
inputs_to_scan--;
}
if (inputs_to_scan > (ADC_INPUTCTRL_INPUTSCAN_Msk >> ADC_INPUTCTRL_INPUTSCAN_Pos) ||
config->pin_scan.offset_start_scan > (ADC_INPUTCTRL_INPUTOFFSET_Msk >> ADC_INPUTCTRL_INPUTOFFSET_Pos)) {
/* Invalid number of input pins or input offset */
return STATUS_ERR_INVALID_ARG;
}
while (adc_is_syncing(module_inst)) {
/* Wait for synchronization */
}
/* Configure pin scan mode and positive and negative input pins */
adc_module->INPUTCTRL.reg =
config->gain_factor |
(config->pin_scan.offset_start_scan <<
ADC_INPUTCTRL_INPUTOFFSET_Pos) |
(inputs_to_scan << ADC_INPUTCTRL_INPUTSCAN_Pos) |
config->negative_input |
config->positive_input;
/* Configure events */
adc_module->EVCTRL.reg = config->event_action;
/* Disable all interrupts */
adc_module->INTENCLR.reg =
(1 << ADC_INTENCLR_SYNCRDY_Pos) | (1 << ADC_INTENCLR_WINMON_Pos) |
(1 << ADC_INTENCLR_OVERRUN_Pos) | (1 << ADC_INTENCLR_RESRDY_Pos);
if (config->correction.correction_enable){
/* Make sure gain_correction value is valid */
if (config->correction.gain_correction > ADC_GAINCORR_GAINCORR_Msk) {
return STATUS_ERR_INVALID_ARG;
} else {
/* Set gain correction value */
adc_module->GAINCORR.reg = config->correction.gain_correction <<
ADC_GAINCORR_GAINCORR_Pos;
}
/* Make sure offset correction value is valid */
if (config->correction.offset_correction > 2047 ||
config->correction.offset_correction < -2048) {
return STATUS_ERR_INVALID_ARG;
} else {
/* Set offset correction value */
adc_module->OFFSETCORR.reg = config->correction.offset_correction <<
ADC_OFFSETCORR_OFFSETCORR_Pos;
}
}
/* Load in the fixed device ADC calibration constants */
adc_module->CALIB.reg =
ADC_CALIB_BIAS_CAL(
(*(uint32_t *)ADC_FUSES_BIASCAL_ADDR >> ADC_FUSES_BIASCAL_Pos)
) |
ADC_CALIB_LINEARITY_CAL(
(*(uint64_t *)ADC_FUSES_LINEARITY_0_ADDR >> ADC_FUSES_LINEARITY_0_Pos)
);
return STATUS_OK;
}
/**
* \brief Initializes the ADC
*
* Initializes the ADC device struct and the hardware module based on the
* given configuration struct values.
*
* \param[out] module_inst Pointer to the ADC software instance struct
* \param[in] hw Pointer to the ADC module instance
* \param[in] config Pointer to the configuration struct
*
* \return Status of the initialization procedure
* \retval STATUS_OK The initialization was successful
* \retval STATUS_ERR_INVALID_ARG Invalid argument(s) were provided
* \retval STATUS_BUSY The module is busy with a reset operation
* \retval STATUS_ERR_DENIED The module is enabled
*/
enum status_code adc_init(
struct adc_module *const module_inst,
Adc *hw,
struct adc_config *config)
{
/* Sanity check arguments */
Assert(module_inst);
Assert(hw);
Assert(config);
/* Associate the software module instance with the hardware module */
module_inst->hw = hw;
/* Turn on the digital interface clock */
system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, PM_APBCMASK_ADC);
if (hw->CTRLA.reg & ADC_CTRLA_SWRST) {
/* We are in the middle of a reset. Abort. */
return STATUS_BUSY;
}
if (hw->CTRLA.reg & ADC_CTRLA_ENABLE) {
/* Module must be disabled before initialization. Abort. */
return STATUS_ERR_DENIED;
}
/* Store the selected reference for later use */
module_inst->reference = config->reference;
#if ADC_CALLBACK_MODE == true
for (uint8_t i = 0; i < ADC_CALLBACK_N; i++) {
module_inst->callback[i] = NULL;
};
module_inst->registered_callback_mask = 0;
module_inst->enabled_callback_mask = 0;
module_inst->remaining_conversions = 0;
module_inst->job_status = STATUS_OK;
_adc_instances[0] = module_inst;
if (config->event_action == ADC_EVENT_ACTION_DISABLED &&
!config->freerunning) {
module_inst->software_trigger = true;
} else {
module_inst->software_trigger = false;
}
#endif
/* Write configuration to module */
return _adc_set_config(module_inst, config);
}

248
temp/adc_callback.c 100644
Wyświetl plik

@ -0,0 +1,248 @@
/**
* \file
*
* \brief SAM D20/D21/R21 Peripheral Analog-to-Digital Converter Driver
*
* Copyright (C) 2012-2014 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#include "adc_callback.h"
struct adc_module *_adc_instances[ADC_INST_NUM];
static void _adc_interrupt_handler(const uint8_t instance)
{
struct adc_module *module = _adc_instances[instance];
/* get interrupt flags and mask out enabled callbacks */
uint32_t flags = module->hw->INTFLAG.reg;
if (flags & ADC_INTFLAG_RESRDY) {
if ((module->enabled_callback_mask & (1 << ADC_CALLBACK_READ_BUFFER)) &&
(module->registered_callback_mask & (1 << ADC_CALLBACK_READ_BUFFER))) {
/* clear interrupt flag */
module->hw->INTFLAG.reg = ADC_INTFLAG_RESRDY;
/* store ADC result in job buffer */
*(module->job_buffer++) = module->hw->RESULT.reg;
if (--module->remaining_conversions > 0) {
if (module->software_trigger == true) {
adc_start_conversion(module);
}
} else {
if (module->job_status == STATUS_BUSY) {
/* job is complete. update status,disable interrupt
*and call callback */
module->job_status = STATUS_OK;
adc_disable_interrupt(module, ADC_INTERRUPT_RESULT_READY);
(module->callback[ADC_CALLBACK_READ_BUFFER])(module);
}
}
}
}
if (flags & ADC_INTFLAG_WINMON) {
module->hw->INTFLAG.reg = ADC_INTFLAG_WINMON;
if ((module->enabled_callback_mask & (1 << ADC_CALLBACK_WINDOW)) &&
(module->registered_callback_mask & (1 << ADC_CALLBACK_WINDOW))) {
(module->callback[ADC_CALLBACK_WINDOW])(module);
}
}
if (flags & ADC_INTFLAG_OVERRUN) {
module->hw->INTFLAG.reg = ADC_INTFLAG_OVERRUN;
if ((module->enabled_callback_mask & (1 << ADC_CALLBACK_ERROR)) &&
(module->registered_callback_mask & (1 << ADC_CALLBACK_ERROR))) {
(module->callback[ADC_CALLBACK_ERROR])(module);
}
}
}
/** Interrupt handler for the ADC module. */
void ADC_Handler(void)
{
_adc_interrupt_handler(0);
}
/**
* \brief Registers a callback
*
* Registers a callback function which is implemented by the user.
*
* \note The callback must be enabled by for the interrupt handler to call it
* when the condition for the callback is met.
*
* \param[in] module Pointer to ADC software instance struct
* \param[in] callback_func Pointer to callback function
* \param[in] callback_type Callback type given by an enum
*
*/
void adc_register_callback(
struct adc_module *const module,
adc_callback_t callback_func,
enum adc_callback callback_type)
{
/* Sanity check arguments */
Assert(module);
Assert(callback_func);
/* Register callback function */
module->callback[callback_type] = callback_func;
/* Set the bit corresponding to the callback_type */
module->registered_callback_mask |= (1 << callback_type);
}
/**
* \brief Unregisters a callback
*
* Unregisters a callback function which is implemented by the user.
*
* \param[in] module Pointer to ADC software instance struct
* \param[in] callback_type Callback type given by an enum
*
*/
void adc_unregister_callback(
struct adc_module *const module,
enum adc_callback callback_type)
{
/* Sanity check arguments */
Assert(module);
/* Unregister callback function */
module->callback[callback_type] = NULL;
/* Clear the bit corresponding to the callback_type */
module->registered_callback_mask &= ~(1 << callback_type);
}
/**
* \brief Read multiple samples from ADC
*
* Read \c samples samples from the ADC into the buffer \c buffer.
* If there is no hardware trigger defined (event action) the
* driver will retrigger the ADC conversion whenever a conversion
* is complete until \c samples samples has been acquired. To avoid
* jitter in the sampling frequency using an event trigger is advised.
*
* \param[in] module_inst Pointer to the ADC software instance struct
* \param[in] samples Number of samples to acquire
* \param[out] buffer Buffer to store the ADC samples
*
* \return Status of the job start
* \retval STATUS_OK The conversion job was started successfully and is
* in progress
* \retval STATUS_BUSY The ADC is already busy with another job
*/
enum status_code adc_read_buffer_job(
struct adc_module *const module_inst,
uint16_t *buffer,
uint16_t samples)
{
Assert(module_inst);
Assert(samples);
Assert(buffer);
if(module_inst->remaining_conversions != 0 ||
module_inst->job_status == STATUS_BUSY){
return STATUS_BUSY;
}
module_inst->job_status = STATUS_BUSY;
module_inst->remaining_conversions = samples;
module_inst->job_buffer = buffer;
adc_enable_interrupt(module_inst, ADC_INTERRUPT_RESULT_READY);
if(module_inst->software_trigger == true) {
adc_start_conversion(module_inst);
}
return STATUS_OK;
}
/**
* \brief Gets the status of a job
*
* Gets the status of an ongoing or the last job.
*
* \param [in] module_inst Pointer to the ADC software instance struct
* \param [in] type Type of job to abort
*
* \return Status of the job
*/
enum status_code adc_get_job_status(
struct adc_module *module_inst,
enum adc_job_type type)
{
/* Sanity check arguments */
Assert(module_inst);
if (type == ADC_JOB_READ_BUFFER ) {
return module_inst->job_status;
} else {
return STATUS_ERR_INVALID_ARG;
}
}
/**
* \brief Aborts an ongoing job
*
* Aborts an ongoing job.
*
* \param [in] module_inst Pointer to the ADC software instance struct
* \param [in] type Type of job to abort
*/
void adc_abort_job(
struct adc_module *module_inst,
enum adc_job_type type)
{
/* Sanity check arguments */
Assert(module_inst);
if (type == ADC_JOB_READ_BUFFER) {
/* Disable interrupt */
adc_disable_interrupt(module_inst, ADC_INTERRUPT_RESULT_READY);
/* Mark job as aborted */
module_inst->job_status = STATUS_ABORTED;
module_inst->remaining_conversions = 0;
}
}