AnsweredAssumed Answered

STM32F2xx DMA->SPI->16 Bit TX Problem

Question asked by morrison.simon on May 31, 2017
Latest reply on Jun 1, 2017 by morrison.simon

I am trying to send a large buffer of samples to an external DAC using SPI to create arbitrary waveforms. I have previously done this successfully for 8-bit data and have tried to adapt my code to work with a 16-bit data word size and 16-bit SPI transfers. I am using Hardware NSS and TI mode to activate the external DAC's Synch input at the end of each 16 bits. All of this seems to work. I get the correct number of 16-bit transfers and activations of SCLK and NSS. There are no gaps in the transmission.

 

The problem is the SPI/DMA seems to be transferring only every second word of data. I have captured this on the scope. My test data array is set thus and I have verified its contents using the debugger:

 

uint16_t Pulse_Buffer[10000] = { 0U, 0U, 0x2000U, 0x1000U, 0x800U, 0x400U, 0x200U, 0x100U, 0x80U, 0x40U, 0x20U, 0x10U, 0U, 0U, 0U, 0U };

 

On the scope I see every other word is missing e.g. 0U, 0x1000U, 0x400U, 0x100U, 0x40U, 0x10U, 0U, 0U

 

My set up routine is this: hopefully this is enough for somebody can tell me what I'm doing wrong. This uses the current Standard Peripheral Library. This is based on the excellent post at: https://javakys.wordpress.com/2014/09/04/how-to-implement-full-duplex-spi-communication-using-spi-dma-mode-on-stm32f2xx-or-stm32f4xx/ but I have adapted it for one-way communications, using hardware NSS, SPI1, DMA2, etc.

 

static void SPIDMA_Init(uint16_t buffersize)
{
 GPIO_InitTypeDef GPIO_InitStructure;
 SPI_InitTypeDef SPI_InitStructure;
 DMA_InitTypeDef DMA_InitStructure;

 /* enable the peripheral clocks for SPI1 and DMA */
 RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_DMA2, ENABLE);
 RCC_APB2PeriphClockCmd( RCC_APB2Periph_SPI1, ENABLE);
 /* On my system The main i/o init function sorts out the clock for port B */
 
 /* init the GPIOs and set to alternate function */
 /* enable the MOSI and SCLK pins */
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_5;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
 GPIO_Init(GPIOB, &GPIO_InitStructure);
 
 // For NSS
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;// was down
 GPIO_Init(GPIOA, &GPIO_InitStructure);
 
 
 /* Connect SPI pins to AF_SPI1 */
 GPIO_PinAFConfig(GPIOB, GPIO_PinSource3, GPIO_AF_SPI1); //SCLK
 GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_SPI1); //MOS1
 GPIO_PinAFConfig(GPIOA, GPIO_PinSource15, GPIO_AF_SPI1); //NSS
 SPI_TIModeCmd(SPI1, ENABLE);
 
 /* SPI Config */
 SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx; //SPI_Direction_2Lines_FullDuplex;
 SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
 SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b; //SPI_DataSize_8b;
 SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
 SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
 SPI_InitStructure.SPI_NSS = SPI_NSS_Hard; 
 /* This should be about 2.133 us per bit, just under 500Kb/s */
 SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;
 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_LSB; //SPI_FirstBit_MSB;
 SPI_InitStructure.SPI_CRCPolynomial = 7;
 
 SPI_Init(SPI1, &SPI_InitStructure);
 

 
 /* Deinitialize DMA Streams */
 DMA_DeInit(DMA2_Stream3); //SPI1_TX_DMA_STREAM
 // This creates n x 16 bit cycles
 DMA_InitStructure.DMA_BufferSize = (uint16_t)(buffersize + 1);
 DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable ;
 DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull ;
 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
 
 DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(SPI1->DR));
 DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; 
 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // probably doesn't matter for memory -> peripheral? Have tried it both ways no difference
 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
 DMA_InitStructure.DMA_Priority = DMA_Priority_High;
 
 /* Configure Tx DMA */
 DMA_InitStructure.DMA_Channel = DMA_Channel_3;
 DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
 DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)(&Pulse_Buffer);
 DMA_Init(DMA2_Stream3, &DMA_InitStructure);
 
 /* Enable the DMA channel */

 DMA_Cmd(DMA2_Stream3, ENABLE); /* Enable the DMA SPI TX Stream */

 SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);
 
 SPI_Cmd(SPI1, ENABLE);
 
}
Any ideas gratefully received
Thanks, Simon Morrison

Outcomes