Add SAMA5D2 Xplained IAR demo.

This commit is contained in:
Richard Barry 2016-04-14 11:14:58 +00:00
parent 5252301cb8
commit f0f2378961
261 changed files with 75876 additions and 0 deletions

View file

@ -0,0 +1,94 @@
# Atmel SAMA5D2x Software Package
## Version 1.2 - 2015-12
### New drivers/examples
- USB Device examples and stack: CDC Serial, HID Keyboard, HID Mouse, Audio,
Mass Storage and some composite examples.
- NAND flash driver and examples: supports MLC/SLC, up to 32-bit ECC.
- SDMMC/eMMC driver and example
- Low Power examples: power_consumption_pll, pmc_clock_switching,
low_power_mode
- New storagemedia library to abstract storage devices (only supports RAM disk
for now, but will support SDMMC/eMMC and NAND flash in later releases)
### Enhancements
- Several new functions in PMC driver, notably 'pmc_set_custom_pck_mck' that
allow changing easily the main clock settings.
- IAR project generator now uses defines and include directories from
CFLAGS_DEFS and CFLAGS_INC mkefile variables. It also generates projects with
CMSIS-DAP debugger selected and proper optimization level.
### Fixes
- Fix CP15 driver to invalidate caches before enable. This fixes some lock-ups
when caches were previously enabled and still contain stale data.
## Version 1.1 - 2015-10
### New drivers
- Class-D audio driver + example
### Enhancements
- Support for ISO7816 and LIN modes to UART driver + example
- Several functions added to PMC driver, mostly UPLL and AudioPLL support
- ISC/sensors: support for new capture modes / resolutions
### Fixes
- Several fixes to ADC driver and example
- Fixed MMU setup (some memory regions where not defined)
## Version 1.0 - 2015-09
### New drivers
- MCAN driver + example
### Changes
- sama5d2-xplained target adapted for final revA board
### Enhancements
- Clock initialization changed to be more reliable
- PMC driver now supports setting generated clocks on sama5d2
- Add support for new memory models to at25 driver (MX25L12835F, MX25L4005,
N25Q032, S25FL127S)
## Version 0.3 -- 2015-08
### New drivers
- ACC driver
- ADC driver + example
- AES / TDES / SHA drivers + examples
- L2CC driver
- GMAC driver + examples (using ad-hoc / LWIP / UIP stacks)
- QT1070 driver
- SHDWC driver
### Enhancements
- FPU is now enabled in GCC startup (was already enabled for IAR)
- ISC example now demonstrates Auto White Balance / Auto Exposure
- SPID/TWID/USARTD drivers now switch the Flexcom mode when appropriate
- MMU is now has a non-cacheable DDR region (used by LCD and GMAC examples)
### Fixes
- RAM timings / configuration adjusted for sama5d2-xplained target
- Component headers in target/sama5d2/components updated to reflect latest
datasheet updates
- PIO and TRNG callbacks now have a configurable user-defined argument

View file

@ -0,0 +1,166 @@
Copyright (c) 2015, Atmel Corporation All rights reserved.
----------------------------------------------------------
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
# Atmel SAMA5D2x Software Package
## Overview
This softpack comes as an early delivery and all presented APIs are subject to change.
Each software module is provided with full source code, example of usage, and ready-to-use projects.
### Supported Platforms
Windows and Linux with the gnu GCC ARM Embedded toolchain. It is downloadable at this address: https://launchpad.net/gcc-arm-embedded (Mac OS X should also work but as not been tested yet).
Dependencies:
- GNU make (from MinGW, Cygwin or GnuWin32 for Windows architectures)
- bash (from MinGW, Cygwin for Windows architectures)
Windows with IAR Embedded Workbench.
Dependencies:
- IAR Embedded Workbench (Tested on version 7.40)
- bash (from MinGW, Cygwin or GnuWin32) for IAR project generation
- GNU make (from MinGW, Cygwin or GnuWin32) for IAR project generation
- mktemp (from MinGW, Cygwin or GnuWin32) for IAR project generation
Notice: This softpack comes as an early delivery and all presented APIs are subject to change.
## Contents
### Directory Architecture
- target/sama5d2
All chip and board specific source files
- target/sama5d2/toolchain/
Linker and debugger scripts
- scripts/
generators and build script templates (Makefiles)
- drivers/
Driver source files
- examples/
All examples
### Examples
This release contains the following examples:
adc: Example using ADC
can: Example using CAN
crypto_aes: AES hardware computation (with and without DMA)
crypto_sha: SHA hardware computation (with and without DMA)
crypto_tdes: Triple-DES hardware computation (with and without DMA)
fifo: Test Flexcom USART FIFO
gettting-started: LED blink (uses PIT and PIO)
gmac: GMAC example using a simple IP stack
gmac_lwip: GMAC example using LWIP stack
gmac_uip_helloworld: GMAC example using UIP stack (UIP helloworld example)
gmac_uip_telnetd: GMAC example using UIP stack (UIP telnetd example)
gmac_uip_webserver: GMAC example using UIP stack (UIP webserver example)
isc: Example using ISC controller (OV7740 sensor)
lcd: Example using LCD controller
qspi_flash: Read/Write/Delete commands to a QSPI serial flash
rtc: RTC Example
spi_serialflash: Read/Write/Delete commands to an SPI serial flash
trng: Example using hardware RNG (interrupt mode)
twi_eeprom: Read/Write/Delete commands to an Two-Wire EEPROM
wdt: Example using watchdog timer
xdma: Memory-to-memory DMA transfert example
xdma_usart: Bidirectionnal Usart-memory DMA transfert example
## Usage (GCC ARM Embedded)
### Environment Variable
TARGET: Name of the wanted target (sama5d2-xplained for samad52 XPLAINED ULTRA boards). This variable is mandatory to launch any build.
DEBUG: Build with debug flags (default).
TRACE_LEVEL: The wanted log level, 5 correspond to full, 0 to none (default to 5)
RELEASE: Build with the release flags
only TARGET must be provided or set at each make invocation.
### Build
Run:
make
#or
make TARGET=wanted_target # if TARGET is not set
### Run and Debug (with GDB)
To run examples with gdb, first, JLinkGDBServer must be started. It can be downloaded for each platform at http://www.segger.com
A make target is provided to launch the test with the correct gdb command arguments, run:
make debug
#or
make TARGET=wanted_target debug # if TARGET is not set
## Usage (IAR)
The Win version of this softpack release comes with pregenerated IAR projects compatible with IAR Systems Embedded Workbench for ARM version 7.40.
The C-SPY device description files and device selections files are not included and must be installed manually.
### IAR Project generation
An IAR project can be generated with GNU make, run in the example directory:
make iar
#or
make TARGET=wanted_target iar # if TARGET is not set
All needed IAR project files will be put in the example directory, including a default workspace one.
Notice:
GNU make may fail on Windows platforms if the Makefile contains UNIX line endings.
You can use unix2dos on all Makefile files in scripts/ directory to fix this issue.

View file

@ -0,0 +1,803 @@
-- *****************************************************************************
-- BSDL file for design top
-- Created by Synopsys Version I-2013.12-SP3 (Apr 18, 2014)
-- Designer:
-- Company:
-- Date: Thu Feb 5 22:28:17 2015
-- *****************************************************************************
entity top is
-- This section identifies the default device package selected.
generic (PHYSICAL_PIN_MAP: string:= "BGA196");
-- This section declares all the ports in the design.
port (
PD14 : in bit;
PD15 : in bit;
PD17 : in bit;
PD18 : in bit;
-- PA0 : linkage bit; -- NC Port
-- PA1 : linkage bit; -- NC Port
-- PA10 : linkage bit; -- NC Port
-- PA11 : linkage bit; -- NC Port
-- PA12 : linkage bit; -- NC Port
-- PA13 : linkage bit; -- NC Port
-- PA14 : linkage bit; -- NC Port
-- PA15 : linkage bit; -- NC Port
-- PA16 : linkage bit; -- NC Port
-- PA17 : linkage bit; -- NC Port
PA18 : inout bit;
PA19 : inout bit;
-- PA2 : linkage bit; -- NC Port
PA20 : inout bit;
PA21 : inout bit;
PA22 : inout bit;
PA23 : inout bit;
PA24 : inout bit;
PA25 : inout bit;
PA26 : inout bit;
PA27 : inout bit;
PA28 : inout bit;
PA29 : inout bit;
-- PA3 : linkage bit; -- NC Port
PA30 : inout bit;
PA31 : inout bit;
-- PA4 : linkage bit; -- NC Port
-- PA5 : linkage bit; -- NC Port
-- PA6 : linkage bit; -- NC Port
-- PA7 : linkage bit; -- NC Port
-- PA8 : linkage bit; -- NC Port
-- PA9 : linkage bit; -- NC Port
PB0 : inout bit;
PB1 : inout bit;
PB10 : inout bit;
PB11 : inout bit;
PB12 : inout bit;
PB13 : inout bit;
PB14 : inout bit;
PB15 : inout bit;
PB16 : inout bit;
PB17 : inout bit;
PB18 : inout bit;
PB19 : inout bit;
PB2 : inout bit;
PB20 : inout bit;
PB21 : inout bit;
PB22 : inout bit;
PB23 : inout bit;
PB24 : inout bit;
PB25 : inout bit;
PB26 : inout bit;
PB27 : inout bit;
PB28 : inout bit;
PB29 : inout bit;
PB3 : inout bit;
PB30 : inout bit;
PB31 : inout bit;
PB4 : inout bit;
PB5 : inout bit;
PB6 : inout bit;
PB7 : inout bit;
PB8 : inout bit;
PB9 : inout bit;
PC0 : inout bit;
PC1 : inout bit;
-- PC10 : linkage bit; -- NC Port
-- PC11 : linkage bit; -- NC Port
-- PC12 : linkage bit; -- NC Port
-- PC13 : linkage bit; -- NC Port
-- PC14 : linkage bit; -- NC Port
-- PC15 : linkage bit; -- NC Port
-- PC16 : linkage bit; -- NC Port
-- PC17 : linkage bit; -- NC Port
-- PC18 : linkage bit; -- NC Port
-- PC19 : linkage bit; -- NC Port
PC2 : inout bit;
-- PC20 : linkage bit; -- NC Port
-- PC21 : linkage bit; -- NC Port
-- PC22 : linkage bit; -- NC Port
-- PC23 : linkage bit; -- NC Port
-- PC24 : linkage bit; -- NC Port
-- PC25 : linkage bit; -- NC Port
-- PC26 : linkage bit; -- NC Port
-- PC27 : linkage bit; -- NC Port
-- PC28 : linkage bit; -- NC Port
-- PC29 : linkage bit; -- NC Port
PC3 : inout bit;
-- PC30 : linkage bit; -- NC Port
-- PC31 : linkage bit; -- NC Port
PC4 : inout bit;
PC5 : inout bit;
PC6 : inout bit;
PC7 : inout bit;
PC8 : inout bit;
-- PC9 : linkage bit; -- NC Port
-- PD0 : linkage bit; -- NC Port
-- PD1 : linkage bit; -- NC Port
PD10 : inout bit;
PD11 : inout bit;
PD12 : inout bit;
PD13 : inout bit;
PD19 : inout bit;
-- PD2 : linkage bit; -- NC Port
PD20 : inout bit;
PD21 : inout bit;
PD22 : inout bit;
PD23 : inout bit;
-- PD24 : linkage bit; -- NC Port
-- PD25 : linkage bit; -- NC Port
-- PD26 : linkage bit; -- NC Port
-- PD27 : linkage bit; -- NC Port
-- PD28 : linkage bit; -- NC Port
-- PD29 : linkage bit; -- NC Port
-- PD3 : linkage bit; -- NC Port
-- PD30 : linkage bit; -- NC Port
-- PD31 : linkage bit; -- NC Port
-- PD4 : linkage bit; -- NC Port
-- PD5 : linkage bit; -- NC Port
-- PD6 : linkage bit; -- NC Port
PD7 : inout bit;
PD8 : inout bit;
PD9 : inout bit;
DDR_D : inout bit_vector (0 to 15);
DDR_DQS : inout bit_vector (0 to 1);
DDR_DQSN : inout bit_vector (0 to 1);
DDR_CAS : out bit;
DDR_CKE : out bit;
DDR_CLK : out bit;
DDR_CLKN : out bit;
DDR_CS : out bit;
DDR_RAS : out bit;
DDR_RESETN : out bit;
DDR_WE : out bit;
PD16 : out bit;
DDR_A : out bit_vector (0 to 13);
DDR_BA : out bit_vector (0 to 2);
DDR_DQM : out bit_vector (0 to 1);
-- ADVREFN : linkage bit;
ADVREFP : linkage bit;
CLK_AUDIO : linkage bit;
COMPN : linkage bit;
COMPP : linkage bit;
DDR_CAL : linkage bit;
DDR_VREF : linkage bit; -- DDR_VREFB0 : linkage bit;
-- DDR_VREFB1 : linkage bit;
-- DDR_VREFB2 : linkage bit;
-- DDR_VREFB3 : linkage bit;
-- DDR_VREFCM : linkage bit;
HHSDMA : linkage bit;
HHSDMB : linkage bit;
-- HHSDMSTRC : linkage bit; -- NC Port
HHSDPA : linkage bit;
HHSDPB : linkage bit;
-- HHSDPDATC : linkage bit; -- NC Port
JTAGSEL : in bit;
NRST : linkage bit;
-- RXD : linkage bit; -- NC Port
-- SDCAL : linkage bit; -- NC Port
SHDN : linkage bit;
TST : in bit;
VBG : linkage bit;
WKUP : linkage bit;
XIN : linkage bit;
XIN32 : linkage bit;
XOUT : linkage bit;
XOUT32 : linkage bit;
-- tst_drst_ana : linkage bit; -- NC Port
-- tst_drst_ddr : linkage bit; -- NC Port
-- tst_drst_iop0 : linkage bit; -- NC Port
-- tst_drst_iop1 : linkage bit; -- NC Port
-- tst_drst_iop2 : linkage bit; -- NC Port
-- tst_drst_isi : linkage bit; -- NC Port
-- tst_drst_osc : linkage bit; -- NC Port
-- tst_drst_sdhc : linkage bit; -- NC Port
-- tst_lft_plla : linkage bit; -- NC Port
-- tst_lft_utmi : linkage bit; -- NC Port
-- tst_por_1v2 : linkage bit; -- NC Port
-- tst_por_1v8 : linkage bit; -- NC Port
-- tst_por_bu : linkage bit; -- NC Port
-- tst_psw_bu : linkage bit; -- NC Port
-- tst_psw_fuse : linkage bit; -- NC Port
PIOBU : linkage bit_vector (0 to 5)
);
use STD_1149_1_1994.all;
attribute COMPONENT_CONFORMANCE of top: entity is "STD_1149_1_1993";
attribute PIN_MAP of top: entity is PHYSICAL_PIN_MAP;
-- This section specifies the pin map for each port. This information is
-- extracted from the port-to-pin map file that was read in using the
-- "read_pin_map" command.
constant BGA196: PIN_MAP_STRING :=
"PD14 : G6," &
"PD15 : H5," &
"PD17 : G2," &
"PD18 : G3," &
"PA18 : L9," &
"PA19 : N9," &
"PA20 : M9," &
"PA21 : M10," &
"PA22 : P9," &
"PA23 : P10," &
"PA24 : N10," &
"PA25 : L10," &
"PA26 : P11," &
"PA27 : P12," &
"PA28 : M11," &
"PA29 : N11," &
"PA30 : N12," &
"PA31 : M12," &
"PB0 : A6," &
"PB1 : A5," &
"PB10 : A1," &
"PB11 : B1," &
"PB12 : B2," &
"PB13 : C1," &
"PB14 : D5," &
"PB15 : E5," &
"PB16 : C5," &
"PB17 : C2," &
"PB18 : D4," &
"PB19 : C4," &
"PB2 : B6," &
"PB20 : C3," &
"PB21 : D1," &
"PB22 : D2," &
"PB23 : E1," &
"PB24 : D3," &
"PB25 : E3," &
"PB26 : E2," &
"PB27 : E6," &
"PB28 : F1," &
"PB29 : F6," &
"PB3 : B5," &
"PB30 : F2," &
"PB31 : F7," &
"PB4 : A4," &
"PB5 : D6," &
"PB6 : A3," &
"PB7 : B4," &
"PB8 : A2," &
"PB9 : B3," &
"PC0 : M13," &
"PC1 : P13," &
"PC2 : N13," &
"PC3 : K10," &
"PC4 : P14," &
"PC5 : J8," &
"PC6 : N14," &
"PC7 : M14," &
"PC8 : J9," &
"PD10 : G4," &
"PD11 : H1," &
"PD12 : H6," &
"PD13 : H3," &
"PD19 : H4," &
"PD20 : J1," &
"PD21 : K1," &
"PD22 : J3," &
"PD23 : K2," &
"PD7 : F5," &
"PD8 : F3," &
"PD9 : G5," &
"DDR_D : (B7, A7, C8, B9, A9, C9, A10, B10, H13, H14, J13, J14, L13, L14, J12, K12)," &
"DDR_DQS : (B8, K14)," &
"DDR_DQSN : (A8, K13)," &
"DDR_CAS : C13," &
"DDR_CKE : E14," &
"DDR_CLK : A13," &
"DDR_CLKN : B13," &
"DDR_CS : F11," &
"DDR_DQM : (D8, G14)," &
"DDR_RAS : C14," &
"DDR_RESETN : D13," &
"DDR_WE : A14," &
"PD16 : G1," &
"DDR_A : (E11, C11, B12, A12, D11, D14, B14, D9, C10, D10, " &
"F9, A11, B11, E13)," &
"DDR_BA : (F13, G13, F14)," &
"ADVREFP : L2," &
"CLK_AUDIO : J7," &
"COMPN : P2," &
"COMPP : N2," &
"DDR_CAL : F10," &
"HHSDMA : P7," &
"HHSDMB : P8," &
"HHSDPA : N7," &
"HHSDPB : N8," &
"JTAGSEL : L4," &
"NRST : N3," &
"SHDN : N1," &
"TST : M2," &
"VBG : L7," &
"WKUP : P1," &
"XIN : P5," &
"XIN32 : M1," &
"XOUT : P6," &
"XOUT32 : L1," &
"PIOBU : (K5, L3, M3, N4, L5, M6)";
-- This section specifies the differential IO port groupings.
attribute PORT_GROUPING of top: entity is
"Differential_Voltage ( " &
"(DDR_CLK,DDR_CLKN))";
-- This section specifies the TAP ports. For the TAP TCK port, the parameters in
-- the brackets are:
-- First Field : Maximum TCK frequency.
-- Second Field: Allowable states TCK may be stopped in.
attribute TAP_SCAN_CLOCK of PD14: signal is (10.0e6, BOTH);
attribute TAP_SCAN_IN of PD15: signal is true;
attribute TAP_SCAN_MODE of PD17: signal is true;
attribute TAP_SCAN_OUT of PD16: signal is true;
attribute TAP_SCAN_RESET of PD18: signal is true;
-- Specifies the compliance enable patterns for the design. It lists a set of
-- design ports and the values that they should be set to, in order to enable
-- compliance to IEEE Std 1149.1
attribute COMPLIANCE_PATTERNS of top: entity is
"(JTAGSEL, TST) (10)";
-- Specifies the number of bits in the instruction register.
attribute INSTRUCTION_LENGTH of top: entity is 4;
-- Specifies the boundary-scan instructions implemented in the design and their
-- opcodes.
attribute INSTRUCTION_OPCODE of top: entity is
"BYPASS (1111, 0001, 0101, 0110, 1100, 0111, 1101, 1000, 1001, 1011, " &
"1110)," &
"EXTEST (0000)," &
"SAMPLE (0100)," &
"INTEST (0010)," &
"IDCODE (0011)," &
"RUNBIST (1010)";
-- Specifies the bit pattern that is loaded into the instruction register when
-- the TAP controller passes through the Capture-IR state. The standard mandates
-- that the two LSBs must be "01". The remaining bits are design specific.
attribute INSTRUCTION_CAPTURE of top: entity is "0001";
-- Specifies the bit pattern that is loaded into the DEVICE_ID register during
-- the IDCODE instruction when the TAP controller passes through the Capture-DR
-- state.
attribute IDCODE_REGISTER of top: entity is
"0000" &
-- 4-bit version number
"0101101100111111" &
-- 16-bit part number
"00000011111" &
-- 11-bit identity of the manufacturer
"1";
-- Required by IEEE Std 1149.1
-- This section specifies the test data register placed between TDI and TDO for
-- each implemented instruction.
attribute REGISTER_ACCESS of top: entity is
"BYPASS (BYPASS)," &
"BOUNDARY (EXTEST, SAMPLE, INTEST)," &
"DEVICE_ID (IDCODE)," &
"UTDR1[41] (RUNBIST)";
-- Specifies the length of the boundary scan register.
attribute BOUNDARY_LENGTH of top: entity is 374;
-- The following list specifies the characteristics of each cell in the boundary
-- scan register from TDI to TDO. The following is a description of the label
-- fields:
-- num : Is the cell number.
-- cell : Is the cell type as defined by the standard.
-- port : Is the design port name. Control cells do not have a port
-- name.
-- function: Is the function of the cell as defined by the standard. Is one
-- of input, output2, output3, bidir, control or controlr.
-- safe : Specifies the value that the BSR cell should be loaded with
-- for safe operation when the software might otherwise choose a
-- random value.
-- ccell : The control cell number. Specifies the control cell that
-- drives the output enable for this port.
-- disval : Specifies the value that is loaded into the control cell to
-- disable the output enable for the corresponding port.
-- rslt : Resulting state. Shows the state of the driver when it is
-- disabled.
attribute BOUNDARY_REGISTER of top: entity is
--
-- num cell port function safe [ccell disval rslt]
--
"373 (BC_1, *, control, 1), " &
"372 (BC_7, PD13, bidir, X, 373, 1, Z), " &
"371 (BC_1, *, control, 1), " &
"370 (BC_7, PD12, bidir, X, 371, 1, Z), " &
"369 (BC_1, *, control, 1), " &
"368 (BC_7, PD11, bidir, X, 369, 1, Z), " &
"367 (BC_1, *, control, 1), " &
"366 (BC_7, PD19, bidir, X, 367, 1, Z), " &
"365 (BC_1, *, control, 1), " &
"364 (BC_7, PD20, bidir, X, 365, 1, Z), " &
"363 (BC_0, *, internal, X), " &
"362 (BC_0, *, internal, X), " &
"361 (BC_1, *, control, 1), " &
"360 (BC_7, PD21, bidir, X, 361, 1, Z), " &
"359 (BC_0, *, internal, X), " &
"358 (BC_0, *, internal, X), " &
"357 (BC_0, *, internal, X), " &
"356 (BC_0, *, internal, X), " &
"355 (BC_1, *, control, 1), " &
"354 (BC_7, PD22, bidir, X, 355, 1, Z), " &
"353 (BC_0, *, internal, X), " &
"352 (BC_0, *, internal, X), " &
"351 (BC_1, *, control, 1), " &
"350 (BC_7, PD23, bidir, X, 351, 1, Z), " &
"349 (BC_0, *, internal, X), " &
"348 (BC_0, *, internal, X), " &
"347 (BC_0, *, internal, X), " &
"346 (BC_0, *, internal, X), " &
"345 (BC_0, *, internal, X), " &
"344 (BC_0, *, internal, X), " &
"343 (BC_0, *, internal, X), " &
"342 (BC_0, *, internal, X), " &
"341 (BC_0, *, internal, X), " &
"340 (BC_0, *, internal, X), " &
"339 (BC_0, *, internal, X), " &
"338 (BC_0, *, internal, X), " &
"337 (BC_0, *, internal, X), " &
"336 (BC_0, *, internal, X), " &
"335 (BC_0, *, internal, X), " &
"334 (BC_0, *, internal, X), " &
"333 (BC_0, *, internal, X), " &
"332 (BC_0, *, internal, X), " &
"331 (BC_0, *, internal, X), " &
"330 (BC_0, *, internal, X), " &
"329 (BC_0, *, internal, X), " &
"328 (BC_0, *, internal, X), " &
"327 (BC_0, *, internal, X), " &
"326 (BC_0, *, internal, X), " &
"325 (BC_0, *, internal, X), " &
"324 (BC_0, *, internal, X), " &
"323 (BC_0, *, internal, X), " &
"322 (BC_0, *, internal, X), " &
"321 (BC_0, *, internal, X), " &
"320 (BC_0, *, internal, X), " &
"319 (BC_1, *, control, 1), " &
"318 (BC_7, PA18, bidir, X, 319, 1, Z), " &
"317 (BC_1, *, control, 1), " &
"316 (BC_7, PA20, bidir, X, 317, 1, Z), " &
"315 (BC_1, *, control, 1), " &
"314 (BC_7, PA19, bidir, X, 315, 1, Z), " &
"313 (BC_1, *, control, 1), " &
"312 (BC_7, PA21, bidir, X, 313, 1, Z), " &
"311 (BC_1, *, control, 1), " &
"310 (BC_7, PA22, bidir, X, 311, 1, Z), " &
"309 (BC_1, *, control, 1), " &
"308 (BC_7, PA23, bidir, X, 309, 1, Z), " &
"307 (BC_1, *, control, 1), " &
"306 (BC_7, PA24, bidir, X, 307, 1, Z), " &
"305 (BC_1, *, control, 1), " &
"304 (BC_7, PA25, bidir, X, 305, 1, Z), " &
"303 (BC_1, *, control, 1), " &
"302 (BC_7, PA26, bidir, X, 303, 1, Z), " &
"301 (BC_1, *, control, 1), " &
"300 (BC_7, PA27, bidir, X, 301, 1, Z), " &
"299 (BC_1, *, control, 1), " &
"298 (BC_7, PA28, bidir, X, 299, 1, Z), " &
"297 (BC_1, *, control, 1), " &
"296 (BC_7, PA30, bidir, X, 297, 1, Z), " &
"295 (BC_1, *, control, 1), " &
"294 (BC_7, PA29, bidir, X, 295, 1, Z), " &
"293 (BC_1, *, control, 1), " &
"292 (BC_7, PA31, bidir, X, 293, 1, Z), " &
"291 (BC_1, *, control, 1), " &
"290 (BC_7, PC0, bidir, X, 291, 1, Z), " &
"289 (BC_0, *, internal, X), " &
"288 (BC_0, *, internal, X), " &
"287 (BC_1, *, control, 1), " &
"286 (BC_7, PC1, bidir, X, 287, 1, Z), " &
"285 (BC_0, *, internal, X), " &
"284 (BC_0, *, internal, X), " &
"283 (BC_0, *, internal, X), " &
"282 (BC_0, *, internal, X), " &
"281 (BC_1, *, control, 1), " &
"280 (BC_7, PC2, bidir, X, 281, 1, Z), " &
"279 (BC_0, *, internal, X), " &
"278 (BC_0, *, internal, X), " &
"277 (BC_0, *, internal, X), " &
"276 (BC_0, *, internal, X), " &
"275 (BC_1, *, control, 1), " &
"274 (BC_7, PC3, bidir, X, 275, 1, Z), " &
"273 (BC_1, *, control, 1), " &
"272 (BC_7, PC4, bidir, X, 273, 1, Z), " &
"271 (BC_0, *, internal, X), " &
"270 (BC_0, *, internal, X), " &
"269 (BC_0, *, internal, X), " &
"268 (BC_0, *, internal, X), " &
"267 (BC_1, *, control, 1), " &
"266 (BC_7, PC5, bidir, X, 267, 1, Z), " &
"265 (BC_1, *, control, 1), " &
"264 (BC_7, PC7, bidir, X, 265, 1, Z), " &
"263 (BC_1, *, control, 1), " &
"262 (BC_7, PC6, bidir, X, 263, 1, Z), " &
"261 (BC_1, *, control, 1), " &
"260 (BC_7, PC8, bidir, X, 261, 1, Z), " &
"259 (BC_0, *, internal, X), " &
"258 (BC_0, *, internal, X), " &
"257 (BC_0, *, internal, X), " &
"256 (BC_0, *, internal, X), " &
"255 (BC_0, *, internal, X), " &
"254 (BC_0, *, internal, X), " &
"253 (BC_0, *, internal, X), " &
"252 (BC_0, *, internal, X), " &
"251 (BC_0, *, internal, X), " &
"250 (BC_0, *, internal, X), " &
"249 (BC_0, *, internal, X), " &
"248 (BC_0, *, internal, X), " &
"247 (BC_0, *, internal, X), " &
"246 (BC_0, *, internal, X), " &
"245 (BC_0, *, internal, X), " &
"244 (BC_0, *, internal, X), " &
"243 (BC_0, *, internal, X), " &
"242 (BC_0, *, internal, X), " &
"241 (BC_0, *, internal, X), " &
"240 (BC_0, *, internal, X), " &
"239 (BC_1, *, control, 1), " &
"238 (BC_7, DDR_D(15), bidir, X, 239, 1, Z), " &
"237 (BC_1, *, control, 1), " &
"236 (BC_7, DDR_D(14), bidir, X, 237, 1, Z), " &
"235 (BC_1, *, control, 1), " &
"234 (BC_7, DDR_D(13), bidir, X, 235, 1, Z), " &
"233 (BC_1, *, control, 1), " &
"232 (BC_7, DDR_D(12), bidir, X, 233, 1, Z), " &
"231 (BC_1, *, control, 1), " &
"230 (BC_7, DDR_DQS(1), bidir, X, 231, 1, Z), " &
"229 (BC_1, *, control, 1), " &
"228 (BC_7, DDR_D(11), bidir, X, 229, 1, Z), " &
"227 (BC_1, *, control, 1), " &
"226 (BC_7, DDR_D(10), bidir, X, 227, 1, Z), " &
"225 (BC_1, *, control, 1), " &
"224 (BC_7, DDR_D(9), bidir, X, 225, 1, Z), " &
"223 (BC_1, *, control, 1), " &
"222 (BC_7, DDR_D(8), bidir, X, 223, 1, Z), " &
"221 (BC_0, *, control, 1), " &
"220 (BC_0, DDR_DQM(1), output3, X, 221, 1, Z), " &
"219 (BC_0, *, control, 1), " &
"218 (BC_0, DDR_BA(2), output3, X, 219, 1, Z), " &
"217 (BC_0, *, control, 1), " &
"216 (BC_0, DDR_BA(1), output3, X, 217, 1, Z), " &
"215 (BC_0, *, control, 1), " &
"214 (BC_0, DDR_BA(0), output3, X, 215, 1, Z), " &
"213 (BC_0, *, control, 1), " &
"212 (BC_0, DDR_CKE, output3, X, 213, 1, Z), " &
"211 (BC_0, *, control, 1), " &
"210 (BC_0, DDR_CS, output3, X, 211, 1, Z), " &
"209 (BC_0, *, control, 1), " &
"208 (BC_0, DDR_A(13), output3, X, 209, 1, Z), " &
"207 (BC_0, *, control, 1), " &
"206 (BC_0, DDR_RESETN, output3, X, 207, 1, Z), " &
"205 (BC_0, *, control, 1), " &
"204 (BC_0, DDR_A(5), output3, X, 205, 1, Z), " &
"203 (BC_0, *, control, 1), " &
"202 (BC_0, DDR_A(6), output3, X, 203, 1, Z), " &
"201 (BC_0, *, control, 1), " &
"200 (BC_0, DDR_RAS, output3, X, 201, 1, Z), " &
"199 (BC_0, *, control, 1), " &
"198 (BC_0, DDR_CAS, output3, X, 199, 1, Z), " &
"197 (BC_0, *, control, 1), " &
"196 (BC_0, DDR_WE, output3, X, 197, 1, Z), " &
"195 (BC_0, *, control, 1), " &
"194 (BC_0, DDR_CLK, output3, X, 195, 1, Z), " &
"193 (BC_0, *, control, 1), " &
"192 (BC_0, DDR_A(0), output3, X, 193, 1, Z), " &
"191 (BC_0, *, control, 1), " &
"190 (BC_0, DDR_A(1), output3, X, 191, 1, Z), " &
"189 (BC_0, *, control, 1), " &
"188 (BC_0, DDR_A(2), output3, X, 189, 1, Z), " &
"187 (BC_0, *, control, 1), " &
"186 (BC_0, DDR_A(3), output3, X, 187, 1, Z), " &
"185 (BC_0, *, control, 1), " &
"184 (BC_0, DDR_A(4), output3, X, 185, 1, Z), " &
"183 (BC_0, *, control, 1), " &
"182 (BC_0, DDR_A(12), output3, X, 183, 1, Z), " &
"181 (BC_0, *, control, 1), " &
"180 (BC_0, DDR_A(11), output3, X, 181, 1, Z), " &
"179 (BC_0, *, control, 1), " &
"178 (BC_0, DDR_A(10), output3, X, 179, 1, Z), " &
"177 (BC_0, *, control, 1), " &
"176 (BC_0, DDR_A(9), output3, X, 177, 1, Z), " &
"175 (BC_0, *, control, 1), " &
"174 (BC_0, DDR_A(8), output3, X, 175, 1, Z), " &
"173 (BC_0, *, control, 1), " &
"172 (BC_0, DDR_A(7), output3, X, 173, 1, Z), " &
"171 (BC_1, *, control, 1), " &
"170 (BC_7, DDR_D(7), bidir, X, 171, 1, Z), " &
"169 (BC_1, *, control, 1), " &
"168 (BC_7, DDR_D(6), bidir, X, 169, 1, Z), " &
"167 (BC_1, *, control, 1), " &
"166 (BC_7, DDR_D(5), bidir, X, 167, 1, Z), " &
"165 (BC_1, *, control, 1), " &
"164 (BC_7, DDR_D(4), bidir, X, 165, 1, Z), " &
"163 (BC_1, *, control, 1), " &
"162 (BC_7, DDR_DQS(0), bidir, X, 163, 1, Z), " &
"161 (BC_1, *, control, 1), " &
"160 (BC_7, DDR_D(3), bidir, X, 161, 1, Z), " &
"159 (BC_1, *, control, 1), " &
"158 (BC_7, DDR_D(2), bidir, X, 159, 1, Z), " &
"157 (BC_1, *, control, 1), " &
"156 (BC_7, DDR_D(1), bidir, X, 157, 1, Z), " &
"155 (BC_1, *, control, 1), " &
"154 (BC_7, DDR_D(0), bidir, X, 155, 1, Z), " &
"153 (BC_0, *, control, 1), " &
"152 (BC_0, DDR_DQM(0), output3, X, 153, 1, Z), " &
"151 (BC_0, *, internal, X), " &
"150 (BC_0, *, internal, X), " &
"149 (BC_0, *, internal, X), " &
"148 (BC_0, *, internal, X), " &
"147 (BC_0, *, internal, X), " &
"146 (BC_0, *, internal, X), " &
"145 (BC_0, *, internal, X), " &
"144 (BC_0, *, internal, X), " &
"143 (BC_0, *, internal, X), " &
"142 (BC_0, *, internal, X), " &
"141 (BC_0, *, internal, X), " &
"140 (BC_0, *, internal, X), " &
"139 (BC_0, *, internal, X), " &
"138 (BC_0, *, internal, X), " &
"137 (BC_0, *, internal, X), " &
"136 (BC_0, *, internal, X), " &
"135 (BC_0, *, internal, X), " &
"134 (BC_0, *, internal, X), " &
"133 (BC_0, *, internal, X), " &
"132 (BC_0, *, internal, X), " &
"131 (BC_0, *, internal, X), " &
"130 (BC_0, *, internal, X), " &
"129 (BC_0, *, internal, X), " &
"128 (BC_0, *, internal, X), " &
"127 (BC_0, *, internal, X), " &
"126 (BC_0, *, internal, X), " &
"125 (BC_0, *, internal, X), " &
"124 (BC_0, *, internal, X), " &
"123 (BC_0, *, internal, X), " &
"122 (BC_0, *, internal, X), " &
"121 (BC_0, *, internal, X), " &
"120 (BC_0, *, internal, X), " &
"119 (BC_0, *, internal, X), " &
"118 (BC_0, *, internal, X), " &
"117 (BC_0, *, internal, X), " &
"116 (BC_0, *, internal, X), " &
"115 (BC_0, *, internal, X), " &
"114 (BC_0, *, internal, X), " &
"113 (BC_1, *, control, 1), " &
"112 (BC_7, PB0, bidir, X, 113, 1, Z), " &
"111 (BC_1, *, control, 1), " &
"110 (BC_7, PB2, bidir, X, 111, 1, Z), " &
"109 (BC_1, *, control, 1), " &
"108 (BC_7, PB1, bidir, X, 109, 1, Z), " &
"107 (BC_1, *, control, 1), " &
"106 (BC_7, PB3, bidir, X, 107, 1, Z), " &
"105 (BC_1, *, control, 1), " &
"104 (BC_7, PB4, bidir, X, 105, 1, Z), " &
"103 (BC_1, *, control, 1), " &
"102 (BC_7, PB5, bidir, X, 103, 1, Z), " &
"101 (BC_1, *, control, 1), " &
"100 (BC_7, PB6, bidir, X, 101, 1, Z), " &
"99 (BC_1, *, control, 1), " &
"98 (BC_7, PB8, bidir, X, 99, 1, Z), " &
"97 (BC_1, *, control, 1), " &
"96 (BC_7, PB7, bidir, X, 97, 1, Z), " &
"95 (BC_1, *, control, 1), " &
"94 (BC_7, PB10, bidir, X, 95, 1, Z), " &
"93 (BC_1, *, control, 1), " &
"92 (BC_7, PB9, bidir, X, 93, 1, Z), " &
"91 (BC_1, *, control, 1), " &
"90 (BC_7, PB11, bidir, X, 91, 1, Z), " &
"89 (BC_1, *, control, 1), " &
"88 (BC_7, PB12, bidir, X, 89, 1, Z), " &
"87 (BC_1, *, control, 1), " &
"86 (BC_7, PB14, bidir, X, 87, 1, Z), " &
"85 (BC_1, *, control, 1), " &
"84 (BC_7, PB13, bidir, X, 85, 1, Z), " &
"83 (BC_1, *, control, 1), " &
"82 (BC_7, PB15, bidir, X, 83, 1, Z), " &
"81 (BC_1, *, control, 1), " &
"80 (BC_7, PB16, bidir, X, 81, 1, Z), " &
"79 (BC_1, *, control, 1), " &
"78 (BC_7, PB17, bidir, X, 79, 1, Z), " &
"77 (BC_1, *, control, 1), " &
"76 (BC_7, PB19, bidir, X, 77, 1, Z), " &
"75 (BC_1, *, control, 1), " &
"74 (BC_7, PB18, bidir, X, 75, 1, Z), " &
"73 (BC_1, *, control, 1), " &
"72 (BC_7, PB20, bidir, X, 73, 1, Z), " &
"71 (BC_1, *, control, 1), " &
"70 (BC_7, PB21, bidir, X, 71, 1, Z), " &
"69 (BC_1, *, control, 1), " &
"68 (BC_7, PB23, bidir, X, 69, 1, Z), " &
"67 (BC_1, *, control, 1), " &
"66 (BC_7, PB22, bidir, X, 67, 1, Z), " &
"65 (BC_1, *, control, 1), " &
"64 (BC_7, PB25, bidir, X, 65, 1, Z), " &
"63 (BC_1, *, control, 1), " &
"62 (BC_7, PB24, bidir, X, 63, 1, Z), " &
"61 (BC_1, *, control, 1), " &
"60 (BC_7, PB26, bidir, X, 61, 1, Z), " &
"59 (BC_1, *, control, 1), " &
"58 (BC_7, PB28, bidir, X, 59, 1, Z), " &
"57 (BC_1, *, control, 1), " &
"56 (BC_7, PB27, bidir, X, 57, 1, Z), " &
"55 (BC_1, *, control, 1), " &
"54 (BC_7, PB30, bidir, X, 55, 1, Z), " &
"53 (BC_1, *, control, 1), " &
"52 (BC_7, PB29, bidir, X, 53, 1, Z), " &
"51 (BC_1, *, control, 1), " &
"50 (BC_7, PB31, bidir, X, 51, 1, Z), " &
"49 (BC_0, *, internal, X), " &
"48 (BC_0, *, internal, X), " &
"47 (BC_0, *, internal, X), " &
"46 (BC_0, *, internal, X), " &
"45 (BC_0, *, internal, X), " &
"44 (BC_0, *, internal, X), " &
"43 (BC_0, *, internal, X), " &
"42 (BC_0, *, internal, X), " &
"41 (BC_0, *, internal, X), " &
"40 (BC_0, *, internal, X), " &
"39 (BC_0, *, internal, X), " &
"38 (BC_0, *, internal, X), " &
"37 (BC_0, *, internal, X), " &
"36 (BC_0, *, internal, X), " &
"35 (BC_0, *, internal, X), " &
"34 (BC_0, *, internal, X), " &
"33 (BC_0, *, internal, X), " &
"32 (BC_0, *, internal, X), " &
"31 (BC_0, *, internal, X), " &
"30 (BC_0, *, internal, X), " &
"29 (BC_0, *, internal, X), " &
"28 (BC_0, *, internal, X), " &
"27 (BC_0, *, internal, X), " &
"26 (BC_0, *, internal, X), " &
"25 (BC_0, *, internal, X), " &
"24 (BC_0, *, internal, X), " &
"23 (BC_0, *, internal, X), " &
"22 (BC_0, *, internal, X), " &
"21 (BC_0, *, internal, X), " &
"20 (BC_0, *, internal, X), " &
"19 (BC_0, *, internal, X), " &
"18 (BC_0, *, internal, X), " &
"17 (BC_0, *, internal, X), " &
"16 (BC_0, *, internal, X), " &
"15 (BC_1, *, control, 1), " &
"14 (BC_7, PD10, bidir, X, 15, 1, Z), " &
"13 (BC_1, *, control, 1), " &
"12 (BC_7, PD9, bidir, X, 13, 1, Z), " &
"11 (BC_1, *, control, 1), " &
"10 (BC_7, PD8, bidir, X, 11, 1, Z), " &
"9 (BC_1, *, control, 1), " &
"8 (BC_7, PD7, bidir, X, 9, 1, Z), " &
"7 (BC_0, *, internal, X), " &
"6 (BC_0, *, internal, X), " &
"5 (BC_0, *, internal, X), " &
"4 (BC_0, *, internal, X), " &
"3 (BC_0, *, internal, X), " &
"2 (BC_0, *, internal, X), " &
"1 (BC_0, *, internal, X), " &
"0 (BC_0, *, internal, X) ";
end top;

View file

@ -0,0 +1,842 @@
-- *****************************************************************************
-- BSDL file for design top
-- Created by Synopsys Version I-2013.12-SP3 (Apr 18, 2014)
-- Designer:
-- Company:
-- Date: Thu Feb 5 22:56:11 2015
-- *****************************************************************************
entity top is
-- This section identifies the default device package selected.
generic (PHYSICAL_PIN_MAP: string:= "BGA256");
-- This section declares all the ports in the design.
port (
PD14 : in bit;
PD15 : in bit;
PD17 : in bit;
PD18 : in bit;
PA0 : inout bit;
PA1 : inout bit;
PA10 : inout bit;
PA11 : inout bit;
PA12 : inout bit;
PA13 : inout bit;
PA14 : inout bit;
PA15 : inout bit;
PA16 : inout bit;
PA17 : inout bit;
PA18 : inout bit;
PA19 : inout bit;
PA2 : inout bit;
PA20 : inout bit;
PA21 : inout bit;
PA22 : inout bit;
PA23 : inout bit;
PA24 : inout bit;
PA25 : inout bit;
PA26 : inout bit;
PA27 : inout bit;
PA28 : inout bit;
PA29 : inout bit;
PA3 : inout bit;
PA30 : inout bit;
PA31 : inout bit;
PA4 : inout bit;
PA5 : inout bit;
PA6 : inout bit;
PA7 : inout bit;
PA8 : inout bit;
PA9 : inout bit;
PB0 : inout bit;
PB1 : inout bit;
PB10 : inout bit;
PB11 : inout bit;
PB12 : inout bit;
PB13 : inout bit;
PB14 : inout bit;
PB15 : inout bit;
PB16 : inout bit;
PB17 : inout bit;
PB18 : inout bit;
PB19 : inout bit;
PB2 : inout bit;
PB20 : inout bit;
PB21 : inout bit;
PB22 : inout bit;
PB23 : inout bit;
PB24 : inout bit;
PB25 : inout bit;
PB26 : inout bit;
PB27 : inout bit;
PB28 : inout bit;
PB29 : inout bit;
PB3 : inout bit;
PB30 : inout bit;
PB31 : inout bit;
PB4 : inout bit;
PB5 : inout bit;
PB6 : inout bit;
PB7 : inout bit;
PB8 : inout bit;
PB9 : inout bit;
PC0 : inout bit;
PC1 : inout bit;
-- PC10 : linkage bit; -- NC(No Connect) Port
-- PC11 : linkage bit; -- NC Port
-- PC12 : linkage bit; -- NC Port
-- PC13 : linkage bit; -- NC Port
-- PC14 : linkage bit; -- NC Port
-- PC15 : linkage bit; -- NC Port
-- PC16 : linkage bit; -- NC Port
-- PC17 : linkage bit; -- NC Port
-- PC18 : linkage bit; -- NC Port
-- PC19 : linkage bit; -- NC Port
PC2 : inout bit;
-- PC20 : linkage bit; -- NC Port
-- PC21 : linkage bit; -- NC Port
-- PC22 : linkage bit; -- NC Port
-- PC23 : linkage bit; -- NC Port
-- PC24 : linkage bit; -- NC Port
-- PC25 : linkage bit; -- NC Port
-- PC26 : linkage bit; -- NC Port
-- PC27 : linkage bit; -- NC Port
-- PC28 : linkage bit; -- NC Port
-- PC29 : linkage bit; -- NC Port
PC3 : inout bit;
-- PC30 : linkage bit; -- NC Port
-- PC31 : linkage bit; -- NC Port
PC4 : inout bit;
PC5 : inout bit;
PC6 : inout bit;
PC7 : inout bit;
PC8 : inout bit;
-- PC9 : linkage bit; -- NC Port
PD0 : inout bit;
PD1 : inout bit;
PD10 : inout bit;
PD11 : inout bit;
PD12 : inout bit;
PD13 : inout bit;
PD19 : inout bit;
PD2 : inout bit;
PD20 : inout bit;
PD21 : inout bit;
PD22 : inout bit;
PD23 : inout bit;
PD24 : inout bit;
PD25 : inout bit;
PD26 : inout bit;
PD27 : inout bit;
PD28 : inout bit;
PD29 : inout bit;
PD3 : inout bit;
PD30 : inout bit;
PD31 : inout bit;
PD4 : inout bit;
PD5 : inout bit;
PD6 : inout bit;
PD7 : inout bit;
PD8 : inout bit;
PD9 : inout bit;
DDR_D : inout bit_vector (0 to 31);
DDR_DQS : inout bit_vector (0 to 3);
DDR_DQSN : inout bit_vector (0 to 3);
DDR_CAS : out bit;
DDR_CKE : out bit;
DDR_CLK : out bit;
DDR_CLKN : out bit;
DDR_CS : out bit;
DDR_RAS : out bit;
DDR_RESETN : out bit;
DDR_WE : out bit;
PD16 : out bit;
DDR_A : out bit_vector (0 to 13);
DDR_BA : out bit_vector (0 to 2);
DDR_DQM : out bit_vector (0 to 3);
-- ADVREFN : linkage bit;
ADVREFP : linkage bit;
CLK_AUDIO : linkage bit;
COMPN : linkage bit;
COMPP : linkage bit;
DDR_CAL : linkage bit;
DDR_VREF : linkage bit; -- DDR_VREFB0 : linkage bit;
-- DDR_VREFB1 : linkage bit;
-- DDR_VREFB2 : linkage bit;
-- DDR_VREFB3 : linkage bit;
-- DDR_VREFCM : linkage bit;
HHSDMA : linkage bit;
HHSDMB : linkage bit;
HHSDMSTRC : linkage bit;
HHSDPA : linkage bit;
HHSDPB : linkage bit;
HHSDPDATC : linkage bit;
JTAGSEL : in bit;
NRST : linkage bit;
RXD : linkage bit;
SDCAL : linkage bit;
SHDN : linkage bit;
TST : in bit;
VBG : linkage bit;
WKUP : linkage bit;
XIN : linkage bit;
XIN32 : linkage bit;
XOUT : linkage bit;
XOUT32 : linkage bit;
-- tst_drst_ana : linkage bit; -- NC Port
-- tst_drst_ddr : linkage bit; -- NC Port
-- tst_drst_iop0 : linkage bit; -- NC Port
-- tst_drst_iop1 : linkage bit; -- NC Port
-- tst_drst_iop2 : linkage bit; -- NC Port
-- tst_drst_isi : linkage bit; -- NC Port
-- tst_drst_osc : linkage bit; -- NC Port
-- tst_drst_sdhc : linkage bit; -- NC Port
-- tst_lft_plla : linkage bit; -- NC Port
-- tst_lft_utmi : linkage bit; -- NC Port
-- tst_por_1v2 : linkage bit; -- NC Port
-- tst_por_1v8 : linkage bit; -- NC Port
-- tst_por_bu : linkage bit; -- NC Port
-- tst_psw_bu : linkage bit; -- NC Port
-- tst_psw_fuse : linkage bit; -- NC Port
PIOBU : linkage bit_vector (0 to 1)
);
use STD_1149_1_1994.all;
attribute COMPONENT_CONFORMANCE of top: entity is "STD_1149_1_1993";
attribute PIN_MAP of top: entity is PHYSICAL_PIN_MAP;
-- This section specifies the pin map for each port. This information is
-- extracted from the port-to-pin map file that was read in using the
-- "read_pin_map" command.
constant BGA256: PIN_MAP_STRING :=
"PD14 : K6," &
"PD15 : K4," &
"PD17 : K2," &
"PD18 : L5," &
"PA0 : R10," &
"PA1 : R9," &
"PA10 : U13," &
"PA11 : R14," &
"PA12 : N13," &
"PA13 : P14," &
"PA14 : P17," &
"PA15 : R18," &
"PA16 : N15," &
"PA17 : P18," &
"PA18 : M9," &
"PA19 : V13," &
"PA2 : U11," &
"PA20 : L9," &
"PA21 : M10," &
"PA22 : V14," &
"PA23 : U14," &
"PA24 : R13," &
"PA25 : U15," &
"PA26 : L10," &
"PA27 : V17," &
"PA28 : U16," &
"PA29 : U17," &
"PA3 : P10," &
"PA30 : V18," &
"PA31 : U18," &
"PA4 : P11," &
"PA5 : V11," &
"PA6 : U12," &
"PA7 : V12," &
"PA8 : N11," &
"PA9 : P12," &
"PB0 : G9," &
"PB1 : A7," &
"PB10 : D6," &
"PB11 : A4," &
"PB12 : B3," &
"PB13 : A3," &
"PB14 : B4," &
"PB15 : G8," &
"PB16 : E5," &
"PB17 : G7," &
"PB18 : A2," &
"PB19 : H7," &
"PB2 : B7," &
"PB20 : A1," &
"PB21 : D2," &
"PB22 : G5," &
"PB23 : C2," &
"PB24 : F4," &
"PB25 : C1," &
"PB26 : E4," &
"PB27 : F1," &
"PB28 : D1," &
"PB29 : F2," &
"PB3 : B6," &
"PB30 : E2," &
"PB31 : E1," &
"PB4 : A6," &
"PB5 : D7," &
"PB6 : B5," &
"PB7 : A5," &
"PB8 : E7," &
"PB9 : F6," &
"PC0 : R15," &
"PC1 : M11," &
"PC2 : P15," &
"PC3 : K9," &
"PC4 : K10," &
"PC5 : L11," &
"PC6 : L12," &
"PC7 : M12," &
"PC8 : K11," &
"PD0 : E9," &
"PD1 : F8," &
"PD10 : G2," &
"PD11 : H2," &
"PD12 : K5," &
"PD13 : J5," &
"PD19 : L4," &
"PD2 : F9," &
"PD20 : M1," &
"PD21 : M2," &
"PD22 : M4," &
"PD23 : P1," &
"PD24 : L6," &
"PD25 : M5," &
"PD26 : N1," &
"PD27 : N2," &
"PD28 : P2," &
"PD29 : R1," &
"PD3 : J4," &
"PD30 : N4," &
"PD31 : T1," &
"PD4 : H6," &
"PD5 : H1," &
"PD6 : G4," &
"PD7 : H5," &
"PD8 : G1," &
"PD9 : H4," &
"DDR_D : (B12, B13, D13, A13, A15, D14, B15, B16, G18, K17, " &
"J13, H15, J15, J14, K13, K18, A8, B9, D9, A9, B11, D10, A11, A12, " &
"L18, K15, K14, M18, N17, M14, M15, N18)," &
"DDR_DQS : (A14, H18, A10, M17)," &
"DDR_DQSN : (B14, J18, B10, L17)," &
"DDR_CAS : E17," &
"DDR_CKE : F18," &
"DDR_CLK : C18," &
"DDR_CLKN : C17," &
"DDR_CS : J12," &
"DDR_RAS : E18," &
"DDR_RESETN : F17," &
"DDR_WE : D18," &
"PD16 : K1," &
"DDR_A : (D17, A17, A18, F15, G12, H12, F13, H10, A16, E12, " &
"H11, J10, D15, J11)," &
"DDR_BA : (H13, K12, H17)," &
"DDR_DQM : (D11, H14, B8, L13)," &
"ADVREFP : P5," &
"CLK_AUDIO : M8," &
"COMPN : V4," &
"COMPP : V3," &
"DDR_CAL : G17," &
"HHSDMA : V8," &
"HHSDMB : V9," &
"HHSDMSTRC : V10," &
"HHSDPA : U8," &
"HHSDPB : U9," &
"HHSDPDATC : U10," &
"JTAGSEL : V2," &
"NRST : V1," &
"RXD : U2," &
"SDCAL : N10," &
"SHDN : U1," &
"TST : P4," &
"VBG : R7," &
"WKUP : R5," &
"XIN : V7," &
"XIN32 : T2," &
"XOUT : V6," &
"XOUT32 : R2," &
"PIOBU : (R6, R4)";
-- This section specifies the differential IO port groupings.
attribute PORT_GROUPING of top: entity is
"Differential_Voltage ( " &
"(DDR_CLK,DDR_CLKN))";
-- This section specifies the TAP ports. For the TAP TCK port, the parameters in
-- the brackets are:
-- First Field : Maximum TCK frequency.
-- Second Field: Allowable states TCK may be stopped in.
attribute TAP_SCAN_CLOCK of PD14: signal is (10.0e6, BOTH);
attribute TAP_SCAN_IN of PD15: signal is true;
attribute TAP_SCAN_MODE of PD17: signal is true;
attribute TAP_SCAN_OUT of PD16: signal is true;
attribute TAP_SCAN_RESET of PD18: signal is true;
-- Specifies the compliance enable patterns for the design. It lists a set of
-- design ports and the values that they should be set to, in order to enable
-- compliance to IEEE Std 1149.1
attribute COMPLIANCE_PATTERNS of top: entity is
"(JTAGSEL, TST) (10)";
-- Specifies the number of bits in the instruction register.
attribute INSTRUCTION_LENGTH of top: entity is 4;
-- Specifies the boundary-scan instructions implemented in the design and their
-- opcodes.
attribute INSTRUCTION_OPCODE of top: entity is
"BYPASS (1111, 0001, 0101, 0110, 1100, 0111, 1101, 1000, 1001, 1011, " &
"1110)," &
"EXTEST (0000)," &
"SAMPLE (0100)," &
"INTEST (0010)," &
"IDCODE (0011)," &
"RUNBIST (1010)";
-- Specifies the bit pattern that is loaded into the instruction register when
-- the TAP controller passes through the Capture-IR state. The standard mandates
-- that the two LSBs must be "01". The remaining bits are design specific.
attribute INSTRUCTION_CAPTURE of top: entity is "0001";
-- Specifies the bit pattern that is loaded into the DEVICE_ID register during
-- the IDCODE instruction when the TAP controller passes through the Capture-DR
-- state.
attribute IDCODE_REGISTER of top: entity is
"0000" &
-- 4-bit version number
"0101101100111111" &
-- 16-bit part number
"00000011111" &
-- 11-bit identity of the manufacturer
"1";
-- Required by IEEE Std 1149.1
-- This section specifies the test data register placed between TDI and TDO for
-- each implemented instruction.
attribute REGISTER_ACCESS of top: entity is
"BYPASS (BYPASS)," &
"BOUNDARY (EXTEST, SAMPLE, INTEST)," &
"DEVICE_ID (IDCODE)," &
"UTDR1[41] (RUNBIST)";
-- Specifies the length of the boundary scan register.
attribute BOUNDARY_LENGTH of top: entity is 374;
-- The following list specifies the characteristics of each cell in the boundary
-- scan register from TDI to TDO. The following is a description of the label
-- fields:
-- num : Is the cell number.
-- cell : Is the cell type as defined by the standard.
-- port : Is the design port name. Control cells do not have a port
-- name.
-- function: Is the function of the cell as defined by the standard. Is one
-- of input, output2, output3, bidir, control or controlr.
-- safe : Specifies the value that the BSR cell should be loaded with
-- for safe operation when the software might otherwise choose a
-- random value.
-- ccell : The control cell number. Specifies the control cell that
-- drives the output enable for this port.
-- disval : Specifies the value that is loaded into the control cell to
-- disable the output enable for the corresponding port.
-- rslt : Resulting state. Shows the state of the driver when it is
-- disabled.
attribute BOUNDARY_REGISTER of top: entity is
--
-- num cell port function safe [ccell disval rslt]
--
"373 (BC_1, *, control, 1), " &
"372 (BC_7, PD13, bidir, X, 373, 1, Z), " &
"371 (BC_1, *, control, 1), " &
"370 (BC_7, PD12, bidir, X, 371, 1, Z), " &
"369 (BC_1, *, control, 1), " &
"368 (BC_7, PD11, bidir, X, 369, 1, Z), " &
"367 (BC_1, *, control, 1), " &
"366 (BC_7, PD19, bidir, X, 367, 1, Z), " &
"365 (BC_1, *, control, 1), " &
"364 (BC_7, PD20, bidir, X, 365, 1, Z), " &
"363 (BC_1, *, control, 1), " &
"362 (BC_7, PD24, bidir, X, 363, 1, Z), " &
"361 (BC_1, *, control, 1), " &
"360 (BC_7, PD21, bidir, X, 361, 1, Z), " &
"359 (BC_1, *, control, 1), " &
"358 (BC_7, PD25, bidir, X, 359, 1, Z), " &
"357 (BC_1, *, control, 1), " &
"356 (BC_7, PD26, bidir, X, 357, 1, Z), " &
"355 (BC_1, *, control, 1), " &
"354 (BC_7, PD22, bidir, X, 355, 1, Z), " &
"353 (BC_1, *, control, 1), " &
"352 (BC_7, PD27, bidir, X, 353, 1, Z), " &
"351 (BC_1, *, control, 1), " &
"350 (BC_7, PD23, bidir, X, 351, 1, Z), " &
"349 (BC_1, *, control, 1), " &
"348 (BC_7, PD28, bidir, X, 349, 1, Z), " &
"347 (BC_1, *, control, 1), " &
"346 (BC_7, PD30, bidir, X, 347, 1, Z), " &
"345 (BC_1, *, control, 1), " &
"344 (BC_7, PD29, bidir, X, 345, 1, Z), " &
"343 (BC_1, *, control, 1), " &
"342 (BC_7, PD31, bidir, X, 343, 1, Z), " &
"341 (BC_1, *, control, 1), " &
"340 (BC_7, PA0, bidir, X, 341, 1, Z), " &
"339 (BC_1, *, control, 1), " &
"338 (BC_7, PA1, bidir, X, 339, 1, Z), " &
"337 (BC_1, *, control, 1), " &
"336 (BC_7, PA2, bidir, X, 337, 1, Z), " &
"335 (BC_1, *, control, 1), " &
"334 (BC_7, PA3, bidir, X, 335, 1, Z), " &
"333 (BC_1, *, control, 1), " &
"332 (BC_7, PA4, bidir, X, 333, 1, Z), " &
"331 (BC_1, *, control, 1), " &
"330 (BC_7, PA5, bidir, X, 331, 1, Z), " &
"329 (BC_1, *, control, 1), " &
"328 (BC_7, PA6, bidir, X, 329, 1, Z), " &
"327 (BC_1, *, control, 1), " &
"326 (BC_7, PA7, bidir, X, 327, 1, Z), " &
"325 (BC_1, *, control, 1), " &
"324 (BC_7, PA8, bidir, X, 325, 1, Z), " &
"323 (BC_1, *, control, 1), " &
"322 (BC_7, PA9, bidir, X, 323, 1, Z), " &
"321 (BC_1, *, control, 1), " &
"320 (BC_7, PA10, bidir, X, 321, 1, Z), " &
"319 (BC_1, *, control, 1), " &
"318 (BC_7, PA18, bidir, X, 319, 1, Z), " &
"317 (BC_1, *, control, 1), " &
"316 (BC_7, PA20, bidir, X, 317, 1, Z), " &
"315 (BC_1, *, control, 1), " &
"314 (BC_7, PA19, bidir, X, 315, 1, Z), " &
"313 (BC_1, *, control, 1), " &
"312 (BC_7, PA21, bidir, X, 313, 1, Z), " &
"311 (BC_1, *, control, 1), " &
"310 (BC_7, PA22, bidir, X, 311, 1, Z), " &
"309 (BC_1, *, control, 1), " &
"308 (BC_7, PA23, bidir, X, 309, 1, Z), " &
"307 (BC_1, *, control, 1), " &
"306 (BC_7, PA24, bidir, X, 307, 1, Z), " &
"305 (BC_1, *, control, 1), " &
"304 (BC_7, PA25, bidir, X, 305, 1, Z), " &
"303 (BC_1, *, control, 1), " &
"302 (BC_7, PA26, bidir, X, 303, 1, Z), " &
"301 (BC_1, *, control, 1), " &
"300 (BC_7, PA27, bidir, X, 301, 1, Z), " &
"299 (BC_1, *, control, 1), " &
"298 (BC_7, PA28, bidir, X, 299, 1, Z), " &
"297 (BC_1, *, control, 1), " &
"296 (BC_7, PA30, bidir, X, 297, 1, Z), " &
"295 (BC_1, *, control, 1), " &
"294 (BC_7, PA29, bidir, X, 295, 1, Z), " &
"293 (BC_1, *, control, 1), " &
"292 (BC_7, PA31, bidir, X, 293, 1, Z), " &
"291 (BC_1, *, control, 1), " &
"290 (BC_7, PC0, bidir, X, 291, 1, Z), " &
"289 (BC_1, *, control, 1), " &
"288 (BC_7, PA11, bidir, X, 289, 1, Z), " &
"287 (BC_1, *, control, 1), " &
"286 (BC_7, PC1, bidir, X, 287, 1, Z), " &
"285 (BC_1, *, control, 1), " &
"284 (BC_7, PA13, bidir, X, 285, 1, Z), " &
"283 (BC_1, *, control, 1), " &
"282 (BC_7, PA12, bidir, X, 283, 1, Z), " &
"281 (BC_1, *, control, 1), " &
"280 (BC_7, PC2, bidir, X, 281, 1, Z), " &
"279 (BC_1, *, control, 1), " &
"278 (BC_7, PA14, bidir, X, 279, 1, Z), " &
"277 (BC_1, *, control, 1), " &
"276 (BC_7, PA15, bidir, X, 277, 1, Z), " &
"275 (BC_1, *, control, 1), " &
"274 (BC_7, PC3, bidir, X, 275, 1, Z), " &
"273 (BC_1, *, control, 1), " &
"272 (BC_7, PC4, bidir, X, 273, 1, Z), " &
"271 (BC_1, *, control, 1), " &
"270 (BC_7, PA16, bidir, X, 271, 1, Z), " &
"269 (BC_1, *, control, 1), " &
"268 (BC_7, PA17, bidir, X, 269, 1, Z), " &
"267 (BC_1, *, control, 1), " &
"266 (BC_7, PC5, bidir, X, 267, 1, Z), " &
"265 (BC_1, *, control, 1), " &
"264 (BC_7, PC7, bidir, X, 265, 1, Z), " &
"263 (BC_1, *, control, 1), " &
"262 (BC_7, PC6, bidir, X, 263, 1, Z), " &
"261 (BC_1, *, control, 1), " &
"260 (BC_7, PC8, bidir, X, 261, 1, Z), " &
"259 (BC_1, *, control, 1), " &
"258 (BC_7, DDR_D(31), bidir, X, 259, 1, Z), " &
"257 (BC_1, *, control, 1), " &
"256 (BC_7, DDR_D(30), bidir, X, 257, 1, Z), " &
"255 (BC_1, *, control, 1), " &
"254 (BC_7, DDR_D(29), bidir, X, 255, 1, Z), " &
"253 (BC_1, *, control, 1), " &
"252 (BC_7, DDR_D(28), bidir, X, 253, 1, Z), " &
"251 (BC_1, *, control, 1), " &
"250 (BC_7, DDR_DQS(3), bidir, X, 251, 1, Z), " &
"249 (BC_1, *, control, 1), " &
"248 (BC_7, DDR_D(27), bidir, X, 249, 1, Z), " &
"247 (BC_1, *, control, 1), " &
"246 (BC_7, DDR_D(26), bidir, X, 247, 1, Z), " &
"245 (BC_1, *, control, 1), " &
"244 (BC_7, DDR_D(25), bidir, X, 245, 1, Z), " &
"243 (BC_1, *, control, 1), " &
"242 (BC_7, DDR_D(24), bidir, X, 243, 1, Z), " &
"241 (BC_0, *, control, 1), " &
"240 (BC_0, DDR_DQM(3), output3, X, 241, 1, Z), " &
"239 (BC_1, *, control, 1), " &
"238 (BC_7, DDR_D(15), bidir, X, 239, 1, Z), " &
"237 (BC_1, *, control, 1), " &
"236 (BC_7, DDR_D(14), bidir, X, 237, 1, Z), " &
"235 (BC_1, *, control, 1), " &
"234 (BC_7, DDR_D(13), bidir, X, 235, 1, Z), " &
"233 (BC_1, *, control, 1), " &
"232 (BC_7, DDR_D(12), bidir, X, 233, 1, Z), " &
"231 (BC_1, *, control, 1), " &
"230 (BC_7, DDR_DQS(1), bidir, X, 231, 1, Z), " &
"229 (BC_1, *, control, 1), " &
"228 (BC_7, DDR_D(11), bidir, X, 229, 1, Z), " &
"227 (BC_1, *, control, 1), " &
"226 (BC_7, DDR_D(10), bidir, X, 227, 1, Z), " &
"225 (BC_1, *, control, 1), " &
"224 (BC_7, DDR_D(9), bidir, X, 225, 1, Z), " &
"223 (BC_1, *, control, 1), " &
"222 (BC_7, DDR_D(8), bidir, X, 223, 1, Z), " &
"221 (BC_0, *, control, 1), " &
"220 (BC_0, DDR_DQM(1), output3, X, 221, 1, Z), " &
"219 (BC_0, *, control, 1), " &
"218 (BC_0, DDR_BA(2), output3, X, 219, 1, Z), " &
"217 (BC_0, *, control, 1), " &
"216 (BC_0, DDR_BA(1), output3, X, 217, 1, Z), " &
"215 (BC_0, *, control, 1), " &
"214 (BC_0, DDR_BA(0), output3, X, 215, 1, Z), " &
"213 (BC_0, *, control, 1), " &
"212 (BC_0, DDR_CKE, output3, X, 213, 1, Z), " &
"211 (BC_0, *, control, 1), " &
"210 (BC_0, DDR_CS, output3, X, 211, 1, Z), " &
"209 (BC_0, *, control, 1), " &
"208 (BC_0, DDR_A(13), output3, X, 209, 1, Z), " &
"207 (BC_0, *, control, 1), " &
"206 (BC_0, DDR_RESETN, output3, X, 207, 1, Z), " &
"205 (BC_0, *, control, 1), " &
"204 (BC_0, DDR_A(5), output3, X, 205, 1, Z), " &
"203 (BC_0, *, control, 1), " &
"202 (BC_0, DDR_A(6), output3, X, 203, 1, Z), " &
"201 (BC_0, *, control, 1), " &
"200 (BC_0, DDR_RAS, output3, X, 201, 1, Z), " &
"199 (BC_0, *, control, 1), " &
"198 (BC_0, DDR_CAS, output3, X, 199, 1, Z), " &
"197 (BC_0, *, control, 1), " &
"196 (BC_0, DDR_WE, output3, X, 197, 1, Z), " &
"195 (BC_0, *, control, 1), " &
"194 (BC_0, DDR_CLK, output3, X, 195, 1, Z), " &
"193 (BC_0, *, control, 1), " &
"192 (BC_0, DDR_A(0), output3, X, 193, 1, Z), " &
"191 (BC_0, *, control, 1), " &
"190 (BC_0, DDR_A(1), output3, X, 191, 1, Z), " &
"189 (BC_0, *, control, 1), " &
"188 (BC_0, DDR_A(2), output3, X, 189, 1, Z), " &
"187 (BC_0, *, control, 1), " &
"186 (BC_0, DDR_A(3), output3, X, 187, 1, Z), " &
"185 (BC_0, *, control, 1), " &
"184 (BC_0, DDR_A(4), output3, X, 185, 1, Z), " &
"183 (BC_0, *, control, 1), " &
"182 (BC_0, DDR_A(12), output3, X, 183, 1, Z), " &
"181 (BC_0, *, control, 1), " &
"180 (BC_0, DDR_A(11), output3, X, 181, 1, Z), " &
"179 (BC_0, *, control, 1), " &
"178 (BC_0, DDR_A(10), output3, X, 179, 1, Z), " &
"177 (BC_0, *, control, 1), " &
"176 (BC_0, DDR_A(9), output3, X, 177, 1, Z), " &
"175 (BC_0, *, control, 1), " &
"174 (BC_0, DDR_A(8), output3, X, 175, 1, Z), " &
"173 (BC_0, *, control, 1), " &
"172 (BC_0, DDR_A(7), output3, X, 173, 1, Z), " &
"171 (BC_1, *, control, 1), " &
"170 (BC_7, DDR_D(7), bidir, X, 171, 1, Z), " &
"169 (BC_1, *, control, 1), " &
"168 (BC_7, DDR_D(6), bidir, X, 169, 1, Z), " &
"167 (BC_1, *, control, 1), " &
"166 (BC_7, DDR_D(5), bidir, X, 167, 1, Z), " &
"165 (BC_1, *, control, 1), " &
"164 (BC_7, DDR_D(4), bidir, X, 165, 1, Z), " &
"163 (BC_1, *, control, 1), " &
"162 (BC_7, DDR_DQS(0), bidir, X, 163, 1, Z), " &
"161 (BC_1, *, control, 1), " &
"160 (BC_7, DDR_D(3), bidir, X, 161, 1, Z), " &
"159 (BC_1, *, control, 1), " &
"158 (BC_7, DDR_D(2), bidir, X, 159, 1, Z), " &
"157 (BC_1, *, control, 1), " &
"156 (BC_7, DDR_D(1), bidir, X, 157, 1, Z), " &
"155 (BC_1, *, control, 1), " &
"154 (BC_7, DDR_D(0), bidir, X, 155, 1, Z), " &
"153 (BC_0, *, control, 1), " &
"152 (BC_0, DDR_DQM(0), output3, X, 153, 1, Z), " &
"151 (BC_1, *, control, 1), " &
"150 (BC_7, DDR_D(23), bidir, X, 151, 1, Z), " &
"149 (BC_1, *, control, 1), " &
"148 (BC_7, DDR_D(22), bidir, X, 149, 1, Z), " &
"147 (BC_1, *, control, 1), " &
"146 (BC_7, DDR_D(21), bidir, X, 147, 1, Z), " &
"145 (BC_1, *, control, 1), " &
"144 (BC_7, DDR_D(20), bidir, X, 145, 1, Z), " &
"143 (BC_1, *, control, 1), " &
"142 (BC_7, DDR_DQS(2), bidir, X, 143, 1, Z), " &
"141 (BC_1, *, control, 1), " &
"140 (BC_7, DDR_D(19), bidir, X, 141, 1, Z), " &
"139 (BC_1, *, control, 1), " &
"138 (BC_7, DDR_D(18), bidir, X, 139, 1, Z), " &
"137 (BC_1, *, control, 1), " &
"136 (BC_7, DDR_D(17), bidir, X, 137, 1, Z), " &
"135 (BC_1, *, control, 1), " &
"134 (BC_7, DDR_D(16), bidir, X, 135, 1, Z), " &
"133 (BC_0, *, control, 1), " &
"132 (BC_0, DDR_DQM(2), output3, X, 133, 1, Z), " &
"131 (BC_1, *, control, 1), " &
"130 (BC_7, PD0, bidir, X, 131, 1, Z), " &
"129 (BC_1, *, control, 1), " &
"128 (BC_7, PD1, bidir, X, 129, 1, Z), " &
"127 (BC_1, *, control, 1), " &
"126 (BC_7, PD2, bidir, X, 127, 1, Z), " &
"125 (BC_0, *, internal, X), " &
"124 (BC_0, *, internal, X), " &
"123 (BC_0, *, internal, X), " &
"122 (BC_0, *, internal, X), " &
"121 (BC_0, *, internal, X), " &
"120 (BC_0, *, internal, X), " &
"119 (BC_0, *, internal, X), " &
"118 (BC_0, *, internal, X), " &
"117 (BC_0, *, internal, X), " &
"116 (BC_0, *, internal, X), " &
"115 (BC_0, *, internal, X), " &
"114 (BC_0, *, internal, X), " &
"113 (BC_1, *, control, 1), " &
"112 (BC_7, PB0, bidir, X, 113, 1, Z), " &
"111 (BC_1, *, control, 1), " &
"110 (BC_7, PB2, bidir, X, 111, 1, Z), " &
"109 (BC_1, *, control, 1), " &
"108 (BC_7, PB1, bidir, X, 109, 1, Z), " &
"107 (BC_1, *, control, 1), " &
"106 (BC_7, PB3, bidir, X, 107, 1, Z), " &
"105 (BC_1, *, control, 1), " &
"104 (BC_7, PB4, bidir, X, 105, 1, Z), " &
"103 (BC_1, *, control, 1), " &
"102 (BC_7, PB5, bidir, X, 103, 1, Z), " &
"101 (BC_1, *, control, 1), " &
"100 (BC_7, PB6, bidir, X, 101, 1, Z), " &
"99 (BC_1, *, control, 1), " &
"98 (BC_7, PB8, bidir, X, 99, 1, Z), " &
"97 (BC_1, *, control, 1), " &
"96 (BC_7, PB7, bidir, X, 97, 1, Z), " &
"95 (BC_1, *, control, 1), " &
"94 (BC_7, PB10, bidir, X, 95, 1, Z), " &
"93 (BC_1, *, control, 1), " &
"92 (BC_7, PB9, bidir, X, 93, 1, Z), " &
"91 (BC_1, *, control, 1), " &
"90 (BC_7, PB11, bidir, X, 91, 1, Z), " &
"89 (BC_1, *, control, 1), " &
"88 (BC_7, PB12, bidir, X, 89, 1, Z), " &
"87 (BC_1, *, control, 1), " &
"86 (BC_7, PB14, bidir, X, 87, 1, Z), " &
"85 (BC_1, *, control, 1), " &
"84 (BC_7, PB13, bidir, X, 85, 1, Z), " &
"83 (BC_1, *, control, 1), " &
"82 (BC_7, PB15, bidir, X, 83, 1, Z), " &
"81 (BC_1, *, control, 1), " &
"80 (BC_7, PB16, bidir, X, 81, 1, Z), " &
"79 (BC_1, *, control, 1), " &
"78 (BC_7, PB17, bidir, X, 79, 1, Z), " &
"77 (BC_1, *, control, 1), " &
"76 (BC_7, PB19, bidir, X, 77, 1, Z), " &
"75 (BC_1, *, control, 1), " &
"74 (BC_7, PB18, bidir, X, 75, 1, Z), " &
"73 (BC_1, *, control, 1), " &
"72 (BC_7, PB20, bidir, X, 73, 1, Z), " &
"71 (BC_1, *, control, 1), " &
"70 (BC_7, PB21, bidir, X, 71, 1, Z), " &
"69 (BC_1, *, control, 1), " &
"68 (BC_7, PB23, bidir, X, 69, 1, Z), " &
"67 (BC_1, *, control, 1), " &
"66 (BC_7, PB22, bidir, X, 67, 1, Z), " &
"65 (BC_1, *, control, 1), " &
"64 (BC_7, PB25, bidir, X, 65, 1, Z), " &
"63 (BC_1, *, control, 1), " &
"62 (BC_7, PB24, bidir, X, 63, 1, Z), " &
"61 (BC_1, *, control, 1), " &
"60 (BC_7, PB26, bidir, X, 61, 1, Z), " &
"59 (BC_1, *, control, 1), " &
"58 (BC_7, PB28, bidir, X, 59, 1, Z), " &
"57 (BC_1, *, control, 1), " &
"56 (BC_7, PB27, bidir, X, 57, 1, Z), " &
"55 (BC_1, *, control, 1), " &
"54 (BC_7, PB30, bidir, X, 55, 1, Z), " &
"53 (BC_1, *, control, 1), " &
"52 (BC_7, PB29, bidir, X, 53, 1, Z), " &
"51 (BC_1, *, control, 1), " &
"50 (BC_7, PB31, bidir, X, 51, 1, Z), " &
"49 (BC_0, *, internal, X), " &
"48 (BC_0, *, internal, X), " &
"47 (BC_0, *, internal, X), " &
"46 (BC_0, *, internal, X), " &
"45 (BC_0, *, internal, X), " &
"44 (BC_0, *, internal, X), " &
"43 (BC_0, *, internal, X), " &
"42 (BC_0, *, internal, X), " &
"41 (BC_0, *, internal, X), " &
"40 (BC_0, *, internal, X), " &
"39 (BC_0, *, internal, X), " &
"38 (BC_0, *, internal, X), " &
"37 (BC_0, *, internal, X), " &
"36 (BC_0, *, internal, X), " &
"35 (BC_0, *, internal, X), " &
"34 (BC_0, *, internal, X), " &
"33 (BC_0, *, internal, X), " &
"32 (BC_0, *, internal, X), " &
"31 (BC_0, *, internal, X), " &
"30 (BC_0, *, internal, X), " &
"29 (BC_0, *, internal, X), " &
"28 (BC_0, *, internal, X), " &
"27 (BC_0, *, internal, X), " &
"26 (BC_0, *, internal, X), " &
"25 (BC_0, *, internal, X), " &
"24 (BC_0, *, internal, X), " &
"23 (BC_0, *, internal, X), " &
"22 (BC_0, *, internal, X), " &
"21 (BC_0, *, internal, X), " &
"20 (BC_0, *, internal, X), " &
"19 (BC_0, *, internal, X), " &
"18 (BC_0, *, internal, X), " &
"17 (BC_0, *, internal, X), " &
"16 (BC_0, *, internal, X), " &
"15 (BC_1, *, control, 1), " &
"14 (BC_7, PD10, bidir, X, 15, 1, Z), " &
"13 (BC_1, *, control, 1), " &
"12 (BC_7, PD9, bidir, X, 13, 1, Z), " &
"11 (BC_1, *, control, 1), " &
"10 (BC_7, PD8, bidir, X, 11, 1, Z), " &
"9 (BC_1, *, control, 1), " &
"8 (BC_7, PD7, bidir, X, 9, 1, Z), " &
"7 (BC_1, *, control, 1), " &
"6 (BC_7, PD6, bidir, X, 7, 1, Z), " &
"5 (BC_1, *, control, 1), " &
"4 (BC_7, PD5, bidir, X, 5, 1, Z), " &
"3 (BC_1, *, control, 1), " &
"2 (BC_7, PD4, bidir, X, 3, 1, Z), " &
"1 (BC_1, *, control, 1), " &
"0 (BC_7, PD3, bidir, X, 1, 1, Z) ";
end top;

View file

@ -0,0 +1,865 @@
-- *****************************************************************************
-- BSDL file for design top
-- Created by Synopsys Version I-2013.12-SP3 (Apr 18, 2014)
-- Designer:
-- Company:
-- Date: Thu Feb 5 23:41:59 2015
-- *****************************************************************************
entity top is
-- This section identifies the default device package selected.
generic (PHYSICAL_PIN_MAP: string:= "BGA289");
-- This section declares all the ports in the design.
port (
PD14 : in bit;
PD15 : in bit;
PD17 : in bit;
PD18 : in bit;
PA0 : inout bit;
PA1 : inout bit;
PA10 : inout bit;
PA11 : inout bit;
PA12 : inout bit;
PA13 : inout bit;
PA14 : inout bit;
PA15 : inout bit;
PA16 : inout bit;
PA17 : inout bit;
PA18 : inout bit;
PA19 : inout bit;
PA2 : inout bit;
PA20 : inout bit;
PA21 : inout bit;
PA22 : inout bit;
PA23 : inout bit;
PA24 : inout bit;
PA25 : inout bit;
PA26 : inout bit;
PA27 : inout bit;
PA28 : inout bit;
PA29 : inout bit;
PA3 : inout bit;
PA30 : inout bit;
PA31 : inout bit;
PA4 : inout bit;
PA5 : inout bit;
PA6 : inout bit;
PA7 : inout bit;
PA8 : inout bit;
PA9 : inout bit;
PB0 : inout bit;
PB1 : inout bit;
PB10 : inout bit;
PB11 : inout bit;
PB12 : inout bit;
PB13 : inout bit;
PB14 : inout bit;
PB15 : inout bit;
PB16 : inout bit;
PB17 : inout bit;
PB18 : inout bit;
PB19 : inout bit;
PB2 : inout bit;
PB20 : inout bit;
PB21 : inout bit;
PB22 : inout bit;
PB23 : inout bit;
PB24 : inout bit;
PB25 : inout bit;
PB26 : inout bit;
PB27 : inout bit;
PB28 : inout bit;
PB29 : inout bit;
PB3 : inout bit;
PB30 : inout bit;
PB31 : inout bit;
PB4 : inout bit;
PB5 : inout bit;
PB6 : inout bit;
PB7 : inout bit;
PB8 : inout bit;
PB9 : inout bit;
PC0 : inout bit;
PC1 : inout bit;
PC10 : inout bit;
PC11 : inout bit;
PC12 : inout bit;
PC13 : inout bit;
PC14 : inout bit;
PC15 : inout bit;
PC16 : inout bit;
PC17 : inout bit;
PC18 : inout bit;
PC19 : inout bit;
PC2 : inout bit;
PC20 : inout bit;
PC21 : inout bit;
PC22 : inout bit;
PC23 : inout bit;
PC24 : inout bit;
PC25 : inout bit;
PC26 : inout bit;
PC27 : inout bit;
PC28 : inout bit;
PC29 : inout bit;
PC3 : inout bit;
PC30 : inout bit;
PC31 : inout bit;
PC4 : inout bit;
PC5 : inout bit;
PC6 : inout bit;
PC7 : inout bit;
PC8 : inout bit;
PC9 : inout bit;
PD0 : inout bit;
PD1 : inout bit;
PD10 : inout bit;
PD11 : inout bit;
PD12 : inout bit;
PD13 : inout bit;
PD19 : inout bit;
PD2 : inout bit;
PD20 : inout bit;
PD21 : inout bit;
PD22 : inout bit;
PD23 : inout bit;
PD24 : inout bit;
PD25 : inout bit;
PD26 : inout bit;
PD27 : inout bit;
PD28 : inout bit;
PD29 : inout bit;
PD3 : inout bit;
PD30 : inout bit;
PD31 : inout bit;
PD4 : inout bit;
PD5 : inout bit;
PD6 : inout bit;
PD7 : inout bit;
PD8 : inout bit;
PD9 : inout bit;
DDR_D : inout bit_vector (0 to 31);
DDR_DQS : inout bit_vector (0 to 3);
DDR_DQSN : inout bit_vector (0 to 3);
DDR_CAS : out bit;
DDR_CKE : out bit;
DDR_CLK : out bit;
DDR_CLKN : out bit;
DDR_CS : out bit;
DDR_RAS : out bit;
DDR_RESETN : out bit;
DDR_WE : out bit;
PD16 : out bit;
DDR_A : out bit_vector (0 to 13);
DDR_BA : out bit_vector (0 to 2);
DDR_DQM : out bit_vector (0 to 3);
-- ADVREFN : linkage bit;
ADVREFP : linkage bit;
CLK_AUDIO : linkage bit;
COMPN : linkage bit;
COMPP : linkage bit;
DDR_CAL : linkage bit;
DDR_VREF : linkage bit; -- DDR_VREFB0 : linkage bit;
-- DDR_VREFB1 : linkage bit;
-- DDR_VREFB2 : linkage bit;
-- DDR_VREFB3 : linkage bit;
-- DDR_VREFCM : linkage bit;
HHSDMA : linkage bit;
HHSDMB : linkage bit;
HHSDMSTRC : linkage bit;
HHSDPA : linkage bit;
HHSDPB : linkage bit;
HHSDPDATC : linkage bit;
JTAGSEL : in bit;
NRST : linkage bit;
RXD : linkage bit;
SDCAL : linkage bit;
SHDN : linkage bit;
TST : in bit;
VBG : linkage bit;
WKUP : linkage bit;
XIN : linkage bit;
XIN32 : linkage bit;
XOUT : linkage bit;
XOUT32 : linkage bit;
-- tst_drst_ana : linkage bit; -- NC Port
-- tst_drst_ddr : linkage bit; -- NC Port
-- tst_drst_iop0 : linkage bit; -- NC Port
-- tst_drst_iop1 : linkage bit; -- NC Port
-- tst_drst_iop2 : linkage bit; -- NC Port
-- tst_drst_isi : linkage bit; -- NC Port
-- tst_drst_osc : linkage bit; -- NC Port
-- tst_drst_sdhc : linkage bit; -- NC Port
-- tst_lft_plla : linkage bit; -- NC Port
-- tst_lft_utmi : linkage bit; -- NC Port
-- tst_por_1v2 : linkage bit; -- NC Port
-- tst_por_1v8 : linkage bit; -- NC Port
-- tst_por_bu : linkage bit; -- NC Port
-- tst_psw_bu : linkage bit; -- NC Port
-- tst_psw_fuse : linkage bit; -- NC Port
PIOBU : linkage bit_vector (0 to 7)
);
use STD_1149_1_1994.all;
attribute COMPONENT_CONFORMANCE of top: entity is "STD_1149_1_1993";
attribute PIN_MAP of top: entity is PHYSICAL_PIN_MAP;
-- This section specifies the pin map for each port. This information is
-- extracted from the port-to-pin map file that was read in using the
-- "read_pin_map" command.
constant BGA289: PIN_MAP_STRING :=
"PD14 : K4," &
"PD15 : K7," &
"PD17 : K2," &
"PD18 : J5," &
"PA0 : U11," &
"PA1 : P10," &
"PA10 : U13," &
"PA11 : P15," &
"PA12 : N15," &
"PA13 : P16," &
"PA14 : M14," &
"PA15 : N16," &
"PA16 : M10," &
"PA17 : N17," &
"PA18 : U14," &
"PA19 : T14," &
"PA2 : T11," &
"PA20 : P12," &
"PA21 : R13," &
"PA22 : U15," &
"PA23 : U16," &
"PA24 : T15," &
"PA25 : U17," &
"PA26 : P13," &
"PA27 : T16," &
"PA28 : R16," &
"PA29 : T17," &
"PA3 : R10," &
"PA30 : R15," &
"PA31 : R17," &
"PA4 : U12," &
"PA5 : T12," &
"PA6 : R12," &
"PA7 : T13," &
"PA8 : N10," &
"PA9 : N11," &
"PB0 : J8," &
"PB1 : A8," &
"PB10 : H8," &
"PB11 : B5," &
"PB12 : D6," &
"PB13 : B4," &
"PB14 : C5," &
"PB15 : H7," &
"PB16 : D5," &
"PB17 : C4," &
"PB18 : A3," &
"PB19 : D4," &
"PB2 : A7," &
"PB20 : B3," &
"PB21 : A2," &
"PB22 : C3," &
"PB23 : A1," &
"PB24 : E5," &
"PB25 : B2," &
"PB26 : E4," &
"PB27 : B1," &
"PB28 : C2," &
"PB29 : D3," &
"PB3 : A6," &
"PB30 : D2," &
"PB31 : C1," &
"PB4 : B6," &
"PB5 : B7," &
"PB6 : C7," &
"PB7 : C6," &
"PB8 : A5," &
"PB9 : A4," &
"PC0 : P17," &
"PC1 : N12," &
"PC10 : E3," &
"PC11 : E2," &
"PC12 : E1," &
"PC13 : F3," &
"PC14 : F5," &
"PC15 : F2," &
"PC16 : G6," &
"PC17 : F1," &
"PC18 : H6," &
"PC19 : G2," &
"PC2 : N14," &
"PC20 : G3," &
"PC21 : G1," &
"PC22 : H2," &
"PC23 : G5," &
"PC24 : H1," &
"PC25 : H5," &
"PC26 : J9," &
"PC27 : H9," &
"PC28 : E8," &
"PC29 : G8," &
"PC3 : M15," &
"PC30 : F8," &
"PC31 : D8," &
"PC4 : M11," &
"PC5 : L10," &
"PC6 : K10," &
"PC7 : M16," &
"PC8 : J10," &
"PC9 : D1," &
"PD0 : G10," &
"PD1 : E10," &
"PD10 : J3," &
"PD11 : M1," &
"PD12 : K8," &
"PD13 : L2," &
"PD19 : K6," &
"PD2 : G9," &
"PD20 : M2," &
"PD21 : N1," &
"PD22 : L4," &
"PD23 : M3," &
"PD24 : L7," &
"PD25 : L6," &
"PD26 : N2," &
"PD27 : L8," &
"PD28 : M4," &
"PD29 : N3," &
"PD3 : K1," &
"PD30 : L9," &
"PD31 : M7," &
"PD4 : J6," &
"PD5 : J4," &
"PD6 : J2," &
"PD7 : J7," &
"PD8 : J1," &
"PD9 : K9," &
"DDR_D : (B12, A12, C12, A13, A14, C13, A15, B15, G17, G16, " &
"H17, K17, K16, J13, K14, K15, B8, B9, C9, A9, A10, D10, B11, A11, " &
"J12, H10, J11, K11, L13, L11, L12, M17)," &
"DDR_DQS : (B13, J17, C10, L17)," &
"DDR_DQSN : (B14, J16, B10, L16)," &
"DDR_CAS : G12," &
"DDR_CKE : F16," &
"DDR_CLK : E17," &
"DDR_CLKN : D17," &
"DDR_CS : G13," &
"DDR_RAS : F13," &
"DDR_RESETN : E16," &
"DDR_WE : F15," &
"PD16 : L1," &
"DDR_A : (F12, C17, B17, B16, C16, G14, F14, F11, C14, D13, " &
"C15, A16, A17, G11)," &
"DDR_BA : (H12, H13, F17)," &
"DDR_DQM : (C11, G15, C8, H11)," &
"ADVREFP : M6," &
"CLK_AUDIO : U3," &
"COMPN : U1," &
"COMPP : T1," &
"DDR_CAL : E13," &
"HHSDMA : R8," &
"HHSDMB : U9," &
"HHSDMSTRC : U10," &
"HHSDPA : T8," &
"HHSDPB : U8," &
"HHSDPDATC : T9," &
"JTAGSEL : T2," &
"NRST : U2," &
"RXD : N4," &
"SDCAL : T10," &
"SHDN : R1," &
"TST : P3," &
"VBG : R6," &
"WKUP : P4," &
"XIN : U7," &
"XIN32 : P1," &
"XOUT : U6," &
"XOUT32 : P2," &
"PIOBU : (R3, N8, R2, R5, R4, P5, P6, M8)";
-- This section specifies the differential IO port groupings.
attribute PORT_GROUPING of top: entity is
"Differential_Voltage ( " &
"(DDR_CLK,DDR_CLKN))";
-- This section specifies the TAP ports. For the TAP TCK port, the parameters in
-- the brackets are:
-- First Field : Maximum TCK frequency.
-- Second Field: Allowable states TCK may be stopped in.
attribute TAP_SCAN_CLOCK of PD14: signal is (10.0e6, BOTH);
attribute TAP_SCAN_IN of PD15: signal is true;
attribute TAP_SCAN_MODE of PD17: signal is true;
attribute TAP_SCAN_OUT of PD16: signal is true;
attribute TAP_SCAN_RESET of PD18: signal is true;
-- Specifies the compliance enable patterns for the design. It lists a set of
-- design ports and the values that they should be set to, in order to enable
-- compliance to IEEE Std 1149.1
attribute COMPLIANCE_PATTERNS of top: entity is
"(JTAGSEL, TST) (10)";
-- Specifies the number of bits in the instruction register.
attribute INSTRUCTION_LENGTH of top: entity is 4;
-- Specifies the boundary-scan instructions implemented in the design and their
-- opcodes.
attribute INSTRUCTION_OPCODE of top: entity is
"BYPASS (1111, 0001, 0101, 0110, 1100, 0111, 1101, 1000, 1001, 1011, " &
"1110)," &
"EXTEST (0000)," &
"SAMPLE (0100)," &
"INTEST (0010)," &
"IDCODE (0011)," &
"RUNBIST (1010)";
-- Specifies the bit pattern that is loaded into the instruction register when
-- the TAP controller passes through the Capture-IR state. The standard mandates
-- that the two LSBs must be "01". The remaining bits are design specific.
attribute INSTRUCTION_CAPTURE of top: entity is "0001";
-- Specifies the bit pattern that is loaded into the DEVICE_ID register during
-- the IDCODE instruction when the TAP controller passes through the Capture-DR
-- state.
attribute IDCODE_REGISTER of top: entity is
"0000" &
-- 4-bit version number
"0101101100111111" &
-- 16-bit part number
"00000011111" &
-- 11-bit identity of the manufacturer
"1";
-- Required by IEEE Std 1149.1
-- This section specifies the test data register placed between TDI and TDO for
-- each implemented instruction.
attribute REGISTER_ACCESS of top: entity is
"BYPASS (BYPASS)," &
"BOUNDARY (EXTEST, SAMPLE, INTEST)," &
"DEVICE_ID (IDCODE)," &
"UTDR1[41] (RUNBIST)";
-- Specifies the length of the boundary scan register.
attribute BOUNDARY_LENGTH of top: entity is 374;
-- The following list specifies the characteristics of each cell in the boundary
-- scan register from TDI to TDO. The following is a description of the label
-- fields:
-- num : Is the cell number.
-- cell : Is the cell type as defined by the standard.
-- port : Is the design port name. Control cells do not have a port
-- name.
-- function: Is the function of the cell as defined by the standard. Is one
-- of input, output2, output3, bidir, control or controlr.
-- safe : Specifies the value that the BSR cell should be loaded with
-- for safe operation when the software might otherwise choose a
-- random value.
-- ccell : The control cell number. Specifies the control cell that
-- drives the output enable for this port.
-- disval : Specifies the value that is loaded into the control cell to
-- disable the output enable for the corresponding port.
-- rslt : Resulting state. Shows the state of the driver when it is
-- disabled.
attribute BOUNDARY_REGISTER of top: entity is
--
-- num cell port function safe [ccell disval rslt]
--
"373 (BC_1, *, control, 1), " &
"372 (BC_7, PD13, bidir, X, 373, 1, Z), " &
"371 (BC_1, *, control, 1), " &
"370 (BC_7, PD12, bidir, X, 371, 1, Z), " &
"369 (BC_1, *, control, 1), " &
"368 (BC_7, PD11, bidir, X, 369, 1, Z), " &
"367 (BC_1, *, control, 1), " &
"366 (BC_7, PD19, bidir, X, 367, 1, Z), " &
"365 (BC_1, *, control, 1), " &
"364 (BC_7, PD20, bidir, X, 365, 1, Z), " &
"363 (BC_1, *, control, 1), " &
"362 (BC_7, PD24, bidir, X, 363, 1, Z), " &
"361 (BC_1, *, control, 1), " &
"360 (BC_7, PD21, bidir, X, 361, 1, Z), " &
"359 (BC_1, *, control, 1), " &
"358 (BC_7, PD25, bidir, X, 359, 1, Z), " &
"357 (BC_1, *, control, 1), " &
"356 (BC_7, PD26, bidir, X, 357, 1, Z), " &
"355 (BC_1, *, control, 1), " &
"354 (BC_7, PD22, bidir, X, 355, 1, Z), " &
"353 (BC_1, *, control, 1), " &
"352 (BC_7, PD27, bidir, X, 353, 1, Z), " &
"351 (BC_1, *, control, 1), " &
"350 (BC_7, PD23, bidir, X, 351, 1, Z), " &
"349 (BC_1, *, control, 1), " &
"348 (BC_7, PD28, bidir, X, 349, 1, Z), " &
"347 (BC_1, *, control, 1), " &
"346 (BC_7, PD30, bidir, X, 347, 1, Z), " &
"345 (BC_1, *, control, 1), " &
"344 (BC_7, PD29, bidir, X, 345, 1, Z), " &
"343 (BC_1, *, control, 1), " &
"342 (BC_7, PD31, bidir, X, 343, 1, Z), " &
"341 (BC_1, *, control, 1), " &
"340 (BC_7, PA0, bidir, X, 341, 1, Z), " &
"339 (BC_1, *, control, 1), " &
"338 (BC_7, PA1, bidir, X, 339, 1, Z), " &
"337 (BC_1, *, control, 1), " &
"336 (BC_7, PA2, bidir, X, 337, 1, Z), " &
"335 (BC_1, *, control, 1), " &
"334 (BC_7, PA3, bidir, X, 335, 1, Z), " &
"333 (BC_1, *, control, 1), " &
"332 (BC_7, PA4, bidir, X, 333, 1, Z), " &
"331 (BC_1, *, control, 1), " &
"330 (BC_7, PA5, bidir, X, 331, 1, Z), " &
"329 (BC_1, *, control, 1), " &
"328 (BC_7, PA6, bidir, X, 329, 1, Z), " &
"327 (BC_1, *, control, 1), " &
"326 (BC_7, PA7, bidir, X, 327, 1, Z), " &
"325 (BC_1, *, control, 1), " &
"324 (BC_7, PA8, bidir, X, 325, 1, Z), " &
"323 (BC_1, *, control, 1), " &
"322 (BC_7, PA9, bidir, X, 323, 1, Z), " &
"321 (BC_1, *, control, 1), " &
"320 (BC_7, PA10, bidir, X, 321, 1, Z), " &
"319 (BC_1, *, control, 1), " &
"318 (BC_7, PA18, bidir, X, 319, 1, Z), " &
"317 (BC_1, *, control, 1), " &
"316 (BC_7, PA20, bidir, X, 317, 1, Z), " &
"315 (BC_1, *, control, 1), " &
"314 (BC_7, PA19, bidir, X, 315, 1, Z), " &
"313 (BC_1, *, control, 1), " &
"312 (BC_7, PA21, bidir, X, 313, 1, Z), " &
"311 (BC_1, *, control, 1), " &
"310 (BC_7, PA22, bidir, X, 311, 1, Z), " &
"309 (BC_1, *, control, 1), " &
"308 (BC_7, PA23, bidir, X, 309, 1, Z), " &
"307 (BC_1, *, control, 1), " &
"306 (BC_7, PA24, bidir, X, 307, 1, Z), " &
"305 (BC_1, *, control, 1), " &
"304 (BC_7, PA25, bidir, X, 305, 1, Z), " &
"303 (BC_1, *, control, 1), " &
"302 (BC_7, PA26, bidir, X, 303, 1, Z), " &
"301 (BC_1, *, control, 1), " &
"300 (BC_7, PA27, bidir, X, 301, 1, Z), " &
"299 (BC_1, *, control, 1), " &
"298 (BC_7, PA28, bidir, X, 299, 1, Z), " &
"297 (BC_1, *, control, 1), " &
"296 (BC_7, PA30, bidir, X, 297, 1, Z), " &
"295 (BC_1, *, control, 1), " &
"294 (BC_7, PA29, bidir, X, 295, 1, Z), " &
"293 (BC_1, *, control, 1), " &
"292 (BC_7, PA31, bidir, X, 293, 1, Z), " &
"291 (BC_1, *, control, 1), " &
"290 (BC_7, PC0, bidir, X, 291, 1, Z), " &
"289 (BC_1, *, control, 1), " &
"288 (BC_7, PA11, bidir, X, 289, 1, Z), " &
"287 (BC_1, *, control, 1), " &
"286 (BC_7, PC1, bidir, X, 287, 1, Z), " &
"285 (BC_1, *, control, 1), " &
"284 (BC_7, PA13, bidir, X, 285, 1, Z), " &
"283 (BC_1, *, control, 1), " &
"282 (BC_7, PA12, bidir, X, 283, 1, Z), " &
"281 (BC_1, *, control, 1), " &
"280 (BC_7, PC2, bidir, X, 281, 1, Z), " &
"279 (BC_1, *, control, 1), " &
"278 (BC_7, PA14, bidir, X, 279, 1, Z), " &
"277 (BC_1, *, control, 1), " &
"276 (BC_7, PA15, bidir, X, 277, 1, Z), " &
"275 (BC_1, *, control, 1), " &
"274 (BC_7, PC3, bidir, X, 275, 1, Z), " &
"273 (BC_1, *, control, 1), " &
"272 (BC_7, PC4, bidir, X, 273, 1, Z), " &
"271 (BC_1, *, control, 1), " &
"270 (BC_7, PA16, bidir, X, 271, 1, Z), " &
"269 (BC_1, *, control, 1), " &
"268 (BC_7, PA17, bidir, X, 269, 1, Z), " &
"267 (BC_1, *, control, 1), " &
"266 (BC_7, PC5, bidir, X, 267, 1, Z), " &
"265 (BC_1, *, control, 1), " &
"264 (BC_7, PC7, bidir, X, 265, 1, Z), " &
"263 (BC_1, *, control, 1), " &
"262 (BC_7, PC6, bidir, X, 263, 1, Z), " &
"261 (BC_1, *, control, 1), " &
"260 (BC_7, PC8, bidir, X, 261, 1, Z), " &
"259 (BC_1, *, control, 1), " &
"258 (BC_7, DDR_D(31), bidir, X, 259, 1, Z), " &
"257 (BC_1, *, control, 1), " &
"256 (BC_7, DDR_D(30), bidir, X, 257, 1, Z), " &
"255 (BC_1, *, control, 1), " &
"254 (BC_7, DDR_D(29), bidir, X, 255, 1, Z), " &
"253 (BC_1, *, control, 1), " &
"252 (BC_7, DDR_D(28), bidir, X, 253, 1, Z), " &
"251 (BC_1, *, control, 1), " &
"250 (BC_7, DDR_DQS(3), bidir, X, 251, 1, Z), " &
"249 (BC_1, *, control, 1), " &
"248 (BC_7, DDR_D(27), bidir, X, 249, 1, Z), " &
"247 (BC_1, *, control, 1), " &
"246 (BC_7, DDR_D(26), bidir, X, 247, 1, Z), " &
"245 (BC_1, *, control, 1), " &
"244 (BC_7, DDR_D(25), bidir, X, 245, 1, Z), " &
"243 (BC_1, *, control, 1), " &
"242 (BC_7, DDR_D(24), bidir, X, 243, 1, Z), " &
"241 (BC_0, *, control, 1), " &
"240 (BC_0, DDR_DQM(3), output3, X, 241, 1, Z), " &
"239 (BC_1, *, control, 1), " &
"238 (BC_7, DDR_D(15), bidir, X, 239, 1, Z), " &
"237 (BC_1, *, control, 1), " &
"236 (BC_7, DDR_D(14), bidir, X, 237, 1, Z), " &
"235 (BC_1, *, control, 1), " &
"234 (BC_7, DDR_D(13), bidir, X, 235, 1, Z), " &
"233 (BC_1, *, control, 1), " &
"232 (BC_7, DDR_D(12), bidir, X, 233, 1, Z), " &
"231 (BC_1, *, control, 1), " &
"230 (BC_7, DDR_DQS(1), bidir, X, 231, 1, Z), " &
"229 (BC_1, *, control, 1), " &
"228 (BC_7, DDR_D(11), bidir, X, 229, 1, Z), " &
"227 (BC_1, *, control, 1), " &
"226 (BC_7, DDR_D(10), bidir, X, 227, 1, Z), " &
"225 (BC_1, *, control, 1), " &
"224 (BC_7, DDR_D(9), bidir, X, 225, 1, Z), " &
"223 (BC_1, *, control, 1), " &
"222 (BC_7, DDR_D(8), bidir, X, 223, 1, Z), " &
"221 (BC_0, *, control, 1), " &
"220 (BC_0, DDR_DQM(1), output3, X, 221, 1, Z), " &
"219 (BC_0, *, control, 1), " &
"218 (BC_0, DDR_BA(2), output3, X, 219, 1, Z), " &
"217 (BC_0, *, control, 1), " &
"216 (BC_0, DDR_BA(1), output3, X, 217, 1, Z), " &
"215 (BC_0, *, control, 1), " &
"214 (BC_0, DDR_BA(0), output3, X, 215, 1, Z), " &
"213 (BC_0, *, control, 1), " &
"212 (BC_0, DDR_CKE, output3, X, 213, 1, Z), " &
"211 (BC_0, *, control, 1), " &
"210 (BC_0, DDR_CS, output3, X, 211, 1, Z), " &
"209 (BC_0, *, control, 1), " &
"208 (BC_0, DDR_A(13), output3, X, 209, 1, Z), " &
"207 (BC_0, *, control, 1), " &
"206 (BC_0, DDR_RESETN, output3, X, 207, 1, Z), " &
"205 (BC_0, *, control, 1), " &
"204 (BC_0, DDR_A(5), output3, X, 205, 1, Z), " &
"203 (BC_0, *, control, 1), " &
"202 (BC_0, DDR_A(6), output3, X, 203, 1, Z), " &
"201 (BC_0, *, control, 1), " &
"200 (BC_0, DDR_RAS, output3, X, 201, 1, Z), " &
"199 (BC_0, *, control, 1), " &
"198 (BC_0, DDR_CAS, output3, X, 199, 1, Z), " &
"197 (BC_0, *, control, 1), " &
"196 (BC_0, DDR_WE, output3, X, 197, 1, Z), " &
"195 (BC_0, *, control, 1), " &
"194 (BC_0, DDR_CLK, output3, X, 195, 1, Z), " &
"193 (BC_0, *, control, 1), " &
"192 (BC_0, DDR_A(0), output3, X, 193, 1, Z), " &
"191 (BC_0, *, control, 1), " &
"190 (BC_0, DDR_A(1), output3, X, 191, 1, Z), " &
"189 (BC_0, *, control, 1), " &
"188 (BC_0, DDR_A(2), output3, X, 189, 1, Z), " &
"187 (BC_0, *, control, 1), " &
"186 (BC_0, DDR_A(3), output3, X, 187, 1, Z), " &
"185 (BC_0, *, control, 1), " &
"184 (BC_0, DDR_A(4), output3, X, 185, 1, Z), " &
"183 (BC_0, *, control, 1), " &
"182 (BC_0, DDR_A(12), output3, X, 183, 1, Z), " &
"181 (BC_0, *, control, 1), " &
"180 (BC_0, DDR_A(11), output3, X, 181, 1, Z), " &
"179 (BC_0, *, control, 1), " &
"178 (BC_0, DDR_A(10), output3, X, 179, 1, Z), " &
"177 (BC_0, *, control, 1), " &
"176 (BC_0, DDR_A(9), output3, X, 177, 1, Z), " &
"175 (BC_0, *, control, 1), " &
"174 (BC_0, DDR_A(8), output3, X, 175, 1, Z), " &
"173 (BC_0, *, control, 1), " &
"172 (BC_0, DDR_A(7), output3, X, 173, 1, Z), " &
"171 (BC_1, *, control, 1), " &
"170 (BC_7, DDR_D(7), bidir, X, 171, 1, Z), " &
"169 (BC_1, *, control, 1), " &
"168 (BC_7, DDR_D(6), bidir, X, 169, 1, Z), " &
"167 (BC_1, *, control, 1), " &
"166 (BC_7, DDR_D(5), bidir, X, 167, 1, Z), " &
"165 (BC_1, *, control, 1), " &
"164 (BC_7, DDR_D(4), bidir, X, 165, 1, Z), " &
"163 (BC_1, *, control, 1), " &
"162 (BC_7, DDR_DQS(0), bidir, X, 163, 1, Z), " &
"161 (BC_1, *, control, 1), " &
"160 (BC_7, DDR_D(3), bidir, X, 161, 1, Z), " &
"159 (BC_1, *, control, 1), " &
"158 (BC_7, DDR_D(2), bidir, X, 159, 1, Z), " &
"157 (BC_1, *, control, 1), " &
"156 (BC_7, DDR_D(1), bidir, X, 157, 1, Z), " &
"155 (BC_1, *, control, 1), " &
"154 (BC_7, DDR_D(0), bidir, X, 155, 1, Z), " &
"153 (BC_0, *, control, 1), " &
"152 (BC_0, DDR_DQM(0), output3, X, 153, 1, Z), " &
"151 (BC_1, *, control, 1), " &
"150 (BC_7, DDR_D(23), bidir, X, 151, 1, Z), " &
"149 (BC_1, *, control, 1), " &
"148 (BC_7, DDR_D(22), bidir, X, 149, 1, Z), " &
"147 (BC_1, *, control, 1), " &
"146 (BC_7, DDR_D(21), bidir, X, 147, 1, Z), " &
"145 (BC_1, *, control, 1), " &
"144 (BC_7, DDR_D(20), bidir, X, 145, 1, Z), " &
"143 (BC_1, *, control, 1), " &
"142 (BC_7, DDR_DQS(2), bidir, X, 143, 1, Z), " &
"141 (BC_1, *, control, 1), " &
"140 (BC_7, DDR_D(19), bidir, X, 141, 1, Z), " &
"139 (BC_1, *, control, 1), " &
"138 (BC_7, DDR_D(18), bidir, X, 139, 1, Z), " &
"137 (BC_1, *, control, 1), " &
"136 (BC_7, DDR_D(17), bidir, X, 137, 1, Z), " &
"135 (BC_1, *, control, 1), " &
"134 (BC_7, DDR_D(16), bidir, X, 135, 1, Z), " &
"133 (BC_0, *, control, 1), " &
"132 (BC_0, DDR_DQM(2), output3, X, 133, 1, Z), " &
"131 (BC_1, *, control, 1), " &
"130 (BC_7, PD0, bidir, X, 131, 1, Z), " &
"129 (BC_1, *, control, 1), " &
"128 (BC_7, PD1, bidir, X, 129, 1, Z), " &
"127 (BC_1, *, control, 1), " &
"126 (BC_7, PD2, bidir, X, 127, 1, Z), " &
"125 (BC_1, *, control, 1), " &
"124 (BC_7, PC26, bidir, X, 125, 1, Z), " &
"123 (BC_1, *, control, 1), " &
"122 (BC_7, PC27, bidir, X, 123, 1, Z), " &
"121 (BC_1, *, control, 1), " &
"120 (BC_7, PC28, bidir, X, 121, 1, Z), " &
"119 (BC_1, *, control, 1), " &
"118 (BC_7, PC29, bidir, X, 119, 1, Z), " &
"117 (BC_1, *, control, 1), " &
"116 (BC_7, PC30, bidir, X, 117, 1, Z), " &
"115 (BC_1, *, control, 1), " &
"114 (BC_7, PC31, bidir, X, 115, 1, Z), " &
"113 (BC_1, *, control, 1), " &
"112 (BC_7, PB0, bidir, X, 113, 1, Z), " &
"111 (BC_1, *, control, 1), " &
"110 (BC_7, PB2, bidir, X, 111, 1, Z), " &
"109 (BC_1, *, control, 1), " &
"108 (BC_7, PB1, bidir, X, 109, 1, Z), " &
"107 (BC_1, *, control, 1), " &
"106 (BC_7, PB3, bidir, X, 107, 1, Z), " &
"105 (BC_1, *, control, 1), " &
"104 (BC_7, PB4, bidir, X, 105, 1, Z), " &
"103 (BC_1, *, control, 1), " &
"102 (BC_7, PB5, bidir, X, 103, 1, Z), " &
"101 (BC_1, *, control, 1), " &
"100 (BC_7, PB6, bidir, X, 101, 1, Z), " &
"99 (BC_1, *, control, 1), " &
"98 (BC_7, PB8, bidir, X, 99, 1, Z), " &
"97 (BC_1, *, control, 1), " &
"96 (BC_7, PB7, bidir, X, 97, 1, Z), " &
"95 (BC_1, *, control, 1), " &
"94 (BC_7, PB10, bidir, X, 95, 1, Z), " &
"93 (BC_1, *, control, 1), " &
"92 (BC_7, PB9, bidir, X, 93, 1, Z), " &
"91 (BC_1, *, control, 1), " &
"90 (BC_7, PB11, bidir, X, 91, 1, Z), " &
"89 (BC_1, *, control, 1), " &
"88 (BC_7, PB12, bidir, X, 89, 1, Z), " &
"87 (BC_1, *, control, 1), " &
"86 (BC_7, PB14, bidir, X, 87, 1, Z), " &
"85 (BC_1, *, control, 1), " &
"84 (BC_7, PB13, bidir, X, 85, 1, Z), " &
"83 (BC_1, *, control, 1), " &
"82 (BC_7, PB15, bidir, X, 83, 1, Z), " &
"81 (BC_1, *, control, 1), " &
"80 (BC_7, PB16, bidir, X, 81, 1, Z), " &
"79 (BC_1, *, control, 1), " &
"78 (BC_7, PB17, bidir, X, 79, 1, Z), " &
"77 (BC_1, *, control, 1), " &
"76 (BC_7, PB19, bidir, X, 77, 1, Z), " &
"75 (BC_1, *, control, 1), " &
"74 (BC_7, PB18, bidir, X, 75, 1, Z), " &
"73 (BC_1, *, control, 1), " &
"72 (BC_7, PB20, bidir, X, 73, 1, Z), " &
"71 (BC_1, *, control, 1), " &
"70 (BC_7, PB21, bidir, X, 71, 1, Z), " &
"69 (BC_1, *, control, 1), " &
"68 (BC_7, PB23, bidir, X, 69, 1, Z), " &
"67 (BC_1, *, control, 1), " &
"66 (BC_7, PB22, bidir, X, 67, 1, Z), " &
"65 (BC_1, *, control, 1), " &
"64 (BC_7, PB25, bidir, X, 65, 1, Z), " &
"63 (BC_1, *, control, 1), " &
"62 (BC_7, PB24, bidir, X, 63, 1, Z), " &
"61 (BC_1, *, control, 1), " &
"60 (BC_7, PB26, bidir, X, 61, 1, Z), " &
"59 (BC_1, *, control, 1), " &
"58 (BC_7, PB28, bidir, X, 59, 1, Z), " &
"57 (BC_1, *, control, 1), " &
"56 (BC_7, PB27, bidir, X, 57, 1, Z), " &
"55 (BC_1, *, control, 1), " &
"54 (BC_7, PB30, bidir, X, 55, 1, Z), " &
"53 (BC_1, *, control, 1), " &
"52 (BC_7, PB29, bidir, X, 53, 1, Z), " &
"51 (BC_1, *, control, 1), " &
"50 (BC_7, PB31, bidir, X, 51, 1, Z), " &
"49 (BC_1, *, control, 1), " &
"48 (BC_7, PC9, bidir, X, 49, 1, Z), " &
"47 (BC_1, *, control, 1), " &
"46 (BC_7, PC11, bidir, X, 47, 1, Z), " &
"45 (BC_1, *, control, 1), " &
"44 (BC_7, PC10, bidir, X, 45, 1, Z), " &
"43 (BC_1, *, control, 1), " &
"42 (BC_7, PC12, bidir, X, 43, 1, Z), " &
"41 (BC_1, *, control, 1), " &
"40 (BC_7, PC13, bidir, X, 41, 1, Z), " &
"39 (BC_1, *, control, 1), " &
"38 (BC_7, PC14, bidir, X, 39, 1, Z), " &
"37 (BC_1, *, control, 1), " &
"36 (BC_7, PC15, bidir, X, 37, 1, Z), " &
"35 (BC_1, *, control, 1), " &
"34 (BC_7, PC17, bidir, X, 35, 1, Z), " &
"33 (BC_1, *, control, 1), " &
"32 (BC_7, PC16, bidir, X, 33, 1, Z), " &
"31 (BC_1, *, control, 1), " &
"30 (BC_7, PC19, bidir, X, 31, 1, Z), " &
"29 (BC_1, *, control, 1), " &
"28 (BC_7, PC18, bidir, X, 29, 1, Z), " &
"27 (BC_1, *, control, 1), " &
"26 (BC_7, PC20, bidir, X, 27, 1, Z), " &
"25 (BC_1, *, control, 1), " &
"24 (BC_7, PC21, bidir, X, 25, 1, Z), " &
"23 (BC_1, *, control, 1), " &
"22 (BC_7, PC22, bidir, X, 23, 1, Z), " &
"21 (BC_1, *, control, 1), " &
"20 (BC_7, PC23, bidir, X, 21, 1, Z), " &
"19 (BC_1, *, control, 1), " &
"18 (BC_7, PC24, bidir, X, 19, 1, Z), " &
"17 (BC_1, *, control, 1), " &
"16 (BC_7, PC25, bidir, X, 17, 1, Z), " &
"15 (BC_1, *, control, 1), " &
"14 (BC_7, PD10, bidir, X, 15, 1, Z), " &
"13 (BC_1, *, control, 1), " &
"12 (BC_7, PD9, bidir, X, 13, 1, Z), " &
"11 (BC_1, *, control, 1), " &
"10 (BC_7, PD8, bidir, X, 11, 1, Z), " &
"9 (BC_1, *, control, 1), " &
"8 (BC_7, PD7, bidir, X, 9, 1, Z), " &
"7 (BC_1, *, control, 1), " &
"6 (BC_7, PD6, bidir, X, 7, 1, Z), " &
"5 (BC_1, *, control, 1), " &
"4 (BC_7, PD5, bidir, X, 5, 1, Z), " &
"3 (BC_1, *, control, 1), " &
"2 (BC_7, PD4, bidir, X, 3, 1, Z), " &
"1 (BC_1, *, control, 1), " &
"0 (BC_7, PD3, bidir, X, 1, 1, Z) ";
end top;

View file

@ -0,0 +1,51 @@
# ----------------------------------------------------------------------------
# SAM Software Package License
# ----------------------------------------------------------------------------
# Copyright (c) 2013, Atmel Corporation
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# - Redistributions of source code must retain the above copyright notice,
# this list of conditions and the disclaimer below.
#
# Atmel's name may not be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# DISCLAIMER: 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
# 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.
# ----------------------------------------------------------------------------
CFLAGS_INC += -I$(TOP)/drivers
lib-y += drivers/drivers.a
drivers-y :=
include $(TOP)/drivers/cortex-a/Makefile.inc
include $(TOP)/drivers/memories/Makefile.inc
include $(TOP)/drivers/misc/Makefile.inc
include $(TOP)/drivers/network/Makefile.inc
include $(TOP)/drivers/peripherals/Makefile.inc
include $(TOP)/drivers/power/Makefile.inc
include $(TOP)/drivers/video/Makefile.inc
include $(TOP)/drivers/usb/Makefile.inc
DRIVERS_OBJS := $(addprefix $(BUILDDIR)/,$(drivers-y))
-include $(DRIVERS_OBJS:.o=.d)
$(BUILDDIR)/drivers/drivers.a: $(DRIVERS_OBJS)
@mkdir -p $(BUILDDIR)/drivers
$(ECHO) AR $@
$(Q)$(AR) -cr $@ $^

View file

@ -0,0 +1,34 @@
# ----------------------------------------------------------------------------
# SAM Software Package License
# ----------------------------------------------------------------------------
# Copyright (c) 2015, Atmel Corporation
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# - Redistributions of source code must retain the above copyright notice,
# this list of conditions and the disclaimer below.
#
# Atmel's name may not be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# DISCLAIMER: 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
# 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.
# ----------------------------------------------------------------------------
drivers-y += drivers/cortex-a/cortexa5_interrupts.o
drivers-y += drivers/cortex-a/cp15.o
drivers-y += drivers/cortex-a/cp15_asm_gcc.o
drivers-y += drivers/cortex-a/cp15_pmu.o
drivers-y += drivers/cortex-a/cpsr_gcc.o
drivers-y += drivers/cortex-a/mmu.o

View file

@ -0,0 +1,194 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* Provides the low-level initialization function that called on chip startup.
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include "compiler.h"
#include "peripherals/aic.h"
#include "cortexa5_interrupts.h"
#include <stdio.h>
/*----------------------------------------------------------------------------
* Constants
*----------------------------------------------------------------------------*/
/* IFSR status */
static const char* _prefetch_abort_status[32] = {
NULL,
NULL,
"debug event",
"access flag fault, section",
NULL,
"translation fault, section",
"access flag fault, page",
"translation fault, page",
"synchronous external abort",
"domain fault, section",
NULL,
"domain fault, page",
"L1 translation, synchronous external abort",
"permission fault, section",
"L2 translation, synchronous external abort",
"permission fault, page",
};
/* DFSR status */
static const char* _data_abort_status[32] = {
NULL,
"alignment fault",
"debug event",
"access flag fault, section",
"instruction cache maintenance fault",
"translation fault, section",
"access flag fault, page",
"translation fault, page",
"synchronous external abort, nontranslation",
"domain fault, section",
NULL,
"domain fault, page",
"1st level translation, synchronous external abort",
"permission fault, section",
"2nd level translation, synchronous external abort",
"permission fault, page",
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"asynchronous external abort"
};
/*----------------------------------------------------------------------------
* Functions Prototypes
*----------------------------------------------------------------------------*/
void default_undefined_instruction_irq_handler(void);
void default_software_interrupt_irq_handler(void);
void default_data_abort_irq_handler(void);
void default_prefetch_abort_irq_handler(void);
#pragma weak undefined_instruction_irq_handler=default_undefined_instruction_irq_handler
#pragma weak software_interrupt_irq_handler=default_software_interrupt_irq_handler
#pragma weak data_abort_irq_handler=default_data_abort_irq_handler
#pragma weak prefetch_abort_irq_handler=default_prefetch_abort_irq_handler
/*----------------------------------------------------------------------------
* Functions
*----------------------------------------------------------------------------*/
/**
* \brief Default handler for "Undefined Instruction" exception
*/
void default_undefined_instruction_irq_handler(void)
{
printf("\n\r");
printf("#####################\n\r");
printf("Undefined Instruction\n\r");
printf("#####################\n\r");
asm("bkpt #0");
while(1);
}
/**
* \brief Default handler for "Software Interrupt" exception
*/
void default_software_interrupt_irq_handler(void)
{
printf("\n\r");
printf("##################\n\r");
printf("Software Interrupt\n\r");
printf("##################\n\r");
asm("bkpt #0");
while(1);
}
/**
* \brief Default handler for "Data Abort" exception
*/
void default_data_abort_irq_handler(void)
{
uint32_t v1, v2, dfsr;
asm("mrc p15, 0, %0, c5, c0, 0" : "=r"(v1));
asm("mrc p15, 0, %0, c6, c0, 0" : "=r"(v2));
printf("\n\r");
printf("####################\n\r");
dfsr = ((v1 >> 4) & 0x0F);
printf("Data Fault occured in %x domain\n\r", (unsigned int)dfsr);
dfsr = (((v1 & 0x400) >> 6) | (v1 & 0x0F));
if (_data_abort_status[dfsr])
printf("Data Fault reason is: %s\n\r", _data_abort_status[dfsr]);
else
printf("Data Fault reason is unknown\n\r");
printf("Data Fault occured at address: 0x%08x\n\n\r", (unsigned int)v2);
printf("Data Fault status register value: 0x%x\n\r", (unsigned int)v1);
printf("####################\n\r");
asm("bkpt #0");
while(1);
}
/**
* \brief Default handler for "Prefetch Abort" exception
*/
void default_prefetch_abort_irq_handler(void)
{
uint32_t v1, v2, ifsr;
asm("mrc p15, 0, %0, c5, c0, 1" : "=r"(v1));
asm("mrc p15, 0, %0, c6, c0, 2" : "=r"(v2));
printf("\n\r");
printf("####################\n\r");
ifsr = (((v1 & 0x400) >> 6) | (v1 & 0x0F));
if (_prefetch_abort_status[ifsr])
printf("Prefetch Fault reason is: %s\n\r", _prefetch_abort_status[ifsr]);
else
printf("Prefetch Fault reason is unknown\n\r");
printf("prefetch Fault occured at address: 0x%08x\n\n\r", (unsigned int)v2);
printf("Prefetch Fault status register value: 0x%x\n\r", (unsigned int)v1);
printf("####################\n\r");
asm("bkpt #0");
while(1);
}

View file

@ -0,0 +1,49 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* Cortex-A5 core interrupt handlers
*
*/
#ifndef INTERRUPTS_CORTEXA5_H
#define INTERRUPTS_CORTEXA5_H
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
extern WEAK void undefined_instruction_irq_handler(void);
extern WEAK void software_interrupt_irq_handler(void);
extern WEAK void prefetch_abort_irq_handler(void);
extern WEAK void data_abort_irq_handler(void);
#endif /* INTERRUPTS_CORTEXA5_H */

View file

@ -0,0 +1,350 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
//-----------------------------------------------------------------------------
// Reg Reads Writes
//----------------------------------------------------------------------------
// 0 ID code Unpredictable
// 0 cache type Unpredictable
// 0 TCM status Unpredictable
// 1 Control Control
// 2 Translation table base Translation table base
// 3 Domain access control Domain access control
// 4 (Reserved)
// 5 Data fault status Data fault status
// 5 Instruction fault status Instruction fault status
// 6 Fault address Fault address
// 7 cache operations cache operations
// 8 Unpredictable TLB operations
// 9 cache lockdown cache lockdown
// 9 TCM region TCM region
// 10 TLB lockdown TLB lockdown
// 11 (Reserved)
// 12 (Reserved)
// 13 FCSE PID FCSE PID
// 13 Context ID Context ID
// 14 (Reserved)
// 15 Test configuration Test configuration
//-----------------------------------------------------------------------------
/** \page cp15_f CP15 Functions
*
* \section CP15 function Usage
*
* Methods to manage the Coprocessor 15. Coprocessor 15, or System Control
* Coprocessor CP15, is used to configure and control all the items in the
* list below:
* <ul>
* <li> ARM core
* <li> caches (Icache, Dcache and write buffer)
* <li> TCM
* <li> MMU
* <li> Other system options
* </ul>
* \section Usage
*
* -# Enable or disable D cache with cp15_enable_dcache() and cp15_disable_dcache()
* -# Enable or disable I cache with cp15_enable_icache() and cp15_disable_icache()
*
* Related files:\n
* \ref cp15.h\n
* \ref cp15.c\n
*/
/** \file */
/**
* \addtogroup cp15_cache L1 Cache Operations
* \ingroup cache_module
*
* \section Usage
*
* They are performed as MCR instructions and only operate on a level 1 cache associated with
* ATM v7 processor.
* The supported operations are:
* <ul>
* <li> Any of these operations can be applied to
* -# any data cache
* -# any unified cache.
* <li> Invalidate by MVA
* Performs an invalidate of a data or unified cache line based on the address it contains.
* <li> Invalidate by set/way
* Performs an invalidate of a data or unified cache line based on its location in the cache hierarchy.
* <li> Clean by MVA
* Performs a clean of a data or unified cache line based on the address it contains.
* <li> Clean by set/way
* Performs a clean of a data or unified cache line based on its location in the cache hierarchy.
* <li> Clean and Invalidate by MVA
* Performs a clean and invalidate of a data or unified cache line based on the address it contains.
* <li> Clean and Invalidate by set/way
* Performs a clean and invalidate of a data or unified cache line based on its location in the cache hierarchy.
* </ul>
*
* Related files:\n
* \ref cp15.h\n
* \ref cp15_asm_gcc.S \n
* \ref cp15_asm_iar.s \n
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#if defined(__ICCARM__)
#include <intrinsics.h>
#endif
#include "cortex-a/cp15.h"
#include "trace.h"
#include <assert.h>
/*----------------------------------------------------------------------------
* Global functions
*----------------------------------------------------------------------------*/
/**
* \brief Check Instruction cache
* \return 0 if I_cache disable, 1 if I_cache enable
*/
unsigned int cp15_is_icached_enabled(void)
{
unsigned int control;
control = cp15_read_control();
return ((control & (1 << CP15_I_BIT)) != 0);
}
/**
* \brief Enable Instruction cache
*/
void cp15_enable_icache(void)
{
unsigned int control;
control = cp15_read_control();
// Check if cache is disabled
if ((control & (1 << CP15_I_BIT)) == 0) {
cp15_icache_invalidate();
control |= (1 << CP15_I_BIT);
cp15_write_control(control);
trace_info("I cache enabled.\n\r");
} else {
trace_info("I cache is already enabled.\n\r");
}
}
/**
* \brief Disable Instruction cache
*/
void cp15_disable_icache(void)
{
unsigned int control;
control = cp15_read_control();
// Check if cache is enabled
if ((control & (1 << CP15_I_BIT)) != 0) {
control &= ~(1ul << CP15_I_BIT);
cp15_write_control(control);
trace_info("I cache disabled.\n\r");
} else {
trace_info("I cache is already disabled.\n\r");
}
}
/**
* \brief Check MMU
* \return 0 if MMU disable, 1 if MMU enable
*/
unsigned int cp15_is_mmu_enabled(void)
{
unsigned int control;
control = cp15_read_control();
return ((control & (1 << CP15_M_BIT)) != 0);
}
/**
* \brief Enable MMU
*/
void cp15_enable_mmu(void)
{
unsigned int control;
control = cp15_read_control();
// Check if MMU is disabled
if ((control & (1 << CP15_M_BIT)) == 0) {
control |= (1 << CP15_M_BIT);
cp15_write_control(control);
trace_info("MMU enabled.\n\r");
} else {
trace_info("MMU is already enabled.\n\r");
}
}
/**
* \brief Disable MMU
*/
void cp15_disable_mmu(void)
{
unsigned int control;
control = cp15_read_control();
// Check if MMU is enabled
if ((control & (1 << CP15_M_BIT)) != 0) {
control &= ~(1ul << CP15_M_BIT);
control &= ~(1ul << CP15_C_BIT);
cp15_write_control(control);
trace_info("MMU disabled.\n\r");
} else {
trace_info("MMU is already disabled.\n\r");
}
}
/**
* \brief Check D_cache
* \return 0 if D_cache disable, 1 if D_cache enable (with MMU of course)
*/
unsigned int cp15_is_dcache_enabled(void)
{
unsigned int control;
control = cp15_read_control();
return ((control & ((1 << CP15_C_BIT) || (1 << CP15_M_BIT))) != 0);
}
/**
* \brief Enable Data cache
*/
void cp15_enable_dcache(void)
{
unsigned int control;
control = cp15_read_control();
if (!cp15_is_mmu_enabled()) {
trace_error("Do nothing: MMU not enabled\n\r");
} else {
// Check if cache is disabled
if ((control & (1 << CP15_C_BIT)) == 0) {
cp15_dcache_invalidate();
control |= (1 << CP15_C_BIT);
cp15_write_control(control);
trace_info("D cache enabled.\n\r");
} else {
trace_info("D cache is already enabled.\n\r");
}
}
}
/**
* \brief Disable Data cache
*/
void cp15_disable_dcache(void)
{
unsigned int control;
control = cp15_read_control();
// Check if cache is enabled
if ((control & (1 << CP15_C_BIT)) != 0) {
control &= ~(1ul << CP15_C_BIT);
cp15_write_control(control);
trace_info("D cache disabled.\n\r");
} else {
trace_info("D cache is already disabled.\n\r");
}
}
/**
* \brief Clean Data cache
*/
void cp15_dcache_clean(void)
{
cp15_select_dcache();
cp15_clean_dcache_by_set_way();
asm("DSB");
}
/**
* \brief Invalidate Icache
*/
void cp15_icache_invalidate(void)
{
cp15_select_icache();
cp15_invalid_icache_inner_sharable();
asm ("ISB");
}
/**
* \brief Invalidate Dcache
*/
void cp15_dcache_invalidate(void)
{
cp15_select_dcache();
cp15_invalid_dcache_by_set_way();
asm ("DSB");
}
/**
* \brief Flush(Clean and invalidate) Data cache
*/
void cp15_dcache_flush(void)
{
cp15_select_dcache();
cp15_clean_invalid_dcache_by_set_way();
asm("DSB");
}
/**
* \brief Invalidate Data cache by address
*/
void cp15_invalid_dcache_by_va(uint32_t S_Add, uint32_t E_Add)
{
cp15_select_dcache();
cp15_invalid_dcache_by_mva(S_Add, E_Add);
}
/**
* \brief Clean Data cache by address
*/
void cp15_clean_dcache_by_va(uint32_t S_Add, uint32_t E_Add)
{
cp15_select_dcache();
cp15_clean_dcache_by_mva(S_Add, E_Add);
}
/**
* \brief Flush Data cache by address
*/
void cp15_flush_dcache_by_va(uint32_t S_Add, uint32_t E_Add)
{
cp15_select_dcache();
cp15_clean_invalid_dcache_by_mva(S_Add, E_Add);
}

View file

@ -0,0 +1,318 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
#ifndef _CP15_H
#define _CP15_H
#include <stdint.h>
/*----------------------------------------------------------------------------
* Definition
*----------------------------------------------------------------------------*/
#define CP15_L4_BIT 15 // Determines if the T bit is set when load instructions
// change the PC:
// 0 = loads to PC set the T bit
// 1 = loads to PC do not set T bit
#define CP15_RR_BIT 14 // RR bit Replacement strategy for Icache and Dcache:
// 0 = Random replacement
// 1 = Round-robin replacement.
#define CP15_V_BIT 13 // V bit Location of exception vectors:
// 0 = Normal exception vectors selected address range = 0x0000 0000 to 0x0000 001C
// 1 = High exception vect selected, address range = 0xFFFF 0000 to 0xFFFF 001C
#define CP15_I_BIT 12 // I bit Icache enable/disable:
// 0 = Icache disabled
// 1 = Icache enabled
#define CP15_R_BIT 9 // R bit ROM protection
#define CP15_S_BIT 8 // S bit System protection
#define CP15_B_BIT 7 // B bit Endianness:
// 0 = Little-endian operation
// 1 = Big-endian operation.
#define CP15_C_BIT 2 // C bit Dcache enable/disable:
// 0 = cache disabled
// 1 = cache enabled
#define CP15_A_BIT 1 // A bit Alignment fault enable/disable:
// 0 = Data address alignment fault checking disabled
// 1 = Data address alignment fault checking enabled
#define CP15_M_BIT 0 // M bit MMU enable/disable: 0 = disabled 1 = enabled.
// 0 = disabled
// 1 = enabled
/** No access Any access generates a domain fault. */
#define CP15_DOMAIN_NO_ACCESS 0x00
/** Client Accesses are checked against the access permission bits in the section or page descriptor. */
#define CP15_DOMAIN_CLIENT_ACCESS 0x01
/** Manager Accesses are not checked against the access permission bits so a permission fault cannot be generated. */
#define CP15_DOMAIN_MANAGER_ACCESS 0x03
#define CP15_ICache 1
#define CP15_DCache 0
#define CP15_PMCNTENSET_ENABLE 31
#define CP15_PMCR_DIVIDER 3
#define CP15_PMCR_RESET 2
#define CP15_PMCR_ENABLE 0
/*------------------------------------------------------------------------------ */
/* Exported functions */
/*------------------------------------------------------------------------------ */
/**
* \brief Read the Main ID Register (MIDR).
* \return register contents
*/
extern unsigned int cp15_read_id(void);
/**
* \brief Read the System Control Register (SCTLR).
* \return register contents
*/
extern unsigned int cp15_read_control(void);
/**
* \brief Indicate CPU that L2 is in exclusive caching mode.
*/
extern void cp15_exclusive_cache(void);
/**
* \brief Allow data to reside in the L1 and L2 caches at the same time.
*/
extern void cp15_non_exclusive_cache(void);
/**
* \brief Instruction Synchronization Barrier operation.
*/
extern void cp15_isb(void);
/**
* \brief Data Synchronization Barrier operation.
*/
extern void cp15_dsb(void);
/**
* \brief Data Memory Barrier operation.
*/
extern void cp15_dmb(void);
/**
* \brief Invalidate unified Translation Lookaside Buffer.
*/
extern void cp15_invalidate_tlb(void);
/**
* \brief Select the data cache as the one to later retrieve architecture
* information about.
*/
extern void cp15_select_dcache(void);
/**
* \brief Select the instruction cache as the one to later retrieve architecture
* information about.
*/
extern void cp15_select_icache(void);
/**
* \brief Modify the System Control Register (SCTLR).
* This register specifies the configuration used to enable and disable the
* caches and MMU.
* It is recommended that you access this register using a read-modify-
* write sequence.
* \param value new value for SCTLR
*/
extern void cp15_write_control(unsigned int value);
/**
* \brief ARMv7A architecture supports two translation tables.
* Configure translation table base (TTB) control register 0.
* \param value address of our page table base
*/
extern void cp15_write_ttb(unsigned int value);
/**
* \brief Modify the Domain Access Control Register (DACR).
* \param value new value for DACR
*/
extern void cp15_write_domain_access_control(unsigned int value);
/**
* \brief Invalidate I cache predictor array to point of unification Inner
* Shareable.
*/
extern void cp15_invalid_icache_inner_sharable(void);
/**
* \brief Invalidate entire branch predictor array Inner Shareable
*/
extern void cp15_invalid_btb_inner_sharable(void);
/**
* \brief Invalidate all instruction caches to point of unification.
* Also flush branch target cache.
*/
extern void cp15_invalid_icache(void);
/**
* \brief Invalidate instruction caches by virtual address to point of
* unification.
*/
extern void cp15_invalid_icache_by_mva(void);
/**
* \brief Invalidate entire branch predictor array.
*/
extern void cp15_invalid_btb(void);
/**
* \brief Invalidate branch predictor array entry by modified virtual address.
* \param addr virtual address
*/
extern void cp15_invalid_btb_by_mva(uint32_t addr);
/**
* \brief Invalidate entire data cache by set/way.
* Should be called further to cp15_select_dcache(), not
* cp15_select_icache().
*/
extern void cp15_invalid_dcache_by_set_way(void);
/**
* \brief Clean entire data cache by set/way.
* Should be called further to cp15_select_dcache(), not
* cp15_select_icache().
*/
extern void cp15_clean_dcache_by_set_way(void);
/**
* \brief Clean and invalidate entire data cache by set/way
* Should be called further to cp15_select_dcache(), not
* cp15_select_icache().
*/
extern void cp15_clean_invalid_dcache_by_set_way(void);
/**
* \brief Invalidate data cache by virtual address to point of coherency.
* \param start virtual start address of region
* \param end virtual end address of region
*/
extern void cp15_invalid_dcache_by_mva(uint32_t start, uint32_t end);
/**
* \brief Clean data cache by modified virtual address to point of coherency.
* \param start virtual start address of region
* \param end virtual end address of region
*/
extern void cp15_clean_dcache_by_mva(uint32_t start, uint32_t end);
/**
* \brief Clean and invalidate data cache by virtual address to point of
* coherency.
* \param start virtual start address of region
* \param end virtual end address of region
*/
extern void cp15_clean_invalid_dcache_by_mva(uint32_t start, uint32_t end);
/**
* \brief Clean unified cache by modified virtual address to point of
* unification.
*/
extern void cp15_clean_dcache_umva(void);
/**
* \brief Ensure that the I and D caches are coherent within the specified
* region. This is typically used when code has been written to
* a memory region, and will be executed.
* \param start virtual start address of region
* \param end virtual end address of region
*/
extern void cp15_coherent_dcache_for_dma(uint32_t start, uint32_t end);
/**
* \brief Invalidate the data cache within the specified region; we will
* be performing a DMA operation in this region and we want to purge the
* cache of old data. Cache data will be discarded, not flushed.
* The specified region should be aligned on cache lines. Otherwise mind
* the data loss that may occur in the collateral part of start/end lines,
* since cache data won't be flushed.
* \param start virtual start address of region
* \param end virtual end address of region
*/
extern void cp15_invalidate_dcache_for_dma(uint32_t start, uint32_t end);
/**
* \brief Clean the data cache within the specified region.
* \param start virtual start address of region
* \param end virtual end address of region
*/
extern void cp15_clean_dcache_for_dma(uint32_t start, uint32_t end);
/**
* \brief Flush, i.e. clean and invalidate, the data cache within the specified
* region.
* \param start virtual start address of region
* \param end virtual end address of region
*/
extern void cp15_flush_dcache_for_dma(uint32_t start, uint32_t end);
/*------------------------------------------------------------------------------ */
/* Exported functions from CP15.c */
/*------------------------------------------------------------------------------ */
/** MMU (Status/Enable/Disable) */
extern unsigned int cp15_is_mmu_enabled(void);
extern void cp15_enable_mmu(void);
extern void cp15_disable_mmu(void);
/** I cache (Status/Enable/Disable) */
extern unsigned int cp15_is_icached_enabled(void);
extern void cp15_enable_icache(void);
extern void cp15_disable_icache(void);
/** D cache (Status/Enable/Disable) */
extern unsigned int cp15_is_dcache_enabled(void);
extern void cp15_enable_dcache(void);
extern void cp15_disable_dcache(void);
extern void cp15_dcache_clean(void);
extern void cp15_dcache_invalidate(void);
extern void cp15_icache_invalidate(void);
extern void cp15_dcache_flush(void);
extern void cp15_invalid_dcache_by_va(uint32_t S_Add, uint32_t E_Add);
extern void cp15_clean_dcache_by_va(uint32_t S_Add, uint32_t E_Add);
extern void cp15_flush_dcache_by_va(uint32_t S_Add, uint32_t E_Add);
#endif // #ifndef _CP15_H

View file

@ -0,0 +1,412 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/** \file */
/*----------------------------------------------------------------------------
* Functions to access CP15 coprocessor register
*----------------------------------------------------------------------------*/
.section .text.cp15_read_id
.global cp15_read_id
cp15_read_id:
mov r0, #0
mrc p15, 0, r0, c0, c0, 0 // read MIDR
bx lr
.section .text.cp15_isb
.global cp15_isb
cp15_isb:
mov r0, #0
mcr p15, 0, r0, c7, c5, 4 // CP15ISB()
nop
bx lr
.section .text.cp15_dsb
.global cp15_dsb
cp15_dsb:
mov r0, #0
mcr p15, 0, r0, c7, c10, 4 // CP15DSB()
nop
bx lr
.section .text.cp15_dmb
.global cp15_dmb
cp15_dmb:
mov r0, #0
mcr p15, 0, r0, c7, c10, 5 // CP15DMB
nop
bx lr
.section .text.cp15_invalidate_tlb
.global cp15_invalidate_tlb
cp15_invalidate_tlb:
mov r0, #0
mcr p15, 0, r0, c8, c7, 0 // TLBIALL()
dsb
bx lr
.section .text.cp15_exclusive_cache
.global cp15_exclusive_cache
cp15_exclusive_cache:
mov r0, #0
mrc p15, 0, r0, c1, c0, 1 // Read ACTLR
orr r0, r0, #0x00000080 // Set EXCL
mcr p15, 0, r0, c1, c0, 1 // Write ACTLR
nop
bx lr
.section .text.cp15_non_exclusive_cache
.global cp15_non_exclusive_cache
cp15_non_exclusive_cache:
mov r0, #0
mrc p15, 0, r0, c1, c0, 1 // Read ACTLR
bic r0, r0, #0x00000080 // Clear EXCL
mcr p15, 0, r0, c1, c0, 1 // Write ACTLR
nop
bx lr
.section .text.cp15_select_icache
.global cp15_select_icache
cp15_select_icache:
mrc p15, 2, r0, c0, c0, 0 // Read CSSELR
orr r0, r0, #0x1 // Set InD: cache type = ICache
mcr p15, 2, r0, c0, c0, 0 // Write CSSELR
nop
bx lr
.section .text.cp15_select_dcache
.global cp15_select_dcache
cp15_select_dcache:
mrc p15, 2, r0, c0, c0, 0 // Read CSSELR
and r0, r0, #0xFFFFFFFE // Clear InD: cache type = DCache
mcr p15, 2, r0, c0, c0, 0 // Write CSSELR
nop
bx lr
.section .text.cp15_read_control
.global cp15_read_control
cp15_read_control:
mov r0, #0
mrc p15, 0, r0, c1, c0, 0 // read SCTLR
bx lr
.section .text.cp15_write_control
.global cp15_write_control
cp15_write_control:
mcr p15, 0, r0, c1, c0, 0 // rewrite SCTLR
nop
nop
nop
nop
nop
nop
nop
nop
bx lr
.section .text.cp15_write_domain_access_control
.global cp15_write_domain_access_control
cp15_write_domain_access_control:
mcr p15, 0, r0, c3, c0, 0 // rewrite DACR
nop
nop
nop
nop
nop
nop
nop
nop
bx lr
.section .text.cp15_write_ttb
.global cp15_write_ttb
cp15_write_ttb:
mcr p15, 0, r0, c2, c0, 0 // rewrite TTBR0
nop
nop
nop
nop
nop
nop
nop
nop
bx lr
.section .text.cp15_invalid_icache_inner_sharable
.global cp15_invalid_icache_inner_sharable
cp15_invalid_icache_inner_sharable:
mov r0, #0
mcr p15, 0, r0, c7, c1, 0 // ICIALLUIS()
bx lr
.section .text.cp15_invalid_btb_inner_sharable
.global cp15_invalid_btb_inner_sharable
cp15_invalid_btb_inner_sharable:
mov r0, #0
mcr p15, 0, r0, c7, c1, 6 // BPIALLIS()
bx lr
.section .text.cp15_invalid_icache
.global cp15_invalid_icache
cp15_invalid_icache:
mov r0, #0
mcr p15, 0, r0, c7, c5, 0 // ICIALLU()
bx lr
.section .text.cp15_invalid_icache_by_mva
.global cp15_invalid_icache_by_mva
cp15_invalid_icache_by_mva:
mov r0, #0
mcr p15, 0, r0, c7, c5, 1 // ICIMVAU()
bx lr
.section .text.cp15_invalid_btb
.global cp15_invalid_btb
cp15_invalid_btb:
mov r0, #0
mcr p15, 0, r0, c7, c5, 6 // BPIALL()
bx lr
.section .text.cp15_invalid_btb_by_mva
.global cp15_invalid_btb_by_mva
cp15_invalid_btb_by_mva:
mcr p15, 0, r0, c7, c5, 7 // BPIMVA()
bx lr
/***********************************************************
* Data Cache related maintenance functions
***********************************************************/
.section .text.cp15_invalid_dcache_by_set_way
.global cp15_invalid_dcache_by_set_way
cp15_invalid_dcache_by_set_way:
push {r1-r4}
mrc p15, 1, r0, c0, c0, 0 // Read CCSIDR
mov r1, r0, lsr #3 // Get Associativity (num of ways)
and r1, r1, #3 // 3 is specific to CortexA5 with 32 KB
mov r2, r0, lsr #13 // Get NumSets (num of sets)
and r2, r2, #0xFF // 8bit is specific to CortexA5 with 32 KB
mov r0, #0 // 0:SHL:5
1:
lsl r4, r1, #30
mov r3, r2
2:
orr r0, r4, r3, lsl #5
mcr p15, 0, r0, c7, c6, 2 // DCISW()
subs r3, r3, #1 // 1:SHL:30
bpl 2b
subs r1, r1, #1
bpl 1b
dsb
pop {r1-r4}
bx lr
.section .text.cp15_clean_dcache_by_set_way
.global cp15_clean_dcache_by_set_way
cp15_clean_dcache_by_set_way:
push {r1-r4}
mrc p15, 1, r0, c0, c0, 0 // Read CCSIDR
mov r1, r0, lsr #3 // Get Associativity (num of ways)
and r1, r1, #3 // 3 is specific to CortexA5 with 32 KB
mov r2, r0, lsr #13 // Get NumSets (num of sets)
and r2, r2, #0xFF // 8bit is specific to CortexA5 with 32 KB
mov r0, #0 // 0:SHL:5
1:
lsl r4, r1, #30
mov r3, r2
2:
orr r0, r4, r3, lsl #5
mcr p15, 0, r0, c7, c10, 2 // DCCSW()
subs r3, r3, #1 // 1:SHL:30
bpl 2b
subs r1, r1, #1
bpl 1b
dsb
pop {r1-r4}
bx lr
.section .text.cp15_clean_invalid_dcache_by_set_way
.global cp15_clean_invalid_dcache_by_set_way
cp15_clean_invalid_dcache_by_set_way:
push {r1-r4}
mrc p15, 1, r0, c0, c0, 0 // Read CCSIDR
mov r1, r0, lsr #3 // Get Associativity (num of ways)
and r1, r1, #3 // 3 is specific to CortexA5 with 32 KB
mov r2, r0, lsr #13 // Get NumSets (num of sets)
and r2, r2, #0xFF // 8bit is specific to CortexA5 with 32 KB
mov r0, #0 // 0:SHL:5
1:
lsl r4, r1, #30
mov r3, r2
2:
orr r0, r4, r3, lsl #5
mcr p15, 0, r0, c7, c14, 2 // DCCISW()
subs r3, r3, #1 // 1:SHL:30
bpl 2b
subs r1, r1, #1
bpl 1b
dsb
pop {r1-r4}
bx lr
.section .text.cp15_invalid_dcache_by_mva
.global cp15_invalid_dcache_by_mva
cp15_invalid_dcache_by_mva:
mov r2, #0x20 // Eight words per line, Cortex-A5 L1 Line Size 32 Bytes
mov r3, r0
inv_loop:
mcr p15, 0, r0, c7, c6, 1 // DCIMVAC()
add r3, r3, r2
cmp r3, r1
bls inv_loop
bx lr
.section .text.cp15_clean_dcache_by_mva
.global cp15_clean_dcache_by_mva
cp15_clean_dcache_by_mva:
mov r2, #0x20 // Eight words per line, Cortex-A5 L1 Line Size 32 Bytes
mov r3, r0
clean_loop:
mcr p15, 0, r0, c7, c10, 1 // DCCMVAC()
add r3, r3, r2
cmp r3, r1
bls clean_loop
bx lr
.section .text.cp15_clean_dcache_umva
.global cp15_clean_dcache_umva
cp15_clean_dcache_umva:
mov r0, #0
mcr p15, 0, r0, c7, c11, 1 // DCCMVAU()
bx lr
.section .text.cp15_clean_invalid_dcache_by_mva
.global cp15_clean_invalid_dcache_by_mva
cp15_clean_invalid_dcache_by_mva:
mov r2, #0x20 // Eight words per line, Cortex-A5 L1 Line Size 32 Bytes
mov r3, r0
clinv_loop:
mcr p15, 0, r0, c7, c14, 1 // DCCIMVAC()
add r3, r3, r2
cmp r3, r1
bls clinv_loop
bx lr
.section .text.cp15_coherent_dcache_for_dma
.global cp15_coherent_dcache_for_dma
cp15_coherent_dcache_for_dma:
push {r2-r4}
mrc p15, 0, r3, c0, c0, 1 // read Cache Type Register
lsr r3, r3, #16
and r3, r3, #0xf // DminLine
mov r2, #4
mov r2, r2, lsl r3 // cache line size, in bytes (4*2^DminLine)
sub r3, r2, #1 // cache line mask
bic r4, r0, r3 // address of the first cache line
1:
mcr p15, 0, r4, c7, c11, 1 // DCCMVAU()
add r4, r4, r2
cmp r4, r1
blo 1b
dsb
bic r4, r0, r3
2:
mcr p15, 0, r4, c7, c5, 1 // ICIMVAU()
add r4, r4, r2
cmp r4, r1
blo 2b
mov r0, #0
mcr p15, 0, r0, c7, c1, 6 // BPIALLIS()
mcr p15, 0, r0, c7, c5, 6 // BPIALL()
dsb
isb
pop {r2-r4}
bx lr
.section .text.cp15_invalidate_dcache_for_dma
.global cp15_invalidate_dcache_for_dma
cp15_invalidate_dcache_for_dma:
push {r2-r3}
mrc p15, 0, r3, c0, c0, 1 // read CP15 Cache Type Register
lsr r3, r3, #16
and r3, r3, #0xf // DminLine
mov r2, #4
mov r2, r2, lsl r3 // cache line size, in bytes (4*2^DminLine)
sub r3, r2, #1 // cache line mask
bic r0, r0, r3 // address of the first cache line
3:
mcr p15, 0, r0, c7, c6, 1 // CP15:DCIMVAC(r0)
add r0, r0, r2
cmp r0, r1 // while ('cache line address' < 'end')
blo 3b
dsb
pop {r2-r3}
bx lr
.section .text.cp15_clean_dcache_for_dma
.global cp15_clean_dcache_for_dma
cp15_clean_dcache_for_dma:
mrc p15, 0, r3, c0, c0, 1 // read Cache Type Register
lsr r3, r3, #16
and r3, r3, #0xf // DminLine
mov r2, #4
mov r2, r2, lsl r3 // cache line size, in bytes (4*2^DminLine)
sub r3, r2, #1 // cache line mask
bic r0, r0, r3 // address of the first cache line
4:
mcr p15, 0, r0, c7, c10, 1 // DCCMVAC()
add r0, r0, r2
cmp r0, r1
blo 4b
dsb
bx lr
.section .text.cp15_flush_dcache_for_dma
.global cp15_flush_dcache_for_dma
cp15_flush_dcache_for_dma:
mrc p15, 0, r3, c0, c0, 1 // read Cache Type Register
lsr r3, r3, #16
and r3, r3, #0xf // DminLine
mov r2, #4
mov r2, r2, lsl r3 // cache line size, in bytes (4*2^DminLine)
sub r3, r2, #1 // cache line mask
bic r0, r0, r3 // address of the first cache line
5:
mcr p15, 0, r0, c7, c14, 1 // DCCIMVAC()
add r0, r0, r2
cmp r0, r1
blo 5b
dsb
bx lr

View file

@ -0,0 +1,420 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/** \file */
MODULE ?cp15
/* Forward declaration of sections. */
SECTION IRQ_STACK:DATA:NOROOT(2)
SECTION CSTACK:DATA:NOROOT(3)
/*----------------------------------------------------------------------------
* Functions to access CP15 coprocessor register
*----------------------------------------------------------------------------*/
SECTION .cp15_read_id:CODE:NOROOT(2)
PUBLIC cp15_read_id
cp15_read_id:
mov r0, #0
mrc p15, 0, r0, c0, c0, 0 ; read MIDR
bx lr
SECTION .cp15_isb:CODE:NOROOT(2)
PUBLIC cp15_isb
cp15_isb:
mov r0, #0
mcr p15, 0, r0, c7, c5, 4 ; CP15ISB()
nop
bx lr
SECTION .cp15_dsb:CODE:NOROOT(2)
PUBLIC cp15_dsb
cp15_dsb:
mov r0, #0
mcr p15, 0, r0, c7, c10, 4 ; CP15DSB()
nop
bx lr
SECTION .cp15_dmb:CODE:NOROOT(2)
PUBLIC cp15_dmb
cp15_dmb:
mov r0, #0
mcr p15, 0, r0, c7, c10, 5 ; CP15DMB()
nop
bx lr
SECTION .cp15_invalidate_tlb:CODE:NOROOT(2)
PUBLIC cp15_invalidate_tlb
cp15_invalidate_tlb:
mov r0, #0
mcr p15, 0, r0, c8, c7, 0 ; TLBIALL()
dsb
bx lr
SECTION .cp15_exclusive_cache:CODE:NOROOT(2)
PUBLIC cp15_exclusive_cache
cp15_exclusive_cache:
mov r0, #0
mrc p15, 0, r0, c1, c0, 1 ; Read ACTLR
orr r0, r0, #0x00000080 ; Set EXCL
mcr p15, 0, r0, c1, c0, 1 ; Write ACTLR
nop
bx lr
SECTION .cp15_non_exclusive_cache:CODE:NOROOT(2)
PUBLIC cp15_non_exclusive_cache
cp15_non_exclusive_cache:
mov r0, #0
mrc p15, 0, r0, c1, c0, 1 ; Read ACTLR
bic r0, r0, #0x00000080 ; Clear EXCL
mcr p15, 0, r0, c1, c0, 1 ; Write ACTLR
nop
bx lr
SECTION .cp15_select_icache:CODE:NOROOT(2)
PUBLIC cp15_select_icache
cp15_select_icache:
mrc p15, 2, r0, c0, c0, 0 ; Read CSSELR
orr r0, r0, #0x1 ; Set InD: cache type = ICache
mcr p15, 2, r0, c0, c0, 0 ; Write CSSELR
nop
bx lr
SECTION .cp15_select_dcache:CODE:NOROOT(2)
PUBLIC cp15_select_dcache
cp15_select_dcache:
mrc p15, 2, r0, c0, c0, 0 ; Read CSSELR
and r0, r0, #0xFFFFFFFE ; Clear InD: cache type = DCache
mcr p15, 2, r0, c0, c0, 0 ; Write CSSELR
nop
bx lr
SECTION .cp15_read_control:CODE:NOROOT(2)
PUBLIC cp15_read_control
cp15_read_control:
mov r0, #0
mrc p15, 0, r0, c1, c0, 0 ; read SCTLR
bx lr
SECTION .cp15_write_control:CODE:NOROOT(2)
PUBLIC cp15_write_control
cp15_write_control:
mcr p15, 0, r0, c1, c0, 0 ; rewrite SCTLR
nop
nop
nop
nop
nop
nop
nop
nop
bx lr
SECTION .cp15_write_domain_access_control:CODE:NOROOT(2)
PUBLIC cp15_write_domain_access_control
cp15_write_domain_access_control:
mcr p15, 0, r0, c3, c0, 0 ; rewrite DACR
nop
nop
nop
nop
nop
nop
nop
nop
bx lr
SECTION .cp15_write_ttb:CODE:NOROOT(2)
PUBLIC cp15_write_ttb
cp15_write_ttb:
mcr p15, 0, r0, c2, c0, 0 ; rewrite TTBR0
nop
nop
nop
nop
nop
nop
nop
nop
bx lr
SECTION .cp15_invalid_icache_inner_sharable:CODE:NOROOT(2)
PUBLIC cp15_invalid_icache_inner_sharable
cp15_invalid_icache_inner_sharable:
mov r0, #0
mcr p15, 0, r0, c7, c1, 0 ; ICIALLUIS()
bx lr
SECTION .cp15_invalid_btb_inner_sharable:CODE:NOROOT(2)
PUBLIC cp15_invalid_btb_inner_sharable
cp15_invalid_btb_inner_sharable:
mov r0, #0
mcr p15, 0, r0, c7, c1, 6 ; BPIALLIS()
bx lr
SECTION .cp15_invalid_icache:CODE:NOROOT(2)
PUBLIC cp15_invalid_icache
cp15_invalid_icache:
mov r0, #0
mcr p15, 0, r0, c7, c5, 0 ; ICIALLU()
bx lr
SECTION .cp15_invalid_icache_by_mva:CODE:NOROOT(2)
PUBLIC cp15_invalid_icache_by_mva
cp15_invalid_icache_by_mva:
mov r0, #0
mcr p15, 0, r0, c7, c5, 1 ; ICIMVAU()
bx lr
SECTION .cp15_invalid_btb:CODE:NOROOT(2)
PUBLIC cp15_invalid_btb
cp15_invalid_btb:
mov r0, #0
mcr p15, 0, r0, c7, c5, 6 ; BPIALL()
bx lr
SECTION .cp15_invalid_btb_by_mva:CODE:NOROOT(2)
PUBLIC cp15_invalid_btb_by_mva
cp15_invalid_btb_by_mva:
mcr p15, 0, r0, c7, c5, 7 ; BPIMVA()
bx lr
/***********************************************************
* Data Cache related maintenance functions
***********************************************************/
SECTION .cp15_invalid_dcache_by_set_way:CODE:NOROOT(2)
PUBLIC cp15_invalid_dcache_by_set_way
cp15_invalid_dcache_by_set_way:
push {r1-r4}
mrc p15, 1, r0, c0, c0, 0 ; Read CCSIDR
mov r1, r0, lsr #3 ; Get Associativity (num of ways)
and r1, r1, #3 ; 3 is specific to CortexA5 with 32 KB
mov r2, r0, lsr #13 ; Get NumSets (num of sets)
and r2, r2, #0xFF ; 8bit is specific to CortexA5 with 32 KB
mov r0, #0 ; 0:SHL:5
dinv_way_loop:
lsl r4, r1, #30
mov r3, r2
dinv_set_loop:
orr r0, r4, r3, lsl #5
mcr p15, 0, r0, c7, c6, 2 ; DCISW()
subs r3, r3, #1 ; 1:SHL:30
bpl dinv_set_loop
subs r1, r1, #1
bpl dinv_way_loop
dsb
pop {r1-r4}
bx lr
SECTION .cp15_clean_dcache_by_set_way:CODE:NOROOT(2)
PUBLIC cp15_clean_dcache_by_set_way
cp15_clean_dcache_by_set_way:
push {r1-r4}
mrc p15, 1, r0, c0, c0, 0 ; Read CCSIDR
mov r1, r0, lsr #3 ; Get Associativity (num of ways)
and r1, r1, #3 ; 3 is specific to CortexA5 with 32 KB
mov r2, r0, lsr #13 ; Get NumSets (num of sets)
and r2, r2, #0xFF ; 8bit is specific to CortexA5 with 32 KB
mov r0, #0 ; 0:SHL:5
dclean_way_loop:
lsl r4, r1, #30
mov r3, r2
dclean_set_loop:
orr r0, r4, r3, lsl #5
mcr p15, 0, r0, c7, c10, 2 ; DCCSW()
subs r3, r3, #1 ; 1:SHL:30
bpl dclean_set_loop
subs r1, r1, #1
bpl dclean_way_loop
dsb
pop {r1-r4}
bx lr
SECTION .cp15_clean_invalid_dcache_by_set_way:CODE:NOROOT(2)
PUBLIC cp15_clean_invalid_dcache_by_set_way
cp15_clean_invalid_dcache_by_set_way:
push {r1-r4}
mrc p15, 1, r0, c0, c0, 0 ; Read CCSIDR
mov r1, r0, lsr #3 ; Get Associativity (num of ways)
and r1, r1, #3 ; 3 is specific to CortexA5 with 32 KB
mov r2, r0, lsr #13 ; Get NumSets (num of sets)
and r2, r2, #0xFF ; 8bit is specific to CortexA5 with 32 KB
mov r0, #0 ; 0:SHL:5
dclinv_way_loop:
lsl r4, r1, #30
mov r3, r2
dclinv_set_loop:
orr r0, r4, r3, lsl #5
mcr p15, 0, r0, c7, c14, 2 ; DCCISW()
subs r3, r3, #1 ; 1:SHL:30
bpl dclinv_set_loop
subs r1, r1, #1
bpl dclinv_way_loop
dsb
pop {r1-r4}
bx lr
SECTION .cp15_invalid_dcache_by_mva:CODE:NOROOT(2)
PUBLIC cp15_invalid_dcache_by_mva
cp15_invalid_dcache_by_mva:
mov r2, #0x20 ; Eight words per line, Cortex-A5 L1 Line Size 32 Bytes
mov r3, r0
inv_loop:
mcr p15, 0, r0, c7, c6, 1 ; DCIMVAC()
add r3, r3, r2
cmp r3, r1
bls inv_loop
bx lr
SECTION .cp15_clean_dcache_by_mva:CODE:NOROOT(2)
PUBLIC cp15_clean_dcache_by_mva
cp15_clean_dcache_by_mva:
mov r2, #0x20 ; Eight words per line, Cortex-A5 L1 Line Size 32 Bytes
mov r3, r0
clean_loop:
mcr p15, 0, r0, c7, c10, 1 ; DCCMVAC()
add r3, r3, r2
cmp r3, r1
bls clean_loop
bx lr
SECTION .cp15_clean_dcache_umva:CODE:NOROOT(2)
PUBLIC cp15_clean_dcache_umva
cp15_clean_dcache_umva:
mov r0, #0
mcr p15, 0, r0, c7, c11, 1 ; DCCMVAU()
bx lr
SECTION .cp15_clean_invalid_dcache_by_mva:CODE:NOROOT(2)
PUBLIC cp15_clean_invalid_dcache_by_mva
cp15_clean_invalid_dcache_by_mva:
mov r2, #0x20 ; Eight words per line, Cortex-A5 L1 Line Size 32 Bytes
mov r3, r0
clinv_loop:
mcr p15, 0, r0, c7, c14, 1 ; DCCIMVAC()
add r3, r3, r2
cmp r3, r1
bls clinv_loop
bx lr
SECTION .cp15_coherent_dcache_for_dma:CODE:NOROOT(2)
PUBLIC cp15_coherent_dcache_for_dma
cp15_coherent_dcache_for_dma:
push {r2-r4}
mrc p15, 0, r3, c0, c0, 1 ; read Cache Type Register
lsr r3, r3, #16
and r3, r3, #0xf ; DminLine
mov r2, #4
mov r2, r2, lsl r3 ; cache line size, in bytes (4*2^DminLine)
sub r3, r2, #1 ; cache line mask
bic r4, r0, r3 ; address of the first cache line
loop1:
mcr p15, 0, r4, c7, c11, 1 ; DCCMVAU()
add r4, r4, r2
cmp r4, r1
blo loop1
dsb
bic r4, r0, r3
loop2:
mcr p15, 0, r4, c7, c5, 1 ; ICIMVAU()
add r4, r4, r2
cmp r4, r1
blo loop2
mov r0, #0
mcr p15, 0, r0, c7, c1, 6 ; BPIALLIS()
mcr p15, 0, r0, c7, c5, 6 ; BPIALL()
dsb
isb
pop {r2-r4}
bx lr
SECTION .cp15_invalidate_dcache_for_dma:CODE:NOROOT(2)
PUBLIC cp15_invalidate_dcache_for_dma
cp15_invalidate_dcache_for_dma:
push {r2-r3}
mrc p15, 0, r3, c0, c0, 1 ; read CP15 Cache Type Register
lsr r3, r3, #16
and r3, r3, #0xf ; DminLine
mov r2, #4
mov r2, r2, lsl r3 ; cache line size, in bytes (4*2^DminLine)
sub r3, r2, #1 ; cache line mask
bic r0, r0, r3 ; address of the first cache line
loop3:
mcr p15, 0, r0, c7, c6, 1 ; CP15:DCIMVAC(r0)
add r0, r0, r2
cmp r0, r1 ; while ('cache line address' < 'end')
blo loop3
dsb
pop {r2-r3}
bx lr
SECTION .cp15_clean_dcache_for_dma:CODE:NOROOT(2)
PUBLIC cp15_clean_dcache_for_dma
cp15_clean_dcache_for_dma:
mrc p15, 0, r3, c0, c0, 1 ; read Cache Type Register
lsr r3, r3, #16
and r3, r3, #0xf ; DminLine
mov r2, #4
mov r2, r2, lsl r3 ; cache line size, in bytes (4*2^DminLine)
sub r3, r2, #1 ; cache line mask
bic r0, r0, r3 ; address of the first cache line
loop4:
mcr p15, 0, r0, c7, c10, 1 ; DCCMVAC()
add r0, r0, r2
cmp r0, r1
blo loop4
dsb
bx lr
SECTION .cp15_flush_dcache_for_dma:CODE:NOROOT(2)
PUBLIC cp15_flush_dcache_for_dma
cp15_flush_dcache_for_dma:
mrc p15, 0, r3, c0, c0, 1 ; read Cache Type Register
lsr r3, r3, #16
and r3, r3, #0xf ; DminLine
mov r2, #4
mov r2, r2, lsl r3 ; cache line size, in bytes (4*2^DminLine)
sub r3, r2, #1 ; cache line mask
bic r0, r0, r3 ; address of the first cache line
loop5:
mcr p15, 0, r0, c7, c14, 1 ; DCCIMVAC()
add r0, r0, r2
cmp r0, r1
blo loop5
dsb
bx lr
END

View file

@ -0,0 +1,252 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/** \file */
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#if defined(__ICCARM__)
#include <intrinsics.h>
#endif
#include "cortex-a/cp15_pmu.h"
#include <assert.h>
/*----------------------------------------------------------------------------
* Global functions
*----------------------------------------------------------------------------*/
/**
* \brief Resets the counter and enables/disables all counters including PMCCNTR.
* \param ResetCounterType CounterType: Performance or Cycle counter
*/
static void cp15_pmu_control(uint8_t ResetCounterType, uint8_t EnableCounter)
{
uint32_t PMU_Value = 0;
asm("mrc p15, 0, %0, c9, c12, 0":"=r"(PMU_Value));
PMU_Value |= ((ResetCounterType << 1) | EnableCounter);
asm("mcr p15, 0, %0, c9, c12, 0": :"r"(PMU_Value));
}
/**
* \brief Select Cycle Count divider
* \param Divider 0 for increment of counter at every single cycle or 1 for at every 64th cycle
*/
static void cp15_cycle_count_divider(uint8_t Divider)
{
uint32_t PMU_Value = 0;
assert((Divider > 1 ? 0 : 1));
asm("mrc p15, 0, %0, c9, c12, 0":"=r"(PMU_Value));
PMU_Value |= (Divider << 3);
asm("mcr p15, 0, %0, c9, c12, 0": :"r"(PMU_Value));
}
/**
* \brief Enables PMCCNTR.
*/
static void cp15_enable_PMCNT(void)
{
uint32_t CNT_Value = 0;
asm("mrc p15, 0, %0, c9, c12, 1":"=r"(CNT_Value));
CNT_Value |= (uint32_t) ((1 << CP15_PMCNTENSET));
asm("mcr p15, 0, %0, c9, c12, 1": :"r"(CNT_Value));
}
/**
* \brief Enables PMCCNTR.
*/
static void cp15_enable_counter(uint8_t Counter)
{
uint32_t CNT_Value = 0;
asm("mrc p15, 0, %0, c9, c12, 1":"=r"(CNT_Value));
CNT_Value |= Counter;
asm("mcr p15, 0, %0, c9, c12, 1": :"r"(CNT_Value));
}
/**
* \brief Disables/clear PMCCNTR.
* \param Counter 0 or 1 to selct counter
*/
static void cp15_clear_PMCNT(void)
{
uint32_t CNT_Value = 0;
asm("mrc p15, 0, %0, c9, c12, 2":"=r"(CNT_Value));
CNT_Value |= (uint32_t) (1 << CP15_PMCNTENCLEAR);
asm("mcr p15, 0, %0, c9, c12, 2": :"r"(CNT_Value));
}
/**
* \brief Disables/Enables overflow flag.
* \param Enable Enables or disables the flag option
* \param ClearCounterFlag selects the counter flag to clear
*/
void cp15_overflow_status(uint8_t Enable, uint8_t ClearCounterFlag)
{
uint32_t OFW_Value = 0;
asm("mrc p15, 0, %0, c9, c12, 3":"=r"(OFW_Value));
OFW_Value |= ((Enable << 31) | ClearCounterFlag);
asm("mcr p15, 0, %0, c9, c12, 3": :"r"(OFW_Value));
}
/**
* \brief Disables/Enables overflow flag.
* \param EventCounter Counter of the events
*/
uint32_t cp15_read_overflow_status(uint8_t EventCounter)
{
uint32_t OFW_Value = 0;
asm("mrc p15, 0, %0, c9, c12, 3":"=r"(OFW_Value));
OFW_Value = ((OFW_Value & EventCounter) >> (EventCounter - 1));
return OFW_Value;
}
/**
* \brief Increments the count of a performance monitor count register.
* \param IncrCounter 0 or 1 counters
*/
void cp15_soft_incr(uint8_t IncrCounter)
{
uint32_t INRC_Value = 0;
asm("mrc p15, 0, %0, c9, c12, 4":"=r"(INRC_Value));
INRC_Value |= IncrCounter;
asm("mcr p15, 0, %0, c9, c12, 4": :"r"(INRC_Value));
}
/**
* \brief Increments the count of a performance monitor count register.
* \param EventType Select Event Type
* \param Counter 0 or 1 counters
*/
static void cp15_select_event(PerfEventType EventType, uint8_t Counter)
{
uint32_t CounterSelect = 0;
assert((Counter == 1) || (Counter == 2));
CounterSelect = (Counter & 0x1F);
asm("mcr p15, 0, %0, c9, c12, 5": :"r"(CounterSelect));
CounterSelect = (EventType & 0xFF);
asm("mcr p15, 0, %0, c9, c13, 1": :"r"(CounterSelect));
// PMXEVTYPER
asm("mrc p15, 0, %0, c9, c13, 1":"=r"(CounterSelect));
// PMXEVTYPER
}
/**
* \brief Enables USER mode
*/
void cp15_enable_user_mode(void)
{
uint8_t Value = 1;
asm("mcr p15, 0, %0, c9, c14, 0": :"r"(Value));
}
/**
* \brief Enables Oveflows interrupt
* \param Enable Enables the Interrupt
* \param Counter 0 or 1 counters
*/
void cp15_enable_interrupt(uint8_t Enable, uint8_t Counter)
{
uint32_t ITE_Value = 0;
ITE_Value |= ((Enable << 31) | Counter);
asm("mcr p15, 0, %0, c9, c14, 1": :"r"(ITE_Value));
}
/**
* \brief Disables Oveflows interrupt
* \param Disable Disables the Interrupt
* \param Counter 0 or 1 counters
*/
void cp15_disable_interrupt(uint8_t Disable, uint8_t Counter)
{
uint32_t ITE_Value = 0;
ITE_Value |= ((Disable << 31) | Counter);
asm("mcr p15, 0, %0, c9, c14, 2": :"r"(ITE_Value));
}
/**
* \brief Initialize Cycle counter with Divider 64
*/
uint32_t cp15_init_cycle_counter(void)
{
uint32_t value;
cp15_clear_PMCNT();
cp15_enable_PMCNT();
cp15_overflow_status(true, CP15_BothCounter);
cp15_cycle_count_divider(CP15_CountDivider64);
cp15_pmu_control(CP15_ResetCycCounter, true);
asm("mrc p15, 0, %0, c9, c13, 0":"=r"(value));
return value;
}
/**
* \brief Initialize Performance monitor counter with Divider 64
* \param Event Event type
* \param Counter 0 or 1 counters
*/
void cp15_init_perf_counter(PerfEventType Event, uint8_t Counter)
{
cp15_pmu_control(CP15_ResetPerCounter, true);
cp15_select_event(Event, Counter);
cp15_overflow_status(false, CP15_BothCounter);
cp15_enable_counter(Counter);
}
/**
* \brief gives total number of event count
* \param Counter 0 or 1 counters
*/
uint32_t cp15_count_evt(uint8_t Counter)
{
uint32_t value;
asm("mcr p15, 0, %0, c9, c12, 5": :"r"(Counter));
asm("mrc p15, 0, %0, c9, c13, 2":"=r"(value));
// PMXEVTYPER
return (value);
}
/**
* \brief gives total number of cycle count
*/
uint32_t cp15_get_cycle_counter(void)
{
uint32_t value;
asm("mrc p15, 0, %0, c9, c13, 0":"=r"(value));
return value;
}

View file

@ -0,0 +1,106 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
#ifndef _CP15_PMU_H
#define _CP15_PMU_H
/*----------------------------------------------------------------------------
* Definition
*----------------------------------------------------------------------------*/
#define CP15_PMCNTENSET 31
#define CP15_PMCNTENCLEAR 31
#define CP15_PMCR_DIVIDER 3
#define CP15_PMCR_RESET 2
#define CP15_PMCR_ENABLE 0
#define CP15_NoReset 0
#define CP15_ResetPerCounter 1
#define CP15_ResetCycCounter 2
#define CP15_ResetPerCycCounter 3
#define CP15_CountDividerSingle 0
#define CP15_CountDivider64 1
#define CP15_CounterNone 0
#define CP15_Counter0 1
#define CP15_Counter1 2
#define CP15_BothCounter 3
typedef enum {
L1_IC_FILL, // Level 1 instruction cache refill
L1_ITLB_FILL, // Level 1 instruction TLB refill
L1_DC_FILL, // Level 1 data cache refill
L1_DC_ACC, // Level 1 data cache access
L1_DTLB_FILL, // Level 1 data TLB refill
LOAD, // Load
STORE, // Store
InstArchExec, // Instruction architecturally executed
ExcepetionTaken, // Exception taken
ExcepetionRet, // Exception return
WrCONTEXTIDR, // Write to CONTEXTIDR
SoftPCChange, // Software change of the PC
ImmBr, // Immediate branch
ProcRet, // Procedure return
UnalingedLdStr, // Unaligned load or store
MispredictedBranchExec, // Mispredicted or not predicted branch speculatively executed
PredictedBranchExec, // Predictable branch speculatively executed
DataMemAcc, // Data memory access.
ICAcc, // Instruction Cache access.
DCEviction, // Data cache eviction.
IRQException, // IRQ exception taken.
FIQException, // FIQ exception taken.
ExtMemReq, // External memory request.
NCExtMemReq, // Non-cacheable external memory request
PrefetchLineFill, // Linefill because of prefetch.
PrefetchLineDrop, // Prefetch linefill dropped.
EnteringRAmode, // Entering read allocate mode.
RAmode, // Read allocate mode.
reserved, // Reserved, do not use
DWstallSBFfull // Data Write operation that stalls the pipeline because the store buffer is full.
} PerfEventType;
/*----------------------------------------------------------------------------
* Functions
*----------------------------------------------------------------------------*/
extern uint32_t cp15_init_cycle_counter(void);
extern uint32_t cp15_get_cycle_counter(void);
extern uint32_t cp15_read_overflow_status(uint8_t EventCounter);
extern void cp15_overflow_status(uint8_t Enable, uint8_t ClearCounterFlag);
extern void cp15_soft_incr(uint8_t IncrCounter);
extern uint32_t cp15_count_evt(uint8_t Counter);
extern void cp15_enable_user_mode(void);
extern void cp15_enable_interrupt(uint8_t Enable, uint8_t Counter);
extern void cp15_disable_interrupt(uint8_t Disable, uint8_t Counter);
extern void cp15_init_perf_counter(PerfEventType Event, uint8_t Counter);
#endif

View file

@ -0,0 +1,43 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
#ifndef CPSR_HEARDER_
#define CPSR_HEARDER_
#include <stdint.h>
#define CPSR_MASK_IRQ 0x00000080
#define CPSR_MASK_FIQ 0x00000040
extern void v_arm_clr_cpsr_bits(uint32_t mask);
extern void v_arm_set_cpsr_bits(uint32_t mask);
#endif

View file

@ -0,0 +1,55 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/** \file */
/*----------------------------------------------------------------------------
* Functions to access CPSR
*----------------------------------------------------------------------------*/
.section .text.v_arm_clr_cpsr_bits
.global v_arm_clr_cpsr_bits
v_arm_clr_cpsr_bits:
push {r1}
mrs r1, cpsr
mvn r0, r0
and r1, r1,r0
msr CPSR_c, r1
pop {r1}
bx lr
.section .text.v_arm_set_cpsr_bits
.global v_arm_set_cpsr_bits
v_arm_set_cpsr_bits:
push {r1}
mrs r1, cpsr
orr r1, r1, r0
msr cpsr_c, r1
pop {r1}
bx lr

View file

@ -0,0 +1,63 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/** \file */
MODULE ?cpsr
/* Forward declaration of sections. */
SECTION IRQ_STACK:DATA:NOROOT(2)
SECTION CSTACK:DATA:NOROOT(3)
/*----------------------------------------------------------------------------
* Functions to access CPSR
*----------------------------------------------------------------------------*/
SECTION .v_arm_clr_cpsr_bits:CODE:NOROOT(2)
PUBLIC v_arm_clr_cpsr_bits
v_arm_clr_cpsr_bits:
push {r1}
mrs r1, cpsr
mvn r0, r0
and r1, r1,r0
msr CPSR_c, r1
pop {r1}
bx lr
SECTION .v_arm_set_cpsr_bits:CODE:NOROOT(2)
PUBLIC v_arm_set_cpsr_bits
v_arm_set_cpsr_bits:
push {r1}
mrs r1, cpsr
orr r1, r1, r0
msr cpsr_c, r1
pop {r1}
bx lr
END

View file

@ -0,0 +1,89 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/** \file */
/**
* \addtogroup mmu MMU Initialization
*
* \section Usage
*
* Translation Lookaside Buffers (TLBs) are an implementation technique that caches translations or
* translation table entries. TLBs avoid the requirement for every memory access to perform a translation table
* lookup. The ARM architecture does not specify the exact form of the TLB structures for any design. In a
* similar way to the requirements for caches, the architecture only defines certain principles for TLBs:
*
* The MMU supports memory accesses based on memory sections or pages:
* Supersections Consist of 16MB blocks of memory. Support for Supersections is optional.
* -# Sections Consist of 1MB blocks of memory.
* -# Large pages Consist of 64KB blocks of memory.
* -# Small pages Consist of 4KB blocks of memory.
*
* Access to a memory region is controlled by the access permission bits and the domain field in the TLB entry.
* Memory region attributes
* Each TLB entry has an associated set of memory region attributes. These control accesses to the caches,
* how the write buffer is used, and if the memory region is Shareable and therefore must be kept coherent.
*
* Related files:\n
* \ref mmu.c\n
* \ref mmu.h \n
*/
/*------------------------------------------------------------------------------ */
/* Headers */
/*------------------------------------------------------------------------------ */
#include "chip.h"
#include "board.h"
#include "cortex-a/cp15.h"
#include "cortex-a/mmu.h"
#include "compiler.h"
/*------------------------------------------------------------------------------ */
/* Local variables */
/*------------------------------------------------------------------------------ */
ALIGNED(16384) static uint32_t _tlb[4096];
/*------------------------------------------------------------------------------ */
/* Exported functions */
/*------------------------------------------------------------------------------ */
void mmu_initialize(void)
{
board_setup_tlb(_tlb);
cp15_write_ttb((unsigned int)_tlb);
/* Program the domain access register */
/* only domain 15: access are not checked */
cp15_write_domain_access_control(0xC0000000);
asm volatile("": : :"memory");
asm("dsb");
asm("isb");
}

View file

@ -0,0 +1,79 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
#ifndef _MMU_
#define _MMU_
/*----------------------------------------------------------------------------
* Exported definitions
*----------------------------------------------------------------------------*/
#define TTB_TYPE(x) ((x) << 0)
#define TTB_TYPE_SECT TTB_TYPE(2)
#define TTB_SECT_B(x) ((x) << 2)
#define TTB_SECT_WRITE_THROUGH TTB_SECT_B(0)
#define TTB_SECT_WRITE_BACK TTB_SECT_B(1)
#define TTB_SECT_C(x) ((x) << 3)
#define TTB_SECT_NON_CACHEABLE TTB_SECT_C(0)
#define TTB_SECT_CACHEABLE TTB_SECT_C(1)
#define TTB_SECT_XN(x) ((x) << 4)
#define TTB_SECT_EXEC TTB_SECT_XN(0)
#define TTB_SECT_EXEC_NEVER TTB_SECT_XN(1)
#define TTB_SECT_DOMAIN(x) ((x) << 5)
#define TTB_SECT_AP(x) ((x) << 10)
#define TTB_SECT_APX(x) ((x) << 15)
#define TTB_SECT_AP_PRIV_ONLY (TTB_SECT_APX(0) | TTB_SECT_AP(1))
#define TTB_SECT_AP_NO_USER_WRITE (TTB_SECT_APX(0) | TTB_SECT_AP(2))
#define TTB_SECT_AP_FULL_ACCESS (TTB_SECT_APX(0) | TTB_SECT_AP(3))
#define TTB_SECT_AP_PRIV_READ_ONLY (TTB_SECT_APX(1) | TTB_SECT_AP(1))
#define TTB_SECT_AP_READ_ONLY (TTB_SECT_APX(1) | TTB_SECT_AP(2))
#define TTB_SECT_TEX(x) ((x) << 12)
#define TTB_SECT_STRONGLY_ORDERED (TTB_SECT_TEX(0) | TTB_SECT_NON_CACHEABLE | TTB_SECT_WRITE_THROUGH)
#define TTB_SECT_SHAREABLE_DEVICE (TTB_SECT_TEX(0) | TTB_SECT_NON_CACHEABLE | TTB_SECT_WRITE_BACK)
#define TTB_SECT_CACHEABLE_WT (TTB_SECT_TEX(0) | TTB_SECT_CACHEABLE | TTB_SECT_WRITE_THROUGH)
#define TTB_SECT_CACHEABLE_WB (TTB_SECT_TEX(0) | TTB_SECT_CACHEABLE | TTB_SECT_WRITE_BACK)
#define TTB_SECT_ADDR(x) ((x) & 0xFFF00000)
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/**
* \brief initializes the MMU
*/
extern void mmu_initialize(void);
#endif /* #ifndef _MMU_ */

View file

@ -0,0 +1,32 @@
# ----------------------------------------------------------------------------
# SAM Software Package License
# ----------------------------------------------------------------------------
# Copyright (c) 2015, Atmel Corporation
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# - Redistributions of source code must retain the above copyright notice,
# this list of conditions and the disclaimer below.
#
# Atmel's name may not be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# DISCLAIMER: 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
# 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.
# ----------------------------------------------------------------------------
drivers-y += drivers/misc/console.o
drivers-y += drivers/misc/led.o
drivers-$(CONFIG_SOC_SAMA5D2) += drivers/misc/bmp280.o

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,444 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/*! \file bmp280.h
\brief BMP280 Sensor Driver Support Header File */
#ifndef __BMP280_H__
#define __BMP280_H__
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include <stdint.h>
/*----------------------------------------------------------------------------
* Definition
*----------------------------------------------------------------------------*/
#define BMP280_64BITSUPPORT_PRESENT
/********************************************/
/**\name ENABLE FLATING OUTPUT */
/**************************************/
// If the user wants to support floating point calculations, please set the following define.
#define BMP280_ENABLE_FLOAT
// If the user wants to support 64 bit integer calculation (needed for optimal pressure accuracy)
// please set the following definition. If int64 calculation is not wanted (e.g. because it would include
// large libraries), please do not set the definition.
#define BMP280_ENABLE_INT64
/****************************************/
/**\name DELAY */
/****************************************/
// defines the return parameter type of the BMP280_DELAY_FUNCTION
#define BMP280_DELAY_RETURN_TYPE void
// defines the calling parameter types of the BMP280_DELAY_FUNCTION
#define BMP280_DELAY_PARAM_TYPES uint16_t
/***************************************************************/
/**\name GET AND SET BITSLICE FUNCTIONS */
/***************************************************************/
/* never change this line */
#define BMP280_DELAY_FUNC(delay_in_msec) delay_func(delay_in_msec)
#define BMP280_GET_BITSLICE(regvar, bitname) ((regvar & bitname##__MSK) >> bitname##__POS)
#define BMP280_SET_BITSLICE(regvar, bitname, val) ((regvar & ~bitname##__MSK) | ((val<<bitname##__POS)&bitname##__MSK))
/***************************************************************/
/**\name COMMON USED CONSTANTS */
/***************************************************************/
/* Constants */
#define BMP280_NULL 0
#define BMP280_INIT_VALUE 0
/************************************************/
/**\name ERROR CODES */
/************************************************/
#define SUCCESS ((uint8_t)0)
#define ERROR ((uint8_t)0xFF)
#define E_BMP280_NULL_PTR ((uint8_t)ERROR-1)
#define E_BMP280_COMM_RES ((uint8_t)ERROR-2)
#define E_BMP280_OUT_OF_RANGE ((uint8_t)ERROR-3)
/************************************************/
/**\name I2C ADDRESS DEFINITION */
/***********************************************/
#define BMP280_I2C_ADDRESS1 0x76
#define BMP280_I2C_ADDRESS2 0x77
/************************************************/
/**\name POWER MODE DEFINITION */
/***********************************************/
/* Sensor Specific constants */
#define BMP280_SLEEP_MODE 0x00
#define BMP280_FORCED_MODE 0x01
#define BMP280_NORMAL_MODE 0x03
#define BMP280_SOFT_RESET_CODE 0xB6
/************************************************/
/**\name STANDBY TIME DEFINITION */
/***********************************************/
#define BMP280_STANDBY_TIME_1_MS 0x00
#define BMP280_STANDBY_TIME_63_MS 0x01
#define BMP280_STANDBY_TIME_125_MS 0x02
#define BMP280_STANDBY_TIME_250_MS 0x03
#define BMP280_STANDBY_TIME_500_MS 0x04
#define BMP280_STANDBY_TIME_1000_MS 0x05
#define BMP280_STANDBY_TIME_2000_MS 0x06
#define BMP280_STANDBY_TIME_4000_MS 0x07
/************************************************/
/**\name OVERSAMPLING DEFINITION */
/***********************************************/
#define BMP280_OVERSAMPLING_SKIPPED 0x00
#define BMP280_OVERSAMP_1X 0x01
#define BMP280_OVERSAMP_2X 0x02
#define BMP280_OVERSAMP_4X 0x03
#define BMP280_OVERSAMP_8X 0x04
#define BMP280_OVERSAMP_16X 0x05
/************************************************/
/**\name WORKING MODE DEFINITION */
/***********************************************/
#define BMP280_ULTRA_LOW_POWER_MODE 0x00
#define BMP280_LOW_POWER_MODE 0x01
#define BMP280_STANDARD_RESOLUTION_MODE 0x02
#define BMP280_HIGH_RESOLUTION_MODE 0x03
#define BMP280_ULTRA_HIGH_RESOLUTION_MODE 0x04
#define BMP280_ULTRALOWPOWER_OVRS_PRES BMP280_OVERSAMP_1X
#define BMP280_ULTRALOWPOWER_OVRS_TEMP BMP280_OVERSAMP_1X
#define BMP280_LOWPOWER_OVRS_PRES BMP280_OVERSAMP_2X
#define BMP280_LOWPOWER_OVRS_TEMP BMP280_OVERSAMP_1X
#define BMP280_STANDARDRESOLUTION_OVRS_PRES BMP280_OVERSAMP_4X
#define BMP280_STANDARDRESOLUTION_OVRS_TEMP BMP280_OVERSAMP_1X
#define BMP280_HIGHRESOLUTION_OVRS_PRES BMP280_OVERSAMP_8X
#define BMP280_HIGHRESOLUTION_OVRS_TEMP BMP280_OVERSAMP_1X
#define BMP280_ULTRAHIGHRESOLUTION_OVRS_PRES BMP280_OVERSAMP_16X
#define BMP280_ULTRAHIGHRESOLUTION_OVRS_TEMP BMP280_OVERSAMP_2X
/************************************************/
/**\name FILTER DEFINITION */
/***********************************************/
#define BMP280_FILTER_COEFF_OFF 0x00
#define BMP280_FILTER_COEFF_2 0x01
#define BMP280_FILTER_COEFF_4 0x02
#define BMP280_FILTER_COEFF_8 0x03
#define BMP280_FILTER_COEFF_16 0x04
/************************************************/
/**\name DELAY TIME DEFINITION */
/***********************************************/
#define T_INIT_MAX 20 /* 20/16 = 1.25 ms */
#define T_MEASURE_PER_OSRS_MAX 37 /* 37/16 = 2.3125 ms*/
#define T_SETUP_PRESSURE_MAX 10 /* 10/16 = 0.625 ms */
/************************************************/
/**\name CALIBRATION PARAMETERS DEFINITION */
/***********************************************/
/*calibration parameters */
#define BMP280_DIG_T1_LSB_REG 0x88
#define BMP280_DIG_T1_MSB_REG 0x89
#define BMP280_DIG_T2_LSB_REG 0x8A
#define BMP280_DIG_T2_MSB_REG 0x8B
#define BMP280_DIG_T3_LSB_REG 0x8C
#define BMP280_DIG_T3_MSB_REG 0x8D
#define BMP280_DIG_P1_LSB_REG 0x8E
#define BMP280_DIG_P1_MSB_REG 0x8F
#define BMP280_DIG_P2_LSB_REG 0x90
#define BMP280_DIG_P2_MSB_REG 0x91
#define BMP280_DIG_P3_LSB_REG 0x92
#define BMP280_DIG_P3_MSB_REG 0x93
#define BMP280_DIG_P4_LSB_REG 0x94
#define BMP280_DIG_P4_MSB_REG 0x95
#define BMP280_DIG_P5_LSB_REG 0x96
#define BMP280_DIG_P5_MSB_REG 0x97
#define BMP280_DIG_P6_LSB_REG 0x98
#define BMP280_DIG_P6_MSB_REG 0x99
#define BMP280_DIG_P7_LSB_REG 0x9A
#define BMP280_DIG_P7_MSB_REG 0x9B
#define BMP280_DIG_P8_LSB_REG 0x9C
#define BMP280_DIG_P8_MSB_REG 0x9D
#define BMP280_DIG_P9_LSB_REG 0x9E
#define BMP280_DIG_P9_MSB_REG 0x9F
/************************************************/
/**\name REGISTER ADDRESS DEFINITION */
/***********************************************/
#define BMP280_CHIP_ID_REG 0xD0 /*Chip ID Register */
#define BMP280_RST_REG 0xE0 /*Softreset Register */
#define BMP280_STAT_REG 0xF3 /*Status Register */
#define BMP280_CTRL_MEAS_REG 0xF4 /*Ctrl Measure Register */
#define BMP280_CONFIG_REG 0xF5 /*Configuration Register */
#define BMP280_PRESSURE_MSB_REG 0xF7 /*Pressure MSB Register */
#define BMP280_PRESSURE_LSB_REG 0xF8 /*Pressure LSB Register */
#define BMP280_PRESSURE_XLSB_REG 0xF9 /*Pressure XLSB Register */
#define BMP280_TEMPERATURE_MSB_REG 0xFA /*Temperature MSB Reg */
#define BMP280_TEMPERATURE_LSB_REG 0xFB /*Temperature LSB Reg */
#define BMP280_TEMPERATURE_XLSB_REG 0xFC /*Temperature XLSB Reg */
/************************************************/
/**\name BIT LENGTH,POSITION AND MASK DEFINITION */
/***********************************************/
/* Status Register */
#define BMP280_STATUS_REG_MEASURING__POS 3
#define BMP280_STATUS_REG_MEASURING__MSK 0x08
#define BMP280_STATUS_REG_MEASURING__LEN 1
#define BMP280_STATUS_REG_MEASURING__REG BMP280_STAT_REG
#define BMP280_STATUS_REG_IM_UPDATE__POS 0
#define BMP280_STATUS_REG_IM_UPDATE__MSK 0x01
#define BMP280_STATUS_REG_IM_UPDATE__LEN 1
#define BMP280_STATUS_REG_IM_UPDATE__REG BMP280_STAT_REG
/************************************************/
/**\name BIT LENGTH,POSITION AND MASK DEFINITION
FOR TEMPERATURE OVERSAMPLING */
/***********************************************/
/* Control Measurement Register */
#define BMP280_CTRL_MEAS_REG_OVRS_TEMP__POS 5
#define BMP280_CTRL_MEAS_REG_OVRS_TEMP__MSK 0xE0
#define BMP280_CTRL_MEAS_REG_OVRS_TEMP__LEN 3
#define BMP280_CTRL_MEAS_REG_OVRS_TEMP__REG \
BMP280_CTRL_MEAS_REG
/************************************************/
/**\name BIT LENGTH,POSITION AND MASK DEFINITION
FOR PRESSURE OVERSAMPLING */
/***********************************************/
#define BMP280_CTRL_MEAS_REG_OVRS_PRES__POS 2
#define BMP280_CTRL_MEAS_REG_OVRS_PRES__MSK 0x1C
#define BMP280_CTRL_MEAS_REG_OVRS_PRES__LEN 3
#define BMP280_CTRL_MEAS_REG_OVRS_PRES__REG \
BMP280_CTRL_MEAS_REG
/************************************************/
/**\name BIT LENGTH,POSITION AND MASK DEFINITION
FOR POWER MODE */
/***********************************************/
#define BMP280_CTRL_MEAS_REG_POWER_MODE__POS 0
#define BMP280_CTRL_MEAS_REG_POWER_MODE__MSK 0x03
#define BMP280_CTRL_MEAS_REG_POWER_MODE__LEN 2
#define BMP280_CTRL_MEAS_REG_POWER_MODE__REG BMP280_CTRL_MEAS_REG
/************************************************/
/**\name BIT LENGTH,POSITION AND MASK DEFINITION
FOR STANDBY DURATION */
/***********************************************/
/* Configuration Register */
#define BMP280_CONFIG_REG_STANDBY_DURN__POS 5
#define BMP280_CONFIG_REG_STANDBY_DURN__MSK 0xE0
#define BMP280_CONFIG_REG_STANDBY_DURN__LEN 3
#define BMP280_CONFIG_REG_STANDBY_DURN__REG BMP280_CONFIG_REG
/************************************************/
/**\name BIT LENGTH,POSITION AND MASK DEFINITION
FOR IIR FILTER */
/***********************************************/
#define BMP280_CONFIG_REG_FILTER__POS 2
#define BMP280_CONFIG_REG_FILTER__MSK 0x1C
#define BMP280_CONFIG_REG_FILTER__LEN 3
#define BMP280_CONFIG_REG_FILTER__REG BMP280_CONFIG_REG
/************************************************/
/**\name BIT LENGTH,POSITION AND MASK DEFINITION
FOR SPI ENABLE*/
/***********************************************/
#define BMP280_CONFIG_REG_SPI3_ENABLE__POS 0
#define BMP280_CONFIG_REG_SPI3_ENABLE__MSK 0x01
#define BMP280_CONFIG_REG_SPI3_ENABLE__LEN 1
#define BMP280_CONFIG_REG_SPI3_ENABLE__REG BMP280_CONFIG_REG
/************************************************/
/**\name BIT LENGTH,POSITION AND MASK DEFINITION
FOR PRESSURE AND TEMPERATURE DATA REGISTERS */
/***********************************************/
/* Data Register */
#define BMP280_PRESSURE_XLSB_REG__POS 4
#define BMP280_PRESSURE_XLSB_REG__MSK 0xF0
#define BMP280_PRESSURE_XLSB_REG__LEN 4
#define BMP280_PRESSURE_XLSB_REG__REG BMP280_PRESSURE_XLSB_REG
#define BMP280_TEMPERATURE_XLSB_REG__POS 4
#define BMP280_TEMPERATURE_XLSB_REG__MSK 0xF0
#define BMP280_TEMPERATURE_XLSB_REG__LEN 4
#define BMP280_TEMPERATURE_XLSB_REG__REG BMP280_TEMPERATURE_XLSB_REG
/****************************************************/
/**\name ARRAY PARAMETERS */
/***************************************************/
#define LSB_ZERO 0
#define MSB_ONE 1
#define LSB_TWO 2
#define MSB_THREE 3
#define LSB_FOUR 4
#define MSB_FIVE 5
#define LSB_SIX 6
#define MSB_SEVEN 7
/****************************************************/
/**\name TRUE TEMPERATURE CALUCULATION PARAMETERS */
/***************************************************/
#define BMP280_DEC_TRUE_TEMP_5 5
#define BMP280_DEC_TRUE_TEMP_128 128
/****************************************************/
/**\name TRUE PRESSURE CALUCULATION PARAMETERS */
/***************************************************/
#define BMP280_DEC_TRUE_PRES_64000 64000
#define BMP280_DEC_TRUE_PRES_2 2
#define BMP280_DEC_TRUE_PRES_32768 32768
#define BMP280_DEC_TRUE_PRES_1048576 1048576
#define BMP280_DEC_TRUE_PRES_3125 3125
#define BMP280_HEX_TRUE_PRES_8M 0x80000000
/****************************************************/
/**\name TRUE TEMPERATURE CALCULATION FLOAT RETURN */
/***************************************************/
#define BMP280_FLOAT_TRUE_TEMP_16384 16384.0
#define BMP280_FLOAT_TRUE_TEMP_1024 1024.0
#define BMP280_FLOAT_TRUE_TEMP_131072 131072.0
#define BMP280_FLOAT_TRUE_TEMP_8192 8192.0
#define BMP280_FLOAT_TRUE_TEMP_5120 5120.0
/****************************************************/
/**\name TRUE PRESSURE CALCULATION FLOAT RETURN */
/***************************************************/
#define BMP280_FLOAT_TRUE_PRES_1 1.0
#define BMP280_FLOAT_TRUE_PRES_0 0.0
#define BMP280_FLOAT_TRUE_PRES_2 2.0
#define BMP280_FLOAT_TRUE_PRES_4 4.0
#define BMP280_FLOAT_TRUE_PRES_1_6 16.0
#define BMP280_FLOAT_TRUE_PRES_64000 64000.0
#define BMP280_FLOAT_TRUE_PRES_32768 32768.0
#define BMP280_FLOAT_TRUE_PRES_65536 65536.0
#define BMP280_FLOAT_TRUE_PRES_524288 524288.0
#define BMP280_FLOAT_TRUE_PRES_1048576 1048576.0
#define BMP280_FLOAT_TRUE_PRES_4096 4096.0
#define BMP280_FLOAT_TRUE_PRES_6250 6250.0
#define BMP280_FLOAT_TRUE_PRES_2147483648 2147483648.0
/****************************************************/
/**\name TRUE PRESSURE CALUCULATION 64BIT RETURN */
/***************************************************/
#define BMP280_TRUE_PRES_128000 128000
#define BMP280_TRUE_PRES_1048576 1048576
#define BMP280_TRUE_PRES_3125 3125
#define BMP280_TRUE_PRES_1 1
/**************************************************************/
/**\name CHIP ID */
/**************************************************************/
#define BMP280_CHIP_ID 0x58
/**************************************************************/
/**\name STRUCTURE DEFINITIONS */
/**************************************************************/
// This structure holds all device specific calibration parameters
struct _bmp280_calib_par
{
uint16_t dig_T1; /**<calibration T1 data*/
int16_t dig_T2; /**<calibration T2 data*/
int16_t dig_T3; /**<calibration T3 data*/
uint16_t dig_P1; /**<calibration P1 data*/
int16_t dig_P2; /**<calibration P2 data*/
int16_t dig_P3; /**<calibration P3 data*/
int16_t dig_P4; /**<calibration P4 data*/
int16_t dig_P5; /**<calibration P5 data*/
int16_t dig_P6; /**<calibration P6 data*/
int16_t dig_P7; /**<calibration P7 data*/
int16_t dig_P8; /**<calibration P8 data*/
int16_t dig_P9; /**<calibration P9 data*/
int32_t t_fine; /**<calibration t_fine data*/
};
// This structure holds BMP280 initialization parameters
struct _bmp280
{
struct _twi_desc* twid;
struct _bmp280_calib_par calpar; /**<calibration data*/
uint8_t chip_id; /**< chip id of the sensor*/
uint8_t dev_addr; /**< device address of the sensor*/
uint8_t overs_temp; /**< temperature over sampling*/
uint8_t overs_pres; /**< pressure over sampling*/
void(*delay_msec)(uint16_t); /**< delay function pointer*/
};
/**************************************************************/
/**\name FUNCTION DECLARATIONS */
/**************************************************************/
static uint8_t _bmp280_read(struct _bmp280* bmp280, uint8_t* buffer, uint32_t len);
static uint8_t _bmp280_write(struct _bmp280* bmp280, const uint8_t* buffer, uint32_t len);
uint8_t bmp280_write_register(struct _bmp280* bmp280, uint8_t addr, uint8_t* pdata, uint8_t len);
uint8_t bmp280_read_register(struct _bmp280* bmp280, uint8_t addr, uint8_t* pdata, uint8_t len);
uint8_t bmp280_read_uncompensed_temperature (struct _bmp280* bmp280, int32_t* uncT);
int32_t bmp280_compensate_temperatureC (struct _bmp280* bmp280, int32_t uncT);
uint8_t bmp280_read_uncompensed_pressure (struct _bmp280* bmp280, int32_t* uncP);
uint32_t bmp280_compensate_pressureP (struct _bmp280* bmp280, int32_t uncP);
uint8_t bmp280_read_uncompensed_pressure_temperature (struct _bmp280* bmp280, int32_t* uncP, int32_t* uncT);
uint8_t bmp280_read_pressure_temperature (struct _bmp280* bmp280, uint32_t* pressure, int32_t* temperature);
uint8_t bmp280_get_calpar (struct _bmp280* bmp280);
uint8_t bmp280_get_overs_temp (struct _bmp280* bmp280, uint8_t* value);
uint8_t bmp280_set_overs_temp (struct _bmp280* bmp280, uint8_t value);
uint8_t bmp280_get_overs_pres (struct _bmp280* bmp280, uint8_t* value);
uint8_t bmp280_set_overs_pres (struct _bmp280* bmp280, uint8_t value);
uint8_t bmp280_get_power_mode(struct _bmp280* bmp280, uint8_t* power_mode);
uint8_t bmp280_set_power_mode (struct _bmp280* bmp280, uint8_t power_mode);
uint8_t bmp280_set_soft_rst (struct _bmp280* bmp280);
uint8_t bmp280_get_spi3 (struct _bmp280* bmp280, uint8_t* enable_disable);
uint8_t bmp280_set_spi3 (struct _bmp280* bmp280, uint8_t enable_disable);
uint8_t bmp280_get_filter (struct _bmp280* bmp280, uint8_t *value);
uint8_t bmp280_set_filter (struct _bmp280* bmp280, uint8_t value);
uint8_t bmp280_get_standby_durn(struct _bmp280* bmp280, uint8_t* standby_durn);
uint8_t bmp280_set_standby_durn (struct _bmp280* bmp280, uint8_t standby_durn);
uint8_t bmp280_set_work_mode (struct _bmp280* bmp280, uint8_t work_mode);
uint8_t bmp280_get_forced_uncP_temperature(struct _bmp280* bmp280, int32_t* uncP, int32_t* uncT);
uint8_t bmp280_read_id_get_calib_param (struct _bmp280* bmp280);
/**************************************************************/
/**\name FUNCTION FOR TRUE TEMPERATURE CALCULATION */
/**************************************************************/
#ifdef BMP280_ENABLE_FLOAT
double bmp280_compensate_T_double(struct _bmp280* bmp280, int32_t uncT);
double bmp280_compensate_P_double(struct _bmp280* bmp280, int32_t uncP);
#endif
#if defined(BMP280_ENABLE_INT64) && defined(BMP280_64BITSUPPORT_PRESENT)
uint32_t bmp280_compensate_P_int64(struct _bmp280* bmp280, int32_t uncP);
#endif
/**************************************************************/
/**\name FUNCTION FOR DELAY CALCULATION DURING FORCEMODE */
/**************************************************************/
uint8_t bmp280_compute_wait_time (struct _bmp280* bmp280, uint8_t* delaytimer);
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
#endif

View file

@ -0,0 +1,372 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* Implements CONSOLE.
*
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "board.h"
#include "chip.h"
#include "misc/console.h"
#include "peripherals/pio.h"
#include "peripherals/pmc.h"
#include "peripherals/uart.h"
#include <stdio.h>
/*----------------------------------------------------------------------------
* Variables
*----------------------------------------------------------------------------*/
typedef void (*_init_handler) (void*,uint32_t,uint32_t);
typedef void (*_put_char_handler) (void*, uint8_t);
typedef uint32_t (*_get_char_handler) (void*);
typedef uint32_t (*_rx_ready_handler) (void*);
typedef void (*_enable_it_handler) (void*,uint32_t);
/* Initialize console structure according to board configuration */
#if CONSOLE_DRIVER == DRV_USART
#include "peripherals/usart.h"
static const struct _console console = {
CONSOLE_PER_ADD,
(_init_handler) usart_configure,
(_put_char_handler) usart_put_char,
(_get_char_handler) usart_get_char,
(_rx_ready_handler) usart_is_rx_ready,
(_enable_it_handler) usart_enable_it
};
#elif CONSOLE_DRIVER == DRV_UART
#include "peripherals/uart.h"
static const struct _console console = {
CONSOLE_PER_ADD,
(_init_handler) uart_configure,
(_put_char_handler) uart_put_char,
(_get_char_handler) uart_get_char,
(_rx_ready_handler) uart_is_rx_ready,
(_enable_it_handler) uart_set_int
};
#elif CONSOLE_DRIVER == DRV_DBGU
#include "peripherals/dbgu.h"
static const struct _console console = {
CONSOLE_PER_ADD,
(_init_handler) dbgu_configure,
(_put_char_handler) dbgu_put_char,
(_get_char_handler) dbgu_get_char,
(_rx_ready_handler) dbgu_is_rx_ready,
(_enable_it_handler) dbgu_enable_it
};
#endif
/** Pins for CONSOLE */
static const struct _pin pinsConsole[] = PINS_CONSOLE;
/** Console initialize status */
static uint8_t _bConsoleIsInitialized = 0;
/*------------------------------------------------------------------------------
* Exported functions
*------------------------------------------------------------------------------*/
/**
* \brief Configures a CONSOLE peripheral with the specified parameters.
*
* \param baudrate Baudrate at which the CONSOLE should operate (in Hz).
*/
void console_configure(uint32_t baudrate)
{
/* Configure PIO */
pio_configure(pinsConsole, ARRAY_SIZE(pinsConsole));
pmc_enable_peripheral(CONSOLE_ID);
uint32_t mode;
#if CONSOLE_DRIVER != DRV_DBGU
mode = US_MR_CHMODE_NORMAL | US_MR_PAR_NO | US_MR_CHRL_8_BIT;
#else
mode = US_MR_CHMODE_NORMAL | US_MR_PAR_NO;
#endif
#if CONSOLE_DRIVER == DRV_UART
uint32_t mr;
mr = mode & US_MR_FILTER ? UART_MR_FILTER_ENABLED
: UART_MR_FILTER_DISABLED;
mr |= UART_MR_PAR((mode & US_MR_PAR_Msk) >> US_MR_PAR_Pos);
if ((mode & US_MR_USCLKS_Msk) == US_MR_USCLKS_PMC_PCK)
mr |= UART_MR_BRSRCCK_PMC_PCK;
else
mr |= UART_MR_BRSRCCK_PERIPH_CLK;
mr |= UART_MR_CHMODE((mode & US_MR_CHMODE_Msk) >> US_MR_CHMODE_Pos);
mode = mr;
#endif
/* Initialize driver to use */
console.init(console.addr, mode, baudrate);
/* Finally */
_bConsoleIsInitialized = 1;
}
/**
* \brief Outputs a character on the CONSOLE line.
*
* \note This function is synchronous (i.e. uses polling).
* \param c Character to send.
*/
void console_put_char(uint8_t c)
{
if (!_bConsoleIsInitialized)
console_configure(CONSOLE_BAUDRATE);
console.put_char(console.addr, c);
}
/**
* \brief Input a character from the CONSOLE line.
*
* \note This function is synchronous
* \return character received.
*/
extern uint32_t console_get_char(void)
{
if (!_bConsoleIsInitialized)
console_configure(CONSOLE_BAUDRATE);
return console.get_char(console.addr);
}
/**
* \brief Check if there is Input from DBGU line.
*
* \return true if there is Input.
*/
extern uint32_t console_is_rx_ready(void)
{
if (!_bConsoleIsInitialized)
console_configure(CONSOLE_BAUDRATE);
return console.is_rx_ready(console.addr);
}
/**
* Displays the content of the given frame on the DBGU.
*
* \param pucFrame Pointer to the frame to dump.
* \param size Buffer size in bytes.
*/
void console_dump_frame(uint8_t * pframe, uint32_t size)
{
uint32_t dw;
for (dw = 0; dw < size; dw++) {
printf("%02X ", pframe[dw]);
}
printf("\n\r");
}
/**
* Displays the content of the given buffer on the DBGU.
*
* \param pbuffer Pointer to the buffer to dump.
* \param size Buffer size in bytes.
* \param address Start address to display
*/
void console_dump_memory(uint8_t * pbuffer, uint32_t size,
uint32_t address)
{
uint32_t i, j;
uint32_t last_line_start;
uint8_t *tmp;
for (i = 0; i < (size / 16); i++) {
printf("0x%08X: ", (unsigned int)(address + (i * 16)));
tmp = (uint8_t *) & pbuffer[i * 16];
for (j = 0; j < 4; j++) {
printf("%02X%02X%02X%02X ", tmp[0], tmp[1], tmp[2],
tmp[3]);
tmp += 4;
}
tmp = (uint8_t *) & pbuffer[i * 16];
for (j = 0; j < 16; j++) {
console_put_char(*tmp++);
}
printf("\n\r");
}
if ((size % 16) != 0) {
last_line_start = size - (size % 16);
printf("0x%08X: ", (unsigned int)(address + last_line_start));
for (j = last_line_start; j < last_line_start + 16; j++) {
if ((j != last_line_start) && (j % 4 == 0)) {
printf(" ");
}
if (j < size)
printf("%02X", pbuffer[j]);
else
printf(" ");
}
printf(" ");
for (j = last_line_start; j < size; j++) {
console_put_char(pbuffer[j]);
}
printf("\n\r");
}
}
/**
* Reads an integer
*
* \param pvalue Pointer to the uint32_t variable to contain the input value.
*/
extern uint32_t console_get_integer(uint32_t * pvalue)
{
uint8_t key;
uint8_t nb = 0;
uint32_t value = 0;
while (1) {
key = console_get_char();
console_put_char(key);
if (key >= '0' && key <= '9') {
value = (value * 10) + (key - '0');
nb++;
} else {
if (key == 0x0D || key == ' ') {
if (nb == 0) {
printf
("\n\rWrite a number and press ENTER or SPACE!\n\r");
return 0;
} else {
printf("\n\r");
*pvalue = value;
return 1;
}
} else {
printf("\n\r'%c' not a number!\n\r", key);
return 0;
}
}
}
}
/**
* Reads an integer and check the value
*
* \param pvalue Pointer to the uint32_t variable to contain the input value.
* \param dwMin Minimum value
* \param dwMax Maximum value
*/
extern uint32_t console_get_integer_min_max(uint32_t * pvalue, uint32_t min,
uint32_t max)
{
uint32_t value = 0;
if (console_get_integer(&value) == 0)
return 0;
if (value < min || value > max) {
printf("\n\rThe number have to be between %u and %u\n\r",
(unsigned int)min, (unsigned int)max);
return 0;
}
printf("\n\r");
*pvalue = value;
return 1;
}
void console_enable_interrupts(uint32_t mask)
{
console.enable_interrupts(console.addr, mask);
}
/**
* Reads an hexadecimal number
*
* \param pvalue Pointer to the uint32_t variable to contain the input value.
*/
extern uint32_t console_get_hexa_32(uint32_t * pvalue)
{
uint8_t key;
uint32_t dw = 0;
uint32_t value = 0;
for (dw = 0; dw < 8; dw++) {
key = console_get_char();
console_put_char(key);
if (key >= '0' && key <= '9') {
value = (value * 16) + (key - '0');
} else {
if (key >= 'A' && key <= 'F') {
value = (value * 16) + (key - 'A' + 10);
} else {
if (key >= 'a' && key <= 'f') {
value = (value * 16) + (key - 'a' + 10);
} else {
printf
("\n\rIt is not a hexa character!\n\r");
return 0;
}
}
}
}
printf("\n\r");
*pvalue = value;
return 1;
}
void console_clear_screen(void)
{
printf("\033[2J\033[0;0f");
}
void console_reset_cursor(void)
{
printf("\033[0;0f");
}
void console_echo(uint8_t c)
{
switch (c) {
case '\r':
case '\n':
printf("\r\n");
break;
case 0x7F:
printf("\033[1D\033[K");
break;
case '\b':
printf("\033[1D\033[K");
break;
default:
console_put_char(c);
}
}

View file

@ -0,0 +1,74 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
#ifndef _CONSOLE_H_
#define _CONSOLE_H_
/*-----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include <stdint.h>
#define DRV_UART (1)
#define DRV_USART (2)
#define DRV_DBGU (3)
//#define DRV_FLEXCOM (4)
struct _console {
void* addr;
void (*init)(void*, uint32_t, uint32_t);
void (*put_char)(void*, uint8_t);
uint32_t (*get_char)(void*);
uint32_t (*is_rx_ready)(void*);
void (*enable_interrupts)(void*, uint32_t);
};
/* ----------------------------------------------------------------------------
* Global function
* ---------------------------------------------------------------------------*/
extern void console_configure(uint32_t baudrate);
extern void console_put_char(uint8_t uc);
extern uint32_t console_get_char(void);
extern uint32_t console_is_rx_ready(void);
extern void console_enable_interrupts(uint32_t mask);
extern void console_dump_frame(uint8_t * pframe, uint32_t size);
extern void console_dump_memory(uint8_t * pbuffer, uint32_t size,
uint32_t address);
extern uint32_t console_get_integer(uint32_t * pvalue);
extern uint32_t console_get_integer_min_max(uint32_t * pvalue, uint32_t min,
uint32_t max);
extern uint32_t console_get_hexa_32(uint32_t * pvalue);
extern void console_echo(uint8_t c);
extern void console_clear_screen(void);
extern void console_reset_cursor(void);
#endif /* _CONSOLE_H_ */

View file

@ -0,0 +1,149 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*/
/*------------------------------------------------------------------------------
* Headers
*------------------------------------------------------------------------------*/
#include "board.h"
#include "misc/led.h"
#include "peripherals/pio.h"
/*------------------------------------------------------------------------------
* Local Variables
*------------------------------------------------------------------------------*/
#ifdef PINS_LEDS
static const struct _pin pinsLeds[] = PINS_LEDS;
static const uint32_t numLeds = ARRAY_SIZE(pinsLeds);
#endif
/*------------------------------------------------------------------------------
* Global Functions
*------------------------------------------------------------------------------*/
/**
* Configures the pin associated with the given LED number. If the LED does
* not exist on the board, the function does nothing.
* \param dwLed Number of the LED to configure.
* \return 1 if the LED exists and has been configured; otherwise 0.
*/
extern uint32_t led_configure (uint32_t led)
{
#ifdef PINS_LEDS
// Check that LED exists
if (led >= numLeds) {
return 0;
}
// Configure LED
return pio_configure(&pinsLeds[led], 1);
#else
return 0;
#endif
}
/**
* Turns the given LED on if it exists; otherwise does nothing.
* \param dwLed Number of the LED to turn on.
* \return 1 if the LED has been turned on; 0 otherwise.
*/
extern uint32_t led_set(uint32_t led)
{
#ifdef PINS_LEDS
/* Check if LED exists */
if (led >= numLeds) {
return 0;
}
/* Turn LED on */
if (pinsLeds[led].type == PIO_OUTPUT_0) {
pio_set(&pinsLeds[led]);
} else {
pio_clear(&pinsLeds[led]);
}
return 1;
#else
return 0;
#endif
}
/**
* Turns a LED off.
*
* \param dwLed Number of the LED to turn off.
* \return 1 if the LED has been turned off; 0 otherwise.
*/
extern uint32_t led_clear (uint32_t led)
{
#ifdef PINS_LEDS
/* Check if LED exists */
if (led >= numLeds) {
return 0;
}
/* Turn LED off */
if (pinsLeds[led].type == PIO_OUTPUT_0) {
pio_clear(&pinsLeds[led]);
} else {
pio_set(&pinsLeds[led]);
}
return 1;
#else
return 0;
#endif
}
/**
* Toggles the current state of a LED.
*
* \param dwLed Number of the LED to toggle.
* \return 1 if the LED has been toggled; otherwise 0.
*/
extern uint32_t led_toggle(uint32_t led)
{
#ifdef PINS_LEDS
/* Check if LED exists */
if (led >= numLeds) {
return 0;
}
/* Toggle LED */
if (pio_get_output_data_status(&pinsLeds[led])) {
pio_clear(&pinsLeds[led]);
} else {
pio_set(&pinsLeds[led]);
}
return 1;
#else
return 0;
#endif
}

View file

@ -0,0 +1,68 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* \section Purpose
*
* Small set of functions for simple and portable LED usage.
*
* \section Usage
*
* -# Configure one or more LEDs using led_configure and
* LED_ConfigureAll.
* -# Set, clear and toggle LEDs using led_set, led_clear and
* led_toggle.
*
* LEDs are numbered starting from 0; the number of LEDs depend on the
* board being used. All the functions defined here will compile properly
* regardless of whether the LED is defined or not; they will simply
* return 0 when a LED which does not exist is given as an argument.
* Also, these functions take into account how each LED is connected on to
* board; thus, \ref led_set might change the level on the corresponding pin
* to 0 or 1, but it will always light the LED on; same thing for the other
* methods.
*/
#ifndef _LED_
#define _LED_
#include <stdint.h>
//------------------------------------------------------------------------------
// Global Functions
//------------------------------------------------------------------------------
extern uint32_t led_configure(uint32_t led);
extern uint32_t led_set(uint32_t led);
extern uint32_t led_clear(uint32_t led);
extern uint32_t led_toggle(uint32_t led);
#endif /* #ifndef LED_H */

View file

@ -0,0 +1,74 @@
# ----------------------------------------------------------------------------
# SAM Software Package License
# ----------------------------------------------------------------------------
# Copyright (c) 2015, Atmel Corporation
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# - Redistributions of source code must retain the above copyright notice,
# this list of conditions and the disclaimer below.
#
# Atmel's name may not be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# DISCLAIMER: 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
# 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.
# ----------------------------------------------------------------------------
drivers-y += drivers/peripherals/adc.o
drivers-y += drivers/peripherals/aes.o
drivers-y += drivers/peripherals/aic.o
drivers-y += drivers/peripherals/gmacd.o
drivers-y += drivers/peripherals/gmac.o
drivers-y += drivers/peripherals/l2cc.o
drivers-y += drivers/peripherals/matrix.o
drivers-y += drivers/peripherals/mpddrc.o
drivers-y += drivers/peripherals/pit.o
drivers-y += drivers/peripherals/pmc.o
drivers-y += drivers/peripherals/pmecc.o
drivers-y += drivers/peripherals/pmecc_gallois_field_512.o
drivers-y += drivers/peripherals/pmecc_gallois_field_1024.o
drivers-y += drivers/peripherals/pwmc.o
drivers-y += drivers/peripherals/rstc.o
drivers-y += drivers/peripherals/rtc.o
drivers-y += drivers/peripherals/sha.o
drivers-y += drivers/peripherals/hsmc.o
drivers-y += drivers/peripherals/spid.o
drivers-y += drivers/peripherals/spi.o
drivers-y += drivers/peripherals/tc.o
drivers-y += drivers/peripherals/tdes.o
drivers-y += drivers/peripherals/trng.o
drivers-y += drivers/peripherals/twid_legacy.o
drivers-y += drivers/peripherals/twi.o
drivers-y += drivers/peripherals/uart.o
drivers-y += drivers/peripherals/usartd.o
drivers-y += drivers/peripherals/usart_iso7816_4.o
drivers-y += drivers/peripherals/usart.o
drivers-y += drivers/peripherals/wdt.o
drivers-y += drivers/peripherals/xdmac.o
drivers-y += drivers/peripherals/xdmad.o
drivers-$(CONFIG_HAVE_FLEXCOM) += drivers/peripherals/flexcom.o
drivers-$(CONFIG_HAVE_USART_LIN) += drivers/peripherals/usart_lin.o
drivers-$(CONFIG_HAVE_PIO4) += drivers/peripherals/pio4.o
drivers-$(CONFIG_HAVE_QSPI) += drivers/peripherals/qspi.o
drivers-$(CONFIG_HAVE_MCAN) += drivers/peripherals/mcan.o
drivers-$(CONFIG_HAVE_SDMMC) += drivers/peripherals/sdmmc.o
drivers-$(CONFIG_SOC_SAMA5D2) += drivers/peripherals/acc.o
drivers-$(CONFIG_SOC_SAMA5D2) += drivers/peripherals/classd.o
drivers-$(CONFIG_SOC_SAMA5D2) += drivers/peripherals/isc.o
drivers-$(CONFIG_SOC_SAMA5D2) += drivers/peripherals/sfrbu.o
drivers-$(CONFIG_SOC_SAMA5D2) += drivers/peripherals/shdwc.o
drivers-$(CONFIG_SOC_SAMA5D2) += drivers/peripherals/twid.o

View file

@ -0,0 +1,135 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include "peripherals/acc.h"
/*----------------------------------------------------------------------------
* Types
*----------------------------------------------------------------------------*/
#define ACC_MR_INV_Pos 12 /* ACC invert output (reg offset) */
#define ACC_ACR_HYST_0mv_max 0x00 /* Hysteresis levels */
#define ACC_ACR_HYST_50mv_max 0x01
#define ACC_ACR_HYST_90mv_max 0x11
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
void acc_init(Acc *p_acc, uint32_t select_plus, uint32_t select_minus,
uint32_t edge_type, uint32_t invert)
{
/* Reset the controller */
p_acc->ACC_CR |= ACC_CR_SWRST;
/* Write to the MR register */
p_acc->ACC_MR = (((select_plus << ACC_MR_SELPLUS_Pos) & ACC_MR_SELPLUS_Msk) |
((select_minus << ACC_MR_SELMINUS_Pos) & ACC_MR_SELMINUS_Msk) |
((edge_type << ACC_MR_EDGETYP_Pos) & ACC_MR_EDGETYP_Msk) |
((invert << ACC_MR_INV_Pos) & ACC_MR_INV));
/* Set hysteresis and current selection (ISEL) */
p_acc->ACC_ACR = (ACC_ACR_ISEL_HISP | ACC_ACR_HYST(ACC_ACR_HYST_50mv_max));
/* Automatic Output Masking Period */
while (p_acc->ACC_ISR & (uint32_t)ACC_ISR_MASK) ;
}
void acc_enable(Acc *p_acc)
{
p_acc->ACC_MR |= ACC_MR_ACEN_EN;
}
void acc_disable(Acc *p_acc)
{
p_acc->ACC_MR &= ~ACC_MR_ACEN_EN;
}
void acc_reset(Acc *p_acc)
{
p_acc->ACC_CR = ACC_CR_SWRST;
}
void acc_set_input(Acc *p_acc, uint32_t select_minus, uint32_t select_plus)
{
p_acc->ACC_MR &= ~(ACC_MR_SELMINUS_Msk & ACC_MR_SELPLUS_Msk);
p_acc->ACC_MR |= select_plus | select_minus;
}
void acc_set_output(Acc *p_acc, uint32_t invert, uint32_t fault_enable,
uint32_t fault_source)
{
p_acc->ACC_MR &= ~(ACC_MR_INV_EN & ACC_MR_FE_EN & ACC_MR_SELFS_OUTPUT);
p_acc->ACC_MR |= invert | fault_source | fault_enable;
}
uint32_t acc_get_comparison_result(Acc *p_acc)
{
uint32_t temp = p_acc->ACC_MR;
uint32_t status = p_acc->ACC_ISR;
if ((temp & ACC_MR_INV_EN) == ACC_MR_INV_EN)
return status & ACC_ISR_SCO ? 0 : 1;
else
return status & ACC_ISR_SCO ? 1 : 0;
}
void acc_enable_interrupt(Acc *p_acc)
{
p_acc->ACC_IER = ACC_IER_CE;
}
void acc_disable_interrupt(Acc *p_acc)
{
p_acc->ACC_IDR = ACC_IDR_CE;
}
uint32_t acc_get_interrupt_status(Acc *p_acc)
{
return p_acc->ACC_ISR;
}
void acc_set_write_protect(Acc *p_acc, uint32_t enable)
{
if (enable)
p_acc->ACC_WPMR = ACC_WPMR_WPKEY_PASSWD | ACC_WPMR_WPEN;
else
p_acc->ACC_WPMR = ACC_WPMR_WPKEY_PASSWD;
}
uint32_t acc_get_write_protect_status(Acc *p_acc)
{
return p_acc->ACC_WPSR & ACC_WPSR_WPVS;
}

View file

@ -0,0 +1,143 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* Implementation of Analog Comparator Controller (ACC).
*
*/
#ifndef _ACC_H
#define _ACC_H
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include <stdint.h>
/*----------------------------------------------------------------------------
* Global functions
*----------------------------------------------------------------------------*/
/**
* \brief Initialize the Analog Comparator Controller.
* \param p_acc Pointer to an Acc instance.
* \param select_plus Input connected to inp, 0~7.
* \param select_minus Input connected to inm, 0~7.
* \param edge_type CF flag triggering mode
* Use pattern defined in the device header file.
* \param invert Invert comparator output.
*/
extern void acc_init(Acc *p_acc, uint32_t select_plus, uint32_t select_minus,
uint32_t edge_type, uint32_t invert);
/**
* \brief Enable the ACC.
* \param p_acc Pointer to ACC registers set instance.
*/
extern void acc_enable(Acc *p_acc);
/**
* \brief Disable the ACC.
* \param p_acc Pointer to ACC registers set instance.
*/
extern void acc_disable(Acc *p_acc);
/**
* \brief Reset the ACC.
* \param p_acc Pointer to ACC registers set instance.
*/
extern void acc_reset(Acc *p_acc);
/**
* \brief Set the input source.
* \param p_acc Pointer to ACC registers set instance.
* \param select_minus Selection for minus comparator input.
* \param select_plus Selection for plus comparator input.
*/
extern void acc_set_input(Acc *p_acc, uint32_t select_minus,
uint32_t select_plus);
/**
* \brief Set the output of the ACC.
* \param p_acc Pointer to ACC registers set instance.
* \param invert Invert comparator output, 0 for disable, 1 for enable.
* \param fault_enable Fault enable, 0 for disable, 1 for enable.
* \param fault_source Selection of fault source, 0 for CF, 1 for output.
*/
extern void acc_set_output(Acc *p_acc, uint32_t invert, uint32_t fault_enable,
uint32_t fault_source);
/**
* \brief Get the comparison result.
* \param p_acc Pointer to ACC registers set instance.
* \return Result of the comparison, 0 for inn > inp, 1 for inp > inn.
*/
extern uint32_t acc_get_comparison_result(Acc *p_acc);
/**
* \brief Enable the interrupt.
* \param p_acc Pointer to ACC registers set instance.
*/
extern void acc_enable_interrupt(Acc *p_acc);
/**
* \brief Disable the interrupt.
* \param p_acc Pointer to ACC registers set instance.
*/
extern void acc_disable_interrupt(Acc *p_acc);
/**
* \brief Get the interrupt status.
* \param p_acc Pointer to ACC registers set instance.
* \return Contents of the Interrupt Status Register.
*/
extern uint32_t acc_get_interrupt_status(Acc *p_acc);
/**
* \brief Write-protect the Mode Register and the Analog Control Register.
* \param p_acc Pointer to ACC registers set instance.
* \param enable 1 to enable, 0 to disable.
*/
extern void acc_set_write_protect(Acc *p_acc, uint32_t enable);
/**
* \brief Return write protect status.
* \param p_acc Pointer to ACC registers set instance.
* \retval 0 No write protection violation occurred.
* \retval 1 At least one write attempt to a write-protected register has been
* detected, since the previous call to this function.
*/
extern uint32_t acc_get_write_protect_status(Acc *p_acc);
#endif /* _ACC_H */

View file

@ -0,0 +1,639 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/** \addtogroup adc_module Working with ADC
* \ingroup peripherals_module
* \section Purpose
* The ADC driver provides the interface to configure and use the ADC peripheral.
* \n
*
* It converts the analog input to digital format. The converted result could be
* 12bit.
*
* To Enable a ADC conversion,the user has to follow these few steps:
* <ul>
* <li> Select an appropriate reference voltage on ADVREF </li>
* <li> Configure the ADC according to its requirements and special needs,which
* could be broken down into several parts:
* -# Select the resolution by setting or clearing ADC_MR_LOWRES bit in
* ADC_MR (Mode Register)
* -# Set ADC clock by setting ADC_MR_PRESCAL bits in ADC_MR, the clock is
* calculated with ADCClock = MCK / ( (PRESCAL+1) * 2 )
* -# Set Startup Time,Tracking Clock cycles and Transfer Clock respectively
* in ADC_MR.
</li>
* <li> Start conversion by setting ADC_CR_START in ADC_CR. </li>
* </ul>
*
* \section Usage
* <ul>
* <li> Initialize the ADC controller using adc_initialize().
* <li> ADC clock and timing configuration using adc_set_clock() and adc_set_timing().
* <li> For ADC trigger using adc_set_trigger(), adc_set_trigger_mode() and
* adc_set_trigger_period().
* <li> For ADC sequence mode using adc_set_sequence_mode(), adc_set_sequence() and
* adc_set_sequence_by_list().
* <li> For ADC compare mode using adc_set_compare_channel(), adc_set_compare_mode()
* and adc_set_comparison_window().
* <li> ADC works with touchscreen using adc_ts_calibration(), adc_set_ts_mode(),
* adc_set_ts_debounce(), adc_set_ts_pen_detect(), adc_set_ts_average(),
* adc_get_ts_xposition(), adc_get_ts_yposition() and adc_get_ts_pressure().
* </li>
* </ul>
*
* For more accurate information, please look at the ADC section of the
* Datasheet.
*
* Related files :\n
* \ref adc.c\n
* \ref adc.h\n
*/
/**
* \file
*
* Implementation of Analog-to-Digital Converter (ADC).
*
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include "peripherals/adc.h"
#include "peripherals/pmc.h"
#include "trace.h"
#include <stdio.h>
/*----------------------------------------------------------------------------
* Local definitions
*----------------------------------------------------------------------------*/
#ifndef ADC_MR_TRANSFER
/* for compatibility with older peripheral versions */
#define ADC_MR_TRANSFER(x) 0
#endif
/*----------------------------------------------------------------------------
* Local variables
*----------------------------------------------------------------------------*/
/** Current working clock */
static uint32_t _adc_clock = 0;
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
uint32_t adc_num_channels(void)
{
return ARRAY_SIZE(ADC->ADC_CDR);
}
/**
* \brief Initialize the ADC controller
*
*/
void adc_initialize(void)
{
/* Enable peripheral clock */
pmc_enable_peripheral(ID_ADC);
/* Reset the controller */
ADC->ADC_CR = ADC_CR_SWRST;
/* Reset Mode Register */
ADC->ADC_MR = 0;
}
/**
* \brief Set ADC clock.
*
* \param clk adc clock frequency
*
* \return ADC clock
*/
uint32_t adc_set_clock(uint32_t clk)
{
uint32_t prescale, mode_reg;
uint32_t mck = pmc_get_peripheral_clock(ID_ADC);
/* Formula for PRESCAL is:
ADCClock = MCK / ( (PRESCAL+1) * 2 )
PRESCAL = (MCK / (2 * ADCCLK)) + 1
First, we do the division, multiplied by 10 to get higher precision
If the last digit is not zero, we round up to avoid generating a higher
than required frequency. */
prescale = (mck * 5) / clk;
if (prescale % 10)
prescale = prescale / 10;
else {
if (prescale == 0)
return 0;
prescale = prescale / 10 - 1;
}
mode_reg = ADC_MR_PRESCAL(prescale);
if (mode_reg == 0)
return 0;
mode_reg |= (ADC->ADC_MR & ~ADC_MR_PRESCAL_Msk);
ADC->ADC_MR = mode_reg;
_adc_clock = mck / (prescale + 1) / 2;
//_adc_clock = _adc_clock / 1000 * 1000;
return _adc_clock;
}
void adc_enable_it(uint32_t mask)
{
ADC->ADC_IER |= mask;
}
void adc_disable_it(uint32_t mask)
{
ADC->ADC_IER &= ~mask;
}
/**
* \brief Set ADC timing.
*
* \param startup startup value
* \param tracking tracking value
* \param settling settling value
*/
void adc_set_timing(uint32_t startup, uint32_t tracking, uint32_t settling)
{
uint32_t mode_reg;
#ifndef CONFIG_HAVE_ADC_SETTLING_TIME
if (settling) {
settling = 0;
trace_warning("adc: Analog settling time not supported, IGNORED!\r\n");
}
#endif
mode_reg = ADC->ADC_MR;
mode_reg &= (~ADC_MR_STARTUP_Msk) & (~ADC_MR_TRACKTIM_Msk);
/* Formula:
* Startup Time = startup value / ADCClock
* Transfer Time = (TRANSFER * 2 + 3) / ADCClock
* Tracking Time = (TRACKTIM + 1) / ADCClock
* Settling Time = settling value / ADCClock
*/
mode_reg |= ADC_MR_STARTUP(startup);
mode_reg |= ADC_MR_TRACKTIM(tracking);
mode_reg |= ADC_MR_TRANSFER(2);
#ifdef CONFIG_HAVE_ADC_SETTLING_TIME
mode_reg |= ADC_MR_SETTLING(settling);
#endif
ADC->ADC_MR |= mode_reg;
}
void adc_set_trigger_mode(uint32_t mode)
{
uint32_t trg_reg = ADC->ADC_TRGR & ~ADC_TRGR_TRGMOD_Msk;
ADC->ADC_TRGR = trg_reg | mode;
}
void adc_set_sleep_mode(uint8_t enable)
{
if (enable) {
ADC->ADC_MR |= ADC_MR_SLEEP;
} else {
ADC->ADC_MR &= ~ADC_MR_SLEEP;
}
}
/**
* \brief Enable/Disable seqnence mode.
*
* \param enable Enable/Disable seqnence mode.
*/
void adc_set_sequence_mode(uint8_t enable)
{
if (enable) {
/* User Sequence Mode: The sequence respects what is defined in
ADC_SEQR1 and ADC_SEQR2 */
ADC->ADC_MR |= ADC_MR_USEQ;
} else {
/* Normal Mode: The controller converts channels in a simple numeric order. */
ADC->ADC_MR &= ~ADC_MR_USEQ;
}
}
/**
* \brief Set channel sequence.
*
* \param seq1 Sequence 1 ~ 8 channel number.
* \param seq2 Sequence 9 ~ 16 channel number.
*/
void adc_set_sequence(uint32_t seq1, uint32_t seq2)
{
ADC->ADC_SEQR1 = seq1;
#ifdef CONFIG_HAVE_ADC_SEQ_REG2
ADC->ADC_SEQR2 = seq2;
#endif
}
/**
* \brief Set channel sequence by given channel list.
*
* \param channel_list Channel list.
* \param len Number of channels in list.
*/
void adc_set_sequence_by_list(uint8_t channel_list[], uint8_t len)
{
uint8_t i;
uint8_t shift;
if (len <= 8) {
ADC->ADC_SEQR1 = 0;
for (i = 0, shift = 0; i < len; i++, shift += 4) {
if (i >= len) return;
ADC->ADC_SEQR1 |= channel_list[i] << shift;
}
}
else {
ADC->ADC_SEQR1 = 0;
for (i = 0, shift = 0; i < 8; i++, shift += 4) {
if (i >= len) return;
ADC->ADC_SEQR1 |= channel_list[i] << shift;
}
#ifdef CONFIG_HAVE_ADC_SEQ_REG2
ADC->ADC_SEQR2 = 0;
for (i = 0, shift = 0; i < (len-8); i++, shift += 4) {
if (i >= len) return;
ADC->ADC_SEQR2 |= channel_list[8+i] << shift;
}
#endif
}
}
void adc_set_tag_enable(uint8_t enable)
{
if (enable) {
ADC->ADC_EMR |= ADC_EMR_TAG;
} else {
ADC->ADC_EMR &= ~ADC_EMR_TAG;
}
}
/**
* \brief Set compare channel.
*
* \param channel channel number to be set, xx for all channels
*/
void adc_set_compare_channel(uint32_t channel)
{
assert(channel <= adc_num_channels());
if (channel < adc_num_channels()) {
ADC->ADC_EMR &= ~(ADC_EMR_CMPALL);
ADC->ADC_EMR &= ~(ADC_EMR_CMPSEL_Msk);
ADC->ADC_EMR |= (channel << ADC_EMR_CMPSEL_Pos);
} else {
ADC->ADC_EMR |= ADC_EMR_CMPALL;
}
}
/**
* \brief Set compare mode.
*
* \param mode compare mode
*/
void adc_set_compare_mode(uint32_t mode)
{
ADC->ADC_EMR &= ~(ADC_EMR_CMPMODE_Msk);
ADC->ADC_EMR |= (mode & ADC_EMR_CMPMODE_Msk);
}
void adc_set_comparison_window(uint32_t window)
{
ADC->ADC_CWR = window;
}
uint8_t adc_check_configuration(void)
{
uint32_t mode_reg;
uint32_t prescale;
uint32_t clock;
uint32_t mck = pmc_get_peripheral_clock(ID_ADC);
mode_reg = ADC->ADC_MR;
prescale = (mode_reg & ADC_MR_PRESCAL_Msk) >> ADC_MR_PRESCAL_Pos;
/* Formula: ADCClock = MCK / ( (PRESCAL+1) * 2 ) */
clock = mck / ((prescale + 1) * 2);
if (clock > ADC_CLOCK_MAX) {
printf ("ADC clock is too high (out of specification: %d Hz)\r\n",
(int) ADC_CLOCK_MAX);
return 1;
}
return 0;
}
uint32_t adc_get_converted_data(uint32_t channel)
{
assert(channel < adc_num_channels());
if (channel < adc_num_channels()) {
return ADC->ADC_CDR[channel];
} else {
return 0;
}
}
void adc_set_startup_time(uint32_t startup)
{
uint32_t start;
uint32_t mode_reg;
if (_adc_clock == 0)
return;
/* Formula for STARTUP is:
STARTUP = (time x ADCCLK) / (1000000) - 1
Division multiplied by 10 for higher precision */
start = (startup * _adc_clock) / (100000);
if (start % 10)
start /= 10;
else {
start /= 10;
if (start)
start--;
}
if (start > 896)
mode_reg = ADC_MR_STARTUP_SUT960;
else if (start > 832)
mode_reg = ADC_MR_STARTUP_SUT896;
else if (start > 768)
mode_reg = ADC_MR_STARTUP_SUT832;
else if (start > 704)
mode_reg = ADC_MR_STARTUP_SUT768;
else if (start > 640)
mode_reg = ADC_MR_STARTUP_SUT704;
else if (start > 576)
mode_reg = ADC_MR_STARTUP_SUT640;
else if (start > 512)
mode_reg = ADC_MR_STARTUP_SUT576;
else if (start > 112)
mode_reg = ADC_MR_STARTUP_SUT512;
else if (start > 96)
mode_reg = ADC_MR_STARTUP_SUT112;
else if (start > 80)
mode_reg = ADC_MR_STARTUP_SUT96;
else if (start > 64)
mode_reg = ADC_MR_STARTUP_SUT80;
else if (start > 24)
mode_reg = ADC_MR_STARTUP_SUT64;
else if (start > 16)
mode_reg = ADC_MR_STARTUP_SUT24;
else if (start > 8)
mode_reg = ADC_MR_STARTUP_SUT16;
else if (start > 0)
mode_reg = ADC_MR_STARTUP_SUT8;
else
mode_reg = ADC_MR_STARTUP_SUT0;
mode_reg |= ADC->ADC_MR & ~ADC_MR_STARTUP_Msk;
ADC->ADC_MR = mode_reg;
}
#ifdef CONFIG_HAVE_ADC_INPUT_OFFSET
/**
* \brief Enable differential input for the specified channel.
*
* \param channel ADC channel number.
*/
void adc_enable_channel_differential_input (uint32_t channel)
{
/* (ADC_COR) Differential Inputs for Channel n */
ADC->ADC_COR |= 0x01u << (16 + channel);
}
/**
* \brief Disable differential input for the specified channel.
*
* \param channel ADC channel number.
*/
void adc_disable_channel_differential_input(uint32_t channel)
{
uint32_t temp;
temp = ADC->ADC_COR;
ADC->ADC_COR &= 0xFFFEFFFFu << channel;
ADC->ADC_COR |= temp;
}
/**
* \brief Enable analog signal offset for the specified channel.
*
* \param channel ADC channel number.
*/
void adc_enable_channel_input_offset (uint32_t channel)
{
ADC->ADC_COR |= 0x01u << channel;
}
/**
* \brief Disable analog signal offset for the specified channel.
*
* \param channel ADC channel number.
*/
void adc_disable_channel_input_offset (uint32_t channel)
{
uint32_t temp;
temp = ADC->ADC_COR;
ADC->ADC_COR &= (0xFFFFFFFEu << channel);
ADC->ADC_COR |= temp;
}
#endif /* CONFIG_HAVE_ADC_INPUT_OFFSET */
#ifdef CONFIG_HAVE_ADC_INPUT_GAIN
/**
* \brief Configure input gain for the specified channel.
*
* \param channel ADC channel number.
* \param gain Gain value for the input.
*/
void adc_set_channel_input_gain (uint32_t channel, uint32_t gain)
{
assert(gain < 3);
uint32_t temp;
temp = ADC->ADC_CGR;
temp |= gain << (2 * channel);
ADC->ADC_CGR = temp;
}
#endif /* CONFIG_HAVE_ADC_INPUT_GAIN */
void adc_set_tracking_time(uint32_t dwNs)
{
uint32_t dwShtim;
uint32_t mode_reg;
if (_adc_clock == 0)
return;
/* Formula for SHTIM is:
SHTIM = (time x ADCCLK) / (1000000000) - 1
Since 1 billion is close to the maximum value for an integer, we first
divide ADCCLK by 1000 to avoid an overflow */
dwShtim = (dwNs * (_adc_clock / 1000)) / 100000;
if (dwShtim % 10)
dwShtim /= 10;
else {
dwShtim /= 10;
if (dwShtim)
dwShtim--;
}
mode_reg = ADC_MR_TRACKTIM(dwShtim);
mode_reg |= ADC->ADC_MR & ~ADC_MR_TRACKTIM_Msk;
ADC->ADC_MR = mode_reg;
}
void adc_set_trigger_period(uint32_t period)
{
uint32_t trg_period;
uint32_t trg_reg;
if (_adc_clock == 0)
return;
trg_period = period * (_adc_clock/1000) - 1;
trg_reg = ADC->ADC_TRGR & ~ADC_TRGR_TRGPER_Msk;
trg_reg |= ADC_TRGR_TRGPER(trg_period);
ADC->ADC_TRGR = trg_reg;
}
void adc_ts_calibration(void)
{
ADC->ADC_CR = ADC_CR_TSCALIB;
}
void adc_set_ts_mode(uint32_t mode)
{
ADC->ADC_TSMR = (ADC->ADC_TSMR & ~ADC_TSMR_TSMODE_Msk) | mode;
}
void adc_configure_ext_mode(uint32_t mode)
{
ADC->ADC_EMR = mode;
}
void adc_set_ts_debounce(uint32_t time)
{
uint32_t div = 1000000000;
uint32_t clk = _adc_clock;
uint32_t dwPenbc = 0;
uint32_t target, current;
uint32_t tsmr;
if (time == 0 || _adc_clock == 0)
return;
/* Divide time & ADCCLK to avoid overflows */
while ((div > 1) && ((time % 10) == 0)) {
time /= 10;
div /= 10;
}
while ((div > 1) && ((clk & 10) == 0)) {
clk /= 10;
div /= 10;
}
/* Compute PENDBC */
target = time * clk / div;
current = 1;
while (current < target) {
dwPenbc++;
current *= 2;
}
tsmr = ADC_TSMR_PENDBC(dwPenbc);
if (tsmr == 0)
return;
tsmr |= ADC->ADC_TSMR & ~ADC_TSMR_PENDBC_Msk;
ADC->ADC_TSMR = tsmr;
}
void adc_set_ts_pen_detect(uint8_t enable)
{
if (enable)
ADC->ADC_TSMR |= ADC_TSMR_PENDET;
else
ADC->ADC_TSMR &= ~ADC_TSMR_PENDET;
}
void adc_set_ts_average(uint32_t avg_2_conv)
{
uint32_t mode_reg = ADC->ADC_TSMR & ~ADC_TSMR_TSAV_Msk;
uint32_t ts_av = avg_2_conv >> ADC_TSMR_TSAV_Pos;
uint32_t ts_freq = (mode_reg & ADC_TSMR_TSFREQ_Msk) >> ADC_TSMR_TSFREQ_Pos;
if (ts_av) {
if (ts_av > ts_freq) {
mode_reg &= ~ADC_TSMR_TSFREQ_Msk;
mode_reg |= ADC_TSMR_TSFREQ(ts_av);
}
}
ADC->ADC_TSMR = mode_reg | avg_2_conv;
}
uint32_t adc_get_ts_xposition(void)
{
return ADC->ADC_XPOSR;
}
uint32_t adc_get_ts_yposition(void)
{
return ADC->ADC_YPOSR;
}
uint32_t adc_get_ts_pressure(void)
{
return ADC->ADC_PRESSR;
}
void adc_set_trigger(uint32_t trigger)
{
uint32_t mode_reg;
mode_reg = ADC->ADC_MR;
mode_reg &= ~ADC_MR_TRGSEL_Msk;
mode_reg |= trigger;
ADC->ADC_MR |= mode_reg;
}
#ifdef CONFIG_HAVE_ADC_LOW_RES
void adc_set_low_resolution(uint8_t enable)
{
if (enable) {
ADC->ADC_MR |= ADC_MR_LOWRES;
} else {
ADC->ADC_MR &= ~ADC_MR_LOWRES;
}
}
#endif

View file

@ -0,0 +1,399 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* \section Purpose
*
* Interface for configuration the Analog-to-Digital Converter (ADC) peripheral.
*
* \section Usage
*
* -# Configurate the pins for ADC.
* -# Initialize the ADC with adc_initialize().
* -# Set ADC clock and timing with adc_set_clock() and adc_set_timing().
* -# Select the active channel using adc_enable_channel().
* -# Start the conversion with adc_start_conversion().
* -# Wait the end of the conversion by polling status with adc_get_status().
* -# Finally, get the converted data using adc_get_converted_data() or adc_get_last_converted_data().
*
*/
#ifndef _ADC_
#define _ADC_
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include <assert.h>
#include <stdint.h>
/*------------------------------------------------------------------------------
* Definitions
*------------------------------------------------------------------------------*/
/* Max. ADC Clock Frequency (Hz) */
#define ADC_CLOCK_MAX 20000000
/* Max. normal ADC startup time (us) */
#define ADC_STARTUP_NORMAL_MAX 40
/* Max. fast ADC startup time (us) */
#define ADC_STARTUP_FAST_MAX 12
/* Definitions for ADC channels */
#define ADC_CHANNEL_0 0
#define ADC_CHANNEL_1 1
#define ADC_CHANNEL_2 2
#define ADC_CHANNEL_3 3
#define ADC_CHANNEL_4 4
#define ADC_CHANNEL_5 5
#define ADC_CHANNEL_6 6
#define ADC_CHANNEL_7 7
#define ADC_CHANNEL_8 8
#define ADC_CHANNEL_9 9
#define ADC_CHANNEL_10 10
#define ADC_CHANNEL_11 11
#ifdef __cplusplus
extern "C" {
#endif
/*------------------------------------------------------------------------------
* Macros function of register access
*------------------------------------------------------------------------------*/
#define adc_get_mode_reg() (ADC->ADC_MR)
#define adc_start_conversion() (ADC->ADC_CR = ADC_CR_START)
#define adc_enable_channel(channel) { \
ADC->ADC_CHER = (1 << (channel)); \
}
#define adc_disable_channel(channel) { \
ADC->ADC_CHDR = (1 << (channel)); \
}
#define adc_enable_interrupt(mode) { \
ADC->ADC_IER = (mode); \
}
#define adc_disable_interrupt(mode) { \
ADC->ADC_IDR = (mode); \
}
#define adc_set_channel_gain(mode) { \
ADC->ADC_CGR = mode; \
}
#define adc_enable_data_ready_it() (ADC->ADC_IER = ADC_IER_DRDY)
#define adc_get_status() (ADC->ADC_ISR)
#define adc_get_compare_mode() ((ADC->ADC_EMR)& (ADC_EMR_CMPMODE_Msk))
#define adc_get_channel_status() (ADC->ADC_CHSR)
#define adc_interrupt_mask_status() (ADC->ADC_IMR)
#define adc_get_last_converted_data() (ADC->ADC_LCDR)
#define adc_get_overrun_status() (ADC->ADC_OVER)
/*------------------------------------------------------------------------------
* Exported functions
*------------------------------------------------------------------------------*/
/**
* \brief Returns the number of ADC channels
*/
extern uint32_t adc_num_channels(void);
/**
* \brief Initialize the ADC controller
*/
extern void adc_initialize(void);
/**
* \brief Set ADC clock.
*
* \param clk Desired ADC clock frequency.
*
* \return ADC clock
*/
extern uint32_t adc_set_clock(uint32_t clk);
/**
* \brief Enable ADC interrupt sources
*
* \param mask bitmask of the sources to enable
*/
extern void adc_enable_it(uint32_t mask);
/**
* \brief Disable ADC interrupt sources
*
* \param mask bitmask of the sources to disable
*/
extern void adc_disable_it(uint32_t mask);
/**
* \brief Set ADC timing.
*
* \param startup startup value
* \param tracking tracking value
* \param settling settling value
*/
extern void adc_set_timing(uint32_t startup, uint32_t tracking,
uint32_t settling);
/**
* Sets the trigger mode to following:
* - \ref ADC_TRGR_TRGMOD_NO_TRIGGER
* - \ref ADC_TRGR_TRGMOD_EXT_TRIG_RISE
* - \ref ADC_TRGR_TRGMOD_EXT_TRIG_FALL
* - \ref ADC_TRGR_TRGMOD_EXT_TRIG_ANY
* - \ref ADC_TRGR_TRGMOD_PEN_TRIG
* - \ref ADC_TRGR_TRGMOD_PERIOD_TRIG
* - \ref ADC_TRGR_TRGMOD_CONTINUOUS
* \param mode Trigger mode.
*/
extern void adc_set_trigger_mode(uint32_t mode);
/**
* \brief Enable/Disable sleep mode.
*
* \param enable Enable/Disable sleep mode.
*/
extern void adc_set_sleep_mode(uint8_t enable);
extern void adc_set_fast_wakeup(uint8_t enable);
/**
* \brief Enable/Disable seqnence mode.
*
* \param enable Enable/Disable seqnence mode.
*/
extern void adc_set_sequence_mode(uint8_t enable);
/**
* \brief Set channel sequence.
*
* \param seq1 Sequence 1 ~ 8 channel number.
* \param seq2 Sequence 9 ~ 16 channel number.
*/
extern void adc_set_sequence(uint32_t seq1, uint32_t seq2);
/**
* \brief Set channel sequence by given channel list.
*
* \param channel_list Channel list.
* \param len Number of channels in list.
*/
extern void adc_set_sequence_by_list(uint8_t channel_list[],
uint8_t len);
/**
* \brief Set "TAG" mode, show channel number in last data or not.
*
* \param enable Enable/Disable TAG value.
*/
extern void adc_set_tag_enable(uint8_t enable);
/**
* Configure extended mode register
* \param mode ADC extended mode.
*/
extern void adc_configure_ext_mode(uint32_t mode);
/**
* \brief Set compare channel.
*
* \param channel channel number to be set,16 for all channels
*/
extern void adc_set_compare_channel(uint32_t channel);
/**
* \brief Set compare mode.
*
* \param mode compare mode
*/
extern void adc_set_compare_mode(uint32_t mode);
/**
* \brief Set comparsion window.
*
* \param window Comparison Window
*/extern void adc_set_comparison_window(uint32_t window);
/**
* \brief Check if ADC configuration is right.
*
* \return 0 if check ok, others if not ok.
*/
extern uint8_t adc_check_configuration(void);
/**
* \brief Return the Channel Converted Data
*
* \param channel channel to get converted value
*/
extern uint32_t adc_get_converted_data(uint32_t channel);
#ifdef CONFIG_HAVE_ADC_INPUT_OFFSET
/**
* \brief Enable differential input for the specified channel.
*
* \param channel ADC channel number.
*/
extern void adc_enable_channel_differential_input (uint32_t channel);
/**
* \brief Disable differential input for the specified channel.
*
* \param channel ADC channel number.
*/
extern void adc_disable_channel_differential_input(uint32_t channel);
/**
* \brief Enable analog signal offset for the specified channel.
*
* \param channel ADC channel number.
*/
extern void adc_enable_channel_input_offset (uint32_t channel);
/**
* \brief Disable analog signal offset for the specified channel.
*
* \param channel ADC channel number.
*/
extern void adc_disable_channel_input_offset (uint32_t channel);
#endif /* CONFIG_HAVE_ADC_INPUT_OFFSET */
#ifdef CONFIG_HAVE_ADC_INPUT_GAIN
/**
* \brief Configure input gain for the specified channel.
*
* \param channel ADC channel number.
* \param gain Gain value for the input.
*/
extern void adc_set_channel_input_gain (uint32_t channel, uint32_t gain);
#endif /* CONFIG_HAVE_ADC_INPUT_GAIN */
/**
* Sets the average of the touch screen ADC. The mode can be:
* - \ref ADC_TSMR_TSAV_NO_FILTER (No filtering)
* - \ref ADC_TSMR_TSAV_AVG2CONV (Average 2 conversions)
* - \ref ADC_TSMR_TSAV_AVG4CONV (Average 4 conversions)
* - \ref ADC_TSMR_TSAV_AVG8CONV (Average 8 conversions)
* \param avg_2_conv Average mode for touch screen
*/
extern void adc_set_ts_average(uint32_t avg_2_conv);
/**
* Return X measurement position value.
*/
extern uint32_t adc_get_ts_xposition(void);
/**
* Return Y measurement position value.
*/
extern uint32_t adc_get_ts_yposition(void);
/**
* Return Z measurement position value.
*/
extern uint32_t adc_get_ts_pressure(void);
/**
* Sets the touchscreen pan debounce time.
* \param time Debounce time in nS.
*/
extern void adc_set_ts_debounce(uint32_t time);
/**
* Enable/Disable touch screen pen detection.
* \param enable If true, pen detection is enabled;
* in normal mode otherwise.
*/
extern void adc_set_ts_pen_detect(uint8_t enable);
/**
* Sets the ADC startup time.
* \param startup Startup time in uS.
*/
extern void adc_set_startup_time(uint32_t startup);
/**
* Set ADC tracking time
* \param dwNs Tracking time in nS.
*/
extern void adc_set_tracking_time(uint32_t dwNs);
/**
* Sets the trigger period.
* \param period Trigger period in nS.
*/
extern void adc_set_trigger_period(uint32_t period);
/**
* Sets the operation mode of the touch screen ADC. The mode can be:
* - \ref ADC_TSMR_TSMODE_NONE (TSADC off)
* - \ref ADC_TSMR_TSMODE_4_WIRE_NO_PM
* - \ref ADC_TSMR_TSMODE_4_WIRE (CH 0~3 used)
* - \ref ADC_TSMR_TSMODE_5_WIRE (CH 0~4 used)
* \param mode Desired mode
*/
extern void adc_set_ts_mode(uint32_t mode);
/**
* Start screen calibration (VDD/GND measurement)
*/
extern void adc_ts_calibration(void);
/**
* \brief Set ADC trigger.
*
* \param trigger Trigger selection
*/
extern void adc_set_trigger(uint32_t trigger);
#ifdef CONFIG_HAVE_ADC_LOW_RES
/**
* \brief Enable/Disable low resolution.
*
* \param enable Enable/Disable low resolution.
*/
extern void adc_set_low_resolution(uint8_t enable);
#endif /* CONFIG_HAVE_ADC_LOW_RES */
#ifdef __cplusplus
}
#endif
#endif /* _ADC_ */

View file

@ -0,0 +1,201 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/** \addtogroup aes_module Working with AES
* \ingroup peripherals_module
* The AES driver provides the interface to configure and use the AES
* peripheral.
* \n
*
* The Advanced Encryption Standard (AES) specifies a FIPS-approved
* cryptographic algorithm that can be used to protect electronic data. The AES
* algorithm is a symmetric block cipher that can encrypt (encipher) and decrypt
* (decipher) information.
* Encryption converts data to an unintelligible form called ciphertext.
* Decrypting the ciphertext converts the data back into its original form,
* called plaintext. The CIPHER bit in the AES Mode Register (AES_MR) allows
* selection between the encryption and the decryption processes. The AES is
* capable of using cryptographic keys of 128/192/256 bits to encrypt and
* decrypt data in blocks of 128 bits.
* This 128-bit/192-bit/256-bit key is defined in the Key Registers (AES_KEYWRx)
* and set by aes_write_key(). The input to the encryption processes of the CBC,
* CFB, and OFB modes includes, in addition to the plaintext, a 128-bit data
* block called the initialization vector (IV), which must be set using
* aes_set_vector(). The initialization vector is used in an initial step in the
* encryption of a message and in the corresponding decryption of the message.
* The Initialization Vector Registers are also used by the CTR mode to set the
* counter value.
*
* To enable AES encryption and decryption, the user has to follow these few
* steps:
* <ul>
* <li> A software triggered hardware reset of the AES interface is performed by
* aes_soft_reset().</li>
* <li> Configure AES algorithm mode, key mode, start mode and operation mode
* with aes_configure().</li>
* <li> Input AES data for encryption and decryption with function
* aes_set_input().</li>
* <li> Set AES key with fucntion aes_write_key().</li>
* <li> To start the encryption or the decryption process with aes_start().</li>
* <li> To get the encryption or decryption result by aes_get_output().</li>
* </ul>
*
*
* For more accurate information, please look at the AES section of the
* Datasheet.
*
* Related files :\n
* \ref aes.c\n
* \ref aes.h\n
*/
/*@{*/
/*@}*/
/**
* \file
*
* Implementation of Advanced Encryption Standard (AES)
*
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include "peripherals/aes.h"
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
void aes_start(void)
{
AES->AES_CR = AES_CR_START;
}
void aes_soft_reset(void)
{
AES->AES_CR = AES_CR_SWRST;
}
void aes_configure(uint32_t mode)
{
AES->AES_MR = mode;
}
void aes_enable_it(uint32_t sources)
{
AES->AES_IER = sources;
}
void aes_disable_it(uint32_t sources)
{
AES->AES_IDR = sources;
}
uint32_t aes_get_status(void)
{
return AES->AES_ISR;
}
void aes_write_key(const uint32_t * key, uint32_t len)
{
AES->AES_KEYWR[0] = key[0];
AES->AES_KEYWR[1] = key[1];
AES->AES_KEYWR[2] = key[2];
AES->AES_KEYWR[3] = key[3];
if (len >= 24) {
AES->AES_KEYWR[4] = key[4];
AES->AES_KEYWR[5] = key[5];
}
if (len == 32) {
AES->AES_KEYWR[6] = key[6];
AES->AES_KEYWR[7] = key[7];
}
}
void aes_set_input(uint32_t * data)
{
uint8_t i;
for (i = 0; i < 4; i++)
AES->AES_IDATAR[i] = data[i];
}
void aes_get_output(uint32_t * data)
{
uint8_t i;
for (i = 0; i < 4; i++)
data[i] = AES->AES_ODATAR[i];
}
void aes_set_vector(const uint32_t * vector)
{
AES->AES_IVR[0] = vector[0];
AES->AES_IVR[1] = vector[1];
AES->AES_IVR[2] = vector[2];
AES->AES_IVR[3] = vector[3];
}
void aes_set_aad_len(uint32_t len)
{
AES->AES_AADLENR = len;
}
void aes_set_data_len(uint32_t len)
{
AES->AES_CLENR = len;
}
void aes_set_gcm_hash(uint32_t * hash)
{
uint8_t i;
for (i = 0; i < 4; i++)
AES->AES_GHASHR[i] = hash[i];
}
void aes_get_gcm_tag(uint32_t * tag)
{
uint8_t i;
for (i = 0; i < 4; i++)
tag[i] = AES->AES_TAGR[i];
}
void aes_get_gcm_counter(uint32_t * counter)
{
*counter = AES->AES_CTRR;
}
void aes_get_gcm_hash_subkey(uint32_t * h)
{
uint8_t i;
for (i = 0; i < 4; i++)
h[i] = AES->AES_GCMHR[i];
}

View file

@ -0,0 +1,155 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
#ifndef _AES_
#define _AES_
/*------------------------------------------------------------------------------
* Headers
*------------------------------------------------------------------------------*/
#include "chip.h"
/*------------------------------------------------------------------------------*/
/* Definition */
/*------------------------------------------------------------------------------*/
#define AES_MR_CIPHER_ENCRYPT 1
#define AES_MR_CIPHER_DECRYPT 0
/*------------------------------------------------------------------------------*/
/* Exported functions */
/*------------------------------------------------------------------------------*/
/**
* \brief Starts Manual encryption/decryption process.
*/
void aes_start(void);
/**
* \brief Resets the AES.
* A software triggered hardware reset of the AES interface is performed.
*/
void aes_soft_reset(void);
/**
* \brief Configures an AES peripheral with the specified parameters.
* \param mode Desired value for the AES mode register (see the datasheet).
*/
void aes_configure(uint32_t mode);
/**
* \brief Enables the selected interrupts sources on a AES peripheral.
* \param sources Bitwise OR of selected interrupt sources.
*/
void aes_enable_it(uint32_t sources);
/**
* \brief Disables the selected interrupts sources on a AES peripheral.
* \param sources Bitwise OR of selected interrupt sources.
*/
void aes_disable_it(uint32_t sources);
/**
* \brief Get the current status register of the given AES peripheral.
* \return AES status register.
*/
extern uint32_t aes_get_status(void);
/**
* \brief Set the 128-bit/192-bit/256-bit cryptographic key used for
* encryption/decryption.
* \param key Pointer to a 16/24/32 bytes cipher key.
* \param len Length of the key, in bytes.
*/
void aes_write_key(const uint32_t * key, uint32_t len);
/**
* \brief Set the for 32-bit input Data allow to set the 128-bit data block used
* for encryption/decryption.
* \param data Pointer to the 16-bytes data to cipher/decipher.
*/
void aes_set_input(uint32_t * data);
/**
* \brief Get the four 32-bit data contain the 128-bit data block which has
* been encrypted/decrypted.
* \param data Pointer to the word that has been encrypted/decrypted..
*/
void aes_get_output(uint32_t * data);
/**
* \brief Set four 64-bit initialization vector data block, which is used by
* some modes of operation as an additional initial input.
* \param vector Pointer to the word of the initialization vector.
*/
void aes_set_vector(const uint32_t * vector);
/**
* \brief Set Length in bytes of the Additional Authenticated Data that are to
* be processed.
* \param len Length.
*/
void aes_set_aad_len(uint32_t len);
/**
* \brief Set Length in bytes of the plaintext/ciphertext data (that is, the C
* portion of the message) that are to be processed.
* \param len Length.
*/
void aes_set_data_len(uint32_t len);
/**
* \brief Set The four 32-bit Hash Word registers expose the intermediate GHASH
* value. May be read to save the current GHASH value so processing can later be
* resumed, presumably on a later message fragment.
* Modes of operation as an additional initial input.
* \param hash Pointer to the word of the hash.
*/
void aes_set_gcm_hash(uint32_t * hash);
/**
* \brief Get The four 32-bit Tag which contain the final 128-bit GCM
* Authentication tag 'T' when GCM processing is complete.
* \param tag Pointer to the word of the tag.
*/
void aes_get_gcm_tag(uint32_t * tag);
/**
* \brief Reports the current value of the 32-bit GCM counter.
* \param counter Pointer to value of GCM counter.
*/
void aes_get_gcm_counter(uint32_t * counter);
/**
* \brief Get the four 32-bit data containing the 128-bit H value computed from
* the KEYW value.
* \param h Pointer to the word that has been encrypted/decrypted.
*/
void aes_get_gcm_hash_subkey(uint32_t * h);
#endif /* #ifndef _AES_ */

View file

@ -0,0 +1,429 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/** \addtogroup aic_module
*
* \section Purpose
* The Advanced Interrupt Controller (AIC) is an 8-level priority, individually
* maskable, vectored interrupt controller, providing handling of up to thirty-two interrupt sources.
*
* \section Usage
* <ul>
* <li> Each interrupt source can be enabled or disabled by using the aic_enable() and aic_disable()</li>
* </ul>
*
* For more accurate information, please look at the AIC section of the
* Datasheet.
*
* Related files :\n
* \ref aic.c\n
* \ref aic.h\n
*/
/*@{*/
/*@}*/
/**
* \file
*
* Implementation of Advanced Interrupt Controller (AIC) controller.
*
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include "peripherals/aic.h"
#include "peripherals/matrix.h"
#include "cortex-a/cp15.h"
#include "cortex-a/cp15_pmu.h"
#include "cortex-a/cpsr.h"
#include <stdint.h>
#include <assert.h>
/*------------------------------------------------------------------------------
* Local functions
*------------------------------------------------------------------------------*/
/**
* \brief Default interrupt handler.
*/
static void _aic_default_irq_handler(void)
{
while (1);
}
/**
* \brief Interrupt Init.
*/
static void _aic_initialize(Aic* aic)
{
uint32_t i;
/* Disable all interrupts */
for (i = 1; i < ID_PERIPH_COUNT; i++)
{
aic->AIC_SSR = i;
aic->AIC_IDCR = AIC_IDCR_INTD;
}
/* Clear All pending interrupts flags */
for (i = 0; i < ID_PERIPH_COUNT; i++)
{
aic->AIC_SSR = i;
aic->AIC_ICCR = AIC_ICCR_INTCLR;
}
/* Perform 8 IT acknowledge (write any value in EOICR) (VPy) */
for (i = 0; i < 8; i++)
aic->AIC_EOICR = 0;
/* Assign default handler */
for (i = 0; i < ID_PERIPH_COUNT; i++)
{
aic->AIC_SSR = i;
aic->AIC_SVR = (uint32_t)_aic_default_irq_handler;
}
aic->AIC_SPU = (uint32_t)_aic_default_irq_handler;
}
/**
* \brief Configures an interrupt in the AIC. The interrupt is identified by its
* source (ID_xxx) and is configured to use the specified mode and
* interrupt handler function. Mode is the value that will be put in AIC_SMRx
* and the function address will be set in AIC_SVRx.
* The interrupt is disabled before configuration, so it is useless
* to do it before calling this function. When aic_configure returns, the
* interrupt will always be disabled and cleared; it must be enabled by a
* call to aic_enable().
*
* \param source Interrupt source to configure.
* \param mode Triggering mode and priority of the interrupt.
* \param handler Interrupt handler function.
*/
static void _aic_configure_it(uint32_t source, uint8_t mode)
{
AIC->AIC_SSR = source;
/* Disable the interrupt first */
AIC->AIC_IDCR = AIC_IDCR_INTD;
/* Configure mode and handler */
AIC->AIC_SMR = mode;
/* Clear interrupt */
AIC->AIC_ICCR = AIC_ICCR_INTCLR;
}
/**
* \brief Enables interrupts coming from the given AIC and (unique) source (ID_xxx).
*
* \param aic AIC instance.
* \param source Interrupt source to enable.
*/
static void _aic_enable_it(Aic * aic, uint32_t source)
{
aic->AIC_SSR = AIC_SSR_INTSEL(source);
aic->AIC_IECR = AIC_IECR_INTEN;
}
/**
* \brief Disables interrupts coming from the given AIC and (unique) source (ID_xxx).
*
* \param aic AIC instance.
* \param source Interrupt source to disable.
*/
static void _aic_disable_it(Aic * aic, uint32_t source)
{
aic->AIC_SSR = AIC_SSR_INTSEL(source);
aic->AIC_IDCR = AIC_IDCR_INTD;
}
/**
* \brief Configure corresponding handler for the interrupts coming from the given (unique) source (ID_xxx).
*
* \param aic AIC instance.
* \param source Interrupt source to configure.
* \param handler handler for the interrupt.
*/
static void _aic_set_source_vector(Aic * aic, uint32_t source, void (*handler)(void))
{
if (aic->AIC_WPMR & AIC_WPMR_WPEN) {
aic_write_protection(aic, 1);
}
aic->AIC_SSR = AIC_SSR_INTSEL(source);
aic->AIC_SVR = (uint32_t)handler;
}
/**
* \brief Configure the spurious interrupt handler
*
* \param aic AIC instance.
* \param handler handler for the interrupt.
*/
static void _aic_set_spurious_vector(Aic * aic, void (*handler)(void))
{
if (aic->AIC_WPMR & AIC_WPMR_WPEN) {
aic_write_protection(aic, 1);
}
aic->AIC_SPU = (uint32_t)handler;
}
/**
* \brief Clears interrupts coming from the given AIC and (unique) source (ID_xxx).
*
* \param aic AIC instance.
* \param source Interrupt source to disable.
*/
static void _aic_clear_it(Aic * aic, uint32_t source)
{
aic->AIC_SSR = AIC_SSR_INTSEL(source);
aic->AIC_ICCR = AIC_ICCR_INTCLR;
}
/**
* \brief Sets interrupts coming from the given AIC and (unique) source (ID_xxx).
*
* \param aic AIC instance.
* \param source Interrupt source to disable.
*/
static void _aic_set_it(Aic * aic, uint32_t source)
{
aic->AIC_SSR = AIC_SSR_INTSEL(source);
aic->AIC_ISCR = AIC_ISCR_INTSET;
}
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/**
* \brief Set the default handler for all interrupts
*/
void aic_initialize(void)
{
/* Disable IRQ and FIQ at core level */
v_arm_set_cpsr_bits(CPSR_MASK_IRQ | CPSR_MASK_FIQ);
/* Set default vectors */
_aic_initialize(AIC);
_aic_initialize(SAIC);
/* Redirect all interrupts to Non-secure AIC */
SFR->SFR_AICREDIR = (SFR_AICREDIR_AICREDIRKEY(AICREDIR_KEY) ^ SFR->SFR_SN1) |
SFR_AICREDIR_NSAIC;
/* Enable IRQ and FIQ at core level */
v_arm_clr_cpsr_bits(CPSR_MASK_IRQ | CPSR_MASK_FIQ);
}
/**
* \brief Enables interrupts coming from the given (unique) source (ID_xxx).
*
* \param source Interrupt source to enable.
*/
void aic_enable(uint32_t source)
{
if (SFR->SFR_AICREDIR) {
_aic_enable_it(AIC, source);
return;
}
Matrix* matrix = get_peripheral_matrix(source);
if (!matrix_is_peripheral_secured(matrix, source)) {
_aic_enable_it(AIC, source);
} else {
_aic_enable_it(SAIC, source);
}
}
/**
* \brief Disables interrupts coming from the given (unique) source (ID_xxx).
*
* \param source Interrupt source to disable.
*/
void aic_disable(uint32_t source)
{
if (SFR->SFR_AICREDIR) {
_aic_disable_it(AIC, source);
return;
}
Matrix* matrix = get_peripheral_matrix(source);
if (!matrix_is_peripheral_secured(matrix, source)) {
_aic_disable_it(AIC, source);
} else {
_aic_disable_it(SAIC, source);
}
}
/**
* \brief Configure interrupts' source mode.
*
* \param source Interrupt source to configure.
* \param mode mode combined of priority level and interrupt source type.
*/
void aic_configure(uint32_t source, uint8_t mode)
{
if (SFR->SFR_AICREDIR) {
_aic_configure_it(source, mode);
return;
}
Matrix* matrix = get_peripheral_matrix(source);
if (!matrix_is_peripheral_secured(matrix, source)) {
_aic_configure_it(source, mode);
} else {
// Does not apply for SAIC
}
}
/**
* \brief Configure corresponding handler for the interrupts coming from the given (unique) source (ID_xxx).
*
* \param source Interrupt source to configure.
* \param handler handler for the interrupt.
*/
void aic_set_source_vector(uint32_t source, void (*handler)(void))
{
Aic *aic = AIC;
if (SFR->SFR_AICREDIR == 0) {
Matrix* matrix = get_peripheral_matrix(source);
if (matrix_is_peripheral_secured(matrix, source))
aic = SAIC;
}
_aic_set_source_vector(aic, source, handler);
}
/**
* \brief Configure the spurious interrupt handler
*
* \param handler handler for the interrupt.
*/
void aic_set_spurious_vector(void (*handler)(void))
{
Aic *aic = AIC;
if (SFR->SFR_AICREDIR == 0) {
aic = SAIC;
}
_aic_set_spurious_vector(aic, handler);
}
/**
* \brief Configure interrupts' source mode.
*
* \param source Interrupt source to configure.
* \param mode mode combined of priority level and interrupt source type.
*/
void aic_set_or_clear(uint32_t source, uint8_t set)
{
Aic *aic = AIC;
if (SFR->SFR_AICREDIR == 0) {
Matrix* matrix = get_peripheral_matrix(source);
if (matrix_is_peripheral_secured(matrix, source))
aic = SAIC;
}
if (set) {
_aic_set_it(aic, source);
} else {
_aic_clear_it(aic, source);
}
}
/**
* \brief Indicate treatment completion for interrupts coming from the given AIC and (unique) source (ID_xxx).
*
* \param aic AIC instance.
*/
void aic_end_interrupt(Aic * aic)
{
aic->AIC_EOICR = AIC_EOICR_ENDIT;
}
/**
* \brief Configuration of protection mode and general interrupt mask for debug.
*
* \param aic AIC instance.
* \param protect Enable/Disable protection mode.
* \param mask Enable/Disable mask IRQ and FIQ.
*
* \retval 0 - succeed. 1 - failed.
*/
uint32_t aic_debug_config(Aic * aic, uint8_t protect, uint8_t mask)
{
uint32_t tmp;
/* return in case the "Write Protection Mode" is enabled */
if (aic->AIC_WPMR & AIC_WPMR_WPEN)
return 1;
tmp = protect ? (1 << 1) : (0 << 1);
if (mask)
tmp++;
aic->AIC_DCR = tmp;
return 0;
}
/**
* \brief Enable/Disable AIC write protection mode.
*
* \param aic AIC instance.
* \param enable Enable/Disable AIC write protection mode.
*/
void aic_write_protection(Aic * aic, uint32_t enable)
{
if (enable) {
aic->AIC_WPMR = AIC_WPMR_WPKEY_PASSWD | AIC_WPMR_WPEN;
} else {
aic->AIC_WPMR = AIC_WPMR_WPKEY_PASSWD;
}
}
/**
* \brief Get AIC Write Protection Status.
*
* \param aic AIC instance.
* \param pViolationSource pointer to address to store the violation source
*
* \retval 0 - No violation occured. 1 - violation occured.
*/
uint32_t aic_violation_occured(Aic * aic, uint32_t * pViolationSource)
{
if (aic->AIC_WPSR & AIC_WPSR_WPVS) {
*pViolationSource =
(aic->
AIC_WPSR & AIC_WPSR_WPVSRC_Msk) >> AIC_WPSR_WPVSRC_Pos;
}
return 0;
}

View file

@ -0,0 +1,79 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* \section Purpose
*
* Methods and definitions for configuring interrupts.
*
* \section Usage
* -# Enable or disable interrupt generation of a particular source with
* IRQ_EnableIT and IRQ_DisableIT.
*/
#ifndef AIC_H
#define AIC_H
/*------------------------------------------------------------------------------
* Headers
*------------------------------------------------------------------------------*/
#include "chip.h"
#include <stdint.h>
typedef void(*aic_handler_t)(void);
/*------------------------------------------------------------------------------
* Global functions
*------------------------------------------------------------------------------*/
#ifdef __cplusplus
extern "C" {
#endif
extern void aic_initialize(void);
extern void aic_enable(uint32_t source);
extern void aic_disable(uint32_t source);
extern void aic_configure(uint32_t source, uint8_t mode);
extern void aic_set_source_vector(uint32_t source, void (*handler)(void));
extern void aic_set_spurious_vector(void (*handler)(void));
extern void aic_set_or_clear(uint32_t source, uint8_t set);
extern void aic_end_interrupt(Aic * aic);
extern uint32_t aic_debug_config(Aic * aic, uint8_t protect, uint8_t mask);
extern void aic_write_protection(Aic * aic, uint32_t enable);
extern uint32_t aic_violation_occured(Aic * aic, uint32_t * pViolationSource);
#ifdef __cplusplus
}
#endif
#endif //#ifndef AIC_H

View file

@ -0,0 +1,386 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include "board.h"
#include "trace.h"
#include "peripherals/classd.h"
#include "peripherals/pmc.h"
#include <stdio.h>
#include <string.h>
/*----------------------------------------------------------------------------
* Local constants
*----------------------------------------------------------------------------*/
static const struct {
uint32_t rate;
uint32_t sample_rate;
uint32_t dsp_clk;
} audio_info[] = {
{ 8000, CLASSD_INTPMR_FRAME_FRAME_8K, CLASSD_INTPMR_DSPCLKFREQ_12M288 },
{ 16000, CLASSD_INTPMR_FRAME_FRAME_16K, CLASSD_INTPMR_DSPCLKFREQ_12M288 },
{ 32000, CLASSD_INTPMR_FRAME_FRAME_32K, CLASSD_INTPMR_DSPCLKFREQ_12M288 },
{ 48000, CLASSD_INTPMR_FRAME_FRAME_48K, CLASSD_INTPMR_DSPCLKFREQ_12M288 },
{ 96000, CLASSD_INTPMR_FRAME_FRAME_96K, CLASSD_INTPMR_DSPCLKFREQ_12M288 },
{ 22050, CLASSD_INTPMR_FRAME_FRAME_22K, CLASSD_INTPMR_DSPCLKFREQ_11M2896 },
{ 44100, CLASSD_INTPMR_FRAME_FRAME_44K, CLASSD_INTPMR_DSPCLKFREQ_11M2896 },
{ 88200, CLASSD_INTPMR_FRAME_FRAME_88K, CLASSD_INTPMR_DSPCLKFREQ_11M2896 },
};
/*----------------------------------------------------------------------------
* Local functions
*----------------------------------------------------------------------------*/
static bool _dspclk_configure(uint32_t dsp_clk)
{
struct _pmc_audio_cfg cfg;
/* Pad Clock: not used */
cfg.div = 0;
cfg.qdaudio = 0;
/* PMC Clock: */
/* 12Mhz * (ND + 1 + FRACR/2^22) / (QDPMC + 1) = 8 * DSPCLK */
switch (dsp_clk) {
case CLASSD_INTPMR_DSPCLKFREQ_12M288:
/* 12Mhz * (56 + 1 + 1442841/2^22) / (6 + 1) = 8 * 12.288Mhz */
cfg.nd = 56;
cfg.fracr = 1442841;
cfg.qdpmc = 6;
break;
case CLASSD_INTPMR_DSPCLKFREQ_11M2896:
/* 12Mhz * (59 + 1 + 885837/2^22) / (7 + 1) = 8 * 11.2896Mhz */
cfg.nd = 59;
cfg.fracr = 885837;
cfg.qdpmc = 7;
break;
default:
return false;
}
pmc_configure_audio(&cfg);
pmc_enable_audio(true, false);
#ifndef NDEBUG
{
uint32_t clk;
clk = pmc_get_audio_pmc_clock();
trace_debug("Configured Audio PLL PMC Clock: %u (= 8 * %u)\r\n",
(unsigned)clk, (unsigned)(clk >> 3));
}
#endif
return true;
}
static bool _set_eqcfg_bits(enum _classd_eqcfg eqcfg, volatile uint32_t *intpmr)
{
uint32_t mask = CLASSD_INTPMR_EQCFG_Msk;
uint32_t bits = 0;
switch (eqcfg) {
case CLASSD_EQCFG_FLAT:
bits = CLASSD_INTPMR_EQCFG_FLAT;
break;
case CLASSD_EQCFG_BBOOST12:
bits = CLASSD_INTPMR_EQCFG_BBOOST12;
break;
case CLASSD_EQCFG_BBOOST6:
bits = CLASSD_INTPMR_EQCFG_BBOOST6;
break;
case CLASSD_EQCFG_BCUT12:
bits = CLASSD_INTPMR_EQCFG_BCUT12;
break;
case CLASSD_EQCFG_BCUT6:
bits = CLASSD_INTPMR_EQCFG_BCUT6;
break;
case CLASSD_EQCFG_MBOOST3:
bits = CLASSD_INTPMR_EQCFG_MBOOST3;
break;
case CLASSD_EQCFG_MBOOST8:
bits = CLASSD_INTPMR_EQCFG_MBOOST8;
break;
case CLASSD_EQCFG_MCUT3:
bits = CLASSD_INTPMR_EQCFG_MCUT3;
break;
case CLASSD_EQCFG_MCUT8:
bits = CLASSD_INTPMR_EQCFG_MCUT8;
break;
case CLASSD_EQCFG_TBOOST12:
bits = CLASSD_INTPMR_EQCFG_TBOOST12;
break;
case CLASSD_EQCFG_TBOOST6:
bits = CLASSD_INTPMR_EQCFG_TBOOST6;
break;
case CLASSD_EQCFG_TCUT12:
bits = CLASSD_INTPMR_EQCFG_TCUT12;
break;
case CLASSD_EQCFG_TCUT6:
bits = CLASSD_INTPMR_EQCFG_TCUT6;
break;
default:
trace_warning("classd: invalid equalizer config %u\r\n",
(unsigned)eqcfg);
return false;
};
*intpmr = (*intpmr & ~mask) | bits;
return true;
}
static bool _set_mono_bits(bool mono, enum _classd_mono mono_mode, volatile uint32_t *intpmr)
{
uint32_t mask = CLASSD_INTPMR_MONO_ENABLED | CLASSD_INTPMR_MONOMODE_Msk;
uint32_t bits = 0;
if (mono) {
bits = CLASSD_INTPMR_MONO_ENABLED;
switch (mono_mode) {
case CLASSD_MONO_MIXED:
bits |= CLASSD_INTPMR_MONOMODE_MONOMIX;
break;
case CLASSD_MONO_SAT:
bits |= CLASSD_INTPMR_MONOMODE_MONOSAT;
break;
case CLASSD_MONO_LEFT:
bits |= CLASSD_INTPMR_MONOMODE_MONOLEFT;
break;
case CLASSD_MONO_RIGHT:
bits |= CLASSD_INTPMR_MONOMODE_MONORIGHT;
break;
default:
trace_warning("classd: invalid mono mode %u\r\n",
(unsigned)mono_mode);
return false;
}
}
*intpmr = (*intpmr & ~mask) | bits;
return true;
}
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
bool classd_configure(struct _classd_desc *desc)
{
uint8_t i;
uint32_t mr, intpmr, dsp_clk_set, frame_set;
for (i = 0; i < ARRAY_SIZE(audio_info); i++) {
if (audio_info[i].rate == desc->sample_rate) {
dsp_clk_set = audio_info[i].dsp_clk;
frame_set = audio_info[i].sample_rate;
break;
}
}
if(i == ARRAY_SIZE(audio_info))
return false;
if (!_dspclk_configure(dsp_clk_set))
return false;
/* enable peripheral clock, disable audio clock for now */
pmc_enable_peripheral(ID_CLASSD);
pmc_disable_gck(ID_CLASSD);
pmc_configure_gck(ID_CLASSD, PMC_PCR_GCKCSS_AUDIO_CLK, 0);
/* perform soft reset */
CLASSD->CLASSD_CR = CLASSD_CR_SWRST;
CLASSD->CLASSD_IDR = CLASSD_IDR_DATRDY;
/* initial MR/INTPMR values */
mr = 0;
intpmr = dsp_clk_set | frame_set;
/* configure output mode */
switch (desc->mode) {
case CLASSD_OUTPUT_SINGLE_ENDED:
break;
case CLASSD_OUTPUT_DIFFERENTIAL:
mr |= CLASSD_MR_PWMTYP;
break;
case CLASSD_OUTPUT_HALF_BRIDGE:
mr |= CLASSD_MR_NON_OVERLAP;
break;
case CLASSD_OUTPUT_FULL_BRIDGE:
mr |= CLASSD_MR_PWMTYP | CLASSD_MR_NON_OVERLAP;
break;
default:
trace_warning("classd: invalid mode %u\n", (unsigned)desc->mode);
return false;
}
/* configure non-overlapping time */
if (mr & CLASSD_MR_NON_OVERLAP) {
switch (desc->non_ovr) {
case CLASSD_NONOVR_5NS:
mr |= CLASSD_MR_NOVRVAL_5NS;
break;
case CLASSD_NONOVR_10NS:
mr |= CLASSD_MR_NOVRVAL_10NS;
break;
case CLASSD_NONOVR_15NS:
mr |= CLASSD_MR_NOVRVAL_15NS;
break;
case CLASSD_NONOVR_20NS:
mr |= CLASSD_MR_NOVRVAL_20NS;
break;
default:
trace_warning("classd: invalid non overlap value %u\r\n",
(unsigned)desc->non_ovr);
return false;
}
}
/* configure mono/stereo */
if (desc->swap_channels)
intpmr |= CLASSD_INTPMR_SWAP;
if (!_set_mono_bits(desc->mono, desc->mono_mode, &intpmr))
return false;
/* configure left channel (muted, max attn) */
if (desc->left_enable)
mr |= CLASSD_MR_LEN;
mr |= CLASSD_MR_LMUTE;
intpmr |= CLASSD_INTPMR_ATTL(CLASSD_INTPMR_ATTL_Msk);
/* configure right channel (muted, max attn) */
if (desc->right_enable)
mr |= CLASSD_MR_REN;
mr |= CLASSD_MR_RMUTE;
intpmr |= CLASSD_INTPMR_ATTR(CLASSD_INTPMR_ATTL_Msk);
/* write configuration */
CLASSD->CLASSD_MR = mr;
CLASSD->CLASSD_INTPMR = intpmr;
/* enable audio clock */
pmc_enable_gck(ID_CLASSD);
return (CLASSD->CLASSD_INTSR & CLASSD_INTSR_CFGERR) == 0;
}
void classd_disable(void)
{
pmc_disable_audio();
pmc_disable_gck(ID_CLASSD);
pmc_disable_peripheral(ID_CLASSD);
}
void classd_swap_channels(bool swap)
{
if (swap) {
CLASSD->CLASSD_INTPMR |= CLASSD_INTPMR_SWAP;
} else {
CLASSD->CLASSD_INTPMR &= ~CLASSD_INTPMR_SWAP;
}
}
void classd_enable_mono(enum _classd_mono mono_mode)
{
_set_mono_bits(true, mono_mode, &CLASSD->CLASSD_INTPMR);
}
void classd_disable_mono(void)
{
_set_mono_bits(false, CLASSD_MONO_MIXED, &CLASSD->CLASSD_INTPMR);
}
void classd_set_equalizer(enum _classd_eqcfg eqcfg)
{
_set_eqcfg_bits(eqcfg, &CLASSD->CLASSD_INTPMR);
}
void classd_enable_channels(bool left, bool right)
{
uint32_t bits = 0;
if (left)
bits |= CLASSD_MR_LEN;
if (right)
bits |= CLASSD_MR_REN;
CLASSD->CLASSD_MR |= bits;
}
void classd_disable_channels(bool left, bool right)
{
uint32_t bits = 0;
if (left)
bits |= CLASSD_MR_LEN;
if (right)
bits |= CLASSD_MR_REN;
CLASSD->CLASSD_MR &= ~bits;
}
void classd_set_left_attenuation(uint8_t attn)
{
if (attn < 1 || attn > 0x3f)
return;
uint32_t intpmr = CLASSD->CLASSD_INTPMR & ~CLASSD_INTPMR_ATTL_Msk;
CLASSD->CLASSD_INTPMR = intpmr | CLASSD_INTPMR_ATTL(attn);
}
void classd_set_right_attenuation(uint8_t attn)
{
if (attn < 1 || attn > 0x3f)
return;
uint32_t intpmr = CLASSD->CLASSD_INTPMR & ~CLASSD_INTPMR_ATTR_Msk;
CLASSD->CLASSD_INTPMR = intpmr | CLASSD_INTPMR_ATTR(attn);
}
void classd_volume_mute(bool left, bool right)
{
uint32_t bits = 0;
if (left)
bits |= CLASSD_MR_LMUTE;
if (right)
bits |= CLASSD_MR_RMUTE;
CLASSD->CLASSD_MR |= bits;
}
void classd_volume_unmute(bool left, bool right)
{
uint32_t bits = 0;
if (left)
bits |= CLASSD_MR_LMUTE;
if (right)
bits |= CLASSD_MR_RMUTE;
CLASSD->CLASSD_MR &= ~bits;
}

View file

@ -0,0 +1,125 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
#ifndef _CLASSD_H
#define _CLASSD_H
/*---------------------------------------------------------------------------
* Includes
*---------------------------------------------------------------------------*/
#include <stdbool.h>
#include <stdint.h>
/*---------------------------------------------------------------------------
* Types
*---------------------------------------------------------------------------*/
enum _classd_mode
{
CLASSD_OUTPUT_SINGLE_ENDED,
CLASSD_OUTPUT_DIFFERENTIAL,
CLASSD_OUTPUT_HALF_BRIDGE,
CLASSD_OUTPUT_FULL_BRIDGE,
};
enum _classd_non_ovr
{
CLASSD_NONOVR_5NS,
CLASSD_NONOVR_10NS,
CLASSD_NONOVR_15NS,
CLASSD_NONOVR_20NS,
};
enum _classd_eqcfg
{
CLASSD_EQCFG_FLAT,
CLASSD_EQCFG_BBOOST12,
CLASSD_EQCFG_BBOOST6,
CLASSD_EQCFG_BCUT12,
CLASSD_EQCFG_BCUT6,
CLASSD_EQCFG_MBOOST3,
CLASSD_EQCFG_MBOOST8,
CLASSD_EQCFG_MCUT3,
CLASSD_EQCFG_MCUT8,
CLASSD_EQCFG_TBOOST12,
CLASSD_EQCFG_TBOOST6,
CLASSD_EQCFG_TCUT12,
CLASSD_EQCFG_TCUT6,
};
enum _classd_mono
{
CLASSD_MONO_MIXED,
CLASSD_MONO_SAT,
CLASSD_MONO_LEFT,
CLASSD_MONO_RIGHT,
};
struct _classd_desc
{
uint32_t sample_rate;
enum _classd_mode mode;
enum _classd_non_ovr non_ovr;
bool swap_channels;
bool mono;
enum _classd_mono mono_mode;
bool left_enable;
bool right_enable;
};
/*---------------------------------------------------------------------------
* Exported functions
*---------------------------------------------------------------------------*/
extern bool classd_configure(struct _classd_desc *desc);
extern void classd_disable(void);
extern void classd_swap_channels(bool swap);
extern void classd_enable_mono(enum _classd_mono mono_mode);
extern void classd_disable_mono(void);
extern void classd_set_equalizer(enum _classd_eqcfg eqcfg);
extern void classd_enable_channels(bool left, bool right);
extern void classd_disable_channels(bool left, bool right);
extern void classd_set_left_attenuation(uint8_t attn);
extern void classd_set_right_attenuation(uint8_t attn);
extern void classd_volume_mute(bool left, bool right);
extern void classd_volume_unmute(bool left, bool right);
#endif /* _CLASSD_H */

View file

@ -0,0 +1,82 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/*------------------------------------------------------------------------------
* Headers
*------------------------------------------------------------------------------*/
#include "chip.h"
#include "peripherals/flexcom.h"
#include "peripherals/usart.h"
#include "peripherals/spi.h"
#include "peripherals/twi.h"
#include <assert.h>
/*------------------------------------------------------------------------------
* Exported functions
*------------------------------------------------------------------------------*/
/**
* \brief Select a protocol for a FLEXCOM device
*
*
* \param flexcom Pointer to FLEXCOM peripheral to configure.
* \param protocol Protocol to use.
*/
void flexcom_select(Flexcom * flexcom, uint32_t protocol)
{
assert(flexcom);
uint32_t current_protocol = flexcom->FLEX_MR;
usart_set_receiver_enabled(&flexcom->usart, 0u);
/* Shutdown previous protocol */
switch (current_protocol) {
case FLEX_MR_OPMODE_USART:
usart_set_receiver_enabled(&flexcom->usart, 0u);
usart_set_transmitter_enabled(&flexcom->usart, 0u);
break;
case FLEX_MR_OPMODE_SPI:
spi_disable(&flexcom->spi);
break;
case FLEX_MR_OPMODE_TWI:
twi_stop(&flexcom->twi);
default:
break;
}
assert(protocol & FLEX_MR_OPMODE_NO_COM ||
protocol & FLEX_MR_OPMODE_USART ||
FLEX_MR_OPMODE_SPI || FLEX_MR_OPMODE_TWI);
/* Activate the new mode () */
flexcom->FLEX_MR = protocol;
}

View file

@ -0,0 +1,75 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* \par Purpose
*
* This module provides several definitions and methods for using an USART
* peripheral.
*
* \par Usage
*
* -# Enable the USART peripheral clock in the PMC.
* -# Enable the required USART PIOs (see pio.h).
* -# Configure the UART by calling usart_configure.
* -# Enable the transmitter and/or the receiver of the USART using
* usart_set_transmitter_enabled and usart_set_receiver_enabled.
* -# Send data through the USART using the usart_write methods.
* -# Receive data from the USART using the usart_read functions; the availability of data can be polled
* with usart_is_data_available.
* -# Disable the transmitter and/or the receiver of the USART with
* usart_set_transmitter_enabled and usart_set_receiver_enabled.
*/
#ifndef _FLEXCOM_
#define _FLEXCOM_
/*------------------------------------------------------------------------------
* Headers
*------------------------------------------------------------------------------*/
#include "chip.h"
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/*------------------------------------------------------------------------------*/
/* Exported functions */
/*------------------------------------------------------------------------------*/
extern void flexcom_select(Flexcom * flexcom, uint32_t protocol);
#ifdef __cplusplus
}
#endif
#endif /* #ifndef _FLEXCOM_ */

View file

@ -0,0 +1,518 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include "trace.h"
#include "peripherals/gmac.h"
#include "peripherals/pmc.h"
#include <stdio.h>
#include <string.h>
#include <assert.h>
/*----------------------------------------------------------------------------
* Local definitions
*----------------------------------------------------------------------------*/
/* some IP versions don't have this configuration flag and instead expect 0 */
#ifndef GMAC_NCFGR_DBW_DBW32
#define GMAC_NCFGR_DBW_DBW32 0
#endif
/* some IP versions don't have this error flag, set it to 0 to ignore it */
#ifndef GMAC_TSR_UND
#define GMAC_TSR_UND 0
#endif
/*----------------------------------------------------------------------------
* Local functions
*----------------------------------------------------------------------------*/
static bool _gmac_configure_mdc_clock(Gmac *gmac)
{
uint32_t mck, clk;
mck = pmc_get_peripheral_clock(get_gmac_id_from_addr(gmac));
/* Disable RX/TX */
gmac->GMAC_NCR &= ~(GMAC_NCR_RXEN | GMAC_NCR_TXEN);
/* Find divider */
if (mck <= 20000000) {
clk = GMAC_NCFGR_CLK_MCK_8; // MCK/8
} else if (mck <= 40000000) {
clk = GMAC_NCFGR_CLK_MCK_16; // MCK/16
} else if (mck <= 80000000) {
clk = GMAC_NCFGR_CLK_MCK_32; // MCK/32
} else if (mck <= 120000000) {
clk = GMAC_NCFGR_CLK_MCK_48; // MCK/48
} else if (mck <= 160000000) {
clk = GMAC_NCFGR_CLK_MCK_64; // MCK/64
} else if (mck <= 240000000) {
clk = GMAC_NCFGR_CLK_MCK_96; // MCK/96
} else {
trace_error("MCK too high, cannot configure MDC clock.\r\n");
return false;
}
/* configure MDC clock divider and enable RX/TX */
gmac->GMAC_NCFGR = (gmac->GMAC_NCFGR & ~GMAC_NCFGR_CLK_Msk) | clk;
gmac->GMAC_NCR |= (GMAC_NCR_RXEN | GMAC_NCR_TXEN);
return true;
}
static bool _gmac_phy_wait_idle(Gmac* gmac, uint32_t retries)
{
uint32_t count = 0;
while ((gmac->GMAC_NSR & GMAC_NSR_IDLE) == 0) {
if (retries > 0 && count > retries) {
trace_debug("Timeout reached while waiting for PHY management logic to become idle");
return false;
}
count++;
}
return true;
}
static void _gmac_set_link_speed(Gmac* gmac, enum _gmac_speed speed, enum _gmac_duplex duplex)
{
/* Configure duplex */
switch (duplex) {
case GMAC_DUPLEX_HALF:
gmac->GMAC_NCFGR &= ~GMAC_NCFGR_FD;
break;
case GMAC_DUPLEX_FULL:
gmac->GMAC_NCFGR |= GMAC_NCFGR_FD;
break;
default:
trace_error("Invalid duplex value %d\r\n", duplex);
return;
}
/* Configure speed */
switch (speed) {
case GMAC_SPEED_10M:
gmac->GMAC_NCFGR &= ~GMAC_NCFGR_SPD;
break;
case GMAC_SPEED_100M:
gmac->GMAC_NCFGR |= GMAC_NCFGR_SPD;
break;
default:
trace_error("Invalid speed value %d\r\n", speed);
return;
}
}
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
bool gmac_configure(Gmac* gmac)
{
pmc_enable_peripheral(get_gmac_id_from_addr(gmac));
/* Disable TX & RX and more */
gmac_set_network_control_register(gmac, 0);
gmac_set_network_config_register(gmac, GMAC_NCFGR_DBW_DBW32);
/* Disable interrupts */
gmac_disable_it(gmac, 0, ~0u);
#ifdef CONFIG_HAVE_GMAC_QUEUES
gmac_disable_it(gmac, 1, ~0u);
gmac_disable_it(gmac, 2, ~0u);
#endif
/* Clear statistics */
gmac_clear_statistics(gmac);
/* Clear all status bits in the receive status register. */
gmac_clear_rx_status(gmac, GMAC_RSR_RXOVR | GMAC_RSR_REC |
GMAC_RSR_BNA | GMAC_RSR_HNO);
/* Clear all status bits in the transmit status register */
gmac_clear_tx_status(gmac, GMAC_TSR_UBR | GMAC_TSR_COL |
GMAC_TSR_RLE | GMAC_TSR_TXGO | GMAC_TSR_TFC |
GMAC_TSR_TXCOMP | GMAC_TSR_UND | GMAC_TSR_HRESP);
/* Clear interrupts */
gmac_get_it_status(gmac, 0);
#ifdef CONFIG_HAVE_GMAC_QUEUES
gmac_get_it_status(gmac, 1);
gmac_get_it_status(gmac, 2);
#endif
return _gmac_configure_mdc_clock(gmac);
}
void gmac_set_network_control_register(Gmac* gmac, uint32_t ncr)
{
gmac->GMAC_NCR = ncr;
}
uint32_t gmac_get_network_control_register(Gmac* gmac)
{
return gmac->GMAC_NCR;
}
void gmac_set_network_config_register(Gmac* gmac, uint32_t ncfgr)
{
gmac->GMAC_NCFGR = ncfgr;
}
uint32_t gmac_get_network_config_register(Gmac* gmac)
{
return gmac->GMAC_NCFGR;
}
void gmac_enable_mdio(Gmac* gmac)
{
/* Disable RX/TX */
gmac->GMAC_NCR &= ~(GMAC_NCR_RXEN | GMAC_NCR_TXEN);
/* Enable MDIO */
gmac->GMAC_NCR |= GMAC_NCR_MPE;
/* Enable RX/TX */
gmac->GMAC_NCR |= (GMAC_NCR_RXEN | GMAC_NCR_TXEN);
}
void gmac_disable_mdio(Gmac* gmac)
{
/* Disable RX/TX */
gmac->GMAC_NCR &= ~(GMAC_NCR_RXEN | GMAC_NCR_TXEN);
/* Disable MDIO */
gmac->GMAC_NCR &= ~GMAC_NCR_MPE;
/* Enable RX/TX */
gmac->GMAC_NCR |= (GMAC_NCR_RXEN | GMAC_NCR_TXEN);
}
bool gmac_phy_read(Gmac* gmac, uint8_t phy_addr, uint8_t reg_addr, uint16_t* data,
uint32_t retries)
{
/* Wait until idle */
if (!_gmac_phy_wait_idle(gmac, retries))
return false;
/* Write maintenance register */
gmac->GMAC_MAN = GMAC_MAN_CLTTO |
GMAC_MAN_OP(2) |
GMAC_MAN_WTN(2) |
GMAC_MAN_PHYA(phy_addr) |
GMAC_MAN_REGA(reg_addr);
/* Wait until idle */
if (!_gmac_phy_wait_idle(gmac, retries))
return false;
*data = (gmac->GMAC_MAN & GMAC_MAN_DATA_Msk) >> GMAC_MAN_DATA_Pos;
return true;
}
bool gmac_phy_write(Gmac* gmac, uint8_t phy_addr, uint8_t reg_addr, uint16_t data,
uint32_t retries)
{
/* Wait until idle */
if (!_gmac_phy_wait_idle(gmac, retries))
return false;
/* Write maintenance register */
gmac->GMAC_MAN = GMAC_MAN_CLTTO |
GMAC_MAN_OP(1) |
GMAC_MAN_WTN(2) |
GMAC_MAN_PHYA(phy_addr) |
GMAC_MAN_REGA(reg_addr) |
GMAC_MAN_DATA(data);
/* Wait until idle */
return _gmac_phy_wait_idle(gmac, retries);
}
void gmac_enable_mii(Gmac* gmac)
{
/* Disable RX/TX */
gmac->GMAC_NCR &= ~(GMAC_NCR_RXEN | GMAC_NCR_TXEN);
/* Disable RMII */
gmac->GMAC_UR &= ~GMAC_UR_RMII;
/* Enable RX/TX */
gmac->GMAC_NCR |= (GMAC_NCR_RXEN | GMAC_NCR_TXEN);
}
void gmac_enable_rmii(Gmac* gmac, enum _gmac_speed speed, enum _gmac_duplex duplex)
{
/* Disable RX/TX */
gmac->GMAC_NCR &= ~(GMAC_NCR_RXEN | GMAC_NCR_TXEN);
/* Configure speed/duplex */
_gmac_set_link_speed(gmac, speed, duplex);
/* Enable RMII */
gmac->GMAC_UR |= GMAC_UR_RMII;
/* Enable RX/TX */
gmac->GMAC_NCR |= (GMAC_NCR_RXEN | GMAC_NCR_TXEN);
}
void gmac_set_link_speed(Gmac* gmac, enum _gmac_speed speed, enum _gmac_duplex duplex)
{
/* Disable RX/TX */
gmac->GMAC_NCR &= ~(GMAC_NCR_RXEN | GMAC_NCR_TXEN);
/* Configure speed/duplex */
_gmac_set_link_speed(gmac, speed, duplex);
/* Enable RX/TX */
gmac->GMAC_NCR |= (GMAC_NCR_RXEN | GMAC_NCR_TXEN);
}
void gmac_enable_local_loopback(Gmac* gmac)
{
gmac->GMAC_NCR |= GMAC_NCR_LBL;
}
void gmac_disable_local_loopback(Gmac* gmac)
{
gmac->GMAC_NCR &= ~GMAC_NCR_LBL;
}
uint32_t gmac_get_tx_status(Gmac* gmac)
{
return gmac->GMAC_TSR;
}
void gmac_clear_tx_status(Gmac* gmac, uint32_t mask)
{
gmac->GMAC_TSR = mask;
}
uint32_t gmac_get_rx_status(Gmac* gmac)
{
return gmac->GMAC_RSR;
}
void gmac_clear_rx_status(Gmac* gmac, uint32_t mask)
{
gmac->GMAC_RSR = mask;
}
void gmac_receive_enable(Gmac* gmac, bool enable)
{
if (enable)
gmac->GMAC_NCR |= GMAC_NCR_RXEN;
else
gmac->GMAC_NCR &= ~GMAC_NCR_RXEN;
}
void gmac_transmit_enable(Gmac* gmac, bool enable)
{
if (enable)
gmac->GMAC_NCR |= GMAC_NCR_TXEN;
else
gmac->GMAC_NCR &= ~GMAC_NCR_TXEN;
}
void gmac_set_rx_desc(Gmac* gmac, uint8_t queue, struct _gmac_desc* desc)
{
if (queue == 0) {
gmac->GMAC_RBQB = ((uint32_t)desc) & GMAC_RBQB_ADDR_Msk;
}
#ifdef CONFIG_HAVE_GMAC_QUEUES
else if (queue <= GMAC_NUM_QUEUES) {
gmac->GMAC_RBQBAPQ[queue - 1] = ((uint32_t)desc) & GMAC_RBQBAPQ_RXBQBA_Msk;
}
#endif
else {
trace_debug("Invalid queue number %d\r\n", queue);
}
}
struct _gmac_desc* gmac_get_rx_desc(Gmac* gmac, uint8_t queue)
{
if (queue == 0) {
return (struct _gmac_desc*)(gmac->GMAC_RBQB & GMAC_RBQB_ADDR_Msk);
}
#ifdef CONFIG_HAVE_GMAC_QUEUES
else if (queue <= GMAC_NUM_QUEUES) {
return (struct _gmac_desc*)(gmac->GMAC_RBQBAPQ[queue - 1] & GMAC_RBQBAPQ_RXBQBA_Msk);
}
#endif
else {
trace_debug("Invalid queue number %d\r\n", queue);
return NULL;
}
}
void gmac_set_tx_desc(Gmac* gmac, uint8_t queue, struct _gmac_desc* desc)
{
if (queue == 0) {
gmac->GMAC_TBQB = ((uint32_t)desc) & GMAC_TBQB_ADDR_Msk;
}
#ifdef CONFIG_HAVE_GMAC_QUEUES
else if (queue <= GMAC_NUM_QUEUES) {
gmac->GMAC_TBQBAPQ[queue - 1] = ((uint32_t)desc) & GMAC_TBQBAPQ_TXBQBA_Msk;
}
#endif
else {
trace_debug("Invalid queue number %d\r\n", queue);
}
}
struct _gmac_desc* gmac_get_tx_desc(Gmac* gmac, uint8_t queue)
{
if (queue == 0) {
return (struct _gmac_desc*)(gmac->GMAC_TBQB & GMAC_TBQB_ADDR_Msk);
}
#ifdef CONFIG_HAVE_GMAC_QUEUES
else if (queue <= GMAC_NUM_QUEUES) {
return (struct _gmac_desc*)(gmac->GMAC_TBQBAPQ[queue - 1] & GMAC_TBQBAPQ_TXBQBA_Msk);
}
#endif
else {
trace_debug("Invalid queue number %d\r\n", queue);
return NULL;
}
}
uint32_t gmac_get_it_mask(Gmac* gmac, uint8_t queue)
{
if (queue == 0) {
return gmac->GMAC_IMR;
}
#ifdef CONFIG_HAVE_GMAC_QUEUES
else if (queue <= GMAC_NUM_QUEUES) {
return gmac->GMAC_IMRPQ[queue - 1];
}
#endif
else {
trace_debug("Invalid queue number %d\r\n", queue);
return 0;
}
}
void gmac_enable_it(Gmac* gmac, uint8_t queue, uint32_t mask)
{
if (queue == 0) {
gmac->GMAC_IER = mask;
}
#ifdef CONFIG_HAVE_GMAC_QUEUES
else if (queue <= GMAC_NUM_QUEUES) {
gmac->GMAC_IERPQ[queue - 1] = mask;
}
#endif
else {
trace_debug("Invalid queue number %d\r\n", queue);
}
}
void gmac_disable_it(Gmac * gmac, uint8_t queue, uint32_t mask)
{
if (queue == 0) {
gmac->GMAC_IDR = mask;
}
#ifdef CONFIG_HAVE_GMAC_QUEUES
else if (queue <= GMAC_NUM_QUEUES) {
gmac->GMAC_IDRPQ[queue - 1] = mask;
}
#endif
else {
trace_debug("Invalid queue number %d\r\n", queue);
}
}
uint32_t gmac_get_it_status(Gmac* gmac, uint8_t queue)
{
if (queue == 0) {
return gmac->GMAC_ISR;
}
#ifdef CONFIG_HAVE_GMAC_QUEUES
else if (queue <= GMAC_NUM_QUEUES) {
return gmac->GMAC_ISRPQ[queue - 1];
}
#endif
else {
trace_debug("Invalid queue number %d\r\n", queue);
return 0;
}
}
void gmac_set_mac_addr(Gmac* gmac, uint8_t sa_idx, uint8_t* mac)
{
gmac->GMAC_SA[sa_idx].GMAC_SAB = (mac[3] << 24) |
(mac[2] << 16) | (mac[1] << 8) | mac[0];
gmac->GMAC_SA[sa_idx].GMAC_SAT = (mac[5] << 8) |
mac[4];
}
void gmac_set_mac_addr32(Gmac* gmac, uint8_t sa_idx,
uint32_t mac_top, uint32_t mac_bottom)
{
gmac->GMAC_SA[sa_idx].GMAC_SAB = mac_bottom;
gmac->GMAC_SA[sa_idx].GMAC_SAT = mac_top;
}
void gmac_set_mac_addr64(Gmac* gmac, uint8_t sa_idx, uint64_t mac)
{
gmac->GMAC_SA[sa_idx].GMAC_SAB = (uint32_t)(mac & 0xffffffff);
gmac->GMAC_SA[sa_idx].GMAC_SAT = (uint32_t)(mac >> 32);
}
void gmac_clear_statistics(Gmac* gmac)
{
gmac->GMAC_NCR |= GMAC_NCR_CLRSTAT;
}
void gmac_increase_statistics(Gmac* gmac)
{
gmac->GMAC_NCR |= GMAC_NCR_INCSTAT;
}
void gmac_enable_statistics_write(Gmac* gmac, bool enable)
{
if (enable)
gmac->GMAC_NCR |= GMAC_NCR_WESTAT;
else
gmac->GMAC_NCR &= ~GMAC_NCR_WESTAT;
}
void gmac_start_transmission(Gmac * gmac)
{
gmac->GMAC_NCR |= GMAC_NCR_TSTART;
}
void gmac_halt_transmission(Gmac * gmac)
{
gmac->GMAC_NCR |= GMAC_NCR_THALT;
}

View file

@ -0,0 +1,361 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/** \file */
/** \addtogroup gmac_module
* @{
* Provides the interface to configure and use the GMAC peripheral.
*
* \section gmac_usage Usage
* - Configure Gmac::GMAC_NCFG with gmac_configure(), some of related controls
* are also available, such as:
* - gmac_set_link_speed(): Setup GMAC working clock.
* - gmac_full_duplex_enable(): Working in full duplex or not.
* - gmac_cpy_all_enable(): Copying all valid frames (\ref GMAC_NCFG_CAF).
* - ...
* - Setup Gmac::GMAC_NCR with gmac_network_control(), more related controls
* can modify with:
* - gmac_receive_enable(): Enable/Disable Rx.
* - gmac_transmit_enable(): Enable/Disable Tx.
* - gmac_broadcast_disable(): Enable/Disable broadcast receiving.
* - ...
* - Manage GMAC interrupts with GMAC_EnableIt(), gmac_disable_it(),
* gmac_get_it_mask() and gmac_get_it_status().
* - Manage GMAC Tx/Rx status with gmac_get_tx_status(), gmac_get_rx_status()
* gmac_clear_tx_status() and gmac_clear_rx_status().
* - Manage GMAC Queue with gmac_set_tx_queue(), GMAC_GetTxQueue(),
* gmac_set_rx_queue() and GMAC_GetRxQueue(), the queue descriptor can define
* by \ref _gmac_rx_descriptor and \ref _gmac_tx_descriptor.
* - Manage PHY through GMAC is performed by
* - gmac_management_enable(): Enable/Disable PHY management.
* - gmac_phy_maintain(): Execute PHY management commands.
* - gmac_phy_data(): Return PHY management data.
* - gmac_is_idle(): Check if PHY is idle.
* - Setup GMAC parameters with following functions:
* - gmac_set_hash(): Set Hash value.
* - gmac_set_address(): Set MAC address.
* - Enable/Disable GMAC transceiver clock via GMAC_TransceiverClockEnable()
* - Switch GMAC MII/RMII mode through gmac_enable_rgmii()
*
* For more accurate information, please look at the GMAC section of the
* Datasheet.
*
* \sa \ref gmacd_module
*
* Related files:\n
* gmac.c\n
* gmac.h.\n
*
* \defgroup gmac_defines GMAC Defines
* \defgroup gmac_structs GMAC Data Structs
* \defgroup gmac_functions GMAC Functions
*/
/**@}*/
#ifndef _GMAC_H_
#define _GMAC_H_
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include <stdbool.h>
#include <stdint.h>
/*----------------------------------------------------------------------------
* Defines
*----------------------------------------------------------------------------*/
/** \addtogroup gmac_defines
@{*/
#ifdef CONFIG_HAVE_GMAC_QUEUES
#define GMAC_NUM_QUEUES 3
#else
#define GMAC_NUM_QUEUES 1
#endif
#define GMAC_MAX_FRAME_LENGTH 1536
#define GMAC_MAX_JUMBO_FRAME_LENGTH 10240
enum _gmac_duplex {
GMAC_DUPLEX_HALF = 0,
GMAC_DUPLEX_FULL = 1,
};
enum _gmac_speed {
GMAC_SPEED_10M = 0,
GMAC_SPEED_100M = 1,
};
/* Bits contained in struct _gmac_desc addr when used for RX*/
#define GMAC_RX_ADDR_OWN (1u << 0)
#define GMAC_RX_ADDR_WRAP (1u << 1)
#define GMAC_RX_ADDR_MASK 0xfffffffcu
/* Bits contained in struct _gmac_desc status when used for RX */
#define GMAC_RX_STATUS_LENGTH_MASK 0x3fffu
#define GMAC_RX_STATUS_SOF (1u << 14)
#define GMAC_RX_STATUS_EOF (1u << 15)
/* Bits contained in struct _gmac_desc status when used for TX */
#define GMAC_TX_STATUS_LASTBUF (1u << 15)
#define GMAC_TX_STATUS_WRAP (1u << 30)
#define GMAC_TX_STATUS_USED (1u << 31)
/**@}*/
/*----------------------------------------------------------------------------
* Types
*----------------------------------------------------------------------------*/
/** \addtogroup gmac_structs
@{*/
/** Transmit/Receive buffer descriptor struct */
struct _gmac_desc {
uint32_t addr;
uint32_t status;
};
/** @}*/
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
#ifdef __cplusplus
extern "C" {
#endif
/**
* TODO
*/
extern bool gmac_configure(Gmac *gmac);
/**
* \brief Write NCR register value
*/
extern void gmac_set_network_control_register(Gmac * gmac, uint32_t ncr);
/**
* \brief Get NCR register value
*/
extern uint32_t gmac_get_network_control_register(Gmac * gmac);
/**
* \brief Set network configuration register
*/
extern void gmac_set_network_config_register(Gmac* gmac, uint32_t ncfgr);
/**
* \brief Get network configuration register
*/
extern uint32_t gmac_get_network_config_register(Gmac* gmac);
/**
* \brief Enable MDI with PHY
* \param gmac Pointer to an Gmac instance.
*/
extern void gmac_enable_mdio(Gmac* gmac);
/**
* \brief Disable MDI with PHY
* \param gmac Pointer to an Gmac instance.
*/
extern void gmac_disable_mdio(Gmac* gmac);
/**
* \brief Execute PHY read command
*/
extern bool gmac_phy_read(Gmac* gmac, uint8_t phy_addr, uint8_t reg_addr,
uint16_t* data, uint32_t retries);
/**
* \brief Execute PHY write command
*/
extern bool gmac_phy_write(Gmac* gmac, uint8_t phy_addr, uint8_t reg_addr,
uint16_t data, uint32_t retries);
/**
* \brief Enable MII mode for GMAC, called once after autonegotiate
* \param gmac Pointer to an Gmac instance.
*/
extern void gmac_enable_mii(Gmac* gmac);
/**
* \brief Enable RMII mode for GMAC, called once after autonegotiate
* \param gmac Pointer to an Gmac instance.
* \param duplex: 1 full duplex 0 half duplex
* \param speed: 0 10M 1 100M
*/
extern void gmac_enable_rmii(Gmac* gmac, enum _gmac_speed speed,
enum _gmac_duplex duplex);
/**
* \brief Setup the GMAC for the link : speed 100M/10M and Full/Half duplex
* \param gmac Pointer to an Gmac instance.
* \param speed Link speed, 0 for 10M, 1 for 100M
* \param fullduplex 1 for Full Duplex mode
*/
extern void gmac_set_link_speed(Gmac* gmac, enum _gmac_speed speed,
enum _gmac_duplex duplex);
/**
* \brief Enable local loop back
* \param gmac Pointer to an Gmac instance.
*/
extern void gmac_enable_local_loopback(Gmac* gmac);
/**
* \brief Disable local loop back
* \param gmac Pointer to an Gmac instance.
*/
extern void gmac_disable_local_loopback(Gmac* gmac);
/**
* \brief Return transmit status
*/
extern uint32_t gmac_get_tx_status(Gmac* gmac);
/**
* \brief Clear transmit status
*/
extern void gmac_clear_tx_status(Gmac* gmac, uint32_t mask);
/**
* \brief Return receive status
*/
extern uint32_t gmac_get_rx_status(Gmac* gmac);
/**
* \brief Clear receive status
*/
extern void gmac_clear_rx_status(Gmac* gmac, uint32_t mask);
/**
* \brief Enable/Disable GMAC receive.
*/
extern void gmac_receive_enable(Gmac* gmac, bool enable);
/**
* \brief Enable/Disable GMAC transmit.
*/
extern void gmac_transmit_enable(Gmac* gmac, bool enable);
/**
* \brief Set RX descriptor address
*/
void gmac_set_rx_desc(Gmac* gmac, uint8_t queue, struct _gmac_desc* desc);
/**
* \brief Get RX descriptor address
*/
struct _gmac_desc* gmac_get_rx_desc(Gmac* gmac, uint8_t queue);
/**
* \brief Set TX descriptor address
*/
void gmac_set_tx_desc(Gmac* gmac, uint8_t queue, struct _gmac_desc* desc);
/**
* \brief Get TX descriptor address
*/
struct _gmac_desc* gmac_get_tx_desc(Gmac* gmac, uint8_t queue);
/**
* \brief Return interrupt mask.
*/
extern uint32_t gmac_get_it_mask(Gmac* gmac, uint8_t queue);
/**
* \brief Enable interrupt(s).
*/
extern void gmac_enable_it(Gmac* gmac, uint8_t queue, uint32_t mask);
/**
* \brief Disable interrupt(s).
*/
extern void gmac_disable_it(Gmac * gmac, uint8_t queue, uint32_t mask);
/**
* \brief Return interrupt status mask.
*/
extern uint32_t gmac_get_it_status(Gmac* gmac, uint8_t queue);
/**
* \brief Set MAC Address
*/
extern void gmac_set_mac_addr(Gmac* gmac, uint8_t sa_idx, uint8_t* mac);
/**
* \brief Set MAC Address using two 32-bit integers
*/
extern void gmac_set_mac_addr32(Gmac* gmac, uint8_t sa_idx,
uint32_t mac_top, uint32_t mac_bottom);
/**
* \brief Set MAC Address using a 64-bit integer
*/
extern void gmac_set_mac_addr64(Gmac* gmac, uint8_t sa_idx, uint64_t mac);
/**
* \brief Clear all statistics registers
*/
extern void gmac_clear_statistics(Gmac* gmac);
/**
* \brief Increase all statistics registers
*/
extern void gmac_increase_statistics(Gmac* gmac);
/**
* \brief Enable/Disable statistics registers writing.
*/
extern void gmac_enable_statistics_write(Gmac* gmac, bool enable);
/**
* \brief Start transmission
*/
extern void gmac_start_transmission(Gmac* gmac);
/**
* \brief Halt transmission
*/
extern void gmac_halt_transmission(Gmac* gmac);
#ifdef __cplusplus
}
#endif
#endif /* _GMAC_H_ */

View file

@ -0,0 +1,823 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/*---------------------------------------------------------------------------
* Headers
*---------------------------------------------------------------------------*/
#include "chip.h"
#include "trace.h"
#include "ring.h"
#include "peripherals/aic.h"
#include "peripherals/gmacd.h"
#include "peripherals/gmac.h"
#include "peripherals/l2cc.h"
#include "peripherals/pmc.h"
#include <string.h>
#include <assert.h>
//------------------------------------------------------------------------------
// Definitions
//------------------------------------------------------------------------------
// Interrupt bits
#define GMAC_INT_RX_BITS (GMAC_IER_RCOMP | GMAC_IER_RXUBR | GMAC_IER_ROVR)
#define GMAC_INT_TX_ERR_BITS (GMAC_IER_TUR | GMAC_IER_RLEX | GMAC_IER_TFC)
#define GMAC_INT_TX_BITS (GMAC_INT_TX_ERR_BITS | GMAC_IER_TCOMP)
/*---------------------------------------------------------------------------
* Types
*---------------------------------------------------------------------------*/
struct _gmacd_irq_handler {
Gmac* addr;
struct _gmacd** gmacd;
uint32_t irq;
aic_handler_t handler;
};
/*---------------------------------------------------------------------------
* IRQ Handlers
*---------------------------------------------------------------------------*/
#ifdef CONFIG_HAVE_GMAC_QUEUES
#if GMAC_NUM_QUEUES != 3
#error This driver assumes that GMAC_NUM_QUEUES is 3
#endif
#endif
static struct _gmacd* _gmacd0;
#ifdef GMAC1
static struct _gmacd* _gmacd1;
#endif
static void _gmacd_handler(struct _gmacd* gmacd, uint8_t queue);
static void _gmacd_gmac0_irq_handler(void)
{
_gmacd_handler(_gmacd0, 0);
}
#ifdef CONFIG_HAVE_GMAC_QUEUES
static void _gmacd_gmac0q1_irq_handler(void)
{
_gmacd_handler(_gmacd0, 1);
}
static void _gmacd_gmac0q2_irq_handler(void)
{
_gmacd_handler(_gmacd0, 2);
}
#endif
#ifdef GMAC1
static void _gmacd_gmac1_irq_handler(void)
{
_gmacd_handler(_gmacd1, 0);
}
#ifdef CONFIG_HAVE_GMAC_QUEUES
static void _gmacd_gmac1q1_irq_handler(void)
{
_gmacd_handler(_gmacd1, 1);
}
static void _gmacd_gmac1q2_irq_handler(void)
{
_gmacd_handler(_gmacd1, 2);
}
#endif
#endif
static const struct _gmacd_irq_handler _gmacd_irq_handlers[] = {
{ GMAC0, &_gmacd0, ID_GMAC0, _gmacd_gmac0_irq_handler },
#ifdef CONFIG_HAVE_GMAC_QUEUES
{ GMAC0, &_gmacd0, ID_GMAC0_Q1, _gmacd_gmac0q1_irq_handler },
{ GMAC0, &_gmacd0, ID_GMAC0_Q2, _gmacd_gmac0q2_irq_handler },
#endif
#ifdef GMAC1
{ GMAC1, &_gmacd1, ID_GMAC1, _gmacd_gmac1_irq_handler },
#ifdef CONFIG_HAVE_GMAC_QUEUES
{ GMAC1, &_gmacd1, ID_GMAC1_Q1, _gmacd_gmac1q1_irq_handler },
{ GMAC1, &_gmacd1, ID_GMAC1_Q2, _gmacd_gmac1q2_irq_handler },
#endif
#endif
};
/*---------------------------------------------------------------------------
* Dummy Buffers for unconfigured queues
*---------------------------------------------------------------------------*/
#define DUMMY_BUFFERS 2
#define DUMMY_UNITSIZE 128
/** TX descriptors list */
ALIGNED(8) SECTION(".region_ddr_nocache")
static struct _gmac_desc dummy_tx_desc[DUMMY_BUFFERS];
/** RX descriptors list */
ALIGNED(8) SECTION(".region_ddr_nocache")
static struct _gmac_desc dummy_rx_desc[DUMMY_BUFFERS];
/** Send Buffer */
ALIGNED(32)
static uint8_t dummy_buffer[DUMMY_BUFFERS * DUMMY_UNITSIZE];
/*---------------------------------------------------------------------------
* Local functions
*---------------------------------------------------------------------------*/
/**
* \brief Disable TX & reset registers and descriptor list
* \param gmacd Pointer to GMAC Driver instance.
*/
static void _gmacd_reset_tx(struct _gmacd* gmacd, uint8_t queue)
{
struct _gmacd_queue* q = &gmacd->queues[queue];
uint32_t addr = (uint32_t)q->tx_buffer;
uint32_t i;
/* Disable TX */
gmac_transmit_enable(gmacd->gmac, false);
/* Setup the TX descriptors */
RING_CLEAR(q->tx_head, q->tx_tail);
for (i = 0; i < q->tx_size; i++) {
q->tx_desc[i].addr = addr;
DSB();
q->tx_desc[i].status = GMAC_TX_STATUS_USED;
addr += GMAC_TX_UNITSIZE;
}
q->tx_desc[q->tx_size - 1].status |= GMAC_TX_STATUS_WRAP;
/* Transmit Buffer Queue Pointer Register */
gmac_set_tx_desc(gmacd->gmac, queue, q->tx_desc);
}
/**
* \brief Disable RX & reset registers and descriptor list
* \param gmacd Pointer to GMAC Driver instance.
*/
static void _gmacd_reset_rx(struct _gmacd* gmacd, uint8_t queue)
{
struct _gmacd_queue* q = &gmacd->queues[queue];
uint32_t addr = (uint32_t)q->rx_buffer;
uint32_t i;
/* Disable RX */
gmac_receive_enable(gmacd->gmac, false);
/* Setup the RX descriptors */
q->rx_head = 0;
for (i = 0; i < q->rx_size; i++) {
q->rx_desc[i].addr = addr & GMAC_RX_ADDR_MASK;
DSB();
q->rx_desc[i].status = 0;
addr += GMAC_RX_UNITSIZE;
}
q->rx_desc[q->rx_size - 1].addr |= GMAC_RX_ADDR_WRAP;
/* Receive Buffer Queue Pointer Register */
gmac_set_rx_desc(gmacd->gmac, queue, q->rx_desc);
}
/**
* \brief Process successfully sent packets
* \param gmacd Pointer to GMAC Driver instance.
*/
static void _gmacd_tx_complete_handler(struct _gmacd* gmacd, uint8_t queue)
{
Gmac* gmac = gmacd->gmac;
struct _gmacd_queue* q = &gmacd->queues[queue];
struct _gmac_desc *desc;
gmacd_callback_t callback;
uint32_t tsr;
//printf("<TX>\r\n");
/* Clear status */
tsr = gmac_get_tx_status(gmac);
gmac_clear_tx_status(gmac, tsr);
while (!RING_EMPTY(q->tx_head, q->tx_tail)) {
desc = &q->tx_desc[q->tx_tail];
/* Exit if frame has not been sent yet:
* On TX completion, the GMAC set the USED bit only into the
* very first buffer descriptor of the sent frame.
* Otherwise it updates this descriptor with status error bits.
* This is the descriptor writeback.
*/
if ((desc->status & GMAC_TX_STATUS_USED) == 0)
break;
/* Process all buffers of the current transmitted frame */
while ((desc->status & GMAC_TX_STATUS_LASTBUF) == 0) {
RING_INC(q->tx_tail, q->tx_size);
desc = &q->tx_desc[q->tx_tail];
}
/* Notify upper layer that a frame has been sent */
if (q->tx_callbacks) {
callback = q->tx_callbacks[q->tx_tail];
if (callback)
callback(queue, tsr);
}
/* Go to next frame */
RING_INC(q->tx_tail, q->tx_size);
}
/* If a wakeup callback has been set, notify upper layer that it can
send more packets now */
if (q->tx_wakeup_callback) {
if (RING_SPACE(q->tx_head, q->tx_tail, q->tx_size) >=
q->tx_wakeup_threshold) {
q->tx_wakeup_callback(queue);
}
}
}
/**
* \brief Reset TX queue when errors are detected
* \param gmacd Pointer to GMAC Driver instance.
*/
static void _gmacd_tx_error_handler(struct _gmacd* gmacd, uint8_t queue)
{
Gmac *gmac = gmacd->gmac;
struct _gmacd_queue* q = &gmacd->queues[queue];
struct _gmac_desc* desc;
gmacd_callback_t callback;
uint32_t tsr;
printf("<TXERR>\r\n");
/* Clear TXEN bit into the Network Configuration Register:
* this is a workaround to recover from TX lockups that
* occur on sama5d4 gmac (r1p24f2) when using scatter-gather.
* This issue has never been seen on sama5d4 gmac (r1p31).
*/
gmac_transmit_enable(gmac, false);
/* The following step should be optional since this function is called
* directly by the IRQ handler. Indeed, according to Cadence
* documentation, the transmission is halted on errors such as
* too many retries or transmit under run.
* However it would become mandatory if the call of this function
* were scheduled as a task by the IRQ handler (this is how Linux
* driver works). Then this function might compete with GMACD_Send().
*
* Setting bit 10, tx_halt, of the Network Control Register is not enough:
* We should wait for bit 3, tx_go, of the Transmit Status Register to
* be cleared at transmit completion if a frame is being transmitted.
*/
gmac_halt_transmission(gmac);
while (gmac_get_tx_status(gmac) & GMAC_TSR_TXGO);
/* Treat frames in TX queue including the ones that caused the error. */
while (!RING_EMPTY(q->tx_head, q->tx_tail)) {
int tx_completed = 0;
desc = &q->tx_desc[q->tx_tail];
/* Check USED bit on the very first buffer descriptor to validate
* TX completion.
*/
if (desc->status & GMAC_TX_STATUS_USED)
tx_completed = 1;
/* Go to the last buffer descriptor of the frame */
while ((desc->status & GMAC_TX_STATUS_LASTBUF) == 0) {
RING_INC(q->tx_tail, q->tx_size);
desc = &q->tx_desc[q->tx_tail];
}
/* Notify upper layer that a frame status */
// TODO: which error to notify?
if (q->tx_callbacks) {
callback = q->tx_callbacks[q->tx_tail];
if (callback)
callback(queue, tx_completed ? GMAC_TSR_TXCOMP : 0);
}
/* Go to next frame */
RING_INC(q->tx_tail, q->tx_size);
}
/* Reset TX queue */
_gmacd_reset_tx(gmacd, queue);
/* Clear status */
tsr = gmac_get_tx_status(gmac);
gmac_clear_tx_status(gmac, tsr);
/* Now we are ready to start transmission again */
gmac_transmit_enable(gmac, true);
if (q->tx_wakeup_callback)
q->tx_wakeup_callback(queue);
}
/*---------------------------------------------------------------------------
* Exported functions
*---------------------------------------------------------------------------*/
/**
* \brief GMAC Interrupt handler
* \param gmacd Pointer to GMAC Driver instance.
*/
static void _gmacd_handler(struct _gmacd * gmacd, uint8_t queue)
{
Gmac *gmac = gmacd->gmac;
struct _gmacd_queue* q = &gmacd->queues[queue];
uint32_t isr;
uint32_t rsr;
/* Interrupt Status Register is cleared on read */
while ((isr = gmac_get_it_status(gmac, queue)) != 0) {
/* RX packet */
if (isr & GMAC_INT_RX_BITS) {
/* Clear status */
rsr = gmac_get_rx_status(gmac);
gmac_clear_rx_status(gmac, rsr);
/* Invoke callback */
if (q->rx_callback)
q->rx_callback(queue, rsr);
}
/* TX error */
if (isr & GMAC_INT_TX_ERR_BITS) {
_gmacd_tx_error_handler(gmacd, queue);
break;
}
/* TX packet */
if (isr & GMAC_IER_TCOMP) {
_gmacd_tx_complete_handler(gmacd, queue);
}
/* HRESP not OK */
if (isr & GMAC_IER_HRESP) {
trace_error("HRESP not OK\n\r");
}
}
}
/**
* \brief Initialize the GMAC with the Gmac controller address
* \param gmacd Pointer to GMAC Driver instance.
* \param gmac Pointer to HW address for registers.
* \param enableCAF Enable/Disable CopyAllFrame.
* \param enableNBC Enable/Disable NoBroadCast.
*/
void gmacd_configure(struct _gmacd * gmacd,
Gmac * gmac, uint8_t enableCAF, uint8_t enableNBC)
{
uint32_t ncfgr;
int i;
/* Initialize struct */
gmacd->gmac = gmac;
gmac_configure(gmac);
uint32_t id = get_gmac_id_from_addr(gmac);
for (i = 0; i < ARRAY_SIZE(_gmacd_irq_handlers); i++) {
if (_gmacd_irq_handlers[i].addr == gmac) {
*_gmacd_irq_handlers[i].gmacd = gmacd;
aic_set_source_vector(_gmacd_irq_handlers[i].irq,
_gmacd_irq_handlers[i].handler);
}
}
aic_enable(id);
/* Enable the copy of data into the buffers
ignore broadcasts, and don't copy FCS. */
ncfgr = gmac_get_network_config_register(gmac);
ncfgr |= GMAC_NCFGR_FD;
if (enableCAF) {
ncfgr |= GMAC_NCFGR_CAF;
}
if (enableNBC) {
ncfgr |= GMAC_NCFGR_NBC;
}
gmac_set_network_config_register(gmac, ncfgr);
for (i = 0; i < GMAC_NUM_QUEUES; i++) {
gmacd_setup_queue(gmacd, i,
DUMMY_BUFFERS, dummy_buffer, dummy_rx_desc,
DUMMY_BUFFERS, dummy_buffer, dummy_tx_desc,
NULL);
}
}
/**
* Initialize necessary allocated buffer lists for GMAC Driver to transfer data.
* Must be invoked after GMACD_Init() but before RX/TX start.
* \param gmacd Pointer to GMAC Driver instance.
* \param rx_buffer Pointer to allocated buffer for RX. The address should
* be 8-byte aligned and the size should be
* GMAC_RX_UNITSIZE * wRxSize.
* \param rx_desc Pointer to allocated RX descriptor list.
* \param wRxSize RX size, in number of registered units (RX descriptors).
* \param tx_buffer Pointer to allocated buffer for TX. The address should
* be 8-byte aligned and the size should be
* GMAC_TX_UNITSIZE * wTxSize.
* \param tx_desc Pointer to allocated TX descriptor list.
* \param pTxCb Pointer to allocated TX callback list.
* \param wTxSize TX size, in number of registered units (TX descriptors).
* \return GMACD_OK or GMACD_PARAM.
* \note If input address is not 8-byte aligned the address is automatically
* adjusted and the list size is reduced by one.
*/
uint8_t gmacd_setup_queue(struct _gmacd* gmacd, uint8_t queue,
uint16_t rx_size, uint8_t* rx_buffer, struct _gmac_desc* rx_desc,
uint16_t tx_size, uint8_t* tx_buffer, struct _gmac_desc* tx_desc,
gmacd_callback_t *tx_callbacks)
{
Gmac *gmac = gmacd->gmac;
struct _gmacd_queue* q = &gmacd->queues[queue];
if (rx_size <= 1 || tx_size <= 1)
return GMACD_PARAM;
/* Assign RX buffers */
if (((uint32_t)rx_buffer & 0x7)
|| ((uint32_t)rx_desc & 0x7)) {
rx_size--;
trace_debug("RX list address adjusted\n\r");
}
q->rx_buffer = (uint8_t*)((uint32_t)rx_buffer & 0xFFFFFFF8);
q->rx_desc = (struct _gmac_desc *)((uint32_t)rx_desc & 0xFFFFFFF8);
q->rx_size = rx_size;
q->rx_callback = NULL;
/* Assign TX buffers */
if (((uint32_t)tx_buffer & 0x7)
|| ((uint32_t)tx_desc & 0x7)) {
tx_size--;
trace_debug("TX list address adjusted\n\r");
}
q->tx_buffer = (uint8_t*)((uint32_t)tx_buffer & 0xFFFFFFF8);
q->tx_desc = (struct _gmac_desc*)((uint32_t)tx_desc & 0xFFFFFFF8);
q->tx_size = tx_size;
q->tx_callbacks = tx_callbacks;
q->tx_wakeup_callback = NULL;
/* Reset TX & RX */
_gmacd_reset_rx(gmacd, queue);
_gmacd_reset_tx(gmacd, queue);
/* Setup the interrupts for RX/TX completion (and errors) */
gmac_enable_it(gmac, queue, GMAC_INT_RX_BITS | GMAC_INT_TX_BITS | GMAC_IER_HRESP);
return GMACD_OK;
}
void gmacd_start(struct _gmacd * gmacd)
{
/* Enable Rx and Tx, plus the stats register. */
gmac_transmit_enable(gmacd->gmac, true);
gmac_receive_enable(gmacd->gmac, true);
gmac_enable_statistics_write(gmacd->gmac, true);
}
/**
* Reset TX & RX queue & statistics
* \param gmacd Pointer to GMAC Driver instance.
*/
void gmacd_reset(struct _gmacd* gmacd)
{
int i;
for (i = 0; i < GMAC_NUM_QUEUES; i++) {
_gmacd_reset_rx(gmacd, i);
_gmacd_reset_tx(gmacd, i);
}
gmac_set_network_control_register(gmacd->gmac, GMAC_NCR_TXEN | GMAC_NCR_RXEN |
GMAC_NCR_WESTAT | GMAC_NCR_CLRSTAT);
}
/**
* \brief Send a frame splitted into buffers. If the frame size is larger than transfer buffer size
* error returned. If frame transfer status is monitored, specify callback for each frame.
* \param gmacd Pointer to GMAC Driver instance.
* \param sgl Pointer to a scatter-gather list describing the buffers of the ethernet frame.
* \param fTxCb Pointer to callback function.
*/
uint8_t gmacd_send_sg(struct _gmacd* gmacd, uint8_t queue,
const struct _gmac_sg_list* sgl, gmacd_callback_t callback)
{
Gmac* gmac = gmacd->gmac;
struct _gmacd_queue* q = &gmacd->queues[queue];
struct _gmac_desc* desc;
uint16_t idx, tx_head;
int i;
if (callback && !q->tx_callbacks) {
trace_error("Cannot set send callback, no tx_callbacks "\
"buffer configured for queue %u", queue);
}
/* Check parameter */
if (!sgl->size) {
trace_error("gmacd_send_sg: ethernet frame is empty.\r\n");
return GMACD_PARAM;
}
if (sgl->size >= q->tx_size) {
trace_error("gmacd_send_sg: ethernet frame has too many buffers.\r\n");
return GMACD_PARAM;
}
/* Check available space */
if (RING_SPACE(q->tx_head, q->tx_tail, q->tx_size) < sgl->size) {
trace_error("gmacd_send_sg: not enough free buffers in TX queue.\r\n");
return GMACD_TX_BUSY;
}
/* Tag end of TX queue */
tx_head = fixed_mod(q->tx_head + sgl->size, q->tx_size);
idx = tx_head;
if (q->tx_callbacks)
q->tx_callbacks[idx] = NULL;
desc = &q->tx_desc[idx];
desc->status |= GMAC_TX_STATUS_USED;
/* Update buffer descriptors in reverse order to avoid a race
* condition with hardware.
*/
for (i = sgl->size - 1; i >= 0; i--) {
const struct _gmac_sg *sg = &sgl->entries[i];
uint32_t status;
if (sg->size > GMAC_TX_UNITSIZE) {
trace_error("gmacd_send_sg: buffer size is too big.\r\n");
return GMACD_PARAM;
}
RING_DEC(idx, q->tx_size);
/* Reset TX callback */
if (q->tx_callbacks)
q->tx_callbacks[idx] = NULL;
desc = &q->tx_desc[idx];
/* Copy data into transmittion buffer */
if (sg->buffer && sg->size) {
memcpy((void*)desc->addr, sg->buffer, sg->size);
l2cc_clean_region(desc->addr, desc->addr + sg->size);
}
/* Compute buffer descriptor status word */
status = sg->size & GMAC_RX_STATUS_LENGTH_MASK;
if (i == (sgl->size - 1)) {
status |= GMAC_TX_STATUS_LASTBUF;
if (q->tx_callbacks)
q->tx_callbacks[idx] = callback;
}
if (idx == (q->tx_size - 1)) {
status |= GMAC_TX_STATUS_WRAP;
}
/* Update buffer descriptor status word: clear USED bit */
desc->status = status;
DSB();
}
/* Update TX ring buffer pointers */
q->tx_head = tx_head;
/* Now start to transmit if it is not already done */
gmac_start_transmission(gmac);
return GMACD_OK;
}
/**
* \brief Send a packet with GMAC. If the packet size is larger than transfer buffer size
* error returned. If packet transfer status is monitored, specify callback for each packet.
* \param gmacd Pointer to GMAC Driver instance.
* \param pBuffer The buffer to be send
* \param size The size of buffer to be send
* \param fTxCb Threshold Wakeup callback
* \return OK, Busy or invalid packet
*/
uint8_t gmacd_send(struct _gmacd* gmacd, uint8_t queue, void *buffer,
uint32_t size, gmacd_callback_t callback)
{
struct _gmac_sg sg;
struct _gmac_sg_list sgl;
/* Init single entry scatter-gather list */
sg.size = size;
sg.buffer = buffer;
sgl.size = 1;
sgl.entries = &sg;
return gmacd_send_sg(gmacd, queue, &sgl, callback);
}
/**
* Return current load of TX.
* \param gmacd Pointer to GMAC Driver instance.
*/
uint32_t gmacd_get_tx_load(struct _gmacd* gmacd, uint8_t queue)
{
struct _gmacd_queue* q = &gmacd->queues[queue];
return RING_CNT(q->tx_head, q->tx_tail, q->tx_size);
}
/**
* \brief Receive a packet with GMAC.
* If not enough buffer for the packet, the remaining data is lost but right
* frame length is returned.
* \param gmacd Pointer to GMAC Driver instance.
* \param pFrame Buffer to store the frame
* \param frameSize Size of the frame
* \param pRcvSize Received size
* \return OK, no data, or frame too small
*/
uint8_t gmacd_poll(struct _gmacd* gmacd, uint8_t queue,
uint8_t* buffer, uint32_t buffer_size, uint32_t* recv_size)
{
struct _gmacd_queue* q = &gmacd->queues[queue];
struct _gmac_desc *desc;
uint32_t idx;
uint32_t cur_frame_size = 0;
uint8_t *cur_frame = 0;
if (!buffer)
return GMACD_PARAM;
/* Set the default return value */
*recv_size = 0;
/* Process RX descriptors */
idx = q->rx_head;
desc = &q->rx_desc[idx];
while (desc->addr & GMAC_RX_ADDR_OWN) {
/* A start of frame has been received, discard previous fragments */
if (desc->status & GMAC_RX_STATUS_SOF) {
/* Skip previous fragment */
while (idx != q->rx_head) {
desc = &q->rx_desc[q->rx_head];
desc->addr &= ~GMAC_RX_ADDR_OWN;
RING_INC(q->rx_head, q->rx_size);
}
cur_frame = buffer;
cur_frame_size = 0;
}
/* Increment the index */
RING_INC(idx, q->rx_size);
/* Copy data in the frame buffer */
if (cur_frame) {
if (idx == q->rx_head) {
trace_info("no EOF (buffers probably too small)\r\n");
do {
desc = &q->rx_desc[q->rx_head];
desc->addr &= ~GMAC_RX_ADDR_OWN;
RING_INC(q->rx_head, q->rx_size);
} while (idx != q->rx_head);
return GMACD_RX_NULL;
}
/* Copy the buffer into the application frame */
uint32_t length = GMAC_RX_UNITSIZE;
if ((cur_frame_size + length) > buffer_size) {
length = buffer_size - cur_frame_size;
}
uint32_t addr = desc->addr & GMAC_RX_ADDR_MASK;
l2cc_invalidate_region(addr, addr + length);
memcpy(cur_frame, (void*)addr, length);
cur_frame += length;
cur_frame_size += length;
/* An end of frame has been received, return the data */
if (desc->status & GMAC_RX_STATUS_EOF) {
/* Frame size from the GMAC */
*recv_size = desc->status & GMAC_RX_STATUS_LENGTH_MASK;
/* Application frame buffer is too small all
* data have not been copied */
if (cur_frame_size < *recv_size) {
return GMACD_SIZE_TOO_SMALL;
}
/* All data have been copied in the application
* frame buffer => release descriptors */
while (q->rx_head != idx) {
desc = &q->rx_desc[q->rx_head];
desc->addr &= ~GMAC_RX_ADDR_OWN;
RING_INC(q->rx_head, q->rx_size);
}
return GMACD_OK;
}
}
/* SOF has not been detected, skip the fragment */
else {
desc->addr &= ~GMAC_RX_ADDR_OWN;
q->rx_head = idx;
}
/* Process the next buffer */
desc = &q->rx_desc[idx];
}
return GMACD_RX_NULL;
}
/**
* \brief Registers pRxCb callback. Callback will be invoked after the next received
* frame. When GMAC_Poll() returns GMAC_RX_NO_DATA the application task call GMAC_Set_RxCb()
* to register pRxCb() callback and enters suspend state. The callback is in charge
* to resume the task once a new frame has been received. The next time GMAC_Poll()
* is called, it will be successful.
* \param gmacd Pointer to GMAC Driver instance.
* \param fRxCb Pointer to callback function
* \return OK, no data, or frame too small
*/
void gmacd_set_rx_callback(struct _gmacd* gmacd, uint8_t queue, gmacd_callback_t callback)
{
struct _gmacd_queue* q = &gmacd->queues[queue];
if (!callback) {
gmac_disable_it(gmacd->gmac, queue, GMAC_IDR_RCOMP);
q->rx_callback = NULL;
} else {
q->rx_callback = callback;
gmac_enable_it(gmacd->gmac, queue, GMAC_IER_RCOMP);
}
}
/**
* Register/Clear TX wakeup callback.
*
* When GMACD_Send() returns GMACD_TX_BUSY (all TD busy) the application
* task calls GMACD_SetTxWakeupCallback() to register fWakeup() callback and
* enters suspend state. The callback is in charge to resume the task once
* several TD have been released. The next time GMACD_Send() will be called,
* it shall be successful.
*
* This function is usually invoked with NULL callback from the TX wakeup
* callback itself, to unregister. Once the callback has resumed the
* application task, there is no need to invoke the callback again.
*
* \param gmacd Pointer to GMAC Driver instance.
* \param fWakeup Wakeup callback.
* \param bThreshold Number of free TD before wakeup callback invoked.
* \return GMACD_OK, GMACD_PARAM on parameter error.
*/
uint8_t gmacd_set_tx_wakeup_callback(struct _gmacd* gmacd, uint8_t queue,
gmacd_wakeup_cb_t callback, uint16_t threshold)
{
struct _gmacd_queue* q = &gmacd->queues[queue];
if (!callback) {
q->tx_wakeup_callback = NULL;
} else {
if (threshold <= q->tx_size) {
q->tx_wakeup_callback = callback;
q->tx_wakeup_threshold = threshold;
} else {
return GMACD_PARAM;
}
}
return GMACD_OK;
}
/**@}*/

View file

@ -0,0 +1,189 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2012, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/** \file */
/** \addtogroup gmacd_module
* @{
* Implement GMAC data transfer and PHY management functions.
*
* \section Usage
* -# Implement GMAC interrupt handler, which must invoke GMACD_Handler()
* to handle GMAC interrupt events.
* -# Implement struct _gmacd instance in application.
* -# Initialize the instance with GMACD_Init() and GMACD_InitTransfer(),
* so that GMAC data can be transmitted/received.
* -# Some management callbacks can be set by GMACD_SetRxCallback()
* and GMACD_SetTxWakeupCallback().
* -# Send ethernet packets using GMACD_Send(), GMACD_TxLoad() is used
* to check the free space in TX queue.
* -# Check and obtain received ethernet packets via GMACD_Poll().
*
* \sa \ref gmacb_module, \ref gmac_module
*
* Related files:\n
* \ref gmacd.c\n
* \ref gmacd.h.\n
*
* \defgroup gmacd_defines GMAC Driver Defines
* \defgroup gmacd_types GMAC Driver Types
* \defgroup gmacd_functions GMAC Driver Functions
*/
/**@}*/
#ifndef _GMACD_H_
#define _GMACD_H_
/*---------------------------------------------------------------------------
* Headers
*---------------------------------------------------------------------------*/
#include "peripherals/gmac.h"
#include <stdint.h>
/*---------------------------------------------------------------------------
* Definitions
*---------------------------------------------------------------------------*/
/** \addtogroup gmacd_defines
@{*/
/** \addtogroup gmacd_buf_size GMACD Default Buffer Size
@{*/
#define GMAC_RX_UNITSIZE 128 /**< RX buffer size, must be 128 */
#define GMAC_TX_UNITSIZE 1536 /**< TX buffer size, must be multiple
of 32 (cache line) */
/** @}*/
/** \addtogroup gmacd_rc GMACD Return Codes
@{*/
#define GMACD_OK 0 /**< Operation OK */
#define GMACD_TX_BUSY 1 /**< TX in progress */
#define GMACD_RX_NULL 1 /**< No data received */
/** Buffer size not enough */
#define GMACD_SIZE_TOO_SMALL 2
/** Parameter error, TX packet invalid or RX size too small */
#define GMACD_PARAM 3
/** Transter is not initialized */
#define GMACD_NOT_INITIALIZED 4
/** @}*/
/** @}*/
/*---------------------------------------------------------------------------
* Types
*---------------------------------------------------------------------------*/
/** \addtogroup gmacd_types
@{*/
/** RX/TX callback */
typedef void (*gmacd_callback_t)(uint8_t queue, uint32_t status);
/** TX Wakeup callback */
typedef void (*gmacd_wakeup_cb_t)(uint8_t queue);
/** GMAC scatter-gather entry */
struct _gmac_sg {
uint32_t size;
void *buffer;
struct _gmac_sg *next;
};
/** GMAC scatter-gather list */
struct _gmac_sg_list {
uint32_t size;
struct _gmac_sg *entries;
};
struct _gmacd_queue {
uint8_t *rx_buffer;
struct _gmac_desc *rx_desc;
uint16_t rx_size;
uint16_t rx_head;
gmacd_callback_t rx_callback;
uint8_t *tx_buffer;
struct _gmac_desc *tx_desc;
uint16_t tx_size;
uint16_t tx_head;
uint16_t tx_tail;
gmacd_callback_t *tx_callbacks;
gmacd_wakeup_cb_t tx_wakeup_callback;
uint16_t tx_wakeup_threshold;
};
/**
* GMAC driver struct.
*/
struct _gmacd {
Gmac* gmac; /**< GMAC instance */
struct _gmacd_queue queues[GMAC_NUM_QUEUES];
};
/** @}*/
/** \addtogroup gmacd_functions
@{*/
/*---------------------------------------------------------------------------
* GMAC Exported functions
*---------------------------------------------------------------------------*/
extern void gmacd_configure(struct _gmacd* gmacd, Gmac *pHw, uint8_t enableCAF, uint8_t enableNBC);
extern uint8_t gmacd_setup_queue(struct _gmacd* gmacd, uint8_t queue,
uint16_t rx_size, uint8_t* rx_buffer, struct _gmac_desc* rx_desc,
uint16_t tx_size, uint8_t* tx_buffer, struct _gmac_desc* tx_desc,
gmacd_callback_t *tx_callbacks);
extern void gmacd_start(struct _gmacd* gmacd);
extern void gmacd_reset(struct _gmacd* gmacd);
extern uint8_t gmacd_send_sg(struct _gmacd* gmacd, uint8_t queue,
const struct _gmac_sg_list* sgl, gmacd_callback_t callback);
extern uint8_t gmacd_send(struct _gmacd* gmacd, uint8_t queue, void *buffer,
uint32_t size, gmacd_callback_t callback);
extern uint32_t gmacd_get_tx_load(struct _gmacd* gmacd, uint8_t queue);
extern uint8_t gmacd_poll(struct _gmacd* gmacd, uint8_t queue,
uint8_t* buffer, uint32_t buffer_size, uint32_t* recv_size);
extern void gmacd_set_rx_callback(struct _gmacd *gmacd, uint8_t queue,
gmacd_callback_t callback);
extern uint8_t gmacd_set_tx_wakeup_callback(struct _gmacd *gmacd,
uint8_t queue, gmacd_wakeup_cb_t wakeup_callback,
uint16_t threshold);
/** @}*/
#endif /* _GMACD_H_ */

View file

@ -0,0 +1,250 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* Implementation of HSMC functions.
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include "peripherals/pmc.h"
#include "peripherals/hsmc.h"
/*----------------------------------------------------------------------------
* Local functions
*----------------------------------------------------------------------------*/
static uint32_t _nfc_read_cmd(uint32_t cmd)
{
return *(volatile uint32_t*)(NFC_ADDR + cmd);
}
static void _nfc_write_cmd(uint32_t cmd, uint32_t value)
{
*(volatile uint32_t*)(NFC_ADDR + cmd) = value;
}
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/**
* \brief Sets SMC timing for NAND FLASH.
* \param cs chip select.
* \param bus_width bus width 8/16.
*/
void hsmc_nand_configure(uint8_t cs, uint8_t bus_width)
{
pmc_enable_peripheral(ID_HSMC);
HSMC->SMC_CS_NUMBER[cs].HSMC_SETUP =
HSMC_SETUP_NWE_SETUP(2) |
HSMC_SETUP_NCS_WR_SETUP(2) |
HSMC_SETUP_NRD_SETUP(2) |
HSMC_SETUP_NCS_RD_SETUP(2);
HSMC->SMC_CS_NUMBER[cs].HSMC_PULSE =
HSMC_PULSE_NWE_PULSE(7) |
HSMC_PULSE_NCS_WR_PULSE(7) |
HSMC_PULSE_NRD_PULSE(7) |
HSMC_PULSE_NCS_RD_PULSE(7);
HSMC->SMC_CS_NUMBER[cs].HSMC_CYCLE =
HSMC_CYCLE_NWE_CYCLE(13) |
HSMC_CYCLE_NRD_CYCLE(13);
HSMC->SMC_CS_NUMBER[cs].HSMC_TIMINGS =
HSMC_TIMINGS_TCLR(3) |
HSMC_TIMINGS_TADL(27) |
HSMC_TIMINGS_TAR(3) |
HSMC_TIMINGS_TRR(6) |
HSMC_TIMINGS_TWB(5) |
HSMC_TIMINGS_RBNSEL(3) |
HSMC_TIMINGS_NFSEL;
HSMC->SMC_CS_NUMBER[cs].HSMC_MODE =
HSMC_MODE_READ_MODE |
HSMC_MODE_WRITE_MODE |
((bus_width == 8 ) ? HSMC_MODE_DBW_BIT_8 : HSMC_MODE_DBW_BIT_16) |
HSMC_MODE_TDF_CYCLES(1);
}
/**
* \brief Sets SMC timing for NOR FLASH.
* \param cs chip select.
* \param bus_width bus width 8/16.
*/
void hsmc_nor_configure(uint8_t cs, uint8_t bus_width)
{
pmc_enable_peripheral(ID_HSMC);
HSMC->SMC_CS_NUMBER[cs].HSMC_SETUP =
HSMC_SETUP_NWE_SETUP(1) |
HSMC_SETUP_NCS_WR_SETUP(0) |
HSMC_SETUP_NRD_SETUP(2) |
HSMC_SETUP_NCS_RD_SETUP(0);
HSMC->SMC_CS_NUMBER[cs].HSMC_PULSE =
HSMC_PULSE_NWE_PULSE(10) |
HSMC_PULSE_NCS_WR_PULSE(10) |
HSMC_PULSE_NRD_PULSE(11) |
HSMC_PULSE_NCS_RD_PULSE(11);
HSMC->SMC_CS_NUMBER[cs].HSMC_CYCLE =
HSMC_CYCLE_NWE_CYCLE(11) |
HSMC_CYCLE_NRD_CYCLE(14);
HSMC->SMC_CS_NUMBER[cs].HSMC_TIMINGS = 0;
HSMC->SMC_CS_NUMBER[cs].HSMC_MODE =
HSMC_MODE_READ_MODE |
HSMC_MODE_WRITE_MODE |
(bus_width == 8 ? HSMC_MODE_DBW_BIT_8 : HSMC_MODE_DBW_BIT_16) |
HSMC_MODE_EXNW_MODE_DISABLED |
HSMC_MODE_TDF_CYCLES(1);
}
/**
* \brief Reset NFC controller.
*/
void hsmc_nfc_reset(void)
{
/* Disable all the SMC NFC interrupts */
HSMC->HSMC_IDR = 0xFFFFFFFF;
HSMC->HSMC_CTRL = 0;
}
/**
* \brief Check if spare area be read in read mode.
*
* \return Returns true if NFC controller reads both main and spare area in
* read mode, otherwise returns false.
*/
bool hsmc_nfc_is_spare_read_enabled(void)
{
return (((HSMC->HSMC_CFG) >> 9) & 0x1) != 0;
}
/**
* \brief Check if spare area be written in write mode.
*
* \return Returns true if NFC controller writes both main and spare area in
* write mode, otherwise returns false.
*/
bool hsmc_nfc_is_spare_write_enabled(void)
{
return (((HSMC->HSMC_CFG) >> 8) & 0x1) != 0;
}
/**
* \brief Check if NFC Controller is busy.
*
* \return Returns 1 if NFC Controller is activated and accesses the memory device,
* otherwise returns 0.
*/
bool hsmc_nfc_is_nfc_busy(void)
{
return ((HSMC->HSMC_SR & HSMC_SR_NFCBUSY) == HSMC_SR_NFCBUSY);
}
/**
* \brief Check if the host controller is busy.
* \return Returns 1 if the host controller is busy, otherwise returns 0.
*/
static bool smc_nfc_is_host_busy(void)
{
return (_nfc_read_cmd(NFCADDR_CMD_NFCCMD) & 0x8000000) == 0x8000000;
}
/**
* \brief Wait for Ready-busy pin falling and then rising.
*/
void hsmc_wait_rb(void)
{
/* Wait for RB pin falling */
while ((HSMC->HSMC_SR & HSMC_SR_RB_FALL) != HSMC_SR_RB_FALL);
/* Wait for RB pin rising */
while ((HSMC->HSMC_SR & HSMC_SR_RB_RISE) != HSMC_SR_RB_RISE);
}
/**
* \brief Wait for NFC command has done.
*/
void hsmc_nfc_wait_cmd_done(void)
{
while ((HSMC->HSMC_SR & HSMC_SR_CMDDONE) != HSMC_SR_CMDDONE);
}
/**
* \brief Wait for NFC Data Transfer Terminated.
*/
void hsmc_nfc_wait_xfr_done(void)
{
while ((HSMC->HSMC_SR & HSMC_SR_XFRDONE) != HSMC_SR_XFRDONE);
}
/**
* \brief Wait for NFC Ready/Busy Line 3 Edge Detected.
*/
void hsmc_nfc_wait_rb_busy(void)
{
while ((HSMC->HSMC_SR & HSMC_SR_RB_EDGE0) != HSMC_SR_RB_EDGE0);
}
/**
* \brief Wait for PMECC ready.
*/
void hsmc_pmecc_wait_ready(void)
{
while((HSMC->HSMC_PMECCSR) & HSMC_PMECCSR_BUSY);
}
/**
* \brief Uses the HOST NANDFLASH controller to send a command to the NFC.
* \param cmd command to send.
* \param address_cycle address cycle when command access id decoded.
* \param cycle0 address at first cycle.
*/
void hsmc_nfc_send_cmd(uint32_t cmd, uint32_t address_cycle, uint32_t cycle0)
{
/* Wait until host controller is not busy. */
while (smc_nfc_is_host_busy());
/* Send the command plus the ADDR_CYCLE */
HSMC->HSMC_ADDR = cycle0;
_nfc_write_cmd(cmd, address_cycle);
hsmc_nfc_wait_cmd_done();
}

View file

@ -0,0 +1,139 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* Definitions and function prototype for smc module
*/
#ifndef _HSMC_
#define _HSMC_
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include <stdbool.h>
#include <stdint.h>
/*----------------------------------------------------------------------------
* Macros
*----------------------------------------------------------------------------*/
#define hsmc_nfc_configure(mode) {HSMC->HSMC_CFG = mode ;}
#define hsmc_nfc_enable() {HSMC->HSMC_CTRL |= HSMC_CTRL_NFCEN;}
#define hsmc_nfc_disable() {HSMC->HSMC_CTRL |= HSMC_CTRL_NFCDIS;}
#define hsmc_nfc_get_status() {HSMC->HSMC_SR;}
#define hsmc_nfc_enable_spare_read() {HSMC->HSMC_CFG |= HSMC_CFG_RSPARE;}
#define hsmc_nfc_disable_spare_read() {HSMC->HSMC_CFG &= (~HSMC_CFG_RSPARE);}
#define hsmc_nfc_enable_spare_write() {HSMC->HSMC_CFG |= HSMC_CFG_WSPARE;}
#define hsmc_nfc_disable_spare_write() {HSMC->HSMC_CFG &= (~HSMC_CFG_WSPARE);}
#define hsmc_pmecc_reset() {HSMC->HSMC_PMECCTRL = HSMC_PMECCTRL_RST; }
#define hsmc_pmecc_or_reset() {HSMC->HSMC_PMECCTRL |= HSMC_PMECCTRL_RST; }
#define hsmc_pmecc_data_phase() {HSMC->HSMC_PMECCTRL |= HSMC_PMECCTRL_DATA; }
#define hsmc_pmecc_enable_write() {HSMC->HSMC_PMECCFG |= HSMC_PMECCFG_NANDWR;}
#define hsmc_pmecc_enable_read() {HSMC->HSMC_PMECCFG &= (~HSMC_PMECCFG_NANDWR);}
#define hsmc_pmecc_error_status() (HSMC->HSMC_PMECCISR )
#define hsmc_pmecc_enable() {HSMC->HSMC_PMECCTRL = HSMC_PMECCTRL_ENABLE;}
#define hsmc_pmecc_disable() {HSMC->HSMC_PMECCTRL = HSMC_PMECCTRL_DISABLE;}
#define hsmc_pmecc_auto_enable() {HSMC->HSMC_PMECCFG |= HSMC_PMECCFG_AUTO;}
#define hsmc_pmecc_auto_disable() {HSMC->HSMC_PMECCFG &= (~HSMC_PMECCFG_AUTO);}
#define hsmc_pmecc_auto_apare_en() ((HSMC->HSMC_PMECCFG & HSMC_PMECCFG_SPAREEN) == HSMC_PMECCFG_SPAREEN)
#define hsmc_pmecc(i) (HSMC->SMC_PMECC[i])
/*----------------------------------------------------------------------------
* Definitions
*----------------------------------------------------------------------------*/
#define HSMC_SR_RB_EDGE0 (0x1u << 24)
/* -------- NFCADDR_CMD : NFC Address Command -------- */
#define NFCADDR_CMD_CMD1 (0xFFu << 2) /* Command Register Value for Cycle 1 */
#define NFCADDR_CMD_CMD2 (0xFFu << 10) /* Command Register Value for Cycle 2 */
#define NFCADDR_CMD_VCMD2 (0x1u << 18) /* Valid Cycle 2 Command */
#define NFCADDR_CMD_ACYCLE (0x7u << 19) /* Number of Address required for the current command */
#define NFCADDR_CMD_ACYCLE_NONE (0x0u << 19) /* No address cycle */
#define NFCADDR_CMD_ACYCLE_ONE (0x1u << 19) /* One address cycle */
#define NFCADDR_CMD_ACYCLE_TWO (0x2u << 19) /* Two address cycles */
#define NFCADDR_CMD_ACYCLE_THREE (0x3u << 19) /* Three address cycles */
#define NFCADDR_CMD_ACYCLE_FOUR (0x4u << 19) /* Four address cycles */
#define NFCADDR_CMD_ACYCLE_FIVE (0x5u << 19) /* Five address cycles */
#define NFCADDR_CMD_CSID (0x7u << 22) /* Chip Select Identifier */
#define NFCADDR_CMD_CSID_0 (0x0u << 22) /* CS0 */
#define NFCADDR_CMD_CSID_1 (0x1u << 22) /* CS1 */
#define NFCADDR_CMD_CSID_2 (0x2u << 22) /* CS2 */
#define NFCADDR_CMD_CSID_3 (0x3u << 22) /* CS3 */
#define NFCADDR_CMD_CSID_4 (0x4u << 22) /* CS4 */
#define NFCADDR_CMD_CSID_5 (0x5u << 22) /* CS5 */
#define NFCADDR_CMD_CSID_6 (0x6u << 22) /* CS6 */
#define NFCADDR_CMD_CSID_7 (0x7u << 22) /* CS7 */
#define NFCADDR_CMD_DATAEN (0x1u << 25) /* NFC Data Enable */
#define NFCADDR_CMD_DATADIS (0x0u << 25) /* NFC Data disable */
#define NFCADDR_CMD_NFCRD (0x0u << 26) /* NFC Read Enable */
#define NFCADDR_CMD_NFCWR (0x1u << 26) /* NFC Write Enable */
#define NFCADDR_CMD_NFCCMD (0x1u << 27) /* NFC Command Enable */
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
extern void hsmc_nand_configure(uint8_t cs, uint8_t bus_width);
extern void hsmc_nor_configure(uint8_t cs, uint8_t bus_width);
extern void hsmc_nfc_reset(void);
extern bool hsmc_nfc_is_spare_read_enabled(void);
extern bool hsmc_nfc_is_spare_write_enabled(void);
extern bool hsmc_nfc_is_nfc_busy(void);
extern void hsmc_wait_rb(void);
extern void hsmc_nfc_send_cmd(uint32_t cmd, uint32_t address_cycle, uint32_t cycle0);
extern void hsmc_nfc_wait_cmd_done(void);
extern void hsmc_nfc_wait_xfr_done(void);
extern void hsmc_nfc_wait_rb_busy(void);
extern void hsmc_nfc_wait_hamming_ready(void);
extern void hsmc_pmecc_wait_ready(void);
#endif /* _HSMC_ */

View file

@ -0,0 +1,694 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2013, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include "peripherals/isc.h"
/*----------------------------------------------------------------------------
* Local functions
*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
* Export functions
*----------------------------------------------------------------------------*/
/*------------------------------------------
* ISC Control functions
*----------------------------------------*/
/**
* \brief Send Capture Input Stream Command to start a single shot capture or a
* multiple frame.
*/
void isc_start_capture(void)
{
ISC->ISC_CTRLEN = ISC_CTRLEN_CAPTURE;
}
/**
* \brief end the capture at the next Vertical Synchronization Detection.
*/
void isc_stop_capture(void)
{
ISC->ISC_CTRLDIS = ISC_CTRLDIS_DISABLE;
}
/**
* \brief Returns ISC Control Status.
*/
uint32_t isc_get_ctrl_status(void)
{
return (ISC->ISC_CTRLSR);
}
/**
* \brief update the color profile.
*/
void isc_update_profile(void)
{
ISC->ISC_CTRLEN = ISC_CTRLEN_UPPRO;
while((ISC->ISC_CTRLSR & ISC_CTRLSR_UPPRO) == ISC_CTRLSR_UPPRO);
}
/**
* \brief Perform software reset of the interface.
*/
void isc_software_reset(void)
{
ISC->ISC_CTRLDIS = ISC_CTRLDIS_SWRST;
}
/*------------------------------------------
* PFE(Parallel Front End) functions
*----------------------------------------*/
/**
* \brief configure PFE(Parallel Front End) video mode.
* \param vmode: Parallel Front End Mode
*/
void isc_pfe_set_video_mode(uint32_t vmode)
{
ISC->ISC_PFE_CFG0 &= ~ISC_PFE_CFG0_MODE_Msk;
ISC->ISC_PFE_CFG0 |= vmode;
}
/**
* \brief set PFE(Parallel Front End) H/V synchronization polarity.
* \param hpol: Horizontal Synchronization Polarity
* \param vpol: Vertical Synchronization Polarity
*/
void isc_pfe_set_sync_polarity(uint32_t hpol, uint32_t vpol)
{
ISC->ISC_PFE_CFG0 &= ~ISC_PFE_CFG0_HPOL;
ISC->ISC_PFE_CFG0 &= ~ISC_PFE_CFG0_VPOL;
ISC->ISC_PFE_CFG0 |= hpol | vpol;
}
/**
* \brief set PFE(Parallel Front End) pixel clock polarity.
* \param ppol: pixel clock Polarity, The pixel stream is sampled on the
* rising or falling edge of the pixel clock
*/
void isc_pfe_set_pixel_polarity(uint32_t ppol)
{
ISC->ISC_PFE_CFG0 &= ~ISC_PFE_CFG0_PPOL;
ISC->ISC_PFE_CFG0 |= ppol ;
}
/**
* \brief set PFE(Parallel Front End) field polarity.
* \param fpol: Top/bottom field polarity configuration.
*/
void isc_pfe_set_field_polarity(uint32_t fpol)
{
ISC->ISC_PFE_CFG0 &= ~ISC_PFE_CFG0_FPOL;
ISC->ISC_PFE_CFG0 |= fpol ;
}
/**
* \brief Enables/disable PFE(Parallel Front End) cropping
* \param enCol: Column Cropping enable/disable(1/0)
* \param enRow: Row Cropping enable/disable(1/0)
*/
void isc_pfe_set_cropping_enabled(uint8_t enCol, uint8_t enRow)
{
ISC->ISC_PFE_CFG0 &= ~ISC_PFE_CFG0_COLEN;
ISC->ISC_PFE_CFG0 &= ~ISC_PFE_CFG0_ROWEN;
if (enCol) ISC->ISC_PFE_CFG0 |=ISC_PFE_CFG0_COLEN;
if (enRow) ISC->ISC_PFE_CFG0 |=ISC_PFE_CFG0_ROWEN;
}
/**
* \brief set PFE(Parallel Front End) Bits Per Sample.
* \param bps: Bits Per Sample.
*/
void isc_pfe_set_bps(uint32_t bps)
{
ISC->ISC_PFE_CFG0 &= ~ISC_PFE_CFG0_BPS_Msk;
ISC->ISC_PFE_CFG0 |= bps ;
}
/**
* \brief set PFE(Parallel Front End)in single shot mode
*/
void isc_pfe_set_single_shot(void)
{
ISC->ISC_PFE_CFG0 &= ~ISC_PFE_CFG0_CONT;
}
/**
* \brief set PFE(Parallel Front End)in continuous mode
*/
void isc_pfe_set_continuous_shot(void)
{
ISC->ISC_PFE_CFG0 |= ISC_PFE_CFG0_CONT;
}
/**
* \brief set PFE(Parallel Front End) gated clock.
* \param en: enable/disable gated clock.
*/
void isc_pfe_set_gated_clock(uint8_t en)
{
ISC->ISC_PFE_CFG0 &= ~ISC_PFE_CFG0_GATED;
if (en) ISC->ISC_PFE_CFG0 |= ISC_PFE_CFG0_GATED ;
}
/**
* \brief configure PFE(Parallel Front End) cropping area.
* \param Hstart: Horizontal starting position of the cropping area
* \param Hend: Horizontal ending position of the cropping area
* \param Vstart: Vertical starting position of the cropping area
* \param Hend: Vertical ending position of the cropping area
*/
void isc_pfe_set_cropping_area(
uint32_t Hstart, uint32_t Hend, uint32_t Vstart, uint32_t Vend)
{
ISC->ISC_PFE_CFG1 = ISC_PFE_CFG1_COLMIN(Hstart) | ISC_PFE_CFG1_COLMAX(Hend);
ISC->ISC_PFE_CFG2 = ISC_PFE_CFG2_ROWMIN(Vstart) | ISC_PFE_CFG2_ROWMAX(Vend);
}
/*------------------------------------------
* Clock configuration functions
*----------------------------------------*/
/**
* \brief Configure the ISP clock.
* \param ispClockDiv ISP Clock Divider.
* \param ispClockSelection ISP Clock Selection.
0: HCLOCK is selected.
1: GCK is selected.
*/
void isc_configure_isp_clock(uint32_t ispClockDiv, uint32_t ispClockSelection)
{
ISC->ISC_CLKCFG |= ISC_CLKCFG_ICDIV(ispClockDiv) | (ispClockSelection << 8);
}
/**
* \brief Enables the ISP clock.
*/
void isc_enable_isp_clock(void)
{
ISC->ISC_CLKEN = ISC_CLKEN_ICEN;
}
/**
* \brief Disables the ISP clock.
*/
void isc_disable_isp_clock(void)
{
ISC->ISC_CLKDIS = ISC_CLKDIS_ICDIS;
}
/**
* \brief Software reset the ISP clock.
*/
void isc_reset_isp_clock(void)
{
ISC->ISC_CLKDIS = ISC_CLKDIS_ICSWRST;
}
/**
* \brief Configure the Master clock.
* \param masterClockDiv Master Clock Divider.
* \param masterClockSelection Master Clock Selection.
0: HCLOCK is selected.
1: GCK is selected.
2: 480-MHz system clock is selected.
*/
void isc_configure_master_clock(uint32_t masterClockDiv, uint32_t masterClockSelection)
{
ISC->ISC_CLKCFG |= ISC_CLKCFG_MCDIV(masterClockDiv)
| ISC_CLKCFG_MCSEL(masterClockSelection);
}
/**
* \brief Enables the master clock.
*/
void isc_enable_master_clock(void)
{
ISC->ISC_CLKEN = ISC_CLKEN_MCEN;
}
/**
* \brief Disables the master clock.
*/
void isc_disable_master_clock(void)
{
ISC->ISC_CLKDIS = ISC_CLKDIS_MCDIS;
}
/**
* \brief Software reset the master clock.
*/
void isc_reset_master_clock(void)
{
ISC->ISC_CLKDIS = ISC_CLKDIS_MCSWRST;
}
/**
* \brief Returns ISC clock Status.
*/
uint32_t isc_get_clock_status(void)
{
return (ISC->ISC_CLKSR);
}
/*------------------------------------------
* Interrupt functions
*----------------------------------------*/
/**
* \brief Enable ISC interrupt
* \param flag of interrupt to enable
*/
void isc_enable_interrupt(uint32_t flag)
{
ISC->ISC_INTEN = flag;
}
/**
* \brief Disable ISC interrupt
* \param flag of interrupt to disable
*/
void isc_disable_interrupt(uint32_t flag)
{
ISC->ISC_INTDIS = flag;
}
/**
* \brief Return ISC status register
* \return Status of ISC register
*/
uint32_t isc_interrupt_status(void)
{
return(ISC->ISC_INTSR);
}
/*------------------------------------------
* White Balance functions
*----------------------------------------*/
/**
* \brief Enables/disable White Balance.
*/
void isc_wb_enabled(uint8_t enabled)
{
if (enabled)
ISC->ISC_WB_CTRL = ISC_WB_CTRL_ENABLE;
else
ISC->ISC_WB_CTRL = 0;
}
/**
* \brief White Balance Bayer Configuration (Pixel Color Pattern).
*/
void isc_wb_set_bayer_pattern(uint8_t pattern)
{
ISC->ISC_WB_CFG = pattern;
}
/**
* \brief adjust White Balance with color component.
* \param rOffset Offset Red Component (signed 13 bits 1:12:0)
* \param grOffset Offset Green Component for Red Row (signed 13 bits 1:12:0)
* \param bOffset Offset Blue Component (signed 13 bits, 1:12:0)
* \param gbOffset Offset Green Component for Blue Row (signed 13 bits, 1:12:0)
* \param rGain Red Component Gain (unsigned 13 bits, 0:4:9)
* \param grGain Green Component (Red row) Gain (unsigned 13 bits, 0:4:9)
* \param bGain Blue Component Gain (unsigned 13 bits, 0:4:9)
* \param gbGain Green Component (Blue row) Gain (unsigned 13 bits, 0:4:9)
*/
void isc_wb_adjust_bayer_color(uint32_t rOffset, uint32_t grOffset,
uint32_t bOffset, uint32_t gbOffset,
uint32_t rGain, uint32_t grGain,
uint32_t bGain, uint32_t gbGain)
{
ISC->ISC_WB_O_RGR =
ISC_WB_O_RGR_ROFST(rOffset) | ISC_WB_O_RGR_GROFST(grOffset);
ISC->ISC_WB_O_BGB =
ISC_WB_O_BGB_BOFST(bOffset) | ISC_WB_O_BGB_GBOFST(gbOffset);
ISC->ISC_WB_G_RGR =
ISC_WB_G_RGR_RGAIN(rGain) | ISC_WB_G_RGR_GRGAIN(grGain);
ISC->ISC_WB_G_BGB =
ISC_WB_G_BGB_BGAIN(bGain) | ISC_WB_G_BGB_GBGAIN(gbGain);
}
/*------------------------------------------
* Color Filter Array functions
*----------------------------------------*/
/**
* \brief Enables/disable Color Filter Array Interpolation.
*/
void isc_cfa_enabled(uint8_t enabled)
{
if (enabled)
ISC->ISC_CFA_CTRL = ISC_CFA_CTRL_ENABLE;
else
ISC->ISC_CFA_CTRL = 0;
}
/**
* \brief configure color filter array interpolation.
* \param pattern Color Filter Array Pattern
* \param edge Edge Interpolation
0: Edges are not interpolated.
1: Edge interpolation is performed.
*/
void isc_cfa_configure(uint8_t pattern, uint8_t edge)
{
ISC->ISC_CFA_CFG = pattern | (edge << 4);
}
/*------------------------------------------
* Color Correction functions
*----------------------------------------*/
/**
* \brief Enables/disable Color Correction.
*/
void isc_cc_enabled(uint8_t enabled)
{
if (enabled)
ISC->ISC_CC_CTRL = ISC_CC_CTRL_ENABLE;
else
ISC->ISC_CFA_CTRL = 0;
}
/**
* \brief Color correction with color component.
* \param cc Pointer to structure _color_correct
*/
void isc_cc_configure(struct _color_correct* cc)
{
ISC->ISC_CC_RR_RG =
ISC_CC_RR_RG_RRGAIN(cc->rrGain) | ISC_CC_RR_RG_RGGAIN(cc->rgGain);
ISC->ISC_CC_RB_OR =
ISC_CC_RB_OR_RBGAIN(cc->rbGain) | ISC_CC_RB_OR_ROFST(cc->rOffset);
ISC->ISC_CC_GR_GG =
ISC_CC_GR_GG_GRGAIN(cc->grGain) | ISC_CC_GR_GG_GGGAIN(cc->ggGain);
ISC->ISC_CC_GB_OG =
ISC_CC_GB_OG_GBGAIN(cc->gbGain) | ISC_CC_GB_OG_ROFST(cc->gOffset);
ISC->ISC_CC_BR_BG =
ISC_CC_BR_BG_BRGAIN(cc->brGain) | ISC_CC_BR_BG_BGGAIN(cc->bgGain);
ISC->ISC_CC_BB_OB =
ISC_CC_BB_OB_BBGAIN(cc->bbGain) | ISC_CC_BB_OB_BOFST(cc->bOffset);
}
/*------------------------------------------
* Gamma Correction functions
*----------------------------------------*/
/**
* \brief Enables/disable Gamma Correction with giving channels.
* \param enabled 1: enable, 0: disable
* \param channels ISC_GAM_CTRL_BENABLE/ISC_GAM_CTRL_GENABLE/ISC_GAM_CTRL_RENABLE
*/
void isc_gamma_enabled(uint8_t enabled, uint8_t channels)
{
if (enabled)
ISC->ISC_GAM_CTRL |= ISC_GAM_CTRL_ENABLE | channels;
else
ISC->ISC_GAM_CTRL = 0;
}
/**
* \brief Configure gamma correction with give table.
* \param rGamConstant Pointer to red Color Constant instance (64 half-word).
* \param rGamSlope Pointer to red Color Slope instance (64 half-word).
* \param gGamConstant Pointer to green Color Constant instance (64 half-word).
* \param gGamSlope Pointer to green Color Slope instance (64 half-word).
* \param bGamConstant Pointer to blue Color Constant instance (64 half-word).
* \param bGamSlope Pointer to blue Color Slope instance (64 half-word).
*/
void isc_gamma_configure(uint16_t* rGamConstant, uint16_t* rGamSlope,
uint16_t* gGamConstant, uint16_t* gGamSlope,
uint16_t* bGamConstant, uint16_t* bGamSlope)
{
uint8_t i;
for (i = 0; i < 64 ; i++) {
ISC->ISC_GAM_BENTRY[i] =
ISC_GAM_BENTRY_BCONSTANT(bGamConstant[i])
| ISC_GAM_BENTRY_BSLOPE(bGamSlope[i]);
ISC->ISC_GAM_GENTRY[i] =
ISC_GAM_GENTRY_GCONSTANT(bGamConstant[i])
| ISC_GAM_GENTRY_GSLOPE(bGamSlope[i]);
ISC->ISC_GAM_RENTRY[i] =
ISC_GAM_RENTRY_RCONSTANT(bGamConstant[i])
| ISC_GAM_RENTRY_RSLOPE(bGamSlope[i]);
}
}
/*------------------------------------------
* Color Space Conversion functions
*----------------------------------------*/
/**
* \brief Enables/disable Color Space Conversion.
*/
void isc_csc_enabled(uint8_t enabled)
{
if (enabled)
ISC->ISC_CSC_CTRL = ISC_CSC_CTRL_ENABLE;
else
ISC->ISC_CSC_CTRL = 0;
}
/**
* \brief Color space convert with color space component.
* \param cs Pointer to structure _color_space
*/
void isc_csc_configure(struct _color_space* cs)
{
ISC->ISC_CSC_YR_YG = ISC_CSC_YR_YG_YRGAIN(cs->YrGain)
| ISC_CSC_YR_YG_YGGAIN(cs->YgGain);
ISC->ISC_CSC_YB_OY = ISC_CSC_YB_OY_YBGAIN(cs->YbGain)
| ISC_CSC_YB_OY_YOFST(cs->Yoffset);
ISC->ISC_CSC_CBR_CBG = ISC_CSC_CBR_CBG_CBRGAIN(cs->cbrGain)
| ISC_CSC_CBR_CBG_CBGGAIN(cs->cbgGain);
ISC->ISC_CSC_CBB_OCB = ISC_CSC_CBB_OCB_CBBGAIN(cs->cbbGain)
| ISC_CSC_CBB_OCB_CBOFST(cs->cbOffset);
ISC->ISC_CSC_CRR_CRG = ISC_CSC_CRR_CRG_CRRGAIN(cs->crrGain)
| ISC_CSC_CRR_CRG_CRGGAIN(cs->crgGain);
ISC->ISC_CSC_CRB_OCR = ISC_CSC_CRB_OCR_CRBGAIN(cs->crbGain)
| ISC_CSC_CRB_OCR_CROFST(cs->crOffset);
}
/*------------------------------------------
* Contrast And Brightness functions
*----------------------------------------*/
/**
* \brief Enables/disable contrast and brightness control.
*/
void isc_cbc_enabled(uint8_t enabled)
{
if (enabled)
ISC->ISC_CBC_CTRL = ISC_CBC_CTRL_ENABLE;
else
ISC->ISC_CBC_CTRL = 0;
}
/**
* \brief Configure Contrast and brightness with give parameter.
* \param ccir656 CCIR656 Stream Enable.
0: Raw mode
1: CCIR mode
* \param byteOrder CCIR656 Byte Ordering.
* \param brightness Brightness Control (signed 11 bits 1:10:0).
* \param Contrast Contrast (signed 12 bits 1:3:8).
*/
void isc_cbc_configure(uint8_t ccir656, uint8_t byteOrder,
uint16_t brightness, uint16_t contrast)
{
if (ccir656)
ISC->ISC_CBC_CFG = ISC_CBC_CFG_CCIR | byteOrder ;
else
ISC->ISC_CBC_CFG = 0;
ISC->ISC_CBC_BRIGHT = ISC_CBC_BRIGHT_BRIGHT(brightness);
ISC->ISC_CBC_CONTRAST = ISC_CBC_CONTRAST_CONTRAST(contrast);
}
/*------------------------------------------
* Sub-sampling functions
*----------------------------------------*/
/**
* \brief Enables/disable 4:4:4 to 4:2:2 Chrominance Horizontal Subsampling Filter Enable.
*/
void isc_sub422_enabled(uint8_t enabled)
{
if (enabled)
ISC->ISC_SUB422_CTRL = ISC_SUB422_CTRL_ENABLE;
else
ISC->ISC_SUB422_CTRL = 0;
}
/**
* \brief Configure Subsampling 4:4:4 to 4:2:2 with giving value.
* \param ccir656 CCIR656 Stream Enable.
0: Raw mode
1: CCIR mode
* \param byteOrder CCIR656 Byte Ordering.
* \param lpf Low Pass Filter Selection.
*/
void isc_sub422_configure(uint8_t ccir656, uint8_t byteOrder, uint8_t lpf)
{
if (ccir656)
ISC->ISC_SUB422_CFG = ISC_SUB422_CFG_CCIR | byteOrder ;
else
ISC->ISC_SUB422_CFG = 0;
ISC->ISC_SUB422_CFG |= lpf;
}
/**
* \brief Configure 4:2:2 to 4:2:0 Vertical Subsampling Filter Enable
(Center Aligned) with giving value.
* \param enabled Subsampler enabled.
0: disabled
1: enabled
* \param filter Interlaced or Progressive Chrominance Filter.
0: Progressive filter {0.5, 0.5}
1: Field-dependent filter, top field filter is {0.75, 0.25},
bottom field filter is {0.25, 0.75}
*/
void isc_sub420_configure(uint8_t enabled, uint8_t filter)
{
if (enabled){
ISC->ISC_SUB420_CTRL = ISC_SUB420_CTRL_ENABLE;
if (filter){
ISC->ISC_SUB420_CTRL |= ISC_SUB420_CTRL_FILTER;
}
} else {
ISC->ISC_SUB420_CTRL = 0;
}
}
/*------------------------------------------
* Rounding, Limiting and Packing functions
*----------------------------------------*/
/**
* \brief Configure Rounding, Limiting and Packing Mode.
* \param rlpMode Rounding, Limiting and Packing Mode.
* \param alpha Alpha Value for Alpha-enabled RGB Mode.
*/
void isc_rlp_configure(uint8_t rlpMode, uint8_t alpha)
{
ISC->ISC_RLP_CFG = rlpMode;
if (alpha)
ISC->ISC_RLP_CFG |= ISC_RLP_CFG_ALPHA(alpha);
}
/*------------------------------------------
* Histogram functions
*----------------------------------------*/
/**
* \brief Enables/disable Histogram
*/
void isc_histogram_enabled(uint8_t enabled)
{
if (enabled)
ISC->ISC_HIS_CTRL = ISC_HIS_CTRL_ENABLE;
else
ISC->ISC_HIS_CTRL = 0;
}
/**
* \brief Configure Histogram.
* \param mode Histogram Operating Mode.
* \param baySel Bayer Color Component Selection.
* \param reset Histogram Reset After Read
0: Reset after read mode is disabled
1: Reset after read mode is enabled.
*/
void isc_histogram_configure(uint8_t mode, uint8_t baySel, uint8_t reset)
{
ISC->ISC_HIS_CFG = mode | baySel;
if (reset)
ISC->ISC_HIS_CFG |= ISC_HIS_CFG_RAR;
}
/**
* \brief update the histogram table.
*/
void isc_update_histogram_table(void)
{
while((ISC->ISC_CTRLSR & ISC_CTRLSR_HISREQ) == ISC_CTRLSR_HISREQ);
ISC->ISC_CTRLEN = ISC_CTRLEN_HISREQ;
}
/**
* \brief clear the histogram table.
*/
void isc_clear_histogram_table(void)
{
ISC->ISC_CTRLEN = ISC_CTRLEN_HISCLR;
}
/*------------------------------------------
* DMA functions
*----------------------------------------*/
/**
* \brief Configure ISC DMA input mode.
* \param mode Operating Mode.
*/
void isc_dma_configure_input_mode(uint32_t mode)
{
ISC->ISC_DCFG = mode;
}
/**
* \brief Configure ISC DMA with giving entry.
* \param descEntry entry of DMA descriptor VIEW.
*/
void isc_dma_configure_desc_entry(uint32_t desc_entry)
{
ISC->ISC_DNDA = desc_entry;
}
/**
* \brief Enable ISC DMA with giving view.
* \param ctrl setting for DMA descriptor VIEW.
*/
void isc_dma_enable(uint32_t ctrl)
{
ISC->ISC_DCTRL = ctrl;
}
/**
* \brief Configure ISC DMA start address.
* \param channel channel number.
* \param address address for giving channel.
* \param stride stride for giving channel.
*/
void isc_dma_adderss(uint8_t channel, uint32_t address, uint32_t stride)
{
ISC->ISC_SUB0[channel].ISC_DAD = address;
ISC->ISC_SUB0[channel].ISC_DST = stride;
}

View file

@ -0,0 +1,281 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2013, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/** \file */
/** \addtogroup isc_module
* @{
* \section isc_usage Usage
* - isc_start_capture: Send Capture Input Stream Command to start a single
* shot capture or a multiple frame
*/
/**@}*/
#ifndef ISC_H
#define ISC_H
#include <stdint.h>
/*------------------------------------------------------------------------------
* Type
*----------------------------------------------------------------------------*/
/** color correction components structure */
struct _color_correct {
/** Red Component Offset (signed 13 bits, 1:12:0) */
uint16_t rOffset;
/** Green Component Offset (signed 13 bits, 1:12:0)*/
uint16_t gOffset;
/** Green Component Offset (signed 13 bits, 1:12:0)*/
uint16_t bOffset;
/** Red Gain for Red Component (signed 12 bits, 1:3:8)*/
uint16_t rrGain;
/** Green Component (Red row) Gain (unsigned 13 bits, 0:4:9)*/
uint16_t rgGain;
/** Blue Gain for Red Component (signed 12 bits, 1:3:8)*/
uint16_t rbGain;
/** Green Gain for Green Component (signed 12 bits, 1:3:8)*/
uint16_t ggGain;
/** Red Gain for Green Component (signed 12 bits, 1:3:8)*/
uint16_t grGain;
/** Blue Gain for Green Component (signed 12 bits, 1:3:8)*/
uint16_t gbGain;
/** Green Gain for Blue Component (signed 12 bits, 1:3:8) */
uint16_t bgGain;
/** Red Gain for Blue Component (signed 12 bits, 1:3:8) */
uint16_t brGain;
/** Blue Gain for Blue Component (signed 12 bits, 1:3:8)*/
uint16_t bbGain;
};
/** color space convertion components structure */
struct _color_space {
/** Red Gain for Luminance (signed 12 bits 1:3:8) */
uint16_t YrGain;
/** Green Gain for Luminance (signed 12 bits 1:3:8)*/
uint16_t YgGain;
/** Blue Gain for Luminance Component (12 bits signed 1:3:8)*/
uint16_t YbGain;
/** Luminance Offset (11 bits signed 1:10:0)*/
uint16_t Yoffset;
/** Green Gain for Blue Chrominance (signed 12 bits 1:3:8)*/
uint16_t cbrGain;
/** Red Gain for Blue Chrominance (signed 12 bits, 1:3:8)*/
uint16_t cbgGain;
/** Blue Gain for Blue Chrominance (signed 12 bits 1:3:8)*/
uint16_t cbbGain;
/** Blue Chrominance Offset (signed 11 bits 1:10:0)*/
uint16_t cbOffset;
/** Red Gain for Red Chrominance (signed 12 bits 1:3:8)*/
uint16_t crrGain;
/** Green Gain for Red Chrominance (signed 12 bits 1:3:8)*/
uint16_t crgGain;
/** Blue Gain for Red Chrominance (signed 12 bits 1:3:8)*/
uint16_t crbGain;
/** Red Chrominance Offset (signed 11 bits 1:10:0)*/
uint16_t crOffset;
};
/** \brief Structure for ISC DMA descriptor view0 that can be
* performed when the pixel or data stream is packed.*/
struct _isc_dma_view0
{
/** ISC DMA Control. */
uint32_t ctrl;
/** Next ISC DMA Descriptor Address number. */
uint32_t next_desc;
/** Transfer Address. */
uint32_t addr;
/** stride . */
uint32_t stride;
};
/** \brief Structure for ISC DMA descriptor view1 that can be
* performed for YCbCr semi-planar pixel stream.*/
struct _isc_dma_view1
{
/** ISC DMA Control. */
uint32_t ctrl;
/** Next ISC DMA Descriptor Address number. */
uint32_t next_desc;
/** Transfer Address 0. */
uint32_t addr0;
/** stride 0 . */
uint32_t stride0;
/** Transfer Address 1. */
uint32_t addr1;
/** stride 1 . */
uint32_t stride1;
};
/** \brief Structure for ISC DMA descriptor view2 that can be
* performed for used for YCbCr planar pixel stream.*/
struct _isc_dma_view2
{
/** ISC DMA Control. */
uint32_t ctrl;
/** Next ISC DMA Descriptor Address number. */
uint32_t next_desc;
/** Transfer Address 0. */
uint32_t addr0;
/** stride 0. */
uint32_t stride0;
/** Transfer Address 1. */
uint32_t addr1;
/** stride 1 . */
uint32_t stride1;
/** Transfer Address 2. */
uint32_t addr2;
/** stride 2. */
uint32_t stride2;
};
/*------------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/*------------------------------------------
* ISC Control functions
*----------------------------------------*/
extern void isc_start_capture(void);
extern void isc_stop_capture(void);
extern uint32_t isc_get_ctrl_status(void);
extern void isc_update_profile(void);
extern void isc_software_reset(void);
/*------------------------------------------
* PFE(Parallel Front End) functions
*----------------------------------------*/
extern void isc_pfe_set_video_mode(uint32_t vmode);
extern void isc_pfe_set_sync_polarity(uint32_t hpol, uint32_t vpol);
extern void isc_pfe_set_pixel_polarity(uint32_t ppol);
extern void isc_pfe_set_field_polarity(uint32_t fpol);
extern void isc_pfe_set_gated_clock(uint8_t en);
extern void isc_pfe_set_cropping_enabled(uint8_t enCol, uint8_t enRow);
extern void isc_pfe_set_bps(uint32_t bps);
extern void isc_pfe_set_single_shot(void);
extern void isc_pfe_set_continuous_shot(void);
extern void isc_pfe_set_cropping_area(uint32_t Hstart, uint32_t Hend,
uint32_t Vstart, uint32_t Vend);
/*------------------------------------------
* Clock configuration functions
*----------------------------------------*/
extern void isc_configure_isp_clock(uint32_t isp_clk_div,
uint32_t isp_clk_sel);
extern void isc_enable_isp_clock(void);
extern void isc_disable_isp_clock(void);
extern void isc_reset_isp_clock(void);
extern void isc_configure_master_clock(uint32_t master_clk_div,
uint32_t master_clk_sel);
extern void isc_enable_master_clock(void);
extern void isc_disable_master_clock(void);
extern void isc_reset_master_clock(void);
extern uint32_t isc_get_clock_status(void);
/*------------------------------------------
* Interrupt functions
*----------------------------------------*/
extern void isc_enable_interrupt(uint32_t flag);
extern void isc_disable_interrupt(uint32_t flag);
extern uint32_t isc_interrupt_status(void);
/*------------------------------------------
* White Balance functions
*----------------------------------------*/
extern void isc_wb_enabled(uint8_t enabled);
extern void isc_wb_set_bayer_pattern(uint8_t pattern);
extern void isc_wb_adjust_bayer_color(uint32_t rOffset, uint32_t grOffset,
uint32_t bOffset, uint32_t gbOffset,
uint32_t rGain, uint32_t grGain,
uint32_t bGain, uint32_t gbGain);
/*------------------------------------------
* Color Filter Array functions
*----------------------------------------*/
extern void isc_cfa_enabled(uint8_t enabled);
extern void isc_cfa_configure(uint8_t pattern, uint8_t edge);
/*------------------------------------------
* Color Correction functions
*----------------------------------------*/
extern void isc_cc_enabled(uint8_t enabled);
extern void isc_cc_configure(struct _color_correct* cc);
/*------------------------------------------
* Gamma Correction functions
*----------------------------------------*/
extern void isc_gamma_enabled(uint8_t enabled, uint8_t channels);
extern void isc_gamma_configure(uint16_t* rGamConstant, uint16_t* rGamSlope,
uint16_t* gGamConstant, uint16_t* gGamSlope,
uint16_t* bGamConstant, uint16_t* bGamSlope);
/*------------------------------------------
* Color Space Conversion functions
*----------------------------------------*/
extern void isc_csc_enabled(uint8_t enabled);
extern void isc_csc_configure(struct _color_space* cs);
/*------------------------------------------
* Contrast And Brightness functions
*----------------------------------------*/
extern void isc_cbc_enabled(uint8_t enabled);
extern void isc_cbc_configure(uint8_t ccir656, uint8_t byteOrder,
uint16_t brightness, uint16_t contrast);
/*------------------------------------------
* Sub-sampling functions
*----------------------------------------*/
extern void isc_sub422_enabled(uint8_t enabled);
extern void isc_sub422_configure(uint8_t ccir656, uint8_t byte_order,
uint8_t lpf);
extern void isc_sub420_configure(uint8_t enabled, uint8_t filter);
/*------------------------------------------
* Rounding, Limiting and Packing functions
*----------------------------------------*/
extern void isc_rlp_configure(uint8_t rlpMode, uint8_t alpha);
/*------------------------------------------
* Histogram functions
*----------------------------------------*/
extern void isc_histogram_enabled(uint8_t enabled);
extern void isc_histogram_configure(uint8_t mode, uint8_t bay_sel,
uint8_t reset);
extern void isc_update_histogram_table(void);
extern void isc_clear_histogram_table(void);
/*------------------------------------------
* DMA functions
*----------------------------------------*/
extern void isc_dma_configure_input_mode(uint32_t mode);
extern void isc_dma_configure_desc_entry(uint32_t desc_entry);
extern void isc_dma_enable(uint32_t ctrl);
extern void isc_dma_adderss(uint8_t channel, uint32_t address, uint32_t stride);
#endif //#ifndef ISC_H

View file

@ -0,0 +1,433 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/** \file */
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include "peripherals/l2cc.h"
#include "cortex-a/cp15.h"
#include "trace.h"
#include <assert.h>
#include <stdbool.h>
#include <string.h>
/*----------------------------------------------------------------------------
* Functions
*----------------------------------------------------------------------------*/
uint32_t l2cc_is_enabled(void)
{
return ((L2CC->L2CC_CR) & L2CC_CR_L2CEN);
}
void l2cc_enable(void)
{
L2CC->L2CC_CR |= L2CC_CR_L2CEN;
asm volatile("": : :"memory");
asm("dsb");
asm("isb");
trace_info("L2 cache is enabled\r\n");
}
void l2cc_disable(void)
{
L2CC->L2CC_CR &= ~L2CC_CR_L2CEN;
asm volatile("": : :"memory");
asm("dsb");
asm("isb");
trace_info("L2 cache is disabled\r\n");
}
void l2cc_exclusive_cache(uint8_t enable)
{
uint32_t cfg;
if (l2cc_is_enabled()) {
l2cc_disable();
}
cfg = L2CC->L2CC_ACR;
if (enable) {
cp15_exclusive_cache();
cfg |= L2CC_ACR_EXCC;
trace_info("L2 Exclusive mode enabled\n\r");
} else {
cp15_non_exclusive_cache();
cfg &= ~L2CC_ACR_EXCC;
trace_info("L2 Exclusive mode disabled\n\r");
}
L2CC->L2CC_ACR |= cfg;
}
void l2cc_config_lat_ram(struct _ram_latency_control * latencies)
{
if (l2cc_is_enabled()) {
l2cc_disable();
}
L2CC->L2CC_TRCR =
(L2CC_TRCR_TSETLAT(latencies->tag.setup) |
L2CC_TRCR_TRDLAT(latencies->tag.read) |
L2CC_TRCR_TWRLAT(latencies->tag.write));
L2CC->L2CC_DRCR =
(L2CC_DRCR_DSETLAT(latencies->data.setup) |
L2CC_DRCR_DRDLAT(latencies->data.read) |
L2CC_DRCR_DWRLAT(latencies->data.write));
}
void l2cc_set_config(const struct _l2cc_control* cfg)
{
uint32_t aux_control, debug_control, prefetch_control, power_control;
if (cfg->offset > 31) {
assert(0);
}
if ((cfg->offset > 7) && (cfg->offset < 15)) {
assert(0);
}
if ((cfg->offset > 15) && (cfg->offset < 23)) {
assert(0);
}
if ((cfg->offset > 23) && (cfg->offset < 31)) {
assert(0);
}
if (l2cc_is_enabled()) {
l2cc_disable();
}
aux_control = ((cfg->high_prior_so << 10) |
(cfg->store_buff_dev_limit << 11) |
(cfg->shared_attr_invalidate << 13) |
(cfg->evt_mon_bus << 20) |
(cfg->parity << 21) |
(cfg->shared_attr_override << 22) |
(L2CC_ACR_FWA(cfg->force_write_alloc)) |
(cfg->cache_replacement << 25) |
(cfg->non_sec_lockdown << 26) |
(cfg->it_acces_non_sec << 27) |
(cfg->data_prefetch << 28) |
(cfg->instruct_prefetch << 29));
debug_control = ((cfg->no_cache_linefill << 0) |
(cfg->no_write_back << 1));
prefetch_control = ((L2CC_PCR_OFFSET(cfg->offset << 0)) |
(cfg->exclusive_seq_same_id << 21) |
(cfg->incr_double_linefill << 23) |
(cfg->prefetch_drop << 24) |
(cfg->DLFWRDIS << 27) |
(cfg->data_prefetch << 28) |
(cfg->instruct_prefetch << 29) |
(cfg->double_linefill << 30));
power_control = ((cfg->standby_mode << 0) |
(cfg->dyn_clock_gating << 1));
L2CC->L2CC_ACR = aux_control;
L2CC->L2CC_DCR = debug_control;
L2CC->L2CC_PCR = prefetch_control;
L2CC->L2CC_POWCR = power_control;
}
void l2cc_data_prefetch_enable(void)
{
L2CC->L2CC_PCR |= L2CC_PCR_DATPEN;
}
void l2cc_inst_prefetch_enable(void)
{
L2CC->L2CC_PCR |= L2CC_PCR_INSPEN;
}
void l2cc_enable_reset_counter(uint8_t event_counter)
{
assert((event_counter > 3) ? 0 : 1);
L2CC->L2CC_ECR = (L2CC_ECR_EVCEN | (event_counter << 1));
}
void l2cc_event_config(uint8_t event_counter, uint8_t source, uint8_t it)
{
if (l2cc_is_enabled()) {
L2CC->L2CC_CR = false;
}
assert((event_counter > 1) ? 0 : 1);
if (!event_counter) {
L2CC->L2CC_ECFGR0 = (source | it);
} else {
L2CC->L2CC_ECFGR1 = (source | it);
}
}
uint32_t l2cc_event_counter_value(uint8_t event_counter)
{
assert((event_counter > 1) ? 0 : 1);
if (!event_counter) {
return L2CC->L2CC_EVR0;
} else {
return L2CC->L2CC_EVR1;
}
}
void l2cc_enable_it(uint16_t sources)
{
L2CC->L2CC_IMR |= sources;
}
void l2cc_disable_it(uint16_t sources)
{
L2CC->L2CC_IMR &= (!sources);
}
unsigned short l2cc_it_status_raw(uint16_t sources)
{
return ((L2CC->L2CC_RISR) & sources) ? 1 : 0;
}
uint16_t l2cc_it_status_mask(uint16_t sources)
{
return ((L2CC->L2CC_MISR) & sources) ? 1 : 0;
}
void l2cc_it_clear(uint16_t sources)
{
L2CC->L2CC_ICR |= sources;
}
uint8_t l2cc_poll_spniden()
{
return ((L2CC->L2CC_DCR & L2CC_DCR_SPNIDEN) >> 2);
}
void l2cc_cache_sync()
{
while ((L2CC->L2CC_CSR) & L2CC_CSR_C) ;
L2CC->L2CC_CSR = L2CC_CSR_C;
while ((L2CC->L2CC_CSR) & L2CC_CSR_C) ;
}
void l2cc_invalidate_pal(uint32_t phys_addr)
{
static uint32_t Tag;
static uint16_t Index;
Tag = (phys_addr >> (OFFSET_BIT + INDEX_BIT));
Index = (phys_addr >> OFFSET_BIT) & ((1 << INDEX_BIT) - 1);
L2CC->L2CC_IPALR = (L2CC_IPALR_TAG(Tag) | L2CC_IPALR_IDX(Index) | L2CC_IPALR_C);
while ((L2CC->L2CC_IPALR) & L2CC_IPALR_C) ;
}
void l2cc_clean_pal(uint32_t phys_addr)
{
static uint32_t Tag;
static uint16_t Index;
Tag = (phys_addr >> (OFFSET_BIT + INDEX_BIT));
Index = (phys_addr >> OFFSET_BIT) & ((1 << INDEX_BIT) - 1);
L2CC->L2CC_CPALR =
(L2CC_CPALR_TAG(Tag) | L2CC_CPALR_IDX(Index) | L2CC_CPALR_C);
while ((L2CC->L2CC_CPALR) & L2CC_CPALR_C) ;
}
void l2cc_clean_ix(uint32_t phys_addr)
{
static uint32_t Tag;
static uint16_t Index;
Tag = (phys_addr >> (OFFSET_BIT + INDEX_BIT));
Index = (phys_addr >> OFFSET_BIT) & ((1 << INDEX_BIT) - 1);
L2CC->L2CC_CIPALR =
(L2CC_CIPALR_TAG(Tag) | L2CC_CIPALR_IDX(Index) | L2CC_CIPALR_C);
while ((L2CC->L2CC_CIPALR) & L2CC_CIPALR_C) ;
}
void l2cc_invalidate_way(uint8_t way)
{
L2CC->L2CC_IWR = way;
while (L2CC->L2CC_IWR) ;
while (L2CC->L2CC_CSR) ;
}
void l2cc_clean_way(uint8_t way)
{
L2CC->L2CC_CWR = way;
while (L2CC->L2CC_CWR) ;
while (L2CC->L2CC_CSR) ;
}
/**
* \brief Clean Invalidate cache by way
* \param way way number
*/
static void l2cc_clean_invalidate_way(uint8_t way)
{
L2CC->L2CC_CIWR = way;
while (L2CC->L2CC_CSR) ;
}
void l2cc_clean_index(uint32_t phys_addr, uint8_t way)
{
static uint16_t Index;
Index = (phys_addr >> OFFSET_BIT) & ((1 << INDEX_BIT) - 1);
L2CC->L2CC_CIR =
(L2CC_CIR_IDX(Index) | L2CC_CIR_WAY(way) | L2CC_CIR_C);
while ((L2CC->L2CC_CIR) & L2CC_CIR_C) ;
}
void l2cc_clean_invalidate_index(uint32_t phys_addr, uint8_t way)
{
static uint16_t Index;
(void) way;
Index = (phys_addr >> OFFSET_BIT) & ((1 << INDEX_BIT) - 1);
L2CC->L2CC_CIIR =
(L2CC_CIIR_IDX(Index) | L2CC_CIIR_WAY(Index) | L2CC_CIIR_C);
while ((L2CC->L2CC_CIIR) & L2CC_CIIR_C) ;
}
void l2cc_data_lockdown(uint8_t way)
{
L2CC->L2CC_DLKR = way;
while (L2CC->L2CC_CSR) ;
}
void l2cc_instruction_lockdown(uint8_t way)
{
L2CC->L2CC_ILKR = way;
while (L2CC->L2CC_CSR) ;
}
static void l2cc_clean(void)
{
// Clean of L1; This is broadcast within the cluster
cp15_dcache_clean();
if (l2cc_is_enabled()) {
// forces the address out past level 2
l2cc_clean_way(0xFF);
// Ensures completion of the L2 clean
l2cc_cache_sync();
}
}
static void l2cc_invalidate(void)
{
if (l2cc_is_enabled()) {
// forces the address out past level 2
l2cc_invalidate_way(0xFF);
// Ensures completion of the L2 inval
l2cc_cache_sync();
}
// Inval of L1; This is broadcast within the cluster
cp15_dcache_invalidate();
}
static void l2cc_clean_invalidate(void)
{
/* Clean of L1; This is broadcast within the cluster */
cp15_dcache_clean();
if (l2cc_is_enabled()) {
/* forces the address out past level 2 */
l2cc_clean_invalidate_way(0xFF);
/* Ensures completion of the L2 inval */
l2cc_cache_sync();
}
/* Inval of L1; This is broadcast within the cluster */
cp15_dcache_invalidate();
}
void l2cc_cache_maintenance(enum _maint_op maintenance)
{
switch (maintenance) {
case L2CC_DCACHE_CLEAN:
l2cc_clean();
break;
case L2CC_DCACHE_INVAL:
l2cc_invalidate();
break;
case L2CC_DCACHE_FLUSH:
l2cc_clean_invalidate();
break;
}
}
void l2cc_invalidate_region(uint32_t start, uint32_t end)
{
assert(start < end);
uint32_t current = start & ~0x1fUL;
if (l2cc_is_enabled()) {
while (current <= end) {
l2cc_invalidate_pal(current);
current += 32;
}
l2cc_invalidate_pal(end);
}
cp15_invalidate_dcache_for_dma(start, end);
}
void l2cc_clean_region(uint32_t start, uint32_t end)
{
assert(start < end);
uint32_t current = start & ~0x1fUL;
if (l2cc_is_enabled()) {
while (current <= end) {
l2cc_clean_pal(current);
current += 32;
}
l2cc_clean_pal(end);
}
cp15_clean_dcache_for_dma(start, end);
}
void l2cc_configure(const struct _l2cc_control* cfg)
{
l2cc_event_config(0, L2CC_ECFGR0_ESRC_SRC_DRHIT,
L2CC_ECFGR0_EIGEN_INT_DIS);
l2cc_event_config(1, L2CC_ECFGR0_ESRC_SRC_DWHIT,
L2CC_ECFGR0_EIGEN_INT_DIS);
l2cc_enable_reset_counter(L2CC_RESET_BOTH_COUNTER);
l2cc_set_config(cfg);
/* Enable Prefetch */
l2cc_inst_prefetch_enable();
l2cc_data_prefetch_enable();
/* Invalidate whole L2CC */
l2cc_invalidate_way(0xFF);
/* Disable all L2CC Interrupt */
l2cc_disable_it(0x1FF);
/* Clear all L2CC Interrupt */
l2cc_it_clear(0xFF);
l2cc_exclusive_cache(true);
l2cc_enable();
}

View file

@ -0,0 +1,347 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* Interface for Level 2 cache (L2CC) controller.
*
*/
/** \addtogroup l2cc_module L2 Cache Operations
* \ingroup cache_module
* \section Usage
* - Enable or disable L2CC with L2CC_Enable() or L2CC_Disable().
* - Check if L2CC is enabled with L2CC_IsEnabled().
* - Enable or disable L2CC interrupt with L2CC_EnableIT() or L2CC_DisableIT().
* - Enable data or instruction prefetch with L2CC_DataPrefetchEnable() or L2CC_InstPrefetchEnable().
*
* Related files:\n
* \ref l2cc.h\n
* \ref l2cc.c\n
*/
#ifndef _L2CC_H
#define _L2CC_H
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include <assert.h>
/*----------------------------------------------------------------------------
* Define
*----------------------------------------------------------------------------*/
#ifdef __cplusplus
extern "C" {
#endif
#define OFFSET_BIT 5
#define INDEX_BIT 9
#define TAG_BIT 18
#define L2CC_RESET_EVCOUNTER0 0
#define L2CC_RESET_EVCOUNTER1 1
#define L2CC_RESET_BOTH_COUNTER 3
#define FWA_DEFAULT 0u
#define FWA_NO_ALLOCATE 1u
#define FWA_FORCE_ALLOCATE 2u
#define FWA_INTERNALLY_MAPPED 3u
/*----------------------------------------------------------------------------
* Types
*----------------------------------------------------------------------------*/
enum _maint_op {
L2CC_DCACHE_CLEAN,
L2CC_DCACHE_INVAL,
L2CC_DCACHE_FLUSH
};
struct _latency {
uint8_t setup;
uint8_t read;
uint8_t write;
};
struct _ram_latency_control {
struct _latency tag;
struct _latency data;
};
/** L2CC structure */
struct _l2cc_control {
/** High Priority for SO and Dev Reads Enable */
uint32_t high_prior_so: 1,
/** Store Buffer Device Limitation Enable */
store_buff_dev_limit: 1,
/** Shared Attribute Invalidate Enable */
shared_attr_invalidate: 1,
/** Event Monitor Bus Enable */
evt_mon_bus: 1,
/** Parity Enable */
parity: 1,
/** Shared Attribute Override Enable */
shared_attr_override: 1,
/** Force Write Allocate */
force_write_alloc: 2,
/** Cache Replacement Policy */
cache_replacement: 1,
/** Non-Secure Lockdown Enable*/
non_sec_lockdown: 1,
/** Non-Secure Interrupt Access Control */
it_acces_non_sec: 1,
/** Data Prefetch Enable*/
data_prefetch: 1,
/** Instruction Prefetch Enable */
instruct_prefetch: 1,
/** Prefetch Offset */
offset: 5,
/** Not Same ID on Exclusive Sequence Enable */
exclusive_seq_same_id: 1,
/** INCR Double Linefill Enable */
incr_double_linefill: 1,
/** Prefetch Drop Enable*/
prefetch_drop: 1,
/** Double Linefill on WRAP Read Disable */
DLFWRDIS: 1,
/** Double linefill Enable */
double_linefill: 1,
/** Standby Mode Enable */
standby_mode: 1,
/** Dynamic Clock Gating Enable */
dyn_clock_gating: 1,
/** Disable Cache Linefill*/
no_cache_linefill: 1,
/** Disable Write-back, Force Write-through */
no_write_back: 1;
};
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/**
* \brief Check if Level 2 cache is enable.
*/
extern uint32_t l2cc_is_enabled(void);
/**
* \brief Enable Level 2 cache.
*/
extern void l2cc_enable(void);
/**
* \brief Disable Level 2 cache.
*/
extern void l2cc_disable(void);
/**
* \brief Configures Level 2 cache as exclusive cache.
* \param Enable Enable/disable exclusive cache.
*/
extern void l2cc_exclusive_cache(uint8_t enable);
/**
* \brief Configures Level 2 cache RAM Latency (Tag and Data).
* \param latencies Structure containing RAM Tag and Data latencies
*/
extern void l2cc_config_lat_ram(struct _ram_latency_control * latencies);
/**
* \brief Configures Level 2 cache.
* \param cfg Configuration values to put in Auxiliary, prefetch,
* debug and powercontrol registers.
*/
extern void l2cc_set_config(const struct _l2cc_control* cfg);
/**
* \brief Enables Data prefetch on L2
*/
extern void l2cc_data_prefetch_enable(void);
/**
* \brief Enables instruction prefetch on L2
*/
extern void l2cc_inst_prefetch_enable(void);
/**
* \brief Enables instruction prefetch on L2
* \param event_counter Counter of the events.
*/
extern void l2cc_enable_reset_counter(uint8_t event_counter);
/**
* \brief Configures Event of Level 2 cache.
* \param event_counter Eventcounter 1 or 0
* \param source Event Genration source
* \param it Event Counter Interrupt Generation condition
*/
extern void l2cc_event_config(uint8_t event_counter, uint8_t source,
uint8_t it);
/**
* \brief Reads Event Counter value.
* \param event_counter choose Eventcounter 1 or 0
*/
extern uint32_t l2cc_event_counter_value(uint8_t event_counter);
/**
* \brief Enable interrupts
* \param sources Interrupt source
*/
extern void l2cc_enable_it(uint16_t sources);
/**
* \brief Disable interrupts
* \param sources Interrupt source
*/
extern void l2cc_disable_it(uint16_t sources);
/**
* \brief Enabled interrupt's raw status
* \param sources Interrupt source
*/
extern uint16_t l2cc_it_status_raw(uint16_t sources);
/**
* \brief Status of masked interrupts
* \param sources Interrupt source
*/
extern uint16_t l2cc_it_status_mask(uint16_t sources);
/**
* \brief Clear interrupts
* \param sources Interrupt source
*/
extern void l2cc_it_clear(uint16_t sources);
/**
* \brief Poll SPNIDEN signal
*/
extern uint8_t l2cc_poll_spniden(void);
/**
* \brief Synchronizes the L2 cache
*/
extern void l2cc_cache_sync(void);
/**
* \brief Invalidate cache by way
* \param way way number
*/
extern void l2cc_invalidate_way(uint8_t way);
/**
* \brief Clean cache by way
* \param way way number
*/
extern void l2cc_clean_way(uint8_t way);
/**
* \brief Invalidate cache by Physical addersse
* \param phys_addr Physical addresse
*/
extern void l2cc_invalidate_pal(uint32_t phys_addr);
/**
* \brief Clean cache by Physical addersse
* \param phys_addr Physical addresse
*/
extern void l2cc_clean_pal(uint32_t phys_addr);
/**
* \brief Clean index cache by Physical addersse
* \param phys_addr Physical addresse
*/
extern void l2cc_clean_ix(uint32_t phys_addr);
/**
* \brief Clean cache by Index
* \param phys_addr Physical addresse
* \param way way number
*/
extern void l2cc_clean_index(uint32_t phys_addr, uint8_t way);
/**
* \brief Clean Invalidate cache by index
* \param phys_addr Physical address
* \param way way number
*/
extern void l2cc_clean_invalidate_index(uint32_t phys_addr, uint8_t way);
/**
* \brief cache Data lockdown
* \param way way number
*/
extern void l2cc_data_lockdown(uint8_t way);
/**
* \brief cache instruction lockdown
* \param way way number
*/
extern void l2cc_instruction_lockdown(uint8_t way);
/**
* \brief L2 DCache maintenance (clean/invalidate/flush)
*
* \param maintenance Maintenance operation to apply: \sa #_maint_op
*/
extern void l2cc_cache_maintenance(enum _maint_op maintenance);
/**
* \brief Invalidate cache lines corresponding to a memory region
*
* \param start Beginning of the memory region
* \param end End of the memory region
*/
extern void l2cc_invalidate_region(uint32_t start, uint32_t end);
/**
* \brief Clean cache lines corresponding to a memory region
*
* \param start Beginning of the memory region
* \param end End of the memory region
*/
extern void l2cc_clean_region(uint32_t start, uint32_t end);
/**
* \brief Enable level two cache controller (L2CC)
*
* \param cfg configuration to apply: \sa #_l2cc_control
*/
extern void l2cc_configure(const struct _l2cc_control* cfg);
#ifdef __cplusplus
}
#endif
#endif /* #ifndef _L2CC_ */

View file

@ -0,0 +1,100 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
#include "peripherals/matrix.h"
#include <assert.h>
void matrix_configure_slave_sec(Matrix* mtx, uint8_t slave_id,
uint8_t sel_mask, uint8_t read_mask,
uint8_t write_mask)
{
mtx->MATRIX_SSR[slave_id] = sel_mask | (read_mask << 8) |
(write_mask << 16);
}
void matrix_set_slave_split_addr(Matrix* mtx, uint8_t slave_id,
uint8_t area_size, uint8_t mask)
{
uint8_t i = mask, j = 0;
uint32_t value = 0;
for (i = 1; (i <= mask) && (j < 32); i <<= 1, j += 4) {
if (i & mask)
value |= area_size << j;
}
mtx->MATRIX_SASSR[slave_id] = value;
}
void matrix_set_slave_region_size(Matrix* mtx, uint8_t slave_id,
uint8_t area_size, uint8_t mask)
{
assert(slave_id != 0);
uint8_t i = mask, j = 0;
uint32_t value = 0;
for (i = 1; (i <= mask) && (j < 32 ); i <<= 1, j += 4) {
if (i & mask)
value |= area_size << j;
}
mtx->MATRIX_SRTSR[slave_id] = value;
}
uint8_t matrix_is_peripheral_secured(Matrix* mtx, uint32_t periph_id)
{
if (mtx->MATRIX_SPSELR[periph_id / 32] & (1 << (periph_id % 32))) {
return 0;
} else {
return 1;
}
}
void matrix_remove_write_protection(Matrix* mtx)
{
mtx->MATRIX_WPMR = MATRIX_WPMR_WPKEY_PASSWD;
}
/**
* \brief Changes the mapping of the chip so that the remap area mirrors the
* internal ROM or the EBI CS0.
*/
void matrix_remap_rom(void)
{
AXIMX->AXIMX_REMAP = 0;
}
/**
* \brief Changes the mapping of the chip so that the remap area mirrors the
* internal RAM.
*/
void matrix_remap_ram(void)
{
volatile uint32_t i;
AXIMX->AXIMX_REMAP = AXIMX_REMAP_REMAP0;
for(i=1000;--i;);
}

View file

@ -0,0 +1,88 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
#ifndef MATRIX_HEADER_
#define MATRIX_HEADER_
#include "chip.h"
#include <stdint.h>
/*----------------------------------------------------------------------------
* Definitions
*----------------------------------------------------------------------------*/
#define MATRIX_AREA_4K (0x0u) /* 0x1000 */
#define MATRIX_AREA_8K (0x1u) /* 0x2000 */
#define MATRIX_AREA_16K (0x2u) /* 0x4000 */
#define MATRIX_AREA_32K (0x3u) /* 0x8000 */
#define MATRIX_AREA_64K (0x4u) /* 0x10000 */
#define MATRIX_AREA_128K (0x5u) /* 0x20000 */
#define MATRIX_AREA_256K (0x6u) /* 0x40000 */
#define MATRIX_AREA_512K (0x7u) /* 0x80000 */
#define MATRIX_AREA_1M (0x8u) /* 0x100000 */
#define MATRIX_AREA_2M (0x9u) /* 0x200000 */
#define MATRIX_AREA_4M (0xAu) /* 0x400000 */
#define MATRIX_AREA_8M (0xBu) /* 0x800000 */
#define MATRIX_AREA_16M (0xCu) /* 0x1000000 */
#define MATRIX_AREA_32M (0xDu) /* 0x2000000 */
#define MATRIX_AREA_64M (0xEu) /* 0x4000000 */
#define MATRIX_AREA_128M (0xFu) /* 0x8000000 */
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
#ifdef __cplusplus
extern "C" {
#endif
extern void matrix_configure_slave_sec(Matrix* mtx, uint8_t slave_id,
uint8_t sel_mask, uint8_t read_mask,
uint8_t write_mask);
extern void matrix_set_slave_split_addr(Matrix* mtx, uint8_t slave_id,
uint8_t area, uint8_t mask);
extern void matrix_set_slave_region_size(Matrix* mtx, uint8_t slave_id,
uint8_t area, uint8_t mask);
extern uint8_t matrix_is_peripheral_secured(Matrix* mtx, uint32_t periph_id);
extern void matrix_remove_write_protection(Matrix* mtx);
extern void matrix_remap_rom(void);
extern void matrix_remap_ram(void);
#ifdef __cplusplus
}
#endif
#endif /* MATRIX_HEADER_ */

View file

@ -0,0 +1,749 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/** \file
* Implements functions for Controller Area Network with Flexible Data-rate,
* relying on the MCAN peripheral.
*/
/** \addtogroup can_module
*@{*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "board.h"
#include "chip.h"
#include "mcan.h"
#include "pmc.h"
#include <assert.h>
#include <string.h>
/*---------------------------------------------------------------------------
* Local definitions
*---------------------------------------------------------------------------*/
enum mcan_dlc
{
CAN_DLC_0 = 0,
CAN_DLC_1 = 1,
CAN_DLC_2 = 2,
CAN_DLC_3 = 3,
CAN_DLC_4 = 4,
CAN_DLC_5 = 5,
CAN_DLC_6 = 6,
CAN_DLC_7 = 7,
CAN_DLC_8 = 8,
CAN_DLC_12 = 9,
CAN_DLC_16 = 10,
CAN_DLC_20 = 11,
CAN_DLC_24 = 12,
CAN_DLC_32 = 13,
CAN_DLC_48 = 14,
CAN_DLC_64 = 15
};
/*---------------------------------------------------------------------------
* Local functions
*---------------------------------------------------------------------------*/
/**
* \brief Convert data length to Data Length Code.
* \param len length, in bytes
* \param dlc address where the matching Data Length Code will be written
* \return true if a code matched the provided length, false if this exact
* length is not supported.
*/
static bool get_length_code(uint8_t len, enum mcan_dlc *dlc)
{
assert(dlc);
if (len <= 8) {
*dlc = (enum mcan_dlc)len;
return true;
}
if (len % 4)
return false;
len /= 4;
if (len <= 6) {
*dlc = (enum mcan_dlc)(len + 6);
return true;
}
if (len % 4)
return false;
len /= 4;
if (len > 4)
return false;
*dlc = (enum mcan_dlc)(len + 11);
return true;
}
/**
* \brief Convert Data Length Code to actual data length.
* \param dlc CAN_DLC_xx enum value
* \return Data length, expressed in bytes.
*/
static uint8_t get_data_length(enum mcan_dlc dlc)
{
assert((dlc == CAN_DLC_0 || dlc > CAN_DLC_0) && dlc <= CAN_DLC_64);
if (dlc <= CAN_DLC_8)
return (uint8_t)dlc;
if (dlc <= CAN_DLC_24)
return ((uint8_t)dlc - 6) * 4;
return ((uint8_t)dlc - 11) * 16;
}
/**
* \brief Compute the size of the Message RAM, depending on the application.
* \param set Pointer to a MCAN instance that will be setup accordingly.
* \param cfg MCAN configuration to be considered. Only integer size parameters
* need to be configured. The other parameters can be left blank at this stage.
* \param size address where the required size of the Message RAM will be
* written, expressed in (32-bit) words.
* \return true if successful, false if a parameter is set to an unsupported
* value.
*/
static bool configure_ram(struct mcan_set *set,
const struct mcan_config *cfg, uint32_t *size)
{
if (cfg->array_size_filt_std > 128 || cfg->array_size_filt_ext > 64
|| cfg->fifo_size_rx0 > 64 || cfg->fifo_size_rx1 > 64
|| cfg->array_size_rx > 64 || cfg->fifo_size_tx_evt > 32
|| cfg->array_size_tx > 32 || cfg->fifo_size_tx > 32
|| cfg->array_size_tx + cfg->fifo_size_tx > 32
|| cfg->buf_size_rx_fifo0 > 64 || cfg->buf_size_rx_fifo1 > 64
|| cfg->buf_size_rx > 64 || cfg->buf_size_tx > 64)
return false;
set->ram_filt_std = cfg->msg_ram;
*size = (uint32_t)cfg->array_size_filt_std * MCAN_RAM_FILT_STD_SIZE;
set->ram_filt_ext = cfg->msg_ram + *size;
*size += (uint32_t)cfg->array_size_filt_ext * MCAN_RAM_FILT_EXT_SIZE;
set->ram_fifo_rx0 = cfg->msg_ram + *size;
*size += (uint32_t)cfg->fifo_size_rx0 * (MCAN_RAM_BUF_HDR_SIZE
+ cfg->buf_size_rx_fifo0 / 4);
set->ram_fifo_rx1 = cfg->msg_ram + *size;
*size += (uint32_t)cfg->fifo_size_rx1 * (MCAN_RAM_BUF_HDR_SIZE
+ cfg->buf_size_rx_fifo1 / 4);
set->ram_array_rx = cfg->msg_ram + *size;
*size += (uint32_t)cfg->array_size_rx * (MCAN_RAM_BUF_HDR_SIZE
+ cfg->buf_size_rx / 4);
set->ram_fifo_tx_evt = cfg->msg_ram + *size;
*size += (uint32_t)cfg->fifo_size_tx_evt * MCAN_RAM_TX_EVT_SIZE;
set->ram_array_tx = cfg->msg_ram + *size;
*size += (uint32_t)cfg->array_size_tx * (MCAN_RAM_BUF_HDR_SIZE
+ cfg->buf_size_tx / 4);
*size += (uint32_t)cfg->fifo_size_tx * (MCAN_RAM_BUF_HDR_SIZE
+ cfg->buf_size_tx / 4);
return true;
}
/*---------------------------------------------------------------------------
* Exported Functions
*---------------------------------------------------------------------------*/
bool mcan_configure_msg_ram(const struct mcan_config *cfg, uint32_t *size)
{
assert(cfg);
assert(size);
struct mcan_set tmp_set = { .cfg = { 0 } };
return configure_ram(&tmp_set, cfg, size);
}
bool mcan_initialize(struct mcan_set *set, const struct mcan_config *cfg)
{
assert(set);
assert(cfg);
assert(cfg->regs);
assert(cfg->msg_ram);
Mcan *mcan = cfg->regs;
uint32_t *element = NULL, *elem_end = NULL;
uint32_t freq, regVal32;
enum mcan_dlc dlc;
memset(set, 0, sizeof(*set));
if (!configure_ram(set, cfg, &regVal32))
return false;
set->cfg = *cfg;
/* Configure the MSB of the Message RAM Base Address */
regVal32 = (uint32_t)cfg->msg_ram >> 16;
if (cfg->id == ID_CAN0_INT0 || cfg->id == ID_CAN0_INT1)
regVal32 = (SFR->SFR_CAN & ~SFR_CAN_EXT_MEM_CAN0_ADDR_Msk)
| SFR_CAN_EXT_MEM_CAN0_ADDR(regVal32);
else
regVal32 = (SFR->SFR_CAN & ~SFR_CAN_EXT_MEM_CAN1_ADDR_Msk)
| SFR_CAN_EXT_MEM_CAN1_ADDR(regVal32);
SFR->SFR_CAN = regVal32;
/* Reset the CC Control Register */
mcan->MCAN_CCCR = 0 | MCAN_CCCR_INIT_ENABLED;
mcan_disable(set);
mcan_reconfigure(set);
/* Global Filter Configuration: Reject remote frames, reject non-matching frames */
mcan->MCAN_GFC = MCAN_GFC_RRFE_REJECT | MCAN_GFC_RRFS_REJECT
| MCAN_GFC_ANFE(2) | MCAN_GFC_ANFS(2);
/* Extended ID Filter AND mask */
mcan->MCAN_XIDAM = 0x1FFFFFFF;
/* Interrupt configuration - leave initialization with all interrupts off
* Disable all interrupts */
mcan->MCAN_IE = 0;
mcan->MCAN_TXBTIE = 0x00000000;
/* All interrupts directed to Line 0 */
mcan->MCAN_ILS = 0x00000000;
/* Disable both interrupt LINE 0 & LINE 1 */
mcan->MCAN_ILE = 0x00;
/* Clear all interrupt flags */
mcan->MCAN_IR = 0xFFCFFFFF;
/* Configure CAN bit timing */
if (cfg->bit_rate == 0
|| cfg->quanta_before_sp < 3 || cfg->quanta_before_sp > 257
|| cfg->quanta_after_sp < 1 || cfg->quanta_after_sp > 128
|| cfg->quanta_sync_jump < 1 || cfg->quanta_sync_jump > 128)
return false;
/* Retrieve the frequency of the CAN core clock i.e. the Generated Clock */
freq = pmc_get_gck_clock(cfg->id);
/* Compute the Nominal Baud Rate Prescaler */
regVal32 = ROUND_INT_DIV(freq, cfg->bit_rate
* (cfg->quanta_before_sp + cfg->quanta_after_sp));
if (regVal32 < 1 || regVal32 > 512)
return false;
/* Apply bit timing configuration */
mcan->MCAN_NBTP = MCAN_NBTP_NBRP(regVal32 - 1)
| MCAN_NBTP_NTSEG1(cfg->quanta_before_sp - 1 - 1)
| MCAN_NBTP_NTSEG2(cfg->quanta_after_sp - 1)
| MCAN_NBTP_NSJW(cfg->quanta_sync_jump - 1);
/* Configure fast CAN FD bit timing */
if (cfg->bit_rate_fd < cfg->bit_rate
|| cfg->quanta_before_sp_fd < 3 || cfg->quanta_before_sp_fd > 33
|| cfg->quanta_after_sp_fd < 1 || cfg->quanta_after_sp_fd > 16
|| cfg->quanta_sync_jump_fd < 1 || cfg->quanta_sync_jump_fd > 8)
return false;
/* Compute the Fast Baud Rate Prescaler */
regVal32 = ROUND_INT_DIV(freq, cfg->bit_rate_fd
* (cfg->quanta_before_sp_fd + cfg->quanta_after_sp_fd));
if (regVal32 < 1 || regVal32 > 32)
return false;
/* Apply bit timing configuration */
mcan->MCAN_DBTP = MCAN_DBTP_FBRP(regVal32 - 1)
| MCAN_DBTP_DTSEG1(cfg->quanta_before_sp_fd - 1 - 1)
| MCAN_DBTP_DTSEG2(cfg->quanta_after_sp_fd - 1)
| MCAN_DBTP_DSJW(cfg->quanta_sync_jump_fd - 1);
/* Configure Message RAM starting addresses and element count */
/* 11-bit Message ID Rx Filters */
mcan->MCAN_SIDFC =
MCAN_SIDFC_FLSSA((uint32_t)set->ram_filt_std >> 2)
| MCAN_SIDFC_LSS(cfg->array_size_filt_std);
/* 29-bit Message ID Rx Filters */
mcan->MCAN_XIDFC =
MCAN_XIDFC_FLESA((uint32_t)set->ram_filt_ext >> 2)
| MCAN_XIDFC_LSE(cfg->array_size_filt_ext);
/* Rx FIFO 0 */
mcan->MCAN_RXF0C =
MCAN_RXF0C_F0SA((uint32_t)set->ram_fifo_rx0 >> 2)
| MCAN_RXF0C_F0S(cfg->fifo_size_rx0)
| MCAN_RXF0C_F0WM(0)
| 0; /* clear MCAN_RXF0C_F0OM */
/* Rx FIFO 1 */
mcan->MCAN_RXF1C =
MCAN_RXF1C_F1SA((uint32_t)set->ram_fifo_rx1 >> 2)
| MCAN_RXF1C_F1S(cfg->fifo_size_rx1)
| MCAN_RXF1C_F1WM(0)
| 0; /* clear MCAN_RXF1C_F1OM */
/* Dedicated Rx Buffers
* Note: the HW does not know (and does not care about) how many
* dedicated Rx Buffers are used by the application. */
mcan->MCAN_RXBC =
MCAN_RXBC_RBSA((uint32_t)set->ram_array_rx >> 2);
/* Tx Event FIFO */
mcan->MCAN_TXEFC =
MCAN_TXEFC_EFSA((uint32_t)set->ram_fifo_tx_evt >> 2)
| MCAN_TXEFC_EFS(cfg->fifo_size_tx_evt)
| MCAN_TXEFC_EFWM(0);
/* Tx Buffers */
mcan->MCAN_TXBC =
MCAN_TXBC_TBSA((uint32_t)set->ram_array_tx >> 2)
| MCAN_TXBC_NDTB(cfg->array_size_tx)
| MCAN_TXBC_TFQS(cfg->fifo_size_tx)
| 0; /* clear MCAN_TXBC_TFQM */
/* Configure the size of data fields in Rx and Tx Buffer Elements */
if (!get_length_code(cfg->buf_size_rx_fifo0, &dlc))
return false;
regVal32 = MCAN_RXESC_F0DS(dlc < CAN_DLC_8 ? 0 : dlc - CAN_DLC_8);
if (!get_length_code(cfg->buf_size_rx_fifo1, &dlc))
return false;
regVal32 |= MCAN_RXESC_F1DS(dlc < CAN_DLC_8 ? 0 : dlc - CAN_DLC_8);
if (!get_length_code(cfg->buf_size_rx, &dlc))
return false;
regVal32 |= MCAN_RXESC_RBDS(dlc < CAN_DLC_8 ? 0 : dlc - CAN_DLC_8);
mcan->MCAN_RXESC = regVal32;
if (!get_length_code(cfg->buf_size_tx, &dlc))
return false;
mcan->MCAN_TXESC =
MCAN_TXESC_TBDS(dlc < CAN_DLC_8 ? 0 : dlc - CAN_DLC_8);
/* Configure Message ID Filters
* ...Disable all standard filters */
for (element = set->ram_filt_std, elem_end = set->ram_filt_std
+ (uint32_t)cfg->array_size_filt_std * MCAN_RAM_FILT_STD_SIZE;
element < elem_end;
element += MCAN_RAM_FILT_STD_SIZE)
element[0] = MCAN_RAM_FILT_SFEC_DIS;
/* ...Disable all extended filters */
for (element = set->ram_filt_ext, elem_end = set->ram_filt_ext
+ (uint32_t)cfg->array_size_filt_ext * MCAN_RAM_FILT_EXT_SIZE;
element < elem_end;
element += MCAN_RAM_FILT_EXT_SIZE)
element[0] = MCAN_RAM_FILT_EFEC_DIS;
mcan->MCAN_NDAT1 = 0xFFFFFFFF; /* clear new (rx) data flags */
mcan->MCAN_NDAT2 = 0xFFFFFFFF; /* clear new (rx) data flags */
regVal32 = mcan->MCAN_CCCR & ~(MCAN_CCCR_BRSE | MCAN_CCCR_FDOE);
mcan->MCAN_CCCR = regVal32 | MCAN_CCCR_PXHD | MCAN_CCCR_BRSE_DISABLED
| MCAN_CCCR_FDOE_DISABLED;
DSB();
ISB();
return true;
}
void mcan_reconfigure(struct mcan_set *set)
{
Mcan *mcan = set->cfg.regs;
uint32_t regVal32;
regVal32 = mcan->MCAN_CCCR & ~MCAN_CCCR_CCE;
assert((regVal32 & MCAN_CCCR_INIT) == MCAN_CCCR_INIT_ENABLED);
/* Enable writing to configuration registers */
mcan->MCAN_CCCR = regVal32 | MCAN_CCCR_CCE_CONFIGURABLE;
}
void mcan_set_mode(struct mcan_set *set, enum mcan_can_mode mode)
{
Mcan *mcan = set->cfg.regs;
uint32_t regVal32;
regVal32 = mcan->MCAN_CCCR & ~(MCAN_CCCR_BRSE | MCAN_CCCR_FDOE);
switch (mode) {
case MCAN_MODE_CAN:
regVal32 |= MCAN_CCCR_BRSE_DISABLED | MCAN_CCCR_FDOE_DISABLED;
break;
case MCAN_MODE_EXT_LEN_CONST_RATE:
regVal32 |= MCAN_CCCR_BRSE_DISABLED | MCAN_CCCR_FDOE_ENABLED;
break;
case MCAN_MODE_EXT_LEN_DUAL_RATE:
regVal32 |= MCAN_CCCR_BRSE_ENABLED | MCAN_CCCR_FDOE_ENABLED;
break;
default:
return;
}
mcan->MCAN_CCCR = regVal32;
}
enum mcan_can_mode mcan_get_mode(const struct mcan_set *set)
{
const uint32_t cccr = set->cfg.regs->MCAN_CCCR;
if ((cccr & MCAN_CCCR_FDOE) == MCAN_CCCR_FDOE_DISABLED)
return MCAN_MODE_CAN;
if ((cccr & MCAN_CCCR_BRSE) == MCAN_CCCR_BRSE_DISABLED)
return MCAN_MODE_EXT_LEN_CONST_RATE;
return MCAN_MODE_EXT_LEN_DUAL_RATE;
}
void mcan_init_loopback(struct mcan_set *set)
{
Mcan *mcan = set->cfg.regs;
mcan->MCAN_CCCR |= MCAN_CCCR_TEST_ENABLED;
#if 0
mcan->MCAN_CCCR |= MCAN_CCCR_MON_ENABLED; /* for internal loop back */
#endif
mcan->MCAN_TEST |= MCAN_TEST_LBCK_ENABLED;
}
void mcan_set_tx_queue_mode(struct mcan_set *set)
{
Mcan *mcan = set->cfg.regs;
mcan->MCAN_TXBC |= MCAN_TXBC_TFQM;
}
void mcan_enable(struct mcan_set *set)
{
uint32_t index, val;
/* Depending on bus condition, the HW may switch back to the
* Initialization state, by itself. Therefore, upon timeout, return.
* [Using an arbitrary timeout criterion.] */
for (index = 0; index < 1024; index++) {
val = set->cfg.regs->MCAN_CCCR;
if ((val & MCAN_CCCR_INIT) == MCAN_CCCR_INIT_DISABLED)
break;
if (index == 0)
set->cfg.regs->MCAN_CCCR = (val & ~MCAN_CCCR_INIT)
| MCAN_CCCR_INIT_DISABLED;
}
}
void mcan_disable(struct mcan_set *set)
{
uint32_t val;
bool initial;
for (initial = true; true; initial = false) {
val = set->cfg.regs->MCAN_CCCR;
if ((val & MCAN_CCCR_INIT) == MCAN_CCCR_INIT_ENABLED)
break;
if (initial)
set->cfg.regs->MCAN_CCCR = (val & ~MCAN_CCCR_INIT)
| MCAN_CCCR_INIT_ENABLED;
}
}
void mcan_loopback_on(struct mcan_set *set)
{
Mcan *mcan = set->cfg.regs;
mcan->MCAN_TEST |= MCAN_TEST_LBCK_ENABLED;
}
void mcan_loopback_off(struct mcan_set *set)
{
Mcan *mcan = set->cfg.regs;
mcan->MCAN_TEST &= ~MCAN_TEST_LBCK_ENABLED;
}
void mcan_enable_rx_array_flag(struct mcan_set *set, uint8_t line)
{
assert(line == 0 || line == 1);
Mcan *mcan = set->cfg.regs;
if (line) {
mcan->MCAN_ILS |= MCAN_ILS_DRXL;
mcan->MCAN_ILE |= MCAN_ILE_EINT1;
} else {
mcan->MCAN_ILS &= ~MCAN_ILS_DRXL;
mcan->MCAN_ILE |= MCAN_ILE_EINT0;
}
mcan->MCAN_IR = MCAN_IR_DRX; /* clear previous flag */
mcan->MCAN_IE |= MCAN_IE_DRXE; /* enable it */
}
uint8_t * mcan_prepare_tx_buffer(struct mcan_set *set, uint8_t buf_idx,
uint32_t id, uint8_t len)
{
assert(buf_idx < set->cfg.array_size_tx);
assert(len <= set->cfg.buf_size_tx);
Mcan *mcan = set->cfg.regs;
uint32_t *pThisTxBuf = 0;
uint32_t val;
const enum mcan_can_mode mode = mcan_get_mode(set);
enum mcan_dlc dlc;
if (buf_idx >= set->cfg.array_size_tx)
return NULL;
if (!get_length_code(len, &dlc))
dlc = CAN_DLC_0;
pThisTxBuf = set->ram_array_tx + buf_idx
* (MCAN_RAM_BUF_HDR_SIZE + set->cfg.buf_size_tx / 4);
if (mcan_is_extended_id(id))
*pThisTxBuf++ = MCAN_RAM_BUF_XTD | MCAN_RAM_BUF_ID_XTD(id);
else
*pThisTxBuf++ = MCAN_RAM_BUF_ID_STD(id);
val = MCAN_RAM_BUF_MM(0) | MCAN_RAM_BUF_DLC((uint32_t)dlc);
if (mode == MCAN_MODE_EXT_LEN_CONST_RATE)
val |= MCAN_RAM_BUF_FDF;
else if (mode == MCAN_MODE_EXT_LEN_DUAL_RATE)
val |= MCAN_RAM_BUF_FDF | MCAN_RAM_BUF_BRS;
*pThisTxBuf++ = val;
/* enable transmit from buffer to set TC interrupt bit in IR,
* but interrupt will not happen unless TC interrupt is enabled */
mcan->MCAN_TXBTIE = (1 << buf_idx);
return (uint8_t *)pThisTxBuf; /* now it points to the data field */
}
void mcan_send_tx_buffer(struct mcan_set *set, uint8_t buf_idx)
{
Mcan *mcan = set->cfg.regs;
if (buf_idx < set->cfg.array_size_tx)
mcan->MCAN_TXBAR = (1 << buf_idx);
}
uint8_t mcan_enqueue_outgoing_msg(struct mcan_set *set, uint32_t id,
uint8_t len, const uint8_t *data)
{
assert(len <= set->cfg.buf_size_tx);
Mcan *mcan = set->cfg.regs;
uint32_t val;
uint32_t *pThisTxBuf = 0;
const enum mcan_can_mode mode = mcan_get_mode(set);
enum mcan_dlc dlc;
uint8_t putIdx = 255;
if (!get_length_code(len, &dlc))
dlc = CAN_DLC_0;
/* Configured for FifoQ and FifoQ not full? */
if (set->cfg.fifo_size_tx == 0 || (mcan->MCAN_TXFQS & MCAN_TXFQS_TFQF))
return putIdx;
putIdx = (uint8_t)((mcan->MCAN_TXFQS & MCAN_TXFQS_TFQPI_Msk)
>> MCAN_TXFQS_TFQPI_Pos);
pThisTxBuf = set->ram_array_tx + (uint32_t)
putIdx * (MCAN_RAM_BUF_HDR_SIZE + set->cfg.buf_size_tx / 4);
if (mcan_is_extended_id(id))
*pThisTxBuf++ = MCAN_RAM_BUF_XTD | MCAN_RAM_BUF_ID_XTD(id);
else
*pThisTxBuf++ = MCAN_RAM_BUF_ID_STD(id);
val = MCAN_RAM_BUF_MM(0) | MCAN_RAM_BUF_DLC((uint32_t)dlc);
if (mode == MCAN_MODE_EXT_LEN_CONST_RATE)
val |= MCAN_RAM_BUF_FDF;
else if (mode == MCAN_MODE_EXT_LEN_DUAL_RATE)
val |= MCAN_RAM_BUF_FDF | MCAN_RAM_BUF_BRS;
*pThisTxBuf++ = val;
memcpy(pThisTxBuf, data, len);
/* enable transmit from buffer to set TC interrupt bit in IR,
* but interrupt will not happen unless TC interrupt is enabled
*/
mcan->MCAN_TXBTIE = (1 << putIdx);
/* request to send */
mcan->MCAN_TXBAR = (1 << putIdx);
return putIdx;
}
bool mcan_is_buffer_sent(const struct mcan_set *set, uint8_t buf_idx)
{
Mcan *mcan = set->cfg.regs;
return mcan->MCAN_TXBTO & (1 << buf_idx) ? true : false;
}
void mcan_filter_single_id(struct mcan_set *set,
uint8_t buf_idx, uint8_t filter, uint32_t id)
{
assert(buf_idx < set->cfg.array_size_rx);
assert(id & CAN_EXT_MSG_ID ? filter < set->cfg.array_size_filt_ext
: filter < set->cfg.array_size_filt_std);
assert(id & CAN_EXT_MSG_ID ? (id & ~CAN_EXT_MSG_ID) <= 0x1fffffff :
id <= 0x7ff);
uint32_t *pThisRxFilt = 0;
if (buf_idx >= set->cfg.array_size_rx)
return;
if (mcan_is_extended_id(id)) {
pThisRxFilt = set->ram_filt_ext + filter
* MCAN_RAM_FILT_EXT_SIZE;
*pThisRxFilt++ = MCAN_RAM_FILT_EFEC_BUF
| MCAN_RAM_FILT_EFID1(id);
*pThisRxFilt = MCAN_RAM_FILT_EFID2_BUF
| MCAN_RAM_FILT_EFID2_BUF_IDX(buf_idx);
} else {
pThisRxFilt = set->ram_filt_std + filter
* MCAN_RAM_FILT_STD_SIZE;
*pThisRxFilt = MCAN_RAM_FILT_SFEC_BUF
| MCAN_RAM_FILT_SFID1(id)
| MCAN_RAM_FILT_SFID2_BUF
| MCAN_RAM_FILT_SFID2_BUF_IDX(buf_idx);
}
}
void mcan_filter_id_mask(struct mcan_set *set, uint8_t fifo, uint8_t filter,
uint32_t id, uint32_t mask)
{
assert(fifo == 0 || fifo == 1);
assert(id & CAN_EXT_MSG_ID ? filter < set->cfg.array_size_filt_ext
: filter < set->cfg.array_size_filt_std);
assert(id & CAN_EXT_MSG_ID ? (id & ~CAN_EXT_MSG_ID) <= 0x1fffffff :
id <= 0x7ff);
assert(id & CAN_EXT_MSG_ID ? mask <= 0x1fffffff : mask <= 0x7ff);
uint32_t *pThisRxFilt = 0;
uint32_t val;
if (mcan_is_extended_id(id)) {
pThisRxFilt = set->ram_filt_ext + filter
* MCAN_RAM_FILT_EXT_SIZE;
*pThisRxFilt++ = (fifo ? MCAN_RAM_FILT_EFEC_FIFO1
: MCAN_RAM_FILT_EFEC_FIFO0) | MCAN_RAM_FILT_EFID1(id);
*pThisRxFilt = MCAN_RAM_FILT_EFT_CLASSIC
| MCAN_RAM_FILT_EFID2(mask);
} else {
pThisRxFilt = set->ram_filt_std + filter
* MCAN_RAM_FILT_STD_SIZE;
val = MCAN_RAM_FILT_SFT_CLASSIC
| MCAN_RAM_FILT_SFID1(id)
| MCAN_RAM_FILT_SFID2(mask);
*pThisRxFilt = (fifo ? MCAN_RAM_FILT_SFEC_FIFO1
: MCAN_RAM_FILT_SFEC_FIFO0) | val;
}
}
bool mcan_rx_buffer_data(const struct mcan_set *set, uint8_t buf_idx)
{
Mcan *mcan = set->cfg.regs;
if (buf_idx < 32)
return mcan->MCAN_NDAT1 & (1 << buf_idx) ? true : false;
else if (buf_idx < 64)
return mcan->MCAN_NDAT2 & (1 << (buf_idx - 32)) ? true : false;
else
return false;
}
void mcan_read_rx_buffer(struct mcan_set *set, uint8_t buf_idx,
struct mcan_msg_info *msg)
{
assert(buf_idx < set->cfg.array_size_rx);
Mcan *mcan = set->cfg.regs;
const uint32_t *pThisRxBuf = 0;
uint32_t tempRy; /* temp copy of RX buffer word */
uint8_t len;
if (buf_idx >= set->cfg.array_size_rx) {
msg->id = 0;
msg->timestamp = 0;
msg->full_len = 0;
msg->data_len = 0;
return;
}
pThisRxBuf = set->ram_array_rx + (buf_idx
* (MCAN_RAM_BUF_HDR_SIZE + set->cfg.buf_size_rx / 4));
tempRy = *pThisRxBuf++; /* word R0 contains ID */
if (tempRy & MCAN_RAM_BUF_XTD)
msg->id = CAN_EXT_MSG_ID | (tempRy & MCAN_RAM_BUF_ID_XTD_Msk)
>> MCAN_RAM_BUF_ID_XTD_Pos;
else
msg->id = (tempRy & MCAN_RAM_BUF_ID_STD_Msk)
>> MCAN_RAM_BUF_ID_STD_Pos;
tempRy = *pThisRxBuf++; /* word R1 contains DLC & time stamp */
msg->full_len = len = get_data_length((enum mcan_dlc)
((tempRy & MCAN_RAM_BUF_DLC_Msk) >> MCAN_RAM_BUF_DLC_Pos));
msg->timestamp = (tempRy & MCAN_RAM_BUF_RXTS_Msk)
>> MCAN_RAM_BUF_RXTS_Pos;
if (msg->data) {
/* copy the data from the Rx Buffer Element to the
* application-owned buffer */
if (len > set->cfg.buf_size_rx)
len = set->cfg.buf_size_rx;
if (len > msg->data_len)
len = msg->data_len;
memcpy(msg->data, pThisRxBuf, len);
msg->data_len = len;
}
else
msg->data_len = 0;
/* clear the new data flag for the buffer */
if (buf_idx < 32)
mcan->MCAN_NDAT1 = (1 << buf_idx);
else
mcan->MCAN_NDAT2 = (1 << (buf_idx - 32));
}
uint8_t mcan_dequeue_received_msg(struct mcan_set *set, uint8_t fifo,
struct mcan_msg_info *msg)
{
assert(fifo == 0 || fifo == 1);
Mcan *mcan = set->cfg.regs;
uint32_t *pThisRxBuf = 0;
uint32_t tempRy; /* temp copy of RX buffer word */
uint8_t buf_elem_data_size, len;
uint32_t *fifo_ack_reg;
uint32_t get_index;
uint8_t fill_level = 0; /* default: fifo empty */
if (fifo) {
get_index = (mcan->MCAN_RXF1S & MCAN_RXF1S_F1GI_Msk) >>
MCAN_RXF1S_F1GI_Pos;
fill_level = (uint8_t)((mcan->MCAN_RXF1S & MCAN_RXF1S_F1FL_Msk)
>> MCAN_RXF1S_F1FL_Pos);
pThisRxBuf = set->ram_fifo_rx1;
buf_elem_data_size = set->cfg.buf_size_rx_fifo1;
fifo_ack_reg = (uint32_t *) & mcan->MCAN_RXF1A;
} else {
get_index = (mcan->MCAN_RXF0S & MCAN_RXF0S_F0GI_Msk)
>> MCAN_RXF0S_F0GI_Pos;
fill_level = (uint8_t)((mcan->MCAN_RXF0S & MCAN_RXF0S_F0FL_Msk)
>> MCAN_RXF0S_F0FL_Pos);
pThisRxBuf = set->ram_fifo_rx0;
buf_elem_data_size = set->cfg.buf_size_rx_fifo0;
fifo_ack_reg = (uint32_t *) & mcan->MCAN_RXF0A;
}
if (fill_level == 0)
return 0;
pThisRxBuf += get_index * (MCAN_RAM_BUF_HDR_SIZE + buf_elem_data_size
/ 4);
tempRy = *pThisRxBuf++; /* word R0 contains ID */
if (tempRy & MCAN_RAM_BUF_XTD)
msg->id = CAN_EXT_MSG_ID | (tempRy & MCAN_RAM_BUF_ID_XTD_Msk)
>> MCAN_RAM_BUF_ID_XTD_Pos;
else
msg->id = (tempRy & MCAN_RAM_BUF_ID_STD_Msk)
>> MCAN_RAM_BUF_ID_STD_Pos;
tempRy = *pThisRxBuf++; /* word R1 contains DLC & timestamps */
msg->full_len = len = get_data_length((enum mcan_dlc)
((tempRy & MCAN_RAM_BUF_DLC_Msk) >> MCAN_RAM_BUF_DLC_Pos));
msg->timestamp = (tempRy & MCAN_RAM_BUF_RXTS_Msk)
>> MCAN_RAM_BUF_RXTS_Pos;
if (msg->data) {
/* copy the data from the Rx Buffer Element to the
* application-owned buffer */
if (len > buf_elem_data_size)
len = buf_elem_data_size;
if (len > msg->data_len)
len = msg->data_len;
memcpy(msg->data, pThisRxBuf, len);
msg->data_len = len;
}
else
msg->data_len = 0;
/* acknowledge reading the fifo entry */
*fifo_ack_reg = get_index;
/* return entries remaining in FIFO */
return (fill_level);
}
/**@}*/

View file

@ -0,0 +1,439 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* \section Purpose
*
* Controller Area Network with Flexible Data-rate.
* Interface for configuring and using the MCAN peripheral.
*/
#ifndef _MCAN_H_
#define _MCAN_H_
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include <assert.h>
#ifdef __cplusplus
extern "C" {
#endif
/*----------------------------------------------------------------------------
* Definitions
*----------------------------------------------------------------------------*/
enum mcan_can_mode
{
/* ISO 11898-1 CAN mode */
MCAN_MODE_CAN,
/* Long CAN FD frame.
* - TX and RX payloads up to 64 bytes.
* - Slow transmitter: TX frames are sent at constant bit rate.
* - Fast receiver: both constant-rate (slow) and dual-rate (fast)
* RX frames are supported and received. */
MCAN_MODE_EXT_LEN_CONST_RATE,
/* Long and fast CAN FD frame.
* - TX and RX payloads up to 64 bytes.
* - Fast transmitter: control, data and CRC fields are transmitted at a
* higher bit rate.
* - Fast receiver. */
MCAN_MODE_EXT_LEN_DUAL_RATE,
};
/* Flag signalling a standard (11-bit) message identifiers */
#define CAN_STD_MSG_ID (0x0u << 30)
/* Flag to be bitwise or'ed to extended (29-bit) message identifiers */
#define CAN_EXT_MSG_ID (0x1u << 30)
struct mcan_msg_info
{
uint32_t id;
uint32_t timestamp;
uint8_t *data;
uint8_t full_len;
uint8_t data_len;
};
struct mcan_config
{
uint32_t id; /* peripheral ID (ID_xxx) */
Mcan *regs; /* set of MCAN hardware registers */
uint32_t *msg_ram; /* base address of the Message RAM to be
* assigned to this MCAN instance */
uint8_t array_size_filt_std; /* # of 11-bit Message ID Rx Filters */
uint8_t array_size_filt_ext; /* # of 29-bit Message ID Rx Filters */
uint8_t fifo_size_rx0; /* # of Rx Buffers in Rx FIFO 0 */
uint8_t fifo_size_rx1; /* # of Rx Buffers in Rx FIFO 1 */
uint8_t array_size_rx; /* # of dedicated Rx Buffers */
uint8_t fifo_size_tx_evt; /* # of Tx Event Elements in the Tx Event
* FIFO */
uint8_t array_size_tx; /* # of dedicated Tx Buffers */
uint8_t fifo_size_tx; /* # of Tx Buffers in the Tx FIFO or Tx
* Queue */
uint8_t buf_size_rx_fifo0; /* size of the data field in each Rx
* Buffer of Rx FIFO 0, in bytes */
uint8_t buf_size_rx_fifo1; /* size of the data field in each Rx
* Buffer of Rx FIFO 1, in bytes */
uint8_t buf_size_rx; /* size of the data field in each
* dedicated Rx Buffer, in bytes */
uint8_t buf_size_tx; /* size of the data field in each Tx
* Buffer, in bytes. Applies to all Tx
* Buffers, dedicated and in Tx FIFO /
* Queue. */
uint32_t bit_rate; /* requested CAN bit rate in CAN mode,
* in bps */
uint16_t quanta_before_sp; /* duration of the time segment before the
* sample point (Sync_Seg + Prop_Seg +
* Phase_Seg1), while in CAN mode,
* expressed in CAN time quanta */
uint8_t quanta_after_sp; /* duration of the time segment after the
* sample point (Phase_Seg2), while in CAN
* mode, expressed in CAN time quanta */
uint32_t bit_rate_fd; /* requested CAN bit rate in fast CAN FD
* mode, in bps */
uint8_t quanta_before_sp_fd; /* duration of the time segment before the
* sample point (Sync_Seg + Prop_Seg +
* Phase_Seg1), while in fast CAN FD mode,
* expressed in CAN time quanta */
uint8_t quanta_after_sp_fd; /* duration of the time segment after the
* sample point (Phase_Seg2), while in
* fast CAN FD mode, expressed in CAN time
* quanta */
uint8_t quanta_sync_jump; /* duration of a (re)synchronization jump,
* while in CAN mode, expressed in CAN
* time quanta */
uint8_t quanta_sync_jump_fd; /* duration of a (re)synchronization jump,
* while in fast CAN FD mode, expressed in
* CAN time quanta */
};
/* This structure is private to the MCAN Driver.
* Allocate it but ignore its members. */
struct mcan_set
{
struct mcan_config cfg;
uint32_t *ram_filt_std;
uint32_t *ram_filt_ext;
uint32_t *ram_fifo_rx0;
uint32_t *ram_fifo_rx1;
uint32_t *ram_array_rx;
uint32_t *ram_fifo_tx_evt;
uint32_t *ram_array_tx;
};
/*----------------------------------------------------------------------------
* Exported symbols
*----------------------------------------------------------------------------*/
static inline bool mcan_is_enabled(const struct mcan_set *set)
{
Mcan *mcan = set->cfg.regs;
return ((mcan->MCAN_CCCR & MCAN_CCCR_INIT) == MCAN_CCCR_INIT_DISABLED);
}
static inline bool mcan_is_extended_id(uint32_t msg_id)
{
return msg_id & CAN_EXT_MSG_ID ? true : false;
}
static inline uint32_t mcan_get_id(uint32_t msg_id)
{
return msg_id & CAN_EXT_MSG_ID ? msg_id & 0x1fffffff : msg_id & 0x7ff;
}
static inline bool mcan_is_tx_complete(const struct mcan_set *set)
{
Mcan *mcan = set->cfg.regs;
return mcan->MCAN_IR & MCAN_IR_TC ? true : false;
}
static inline void mcan_clear_tx_flag(const struct mcan_set *set)
{
Mcan *mcan = set->cfg.regs;
mcan->MCAN_IR = MCAN_IR_TC;
}
static inline bool mcan_rx_array_data(const struct mcan_set *set)
{
Mcan *mcan = set->cfg.regs;
return mcan->MCAN_IR & MCAN_IR_DRX ? true : false;
}
static inline void mcan_clear_rx_array_flag(const struct mcan_set *set)
{
Mcan *mcan = set->cfg.regs;
mcan->MCAN_IR = MCAN_IR_DRX;
}
static inline bool mcan_rx_fifo_data(const struct mcan_set *set, uint8_t fifo)
{
assert(fifo == 0 || fifo == 1);
Mcan *mcan = set->cfg.regs;
return mcan->MCAN_IR & (fifo ? MCAN_IR_RF1N : MCAN_IR_RF0N) ? true
: false;
}
static inline void mcan_clear_rx_fifo_flag(const struct mcan_set *set,
uint8_t fifo)
{
assert(fifo == 0 || fifo == 1);
Mcan *mcan = set->cfg.regs;
mcan->MCAN_IR = fifo ? MCAN_IR_RF1N : MCAN_IR_RF0N;
}
/**
* \brief Compute the size of the Message RAM to be assigned to the MCAN.
* \param cfg MCAN configuration to be considered. Only integer size parameters
* need to be configured. The other parameters can be left blank at this stage.
* \param size address where the required size of the Message RAM will be
* written, expressed in (32-bit) words.
* \return true if successful, false if a parameter is set to an unsupported
* value.
*/
bool mcan_configure_msg_ram(const struct mcan_config *cfg, uint32_t *size);
/**
* \brief Initialize the MCAN hardware for the given peripheral.
* Default: Non-FD, ISO 11898-1 CAN mode; mixed mode TX Buffer + FIFO.
* \param set Pointer to uninitialized driver instance data.
* \param cfg MCAN configuration to be used.
* \return true if successful, false if a parameter is set to an unsupported
* value.
*/
bool mcan_initialize(struct mcan_set *set, const struct mcan_config *cfg);
/**
* \brief Unlock the peripheral configuration so it can be altered.
* Prerequisite: the peripheral shall be disabled. In case the device has been
* enabled, call mcan_disable.
* \param set Pointer to driver instance data.
*/
void mcan_reconfigure(struct mcan_set *set);
/**
* \brief Select either the legacy ISO 11898-1 CAN mode or the CAN-FD mode,
* along with the FD variant in the latter case.
* Should be called further to mcan_initialize() or mcan_reconfigure(), before
* mcan_enable().
* \param set Pointer to driver instance data.
* \param mode CAN mode, and FD variant in case of FD mode.
*/
void mcan_set_mode(struct mcan_set *set, enum mcan_can_mode mode);
/**
* \brief Query the current CAN mode.
* \param set Pointer to driver instance data.
* \return Currently selected CAN mode, and FD variant in case of CAN FD mode.
*/
enum mcan_can_mode mcan_get_mode(const struct mcan_set *set);
/**
* \brief Select the TX Queue mode, disable TX FIFO mode.
* INIT must be set - so this should be called between mcan_initialize() and
* mcan_enable().
* \param set Pointer to driver instance data.
*/
void mcan_set_tx_queue_mode(struct mcan_set *set);
/**
* \brief Initialize the MCAN in loop back mode.
* INIT must be set - so this should be called between mcan_initialize() and
* mcan_enable().
* \param set Pointer to driver instance data.
*/
void mcan_init_loopback(struct mcan_set *set);
/**
* \brief Enable the peripheral I/O stage. Synchronize with the bus.
* INIT must be set - so this should be called after mcan_initialize().
* \param set Pointer to driver instance data.
*/
void mcan_enable(struct mcan_set *set);
/**
* \brief Disable the peripheral I/O stage. Go Bus_Off.
* \note Subsequent operations may include reconfiguring the peripheral
* (mcan_reconfigure) and/or re-enabling it (mcan_enable).
* \param set Pointer to driver instance data.
*/
void mcan_disable(struct mcan_set *set);
/**
* \brief Turn the loop-back mode ON.
* \note TEST must be set in MCAN_CCCR. This mode should have been enabled upon
* initialization.
* \param set Pointer to driver instance data.
*/
void mcan_loopback_on(struct mcan_set *set);
/**
* \brief Turn the loop-back mode OFF.
* \param set Pointer to driver instance data.
*/
void mcan_loopback_off(struct mcan_set *set);
/**
* \brief Select either the m_can_int0 or the m_can_int1 interrupt line.
* Also, enable the 'Message stored to Dedicated Receive Buffer' specific
* interrupt.
* \param set Pointer to driver instance data.
* \param int_line The interrupt line to be enabled:
* 0 -> m_can_int0
* 1 -> m_can_int1.
*/
void mcan_enable_rx_array_flag(struct mcan_set *set, uint8_t int_line);
/**
* \brief Configure a Dedicated TX Buffer.
* \param set Pointer to driver instance data.
* \param buf_idx Index of the dedicated transmit buffer to be used.
* \param id Message ID.
* \param len Data length, in bytes.
* \return Address of data byte 0, part of the transmit buffer.
*/
uint8_t * mcan_prepare_tx_buffer(struct mcan_set *set, uint8_t buf_idx,
uint32_t id, uint8_t len);
/**
* \brief Start the transmission of a Dedicated TX Buffer.
* \param set Pointer to driver instance data.
* \param buf_idx Index of the dedicated transmit buffer to be used.
*/
void mcan_send_tx_buffer(struct mcan_set *set, uint8_t buf_idx);
/**
* \brief Append the provided message to the TX FIFO, or to the TX Queue,
* depending on whether mcan_set_tx_queue_mode() has been invoked or not.
* \param set Pointer to driver instance data.
* \param id Message ID.
* \param len Data length, in bytes.
* \param data Pointer to data.
* \return Index of the assigned transmit buffer, part of the FIFO / queue.
* Or 0xff if the TX FIFO / queue was full, or an error occurred.
*/
uint8_t mcan_enqueue_outgoing_msg(struct mcan_set *set, uint32_t id,
uint8_t len, const uint8_t *data);
/**
* \brief Check if message transmitted from the specified TX Buffer, either
* dedicated or part of the TX FIFO or TX Queue.
* \param set Pointer to driver instance data.
* \param buf_idx Index of the transmit buffer to be queried.
* \return true if the message has been successfully transmitted, false
* otherwise.
*/
bool mcan_is_buffer_sent(const struct mcan_set *set, uint8_t buf_idx);
/**
* \brief Configure RX buffer filter.
* \param set Pointer to driver instance data.
* \param buf_idx Index of the receive buffer to be used as the recipient.
* \param filter Index of the filter to be configured.
* \param id Single message identifier. Incoming message need to match exactly
* to be accepted.
*/
void mcan_filter_single_id(struct mcan_set *set, uint8_t buf_idx,
uint8_t filter, uint32_t id);
/**
* \brief Configure classic RX filter.
* The classic filters direct the accepted messages to a FIFO, and include both
* an ID and an ID mask.
* \param set Pointer to driver instance data.
* \param fifo Index of the RX FIFO to be used as the recipient.
* \param filter Index of the filter to be configured.
* \param id Message identifier.
* \param mask Message identifier mask to be matched.
*/
void mcan_filter_id_mask(struct mcan_set *set, uint8_t fifo, uint8_t filter,
uint32_t id, uint32_t mask);
/**
* \brief Check whether some data has been received into the specified RX
* Buffer.
* \param set Pointer to driver instance data.
* \param buf_idx Index of the receive buffer to be queried.
* \return true if the receive buffer is flagged as containing an unfetched
* frame, and false otherwise.
*/
bool mcan_rx_buffer_data(const struct mcan_set *set, uint8_t buf_idx);
/**
* \brief Get RX buffer.
* \param set Pointer to driver instance data.
* \param buf_idx Index of the receive buffer to be read.
* \param msg Address where the CAN message properties will be written.
* The msg->data and msg->data_len parameters shall be initialized prior to
* calling this function. Message contents will be copied to msg->data if
* msg->data is not null and if msg->data_len is large enough.
*/
void mcan_read_rx_buffer(struct mcan_set *set, uint8_t buf_idx,
struct mcan_msg_info *msg);
/**
* \brief Detach one received message from the specified RX FIFO, and copy it to
* a buffer owned by the application.
* \param set Pointer to driver instance data.
* \param fifo Index of the RX FIFO to dequeue from.
* \param msg Address where the CAN message properties will be written.
* The msg->data and msg->data_len parameters shall be initialized prior to
* calling this function. Message contents will be copied to msg->data if
* msg->data is not null and if msg->data_len is large enough.
* \return: # of FIFO entries at the time the function was entered:
* 0 -> The FIFO was initially empty.
* 1 -> The FIFO had 1 entry upon entry, but is empty upon exit.
* 2 to 64 -> The FIFO had several entries upon entry, and still holds one
* or more entries upon exit.
*/
uint8_t mcan_dequeue_received_msg(struct mcan_set *set, uint8_t fifo,
struct mcan_msg_info *msg);
#ifdef __cplusplus
}
#endif
#endif /* #ifndef _MCAN_H_ */

View file

@ -0,0 +1,359 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
#include "chip.h"
#include "peripherals/mpddrc.h"
#include "peripherals/sfrbu.h"
#include "peripherals/pmc.h"
#include "trace.h"
#include "timer.h"
#include "compiler.h"
#include <stdlib.h>
static void _set_ddr_timings(struct _mpddrc_desc* desc)
{
MPDDRC->MPDDRC_TPR0 = desc->tpr0;
MPDDRC->MPDDRC_TPR1 = desc->tpr1;
MPDDRC->MPDDRC_TPR2 = desc->tpr2;
}
static uint32_t _compute_ba_offset(void)
{
/* Compute BA[] offset according to CR configuration */
uint32_t offset = (MPDDRC->MPDDRC_CR & MPDDRC_CR_NC_Msk) + 9;
if (!(MPDDRC->MPDDRC_CR & MPDDRC_CR_DECOD_INTERLEAVED))
offset += ((MPDDRC->MPDDRC_CR & MPDDRC_CR_NR_Msk) >> 2) + 11;
offset += (MPDDRC->MPDDRC_MD & MPDDRC_MD_DBW) ? 1 : 2;
return offset;
}
/**
* \brief Send a NOP command
*/
static void _send_nop_cmd(void)
{
MPDDRC->MPDDRC_MR = MPDDRC_MR_MODE_NOP_CMD;
/* Perform a write to a DDR memory access to acknoledge the command */
*((uint32_t *)DDR_CS_ADDR) = 0;
}
static void _send_lmr_cmd(void)
{
MPDDRC->MPDDRC_MR = MPDDRC_MR_MODE_LMR_CMD;
/* Perform a write to a DDR memory access to acknoledge the command */
*((uint32_t *)DDR_CS_ADDR) = 0u;
}
static void _send_ext_lmr_cmd(uint32_t opcode, uint32_t ba_offset)
{
MPDDRC->MPDDRC_MR = MPDDRC_MR_MODE_EXT_LMR_CMD;
/* Perform a write to a DDR memory access to acknoledge the command */
*((uint32_t *)(DDR_CS_ADDR + (opcode << ba_offset))) = 0u;
}
static void _send_normal_cmd(void)
{
MPDDRC->MPDDRC_MR = MPDDRC_MR_MODE_NORMAL_CMD;
/* Perform a write to a DDR memory access to acknoledge the command */
*((uint32_t *)DDR_CS_ADDR) = 0;
}
static void _send_precharge_cmd(void)
{
MPDDRC->MPDDRC_MR = MPDDRC_MR_MODE_PRCGALL_CMD;
/* Perform a write to a DDR memory access to acknoledge the command */
*((uint32_t *)DDR_CS_ADDR) = 0;
}
static void _send_refresh_cmd(void)
{
MPDDRC->MPDDRC_MR = MPDDRC_MR_MODE_RFSH_CMD;
/* Perform a write to a DDR memory access to acknoledge the command */
*((uint32_t *)DDR_CS_ADDR) = 0;
}
#ifdef CONFIG_HAVE_DDR3
static void _send_calib_cmd(void)
{
MPDDRC->MPDDRC_MR = MPDDRC_MR_MODE_DEEP_CALIB_MD;
/* Perform a write to a DDR memory access to acknoledge the command */
*((uint32_t *)DDR_CS_ADDR) = 0;
}
static void _configure_ddr3(struct _mpddrc_desc* desc)
{
/* Timings */
_set_ddr_timings(desc);
uint32_t ba_offset = _compute_ba_offset();
/*
* Step 3: Issue a NOP command to the memory controller using
* its mode register (MPDDRC_MR).
*/
_send_nop_cmd();
/*
* Step 4: A pause of at least 500us must be observed before a
* single toggle.
*/
timer_sleep(50);
/*
* Step 5: Issue a NOP command to the memory controller using
* its mode register (MPDDRC_MR). CKE is now driven high.
*/
_send_nop_cmd();
timer_sleep(1);
/*
* Step 6: Issue Extended Mode Register Set 2 (EMRS2) cycle to
* choose between commercial or high temperature
* operations.
*/
_send_ext_lmr_cmd(0x2, ba_offset);
timer_sleep(1);
/*
* Step 7: Issue Extended Mode Register Set 3 (EMRS3) cycle to set
* the Extended Mode Register to 0.
*/
_send_ext_lmr_cmd(0x3, ba_offset);
timer_sleep(1);
/*
* Step 8: Issue Extended Mode Register Set 1 (EMRS1) cycle to
* disable and to program O.D.S. (Output Driver Strength).
*/
_send_ext_lmr_cmd(0x1, ba_offset);
timer_sleep(1);
/*
* Step 9: Write a one to the DLL bit (enable DLL reset) in the MPDDRC
* Configuration Register (MPDDRC_CR)
*/
/* Not done for DDR3 */
/*
* Step 10: Issue a Mode Register Set (MRS) cycle to reset DLL.
*/
_send_lmr_cmd();
timer_sleep(5);
/*
* Step 11: Issue a Calibration command (MRS) cycle to calibrate RTT and
* RON values for the Process Voltage Temperature (PVT).
*/
_send_calib_cmd();
timer_sleep(1);
/*
* Step 12: A Normal Mode command is provided.
* Program the Normal mode in the MPDDRC_MR and perform a write access
* to any DDR3-SDRAM address to acknowledge this command.
*/
_send_normal_cmd();
/*
* Step 13: Perform a write access to any DDR3-SDRAM address.
*/
*((uint32_t *)(DDR_CS_ADDR)) = 0;
}
#endif
static void _configure_ddr2(struct _mpddrc_desc* desc)
{
/* Timings */
_set_ddr_timings(desc);
uint32_t ba_offset = _compute_ba_offset();
/* Step 3: An NOP command is issued to the DDR2-SDRAM. Program
* the NOP command into the Mode Register and wait minimum 200
* us */
_send_nop_cmd();
timer_sleep(20);
/* Step 4: Issue a NOP command. */
_send_nop_cmd();
timer_sleep(1);
/* Step 5: Issue all banks precharge command. */
_send_precharge_cmd();
timer_sleep(1);
/* Step 6: Issue an Extended Mode Register set (EMRS2) cycle
* to chose between commercialor high temperature
* operations. */
_send_ext_lmr_cmd(0x2, ba_offset);
timer_sleep(1);
/* Step 7: Issue an Extended Mode Register set (EMRS3) cycle
* to set all registers to 0. */
_send_ext_lmr_cmd(0x3, ba_offset);
timer_sleep(1);
/* Step 8: Issue an Extended Mode Register set (EMRS1) cycle
* to enable DLL. */
_send_ext_lmr_cmd(0x1, ba_offset);
timer_sleep(1);
/* Step 9: Program DLL field into the Configuration Register. */
MPDDRC->MPDDRC_CR |= MPDDRC_CR_DLL_RESET_ENABLED;
/* Step 10: A Mode Register set (MRS) cycle is issued to reset DLL. */
MPDDRC->MPDDRC_MR = MPDDRC_MR_MODE_LMR_CMD;
/* Perform a write to a DDR memory access to acknoledge the command */
*((uint32_t *)DDR_CS_ADDR) = 0;
timer_sleep(1);
/* Step 11: Issue all banks precharge command to the DDR2-SDRAM. */
_send_precharge_cmd();
timer_sleep(1);
/* Step 12: Two auto-refresh (CBR) cycles are
* provided. Program the auto refresh command (CBR) into the
* Mode Register. */
_send_refresh_cmd();
timer_sleep(1);
_send_refresh_cmd();
timer_sleep(1);
/* Step 13: Program DLL field into the Configuration Register
* to low(Disable DLL reset). */
MPDDRC->MPDDRC_CR &= ~MPDDRC_CR_DLL_RESET_ENABLED;
/* Step 14: Issue a Mode Register set (MRS) cycle to program
* the parameters of the DDR2-SDRAM devices. */
_send_lmr_cmd();
timer_sleep(1);
/* Step 15: Program OCD field into the Configuration Register
* to high (OCD calibration default). */
MPDDRC->MPDDRC_CR |= MPDDRC_CR_OCD_DDR2_DEFAULT_CALIB;
/* Step 16: An Extended Mode Register set (EMRS1) cycle is
* issued to OCD default value. */
_send_ext_lmr_cmd(0x1, ba_offset);
timer_sleep(1);
/* Step 19,20: A mode Normal command is provided. Program the
* Normal mode into Mode Register. */
_send_normal_cmd();
timer_sleep(1);
}
extern void mpddrc_configure(struct _mpddrc_desc* desc)
{
/* Retrieve the current resolution to put it back later */
uint32_t resolution = timer_get_resolution();
/* Configure time to have 10 microseconds resolution */
timer_configure(10);
/* controller and DDR clock */
pmc_enable_peripheral(ID_MPDDRC);
pmc_enable_system_clock(PMC_SYSTEM_CLOCK_DDR);
/* Step1: Program memory device type */
MPDDRC->MPDDRC_MD = desc->mode;
/* set driver impedance */
uint32_t value = MPDDRC->MPDDRC_IO_CALIBR;
value &= ~MPDDRC_IO_CALIBR_RDIV_Msk;
value &= ~MPDDRC_IO_CALIBR_TZQIO_Msk;
value &= ~MPDDRC_IO_CALIBR_CALCODEP_Msk;
value &= ~MPDDRC_IO_CALIBR_CALCODEN_Msk;
value |= desc->io_calibr;
MPDDRC->MPDDRC_IO_CALIBR = value;
MPDDRC->MPDDRC_RD_DATA_PATH = desc->data_path;
/* Step 2: Program features of the DDR3-SDRAM device in the
* configuration register and timing parameter registers (TPR0
* ans TPR1) */
/* Configurations */
MPDDRC->MPDDRC_CR = desc->control;
#ifdef CONFIG_HAVE_DDR3_SELFREFRESH
if (sfrbu_is_ddr_backup_enabled())
/* DDR memory had been initilized and in backup mode */
MPDDRC->MPDDRC_LPR =
MPDDRC_LPR_LPCB_SELFREFRESH |
MPDDRC_LPR_CLK_FR_ENABLED |
MPDDRC_LPR_PASR(0) |
MPDDRC_LPR_DS(2) |
MPDDRC_LPR_TIMEOUT_NONE |
MPDDRC_LPR_APDE_DDR2_FAST_EXIT |
MPDDRC_LPR_UPD_MR(0);
else
/* DDR memory is not in backup mode */
MPDDRC->MPDDRC_LPR =
MPDDRC_LPR_LPCB_SELFREFRESH |
MPDDRC_LPR_CLK_FR_ENABLED |
MPDDRC_LPR_PASR(0) |
MPDDRC_LPR_DS(2) |
MPDDRC_LPR_TIMEOUT_DELAY_128_CLK |
MPDDRC_LPR_APDE_DDR2_SLOW_EXIT |
MPDDRC_LPR_UPD_MR(0);
#endif
switch(desc->type) {
#ifdef CONFIG_HAVE_DDR3
case MPDDRC_TYPE_DDR3:
#ifdef CONFIG_HAVE_DDR3_SELFREFRESH
_set_ddr_timings(desc);
/* Initialize DDR chip when needed */
if (!sfrbu_is_ddr_backup_enabled())
#endif
_configure_ddr3(desc);
break;
#endif
case MPDDRC_TYPE_DDR2:
_configure_ddr2(desc);
break;
default:
trace_error("Device not handled\r\n");
abort();
}
/* Last step: Write the refresh rate */
/* Refresh Timer is (64ms / (bank_size)) * master_clock */
uint32_t master_clock = pmc_get_master_clock()/1000000;
MPDDRC->MPDDRC_RTR = MPDDRC_RTR_COUNT(64000*master_clock/desc->bank);
/* wait for end of calibration */
timer_sleep(1);
/* Restore resolution or put the default one if not already set */
timer_configure(resolution);
#ifdef CONFIG_HAVE_DDR3_SELFREFRESH
if (sfrbu_is_ddr_backup_enabled()) {
MPDDRC->MPDDRC_MR = MPDDRC_MR_MODE_NORMAL_CMD;
sfrbu_disable_ddr_backup();
}
#endif
}

View file

@ -0,0 +1,57 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
#ifndef MPDDRC_HEADER_
#define MPDDRC_HEADER_
#include <stdint.h>
enum _ram_type {
MPDDRC_TYPE_DDR3,
MPDDRC_TYPE_LPDDR3,
MPDDRC_TYPE_DDR2,
MPDDRC_TYPE_LPDDR2,
MPDDRC_TYPE_DDR
};
struct _mpddrc_desc {
enum _ram_type type;
uint32_t io_calibr;
uint32_t data_path;
uint32_t mode;
uint32_t control;
uint32_t bank;
uint32_t tpr0;
uint32_t tpr1;
uint32_t tpr2;
};
extern void mpddrc_configure(struct _mpddrc_desc* desc);
#endif

View file

@ -0,0 +1,205 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
#ifndef _PIO_H
#define _PIO_H
#define IRQ_PIO_HANDLERS_SIZE 16
/*------------------------------------------------------------------------------
* Global Types
*------------------------------------------------------------------------------*/
#include "chip.h"
struct _pin
{
uint8_t group; /*< The IO group containing the pins you want to use. */
uint32_t mask; /*< Bitmask indicating which pin(s) to configure. */
uint8_t type; /*< Pin type */
uint32_t attribute; /*< Pin config attribute. */
};
typedef void(*pio_handler_t)(uint32_t, uint32_t, void*);
/*------------------------------------------------------------------------------
* Headers
*------------------------------------------------------------------------------*/
#if defined(CONFIG_HAVE_PIO4)
#include "peripherals/pio4.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/*------------------------------------------------------------------------------
* Exported functions
*------------------------------------------------------------------------------*/
/**
* \brief Configures a list of Pin instances.
*
* \details Each of them can either hold a single pin or a group of
* pins, depending on the mask value; all pins are configured by this
* function. The size of the array must also be provided and is easily
* computed using ARRAY_SIZE whenever its length is not known in
* advance.
*
* \param list Pointer to a list of Pin instances.
* \param size Size of the Pin list (calculated using ARRAY_SIZE).
*
* \return 1 if the pins have been configured properly; otherwise 0.
*/
extern uint8_t pio_configure(const struct _pin *list, uint32_t size);
/**
* \brief Sets a high output level on all the PIOs defined in the
* given Pin instance.
*
* \details This has no immediate effects on PIOs that are not output,
* but the PIO controller will memorize the value they are changed to
* outputs.
*
* \param pin Pointer to a Pin instance describing one or more pins.
*/
extern void pio_set(const struct _pin *pin);
/**
* \brief Sets a low output level on all the PIOs defined in the given
* Pin instance.
*
* \details This has no immediate effects on PIOs that are not output,
* but the PIO controller will memorize the value they are changed to
* outputs.
*
* \param pin Pointer to a Pin instance describing one or more pins.
*/
extern void pio_clear(const struct _pin *pin);
/**
* \brief Returns 1 if one or more PIO of the given Pin instance currently have
* a high level; otherwise returns 0. This method returns the actual value that
* is being read on the pin. To return the supposed output value of a pin, use
* \ref pio_get_output_date_status() instead.
*
* \param pin Pointer to a Pin instance describing one or more pins.
*
* \return 1 if the Pin instance contains at least one PIO that currently has
* a high level; otherwise 0.
*/
extern uint8_t pio_get(const struct _pin *pin);
/**
* \brief Returns 1 if one or more PIO of the given Pin are configured to output a
* high level (even if they are not output).
* To get the actual value of the pin, use pio_get() instead.
*
* \param pin Pointer to a Pin instance describing one or more pins.
*
* \return 1 if the Pin instance contains at least one PIO that is configured
* to output a high level; otherwise 0.
*/
extern uint8_t pio_get_output_data_status(const struct _pin *pin);
/**
* \brief Configures Glitch or Debouncing filter for input.
*
* \param pin Pointer to a Pin instance describing one or more pins.
* \param cuttoff Cutt off frequency for debounce filter.
*/
extern void pio_set_debounce_filter(const struct _pin *pin, uint32_t cuttoff);
/**
* \brief Enable write protect.
*
* \param pin Pointer to a Pin instance describing one or more pins.
*/
extern void pio_enable_write_protect(const struct _pin *pin);
/**
* \brief Disable write protect.
*
* \param pin Pointer to a Pin instance describing one or more pins.
*/
extern void pio_disable_write_protect(const struct _pin *pin);
/**
* \brief Get write protect violation information.
*
* \param pin Pointer to a Pin instance describing one or more pins.
*/
extern uint32_t pio_get_write_protect_violation_info(const struct _pin * pin);
/**
* \brief Configure all pio outputs low
*
* \param group PIO group number
* \param mask Bitmask of one or more pin(s) to configure.
*/
extern void pio_output_low(uint32_t group, uint32_t mask);
extern void pio_add_handler_to_group(uint32_t group, uint32_t mask,
pio_handler_t handler, void* user_arg);
extern void pio_reset_all_it(void);
/**
* \brief Generate an interrupt on status change for a PIO or a group
* of PIO.
* \details The provided interrupt handler will be called with the
* triggering pin as its parameter (enabling different pin instances
* to share the same handler).
*
* \param pin Pointer to a _pin instance.
*/
extern void pio_configure_it(const struct _pin * pin);
/**
* Enables the given interrupt source if it has been configured. The status
* register of the corresponding PIO controller is cleared prior to enabling
* the interrupt.
* \param pin Interrupt source to enable.
*/
extern void pio_enable_it(const struct _pin * pin);
/**
* Disables a given interrupt source, with no added side effects.
*
* \param pin Interrupt source to disable.
*/
extern void pio_disable_it(const struct _pin * pin);
#ifdef __cplusplus
}
#endif
#endif /* _PIO_H */

View file

@ -0,0 +1,601 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/** \addtogroup pio_module Working with PIO
* \section Purpose
* The PIO driver provides the Interface for configuration the Parallel Input/Output
* Controller (PIO).
*
* \section Usage
* <ul>
* <li> Initialize the PIO with the desired period using pio_configure().
* <li> Set a high or low output level on the given PIO using pio_set() or pio_clear().
* <li> Get the level of the given PIOs using pio_get() or pio_get_output_date_status().
* <li> Configures Glitch or Debouncing filter for given input PIO using pio_set_debounce_filter().
* <li> Enable & disable write protect of the given PIOs using pio_enable_write_protect() or pio_disable_write_protect().
* <li> Get write protect violation information of given PIO using pio_get_write_protect_violation_info().
* </li>
* </ul>
*
* For more accurate information, please look at the PIT section of the Datasheet.
*
* Related files :\n
* \ref pio.c\n
* \ref pio3.h\n
*/
/*@{*/
/*@}*/
/**
* \file
*
* Implementation of PIO V3 (Parallel Input/Output) controller.
*
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include "peripherals/pio.h"
#include "peripherals/pmc.h"
#include "peripherals/aic.h"
#include "peripherals/matrix.h"
#include "trace.h"
#include "compiler.h"
#include <stdint.h>
#include <string.h>
#include <assert.h>
/*----------------------------------------------------------------------------
* Local types
*----------------------------------------------------------------------------*/
struct _bitfield_pio_cfgr_func {
uint32_t
func : 3,
rfu3_7 : 5,
dir : 1,
puen : 1,
pden : 1,
rfu11 : 1,
ifen : 1,
ifscen : 1,
opd : 1,
schmitt : 1,
drvstr : 2,
rfu18_23 : 6,
evtsel : 3,
rfu27_28 : 2,
pcfs : 1,
icfs : 1,
tampen : 1;
};
union _pio_cfg {
struct _bitfield_pio_cfgr_func bitfield;
uint32_t uint32_value;
};
/*----------------------------------------------------------------------------
* Local functions declarations
*----------------------------------------------------------------------------*/
#ifdef ID_PIOA
static void _pioa_handler(void);
#endif
#ifdef ID_PIOB
static void _piob_handler(void);
#endif
#ifdef ID_PIOC
static void _pioc_handler(void);
#endif
#ifdef ID_PIOD
static void _piod_handler(void);
#endif
/*----------------------------------------------------------------------------
* Local variables
*----------------------------------------------------------------------------*/
struct _handler {
uint32_t mask;
pio_handler_t handler;
void *user_arg;
};
static struct _handler _handlers[IRQ_PIO_HANDLERS_SIZE];
static const aic_handler_t _generic_handlers[PIO_GROUP_LENGTH] = {
#ifdef ID_PIOA
_pioa_handler,
#endif
#ifdef ID_PIOB
_piob_handler,
#endif
#ifdef ID_PIOC
_pioc_handler,
#endif
#ifdef ID_PIOD
_piod_handler,
#endif
};
/*----------------------------------------------------------------------------
* Local functions definitions
*----------------------------------------------------------------------------*/
static void _handler_push(void (*handler)(uint32_t, uint32_t, void*),
uint32_t mask, void* user_arg)
{
static int i = 0;
_handlers[i].mask = mask;
_handlers[i].handler = handler;
_handlers[i].user_arg = user_arg;
++i;
assert(i < ARRAY_SIZE(_handlers));
}
#ifdef ID_PIOA
static void _pioa_handler(void)
{
uint32_t status = 0;
unsigned int i = 0;
if (matrix_is_peripheral_secured(MATRIX1, ID_PIOA))
status = PIOA->PIO_PIO_[PIO_GROUP_A].S_PIO_ISR;
else
status = PIOA->PIO_IO_GROUP[PIO_GROUP_A].PIO_ISR;
for (i = 0; i < ARRAY_SIZE(_handlers); ++i) {
if (_handlers[i].mask & status) {
_handlers[i].handler(PIO_GROUP_A, status,
_handlers[i].user_arg);
}
}
}
#endif
#ifdef ID_PIOB
static void _piob_handler(void)
{
uint32_t status = 0;
unsigned int i = 0;
if (matrix_is_peripheral_secured(MATRIX1, ID_PIOB))
status = PIOA->PIO_PIO_[PIO_GROUP_B].S_PIO_ISR;
else
status = PIOA->PIO_IO_GROUP[PIO_GROUP_B].PIO_ISR;
for (i = 0; i < ARRAY_SIZE(_handlers); ++i) {
if (_handlers[i].mask & status) {
_handlers[i].handler(PIO_GROUP_B, status,
_handlers[i].user_arg);
}
}
}
#endif
#ifdef ID_PIOC
static void _pioc_handler(void)
{
uint32_t status = 0;
unsigned int i = 0;
if (matrix_is_peripheral_secured(MATRIX1, ID_PIOC))
status = PIOA->PIO_PIO_[PIO_GROUP_C].S_PIO_ISR;
else
status = PIOA->PIO_IO_GROUP[PIO_GROUP_C].PIO_ISR;
for (i = 0; i < ARRAY_SIZE(_handlers); ++i) {
if (_handlers[i].mask & status) {
_handlers[i].handler(PIO_GROUP_C, status,
_handlers[i].user_arg);
}
}
}
#endif
#ifdef ID_PIOD
static void _piod_handler(void)
{
uint32_t status = 0;
unsigned int i = 0;
if (matrix_is_peripheral_secured(MATRIX1, ID_PIOD))
status = PIOA->PIO_PIO_[PIO_GROUP_D].S_PIO_ISR;
else
status = PIOA->PIO_IO_GROUP[PIO_GROUP_D].PIO_ISR;
for (i = 0; i < ARRAY_SIZE(_handlers); ++i) {
if (_handlers[i].mask & status) {
_handlers[i].handler(PIO_GROUP_D, status,
_handlers[i].user_arg);
}
}
}
#endif
static inline uint32_t _pio_group_to_id(int group)
{
switch(group) {
case PIO_GROUP_A:
return ID_PIOA;
case PIO_GROUP_B:
return ID_PIOB;
case PIO_GROUP_C:
return ID_PIOC;
case PIO_GROUP_D:
return ID_PIOD;
default:
return (unsigned int)-1;
};
}
static void* _pio_configure_pins(const struct _pin *pin, uint32_t periph_id)
{
PioPio_* piogroup = &PIOA->PIO_PIO_[pin->group];
if (!matrix_is_peripheral_secured(MATRIX1, periph_id)) {
piogroup->S_PIO_SIONR = pin->mask;
return (void*) &PIOA->PIO_IO_GROUP[pin->group];
} else {
piogroup->S_PIO_SIOSR = pin->mask;
return (void*) piogroup;
}
}
static void* _pio_retrive_group(const struct _pin *pin, uint32_t periph_id)
{
if (!matrix_is_peripheral_secured(MATRIX1, periph_id)) {
return (void*) &PIOA->PIO_IO_GROUP[pin->group];
} else {
return (void*) &PIOA->PIO_PIO_[pin->group];
}
}
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/**
* \brief Configures a list of Pin instances, each of which can either
* hold a single pin or a group of pins, depending on the mask value;
* all pins are configured by this function. The size of the array
* must also be provided and is easily computed using ARRAY_SIZE
* whenever its length is not known in advance.
*
* \param list Pointer to a list of _pin instances.
* \param size Size of the _pin list (calculated using PIN_LISTSIZE).
*
* \return 1 if the pins have been configured properly; otherwise 0.
*/
uint8_t pio_configure(const struct _pin *pin_list, uint32_t size)
{
union _pio_cfg cfg;
PioIo_group* pioiog;
/* Configure pins */
while (size--)
{
/* Enable the PIO group if needed */
uint32_t periph_id = _pio_group_to_id(pin_list->group);
assert(pin_list->group < PIO_GROUP_LENGTH);
cfg.uint32_value = 0;
pioiog = (PioIo_group*) _pio_configure_pins(pin_list, periph_id);
if ( pin_list->attribute != PIO_DEFAULT) {
cfg.bitfield.puen = (pin_list->attribute & PIO_PULLUP)? 1:0;
cfg.bitfield.pden = (pin_list->attribute & PIO_PULLDOWN)? 1:0;
cfg.bitfield.ifen = (pin_list->attribute & PIO_DEGLITCH)? 1:0;
cfg.bitfield.ifscen = (pin_list->attribute & PIO_DEBOUNCE)? 1:0;
cfg.bitfield.opd = (pin_list->attribute & PIO_OPENDRAIN)? 1:0;
cfg.bitfield.schmitt =(pin_list->attribute & PIO_TRIGGER_DIS)? 1:0;
switch (pin_list->attribute & PIO_DRVSTR_Msk) {
case PIO_DRVSTR_HI:
cfg.bitfield.drvstr = PIO_CFGR_DRVSTR_HI >> PIO_CFGR_DRVSTR_Pos;
break;
case PIO_DRVSTR_ME:
cfg.bitfield.drvstr = PIO_CFGR_DRVSTR_ME >> PIO_CFGR_DRVSTR_Pos;
break;
case PIO_DRVSTR_LO:
default:
cfg.bitfield.drvstr = PIO_CFGR_DRVSTR_LO >> PIO_CFGR_DRVSTR_Pos;
break;
}
switch (pin_list->attribute & PIO_EVTSEL_Msk) {
case PIO_IT_HIGH_LEVEL:
cfg.bitfield.evtsel = PIO_CFGR_EVTSEL_HIGH >> PIO_CFGR_EVTSEL_Pos;
break;
case PIO_IT_LOW_LEVEL:
cfg.bitfield.evtsel = PIO_CFGR_EVTSEL_LOW >> PIO_CFGR_EVTSEL_Pos;
break;
case PIO_IT_BOTH_EDGE:
cfg.bitfield.evtsel = PIO_CFGR_EVTSEL_BOTH >> PIO_CFGR_EVTSEL_Pos;
break;
case PIO_IT_RISE_EDGE:
cfg.bitfield.evtsel = PIO_CFGR_EVTSEL_RISING >> PIO_CFGR_EVTSEL_Pos;
break;
case PIO_IT_FALL_EDGE:
default:
cfg.bitfield.evtsel = PIO_CFGR_EVTSEL_FALLING >> PIO_CFGR_EVTSEL_Pos;
break;
}
}
switch (pin_list->type){
case PIO_PERIPH_A:
cfg.bitfield.func = PIO_CFGR_FUNC_PERIPH_A >> PIO_CFGR_FUNC_Pos;
break;
case PIO_PERIPH_B:
cfg.bitfield.func = PIO_CFGR_FUNC_PERIPH_B >> PIO_CFGR_FUNC_Pos;
break;
case PIO_PERIPH_C:
cfg.bitfield.func = PIO_CFGR_FUNC_PERIPH_C >> PIO_CFGR_FUNC_Pos;
break;
case PIO_PERIPH_D:
cfg.bitfield.func = PIO_CFGR_FUNC_PERIPH_D >> PIO_CFGR_FUNC_Pos;
break;
case PIO_PERIPH_E:
cfg.bitfield.func = PIO_CFGR_FUNC_PERIPH_E >> PIO_CFGR_FUNC_Pos;
break;
case PIO_PERIPH_F:
cfg.bitfield.func = PIO_CFGR_FUNC_PERIPH_F >> PIO_CFGR_FUNC_Pos;
break;
case PIO_GENERIC:
case PIO_INPUT:
cfg.bitfield.dir = 0;
break;
case PIO_OUTPUT_0:
cfg.bitfield.dir = 1;
pio_clear(pin_list);
break;
case PIO_OUTPUT_1:
cfg.bitfield.dir = 1;
pio_set(pin_list);
break;
default:
case PIO_PERIPH_G:
return 0;
}
pioiog->PIO_MSKR = pin_list->mask;
pioiog->PIO_CFGR = cfg.uint32_value;
pmc_enable_peripheral(periph_id);
++pin_list;
}
return 1;
}
/**
* \brief Sets a high output level on all the PIOs defined in the
* given Pin instance. This has no immediate effects on PIOs that are
* not output, but the PIO controller will memorize the value they are
* changed to outputs.
*
* \param pin Pointer to a Pin instance describing one or more pins.
*/
void pio_set(const struct _pin *pin)
{
assert(pin->group < PIO_GROUP_LENGTH);
uint32_t periph_id = _pio_group_to_id(pin->group);
PioIo_group* pioiog = (PioIo_group*) _pio_retrive_group(pin, periph_id);
pioiog->PIO_SODR = pin->mask;
}
/**
* \brief Sets a low output level on all the PIOs defined in the given
* Pin instance. This has no immediate effects on PIOs that are not
* output, but the PIO controller will memorize the value they are
* changed to outputs.
*
* \param pin Pointer to a Pin instance describing one or more pins.
*/
void pio_clear(const struct _pin *pin)
{
assert(pin->group < PIO_GROUP_LENGTH);
uint32_t periph_id = _pio_group_to_id(pin->group);
PioIo_group* pioiog = (PioIo_group*) _pio_retrive_group(pin, periph_id);
pioiog->PIO_CODR = pin->mask;
}
/**
* \brief Returns 1 if one or more PIO of the given Pin instance currently have
* a high level; otherwise returns 0. This method returns the actual value that
* is being read on the pin. To return the supposed output value of a pin, use
* pio_get_output_date_status() instead.
*
* \param pin Pointer to a Pin instance describing one or more pins.
*
* \return 1 if the Pin instance contains at least one PIO that currently has
* a high level; otherwise 0.
*/
uint8_t pio_get(const struct _pin *pin)
{
assert(pin->group < PIO_GROUP_LENGTH);
uint32_t reg ;
uint32_t periph_id = _pio_group_to_id(pin->group);
PioIo_group* pioiog = (PioIo_group*) _pio_retrive_group(pin, periph_id);
if ((pin->type == PIO_OUTPUT_0) || (pin->type == PIO_OUTPUT_1)) {
reg = pioiog->PIO_ODSR ;
}
else {
reg = pioiog->PIO_PDSR ;
}
if ( (reg & pin->mask) == 0 ) {
return 0 ;
}
else {
return 1 ;
}
}
/**
* \brief Returns 1 if one or more PIO of the given Pin are configured
* to output a high level (even if they are not output). To get the
* actual value of the pin, use pio_get() instead.
*
* \param pin Pointer to a Pin instance describing one or more pins.
*
* \return 1 if the Pin instance contains at least one PIO that is configured
* to output a high level; otherwise 0.
*/
uint8_t pio_get_output_data_status(const struct _pin *pin)
{
assert(pin->group < PIO_GROUP_LENGTH);
uint32_t periph_id = _pio_group_to_id(pin->group);
PioIo_group* pioiog = (PioIo_group*) _pio_retrive_group(pin, periph_id);
if ((pioiog->PIO_ODSR & pin->mask) == 0) {
return 0;
}
else {
return 1;
}
}
/**
* \brief Configures Glitch or Debouncing filter for input.
*
* \param pin Pointer to a Pin instance describing one or more pins.
* \param cuttoff Cutt off frequency for debounce filter.
*/
void pio_set_debounce_filter(const struct _pin *pin, uint32_t cuttoff)
{
assert(pin->group < PIO_GROUP_LENGTH);
if (cuttoff == 0) {
PIOA->S_PIO_SCDR = 0;
}
else {
/* the lowest 14 bits work */
PIOA->S_PIO_SCDR =
((pmc_get_slow_clock()/(2*(cuttoff))) - 1) & 0x3FFF;
}
}
/**
* \brief Enable write protect.
*
* \param pin Pointer to a Pin instance describing one or more pins.
*/
void pio_enable_write_protect(const struct _pin *pin)
{
assert(pin->group < PIO_GROUP_LENGTH);
PIOA->PIO_WPMR = (PIO_WPMR_WPKEY_VALID | PIO_WPMR_WPEN_EN );
}
/**
* \brief Disable write protect.
*
* \param pin Pointer to a Pin instance describing one or more pins.
*/
void pio_disable_write_protect(const struct _pin *pin)
{
assert(pin->group < PIO_GROUP_LENGTH);
PIOA->PIO_WPMR = (PIO_WPMR_WPKEY_VALID | PIO_WPMR_WPEN_DIS );
}
/**
* \brief Get write protect violation information.
*
* \param pin Pointer to a Pin instance describing one or more pins.
*/
uint32_t pio_get_write_protect_violation_info(const struct _pin * pin)
{
assert(pin->group < PIO_GROUP_LENGTH);
return PIOA->PIO_WPSR;
}
void pio_add_handler_to_group(uint32_t group, uint32_t mask,
pio_handler_t handler, void* user_arg)
{
trace_debug("Enter in pio_add_handler_to_group()\n\r");
assert(group <
(sizeof(_generic_handlers)/sizeof(_generic_handlers[0])));
_handler_push(handler, mask, user_arg);
uint32_t id = _pio_group_to_id(group);
aic_set_source_vector(id,
(aic_handler_t)_generic_handlers[group]);
aic_enable(id);
}
void pio_reset_all_it(void)
{
int i = 0;
for (i = 0; i < PIO_GROUP_LENGTH; ++i) {
PIOA->PIO_IO_GROUP[i].PIO_ISR;
PIOA->PIO_IO_GROUP[i].PIO_IDR = ~0UL;
}
}
/**
* Configures a PIO or a group of PIO to generate an interrupt on status
* change. The provided interrupt handler will be called with the triggering
* pin as its parameter (enabling different pin instances to share the same
* handler).
* \param pin Pointer to a _pin instance.
*/
void pio_configure_it(const struct _pin *pin)
{
trace_debug("Enter in pio_configure_it()\n\r");
assert(pin != NULL);
}
/**
* Enables the given interrupt source if it has been configured. The status
* register of the corresponding PIO controller is cleared prior to enabling
* the interrupt.
* \param pin Interrupt source to enable.
*/
void pio_enable_it(const struct _pin *pin)
{
trace_debug("pio_enable_it() \n\r");
assert(pin != NULL);
uint32_t periph_id = _pio_group_to_id(pin->group);
PioIo_group* pioiog = (PioIo_group*) _pio_retrive_group(pin, periph_id);
pioiog->PIO_ISR;
/* Configure interrupt enable register */
pioiog->PIO_IER = pin->mask; /* enable interrupt register */
}
/**
* Disables a given interrupt source, with no added side effects.
*
* \param pin Interrupt source to disable.
*/
void pio_disable_it(const struct _pin *pin)
{
trace_debug("pio_enable_it()\n\r");
assert(pin != NULL);
uint32_t periph_id = _pio_group_to_id(pin->group);
PioIo_group* pioiog = (PioIo_group*) _pio_retrive_group(pin, periph_id);
pioiog->PIO_IDR = pin->mask;
}

View file

@ -0,0 +1,164 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* \section Purpose
*
* This file provides a basic API for PIO configuration and usage of
* user-controlled pins. Please refer to the board.h file for a list of
* available pin definitions.
*
* \section Usage
*
* -# Define a constant pin description array such as the following one, using
* the existing definitions provided by the board.h file if possible:
* \code
* const struct _pin pins[] = {PIN_USART0_TXD, PIN_USART0_RXD};
* \endcode
* Alternatively, it is possible to add new pins by provided the full Pin
* structure:
* \code
* // Pin instance to configure PA10 & PA11 as inputs with the internal
* // pull-up enabled.
* const Pin pins = {
* (1 << 10) | (1 << 11),
* REG_PIOA,
* ID_PIOA,
* PIO_INPUT,
* PIO_PULLUP
* };
* \endcode
* -# Configure a pin array by calling pio_configure() with a pointer to the
* array and its size (which is computed using the ARRAY_SIZE macro).
* -# Change and get the value of a user-controlled pin using the pio_set,
* pio_clear and pio_get methods.
* -# Get the level being currently output by a user-controlled pin configured
* as an output using pio_get_output_date_status().
*/
#ifndef _PIO_H
#error "pio3.h cannot be included. pio.h should be used instead"
#endif
#ifndef _PIO4_H
#define _PIO4_H
/*------------------------------------------------------------------------------
* Headers
*------------------------------------------------------------------------------*/
#include "chip.h"
#include <stdint.h>
/*------------------------------------------------------------------------------
* Definitions
*------------------------------------------------------------------------------*/
/* The IO group is A (or 0) */
#define PIO_GROUP_A 0
/* The IO group is B (or 1) */
#define PIO_GROUP_B 1
/* The IO group is C (or 2) */
#define PIO_GROUP_C 2
/* The IO group is D (or 3) */
#define PIO_GROUP_D 3
#define PIO_GROUP_LENGTH PIOIO_GROUP_NUMBER
/* The pin is controlled by the generic PIO. */
#define PIO_GENERIC 0
/* The pin is controlled by the associated signal of peripheral A. */
#define PIO_PERIPH_A 1
/* The pin is controlled by the associated signal of peripheral B. */
#define PIO_PERIPH_B 2
/* The pin is controlled by the associated signal of peripheral C. */
#define PIO_PERIPH_C 3
/* The pin is controlled by the associated signal of peripheral D. */
#define PIO_PERIPH_D 4
/* The pin is controlled by the associated signal of peripheral E. */
#define PIO_PERIPH_E 5
/* The pin is controlled by the associated signal of peripheral F. */
#define PIO_PERIPH_F 6
/* The pin is controlled by the associated signal of peripheral G. */
#define PIO_PERIPH_G 7
/* The pin is an input. */
#define PIO_INPUT 10
/* The pin is an output. */
#define PIO_OUTPUT 11
/* The pin is an output and has a default level of 0. */
#define PIO_OUTPUT_0 11
/* The pin is an output and has a default level of 1. */
#define PIO_OUTPUT_1 12
/* Default pin configuration (no attribute). */
#define PIO_DEFAULT (0x0u << 0)
/* The internal pin pull-up is active. */
#define PIO_PULLUP (0x1u << 0)
/* The internal pin pull-down is active. */
#define PIO_PULLDOWN (0x1u << 1)
/* The pin is open-drain. */
#define PIO_OPENDRAIN (0x1u << 2)
/* The internal glitch filter is active. */
#define PIO_DEGLITCH (0x1u << 3)
/* The internal Debounce filter is active. */
#define PIO_DEBOUNCE (0x1u << 4)
/* The internal Schmitt trigger is disable. */
#define PIO_TRIGGER_DIS (0x1u << 5)
/* Drive Strength. */
#define PIO_DRVSTR_Pos 10
#define PIO_DRVSTR_Msk (0x3u << 10)
#define PIO_DRVSTR_HI (0x2u << 10) /* High drive */
#define PIO_DRVSTR_ME (0x1u << 10) /* Medium drive */
#define PIO_DRVSTR_LO (0x0u << 10) /* Low drive */
#define PIO_EVTSEL_Pos 12
#define PIO_EVTSEL_Msk (0x7u << 12)
/* Event detection on input falling edge. */
#define PIO_IT_FALL_EDGE (0x0u << 12)
/* Event detection on input rising edge. */
#define PIO_IT_RISE_EDGE (0x1u << 12)
/* Event detection on input both edge. */
#define PIO_IT_BOTH_EDGE (0x2u << 12)
/* Event detection on low level input. */
#define PIO_IT_LOW_LEVEL (0x3u << 12)
/*Event detection on high level input. */
#define PIO_IT_HIGH_LEVEL (0x4u << 12)
#define PIO_WPMR_WPEN_EN ( 0x01 << 0 )
#define PIO_WPMR_WPEN_DIS ( 0x00 << 0 )
#define PIO_WPMR_WPKEY_VALID ( 0x50494F << 8 )
#endif /* #ifndef _PIO4_H */

View file

@ -0,0 +1,128 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/** \addtogroup pit_module Working with PIT
* \section Purpose
* The PIT driver provides the Interface for configuration the Periodic
* Interval Timer (PIT) peripheral.
*
* \section Usage
* <ul>
* <li> Initialize the PIT with the desired period using pit_init().
* Alternatively, the Periodic Interval Value (PIV) can be configured
* manually using pit_set_piv(). </li>
* <li> Start the PIT counting using pit_enable().
* <li> Enable & disable the PIT interrupt using pit_enable_it() and
* pit_disable_it(). </li>
* <li> Retrieve the current status of the PIT using pit_get_status(). </li>
* <li> To get the current value of the internal counter and the number of ticks
* that have occurred, use either pit_get_pivr() or pit_get_piir() depending
* on whether you want the values to be cleared or not. </li>
*
* </ul>
* For more accurate information, please look at the PIT section of the
* Datasheet.
*
* Related files :\n
* \ref pit.c\n
* \ref pit.h.\n
*/
/*@{*/
/*@}*/
/**
* \file
*
* Implementation of PIT (Periodic Interval Timer) controller.
*
*/
/*------------------------------------------------------------------------------
* Headers
*------------------------------------------------------------------------------*/
#include "chip.h"
#include "peripherals/pit.h"
#include "peripherals/pmc.h"
/*------------------------------------------------------------------------------
* Exported functions
*------------------------------------------------------------------------------*/
void pit_init(uint32_t period)
{
uint32_t pit_frequency = pmc_get_peripheral_clock(ID_PIT) / 1000000;
PIT->PIT_MR = period ? (period * pit_frequency + 8) >> 4 : 0;
PIT->PIT_MR |= PIT_MR_PITEN;
}
void pit_set_piv(uint32_t piv)
{
uint32_t dwMr = PIT->PIT_MR & (~PIT_MR_PIV_Msk);
PIT->PIT_MR = dwMr | PIT_MR_PIV(piv);
}
void pit_enable(void)
{
PIT->PIT_MR |= PIT_MR_PITEN;
}
void pit_disable(void)
{
PIT->PIT_MR &= ~PIT_MR_PITEN;
}
void pit_enable_it(void)
{
PIT->PIT_MR |= PIT_MR_PITIEN;
}
void pit_disable_it(void)
{
PIT->PIT_MR &= ~PIT_MR_PITIEN;
}
uint32_t pit_get_mode(void)
{
return PIT->PIT_MR;
}
uint32_t pit_get_status(void)
{
return PIT->PIT_SR;
}
uint32_t pit_get_piir(void)
{
return PIT->PIT_PIIR;
}
uint32_t pit_get_pivr(void)
{
return PIT->PIT_PIVR;
}

View file

@ -0,0 +1,121 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2011, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
#ifndef _PIT_H_
#define _PIT_H_
/*------------------------------------------------------------------------------
* Headers
*------------------------------------------------------------------------------*/
#include <stdint.h>
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Initialize the Periodic Interval Timer to generate a tick at the
* specified period, given the current master clock frequency.
*
* \param period Period in micro seconds.
*/
extern void pit_init(uint32_t period);
/**
* \brief Set the Periodic Interval Value of the PIT.
*
* \param piv PIV value to set.
*/
extern void pit_set_piv(uint32_t piv);
/**
* \brief Enables the PIT if this is not already the case.
*
*/
extern void pit_enable(void);
/**
* \brief Disnables the PIT when PIV value is reached.
*
*/
extern void pit_disable(void);
/**
* \brief Enable the PIT periodic interrupt.
*
*/
extern void pit_enable_it(void);
/**
* \brief Disables the PIT periodic interrupt.
*
*/
extern void pit_disable_it(void);
/**
* \brief Returns the value of the PIT mode register.
*
* \return PIT_MR value.
*/
extern uint32_t pit_get_mode(void);
/**
* \brief Returns the value of the PIT status register, clearing it as
* a side effect.
*
* \return PIT_SR value.
*/
extern uint32_t pit_get_status(void);
/**
* \brief Returns the value of the PIT Image Register, to read PICNT
* and CPIV without clearing the current values.
*
* \return PIT_PIIR value.
*/
extern uint32_t pit_get_piir(void);
/**
* \brief Returns the value of the PIT Value Register, clearing it as
* a side effect.
*
* \return PITC_PIVR value.
*/
extern uint32_t pit_get_pivr(void);
#ifdef __cplusplus
}
#endif
#endif /* #ifndef _PIT_H_ */

View file

@ -0,0 +1,978 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/** \addtogroup pmc_module Working with PMC
* \section Purpose
* The PMC driver provides the Interface for configuration the Power Management
* Controller (PMC).
*
* \section Usage
* <ul>
* <li> Enable & disable peripherals using pmc_enable_peripheral() and
* pmc_enable_all_peripherals() or pmc_disable_peripheral() and
* pmc_disable_all_peripherals().
* <li> Get & set maximum frequency clock for giving peripheral using
* pmc_get_peri_max_freq() and pmc_set_peri_max_clock().
* <li> Get Peripheral Status for the given peripheral using pmc_is_periph_enabled()
* <li> Select clocks's source using pmc_select_external_crystal(),
* pmc_select_internal_crystal(), pmc_select_external_osc() and pmc_select_internal_osc().
* <li> Switch MCK using pmc_switch_mck_to_pll(), pmc_switch_mck_to_main() and
* pmc_switch_mck_to_slck().
* <li> Config PLL using pmc_set_pll_a() and pmc_disable_pll_a().
* </li>
* </ul>
* For more accurate information, please look at the PMC section of the
* Datasheet.
*
* Related files :\n
* \ref pmc.c\n
* \ref pmc.h\n
*/
/*@{*/
/*@}*/
/**
* \file
*
* Implementation of PIO (Parallel Input/Output) controller.
*
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include "board.h"
#include "peripherals/pmc.h"
#include "trace.h"
#include <assert.h>
/*----------------------------------------------------------------------------
* Variables
*----------------------------------------------------------------------------*/
static uint32_t _pmc_mck = 0;
/*----------------------------------------------------------------------------
* Private functions
*----------------------------------------------------------------------------*/
static void _pmc_compute_mck(void)
{
uint32_t clk = 0;
uint32_t mckr = PMC->PMC_MCKR;
uint32_t css = mckr & PMC_MCKR_CSS_Msk;
switch (css) {
case PMC_MCKR_CSS_SLOW_CLK:
clk = pmc_get_slow_clock();
break;
case PMC_MCKR_CSS_MAIN_CLK:
clk = pmc_get_main_clock();
break;
case PMC_MCKR_CSS_PLLA_CLK:
clk = pmc_get_plla_clock();
break;
case PMC_MCKR_CSS_UPLL_CLK:
clk = pmc_get_upll_clock();
break;
default:
/* should never get here... */
break;
}
uint32_t pres = mckr & PMC_MCKR_PRES_Msk;
switch (pres) {
case PMC_MCKR_PRES_CLOCK:
break;
case PMC_MCKR_PRES_CLOCK_DIV2:
clk >>= 1;
break;
case PMC_MCKR_PRES_CLOCK_DIV4:
clk >>= 2;
break;
case PMC_MCKR_PRES_CLOCK_DIV8:
clk >>= 3;
break;
case PMC_MCKR_PRES_CLOCK_DIV16:
clk >>= 4;
break;
case PMC_MCKR_PRES_CLOCK_DIV32:
clk >>= 5;
break;
case PMC_MCKR_PRES_CLOCK_DIV64:
clk >>= 6;
break;
default:
/* should never get here... */
break;
}
uint32_t mdiv = mckr & PMC_MCKR_MDIV_Msk;
switch (mdiv) {
case PMC_MCKR_MDIV_EQ_PCK:
break;
case PMC_MCKR_MDIV_PCK_DIV2:
clk >>= 1; // divide by 2
break;
case PMC_MCKR_MDIV_PCK_DIV4:
clk >>= 2; // divide by 4
break;
case PMC_MCKR_MDIV_PCK_DIV3:
clk /= 3; // divide by 3
break;
default:
/* should never get here... */
break;
}
_pmc_mck = clk;
}
static uint32_t _pmc_get_pck_clock(uint32_t index)
{
uint32_t clk = 0;
uint32_t pck = PMC->PMC_PCK[index];
switch (pck & PMC_PCK_CSS_Msk) {
case PMC_PCK_CSS_SLOW_CLK:
clk = pmc_get_slow_clock();
break;
case PMC_PCK_CSS_MAIN_CLK:
clk = pmc_get_main_clock();
break;
case PMC_PCK_CSS_PLLA_CLK:
clk = pmc_get_plla_clock();
break;
case PMC_PCK_CSS_UPLL_CLK:
clk = pmc_get_upll_clock();
break;
case PMC_PCK_CSS_MCK_CLK:
clk = pmc_get_master_clock();
break;
#ifdef CONFIG_HAVE_PMC_AUDIO_CLOCK
case PMC_PCK_CSS_AUDIO_CLK:
clk = pmc_get_audio_pmc_clock();
break;
#endif
}
uint32_t prescaler = (pck & PMC_PCK_PRES_Msk) >> PMC_PCK_PRES_Pos;
return clk / (prescaler + 1);
}
static bool _pmc_get_system_clock_bits(enum _pmc_system_clock clock,
uint32_t *scer, uint32_t* scdr, uint32_t *scsr)
{
uint32_t e, d, s;
switch (clock)
{
#ifdef PMC_SCDR_PCK
case PMC_SYSTEM_CLOCK_PCK:
e = 0;
d = PMC_SCDR_PCK;
s = PMC_SCSR_PCK;
break;
#endif
case PMC_SYSTEM_CLOCK_DDR:
e = PMC_SCER_DDRCK;
d = PMC_SCDR_DDRCK;
s = PMC_SCSR_DDRCK;
break;
case PMC_SYSTEM_CLOCK_LCD:
e = PMC_SCER_LCDCK;
d = PMC_SCDR_LCDCK;
s = PMC_SCSR_LCDCK;
break;
#ifdef PMC_SCER_SMDCK
case PMC_SYSTEM_CLOCK_SMD:
e = PMC_SCER_SMDCK;
d = PMC_SCDR_SMDCK;
s = PMC_SCSR_SMDCK;
break;
#endif
case PMC_SYSTEM_CLOCK_UHP:
e = PMC_SCER_UHP;
d = PMC_SCDR_UHP;
s = PMC_SCSR_UHP;
break;
case PMC_SYSTEM_CLOCK_UDP:
e = PMC_SCER_UDP;
d = PMC_SCDR_UDP;
s = PMC_SCSR_UDP;
break;
case PMC_SYSTEM_CLOCK_PCK0:
e = PMC_SCER_PCK0;
d = PMC_SCDR_PCK0;
s = PMC_SCSR_PCK0;
break;
case PMC_SYSTEM_CLOCK_PCK1:
e = PMC_SCER_PCK1;
d = PMC_SCDR_PCK1;
s = PMC_SCSR_PCK1;
break;
case PMC_SYSTEM_CLOCK_PCK2:
e = PMC_SCER_PCK2;
d = PMC_SCDR_PCK2;
s = PMC_SCSR_PCK2;
break;
#ifdef PMC_SCER_ISCCK
case PMC_SYSTEM_CLOCK_ISC:
e = PMC_SCER_ISCCK;
d = PMC_SCDR_ISCCK;
s = PMC_SCSR_ISCCK;
break;
#endif
default:
return false;
}
if (scer) {
if (e)
*scer = e;
else
return false;
}
if (scdr) {
if (d)
*scdr = d;
else
return false;
}
if (scsr) {
if (s)
*scsr = s;
else
return false;
}
return true;
}
/*----------------------------------------------------------------------------
* Exported functions (General)
*----------------------------------------------------------------------------*/
uint32_t pmc_get_master_clock(void)
{
if (!_pmc_mck) {
_pmc_compute_mck();
}
return _pmc_mck;
}
uint32_t pmc_get_slow_clock(void)
{
if (SCKC->SCKC_CR & SCKC_CR_OSCSEL)
return SLOW_CLOCK_INT_OSC; /* on-chip slow clock RC */
else
return BOARD_SLOW_CLOCK_EXT_OSC; /* external crystal */
}
uint32_t pmc_get_main_clock(void)
{
if (PMC->CKGR_MOR & CKGR_MOR_MOSCSEL)
return MAIN_CLOCK_INT_OSC; /* on-chip main clock RC */
else
return BOARD_MAIN_CLOCK_EXT_OSC; /* external crystal */
}
uint32_t pmc_get_plla_clock(void)
{
uint32_t pllaclk, pllar, pllmula, plldiva;
if (PMC->CKGR_MOR & CKGR_MOR_MOSCSEL)
pllaclk = MAIN_CLOCK_INT_OSC; /* on-chip main clock RC */
else
pllaclk = BOARD_MAIN_CLOCK_EXT_OSC; /* external crystal */
pllar = PMC->CKGR_PLLAR;
pllmula = (pllar & CKGR_PLLAR_MULA_Msk) >> CKGR_PLLAR_MULA_Pos;
plldiva = (pllar & CKGR_PLLAR_DIVA_Msk) >> CKGR_PLLAR_DIVA_Pos;
if (plldiva == 0 || pllmula == 0) {
pllaclk = 0;
} else {
pllaclk = pllaclk * (pllmula + 1) / plldiva;
if (PMC->PMC_MCKR & PMC_MCKR_PLLADIV2)
pllaclk >>= 1;
}
return pllaclk;
}
uint32_t pmc_get_processor_clock(void)
{
uint32_t procclk, mdiv;
procclk = pmc_get_master_clock();
mdiv = PMC->PMC_MCKR & PMC_MCKR_MDIV_Msk;
switch (mdiv) {
case PMC_MCKR_MDIV_EQ_PCK:
break;
case PMC_MCKR_MDIV_PCK_DIV2:
procclk <<= 1; // multiply by 2
break;
case PMC_MCKR_MDIV_PCK_DIV3:
procclk *= 3; // multiply by 3
break;
case PMC_MCKR_MDIV_PCK_DIV4:
procclk <<= 2; // multiply by 4
break;
default:
/* should never get here... */
break;
}
return procclk;
}
void pmc_select_external_crystal(void)
{
int return_to_sclock = 0;
if (PMC->PMC_MCKR == PMC_MCKR_CSS(PMC_MCKR_CSS_SLOW_CLK)) {
pmc_switch_mck_to_main();
return_to_sclock = 1;
}
/* switch from internal RC 32kHz to external OSC 32 kHz */
SCKC->SCKC_CR = (SCKC->SCKC_CR & ~SCKC_CR_OSCSEL) | SCKC_CR_OSCSEL_XTAL;
/* Wait 5 slow clock cycles for internal resynchronization */
volatile int count;
for (count = 0; count < 0x1000; count++);
/* Switch to slow clock again if needed */
if (return_to_sclock)
pmc_switch_mck_to_slck();
}
void pmc_select_internal_crystal(void)
{
int return_to_sclock = 0;
if (PMC->PMC_MCKR == PMC_MCKR_CSS(PMC_MCKR_CSS_SLOW_CLK)) {
pmc_switch_mck_to_main();
return_to_sclock = 1;
}
/* switch from extenal OSC 32kHz to internal RC 32 kHz */
/* switch slow clock source to internal OSC 32 kHz */
SCKC->SCKC_CR = (SCKC->SCKC_CR & ~SCKC_CR_OSCSEL) | SCKC_CR_OSCSEL_RC;
/* Wait 5 slow clock cycles for internal resynchronization */
volatile int count;
for (count = 0; count < 0x1000; count++);
/* Switch to slow clock again if needed */
if (return_to_sclock)
pmc_switch_mck_to_slck();
}
void pmc_select_external_osc(void)
{
/* Enable external osc 12 MHz when needed */
if ((PMC->CKGR_MOR & CKGR_MOR_MOSCXTEN) != CKGR_MOR_MOSCXTEN) {
PMC->CKGR_MOR |= CKGR_MOR_MOSCXTST(18) | CKGR_MOR_MOSCXTEN | CKGR_MOR_KEY_PASSWD;
/* Wait Main Oscillator ready */
while(!(PMC->PMC_SR & PMC_SR_MOSCXTS));
}
/* Return if external osc had been selected */
if ((PMC->CKGR_MOR & CKGR_MOR_MOSCSEL) == CKGR_MOR_MOSCSEL)
return;
/* switch MAIN clock to external OSC 12 MHz */
PMC->CKGR_MOR |= CKGR_MOR_MOSCSEL | CKGR_MOR_KEY_PASSWD;
/* wait for the command to be taken into account */
while ((PMC->CKGR_MOR & CKGR_MOR_MOSCSEL) != CKGR_MOR_MOSCSEL);
/* wait MAIN clock status change for external OSC 12 MHz selection */
while (!(PMC->PMC_SR & PMC_SR_MOSCSELS));
/* disable internal RC 12 MHz to save power */
pmc_disable_internal_osc();
}
void pmc_disable_external_osc(void)
{
/* disable external OSC 12 MHz */
PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCXTEN) | CKGR_MOR_KEY_PASSWD;
}
void pmc_select_internal_osc(void)
{
#ifdef CKGR_MOR_MOSCRCEN
/* Enable internal RC 12 MHz when needed */
if ((PMC->CKGR_MOR & CKGR_MOR_MOSCRCEN) != CKGR_MOR_MOSCRCEN) {
PMC->CKGR_MOR |= CKGR_MOR_MOSCRCEN | CKGR_MOR_KEY_PASSWD;
/* Wait internal 12 MHz RC Startup Time for clock stabilization */
while (!(PMC->PMC_SR & PMC_SR_MOSCRCS));
}
#endif
/* switch MAIN clock to internal RC 12 MHz */
PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCSEL) | CKGR_MOR_KEY_PASSWD;
/* in case where MCK is running on MAIN CLK */
while (!(PMC->PMC_SR & PMC_SR_MCKRDY));
/* disable external OSC 12 MHz to save power*/
pmc_disable_external_osc();
}
void pmc_disable_internal_osc(void)
{
#ifdef CKGR_MOR_MOSCRCEN
/* disable internal RC 12 MHz */
PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCRCEN) | CKGR_MOR_KEY_PASSWD;
#endif
}
void pmc_switch_mck_to_pll(void)
{
/* Select PLL as input clock for PCK and MCK */
PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_PLLA_CLK;
while (!(PMC->PMC_SR & PMC_SR_MCKRDY));
_pmc_mck = 0;
}
void pmc_switch_mck_to_upll(void)
{
/* Select UPLL as input clock for PCK and MCK */
PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_UPLL_CLK;
while (!(PMC->PMC_SR & PMC_SR_MCKRDY));
_pmc_mck = 0;
}
void pmc_switch_mck_to_main(void)
{
/* Select Main Oscillator as input clock for PCK and MCK */
PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk) | PMC_PCK_CSS_MAIN_CLK;
while (!(PMC->PMC_SR & PMC_SR_MCKRDY));
_pmc_mck = 0;
}
void pmc_switch_mck_to_slck(void)
{
/* Select Slow Clock as input clock for PCK and MCK */
PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk) | PMC_PCK_CSS_SLOW_CLK;
while (!(PMC->PMC_SR & PMC_SR_MCKRDY));
_pmc_mck = 0;
}
void pmc_set_mck_prescaler(uint32_t prescaler)
{
/* Change MCK Prescaler divider in PMC_MCKR register */
PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_PRES_Msk) | prescaler;
while (!(PMC->PMC_SR & PMC_SR_MCKRDY));
}
void pmc_set_mck_plla_div(uint32_t divider)
{
if ((PMC->PMC_MCKR & PMC_MCKR_PLLADIV2) == PMC_MCKR_PLLADIV2) {
if (divider == 0) {
PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_PLLADIV2);
}
} else {
if (divider == PMC_MCKR_PLLADIV2) {
PMC->PMC_MCKR = (PMC->PMC_MCKR | PMC_MCKR_PLLADIV2);
}
}
while (!(PMC->PMC_SR & PMC_SR_MCKRDY));
}
void pmc_set_mck_h32mxdiv(uint32_t divider)
{
if ((PMC->PMC_MCKR & PMC_MCKR_H32MXDIV) == PMC_MCKR_H32MXDIV_H32MXDIV2) {
if (divider == PMC_MCKR_H32MXDIV_H32MXDIV1) {
PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_H32MXDIV);
}
} else {
if (divider == PMC_MCKR_H32MXDIV_H32MXDIV2) {
PMC->PMC_MCKR = (PMC->PMC_MCKR | PMC_MCKR_H32MXDIV_H32MXDIV2);
}
}
while (!(PMC->PMC_SR & PMC_SR_MCKRDY));
}
void pmc_set_mck_divider(uint32_t divider)
{
/* change MCK Prescaler divider in PMC_MCKR register */
PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_MDIV_Msk) | divider;
while (!(PMC->PMC_SR & PMC_SR_MCKRDY));
}
void pmc_set_plla(uint32_t pll, uint32_t cpcr)
{
PMC->CKGR_PLLAR = pll;
PMC->PMC_PLLICPR = cpcr;
if ((pll & CKGR_PLLAR_DIVA_Msk) != CKGR_PLLAR_DIVA_0) {
while (!(PMC->PMC_SR & PMC_SR_LOCKA));
}
}
void pmc_disable_plla(void)
{
PMC->CKGR_PLLAR = (PMC->CKGR_PLLAR & ~CKGR_PLLAR_MULA_Msk) | CKGR_PLLAR_MULA(0);
}
void pmc_enable_system_clock(enum _pmc_system_clock clock)
{
uint32_t scer, scsr;
if (!_pmc_get_system_clock_bits(clock, &scer, NULL, &scsr))
return;
PMC->PMC_SCER |= scer;
while (!(PMC->PMC_SCSR & scsr));
}
void pmc_disable_system_clock(enum _pmc_system_clock clock)
{
uint32_t scdr, scsr;
if (!_pmc_get_system_clock_bits(clock, NULL, &scdr, &scsr))
return;
PMC->PMC_SCDR |= scdr;
while (PMC->PMC_SCSR & scsr);
}
#ifdef CONFIG_HAVE_PMC_FAST_STARTUP
void pmc_set_fast_startup_mode(uint32_t startup_mode)
{
PMC->PMC_FSMR = startup_mode;
}
void pmc_set_fast_startup_polarity(uint32_t high_level, uint32_t low_level)
{
PMC->PMC_FSPR &= ~low_level;
PMC->PMC_FSPR |= high_level;
}
#endif /* CONFIG_HAVE_PMC_FAST_STARTUP */
void pmc_set_custom_pck_mck(struct pck_mck_cfg *cfg)
{
pmc_switch_mck_to_slck();
if (cfg->ext12m)
pmc_select_external_osc();
else
pmc_select_internal_osc();
pmc_switch_mck_to_main();
if (cfg->ext32k)
pmc_select_external_crystal();
else
pmc_select_internal_crystal();
pmc_set_mck_prescaler(cfg->pck_pres);
pmc_set_mck_divider(cfg->mck_div);
pmc_set_mck_plla_div(cfg->plla_div2 ? PMC_MCKR_PLLADIV2 : 0);
if (cfg->plla_mul > 0) {
pmc_disable_plla();
uint32_t tmp = CKGR_PLLAR_ONE |
CKGR_PLLAR_PLLACOUNT(0x3F) |
CKGR_PLLAR_OUTA(0x0) |
CKGR_PLLAR_MULA(cfg->plla_mul) |
CKGR_PLLAR_DIVA(cfg->plla_div);
pmc_set_plla(tmp, PMC_PLLICPR_IPLL_PLLA(0x3));
} else {
pmc_disable_plla();
}
if (cfg->h32mxdiv2)
pmc_set_mck_h32mxdiv(PMC_MCKR_H32MXDIV_H32MXDIV2);
else
pmc_set_mck_h32mxdiv(PMC_MCKR_H32MXDIV_H32MXDIV1);
switch (cfg->pck_input) {
case PMC_MCKR_CSS_PLLA_CLK:
pmc_switch_mck_to_pll();
break;
case PMC_MCKR_CSS_UPLL_CLK:
pmc_switch_mck_to_upll();
break;
case PMC_MCKR_CSS_SLOW_CLK:
pmc_switch_mck_to_slck();
pmc_disable_internal_osc();
pmc_disable_external_osc();
break;
}
}
/*----------------------------------------------------------------------------
* Exported functions (Peripherals)
*----------------------------------------------------------------------------*/
void pmc_enable_peripheral(uint32_t id)
{
assert(id > 1 && id < ID_PERIPH_COUNT);
PMC->PMC_PCR = PMC_PCR_PID(id);
volatile uint32_t pcr = PMC->PMC_PCR;
PMC->PMC_PCR = pcr | PMC_PCR_CMD | PMC_PCR_EN;
}
void pmc_disable_peripheral(uint32_t id)
{
assert(id > 1 && id < ID_PERIPH_COUNT);
PMC->PMC_PCR = PMC_PCR_PID(id);
volatile uint32_t pcr = PMC->PMC_PCR;
PMC->PMC_PCR = PMC_PCR_CMD | (pcr & ~PMC_PCR_EN);
}
uint32_t pmc_is_peripheral_enabled(uint32_t id)
{
assert(id > 1 && id < ID_PERIPH_COUNT);
PMC->PMC_PCR = PMC_PCR_PID(id);
volatile uint32_t pcr = PMC->PMC_PCR;
return !!(pcr & PMC_PCR_EN);
}
uint32_t pmc_get_peripheral_clock(uint32_t id)
{
assert(id > 1 && id < ID_PERIPH_COUNT);
uint32_t div = get_peripheral_clock_divider(id);
if (div)
return pmc_get_master_clock() / div;
return 0;
}
void pmc_disable_all_peripherals(void)
{
int i;
for (i = 2; i < ID_PERIPH_COUNT; i++)
pmc_disable_peripheral(i);
}
/*----------------------------------------------------------------------------
* Exported functions (PCK0-2)
*----------------------------------------------------------------------------*/
void pmc_configure_pck0(uint32_t clock_source, uint32_t prescaler)
{
pmc_disable_pck0();
PMC->PMC_PCK[0] = (clock_source & PMC_PCK_CSS_Msk) | PMC_PCK_PRES(prescaler);
}
void pmc_enable_pck0(void)
{
PMC->PMC_SCER = PMC_SCER_PCK0;
while (!(PMC->PMC_SR & PMC_SR_PCKRDY0));
}
void pmc_disable_pck0(void)
{
PMC->PMC_SCDR = PMC_SCDR_PCK0;
while (PMC->PMC_SCSR & PMC_SCSR_PCK0);
}
uint32_t pmc_get_pck0_clock(void)
{
return _pmc_get_pck_clock(0);
}
void pmc_configure_pck1(uint32_t clock_source, uint32_t prescaler)
{
pmc_disable_pck1();
PMC->PMC_PCK[1] = (clock_source & PMC_PCK_CSS_Msk) | PMC_PCK_PRES(prescaler);
}
void pmc_enable_pck1(void)
{
PMC->PMC_SCER = PMC_SCER_PCK1;
while (!(PMC->PMC_SR & PMC_SR_PCKRDY1));
}
void pmc_disable_pck1(void)
{
PMC->PMC_SCDR = PMC_SCDR_PCK1;
while (PMC->PMC_SCSR & PMC_SCSR_PCK1);
}
uint32_t pmc_get_pck1_clock(void)
{
return _pmc_get_pck_clock(1);
}
void pmc_configure_pck2(uint32_t clock_source, uint32_t prescaler)
{
pmc_disable_pck2();
PMC->PMC_PCK[2] = (clock_source & PMC_PCK_CSS_Msk) | PMC_PCK_PRES(prescaler);
}
void pmc_enable_pck2(void)
{
PMC->PMC_SCER = PMC_SCER_PCK2;
while (!(PMC->PMC_SR & PMC_SR_PCKRDY2));
}
void pmc_disable_pck2(void)
{
PMC->PMC_SCDR = PMC_SCDR_PCK2;
while (PMC->PMC_SCSR & PMC_SCSR_PCK2);
}
uint32_t pmc_get_pck2_clock(void)
{
return _pmc_get_pck_clock(2);
}
/*----------------------------------------------------------------------------
* Exported functions (UPLL)
*----------------------------------------------------------------------------*/
void pmc_enable_upll_clock(void)
{
/* enable 480Mhz UPLL */
PMC->CKGR_UCKR = CKGR_UCKR_UPLLEN | CKGR_UCKR_UPLLCOUNT(0x3)
| CKGR_UCKR_BIASCOUNT(0x1);
/* wait until UPLL is locked */
while (!(PMC->PMC_SR & PMC_SR_LOCKU));
}
void pmc_disable_upll_clock(void)
{
PMC->CKGR_UCKR &= ~CKGR_UCKR_UPLLEN;
}
uint32_t pmc_get_upll_clock(void)
{
#ifdef SFR_UTMICKTRIM_FREQ_Msk
uint32_t clktrim = SFR->SFR_UTMICKTRIM & SFR_UTMICKTRIM_FREQ_Msk;
switch (clktrim) {
case SFR_UTMICKTRIM_FREQ_16:
return 30 * BOARD_MAIN_CLOCK_EXT_OSC;
case SFR_UTMICKTRIM_FREQ_24:
return 20 * BOARD_MAIN_CLOCK_EXT_OSC;
default:
return 40 * BOARD_MAIN_CLOCK_EXT_OSC;
}
#else
return 40 * BOARD_MAIN_CLOCK_EXT_OSC;
#endif
}
void pmc_enable_upll_bias(void)
{
PMC->CKGR_UCKR |= CKGR_UCKR_BIASEN;
}
void pmc_disable_upll_bias(void)
{
PMC->CKGR_UCKR &= ~CKGR_UCKR_BIASEN;
}
/*----------------------------------------------------------------------------
* Exported functions (Generated clocks)
*----------------------------------------------------------------------------*/
#ifdef CONFIG_HAVE_PMC_GENERATED_CLOCKS
void pmc_configure_gck(uint32_t id, uint32_t clock_source, uint32_t div)
{
assert(id > 1 && id < ID_PERIPH_COUNT);
assert(!(clock_source & ~PMC_PCR_GCKCSS_Msk));
assert(!(div << PMC_PCR_GCKDIV_Pos & ~PMC_PCR_GCKDIV_Msk));
pmc_disable_gck(id);
PMC->PMC_PCR = PMC_PCR_PID(id);
volatile uint32_t pcr = PMC->PMC_PCR;
PMC->PMC_PCR = pcr | (clock_source & PMC_PCR_GCKCSS_Msk) | PMC_PCR_CMD
| PMC_PCR_GCKDIV(div);
}
void pmc_enable_gck(uint32_t id)
{
assert(id > 1 && id < ID_PERIPH_COUNT);
PMC->PMC_PCR = PMC_PCR_PID(id);
volatile uint32_t pcr = PMC->PMC_PCR;
PMC->PMC_PCR = pcr | PMC_PCR_CMD | PMC_PCR_GCKEN;
while (!(PMC->PMC_SR & PMC_SR_GCKRDY));
}
void pmc_disable_gck(uint32_t id)
{
assert(id > 1 && id < ID_PERIPH_COUNT);
PMC->PMC_PCR = PMC_PCR_PID(id);
volatile uint32_t pcr = PMC->PMC_PCR;
PMC->PMC_PCR = PMC_PCR_CMD | (pcr & ~PMC_PCR_GCKEN);
}
uint32_t pmc_get_gck_clock(uint32_t id)
{
uint32_t clk = 0;
assert(id > 1 && id < ID_PERIPH_COUNT);
PMC->PMC_PCR = PMC_PCR_PID(id);
volatile uint32_t pcr = PMC->PMC_PCR;
switch (pcr & PMC_PCR_GCKCSS_Msk) {
case PMC_PCR_GCKCSS_SLOW_CLK:
clk = pmc_get_slow_clock();
break;
case PMC_PCR_GCKCSS_MAIN_CLK:
clk = pmc_get_main_clock();
break;
case PMC_PCR_GCKCSS_PLLA_CLK:
clk = pmc_get_plla_clock();
break;
case PMC_PCR_GCKCSS_UPLL_CLK:
clk = pmc_get_upll_clock();
break;
case PMC_PCR_GCKCSS_MCK_CLK:
clk = pmc_get_master_clock();
break;
#ifdef CONFIG_HAVE_PMC_AUDIO_CLOCK
case PMC_PCR_GCKCSS_AUDIO_CLK:
clk = pmc_get_audio_pmc_clock();
break;
#endif
}
uint32_t div = (pcr & PMC_PCR_GCKDIV_Msk) >> PMC_PCR_GCKDIV_Pos;
return ROUND_INT_DIV(clk, div + 1);
}
#endif /* CONFIG_HAVE_PMC_GENERATED_CLOCKS */
/*----------------------------------------------------------------------------
* Exported functions (Audio PLL)
*----------------------------------------------------------------------------*/
#ifdef CONFIG_HAVE_PMC_AUDIO_CLOCK
void pmc_configure_audio(struct _pmc_audio_cfg *cfg)
{
/* reset audio clock */
PMC->PMC_AUDIO_PLL0 &= ~PMC_AUDIO_PLL0_RESETN;
PMC->PMC_AUDIO_PLL0 |= PMC_AUDIO_PLL0_RESETN;
/* configure values */
uint32_t pll0 = PMC->PMC_AUDIO_PLL0;
pll0 &= ~PMC_AUDIO_PLL0_ND_Msk;
pll0 |= cfg->nd << PMC_AUDIO_PLL0_ND_Pos;
pll0 &= ~PMC_AUDIO_PLL0_QDPMC_Msk;
pll0 |= cfg->qdpmc << PMC_AUDIO_PLL0_QDPMC_Pos;
PMC->PMC_AUDIO_PLL0 = pll0;
uint32_t pll1 = PMC->PMC_AUDIO_PLL1;
pll1 &= ~PMC_AUDIO_PLL1_DIV_Msk;
pll1 |= cfg->div << PMC_AUDIO_PLL1_DIV_Pos;
pll1 &= ~PMC_AUDIO_PLL1_FRACR_Msk;
pll1 |= cfg->fracr << PMC_AUDIO_PLL1_FRACR_Pos;
pll1 &= ~PMC_AUDIO_PLL1_QDAUDIO_Msk;
pll1 |= cfg->qdaudio << PMC_AUDIO_PLL1_QDAUDIO_Pos;
PMC->PMC_AUDIO_PLL1 = pll1;
}
void pmc_enable_audio(bool pmc_clock, bool pad_clock)
{
uint32_t bits = PMC_AUDIO_PLL0_PLLEN | PMC_AUDIO_PLL0_RESETN;
uint32_t nbits = 0;
if (pad_clock)
bits |= PMC_AUDIO_PLL0_PADEN;
else
nbits |= PMC_AUDIO_PLL0_PADEN;
if (pmc_clock)
bits |= PMC_AUDIO_PLL0_PMCEN;
else
nbits |= PMC_AUDIO_PLL0_PMCEN;
PMC->PMC_AUDIO_PLL0 = (PMC->PMC_AUDIO_PLL0 & ~nbits) | bits;
}
void pmc_disable_audio()
{
uint32_t nbits = PMC_AUDIO_PLL0_PLLEN | PMC_AUDIO_PLL0_RESETN |
PMC_AUDIO_PLL0_PADEN | PMC_AUDIO_PLL0_PMCEN;
PMC->PMC_AUDIO_PLL0 &= ~nbits;
}
uint32_t pmc_get_audio_pmc_clock(void)
{
uint32_t pll0 = PMC->PMC_AUDIO_PLL0;
uint32_t pll1 = PMC->PMC_AUDIO_PLL1;
uint32_t nd = (pll0 & PMC_AUDIO_PLL0_ND_Msk) >> PMC_AUDIO_PLL0_ND_Pos;
uint32_t fracr = (pll1 & PMC_AUDIO_PLL1_FRACR_Msk) >> PMC_AUDIO_PLL1_FRACR_Pos;
uint32_t qdpmc = (pll0 & PMC_AUDIO_PLL0_QDPMC_Msk) >> PMC_AUDIO_PLL0_QDPMC_Pos;
uint64_t clk = BOARD_MAIN_CLOCK_EXT_OSC;
clk *= ((nd + 1) << 22) + fracr;
clk /= 1 << 22;
clk /= qdpmc + 1;
return (uint32_t)clk;
}
uint32_t pmc_get_audio_pad_clock(void)
{
uint32_t pll0 = PMC->PMC_AUDIO_PLL0;
uint32_t pll1 = PMC->PMC_AUDIO_PLL1;
uint32_t nd = (pll0 & PMC_AUDIO_PLL0_ND_Msk) >> PMC_AUDIO_PLL0_ND_Pos;
uint32_t fracr = (pll1 & PMC_AUDIO_PLL1_FRACR_Msk) >> PMC_AUDIO_PLL1_FRACR_Pos;
uint32_t qdaudio = (pll1 & PMC_AUDIO_PLL1_QDAUDIO_Msk) >> PMC_AUDIO_PLL1_QDAUDIO_Pos;
if (qdaudio == 0)
return 0;
uint32_t div = (pll1 & PMC_AUDIO_PLL1_DIV_Msk) >> PMC_AUDIO_PLL1_DIV_Pos;
if (div != 2 && div != 3)
return 0;
uint64_t clk = BOARD_MAIN_CLOCK_EXT_OSC;
clk *= ((nd + 1) << 22) + fracr;
clk /= 1 << 22;
clk /= div * qdaudio;
return (uint32_t)clk;
}
#endif /* CONFIG_HAVE_PMC_AUDIO_CLOCK */

View file

@ -0,0 +1,466 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
#ifndef _PMC_H_
#define _PMC_H_
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "board.h"
#include <stdint.h>
/*----------------------------------------------------------------------------
* Types
*----------------------------------------------------------------------------*/
struct pck_mck_cfg {
/** PLL A, SLCK, MAIN, UPLL */
uint32_t pck_input;
/** RC12M (false) or EXT12M (true) */
bool ext12m;
/** RC32K (false) or EXT32K (true) */
bool ext32k;
/** PLLA MUL value in PMC PLL register */
uint32_t plla_mul;
/** PLLA DIV value in PMC PLL register */
uint32_t plla_div;
/** PLLA DIV value by 2 */
bool plla_div2;
/** Master/Processor Clock Prescaler */
uint32_t pck_pres;
/** Master Clock Division after Prescaler divider */
uint32_t mck_div;
/** true if the AHB 32-bit Matrix frequency is equal to the AHB 64-bit Matrix frequency divided by 2 */
bool h32mxdiv2;
};
/**
* \brief System clock identifiers, used for pmc_{enable,disable}_system_clock
*/
enum _pmc_system_clock {
PMC_SYSTEM_CLOCK_PCK,
PMC_SYSTEM_CLOCK_DDR,
PMC_SYSTEM_CLOCK_LCD,
PMC_SYSTEM_CLOCK_SMD,
PMC_SYSTEM_CLOCK_UHP,
PMC_SYSTEM_CLOCK_UDP,
PMC_SYSTEM_CLOCK_PCK0,
PMC_SYSTEM_CLOCK_PCK1,
PMC_SYSTEM_CLOCK_PCK2,
PMC_SYSTEM_CLOCK_ISC,
};
#ifdef CONFIG_HAVE_PMC_AUDIO_CLOCK
/**
* \brief Configuration data for Audio clock
*
* AUDIOPLLCK = BOARD_EXT_OSC * (nd + 1 + (fracr / 2^22)) / (qdpmc + 1)
* AUDIOPINCLK = BOARD_EXT_OSC * (nc + 1 + (fracr / 2^22)) / (div * qdaudio)
*/
struct _pmc_audio_cfg {
uint32_t nd;
uint32_t fracr;
uint32_t qdpmc;
uint32_t div;
uint32_t qdaudio;
};
#endif /* CONFIG_HAVE_PMC_AUDIO_CLOCK */
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Configure PCK and MCK with custom setting
*/
extern void pmc_set_custom_pck_mck(struct pck_mck_cfg *cfg);
/**
* \brief Get the configured frequency of the master clock
* \return master clock frequency in Hz
*/
extern uint32_t pmc_get_master_clock(void);
/**
* \brief Get the configured frequency of the slow clock
* \return slow clock frequency in Hz
*/
extern uint32_t pmc_get_slow_clock(void);
/**
* \brief Get the configured frequency of the main clock
* \return main clock frequency in Hz
*/
extern uint32_t pmc_get_main_clock(void);
/**
* \brief Get the configured frequency of the PLLA clock
* \return PLLA clock frequency in Hz
*/
extern uint32_t pmc_get_plla_clock(void);
/**
* \brief Get the configured frequency of the processor clock
* \return processor clock frequency in Hz
*/
extern uint32_t pmc_get_processor_clock(void);
/**
* \brief Select external 32K crystal.
*/
extern void pmc_select_external_crystal(void);
/**
* \brief Select internal 32K crystal.
*/
extern void pmc_select_internal_crystal(void);
/**
* \brief Select external 12M OSC.
*/
extern void pmc_select_external_osc(void);
/**
* \brief Disable external 12M OSC.
*/
extern void pmc_disable_external_osc(void);
/**
* \brief Select internal 12M OSC.
*/
extern void pmc_select_internal_osc(void);
/**
* \brief Disable internal 12M OSC.
*/
extern void pmc_disable_internal_osc(void);
/**
* \brief Switch PMC from MCK to PLL clock.
*/
extern void pmc_switch_mck_to_pll(void);
/**
* \brief Switch PMC from MCK to UPLL clock.
*/
extern void pmc_switch_mck_to_upll(void);
/**
* \brief Switch PMC from MCK to main clock.
*/
extern void pmc_switch_mck_to_main(void);
/**
* \brief Switch PMC from MCK to slow clock.
*/
extern void pmc_switch_mck_to_slck(void);
/**
* \brief Configure PLL Register.
* \param pll pll value.
* \param cpcr cpcr value.
*/
extern void pmc_set_plla(uint32_t pll, uint32_t cpcr);
/**
* \brief Configure MCK Prescaler.
* \param prescaler prescaler value.
*/
extern void pmc_set_mck_prescaler(uint32_t prescaler);
/**
* \brief Configure MCK Divider.
* \param divider divider value.
*/
extern void pmc_set_mck_divider(uint32_t divider);
/**
* \brief Configure MCK H32MXDIV.
* \param divider divider value.
*/
extern void pmc_set_mck_h32mxdiv(uint32_t divider);
/**
* \brief Configure MCK PLLA divider.
* \param divider PLL divider value.
*/
extern void pmc_set_mck_plla_div(uint32_t divider);
/**
* \brief Disable PLLA Register.
*/
extern void pmc_disable_plla(void);
/**
* \brief Enables a system clock
* \param clock system clock to enable
*/
extern void pmc_enable_system_clock(enum _pmc_system_clock clock);
/**
* \brief Disables a system clock
* \param clock system clock to disable
*/
extern void pmc_disable_system_clock(enum _pmc_system_clock clock);
#ifdef CONFIG_HAVE_PMC_FAST_STARTUP
/**
* \brief Set up fast startup mode
* \param source and low power mode
*/
extern void pmc_set_fast_startup_mode(uint32_t startup_mode);
/**
* \brief Set up fast startup polarity
* \param level
*/
extern void pmc_set_fast_startup_polarity(uint32_t high_level,
uint32_t low_level);
#endif /* CONFIG_HAVE_PMC_FAST_STARTUP */
/**
* \brief Enables the clock of a peripheral. The peripheral ID is used
* to identify which peripheral is targeted.
*
* \param id Peripheral ID (ID_xxx).
*/
extern void pmc_enable_peripheral(uint32_t id);
/**
* \brief Disables the clock of a peripheral. The peripheral ID is used
* to identify which peripheral is targeted.
*
* \param id Peripheral ID (ID_xxx).
*/
extern void pmc_disable_peripheral(uint32_t id);
/**
* \brief Get Peripheral Status for the given peripheral ID.
*
* \param id Peripheral ID (ID_xxx).
*/
extern uint32_t pmc_is_peripheral_enabled(uint32_t id);
/**
* \brief Get current frequency clock for the given peripheral ID.
*
* \param id Peripheral ID (ID_xxx).
*/
extern uint32_t pmc_get_peripheral_clock(uint32_t id);
/**
* \brief Disable clocks for all peripherals
*/
extern void pmc_disable_all_peripherals(void);
/**
* \brief Configure programmable clock 0 (PCK0) with the given master clock
* source and clock prescaler
* \param clock_source clock source selection (one of the PMC_PCK_CSS_xxx_CLK
* constants)
* \param prescaler prescaler
*/
extern void pmc_configure_pck0(uint32_t clock_source, uint32_t prescaler);
/**
* \brief Enable programmable clock 0 (PCK0)
*/
extern void pmc_enable_pck0(void);
/**
* \brief Disable programmable clock 0 (PCK0)
*/
extern void pmc_disable_pck0(void);
/**
* \brief Get the frequency of the programmable clock 0 (PCK0)
* \return PCK0 frequency in Hz
*/
extern uint32_t pmc_get_pck0_clock(void);
/**
* \brief Configure programmable clock 1 (PCK1) with the given master clock
* source and clock prescaler
* \param clock_source Clock source selection (one of the PMC_PCK_CSS_xxx_CLK
* constants)
* \param prescaler Prescaler value
*/
extern void pmc_configure_pck1(uint32_t clock_source, uint32_t prescaler);
/**
* \brief Enable programmable clock 1 (PCK1)
*/
extern void pmc_enable_pck1(void);
/**
* \brief Disable programmable clock 1 (PCK1)
*/
extern void pmc_disable_pck1(void);
/**
* \brief Get the frequency of the programmable clock 1 (PCK1)
* \return PCK1 Frequency in Hz
*/
extern uint32_t pmc_get_pck1_clock(void);
/**
* \brief Configure programmable clock 2 (PCK2) with the given master clock
* source and clock prescaler
* \param clock_source Clock source selection (one of the PMC_PCK_CSS_xxx_CLK
* constants)
* \param prescaler Prescaler value
*/
extern void pmc_configure_pck2(uint32_t clock_source, uint32_t prescaler);
/**
* \brief Enable programmable clock 2 (PCK2)
*/
extern void pmc_enable_pck2(void);
/**
* \brief Disable programmable clock 2 (PCK2)
*/
extern void pmc_disable_pck2(void);
/**
* \brief Get the frequency of the programmable clock 2 (PCK2)
* \return PCK2 Frequency in Hz
*/
extern uint32_t pmc_get_pck2_clock(void);
/**
* \brief Enable the UPLL clock
*/
extern void pmc_enable_upll_clock(void);
/**
* \brief Disable the UPLL clock
*/
extern void pmc_disable_upll_clock(void);
/**
* \brief Get the frequency of the UPLL clock
* \return UPLL clock frequency in Hz
*/
extern uint32_t pmc_get_upll_clock(void);
/**
* \brief Enable the UPLL clock bias
*/
extern void pmc_enable_upll_bias(void);
/**
* \brief Disable the UPLL clock bias
*/
extern void pmc_disable_upll_bias(void);
#ifdef CONFIG_HAVE_PMC_GENERATED_CLOCKS
/**
* \brief Configure the generated clock (GCK) for the given peripheral with the
* given master clock source and clock prescaler
* \param id Peripheral ID (ID_xxx)
* \param clock_source Clock source selection (one of the
* PMC_PCR_GCKCSS_xxx_CLK constants)
* \param div Generated Clock Division Ratio (selected clock is divided by
* div + 1)
*/
extern void pmc_configure_gck(uint32_t id, uint32_t clock_source, uint32_t div);
/**
* \brief Enable generated clock for the given peripheral
* \param id Peripheral ID (ID_xxx)
*/
extern void pmc_enable_gck(uint32_t id);
/**
* \brief Disable generated clock for the given peripheral
* \param id Peripheral ID (ID_xxx)
*/
extern void pmc_disable_gck(uint32_t id);
/**
* \brief Get the frequency of the generated clock (GCK) for the given
* peripheral
* \param id Peripheral ID (ID_xxx)
* \return GCK Frequency in Hz
*/
extern uint32_t pmc_get_gck_clock(uint32_t id);
#endif /* CONFIG_HAVE_PMC_GENERATED_CLOCKS */
#ifdef CONFIG_HAVE_PMC_AUDIO_CLOCK
/**
* \brief Configure the audio clock
*/
extern void pmc_configure_audio(struct _pmc_audio_cfg *cfg);
/**
* \brief Enable audio clocks
* \param pmc_clock if true AUDIOPLLCK is sent to the PMC
* \param pad_clock if true the external audio pin is driven by AUDIOPINCLK, if
* false the audio pin is driven low
*/
extern void pmc_enable_audio(bool pmc_clock, bool pad_clock);
/**
* \brief Disable audio clocks
*/
extern void pmc_disable_audio(void);
/**
* \brief Get the frequency of the audio PMC clock
* \return Audio PMC Frequency in Hz
*/
extern uint32_t pmc_get_audio_pmc_clock(void);
/**
* \brief Get the frequency of the audio pad clock
* \return Audio pad Frequency in Hz
*/
extern uint32_t pmc_get_audio_pad_clock(void);
#endif /* CONFIG_HAVE_PMC_AUDIO_CLOCK */
#ifdef __cplusplus
}
#endif
#endif /* #ifndef _PMC_H_ */

View file

@ -0,0 +1,749 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2012, Atmel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/** \file */
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include "trace.h"
#include "peripherals/pmecc.h"
#include "peripherals/pmecc_gallois_field_512.h"
#include "peripherals/pmecc_gallois_field_1024.h"
/*--------------------------------------------------------------------------- */
/* Local types */
/*--------------------------------------------------------------------------- */
/** PMECC configuration descriptor */
struct _pmecc_descriptor {
/** Number of Sectors in one Page */
uint32_t page_size;
/** The spare area size is equal to (SPARESIZE+1) bytes */
uint32_t spare_size;
/** 0 for 512, 1 for 1024 bytes, like in PMECCFG register */
uint32_t sector_size;
/** Coded value of ECC bit number correction
* 0 (2 bits), 1 (4 bits), 2 (8 bits), 3 (12 bits), 4 (24 bits), 5 (NU)) */
uint32_t err_bit_nbr_capability;
/** Real size in bytes of ECC in spare */
uint32_t ecc_size_byte;
/** The first byte address of the ECC area */
uint32_t ecc_start_address;
/** The last byte address of the ECC area */
uint32_t ecc_end_address;
/** NAND Write Access*/
uint32_t nand_wr;
/** Spare Enable */
uint32_t spare_ena;
/** Automatic Mode */
uint32_t mode_auto;
/** The PMECC Module data path Setup Time is set to CLKCTRL+1. */
uint32_t clk_ctrl;
/** */
uint32_t interrupt;
/** defines the error correcting capability selected at encoding/decoding time */
int32_t tt;
/** degree of the remainders, GF(2**mm) */
int32_t mm;
/** length of codeword = nn=2**mm -1 */
int32_t nn;
/** Gallois field table */
const int16_t *alpha_to;
/** Index of Gallois field table */
const int16_t *index_of;
/** */
int16_t partial_syn[100];
/** Holds the current syndrome value, an element of that table belongs to the field.*/
int16_t si[100];
/** sigma table */
int16_t smu[PMECC_NB_ERROR_MAX + 2][2 * PMECC_NB_ERROR_MAX + 1];
/** polynom order */
int16_t lmu[PMECC_NB_ERROR_MAX + 1];
};
/*--------------------------------------------------------------------------- */
/* Local variables */
/*--------------------------------------------------------------------------- */
/** Pmecc decriptor instance */
struct _pmecc_descriptor pmecc_desc;
/*----------------------------------------------------------------------------
* Local functions
*----------------------------------------------------------------------------*/
/**
* \brief Build the pseudo syndromes table
* \param sector Targetted sector.
*/
static void gen_syn(uint32_t sector)
{
int16_t *remainer;
uint32_t index;
remainer = (int16_t*)&HSMC->SMC_REM[sector];
for (index = 0; index < (uint32_t)pmecc_desc.tt; index++) {
/* Fill odd syndromes */
pmecc_desc.partial_syn[1 + (2 * index)] = remainer[index];
}
}
/**
* \brief The substitute function evaluates the polynomial remainder,
* with different values of the field primitive elements.
*/
static uint32_t substitute(void)
{
int32_t i, j;
int16_t *si;
int16_t *p_partial_syn = pmecc_desc.partial_syn;
const int16_t *alpha_to = pmecc_desc.alpha_to;
const int16_t *index_of = pmecc_desc.index_of;
/* si[] is a table that holds the current syndrome value, an element of that table belongs to the field.*/
si = pmecc_desc.si;
for (i = 1; i < 2 * PMECC_NB_ERROR_MAX; i++)
si[i] = 0;
/* Computation 2t syndromes based on S(x) */
/* Odd syndromes */
for (i = 1; i <= 2 * pmecc_desc.tt - 1; i = i + 2) {
si[i] = 0;
for (j = 0; j < pmecc_desc.mm; j++) {
if (p_partial_syn[i] & ((uint16_t)0x1 << j))
si[i] = alpha_to[(i * j)] ^ si[i];
}
}
/* Even syndrome = (Odd syndrome) ** 2 */
for (i = 2; i <= 2 * pmecc_desc.tt; i = i + 2) {
j = i / 2;
if (si[j] == 0) {
si[i] = 0;
} else {
si[i] = alpha_to[(2 * index_of[si[j]]) % pmecc_desc.nn];
}
}
return 0;
}
/**
* \brief The substitute function finding the value of the error
* location polynomial.
*/
static uint32_t get_sigma(void)
{
uint32_t dmu_0_count;
int32_t i, j, k;
int16_t *lmu = pmecc_desc.lmu;
int16_t *si = pmecc_desc.si;
int16_t tt = pmecc_desc.tt;
int32_t mu[PMECC_NB_ERROR_MAX+1]; /* mu */
int32_t dmu[PMECC_NB_ERROR_MAX+1]; /* discrepancy */
int32_t delta[PMECC_NB_ERROR_MAX+1]; /* delta order */
int32_t ro; /* index of largest delta */
int32_t largest;
int32_t diff;
dmu_0_count = 0;
/* -- First Row -- */
/* Mu */
mu[0] = -1;
/* Actually -1/2 */
/* Sigma(x) set to 1 */
for (i = 0; i < (2 * PMECC_NB_ERROR_MAX + 1); i++)
pmecc_desc.smu[0][i] = 0;
pmecc_desc.smu[0][0] = 1;
/* discrepancy set to 1 */
dmu[0] = 1;
/* polynom order set to 0 */
lmu[0] = 0;
/* delta set to -1 */
delta[0] = (mu[0] * 2 - lmu[0]) >> 1;
/* -- Second Row -- */
/* Mu */
mu[1] = 0;
/* Sigma(x) set to 1 */
for (i = 0; i < (2 * PMECC_NB_ERROR_MAX + 1); i++)
pmecc_desc.smu[1][i] = 0;
pmecc_desc.smu[1][0] = 1;
/* discrepancy set to S1 */
dmu[1] = si[1];
/* polynom order set to 0 */
lmu[1] = 0;
/* delta set to 0 */
delta[1] = (mu[1] * 2 - lmu[1]) >> 1;
/* Init the Sigma(x) last row */
for (i = 0; i < (2 * PMECC_NB_ERROR_MAX + 1); i++)
pmecc_desc.smu[tt + 1][i] = 0;
for (i = 1; i <= tt; i++) {
mu[i+1] = i << 1;
/* Compute Sigma (Mu+1) */
/* And L(mu) */
/* check if discrepancy is set to 0 */
if ( dmu[i] == 0) {
dmu_0_count++;
if (( tt - (lmu[i] >> 1) - 1) & 0x1) {
if (dmu_0_count == (uint32_t)((tt - (lmu[i] >> 1) - 1) / 2) + 2) {
for (j = 0; j <= (lmu[i] >> 1) + 1; j++)
pmecc_desc.smu[tt+1][j] = pmecc_desc.smu[i][j];
lmu[tt + 1] = lmu[i];
return 0;
}
} else {
if (dmu_0_count == (uint32_t)((tt - (lmu[i] >> 1) - 1) / 2) + 1) {
for (j = 0; j <= (lmu[i] >> 1) + 1; j++)
pmecc_desc.smu[tt + 1][j] = pmecc_desc.smu[i][j];
lmu[tt + 1] = lmu[i];
return 0;
}
}
/* copy polynom */
for (j = 0; j <= (lmu[i] >> 1); j++)
pmecc_desc.smu[i + 1][j] = pmecc_desc.smu[i][j];
/* copy previous polynom order to the next */
lmu[i + 1] = lmu[i];
} else {
/* find largest delta with dmu != 0 */
ro = 0;
largest = -1;
for (j = 0; j < i; j++) {
if (dmu[j]) {
if (delta[j] > largest) {
largest = delta[j];
ro = j;
}
}
}
/* compute difference */
diff = (mu[i] - mu[ro]);
/* Compute degree of the new smu polynomial */
if ((lmu[i] >> 1) > ((lmu[ro] >> 1) + diff))
lmu[i + 1] = lmu[i];
else
lmu[i + 1] = ((lmu[ro] >> 1) + diff) * 2;
/* Init smu[i+1] with 0 */
for (k = 0; k < (2 * PMECC_NB_ERROR_MAX + 1); k++)
pmecc_desc.smu[i+1][k] = 0;
/* Compute smu[i+1] */
for (k = 0; k <= (lmu[ro] >> 1); k++) {
if (pmecc_desc.smu[ro][k] && dmu[i])
pmecc_desc.smu[i + 1][k + diff] = pmecc_desc.alpha_to[(pmecc_desc.index_of[dmu[i]] +
(pmecc_desc.nn - pmecc_desc.index_of[dmu[ro]]) +
pmecc_desc.index_of[pmecc_desc.smu[ro][k]]) % pmecc_desc.nn];
}
for (k = 0; k <= (lmu[i] >> 1); k++)
pmecc_desc.smu[i+1][k] ^= pmecc_desc.smu[i][k];
}
/*************************************************/
/* End Compute Sigma (Mu+1) */
/* And L(mu) */
/*************************************************/
/* In either case compute delta */
delta[i + 1] = (mu[i + 1] * 2 - lmu[i + 1]) >> 1;
/* Do not compute discrepancy for the last iteration */
if (i < tt) {
for (k = 0 ; k <= (lmu[i + 1] >> 1); k++) {
if (k == 0)
dmu[i + 1] = si[2 * (i - 1) + 3];
/* check if one operand of the multiplier is null, its index is -1 */
else if (pmecc_desc.smu[i+1][k] && si[2 * (i - 1) + 3 - k])
dmu[i + 1] = pmecc_desc.alpha_to[(pmecc_desc.index_of[pmecc_desc.smu[i + 1][k]] +
pmecc_desc.index_of[si[2 * (i - 1) + 3 - k]]) % pmecc_desc.nn] ^ dmu[i + 1];
}
}
}
return 0;
}
/**
* \brief Init the PMECC Error Location peripheral and start the error
* location processing
* \param sector_size_in_bits Size of the sector in bits.
* \return Number of errors
*/
static int32_t error_location (uint32_t sector_size_in_bits)
{
uint32_t alphax;
uint32_t *sigma;
uint32_t error_number;
uint32_t nbr_of_roots;
/* Disable PMECC Error Location IP */
HSMC->HSMC_ELDIS |= 0xFFFFFFFF;
error_number = 0;
alphax = 0;
sigma = (uint32_t*)&HSMC->HSMC_SIGMA0;
for (alphax = 0; alphax <= (uint32_t)(pmecc_desc.lmu[pmecc_desc.tt + 1] >> 1); alphax++) {
*sigma++ = pmecc_desc.smu[pmecc_desc.tt + 1][alphax];
error_number++;
}
/* Enable error location process */
HSMC->HSMC_ELCFG |= ((error_number - 1) << 16);
HSMC->HSMC_ELEN = sector_size_in_bits;
while ((HSMC->HSMC_ELISR & HSMC_ELISR_DONE) == 0);
nbr_of_roots = (HSMC->HSMC_ELISR & HSMC_ELISR_ERR_CNT_Msk) >> 8;
/* Number of roots == degree of smu hence <= tt */
if (nbr_of_roots == (uint32_t)(pmecc_desc.lmu[pmecc_desc.tt + 1] >> 1))
return (error_number - 1);
/* Number of roots not match the degree of smu ==> unable to correct error */
return -1;
}
/**
* \brief Correct errors indicated in the PMECCEL error location registers.
* \param sector_base_address Base address of the sector.
* \param extra_bytes Number of extra bytes of the sector.(encoded Spare Area, only for the last sector)
* \param error_nbr Number of error to correct
* \return Number of errors
*/
static uint32_t error_correction(uint32_t sector_base_address, uint32_t extra_bytes, uint32_t error_nbr)
{
uint32_t *error_pos;
uint32_t byte_pos;
uint32_t bit_pos;
uint32_t sector_size;
uint32_t ecc_size;
uint32_t ecc_end_addr;
error_pos = (uint32_t*)&HSMC->HSMC_ERRLOC0;
sector_size = 512 * (((HSMC->HSMC_PMECCFG & HSMC_PMECCFG_SECTORSZ) >> 4) + 1);
/* Get number of ECC bytes */
ecc_end_addr = HSMC->HSMC_PMECCEADDR;
ecc_size = (ecc_end_addr - HSMC->HSMC_PMECCSADDR) + 1;
while (error_nbr) {
byte_pos = (*error_pos - 1) / 8;
bit_pos = (*error_pos - 1) % 8;
/* If error is located in the data area(not in ECC) */
if ( byte_pos < (sector_size + extra_bytes)) {
uint8_t *data_ptr = NULL;
/* If the error position is before ECC area */
if ( byte_pos < sector_size + HSMC->HSMC_PMECCSADDR) {
data_ptr = (uint8_t*)(sector_base_address + byte_pos);
} else {
data_ptr = (uint8_t*)(sector_base_address + byte_pos + ecc_size);
}
trace_info("Correct error bit @[#Byte %u,Bit# %u]\n\r",
(unsigned)byte_pos, (unsigned)bit_pos);
if (*data_ptr & (1 << bit_pos))
*data_ptr &= (0xFF ^ (1 << bit_pos));
else
*data_ptr |= (1 << bit_pos);
}
error_pos++;
error_nbr--;
}
return 0;
}
/**
* \brief Configure the PMECC peripheral
* \param pPmeccDescriptor Pointer to a PmeccDescriptor instance.
*/
static void _pmecc_configure(void)
{
/* Disable ECC module */
HSMC->HSMC_PMECCTRL |= HSMC_PMECCTRL_DISABLE;
/* Reset the ECC module */
HSMC->HSMC_PMECCTRL = HSMC_PMECCTRL_RST;
HSMC->HSMC_PMECCFG = pmecc_desc.err_bit_nbr_capability |
pmecc_desc.sector_size |
pmecc_desc.page_size |
pmecc_desc.nand_wr |
pmecc_desc.spare_ena |
pmecc_desc.mode_auto;
HSMC->HSMC_PMECCSAREA = pmecc_desc.spare_size - 1;
HSMC->HSMC_PMECCSADDR = pmecc_desc.ecc_start_address;
HSMC->HSMC_PMECCEADDR = pmecc_desc.ecc_end_address - 1;
/* Disable all interrupts */
HSMC->HSMC_PMECCIDR = 0xFF;
/* Enable ECC module */
HSMC->HSMC_PMECCTRL |= HSMC_PMECCTRL_ENABLE;
}
/*----------------------------------------------------------------------------
* Export functions
*----------------------------------------------------------------------------*/
/**
* \brief This function is able to build Galois Field.
* \param mm degree of the remainders.
* \param index_of Pointer to a buffer for index_of table.
* \param alpha_to Pointer to a buffer for alpha_to table.
*/
void build_gf(uint32_t mm, int32_t* index_of, int32_t* alpha_to)
{
uint32_t i;
uint32_t mask;
uint32_t nn;
uint32_t p[15];
nn = (1 << mm) - 1;
/* set default value */
for (i = 1; i < mm; i++)
p[i] = 0;
/* 1 + X^mm */
p[0] = 1;
p[mm] = 1;
/* others */
if (mm == 3)
p[1] = 1;
else if (mm == 4)
p[1] = 1;
else if (mm == 5)
p[2] = 1;
else if (mm == 6)
p[1] = 1;
else if (mm == 7)
p[3] = 1;
else if (mm == 8)
p[2] = p[3] = p[4] = 1;
else if (mm == 9)
p[4] = 1;
else if (mm == 10)
p[3] = 1;
else if (mm == 11)
p[2] = 1;
else if (mm == 12)
p[1] = p[4] = p[6] = 1;
else if (mm == 13)
p[1] = p[3] = p[4] = 1;
else if (mm == 14)
p[1] = p[6] = p[10] = 1;
else if (mm == 15)
p[1] = 1;
/*-- First of All */
/*-- build alpha ^ mm it will help to generate the field (primitiv) */
alpha_to[mm] = 0;
for (i = 0; i < mm; i++)
if (p[i])
alpha_to[mm] |= 1 << i;
/* Secondly */
/* Build elements from 0 to mm - 1 */
/* very easy because degree is less than mm so it is */
/* just a logical shift ! (only the remainder) */
mask = 1;
for (i = 0; i < mm; i++) {
alpha_to[i] = mask;
index_of[alpha_to[i]] = i;
mask <<= 1;
}
index_of[alpha_to[mm]] = mm;
/* use a mask to select the MSB bit of the */
/* LFSR ! */
mask >>= 1; /* previous value moust be decremented */
/* then finish the building */
for (i = mm + 1; i <= nn; i++) {
/* check if the msb bit of the lfsr is set */
if (alpha_to[i-1] & mask)
/* feedback loop is set */
alpha_to[i] = alpha_to[mm] ^ ((alpha_to[i-1] ^ mask) << 1);
else
/* only shift is enabled */
alpha_to[i] = alpha_to[i-1] << 1;
/* lookup table */
//index_of[alpha_to[i]] = i ;
index_of[alpha_to[i]] = i%nn ;
}
/* of course index of 0 is undefined in a multiplicative field */
index_of[0] = -1;
}
/**
* \brief Initialize the PMECC peripheral
* \param sector_size 0 for 512, 1 for 1024.
* \param ecc_errors_per_sector Coded value of ECC bit number correction(2,4,8,12,24).
* \param page_data_size Data area size in byte.
* \param page_spare_size Spare area size in byte.
* \param ecc_offset_in_spare offset of the first ecc byte in spare zone.
* \param spare_protected 1: The spare area is protected with the last sector of data.
* 0: The spare area is skipped in read or write mode.
* \return 0 if successful; otherwise returns 1.
*/
uint8_t pmecc_initialize(uint8_t sector_size , uint8_t ecc_errors_per_sector,
uint32_t page_data_size, uint32_t page_spare_size,
uint16_t ecc_offset_in_spare, uint8_t spare_protected)
{
uint8_t nb_sectors_per_page = 0;
if (ecc_errors_per_sector == 0xFF) {
/* ONFI 2.2 : a value of 0xff indaicate we must apply a correction on sector > 512 bytes,
so we set at the maximum allowed by PMECC 24 bits on 1024 sectors. */
ecc_errors_per_sector = 24;
sector_size = 1; /* 1 for 1024 bytes per sector */
}
/* Number of Sectors in one Page */
switch (sector_size) {
/* 512 bytes per sector */
case 0:
pmecc_desc.sector_size = 0;
nb_sectors_per_page = page_data_size / 512;
pmecc_desc.mm = 13;
pmecc_get_gf_512_tables(&pmecc_desc.alpha_to, &pmecc_desc.index_of);
break;
/* 1024 bytes per sector */
case 1:
pmecc_desc.sector_size = HSMC_PMECCFG_SECTORSZ;
nb_sectors_per_page = page_data_size / 1024;
pmecc_desc.mm = 14;
pmecc_get_gf_1024_tables(&pmecc_desc.alpha_to, &pmecc_desc.index_of);
break;
}
switch (nb_sectors_per_page) {
case 1:
pmecc_desc.page_size = HSMC_PMECCFG_PAGESIZE_PAGESIZE_1SEC;
break;
case 2:
pmecc_desc.page_size = HSMC_PMECCFG_PAGESIZE_PAGESIZE_2SEC;
break;
case 4:
pmecc_desc.page_size = HSMC_PMECCFG_PAGESIZE_PAGESIZE_4SEC;
break;
case 8:
pmecc_desc.page_size = HSMC_PMECCFG_PAGESIZE_PAGESIZE_8SEC;
break;
default :
pmecc_desc.page_size = HSMC_PMECCFG_PAGESIZE_PAGESIZE_1SEC;
break;
}
pmecc_desc.nn = (1 << pmecc_desc.mm) - 1;
/* Coded value of ECC bit number correction (0 (2 bits), 1 (4 bits), 2 (8 bits), 3 (12 bits), 4 (24 bits), 5 (NU)) */
switch (ecc_errors_per_sector) {
case 2:
pmecc_desc.err_bit_nbr_capability = HSMC_PMECCFG_BCH_ERR_BCH_ERR2;
break;
case 4:
pmecc_desc.err_bit_nbr_capability = HSMC_PMECCFG_BCH_ERR_BCH_ERR4;
break;
case 8:
pmecc_desc.err_bit_nbr_capability = HSMC_PMECCFG_BCH_ERR_BCH_ERR8;
break;
case 12:
pmecc_desc.err_bit_nbr_capability = HSMC_PMECCFG_BCH_ERR_BCH_ERR12;
break;
case 24:
pmecc_desc.err_bit_nbr_capability = HSMC_PMECCFG_BCH_ERR_BCH_ERR24;
break;
default:
pmecc_desc.err_bit_nbr_capability = HSMC_PMECCFG_BCH_ERR_BCH_ERR2;
ecc_errors_per_sector = 2;
break;
}
/* Real value of ECC bit number correction (2, 4, 8, 12, 24) */
pmecc_desc.tt = ecc_errors_per_sector;
if (((pmecc_desc.mm * ecc_errors_per_sector ) % 8 ) == 0) {
pmecc_desc.ecc_size_byte = ((pmecc_desc.mm * ecc_errors_per_sector ) / 8) * nb_sectors_per_page;
} else {
pmecc_desc.ecc_size_byte = (((pmecc_desc.mm * ecc_errors_per_sector ) / 8 ) + 1 ) * nb_sectors_per_page;
}
if (ecc_offset_in_spare <= 2) {
pmecc_desc.ecc_start_address = PMECC_ECC_DEFAULT_START_ADDR;
} else {
pmecc_desc.ecc_start_address = ecc_offset_in_spare;
}
pmecc_desc.ecc_end_address = pmecc_desc.ecc_start_address + pmecc_desc.ecc_size_byte;
if (pmecc_desc.ecc_end_address > page_spare_size) {
return 1;
}
pmecc_desc.spare_size = pmecc_desc.ecc_end_address;
//pmecc_desc.nand_wr = PMECC_CFG_NANDWR; /* NAND write access */
pmecc_desc.nand_wr = 0; /* NAND Read access */
if (spare_protected) {
pmecc_desc.spare_ena = HSMC_PMECCFG_SPAREEN;
} else {
pmecc_desc.spare_ena = 0;
}
/* PMECC_CFG_AUTO indicates that the spare is error protected. In this case, the ECC computation takes into account the whole spare area
minus the ECC area in the ECC computation operation */
pmecc_desc.mode_auto = 0;
/* At 133 Mhz, this field must be programmed with 2,
indicating that the setup time is 3 clock cycles.*/
pmecc_desc.clk_ctrl = 2;
pmecc_desc.interrupt = 0;
_pmecc_configure();
return 0;
}
/**
* \brief Return PMECC page size.
*/
uint32_t pmecc_get_page_size(void)
{
return pmecc_desc.page_size;
}
/**
* \brief Return PMECC ecc size.
*/
uint32_t pmecc_get_ecc_bytes(void)
{
return pmecc_desc.ecc_size_byte;
}
/**
* \brief Return PMECC ecc start address.
*/
uint32_t pmecc_get_ecc_start_address(void)
{
return pmecc_desc.ecc_start_address;
}
/**
* \brief Return PMECC ecc end address.
*/
uint32_t pmecc_get_ecc_end_address(void)
{
return pmecc_desc.ecc_end_address;
}
typedef uint32_t (*pmecc_correction_algo_t)(Smc *, struct _pmecc_descriptor *, uint32_t, uint32_t);
/**
* \brief Launch error detection functions and correct corrupted bits.
* \param pmecc_status Value of the PMECC status register.
* \param page_buffer Base address of the buffer containing the page to be corrected.
* \return 0 if all errors have been corrected, 1 if too many errors detected
*/
uint32_t pmecc_correction(uint32_t pmecc_status, uint32_t page_buffer)
{
uint32_t sector_number = 0;
uint32_t sector_base_address;
volatile int32_t error_nbr;
/* Set the sector size (512 or 1024 bytes) */
HSMC->HSMC_ELCFG = pmecc_desc.sector_size >> 4;
while (sector_number < (uint32_t)((1 << ((HSMC->HSMC_PMECCFG & HSMC_PMECCFG_PAGESIZE_Msk) >> 8)))) {
error_nbr = 0;
if (pmecc_status & 0x1) {
sector_base_address = page_buffer + (sector_number * ((pmecc_desc.sector_size >> 4) + 1) * 512);
gen_syn(sector_number);
substitute();
get_sigma();
error_nbr = error_location((((pmecc_desc.sector_size >> 4) + 1) * 512 * 8) +
(pmecc_desc.tt * (13 + (pmecc_desc.sector_size >> 4)))); /* number of bits of the sector + ecc */
if (error_nbr == -1)
return 1;
else
error_correction(sector_base_address, 0, error_nbr); /* Extra byte is 0 */
}
sector_number++;
pmecc_status = pmecc_status >> 1;
}
return 0;
}
/**
* \brief Disable pmecc.
*/
void pmecc_disable(void)
{
/* Disable ECC module */
HSMC->HSMC_PMECCTRL |= HSMC_PMECCTRL_DISABLE;
}

View file

@ -0,0 +1,66 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
#ifndef PMECC_H
#define PMECC_H
/*----------------------------------------------------------------------- */
/* Definition */
/*----------------------------------------------------------------------- */
/** Start address of ECC cvalue in spare zone, this must not be 0 since Bad block tag are at 0. */
#define PMECC_ECC_DEFAULT_START_ADDR 0x02
/*------------------------------------------------------------------------------ */
/* Exported functions */
/*------------------------------------------------------------------------------ */
extern uint8_t pmecc_initialize(uint8_t sector_size,
uint8_t ecc_errors_per_sector,
uint32_t page_data_size,
uint32_t page_spare_size,
uint16_t ecc_offset_in_spare,
uint8_t spare_protected);
extern uint32_t pmecc_get_page_size(void);
extern uint32_t pmecc_get_ecc_bytes(void);
extern uint32_t pmecc_get_ecc_start_address(void);
extern uint32_t pmecc_get_ecc_end_address(void);
extern uint32_t pmecc_correction(uint32_t pmecc_status, uint32_t page_buffer);
extern void build_gf(uint32_t mm, int32_t *index_of, int32_t *alpha_to);
extern void pmecc_disable(void);
#endif

View file

@ -0,0 +1,52 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2013, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
#ifndef PMECC_TABLES_1024_H
#define PMECC_TABLES_1024_H
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include <stdint.h>
/*----------------------------------------------------------------------------
* Definitions
*----------------------------------------------------------------------------*/
#define PMECC_GF_1024_SIZE (0x4000)
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/** \brief Get the addresses of Gallois Field tables for 1024 bytes sectors */
void pmecc_get_gf_1024_tables(const int16_t **alpha_to, const int16_t **index_of);
#endif /* PMECC_TABLES_1024_H */

View file

@ -0,0 +1,52 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2013, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
#ifndef PMECC_TABLES_512_H
#define PMECC_TABLES_512_H
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include <stdint.h>
/*----------------------------------------------------------------------------
* Definitions
*----------------------------------------------------------------------------*/
#define PMECC_GF_512_SIZE (0x2000)
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/** \brief Get the addresses of Gallois Field tables for 512 bytes sectors */
void pmecc_get_gf_512_tables(const int16_t **alpha_to, const int16_t **index_of);
#endif /* PMECC_TABLES_512_H */

View file

@ -0,0 +1,147 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/** \addtogroup pwm_module Working with PWM
* \section Purpose
* The PWM driver provides the interface to configure and use the PWM
* peripheral.
*
* The PWM macrocell controls square output waveforms of 4 channels.
* Characteristics of output waveforms such as period, duty-cycle can be configured.\n
*
* Before enabling the channels, they must have been configured first.
* The main settings include:
* <ul>
* <li>Configuration of the clock generator.</li>
* <li>Selection of the clock for each channel.</li>
* <li>Configuration of output waveform characteristics, such as period, duty-cycle etc.</li>
* </ul>
*
* After the channels is enabled, the user must use respective update registers
* to change the wave characteristics to prevent unexpected output waveform.
* i.e. PWM_CUPDx register should be used if user want to change duty-cycle
* when the channel is enabled.
*
* \section Usage
* <ul>
* <li> Configure PWM clock using pwmc_configure_clocks().
* <li> Enable & disable given PWM channel using pwmc_enable_channel() and pwmc_disable_channel().
* <li> Enable & disable interrupt of given PWM channel using pwmc_enable_channel_it()
* and pwmc_disable_channel_it().
* <li> Set feature of the given PWM channel's output signal using pwmc_set_period()
* and pwmc_set_duty_cycle().
* </li>
* </ul>
*
* For more accurate information, please look at the PWM section of the
* Datasheet.
*
* Related files :\n
* \ref pwmc.c\n
* \ref pwmc.h.\n
*/
/*@{*/
/*@}*/
/**
* \file
*
* Implementation of the Pulse Width Modulation Controller (PWM) peripheral.
*
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include "peripherals/pwmc.h"
#include <stdint.h>
#include <assert.h>
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
void pwmc_configure_clocks(Pwm * p_pwm, uint32_t mode)
{
p_pwm->PWM_CLK = mode;
}
void pwmc_enable_channel(Pwm * p_pwm, uint8_t channel)
{
p_pwm->PWM_ENA = 0x1ul << channel;
}
void pwmc_disable_channel(Pwm * p_pwm, uint8_t channel)
{
p_pwm->PWM_DIS = 0x1ul << channel;
}
void pwmc_enable_channel_it(Pwm * p_pwm, uint8_t channel)
{
p_pwm->PWM_IER1 = 0x1ul << channel;
}
void pwmc_disable_channel_it(Pwm * p_pwm, uint8_t channel)
{
p_pwm->PWM_IDR1 = 0x1ul << channel;
}
void pwmc_configure_channel(Pwm * p_pwm, uint8_t channel, uint32_t mode)
{
p_pwm->PWM_CH_NUM[channel].PWM_CMR = mode;
}
void pwmc_set_period(Pwm * p_pwm, uint8_t channel, uint16_t period)
{
/* If channel is disabled, write to CPRD */
if ((p_pwm->PWM_SR & (1 << channel)) == 0) {
p_pwm->PWM_CH_NUM[channel].PWM_CPRD = period;
}
/* Otherwise use update register */
else {
p_pwm->PWM_CH_NUM[channel].PWM_CPRDUPD = period;
}
}
void pwmc_set_duty_cycle(Pwm * p_pwm, uint8_t channel, uint16_t duty)
{
assert(duty <= p_pwm->PWM_CH_NUM[channel].PWM_CPRD);
/* If channel is disabled, write to CDTY */
if ((p_pwm->PWM_SR & (1 << channel)) == 0) {
p_pwm->PWM_CH_NUM[channel].PWM_CDTY = duty;
}
/* Otherwise use update register */
else {
p_pwm->PWM_CH_NUM[channel].PWM_CDTYUPD = duty;
}
}

View file

@ -0,0 +1,157 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* \par Purpose
*
* Interface for configuration the Pulse Width Modulation Controller (PWM) peripheral.
*
* \par Usage
*
* -# Configures PWM clocks A & B to run at the given frequencies using
* pwmc_configure_clocks().
* -# Configure PWMC channel using pwmc_configure_channel(), pwmc_set_period()
* and pwmc_set_duty_cycle().
* -# Enable & disable channel using pwmc_enable_channel() and pwmc_disable_channel().
* -# Enable & disable the period interrupt for the given PWM channel using
* pwmc_enable_channel_it() and pwmc_disable_channel_it().
*
*/
#ifndef _PWMC_
#define _PWMC_
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/**
* \brief Configures PWM clocks
* \param p_pwm Pointer to a Pwm instance
* \param mode PWM clock source selection and divide factor.
*/
extern void pwmc_configure_clocks(Pwm * p_pwm, uint32_t mode);
/**
* \brief Enables the given PWM channel.
*
* This does NOT enable the corresponding pin; this must be done in the user
* code.
*
* \param p_pwm Pointer to a Pwm instance
* \param channel Channel number.
*/
extern void pwmc_enable_channel(Pwm * p_pwm, uint8_t channel);
/**
* \brief Disables the given PWM channel.
*
* Beware, the channel will be effectively disabled at the end of the current
* period.
* Applications may check whether the channel is disabled using the following
* wait loop:
* while ((PWM->PWM_SR & (1 << channel)) != 0) {};
*
* \param p_pwm Pointer to a Pwm instance
* \param channel Channel number.
*/
extern void pwmc_disable_channel(Pwm * p_pwm, uint8_t channel);
/**
* \brief Enables the selected interrupts sources on a PWMC peripheral.
* \param p_pwm Pointer to a Pwm instance
* \param channel Channel number.
*/
extern void pwmc_enable_channel_it(Pwm * p_pwm, uint8_t channel);
/**
* \brief Disables the selected interrupts sources on a PWMC peripheral.
* \param p_pwm Pointer to a Pwm instance
* \param channel Channel number.
*/
extern void pwmc_disable_channel_it(Pwm * p_pwm, uint8_t channel);
/**
* \brief Configures a PWM channel with the given parameters, basic configure
* function.
*
* The PWM controller must have been clocked in the PMC prior to calling this
* function.
* Beware: this function disables the channel. It will wait until the channel is
* effectively disabled.
*
* \param p_pwm Pointer to a Pwm instance
* \param channel Channel number.
* \param mode Channel mode.
*/
extern void pwmc_configure_channel(Pwm * p_pwm, uint8_t channel, uint32_t mode);
/**
* \brief Sets the period value used by a PWM channel.
*
* This function writes directly to the CPRD register if the channel is
* disabled. Otherwise it sets the update register CPRDUPD.
*
* \param p_pwm Pointer to a Pwm instance
* \param channel Channel number.
* \param period Period value.
*/
extern void pwmc_set_period(Pwm * p_pwm, uint8_t channel, uint16_t period);
/**
* \brief Sets the duty cycle used by a PWM channel.
* This function writes directly to the CDTY register if the channel is
* disabled. Otherwise it sets the update register CDTYUPD.
* Note that the duty cycle must always be inferior or equal to the channel
* period.
*
* \param p_pwm Pointer to a Pwm instance
* \param channel Channel number.
* \param duty Duty cycle value.
*/
extern void pwmc_set_duty_cycle(Pwm * p_pwm, uint8_t channel, uint16_t duty);
#ifdef __cplusplus
}
#endif
#endif /* #ifndef _PWMC_ */

View file

@ -0,0 +1,233 @@
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include "timer.h"
#include "trace.h"
#include "peripherals/pmc.h"
#include "peripherals/qspi.h"
#include <stdint.h>
#include <string.h>
/*----------------------------------------------------------------------------
* Local functions
*----------------------------------------------------------------------------*/
static void qspi_memcpy(uint8_t *dst, const uint8_t *src, int count)
{
while (count--)
*dst++ = *src++;
}
/*----------------------------------------------------------------------------
* Public functions
*----------------------------------------------------------------------------*/
void qspi_initialize(Qspi *qspi)
{
pmc_enable_peripheral(get_qspi_id_from_addr(qspi));
/* Disable write protection */
qspi->QSPI_WPMR = QSPI_WPMR_WPKEY_PASSWD;
/* Reset */
qspi->QSPI_CR = QSPI_CR_SWRST;
/* Configure */
qspi->QSPI_MR = QSPI_MR_SMM_MEMORY;
qspi->QSPI_SCR = 0;
/* Enable */
qspi->QSPI_CR = QSPI_CR_QSPIEN;
}
uint32_t qspi_set_baudrate(Qspi *qspi, uint32_t baudrate)
{
uint32_t mck, scr, scbr;
if (!baudrate)
return 0;
/* Serial Clock Baudrate */
mck = pmc_get_peripheral_clock(get_qspi_id_from_addr(qspi));
scbr = (mck + baudrate - 1) / baudrate;
if (scbr > 0)
scbr--;
/* Update the Serial Clock Register */
scr = qspi->QSPI_SCR;
scr &= ~QSPI_SCR_SCBR_Msk;
scr |= QSPI_SCR_SCBR(scbr);
qspi->QSPI_SCR = scr;
return mck / (scbr + 1);
}
bool qspi_perform_command(Qspi *qspi, const struct _qspi_cmd *cmd)
{
uint32_t iar, icr, ifr;
uint32_t offset;
iar = 0;
icr = 0;
ifr = (cmd->ifr_width & QSPI_IFR_WIDTH_Msk) | (cmd->ifr_type & QSPI_IFR_TFRTYP_Msk);
/* Compute address parameters */
switch (cmd->enable.address) {
case 4:
ifr |= QSPI_IFR_ADDRL_32_BIT;
/* fallback to the 24-bit address case */
case 3:
iar = (cmd->enable.data) ? 0 : QSPI_IAR_ADDR(cmd->address);
ifr |= QSPI_IFR_ADDREN;
offset = cmd->address;
break;
case 0:
offset = 0;
break;
default:
return false;
}
/* Compute instruction parameters */
if (cmd->enable.instruction) {
icr |= QSPI_ICR_INST(cmd->instruction);
ifr |= QSPI_IFR_INSTEN;
}
/* Compute option parameters */
if (cmd->enable.mode && cmd->num_mode_cycles) {
uint32_t mode_cycle_bits, mode_bits;
icr |= QSPI_ICR_OPT(cmd->mode);
ifr |= QSPI_IFR_OPTEN;
switch (ifr & QSPI_IFR_WIDTH_Msk) {
case QSPI_IFR_WIDTH_SINGLE_BIT_SPI:
case QSPI_IFR_WIDTH_DUAL_OUTPUT:
case QSPI_IFR_WIDTH_QUAD_OUTPUT:
mode_cycle_bits = 1;
break;
case QSPI_IFR_WIDTH_DUAL_IO:
case QSPI_IFR_WIDTH_DUAL_CMD:
mode_cycle_bits = 2;
break;
case QSPI_IFR_WIDTH_QUAD_IO:
case QSPI_IFR_WIDTH_QUAD_CMD:
mode_cycle_bits = 4;
break;
default:
return false;
}
mode_bits = cmd->num_mode_cycles * mode_cycle_bits;
switch (mode_bits) {
case 1:
ifr |= QSPI_IFR_OPTL_OPTION_1BIT;
break;
case 2:
ifr |= QSPI_IFR_OPTL_OPTION_2BIT;
break;
case 4:
ifr |= QSPI_IFR_OPTL_OPTION_4BIT;
break;
case 8:
ifr |= QSPI_IFR_OPTL_OPTION_8BIT;
break;
default:
return false;
}
}
/* Set number of dummy cycles */
if (cmd->enable.dummy)
ifr |= QSPI_IFR_NBDUM(cmd->num_dummy_cycles);
else
ifr |= QSPI_IFR_NBDUM(0);
/* Set data enable */
if (cmd->enable.data) {
ifr |= QSPI_IFR_DATAEN;
/* Special case for Continous Read Mode */
if (!cmd->tx_buffer && !cmd->rx_buffer)
ifr |= QSPI_IFR_CRM_ENABLED;
}
/* Set QSPI Instruction Frame registers */
qspi->QSPI_IAR = iar;
qspi->QSPI_ICR = icr;
qspi->QSPI_IFR = ifr;
/* Skip to the final steps if there is no data */
if (!cmd->enable.data)
goto no_data;
/* Dummy read of QSPI_IFR to synchronize APB and AHB accesses */
(void)qspi->QSPI_IFR;
/* Send/Receive data */
if (cmd->tx_buffer) {
/* Write data */
uint8_t *ptr = (uint8_t*)get_qspi_mem_from_addr(qspi);
qspi_memcpy(ptr + offset, cmd->tx_buffer, cmd->buffer_len);
} else if (cmd->rx_buffer) {
/* Read data */
const uint8_t *ptr = (const uint8_t*)get_qspi_mem_from_addr(qspi);
qspi_memcpy(cmd->rx_buffer, ptr + offset, cmd->buffer_len);
} else {
/* Stop here for continuous read */
return true;
}
no_data:
/* Release the chip-select */
qspi->QSPI_CR = QSPI_CR_LASTXFER;
/* Wait for INSTRuction End */
struct _timeout timeout;
timer_start_timeout(&timeout, cmd->timeout);
while (!(qspi->QSPI_SR & QSPI_SR_INSTRE)) {
if (timer_timeout_reached(&timeout)) {
trace_debug("qspi_perform_command timeout reached\r\n");
return false;
}
}
return true;
}

View file

@ -0,0 +1,143 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* Interface for Quad Serial Peripheral Interface (QSPI) controller.
*
*/
#ifndef _QSPI_H_
#define _QSPI_H_
/*----------------------------------------------------------------------------
* Types
*----------------------------------------------------------------------------*/
/** QSPI Command structure */
struct _qspi_cmd {
/** Data Transfer Type (QSPI_IFR_TFRTYP_TRSFR_xxx) */
uint32_t ifr_type;
/** Width of Instruction Code, Address, Option Code and Data
* (QSPI_IFR_WIDTH_xxx) */
uint32_t ifr_width;
/** Flags to select which information is included in the command */
struct {
/** 0: don't send instruction code, 1: send instuction code */
uint32_t instruction:1;
/** 0: don't send address, 3: send 3-byte address, 4: send
* 4-byte address */
uint32_t address:3;
/** 0: don't send mode bits, 1: send mode bits */
uint32_t mode:1;
/** 0: don't send dummy bits, 1: send dummy bits */
uint32_t dummy:1;
/** 0: don't send/recieve data, 1: send/recieve data */
uint32_t data:1;
/** reserved, not used */
uint32_t reserved:25;
} enable;
/** Instruction code */
uint8_t instruction;
/** Mode bits */
uint8_t mode;
/** Number of mode cycles */
uint8_t num_mode_cycles;
/** Number of dummy cycles */
uint8_t num_dummy_cycles;
/** QSPI address */
uint32_t address;
/** Address of the TX buffer */
const void *tx_buffer;
/** Address of the RX buffer */
void *rx_buffer;
/** Size of the RX/TX buffer */
uint32_t buffer_len;
/** Timeout for the command execution, in timer ticks */
uint32_t timeout;
};
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Reset and initialize a QSPI instance.
*
* \param qspi the QSPI instance
*/
void qspi_initialize(Qspi *qspi);
/**
* \brief Configure the baudrate for a QSPI instance.
*
* \param qspi the QSPI instance
* \param baudrate the requested baudrate
* \return the actual baudrate configured (can be lower than requested)
*/
uint32_t qspi_set_baudrate(Qspi *qspi, uint32_t baudrate);
/**
* \brief Perform a QSPI command.
*
* Note that if enable.data is set in the command, data will be sent/recieved:
* - if tx_buffer is not NULL, data will be sent
* - if rx_buffer is not NULL, data will be recieved
* - if both tx_buffer and rx_buffer are NULL, QSPI will be configured in
* "Continuous Read" mode and random read access can be done at the address
* returned by get_qspi_mem_from_addr
*
* \param qspi the QSPI instance
* \param cmd the QSPI command to perform
* \return true if the command was succesfully issued, false otherwise
*/
bool qspi_perform_command(Qspi *qspi, const struct _qspi_cmd *cmd);
#ifdef __cplusplus
}
#endif
#endif /* _QSPI_H_ */

View file

@ -0,0 +1,131 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/** \file */
/*---------------------------------------------------------------------------
* Headers
*---------------------------------------------------------------------------*/
#include "chip.h"
#include "peripherals/rstc.h"
/*---------------------------------------------------------------------------
* Exported functions
*---------------------------------------------------------------------------*/
/**
* Configure the mode of the RSTC peripheral.
* The configuration is computed by the lib (RSTC_RMR_*).
* \param mr Desired mode configuration.
*/
void rstc_configure_mode(uint32_t mr)
{
RSTC->RSTC_MR = (mr & ~RSTC_MR_KEY_Msk) | RSTC_MR_KEY_PASSWD;
}
/**
* Enable/Disable the detection of a low level on the pin NRST as User Reset
* \param enable 1 to enable & 0 to disable.
*/
void rstc_set_user_reset_enable(uint8_t enable)
{
uint32_t mr = RSTC->RSTC_MR;
if (enable) {
mr |= RSTC_MR_URSTEN;
} else {
mr &= ~RSTC_MR_URSTEN;
}
RSTC->RSTC_MR = mr | RSTC_MR_KEY_PASSWD;
}
/**
* Enable/Disable the interrupt of a User Reset (USRTS bit in RSTC_RST).
* \param enable 1 to enable & 0 to disable.
*/
void rstc_set_user_reset_interrupt_enable(uint8_t enable)
{
uint32_t mr = RSTC->RSTC_MR;
if (enable) {
mr |= RSTC_MR_URSTIEN;
} else {
mr &= ~RSTC_MR_URSTIEN;
}
RSTC->RSTC_MR = mr | RSTC_MR_KEY_PASSWD;
}
/**
* Resets the processor.
*/
void rstc_processor_reset(void)
{
RSTC->RSTC_CR = RSTC_CR_PROCRST | RSTC_MR_KEY_PASSWD;
}
/**
* Resets the peripherals.
*/
void rstc_peripheral_reset(void)
{
RSTC->RSTC_CR = RSTC_CR_PERRST | RSTC_MR_KEY_PASSWD;
}
/**
* Return NRST pin level ( 1 or 0 ).
*/
uint8_t rstc_get_nrst_level(void)
{
return (RSTC->RSTC_SR & RSTC_SR_NRSTL) != 0;
}
/**
* Returns 1 if at least one high-to-low transition of NRST (User Reset) has
* been detected since the last read of RSTC_RSR.
*/
uint8_t rstc_is_user_reset_detected(void)
{
return (RSTC->RSTC_SR & RSTC_SR_URSTS) != 0;
}
/**
* Return 1 if a software reset command is being performed by the reset
* controller. The reset controller is busy.
*/
uint8_t rstc_is_busy(void)
{
return (RSTC->RSTC_SR & RSTC_SR_SRCMP) != 0;
}
/**
* Get the status
*/
uint32_t rstc_get_status(void)
{
return RSTC->RSTC_SR;
}

View file

@ -0,0 +1,53 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
#ifndef _RSTC_H
#define _RSTC_H
/*---------------------------------------------------------------------------
* Includes
*---------------------------------------------------------------------------*/
#include <stdint.h>
/*---------------------------------------------------------------------------
* Exported functions
*---------------------------------------------------------------------------*/
extern void rstc_configure_mode(uint32_t rmr);
extern void rstc_set_user_reset_enable(uint8_t enable);
extern void rstc_set_user_reset_interrupt_enable(uint8_t enable);
extern void rstc_processor_reset(void);
extern void rstc_peripheral_reset(void);
extern uint8_t rstc_get_nrst_level(void);
extern uint8_t rstc_is_user_reset_detected(void);
extern uint8_t rstc_is_busy(void);
extern uint32_t rstc_get_status(void);
#endif /* #ifndef _RSTC_H */

View file

@ -0,0 +1,554 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/** \addtogroup rtc_module Working with RTC
* \section Purpose
* The RTC driver provides the interface to configure and use the RTC
* peripheral.
*
* It manages date, time, and alarms.\n
* This timer is clocked by the 32kHz system clock, and is not impacted by
* power management settings (PMC). To be accurate, it is better to use an
* external 32kHz crystal instead of the internal 32kHz RC.\n
*
* It uses BCD format, and time can be set in AM/PM or 24h mode through a
* configuration bit in the mode register.\n
*
* To update date or time, the user has to follow these few steps :
* <ul>
* <li>Set UPDTIM and/or UPDCAL bit(s) in RTC_CR,</li>
* <li>Polling or IRQ on the ACKUPD bit of RTC_CR,</li>
* <li>Clear ACKUPD bit in RTC_SCCR,</li>
* <li>Update Time and/or Calendar values in RTC_TIMR/RTC_CALR (BCD format),</li>
* <li>Clear UPDTIM and/or UPDCAL bit in RTC_CR.</li>
* </ul>
* An alarm can be set to happen on month, date, hours, minutes or seconds,
* by setting the proper "Enable" bit of each of these fields in the Time and
* Calendar registers.
* This allows a large number of configurations to be available for the user.
* Alarm occurence can be detected even by polling or interrupt.
*
* A check of the validity of the date and time format and values written by the user is automatically done.
* Errors are reported through the Valid Entry Register.
*
* \section Usage
* <ul>
* <li> Enable & disable RTC interrupt using rtc_enable_it() and rtc_disable_it().
* <li> Set RTC data, time, alarm using rtc_set_date(), rtc_set_time(),
* rtc_set_time_alarm() and rtc_set_date_alarm().
* <li> Get RTC data, time using rtc_get_date() and rtc_get_time().
* </li>
* </ul>
*
* For more accurate information, please look at the RTC section of the
* Datasheet.
*
* Related files :\n
* \ref rtc.c\n
* \ref rtc.h.\n
*/
/*@{*/
/*@}*/
/**
* \file
*
* Implementation of Real Time Clock (RTC) controller.
*
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include "peripherals/rtc.h"
#include "trace.h"
#include <stdint.h>
#include <assert.h>
/*----------------------------------------------------------------------------
* Local Defines
*----------------------------------------------------------------------------*/
/* The BCD code shift value */
#define BCD_SHIFT 4
/* The BCD code mask value */
#define BCD_MASK 0xfu
/* The BCD mul/div factor value */
#define BCD_FACTOR 10
/*----------------------------------------------------------------------------
* Local Types
*----------------------------------------------------------------------------*/
struct rtc_ppm_lookup {
int8_t tempr;
int16_t ppm;
uint8_t negppm;
uint8_t highppm;
uint16_t correction;
};
//------------------------------------------------------------------------------
// Local constants
//------------------------------------------------------------------------------
static const struct rtc_ppm_lookup ppm_lookup[] = {
{-40, -168, 0, 1, 22},
{-39, -163, 0, 1, 23},
{-38, -158, 0, 1, 24},
{-37, -153, 0, 1, 25},
{-36, -148, 0, 1, 25},
{-35, -143, 0, 1, 26},
{-34, -138, 0, 1, 27},
{-33, -134, 0, 1, 28},
{-32, -129, 0, 1, 29},
{-31, -124, 0, 1, 31},
{-30, -120, 0, 1, 32},
{-29, -116, 0, 1, 33},
{-28, -111, 0, 1, 34},
{-27, -107, 0, 1, 36},
{-26, -103, 0, 1, 37},
{-25, -99, 0, 1, 38},
{-24, -95, 0, 1, 40},
{-23, -91, 0, 1, 42},
{-22, -87, 0, 1, 44},
{-21, -84, 0, 1, 45},
{-20, -80, 0, 1, 48},
{-19, -76, 0, 1, 50},
{-18, -73, 0, 1, 53},
{-17, -70, 0, 1, 55},
{-16, -66, 0, 1, 58},
{-15, -63, 0, 1, 61},
{-14, -60, 0, 1, 64},
{-13, -57, 0, 1, 68},
{-12, -54, 0, 1, 71},
{-11, -51, 0, 1, 76},
{-10, -48, 0, 1, 80},
{-9, -45, 0, 1, 86},
{-8, -43, 0, 1, 90},
{-7, -40, 0, 1, 97},
{-6, -37, 0, 1, 105},
{-5, -35, 0, 1, 111},
{-4, -33, 0, 1, 117},
{-3, -30, 0, 0, 6},
{-2, -28, 0, 0, 6},
{-1, -26, 0, 0, 7},
{0, -24, 0, 0, 7},
{1, -22, 0, 0, 8},
{2, -20, 0, 0, 9},
{3, -18, 0, 0, 10},
{4, -17, 0, 0, 10},
{5, -15, 0, 0, 12},
{6, -13, 0, 0, 14},
{7, -12, 0, 0, 15},
{8, -11, 0, 0, 17},
{9, -9, 0, 0, 21},
{10, -8, 0, 0, 23},
{11, -7, 0, 0, 27},
{12, -6, 0, 0, 32},
{13, -5, 0, 0, 38},
{14, -4, 0, 0, 48},
{15, -3, 0, 0, 64},
{16, -2, 0, 0, 97},
{17, -2, 0, 0, 97},
{18, -1, 0, 0, 127},
{19, 0, 1, 0, 0},
{20, 0, 1, 0, 0},
{21, 0, 1, 0, 0},
{22, 1, 1, 0, 127},
{23, 1, 1, 0, 127},
{24, 1, 1, 0, 127},
{25, 1, 1, 0, 127},
{26, 1, 1, 0, 127},
{27, 1, 1, 0, 127},
{28, 1, 1, 0, 127},
{29, 0, 1, 0, 0},
{30, 0, 1, 0, 0},
{31, 0, 1, 0, 0},
{32, -1, 0, 0, 127},
{33, -2, 0, 0, 97},
{34, -2, 0, 0, 97},
{35, -3, 0, 0, 64},
{36, -4, 0, 0, 48},
{37, -5, 0, 0, 38},
{38, -6, 0, 0, 32},
{39, -7, 0, 0, 27},
{40, -8, 0, 0, 23},
{41, -9, 0, 0, 21},
{42, -11, 0, 0, 17},
{43, -12, 0, 0, 15},
{44, -13, 0, 0, 14},
{45, -15, 0, 0, 12},
{46, -17, 0, 0, 10},
{47, -18, 0, 0, 10},
{48, -20, 0, 0, 9},
{49, -22, 0, 0, 8},
{50, -24, 0, 0, 7},
{51, -26, 0, 0, 7},
{52, -28, 0, 0, 6},
{53, -30, 0, 0, 6},
{54, -33, 0, 1, 117},
{55, -35, 0, 1, 111},
{56, -37, 0, 1, 105},
{57, -40, 0, 1, 97},
{58, -43, 0, 1, 90},
{59, -45, 0, 1, 86},
{60, -48, 0, 1, 80},
{61, -51, 0, 1, 76},
{62, -54, 0, 1, 71},
{63, -57, 0, 1, 68},
{64, -60, 0, 1, 64},
{65, -63, 0, 1, 61},
{66, -66, 0, 1, 58},
{67, -70, 0, 1, 55},
{68, -73, 0, 1, 53},
{69, -76, 0, 1, 50},
{70, -80, 0, 1, 48},
{71, -84, 0, 1, 45},
{72, -87, 0, 1, 44},
{73, -91, 0, 1, 42},
{74, -95, 0, 1, 40},
{75, -99, 0, 1, 38},
{76, -103, 0, 1, 37},
{77, -107, 0, 1, 36},
{78, -111, 0, 1, 34},
{79, -116, 0, 1, 33},
{80, -120, 0, 1, 32},
{81, -124, 0, 1, 31},
{82, -129, 0, 1, 29},
{83, -134, 0, 1, 28},
{84, -138, 0, 1, 27},
{85, -143, 0, 1, 26}
};
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/**
* \brief Sets the RTC in either 12 or 24 hour mode.
*
* \param dwMode Hour mode.
*/
void rtc_set_hour_mode(uint32_t mode)
{
assert((mode & 0xFFFFFFFE) == 0);
RTC->RTC_MR = mode;
}
extern uint32_t rtc_get_hour_mode(void)
{
uint32_t mode;
mode = RTC->RTC_MR;
mode &= 0xFFFFFFFE;
return mode;
}
void rtc_enable_it(uint32_t sources)
{
assert((sources & (uint32_t) (~0x1F)) == 0);
RTC->RTC_IER = sources;
}
void rtc_disable_it(uint32_t sources)
{
assert((sources & (uint32_t) (~0x1F)) == 0);
RTC->RTC_IDR = sources;
}
uint32_t rtc_set_time(struct _time *time)
{
uint32_t ltime = 0;
uint8_t hour_bcd , min_bcd, sec_bcd;
/* if 12-hour mode, set AMPM bit */
if ((RTC->RTC_MR & RTC_MR_HRMOD) == RTC_MR_HRMOD) {
if (time->hour > 12) {
time->hour -= 12;
ltime |= RTC_TIMR_AMPM;
}
}
hour_bcd = (time->hour % 10) | ((time->hour / 10) << 4);
min_bcd = (time->min % 10) | ((time->min / 10) << 4);
sec_bcd = (time->sec % 10) | ((time->sec / 10) << 4);
/* value overflow */
if ((hour_bcd & (uint8_t) (~RTC_HOUR_BIT_LEN_MASK)) |
(min_bcd & (uint8_t) (~RTC_MIN_BIT_LEN_MASK)) |
(sec_bcd & (uint8_t) (~RTC_SEC_BIT_LEN_MASK))) {
return 1;
}
ltime = sec_bcd | (min_bcd << 8) | (hour_bcd << 16);
RTC->RTC_CR |= RTC_CR_UPDTIM;
while ((RTC->RTC_SR & RTC_SR_ACKUPD) != RTC_SR_ACKUPD) ;
RTC->RTC_SCCR = RTC_SCCR_ACKCLR;
RTC->RTC_TIMR = ltime;
RTC->RTC_CR &= (uint32_t) (~RTC_CR_UPDTIM);
RTC->RTC_SCCR |= RTC_SCCR_SECCLR;
return (uint32_t) (RTC->RTC_VER & RTC_VER_NVTIM);
}
void rtc_get_time(struct _time *time)
{
uint32_t ltime;
/* Get current RTC time */
ltime = RTC->RTC_TIMR;
while (ltime != RTC->RTC_TIMR) {
ltime = RTC->RTC_TIMR;
}
/* Hour */
time->hour = ((ltime & 0x00300000) >> 20) * 10 + ((ltime & 0x000F0000) >> 16);
if ((ltime & RTC_TIMR_AMPM) == RTC_TIMR_AMPM) {
time->hour += 12;
}
/* Minute */
time->min = ((ltime & 0x00007000) >> 12) * 10 + ((ltime & 0x00000F00) >> 8);
/* Second */
time->sec = ((ltime & 0x00000070) >> 4) * 10 + (ltime & 0x0000000F);
}
uint32_t rtc_set_time_alarm(struct _time *time)
{
uint32_t alarm = 0;
/* Hour */
if (time->hour) {
alarm |= RTC_TIMALR_HOUREN | ((time->hour / 10) << 20) | ((time->hour % 10) << 16);
}
/* Minute */
if (time->min) {
alarm |= RTC_TIMALR_MINEN | ((time->min / 10) << 12) | ((time->min % 10) << 8);
}
/* Second */
if (time->sec) {
alarm |= RTC_TIMALR_SECEN | ((time->sec / 10) << 4) | (time->sec % 10);
}
RTC->RTC_TIMALR = alarm;
return (uint32_t) (RTC->RTC_VER & RTC_VER_NVTIMALR);
}
void rtc_get_date(struct _date *date)
{
uint32_t ldate;
/* Get current date (multiple reads are necessary to insure a stable value) */
do {
ldate = RTC->RTC_CALR;
} while (ldate != RTC->RTC_CALR);
/* Retrieve values */
date->year = (((ldate >> 4) & 0x7) * 1000) + ((ldate & 0xF) * 100)
+ (((ldate >> 12) & 0xF) * 10) + ((ldate >> 8) & 0xF);
date->month = (((ldate >> 20) & 1) * 10) + ((ldate >> 16) & 0xF);
date->day = (((ldate >> 28) & 0x3) * 10) + ((ldate >> 24) & 0xF);
date->week = ((ldate >> 21) & 0x7);
}
uint32_t rtc_set_date(struct _date *date)
{
uint32_t ldate;
uint8_t cent_bcd, year_bcd, month_bcd, day_bcd, week_bcd;
cent_bcd = ((date->year / 100) % 10) | ((date->year / 1000) << 4);
year_bcd = (date->year % 10) | (((date->year / 10) % 10) << 4);
month_bcd = ((date->month % 10) | (date->month / 10) << 4);
day_bcd = ((date->day % 10) | (date->day / 10) << 4);
week_bcd = ((date->week % 10) | (date->week / 10) << 4);
/* value over flow */
if ((cent_bcd & (uint8_t) (~RTC_CENT_BIT_LEN_MASK)) |
(year_bcd & (uint8_t) (~RTC_YEAR_BIT_LEN_MASK)) |
(month_bcd & (uint8_t) (~RTC_MONTH_BIT_LEN_MASK)) |
(week_bcd & (uint8_t) (~RTC_WEEK_BIT_LEN_MASK)) |
(day_bcd & (uint8_t) (~RTC_DATE_BIT_LEN_MASK))
) {
return 1;
}
/* Convert values to date register value */
ldate = cent_bcd | (year_bcd << 8) | (month_bcd << 16) | (week_bcd << 21) | (day_bcd << 24);
/* Update calendar register */
RTC->RTC_CR |= RTC_CR_UPDCAL;
while ((RTC->RTC_SR & RTC_SR_ACKUPD) != RTC_SR_ACKUPD) ;
RTC->RTC_SCCR = RTC_SCCR_ACKCLR;
RTC->RTC_CALR = ldate;
RTC->RTC_CR &= (uint32_t) (~RTC_CR_UPDCAL);
RTC->RTC_SCCR |= RTC_SCCR_SECCLR; /* clear SECENV in SCCR */
return (uint32_t) (RTC->RTC_VER & RTC_VER_NVCAL);
}
uint32_t rtc_set_date_alarm(struct _date *date)
{
uint32_t alarm;
alarm = ((date->month) || (date->day)) ? (0) : (0x01010000);
/* Compute alarm field value */
if (date->month) {
alarm |= RTC_CALALR_MTHEN | ((date->month / 10) << 20) | ((date->month % 10) << 16);
}
if (date->day) {
alarm |= RTC_CALALR_DATEEN | ((date->day / 10) << 28) | ((date->day % 10) << 24);
}
/* Set alarm */
RTC->RTC_CALALR = alarm;
return (uint32_t) (RTC->RTC_VER & RTC_VER_NVCALALR);
}
void rtc_clear_sccr(uint32_t mask)
{
/* Clear all flag bits in status clear command register */
mask &= RTC_SCCR_ACKCLR | RTC_SCCR_ALRCLR | RTC_SCCR_SECCLR |
RTC_SCCR_TIMCLR | RTC_SCCR_CALCLR;
RTC->RTC_SCCR = mask;
}
uint32_t rtc_get_sr(uint32_t mask)
{
return (RTC->RTC_SR) & mask;
}
void rtc_get_tamper_time(struct _time *time, uint8_t reg_num)
{
uint32_t ltime, temp;
/* Get current RTC time */
ltime = RTC->RTC_TS[reg_num].RTC_TSTR;
while (ltime != RTC->RTC_TS[reg_num].RTC_TSTR) {
ltime = RTC->RTC_TS[reg_num].RTC_TSTR;
}
/* Hour */
if (time->hour) {
temp = (ltime & RTC_TSTR_HOUR_Msk) >> RTC_TSTR_HOUR_Pos;
time->hour = (temp >> BCD_SHIFT) * BCD_FACTOR + (temp & BCD_MASK);
if ((ltime & RTC_TSTR_AMPM) == RTC_TSTR_AMPM) {
time->hour += 12;
}
}
/* Minute */
if (time->min) {
temp = (ltime & RTC_TSTR_MIN_Msk) >> RTC_TSTR_MIN_Pos;
time->min = (temp >> BCD_SHIFT) * BCD_FACTOR + (temp & BCD_MASK);
}
/* Second */
if (time->sec) {
temp = (ltime & RTC_TSTR_SEC_Msk) >> RTC_TSTR_SEC_Pos;
time->sec = (temp >> BCD_SHIFT) * BCD_FACTOR + (temp & BCD_MASK);
}
}
void rtc_get_tamper_date(struct _date *date, uint8_t reg_num)
{
uint32_t ldate, cent, temp;
/* Get the current date (multiple reads are to insure a stable value). */
ldate = RTC->RTC_TS[reg_num].RTC_TSDR;
while (ldate != RTC->RTC_TS[reg_num].RTC_TSDR) {
ldate = RTC->RTC_TS[reg_num].RTC_TSDR;
}
/* Retrieve year */
temp = (ldate & RTC_TSDR_CENT_Msk) >> RTC_TSDR_CENT_Pos;
cent = (temp >> BCD_SHIFT) * BCD_FACTOR + (temp & BCD_MASK);
temp = (ldate & RTC_TSDR_YEAR_Msk) >> RTC_TSDR_YEAR_Pos;
date->year = (cent * BCD_FACTOR * BCD_FACTOR) + (temp >> BCD_SHIFT) * BCD_FACTOR + (temp & BCD_MASK);
/* Retrieve month */
temp = (ldate & RTC_TSDR_MONTH_Msk) >> RTC_TSDR_MONTH_Pos;
date->month = (temp >> BCD_SHIFT) * BCD_FACTOR + (temp & BCD_MASK);
/* Retrieve day */
temp = (ldate & RTC_TSDR_DATE_Msk) >> RTC_TSDR_DATE_Pos;
date->day = (temp >> BCD_SHIFT) * BCD_FACTOR + (temp & BCD_MASK);
/* Retrieve week */
date->week= ((ldate & RTC_TSDR_DAY_Msk) >> RTC_TSDR_DAY_Pos);
}
uint32_t rtc_get_tamper_source(uint8_t reg_num)
{
return RTC->RTC_TS[reg_num].RTC_TSSR;
}
uint32_t rtc_get_tamper_event_counter(void)
{
return (RTC->RTC_TS[0].RTC_TSTR & RTC_TSTR_TEVCNT_Msk) >> RTC_TSTR_TEVCNT_Pos;
}
uint8_t rtc_is_tamper_occur_in_backup_mode(uint8_t reg_num)
{
if (RTC->RTC_TS[reg_num].RTC_TSTR & RTC_TSTR_BACKUP) {
return 1;
} else {
return 0;
}
}
void rtc_convert_time_to_hms(struct _time *time, uint32_t count)
{
count = count % 86400;
time->hour = count / 3600;
count -= time->hour * 3600;
time->min = count / 60;
time->sec = count % 60;
}
void rtc_calibration(int32_t current_tempr)
{
uint32_t i, mr;
for (i = 0; i < ARRAY_SIZE(ppm_lookup); i++) {
if (ppm_lookup[i].tempr == current_tempr) {
mr = RTC_MR_CORRECTION(ppm_lookup[i].correction);
mr |= (ppm_lookup[i].highppm << 15);
mr |= (ppm_lookup[i].negppm << 4);
RTC->RTC_MR = mr; // update the calibration value
break;
}
}
}
uint32_t rtc_set_time_event (uint32_t mask)
{
uint32_t reg;
reg = RTC->RTC_CR;
reg &= ~RTC_CR_TIMEVSEL_Msk;
reg |= mask;
RTC->RTC_CR = reg;
return RTC->RTC_CR;
}
uint32_t rtc_set_calendar_event (uint32_t mask)
{
uint32_t reg;
reg = RTC->RTC_CR;
reg &= ~RTC_CR_CALEVSEL_Msk;
reg |= mask;
RTC->RTC_CR = reg;
return RTC->RTC_CR;
}

View file

@ -0,0 +1,305 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2011, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* Interface for Real Time Clock (RTC) controller.
*
*/
#ifndef _RTC_H_
#define _RTC_H_
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include <stdint.h>
/*----------------------------------------------------------------------------
* Definitions
*----------------------------------------------------------------------------*/
#define RTC_HOUR_BIT_LEN_MASK 0x3F
#define RTC_MIN_BIT_LEN_MASK 0x7F
#define RTC_SEC_BIT_LEN_MASK 0x7F
#define RTC_CENT_BIT_LEN_MASK 0x7F
#define RTC_YEAR_BIT_LEN_MASK 0xFF
#define RTC_MONTH_BIT_LEN_MASK 0x1F
#define RTC_DATE_BIT_LEN_MASK 0x3F
#define RTC_WEEK_BIT_LEN_MASK 0x07
struct _time
{
uint8_t hour;
uint8_t min;
uint8_t sec;
} ;
struct _date
{
uint16_t year;
uint8_t month;
uint8_t day;
uint8_t week;
} ;
#ifdef CONFIG_SOC_SAMA5D2
/* -------- RTC_TSTR : (RTC Offset: N/A) TimeStamp Time Register 0 -------- */
#define RTC_TSTR_SEC_Pos 0
#define RTC_TSTR_SEC_Msk (0x7fu << RTC_TSTR_SEC_Pos) /**< \brief (RTC_TSTR) SEConds of the tamper */
#define RTC_TSTR_MIN_Pos 8
#define RTC_TSTR_MIN_Msk (0x7fu << RTC_TSTR_MIN_Pos) /**< \brief (RTC_TSTR) MINutes of the tamper */
#define RTC_TSTR_HOUR_Pos 16
#define RTC_TSTR_HOUR_Msk (0x3fu << RTC_TSTR_HOUR_Pos) /**< \brief (RTC_TSTR) HOURs of the tamper */
#define RTC_TSTR_AMPM (0x1u << 22) /**< \brief (RTC_TSTR) AMPM indicator of the tamper */
#define RTC_TSTR_TEVCNT_Pos 24
#define RTC_TSTR_TEVCNT_Msk (0xfu << RTC_TSTR_TEVCNT_Pos) /**< \brief (RTC_TSTR) Tamper events counter */
#define RTC_TSTR_BACKUP (0x1u << 31) /**< \brief (RTC_TSTR) system mode of the tamper */
/* -------- RTC_TSDR : (RTC Offset: N/A) TimeStamp Date Register 0 -------- */
#define RTC_TSDR_CENT_Pos 0
#define RTC_TSDR_CENT_Msk (0x7fu << RTC_TSDR_CENT_Pos) /**< \brief (RTC_TSDR) Century of the tamper */
#define RTC_TSDR_YEAR_Pos 8
#define RTC_TSDR_YEAR_Msk (0xffu << RTC_TSDR_YEAR_Pos) /**< \brief (RTC_TSDR) Year of the tamper */
#define RTC_TSDR_MONTH_Pos 16
#define RTC_TSDR_MONTH_Msk (0x1fu << RTC_TSDR_MONTH_Pos) /**< \brief (RTC_TSDR) Month of the tamper */
#define RTC_TSDR_DAY_Pos 21
#define RTC_TSDR_DAY_Msk (0x7u << RTC_TSDR_DAY_Pos) /**< \brief (RTC_TSDR) Day of the tamper */
#define RTC_TSDR_DATE_Pos 24
#define RTC_TSDR_DATE_Msk (0x3fu << RTC_TSDR_DATE_Pos) /**< \brief (RTC_TSDR) Date of the tamper */
#endif
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Sets the RTC in either 12 or 24 hour mode.
*
* \param mode Hour mode.
*/
extern void rtc_set_hour_mode(uint32_t mode);
/**
* \brief Gets the RTC mode.
*
* \return Hour mode.
*/
extern uint32_t rtc_get_hour_mode(void);
/**
* \brief Enables the selected interrupt sources of the RTC.
*
* \param sources Interrupt sources to enable.
*/
extern void rtc_enable_it(uint32_t sources);
/**
* \brief Disables the selected interrupt sources of the RTC.
*
* \param sources Interrupt sources to disable.
*/
extern void rtc_disable_it(uint32_t sources);
/**
* \brief Sets the current time in the RTC.
*
* \note In successive update operations, the user must wait at least one second
* after resetting the UPDTIM/UPDCAL bit in the RTC_CR before setting these
* bits again. Please look at the RTC section of the datasheet for detail.
*
* \param time Pointer to structure time
*
* \return 0 sucess, 1 fail to set
*/
extern uint32_t rtc_set_time(struct _time *time);
/**
* \brief Retrieves the current time as stored in the RTC in several variables.
*
* \param time Pointer to structure time
*/
extern void rtc_get_time(struct _time *time);
/**
* \brief Sets a time alarm on the RTC.
* The match is performed only on the provided variables;
* Setting all pointers to 0 disables the time alarm.
*
* \note In AM/PM mode, the hour value must have bit #7 set for PM, cleared for
* AM (as expected in the time registers).
*
* \param time Pointer to structure time.
*
* \return 0 success, 1 fail to set
*/
extern uint32_t rtc_set_time_alarm(struct _time *time);
/**
* \brief Retrieves the current year, month and day from the RTC.
* Month, day and week values are numbered starting at 1.
*
* \param date Pointer to structure Date.
*/
extern void rtc_get_date(struct _date *date);
/**
* \brief Sets the current year, month and day in the RTC.
* Month, day and week values must be numbered starting from 1.
*
* \note In successive update operations, the user must wait at least one second
* after resetting the UPDTIM/UPDCAL bit in the RTC_CR before setting these
* bits again. Please look at the RTC section of the datasheet for detail.
*
* \param date Pointer to structure Date
*
* \return 0 success, 1 fail to set
*/
extern uint32_t rtc_set_date(struct _date *date);
/**
* \brief Sets a date alarm in the RTC.
* The alarm will match only the provided values;
* Passing a null-pointer disables the corresponding field match.
*
* \param pucMonth If not null, the RTC alarm will month-match this value.
* \param pucDay If not null, the RTC alarm will day-match this value.
*
* \return 0 success, 1 fail to set
*/
extern uint32_t rtc_set_date_alarm(struct _date *date);
/**
* \brief Clear flag bits of status clear command register in the RTC.
*
* \param mask Bits mask of cleared events
*/
extern void rtc_clear_sccr(uint32_t mask);
/**
* \brief Get flag bits of status register in the RTC.
*
* \param mask Bits mask of Status Register
*
* \return Status register & mask
*/
extern uint32_t rtc_get_sr(uint32_t mask);
/**
* \brief Get the RTC tamper time value.
*
* \note This function should be called before rtc_get_tamper_source()
* function call, Otherwise the tamper time will be cleared.
*
* \param time Pointer to structure Time.
* \param reg_num Tamper register set number.
*/
extern void rtc_get_tamper_time(struct _time *time, uint8_t reg_num);
/**
* \brief Get the RTC tamper date.
*
* \note This function should be called before rtc_get_tamper_source()
* function call, Otherwise the tamper date will be cleared.
*
* \param date Pointer to structure Date
* \param reg_num Tamper register set number.
*/
extern void rtc_get_tamper_date(struct _date *date, uint8_t reg_num);
/**
* \brief Get the RTC tamper source.
*
* \param reg_num Current tamper register set number.
*
* \return Tamper source.
*/
extern uint32_t rtc_get_tamper_source(uint8_t reg_num);
/**
* \brief Get the RTC tamper event counter.
*
* \note This function should be called before rtc_get_tamper_source()
* function call, Otherwise the tamper event counter will be cleared.
*
* \return Tamper event counter
*/
extern uint32_t rtc_get_tamper_event_counter(void);
/**
* \brief Check the system is in backup mode when RTC tamper event happen.
*
* \note This function should be called before rtc_get_tamper_source()
* function call, Otherwise the flag indicates tamper occur in backup
* mode will be cleared.
*
* \param reg_num Current tamper register set number.
*
* \return 1 - The system is in backup mode when the tamper event occurs.
* 0 - The system is different from backup mode.
*/
extern uint8_t rtc_is_tamper_occur_in_backup_mode(uint8_t reg_num);
/**
* \brief Convert number of second (count) to HMS format.
*
*/
extern void rtc_convert_time_to_hms (struct _time *time, uint32_t count);
/**
* \brief RTC calibration for Temperature or PPM drift
*/
extern void rtc_calibration(int32_t current_tempr);
/**
* \brief Set calendar event selection.
*
* \param mask Bits CALEVSEL of Control Register
* \return Status register & mask
*/
extern uint32_t rtc_set_calendar_event (uint32_t mask);
/**
* \brief Set time event selection.
*
* \param mask Bits TIMEVSEL of Control Register
* \return Status register & mask
*/
extern uint32_t rtc_set_time_event (uint32_t maskask);
#ifdef __cplusplus
}
#endif
#endif /* _RTC_H_ */

View file

@ -0,0 +1,109 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
#ifndef _SDMMC_PERIPH_H_
#define _SDMMC_PERIPH_H_
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#ifdef __cplusplus
extern "C" {
#endif
struct _SdmmcCommand;
/*----------------------------------------------------------------------------
* Definitions
*----------------------------------------------------------------------------*/
/* This structure is private to the SDMMC Driver.
* Allocate it but ignore its members. */
struct sdmmc_set
{
uint32_t id; /* SDMMC peripheral ID (ID_SDMMCx) */
Sdmmc *regs; /* set of SDMMC hardware registers */
uint32_t tc_id; /* Timer/Counter peripheral ID (ID_TCx) */
TcChannel *timer; /* set of TC channel hardware registers */
uint32_t *table; /* ADMA descriptor table, or NULL when DMA
* is not used */
uint32_t table_size; /* Max size of the ADMA descriptor table,
* in lines */
bool use_polling; /* polling mode */
bool use_set_blk_cnt; /* implicit SET_BLOCK_COUNT command */
uint16_t blk_size; /* max data block size, in bytes */
uint32_t dev_freq; /* frequency of clock provided to memory
* device, in Hz */
volatile uint8_t state;
struct _SdmmcCommand *cmd; /* pointer to the command being processed */
uint16_t blk_index; /* count of data blocks tranferred already,
* in the context of the command and data
* transfer being executed */
uint8_t resp_len; /* size of the response, once retrieved,
* in the context of the command being
* executed, expressed in 32-bit words */
bool expect_auto_end; /* waiting for completion of Auto CMD12 */
};
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/**
* \brief Initialize the specified driver instance and the associated SDMMC
* peripheral.
* \param set Pointer to uninitialized driver instance data.
* \param regs Base address of registers of the SDMMC peripheral.
* \param sdmmc_id SDMMC peripheral ID (ID_SDMMCx).
* \param tc_id TC peripheral ID (ID_TCx).
* \note The application shall have enabled the clock assigned to this
* Timer/Counter peripheral.
* \param tc_ch TC channel number, within the Timer/Counter module designated
* by tc_id. Every instance of the SDMMC Driver requires a Timer/Counter channel
* for its exclusive usage.
* \param dma_buf Buffer allocated by the application, required when DMA is
* used. This is where the DMA descriptor table will be set up. The larger
* the buffer is, the greater throughput we achieve. Up to 4 KiB. Shall be
* word-aligned. NULL to have the CPU read/write data, word by word.
* \param dma_buf_size Size of the dma_buf buffer, in words.
* \return true if successful, false if a parameter is assigned an unsupported
* value.
*/
bool sdmmc_initialize(struct sdmmc_set *set, Sdmmc *regs, uint32_t sdmmc_id,
uint32_t tc_id, uint32_t tc_ch, uint32_t *dma_buf, uint32_t dma_buf_size);
#ifdef __cplusplus
}
#endif
#endif /* #ifndef _SDMMC_PERIPH_H_ */

View file

@ -0,0 +1,56 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "peripherals/sfrbu.h"
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
void sfrbu_enable_ddr_backup(void)
{
/* Enable DDR backup mode. Isolate the DDR Pads from the CPU domain,
VCCCORE */
SFRBU->SFRBU_DDRBUMCR = SFRBU_DDRBUMCR_BUMEN;
}
void sfrbu_disable_ddr_backup(void)
{
/* Connect the DDR Pads to the CPU domain, VCCCORE */
SFRBU->SFRBU_DDRBUMCR &= ~SFRBU_DDRBUMCR_BUMEN;
}
bool sfrbu_is_ddr_backup_enabled(void)
{
return (SFRBU->SFRBU_DDRBUMCR & SFRBU_DDRBUMCR_BUMEN) != 0;
}

View file

@ -0,0 +1,62 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
#ifndef _SFRBU_H
#define _SFRBU_H
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include <stdbool.h>
#include <stdint.h>
/*----------------------------------------------------------------------------
* Global functions
*----------------------------------------------------------------------------*/
/**
* \brief Enable DDR backup
*/
extern void sfrbu_enable_ddr_backup(void);
/**
* \brief Disable DDR backup
*/
extern void sfrbu_disable_ddr_backup(void);
/**
* \brief Get DDR backup status
* \return true if DDR BU Mode is enabled, false otherwise
*/
extern bool sfrbu_is_ddr_backup_enabled(void);
#endif //#ifndef _SFRBU_H

View file

@ -0,0 +1,135 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/** \addtogroup sha_module Working with SHA
* \ingroup peripherals_module
* The SHA driver provides the interface to configure and use the SHA
* peripheral.
* \n
*
* The Secure Hash Algorithm (SHA) module requires a padded message
* according to FIPS180-2 specification. The first block of the
* message must be indicated to the module by a specific command. The
* SHA module produces a N-bit message digest each time a block is
* written and processing period ends. N is 160 for SHA1, 224 for
* SHA224, 256 for SHA256, 384 for SHA384, 512 for SHA512.
*
* To Enable a SHA encryption and decrypt,the user has to follow these
* few steps:
* <ul>
* <li> Configure SHA algorithm mode, key mode, start mode and
* operation mode by sha_configure(). </li>
* <li> Set sha_first_block() to indicates that the next block to
* process is the first one of a message.</li>
* <li> Input data for encryption by sha_set_input(). </li>
* <li> To start the encryption process with sha_start()</li>
* <li> To get the encryption reslut by sha_get_output() </li>
* </ul>
*
* For more accurate information, please look at the SHA section of the
* Datasheet.
*
* Related files :\n
* \ref sha.c\n
* \ref sha.h\n
*/
/*@{*/
/*@}*/
/**
* \file
*
* Implementation of Secure Hash Algorithm (SHA)
*
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include "peripherals/sha.h"
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
void sha_start(void)
{
SHA->SHA_CR = SHA_CR_START;
}
void sha_soft_reset(void)
{
SHA->SHA_CR = SHA_CR_SWRST;
}
void sha_first_block(void)
{
SHA->SHA_CR = SHA_CR_FIRST;
}
void sha_configure(uint32_t mode)
{
SHA->SHA_MR = mode;
}
void sha_enable_it(uint32_t sources)
{
SHA->SHA_IER = sources;
}
void sha_disable_it(uint32_t sources)
{
SHA->SHA_IDR = sources;
}
uint32_t sha_get_status(void)
{
return SHA->SHA_ISR;
}
void sha_set_input(uint32_t * data, uint8_t len)
{
uint8_t i;
uint8_t num;
num = len <= 16 ? len : 16;
for (i = 0; i < num; i++)
SHA->SHA_IDATAR[i] = (data[i]);
num = len > 16 ? len - 16 : 0;
for (i = 0; i < num; i++)
SHA->SHA_IODATAR[i] = (data[i + 16]);
}
void sha_get_output(uint32_t * data)
{
uint8_t i;
for (i = 0; i < 16; i++)
data[i] = SHA->SHA_IODATAR[i];
}

View file

@ -0,0 +1,98 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
#ifndef _SHA_
#define _SHA_
/*------------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
/*----------------------------------------------------------------------------*/
/* Exported functions */
/*----------------------------------------------------------------------------*/
/**
* \brief Starts Manual hash algorithm process.
*/
extern void sha_start(void);
/**
* \brief Resets the SHA. A software triggered hardware reset of the
* SHA interface is performed.
*/
extern void sha_soft_reset(void);
/**
* \brief Indicates that the next block to process is the first one of
* a message.
*/
extern void sha_first_block(void);
/**
* \brief Configures an SHA peripheral with the specified parameters.
* \param mode Desired value for the SHA mode register (see the datasheet).
*/
extern void sha_configure(uint32_t mode);
/**
* \brief Enables the selected interrupts sources on a SHA peripheral.
* \param sources Bitwise OR of selected interrupt sources.
*/
extern void sha_enable_it(uint32_t sources);
/**
* \brief Disables the selected interrupts sources on a SHA peripheral.
* \param sources Bitwise OR of selected interrupt sources.
*/
extern void sha_disable_it(uint32_t sources);
/**
* \brief Get the current status register of the given SHA peripheral.
* \return SHA status register.
*/
extern uint32_t sha_get_status(void);
/**
* \brief Set the 32-bit Input Data registers allow to load the data block used for hash processing.
* \param data Pointer data block.
* \param len 512/1024-bits block size
*/
extern void sha_set_input(uint32_t * data, uint8_t len);
/**
* \brief Getread the resulting message digest and to write the second part of the message block when the
* SHA algorithm is SHA-384 or SHA-512.
* \param data pointer to the word that has been encrypted/decrypted..
*/
extern void sha_get_output(uint32_t * data);
#endif /* #ifndef _SHA_ */

View file

@ -0,0 +1,100 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include "peripherals/shdwc.h"
#include <stdint.h>
/*----------------------------------------------------------------------------
* Local Defines
*----------------------------------------------------------------------------*/
struct _bitfield_shdwc_cfgr {
uint32_t
lpdbcen0: 1,
lpdbcen1: 1,
rfu2_7: 6,
lpdbc: 3,
rfu10_15: 5,
rttwken: 1,
rtcwken: 1,
accwken: 1,
rxlpwken: 1,
rfu20_23: 4,
wkupdbc: 3,
rfu26_31: 5;
};
union _shdwc_cfg {
struct _bitfield_shdwc_cfgr bfield;
uint32_t uint32_value;
};
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
void shdwc_configure_wakeup_mode(uint32_t config)
{
union _shdwc_cfg cfg;
cfg.uint32_value = SHDWC->SHDW_MR;
cfg.bfield.lpdbcen0 = (config & SHDW_MR_LPDBCEN0_ENABLE) ? 1 : 0;
cfg.bfield.lpdbcen1 = (config & SHDW_MR_LPDBCEN1_ENABLE) ? 1 : 0;
cfg.bfield.lpdbc = (config & SHDW_MR_LPDBC_Msk) >> SHDW_MR_LPDBC_Pos;
cfg.bfield.rttwken = (config & SHDW_MR_RTTWKEN) ? 1 : 0;
cfg.bfield.rtcwken = (config & SHDW_MR_RTCWKEN) ? 1 : 0;
cfg.bfield.accwken = (config & SHDW_MR_ACCWKEN) ? 1 : 0;
cfg.bfield.rxlpwken = (config & SHDW_MR_RXLPWKEN) ? 1 : 0;
cfg.bfield.wkupdbc = (config & SHDW_MR_WKUPDBC_Msk) >> SHDW_MR_WKUPDBC_Pos;
SHDWC->SHDW_MR = cfg.uint32_value;
}
void shdwc_set_wakeup_input(uint32_t input_enable, uint32_t input_type)
{
uint32_t wuir = (input_enable & 0x0000FFFF) | (input_type & 0xFFFF0000);
SHDWC->SHDW_WUIR |= wuir;
}
void shdwc_do_shutdown(void)
{
SHDWC->SHDW_CR = SHDW_CR_KEY_PASSWD | SHDW_CR_SHDW;
}
uint32_t shdwc_get_status(void)
{
return SHDWC->SHDW_SR;
}

View file

@ -0,0 +1,72 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
#ifndef _SHDWC_H
#define _SHDWC_H
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include <stdint.h>
/*----------------------------------------------------------------------------
* Global functions
*----------------------------------------------------------------------------*/
/**
* \brief Configure the Shutdown Mode Register
*/
extern void shdwc_configure_wakeup_mode(uint32_t config);
/**
* \brief Configure the Shutdown Wake-up Input Register
*
* \param input_enable, WKUPEN0-WKUPEN15: define the corresponding
* wake-up input.
* \param input_type, WKUPT0-WKUPT15: define falling or rising edge
* on wake-up input.
*/
extern void shdwc_set_wakeup_input(uint32_t input_enable,
uint32_t input_type);
/**
* \brief Launch the ShutDown
*/
extern void shdwc_do_shutdown(void);
/**
* \brief Get Status
* \return Contents of the Shutdown Status Register
*/
extern uint32_t shdwc_get_status(void);
#endif //#ifndef _SHDWC_H

View file

@ -0,0 +1,451 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/** \addtogroup spi_module Working with SPI
* \section Purpose
* The SPI driver provides the interface to configure and use the SPI
* peripheral.
*
* The Serial Peripheral Interface (SPI) circuit is a synchronous serial
* data link that provides communication with external devices in Master
* or Slave Mode.
*
* \section Usage
* To use the SPI, the user has to follow these few steps:
* -# Enable the SPI pins required by the application (see pio.h).
* -# Configure the SPI using the \ref spi_configure(). This enables the
* peripheral clock. The mode register is loaded with the given value.
* -# Configure all the necessary chip selects with \ref spi_configure_npcs().
* -# Enable the SPI by calling \ref spi_enable().
* -# Send/receive data using \ref spi_write() and \ref
* spi_read(). Note that \ref spi_read()
* must be called after \ref spi_write() to retrieve the last value read.
* -# Disable the SPI by calling \ref spi_disable().
*
* For more accurate information, please look at the SPI section of the
* Datasheet.
*
* Related files :\n
* \ref spi.c\n
* \ref spi.h\n
*/
/*@{*/
/*@}*/
/**
* \file
*
* Implementation of Serial Peripheral Interface (SPI) controller.
*
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include "peripherals/spi.h"
#include "peripherals/pmc.h"
#include "io.h"
#include "trace.h"
#include <stdint.h>
#include <assert.h>
/*---------------------------------------------------------------------------
* Macros
*----------------------------------------------------------------------------*/
#define SPI_PCS(npcs) SPI_MR_PCS((~(1 << npcs) & 0xF))
/*----------------------------------------------------------------------------
* local functions
*----------------------------------------------------------------------------*/
static inline uint32_t _spi_compute_scbr(uint32_t bitrate, uint32_t periph_id)
{
assert(bitrate>0);
return SPI_CSR_SCBR(
pmc_get_peripheral_clock(periph_id) / (bitrate*1000));
}
static inline uint32_t _spi_compute_dlybs(uint32_t delay, uint32_t periph_id)
{
uint32_t dlybs =
((pmc_get_peripheral_clock(periph_id)/1000000u) * delay) / 100;
return SPI_CSR_DLYBS(dlybs);
}
static inline uint32_t _spi_compute_dlybct(uint32_t delay, uint32_t periph_id)
{
uint32_t dlybct =
((pmc_get_peripheral_clock(periph_id)/31250u) * delay) / 100;
return SPI_CSR_DLYBCT(dlybct);
}
static inline uint32_t _spi_is_master(Spi* spi)
{
return (spi->SPI_MR & SPI_MR_MSTR);
}
static inline uint32_t _spi_is_variable_ps(Spi* spi)
{
return (spi->SPI_MR & SPI_MR_PS);
}
static void _spi_write_dummy(Spi* spi)
{
if (_spi_is_master(spi)) {
writehw(&spi->SPI_TDR, 0xFF);
}
}
static void _spi_consume_read(Spi* spi, uint32_t cs)
{
if (_spi_is_master(spi)) {
while(!(spi->SPI_SR & SPI_SR_RDRF));
uint16_t value;
if ((spi->SPI_CSR[cs] & SPI_CSR_BITS_Msk) < SPI_CSR_BITS_9_BIT) {
readb(&spi->SPI_RDR, (uint8_t*)&value);
} else {
readhw(&spi->SPI_RDR, &value);
}
(void)value;
}
}
#ifdef CONFIG_HAVE_SPI_FIFO
static void _spi_fifo_clear(Spi* spi, uint32_t fifos)
{
trace_debug("Spi: Clearing FIFOs\r\n");
while (!(spi->SPI_SR & SPI_SR_TXFEF));
spi->SPI_CR = fifos & (SPI_CR_RXFCLR | SPI_CR_TXFCLR);
}
static inline void _clear_fifo_control_flags(uint32_t* control_reg)
{
*control_reg |= SPI_CR_TXFCLR | SPI_CR_RXFCLR | SPI_CR_FIFODIS;
}
#else
#define _clear_fifo_control_flags(dummy) do {} while(0)
#endif
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
void spi_enable(Spi * spi)
{
spi->SPI_CR = SPI_CR_SPIEN;
}
void spi_disable(Spi * spi)
{
spi->SPI_CR = SPI_CR_SPIDIS;
}
void spi_enable_it(Spi * spi, uint32_t dwSources)
{
spi->SPI_IER = dwSources;
}
void spi_disable_it(Spi * spi, uint32_t dwSources)
{
spi->SPI_IDR = dwSources;
}
void spi_configure(Spi * spi, uint32_t configuration)
{
/* Execute a software reset of the SPI twice */
spi->SPI_CR = SPI_CR_SWRST;
spi->SPI_CR = SPI_CR_SWRST;
uint32_t control_reg = SPI_CR_SPIDIS;
/* Add clear FIFO flags if present */
_clear_fifo_control_flags(&control_reg);
/* Apply */
spi->SPI_CR = control_reg;
spi->SPI_MR = configuration;
}
void spi_chip_select(Spi * spi, uint8_t cS)
{
spi->SPI_MR &= ~SPI_MR_PCS_Msk;
spi->SPI_MR |= SPI_PCS(cS);
}
void spi_set_mode(Spi * spi, uint32_t dwConfiguration)
{
spi->SPI_MR = dwConfiguration;
}
void spi_release_cs(Spi * spi)
{
spi->SPI_CR = SPI_CR_LASTXFER;
}
void spi_configure_cs(Spi * spi, uint32_t cs, uint32_t bitrate,
uint32_t delay_dlybs, uint32_t delay_dlybct,
uint32_t spi_mode, uint32_t release_on_last)
{
trace_debug("Spi: configuring chip select %u\r\n", (unsigned int)cs);
uint32_t id = get_spi_id_from_addr(spi);
assert(id < ID_PERIPH_COUNT);
bitrate = _spi_compute_scbr(bitrate, id);
delay_dlybs = _spi_compute_dlybs(delay_dlybs, id);
delay_dlybct = _spi_compute_dlybct(delay_dlybct, id);
release_on_last = release_on_last ? SPI_CSR_CSAAT : 0;
spi->SPI_CSR[cs] = bitrate | delay_dlybs | delay_dlybct
| release_on_last | spi_mode;
}
void spi_configure_cs_mode(Spi * spi, uint32_t cs, uint32_t release_on_last)
{
if (!release_on_last) {
spi->SPI_CSR[cs] |= SPI_CSR_CSAAT;
} else {
spi->SPI_CSR[cs] &= ~SPI_CSR_CSAAT;
}
}
uint32_t spi_get_status(Spi * spi)
{
return spi->SPI_SR;
}
uint16_t spi_read(Spi * spi, uint8_t cs)
{
_spi_write_dummy(spi);
while ((spi->SPI_SR & SPI_SR_RDRF) == 0) ;
uint16_t value;
if ((spi->SPI_CSR[cs] & SPI_CSR_BITS_Msk) < SPI_CSR_BITS_9_BIT) {
readb(&spi->SPI_RDR, (uint8_t*)&value);
} else {
readhw(&spi->SPI_RDR, &value);
}
return value;
}
/**
* \details If the SPI is configured to use a fixed peripheral select,
* the npcs value is meaningless. Otherwise, it identifies the
* component which shall be addressed.
*/
void spi_write(Spi * spi, uint32_t cs, uint16_t data)
{
/* Send data */
while ((spi->SPI_SR & SPI_SR_TXEMPTY) == 0);
if (_spi_is_variable_ps(spi)) {
spi->SPI_TDR = data | SPI_PCS(cs);
} else {
writehw(&spi->SPI_TDR, data);
}
/* Consume write */
_spi_consume_read(spi, cs);
}
/**
* \brief Sends last data through a SPI peripheral.
*
* \details If the SPI is configured to use a fixed peripheral select,
* the npcs value is meaningless. Otherwise, it identifies the
* component which shall be addressed.
*
* \param spi Pointer to an Spi instance.
* \param dwNpcs Chip select of the component to address (0, 1, 2 or 3).
* \param wData Word of data to send.
*/
void spi_write_last(Spi * spi, uint32_t cs, uint16_t data)
{
/* Send data */
while ((spi->SPI_SR & SPI_SR_TXEMPTY) == 0) ;
spi->SPI_TDR = data | SPI_PCS(cs) | SPI_TDR_LASTXFER;
/* Consume write to not corrupt FIFO if present (dummy
* function if CONFIG_HAV_SPI_FIFO not defined) */
_spi_consume_read(spi, cs);
}
uint32_t spi_is_finished(Spi * spi)
{
return ((spi->SPI_SR & SPI_SR_TXEMPTY) != 0);
}
#ifdef CONFIG_HAVE_SPI_FIFO
static void _spi_fifo_set_rx_threshold(Spi* spi, uint8_t rx_thres)
{
spi->SPI_FMR &= ~SPI_FMR_RXFTHRES_Msk;
spi->SPI_FMR |= SPI_FMR_RXFTHRES(rx_thres);
}
static uint32_t _spi_write_stream(Spi *spi, uint32_t chip_select,
const void *stream, uint32_t len)
{
const uint8_t* buffer = stream;
uint32_t left = len;
uint8_t is_ps = _spi_is_variable_ps(spi);
uint32_t max_size = is_ps ? sizeof(uint8_t) : sizeof(uint16_t);
int32_t fifo_size = get_peripheral_fifo_depth(spi);
if (fifo_size < 0)
return 0;
while (left > 0) {
if ((spi->SPI_SR & SPI_SR_TDRE) == 0) continue;
/* Get FIFO free size (int octet) and clamp it */
uint32_t buf_size = fifo_size - spi_fifo_tx_size(spi);
buf_size = (buf_size > left) ? left : buf_size;
/* Fill the FIFO as must as possible */
while (buf_size >= max_size) {
if (is_ps) {
spi->SPI_TDR = *(uint8_t*)buffer |
SPI_PCS(chip_select);
} else {
spi->SPI_TDR = *buffer |
(*(buffer+1) << 16);
}
buffer += max_size;
left -= max_size;
buf_size -= max_size;
}
if (buf_size >= sizeof(uint8_t)) {
writehw(&spi->SPI_TDR, *(uint8_t*)buffer);
buffer += sizeof(uint8_t);
left -= sizeof(uint8_t);
}
}
trace_debug("Spi (fifo): %u data writen\r\n",
(unsigned int)(len-left));
return len - left;
}
void spi_fifo_configure(Spi* spi, uint8_t tx_thres,
uint8_t rx_thres,
uint32_t ready_modes)
{
/* Disable SPI and activate FIFO */
spi->SPI_CR = SPI_CR_SPIDIS | SPI_CR_FIFOEN;
/* Configure FIFO */
spi->SPI_FMR = SPI_FMR_TXFTHRES(tx_thres) | SPI_FMR_RXFTHRES(rx_thres)
| ready_modes;
/* Reenable SPI */
spi->SPI_CR = SPI_CR_SPIEN;
}
void spi_fifo_disable(Spi* spi)
{
uint32_t reg = 0;
_clear_fifo_control_flags(&reg);
spi->SPI_CR = reg;
}
uint32_t spi_fifo_rx_size(Spi *spi)
{
return (spi->SPI_FLR & SPI_FLR_RXFL_Msk) >> SPI_FLR_RXFL_Pos;
}
uint32_t spi_fifo_tx_size(Spi *spi)
{
return (spi->SPI_FLR & SPI_FLR_TXFL_Msk) >> SPI_FLR_TXFL_Pos;
}
uint32_t spi_read_stream(Spi *spi, uint32_t chip_select,
void *stream, uint32_t len)
{
uint8_t* buffer = stream;
uint32_t left = len;
uint8_t is_master = _spi_is_master(spi);
uint32_t max_size = is_master ? sizeof(uint8_t) : sizeof(uint32_t);
while (left > 0) {
uint32_t lenwrite = (left > SPI_FIFO_DEPTH) ?
SPI_FIFO_DEPTH : left;
_spi_fifo_set_rx_threshold(spi, lenwrite);
_spi_write_stream(spi, chip_select,
stream, lenwrite);
while (!(spi->SPI_SR & SPI_SR_RXFTHF));
/* Get FIFO size (in octets) and clamp it */
uint32_t buf_size = spi_fifo_rx_size(spi);
buf_size = buf_size > left ? left : buf_size;
/* Fill the buffer as must as possible with four data reads */
while (buf_size >= max_size) {
if (is_master) {
readb(&spi->SPI_RDR, (uint8_t*)buffer);
} else {
*(uint32_t*)buffer = spi->SPI_RDR;
}
buffer += max_size;
left -= max_size;
buf_size -= max_size;
}
/* Add tail data if stream is not 4 octet aligned */
if (buf_size >= sizeof(uint16_t)) {
/* two data read */
readhw(&spi->SPI_RDR, (uint16_t*)buffer);
left -= sizeof(uint16_t);
buffer += sizeof(uint16_t);
buf_size -= sizeof(uint16_t);
}
if (buf_size >= sizeof(uint8_t)) {
/* two data read */
readb(&spi->SPI_RDR, (uint8_t*)buffer);
left -= sizeof(uint8_t);
buffer += sizeof(uint8_t);
}
}
trace_debug("Spi (fifo): %u data read\r\n",
(unsigned int)(len-left));
return len - left;
}
uint32_t spi_write_stream(Spi *spi, uint32_t chip_select,
const void *stream, uint32_t len)
{
uint32_t consumed = _spi_write_stream(spi, chip_select, stream, len);
_spi_fifo_clear(spi, SPI_CR_RXFCLR);
return consumed;
}
#endif

View file

@ -0,0 +1,214 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* Interface for Serial Peripheral Interface (SPI) controller.
*
*/
#ifndef _SPI_
#define _SPI_
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
/*----------------------------------------------------------------------------
* Macros
*----------------------------------------------------------------------------*/
#define SPI_KEEP_CS_OW (0)
#define SPI_RELEASE_CS_OW (1)
/*------------------------------------------------------------------------------ */
#ifdef __cplusplus
extern "C" {
#endif
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/**
* \brief Enables a SPI peripheral.
*
* \param spi Pointer to an Spi instance.
*/
extern void spi_enable(Spi * spi);
/**
* \brief Disables a SPI peripheral.
*
* \param spi Pointer to an Spi instance.
*/
extern void spi_disable(Spi * spi);
/**
* \brief Enables one or more interrupt sources of a SPI peripheral.
*
* \param spi Pointer to an Spi instance.
* \param dwSources Bitwise OR of selected interrupt sources.
*/
extern void spi_enable_it(Spi * spi, uint32_t dwSources);
/**
* \brief Disables one or more interrupt sources of a SPI peripheral.
*
* \param spi Pointer to an Spi instance.
* \param dwSources Bitwise OR of selected interrupt sources.
*/
extern void spi_disable_it(Spi * spi, uint32_t dwSources);
/**
* \brief Configures a SPI peripheral as specified. The configuration
* can be computed
* using several macros (see \ref spi_configuration_macros).
*
* \param spi Pointer to an Spi instance.
* \param dwConfiguration Value of the SPI configuration register.
*/
extern void spi_configure(Spi * spi, uint32_t configuration);
/**
* \brief Configures SPI Mode Register.
*
* \param spi Pointer to an Spi instance.
* \param dwConfiguration Value of the SPI mode register.
*/
extern void spi_set_mode(Spi * spi, uint32_t dwConfiguration);
/**
* \brief Configures SPI chip select.
*
* \param spi Pointer to an Spi instance.
* \param cS Chip select of NPSCx.
*/
extern void spi_chip_select(Spi * spi, uint8_t cS);
/**
* \brief Configures SPI to release last used CS line.
*
* \param spi Pointer to an Spi instance.
*/
extern void spi_release_cs(Spi * spi);
/**
* \brief Configures a chip select of a SPI peripheral.
*
* \param spi Pointer to an Spi instance.
* \param cs Chip select to configure (0, 1, 2 or 3).
* \param bitrate
* \param delay_dlybs
* \param delay_dlybct
* \param spi_mode
* \param release_on_last
*/
extern void spi_configure_cs(Spi * spi, uint32_t cs,uint32_t bitrate,
uint32_t delay_dlybs, uint32_t delay_dlybct,
uint32_t spi_mode, uint32_t release_on_last);
/**
* \brief Configures a chip select active mode of a SPI peripheral.
*
* \param spi Pointer to an Spi instance.
* \param cs Chip select to configure (0, 1, 2 or 3).
* \param release_on_last CS controlled by last transfer.
* spi_release_cs() is used to deactive CS.
*/
extern void spi_configure_cs_mode(Spi * spi, uint32_t cs,
uint32_t release_on_last);
/**
* \brief Reads one data from SPI peripheral with a dummy write.
*
* \param spi Pointer to an Spi instance.
*
* \return readed data.
*/
extern uint16_t spi_read(Spi * spi, uint8_t cs);
/**
* \brief Sends data through a SPI peripheral consuming reads.
*
*
* \param spi Pointer to an Spi instance.
* \param cs Chip select of the component to address (0, 1, 2 or 3).
* \param data Word of data to send.
*/
extern void spi_write(Spi * spi, uint32_t cs, uint16_t data);
extern void spi_write_last(Spi * spi, uint32_t cs, uint16_t data);
/**
* \brief Get the current status register of the given SPI peripheral.
*
* \note This resets the internal value of the status register, so further
* read may yield different values.
*
* \param spi Pointer to a Spi instance.
* \return SPI status register.
*/
extern uint32_t spi_get_status(Spi * spi);
/**
* \brief Check if SPI transfer finish.
*
* \param spi Pointer to an Spi instance.
*
* \return Returns 1 if there is no pending write operation on the SPI;
* otherwise returns 0.
*/
extern uint32_t spi_is_finished(Spi * spi);
#ifdef CONFIG_HAVE_SPI_FIFO
extern void spi_fifo_configure(Spi* spi, uint8_t tx_thres,
uint8_t rx_thres,
uint32_t ready_modes);
extern void spi_fifo_disable(Spi* spi);
extern uint32_t spi_fifo_rx_size(Spi *spi);
extern uint32_t spi_fifo_tx_size(Spi *spi);
extern uint32_t spi_read_stream(Spi *spi, uint32_t chip_select,
void *stream, uint32_t len);
extern uint32_t spi_write_stream(Spi *spi, uint32_t chip_select,
const void *stream, uint32_t len);
#endif
#ifdef __cplusplus
}
#endif
#endif /* #ifndef _SPI_ */

View file

@ -0,0 +1,368 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
#include "peripherals/aic.h"
#ifdef CONFIG_HAVE_FLEXCOM
#include "peripherals/flexcom.h"
#endif
#include "peripherals/pmc.h"
#include "peripherals/spid.h"
#include "peripherals/spi.h"
#include "peripherals/xdmac.h"
#include "peripherals/xdmad.h"
#include "peripherals/l2cc.h"
#include "cortex-a/cp15.h"
#include "trace.h"
#include <stddef.h>
#include <stdint.h>
#include <assert.h>
#include <string.h>
#define SPID_ATTRIBUTE_MASK (SPI_MR_PS | SPI_MR_MODFDIS | SPI_MR_MSTR | SPI_MR_WDRBT)
#define SPID_DMA_THRESHOLD 16
static uint32_t _garbage = 0;
static void _spid_xdmad_callback_wrapper(struct _xdmad_channel *channel,
void *arg)
{
trace_debug("SPID DMA Transfert Finished\r\n");
struct _spi_desc* spid = (struct _spi_desc*) arg;
xdmad_free_channel(channel);
if (spid->region_start && spid->region_end) {
l2cc_invalidate_region(spid->region_start, spid->region_end);
}
if (spid && spid->callback)
spid->callback(spid, spid->cb_args);
}
static void _spid_xdmad_cleanup_callback(struct _xdmad_channel *channel,
void *arg)
{
xdmad_free_channel(channel);
}
#ifdef CONFIG_HAVE_SPI_FIFO
static void spid_fifo_error(void)
{
trace_error("Fifo pointer error encountered !!\r\n");
}
#endif
void spid_configure(struct _spi_desc* desc)
{
uint32_t id = get_spi_id_from_addr(desc->addr);
#ifdef CONFIG_HAVE_FLEXCOM
Flexcom* flexcom = get_flexcom_addr_from_id(id);
if (flexcom) {
flexcom_select(flexcom, FLEX_MR_OPMODE_SPI);
}
#endif
/* Enable SPI early otherwise FIFO configuration won't be applied */
pmc_enable_peripheral(id);
if (desc->transfert_mode == SPID_MODE_FIFO) {
desc->attributes &= ~SPI_MR_WDRBT;
}
spi_configure(desc->addr, (desc->attributes & SPID_ATTRIBUTE_MASK) | SPI_MR_MSTR);
spi_chip_select(desc->addr, desc->chip_select);
spi_configure_cs(desc->addr, desc->chip_select, desc->bitrate,
desc->dlybs, desc->dlybct, desc->spi_mode, 0);
#ifdef CONFIG_HAVE_SPI_FIFO
if (desc->transfert_mode == SPID_MODE_FIFO) {
spi_fifo_configure(desc->addr, SPI_FIFO_DEPTH, SPI_FIFO_DEPTH,
SPI_FMR_TXRDYM_ONE_DATA | SPI_FMR_RXRDYM_ONE_DATA);
spi_enable_it(desc->addr, SPI_IER_TXFPTEF | SPI_IER_RXFPTEF);
aic_set_source_vector(id, spid_fifo_error);
aic_enable(id);
}
#endif
(void)spi_get_status(desc->addr);
spi_enable(desc->addr);
}
void spid_begin_transfert(struct _spi_desc* desc)
{
spi_chip_select(desc->addr, desc->chip_select);
spi_configure_cs_mode(desc->addr, desc->chip_select, SPI_KEEP_CS_OW);
}
static void _spid_init_dma_write_channel(const struct _spi_desc* desc,
struct _xdmad_channel** channel,
struct _xdmad_cfg* cfg)
{
assert(cfg);
assert(channel);
uint32_t id = get_spi_id_from_addr(desc->addr);
memset(cfg, 0x0, sizeof(*cfg));
*channel =
xdmad_allocate_channel(XDMAD_PERIPH_MEMORY, id);
assert(*channel);
xdmad_prepare_channel(*channel);
cfg->cfg.uint32_value = XDMAC_CC_TYPE_PER_TRAN
| XDMAC_CC_DSYNC_MEM2PER
| XDMAC_CC_MEMSET_NORMAL_MODE
| XDMAC_CC_CSIZE_CHK_1
| XDMAC_CC_DWIDTH_BYTE
| XDMAC_CC_DIF_AHB_IF1
| XDMAC_CC_SIF_AHB_IF0
| XDMAC_CC_DAM_FIXED_AM;
cfg->dest_addr = (void*)&desc->addr->SPI_TDR;
}
static void _spid_init_dma_read_channel(const struct _spi_desc* desc,
struct _xdmad_channel** channel,
struct _xdmad_cfg* cfg)
{
assert(cfg);
assert(channel);
uint32_t id = get_spi_id_from_addr(desc->addr);
memset(cfg, 0x0, sizeof(*cfg));
*channel =
xdmad_allocate_channel(id, XDMAD_PERIPH_MEMORY);
assert(*channel);
xdmad_prepare_channel(*channel);
cfg->cfg.uint32_value = XDMAC_CC_TYPE_PER_TRAN
| XDMAC_CC_DSYNC_PER2MEM
| XDMAC_CC_MEMSET_NORMAL_MODE
| XDMAC_CC_CSIZE_CHK_1
| XDMAC_CC_DWIDTH_BYTE
| XDMAC_CC_DIF_AHB_IF0
| XDMAC_CC_SIF_AHB_IF1
| XDMAC_CC_SAM_FIXED_AM;
cfg->src_addr = (void*)&desc->addr->SPI_RDR;
}
static void _spid_dma_write(const struct _spi_desc* desc,
const struct _buffer* buffer)
{
struct _xdmad_channel* w_channel = NULL;
struct _xdmad_channel* r_channel = NULL;
struct _xdmad_cfg w_cfg;
struct _xdmad_cfg r_cfg;
_spid_init_dma_write_channel(desc, &w_channel, &w_cfg);
_spid_init_dma_read_channel(desc, &r_channel, &r_cfg);
w_cfg.cfg.bitfield.sam = XDMAC_CC_SAM_INCREMENTED_AM
>> XDMAC_CC_SAM_Pos;
w_cfg.src_addr = buffer->data;
w_cfg.ublock_size = buffer->size;
xdmad_configure_transfer(w_channel, &w_cfg, 0, 0);
xdmad_set_callback(w_channel, _spid_xdmad_cleanup_callback,
NULL);
r_cfg.cfg.bitfield.dam = XDMAC_CC_DAM_FIXED_AM
>> XDMAC_CC_DAM_Pos;
r_cfg.dest_addr = &_garbage;
r_cfg.ublock_size = buffer->size;
xdmad_configure_transfer(r_channel, &r_cfg, 0, 0);
xdmad_set_callback(r_channel, _spid_xdmad_callback_wrapper,
(void*)desc);
l2cc_clean_region(desc->region_start, desc->region_end);
xdmad_start_transfer(w_channel);
xdmad_start_transfer(r_channel);
}
static void _spid_dma_read(const struct _spi_desc* desc,
struct _buffer* buffer)
{
struct _xdmad_channel* w_channel = NULL;
struct _xdmad_channel* r_channel = NULL;
struct _xdmad_cfg w_cfg;
struct _xdmad_cfg r_cfg;
_spid_init_dma_write_channel(desc, &w_channel, &w_cfg);
_spid_init_dma_read_channel(desc, &r_channel, &r_cfg);
w_cfg.cfg.bitfield.sam = XDMAC_CC_SAM_FIXED_AM
>> XDMAC_CC_SAM_Pos;
w_cfg.src_addr = buffer->data;
w_cfg.ublock_size = buffer->size;
w_cfg.block_size = 0;
xdmad_configure_transfer(w_channel, &w_cfg, 0, 0);
xdmad_set_callback(w_channel, _spid_xdmad_cleanup_callback, NULL);
r_cfg.cfg.bitfield.dam = XDMAC_CC_DAM_INCREMENTED_AM
>> XDMAC_CC_DAM_Pos;
r_cfg.dest_addr = buffer->data;
r_cfg.ublock_size = buffer->size;
xdmad_configure_transfer(r_channel, &r_cfg, 0, 0);
xdmad_set_callback(r_channel, _spid_xdmad_callback_wrapper,
(void*)desc);
l2cc_clean_region(desc->region_start, desc->region_end);
xdmad_start_transfer(w_channel);
xdmad_start_transfer(r_channel);
}
uint32_t spid_transfert(struct _spi_desc* desc, struct _buffer* rx,
struct _buffer* tx, spid_callback_t cb,
void* user_args)
{
Spi* spi = desc->addr;
uint32_t i = 0;
desc->callback = cb;
desc->cb_args = user_args;
if (mutex_try_lock(&desc->mutex)) {
return SPID_ERROR_LOCK;
}
switch (desc->transfert_mode) {
case SPID_MODE_POLLING:
if (tx) {
for (i = 0; i < tx->size; ++i) {
spi_write(spi, desc->chip_select, tx->data[i]);
}
}
if (rx) {
for (i = 0; i < rx->size; ++i) {
rx->data[i] = spi_read(spi, desc->chip_select);
}
}
mutex_free(&desc->mutex);
if (cb)
cb(desc, user_args);
break;
case SPID_MODE_DMA:
if (tx) {
if (tx->size < SPID_DMA_THRESHOLD) {
for (i = 0; i < tx->size; ++i) {
spi_write(spi, desc->chip_select, tx->data[i]);
}
if (!rx) {
if (cb)
cb(desc, user_args);
mutex_free(&desc->mutex);
}
} else {
desc->region_start = (uint32_t)tx->data;
desc->region_end = desc->region_start
+ tx->size;
_spid_dma_write(desc, tx);
if (rx) {
spid_wait_transfert(desc);
mutex_lock(&desc->mutex);
}
}
}
if (rx) {
if (rx->size < SPID_DMA_THRESHOLD) {
for (i = 0; i < rx->size; ++i) {
rx->data[i] = spi_read(spi, desc->chip_select);
}
if (cb)
cb(desc, user_args);
mutex_free(&desc->mutex);
} else {
desc->region_start = (uint32_t)rx->data;
desc->region_end = desc->region_start
+ rx->size;
_spid_dma_read(desc, rx);
}
}
break;
#ifdef CONFIG_HAVE_SPI_FIFO
case SPID_MODE_FIFO:
if (tx) {
spi_write_stream(spi, desc->chip_select,
tx->data, tx->size);
}
if (rx) {
spi_read_stream(spi, desc->chip_select,
rx->data, rx->size);
}
mutex_free(&desc->mutex);
if (cb)
cb(desc, user_args);
break;
#endif
default:
trace_debug("Unkown mode");
}
return SPID_SUCCESS;
}
void spid_finish_transfert_callback(struct _spi_desc* desc, void* user_args)
{
(void)user_args;
spid_finish_transfert(desc);
}
void spid_finish_transfert(struct _spi_desc* desc)
{
spi_release_cs(desc->addr);
mutex_free(&desc->mutex);
}
void spid_close(const struct _spi_desc* desc)
{
uint32_t id = get_spi_id_from_addr(desc->addr);
#ifdef CONFIG_HAVE_SPI_FIFO
spi_fifo_disable(desc->addr);
spi_disable_it(desc->addr, SPI_IER_TXFPTEF | SPI_IER_RXFPTEF);
aic_disable(id);
#endif
spi_disable(desc->addr);
pmc_disable_peripheral(id);
}
uint32_t spid_is_busy(const struct _spi_desc* desc)
{
return mutex_is_locked(&desc->mutex);
}
void spid_wait_transfert(const struct _spi_desc* desc)
{
while (mutex_is_locked(&desc->mutex));
}

View file

@ -0,0 +1,101 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
#ifndef SPID_HEADER__
#define SPID_HEADER__
/*------------------------------------------------------------------------------
* Header
*----------------------------------------------------------------------------*/
#include <stdint.h>
#include "mutex.h"
#include "io.h"
/*------------------------------------------------------------------------------
* Types
*----------------------------------------------------------------------------*/
#define SPID_SUCCESS (0)
#define SPID_INVALID_ID (1)
#define SPID_INVALID_BITRATE (2)
#define SPID_ERROR_LOCK (3)
#define SPID_NO_CALLBACK ((spid_callback_t)0)
struct _spi_desc;
typedef void (*spid_callback_t)(struct _spi_desc* spid, void* args);
enum _spid_trans_mode
{
SPID_MODE_POLLING,
SPID_MODE_FIFO,
SPID_MODE_DMA
};
struct _spi_desc
{
Spi* addr;
uint32_t bitrate;
uint32_t attributes;
uint8_t dlybs;
uint8_t dlybct;
uint8_t chip_select;
uint8_t spi_mode;
uint8_t transfert_mode;
/* implicit internal padding is mandatory here */
spid_callback_t callback;
void* cb_args;
mutex_t mutex;
uint32_t region_start;
uint32_t region_end;
};
/*------------------------------------------------------------------------------
* Functions
*----------------------------------------------------------------------------*/
extern void spid_configure(struct _spi_desc* desc);
extern void spid_begin_transfert(struct _spi_desc* desc);
extern uint32_t spid_transfert(struct _spi_desc* desc, struct _buffer* rx,
struct _buffer* tx, spid_callback_t cb,
void* user_args);
extern void spid_finish_transfert(struct _spi_desc* desc);
extern void spid_finish_transfert_callback(struct _spi_desc* desc,
void* user_arg);
extern void spid_close(const struct _spi_desc* desc);
extern uint32_t spid_is_busy(const struct _spi_desc* desc);
extern void spid_wait_transfert(const struct _spi_desc* desc);
#endif /* SPID_HEADER__ */

View file

@ -0,0 +1,228 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/** \addtogroup tc_module
* \section Purpose
* The TC driver provides the Interface to configure the Timer Counter (TC).
*
* \section Usage
* <ul>
* <li> Optionally, use tc_find_mck_divisor() to let the program find the best
* TCCLKS field value automatically.</li>
* <li> Configure a Timer Counter in the desired mode using tc_configure().</li>
* <li> Start or stop the timer clock using tc_start() and tc_stop().</li>
* </li>
* </ul>
* For more accurate information, please look at the TC section of the Datasheet.
*
* Related files :\n
* \ref tc.c\n
* \ref tc.h.\n
*/
/**
* \file
*
* \section Purpose
*
* Interface for configuring and using Timer Counter (TC) peripherals.
*
* \section Usage
* -# Optionally, use tc_find_mck_divisor() to let the program find the best
* TCCLKS field value automatically.
* -# Configure a Timer Counter in the desired mode using tc_configure().
* -# Start or stop the timer clock using tc_start() and tc_stop().
*/
/**
* \file
*
* Implementation of Timer Counter (TC).
*
*/
/*------------------------------------------------------------------------------
* Headers
*------------------------------------------------------------------------------*/
#include "chip.h"
#include "peripherals/tc.h"
#include "peripherals/pmc.h"
#include <assert.h>
/*------------------------------------------------------------------------------
* Global functions
*------------------------------------------------------------------------------*/
/**
* \brief Configures a Timer Counter Channel
*
* Configures a Timer Counter to operate in the given mode. Timer is stopped
* after configuration and must be restarted with tc_start(). All the
* interrupts of the timer are also disabled.
*
* \param pTc Pointer to a Tc instance.
* \param channel Channel number.
* \param mode Operating mode (TC_CMR value).
*/
void tc_configure(Tc * pTc, uint32_t channel, uint32_t mode)
{
volatile TcChannel *pTcCh;
assert(channel <
(sizeof (pTc->TC_CHANNEL) / sizeof (pTc->TC_CHANNEL[0])));
pTcCh = pTc->TC_CHANNEL + channel;
/* Disable TC clock */
pTcCh->TC_CCR = TC_CCR_CLKDIS;
/* Disable interrupts */
pTcCh->TC_IDR = 0xFFFFFFFF;
/* Clear status register */
pTcCh->TC_SR;
/* Set mode */
pTcCh->TC_CMR = mode;
}
/**
* \brief Reset and Start the TC Channel
*
* Enables the timer clock and performs a software reset to start the counting.
*
* \param pTc Pointer to a Tc instance.
* \param channel Channel number.
*/
void tc_start(Tc * pTc, uint32_t channel)
{
volatile TcChannel *pTcCh;
assert(channel <
(sizeof (pTc->TC_CHANNEL) / sizeof (pTc->TC_CHANNEL[0])));
pTcCh = pTc->TC_CHANNEL + channel;
pTcCh->TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG;
pTcCh->TC_IER = TC_IER_COVFS;
}
/**
* \brief Stop TC Channel
*
* Disables the timer clock, stopping the counting.
*
* \param pTc Pointer to a Tc instance.
* \param channel Channel number.
*/
void tc_stop(Tc * pTc, uint32_t channel)
{
volatile TcChannel *pTcCh;
assert(channel <
(sizeof (pTc->TC_CHANNEL) / sizeof (pTc->TC_CHANNEL[0])));
pTcCh = pTc->TC_CHANNEL + channel;
pTcCh->TC_CCR = TC_CCR_CLKDIS;
pTcCh->TC_IDR = TC_IER_COVFS;
}
/**
* \brief Enables TC channel interrupts
*
* \param tc Pointer to Tc instance
* \param channel Channel number
* \param mask mask of interrupts to enable
*/
void tc_enable_it(Tc* tc, uint32_t channel, uint32_t mask)
{
assert(channel < (sizeof (tc->TC_CHANNEL) / sizeof (tc->TC_CHANNEL[0])));
tc->TC_CHANNEL[channel].TC_IER = mask;
}
/**
* \brief Find best MCK divisor
*
* Finds the best MCK divisor given the timer frequency and MCK. The result
* is guaranteed to satisfy the following equation:
* \code
* (MCK / (DIV * 65536)) <= freq <= (MCK / DIV)
* \endcode
* with DIV being the highest possible value.
*
* \param freq Desired timer freq.
* \param div Divisor value.
* \param tc_clks TCCLKS field value for divisor.
*
* \return 1 if a proper divisor has been found, otherwise 0.
*/
uint32_t tc_find_mck_divisor (uint32_t freq, uint32_t * div,
uint32_t * tc_clks)
{
const uint32_t periph_clock = pmc_get_peripheral_clock(ID_TC0);
const uint32_t available_freqs[5] = {periph_clock >> 1, periph_clock >> 3, periph_clock >> 5, periph_clock >> 7, 32768};
int i = 0;
for (i = 0; i < 5; ++i)
{
uint32_t tmp = freq << 1;
if (tmp > available_freqs[i])
break;
}
i = (i == 5 ? i-1 : i);
/* Store results */
if (div) {
*div = periph_clock / available_freqs[i];
}
if (tc_clks) {
*tc_clks = i;
}
return 1;
}
uint32_t tc_get_status(Tc* tc, uint32_t channel_num)
{
return tc->TC_CHANNEL[channel_num].TC_SR;
}
void tc_trigger_on_freq(Tc* tc, uint32_t channel_num, uint32_t freq)
{
uint32_t div = 0;
uint32_t tcclks = 0;
uint32_t tc_id = get_tc_id_from_addr(tc);
TcChannel* channel = &tc->TC_CHANNEL[channel_num];
tc_find_mck_divisor(freq, &div, &tcclks);
tc_configure(tc, channel_num, tcclks | TC_CMR_CPCTRG);
channel->TC_RC = (pmc_get_peripheral_clock(tc_id) / div) / freq;
}

View file

@ -0,0 +1,74 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* \section Purpose
*
* Interface for configuring and using Timer Counter (TC) peripherals.
*
* \section Usage
* -# Optionally, use tc_find_mck_divisor() to let the program find the best
* TCCLKS field value automatically.
* -# Configure a Timer Counter in the desired mode using tc_configure().
* -# Start or stop the timer clock using tc_start() and tc_stop().
*/
#ifndef _TC_
#define _TC_
/*------------------------------------------------------------------------------
* Headers
*------------------------------------------------------------------------------*/
#include "chip.h"
#include <stdint.h>
/*------------------------------------------------------------------------------
* Global functions
*------------------------------------------------------------------------------*/
#ifdef __cplusplus
extern "C" {
#endif
extern void tc_configure (Tc* pTc, uint32_t channel, uint32_t mode);
extern void tc_start (Tc * pTc, uint32_t channel);
extern void tc_stop (Tc * pTc, uint32_t channel);
extern void tc_enable_it(Tc* tc, uint32_t channel, uint32_t mask);
extern uint32_t tc_find_mck_divisor (uint32_t freq, uint32_t* div, uint32_t * tc_clks);
extern uint32_t tc_get_status(Tc* tc, uint32_t channel_num);
extern void tc_trigger_on_freq(Tc* tc, uint32_t channel_num, uint32_t freq);
#ifdef __cplusplus
}
#endif
#endif /* #ifndef _TC_ */

View file

@ -0,0 +1,164 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/** \addtogroup tdes_module Working with TDES
* \ingroup peripherals_module
* The TDES driver provides the interface to configure and use the TDES
* peripheral.
* \n
*
* The Data Encryption Standard (DES) and the Triple Data Encryption Algorithm
* (TDES) specify FIPS-approved cryptographic algorithms that can be used to
* protect electronic data.
* The TDES bit in the TDES Mode Register (TDES_MR) is used to select either the
* single DES or the Triple DES mode (make use of the tdes_configure()
* function).
*
* The DES uses 64-bit cryptographic keys to encrypt and decrypt 64-bit data
* blocks. Input data can be fed calling tdes_set_input().
* The 64-bit key is defined in the Key 1 Word Registers (TDES_KEY1WRx) and set
* by tdes_write_key1().
*
* The Triple DES key consists in three DES keys, which set is also referred to
* as a key bundle. These three 64-bit keys are defined, respectively, in the
* Key 1, 2 and 3 Word Registers (TDES_KEY1WRx, TDES_KEY2WRx and TDES_KEY3WRx).
* In Triple DES mode (TDES_MR:TDESMOD set to 1), the TDES_MR:KEYMOD bit is used
* to select either the two- or three-key algorithm.
*
* In order to perform TDES encryption/decryption, the user has to follow these
* few steps:
* <ul>
* <li> A software-triggered hardware reset of the TDES interface is performed
* by tdes_soft_reset().</li>
* <li> Configure TDES algorithm mode, key mode, start mode and operation mode
* by means of tdes_configure().</li>
* <li> Set DES keys with function tdes_write_key1(), tdes_write_key2(), and
* tdes_write_key3().</li>
* <li> To start encrypting or decrypting call tdes_start().</li>
* <li> Retrieve the encryption or decryption result by means of
* tdes_get_output().</li>
* </ul>
*
* For more accurate information, please look at the TDES section of the
* Datasheet.
*
* Related files:\n
* \ref tdes.c\n
* \ref tdes.h\n
*/
/*@{*/
/*@}*/
/**
* \file
*
* Implementation of the Triple Data Encryption Algorithm (TDES).
*
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include "peripherals/tdes.h"
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
void tdes_start(void)
{
TDES->TDES_CR = TDES_CR_START;
}
void tdes_soft_reset(void)
{
TDES->TDES_CR = TDES_CR_SWRST;
}
void tdes_configure(uint32_t mode)
{
TDES->TDES_MR = mode;
}
void tdes_enable_it(uint32_t sources)
{
TDES->TDES_IER = sources;
}
void tdes_disable_it(uint32_t sources)
{
TDES->TDES_IDR = sources;
}
uint32_t tdes_get_status(void)
{
return TDES->TDES_ISR;
}
void tdes_write_key1(uint32_t key_word0, uint32_t key_word1)
{
TDES->TDES_KEY1WR[0] = key_word0;
TDES->TDES_KEY1WR[1] = key_word1;
}
void tdes_write_key2(uint32_t key_word0, uint32_t key_word1)
{
TDES->TDES_KEY2WR[0] = key_word0;
TDES->TDES_KEY2WR[1] = key_word1;
}
void tdes_write_key3(uint32_t key_word0, uint32_t key_word1)
{
TDES->TDES_KEY3WR[0] = key_word0;
TDES->TDES_KEY3WR[1] = key_word1;
}
void tdes_set_input(uint32_t data0, uint32_t data1)
{
TDES->TDES_IDATAR[0] = data0;
TDES->TDES_IDATAR[1] = data1;
}
void tdes_get_output(uint32_t *data0, uint32_t *data1)
{
*data0 = TDES->TDES_ODATAR[0];
*data1 = TDES->TDES_ODATAR[1];
}
void tdes_set_vector(uint32_t v0, uint32_t v1)
{
TDES->TDES_IVR[0] = v0;
TDES->TDES_IVR[1] = v1;
}
void tdes_set_xtea_rounds(uint32_t rounds)
{
TDES->TDES_XTEA_RNDR = TDES_XTEA_RNDR_XTEA_RNDS(rounds);
}

View file

@ -0,0 +1,125 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
#ifndef _TDES_
#define _TDES_
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
/*----------------------------------------------------------------------------
* Definitions
*----------------------------------------------------------------------------*/
#define MODE_SINGLE_DES 0x00
#define MODE_TRIPLE_DES 0x01
#define MODE_XTEA 0x02
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/**
* \brief Starts Manual encryption/decryption process.
*/
void tdes_start(void);
/**
* \brief Resets the TDES.
* A software triggered hardware reset of the TDES interface is performed.
*/
void tdes_soft_reset(void);
/**
* \brief Configures an TDES peripheral with the specified parameters.
* \param mode Desired value for the TDES_MR mode register (see the datasheet).
*/
void tdes_configure(uint32_t mode);
/**
* \brief Enables the selected interrupts sources on a TDES peripheral.
* \param sources Bitwise OR of selected interrupt sources.
*/
void tdes_enable_it(uint32_t sources);
/**
* \brief Disables the selected interrupts sources on a TDES peripheral.
* \param sources Bitwise OR of selected interrupt sources.
*/
void tdes_disable_it(uint32_t sources);
/**
* \brief Get the current status register of the given TDES peripheral.
* \return TDES status register.
*/
extern uint32_t tdes_get_status(void);
/**
* \brief Set KEY 1/2/3.
* \param key_word0 Key x, word 0
* \param key_word1 Key x, word 1
*/
void tdes_write_key1(uint32_t key_word0, uint32_t key_word1);
void tdes_write_key2(uint32_t key_word0, uint32_t key_word1);
void tdes_write_key3(uint32_t key_word0, uint32_t key_word1);
/**
* \brief Set the two 32-bit input data registers. Allows to set the 64-bit data
* block used for encryption/decryption.
* \param data0 Corresponds to the first word of the data to be processed.
* \param data1 Corresponds to the last word of the data to be processed.
*/
void tdes_set_input(uint32_t data0, uint32_t data1);
/**
* \brief Read from the two 32-bit data registers containing the 64-bit data
* block which has been encrypted/decrypted.
* \param data0 Points to the first word.
* \param data1 Points to the second word.
*/
void tdes_get_output(uint32_t *data0, uint32_t *data1);
/**
* \brief Set the 64-bit initialization vector data block, which is used by
* specific modes of operation as an additional initial input.
* \param v0 Corresponds to the first word of the initialization vector.
* \param v1 Corresponds to the second word of the initialization vector.
*/
void tdes_set_vector(uint32_t v0, uint32_t v1);
/**
* \brief Set the 6-bit complete rounds.
* \param rounds Corresponds to rounds+1 complete round.
*/
void tdes_set_xtea_rounds(uint32_t rounds);
#endif /* #ifndef _TDES_ */

View file

@ -0,0 +1,128 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/** \addtogroup rtng_module Working with RTNG
* \ingroup peripherals_module
* The TRNG driver provides the interface to configure and use the TRNG
* peripheral.
* \n
*
* The True Random Number Generator (TRNG) passes the American NIST Special
* Publication 800-22 and Diehard Random Tests Suites. As soon as the TRNG is
* enabled (trng_enable()), the generator provides one 32-bit value every 84
* clock cycles. TRNG Interrupt can be enabled through trng_enable_it()
* (respectively disabled with trng_disable_it()). When new random data is
* ready, the interrupt will fire and the configured callback will be called.
* Alternatively, the TRNG can also be used in polling mode using
* trng_get_random_data().
*
* For more accurate information, please look at the TRNG section of the
* datasheet.
*
* Related files :\n
* \ref trng.c\n
* \ref trng.h\n
*/
/*@{*/
/*@}*/
/**
* \file
*
* Implementation of True Random Number Generator (TRNG)
*
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include "peripherals/aic.h"
#include "peripherals/pmc.h"
#include "peripherals/trng.h"
/*----------------------------------------------------------------------------
* Local Data
*----------------------------------------------------------------------------*/
static trng_callback_t _trng_callback;
static void* _trng_callback_arg;
/*------------------------------------------------------------------------------
* Local functions
*------------------------------------------------------------------------------*/
static void _trng_handler(void)
{
if (TRNG->TRNG_ISR & TRNG_ISR_DATRDY) {
if (_trng_callback) {
_trng_callback(TRNG->TRNG_ODATA, _trng_callback_arg);
}
}
}
/*------------------------------------------------------------------------------
* Exported functions
*------------------------------------------------------------------------------*/
void trng_enable()
{
pmc_enable_peripheral(ID_TRNG);
TRNG->TRNG_CR = TRNG_CR_ENABLE | TRNG_CR_KEY_PASSWD;
}
void trng_disable()
{
TRNG->TRNG_CR = TRNG_CR_KEY_PASSWD;
pmc_disable_peripheral(ID_TRNG);
}
void trng_enable_it(trng_callback_t cb, void* user_arg)
{
_trng_callback = cb;
_trng_callback_arg = user_arg;
aic_set_source_vector(ID_TRNG, _trng_handler);
aic_enable(ID_TRNG);
TRNG->TRNG_IER = TRNG_IER_DATRDY;
}
void trng_disable_it(void)
{
TRNG->TRNG_IDR = TRNG_IDR_DATRDY;
aic_disable(ID_TRNG);
_trng_callback = NULL;
_trng_callback_arg = NULL;
}
uint32_t trng_get_random_data(void)
{
while (!(TRNG->TRNG_ISR & TRNG_ISR_DATRDY));
return TRNG->TRNG_ODATA;
}

View file

@ -0,0 +1,81 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
#ifndef _TRNG_H_
#define _TRNG_H_
/*------------------------------------------------------------------------------
* Headers
*------------------------------------------------------------------------------*/
#include <stdint.h>
#include "chip.h"
/*------------------------------------------------------------------------------
* Types
*------------------------------------------------------------------------------*/
typedef void (*trng_callback_t)(uint32_t random_value, void* user_arg);
/*------------------------------------------------------------------------------
* Exported functions
*------------------------------------------------------------------------------*/
/**
* \brief Enables the TRNG.
*/
extern void trng_enable(void);
/**
* \brief Disables the TRNG.
*/
extern void trng_disable(void);
/**
* \brief Enable the TRNG interrupt, the callback will be called for each new
* generated random value.
*
* \param cb user callback
* \param user_arg user argument passed as-is to the callback
*/
extern void trng_enable_it(trng_callback_t cb, void* user_arg);
/**
* \brief Disable the TRNG interrupt.
*/
extern void trng_disable_it(void);
/**
* \brief Get the next random value generated by the TRNG. This function will
* block until a value is available.
* \return a random value
*/
extern uint32_t trng_get_random_data(void);
#endif /* _TRNG_H_ */

View file

@ -0,0 +1,500 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/** \addtogroup twi_module Working with TWI
* \section Purpose
* The TWI driver provides the interface to configure and use the TWI
* peripheral.
*
* \section Usage
* <ul>
* <li> Configures a TWI peripheral to operate in master mode, at the given
* frequency (in Hz) using twi_configure(). </li>
* <li> Sends a STOP condition on the TWI using twi_stop().</li>
* <li> Starts a read operation on the TWI bus with the specified slave using
* twi_start_read(). Data must then be read using twi_read_byte() whenever
* a byte is available (poll using twi_is_byte_received()).</li>
* <li> Starts a write operation on the TWI to access the selected slave using
* twi_start_write(). A byte of data must be provided to start the write;
* other bytes are written next.</li>
* <li> Sends a byte of data to one of the TWI slaves on the bus using twi_write_byte().
* This function must be called once before twi_start_write() with the first byte of data
* to send, then it shall be called repeatedly after that to send the remaining bytes.</li>
* <li> Check if a byte has been received and can be read on the given TWI
* peripheral using twi_is_byte_received().<
* Check if a byte has been sent using twi_byte_sent().</li>
* <li> Check if the current transmission is complete (the STOP has been sent)
* using twi_is_transfer_complete().</li>
* <li> Enables & disable the selected interrupts sources on a TWI peripheral
* using twi_enable_it() and twi_enable_it().</li>
* <li> Get current status register of the given TWI peripheral using
* twi_get_status(). Get current status register of the given TWI peripheral, but
* masking interrupt sources which are not currently enabled using
* twi_get_masked_status().</li>
* </ul>
* For more accurate information, please look at the TWI section of the
* Datasheet.
*
* Related files :\n
* \ref twi.c\n
* \ref twi.h.\n
*/
/*@{*/
/*@}*/
/**
* \file
*
* Implementation of Two Wire Interface (TWI).
*
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include "peripherals/twi.h"
#include "peripherals/pmc.h"
#include "trace.h"
#include "timer.h"
#include "io.h"
#include <stddef.h>
#include <assert.h>
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/**
* \brief Configures a TWI peripheral to operate in master mode, at the given
* frequency (in Hz). The duty cycle of the TWI clock is set to 50%.
* \param twi Pointer to an Twi instance.
* \param twi_clock Desired TWI clock frequency.
*/
void twi_configure_master(Twi * pTwi, uint32_t twi_clock)
{
uint32_t ck_div, cl_div, hold, ok, clock;
uint32_t id = get_twi_id_from_addr(pTwi);
trace_debug("twi_configure_master(%u)\n\r", (unsigned)twi_clock);
assert(pTwi);
assert(id < ID_PERIPH_COUNT);
/* SVEN: TWI Slave Mode Enabled */
pTwi->TWI_CR = TWI_CR_SVEN;
/* Reset the TWI */
pTwi->TWI_CR = TWI_CR_SWRST;
pTwi->TWI_RHR;
timer_sleep(10);
/* TWI Slave Mode Disabled, TWI Master Mode Disabled. */
pTwi->TWI_MMR = 0;
pTwi->TWI_CR = TWI_CR_SVDIS;
pTwi->TWI_CR = TWI_CR_MSDIS;
clock = pmc_get_peripheral_clock(id);
/* Compute clock */
ck_div = 0; ok = 0;
while (!ok) {
cl_div = ((clock / (2 * twi_clock)) - 3) >> ck_div;
if (cl_div <= 255)
ok = 1;
else
ck_div++;
}
twi_clock = ROUND_INT_DIV(clock, (((cl_div * 2) << ck_div) + 3));
assert(ck_div < 8);
trace_debug("twi: CKDIV=%u CLDIV=CHDIV=%u -> TWI Clock %uHz\n\r",
(unsigned)ck_div, (unsigned)cl_div, (unsigned)twi_clock);
/* Compute holding time (I2C spec requires 300ns) */
hold = ROUND_INT_DIV((uint32_t)(0.3 * clock), 1000000) - 3;
trace_debug("twi: HOLD=%u -> Holding Time %uns\n\r",
(unsigned)hold, (unsigned)((1000000 * (hold + 3)) / (clock / 1000)));
/* Configure clock */
pTwi->TWI_CWGR = 0;
pTwi->TWI_CWGR = TWI_CWGR_CKDIV(ck_div) | TWI_CWGR_CHDIV(cl_div) |
TWI_CWGR_CLDIV(cl_div) | TWI_CWGR_HOLD(hold);
/* Set master mode */
pTwi->TWI_CR = TWI_CR_MSEN;
timer_sleep(10);
assert((pTwi->TWI_CR & TWI_CR_SVDIS) != TWI_CR_MSDIS);
}
/**
* \brief Configures a TWI peripheral to operate in slave mode.
* \param twi Pointer to an Twi instance.
* \param slaveAddress Slave address.
*/
void twi_configure_slave(Twi * pTwi, uint8_t slave_address)
{
trace_debug("twi_configure_slave()\n\r");
assert(pTwi);
/* TWI software reset */
pTwi->TWI_CR = TWI_CR_SWRST;
pTwi->TWI_RHR;
/* Wait at least 10 ms */
timer_sleep(10);
/* TWI Slave Mode Disabled, TWI Master Mode Disabled */
pTwi->TWI_CR = TWI_CR_SVDIS | TWI_CR_MSDIS;
/* Configure slave address. */
pTwi->TWI_SMR = 0;
pTwi->TWI_SMR = TWI_SMR_SADR(slave_address);
/* SVEN: TWI Slave Mode Enabled */
pTwi->TWI_CR = TWI_CR_SVEN;
/* Wait at least 10 ms */
timer_sleep(10);
assert((pTwi->TWI_CR & TWI_CR_SVDIS) != TWI_CR_SVDIS);
}
/**
* \brief Sends a STOP condition on the TWI.
* \param twi Pointer to an Twi instance.
*/
void twi_stop(Twi * pTwi)
{
assert(pTwi != NULL);
pTwi->TWI_CR = TWI_CR_STOP;
}
/**
* \brief Starts a read operation on the TWI bus with the specified slave, it returns
* immediately. Data must then be read using twi_read_byte() whenever a byte is
* available (poll using twi_is_byte_received()).
* \param twi Pointer to an Twi instance.
* \param address Slave address on the bus.
* \param iaddress Optional internal address bytes.
* \param isize Number of internal address bytes.
*/
void twi_start_read(Twi * pTwi, uint8_t address,
uint32_t iaddress, uint8_t isize)
{
assert(pTwi != NULL);
assert((address & 0x80) == 0);
assert((iaddress & 0xFF000000) == 0);
assert(isize < 4);
/* Set slave address and number of internal address bytes. */
pTwi->TWI_MMR = 0;
pTwi->TWI_MMR = (isize << 8) | TWI_MMR_MREAD | (address << 16);
/* Set internal address bytes */
pTwi->TWI_IADR = 0;
pTwi->TWI_IADR = iaddress;
/* Send START condition */
pTwi->TWI_CR = TWI_CR_START;
}
/**
* \brief Reads a byte from the TWI bus. The read operation must have been started
* using twi_start_read() and a byte must be available (check with twi_is_byte_received()).
* \param twi Pointer to an Twi instance.
* \return byte read.
*/
uint8_t twi_read_byte(Twi * twi)
{
assert(twi != NULL);
uint8_t value;
readb(&twi->TWI_RHR, &value);
return value;
}
/**
* \brief Sends a byte of data to one of the TWI slaves on the bus.
* \note This function must be called once before twi_start_write() with
* the first byte of data to send, then it shall be called repeatedly
* after that to send the remaining bytes.
* \param twi Pointer to an Twi instance.
* \param byte Byte to send.
*/
void twi_write_byte(Twi * twi, uint8_t byte)
{
assert(twi != NULL);
writeb(&twi->TWI_THR, byte);
}
/**
* \brief Starts a write operation on the TWI to access the selected slave, then
* returns immediately. A byte of data must be provided to start the write;
* other bytes are written next.
* after that to send the remaining bytes.
* \param twi Pointer to an Twi instance.
* \param address Address of slave to acccess on the bus.
* \param iaddress Optional slave internal address.
* \param isize Number of internal address bytes.
* \param byte First byte to send.
*/
void twi_start_write(Twi * pTwi, uint8_t address, uint32_t iaddress,
uint8_t isize, uint8_t byte)
{
assert(pTwi != NULL);
assert((address & 0x80) == 0);
assert((iaddress & 0xFF000000) == 0);
assert(isize < 4);
/* Set slave address and number of internal address bytes. */
pTwi->TWI_MMR = 0;
pTwi->TWI_MMR = (isize << 8) | (address << 16);
/* Set internal address bytes. */
pTwi->TWI_IADR = 0;
pTwi->TWI_IADR = iaddress;
/* Write first byte to send. */
twi_write_byte(pTwi, byte);
}
/**
* \brief Check if a byte have been receiced from TWI.
* \param twi Pointer to an Twi instance.
* \return 1 if a byte has been received and can be read on the given TWI
* peripheral; otherwise, returns 0. This function resets the status register.
*/
uint8_t twi_is_byte_received(Twi * pTwi)
{
assert(pTwi != NULL);
return ((pTwi->TWI_SR & TWI_SR_RXRDY) == TWI_SR_RXRDY);
}
/**
* \brief Check if a byte have been sent to TWI.
* \param twi Pointer to an Twi instance.
* \return 1 if a byte has been sent so another one can be stored for
* transmission; otherwise returns 0. This function clears the status register.
*/
uint8_t twi_byte_sent(Twi * pTwi)
{
assert(pTwi != NULL);
return ((pTwi->TWI_SR & TWI_SR_TXRDY) == TWI_SR_TXRDY);
}
/**
* \brief Check if current transmission is complet.
* \param twi Pointer to an Twi instance.
* \return 1 if the current transmission is complete (the STOP has been sent);
* otherwise returns 0.
*/
uint8_t twi_is_transfer_complete(Twi * pTwi)
{
assert(pTwi != NULL);
return ((pTwi->TWI_SR & TWI_SR_TXCOMP) == TWI_SR_TXCOMP);
}
/**
* \brief Enables the selected interrupts sources on a TWI peripheral.
* \param twi Pointer to an Twi instance.
* \param sources Bitwise OR of selected interrupt sources.
*/
void twi_enable_it(Twi * pTwi, uint32_t sources)
{
assert(pTwi != NULL);
pTwi->TWI_IER = sources;
}
/**
* \brief Disables the selected interrupts sources on a TWI peripheral.
* \param twi Pointer to an Twi instance.
* \param sources Bitwise OR of selected interrupt sources.
*/
void twi_disable_it(Twi * pTwi, uint32_t sources)
{
assert(pTwi != NULL);
pTwi->TWI_IDR = sources;
}
/**
* \brief Get the current status register of the given TWI peripheral.
* \note This resets the internal value of the status register, so further
* read may yield different values.
* \param twi Pointer to an Twi instance.
* \return TWI status register.
*/
uint32_t twi_get_status(Twi * pTwi)
{
assert(pTwi != NULL);
return pTwi->TWI_SR;
}
/**
* \brief Returns the current status register of the given TWI peripheral, but
* masking interrupt sources which are not currently enabled.
* \note This resets the internal value of the status register, so further
* read may yield different values.
* \param twi Pointer to an Twi instance.
*/
uint32_t twi_get_masked_status(Twi * pTwi)
{
uint32_t status;
assert(pTwi != NULL);
status = pTwi->TWI_SR;
status &= pTwi->TWI_IMR;
return status;
}
/**
* \brief Sends a STOP condition. STOP Condition is sent just after completing
* the current byte transmission in master read mode.
* \param twi Pointer to an Twi instance.
*/
void twi_send_stop_condition(Twi * pTwi)
{
assert(pTwi != NULL);
pTwi->TWI_CR |= TWI_CR_STOP;
}
#ifdef CONFIG_HAVE_TWI_ALTERNATE_CMD
void twi_init_write_transfert(Twi * twi, uint8_t addr, uint32_t iaddress,
uint8_t isize, uint8_t len)
{
twi->TWI_RHR;
twi->TWI_CR = TWI_CR_MSDIS;
twi->TWI_CR = TWI_CR_MSEN;
twi->TWI_CR = TWI_CR_MSEN | TWI_CR_SVDIS | TWI_CR_ACMEN;
twi->TWI_ACR = 0;
twi->TWI_ACR = TWI_ACR_DATAL(len);
twi->TWI_MMR = 0;
twi->TWI_MMR = TWI_MMR_DADR(addr) | TWI_MMR_IADRSZ(isize);
/* Set internal address bytes. */
twi->TWI_IADR = 0;
twi->TWI_IADR = iaddress;
}
void twi_init_read_transfert(Twi * twi, uint8_t addr, uint32_t iaddress,
uint8_t isize, uint8_t len)
{
twi->TWI_RHR;
twi->TWI_CR = TWI_CR_MSEN | TWI_CR_SVDIS | TWI_CR_ACMEN;
twi->TWI_ACR = 0;
twi->TWI_ACR = TWI_ACR_DATAL(len) | TWI_ACR_DIR;
twi->TWI_MMR = 0;
twi->TWI_MMR = TWI_MMR_DADR(addr) | TWI_MMR_MREAD
| TWI_MMR_IADRSZ(isize);
/* Set internal address bytes. */
twi->TWI_IADR = 0;
twi->TWI_IADR = iaddress;
twi->TWI_CR = TWI_CR_START;
while(twi->TWI_SR & TWI_SR_TXCOMP);
}
#endif
#ifdef CONFIG_HAVE_TWI_FIFO
void twi_fifo_configure(Twi* twi, uint8_t tx_thres,
uint8_t rx_thres,
uint32_t ready_modes)
{
/* Disable TWI master and slave mode and activate FIFO */
twi->TWI_CR = TWI_CR_MSDIS | TWI_CR_SVDIS | TWI_CR_FIFOEN;
/* Configure FIFO */
twi->TWI_FMR = TWI_FMR_TXFTHRES(tx_thres) | TWI_FMR_RXFTHRES(rx_thres)
| ready_modes;
}
uint32_t twi_fifo_rx_size(Twi *twi)
{
return (twi->TWI_FLR & TWI_FLR_RXFL_Msk) >> TWI_FLR_RXFL_Pos;
}
uint32_t twi_fifo_tx_size(Twi *twi)
{
return (twi->TWI_FLR & TWI_FLR_TXFL_Msk) >> TWI_FLR_TXFL_Pos;
}
uint32_t twi_read_stream(Twi *twi, uint32_t addr, uint32_t iaddr,
uint32_t isize, const void *stream, uint8_t len)
{
const uint8_t* buffer = stream;
uint8_t left = len;
twi_init_read_transfert(twi, addr, iaddr, isize, len);
if (twi_get_status(twi) & TWI_SR_NACK) {
trace_error("twid2: command NACK!\r\n");
return 0;
}
while (left > 0) {
if ((twi->TWI_SR & TWI_SR_RXRDY) == 0) continue;
/* Get FIFO free size (int octet) and clamp it */
uint32_t buf_size = twi_fifo_rx_size(twi);
buf_size = buf_size > left ? left : buf_size;
/* Fill the FIFO as must as possible */
while (buf_size > sizeof(uint32_t)) {
*(uint32_t*)buffer = twi->TWI_RHR;
buffer += sizeof(uint32_t);
left -= sizeof(uint32_t);
buf_size -= sizeof(uint32_t);
}
while (buf_size >= sizeof(uint8_t)) {
readb(&twi->TWI_RHR, (uint8_t*)buffer);
buffer += sizeof(uint8_t);
left -= sizeof(uint8_t);
buf_size -= sizeof(uint8_t);
}
}
return len - left;
}
uint32_t twi_write_stream(Twi *twi, uint32_t addr, uint32_t iaddr,
uint32_t isize, const void *stream, uint8_t len)
{
const uint8_t* buffer = stream;
uint8_t left = len;
int32_t fifo_size = get_peripheral_fifo_depth(twi);
if (fifo_size < 0)
return 0;
twi_init_write_transfert(twi, addr, iaddr, isize, len);
if (twi_get_status(twi) & TWI_SR_NACK) {
trace_error("twid2: command NACK!\r\n");
return 0;
}
while (left > 0) {
if ((twi->TWI_SR & TWI_SR_TXRDY) == 0) continue;
/* Get FIFO free size (int octet) and clamp it */
uint32_t buf_size = fifo_size - twi_fifo_tx_size(twi);
buf_size = buf_size > left ? left : buf_size;
/* /\* Fill the FIFO as must as possible *\/ */
while (buf_size >= sizeof(uint8_t)) {
writeb(&twi->TWI_THR,*buffer);
buffer += sizeof(uint8_t);
left -= sizeof(uint8_t);
buf_size -= sizeof(uint8_t);
}
}
return len - left;
}
#endif

View file

@ -0,0 +1,111 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* Interface for configuration the Two Wire Interface (TWI) peripheral.
*
*/
#ifndef _TWI_H_
#define _TWI_H_
/*------------------------------------------------------------------------------
* Headers
*------------------------------------------------------------------------------*/
#include "chip.h"
#include <stdint.h>
/*----------------------------------------------------------------------------
* Macros
*----------------------------------------------------------------------------*/
/* Returns 1 if the TXRDY bit (ready to transmit data) is set in the given status register value.*/
#define TWI_STATUS_TXRDY(status) ((status & TWI_SR_TXRDY) == TWI_SR_TXRDY)
/* Returns 1 if the RXRDY bit (ready to receive data) is set in the given status register value.*/
#define TWI_STATUS_RXRDY(status) ((status & TWI_SR_RXRDY) == TWI_SR_RXRDY)
/* Returns 1 if the TXCOMP bit (transfer complete) is set in the given status register value.*/
#define TWI_STATUS_TXCOMP(status) ((status & TWI_SR_TXCOMP) == TWI_SR_TXCOMP)
#ifdef __cplusplus
extern "C" {
#endif
/*----------------------------------------------------------------------------
* External function
*----------------------------------------------------------------------------*/
extern void twi_configure_master(Twi * pTwi, uint32_t twck);
extern void twi_configure_slave(Twi * pTwi, uint8_t slaveAddress);
extern void twi_stop(Twi * pTwi);
extern void twi_start_read(Twi * pTwi, uint8_t address,
uint32_t iaddress, uint8_t isize);
extern uint8_t twi_read_byte(Twi * pTwi);
extern void twi_write_byte(Twi * pTwi, uint8_t byte);
extern void twi_start_write(Twi * pTwi, uint8_t address, uint32_t iaddress,
uint8_t isize, uint8_t byte);
extern uint8_t twi_is_byte_received(Twi * pTwi);
extern uint8_t twi_byte_sent(Twi * pTwi);
extern uint8_t twi_is_transfer_complete(Twi * pTwi);
extern void twi_enable_it(Twi * pTwi, uint32_t sources);
extern void twi_disable_it(Twi * pTwi, uint32_t sources);
extern uint32_t twi_get_status(Twi * pTwi);
extern uint32_t twi_get_masked_status(Twi * pTwi);
extern void twi_send_stop_condition(Twi * pTwi);
#ifdef CONFIG_HAVE_TWI_ALTERNATE_CMD
extern void twi_init_write_transfert(Twi * twi, uint8_t addr, uint32_t iaddress,
uint8_t isize, uint8_t len);
extern void twi_init_read_transfert(Twi * twi, uint8_t addr, uint32_t iaddress,
uint8_t isize, uint8_t len);
#endif
#ifdef CONFIG_HAVE_TWI_FIFO
extern void twi_fifo_configure(Twi* twi, uint8_t tx_thres,
uint8_t rx_thres,
uint32_t ready_modes);
extern void twi_fifo_disable(Twi* twi);
extern uint32_t twi_fifo_rx_size(Twi *twi);
extern uint32_t twi_fifo_tx_size(Twi *twi);
extern uint32_t twi_read_stream(Twi *twi, uint32_t addr, uint32_t iaddr,
uint32_t isize, const void *stream, uint8_t len);
extern uint32_t twi_write_stream(Twi *twi, uint32_t addr, uint32_t iaddr,
uint32_t isize, const void *stream, uint8_t len);
#endif
#ifdef __cplusplus
}
#endif
#endif /* #ifndef _TWI_H_ */

View file

@ -0,0 +1,409 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
#ifdef CONFIG_HAVE_FLEXCOM
#include "peripherals/flexcom.h"
#endif
#include "peripherals/pmc.h"
#include "peripherals/twid.h"
#include "peripherals/twi.h"
#include "peripherals/xdmad.h"
#include "peripherals/l2cc.h"
#include "cortex-a/cp15.h"
#include "trace.h"
#include "io.h"
#include "timer.h"
#include <assert.h>
#include <string.h>
#define TWID_DMA_THRESHOLD 16
#define TWID_TIMEOUT 100
static uint32_t _twid_wait_twi_transfer(struct _twi_desc* desc)
{
struct _timeout timeout;
timer_start_timeout(&timeout, TWID_TIMEOUT);
while(!twi_is_transfer_complete(desc->addr)){
if (timer_timeout_reached(&timeout)) {
trace_error("twid: Unable to complete transfert!\r\n");
twid_configure(desc);
return TWID_ERROR_TRANSFER;
}
}
return TWID_SUCCESS;
}
static void _twid_xdmad_callback_wrapper(struct _xdmad_channel* channel,
void* args)
{
trace_debug("TWID DMA Transfert Finished\r\n");
struct _twi_desc* twid = (struct _twi_desc*) args;
xdmad_free_channel(channel);
if (twid->region_start && twid->region_end) {
l2cc_invalidate_region(twid->region_start, twid->region_end);
}
if (twid && twid->callback)
twid->callback(twid, twid->cb_args);
}
static void _twid_init_dma_read_channel(const struct _twi_desc* desc,
struct _xdmad_channel** channel,
struct _xdmad_cfg* cfg)
{
assert(cfg);
assert(channel);
uint32_t id = get_twi_id_from_addr(desc->addr);
assert(id < ID_PERIPH_COUNT);
memset(cfg, 0x0, sizeof(*cfg));
*channel =
xdmad_allocate_channel(id, XDMAD_PERIPH_MEMORY);
assert(*channel);
xdmad_prepare_channel(*channel);
cfg->cfg.uint32_value = XDMAC_CC_TYPE_PER_TRAN
| XDMAC_CC_DSYNC_PER2MEM
| XDMAC_CC_MEMSET_NORMAL_MODE
| XDMAC_CC_CSIZE_CHK_1
| XDMAC_CC_DWIDTH_BYTE
| XDMAC_CC_DIF_AHB_IF0
| XDMAC_CC_SIF_AHB_IF1
| XDMAC_CC_SAM_FIXED_AM;
cfg->src_addr = (void*)&desc->addr->TWI_RHR;
}
static void _twid_dma_read(const struct _twi_desc* desc,
struct _buffer* buffer)
{
struct _xdmad_channel* channel = NULL;
struct _xdmad_cfg cfg;
_twid_init_dma_read_channel(desc, &channel, &cfg);
cfg.cfg.bitfield.dam = XDMAC_CC_DAM_INCREMENTED_AM
>> XDMAC_CC_DAM_Pos;
cfg.dest_addr = buffer->data;
cfg.ublock_size = buffer->size;
cfg.block_size = 0;
xdmad_configure_transfer(channel, &cfg, 0, 0);
xdmad_set_callback(channel, _twid_xdmad_callback_wrapper,
(void*)desc);
l2cc_clean_region(desc->region_start, desc->region_end);
xdmad_start_transfer(channel);
}
static void _twid_init_dma_write_channel(struct _twi_desc* desc,
struct _xdmad_channel** channel,
struct _xdmad_cfg* cfg)
{
assert(cfg);
assert(channel);
uint32_t id = get_twi_id_from_addr(desc->addr);
assert(id < ID_PERIPH_COUNT);
memset(cfg, 0x0, sizeof(*cfg));
*channel =
xdmad_allocate_channel(XDMAD_PERIPH_MEMORY, id);
assert(*channel);
xdmad_prepare_channel(*channel);
cfg->cfg.uint32_value = XDMAC_CC_TYPE_PER_TRAN
| XDMAC_CC_DSYNC_MEM2PER
| XDMAC_CC_MEMSET_NORMAL_MODE
| XDMAC_CC_CSIZE_CHK_1
| XDMAC_CC_DWIDTH_BYTE
| XDMAC_CC_DIF_AHB_IF1
| XDMAC_CC_SIF_AHB_IF0
| XDMAC_CC_DAM_FIXED_AM;
cfg->dest_addr = (void*)&desc->addr->TWI_THR;
}
static void _twid_dma_write(struct _twi_desc* desc,
struct _buffer* buffer)
{
struct _xdmad_channel* channel = NULL;
struct _xdmad_cfg cfg;
_twid_init_dma_write_channel(desc, &channel, &cfg);
cfg.cfg.bitfield.sam = XDMAC_CC_SAM_INCREMENTED_AM
>> XDMAC_CC_SAM_Pos;
cfg.src_addr = buffer->data;
cfg.ublock_size = buffer->size;
cfg.block_size = 0;
xdmad_configure_transfer(channel, &cfg, 0, 0);
xdmad_set_callback(channel, _twid_xdmad_callback_wrapper,
(void*)desc);
l2cc_clean_region(desc->region_start, desc->region_end);
xdmad_start_transfer(channel);
}
void twid_configure(struct _twi_desc* desc)
{
uint32_t id = get_twi_id_from_addr(desc->addr);
assert(id < ID_PERIPH_COUNT);
#ifdef CONFIG_HAVE_FLEXCOM
Flexcom* flexcom = get_flexcom_addr_from_id(get_twi_id_from_addr(desc->addr));
if (flexcom) {
flexcom_select(flexcom, FLEX_MR_OPMODE_TWI);
}
#endif
pmc_enable_peripheral(id);
twi_configure_master(desc->addr, desc->freq);
#ifdef CONFIG_HAVE_TWI_FIFO
if (desc->transfert_mode == TWID_MODE_FIFO) {
uint32_t fifo_depth = get_peripheral_fifo_depth(desc->addr);
twi_fifo_configure(desc->addr, fifo_depth/2, fifo_depth/2,
TWI_FMR_RXRDYM_ONE_DATA | TWI_FMR_TXRDYM_ONE_DATA);
}
#endif
}
static uint32_t _twid_poll_write(struct _twi_desc* desc, struct _buffer* buffer)
{
int i = 0;
struct _timeout timeout;
twi_init_write_transfert(desc->addr,
desc->slave_addr,
desc->iaddr,
desc->isize,
buffer->size);
if (twi_get_status(desc->addr) & TWI_SR_NACK) {
trace_error("twid: command NACK!\r\n");
return TWID_ERROR_ACK;
}
for (i = 0; i < buffer->size; ++i) {
timer_start_timeout(&timeout, TWID_TIMEOUT);
while(!twi_byte_sent(desc->addr)) {
if (timer_timeout_reached(&timeout)) {
trace_error("twid: Device doesn't answer, "
"(TX TIMEOUT)\r\n");
break;
}
}
twi_write_byte(desc->addr, buffer->data[i]);
if(twi_get_status(desc->addr) & TWI_SR_NACK) {
trace_error("twid: command NACK!\r\n");
return TWID_ERROR_ACK;
}
}
/* wait transfert to be finished */
return _twid_wait_twi_transfer(desc);
}
static uint32_t _twid_poll_read(struct _twi_desc* desc, struct _buffer* buffer)
{
int i = 0;
struct _timeout timeout;
twi_init_read_transfert(desc->addr,
desc->slave_addr,
desc->iaddr,
desc->isize,
buffer->size);
if (twi_get_status(desc->addr) & TWI_SR_NACK) {
trace_error("twid: command NACK!\r\n");
return TWID_ERROR_ACK;
}
for (i = 0; i < buffer->size; ++i) {
timer_start_timeout(&timeout, TWID_TIMEOUT);
while(!twi_is_byte_received(desc->addr)) {
if (timer_timeout_reached(&timeout)) {
trace_error("twid: Device doesn't answer, "
"(RX TIMEOUT)\r\n");
break;
}
}
buffer->data[i] = twi_read_byte(desc->addr);
if(twi_get_status(desc->addr) & TWI_SR_NACK) {
trace_error("twid: command NACK\r\n");
return TWID_ERROR_ACK;
}
}
/* wait transfert to be finished */
return _twid_wait_twi_transfer(desc);
}
uint32_t twid_transfert(struct _twi_desc* desc, struct _buffer* rx,
struct _buffer* tx, twid_callback_t cb,
void* user_args)
{
uint32_t status = TWID_SUCCESS;
desc->callback = cb;
desc->cb_args = user_args;
if (mutex_try_lock(&desc->mutex)) {
return TWID_ERROR_LOCK;
}
switch (desc->transfert_mode) {
case TWID_MODE_POLLING:
if (tx) {
status = _twid_poll_write(desc, tx);
if (status) break;
}
if (rx) {
status = _twid_poll_read(desc, rx);
if (status) break;
}
if (cb)
cb(desc, user_args);
mutex_free(&desc->mutex);
break;
case TWID_MODE_DMA:
if (!(rx || tx)) {
status = TWID_ERROR_DUPLEX;
break;
}
if (tx) {
if (tx->size < TWID_DMA_THRESHOLD) {
status = _twid_poll_write(desc, tx);
if (status) break;
if (cb)
cb(desc, user_args);
mutex_free(&desc->mutex);
} else {
twi_init_write_transfert(desc->addr,
desc->slave_addr,
desc->iaddr,
desc->isize,
tx->size);
desc->region_start = (uint32_t)tx->data;
desc->region_end = desc->region_start
+ tx->size;
_twid_dma_write(desc, tx);
}
}
if (rx) {
if (rx->size < TWID_DMA_THRESHOLD) {
status = _twid_poll_read(desc, rx);
if (status) break;
if (cb)
cb(desc, user_args);
mutex_free(&desc->mutex);
} else {
twi_init_read_transfert(desc->addr,
desc->slave_addr,
desc->iaddr,
desc->isize,
rx->size);
desc->region_start = (uint32_t)rx->data;
desc->region_end = desc->region_start
+ rx->size;
if(twi_get_status(desc->addr) & TWI_SR_NACK) {
trace_error("twid: Acknolegment "
"Error\r\n");
status = TWID_ERROR_ACK;
break;
}
_twid_dma_read(desc, rx);
}
}
break;
#ifdef CONFIG_HAVE_TWI_FIFO
case TWID_MODE_FIFO:
if (tx) {
status = twi_write_stream(desc->addr, desc->slave_addr,
desc->iaddr, desc->isize,
tx->data, tx->size);
status = status ? TWID_SUCCESS : TWID_ERROR_ACK;
if (status)
break;
status = _twid_wait_twi_transfer(desc);
if (status)
break;
}
if (rx) {
status = twi_read_stream(desc->addr, desc->slave_addr,
desc->iaddr, desc->isize,
rx->data, rx->size);
status = status ? TWID_SUCCESS : TWID_ERROR_ACK;
if (status)
break;
status = _twid_wait_twi_transfer(desc);
if (status)
break;
}
if (cb)
cb(desc, user_args);
mutex_free(&desc->mutex);
break;
#endif
default:
trace_debug("Unkown mode");
}
if (status)
mutex_free(&desc->mutex);
return status;
}
void twid_finish_transfert_callback(struct _twi_desc* desc, void* user_args)
{
(void)user_args;
twid_finish_transfert(desc);
}
void twid_finish_transfert(struct _twi_desc* desc)
{
mutex_free(&desc->mutex);
}
uint32_t twid_is_busy(const struct _twi_desc* desc)
{
return mutex_is_locked(&desc->mutex);
}
void twid_wait_transfert(const struct _twi_desc* desc)
{
while (mutex_is_locked(&desc->mutex));
}

View file

@ -0,0 +1,95 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
#ifndef TWID_HEADER__
#define TWID_HEADER__
/*------------------------------------------------------------------------------
* Header
*----------------------------------------------------------------------------*/
#include "peripherals/twi.h"
#include "mutex.h"
#include "io.h"
/*------------------------------------------------------------------------------
* Types
*----------------------------------------------------------------------------*/
#define TWID_SUCCESS (0)
#define TWID_INVALID_ID (1)
#define TWID_INVALID_BITRATE (2)
#define TWID_ERROR_LOCK (3)
#define TWID_ERROR_DUPLEX (4)
#define TWID_ERROR_ACK (5)
#define TWID_ERROR_TIMEOUT (6)
#define TWID_ERROR_TRANSFER (7)
enum _twid_trans_mode
{
TWID_MODE_POLLING,
TWID_MODE_FIFO,
TWID_MODE_DMA
};
struct _twi_desc;
typedef void (*twid_callback_t)(struct _twi_desc* spid, void* args);
struct _twi_desc
{
Twi* addr;
uint32_t freq;
uint32_t slave_addr;
uint32_t iaddr;
uint32_t isize;
uint8_t transfert_mode;
/* implicit internal padding is mandatory here */
mutex_t mutex;
uint32_t region_start;
uint32_t region_end;
twid_callback_t callback;
void* cb_args;
};
/*------------------------------------------------------------------------------
* Functions
*----------------------------------------------------------------------------*/
extern void twid_configure(struct _twi_desc* desc);
extern uint32_t twid_transfert(struct _twi_desc* desc, struct _buffer* rx,
struct _buffer* tx, twid_callback_t cb,
void* user_args);
extern void twid_finish_transfert_callback(struct _twi_desc* desc,
void* user_args);
extern void twid_finish_transfert(struct _twi_desc* desc);
extern uint32_t twid_is_busy(const struct _twi_desc* desc);
extern void twid_wait_transfert(const struct _twi_desc* desc);
#endif /* TWID_HEADER__ */

View file

@ -0,0 +1,675 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/** \file */
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "peripherals/twid_legacy.h"
#include "peripherals/xdmad.h"
#include "cortex-a/cp15.h"
#include "trace.h"
#include <assert.h>
/*----------------------------------------------------------------------------
* Definition
*----------------------------------------------------------------------------*/
#define TWITIMEOUTMAX 0xfffff
static struct _xdmad_cfg twi_dmaCfg;
static struct _xdmad_channel *dmaWriteChannel;
static struct _xdmad_channel *dmaReadChannel;
static struct _xdmad_desc_view1 dmaWriteLinkList[1];
static struct _xdmad_desc_view1 dmaReadLinkList[1];
/*----------------------------------------------------------------------------
* Types
*----------------------------------------------------------------------------*/
/** TWI driver callback function.*/
typedef void (*TwiCallback) (struct _async *);
/** \brief TWI asynchronous transfer descriptor.*/
struct _async_twi {
volatile uint32_t status; /** Asynchronous transfer status. */
TwiCallback callback; /** Callback function to invoke when transfer completes or fails.*/
uint8_t *pData; /** Pointer to the data buffer.*/
uint32_t num; /** Total number of bytes to transfer.*/
uint32_t transferred; /** Number of already transferred bytes.*/
};
//struct _async_twi async_twi ;
/*----------------------------------------------------------------------------
* Global functions
*----------------------------------------------------------------------------*/
/**
* \brief Initializes a TWI DMA Read channel.
*/
static void twid_dma_initialize_read(uint8_t TWI_ID)
{
/* Allocate a XDMA channel, Read accesses into TWI_THR */
dmaReadChannel = xdmad_allocate_channel(TWI_ID, XDMAD_PERIPH_MEMORY);
if (!dmaReadChannel) {
printf("-E- Can't allocate XDMA channel\n\r");
}
xdmad_prepare_channel(dmaReadChannel);
}
/**
* \brief Initializes a TWI DMA write channel.
*/
static void twid_dma_initialize_write(uint8_t TWI_ID)
{
/* Allocate a XDMA channel, Write accesses into TWI_THR */
dmaWriteChannel = xdmad_allocate_channel(XDMAD_PERIPH_MEMORY, TWI_ID);
if (!dmaWriteChannel) {
printf("-E- Can't allocate XDMA channel\n\r");
}
xdmad_prepare_channel(dmaWriteChannel);
}
/**
* \brief Initializes a TWI driver instance, using the given TWI peripheral.
* \note The peripheral must have been initialized properly before calling this function.
* \param pTwid Pointer to the Twid instance to initialize.
* \param pTwi Pointer to the TWI peripheral to use.
*/
void twid_initialize(struct _twid* pTwid, Twi * pTwi)
{
trace_debug("twid_initialize()\n\r");
assert(pTwid != NULL);
assert(pTwi != NULL);
/* Initialize driver. */
pTwid->pTwi = pTwi;
pTwid->pTransfer = 0;
/* Initialize XDMA driver instance with polling mode */
// ************* need to be updated XDMAD_Initialize(&twi_dma, 1);
}
/**
* \brief Configure xDMA write linker list for TWI transfer.
*/
static void _xdma_configure_write(uint8_t * buf, uint32_t len, uint8_t twi_id)
{
uint32_t i;
uint32_t xdmaCndc, Thr;
Twi* twi = (Twi*)get_twi_addr_from_id(twi_id);
Thr = (uint32_t) & (TWI0->TWI_THR);
if (twi)
Thr = (uint32_t) & (twi->TWI_THR);
for (i = 0; i < 1; i++) {
dmaWriteLinkList[i].ublock_size = XDMA_UBC_NVIEW_NDV1
| ((i == len - 1) ? 0 : XDMA_UBC_NDE_FETCH_EN)
| len;
dmaWriteLinkList[i].src_addr = & buf[i];
dmaWriteLinkList[i].dest_addr = (void*)Thr;
if (i == len - 1)
dmaWriteLinkList[i].next_desc = 0;
else
dmaWriteLinkList[i].next_desc =
& dmaWriteLinkList[i + 1];
}
twi_dmaCfg.cfg.uint32_value = XDMAC_CC_TYPE_PER_TRAN
| XDMAC_CC_MBSIZE_SINGLE
| XDMAC_CC_DSYNC_MEM2PER
| XDMAC_CC_CSIZE_CHK_1
| XDMAC_CC_DWIDTH_BYTE
| XDMAC_CC_SIF_AHB_IF0
| XDMAC_CC_DIF_AHB_IF1
| XDMAC_CC_SAM_INCREMENTED_AM
| XDMAC_CC_DAM_FIXED_AM
|
XDMAC_CC_PERID(get_peripheral_xdma_channel(twi_id, XDMAC0, true));
xdmaCndc =
XDMAC_CNDC_NDVIEW_NDV1 | XDMAC_CNDC_NDE_DSCR_FETCH_EN |
XDMAC_CNDC_NDSUP_SRC_PARAMS_UPDATED |
XDMAC_CNDC_NDDUP_DST_PARAMS_UNCHANGED;
cp15_coherent_dcache_for_dma((uint32_t) & dmaWriteLinkList,
((uint32_t) & dmaWriteLinkList +
sizeof (*dmaWriteLinkList) * len));
xdmad_configure_transfer(dmaWriteChannel, &twi_dmaCfg,
xdmaCndc, dmaWriteLinkList);
}
/**
* \brief Configure xDMA read linker list for TWI transfer.
*/
static void _xdma_configure_read(uint8_t * buf, uint32_t len, uint8_t twi_id)
{
uint32_t i;
uint32_t xdmaCndc, Rhr;
Twi* twi = get_twi_addr_from_id(twi_id);
Rhr = (uint32_t) & (TWI0->TWI_RHR);
if (twi) {
Rhr = twi->TWI_RHR;
}
/* if (twi_id == ID_TWI1) { */
/* Rhr = (uint32_t) & (TWI1->TWI_RHR); */
/* } */
/* if (twi_id == ID_TWI2) { */
/* Rhr = (uint32_t) & (TWI2->TWI_RHR); */
/* } */
for (i = 0; i < 1; i++) {
dmaReadLinkList[i].ublock_size = XDMA_UBC_NVIEW_NDV1
| ((i == len - 1) ? 0 : XDMA_UBC_NDE_FETCH_EN)
| len;
dmaReadLinkList[i].src_addr = (void*)Rhr;
dmaReadLinkList[i].dest_addr = & buf[i];
if (i == len - 1)
dmaReadLinkList[i].next_desc = 0;
else
dmaReadLinkList[i].next_desc =
& dmaReadLinkList[i + 1];
}
twi_dmaCfg.cfg.uint32_value = XDMAC_CC_TYPE_PER_TRAN
| XDMAC_CC_MBSIZE_SINGLE
| XDMAC_CC_DSYNC_PER2MEM
| XDMAC_CC_CSIZE_CHK_1
| XDMAC_CC_DWIDTH_BYTE
| XDMAC_CC_SIF_AHB_IF1
| XDMAC_CC_DIF_AHB_IF0
| XDMAC_CC_SAM_FIXED_AM
| XDMAC_CC_DAM_INCREMENTED_AM
|
XDMAC_CC_PERID(get_peripheral_xdma_channel(twi_id, XDMAC0, false));
xdmaCndc =
XDMAC_CNDC_NDVIEW_NDV1 | XDMAC_CNDC_NDE_DSCR_FETCH_EN |
XDMAC_CNDC_NDSUP_SRC_PARAMS_UPDATED |
XDMAC_CNDC_NDDUP_DST_PARAMS_UPDATED;
cp15_coherent_dcache_for_dma((uint32_t) & dmaReadLinkList,
((uint32_t) & dmaReadLinkList +
sizeof (*dmaReadLinkList) * len));
xdmad_configure_transfer(dmaReadChannel, &twi_dmaCfg, xdmaCndc,
dmaReadLinkList);
}
/**
* \brief Interrupt handler for a TWI peripheral. Manages asynchronous transfer
* occuring on the bus. This function MUST be called by the interrupt service
* routine of the TWI peripheral if asynchronous read/write are needed.
* \param pTwid Pointer to a Twid instance.
*/
void twid_handler(struct _twid* pTwid)
{
uint32_t status;
struct _async_twi* pTransfer;
Twi *pTwi;
assert(pTwid != NULL);
pTransfer = (struct _async_twi *) pTwid->pTransfer;
assert(pTransfer != NULL);
pTwi = pTwid->pTwi;
assert(pTwi != NULL);
/* Retrieve interrupt status */
status = twi_get_masked_status(pTwi);
/* Byte received */
if (TWI_STATUS_RXRDY(status)) {
pTransfer->pData[pTransfer->transferred] = twi_read_byte(pTwi);
pTransfer->transferred++;
/* check for transfer finish */
if (pTransfer->transferred == pTransfer->num) {
twi_enable_it(pTwi, TWI_IDR_RXRDY);
twi_enable_it(pTwi, TWI_IER_TXCOMP);
}
/* Last byte? */
else if (pTransfer->transferred == (pTransfer->num - 1)) {
twi_stop(pTwi);
}
}
/* Byte sent */
else if (TWI_STATUS_TXRDY(status)) {
/* Transfer finished ? */
if (pTransfer->transferred == pTransfer->num) {
twi_enable_it(pTwi, TWI_IDR_TXRDY);
twi_enable_it(pTwi, TWI_IER_TXCOMP);
twi_send_stop_condition(pTwi);
}
/* Bytes remaining */
else {
twi_write_byte(pTwi,
pTransfer->pData[pTransfer->transferred]);
pTransfer->transferred++;
}
}
/* Transfer complete */
else if (TWI_STATUS_TXCOMP(status)) {
twi_enable_it(pTwi, TWI_IDR_TXCOMP);
pTransfer->status = 0;
if (pTransfer->callback) {
pTransfer->callback((struct _async *) (void *) pTransfer);
}
pTwid->pTransfer = 0;
}
}
/**
* \brief Asynchronously reads data from a slave on the TWI bus. An optional
* callback function is triggered when the transfer is complete.
* \param pTwid Pointer to a Twid instance.
* \param address TWI slave address.
* \param iaddress Optional slave internal address.
* \param isize Internal address size in bytes.
* \param pData Data buffer for storing received bytes.
* \param num Number of bytes to read.
* \param pAsync Asynchronous transfer descriptor.
* \return 0 if the transfer has been started; otherwise returns a TWI error code.
*/
uint8_t twid_read(struct _twid* pTwid, uint8_t address, uint32_t iaddress,
uint8_t isize, uint8_t * pData, uint32_t num, struct _async * pAsync)
{
Twi *pTwi;
struct _async_twi* pTransfer;
uint32_t timeout = 0;
uint32_t i = 0;
uint32_t status;
assert(pTwid != NULL);
pTwi = pTwid->pTwi;
pTransfer = (struct _async_twi*) pTwid->pTransfer;
assert((address & 0x80) == 0);
assert((iaddress & 0xFF000000) == 0);
assert(isize < 4);
/* Check that no transfer is already pending */
if (pTransfer) {
trace_error("twid_read: A transfer is already pending\n\r");
return TWID_ERROR_BUSY;
}
/* Asynchronous transfer */
if (pAsync) {
/* Update the transfer descriptor */
pTwid->pTransfer = pAsync;
pTransfer = (struct _async_twi*) pAsync;
pTransfer->status = ASYNC_STATUS_PENDING;
pTransfer->pData = pData;
pTransfer->num = num;
pTransfer->transferred = 0;
/* Enable read interrupt and start the transfer */
twi_enable_it(pTwi, TWI_IER_RXRDY);
twi_start_read(pTwi, address, iaddress, isize);
}
/* Synchronous transfer */
else {
/* Start read */
twi_start_read(pTwi, address, iaddress, isize);
if (num != 1) {
status = twi_get_status(pTwi);
if (status & TWI_SR_NACK)
trace_error("TWID NACK error\n\r");
timeout = 0;
while (!(status & TWI_SR_RXRDY)
&& (++timeout < TWITIMEOUTMAX)) {
status = twi_get_status(pTwi);
//trace_error("TWID status %x\n\r",twi_get_status(pTwi));
}
pData[0] = twi_read_byte(pTwi);
for (i = 1; i < num - 1; i++) {
status = twi_get_status(pTwi);
if (status & TWI_SR_NACK)
trace_error("TWID NACK error\n\r");
timeout = 0;
while (!(status & TWI_SR_RXRDY)
&& (++timeout < TWITIMEOUTMAX)) {
status = twi_get_status(pTwi);
//trace_error("TWID status %x\n\r",twi_get_status(pTwi));
}
pData[i] = twi_read_byte(pTwi);
}
}
twi_stop(pTwi);
status = twi_get_status(pTwi);
if (status & TWI_SR_NACK)
trace_error("TWID NACK error\n\r");
timeout = 0;
while (!(status & TWI_SR_RXRDY) && (++timeout < TWITIMEOUTMAX)) {
status = twi_get_status(pTwi);
//trace_error("TWID status %x\n\r",twi_get_status(pTwi));
}
pData[i] = twi_read_byte(pTwi);
timeout = 0;
status = twi_get_status(pTwi);
while (!(status & TWI_SR_TXCOMP) && (++timeout < TWITIMEOUTMAX)) {
status = twi_get_status(pTwi);
//trace_error("TWID status %x\n\r",twi_get_status(pTwi));
}
}
return 0;
}
/**
* \brief Asynchronously reads data from a slave on the TWI bus. An optional
* callback function is triggered when the transfer is complete.
* \param pTwid Pointer to a Twid instance.
* \param address TWI slave address.
* \param iaddress Optional slave internal address.
* \param isize Internal address size in bytes.
* \param pData Data buffer for storing received bytes.
* \param num Number of bytes to read.
* \param pAsync Asynchronous transfer descriptor.
* \param twi_id TWI ID for TWI0, TWI1, TWI2.
* \return 0 if the transfer has been started; otherwise returns a TWI error code.
*/
uint8_t twid_dma_read(struct _twid* pTwid, uint8_t address, uint32_t iaddress,
uint8_t isize, uint8_t * pData, uint32_t num, struct _async * pAsync, uint8_t twi_id)
{
Twi *pTwi;
struct _async_twi* pTransfer;
uint32_t timeout = 0;
uint32_t status;
assert(pTwid != NULL);
pTwi = pTwid->pTwi;
pTransfer = (struct _async_twi*) pTwid->pTransfer;
assert((address & 0x80) == 0);
assert((iaddress & 0xFF000000) == 0);
assert(isize < 4);
/* Check that no transfer is already pending */
if (pTransfer) {
trace_error("twid_read: A transfer is already pending\n\r");
return TWID_ERROR_BUSY;
}
/* Asynchronous transfer */
if (pAsync) {
/* Update the transfer descriptor */
pTwid->pTransfer = pAsync;
pTransfer = (struct _async_twi*) pAsync;
pTransfer->status = ASYNC_STATUS_PENDING;
pTransfer->pData = pData;
pTransfer->num = num;
pTransfer->transferred = 0;
/* Enable read interrupt and start the transfer */
twi_enable_it(pTwi, TWI_IER_RXRDY);
twi_start_read(pTwi, address, iaddress, isize);
}
/* Synchronous transfer */
else {
twid_dma_initialize_read(twi_id);
_xdma_configure_read(pData, num, twi_id);
/* Start read */
xdmad_start_transfer(dmaReadChannel);
twi_start_read(pTwi, address, iaddress, isize);
while ((!xdmad_is_transfer_done(dmaReadChannel))
&& (++timeout < TWITIMEOUTMAX))
xdmad_poll();
xdmad_stop_transfer(dmaReadChannel);
status = twi_get_status(pTwi);
timeout = 0;
while (!(status & TWI_SR_RXRDY)
&& (++timeout < TWITIMEOUTMAX)) ;
twi_stop(pTwi);
twi_read_byte(pTwi);
status = twi_get_status(pTwi);
timeout = 0;
while (!(status & TWI_SR_RXRDY)
&& (++timeout < TWITIMEOUTMAX)) ;
twi_read_byte(pTwi);
status = twi_get_status(pTwi);
timeout = 0;
while (!(status & TWI_SR_TXCOMP)
&& (++timeout < TWITIMEOUTMAX)) ;
if (timeout == TWITIMEOUTMAX) {
trace_error("TWID Timeout Read\n\r");
}
xdmad_free_channel(dmaReadChannel);
}
return 0;
}
/**
* \brief Asynchronously sends data to a slave on the TWI bus. An optional callback
* function is invoked whenever the transfer is complete.
* \param pTwid Pointer to a Twid instance.
* \param address TWI slave address.
* \param iaddress Optional slave internal address.
* \param isize Number of internal address bytes.
* \param pData Data buffer for storing received bytes.
* \param num Data buffer to send.
* \param pAsync Asynchronous transfer descriptor.
* \param twi_id TWI ID for TWI0, TWI1, TWI2.
* \return 0 if the transfer has been started; otherwise returns a TWI error code.
*/
uint8_t twid_dma_write(struct _twid* pTwid, uint8_t address, uint32_t iaddress,
uint8_t isize, uint8_t * pData, uint32_t num, struct _async * pAsync, uint8_t twi_id)
{
Twi *pTwi = pTwid->pTwi;
struct _async_twi* pTransfer;
uint32_t timeout = 0;
uint32_t status;
//uint8_t singleTransfer = 0;
assert(pTwi != NULL);
assert((address & 0x80) == 0);
assert((iaddress & 0xFF000000) == 0);
assert(isize < 4);
pTransfer = (struct _async_twi *) pTwid->pTransfer;
// if(num == 1) singleTransfer = 1;
/* Check that no transfer is already pending */
if (pTransfer) {
trace_error("TWI_Write: A transfer is already pending\n\r");
return TWID_ERROR_BUSY;
}
/* Asynchronous transfer */
if (pAsync) {
/* Update the transfer descriptor */
pTwid->pTransfer = pAsync;
pTransfer = (struct _async_twi*) pAsync;
pTransfer->status = ASYNC_STATUS_PENDING;
pTransfer->pData = pData;
pTransfer->num = num;
pTransfer->transferred = 1;
/* Enable write interrupt and start the transfer */
twi_start_write(pTwi, address, iaddress, isize, *pData);
twi_enable_it(pTwi, TWI_IER_TXRDY);
}
/* Synchronous transfer */
else {
cp15_coherent_dcache_for_dma((uint32_t) pData, (uint32_t) pData);
twid_dma_initialize_write(twi_id);
_xdma_configure_write(pData, num, twi_id);
/* Set slave address and number of internal address bytes. */
pTwi->TWI_MMR = 0;
pTwi->TWI_MMR = (isize << 8) | (address << 16);
/* Set internal address bytes. */
pTwi->TWI_IADR = 0;
pTwi->TWI_IADR = iaddress;
xdmad_start_transfer(dmaWriteChannel);
while (!xdmad_is_transfer_done(dmaWriteChannel))
xdmad_poll();
xdmad_stop_transfer(dmaWriteChannel);
status = twi_get_status(pTwi);
timeout = 0;
while (!(status & TWI_SR_TXRDY) && (timeout++ < TWITIMEOUTMAX)) {
status = twi_get_status(pTwi);
}
if (timeout == TWITIMEOUTMAX) {
trace_error("TWID Timeout TXRDY\n\r");
}
/* Send a STOP condition */
twi_stop(pTwi);
status = twi_get_status(pTwi);
timeout = 0;
while (!(status & TWI_SR_TXCOMP) && (++timeout < TWITIMEOUTMAX)) {
status = twi_get_status(pTwi);
}
if (timeout == TWITIMEOUTMAX) {
trace_error("TWID Timeout Write\n\r");
}
cp15_invalidate_dcache_for_dma((uint32_t) pData, (uint32_t) (pData));
xdmad_free_channel(dmaWriteChannel);
}
return 0;
}
/**
* \brief Asynchronously sends data to a slave on the TWI bus. An optional callback
* function is invoked whenever the transfer is complete.
* \param pTwid Pointer to a Twid instance.
* \param address TWI slave address.
* \param iaddress Optional slave internal address.
* \param isize Number of internal address bytes.
* \param pData Data buffer for storing received bytes.
* \param num Data buffer to send.
* \param pAsync Asynchronous transfer descriptor.
* \return 0 if the transfer has been started; otherwise returns a TWI error code.
*/
uint8_t twid_write(struct _twid* pTwid, uint8_t address, uint32_t iaddress,
uint8_t isize, uint8_t * pData, uint32_t num, struct _async * pAsync)
{
Twi *pTwi = pTwid->pTwi;
struct _async_twi* pTransfer;
uint32_t timeout = 0;
uint32_t status;
uint8_t singleTransfer = 0;
assert(pTwi != NULL);
assert((address & 0x80) == 0);
assert((iaddress & 0xFF000000) == 0);
assert(isize < 4);
pTransfer = (struct _async_twi *) pTwid->pTransfer;
if (num == 1)
singleTransfer = 1;
/* Check that no transfer is already pending */
if (pTransfer) {
trace_error("TWI_Write: A transfer is already pending\n\r");
return TWID_ERROR_BUSY;
}
/* Asynchronous transfer */
if (pAsync) {
/* Update the transfer descriptor */
pTwid->pTransfer = pAsync;
pTransfer = (struct _async_twi*) pAsync;
pTransfer->status = ASYNC_STATUS_PENDING;
pTransfer->pData = pData;
pTransfer->num = num;
pTransfer->transferred = 1;
/* Enable write interrupt and start the transfer */
twi_start_write(pTwi, address, iaddress, isize, *pData);
twi_enable_it(pTwi, TWI_IER_TXRDY);
}
/* Synchronous transfer */
else {
// Start write
twi_start_write(pTwi, address, iaddress, isize, *pData++);
num--;
if (singleTransfer) {
/* Send a STOP condition */
twi_send_stop_condition(pTwi);
}
status = twi_get_status(pTwi);
if (status & TWI_SR_NACK)
trace_error("TWID NACK error\n\r");
while (!(status & TWI_SR_TXRDY) && (timeout++ < TWITIMEOUTMAX)) {
status = twi_get_status(pTwi);
}
if (timeout == TWITIMEOUTMAX) {
trace_error("TWID Timeout BS\n\r");
}
timeout = 0;
/* Send all bytes */
while (num > 0) {
/* Wait before sending the next byte */
timeout = 0;
twi_write_byte(pTwi, *pData++);
status = twi_get_status(pTwi);
if (status & TWI_SR_NACK)
trace_error("TWID NACK error\n\r");
while (!(status & TWI_SR_TXRDY)
&& (timeout++ < TWITIMEOUTMAX)) {
status = twi_get_status(pTwi);
}
if (timeout == TWITIMEOUTMAX) {
trace_error("TWID Timeout BS\n\r");
}
num--;
}
/* Wait for actual end of transfer */
timeout = 0;
if (!singleTransfer) {
/* Send a STOP condition */
twi_send_stop_condition(pTwi);
}
while (!twi_is_transfer_complete(pTwi)
&& (++timeout < TWITIMEOUTMAX)) ;
if (timeout == TWITIMEOUTMAX) {
trace_error("TWID Timeout TC2\n\r");
}
}
return 0;
}

View file

@ -0,0 +1,128 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
#ifndef _TWID_
#define _TWID_
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "board.h"
#include "peripherals/twi.h"
#include "async.h"
#include <stdint.h>
/*----------------------------------------------------------------------------
* Definition
*----------------------------------------------------------------------------*/
/** TWI driver is currently busy. */
#define TWID_ERROR_BUSY 1
// TWI clock frequency in Hz.
#define TWCK_400K 400000
#define TWCK_200K 200000
#define TWCK_100K 100000
#ifdef __cplusplus
extern "C" {
#endif
/*----------------------------------------------------------------------------
* Types
*----------------------------------------------------------------------------*/
/** \brief TWI driver structure. Holds the internal state of the driver.*/
struct _twid {
Twi *pTwi; /** Pointer to the underlying TWI peripheral.*/
struct _async *pTransfer; /** Current asynchronous transfer being processed.*/
};
struct _handler_twi
{
uint8_t IdTwi; // ID TWI
uint8_t Status; // status of the TWI
uint8_t PeriphAddr; // Address of the component
uint8_t LenData; // Lenfth of the data to be read or write
uint8_t AddSize; // Size of the address
uint16_t RegMemAddr; // Address of the memory or register
uint32_t Twck; // default clock of the bus TWI
uint8_t* pData; // pointer to a data buffer
struct _twid twid;
};
enum TWI_CMD
{
TWI_RD = 0,
TWI_WR = 1
};
enum TWI_STATUS
{
TWI_STATUS_RESET = 0,
TWI_STATUS_HANDLE = 1u<<0,
TWI_STATUS_RFU2 = 1u<<1,
TWI_STATUS_RFU3 = 1u<<2,
TWI_STATUS_RFU4 = 1u<<3,
TWI_STATUS_READY = 1u<<7,
};
enum TWI_RESULT
{
TWI_SUCCES = 0,
TWI_FAIL = 1
};
/*----------------------------------------------------------------------------
* Export functions
*----------------------------------------------------------------------------*/
extern void twid_initialize(struct _twid* pTwid, Twi * pTwi);
extern void twid_handler(struct _twid* pTwid);
extern uint8_t twid_read(struct _twid* pTwid, uint8_t address, uint32_t iaddress,
uint8_t isize, uint8_t * pData, uint32_t num, struct _async * pAsync);
extern uint8_t twid_dma_read(struct _twid* pTwid, uint8_t address, uint32_t iaddress,
uint8_t isize, uint8_t * pData, uint32_t num,
struct _async * pAsync, uint8_t TWI_ID);
extern uint8_t twid_write(struct _twid* pTwid, uint8_t address, uint32_t iaddress,
uint8_t isize, uint8_t * pData, uint32_t num, struct _async * pAsync);
extern uint8_t twid_dma_write(struct _twid* pTwid, uint8_t address,
uint32_t iaddress, uint8_t isize, uint8_t * pData,
uint32_t num, struct _async * pAsync, uint8_t TWI_ID);
#ifdef __cplusplus
}
#endif
#endif //#ifndef TWID_H

View file

@ -0,0 +1,135 @@
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2015, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: 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
* 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.
* ----------------------------------------------------------------------------
*/
/*------------------------------------------------------------------------------
* Headers
*------------------------------------------------------------------------------*/
#include "chip.h"
#include "peripherals/uart.h"
#include "peripherals/pmc.h"
#include <stdint.h>
/*------------------------------------------------------------------------------
* Exported functions
*------------------------------------------------------------------------------*/
/*
* Initializes the UART with the given parameters, and enables both the
* transmitter and the receiver. The mode parameter contains the value of the
* UART_MR register.
* Value UART_STANDARD can be used for mode to get the most common configuration
* (i.e. aysnchronous, 8bits, no parity, 1 stop bit, no flow control).
* \param mode Operating mode to configure.
* \param baudrate Desired baudrate (e.g. 115200).
* \param mck Frequency of the system master clock in Hz.
*/
void uart_configure(Uart* pUart, uint32_t mode, uint32_t baudrate)
{
uint32_t uart_id = get_uart_id_from_addr(pUart);
// Reset & disable receiver and transmitter, disable interrupts
pUart->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX | UART_CR_RXDIS | UART_CR_TXDIS
| UART_CR_RSTSTA;
pUart->UART_IDR = 0xFFFFFFFF;
// Configure baud rate
pUart->UART_BRGR = pmc_get_peripheral_clock(uart_id) / (baudrate * 16);
// Configure mode register
pUart->UART_MR = mode;
// Enable receiver and transmitter
pUart->UART_CR = UART_CR_RXEN | UART_CR_TXEN;
}
/* Enable transmitter
*
*/
void uart_set_transmitter_enabled (Uart* pUart, uint8_t enabled)
{
if (enabled) pUart->UART_CR = UART_CR_TXEN;
else pUart->UART_CR = UART_CR_TXDIS;
}
/* Enable receiver
*
*/
void uart_set_receiver_enabled (Uart* pUart, uint8_t enabled)
{
if (enabled)
pUart->UART_CR = UART_CR_RXEN;
else
pUart->UART_CR = UART_CR_RXDIS;
}
/* Set interrupt register
*
*/
void uart_set_int (Uart* pUart, uint32_t int_mask)
{
pUart->UART_IER |= int_mask;
}
/**
* Outputs a character on the UART line.
* \note This function is synchronous (i.e. uses polling).
* \param c Character to send.
*/
void uart_put_char(Uart* pUart, uint8_t c)
{
// Wait for the transmitter to be ready
while ((pUart->UART_SR & UART_SR_TXEMPTY) == 0);
// Send character
pUart->UART_THR = c;
}
/**
* Return 1 if a character can be read in UART
*/
uint32_t uart_is_rx_ready(Uart* pUart)
{
return (pUart->UART_SR & UART_SR_RXRDY);
}
/**
* Return 1 if a character can be write in UART
*/
uint32_t uart_is_tx_ready(Uart* pUart)
{
return (pUart->UART_SR & UART_SR_TXRDY);
}
/**
* \brief Reads and returns a character from the UART.
* \note This function is synchronous (i.e. uses polling).
* \return Character received.
*/
uint8_t uart_get_char(Uart* pUart)
{
while ((pUart->UART_SR & UART_SR_RXRDY) == 0);
return pUart->UART_RHR;
}

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