cancel
Showing results for 
Search instead for 
Did you mean: 

DMA to external DAC transfer via SPI communication

franck2
Associate II
Posted on November 13, 2014 at 13:32

Hi everybody,

I'm a beginner with STM32F30x µP. I'd like to made a DMA transfers from SRAM to an external DAC via SPI communication. Is it possible? Can I even configure a timer (TIMx) to generate a PWM signal or One Pulse Mode signal on TIMx_CHx and use it as DMA trigger and also as NSS signal input to latch the SPI data transfers to my external DAC?

Thanks for your advice on that point.

Regards,

Franck
19 REPLIES 19
megahercas6
Senior
Posted on November 13, 2014 at 15:20

Not exactly,

you could generate data stream, with CLK and MOSI, but you will not be able to toggle CS pin to make it work, or at least this is what i know, i never had luck with hard_cs on stm32

but i can give you code for internal SRAM to internal DAC, triggered by timer, it does work for me,

franck2
Associate II
Posted on November 13, 2014 at 16:13

Hi Linas,

I need a DAC resolution of 12bit ILN +/-1LSB for my application. The STM32F30x internal DAC is really bad. On page 109 of DM00093333(STM32F302x6/x8) the electrical specifications of DAC are given. ILN given for a 12-bit input code of ±4 max LSB with note3: ''Data based on characterization results, not tested in production''. So as far I can't use the internal DAC! That's why I select an external one (AD5628 -Octal 12 bits SPI voltage output).

Also reference manual RM0365 DM00094349 gives at pg159 the summary of DMA1 request for each channel. (STM32F302 I am working with, uses only DMA1 which have 7 configurable channels). I've attached also a timer comparison table. It shows for my application which timer I can use.

Why can't I used TIM2 to generate a PWM signal on TIM2_CH2 for example and use it as DMA trigger and also as NSS signal input to latch the SPI data transfers?

________________

Attachments :

Timer_Feature_comparison.xlsx : https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006Hyhm&d=%2Fa%2F0X0000000bkd%2F5nLl3z88vP1_4CdRV0dtiATqh07A3II9MRvK5eoCEqc&asPdf=false
Posted on November 13, 2014 at 16:37

> Why can't I used TIM2 to generate a PWM signal on TIM2_CH2 for example and use it as DMA trigger and also as NSS signal input to latch the SPI data transfers?

IMO you can. Why don't you simply try?

I personally would divide the problem: first, learn to set up the timer, then leran to set up SPI with ''manual'' ''filling'' of data register, then learn to set up the DMA.

There will be some latency between TIM2_CH2 event and start of SPI transmission, and this latency will have some jitter dependent on load on the DMA controller and involved buses, so count on this and don't try to make a too tight timing of the NSS signal.

JW

franck2
Associate II
Posted on November 13, 2014 at 17:22

Hi Jan,

IMO you can. Why don't you simply try?

By the way i will try ;0)))

Thanks for your advices.

Franck

megahercas6
Senior
Posted on November 13, 2014 at 20:16

I try to make this program work from on my STM32F429i devkit. So far i don't know how to trigger dma with Timer.

however, i could give you program that will generate high duty cycle PWM, and inside low period it i will generate TIM1_CC_IRQHandler interrupt program, that could transfer one 16b halfword to spi, with software CS. But i guess this is not what you are trying to achieve

franck2
Associate II
Posted on November 14, 2014 at 10:07

Hi Linas,

I read in the DM00068049_Description of STM32F30xx-STM32F31xx Standard Peripheral Library about the following DMA/TIM instruction on page 186:

Function Name void DMA_Init ( DMA_Channel_TypeDef *  DMAy_Channelx, DMA_InitTypeDef *  DMA_InitStruct) 

 

Function Description  Initializes the DMAy Channelx according to the specified parameters in the DMA_InitStruct.

Parameters :

 

  • DMAy_Channelx :  where y can be 1 or 2 to select the DMA and x can be 1 to 7 for DMA1 and 1 to 5 for DMA2 to select the DMA Channel. 

     

  • DMA_InitStruct :  pointer to a DMA_InitTypeDef structure that contains the configuration information for the specified DMA Channel.  

     

  • Return values : None. 

     

  • Notes : None
So I am thinking of doing:

 /* DMA TIM trigger channel Configuration */

    DMA_InitStructure.DMA_BufferSize = (uint16_t)1;

    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)SPIx_DR_ADDRESS;

    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) &CommandTransmitted;

    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;

    DMA_InitStructure.DMA_Priority = DMA_Priority_Low;

    DMA_Init(TIMx_CHANNEL_DMA_CHANNEL, &DMA_InitStructure);

with a

  /* TIM Capture Compare DMA Request enable */

  TIM_DMACmd(TIMx, TIMx_DMA_CHANNEL, ENABLE);

What do you think about it?

Can you please send me in attachment your code....It can help.

 As I said I'm a beginner....

Thanks.

Best regards,

Franck

franck2
Associate II
Posted on November 14, 2014 at 11:43

Hi Linas,

Can you please send me your code example? Thanks a lot.

Franck

franck2
Associate II
Posted on November 19, 2014 at 15:16

Hi Linas,

I'm still working hard on DMA to extarnal DAC through SPI communication on STM32F302. In one of your email you said you can provide me with a program able to generate high duty cycle PWM, and inside low period it i will generate TIM1_CC_IRQHandler interrupt program, that could transfer one 16b halfword to spi, with software CS.

Can you please share it attached it?

Thanks a lot.

Best regards,

Franck

megahercas6
Senior
Posted on November 19, 2014 at 18:04

uint32_t adc_pointer = 0;
void TIM1_CC_IRQHandler(void)
{
if (TIM_GetITStatus(TIM1, TIM_IT_CC1) != RESET)
{
ToDo
TIM_ClearITPendingBit(TIM1, TIM_IT_CC1);
}
}
void TIM_Config_Update(void)
{
TIM_TimeBaseStructure.TIM_Period = period;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); 
TIM_OCInitStructure.TIM_Pulse = ccr;
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
}
void TIM_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
/* GPIOA Configuration: Channel 1, 2, 3, 4 and Channel 1N as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_TIM1);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1 , ENABLE);
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = period;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
TIM_OCInitStructure.TIM_Pulse = ccr;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset; ;//TIM_OCIdleState_Set;
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Set;//TIM_OCIdleState_Reset;
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
TIM_ITConfig(TIM1,TIM_IT_CC1,ENABLE);
/* TIM1 counter enable */
TIM_Cmd(TIM1, ENABLE);
/* TIM1 Main Output Enable */
TIM_CtrlPWMOutputs(TIM1, ENABLE);
}

you can use this for CS, but you have to figure out how to trigger dma via timer. i did same configuration with update, but it was not successful