1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-06-17 22:23:10 +03:00

[sam] adding more peripherals to SAM3X/Due

This commit is contained in:
Thibaut VIARD
2012-12-19 15:20:14 +01:00
parent acfd670124
commit 5d0ba1c64a
19 changed files with 5431 additions and 48 deletions

View File

@ -32,9 +32,9 @@
#define part_is_defined(part) (defined(__ ## part ## __))
/*
/*
* ----------------------------------------------------------------------------
* SAM3 family
* SAM3 family
* ----------------------------------------------------------------------------
*/
@ -66,8 +66,17 @@
/* Entire SAM3N series */
#define SAM3N_SERIES (SAM3N00 || SAM3N0 || SAM3N1 || SAM3N2 || SAM3N4)
/* SAM3S series */
#define SAM3S00 ( \
part_is_defined( SAM3S00A ) || \
part_is_defined( SAM3S00B ) )
#define SAM3S0 ( \
part_is_defined( SAM3S0A ) || \
part_is_defined( SAM3S0B ) || \
part_is_defined( SAM3S0C ) )
#define SAM3S1 ( \
part_is_defined( SAM3S1A ) || \
part_is_defined( SAM3S1B ) || \
@ -84,7 +93,7 @@
part_is_defined( SAM3S4C ) )
/* Entire SAM3S series */
#define SAM3S_SERIES (SAM3S1 || SAM3S2 || SAM3S4)
#define SAM3S_SERIES (SAM3S00 || SAM3S0 ||SAM3S1 || SAM3S2 || SAM3S4)
/* SAM3SD8 series */
#define SAM3S8 ( \
@ -133,9 +142,9 @@
/* Entire SAM3XA series */
#define SAM3XA_SERIES ( SAM3X4 || SAM3X8 || SAM3A4 || SAM3A8)
/*
/*
* ----------------------------------------------------------------------------
* SAM4 family
* SAM4 family
* ----------------------------------------------------------------------------
*/
@ -158,30 +167,30 @@
/* Entire SAM4 Family */
#define SAM4_SERIES ( SAM4S_SERIES )
/*
/*
* ----------------------------------------------------------------------------
* SAM9 family
* SAM9 family
* ----------------------------------------------------------------------------
*/
/*
/*
* ----------------------------------------------------------------------------
* SAM7 family
* SAM7 family
* ----------------------------------------------------------------------------
*/
/*
/*
* ----------------------------------------------------------------------------
* Whole SAM product line
* ----------------------------------------------------------------------------
*/
#define SAM ( SAM3_SERIES || SAM4_SERIES )
/*
/*
* ----------------------------------------------------------------------------
* Header inclusion
* Header inclusion
* ----------------------------------------------------------------------------
*/

View File

@ -25,8 +25,9 @@ SUBMAKE_OPTIONS=--no-builtin-rules --no-builtin-variables --no-print-directory
#-------------------------------------------------------------------------------
# libsam_sam3s4c_gcc_rel.a libsam_sam3u4e_gcc_rel.a libsam_sam3x8e_gcc_rel.a libsam_sam3x8h_gcc_rel.a
all: libsam_sam3s4c_gcc_dbg.a libsam_sam3u4e_gcc_dbg.a libsam_sam3x8e_gcc_dbg.a libsam_sam3x8h_gcc_dbg.a
all: libsam_sam3s4c_gcc_dbg.a libsam_sam3u4e_gcc_dbg.a libsam_sam3x8e_gcc_dbg.a libsam_sam3x8h_gcc_dbg.a arduino_due_x
.PHONY: arduino_due_u
arduino_due_u:
@echo ------------------------------------------------------------------------------------
@echo --- Making $@
@ -34,6 +35,7 @@ arduino_due_u:
@$(MAKE) CHIP=__SAM3U4E__ $(SUBMAKE_OPTIONS) OUTPUT_BIN=../../../variants/arduino_due_u -f sam3.mk
@echo ------------------------------------------------------------------------------------
.PHONY: arduino_due_x
arduino_due_x:
@echo ------------------------------------------------------------------------------------
@echo --- Making $@

View File

@ -42,14 +42,20 @@
* Peripherals
*/
#include "include/adc.h"
#if (SAM3XA_SERIES) || (SAM3N_SERIES) || (SAM3S_SERIES)
#include "include/dacc.h"
#endif // (SAM3XA_SERIES) || (SAM3N_SERIES) || (SAM3S_SERIES)
#include "include/interrupt_sam_nvic.h"
#include "include/efc.h"
#include "include/gpbr.h"
#include "include/pio.h"
#include "include/pmc.h"
#include "include/pwmc.h"
#include "include/rtc.h"
#include "include/rtt.h"
#include "include/spi.h"
#include "include/ssc.h"
#include "include/tc.h"
#include "include/twi.h"
#include "include/usart.h"
@ -59,9 +65,12 @@
#include "include/USB_device.h"
#include "include/USB_host.h"
#if SAM3XA_SERIES
#if (SAM3XA_SERIES)
#include "include/can.h"
//#include "include/emac.h"
#include "include/trng.h"
#include "include/uotghs_device.h"
#include "include/uotghs_host.h"
#endif /* SAM3XA_SERIES */
#endif /* (SAM3XA_SERIES) */
#endif /* _LIB_SAM_ */

View File

@ -0,0 +1,468 @@
/**
* \file
*
* \brief Controller Area Network (CAN) driver module for SAM.
*
* Copyright (c) 2011 - 2012 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#ifndef CAN_H_INCLUDED
#define CAN_H_INCLUDED
#include "../chip.h"
/** @cond 0 */
/**INDENT-OFF**/
#ifdef __cplusplus
extern "C" {
#endif
/**INDENT-ON**/
/** @endcond */
/** Define the Mailbox mask for eight mailboxes. */
#define GLOBAL_MAILBOX_MASK 0x000000ff
/** Disable all interrupt mask */
#define CAN_DISABLE_ALL_INTERRUPT_MASK 0xffffffff
/** Define the typical baudrate for CAN communication in KHz. */
#define CAN_BPS_1000K 1000
#define CAN_BPS_800K 800
#define CAN_BPS_500K 500
#define CAN_BPS_250K 250
#define CAN_BPS_125K 125
#define CAN_BPS_50K 50
#define CAN_BPS_25K 25
#define CAN_BPS_10K 10
#define CAN_BPS_5K 5
/** Define the mailbox mode. */
#define CAN_MB_DISABLE_MODE 0
#define CAN_MB_RX_MODE 1
#define CAN_MB_RX_OVER_WR_MODE 2
#define CAN_MB_TX_MODE 3
#define CAN_MB_CONSUMER_MODE 4
#define CAN_MB_PRODUCER_MODE 5
/** Define CAN mailbox transfer status code. */
#define CAN_MAILBOX_TRANSFER_OK 0 //! Read from or write into mailbox successfully.
#define CAN_MAILBOX_NOT_READY 0x01 //! Receiver is empty or transmitter is busy.
#define CAN_MAILBOX_RX_OVER 0x02 //! Message overwriting happens or there're messages lost in different receive modes.
#define CAN_MAILBOX_RX_NEED_RD_AGAIN 0x04 //! Application needs to re-read the data register in Receive with Overwrite mode.
/** Define the struct for CAN message mailbox. */
typedef struct {
uint32_t ul_mb_idx;
uint8_t uc_obj_type; //! Mailbox object type, one of the six different objects.
uint8_t uc_id_ver; //! 0 stands for standard frame, 1 stands for extended frame.
uint8_t uc_length; //! Received data length or transmitted data length.
uint8_t uc_tx_prio; //! Mailbox priority, no effect in receive mode.
uint32_t ul_status; //! Mailbox status register value.
uint32_t ul_id_msk; //! No effect in transmit mode.
uint32_t ul_id; //! Received frame ID or the frame ID to be transmitted.
uint32_t ul_fid; //! Family ID.
uint32_t ul_datal;
uint32_t ul_datah;
} can_mb_conf_t;
/**
* \defgroup sam_driver_can_group Controller Area Network (CAN) Driver
*
* See \ref sam_can_quickstart.
*
* \par Purpose
*
* The CAN controller provides all the features required to implement
* the serial communication protocol CAN defined by Robert Bosch GmbH,
* the CAN specification. This is a driver for configuration, enabling,
* disabling and use of the CAN peripheral.
*
* @{
*/
uint32_t can_init(Can *p_can, uint32_t ul_mck, uint32_t ul_baudrate);
void can_enable(Can *p_can);
void can_disable(Can *p_can);
void can_disable_low_power_mode(Can *p_can);
void can_enable_low_power_mode(Can *p_can);
void can_disable_autobaud_listen_mode(Can *p_can);
void can_enable_autobaud_listen_mode(Can *p_can);
void can_disable_overload_frame(Can *p_can);
void can_enable_overload_frame(Can *p_can);
void can_set_timestamp_capture_point(Can *p_can, uint32_t ul_flag);
void can_disable_time_triggered_mode(Can *p_can);
void can_enable_time_triggered_mode(Can *p_can);
void can_disable_timer_freeze(Can *p_can);
void can_enable_timer_freeze(Can *p_can);
void can_disable_tx_repeat(Can *p_can);
void can_enable_tx_repeat(Can *p_can);
void can_set_rx_sync_stage(Can *p_can, uint32_t ul_stage);
void can_enable_interrupt(Can *p_can, uint32_t dw_mask);
void can_disable_interrupt(Can *p_can, uint32_t dw_mask);
uint32_t can_get_interrupt_mask(Can *p_can);
uint32_t can_get_status(Can *p_can);
uint32_t can_get_internal_timer_value(Can *p_can);
uint32_t can_get_timestamp_value(Can *p_can);
uint8_t can_get_tx_error_cnt(Can *p_can);
uint8_t can_get_rx_error_cnt(Can *p_can);
void can_reset_internal_timer(Can *p_can);
void can_global_send_transfer_cmd(Can *p_can, uint8_t uc_mask);
void can_global_send_abort_cmd(Can *p_can, uint8_t uc_mask);
void can_mailbox_set_timemark(Can *p_can, uint8_t uc_index, uint16_t us_cnt);
uint32_t can_mailbox_get_status(Can *p_can, uint8_t uc_index);
void can_mailbox_send_transfer_cmd(Can *p_can, uint8_t uc_index);
void can_mailbox_send_abort_cmd(Can *p_can, uint8_t uc_index);
void can_mailbox_init(Can *p_can, can_mb_conf_t *p_mailbox);
uint32_t can_mailbox_read(Can *p_can, can_mb_conf_t *p_mailbox);
uint32_t can_mailbox_write(Can *p_can, can_mb_conf_t *p_mailbox);
uint32_t can_mailbox_tx_remote_frame(Can *p_can, can_mb_conf_t *p_mailbox);
void can_reset_all_mailbox(Can *p_can);
/** @} */
/** @cond 0 */
/**INDENT-OFF**/
#ifdef __cplusplus
}
#endif
/**INDENT-ON**/
/** @endcond */
/**
* \page sam_can_quickstart Quickstart guide for SAM CAN module.
*
* This is the quickstart guide for the \ref sam_drivers_can_group "SAM CAN module",
* with step-by-step instructions on how to configure and use the drivers in a
* selection of use cases.
*
* The use cases contain several code fragments. The code fragments in the
* steps for setup can be copied into a custom initialization function, while
* the steps for usage can be copied into, e.g., the main application function.
*
* \section can_basic_use_case Basic use case
* In this basic use case, as CAN module needs to work in network, two CAN modules
* need to be configured. CAN0 mailbox 0 is configured as transmitter, and CAN1 mailbox 0
* is configured as receiver. The communication baudrate is 1Mbit/s.
*
* \section can_basic_use_case_setup Setup steps
*
* \subsection can_basic_use_case_setup_prereq Prerequisites
* - \ref group_pmc "Power Management Controller driver"
* - \ref group_sn65hvd234_transceiver "CAN transceiver driver"
*
* \subsection can_basic_use_case_setup_code Example code
* Add to application initialization:
* \code
* can_mb_conf_t can0_mailbox;
* can_mb_conf_t can1_mailbox;
*
* pmc_enable_periph_clk(ID_CAN0);
* pmc_enable_periph_clk(ID_CAN1);
*
* can_init(CAN0, ul_sysclk, CAN_BPS_1000K);
* can_init(CAN1, ul_sysclk, CAN_BPS_1000K);
*
* can_reset_all_mailbox(CAN0);
* can_reset_all_mailbox(CAN1);
*
* can1_mailbox.ul_mb_idx = 0;
* can1_mailbox.uc_obj_type = CAN_MB_RX_MODE;
* can1_mailbox.ul_id_msk = CAN_MAM_MIDvA_Msk | CAN_MAM_MIDvB_Msk;
* can1_mailbox.ul_id = CAN_MID_MIDvA(0x07);
* can_mailbox_init(CAN1, &can1_mailbox);
*
* can0_mailbox.ul_mb_idx = 0;
* can0_mailbox.uc_obj_type = CAN_MB_TX_MODE;
* can0_mailbox.uc_tx_prio = 15;
* can0_mailbox.uc_id_ver = 0;
* can0_mailbox.ul_id_msk = 0;
* can_mailbox_init(CAN0, &can0_mailbox);
*
* can0_mailbox.ul_id = CAN_MID_MIDvA(0x07);
* can0_mailbox.ul_datal = 0x12345678;
* can0_mailbox.ul_datah = 0x87654321;
* can0_mailbox.uc_length = 8;
* can_mailbox_write(CAN0, &can0_mailbox);
* \endcode
*
* \subsection can_basic_use_case_setup_flow Workflow
* -# Define the CAN0 and CAN1 Transfer mailbox structure:
* - \code
* can_mb_conf_t can0_mailbox;
* can_mb_conf_t can1_mailbox;
* \endcode
* -# Enable the module clock for CAN0 and CAN1:
* - \code
* pmc_enable_periph_clk(ID_CAN0);
* pmc_enable_periph_clk(ID_CAN1);
* \endcode
* -# Initialize CAN0 and CAN1, baudrate is 1Mb/s:
* - \code
* can_init(CAN0, ul_sysclk, CAN_BPS_1000K);
* can_init(CAN1, ul_sysclk, CAN_BPS_1000K);
* \endcode
* - \note The CAN transceiver should be configured before initializing the CAN module.
* -# Reset all CAN0 and CAN1 mailboxes:
* - \code
* can_reset_all_mailbox(CAN0);
* can_reset_all_mailbox(CAN1);
* \endcode
* -# Initialize CAN1 mailbox 0 as receiver, frame ID is 0x07:
* - \code
* can1_mailbox.ul_mb_idx = 0;
* can1_mailbox.uc_obj_type = CAN_MB_RX_MODE;
* can1_mailbox.ul_id_msk = CAN_MAM_MIDvA_Msk | CAN_MAM_MIDvB_Msk;
* can1_mailbox.ul_id = CAN_MID_MIDvA(0x07);
* can_mailbox_init(CAN1, &can1_mailbox);
* \endcode
* -# Initialize CAN0 mailbox 0 as transmitter, transmit priority is 15:
* - \code
* can0_mailbox.ul_mb_idx = 0;
* can0_mailbox.uc_obj_type = CAN_MB_TX_MODE;
* can0_mailbox.uc_tx_prio = 15;
* can0_mailbox.uc_id_ver = 0;
* can0_mailbox.ul_id_msk = 0;
* can_mailbox_init(CAN0, &can0_mailbox);
* \endcode
* -# Prepare transmit ID, data and data length in CAN0 mailbox 0:
* - \code
* can0_mailbox.ul_id = CAN_MID_MIDvA(0x07);
* can0_mailbox.ul_datal = 0x12345678;
* can0_mailbox.ul_datah = 0x87654321;
* can0_mailbox.uc_length = 8;
* can_mailbox_write(CAN0, &can0_mailbox);
* \endcode
*
* \section can_basic_use_case_usage Usage steps
*
* \subsection can_basic_use_case_usage_code Example code
* Add to, e.g., main loop in application C-file:
* \code
* can_global_send_transfer_cmd(CAN0, CAN_TCR_MB0);
*
* while (!(can_mailbox_get_status(CAN1, 0) & CAN_MSR_MRDY)) {
* }
*
* can_mailbox_read(CAN1, &can1_mailbox);
* \endcode
*
* \subsection can_basic_use_case_usage_flow Workflow
* -# Send out data in CAN0 mailbox 0:
* - \code can_global_send_transfer_cmd(CAN0, CAN_TCR_MB0); \endcode
* -# Wait for CAN1 mailbox 0 to receive the data:
* - \code
* while (!(can_mailbox_get_status(CAN1, 0) & CAN_MSR_MRDY)) {
* }
* \endcode
* -# Read the received data from CAN1 mailbox 0:
* - \code can_mailbox_read(CAN1, &can1_mailbox); \endcode
*
* \section can_use_cases Advanced use cases
* For more advanced use of the CAN driver, see the following use cases:
* - \subpage can_use_case_1 : Two CAN modules work in PRODUCER and CONSUMER mode
* respectively, use CAN interrupt handler to check whether the communication has been
* completed.
*/
/**
* \page can_use_case_1 Use case #1
*
* In this use case, CAN0 mailbox 0 works in PRODUCER mode, and CAN1 mailbox 0
* works in CONSUMER mode. While CAN1 mailbox 0 receives a data frame from the bus,
* an interrupt is triggered.
*
* \section can_use_case_1_setup Setup steps
*
* \subsection can_basic_use_case_setup_prereq Prerequisites
* - \ref group_pmc "Power Management Controller driver"
* - \ref group_sn65hvd234_transceiver "CAN transceiver driver"
*
* \subsection can_use_case_1_setup_code Example code
* Add to application C-file:
* \code
* can_mb_conf_t can0_mailbox;
* can_mb_conf_t can1_mailbox;
* volatile uint32_t g_ul_recv_status = 0;
* \endcode
*
* \code
* void CAN1_Handler(void)
* {
* uint32_t ul_status;
*
* ul_status = can_mailbox_get_status(CAN1, 0);
* if ((ul_status & CAN_MSR_MRDY) == CAN_MSR_MRDY) {
* can1_mailbox.ul_mb_idx = 0;
* can1_mailbox.ul_status = ul_status;
* can_mailbox_read(CAN1, &can1_mailbox);
* g_ul_recv_status = 1;
* }
* }
* \endcode
*
* \code
* pmc_enable_periph_clk(ID_CAN0);
* pmc_enable_periph_clk(ID_CAN1);
*
* can_init(CAN0, ul_sysclk, CAN_BPS_1000K);
* can_init(CAN1, ul_sysclk, CAN_BPS_1000K);
*
* can_reset_all_mailbox(CAN0);
* can_reset_all_mailbox(CAN1);
*
* can0_mailbox.ul_mb_idx = 0;
* can0_mailbox.uc_obj_type = CAN_MB_PRODUCER_MODE;
* can0_mailbox.ul_id_msk = 0;
* can0_mailbox.ul_id = CAN_MID_MIDvA(0x0b);
* can_mailbox_init(CAN0, &can0_mailbox);
*
* can0_mailbox.ul_datal = 0x11223344;
* can0_mailbox.ul_datah = 0x44332211;
* can0_mailbox.uc_length = 8;
* can_mailbox_write(CAN0, &can0_mailbox);
*
* can1_mailbox.ul_mb_idx = 0;
* can1_mailbox.uc_obj_type = CAN_MB_CONSUMER_MODE;
* can1_mailbox.uc_tx_prio = 15;
* can1_mailbox.ul_id_msk = CAN_MID_MIDvA_Msk | CAN_MID_MIDvB_Msk;
* can1_mailbox.ul_id = CAN_MID_MIDvA(0x0b);
* can_mailbox_init(CAN1, &can1_mailbox);
*
* can_enable_interrupt(CAN1, CAN_IER_MB0);
* NVIC_EnableIRQ(CAN1_IRQn);
* \endcode
*
* \subsection can_use_case_1_setup_flow Workflow
* -# Define the CAN0 and CAN1 Transfer mailbox structure:
* - \code
* can_mb_conf_t can0_mailbox;
* can_mb_conf_t can1_mailbox;
* \endcode
* -# Define the receive flag that is changed in CAN1 ISR handler:
* - \code volatile uint32_t g_ul_recv_status = 0; \endcode
* -# Define the CAN1 ISR handler in the application:
* - \code void CAN1_Handler(void); \endcode
* -# In CAN1_Handler(), get CAN1 mailbox 0 status:
* - \code ul_status = can_mailbox_get_status(CAN1, 0); \endcode
* -# In CAN1_Handler(), check whether the mailbox 0 has received a data frame:
* - \code
* if ((ul_status & CAN_MSR_MRDY) == CAN_MSR_MRDY) {
* can1_mailbox.ul_mb_idx = 0;
* can1_mailbox.ul_status = ul_status;
* can_mailbox_read(CAN1, &can1_mailbox);
* g_ul_recv_status = 1;
* }
* \endcode
* -# In CAN1_Handler(), if mailbox 0 is ready, read the received data from CAN1 mailbox 0:
* - \code
* can1_mailbox.ul_mb_idx = 0;
* can1_mailbox.ul_status = ul_status;
* can_mailbox_read(CAN1, &can1_mailbox);
* \endcode
* -# In CAN1_Handler(), if mailbox 0 is ready, set up the receive flag:
* - \code g_ul_recv_status = 1; \endcode
* -# Enable the module clock for CAN0 and CAN1:
* - \code
* pmc_enable_periph_clk(ID_CAN0);
* pmc_enable_periph_clk(ID_CAN1);
* \endcode
* -# Initialize CAN0 and CAN1, baudrate is 1Mb/s:
* - \code
* can_init(CAN0, ul_sysclk, CAN_BPS_1000K);
* can_init(CAN1, ul_sysclk, CAN_BPS_1000K);
* \endcode
* - \note The CAN transceiver should be configured before initializing the CAN module.
* -# Reset all CAN0 and CAN1 mailboxes:
* - \code
* can_reset_all_mailbox(CAN0);
* can_reset_all_mailbox(CAN1);
* \endcode
* -# Initialize CAN0 mailbox 0 as PRODUCER:
* - \code
* can0_mailbox.ul_mb_idx = 0;
* can0_mailbox.uc_obj_type = CAN_MB_PRODUCER_MODE;
* can0_mailbox.ul_id_msk = 0;
* can0_mailbox.ul_id = CAN_MID_MIDvA(0x0b);
* can_mailbox_init(CAN0, &can0_mailbox);
* \endcode
* -# Prepare the response information when it receives a remote frame:
* - \code
* can0_mailbox.ul_datal = 0x11223344;
* can0_mailbox.ul_datah = 0x44332211;
* can0_mailbox.uc_length = 8;
* can_mailbox_write(CAN0, &can0_mailbox);
* \endcode
* -# Initialize CAN1 mailbox 0 as CONSUMER:
* - \code
* can1_mailbox.ul_mb_idx = 0;
* can1_mailbox.uc_obj_type = CAN_MB_CONSUMER_MODE;
* can1_mailbox.uc_tx_prio = 15;
* can1_mailbox.ul_id_msk = CAN_MID_MIDvA_Msk | CAN_MID_MIDvB_Msk;
* can1_mailbox.ul_id = CAN_MID_MIDvA(0x0b);
* can_mailbox_init(CAN1, &can1_mailbox);
* \endcode
* -# Enable the CAN1 mailbox 0 interrupt:
* - \code
* can_enable_interrupt(CAN1, CAN_IER_MB0);
* NVIC_EnableIRQ(CAN1_IRQn);
* \endcode
*
* \section can_use_case_1_usage Usage steps
*
* \subsection can_use_case_1_usage_code Example code
* \code
* can_global_send_transfer_cmd(CAN0, CAN_TCR_MB0);
* can_global_send_transfer_cmd(CAN1, CAN_TCR_MB0);
*
* while (!g_ul_recv_status) {
* }
* \endcode
*
* \subsection can_use_case_1_usage_flow Workflow
* -# Enable CAN0 mailbox 0 to receive remote frame and respond it:
* - \code can_global_send_transfer_cmd(CAN0, CAN_TCR_MB0); \endcode
* -# Enable CAN1 mailbox 0 to send out a remote frame and then receive data frame from bus:
* - \code can_global_send_transfer_cmd(CAN1, CAN_TCR_MB0); \endcode
* -# Wait for the communication to be completed.
* - \code
* while (!g_ul_recv_status) {
* }
* \endcode
*/
#endif /* CAN_H_INCLUDED */

