0

Good morning, everyone, I am a firmware developer and am currently using the GD32F303R8T6 microcontroller to control a brushless motor. To control such a motor, I plan to use the timer peripheral TIMER_0 (advanced timer) to generate 3 PWM signals with related negated signals (in total, 6 signals). These signals are sent inside an ST driver that will command the motor. The problem I am experiencing is configuring the TIMER_0 timer to have the PWM signals generated.

Specifications on PWM:

  • Freq SYS_CLK: 72MHz
  • PWM freq: 8kHz
  • PWM Center Aligned

With the code shown, the goal is to generate the 6 PWM signals (3 normal and 3 complementary), then the control part will be implemented later.

In the following I'll write down the code that I tried to use to set the TIMER_0:

        // cleaning control registers
    CLEAR_REG(TIMER_CTL0(TIMER0));
    CLEAR_REG(TIMER_CTL1(TIMER0));

        // [ CLT0: 0x00000075 ]
    WRITE_REG(TIMER_CTL0(TIMER0),   TIMER_CTL0_UPS          |  
                    TIMER_CTL0_CAM_0    |
                    TIMER_CTL0_CAM_1    |
                    0);
        
        // [ CLT1: 0x00000070 ]
    WRITE_REG(TIMER_CTL1(TIMER0),   TIMER_CTL1_MMC          | 
                    0);
    
        // [ DMAINTEN: 0x00000001 ]
    WRITE_REG(TIMER_DMAINTEN(TIMER0), TIMER_DMAINTEN_UPIE);

        // [ CHCTL0: 0x00006868 ]
    WRITE_REG(TIMER_CHCTL0(TIMER0), TIMER_CHCTL0_CH0COMSEN          |
                    TIMER_CHCTL0_CH0COMCTL_PWM0 |
                    TIMER_CHCTL0_CH1COMSEN      |
                        TIMER_CHCTL0_CH1COMCTL_PWM0 |
                    0);
        // [ CHCTL1: 0x00006868 ]
    WRITE_REG(TIMER_CHCTL1(TIMER0), TIMER_CHCTL1_CH2COMSEN          |
                    TIMER_CHCTL1_CH2COMCTL_PWM0 |
                    TIMER_CHCTL1_CH3COMSEN      |
                    TIMER_CHCTL1_CH3COMCTL_PWM0 |
                    0);

        // enable of the 3 + 3 channels 
    // [ CHCTL2: 0x00001555 ]
    WRITE_REG(TIMER_CHCTL2(TIMER0), TIMER_CHCTL2_CH0EN      |
                    TIMER_CHCTL2_CH0NEN |
                    TIMER_CHCTL2_CH1EN  |
                    TIMER_CHCTL2_CH1NEN |
                    TIMER_CHCTL2_CH2EN  |
                    TIMER_CHCTL2_CH2NEN |
                    TIMER_CHCTL2_CH3EN  |
                    0);
    
    WRITE_REG(TIMER_PSC(TIMER0), 0);

        // "autoreload register"
    WRITE_REG(TIMER_CAR(TIMER0), 4500);
    
        // set of Compare Value Registers
    WRITE_REG(TIMER_CH0CV(TIMER0), 2250);
    WRITE_REG(TIMER_CH1CV(TIMER0), 2250);
    WRITE_REG(TIMER_CH2CV(TIMER0), 2250);
    WRITE_REG(TIMER_CH3CV(TIMER0), 2250);

        // [ CCHP: 0x00004088 ]
    WRITE_REG(TIMER_CCHP(TIMER0),   TIMER_CCHP_OAEN     |
                    //TIMER_CCHP_POEN   |
                    //TIMER_CCHP_BRKEN  |
                    //TIMER_CCHP_ROS    |
                    TIMER_CCHP_DTCFG_88 |
                                    0);
        // enable counter (start PWM generation)
    MODIFY_REG(TIMER_CTL0(TIMER0), TIMER_CTL0_CEN, TIMER_CTL0_CEN);

