Skip to content

Commit 88bd8a1

Browse files
committed
drivers/kinetis/spi: Fix Kinetis DSPI transfers in non-FIFO mode.
Fix a transfer issue in the Kinetis DSPI driver when operating with transmit and receive FIFOs disabled (`MCR[DIS_TXF]=1`, `MCR[DIS_RXF]=1`). In this mode, the DSPI module behaves as a simple double-buffered SPI interface without TX staging. When FIFOs are disabled, `PUSHR` acts as a single 32-bit command/data register. Partial (16-bit) writes to its upper or lower halves can result in incomplete or corrupted transfers. This patch ensures the full 32-bit packet is prepared and written in a single operation. * Resolves broken SPI transactions with LAN9252 (EasyCAT). * Improves reliability in non-FIFO DSPI configurations. * No impact on DMA or FIFO-enabled modes. Signed-off-by: trns1997 <[email protected]>
1 parent 9053b60 commit 88bd8a1

File tree

6 files changed

+84
-19
lines changed

6 files changed

+84
-19
lines changed

arch/arm/src/kinetis/kinetis_spi.c

Lines changed: 49 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ static inline void spi_putreg8(struct kinetis_spidev_s *priv,
134134
uint8_t offset, uint8_t value);
135135
static inline uint16_t spi_readword(struct kinetis_spidev_s *priv);
136136
static inline void spi_writeword(struct kinetis_spidev_s *priv,
137-
uint16_t word);
137+
uint16_t word, bool first_word);
138138

139139
static inline void spi_run(struct kinetis_spidev_s *priv,
140140
bool enable);
@@ -559,27 +559,51 @@ static inline void spi_write_control(struct kinetis_spidev_s *priv,
559559
* Name: spi_writeword
560560
*
561561
* Description:
562-
* Write one 16 bit word to SPI TX FIFO
562+
* Write one word to SPI TX FIFO or single-entry buffer.
563+
* In non-FIFO mode, performs 32-bit write including control bits.
564+
* In FIFO-enabled mode, writes only the data (control handled separately).
563565
*
564566
* Input Parameters:
565567
* priv - Device-specific state data
566568
* word - word to send
569+
* first_word - Flag to set control in case of FIFO disabled
567570
*
568571
* Returned Value:
569572
* None
570573
*
571574
****************************************************************************/
572575

573576
static inline void spi_writeword(struct kinetis_spidev_s *priv,
574-
uint16_t word)
577+
uint16_t word, bool first_word)
575578
{
579+
uint32_t mcr = spi_getreg(priv, KINETIS_SPI_MCR_OFFSET);
580+
uint32_t pushr_val;
581+
576582
/* Wait until there is space in the fifo */
577583

578584
spi_wait_status(priv, SPI_SR_TFFF);
579585

580-
/* Write the data to transmitted to the SPI Data Register */
586+
if (mcr & SPI_MCR_DIS_TXF)
587+
{
588+
/* FIFO disabled: 32-bit write including control + data */
589+
590+
pushr_val = SPI_PUSHR_TXDATA(word);
591+
592+
if (first_word)
593+
{
594+
/* Set Control word */
595+
596+
pushr_val |= SPI_PUSHR_CTAS_CTAR0 | SPI_PUSHR_CTCNT;
597+
}
598+
599+
spi_putreg(priv, KINETIS_SPI_PUSHR_OFFSET, pushr_val);
600+
}
601+
else
602+
{
603+
/* FIFO enabled: write only data; control handled separately */
581604

582-
spi_putreg16(priv, KINETIS_SPI_PUSHR_OFFSET, SPI_PUSHR_TXDATA(word));
605+
spi_putreg16(priv, KINETIS_SPI_PUSHR_OFFSET, SPI_PUSHR_TXDATA(word));
606+
}
583607
}
584608

