/** * @file spi_master.c * @date 2018-06-20 * * NOTE: * This file is generated by DAVE. Any manual modification done to this file will be lost when the code is regenerated. * * @cond *********************************************************************************************************************** * SPI_MASTER v4.3.24 - Configures the properties of USIC channel to support SPI mode of communication. * * Copyright (c) 2015-2018, Infineon Technologies AG * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification,are permitted provided that the * following conditions are met: * * Redistributions of source code must retain the above copyright notice, this list of conditions and the following * disclaimer. * * 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. * * Neither the name of the copyright holders nor the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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. * * To improve the quality of the software, users are encouraged to share modifications, enhancements or bug fixes * with Infineon Technologies AG (dave@infineon.com). *********************************************************************************************************************** * * Change History * -------------- * * 2015-02-16: * - Initial version
* * 2015-02-20: * - SPI_MASTER_SetMode() API is updated to return, error if mode change is not possible.
* * 2015-05-08: * - SPI_MASTER_SetBaudRate() and SPI_MASTER_Transfer() are added
* - "SPI_MASTER_OVERSAMPLING" macro is removed, since it is not being used
* - SPI_MASTER_lInit() prototype is moved to spi_master_conf.c file
* - All local APIs are made as static
* - Added SPI_MASTER_lPortModeSet() and SPI_MASTER_lPortModeReset() to support SPI_MASTER_SetBaudRate() API
* - SPI_MASTER_lStd_RBUF_Flush() renamed as SPI_MASTER_lStd_RBUFFlush()
* - SPI_MASTER_lGetFIFOSize() is removed by replacing the functionality
* - In SPI_MASTER_Receive(), SPI_MASTER_Transmit() APIs a runtime condition check is added for null data pointer * and length
* - In SPI_MASTER_lTransmitHandler() API, local call to FIFO fill is removed and replaced with code
* * 2015-06-20: * - For SPI_MASTER_Transfer(), SPI_MASTER_Receive(), SPI_MASTER_Transmit() APIs, the input data pointer is changed * from 16-bit to 8-bit. * - Word count in Transmission and reception APIs, is updated according to the word length set, * instead of data length. * - In SPI_MASTER_Transfer() API, a check is added to support full duplex mode only. * - SPI_MASTER_lFIFORead() local API signature is changed to accept number of bytes per word. * - word_length is moved from SPI_MASTER_CONFIG_t to SPI_MASTER_DYNAMIC_CONFIG_t, to support runtime change. * - Abort API are updated to return the status. * * 2015-07-07: * - DYNAMIC_CONFIG_t is renamed as RUNTIME_t * * 2015-09-30: * - SPI_MASTER_STATUS_MODE_MISMATCH is returned from the transmit and receive APIs * * 2015-10-08: * - SPI_MASTER_lValidateModeChange() local API is added to chekc the mode change is vaild or not. * - Abort APIs are updated. * * 2015-10-14: * - new variable "spi_master_config_mode" to store the actual mode generated during initialisation. * - SPI_MASTER_lValidateModeChange() is updated to support full-duplex to half-duplex mode. * - XMC_USIC_CH_TriggerServiceRequest() is removed from the DMA transmit by adding during init. * * 2015-12-17: * - Corrected transmission of unintended data during reception. * * 2016-04-07: * - memcpy() usage is eliminated. * - Usage of the XMC_SPI_Transmit() API is replaced with XMC_USIC_CH_WriteToTBUFTCI(), * XMC_USIC_CH_TXFIFO_PutDataHPCMode() based on the mode selected to improve the performance. * * 2016-06-07: * - SPI_MASTER_Receive API in direct mode, corrected. * * 2016-10-26: * - Fix issue when using FIFO and high baudrates by setting the RX FIFO limit to half of the RX FIFO size. * * 2018-06-20: * - Fix SPI_MASTER_lReceiveHandler FIFO limit setting * * @endcond * */ /*********************************************************************************************************************** * 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) /*********************************************************************************************************************** * LOCAL DATA ***********************************************************************************************************************/ /*********************************************************************************************************************** * LOCAL ROUTINES **********************************************************************************************************************/ #if (SPI_MASTER_INTERRUPT_TRANSMIT_MODE == 1U) /* Transmit interrupt handler for the APP */ void SPI_MASTER_lTransmitHandler(const SPI_MASTER_t * const handle); #endif #if (SPI_MASTER_INTERRUPT_RECEIVE_MODE == 1U) 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); #endif #if(SPI_MASTER_DMA_RECEIVE_MODE == 1U) static SPI_MASTER_STATUS_t SPI_MASTER_lReceiveDMA(const SPI_MASTER_t *const handle, uint32_t count); #endif #if(SPI_MASTER_DIRECT_TRANSMIT_MODE == 1U) static SPI_MASTER_STATUS_t SPI_MASTER_lStartTransmitPolling(const SPI_MASTER_t *const handle, uint8_t* dataptr, uint32_t count); #endif #if(SPI_MASTER_DIRECT_RECEIVE_MODE == 1U) static SPI_MASTER_STATUS_t SPI_MASTER_lStartReceivePolling(const SPI_MASTER_t *const handle, uint8_t* dataptr, uint32_t count); static SPI_MASTER_STATUS_t SPI_MASTER_lReceivePolling(const SPI_MASTER_t *const handle, uint32_t count); #endif #ifdef SPI_MASTER_PARITY_ERROR /* Protocol interrupt handler for the APP */ void SPI_MASTER_lProtocolHandler(const SPI_MASTER_t * const handle); #endif /* 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); /*********************************************************************************************************************** * API IMPLEMENTATION **********************************************************************************************************************/ /* * API to retrieve the version of the SPI_MASTER */ DAVE_APP_VERSION_t SPI_MASTER_GetAppVersion() { DAVE_APP_VERSION_t version; version.major = SPI_MASTER_MAJOR_VERSION; version.minor = SPI_MASTER_MINOR_VERSION; version.patch = SPI_MASTER_PATCH_VERSION; return version; } /* * This function initializes the SPI channel, based on UI configuration. */ SPI_MASTER_STATUS_t SPI_MASTER_Init(SPI_MASTER_t* const handle) { SPI_MASTER_STATUS_t status; XMC_ASSERT("SPI_MASTER_Init:handle NULL" , (handle != NULL)); /* Configure the port registers and data input registers of SPI channel */ status = handle->config->fptr_spi_master_config(); return status; } /* * Change the SPI mode of communication. */ 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; } /* * Set the baud rate during runtime. */ 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; } 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 (SPI_MASTER_INTERRUPT_TRANSMIT_MODE == 1U) if (handle->config->transmit_mode == SPI_MASTER_TRANSFER_MODE_INTERRUPT) { status = SPI_MASTER_StartTransmitIRQ(handle, dataptr, count); } #endif #if (SPI_MASTER_DMA_TRANSMIT_MODE == 1U) if (handle->config->transmit_mode == SPI_MASTER_TRANSFER_MODE_DMA) { status = SPI_MASTER_StartTransmitDMA(handle, dataptr, count); } #endif #if (SPI_MASTER_DIRECT_TRANSMIT_MODE == 1U) if (handle->config->transmit_mode == SPI_MASTER_TRANSFER_MODE_DIRECT) { status = SPI_MASTER_lStartTransmitPolling(handle, dataptr, count); } #endif return status; } 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 (SPI_MASTER_INTERRUPT_RECEIVE_MODE == 1U) if (handle->config->receive_mode == SPI_MASTER_TRANSFER_MODE_INTERRUPT) { status = SPI_MASTER_StartReceiveIRQ(handle, dataptr, count); } #endif #if (SPI_MASTER_DMA_RECEIVE_MODE == 1U) if (handle->config->receive_mode == SPI_MASTER_TRANSFER_MODE_DMA) { status = SPI_MASTER_StartReceiveDMA(handle, dataptr, count); } #endif #if (SPI_MASTER_DIRECT_RECEIVE_MODE == 1U) if (handle->config->receive_mode == SPI_MASTER_TRANSFER_MODE_DIRECT) { status = SPI_MASTER_lStartReceivePolling(handle, dataptr, count); } #endif return status; } #if (SPI_MASTER_INTERRUPT_TRANSMIT_MODE == 1U) /* * Transmit the number of data words specified. */ 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; } #endif #if(SPI_MASTER_DMA_TRANSMIT_MODE == 1U) SPI_MASTER_STATUS_t SPI_MASTER_StartTransmitDMA(const SPI_MASTER_t *const handle, uint8_t *data_ptr, uint32_t block_size) { SPI_MASTER_STATUS_t status; SPI_MASTER_RUNTIME_t * runtime_handle; uint32_t dma_ctll; uint32_t mode; XMC_ASSERT("SPI_MASTER_StartTransmitDMA:handle NULL" , (handle != NULL)); status = SPI_MASTER_STATUS_MODE_MISMATCH; runtime_handle = handle->runtime; if (handle->config->transmit_mode == SPI_MASTER_TRANSFER_MODE_DMA) { /* Check whether SPI channel is free or not */ if (false == runtime_handle->tx_busy) { /* Check data pointer is valid or not */ if ((data_ptr != NULL) && (block_size > 0U) && (block_size <= SPI_MASTER_DMA_MAXCOUNT)) { /* Obtain the address of data, size of data */ runtime_handle->tx_data_count = block_size; /* Initialize to first index and set the busy flag */ runtime_handle->tx_data_index = 0U; runtime_handle->tx_busy = true; if (runtime_handle->tx_data_dummy == true) { dma_ctll = (uint32_t)handle->global_dma->dma->CH[handle->dma_ch_tx_number].CTLL; dma_ctll = (uint32_t)(dma_ctll & (uint32_t)(~(GPDMA0_CH_CTLL_SINC_Msk))) | ((uint32_t)XMC_DMA_CH_ADDRESS_COUNT_MODE_NO_CHANGE << GPDMA0_CH_CTLL_SINC_Pos); handle->global_dma->dma->CH[handle->dma_ch_tx_number].CTLL = dma_ctll; mode = (uint32_t)((uint32_t)handle->runtime->spi_master_mode & 0xfffbU); } else { runtime_handle->tx_data = data_ptr; dma_ctll = handle->global_dma->dma->CH[handle->dma_ch_tx_number].CTLL; dma_ctll = (uint32_t)(dma_ctll & (~GPDMA0_CH_CTLL_SINC_Msk)) | ((uint32_t)XMC_DMA_CH_ADDRESS_COUNT_MODE_INCREMENT << GPDMA0_CH_CTLL_SINC_Pos); handle->global_dma->dma->CH[handle->dma_ch_tx_number].CTLL = dma_ctll; mode = (uint32_t)handle->runtime->spi_master_mode; } /* Enable transmit event generation */ XMC_SPI_CH_EnableEvent(handle->channel, (uint32_t)XMC_SPI_CH_EVENT_RECEIVE_START); XMC_DMA_CH_SetBlockSize(handle->global_dma->dma, handle->dma_ch_tx_number, block_size); XMC_DMA_CH_SetSourceAddress(handle->global_dma->dma, handle->dma_ch_tx_number, (uint32_t)runtime_handle->tx_data); XMC_SPI_CH_SetTransmitMode(handle->channel, runtime_handle->spi_master_mode); XMC_DMA_CH_SetDestinationAddress(handle->global_dma->dma, handle->dma_ch_tx_number, (uint32_t)&(handle->channel->TBUF[mode])); status = SPI_MASTER_STATUS_SUCCESS; XMC_DMA_CH_Enable(handle->global_dma->dma, handle->dma_ch_tx_number); } else { status = SPI_MASTER_STATUS_BUFFER_INVALID; } } else { status = SPI_MASTER_STATUS_BUSY; } } return status; } #endif #if (SPI_MASTER_DIRECT_TRANSMIT_MODE == 1U) SPI_MASTER_STATUS_t SPI_MASTER_lStartTransmitPolling(const SPI_MASTER_t *const handle, uint8_t* dataptr, uint32_t count) { SPI_MASTER_STATUS_t status; uint16_t data; 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; status = SPI_MASTER_STATUS_BUSY; runtime_handle = handle->runtime; data = 0U; XMC_ASSERT("SPI_MASTER_lStartTransmitPolling:handle NULL" , (handle != NULL)); /* Check whether SPI channel is free or not */ if ((dataptr != NULL) && (count > 0U)) { /* 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 */ } runtime_handle->tx_busy = true; /* 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; XMC_SPI_CH_SetTransmitMode(handle->channel, runtime_handle->spi_master_mode); if ((uint32_t)handle->config->tx_fifo_size > 0U) { /* Flush the Transmit FIFO */ XMC_USIC_CH_TXFIFO_Flush(handle->channel); while (runtime_handle->tx_data_index < runtime_handle->tx_data_count) { while (XMC_USIC_CH_TXFIFO_IsFull(handle->channel) == true) { /* Wait until FIFO is having space for next entry */ } 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 { do { while((uint32_t)XMC_USIC_CH_GetTransmitBufferStatus(handle->channel) == (uint32_t)XMC_USIC_CH_TBUF_STATUS_BUSY) { } if (runtime_handle->tx_data_dummy == true) { XMC_USIC_CH_WriteToTBUFTCI(handle->channel, 0xFFFFU, 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, runtime_handle->spi_master_mode); } (runtime_handle->tx_data_index)+=bytes_per_word; while ((XMC_SPI_CH_GetStatusFlag(handle->channel) & (uint32_t)XMC_SPI_CH_STATUS_FLAG_RECEIVER_START_INDICATION) == 0U) { } XMC_SPI_CH_ClearStatusFlag(handle->channel, (uint32_t)XMC_SPI_CH_STATUS_FLAG_RECEIVER_START_INDICATION); } while(runtime_handle->tx_data_index < runtime_handle->tx_data_count); } while((uint32_t)XMC_USIC_CH_GetTransmitBufferStatus(handle->channel) == (uint32_t)XMC_USIC_CH_TBUF_STATUS_BUSY) { } runtime_handle->tx_busy = false; runtime_handle->tx_data_count = 0U; runtime_handle->tx_data_index = 0U; status = SPI_MASTER_STATUS_SUCCESS; } } else { status = SPI_MASTER_STATUS_BUFFER_INVALID; } runtime_handle->rx_data_dummy = true; return status; } #endif #if (SPI_MASTER_DIRECT_RECEIVE_MODE == 1U) SPI_MASTER_STATUS_t SPI_MASTER_lStartReceivePolling(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_lStartReceivePolling:handle NULL" , (handle != NULL)); status = SPI_MASTER_STATUS_BUSY; runtime_handle = handle->runtime; 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_dummy = true; runtime_handle->rx_data_dummy = false; status = SPI_MASTER_lReceivePolling(handle, count); runtime_handle->tx_data_dummy = false; runtime_handle->rx_busy = false; } } else { status = SPI_MASTER_STATUS_BUFFER_INVALID; } return status; } #endif #if (SPI_MASTER_INTERRUPT_RECEIVE_MODE == 1U) /* * Receive the specified the number of data words. */ 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; } #endif #if(SPI_MASTER_DMA_RECEIVE_MODE == 1U) SPI_MASTER_STATUS_t SPI_MASTER_StartReceiveDMA(const SPI_MASTER_t *const handle, uint8_t *dataptr, uint32_t block_size) { SPI_MASTER_STATUS_t status; SPI_MASTER_RUNTIME_t * runtime_handle; static uint8_t dummy_data[2] = {0xFFU, 0xFFU}; XMC_ASSERT("SPI_MASTER_StartReceiveDMA:handle NULL" , (handle != NULL)); status = SPI_MASTER_STATUS_MODE_MISMATCH; runtime_handle = handle->runtime; if (handle->config->receive_mode == SPI_MASTER_TRANSFER_MODE_DMA) { status = SPI_MASTER_STATUS_BUSY; /* Check whether SPI channel is free or not */ if ((false == runtime_handle->rx_busy) && (false == runtime_handle->tx_busy)) { /* Check data pointer is valid or not */ if ((dataptr != NULL) && (block_size > 0U) && (block_size <= SPI_MASTER_DMA_MAXCOUNT)) { runtime_handle->rx_busy = true; runtime_handle->rx_data = dataptr; runtime_handle->tx_data = &dummy_data[0]; runtime_handle->tx_data_count = block_size; runtime_handle->tx_data_dummy = true; runtime_handle->rx_data_dummy = false; status = SPI_MASTER_lReceiveDMA(handle, block_size); } else { status = SPI_MASTER_STATUS_BUFFER_INVALID; } } else { status = SPI_MASTER_STATUS_BUSY; } } return status; } #endif /* * Transmit and receive the data at the same time. This is supported for full duplex mode only. */ 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 (SPI_MASTER_INTERRUPT_RECEIVE_MODE == 1U) if (handle->config->receive_mode == SPI_MASTER_TRANSFER_MODE_INTERRUPT) { status = SPI_MASTER_lReceiveIRQ(handle, count); } #endif #if (SPI_MASTER_DMA_RECEIVE_MODE == 1U) if (handle->config->receive_mode == SPI_MASTER_TRANSFER_MODE_DMA) { status = SPI_MASTER_lReceiveDMA(handle, count); } #endif #if (SPI_MASTER_DIRECT_RECEIVE_MODE == 1U) if (handle->config->receive_mode == SPI_MASTER_TRANSFER_MODE_DIRECT) { status = SPI_MASTER_lReceivePolling(handle, count); runtime_handle->rx_busy = false; } #endif } } else { status = SPI_MASTER_STATUS_BUFFER_INVALID; } } else { status = SPI_MASTER_STATUS_FAILURE; } return status; } /* * Aborts the ongoing data reception. */ 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 { #if (SPI_MASTER_DMA_RECEIVE_MODE == 1U) if (handle->config->receive_mode == SPI_MASTER_TRANSFER_MODE_DMA) { /* Disable the receive event */ if(XMC_DMA_CH_IsEnabled(handle->global_dma->dma, handle->dma_ch_rx_number)) { XMC_DMA_CH_Disable(handle->global_dma->dma, handle->dma_ch_rx_number); while(XMC_DMA_CH_IsEnabled(handle->global_dma->dma, handle->dma_ch_rx_number)==true) { } XMC_SPI_CH_DisableEvent(handle->channel, (uint32_t)((uint32_t)XMC_USIC_CH_EVENT_STANDARD_RECEIVE | (uint32_t)XMC_USIC_CH_EVENT_ALTERNATIVE_RECEIVE)); } } else #endif { 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; } /* * Aborts the ongoing data transmission. */ 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 { #if (SPI_MASTER_DMA_TRANSMIT_MODE == 1U) if(handle->config->transmit_mode == SPI_MASTER_TRANSFER_MODE_DMA) { /*Disable the standard transmit event*/ if(XMC_DMA_CH_IsEnabled(handle->global_dma->dma, handle->dma_ch_tx_number)) { XMC_DMA_CH_Disable(handle->global_dma->dma, handle->dma_ch_tx_number); while(XMC_DMA_CH_IsEnabled(handle->global_dma->dma, handle->dma_ch_tx_number)==true) { } XMC_SPI_CH_DisableEvent(handle->channel, (uint32_t)XMC_USIC_CH_EVENT_TRANSMIT_BUFFER); } } else #endif { /*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; } /*********************************************************************************************************************** ** Private API definitions ** ***********************************************************************************************************************/ #if(SPI_MASTER_INTERRUPT_TRANSMIT_MODE == 1U) /* * Transmit interrupt handler for the APP. * This is a common interrupt handling function called for different instances of the APP. * */ 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; } } } else/*When Transmit FIFO is disabled*/ { 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(); } } } } #endif #if (SPI_MASTER_INTERRUPT_RECEIVE_MODE == 1U) 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; } /* * Receive interrupt handler for the APP. * This is a common interrupt handling function for different instances of the SPI_MASTER APP. */ 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); /* Reconfigure the RXFIFO trigger limit based on pending receive bytes */ if ((runtime_handle->rx_data_count - runtime_handle->rx_data_index) <= (1UL << (handle->config->rx_fifo_size - 1))) { 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(); } } } } /* * Read the data from FIFO until it becomes empty. */ 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; } } } /* * This function configures the FIFO settings */ 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 = 1UL << (handle->config->rx_fifo_size - 1); 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; } /*Set the limit value*/ XMC_USIC_CH_RXFIFO_SetSizeTriggerLimit(handle->channel, handle->config->rx_fifo_size, ret_limit_val); } } #endif #if (SPI_MASTER_DIRECT_RECEIVE_MODE == 1U) SPI_MASTER_STATUS_t SPI_MASTER_lReceivePolling(const SPI_MASTER_t *const handle, uint32_t count) { 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 */ uint16_t data; runtime_handle = handle->runtime; data = 0U; runtime_handle->rx_data_index = 0U; runtime_handle->tx_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 */ } runtime_handle->rx_data_count = (uint32_t)count << (bytes_per_word - 1U); XMC_SPI_CH_SetTransmitMode(handle->channel, runtime_handle->spi_master_mode); /* 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); 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; while (runtime_handle->tx_data_index < runtime_handle->rx_data_count) { 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); } while(XMC_USIC_CH_RXFIFO_IsEmpty(handle->channel) == true) { } 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; (runtime_handle->tx_data_index)+= bytes_per_word; } while(XMC_USIC_CH_RXFIFO_IsEmpty(handle->channel) == true) { } 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); } XMC_USIC_CH_RXFIFO_ClearEvent(handle->channel, SPI_MASTER_FIFO_RECEIVE_INDICATION_FLAG); } else { /* Flush the RBUF0 and RBUF1 */ SPI_MASTER_lStdRBUFFlush(handle->channel); while((uint32_t)XMC_USIC_CH_GetTransmitBufferStatus(handle->channel) == (uint32_t)XMC_USIC_CH_TBUF_STATUS_BUSY) { } 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; while (runtime_handle->tx_data_index < runtime_handle->rx_data_count) { while((uint32_t)XMC_USIC_CH_GetTransmitBufferStatus(handle->channel) == (uint32_t)XMC_USIC_CH_TBUF_STATUS_BUSY) { } 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); } while (XMC_USIC_CH_GetReceiveBufferStatus(handle->channel) == 0U) { } 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; (runtime_handle->tx_data_index)+= bytes_per_word; XMC_SPI_CH_ClearStatusFlag(handle->channel, SPI_MASTER_RECEIVE_INDICATION_FLAG); } while (XMC_USIC_CH_GetReceiveBufferStatus(handle->channel) == 0U) { } 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); } XMC_SPI_CH_ClearStatusFlag(handle->channel, SPI_MASTER_RECEIVE_INDICATION_FLAG); } runtime_handle->rx_data_count = 0U; runtime_handle->rx_data_index = 0U; runtime_handle->tx_data_index = 0U; return SPI_MASTER_STATUS_SUCCESS; } #endif #if (SPI_MASTER_DMA_RECEIVE_MODE == 1U) SPI_MASTER_STATUS_t SPI_MASTER_lReceiveDMA(const SPI_MASTER_t *const handle, uint32_t block_size) { SPI_MASTER_STATUS_t status; SPI_MASTER_RUNTIME_t * runtime_handle; runtime_handle = handle->runtime; runtime_handle->rx_data_index = 0U; runtime_handle->rx_data_count = (uint32_t)block_size; SPI_MASTER_lStdRBUFFlush(handle->channel); XMC_SPI_CH_EnableEvent(handle->channel, (uint32_t)SPI_MASTER_RECEIVE_EVENT); XMC_DMA_CH_SetBlockSize(handle->global_dma->dma, handle->dma_ch_rx_number, runtime_handle->rx_data_count); XMC_DMA_CH_SetSourceAddress(handle->global_dma->dma, handle->dma_ch_rx_number, (uint32_t)&(handle->channel->RBUF)); XMC_DMA_CH_SetDestinationAddress(handle->global_dma->dma, handle->dma_ch_rx_number, (uint32_t)runtime_handle->rx_data); status = SPI_MASTER_STATUS_SUCCESS; XMC_DMA_CH_Enable(handle->global_dma->dma, handle->dma_ch_rx_number); /* Call the transmit, to receive the data synchronously */ status = SPI_MASTER_Transmit(handle, runtime_handle->tx_data, runtime_handle->tx_data_count); return status; } #endif /* * Clears the receive buffers */ 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); } #if (SPI_MASTER_PARITY_ERROR == 1U) /* * Protocol interrupt handling function. * The function is common for different instances of the SPI_MASTER APP. */ void SPI_MASTER_lProtocolHandler(const SPI_MASTER_t * const handle) { uint32_t psr_status; psr_status = XMC_SPI_CH_GetStatusFlag(handle->channel); /*Check for Parity detection error */ if ((handle->config->parity_cbhandler != NULL) && \ (psr_status & (uint32_t)XMC_SPI_CH_STATUS_FLAG_PARITY_ERROR_EVENT_DETECTED)) { handle->config->parity_cbhandler(); } } #endif /* * This is used to reconfigure the registers while changing the SPI mode dynamically */ 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; } } /* * This is used to reassign the mode for ports after updating the baud rate */ 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; } } /* * This is used to make the ports as input during update of the baud rate, to avoid the noise in output ports */ 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; } } /* * This is used check whether the 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) { 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; }