GD32F450 rgb移植調試


直接照着上個項目的GD32F407的RGB驅動移植就行。

 1 /*!**************************************************************************************************
 2 \brief        ch0 - rgb0 - pa0(af2)
 3             ch1 - rgb1 - pa1(af2)
 4 ****************************************************************************************************/
 5 void Timer4_init(void)
 6 {
 7     rcu_periph_clock_enable(RCU_TIMER4);
 8     rcu_periph_clock_enable(RCU_GPIOA);
 9     rcu_periph_clock_enable(RCU_GPIOC);
10     rcu_periph_clock_enable(RCU_DMA0);
11 
12     dma_single_data_parameter_struct dma_data_parameter;
13     timer_oc_parameter_struct timer_ocintpara;
14     timer_parameter_struct timer_initpara;
15 
16     //rgb_pwn
17     gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_PIN_14);
18     gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_14);
19 
20     gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_0|GPIO_PIN_1);
21     gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0|GPIO_PIN_1);
22     gpio_af_set(GPIOA, GPIO_AF_2, GPIO_PIN_0|GPIO_PIN_1);
23 
24     /* TIMER4 configuration */
25     timer_initpara.prescaler         = 9;            //時鍾預分頻數 (200)M/10/25 = 0.8mHz = 800KHz
26     timer_initpara.alignedmode         = TIMER_COUNTER_EDGE;        //向上&向下都是邊沿對齊
27     timer_initpara.counterdirection  = TIMER_COUNTER_UP;
28     timer_initpara.period             = 24;                    /* 自動重裝載寄存器周期的值(計數值) */
29     timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
30     timer_initpara.repetitioncounter = 0;
31     timer_init(TIMER4, &timer_initpara);
32 
33     /* TIMER1 channel3 configuration in PWM mode */
34     timer_ocintpara.outputstate  = TIMER_CCX_ENABLE;
35     timer_ocintpara.ocpolarity     = TIMER_OC_POLARITY_HIGH;
36     timer_channel_output_config(TIMER4, TIMER_CH_0, &timer_ocintpara);
37     timer_channel_output_config(TIMER4, TIMER_CH_1, &timer_ocintpara);
38 
39     timer_channel_output_pulse_value_config(TIMER4, TIMER_CH_0, 0); //占空比 = TIMERx_CHxCV / TIMERx_CAR
40     timer_channel_output_mode_config(TIMER4, TIMER_CH_0, TIMER_OC_MODE_PWM0);
41     timer_channel_output_shadow_config(TIMER4, TIMER_CH_0, TIMER_OC_SHADOW_ENABLE);//TIMER_OC_SHADOW_ENABLE
42 
43     timer_channel_output_pulse_value_config(TIMER4, TIMER_CH_1, 0); //占空比 = TIMERx_CHxCV / TIMERx_CAR
44     timer_channel_output_mode_config(TIMER4, TIMER_CH_1, TIMER_OC_MODE_PWM0);
45     timer_channel_output_shadow_config(TIMER4, TIMER_CH_1, TIMER_OC_SHADOW_ENABLE);//TIMER_OC_SHADOW_ENABLE
46 
47     timer_auto_reload_shadow_disable(TIMER4);
48 
49 ////RGB0--(Timer4_Ch0)--(DMA0_ch2_stream6)-pa0
50     dma_deinit(DMA0,DMA_CH2);
51 
52     /* initialize DMA single data mode */
53     dma_data_parameter.periph_addr    = (uint32_t)TIMER4_CCR0_Address;
54     dma_data_parameter.periph_inc    = DMA_PERIPH_INCREASE_DISABLE;
55     dma_data_parameter.memory0_addr = (uint32_t)LED_BYTE_Buffer;
56     dma_data_parameter.memory_inc    = DMA_MEMORY_INCREASE_ENABLE;
57     dma_data_parameter.periph_memory_width = DMA_PERIPH_WIDTH_16BIT;
58     dma_data_parameter.direction    = DMA_MEMORY_TO_PERIPH;
59     dma_data_parameter.number        = 42;
60     dma_data_parameter.priority     = DMA_PRIORITY_HIGH;  
61 
62     dma_single_data_mode_init(DMA0, DMA_CH2, &dma_data_parameter);    
63     dma_channel_subperipheral_select(DMA0, DMA_CH2, DMA_SUBPERI6);
64     dma_circulation_disable(DMA0, DMA_CH2);
65     timer_dma_enable(TIMER4,TIMER_DMA_CH0D);
66     dma_channel_disable(DMA0, DMA_CH2); 
67 
68 ////RGB1--(Timer4_Ch1)--(DMA0_ch4_stream6)-pa1
69     dma_deinit(DMA0,DMA_CH4);
70 
71     /* initialize DMA single data mode */
72     dma_data_parameter.periph_addr    = (uint32_t)TIMER4_CCR1_Address;
73     dma_data_parameter.periph_inc    = DMA_PERIPH_INCREASE_DISABLE;
74     dma_data_parameter.memory0_addr = (uint32_t)LED_BYTE_Buffer;
75     dma_data_parameter.memory_inc    = DMA_MEMORY_INCREASE_ENABLE;
76     dma_data_parameter.periph_memory_width = DMA_PERIPH_WIDTH_16BIT;
77     dma_data_parameter.direction    = DMA_MEMORY_TO_PERIPH;
78     dma_data_parameter.number        = 42;
79     dma_data_parameter.priority     = DMA_PRIORITY_HIGH;  
80 
81     dma_single_data_mode_init(DMA0, DMA_CH4, &dma_data_parameter);    
82     dma_channel_subperipheral_select(DMA0, DMA_CH4, DMA_SUBPERI6);
83     dma_circulation_disable(DMA0, DMA_CH4);
84     timer_dma_enable(TIMER4,TIMER_DMA_CH1D);
85     dma_channel_disable(DMA0, DMA_CH4); 
86 
87     timer_disable(TIMER4);
88 
89 }
 1 /****************************************************************************
 2 *函數名:Timer2_init
 3 *輸  入:無
 4 *輸  出:無
 5 *功  能:TIM2時鍾初始化函數,以及DMA初始化函數:PWM,單色LED控制
 6 *作  者:xj
 7 ****************************************************************************/
 8 void Timer2_init(void)
 9 {    
10     /* 結構體定義 */
11     dma_single_data_parameter_struct dma_data_parameter;
12     timer_oc_parameter_struct timer_ocintpara;
13     timer_parameter_struct timer_initpara;
14 
15     rcu_periph_clock_enable(RCU_GPIOB);
16     rcu_periph_clock_enable(RCU_DMA0);
17     rcu_periph_clock_enable(RCU_TIMER2);
18 
19     gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_1);//GPIO_MODE_OUTPUT//GPIO_MODE_AF
20     gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_1);
21     gpio_af_set(GPIOB, GPIO_AF_2, GPIO_PIN_1);
22 
23     /*
24         備注:從STM32F4的內部時鍾樹可知,當APB1和APB2分頻數為1的時候,
25         TIM1、TIM8~TIM11的時鍾為APB2的時鍾,TIM2~TIM7、TIM12~TIM14的時鍾為APB1的時鍾;
26         而如果APB1和APB2分頻數不為1,那么TIM1、TIM8~TIM11的時鍾為APB2的時鍾的兩倍,
27         TIMER1~TIM7、TIM12~TIM14的時鍾為APB1的時鍾的兩倍。
28         故:APB1:42MHz 對應的TIM 時鍾翻倍;APB2:84MHz,同理
29         */
30 
31     /* TIMER2 configuration */    
32     timer_initpara.prescaler         = 9;            //時鍾預分頻數 (200)M/10/25 = 0.8mHz = 800KHz
33     timer_initpara.alignedmode         = TIMER_COUNTER_EDGE;        //向上&向下都是邊沿對齊
34     timer_initpara.counterdirection  = TIMER_COUNTER_UP;
35     timer_initpara.period             = 24;                    /* 自動重裝載寄存器周期的值(計數值) */
36     timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
37     timer_initpara.repetitioncounter = 0;
38     timer_init(TIMER2, &timer_initpara);
39 
40     /* TIMER1 channel3 configuration in PWM mode */
41     timer_ocintpara.outputstate  = TIMER_CCX_ENABLE;
42     timer_ocintpara.ocpolarity   = TIMER_OC_POLARITY_HIGH;
43     timer_channel_output_config(TIMER2, TIMER_CH_3, &timer_ocintpara);
44 
45     timer_channel_output_pulse_value_config(TIMER2, TIMER_CH_3, 0);    //占空比 = TIMERx_CHxCV / TIMERx_CAR
46     timer_channel_output_mode_config(TIMER2, TIMER_CH_3, TIMER_OC_MODE_PWM0);
47     timer_channel_output_shadow_config(TIMER2, TIMER_CH_3, TIMER_OC_SHADOW_ENABLE);//TIMER_OC_SHADOW_ENABLE
48 
49     timer_auto_reload_shadow_disable(TIMER2);
50 
51     ////RGB2-(Timer2_Ch3)-(DMA0_ch2_stream5)(gd的通道和流與ST的相反)
52     dma_deinit(DMA0,DMA_CH2);
53     
54     /* initialize DMA single data mode */
55     dma_data_parameter.periph_addr    = (uint32_t)TIMER2_CCR3_Address;
56     dma_data_parameter.periph_inc    = DMA_PERIPH_INCREASE_DISABLE;
57     dma_data_parameter.memory0_addr    = (uint32_t)LED_BYTE_Buffer;
58     dma_data_parameter.memory_inc    = DMA_MEMORY_INCREASE_ENABLE;
59     dma_data_parameter.periph_memory_width = DMA_PERIPH_WIDTH_16BIT;
60     dma_data_parameter.direction    = DMA_MEMORY_TO_PERIPH;
61     dma_data_parameter.number        = 42;
62     dma_data_parameter.priority     = DMA_PRIORITY_HIGH;  
63 
64     dma_single_data_mode_init(DMA0, DMA_CH2, &dma_data_parameter);  
65     dma_channel_subperipheral_select(DMA0, DMA_CH2, DMA_SUBPERI5);
66     dma_circulation_disable(DMA0, DMA_CH2);
67     timer_dma_enable(TIMER2,TIMER_DMA_UPD);
68     dma_channel_disable(DMA0, DMA_CH2);        
69     
70     timer_disable(TIMER2);
71 }

