Skip to content
Permalink
4d2bdd9d79
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
1233 lines (1104 sloc) 47.5 KB
/******************************************************************************
* File Name: spi_master.c
*
* Description: This is the source code for the XMC MCU: SPI QSPI Flash
* example for ModusToolbox. This file contains all the
* function definitions required to interface with the
* on-board external memory chip.
*
* Related Document: See README.md
*
******************************************************************************
*
* Copyright (c) 2015-2022, Infineon Technologies AG
* All rights reserved.
*
* Boost Software License - Version 1.0 - August 17th, 2003
*
* Permission is hereby granted, free of charge, to any person or organization
* obtaining a copy of the software and accompanying documentation covered by
* this license (the "Software") to use, reproduce, display, distribute,
* execute, and transmit the Software, and to prepare derivative works of the
* Software, and to permit third-parties to whom the Software is furnished to
* do so, all subject to the following:
*
* The copyright notices in the Software and this entire statement, including
* the above license grant, this restriction and the following disclaimer,
* must be included in all copies of the Software, in whole or in part, and
* all derivative works of the Software, unless such copies or derivative
* works are solely in the form of machine-executable object code generated by
* a source language processor.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*****************************************************************************/
/*******************************************************************************
* Include header files
*******************************************************************************/
#include "spi_master.h"
/*******************************************************************************
* Macros
*******************************************************************************/
#define SPI_MASTER_WORD_LENGTH_8_BIT (8U) /* This is used to check while incrementing the data index */
#define SPI_MASTER_2_BYTES_PER_WORD (2U) /* Word length is 16-bits */
#define SPI_MASTER_1_BYTE_PER_WORD (1U) /* Word length is 8-bits */
#define SPI_MASTER_RECEIVE_INDICATION_FLAG ((uint32_t)XMC_SPI_CH_STATUS_FLAG_RECEIVE_INDICATION | \
(uint32_t)XMC_SPI_CH_STATUS_FLAG_ALTERNATIVE_RECEIVE_INDICATION)
#define SPI_MASTER_FIFO_RECEIVE_INDICATION_FLAG ((uint32_t)XMC_USIC_CH_RXFIFO_EVENT_STANDARD | \
(uint32_t)XMC_USIC_CH_RXFIFO_EVENT_ALTERNATE)
#define SPI_MASTER_RECEIVE_EVENT ((uint32_t)XMC_SPI_CH_EVENT_STANDARD_RECEIVE | \
(uint32_t)XMC_SPI_CH_EVENT_ALTERNATIVE_RECEIVE)
#define SPI_MASTER_FIFO_RECEIVE_EVENT ((uint32_t)XMC_USIC_CH_RXFIFO_EVENT_CONF_STANDARD | \
(uint32_t)XMC_USIC_CH_RXFIFO_EVENT_CONF_ALTERNATE)
/*******************************************************************************
* Function Prototypes
*******************************************************************************/
/* Transmit interrupt handler for the APP */
void SPI_MASTER_lTransmitHandler(const SPI_MASTER_t * const handle);
static SPI_MASTER_STATUS_t SPI_MASTER_lReceiveIRQ(const SPI_MASTER_t *const handle, uint32_t count);
/* This is used to reconfigure the FIFO settings dynamically */
static void SPI_MASTER_lReconfigureRxFIFO(const SPI_MASTER_t * const handle, uint32_t data_size);
/* Read data from FIFO */
static void SPI_MASTER_lFIFORead(const SPI_MASTER_t * const handle, const uint32_t bytes_per_word);
/* Receive interrupt handler for the APP */
void SPI_MASTER_lReceiveHandler(const SPI_MASTER_t * const handle);
/* Protocol interrupt handler for the APP */
void SPI_MASTER_lProtocolHandler(const SPI_MASTER_t * const handle);
/* Flush RBUF0, RBUF1 */
static void SPI_MASTER_lStdRBUFFlush(XMC_USIC_CH_t *const channel);
/* This is used to reconfigure the registers while changing the SPI mode dynamically */
static void SPI_MASTER_lPortConfig(const SPI_MASTER_t* handle);
/* Set the mode of the port pin according to the configuration */
static void SPI_MASTER_lPortModeSet(const SPI_MASTER_t* handle);
/* Set the mode of the port pin as input */
static void SPI_MASTER_lPortModeReset(const SPI_MASTER_t* handle);
/* Returns whether mode change is valid or not */
static SPI_MASTER_STATUS_t SPI_MASTER_lValidateModeChange(const SPI_MASTER_t * handle, XMC_SPI_CH_MODE_t mode);
/*******************************************************************************
* Function Name: SPI_MASTER_SetMode
********************************************************************************
* Summary:
* This function changes the SPI mode of communication.
*
* Parameters:
* - SPI_MASTER_t* const handle - Pointer to SPI Master configuration
* structure
* - const XMC_SPI_CH_MODE_t mode - SPI mode to be changed to
*
* Return:
* SPI_MASTER_STATUS_t - Status of SPI_MASTER driver mode change operation
* - SPI_MASTER_STATUS_SUCCESS : on successful operation
* - SPI_MASTER_STATUS_FAILURE : if mode is not supported
* - SPI_MASTER_STATUS_BUSY : if SPI channel is busy with transmit
* or receive operation
*
*******************************************************************************/
SPI_MASTER_STATUS_t SPI_MASTER_SetMode(SPI_MASTER_t* const handle,
const XMC_SPI_CH_MODE_t mode)
{
SPI_MASTER_STATUS_t status;
XMC_ASSERT("SPI_MASTER_Configure:handle NULL" , (handle != NULL));
status = SPI_MASTER_STATUS_SUCCESS;
if ((false == handle->runtime->tx_busy) && (false == handle->runtime->rx_busy))
{
if (handle->runtime->spi_master_mode != mode)
{
status = SPI_MASTER_lValidateModeChange(handle, mode);
if (SPI_MASTER_STATUS_SUCCESS == status)
{
handle->runtime->spi_master_mode = mode;
/* This changes the operating mode and related settings */
SPI_MASTER_lPortConfig(handle);
}
}
}
else
{
status = SPI_MASTER_STATUS_BUSY;
}
return status;
}
/*******************************************************************************
* Function Name: SPI_MASTER_SetBaudRate
********************************************************************************
* Summary:
* This function sets the baud rate during runtime.
*
* Parameters:
* - SPI_MASTER_t* const handle - Pointer to SPI Master configuration
* structure
* - const uint32_t baud_rate - baud rate to be set
*
* Return:
* SPI_MASTER_STATUS_t - Status of SPI_MASTER driver operation
* - SPI_MASTER_STATUS_SUCCESS : on successful operation
* - SPI_MASTER_STATUS_FAILURE : if operation fails
* - SPI_MASTER_STATUS_BUSY : if SPI channel is busy with other
* operation
*
*******************************************************************************/
SPI_MASTER_STATUS_t SPI_MASTER_SetBaudRate(SPI_MASTER_t* const handle, const uint32_t baud_rate)
{
SPI_MASTER_STATUS_t status;
if ((false == handle->runtime->tx_busy) && (false == handle->runtime->rx_busy))
{
/* Stops the SPI channel */
status = (SPI_MASTER_STATUS_t)XMC_SPI_CH_Stop(handle->channel);
if (SPI_MASTER_STATUS_SUCCESS == status)
{
/* Set all the pins as input */
SPI_MASTER_lPortModeReset(handle);
/* Update the new baud rate */
status = (SPI_MASTER_STATUS_t)XMC_SPI_CH_SetBaudrate(handle->channel, baud_rate);
if (SPI_MASTER_STATUS_SUCCESS == status)
{
/* Configure Leading/Trailing delay */
XMC_SPI_CH_SetSlaveSelectDelay(handle->channel, (uint32_t)handle->config->leading_trailing_delay);
}
/* Configure the clock polarity and clock delay */
XMC_SPI_CH_ConfigureShiftClockOutput(handle->channel,
handle->config->shift_clk_passive_level,
XMC_SPI_CH_BRG_SHIFT_CLOCK_OUTPUT_SCLK);
/* Start the SPI channel */
XMC_SPI_CH_Start(handle->channel);
/* Set the mode of the according the generated configuration */
SPI_MASTER_lPortModeSet(handle);
}
}
else
{
status = SPI_MASTER_STATUS_BUSY;
}
return status;
}
/*******************************************************************************
* Function Name: SPI_MASTER_Transmit
********************************************************************************
* Summary:
* This function transmits the specified number of data words
*
* Parameters:
* - SPI_MASTER_t* const handle - Pointer to SPI Master configuration
* structure
* - uint8_t* dataptr - Pointer to data
* - uint32_t count - number of data words to be transmitted
*
* Return:
* SPI_MASTER_STATUS_t - Status of SPI_MASTER driver operation
* - SPI_MASTER_STATUS_SUCCESS : on successful operation
* - SPI_MASTER_STATUS_BUSY : if SPI channel is busy with other
* operation
*
*******************************************************************************/
SPI_MASTER_STATUS_t SPI_MASTER_Transmit(const SPI_MASTER_t *const handle, uint8_t* dataptr, uint32_t count)
{
SPI_MASTER_STATUS_t status;
status = SPI_MASTER_STATUS_FAILURE;
if (handle->config->transmit_mode == SPI_MASTER_TRANSFER_MODE_INTERRUPT)
{
status = SPI_MASTER_StartTransmitIRQ(handle, dataptr, count);
}
return status;
}
/*******************************************************************************
* Function Name: SPI_MASTER_Receive
********************************************************************************
* Summary:
* This function receives the specified number of data words
*
* Parameters:
* - SPI_MASTER_t* const handle - Pointer to SPI Master configuration
* structure
* - uint8_t* dataptr - Pointer to data
* - uint32_t count - number of data words to be received
*
* Return:
* SPI_MASTER_STATUS_t - Status of SPI_MASTER driver operation
* - SPI_MASTER_STATUS_SUCCESS : on successful operation
* - SPI_MASTER_STATUS_BUSY : if SPI channel is busy with other
* operation
*
*******************************************************************************/
SPI_MASTER_STATUS_t SPI_MASTER_Receive(const SPI_MASTER_t *const handle, uint8_t* dataptr, uint32_t count)
{
SPI_MASTER_STATUS_t status;
status = SPI_MASTER_STATUS_FAILURE;
if (handle->config->receive_mode == SPI_MASTER_TRANSFER_MODE_INTERRUPT)
{
status = SPI_MASTER_StartReceiveIRQ(handle, dataptr, count);
}
return status;
}
/*******************************************************************************
* Function Name: SPI_MASTER_StartTransmitIRQ
********************************************************************************
* Summary:
* This function only registers a data transmission request if there is no
* active transmission in progress. Actual data transmission happens in the
* transmit interrupt service routine.
*
* Parameters:
* - SPI_MASTER_t* const handle - Pointer to SPI Master configuration
* structure
* - uint8_t* dataptr - Pointer to data
* - uint32_t count - number of data words to be transmitted
*
* Return:
* SPI_MASTER_STATUS_t - Status of SPI_MASTER driver operation
* - SPI_MASTER_STATUS_SUCCESS : on successful operation
* - SPI_MASTER_STATUS_BUSY : if SPI channel is busy with other
* operation
*
*******************************************************************************/
SPI_MASTER_STATUS_t SPI_MASTER_StartTransmitIRQ(const SPI_MASTER_t *const handle, uint8_t* dataptr, uint32_t count)
{
SPI_MASTER_STATUS_t status;
uint32_t bytes_per_word = SPI_MASTER_1_BYTE_PER_WORD; /* This is to support the word length 8 and 16.
Specify the number of bytes for the configured word length */
SPI_MASTER_RUNTIME_t * runtime_handle;
XMC_ASSERT("SPI_MASTER_StartTransmitIRQ:handle NULL" , (handle != NULL));
status = SPI_MASTER_STATUS_MODE_MISMATCH;
runtime_handle = handle->runtime;
if (handle->config->transmit_mode == SPI_MASTER_TRANSFER_MODE_INTERRUPT)
{
/* Check whether SPI channel is free or not */
if ((dataptr != NULL) && (count > 0U))
{
status = SPI_MASTER_STATUS_BUSY;
/*Check data pointer is valid or not*/
if (false == runtime_handle->tx_busy)
{
if (handle->runtime->word_length > SPI_MASTER_WORD_LENGTH_8_BIT)
{
bytes_per_word = SPI_MASTER_2_BYTES_PER_WORD; /* Word length is 16-bits */
}
/* Obtain the address of data, size of data */
runtime_handle->tx_data = dataptr;
runtime_handle->tx_data_count = (uint32_t)count << (bytes_per_word - 1U);
/* Initialize to first index and set the busy flag */
runtime_handle->tx_data_index = 0U;
runtime_handle->tx_busy = true;
/* Enable the transmit buffer event */
if ((uint32_t)handle->config->tx_fifo_size > 0U)
{
/* Flush the Transmit FIFO */
XMC_USIC_CH_TXFIFO_Flush(handle->channel);
XMC_USIC_CH_TXFIFO_EnableEvent(handle->channel,(uint32_t)XMC_USIC_CH_TXFIFO_EVENT_CONF_STANDARD);
}
else
{
XMC_USIC_CH_EnableEvent(handle->channel,(uint32_t)XMC_USIC_CH_EVENT_TRANSMIT_BUFFER);
}
XMC_SPI_CH_SetTransmitMode(handle->channel, runtime_handle->spi_master_mode);
status = SPI_MASTER_STATUS_SUCCESS;
/* Trigger the transmit buffer interrupt */
XMC_USIC_CH_TriggerServiceRequest(handle->channel, (uint32_t)handle->config->tx_sr);
}
}
else
{
status = SPI_MASTER_STATUS_BUFFER_INVALID;
}
}
return status;
}
/*******************************************************************************
* Function Name: SPI_MASTER_StartReceiveIRQ
********************************************************************************
* Summary:
* This function only registers a request to receive a number of data bytes
* from a SPI channel.
*
* Parameters:
* - SPI_MASTER_t* const handle - Pointer to SPI Master configuration
* structure
* - uint8_t* dataptr - Pointer to data
* - uint32_t count - number of data words to be received
*
* Return:
* SPI_MASTER_STATUS_t - Status of SPI_MASTER driver operation
* - SPI_MASTER_STATUS_SUCCESS : on successful operation
* - SPI_MASTER_STATUS_BUSY : if SPI channel is busy with other
* operation
*
*******************************************************************************/
SPI_MASTER_STATUS_t SPI_MASTER_StartReceiveIRQ(const SPI_MASTER_t *const handle, uint8_t* dataptr, uint32_t count)
{
SPI_MASTER_STATUS_t status;
SPI_MASTER_RUNTIME_t * runtime_handle;
static uint8_t dummy_data[2] = {0xFFU, 0xFFU};
XMC_ASSERT("SPI_MASTER_StartReceiveIRQ:handle NULL" , (handle != NULL));
status = SPI_MASTER_STATUS_MODE_MISMATCH;
runtime_handle = handle->runtime;
if (handle->config->receive_mode == SPI_MASTER_TRANSFER_MODE_INTERRUPT)
{
status = SPI_MASTER_STATUS_BUSY;
/* Check whether SPI channel is free or not */
if ((dataptr != NULL) && (count > 0U))
{
/*Check data pointer is valid or not*/
if ((false == runtime_handle->rx_busy) && (false == runtime_handle->tx_busy))
{
runtime_handle->rx_busy = true;
runtime_handle->rx_data = dataptr;
runtime_handle->tx_data = &dummy_data[0];
runtime_handle->tx_data_count = count;
runtime_handle->tx_data_dummy = true;
runtime_handle->rx_data_dummy = false;
status = SPI_MASTER_lReceiveIRQ(handle, count);
}
}
else
{
status = SPI_MASTER_STATUS_BUFFER_INVALID;
}
}
return status;
}
/*******************************************************************************
* Function Name: SPI_MASTER_Transfer
********************************************************************************
* Summary:
* This function transmits and receives the specified number of data words at
* the same time.
*
* Parameters:
* - SPI_MASTER_t* const handle - Pointer to SPI Master configuration
* structure
* - uint8_t* tx_dataptr - Pointer to data buffer which has to be sent
* - uint8_t* rx_dataptr - Pointer to data buffer where the received data
* has to be stored.
* - uint32_t count - number of data words to be read/written
*
* Return:
* SPI_MASTER_STATUS_t - Status of SPI_MASTER driver operation
* - SPI_MASTER_STATUS_SUCCESS : on successful operation
* - SPI_MASTER_STATUS_FAILURE : if transfer of data fails (or)
* in other than standard full duplex mode
* - SPI_MASTER_STATUS_BUFFER_INVALID : if passed buffers are NULL pointers
* (or) length of data transfer is zero.
*
*******************************************************************************/
SPI_MASTER_STATUS_t SPI_MASTER_Transfer(const SPI_MASTER_t *const handle,
uint8_t* tx_dataptr,
uint8_t* rx_dataptr,
uint32_t count)
{
SPI_MASTER_STATUS_t status;
SPI_MASTER_RUNTIME_t * runtime_handle;
XMC_ASSERT("SPI_MASTER_Transfer:handle NULL" , (handle != NULL));
status = SPI_MASTER_STATUS_BUSY;
runtime_handle = handle->runtime;
if (XMC_SPI_CH_MODE_STANDARD == runtime_handle->spi_master_mode)
{
/* Check whether SPI channel is free or not */
if ((tx_dataptr != NULL) && (rx_dataptr != NULL) && (count > 0U))
{
/* Check data pointer is valid or not */
if ((false == runtime_handle->rx_busy) && (false == runtime_handle->tx_busy))
{
runtime_handle->rx_busy = true;
runtime_handle->rx_data = rx_dataptr;
runtime_handle->tx_data = tx_dataptr;
runtime_handle->tx_data_count = count;
runtime_handle->tx_data_dummy = false;
runtime_handle->rx_data_dummy = false;
if (handle->config->receive_mode == SPI_MASTER_TRANSFER_MODE_INTERRUPT)
{
status = SPI_MASTER_lReceiveIRQ(handle, count);
}
}
}
else
{
status = SPI_MASTER_STATUS_BUFFER_INVALID;
}
}
else
{
status = SPI_MASTER_STATUS_FAILURE;
}
return status;
}
/*******************************************************************************
* Function Name: SPI_MASTER_AbortReceive
********************************************************************************
* Summary:
* This function aborts the ongoing data reception.
*
* Parameters:
* - SPI_MASTER_t* const handle - Pointer to SPI Master configuration
* structure
*
* Return:
* SPI_MASTER_STATUS_t - Status of SPI_MASTER driver operation
* - SPI_MASTER_STATUS_SUCCESS : on successful operation
* - SPI_MASTER_STATUS_FAILURE : unknown error occurred
*
*******************************************************************************/
SPI_MASTER_STATUS_t SPI_MASTER_AbortReceive(const SPI_MASTER_t *const handle)
{
SPI_MASTER_STATUS_t status;
status = SPI_MASTER_STATUS_FAILURE;
if ((handle->config->receive_mode != SPI_MASTER_TRANSFER_MODE_DIRECT) && (handle->runtime->rx_busy))
{
/* Abort if any ongoing transmission w.r.t reception. */
status = SPI_MASTER_AbortTransmit(handle);
if (status == SPI_MASTER_STATUS_SUCCESS)
{
/* Reset the user buffer pointer to null */
handle->runtime->rx_busy = false;
handle->runtime->rx_data = NULL;
handle->runtime->tx_data_dummy = false;
/* Disable the receive interrupts */
if ((uint32_t)handle->config->rx_fifo_size > 0U)
{
XMC_USIC_CH_RXFIFO_DisableEvent(handle->channel, (uint32_t)SPI_MASTER_FIFO_RECEIVE_EVENT);
}
else
{
{
XMC_SPI_CH_DisableEvent(handle->channel,
(uint32_t)((uint32_t)XMC_USIC_CH_EVENT_STANDARD_RECEIVE | (uint32_t)XMC_USIC_CH_EVENT_ALTERNATIVE_RECEIVE));
}
}
status = SPI_MASTER_STATUS_SUCCESS;
}
else
{
status = SPI_MASTER_STATUS_FAILURE;
}
}
return status;
}
/*******************************************************************************
* Function Name: SPI_MASTER_AbortTransmit
********************************************************************************
* Summary:
* This function aborts the ongoing data transmission.
*
* Parameters:
* - SPI_MASTER_t* const handle - Pointer to SPI Master configuration
* structure
*
* Return:
* SPI_MASTER_STATUS_t - Status of SPI_MASTER driver operation
* - SPI_MASTER_STATUS_SUCCESS : on successful operation
* - SPI_MASTER_STATUS_FAILURE : unknown error occurred
*
*******************************************************************************/
SPI_MASTER_STATUS_t SPI_MASTER_AbortTransmit(const SPI_MASTER_t *const handle)
{
SPI_MASTER_STATUS_t status;
status = SPI_MASTER_STATUS_FAILURE;
if ((handle->config->transmit_mode != SPI_MASTER_TRANSFER_MODE_DIRECT) && (handle->runtime->tx_busy))
{
/* Reset the user buffer pointer to null */
handle->runtime->tx_busy = false;
handle->runtime->tx_data = NULL;
handle->runtime->tx_data_dummy = false;
/* Disable the transmit interrupts */
if ((uint32_t)handle->config->tx_fifo_size > 0U)
{
/* Disable the transmit FIFO event */
XMC_USIC_CH_TXFIFO_DisableEvent(handle->channel, (uint32_t)XMC_USIC_CH_TXFIFO_EVENT_CONF_STANDARD);
XMC_USIC_CH_TXFIFO_Flush(handle->channel);
}
else
{
{
/* Disable the standard transmit event */
XMC_SPI_CH_DisableEvent(handle->channel, (uint32_t)XMC_USIC_CH_EVENT_TRANSMIT_BUFFER);
}
}
status = SPI_MASTER_STATUS_SUCCESS;
}
return status;
}
/*******************************************************************************
* Function Name: SPI_MASTER_lTransmitHandler
********************************************************************************
* Summary:
* This function is the interrupt handler for the transmit operation.
*
* Parameters:
* - SPI_MASTER_t* const handle - Pointer to SPI Master configuration
* structure
*
* Return:
* void
*
*******************************************************************************/
void SPI_MASTER_lTransmitHandler(const SPI_MASTER_t * const handle)
{
uint16_t data; /* Data to be loaded into the TBUF */
uint32_t bytes_per_word = SPI_MASTER_1_BYTE_PER_WORD; /* This is to support the word length 8 and 16 */
SPI_MASTER_RUNTIME_t * runtime_handle = handle->runtime;
if (handle->runtime->word_length > SPI_MASTER_WORD_LENGTH_8_BIT)
{
bytes_per_word = SPI_MASTER_2_BYTES_PER_WORD; /* Word length is 16-bits */
}
if (runtime_handle->tx_data_index < runtime_handle->tx_data_count)
{
data = 0U;
/* When Transmit FIFO is enabled */
if ((uint32_t)handle->config->tx_fifo_size > 0U)
{
/* Fill the transmit FIFO */
while (XMC_USIC_CH_TXFIFO_IsFull(handle->channel) == false)
{
if (runtime_handle->tx_data_index < runtime_handle->tx_data_count)
{
/* Load the FIFO byte by byte till either FIFO is full or all data is loaded */
if (runtime_handle->tx_data_dummy == true)
{
XMC_USIC_CH_TXFIFO_PutDataHPCMode(handle->channel, 0xFFFFU, (uint32_t)runtime_handle->spi_master_mode);
}
else
{
if(bytes_per_word == SPI_MASTER_2_BYTES_PER_WORD)
{
data = *((uint16_t*)&runtime_handle->tx_data[runtime_handle->tx_data_index]);
}
else
{
data = runtime_handle->tx_data[runtime_handle->tx_data_index];
}
XMC_USIC_CH_TXFIFO_PutDataHPCMode(handle->channel, data, (uint32_t)runtime_handle->spi_master_mode);
}
(runtime_handle->tx_data_index) += bytes_per_word;
}
else
{
break;
}
}
}
/* When Transmit FIFO is disabled */
else
{
if (runtime_handle->tx_data_dummy == true)
{
XMC_USIC_CH_WriteToTBUFTCI(handle->channel, 0xFFFFU, (uint32_t)runtime_handle->spi_master_mode);
}
else
{
if(bytes_per_word == SPI_MASTER_2_BYTES_PER_WORD)
{
data = *((uint16_t*)&runtime_handle->tx_data[runtime_handle->tx_data_index]);
}
else
{
data = runtime_handle->tx_data[runtime_handle->tx_data_index];
}
XMC_USIC_CH_WriteToTBUFTCI(handle->channel, data, (uint32_t)runtime_handle->spi_master_mode);
}
(runtime_handle->tx_data_index)+= bytes_per_word;
}
}
else
{
if (XMC_USIC_CH_TXFIFO_IsEmpty(handle->channel) == true)
{
/* Clear the flag */
if ((uint32_t)handle->config->tx_fifo_size > 0U)
{
/* Clear the transmit FIFO event */
XMC_USIC_CH_TXFIFO_DisableEvent(handle->channel, (uint32_t)XMC_USIC_CH_TXFIFO_EVENT_CONF_STANDARD);
}
else
{
/* Clear the standard transmit event */
XMC_USIC_CH_DisableEvent(handle->channel, (uint32_t)XMC_USIC_CH_EVENT_TRANSMIT_BUFFER);
}
/* Wait for the transmit buffer to be free to ensure that all data is transmitted */
while (XMC_USIC_CH_GetTransmitBufferStatus(handle->channel) == XMC_USIC_CH_TBUF_STATUS_BUSY)
{
}
/* All data is transmitted */
runtime_handle->tx_busy = false;
runtime_handle->tx_data = NULL;
if ((handle->config->tx_cbhandler != NULL) && (runtime_handle->rx_busy == false))
{
/* Execute the callback function provided in the SPI_MASTER APP UI */
handle->config->tx_cbhandler();
}
}
}
}
/*******************************************************************************
* Function Name: SPI_MASTER_lReceiveIRQ
********************************************************************************
* Summary:
* This function configures and enables the ReceiveIRQ handler.
*
* Parameters:
* - SPI_MASTER_t* const handle - Pointer to SPI Master configuration
* structure
* - uint32_t count - number of data bytes to be received
*
* Return:
* SPI_MASTER_STATUS_t - Status of SPI_MASTER driver operation
* - SPI_MASTER_STATUS_SUCCESS : on successful operation
* - SPI_MASTER_STATUS_FAILURE : if operation failed
*
*******************************************************************************/
SPI_MASTER_STATUS_t SPI_MASTER_lReceiveIRQ(const SPI_MASTER_t *const handle, uint32_t count)
{
SPI_MASTER_STATUS_t status;
SPI_MASTER_RUNTIME_t * runtime_handle;
uint32_t bytes_per_word = SPI_MASTER_1_BYTE_PER_WORD;; /* This is to support the word length 8 and 16.
Specify the number of bytes for the configured word length */
runtime_handle = handle->runtime;
runtime_handle->rx_data_index = 0U;
if (handle->runtime->word_length > SPI_MASTER_WORD_LENGTH_8_BIT)
{
bytes_per_word = SPI_MASTER_2_BYTES_PER_WORD; /* Word length is 16-bits */
}
/* If no active reception in progress, obtain the address of data buffer and number of data bytes to be received */
runtime_handle->rx_data_count = (uint32_t)count << (bytes_per_word - 1U);
/* Check if FIFO is enabled */
if ((uint32_t)handle->config->rx_fifo_size > 0U)
{
/* Clear the receive FIFO */
XMC_USIC_CH_RXFIFO_Flush(handle->channel);
SPI_MASTER_lStdRBUFFlush(handle->channel);
/* Configure the FIFO trigger limit based on the required data size */
SPI_MASTER_lReconfigureRxFIFO(handle, runtime_handle->rx_data_count);
/* Enable the receive FIFO events */
XMC_USIC_CH_RXFIFO_EnableEvent(handle->channel,(uint32_t)SPI_MASTER_FIFO_RECEIVE_EVENT);
}
else
{
/* Flush the RBUF0 and RBUF1 */
SPI_MASTER_lStdRBUFFlush(handle->channel);
/* Enable the standard receive events */
XMC_USIC_CH_EnableEvent(handle->channel, (uint32_t)SPI_MASTER_RECEIVE_EVENT);
}
/* Call the transmit, to receive the data synchronously */
status = SPI_MASTER_Transmit(handle, runtime_handle->tx_data, runtime_handle->tx_data_count);
return status;
}
/*******************************************************************************
* Function Name: SPI_MASTER_lTransmitHandler
********************************************************************************
* Summary:
* This function is the interrupt handler for the receive operation.
*
* Parameters:
* - SPI_MASTER_t* const handle - Pointer to SPI Master configuration
* structure
*
* Return:
* void
*
*******************************************************************************/
void SPI_MASTER_lReceiveHandler(const SPI_MASTER_t * const handle)
{
uint16_t data; /* Data to be loaded into the TBUF */
uint32_t bytes_per_word = SPI_MASTER_1_BYTE_PER_WORD; /* This is to support the word length 8 and 16. */
SPI_MASTER_RUNTIME_t * runtime_handle = handle->runtime;
data = 0U;
if (handle->runtime->word_length > SPI_MASTER_WORD_LENGTH_8_BIT)
{
bytes_per_word = SPI_MASTER_2_BYTES_PER_WORD; /* Word length is 16-bits */
}
if ((uint32_t)handle->config->rx_fifo_size > 0U)
{
/* read the FIFO */
SPI_MASTER_lFIFORead(handle, bytes_per_word);
/* Set the trigger limit if data still to be received */
if (runtime_handle->rx_data_index < runtime_handle->rx_data_count)
{
SPI_MASTER_lReconfigureRxFIFO(handle, \
(uint32_t)(runtime_handle->rx_data_count - runtime_handle->rx_data_index));
}
}
else
{
/* When RxFIFO is disabled */
if ((XMC_USIC_CH_GetReceiveBufferStatus(handle->channel) & (uint32_t)XMC_USIC_CH_RBUF_STATUS_DATA_VALID0) != 0U )
{
if (runtime_handle->rx_data_index < runtime_handle->rx_data_count)
{
data = XMC_SPI_CH_GetReceivedData(handle->channel);
runtime_handle->rx_data[runtime_handle->rx_data_index] = (uint8_t)data;
if (bytes_per_word == SPI_MASTER_2_BYTES_PER_WORD)
{
runtime_handle->rx_data[runtime_handle->rx_data_index + 1U] = (uint8_t)((uint16_t)data >> 8);
}
(runtime_handle->rx_data_index)+= bytes_per_word;
}
}
if ((XMC_USIC_CH_GetReceiveBufferStatus(handle->channel) & (uint32_t)XMC_USIC_CH_RBUF_STATUS_DATA_VALID1) != 0U)
{
if (runtime_handle->rx_data_index < runtime_handle->rx_data_count)
{
data = XMC_SPI_CH_GetReceivedData(handle->channel);
runtime_handle->rx_data[runtime_handle->rx_data_index] = (uint8_t)data;
if (bytes_per_word == SPI_MASTER_2_BYTES_PER_WORD)
{
runtime_handle->rx_data[runtime_handle->rx_data_index + 1U] = (uint8_t)((uint16_t)data >> 8);
}
(runtime_handle->rx_data_index)+= bytes_per_word;
}
}
if (runtime_handle->rx_data_index == runtime_handle->rx_data_count)
{
/* Disable both standard receive and alternative receive FIFO events */
if ((uint32_t)handle->config->rx_fifo_size > 0U)
{
/* Enable the receive FIFO events */
XMC_USIC_CH_RXFIFO_DisableEvent(handle->channel, (uint32_t)SPI_MASTER_FIFO_RECEIVE_EVENT);
}
else
{
XMC_SPI_CH_DisableEvent(handle->channel, (uint32_t)SPI_MASTER_RECEIVE_EVENT);
}
/* Reception complete */
runtime_handle->rx_busy = false;
runtime_handle->tx_data_dummy = false;
runtime_handle->rx_data_dummy = true;
runtime_handle->rx_data = NULL;
if (handle->config->rx_cbhandler != NULL)
{
/* Execute the 'End of reception' callback function */
handle->config->rx_cbhandler();
}
}
}
}
/*******************************************************************************
* Function Name: SPI_MASTER_lFIFORead
********************************************************************************
* Summary:
* This function reads the data from FIFO until it becomes empty.
*
* Parameters:
* - SPI_MASTER_t* const handle - Pointer to SPI Master configuration
* structure
* - const uint32_t bytes_per_word - number of bytes to be read
*
* Return:
* void
*
*******************************************************************************/
void SPI_MASTER_lFIFORead(const SPI_MASTER_t * const handle, const uint32_t bytes_per_word)
{
SPI_MASTER_RUNTIME_t * runtime_handle;
uint16_t data;
runtime_handle = handle->runtime;
data = 0U;
/* When Receive FIFO is enabled*/
while (XMC_USIC_CH_RXFIFO_IsEmpty(handle->channel) == false)
{
if (runtime_handle->rx_data_index < runtime_handle->rx_data_count)
{
data = XMC_SPI_CH_GetReceivedData(handle->channel);
runtime_handle->rx_data[runtime_handle->rx_data_index] = (uint8_t)data;
if (bytes_per_word == SPI_MASTER_2_BYTES_PER_WORD)
{
runtime_handle->rx_data[runtime_handle->rx_data_index + 1U] = (uint8_t)((uint16_t)data >> 8);
}
(runtime_handle->rx_data_index)+= bytes_per_word;
}
if (runtime_handle->rx_data_index == runtime_handle->rx_data_count)
{
/* Reception complete */
runtime_handle->rx_busy = false;
runtime_handle->tx_data_dummy = false;
/* Disable both standard receive and alternative receive FIFO events */
XMC_USIC_CH_RXFIFO_DisableEvent(handle->channel,(uint32_t)SPI_MASTER_FIFO_RECEIVE_EVENT);
if (handle->config->rx_cbhandler != NULL)
{
/* Execute the 'End of reception' callback function */
handle->config->rx_cbhandler();
}
break;
}
}
}
/*******************************************************************************
* Function Name: SPI_MASTER_lReconfigureRxFIFO
********************************************************************************
* Summary:
* This function configures the FIFO settings
*
* Parameters:
* - SPI_MASTER_t* const handle - Pointer to SPI Master configuration
* structure
* - uint32_t data_size - size of the data
*
* Return:
* void
*
*******************************************************************************/
static void SPI_MASTER_lReconfigureRxFIFO(const SPI_MASTER_t * const handle, uint32_t data_size)
{
uint32_t fifo_size;
uint32_t ret_limit_val;
if (((uint32_t)handle->config->rx_fifo_size > 0U) && (data_size > 0U))
{
fifo_size = (uint32_t)0x01 << handle->config->rx_fifo_size;
if (handle->runtime->word_length > SPI_MASTER_WORD_LENGTH_8_BIT)
{
/* Data size is divided by 2, to change the trigger limit according the word length */
data_size = (uint32_t)data_size >> 1U;
}
/* If data size is more than FIFO size, configure the limit to the FIFO size */
if (data_size < fifo_size)
{
ret_limit_val = data_size - 1U;
}
else
{
ret_limit_val = fifo_size - 1U;
}
/*Set the limit value*/
XMC_USIC_CH_RXFIFO_SetSizeTriggerLimit(handle->channel, handle->config->rx_fifo_size, ret_limit_val);
}
}
/*******************************************************************************
* Function Name: SPI_MASTER_lStdRBUFFlush
********************************************************************************
* Summary:
* This function clears the receive buffers
*
* Parameters:
* - XMC_USIC_CH_t *const channel - Pointer to USIC channel structure
* structure
*
* Return:
* void
*
*******************************************************************************/
static void SPI_MASTER_lStdRBUFFlush(XMC_USIC_CH_t *const channel)
{
/* Clear RBF0 */
(void)XMC_SPI_CH_GetReceivedData(channel);
/* Clear RBF1 */
(void)XMC_SPI_CH_GetReceivedData(channel);
}
/*******************************************************************************
* Function Name: SPI_MASTER_lPortConfig
********************************************************************************
* Summary:
* This function is used to reconfigure the registers while changing the SPI
* mode dynamically
*
* Parameters:
* - SPI_MASTER_t* const handle - Pointer to SPI Master configuration
* structure
*
* Return:
* void
*
*******************************************************************************/
static void SPI_MASTER_lPortConfig(const SPI_MASTER_t* handle)
{
switch (handle->runtime->spi_master_mode)
{
case XMC_SPI_CH_MODE_STANDARD:
/* Configure the data input line selected */
XMC_SPI_CH_SetInputSource(handle->channel, XMC_SPI_CH_INPUT_DIN0, (uint8_t)(handle->runtime->dx0_input));
/* Configure the pin as input */
XMC_GPIO_SetMode(handle->config->mosi_1_pin->port, handle->config->mosi_1_pin->pin, XMC_GPIO_MODE_INPUT_TRISTATE);
/* Disable the HW control of the PINs */
XMC_GPIO_SetHardwareControl(handle->config->mosi_0_pin->port,
handle->config->mosi_0_pin->pin,
XMC_GPIO_HWCTRL_DISABLED);
XMC_GPIO_SetHardwareControl(handle->config->mosi_1_pin->port,
handle->config->mosi_1_pin->pin,
XMC_GPIO_HWCTRL_DISABLED);
break;
case XMC_SPI_CH_MODE_STANDARD_HALFDUPLEX:
/* Configure the data input line selected */
XMC_SPI_CH_SetInputSource(handle->channel, XMC_SPI_CH_INPUT_DIN0, (uint8_t)(handle->runtime->dx0_input_half_duplex));
/* Disable the HW control of the PINs */
XMC_GPIO_SetHardwareControl(handle->config->mosi_0_pin->port,
handle->config->mosi_0_pin->pin,
XMC_GPIO_HWCTRL_DISABLED);
break;
case XMC_SPI_CH_MODE_DUAL:
case XMC_SPI_CH_MODE_QUAD:
/* Configure the data input line for loopback mode */
XMC_SPI_CH_SetInputSource(handle->channel, XMC_SPI_CH_INPUT_DIN0, (uint8_t)SPI_MASTER_INPUT_G);
/* Configure the pin as input */
XMC_GPIO_SetMode(handle->config->mosi_1_pin->port,
handle->config->mosi_1_pin->pin,
handle->config->mosi_1_pin_config->port_config->mode);
/* Configure the Hardware control mode selected for the pin */
XMC_GPIO_SetHardwareControl(handle->config->mosi_0_pin->port,
handle->config->mosi_0_pin->pin,
handle->config->mosi_0_pin_config->hw_control);
XMC_GPIO_SetHardwareControl(handle->config->mosi_1_pin->port,
handle->config->mosi_1_pin->pin,
handle->config->mosi_1_pin_config->hw_control);
break;
default:
break;
}
}
/*******************************************************************************
* Function Name: SPI_MASTER_lPortModeSet
********************************************************************************
* Summary:
* This function is used to reassign the mode for ports after updating the baud
* rate.
*
* Parameters:
* - SPI_MASTER_t* const handle - Pointer to SPI Master configuration
* structure
*
* Return:
* void
*
*******************************************************************************/
static void SPI_MASTER_lPortModeSet(const SPI_MASTER_t* handle)
{
uint32_t ss_line;
/* Configure the ports with actual mode */
for (ss_line = 0U; ss_line < handle->config->slave_select_lines; ss_line++)
{
XMC_GPIO_SetMode(handle->config->slave_select_pin[ss_line]->port,
handle->config->slave_select_pin[ss_line]->pin,
handle->config->slave_select_pin_config[ss_line]->port_config->mode);
}
XMC_GPIO_SetMode(handle->config->sclk_out_pin->port,
handle->config->sclk_out_pin->pin,
handle->config->sclk_out_pin_config->port_config->mode);
switch (handle->runtime->spi_master_mode)
{
case XMC_SPI_CH_MODE_STANDARD:
case XMC_SPI_CH_MODE_STANDARD_HALFDUPLEX:
XMC_GPIO_SetMode(handle->config->mosi_0_pin->port,
handle->config->mosi_0_pin->pin,
handle->config->mosi_0_pin_config->port_config->mode);
break;
case XMC_SPI_CH_MODE_DUAL:
XMC_GPIO_SetMode(handle->config->mosi_0_pin->port,
handle->config->mosi_0_pin->pin,
handle->config->mosi_0_pin_config->port_config->mode);
XMC_GPIO_SetMode(handle->config->mosi_1_pin->port,
handle->config->mosi_1_pin->pin,
handle->config->mosi_1_pin_config->port_config->mode);
break;
case XMC_SPI_CH_MODE_QUAD:
XMC_GPIO_SetMode(handle->config->mosi_0_pin->port,
handle->config->mosi_0_pin->pin,
handle->config->mosi_0_pin_config->port_config->mode);
XMC_GPIO_SetMode(handle->config->mosi_1_pin->port,
handle->config->mosi_1_pin->pin,
handle->config->mosi_1_pin_config->port_config->mode);
XMC_GPIO_SetMode(handle->config->mosi_2_pin->port,
handle->config->mosi_2_pin->pin,
handle->config->mosi_2_pin_config->port_config->mode);
XMC_GPIO_SetMode(handle->config->mosi_3_pin->port,
handle->config->mosi_3_pin->pin,
handle->config->mosi_3_pin_config->port_config->mode);
break;
default:
break;
}
}
/*******************************************************************************
* Function Name: SPI_MASTER_lPortModeReset
********************************************************************************
* Summary:
* This function is used to make the ports as input during update of the baud
* rate, to avoid the noise in output ports.
*
* Parameters:
* - SPI_MASTER_t* const handle - Pointer to SPI Master configuration
* structure
*
* Return:
* void
*
*******************************************************************************/
static void SPI_MASTER_lPortModeReset(const SPI_MASTER_t* handle)
{
uint32_t ss_line;
/* Configure the ports as input */
for (ss_line = 0U; ss_line < handle->config->slave_select_lines; ss_line++)
{
XMC_GPIO_SetMode(handle->config->slave_select_pin[ss_line]->port,
handle->config->slave_select_pin[ss_line]->pin,
XMC_GPIO_MODE_INPUT_TRISTATE);
}
XMC_GPIO_SetMode(handle->config->sclk_out_pin->port, handle->config->sclk_out_pin->pin, XMC_GPIO_MODE_INPUT_TRISTATE);
switch (handle->runtime->spi_master_mode)
{
case XMC_SPI_CH_MODE_STANDARD:
case XMC_SPI_CH_MODE_STANDARD_HALFDUPLEX:
XMC_GPIO_SetMode(handle->config->mosi_0_pin->port, handle->config->mosi_0_pin->pin, XMC_GPIO_MODE_INPUT_TRISTATE);
break;
case XMC_SPI_CH_MODE_DUAL:
XMC_GPIO_SetMode(handle->config->mosi_0_pin->port, handle->config->mosi_0_pin->pin, XMC_GPIO_MODE_INPUT_TRISTATE);
XMC_GPIO_SetMode(handle->config->mosi_1_pin->port, handle->config->mosi_1_pin->pin, XMC_GPIO_MODE_INPUT_TRISTATE);
break;
case XMC_SPI_CH_MODE_QUAD:
XMC_GPIO_SetMode(handle->config->mosi_0_pin->port, handle->config->mosi_0_pin->pin, XMC_GPIO_MODE_INPUT_TRISTATE);
XMC_GPIO_SetMode(handle->config->mosi_1_pin->port, handle->config->mosi_1_pin->pin, XMC_GPIO_MODE_INPUT_TRISTATE);
XMC_GPIO_SetMode(handle->config->mosi_2_pin->port, handle->config->mosi_2_pin->pin, XMC_GPIO_MODE_INPUT_TRISTATE);
XMC_GPIO_SetMode(handle->config->mosi_3_pin->port, handle->config->mosi_3_pin->pin, XMC_GPIO_MODE_INPUT_TRISTATE);
break;
default:
break;
}
}
/*******************************************************************************
* Function Name: SPI_MASTER_lValidateModeChange
********************************************************************************
* Summary:
* This function is used check whether the mode change is valid or not
*
* Parameters:
* - SPI_MASTER_t* const handle - Pointer to SPI Master configuration
* structure
* - XMC_SPI_CH_MODE_t mode - SPI transfer mode to be changed to
*
* Return:
* void
*
*******************************************************************************/
static SPI_MASTER_STATUS_t SPI_MASTER_lValidateModeChange(const SPI_MASTER_t * handle, XMC_SPI_CH_MODE_t mode)
{
SPI_MASTER_STATUS_t status;
status = SPI_MASTER_STATUS_SUCCESS;
if ((handle->config->spi_master_config_mode == XMC_SPI_CH_MODE_STANDARD_HALFDUPLEX) ||
(handle->config->spi_master_config_mode < mode))
{
status = SPI_MASTER_STATUS_FAILURE;
}
else if (handle->config->spi_master_config_mode == XMC_SPI_CH_MODE_STANDARD)
{
if (XMC_SPI_CH_MODE_DUAL <= mode)
{
status = SPI_MASTER_STATUS_FAILURE;
}
}
else
{
if ((mode == XMC_SPI_CH_MODE_STANDARD) && (handle->runtime->dx0_input == SPI_MASTER_INPUT_INVALID))
{
status = SPI_MASTER_STATUS_FAILURE;
}
else if ((mode == XMC_SPI_CH_MODE_STANDARD_HALFDUPLEX) && (handle->runtime->dx0_input_half_duplex == SPI_MASTER_INPUT_INVALID))
{
status = SPI_MASTER_STATUS_FAILURE;
}
else
{
/* added to abide MISRA */
}
}
return status;
}
/* [] END OF FILE */