1 /*
2  * Copyright (c) 2016, Freescale Semiconductor, Inc.
3  * Copyright 2016-2021 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_flexio_mculcd.h"
10 
11 /* Component ID definition, used by tools. */
12 #ifndef FSL_COMPONENT_ID
13 #define FSL_COMPONENT_ID "platform.drivers.flexio_mculcd"
14 #endif
15 
16 /*******************************************************************************
17  * Definitations
18  ******************************************************************************/
19 
20 enum _mculcd_transfer_state
21 {
22     kFLEXIO_MCULCD_StateIdle,           /*!< No transfer in progress. */
23     kFLEXIO_MCULCD_StateReadArray,      /*!< Reading array in progress. */
24     kFLEXIO_MCULCD_StateWriteArray,     /*!< Writing array in progress. */
25     kFLEXIO_MCULCD_StateWriteSameValue, /*!< Writing the same value in progress. */
26 };
27 
28 /* The TIMCFG[0:7] is used for baud rate divider in dual 8-bit counters baud/bit mode. */
29 #define FLEXIO_BAUDRATE_DIV_MASK 0xFFU
30 
31 /*******************************************************************************
32  * Prototypes
33  ******************************************************************************/
34 
35 /*******************************************************************************
36  * Variables
37  ******************************************************************************/
38 
39 /*******************************************************************************
40  * Code
41  ******************************************************************************/
42 /*!
43  * brief Ungates the FlexIO clock, resets the FlexIO module, configures the
44  * FlexIO MCULCD hardware, and configures the FlexIO MCULCD with FlexIO MCULCD
45  * configuration.
46  * The configuration structure can be filled by the user, or be set with default
47  * values
48  * by the ref FLEXIO_MCULCD_GetDefaultConfig.
49  *
50  * param base Pointer to the FLEXIO_MCULCD_Type structure.
51  * param config Pointer to the flexio_mculcd_config_t structure.
52  * param srcClock_Hz FlexIO source clock in Hz.
53  * retval kStatus_Success Initialization success.
54  * retval kStatus_InvalidArgument Initialization failed because of invalid
55  * argument.
56  */
FLEXIO_MCULCD_Init(FLEXIO_MCULCD_Type * base,flexio_mculcd_config_t * config,uint32_t srcClock_Hz)57 status_t FLEXIO_MCULCD_Init(FLEXIO_MCULCD_Type *base, flexio_mculcd_config_t *config, uint32_t srcClock_Hz)
58 {
59     assert(NULL != config);
60 
61     flexio_config_t flexioConfig = {config->enable, config->enableInDoze, config->enableInDebug,
62                                     config->enableFastAccess};
63 
64     FLEXIO_Init(base->flexioBase, &flexioConfig);
65 
66     if (kStatus_Success != FLEXIO_MCULCD_SetBaudRate(base, config->baudRate_Bps, srcClock_Hz))
67     {
68         return kStatus_Success;
69     }
70 
71     base->setCSPin(true);
72     base->setRSPin(true);
73 
74     return kStatus_Success;
75 }
76 
77 /*!
78  * brief Resets the FLEXIO_MCULCD timer and shifter configuration.
79  *
80  * param base Pointer to the FLEXIO_MCULCD_Type.
81  */
FLEXIO_MCULCD_Deinit(FLEXIO_MCULCD_Type * base)82 void FLEXIO_MCULCD_Deinit(FLEXIO_MCULCD_Type *base)
83 {
84     FLEXIO_MCULCD_ClearSingleBeatWriteConfig(base);
85     FLEXIO_MCULCD_ClearSingleBeatReadConfig(base);
86 }
87 
88 /*!
89  * brief Gets the default configuration to configure the FlexIO MCULCD.
90  *
91  * The default configuration value is:
92  * code
93  *  config->enable = true;
94  *  config->enableInDoze = false;
95  *  config->enableInDebug = true;
96  *  config->enableFastAccess = true;
97  *  config->baudRate_Bps = 96000000U;
98  * endcode
99  * param Config Pointer to the flexio_mculcd_config_t structure.
100  */
FLEXIO_MCULCD_GetDefaultConfig(flexio_mculcd_config_t * config)101 void FLEXIO_MCULCD_GetDefaultConfig(flexio_mculcd_config_t *config)
102 {
103     assert(NULL != config);
104 
105     /* Initializes the configure structure to zero. */
106     (void)memset(config, 0, sizeof(*config));
107 
108     config->enable           = true;
109     config->enableInDoze     = false;
110     config->enableInDebug    = true;
111     config->enableFastAccess = true;
112     config->baudRate_Bps     = 96000000U;
113 }
114 
115 /*!
116  * brief Set desired baud rate.
117  *
118  * param base Pointer to the FLEXIO_MCULCD_Type structure.
119  * param baudRate_Bps Desired baud rate.
120  * param srcClock_Hz FLEXIO clock frequency in Hz.
121  * retval kStatus_Success Set successfully.
122  * retval kStatus_InvalidArgument Could not set the baud rate.
123  */
FLEXIO_MCULCD_SetBaudRate(FLEXIO_MCULCD_Type * base,uint32_t baudRate_Bps,uint32_t srcClock_Hz)124 status_t FLEXIO_MCULCD_SetBaudRate(FLEXIO_MCULCD_Type *base, uint32_t baudRate_Bps, uint32_t srcClock_Hz)
125 {
126     uint32_t baudRateDiv;
127     uint32_t baudRatePerDataLine;
128     uint32_t timerCompare;
129     status_t status;
130 
131     baudRatePerDataLine = baudRate_Bps / (uint32_t)FLEXIO_MCULCD_DATA_BUS_WIDTH;
132 
133     baudRateDiv = (srcClock_Hz + baudRatePerDataLine) / (baudRatePerDataLine * 2U);
134 
135     if ((0U == baudRateDiv) || (baudRateDiv > (FLEXIO_BAUDRATE_DIV_MASK + 1U)))
136     {
137         status = kStatus_InvalidArgument;
138     }
139     else
140     {
141         baudRateDiv--;
142 
143         timerCompare = base->flexioBase->TIMCMP[base->timerIndex];
144 
145         timerCompare = (timerCompare & ~FLEXIO_BAUDRATE_DIV_MASK) | baudRateDiv;
146 
147         base->flexioBase->TIMCMP[base->timerIndex] = timerCompare;
148 
149         status = kStatus_Success;
150     }
151 
152     return status;
153 }
154 
155 /*!
156  * brief Gets FlexIO MCULCD status flags.
157  *
158  * param base Pointer to the FLEXIO_MCULCD_Type structure.
159  * return status flag; OR'ed value or the ref _flexio_mculcd_status_flags.
160  *
161  * note Don't use this function with DMA APIs.
162  */
FLEXIO_MCULCD_GetStatusFlags(FLEXIO_MCULCD_Type * base)163 uint32_t FLEXIO_MCULCD_GetStatusFlags(FLEXIO_MCULCD_Type *base)
164 {
165     uint32_t ret = 0U;
166     uint32_t flags;
167 
168     /* Get shifter status. */
169     flags = FLEXIO_GetShifterStatusFlags(base->flexioBase);
170 
171     if (0U != (flags & (1UL << base->rxShifterEndIndex)))
172     {
173         ret |= (uint32_t)kFLEXIO_MCULCD_RxFullFlag;
174     }
175 
176     if (0U != (flags & (1UL << base->txShifterStartIndex)))
177     {
178         ret |= (uint32_t)kFLEXIO_MCULCD_TxEmptyFlag;
179     }
180 
181     return ret;
182 }
183 
184 /*!
185  * brief Clears FlexIO MCULCD status flags.
186  *
187  * param base Pointer to the FLEXIO_MCULCD_Type structure.
188  * param mask Status to clear, it is the OR'ed value of ref
189  * _flexio_mculcd_status_flags.
190  *
191  * note Don't use this function with DMA APIs.
192  */
FLEXIO_MCULCD_ClearStatusFlags(FLEXIO_MCULCD_Type * base,uint32_t mask)193 void FLEXIO_MCULCD_ClearStatusFlags(FLEXIO_MCULCD_Type *base, uint32_t mask)
194 {
195     uint32_t flags = 0U;
196 
197     /* Clear the shifter flags. */
198     if (0U != (mask & (uint32_t)kFLEXIO_MCULCD_RxFullFlag))
199     {
200         flags |= (1UL << base->rxShifterEndIndex);
201     }
202 
203     if (0U != (mask & (uint32_t)kFLEXIO_MCULCD_TxEmptyFlag))
204     {
205         flags |= (1UL << base->txShifterStartIndex);
206     }
207 
208     FLEXIO_ClearShifterStatusFlags(base->flexioBase, flags);
209 }
210 
211 /*!
212  * brief Enables the FlexIO MCULCD interrupt.
213  *
214  * This function enables the FlexIO MCULCD interrupt.
215  *
216  * param base Pointer to the FLEXIO_MCULCD_Type structure.
217  * param mask Interrupts to enable, it is the OR'ed value of ref
218  * _flexio_mculcd_interrupt_enable.
219  */
FLEXIO_MCULCD_EnableInterrupts(FLEXIO_MCULCD_Type * base,uint32_t mask)220 void FLEXIO_MCULCD_EnableInterrupts(FLEXIO_MCULCD_Type *base, uint32_t mask)
221 {
222     uint32_t interrupts = 0U;
223 
224     /* Enable shifter interrupts. */
225     if (0U != (mask & (uint32_t)kFLEXIO_MCULCD_RxFullFlag))
226     {
227         interrupts |= (1UL << base->rxShifterEndIndex);
228     }
229 
230     if (0U != (mask & (uint32_t)kFLEXIO_MCULCD_TxEmptyFlag))
231     {
232         interrupts |= (1UL << base->txShifterStartIndex);
233     }
234 
235     FLEXIO_EnableShifterStatusInterrupts(base->flexioBase, interrupts);
236 }
237 
238 /*!
239  * brief Disables the FlexIO MCULCD interrupt.
240  *
241  * This function disables the FlexIO MCULCD interrupt.
242  *
243  * param base Pointer to the FLEXIO_MCULCD_Type structure.
244  * param mask Interrupts to disable, it is the OR'ed value of ref
245  * _flexio_mculcd_interrupt_enable.
246  */
FLEXIO_MCULCD_DisableInterrupts(FLEXIO_MCULCD_Type * base,uint32_t mask)247 void FLEXIO_MCULCD_DisableInterrupts(FLEXIO_MCULCD_Type *base, uint32_t mask)
248 {
249     uint32_t interrupts = 0U;
250 
251     /* Disable shifter interrupts. */
252     if (0U != (mask & (uint32_t)kFLEXIO_MCULCD_RxFullFlag))
253     {
254         interrupts |= (1UL << base->rxShifterEndIndex);
255     }
256 
257     if (0U != (mask & (uint32_t)kFLEXIO_MCULCD_TxEmptyFlag))
258     {
259         interrupts |= (1UL << base->txShifterStartIndex);
260     }
261 
262     FLEXIO_DisableShifterStatusInterrupts(base->flexioBase, interrupts);
263 }
264 
265 /*!
266  * brief Read data from the FLEXIO MCULCD RX shifter buffer.
267  *
268  * Read data from the RX shift buffer directly, it does no check whether the
269  * buffer is empty or not.
270  *
271  * If the data bus width is 8-bit:
272  * code
273  * uint8_t value;
274  * value = (uint8_t)FLEXIO_MCULCD_ReadData(base);
275  * endcode
276  *
277  * If the data bus width is 16-bit:
278  * code
279  * uint16_t value;
280  * value = (uint16_t)FLEXIO_MCULCD_ReadData(base);
281  * endcode
282  *
283  * note This function returns the RX shifter buffer value (32-bit) directly.
284  * The return value should be converted according to data bus width.
285  *
286  * param base Pointer to the FLEXIO_MCULCD_Type structure.
287  * return The data read out.
288  *
289  * note Don't use this function with DMA APIs.
290  */
FLEXIO_MCULCD_ReadData(FLEXIO_MCULCD_Type * base)291 uint32_t FLEXIO_MCULCD_ReadData(FLEXIO_MCULCD_Type *base)
292 {
293 #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
294     return base->flexioBase->SHIFTBUFBYS[base->rxShifterEndIndex];
295 #else
296     return base->flexioBase->SHIFTBUFHWS[base->rxShifterEndIndex];
297 #endif
298 }
299 
300 /*!
301  * brief Configures the FLEXIO MCULCD to multiple beats write mode.
302  *
303  * At the begining multiple beats write operation, the FLEXIO MCULCD is configured to
304  * multiple beats write mode using this function. After write operation, the configuration
305  * is cleared by ref FLEXIO_MCULCD_ClearSingleBeatWriteConfig.
306  *
307  * param base Pointer to the FLEXIO_MCULCD_Type.
308  *
309  * note This is an internal used function, upper layer should not use.
310  */
FLEXIO_MCULCD_SetSingleBeatWriteConfig(FLEXIO_MCULCD_Type * base)311 void FLEXIO_MCULCD_SetSingleBeatWriteConfig(FLEXIO_MCULCD_Type *base)
312 {
313     /*
314      * This function will be called at the beginning of every data writing. For
315      * performance consideration, it access the FlexIO registers directly, but not
316      * call FlexIO driver APIs.
317      */
318 
319     uint32_t timerCompare;
320 
321     /* Enable the TX Shifter output. */
322     base->flexioBase->SHIFTCFG[base->txShifterStartIndex] =
323         FLEXIO_SHIFTCFG_PWIDTH((uint32_t)FLEXIO_MCULCD_DATA_BUS_WIDTH - 1U) |
324         FLEXIO_SHIFTCFG_INSRC(kFLEXIO_ShifterInputFromNextShifterOutput);
325 
326     base->flexioBase->SHIFTCTL[base->txShifterStartIndex] =
327         FLEXIO_SHIFTCTL_TIMSEL(base->timerIndex) | FLEXIO_SHIFTCTL_TIMPOL(kFLEXIO_ShifterTimerPolarityOnPositive) |
328         FLEXIO_SHIFTCTL_PINCFG(kFLEXIO_PinConfigOutput) | FLEXIO_SHIFTCTL_PINSEL(base->dataPinStartIndex) |
329         FLEXIO_SHIFTCTL_PINPOL(kFLEXIO_PinActiveHigh) | FLEXIO_SHIFTCTL_SMOD(kFLEXIO_ShifterModeTransmit);
330 
331     timerCompare = base->flexioBase->TIMCMP[base->timerIndex] & 0xFFU;
332 
333     /*
334      * TIMCMP[15:8] = (number of beats x 2) - 1. Because the number of beat is 1,
335      * so the TIMCMP[15:8] is 1.
336      */
337     base->flexioBase->TIMCMP[base->timerIndex] = (1UL << 8U) | timerCompare;
338 
339     /* Use TX shifter flag as the inverted timer trigger. Timer output to WR/EN pin. */
340     base->flexioBase->TIMCFG[base->timerIndex] =
341         FLEXIO_TIMCFG_TIMOUT(kFLEXIO_TimerOutputOneNotAffectedByReset) |
342         FLEXIO_TIMCFG_TIMDEC(kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput) |
343         FLEXIO_TIMCFG_TIMRST(kFLEXIO_TimerResetNever) | FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnTimerCompare) |
344         FLEXIO_TIMCFG_TIMENA(kFLEXIO_TimerEnableOnTriggerHigh) | FLEXIO_TIMCFG_TSTOP(kFLEXIO_TimerStopBitDisabled) |
345         FLEXIO_TIMCFG_TSTART(kFLEXIO_TimerStartBitDisabled);
346 
347     base->flexioBase->TIMCTL[base->timerIndex] =
348         FLEXIO_TIMCTL_TRGSEL(FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->txShifterStartIndex)) |
349         FLEXIO_TIMCTL_TRGPOL(kFLEXIO_TimerTriggerPolarityActiveLow) |
350         FLEXIO_TIMCTL_TRGSRC(kFLEXIO_TimerTriggerSourceInternal) | FLEXIO_TIMCTL_PINCFG(kFLEXIO_PinConfigOutput) |
351         FLEXIO_TIMCTL_PINSEL(base->ENWRPinIndex) | FLEXIO_TIMCTL_PINPOL(kFLEXIO_PinActiveLow) |
352         FLEXIO_TIMCTL_TIMOD(kFLEXIO_TimerModeDual8BitBaudBit);
353 }
354 
355 /*!
356  * brief Clear the FLEXIO MCULCD multiple beats write mode configuration.
357  *
358  * Clear the write configuration set by ref FLEXIO_MCULCD_SetSingleBeatWriteConfig.
359  *
360  * param base Pointer to the FLEXIO_MCULCD_Type.
361  *
362  * note This is an internal used function, upper layer should not use.
363  */
FLEXIO_MCULCD_ClearSingleBeatWriteConfig(FLEXIO_MCULCD_Type * base)364 void FLEXIO_MCULCD_ClearSingleBeatWriteConfig(FLEXIO_MCULCD_Type *base)
365 {
366     /* Disable the timer. */
367     base->flexioBase->TIMCTL[base->timerIndex] = 0U;
368     base->flexioBase->TIMCFG[base->timerIndex] = 0U;
369     /* Clear the timer flag. */
370     base->flexioBase->TIMSTAT = (1UL << base->timerIndex);
371     /* Stop the TX shifter. */
372     base->flexioBase->SHIFTCTL[base->txShifterStartIndex] = 0U;
373     base->flexioBase->SHIFTCFG[base->txShifterStartIndex] = 0U;
374     /* Clear the shifter flag. */
375     base->flexioBase->SHIFTSTAT = (1UL << base->txShifterStartIndex);
376 }
377 
378 /*!
379  * brief Configures the FLEXIO MCULCD to multiple beats read mode.
380  *
381  * At the begining or multiple beats read operation, the FLEXIO MCULCD is configured
382  * to multiple beats read mode using this function. After read operation, the configuration
383  * is cleared by ref FLEXIO_MCULCD_ClearSingleBeatReadConfig.
384  *
385  * param base Pointer to the FLEXIO_MCULCD_Type.
386  *
387  * note This is an internal used function, upper layer should not use.
388  */
FLEXIO_MCULCD_SetSingleBeatReadConfig(FLEXIO_MCULCD_Type * base)389 void FLEXIO_MCULCD_SetSingleBeatReadConfig(FLEXIO_MCULCD_Type *base)
390 {
391     /*
392      * This function will be called at the beginning of every data reading. For
393      * performance consideration, it access the FlexIO registers directly, but not
394      * call FlexIO driver APIs.
395      */
396 
397     uint8_t timerPin;
398     uint32_t timerCompare;
399     flexio_pin_polarity_t timerPinPolarity;
400 
401     /* Timer output to RD pin (8080 mode), to WR/EN pin in 6800 mode. */
402     if (kFLEXIO_MCULCD_8080 == base->busType)
403     {
404         timerPin         = base->RDPinIndex;
405         timerPinPolarity = kFLEXIO_PinActiveLow;
406     }
407     else
408     {
409         timerPin         = base->ENWRPinIndex;
410         timerPinPolarity = kFLEXIO_PinActiveHigh;
411     }
412 
413     /* Enable the RX Shifter input. */
414     base->flexioBase->SHIFTCFG[base->rxShifterEndIndex] =
415         FLEXIO_SHIFTCFG_PWIDTH((uint32_t)FLEXIO_MCULCD_DATA_BUS_WIDTH - 1U);
416 
417     base->flexioBase->SHIFTCTL[base->rxShifterEndIndex] =
418         FLEXIO_SHIFTCTL_TIMSEL(base->timerIndex) | FLEXIO_SHIFTCTL_TIMPOL(kFLEXIO_ShifterTimerPolarityOnNegitive) |
419         FLEXIO_SHIFTCTL_PINCFG(kFLEXIO_PinConfigOutputDisabled) | FLEXIO_SHIFTCTL_PINSEL(base->dataPinStartIndex) |
420         FLEXIO_SHIFTCTL_PINPOL(kFLEXIO_PinActiveHigh) | FLEXIO_SHIFTCTL_SMOD(kFLEXIO_ShifterModeReceive);
421 
422     /* Use RX shifter flag as the inverted timer trigger. */
423     base->flexioBase->TIMCFG[base->timerIndex] =
424         FLEXIO_TIMCFG_TIMOUT(kFLEXIO_TimerOutputOneNotAffectedByReset) |
425         FLEXIO_TIMCFG_TIMDEC(kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput) |
426         FLEXIO_TIMCFG_TIMRST(kFLEXIO_TimerResetNever) | FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnTimerCompare) |
427         FLEXIO_TIMCFG_TIMENA(kFLEXIO_TimerEnableOnTriggerHigh) |
428         FLEXIO_TIMCFG_TSTOP(kFLEXIO_TimerStopBitEnableOnTimerDisable) |
429         FLEXIO_TIMCFG_TSTART(kFLEXIO_TimerStartBitDisabled);
430 
431     timerCompare = base->flexioBase->TIMCMP[base->timerIndex] & 0xFFU;
432 
433     /*
434      * TIMCMP[15:8] = (number of beats x 2) - 1. Because the number of beat is 1,
435      * so the TIMCMP[15:8] is 1.
436      */
437     base->flexioBase->TIMCMP[base->timerIndex] = (1UL << 8U) | timerCompare;
438 
439     base->flexioBase->TIMCTL[base->timerIndex] |=
440         FLEXIO_TIMCTL_TRGSEL(FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->rxShifterEndIndex)) |
441         FLEXIO_TIMCTL_TRGPOL(kFLEXIO_TimerTriggerPolarityActiveLow) |
442         FLEXIO_TIMCTL_TRGSRC(kFLEXIO_TimerTriggerSourceInternal) | FLEXIO_TIMCTL_PINCFG(kFLEXIO_PinConfigOutput) |
443         FLEXIO_TIMCTL_PINSEL(timerPin) | FLEXIO_TIMCTL_PINPOL(timerPinPolarity) |
444         FLEXIO_TIMCTL_TIMOD(kFLEXIO_TimerModeDual8BitBaudBit);
445 }
446 
447 /*!
448  * brief Clear the FLEXIO MCULCD multiple beats read mode configuration.
449  *
450  * Clear the read configuration set by ref FLEXIO_MCULCD_SetSingleBeatReadConfig.
451  *
452  * param base Pointer to the FLEXIO_MCULCD_Type.
453  *
454  * note This is an internal used function, upper layer should not use.
455  */
FLEXIO_MCULCD_ClearSingleBeatReadConfig(FLEXIO_MCULCD_Type * base)456 void FLEXIO_MCULCD_ClearSingleBeatReadConfig(FLEXIO_MCULCD_Type *base)
457 {
458     /* Disable the timer. */
459     base->flexioBase->TIMCTL[base->timerIndex] = 0U;
460     base->flexioBase->TIMCFG[base->timerIndex] = 0U;
461     /* Clear the timer flag. */
462     base->flexioBase->TIMSTAT = (1UL << base->timerIndex);
463     /* Stop the RX shifter. */
464     base->flexioBase->SHIFTCTL[base->rxShifterEndIndex] = 0U;
465     base->flexioBase->SHIFTCFG[base->rxShifterEndIndex] = 0U;
466     /* Clear the shifter flag. */
467     base->flexioBase->SHIFTSTAT = (1UL << base->rxShifterEndIndex);
468 }
469 
470 /*!
471  * brief Configures the FLEXIO MCULCD to multiple beats write mode.
472  *
473  * At the begining multiple beats write operation, the FLEXIO MCULCD is configured to
474  * multiple beats write mode using this function. After write operation, the configuration
475  * is cleared by ref FLEXIO_MCULCD_ClearMultBeatsWriteConfig.
476  *
477  * param base Pointer to the FLEXIO_MCULCD_Type.
478  *
479  * note This is an internal used function, upper layer should not use.
480  */
FLEXIO_MCULCD_SetMultiBeatsWriteConfig(FLEXIO_MCULCD_Type * base)481 void FLEXIO_MCULCD_SetMultiBeatsWriteConfig(FLEXIO_MCULCD_Type *base)
482 {
483     /*
484      * This function will be called at the beginning of every data writing. For
485      * performance consideration, it access the FlexIO registers directly, but not
486      * call FlexIO driver APIs.
487      */
488 
489     uint32_t timerCompare;
490     uint8_t beats;
491     uint8_t i;
492 
493     /* Enable the TX Shifter output. */
494     base->flexioBase->SHIFTCFG[base->txShifterStartIndex] =
495         FLEXIO_SHIFTCFG_PWIDTH((uint32_t)FLEXIO_MCULCD_DATA_BUS_WIDTH - 1U) |
496         FLEXIO_SHIFTCFG_INSRC(kFLEXIO_ShifterInputFromNextShifterOutput);
497 
498     base->flexioBase->SHIFTCTL[base->txShifterStartIndex] =
499         FLEXIO_SHIFTCTL_TIMSEL(base->timerIndex) | FLEXIO_SHIFTCTL_TIMPOL(kFLEXIO_ShifterTimerPolarityOnPositive) |
500         FLEXIO_SHIFTCTL_PINCFG(kFLEXIO_PinConfigOutput) | FLEXIO_SHIFTCTL_PINSEL(base->dataPinStartIndex) |
501         FLEXIO_SHIFTCTL_PINPOL(kFLEXIO_PinActiveHigh) | FLEXIO_SHIFTCTL_SMOD(kFLEXIO_ShifterModeTransmit);
502 
503     for (i = base->txShifterStartIndex + 1U; i <= base->txShifterEndIndex; i++)
504     {
505         base->flexioBase->SHIFTCFG[i] = FLEXIO_SHIFTCFG_PWIDTH((uint32_t)FLEXIO_MCULCD_DATA_BUS_WIDTH - 1U) |
506                                         FLEXIO_SHIFTCFG_INSRC(kFLEXIO_ShifterInputFromNextShifterOutput);
507 
508         base->flexioBase->SHIFTCTL[i] =
509             FLEXIO_SHIFTCTL_TIMSEL(base->timerIndex) | FLEXIO_SHIFTCTL_TIMPOL(kFLEXIO_ShifterTimerPolarityOnPositive) |
510             FLEXIO_SHIFTCTL_PINCFG(kFLEXIO_PinConfigOutputDisabled) | FLEXIO_SHIFTCTL_PINSEL(0) |
511             FLEXIO_SHIFTCTL_PINPOL(kFLEXIO_PinActiveHigh) | FLEXIO_SHIFTCTL_SMOD(kFLEXIO_ShifterModeTransmit);
512     }
513 
514     timerCompare = base->flexioBase->TIMCMP[base->timerIndex] & 0xFFU;
515 
516 #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
517     beats = 4U * (base->txShifterEndIndex - base->txShifterStartIndex + 1U);
518 #else
519     beats = 2U * (base->txShifterEndIndex - base->txShifterStartIndex + 1U);
520 #endif
521 
522     /*
523      * TIMCMP[15:8] = (number of beats x 2) - 1.
524      */
525     base->flexioBase->TIMCMP[base->timerIndex] = ((beats * 2UL - 1UL) << 8U) | timerCompare;
526 
527     /* Use TX shifter flag as the inverted timer trigger. Timer output to WR/EN pin. */
528     base->flexioBase->TIMCFG[base->timerIndex] =
529         FLEXIO_TIMCFG_TIMOUT(kFLEXIO_TimerOutputOneNotAffectedByReset) |
530         FLEXIO_TIMCFG_TIMDEC(kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput) |
531         FLEXIO_TIMCFG_TIMRST(kFLEXIO_TimerResetNever) | FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnTimerCompare) |
532         FLEXIO_TIMCFG_TIMENA(kFLEXIO_TimerEnableOnTriggerHigh) | FLEXIO_TIMCFG_TSTOP(kFLEXIO_TimerStopBitDisabled) |
533         FLEXIO_TIMCFG_TSTART(kFLEXIO_TimerStartBitDisabled);
534 
535     base->flexioBase->TIMCTL[base->timerIndex] =
536         FLEXIO_TIMCTL_TRGSEL(FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->txShifterEndIndex)) |
537         FLEXIO_TIMCTL_TRGPOL(kFLEXIO_TimerTriggerPolarityActiveLow) |
538         FLEXIO_TIMCTL_TRGSRC(kFLEXIO_TimerTriggerSourceInternal) | FLEXIO_TIMCTL_PINCFG(kFLEXIO_PinConfigOutput) |
539         FLEXIO_TIMCTL_PINSEL(base->ENWRPinIndex) | FLEXIO_TIMCTL_PINPOL(kFLEXIO_PinActiveLow) |
540         FLEXIO_TIMCTL_TIMOD(kFLEXIO_TimerModeDual8BitBaudBit);
541 }
542 
543 /*!
544  * brief Clear the FLEXIO MCULCD multiple beats write mode configuration.
545  *
546  * Clear the write configuration set by ref FLEXIO_MCULCD_SetMultBeatsWriteConfig.
547  *
548  * param base Pointer to the FLEXIO_MCULCD_Type.
549  *
550  * note This is an internal used function, upper layer should not use.
551  */
FLEXIO_MCULCD_ClearMultiBeatsWriteConfig(FLEXIO_MCULCD_Type * base)552 void FLEXIO_MCULCD_ClearMultiBeatsWriteConfig(FLEXIO_MCULCD_Type *base)
553 {
554     uint8_t i;
555     uint32_t statusFlags = 0U;
556 
557     /* Disable the timer. */
558     base->flexioBase->TIMCTL[base->timerIndex] = 0U;
559     base->flexioBase->TIMCFG[base->timerIndex] = 0U;
560     /* Clear the timer flag. */
561     base->flexioBase->TIMSTAT = (1UL << base->timerIndex);
562 
563     /* Stop the TX shifter. */
564     for (i = base->txShifterStartIndex; i <= base->txShifterEndIndex; i++)
565     {
566         base->flexioBase->SHIFTCFG[i] = 0U;
567         base->flexioBase->SHIFTCTL[i] = 0U;
568         statusFlags |= (1UL << i);
569     }
570     /* Clear the shifter flag. */
571     base->flexioBase->SHIFTSTAT = statusFlags;
572 }
573 
574 /*!
575  * brief Configures the FLEXIO MCULCD to multiple beats read mode.
576  *
577  * At the begining or multiple beats read operation, the FLEXIO MCULCD is configured
578  * to multiple beats read mode using this function. After read operation, the configuration
579  * is cleared by ref FLEXIO_MCULCD_ClearMultBeatsReadConfig.
580  *
581  * param base Pointer to the FLEXIO_MCULCD_Type.
582  *
583  * note This is an internal used function, upper layer should not use.
584  */
FLEXIO_MCULCD_SetMultiBeatsReadConfig(FLEXIO_MCULCD_Type * base)585 void FLEXIO_MCULCD_SetMultiBeatsReadConfig(FLEXIO_MCULCD_Type *base)
586 {
587     /*
588      * This function will be called at the beginning of every data reading. For
589      * performance consideration, it access the FlexIO registers directly, but not
590      * call FlexIO driver APIs.
591      */
592 
593     uint8_t timerPin;
594     uint8_t beats;
595     uint8_t i;
596     uint32_t timerCompare;
597     flexio_pin_polarity_t timerPinPolarity;
598 
599     /* Timer output to RD pin (8080 mode), to WR/EN pin in 6800 mode. */
600     if (kFLEXIO_MCULCD_8080 == base->busType)
601     {
602         timerPin         = base->RDPinIndex;
603         timerPinPolarity = kFLEXIO_PinActiveLow;
604     }
605     else
606     {
607         timerPin         = base->ENWRPinIndex;
608         timerPinPolarity = kFLEXIO_PinActiveHigh;
609     }
610 
611     /* Enable the RX Shifter input. */
612     for (i = base->rxShifterStartIndex; i < base->rxShifterEndIndex; i++)
613     {
614         base->flexioBase->SHIFTCFG[i] = FLEXIO_SHIFTCFG_PWIDTH((uint32_t)FLEXIO_MCULCD_DATA_BUS_WIDTH - 1U) |
615                                         FLEXIO_SHIFTCFG_INSRC(kFLEXIO_ShifterInputFromNextShifterOutput);
616 
617         base->flexioBase->SHIFTCTL[i] =
618             FLEXIO_SHIFTCTL_TIMSEL(base->timerIndex) | FLEXIO_SHIFTCTL_TIMPOL(kFLEXIO_ShifterTimerPolarityOnNegitive) |
619             FLEXIO_SHIFTCTL_PINCFG(kFLEXIO_PinConfigOutputDisabled) | FLEXIO_SHIFTCTL_PINSEL(base->dataPinStartIndex) |
620             FLEXIO_SHIFTCTL_PINPOL(kFLEXIO_PinActiveHigh) | FLEXIO_SHIFTCTL_SMOD(kFLEXIO_ShifterModeReceive);
621     }
622 
623     base->flexioBase->SHIFTCFG[base->rxShifterEndIndex] =
624         FLEXIO_SHIFTCFG_PWIDTH((uint32_t)FLEXIO_MCULCD_DATA_BUS_WIDTH - 1U);
625     base->flexioBase->SHIFTCTL[base->rxShifterEndIndex] =
626         FLEXIO_SHIFTCTL_TIMSEL(base->timerIndex) | FLEXIO_SHIFTCTL_TIMPOL(kFLEXIO_ShifterTimerPolarityOnNegitive) |
627         FLEXIO_SHIFTCTL_PINCFG(kFLEXIO_PinConfigOutputDisabled) | FLEXIO_SHIFTCTL_PINSEL(base->dataPinStartIndex) |
628         FLEXIO_SHIFTCTL_PINPOL(kFLEXIO_PinActiveHigh) | FLEXIO_SHIFTCTL_SMOD(kFLEXIO_ShifterModeReceive);
629 
630     timerCompare = base->flexioBase->TIMCMP[base->timerIndex] & 0xFFU;
631 
632 #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
633     beats = 4U * (base->rxShifterEndIndex - base->rxShifterStartIndex + 1U);
634 #else
635     beats = 2U * (base->rxShifterEndIndex - base->rxShifterStartIndex + 1U);
636 #endif
637 
638     /*
639      * TIMCMP[15:8] = (number of beats x 2) - 1.
640      */
641     base->flexioBase->TIMCMP[base->timerIndex] = ((beats * 2UL - 1UL) << 8U) | timerCompare;
642 
643     /* Use RX shifter flag as the inverted timer trigger. */
644     base->flexioBase->TIMCFG[base->timerIndex] =
645         FLEXIO_TIMCFG_TIMOUT(kFLEXIO_TimerOutputOneNotAffectedByReset) |
646         FLEXIO_TIMCFG_TIMDEC(kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput) |
647         FLEXIO_TIMCFG_TIMRST(kFLEXIO_TimerResetNever) | FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnTimerCompare) |
648         FLEXIO_TIMCFG_TIMENA(kFLEXIO_TimerEnableOnTriggerHigh) |
649         FLEXIO_TIMCFG_TSTOP(kFLEXIO_TimerStopBitEnableOnTimerDisable) |
650         FLEXIO_TIMCFG_TSTART(kFLEXIO_TimerStartBitDisabled);
651 
652     base->flexioBase->TIMCTL[base->timerIndex] |=
653         FLEXIO_TIMCTL_TRGSEL(FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->rxShifterEndIndex)) |
654         FLEXIO_TIMCTL_TRGPOL(kFLEXIO_TimerTriggerPolarityActiveLow) |
655         FLEXIO_TIMCTL_TRGSRC(kFLEXIO_TimerTriggerSourceInternal) | FLEXIO_TIMCTL_PINCFG(kFLEXIO_PinConfigOutput) |
656         FLEXIO_TIMCTL_PINSEL(timerPin) | FLEXIO_TIMCTL_PINPOL(timerPinPolarity) |
657         FLEXIO_TIMCTL_TIMOD(kFLEXIO_TimerModeDual8BitBaudBit);
658 }
659 
660 /*!
661  * brief Clear the FLEXIO MCULCD multiple beats read mode configuration.
662  *
663  * Clear the read configuration set by ref FLEXIO_MCULCD_SetMultBeatsReadConfig.
664  *
665  * param base Pointer to the FLEXIO_MCULCD_Type.
666  *
667  * note This is an internal used function, upper layer should not use.
668  */
FLEXIO_MCULCD_ClearMultiBeatsReadConfig(FLEXIO_MCULCD_Type * base)669 void FLEXIO_MCULCD_ClearMultiBeatsReadConfig(FLEXIO_MCULCD_Type *base)
670 {
671     uint8_t i;
672     uint32_t statusFlags = 0U;
673 
674     /* Disable the timer. */
675     base->flexioBase->TIMCTL[base->timerIndex] = 0U;
676     base->flexioBase->TIMCFG[base->timerIndex] = 0U;
677     /* Clear the timer flag. */
678     base->flexioBase->TIMSTAT = (1UL << base->timerIndex);
679     /* Stop the RX shifter. */
680     for (i = base->rxShifterStartIndex; i <= base->rxShifterEndIndex; i++)
681     {
682         base->flexioBase->SHIFTCTL[i] = 0U;
683         base->flexioBase->SHIFTCFG[i] = 0U;
684         statusFlags |= (1UL << i);
685     }
686     /* Clear the shifter flag. */
687     base->flexioBase->SHIFTSTAT = statusFlags;
688 }
689 
690 /*!
691  * brief Wait for transmit data send out finished.
692  *
693  * Currently there is no effective method to wait for the data send out
694  * from the shiter, so here use a while loop to wait.
695  *
696  * note This is an internal used function.
697  */
FLEXIO_MCULCD_WaitTransmitComplete(void)698 void FLEXIO_MCULCD_WaitTransmitComplete(void)
699 {
700     uint32_t i = FLEXIO_MCULCD_WAIT_COMPLETE_TIME;
701 
702     while (0U != (i--))
703     {
704         __NOP();
705     }
706 }
707 
708 /*!
709  * brief Send command in blocking way.
710  *
711  * This function sends the command and returns when the command has been sent
712  * out.
713  *
714  * param base Pointer to the FLEXIO_MCULCD_Type structure.
715  * param command The command to send.
716  */
FLEXIO_MCULCD_WriteCommandBlocking(FLEXIO_MCULCD_Type * base,uint32_t command)717 void FLEXIO_MCULCD_WriteCommandBlocking(FLEXIO_MCULCD_Type *base, uint32_t command)
718 {
719     FLEXIO_Type *flexioBase = base->flexioBase;
720 
721     /* De-assert the RS pin. */
722     base->setRSPin(false);
723 
724     /* For 6800, de-assert the RDWR pin. */
725     if (kFLEXIO_MCULCD_6800 == base->busType)
726     {
727         base->setRDWRPin(false);
728     }
729 
730     /* Configure the timer and TX shifter. */
731     FLEXIO_MCULCD_SetSingleBeatWriteConfig(base);
732 
733     /* Write command to shifter buffer. */
734     flexioBase->SHIFTBUF[base->txShifterStartIndex] = command;
735 
736     /* Wait for command send out. */
737     while (0U == ((1UL << base->timerIndex) & FLEXIO_GetTimerStatusFlags(flexioBase)))
738     {
739     }
740 
741     /* Stop the timer and TX shifter. */
742     FLEXIO_MCULCD_ClearSingleBeatWriteConfig(base);
743 
744     /* Assert the RS pin. */
745     base->setRSPin(true);
746     /* For 6800, assert the RDWR pin. */
747     if (kFLEXIO_MCULCD_6800 == base->busType)
748     {
749         base->setRDWRPin(true);
750     }
751 }
752 
753 /*!
754  * brief Send data array in blocking way.
755  *
756  * This function sends the data array and returns when the data sent out.
757  *
758  * param base Pointer to the FLEXIO_MCULCD_Type structure.
759  * param data The data array to send.
760  * param size How many bytes to write.
761  */
FLEXIO_MCULCD_WriteDataArrayBlocking(FLEXIO_MCULCD_Type * base,const void * data,size_t size)762 void FLEXIO_MCULCD_WriteDataArrayBlocking(FLEXIO_MCULCD_Type *base, const void *data, size_t size)
763 {
764     assert(size > 0U);
765 
766     uint32_t i;
767 #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
768     const uint8_t *data8Bit;
769 #else
770     const uint16_t *data16Bit;
771 #endif
772     FLEXIO_Type *flexioBase = base->flexioBase;
773 
774     /* Assert the RS pin. */
775     base->setRSPin(true);
776     /* For 6800, de-assert the RDWR pin. */
777     if (kFLEXIO_MCULCD_6800 == base->busType)
778     {
779         base->setRDWRPin(false);
780     }
781 
782     /* Configure the timer and TX shifter. */
783     FLEXIO_MCULCD_SetSingleBeatWriteConfig(base);
784 
785 /* If data bus width is 8. */
786 #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
787     data8Bit = (const uint8_t *)data;
788 
789     for (i = 0; i < size; i++)
790     {
791         flexioBase->SHIFTBUF[base->txShifterStartIndex] = data8Bit[i];
792 
793         /* Wait for the data send out. */
794         while (0U == ((1UL << base->timerIndex) & flexioBase->TIMSTAT))
795         {
796         }
797 
798         /* Clear the timer stat. */
799         flexioBase->TIMSTAT = 1UL << base->timerIndex;
800     }
801 #else
802     data16Bit = (const uint16_t *)data;
803     size /= 2U;
804 
805     for (i = 0; i < size; i++)
806     {
807         flexioBase->SHIFTBUF[base->txShifterStartIndex] = data16Bit[i];
808 
809         /* Wait for the data send out. */
810         while (0U == ((1UL << base->timerIndex) & flexioBase->TIMSTAT))
811         {
812         }
813 
814         /* Clear the timer stat. */
815         flexioBase->TIMSTAT = 1UL << base->timerIndex;
816     }
817 #endif
818 
819     /* Stop the timer and TX shifter. */
820     FLEXIO_MCULCD_ClearSingleBeatWriteConfig(base);
821 }
822 
823 /*!
824  * brief Read data into array in blocking way.
825  *
826  * This function reads the data into array and returns when the data read
827  * finished.
828  *
829  * param base Pointer to the FLEXIO_MCULCD_Type structure.
830  * param data The array to save the data.
831  * param size How many bytes to read.
832  */
FLEXIO_MCULCD_ReadDataArrayBlocking(FLEXIO_MCULCD_Type * base,void * data,size_t size)833 void FLEXIO_MCULCD_ReadDataArrayBlocking(FLEXIO_MCULCD_Type *base, void *data, size_t size)
834 {
835     assert(size > 0U);
836 
837     uint32_t i;
838 
839 #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
840     uint8_t *data8Bit = (uint8_t *)data;
841 #else
842     uint16_t *data16Bit = (uint16_t *)data;
843 #endif
844     FLEXIO_Type *flexioBase = base->flexioBase;
845 
846     /* Assert the RS pin. */
847     base->setRSPin(true);
848     /* For 6800, de-assert the RDWR pin. */
849     if (kFLEXIO_MCULCD_6800 == base->busType)
850     {
851         base->setRDWRPin(false);
852     }
853 
854     /* Enable the timer and RX shifter. */
855     FLEXIO_MCULCD_SetSingleBeatReadConfig(base);
856 
857 /* If data bus width is 8. */
858 #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
859     for (i = 0; i < (size - 1U); i++)
860     {
861         /* Wait for shifter buffer full. */
862         while (0U == ((1UL << base->rxShifterEndIndex) & FLEXIO_GetShifterStatusFlags(flexioBase)))
863         {
864         }
865 
866         data8Bit[i] = (uint8_t)flexioBase->SHIFTBUFBYS[base->rxShifterEndIndex];
867     }
868 #else
869     /* Data bus width is 16. */
870     size /= 2U;
871 
872     for (i = 0; i < (size - 1U); i++)
873     {
874         /* Wait for shifter buffer full. */
875         while (0U == ((1UL << base->rxShifterEndIndex) & FLEXIO_GetShifterStatusFlags(flexioBase)))
876         {
877         }
878 
879         data16Bit[i] = (uint16_t)flexioBase->SHIFTBUFHWS[base->rxShifterEndIndex];
880     }
881 #endif
882 
883     /* Wait for shifter buffer full. */
884     while (0U == ((1UL << base->rxShifterEndIndex) & FLEXIO_GetShifterStatusFlags(flexioBase)))
885     {
886     }
887 
888     /* Stop the timer and disable the RX shifter. */
889     FLEXIO_MCULCD_ClearSingleBeatReadConfig(base);
890 
891 /* Read out the last data. */
892 #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
893     data8Bit[i] = (uint8_t)flexioBase->SHIFTBUFBYS[base->rxShifterEndIndex];
894 #else
895     data16Bit[i] = (uint16_t)flexioBase->SHIFTBUFHWS[base->rxShifterEndIndex];
896 #endif
897 }
898 
899 /*!
900  * brief Send the same value many times in blocking way.
901  *
902  * This function sends the same value many times. It could be used to clear the
903  * LCD screen. If the data bus width is 8, this function will send LSB 8 bits of
904  * p sameValue for p size times. If the data bus is 16, this function will send
905  * LSB 16 bits of p sameValue for p size / 2 times.
906  *
907  * param base Pointer to the FLEXIO_MCULCD_Type structure.
908  * param sameValue The same value to send.
909  * param size How many bytes to send.
910  */
FLEXIO_MCULCD_WriteSameValueBlocking(FLEXIO_MCULCD_Type * base,uint32_t sameValue,size_t size)911 void FLEXIO_MCULCD_WriteSameValueBlocking(FLEXIO_MCULCD_Type *base, uint32_t sameValue, size_t size)
912 {
913     assert(size > 0U);
914 
915     uint32_t i;
916     FLEXIO_Type *flexioBase = base->flexioBase;
917 
918 #if (16 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
919     size /= 2U;
920 #endif
921 
922     /* Assert the RS pin. */
923     base->setRSPin(true);
924     /* For 6800, de-assert the RDWR pin. */
925     if (kFLEXIO_MCULCD_6800 == base->busType)
926     {
927         base->setRDWRPin(false);
928     }
929 
930     /* Configure the timer and TX shifter. */
931     FLEXIO_MCULCD_SetSingleBeatWriteConfig(base);
932 
933     for (i = 0; i < size; i++)
934     {
935         flexioBase->SHIFTBUF[base->txShifterStartIndex] = sameValue;
936 
937         /* Wait for the data send out. */
938         while (0U == ((1UL << base->timerIndex) & flexioBase->TIMSTAT))
939         {
940         }
941 
942         /* Clear the timer stat. */
943         flexioBase->TIMSTAT = 1UL << base->timerIndex;
944     }
945 
946     /* Stop the timer and TX shifter. */
947     FLEXIO_MCULCD_ClearSingleBeatWriteConfig(base);
948 }
949 
950 /*!
951  * brief Performs a polling transfer.
952  *
953  * note The API does not return until the transfer finished.
954  *
955  * param base pointer to FLEXIO_MCULCD_Type structure.
956  * param xfer pointer to flexio_mculcd_transfer_t structure.
957  */
FLEXIO_MCULCD_TransferBlocking(FLEXIO_MCULCD_Type * base,flexio_mculcd_transfer_t * xfer)958 void FLEXIO_MCULCD_TransferBlocking(FLEXIO_MCULCD_Type *base, flexio_mculcd_transfer_t *xfer)
959 {
960     FLEXIO_MCULCD_StartTransfer(base);
961 
962     FLEXIO_MCULCD_WriteCommandBlocking(base, xfer->command);
963 
964     if (xfer->dataSize > 0U)
965     {
966         if (kFLEXIO_MCULCD_ReadArray == xfer->mode)
967         {
968             FLEXIO_MCULCD_ReadDataArrayBlocking(base, (uint8_t *)(xfer->dataAddrOrSameValue), xfer->dataSize);
969         }
970         else if (kFLEXIO_MCULCD_WriteArray == xfer->mode)
971         {
972             FLEXIO_MCULCD_WriteDataArrayBlocking(base, (uint8_t *)(xfer->dataAddrOrSameValue), xfer->dataSize);
973         }
974         else
975         {
976             FLEXIO_MCULCD_WriteSameValueBlocking(base, xfer->dataAddrOrSameValue, xfer->dataSize);
977         }
978     }
979 
980     FLEXIO_MCULCD_StopTransfer(base);
981 }
982 
983 /*!
984  * brief Initializes the FlexIO MCULCD handle, which is used in transactional
985  * functions.
986  *
987  * param base Pointer to the FLEXIO_MCULCD_Type structure.
988  * param handle Pointer to the flexio_mculcd_handle_t structure to store the
989  * transfer state.
990  * param callback The callback function.
991  * param userData The parameter of the callback function.
992  * retval kStatus_Success Successfully create the handle.
993  * retval kStatus_OutOfRange The FlexIO type/handle/ISR table out of range.
994  */
FLEXIO_MCULCD_TransferCreateHandle(FLEXIO_MCULCD_Type * base,flexio_mculcd_handle_t * handle,flexio_mculcd_transfer_callback_t callback,void * userData)995 status_t FLEXIO_MCULCD_TransferCreateHandle(FLEXIO_MCULCD_Type *base,
996                                             flexio_mculcd_handle_t *handle,
997                                             flexio_mculcd_transfer_callback_t callback,
998                                             void *userData)
999 {
1000     assert(NULL != handle);
1001 
1002     IRQn_Type flexio_irqs[] = FLEXIO_IRQS;
1003 
1004     /* Zero the handle. */
1005     (void)memset(handle, 0, sizeof(*handle));
1006 
1007     handle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle;
1008 
1009     /* Register callback and userData. */
1010     handle->completionCallback = callback;
1011     handle->userData           = userData;
1012 
1013     /* Enable interrupt in NVIC. */
1014     (void)EnableIRQ(flexio_irqs[FLEXIO_GetInstance(base->flexioBase)]);
1015 
1016     /* Save the context in global variables to support the double weak mechanism.
1017      */
1018     return FLEXIO_RegisterHandleIRQ(base, handle, FLEXIO_MCULCD_TransferHandleIRQ);
1019 }
1020 
1021 /*!
1022  * brief Transfer data using IRQ.
1023  *
1024  * This function sends data using IRQ. This is a non-blocking function, which
1025  * returns right away. When all data is sent out/received, the callback
1026  * function is called.
1027  *
1028  * param base Pointer to the FLEXIO_MCULCD_Type structure.
1029  * param handle Pointer to the flexio_mculcd_handle_t structure to store the
1030  * transfer state.
1031  * param xfer FlexIO MCULCD transfer structure. See #flexio_mculcd_transfer_t.
1032  * retval kStatus_Success Successfully start a transfer.
1033  * retval kStatus_InvalidArgument Input argument is invalid.
1034  * retval kStatus_FLEXIO_MCULCD_Busy MCULCD is busy with another transfer.
1035  */
FLEXIO_MCULCD_TransferNonBlocking(FLEXIO_MCULCD_Type * base,flexio_mculcd_handle_t * handle,flexio_mculcd_transfer_t * xfer)1036 status_t FLEXIO_MCULCD_TransferNonBlocking(FLEXIO_MCULCD_Type *base,
1037                                            flexio_mculcd_handle_t *handle,
1038                                            flexio_mculcd_transfer_t *xfer)
1039 {
1040     /* If previous transfer is in progress. */
1041     if ((uint32_t)kFLEXIO_MCULCD_StateIdle != handle->state)
1042     {
1043         return kStatus_FLEXIO_MCULCD_Busy;
1044     }
1045 
1046     /* Set the state in handle. */
1047     if (kFLEXIO_MCULCD_ReadArray == xfer->mode)
1048     {
1049         handle->state = (uint32_t)kFLEXIO_MCULCD_StateReadArray;
1050     }
1051     else if (kFLEXIO_MCULCD_WriteArray == xfer->mode)
1052     {
1053         handle->state = (uint32_t)kFLEXIO_MCULCD_StateWriteArray;
1054     }
1055     else
1056     {
1057         handle->state = (uint32_t)kFLEXIO_MCULCD_StateWriteSameValue;
1058     }
1059 
1060     /* Assert the nCS. */
1061     FLEXIO_MCULCD_StartTransfer(base);
1062 
1063     /* Send the command. */
1064     FLEXIO_MCULCD_WriteCommandBlocking(base, xfer->command);
1065 
1066     /* If transfer count is 0 (only to send command), return directly. */
1067     if (0U == xfer->dataSize)
1068     {
1069         handle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle;
1070 
1071         /* De-assert the nCS. */
1072         FLEXIO_MCULCD_StopTransfer(base);
1073 
1074         if (NULL != handle->completionCallback)
1075         {
1076             handle->completionCallback(base, handle, kStatus_FLEXIO_MCULCD_Idle, handle->userData);
1077         }
1078     }
1079     else
1080     {
1081 #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
1082         handle->dataCount = xfer->dataSize;
1083 #else
1084         handle->dataCount = xfer->dataSize / 2U;
1085 #endif
1086 
1087         handle->remainingCount = handle->dataCount;
1088 
1089         handle->dataAddrOrSameValue = xfer->dataAddrOrSameValue;
1090 
1091         /* Enable interrupt. */
1092         if (kFLEXIO_MCULCD_ReadArray == xfer->mode)
1093         {
1094             /* For 6800, assert the RDWR pin. */
1095             if (kFLEXIO_MCULCD_6800 == base->busType)
1096             {
1097                 base->setRDWRPin(true);
1098             }
1099             FLEXIO_MCULCD_SetSingleBeatReadConfig(base);
1100             FLEXIO_MCULCD_EnableInterrupts(base, (uint32_t)kFLEXIO_MCULCD_RxFullInterruptEnable);
1101         }
1102         else
1103         {
1104             /* For 6800, de-assert the RDWR pin. */
1105             if (kFLEXIO_MCULCD_6800 == base->busType)
1106             {
1107                 base->setRDWRPin(false);
1108             }
1109             FLEXIO_MCULCD_SetSingleBeatWriteConfig(base);
1110             FLEXIO_MCULCD_EnableInterrupts(base, (uint32_t)kFLEXIO_MCULCD_TxEmptyInterruptEnable);
1111         }
1112     }
1113 
1114     return kStatus_Success;
1115 }
1116 
1117 /*!
1118  * brief Aborts the data transfer, which used IRQ.
1119  *
1120  * param base Pointer to the FLEXIO_MCULCD_Type structure.
1121  * param handle Pointer to the flexio_mculcd_handle_t structure to store the
1122  * transfer state.
1123  */
FLEXIO_MCULCD_TransferAbort(FLEXIO_MCULCD_Type * base,flexio_mculcd_handle_t * handle)1124 void FLEXIO_MCULCD_TransferAbort(FLEXIO_MCULCD_Type *base, flexio_mculcd_handle_t *handle)
1125 {
1126     /* If no transfer in process, return directly. */
1127     if ((uint32_t)kFLEXIO_MCULCD_StateIdle == handle->state)
1128     {
1129         return;
1130     }
1131 
1132     /* Disable the interrupt. */
1133     FLEXIO_MCULCD_DisableInterrupts(
1134         base, (uint32_t)kFLEXIO_MCULCD_RxFullInterruptEnable | (uint32_t)kFLEXIO_MCULCD_TxEmptyInterruptEnable);
1135 
1136     if ((uint32_t)kFLEXIO_MCULCD_StateReadArray == handle->state)
1137     {
1138         /* Stop the timer and disable the RX shifter. */
1139         FLEXIO_MCULCD_ClearSingleBeatReadConfig(base);
1140     }
1141     else
1142     {
1143         /* Stop the timer and disable the TX shifter. */
1144         FLEXIO_MCULCD_ClearSingleBeatWriteConfig(base);
1145     }
1146 
1147     /* Clean the flags. */
1148     FLEXIO_MCULCD_ClearStatusFlags(base, (uint32_t)kFLEXIO_MCULCD_TxEmptyFlag | (uint32_t)kFLEXIO_MCULCD_RxFullFlag);
1149 
1150     /* De-assert the nCS. */
1151     FLEXIO_MCULCD_StopTransfer(base);
1152 
1153     handle->dataCount      = 0;
1154     handle->remainingCount = 0;
1155     handle->state          = (uint32_t)kFLEXIO_MCULCD_StateIdle;
1156 }
1157 
1158 /*!
1159  * brief Gets the data transfer status which used IRQ.
1160  *
1161  * param base Pointer to the FLEXIO_MCULCD_Type structure.
1162  * param handle Pointer to the flexio_mculcd_handle_t structure to store the
1163  * transfer state.
1164  * param count How many bytes transferred so far by the non-blocking transaction.
1165  * retval kStatus_Success Get the transferred count Successfully.
1166  * retval kStatus_NoTransferInProgress No transfer in process.
1167  */
FLEXIO_MCULCD_TransferGetCount(FLEXIO_MCULCD_Type * base,flexio_mculcd_handle_t * handle,size_t * count)1168 status_t FLEXIO_MCULCD_TransferGetCount(FLEXIO_MCULCD_Type *base, flexio_mculcd_handle_t *handle, size_t *count)
1169 {
1170     assert(NULL != count);
1171 
1172     if ((uint32_t)kFLEXIO_MCULCD_StateIdle == handle->state)
1173     {
1174         return kStatus_NoTransferInProgress;
1175     }
1176 
1177     *count = handle->dataCount - handle->remainingCount;
1178 
1179 #if (16 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
1180     *count *= 2U;
1181 #endif
1182 
1183     return kStatus_Success;
1184 }
1185 
1186 /*!
1187  * brief FlexIO MCULCD IRQ handler function.
1188  *
1189  * param base Pointer to the FLEXIO_MCULCD_Type structure.
1190  * param handle Pointer to the flexio_mculcd_handle_t structure to store the
1191  * transfer state.
1192  */
FLEXIO_MCULCD_TransferHandleIRQ(void * base,void * handle)1193 void FLEXIO_MCULCD_TransferHandleIRQ(void *base, void *handle)
1194 {
1195     FLEXIO_MCULCD_Type *flexioLcdMcuBase       = (FLEXIO_MCULCD_Type *)base;
1196     flexio_mculcd_handle_t *flexioLcdMcuHandle = (flexio_mculcd_handle_t *)handle;
1197     uint32_t statusFlags                       = FLEXIO_MCULCD_GetStatusFlags(flexioLcdMcuBase);
1198     uint32_t data;
1199 
1200     if ((uint32_t)kFLEXIO_MCULCD_StateReadArray == flexioLcdMcuHandle->state)
1201     {
1202         /* Handle the reading process. */
1203         while ((0U != ((uint32_t)kFLEXIO_MCULCD_RxFullFlag & statusFlags)) && (flexioLcdMcuHandle->remainingCount > 0U))
1204         {
1205             if (1U == flexioLcdMcuHandle->remainingCount)
1206             {
1207                 /* If this is the last data, stop the RX shifter and timer. */
1208                 FLEXIO_MCULCD_DisableInterrupts(flexioLcdMcuBase, (uint32_t)kFLEXIO_MCULCD_RxFullInterruptEnable);
1209                 FLEXIO_MCULCD_ClearSingleBeatReadConfig(flexioLcdMcuBase);
1210                 FLEXIO_MCULCD_StopTransfer(flexioLcdMcuBase);
1211             }
1212 
1213             /* Read out the data. */
1214             data = FLEXIO_MCULCD_ReadData(flexioLcdMcuBase);
1215 
1216 #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
1217             *(uint8_t *)(flexioLcdMcuHandle->dataAddrOrSameValue) = (uint8_t)data;
1218             flexioLcdMcuHandle->dataAddrOrSameValue++;
1219 #else
1220             *(uint16_t *)(flexioLcdMcuHandle->dataAddrOrSameValue) = (uint16_t)data;
1221             flexioLcdMcuHandle->dataAddrOrSameValue += 2U;
1222 #endif
1223 
1224             flexioLcdMcuHandle->remainingCount--;
1225 
1226             /* Transfer finished, call the callback. */
1227             if (0U == flexioLcdMcuHandle->remainingCount)
1228             {
1229                 flexioLcdMcuHandle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle;
1230 
1231                 if (NULL != flexioLcdMcuHandle->completionCallback)
1232                 {
1233                     flexioLcdMcuHandle->completionCallback(flexioLcdMcuBase, flexioLcdMcuHandle,
1234                                                            kStatus_FLEXIO_MCULCD_Idle, flexioLcdMcuHandle->userData);
1235                 }
1236             }
1237 
1238             /* Is the shifter buffer ready to send the next data? */
1239             statusFlags = FLEXIO_MCULCD_GetStatusFlags(flexioLcdMcuBase);
1240         }
1241     }
1242     else
1243     {
1244         /* Handle the writing process. */
1245         while ((0U != ((uint32_t)kFLEXIO_MCULCD_TxEmptyFlag & statusFlags)) &&
1246                (flexioLcdMcuHandle->remainingCount > 0U))
1247         {
1248             /* Send the data. */
1249             if ((uint32_t)kFLEXIO_MCULCD_StateWriteSameValue == flexioLcdMcuHandle->state)
1250             {
1251                 data = flexioLcdMcuHandle->dataAddrOrSameValue;
1252             }
1253             else
1254             {
1255 #if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
1256                 data = *(uint8_t *)(flexioLcdMcuHandle->dataAddrOrSameValue);
1257                 flexioLcdMcuHandle->dataAddrOrSameValue++;
1258 #else
1259                 data = *(uint16_t *)(flexioLcdMcuHandle->dataAddrOrSameValue);
1260                 flexioLcdMcuHandle->dataAddrOrSameValue += 2U;
1261 #endif
1262             }
1263 
1264             /* If this is the last data to send, delay to wait for the data shift out.  */
1265             if (1U == flexioLcdMcuHandle->remainingCount)
1266             {
1267                 FLEXIO_MCULCD_DisableInterrupts(flexioLcdMcuBase, (uint32_t)kFLEXIO_MCULCD_TxEmptyInterruptEnable);
1268 
1269                 /* Write the last data. */
1270                 FLEXIO_MCULCD_WriteData(flexioLcdMcuBase, data);
1271 
1272                 /* Wait for the last data send finished. */
1273                 FLEXIO_MCULCD_WaitTransmitComplete();
1274                 flexioLcdMcuHandle->remainingCount = 0;
1275 
1276                 FLEXIO_MCULCD_ClearSingleBeatWriteConfig(flexioLcdMcuBase);
1277                 FLEXIO_MCULCD_StopTransfer(flexioLcdMcuBase);
1278                 flexioLcdMcuHandle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle;
1279 
1280                 if (NULL != flexioLcdMcuHandle->completionCallback)
1281                 {
1282                     flexioLcdMcuHandle->completionCallback(flexioLcdMcuBase, flexioLcdMcuHandle,
1283                                                            kStatus_FLEXIO_MCULCD_Idle, flexioLcdMcuHandle->userData);
1284                 }
1285             }
1286             else
1287             {
1288                 FLEXIO_MCULCD_WriteData(flexioLcdMcuBase, data);
1289                 flexioLcdMcuHandle->remainingCount--;
1290             }
1291             /* Is the shifter buffer ready to send the next data? */
1292             statusFlags = FLEXIO_MCULCD_GetStatusFlags(flexioLcdMcuBase);
1293         }
1294     }
1295 }
1296