Skip to main content
fabio1
Associate II
January 25, 2014
Question

STM32 SPI DMA for External SPI DAC

  • January 25, 2014
  • 12 replies
  • 3068 views
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

 

    This topic has been closed for replies.

    12 replies

    waclawek.jan
    Super User
    January 26, 2014
    Posted on January 26, 2014 at 17:51

    You might want to use timer-triggered DMA.

    JW

    fabio1
    fabio1Author
    Associate II
    January 26, 2014
    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

    Tesla DeLorean
    Guru
    January 26, 2014
    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 VenmoUp vote any posts that you find helpful, it shows what's working..
    Tesla DeLorean
    Guru
    January 26, 2014
    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 VenmoUp vote any posts that you find helpful, it shows what's working..
    waclawek.jan
    Super User
    January 27, 2014
    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
    fabio1Author
    Associate II
    January 29, 2014
    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
    fabio1Author
    Associate II
    January 31, 2014
    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
    fabio1Author
    Associate II
    February 2, 2014
    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
    July 20, 2014
    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

    franck2
    Associate III
    November 24, 2014
    Posted on November 24, 2014 at 15:46

    Hi Fabio,

    Same question as Blaz.

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

    Thank you for your answers,

    Franck