RGB的驅動代碼如下:

 1 void KeyLampProc(void)
 2 { 
 3     memset(RGB1_buf,    0xFF, sizeof(RGB1_buf));
 4     memset(RGB2_buf,    0xFF, sizeof(RGB2_buf));
 5     memset(RGB3_buf,    0xFF, sizeof(RGB3_buf));    
 7 
 8     WS2812_send(RGB1_buf, 17,RGB1); 
 9     
10     WS2812_send(RGB2_buf, 10,RGB2);
11     
12     WS2812_send(RGB3_buf, 17,RGB3);    //長度需+1,否則最后一個filter2不亮 
13 
14 }
  1 void WS2812_send( uint8_t (*color)[ 3 ], uint16_t len,uint8_t PWM_CHANNEL )
  2 {
  3     uint8_t  j;
  4     uint8_t led = 0;
  5     uint16_t memaddr= 0;
  6     uint16_t buffersize = 0;
  7     buffersize = ( len * 24 ) + 42; // number of bytes needed is #LEDs * 24 bytes + 42 trailing bytes
  8 
  9     while ( len )
 10     {
 11     // GREEN data
 12       for ( j = 0; j < 8; j++ )         
 13       {
 14         if ( ( color[ led ][ 1 ] << j ) & 0x80 ) // data sent MSB first, j = 0 is MSB j = 7 is LSB
 15         {
 16             if(memaddr<500)
 17             {
 18                 LED_BYTE_Buffer[ memaddr ] = 17;  // compare value for logical 1
 19             }
 20             if((memaddr ==1) && (PWM_CHANNEL != 1 && PWM_CHANNEL != 5))    //timer3不會丟失波形,timer2和timer0會丟失第2bit的波形,所以此處要冗余一次bit2
 21             {
 22                 LED_BYTE_Buffer[ ++memaddr ] = 17;
 23             }
 24             else if((memaddr ==DecrsNm) && (PWM_CHANNEL == 1))
 25             {
 26                 LED_BYTE_Buffer[ ++memaddr ] = 17;
 27             }
 28           }
 29         else
 30         {
 31             if(memaddr<500)
 32             {
 33                 LED_BYTE_Buffer[ memaddr ] = 9; // compare value for logical 0 9
 34             }
 35             
 36             if((memaddr ==1) && (PWM_CHANNEL != 1&& PWM_CHANNEL != 5))    //timer3不會丟失波形,timer2和timer0會丟失第2bit的波形,所以此處要冗余一次bit2
 37             {
 38                 LED_BYTE_Buffer[ ++memaddr ] = 9;
 39             }
 40             else if((memaddr ==DecrsNm) && (PWM_CHANNEL == 1))
 41             {
 42                 LED_BYTE_Buffer[ ++memaddr ] = 9;
 43             }
 44         }
 45             memaddr++;
 46       }
 47     //RED data
 48     for ( j = 0; j < 8; j++ )
 49     {
 50         if ( ( color[ led ][ 0 ] << j ) & 0x80 ) // data sent MSB first, j = 0 is MSB j = 7 is LSB
 51         {
 52             if(memaddr<500)
 53             {
 54                 LED_BYTE_Buffer[ memaddr ] = 17;  // compare value for logical 1
 55             }
 56         }
 57         else
 58         {
 59             if(memaddr<500)
 60             {
 61                 LED_BYTE_Buffer[ memaddr ] = 9; // compare value for logical 0
 62             }
 63         }
 64         memaddr++;
 65     }
 66        
 67     // BLUE data
 68     for ( j = 0; j < 8; j++ )         
 69     {
 70       if ( ( color[ led ][ 2 ] << j ) & 0x80 ) // data sent MSB first, j = 0 is MSB j = 7 is LSB
 71       {
 72           if(memaddr<500)
 73           {
 74               LED_BYTE_Buffer[ memaddr ] = 17;  // compare value for logical 1
 75           }
 76       }
 77       else
 78       {
 79           if(memaddr<500)
 80           {
 81               LED_BYTE_Buffer[ memaddr ] = 9; // compare value for logical 0
 82           }
 83       }
 84       memaddr++;
 85     }
 86      led++;
 87      len--;
 88     }
 89 
 90     if(PWM_CHANNEL==1)  timer_channel_output_pulse_value_config(TIMER4,TIMER_CH_0,0);//此設置可以讓TIM對應channel的輸出為高電平,
 91 
 92     if(PWM_CHANNEL==2)  timer_channel_output_pulse_value_config(TIMER4,TIMER_CH_1,0);//此設置可以讓TIM 預想的情況下,輸出為高電平而不需要把TIM關掉
 93 
 94     if(PWM_CHANNEL==3)  timer_channel_output_pulse_value_config(TIMER2,TIMER_CH_3,0);//此設置可以讓TIM 預想的情況下,輸出為高電平而不需要把TIM關掉    
 95 
 96     while ( memaddr < buffersize )
 97     {
 98         if(memaddr<500)
 99         {       
100             LED_BYTE_Buffer[ memaddr ] = 0;       
101         }
102         memaddr++;
103     }
104  
105        
106     if(PWM_CHANNEL==1) //TIM4_CH0
107     { 
108      //   Timer4CH0_init_DMA();
109         
110           dma_transfer_number_config(DMA0, DMA_CH2, buffersize);
111        
112         dma_channel_enable(DMA0, DMA_CH2);        
113 
114         timer_enable(TIMER4);
115         
116         while ( !dma_flag_get( DMA0, DMA_CH2,DMA_FLAG_FTF ) ) //DMA channl2的中斷
117         ;   // wait until transfer complete
118 
119         dma_channel_disable(DMA0, DMA_CH2); 
120         
121         dma_flag_clear( DMA0, DMA_CH2,DMA_FLAG_FTF);
122 
123         timer_disable(TIMER4);
124     }
125     if(PWM_CHANNEL==2) //TIM4CH1
126     { 
127           dma_transfer_number_config(DMA0, DMA_CH4, buffersize);
128        
129         dma_channel_enable(DMA0, DMA_CH4);
130 
131         timer_enable(TIMER4);
132         
133         while ( !dma_flag_get( DMA0, DMA_CH4,DMA_FLAG_FTF ) ) //DMA channl4中斷
134         ;   // wait until transfer complete
135 
136         dma_channel_disable(DMA0, DMA_CH4); 
137         
138         dma_flag_clear( DMA0, DMA_CH4,DMA_FLAG_FTF);
139 
140         timer_disable(TIMER4);
141     }
142     if(PWM_CHANNEL==3) //TIM2_CH3
143    {
144     //       Tim2CH3_init_DMA();
145     
146         dma_transfer_number_config(DMA0, DMA_CH2, buffersize);
147        
148         dma_channel_enable(DMA0, DMA_CH2);
149 
150         timer_enable(TIMER2); 
151         
152         while ( !dma_flag_get( DMA0, DMA_CH2,DMA_FLAG_FTF ) ) //DMA channl2的中斷
153         ;   // wait until transfer complete         
154         
155         dma_channel_disable(DMA0, DMA_CH2); 
156         
157         dma_flag_clear( DMA0, DMA_CH2,DMA_FLAG_FTF );
158 
159         timer_disable(TIMER2);
160     }
161 }