View File

@ -0,0 +1,132 @@
/**
* \file
*
* \brief Embedded Flash Controller (EFC) driver for SAM.
*
* Copyright (c) 2011-2012 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#ifndef EFC_H_INCLUDED
#define EFC_H_INCLUDED
#include "../chip.h"
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
extern "C" {
#endif
/**INDENT-ON**/
/// @endcond
/*! \name EFC return codes */
//! @{
typedef enum efc_rc {
EFC_RC_OK = 0, //!< Operation OK
EFC_RC_YES = 0, //!< Yes
EFC_RC_NO = 1, //!< No
EFC_RC_ERROR = 1, //!< General error
EFC_RC_INVALID, //!< Invalid argument input
EFC_RC_NOT_SUPPORT = 0xFFFFFFFF //!< Operation is not supported
} efc_rc_t;
//! @}
/*! \name EFC command */
//! @{
#define EFC_FCMD_GETD 0x00 //!< Get Flash Descriptor
#define EFC_FCMD_WP 0x01 //!< Write page
#define EFC_FCMD_WPL 0x02 //!< Write page and lock
#define EFC_FCMD_EWP 0x03 //!< Erase page and write page
#define EFC_FCMD_EWPL 0x04 //!< Erase page and write page then lock
#define EFC_FCMD_EA 0x05 //!< Erase all
#if (SAM3SD8_SERIES)
#define EFC_FCMD_EPL 0x06 //!< Erase plane
#endif
#if (SAM4S_SERIES)
#define EFC_FCMD_EPA 0x07 //!< Erase pages
#endif
#define EFC_FCMD_SLB 0x08 //!< Set Lock Bit
#define EFC_FCMD_CLB 0x09 //!< Clear Lock Bit
#define EFC_FCMD_GLB 0x0A //!< Get Lock Bit
#define EFC_FCMD_SGPB 0x0B //!< Set GPNVM Bit
#define EFC_FCMD_CGPB 0x0C //!< Clear GPNVM Bit
#define EFC_FCMD_GGPB 0x0D //!< Get GPNVM Bit
#define EFC_FCMD_STUI 0x0E //!< Start unique ID
#define EFC_FCMD_SPUI 0x0F //!< Stop unique ID
#if (SAM3S_SERIES || SAM3N_SERIES || SAM3XA_SERIES || SAM4S_SERIES)
#define EFC_FCMD_GCALB 0x10 //!< Get CALIB Bit
#endif
#if (SAM4S_SERIES)
#define EFC_FCMD_ES 0x11 //!< Erase sector
#define EFC_FCMD_WUS 0x12 //!< Write user signature
#define EFC_FCMD_EUS 0x13 //!< Erase user signature
#define EFC_FCMD_STUS 0x14 //!< Start read user signature
#define EFC_FCMD_SPUS 0x15 //!< Stop read user signature
#endif
//! @}
/*! The IAP function entry address */
#define CHIP_FLASH_IAP_ADDRESS (IROM_ADDR + 8)
/*! \name EFC access mode */
//! @{
#define EFC_ACCESS_MODE_128 0
#define EFC_ACCESS_MODE_64 EEFC_FMR_FAM
//! @}
uint32_t efc_init(Efc *p_efc, uint32_t ul_access_mode, uint32_t ul_fws);
void efc_enable_frdy_interrupt(Efc *p_efc);
void efc_disable_frdy_interrupt(Efc *p_efc);
void efc_set_flash_access_mode(Efc *p_efc, uint32_t ul_mode);
uint32_t efc_get_flash_access_mode(Efc *p_efc);
void efc_set_wait_state(Efc *p_efc, uint32_t ul_fws);
uint32_t efc_get_wait_state(Efc *p_efc);
uint32_t efc_perform_command(Efc *p_efc, uint32_t ul_command, uint32_t ul_argument);
uint32_t efc_get_status(Efc *p_efc);
uint32_t efc_get_result(Efc *p_efc);
uint32_t efc_perform_read_sequence(Efc *p_efc, uint32_t ul_cmd_st, uint32_t ul_cmd_sp, uint32_t *p_ul_buf, uint32_t ul_size);
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
}
#endif
/**INDENT-ON**/
/// @endcond
#endif /* EFC_H_INCLUDED */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,80 @@
/**
* \file
*
* \brief General Purpose Backup Registers (GPBR) driver for SAM.
*
* Copyright (c) 2011-2012 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#ifndef GPBR_H_INCLUDED
#define GPBR_H_INCLUDED
#include "../chip.h"
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
extern "C" {
#endif
/**INDENT-ON**/
/// @endcond
/** GPBR register number type */
typedef enum gpbr_num_type {
GPBR0 = 0,
GPBR1,
GPBR2,
GPBR3,
GPBR4,
GPBR5,
GPBR6,
GPBR7
} gpbr_num_t;
uint32_t gpbr_read(gpbr_num_t ul_reg_num);
void gpbr_write(gpbr_num_t ul_reg_num, uint32_t ul_value);
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
}
#endif
/**INDENT-ON**/
/// @endcond
#endif /* GPBR_H_INCLUDED */

View File

@ -0,0 +1,210 @@
/**
* \file
*
* \brief Synchronous Serial Controller (SSC) driver for SAM.
*
* Copyright (c) 2011-2012 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#ifndef SSC_H_INCLUDED
#define SSC_H_INCLUDED
#include "../chip.h"
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
extern "C" {
#endif
/**INDENT-ON**/
/// @endcond
//! Receive stop selection.
#define SSC_RX_STOP_COMPARE_0 0
#define SSC_RX_STOP_COMPARE_0_1 1
//! Compare register ID.
#define COMPARE_ID0 0
#define COMPARE_ID1 1
//! SSC module default timeout. */
#define SSC_DEFAULT_TIMEOUT 10000
//! \brief SSC driver return codes.
enum ssc_return_code {
SSC_RC_OK = 0, //!< OK
SSC_RC_YES = 0, //!< Yes
SSC_RC_NO = 1, //!< No
SSC_RC_ERROR = 1, //!< General error
SSC_RC_INVALID = 0xFFFFFFFF //!< Parameter invalid
};
//! Data frame structure.
typedef struct {
//! Data bits length per transfer, should be 0 to 31.
uint32_t ul_datlen;
//! Bit sequence LSBF or MSBF.
//! For receiver configuration, SSC_RFMR_MSBF or 0.
//! For transmitter configuration, SSC_TFMR_MSBF or 0.
uint32_t ul_msbf;
//! Data number per frame, should be 0 to 15.
uint32_t ul_datnb;
//! Frame Sync. length should be 0 to 15.
uint32_t ul_fslen;
//! Frame Sync. length extension field, should be 0 to 15.
uint32_t ul_fslen_ext;
//! Frame Sync. output selection.
//! For receiver configuration, one of SSC_RFMR_FSOS_NONE, SSC_RFMR_FSOS_NEGATIVE, SSC_RFMR_FSOS_POSITIVE,
//! SSC_RFMR_FSOS_LOW, SSC_RFMR_FSOS_HIGH or SSC_RFMR_FSOS_TOGGLING.
//! For transmitter configuration, one of SSC_TFMR_FSOS_NONE, SSC_TFMR_FSOS_NEGATIVE, SSC_TFMR_FSOS_POSITIVE
//! SSC_TFMR_FSOS_LOW, SSC_TFMR_FSOS_HIGH, SSC_TFMR_FSOS_TOGGLING,
uint32_t ul_fsos;
//! Frame Sync. edge detection.
//! For receiver configuration, SSC_RFMR_FSEDGE_POSITIVE or SSC_RFMR_FSEDGE_NEGATIVE.
//! For transmitter configuration, SSC_TFMR_FSEDGE_POSITIVE or SSC_TFMR_FSEDGE_NEGATIVE.
uint32_t ul_fsedge;
} data_frame_opt_t;
//! Clock mode structure.
typedef struct {
//! Communication clock selection.
//! For receiver configuration, one of SSC_RCMR_CKS_MCK, SSC_RCMR_CKS_TK or SSC_RCMR_CKS_RK.
//! For transmitter configuration, one of SSC_TCMR_CKS_MCK, SSC_TCMR_CKS_TK or SSC_TCMR_CKS_RK.
uint32_t ul_cks;
//! Communication clock output mode selection.
//! For receiver configuration, one of SSC_RCMR_CKO_NONE, SSC_RCMR_CKO_CONTINUOUS or SSC_RCMR_CKO_TRANSFER.
//! For transmitter configuration, one of SSC_TCMR_CKO_NONE, SSC_TCMR_CKO_CONTINUOUS or SSC_TCMR_CKO_TRANSFER.
uint32_t ul_cko;
//! Communication clock inversion.
//! For receiver configuration, SSC_RCMR_CKI or 0.
//! For transmitter configuration, SSC_TCMR_CKI or 0.
uint32_t ul_cki;
//! Communication clock gating selection.
//! For receiver configuration, one of SSC_RCMR_CKG_NONE, SSC_RCMR_CKG_CONTINUOUS and SSC_RCMR_CKG_TRANSFER.
//! For transmitter configuration, one of SSC_TCMR_CKG_NONE, SSC_TCMR_CKG_CONTINUOUS and SSC_TCMR_CKG_TRANSFER.
uint32_t ul_ckg;
//! Period divider selection, should be 0 to 255.
uint32_t ul_period;
//! Communication start delay, should be 0 to 255.
uint32_t ul_sttdly;
//! Communication start selection.
//! For receiver configuration, one of SSC_RCMR_START_CONTINUOUS, SSC_RCMR_START_TRANSMIT, SSC_RCMR_START_RF_LOW,
//! SSC_RCMR_START_RF_HIGH, SSC_RCMR_START_RF_FALLING, SSC_RCMR_START_RF_RISING, SSC_RCMR_START_RF_LEVEL,
//! SSC_RCMR_START_RF_EDGE or SSC_RCMR_START_CMP_0.
//! For transmitter configuration, one of SSC_TCMR_START_CONTINUOUS, SSC_TCMR_START_TRANSMIT, SSC_TCMR_START_RF_LOW,
//! SSC_TCMR_START_RF_HIGH, SSC_TCMR_START_RF_FALLING, SSC_TCMR_START_RF_RISING, SSC_TCMR_START_RF_LEVEL,
//! SSC_TCMR_START_RF_EDGE or SSC_TCMR_START_CMP_0.
uint32_t ul_start_sel;
} clock_opt_t;
//! SSC working role in I2S mode.
#define SSC_I2S_MASTER_OUT (1 << 0) //! Working mode for transmitter as master.
#define SSC_I2S_MASTER_IN (1 << 1) //! Working mode for receiver as master.
#define SSC_I2S_SLAVE_OUT (1 << 2) //! Working mode for transmitter as slave.
#define SSC_I2S_SLAVE_IN (1 << 3) //! Working mode for receiver as slave.
//! Bit for SSC Audio channel left.
#define SSC_AUDIO_CH_LEFT (1 << 0)
//! Bit for SSC Audio channel right.
#define SSC_AUDIO_CH_RIGHT (1 << 1)
//! SSC Audio Channel modes.
enum {
//! Mono, left channel enabled.
SSC_AUDIO_MONO_LEFT = (SSC_AUDIO_CH_LEFT),
//! Mono, right channel enabled.
SSC_AUDIO_MONO_RIGHT = (SSC_AUDIO_CH_RIGHT),
//! Stereo, two channels.
SSC_AUDIO_STERO = (SSC_AUDIO_CH_LEFT | SSC_AUDIO_CH_RIGHT)
};
uint32_t ssc_set_clock_divider(Ssc *p_ssc, uint32_t ul_bitclock, uint32_t ul_mck);
void ssc_i2s_set_transmitter(Ssc *p_ssc, uint32_t ul_mode,
uint32_t ul_cks, uint32_t ul_ch_mode, uint32_t ul_datlen);
void ssc_i2s_set_receiver(Ssc *p_ssc, uint32_t ul_mode,
uint32_t ul_cks, uint32_t ul_ch_mode, uint32_t ul_datlen);
void ssc_reset(Ssc *p_ssc);
void ssc_enable_rx(Ssc *p_ssc);
void ssc_disable_rx(Ssc *p_ssc);
void ssc_enable_tx(Ssc *p_ssc);
void ssc_disable_tx(Ssc *p_ssc);
void ssc_set_normal_mode(Ssc *p_ssc);
void ssc_set_loop_mode(Ssc *p_ssc);
void ssc_set_rx_stop_selection(Ssc *p_ssc, uint32_t ul_sel);
void ssc_set_td_default_level(Ssc *p_ssc, uint32_t ul_level);
void ssc_enable_tx_frame_sync_data(Ssc *p_ssc);
void ssc_disable_tx_frame_sync_data(Ssc *p_ssc);
void ssc_set_receiver(Ssc *p_ssc, clock_opt_t *p_rx_clk_opt, data_frame_opt_t *p_rx_data_frame);
void ssc_set_transmitter(Ssc *p_ssc, clock_opt_t *p_tx_clk_opt, data_frame_opt_t *p_tx_data_frame);
void ssc_set_rx_compare(Ssc *p_ssc, uint32_t ul_id, uint32_t ul_value);
uint32_t ssc_get_rx_compare(Ssc *p_ssc, uint32_t ul_id);
void ssc_enable_interrupt(Ssc *p_ssc, uint32_t ul_sources);
void ssc_disable_interrupt(Ssc *p_ssc, uint32_t ul_sources);
uint32_t ssc_get_interrupt_mask(Ssc *p_ssc);
uint32_t ssc_get_status(Ssc *p_ssc);
uint32_t ssc_is_tx_ready(Ssc *p_ssc);
uint32_t ssc_is_tx_empty(Ssc *p_ssc);
uint32_t ssc_is_rx_ready(Ssc *p_ssc);
uint32_t ssc_is_tx_enabled(Ssc *p_ssc);
uint32_t ssc_is_rx_enabled(Ssc *p_ssc);
#if (defined _SAM3S_) || (defined _SAM4S_)
uint32_t ssc_is_rx_buf_end(Ssc *p_ssc);
uint32_t ssc_is_tx_buf_end(Ssc *p_ssc);
uint32_t ssc_is_rx_buf_full(Ssc *p_ssc);
uint32_t ssc_is_tx_buf_empty(Ssc *p_ssc);
Pdc *ssc_get_pdc_base(Ssc *p_ssc);
#endif
uint32_t ssc_write(Ssc *p_ssc, uint32_t ul_frame);
uint32_t ssc_read(Ssc *p_ssc, uint32_t *ul_data);
void ssc_write_sync_data(Ssc *p_ssc, uint32_t ul_frame);
uint32_t ssc_read_sync_data(Ssc *p_ssc);
#if ((defined _SAM3XA_) || (defined _SAM3U_))
void *ssc_get_tx_access(Ssc *p_ssc);
void *ssc_get_rx_access(Ssc *p_ssc);
#endif
void ssc_set_writeprotect(Ssc *p_ssc, uint32_t ul_enable);
uint32_t ssc_get_writeprotect_status(Ssc *p_ssc);
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
}
#endif
/**INDENT-ON**/
/// @endcond
#endif /* SSC_H_INCLUDED */

