cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 SPI DMA for External SPI DAC

fabio1
Associate II
Posted on January 25, 2014 at 21:34

Hi,

I am trying to sample some data using DMA and the internal ADC and send the same data , still using DMA to an external DAC using the SPI Internface, through an optoisolation barrier.

It all works great, I need 1MS/s  and this is not a problem.

Still I need to qualify the data using a NSS line and TI Mode works fine, but the lack of wait states makes my task hard.

The NSS is released on the 14th byte and re-issued on the 15th. Most of the DACs (I have been using DAC8311 for a while) need some time between the sync signal and the new data, so the NSS line needs to be inactive for a while between the subsequent data.

I could not find any suitable DAC.

Is the interface not suitable for such a task or am I missing something?

Thanks

Fabio

 

12 REPLIES 12
Posted on January 26, 2014 at 17:51

You might want to use timer-triggered DMA.

JW

fabio1
Associate II
Posted on January 26, 2014 at 18:36

Thanks for your suggestion,

If I understand you properly, you suggest to qualify the data via software in an IRS.

I think this will not work because of the enormous amount of interrupts (@1MS/s I'll get 1 Interrupt every us).

I either need DACs that support continuos mode, or I need to make somehow the transfer discontinuos to let the DAC have the necessary settling time or either build external glue logic (please noooo.....)

Fabio

Posted on January 26, 2014 at 23:39

No, what Jan is suggesting is that you pace the SPI DMA with a timer driven request instead of an SPI-TXE one.

That said the STM32 SPI implementation is going to be totally useless driving NSS in a useful way.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on January 26, 2014 at 23:42

What about a DAC using an I2S data stream?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on January 27, 2014 at 08:34

> No, what Jan is suggesting is that you pace the SPI DMA with a timer driven request instead of an SPI-TXE one.

That is. The DMA transfer source/target does not necessarily needs to involve the trigger source, so you can trigger it from a timer (i.e. use stream/channel ''assigned to'' the timer) but set the SPI DR as transfer target. It's not obvious at the first reading, I guess.

Of course, the timing has to be set right, and possible latency of the DMA transfer has to be taken into account.

> That said the STM32 SPI implementation is going to be totally useless driving NSS in a useful way.

Clive, Fabio above said he is OK with the TI mode.

Alternatively, the same timer's compare could be used to generate a select signal, perhaps.

> I2S

That sounds like an interesting option, too, a bit less flexible perhaps, as the ''wait'' would be fixed to the same time as the transfer lasts - but it is up to Fabio to judge whether this fits his needs.

JW

fabio1
Associate II
Posted on January 29, 2014 at 09:48

First of all thanks a lot.

1) Timer driven DMA : well , I guess it might work.

Using TI Mode the CS (NSS) line will be possibly driven by the hardware so there is no need for an additional interrupt to qualify the data.

The only problem I still have with TI mode, is that the CS line is released while the MOSI line is transmitting the LSB (or MSB). This might result in data corruption on the DAC.

I'll check it out and let you know.

2) I2S : this is also an interesting option, unfortunately as far as now I could not find suitable DACs. I2S is mostly used for audio applications and so the data rate is limited.

I need somthing close to a 1MS/s. Any suggestion ?

I'll keep on searching.

3) I see anyhow that Continuos TI Mode transfer is similar to the Microchip 'SPI Framed mode and so I wonder what this mode is intended for.

Master slave data transfer between two microcontrollers is an option but I don't see many advantages

Does anybody know what the main purpose of this mode is?

Thanks

Fabio

fabio1
Associate II
Posted on January 31, 2014 at 16:30

So,

i decided to go for a timer triggered DMA transfer but I can't get it running... :(

Well this is what I do,

TMR3 is configured in PWM mode, works

      RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM3, ENABLE );

      RCC_TIMCLKPresConfig(RCC_TIMPrescActivated);

      /* Time base configuration */

      TIM_TimeBaseStructure.TIM_Period = 150;

      TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t) (SystemCoreClock / 40000000) - 1;

      TIM_TimeBaseStructure.TIM_ClockDivision = 0;

      TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

      TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

      /* PWM1 Mode configuration: Channel1 */

      TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;

      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

      TIM_OCInitStructure.TIM_Pulse = 5;

      TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

      TIM_OC1Init(TIM3, &TIM_OCInitStructure);

      TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);

      TIM_SelectOutputTrigger(TIM3, TIM_TRGOSource_Update);

      TIM_Cmd(TIM3, ENABLE );

than I try to start

DMA1 Stream 2 channel5 to get a DMA triggered everytime the timer overflows

       RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);

       DMA_DeInit(DMA1_Stream2);

       DMA_StructInit(&DMA_InitStructure);

       DMA_InitStructure.DMA_Channel            = DMA_Channel_5;

       DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI4->DR;

       DMA_InitStructure.DMA_Memory0BaseAddr    = (uint32_t)&uwADC3ConvertedVoltage;

       DMA_InitStructure.DMA_DIR                = DMA_DIR_MemoryToPeripheral;

       DMA_InitStructure.DMA_BufferSize         = 1;

       DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;

       DMA_InitStructure.DMA_MemoryInc          = DMA_MemoryInc_Disable;

       DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

       DMA_InitStructure.DMA_MemoryDataSize     = DMA_MemoryDataSize_HalfWord;

       DMA_InitStructure.DMA_Mode               = DMA_Mode_Normal;

       DMA_InitStructure.DMA_Priority           = DMA_Priority_High;

       DMA_InitStructure.DMA_FIFOMode           = DMA_FIFOMode_Disable;

       DMA_InitStructure.DMA_FIFOThreshold      = DMA_FIFOThreshold_HalfFull;

       DMA_InitStructure.DMA_MemoryBurst        = DMA_MemoryBurst_Single;

       DMA_InitStructure.DMA_PeripheralBurst    = DMA_PeripheralBurst_Single;

       DMA_ITConfig(DMA1_Stream2, DMA_IT_TC, DISABLE);

       DMA_Init(DMA1_Stream2, &DMA_InitStructure);

       DMA_Cmd(DMA1_Stream2, ENABLE);

       TIM_DMACmd(TIM3, TIM_DMA_Update, ENABLE);

Can't get it running....

fabio1
Associate II
Posted on February 02, 2014 at 15:14

I fixed the issue,

it was trivial, as usual :((

DMA1 is not connected to APB2 and thus cannot trigger SPI4 transfers.

I was trying to use the free pins on the 429discovery and didn't care much.

Now TMR1 Ch3, pin PC8 is free, DMA2 on APB2 works.

DMA sampling 1MS/s and sendind out SPI4, 500kS/s is not a problem.

I send the data back and forth through an optoisolation barrier for kW level current control.

Fabio

jakopinorama
Associate II
Posted on July 20, 2014 at 12:49

Hi Fabio!

Thank you for this nice post. 

How did you configure the SPI? Do you require any additional code to start the transfer?

Thank you for your answers,

Blaz