Skip to main content
arre24
Associate
August 22, 2012
Question

Variable frequency pulse train for pulse transformer application

  • August 22, 2012
  • 53 replies
  • 8009 views
Posted on August 22, 2012 at 17:22

Hi

The objective is to create a

variable frequency

pulse train with as little CPU intervention as possible.

This was quite straightforward with the TMS320 TI MCU. It had a feature called ''PWM chopper'' where it was possible to configure frequency, pulse width, duty cycle and number of pulses.

To achieve the same kind of functionality with the STM32F4, the idea that first came to mind was to use the Advanced Control Timer & DMA peripheral.

A table which consists of the timer periods that define the pulse train characteristics is setup in RAM. The have the DMA transfer these values to the timer compare register using memory increment mode. The timer output pin is configured to toggle at every compare match. 

Also, it is desired to have control of the time interval between each consecutive pulse train. Therefore a timer capture/compare interrupt is enabled. In the interrupt, the pulse train starting time (first positive flank) is defined as:

Current time (time when the interrupt occurs) + A settable delay

The time when the next interrupt occurs is also settable.

The questions are:

1) Is the method described above possible with the STM32F4?

2) Are there any other ways to get the same result?
    This topic has been closed for replies.

    53 replies

    webmaster
    Visitor II
    March 22, 2015
    Posted on March 22, 2015 at 10:00

     I need to load the table with alpha values from 0 degrees to 90 degrees. Before the end you should be loading from 90 to 180. You can not split the tablets because the values are odd and I need that high or low levels remain inthe table changes. These levels SRC_Buffer maintains only [0].

    notice that the values in Table 90 to 180 are a mirror table 90. TIM1- 0> CCR1 = SRC_Buffer [0] = (5000 - Tabla_Buffer [Table] [18]);

    webmaster
    Visitor II
    March 22, 2015
    Posted on March 22, 2015 at 10:02

    0690X00000602ulQAA.jpg

    webmaster
    Visitor II
    March 22, 2015
    Posted on March 22, 2015 at 10:18

    Clive Sorry,I forgot.

    The regulation requires the refreshment table at 90 degrees or what is the same five msg

    Tesla DeLorean
    Guru
    March 22, 2015
    Posted on March 22, 2015 at 16:46

    So, I'm assuming 5ms (200Hz). I'm not convinced you need to build the entire table, you could build 20 entries initially (0..19), at HT (10 entries) you could rebuild/replace the first 10 (20..29), at TC the next 10 (30..39), etc.

    Or you could do 5 at a time, and not stuff the CCR1 value, or CNT

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    Tesla DeLorean
    Guru
    March 22, 2015
    Posted on March 22, 2015 at 16:53

    I'm missing the frequency/period details, the relationship of the 5 milliseconds, 5 messages, 19/38 samples, why the entire sequence can't be in a single table, or built on the fly.

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    webmaster
    Visitor II
    March 22, 2015
    Posted on March 22, 2015 at 22:20

    The frequency is 100Hz. The table has 19 values, ranging from 0 degrees to 90 degrees. The values from 90-100 degrees to complete the cycle are constructed by the mirror table from 0 degrees to 90 degrees.

    I have tried using CT and HT and malfunctions. DMA2_Stream1_IRQHandler not interrupt me and has stopped working USART3. As you can see I tried to load half the table and segundamitad 0-9 9-18, but not if it works as there is no interruption for loading them. The tables are pre-calculated and stored are an 500 have 19 values each

    void DMA2_Stream1_IRQHandler(void) 
    {
    if (DMA_GetITStatus(DMA2_Stream1, DMA_IT_TCIF2))
    {
    // Transfer complete.
    DMA_ClearITPendingBit(DMA2_Stream1, DMA_IT_TCIF2);
    if (semiciclo) 
    {
    SRC_Buffer[10] = Tabla_Buffer [Tabla][10];
    SRC_Buffer[11] = Tabla_Buffer [Tabla][11];
    SRC_Buffer[12] = Tabla_Buffer [Tabla][12];
    SRC_Buffer[13] = Tabla_Buffer [Tabla][13];
    SRC_Buffer[14] = Tabla_Buffer [Tabla][14];
    SRC_Buffer[15] = Tabla_Buffer [Tabla][15];
    SRC_Buffer[16] = Tabla_Buffer [Tabla][16];
    SRC_Buffer[17] = Tabla_Buffer [Tabla][17];
    SRC_Buffer[18] = Tabla_Buffer [Tabla][18];
    }
    else
    {
    SRC_Buffer[10] = (5000 - Tabla_Buffer [Tabla][8]);
    SRC_Buffer[11] = (5000 - Tabla_Buffer [Tabla][7]);
    SRC_Buffer[12] = (5000 - Tabla_Buffer [Tabla][6]);
    SRC_Buffer[13] = (5000 - Tabla_Buffer [Tabla][5]);
    SRC_Buffer[14] = (5000 - Tabla_Buffer [Tabla][4]);
    SRC_Buffer[15] = (5000 - Tabla_Buffer [Tabla][3]);
    SRC_Buffer[16] = (5000 - Tabla_Buffer [Tabla][2]);
    SRC_Buffer[17] = (5000 - Tabla_Buffer [Tabla][1]);
    SRC_Buffer[18] = (5000 - Tabla_Buffer [Tabla][0]);
    } 
    }
    else if (DMA_GetITStatus(DMA2_Stream1, DMA_IT_HTIF2))
    {
    // Half transfer.
    DMA_ClearITPendingBit(DMA2_Stream1, DMA_IT_HTIF2);
    if (semiciclo) 
    {
    TIM1->CCR1 = SRC_Buffer[0] = (5000 - Tabla_Buffer [Tabla][18]);
    SRC_Buffer[1] = (5000 - Tabla_Buffer [Tabla][17]);
    SRC_Buffer[2] = (5000 - Tabla_Buffer [Tabla][16]);
    SRC_Buffer[3] = (5000 - Tabla_Buffer [Tabla][15]);
    SRC_Buffer[4] = (5000 - Tabla_Buffer [Tabla][14]);
    SRC_Buffer[5] = (5000 - Tabla_Buffer [Tabla][13]);
    SRC_Buffer[6] = (5000 - Tabla_Buffer [Tabla][12]);
    SRC_Buffer[7] = (5000 - Tabla_Buffer [Tabla][11]);
    SRC_Buffer[8] = (5000 - Tabla_Buffer [Tabla][10]);
    SRC_Buffer[9] = (5000 - Tabla_Buffer [Tabla][9]);
    }
    else
    {
    TIM1->CCR1 = SRC_Buffer[0] = Tabla_Buffer [Tabla][0];
    SRC_Buffer[1] = Tabla_Buffer [Tabla][1];
    SRC_Buffer[2] = Tabla_Buffer [Tabla][2];
    SRC_Buffer[3] = Tabla_Buffer [Tabla][3];
    SRC_Buffer[4] = Tabla_Buffer [Tabla][4];
    SRC_Buffer[5] = Tabla_Buffer [Tabla][5];
    SRC_Buffer[6] = Tabla_Buffer [Tabla][6];
    SRC_Buffer[7] = Tabla_Buffer [Tabla][7];
    SRC_Buffer[8] = Tabla_Buffer [Tabla][8];
    SRC_Buffer[9] = Tabla_Buffer [Tabla][9];
    }
    }
    else if (DMA_GetITStatus(DMA2_Stream1, DMA_IT_TEIF2))
    {
    // Transfer error.
    DMA_ClearITPendingBit(DMA2_Stream1, DMA_IT_TEIF2);
    }
    }

    webmaster
    Visitor II
    March 22, 2015
    Posted on March 22, 2015 at 22:23

    
    void TIM1_CC_IRQHandler(void)
    
    { 
    
    
    /* check if the TIM1_CC4 interrupt has occurred */
    
    if (TIM_GetITStatus(TIM1, TIM_IT_CC4) != RESET)
    
    {
    
    /* clear the TIM1_CC4 interrupt pending bits */
    
    TIM_ClearITPendingBit(TIM1, TIM_IT_CC4);
    
    }
    
    
    
    TIM1->CNT = 0; /* Reset the counter back to zero */
    
    /* Set up data for DMA-transfer */
    
    
    semiciclo = !semiciclo;
    
    
    
    if (semiciclo) 
    
    {
    
    
    
    GPIO_WriteBit(GPIOE,GPIO_Pin_9,Bit_SET);
    
    }
    
    else
    
    { 
    
    
    
    
    GPIO_WriteBit(GPIOE,GPIO_Pin_9,Bit_RESET);
    
    
    
    }
    
    
    
    
    /* Next interrupt to occur after 5 ms */
    
    TIM1->CCR4 = 5000;
    
    
    }
    
    
    void NVIC_Configuration(void) 
    
    { 
    
    // When the compare event CC4 on TIM1 occurs, this interrupt begins to execute
    
    NVIC_InitTypeDef NVIC_InitStruct;
    
    NVIC_InitStruct.NVIC_IRQChannel = TIM1_CC_IRQn; 
    
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
    
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
    
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    
    NVIC_Init(&NVIC_InitStruct);
    
    
    /* Enable the USARTx Interrupt */
    
    NVIC_InitStruct.NVIC_IRQChannel = USART3_IRQn;
    
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
    
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
    
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    
    NVIC_Init(&NVIC_InitStruct);
    
    
    /* Enable the UARTx Interrupt */
    
    NVIC_InitStruct.NVIC_IRQChannel = UART4_IRQn;
    
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
    
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
    
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    
    NVIC_Init(&NVIC_InitStruct);
    
    
    /* Enable the DMA2_Stream1 Interrupt */
    
    NVIC_InitStruct.NVIC_IRQChannel = DMA2_Stream1_IRQn;
    
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
    
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
    
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    
    NVIC_Init(&NVIC_InitStruct);
    
    
    }
    
    
    void DMA_Configuration(void)
    
    {
    
    DMA_InitTypeDef DMA_InitStructure;
    
    
    // TIM4_UP - DMA1, Channel 2, Stream 6
    
    DMA_InitStructure.DMA_Channel = DMA_Channel_2;
    
    DMA_InitStructure.DMA_BufferSize = PWM_ELEMENTS;
    
    DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
    
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
    
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
    
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&PWM_Buffer[0];
    
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&TIM4->CCR1;
    
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; 
    
    DMA_Init(DMA1_Stream6, &DMA_InitStructure); 
    
    DMA_Cmd(DMA1_Stream6, ENABLE);// turning DMA on
    
    
    
    // TIM1 - DMA2, Channel 6, Stream 1
    
    DMA_InitStructure.DMA_Channel = DMA_Channel_6;
    
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(TIM1_CCR1_ADDRESS);
    
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)SRC_Buffer;
    
    DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
    
    DMA_InitStructure.DMA_BufferSize = SPWM_ELEMENTS; // Nº data items to transfer
    
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 
    
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; 
    
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; 
    
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
    
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
    
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    
    DMA_Init(DMA2_Stream1, &DMA_InitStructure);
    
    
    // Enable Transfer Complete, Half Transfer and Transfer Error interrupts.
    
    DMA_ITConfig(DMA2_Stream1, DMA_IT_TC | DMA_IT_HT | DMA_IT_TE, ENABLE);
    
    
    DMA_Cmd(DMA2_Stream1, ENABLE); // enable DMA2_Stream1
    
    
    // wait until the DMA stream is enabled
    
    while (DMA_GetCmdStatus(DMA2_Stream1) != ENABLE) 
    
    {
    
    }
    
    }

    Tesla DeLorean
    Guru
    March 22, 2015
    Posted on March 22, 2015 at 23:01

    DMA_IT_TCIF2 << This should be TCIF1 for Stream1

    How is the timer configured? It's very hard to figure out what's going to happen with random assortments of code, please post a complete/concise example, without line numbers.

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    webmaster
    Visitor II
    March 23, 2015
    Posted on March 23, 2015 at 21:55

    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=0680X000006I6bq&d=%2Fa%2F0X0000000brl%2FohtNpRqayMgZUwUR7iVFIS.s5cxp2n1P2XRI3qSk3xk&asPdf=false
    Tesla DeLorean
    Guru
    March 24, 2015
    Posted on March 24, 2015 at 17:57

    Is there a reason to configure the timer as maximal, rather than at 5000, or 10000? At 5000 you'd keep getting an interrupt every 5ms and the counter would wrap automatically.

    The purpose of HT/TC would be to keep a streaming DMA operation to be sustained.

    If there is adequate time between the 19th sample being loaded, and subsequently firing, you couple perhaps just service the TC

    With a 38 sample buffer, HT/TC would fire at 19 sample intervals, allowing you to update the after-next portion of the table.

    How many of the 19 forward, vs 19 backward, sequences do you normally expect to send?

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..