View File

@ -0,0 +1,73 @@
/**
* \file
*
* \brief API for SAM TRNG.
*
* Copyright (c) 2011-2012 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#ifndef TRNG_H_INCLUDED
#define TRNG_H_INCLUDED
#include "../chip.h"
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
extern "C" {
#endif
/**INDENT-ON**/
/// @endcond
void trng_enable(Trng *p_trng);
void trng_disable(Trng *p_trng);
void trng_enable_interrupt(Trng *p_trng);
void trng_disable_interrupt(Trng *p_trng);
uint32_t trng_get_interrupt_mask(Trng *p_trng);
uint32_t trng_get_interrupt_status(Trng *p_trng);
uint32_t trng_read_output_data(Trng *p_trng);
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
}
#endif
/**INDENT-ON**/
/// @endcond
#endif /* TRNG_H_INCLUDED */

View File

@ -386,7 +386,7 @@ Pdc *adc12b_get_pdc_base(const Adc12b *p_adc)
{
return PDC_ADC12B;
}
#endif
#endif // SAM3U_SERIES
//@}

View File

@ -0,0 +1,776 @@
/**
* \file
*
* \brief Controller Area Network (CAN) driver module for SAM.
*
* Copyright (c) 2011 - 2012 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#include "../chip.h"
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
extern "C" {
#endif
/**INDENT-ON**/
/// @endcond
#if SAM3XA_SERIES
/** Define the timemark mask. */
#define TIMEMARK_MASK 0x0000ffff
/* CAN timeout for synchronization. */
#define CAN_TIMEOUT 100000
/** The max value for CAN baudrate prescale. */
#define CAN_BAUDRATE_MAX_DIV 128
/** Define the scope for TQ. */
#define CAN_MIN_TQ_NUM 8
#define CAN_MAX_TQ_NUM 25
/** Define the fixed bit time value. */
#define CAN_BIT_SYNC 1
#define CAN_BIT_IPT 2
typedef struct {
uint8_t uc_tq; //! CAN_BIT_SYNC + uc_prog + uc_phase1 + uc_phase2 = uc_tq, 8 <= uc_tq <= 25.
uint8_t uc_prog; //! Propagation segment, (3-bits + 1), 1~8;
uint8_t uc_phase1; //! Phase segment 1, (3-bits + 1), 1~8;
uint8_t uc_phase2; //! Phase segment 2, (3-bits + 1), 1~8, CAN_BIT_IPT <= uc_phase2;
uint8_t uc_sjw; //! Resynchronization jump width, (2-bits + 1), min(uc_phase1, 4);
uint8_t uc_sp; //! Sample point value, 0~100 in percent.
} can_bit_timing_t;
/** Values of bit time register for different baudrates, Sample point = ((1 + uc_prog + uc_phase1) / uc_tq) * 100%. */
const can_bit_timing_t can_bit_time[] = {
{8, (2 + 1), (1 + 1), (1 + 1), (2 + 1), 75},
{9, (1 + 1), (2 + 1), (2 + 1), (1 + 1), 67},
{10, (2 + 1), (2 + 1), (2 + 1), (2 + 1), 70},
{11, (3 + 1), (2 + 1), (2 + 1), (3 + 1), 72},
{12, (2 + 1), (3 + 1), (3 + 1), (3 + 1), 67},
{13, (3 + 1), (3 + 1), (3 + 1), (3 + 1), 77},
{14, (3 + 1), (3 + 1), (4 + 1), (3 + 1), 64},
{15, (3 + 1), (4 + 1), (4 + 1), (3 + 1), 67},
{16, (4 + 1), (4 + 1), (4 + 1), (3 + 1), 69},
{17, (5 + 1), (4 + 1), (4 + 1), (3 + 1), 71},
{18, (4 + 1), (5 + 1), (5 + 1), (3 + 1), 67},
{19, (5 + 1), (5 + 1), (5 + 1), (3 + 1), 68},
{20, (6 + 1), (5 + 1), (5 + 1), (3 + 1), 70},
{21, (7 + 1), (5 + 1), (5 + 1), (3 + 1), 71},
{22, (6 + 1), (6 + 1), (6 + 1), (3 + 1), 68},
{23, (7 + 1), (7 + 1), (6 + 1), (3 + 1), 70},
{24, (6 + 1), (7 + 1), (7 + 1), (3 + 1), 67},
{25, (7 + 1), (7 + 1), (7 + 1), (3 + 1), 68}
};
/**
* \brief Configure CAN baudrate.
*
* \param p_can Pointer to a CAN peripheral instance.
* \param ul_mck The input main clock for the CAN module.
* \param ul_baudrate Baudrate value (kB/s), allowed values:
* 1000, 800, 500, 250, 125, 50, 25, 10, 5.
*
* \retval Set the baudrate successfully or not.
*/
static uint32_t can_set_baudrate(Can *p_can, uint32_t ul_mck, uint32_t ul_baudrate)
{
uint8_t uc_tq;
uint8_t uc_prescale;
uint32_t ul_mod;
uint32_t ul_cur_mod;
can_bit_timing_t *p_bit_time;
/* Check whether the baudrate prescale will be greater than the max divide value. */
if (((ul_mck + (ul_baudrate * CAN_MAX_TQ_NUM * 1000 - 1)) /
(ul_baudrate * CAN_MAX_TQ_NUM * 1000)) > CAN_BAUDRATE_MAX_DIV) {
return 0;
}
/* Check whether the input MCK is too small. */
if (ul_mck < ul_baudrate * CAN_MIN_TQ_NUM * 1000) {
return 0;
}
/* Initialize it as the minimum Time Quantum. */
uc_tq = CAN_MIN_TQ_NUM;
/* Initialize the remainder as the max value. When the remainder is 0, get the right TQ number. */
ul_mod = 0xffffffff;
/* Find out the approximate Time Quantum according to the baudrate. */
for (uint8_t i = CAN_MIN_TQ_NUM; i <= CAN_MAX_TQ_NUM; i++) {
if ((ul_mck / (ul_baudrate * i * 1000)) <= CAN_BAUDRATE_MAX_DIV) {
ul_cur_mod = ul_mck % (ul_baudrate * i * 1000);
if (ul_cur_mod < ul_mod){
ul_mod = ul_cur_mod;
uc_tq = i;
if (!ul_mod) {
break;
}
}
}
}
/* Calculate the baudrate prescale value. */
uc_prescale = ul_mck / (ul_baudrate * uc_tq * 1000);
/* Get the right CAN BIT Timing group. */
p_bit_time = (can_bit_timing_t *)&can_bit_time[uc_tq - CAN_MIN_TQ_NUM];
/* Before modifying the CANBR register, disable the CAN controller. */
can_disable(p_can);
/* Write into the CAN baudrate register. */
p_can->CAN_BR = CAN_BR_PHASE2(p_bit_time->uc_phase2 - 1) |
CAN_BR_PHASE1(p_bit_time->uc_phase1 - 1) |
CAN_BR_PROPAG(p_bit_time->uc_prog - 1) |
CAN_BR_SJW(p_bit_time->uc_sjw - 1) |
CAN_BR_BRP(uc_prescale - 1);
return 1;
}
/**
* \brief Initialize CAN controller.
*
* \param p_can Pointer to a CAN peripheral instance.
* \param ul_mck CAN module input clock.
* \param ul_baudrate CAN communication baudrate in kbs.
*
* \retval 0 If failed to initialize the CAN module; otherwise successful.
*
* \note PMC clock for CAN peripheral should be enabled before calling this function.
*/
uint32_t can_init(Can *p_can, uint32_t ul_mck, uint32_t ul_baudrate)
{
uint32_t ul_flag;
uint32_t ul_tick;
/* Initialize the baudrate for CAN module. */
ul_flag = can_set_baudrate(p_can, ul_mck, ul_baudrate);
if (ul_flag == 0) {
return 0;
}
/* Reset the CAN eight message mailbox. */
can_reset_all_mailbox(p_can);
/* Enable the CAN controller. */
can_enable(p_can);
/* Wait until the CAN is synchronized with the bus activity. */
ul_flag = 0;
ul_tick = 0;
while (!(ul_flag & CAN_SR_WAKEUP) && (ul_tick < CAN_TIMEOUT)) {
ul_flag = can_get_status(p_can);
ul_tick++;
}
/* Timeout or the CAN module has been synchronized with the bus. */
if (CAN_TIMEOUT == ul_tick) {
return 0;
} else {
return 1;
}
}
/**
* \brief Enable CAN Controller.
*
* \param p_can Pointer to a CAN peripheral instance.
*/
void can_enable(Can *p_can)
{
p_can->CAN_MR |= CAN_MR_CANEN;
}
/**
* \brief Disable CAN Controller.
*
* \param p_can Pointer to a CAN peripheral instance.
*/
void can_disable(Can *p_can)
{
p_can->CAN_MR &= ~CAN_MR_CANEN;
}
/**
* \brief Disable CAN Controller low power mode.
*
* \param p_can Pointer to a CAN peripheral instance.
*/
void can_disable_low_power_mode(Can *p_can)
{
p_can->CAN_MR &= ~CAN_MR_LPM;
}
/**
* \brief Enable CAN Controller low power mode.
*
* \param p_can Pointer to a CAN peripheral instance.
*/
void can_enable_low_power_mode(Can *p_can)
{
p_can->CAN_MR |= CAN_MR_LPM;
}
/**
* \brief Disable CAN Controller autobaud/listen mode.
*
* \param p_can Pointer to a CAN peripheral instance.
*/
void can_disable_autobaud_listen_mode(Can *p_can)
{
p_can->CAN_MR &= ~CAN_MR_ABM;
}
/**
* \brief Enable CAN Controller autobaud/listen mode.
*
* \param p_can Pointer to a CAN peripheral instance.
*/
void can_enable_autobaud_listen_mode(Can *p_can)
{
p_can->CAN_MR |= CAN_MR_ABM;
}
/**
* \brief CAN Controller won't generate overload frame.
*
* \param p_can Pointer to a CAN peripheral instance.
*/
void can_disable_overload_frame(Can *p_can)
{
p_can->CAN_MR &= ~CAN_MR_OVL;
}
/**
* \brief CAN Controller will generate an overload frame after each successful
* reception for mailboxes configured in Receive mode, Producer and Consumer.
*
* \param p_can Pointer to a CAN peripheral instance.
*/
void can_enable_overload_frame(Can *p_can)
{
p_can->CAN_MR |= CAN_MR_OVL;
}
/**
* \brief Configure the timestamp capture point, at the start or the end of frame.
*
* \param p_can Pointer to a CAN peripheral instance.
* \param ul_flag 0: Timestamp is captured at each start of frame;
* 1: Timestamp is captured at each end of frame.
*/
void can_set_timestamp_capture_point(Can *p_can, uint32_t ul_flag)
{
if (ul_flag) {
p_can->CAN_MR |= CAN_MR_TEOF;
} else {
p_can->CAN_MR &= ~CAN_MR_TEOF;
}
}
/**
* \brief Disable CAN Controller time triggered mode.
*
* \param p_can Pointer to a CAN peripheral instance.
*/
void can_disable_time_triggered_mode(Can *p_can)
{
p_can->CAN_MR &= ~CAN_MR_TTM;
}
/**
* \brief Enable CAN Controller time triggered mode.
*
* \param p_can Pointer to a CAN peripheral instance.
*/
void can_enable_time_triggered_mode(Can *p_can)
{
p_can->CAN_MR |= CAN_MR_TTM;
}
/**
* \brief Disable CAN Controller timer freeze.
*
* \param p_can Pointer to a CAN peripheral instance.
*/
void can_disable_timer_freeze(Can *p_can)
{
p_can->CAN_MR &= ~CAN_MR_TIMFRZ;
}
/**
* \brief Enable CAN Controller timer freeze.
*
* \param p_can Pointer to a CAN peripheral instance.
*/
void can_enable_timer_freeze(Can *p_can)
{
p_can->CAN_MR |= CAN_MR_TIMFRZ;
}
/**
* \brief Disable CAN Controller transmit repeat function.
*
* \param p_can Pointer to a CAN peripheral instance.
*/
void can_disable_tx_repeat(Can *p_can)
{
p_can->CAN_MR |= CAN_MR_DRPT;
}
/**
* \brief Enable CAN Controller transmit repeat function.
*
* \param p_can Pointer to a CAN peripheral instance.
*/
void can_enable_tx_repeat(Can *p_can)
{
p_can->CAN_MR &= ~CAN_MR_DRPT;
}
/**
* \brief Configure CAN Controller reception synchronization stage.
*
* \param p_can Pointer to a CAN peripheral instance.
* \param ul_stage The reception stage to be configured.
*
* \note This is just for debug purpose only.
*/
void can_set_rx_sync_stage(Can *p_can, uint32_t ul_stage)
{
p_can->CAN_MR = (p_can->CAN_MR & ~CAN_MR_RXSYNC_Msk) | ul_stage;
}
/**
* \brief Enable CAN interrupt.
*
* \param p_can Pointer to a CAN peripheral instance.
* \param dw_mask Interrupt to be enabled.
*/
void can_enable_interrupt(Can *p_can, uint32_t dw_mask)
{
p_can->CAN_IER = dw_mask;
}
/**
* \brief Disable CAN interrupt.
*
* \param p_can Pointer to a CAN peripheral instance.
* \param dw_mask Interrupt to be disabled.
*/
void can_disable_interrupt(Can *p_can, uint32_t dw_mask)
{
p_can->CAN_IDR = dw_mask;
}
/**
* \brief Get CAN Interrupt Mask.
*
* \param p_can Pointer to a CAN peripheral instance.
*
* \retval CAN interrupt mask.
*/
uint32_t can_get_interrupt_mask(Can *p_can)
{
return (p_can->CAN_IMR);
}
/**
* \brief Get CAN status.
*
* \param p_can Pointer to a CAN peripheral instance.
*
* \retval CAN status.
*/
uint32_t can_get_status(Can *p_can)
{
return (p_can->CAN_SR);
}
/**
* \brief Get the 16-bit free-running internal timer count.
*
* \param p_can Pointer to a CAN peripheral instance.
*
* \retval The internal CAN free-running timer counter.
*/
uint32_t can_get_internal_timer_value(Can *p_can)
{
return (p_can->CAN_TIM);
}
/**
* \brief Get CAN timestamp register value.
*
* \param p_can Pointer to a CAN peripheral instance.
*
* \retval The timestamp value.
*/
uint32_t can_get_timestamp_value(Can *p_can)
{
return (p_can->CAN_TIMESTP);
}
/**
* \brief Get CAN transmit error counter.
*
* \param p_can Pointer to a CAN peripheral instance.
*
* \retval Transmit error counter.
*/
uint8_t can_get_tx_error_cnt(Can *p_can)
{
return (uint8_t) (p_can->CAN_ECR >> CAN_ECR_TEC_Pos);
}
/**
* \brief Get CAN receive error counter.
*
* \param p_can Pointer to a CAN peripheral instance.
*
* \retval Receive error counter.
*/
uint8_t can_get_rx_error_cnt(Can *p_can)
{
return (uint8_t) (p_can->CAN_ECR >> CAN_ECR_REC_Pos);
}
/**
* \brief Reset the internal free-running 16-bit timer.
*
* \param p_can Pointer to a CAN peripheral instance.
*
* \note If the internal timer counter is frozen, this function automatically
* re-enables it.
*/
void can_reset_internal_timer(Can *p_can)
{
p_can->CAN_TCR |= CAN_TCR_TIMRST;
}
/**
* \brief Send global transfer request.
*
* \param p_can Pointer to a CAN peripheral instance.
* \param uc_mask Mask for mailboxes that are requested to transfer.
*/
void can_global_send_transfer_cmd(Can *p_can, uint8_t uc_mask)
{
uint32_t ul_reg;
ul_reg = p_can->CAN_TCR & ((uint32_t)~GLOBAL_MAILBOX_MASK);
p_can->CAN_TCR = ul_reg | uc_mask;
}
/**
* \brief Send global abort request.
*
* \param p_can Pointer to a CAN peripheral instance.
* \param uc_mask Mask for mailboxes that are requested to abort.
*/
void can_global_send_abort_cmd(Can *p_can, uint8_t uc_mask)
{
uint32_t ul_reg;
ul_reg = p_can->CAN_ACR & ((uint32_t)~GLOBAL_MAILBOX_MASK);
p_can->CAN_ACR = ul_reg | uc_mask;
}
/**
* \brief Configure the timemark for the mailbox.
*
* \param p_can Pointer to a CAN peripheral instance.
* \param uc_index Indicate which mailbox is to be configured.
* \param us_cnt The timemark to be set.
*
* \note The timemark is active in Time Triggered mode only.
*/
void can_mailbox_set_timemark(Can *p_can, uint8_t uc_index, uint16_t us_cnt)
{
uint32_t ul_reg;
ul_reg = p_can->CAN_MB[uc_index].CAN_MMR & ((uint32_t)~TIMEMARK_MASK);
p_can->CAN_MB[uc_index].CAN_MMR = ul_reg | us_cnt;
}
/**
* \brief Get status of the mailbox.
*
* \param p_can Pointer to a CAN peripheral instance.
* \param uc_index Indicate which mailbox is to be read.
*
* \retval The mailbox status.
*/
uint32_t can_mailbox_get_status(Can *p_can, uint8_t uc_index)
{
return (p_can->CAN_MB[uc_index].CAN_MSR);
}
/**
* \brief Send single mailbox transfer request.
*
* \param p_can Pointer to a CAN peripheral instance.
* \param uc_index Indicate which mailbox is to be configured.
*/
void can_mailbox_send_transfer_cmd(Can *p_can, uint8_t uc_index)
{
p_can->CAN_MB[uc_index].CAN_MCR |= CAN_MCR_MTCR;
}
/**
* \brief Send single mailbox abort request.
*
* \param p_can Pointer to a CAN peripheral instance.
* \param uc_index Indicate which mailbox is to be configured.
*/
void can_mailbox_send_abort_cmd(Can *p_can, uint8_t uc_index)
{
p_can->CAN_MB[uc_index].CAN_MCR |= CAN_MCR_MACR;
}
/**
* \brief Initialize the mailbox in different mode and set up related configuration.
*
* \param p_can Pointer to a CAN peripheral instance.
* \param p_mailbox Pointer to a CAN mailbox instance.
*/
void can_mailbox_init(Can *p_can, can_mb_conf_t *p_mailbox)
{
uint8_t uc_index;
uc_index = (uint8_t)p_mailbox->ul_mb_idx;
/* Check the object type of the mailbox. If it's used to disable the mailbox, reset the whole mailbox. */
if (!p_mailbox->uc_obj_type) {
p_can->CAN_MB[uc_index].CAN_MMR = 0;
p_can->CAN_MB[uc_index].CAN_MAM = 0;
p_can->CAN_MB[uc_index].CAN_MID = 0;
p_can->CAN_MB[uc_index].CAN_MDL = 0;
p_can->CAN_MB[uc_index].CAN_MDH = 0;
p_can->CAN_MB[uc_index].CAN_MCR = 0;
return;
}
/* Set the priority in Transmit mode. */
p_can->CAN_MB[uc_index].CAN_MMR = (p_can->CAN_MB[uc_index].CAN_MMR &
~CAN_MMR_PRIOR_Msk) | (p_mailbox-> uc_tx_prio << CAN_MMR_PRIOR_Pos);
/* Set the message ID and message acceptance mask for the mailbox in other modes. */
if (p_mailbox->uc_id_ver) {
p_can->CAN_MB[uc_index].CAN_MAM = p_mailbox->ul_id_msk | CAN_MAM_MIDE;
p_can->CAN_MB[uc_index].CAN_MID = p_mailbox->ul_id | CAN_MAM_MIDE;
} else {
p_can->CAN_MB[uc_index].CAN_MAM = p_mailbox->ul_id_msk;
p_can->CAN_MB[uc_index].CAN_MID = p_mailbox->ul_id;
}
/* Set up mailbox in one of the five different modes. */
p_can->CAN_MB[uc_index].CAN_MMR = (p_can->CAN_MB[uc_index].CAN_MMR &
~CAN_MMR_MOT_Msk) | (p_mailbox-> uc_obj_type << CAN_MMR_MOT_Pos);
}
/**
* \brief Read receive information for the mailbox.
*
* \param p_can Pointer to a CAN peripheral instance.
* \param p_mailbox Pointer to a CAN mailbox instance.
*
* \retval Different CAN mailbox transfer status.
*
* \note Read the mailbox status before calling this function.
*/
uint32_t can_mailbox_read(Can *p_can, can_mb_conf_t *p_mailbox)
{
uint32_t ul_status;
uint8_t uc_index;
uint32_t ul_retval;
ul_retval = 0;
uc_index = (uint8_t)p_mailbox->ul_mb_idx;
ul_status = p_mailbox->ul_status;
/* Check whether there is overwriting happening in Receive with Overwrite mode,
or there're messages lost in Receive mode. */
if ((ul_status & CAN_MSR_MRDY) && (ul_status & CAN_MSR_MMI)) {
ul_retval = CAN_MAILBOX_RX_OVER;
}
/* Read the message family ID. */
p_mailbox->ul_fid = p_can->CAN_MB[uc_index].CAN_MFID & CAN_MFID_MFID_Msk;
/* Read received data length. */
p_mailbox->uc_length = (ul_status & CAN_MSR_MDLC_Msk) >> CAN_MSR_MDLC_Pos;
/* Read received data. */
p_mailbox->ul_datal = p_can->CAN_MB[uc_index].CAN_MDL;
if (p_mailbox->uc_length > 4) {
p_mailbox->ul_datah = p_can->CAN_MB[uc_index].CAN_MDH;
}
/* Read the mailbox status again to check whether the software needs to re-read mailbox data register. */
p_mailbox->ul_status = p_can->CAN_MB[uc_index].CAN_MSR;
ul_status = p_mailbox->ul_status;
if (ul_status & CAN_MSR_MMI) {
ul_retval |= CAN_MAILBOX_RX_NEED_RD_AGAIN;
} else {
ul_retval |= CAN_MAILBOX_TRANSFER_OK;
}
/* Enable next receive process. */
can_mailbox_send_transfer_cmd(p_can, uc_index);
return ul_retval;
}
/**
* \brief Prepare transmit information and write them into the mailbox.
*
* \param p_can Pointer to a CAN peripheral instance.
* \param p_mailbox Pointer to a CAN mailbox instance.
*
* \retval CAN_MAILBOX_NOT_READY: Failed because mailbox isn't ready.
* CAN_MAILBOX_TRANSFER_OK: Successfully write message into mailbox.
*
* \note After calling this function, the mailbox message won't be sent out until
* can_mailbox_send_transfer_cmd() is called.
*/
uint32_t can_mailbox_write(Can *p_can, can_mb_conf_t *p_mailbox)
{
uint32_t ul_status;
uint8_t uc_index;
uc_index = (uint8_t)p_mailbox->ul_mb_idx;
/* Read the mailbox status firstly to check whether the mailbox is ready or not. */
p_mailbox->ul_status = can_mailbox_get_status(p_can, uc_index);
ul_status = p_mailbox->ul_status;
if (!(ul_status & CAN_MSR_MRDY)) {
return CAN_MAILBOX_NOT_READY;
}
/* Write transmit identifier. */
if (p_mailbox->uc_id_ver) {
p_can->CAN_MB[uc_index].CAN_MID = p_mailbox->ul_id | CAN_MAM_MIDE;
} else {
p_can->CAN_MB[uc_index].CAN_MID = p_mailbox->ul_id;
}
/* Write transmit data into mailbox data register. */
p_can->CAN_MB[uc_index].CAN_MDL = p_mailbox->ul_datal;
if (p_mailbox->uc_length > 4) {
p_can->CAN_MB[uc_index].CAN_MDH = p_mailbox->ul_datah;
}
/* Write transmit data length into mailbox control register. */
p_can->CAN_MB[uc_index].CAN_MCR = (p_can->CAN_MB[uc_index].CAN_MCR &
~CAN_MCR_MDLC_Msk) | CAN_MCR_MDLC(p_mailbox->uc_length);
return CAN_MAILBOX_TRANSFER_OK;
}
/**
* \brief Require to send out a remote frame.
*
* \param p_can Pointer to a CAN peripheral instance.
* \param p_mailbox Pointer to a CAN mailbox instance.
*
* \retval CAN_MAILBOX_NOT_READY: Failed because mailbox isn't ready for transmitting message.
* CAN_MAILBOX_TRANSFER_OK: Successfully send out a remote frame.
*/
uint32_t can_mailbox_tx_remote_frame(Can *p_can, can_mb_conf_t *p_mailbox)
{
uint32_t ul_status;
uint8_t uc_index;
uc_index = (uint8_t)p_mailbox->ul_mb_idx;
/* Read the mailbox status firstly to check whether the mailbox is ready or not. */
p_mailbox->ul_status = p_can->CAN_MB[uc_index].CAN_MSR;
ul_status = p_mailbox->ul_status;
if (!(ul_status & CAN_MSR_MRDY)) {
return CAN_MAILBOX_NOT_READY;
}
/* Write transmit identifier. */
if (p_mailbox->uc_id_ver) {
p_can->CAN_MB[uc_index].CAN_MID = p_mailbox->ul_id | CAN_MAM_MIDE;
} else {
p_can->CAN_MB[uc_index].CAN_MID = p_mailbox->ul_id;
}
/* Set the RTR bit in the sent frame. */
p_can->CAN_MB[uc_index].CAN_MCR |= CAN_MCR_MRTR;
/* Set the MBx bit in the Transfer Command Register to send out the remote frame. */
can_global_send_transfer_cmd(p_can, (1 << uc_index));
return CAN_MAILBOX_TRANSFER_OK;
}
/**
* \brief Reset the eight mailboxes.
*
* \param p_can Pointer to a CAN peripheral instance.
*/
void can_reset_all_mailbox(Can *p_can)
{
can_mb_conf_t mb_config_t;
/* Set the mailbox object type parameter to disable the mailbox. */
mb_config_t.uc_obj_type = CAN_MB_DISABLE_MODE;
for (uint8_t i = 0; i < CANMB_NUMBER; i++) {
mb_config_t.ul_mb_idx = i;
can_mailbox_init(p_can, &mb_config_t);
}
}
#endif // SAM3XA_SERIES
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
}
#endif
/**INDENT-ON**/
/// @endcond

