From fa85c6f74dd622cfe6c42408bc6fb69490c41ef2 Mon Sep 17 00:00:00 2001 From: vimalrajr Date: Tue, 16 Jun 2015 15:04:40 +0530 Subject: [PATCH] Adding untested code for SPI support in SAM21 --- .../SAMR21_XPLAINED_PRO/mbed_overrides.c | 4 +- .../TARGET_SAM21/TARGET_SAMR21G18A/device.h | 3 +- .../spi/quick_start_dma/qs_spi_dma_use.h | 240 --- .../quick_start_master/qs_spi_master_basic.h | 133 -- .../quick_start_slave/qs_spi_slave_basic.h | 123 -- .../TARGET_SAM21/drivers/sercom/spi/spi.c | 1242 ------------ .../TARGET_SAM21/drivers/sercom/spi/spi.h | 1763 ----------------- .../hal/TARGET_Atmel/TARGET_SAM21/objects.h | 13 +- .../hal/TARGET_Atmel/TARGET_SAM21/spi_api.c | 772 ++++++++ .../hal/TARGET_Atmel/TARGET_SAM21/us_ticker.c | 24 +- 10 files changed, 806 insertions(+), 3511 deletions(-) delete mode 100644 libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/drivers/sercom/spi/quick_start_dma/qs_spi_dma_use.h delete mode 100644 libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/drivers/sercom/spi/quick_start_master/qs_spi_master_basic.h delete mode 100644 libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/drivers/sercom/spi/quick_start_slave/qs_spi_slave_basic.h delete mode 100644 libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/drivers/sercom/spi/spi.c delete mode 100644 libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/drivers/sercom/spi/spi.h create mode 100644 libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/spi_api.c diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/TARGET_SAMR21G18A/SAMR21_XPLAINED_PRO/mbed_overrides.c b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/TARGET_SAMR21G18A/SAMR21_XPLAINED_PRO/mbed_overrides.c index 074e99efea..9b9f384ae6 100644 --- a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/TARGET_SAMR21G18A/SAMR21_XPLAINED_PRO/mbed_overrides.c +++ b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/TARGET_SAMR21G18A/SAMR21_XPLAINED_PRO/mbed_overrides.c @@ -16,11 +16,13 @@ #include "mbed_assert.h" #include "compiler.h" +#include "system.h" + //called before main - implement here if board needs it ortherwise, let // the application override this if necessary //TODO: To be implemented by adding system init and board init void mbed_sdk_init() { - + system_init(); } /***************************************************************/ diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/TARGET_SAMR21G18A/device.h b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/TARGET_SAMR21G18A/device.h index cdbedf818a..a9f626e0d8 100644 --- a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/TARGET_SAMR21G18A/device.h +++ b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/TARGET_SAMR21G18A/device.h @@ -31,8 +31,9 @@ #define DEVICE_I2C 0 #define DEVICE_I2CSLAVE 0 -#define DEVICE_SPI 0 +#define DEVICE_SPI 1 #define DEVICE_SPISLAVE 0 +#define DEVICE_SPI_ASYNCH 1 #define DEVICE_CAN 0 diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/drivers/sercom/spi/quick_start_dma/qs_spi_dma_use.h b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/drivers/sercom/spi/quick_start_dma/qs_spi_dma_use.h deleted file mode 100644 index 06a5061ef2..0000000000 --- a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/drivers/sercom/spi/quick_start_dma/qs_spi_dma_use.h +++ /dev/null @@ -1,240 +0,0 @@ -/** - * \file - * - * \brief SAM D21/R21/L21 Quick Start Guide for Using SPI driver with DMA - * - * Copyright (C) 2014 Atmel Corporation. All rights reserved. - * - * \asf_license_start - * - * \page License - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. The name of Atmel may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * 4. This software may only be redistributed and used in connection with an - * Atmel microcontroller product. - * - * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * \asf_license_stop - * - */ - -/** - * \page asfdoc_sam0_sercom_spi_dma_use_case Quick Start Guide for Using DMA with SERCOM SPI - * - * The supported board list: - * - SAMD21 Xplained Pro - * - SAMR21 Xplained Pro - * - SAML21 Xplained Pro - * - * This quick start will transmit a buffer data from master to slave through DMA. - * In this use case the SPI master will be configured with the following - * settings on SAM Xplained Pro: - * - Master Mode enabled - * - MSB of the data is transmitted first - * - Transfer mode 0 - * - 8-bit character size - * - Not enabled in sleep mode - * - Baudrate 100000 - * - GLCK generator 0 - * - * The SPI slave will be configured with the following settings: - * - Slave mode enabled - * - Preloading of shift register enabled - * - MSB of the data is transmitted first - * - Transfer mode 0 - * - 8-bit character size - * - Not enabled in sleep mode - * - GLCK generator 0 - * - * Note that the pinouts on other boards may different, see next sector for - * details. - * - * \section asfdoc_sam0_sercom_spi_dma_use_case_setup Setup - * - * \subsection asfdoc_sam0_sercom_spi_dma_use_case_prereq Prerequisites - * The following connections has to be made using wires: - * - SAM D21 Xplained Pro. - * - \b SS_0: EXT1 PIN15 (PA05) <--> EXT2 PIN15 (PA17) - * - \b DO/DI: EXT1 PIN16 (PA06) <--> EXT2 PIN17 (PA16) - * - \b DI/DO: EXT1 PIN17 (PA04) <--> EXT2 PIN16 (PA18) - * - \b SCK: EXT1 PIN18 (PA07) <--> EXT2 PIN18 (PA19) - * - SAM R21 Xplained Pro. - * - \b SS_0: EXT1 PIN15 (PB03) <--> EXT1 PIN10 (PA23) - * - \b DO/DI: EXT1 PIN16 (PB22) <--> EXT1 PIN9 (PA22) - * - \b DI/DO: EXT1 PIN17 (PB02) <--> EXT1 PIN7 (PA18) - * - \b SCK: EXT1 PIN18 (PB23) <--> EXT1 PIN8 (PA19) - * - SAM L21 Xplained Pro. - * - \b SS_0: EXT1 PIN15 (PA05) <--> EXT1 PIN12 (PA09) - * - \b DO/DI: EXT1 PIN16 (PA06) <--> EXT1 PIN11 (PA08) - * - \b DI/DO: EXT1 PIN17 (PA04) <--> EXT2 PIN03 (PA10) - * - \b SCK: EXT1 PIN18 (PA07) <--> EXT2 PIN04 (PA11) - * - * \subsection asfdoc_sam0_spi_dma_use_case_setup_code Code - * - * Add to the main application source file, before user definitions and - * functions according to your board: - * - * For SAMD21 Xplained Pro: - * \snippet samd21_xplained_pro/conf_quick_start.h definition_master - * \snippet samd21_xplained_pro/conf_quick_start.h definition_slave - * \snippet samd21_xplained_pro/conf_quick_start.h definition_peripheral_trigger - * For SAMR21 Xplained Pro: - * \snippet samr21_xplained_pro/conf_quick_start.h definition_master - * \snippet samr21_xplained_pro/conf_quick_start.h definition_slave - * \snippet samr21_xplained_pro/conf_quick_start.h definition_peripheral_trigger - * For SAML21 Xplained Pro: - * \snippet saml21_xplained_pro/conf_quick_start.h definition_master - * \snippet saml21_xplained_pro/conf_quick_start.h definition_slave - * \snippet saml21_xplained_pro/conf_quick_start.h definition_peripheral_trigger - - * Add to the main application source file, outside of any functions: - * \snippet qs_spi_dma_use.c buf_length - * \snippet qs_spi_dma_use.c spi_baudrate - * \snippet qs_spi_dma_use.c slave_select_pin - * \snippet qs_spi_dma_use.c spi_buffer - * \snippet qs_spi_dma_use.c spi_module_inst - * \snippet qs_spi_dma_use.c dma_transfer_done_flag - * \snippet qs_spi_dma_use.c slave_dev_inst - * \snippet qs_spi_dma_use.c dma_transfer_descriptor - * - * Copy-paste the following setup code to your user application: - * \snippet qs_spi_dma_use.c setup - * - * Add to user application initialization (typically the start of \c main()): - * \snippet qs_spi_dma_use.c setup_init - * - * \subsection asfdoc_sam0_spi_dma_use_case_setup_flow Workflow - * -# Create a module software instance structure for the SPI module to store - * the SPI driver state while it is in use. - * \snippet qs_spi_dma_use.c spi_module_inst - * \note This should never go out of scope as long as the module is in use. - * In most cases, this should be global. - * - * -# Create a module software instance structure for DMA resource to store - * the DMA resource state while it is in use. - * \snippet qs_spi_dma_use.c dma_resource - * \note This should never go out of scope as long as the module is in use. - * In most cases, this should be global. - * - * -# Create transfer done flag to indication DMA transfer done. - * \snippet qs_spi_dma_use.c dma_transfer_done_flag - * -# Define the buffer length for TX/RX. - * \snippet qs_spi_dma_use.c buf_length - * -# Create buffer to store the data to be transferred. - * \snippet qs_spi_dma_use.c spi_buffer - * -# Create SPI module configuration struct, which can be filled out to - * adjust the configuration of a physical SPI peripheral. - * \snippet qs_spi_dma_use.c spi_master_config - * \snippet qs_spi_dma_use.c spi_slave_config - * -# Initialize the SPI configuration struct with the module's default values. - * \snippet qs_spi_dma_use.c spi_master_conf_defaults - * \snippet qs_spi_dma_use.c spi_slave_conf_defaults - * \note This should always be performed before using the configuration - * struct to ensure that all values are initialized to known default - * settings. - * - * -# Alter the SPI settings to configure the physical pinout, baudrate and - * other relevant parameters. - * \snippet qs_spi_dma_use.c spi_master_mux_setting - * \snippet qs_spi_dma_use.c spi_slave_mux_setting - * -# Configure the SPI module with the desired settings, retrying while the - * driver is busy until the configuration is stressfully set. - * \snippet qs_spi_dma_use.c spi_master_init - * \snippet qs_spi_dma_use.c spi_slave_init - * -# Enable the SPI module. - * \snippet qs_spi_dma_use.c spi_master_enable - * \snippet qs_spi_dma_use.c spi_slave_enable - * - * -# Create DMA resource configuration structure, which can be filled out to - * adjust the configuration of a single DMA transfer. - * \snippet qs_spi_dma_use.c dma_tx_setup_1 - * \snippet qs_spi_dma_use.c dma_rx_setup_1 - * - * -# Initialize the DMA resource configuration struct with the module's - * default values. - * \snippet qs_spi_dma_use.c dma_tx_setup_2 - * \snippet qs_spi_dma_use.c dma_rx_setup_2 - * \note This should always be performed before using the configuration - * struct to ensure that all values are initialized to known default - * settings. - * - * -# Set extra configurations for the DMA resource. It is using peripheral - * trigger. SERCOM TX empty and RX complete trigger causes a beat transfer in - * this example. - * \snippet qs_spi_dma_use.c dma_tx_setup_3 - * \snippet qs_spi_dma_use.c dma_rx_setup_3 - * - * -# Allocate a DMA resource with the configurations. - * \snippet qs_spi_dma_use.c dma_tx_setup_4 - * \snippet qs_spi_dma_use.c dma_rx_setup_4 - * - * -# Create a DMA transfer descriptor configuration structure, which can be - * filled out to adjust the configuration of a single DMA transfer. - * \snippet qs_spi_dma_use.c dma_tx_setup_5 - * \snippet qs_spi_dma_use.c dma_rx_setup_5 - * - * -# Initialize the DMA transfer descriptor configuration struct with the module's - * default values. - * \snippet qs_spi_dma_use.c dma_tx_setup_6 - * \snippet qs_spi_dma_use.c dma_rx_setup_6 - * \note This should always be performed before using the configuration - * struct to ensure that all values are initialized to known default - * settings. - * - * -# Set the specific parameters for a DMA transfer with transfer size, source - * address, and destination address. - * \snippet qs_spi_dma_use.c dma_tx_setup_7 - * \snippet qs_spi_dma_use.c dma_rx_setup_7 - * - * -# Create the DMA transfer descriptor. - * \snippet qs_spi_dma_use.c dma_tx_setup_8 - * \snippet qs_spi_dma_use.c dma_rx_setup_8 - * - * \section asfdoc_sam0_spi_dma_use_case_main Use Case - * - * \subsection asfdoc_sam0_spi_dma_use_case_main_code Code - * Copy-paste the following code to your user application: - * \snippet qs_spi_dma_use.c main - * - * \subsection asfdoc_sam0_spi_dma_use_case_main_flow Workflow - * -# Select the slave. - * \snippet qs_spi_dma_use.c select_slave - * - * -# Start the transfer job. - * \snippet qs_spi_dma_use.c main_1 - * - * -# Wait for transfer done. - * \snippet qs_spi_dma_use.c main_2 - * - * -# Deselect the slave. - * \snippet qs_spi_dma_use.c deselect_slave - * - * -# Enter endless loop. - * \snippet qs_spi_dma_use.c endless_loop - */ - /** - * Support and FAQ: visit Atmel Support - */ diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/drivers/sercom/spi/quick_start_master/qs_spi_master_basic.h b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/drivers/sercom/spi/quick_start_master/qs_spi_master_basic.h deleted file mode 100644 index d404556dc2..0000000000 --- a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/drivers/sercom/spi/quick_start_master/qs_spi_master_basic.h +++ /dev/null @@ -1,133 +0,0 @@ -/** - * \file - * - * \brief SAM SPI Quick Start - * - * Copyright (C) 2012-2014 Atmel Corporation. All rights reserved. - * - * \asf_license_start - * - * \page License - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. The name of Atmel may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * 4. This software may only be redistributed and used in connection with an - * Atmel microcontroller product. - * - * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * \asf_license_stop - * - */ - -/** - * \page asfdoc_sam0_sercom_spi_master_basic_use Quick Start Guide for SERCOM SPI Master - Polled - * - * In this use case, the SPI on extension header 1 of the Xplained Pro board - * will configured with the following settings: - * - Master Mode enabled - * - MSB of the data is transmitted first - * - Transfer mode 0 - * - 8-bit character size - * - Not enabled in sleep mode - * - Baudrate 100000 - * - GLCK generator 0 - * - * - * \section asfdoc_sam0_sercom_spi_master_basic_use_setup Setup - * - * \subsection asfdoc_sam0_sercom_spi_master_basic_use_prereq Prerequisites - * There are no special setup requirements for this use-case. - * - * \subsection asfdoc_sam0_sercom_spi_master_basic_use_setup_code Code - * The following must be added to the user application: - * - * A sample buffer to send via SPI. - * \snippet qs_spi_master_basic.c buffer - * Number of entries in the sample buffer. - * \snippet qs_spi_master_basic.c buf_length - * GPIO pin to use as Slave Select. - * \snippet qs_spi_master_basic.c slave_select_pin - * A globally available software device instance struct to store the SPI driver - * state while it is in use. - * \snippet qs_spi_master_basic.c dev_inst - * A globally available peripheral slave software device instance struct. - * \snippet qs_spi_master_basic.c slave_dev_inst - * A function for configuring the SPI. - * \snippet qs_spi_master_basic.c configure_spi - * - * Add to user application \c main(). - * \snippet qs_spi_master_basic.c main_setup - * - * \section asfdoc_sam0_sercom_spi_master_basic_use_workflow Workflow - * -# Initialize system. - * \snippet qs_spi_master_basic.c system_init - * -# Setup the SPI. - * \snippet qs_spi_master_basic.c run_config - * -# Create configuration struct. - * \snippet qs_spi_master_basic.c config - * -# Create peripheral slave configuration struct. - * \snippet qs_spi_master_basic.c slave_config - * -# Create peripheral slave software device instance struct. - * \snippet qs_spi_master_basic.c slave_dev_inst - * -# Get default peripheral slave configuration. - * \snippet qs_spi_master_basic.c slave_conf_defaults - * -# Set Slave Select pin. - * \snippet qs_spi_master_basic.c ss_pin - * -# Initialize peripheral slave software instance with configuration. - * \snippet qs_spi_master_basic.c slave_init - * -# Get default configuration to edit. - * \snippet qs_spi_master_basic.c conf_defaults - * -# Set MUX setting E. - * \snippet qs_spi_master_basic.c mux_setting - * -# Set pinmux for pad 0 (data in (MISO)). - * \snippet qs_spi_master_basic.c di - * -# Set pinmux for pad 1 as unused, so the pin can be used for other purposes. - * \snippet qs_spi_master_basic.c ss - * -# Set pinmux for pad 2 (data out (MOSI)). - * \snippet qs_spi_master_basic.c do - * -# Set pinmux for pad 3 (SCK). - * \snippet qs_spi_master_basic.c sck - * -# Initialize SPI module with configuration. - * \snippet qs_spi_master_basic.c init - * -# Enable SPI module. - * \snippet qs_spi_master_basic.c enable - * - * \section asfdoc_sam0_sercom_spi_master_basic_use_case Use Case - * \subsection asfdoc_sam0_sercom_spi_master_basic_use_case_code Code - * Add the following to your user application \c main(). - * \snippet qs_spi_master_basic.c main_use_case - * \subsection asfdoc_sam0_sercom_spi_master_basic_use_case_workflow Workflow - * -# Select slave. - * \snippet qs_spi_master_basic.c select_slave - * -# Write buffer to SPI slave. - * \snippet qs_spi_master_basic.c write - * -# Deselect slave. - * \snippet qs_spi_master_basic.c deselect_slave - * -# Infinite loop. - * \snippet qs_spi_master_basic.c inf_loop - */ - /** - * Support and FAQ: visit Atmel Support - */ diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/drivers/sercom/spi/quick_start_slave/qs_spi_slave_basic.h b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/drivers/sercom/spi/quick_start_slave/qs_spi_slave_basic.h deleted file mode 100644 index 7aa6e5183c..0000000000 --- a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/drivers/sercom/spi/quick_start_slave/qs_spi_slave_basic.h +++ /dev/null @@ -1,123 +0,0 @@ -/** - * \file - * - * \brief SAM SPI Quick Start - * - * Copyright (C) 2012-2014 Atmel Corporation. All rights reserved. - * - * \asf_license_start - * - * \page License - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. The name of Atmel may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * 4. This software may only be redistributed and used in connection with an - * Atmel microcontroller product. - * - * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * \asf_license_stop - * - */ - -/** - * \page asfdoc_sam0_sercom_spi_slave_basic_use Quick Start Guide for SERCOM SPI Slave - Polled - * - * In this use case, the SPI on extension header 1 of the Xplained Pro board - * will configured with the following settings: - * - Slave mode enabled - * - Preloading of shift register enabled - * - MSB of the data is transmitted first - * - Transfer mode 0 - * - 8-bit character size - * - Not enabled in sleep mode - * - GLCK generator 0 - * - * - * \section asfdoc_sam0_sercom_spi_slave_basic_use_setup Setup - * - * \subsection asfdoc_sam0_sercom_spi_slave_basic_use_prereq Prerequisites - * The device must be connected to a SPI master which must read from the device. - * - * \subsection asfdoc_sam0_sercom_spi_slave_basic_use_setup_code Code - * The following must be added to the user application source file, outside - * any functions: - * - * A sample buffer to send via SPI. - * \snippet qs_spi_slave_basic.c buffer - * Number of entries in the sample buffer. - * \snippet qs_spi_slave_basic.c buf_length - * A globally available software device instance struct to store the SPI driver - * state while it is in use. - * \snippet qs_spi_slave_basic.c dev_inst - * A function for configuring the SPI. - * \snippet qs_spi_slave_basic.c configure_spi - * - * Add to user application \c main(). - * \snippet qs_spi_slave_basic.c main_start - * - * \subsection asfdoc_sam0_sercom_spi_slave_basic_use_workflow Workflow - * -# Initialize system. - * \snippet qs_spi_slave_basic.c system_init - * -# Setup the SPI. - * \snippet qs_spi_slave_basic.c run_config - * -# Create configuration struct. - * \snippet qs_spi_slave_basic.c config - * -# Get default configuration to edit. - * \snippet qs_spi_slave_basic.c conf_defaults - * -# Set the SPI in slave mode. - * \snippet qs_spi_slave_basic.c conf_spi_slave_instance - * -# Enable preloading of shift register. - * \snippet qs_spi_slave_basic.c conf_preload - * -# Set frame format to SPI frame. - * \snippet qs_spi_slave_basic.c conf_format - * -# Set MUX setting E. - * \snippet qs_spi_slave_basic.c mux_setting - * -# Set pinmux for pad 0 (data in (MOSI)). - * \snippet qs_spi_slave_basic.c di - * -# Set pinmux for pad 1 (slave select). - * \snippet qs_spi_slave_basic.c ss - * -# Set pinmux for pad 2 (data out (MISO)). - * \snippet qs_spi_slave_basic.c do - * -# Set pinmux for pad 3 (SCK). - * \snippet qs_spi_slave_basic.c sck - * -# Initialize SPI module with configuration. - * \snippet qs_spi_slave_basic.c init - * -# Enable SPI module. - * \snippet qs_spi_slave_basic.c enable - * - * \section asfdoc_sam0_sercom_spi_slave_basic_use_case Use Case - * \subsection asfdoc_sam0_sercom_spi_slave_basic_use_case_code Code - * Add the following to your user application \c main(). - * \snippet qs_spi_slave_basic.c main_use_case - * \subsection asfdoc_sam0_sercom_spi_slave_basic_use_case_workflow Workflow - * -# Write buffer to SPI master. Placed in a loop to retry in case of a - * timeout before a master initiates a transaction. - * \snippet qs_spi_slave_basic.c write - * -# Infinite loop. - * \snippet qs_spi_slave_basic.c inf_loop - */ - /** - * Support and FAQ: visit Atmel Support - */ diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/drivers/sercom/spi/spi.c b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/drivers/sercom/spi/spi.c deleted file mode 100644 index 941e243993..0000000000 --- a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/drivers/sercom/spi/spi.c +++ /dev/null @@ -1,1242 +0,0 @@ -/** - * \file - * - * \brief SAM Serial Peripheral Interface Driver - * - * Copyright (C) 2012-2014 Atmel Corporation. All rights reserved. - * - * \asf_license_start - * - * \page License - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. The name of Atmel may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * 4. This software may only be redistributed and used in connection with an - * Atmel microcontroller product. - * - * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * \asf_license_stop - * - */ - /** - * Support and FAQ: visit Atmel Support - */ -#include "spi.h" - -/** - * \brief Resets the SPI module - * - * This function will reset the SPI module to its power on default values and - * disable it. - * - * \param[in,out] module Pointer to the software instance struct - */ -void spi_reset( - struct spi_module *const module) -{ - /* Sanity check arguments */ - Assert(module); - Assert(module->hw); - - SercomSpi *const spi_module = &(module->hw->SPI); - - /* Disable the module */ - spi_disable(module); - - while (spi_is_syncing(module)) { - /* Wait until the synchronization is complete */ - } - - /* Software reset the module */ - spi_module->CTRLA.reg |= SERCOM_SPI_CTRLA_SWRST; -} - -/** - * \brief Set the baudrate of the SPI module - * - * This function will set the baudrate of the SPI module. - * - * \param[in] module Pointer to the software instance struct - * \param[in] baudrate The baudrate wanted - * - * \return The status of the configuration. - * \retval STATUS_ERR_INVALID_ARG If invalid argument(s) were provided - * \retval STATUS_OK If the configuration was written - */ -enum status_code spi_set_baudrate( - struct spi_module *const module, - uint32_t baudrate) -{ - /* Sanity check arguments */ - Assert(module); - Assert(baudrate); - Assert(module->hw); - - /* Value to write to BAUD register */ - uint16_t baud = 0; - - SercomSpi *const spi_module = &(module->hw->SPI); - - /* Disable the module */ - spi_disable(module); - - while (spi_is_syncing(module)) { - /* Wait until the synchronization is complete */ - } - - /* Find frequency of the internal SERCOMi_GCLK_ID_CORE */ - uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw); - uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; - uint32_t internal_clock = system_gclk_chan_get_hz(gclk_index); - - /* Get baud value, based on baudrate and the internal clock frequency */ - enum status_code error_code = _sercom_get_sync_baud_val( - baudrate, internal_clock, &baud); - - if (error_code != STATUS_OK) { - /* Baud rate calculation error, return status code */ - return STATUS_ERR_INVALID_ARG; - } - - spi_module->BAUD.reg = (uint8_t)baud; - - while (spi_is_syncing(module)) { - /* Wait until the synchronization is complete */ - } - - /* Enable the module */ - spi_enable(module); - - while (spi_is_syncing(module)) { - /* Wait until the synchronization is complete */ - } - - return STATUS_OK; -} - -# if CONF_SPI_SLAVE_ENABLE == true -/** - * \internal Clears the Transmit Complete interrupt flag. - * - * \param[in] module Pointer to the software instance struct - */ -static void _spi_clear_tx_complete_flag( - struct spi_module *const module) -{ - /* Sanity check arguments */ - Assert(module); - Assert(module->hw); - - SercomSpi *const spi_module = &(module->hw->SPI); - - /* Clear interrupt flag */ - spi_module->INTFLAG.reg = SPI_INTERRUPT_FLAG_TX_COMPLETE; -} -# endif - -/** - * \internal Writes an SPI SERCOM configuration to the hardware module. - * - * This function will write out a given configuration to the hardware module. - * Can only be done when the module is disabled. - * - * \param[in] module Pointer to the software instance struct - * \param[in] config Pointer to the configuration struct - * - * \return The status of the configuration. - * \retval STATUS_ERR_INVALID_ARG If invalid argument(s) were provided - * \retval STATUS_OK If the configuration was written - */ -static enum status_code _spi_set_config( - struct spi_module *const module, - const struct spi_config *const config) -{ - /* Sanity check arguments */ - Assert(module); - Assert(config); - Assert(module->hw); - - SercomSpi *const spi_module = &(module->hw->SPI); - Sercom *const hw = module->hw; - - struct system_pinmux_config pin_conf; - system_pinmux_get_config_defaults(&pin_conf); - pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; - if(config->mode == SPI_MODE_SLAVE) { - pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE; - } - - uint32_t pad_pinmuxes[] = { - config->pinmux_pad0, config->pinmux_pad1, - config->pinmux_pad2, config->pinmux_pad3 - }; - - /* Configure the SERCOM pins according to the user configuration */ - for (uint8_t pad = 0; pad < 4; pad++) { - uint32_t current_pinmux = pad_pinmuxes[pad]; - - if (current_pinmux == PINMUX_DEFAULT) { - current_pinmux = _sercom_get_default_pad(hw, pad); - } - - if (current_pinmux != PINMUX_UNUSED) { - pin_conf.mux_position = current_pinmux & 0xFFFF; - system_pinmux_pin_set_config(current_pinmux >> 16, &pin_conf); - } - } - - module->mode = config->mode; - module->character_size = config->character_size; - module->receiver_enabled = config->receiver_enable; -# ifdef FEATURE_SPI_HARDWARE_SLAVE_SELECT - module->master_slave_select_enable = config->master_slave_select_enable; -# endif - -# if CONF_SPI_MASTER_ENABLE == true - /* Value to write to BAUD register */ - uint16_t baud = 0; -# endif - /* Value to write to CTRLA register */ - uint32_t ctrla = 0; - /* Value to write to CTRLB register */ - uint32_t ctrlb = 0; - -# if CONF_SPI_MASTER_ENABLE == true - /* Find baud value and write it */ - if (config->mode == SPI_MODE_MASTER) { - /* Find frequency of the internal SERCOMi_GCLK_ID_CORE */ - uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw); - uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; - uint32_t internal_clock = system_gclk_chan_get_hz(gclk_index); - - /* Get baud value, based on baudrate and the internal clock frequency */ - enum status_code error_code = _sercom_get_sync_baud_val( - config->mode_specific.master.baudrate, - internal_clock, &baud); - - if (error_code != STATUS_OK) { - /* Baud rate calculation error, return status code */ - return STATUS_ERR_INVALID_ARG; - } - - spi_module->BAUD.reg = (uint8_t)baud; - } -# endif -# if CONF_SPI_SLAVE_ENABLE == true - if (config->mode == SPI_MODE_SLAVE) { - /* Set frame format */ - ctrla = config->mode_specific.slave.frame_format; - - /* Set address mode */ - ctrlb = config->mode_specific.slave.address_mode; - - /* Set address and address mask*/ - spi_module->ADDR.reg |= - (config->mode_specific.slave.address << SERCOM_SPI_ADDR_ADDR_Pos) | - (config->mode_specific.slave.address_mask << SERCOM_SPI_ADDR_ADDRMASK_Pos); - - if (config->mode_specific.slave.preload_enable) { - /* Enable pre-loading of shift register */ - ctrlb |= SERCOM_SPI_CTRLB_PLOADEN; - } - } -# endif - /* Set data order */ - ctrla |= config->data_order; - - /* Set clock polarity and clock phase */ - ctrla |= config->transfer_mode; - - /* Set MUX setting */ - ctrla |= config->mux_setting; - - /* Set SPI character size */ - ctrlb |= config->character_size; - - /* Set whether module should run in standby. */ - if (config->run_in_standby || system_is_debugger_present()) { - ctrla |= SERCOM_SPI_CTRLA_RUNSTDBY; - } - - if (config->receiver_enable) { - /* Enable receiver */ - ctrlb |= SERCOM_SPI_CTRLB_RXEN; - } -# ifdef FEATURE_SPI_SLAVE_SELECT_LOW_DETECT - if (config->select_slave_low_detect_enable) { - /* Enable Slave Select Low Detect */ - ctrlb |= SERCOM_SPI_CTRLB_SSDE; - } -# endif -# ifdef FEATURE_SPI_HARDWARE_SLAVE_SELECT - if (config->master_slave_select_enable) { - /* Enable Master Slave Select */ - ctrlb |= SERCOM_SPI_CTRLB_MSSEN; - } -# endif - /* Write CTRLA register */ - spi_module->CTRLA.reg |= ctrla; - - /* Write CTRLB register */ - spi_module->CTRLB.reg |= ctrlb; - - return STATUS_OK; -} - -#if SPI_CALLBACK_MODE == false -/** - * \internal Checks an SPI config against current set config - * - * This function will check that the config does not alter the - * configuration of the module. If the new config changes any - * setting, the initialization will be discarded. - * - * \param[in] module Pointer to the software instance struct - * \param[in] config Pointer to the configuration struct - * - * \return The status of the configuration. - * \retval STATUS_ERR_INVALID_ARG If invalid argument(s) were provided - * \retval STATUS_ERR_DENIED If configuration was different from previous - * \retval STATUS_OK If the configuration was written - */ -static enum status_code _spi_check_config( - struct spi_module *const module, - const struct spi_config *const config) -{ - /* Sanity check arguments */ - Assert(module); - Assert(config); - Assert(module->hw); - - SercomSpi *const spi_module = &(module->hw->SPI); - Sercom *const hw = module->hw; - - uint32_t pad_pinmuxes[] = { - config->pinmux_pad0, config->pinmux_pad1, - config->pinmux_pad2, config->pinmux_pad3 - }; - - /* Compare the current SERCOM pins against the user configuration */ - for (uint8_t pad = 0; pad < 4; pad++) { - uint32_t current_pinmux = pad_pinmuxes[pad]; - - if (current_pinmux == PINMUX_DEFAULT) { - current_pinmux = _sercom_get_default_pad(hw, pad); - } - - if (current_pinmux == PINMUX_UNUSED) { - continue; - } - - if ((current_pinmux & 0xFFFF) != - system_pinmux_pin_get_mux_position(current_pinmux >> 16)) { - module->hw = NULL; - return STATUS_ERR_DENIED; - } - } - -# if CONF_SPI_MASTER_ENABLE == true - /* Value to read BAUD register */ - uint16_t baud; - uint32_t external_clock = system_gclk_chan_get_hz(SERCOM_GCLK_ID); -# endif - /* Value to read CTRLA, CTRLB and ADDR register */ - uint32_t ctrla = 0; - uint32_t ctrlb = 0; -# if CONF_SPI_SLAVE_ENABLE == true - uint32_t addr = 0; -# endif - -# if CONF_SPI_MASTER_ENABLE == true - /* Find baud value and compare it */ - if (config->mode == SPI_MODE_MASTER) { - enum status_code error_code = _sercom_get_sync_baud_val( - config->mode_specific.master.baudrate, - external_clock, &baud); - - if (error_code != STATUS_OK) { - /* Baud rate calculation error, return status code */ - return STATUS_ERR_INVALID_ARG; - } - - if (spi_module->BAUD.reg != (uint8_t)baud) { - return STATUS_ERR_DENIED; - } - - ctrla |= SERCOM_SPI_CTRLA_MODE(0x3); - } -# endif - -# if CONF_SPI_SLAVE_ENABLE == true - if (config->mode == SPI_MODE_SLAVE) { - - /* Set frame format */ - ctrla |= config->mode_specific.slave.frame_format; - - /* Set address mode */ - ctrlb |= config->mode_specific.slave.address_mode; - - /* Set address and address mask*/ - addr |= (config->mode_specific.slave.address << SERCOM_SPI_ADDR_ADDR_Pos) | - (config->mode_specific.slave.address_mask << SERCOM_SPI_ADDR_ADDRMASK_Pos); - if (spi_module->CTRLA.reg != addr) { - return STATUS_ERR_DENIED; - } - - if (config->mode_specific.slave.preload_enable) { - /* Enable pre-loading of shift register */ - ctrlb |= SERCOM_SPI_CTRLB_PLOADEN; - } - ctrla |= SERCOM_SPI_CTRLA_MODE(0x2); - } -# endif - /* Set data order */ - ctrla |= config->data_order; - - /* Set clock polarity and clock phase */ - ctrla |= config->transfer_mode; - - /* Set MUX setting */ - ctrla |= config->mux_setting; - - /* Set SPI character size */ - ctrlb |= config->character_size; - - if (config->run_in_standby) { - /* Enable in sleep mode */ - ctrla |= SERCOM_SPI_CTRLA_RUNSTDBY; - } - - if (config->receiver_enable) { - /* Enable receiver */ - ctrlb |= SERCOM_SPI_CTRLB_RXEN; - } - -# ifdef FEATURE_SPI_SLAVE_SELECT_LOW_DETECT - if (config->select_slave_low_detect_enable) { - /* Enable Slave Select Low Detect */ - ctrlb |= SERCOM_SPI_CTRLB_SSDE; - } -# endif -# ifdef FEATURE_SPI_HARDWARE_SLAVE_SELECT - if (config->master_slave_select_enable) { - /* Enable Master Slave Select */ - ctrlb |= SERCOM_SPI_CTRLB_MSSEN; - } -# endif - - ctrla |= SERCOM_SPI_CTRLA_ENABLE; - - /* Check that same config is set */ - if (spi_module->CTRLA.reg == ctrla && - spi_module->CTRLB.reg == ctrlb) { - module->mode = config->mode; - module->character_size = config->character_size; - return STATUS_OK; - } - - /* Not same config, wipe module pointer and return */ - module->hw = NULL; - - return STATUS_ERR_DENIED; -} -#endif - -/** - * \brief Initializes the SERCOM SPI module - * - * This function will initialize the SERCOM SPI module, based on the values - * of the config struct. - * - * \param[out] module Pointer to the software instance struct - * \param[in] hw Pointer to hardware instance - * \param[in] config Pointer to the config struct - * - * \return Status of the initialization. - * \retval STATUS_OK Module initiated correctly - * \retval STATUS_ERR_DENIED If module is enabled - * \retval STATUS_BUSY If module is busy resetting - * \retval STATUS_ERR_INVALID_ARG If invalid argument(s) were provided - */ -enum status_code spi_init( - struct spi_module *const module, - Sercom *const hw, - const struct spi_config *const config) -{ - - /* Sanity check arguments */ - Assert(module); - Assert(hw); - Assert(config); - - /* Initialize device instance */ - module->hw = hw; - - SercomSpi *const spi_module = &(module->hw->SPI); - - /* Check if module is enabled. */ - if (spi_module->CTRLA.reg & SERCOM_SPI_CTRLA_ENABLE) { -# if SPI_CALLBACK_MODE == false - /* Check if config is valid */ - return _spi_check_config(module, config); -# else - return STATUS_ERR_DENIED; -# endif - } - - /* Check if reset is in progress. */ - if (spi_module->CTRLA.reg & SERCOM_SPI_CTRLA_SWRST){ - return STATUS_BUSY; - } - - uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw); - uint32_t pm_index, gclk_index; -#if (SAML21) - if (sercom_index == 5) { - pm_index = MCLK_APBDMASK_SERCOM5_Pos; - gclk_index = SERCOM5_GCLK_ID_CORE; - } else { - pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos; - gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; - } -#else - pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos; - gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; -#endif - - /* Turn on module in PM */ -#if (SAML21) - if (sercom_index == 5) { - system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBD, 1 << pm_index); - } else { - system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index); - } -#else - system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index); -#endif - - /* Set up the GCLK for the module */ - struct system_gclk_chan_config gclk_chan_conf; - system_gclk_chan_get_config_defaults(&gclk_chan_conf); - gclk_chan_conf.source_generator = config->generator_source; - system_gclk_chan_set_config(gclk_index, &gclk_chan_conf); - system_gclk_chan_enable(gclk_index); - sercom_set_gclk_generator(config->generator_source, false); - -# if CONF_SPI_MASTER_ENABLE == true - if (config->mode == SPI_MODE_MASTER) { - /* Set the SERCOM in SPI master mode */ - spi_module->CTRLA.reg |= SERCOM_SPI_CTRLA_MODE(0x3); - } -# endif - -# if CONF_SPI_SLAVE_ENABLE == true - if (config->mode == SPI_MODE_SLAVE) { - /* Set the SERCOM in SPI slave mode */ - spi_module->CTRLA.reg |= SERCOM_SPI_CTRLA_MODE(0x2); - } -# endif - -#if SPI_CALLBACK_MODE == true - /* Temporary variables */ - uint8_t i; - uint8_t instance_index; - - /* Initialize parameters */ - for (i = 0; i < SPI_CALLBACK_N; i++) { - module->callback[i] = NULL; - } - module->tx_buffer_ptr = NULL; - module->rx_buffer_ptr = NULL; - module->remaining_tx_buffer_length = 0x0000; - module->remaining_rx_buffer_length = 0x0000; - module->registered_callback = 0x00; - module->enabled_callback = 0x00; - module->status = STATUS_OK; - module->dir = SPI_DIRECTION_IDLE; - module->locked = false; - /* - * Set interrupt handler and register SPI software module struct in - * look-up table - */ - instance_index = _sercom_get_sercom_inst_index(module->hw); - _sercom_set_handler(instance_index, _spi_interrupt_handler); - _sercom_instances[instance_index] = module; -#endif - - /* Write configuration to module and return status code */ - return _spi_set_config(module, config); -} - -/** - * \brief Reads buffer of \c length SPI characters - * - * This function will read a buffer of data from an SPI peripheral by sending - * dummy SPI character if in master mode, or by waiting for data in slave mode. - * - * \note If address matching is enabled for the slave, the first character - * received and placed in the buffer will be the address. - * - * \param[in] module Pointer to the software instance struct - * \param[out] rx_data Data buffer for received data - * \param[in] length Length of data to receive - * \param[in] dummy 8- or 9-bit dummy byte to shift out in master mode - * - * \return Status of the read operation. - * \retval STATUS_OK If the read was completed - * \retval STATUS_ABORTED If transaction was ended by master before - * entire buffer was transferred - * \retval STATUS_ERR_INVALID_ARG If invalid argument(s) were provided - * \retval STATUS_ERR_TIMEOUT If the operation was not completed within the - * timeout in slave mode - * \retval STATUS_ERR_DENIED If the receiver is not enabled - * \retval STATUS_ERR_OVERFLOW If the data is overflown - */ -enum status_code spi_read_buffer_wait( - struct spi_module *const module, - uint8_t *rx_data, - uint16_t length, - uint16_t dummy) -{ - /* Sanity check arguments */ - Assert(module); - Assert(module->hw); - -# if SPI_CALLBACK_MODE == true - if (module->status == STATUS_BUSY) { - /* Check if the SPI module is busy with a job */ - return STATUS_BUSY; - } -# endif - - /* Sanity check arguments */ - if (length == 0) { - return STATUS_ERR_INVALID_ARG; - } - - if (!(module->receiver_enabled)) { - return STATUS_ERR_DENIED; - } -# if CONF_SPI_SLAVE_ENABLE == true - if ((module->mode == SPI_MODE_SLAVE) && (spi_is_write_complete(module))) { - /* Clear TX complete flag */ - _spi_clear_tx_complete_flag(module); - } -# endif - uint16_t rx_pos = 0; - - while (length--) { -# if CONF_SPI_MASTER_ENABLE == true - if (module->mode == SPI_MODE_MASTER) { - /* Wait until the module is ready to write a character */ - while (!spi_is_ready_to_write(module)) { - } - - /* Send dummy SPI character to read in master mode */ - spi_write(module, dummy); - } -# endif - -# if CONF_SPI_SLAVE_ENABLE == true - /* Start timeout period for slave */ - if (module->mode == SPI_MODE_SLAVE) { - for (uint32_t i = 0; i <= SPI_TIMEOUT; i++) { - if (spi_is_ready_to_read(module)) { - break; - } - } - /* Check if master has ended the transaction */ - if (spi_is_write_complete(module)) { - _spi_clear_tx_complete_flag(module); - return STATUS_ABORTED; - } - - if (!spi_is_ready_to_read(module)) { - /* Not ready to read data within timeout period */ - return STATUS_ERR_TIMEOUT; - } - } -# endif - - /* Wait until the module is ready to read a character */ - while (!spi_is_ready_to_read(module)) { - } - - uint16_t received_data = 0; - enum status_code retval = spi_read(module, &received_data); - - if (retval != STATUS_OK) { - /* Overflow, abort */ - return retval; - } - - /* Read value will be at least 8-bits long */ - rx_data[rx_pos++] = received_data; - - /* If 9-bit data, write next received byte to the buffer */ - if (module->character_size == SPI_CHARACTER_SIZE_9BIT) { - rx_data[rx_pos++] = (received_data >> 8); - } - } - - return STATUS_OK; -} - -/** - * \brief Sends and reads a single SPI character - * - * This function will transfer a single SPI character via SPI and return the - * SPI character that is shifted into the shift register. - * - * In master mode the SPI character will be sent immediately and the received - * SPI character will be read as soon as the shifting of the data is - * complete. - * - * In slave mode this function will place the data to be sent into the transmit - * buffer. It will then block until an SPI master has shifted a complete - * SPI character, and the received data is available. - * - * \note The data to be sent might not be sent before the next transfer, as - * loading of the shift register is dependent on SCK. - * \note If address matching is enabled for the slave, the first character - * received and placed in the buffer will be the address. - * - * \param[in] module Pointer to the software instance struct - * \param[in] tx_data SPI character to transmit - * \param[out] rx_data Pointer to store the received SPI character - * - * \return Status of the operation. - * \retval STATUS_OK If the operation was completed - * \retval STATUS_ERR_TIMEOUT If the operation was not completed within the - * timeout in slave mode - * \retval STATUS_ERR_DENIED If the receiver is not enabled - * \retval STATUS_ERR_OVERFLOW If the incoming data is overflown - */ -enum status_code spi_transceive_wait( - struct spi_module *const module, - uint16_t tx_data, - uint16_t *rx_data) -{ - /* Sanity check arguments */ - Assert(module); - - if (!(module->receiver_enabled)) { - return STATUS_ERR_DENIED; - } - -# if SPI_CALLBACK_MODE == true - if (module->status == STATUS_BUSY) { - /* Check if the SPI module is busy with a job */ - return STATUS_BUSY; - } -# endif - -# if CONF_SPI_SLAVE_ENABLE == true - uint16_t j; -# endif - enum status_code retval = STATUS_OK; - -# if CONF_SPI_SLAVE_ENABLE == true - /* Start timeout period for slave */ - if (module->mode == SPI_MODE_SLAVE) { - for (j = 0; j <= SPI_TIMEOUT; j++) { - if (spi_is_ready_to_write(module)) { - break; - } else if (j == SPI_TIMEOUT) { - /* Not ready to write data within timeout period */ - return STATUS_ERR_TIMEOUT; - } - } - } -# endif - /* Wait until the module is ready to write the character */ - while (!spi_is_ready_to_write(module)) { - } - - /* Write data */ - spi_write(module, tx_data); - -# if CONF_SPI_SLAVE_ENABLE == true - /* Start timeout period for slave */ - if (module->mode == SPI_MODE_SLAVE) { - for (j = 0; j <= SPI_TIMEOUT; j++) { - if (spi_is_ready_to_read(module)) { - break; - } else if (j == SPI_TIMEOUT) { - /* Not ready to read data within timeout period */ - return STATUS_ERR_TIMEOUT; - } - } - } -# endif - - /* Wait until the module is ready to read the character */ - while (!spi_is_ready_to_read(module)) { - } - - /* Read data */ - retval = spi_read(module, rx_data); - - return retval; -} - - /** - * \brief Selects slave device - * - * This function will drive the slave select pin of the selected device low or - * high depending on the select Boolean. - * If slave address recognition is enabled, the address will be sent to the - * slave when selecting it. - * - * \param[in] module Pointer to the software module struct - * \param[in] slave Pointer to the attached slave - * \param[in] select Boolean stating if the slave should be selected or - * deselected - * - * \return Status of the operation. - * \retval STATUS_OK If the slave device was selected - * \retval STATUS_ERR_UNSUPPORTED_DEV If the SPI module is operating in slave - * mode - * \retval STATUS_BUSY If the SPI module is not ready to write - * the slave address - */ -enum status_code spi_select_slave( - struct spi_module *const module, - struct spi_slave_inst *const slave, - const bool select) -{ - /* Sanity check arguments */ - Assert(module); - Assert(module->hw); - Assert(slave); - - /* Check that the SPI module is operating in master mode */ - if (module->mode != SPI_MODE_MASTER) { - return STATUS_ERR_UNSUPPORTED_DEV; - } -# ifdef FEATURE_SPI_HARDWARE_SLAVE_SELECT - if(!(module->master_slave_select_enable)) -# endif - { - if (select) { - /* Check if address recognition is enabled */ - if (slave->address_enabled) { - /* Check if the module is ready to write the address */ - if (!spi_is_ready_to_write(module)) { - /* Not ready, do not select slave and return */ - port_pin_set_output_level(slave->ss_pin, true); - return STATUS_BUSY; - } - - /* Drive Slave Select low */ - port_pin_set_output_level(slave->ss_pin, false); - - /* Write address to slave */ - spi_write(module, slave->address); - - if (!(module->receiver_enabled)) { - /* Flush contents of shift register shifted back from slave */ - while (!spi_is_ready_to_read(module)) { - } - uint16_t flush = 0; - spi_read(module, &flush); - } - } else { - /* Drive Slave Select low */ - port_pin_set_output_level(slave->ss_pin, false); - } - } else { - /* Drive Slave Select high */ - port_pin_set_output_level(slave->ss_pin, true); - } - } - return STATUS_OK; -} - -/** - * \brief Sends a buffer of \c length SPI characters - * - * This function will send a buffer of SPI characters via the SPI - * and discard any data that is received. To both send and receive a buffer of - * data, use the \ref spi_transceive_buffer_wait function. - * - * Note that this function does not handle the _SS (slave select) pin(s) in - * master mode; this must be handled by the user application. - * - * \param[in] module Pointer to the software instance struct - * \param[in] tx_data Pointer to the buffer to transmit - * \param[in] length Number of SPI characters to transfer - * - * \return Status of the write operation. - * \retval STATUS_OK If the write was completed - * \retval STATUS_ABORTED If transaction was ended by master before - * entire buffer was transferred - * \retval STATUS_ERR_INVALID_ARG If invalid argument(s) were provided - * \retval STATUS_ERR_TIMEOUT If the operation was not completed within the - * timeout in slave mode - */ -enum status_code spi_write_buffer_wait( - struct spi_module *const module, - const uint8_t *tx_data, - uint16_t length) -{ - /* Sanity check arguments */ - Assert(module); - -# if SPI_CALLBACK_MODE == true - if (module->status == STATUS_BUSY) { - /* Check if the SPI module is busy with a job */ - return STATUS_BUSY; - } -# endif - - if (length == 0) { - return STATUS_ERR_INVALID_ARG; - } - -# if CONF_SPI_SLAVE_ENABLE == true - if ((module->mode == SPI_MODE_SLAVE) && (spi_is_write_complete(module))) { - /* Clear TX complete flag */ - _spi_clear_tx_complete_flag(module); - } -# endif - - uint16_t tx_pos = 0; - uint16_t flush_length = length; - - /* Write block */ - while (length--) { -# if CONF_SPI_SLAVE_ENABLE == true - /* Start timeout period for slave */ - if (module->mode == SPI_MODE_SLAVE) { - for (uint32_t i = 0; i <= SPI_TIMEOUT; i++) { - if (spi_is_ready_to_write(module)) { - break; - } - } - /* Check if master has ended the transaction */ - if (spi_is_write_complete(module)) { - _spi_clear_tx_complete_flag(module); - return STATUS_ABORTED; - } - - if (!spi_is_ready_to_write(module)) { - /* Not ready to write data within timeout period */ - return STATUS_ERR_TIMEOUT; - } - } -# endif - - /* Wait until the module is ready to write a character */ - while (!spi_is_ready_to_write(module)) { - } - - /* Write value will be at least 8-bits long */ - uint16_t data_to_send = tx_data[tx_pos++]; - - /* If 9-bit data, get next byte to send from the buffer */ - if (module->character_size == SPI_CHARACTER_SIZE_9BIT) { - data_to_send |= (tx_data[tx_pos++] << 8); - } - - /* Write the data to send */ - spi_write(module, data_to_send); - - if (module->receiver_enabled) { -# if CONF_SPI_SLAVE_ENABLE == true - /* Start timeout period for slave */ - if (module->mode == SPI_MODE_SLAVE) { - for (uint32_t i = 0; i <= SPI_TIMEOUT; i++) { - if (spi_is_ready_to_write(module)) { - data_to_send = tx_data[tx_pos++]; - /* If 9-bit data, get next byte to send from the buffer */ - if (module->character_size == SPI_CHARACTER_SIZE_9BIT) { - data_to_send |= (tx_data[tx_pos++] << 8); - } - - /* Write the data to send */ - spi_write(module, data_to_send); - length--; - } - if (spi_is_ready_to_read(module)) { - break; - } - } - - /* Check if master has ended the transaction */ - if (spi_is_write_complete(module)) { - _spi_clear_tx_complete_flag(module); - return STATUS_ABORTED; - } - - if (!spi_is_ready_to_read(module)) { - /* Not ready to read data within timeout period */ - return STATUS_ERR_TIMEOUT; - } - } -# endif - - while (!spi_is_ready_to_read(module)) { - } - - /* Flush read buffer */ - uint16_t flush; - spi_read(module, &flush); - flush_length--; - } - } - -# if CONF_SPI_MASTER_ENABLE == true - if (module->mode == SPI_MODE_MASTER) { - /* Wait for last byte to be transferred */ - while (!spi_is_write_complete(module)) { - } - } -# endif - -# if CONF_SPI_SLAVE_ENABLE == true - if (module->mode == SPI_MODE_SLAVE) { - if (module->receiver_enabled) { - while (flush_length) { - /* Start timeout period for slave */ - for (uint32_t i = 0; i <= SPI_TIMEOUT; i++) { - if (spi_is_ready_to_read(module)) { - break; - } - } - if (!spi_is_ready_to_read(module)) { - /* Not ready to read data within timeout period */ - return STATUS_ERR_TIMEOUT; - } - /* Flush read buffer */ - uint16_t flush; - spi_read(module, &flush); - flush_length--; - } - } - } -# endif - return STATUS_OK; -} - -/** - * \brief Sends and receives a buffer of \c length SPI characters - * - * This function will send and receive a buffer of data via the SPI. - * - * In master mode the SPI characters will be sent immediately and the - * received SPI character will be read as soon as the shifting of the SPI - * character is complete. - * - * In slave mode this function will place the data to be sent into the transmit - * buffer. It will then block until an SPI master has shifted the complete - * buffer and the received data is available. - * - * \param[in] module Pointer to the software instance struct - * \param[in] tx_data Pointer to the buffer to transmit - * \param[out] rx_data Pointer to the buffer where received data will be stored - * \param[in] length Number of SPI characters to transfer - * - * \return Status of the operation. - * \retval STATUS_OK If the operation was completed - * \retval STATUS_ERR_INVALID_ARG If invalid argument(s) were provided - * \retval STATUS_ERR_TIMEOUT If the operation was not completed within the - * timeout in slave mode - * \retval STATUS_ERR_DENIED If the receiver is not enabled - * \retval STATUS_ERR_OVERFLOW If the data is overflown - */ -enum status_code spi_transceive_buffer_wait( - struct spi_module *const module, - uint8_t *tx_data, - uint8_t *rx_data, - uint16_t length) -{ - /* Sanity check arguments */ - Assert(module); - -# if SPI_CALLBACK_MODE == true - if (module->status == STATUS_BUSY) { - /* Check if the SPI module is busy with a job */ - return STATUS_BUSY; - } -# endif - - /* Sanity check arguments */ - if (length == 0) { - return STATUS_ERR_INVALID_ARG; - } - - if (!(module->receiver_enabled)) { - return STATUS_ERR_DENIED; - } - -# if CONF_SPI_SLAVE_ENABLE == true - if ((module->mode == SPI_MODE_SLAVE) && (spi_is_write_complete(module))) { - /* Clear TX complete flag */ - _spi_clear_tx_complete_flag(module); - } -# endif - - uint16_t tx_pos = 0; - uint16_t rx_pos = 0; - uint16_t rx_length = length; - - /* Send and receive buffer */ - while (length--) { -# if CONF_SPI_SLAVE_ENABLE == true - /* Start timeout period for slave */ - if (module->mode == SPI_MODE_SLAVE) { - for (uint32_t i = 0; i <= SPI_TIMEOUT; i++) { - if (spi_is_ready_to_write(module)) { - break; - } - } - /* Check if master has ended the transaction */ - if (spi_is_write_complete(module)) { - _spi_clear_tx_complete_flag(module); - return STATUS_ABORTED; - } - - if (!spi_is_ready_to_write(module)) { - /* Not ready to write data within timeout period */ - return STATUS_ERR_TIMEOUT; - } - } -# endif - - /* Wait until the module is ready to write a character */ - while (!spi_is_ready_to_write(module)) { - } - - /* Write value will be at least 8-bits long */ - uint16_t data_to_send = tx_data[tx_pos++]; - - /* If 9-bit data, get next byte to send from the buffer */ - if (module->character_size == SPI_CHARACTER_SIZE_9BIT) { - data_to_send |= (tx_data[tx_pos++] << 8); - } - - /* Write the data to send */ - spi_write(module, data_to_send); - -# if CONF_SPI_SLAVE_ENABLE == true - /* Start timeout period for slave */ - if (module->mode == SPI_MODE_SLAVE) { - for (uint32_t i = 0; i <= SPI_TIMEOUT; i++) { - if (spi_is_ready_to_write(module)) { - data_to_send = tx_data[tx_pos++]; - /* If 9-bit data, get next byte to send from the buffer */ - if (module->character_size == SPI_CHARACTER_SIZE_9BIT) { - data_to_send |= (tx_data[tx_pos++] << 8); - } - - /* Write the data to send */ - spi_write(module, data_to_send); - length--; - } - if (spi_is_ready_to_read(module)) { - break; - } - } - /* Check if master has ended the transaction */ - if (spi_is_write_complete(module)) { - _spi_clear_tx_complete_flag(module); - return STATUS_ABORTED; - } - - if (!spi_is_ready_to_read(module)) { - /* Not ready to read data within timeout period */ - return STATUS_ERR_TIMEOUT; - } - } -# endif - - /* Wait until the module is ready to read a character */ - while (!spi_is_ready_to_read(module)) { - } - - enum status_code retval; - uint16_t received_data = 0; - rx_length--; - - retval = spi_read(module, &received_data); - - if (retval != STATUS_OK) { - /* Overflow, abort */ - return retval; - } - - /* Read value will be at least 8-bits long */ - rx_data[rx_pos++] = received_data; - - /* If 9-bit data, write next received byte to the buffer */ - if (module->character_size == SPI_CHARACTER_SIZE_9BIT) { - rx_data[rx_pos++] = (received_data >> 8); - } - } - -# if CONF_SPI_MASTER_ENABLE == true - if (module->mode == SPI_MODE_MASTER) { - /* Wait for last byte to be transferred */ - while (!spi_is_write_complete(module)) { - } - } -# endif - -# if CONF_SPI_SLAVE_ENABLE == true - if (module->mode == SPI_MODE_SLAVE) { - while (rx_length) { - /* Start timeout period for slave */ - for (uint32_t i = 0; i <= SPI_TIMEOUT; i++) { - if (spi_is_ready_to_read(module)) { - break; - } - } - if (!spi_is_ready_to_read(module)) { - /* Not ready to read data within timeout period */ - return STATUS_ERR_TIMEOUT; - } - enum status_code retval; - uint16_t received_data = 0; - rx_length--; - - retval = spi_read(module, &received_data); - - if (retval != STATUS_OK) { - /* Overflow, abort */ - return retval; - } - /* Read value will be at least 8-bits long */ - rx_data[rx_pos++] = received_data; - - /* If 9-bit data, write next received byte to the buffer */ - if (module->character_size == SPI_CHARACTER_SIZE_9BIT) { - rx_data[rx_pos++] = (received_data >> 8); - } - } - } -# endif - return STATUS_OK; -} diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/drivers/sercom/spi/spi.h b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/drivers/sercom/spi/spi.h deleted file mode 100644 index 27a7f0869c..0000000000 --- a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/drivers/sercom/spi/spi.h +++ /dev/null @@ -1,1763 +0,0 @@ -/** - * \file - * - * \brief SAM Serial Peripheral Interface Driver - * - * Copyright (C) 2012-2014 Atmel Corporation. All rights reserved. - * - * \asf_license_start - * - * \page License - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. The name of Atmel may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * 4. This software may only be redistributed and used in connection with an - * Atmel microcontroller product. - * - * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE - * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * \asf_license_stop - * - */ - /** - * Support and FAQ: visit Atmel Support - */ - -#ifndef SPI_H_INCLUDED -#define SPI_H_INCLUDED - -/** - * \defgroup asfdoc_sam0_sercom_spi_group SAM Serial Peripheral Interface Driver (SERCOM SPI) - * - * This driver for Atmel庐 | SMART SAM devices provides an interface for the configuration - * and management of the SERCOM module in its SPI mode to transfer SPI data - * frames. The following driver API modes are covered by this manual: - * - * - Polled APIs - * \if SPI_CALLBACK_MODE - * - Callback APIs - * \endif - * - * The following peripherals are used by this module: - * - SERCOM (Serial Communication Interface) - * - * The following devices can use this module: - * - Atmel | SMART SAM D20/D21 - * - Atmel | SMART SAM R21 - * - Atmel | SMART SAM D10/D11 - * - Atmel | SMART SAM L21 - * - * The outline of this documentation is as follows: - * - \ref asfdoc_sam0_sercom_spi_prerequisites - * - \ref asfdoc_sam0_sercom_spi_module_overview - * - \ref asfdoc_sam0_sercom_spi_special_considerations - * - \ref asfdoc_sam0_sercom_spi_extra_info - * - \ref asfdoc_sam0_sercom_spi_examples - * - \ref asfdoc_sam0_sercom_spi_api_overview - * - * \section asfdoc_sam0_sercom_spi_prerequisites Prerequisites - * There are no prerequisites. - * - * - * \section asfdoc_sam0_sercom_spi_module_overview Module Overview - * The Serial Peripheral Interface (SPI) is a high-speed synchronous data - * transfer interface using three or four pins. It allows fast communication - * between a master device and one or more peripheral devices. - * - * A device connected to the bus must act as a master or a slave. The master - * initiates and controls all data transactions. - * The SPI master initiates a communication cycle by pulling low the Slave - * Select (SS) pin of the desired slave. The Slave Select pin is active low. - * Master and slave prepare data to be sent in their respective shift - * registers, and the master generates the required clock pulses on the SCK - * line to interchange data. Data is always shifted from master to slave on - * the Master Out - Slave In (MOSI) line, and from slave to master on the - * Master In - Slave Out (MISO) line. After each data transfer, the master can - * synchronize to the slave by pulling the SS line high. - * - * \subsection asfdoc_sam0_sercom_spi_module_features Driver Feature Macro Definition - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Driver Feature MacroSupported devices
FEATURE_SPI_SLAVE_SELECT_LOW_DETECTSAM D21/R21/D10/D11/L21
FEATURE_SPI_HARDWARE_SLAVE_SELECTSAM D21/R21/D10/D11/L21
FEATURE_SPI_ERROR_INTERRUPTSAM D21/R21/D10/D11/L21
FEATURE_SPI_SYNC_SCHEME_VERSION_2SAM D21/R21/D10/D11/L21
- * \note The specific features are only available in the driver when the - * selected device supports those features. - * - * \subsection asfdoc_sam0_sercom_spi_bus SPI Bus Connection - * In \ref asfdoc_sam0_spi_connection_example "the figure below", the - * connection between one master and one slave is shown. - * - * \anchor asfdoc_sam0_spi_connection_example - * \dot - * digraph spi_slaves_par { - * subgraph cluster_spi_master { - * shift_reg [label="Shift register", shape=box]; - * mosi_m [label="MOSI", shape=none]; - * miso_m [label="MISO", shape=none]; - * sck_m [label="SCK", shape=none]; - * ss_m [label="GPIO pin", shape=none]; - * {rank=same; mosi_m miso_m sck_m ss_m} - * label="SPI Master"; - * } - * subgraph cluster_spi_slave { - * mosi_s [label="MOSI", shape=none]; - * miso_s [label="MISO", shape=none]; - * sck_s [label="SCK", shape=none]; - * ss_s [label="SS", shape=none]; - * shift_reg_s [label="Shift register", shape=box]; - * {rank=same; mosi_s miso_s sck_s ss_s} - * label="SPI Slave"; - * rankdir=LR; - * } - * shift_reg:e -> mosi_m:w [label=""]; - * mosi_m:e -> mosi_s:w [label=""]; - * mosi_s:e -> shift_reg_s:w [label=""]; - * miso_s:w -> miso_m:e [label=""]; - * sck_m -> sck_s; - * ss_m -> ss_s; - * shift_reg_s:se -> miso_s:e [label=""]; - * miso_m:w -> shift_reg:sw [label=""]; - * rankdir=LR; - * } - * \enddot - * - * The different lines are as follows: - * - \b MISO Master Input Slave Output. The line where the data is shifted - * out from the slave and in to the master. - * - \b MOSI Master Output Slave Input. The line where the data is shifted - * out from the master and in to the slave. - * - \b SCK Serial Clock. Generated by the master device. - * - \b SS Slave Select. To initiate a transaction, the master must pull this - * line low. - * - * If the bus consists of several SPI slaves, they can be connected in parallel - * and the SPI master can use general I/O pins to control separate SS lines to - * each slave on the bus. - * - * It is also possible to connect all slaves in series. In this configuration, - * a common SS is provided to \c N slaves, enabling them simultaneously. The - * MISO from the \c N-1 slaves is connected to the MOSI on the next slave. The - * \c Nth slave connects its MISO back to the master. For a - * complete transaction, the master must shift \c N+1 characters. - * - * \subsection asfdoc_sam0_sercom_spi_chsize SPI Character Size - * The SPI character size is configurable to eight or nine bits. - * - * \subsection asfdoc_sam0_sercom_spi_master_mode Master Mode - * When configured as a master, the SS pin will be configured as an output. - * - * \subsubsection asfdoc_sam0_sercom_spi_master_mode_data_transfer Data Transfer - * Writing a character will start the SPI clock generator, and - * the character is transferred to the shift register when the shift - * register is empty. - * Once this is done, a new character can be written. - * As each character is shifted out from the master, a character is shifted in - * from the slave. If the receiver is enabled, the data is moved to the receive - * buffer at the completion of the frame and can be read. - * - * \subsection asfdoc_sam0_sercom_spi_slave_mode Slave Mode - * When configured as a slave, the SPI interface will remain inactive with MISO - * tri-stated as long as the SS pin is driven high. - * - * \subsubsection asfdoc_sam0_sercom_spi_slave_mode_data_transfer_slave Data Transfer - * The data register can be updated at any time. - * As the SPI slave shift register is clocked by SCK, a minimum of three SCK - * cycles are needed from the time new data is written, until the character is - * ready to be shifted out. If the shift register has not been loaded with - * data, the current contents will be transmitted. - * - * If constant transmission of data is needed in SPI slave mode, the system - * clock should be faster than SCK. - * If the receiver is enabled, the received character can be read from the. - * When SS line is driven high, the slave will not receive any additional data. - * - * \subsubsection asfdoc_sam0_sercom_spi_slave_mode_addr_recognition Address Recognition - * When the SPI slave is configured with address recognition, the first - * character in a transaction is checked for an address match. If there is a - * match, the MISO output is enabled and the transaction is processed. - * If the address does not match, the complete transaction is ignored. - * - * If the device is asleep, it can be woken up by an address match in order - * to process the transaction. - * - * \note In master mode, an address packet is written by the - * \ref spi_select_slave function if the address_enabled configuration is - * set in the \ref spi_slave_inst_config struct. - * - * \subsection asfdoc_sam0_sercom_spi_data_modes Data Modes - * There are four combinations of SCK phase and polarity with respect to - * serial data. \ref asfdoc_sam0_spi_mode_table "The table below" shows the - * clock polarity (CPOL) and clock phase (CPHA) in the different modes. - * Leading edge is the first clock edge in a clock cycle and - * trailing edge is the last clock edge in a clock cycle. - * - * \anchor asfdoc_sam0_spi_mode_table - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
SPI Data Modes
ModeCPOLCPHALeading EdgeTrailing Edge
0 0 0 Rising, Sample Falling, Setup
1 0 1 Rising, Setup Falling, Sample
2 1 0 Falling, Sample Rising, Setup
3 1 1 Falling, Setup Rising, Sample
- * - * - * \subsection asfdoc_sam0_sercom_spi_pads SERCOM Pads - * The SERCOM pads are automatically configured as seen in - * \ref asfdoc_sam0_spi_sercom_pad_table "the table below". If the receiver - * is disabled, the data input (MISO for master, MOSI for slave) can be used - * for other purposes. - * - * In master mode, the SS pin(s) must be configured using the \ref spi_slave_inst - * struct. - * - * \anchor asfdoc_sam0_spi_sercom_pad_table - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
SERCOM SPI Pad Usages
Pin Master SPI Slave SPI
MOSI Output Input
MISO Input Output
SCK Output Input
SS User defined output enable Input
- * - * \subsection asfdoc_sam0_sercom_spi_sleep_modes Operation in Sleep Modes - * The SPI module can operate in all sleep modes by setting the run_in_standby - * option in the \ref spi_config struct. The operation in slave and master mode - * is shown in the table below. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
run_in_standby Slave Master
false Disabled, all reception is dropped GCLK disabled when master is idle, wake on transmit complete
true Wake on reception GCLK is enabled while in sleep modes, wake on all interrupts
- * - * \subsection asfdoc_sam0_sercom_spi_clock_generation Clock Generation - * In SPI master mode, the clock (SCK) is generated internally using the - * SERCOM baudrate generator. In SPI slave mode, the clock is provided by - * an external master on the SCK pin. This clock is used to directly clock - * the SPI shift register. - * - * \section asfdoc_sam0_sercom_spi_special_considerations Special Considerations - * \subsection pin_mux pinmux Settings - * The pin MUX settings must be configured properly, as not all settings - * can be used in different modes of operation. - * - * \section asfdoc_sam0_sercom_spi_extra_info Extra Information - * For extra information, see \ref asfdoc_sam0_sercom_spi_extra. This includes: - * - \ref asfdoc_sam0_sercom_spi_extra_acronyms - * - \ref asfdoc_sam0_sercom_spi_extra_dependencies - * - \ref asfdoc_sam0_sercom_spi_extra_workarounds - * - \ref asfdoc_sam0_sercom_spi_extra_history - * - * \section asfdoc_sam0_sercom_spi_examples Examples - * - * For a list of examples related to this driver, see - * \ref asfdoc_sam0_sercom_spi_exqsg. - * - * \section asfdoc_sam0_sercom_spi_api_overview API Overview - * @{ - */ - -#include -#include -#include -#include -#include -#include - -# if SPI_CALLBACK_MODE == true -# include -# endif - -#ifdef __cplusplus -extern "C" { -#endif - -#if (CONF_SPI_MASTER_ENABLE == false) && (CONF_SPI_SLAVE_ENABLE == false) -#error "Not possible compile SPI driver, invalid driver configuration. Make sure that either/both CONF_SPI_MASTER_ENABLE/CONF_SPI_SLAVE_ENABLE is set to true." -#endif - -/** - * \name Driver Feature Definition - * Define SERCOM SPI features set according to different device family. - * @{ - */ -# if (SAMD21) || (SAMR21) || (SAMD11) || (SAMD10) || (SAML21) || defined(__DOXYGEN__) -/** SPI slave select low detection. */ -# define FEATURE_SPI_SLAVE_SELECT_LOW_DETECT -/** Slave select can be controlled by hardware. */ -# define FEATURE_SPI_HARDWARE_SLAVE_SELECT -/** SPI with error detect feature. */ -# define FEATURE_SPI_ERROR_INTERRUPT -/** SPI sync scheme version 2. */ -# define FEATURE_SPI_SYNC_SCHEME_VERSION_2 -# endif -/*@}*/ - -# ifndef PINMUX_DEFAULT -/** Default pinmux. */ -# define PINMUX_DEFAULT 0 -# endif - -# ifndef PINMUX_UNUSED -/** Unused pinmux. */ -# define PINMUX_UNUSED 0xFFFFFFFF -# endif - -# ifndef SPI_TIMEOUT -/** SPI timeout value. */ -# define SPI_TIMEOUT 10000 -# endif - -# if SPI_CALLBACK_MODE == true -/** - * \brief SPI Callback enum - * - * Callbacks for SPI callback driver. - * - * \note For slave mode, these callbacks will be called when a transaction - * is ended by the master pulling Slave Select high. - * - */ -enum spi_callback { - /** Callback for buffer transmitted. */ - SPI_CALLBACK_BUFFER_TRANSMITTED, - /** Callback for buffer received. */ - SPI_CALLBACK_BUFFER_RECEIVED, - /** Callback for buffers transceived. */ - SPI_CALLBACK_BUFFER_TRANSCEIVED, - /** Callback for error. */ - SPI_CALLBACK_ERROR, - /** - * Callback for transmission ended by master before entire buffer was - * read or written from slave. - */ - SPI_CALLBACK_SLAVE_TRANSMISSION_COMPLETE, -# ifdef FEATURE_SPI_SLAVE_SELECT_LOW_DETECT - /** Callback for slave select low. */ - SPI_CALLBACK_SLAVE_SELECT_LOW, -# endif -# ifdef FEATURE_SPI_ERROR_INTERRUPT - /** Callback for combined error happen. */ - SPI_CALLBACK_COMBINED_ERROR, -# endif -# if !defined(__DOXYGEN__) - /** Number of available callbacks. */ - SPI_CALLBACK_N, -# endif -}; -# endif - -#if SPI_CALLBACK_MODE == true -# if !defined(__DOXYGEN__) -/** - * \internal SPI transfer directions - */ -enum _spi_direction { - /** Transfer direction is read. */ - SPI_DIRECTION_READ, - /** Transfer direction is write. */ - SPI_DIRECTION_WRITE, - /** Transfer direction is read and write. */ - SPI_DIRECTION_BOTH, - /** No transfer. */ - SPI_DIRECTION_IDLE, -}; -# endif -#endif - -/** - * \brief SPI Interrupt Flags - * - * Interrupt flags for the SPI module. - * - */ -enum spi_interrupt_flag { - /** - * This flag is set when the contents of the data register has been moved - * to the shift register and the data register is ready for new data. - */ - SPI_INTERRUPT_FLAG_DATA_REGISTER_EMPTY = SERCOM_SPI_INTFLAG_DRE, - /** - * This flag is set when the contents of the shift register has been - * shifted out. - */ - SPI_INTERRUPT_FLAG_TX_COMPLETE = SERCOM_SPI_INTFLAG_TXC, - /** This flag is set when data has been shifted into the data register. */ - SPI_INTERRUPT_FLAG_RX_COMPLETE = SERCOM_SPI_INTFLAG_RXC, -# ifdef FEATURE_SPI_SLAVE_SELECT_LOW_DETECT - /** This flag is set when slave select low. */ - SPI_INTERRUPT_FLAG_SLAVE_SELECT_LOW = SERCOM_SPI_INTFLAG_SSL, -# endif -# ifdef FEATURE_SPI_ERROR_INTERRUPT - /** This flag is set when combined error happen. */ - SPI_INTERRUPT_FLAG_COMBINED_ERROR = SERCOM_SPI_INTFLAG_ERROR, -# endif -}; - -/** - * \brief SPI transfer modes enum - * - * SPI transfer mode. - */ -enum spi_transfer_mode { - /** Mode 0. Leading edge: rising, sample. Trailing edge: falling, setup. */ - SPI_TRANSFER_MODE_0 = 0, - /** Mode 1. Leading edge: rising, setup. Trailing edge: falling, sample. */ - SPI_TRANSFER_MODE_1 = SERCOM_SPI_CTRLA_CPHA, - /** Mode 2. Leading edge: falling, sample. Trailing edge: rising, setup. */ - SPI_TRANSFER_MODE_2 = SERCOM_SPI_CTRLA_CPOL, - /** Mode 3. Leading edge: falling, setup. Trailing edge: rising, sample. */ - SPI_TRANSFER_MODE_3 = SERCOM_SPI_CTRLA_CPHA | SERCOM_SPI_CTRLA_CPOL, -}; - -/** - * \brief SPI frame format enum - * - * Frame format for slave mode. - */ -enum spi_frame_format { - /** SPI frame. */ - SPI_FRAME_FORMAT_SPI_FRAME = SERCOM_SPI_CTRLA_FORM(0), - /** SPI frame with address. */ - SPI_FRAME_FORMAT_SPI_FRAME_ADDR = SERCOM_SPI_CTRLA_FORM(2), -}; - -/** - * \brief SPI signal MUX settings - * - * Set the functionality of the SERCOM pins. - * As not all settings can be used in different modes of operation, proper - * settings must be chosen according to the rest of the configuration. - * - * See \ref asfdoc_sam0_sercom_spi_mux_settings for a description of the - * various MUX setting options. - */ -enum spi_signal_mux_setting { - /** SPI MUX setting A. */ - SPI_SIGNAL_MUX_SETTING_A = - (0x0 << SERCOM_SPI_CTRLA_DOPO_Pos) | - (0x0 << SERCOM_SPI_CTRLA_DIPO_Pos), - /** SPI MUX setting B. */ - SPI_SIGNAL_MUX_SETTING_B = - (0x0 << SERCOM_SPI_CTRLA_DOPO_Pos) | - (0x1 << SERCOM_SPI_CTRLA_DIPO_Pos), - /** SPI MUX setting C. */ - SPI_SIGNAL_MUX_SETTING_C = - (0x0 << SERCOM_SPI_CTRLA_DOPO_Pos) | - (0x2 << SERCOM_SPI_CTRLA_DIPO_Pos), - /** SPI MUX setting D. */ - SPI_SIGNAL_MUX_SETTING_D = - (0x0 << SERCOM_SPI_CTRLA_DOPO_Pos) | - (0x3 << SERCOM_SPI_CTRLA_DIPO_Pos), - /** SPI MUX setting E. */ - SPI_SIGNAL_MUX_SETTING_E = - (0x1 << SERCOM_SPI_CTRLA_DOPO_Pos) | - (0x0 << SERCOM_SPI_CTRLA_DIPO_Pos), - /** SPI MUX setting F. */ - SPI_SIGNAL_MUX_SETTING_F = - (0x1 << SERCOM_SPI_CTRLA_DOPO_Pos) | - (0x1 << SERCOM_SPI_CTRLA_DIPO_Pos), - /** SPI MUX setting G. */ - SPI_SIGNAL_MUX_SETTING_G = - (0x1 << SERCOM_SPI_CTRLA_DOPO_Pos) | - (0x2 << SERCOM_SPI_CTRLA_DIPO_Pos), - /** SPI MUX setting H. */ - SPI_SIGNAL_MUX_SETTING_H = - (0x1 << SERCOM_SPI_CTRLA_DOPO_Pos) | - (0x3 << SERCOM_SPI_CTRLA_DIPO_Pos), - /** SPI MUX setting I. */ - SPI_SIGNAL_MUX_SETTING_I = - (0x2 << SERCOM_SPI_CTRLA_DOPO_Pos) | - (0x0 << SERCOM_SPI_CTRLA_DIPO_Pos), - /** SPI MUX setting J. */ - SPI_SIGNAL_MUX_SETTING_J = - (0x2 << SERCOM_SPI_CTRLA_DOPO_Pos) | - (0x1 << SERCOM_SPI_CTRLA_DIPO_Pos), - /** SPI MUX setting K. */ - SPI_SIGNAL_MUX_SETTING_K = - (0x2 << SERCOM_SPI_CTRLA_DOPO_Pos) | - (0x2 << SERCOM_SPI_CTRLA_DIPO_Pos), - /** SPI MUX setting L. */ - SPI_SIGNAL_MUX_SETTING_L = - (0x2 << SERCOM_SPI_CTRLA_DOPO_Pos) | - (0x3 << SERCOM_SPI_CTRLA_DIPO_Pos), - /** SPI MUX setting M. */ - SPI_SIGNAL_MUX_SETTING_M = - (0x3 << SERCOM_SPI_CTRLA_DOPO_Pos) | - (0x0 << SERCOM_SPI_CTRLA_DIPO_Pos), - /** SPI MUX setting N. */ - SPI_SIGNAL_MUX_SETTING_N = - (0x3 << SERCOM_SPI_CTRLA_DOPO_Pos) | - (0x1 << SERCOM_SPI_CTRLA_DIPO_Pos), - /** SPI MUX setting O. */ - SPI_SIGNAL_MUX_SETTING_O = - (0x3 << SERCOM_SPI_CTRLA_DOPO_Pos) | - (0x2 << SERCOM_SPI_CTRLA_DIPO_Pos), - /** SPI MUX setting P. */ - SPI_SIGNAL_MUX_SETTING_P = - (0x3 << SERCOM_SPI_CTRLA_DOPO_Pos) | - (0x3 << SERCOM_SPI_CTRLA_DIPO_Pos), -}; - -/** - * \brief SPI address modes enum - * - * For slave mode when using the SPI frame with address format. - * - */ -enum spi_addr_mode { - /** - * \c address_mask in the \ref spi_config struct is used as a mask to the register. - */ - SPI_ADDR_MODE_MASK = SERCOM_SPI_CTRLB_AMODE(0), - /** - * The slave responds to the two unique addresses in \c address and - * \c address_mask in the \ref spi_config struct. - */ - SPI_ADDR_MODE_UNIQUE = SERCOM_SPI_CTRLB_AMODE(1), - /** - * The slave responds to the range of addresses between and including \c address - * and \c address_mask in in the \ref spi_config struct. - */ - SPI_ADDR_MODE_RANGE = SERCOM_SPI_CTRLB_AMODE(2), -}; - -/** - * \brief SPI modes enum - * - * SPI mode selection. - */ -enum spi_mode { - /** Master mode. */ - SPI_MODE_MASTER = 1, - /** Slave mode. */ - SPI_MODE_SLAVE = 0, -}; - -/** - * \brief SPI data order enum - * - * SPI data order. - * - */ -enum spi_data_order { - /** The LSB of the data is transmitted first. */ - SPI_DATA_ORDER_LSB = SERCOM_SPI_CTRLA_DORD, - /** The MSB of the data is transmitted first. */ - SPI_DATA_ORDER_MSB = 0, -}; - -/** - * \brief SPI character size enum - * - * SPI character size. - * - */ -enum spi_character_size { - /** 8-bit character. */ - SPI_CHARACTER_SIZE_8BIT = SERCOM_SPI_CTRLB_CHSIZE(0), - /** 9-bit character. */ - SPI_CHARACTER_SIZE_9BIT = SERCOM_SPI_CTRLB_CHSIZE(1), -}; - -# if SPI_CALLBACK_MODE == true -/** Prototype for the device instance. */ -struct spi_module; - -/** Type of the callback functions. */ -typedef void (*spi_callback_t)(const struct spi_module *const module); - -# if !defined(__DOXYGEN__) -/** Prototype for the interrupt handler. */ -extern void _spi_interrupt_handler(uint8_t instance); -# endif -# endif - -/** - * \brief SERCOM SPI driver software device instance structure. - * - * SERCOM SPI driver software instance structure, used to retain software state - * information of an associated hardware module instance. - * - * \note The fields of this structure should not be altered by the user - * application; they are reserved for module-internal use only. - */ -struct spi_module { -# if !defined(__DOXYGEN__) - /** SERCOM hardware module. */ - Sercom *hw; - /** Module lock. */ - volatile bool locked; - /** SPI mode. */ - enum spi_mode mode; - /** SPI character size. */ - enum spi_character_size character_size; - /** Receiver enabled. */ - bool receiver_enabled; -# ifdef FEATURE_SPI_HARDWARE_SLAVE_SELECT - /** Enable Hardware Slave Select. */ - bool master_slave_select_enable; -# endif -# if SPI_CALLBACK_MODE == true - /** Direction of transaction. */ - volatile enum _spi_direction dir; - /** Array to store callback function pointers in. */ - spi_callback_t callback[SPI_CALLBACK_N]; - /** Buffer pointer to where the next received character will be put. */ - volatile uint8_t *rx_buffer_ptr; - /** Buffer pointer to where the next character will be transmitted from. - **/ - volatile uint8_t *tx_buffer_ptr; - /** Remaining characters to receive. */ - volatile uint16_t remaining_rx_buffer_length; - /** Remaining dummy characters to send when reading. */ - volatile uint16_t remaining_dummy_buffer_length; - /** Remaining characters to transmit. */ - volatile uint16_t remaining_tx_buffer_length; - /** Bit mask for callbacks registered. */ - uint8_t registered_callback; - /** Bit mask for callbacks enabled. */ - uint8_t enabled_callback; - /** Holds the status of the ongoing or last operation. */ - volatile enum status_code status; -# endif -# endif -}; - -/** - * \brief SPI peripheral slave instance structure - * - * SPI peripheral slave software instance structure, used to configure the - * correct SPI transfer mode settings for an attached slave. See - * \ref spi_select_slave. - */ -struct spi_slave_inst { - /** Pin to use as Slave Select. */ - uint8_t ss_pin; - /** Address recognition enabled in slave device. */ - bool address_enabled; - /** Address of slave device. */ - uint8_t address; -}; - -/** - * \brief SPI peripheral slave configuration structure - * - * SPI Peripheral slave configuration structure. - */ -struct spi_slave_inst_config { - /** Pin to use as Slave Select. */ - uint8_t ss_pin; - /** Enable address. */ - bool address_enabled; - /** Address of slave. */ - uint8_t address; -}; - -/** - * \brief SPI Master configuration structure - * - * SPI Master configuration structure. - */ -struct spi_master_config { - /** Baud rate. */ - uint32_t baudrate; -}; - -/** - * \brief SPI slave configuration structure - * - * SPI slave configuration structure. - */ -struct spi_slave_config { - /** Frame format. */ - enum spi_frame_format frame_format; - /** Address mode. */ - enum spi_addr_mode address_mode; - /** Address. */ - uint8_t address; - /** Address mask. */ - uint8_t address_mask; - /** Preload data to the shift register while SS is high. */ - bool preload_enable; -}; - -/** - * \brief SPI configuration structure - * - * Configuration structure for an SPI instance. This structure should be - * initialized by the \ref spi_get_config_defaults function before being - * modified by the user application. - */ -struct spi_config { - /** SPI mode. */ - enum spi_mode mode; - /** Data order. */ - enum spi_data_order data_order; - /** Transfer mode. */ - enum spi_transfer_mode transfer_mode; - /** MUX setting. */ - enum spi_signal_mux_setting mux_setting; - /** SPI character size. */ - enum spi_character_size character_size; - /** Enabled in sleep modes. */ - bool run_in_standby; - /** Enable receiver. */ - bool receiver_enable; -# ifdef FEATURE_SPI_SLAVE_SELECT_LOW_DETECT - /** Enable Slave Select Low Detect. */ - bool select_slave_low_detect_enable; -# endif -# ifdef FEATURE_SPI_HARDWARE_SLAVE_SELECT - /** Enable Master Slave Select. */ - bool master_slave_select_enable; -# endif - /** Union for slave or master specific configuration. */ - union { - /** Slave specific configuration. */ - struct spi_slave_config slave; - /** Master specific configuration. */ - struct spi_master_config master; - } mode_specific; - /** GCLK generator to use as clock source. */ - enum gclk_generator generator_source; - /** PAD0 pinmux. */ - uint32_t pinmux_pad0; - /** PAD1 pinmux. */ - uint32_t pinmux_pad1; - /** PAD2 pinmux. */ - uint32_t pinmux_pad2; - /** PAD3 pinmux. */ - uint32_t pinmux_pad3; -}; - -/** - * \brief Determines if the SPI module is currently synchronizing to the bus. - * - * This function will check if the underlying hardware peripheral module is - * currently synchronizing across multiple clock domains to the hardware bus. - * This function can be used to delay further operations on the module until it - * is ready. - * - * \param[in] module SPI hardware module - * - * \return Synchronization status of the underlying hardware module. - * \retval true Module synchronization is ongoing - * \retval false Module synchronization is not ongoing - * - */ -static inline bool spi_is_syncing( - struct spi_module *const module) -{ - /* Sanity check arguments */ - Assert(module); - Assert(module->hw); - - SercomSpi *const spi_module = &(module->hw->SPI); - -# ifdef FEATURE_SPI_SYNC_SCHEME_VERSION_2 - /* Return synchronization status */ - return (spi_module->SYNCBUSY.reg); -# else - /* Return synchronization status */ - return (spi_module->STATUS.reg & SERCOM_SPI_STATUS_SYNCBUSY); -# endif -} - -/** - * \name Driver Initialization and Configuration - * @{ - */ - -/** - * \brief Initializes an SPI configuration structure to default values - * - * This function will initialize a given SPI configuration structure to a set - * of known default values. This function should be called on any new - * instance of the configuration structures before being modified by the - * user application. - * - * The default configuration is as follows: - * \li Master mode enabled - * \li MSB of the data is transmitted first - * \li Transfer mode 0 - * \li MUX Setting D - * \li Character size eight bits - * \li Not enabled in sleep mode - * \li Receiver enabled - * \li Baudrate 100000 - * \li Default pinmux settings for all pads - * \li GCLK generator 0 - * - * \param[out] config Configuration structure to initialize to default values - */ -static inline void spi_get_config_defaults( - struct spi_config *const config) -{ - /* Sanity check arguments */ - Assert(config); - - /* Default configuration values */ - config->mode = SPI_MODE_MASTER; - config->data_order = SPI_DATA_ORDER_MSB; - config->transfer_mode = SPI_TRANSFER_MODE_0; - config->mux_setting = SPI_SIGNAL_MUX_SETTING_D; - config->character_size = SPI_CHARACTER_SIZE_8BIT; - config->run_in_standby = false; - config->receiver_enable = true; -# ifdef FEATURE_SPI_SLAVE_SELECT_LOW_DETECT - config->select_slave_low_detect_enable= true; -# endif -# ifdef FEATURE_SPI_HARDWARE_SLAVE_SELECT - config->master_slave_select_enable= false; -# endif - config->generator_source = GCLK_GENERATOR_0; - - /* Clear mode specific config */ - memset(&(config->mode_specific), 0, sizeof(config->mode_specific)); - - /* Master config defaults */ - config->mode_specific.master.baudrate = 100000; - - /* pinmux config defaults */ - config->pinmux_pad0 = PINMUX_DEFAULT; - config->pinmux_pad1 = PINMUX_DEFAULT; - config->pinmux_pad2 = PINMUX_DEFAULT; - config->pinmux_pad3 = PINMUX_DEFAULT; - -}; - -/** - * \brief Initializes an SPI peripheral slave device configuration structure to default values - * - * This function will initialize a given SPI slave device configuration - * structure to a set of known default values. This function should be called - * on any new instance of the configuration structures before being modified by - * the user application. - * - * The default configuration is as follows: - * \li Slave Select on GPIO pin 10 - * \li Addressing not enabled - * - * \param[out] config Configuration structure to initialize to default values - */ -static inline void spi_slave_inst_get_config_defaults( - struct spi_slave_inst_config *const config) -{ - Assert(config); - - config->ss_pin = 10; - config->address_enabled = false; - config->address = 0; -} - -/** - * \brief Attaches an SPI peripheral slave - * - * This function will initialize the software SPI peripheral slave, based on - * the values of the config struct. The slave can then be selected and - * optionally addressed by the \ref spi_select_slave function. - * - * \param[out] slave Pointer to the software slave instance struct - * \param[in] config Pointer to the config struct - * - */ -static inline void spi_attach_slave( - struct spi_slave_inst *const slave, - struct spi_slave_inst_config *const config) -{ - Assert(slave); - Assert(config); - - slave->ss_pin = config->ss_pin; - slave->address_enabled = config->address_enabled; - slave->address = config->address; - - /* Get default config for pin */ - struct port_config pin_conf; - port_get_config_defaults(&pin_conf); - - /* Edit config to set the pin as output */ - pin_conf.direction = PORT_PIN_DIR_OUTPUT; - - /* Set config on Slave Select pin */ - port_pin_set_config(slave->ss_pin, &pin_conf); - port_pin_set_output_level(slave->ss_pin, true); -} - -enum status_code spi_init( - struct spi_module *const module, - Sercom *const hw, - const struct spi_config *const config); - -/** @} */ - -/** - * \name Enable/Disable - * @{ - */ - -/** - * \brief Enables the SERCOM SPI module - * - * This function will enable the SERCOM SPI module. - * - * \param[in,out] module Pointer to the software instance struct - */ -static inline void spi_enable( - struct spi_module *const module) -{ - /* Sanity check arguments */ - Assert(module); - Assert(module->hw); - - SercomSpi *const spi_module = &(module->hw->SPI); - -# if SPI_CALLBACK_MODE == true - system_interrupt_enable(_sercom_get_interrupt_vector(module->hw)); -# endif - - while (spi_is_syncing(module)) { - /* Wait until the synchronization is complete */ - } - - /* Enable SPI */ - spi_module->CTRLA.reg |= SERCOM_SPI_CTRLA_ENABLE; -} - -/** - * \brief Disables the SERCOM SPI module - * - * This function will disable the SERCOM SPI module. - * - * \param[in,out] module Pointer to the software instance struct - */ -static inline void spi_disable( - struct spi_module *const module) -{ - /* Sanity check arguments */ - Assert(module); - Assert(module->hw); - - SercomSpi *const spi_module = &(module->hw->SPI); - -# if SPI_CALLBACK_MODE == true - system_interrupt_disable(_sercom_get_interrupt_vector(module->hw)); -# endif - - while (spi_is_syncing(module)) { - /* Wait until the synchronization is complete */ - } - - /* Disable SPI */ - spi_module->CTRLA.reg &= ~SERCOM_SPI_CTRLA_ENABLE; -} - -void spi_reset( - struct spi_module *const module); - -/** @} */ - -enum status_code spi_set_baudrate( - struct spi_module *const module, - uint32_t baudrate); - -/** - * \name Lock/Unlock - * @{ - */ - -/** - * \brief Attempt to get lock on driver instance - * - * This function checks the instance's lock, which indicates whether or not it - * is currently in use, and sets the lock if it was not already set. - * - * The purpose of this is to enable exclusive access to driver instances, so - * that, e.g., transactions by different services will not interfere with each - * other. - * - * \param[in,out] module Pointer to the driver instance to lock - * - * \retval STATUS_OK if the module was locked - * \retval STATUS_BUSY if the module was already locked - */ -static inline enum status_code spi_lock(struct spi_module *const module) -{ - enum status_code status; - - system_interrupt_enter_critical_section(); - - if (module->locked) { - status = STATUS_BUSY; - } else { - module->locked = true; - status = STATUS_OK; - } - - system_interrupt_leave_critical_section(); - - return status; -} - -/** - * \brief Unlock driver instance - * - * This function clears the instance lock, indicating that it is available for - * use. - * - * \param[in,out] module Pointer to the driver instance to lock - * - * \retval STATUS_OK if the module was locked - * \retval STATUS_BUSY if the module was already locked - */ -static inline void spi_unlock(struct spi_module *const module) -{ - module->locked = false; -} - -/** @} */ - -/** - * \name Ready to Write/Read - * @{ - */ - - /** - * \brief Checks if the SPI in master mode has shifted out last data, or if the master has ended the transfer in slave mode. - * - * This function will check if the SPI master module has shifted out last data, - * or if the slave select pin has been drawn high by the master for the SPI - * slave module. - * - * \param[in] module Pointer to the software instance struct - * - * \return Indication of whether any writes are ongoing. - * \retval true If the SPI master module has shifted out data, or slave select - * has been drawn high for SPI slave - * \retval false If the SPI master module has not shifted out data - */ -static inline bool spi_is_write_complete( - struct spi_module *const module) -{ - /* Sanity check arguments */ - Assert(module); - Assert(module->hw); - - SercomSpi *const spi_module = &(module->hw->SPI); - - /* Check interrupt flag */ - return (spi_module->INTFLAG.reg & SERCOM_SPI_INTFLAG_TXC); -} - - /** - * \brief Checks if the SPI module is ready to write data - * - * This function will check if the SPI module is ready to write data. - * - * \param[in] module Pointer to the software instance struct - * - * \return Indication of whether the module is ready to read data or not. - * \retval true If the SPI module is ready to write data - * \retval false If the SPI module is not ready to write data - */ -static inline bool spi_is_ready_to_write( - struct spi_module *const module) -{ - /* Sanity check arguments */ - Assert(module); - Assert(module->hw); - - SercomSpi *const spi_module = &(module->hw->SPI); - - /* Check interrupt flag */ - return (spi_module->INTFLAG.reg & SERCOM_SPI_INTFLAG_DRE); -} - -/** - * \brief Checks if the SPI module is ready to read data - * - * This function will check if the SPI module is ready to read data. - * - * \param[in] module Pointer to the software instance struct - * - * \return Indication of whether the module is ready to read data or not. - * \retval true If the SPI module is ready to read data - * \retval false If the SPI module is not ready to read data - */ -static inline bool spi_is_ready_to_read( - struct spi_module *const module) -{ - /* Sanity check arguments */ - Assert(module); - Assert(module->hw); - - SercomSpi *const spi_module = &(module->hw->SPI); - - /* Check interrupt flag */ - return (spi_module->INTFLAG.reg & SERCOM_SPI_INTFLAG_RXC); -} -/** @} */ - -/** - * \name Read/Write - * @{ - */ - - /** - * \brief Transfers a single SPI character - * - * This function will send a single SPI character via SPI and ignore any data - * shifted in by the connected device. To both send and receive data, use the - * \ref spi_transceive_wait function or use the \ref spi_read function after - * writing a character. The \ref spi_is_ready_to_write function - * should be called before calling this function. - * - * Note that this function does not handle the SS (Slave Select) - * pin(s) in master mode; this must be handled from the user application. - * - * \note In slave mode, the data will not be transferred before a master - * initiates a transaction. - * - * \param[in] module Pointer to the software instance struct - * \param[in] tx_data Data to transmit - * - * \return Status of the procedure. - * \retval STATUS_OK If the data was written - * \retval STATUS_BUSY If the last write was not completed - */ -static inline enum status_code spi_write( - struct spi_module *module, - uint16_t tx_data) -{ - /* Sanity check arguments */ - Assert(module); - Assert(module->hw); - - SercomSpi *const spi_module = &(module->hw->SPI); - - /* Check if the data register has been copied to the shift register */ - if (!spi_is_ready_to_write(module)) { - /* Data register has not been copied to the shift register, return */ - return STATUS_BUSY; - } - - /* Write the character to the DATA register */ - spi_module->DATA.reg = tx_data & SERCOM_SPI_DATA_MASK; - - return STATUS_OK; -} - -enum status_code spi_write_buffer_wait( - struct spi_module *const module, - const uint8_t *tx_data, - uint16_t length); - -/** - * \brief Reads last received SPI character - * - * This function will return the last SPI character shifted into the receive - * register by the \ref spi_write function. - * - * \note The \ref spi_is_ready_to_read function should be called before calling - * this function. - * - * \note Receiver must be enabled in the configuration. - * - * \param[in] module Pointer to the software instance struct - * \param[out] rx_data Pointer to store the received data - * - * \returns Status of the read operation. - * \retval STATUS_OK If data was read - * \retval STATUS_ERR_IO If no data is available - * \retval STATUS_ERR_OVERFLOW If the data is overflown - */ -static inline enum status_code spi_read( - struct spi_module *const module, - uint16_t *rx_data) -{ - /* Sanity check arguments */ - Assert(module); - Assert(module->hw); - - SercomSpi *const spi_module = &(module->hw->SPI); - - /* Check if data is ready to be read */ - if (!spi_is_ready_to_read(module)) { - /* No data has been received, return */ - return STATUS_ERR_IO; - } - - /* Return value */ - enum status_code retval = STATUS_OK; - - /* Check if data is overflown */ - if (spi_module->STATUS.reg & SERCOM_SPI_STATUS_BUFOVF) { - retval = STATUS_ERR_OVERFLOW; - /* Clear overflow flag */ - spi_module->STATUS.reg |= SERCOM_SPI_STATUS_BUFOVF; - } - - /* Read the character from the DATA register */ - if (module->character_size == SPI_CHARACTER_SIZE_9BIT) { - *rx_data = (spi_module->DATA.reg & SERCOM_SPI_DATA_MASK); - } else { - *rx_data = (uint8_t)spi_module->DATA.reg; - } - - return retval; -} - -enum status_code spi_read_buffer_wait( - struct spi_module *const module, - uint8_t *rx_data, - uint16_t length, - uint16_t dummy); - -enum status_code spi_transceive_wait( - struct spi_module *const module, - uint16_t tx_data, - uint16_t *rx_data); - -enum status_code spi_transceive_buffer_wait( - struct spi_module *const module, - uint8_t *tx_data, - uint8_t *rx_data, - uint16_t length); - -enum status_code spi_select_slave( - struct spi_module *const module, - struct spi_slave_inst *const slave, - bool select); - -/** @} */ - -#ifdef __cplusplus -} -#endif - -/** @} */ - - -/** - * \page asfdoc_sam0_sercom_spi_extra Extra Information for SERCOM SPI Driver - * - * \section asfdoc_sam0_sercom_spi_extra_acronyms Acronyms - * Below is a table listing the acronyms used in this module, along with their - * intended meanings. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
AcronymDescription
SERCOMSerial Communication Interface
SPISerial Peripheral Interface
SCKSerial Clock
MOSIMaster Output Slave Input
MISOMaster Input Slave Output
SSSlave Select
DIOData Input Output
DOData Output
DIData Input
DMADirect Memory Access
- * - * \section asfdoc_sam0_sercom_spi_extra_dependencies Dependencies - * The SPI driver has the following dependencies: - * \li \ref asfdoc_sam0_system_pinmux_group "System Pin Multiplexer Driver" - * - * - * \section asfdoc_sam0_sercom_spi_extra_workarounds Workarounds Implemented by Driver - * No workarounds in driver. - * - * \section asfdoc_sam0_sercom_spi_extra_history Module History - * An overview of the module history is presented in the table below, with - * details on the enhancements and fixes made to the module since its first - * release. The current version of this corresponds to the newest version in the table. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Changelog
Add SAML21 support
Add SAMD21 support and added new features as below: - * \li Slave select low detect - * \li Hardware slave select - * \li DMA support
Edited slave part of write and transceive buffer functions to ensure - * that second character is sent at the right time
Renamed the anonymous union in \c struct spi_config to - * \c mode_specific
Initial Release
- */ - -/** - * \page asfdoc_sam0_sercom_spi_exqsg Examples for SERCOM SPI Driver - * - * This is a list of the available Quick Start guides (QSGs) and example - * applications for \ref asfdoc_sam0_sercom_spi_group. QSGs are simple examples with - * step-by-step instructions to configure and use this driver in a selection of - * use cases. Note that QSGs can be compiled as a standalone application or be - * added to the user application. - * - * - \subpage asfdoc_sam0_sercom_spi_master_basic_use - * - \subpage asfdoc_sam0_sercom_spi_slave_basic_use - * \if SPI_CALLBACK_MODE - * - \subpage asfdoc_sam0_sercom_spi_master_callback_use - * - \subpage asfdoc_sam0_sercom_spi_slave_callback_use - * \endif - * - \subpage asfdoc_sam0_sercom_spi_dma_use_case - */ - - /** - * \page asfdoc_sam0_sercom_spi_mux_settings MUX Settings - * - * The following lists the possible internal SERCOM module pad function - * assignments, for the four SERCOM pads in both SPI Master, and SPI Slave - * modes. Note that this is in addition to the physical GPIO pin MUX of the - * device, and can be used in conjunction to optimize the serial data pin-out. - * - * \section asfdoc_sam0_sercom_spi_mux_settings_master Master Mode Settings - * The following table describes the SERCOM pin functionalities for the various - * MUX settings, whilst in SPI Master mode. - * - * \note If MISO is unlisted, the SPI receiver must not be enabled for the - * given MUX setting. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
MUX/PadPAD 0PAD 1PAD 2PAD 3
AMOSISCK--
BMOSISCK--
CMOSISCKMISO-
DMOSISCK-MISO
EMISO-MOSISCK
F-MISOMOSISCK
G--MOSISCK
H--MOSISCK
I (1)MISOSCK-MOSI
J (1)-SCK-MOSI
K (1)-SCKMISOMOSI
L (1)-SCK-MOSI
M (1)MOSI--SCK
N (1)MOSIMISO-SCK
O (1)MOSI-MISOSCK
P (1)MOSI--SCK
- * - * (1) Not available in all silicon revisions. - * - * \section asfdoc_sam0_sercom_spi_mux_settings_slave Slave Mode Settings - * The following table describes the SERCOM pin functionalities for the various - * MUX settings, whilst in SPI Slave mode. - * - * \note If MISO is unlisted, the SPI receiver must not be enabled for the - * given MUX setting. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
MUX/PadPAD 0PAD 1PAD 2PAD 3
AMISOSCK/SS-
BMISOSCK/SS-
CMISOSCK/SS-
DMISOSCK/SSMOSI
EMOSI/SSMISOSCK
F-/SSMISOSCK
G-/SSMISOSCK
H-/SSMISOSCK
I (1)MOSISCK/SSMISO
J (1)-SCK/SSMISO
K (1)-SCK/SSMISO
L (1)-SCK/SSMISO
M (1)MISO/SS-SCK
N (1)MISO/SS-SCK
O (1)MISO/SSMOSISCK
P (1)MISO/SS-SCK
- * - * (1) Not available in all silicon revisions. - * - * - * \page asfdoc_sam0_sercom_spi_document_revision_history Document Revision History - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Doc. Rev. - * Date - * Comments - *
E11/2014Add SAM L21 support.
D12/2014Add SAM R21/D10/D11 support.
C01/2014Add SAM D21 support.
B11/2013Replaced the pad multiplexing documentation with a condensed table.
A06/2013Initial release
- */ - -#endif /* SPI_H_INCLUDED */ diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/objects.h b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/objects.h index 758d89b2c7..2ce40bb12e 100644 --- a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/objects.h +++ b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/objects.h @@ -71,11 +71,20 @@ struct can_s { struct i2c_s { LPC_I2C_TypeDef *i2c; }; +*/ struct spi_s { - LPC_SSP_TypeDef *spi; + Sercom *spi; + uint8_t mode; +#if DEVICE_SPI_ASYNCH + uint8_t status; + uint32_t mask; + uint32_t event; + void *tx_buffer; + void *rx_buffer; +#endif }; -*/ + #ifdef __cplusplus } #endif diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/spi_api.c b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/spi_api.c new file mode 100644 index 0000000000..fbdbb8903b --- /dev/null +++ b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/spi_api.c @@ -0,0 +1,772 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "mbed_assert.h" +#include "spi_api.h" + +#include + +#include "cmsis.h" +#include "pinmap.h" +#include "sercom.h" + +//////////////////////////////////////// +#define EXT1_SPI_MODULE SERCOM5 +#define EXT1_SPI_SERCOM_MUX_SETTING ((0x1 << SERCOM_SPI_CTRLA_DOPO_Pos) | (0x0 << SERCOM_SPI_CTRLA_DIPO_Pos)) +#define EXT1_SPI_SERCOM_PINMUX_PAD0 PINMUX_PB02D_SERCOM5_PAD0 +#define EXT1_SPI_SERCOM_PINMUX_PAD1 PINMUX_PB03D_SERCOM5_PAD1 +#define EXT1_SPI_SERCOM_PINMUX_PAD2 PINMUX_PB22D_SERCOM5_PAD2 +#define EXT1_SPI_SERCOM_PINMUX_PAD3 PINMUX_PB23D_SERCOM5_PAD3 +#define EXT1_SPI_SERCOM_DMAC_ID_TX SERCOM5_DMAC_ID_TX +#define EXT1_SPI_SERCOM_DMAC_ID_RX SERCOM5_DMAC_ID_RX + +/** Default pinmux. */ +# define PINMUX_DEFAULT 0 + +/** Unused pinmux. */ +# define PINMUX_UNUSED 0xFFFFFFFF +//////////////////////////////////////// + +#if DEVICE_SPI_ASYNCH +#define pSPI_S(obj) obj->spi.spi +#else +#define pSPI_S(obj) obj->spi +#endif +#define _SPI(obj) pSPI_S(obj)->SPI + +/** SPI default baud rate. */ +#define SPI_DEFAULT_BAUD 50000//100000 + + +/** SPI timeout value. */ +# define SPI_TIMEOUT 10000 + +#if DEVICE_SPI_ASYNCH +/* Global variables */ +void *_sercom_instances[SERCOM_INST_NUM] = {0}; + +static void _spi_transceive_buffer(spi_t *obj); + +/** \internal + * Generates a SERCOM interrupt handler function for a given SERCOM index. + */ +#define _SERCOM_SPI_INTERRUPT_HANDLER(n, unused) \ +void SERCOM##n##_SPIHandler(void) \ +{ \ + _spi_transceive_buffer((spi_t *)_sercom_instances[n]); \ +} +#define _SERCOM_SPI_INTERRUPT_HANDLER_DECLR(n, unused) \ + (uint32_t)SERCOM##n##_SPIHandler, + +/** Auto-generate a set of interrupt handlers for each SERCOM SPI in the device */ +MREPEAT(SERCOM_INST_NUM, _SERCOM_SPI_INTERRUPT_HANDLER, ~) + +uint32_t _sercom_handlers[SERCOM_INST_NUM] = { + MREPEAT(SERCOM_INST_NUM, _SERCOM_SPI_INTERRUPT_HANDLER_DECLR, ~) + }; +#endif + +static inline bool spi_is_syncing(spi_t *obj) +{ + /* Sanity check arguments */ + MBED_ASSERT(obj); + + /* Return synchronization status */ + return (_SPI(obj).SYNCBUSY.reg); +} + +static inline void spi_enable(spi_t *obj) +{ + /* Sanity check arguments */ + MBED_ASSERT(obj); + +#if DEVICE_SPI_ASYNCH + /* Enable interrupt */ + NVIC_EnableIRQ(SERCOM0_IRQn + _sercom_get_sercom_inst_index(pSPI_S(obj))); +#endif + + /* Wait until the synchronization is complete */ + while (spi_is_syncing(obj)); + + /* Enable SPI */ + _SPI(obj).CTRLA.reg |= SERCOM_SPI_CTRLA_ENABLE; +} + +static inline void spi_disable(spi_t *obj) +{ + /* Sanity check arguments */ + MBED_ASSERT(obj); + +#if DEVICE_SPI_ASYNCH + /* Disable interrupt */ + NVIC_DisableIRQ(SERCOM0_IRQn + _sercom_get_sercom_inst_index(pSPI_S(obj))); +#endif + /* Wait until the synchronization is complete */ + while (spi_is_syncing(obj)); + + /* Disable SPI */ + _SPI(obj).CTRLA.reg &= ~SERCOM_SPI_CTRLA_ENABLE; +} + +static inline bool spi_is_write_complete(spi_t *obj) +{ + /* Sanity check arguments */ + MBED_ASSERT(obj); + + /* Check interrupt flag */ + return (_SPI(obj).INTFLAG.reg & SERCOM_SPI_INTFLAG_TXC); +} + +static inline bool spi_is_ready_to_write(spi_t *obj) +{ + /* Sanity check arguments */ + MBED_ASSERT(obj); + + /* Check interrupt flag */ + return (_SPI(obj).INTFLAG.reg & SERCOM_SPI_INTFLAG_DRE); +} + +static inline bool spi_is_ready_to_read(spi_t *obj) +{ + /* Sanity check arguments */ + MBED_ASSERT(obj); + + /* Check interrupt flag */ + return (_SPI(obj).INTFLAG.reg & SERCOM_SPI_INTFLAG_RXC); +} + +static inline bool spi_write(spi_t *obj, uint16_t tx_data) +{ + /* Sanity check arguments */ + MBED_ASSERT(obj); + + /* Check if the data register has been copied to the shift register */ + if (!spi_is_ready_to_write(obj)) { + /* Data register has not been copied to the shift register, return */ + return 0; + } + + /* Write the character to the DATA register */ + _SPI(obj).DATA.reg = tx_data & SERCOM_SPI_DATA_MASK; + + return 1; +} + +static inline bool spi_read(spi_t *obj, uint16_t *rx_data) +{ + /* Sanity check arguments */ + MBED_ASSERT(obj); + + /* Check if data is ready to be read */ + if (!spi_is_ready_to_read(obj)) { + /* No data has been received, return */ + return 0; + } + + /* Check if data is overflown */ + if (_SPI(obj).STATUS.reg & SERCOM_SPI_STATUS_BUFOVF) { + /* Clear overflow flag */ + _SPI(obj).STATUS.reg |= SERCOM_SPI_STATUS_BUFOVF; + } + + /* Read the character from the DATA register */ + if (_SPI(obj).CTRLB.bit.CHSIZE == 1) { + *rx_data = (_SPI(obj).DATA.reg & SERCOM_SPI_DATA_MASK); + } else { + *rx_data = (uint8_t)_SPI(obj).DATA.reg; + } + + return 1; +} + +/** + * \defgroup GeneralSPI SPI Configuration Functions + * @{ + */ + +/** Initialize the SPI peripheral + * + * Configures the pins used by SPI, sets a default format and frequency, and enables the peripheral + * @param[out] obj The SPI object to initialize + * @param[in] mosi The pin to use for MOSI + * @param[in] miso The pin to use for MISO + * @param[in] sclk The pin to use for SCLK + * @param[in] ssel The pin to use for SSEL + */ +void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel) { + uint16_t baud = 0; + uint32_t ctrla = 0; + uint32_t ctrlb = 0; + enum status_code error_code; + + // TODO: Calculate SERCOM instance from pins + // TEMP: Giving our own value for testing + pSPI_S(obj) = EXT1_SPI_MODULE; + + /* Disable SPI */ + spi_disable(obj); + + /* Check if reset is in progress. */ + if (_SPI(obj).CTRLA.reg & SERCOM_SPI_CTRLA_SWRST){ + return; + } + uint32_t sercom_index = _sercom_get_sercom_inst_index(pSPI_S(obj)); + uint32_t pm_index, gclk_index; +#if (SAML21) + if (sercom_index == 5) { + pm_index = MCLK_APBDMASK_SERCOM5_Pos; + gclk_index = SERCOM5_GCLK_ID_CORE; + } else { + pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos; + gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; + } +#else + pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos; + gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; +#endif + + /* Turn on module in PM */ +#if (SAML21) + if (sercom_index == 5) { + system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBD, 1 << pm_index); + } else { + system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index); + } +#else + system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index); +#endif + + /* Set up the GCLK for the module */ + struct system_gclk_chan_config gclk_chan_conf; + system_gclk_chan_get_config_defaults(&gclk_chan_conf); + gclk_chan_conf.source_generator = GCLK_GENERATOR_0; + system_gclk_chan_set_config(gclk_index, &gclk_chan_conf); + system_gclk_chan_enable(gclk_index); + sercom_set_gclk_generator(GCLK_GENERATOR_0, false); + +#if DEVICE_SPI_ASYNCH + /* Save the object */ + _sercom_instances[sercom_index] = obj; + + /* Configure interrupt handler */ + NVIC_SetVector((SERCOM0_IRQn + sercom_index), (uint32_t)_sercom_handlers[sercom_index]); +#endif + + /* Set the SERCOM in SPI master mode */ + _SPI(obj).CTRLA.reg |= SERCOM_SPI_CTRLA_MODE(0x3); + + // TODO: Do pin muxing here + struct system_pinmux_config pin_conf; + system_pinmux_get_config_defaults(&pin_conf); + pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; + //if(config->mode == SPI_MODE_SLAVE) { + //pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE; + //} + + uint32_t pad_pinmuxes[] = { + EXT1_SPI_SERCOM_PINMUX_PAD0, EXT1_SPI_SERCOM_PINMUX_PAD1, + EXT1_SPI_SERCOM_PINMUX_PAD2, EXT1_SPI_SERCOM_PINMUX_PAD3 + }; + + /* Configure the SERCOM pins according to the user configuration */ + for (uint8_t pad = 0; pad < 4; pad++) { + uint32_t current_pinmux = pad_pinmuxes[pad]; + + if (current_pinmux == PINMUX_DEFAULT) { + current_pinmux = _sercom_get_default_pad(pSPI_S(obj), pad); + } + + if (current_pinmux != PINMUX_UNUSED) { + pin_conf.mux_position = current_pinmux & 0xFFFF; + system_pinmux_pin_set_config(current_pinmux >> 16, &pin_conf); + } + } + + /* Get baud value, based on baudrate and the internal clock frequency */ + uint32_t internal_clock = system_gclk_chan_get_hz(gclk_index); + //internal_clock = 8000000; + error_code = _sercom_get_sync_baud_val(SPI_DEFAULT_BAUD, internal_clock, &baud); + if (error_code != STATUS_OK) { + /* Baud rate calculation error */ + return; + } + _SPI(obj).BAUD.reg = (uint8_t)baud; + + /* Set MUX setting */ + ctrla |= EXT1_SPI_SERCOM_MUX_SETTING; // TODO: Change this to appropriate Settings + + /* Set SPI character size */ + ctrlb |= SERCOM_SPI_CTRLB_CHSIZE(0); + + /* Enable receiver */ + ctrlb |= SERCOM_SPI_CTRLB_RXEN; + + /* Write CTRLA register */ + _SPI(obj).CTRLA.reg |= ctrla; + + /* Write CTRLB register */ + _SPI(obj).CTRLB.reg |= ctrlb; + + /* Enable SPI */ + spi_enable(obj); +} + +/** Release a SPI object + * + * TODO: spi_free is currently unimplemented + * This will require reference counting at the C++ level to be safe + * + * Return the pins owned by the SPI object to their reset state + * Disable the SPI peripheral + * Disable the SPI clock + * @param[in] obj The SPI object to deinitialize + */ +void spi_free(spi_t *obj) { + // [TODO] +} + +/** Configure the SPI format + * + * Set the number of bits per frame, configure clock polarity and phase, shift order and master/slave mode + * @param[in,out] obj The SPI object to configure + * @param[in] bits The number of bits per frame + * @param[in] mode The SPI mode (clock polarity, phase, and shift direction) + * @param[in] slave Zero for master mode or non-zero for slave mode + */ +void spi_format(spi_t *obj, int bits, int mode, int slave) { + + /* Disable SPI */ + spi_disable(obj); + + /* Set the SERCOM in SPI mode */ + _SPI(obj).CTRLA.bit.MODE = slave? 0x2 : 0x3; + + /* Set SPI Frame size - only 8-bit and 9-bit supported now */ + _SPI(obj).CTRLB.bit.CHSIZE = (bits > 8)? 1 : 0; + + /* Set SPI Clock Phase */ + _SPI(obj).CTRLA.bit.CPHA = (mode & 0x01)? 1 : 0; + + /* Set SPI Clock Polarity */ + _SPI(obj).CTRLA.bit.CPOL = (mode & 0x02)? 1 : 0; + + /* Enable SPI */ + spi_enable(obj); +} + +/** Set the SPI baud rate + * + * Actual frequency may differ from the desired frequency due to available dividers and bus clock + * Configures the SPI peripheral's baud rate + * @param[in,out] obj The SPI object to configure + * @param[in] hz The baud rate in Hz + */ +void spi_frequency(spi_t *obj, int hz) { + uint16_t baud = 0; + + /* Disable SPI */ + spi_disable(obj); + + /* Find frequency of the internal SERCOMi_GCLK_ID_CORE */ + uint32_t sercom_index = _sercom_get_sercom_inst_index(pSPI_S(obj)); + uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; + uint32_t internal_clock = system_gclk_chan_get_hz(gclk_index); + + /* Get baud value, based on baudrate and the internal clock frequency */ + enum status_code error_code = _sercom_get_sync_baud_val(hz, internal_clock, &baud); + + if (error_code != STATUS_OK) { + /* Baud rate calculation error, return status code */ + /* Enable SPI */ + spi_enable(obj); + return; + } + + _SPI(obj).BAUD.reg = (uint8_t)baud; + + /* Enable SPI */ + spi_enable(obj); +} + +/**@}*/ +/** + * \defgroup SynchSPI Synchronous SPI Hardware Abstraction Layer + * @{ + */ + +/** Write a byte out in master mode and receive a value + * + * @param[in] obj The SPI peripheral to use for sending + * @param[in] value The value to send + * @return Returns the value received during send + */ +int spi_master_write(spi_t *obj, int value) { + uint16_t rx_data = 0; + + /* Sanity check arguments */ + MBED_ASSERT(obj); + +#if DEVICE_SPI_ASYNCH + if (obj->spi.status == STATUS_BUSY) { + /* Check if the SPI module is busy with a job */ + return 0; + } +#endif + + /* Wait until the module is ready to write the character */ + while (!spi_is_ready_to_write(obj)); + + /* Write data */ + spi_write(obj, value); + + if (!(_SPI(obj).CTRLB.bit.RXEN)) { + return 0; + } + + /* Wait until the module is ready to read the character */ + while (!spi_is_ready_to_read(obj)); + + /* Read data */ + spi_read(obj, &rx_data); + + return rx_data; +} + +/** Check if a value is available to read + * + * @param[in] obj The SPI peripheral to check + * @return non-zero if a value is available + */ +int spi_slave_receive(spi_t *obj) { + /* Sanity check arguments */ + MBED_ASSERT(obj); + + return spi_is_ready_to_read(obj); +} + +/** Get a received value out of the SPI receive buffer in slave mode + * + * Blocks until a value is available + * @param[in] obj The SPI peripheral to read + * @return The value received + */ +int spi_slave_read(spi_t *obj) { + int i; + uint16_t rx_data = 0; + + /* Sanity check arguments */ + MBED_ASSERT(obj); + + /* Check for timeout period */ + for (i = 0; i < SPI_TIMEOUT; i++) { + if (spi_is_ready_to_read(obj)) { + break; + } + } + if (i == SPI_TIMEOUT) { + /* Not ready to read data within timeout period */ + return 0; + } + + /* Read data */ + spi_read(obj, &rx_data); + + return rx_data; +} + +/** Write a value to the SPI peripheral in slave mode + * + * Blocks until the SPI peripheral can be written to + * @param[in] obj The SPI peripheral to write + * @param[in] value The value to write + */ +void spi_slave_write(spi_t *obj, int value) { + int i; + + /* Sanity check arguments */ + MBED_ASSERT(obj); + + /* Check for timeout period */ + for (i = 0; i < SPI_TIMEOUT; i++) { + if (spi_is_ready_to_write(obj)) { + break; + } + } + if (i == SPI_TIMEOUT) { + /* Not ready to write data within timeout period */ + return; + } + + /* Write data */ + spi_write(obj, value); +} + +/** Checks if the specified SPI peripheral is in use + * + * @param[in] obj The SPI peripheral to check + * @return non-zero if the peripheral is currently transmitting + */ +int spi_busy(spi_t *obj) +{ + /* Sanity check arguments */ + MBED_ASSERT(obj); + + return spi_is_write_complete(obj); +} + +/** Get the module number + * + * @param[in] obj The SPI peripheral to check + * @return The module number + */ +uint8_t spi_get_module(spi_t *obj) +{ + /* Sanity check arguments */ + MBED_ASSERT(obj); + return _sercom_get_sercom_inst_index(pSPI_S(obj)); +} + + +#if DEVICE_SPI_ASYNCH +/** + * \defgroup AsynchSPI Asynchronous SPI Hardware Abstraction Layer + * @{ + */ + + +/** + * \internal + * Writes a character from the TX buffer to the Data register. + * + * \param[in,out] module Pointer to SPI software instance struct + */ +static void _spi_write_async(spi_t *obj) +{ + /* Sanity check arguments */ + MBED_ASSERT(obj); + + uint16_t data_to_send; + uint8_t *tx_buffer = obj->tx_buff.buffer; + + /* Do nothing if we are at the end of buffer */ + if (obj->tx_buff.pos < obj->tx_buff.length) { + /* Write value will be at least 8-bits long */ + data_to_send = tx_buffer[obj->tx_buff.pos]; + /* Increment 8-bit index */ + obj->tx_buff.pos++; + + if (_SPI(obj).CTRLB.bit.CHSIZE == 1) { + data_to_send |= (tx_buffer[obj->tx_buff.pos] << 8); + /* Increment 8-bit index */ + obj->tx_buff.pos++; + } + } else { + /* Write a dummy packet */ + data_to_send = ~0; + } + + /* Write the data to send*/ + _SPI(obj).DATA.reg = data_to_send & SERCOM_SPI_DATA_MASK; + + /* Check for error */ + if ((_SPI(obj).INTFLAG.reg & SERCOM_SPI_INTFLAG_ERROR) && (obj->spi.mask & SPI_EVENT_ERROR)) { + obj->spi.event != SPI_EVENT_ERROR; + } +} + +/** + * \internal + * Reads a character from the Data register to the RX buffer. + * + * \param[in,out] module Pointer to SPI software instance struct + */ +static void _spi_read_async(spi_t *obj) +{ + /* Sanity check arguments */ + MBED_ASSERT(obj); + + uint8_t *rx_buffer = obj->rx_buff.buffer; + + /* Check if data is overflown */ + if (_SPI(obj).STATUS.reg & SERCOM_SPI_STATUS_BUFOVF) { + /* Clear overflow flag */ + _SPI(obj).STATUS.reg |= SERCOM_SPI_STATUS_BUFOVF; + if (obj->spi.mask & SPI_EVENT_RX_OVERFLOW) { + /* Set overflow error */ + obj->spi.event != SPI_EVENT_RX_OVERFLOW; + return; + } + } + + /* Read data, either valid, or dummy */ + uint16_t received_data = (_SPI(obj).DATA.reg & SERCOM_SPI_DATA_MASK); + + /* Do nothing if we are at the end of buffer */ + if (obj->rx_buff.pos >= obj->rx_buff.length) { + return; + } + + /* Read value will be at least 8-bits long */ + rx_buffer[obj->rx_buff.pos] = received_data; + /* Increment 8-bit index */ + obj->rx_buff.pos++; + + if (_SPI(obj).CTRLB.bit.CHSIZE == 1) { + /* 9-bit data, write next received byte to the buffer */ + rx_buffer[obj->rx_buff.pos] = (received_data >> 8); + /* Increment 8-bit index */ + obj->rx_buff.pos++; + } + + /* Check for error */ + if ((_SPI(obj).INTFLAG.reg & SERCOM_SPI_INTFLAG_ERROR) && (obj->spi.mask & SPI_EVENT_ERROR)) { + obj->spi.event != SPI_EVENT_ERROR; + } +} + +/** + * \internal + * Starts transceive of buffers with a given length + * + * \param[in] obj Pointer to SPI software instance struct + * + */ +static void _spi_transceive_buffer(spi_t *obj) +{ + /* Sanity check arguments */ + MBED_ASSERT(obj); + + uint16_t interrupt_status = _SPI(obj).INTFLAG.reg; + + uint8_t sercom_index = _sercom_get_sercom_inst_index(obj->spi.spi); + + /* Disable all interrupt handlers for now + _SPI(obj).INTENCLR.reg = interrupt_status;*/ + + interrupt_status &= _SPI(obj).INTENSET.reg; + + if (interrupt_status & SERCOM_SPI_INTFLAG_DRE) { + _spi_write_async(obj); + } + + if (interrupt_status & SERCOM_SPI_INTFLAG_RXC) { + _spi_read_async(obj); + } + + if ((obj->spi.event & SPI_EVENT_ERROR) || (obj->spi.event & SPI_EVENT_RX_OVERFLOW)) { + /* Disable all interrupts */ + _SPI(obj).INTENCLR.reg = + SERCOM_SPI_INTFLAG_DRE | + SERCOM_SPI_INTFLAG_TXC | + SERCOM_SPI_INTFLAG_RXC | + SERCOM_SPI_INTFLAG_ERROR; + NVIC_DisableIRQ(SERCOM0_IRQn + sercom_index); + + /* Transfer complete, invoke the callback function */ + if (obj->spi.event & SPI_EVENT_RX_OVERFLOW) { + obj->spi.status = STATUS_ERR_OVERFLOW; + } else { + obj->spi.status = STATUS_ERR_BAD_DATA; + } + // TODO: Invoke callback + return; + } + + if (interrupt_status & (SERCOM_SPI_INTFLAG_TXC | SERCOM_SPI_INTFLAG_RXC)) { + if ((obj->tx_buff.pos >= obj->tx_buff.length) && (obj->rx_buff.pos >= obj->rx_buff.length)) { + /* Clear all interrupts */ + _SPI(obj).INTENCLR.reg = + SERCOM_SPI_INTFLAG_DRE | + SERCOM_SPI_INTFLAG_TXC | + SERCOM_SPI_INTFLAG_RXC | + SERCOM_SPI_INTFLAG_ERROR; + NVIC_DisableIRQ(SERCOM0_IRQn + sercom_index); + NVIC_SetVector((SERCOM0_IRQn + sercom_index), (uint32_t)NULL); + + /* Transfer complete, invoke the callback function */ + obj->spi.event |= SPI_EVENT_COMPLETE; + // TODO: Invoke callback + return; + } + } + + /* Enable back interrupts + _SPI(obj).INTENSET.reg = interrupt_status;*/ +} + +/** Begin the SPI transfer. Buffer pointers and lengths are specified in tx_buff and rx_buff + * + * @param[in] obj The SPI object which holds the transfer information + * @param[in] tx The buffer to send + * @param[in] tx_length The number of words to transmit + * @param[in] rx The buffer to receive + * @param[in] rx_length The number of words to receive + * @param[in] bit_width The bit width of buffer words + * @param[in] event The logical OR of events to be registered + * @param[in] handler SPI interrupt handler + * @param[in] hint A suggestion for how to use DMA with this transfer **< DMA currently not implemented >** + */ +void spi_master_transfer(spi_t *obj, void *tx, size_t tx_length, void *rx, size_t rx_length, uint8_t bit_width, uint32_t handler, uint32_t event, DMAUsage hint) +{ + // TODO: +} + +/** The asynchronous IRQ handler + * + * Reads the received values out of the RX FIFO, writes values into the TX FIFO and checks for transfer termination + * conditions, such as buffer overflows or transfer complete. + * @param[in] obj The SPI object which holds the transfer information + * @return event flags if a transfer termination condition was met or 0 otherwise. + */ +uint32_t spi_irq_handler_asynch(spi_t *obj) +{ + return 0; +} + +/** Attempts to determine if the SPI peripheral is already in use. + * @param[in] obj The SPI object to check for activity + * @return non-zero if the SPI port is active or zero if it is not. + */ +uint8_t spi_active(spi_t *obj) +{ + return 0; +} + +/** Abort an SPI transfer + * + * @param obj The SPI peripheral to stop + */ +void spi_abort_asynch(spi_t *obj) +{ + /* Sanity check arguments */ + MBED_ASSERT(obj); + + uint8_t sercom_index = _sercom_get_sercom_inst_index(obj->spi.spi); + + /* Clear all interrupts */ + _SPI(obj).INTENCLR.reg = + SERCOM_SPI_INTFLAG_DRE | + SERCOM_SPI_INTFLAG_TXC | + SERCOM_SPI_INTFLAG_RXC | + SERCOM_SPI_INTFLAG_ERROR; + + // TODO: Disable and remove irq handler + NVIC_DisableIRQ(SERCOM0_IRQn + sercom_index); + NVIC_SetVector((SERCOM0_IRQn + sercom_index), NULL); + + obj->spi.status = STATUS_ABORTED; +} + +#endif diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/us_ticker.c b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/us_ticker.c index 56356d102f..5458bdd135 100644 --- a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/us_ticker.c +++ b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/us_ticker.c @@ -22,6 +22,10 @@ #include "tc.h" #include "tc_interrupt.h" +#define TICKER_COUNTER_uS TC4 +#define TICKER_COUNTER_IRQn TC4_IRQn +#define TICKER_COUNTER_Handlr TC4_Handler + static int us_ticker_inited = 0; struct tc_module us_ticker_module; @@ -30,8 +34,8 @@ void us_ticker_irq_handler_internal(struct tc_module* us_tc_module) { us_ticker_irq_handler(); - /* Disable the callback */ - tc_disable_callback(us_tc_module, TC_CALLBACK_CC_CHANNEL0); + /* Disable the interrupt */ + us_ticker_disable_interrupt(); } void us_ticker_init(void) @@ -55,13 +59,14 @@ void us_ticker_init(void) } config_tc.clock_prescaler = TC_CTRLA_PRESCALER(prescaler); config_tc.counter_size = TC_COUNTER_SIZE_32BIT; + config_tc.run_in_standby = true; config_tc.counter_32_bit.value = 0; config_tc.counter_32_bit.compare_capture_channel[0] = 0xFFFFFFFF; //config_tc.oneshot = true; /* Initialize the timer */ - ret_status = tc_init(&us_ticker_module, TC4, &config_tc); + ret_status = tc_init(&us_ticker_module, TICKER_COUNTER_uS, &config_tc); MBED_ASSERT(ret_status == STATUS_OK); /* Register callback function */ @@ -92,9 +97,12 @@ void us_ticker_set_interrupt(timestamp_t timestamp) us_ticker_irq_handler(); return; } - + tc_set_compare_value(&us_ticker_module, TC_CALLBACK_CC_CHANNEL0, timestamp); + NVIC_SetVector(TICKER_COUNTER_IRQn, (uint32_t)TICKER_COUNTER_Handlr); + NVIC_EnableIRQ(TICKER_COUNTER_IRQn); + /* Enable the callback */ tc_enable_callback(&us_ticker_module, TC_CALLBACK_CC_CHANNEL0); @@ -105,9 +113,13 @@ void us_ticker_set_interrupt(timestamp_t timestamp) void us_ticker_disable_interrupt(void) { /* Disable the callback */ tc_disable_callback(&us_ticker_module, TC_CALLBACK_CC_CHANNEL0); + NVIC_DisableIRQ(TICKER_COUNTER_IRQn); } void us_ticker_clear_interrupt(void) { - /* Disable the callback */ - tc_disable_callback(&us_ticker_module, TC_CALLBACK_CC_CHANNEL0); + /* Disable the interrupt, this is clear the interrupt also */ + us_ticker_disable_interrupt(); + + NVIC_DisableIRQ(TICKER_COUNTER_IRQn); + NVIC_SetVector(TICKER_COUNTER_IRQn, (uint32_t)NULL); } \ No newline at end of file