Skip to content

Commit cb883e7

Browse files
zejiang0jasonmmahadevan108
authored andcommitted
mcux-sdk-ng: flexio: spi: Fix SPI master CS continuous issue
- With current FLEXIO SPI master CS continuous mode implementation, the TX shifter register must be filled in time, otherwise the CS won't be continuous. - Before CS continuous mode was supported, the function FLEXIO_SPI_MasterTransferNonBlocking: 1. When it is called to transfer data, it fills one data frame to TX shifter buffer register first, then enables the FLEXIO interrupt. 2. Only enables the RX shift buffer register full interrupt, reads RX data and fills TX data in ISR. - This flow can't meet CS continuous mode requirement, because: After the first data frame written to TX shifter buffer register, the second data frame is only written after RX interrupt asserts. During this period, the TX shifter is not filled in time. CS is not continuous. - To fix this issue, the TX interrupt is also enabled in CS continuous mode, to make the second TX data be filled in time in ISR. But this fix is not good: - If FLEXIO interrupt is blocked by other higher priority interrupt, and not served in time, the CS will still not be continuous. - In the ISR, when no interrupt status flag assert (#221), the ISR should return directly, but current fix assumes TX interrupt occurs and writes TX shifter buffer. - This patch uses a new way to implement the CS continuous mode: - Only enable RX interrupt, don't enable TX interrupt - Change the timer1 working mode, to make sure CS is always low during whole data transfer, it is not necessary to always fill TX shifter buffer in time. Signed-off-by: Jason Yu <[email protected]>
1 parent 813ce67 commit cb883e7

File tree

2 files changed

+123
-41
lines changed

2 files changed

+123
-41
lines changed

mcux/mcux-sdk-ng/drivers/flexio/spi/fsl_flexio_spi.c

Lines changed: 121 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,41 @@ static void FLEXIO_SPI_TransferSendTransaction(FLEXIO_SPI_Type *base, flexio_spi
5252
*/
5353
static void FLEXIO_SPI_TransferReceiveTransaction(FLEXIO_SPI_Type *base, flexio_spi_master_handle_t *handle);
5454

55+
/*!
56+
* @brief Set the Timer 1 register TIMCFG
57+
*
58+
* This function is used for master mode. It sets the Timer 1 (used to control CS pin)
59+
* TIMCFG register based on CS continous mode configuration, and return the old
60+
* register value, for later recovery.
61+
*
62+
* @param base Pointer to FLEXIO_SPI_Type structure
63+
* @param csContinuous Use CS continuous mode or not.
64+
* @return The old TIMCFG register value.
65+
*/
66+
static uint32_t FLEXIO_SPI_MasterSetTimer1Cfg(FLEXIO_SPI_Type *base, bool csContinuous);
67+
68+
/*!
69+
* @brief Recover the Timer 1 register TIMCFG
70+
*
71+
* This function is used for master mode. It recovers the TIMCFG register using
72+
* the value got by @ref FLEXIO_SPI_MasterSetTimer1Cfg.
73+
*
74+
* @param base Pointer to FLEXIO_SPI_Type structure
75+
* @param The old TIMCFG register value.
76+
*/
77+
static void FLEXIO_SPI_MasterRecoverTimer1Cfg(FLEXIO_SPI_Type *base, uint32_t timer1Cfg);
78+
79+
/*!
80+
* @brief Force disable the Timer 1 register TIMCFG
81+
*
82+
* This function is used for master mode CS continuous mode. In this mode,
83+
* the timer1 is set to kFLEXIO_TimerDisableNever, so after all data transfer
84+
* done, this function should be called to disable the timer1.
85+
*
86+
* @param base Pointer to FLEXIO_SPI_Type structure
87+
*/
88+
static void FLEXIO_SPI_MasterForceDisableTimer1(FLEXIO_SPI_Type *base);
89+
5590
/*******************************************************************************
5691
* Variables
5792
******************************************************************************/
@@ -60,6 +95,64 @@ static void FLEXIO_SPI_TransferReceiveTransaction(FLEXIO_SPI_Type *base, flexio_
6095
* Codes
6196
******************************************************************************/
6297

98+
static uint32_t FLEXIO_SPI_MasterSetTimer1Cfg(FLEXIO_SPI_Type *base, bool csContinuous)
99+
{
100+
uint32_t timer1Cfg = base->flexioBase->TIMCFG[base->timerIndex[1]];
101+
102+
/*
103+
* Timer1 configuration for CS continuous and non-continuous modes.
104+
*
105+
* CS pin is configured to be logical one when timer1 enabled, so the
106+
* keypoint is:
107+
* - In CS non-continuous mode, set timers only enabled when the data frame
108+
* transfer is in progress.
109+
* - In CS continuous mode, set timer1 always enabled during data transfer.
110+
*
111+
* Non-continuous mode:
112+
* In this mode, enable timer1 when timer0 is enabled, and disable timer1
113+
* when timer0 is disabled. Timer0 controls SCK, it is enabled/disabled
114+
* when a data frame starts/stops, so timer1 is only enabled when
115+
* one data frame transfer is in progress.
116+
*
117+
* Continuous mode:
118+
* In this mode, enable timer1 when timer0 is enabled, in other word, timer1
119+
* will be enabled at the beginning of the whole data transfer. Timer1
120+
* will never be disabled, until FLEXIO_SPI_MasterForceDisableTimer1 is called
121+
* after all data transfer done. Also, the TIMDEC is set to
122+
* kFLEXIO_TimerDecSrcOnPinInputShiftPinInput, so that the timer won't
123+
* decrease in the whole process.
124+
*/
125+
126+
if (csContinuous)
127+
{
128+
base->flexioBase->TIMCFG[base->timerIndex[1]] =
129+
(base->flexioBase->TIMCFG[base->timerIndex[1]] & ~(FLEXIO_TIMCFG_TIMDIS_MASK | FLEXIO_TIMCFG_TIMDEC_MASK)) |
130+
FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableNever) |
131+
FLEXIO_TIMCFG_TIMDEC(kFLEXIO_TimerDecSrcOnPinInputShiftPinInput);
132+
}
133+
else
134+
{
135+
base->flexioBase->TIMCFG[base->timerIndex[1]] =
136+
(base->flexioBase->TIMCFG[base->timerIndex[1]] & ~(FLEXIO_TIMCFG_TIMDIS_MASK | FLEXIO_TIMCFG_TIMDEC_MASK)) |
137+
FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnPreTimerDisable) |
138+
FLEXIO_TIMCFG_TIMDEC(kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput);
139+
}
140+
141+
return timer1Cfg;
142+
}
143+
144+
static void FLEXIO_SPI_MasterRecoverTimer1Cfg(FLEXIO_SPI_Type *base, uint32_t timer1Cfg)
145+
{
146+
base->flexioBase->TIMCFG[base->timerIndex[1]] = timer1Cfg;
147+
}
148+
149+
static void FLEXIO_SPI_MasterForceDisableTimer1(FLEXIO_SPI_Type *base)
150+
{
151+
uint32_t timctl = base->flexioBase->TIMCTL[base->timerIndex[1]];
152+
base->flexioBase->TIMCTL[base->timerIndex[1]] = timctl & (~FLEXIO_TIMCTL_TIMOD_MASK);
153+
base->flexioBase->TIMCTL[base->timerIndex[1]] = timctl;
154+
}
155+
63156
static uint32_t FLEXIO_SPI_GetInstance(FLEXIO_SPI_Type *base)
64157
{
65158
return FLEXIO_GetInstance(base->flexioBase);
@@ -813,21 +906,11 @@ status_t FLEXIO_SPI_MasterTransferBlocking(FLEXIO_SPI_Type *base, flexio_spi_tra
813906
#if SPI_RETRY_TIMES
814907
uint32_t waitTimes;
815908
#endif
909+
status_t status = kStatus_Success;
910+
bool isCsContinuous = ((xfer->flags & (uint8_t)kFLEXIO_SPI_csContinuous) != 0U);
816911

817912
timerCmp &= 0x00FFU;
818-
819-
if ((xfer->flags & (uint8_t)kFLEXIO_SPI_csContinuous) != 0U)
820-
{
821-
base->flexioBase->TIMCFG[base->timerIndex[0]] =
822-
(base->flexioBase->TIMCFG[base->timerIndex[0]] & ~FLEXIO_TIMCFG_TSTOP_MASK) |
823-
FLEXIO_TIMCFG_TSTOP(kFLEXIO_TimerStopBitDisabled);
824-
}
825-
else
826-
{
827-
base->flexioBase->TIMCFG[base->timerIndex[0]] =
828-
(base->flexioBase->TIMCFG[base->timerIndex[0]] & ~FLEXIO_TIMCFG_TSTOP_MASK) |
829-
FLEXIO_TIMCFG_TSTOP(kFLEXIO_TimerStopBitEnableOnTimerDisable);
830-
}
913+
uint32_t timer1Cfg;
831914

832915
/* Configure the values in handle. */
833916
switch (dataFormat)
@@ -884,6 +967,8 @@ status_t FLEXIO_SPI_MasterTransferBlocking(FLEXIO_SPI_Type *base, flexio_spi_tra
884967
return kStatus_InvalidArgument;
885968
}
886969

970+
timer1Cfg = FLEXIO_SPI_MasterSetTimer1Cfg(base, isCsContinuous);
971+
887972
/* Configure transfer size. */
888973
base->flexioBase->TIMCMP[base->timerIndex[0]] = dataMode;
889974

@@ -902,7 +987,8 @@ status_t FLEXIO_SPI_MasterTransferBlocking(FLEXIO_SPI_Type *base, flexio_spi_tra
902987
#if SPI_RETRY_TIMES
903988
if (waitTimes == 0U)
904989
{
905-
return kStatus_FLEXIO_SPI_Timeout;
990+
status = kStatus_FLEXIO_SPI_Timeout;
991+
break;
906992
}
907993
#endif
908994
if (xfer->txData != NULL)
@@ -967,7 +1053,8 @@ status_t FLEXIO_SPI_MasterTransferBlocking(FLEXIO_SPI_Type *base, flexio_spi_tra
9671053
#if SPI_RETRY_TIMES
9681054
if (waitTimes == 0U)
9691055
{
970-
return kStatus_FLEXIO_SPI_Timeout;
1056+
status = kStatus_FLEXIO_SPI_Timeout;
1057+
break;
9711058
}
9721059
#endif
9731060
tmpData = FLEXIO_SPI_ReadData(base, direction);
@@ -1020,7 +1107,14 @@ status_t FLEXIO_SPI_MasterTransferBlocking(FLEXIO_SPI_Type *base, flexio_spi_tra
10201107
}
10211108
}
10221109

1023-
return kStatus_Success;
1110+
if (isCsContinuous)
1111+
{
1112+
FLEXIO_SPI_MasterForceDisableTimer1(base);
1113+
}
1114+
1115+
FLEXIO_SPI_MasterRecoverTimer1Cfg(base, timer1Cfg);
1116+
1117+
return status;
10241118
}
10251119

10261120
/*!
@@ -1097,24 +1191,9 @@ status_t FLEXIO_SPI_MasterTransferNonBlocking(FLEXIO_SPI_Type *base,
10971191
return kStatus_InvalidArgument;
10981192
}
10991193

1100-
/* Timer1 controls the CS signal which enables/disables(asserts/deasserts) when timer0 enable/disable. Timer0
1101-
enables when tx shifter is written and disables when timer compare. The timer compare event causes the
1102-
transmit shift registers to load which generates a tx register empty event. Since when timer stop bit is
1103-
disabled, a timer enable condition can be detected in the same cycle as a timer disable condition, so if
1104-
software writes the tx register upon the detection of tx register empty event, the timer enable condition
1105-
is triggered again, then the CS signal can remain low until software no longer writes the tx register. */
1106-
if ((xfer->flags & (uint8_t)kFLEXIO_SPI_csContinuous) != 0U)
1107-
{
1108-
base->flexioBase->TIMCFG[base->timerIndex[0]] =
1109-
(base->flexioBase->TIMCFG[base->timerIndex[0]] & ~FLEXIO_TIMCFG_TSTOP_MASK) |
1110-
FLEXIO_TIMCFG_TSTOP(kFLEXIO_TimerStopBitDisabled);
1111-
}
1112-
else
1113-
{
1114-
base->flexioBase->TIMCFG[base->timerIndex[0]] =
1115-
(base->flexioBase->TIMCFG[base->timerIndex[0]] & ~FLEXIO_TIMCFG_TSTOP_MASK) |
1116-
FLEXIO_TIMCFG_TSTOP(kFLEXIO_TimerStopBitEnableOnTimerDisable);
1117-
}
1194+
handle->isCsContinuous = ((xfer->flags & (uint8_t)kFLEXIO_SPI_csContinuous) != 0U);
1195+
1196+
handle->timer1Cfg = FLEXIO_SPI_MasterSetTimer1Cfg(base, handle->isCsContinuous);
11181197

11191198
/* Configure the values in handle */
11201199
switch (dataFormat)
@@ -1229,12 +1308,7 @@ status_t FLEXIO_SPI_MasterTransferNonBlocking(FLEXIO_SPI_Type *base,
12291308

12301309
/* Enable transmit and receive interrupt to handle rx. */
12311310
FLEXIO_SPI_EnableInterrupts(base, (uint32_t)kFLEXIO_SPI_RxFullInterruptEnable);
1232-
1233-
if ((xfer->flags & (uint8_t)kFLEXIO_SPI_csContinuous) != 0U)
1234-
{
1235-
FLEXIO_SPI_EnableInterrupts(base, (uint32_t)kFLEXIO_SPI_TxEmptyInterruptEnable);
1236-
}
1237-
1311+
12381312
return kStatus_Success;
12391313
}
12401314

@@ -1282,6 +1356,13 @@ void FLEXIO_SPI_MasterTransferAbort(FLEXIO_SPI_Type *base, flexio_spi_master_han
12821356
FLEXIO_SPI_DisableInterrupts(base, (uint32_t)kFLEXIO_SPI_RxFullInterruptEnable);
12831357
FLEXIO_SPI_DisableInterrupts(base, (uint32_t)kFLEXIO_SPI_TxEmptyInterruptEnable);
12841358

1359+
if (handle->isCsContinuous)
1360+
{
1361+
FLEXIO_SPI_MasterForceDisableTimer1(base);
1362+
}
1363+
1364+
FLEXIO_SPI_MasterRecoverTimer1Cfg(base, handle->timer1Cfg);
1365+
12851366
/* Transfer finished, set the state to idle. */
12861367
handle->state = (uint32_t)kFLEXIO_SPI_Idle;
12871368

@@ -1315,7 +1396,6 @@ void FLEXIO_SPI_MasterTransferHandleIRQ(void *spiType, void *spiHandle)
13151396
/* Receive interrupt. */
13161397
if ((status & (uint32_t)kFLEXIO_SPI_RxBufferFullFlag) == 0U)
13171398
{
1318-
FLEXIO_SPI_TransferSendTransaction(base, handle);
13191399
return;
13201400
}
13211401

mcux/mcux-sdk-ng/drivers/flexio/spi/fsl_flexio_spi.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,8 @@ struct _flexio_spi_master_handle
189189
flexio_spi_shift_direction_t direction; /*!< Shift direction. */
190190
flexio_spi_master_transfer_callback_t callback; /*!< FlexIO SPI callback. */
191191
void *userData; /*!< Callback parameter. */
192+
bool isCsContinuous; /*!< Is current transfer using CS continuous mode. */
193+
uint32_t timer1Cfg; /*!< TIMER1 TIMCFG regiser value backup. */
192194
};
193195

194196
/*******************************************************************************

0 commit comments

Comments
 (0)