View File

@ -27,7 +27,7 @@
* ----------------------------------------------------------------------------
*/
#include "dacc.h"
#include "../chip.h"
/// @cond 0
/**INDENT-OFF**/
@ -37,6 +37,8 @@ extern "C" {
/**INDENT-ON**/
/// @endcond
#if (SAM3XA_SERIES) || (SAM3N_SERIES) || (SAM3S_SERIES)
/**
* \defgroup sam_drivers_dacc_group Digital-to-Analog Converter Controller (DACC)
*
@ -472,6 +474,9 @@ uint32_t dacc_get_analog_control(Dacc *p_dacc)
//@}
#endif // SAM3XA_SERIES
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus

View File

@ -0,0 +1,402 @@
/**
* \file
*
* \brief Enhanced Embedded Flash Controller (EEFC) driver for SAM.
*
* Copyright (c) 2011-2012 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#include "../chip.h"
#include <string.h>
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
extern "C" {
#endif
/**INDENT-ON**/
/// @endcond
/**
* \defgroup sam_drivers_efc_group Enhanced Embedded Flash Controller (EEFC)
*
* The Enhanced Embedded Flash Controller ensures the interface of the Flash block with
* the 32-bit internal bus.
*
* @{
*/
/* Address definition for read operation */
#if (SAM3XA_SERIES || SAM3U_SERIES /*|| SAM4SD16 || SAM4SD32*/)
# define READ_BUFF_ADDR0 IFLASH0_ADDR
# define READ_BUFF_ADDR1 IFLASH1_ADDR
#elif (SAM3S_SERIES || SAM3N_SERIES)
# define READ_BUFF_ADDR IFLASH_ADDR
#elif (SAM3U_SERIES || SAM4S_SERIES)
# define READ_BUFF_ADDR IFLASH0_ADDR
#else
# warning Only reading unique id for sam3 is implemented.
#endif
/* Flash Writing Protection Key */
#define FWP_KEY 0x5Au
#if SAM4S_SERIES
#define EEFC_FCR_FCMD(value) \
((EEFC_FCR_FCMD_Msk & ((value) << EEFC_FCR_FCMD_Pos)))
#define EEFC_ERROR_FLAGS (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE | EEFC_FSR_FLERR)
#else
#define EEFC_ERROR_FLAGS (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE)
#endif
/*
* Local function declaration.
* Because they are RAM functions, they need 'extern' declaration.
*/
extern void efc_write_fmr(Efc *p_efc, uint32_t ul_fmr);
extern uint32_t efc_perform_fcr(Efc *p_efc, uint32_t ul_fcr);
/**
* \brief Initialize the EFC controller.
*
* \param ul_access_mode 0 for 128-bit, EEFC_FMR_FAM for 64-bit.
* \param ul_fws The number of wait states in cycle (no shift).
*
* \return 0 if successful.
*/
uint32_t efc_init(Efc *p_efc, uint32_t ul_access_mode, uint32_t ul_fws)
{
efc_write_fmr(p_efc, ul_access_mode | EEFC_FMR_FWS(ul_fws));
return EFC_RC_OK;
}
/**
* \brief Enable the flash ready interrupt.
*
* \param p_efc Pointer to an EFC instance.
*/
void efc_enable_frdy_interrupt(Efc *p_efc)
{
uint32_t ul_fmr = p_efc->EEFC_FMR;
efc_write_fmr(p_efc, ul_fmr | EEFC_FMR_FRDY);
}
/**
* \brief Disable the flash ready interrupt.
*
* \param p_efc Pointer to an EFC instance.
*/
void efc_disable_frdy_interrupt(Efc *p_efc)
{
uint32_t ul_fmr = p_efc->EEFC_FMR;
efc_write_fmr(p_efc, ul_fmr & (~EEFC_FMR_FRDY));
}
/**
* \brief Set flash access mode.
*
* \param p_efc Pointer to an EFC instance.
* \param ul_mode 0 for 128-bit, EEFC_FMR_FAM for 64-bit.
*/
void efc_set_flash_access_mode(Efc *p_efc, uint32_t ul_mode)
{
uint32_t ul_fmr = p_efc->EEFC_FMR & (~EEFC_FMR_FAM);
efc_write_fmr(p_efc, ul_fmr | ul_mode);
}
/**
* \brief Get flash access mode.
*
* \param p_efc Pointer to an EFC instance.
*
* \return 0 for 128-bit or EEFC_FMR_FAM for 64-bit.
*/
uint32_t efc_get_flash_access_mode(Efc *p_efc)
{
return (p_efc->EEFC_FMR & EEFC_FMR_FAM);
}
/**
* \brief Set flash wait state.
*
* \param p_efc Pointer to an EFC instance.
* \param ul_fws The number of wait states in cycle (no shift).
*/
void efc_set_wait_state(Efc *p_efc, uint32_t ul_fws)
{
uint32_t ul_fmr = p_efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk);
efc_write_fmr(p_efc, ul_fmr | EEFC_FMR_FWS(ul_fws));
}
/**
* \brief Get flash wait state.
*
* \param p_efc Pointer to an EFC instance.
*
* \return The number of wait states in cycle (no shift).
*/
uint32_t efc_get_wait_state(Efc *p_efc)
{
return ((p_efc->EEFC_FMR & EEFC_FMR_FWS_Msk) >> EEFC_FMR_FWS_Pos);
}
/**
* \brief Perform the given command and wait until its completion (or an error).
*
* \note Unique ID commands are not supported, use efc_read_unique_id.
*
* \param p_efc Pointer to an EFC instance.
* \param ul_command Command to perform.
* \param ul_argument Optional command argument.
*
* \note This function will automatically choose to use IAP function.
*
* \return 0 if successful, otherwise returns an error code.
*/
uint32_t efc_perform_command(Efc *p_efc, uint32_t ul_command,
uint32_t ul_argument)
{
// Unique ID commands are not supported.
if (ul_command == EFC_FCMD_STUI || ul_command == EFC_FCMD_SPUI) {
return EFC_RC_NOT_SUPPORT;
}
#if (SAM3XA_SERIES || SAM3U4)
// Use IAP function with 2 parameters in ROM.
static uint32_t(*iap_perform_command) (uint32_t, uint32_t);
uint32_t ul_efc_nb = (p_efc == EFC0) ? 0 : 1;
iap_perform_command =
(uint32_t(*)(uint32_t, uint32_t))
*((uint32_t *) CHIP_FLASH_IAP_ADDRESS);
iap_perform_command(ul_efc_nb,
EEFC_FCR_FKEY(FWP_KEY) | EEFC_FCR_FARG(ul_argument) |
EEFC_FCR_FCMD(ul_command));
return (p_efc->EEFC_FSR & EEFC_ERROR_FLAGS);
#elif (SAM3N_SERIES || SAM3S_SERIES || SAM4S_SERIES || SAM3U_SERIES)
// Use IAP function with 2 parameter in ROM.
static uint32_t(*iap_perform_command) (uint32_t, uint32_t);
iap_perform_command =
(uint32_t(*)(uint32_t, uint32_t))
*((uint32_t *) CHIP_FLASH_IAP_ADDRESS);
#if SAM4S_SERIES
uint32_t ul_efc_nb = (p_efc == EFC0) ? 0 : 1;
iap_perform_command(ul_efc_nb,
EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FARG(ul_argument) |
EEFC_FCR_FCMD(ul_command));
#else
iap_perform_command(0,
EEFC_FCR_FKEY(FWP_KEY) | EEFC_FCR_FARG(ul_argument) |
EEFC_FCR_FCMD(ul_command));
#endif
return (p_efc->EEFC_FSR & EEFC_ERROR_FLAGS);
#else
// Use RAM Function.
return efc_perform_fcr(p_efc,
EEFC_FCR_FKEY(FWP_KEY) | EEFC_FCR_FARG(ul_argument) |
EEFC_FCR_FCMD(ul_command));
#endif
}
/**
* \brief Get the current status of the EEFC.
*
* \note This function clears the value of some status bits (FLOCKE, FCMDE).
*
* \param p_efc Pointer to an EFC instance.
*
* \return The current status.
*/
uint32_t efc_get_status(Efc *p_efc)
{
return p_efc->EEFC_FSR;
}
/**
* \brief Get the result of the last executed command.
*
* \param p_efc Pointer to an EFC instance.
*
* \return The result of the last executed command.
*/
uint32_t efc_get_result(Efc *p_efc)
{
return p_efc->EEFC_FRR;
}
/**
* \brief Perform read sequence. Supported sequences are read Unique ID and
* read User Signature
*
* \param p_efc Pointer to an EFC instance.
* \param ul_cmd_st Start command to perform.
* \param ul_cmd_sp Stop command to perform.
* \param p_ul_buf Pointer to an data buffer.
* \param ul_size Buffer size.
*
* \return 0 if successful, otherwise returns an error code.
*/
#ifdef __ICCARM__
__ramfunc
#else
__attribute__ ((section(".ramfunc")))
#endif
uint32_t efc_perform_read_sequence(Efc *p_efc,
uint32_t ul_cmd_st, uint32_t ul_cmd_sp,
uint32_t *p_ul_buf, uint32_t ul_size)
{
volatile uint32_t ul_status;
uint32_t ul_cnt;
#if (SAM3U4 || SAM3XA_SERIES /*|| SAM4SD16 || SAM4SD32*/)
uint32_t *p_ul_data =
(uint32_t *) ((p_efc == EFC0) ?
READ_BUFF_ADDR0 : READ_BUFF_ADDR1);
#elif (SAM3S_SERIES || SAM4S_SERIES || SAM3N_SERIES || SAM3U_SERIES)
uint32_t *p_ul_data = (uint32_t *) READ_BUFF_ADDR;
#else
return EFC_RC_NOT_SUPPORT;
#endif
if (p_ul_buf == NULL) {
return EFC_RC_INVALID;
}
p_efc->EEFC_FMR |= (0x1u << 16);
/* Send the Start Read command */
#if SAM4S_SERIES
p_efc->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FARG(0)
| EEFC_FCR_FCMD(ul_cmd_st);
#else
p_efc->EEFC_FCR = EEFC_FCR_FKEY(FWP_KEY) | EEFC_FCR_FARG(0)
| EEFC_FCR_FCMD(ul_cmd_st);
#endif
/* Wait for the FRDY bit in the Flash Programming Status Register
* (EEFC_FSR) falls.
*/
do {
ul_status = p_efc->EEFC_FSR;
} while ((ul_status & EEFC_FSR_FRDY) == EEFC_FSR_FRDY);
/* The data is located in the first address of the Flash
* memory mapping.
*/
for (ul_cnt = 0; ul_cnt < ul_size; ul_cnt++) {
p_ul_buf[ul_cnt] = p_ul_data[ul_cnt];
}
/* To stop the read mode */
p_efc->EEFC_FCR =
#if SAM4S_SERIES
EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FARG(0) |
EEFC_FCR_FCMD(ul_cmd_sp);
#else
EEFC_FCR_FKEY(FWP_KEY) | EEFC_FCR_FARG(0) |
EEFC_FCR_FCMD(ul_cmd_sp);
#endif
/* Wait for the FRDY bit in the Flash Programming Status Register (EEFC_FSR)
* rises.
*/
do {
ul_status = p_efc->EEFC_FSR;
} while ((ul_status & EEFC_FSR_FRDY) != EEFC_FSR_FRDY);
p_efc->EEFC_FMR &= ~(0x1u << 16);
return EFC_RC_OK;
}
/**
* \brief Set mode register.
*
* \param p_efc Pointer to an EFC instance.
* \param ul_fmr Value of mode register
*/
#ifdef __ICCARM__
__ramfunc
#else
__attribute__ ((section(".ramfunc")))
#endif
void efc_write_fmr(Efc *p_efc, uint32_t ul_fmr)
{
p_efc->EEFC_FMR = ul_fmr;
}
/**
* \brief Perform command.
*
* \param p_efc Pointer to an EFC instance.
* \param ul_fcr Flash command.
*
* \return The current status.
*/
#ifdef __ICCARM__
__ramfunc
#else
__attribute__ ((section(".ramfunc")))
#endif
uint32_t efc_perform_fcr(Efc *p_efc, uint32_t ul_fcr)
{
volatile uint32_t ul_status;
p_efc->EEFC_FCR = ul_fcr;
do {
ul_status = p_efc->EEFC_FSR;
} while ((ul_status & EEFC_FSR_FRDY) != EEFC_FSR_FRDY);
return (ul_status & EEFC_ERROR_FLAGS);
}
//@}
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
}
#endif
/**INDENT-ON**/
/// @endcond