In the datasheet of this microcontroller, it is indicated that the PINs dedicated to TIMER_0 for PWM are as follows:

  • PA8 [ CH0 ]
  • PA9 [ CH1 ]
  • PA10 [ CH2 ]
  • PB13 [ CH0N ]
  • PB14 [ CH1N ]
  • PB15 [ CH2N ]

The following is the setting of the registers related to the above GPIOs.

    // enable clock to GPIO A and B
        rcu_periph_clock_enable(RCU_GPIOA); 
    rcu_periph_clock_enable(RCU_GPIOB);

        // enable AF clock
    rcu_periph_clock_enable(RCU_AF);

    WRITE_REG(GPIO_CTL1(GPIOA),     GPIO_CTL1_MD8_1     |
                    GPIO_CTL1_CTL8_2    |

                    GPIO_CTL1_MD9_1     |
                    GPIO_CTL1_CTL9_2    |

                    GPIO_CTL1_MD10_1    |
                    GPIO_CTL1_CTL10_2   |

                    GPIO_CTL1_MD13_1    |
                    GPIO_CTL1_CTL13_2   |

                    GPIO_CTL1_MD14_1    |
                    GPIO_CTL1_CTL14_2   |

                    GPIO_CTL1_MD15_1    |
                    GPIO_CTL1_CTL15_2   |
                    0); 

This is the part of the schematic showing how the microcontroller pins are connected to the power bridge: Scheme Connetion Micro to Bridge

The red arrows represent the 6 pins dedicated to the 6 PWM signals, the red dots represent the points in which I connect my oscilloscope.

With the configuration of TIMER0 and GPIO that I show u before, if I watch the oscilloscope I see active just CH0 and CH2 and no other signals (also all the complementary channels are completely dead). As debugger I'm using a JLINK. This is the Reference Manual and the datasheet documents that I used to configure the micro:

LINK FOR REFERENCE MANUAL

LINK FOR DATASHEET

