mirror of https://github.com/ARMmbed/mbed-os.git
Adding untested code for SPI support in SAM21
parent
cbcf0a8ed7
commit
fa85c6f74d
|
@ -16,11 +16,13 @@
|
||||||
#include "mbed_assert.h"
|
#include "mbed_assert.h"
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
|
|
||||||
|
#include "system.h"
|
||||||
|
|
||||||
//called before main - implement here if board needs it ortherwise, let
|
//called before main - implement here if board needs it ortherwise, let
|
||||||
// the application override this if necessary
|
// the application override this if necessary
|
||||||
//TODO: To be implemented by adding system init and board init
|
//TODO: To be implemented by adding system init and board init
|
||||||
void mbed_sdk_init()
|
void mbed_sdk_init()
|
||||||
{
|
{
|
||||||
|
system_init();
|
||||||
}
|
}
|
||||||
/***************************************************************/
|
/***************************************************************/
|
||||||
|
|
|
@ -31,8 +31,9 @@
|
||||||
#define DEVICE_I2C 0
|
#define DEVICE_I2C 0
|
||||||
#define DEVICE_I2CSLAVE 0
|
#define DEVICE_I2CSLAVE 0
|
||||||
|
|
||||||
#define DEVICE_SPI 0
|
#define DEVICE_SPI 1
|
||||||
#define DEVICE_SPISLAVE 0
|
#define DEVICE_SPISLAVE 0
|
||||||
|
#define DEVICE_SPI_ASYNCH 1
|
||||||
|
|
||||||
#define DEVICE_CAN 0
|
#define DEVICE_CAN 0
|
||||||
|
|
||||||
|
|
|
@ -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 <a href="http://www.atmel.com/design-support/">Atmel Support</a>
|
|
||||||
*/
|
|
|
@ -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 <a href="http://www.atmel.com/design-support/">Atmel Support</a>
|
|
||||||
*/
|
|
|
@ -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 <a href="http://www.atmel.com/design-support/">Atmel Support</a>
|
|
||||||
*/
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -71,11 +71,20 @@ struct can_s {
|
||||||
struct i2c_s {
|
struct i2c_s {
|
||||||
LPC_I2C_TypeDef *i2c;
|
LPC_I2C_TypeDef *i2c;
|
||||||
};
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
struct spi_s {
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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 <math.h>
|
||||||
|
|
||||||
|
#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
|
|
@ -22,6 +22,10 @@
|
||||||
#include "tc.h"
|
#include "tc.h"
|
||||||
#include "tc_interrupt.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;
|
static int us_ticker_inited = 0;
|
||||||
|
|
||||||
struct tc_module us_ticker_module;
|
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();
|
us_ticker_irq_handler();
|
||||||
|
|
||||||
/* Disable the callback */
|
/* Disable the interrupt */
|
||||||
tc_disable_callback(us_tc_module, TC_CALLBACK_CC_CHANNEL0);
|
us_ticker_disable_interrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void us_ticker_init(void)
|
void us_ticker_init(void)
|
||||||
|
@ -55,13 +59,14 @@ void us_ticker_init(void)
|
||||||
}
|
}
|
||||||
config_tc.clock_prescaler = TC_CTRLA_PRESCALER(prescaler);
|
config_tc.clock_prescaler = TC_CTRLA_PRESCALER(prescaler);
|
||||||
config_tc.counter_size = TC_COUNTER_SIZE_32BIT;
|
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.value = 0;
|
||||||
config_tc.counter_32_bit.compare_capture_channel[0] = 0xFFFFFFFF;
|
config_tc.counter_32_bit.compare_capture_channel[0] = 0xFFFFFFFF;
|
||||||
|
|
||||||
//config_tc.oneshot = true;
|
//config_tc.oneshot = true;
|
||||||
|
|
||||||
/* Initialize the timer */
|
/* 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);
|
MBED_ASSERT(ret_status == STATUS_OK);
|
||||||
|
|
||||||
/* Register callback function */
|
/* Register callback function */
|
||||||
|
@ -95,6 +100,9 @@ void us_ticker_set_interrupt(timestamp_t timestamp)
|
||||||
|
|
||||||
tc_set_compare_value(&us_ticker_module, TC_CALLBACK_CC_CHANNEL0, timestamp);
|
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 */
|
/* Enable the callback */
|
||||||
tc_enable_callback(&us_ticker_module, TC_CALLBACK_CC_CHANNEL0);
|
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) {
|
void us_ticker_disable_interrupt(void) {
|
||||||
/* Disable the callback */
|
/* Disable the callback */
|
||||||
tc_disable_callback(&us_ticker_module, TC_CALLBACK_CC_CHANNEL0);
|
tc_disable_callback(&us_ticker_module, TC_CALLBACK_CC_CHANNEL0);
|
||||||
|
NVIC_DisableIRQ(TICKER_COUNTER_IRQn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void us_ticker_clear_interrupt(void) {
|
void us_ticker_clear_interrupt(void) {
|
||||||
/* Disable the callback */
|
/* Disable the interrupt, this is clear the interrupt also */
|
||||||
tc_disable_callback(&us_ticker_module, TC_CALLBACK_CC_CHANNEL0);
|
us_ticker_disable_interrupt();
|
||||||
|
|
||||||
|
NVIC_DisableIRQ(TICKER_COUNTER_IRQn);
|
||||||
|
NVIC_SetVector(TICKER_COUNTER_IRQn, (uint32_t)NULL);
|
||||||
}
|
}
|
Loading…
Reference in New Issue