Skip to main content
franck2
Associate III
December 1, 2014
Question

Is there anaybody that have a TIM triggered DMA working Code?

  • December 1, 2014
  • 24 replies
  • 3080 views
Posted on December 01, 2014 at 22:49

I'm stuck on TIM triggered DMA to SPI.

My DMA Code configuration is as follow:

void DMA_Configuration(void)

 {

     DMA_InitTypeDef               DMA_InitStructure;

    

     /* Enable DMA1 clock */

   RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    

     /* Blank DMA Configuration */

     DMA_DeInit(DMA1_Channel1);      

    

     /* Using the default values at Startup */

     DMA_StructInit(&DMA_InitStructure);            

   /*Changes from the default values */    

     DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(SPI2->DR);            // Address of peripheral the DMA must map to => SPI2 Data Register

   DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) TTxBuffer;                // Variable to which received data will be stored

     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;                           // Direction of transfer Memory to Peripheral =Destinatary

   DMA_InitStructure.DMA_BufferSize = 32;                                       // BufferSize

   DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;             // We don't want to change the SPI2 Data register

   DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                      // We increment Memory

   DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;      // We define Peripheral Data Size as Byte

   DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;              // We define Memory Data Size as Byte

   DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                              // Circular Mode define

   DMA_InitStructure.DMA_Priority = DMA_Priority_High;                          // High Priority

   DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                                 // Memory to Memory Disable

    

      /* Initialize the DMA */

     DMA_Init(DMA1_Channel1, &DMA_InitStructure);           

    

     /* Enable the DMA transfer half and complete interrupt */

     DMA_ITConfig(DMA1_Channel1, DMA_IT_HT, ENABLE);                               // Half Transfer Interrupt Enable

   DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);                                 // Full transfer Interrupt Enable

    

     /* Enable the DMA TIM Triggered */

     TIM_DMACmd(TIM2, TIM_DMA_Trigger, ENABLE);

     TIM_DMACmd(TIM2, TIM_DMA_Update, ENABLE);

    

     /* Enable DMA1 Channel1 */

     DMA_Cmd(DMA1_Channel1, ENABLE);

 }

Looking at DMA_CCR1 gives me 0x2AB7 which is ok.

Looking at the SPI2_DR I found no value ; i.e. 0

