17bit or 25bit spi frame using LPC546xx family

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

17bit or 25bit spi frame using LPC546xx family

Jump to solution
3,186 Views
iann
Contributor III

Hi All,

I'm looking to interface to a slightly non standard spi interface using a 9bit address word as shown below to make a 17 or 25 bit total frame size.

spi17bit.png

In the LPC546xx manual (section 26.2) I see larger frame sizes beyond 16bits are supported by software. Are there further details on how this can be achieved? As I'd still have to interface to the 8 bit fifo's.

Labels (2)
0 Kudos
1 Solution
3,014 Views
Alexis_A
NXP TechSupport
NXP TechSupport

Hello Ian, 

The changes you made are totally right, I will report this to the SDK team, and about your other question, the best way would be to change the data width in the section the master init is storing this configuration. This configuration is stored in g_configs so an API like the next one should do the trick:

status_t SPI_ChangeTransferWidth(SPI_Type *base, spi_data_width_t datawidth){
    uint32_t instance;
    
    instance  = SPI_GetInstance(base);
    /* store configuration */
    g_configs[instance].dataWidth = datawidth;
}

Best Regards,

Alexis Andalon

View solution in original post

12 Replies
3,014 Views
iann
Contributor III

For the second part of the problem then sending an 8 bit transfer, I can't see how to get the new value of userConfig.dataWidth = kSPI_Data8Bits;  to take effect? As just updating this is ignored. 

I've also tried running the SPI_Deinit and then SPI_MasterInit again with the new value but not surprisingly this causes the bus to reset.

What is the correct way to do a two transaction spi transfer changing the spi  datawidth in between?

Kind regards

Ian

0 Kudos
3,015 Views
Alexis_A
NXP TechSupport
NXP TechSupport

Hello Ian, 

The changes you made are totally right, I will report this to the SDK team, and about your other question, the best way would be to change the data width in the section the master init is storing this configuration. This configuration is stored in g_configs so an API like the next one should do the trick:

status_t SPI_ChangeTransferWidth(SPI_Type *base, spi_data_width_t datawidth){
    uint32_t instance;
    
    instance  = SPI_GetInstance(base);
    /* store configuration */
    g_configs[instance].dataWidth = datawidth;
}

Best Regards,

Alexis Andalon

2,688 Views
iann
Contributor III

Hi Alexis,

I'm having to revisit this as now we're trying to get our prototype hardware up and running I've switched to using the freeRTOS spi functions which use the SPI_MasterTransferNonBlocking functions in the fsl_spi.c driver and this is showing the original problem of not being able to change the bit width as there a way to modify the function to allow this?

Cheers

Ian

0 Kudos
3,014 Views
iann
Contributor III

Thanks Alexis, that's the missing piece I needed.

To close this off now, my waveforms now are 

17bits

17bits.jpg

and 25bits

25bits.jpg

Cheers

Ian

0 Kudos
3,016 Views
iann
Contributor III

For the first part of the problem, sending a 9 bit transfer I found an issue in the sdk (version 2.7) 

in fsl_spi.c  lines 562 to 618 the two lines in bold need changing.

while ((txRemainingBytes != 0U) || (rxRemainingBytes != 0U) || (toReceiveCount != 0U))
{
/* if rxFIFO is not empty */
if ((base->FIFOSTAT & SPI_FIFOSTAT_RXNOTEMPTY_MASK) != 0U)
{
tmp32 = base->FIFORD;
/* rxBuffer is not empty */
if (rxRemainingBytes != 0U)
{
*(rxData++) = (uint8_t)tmp32;
rxRemainingBytes--;
/* read 16 bits at once */
if (dataWidth >= 8U)          //  was if (dataWidth >8U)  
{
*(rxData++) = (uint8_t)(tmp32 >> 8);
rxRemainingBytes--;
}
}
/* decrease number of data expected to receive */
toReceiveCount -= 1U;
}
/* transmit if txFIFO is not full and data to receive does not exceed FIFO depth */
if (((base->FIFOSTAT & SPI_FIFOSTAT_TXNOTFULL_MASK) != 0U) && (toReceiveCount < fifoDepth) &&
((txRemainingBytes != 0U) || (rxRemainingBytes >= SPI_COUNT_TO_BYTES(dataWidth, toReceiveCount + 1U))))
{
/* txBuffer is not empty */
if (txRemainingBytes != 0U)
{
tmp32 = *(txData++);
txRemainingBytes--;
/* write 16 bit at once */
if (dataWidth >= 8U)  //  was if (dataWidth >8U)  
{
tmp32 |= ((uint32_t)(*(txData++))) << 8U;
txRemainingBytes--;
}
if (txRemainingBytes == 0U)
{
tx_ctrl |= last_ctrl;
}
}
else
{
tmp32 = (uint32_t)s_dummyData[instance];
tmp32 |= (uint32_t)s_dummyData[instance] << 8U;
/* last transfer */
if (rxRemainingBytes == SPI_COUNT_TO_BYTES(dataWidth, toReceiveCount + 1U))
{
tx_ctrl |= last_ctrl;
}
}
/* send data */
tmp32 = tx_ctrl | tmp32;
base->FIFOWR = tmp32;
toReceiveCount += 1U;
}
}