然后運行的時候發現RGB2和RGB3都能正常執行,而RGB1卻在while處出不來。

代碼都沒問題,而根據RGB2和RGB3都能正常執行,推測是RGB1的配置出了問題。翻看下F407的代碼,發現有這段代碼

   然后再看下450的DMA通道配置信息:

  發現TIMER4_CH0 和 TIMER2_CH3共用了DMA0_CH2通道。而我的代碼是先運行的timer4init(),后運行的timer2init(),這樣timer2就把timer4的DMA通道配置給覆蓋了。所以解決方案也很簡單,照着上面配置下就可以了。

 1 void Tim2CH3_init_DMA(void)
 2 {
 3     dma_single_data_parameter_struct dma_data_parameter;
 4     
 5 ////RGB2-Timer2_Ch0--DMA0_ch4_stream5
 6     dma_deinit(DMA0,DMA_CH2);
 7     
 8     /* initialize DMA single data mode */
 9     dma_data_parameter.periph_addr    = (uint32_t)TIMER2_CCR3_Address;
10     dma_data_parameter.periph_inc    = DMA_PERIPH_INCREASE_DISABLE;
11     dma_data_parameter.memory0_addr = (uint32_t)LED_BYTE_Buffer;
12     dma_data_parameter.memory_inc    = DMA_MEMORY_INCREASE_ENABLE;
13     dma_data_parameter.periph_memory_width = DMA_PERIPH_WIDTH_16BIT;
14     dma_data_parameter.direction    = DMA_MEMORY_TO_PERIPH;
15     dma_data_parameter.number        = 42;
16     dma_data_parameter.priority     = DMA_PRIORITY_HIGH; 
17     
18     dma_single_data_mode_init(DMA0, DMA_CH2, &dma_data_parameter);
19     dma_channel_subperipheral_select(DMA0, DMA_CH2, DMA_SUBPERI5);
20     dma_circulation_disable(DMA0, DMA_CH2);
21 }
22 
23 void Timer4CH0_init_DMA(void)
24 {
25     dma_single_data_parameter_struct dma_data_parameter;
26     
27 ////RGB2-Timer2_Ch0--DMA0_ch4_stream5
28     dma_deinit(DMA0,DMA_CH2);
29     
30     /* initialize DMA single data mode */
31     dma_data_parameter.periph_addr    = (uint32_t)TIMER4_CCR0_Address;
32     dma_data_parameter.periph_inc    = DMA_PERIPH_INCREASE_DISABLE;
33     dma_data_parameter.memory0_addr = (uint32_t)LED_BYTE_Buffer;
34     dma_data_parameter.memory_inc    = DMA_MEMORY_INCREASE_ENABLE;
35     dma_data_parameter.periph_memory_width = DMA_PERIPH_WIDTH_16BIT;
36     dma_data_parameter.direction    = DMA_MEMORY_TO_PERIPH;
37     dma_data_parameter.number        = 42;
38     dma_data_parameter.priority     = DMA_PRIORITY_HIGH; 
39     
40     dma_single_data_mode_init(DMA0, DMA_CH2, &dma_data_parameter);
41     dma_channel_subperipheral_select(DMA0, DMA_CH2, DMA_SUBPERI6);
42     dma_circulation_disable(DMA0, DMA_CH2);
43 }