View File

@ -0,0 +1,797 @@
/**
* \file
*
* \brief EMAC (Ethernet MAC) driver for SAM.
*
* Copyright (c) 2011-2012 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#include "../chip.h"
//#include <string.h>
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
extern "C" {
#endif
/**INDENT-ON**/
/// @endcond
#if SAM3XA_SERIES
/**
* \defgroup emac_group Ethernet Media Access Controller
*
* See \ref emac_quickstart.
*
* Driver for the EMAC (Ethernet Media Access Controller).
* This file contains basic functions for the EMAC, with support for all modes, settings
* and clock speeds.
*
* \section dependencies Dependencies
* This driver does not depend on other modules.
*
* @{
*/
/** TX descriptor lists */
#ifdef __ICCARM__ /* IAR */
#pragma data_alignment=8
#endif
static emac_tx_descriptor_t gs_tx_desc[EMAC_TX_BUFFERS];
/** TX callback lists */
static emac_dev_tx_cb_t gs_tx_callback[EMAC_TX_BUFFERS];
/** RX descriptors lists */
#ifdef __ICCARM__ /* IAR */
#pragma data_alignment=8
#endif
static emac_rx_descriptor_t gs_rx_desc[EMAC_RX_BUFFERS];
/** Send Buffer. Section 3.6 of AMBA 2.0 spec states that burst should not cross the
* 1K Boundaries. Receive buffer manager write operations are burst of 2 words => 3 lsb bits
* of the address shall be set to 0.
*/
#ifdef __ICCARM__ /* IAR */
#pragma data_alignment=8
#endif
static uint8_t gs_uc_tx_buffer[EMAC_TX_BUFFERS * EMAC_TX_UNITSIZE]
__attribute__ ((aligned(8)));
#ifdef __ICCARM__ /* IAR */
#pragma data_alignment=8
#endif
/** Receive Buffer */
static uint8_t gs_uc_rx_buffer[EMAC_RX_BUFFERS * EMAC_RX_UNITSIZE]
__attribute__ ((aligned(8)));
/**
* EMAC device memory management struct.
*/
typedef struct emac_dev_mem {
/* Pointer to allocated buffer for RX. The address should be 8-byte aligned
and the size should be EMAC_RX_UNITSIZE * wRxSize. */
uint8_t *p_rx_buffer;
/* Pointer to allocated RX descriptor list. */
emac_rx_descriptor_t *p_rx_dscr;
/* RX size, in number of registered units (RX descriptors). */
uint16_t us_rx_size;
/* Pointer to allocated buffer for TX. The address should be 8-byte aligned
and the size should be EMAC_TX_UNITSIZE * wTxSize. */
uint8_t *p_tx_buffer;
/* Pointer to allocated TX descriptor list. */
emac_tx_descriptor_t *p_tx_dscr;
/* TX size, in number of registered units (TX descriptors). */
uint16_t us_tx_size;
} emac_dev_mem_t;
/** Return count in buffer */
#define CIRC_CNT(head,tail,size) (((head) - (tail)) % (size))
/*
* Return space available, from 0 to size-1.
* Always leave one free char as a completely full buffer that has (head == tail),
* which is the same as empty.
*/
#define CIRC_SPACE(head,tail,size) CIRC_CNT((tail),((head)+1),(size))
/** Circular buffer is empty ? */
#define CIRC_EMPTY(head, tail) (head == tail)
/** Clear circular buffer */
#define CIRC_CLEAR(head, tail) (head = tail = 0)
/** Increment head or tail */
static void circ_inc(uint16_t *headortail, uint32_t size)
{
(*headortail)++;
if((*headortail) >= size) {
(*headortail) = 0;
}
}
/**
* \brief Wait PHY operation to be completed.
*
* \param p_emac HW controller address.
* \param ul_retry The retry times, 0 to wait forever until completeness.
*
* Return EMAC_OK if the operation is completed successfully.
*/
static uint8_t emac_wait_phy(Emac* p_emac, const uint32_t ul_retry)
{
volatile uint32_t ul_retry_count = 0;
while (!emac_is_phy_idle(p_emac)) {
if (ul_retry == 0) {
continue;
}
ul_retry_count++;
if (ul_retry_count >= ul_retry) {
return EMAC_TIMEOUT;
}
}
return EMAC_OK;
}
/**
* \brief Disable transfer, reset registers and descriptor lists.
*
* \param p_dev Pointer to EMAC driver instance.
*
*/
static void emac_reset_tx_mem(emac_device_t* p_dev)
{
Emac *p_hw = p_dev->p_hw;
uint8_t *p_tx_buff = p_dev->p_tx_buffer;
emac_tx_descriptor_t *p_td = p_dev->p_tx_dscr;
uint32_t ul_index;
uint32_t ul_address;
/* Disable TX */
emac_enable_transmit(p_hw, 0);
/* Set up the TX descriptors */
CIRC_CLEAR(p_dev->us_tx_head, p_dev->us_tx_tail);
for (ul_index = 0; ul_index < p_dev->us_tx_list_size; ul_index++) {
ul_address = (uint32_t) (&(p_tx_buff[ul_index * EMAC_TX_UNITSIZE]));
p_td[ul_index].addr = ul_address;
p_td[ul_index].status.val = EMAC_TXD_USED;
}
p_td[p_dev->us_tx_list_size - 1].status.val =
EMAC_TXD_USED | EMAC_TXD_WRAP;
/* Set transmit buffer queue */
emac_set_tx_queue(p_hw, (uint32_t) p_td);
}
/**
* \brief Disable receiver, reset registers and descriptor list.
*
* \param p_drv Pointer to EMAC Driver instance.
*/
static void emac_reset_rx_mem(emac_device_t* p_dev)
{
Emac *p_hw = p_dev->p_hw;
uint8_t *p_rx_buff = p_dev->p_rx_buffer;
emac_rx_descriptor_t *pRd = p_dev->p_rx_dscr;
uint32_t ul_index;
uint32_t ul_address;
/* Disable RX */
emac_enable_receive(p_hw, 0);
/* Set up the RX descriptors */
p_dev->us_rx_idx = 0;
for (ul_index = 0; ul_index < p_dev->us_rx_list_size; ul_index++) {
ul_address = (uint32_t) (&(p_rx_buff[ul_index * EMAC_RX_UNITSIZE]));
pRd[ul_index].addr.val = ul_address & EMAC_RXD_ADDR_MASK;
pRd[ul_index].status.val = 0;
}
pRd[p_dev->us_rx_list_size - 1].addr.val |= EMAC_RXD_WRAP;
/* Set receive buffer queue */
emac_set_rx_queue(p_hw, (uint32_t) pRd);
}
/**
* \brief Initialize the allocated buffer lists for EMAC driver to transfer data.
* Must be invoked after emac_dev_init() but before RX/TX starts.
*
* \note If input address is not 8-byte aligned, the address is automatically
* adjusted and the list size is reduced by one.
*
* \param p_emac Pointer to EMAC instance.
* \param p_emac_dev Pointer to EMAC device instance.
* \param p_dev_mm Pointer to the EMAC memory management control block.
* \param p_tx_cb Pointer to allocated TX callback list.
*
* \return EMAC_OK or EMAC_PARAM.
*/
static uint8_t emac_init_mem(Emac* p_emac, emac_device_t* p_emac_dev,
emac_dev_mem_t* p_dev_mm,
emac_dev_tx_cb_t* p_tx_cb)
{
if (p_dev_mm->us_rx_size <= 1 || p_dev_mm->us_tx_size <= 1 || p_tx_cb == NULL) {
return EMAC_PARAM;
}
/* Assign RX buffers */
if (((uint32_t) p_dev_mm->p_rx_buffer & 0x7)
|| ((uint32_t) p_dev_mm->p_rx_dscr & 0x7)) {
p_dev_mm->us_rx_size--;
}
p_emac_dev->p_rx_buffer =
(uint8_t *) ((uint32_t) p_dev_mm->p_rx_buffer & 0xFFFFFFF8);
p_emac_dev->p_rx_dscr =
(emac_rx_descriptor_t *) ((uint32_t) p_dev_mm->p_rx_dscr
& 0xFFFFFFF8);
p_emac_dev->us_rx_list_size = p_dev_mm->us_rx_size;
/* Assign TX buffers */
if (((uint32_t) p_dev_mm->p_tx_buffer & 0x7)
|| ((uint32_t) p_dev_mm->p_tx_dscr & 0x7)) {
p_dev_mm->us_tx_size--;
}
p_emac_dev->p_tx_buffer =
(uint8_t *) ((uint32_t) p_dev_mm->p_tx_buffer & 0xFFFFFFF8);
p_emac_dev->p_tx_dscr =
(emac_tx_descriptor_t *) ((uint32_t) p_dev_mm->p_tx_dscr
& 0xFFFFFFF8);
p_emac_dev->us_tx_list_size = p_dev_mm->us_tx_size;
p_emac_dev->func_tx_cb_list = p_tx_cb;
/* Reset TX & RX */
emac_reset_rx_mem(p_emac_dev);
emac_reset_tx_mem(p_emac_dev);
/* Enable Rx and Tx, plus the statistics register */
emac_enable_transmit(p_emac, true);
emac_enable_receive(p_emac, true);
emac_enable_statistics_write(p_emac, true);
/* Set up the interrupts for transmission and errors */
emac_enable_interrupt(p_emac,
EMAC_IER_RXUBR | /* Enable receive used bit read interrupt. */
EMAC_IER_TUND | /* Enable transmit underrun interrupt. */
EMAC_IER_RLE | /* Enable retry limit exceeded interrupt. */
EMAC_IER_TXERR | /* Enable transmit buffers exhausted in mid-frame interrupt. */
EMAC_IER_TCOMP | /* Enable transmit complete interrupt. */
EMAC_IER_ROVR | /* Enable receive overrun interrupt. */
EMAC_IER_HRESP | /* Enable Hresp not OK interrupt. */
EMAC_IER_PFR | /* Enable pause frame received interrupt. */
EMAC_IER_PTZ); /* Enable pause time zero interrupt. */
return EMAC_OK;
}
/**
* \brief Read the PHY register.
*
* \param p_emac Pointer to the EMAC instance.
* \param uc_phy_address PHY address.
* \param uc_address Register address.
* \param p_value Pointer to a 32-bit location to store read data.
*
* \Return EMAC_OK if successfully, EMAC_TIMEOUT if timeout.
*/
uint8_t emac_phy_read(Emac* p_emac, uint8_t uc_phy_address, uint8_t uc_address,
uint32_t* p_value)
{
emac_maintain_phy(p_emac, uc_phy_address, uc_address, 1, 0);
if (emac_wait_phy(p_emac, MAC_PHY_RETRY_MAX) == EMAC_TIMEOUT) {
return EMAC_TIMEOUT;
}
*p_value = emac_get_phy_data(p_emac);
return EMAC_OK;
}
/**
* \brief Write the PHY register.
*
* \param p_emac Pointer to the EMAC instance.
* \param uc_phy_address PHY Address.
* \param uc_address Register Address.
* \param ul_value Data to write, actually 16-bit data.
*
* \Return EMAC_OK if successfully, EMAC_TIMEOUT if timeout.
*/
uint8_t emac_phy_write(Emac* p_emac, uint8_t uc_phy_address,
uint8_t uc_address, uint32_t ul_value)
{
emac_maintain_phy(p_emac, uc_phy_address, uc_address, 0, ul_value);
if (emac_wait_phy(p_emac, MAC_PHY_RETRY_MAX) == EMAC_TIMEOUT) {
return EMAC_TIMEOUT;
}
return EMAC_OK;
}
/**
* \brief Initialize the EMAC driver.
*
* \param p_emac Pointer to the EMAC instance.
* \param p_emac_dev Pointer to the EMAC device instance.
* \param p_opt EMAC configure options.
*/
void emac_dev_init(Emac* p_emac, emac_device_t* p_emac_dev,
emac_options_t* p_opt)
{
emac_dev_mem_t emac_dev_mm;
/* Disable TX & RX and more */
emac_network_control(p_emac, 0);
emac_disable_interrupt(p_emac, ~0u);
emac_clear_statistics(p_emac);
/* Clear all status bits in the receive status register. */
emac_clear_rx_status(p_emac, EMAC_RSR_OVR | EMAC_RSR_REC | EMAC_RSR_BNA);
/* Clear all status bits in the transmit status register */
emac_clear_tx_status(p_emac, EMAC_TSR_UBR | EMAC_TSR_COL | EMAC_TSR_RLES
| EMAC_TSR_BEX | EMAC_TSR_COMP | EMAC_TSR_UND);
/* Clear interrupts */
emac_get_interrupt_status(p_emac);
/* Enable the copy of data into the buffers
ignore broadcasts, and not copy FCS. */
emac_set_configure(p_emac,
emac_get_configure(p_emac) | EMAC_NCFGR_DRFCS | EMAC_NCFGR_PAE);
emac_enable_copy_all(p_emac, p_opt->uc_copy_all_frame);
emac_disable_broadcast(p_emac, p_opt->uc_no_boardcast);
/* Fill in EMAC device memory management */
emac_dev_mm.p_rx_buffer = gs_uc_rx_buffer;
emac_dev_mm.p_rx_dscr = gs_rx_desc;
emac_dev_mm.us_rx_size = EMAC_RX_BUFFERS;
emac_dev_mm.p_tx_buffer = gs_uc_tx_buffer;
emac_dev_mm.p_tx_dscr = gs_tx_desc;
emac_dev_mm.us_tx_size = EMAC_TX_BUFFERS;
emac_init_mem(p_emac, p_emac_dev, &emac_dev_mm, gs_tx_callback);
emac_set_address(p_emac, 0, p_opt->uc_mac_addr);
}
/**
* \brief Frames can be read from the EMAC in multiple sections.
* Read ul_frame_size bytes from the EMAC receive buffers to pcTo.
* p_rcv_size is the size of the entire frame. Generally emac_read
* will be repeatedly called until the sum of all the ul_frame_size equals
* the value of p_rcv_size.
*
* \param p_emac_dev Pointer to the EMAC device instance.
* \param p_frame Address of the frame buffer.
* \param ul_frame_size Length of the frame.
* \param p_rcv_size Received frame size.
*
* \return EMAC_OK if receiving frame successfully, otherwise failed.
*/
uint32_t emac_dev_read(emac_device_t* p_emac_dev, uint8_t* p_frame,
uint32_t ul_frame_size, uint32_t* p_rcv_size)
{
uint16_t us_buffer_length;
uint32_t tmp_ul_frame_size = 0;
uint8_t *p_tmp_frame = 0;
uint16_t us_tmp_idx = p_emac_dev->us_rx_idx;
emac_rx_descriptor_t *p_rx_td =
&p_emac_dev->p_rx_dscr[p_emac_dev->us_rx_idx];
int8_t c_is_frame = 0;
if (p_frame == NULL)
return EMAC_PARAM;
/* Set the default return value */
*p_rcv_size = 0;
/* Process received RX descriptor */
while ((p_rx_td->addr.val & EMAC_RXD_OWNERSHIP) == EMAC_RXD_OWNERSHIP) {
/* A start of frame has been received, discard previous fragments */
if ((p_rx_td->status.val & EMAC_RXD_SOF) == EMAC_RXD_SOF) {
/* Skip previous fragment */
while (us_tmp_idx != p_emac_dev->us_rx_idx) {
p_rx_td = &p_emac_dev->p_rx_dscr[p_emac_dev->us_rx_idx];
p_rx_td->addr.val &= ~(EMAC_RXD_OWNERSHIP);
circ_inc(&p_emac_dev->us_rx_idx, p_emac_dev->us_rx_list_size);
}
/* Reset the temporary frame pointer */
p_tmp_frame = p_frame;
tmp_ul_frame_size = 0;
/* Start to gather buffers in a frame */
c_is_frame = 1;
}
/* Increment the pointer */
circ_inc(&us_tmp_idx, p_emac_dev->us_rx_list_size);
/* Copy data in the frame buffer */
if (c_is_frame) {
if (us_tmp_idx == p_emac_dev->us_rx_idx) {
do {
p_rx_td = &p_emac_dev->p_rx_dscr[p_emac_dev->us_rx_idx];
p_rx_td->addr.val &= ~(EMAC_RXD_OWNERSHIP);
circ_inc(&p_emac_dev->us_rx_idx, p_emac_dev->us_rx_list_size);
} while (us_tmp_idx != p_emac_dev->us_rx_idx);
return EMAC_RX_NULL;
}
/* Copy the buffer into the application frame */
us_buffer_length = EMAC_RX_UNITSIZE;
if ((tmp_ul_frame_size + us_buffer_length) > ul_frame_size) {
us_buffer_length = ul_frame_size - tmp_ul_frame_size;
}
memcpy(p_tmp_frame,
(void *)(p_rx_td->addr.val & EMAC_RXD_ADDR_MASK),
us_buffer_length);
p_tmp_frame += us_buffer_length;
tmp_ul_frame_size += us_buffer_length;
/* An end of frame has been received, return the data */
if ((p_rx_td->status.val & EMAC_RXD_EOF) == EMAC_RXD_EOF) {
/* Frame size from the EMAC */
*p_rcv_size = (p_rx_td->status.val & EMAC_RXD_LEN_MASK);
/* All data have been copied in the application frame buffer => release TD */
while (p_emac_dev->us_rx_idx != us_tmp_idx) {
p_rx_td = &p_emac_dev->p_rx_dscr[p_emac_dev->us_rx_idx];
p_rx_td->addr.val &= ~(EMAC_RXD_OWNERSHIP);
circ_inc(&p_emac_dev->us_rx_idx, p_emac_dev->us_rx_list_size);
}
/* Application frame buffer is too small so that all data have not been copied */
if (tmp_ul_frame_size < *p_rcv_size) {
return EMAC_SIZE_TOO_SMALL;
}
return EMAC_OK;
}
}
/* SOF has not been detected, skip the fragment */
else {
p_rx_td->addr.val &= ~(EMAC_RXD_OWNERSHIP);
p_emac_dev->us_rx_idx = us_tmp_idx;
}
/* Process the next buffer */
p_rx_td = &p_emac_dev->p_rx_dscr[us_tmp_idx];
}
return EMAC_RX_NULL;
}
/**
* \brief Send ulLength bytes from pcFrom. This copies the buffer to one of the
* EMAC Tx buffers, and then indicates to the EMAC that the buffer is ready.
* If lEndOfFrame is true then the data being copied is the end of the frame
* and the frame can be transmitted.
*
* \param p_emac_dev Pointer to the EMAC device instance.
* \param p_buffer Pointer to the data buffer.
* \param ul_size Length of the frame.
* \param func_tx_cb Transmit callback function.
*
* \return Length sent.
*/
uint32_t emac_dev_write(emac_device_t* p_emac_dev, void *p_buffer,
uint32_t ul_size, emac_dev_tx_cb_t func_tx_cb)
{
volatile emac_tx_descriptor_t *p_tx_td;
volatile emac_dev_tx_cb_t *p_func_tx_cb;
Emac *p_hw = p_emac_dev->p_hw;
/* Check parameter */
if (ul_size > EMAC_TX_UNITSIZE) {
return EMAC_PARAM;
}
/* Pointers to the current transmit descriptor */
p_tx_td = &p_emac_dev->p_tx_dscr[p_emac_dev->us_tx_head];
/* If no free TxTd, buffer can't be sent, schedule the wakeup callback */
if (CIRC_SPACE(p_emac_dev->us_tx_head, p_emac_dev->us_tx_tail,
p_emac_dev->us_tx_list_size) == 0) {
return EMAC_TX_BUSY;
}
/* Pointers to the current Tx callback */
p_func_tx_cb = &p_emac_dev->func_tx_cb_list[p_emac_dev->us_tx_head];
/* Set up/copy data to transmission buffer */
if (p_buffer && ul_size) {
/* Driver manages the ring buffer */
memcpy((void *)p_tx_td->addr, p_buffer, ul_size);
}
/* Tx callback */
*p_func_tx_cb = func_tx_cb;
/* Update transmit descriptor status */
/* The buffer size defined is the length of ethernet frame,
so it's always the last buffer of the frame. */
if (p_emac_dev->us_tx_head == p_emac_dev->us_tx_list_size - 1) {
p_tx_td->status.val =
(ul_size & EMAC_TXD_LEN_MASK) | EMAC_TXD_LAST
| EMAC_TXD_WRAP;
} else {
p_tx_td->status.val =
(ul_size & EMAC_TXD_LEN_MASK) | EMAC_TXD_LAST;
}
circ_inc(&p_emac_dev->us_tx_head, p_emac_dev->us_tx_list_size);
/* Now start to transmit if it is still not done */
emac_start_transmission(p_hw);
return EMAC_OK;
}
/**
* \brief Get current load of transmit.
*
* \param p_emac_dev Pointer to the EMAC device instance.
*
* \return Current load of transmit.
*/
uint32_t emac_dev_get_tx_load(emac_device_t* p_emac_dev)
{
uint16_t us_head = p_emac_dev->us_tx_head;
uint16_t us_tail = p_emac_dev->us_tx_tail;
return CIRC_CNT(us_head, us_tail, p_emac_dev->us_tx_list_size);
}
/**
* \brief Register/Clear RX callback. Callback will be invoked after the next received
* frame.
*
* When emac_dev_read() returns EMAC_RX_NULL, the application task calls
* emac_dev_set_rx_callback() to register func_rx_cb() callback and enters suspend state.
* The callback is in charge to resume the task once a new frame has been
* received. The next time emac_dev_read() is called, it will be successful.
*
* This function is usually invoked from the RX callback itself with NULL
* callback, to unregister. Once the callback has resumed the application task,
* there is no need to invoke the callback again.
*
* \param p_emac_dev Pointer to the EMAC device instance.
* \param func_tx_cb Receive callback function.
*/
void emac_dev_set_rx_callback(emac_device_t* p_emac_dev,
emac_dev_tx_cb_t func_rx_cb)
{
Emac *p_hw = p_emac_dev->p_hw;
if (func_rx_cb == NULL) {
emac_disable_interrupt(p_hw, EMAC_IDR_RCOMP);
p_emac_dev->func_rx_cb = NULL;
} else {
p_emac_dev->func_rx_cb = func_rx_cb;
emac_enable_interrupt(p_hw, EMAC_IER_RCOMP);
}
}
/**
* \brief Register/Clear TX wakeup callback.
*
* When emac_dev_write() returns EMAC_TX_BUSY (all transmit descriptor busy), the application
* task calls emac_dev_set_tx_wakeup_callback() to register func_wakeup() callback and
* enters suspend state. The callback is in charge to resume the task once
* several transmit descriptors have been released. The next time emac_dev_write() 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 p_emac_dev Pointer to EMAC device instance.
* \param func_wakeup Pointer to wakeup callback function.
* \param uc_threshold Number of free transmit descriptor before wakeup callback invoked.
*
* \return EMAC_OK, EMAC_PARAM on parameter error.
*/
uint8_t emac_dev_set_tx_wakeup_callback(emac_device_t* p_emac_dev,
emac_dev_wakeup_cb_t func_wakeup_cb, uint8_t uc_threshold)
{
if (func_wakeup_cb == NULL) {
p_emac_dev->func_wakeup_cb = NULL;
} else {
if (uc_threshold <= p_emac_dev->us_tx_list_size) {
p_emac_dev->func_wakeup_cb = func_wakeup_cb;
p_emac_dev->uc_wakeup_threshold = uc_threshold;
} else {
return EMAC_PARAM;
}
}
return EMAC_OK;
}
/**
* \brief Reset TX & RX queue & statistics.
*
* \param p_emac_dev Pointer to EMAC device instance.
*/
void emac_dev_reset(emac_device_t* p_emac_dev)
{
Emac *p_hw = p_emac_dev->p_hw;
emac_reset_rx_mem(p_emac_dev);
emac_reset_tx_mem(p_emac_dev);
emac_network_control(p_hw, EMAC_NCR_TE | EMAC_NCR_RE
| EMAC_NCR_WESTAT | EMAC_NCR_CLRSTAT);
}
/**
* \brief EMAC Interrupt handler.
*
* \param p_emac_dev Pointer to EMAC device instance.
*/
void emac_handler(emac_device_t* p_emac_dev)
{
Emac *p_hw = p_emac_dev->p_hw;
emac_tx_descriptor_t *p_tx_td;
emac_dev_tx_cb_t *p_tx_cb;
volatile uint32_t ul_isr;
volatile uint32_t ul_rsr;
volatile uint32_t ul_tsr;
uint32_t ul_rx_status_flag;
uint32_t ul_tx_status_flag;
ul_isr = emac_get_interrupt_status(p_hw);
ul_rsr = emac_get_rx_status(p_hw);
ul_tsr = emac_get_tx_status(p_hw);
ul_isr &= ~(emac_get_interrupt_mask(p_hw) | 0xFFC300);
/* RX packet */
if ((ul_isr & EMAC_ISR_RCOMP) || (ul_rsr & EMAC_RSR_REC)) {
ul_rx_status_flag = EMAC_RSR_REC;
/* Check OVR */
if (ul_rsr & EMAC_RSR_OVR) {
ul_rx_status_flag |= EMAC_RSR_OVR;
}
/* Check BNA */
if (ul_rsr & EMAC_RSR_BNA) {
ul_rx_status_flag |= EMAC_RSR_BNA;
}
/* Clear status */
emac_clear_rx_status(p_hw, ul_rx_status_flag);
/* Invoke callbacks */
if (p_emac_dev->func_rx_cb) {
p_emac_dev->func_rx_cb(ul_rx_status_flag);
}
}
/* TX packet */
if ((ul_isr & EMAC_ISR_TCOMP) || (ul_tsr & EMAC_TSR_COMP)) {
ul_tx_status_flag = EMAC_TSR_COMP;
/* A frame transmitted */
/* Check RLE */
if (ul_tsr & EMAC_TSR_RLES) {
/* Status RLE & Number of discarded buffers */
ul_tx_status_flag = EMAC_TSR_RLES | CIRC_CNT(p_emac_dev->us_tx_head,
p_emac_dev->us_tx_tail, p_emac_dev->us_tx_list_size);
p_tx_cb = &p_emac_dev->func_tx_cb_list[p_emac_dev->us_tx_tail];
emac_reset_tx_mem(p_emac_dev);
emac_enable_transmit(p_hw, 1);
}
/* Check COL */
if (ul_tsr & EMAC_TSR_COL) {
ul_tx_status_flag |= EMAC_TSR_COL;
}
/* Check BEX */
if (ul_tsr & EMAC_TSR_BEX) {
ul_tx_status_flag |= EMAC_TSR_BEX;
}
/* Check UND */
if (ul_tsr & EMAC_TSR_UND) {
ul_tx_status_flag |= EMAC_TSR_UND;
}
/* Clear status */
emac_clear_tx_status(p_hw, ul_tx_status_flag);
if (!CIRC_EMPTY(p_emac_dev->us_tx_head, p_emac_dev->us_tx_tail)) {
/* Check the buffers */
do {
p_tx_td = &p_emac_dev->p_tx_dscr[p_emac_dev->us_tx_tail];
p_tx_cb = &p_emac_dev->func_tx_cb_list[p_emac_dev->us_tx_tail];
/* Any error? Exit if buffer has not been sent yet */
if ((p_tx_td->status.val & EMAC_TXD_USED) == 0) {
break;
}
/* Notify upper layer that a packet has been sent */
if (*p_tx_cb) {
(*p_tx_cb) (ul_tx_status_flag);
}
circ_inc(&p_emac_dev->us_tx_tail, p_emac_dev->us_tx_list_size);
} while (CIRC_CNT(p_emac_dev->us_tx_head, p_emac_dev->us_tx_tail,
p_emac_dev->us_tx_list_size));
}
if (ul_tsr & EMAC_TSR_RLES) {
/* Notify upper layer RLE */
if (*p_tx_cb) {
(*p_tx_cb) (ul_tx_status_flag);
}
}
/* If a wakeup has been scheduled, notify upper layer that it can
send other packets, and the sending will be successful. */
if ((CIRC_SPACE(p_emac_dev->us_tx_head, p_emac_dev->us_tx_tail,
p_emac_dev->us_tx_list_size) >= p_emac_dev->uc_wakeup_threshold)
&& p_emac_dev->func_wakeup_cb) {
p_emac_dev->func_wakeup_cb();
}
}
}
//@}
#endif // SAM3XA_SERIES
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
}
#endif
/**INDENT-ON**/
/// @endcond

