LPC55S6x DMA on High speed SPI

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

LPC55S6x DMA on High speed SPI

1,817 Views
jreh
Contributor I

I have a DMA triggering from a SCTimer transmitting on the SPI bus every 10uS.  This works, I'm happy.  The issue I have is that the buffer that the DMA is sourcing from is 32 bits for each entry; address, data, and the upper 16 bits which has the CS, transfer type etc.

I want the source buffer entries to be 16 bits, address and data only.  I've written to the upper 16 bits, offset 0x0E22, of the FIFOWR register with the correct pattern prior to starting the DMA, and set the source buffer to be uint16_t.  Set up the DMA_CHANNEL_XFER to 16 bits wide and halved the number of bytes to transfer from the 32 bit version.  But it doesn't work.  It outputs 4 SPI transfers as fast as possible then stops.  The source buffer has 512 entries.

Does the SPI DMA operations always have to be 32 bits?  If not, what else am I missing?

 

Thanks

Jeff

0 Kudos
9 Replies

1,780 Views
Alice_Yang
NXP TechSupport
NXP TechSupport

Hello jreh,

I‘m not very clear your meaning, while it is confirm that DMA support 16 bit transfer width.

 

Alice_Yang_0-1653292610998.png

 

BR

Alice

 

0 Kudos

1,775 Views
jreh
Contributor I

Hi Alice, The DMA is setup to transfer an array[] which the entries are 32 bits each.  Each entry has the upper 16 bits of the SPI FIFO control bits, and the lower 16 has the address and data. 

I would like to reduce the array[] to 16 bits, address and data, after setting the upper 16 bits once.  I've tried, but for the DMA it doesn't work.  It sends out 3-4 SPI transfers, which were wrong and hangs-up.

Is it possible to have a 16 bit array[] for a DMA SPI transfer?

 

Thanks

0 Kudos

1,755 Views
Alice_Yang
NXP TechSupport
NXP TechSupport

Hello,

Could you please share your project or code about how to config?

 

BR

Alice

0 Kudos

1,751 Views
jreh
Contributor I

Below is the present code that is working with 32 bit entries for the SPI DMA.  There's a switch,  DMA_16, which is where I tried 16 bit entries.  The DMA is transferring from RAM, 32 bit entries or attempted 16 bit entries, to SPI8/FLexComm8 which is the high speed SPI.

 


void DMA0init( void )
{
// Turn off spi timer, and disable DMA0
haltDMATrigger( );
DMA0->CTRL = 0UL; // Disable DMA0

// Get input mux up and running, apply clocks, reset, etc.
INPUTMUX_Init( INPUTMUX );

// CTimer2 match 0 is trigger input
INPUTMUX->DMA0_ITRIG_INMUX[3] = 8;

// Enable clocks to, reset, then enable DMA0
DMA_Init( DMA0 );

// Set up DMA0 channel 3
DMA_EnableChannel( DMA0, DMA0_CHANNEL_3 );

/* Fill in DMA0_CH3_Handle handle */
DMA_CreateHandle( &DMA0_CH3_Handle, DMA0, DMA0_CHANNEL_3 );

// Set up when done
DMA_SetCallback( &DMA0_CH3_Handle, DMA_Callback, NULL );

/* Enable the DMA on channel 3 in the DMA */
DMA_EnableChannel( DMA0, DMA0_CHANNEL_3 );

// This will start the trigger(s), when enabled
startSpiTimer( );
}

