In this blog I'm using a scroll wheel from a defunct mouse to control a GaN power stage.


hercules GaN FET half-bridge TMS570LS43x texasinstruments


A Hercules LaunchPad has the duty to read the scroll wheel and drive the GaN.

I'm controlling a humble 15 watt incandescent lamp here, but we wouldn't have to change a single line of code to control a 500 watt motor.






I'm trying to control high powers with a jellybean scroll wheel. Scrolls wheel are common these days.
You find them in your mouse - between the left and right button. And in many other places like oscilloscopes and car entertainment systems.

The power is regulated by a Gallium Nitride half-bridge.





There are 8 items that play a role in my test configuration:

  • An LMG5200 GaN half-bridge power stage.
    Controls the amount of power going to the load
    I received mine from TI after attending a GaN seminar and answering right on the quiz.
  • A Hercules TMS570LC43x LaunchPad - but this could be any controller of the
    Hercules family that has one quadrature encoder (eQEP) and one PWM (etPWM) module.
    This was donated by TI.
  • A DC power supply that can deliver a low current between 5.5 V and 6.5 V.
    It will provide the LMG5200 bias voltage. It doesn't have to be very stable.
  • A DC power supply that can deliver a high current between 10 V to 60 V.
    That's the one that will provide the power to the load, and that will be controlled by the LMG5200.
    I use 20 V, 1 A.
  • A rotary (quadrature) encoder. I'm using one from a mouse scroll wheel.
  • An optional DC current meter with an Amp range. We'll be burning approximately 1 A here.
    Most DMMs have a 10 A range that will do just fine.
  • An optional DC volt meter. We're working in the range between 0 V and 20 V.
    Again any DMM will do.
  • An optional oscilloscope to look at the signal going into the LMG5200. We'll be working at 1 MHz.
    The scope is not neccesary, but it will enable you to see and measure the attributes of that input signal (frequency, duty cycle).


GaN Hercules Launchpad setup eqep epwm




Design Decisions


All things are done for pragmatic reasons.

I'm using a Hercules LaunchPad and an LMG5200 GaN module because that's the components that I'm experimenting with.

I select a 1 MHz PWM signal because I want to see how the GaN half-bridge holds up at high frequencies

(and that's the actual reason for my setup - I didn't build it for this blog, but as a testbed).

You 'll see in the firmware that I'm defining a scroll range of 0 - 55. That's because I draw the maximum of 1 A from my power supply at that point.

The software is layered on a level that fits this exercise.



Abstraction level


I've applied a modest abstraction level in my design.

My only purpose is to have specific logic out of the main file, and to build modules with useful functions for this particular project only.

The Quadrature Encoder and PWM logic have their own source files with a few functions, but this isn't an abstraction lib that allows different peripheral or generic changes.

Module initialization and setup done in usual tools (HALCoGen in this case). I have no intention to take that any of that over in abstraction layer.


halcogen firmware hardware abstraction layer


Firmware and Module Setup


Each module requires some setup. Activation and configuration of peripherals is done in Hercules HALCoGen.


Generic setup


We'll use SCI for data logging during debug. This is so simple - and only related to test code - that I haven't bothered to abstract it out.



#include "HL_sci.h"
// ...
void main(void)
   // ...
    sciInit(); //Initializes the SCI (UART) module
   // ...


Rotary Encoder


Quadrature information is decoded with the eQEP module. We're using eQEP instance #2 because that is broken out to connector J10.



At least EQEP2 Pin A and B need to be enabled.




#include "HL_eqep.h"

void rotaryInit(boolean wrap);
uint32_t getRotaryPosition();

#endif /* ROTARY_ROTARY_H_ */


#include "rotary.h"


uint32_t uRotary2LastVal = EQEP2_QPOSINIT_CONFIGVALUE; // no need to set volatile, only used in this function
uint32_t uRotary2 = EQEP2_QPOSINIT_CONFIGVALUE; // no need to set volatile, only used in this function
boolean bWrap;