Franck
    This topic has been closed for replies.

    24 replies

    franck2
    franck2Author
    Associate III
    December 3, 2014
    Posted on December 03, 2014 at 14:39

    The original post was too long to process during our migration. Please click on the provided URL to read the original post. https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I6gc&d=%2Fa%2F0X0000000btC%2FN5NG.gMlUI6rySsmSOwErAxCgvF72Dz3Cj7SwBg3br0&asPdf=false
    franck2
    franck2Author
    Associate III
    December 3, 2014
    Posted on December 03, 2014 at 14:57

    The original post was too long to process during our migration. Please click on the provided URL to read the original post. https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I6gh&d=%2Fa%2F0X0000000btD%2F7_Ac.WxsYh1anKZ6p1AnXr7TOnKfK1WOYzIbLN_K_54&asPdf=false
    Tesla DeLorean
    Guru
    December 3, 2014
    Posted on December 03, 2014 at 19:41

    This would seem to reasonably demonstrate SPI output paced via TIM+DMA, ported from my STM32F4-DISCO version.

    // STM32F3-Discovery SPI2 TX DMA TIM Demo - sourcer32@gmail.com
    #include ''stm32f3_discovery.h''
    #include ''stm32f30x.h''
    //******************************************************************************
    void RCC_Configuration(void)
    {
    /* Enable DMA1 clock */
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    /* Enable TIM1 clock */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
    /* Enable SPI2 clock */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
    /* GPIOB clock enable */
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
    }
    //******************************************************************************
    void GPIO_Configuration(void)
    {
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | 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;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_5); // PB13 SPI2 SCLK
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_5); // PB15 SPI2 MOSI
    }
    //******************************************************************************
    void TIM_Configuration(void)
    {
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_OCInitTypeDef TIM_OCInitStructure;
    int Prescaler, Period;
    Prescaler = (SystemCoreClock / 8000000); // 8 MHz timebase, assumes APB2 H/1 TIMCLK1 H/1
    Period = 8000000 / 8000; // 8 MHz -> 8 KHz
    /* Time base configuration */
    TIM_TimeBaseStructure.TIM_Period = Period - 1;
    TIM_TimeBaseStructure.TIM_Prescaler = Prescaler - 1;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
    // Need to add code to drive TIM1_CH1N as faux chip select
    // going LOW at UPDATE, with Pulse tuned to go high after DMA initiated burst
    // completes
    /* Output Compare PMW1 Mode configuration */
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;
    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCPolarity_High;
    TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
    TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
    TIM_OCInitStructure.TIM_Pulse = Period / 2; // 50%
    TIM_OC1Init(TIM1, &TIM_OCInitStructure);
    /* Enable pins, TIM1 more sensitive */
    TIM_CtrlPWMOutputs(TIM1, ENABLE);
    /* Enable the DMA trigger */
    TIM_DMACmd(TIM1, TIM_DMA_Update, ENABLE);
    /* TIM1 enable counter */
    TIM_Cmd(TIM1, ENABLE);
    }
    //******************************************************************************
    void SPI_Configuration(void)
    {
    SPI_InitTypeDef SPI_InitStructure;
    /* SPI configuration */
    SPI_I2S_DeInit(SPI2);
    /* Initializes the SPI communication */
    SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64; // APB1 36 MHz, SPI2 55 KHz
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_InitStructure.SPI_CRCPolynomial = 7;
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
    SPI_Init(SPI2, &SPI_InitStructure);
    /* Enable the SPI peripheral */
    SPI_Cmd(SPI2, ENABLE);
    }
    //******************************************************************************
    uint8_t TxBuffer[] = ''The quick brown fox jumps over the lazy dog'';
    void DMA_Configuration(void)
    {
    DMA_InitTypeDef DMA_InitStructure;
    // DMA1 Channel5 TIM1_UP
    /* DMA configuration */
    DMA_DeInit(DMA1_Channel5);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI2->DR;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&TxBuffer[0];
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_InitStructure.DMA_BufferSize = sizeof(TxBuffer) - 1;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel5, &DMA_InitStructure);
    /* Enable DMA Stream Transfer Complete interrupt */
    DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE);
    /* Enable the DMA channel */
    DMA_Cmd(DMA1_Channel5, ENABLE);
    }
    //******************************************************************************
    void NVIC_Configuration(void)
    {
    NVIC_InitTypeDef NVIC_InitStructure;
    /* Enable the DMA1 Channel5 Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    }
    //******************************************************************************
    void DMA1_Channel5_IRQHandler(void) // X Hz
    {
    /* Test on DMA1 Channel5 Transfer Complete interrupt */
    if(DMA_GetITStatus(DMA1_IT_TC5))
    {
    /* Clear DMA1 Channel5 Transfer Complete interrupt pending bits */
    DMA_ClearITPendingBit(DMA1_IT_TC5);
    STM_EVAL_LEDToggle(LED3); // X/2 Hz
    }
    }
    //******************************************************************************
    int main(void)
    {
    /* Initialize LED available on STM32F3-Discovery board */
    STM_EVAL_LEDInit(LED3);
    /* Turn on LD3 */
    STM_EVAL_LEDOn(LED3);
    RCC_Configuration();
    NVIC_Configuration();
    GPIO_Configuration();
    DMA_Configuration();
    SPI_Configuration();
    TIM_Configuration();
    while(1); /* Infinite loop */
    }
    /**************************************************************************************/
    #ifdef USE_FULL_ASSERT
    /**
    * @brief Reports the name of the source file and the source line number
    * where the assert_param error has occurred.
    * @param file: pointer to the source file name
    * @param line: assert_param error line source number
    * @retval None
    */
    void assert_failed(uint8_t* file, uint32_t line)
    {
    /* User can add his own implementation to report the file name and line number,
    ex: printf(''Wrong parameters value: file %s on line %d
    
    '', file, line) */
    /* Infinite loop */
    while (1)
    {
    }
    }
    #endif

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    franck2
    franck2Author
    Associate III
    December 4, 2014
    Posted on December 04, 2014 at 14:10

    Many, Many Thanks Clive.

    It works perfectly also on my evaluation board (STM32F3xx).

    Few questions:

    *Which pin is assign for TIM1? so I can see it on a GPIO pins of my STM32F.

    As far I understand it is going low at UPDATE with Pulse tuned to go high after DMA initiated burst completes. Right?

    Tesla DeLorean
    Guru
    December 4, 2014
    Posted on December 04, 2014 at 14:32

    Well that's functionality I didn't take to completion. You'd have to select a suitable pin/channel from the timer. I might tinker with it if I find some moments.

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    franck2
    franck2Author
    Associate III
    December 4, 2014
    Posted on December 04, 2014 at 16:20

    Hi Clive,

    You've done the job!

    It's my turn to keep going on and work on it!

    Thanks a lot, again.

    Best regards.

    franck2
    franck2Author
    Associate III
    December 12, 2014
    Posted on December 12, 2014 at 15:47

    Hi,

    I have a pb. Everything working perfectly as shown by attachment file.

    However looking to Reference Manual of STM32F302, the frame size of the SPI is 16-bits. My source is 32-bit. As indicated by still the manual the data will be truncated. Source 32-bit & Destination 16-bit. So @0x0 /B4B3B2B1 => @0x0/B1B0.

    How should I overcome?

    Thanks

    ________________

    Attachments :

    Screen_2014-12-12_03-40-37_0.jpeg : https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I0tO&d=%2Fa%2F0X0000000biX%2FpXvM2nxXWgCrATbT1PtiGSFYKYMx_HjlRy2K7khBdtk&asPdf=false
    Tesla DeLorean
    Guru
    December 12, 2014
    Posted on December 12, 2014 at 16:52

    I'm not sure how two back-to-back 16-bit bus transactions, without intervening CS, would be materially different than one 32-bit transaction.

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    franck2
    franck2Author
    Associate III
    December 12, 2014
    Posted on December 12, 2014 at 18:01

    Clive,

    I send a 32-bits word ABCD1234 and obtain only 1234 on the SPI as shown by the attachement as expected and said by the Reference Manual. Do I misunderstand something?

    SPI configured with a 16-bit Datasize and DMA as follow:

      DMA_DeInit(DMA1_Channel5);

     

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

     

      DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&TxBuffer[0];

     

      DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;

     

      DMA_InitStructure.DMA_BufferSize = 1;

     

      DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

     

      DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

     

      DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;

     

      DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;

     

      DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

     

      DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;

     

      DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

     

      DMA_Init(DMA1_Channel5, &DMA_InitStructure);

    Best regards

    franck2
    franck2Author
    Associate III
    December 12, 2014