I hope that gets changed in a later sdk version.

Cheers

Ian.

0 Kudos
3,016 Views
iann
Contributor III

As indicated in the manual I'm looking to do this as two transfers, one of 9bits and then the remain 8bits with I assume manual control of the EOF bit in the FIFOWR register.

Though I seem to be falling down at writing the initial 9bits as I get 18bits instead.

Following the spi sdk example I define the following.

#define BUFFER_SIZE (2)

static uint8_t srcBuff[BUFFER_SIZE];
static uint8_t destBuff[BUFFER_SIZE];

spi_master_config_t userConfig = {0};
spi_transfer_t xfer = {0};

SPI_MasterGetDefaultConfig(&userConfig);
srcFreq = EXAMPLE_SPI_MASTER_CLK_FREQ;
userConfig.sselNum = (spi_ssel_t)EXAMPLE_SPI_SSEL;
userConfig.sselPol = (spi_spol_t)EXAMPLE_SPI_SPOL;
userConfig.dataWidth = kSPI_Data9Bits;


SPI_MasterInit(EXAMPLE_SPI_MASTER, &userConfig, srcFreq);

//Start Transfer
xfer.txData = srcBuff;
xfer.rxData = destBuff;
xfer.dataSize = 2;
xfer.configFlags = kSPI_FrameAssert;
SPI_MasterTransferBlocking(EXAMPLE_SPI_MASTER, &xfer);

How should I be using the datawidth register?

Cheers

Ian.

 

0 Kudos
3,016 Views
Alexis_A
NXP TechSupport
NXP TechSupport

Hello Ian,

Unfortunately, the APIs in the SDK support transfer up to 16 bit. In this case, in your code you're setting 2 transfer of 9 bits, so you would need to set first a 9-bit transfer first, modify the data width, and set other transfer with the flags kSPI_FrameDelay and kSPI_FrameAssert to indicate the end of the frame.

Best Regards,
Alexis Andalon

3,016 Views
iann
Contributor III

Hi Alexis thanks for the reply, this is what I was trying to achieve, though I can't see how to send just 1 transfer of 9bits as if I sent  xfer.dataSize = 1; 

at runtime I get an ASSERT ERROR " .fsl_spi.c:544 : !((dataWidth > kSPI_Data8Bits) && ((xfer->dataSize & 0x1U) != 0U)) 

not surprisingly as the api for the spi_transfer_t  has data as 8bits.

So how can I just send 1 transfer of 9bits though the api?

Thanks

Ian

0 Kudos
3,016 Views
Alexis_A
NXP TechSupport
NXP TechSupport

Hello Ian,

You're right, it looks like when the driver recognizes a transfer higher than 8-bits the extra bits will put in the next byte, so you will need to filter the information in the second byte.

Best Regards,

Alexis Andalon

0 Kudos
3,016 Views
iann
Contributor III

Hi Alexis this is what I'm trying to do, but there seems to be a problem with this particular combination as if I do a 10bit transfer I get what I expect 10 bits clocked out per frame with 

#define BUFFER_SIZE (2)
static uint8_t srcBuff[BUFFER_SIZE];
static uint8_t destBuff[BUFFER_SIZE];

spi_master_config_t userConfig = {0};
uint32_t srcFreq = 0;
uint32_t i = 0;
uint32_t err = 0;
spi_transfer_t xfer = {0};

for (i = 0; i < BUFFER_SIZE; i++)
{
srcBuff[BUFFER_SIZE] = 0xA5;
}

SPI_MasterGetDefaultConfig(&userConfig);
srcFreq = EXAMPLE_SPI_MASTER_CLK_FREQ;
userConfig.sselNum = (spi_ssel_t)EXAMPLE_SPI_SSEL;
userConfig.sselPol = (spi_spol_t)EXAMPLE_SPI_SPOL;
userConfig.dataWidth = kSPI_Data10Bits;
SPI_MasterInit(EXAMPLE_SPI_MASTER, &userConfig, srcFreq);

//Start Transfer
xfer.txData = srcBuff;
xfer.rxData = destBuff;
xfer.dataSize = 2;
xfer.configFlags = kSPI_FrameAssert;
 SPI_MasterTransferBlocking(EXAMPLE_SPI_MASTER, &xfer);

but when I go and just change to 9 bits with userConfig.dataWidth = kSPI_Data9Bits;

it jumps to clocking out 18bits. 

So how can I get the elusive 9 bits?

Cheers

Ian

0 Kudos
3,016 Views
Alexis_A
NXP TechSupport
NXP TechSupport

Hello Ian,

Have you tried using one transmission with for example 11 bit-s and the other one for 8-bit? This to have one filtered transmission and the other to received as it is.

Best Regards,

Alexis Andalon

0 Kudos
3,016 Views
iann
Contributor III

Yes all the other combinations work, 10bits through to 16 bits. It's just the one I need 9bits that doesn't, so I assume there's an error in the sdk, is there a fix?

Cheers

Ian

0 Kudos