123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851 |
- /*
- * The Clear BSD License
- * 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 (subject to the limitations in the disclaimer below) 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 the copyright holder nor the names of its
- * contributors may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE.
- * 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.
- */
- #include "fsl_lpspi.h"
- /*******************************************************************************
- * Definitions
- ******************************************************************************/
- /* Component ID definition, used by tools. */
- #ifndef FSL_COMPONENT_ID
- #define FSL_COMPONENT_ID "platform.drivers.lpspi"
- #endif
- /*!
- * @brief Default watermark values.
- *
- * The default watermarks are set to zero.
- */
- enum _lpspi_default_watermarks
- {
- kLpspiDefaultTxWatermark = 0,
- kLpspiDefaultRxWatermark = 0,
- };
- /*! @brief Typedef for master interrupt handler. */
- typedef void (*lpspi_master_isr_t)(LPSPI_Type *base, lpspi_master_handle_t *handle);
- /*! @brief Typedef for slave interrupt handler. */
- typedef void (*lpspi_slave_isr_t)(LPSPI_Type *base, lpspi_slave_handle_t *handle);
- /*******************************************************************************
- * Prototypes
- ******************************************************************************/
- /*!
- * @brief Configures the LPSPI peripheral chip select polarity.
- *
- * This function takes in the desired peripheral chip select (Pcs) and it's corresponding desired polarity and
- * configures the Pcs signal to operate with the desired characteristic.
- *
- * @param base LPSPI peripheral address.
- * @param pcs The particular peripheral chip select (parameter value is of type lpspi_which_pcs_t) for which we wish to
- * apply the active high or active low characteristic.
- * @param activeLowOrHigh The setting for either "active high, inactive low (0)" or "active low, inactive high(1)" of
- * type lpspi_pcs_polarity_config_t.
- */
- static void LPSPI_SetOnePcsPolarity(LPSPI_Type *base,
- lpspi_which_pcs_t pcs,
- lpspi_pcs_polarity_config_t activeLowOrHigh);
- /*!
- * @brief Combine the write data for 1 byte to 4 bytes.
- * This is not a public API.
- */
- static uint32_t LPSPI_CombineWriteData(uint8_t *txData, uint32_t bytesEachWrite, bool isByteSwap);
- /*!
- * @brief Separate the read data for 1 byte to 4 bytes.
- * This is not a public API.
- */
- static void LPSPI_SeparateReadData(uint8_t *rxData, uint32_t readData, uint32_t bytesEachRead, bool isByteSwap);
- /*!
- * @brief Master fill up the TX FIFO with data.
- * This is not a public API.
- */
- static void LPSPI_MasterTransferFillUpTxFifo(LPSPI_Type *base, lpspi_master_handle_t *handle);
- /*!
- * @brief Master finish up a transfer.
- * It would call back if there is callback function and set the state to idle.
- * This is not a public API.
- */
- static void LPSPI_MasterTransferComplete(LPSPI_Type *base, lpspi_master_handle_t *handle);
- /*!
- * @brief Slave fill up the TX FIFO with data.
- * This is not a public API.
- */
- static void LPSPI_SlaveTransferFillUpTxFifo(LPSPI_Type *base, lpspi_slave_handle_t *handle);
- /*!
- * @brief Slave finish up a transfer.
- * It would call back if there is callback function and set the state to idle.
- * This is not a public API.
- */
- static void LPSPI_SlaveTransferComplete(LPSPI_Type *base, lpspi_slave_handle_t *handle);
- /*!
- * @brief LPSPI common interrupt handler.
- *
- * @param handle pointer to s_lpspiHandle which stores the transfer state.
- */
- static void LPSPI_CommonIRQHandler(LPSPI_Type *base, void *param);
- /*******************************************************************************
- * Variables
- ******************************************************************************/
- /* Defines constant value arrays for the baud rate pre-scalar and scalar divider values.*/
- static const uint8_t s_baudratePrescaler[] = {1, 2, 4, 8, 16, 32, 64, 128};
- /*! @brief Pointers to lpspi bases for each instance. */
- static LPSPI_Type *const s_lpspiBases[] = LPSPI_BASE_PTRS;
- /*! @brief Pointers to lpspi IRQ number for each instance. */
- static const IRQn_Type s_lpspiIRQ[] = LPSPI_IRQS;
- #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
- /*! @brief Pointers to lpspi clocks for each instance. */
- static const clock_ip_name_t s_lpspiClocks[] = LPSPI_CLOCKS;
- #if defined(LPSPI_PERIPH_CLOCKS)
- static const clock_ip_name_t s_LpspiPeriphClocks[] = LPSPI_PERIPH_CLOCKS;
- #endif
- #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
- /*! @brief Pointers to lpspi handles for each instance. */
- static void *s_lpspiHandle[ARRAY_SIZE(s_lpspiBases)] = {NULL};
- /*! @brief Pointer to master IRQ handler for each instance. */
- static lpspi_master_isr_t s_lpspiMasterIsr;
- /*! @brief Pointer to slave IRQ handler for each instance. */
- static lpspi_slave_isr_t s_lpspiSlaveIsr;
- /* @brief Dummy data for each instance. This data is used when user's tx buffer is NULL*/
- volatile uint8_t g_lpspiDummyData[ARRAY_SIZE(s_lpspiBases)] = {0};
- /**********************************************************************************************************************
- * Code
- *********************************************************************************************************************/
- uint32_t LPSPI_GetInstance(LPSPI_Type *base)
- {
- uint8_t instance = 0;
- /* Find the instance index from base address mappings. */
- for (instance = 0; instance < ARRAY_SIZE(s_lpspiBases); instance++)
- {
- if (s_lpspiBases[instance] == base)
- {
- break;
- }
- }
- assert(instance < ARRAY_SIZE(s_lpspiBases));
- return instance;
- }
- void LPSPI_SetDummyData(LPSPI_Type *base, uint8_t dummyData)
- {
- uint32_t instance = LPSPI_GetInstance(base);
- g_lpspiDummyData[instance] = dummyData;
- }
- void LPSPI_MasterInit(LPSPI_Type *base, const lpspi_master_config_t *masterConfig, uint32_t srcClock_Hz)
- {
- assert(masterConfig);
- uint32_t tcrPrescaleValue = 0;
- #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
- uint32_t instance = LPSPI_GetInstance(base);
- /* Enable LPSPI clock */
- CLOCK_EnableClock(s_lpspiClocks[instance]);
- #if defined(LPSPI_PERIPH_CLOCKS)
- CLOCK_EnableClock(s_LpspiPeriphClocks[instance]);
- #endif
- #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
- /* Reset to known status */
- LPSPI_Reset(base);
- /* Set LPSPI to master */
- LPSPI_SetMasterSlaveMode(base, kLPSPI_Master);
- /* Set specific PCS to active high or low */
- LPSPI_SetOnePcsPolarity(base, masterConfig->whichPcs, masterConfig->pcsActiveHighOrLow);
- /* Set Configuration Register 1 related setting.*/
- base->CFGR1 = (base->CFGR1 & ~(LPSPI_CFGR1_OUTCFG_MASK | LPSPI_CFGR1_PINCFG_MASK | LPSPI_CFGR1_NOSTALL_MASK)) |
- LPSPI_CFGR1_OUTCFG(masterConfig->dataOutConfig) | LPSPI_CFGR1_PINCFG(masterConfig->pinCfg) |
- LPSPI_CFGR1_NOSTALL(0);
- /* Set baudrate and delay times*/
- LPSPI_MasterSetBaudRate(base, masterConfig->baudRate, srcClock_Hz, &tcrPrescaleValue);
- /* Set default watermarks */
- LPSPI_SetFifoWatermarks(base, kLpspiDefaultTxWatermark, kLpspiDefaultRxWatermark);
- /* Set Transmit Command Register*/
- base->TCR = LPSPI_TCR_CPOL(masterConfig->cpol) | LPSPI_TCR_CPHA(masterConfig->cpha) |
- LPSPI_TCR_LSBF(masterConfig->direction) | LPSPI_TCR_FRAMESZ(masterConfig->bitsPerFrame - 1) |
- LPSPI_TCR_PRESCALE(tcrPrescaleValue) | LPSPI_TCR_PCS(masterConfig->whichPcs);
- LPSPI_Enable(base, true);
- LPSPI_MasterSetDelayTimes(base, masterConfig->pcsToSckDelayInNanoSec, kLPSPI_PcsToSck, srcClock_Hz);
- LPSPI_MasterSetDelayTimes(base, masterConfig->lastSckToPcsDelayInNanoSec, kLPSPI_LastSckToPcs, srcClock_Hz);
- LPSPI_MasterSetDelayTimes(base, masterConfig->betweenTransferDelayInNanoSec, kLPSPI_BetweenTransfer, srcClock_Hz);
- LPSPI_SetDummyData(base, LPSPI_DUMMY_DATA);
- }
- void LPSPI_MasterGetDefaultConfig(lpspi_master_config_t *masterConfig)
- {
- assert(masterConfig);
- masterConfig->baudRate = 500000;
- masterConfig->bitsPerFrame = 8;
- masterConfig->cpol = kLPSPI_ClockPolarityActiveHigh;
- masterConfig->cpha = kLPSPI_ClockPhaseFirstEdge;
- masterConfig->direction = kLPSPI_MsbFirst;
- masterConfig->pcsToSckDelayInNanoSec = 1000000000 / masterConfig->baudRate * 2;
- masterConfig->lastSckToPcsDelayInNanoSec = 1000000000 / masterConfig->baudRate * 2;
- masterConfig->betweenTransferDelayInNanoSec = 1000000000 / masterConfig->baudRate * 2;
- masterConfig->whichPcs = kLPSPI_Pcs0;
- masterConfig->pcsActiveHighOrLow = kLPSPI_PcsActiveLow;
- masterConfig->pinCfg = kLPSPI_SdiInSdoOut;
- masterConfig->dataOutConfig = kLpspiDataOutRetained;
- }
- void LPSPI_SlaveInit(LPSPI_Type *base, const lpspi_slave_config_t *slaveConfig)
- {
- assert(slaveConfig);
- #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
- uint32_t instance = LPSPI_GetInstance(base);
- /* Enable LPSPI clock */
- CLOCK_EnableClock(s_lpspiClocks[instance]);
- #if defined(LPSPI_PERIPH_CLOCKS)
- CLOCK_EnableClock(s_LpspiPeriphClocks[instance]);
- #endif
- #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
- /* Reset to known status */
- LPSPI_Reset(base);
- LPSPI_SetMasterSlaveMode(base, kLPSPI_Slave);
- LPSPI_SetOnePcsPolarity(base, slaveConfig->whichPcs, slaveConfig->pcsActiveHighOrLow);
- base->CFGR1 = (base->CFGR1 & ~(LPSPI_CFGR1_OUTCFG_MASK | LPSPI_CFGR1_PINCFG_MASK)) |
- LPSPI_CFGR1_OUTCFG(slaveConfig->dataOutConfig) | LPSPI_CFGR1_PINCFG(slaveConfig->pinCfg);
- LPSPI_SetFifoWatermarks(base, kLpspiDefaultTxWatermark, kLpspiDefaultRxWatermark);
- base->TCR = LPSPI_TCR_CPOL(slaveConfig->cpol) | LPSPI_TCR_CPHA(slaveConfig->cpha) |
- LPSPI_TCR_LSBF(slaveConfig->direction) | LPSPI_TCR_FRAMESZ(slaveConfig->bitsPerFrame - 1);
- /* This operation will set the dummy data for edma transfer, no effect in interrupt way. */
- LPSPI_SetDummyData(base, LPSPI_DUMMY_DATA);
- LPSPI_Enable(base, true);
- }
- void LPSPI_SlaveGetDefaultConfig(lpspi_slave_config_t *slaveConfig)
- {
- assert(slaveConfig);
- slaveConfig->bitsPerFrame = 8; /*!< Bits per frame, minimum 8, maximum 4096.*/
- slaveConfig->cpol = kLPSPI_ClockPolarityActiveHigh; /*!< Clock polarity. */
- slaveConfig->cpha = kLPSPI_ClockPhaseFirstEdge; /*!< Clock phase. */
- slaveConfig->direction = kLPSPI_MsbFirst; /*!< MSB or LSB data shift direction. */
- slaveConfig->whichPcs = kLPSPI_Pcs0; /*!< Desired Peripheral Chip Select (pcs) */
- slaveConfig->pcsActiveHighOrLow = kLPSPI_PcsActiveLow; /*!< Desired PCS active high or low */
- slaveConfig->pinCfg = kLPSPI_SdiInSdoOut;
- slaveConfig->dataOutConfig = kLpspiDataOutRetained;
- }
- void LPSPI_Reset(LPSPI_Type *base)
- {
- /* Reset all internal logic and registers, except the Control Register. Remains set until cleared by software.*/
- base->CR |= LPSPI_CR_RST_MASK;
- /* Software reset doesn't reset the CR, so manual reset the FIFOs */
- base->CR |= LPSPI_CR_RRF_MASK | LPSPI_CR_RTF_MASK;
- /* Master logic is not reset and module is disabled.*/
- base->CR = 0x00U;
- }
- void LPSPI_Deinit(LPSPI_Type *base)
- {
- /* Reset to default value */
- LPSPI_Reset(base);
- #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
- uint32_t instance = LPSPI_GetInstance(base);
- /* Enable LPSPI clock */
- CLOCK_DisableClock(s_lpspiClocks[instance]);
- #if defined(LPSPI_PERIPH_CLOCKS)
- CLOCK_DisableClock(s_LpspiPeriphClocks[instance]);
- #endif
- #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
- }
- static void LPSPI_SetOnePcsPolarity(LPSPI_Type *base,
- lpspi_which_pcs_t pcs,
- lpspi_pcs_polarity_config_t activeLowOrHigh)
- {
- uint32_t cfgr1Value = 0;
- /* Clear the PCS polarity bit */
- cfgr1Value = base->CFGR1 & ~(1U << (LPSPI_CFGR1_PCSPOL_SHIFT + pcs));
- /* Configure the PCS polarity bit according to the activeLowOrHigh setting */
- base->CFGR1 = cfgr1Value | ((uint32_t)activeLowOrHigh << (LPSPI_CFGR1_PCSPOL_SHIFT + pcs));
- }
- uint32_t LPSPI_MasterSetBaudRate(LPSPI_Type *base,
- uint32_t baudRate_Bps,
- uint32_t srcClock_Hz,
- uint32_t *tcrPrescaleValue)
- {
- assert(tcrPrescaleValue);
- /* For master mode configuration only, if slave mode detected, return 0.
- * Also, the LPSPI module needs to be disabled first, if enabled, return 0
- */
- if ((!LPSPI_IsMaster(base)) || (base->CR & LPSPI_CR_MEN_MASK))
- {
- return 0;
- }
- uint32_t prescaler, bestPrescaler;
- uint32_t scaler, bestScaler;
- uint32_t realBaudrate, bestBaudrate;
- uint32_t diff, min_diff;
- uint32_t desiredBaudrate = baudRate_Bps;
- /* find combination of prescaler and scaler resulting in baudrate closest to the
- * requested value
- */
- min_diff = 0xFFFFFFFFU;
- /* Set to maximum divisor value bit settings so that if baud rate passed in is less
- * than the minimum possible baud rate, then the SPI will be configured to the lowest
- * possible baud rate
- */
- bestPrescaler = 7;
- bestScaler = 255;
- bestBaudrate = 0; /* required to avoid compilation warning */
- /* In all for loops, if min_diff = 0, the exit for loop*/
- for (prescaler = 0; (prescaler < 8) && min_diff; prescaler++)
- {
- for (scaler = 0; (scaler < 256) && min_diff; scaler++)
- {
- realBaudrate = (srcClock_Hz / (s_baudratePrescaler[prescaler] * (scaler + 2U)));
- /* calculate the baud rate difference based on the conditional statement
- * that states that the calculated baud rate must not exceed the desired baud rate
- */
- if (desiredBaudrate >= realBaudrate)
- {
- diff = desiredBaudrate - realBaudrate;
- if (min_diff > diff)
- {
- /* a better match found */
- min_diff = diff;
- bestPrescaler = prescaler;
- bestScaler = scaler;
- bestBaudrate = realBaudrate;
- }
- }
- }
- }
- /* Write the best baud rate scalar to the CCR.
- * Note, no need to check for error since we've already checked to make sure the module is
- * disabled and in master mode. Also, there is a limit on the maximum divider so we will not
- * exceed this.
- */
- base->CCR = (base->CCR & ~LPSPI_CCR_SCKDIV_MASK) | LPSPI_CCR_SCKDIV(bestScaler);
- /* return the best prescaler value for user to use later */
- *tcrPrescaleValue = bestPrescaler;
- /* return the actual calculated baud rate */
- return bestBaudrate;
- }
- void LPSPI_MasterSetDelayScaler(LPSPI_Type *base, uint32_t scaler, lpspi_delay_type_t whichDelay)
- {
- /*These settings are only relevant in master mode */
- switch (whichDelay)
- {
- case kLPSPI_PcsToSck:
- base->CCR = (base->CCR & (~LPSPI_CCR_PCSSCK_MASK)) | LPSPI_CCR_PCSSCK(scaler);
- break;
- case kLPSPI_LastSckToPcs:
- base->CCR = (base->CCR & (~LPSPI_CCR_SCKPCS_MASK)) | LPSPI_CCR_SCKPCS(scaler);
- break;
- case kLPSPI_BetweenTransfer:
- base->CCR = (base->CCR & (~LPSPI_CCR_DBT_MASK)) | LPSPI_CCR_DBT(scaler);
- break;
- default:
- assert(false);
- break;
- }
- }
- uint32_t LPSPI_MasterSetDelayTimes(LPSPI_Type *base,
- uint32_t delayTimeInNanoSec,
- lpspi_delay_type_t whichDelay,
- uint32_t srcClock_Hz)
- {
- uint64_t realDelay, bestDelay;
- uint32_t scaler, bestScaler;
- uint32_t diff, min_diff;
- uint64_t initialDelayNanoSec;
- uint32_t clockDividedPrescaler;
- /* For delay between transfer, an additional scaler value is needed */
- uint32_t additionalScaler = 0;
- /*As the RM note, the LPSPI baud rate clock is itself divided by the PRESCALE setting, which can vary between
- * transfers.*/
- clockDividedPrescaler =
- srcClock_Hz / s_baudratePrescaler[(base->TCR & LPSPI_TCR_PRESCALE_MASK) >> LPSPI_TCR_PRESCALE_SHIFT];
- /* Find combination of prescaler and scaler resulting in the delay closest to the requested value.*/
- min_diff = 0xFFFFFFFFU;
- /* Initialize scaler to max value to generate the max delay */
- bestScaler = 0xFFU;
- /* Calculate the initial (min) delay and maximum possible delay based on the specific delay as
- * the delay divisors are slightly different based on which delay we are configuring.
- */
- if (whichDelay == kLPSPI_BetweenTransfer)
- {
- /* First calculate the initial, default delay, note min delay is 2 clock cycles. Due to large size of
- calculated values (uint64_t), we need to break up the calculation into several steps to ensure
- accurate calculated results
- */
- initialDelayNanoSec = 1000000000U;
- initialDelayNanoSec *= 2U;
- initialDelayNanoSec /= clockDividedPrescaler;
- /* Calculate the maximum delay */
- bestDelay = 1000000000U;
- bestDelay *= 257U; /* based on DBT+2, or 255 + 2 */
- bestDelay /= clockDividedPrescaler;
- additionalScaler = 1U;
- }
- else
- {
- /* First calculate the initial, default delay, min delay is 1 clock cycle. Due to large size of calculated
- values (uint64_t), we need to break up the calculation into several steps to ensure accurate calculated
- results.
- */
- initialDelayNanoSec = 1000000000U;
- initialDelayNanoSec /= clockDividedPrescaler;
- /* Calculate the maximum delay */
- bestDelay = 1000000000U;
- bestDelay *= 256U; /* based on SCKPCS+1 or PCSSCK+1, or 255 + 1 */
- bestDelay /= clockDividedPrescaler;
- additionalScaler = 0;
- }
- /* If the initial, default delay is already greater than the desired delay, then
- * set the delay to their initial value (0) and return the delay. In other words,
- * there is no way to decrease the delay value further.
- */
- if (initialDelayNanoSec >= delayTimeInNanoSec)
- {
- LPSPI_MasterSetDelayScaler(base, 0, whichDelay);
- return initialDelayNanoSec;
- }
- /* If min_diff = 0, the exit for loop */
- for (scaler = 0; (scaler < 256U) && min_diff; scaler++)
- {
- /* Calculate the real delay value as we cycle through the scaler values.
- Due to large size of calculated values (uint64_t), we need to break up the
- calculation into several steps to ensure accurate calculated results
- */
- realDelay = 1000000000U;
- realDelay *= (scaler + 1 + additionalScaler);
- realDelay /= clockDividedPrescaler;
- /* calculate the delay difference based on the conditional statement
- * that states that the calculated delay must not be less then the desired delay
- */
- if (realDelay >= delayTimeInNanoSec)
- {
- diff = realDelay - delayTimeInNanoSec;
- if (min_diff > diff)
- {
- /* a better match found */
- min_diff = diff;
- bestScaler = scaler;
- bestDelay = realDelay;
- }
- }
- }
- /* write the best scaler value for the delay */
- LPSPI_MasterSetDelayScaler(base, bestScaler, whichDelay);
- /* return the actual calculated delay value (in ns) */
- return bestDelay;
- }
- /*Transactional APIs -- Master*/
- void LPSPI_MasterTransferCreateHandle(LPSPI_Type *base,
- lpspi_master_handle_t *handle,
- lpspi_master_transfer_callback_t callback,
- void *userData)
- {
- assert(handle);
- /* Zero the handle. */
- memset(handle, 0, sizeof(*handle));
- s_lpspiHandle[LPSPI_GetInstance(base)] = handle;
- /* Set irq handler. */
- s_lpspiMasterIsr = LPSPI_MasterTransferHandleIRQ;
- handle->callback = callback;
- handle->userData = userData;
- }
- bool LPSPI_CheckTransferArgument(lpspi_transfer_t *transfer, uint32_t bitsPerFrame, uint32_t bytesPerFrame)
- {
- assert(transfer);
- /* If the transfer count is zero, then return immediately.*/
- if (transfer->dataSize == 0)
- {
- return false;
- }
- /* If both send buffer and receive buffer is null */
- if ((!(transfer->txData)) && (!(transfer->rxData)))
- {
- return false;
- }
- /*The transfer data size should be integer multiples of bytesPerFrame if bytesPerFrame is less than or equal to 4 .
- *For bytesPerFrame greater than 4 situation:
- *the transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not integer multiples of 4 ,
- *otherwise , the transfer data size can be integer multiples of bytesPerFrame.
- */
- if (bytesPerFrame <= 4)
- {
- if ((transfer->dataSize % bytesPerFrame) != 0)
- {
- return false;
- }
- }
- else
- {
- if ((bytesPerFrame % 4U) != 0)
- {
- if (transfer->dataSize != bytesPerFrame)
- {
- return false;
- }
- }
- else
- {
- if ((transfer->dataSize % bytesPerFrame) != 0)
- {
- return false;
- }
- }
- }
- return true;
- }
- status_t LPSPI_MasterTransferBlocking(LPSPI_Type *base, lpspi_transfer_t *transfer)
- {
- assert(transfer);
- uint32_t bitsPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) + 1;
- uint32_t bytesPerFrame = (bitsPerFrame + 7) / 8;
- uint32_t temp = 0U;
- uint8_t dummyData = g_lpspiDummyData[LPSPI_GetInstance(base)];
- if (!LPSPI_CheckTransferArgument(transfer, bitsPerFrame, bytesPerFrame))
- {
- return kStatus_InvalidArgument;
- }
- /* Check that LPSPI is not busy.*/
- if (LPSPI_GetStatusFlags(base) & kLPSPI_ModuleBusyFlag)
- {
- return kStatus_LPSPI_Busy;
- }
- uint8_t *txData = transfer->txData;
- uint8_t *rxData = transfer->rxData;
- uint32_t txRemainingByteCount = transfer->dataSize;
- uint32_t rxRemainingByteCount = transfer->dataSize;
- uint8_t bytesEachWrite;
- uint8_t bytesEachRead;
- uint32_t readData = 0;
- uint32_t wordToSend =
- ((uint32_t)dummyData) | ((uint32_t)dummyData << 8) | ((uint32_t)dummyData << 16) | ((uint32_t)dummyData << 24);
- /*The TX and RX FIFO sizes are always the same*/
- uint32_t fifoSize = LPSPI_GetRxFifoSize(base);
- uint32_t whichPcs = (transfer->configFlags & LPSPI_MASTER_PCS_MASK) >> LPSPI_MASTER_PCS_SHIFT;
- bool isPcsContinuous = (bool)(transfer->configFlags & kLPSPI_MasterPcsContinuous);
- bool isRxMask = false;
- bool isByteSwap = (bool)(transfer->configFlags & kLPSPI_MasterByteSwap);
- LPSPI_FlushFifo(base, true, true);
- LPSPI_ClearStatusFlags(base, kLPSPI_AllStatusFlag);
- if (!rxData)
- {
- isRxMask = true;
- }
- LPSPI_Enable(base, false);
- base->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK);
- /* Check if using 3-wire mode and the txData is NULL, set the output pin to tristated. */
- temp = base->CFGR1;
- temp &= LPSPI_CFGR1_PINCFG_MASK;
- if ((temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdiInSdiOut)) || (temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdoInSdoOut)))
- {
- if (!txData)
- {
- base->CFGR1 |= LPSPI_CFGR1_OUTCFG_MASK;
- }
- /* The 3-wire mode can't send and receive data at the same time. */
- if ((txData) && (rxData))
- {
- return kStatus_InvalidArgument;
- }
- }
- LPSPI_Enable(base, true);
- base->TCR =
- (base->TCR & ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_RXMSK_MASK | LPSPI_TCR_PCS_MASK)) |
- LPSPI_TCR_CONT(isPcsContinuous) | LPSPI_TCR_CONTC(0) | LPSPI_TCR_RXMSK(isRxMask) | LPSPI_TCR_PCS(whichPcs);
- if (bytesPerFrame <= 4)
- {
- bytesEachWrite = bytesPerFrame;
- bytesEachRead = bytesPerFrame;
- }
- else
- {
- bytesEachWrite = 4;
- bytesEachRead = 4;
- }
- /*Write the TX data until txRemainingByteCount is equal to 0 */
- while (txRemainingByteCount > 0)
- {
- if (txRemainingByteCount < bytesEachWrite)
- {
- bytesEachWrite = txRemainingByteCount;
- }
- /*Wait until TX FIFO is not full*/
- while (LPSPI_GetTxFifoCount(base) == fifoSize)
- {
- }
- if (txData)
- {
- wordToSend = LPSPI_CombineWriteData(txData, bytesEachWrite, isByteSwap);
- txData += bytesEachWrite;
- }
- LPSPI_WriteData(base, wordToSend);
- txRemainingByteCount -= bytesEachWrite;
- /*Check whether there is RX data in RX FIFO . Read out the RX data so that the RX FIFO would not overrun.*/
- if (rxData)
- {
- while (LPSPI_GetRxFifoCount(base))
- {
- readData = LPSPI_ReadData(base);
- if (rxRemainingByteCount < bytesEachRead)
- {
- bytesEachRead = rxRemainingByteCount;
- }
- LPSPI_SeparateReadData(rxData, readData, bytesEachRead, isByteSwap);
- rxData += bytesEachRead;
- rxRemainingByteCount -= bytesEachRead;
- }
- }
- }
- /* After write all the data in TX FIFO , should write the TCR_CONTC to 0 to de-assert the PCS. Note that TCR
- * register also use the TX FIFO.
- */
- while ((LPSPI_GetTxFifoCount(base) == fifoSize))
- {
- }
- base->TCR = (base->TCR & ~(LPSPI_TCR_CONTC_MASK));
- /*Read out the RX data in FIFO*/
- if (rxData)
- {
- while (rxRemainingByteCount > 0)
- {
- while (LPSPI_GetRxFifoCount(base))
- {
- readData = LPSPI_ReadData(base);
- if (rxRemainingByteCount < bytesEachRead)
- {
- bytesEachRead = rxRemainingByteCount;
- }
- LPSPI_SeparateReadData(rxData, readData, bytesEachRead, isByteSwap);
- rxData += bytesEachRead;
- rxRemainingByteCount -= bytesEachRead;
- }
- }
- }
- else
- {
- /* If no RX buffer, then transfer is not complete until transfer complete flag sets */
- while (!(LPSPI_GetStatusFlags(base) & kLPSPI_TransferCompleteFlag))
- {
- }
- }
- return kStatus_Success;
- }
- status_t LPSPI_MasterTransferNonBlocking(LPSPI_Type *base, lpspi_master_handle_t *handle, lpspi_transfer_t *transfer)
- {
- assert(handle);
- assert(transfer);
- uint32_t bitsPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) + 1;
- uint32_t bytesPerFrame = (bitsPerFrame + 7) / 8;
- uint32_t temp = 0U;
- uint8_t dummyData = g_lpspiDummyData[LPSPI_GetInstance(base)];
- if (!LPSPI_CheckTransferArgument(transfer, bitsPerFrame, bytesPerFrame))
- {
- return kStatus_InvalidArgument;
- }
- /* Check that we're not busy.*/
- if (handle->state == kLPSPI_Busy)
- {
- return kStatus_LPSPI_Busy;
- }
- handle->state = kLPSPI_Busy;
- bool isRxMask = false;
- uint8_t txWatermark;
- uint32_t whichPcs = (transfer->configFlags & LPSPI_MASTER_PCS_MASK) >> LPSPI_MASTER_PCS_SHIFT;
- handle->txData = transfer->txData;
- handle->rxData = transfer->rxData;
- handle->txRemainingByteCount = transfer->dataSize;
- handle->rxRemainingByteCount = transfer->dataSize;
- handle->totalByteCount = transfer->dataSize;
- handle->writeTcrInIsr = false;
- handle->writeRegRemainingTimes = (transfer->dataSize / bytesPerFrame) * ((bytesPerFrame + 3) / 4);
- handle->readRegRemainingTimes = handle->writeRegRemainingTimes;
- handle->txBuffIfNull =
- ((uint32_t)dummyData) | ((uint32_t)dummyData << 8) | ((uint32_t)dummyData << 16) | ((uint32_t)dummyData << 24);
- /*The TX and RX FIFO sizes are always the same*/
- handle->fifoSize = LPSPI_GetRxFifoSize(base);
- handle->isPcsContinuous = (bool)(transfer->configFlags & kLPSPI_MasterPcsContinuous);
- handle->isByteSwap = (bool)(transfer->configFlags & kLPSPI_MasterByteSwap);
- /*Set the RX and TX watermarks to reduce the ISR times.*/
- if (handle->fifoSize > 1)
- {
- txWatermark = 1;
- handle->rxWatermark = handle->fifoSize - 2;
- }
- else
- {
- txWatermark = 0;
- handle->rxWatermark = 0;
- }
- LPSPI_SetFifoWatermarks(base, txWatermark, handle->rxWatermark);
- LPSPI_Enable(base, false);
- /*Transfers will stall when transmit FIFO is empty or receive FIFO is full. */
- base->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK);
- /* Check if using 3-wire mode and the txData is NULL, set the output pin to tristated. */
- temp = base->CFGR1;
- temp &= LPSPI_CFGR1_PINCFG_MASK;
- if ((temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdiInSdiOut)) || (temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdoInSdoOut)))
- {
- if (!handle->txData)
- {
- base->CFGR1 |= LPSPI_CFGR1_OUTCFG_MASK;
- }
- /* The 3-wire mode can't send and receive data at the same time. */
- if ((handle->txData) && (handle->rxData))
- {
- return kStatus_InvalidArgument;
- }
- }
- LPSPI_Enable(base, true);
- /*Flush FIFO , clear status , disable all the inerrupts.*/
- LPSPI_FlushFifo(base, true, true);
- LPSPI_ClearStatusFlags(base, kLPSPI_AllStatusFlag);
- LPSPI_DisableInterrupts(base, kLPSPI_AllInterruptEnable);
- /* If there is not rxData , can mask the receive data (receive data is not stored in receive FIFO).
- * For master transfer , we'd better not masked the transmit data in TCR since the transfer flow is hard to
- * controlled by software.*/
- if (handle->rxData == NULL)
- {
- isRxMask = true;
- handle->rxRemainingByteCount = 0;
- }
- base->TCR =
- (base->TCR & ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_RXMSK_MASK | LPSPI_TCR_PCS_MASK)) |
- LPSPI_TCR_CONT(handle->isPcsContinuous) | LPSPI_TCR_CONTC(0) | LPSPI_TCR_RXMSK(isRxMask) |
- LPSPI_TCR_PCS(whichPcs);
- /*Calculate the bytes for write/read the TX/RX register each time*/
- if (bytesPerFrame <= 4)
- {
- handle->bytesEachWrite = bytesPerFrame;
- handle->bytesEachRead = bytesPerFrame;
- }
- else
- {
- handle->bytesEachWrite = 4;
- handle->bytesEachRead = 4;
- }
- /* Enable the NVIC for LPSPI peripheral. Note that below code is useless if the LPSPI interrupt is in INTMUX ,
- * and you should also enable the INTMUX interupt in your application.
- */
- EnableIRQ(s_lpspiIRQ[LPSPI_GetInstance(base)]);
- /*TCR is also shared the FIFO , so wait for TCR written.*/
- while (LPSPI_GetTxFifoCount(base) != 0)
- {
- }
- /*Fill up the TX data in FIFO */
- LPSPI_MasterTransferFillUpTxFifo(base, handle);
- /* Since SPI is a synchronous interface, we only need to enable the RX interrupt if there is RX data.
- * The IRQ handler will get the status of RX and TX interrupt flags.
- */
- if (handle->rxData)
- {
- /*Set rxWatermark to (readRegRemainingTimes-1) if readRegRemainingTimes less than rxWatermark. Otherwise there
- *is not RX interrupt for the last datas because the RX count is not greater than rxWatermark.
- */
- if ((handle->readRegRemainingTimes) <= handle->rxWatermark)
- {
- base->FCR = (base->FCR & (~LPSPI_FCR_RXWATER_MASK)) | LPSPI_FCR_RXWATER(handle->readRegRemainingTimes - 1);
- }
- LPSPI_EnableInterrupts(base, kLPSPI_RxInterruptEnable);
- }
- else
- {
- LPSPI_EnableInterrupts(base, kLPSPI_TxInterruptEnable);
- }
- return kStatus_Success;
- }
- static void LPSPI_MasterTransferFillUpTxFifo(LPSPI_Type *base, lpspi_master_handle_t *handle)
- {
- assert(handle);
- uint32_t wordToSend = 0;
- /* Make sure the difference in remaining TX and RX byte counts does not exceed FIFO depth
- * and that the number of TX FIFO entries does not exceed the FIFO depth.
- * But no need to make the protection if there is no rxData.
- */
- while ((LPSPI_GetTxFifoCount(base) < (handle->fifoSize)) &&
- (((handle->readRegRemainingTimes - handle->writeRegRemainingTimes) < handle->fifoSize) ||
- (handle->rxData == NULL)))
- {
- if (handle->txRemainingByteCount < handle->bytesEachWrite)
- {
- handle->bytesEachWrite = handle->txRemainingByteCount;
- }
- if (handle->txData)
- {
- wordToSend = LPSPI_CombineWriteData(handle->txData, handle->bytesEachWrite, handle->isByteSwap);
- handle->txData += handle->bytesEachWrite;
- }
- else
- {
- wordToSend = handle->txBuffIfNull;
- }
- /*Write the word to TX register*/
- LPSPI_WriteData(base, wordToSend);
- /*Decrease the write TX register times.*/
- --handle->writeRegRemainingTimes;
- /*Decrease the remaining TX byte count.*/
- handle->txRemainingByteCount -= handle->bytesEachWrite;
- if (handle->txRemainingByteCount == 0)
- {
- /* If PCS is continuous, update TCR to de-assert PCS */
- if (handle->isPcsContinuous)
- {
- /* Only write to the TCR if the FIFO has room */
- if ((LPSPI_GetTxFifoCount(base) < (handle->fifoSize)))
- {
- base->TCR = (base->TCR & ~(LPSPI_TCR_CONTC_MASK));
- handle->writeTcrInIsr = false;
- }
- /* Else, set a global flag to tell the ISR to do write to the TCR */
- else
- {
- handle->writeTcrInIsr = true;
- }
- }
- break;
- }
- }
- }
- static void LPSPI_MasterTransferComplete(LPSPI_Type *base, lpspi_master_handle_t *handle)
- {
- assert(handle);
- /* Disable interrupt requests*/
- LPSPI_DisableInterrupts(base, kLPSPI_AllInterruptEnable);
- handle->state = kLPSPI_Idle;
- if (handle->callback)
- {
- handle->callback(base, handle, kStatus_Success, handle->userData);
- }
- }
- status_t LPSPI_MasterTransferGetCount(LPSPI_Type *base, lpspi_master_handle_t *handle, size_t *count)
- {
- assert(handle);
- if (!count)
- {
- return kStatus_InvalidArgument;
- }
- /* Catch when there is not an active transfer. */
- if (handle->state != kLPSPI_Busy)
- {
- *count = 0;
- return kStatus_NoTransferInProgress;
- }
- size_t remainingByte;
- if (handle->rxData)
- {
- remainingByte = handle->rxRemainingByteCount;
- }
- else
- {
- remainingByte = handle->txRemainingByteCount;
- }
- *count = handle->totalByteCount - remainingByte;
- return kStatus_Success;
- }
- void LPSPI_MasterTransferAbort(LPSPI_Type *base, lpspi_master_handle_t *handle)
- {
- assert(handle);
- /* Disable interrupt requests*/
- LPSPI_DisableInterrupts(base, kLPSPI_AllInterruptEnable);
- LPSPI_Reset(base);
- handle->state = kLPSPI_Idle;
- handle->txRemainingByteCount = 0;
- handle->rxRemainingByteCount = 0;
- }
- void LPSPI_MasterTransferHandleIRQ(LPSPI_Type *base, lpspi_master_handle_t *handle)
- {
- assert(handle);
- uint32_t readData;
- if (handle->rxData != NULL)
- {
- if (handle->rxRemainingByteCount)
- {
- /* First, disable the interrupts to avoid potentially triggering another interrupt
- * while reading out the RX FIFO as more data may be coming into the RX FIFO. We'll
- * re-enable the interrupts based on the LPSPI state after reading out the FIFO.
- */
- LPSPI_DisableInterrupts(base, kLPSPI_RxInterruptEnable);
- while ((LPSPI_GetRxFifoCount(base)) && (handle->rxRemainingByteCount))
- {
- /*Read out the data*/
- readData = LPSPI_ReadData(base);
- /*Decrease the read RX register times.*/
- --handle->readRegRemainingTimes;
- if (handle->rxRemainingByteCount < handle->bytesEachRead)
- {
- handle->bytesEachRead = handle->rxRemainingByteCount;
- }
- LPSPI_SeparateReadData(handle->rxData, readData, handle->bytesEachRead, handle->isByteSwap);
- handle->rxData += handle->bytesEachRead;
- /*Decrease the remaining RX byte count.*/
- handle->rxRemainingByteCount -= handle->bytesEachRead;
- }
- /* Re-enable the interrupts only if rxCount indicates there is more data to receive,
- * else we may get a spurious interrupt.
- * */
- if (handle->rxRemainingByteCount)
- {
- /* Set the TDF and RDF interrupt enables simultaneously to avoid race conditions */
- LPSPI_EnableInterrupts(base, kLPSPI_RxInterruptEnable);
- }
- }
- /*Set rxWatermark to (readRegRemainingTimes-1) if readRegRemainingTimes less than rxWatermark. Otherwise there
- *is not RX interrupt for the last datas because the RX count is not greater than rxWatermark.
- */
- if ((handle->readRegRemainingTimes) <= (handle->rxWatermark))
- {
- base->FCR =
- (base->FCR & (~LPSPI_FCR_RXWATER_MASK)) |
- LPSPI_FCR_RXWATER((handle->readRegRemainingTimes > 1) ? (handle->readRegRemainingTimes - 1U) : (0U));
- }
- }
- if (handle->txRemainingByteCount)
- {
- LPSPI_MasterTransferFillUpTxFifo(base, handle);
- }
- else
- {
- if ((LPSPI_GetTxFifoCount(base) < (handle->fifoSize)))
- {
- if ((handle->isPcsContinuous) && (handle->writeTcrInIsr))
- {
- base->TCR = (base->TCR & ~(LPSPI_TCR_CONTC_MASK));
- handle->writeTcrInIsr = false;
- }
- }
- }
- if ((handle->txRemainingByteCount == 0) && (handle->rxRemainingByteCount == 0) && (!handle->writeTcrInIsr))
- {
- /* If no RX buffer, then transfer is not complete until transfer complete flag sets */
- if (handle->rxData == NULL)
- {
- if (LPSPI_GetStatusFlags(base) & kLPSPI_TransferCompleteFlag)
- {
- /* Complete the transfer and disable the interrupts */
- LPSPI_MasterTransferComplete(base, handle);
- }
- else
- {
- LPSPI_EnableInterrupts(base, kLPSPI_TransferCompleteInterruptEnable);
- LPSPI_DisableInterrupts(base, kLPSPI_TxInterruptEnable | kLPSPI_RxInterruptEnable);
- }
- }
- else
- {
- /* Complete the transfer and disable the interrupts */
- LPSPI_MasterTransferComplete(base, handle);
- }
- }
- }
- /*Transactional APIs -- Slave*/
- void LPSPI_SlaveTransferCreateHandle(LPSPI_Type *base,
- lpspi_slave_handle_t *handle,
- lpspi_slave_transfer_callback_t callback,
- void *userData)
- {
- assert(handle);
- /* Zero the handle. */
- memset(handle, 0, sizeof(*handle));
- s_lpspiHandle[LPSPI_GetInstance(base)] = handle;
- /* Set irq handler. */
- s_lpspiSlaveIsr = LPSPI_SlaveTransferHandleIRQ;
- handle->callback = callback;
- handle->userData = userData;
- }
- status_t LPSPI_SlaveTransferNonBlocking(LPSPI_Type *base, lpspi_slave_handle_t *handle, lpspi_transfer_t *transfer)
- {
- assert(handle);
- assert(transfer);
- uint32_t bitsPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) + 1;
- uint32_t bytesPerFrame = (bitsPerFrame + 7) / 8;
- uint32_t temp = 0U;
- if (!LPSPI_CheckTransferArgument(transfer, bitsPerFrame, bytesPerFrame))
- {
- return kStatus_InvalidArgument;
- }
- /* Check that we're not busy.*/
- if (handle->state == kLPSPI_Busy)
- {
- return kStatus_LPSPI_Busy;
- }
- handle->state = kLPSPI_Busy;
- bool isRxMask = false;
- bool isTxMask = false;
- uint32_t whichPcs = (transfer->configFlags & LPSPI_SLAVE_PCS_MASK) >> LPSPI_SLAVE_PCS_SHIFT;
- handle->txData = transfer->txData;
- handle->rxData = transfer->rxData;
- handle->txRemainingByteCount = transfer->dataSize;
- handle->rxRemainingByteCount = transfer->dataSize;
- handle->totalByteCount = transfer->dataSize;
- handle->writeRegRemainingTimes = (transfer->dataSize / bytesPerFrame) * ((bytesPerFrame + 3) / 4);
- handle->readRegRemainingTimes = handle->writeRegRemainingTimes;
- /*The TX and RX FIFO sizes are always the same*/
- handle->fifoSize = LPSPI_GetRxFifoSize(base);
- handle->isByteSwap = (bool)(transfer->configFlags & kLPSPI_SlaveByteSwap);
- /*Set the RX and TX watermarks to reduce the ISR times.*/
- uint8_t txWatermark;
- if (handle->fifoSize > 1)
- {
- txWatermark = 1;
- handle->rxWatermark = handle->fifoSize - 2;
- }
- else
- {
- txWatermark = 0;
- handle->rxWatermark = 0;
- }
- LPSPI_SetFifoWatermarks(base, txWatermark, handle->rxWatermark);
- /* Check if using 3-wire mode and the txData is NULL, set the output pin to tristated. */
- temp = base->CFGR1;
- temp &= LPSPI_CFGR1_PINCFG_MASK;
- if ((temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdiInSdiOut)) || (temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdoInSdoOut)))
- {
- if (!handle->txData)
- {
- LPSPI_Enable(base, false);
- base->CFGR1 |= LPSPI_CFGR1_OUTCFG_MASK;
- LPSPI_Enable(base, true);
- }
- /* The 3-wire mode can't send and receive data at the same time. */
- if ((handle->txData) && (handle->rxData))
- {
- return kStatus_InvalidArgument;
- }
- }
- /*Flush FIFO , clear status , disable all the inerrupts.*/
- LPSPI_FlushFifo(base, true, true);
- LPSPI_ClearStatusFlags(base, kLPSPI_AllStatusFlag);
- LPSPI_DisableInterrupts(base, kLPSPI_AllInterruptEnable);
- /*If there is not rxData , can mask the receive data (receive data is not stored in receive FIFO).*/
- if (handle->rxData == NULL)
- {
- isRxMask = true;
- handle->rxRemainingByteCount = 0;
- }
- /*If there is not txData , can mask the transmit data (no data is loaded from transmit FIFO and output pin
- * is tristated).
- */
- if (handle->txData == NULL)
- {
- isTxMask = true;
- handle->txRemainingByteCount = 0;
- }
- base->TCR = (base->TCR &
- ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_RXMSK_MASK | LPSPI_TCR_TXMSK_MASK |
- LPSPI_TCR_PCS_MASK)) |
- LPSPI_TCR_CONT(0) | LPSPI_TCR_CONTC(0) | LPSPI_TCR_RXMSK(isRxMask) | LPSPI_TCR_TXMSK(isTxMask) |
- LPSPI_TCR_PCS(whichPcs);
- /*Calculate the bytes for write/read the TX/RX register each time*/
- if (bytesPerFrame <= 4)
- {
- handle->bytesEachWrite = bytesPerFrame;
- handle->bytesEachRead = bytesPerFrame;
- }
- else
- {
- handle->bytesEachWrite = 4;
- handle->bytesEachRead = 4;
- }
- /* Enable the NVIC for LPSPI peripheral. Note that below code is useless if the LPSPI interrupt is in INTMUX ,
- * and you should also enable the INTMUX interupt in your application.
- */
- EnableIRQ(s_lpspiIRQ[LPSPI_GetInstance(base)]);
- /*TCR is also shared the FIFO , so wait for TCR written.*/
- while (LPSPI_GetTxFifoCount(base) != 0)
- {
- }
- /*Fill up the TX data in FIFO */
- if (handle->txData)
- {
- LPSPI_SlaveTransferFillUpTxFifo(base, handle);
- }
- /* Since SPI is a synchronous interface, we only need to enable the RX interrupt if there is RX data.
- * The IRQ handler will get the status of RX and TX interrupt flags.
- */
- if (handle->rxData)
- {
- /*Set rxWatermark to (readRegRemainingTimes-1) if readRegRemainingTimes less than rxWatermark. Otherwise there
- *is not RX interrupt for the last datas because the RX count is not greater than rxWatermark.
- */
- if ((handle->readRegRemainingTimes) <= handle->rxWatermark)
- {
- base->FCR = (base->FCR & (~LPSPI_FCR_RXWATER_MASK)) | LPSPI_FCR_RXWATER(handle->readRegRemainingTimes - 1);
- }
- LPSPI_EnableInterrupts(base, kLPSPI_RxInterruptEnable);
- }
- else
- {
- LPSPI_EnableInterrupts(base, kLPSPI_TxInterruptEnable);
- }
- if (handle->rxData)
- {
- /* RX FIFO overflow request enable */
- LPSPI_EnableInterrupts(base, kLPSPI_ReceiveErrorInterruptEnable);
- }
- if (handle->txData)
- {
- /* TX FIFO underflow request enable */
- LPSPI_EnableInterrupts(base, kLPSPI_TransmitErrorInterruptEnable);
- }
- return kStatus_Success;
- }
- static void LPSPI_SlaveTransferFillUpTxFifo(LPSPI_Type *base, lpspi_slave_handle_t *handle)
- {
- assert(handle);
- uint32_t wordToSend = 0;
- while (LPSPI_GetTxFifoCount(base) < (handle->fifoSize))
- {
- if (handle->txRemainingByteCount < handle->bytesEachWrite)
- {
- handle->bytesEachWrite = handle->txRemainingByteCount;
- }
- wordToSend = LPSPI_CombineWriteData(handle->txData, handle->bytesEachWrite, handle->isByteSwap);
- handle->txData += handle->bytesEachWrite;
- /*Decrease the remaining TX byte count.*/
- handle->txRemainingByteCount -= handle->bytesEachWrite;
- /*Write the word to TX register*/
- LPSPI_WriteData(base, wordToSend);
- if (handle->txRemainingByteCount == 0)
- {
- break;
- }
- }
- }
- static void LPSPI_SlaveTransferComplete(LPSPI_Type *base, lpspi_slave_handle_t *handle)
- {
- assert(handle);
- status_t status = 0;
- /* Disable interrupt requests*/
- LPSPI_DisableInterrupts(base, kLPSPI_AllInterruptEnable);
- if (handle->state == kLPSPI_Error)
- {
- status = kStatus_LPSPI_Error;
- }
- else
- {
- status = kStatus_Success;
- }
- handle->state = kLPSPI_Idle;
- if (handle->callback)
- {
- handle->callback(base, handle, status, handle->userData);
- }
- }
- status_t LPSPI_SlaveTransferGetCount(LPSPI_Type *base, lpspi_slave_handle_t *handle, size_t *count)
- {
- assert(handle);
- if (!count)
- {
- return kStatus_InvalidArgument;
- }
- /* Catch when there is not an active transfer. */
- if (handle->state != kLPSPI_Busy)
- {
- *count = 0;
- return kStatus_NoTransferInProgress;
- }
- size_t remainingByte;
- if (handle->rxData)
- {
- remainingByte = handle->rxRemainingByteCount;
- }
- else
- {
- remainingByte = handle->txRemainingByteCount;
- }
- *count = handle->totalByteCount - remainingByte;
- return kStatus_Success;
- }
- void LPSPI_SlaveTransferAbort(LPSPI_Type *base, lpspi_slave_handle_t *handle)
- {
- assert(handle);
- /* Disable interrupt requests*/
- LPSPI_DisableInterrupts(base, kLPSPI_TxInterruptEnable | kLPSPI_RxInterruptEnable);
- LPSPI_Reset(base);
- handle->state = kLPSPI_Idle;
- handle->txRemainingByteCount = 0;
- handle->rxRemainingByteCount = 0;
- }
- void LPSPI_SlaveTransferHandleIRQ(LPSPI_Type *base, lpspi_slave_handle_t *handle)
- {
- assert(handle);
- uint32_t readData; /* variable to store word read from RX FIFO */
- uint32_t wordToSend; /* variable to store word to write to TX FIFO */
- if (handle->rxData != NULL)
- {
- if (handle->rxRemainingByteCount > 0)
- {
- while (LPSPI_GetRxFifoCount(base))
- {
- /*Read out the data*/
- readData = LPSPI_ReadData(base);
- /*Decrease the read RX register times.*/
- --handle->readRegRemainingTimes;
- if (handle->rxRemainingByteCount < handle->bytesEachRead)
- {
- handle->bytesEachRead = handle->rxRemainingByteCount;
- }
- LPSPI_SeparateReadData(handle->rxData, readData, handle->bytesEachRead, handle->isByteSwap);
- handle->rxData += handle->bytesEachRead;
- /*Decrease the remaining RX byte count.*/
- handle->rxRemainingByteCount -= handle->bytesEachRead;
- if ((handle->txRemainingByteCount > 0) && (handle->txData != NULL))
- {
- if (handle->txRemainingByteCount < handle->bytesEachWrite)
- {
- handle->bytesEachWrite = handle->txRemainingByteCount;
- }
- wordToSend = LPSPI_CombineWriteData(handle->txData, handle->bytesEachWrite, handle->isByteSwap);
- handle->txData += handle->bytesEachWrite;
- /*Decrease the remaining TX byte count.*/
- handle->txRemainingByteCount -= handle->bytesEachWrite;
- /*Write the word to TX register*/
- LPSPI_WriteData(base, wordToSend);
- }
- if (handle->rxRemainingByteCount == 0)
- {
- break;
- }
- }
- }
- /*Set rxWatermark to (readRegRemainingTimes-1) if readRegRemainingTimes less than rxWatermark. Otherwise there
- *is not RX interrupt for the last datas because the RX count is not greater than rxWatermark.
- */
- if ((handle->readRegRemainingTimes) <= (handle->rxWatermark))
- {
- base->FCR =
- (base->FCR & (~LPSPI_FCR_RXWATER_MASK)) |
- LPSPI_FCR_RXWATER((handle->readRegRemainingTimes > 1) ? (handle->readRegRemainingTimes - 1U) : (0U));
- }
- }
- else if ((handle->txRemainingByteCount) && (handle->txData != NULL))
- {
- LPSPI_SlaveTransferFillUpTxFifo(base, handle);
- }
- else
- {
- __NOP();
- }
- if ((handle->txRemainingByteCount == 0) && (handle->rxRemainingByteCount == 0))
- {
- /* If no RX buffer, then transfer is not complete until transfer complete flag sets and the TX FIFO empty*/
- if (handle->rxData == NULL)
- {
- if ((LPSPI_GetStatusFlags(base) & kLPSPI_FrameCompleteFlag) && (LPSPI_GetTxFifoCount(base) == 0))
- {
- /* Complete the transfer and disable the interrupts */
- LPSPI_SlaveTransferComplete(base, handle);
- }
- else
- {
- LPSPI_ClearStatusFlags(base, kLPSPI_FrameCompleteFlag);
- LPSPI_EnableInterrupts(base, kLPSPI_FrameCompleteInterruptEnable);
- LPSPI_DisableInterrupts(base, kLPSPI_TxInterruptEnable | kLPSPI_RxInterruptEnable);
- }
- }
- else
- {
- /* Complete the transfer and disable the interrupts */
- LPSPI_SlaveTransferComplete(base, handle);
- }
- }
- /* Catch tx fifo underflow conditions, service only if tx under flow interrupt enabled */
- if ((LPSPI_GetStatusFlags(base) & kLPSPI_TransmitErrorFlag) && (base->IER & LPSPI_IER_TEIE_MASK))
- {
- LPSPI_ClearStatusFlags(base, kLPSPI_TransmitErrorFlag);
- /* Change state to error and clear flag */
- if (handle->txData)
- {
- handle->state = kLPSPI_Error;
- }
- handle->errorCount++;
- }
- /* Catch rx fifo overflow conditions, service only if rx over flow interrupt enabled */
- if ((LPSPI_GetStatusFlags(base) & kLPSPI_ReceiveErrorFlag) && (base->IER & LPSPI_IER_REIE_MASK))
- {
- LPSPI_ClearStatusFlags(base, kLPSPI_ReceiveErrorFlag);
- /* Change state to error and clear flag */
- if (handle->txData)
- {
- handle->state = kLPSPI_Error;
- }
- handle->errorCount++;
- }
- }
- static uint32_t LPSPI_CombineWriteData(uint8_t *txData, uint32_t bytesEachWrite, bool isByteSwap)
- {
- assert(txData);
- uint32_t wordToSend = 0;
- switch (bytesEachWrite)
- {
- case 1:
- wordToSend = *txData;
- ++txData;
- break;
- case 2:
- if (!isByteSwap)
- {
- wordToSend = *txData;
- ++txData;
- wordToSend |= (unsigned)(*txData) << 8U;
- ++txData;
- }
- else
- {
- wordToSend = (unsigned)(*txData) << 8U;
- ++txData;
- wordToSend |= *txData;
- ++txData;
- }
- break;
- case 3:
- if (!isByteSwap)
- {
- wordToSend = *txData;
- ++txData;
- wordToSend |= (unsigned)(*txData) << 8U;
- ++txData;
- wordToSend |= (unsigned)(*txData) << 16U;
- ++txData;
- }
- else
- {
- wordToSend = (unsigned)(*txData) << 16U;
- ++txData;
- wordToSend |= (unsigned)(*txData) << 8U;
- ++txData;
- wordToSend |= *txData;
- ++txData;
- }
- break;
- case 4:
- if (!isByteSwap)
- {
- wordToSend = *txData;
- ++txData;
- wordToSend |= (unsigned)(*txData) << 8U;
- ++txData;
- wordToSend |= (unsigned)(*txData) << 16U;
- ++txData;
- wordToSend |= (unsigned)(*txData) << 24U;
- ++txData;
- }
- else
- {
- wordToSend = (unsigned)(*txData) << 24U;
- ++txData;
- wordToSend |= (unsigned)(*txData) << 16U;
- ++txData;
- wordToSend |= (unsigned)(*txData) << 8U;
- ++txData;
- wordToSend |= *txData;
- ++txData;
- }
- break;
- default:
- assert(false);
- break;
- }
- return wordToSend;
- }
- static void LPSPI_SeparateReadData(uint8_t *rxData, uint32_t readData, uint32_t bytesEachRead, bool isByteSwap)
- {
- assert(rxData);
- switch (bytesEachRead)
- {
- case 1:
- *rxData = readData;
- ++rxData;
- break;
- case 2:
- if (!isByteSwap)
- {
- *rxData = readData;
- ++rxData;
- *rxData = readData >> 8;
- ++rxData;
- }
- else
- {
- *rxData = readData >> 8;
- ++rxData;
- *rxData = readData;
- ++rxData;
- }
- break;
- case 3:
- if (!isByteSwap)
- {
- *rxData = readData;
- ++rxData;
- *rxData = readData >> 8;
- ++rxData;
- *rxData = readData >> 16;
- ++rxData;
- }
- else
- {
- *rxData = readData >> 16;
- ++rxData;
- *rxData = readData >> 8;
- ++rxData;
- *rxData = readData;
- ++rxData;
- }
- break;
- case 4:
- if (!isByteSwap)
- {
- *rxData = readData;
- ++rxData;
- *rxData = readData >> 8;
- ++rxData;
- *rxData = readData >> 16;
- ++rxData;
- *rxData = readData >> 24;
- ++rxData;
- }
- else
- {
- *rxData = readData >> 24;
- ++rxData;
- *rxData = readData >> 16;
- ++rxData;
- *rxData = readData >> 8;
- ++rxData;
- *rxData = readData;
- ++rxData;
- }
- break;
- default:
- assert(false);
- break;
- }
- }
- static void LPSPI_CommonIRQHandler(LPSPI_Type *base, void *param)
- {
- if (LPSPI_IsMaster(base))
- {
- s_lpspiMasterIsr(base, (lpspi_master_handle_t *)param);
- }
- else
- {
- s_lpspiSlaveIsr(base, (lpspi_slave_handle_t *)param);
- }
- /* 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(LPSPI0)
- void LPSPI0_DriverIRQHandler(void)
- {
- assert(s_lpspiHandle[0]);
- LPSPI_CommonIRQHandler(LPSPI0, s_lpspiHandle[0]);
- }
- #endif
- #if defined(LPSPI1)
- void LPSPI1_DriverIRQHandler(void)
- {
- assert(s_lpspiHandle[1]);
- LPSPI_CommonIRQHandler(LPSPI1, s_lpspiHandle[1]);
- }
- #endif
- #if defined(LPSPI2)
- void LPSPI2_DriverIRQHandler(void)
- {
- assert(s_lpspiHandle[2]);
- LPSPI_CommonIRQHandler(LPSPI2, s_lpspiHandle[2]);
- }
- #endif
- #if defined(LPSPI3)
- void LPSPI3_DriverIRQHandler(void)
- {
- assert(s_lpspiHandle[3]);
- LPSPI_CommonIRQHandler(LPSPI3, s_lpspiHandle[3]);
- }
- #endif
- #if defined(LPSPI4)
- void LPSPI4_DriverIRQHandler(void)
- {
- assert(s_lpspiHandle[4]);
- LPSPI_CommonIRQHandler(LPSPI4, s_lpspiHandle[4]);
- }
- #endif
- #if defined(LPSPI5)
- void LPSPI5_DriverIRQHandler(void)
- {
- assert(s_lpspiHandle[5]);
- LPSPI_CommonIRQHandler(LPSPI5, s_lpspiHandle[5]);
- }
- #endif
- #if defined(DMA__LPSPI0)
- void DMA_SPI0_INT_DriverIRQHandler(void)
- {
- assert(s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI0)]);
- LPSPI_CommonIRQHandler(DMA__LPSPI0, s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI0)]);
- }
- #endif
- #if defined(DMA__LPSPI1)
- void DMA_SPI1_INT_DriverIRQHandler(void)
- {
- assert(s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI1)]);
- LPSPI_CommonIRQHandler(DMA__LPSPI1, s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI1)]);
- }
- #endif
- #if defined(DMA__LPSPI2)
- void DMA_SPI2_INT_DriverIRQHandler(void)
- {
- assert(s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI2)]);
- LPSPI_CommonIRQHandler(DMA__LPSPI2, s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI2)]);
- }
- #endif
- #if defined(DMA__LPSPI3)
- void DMA_SPI3_INT_DriverIRQHandler(void)
- {
- assert(s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI3)]);
- LPSPI_CommonIRQHandler(DMA__LPSPI3, s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI3)]);
- }
- #endif
- #if defined(ADMA__LPSPI0)
- void ADMA_SPI0_INT_DriverIRQHandler(void)
- {
- assert(s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI0)]);
- LPSPI_CommonIRQHandler(ADMA__LPSPI0, s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI0)]);
- }
- #endif
- #if defined(ADMA__LPSPI1)
- void ADMA_SPI1_INT_DriverIRQHandler(void)
- {
- assert(s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI1)]);
- LPSPI_CommonIRQHandler(ADMA__LPSPI1, s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI1)]);
- }
- #endif
- #if defined(ADMA__LPSPI2)
- void ADMA_SPI2_INT_DriverIRQHandler(void)
- {
- assert(s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI2)]);
- LPSPI_CommonIRQHandler(ADMA__LPSPI2, s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI2)]);
- }
- #endif
- #if defined(ADMA__LPSPI3)
- void ADMA_SPI3_INT_DriverIRQHandler(void)
- {
- assert(s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI3)]);
- LPSPI_CommonIRQHandler(ADMA__LPSPI3, s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI3)]);
- }
- #endif
|