Adding untested code for SPI support in SAM21

pull/1214/head
vimalrajr 2015-06-16 15:04:40 +05:30 committed by Karthik Purushothaman
parent cbcf0a8ed7
commit fa85c6f74d
10 changed files with 806 additions and 3511 deletions

View File

@ -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();
}
/***************************************************************/

View File

@ -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

View File

@ -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>
*/

View File

@ -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>
*/

View File

@ -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>
*/

View File

@ -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

View File

@ -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

View File

@ -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);
}