After trying to set the logs manually, I tried using the functions already available to set the logs. Below is the code for only the TIMER0 part of the timer, the GPIO configuration remains the same as before.

   /* -----------------------------------------------------------------------
    TIMER0 configuration:
    generate 3 complementary PWM signal.
    TIMER0CLK is fixed to systemcoreclock, the TIMER0 prescaler is equal to 119 
    so the TIMER0 counter clock used is 1MHz.
    insert a dead time equal to 200/systemcoreclock =1.67us 
    configure the break feature, active at low level, and using the automatic
    output enable feature.
    use the locking parameters level 0.
    ----------------------------------------------------------------------- */
    timer_oc_parameter_struct timer_ocintpara;
    timer_parameter_struct timer_initpara;
    timer_break_parameter_struct timer_breakpara;

    //rcu_periph_clock_enable(RCU_TIMER0);

    timer_deinit(TIMER0);

    /* TIMER0 configuration */
    timer_initpara.prescaler         = 0;
    timer_initpara.alignedmode       = TIMER_COUNTER_CENTER_BOTH;
    timer_initpara.counterdirection  = TIMER_COUNTER_UP;
    timer_initpara.period            = 4499;
    timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
    timer_initpara.repetitioncounter = 0;
    timer_init(TIMER0,&timer_initpara);

     /* CH0/CH0N,CH1/CH1N and CH2/CH2N configuration in timing mode */
    timer_ocintpara.outputstate  = TIMER_CCX_ENABLE;
    timer_ocintpara.outputnstate = TIMER_CCXN_ENABLE;
    timer_ocintpara.ocpolarity   = TIMER_OC_POLARITY_HIGH;
    timer_ocintpara.ocnpolarity  = TIMER_OCN_POLARITY_HIGH;
    timer_ocintpara.ocidlestate  = TIMER_OC_IDLE_STATE_HIGH;
    timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_HIGH;

    timer_channel_output_config(TIMER0,TIMER_CH_0,&timer_ocintpara);
    timer_channel_output_config(TIMER0,TIMER_CH_1,&timer_ocintpara);
    timer_channel_output_config(TIMER0,TIMER_CH_2,&timer_ocintpara);

    timer_channel_output_pulse_value_config(TIMER0,TIMER_CH_0,2249);
    timer_channel_output_mode_config(TIMER0,TIMER_CH_0,TIMER_OC_MODE_PWM0);
    timer_channel_output_shadow_config(TIMER0,TIMER_CH_0,TIMER_OC_SHADOW_ENABLE);

    timer_channel_output_pulse_value_config(TIMER0,TIMER_CH_1,2249);
    timer_channel_output_mode_config(TIMER0,TIMER_CH_1,TIMER_OC_MODE_PWM0);
    timer_channel_output_shadow_config(TIMER0,TIMER_CH_1,TIMER_OC_SHADOW_ENABLE);

    timer_channel_output_pulse_value_config(TIMER0,TIMER_CH_2,2249);
    timer_channel_output_mode_config(TIMER0,TIMER_CH_2,TIMER_OC_MODE_PWM0);
    timer_channel_output_shadow_config(TIMER0,TIMER_CH_2,TIMER_OC_SHADOW_ENABLE);


    /* automatic output enable, break, dead time and lock configuration*/
    timer_breakpara.runoffstate      = TIMER_ROS_STATE_ENABLE;
    timer_breakpara.ideloffstate     = TIMER_IOS_STATE_ENABLE ;
    timer_breakpara.deadtime         = 164;
    timer_breakpara.breakpolarity    = TIMER_BREAK_POLARITY_LOW;
    timer_breakpara.outputautostate  = TIMER_OUTAUTO_ENABLE;
    timer_breakpara.protectmode      = TIMER_CCHP_PROT_OFF;
    timer_breakpara.breakstate       = TIMER_BREAK_DISABLE;
    timer_break_config(TIMER0,&timer_breakpara);
    
    /* TIMER0 primary output function enable */
    timer_primary_output_config(TIMER0,ENABLE);

    /* TIMER0 channel control update interrupt enable */
    timer_interrupt_enable(TIMER0,TIMER_INT_CMT);
    /* TIMER0 break interrupt disable */
    timer_interrupt_disable(TIMER0,TIMER_INT_BRK);

    /* TIMER0 counter enable */
    timer_enable(TIMER0);

Even with this new configuration, the result does not change from before: only the CH0 channel and CH2 generate the required PWM, while the other channels (even the complementary ones) remain inactive.

NOTE: The configuration you see above, I found on a Gitlab repository dedicated to GigaDevice. Below I attach the link if you find it useful.

LINK for GitLab Repo for GigaDevice Config Peripherals

Can you help me understand what I am doing wrong in the configuration of TIMER0 to generate all PWM signals ? Thank you in advance and I hope I have explained my problem as best as I can

Aristide

1 Answers1

0

WRITE_REG(GPIO_CTL1(GPIOA), GPIO_CTL1_MD8_1 | GPIO_CTL1_CTL8_2 |

GPIO_CTL1_MD9_1 | GPIO_CTL1_CTL9_2 |

GPIO_CTL1_MD10_1 | GPIO_CTL1_CTL10_2 |

GPIO_CTL1_MD13_1 | GPIO_CTL1_CTL13_2 |

GPIO_CTL1_MD14_1 | GPIO_CTL1_CTL14_2 |

GPIO_CTL1_MD15_1 | GPIO_CTL1_CTL15_2 | 0);

You are writing only to GPIOA registers. That won't set the pins on GPIOB (PB13..PB15), so that explains lack of PWM on those pins.

That won't explain PA9, though.

At any case, always start with reading out and checking/posting the related TIM and GPIO registers.

Btw. don't you enable USART0? That conflicts on PA9.

JW

wek
  • 137
  • 3