diff options
Diffstat (limited to '')
-rw-r--r-- | bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_mculcd.c | 1293 |
1 files changed, 1293 insertions, 0 deletions
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_mculcd.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_mculcd.c new file mode 100644 index 0000000000..f9f890a627 --- /dev/null +++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_mculcd.c @@ -0,0 +1,1293 @@ +/* + * Copyright (c) 2016, Freescale Semiconductor, Inc. + * Copyright 2016-2020 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 / 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(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(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(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(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(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(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, void *data, size_t size) +{ + assert(size > 0U); + + uint32_t i; +#if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH) + uint8_t *data8Bit; +#else + 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 = (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 = (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); + } + } +} |