View File

@ -0,0 +1,94 @@
/**
* \file
*
* \brief General Purpose Backup Registers (GPBR) driver for SAM.
*
* Copyright (c) 2011-2012 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#include "gpbr.h"
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
extern "C" {
#endif
/**INDENT-ON**/
/// @endcond
/**
* \defgroup sam_drivers_gpbr_group General Purpose Backup Registers (GPBR)
*
* Driver for the General Purpose Backup Registers. This driver provides access
* to the main features of the GPBR controller.
*
* @{
*/
/**
* \brief Read the specified backup register.
*
* \param ul_reg_num General purpose backup register number.
*
* \return Value of the specified backup register.
*/
uint32_t gpbr_read(gpbr_num_t ul_reg_num)
{
return GPBR->SYS_GPBR[ul_reg_num];
}
/**
* \brief Write a value to the specified backup register.
*
* \param ul_reg_num General purpose backup register number.
* \param ul_value Value to be written.
*/
void gpbr_write(gpbr_num_t ul_reg_num, uint32_t ul_value)
{
GPBR->SYS_GPBR[ul_reg_num] = ul_value;
}
//@}
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
}
#endif
/**INDENT-ON**/
/// @endcond

View File

@ -0,0 +1,835 @@
/**
* \file
*
* \brief Synchronous Serial Controller (SSC) driver for SAM.
*
* Copyright (c) 2011-2012 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#include <string.h>
#include "ssc.h"
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
extern "C" {
#endif
/**INDENT-ON**/
/// @endcond
/**
* \defgroup sam_drivers_ssc_group Synchronous Serial Controller (SSC)
*
* The Synchronous Serial Controller (SSC) provides a synchronous communication
* link with external devices. It supports many serial synchronous communication
* protocols generally used in audio and telecom applications such as I2S,
* Short Frame Sync, Long Frame Sync, etc.
* This is a driver for configuration and use of the SSC peripheral.
*
* @{
*/
#define SSC_WPKEY SSC_WPMR_WPKEY(0x535343)
/**
* \brief Set up clock.
*
* \param p_ssc Pointer to an SSC instance.
* \param ul_bitrate Desired bit clock.
* \param ul_mck MCK clock.
*
* \retval SSC_RC_YES Success.
* \retval SSC_RC_NO Invalid input value.
*/
uint32_t ssc_set_clock_divider(Ssc *p_ssc, uint32_t ul_bitrate,
uint32_t ul_mck)
{
if (ul_mck && ul_bitrate) {
p_ssc->SSC_CMR = SSC_CMR_DIV(((ul_mck + ul_bitrate) / ul_bitrate) >> 1);
return SSC_RC_YES;
} else {
return SSC_RC_NO;
}
}
/**
* \brief Setup for I2S transmitter.
*
* \note If working in master mode, the divided clock needs to be configured before
* calling this function according to the sample rate and ul_datlen field.
*
* \param p_ssc Pointer to an SSC instance.
* \param ul_mode Working mode, SSC_I2S_MASTER_OUT or SSC_I2S_SLAVE_OUT.
* \param ul_cks Source clock selection while working in SSC_I2S_SLAVE_OUT mode.
* \param ul_ch_mode Channel mode, stereo or mono.
* \param ul_datlen Data length for one channel.
*/
void ssc_i2s_set_transmitter(Ssc *p_ssc, uint32_t ul_mode,
uint32_t ul_cks, uint32_t ul_ch_mode, uint32_t ul_datlen)
{
clock_opt_t tx_clk_option;
data_frame_opt_t tx_data_frame_option;
/* Initialize the local variable. */
memset((uint8_t *)&tx_clk_option, 0, sizeof(clock_opt_t));
memset((uint8_t *)&tx_data_frame_option, 0, sizeof(data_frame_opt_t));
/* Data start: MonoLeft-Falling, MonoRight-Rising, Stero-Edge. */
switch (ul_ch_mode) {
case SSC_AUDIO_MONO_RIGHT:
tx_clk_option.ul_start_sel = SSC_TCMR_START_RF_RISING;
break;
case SSC_AUDIO_MONO_LEFT:
tx_clk_option.ul_start_sel = SSC_TCMR_START_RF_FALLING;
break;
case SSC_AUDIO_STERO:
tx_clk_option.ul_start_sel = SSC_TCMR_START_RF_EDGE;
break;
}
if (ul_mode & SSC_I2S_MASTER_OUT) {
/* Stereo has 2 data words, and mono has only one data word. */
if (SSC_AUDIO_STERO == ul_ch_mode) {
tx_data_frame_option.ul_datnb = 1;
} else {
tx_data_frame_option.ul_datnb = 0;
}
/* Configure TCMR Settings. */
tx_clk_option.ul_cks = SSC_TCMR_CKS_MCK;
tx_clk_option.ul_cko = SSC_TCMR_CKO_CONTINUOUS;
tx_clk_option.ul_cki = 0;
tx_clk_option.ul_ckg = SSC_RCMR_CKG_NONE;
/* The delay is defined by I2S protocol. */
tx_clk_option.ul_sttdly = 1;
tx_clk_option.ul_period = ul_datlen - 1;
/* Configure TFMR Settings. */
tx_data_frame_option.ul_datlen = ul_datlen - 1;
tx_data_frame_option.ul_msbf = SSC_TFMR_MSBF;
tx_data_frame_option.ul_fslen = ul_datlen - 1;
tx_data_frame_option.ul_fsos = SSC_TFMR_FSOS_NEGATIVE;
tx_data_frame_option.ul_fsedge = SSC_TFMR_FSEDGE_POSITIVE;
} else if (ul_mode & SSC_I2S_SLAVE_OUT) {
/* Configure TCMR Settings. */
tx_clk_option.ul_cks = ul_cks;
tx_clk_option.ul_cko = SSC_TCMR_CKO_NONE;
tx_clk_option.ul_cki = 0;
tx_clk_option.ul_ckg = SSC_RCMR_CKG_NONE;
tx_clk_option.ul_sttdly = 1;
tx_clk_option.ul_period = 0;
/* Configure TFMR Settings. */
tx_data_frame_option.ul_datlen = ul_datlen - 1;
tx_data_frame_option.ul_msbf = SSC_TFMR_MSBF;
tx_data_frame_option.ul_fslen = 0;
tx_data_frame_option.ul_fsos = SSC_TFMR_FSOS_NONE;
tx_data_frame_option.ul_fsedge = SSC_TFMR_FSEDGE_POSITIVE;
}
/* Configure the default level on TD pin. */
ssc_set_td_default_level(p_ssc, 0);
/* Configure the SSC transmitter. */
ssc_set_transmitter(p_ssc, &tx_clk_option, &tx_data_frame_option);
}
/**
* \brief Setup for I2S receiver.
*
* \note If working in master mode, the divided clock needs to be configured before
* calling this function according to the sample rate and ul_datlen field.
*
* \param p_ssc Pointer to an SSC instance.
* \param ul_mode Working mode, SSC_I2S_MASTER_IN or SSC_I2S_SLAVE_IN.
* \param ul_cks Source clock selection while working in SSC_I2S_SLAVE_IN mode.
* \param ul_ch_mode Channel mode, stereo or mono.
* \param ul_datlen Data length for one channel.
*/
void ssc_i2s_set_receiver(Ssc *p_ssc, uint32_t ul_mode,
uint32_t ul_cks, uint32_t ul_ch_mode, uint32_t ul_datlen)
{
clock_opt_t rx_clk_option;
data_frame_opt_t rx_data_frame_option;
/* Initialize the local variable. */
memset((uint8_t *)&rx_clk_option, 0, sizeof(clock_opt_t));
memset((uint8_t *)&rx_data_frame_option, 0, sizeof(data_frame_opt_t));
/* Data start: MonoLeft-Falling, MonoRight-Rising, Stero-Edge. */
switch (ul_ch_mode) {
case SSC_AUDIO_MONO_RIGHT:
rx_clk_option.ul_start_sel = SSC_RCMR_START_RF_RISING;
break;
case SSC_AUDIO_MONO_LEFT:
rx_clk_option.ul_start_sel = SSC_RCMR_START_RF_FALLING;
break;
case SSC_AUDIO_STERO:
rx_clk_option.ul_start_sel = SSC_RCMR_START_RF_EDGE;
break;
}
if (ul_mode & SSC_I2S_MASTER_IN) {
/* Stereo has 2 data words, and mono has only one data word. */
if (SSC_AUDIO_STERO == ul_ch_mode) {
rx_data_frame_option.ul_datnb = 1;
} else {
rx_data_frame_option.ul_datnb = 0;
}
/* Configure RCMR Settings. */
rx_clk_option.ul_cks = SSC_TCMR_CKS_MCK;
rx_clk_option.ul_cko = SSC_TCMR_CKO_CONTINUOUS;
rx_clk_option.ul_cki = 0;
rx_clk_option.ul_ckg = SSC_RCMR_CKG_NONE;
rx_clk_option.ul_sttdly = 1;
rx_clk_option.ul_period = ul_datlen - 1;
/* Configure RFMR Settings. */
rx_data_frame_option.ul_datlen = ul_datlen - 1;
rx_data_frame_option.ul_msbf = SSC_TFMR_MSBF;
rx_data_frame_option.ul_fslen = ul_datlen - 1;
rx_data_frame_option.ul_fsos = SSC_TFMR_FSOS_NEGATIVE;
rx_data_frame_option.ul_fsedge = SSC_TFMR_FSEDGE_POSITIVE;
} else if (ul_mode & SSC_I2S_SLAVE_IN) {
/* Configure TCMR Settings. */
rx_clk_option.ul_cks = ul_cks;
rx_clk_option.ul_cko = SSC_TCMR_CKO_NONE;
rx_clk_option.ul_cki = 0;
rx_clk_option.ul_ckg = SSC_RCMR_CKG_NONE;
rx_clk_option.ul_sttdly = 1;
rx_clk_option.ul_period = 0;
/* Configure TFMR Settings. */
rx_data_frame_option.ul_datlen = ul_datlen - 1;
rx_data_frame_option.ul_msbf = SSC_TFMR_MSBF;
rx_data_frame_option.ul_fslen = 0;
rx_data_frame_option.ul_fsos = SSC_TFMR_FSOS_NONE;
rx_data_frame_option.ul_fsedge = SSC_TFMR_FSEDGE_POSITIVE;
}
/* Configure the SSC receiver. */
ssc_set_receiver(p_ssc, &rx_clk_option, &rx_data_frame_option);
}
/**
* \brief Reset SSC module.
*
* \param p_ssc Pointer to an SSC instance.
*/
void ssc_reset(Ssc *p_ssc)
{
p_ssc->SSC_CR = SSC_CR_SWRST;
p_ssc->SSC_CMR = 0;
p_ssc->SSC_RCMR = 0;
p_ssc->SSC_RFMR = 0;
p_ssc->SSC_TCMR = 0;
p_ssc->SSC_TFMR = 0;
}
/**
* \brief Enable SSC receiver.
*
* \param p_ssc Pointer to an SSC instance.
*/
void ssc_enable_rx(Ssc *p_ssc)
{
p_ssc->SSC_CR = SSC_CR_RXEN;
}
/**
* \brief Disable SSC receiver.
*
* \param p_ssc Pointer to an SSC instance.
*/
void ssc_disable_rx(Ssc *p_ssc)
{
p_ssc->SSC_CR = SSC_CR_RXDIS;
}
/**
* \brief Enable SSC Transmitter.
*
* \param p_ssc Pointer to an SSC instance.
*/
void ssc_enable_tx(Ssc *p_ssc)
{
p_ssc->SSC_CR = SSC_CR_TXEN;
}
/**
* \brief Disable SSC Transmitter.
*
* \param p_ssc Pointer to an SSC instance.
*/
void ssc_disable_tx(Ssc *p_ssc)
{
p_ssc->SSC_CR = SSC_CR_TXDIS;
}
/**
* \brief Configure SSC to work in normal mode.
*
* \param p_ssc Pointer to an SSC instance.
*/
void ssc_set_normal_mode(Ssc *p_ssc)
{
p_ssc->SSC_RFMR &= ~SSC_RFMR_LOOP;
}
/**
* \brief Configure SSC to work in loop mode.
*
* \param p_ssc Pointer to an SSC instance.
*/
void ssc_set_loop_mode(Ssc *p_ssc)
{
p_ssc->SSC_RFMR |= SSC_RFMR_LOOP;
}
/**
* \brief Configure SSC receive stop selection.
*
* \param p_ssc Pointer to an SSC instance.
* \param ul_sel Compare 0 used or Compare both 0 & 1 used.
*/
void ssc_set_rx_stop_selection(Ssc *p_ssc, uint32_t ul_sel)
{
if (SSC_RX_STOP_COMPARE_0_1 == ul_sel) {
p_ssc->SSC_RCMR |= SSC_RCMR_STOP;
} else if (SSC_RX_STOP_COMPARE_0 == ul_sel) {
p_ssc->SSC_RCMR &= ~SSC_RCMR_STOP;
}
}
/**
* \brief Configure SSC default level driven on the TD pin while
* out of transmission.
*
* \param p_ssc Pointer to an SSC instance.
* \param ul_level The default driven level of TD pin.
*/
void ssc_set_td_default_level(Ssc *p_ssc, uint32_t ul_level)
{
if (ul_level) {
p_ssc->SSC_TFMR |= SSC_TFMR_DATDEF;
} else {
p_ssc->SSC_TFMR &= ~SSC_TFMR_DATDEF;
}
}
/**
* \brief The TD line is driven with the SSC_TSHR register value
* during the transmission of the Transmit Frame Sync Signal.
*
* \param p_ssc Pointer to an SSC instance.
*/
void ssc_enable_tx_frame_sync_data(Ssc *p_ssc)
{
p_ssc->SSC_TFMR |= SSC_TFMR_FSDEN;
}
/**
* \brief The TD line is driven with the default value during the Transmit
* Frame Sync signal.
*
* \param p_ssc Pointer to an SSC instance.
*/
void ssc_disable_tx_frame_sync_data(Ssc *p_ssc)
{
p_ssc->SSC_TFMR &= ~SSC_TFMR_FSDEN;
}
/**
* \brief Configure SSC receiver clock mode and date frame configuration.
*
* \param p_ssc Pointer to an SSC instance.
* \param p_rx_clk_opt Pointer to the receiver clock configuration structure.
* \param p_rx_data_frame Pointer to the receiver data frame configuration structure.
*/
void ssc_set_receiver(Ssc *p_ssc, clock_opt_t *p_rx_clk_opt,
data_frame_opt_t *p_rx_data_frame)
{
if (p_rx_clk_opt == NULL) {
p_ssc->SSC_RCMR = 0;
} else {
p_ssc->SSC_RCMR |= p_rx_clk_opt->ul_cks |
p_rx_clk_opt->ul_cko | p_rx_clk_opt->ul_cki |
p_rx_clk_opt->ul_ckg |
p_rx_clk_opt->ul_start_sel |
SSC_RCMR_PERIOD(p_rx_clk_opt->ul_period) |
SSC_RCMR_STTDLY(p_rx_clk_opt->ul_sttdly);
}
if (p_rx_data_frame == NULL) {
p_ssc->SSC_RFMR = 0;
} else {
p_ssc->SSC_RFMR |= SSC_RFMR_DATLEN(p_rx_data_frame->ul_datlen) |
p_rx_data_frame->ul_msbf |
SSC_RFMR_DATNB(p_rx_data_frame->ul_datnb) |
SSC_RFMR_FSLEN(p_rx_data_frame->ul_fslen) |
SSC_RFMR_FSLEN_EXT(p_rx_data_frame->ul_fslen_ext) |
p_rx_data_frame->ul_fsos |
p_rx_data_frame->ul_fsedge;
}
}
/**
* \brief Configure SSC transmitter clock mode and date frame configuration.
*
* \param p_ssc Pointer to an SSC instance.
* \param p_tx_clk_opt Pointer to the transmitter clock configuration structure.
* \param p_tx_data_frame Pointer to the transmitter data frame configuration structure.
*/
void ssc_set_transmitter(Ssc *p_ssc, clock_opt_t *p_tx_clk_opt,
data_frame_opt_t *p_tx_data_frame)
{
if (p_tx_clk_opt == NULL) {
p_ssc->SSC_TCMR = 0;
} else {
p_ssc->SSC_TCMR |= p_tx_clk_opt->ul_cks |
p_tx_clk_opt->ul_cko | p_tx_clk_opt->ul_cki |
p_tx_clk_opt->ul_ckg |
p_tx_clk_opt->ul_start_sel |
SSC_RCMR_PERIOD(p_tx_clk_opt->ul_period) |
SSC_RCMR_STTDLY(p_tx_clk_opt->ul_sttdly);
}
if (p_tx_data_frame == NULL) {
p_ssc->SSC_TFMR = 0;
} else {
p_ssc->SSC_TFMR |= SSC_RFMR_DATLEN(p_tx_data_frame->ul_datlen) |
p_tx_data_frame->ul_msbf |
SSC_RFMR_DATNB(p_tx_data_frame->ul_datnb) |
SSC_RFMR_FSLEN(p_tx_data_frame->ul_fslen) |
SSC_RFMR_FSLEN_EXT(p_tx_data_frame->ul_fslen_ext) |
p_tx_data_frame->ul_fsos |
p_tx_data_frame->ul_fsedge;
}
}
/**
* \brief Configure SSC Receive Compare Register.
*
* \param p_ssc Pointer to an SSC instance.
* \param ul_id Compare register ID.
* \param ul_value Value to configure.
*/
void ssc_set_rx_compare(Ssc *p_ssc, uint32_t ul_id, uint32_t ul_value)
{
switch (ul_id) {
case COMPARE_ID0:
p_ssc->SSC_RC0R = ul_value;
break;
case COMPARE_ID1:
p_ssc->SSC_RC1R = ul_value;
break;
}
}
/**
* \brief Get SSC Receive Compare Register.
*
* \param p_ssc Pointer to an SSC instance.
* \param ul_id Compare register ID.
*
* \return Receive Compare Register value for the specified ul_id, otherwise SSC_RC_INVALID.
*/
uint32_t ssc_get_rx_compare(Ssc *p_ssc, uint32_t ul_id)
{
switch (ul_id) {
case COMPARE_ID0:
return p_ssc->SSC_RC0R;
case COMPARE_ID1:
return p_ssc->SSC_RC1R;
default:
return SSC_RC_INVALID;
}
}
/**
* \brief Enable SSC interrupts.
*
* \param p_ssc Pointer to an SSC instance.
* \param ul_sources Interrupts to be enabled.
*/
void ssc_enable_interrupt(Ssc *p_ssc, uint32_t ul_sources)
{
p_ssc->SSC_IER = ul_sources;
}
/**
* \brief Disable SSC interrupts.
*
* \param p_ssc Pointer to an SSC instance.
* \param ul_sources Interrupts to be enabled.
*/
void ssc_disable_interrupt(Ssc *p_ssc, uint32_t ul_sources)
{
p_ssc->SSC_IDR = ul_sources;
}
/**
* \brief Read SSC interrupt mask.
*
* \param p_ssc Pointer to an SSC instance.
*
* \return The interrupt mask value.
*/
uint32_t ssc_get_interrupt_mask(Ssc *p_ssc)
{
return p_ssc->SSC_IMR;
}
/**
* \brief Read SSC status.
*
* \param p_ssc Pointer to an SSC instance.
*
* \return The SSC status value.
*/
uint32_t ssc_get_status(Ssc *p_ssc)
{
return p_ssc->SSC_SR;
}
/**
* \brief Check if data has been loaded in SSC_THR and is waiting to be loaded
* in the Transmit Shift Register (TSR).
*
* \param p_ssc Pointer to an SSC instance.
*
* \retval SSC_RC_YES There is no data in the SSC_THR.
* \retval SSC_RC_NO There is one data in the SSC_THR.
*/
uint32_t ssc_is_tx_ready(Ssc *p_ssc)
{
if (p_ssc->SSC_SR & SSC_SR_TXRDY) {
return SSC_RC_YES;
}
return SSC_RC_NO;
}
/**
* \brief Check if the last data written in SSC_THR has been loaded in TSR
* and the last data loaded in TSR has been transmitted.
*
* \param p_ssc Pointer to an SSC instance.
*
* \retval SSC_RC_YES Both of the two registers are empty.
* \retval SSC_RC_NO At least one of the two registers is not empty.
*/
uint32_t ssc_is_tx_empty(Ssc *p_ssc)
{
if (p_ssc->SSC_SR & SSC_SR_TXEMPTY) {
return SSC_RC_YES;
}
return SSC_RC_NO;
}
/**
* \brief Check if data has been received and loaded in SSC_RHR.
*
* \param p_ssc Pointer to an SSC instance.
*
* \retval SSC_RC_YES There is one data in the SSC_RHR.
* \retval SSC_RC_NO There is no data in the SSC_RHR.
*/
uint32_t ssc_is_rx_ready(Ssc *p_ssc)
{
if (p_ssc->SSC_SR & SSC_SR_RXRDY) {
return SSC_RC_YES;
}
return SSC_RC_NO;
}
/**
* \brief Check if transmitter is enabled.
*
* \param p_ssc Pointer to an SSC instance.
*
* \retval SSC_RC_YES The transmitter is enabled.
* \retval SSC_RC_NO The transmitter is disabled.
*/
uint32_t ssc_is_tx_enabled(Ssc *p_ssc)
{
if (p_ssc->SSC_SR & SSC_SR_TXEN) {
return SSC_RC_YES;
}
return SSC_RC_NO;
}
/**
* \brief Check if receiver is enabled.
*
* \param p_ssc Pointer to an SSC instance.
*
* \retval SSC_RC_YES The receiver is enabled.
* \retval SSC_RC_NO The receiver is disabled.
*/
uint32_t ssc_is_rx_enabled(Ssc *p_ssc)
{
if (p_ssc->SSC_SR & SSC_SR_RXEN) {
return SSC_RC_YES;
}
return SSC_RC_NO;
}
#if (SAM3S_SERIES) || (SAM4S_SERIES)
/**
* \brief Check if one receive buffer is filled.
*
* \param p_ssc Pointer to an SSC instance.
*
* \retval SSC_RC_YES Receive Counter has reached zero.
* \retval SSC_RC_NO Data is written on the Receive Counter Register or
* Receive Next Counter Register.
*/
uint32_t ssc_is_rx_buf_end(Ssc *p_ssc)
{
if (p_ssc->SSC_SR & SSC_SR_ENDRX) {
return SSC_RC_YES;
}
return SSC_RC_NO;
}
/**
* \brief Check if the register SSC_TCR has reached 0.
*
* \param p_ssc Pointer to an SSC instance.
*
* \retval SSC_RC_YES The register SSC_TCR has reached 0.
* \retval SSC_RC_NO The register SSC_TCR hasn't reached 0.
*/
uint32_t ssc_is_tx_buf_end(Ssc *p_ssc)
{
if (p_ssc->SSC_SR & SSC_SR_ENDTX) {
return SSC_RC_YES;
}
return SSC_RC_NO;
}
/**
* \brief Check if both receive buffers are full.
*
* \param p_ssc Pointer to an SSC instance.
*
* \retval SSC_RC_YES Both of the two receive buffers have reached 0.
* \retval SSC_RC_NO One of the two receive buffers hasn't reached 0.
*/
uint32_t ssc_is_rx_buf_full(Ssc *p_ssc)
{
if (p_ssc->SSC_SR & SSC_SR_RXBUFF) {
return SSC_RC_YES;
}
return SSC_RC_NO;
}
/**
* \brief Check if both transmit buffers are empty.
*
* \param p_ssc Pointer to an SSC instance.
*
* \retval SSC_RC_YES Both of the two transmit buffers have reached 0.
* \retval SSC_RC_NO One of the two transmit buffers hasn't reached 0.
*/
uint32_t ssc_is_tx_buf_empty(Ssc *p_ssc)
{
if (p_ssc->SSC_SR & SSC_SR_TXBUFE) {
return SSC_RC_YES;
}
return SSC_RC_NO;
}
/**
* \brief Get SSC PDC registers base address.
*
* \param p_ssc Pointer to SSC registers set instance.
*
* \return SSC PDC registers base address for PDC driver to access.
*/
Pdc *ssc_get_pdc_base(Ssc *p_ssc)
{
return (Pdc *)&(p_ssc->SSC_RPR);
}
#endif // (SAM3S_SERIES) || (SAM4S_SERIES)
/**
* \brief Write to SSC Transmit Holding Register.
* Send data through SSC Data frame.
*
* \param p_ssc Pointer to an SSC instance.
* \param ul_frame Frame data to be transmitted.
*
* \retval SSC_RC_ERROR Time-out.
* \retval SSC_RC_OK Success.
*
*/
uint32_t ssc_write(Ssc *p_ssc, uint32_t ul_frame)
{
uint32_t ul_timeout = SSC_DEFAULT_TIMEOUT;
while (!(p_ssc->SSC_SR & SSC_SR_TXEMPTY)) {
if (!ul_timeout--) {
return SSC_RC_ERROR;
}
}
p_ssc->SSC_THR = ul_frame;
return SSC_RC_OK;
}
/**
* \brief Read from SSC Receive Holding Register.
* Read data that is received in SSC Data frame.
*
* \param p_ssc Pointer to an SSC instance.
* \param ul_data Pointer to the location where to store the received data.
*
* \retval SSC_RC_ERROR Time-out.
* \retval SSC_RC_OK Success.
*/
uint32_t ssc_read(Ssc *p_ssc, uint32_t *ul_data)
{
uint32_t ul_timeout = SSC_DEFAULT_TIMEOUT;
while (!(p_ssc->SSC_SR & SSC_SR_RXRDY)) {
if (!ul_timeout--) {
return SSC_RC_ERROR;
}
}
*ul_data = p_ssc->SSC_RHR;
return SSC_RC_OK;
}
/**
* \brief Write to SSC Transmit Synchronization Holding Register.
* Send data through SSC Synchronization frame. If there is sync data that needs to be
* transmitted, call this function first to send out the sync data, and then call the
* ssc_write() function to send out application data.
*
* \param p_ssc Pointer to an SSC instance.
* \param ul_frame Frame Synchronization data.
*/
void ssc_write_sync_data(Ssc *p_ssc, uint32_t ul_frame)
{
p_ssc->SSC_TSHR = ul_frame;
}
/**
* \brief Read from SSC Receive Synchronization Holding Register.
* Read data that is received in SSC Synchronization frame. When the sync data is actually
* used, after successfully reading the application data by calling ssc_read(), call
* this function, and the return sync data is useful.
*
* \param p_ssc Pointer to an SSC instance.
*
* \return Current RSHR value.
*/
uint32_t ssc_read_sync_data(Ssc *p_ssc)
{
return p_ssc->SSC_RSHR;
}
#if (SAM3XA_SERIES || SAM3U_SERIES)
/**
* \brief Get Transmit address for DMA operation.
*
* \param p_ssc Pointer to an SSC instance.
*
* \return Transmitting address for DMA access.
*/
void *ssc_get_tx_access(Ssc *p_ssc)
{
return (void *)&(p_ssc->SSC_THR);
}
/**
* \brief Get Receive address for DMA operation.
*
* \param p_ssc Pointer to an SSC instance.
*
* \return Transmitting address for DMA access.
*/
void *ssc_get_rx_access(Ssc *p_ssc)
{
return (void *)&(p_ssc->SSC_RHR);
}
#endif // (SAM3XA_SERIES || SAM3U_SERIES)
/**
* \brief Enable or disable write protection of SSC registers.
*
* \param p_ssc Pointer to an SSC instance.
* \param ul_enable 1 to enable, 0 to disable.
*/
void ssc_set_writeprotect(Ssc *p_ssc, uint32_t ul_enable)
{
if (ul_enable) {
p_ssc->SSC_WPMR = SSC_WPKEY | SSC_WPMR_WPEN;
} else {
p_ssc->SSC_WPMR = SSC_WPKEY;
}
}
/**
* \brief Indicate write protect status.
*
* \param p_ssc Pointer to an SSC instance.
*
* \return 0 if the peripheral is not protected. Write Protect Violation Status otherwise.
*/
uint32_t ssc_get_writeprotect_status(Ssc *p_ssc)
{
uint32_t ul_reg_val;
ul_reg_val = p_ssc->SSC_WPMR;
if (ul_reg_val & SSC_WPMR_WPEN) {
return (ul_reg_val & SSC_WPSR_WPVSRC_Msk) >> SSC_WPSR_WPVSRC_Pos;
} else {
return 0;
}
}
//@}
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
}
#endif
/**INDENT-ON**/
/// @endcond