然后在每次使用DMA的時候重新配置下DMA_CH2即可。

  這樣就能成功的運行了。但是RGB燈還是不亮。

===============↓↓↓↓2021-12-6更新↓↓↓=================

 將TIMRT4作為定時器,在其中斷中翻轉IO模擬PWM,是可以正常輸出的

 1 /*!**************************************************************************************************
 2 \brief        初始化
 3 ****************************************************************************************************/
 4 void SystemTimer_Init(void)
 5 {
 6     rcu_periph_clock_enable(RCU_GPIOA);    
 7     rcu_periph_clock_enable(RCU_TIMER4);
 8 
 9     timer4_IrqPriority_Init();
10     
11     /* 復位TIMER4定時器,並選擇內部時鍾200M */
12     timer_deinit(TIMER4);
13 //    timer_internal_clock_config(TIMER4);
14 
15     gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_PIN_1);
16     gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_1);
17 
18     /* TIMER4 configuration */
19     timer_parameter_struct timer_initpara;
20     timer_initpara.prescaler         = (4);//200/200/1000
21     timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;//根據prescaler,clockdivision最終該定時器時鍾頻率為1M
22     timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;//觸發方式設置根據邊沿決定
23     timer_initpara.counterdirection  = TIMER_COUNTER_UP;//設置為上升沿觸發
24     timer_initpara.period            = 49;//設置0.1ms定時
25     timer_initpara.repetitioncounter = 0;
26     timer_init(TIMER4, &timer_initpara);
27 
28     /* TIMER4 enable */
29     timer_enable(TIMER4);
30     
31     timer_interrupt_enable(TIMER4,TIMER_INT_UP);
32 }

