diff --git a/system/CMSIS/Device/ATMEL/sam.h b/system/CMSIS/Device/ATMEL/sam.h index 97394e0..2c10bba 100644 --- a/system/CMSIS/Device/ATMEL/sam.h +++ b/system/CMSIS/Device/ATMEL/sam.h @@ -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 * ---------------------------------------------------------------------------- */ diff --git a/system/libsam/build_gcc/Makefile b/system/libsam/build_gcc/Makefile index 63a1243..a04d3ca 100644 --- a/system/libsam/build_gcc/Makefile +++ b/system/libsam/build_gcc/Makefile @@ -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 $@ diff --git a/system/libsam/chip.h b/system/libsam/chip.h index 0d90c7f..298e485 100644 --- a/system/libsam/chip.h +++ b/system/libsam/chip.h @@ -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_ */ diff --git a/system/libsam/include/can.h b/system/libsam/include/can.h new file mode 100644 index 0000000..66d4c1a --- /dev/null +++ b/system/libsam/include/can.h @@ -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 */ diff --git a/system/libsam/include/efc.h b/system/libsam/include/efc.h new file mode 100644 index 0000000..07f78bb --- /dev/null +++ b/system/libsam/include/efc.h @@ -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 */ diff --git a/system/libsam/include/emac.h b/system/libsam/include/emac.h new file mode 100644 index 0000000..cdcd03d --- /dev/null +++ b/system/libsam/include/emac.h @@ -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 */ diff --git a/system/libsam/include/gpbr.h b/system/libsam/include/gpbr.h new file mode 100644 index 0000000..531af5d --- /dev/null +++ b/system/libsam/include/gpbr.h @@ -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 */ diff --git a/system/libsam/include/ssc.h b/system/libsam/include/ssc.h new file mode 100644 index 0000000..4af8091 --- /dev/null +++ b/system/libsam/include/ssc.h @@ -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 */ diff --git a/system/libsam/include/trng.h b/system/libsam/include/trng.h new file mode 100644 index 0000000..3b5f0dc --- /dev/null +++ b/system/libsam/include/trng.h @@ -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 */ diff --git a/system/libsam/source/adc12_sam3u.c b/system/libsam/source/adc12_sam3u.c index 64e3923..77def4d 100644 --- a/system/libsam/source/adc12_sam3u.c +++ b/system/libsam/source/adc12_sam3u.c @@ -386,7 +386,7 @@ Pdc *adc12b_get_pdc_base(const Adc12b *p_adc) { return PDC_ADC12B; } -#endif +#endif // SAM3U_SERIES //@} diff --git a/system/libsam/source/can.c b/system/libsam/source/can.c new file mode 100644 index 0000000..b31562d --- /dev/null +++ b/system/libsam/source/can.c @@ -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 diff --git a/system/libsam/source/dacc.c b/system/libsam/source/dacc.c index aa8f9fe..0637909 100644 --- a/system/libsam/source/dacc.c +++ b/system/libsam/source/dacc.c @@ -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 diff --git a/system/libsam/source/efc.c b/system/libsam/source/efc.c new file mode 100644 index 0000000..364926f --- /dev/null +++ b/system/libsam/source/efc.c @@ -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 + +/// @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 diff --git a/system/libsam/source/emac.c.disabled b/system/libsam/source/emac.c.disabled new file mode 100644 index 0000000..dfaa36d --- /dev/null +++ b/system/libsam/source/emac.c.disabled @@ -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 + +/// @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 diff --git a/system/libsam/source/gpbr.c b/system/libsam/source/gpbr.c new file mode 100644 index 0000000..83d34eb --- /dev/null +++ b/system/libsam/source/gpbr.c @@ -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 diff --git a/system/libsam/source/ssc.c b/system/libsam/source/ssc.c new file mode 100644 index 0000000..ca18a69 --- /dev/null +++ b/system/libsam/source/ssc.c @@ -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 +#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 diff --git a/system/libsam/source/trng.c b/system/libsam/source/trng.c new file mode 100644 index 0000000..747f73d --- /dev/null +++ b/system/libsam/source/trng.c @@ -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 + +/** + * \} + */ diff --git a/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a b/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a index 390d253..62572a4 100644 Binary files a/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a and b/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a differ diff --git a/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a.txt b/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a.txt index 600f004..d2adba7 100644 --- a/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a.txt +++ b/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a.txt @@ -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