View File

@ -0,0 +1,160 @@
/**
* \file
*
* \brief TRNG driver for SAM.
*
* Copyright (c) 2011-2012 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/**
* \defgroup group_sam_drivers_trng TRNG - True Random Number Generator
*
* Driver for the TRNG (True Random Number Generator). This driver provides access
* to the main features of the TRNG controller.
*
* \{
*/
#include "../chip.h"
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
extern "C" {
#endif
/**INDENT-ON**/
/// @endcond
#if SAM3XA_SERIES
/* TRNG Security Key Value */
#define TRNG_KEY 0x524E47
/**
* \brief Enable TRNG.
*
* \param p_trng Pointer to a TRNG instance.
*
*/
void trng_enable(Trng *p_trng)
{
p_trng->TRNG_CR = TRNG_CR_ENABLE | TRNG_CR_KEY(TRNG_KEY);
}
/**
* \brief Disable TRNG.
*
* \param p_trng Pointer to a TRNG instance.
*
*/
void trng_disable(Trng *p_trng)
{
p_trng->TRNG_CR = TRNG_CR_KEY(TRNG_KEY);
}
/**
* \brief Enable TRNG interrupt.
*
* \param p_trng Pointer to a TRNG instance.
*
*/
void trng_enable_interrupt(Trng *p_trng)
{
p_trng->TRNG_IER = TRNG_IER_DATRDY;
}
/**
* \brief Disable TRNG interrupt.
*
* \param p_trng Pointer to a TRNG instance.
*
*/
void trng_disable_interrupt(Trng *p_trng)
{
p_trng->TRNG_IDR = TRNG_IER_DATRDY;
}
/**
* \brief Get TRNG interrupt mask.
*
* \param p_trng Pointer to a TRNG instance.
*
* \retval The interrupt mask value.
*/
uint32_t trng_get_interrupt_mask(Trng *p_trng)
{
return p_trng->TRNG_IMR;
}
/**
* \brief Get TRNG interrupt status.
*
* \param p_trng Pointer to a TRNG instance.
*
* \retval The interrupt status value.
*/
uint32_t trng_get_interrupt_status(Trng *p_trng)
{
return p_trng->TRNG_ISR;
}
/**
* \brief Read TRNG output data.
*
* \param p_trng Pointer to a TRNG instance.
*
* \retval The output data value.
*/
uint32_t trng_read_output_data(Trng *p_trng)
{
return p_trng->TRNG_ODATA;
}
#endif // SAM3XA_SERIES
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
}
#endif
/**INDENT-ON**/
/// @endcond
/**
* \}
*/

