/* * Copyright (c) 2016, Freescale Semiconductor, Inc. * Copyright 2016-2021 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include "fsl_flexio_mculcd.h" /* Component ID definition, used by tools. */ #ifndef FSL_COMPONENT_ID #define FSL_COMPONENT_ID "platform.drivers.flexio_mculcd" #endif /******************************************************************************* * Definitations ******************************************************************************/ enum _mculcd_transfer_state { kFLEXIO_MCULCD_StateIdle, /*!< No transfer in progress. */ kFLEXIO_MCULCD_StateReadArray, /*!< Reading array in progress. */ kFLEXIO_MCULCD_StateWriteArray, /*!< Writing array in progress. */ kFLEXIO_MCULCD_StateWriteSameValue, /*!< Writing the same value in progress. */ }; /* The TIMCFG[0:7] is used for baud rate divider in dual 8-bit counters baud/bit mode. */ #define FLEXIO_BAUDRATE_DIV_MASK 0xFFU /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ /******************************************************************************* * Code ******************************************************************************/ /*! * brief Ungates the FlexIO clock, resets the FlexIO module, configures the * FlexIO MCULCD hardware, and configures the FlexIO MCULCD with FlexIO MCULCD * configuration. * The configuration structure can be filled by the user, or be set with default * values * by the ref FLEXIO_MCULCD_GetDefaultConfig. * * param base Pointer to the FLEXIO_MCULCD_Type structure. * param config Pointer to the flexio_mculcd_config_t structure. * param srcClock_Hz FlexIO source clock in Hz. * retval kStatus_Success Initialization success. * retval kStatus_InvalidArgument Initialization failed because of invalid * argument. */ status_t FLEXIO_MCULCD_Init(FLEXIO_MCULCD_Type *base, flexio_mculcd_config_t *config, uint32_t srcClock_Hz) { assert(NULL != config); flexio_config_t flexioConfig = {config->enable, config->enableInDoze, config->enableInDebug, config->enableFastAccess}; FLEXIO_Init(base->flexioBase, &flexioConfig); if (kStatus_Success != FLEXIO_MCULCD_SetBaudRate(base, config->baudRate_Bps, srcClock_Hz)) { return kStatus_Success; } base->setCSPin(true); base->setRSPin(true); return kStatus_Success; } /*! * brief Resets the FLEXIO_MCULCD timer and shifter configuration. * * param base Pointer to the FLEXIO_MCULCD_Type. */ void FLEXIO_MCULCD_Deinit(FLEXIO_MCULCD_Type *base) { FLEXIO_MCULCD_ClearSingleBeatWriteConfig(base); FLEXIO_MCULCD_ClearSingleBeatReadConfig(base); } /*! * brief Gets the default configuration to configure the FlexIO MCULCD. * * The default configuration value is: * code * config->enable = true; * config->enableInDoze = false; * config->enableInDebug = true; * config->enableFastAccess = true; * config->baudRate_Bps = 96000000U; * endcode * param Config Pointer to the flexio_mculcd_config_t structure. */ void FLEXIO_MCULCD_GetDefaultConfig(flexio_mculcd_config_t *config) { assert(NULL != config); /* Initializes the configure structure to zero. */ (void)memset(config, 0, sizeof(*config)); config->enable = true; config->enableInDoze = false; config->enableInDebug = true; config->enableFastAccess = true; config->baudRate_Bps = 96000000U; } /*! * brief Set desired baud rate. * * param base Pointer to the FLEXIO_MCULCD_Type structure. * param baudRate_Bps Desired baud rate. * param srcClock_Hz FLEXIO clock frequency in Hz. * retval kStatus_Success Set successfully. * retval kStatus_InvalidArgument Could not set the baud rate. */ status_t FLEXIO_MCULCD_SetBaudRate(FLEXIO_MCULCD_Type *base, uint32_t baudRate_Bps, uint32_t srcClock_Hz) { uint32_t baudRateDiv; uint32_t baudRatePerDataLine; uint32_t timerCompare; status_t status; baudRatePerDataLine = baudRate_Bps / (uint32_t)FLEXIO_MCULCD_DATA_BUS_WIDTH; baudRateDiv = (srcClock_Hz + baudRatePerDataLine) / (baudRatePerDataLine * 2U); if ((0U == baudRateDiv) || (baudRateDiv > (FLEXIO_BAUDRATE_DIV_MASK + 1U))) { status = kStatus_InvalidArgument; } else { baudRateDiv--; timerCompare = base->flexioBase->TIMCMP[base->timerIndex]; timerCompare = (timerCompare & ~FLEXIO_BAUDRATE_DIV_MASK) | baudRateDiv; base->flexioBase->TIMCMP[base->timerIndex] = timerCompare; status = kStatus_Success; } return status; } /*! * brief Gets FlexIO MCULCD status flags. * * param base Pointer to the FLEXIO_MCULCD_Type structure. * return status flag; OR'ed value or the ref _flexio_mculcd_status_flags. * * note Don't use this function with DMA APIs. */ uint32_t FLEXIO_MCULCD_GetStatusFlags(FLEXIO_MCULCD_Type *base) { uint32_t ret = 0U; uint32_t flags; /* Get shifter status. */ flags = FLEXIO_GetShifterStatusFlags(base->flexioBase); if (0U != (flags & (1UL << base->rxShifterEndIndex))) { ret |= (uint32_t)kFLEXIO_MCULCD_RxFullFlag; } if (0U != (flags & (1UL << base->txShifterStartIndex))) { ret |= (uint32_t)kFLEXIO_MCULCD_TxEmptyFlag; } return ret; } /*! * brief Clears FlexIO MCULCD status flags. * * param base Pointer to the FLEXIO_MCULCD_Type structure. * param mask Status to clear, it is the OR'ed value of ref * _flexio_mculcd_status_flags. * * note Don't use this function with DMA APIs. */ void FLEXIO_MCULCD_ClearStatusFlags(FLEXIO_MCULCD_Type *base, uint32_t mask) { uint32_t flags = 0U; /* Clear the shifter flags. */ if (0U != (mask & (uint32_t)kFLEXIO_MCULCD_RxFullFlag)) { flags |= (1UL << base->rxShifterEndIndex); } if (0U != (mask & (uint32_t)kFLEXIO_MCULCD_TxEmptyFlag)) { flags |= (1UL << base->txShifterStartIndex); } FLEXIO_ClearShifterStatusFlags(base->flexioBase, flags); } /*! * brief Enables the FlexIO MCULCD interrupt. * * This function enables the FlexIO MCULCD interrupt. * * param base Pointer to the FLEXIO_MCULCD_Type structure. * param mask Interrupts to enable, it is the OR'ed value of ref * _flexio_mculcd_interrupt_enable. */ void FLEXIO_MCULCD_EnableInterrupts(FLEXIO_MCULCD_Type *base, uint32_t mask) { uint32_t interrupts = 0U; /* Enable shifter interrupts. */ if (0U != (mask & (uint32_t)kFLEXIO_MCULCD_RxFullFlag)) { interrupts |= (1UL << base->rxShifterEndIndex); } if (0U != (mask & (uint32_t)kFLEXIO_MCULCD_TxEmptyFlag)) { interrupts |= (1UL << base->txShifterStartIndex); } FLEXIO_EnableShifterStatusInterrupts(base->flexioBase, interrupts); } /*! * brief Disables the FlexIO MCULCD interrupt. * * This function disables the FlexIO MCULCD interrupt. * * param base Pointer to the FLEXIO_MCULCD_Type structure. * param mask Interrupts to disable, it is the OR'ed value of ref * _flexio_mculcd_interrupt_enable. */ void FLEXIO_MCULCD_DisableInterrupts(FLEXIO_MCULCD_Type *base, uint32_t mask) { uint32_t interrupts = 0U; /* Disable shifter interrupts. */ if (0U != (mask & (uint32_t)kFLEXIO_MCULCD_RxFullFlag)) { interrupts |= (1UL << base->rxShifterEndIndex); } if (0U != (mask & (uint32_t)kFLEXIO_MCULCD_TxEmptyFlag)) { interrupts |= (1UL << base->txShifterStartIndex); } FLEXIO_DisableShifterStatusInterrupts(base->flexioBase, interrupts); } /*! * brief Read data from the FLEXIO MCULCD RX shifter buffer. * * Read data from the RX shift buffer directly, it does no check whether the * buffer is empty or not. * * If the data bus width is 8-bit: * code * uint8_t value; * value = (uint8_t)FLEXIO_MCULCD_ReadData(base); * endcode * * If the data bus width is 16-bit: * code * uint16_t value; * value = (uint16_t)FLEXIO_MCULCD_ReadData(base); * endcode * * note This function returns the RX shifter buffer value (32-bit) directly. * The return value should be converted according to data bus width. * * param base Pointer to the FLEXIO_MCULCD_Type structure. * return The data read out. * * note Don't use this function with DMA APIs. */ uint32_t FLEXIO_MCULCD_ReadData(FLEXIO_MCULCD_Type *base) { #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH) return base->flexioBase->SHIFTBUFBYS[base->rxShifterEndIndex]; #else return base->flexioBase->SHIFTBUFHWS[base->rxShifterEndIndex]; #endif } /*! * brief Configures the FLEXIO MCULCD to multiple beats write mode. * * At the begining multiple beats write operation, the FLEXIO MCULCD is configured to * multiple beats write mode using this function. After write operation, the configuration * is cleared by ref FLEXIO_MCULCD_ClearSingleBeatWriteConfig. * * param base Pointer to the FLEXIO_MCULCD_Type. * * note This is an internal used function, upper layer should not use. */ void FLEXIO_MCULCD_SetSingleBeatWriteConfig(FLEXIO_MCULCD_Type *base) { /* * This function will be called at the beginning of every data writing. For * performance consideration, it access the FlexIO registers directly, but not * call FlexIO driver APIs. */ uint32_t timerCompare; /* Enable the TX Shifter output. */ base->flexioBase->SHIFTCFG[base->txShifterStartIndex] = FLEXIO_SHIFTCFG_PWIDTH((uint32_t)FLEXIO_MCULCD_DATA_BUS_WIDTH - 1U) | FLEXIO_SHIFTCFG_INSRC(kFLEXIO_ShifterInputFromNextShifterOutput); base->flexioBase->SHIFTCTL[base->txShifterStartIndex] = FLEXIO_SHIFTCTL_TIMSEL(base->timerIndex) | FLEXIO_SHIFTCTL_TIMPOL(kFLEXIO_ShifterTimerPolarityOnPositive) | FLEXIO_SHIFTCTL_PINCFG(kFLEXIO_PinConfigOutput) | FLEXIO_SHIFTCTL_PINSEL(base->dataPinStartIndex) | FLEXIO_SHIFTCTL_PINPOL(kFLEXIO_PinActiveHigh) | FLEXIO_SHIFTCTL_SMOD(kFLEXIO_ShifterModeTransmit); timerCompare = base->flexioBase->TIMCMP[base->timerIndex] & 0xFFU; /* * TIMCMP[15:8] = (number of beats x 2) - 1. Because the number of beat is 1, * so the TIMCMP[15:8] is 1. */ base->flexioBase->TIMCMP[base->timerIndex] = (1UL << 8U) | timerCompare; /* Use TX shifter flag as the inverted timer trigger. Timer output to WR/EN pin. */ base->flexioBase->TIMCFG[base->timerIndex] = FLEXIO_TIMCFG_TIMOUT(kFLEXIO_TimerOutputOneNotAffectedByReset) | FLEXIO_TIMCFG_TIMDEC(kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput) | FLEXIO_TIMCFG_TIMRST(kFLEXIO_TimerResetNever) | FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnTimerCompare) | FLEXIO_TIMCFG_TIMENA(kFLEXIO_TimerEnableOnTriggerHigh) | FLEXIO_TIMCFG_TSTOP(kFLEXIO_TimerStopBitDisabled) | FLEXIO_TIMCFG_TSTART(kFLEXIO_TimerStartBitDisabled); base->flexioBase->TIMCTL[base->timerIndex] = FLEXIO_TIMCTL_TRGSEL(FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->txShifterStartIndex)) | FLEXIO_TIMCTL_TRGPOL(kFLEXIO_TimerTriggerPolarityActiveLow) | FLEXIO_TIMCTL_TRGSRC(kFLEXIO_TimerTriggerSourceInternal) | FLEXIO_TIMCTL_PINCFG(kFLEXIO_PinConfigOutput) | FLEXIO_TIMCTL_PINSEL(base->ENWRPinIndex) | FLEXIO_TIMCTL_PINPOL(kFLEXIO_PinActiveLow) | FLEXIO_TIMCTL_TIMOD(kFLEXIO_TimerModeDual8BitBaudBit); } /*! * brief Clear the FLEXIO MCULCD multiple beats write mode configuration. * * Clear the write configuration set by ref FLEXIO_MCULCD_SetSingleBeatWriteConfig. * * param base Pointer to the FLEXIO_MCULCD_Type. * * note This is an internal used function, upper layer should not use. */ void FLEXIO_MCULCD_ClearSingleBeatWriteConfig(FLEXIO_MCULCD_Type *base) { /* Disable the timer. */ base->flexioBase->TIMCTL[base->timerIndex] = 0U; base->flexioBase->TIMCFG[base->timerIndex] = 0U; /* Clear the timer flag. */ base->flexioBase->TIMSTAT = (1UL << base->timerIndex); /* Stop the TX shifter. */ base->flexioBase->SHIFTCTL[base->txShifterStartIndex] = 0U; base->flexioBase->SHIFTCFG[base->txShifterStartIndex] = 0U; /* Clear the shifter flag. */ base->flexioBase->SHIFTSTAT = (1UL << base->txShifterStartIndex); } /*! * brief Configures the FLEXIO MCULCD to multiple beats read mode. * * At the begining or multiple beats read operation, the FLEXIO MCULCD is configured * to multiple beats read mode using this function. After read operation, the configuration * is cleared by ref FLEXIO_MCULCD_ClearSingleBeatReadConfig. * * param base Pointer to the FLEXIO_MCULCD_Type. * * note This is an internal used function, upper layer should not use. */ void FLEXIO_MCULCD_SetSingleBeatReadConfig(FLEXIO_MCULCD_Type *base) { /* * This function will be called at the beginning of every data reading. For * performance consideration, it access the FlexIO registers directly, but not * call FlexIO driver APIs. */ uint8_t timerPin; uint32_t timerCompare; flexio_pin_polarity_t timerPinPolarity; /* Timer output to RD pin (8080 mode), to WR/EN pin in 6800 mode. */ if (kFLEXIO_MCULCD_8080 == base->busType) { timerPin = base->RDPinIndex; timerPinPolarity = kFLEXIO_PinActiveLow; } else { timerPin = base->ENWRPinIndex; timerPinPolarity = kFLEXIO_PinActiveHigh; } /* Enable the RX Shifter input. */ base->flexioBase->SHIFTCFG[base->rxShifterEndIndex] = FLEXIO_SHIFTCFG_PWIDTH((uint32_t)FLEXIO_MCULCD_DATA_BUS_WIDTH - 1U); base->flexioBase->SHIFTCTL[base->rxShifterEndIndex] = FLEXIO_SHIFTCTL_TIMSEL(base->timerIndex) | FLEXIO_SHIFTCTL_TIMPOL(kFLEXIO_ShifterTimerPolarityOnNegitive) | FLEXIO_SHIFTCTL_PINCFG(kFLEXIO_PinConfigOutputDisabled) | FLEXIO_SHIFTCTL_PINSEL(base->dataPinStartIndex) | FLEXIO_SHIFTCTL_PINPOL(kFLEXIO_PinActiveHigh) | FLEXIO_SHIFTCTL_SMOD(kFLEXIO_ShifterModeReceive); /* Use RX shifter flag as the inverted timer trigger. */ base->flexioBase->TIMCFG[base->timerIndex] = FLEXIO_TIMCFG_TIMOUT(kFLEXIO_TimerOutputOneNotAffectedByReset) | FLEXIO_TIMCFG_TIMDEC(kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput) | FLEXIO_TIMCFG_TIMRST(kFLEXIO_TimerResetNever) | FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnTimerCompare) | FLEXIO_TIMCFG_TIMENA(kFLEXIO_TimerEnableOnTriggerHigh) | FLEXIO_TIMCFG_TSTOP(kFLEXIO_TimerStopBitEnableOnTimerDisable) | FLEXIO_TIMCFG_TSTART(kFLEXIO_TimerStartBitDisabled); timerCompare = base->flexioBase->TIMCMP[base->timerIndex] & 0xFFU; /* * TIMCMP[15:8] = (number of beats x 2) - 1. Because the number of beat is 1, * so the TIMCMP[15:8] is 1. */ base->flexioBase->TIMCMP[base->timerIndex] = (1UL << 8U) | timerCompare; base->flexioBase->TIMCTL[base->timerIndex] |= FLEXIO_TIMCTL_TRGSEL(FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->rxShifterEndIndex)) | FLEXIO_TIMCTL_TRGPOL(kFLEXIO_TimerTriggerPolarityActiveLow) | FLEXIO_TIMCTL_TRGSRC(kFLEXIO_TimerTriggerSourceInternal) | FLEXIO_TIMCTL_PINCFG(kFLEXIO_PinConfigOutput) | FLEXIO_TIMCTL_PINSEL(timerPin) | FLEXIO_TIMCTL_PINPOL(timerPinPolarity) | FLEXIO_TIMCTL_TIMOD(kFLEXIO_TimerModeDual8BitBaudBit); } /*! * brief Clear the FLEXIO MCULCD multiple beats read mode configuration. * * Clear the read configuration set by ref FLEXIO_MCULCD_SetSingleBeatReadConfig. * * param base Pointer to the FLEXIO_MCULCD_Type. * * note This is an internal used function, upper layer should not use. */ void FLEXIO_MCULCD_ClearSingleBeatReadConfig(FLEXIO_MCULCD_Type *base) { /* Disable the timer. */ base->flexioBase->TIMCTL[base->timerIndex] = 0U; base->flexioBase->TIMCFG[base->timerIndex] = 0U; /* Clear the timer flag. */ base->flexioBase->TIMSTAT = (1UL << base->timerIndex); /* Stop the RX shifter. */ base->flexioBase->SHIFTCTL[base->rxShifterEndIndex] = 0U; base->flexioBase->SHIFTCFG[base->rxShifterEndIndex] = 0U; /* Clear the shifter flag. */ base->flexioBase->SHIFTSTAT = (1UL << base->rxShifterEndIndex); } /*! * brief Configures the FLEXIO MCULCD to multiple beats write mode. * * At the begining multiple beats write operation, the FLEXIO MCULCD is configured to * multiple beats write mode using this function. After write operation, the configuration * is cleared by ref FLEXIO_MCULCD_ClearMultBeatsWriteConfig. * * param base Pointer to the FLEXIO_MCULCD_Type. * * note This is an internal used function, upper layer should not use. */ void FLEXIO_MCULCD_SetMultiBeatsWriteConfig(FLEXIO_MCULCD_Type *base) { /* * This function will be called at the beginning of every data writing. For * performance consideration, it access the FlexIO registers directly, but not * call FlexIO driver APIs. */ uint32_t timerCompare; uint8_t beats; uint8_t i; /* Enable the TX Shifter output. */ base->flexioBase->SHIFTCFG[base->txShifterStartIndex] = FLEXIO_SHIFTCFG_PWIDTH((uint32_t)FLEXIO_MCULCD_DATA_BUS_WIDTH - 1U) | FLEXIO_SHIFTCFG_INSRC(kFLEXIO_ShifterInputFromNextShifterOutput); base->flexioBase->SHIFTCTL[base->txShifterStartIndex] = FLEXIO_SHIFTCTL_TIMSEL(base->timerIndex) | FLEXIO_SHIFTCTL_TIMPOL(kFLEXIO_ShifterTimerPolarityOnPositive) | FLEXIO_SHIFTCTL_PINCFG(kFLEXIO_PinConfigOutput) | FLEXIO_SHIFTCTL_PINSEL(base->dataPinStartIndex) | FLEXIO_SHIFTCTL_PINPOL(kFLEXIO_PinActiveHigh) | FLEXIO_SHIFTCTL_SMOD(kFLEXIO_ShifterModeTransmit); for (i = base->txShifterStartIndex + 1U; i <= base->txShifterEndIndex; i++) { base->flexioBase->SHIFTCFG[i] = FLEXIO_SHIFTCFG_PWIDTH((uint32_t)FLEXIO_MCULCD_DATA_BUS_WIDTH - 1U) | FLEXIO_SHIFTCFG_INSRC(kFLEXIO_ShifterInputFromNextShifterOutput); base->flexioBase->SHIFTCTL[i] = FLEXIO_SHIFTCTL_TIMSEL(base->timerIndex) | FLEXIO_SHIFTCTL_TIMPOL(kFLEXIO_ShifterTimerPolarityOnPositive) | FLEXIO_SHIFTCTL_PINCFG(kFLEXIO_PinConfigOutputDisabled) | FLEXIO_SHIFTCTL_PINSEL(0) | FLEXIO_SHIFTCTL_PINPOL(kFLEXIO_PinActiveHigh) | FLEXIO_SHIFTCTL_SMOD(kFLEXIO_ShifterModeTransmit); } timerCompare = base->flexioBase->TIMCMP[base->timerIndex] & 0xFFU; #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH) beats = 4U * (base->txShifterEndIndex - base->txShifterStartIndex + 1U); #else beats = 2U * (base->txShifterEndIndex - base->txShifterStartIndex + 1U); #endif /* * TIMCMP[15:8] = (number of beats x 2) - 1. */ base->flexioBase->TIMCMP[base->timerIndex] = ((beats * 2UL - 1UL) << 8U) | timerCompare; /* Use TX shifter flag as the inverted timer trigger. Timer output to WR/EN pin. */ base->flexioBase->TIMCFG[base->timerIndex] = FLEXIO_TIMCFG_TIMOUT(kFLEXIO_TimerOutputOneNotAffectedByReset) | FLEXIO_TIMCFG_TIMDEC(kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput) | FLEXIO_TIMCFG_TIMRST(kFLEXIO_TimerResetNever) | FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnTimerCompare) | FLEXIO_TIMCFG_TIMENA(kFLEXIO_TimerEnableOnTriggerHigh) | FLEXIO_TIMCFG_TSTOP(kFLEXIO_TimerStopBitDisabled) | FLEXIO_TIMCFG_TSTART(kFLEXIO_TimerStartBitDisabled); base->flexioBase->TIMCTL[base->timerIndex] = FLEXIO_TIMCTL_TRGSEL(FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->txShifterEndIndex)) | FLEXIO_TIMCTL_TRGPOL(kFLEXIO_TimerTriggerPolarityActiveLow) | FLEXIO_TIMCTL_TRGSRC(kFLEXIO_TimerTriggerSourceInternal) | FLEXIO_TIMCTL_PINCFG(kFLEXIO_PinConfigOutput) | FLEXIO_TIMCTL_PINSEL(base->ENWRPinIndex) | FLEXIO_TIMCTL_PINPOL(kFLEXIO_PinActiveLow) | FLEXIO_TIMCTL_TIMOD(kFLEXIO_TimerModeDual8BitBaudBit); } /*! * brief Clear the FLEXIO MCULCD multiple beats write mode configuration. * * Clear the write configuration set by ref FLEXIO_MCULCD_SetMultBeatsWriteConfig. * * param base Pointer to the FLEXIO_MCULCD_Type. * * note This is an internal used function, upper layer should not use. */ void FLEXIO_MCULCD_ClearMultiBeatsWriteConfig(FLEXIO_MCULCD_Type *base) { uint8_t i; uint32_t statusFlags = 0U; /* Disable the timer. */ base->flexioBase->TIMCTL[base->timerIndex] = 0U; base->flexioBase->TIMCFG[base->timerIndex] = 0U; /* Clear the timer flag. */ base->flexioBase->TIMSTAT = (1UL << base->timerIndex); /* Stop the TX shifter. */ for (i = base->txShifterStartIndex; i <= base->txShifterEndIndex; i++) { base->flexioBase->SHIFTCFG[i] = 0U; base->flexioBase->SHIFTCTL[i] = 0U; statusFlags |= (1UL << i); } /* Clear the shifter flag. */ base->flexioBase->SHIFTSTAT = statusFlags; } /*! * brief Configures the FLEXIO MCULCD to multiple beats read mode. * * At the begining or multiple beats read operation, the FLEXIO MCULCD is configured * to multiple beats read mode using this function. After read operation, the configuration * is cleared by ref FLEXIO_MCULCD_ClearMultBeatsReadConfig. * * param base Pointer to the FLEXIO_MCULCD_Type. * * note This is an internal used function, upper layer should not use. */ void FLEXIO_MCULCD_SetMultiBeatsReadConfig(FLEXIO_MCULCD_Type *base) { /* * This function will be called at the beginning of every data reading. For * performance consideration, it access the FlexIO registers directly, but not * call FlexIO driver APIs. */ uint8_t timerPin; uint8_t beats; uint8_t i; uint32_t timerCompare; flexio_pin_polarity_t timerPinPolarity; /* Timer output to RD pin (8080 mode), to WR/EN pin in 6800 mode. */ if (kFLEXIO_MCULCD_8080 == base->busType) { timerPin = base->RDPinIndex; timerPinPolarity = kFLEXIO_PinActiveLow; } else { timerPin = base->ENWRPinIndex; timerPinPolarity = kFLEXIO_PinActiveHigh; } /* Enable the RX Shifter input. */ for (i = base->rxShifterStartIndex; i < base->rxShifterEndIndex; i++) { base->flexioBase->SHIFTCFG[i] = FLEXIO_SHIFTCFG_PWIDTH((uint32_t)FLEXIO_MCULCD_DATA_BUS_WIDTH - 1U) | FLEXIO_SHIFTCFG_INSRC(kFLEXIO_ShifterInputFromNextShifterOutput); base->flexioBase->SHIFTCTL[i] = FLEXIO_SHIFTCTL_TIMSEL(base->timerIndex) | FLEXIO_SHIFTCTL_TIMPOL(kFLEXIO_ShifterTimerPolarityOnNegitive) | FLEXIO_SHIFTCTL_PINCFG(kFLEXIO_PinConfigOutputDisabled) | FLEXIO_SHIFTCTL_PINSEL(base->dataPinStartIndex) | FLEXIO_SHIFTCTL_PINPOL(kFLEXIO_PinActiveHigh) | FLEXIO_SHIFTCTL_SMOD(kFLEXIO_ShifterModeReceive); } base->flexioBase->SHIFTCFG[base->rxShifterEndIndex] = FLEXIO_SHIFTCFG_PWIDTH((uint32_t)FLEXIO_MCULCD_DATA_BUS_WIDTH - 1U); base->flexioBase->SHIFTCTL[base->rxShifterEndIndex] = FLEXIO_SHIFTCTL_TIMSEL(base->timerIndex) | FLEXIO_SHIFTCTL_TIMPOL(kFLEXIO_ShifterTimerPolarityOnNegitive) | FLEXIO_SHIFTCTL_PINCFG(kFLEXIO_PinConfigOutputDisabled) | FLEXIO_SHIFTCTL_PINSEL(base->dataPinStartIndex) | FLEXIO_SHIFTCTL_PINPOL(kFLEXIO_PinActiveHigh) | FLEXIO_SHIFTCTL_SMOD(kFLEXIO_ShifterModeReceive); timerCompare = base->flexioBase->TIMCMP[base->timerIndex] & 0xFFU; #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH) beats = 4U * (base->rxShifterEndIndex - base->rxShifterStartIndex + 1U); #else beats = 2U * (base->rxShifterEndIndex - base->rxShifterStartIndex + 1U); #endif /* * TIMCMP[15:8] = (number of beats x 2) - 1. */ base->flexioBase->TIMCMP[base->timerIndex] = ((beats * 2UL - 1UL) << 8U) | timerCompare; /* Use RX shifter flag as the inverted timer trigger. */ base->flexioBase->TIMCFG[base->timerIndex] = FLEXIO_TIMCFG_TIMOUT(kFLEXIO_TimerOutputOneNotAffectedByReset) | FLEXIO_TIMCFG_TIMDEC(kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput) | FLEXIO_TIMCFG_TIMRST(kFLEXIO_TimerResetNever) | FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnTimerCompare) | FLEXIO_TIMCFG_TIMENA(kFLEXIO_TimerEnableOnTriggerHigh) | FLEXIO_TIMCFG_TSTOP(kFLEXIO_TimerStopBitEnableOnTimerDisable) | FLEXIO_TIMCFG_TSTART(kFLEXIO_TimerStartBitDisabled); base->flexioBase->TIMCTL[base->timerIndex] |= FLEXIO_TIMCTL_TRGSEL(FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->rxShifterEndIndex)) | FLEXIO_TIMCTL_TRGPOL(kFLEXIO_TimerTriggerPolarityActiveLow) | FLEXIO_TIMCTL_TRGSRC(kFLEXIO_TimerTriggerSourceInternal) | FLEXIO_TIMCTL_PINCFG(kFLEXIO_PinConfigOutput) | FLEXIO_TIMCTL_PINSEL(timerPin) | FLEXIO_TIMCTL_PINPOL(timerPinPolarity) | FLEXIO_TIMCTL_TIMOD(kFLEXIO_TimerModeDual8BitBaudBit); } /*! * brief Clear the FLEXIO MCULCD multiple beats read mode configuration. * * Clear the read configuration set by ref FLEXIO_MCULCD_SetMultBeatsReadConfig. * * param base Pointer to the FLEXIO_MCULCD_Type. * * note This is an internal used function, upper layer should not use. */ void FLEXIO_MCULCD_ClearMultiBeatsReadConfig(FLEXIO_MCULCD_Type *base) { uint8_t i; uint32_t statusFlags = 0U; /* Disable the timer. */ base->flexioBase->TIMCTL[base->timerIndex] = 0U; base->flexioBase->TIMCFG[base->timerIndex] = 0U; /* Clear the timer flag. */ base->flexioBase->TIMSTAT = (1UL << base->timerIndex); /* Stop the RX shifter. */ for (i = base->rxShifterStartIndex; i <= base->rxShifterEndIndex; i++) { base->flexioBase->SHIFTCTL[i] = 0U; base->flexioBase->SHIFTCFG[i] = 0U; statusFlags |= (1UL << i); } /* Clear the shifter flag. */ base->flexioBase->SHIFTSTAT = statusFlags; } /*! * brief Wait for transmit data send out finished. * * Currently there is no effective method to wait for the data send out * from the shiter, so here use a while loop to wait. * * note This is an internal used function. */ void FLEXIO_MCULCD_WaitTransmitComplete(void) { uint32_t i = FLEXIO_MCULCD_WAIT_COMPLETE_TIME; while (0U != (i--)) { __NOP(); } } /*! * brief Send command in blocking way. * * This function sends the command and returns when the command has been sent * out. * * param base Pointer to the FLEXIO_MCULCD_Type structure. * param command The command to send. */ void FLEXIO_MCULCD_WriteCommandBlocking(FLEXIO_MCULCD_Type *base, uint32_t command) { FLEXIO_Type *flexioBase = base->flexioBase; /* De-assert the RS pin. */ base->setRSPin(false); /* For 6800, de-assert the RDWR pin. */ if (kFLEXIO_MCULCD_6800 == base->busType) { base->setRDWRPin(false); } /* Configure the timer and TX shifter. */ FLEXIO_MCULCD_SetSingleBeatWriteConfig(base); /* Write command to shifter buffer. */ flexioBase->SHIFTBUF[base->txShifterStartIndex] = command; /* Wait for command send out. */ while (0U == ((1UL << base->timerIndex) & FLEXIO_GetTimerStatusFlags(flexioBase))) { } /* Stop the timer and TX shifter. */ FLEXIO_MCULCD_ClearSingleBeatWriteConfig(base); /* Assert the RS pin. */ base->setRSPin(true); /* For 6800, assert the RDWR pin. */ if (kFLEXIO_MCULCD_6800 == base->busType) { base->setRDWRPin(true); } } /*! * brief Send data array in blocking way. * * This function sends the data array and returns when the data sent out. * * param base Pointer to the FLEXIO_MCULCD_Type structure. * param data The data array to send. * param size How many bytes to write. */ void FLEXIO_MCULCD_WriteDataArrayBlocking(FLEXIO_MCULCD_Type *base, const void *data, size_t size) { assert(size > 0U); uint32_t i; #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH) const uint8_t *data8Bit; #else const uint16_t *data16Bit; #endif FLEXIO_Type *flexioBase = base->flexioBase; /* Assert the RS pin. */ base->setRSPin(true); /* For 6800, de-assert the RDWR pin. */ if (kFLEXIO_MCULCD_6800 == base->busType) { base->setRDWRPin(false); } /* Configure the timer and TX shifter. */ FLEXIO_MCULCD_SetSingleBeatWriteConfig(base); /* If data bus width is 8. */ #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH) data8Bit = (const uint8_t *)data; for (i = 0; i < size; i++) { flexioBase->SHIFTBUF[base->txShifterStartIndex] = data8Bit[i]; /* Wait for the data send out. */ while (0U == ((1UL << base->timerIndex) & flexioBase->TIMSTAT)) { } /* Clear the timer stat. */ flexioBase->TIMSTAT = 1UL << base->timerIndex; } #else data16Bit = (const uint16_t *)data; size /= 2U; for (i = 0; i < size; i++) { flexioBase->SHIFTBUF[base->txShifterStartIndex] = data16Bit[i]; /* Wait for the data send out. */ while (0U == ((1UL << base->timerIndex) & flexioBase->TIMSTAT)) { } /* Clear the timer stat. */ flexioBase->TIMSTAT = 1UL << base->timerIndex; } #endif /* Stop the timer and TX shifter. */ FLEXIO_MCULCD_ClearSingleBeatWriteConfig(base); } /*! * brief Read data into array in blocking way. * * This function reads the data into array and returns when the data read * finished. * * param base Pointer to the FLEXIO_MCULCD_Type structure. * param data The array to save the data. * param size How many bytes to read. */ void FLEXIO_MCULCD_ReadDataArrayBlocking(FLEXIO_MCULCD_Type *base, void *data, size_t size) { assert(size > 0U); uint32_t i; #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH) uint8_t *data8Bit = (uint8_t *)data; #else uint16_t *data16Bit = (uint16_t *)data; #endif FLEXIO_Type *flexioBase = base->flexioBase; /* Assert the RS pin. */ base->setRSPin(true); /* For 6800, de-assert the RDWR pin. */ if (kFLEXIO_MCULCD_6800 == base->busType) { base->setRDWRPin(false); } /* Enable the timer and RX shifter. */ FLEXIO_MCULCD_SetSingleBeatReadConfig(base); /* If data bus width is 8. */ #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH) for (i = 0; i < (size - 1U); i++) { /* Wait for shifter buffer full. */ while (0U == ((1UL << base->rxShifterEndIndex) & FLEXIO_GetShifterStatusFlags(flexioBase))) { } data8Bit[i] = (uint8_t)flexioBase->SHIFTBUFBYS[base->rxShifterEndIndex]; } #else /* Data bus width is 16. */ size /= 2U; for (i = 0; i < (size - 1U); i++) { /* Wait for shifter buffer full. */ while (0U == ((1UL << base->rxShifterEndIndex) & FLEXIO_GetShifterStatusFlags(flexioBase))) { } data16Bit[i] = (uint16_t)flexioBase->SHIFTBUFHWS[base->rxShifterEndIndex]; } #endif /* Wait for shifter buffer full. */ while (0U == ((1UL << base->rxShifterEndIndex) & FLEXIO_GetShifterStatusFlags(flexioBase))) { } /* Stop the timer and disable the RX shifter. */ FLEXIO_MCULCD_ClearSingleBeatReadConfig(base); /* Read out the last data. */ #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH) data8Bit[i] = (uint8_t)flexioBase->SHIFTBUFBYS[base->rxShifterEndIndex]; #else data16Bit[i] = (uint16_t)flexioBase->SHIFTBUFHWS[base->rxShifterEndIndex]; #endif } /*! * brief Send the same value many times in blocking way. * * This function sends the same value many times. It could be used to clear the * LCD screen. If the data bus width is 8, this function will send LSB 8 bits of * p sameValue for p size times. If the data bus is 16, this function will send * LSB 16 bits of p sameValue for p size / 2 times. * * param base Pointer to the FLEXIO_MCULCD_Type structure. * param sameValue The same value to send. * param size How many bytes to send. */ void FLEXIO_MCULCD_WriteSameValueBlocking(FLEXIO_MCULCD_Type *base, uint32_t sameValue, size_t size) { assert(size > 0U); uint32_t i; FLEXIO_Type *flexioBase = base->flexioBase; #if (16 == FLEXIO_MCULCD_DATA_BUS_WIDTH) size /= 2U; #endif /* Assert the RS pin. */ base->setRSPin(true); /* For 6800, de-assert the RDWR pin. */ if (kFLEXIO_MCULCD_6800 == base->busType) { base->setRDWRPin(false); } /* Configure the timer and TX shifter. */ FLEXIO_MCULCD_SetSingleBeatWriteConfig(base); for (i = 0; i < size; i++) { flexioBase->SHIFTBUF[base->txShifterStartIndex] = sameValue; /* Wait for the data send out. */ while (0U == ((1UL << base->timerIndex) & flexioBase->TIMSTAT)) { } /* Clear the timer stat. */ flexioBase->TIMSTAT = 1UL << base->timerIndex; } /* Stop the timer and TX shifter. */ FLEXIO_MCULCD_ClearSingleBeatWriteConfig(base); } /*! * brief Performs a polling transfer. * * note The API does not return until the transfer finished. * * param base pointer to FLEXIO_MCULCD_Type structure. * param xfer pointer to flexio_mculcd_transfer_t structure. */ void FLEXIO_MCULCD_TransferBlocking(FLEXIO_MCULCD_Type *base, flexio_mculcd_transfer_t *xfer) { FLEXIO_MCULCD_StartTransfer(base); FLEXIO_MCULCD_WriteCommandBlocking(base, xfer->command); if (xfer->dataSize > 0U) { if (kFLEXIO_MCULCD_ReadArray == xfer->mode) { FLEXIO_MCULCD_ReadDataArrayBlocking(base, (uint8_t *)(xfer->dataAddrOrSameValue), xfer->dataSize); } else if (kFLEXIO_MCULCD_WriteArray == xfer->mode) { FLEXIO_MCULCD_WriteDataArrayBlocking(base, (uint8_t *)(xfer->dataAddrOrSameValue), xfer->dataSize); } else { FLEXIO_MCULCD_WriteSameValueBlocking(base, xfer->dataAddrOrSameValue, xfer->dataSize); } } FLEXIO_MCULCD_StopTransfer(base); } /*! * brief Initializes the FlexIO MCULCD handle, which is used in transactional * functions. * * param base Pointer to the FLEXIO_MCULCD_Type structure. * param handle Pointer to the flexio_mculcd_handle_t structure to store the * transfer state. * param callback The callback function. * param userData The parameter of the callback function. * retval kStatus_Success Successfully create the handle. * retval kStatus_OutOfRange The FlexIO type/handle/ISR table out of range. */ status_t FLEXIO_MCULCD_TransferCreateHandle(FLEXIO_MCULCD_Type *base, flexio_mculcd_handle_t *handle, flexio_mculcd_transfer_callback_t callback, void *userData) { assert(NULL != handle); IRQn_Type flexio_irqs[] = FLEXIO_IRQS; /* Zero the handle. */ (void)memset(handle, 0, sizeof(*handle)); handle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle; /* Register callback and userData. */ handle->completionCallback = callback; handle->userData = userData; /* Enable interrupt in NVIC. */ (void)EnableIRQ(flexio_irqs[FLEXIO_GetInstance(base->flexioBase)]); /* Save the context in global variables to support the double weak mechanism. */ return FLEXIO_RegisterHandleIRQ(base, handle, FLEXIO_MCULCD_TransferHandleIRQ); } /*! * brief Transfer data using IRQ. * * This function sends data using IRQ. This is a non-blocking function, which * returns right away. When all data is sent out/received, the callback * function is called. * * param base Pointer to the FLEXIO_MCULCD_Type structure. * param handle Pointer to the flexio_mculcd_handle_t structure to store the * transfer state. * param xfer FlexIO MCULCD transfer structure. See #flexio_mculcd_transfer_t. * retval kStatus_Success Successfully start a transfer. * retval kStatus_InvalidArgument Input argument is invalid. * retval kStatus_FLEXIO_MCULCD_Busy MCULCD is busy with another transfer. */ status_t FLEXIO_MCULCD_TransferNonBlocking(FLEXIO_MCULCD_Type *base, flexio_mculcd_handle_t *handle, flexio_mculcd_transfer_t *xfer) { /* If previous transfer is in progress. */ if ((uint32_t)kFLEXIO_MCULCD_StateIdle != handle->state) { return kStatus_FLEXIO_MCULCD_Busy; } /* Set the state in handle. */ if (kFLEXIO_MCULCD_ReadArray == xfer->mode) { handle->state = (uint32_t)kFLEXIO_MCULCD_StateReadArray; } else if (kFLEXIO_MCULCD_WriteArray == xfer->mode) { handle->state = (uint32_t)kFLEXIO_MCULCD_StateWriteArray; } else { handle->state = (uint32_t)kFLEXIO_MCULCD_StateWriteSameValue; } /* Assert the nCS. */ FLEXIO_MCULCD_StartTransfer(base); /* Send the command. */ FLEXIO_MCULCD_WriteCommandBlocking(base, xfer->command); /* If transfer count is 0 (only to send command), return directly. */ if (0U == xfer->dataSize) { handle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle; /* De-assert the nCS. */ FLEXIO_MCULCD_StopTransfer(base); if (NULL != handle->completionCallback) { handle->completionCallback(base, handle, kStatus_FLEXIO_MCULCD_Idle, handle->userData); } } else { #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH) handle->dataCount = xfer->dataSize; #else handle->dataCount = xfer->dataSize / 2U; #endif handle->remainingCount = handle->dataCount; handle->dataAddrOrSameValue = xfer->dataAddrOrSameValue; /* Enable interrupt. */ if (kFLEXIO_MCULCD_ReadArray == xfer->mode) { /* For 6800, assert the RDWR pin. */ if (kFLEXIO_MCULCD_6800 == base->busType) { base->setRDWRPin(true); } FLEXIO_MCULCD_SetSingleBeatReadConfig(base); FLEXIO_MCULCD_EnableInterrupts(base, (uint32_t)kFLEXIO_MCULCD_RxFullInterruptEnable); } else { /* For 6800, de-assert the RDWR pin. */ if (kFLEXIO_MCULCD_6800 == base->busType) { base->setRDWRPin(false); } FLEXIO_MCULCD_SetSingleBeatWriteConfig(base); FLEXIO_MCULCD_EnableInterrupts(base, (uint32_t)kFLEXIO_MCULCD_TxEmptyInterruptEnable); } } return kStatus_Success; } /*! * brief Aborts the data transfer, which used IRQ. * * param base Pointer to the FLEXIO_MCULCD_Type structure. * param handle Pointer to the flexio_mculcd_handle_t structure to store the * transfer state. */ void FLEXIO_MCULCD_TransferAbort(FLEXIO_MCULCD_Type *base, flexio_mculcd_handle_t *handle) { /* If no transfer in process, return directly. */ if ((uint32_t)kFLEXIO_MCULCD_StateIdle == handle->state) { return; } /* Disable the interrupt. */ FLEXIO_MCULCD_DisableInterrupts( base, (uint32_t)kFLEXIO_MCULCD_RxFullInterruptEnable | (uint32_t)kFLEXIO_MCULCD_TxEmptyInterruptEnable); if ((uint32_t)kFLEXIO_MCULCD_StateReadArray == handle->state) { /* Stop the timer and disable the RX shifter. */ FLEXIO_MCULCD_ClearSingleBeatReadConfig(base); } else { /* Stop the timer and disable the TX shifter. */ FLEXIO_MCULCD_ClearSingleBeatWriteConfig(base); } /* Clean the flags. */ FLEXIO_MCULCD_ClearStatusFlags(base, (uint32_t)kFLEXIO_MCULCD_TxEmptyFlag | (uint32_t)kFLEXIO_MCULCD_RxFullFlag); /* De-assert the nCS. */ FLEXIO_MCULCD_StopTransfer(base); handle->dataCount = 0; handle->remainingCount = 0; handle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle; } /*! * brief Gets the data transfer status which used IRQ. * * param base Pointer to the FLEXIO_MCULCD_Type structure. * param handle Pointer to the flexio_mculcd_handle_t structure to store the * transfer state. * param count How many bytes transferred so far by the non-blocking transaction. * retval kStatus_Success Get the transferred count Successfully. * retval kStatus_NoTransferInProgress No transfer in process. */ status_t FLEXIO_MCULCD_TransferGetCount(FLEXIO_MCULCD_Type *base, flexio_mculcd_handle_t *handle, size_t *count) { assert(NULL != count); if ((uint32_t)kFLEXIO_MCULCD_StateIdle == handle->state) { return kStatus_NoTransferInProgress; } *count = handle->dataCount - handle->remainingCount; #if (16 == FLEXIO_MCULCD_DATA_BUS_WIDTH) *count *= 2U; #endif return kStatus_Success; } /*! * brief FlexIO MCULCD IRQ handler function. * * param base Pointer to the FLEXIO_MCULCD_Type structure. * param handle Pointer to the flexio_mculcd_handle_t structure to store the * transfer state. */ void FLEXIO_MCULCD_TransferHandleIRQ(void *base, void *handle) { FLEXIO_MCULCD_Type *flexioLcdMcuBase = (FLEXIO_MCULCD_Type *)base; flexio_mculcd_handle_t *flexioLcdMcuHandle = (flexio_mculcd_handle_t *)handle; uint32_t statusFlags = FLEXIO_MCULCD_GetStatusFlags(flexioLcdMcuBase); uint32_t data; if ((uint32_t)kFLEXIO_MCULCD_StateReadArray == flexioLcdMcuHandle->state) { /* Handle the reading process. */ while ((0U != ((uint32_t)kFLEXIO_MCULCD_RxFullFlag & statusFlags)) && (flexioLcdMcuHandle->remainingCount > 0U)) { if (1U == flexioLcdMcuHandle->remainingCount) { /* If this is the last data, stop the RX shifter and timer. */ FLEXIO_MCULCD_DisableInterrupts(flexioLcdMcuBase, (uint32_t)kFLEXIO_MCULCD_RxFullInterruptEnable); FLEXIO_MCULCD_ClearSingleBeatReadConfig(flexioLcdMcuBase); FLEXIO_MCULCD_StopTransfer(flexioLcdMcuBase); } /* Read out the data. */ data = FLEXIO_MCULCD_ReadData(flexioLcdMcuBase); #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH) *(uint8_t *)(flexioLcdMcuHandle->dataAddrOrSameValue) = (uint8_t)data; flexioLcdMcuHandle->dataAddrOrSameValue++; #else *(uint16_t *)(flexioLcdMcuHandle->dataAddrOrSameValue) = (uint16_t)data; flexioLcdMcuHandle->dataAddrOrSameValue += 2U; #endif flexioLcdMcuHandle->remainingCount--; /* Transfer finished, call the callback. */ if (0U == flexioLcdMcuHandle->remainingCount) { flexioLcdMcuHandle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle; if (NULL != flexioLcdMcuHandle->completionCallback) { flexioLcdMcuHandle->completionCallback(flexioLcdMcuBase, flexioLcdMcuHandle, kStatus_FLEXIO_MCULCD_Idle, flexioLcdMcuHandle->userData); } } /* Is the shifter buffer ready to send the next data? */ statusFlags = FLEXIO_MCULCD_GetStatusFlags(flexioLcdMcuBase); } } else { /* Handle the writing process. */ while ((0U != ((uint32_t)kFLEXIO_MCULCD_TxEmptyFlag & statusFlags)) && (flexioLcdMcuHandle->remainingCount > 0U)) { /* Send the data. */ if ((uint32_t)kFLEXIO_MCULCD_StateWriteSameValue == flexioLcdMcuHandle->state) { data = flexioLcdMcuHandle->dataAddrOrSameValue; } else { #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH) data = *(uint8_t *)(flexioLcdMcuHandle->dataAddrOrSameValue); flexioLcdMcuHandle->dataAddrOrSameValue++; #else data = *(uint16_t *)(flexioLcdMcuHandle->dataAddrOrSameValue); flexioLcdMcuHandle->dataAddrOrSameValue += 2U; #endif } /* If this is the last data to send, delay to wait for the data shift out. */ if (1U == flexioLcdMcuHandle->remainingCount) { FLEXIO_MCULCD_DisableInterrupts(flexioLcdMcuBase, (uint32_t)kFLEXIO_MCULCD_TxEmptyInterruptEnable); /* Write the last data. */ FLEXIO_MCULCD_WriteData(flexioLcdMcuBase, data); /* Wait for the last data send finished. */ FLEXIO_MCULCD_WaitTransmitComplete(); flexioLcdMcuHandle->remainingCount = 0; FLEXIO_MCULCD_ClearSingleBeatWriteConfig(flexioLcdMcuBase); FLEXIO_MCULCD_StopTransfer(flexioLcdMcuBase); flexioLcdMcuHandle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle; if (NULL != flexioLcdMcuHandle->completionCallback) { flexioLcdMcuHandle->completionCallback(flexioLcdMcuBase, flexioLcdMcuHandle, kStatus_FLEXIO_MCULCD_Idle, flexioLcdMcuHandle->userData); } } else { FLEXIO_MCULCD_WriteData(flexioLcdMcuBase, data); flexioLcdMcuHandle->remainingCount--; } /* Is the shifter buffer ready to send the next data? */ statusFlags = FLEXIO_MCULCD_GetStatusFlags(flexioLcdMcuBase); } } }