然后關閉Timer4其中一路,只實驗一路輸出,減少變量的干擾,但是還是不行

 1 /*!**************************************************************************************************
 2 \brief        ch0 - rgb0 - pa0(af2)
 3             ch1 - rgb1 - pa1(af2)
 4 ****************************************************************************************************/
 5 void Timer4_init(void)
 6 {
 7     rcu_periph_clock_enable(RCU_TIMER4);
 8     rcu_periph_clock_enable(RCU_GPIOA);
 9     rcu_periph_clock_enable(RCU_GPIOC);
10     rcu_periph_clock_enable(RCU_DMA0);
11 
12     dma_single_data_parameter_struct dma_data_parameter;
13     timer_oc_parameter_struct timer_ocintpara;
14     timer_parameter_struct timer_initpara;
15 
16     //rgb_power
17     gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_PIN_14);
18     gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, GPIO_PIN_14);
19 
20     gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_0|GPIO_PIN_1);
21     gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0|GPIO_PIN_1);
22     gpio_af_set(GPIOA, GPIO_AF_2, GPIO_PIN_0|GPIO_PIN_1);
23 
24     /* TIMER4 configuration */
25     timer_initpara.prescaler         = 4;            //時鍾預分頻數 (100)M/10/25 = 0.8mHz = 800KHz
26     timer_initpara.alignedmode         = TIMER_COUNTER_EDGE;        //向上&向下都是邊沿對齊
27     timer_initpara.counterdirection  = TIMER_COUNTER_UP;
28     timer_initpara.period             = 49;                    /* 自動重裝載寄存器周期的值(計數值) */
29     timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
30     timer_initpara.repetitioncounter = 0;
31     timer_init(TIMER4, &timer_initpara);
32 
33     /* TIMER1 channel3 configuration in PWM mode */
34     timer_ocintpara.outputstate  = TIMER_CCX_ENABLE;
35     timer_ocintpara.outputnstate = TIMER_CCXN_DISABLE;
36     timer_ocintpara.ocpolarity     = TIMER_OC_POLARITY_HIGH;
37     timer_ocintpara.ocnpolarity  = TIMER_OCN_POLARITY_HIGH;
38     timer_ocintpara.ocidlestate  = TIMER_OC_IDLE_STATE_LOW;
39     timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
40     timer_channel_output_config(TIMER4, TIMER_CH_0, &timer_ocintpara);
41 //    timer_channel_output_config(TIMER4, TIMER_CH_1, &timer_ocintpara);
42 
43     timer_channel_output_pulse_value_config(TIMER4, TIMER_CH_0, 0); //占空比 = TIMERx_CHxCV / TIMERx_CAR
44     timer_channel_output_mode_config(TIMER4, TIMER_CH_0, TIMER_OC_MODE_PWM0);
45     timer_channel_output_shadow_config(TIMER4, TIMER_CH_0, TIMER_OC_SHADOW_DISABLE);//TIMER_OC_SHADOW_ENABLE
46 
47 //    timer_channel_output_pulse_value_config(TIMER4, TIMER_CH_1, 0); //占空比 = TIMERx_CHxCV / TIMERx_CAR
48 //    timer_channel_output_mode_config(TIMER4, TIMER_CH_1, TIMER_OC_MODE_PWM0);
49 //    timer_channel_output_shadow_config(TIMER4, TIMER_CH_1, TIMER_OC_SHADOW_DISABLE);//TIMER_OC_SHADOW_ENABLE
50 
51     timer_primary_output_config(TIMER4,ENABLE);
52     timer_auto_reload_shadow_enable(TIMER4);
53 
54 ////RGB0--(Timer4_Ch0)--(DMA0_ch2_stream6)-pa0
55     dma_deinit(DMA0,DMA_CH2);
56 
57     /* initialize DMA single data mode */
58     dma_data_parameter.periph_addr    = (uint32_t)TIMER4_CCR0_Address;
59     dma_data_parameter.periph_inc    = DMA_PERIPH_INCREASE_DISABLE;
60     dma_data_parameter.memory0_addr = (uint32_t)LED_BYTE_Buffer;
61     dma_data_parameter.memory_inc    = DMA_MEMORY_INCREASE_ENABLE;
62     dma_data_parameter.periph_memory_width = DMA_PERIPH_WIDTH_16BIT;
63     dma_data_parameter.direction    = DMA_MEMORY_TO_PERIPH;
64     dma_data_parameter.number        = 42;
65     dma_data_parameter.priority     = DMA_PRIORITY_HIGH;  
66 
67     dma_single_data_mode_init(DMA0, DMA_CH2, &dma_data_parameter);    
68     dma_channel_subperipheral_select(DMA0, DMA_CH2, DMA_SUBPERI6);
69     dma_circulation_disable(DMA0, DMA_CH2);
70     timer_dma_enable(TIMER4,TIMER_DMA_CH0D);
71     dma_channel_disable(DMA0, DMA_CH2); 
72 
73 ////RGB1--(Timer4_Ch1)--(DMA0_ch4_stream6)-pa1
74 //    dma_deinit(DMA0,DMA_CH4);
75 //
76 //    /* initialize DMA single data mode */
77 //    dma_data_parameter.periph_addr    = (uint32_t)TIMER4_CCR1_Address;
78 //    dma_data_parameter.periph_inc    = DMA_PERIPH_INCREASE_DISABLE;
79 //    dma_data_parameter.memory0_addr = (uint32_t)LED_BYTE_Buffer;
80 //    dma_data_parameter.memory_inc    = DMA_MEMORY_INCREASE_ENABLE;
81 //    dma_data_parameter.periph_memory_width = DMA_PERIPH_WIDTH_16BIT;
82 //    dma_data_parameter.direction    = DMA_MEMORY_TO_PERIPH;
83 //    dma_data_parameter.number        = 42;
84 //    dma_data_parameter.priority     = DMA_PRIORITY_HIGH;  
85 //
86 //    dma_single_data_mode_init(DMA0, DMA_CH4, &dma_data_parameter);    
87 //    dma_channel_subperipheral_select(DMA0, DMA_CH4, DMA_SUBPERI6);
88 //    dma_circulation_disable(DMA0, DMA_CH4);
89 //    timer_dma_enable(TIMER4,TIMER_DMA_CH1D);
90 //    dma_channel_disable(DMA0, DMA_CH4); 
91 
92     timer_disable(TIMER4);
93 
94 }