View File

@ -72,7 +72,6 @@ pmc.o:
00000000 T pmc_switch_udpck_to_upllck
pwmc.o:
00000000 r C.9.7280
00000000 t FindClockConfiguration
00000000 T PWMC_ConfigureChannel
00000000 T PWMC_ConfigureChannelExt
@ -100,14 +99,14 @@ pwmc.o:
00000000 T PWMC_SetSyncChannelUpdateUnlock
00000000 T PWMC_WriteBuffer
U __assert_func
00000000 r __func__.5974
00000000 r __func__.5985
00000000 r __func__.6000
00000000 r __func__.6011
00000000 r __func__.6022
00000000 r __func__.6029
00000000 r __func__.6113
00000000 r __func__.6119
00000000 r __func__.6271
00000000 r __func__.6282
00000000 r __func__.6297
00000000 r __func__.6308
00000000 r __func__.6319
00000000 r __func__.6326
00000000 r __func__.6410
00000000 r __func__.6416
rtc.o:
00000000 T RTC_ClearSCCR
@ -123,9 +122,9 @@ rtc.o:
00000000 T RTC_SetTime
00000000 T RTC_SetTimeAlarm
U __assert_func
00000000 r __func__.5971
00000000 r __func__.5980
00000000 r __func__.5985
00000000 r __func__.6268
00000000 r __func__.6277
00000000 r __func__.6282
rtt.o:
00000000 T RTT_EnableIT
@ -134,8 +133,8 @@ rtt.o:
00000000 T RTT_SetAlarm
00000000 T RTT_SetPrescaler
U __assert_func
00000000 r __func__.5978
00000000 r __func__.5986
00000000 r __func__.6275
00000000 r __func__.6283
spi.o:
00000000 T SPI_Configure
@ -161,9 +160,9 @@ tc.o:
00000000 T TC_Start
00000000 T TC_Stop
U __assert_func
00000000 r __func__.5973
00000000 r __func__.5979
00000000 r __func__.5985
00000000 r __func__.6270
00000000 r __func__.6276
00000000 r __func__.6282
timetick.o:
00000000 T GetTickCount
@ -190,18 +189,18 @@ twi.o:
00000000 T TWI_TransferComplete
00000000 T TWI_WriteByte
U __assert_func
00000000 r __func__.6346
00000000 r __func__.6361
00000000 r __func__.6365
00000000 r __func__.6372
00000000 r __func__.6376
00000000 r __func__.6381
00000000 r __func__.6389
00000000 r __func__.6403
00000000 r __func__.6408
00000000 r __func__.6412
00000000 r __func__.6417
00000000 r __func__.6421
00000000 r __func__.6635
00000000 r __func__.6650
00000000 r __func__.6654
00000000 r __func__.6661
00000000 r __func__.6665
00000000 r __func__.6670
00000000 r __func__.6678
00000000 r __func__.6692
00000000 r __func__.6697
00000000 r __func__.6701
00000000 r __func__.6706
00000000 r __func__.6710
usart.o:
00000000 T USART_Configure
@ -220,7 +219,7 @@ usart.o:
00000000 T USART_Write
00000000 T USART_WriteBuffer
U __assert_func
00000000 r __func__.6267
00000000 r __func__.6556
wdt.o:
00000000 T WDT_Disable
@ -430,3 +429,110 @@ dacc.o:
00000000 T dacc_set_trigger
00000000 T dacc_set_writeprotect
00000000 T dacc_write_conversion_data
can.o:
00000000 R can_bit_time
00000000 T can_disable
00000000 T can_disable_autobaud_listen_mode
00000000 T can_disable_interrupt
00000000 T can_disable_low_power_mode
00000000 T can_disable_overload_frame
00000000 T can_disable_time_triggered_mode
00000000 T can_disable_timer_freeze
00000000 T can_disable_tx_repeat
00000000 T can_enable
00000000 T can_enable_autobaud_listen_mode
00000000 T can_enable_interrupt
00000000 T can_enable_low_power_mode
00000000 T can_enable_overload_frame
00000000 T can_enable_time_triggered_mode
00000000 T can_enable_timer_freeze
00000000 T can_enable_tx_repeat
00000000 T can_get_internal_timer_value
00000000 T can_get_interrupt_mask
00000000 T can_get_rx_error_cnt
00000000 T can_get_status
00000000 T can_get_timestamp_value
00000000 T can_get_tx_error_cnt
00000000 T can_global_send_abort_cmd
00000000 T can_global_send_transfer_cmd
00000000 T can_init
00000000 T can_mailbox_get_status
00000000 T can_mailbox_init
00000000 T can_mailbox_read
00000000 T can_mailbox_send_abort_cmd
00000000 T can_mailbox_send_transfer_cmd
00000000 T can_mailbox_set_timemark
00000000 T can_mailbox_tx_remote_frame
00000000 T can_mailbox_write
00000000 T can_reset_all_mailbox
00000000 T can_reset_internal_timer
00000000 T can_set_rx_sync_stage
00000000 T can_set_timestamp_capture_point
efc.o:
00000000 T efc_disable_frdy_interrupt
00000000 T efc_enable_frdy_interrupt
00000000 T efc_get_flash_access_mode
00000000 T efc_get_result
00000000 T efc_get_status
00000000 T efc_get_wait_state
00000000 T efc_init
00000000 T efc_perform_command
0000006c T efc_perform_fcr
00000000 T efc_perform_read_sequence
00000000 T efc_set_flash_access_mode
00000000 T efc_set_wait_state
00000068 T efc_write_fmr
00000000 b iap_perform_command.6537
gpbr.o:
00000000 T gpbr_read
00000000 T gpbr_write
ssc.o:
U memset
00000000 T ssc_disable_interrupt
00000000 T ssc_disable_rx
00000000 T ssc_disable_tx
00000000 T ssc_disable_tx_frame_sync_data
00000000 T ssc_enable_interrupt
00000000 T ssc_enable_rx
00000000 T ssc_enable_tx
00000000 T ssc_enable_tx_frame_sync_data
00000000 T ssc_get_interrupt_mask
00000000 T ssc_get_rx_access
00000000 T ssc_get_rx_compare
00000000 T ssc_get_status
00000000 T ssc_get_tx_access
00000000 T ssc_get_writeprotect_status
00000000 T ssc_i2s_set_receiver
00000000 T ssc_i2s_set_transmitter
00000000 T ssc_is_rx_enabled
00000000 T ssc_is_rx_ready
00000000 T ssc_is_tx_empty
00000000 T ssc_is_tx_enabled
00000000 T ssc_is_tx_ready
00000000 T ssc_read
00000000 T ssc_read_sync_data
00000000 T ssc_reset
00000000 T ssc_set_clock_divider
00000000 T ssc_set_loop_mode
00000000 T ssc_set_normal_mode
00000000 T ssc_set_receiver
00000000 T ssc_set_rx_compare
00000000 T ssc_set_rx_stop_selection
00000000 T ssc_set_td_default_level
00000000 T ssc_set_transmitter
00000000 T ssc_set_writeprotect
00000000 T ssc_write
00000000 T ssc_write_sync_data
trng.o:
00000000 T trng_disable
00000000 T trng_disable_interrupt
00000000 T trng_enable
00000000 T trng_enable_interrupt
00000000 T trng_get_interrupt_mask
00000000 T trng_get_interrupt_status
00000000 T trng_read_output_data