diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL27Z/drivers/fsl_spi.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL27Z/drivers/fsl_spi.c index a7c137618b..df67413d61 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL27Z/drivers/fsl_spi.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL27Z/drivers/fsl_spi.c @@ -1,38 +1,22 @@ /* * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP * All rights reserved. * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * o Redistributions of source code must retain the above copyright notice, this list - * of conditions and the following disclaimer. - * - * o 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. - * - * o Neither the name of Freescale Semiconductor, Inc. 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. + * SPDX-License-Identifier: BSD-3-Clause */ #include "fsl_spi.h" /******************************************************************************* - * Definitons + * Definitions ******************************************************************************/ + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.spi" +#endif + /*! @brief SPI transfer state, which is used for SPI transactiaonl APIs' internal state. */ enum _spi_transfer_states_t { @@ -46,12 +30,6 @@ typedef void (*spi_isr_t)(SPI_Type *base, spi_master_handle_t *spiHandle); /******************************************************************************* * Prototypes ******************************************************************************/ -/*! - * @brief Get the instance for SPI module. - * - * @param base SPI base address - */ -uint32_t SPI_GetInstance(SPI_Type *base); /*! * @brief Sends a buffer of data bytes in non-blocking way. @@ -71,6 +49,14 @@ static void SPI_WriteNonBlocking(SPI_Type *base, uint8_t *buffer, size_t size); */ static void SPI_ReadNonBlocking(SPI_Type *base, uint8_t *buffer, size_t size); +/*! + * @brief Get the waterrmark value for this SPI instance. + * + * @param base SPI base pointer + * @return Watermark value for the SPI instance. + */ +static uint8_t SPI_GetWatermark(SPI_Type *base); + /*! * @brief Send a piece of data for SPI. * @@ -78,6 +64,7 @@ static void SPI_ReadNonBlocking(SPI_Type *base, uint8_t *buffer, size_t size); * and write the data into it. At the same time, this function updates the values in * master handle structure. * + * @param base SPI base pointer * @param handle Pointer to SPI master handle structure. */ static void SPI_SendTransfer(SPI_Type *base, spi_master_handle_t *handle); @@ -89,9 +76,18 @@ static void SPI_SendTransfer(SPI_Type *base, spi_master_handle_t *handle); * and write the data to destination address. At the same time, this function updates * the values in master handle structure. * + * @param base SPI base pointer * @param handle Pointer to SPI master handle structure. */ static void SPI_ReceiveTransfer(SPI_Type *base, spi_master_handle_t *handle); + +/*! + * @brief Common IRQ handler for SPI. + * + * @param base SPI base pointer. + * @param instance SPI instance number. + */ +static void SPI_CommonIRQHandler(SPI_Type *base, uint32_t instance); /******************************************************************************* * Variables ******************************************************************************/ @@ -101,21 +97,31 @@ static spi_master_handle_t *s_spiHandle[FSL_FEATURE_SOC_SPI_COUNT]; static SPI_Type *const s_spiBases[] = SPI_BASE_PTRS; /*! @brief IRQ name array */ static const IRQn_Type s_spiIRQ[] = SPI_IRQS; +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /*! @brief Clock array name */ static const clock_ip_name_t s_spiClock[] = SPI_CLOCKS; +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ /*! @brief Pointer to master IRQ handler for each instance. */ -static spi_isr_t s_spiIsr; +static spi_isr_t s_spiMasterIsr; +static spi_isr_t s_spiSlaveIsr; +/* @brief Dummy data for each instance. This data is used when user's tx buffer is NULL*/ +volatile uint8_t g_spiDummyData[ARRAY_SIZE(s_spiBases)] = {0}; /******************************************************************************* * Code ******************************************************************************/ +/*! + * brief Get the instance for SPI module. + * + * param base SPI base address + */ uint32_t SPI_GetInstance(SPI_Type *base) { uint32_t instance; /* Find the instance index from base address mappings. */ - for (instance = 0; instance < FSL_FEATURE_SOC_SPI_COUNT; instance++) + for (instance = 0; instance < ARRAY_SIZE(s_spiBases); instance++) { if (s_spiBases[instance] == base) { @@ -123,15 +129,28 @@ uint32_t SPI_GetInstance(SPI_Type *base) } } - assert(instance < FSL_FEATURE_SOC_SPI_COUNT); + assert(instance < ARRAY_SIZE(s_spiBases)); return instance; } +/*! + * brief Set up the dummy data. + * + * param base SPI peripheral address. + * param dummyData Data to be transferred when tx buffer is NULL. + */ +void SPI_SetDummyData(SPI_Type *base, uint8_t dummyData) +{ + uint32_t instance = SPI_GetInstance(base); + g_spiDummyData[instance] = dummyData; +} + static void SPI_WriteNonBlocking(SPI_Type *base, uint8_t *buffer, size_t size) { - uint32_t i = 0; + uint32_t i = 0; uint8_t bytesPerFrame = 1U; + uint32_t instance = SPI_GetInstance(base); #if defined(FSL_FEATURE_SPI_16BIT_TRANSFERS) && FSL_FEATURE_SPI_16BIT_TRANSFERS /* Check if 16 bits or 8 bits */ @@ -155,13 +174,13 @@ static void SPI_WriteNonBlocking(SPI_Type *base, uint8_t *buffer, size_t size) base->DL = *buffer++; } #else - base->D = *buffer++; + base->D = *buffer++; #endif /* FSL_FEATURE_SPI_16BIT_TRANSFERS */ } /* Send dummy data */ else { - SPI_WriteData(base, SPI_DUMMYDATA); + SPI_WriteData(base, ((uint32_t)g_spiDummyData[instance] << 8 | g_spiDummyData[instance])); } i += bytesPerFrame; } @@ -169,7 +188,7 @@ static void SPI_WriteNonBlocking(SPI_Type *base, uint8_t *buffer, size_t size) static void SPI_ReadNonBlocking(SPI_Type *base, uint8_t *buffer, size_t size) { - uint32_t i = 0; + uint32_t i = 0; uint8_t bytesPerFrame = 1U; #if defined(FSL_FEATURE_SPI_16BIT_TRANSFERS) && FSL_FEATURE_SPI_16BIT_TRANSFERS @@ -205,18 +224,68 @@ static void SPI_ReadNonBlocking(SPI_Type *base, uint8_t *buffer, size_t size) } } +/* Get the watermark value of transfer. Please note that the entery width of FIFO is 16 bits. */ +static uint8_t SPI_GetWatermark(SPI_Type *base) +{ + uint8_t ret = 0; +#if defined(FSL_FEATURE_SPI_HAS_FIFO) && FSL_FEATURE_SPI_HAS_FIFO + uint8_t rxSize = 0U; + /* Get the number to be sent if there is FIFO */ + if (FSL_FEATURE_SPI_FIFO_SIZEn(base) != 0) + { + rxSize = (base->C3 & SPI_C3_RNFULLF_MARK_MASK) >> SPI_C3_RNFULLF_MARK_SHIFT; + if (rxSize == 0U) + { + ret = FSL_FEATURE_SPI_FIFO_SIZEn(base) * 3U / 4U; + } + else + { + ret = FSL_FEATURE_SPI_FIFO_SIZEn(base) / 2U; + } + } + /* If no FIFO, just set the watermark to 1 */ + else + { + ret = 1U; + } +#else + ret = 1U; +#endif /* FSL_FEATURE_SPI_HAS_FIFO */ + return ret; +} + +static void SPI_SendInitialTransfer(SPI_Type *base, spi_master_handle_t *handle) +{ + uint8_t bytestoTransfer = handle->bytePerFrame; + +#if defined(FSL_FEATURE_SPI_HAS_FIFO) && (FSL_FEATURE_SPI_HAS_FIFO) + if (handle->watermark > 1) + { + /* In the first time to send data to FIFO, if transfer size is not larger than + * the FIFO size, send all data to FIFO, or send data to make the FIFO full. + * Besides, The FIFO's entry width is 16 bits, need to translate it to bytes. + */ + bytestoTransfer = MIN(handle->txRemainingBytes, (FSL_FEATURE_SPI_FIFO_SIZEn(base) * 2)); + } +#endif + + SPI_WriteNonBlocking(base, handle->txData, bytestoTransfer); + + /* Update handle information */ + if (handle->txData) + { + handle->txData += bytestoTransfer; + } + handle->txRemainingBytes -= bytestoTransfer; +} + static void SPI_SendTransfer(SPI_Type *base, spi_master_handle_t *handle) { - uint8_t bytes = MIN((handle->watermark * 2U), handle->txRemainingBytes); + uint8_t bytes = handle->bytePerFrame; /* Read S register and ensure SPTEF is 1, otherwise the write would be ignored. */ if (handle->watermark == 1U) { - if (bytes != 0U) - { - bytes = handle->bytePerFrame; - } - /* Send data */ if (base->C1 & SPI_C1_MSTR_MASK) { @@ -231,11 +300,11 @@ static void SPI_SendTransfer(SPI_Type *base, spi_master_handle_t *handle) } handle->txRemainingBytes -= bytes; } - } - else - { + } + else + { /* As a slave, send data until SPTEF cleared */ - while ((base->S & SPI_S_SPTEF_MASK) && (handle->txRemainingBytes > 0)) + while ((base->S & SPI_S_SPTEF_MASK) && (handle->txRemainingBytes >= bytes)) { SPI_WriteNonBlocking(base, handle->txData, bytes); @@ -253,56 +322,96 @@ static void SPI_SendTransfer(SPI_Type *base, spi_master_handle_t *handle) /* If use FIFO */ else { - if (base->S & SPI_S_TNEAREF_MASK) - { - SPI_WriteNonBlocking(base, handle->txData, bytes); + /* The FIFO's entry width is 16 bits, need to translate it to bytes. */ + uint8_t bytestoTransfer = handle->watermark * 2; - /* Update handle information */ - if (handle->txData) - { - handle->txData += bytes; - } - handle->txRemainingBytes -= bytes; + if (handle->txRemainingBytes < 8U) + { + bytestoTransfer = handle->txRemainingBytes; } + + SPI_WriteNonBlocking(base, handle->txData, bytestoTransfer); + + /* Update handle information */ + if (handle->txData) + { + handle->txData += bytestoTransfer; + } + handle->txRemainingBytes -= bytestoTransfer; } #endif } static void SPI_ReceiveTransfer(SPI_Type *base, spi_master_handle_t *handle) { - uint8_t bytes = MIN((handle->watermark * 2U), handle->rxRemainingBytes); - uint8_t val = 1U; + uint8_t bytes = handle->bytePerFrame; /* Read S register and ensure SPRF is 1, otherwise the write would be ignored. */ if (handle->watermark == 1U) { - val = base->S & SPI_S_SPRF_MASK; - if (bytes != 0U) + if (base->S & SPI_S_SPRF_MASK) { - bytes = handle->bytePerFrame; + SPI_ReadNonBlocking(base, handle->rxData, bytes); + + /* Update information in handle */ + if (handle->rxData) + { + handle->rxData += bytes; + } + handle->rxRemainingBytes -= bytes; } } - - if (val) +#if defined(FSL_FEATURE_SPI_HAS_FIFO) && (FSL_FEATURE_SPI_HAS_FIFO) + /* If use FIFO */ + else { - SPI_ReadNonBlocking(base, handle->rxData, bytes); - - /* Update information in handle */ - if (handle->rxData) + /* While rx fifo not empty and remaining data can also trigger the last interrupt */ + while ((base->S & SPI_S_RFIFOEF_MASK) == 0U) { - handle->rxData += bytes; + SPI_ReadNonBlocking(base, handle->rxData, bytes); + + /* Update information in handle */ + if (handle->rxData) + { + handle->rxData += bytes; + } + handle->rxRemainingBytes -= bytes; + + /* If the reamining data equals to watermark, leave to last interrupt */ + if (handle->rxRemainingBytes == (handle->watermark * 2U)) + { + break; + } } - handle->rxRemainingBytes -= bytes; } +#endif } +/*! + * brief Sets the SPI master configuration structure to default values. + * + * The purpose of this API is to get the configuration structure initialized for use in SPI_MasterInit(). + * User may use the initialized structure unchanged in SPI_MasterInit(), or modify + * some fields of the structure before calling SPI_MasterInit(). After calling this API, + * the master is ready to transfer. + * Example: + code + spi_master_config_t config; + SPI_MasterGetDefaultConfig(&config); + endcode + * + * param config pointer to master config structure + */ void SPI_MasterGetDefaultConfig(spi_master_config_t *config) { - config->enableMaster = true; + /* Initializes the configure structure to zero. */ + memset(config, 0, sizeof(*config)); + + config->enableMaster = true; config->enableStopInWaitMode = false; - config->polarity = kSPI_ClockPolarityActiveHigh; - config->phase = kSPI_ClockPhaseFirstEdge; - config->direction = kSPI_MsbFirst; + config->polarity = kSPI_ClockPolarityActiveHigh; + config->phase = kSPI_ClockPhaseFirstEdge; + config->direction = kSPI_MsbFirst; #if defined(FSL_FEATURE_SPI_16BIT_TRANSFERS) && FSL_FEATURE_SPI_16BIT_TRANSFERS config->dataMode = kSPI_8BitMode; @@ -313,17 +422,37 @@ void SPI_MasterGetDefaultConfig(spi_master_config_t *config) config->rxWatermark = kSPI_RxFifoOneHalfFull; #endif /* FSL_FEATURE_SPI_HAS_FIFO */ - config->pinMode = kSPI_PinModeNormal; - config->outputMode = kSPI_SlaveSelectAutomaticOutput; + config->pinMode = kSPI_PinModeNormal; + config->outputMode = kSPI_SlaveSelectAutomaticOutput; config->baudRate_Bps = 500000U; } +/*! + * brief Initializes the SPI with master configuration. + * + * The configuration structure can be filled by user from scratch, or be set with default + * values by SPI_MasterGetDefaultConfig(). After calling this API, the slave is ready to transfer. + * Example + code + spi_master_config_t config = { + .baudRate_Bps = 400000, + ... + }; + SPI_MasterInit(SPI0, &config); + endcode + * + * param base SPI base pointer + * param config pointer to master configuration structure + * param srcClock_Hz Source clock frequency. + */ void SPI_MasterInit(SPI_Type *base, const spi_master_config_t *config, uint32_t srcClock_Hz) { assert(config && srcClock_Hz); +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /* Open clock gate for SPI and open interrupt */ CLOCK_EnableClock(s_spiClock[SPI_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ /* Disable SPI before configuration */ base->C1 &= ~SPI_C1_SPE_MASK; @@ -354,6 +483,9 @@ void SPI_MasterInit(SPI_Type *base, const spi_master_config_t *config, uint32_t /* Set baud rate */ SPI_MasterSetBaudRate(base, config->baudRate_Bps, srcClock_Hz); + /* Set the dummy data, this data will usefull when tx buffer is NULL. */ + SPI_SetDummyData(base, SPI_DUMMYDATA); + /* Enable SPI */ if (config->enableMaster) { @@ -361,12 +493,28 @@ void SPI_MasterInit(SPI_Type *base, const spi_master_config_t *config, uint32_t } } +/*! + * brief Sets the SPI slave configuration structure to default values. + * + * The purpose of this API is to get the configuration structure initialized for use in SPI_SlaveInit(). + * Modify some fields of the structure before calling SPI_SlaveInit(). + * Example: + code + spi_slave_config_t config; + SPI_SlaveGetDefaultConfig(&config); + endcode + * + * param config pointer to slave configuration structure + */ void SPI_SlaveGetDefaultConfig(spi_slave_config_t *config) { - config->enableSlave = true; - config->polarity = kSPI_ClockPolarityActiveHigh; - config->phase = kSPI_ClockPhaseFirstEdge; - config->direction = kSPI_MsbFirst; + /* Initializes the configure structure to zero. */ + memset(config, 0, sizeof(*config)); + + config->enableSlave = true; + config->polarity = kSPI_ClockPolarityActiveHigh; + config->phase = kSPI_ClockPhaseFirstEdge; + config->direction = kSPI_MsbFirst; config->enableStopInWaitMode = false; #if defined(FSL_FEATURE_SPI_16BIT_TRANSFERS) && FSL_FEATURE_SPI_16BIT_TRANSFERS @@ -377,14 +525,37 @@ void SPI_SlaveGetDefaultConfig(spi_slave_config_t *config) config->txWatermark = kSPI_TxFifoOneHalfEmpty; config->rxWatermark = kSPI_RxFifoOneHalfFull; #endif /* FSL_FEATURE_SPI_HAS_FIFO */ + config->pinMode = kSPI_PinModeNormal; } +/*! + * brief Initializes the SPI with slave configuration. + * + * The configuration structure can be filled by user from scratch or be set with + * default values by SPI_SlaveGetDefaultConfig(). + * After calling this API, the slave is ready to transfer. + * Example + code + spi_slave_config_t config = { + .polarity = kSPIClockPolarity_ActiveHigh; + .phase = kSPIClockPhase_FirstEdge; + .direction = kSPIMsbFirst; + ... + }; + SPI_MasterInit(SPI0, &config); + endcode + * + * param base SPI base pointer + * param config pointer to master configuration structure + */ void SPI_SlaveInit(SPI_Type *base, const spi_slave_config_t *config) { assert(config); +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /* Open clock gate for SPI and open interrupt */ CLOCK_EnableClock(s_spiClock[SPI_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ /* Disable SPI before configuration */ base->C1 &= ~SPI_C1_SPE_MASK; @@ -395,9 +566,11 @@ void SPI_SlaveInit(SPI_Type *base, const spi_slave_config_t *config) /* Configure data mode if needed */ #if defined(FSL_FEATURE_SPI_16BIT_TRANSFERS) && FSL_FEATURE_SPI_16BIT_TRANSFERS - base->C2 = SPI_C2_SPIMODE(config->dataMode) | SPI_C2_SPISWAI(config->enableStopInWaitMode); + base->C2 = SPI_C2_SPIMODE(config->dataMode) | SPI_C2_SPISWAI(config->enableStopInWaitMode) | + SPI_C2_BIDIROE(config->pinMode >> 1U) | SPI_C2_SPC0(config->pinMode & 1U); #else - base->C2 = SPI_C2_SPISWAI(config->enableStopInWaitMode); + base->C2 = SPI_C2_SPISWAI(config->enableStopInWaitMode) | SPI_C2_BIDIROE(config->pinMode >> 1U) | + SPI_C2_SPC0(config->pinMode & 1U); #endif /* FSL_FEATURE_SPI_16BIT_TRANSFERS */ /* Set watermark */ @@ -409,6 +582,9 @@ void SPI_SlaveInit(SPI_Type *base, const spi_slave_config_t *config) } #endif /* FSL_FEATURE_SPI_HAS_FIFO */ + /* Set the dummy data, this data will usefull when tx buffer is NULL. */ + SPI_SetDummyData(base, SPI_DUMMYDATA); + /* Enable SPI */ if (config->enableSlave) { @@ -416,15 +592,31 @@ void SPI_SlaveInit(SPI_Type *base, const spi_slave_config_t *config) } } +/*! + * brief De-initializes the SPI. + * + * Calling this API resets the SPI module, gates the SPI clock. + * The SPI module can't work unless calling the SPI_MasterInit/SPI_SlaveInit to initialize module. + * + * param base SPI base pointer + */ void SPI_Deinit(SPI_Type *base) { /* Disable SPI module before shutting down */ base->C1 &= ~SPI_C1_SPE_MASK; +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /* Gate the clock */ CLOCK_DisableClock(s_spiClock[SPI_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ } +/*! + * brief Gets the status flag. + * + * param base SPI base pointer + * return SPI Status, use status flag to AND #_spi_flags could get the related status. + */ uint32_t SPI_GetStatusFlags(SPI_Type *base) { #if defined(FSL_FEATURE_SPI_HAS_FIFO) && FSL_FEATURE_SPI_HAS_FIFO @@ -441,6 +633,17 @@ uint32_t SPI_GetStatusFlags(SPI_Type *base) #endif /* FSL_FEATURE_SPI_HAS_FIFO */ } +/*! + * brief Enables the interrupt for the SPI. + * + * param base SPI base pointer + * param mask SPI interrupt source. The parameter can be any combination of the following values: + * arg kSPI_RxFullAndModfInterruptEnable + * arg kSPI_TxEmptyInterruptEnable + * arg kSPI_MatchInterruptEnable + * arg kSPI_RxFifoNearFullInterruptEnable + * arg kSPI_TxFifoNearEmptyInterruptEnable + */ void SPI_EnableInterrupts(SPI_Type *base, uint32_t mask) { /* Rx full interrupt */ @@ -480,6 +683,17 @@ void SPI_EnableInterrupts(SPI_Type *base, uint32_t mask) #endif /* FSL_FEATURE_SPI_HAS_FIFO */ } +/*! + * brief Disables the interrupt for the SPI. + * + * param base SPI base pointer + * param mask SPI interrupt source. The parameter can be any combination of the following values: + * arg kSPI_RxFullAndModfInterruptEnable + * arg kSPI_TxEmptyInterruptEnable + * arg kSPI_MatchInterruptEnable + * arg kSPI_RxFifoNearFullInterruptEnable + * arg kSPI_TxFifoNearEmptyInterruptEnable + */ void SPI_DisableInterrupts(SPI_Type *base, uint32_t mask) { /* Rx full interrupt */ @@ -518,6 +732,13 @@ void SPI_DisableInterrupts(SPI_Type *base, uint32_t mask) #endif /* FSL_FEATURE_SPI_HAS_FIFO */ } +/*! + * brief Sets the baud rate for SPI transfer. This is only used in master. + * + * param base SPI base pointer + * param baudRate_Bps baud rate needed in Hz. + * param srcClock_Hz SPI source clock frequency in Hz. + */ void SPI_MasterSetBaudRate(SPI_Type *base, uint32_t baudRate_Bps, uint32_t srcClock_Hz) { uint32_t prescaler; @@ -535,7 +756,7 @@ void SPI_MasterSetBaudRate(SPI_Type *base, uint32_t baudRate_Bps, uint32_t srcCl /* Set the maximum divisor bit settings for each of the following divisors */ bestPrescaler = 7U; - bestDivisor = 8U; + bestDivisor = 8U; /* In all for loops, if min_diff = 0, the exit for loop*/ for (prescaler = 0; (prescaler <= 7) && min_diff; prescaler++) @@ -556,9 +777,9 @@ void SPI_MasterSetBaudRate(SPI_Type *base, uint32_t baudRate_Bps, uint32_t srcCl if (min_diff > diff) { /* A better match found */ - min_diff = diff; + min_diff = diff; bestPrescaler = prescaler; - bestDivisor = rateDivisor; + bestDivisor = rateDivisor; } } @@ -571,9 +792,18 @@ void SPI_MasterSetBaudRate(SPI_Type *base, uint32_t baudRate_Bps, uint32_t srcCl base->BR = SPI_BR_SPR(bestDivisor) | SPI_BR_SPPR(bestPrescaler); } +/*! + * brief Sends a buffer of data bytes using a blocking method. + * + * note This function blocks via polling until all bytes have been sent. + * + * param base SPI base pointer + * param buffer The data bytes to send + * param size The number of data bytes to send + */ void SPI_WriteBlocking(SPI_Type *base, uint8_t *buffer, size_t size) { - uint32_t i = 0; + uint32_t i = 0; uint8_t bytesPerFrame = 1U; #if defined(FSL_FEATURE_SPI_16BIT_TRANSFERS) && FSL_FEATURE_SPI_16BIT_TRANSFERS @@ -596,6 +826,12 @@ void SPI_WriteBlocking(SPI_Type *base, uint8_t *buffer, size_t size) } #if defined(FSL_FEATURE_SPI_HAS_FIFO) && FSL_FEATURE_SPI_HAS_FIFO +/*! + * brief Enables or disables the FIFO if there is a FIFO. + * + * param base SPI base pointer + * param enable True means enable FIFO, false means disable FIFO. + */ void SPI_EnableFIFO(SPI_Type *base, bool enable) { if (FSL_FEATURE_SPI_FIFO_SIZEn(base) != 0U) @@ -612,6 +848,12 @@ void SPI_EnableFIFO(SPI_Type *base, bool enable) } #endif /* FSL_FEATURE_SPI_HAS_FIFO */ +/*! + * brief Writes a data into the SPI data register. + * + * param base SPI base pointer + * param data needs to be write. + */ void SPI_WriteData(SPI_Type *base, uint16_t data) { #if defined(FSL_FEATURE_SPI_16BIT_TRANSFERS) && (FSL_FEATURE_SPI_16BIT_TRANSFERS) @@ -622,6 +864,12 @@ void SPI_WriteData(SPI_Type *base, uint16_t data) #endif } +/*! + * brief Gets a data from the SPI data register. + * + * param base SPI base pointer + * return Data in the register. + */ uint16_t SPI_ReadData(SPI_Type *base) { uint16_t val = 0; @@ -634,6 +882,14 @@ uint16_t SPI_ReadData(SPI_Type *base) return val; } +/*! + * brief Transfers a block of data using a polling method. + * + * param base SPI base pointer + * param xfer pointer to spi_xfer_config_t structure + * retval kStatus_Success Successfully start a transfer. + * retval kStatus_InvalidArgument Input argument is invalid. + */ status_t SPI_MasterTransferBlocking(SPI_Type *base, spi_transfer_t *xfer) { assert(xfer); @@ -651,10 +907,6 @@ status_t SPI_MasterTransferBlocking(SPI_Type *base, spi_transfer_t *xfer) bytesPerFrame = ((base->C2 & SPI_C2_SPIMODE_MASK) >> SPI_C2_SPIMODE_SHIFT) + 1U; #endif - /* Disable SPI and then enable it, this is used to clear S register */ - base->C1 &= ~SPI_C1_SPE_MASK; - base->C1 |= SPI_C1_SPE_MASK; - #if defined(FSL_FEATURE_SPI_HAS_FIFO) && FSL_FEATURE_SPI_HAS_FIFO /* Disable FIFO, as the FIFO may cause data loss if the data size is not integer @@ -696,6 +948,17 @@ status_t SPI_MasterTransferBlocking(SPI_Type *base, spi_transfer_t *xfer) return kStatus_Success; } +/*! + * brief Initializes the SPI master handle. + * + * This function initializes the SPI master handle which can be used for other SPI master transactional APIs. Usually, + * for a specified SPI instance, call this API once to get the initialized handle. + * + * param base SPI peripheral base address. + * param handle SPI handle pointer. + * param callback Callback function. + * param userData User data. + */ void SPI_MasterTransferCreateHandle(SPI_Type *base, spi_master_handle_t *handle, spi_master_callback_t callback, @@ -705,35 +968,15 @@ void SPI_MasterTransferCreateHandle(SPI_Type *base, uint8_t instance = SPI_GetInstance(base); + /* Zero the handle */ + memset(handle, 0, sizeof(*handle)); + /* Initialize the handle */ s_spiHandle[instance] = handle; - handle->callback = callback; - handle->userData = userData; - s_spiIsr = SPI_MasterTransferHandleIRQ; - -#if defined(FSL_FEATURE_SPI_HAS_FIFO) && FSL_FEATURE_SPI_HAS_FIFO - uint8_t txSize = 0U; - /* Get the number to be sent if there is FIFO */ - if (FSL_FEATURE_SPI_FIFO_SIZEn(base) != 0) - { - txSize = (base->C3 & SPI_C3_TNEAREF_MARK_MASK) >> SPI_C3_TNEAREF_MARK_SHIFT; - if (txSize == 0U) - { - handle->watermark = FSL_FEATURE_SPI_FIFO_SIZEn(base) * 3U / 4U; - } - else - { - handle->watermark = FSL_FEATURE_SPI_FIFO_SIZEn(base) / 2U; - } - } - /* If no FIFO, just set the watermark to 1 */ - else - { - handle->watermark = 1U; - } -#else - handle->watermark = 1U; -#endif /* FSL_FEATURE_SPI_HAS_FIFO */ + handle->callback = callback; + handle->userData = userData; + s_spiMasterIsr = SPI_MasterTransferHandleIRQ; + handle->watermark = SPI_GetWatermark(base); /* Get the bytes per frame */ #if defined(FSL_FEATURE_SPI_16BIT_TRANSFERS) && (FSL_FEATURE_SPI_16BIT_TRANSFERS) @@ -746,6 +989,20 @@ void SPI_MasterTransferCreateHandle(SPI_Type *base, EnableIRQ(s_spiIRQ[instance]); } +/*! + * brief Performs a non-blocking SPI interrupt transfer. + * + * note The API immediately returns after transfer initialization is finished. + * Call SPI_GetStatusIRQ() to get the transfer status. + * note If SPI transfer data frame size is 16 bits, the transfer size cannot be an odd number. + * + * param base SPI peripheral base address. + * param handle pointer to spi_master_handle_t structure which stores the transfer state + * param xfer pointer to spi_xfer_config_t structure + * retval kStatus_Success Successfully start a transfer. + * retval kStatus_InvalidArgument Input argument is invalid. + * retval kStatus_SPI_Busy SPI is not idle, is running another transfer. + */ status_t SPI_MasterTransferNonBlocking(SPI_Type *base, spi_master_handle_t *handle, spi_transfer_t *xfer) { assert(handle && xfer); @@ -763,47 +1020,76 @@ status_t SPI_MasterTransferNonBlocking(SPI_Type *base, spi_master_handle_t *hand } /* Set the handle information */ - handle->txData = xfer->txData; - handle->rxData = xfer->rxData; - handle->transferSize = xfer->dataSize; + handle->txData = xfer->txData; + handle->rxData = xfer->rxData; + handle->transferSize = xfer->dataSize; handle->txRemainingBytes = xfer->dataSize; handle->rxRemainingBytes = xfer->dataSize; /* Set the SPI state to busy */ handle->state = kSPI_Busy; - /* Disable SPI and then enable it, this is used to clear S register*/ - base->C1 &= ~SPI_C1_SPE_MASK; - base->C1 |= SPI_C1_SPE_MASK; - /* Enable Interrupt, only enable Rx interrupt, use rx interrupt to driver SPI transfer */ #if defined(FSL_FEATURE_SPI_HAS_FIFO) && FSL_FEATURE_SPI_HAS_FIFO + + handle->watermark = SPI_GetWatermark(base); + + /* If the size of the transfer size less than watermark, set watermark to 1 */ + if (xfer->dataSize < handle->watermark * 2U) + { + handle->watermark = 1U; + } + + /* According to watermark size, enable interrupts */ if (handle->watermark > 1U) { + SPI_EnableFIFO(base, true); + /* First send a piece of data to Tx Data or FIFO to start a SPI transfer */ + while ((base->S & SPI_S_TNEAREF_MASK) != SPI_S_TNEAREF_MASK) + { + } + SPI_SendInitialTransfer(base, handle); /* Enable Rx near full interrupt */ SPI_EnableInterrupts(base, kSPI_RxFifoNearFullInterruptEnable); } else { + SPI_EnableFIFO(base, false); + while ((base->S & SPI_S_SPTEF_MASK) != SPI_S_SPTEF_MASK) + { + } + /* First send a piece of data to Tx Data or FIFO to start a SPI transfer */ + SPI_SendInitialTransfer(base, handle); SPI_EnableInterrupts(base, kSPI_RxFullAndModfInterruptEnable); } #else + while ((base->S & SPI_S_SPTEF_MASK) != SPI_S_SPTEF_MASK) + { + } + /* First send a piece of data to Tx Data or FIFO to start a SPI transfer */ + SPI_SendInitialTransfer(base, handle); SPI_EnableInterrupts(base, kSPI_RxFullAndModfInterruptEnable); #endif - /* First send a piece of data to Tx Data or FIFO to start a SPI transfer */ - SPI_SendTransfer(base, handle); - return kStatus_Success; } +/*! + * brief Gets the bytes of the SPI interrupt transferred. + * + * param base SPI peripheral base address. + * param handle Pointer to SPI transfer handle, this should be a static variable. + * param count Transferred bytes of SPI master. + * retval kStatus_SPI_Success Succeed get the transfer count. + * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress. + */ status_t SPI_MasterTransferGetCount(SPI_Type *base, spi_master_handle_t *handle, size_t *count) { assert(handle); status_t status = kStatus_Success; - if (handle->state != kStatus_SPI_Busy) + if (handle->state != kSPI_Busy) { status = kStatus_NoTransferInProgress; } @@ -823,6 +1109,12 @@ status_t SPI_MasterTransferGetCount(SPI_Type *base, spi_master_handle_t *handle, return status; } +/*! + * brief Aborts an SPI transfer using interrupt. + * + * param base SPI peripheral base address. + * param handle Pointer to SPI transfer handle, this should be a static variable. + */ void SPI_MasterTransferAbort(SPI_Type *base, spi_master_handle_t *handle) { assert(handle); @@ -849,6 +1141,12 @@ void SPI_MasterTransferAbort(SPI_Type *base, spi_master_handle_t *handle) handle->txRemainingBytes = 0; } +/*! + * brief Interrupts the handler for the SPI. + * + * param base SPI peripheral base address. + * param handle pointer to spi_master_handle_t structure which stores the transfer state. + */ void SPI_MasterTransferHandleIRQ(SPI_Type *base, spi_master_handle_t *handle) { assert(handle); @@ -878,6 +1176,17 @@ void SPI_MasterTransferHandleIRQ(SPI_Type *base, spi_master_handle_t *handle) } } +/*! + * brief Initializes the SPI slave handle. + * + * This function initializes the SPI slave handle which can be used for other SPI slave transactional APIs. Usually, + * for a specified SPI instance, call this API once to get the initialized handle. + * + * param base SPI peripheral base address. + * param handle SPI handle pointer. + * param callback Callback function. + * param userData User data. + */ void SPI_SlaveTransferCreateHandle(SPI_Type *base, spi_slave_handle_t *handle, spi_slave_callback_t callback, @@ -888,9 +1197,15 @@ void SPI_SlaveTransferCreateHandle(SPI_Type *base, /* Slave create handle share same logic with master create handle, the only difference is the Isr pointer. */ SPI_MasterTransferCreateHandle(base, handle, callback, userData); - s_spiIsr = SPI_SlaveTransferHandleIRQ; + s_spiSlaveIsr = SPI_SlaveTransferHandleIRQ; } +/*! + * brief Interrupts a handler for the SPI slave. + * + * param base SPI peripheral base address. + * param handle pointer to spi_slave_handle_t structure which stores the transfer state + */ void SPI_SlaveTransferHandleIRQ(SPI_Type *base, spi_slave_handle_t *handle) { assert(handle); @@ -920,11 +1235,28 @@ void SPI_SlaveTransferHandleIRQ(SPI_Type *base, spi_slave_handle_t *handle) } } +static void SPI_CommonIRQHandler(SPI_Type *base, uint32_t instance) +{ + if (base->C1 & SPI_C1_MSTR_MASK) + { + s_spiMasterIsr(base, s_spiHandle[instance]); + } + else + { + s_spiSlaveIsr(base, s_spiHandle[instance]); + } +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} + #if defined(SPI0) void SPI0_DriverIRQHandler(void) { assert(s_spiHandle[0]); - s_spiIsr(SPI0, s_spiHandle[0]); + SPI_CommonIRQHandler(SPI0, 0); } #endif @@ -932,7 +1264,7 @@ void SPI0_DriverIRQHandler(void) void SPI1_DriverIRQHandler(void) { assert(s_spiHandle[1]); - s_spiIsr(SPI1, s_spiHandle[1]); + SPI_CommonIRQHandler(SPI1, 1); } #endif @@ -940,6 +1272,6 @@ void SPI1_DriverIRQHandler(void) void SPI2_DriverIRQHandler(void) { assert(s_spiHandle[2]); - s_spiIsr(SPI0, s_spiHandle[2]); + SPI_CommonIRQHandler(SPI2, 2); } #endif diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL27Z/drivers/fsl_spi.h b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL27Z/drivers/fsl_spi.h index 7e9162350d..0e0360ca5c 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL27Z/drivers/fsl_spi.h +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL27Z/drivers/fsl_spi.h @@ -1,31 +1,9 @@ /* * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP * All rights reserved. * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * o Redistributions of source code must retain the above copyright notice, this list - * of conditions and the following disclaimer. - * - * o 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. - * - * o Neither the name of Freescale Semiconductor, Inc. nor the names of its - * contributors may be used tom 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. + * SPDX-License-Identifier: BSD-3-Clause */ #ifndef _FSL_SPI_H_ #define _FSL_SPI_H_ @@ -37,15 +15,14 @@ * @{ */ - /******************************************************************************* * Definitions ******************************************************************************/ /*! @name Driver version */ /*@{*/ -/*! @brief SPI driver version 2.0.1. */ -#define FSL_SPI_DRIVER_VERSION (MAKE_VERSION(2, 0, 1)) +/*! @brief SPI driver version 2.0.4. */ +#define FSL_SPI_DRIVER_VERSION (MAKE_VERSION(2, 0, 4)) /*@}*/ #ifndef SPI_DUMMYDATA @@ -53,12 +30,15 @@ #define SPI_DUMMYDATA (0xFFU) #endif +/*! @brief Global variable for dummy data value setting. */ +extern volatile uint8_t g_spiDummyData[]; + /*! @brief Return status for the SPI driver.*/ enum _spi_status { - kStatus_SPI_Busy = MAKE_STATUS(kStatusGroup_SPI, 0), /*!< SPI bus is busy */ - kStatus_SPI_Idle = MAKE_STATUS(kStatusGroup_SPI, 1), /*!< SPI is idle */ - kStatus_SPI_Error = MAKE_STATUS(kStatusGroup_SPI, 2) /*!< SPI error */ + kStatus_SPI_Busy = MAKE_STATUS(kStatusGroup_SPI, 0), /*!< SPI bus is busy */ + kStatus_SPI_Idle = MAKE_STATUS(kStatusGroup_SPI, 1), /*!< SPI is idle */ + kStatus_SPI_Error = MAKE_STATUS(kStatusGroup_SPI, 2) /*!< SPI error */ }; /*! @brief SPI clock polarity configuration.*/ @@ -87,16 +67,16 @@ typedef enum _spi_shift_direction /*! @brief SPI slave select output mode options.*/ typedef enum _spi_ss_output_mode { - kSPI_SlaveSelectAsGpio = 0x0U, /*!< Slave select pin configured as GPIO. */ - kSPI_SlaveSelectFaultInput = 0x2U, /*!< Slave select pin configured for fault detection. */ - kSPI_SlaveSelectAutomaticOutput = 0x3U /*!< Slave select pin configured for automatic SPI output. */ + kSPI_SlaveSelectAsGpio = 0x0U, /*!< Slave select pin configured as GPIO. */ + kSPI_SlaveSelectFaultInput = 0x2U, /*!< Slave select pin configured for fault detection. */ + kSPI_SlaveSelectAutomaticOutput = 0x3U /*!< Slave select pin configured for automatic SPI output. */ } spi_ss_output_mode_t; /*! @brief SPI pin mode options.*/ typedef enum _spi_pin_mode { kSPI_PinModeNormal = 0x0U, /*!< Pins operate in normal, single-direction mode.*/ - kSPI_PinModeInput = 0x1U, /*!< Bidirectional mode. Master: MOSI pin is input; + kSPI_PinModeInput = 0x1U, /*!< Bidirectional mode. Master: MOSI pin is input; * Slave: MISO pin is input. */ kSPI_PinModeOutput = 0x3U /*!< Bidirectional mode. Master: MOSI pin is output; * Slave: MISO pin is output. */ @@ -113,10 +93,10 @@ typedef enum _spi_data_bitcount_mode enum _spi_interrupt_enable { kSPI_RxFullAndModfInterruptEnable = 0x1U, /*!< Receive buffer full (SPRF) and mode fault (MODF) interrupt */ - kSPI_TxEmptyInterruptEnable = 0x2U, /*!< Transmit buffer empty interrupt */ - kSPI_MatchInterruptEnable = 0x4U, /*!< Match interrupt */ + kSPI_TxEmptyInterruptEnable = 0x2U, /*!< Transmit buffer empty interrupt */ + kSPI_MatchInterruptEnable = 0x4U, /*!< Match interrupt */ #if defined(FSL_FEATURE_SPI_HAS_FIFO) && FSL_FEATURE_SPI_HAS_FIFO - kSPI_RxFifoNearFullInterruptEnable = 0x8U, /*!< Receive FIFO nearly full interrupt */ + kSPI_RxFifoNearFullInterruptEnable = 0x8U, /*!< Receive FIFO nearly full interrupt */ kSPI_TxFifoNearEmptyInterruptEnable = 0x10U, /*!< Transmit FIFO nearly empty interrupt */ #endif /* FSL_FEATURE_SPI_HAS_FIFO */ }; @@ -124,44 +104,44 @@ enum _spi_interrupt_enable /*! @brief SPI status flags.*/ enum _spi_flags { - kSPI_RxBufferFullFlag = SPI_S_SPRF_MASK, /*!< Read buffer full flag */ - kSPI_MatchFlag = SPI_S_SPMF_MASK, /*!< Match flag */ + kSPI_RxBufferFullFlag = SPI_S_SPRF_MASK, /*!< Read buffer full flag */ + kSPI_MatchFlag = SPI_S_SPMF_MASK, /*!< Match flag */ kSPI_TxBufferEmptyFlag = SPI_S_SPTEF_MASK, /*!< Transmit buffer empty flag */ - kSPI_ModeFaultFlag = SPI_S_MODF_MASK, /*!< Mode fault flag */ + kSPI_ModeFaultFlag = SPI_S_MODF_MASK, /*!< Mode fault flag */ #if defined(FSL_FEATURE_SPI_HAS_FIFO) && FSL_FEATURE_SPI_HAS_FIFO - kSPI_RxFifoNearFullFlag = SPI_S_RNFULLF_MASK, /*!< Rx FIFO near full */ - kSPI_TxFifoNearEmptyFlag = SPI_S_TNEAREF_MASK, /*!< Tx FIFO near empty */ - kSPI_TxFifoFullFlag = SPI_S_TXFULLF_MASK, /*!< Tx FIFO full */ - kSPI_RxFifoEmptyFlag = SPI_S_RFIFOEF_MASK, /*!< Rx FIFO empty */ - kSPI_TxFifoError = SPI_CI_TXFERR_MASK << 8U, /*!< Tx FIFO error */ - kSPI_RxFifoError = SPI_CI_RXFERR_MASK << 8U, /*!< Rx FIFO error */ - kSPI_TxOverflow = SPI_CI_TXFOF_MASK << 8U, /*!< Tx FIFO Overflow */ - kSPI_RxOverflow = SPI_CI_RXFOF_MASK << 8U /*!< Rx FIFO Overflow */ -#endif /* FSL_FEATURE_SPI_HAS_FIFO */ + kSPI_RxFifoNearFullFlag = SPI_S_RNFULLF_MASK, /*!< Rx FIFO near full */ + kSPI_TxFifoNearEmptyFlag = SPI_S_TNEAREF_MASK, /*!< Tx FIFO near empty */ + kSPI_TxFifoFullFlag = SPI_S_TXFULLF_MASK, /*!< Tx FIFO full */ + kSPI_RxFifoEmptyFlag = SPI_S_RFIFOEF_MASK, /*!< Rx FIFO empty */ + kSPI_TxFifoError = SPI_CI_TXFERR_MASK << 8U, /*!< Tx FIFO error */ + kSPI_RxFifoError = SPI_CI_RXFERR_MASK << 8U, /*!< Rx FIFO error */ + kSPI_TxOverflow = SPI_CI_TXFOF_MASK << 8U, /*!< Tx FIFO Overflow */ + kSPI_RxOverflow = SPI_CI_RXFOF_MASK << 8U /*!< Rx FIFO Overflow */ +#endif /* FSL_FEATURE_SPI_HAS_FIFO */ }; #if defined(FSL_FEATURE_SPI_HAS_FIFO) && FSL_FEATURE_SPI_HAS_FIFO /*! @brief SPI FIFO write-1-to-clear interrupt flags.*/ typedef enum _spi_w1c_interrupt { - kSPI_RxFifoFullClearInterrupt = SPI_CI_SPRFCI_MASK, /*!< Receive FIFO full interrupt */ - kSPI_TxFifoEmptyClearInterrupt = SPI_CI_SPTEFCI_MASK, /*!< Transmit FIFO empty interrupt */ - kSPI_RxNearFullClearInterrupt = SPI_CI_RNFULLFCI_MASK, /*!< Receive FIFO nearly full interrupt */ - kSPI_TxNearEmptyClearInterrupt = SPI_CI_TNEAREFCI_MASK /*!< Transmit FIFO nearly empty interrupt */ + kSPI_RxFifoFullClearInterrupt = SPI_CI_SPRFCI_MASK, /*!< Receive FIFO full interrupt */ + kSPI_TxFifoEmptyClearInterrupt = SPI_CI_SPTEFCI_MASK, /*!< Transmit FIFO empty interrupt */ + kSPI_RxNearFullClearInterrupt = SPI_CI_RNFULLFCI_MASK, /*!< Receive FIFO nearly full interrupt */ + kSPI_TxNearEmptyClearInterrupt = SPI_CI_TNEAREFCI_MASK /*!< Transmit FIFO nearly empty interrupt */ } spi_w1c_interrupt_t; /*! @brief SPI TX FIFO watermark settings.*/ typedef enum _spi_txfifo_watermark { kSPI_TxFifoOneFourthEmpty = 0, /*!< SPI tx watermark at 1/4 FIFO size */ - kSPI_TxFifoOneHalfEmpty = 1 /*!< SPI tx watermark at 1/2 FIFO size */ + kSPI_TxFifoOneHalfEmpty = 1 /*!< SPI tx watermark at 1/2 FIFO size */ } spi_txfifo_watermark_t; /*! @brief SPI RX FIFO watermark settings.*/ typedef enum _spi_rxfifo_watermark { kSPI_RxFifoThreeFourthsFull = 0, /*!< SPI rx watermark at 3/4 FIFO size */ - kSPI_RxFifoOneHalfFull = 1 /*!< SPI rx watermark at 1/2 FIFO size */ + kSPI_RxFifoOneHalfFull = 1 /*!< SPI rx watermark at 1/2 FIFO size */ } spi_rxfifo_watermark_t; #endif /* FSL_FEATURE_SPI_HAS_FIFO */ @@ -169,8 +149,8 @@ typedef enum _spi_rxfifo_watermark /*! @brief SPI DMA source*/ enum _spi_dma_enable_t { - kSPI_TxDmaEnable = SPI_C2_TXDMAE_MASK, /*!< Tx DMA request source */ - kSPI_RxDmaEnable = SPI_C2_RXDMAE_MASK, /*!< Rx DMA request source */ + kSPI_TxDmaEnable = SPI_C2_TXDMAE_MASK, /*!< Tx DMA request source */ + kSPI_RxDmaEnable = SPI_C2_RXDMAE_MASK, /*!< Rx DMA request source */ kSPI_DmaAllEnable = (SPI_C2_TXDMAE_MASK | SPI_C2_RXDMAE_MASK) /*!< All DMA request source*/ }; #endif /* FSL_FEATURE_SPI_HAS_DMA_SUPPORT */ @@ -210,6 +190,7 @@ typedef struct _spi_slave_config spi_txfifo_watermark_t txWatermark; /*!< Tx watermark settings */ spi_rxfifo_watermark_t rxWatermark; /*!< Rx watermark settings */ #endif /* FSL_FEATURE_SPI_HAS_FIFO */ + spi_pin_mode_t pinMode; /*!< SPI pin mode select */ } spi_slave_config_t; /*! @brief SPI transfer structure */ @@ -478,6 +459,27 @@ static inline uint32_t SPI_GetDataRegisterAddress(SPI_Type *base) * @{ */ +/*! + * @brief Get the instance for SPI module. + * + * @param base SPI base address + */ +uint32_t SPI_GetInstance(SPI_Type *base); + +/*! + * @brief Sets the pin mode for transfer. + * + * @param base SPI base pointer + * @param pinMode pin mode for transfer AND #_spi_pin_mode could get the related configuration. + */ +static inline void SPI_SetPinMode(SPI_Type *base, spi_pin_mode_t pinMode) +{ + /* Clear SPC0 and BIDIROE bit. */ + base->C2 &= ~(SPI_C2_BIDIROE_MASK | SPI_C2_SPC0_MASK); + /* Set pin mode for transfer. */ + base->C2 |= SPI_C2_BIDIROE(pinMode >> 1U) | SPI_C2_SPC0(pinMode & 1U); +} + /*! * @brief Sets the baud rate for SPI transfer. This is only used in master. * @@ -544,6 +546,13 @@ void SPI_WriteData(SPI_Type *base, uint16_t data); */ uint16_t SPI_ReadData(SPI_Type *base); +/*! + * @brief Set up the dummy data. + * + * @param base SPI peripheral address. + * @param dummyData Data to be transferred when tx buffer is NULL. + */ +void SPI_SetDummyData(SPI_Type *base, uint8_t dummyData); /*! @} */ /*! @@ -582,11 +591,7 @@ status_t SPI_MasterTransferBlocking(SPI_Type *base, spi_transfer_t *xfer); * * @note The API immediately returns after transfer initialization is finished. * Call SPI_GetStatusIRQ() to get the transfer status. - * @note If using the SPI with FIFO for the interrupt transfer, the transfer size is the integer times of the watermark. - * Otherwise, - * the last data may be lost because it cannot generate an interrupt request. Users can also call the functional API to - * get the last - * received data. + * @note If SPI transfer data frame size is 16 bits, the transfer size cannot be an odd number. * * @param base SPI peripheral base address. * @param handle pointer to spi_master_handle_t structure which stores the transfer state @@ -636,8 +641,8 @@ void SPI_MasterTransferHandleIRQ(SPI_Type *base, spi_master_handle_t *handle); * @param userData User data. */ void SPI_SlaveTransferCreateHandle(SPI_Type *base, - spi_slave_handle_t *handle, - spi_slave_callback_t callback, + spi_slave_handle_t *handle, + spi_slave_callback_t callback, void *userData); /*! @@ -645,11 +650,7 @@ void SPI_SlaveTransferCreateHandle(SPI_Type *base, * * @note The API returns immediately after the transfer initialization is finished. * Call SPI_GetStatusIRQ() to get the transfer status. - * @note If using the SPI with FIFO for the interrupt transfer, the transfer size is the integer times the watermark. - * Otherwise, - * the last data may be lost because it cannot generate an interrupt request. Call the functional API to get the last - * several - * receive data. + * @note If SPI transfer data frame size is 16 bits, the transfer size cannot be an odd number. * * @param base SPI peripheral base address. * @param handle pointer to spi_master_handle_t structure which stores the transfer state diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL27Z/drivers/fsl_spi_dma.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL27Z/drivers/fsl_spi_dma.c index cdaddcc799..003d4c3ed7 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL27Z/drivers/fsl_spi_dma.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL27Z/drivers/fsl_spi_dma.c @@ -1,38 +1,22 @@ /* * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP * All rights reserved. * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * o Redistributions of source code must retain the above copyright notice, this list - * of conditions and the following disclaimer. - * - * o 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. - * - * o Neither the name of Freescale Semiconductor, Inc. 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. + * SPDX-License-Identifier: BSD-3-Clause */ #include "fsl_spi_dma.h" /******************************************************************************* - * Definitons + * Definitions ******************************************************************************/ + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.spi_dma" +#endif + /*handle; - SPI_Type *base = privHandle->base; + spi_dma_handle_t *spiHandle = privHandle->handle; + SPI_Type *base = privHandle->base; /* Disable Tx dma */ SPI_EnableDMA(base, kSPI_TxDmaEnable, false); - /* Stop DMA tranfer */ + /* Stop DMA transfer */ DMA_StopTransfer(spiHandle->txHandle); /* change the state */ @@ -114,13 +84,13 @@ static void SPI_TxDMACallback(dma_handle_t *handle, void *userData) static void SPI_RxDMACallback(dma_handle_t *handle, void *userData) { spi_dma_private_handle_t *privHandle = (spi_dma_private_handle_t *)userData; - spi_dma_handle_t *spiHandle = privHandle->handle; - SPI_Type *base = privHandle->base; + spi_dma_handle_t *spiHandle = privHandle->handle; + SPI_Type *base = privHandle->base; /* Disable Tx dma */ SPI_EnableDMA(base, kSPI_RxDmaEnable, false); - /* Stop DMA tranfer */ + /* Stop DMA transfer */ DMA_StopTransfer(spiHandle->rxHandle); /* change the state */ @@ -137,6 +107,19 @@ static void SPI_RxDMACallback(dma_handle_t *handle, void *userData) } } +/*! + * brief Initialize the SPI master DMA handle. + * + * This function initializes the SPI master DMA handle which can be used for other SPI master transactional APIs. + * Usually, for a specified SPI instance, user need only call this API once to get the initialized handle. + * + * param base SPI peripheral base address. + * param handle SPI handle pointer. + * param callback User callback function called at the end of a transfer. + * param userData User data for callback. + * param txHandle DMA handle pointer for SPI Tx, the handle shall be static allocated by users. + * param rxHandle DMA handle pointer for SPI Rx, the handle shall be static allocated by users. + */ void SPI_MasterTransferCreateHandleDMA(SPI_Type *base, spi_dma_handle_t *handle, spi_dma_callback_t callback, @@ -146,7 +129,10 @@ void SPI_MasterTransferCreateHandleDMA(SPI_Type *base, { assert(handle); dma_transfer_config_t config = {0}; - uint32_t instance = SPI_GetInstance(base); + uint32_t instance = SPI_GetInstance(base); + + /* Zero the handle */ + memset(handle, 0, sizeof(*handle)); /* Set spi base to handle */ handle->txHandle = txHandle; @@ -158,7 +144,7 @@ void SPI_MasterTransferCreateHandleDMA(SPI_Type *base, handle->state = kSPI_Idle; /* Set handle to global state */ - s_dmaPrivateHandle[instance].base = base; + s_dmaPrivateHandle[instance].base = base; s_dmaPrivateHandle[instance].handle = handle; /* Compute internal state */ @@ -180,27 +166,27 @@ void SPI_MasterTransferCreateHandleDMA(SPI_Type *base, #endif /* FSL_FEATURE_SPI_HAS_FIFO */ /* Set the non-change attribute for Tx DMA transfer, to improve efficiency */ - config.destAddr = SPI_GetDataRegisterAddress(base); + config.destAddr = SPI_GetDataRegisterAddress(base); config.enableDestIncrement = false; - config.enableSrcIncrement = true; + config.enableSrcIncrement = true; if (handle->bytesPerFrame == 1U) { - config.srcSize = kDMA_Transfersize8bits; + config.srcSize = kDMA_Transfersize8bits; config.destSize = kDMA_Transfersize8bits; } else { - config.srcSize = kDMA_Transfersize16bits; + config.srcSize = kDMA_Transfersize16bits; config.destSize = kDMA_Transfersize16bits; } DMA_SubmitTransfer(handle->txHandle, &config, true); /* Set non-change attribute for Rx DMA */ - config.srcAddr = SPI_GetDataRegisterAddress(base); - config.destAddr = 0U; + config.srcAddr = SPI_GetDataRegisterAddress(base); + config.destAddr = 0U; config.enableDestIncrement = true; - config.enableSrcIncrement = false; + config.enableSrcIncrement = false; DMA_SubmitTransfer(handle->rxHandle, &config, true); /* Install callback for Tx dma channel */ @@ -208,6 +194,19 @@ void SPI_MasterTransferCreateHandleDMA(SPI_Type *base, DMA_SetCallback(handle->rxHandle, SPI_RxDMACallback, &s_dmaPrivateHandle[instance]); } +/*! + * brief Perform a non-blocking SPI transfer using DMA. + * + * note This interface returned immediately after transfer initiates, users should call + * SPI_GetTransferStatus to poll the transfer status to check whether SPI transfer finished. + * + * param base SPI peripheral base address. + * param handle SPI DMA handle pointer. + * param xfer Pointer to dma transfer structure. + * retval kStatus_Success Successfully start a transfer. + * retval kStatus_InvalidArgument Input argument is invalid. + * retval kStatus_SPI_Busy SPI is not idle, is running another transfer. + */ status_t SPI_MasterTransferDMA(SPI_Type *base, spi_dma_handle_t *handle, spi_transfer_t *xfer) { assert(handle && xfer); @@ -231,16 +230,16 @@ status_t SPI_MasterTransferDMA(SPI_Type *base, spi_dma_handle_t *handle, spi_tra SPI_Enable(base, true); /* Configure tx transfer DMA */ - config.destAddr = SPI_GetDataRegisterAddress(base); + config.destAddr = SPI_GetDataRegisterAddress(base); config.enableDestIncrement = false; if (handle->bytesPerFrame == 1U) { - config.srcSize = kDMA_Transfersize8bits; + config.srcSize = kDMA_Transfersize8bits; config.destSize = kDMA_Transfersize8bits; } else { - config.srcSize = kDMA_Transfersize16bits; + config.srcSize = kDMA_Transfersize16bits; config.destSize = kDMA_Transfersize16bits; } config.transferSize = xfer->dataSize; @@ -248,13 +247,13 @@ status_t SPI_MasterTransferDMA(SPI_Type *base, spi_dma_handle_t *handle, spi_tra if (xfer->txData) { config.enableSrcIncrement = true; - config.srcAddr = (uint32_t)(xfer->txData); + config.srcAddr = (uint32_t)(xfer->txData); } else { /* Disable the source increasement and source set to dummyData */ config.enableSrcIncrement = false; - config.srcAddr = (uint32_t)(&s_dummyData); + config.srcAddr = (uint32_t)(&g_spiDummyData[SPI_GetInstance(base)]); } DMA_SubmitTransfer(handle->txHandle, &config, true); @@ -270,7 +269,7 @@ status_t SPI_MasterTransferDMA(SPI_Type *base, spi_dma_handle_t *handle, spi_tra /* Change the state of handle */ handle->transferSize = xfer->dataSize; - handle->state = kSPI_Busy; + handle->state = kSPI_Busy; /* Start Rx transfer if needed */ if (xfer->rxData) @@ -288,6 +287,15 @@ status_t SPI_MasterTransferDMA(SPI_Type *base, spi_dma_handle_t *handle, spi_tra return kStatus_Success; } +/*! + * brief Get the transferred bytes for SPI slave DMA. + * + * param base SPI peripheral base address. + * param handle SPI DMA handle pointer. + * param count Transferred bytes. + * retval kStatus_SPI_Success Succeed get the transfer count. + * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress. + */ status_t SPI_MasterTransferGetCountDMA(SPI_Type *base, spi_dma_handle_t *handle, size_t *count) { assert(handle); @@ -313,6 +321,12 @@ status_t SPI_MasterTransferGetCountDMA(SPI_Type *base, spi_dma_handle_t *handle, return status; } +/*! + * brief Abort a SPI transfer using DMA. + * + * param base SPI peripheral base address. + * param handle SPI DMA handle pointer. + */ void SPI_MasterTransferAbortDMA(SPI_Type *base, spi_dma_handle_t *handle) { assert(handle); @@ -327,5 +341,5 @@ void SPI_MasterTransferAbortDMA(SPI_Type *base, spi_dma_handle_t *handle) /* Set the handle state */ handle->txInProgress = false; handle->rxInProgress = false; - handle->state = kSPI_Idle; + handle->state = kSPI_Idle; } diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL27Z/drivers/fsl_spi_dma.h b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL27Z/drivers/fsl_spi_dma.h index 90c7c93fb6..4d9b6b3580 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL27Z/drivers/fsl_spi_dma.h +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL27Z/drivers/fsl_spi_dma.h @@ -1,31 +1,9 @@ /* * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP * All rights reserved. * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * o Redistributions of source code must retain the above copyright notice, this list - * of conditions and the following disclaimer. - * - * o 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. - * - * o Neither the name of Freescale Semiconductor, Inc. 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. + * SPDX-License-Identifier: BSD-3-Clause */ #ifndef _FSL_SPI_DMA_H_ #define _FSL_SPI_DMA_H_ @@ -38,11 +16,16 @@ * @{ */ - /******************************************************************************* * Definitions ******************************************************************************/ +/*! @name Driver version */ +/*@{*/ +/*! @brief SPI DMA driver version 2.0.4. */ +#define FSL_SPI_DMA_DRIVER_VERSION (MAKE_VERSION(2, 0, 4)) +/*@}*/ + typedef struct _spi_dma_handle spi_dma_handle_t; /*! @brief SPI DMA callback called at the end of transfer. */ @@ -55,7 +38,7 @@ struct _spi_dma_handle bool rxInProgress; /*!< Receive transfer finished */ dma_handle_t *txHandle; /*!< DMA handler for SPI send */ dma_handle_t *rxHandle; /*!< DMA handler for SPI receive */ - uint8_t bytesPerFrame; /*!< Bytes in a frame for SPI tranfer */ + uint8_t bytesPerFrame; /*!< Bytes in a frame for SPI transfer */ spi_dma_callback_t callback; /*!< Callback for SPI DMA transfer */ void *userData; /*!< User Data for SPI DMA callback */ uint32_t state; /*!< Internal state of SPI DMA transfer */ diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL43Z/drivers/fsl_spi.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL43Z/drivers/fsl_spi.c index b2dde5cb9b..df67413d61 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL43Z/drivers/fsl_spi.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL43Z/drivers/fsl_spi.c @@ -1,38 +1,22 @@ /* * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP * All rights reserved. * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * o Redistributions of source code must retain the above copyright notice, this list - * of conditions and the following disclaimer. - * - * o 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. - * - * o Neither the name of Freescale Semiconductor, Inc. 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. + * SPDX-License-Identifier: BSD-3-Clause */ #include "fsl_spi.h" /******************************************************************************* - * Definitons + * Definitions ******************************************************************************/ + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.spi" +#endif + /*! @brief SPI transfer state, which is used for SPI transactiaonl APIs' internal state. */ enum _spi_transfer_states_t { @@ -46,12 +30,6 @@ typedef void (*spi_isr_t)(SPI_Type *base, spi_master_handle_t *spiHandle); /******************************************************************************* * Prototypes ******************************************************************************/ -/*! - * @brief Get the instance for SPI module. - * - * @param base SPI base address - */ -uint32_t SPI_GetInstance(SPI_Type *base); /*! * @brief Sends a buffer of data bytes in non-blocking way. @@ -71,6 +49,14 @@ static void SPI_WriteNonBlocking(SPI_Type *base, uint8_t *buffer, size_t size); */ static void SPI_ReadNonBlocking(SPI_Type *base, uint8_t *buffer, size_t size); +/*! + * @brief Get the waterrmark value for this SPI instance. + * + * @param base SPI base pointer + * @return Watermark value for the SPI instance. + */ +static uint8_t SPI_GetWatermark(SPI_Type *base); + /*! * @brief Send a piece of data for SPI. * @@ -78,6 +64,7 @@ static void SPI_ReadNonBlocking(SPI_Type *base, uint8_t *buffer, size_t size); * and write the data into it. At the same time, this function updates the values in * master handle structure. * + * @param base SPI base pointer * @param handle Pointer to SPI master handle structure. */ static void SPI_SendTransfer(SPI_Type *base, spi_master_handle_t *handle); @@ -89,9 +76,18 @@ static void SPI_SendTransfer(SPI_Type *base, spi_master_handle_t *handle); * and write the data to destination address. At the same time, this function updates * the values in master handle structure. * + * @param base SPI base pointer * @param handle Pointer to SPI master handle structure. */ static void SPI_ReceiveTransfer(SPI_Type *base, spi_master_handle_t *handle); + +/*! + * @brief Common IRQ handler for SPI. + * + * @param base SPI base pointer. + * @param instance SPI instance number. + */ +static void SPI_CommonIRQHandler(SPI_Type *base, uint32_t instance); /******************************************************************************* * Variables ******************************************************************************/ @@ -101,21 +97,31 @@ static spi_master_handle_t *s_spiHandle[FSL_FEATURE_SOC_SPI_COUNT]; static SPI_Type *const s_spiBases[] = SPI_BASE_PTRS; /*! @brief IRQ name array */ static const IRQn_Type s_spiIRQ[] = SPI_IRQS; +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /*! @brief Clock array name */ static const clock_ip_name_t s_spiClock[] = SPI_CLOCKS; +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ /*! @brief Pointer to master IRQ handler for each instance. */ -static spi_isr_t s_spiIsr; +static spi_isr_t s_spiMasterIsr; +static spi_isr_t s_spiSlaveIsr; +/* @brief Dummy data for each instance. This data is used when user's tx buffer is NULL*/ +volatile uint8_t g_spiDummyData[ARRAY_SIZE(s_spiBases)] = {0}; /******************************************************************************* * Code ******************************************************************************/ +/*! + * brief Get the instance for SPI module. + * + * param base SPI base address + */ uint32_t SPI_GetInstance(SPI_Type *base) { uint32_t instance; /* Find the instance index from base address mappings. */ - for (instance = 0; instance < FSL_FEATURE_SOC_SPI_COUNT; instance++) + for (instance = 0; instance < ARRAY_SIZE(s_spiBases); instance++) { if (s_spiBases[instance] == base) { @@ -123,15 +129,28 @@ uint32_t SPI_GetInstance(SPI_Type *base) } } - assert(instance < FSL_FEATURE_SOC_SPI_COUNT); + assert(instance < ARRAY_SIZE(s_spiBases)); return instance; } +/*! + * brief Set up the dummy data. + * + * param base SPI peripheral address. + * param dummyData Data to be transferred when tx buffer is NULL. + */ +void SPI_SetDummyData(SPI_Type *base, uint8_t dummyData) +{ + uint32_t instance = SPI_GetInstance(base); + g_spiDummyData[instance] = dummyData; +} + static void SPI_WriteNonBlocking(SPI_Type *base, uint8_t *buffer, size_t size) { - uint32_t i = 0; + uint32_t i = 0; uint8_t bytesPerFrame = 1U; + uint32_t instance = SPI_GetInstance(base); #if defined(FSL_FEATURE_SPI_16BIT_TRANSFERS) && FSL_FEATURE_SPI_16BIT_TRANSFERS /* Check if 16 bits or 8 bits */ @@ -155,13 +174,13 @@ static void SPI_WriteNonBlocking(SPI_Type *base, uint8_t *buffer, size_t size) base->DL = *buffer++; } #else - base->D = *buffer++; + base->D = *buffer++; #endif /* FSL_FEATURE_SPI_16BIT_TRANSFERS */ } /* Send dummy data */ else { - SPI_WriteData(base, SPI_DUMMYDATA); + SPI_WriteData(base, ((uint32_t)g_spiDummyData[instance] << 8 | g_spiDummyData[instance])); } i += bytesPerFrame; } @@ -169,7 +188,7 @@ static void SPI_WriteNonBlocking(SPI_Type *base, uint8_t *buffer, size_t size) static void SPI_ReadNonBlocking(SPI_Type *base, uint8_t *buffer, size_t size) { - uint32_t i = 0; + uint32_t i = 0; uint8_t bytesPerFrame = 1U; #if defined(FSL_FEATURE_SPI_16BIT_TRANSFERS) && FSL_FEATURE_SPI_16BIT_TRANSFERS @@ -205,18 +224,68 @@ static void SPI_ReadNonBlocking(SPI_Type *base, uint8_t *buffer, size_t size) } } +/* Get the watermark value of transfer. Please note that the entery width of FIFO is 16 bits. */ +static uint8_t SPI_GetWatermark(SPI_Type *base) +{ + uint8_t ret = 0; +#if defined(FSL_FEATURE_SPI_HAS_FIFO) && FSL_FEATURE_SPI_HAS_FIFO + uint8_t rxSize = 0U; + /* Get the number to be sent if there is FIFO */ + if (FSL_FEATURE_SPI_FIFO_SIZEn(base) != 0) + { + rxSize = (base->C3 & SPI_C3_RNFULLF_MARK_MASK) >> SPI_C3_RNFULLF_MARK_SHIFT; + if (rxSize == 0U) + { + ret = FSL_FEATURE_SPI_FIFO_SIZEn(base) * 3U / 4U; + } + else + { + ret = FSL_FEATURE_SPI_FIFO_SIZEn(base) / 2U; + } + } + /* If no FIFO, just set the watermark to 1 */ + else + { + ret = 1U; + } +#else + ret = 1U; +#endif /* FSL_FEATURE_SPI_HAS_FIFO */ + return ret; +} + +static void SPI_SendInitialTransfer(SPI_Type *base, spi_master_handle_t *handle) +{ + uint8_t bytestoTransfer = handle->bytePerFrame; + +#if defined(FSL_FEATURE_SPI_HAS_FIFO) && (FSL_FEATURE_SPI_HAS_FIFO) + if (handle->watermark > 1) + { + /* In the first time to send data to FIFO, if transfer size is not larger than + * the FIFO size, send all data to FIFO, or send data to make the FIFO full. + * Besides, The FIFO's entry width is 16 bits, need to translate it to bytes. + */ + bytestoTransfer = MIN(handle->txRemainingBytes, (FSL_FEATURE_SPI_FIFO_SIZEn(base) * 2)); + } +#endif + + SPI_WriteNonBlocking(base, handle->txData, bytestoTransfer); + + /* Update handle information */ + if (handle->txData) + { + handle->txData += bytestoTransfer; + } + handle->txRemainingBytes -= bytestoTransfer; +} + static void SPI_SendTransfer(SPI_Type *base, spi_master_handle_t *handle) { - uint8_t bytes = MIN((handle->watermark * 2U), handle->txRemainingBytes); + uint8_t bytes = handle->bytePerFrame; /* Read S register and ensure SPTEF is 1, otherwise the write would be ignored. */ if (handle->watermark == 1U) { - if (bytes != 0U) - { - bytes = handle->bytePerFrame; - } - /* Send data */ if (base->C1 & SPI_C1_MSTR_MASK) { @@ -235,7 +304,7 @@ static void SPI_SendTransfer(SPI_Type *base, spi_master_handle_t *handle) else { /* As a slave, send data until SPTEF cleared */ - while ((base->S & SPI_S_SPTEF_MASK) && (handle->txRemainingBytes > 0)) + while ((base->S & SPI_S_SPTEF_MASK) && (handle->txRemainingBytes >= bytes)) { SPI_WriteNonBlocking(base, handle->txData, bytes); @@ -253,56 +322,96 @@ static void SPI_SendTransfer(SPI_Type *base, spi_master_handle_t *handle) /* If use FIFO */ else { - if (base->S & SPI_S_TNEAREF_MASK) - { - SPI_WriteNonBlocking(base, handle->txData, bytes); + /* The FIFO's entry width is 16 bits, need to translate it to bytes. */ + uint8_t bytestoTransfer = handle->watermark * 2; - /* Update handle information */ - if (handle->txData) - { - handle->txData += bytes; - } - handle->txRemainingBytes -= bytes; + if (handle->txRemainingBytes < 8U) + { + bytestoTransfer = handle->txRemainingBytes; } + + SPI_WriteNonBlocking(base, handle->txData, bytestoTransfer); + + /* Update handle information */ + if (handle->txData) + { + handle->txData += bytestoTransfer; + } + handle->txRemainingBytes -= bytestoTransfer; } #endif } static void SPI_ReceiveTransfer(SPI_Type *base, spi_master_handle_t *handle) { - uint8_t bytes = MIN((handle->watermark * 2U), handle->rxRemainingBytes); - uint8_t val = 1U; + uint8_t bytes = handle->bytePerFrame; /* Read S register and ensure SPRF is 1, otherwise the write would be ignored. */ if (handle->watermark == 1U) { - val = base->S & SPI_S_SPRF_MASK; - if (bytes != 0U) + if (base->S & SPI_S_SPRF_MASK) { - bytes = handle->bytePerFrame; + SPI_ReadNonBlocking(base, handle->rxData, bytes); + + /* Update information in handle */ + if (handle->rxData) + { + handle->rxData += bytes; + } + handle->rxRemainingBytes -= bytes; } } - - if (val) +#if defined(FSL_FEATURE_SPI_HAS_FIFO) && (FSL_FEATURE_SPI_HAS_FIFO) + /* If use FIFO */ + else { - SPI_ReadNonBlocking(base, handle->rxData, bytes); - - /* Update information in handle */ - if (handle->rxData) + /* While rx fifo not empty and remaining data can also trigger the last interrupt */ + while ((base->S & SPI_S_RFIFOEF_MASK) == 0U) { - handle->rxData += bytes; + SPI_ReadNonBlocking(base, handle->rxData, bytes); + + /* Update information in handle */ + if (handle->rxData) + { + handle->rxData += bytes; + } + handle->rxRemainingBytes -= bytes; + + /* If the reamining data equals to watermark, leave to last interrupt */ + if (handle->rxRemainingBytes == (handle->watermark * 2U)) + { + break; + } } - handle->rxRemainingBytes -= bytes; } +#endif } +/*! + * brief Sets the SPI master configuration structure to default values. + * + * The purpose of this API is to get the configuration structure initialized for use in SPI_MasterInit(). + * User may use the initialized structure unchanged in SPI_MasterInit(), or modify + * some fields of the structure before calling SPI_MasterInit(). After calling this API, + * the master is ready to transfer. + * Example: + code + spi_master_config_t config; + SPI_MasterGetDefaultConfig(&config); + endcode + * + * param config pointer to master config structure + */ void SPI_MasterGetDefaultConfig(spi_master_config_t *config) { - config->enableMaster = true; + /* Initializes the configure structure to zero. */ + memset(config, 0, sizeof(*config)); + + config->enableMaster = true; config->enableStopInWaitMode = false; - config->polarity = kSPI_ClockPolarityActiveHigh; - config->phase = kSPI_ClockPhaseFirstEdge; - config->direction = kSPI_MsbFirst; + config->polarity = kSPI_ClockPolarityActiveHigh; + config->phase = kSPI_ClockPhaseFirstEdge; + config->direction = kSPI_MsbFirst; #if defined(FSL_FEATURE_SPI_16BIT_TRANSFERS) && FSL_FEATURE_SPI_16BIT_TRANSFERS config->dataMode = kSPI_8BitMode; @@ -313,17 +422,37 @@ void SPI_MasterGetDefaultConfig(spi_master_config_t *config) config->rxWatermark = kSPI_RxFifoOneHalfFull; #endif /* FSL_FEATURE_SPI_HAS_FIFO */ - config->pinMode = kSPI_PinModeNormal; - config->outputMode = kSPI_SlaveSelectAutomaticOutput; + config->pinMode = kSPI_PinModeNormal; + config->outputMode = kSPI_SlaveSelectAutomaticOutput; config->baudRate_Bps = 500000U; } +/*! + * brief Initializes the SPI with master configuration. + * + * The configuration structure can be filled by user from scratch, or be set with default + * values by SPI_MasterGetDefaultConfig(). After calling this API, the slave is ready to transfer. + * Example + code + spi_master_config_t config = { + .baudRate_Bps = 400000, + ... + }; + SPI_MasterInit(SPI0, &config); + endcode + * + * param base SPI base pointer + * param config pointer to master configuration structure + * param srcClock_Hz Source clock frequency. + */ void SPI_MasterInit(SPI_Type *base, const spi_master_config_t *config, uint32_t srcClock_Hz) { assert(config && srcClock_Hz); +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /* Open clock gate for SPI and open interrupt */ CLOCK_EnableClock(s_spiClock[SPI_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ /* Disable SPI before configuration */ base->C1 &= ~SPI_C1_SPE_MASK; @@ -354,6 +483,9 @@ void SPI_MasterInit(SPI_Type *base, const spi_master_config_t *config, uint32_t /* Set baud rate */ SPI_MasterSetBaudRate(base, config->baudRate_Bps, srcClock_Hz); + /* Set the dummy data, this data will usefull when tx buffer is NULL. */ + SPI_SetDummyData(base, SPI_DUMMYDATA); + /* Enable SPI */ if (config->enableMaster) { @@ -361,12 +493,28 @@ void SPI_MasterInit(SPI_Type *base, const spi_master_config_t *config, uint32_t } } +/*! + * brief Sets the SPI slave configuration structure to default values. + * + * The purpose of this API is to get the configuration structure initialized for use in SPI_SlaveInit(). + * Modify some fields of the structure before calling SPI_SlaveInit(). + * Example: + code + spi_slave_config_t config; + SPI_SlaveGetDefaultConfig(&config); + endcode + * + * param config pointer to slave configuration structure + */ void SPI_SlaveGetDefaultConfig(spi_slave_config_t *config) { - config->enableSlave = true; - config->polarity = kSPI_ClockPolarityActiveHigh; - config->phase = kSPI_ClockPhaseFirstEdge; - config->direction = kSPI_MsbFirst; + /* Initializes the configure structure to zero. */ + memset(config, 0, sizeof(*config)); + + config->enableSlave = true; + config->polarity = kSPI_ClockPolarityActiveHigh; + config->phase = kSPI_ClockPhaseFirstEdge; + config->direction = kSPI_MsbFirst; config->enableStopInWaitMode = false; #if defined(FSL_FEATURE_SPI_16BIT_TRANSFERS) && FSL_FEATURE_SPI_16BIT_TRANSFERS @@ -377,14 +525,37 @@ void SPI_SlaveGetDefaultConfig(spi_slave_config_t *config) config->txWatermark = kSPI_TxFifoOneHalfEmpty; config->rxWatermark = kSPI_RxFifoOneHalfFull; #endif /* FSL_FEATURE_SPI_HAS_FIFO */ + config->pinMode = kSPI_PinModeNormal; } +/*! + * brief Initializes the SPI with slave configuration. + * + * The configuration structure can be filled by user from scratch or be set with + * default values by SPI_SlaveGetDefaultConfig(). + * After calling this API, the slave is ready to transfer. + * Example + code + spi_slave_config_t config = { + .polarity = kSPIClockPolarity_ActiveHigh; + .phase = kSPIClockPhase_FirstEdge; + .direction = kSPIMsbFirst; + ... + }; + SPI_MasterInit(SPI0, &config); + endcode + * + * param base SPI base pointer + * param config pointer to master configuration structure + */ void SPI_SlaveInit(SPI_Type *base, const spi_slave_config_t *config) { assert(config); +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /* Open clock gate for SPI and open interrupt */ CLOCK_EnableClock(s_spiClock[SPI_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ /* Disable SPI before configuration */ base->C1 &= ~SPI_C1_SPE_MASK; @@ -395,9 +566,11 @@ void SPI_SlaveInit(SPI_Type *base, const spi_slave_config_t *config) /* Configure data mode if needed */ #if defined(FSL_FEATURE_SPI_16BIT_TRANSFERS) && FSL_FEATURE_SPI_16BIT_TRANSFERS - base->C2 = SPI_C2_SPIMODE(config->dataMode) | SPI_C2_SPISWAI(config->enableStopInWaitMode); + base->C2 = SPI_C2_SPIMODE(config->dataMode) | SPI_C2_SPISWAI(config->enableStopInWaitMode) | + SPI_C2_BIDIROE(config->pinMode >> 1U) | SPI_C2_SPC0(config->pinMode & 1U); #else - base->C2 = SPI_C2_SPISWAI(config->enableStopInWaitMode); + base->C2 = SPI_C2_SPISWAI(config->enableStopInWaitMode) | SPI_C2_BIDIROE(config->pinMode >> 1U) | + SPI_C2_SPC0(config->pinMode & 1U); #endif /* FSL_FEATURE_SPI_16BIT_TRANSFERS */ /* Set watermark */ @@ -409,6 +582,9 @@ void SPI_SlaveInit(SPI_Type *base, const spi_slave_config_t *config) } #endif /* FSL_FEATURE_SPI_HAS_FIFO */ + /* Set the dummy data, this data will usefull when tx buffer is NULL. */ + SPI_SetDummyData(base, SPI_DUMMYDATA); + /* Enable SPI */ if (config->enableSlave) { @@ -416,15 +592,31 @@ void SPI_SlaveInit(SPI_Type *base, const spi_slave_config_t *config) } } +/*! + * brief De-initializes the SPI. + * + * Calling this API resets the SPI module, gates the SPI clock. + * The SPI module can't work unless calling the SPI_MasterInit/SPI_SlaveInit to initialize module. + * + * param base SPI base pointer + */ void SPI_Deinit(SPI_Type *base) { /* Disable SPI module before shutting down */ base->C1 &= ~SPI_C1_SPE_MASK; +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /* Gate the clock */ CLOCK_DisableClock(s_spiClock[SPI_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ } +/*! + * brief Gets the status flag. + * + * param base SPI base pointer + * return SPI Status, use status flag to AND #_spi_flags could get the related status. + */ uint32_t SPI_GetStatusFlags(SPI_Type *base) { #if defined(FSL_FEATURE_SPI_HAS_FIFO) && FSL_FEATURE_SPI_HAS_FIFO @@ -441,6 +633,17 @@ uint32_t SPI_GetStatusFlags(SPI_Type *base) #endif /* FSL_FEATURE_SPI_HAS_FIFO */ } +/*! + * brief Enables the interrupt for the SPI. + * + * param base SPI base pointer + * param mask SPI interrupt source. The parameter can be any combination of the following values: + * arg kSPI_RxFullAndModfInterruptEnable + * arg kSPI_TxEmptyInterruptEnable + * arg kSPI_MatchInterruptEnable + * arg kSPI_RxFifoNearFullInterruptEnable + * arg kSPI_TxFifoNearEmptyInterruptEnable + */ void SPI_EnableInterrupts(SPI_Type *base, uint32_t mask) { /* Rx full interrupt */ @@ -480,6 +683,17 @@ void SPI_EnableInterrupts(SPI_Type *base, uint32_t mask) #endif /* FSL_FEATURE_SPI_HAS_FIFO */ } +/*! + * brief Disables the interrupt for the SPI. + * + * param base SPI base pointer + * param mask SPI interrupt source. The parameter can be any combination of the following values: + * arg kSPI_RxFullAndModfInterruptEnable + * arg kSPI_TxEmptyInterruptEnable + * arg kSPI_MatchInterruptEnable + * arg kSPI_RxFifoNearFullInterruptEnable + * arg kSPI_TxFifoNearEmptyInterruptEnable + */ void SPI_DisableInterrupts(SPI_Type *base, uint32_t mask) { /* Rx full interrupt */ @@ -518,6 +732,13 @@ void SPI_DisableInterrupts(SPI_Type *base, uint32_t mask) #endif /* FSL_FEATURE_SPI_HAS_FIFO */ } +/*! + * brief Sets the baud rate for SPI transfer. This is only used in master. + * + * param base SPI base pointer + * param baudRate_Bps baud rate needed in Hz. + * param srcClock_Hz SPI source clock frequency in Hz. + */ void SPI_MasterSetBaudRate(SPI_Type *base, uint32_t baudRate_Bps, uint32_t srcClock_Hz) { uint32_t prescaler; @@ -535,7 +756,7 @@ void SPI_MasterSetBaudRate(SPI_Type *base, uint32_t baudRate_Bps, uint32_t srcCl /* Set the maximum divisor bit settings for each of the following divisors */ bestPrescaler = 7U; - bestDivisor = 8U; + bestDivisor = 8U; /* In all for loops, if min_diff = 0, the exit for loop*/ for (prescaler = 0; (prescaler <= 7) && min_diff; prescaler++) @@ -556,9 +777,9 @@ void SPI_MasterSetBaudRate(SPI_Type *base, uint32_t baudRate_Bps, uint32_t srcCl if (min_diff > diff) { /* A better match found */ - min_diff = diff; + min_diff = diff; bestPrescaler = prescaler; - bestDivisor = rateDivisor; + bestDivisor = rateDivisor; } } @@ -571,9 +792,18 @@ void SPI_MasterSetBaudRate(SPI_Type *base, uint32_t baudRate_Bps, uint32_t srcCl base->BR = SPI_BR_SPR(bestDivisor) | SPI_BR_SPPR(bestPrescaler); } +/*! + * brief Sends a buffer of data bytes using a blocking method. + * + * note This function blocks via polling until all bytes have been sent. + * + * param base SPI base pointer + * param buffer The data bytes to send + * param size The number of data bytes to send + */ void SPI_WriteBlocking(SPI_Type *base, uint8_t *buffer, size_t size) { - uint32_t i = 0; + uint32_t i = 0; uint8_t bytesPerFrame = 1U; #if defined(FSL_FEATURE_SPI_16BIT_TRANSFERS) && FSL_FEATURE_SPI_16BIT_TRANSFERS @@ -596,6 +826,12 @@ void SPI_WriteBlocking(SPI_Type *base, uint8_t *buffer, size_t size) } #if defined(FSL_FEATURE_SPI_HAS_FIFO) && FSL_FEATURE_SPI_HAS_FIFO +/*! + * brief Enables or disables the FIFO if there is a FIFO. + * + * param base SPI base pointer + * param enable True means enable FIFO, false means disable FIFO. + */ void SPI_EnableFIFO(SPI_Type *base, bool enable) { if (FSL_FEATURE_SPI_FIFO_SIZEn(base) != 0U) @@ -612,6 +848,12 @@ void SPI_EnableFIFO(SPI_Type *base, bool enable) } #endif /* FSL_FEATURE_SPI_HAS_FIFO */ +/*! + * brief Writes a data into the SPI data register. + * + * param base SPI base pointer + * param data needs to be write. + */ void SPI_WriteData(SPI_Type *base, uint16_t data) { #if defined(FSL_FEATURE_SPI_16BIT_TRANSFERS) && (FSL_FEATURE_SPI_16BIT_TRANSFERS) @@ -622,6 +864,12 @@ void SPI_WriteData(SPI_Type *base, uint16_t data) #endif } +/*! + * brief Gets a data from the SPI data register. + * + * param base SPI base pointer + * return Data in the register. + */ uint16_t SPI_ReadData(SPI_Type *base) { uint16_t val = 0; @@ -634,6 +882,14 @@ uint16_t SPI_ReadData(SPI_Type *base) return val; } +/*! + * brief Transfers a block of data using a polling method. + * + * param base SPI base pointer + * param xfer pointer to spi_xfer_config_t structure + * retval kStatus_Success Successfully start a transfer. + * retval kStatus_InvalidArgument Input argument is invalid. + */ status_t SPI_MasterTransferBlocking(SPI_Type *base, spi_transfer_t *xfer) { assert(xfer); @@ -651,10 +907,6 @@ status_t SPI_MasterTransferBlocking(SPI_Type *base, spi_transfer_t *xfer) bytesPerFrame = ((base->C2 & SPI_C2_SPIMODE_MASK) >> SPI_C2_SPIMODE_SHIFT) + 1U; #endif - /* Disable SPI and then enable it, this is used to clear S register */ - base->C1 &= ~SPI_C1_SPE_MASK; - base->C1 |= SPI_C1_SPE_MASK; - #if defined(FSL_FEATURE_SPI_HAS_FIFO) && FSL_FEATURE_SPI_HAS_FIFO /* Disable FIFO, as the FIFO may cause data loss if the data size is not integer @@ -696,6 +948,17 @@ status_t SPI_MasterTransferBlocking(SPI_Type *base, spi_transfer_t *xfer) return kStatus_Success; } +/*! + * brief Initializes the SPI master handle. + * + * This function initializes the SPI master handle which can be used for other SPI master transactional APIs. Usually, + * for a specified SPI instance, call this API once to get the initialized handle. + * + * param base SPI peripheral base address. + * param handle SPI handle pointer. + * param callback Callback function. + * param userData User data. + */ void SPI_MasterTransferCreateHandle(SPI_Type *base, spi_master_handle_t *handle, spi_master_callback_t callback, @@ -705,35 +968,15 @@ void SPI_MasterTransferCreateHandle(SPI_Type *base, uint8_t instance = SPI_GetInstance(base); + /* Zero the handle */ + memset(handle, 0, sizeof(*handle)); + /* Initialize the handle */ s_spiHandle[instance] = handle; - handle->callback = callback; - handle->userData = userData; - s_spiIsr = SPI_MasterTransferHandleIRQ; - -#if defined(FSL_FEATURE_SPI_HAS_FIFO) && FSL_FEATURE_SPI_HAS_FIFO - uint8_t txSize = 0U; - /* Get the number to be sent if there is FIFO */ - if (FSL_FEATURE_SPI_FIFO_SIZEn(base) != 0) - { - txSize = (base->C3 & SPI_C3_TNEAREF_MARK_MASK) >> SPI_C3_TNEAREF_MARK_SHIFT; - if (txSize == 0U) - { - handle->watermark = FSL_FEATURE_SPI_FIFO_SIZEn(base) * 3U / 4U; - } - else - { - handle->watermark = FSL_FEATURE_SPI_FIFO_SIZEn(base) / 2U; - } - } - /* If no FIFO, just set the watermark to 1 */ - else - { - handle->watermark = 1U; - } -#else - handle->watermark = 1U; -#endif /* FSL_FEATURE_SPI_HAS_FIFO */ + handle->callback = callback; + handle->userData = userData; + s_spiMasterIsr = SPI_MasterTransferHandleIRQ; + handle->watermark = SPI_GetWatermark(base); /* Get the bytes per frame */ #if defined(FSL_FEATURE_SPI_16BIT_TRANSFERS) && (FSL_FEATURE_SPI_16BIT_TRANSFERS) @@ -746,6 +989,20 @@ void SPI_MasterTransferCreateHandle(SPI_Type *base, EnableIRQ(s_spiIRQ[instance]); } +/*! + * brief Performs a non-blocking SPI interrupt transfer. + * + * note The API immediately returns after transfer initialization is finished. + * Call SPI_GetStatusIRQ() to get the transfer status. + * note If SPI transfer data frame size is 16 bits, the transfer size cannot be an odd number. + * + * param base SPI peripheral base address. + * param handle pointer to spi_master_handle_t structure which stores the transfer state + * param xfer pointer to spi_xfer_config_t structure + * retval kStatus_Success Successfully start a transfer. + * retval kStatus_InvalidArgument Input argument is invalid. + * retval kStatus_SPI_Busy SPI is not idle, is running another transfer. + */ status_t SPI_MasterTransferNonBlocking(SPI_Type *base, spi_master_handle_t *handle, spi_transfer_t *xfer) { assert(handle && xfer); @@ -763,47 +1020,76 @@ status_t SPI_MasterTransferNonBlocking(SPI_Type *base, spi_master_handle_t *hand } /* Set the handle information */ - handle->txData = xfer->txData; - handle->rxData = xfer->rxData; - handle->transferSize = xfer->dataSize; + handle->txData = xfer->txData; + handle->rxData = xfer->rxData; + handle->transferSize = xfer->dataSize; handle->txRemainingBytes = xfer->dataSize; handle->rxRemainingBytes = xfer->dataSize; /* Set the SPI state to busy */ handle->state = kSPI_Busy; - /* Disable SPI and then enable it, this is used to clear S register*/ - base->C1 &= ~SPI_C1_SPE_MASK; - base->C1 |= SPI_C1_SPE_MASK; - /* Enable Interrupt, only enable Rx interrupt, use rx interrupt to driver SPI transfer */ #if defined(FSL_FEATURE_SPI_HAS_FIFO) && FSL_FEATURE_SPI_HAS_FIFO + + handle->watermark = SPI_GetWatermark(base); + + /* If the size of the transfer size less than watermark, set watermark to 1 */ + if (xfer->dataSize < handle->watermark * 2U) + { + handle->watermark = 1U; + } + + /* According to watermark size, enable interrupts */ if (handle->watermark > 1U) { + SPI_EnableFIFO(base, true); + /* First send a piece of data to Tx Data or FIFO to start a SPI transfer */ + while ((base->S & SPI_S_TNEAREF_MASK) != SPI_S_TNEAREF_MASK) + { + } + SPI_SendInitialTransfer(base, handle); /* Enable Rx near full interrupt */ SPI_EnableInterrupts(base, kSPI_RxFifoNearFullInterruptEnable); } else { + SPI_EnableFIFO(base, false); + while ((base->S & SPI_S_SPTEF_MASK) != SPI_S_SPTEF_MASK) + { + } + /* First send a piece of data to Tx Data or FIFO to start a SPI transfer */ + SPI_SendInitialTransfer(base, handle); SPI_EnableInterrupts(base, kSPI_RxFullAndModfInterruptEnable); } #else + while ((base->S & SPI_S_SPTEF_MASK) != SPI_S_SPTEF_MASK) + { + } + /* First send a piece of data to Tx Data or FIFO to start a SPI transfer */ + SPI_SendInitialTransfer(base, handle); SPI_EnableInterrupts(base, kSPI_RxFullAndModfInterruptEnable); #endif - /* First send a piece of data to Tx Data or FIFO to start a SPI transfer */ - SPI_SendTransfer(base, handle); - return kStatus_Success; } +/*! + * brief Gets the bytes of the SPI interrupt transferred. + * + * param base SPI peripheral base address. + * param handle Pointer to SPI transfer handle, this should be a static variable. + * param count Transferred bytes of SPI master. + * retval kStatus_SPI_Success Succeed get the transfer count. + * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress. + */ status_t SPI_MasterTransferGetCount(SPI_Type *base, spi_master_handle_t *handle, size_t *count) { assert(handle); status_t status = kStatus_Success; - if (handle->state != kStatus_SPI_Busy) + if (handle->state != kSPI_Busy) { status = kStatus_NoTransferInProgress; } @@ -823,6 +1109,12 @@ status_t SPI_MasterTransferGetCount(SPI_Type *base, spi_master_handle_t *handle, return status; } +/*! + * brief Aborts an SPI transfer using interrupt. + * + * param base SPI peripheral base address. + * param handle Pointer to SPI transfer handle, this should be a static variable. + */ void SPI_MasterTransferAbort(SPI_Type *base, spi_master_handle_t *handle) { assert(handle); @@ -849,6 +1141,12 @@ void SPI_MasterTransferAbort(SPI_Type *base, spi_master_handle_t *handle) handle->txRemainingBytes = 0; } +/*! + * brief Interrupts the handler for the SPI. + * + * param base SPI peripheral base address. + * param handle pointer to spi_master_handle_t structure which stores the transfer state. + */ void SPI_MasterTransferHandleIRQ(SPI_Type *base, spi_master_handle_t *handle) { assert(handle); @@ -878,6 +1176,17 @@ void SPI_MasterTransferHandleIRQ(SPI_Type *base, spi_master_handle_t *handle) } } +/*! + * brief Initializes the SPI slave handle. + * + * This function initializes the SPI slave handle which can be used for other SPI slave transactional APIs. Usually, + * for a specified SPI instance, call this API once to get the initialized handle. + * + * param base SPI peripheral base address. + * param handle SPI handle pointer. + * param callback Callback function. + * param userData User data. + */ void SPI_SlaveTransferCreateHandle(SPI_Type *base, spi_slave_handle_t *handle, spi_slave_callback_t callback, @@ -888,9 +1197,15 @@ void SPI_SlaveTransferCreateHandle(SPI_Type *base, /* Slave create handle share same logic with master create handle, the only difference is the Isr pointer. */ SPI_MasterTransferCreateHandle(base, handle, callback, userData); - s_spiIsr = SPI_SlaveTransferHandleIRQ; + s_spiSlaveIsr = SPI_SlaveTransferHandleIRQ; } +/*! + * brief Interrupts a handler for the SPI slave. + * + * param base SPI peripheral base address. + * param handle pointer to spi_slave_handle_t structure which stores the transfer state + */ void SPI_SlaveTransferHandleIRQ(SPI_Type *base, spi_slave_handle_t *handle) { assert(handle); @@ -920,11 +1235,28 @@ void SPI_SlaveTransferHandleIRQ(SPI_Type *base, spi_slave_handle_t *handle) } } +static void SPI_CommonIRQHandler(SPI_Type *base, uint32_t instance) +{ + if (base->C1 & SPI_C1_MSTR_MASK) + { + s_spiMasterIsr(base, s_spiHandle[instance]); + } + else + { + s_spiSlaveIsr(base, s_spiHandle[instance]); + } +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} + #if defined(SPI0) void SPI0_DriverIRQHandler(void) { assert(s_spiHandle[0]); - s_spiIsr(SPI0, s_spiHandle[0]); + SPI_CommonIRQHandler(SPI0, 0); } #endif @@ -932,7 +1264,7 @@ void SPI0_DriverIRQHandler(void) void SPI1_DriverIRQHandler(void) { assert(s_spiHandle[1]); - s_spiIsr(SPI1, s_spiHandle[1]); + SPI_CommonIRQHandler(SPI1, 1); } #endif @@ -940,6 +1272,6 @@ void SPI1_DriverIRQHandler(void) void SPI2_DriverIRQHandler(void) { assert(s_spiHandle[2]); - s_spiIsr(SPI0, s_spiHandle[2]); + SPI_CommonIRQHandler(SPI2, 2); } #endif diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL43Z/drivers/fsl_spi.h b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL43Z/drivers/fsl_spi.h index 7e9162350d..0e0360ca5c 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL43Z/drivers/fsl_spi.h +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL43Z/drivers/fsl_spi.h @@ -1,31 +1,9 @@ /* * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP * All rights reserved. * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * o Redistributions of source code must retain the above copyright notice, this list - * of conditions and the following disclaimer. - * - * o 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. - * - * o Neither the name of Freescale Semiconductor, Inc. nor the names of its - * contributors may be used tom 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. + * SPDX-License-Identifier: BSD-3-Clause */ #ifndef _FSL_SPI_H_ #define _FSL_SPI_H_ @@ -37,15 +15,14 @@ * @{ */ - /******************************************************************************* * Definitions ******************************************************************************/ /*! @name Driver version */ /*@{*/ -/*! @brief SPI driver version 2.0.1. */ -#define FSL_SPI_DRIVER_VERSION (MAKE_VERSION(2, 0, 1)) +/*! @brief SPI driver version 2.0.4. */ +#define FSL_SPI_DRIVER_VERSION (MAKE_VERSION(2, 0, 4)) /*@}*/ #ifndef SPI_DUMMYDATA @@ -53,12 +30,15 @@ #define SPI_DUMMYDATA (0xFFU) #endif +/*! @brief Global variable for dummy data value setting. */ +extern volatile uint8_t g_spiDummyData[]; + /*! @brief Return status for the SPI driver.*/ enum _spi_status { - kStatus_SPI_Busy = MAKE_STATUS(kStatusGroup_SPI, 0), /*!< SPI bus is busy */ - kStatus_SPI_Idle = MAKE_STATUS(kStatusGroup_SPI, 1), /*!< SPI is idle */ - kStatus_SPI_Error = MAKE_STATUS(kStatusGroup_SPI, 2) /*!< SPI error */ + kStatus_SPI_Busy = MAKE_STATUS(kStatusGroup_SPI, 0), /*!< SPI bus is busy */ + kStatus_SPI_Idle = MAKE_STATUS(kStatusGroup_SPI, 1), /*!< SPI is idle */ + kStatus_SPI_Error = MAKE_STATUS(kStatusGroup_SPI, 2) /*!< SPI error */ }; /*! @brief SPI clock polarity configuration.*/ @@ -87,16 +67,16 @@ typedef enum _spi_shift_direction /*! @brief SPI slave select output mode options.*/ typedef enum _spi_ss_output_mode { - kSPI_SlaveSelectAsGpio = 0x0U, /*!< Slave select pin configured as GPIO. */ - kSPI_SlaveSelectFaultInput = 0x2U, /*!< Slave select pin configured for fault detection. */ - kSPI_SlaveSelectAutomaticOutput = 0x3U /*!< Slave select pin configured for automatic SPI output. */ + kSPI_SlaveSelectAsGpio = 0x0U, /*!< Slave select pin configured as GPIO. */ + kSPI_SlaveSelectFaultInput = 0x2U, /*!< Slave select pin configured for fault detection. */ + kSPI_SlaveSelectAutomaticOutput = 0x3U /*!< Slave select pin configured for automatic SPI output. */ } spi_ss_output_mode_t; /*! @brief SPI pin mode options.*/ typedef enum _spi_pin_mode { kSPI_PinModeNormal = 0x0U, /*!< Pins operate in normal, single-direction mode.*/ - kSPI_PinModeInput = 0x1U, /*!< Bidirectional mode. Master: MOSI pin is input; + kSPI_PinModeInput = 0x1U, /*!< Bidirectional mode. Master: MOSI pin is input; * Slave: MISO pin is input. */ kSPI_PinModeOutput = 0x3U /*!< Bidirectional mode. Master: MOSI pin is output; * Slave: MISO pin is output. */ @@ -113,10 +93,10 @@ typedef enum _spi_data_bitcount_mode enum _spi_interrupt_enable { kSPI_RxFullAndModfInterruptEnable = 0x1U, /*!< Receive buffer full (SPRF) and mode fault (MODF) interrupt */ - kSPI_TxEmptyInterruptEnable = 0x2U, /*!< Transmit buffer empty interrupt */ - kSPI_MatchInterruptEnable = 0x4U, /*!< Match interrupt */ + kSPI_TxEmptyInterruptEnable = 0x2U, /*!< Transmit buffer empty interrupt */ + kSPI_MatchInterruptEnable = 0x4U, /*!< Match interrupt */ #if defined(FSL_FEATURE_SPI_HAS_FIFO) && FSL_FEATURE_SPI_HAS_FIFO - kSPI_RxFifoNearFullInterruptEnable = 0x8U, /*!< Receive FIFO nearly full interrupt */ + kSPI_RxFifoNearFullInterruptEnable = 0x8U, /*!< Receive FIFO nearly full interrupt */ kSPI_TxFifoNearEmptyInterruptEnable = 0x10U, /*!< Transmit FIFO nearly empty interrupt */ #endif /* FSL_FEATURE_SPI_HAS_FIFO */ }; @@ -124,44 +104,44 @@ enum _spi_interrupt_enable /*! @brief SPI status flags.*/ enum _spi_flags { - kSPI_RxBufferFullFlag = SPI_S_SPRF_MASK, /*!< Read buffer full flag */ - kSPI_MatchFlag = SPI_S_SPMF_MASK, /*!< Match flag */ + kSPI_RxBufferFullFlag = SPI_S_SPRF_MASK, /*!< Read buffer full flag */ + kSPI_MatchFlag = SPI_S_SPMF_MASK, /*!< Match flag */ kSPI_TxBufferEmptyFlag = SPI_S_SPTEF_MASK, /*!< Transmit buffer empty flag */ - kSPI_ModeFaultFlag = SPI_S_MODF_MASK, /*!< Mode fault flag */ + kSPI_ModeFaultFlag = SPI_S_MODF_MASK, /*!< Mode fault flag */ #if defined(FSL_FEATURE_SPI_HAS_FIFO) && FSL_FEATURE_SPI_HAS_FIFO - kSPI_RxFifoNearFullFlag = SPI_S_RNFULLF_MASK, /*!< Rx FIFO near full */ - kSPI_TxFifoNearEmptyFlag = SPI_S_TNEAREF_MASK, /*!< Tx FIFO near empty */ - kSPI_TxFifoFullFlag = SPI_S_TXFULLF_MASK, /*!< Tx FIFO full */ - kSPI_RxFifoEmptyFlag = SPI_S_RFIFOEF_MASK, /*!< Rx FIFO empty */ - kSPI_TxFifoError = SPI_CI_TXFERR_MASK << 8U, /*!< Tx FIFO error */ - kSPI_RxFifoError = SPI_CI_RXFERR_MASK << 8U, /*!< Rx FIFO error */ - kSPI_TxOverflow = SPI_CI_TXFOF_MASK << 8U, /*!< Tx FIFO Overflow */ - kSPI_RxOverflow = SPI_CI_RXFOF_MASK << 8U /*!< Rx FIFO Overflow */ -#endif /* FSL_FEATURE_SPI_HAS_FIFO */ + kSPI_RxFifoNearFullFlag = SPI_S_RNFULLF_MASK, /*!< Rx FIFO near full */ + kSPI_TxFifoNearEmptyFlag = SPI_S_TNEAREF_MASK, /*!< Tx FIFO near empty */ + kSPI_TxFifoFullFlag = SPI_S_TXFULLF_MASK, /*!< Tx FIFO full */ + kSPI_RxFifoEmptyFlag = SPI_S_RFIFOEF_MASK, /*!< Rx FIFO empty */ + kSPI_TxFifoError = SPI_CI_TXFERR_MASK << 8U, /*!< Tx FIFO error */ + kSPI_RxFifoError = SPI_CI_RXFERR_MASK << 8U, /*!< Rx FIFO error */ + kSPI_TxOverflow = SPI_CI_TXFOF_MASK << 8U, /*!< Tx FIFO Overflow */ + kSPI_RxOverflow = SPI_CI_RXFOF_MASK << 8U /*!< Rx FIFO Overflow */ +#endif /* FSL_FEATURE_SPI_HAS_FIFO */ }; #if defined(FSL_FEATURE_SPI_HAS_FIFO) && FSL_FEATURE_SPI_HAS_FIFO /*! @brief SPI FIFO write-1-to-clear interrupt flags.*/ typedef enum _spi_w1c_interrupt { - kSPI_RxFifoFullClearInterrupt = SPI_CI_SPRFCI_MASK, /*!< Receive FIFO full interrupt */ - kSPI_TxFifoEmptyClearInterrupt = SPI_CI_SPTEFCI_MASK, /*!< Transmit FIFO empty interrupt */ - kSPI_RxNearFullClearInterrupt = SPI_CI_RNFULLFCI_MASK, /*!< Receive FIFO nearly full interrupt */ - kSPI_TxNearEmptyClearInterrupt = SPI_CI_TNEAREFCI_MASK /*!< Transmit FIFO nearly empty interrupt */ + kSPI_RxFifoFullClearInterrupt = SPI_CI_SPRFCI_MASK, /*!< Receive FIFO full interrupt */ + kSPI_TxFifoEmptyClearInterrupt = SPI_CI_SPTEFCI_MASK, /*!< Transmit FIFO empty interrupt */ + kSPI_RxNearFullClearInterrupt = SPI_CI_RNFULLFCI_MASK, /*!< Receive FIFO nearly full interrupt */ + kSPI_TxNearEmptyClearInterrupt = SPI_CI_TNEAREFCI_MASK /*!< Transmit FIFO nearly empty interrupt */ } spi_w1c_interrupt_t; /*! @brief SPI TX FIFO watermark settings.*/ typedef enum _spi_txfifo_watermark { kSPI_TxFifoOneFourthEmpty = 0, /*!< SPI tx watermark at 1/4 FIFO size */ - kSPI_TxFifoOneHalfEmpty = 1 /*!< SPI tx watermark at 1/2 FIFO size */ + kSPI_TxFifoOneHalfEmpty = 1 /*!< SPI tx watermark at 1/2 FIFO size */ } spi_txfifo_watermark_t; /*! @brief SPI RX FIFO watermark settings.*/ typedef enum _spi_rxfifo_watermark { kSPI_RxFifoThreeFourthsFull = 0, /*!< SPI rx watermark at 3/4 FIFO size */ - kSPI_RxFifoOneHalfFull = 1 /*!< SPI rx watermark at 1/2 FIFO size */ + kSPI_RxFifoOneHalfFull = 1 /*!< SPI rx watermark at 1/2 FIFO size */ } spi_rxfifo_watermark_t; #endif /* FSL_FEATURE_SPI_HAS_FIFO */ @@ -169,8 +149,8 @@ typedef enum _spi_rxfifo_watermark /*! @brief SPI DMA source*/ enum _spi_dma_enable_t { - kSPI_TxDmaEnable = SPI_C2_TXDMAE_MASK, /*!< Tx DMA request source */ - kSPI_RxDmaEnable = SPI_C2_RXDMAE_MASK, /*!< Rx DMA request source */ + kSPI_TxDmaEnable = SPI_C2_TXDMAE_MASK, /*!< Tx DMA request source */ + kSPI_RxDmaEnable = SPI_C2_RXDMAE_MASK, /*!< Rx DMA request source */ kSPI_DmaAllEnable = (SPI_C2_TXDMAE_MASK | SPI_C2_RXDMAE_MASK) /*!< All DMA request source*/ }; #endif /* FSL_FEATURE_SPI_HAS_DMA_SUPPORT */ @@ -210,6 +190,7 @@ typedef struct _spi_slave_config spi_txfifo_watermark_t txWatermark; /*!< Tx watermark settings */ spi_rxfifo_watermark_t rxWatermark; /*!< Rx watermark settings */ #endif /* FSL_FEATURE_SPI_HAS_FIFO */ + spi_pin_mode_t pinMode; /*!< SPI pin mode select */ } spi_slave_config_t; /*! @brief SPI transfer structure */ @@ -478,6 +459,27 @@ static inline uint32_t SPI_GetDataRegisterAddress(SPI_Type *base) * @{ */ +/*! + * @brief Get the instance for SPI module. + * + * @param base SPI base address + */ +uint32_t SPI_GetInstance(SPI_Type *base); + +/*! + * @brief Sets the pin mode for transfer. + * + * @param base SPI base pointer + * @param pinMode pin mode for transfer AND #_spi_pin_mode could get the related configuration. + */ +static inline void SPI_SetPinMode(SPI_Type *base, spi_pin_mode_t pinMode) +{ + /* Clear SPC0 and BIDIROE bit. */ + base->C2 &= ~(SPI_C2_BIDIROE_MASK | SPI_C2_SPC0_MASK); + /* Set pin mode for transfer. */ + base->C2 |= SPI_C2_BIDIROE(pinMode >> 1U) | SPI_C2_SPC0(pinMode & 1U); +} + /*! * @brief Sets the baud rate for SPI transfer. This is only used in master. * @@ -544,6 +546,13 @@ void SPI_WriteData(SPI_Type *base, uint16_t data); */ uint16_t SPI_ReadData(SPI_Type *base); +/*! + * @brief Set up the dummy data. + * + * @param base SPI peripheral address. + * @param dummyData Data to be transferred when tx buffer is NULL. + */ +void SPI_SetDummyData(SPI_Type *base, uint8_t dummyData); /*! @} */ /*! @@ -582,11 +591,7 @@ status_t SPI_MasterTransferBlocking(SPI_Type *base, spi_transfer_t *xfer); * * @note The API immediately returns after transfer initialization is finished. * Call SPI_GetStatusIRQ() to get the transfer status. - * @note If using the SPI with FIFO for the interrupt transfer, the transfer size is the integer times of the watermark. - * Otherwise, - * the last data may be lost because it cannot generate an interrupt request. Users can also call the functional API to - * get the last - * received data. + * @note If SPI transfer data frame size is 16 bits, the transfer size cannot be an odd number. * * @param base SPI peripheral base address. * @param handle pointer to spi_master_handle_t structure which stores the transfer state @@ -636,8 +641,8 @@ void SPI_MasterTransferHandleIRQ(SPI_Type *base, spi_master_handle_t *handle); * @param userData User data. */ void SPI_SlaveTransferCreateHandle(SPI_Type *base, - spi_slave_handle_t *handle, - spi_slave_callback_t callback, + spi_slave_handle_t *handle, + spi_slave_callback_t callback, void *userData); /*! @@ -645,11 +650,7 @@ void SPI_SlaveTransferCreateHandle(SPI_Type *base, * * @note The API returns immediately after the transfer initialization is finished. * Call SPI_GetStatusIRQ() to get the transfer status. - * @note If using the SPI with FIFO for the interrupt transfer, the transfer size is the integer times the watermark. - * Otherwise, - * the last data may be lost because it cannot generate an interrupt request. Call the functional API to get the last - * several - * receive data. + * @note If SPI transfer data frame size is 16 bits, the transfer size cannot be an odd number. * * @param base SPI peripheral base address. * @param handle pointer to spi_master_handle_t structure which stores the transfer state diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL43Z/drivers/fsl_spi_dma.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL43Z/drivers/fsl_spi_dma.c index cdaddcc799..003d4c3ed7 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL43Z/drivers/fsl_spi_dma.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL43Z/drivers/fsl_spi_dma.c @@ -1,38 +1,22 @@ /* * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP * All rights reserved. * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * o Redistributions of source code must retain the above copyright notice, this list - * of conditions and the following disclaimer. - * - * o 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. - * - * o Neither the name of Freescale Semiconductor, Inc. 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. + * SPDX-License-Identifier: BSD-3-Clause */ #include "fsl_spi_dma.h" /******************************************************************************* - * Definitons + * Definitions ******************************************************************************/ + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.spi_dma" +#endif + /*handle; - SPI_Type *base = privHandle->base; + spi_dma_handle_t *spiHandle = privHandle->handle; + SPI_Type *base = privHandle->base; /* Disable Tx dma */ SPI_EnableDMA(base, kSPI_TxDmaEnable, false); - /* Stop DMA tranfer */ + /* Stop DMA transfer */ DMA_StopTransfer(spiHandle->txHandle); /* change the state */ @@ -114,13 +84,13 @@ static void SPI_TxDMACallback(dma_handle_t *handle, void *userData) static void SPI_RxDMACallback(dma_handle_t *handle, void *userData) { spi_dma_private_handle_t *privHandle = (spi_dma_private_handle_t *)userData; - spi_dma_handle_t *spiHandle = privHandle->handle; - SPI_Type *base = privHandle->base; + spi_dma_handle_t *spiHandle = privHandle->handle; + SPI_Type *base = privHandle->base; /* Disable Tx dma */ SPI_EnableDMA(base, kSPI_RxDmaEnable, false); - /* Stop DMA tranfer */ + /* Stop DMA transfer */ DMA_StopTransfer(spiHandle->rxHandle); /* change the state */ @@ -137,6 +107,19 @@ static void SPI_RxDMACallback(dma_handle_t *handle, void *userData) } } +/*! + * brief Initialize the SPI master DMA handle. + * + * This function initializes the SPI master DMA handle which can be used for other SPI master transactional APIs. + * Usually, for a specified SPI instance, user need only call this API once to get the initialized handle. + * + * param base SPI peripheral base address. + * param handle SPI handle pointer. + * param callback User callback function called at the end of a transfer. + * param userData User data for callback. + * param txHandle DMA handle pointer for SPI Tx, the handle shall be static allocated by users. + * param rxHandle DMA handle pointer for SPI Rx, the handle shall be static allocated by users. + */ void SPI_MasterTransferCreateHandleDMA(SPI_Type *base, spi_dma_handle_t *handle, spi_dma_callback_t callback, @@ -146,7 +129,10 @@ void SPI_MasterTransferCreateHandleDMA(SPI_Type *base, { assert(handle); dma_transfer_config_t config = {0}; - uint32_t instance = SPI_GetInstance(base); + uint32_t instance = SPI_GetInstance(base); + + /* Zero the handle */ + memset(handle, 0, sizeof(*handle)); /* Set spi base to handle */ handle->txHandle = txHandle; @@ -158,7 +144,7 @@ void SPI_MasterTransferCreateHandleDMA(SPI_Type *base, handle->state = kSPI_Idle; /* Set handle to global state */ - s_dmaPrivateHandle[instance].base = base; + s_dmaPrivateHandle[instance].base = base; s_dmaPrivateHandle[instance].handle = handle; /* Compute internal state */ @@ -180,27 +166,27 @@ void SPI_MasterTransferCreateHandleDMA(SPI_Type *base, #endif /* FSL_FEATURE_SPI_HAS_FIFO */ /* Set the non-change attribute for Tx DMA transfer, to improve efficiency */ - config.destAddr = SPI_GetDataRegisterAddress(base); + config.destAddr = SPI_GetDataRegisterAddress(base); config.enableDestIncrement = false; - config.enableSrcIncrement = true; + config.enableSrcIncrement = true; if (handle->bytesPerFrame == 1U) { - config.srcSize = kDMA_Transfersize8bits; + config.srcSize = kDMA_Transfersize8bits; config.destSize = kDMA_Transfersize8bits; } else { - config.srcSize = kDMA_Transfersize16bits; + config.srcSize = kDMA_Transfersize16bits; config.destSize = kDMA_Transfersize16bits; } DMA_SubmitTransfer(handle->txHandle, &config, true); /* Set non-change attribute for Rx DMA */ - config.srcAddr = SPI_GetDataRegisterAddress(base); - config.destAddr = 0U; + config.srcAddr = SPI_GetDataRegisterAddress(base); + config.destAddr = 0U; config.enableDestIncrement = true; - config.enableSrcIncrement = false; + config.enableSrcIncrement = false; DMA_SubmitTransfer(handle->rxHandle, &config, true); /* Install callback for Tx dma channel */ @@ -208,6 +194,19 @@ void SPI_MasterTransferCreateHandleDMA(SPI_Type *base, DMA_SetCallback(handle->rxHandle, SPI_RxDMACallback, &s_dmaPrivateHandle[instance]); } +/*! + * brief Perform a non-blocking SPI transfer using DMA. + * + * note This interface returned immediately after transfer initiates, users should call + * SPI_GetTransferStatus to poll the transfer status to check whether SPI transfer finished. + * + * param base SPI peripheral base address. + * param handle SPI DMA handle pointer. + * param xfer Pointer to dma transfer structure. + * retval kStatus_Success Successfully start a transfer. + * retval kStatus_InvalidArgument Input argument is invalid. + * retval kStatus_SPI_Busy SPI is not idle, is running another transfer. + */ status_t SPI_MasterTransferDMA(SPI_Type *base, spi_dma_handle_t *handle, spi_transfer_t *xfer) { assert(handle && xfer); @@ -231,16 +230,16 @@ status_t SPI_MasterTransferDMA(SPI_Type *base, spi_dma_handle_t *handle, spi_tra SPI_Enable(base, true); /* Configure tx transfer DMA */ - config.destAddr = SPI_GetDataRegisterAddress(base); + config.destAddr = SPI_GetDataRegisterAddress(base); config.enableDestIncrement = false; if (handle->bytesPerFrame == 1U) { - config.srcSize = kDMA_Transfersize8bits; + config.srcSize = kDMA_Transfersize8bits; config.destSize = kDMA_Transfersize8bits; } else { - config.srcSize = kDMA_Transfersize16bits; + config.srcSize = kDMA_Transfersize16bits; config.destSize = kDMA_Transfersize16bits; } config.transferSize = xfer->dataSize; @@ -248,13 +247,13 @@ status_t SPI_MasterTransferDMA(SPI_Type *base, spi_dma_handle_t *handle, spi_tra if (xfer->txData) { config.enableSrcIncrement = true; - config.srcAddr = (uint32_t)(xfer->txData); + config.srcAddr = (uint32_t)(xfer->txData); } else { /* Disable the source increasement and source set to dummyData */ config.enableSrcIncrement = false; - config.srcAddr = (uint32_t)(&s_dummyData); + config.srcAddr = (uint32_t)(&g_spiDummyData[SPI_GetInstance(base)]); } DMA_SubmitTransfer(handle->txHandle, &config, true); @@ -270,7 +269,7 @@ status_t SPI_MasterTransferDMA(SPI_Type *base, spi_dma_handle_t *handle, spi_tra /* Change the state of handle */ handle->transferSize = xfer->dataSize; - handle->state = kSPI_Busy; + handle->state = kSPI_Busy; /* Start Rx transfer if needed */ if (xfer->rxData) @@ -288,6 +287,15 @@ status_t SPI_MasterTransferDMA(SPI_Type *base, spi_dma_handle_t *handle, spi_tra return kStatus_Success; } +/*! + * brief Get the transferred bytes for SPI slave DMA. + * + * param base SPI peripheral base address. + * param handle SPI DMA handle pointer. + * param count Transferred bytes. + * retval kStatus_SPI_Success Succeed get the transfer count. + * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress. + */ status_t SPI_MasterTransferGetCountDMA(SPI_Type *base, spi_dma_handle_t *handle, size_t *count) { assert(handle); @@ -313,6 +321,12 @@ status_t SPI_MasterTransferGetCountDMA(SPI_Type *base, spi_dma_handle_t *handle, return status; } +/*! + * brief Abort a SPI transfer using DMA. + * + * param base SPI peripheral base address. + * param handle SPI DMA handle pointer. + */ void SPI_MasterTransferAbortDMA(SPI_Type *base, spi_dma_handle_t *handle) { assert(handle); @@ -327,5 +341,5 @@ void SPI_MasterTransferAbortDMA(SPI_Type *base, spi_dma_handle_t *handle) /* Set the handle state */ handle->txInProgress = false; handle->rxInProgress = false; - handle->state = kSPI_Idle; + handle->state = kSPI_Idle; } diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL43Z/drivers/fsl_spi_dma.h b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL43Z/drivers/fsl_spi_dma.h index 90c7c93fb6..4d9b6b3580 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL43Z/drivers/fsl_spi_dma.h +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL43Z/drivers/fsl_spi_dma.h @@ -1,31 +1,9 @@ /* * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP * All rights reserved. * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * o Redistributions of source code must retain the above copyright notice, this list - * of conditions and the following disclaimer. - * - * o 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. - * - * o Neither the name of Freescale Semiconductor, Inc. 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. + * SPDX-License-Identifier: BSD-3-Clause */ #ifndef _FSL_SPI_DMA_H_ #define _FSL_SPI_DMA_H_ @@ -38,11 +16,16 @@ * @{ */ - /******************************************************************************* * Definitions ******************************************************************************/ +/*! @name Driver version */ +/*@{*/ +/*! @brief SPI DMA driver version 2.0.4. */ +#define FSL_SPI_DMA_DRIVER_VERSION (MAKE_VERSION(2, 0, 4)) +/*@}*/ + typedef struct _spi_dma_handle spi_dma_handle_t; /*! @brief SPI DMA callback called at the end of transfer. */ @@ -55,7 +38,7 @@ struct _spi_dma_handle bool rxInProgress; /*!< Receive transfer finished */ dma_handle_t *txHandle; /*!< DMA handler for SPI send */ dma_handle_t *rxHandle; /*!< DMA handler for SPI receive */ - uint8_t bytesPerFrame; /*!< Bytes in a frame for SPI tranfer */ + uint8_t bytesPerFrame; /*!< Bytes in a frame for SPI transfer */ spi_dma_callback_t callback; /*!< Callback for SPI DMA transfer */ void *userData; /*!< User Data for SPI DMA callback */ uint32_t state; /*!< Internal state of SPI DMA transfer */