其輸出的波形如下:500Hz的不知道什么的波形

  由此推斷,TIMER4沒問題,問題應該出在DMA上。需要在DMA上做實驗驗證。

----------------------------2021-12-8-------------------------------------------------

經過原廠的手把手教學,今天終於找到了問題的所在!

首先原廠確認他們的芯片有一個問題,在DMA傳輸數據有0的時候,它會把后面的第1或者第2個數據丟失(類似往CCR里扔0,就會導致定時器重啟,有個反應時間,所以會丟失后面的幾個數據?)。這是一個大坑,不過這個坑我沒踩到。

另外一個沒注意到的地方(2坑)是定時器的比較寄存器有差異。

這個系列的芯片雖然定時器1234都屬於L0組的通用定時器,我們一般會想當然的認為用法都一樣。但是其實有很大的差異。下面圖里能看到,1,4的CH1CV是個32位的寄存器

 

 而2,3的CHCV卻是16位的寄存器。

 

 而這個跟我們配置的DMA的傳輸方式和傳輸的數據格式息息相關!

我們傳輸的數據是16位的數據

  而我們DMA的傳輸方式選擇的也是16位

  這樣的配置就導致我們把一個16位的數據傳遞給了32位的寄存器,按照不能正常運行的結果看,顯然它是把16位的數據放在了比較寄存器的高16位了,那么這個比較值就是17<<16 = 1114112。

而我們定時器的自動重載值才是35,永遠到不了比較值,那么輸出的就是全是低電平了。

 因此需要把它們改成32位的即可。

定時器的DMA請求使能更新方式和其通道的關系

定時器的DMA請求使能方式有以下7種。

 

 一般我們是按照DMA外設請求表來填寫。就像上面最開始的代碼那樣。

而timer 的TIMER_DMA_UPD更新方式跟具體的某個timer的通道沒關系,它會啟動所有通道的更新。而update更新方式,就可以避免上面說的那個大坑!

因此需要對上面的代碼進行修改:

 

 timer4_ch0 采用update更新,使用DMA0_CH0;

 timer4_ch1 采用update更新,使用DMA0_CH6;

如此配置后,WS2811的RGB燈珠即可成功穩定的點亮。

而如果采用通道更新的話,燈珠就會亂閃,很明顯就是他們說的數據丟失的問題。這也驗證了我在做407的時候為什么固定第二個bit丟失數據的問題。

出了問題還是要找他們原廠的人,售后的人基本解決不了任何問題。


免責聲明!

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



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