/*
* Will start the DMA engine to transfer data, pointed to with input parameter
* srcBuffer. The number of SPI transfers is also passed in with input parameter
* N_spiTransfers. N_spiTransfers is number of transfers, not bytes.
* The user can monitor when the DMA process is done, ie. all the data has been
* transfered, by calling dmaIsActive( ) or place a callback in DMA0_IRQHandler( )
*/
#if DMA_16
void startDMA0Transfer( uint16_t *srcBuffer, uint32_t N_spiTransfers )
{
// Sanity check
if( 0 == N_spiTransfers )
{
return;
}

// Set up upper control lines
*(uint16_t *)((&(SPI8->FIFOWR))+2UL) = UPPER_FIFO_DMA >> 16;

DMA_PrepareChannelTransfer( &dmaConfig, /* dma_channel_config_t that gets filled in */
srcBuffer, /* Pointer to source of data to output */
(void *)&(SPI8->FIFOWR), /* Destination address */
/* DMA_CHANNEL_XFER(reload, clrTrig, intA, intB, width, srcInc, dstInc, bytes) */
DMA_CHANNEL_XFER(false, true, true, false, kDMA_Transfer16BitWidth, kDMA_AddressInterleave1xWidth, kDMA_AddressInterleave0xWidth, (N_spiTransfers*2UL) ),
kDMA_MemoryToPeripheral, /* Reading from srcBuffer, writing to SPI8->FIFOWR */
&dmaChan3Trigger, /* Pointer to how the trigger is hangled */
NULL ); /* Pointer to any data to be used in callback */

#else
void startDMA0Transfer( uint32_t *srcBuffer, uint32_t N_spiTransfers )
{
// Sanity check
if( 0 == N_spiTransfers )
{
return;
}

DMA_PrepareChannelTransfer( &dmaConfig, /* dma_channel_config_t that gets filled in */
srcBuffer, /* Pointer to source of data to output */
(void *)&(SPI8->FIFOWR), /* Destination address */
/* DMA_CHANNEL_XFER(reload, clrTrig, intA, intB, width, srcInc, dstInc, bytes) */
DMA_CHANNEL_XFER(false, true, true, false, kDMA_Transfer32BitWidth, kDMA_AddressInterleave1xWidth, kDMA_AddressInterleave0xWidth, (N_spiTransfers*4UL) ),
kDMA_MemoryToPeripheral, /* Reading from srcBuffer, writing to SPI8->FIFOWR */
&dmaChan3Trigger, /* Pointer to how the trigger is hangled */
NULL ); /* Pointer to any data to be used in callback */


#endif

DMA_SubmitChannelTransfer( &DMA0_CH3_Handle, &dmaConfig );

// Start the request for a DMA
DMA_StartTransfer( &DMA0_CH3_Handle );

// This will start the trigger(s)
SPI8->FIFOCFG |= SPI_FIFOCFG_DMATX_MASK;
DMA0->CTRL = 1UL; // Enable DMA0
startSpiTimer( ); // Clear residual trigger and start timer
}

0 Kudos

1,735 Views
Alice_Yang
NXP TechSupport
NXP TechSupport

Hello,

What about the definition of srcBuffer :

 

Alice_Yang_0-1653882463018.png

 

BR

Alice

 

0 Kudos

1,729 Views
jreh
Contributor I

uint32_t txDataBuffer32[] __attribute__((aligned(sizeof(uint32_t)))) = {
( UPPER_FIFO_DMA | (0x00 << | CC1125_REG_TXRX_FIFO ),
( UPPER_FIFO_DMA | (0x01 << | CC1125_REG_TXRX_FIFO ),
( UPPER_FIFO_DMA | (0x02 << | CC1125_REG_TXRX_FIFO ),
( UPPER_FIFO_DMA | (0x03 << | CC1125_REG_TXRX_FIFO ),
( UPPER_FIFO_DMA | (0x04 << | CC1125_REG_TXRX_FIFO ),...........

Where

#define UPPER_FIFO_DMA ( SPI_XFER_LEN | SPI_FIFOWR_RXIGNORE_MASK | SPI_FIFOWR_EOF_MASK | SPI_FIFOWR_EOT_MASK | SPI_FIFOWR_TXSSEL0_N_MASK )

And where

#define SPI_XFER_LEN ((16UL - 1UL) << SPI_FIFOWR_LEN_SHIFT)

 

Thanks

 

0 Kudos

1,723 Views
Alice_Yang
NXP TechSupport
NXP TechSupport

Hello,

How about change source type   to (uint16_t *) to transfer.

And recommend you first transfer some simple data to confirm DMA-SPI with 16 bits type can work well.

 

BR

Alice

0 Kudos

1,716 Views
jreh
Contributor I

Hi Alice,

Thanks for sticking with this.

I've already tried what you've asked.  In the code there's a #define DMA_16, which switches between using 32 bit transfers and attempting 16 bit transfers.  The switch is used in section of code is below;


#if !DMA_16
uint32_t txDataBuffer32[] __attribute__((aligned(sizeof(uint32_t)))) = {
( UPPER_FIFO_DMA | (0x00 << | CC1125_REG_TXRX_FIFO ),
( UPPER_FIFO_DMA | (0x01 << | CC1125_REG_TXRX_FIFO ),
( UPPER_FIFO_DMA | (0x02 << | CC1125_REG_TXRX_FIFO ),..............

( UPPER_FIFO_DMA | (0x7E << | CC1125_REG_TXRX_FIFO ),
( UPPER_FIFO_DMA | (0x7F << | CC1125_REG_TXRX_FIFO )
};
#else
uint16_t txDataBuffer16[] __attribute__((aligned(sizeof(uint16_t)))) = {
( (0x00 << | CC1125_REG_TXRX_FIFO ),
( (0x01 << | CC1125_REG_TXRX_FIFO ),
( (0x02 << | CC1125_REG_TXRX_FIFO ),
( (0x03 << | CC1125_REG_TXRX_FIFO ),
( (0x04 << | CC1125_REG_TXRX_FIFO ),......

( (0x7E << | CC1125_REG_TXRX_FIFO ),
( (0x7F << | CC1125_REG_TXRX_FIFO )
};
#endif

 

And the function which starts the DMA also uses the the same #define DMA_16

 

#if DMA_16
void startDMA0Transfer( uint16_t *srcBuffer, uint32_t N_spiTransfers )
{
// Sanity check
if( 0 == N_spiTransfers )
{
return;
}

// Set up upper control lines
*(uint16_t *)((&(SPI8->FIFOWR))+2UL) = UPPER_FIFO_DMA >> 16;

DMA_PrepareChannelTransfer( &dmaConfig, /* dma_channel_config_t that gets filled in */
srcBuffer, /* Pointer to source of data to output */
(void *)&(SPI8->FIFOWR), /* Destination address */
/* DMA_CHANNEL_XFER(reload, clrTrig, intA, intB, width, srcInc, dstInc, bytes) */
DMA_CHANNEL_XFER(false, true, true, false, kDMA_Transfer16BitWidth, kDMA_AddressInterleave1xWidth, kDMA_AddressInterleave0xWidth, (N_spiTransfers*2UL) ),
kDMA_MemoryToPeripheral, /* Reading from srcBuffer, writing to SPI8->FIFOWR */
&dmaChan3Trigger, /* Pointer to how the trigger is hangled */
NULL ); /* Pointer to any data to be used in callback */

#else
void startDMA0Transfer( uint32_t *srcBuffer, uint32_t N_spiTransfers )
{
// Sanity check
if( 0 == N_spiTransfers )
{
return;
}

DMA_PrepareChannelTransfer( &dmaConfig, /* dma_channel_config_t that gets filled in */
srcBuffer, /* Pointer to source of data to output */
(void *)&(SPI8->FIFOWR), /* Destination address */
/* DMA_CHANNEL_XFER(reload, clrTrig, intA, intB, width, srcInc, dstInc, bytes) */
DMA_CHANNEL_XFER(false, true, true, false, kDMA_Transfer32BitWidth, kDMA_AddressInterleave1xWidth, kDMA_AddressInterleave0xWidth, (N_spiTransfers*4UL) ),
kDMA_MemoryToPeripheral, /* Reading from srcBuffer, writing to SPI8->FIFOWR */
&dmaChan3Trigger, /* Pointer to how the trigger is hangled */
NULL ); /* Pointer to any data to be used in callback */


#endif

DMA_SubmitChannelTransfer( &DMA0_CH3_Handle, &dmaConfig );

// Start the request for a DMA
DMA_StartTransfer( &DMA0_CH3_Handle );

// This will start the trigger(s)
SPI8->FIFOCFG |= SPI_FIFOCFG_DMATX_MASK;
DMA0->CTRL = 1UL; // Enable DMA0
startSpiTimer( ); // Clear residual trigger and start timer
}

The 32 bit transfers work.  The 16 bit version outputs 3-4 transfers with garbage, not the data that's in the array.

Thanks

Jeff

0 Kudos

1,700 Views
Alice_Yang
NXP TechSupport
NXP TechSupport

Hello,

I think the best way is debug to check step by step.

For example first check whether DMA transfer right data from source to destination.

then measure MOSI pin, whether send right data out?

Also test if disable DMA, SPI whether can work well?

 

BR

Alice

0 Kudos