STM32 G431RB 利用PWM+DMA+Circular Mode 少量內存 實現對WS2812 燈帶的控制


在上一篇文章中DMA的設置使用的是"Normal" Mode,這種實現方法的問題是費內存,要控制168顆燈帶的顏色,需要准備168*24 +2*TRST 約4K Byte的內存,

在MCU的世界里就麻煩了,這次這個項目中需要控制4個燈帶,兩個168,一個21, 一個23.內存嚴重告急。采用DMA Circular模式能大大的減少內存的使用。

DMA Cirular模式就是DMA發送完成后,在調用HAL_TIM_PWM_Stop_DMA,DMA會自動的循環一直發送數據。

代碼工作原理如下:

  1. 用兩顆LED燈的長度(24x2)作為DMA Buffer
  2. DMA發送數據的時候會產生兩個中斷,一個是數據發送一半的時候產生一次中斷,在中斷里將下一個燈的數據填入Buffer的前半段
  3. DMA一次發送完成產生第二個中斷,我們再將下一個燈的數據填入下半Buffer
  4. 循環往復直到所有的燈的數據都發送完成

當然前后都需要發送TRST數據。

 

 

我在例子代碼中可以同時配置4個PWM+DMA通道,進行數據發送。感興趣的可以直接用我的實現函數。

代碼放到Github上了。https://github.com/magicduan/demo_pwm_dma

/**
* @brief Initilaize the pwm_dma data(Global array pwm_dma_data) according to dma_id.
* 
* @param dma_id: the PWM_DMA item (0 - PWM_LED_CHANNEL_MAX_COUNT-1)
* @param htim: pwm Timer
* @param channel: pwm DMA channel
* @param p_colors: the color buffer of LEDs, every LED color use 24bit (RGB)  = 3 Byte 
* @param leds_count: the numbers of LEDs
* @retval 0: success
*/
void pwm_dma_init(uint32_t dma_id, TIM_HandleTypeDef *htim, uint32_t channel,
                 uint8_t* p_colors, uint32_t leds_count )
{
    if (dma_id >= PWM_LED_CHANNEL_MAX_COUNT){
        return;
    }

    pwm_dma_data[dma_id].htim = htim;    
    pwm_dma_data[dma_id].dma_channel = channel;
    pwm_dma_data[dma_id].p_dma_colors = p_colors;    
    pwm_dma_data[dma_id].total_leds = leds_count;
}                 

/**
* @brief Send colors to LEDs by PWM + DMA + Circular mode
* 
* @param dma_id: the PWM_DMA item (0 - PWM_LED_CHANNEL_MAX_COUNT-1)
* @param channel: pwm DMA channel
* @param p_colors: the color buffer of LEDs, every LED color use 24bit (RGB)  = 3 Byte 
* @param leds_count: the numbers of LEDs
* @param b_block: flag whether waiting complete for DMA send. b_block = 1, waiting block mode , = 0 noblock mode
* @retval 0: success
*/
int pwm_dma_send(uint32_t dma_id,uint8_t b_block)
{
    int res = 0;
    if (dma_id >= PWM_LED_CHANNEL_MAX_COUNT){
        return -1;
    }

    if(pwm_dma_data[dma_id].htim == NULL){
        return -1;
    }

    pwm_dma_data[dma_id].inter_dma_data.status = PWM_DMA_HEAD_RST;
    pwm_dma_data[dma_id].inter_dma_data.cur_led = 0;
    pwm_dma_data[dma_id].inter_dma_data.b_completed = 0;

    led_data_fill(pwm_dma_data+dma_id,0);
    res = HAL_TIM_PWM_Start_DMA(pwm_dma_data[dma_id].htim,
                                pwm_dma_data[dma_id].dma_channel,
                                (uint32_t*)(pwm_dma_data[dma_id].inter_dma_data.pwm_buffer),
                                DMA_BUFFER_LEN);
    if ( res != HAL_OK){
        return res;
    }

    if (b_block){ // Block Mode
        while(pwm_dma_data[dma_id].inter_dma_data.b_completed == 0){
            osDelay(1);
        }
    }

    return res;
}                

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM