1
0
mirror of https://github.com/arduino/Arduino.git synced 2025-03-13 10:29:35 +01: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 */

View File

@ -0,0 +1,1225 @@
/**
* \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
*
*/
#ifndef EMAC_H_INCLUDED
#define EMAC_H_INCLUDED
#include "../chip.h"
//#include "conf_eth.h"
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
extern "C" {
#endif
/**INDENT-ON**/
/// @endcond
/** The buffer addresses written into the descriptors must be aligned, so the
last few bits are zero. These bits have special meaning for the EMAC
peripheral and cannot be used as part of the address. */
#define EMAC_RXD_ADDR_MASK 0xFFFFFFFC
#define EMAC_RXD_WRAP (1ul << 1) /**< Wrap bit */
#define EMAC_RXD_OWNERSHIP (1ul << 0) /**< Ownership bit */
#define EMAC_RXD_BROADCAST (1ul << 31) /**< Broadcast detected */
#define EMAC_RXD_MULTIHASH (1ul << 30) /**< Multicast hash match */
#define EMAC_RXD_UNIHASH (1ul << 29) /**< Unicast hash match */
#define EMAC_RXD_EXTADDR (1ul << 28) /**< External address match */
#define EMAC_RXD_ADDR1 (1ul << 26) /**< Address 1 match */
#define EMAC_RXD_ADDR2 (1ul << 25) /**< Address 2 match */
#define EMAC_RXD_ADDR3 (1ul << 24) /**< Address 3 match */
#define EMAC_RXD_ADDR4 (1ul << 23) /**< Address 4 match */
#define EMAC_RXD_TYPE (1ul << 22) /**< Type ID match */
#define EMAC_RXD_VLAN (1ul << 21) /**< VLAN tag detected */
#define EMAC_RXD_PRIORITY (1ul << 20) /**< Priority tag detected */
#define EMAC_RXD_PRIORITY_MASK (3ul << 17) /**< VLAN priority */
#define EMAC_RXD_CFI (1ul << 16) /**< Concatenation Format Indicator only if bit 21 is set */
#define EMAC_RXD_EOF (1ul << 15) /**< End of frame */
#define EMAC_RXD_SOF (1ul << 14) /**< Start of frame */
#define EMAC_RXD_OFFSET_MASK /**< Receive buffer offset */
#define EMAC_RXD_LEN_MASK (0xFFF) /**< Length of frame including FCS (if selected) */
#define EMAC_RXD_LENJUMBO_MASK (0x3FFF) /**< Jumbo frame length */
#define EMAC_TXD_USED (1ul << 31) /**< Frame is transmitted */
#define EMAC_TXD_WRAP (1ul << 30) /**< Last descriptor */
#define EMAC_TXD_ERROR (1ul << 29) /**< Retry limit exceeded, error */
#define EMAC_TXD_UNDERRUN (1ul << 28) /**< Transmit underrun */
#define EMAC_TXD_EXHAUSTED (1ul << 27) /**< Buffer exhausted */
#define EMAC_TXD_NOCRC (1ul << 16) /**< No CRC */
#define EMAC_TXD_LAST (1ul << 15) /**< Last buffer in frame */
#define EMAC_TXD_LEN_MASK (0x7FF) /**< Length of buffer */
/** The MAC can support frame lengths up to 1536 bytes */
#define EMAC_FRAME_LENTGH_MAX 1536
#define EMAC_RX_UNITSIZE 128 /**< Fixed size for RX buffer */
#define EMAC_TX_UNITSIZE 1518 /**< Size for ETH frame length */
/** EMAC clock speed */
#define EMAC_CLOCK_SPEED_160MHZ (160*1000*1000)
#define EMAC_CLOCK_SPEED_80MHZ (80*1000*1000)
#define EMAC_CLOCK_SPEED_40MHZ (40*1000*1000)
#define EMAC_CLOCK_SPEED_20MHZ (20*1000*1000)
/** EMAC maintain code default value*/
#define EMAC_MAN_CODE_VALUE (10)
/** EMAC maintain start of frame default value*/
#define EMAC_MAN_SOF_VALUE (1)
/** EMAC maintain read/write*/
#define EMAC_MAN_RW_TYPE (2)
/** EMAC maintain read only*/
#define EMAC_MAN_READ_ONLY (1)
/** EMAC address length */
#define EMAC_ADDR_LENGTH (6)
/**
* \brief Return codes for EMAC APIs.
*/
typedef enum {
EMAC_OK = 0, /** Operation OK */
EMAC_TIMEOUT = 1, /** EMAC operation timeout */
EMAC_TX_BUSY, /** TX in progress */
EMAC_RX_NULL, /** No data received */
EMAC_SIZE_TOO_SMALL, /** Buffer size not enough */
EMAC_PARAM, /** Parameter error, TX packet invalid or RX size too small */
EMAC_INVALID = 0xFF, /* Invalid */
} emac_status_t;
#if defined __ICCARM__
#pragma pack(4) /* IAR */
#define __attribute__(...) /* IAR */
#endif /* IAR */
/** Receive buffer descriptor struct */
typedef struct emac_rx_descriptor {
union emac_rx_addr {
uint32_t val;
struct emac_rx_addr_bm {
uint32_t b_ownership:1, /**< User clear, EMAC sets this to 1 once it has successfully written a frame to memory */
b_wrap:1, /**< Marks last descriptor in receive buffer */
addr_dw:30; /**< Address in number of DW */
} bm;
} addr; /**< Address, Wrap & Ownership */
union emac_rx_status {
uint32_t val;
struct emac_rx_status_bm {
uint32_t len:12, /** Length of frame including FCS */
offset:2, /** Receive buffer offset, bits 13:12 of frame length for jumbo frame */
b_sof:1, /** Start of frame */
b_eof:1, /** End of frame */
b_cfi:1, /** Concatenation Format Indicator */
vlan_priority:3, /** VLAN priority (if VLAN detected) */
b_priority_detected:1, /** Priority tag detected */
b_vlan_detected:1, /**< VLAN tag detected */
b_type_id_match:1, /**< Type ID match */
b_addr4match:1, /**< Address register 4 match */
b_addr3match:1, /**< Address register 3 match */
b_addr2match:1, /**< Address register 2 match */
b_addr1match:1, /**< Address register 1 match */
reserved:1,
b_ext_addr_match:1, /**< External address match */
b_uni_hash_match:1, /**< Unicast hash match */
b_multi_hash_match:1, /**< Multicast hash match */
b_boardcast_detect:1; /**< Global broadcast address detected */
} bm;
} status;
} __attribute__ ((packed, aligned(8))) emac_rx_descriptor_t; /* GCC */
/** Transmit buffer descriptor struct */
typedef struct emac_tx_descriptor {
uint32_t addr;
union emac_tx_status {
uint32_t val;
struct emac_tx_status_bm {
uint32_t len:11, /**< Length of buffer */
reserved:4,
b_last_buffer:1, /**< Last buffer (in the current frame) */
b_no_crc:1, /**< No CRC */
reserved1:10,
b_exhausted:1, /**< Buffer exhausted in mid frame */
b_underrun:1, /**< Transmit underrun */
b_error:1, /**< Retry limit exceeded, error detected */
b_wrap:1, /**< Marks last descriptor in TD list */
b_used:1; /**< User clear, EMAC sets this to 1 once a frame has been successfully transmitted */
} bm;
} status;
} __attribute__ ((packed, aligned(8))) emac_tx_descriptor_t; /* GCC */
#ifdef __ICCARM__ /* IAR */
#pragma pack()
#endif
/**
* \brief Input parameters when initializing the emac module mode.
*/
typedef struct emac_options {
/* Enable/Disable CopyAllFrame */
uint8_t uc_copy_all_frame;
/* Enable/Disable NoBroadCast */
uint8_t uc_no_boardcast;
/* MAC address */
uint8_t uc_mac_addr[EMAC_ADDR_LENGTH];
} emac_options_t;
/** RX callback */
typedef void (*emac_dev_tx_cb_t) (uint32_t ul_status);
/** Wakeup callback */
typedef void (*emac_dev_wakeup_cb_t) (void);
/**
* EMAC driver structure.
*/
typedef struct emac_device {
/** Pointer to HW register base */
Emac *p_hw;
/**
* Pointer to allocated TX buffer.
* Section 3.6 of AMBA 2.0 spec states that burst should not cross
* 1K Boundaries.
* Receive buffer manager writes are burst of 2 words => 3 lsb bits
* of the address shall be set to 0.
*/
uint8_t *p_tx_buffer;
/** Pointer to allocated RX buffer */
uint8_t *p_rx_buffer;
/** Pointer to Rx TDs (must be 8-byte aligned) */
emac_rx_descriptor_t *p_rx_dscr;
/** Pointer to Tx TDs (must be 8-byte aligned) */
emac_tx_descriptor_t *p_tx_dscr;
/** Optional callback to be invoked once a frame has been received */
emac_dev_tx_cb_t func_rx_cb;
/** Optional callback to be invoked once several TDs have been released */
emac_dev_wakeup_cb_t func_wakeup_cb;
/** Optional callback list to be invoked once TD has been processed */
emac_dev_tx_cb_t *func_tx_cb_list;
/** RX TD list size */
uint16_t us_rx_list_size;
/** RX index for current processing TD */
uint16_t us_rx_idx;
/** TX TD list size */
uint16_t us_tx_list_size;
/** Circular buffer head pointer by upper layer (buffer to be sent) */
uint16_t us_tx_head;
/** Circular buffer tail pointer incremented by handlers (buffer sent) */
uint16_t us_tx_tail;
/** Number of free TD before wakeup callback is invoked */
uint8_t uc_wakeup_threshold;
} emac_device_t;
/**
* \brief Write network control value.
*
* \param p_emac Pointer to the EMAC instance.
* \param ul_ncr Network control value.
*/
static inline void emac_network_control(Emac* p_emac, uint32_t ul_ncr)
{
p_emac->EMAC_NCR = ul_ncr;
}
/**
* \brief Get network control value.
*
* \param p_emac Pointer to the EMAC instance.
*/
static inline uint32_t emac_get_network_control(Emac* p_emac)
{
return p_emac->EMAC_NCR;
}
/**
* \brief Enable/Disable EMAC receive.
*
* \param p_emac Pointer to the EMAC instance.
* \param uc_enable 0 to disable EMAC receiver, else to enable it.
*/
static inline void emac_enable_receive(Emac* p_emac, uint8_t uc_enable)
{
if (uc_enable) {
p_emac->EMAC_NCR |= EMAC_NCR_RE;
} else {
p_emac->EMAC_NCR &= ~EMAC_NCR_RE;
}
}
/**
* \brief Enable/Disable EMAC transmit.
*
* \param p_emac Pointer to the EMAC instance.
* \param uc_enable 0 to disable EMAC transmit, else to enable it.
*/
static inline void emac_enable_transmit(Emac* p_emac, uint8_t uc_enable)
{
if (uc_enable) {
p_emac->EMAC_NCR |= EMAC_NCR_TE;
} else {
p_emac->EMAC_NCR &= ~EMAC_NCR_TE;
}
}
/**
* \brief Enable/Disable EMAC management.
*
* \param p_emac Pointer to the EMAC instance.
* \param uc_enable 0 to disable EMAC management, else to enable it.
*/
static inline void emac_enable_management(Emac* p_emac, uint8_t uc_enable)
{
if (uc_enable) {
p_emac->EMAC_NCR |= EMAC_NCR_MPE;
} else {
p_emac->EMAC_NCR &= ~EMAC_NCR_MPE;
}
}
/**
* \brief Clear all statistics registers.
*
* \param p_emac Pointer to the EMAC instance.
*/
static inline void emac_clear_statistics(Emac* p_emac)
{
p_emac->EMAC_NCR |= EMAC_NCR_CLRSTAT;
}
/**
* \brief Increase all statistics registers.
*
* \param p_emac Pointer to the EMAC instance.
*/
static inline void emac_increase_statistics(Emac* p_emac)
{
p_emac->EMAC_NCR |= EMAC_NCR_INCSTAT;
}
/**
* \brief Enable/Disable statistics registers writing.
*
* \param p_emac Pointer to the EMAC instance.
* \param uc_enable 0 to disable the statistics registers writing, else to enable it.
*/
static inline void emac_enable_statistics_write(Emac* p_emac,
uint8_t uc_enable)
{
if (uc_enable) {
p_emac->EMAC_NCR |= EMAC_NCR_WESTAT;
} else {
p_emac->EMAC_NCR &= ~EMAC_NCR_WESTAT;
}
}
/**
* \brief In half-duplex mode, forces collisions on all received frames.
*
* \param p_emac Pointer to the EMAC instance.
* \param uc_enable 0 to disable the back pressure, else to enable it.
*/
static inline void emac_enable_back_pressure(Emac* p_emac, uint8_t uc_enable)
{
if (uc_enable) {
p_emac->EMAC_NCR |= EMAC_NCR_BP;
} else {
p_emac->EMAC_NCR &= ~EMAC_NCR_BP;
}
}
/**
* \brief Start transmission.
*
* \param p_emac Pointer to the EMAC instance.
*/
static inline void emac_start_transmission(Emac* p_emac)
{
p_emac->EMAC_NCR |= EMAC_NCR_TSTART;
}
/**
* \brief Halt transmission.
*
* \param p_emac Pointer to the EMAC instance.
*/
static inline void emac_halt_transmission(Emac* p_emac)
{
p_emac->EMAC_NCR |= EMAC_NCR_THALT;
}
/**
* \brief Set up network configuration register.
*
* \param p_emac Pointer to the EMAC instance.
* \param ul_cfg Network configuration value.
*/
static inline void emac_set_configure(Emac* p_emac, uint32_t ul_cfg)
{
p_emac->EMAC_NCFGR = ul_cfg;
}
/**
* \brief Get network configuration.
*
* \param p_emac Pointer to the EMAC instance.
*
* \return Network configuration.
*/
static inline uint32_t emac_get_configure(Emac* p_emac)
{
return p_emac->EMAC_NCFGR;
}
/**
* \brief Set speed.
*
* \param p_emac Pointer to the EMAC instance.
* \param uc_speed 1 to indicate 100Mbps, 0 to 10Mbps.
*/
static inline void emac_set_speed(Emac* p_emac, uint8_t uc_speed)
{
if (uc_speed) {
p_emac->EMAC_NCFGR |= EMAC_NCFGR_SPD;
} else {
p_emac->EMAC_NCFGR &= ~EMAC_NCFGR_SPD;
}
}
/**
* \brief Enable/Disable Full-Duplex mode.
*
* \param p_emac Pointer to the EMAC instance.
* \param uc_enable 0 to disable the Full-Duplex mode, else to enable it.
*/
static inline void emac_enable_full_duplex(Emac* p_emac, uint8_t uc_enable)
{
if (uc_enable) {
p_emac->EMAC_NCFGR |= EMAC_NCFGR_FD;
} else {
p_emac->EMAC_NCFGR &= ~EMAC_NCFGR_FD;
}
}
/**
* \brief Enable/Disable Copy(Receive) All Valid Frames.
*
* \param p_emac Pointer to the EMAC instance.
* \param uc_enable 0 to disable copying all valid frames, else to enable it.
*/
static inline void emac_enable_copy_all(Emac* p_emac, uint8_t uc_enable)
{
if (uc_enable) {
p_emac->EMAC_NCFGR |= EMAC_NCFGR_CAF;
} else {
p_emac->EMAC_NCFGR &= ~EMAC_NCFGR_CAF;
}
}
/**
* \brief Enable/Disable jumbo frames (up to 10240 bytes).
*
* \param p_emac Pointer to the EMAC instance.
* \param uc_enable 0 to disable the jumbo frames, else to enable it.
*/
static inline void emac_enable_jumbo_frames(Emac* p_emac, uint8_t uc_enable)
{
if (uc_enable) {
p_emac->EMAC_NCFGR |= EMAC_NCFGR_JFRAME;
} else {
p_emac->EMAC_NCFGR &= ~EMAC_NCFGR_JFRAME;
}
}
/**
* \brief Disable/Enable broadcast receiving.
*
* \param p_emac Pointer to the EMAC instance.
* \param uc_enable 1 to disable the broadcast, else to enable it.
*/
static inline void emac_disable_broadcast(Emac* p_emac, uint8_t uc_enable)
{
if (uc_enable) {
p_emac->EMAC_NCFGR |= EMAC_NCFGR_NBC;
} else {
p_emac->EMAC_NCFGR &= ~EMAC_NCFGR_NBC;
}
}
/**
* \brief Enable/Disable multicast hash.
*
* \param p_emac Pointer to the EMAC instance.
* \param uc_enable 0 to disable the multicast hash, else to enable it.
*/
static inline void emac_enable_multicast_hash(Emac* p_emac, uint8_t uc_enable)
{
if (uc_enable) {
p_emac->EMAC_NCFGR |= EMAC_NCFGR_UNI;
} else {
p_emac->EMAC_NCFGR &= ~EMAC_NCFGR_UNI;
}
}
/**
* \brief Enable/Disable big frames (over 1518, up to 1536).
*
* \param p_emac Pointer to the EMAC instance.
* \param uc_enable 0 to disable big frames else to enable it.
*/
static inline void emac_enable_big_frame(Emac* p_emac, uint8_t uc_enable)
{
if (uc_enable) {
p_emac->EMAC_NCFGR |= EMAC_NCFGR_BIG;
} else {
p_emac->EMAC_NCFGR &= ~EMAC_NCFGR_BIG;
}
}
/**
* \brief Set MDC clock divider.
*
* \param p_emac Pointer to the EMAC instance.
* \param ul_mck EMAC MCK.
*
* \return EMAC_OK if successfully.
*/
static inline uint8_t emac_set_clock(Emac* p_emac, uint32_t ul_mck)
{
uint32_t ul_clk;
if (ul_mck > EMAC_CLOCK_SPEED_160MHZ) {
return EMAC_INVALID;
} else if (ul_mck > EMAC_CLOCK_SPEED_80MHZ) {
ul_clk = EMAC_NCFGR_CLK_MCK_64;
} else if (ul_mck > EMAC_CLOCK_SPEED_40MHZ) {
ul_clk = EMAC_NCFGR_CLK_MCK_32;
} else if (ul_mck > EMAC_CLOCK_SPEED_20MHZ) {
ul_clk = EMAC_NCFGR_CLK_MCK_16;
} else {
ul_clk = EMAC_NCFGR_CLK_MCK_8;
}
p_emac->EMAC_NCFGR &= ~EMAC_NCFGR_CLK_Msk;
p_emac->EMAC_NCFGR |= ul_clk;
return EMAC_OK;
}
/**
* \brief Enable/Disable retry test.
*
* \param p_emac Pointer to the EMAC instance.
* \param uc_enable 0 to disable the EMAC receiver, else to enable it.
*/
static inline void emac_enable_retry_test(Emac* p_emac, uint8_t uc_enable)
{
if (uc_enable) {
p_emac->EMAC_NCFGR |= EMAC_NCFGR_RTY;
} else {
p_emac->EMAC_NCFGR &= ~EMAC_NCFGR_RTY;
}
}
/**
* \brief Enable/Disable pause (when a valid pause frame is received).
*
* \param p_emac Pointer to the EMAC instance.
* \param uc_enable 0 to disable pause frame, else to enable it.
*/
static inline void emac_enable_pause_frame(Emac* p_emac, uint8_t uc_enable)
{
if (uc_enable) {
p_emac->EMAC_NCFGR |= EMAC_NCFGR_PAE;
} else {
p_emac->EMAC_NCFGR &= ~EMAC_NCFGR_PAE;
}
}
/**
* \brief Set receive buffer offset to 0 ~ 3.
*
* \param p_emac Pointer to the EMAC instance.
*/
static inline void emac_set_rx_buffer_offset(Emac* p_emac, uint8_t uc_offset)
{
p_emac->EMAC_NCFGR &= ~EMAC_NCFGR_RBOF_Msk;
p_emac->EMAC_NCFGR |=
(EMAC_NCFGR_RBOF_Msk & ((uc_offset) << EMAC_NCFGR_RBOF_Pos));
}
/**
* \brief Enable/Disable receive length field checking.
*
* \param p_emac Pointer to the EMAC instance.
* \param uc_enable 0 to disable receive length field checking, else to enable it.
*/
static inline void emac_enable_rx_length_check(Emac* p_emac, uint8_t uc_enable)
{
if (uc_enable) {
p_emac->EMAC_NCFGR |= EMAC_NCFGR_RLCE;
} else {
p_emac->EMAC_NCFGR &= ~EMAC_NCFGR_RLCE;
}
}
/**
* \brief Enable/Disable discarding FCS field of received frames.
*
* \param p_emac Pointer to the EMAC instance.
* \param uc_enable 0 to disable discarding FCS field of received frames, else to enable it.
*/
static inline void emac_enable_discard_fcs(Emac* p_emac, uint8_t uc_enable)
{
if (uc_enable) {
p_emac->EMAC_NCFGR |= EMAC_NCFGR_DRFCS;
} else {
p_emac->EMAC_NCFGR &= ~EMAC_NCFGR_DRFCS;
}
}
/**
* \brief Enable/Disable frames to be received in half-duplex mode
* while transmitting.
*
* \param p_emac Pointer to the EMAC instance.
* \param uc_enable 0 to disable the received in half-duplex mode, else to enable it.
*/
static inline void emac_enable_efrhd(Emac* p_emac, uint8_t uc_enable)
{
if (uc_enable) {
p_emac->EMAC_NCFGR |= EMAC_NCFGR_EFRHD;
} else {
p_emac->EMAC_NCFGR &= ~EMAC_NCFGR_EFRHD;
}
}
/**
* \brief Enable/Disable ignore RX FCS.
*
* \param p_emac Pointer to the EMAC instance.
* \param uc_enable 0 to disable ignore RX FCS, else to enable it.
*/
static inline void emac_enable_ignore_rx_fcs(Emac* p_emac, uint8_t uc_enable)
{
if (uc_enable) {
p_emac->EMAC_NCFGR |= EMAC_NCFGR_IRXFCS;
} else {
p_emac->EMAC_NCFGR &= ~EMAC_NCFGR_IRXFCS;
}
}
/**
* \brief Get Network Status.
*
* \param p_emac Pointer to the EMAC instance.
*
* \return Network status.
*/
static inline uint32_t emac_get_status(Emac* p_emac)
{
return p_emac->EMAC_NSR;
}
/**
* \brief Get MDIO IN pin status.
*
* \param p_emac Pointer to the EMAC instance.
*
* \return MDIO IN pin status.
*/
static inline uint8_t emac_get_MDIO(Emac* p_emac)
{
return ((p_emac->EMAC_NSR & EMAC_NSR_MDIO) > 0);
}
/**
* \brief Check if PHY is idle.
*
* \param p_emac Pointer to the EMAC instance.
*
* \return 1 if PHY is idle.
*/
static inline uint8_t emac_is_phy_idle(Emac* p_emac)
{
return ((p_emac->EMAC_NSR & EMAC_NSR_IDLE) > 0);
}
/**
* \brief Return transmit status.
*
* \param p_emac Pointer to the EMAC instance.
*
* \return Transmit status.
*/
static inline uint32_t emac_get_tx_status(Emac* p_emac)
{
return p_emac->EMAC_TSR;
}
/**
* \brief Clear transmit status.
*
* \param p_emac Pointer to the EMAC instance.
* \param ul_status Transmit status.
*/
static inline void emac_clear_tx_status(Emac* p_emac, uint32_t ul_status)
{
p_emac->EMAC_TSR = ul_status;
}
/**
* \brief Return receive status.
*
* \param p_emac Pointer to the EMAC instance.
*/
static inline uint32_t emac_get_rx_status(Emac* p_emac)
{
return p_emac->EMAC_RSR;
}
/**
* \brief Clear receive status.
*
* \param p_emac Pointer to the EMAC instance.
* \param ul_status Receive status.
*/
static inline void emac_clear_rx_status(Emac* p_emac, uint32_t ul_status)
{
p_emac->EMAC_RSR = ul_status;
}
/**
* \brief Set Rx Queue.
*
* \param p_emac Pointer to the EMAC instance.
* \param ul_addr Rx queue address.
*/
static inline void emac_set_rx_queue(Emac* p_emac, uint32_t ul_addr)
{
p_emac->EMAC_RBQP = EMAC_RBQP_ADDR_Msk & ul_addr;
}
/**
* \brief Get Rx Queue Address.
*
* \param p_emac Pointer to the EMAC instance.
*
* \return Rx queue address.
*/
static inline uint32_t emac_get_rx_queue(Emac* p_emac)
{
return p_emac->EMAC_RBQP;
}
/**
* \brief Set Tx Queue.
*
* \param p_emac Pointer to the EMAC instance.
* \param ul_addr Tx queue address.
*/
static inline void emac_set_tx_queue(Emac* p_emac, uint32_t ul_addr)
{
p_emac->EMAC_TBQP = EMAC_TBQP_ADDR_Msk & ul_addr;
}
/**
* \brief Get Tx Queue.
*
* \param p_emac Pointer to the EMAC instance.
*
* \return Rx queue address.
*/
static inline uint32_t emac_get_tx_queue(Emac* p_emac)
{
return p_emac->EMAC_TBQP;
}
/**
* \brief Enable interrupt(s).
*
* \param p_emac Pointer to the EMAC instance.
* \param ul_source Interrupt source(s) to be enabled.
*/
static inline void emac_enable_interrupt(Emac* p_emac, uint32_t ul_source)
{
p_emac->EMAC_IER = ul_source;
}
/**
* \brief Disable interrupt(s).
*
* \param p_emac Pointer to the EMAC instance.
* \param ul_source Interrupt source(s) to be disabled.
*/
static inline void emac_disable_interrupt(Emac* p_emac, uint32_t ul_source)
{
p_emac->EMAC_IDR = ul_source;
}
/**
* \brief Return interrupt status.
*
* \param p_emac Pointer to the EMAC instance.
*
* \return Interrupt status.
*/
static inline uint32_t emac_get_interrupt_status(Emac* p_emac)
{
return p_emac->EMAC_ISR;
}
/**
* \brief Return interrupt mask.
*
* \param p_emac Pointer to the EMAC instance.
*
* \return Interrupt mask.
*/
static inline uint32_t emac_get_interrupt_mask(Emac* p_emac)
{
return p_emac->EMAC_IMR;
}
/**
* \brief Execute PHY maintenance command.
*
* \param p_emac Pointer to the EMAC instance.
* \param uc_phy_addr PHY address.
* \param uc_reg_addr Register address.
* \param uc_rw 1 to Read, 0 to write.
* \param us_data Data to be performed, write only.
*/
static inline void emac_maintain_phy(Emac* p_emac,
uint8_t uc_phy_addr, uint8_t uc_reg_addr, uint8_t uc_rw,
uint16_t us_data)
{
/* Wait until bus idle */
while ((p_emac->EMAC_NSR & EMAC_NSR_IDLE) == 0);
/* Write maintain register */
p_emac->EMAC_MAN = EMAC_MAN_CODE(EMAC_MAN_CODE_VALUE)
| EMAC_MAN_SOF(EMAC_MAN_SOF_VALUE)
| EMAC_MAN_PHYA(uc_phy_addr)
| EMAC_MAN_REGA(uc_reg_addr)
| EMAC_MAN_RW((uc_rw ? EMAC_MAN_RW_TYPE : EMAC_MAN_READ_ONLY))
| EMAC_MAN_DATA(us_data);
}
/**
* \brief Get PHY maintenance data returned.
*
* \param p_emac Pointer to the EMAC instance.
*
* \return Get PHY data.
*/
static inline uint16_t emac_get_phy_data(Emac* p_emac)
{
/* Wait until bus idle */
while ((p_emac->EMAC_NSR & EMAC_NSR_IDLE) == 0);
/* Return data */
return (uint16_t) (p_emac->EMAC_MAN & EMAC_MAN_DATA_Msk);
}
/**
* \brief Set pause time.
*
* \param p_emac Pointer to the EMAC instance.
* \param us_pause_time Pause time.
*/
static inline void emac_set_pause_time(Emac* p_emac, uint16_t us_pause_time)
{
p_emac->EMAC_PTR = us_pause_time;
}
/**
* \brief Set Hash.
*
* \param p_emac Pointer to the EMAC instance.
* \param ul_hash_top Hash top.
* \param ul_hash_bottom Hash bottom.
*/
static inline void emac_set_hash(Emac* p_emac, uint32_t ul_hash_top,
uint32_t ul_hash_bottom)
{
p_emac->EMAC_HRB = ul_hash_bottom;
p_emac->EMAC_HRT = ul_hash_top;
}
/**
* \brief Set 64 bits Hash.
*
* \param p_emac Pointer to the EMAC instance.
* \param ull_hash 64 bits hash value.
*/
static inline void emac_set_hash64(Emac* p_emac, uint64_t ull_hash)
{
p_emac->EMAC_HRB = (uint32_t) ull_hash;
p_emac->EMAC_HRT = (uint32_t) (ull_hash >> 32);
}
/**
* \brief Set MAC Address.
*
* \param p_emac Pointer to the EMAC instance.
* \param uc_index EMAC specific address register index.
* \param p_mac_addr EMAC address.
*/
static inline void emac_set_address(Emac* p_emac, uint8_t uc_index,
uint8_t* p_mac_addr)
{
p_emac->EMAC_SA[uc_index].EMAC_SAxB = (p_mac_addr[3] << 24)
| (p_mac_addr[2] << 16)
| (p_mac_addr[1] << 8)
| (p_mac_addr[0]);
p_emac->EMAC_SA[uc_index].EMAC_SAxT = (p_mac_addr[5] << 8)
| (p_mac_addr[4]);
}
/**
* \brief Set MAC Address via 2 dword.
*
* \param p_emac Pointer to the EMAC instance.
* \param uc_index EMAC specific address register index.
* \param ul_mac_top EMAC top address.
* \param ul_mac_bottom EMAC bottom address.
*/
static inline void emac_set_address32(Emac* p_emac, uint8_t uc_index,
uint32_t ul_mac_top, uint32_t ul_mac_bottom)
{
p_emac->EMAC_SA[uc_index].EMAC_SAxB = ul_mac_bottom;
p_emac->EMAC_SA[uc_index].EMAC_SAxT = ul_mac_top;
}
/**
* \brief Set MAC Address via int64.
*
* \param p_emac Pointer to the EMAC instance.
* \param uc_index EMAC specific address register index.
* \param ull_mac 64-bit EMAC address.
*/
static inline void emac_set_address64(Emac* p_emac, uint8_t uc_index,
uint64_t ull_mac)
{
p_emac->EMAC_SA[uc_index].EMAC_SAxB = (uint32_t) ull_mac;
p_emac->EMAC_SA[uc_index].EMAC_SAxT = (uint32_t) (ull_mac >> 32);
}
/**
* \brief Set type ID.
*
* \param p_emac Pointer to the EMAC instance.
* \param us_type_id Type to be set.
*/
static inline void emac_set_type_id(Emac* p_emac, uint16_t us_type_id)
{
p_emac->EMAC_TID = EMAC_TID_TID(us_type_id);
}
/**
* \brief Get type ID.
*
* \param p_emac Pointer to the EMAC instance.
*
* \return Type ID.
*/
static inline uint16_t emac_get_type_id(Emac* p_emac)
{
return (p_emac->EMAC_TID & EMAC_TID_TID_Msk);
}
/**
* \brief Enable/Disable RMII.
*
* \param p_emac Pointer to the EMAC instance.
* \param uc_enable 0 to disable the RMII mode, else to enable it.
*/
static inline void emac_enable_rmii(Emac* p_emac, uint8_t uc_enable)
{
if (uc_enable) {
p_emac->EMAC_USRIO |= EMAC_USRIO_RMII;
} else {
p_emac->EMAC_USRIO &= ~EMAC_USRIO_RMII;
}
}
/**
* \brief Enable/Disable transceiver input clock.
*
* \param p_emac Pointer to the EMAC instance.
* \param uc_enable 0 to disable transceiver input clock, else to enable it.
*/
static inline void emac_enable_transceiver_clock(Emac* p_emac,
uint8_t uc_enable)
{
if (uc_enable) {
p_emac->EMAC_USRIO |= EMAC_USRIO_CLKEN;
} else {
p_emac->EMAC_USRIO &= ~EMAC_USRIO_CLKEN;
}
}
uint8_t emac_phy_read(Emac* p_emac, uint8_t uc_phy_address, uint8_t uc_address,
uint32_t* p_value);
uint8_t emac_phy_write(Emac* p_emac, uint8_t uc_phy_address,
uint8_t uc_address, uint32_t ul_value);
void emac_dev_init(Emac* p_emac, emac_device_t* p_emac_dev,
emac_options_t* p_opt);
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);
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);
uint32_t emac_dev_get_tx_load(emac_device_t* p_emac_dev);
void emac_dev_set_rx_callback(emac_device_t* p_emac_dev,
emac_dev_tx_cb_t func_rx_cb);
uint8_t emac_dev_set_tx_wakeup_callback(emac_device_t* p_emac_dev,
emac_dev_wakeup_cb_t func_wakeup, uint8_t uc_threshold);
void emac_dev_reset(emac_device_t* p_emac_dev);
void emac_handler(emac_device_t* p_emac_dev);
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
}
#endif
/**INDENT-ON**/
/// @endcond
/**
* \page emac_quickstart Quickstart guide for EMAC driver.
*
* This is the quickstart guide for the \ref emac_group "Ethernet MAC",
* with step-by-step instructions on how to configure and use the driver 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 emac_basic_use_case Basic use case
* In the basic use case, the EMAC driver are configured for:
* - PHY component DM9161A is used
* - EMAC uses RMII mode
* - The number of receive buffer is 16
* - The number of transfer buffer is 8
* - MAC address is set to 00-04-25-1c-a0-02
* - IP address is set to 192.168.0.2
* - IP address is set to 192.168.0.2
* - Gateway is set to 192.168.0.1
* - Network mask is 255.255.255.0
* - PHY operation max retry count is 1000000
* - EMAC is configured to not support copy all frame and support broadcast
* - The reset PIN of DM9161A is connected to the NRST of SAM3X
* - The data will be read from the ethernet
*
* \section emac_basic_use_case_setup Setup steps
*
* \subsection emac_basic_use_case_setup_prereq Prerequisites
* -# \ref sysclk_group "System Clock Management (sysclock)"
* -# \ref pio_group "Parallel Input/Output Controller (pio)"
* -# \ref pmc_group "Power Management Controller (pmc)"
* -# \ref sam_drivers_rstc_group "Reset Controller (RSTC)"
* -# \ref dm9161a_ethernet_phy_group "PHY component (DM9161A)"
*
* \subsection emac_basic_use_case_setup_code Example code
* Content of conf_eth.h
* \code
* #define EMAC_RX_BUFFERS 16
* #define EMAC_TX_BUFFERS 8
* #define MAC_PHY_RETRY_MAX 1000000
* #define ETHERNET_CONF_ETHADDR0 0x00
* #define ETHERNET_CONF_ETHADDR0 0x00
* #define ETHERNET_CONF_ETHADDR1 0x04
* #define ETHERNET_CONF_ETHADDR2 0x25
* #define ETHERNET_CONF_ETHADDR3 0x1C
* #define ETHERNET_CONF_ETHADDR4 0xA0
* #define ETHERNET_CONF_ETHADDR5 0x02
* #define ETHERNET_CONF_IPADDR0 192
* #define ETHERNET_CONF_IPADDR1 168
* #define ETHERNET_CONF_IPADDR2 0
* #define ETHERNET_CONF_IPADDR3 2
* #define ETHERNET_CONF_GATEWAY_ADDR0 192
* #define ETHERNET_CONF_GATEWAY_ADDR1 168
* #define ETHERNET_CONF_GATEWAY_ADDR2 0
* #define ETHERNET_CONF_GATEWAY_ADDR3 1
* #define ETHERNET_CONF_NET_MASK0 255
* #define ETHERNET_CONF_NET_MASK1 255
* #define ETHERNET_CONF_NET_MASK2 255
* #define ETHERNET_CONF_NET_MASK3 0
* #define ETH_PHY_MODE BOARD_EMAC_MODE_RMII
* \endcode
*
* A specific emac device and the receive data buffer must be defined; another ul_frm_size should be defined
* to trace the actual size of the data received.
* \code
* static emac_device_t gs_emac_dev;
* static volatile uint8_t gs_uc_eth_buffer[EMAC_FRAME_LENTGH_MAX];
*
* uint32_t ul_frm_size;
* \endcode
*
* Add to application C-file:
* \code
* void emac_init(void)
* {
* sysclk_init();
*
* board_init();
*
* rstc_set_external_reset(RSTC, 13);
* rstc_reset_extern(RSTC);
* while (rstc_get_status(RSTC) & RSTC_SR_NRSTL) {
* };
*
* ul_delay = sysclk_get_cpu_hz() / 1000 / 3 * 400;
* while (ul_delay--);
*
* pmc_enable_periph_clk(ID_EMAC);
*
* emac_option.uc_copy_all_frame = 0;
* emac_option.uc_no_boardcast = 0;
* memcpy(emac_option.uc_mac_addr, gs_uc_mac_address, sizeof(gs_uc_mac_address));
* gs_emac_dev.p_hw = EMAC;
*
* emac_dev_init(EMAC, &gs_emac_dev, &emac_option);
*
* NVIC_EnableIRQ(EMAC_IRQn);
*
* ethernet_phy_init(EMAC, BOARD_EMAC_PHY_ADDR, sysclk_get_cpu_hz()
*
* ethernet_phy_auto_negotiate(EMAC, BOARD_EMAC_PHY_ADDR
*
* ethernet_phy_set_link(EMAC, BOARD_EMAC_PHY_ADDR, 1)
* \endcode
*
* \subsection emac_basic_use_case_setup_flow Workflow
* -# Ensure that conf_emac.h is present and contains the
* following configuration symbol. This configuration file is used
* by the driver and should not be included by the user.
* - \code
* #define EMAC_RX_BUFFERS 16
* #define EMAC_TX_BUFFERS 8
* #define MAC_PHY_RETRY_MAX 1000000
* #define ETHERNET_CONF_ETHADDR0 0x00
* #define ETHERNET_CONF_ETHADDR0 0x00
* #define ETHERNET_CONF_ETHADDR1 0x04
* #define ETHERNET_CONF_ETHADDR2 0x25
* #define ETHERNET_CONF_ETHADDR3 0x1C
* #define ETHERNET_CONF_ETHADDR4 0xA0
* #define ETHERNET_CONF_ETHADDR5 0x02
* #define ETHERNET_CONF_IPADDR0 192
* #define ETHERNET_CONF_IPADDR1 168
* #define ETHERNET_CONF_IPADDR2 0
* #define ETHERNET_CONF_IPADDR3 2
* #define ETHERNET_CONF_GATEWAY_ADDR0 192
* #define ETHERNET_CONF_GATEWAY_ADDR1 168
* #define ETHERNET_CONF_GATEWAY_ADDR2 0
* #define ETHERNET_CONF_GATEWAY_ADDR3 1
* #define ETHERNET_CONF_NET_MASK0 255
* #define ETHERNET_CONF_NET_MASK1 255
* #define ETHERNET_CONF_NET_MASK2 255
* #define ETHERNET_CONF_NET_MASK3 0
* #define ETH_PHY_MODE BOARD_EMAC_MODE_RMII
* \endcode
* -# Enable the system clock:
* - \code sysclk_init(); \endcode
* -# Enable PIO configurations for EMAC:
* - \code board_init(); \endcode
* -# Reset PHY; this is required by the DM9161A component:
* - \code
* rstc_set_external_reset(RSTC, 13);
* rstc_reset_extern(RSTC);
* while (rstc_get_status(RSTC) & RSTC_SR_NRSTL) {
* };
* \endcode
* -# Wait for PHY ready:
* - \code
* ul_delay = sysclk_get_cpu_hz() / 1000 / 3 * 400;
* while (ul_delay--);
* \endcode
* -# Enable PMC clock for EMAC:
* - \code pmc_enable_periph_clk(ID_EMAC); \endcode
* -# Set the EMAC options; it's set to copy all frame and support broadcast:
* - \code
* emac_option.uc_copy_all_frame = 0;
* emac_option.uc_no_boardcast = 0;
* memcpy(emac_option.uc_mac_addr, gs_uc_mac_address, sizeof(gs_uc_mac_address));
* gs_emac_dev.p_hw = EMAC;
* \endcode
* -# Initialize EMAC device with the filled option:
* - \code
* emac_dev_init(EMAC, &gs_emac_dev, &emac_option);
* \endcode
* -# Enable the interrupt service for EMAC:
* - \code
* NVIC_EnableIRQ(EMAC_IRQn);
* \endcode
* -# Initialize the PHY component:
* - \code
* ethernet_phy_init(EMAC, BOARD_EMAC_PHY_ADDR, sysclk_get_cpu_hz());
* \endcode
* -# The link will be established based on auto negotiation.
* - \code
* ethernet_phy_auto_negotiate(EMAC, BOARD_EMAC_PHY_ADDR);
* \endcode
* -# Establish the ethernet link; the network can be worked from now on:
* - \code
* ethernet_phy_set_link(EMAC, BOARD_EMAC_PHY_ADDR, 1);
* \endcode
*
* \section emac_basic_use_case_usage Usage steps
* \subsection emac_basic_use_case_usage_code Example code
* Add to, e.g., main loop in application C-file:
* \code
* emac_dev_read(&gs_emac_dev, (uint8_t *) gs_uc_eth_buffer, sizeof(gs_uc_eth_buffer), &ul_frm_size));
* \endcode
*
* \subsection emac_basic_use_case_usage_flow Workflow
* -# Start reading the data from the ethernet:
* - \code emac_dev_read(&gs_emac_dev, (uint8_t *) gs_uc_eth_buffer, sizeof(gs_uc_eth_buffer), &ul_frm_size)); \endcode
*/
#endif /* EMAC_H_INCLUDED */

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