AnsweredAssumed Answered

TIM1 to control DMA peripheral-to-memory (8 ADCs)

Question asked by piovanelli.matteo on Apr 2, 2014
Latest reply on Apr 2, 2014 by piovanelli.matteo
Hello, 
Me again with basic questions.

I am still trying to acquire from a bank of ADCs. 8 SAR ADCs in parallel on my stm32f429i-disco. From previous forum posts, and my own attempts, it appears I cannot use the HSI clock directly by putting it out on MCO1 and reading its transitions. So I am trying to learn how to use TIM1 and a peripheral-to-memory DMA. Since it's TIM1, I'll use DMA2.

Because of the ADCs I have, a full read takes 16 cycles of the clock I send them (call it SCLK):
 - 4 leading zeros
 - 8 bits of data
 - 4 trailing zeros

I generate the SCLK from the TIM1 and put it out on PA8:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
    //Fill the TIM_TimeBaseInitStruct with the desired parameters
//  TIM_TimeBaseInitTypeDef base;
    TIM_TimeBaseStructInit(&TIM1_Settings);
    TIM1_Settings.TIM_Prescaler = 0;
    TIM1_Settings.TIM_CounterMode = TIM_CounterMode_Up;
    TIM1_Settings.TIM_Period = 5; //AutoReload value in the TIM1->ARR register
    TIM1_Settings.TIM_ClockDivision = 0;
//configure the Time Base unit with the corresponding configuration
    TIM_TimeBaseInit(TIM1, &TIM1_Settings);
    /* Channel 1 output configuration */
    TIM_OCInitTypeDef OCbase;
    TIM_OCStructInit(&OCbase);
    OCbase.TIM_OCMode = TIM_OCMode_PWM2;
    OCbase.TIM_OutputState = TIM_OutputState_Enable;
    OCbase.TIM_Pulse = 2;
    OCbase.TIM_OCPolarity = TIM_OCPolarity_Low;
    OCbase.TIM_OCIdleState = TIM_OCIdleState_Set;
    TIM_OC1Init(TIM1, &OCbase);
    //Enable TIM1 output on pin PA8
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_TIM1);
    /* Very much needed.  Enable Preload register on CCR1. */
    TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
    //Enable Timer
  TIM_Cmd(TIM1, ENABLE);
    /* TIM1 Main Output Enable */
    TIM_CtrlPWMOutputs(TIM1, ENABLE);
With the settings above (along with my clock settings), the SCLK clock I see on PA8 is at 15.77MHz, with sightly less than 50% duty cycle. 

I my acquisition code, I would like to start the DMA peripheral reading after the leading zeros, and synch it to the rising edge of the SCLK (read 1 bit from the 8 ADCs on each rising edge of SCLK). The ADCs start converting when I set their chip select CS to low:
//before assigning CS=0, we need to wait for the SCLK to be high, for synch reasons
while(SCLK==0);
 CS_TO_LOW;
TIM1->RCR = 3; //Set the repetition value to skip 4 leading zeros
TIM1->DIER |= TIM_IT_Update; //enable update interrupt
while((TIM1->SR & TIM_IT_Update) == 0); //wait until update flag
SCLK in the code is a macro that queries the  GPIOA->IDR to see if the output of PA8 is zero; CS_TO_LOW is a macro that lowers the value I output as chip select. They both work.
In my mind, after the execution of the snippet above I should have skipped the four leading zeros, and be ready to have my DMA read the 8 bytes from the ADC bank.

I am stumped as to how to proceed from there.
Should I disable the TIM1 update interrupt, and have the DMA2 stream synch on the TIM1 clock? In that case, which one of the TIM1 "events" would cause the DMA2 transaction to synch with the rising edges of SCLK? (like TIM1_CH1? or what else?) I would then wait for an interrupt from the DMA2 telling me the 8 bytes have been transferred, and after 4 more cycles I would set CS to 1 thus ending a reading.
OR
Should I cause the TIM1 update interrupt to trigger on every period (assuming a period corresponds to the period of SCLK i see on PA8), and use that interrupt to cause a single DMA transfer (of 1 byte) from DMA2.Stream5.Channel6?

I hope I provided enough information to get some advice.

Best,
Matteo

Outcomes