585609
/****************************************************************************
@@ -964,16 +988,27 @@ static uint16_t spi_send_data(struct kinetis_spidev_s *priv, uint16_t wd,
964988
bool last)
965989
{
966990
uint16_t ret;
991+
uint32_t mcr = spi_getreg(priv, KINETIS_SPI_MCR_OFFSET);
992+
bool first_word = false;
967993

968-
/* On first write set control word and start transfer */
994+
/* Start module and write control if FIFO enabled on first transfer */
969995

970-
if (0 == (spi_getreg(priv, KINETIS_SPI_SR_OFFSET) & SPI_SR_TXRXS))
996+
if ((spi_getreg(priv, KINETIS_SPI_SR_OFFSET) & SPI_SR_TXRXS) == 0)
971997
{
972998
spi_run(priv, true);
973-
spi_write_control(priv, SPI_PUSHR_CTAS_CTAR0 | SPI_PUSHR_CTCNT);
999+
first_word = true;
1000+
1001+
if ((mcr & SPI_MCR_DIS_TXF) == 0)
1002+
{
1003+
/* FIFO enabled: safe to write control separately */
1004+
1005+
spi_write_control(priv, SPI_PUSHR_CTAS_CTAR0 | SPI_PUSHR_CTCNT);
1006+
}
1007+
1008+
/* Non-FIFO mode: first_word flag used in spi_writeword() */
9741009
}
9751010

976-
spi_writeword(priv, wd);
1011+
spi_writeword(priv, wd, first_word);
9771012
ret = spi_readword(priv);
9781013

9791014
if (!last)
@@ -1037,15 +1072,14 @@ static uint32_t spi_send(struct spi_dev_s *dev, uint32_t wd)
10371072
*
10381073
****************************************************************************/
10391074

1040-
#if !defined(CONFIG_STM32_SPI_DMA) || defined(CONFIG_STM32_SPI_DMATHRESHOLD)
1041-
# if !defined(CONFIG_KINETIS_SPI_DMA)
1075+
#if !defined(CONFIG_KINETIS_SPI_DMA)
10421076
static void spi_exchange(struct spi_dev_s *dev, const void *txbuffer,
10431077
void *rxbuffer, size_t nwords)
1044-
# else
1078+
#else
10451079
static void spi_exchange_nodma(struct spi_dev_s *dev,
10461080
const void *txbuffer,
10471081
void *rxbuffer, size_t nwords)
1048-
# endif
1082+
#endif
10491083
{
10501084
struct kinetis_spidev_s *priv = (struct kinetis_spidev_s *)dev;
10511085
uint8_t *brxptr = (uint8_t *)rxbuffer;
@@ -1117,7 +1151,6 @@ static void spi_exchange_nodma(struct spi_dev_s *dev,
11171151
}
11181152
}
11191153
}
1120-
#endif /* !defined(CONFIG_STM32_SPI_DMA) || defined(CONFIG_STM32_SPI_DMATHRESHOLD) */
11211154

11221155
/****************************************************************************
11231156
* Name: spi_exchange (with DMA capability)
@@ -1620,13 +1653,13 @@ struct spi_dev_s *kinetis_spibus_initialize(int port)
16201653
* Peripheral Chip Select Strobe - Peripheral Chip Select[5] signal
16211654
* Receive FIFO Overflow Overwrite - Ignore incoming
16221655
* Chip Select x Inactive State - High
1623-
* Doze - Disabled
1656+
* Doze - Disabled
16241657
* Module Disable - Enables the module clocks.
16251658
* Disable Transmit FIFO - yes
16261659
* Disable Receive FIFO - yes
16271660
* Clear TX FIFO - No
16281661
* Clear RX FIFO - No
1629-
* Sample Point - 0 clocks between edge and sample
1662+
* Sample Point - 0 clocks between edge and sample
16301663
*
16311664
*/
16321665

boards/arm/kinetis/freedom-k64f/include/board.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,4 +297,17 @@
297297
#define PIN_I2C0_SCL PIN_I2C0_SCL_4
298298
#define PIN_I2C0_SDA PIN_I2C0_SDA_4
299299

