直接照着上個項目的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丟失數據的問題。
出了問題還是要找他們原廠的人,售后的人基本解決不了任何問題。