Skip to main content
Visitor II
June 30, 2025
Question

lwip freeRTOS with DAM DDS dubble buffer pulse generator

  • June 30, 2025
  • 2 replies
  • 387 views

 

Hello everyone,

I am implementing a DDS-based pulse generator using DMA double buffer technique on my STM32H7. When I run this pulse generator as a standalone project, it works perfectly — the output pulse frequency is accurate and stable.

However, when I integrate LwIP into the same project, I notice that the generated pulse frequency occasionally changes unexpectedly and produces wrong output values. It looks like there is interference or resource conflict when both the DDS pulse generator and LwIP run together.

Has anyone faced similar issues? Is there a recommended way to isolate or manage DMA, timers, and LwIP to avoid such conflicts on STM32H7?

Any suggestions would be greatly appreciated.

Thank you!

    This topic has been closed for replies.

    2 replies

    Technical Moderator
    June 30, 2025

    Hello,

    I think it's an interrupt priority issue or Task priority issue. That depends on your implementation.

    Try to increase the interrupts resources linked to your DDS (TIM, DMA?)

    If your DDS implementation is task dependent, increase its task priority.

    sumangaAuthor
    Visitor II
    June 30, 2025

    Dear mEALLEm

    I already set highest priority for DDS 

    but no change result.

    I used github provided lwip freeRTOS example and aditional TIM1 confige as 1Mhz trigering frequency use DMA circular memory to peripheral TIM1-UP update-event priority very high then main.C declear bufferA & bufferB size is 1000 like this

    #define DDS_BUFFER_SIZE 1000
    #define DDS_TABLE_SIZE 1024
    #define PWM_RESOLUTION 1000 // Timer counts from 0 to 999
    
    uint16_t dmaBuffer[2][DDS_BUFFER_SIZE]; // Double buffer
    uint16_t *currentBuffer;
    float ddsTable[DDS_TABLE_SIZE];
    float phaseAccumulator = 0.0f;
    float phaseStep; // Controls frequency
    
    void FillDDSBuffer(uint16_t *buffer)
    {
    for (int i = 0; i < DDS_BUFFER_SIZE; i++) {
    uint32_t index = (uint32_t)phaseAccumulator % DDS_TABLE_SIZE;
    buffer[i] = (uint16_t)ddsTable[index];
    phaseAccumulator += phaseStep;
    if (phaseAccumulator >= DDS_TABLE_SIZE)
    phaseAccumulator -= DDS_TABLE_SIZE;
    }
    }
    
    void HAL_TIM_PWM_PulseFinishedHalfCpltCallback(TIM_HandleTypeDef *htim)
    {
    if (htim->Instance == TIM1) {
    FillDDSBuffer(dmaBuffer[0]);
    }
    }
    
    void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
    {
    if (htim->Instance == TIM1) {
    FillDDSBuffer(dmaBuffer[1]);
    }
    }

    inside main function add

    FillDDSBuffer(dmaBuffer[0]);
    FillDDSBuffer(dmaBuffer[1]);
    
    HAL_DMAEx_MultiBufferStart_IT(
    htim1.hdma[TIM_DMA_ID_CC2], // DMA handle linked to TIM1_CH2
    (uint32_t)dmaBuffer[0], // Buffer A start
    (uint32_t)&TIM1->CCR2, // Peripheral address (CCR2)
    (uint32_t)dmaBuffer[1], // Buffer B start
    DDS_BUFFER_SIZE // Size of each buffer
    );

    to start task but not clearly work if we remove lwip from project without any changing ,we can run DDS fully accurate 

    please help to solve this problem or give me sample project combined lwip with DDS pulse generator 

    sumangaAuthor
    Visitor II
    June 30, 2025

    this is corectly working code

    define BUFFER_SIZE 1000
    #define DDS_ACCUMULATOR_BITS 32
    #define DDS_CLOCK 1000000UL // TIM1 update rate = 1 MHz
    
    uint32_t pulseBufferA[BUFFER_SIZE];
    uint32_t pulseBufferB[BUFFER_SIZE];
    
    TIM_HandleTypeDef htim1;
    DMA_HandleTypeDef hdma_tim1_up;
    
    volatile uint32_t dds_accumulator = 0;
    uint32_t dds_tuning_word = 0;
    
    // Forward declarations
    void SystemClock_Config(void);
    void MX_GPIO_Init(void);
    void MX_DMA_Init(void);
    void MX_TIM1_Init(void);
    
    void FillDDSBuffer(uint32_t *buffer)
    {
    for (int i = 0; i < BUFFER_SIZE; i++)
    {
    dds_accumulator += dds_tuning_word;
    if (dds_accumulator & 0x80000000)
    buffer[i] = GPIO_PIN_0; // PB0 high
    else
    buffer[i] = 0; // PB0 low
    }
    }
    
    void SetDDSFrequency(float freq)
    {
    dds_tuning_word = (uint32_t)((freq * ((uint64_t)1 << DDS_ACCUMULATOR_BITS)) / DDS_CLOCK);
    }
    
    void HAL_DMA_XferCpltCallback(DMA_HandleTypeDef *hdma)
    {
    if (hdma->Instance == DMA1_Stream0)
    {
    FillDDSBuffer(pulseBufferA);
    }
    }
    
    void HAL_DMA_XferM1CpltCallback(DMA_HandleTypeDef *hdma)
    {
    if (hdma->Instance == DMA1_Stream0)
    {
    FillDDSBuffer(pulseBufferB);
    }
    }
    
    int main(void)
    {
    HAL_Init();
    SystemClock_Config();
    
    MX_GPIO_Init();
    MX_DMA_Init();
    MX_TIM1_Init();
    
    SetDDSFrequency(5000.0f); // 5 kHz output
    
    FillDDSBuffer(pulseBufferA);
    FillDDSBuffer(pulseBufferB);
    
    HAL_TIM_Base_Start(&htim1);
    
    HAL_DMAEx_MultiBufferStart_IT(&hdma_tim1_up,
    (uint32_t)pulseBufferA,
    (uint32_t)&(GPIOB->ODR),
    (uint32_t)pulseBufferB,
    BUFFER_SIZE);
    
    __HAL_TIM_ENABLE_DMA(&htim1, TIM_DMA_UPDATE);
    
    while (1)
    {
    // Optionally update frequency with SetDDSFrequency(new_freq);
    }
    }
    
    // Minimal peripheral init code follows