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丢失数据的问题。
出了问题还是要找他们原厂的人,售后的人基本解决不了任何问题。
本文来自博客园,作者:xjxcxjx,转载请注明原文链接:https://www.cnblogs.com/xjxcxjx/p/15623127.html,谢绝CSDN转载!