300+
/* SPI Bus 0
301+
*
302+
* Arduino Pin FRDM-K64F J1 Connector
303+
* ------------------------ -----------------------
304+
* SPI CLK, Arduino D13 Pin 94, PTD1, SPI0_SCK
305+
* SPI MISO, Arduino D12 Pin 95, PTD3, SPI0_SOUT
306+
* SPI MOSI, Arduino D11 Pin 96, PTD2, SPI0_SIN
307+
*/
308+
309+
#define PIN_SPI0_SCK PIN_SPI0_SCK_3
310+
#define PIN_SPI0_SIN PIN_SPI0_SIN_3
311+
#define PIN_SPI0_OUT PIN_SPI0_SOUT_3
312+
300313
#endif /* __BOARDS_ARM_FREEDOM_K64F_INCLUDE_BOARD_H */

boards/arm/kinetis/freedom-k64f/src/freedom-k64f.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,9 @@
213213
#define GPIO_LED_G (GPIO_LOWDRIVE | GPIO_OUTPUT_ONE | PIN_PORTE | PIN26)
214214
#define GPIO_LED_B (GPIO_LOWDRIVE | GPIO_OUTPUT_ONE | PIN_PORTB | PIN21)
215215

216+
/* SPI CS, Arduino D10 Pin 93, PTD0, PIN_SPI0_PCS0_2 */
217+
#define GPIO_SPI0_CS (GPIO_LOWDRIVE | GPIO_OUTPUT_ONE | PIN_PORTC | PIN4)
218+
216219
/****************************************************************************
217220
* Public Data
218221
****************************************************************************/

boards/arm/kinetis/freedom-k64f/src/k64_boot.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151

5252
void kinetis_boardinitialize(void)
5353
{
54-
#if defined(CONFIG_KINETIS_SPI1) || defined(CONFIG_KINETIS_SPI2)
54+
#if defined(CONFIG_KINETIS_SPI0) || defined(CONFIG_KINETIS_SPI1) || defined(CONFIG_KINETIS_SPI2)
5555
/* Configure SPI chip selects if 1) SPI is not disabled, and 2)
5656
* the weak function k64_spidev_initialize() has been brought into the
5757
* link.

boards/arm/kinetis/freedom-k64f/src/k64_bringup.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@
4848
# define LED_DRIVER_PATH "/dev/userleds"
4949
#endif
5050

51+
#include <nuttx/spi/spi_transfer.h>
52+
53+
#include "kinetis_spi.h"
5154
#include "freedom-k64f.h"
5255

5356
#if defined(CONFIG_BOARDCTL) || defined(CONFIG_BOARD_LATE_INITIALIZE)
@@ -102,6 +105,19 @@ int k64_bringup(void)
102105
k64_i2cdev_initialize();
103106
#endif
104107

108+
#ifdef CONFIG_KINETIS_SPI0
109+
struct spi_dev_s *spi0;
110+
spi0 = kinetis_spibus_initialize(0);
111+
112+
if (!spi0)
113+
{
114+
syslog(LOG_ERR, "ERROR:FAILED to initialize SPI port 0\n");
115+
return -ENODEV;
116+
}
117+
118+
spi_register(spi0, 0);
119+
#endif
120+
105121
#ifdef HAVE_MMCSD
106122
/* Initialize the SDHC driver */
107123

boards/arm/kinetis/freedom-k64f/src/k64_spi.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757

5858
void weak_function k64_spidev_initialize(void)
5959
{
60-
# warning "Missing logic"
60+
kinetis_pinconfig(GPIO_SPI0_CS);
6161
}
6262

6363
/****************************************************************************
@@ -98,7 +98,7 @@ void kinetis_spi0select(struct spi_dev_s *dev, uint32_t devid,
9898
{
9999
spiinfo("devid: %d CS: %s\n", (int)devid,
100100
selected ? "assert" : "de-assert");
101-
# warning "Missing logic"
101+
kinetis_gpiowrite(GPIO_SPI0_CS, !selected);
102102
}
103103

104104
uint8_t kinetis_spi0status(struct spi_dev_s *dev, uint32_t devid)

0 commit comments

Comments
 (0)