void rotaryInit(boolean wrap) {
    bWrap = wrap;
    /* Enable Position Counter */
    /* Enable Unit Timer. */

    /* Enable capture timer and capture period latch. */

uint32_t getRotaryPosition() {
    /* Status flag is set to indicate that a new value is latched in the QCPRD register*/
    if((eqepREG2->QEPSTS & 0x80U) !=0U) {
        uRotary2 = eqepREG2->QPOSLAT;
        // address border conditions to avoid shootthrough around min or max
        if (!bWrap && (uRotary2 > EQEP2_QPOSMAX_CONFIGVALUE - EQEP_BORDER_CHECK) && (uRotary2LastVal < EQEP_BORDER_CHECK)) {
            uRotary2 = 0x0U;
            eqepREG2->QPOSCNT = 0x0U;
            eqepREG2->QPOSLAT = 0x0U;
        } else if (!bWrap && (uRotary2 < EQEP_BORDER_CHECK) && (uRotary2LastVal > EQEP2_QPOSMAX_CONFIGVALUE - EQEP_BORDER_CHECK)) {
            uRotary2 = EQEP2_QPOSMAX_CONFIGVALUE;

        /* Clear the Status flag. */
        eqepREG2->QEPSTS |= 0x80U;
        uRotary2LastVal = uRotary2;

    return uRotary2;





For pulse width modulation , the Hercules family has ePWM modules.



At least PWM1 A needs to be enabled. Don't forget to check the Special Muxing settings.




#ifndef PWM_PWM_H_
#define PWM_PWM_H_

#include "HL_etpwm.h"

void pwmInit();
void setPwmDutyCycle(uint32_t dutyCycle);

#endif /* PWM_PWM_H_ */


#include "pwm.h"


void pwmInit() {

void setPwmDutyCycle(uint32_t dutyCycle) {
    etpwmSetCmpA(etpwmREG1, DUTYCYCLE_STEP * dutyCycle);




The main file stitches everything together.


#include "HL_sys_common.h"
#include "HL_sci.h"
#include "HL_sys_core.h"
#include <stdlib.h>
#include "rotary.h"
#include "pwm.h"

unsigned char command[8];

void main(void)
    uint32_t NumberOfChars;
    uint32_t uRotaryLastVal;
    uint32_t uRotary;

    sciInit(); //Initializes the SCI (UART) module

    rotaryInit(false); // no wrap around



    uRotary = getRotaryPosition();
    uRotaryLastVal = uRotary;
        uRotary = getRotaryPosition();
        if (uRotary != uRotaryLastVal) {
            uRotaryLastVal = uRotary;

            NumberOfChars = ltoa(uRotary,(char *)command);
            sciSend(sciREG1, NumberOfChars, command); //Sends the eQEP data
            sciSend(sciREG1, 2, (unsigned char *)"\r\n"); //Sends new line character







The system will start up with the lamp fully dimmed. You can control the brightness by rotating the encoder.

Use the current meter to check the current coming from the power supply, and the current going to the lamp.

Check how it changes when rotating the scroll wheel.

Attach the voltmeter and check how the output voltage changes.

Attach your scope to the PWM signal. If you have a math function, you can see the duty cycle change and the frequency staying stable.




Related Blogs
Hercules LaunchPad and GaN FETs - Part 1: Control Big Power with a Flimsy Mouse Scroll Wheel
Hercules LaunchPad and GaN FETs - Part 2: Make a BoosterPack
Hercules LaunchPad and GaN FETs - Part 3a: BoosterPack Layout - Reference Design
Hercules LaunchPad and GaN FETs - Part 3b: BoosterPack Layout - my version
Hercules LaunchPad and GaN FETs - Side Note A: BoosterPack Layout - Custom KiCad Parts
Hercules LaunchPad and GaN FETs - Side Note B: Look at the PCB
Rotary Encoders - Part 1: Electronics
Checking Out GaN Half-Bridge Power Stage: Texas Instruments LMG5200 - Part 1: Preview
Rotary Encoders - Part 4: Capturing Input on a Texas Instruments Hercules LaunchPad with eQEP
Vintage Turntable repair: Can I fix a Perpetuum Ebner from 1958 - part 4 - Hercules LaunchPad Enhanced PWM try-out



The CCS / HALCoGen projects are attached to the blog.