SPI IRQ Handler written for the LPC54018 fails to execute the SPI_ReadData function

cancel
Showing results for 
Search instead for 
Did you mean: 

SPI IRQ Handler written for the LPC54018 fails to execute the SPI_ReadData function

101 Views
jmueckl
Contributor III
I wrote the following IRQ Handler to transfer one byte of SPI data to a slave. The handler is called by the function writeRegister8() which first writes the address of the slave followed by the slave data that is to be written to that address. The same handler is called by the function readRegister8() which first writes the address of the slave to be read from and then reads the data from that address using the dedicated function SPI_ReadData(). The function writeRegister8 works, but the readRegister8 function fails when SPI_ReadData() is called. All SPI_ReadData() does is return base->FIFORD, a 32 bit register. Although SPI_ReadData typically returns values like 0xe00ff, 0xe003f or 0x300d0, the scope does not get triggered. Channel 1 of my scope is connected to SCK and channel 2 to MISO (SDO). The scope does correctly capture the Clock and MOSI signals when SPI_WriteData is executed. Can someone tell me why SPI_ReadData is failing? I think the problem is related to something I don’t understand about the nature of the FIFO in the LPC54018, since I am attempting to read or write a single byte to the slave. I know that my slave works and is wired correctly because I have implemented a similar version of my writeRegister8 and readRegister8 function using the masterCallback function as implemented in the SDK example spi_interrupt_b2b_master_transfer. In this implementation my scope correctly captures both MOSI and MISO signals. Note that both implementations are C++. I would like to understand which of the two methods I am experimenting with is preferable for the purpose of transferring byte sized data to a SPI slave. Is one more efficient than the other? Will the interrupt driven method take more or less time than the masterCallback method? uint8_t SPIAddr; static uint32_t RxData; static uint8_t TxData; void FLEXCOMM9_IRQHandler(void) { if ((SPI_GetStatusFlags(SPI9) & kSPI_TxNotFullFlag)) { if (SPI_RW == WRITE) // A second Write is coming { // need to disable Both Rx & Tx interrupts or handler wraps SPI_DisableInterrupts(SPI9, kSPI_TxLvlIrq | kSPI_RxLvlIrq); // SSEL will be deasserted (stays low) at the end of transfer SPI_WriteData(SPI9, (uint16_t)(SPIAddr), 0); } if (SPI_RW == READ) { // need to disable Both Rx & Tx interrupts or handler wraps SPI_DisableInterrupts(SPI9, kSPI_TxLvlIrq | kSPI_RxLvlIrq); // SSEL will be deasserted (stays low) at the end of transfer SPI_WriteData(SPI9, (uint16_t)(SPIAddr), 0); } } if ((SPI_GetStatusFlags(SPI9) & kSPI_RxNotEmptyFlag) && (SPI_RW == READ)) { RxData = SPI_ReadData(SPI9); SDK_DelayAtLeastUs(10, BOARD_BOOTCLOCKFRO12M_CORE_CLOCK); // 10us } if ((SPI_GetStatusFlags(SPI9) & kSPI_TxNotFullFlag) && (SPI_RW == WRITE)) { // End of transfer // Set MOSI high after the write SPI_WriteData(SPI9, (uint16_t)(TxData), kSPI_FrameAssert); } SPI_IRQ_Finished = true; IRQH_count++; SDK_ISR_EXIT_BARRIER; } uint32_t MAX31865::readRegister8(uint8_t RegAddr) { SPI_RW = READ; SPIAddr = RegAddr & 0x7F; // make sure top bit is not set TxData = 0; SPI_EnableInterrupts(SPI9, kSPI_TxLvlIrq | kSPI_RxLvlIrq); while (SPI_IRQ_Finished != true) { } SPI_IRQ_Finished = false; return RxData; // RxData obtained in SPI_Handler } void MAX31865::writeRegister8(uint8_t RegAddr, uint8_t writeData) { SPI_RW = WRITE; SPIAddr = RegAddr | 0x80; // top bit keeps PCSn signals asserted between transfers TxData = writeData; SPI_EnableInterrupts(SPI9, kSPI_TxLvlIrq | kSPI_RxLvlIrq); while (SPI_IRQ_Finished != true) { } SPI_IRQ_Finished = false; }
0 Kudos
9 Replies

100 Views
jmueckl
Contributor III

Let's submit this post again with the code in an attached document.

I wrote the following IRQ Handler to transfer one byte of SPI data to a slave.  The handler is called by the function writeRegister8() which first writes the address of the slave followed by the slave data that is to be written to that address.  The same handler is called by the function readRegister8() which first writes the address of the slave to be read from and then reads the data from that address using the dedicated function SPI_ReadData().  The function writeRegister8 works, but the readRegister8 function fails when SPI_ReadData() is called.  All SPI_ReadData() does is return base->FIFORD, a 32 bit register.  Although SPI_ReadData typically returns values like 0xe00ff, 0xe003f or 0x300d0, the scope does not get triggered. Channel 1 of my scope is connected to SCK and channel 2 to MISO (SDO).  The scope does correctly capture the Clock and MOSI signals when SPI_WriteData is executed.  Can someone tell me why SPI_ReadData is failing?  I think the problem is related to something I don’t understand about the nature of the FIFO in the LPC54018, since I am attempting to read or write a single byte to the slave.    

I know that my slave works and is wired correctly because I have implemented a similar version of my writeRegister8 and readRegister8 function using the masterCallback function as implemented in the SDK example spi_interrupt_b2b_master_transfer.  In this implementation my scope correctly captures both MOSI and MISO signals.  Note that both implementations are C++.

I would like to understand which of the two methods I am experimenting with is preferable for the purpose of transferring byte sized data to a SPI slave.  Is one more efficient than the other?  Will the interrupt driven method take more or less time than the masterCallback method?

0 Kudos

83 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Jerry,

It appears that you use MC31865, it is a RTD converter.

This is the SPI timing:

xiangjun_rong_0-1617950875193.png

For the above SPI timing, you should set the data length as 16 bits, in other words, after all 16 bits has transferred, the flag in SPI status will be set, then you can read the data.

 

uint32_t temp;

 

SPI_FIFOWR=0x0F1E0000|BYTE_ADDRSSS<<8;

While(!(SPI_FIFOSTAT*0x10)) {}

temp= (SPI_FIFOWR&0xFF);

You have to init the other register for example setting the baud rate, master mode, CPHA/CPOL...

Hope it can help you

BR

XiangJun Rong

0 Kudos

77 Views
jmueckl
Contributor III

Xiang_jun, what you have described is related to the the function SPI_WriteData(), which works well for me.  The problem I have described is only with respect to the SPI_READ() function which is defined in fsl_spi.h as

static inline uint32_t SPI_ReadData(SPI_Type *base)

{

    assert(NULL != base);

    return base->FIFORD;

}

 

My SPI IRQHandler performs a byte write to the slave by calling SPI_WriteData() to write the slave address (SPIAddr), and a second call to SPI_WriteData() to write the transmit byte (TxData).  The two 8 bit writes is equivalent to a 16 bit write.

As the timing diagrams you posted illustrates, to read a byte from the slave one must first write the address of the slave, which I implement in my handler using  

(1) SPI_WriteData(SPI9, uint16_6 (SPIAddr), 0);

To read the byte from that slave address I then execute the code

(2) RxData = SPI_ReadData(SPI9);

But during this call my oscilloscope doesn’t detect any clock or MISO transitions.  The value that my readRegister8() function returns is the value that my scope captured on the MISO pin during code line (1).

I hope that clarifies my question so that you or someone else can answer it.

0 Kudos

57 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi,

As you said that  during this call my oscilloscope doesn’t detect any clock or MISO transitions. The value that my readRegister8() function returns is the value that my scope captured on the MISO pin during code line (1).

If you can not see the SCK, MOSI even CS signal of SPI via scope, I suppose that it is another question, have you set up the pin mux.

PIO4_14 ENET_RX_CLK CTIMER4_MAT1 FC9_SCK - SCT0_GPI7 - - - -

/* Enables the clock for the IOCON block. 0 = Disable; 1 = Enable.: 0x01u */
CLOCK_EnableClock(kCLOCK_Iocon);

IOCON->PIO[4][14] = ((IOCON->PIO[4][14] &
/* Mask bits to zero which are setting */
(~(IOCON_PIO_FUNC_MASK | IOCON_PIO_MODE_MASK | IOCON_PIO_DIGIMODE_MASK)))

/* Selects pin function.
* : PORT010 (pin P2) is configured as SWO. */
| IOCON_PIO_FUNC(PIO010_FUNC_ALT3)

/* Selects function mode (on-chip pull-up/pull-down resistor control).
* : Inactive.
* Inactive (no pull-down/pull-up resistor enabled). */
| IOCON_PIO_MODE(PIO414_MODE_INACTIVE)

/* Select Analog/Digital mode.
* : Digital mode. */
| IOCON_PIO_DIGIMODE(PIO414_DIGIMODE_DIGITAL));

 


PIO4_15 ENET_MDC CTIMER4_MAT2 FC9_RXD_SDA_MOSI - - - - - -
PIO4_16 ENET_MDIO CTIMER4_MAT3 FC9_TXD_SCL_MISO

xiangjun_rong_0-1618227737810.png

BTW, I suggest you set up the SPI width with 16 bits instead of 8 bits.

Hope it can help you

BR

XiangJun Rong

0 Kudos

50 Views
jmueckl
Contributor III

Please understand that my scope is triggered by CLK, CS, MOSI & MISO signals at the time the following function is called:

(1) SPI_WriteData(SPI9, uint16_6 (SPIAddr), 0);

It is only when SPI_ReadData() is called that there is no scope activity.

I don’t see a means to specify the width of my SPI bus.  Exactly how do you do that for the LPC54018?  The fact that I am using an 8 bit variable to read the result of SPI_ReadData() does not change the internal width of the SPI bus. Is there a setting for the SPI FIFO size?

0 Kudos

19 Views
jmueckl
Contributor III

Please realize there are two questions here.

You are indicating then that there is no need to use the function SPI_ReadData().  Why is it in the API?  It is misleading.

You suggested that I specify the width of my SPI bus as 16 bits.  Exactly how do I do that in the code for the LPC54018?  

0 Kudos

9 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Jerry,

Pls refer to the SPI_WriteData() function in SDK package, which writes the FIFOWR register and generate SPI timing. The control bits specify the bit width of SPI data.

Regarding the SPI_ReadData(), it just reads the FIFORD register and encapsulate a function. As I said it does not generate SPI timing.

You can download SDK package from the link:

https://www.nxp.com/design/software/development-software/mcuxpresso-software-and-tools-/mcuxpresso-s...

 

Hope it can help you

BR

XiangJun Rong

 

void SPI_WriteData(SPI_Type *base, uint16_t data, uint32_t configFlags)
{
uint32_t control = 0U;
uint32_t instance;

/* check params */
assert(NULL != base);
/* get and check instance */
instance = SPI_GetInstance(base);

/* set data width */
control |= (uint32_t)SPI_FIFOWR_LEN((g_configs[instance].dataWidth));
/* set sssel */
control |= (SPI_DEASSERT_ALL & (~SPI_DEASSERTNUM_SSEL((uint32_t)(g_configs[instance].sselNum))));
/* mask configFlags */
control |= (configFlags & (uint32_t)SPI_FIFOWR_FLAGS_MASK);
/* control should not affect lower 16 bits */
assert(0U == (control & 0xFFFFU));
base->FIFOWR = data | control;
}

 

void SPI_MasterGetDefaultConfig(spi_master_config_t *config)
{
assert(NULL != config);

/* Initializes the configure structure to zero. */
(void)memset(config, 0, sizeof(*config));

config->enableLoopback = false;
config->enableMaster = true;
config->polarity = kSPI_ClockPolarityActiveHigh;
config->phase = kSPI_ClockPhaseFirstEdge;
config->direction = kSPI_MsbFirst;
config->baudRate_Bps = 500000U;
config->dataWidth = kSPI_Data8Bits;  ////// the line initilize the spi data width, it is kSPI_Data16Bits for //your case.
config->sselNum = kSPI_Ssel0;
config->txWatermark = (uint8_t)kSPI_TxFifo0;
config->rxWatermark = (uint8_t)kSPI_RxFifo1;
config->sselPol = kSPI_SpolActiveAllLow;
config->delayConfig.preDelay = 0U;
config->delayConfig.postDelay = 0U;
config->delayConfig.frameDelay = 0U;
config->delayConfig.transferDelay = 0U;
}

typedef enum _spi_data_width
{
kSPI_Data4Bits = 3, /*!< 4 bits data width */
kSPI_Data5Bits = 4, /*!< 5 bits data width */
kSPI_Data6Bits = 5, /*!< 6 bits data width */
kSPI_Data7Bits = 6, /*!< 7 bits data width */
kSPI_Data8Bits = 7, /*!< 8 bits data width */
kSPI_Data9Bits = 8, /*!< 9 bits data width */
kSPI_Data10Bits = 9, /*!< 10 bits data width */
kSPI_Data11Bits = 10, /*!< 11 bits data width */
kSPI_Data12Bits = 11, /*!< 12 bits data width */
kSPI_Data13Bits = 12, /*!< 13 bits data width */
kSPI_Data14Bits = 13, /*!< 14 bits data width */
kSPI_Data15Bits = 14, /*!< 15 bits data width */
kSPI_Data16Bits = 15, /*!< 16 bits data width */
} spi_data_width_t;

0 Kudos

3 Views
jmueckl
Contributor III

Rong,

After changing the dataWidth from 8 bits to 16 bits, I simplified my writeRegister8() function as I show below.  However, my readRegister8() doesn’t work.   I attempted to implement your code line 

temp= (SPI_FIFOWR&0xFF);

but I don’t have direct access to register FIFOWR (SPI_FIFOWR doesn’t exist). I believe I can only call SPI_WriteData() or SPI_ReadData().  Since I have to write the register address before the processor can read the SDO read data, SPI_WriteData(SPI9, RDData) now writes two bytes rather than one. The following SPI_ReadData(SPI9) function always reads the value of 0xFF in the LS Byte.  

How did you intend for me to implement your process?

void FLEXCOMM9_IRQHandler(void)

{

    if ((SPI_GetStatusFlags(SPI9) & kSPI_TxEmptyFlag) && SPI_RW == WRITE)

    {

       // need to disable Both Rx & Tx interrupts or handler wraps

       SPI_DisableInterrupts(SPI9, kSPI_TxLvlIrq | kSPI_RxLvlIrq);

// WRData = (RegAddr | 0x80) << 8 | byte-to-write;

       SPI_WriteData(SPI9, (uint16_t)(WRData), kSPI_FrameAssert);

    }

    if (SPI_RW == READ)  // Doesn’t work

    {

       while (!(SPI_GetStatusFlags(SPI9) & kSPI_TxEmptyFlag)) { };

       // need to disable Both Rx & Tx interrupts or handler wraps

       SPI_DisableInterrupts(SPI9, kSPI_TxLvlIrq | kSPI_RxLvlIrq);

       // RDData = (RegAddr | 0x80) << 8;

       SPI_WriteData(SPI9, (uint16_t)(RDData), kSPI_FrameAssert);

       RxData = SPI_ReadData(SPI9);  // Always reads 0xFF 

    }

    SPI_IRQ_Finished = true;

    IRQH_count++;

    SDK_ISR_EXIT_BARRIER;

}

0 Kudos

31 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Jerry,

It appears that you misunderstand the SPI mechanism. When the SPI module is configured as a master, after your write the SPI_FIFOWR register, the SPI module will generate the SPI timing, the bits in SPI_FIFOWR will appeared on MOSI with SCK clocking, at the same time, the master will receive data from MISO pin with SCK and save the data in SPI->FIFORD. In other words, reading data from SPI->FIFORD can NOT generate SPI timing.

This is the model of the SPI writing/reading, firstly, write SPI_FIFOWR, after the data in SPI_FIFOWR has been transmitted, a flag will be set, after the flag is set, it means that the data has been received also, it is okay read it to memory variable temp.


SPI_FIFOWR=0x0F1E0000|BYTE_ADDRSSS<<8;

While(!(SPI_FIFOSTAT*0x10)) {}

temp= (SPI_FIFOWR&0xFF);

Hope it can help you

BR

XiangJun Rong

0 Kudos