mirror of
https://github.com/apache/nuttx.git
synced 2025-12-17 10:16:49 +08:00
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 <trns1997@gmail.com>
This commit is contained in:
@@ -134,7 +134,7 @@ static inline void spi_putreg8(struct kinetis_spidev_s *priv,
|
|||||||
uint8_t offset, uint8_t value);
|
uint8_t offset, uint8_t value);
|
||||||
static inline uint16_t spi_readword(struct kinetis_spidev_s *priv);
|
static inline uint16_t spi_readword(struct kinetis_spidev_s *priv);
|
||||||
static inline void spi_writeword(struct kinetis_spidev_s *priv,
|
static inline void spi_writeword(struct kinetis_spidev_s *priv,
|
||||||
uint16_t word);
|
uint16_t word, bool first_word);
|
||||||
|
|
||||||
static inline void spi_run(struct kinetis_spidev_s *priv,
|
static inline void spi_run(struct kinetis_spidev_s *priv,
|
||||||
bool enable);
|
bool enable);
|
||||||
@@ -559,11 +559,14 @@ static inline void spi_write_control(struct kinetis_spidev_s *priv,
|
|||||||
* Name: spi_writeword
|
* Name: spi_writeword
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Write one 16 bit word to SPI TX FIFO
|
* Write one word to SPI TX FIFO or single-entry buffer.
|
||||||
|
* In non-FIFO mode, performs 32-bit write including control bits.
|
||||||
|
* In FIFO-enabled mode, writes only the data (control handled separately).
|
||||||
*
|
*
|
||||||
* Input Parameters:
|
* Input Parameters:
|
||||||
* priv - Device-specific state data
|
* priv - Device-specific state data
|
||||||
* word - word to send
|
* word - word to send
|
||||||
|
* first_word - Flag to set control in case of FIFO disabled
|
||||||
*
|
*
|
||||||
* Returned Value:
|
* Returned Value:
|
||||||
* None
|
* None
|
||||||
@@ -571,15 +574,36 @@ static inline void spi_write_control(struct kinetis_spidev_s *priv,
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static inline void spi_writeword(struct kinetis_spidev_s *priv,
|
static inline void spi_writeword(struct kinetis_spidev_s *priv,
|
||||||
uint16_t word)
|
uint16_t word, bool first_word)
|
||||||
{
|
{
|
||||||
|
uint32_t mcr = spi_getreg(priv, KINETIS_SPI_MCR_OFFSET);
|
||||||
|
uint32_t pushr_val;
|
||||||
|
|
||||||
/* Wait until there is space in the fifo */
|
/* Wait until there is space in the fifo */
|
||||||
|
|
||||||
spi_wait_status(priv, SPI_SR_TFFF);
|
spi_wait_status(priv, SPI_SR_TFFF);
|
||||||
|
|
||||||
/* Write the data to transmitted to the SPI Data Register */
|
if (mcr & SPI_MCR_DIS_TXF)
|
||||||
|
{
|
||||||
|
/* FIFO disabled: 32-bit write including control + data */
|
||||||
|
|
||||||
spi_putreg16(priv, KINETIS_SPI_PUSHR_OFFSET, SPI_PUSHR_TXDATA(word));
|
pushr_val = SPI_PUSHR_TXDATA(word);
|
||||||
|
|
||||||
|
if (first_word)
|
||||||
|
{
|
||||||
|
/* Set Control word */
|
||||||
|
|
||||||
|
pushr_val |= SPI_PUSHR_CTAS_CTAR0 | SPI_PUSHR_CTCNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
spi_putreg(priv, KINETIS_SPI_PUSHR_OFFSET, pushr_val);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* FIFO enabled: write only data; control handled separately */
|
||||||
|
|
||||||
|
spi_putreg16(priv, KINETIS_SPI_PUSHR_OFFSET, SPI_PUSHR_TXDATA(word));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -964,16 +988,27 @@ static uint16_t spi_send_data(struct kinetis_spidev_s *priv, uint16_t wd,
|
|||||||
bool last)
|
bool last)
|
||||||
{
|
{
|
||||||
uint16_t ret;
|
uint16_t ret;
|
||||||
|
uint32_t mcr = spi_getreg(priv, KINETIS_SPI_MCR_OFFSET);
|
||||||
|
bool first_word = false;
|
||||||
|
|
||||||
/* On first write set control word and start transfer */
|
/* Start module and write control if FIFO enabled on first transfer */
|
||||||
|
|
||||||
if (0 == (spi_getreg(priv, KINETIS_SPI_SR_OFFSET) & SPI_SR_TXRXS))
|
if ((spi_getreg(priv, KINETIS_SPI_SR_OFFSET) & SPI_SR_TXRXS) == 0)
|
||||||
{
|
{
|
||||||
spi_run(priv, true);
|
spi_run(priv, true);
|
||||||
spi_write_control(priv, SPI_PUSHR_CTAS_CTAR0 | SPI_PUSHR_CTCNT);
|
first_word = true;
|
||||||
|
|
||||||
|
if ((mcr & SPI_MCR_DIS_TXF) == 0)
|
||||||
|
{
|
||||||
|
/* FIFO enabled: safe to write control separately */
|
||||||
|
|
||||||
|
spi_write_control(priv, SPI_PUSHR_CTAS_CTAR0 | SPI_PUSHR_CTCNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Non-FIFO mode: first_word flag used in spi_writeword() */
|
||||||
}
|
}
|
||||||
|
|
||||||
spi_writeword(priv, wd);
|
spi_writeword(priv, wd, first_word);
|
||||||
ret = spi_readword(priv);
|
ret = spi_readword(priv);
|
||||||
|
|
||||||
if (!last)
|
if (!last)
|
||||||
@@ -1037,15 +1072,14 @@ static uint32_t spi_send(struct spi_dev_s *dev, uint32_t wd)
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#if !defined(CONFIG_STM32_SPI_DMA) || defined(CONFIG_STM32_SPI_DMATHRESHOLD)
|
#if !defined(CONFIG_KINETIS_SPI_DMA)
|
||||||
# if !defined(CONFIG_KINETIS_SPI_DMA)
|
|
||||||
static void spi_exchange(struct spi_dev_s *dev, const void *txbuffer,
|
static void spi_exchange(struct spi_dev_s *dev, const void *txbuffer,
|
||||||
void *rxbuffer, size_t nwords)
|
void *rxbuffer, size_t nwords)
|
||||||
# else
|
#else
|
||||||
static void spi_exchange_nodma(struct spi_dev_s *dev,
|
static void spi_exchange_nodma(struct spi_dev_s *dev,
|
||||||
const void *txbuffer,
|
const void *txbuffer,
|
||||||
void *rxbuffer, size_t nwords)
|
void *rxbuffer, size_t nwords)
|
||||||
# endif
|
#endif
|
||||||
{
|
{
|
||||||
struct kinetis_spidev_s *priv = (struct kinetis_spidev_s *)dev;
|
struct kinetis_spidev_s *priv = (struct kinetis_spidev_s *)dev;
|
||||||
uint8_t *brxptr = (uint8_t *)rxbuffer;
|
uint8_t *brxptr = (uint8_t *)rxbuffer;
|
||||||
@@ -1117,7 +1151,6 @@ static void spi_exchange_nodma(struct spi_dev_s *dev,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* !defined(CONFIG_STM32_SPI_DMA) || defined(CONFIG_STM32_SPI_DMATHRESHOLD) */
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: spi_exchange (with DMA capability)
|
* Name: spi_exchange (with DMA capability)
|
||||||
@@ -1620,13 +1653,13 @@ struct spi_dev_s *kinetis_spibus_initialize(int port)
|
|||||||
* Peripheral Chip Select Strobe - Peripheral Chip Select[5] signal
|
* Peripheral Chip Select Strobe - Peripheral Chip Select[5] signal
|
||||||
* Receive FIFO Overflow Overwrite - Ignore incoming
|
* Receive FIFO Overflow Overwrite - Ignore incoming
|
||||||
* Chip Select x Inactive State - High
|
* Chip Select x Inactive State - High
|
||||||
* Doze - Disabled
|
* Doze - Disabled
|
||||||
* Module Disable - Enables the module clocks.
|
* Module Disable - Enables the module clocks.
|
||||||
* Disable Transmit FIFO - yes
|
* Disable Transmit FIFO - yes
|
||||||
* Disable Receive FIFO - yes
|
* Disable Receive FIFO - yes
|
||||||
* Clear TX FIFO - No
|
* Clear TX FIFO - No
|
||||||
* Clear RX FIFO - No
|
* Clear RX FIFO - No
|
||||||
* Sample Point - 0 clocks between edge and sample
|
* Sample Point - 0 clocks between edge and sample
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -297,4 +297,17 @@
|
|||||||
#define PIN_I2C0_SCL PIN_I2C0_SCL_4
|
#define PIN_I2C0_SCL PIN_I2C0_SCL_4
|
||||||
#define PIN_I2C0_SDA PIN_I2C0_SDA_4
|
#define PIN_I2C0_SDA PIN_I2C0_SDA_4
|
||||||
|
|
||||||
|
/* SPI Bus 0
|
||||||
|
*
|
||||||
|
* Arduino Pin FRDM-K64F J1 Connector
|
||||||
|
* ------------------------ -----------------------
|
||||||
|
* SPI CLK, Arduino D13 Pin 94, PTD1, SPI0_SCK
|
||||||
|
* SPI MISO, Arduino D12 Pin 95, PTD3, SPI0_SOUT
|
||||||
|
* SPI MOSI, Arduino D11 Pin 96, PTD2, SPI0_SIN
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define PIN_SPI0_SCK PIN_SPI0_SCK_3
|
||||||
|
#define PIN_SPI0_SIN PIN_SPI0_SIN_3
|
||||||
|
#define PIN_SPI0_OUT PIN_SPI0_SOUT_3
|
||||||
|
|
||||||
#endif /* __BOARDS_ARM_FREEDOM_K64F_INCLUDE_BOARD_H */
|
#endif /* __BOARDS_ARM_FREEDOM_K64F_INCLUDE_BOARD_H */
|
||||||
|
|||||||
@@ -213,6 +213,9 @@
|
|||||||
#define GPIO_LED_G (GPIO_LOWDRIVE | GPIO_OUTPUT_ONE | PIN_PORTE | PIN26)
|
#define GPIO_LED_G (GPIO_LOWDRIVE | GPIO_OUTPUT_ONE | PIN_PORTE | PIN26)
|
||||||
#define GPIO_LED_B (GPIO_LOWDRIVE | GPIO_OUTPUT_ONE | PIN_PORTB | PIN21)
|
#define GPIO_LED_B (GPIO_LOWDRIVE | GPIO_OUTPUT_ONE | PIN_PORTB | PIN21)
|
||||||
|
|
||||||
|
/* SPI CS, Arduino D10 Pin 93, PTD0, PIN_SPI0_PCS0_2 */
|
||||||
|
#define GPIO_SPI0_CS (GPIO_LOWDRIVE | GPIO_OUTPUT_ONE | PIN_PORTC | PIN4)
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Data
|
* Public Data
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|||||||
@@ -51,7 +51,7 @@
|
|||||||
|
|
||||||
void kinetis_boardinitialize(void)
|
void kinetis_boardinitialize(void)
|
||||||
{
|
{
|
||||||
#if defined(CONFIG_KINETIS_SPI1) || defined(CONFIG_KINETIS_SPI2)
|
#if defined(CONFIG_KINETIS_SPI0) || defined(CONFIG_KINETIS_SPI1) || defined(CONFIG_KINETIS_SPI2)
|
||||||
/* Configure SPI chip selects if 1) SPI is not disabled, and 2)
|
/* Configure SPI chip selects if 1) SPI is not disabled, and 2)
|
||||||
* the weak function k64_spidev_initialize() has been brought into the
|
* the weak function k64_spidev_initialize() has been brought into the
|
||||||
* link.
|
* link.
|
||||||
|
|||||||
@@ -48,6 +48,9 @@
|
|||||||
# define LED_DRIVER_PATH "/dev/userleds"
|
# define LED_DRIVER_PATH "/dev/userleds"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <nuttx/spi/spi_transfer.h>
|
||||||
|
|
||||||
|
#include "kinetis_spi.h"
|
||||||
#include "freedom-k64f.h"
|
#include "freedom-k64f.h"
|
||||||
|
|
||||||
#if defined(CONFIG_BOARDCTL) || defined(CONFIG_BOARD_LATE_INITIALIZE)
|
#if defined(CONFIG_BOARDCTL) || defined(CONFIG_BOARD_LATE_INITIALIZE)
|
||||||
@@ -102,6 +105,19 @@ int k64_bringup(void)
|
|||||||
k64_i2cdev_initialize();
|
k64_i2cdev_initialize();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_KINETIS_SPI0
|
||||||
|
struct spi_dev_s *spi0;
|
||||||
|
spi0 = kinetis_spibus_initialize(0);
|
||||||
|
|
||||||
|
if (!spi0)
|
||||||
|
{
|
||||||
|
syslog(LOG_ERR, "ERROR:FAILED to initialize SPI port 0\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
spi_register(spi0, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_MMCSD
|
#ifdef HAVE_MMCSD
|
||||||
/* Initialize the SDHC driver */
|
/* Initialize the SDHC driver */
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,7 @@
|
|||||||
|
|
||||||
void weak_function k64_spidev_initialize(void)
|
void weak_function k64_spidev_initialize(void)
|
||||||
{
|
{
|
||||||
# warning "Missing logic"
|
kinetis_pinconfig(GPIO_SPI0_CS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -98,7 +98,7 @@ void kinetis_spi0select(struct spi_dev_s *dev, uint32_t devid,
|
|||||||
{
|
{
|
||||||
spiinfo("devid: %d CS: %s\n", (int)devid,
|
spiinfo("devid: %d CS: %s\n", (int)devid,
|
||||||
selected ? "assert" : "de-assert");
|
selected ? "assert" : "de-assert");
|
||||||
# warning "Missing logic"
|
kinetis_gpiowrite(GPIO_SPI0_CS, !selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t kinetis_spi0status(struct spi_dev_s *dev, uint32_t devid)
|
uint8_t kinetis_spi0status(struct spi_dev_s *dev, uint32_t devid)
|
||||||
|
|||||||
Reference in New Issue
Block a user