element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products & Partners
    Products & Partners
    • Arduino
    • Avnet & Tria Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • About Us
    About the element14 Community
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Japan
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      •  Vietnam
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Embedded and Microcontrollers
  • Technologies
  • More
Embedded and Microcontrollers
Blog MSPM0 stepper motor control with TI DRV8711 stepper driver, with s-curve ramps
  • Blog
  • Forum
  • Documents
  • Quiz
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Embedded and Microcontrollers to participate - click to join for free!
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: Jan Cumps
  • Date Created: 15 Oct 2026 5:58 PM Date Created
  • Views 45 views
  • Likes 1 like
  • Comments 0 comments
  • MSPM0L1105
  • MSPM0
  • easyL1105
  • drv8711
  • VS Code
  • MSPM0L1306
  • vscode
Related
Recommended

MSPM0 stepper motor control with TI DRV8711 stepper driver, with s-curve ramps

Jan Cumps
Jan Cumps
15 Oct 2026
MSPM0 stepper motor control with TI DRV8711 stepper driver, with s-curve ramps

Stepper Motors are controlled by a driver IC.  This blog shows how to use a Texas Instruments DRV8711 stepper motor IC with the MSPM0 controller family.

image


It's a port of a Raspberry Pico driver I designed for that IC:Raspberry Pico stepper driver IC library, with example: Texas Instruments DRV8711 .
This post is part of a MSPM0 stepper motor series. I've made a design for an Allegro A4899 IC earlier: MSPM0 project with VS Code, CMake and GCC - part 7b: middleware stepper motor control with A4988 stepper driver .

hardware provisioning

I use the same timers as the design with the A4988 stepper driver, and the same DIR and n_enable GPIOs.

The DRV8711 is controlled over SPI, so I'll need to enable the SPI peripheral.

image

image

The DRV8711 requires that the CS is asserted over multiple data exchanges, so I have to implement a manual CS. That's why I selected 3-wire SPI.
Also, the CS works active high. It's different than most SPI ICs.

Here's the CS definition:

image

I had to select a high drive strength pin, because normal drive didn't get the job done.

other GPIOs used: reset: PA1. Just a normal Output pin.

MSPM0 DRV8711 class

I used the exact same design as the class I made for Raspberry Pico. I only ported the GPIO and SPI functions, to use the MSPM0 SDK.

/**
 * mspm0 port of DRV8711 library https://github.com/jancumps/drv8711_lib
*/

module;

/* Including all the sysconfig generated defines */
#include "ti_msp_dl_config.h"

import drv8711;
import drv8711_config;

export module drv8711_mspm0;
export namespace drv8711_mspm0 {

class drv8711_mspm0 : public drv8711::drv8711_driver {
public:    
    drv8711_mspm0(SPI_Regs * spi, uint32_t cs,
        GPIO_Regs* gpio, uint32_t n_sleep, uint32_t reset) : drv8711::drv8711_driver(),
        spi_(spi), cs_(cs), gpio_(gpio), n_sleep_(n_sleep), reset_(reset) {}
    
    virtual void enable(bool enable) override {
        put(n_sleep_, enable);
    }

private:
    // initialise all registers from the defaults
    // defined in module drv8711_config
    // developer can override values before calling
    virtual void init_registers() {
        write(drv8711::reg_ctrl);
        write(drv8711::reg_torque);
        write(drv8711::reg_off);
        write(drv8711::reg_blank);
        write(drv8711::reg_decay);
        write(drv8711::reg_stall);
        write(drv8711::reg_drive);
        write(drv8711::reg_status);
    }
    
    virtual void init_spi() override{
        // Enable SPI at 1 MHz
        // cs is initiated in its own method
    }

    // users may want to use different CS with same SPI for several ICs
    // and can do that by overriding this method
    virtual void init_cs() override {
        put(cs_, false);
    }

    virtual void init_gpio() override{
        // nsleep as output
        put(n_sleep_, false);
        // reset as output
        put(reset_, false);
    }

    // write to a register
    virtual void write(uint16_t reg) override {
        SPI_Write16_Blocking(reg);
    }

    // read from a register
    virtual uint16_t read(uint16_t reg) override {
        uint16_t r_buffer;
        uint16_t w_buffer;
        w_buffer = reg | 0b1000;
        w_buffer = w_buffer << 12;
        r_buffer = SPI_WriteRead16_Blocking(w_buffer);
        return r_buffer & 0b0000111111111111; // first 4 read bits are undefined
    }

protected:
    SPI_Regs *spi_;
    uint32_t cs_; // chip select pin needs to be managed manually for this driver, as it needs to stay high accross the entire SPI transaction, which is not supported by the MSPM0 SPI driver
    GPIO_Regs* gpio_;
    uint32_t  n_sleep_;
    uint32_t  reset_;

private:
    void put(uint32_t pin, bool set) {
        DL_GPIO_writePinsVal(gpio_, pin, set ? pin : 0U);
    }

    void SPI_Write16_Blocking(uint16_t data) {
        // 1. Wait until there is space available in the SPI TX FIFO
        while (DL_SPI_isTXFIFOFull(spi_));
    
        // 2. Load the 16-bit data packet into the transmission register
        put(cs_, true);
        // Pad the setup time (Delays 31.25 ns, which satisfies 5 ns minimum requirement)
//        delay_cycles(1);
        DL_SPI_transmitData16(spi_, data);
    
        // 3. Block until the shift register completes transmission and the bus is idle
        while (DL_SPI_isBusy(spi_));
        // Pad the setup time (Delays 31.25 ns, which satisfies 5 ns minimum requirement)
        put(cs_, false);
    }

    uint16_t SPI_WriteRead16_Blocking(uint16_t dataToWrite) {
        uint16_t receivedData = 0;
        // 1. Flush any leftover garbage data out of the RX FIFO to ensure a clean transaction
        put(cs_, true);
        // Pad the setup time (Delays 31.25 ns, which satisfies 5 ns minimum requirement)
 //       delay_cycles(1);
        while (!DL_SPI_isRXFIFOEmpty(spi_)) {
            DL_SPI_receiveData16(spi_); // Read and discard
        }

        // 2. Wait until there is space available in the TX FIFO
        while (DL_SPI_isTXFIFOFull(spi_));
    
        // 3. Write the 16-bit variable into the transmission register
        DL_SPI_transmitData16(spi_, dataToWrite);
    
        // 4. Block until the RX FIFO receives the 16-bit response back from the slave
        while (DL_SPI_isRXFIFOEmpty(spi_));
    
        // 5. Extract and return the 16-bit data packet out of the RX FIFO
        receivedData = DL_SPI_receiveData16(spi_);
        // Pad the setup time (Delays 31.25 ns, which satisfies 5 ns minimum requirement)
//        delay_cycles(1);
        put(cs_, false);
        return receivedData;
    }

};

} // namespace drv8711_mspm0

The other classes are exact the same as used in the MSPM0 Allegro  A4988 example.

test code

Also very similar as the A4988 code, except for the configuration. That's DRV8711 / SPI specific:

#include "ti_msp_dl_config.h"
#include "hal.h"
#include <array>
#include <algorithm> // for std::transform


import stepper_driver;                          // wakeup class
import drv8711;                                 // driver classes and registers
import drv8711_config;                          // register pre-configuration
import drv8711_mspm0;                           // hw driver classes and registers
import mspm0_pwm_stepper_driver;                // pwm step and dir driver
import mspm0_pwm_stepper_ramp_driver;           // pwm step and dir driver

const uint32_t dir = GPIO_GRP_DRIVER_PIN_DIR_PIN;
const uint32_t n_enable = GPIO_GRP_DRIVER_PIN_N_ENABLE_PIN;
const uint32_t cs = GPIO_GRP_DRIVER_PIN_SPI_0_CS_PIN;

const uint32_t microstep_x = 16;
const uint32_t max_step_freq = 300000;

// object to manage the drv8711 IC used for motor1
using driver_t = drv8711_mspm0::drv8711_mspm0;
driver_t driver1(SPI_0_INST, cs, GPIO_GRP_DRIVER_PORT, n_enable, microstep_x);

// object to manage the stepper motor using PWM for step and dir.
// uncomment the one to use:
// using pwm_stepper_driver_t = mspm0_pwm_stepper_driver::mspm0_pwm_stepper_driver;
using pwm_stepper_driver_t = mspm0_pwm_stepper_driver::mspm0_pwm_stepper_ramp_driver;
pwm_stepper_driver_t pwm_stepper_driver1(dir, GPIO_GRP_DRIVER_PORT, max_step_freq);


// S-curve pre-calculated profile (Speed values in Pulses Per Second / Hz)
// used by he mspm0_pwm_stepper_ramp_driver to implement a smooth acceleration and deceleration profile
const unsigned int RAMP_STEPS = 43;
// S-curve pre-calculated profile (Speed values in Pulses Per Second / Hz)
// TODO: translate to raw Hardware Timer Ticks (Highly Recommended for Performance)
inline static /*const*/ std::array<uint32_t, RAMP_STEPS> s_curve_lut = {
    150,  151,  152,  155,  160,  166,  174,  184,  196,  211,
    228,  247,  269,  293,  321,  352,  386,  424,  465,  509,  
    557,  608,  662,  719,  779,  842,  908,  976,  1046, 1118, 
    1191, 1265, 1340, 1414, 1489, 1563, 1636, 1707, 1777, 1845, 
    1910, 1971, 2000
};

// Function to introduce a delay of approximately 200 nanoseconds
// A4988 needs this time, after changing dir/enable/microstep pins, before the next step pulse is sent
inline void wait_200ns() {
    delay_cycles(7);
}

int main() {
    SYSCFG_DL_init();
    
    /* Initialize the HAL module */
    HAL_init(); // TODO step away from HAL?
    
    // drv8711::reg_torque.torque = 0x00ff; 
    driver1.init();
    driver1.microsteps(microstep_x);
    
    pwm_stepper_driver1.init();
    pwm_stepper_driver1.stop_motor();
    pwm_stepper_driver1.set_control_mode(mspm0_pwm_stepper_driver::control_mode::step);

    // not used by the ramp driver, but needed for the mspm0_pwm_stepper_driver::mspm0_pwm_stepper_driver to work
    // pwm_stepper_driver1.set_speed(1); // CURVE determines speed for ramp style motion, so set_speed() is not used in this example

    std::transform(s_curve_lut.begin(), s_curve_lut.end(), s_curve_lut.begin(), [](uint32_t val) {
        return val * 11.5; // Adjust the divisor to scale the speed values as needed
    });    

    pwm_stepper_driver1.set_ramp(s_curve_lut); // the vector has to stay alive for the duration of the motor run, so it is stored in a static variable in this example 

    /* Set the priority for interrupts */
    NVIC_SetPriority(GENERIC_PWM_CHANNEL_0_INST_INT_IRQN, 1);
    NVIC_SetPriority(TIMER_RAMP_INST_INT_IRQN, 2);

    while (1) {
        stepper_driver::wakeup w(driver1);

        
        pwm_stepper_driver1.set_dir(true);
        wait_200ns();
        pwm_stepper_driver1.set_step(100000);
        pwm_stepper_driver1.start_motor();
        
        while (pwm_stepper_driver1.is_motor_running()) {
            __WFI(); // Enter low-power sleep mode; wake on timer interrupts
        }
        
        pwm_stepper_driver1.set_dir(false);
        wait_200ns();
        pwm_stepper_driver1.set_step(100000);
        pwm_stepper_driver1.start_motor();       
        
        while (pwm_stepper_driver1.is_motor_running()) {
            __WFI(); // Enter low-power sleep mode; wake on timer interrupts
        }

    }
}

extern "C" {
    
    void GENERIC_PWM_CHANNEL_0_INST_IRQHandler() {
        if (DL_Timer_getPendingInterrupt(GENERIC_PWM_CHANNEL_0_INST) == DL_TIMER_IIDX_ZERO) {
            pwm_stepper_driver1.check_step();
        }
    }

    void TIMER_RAMP_INST_IRQHandler(void) {
        if (DL_Timer_getPendingInterrupt(TIMER_RAMP_INST) == DL_TIMER_IIDX_ZERO) {
            pwm_stepper_driver1.check_ramp();
        }
    }

}

Before trying the design with a motor, I checked if the SPI conversations work, with a logic analyser:

image

All good. And when I tried to spin a stepper motor, it worked right away. Spot the smooth operation, driven with s-curve accelerator and decelerator patterns.

You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image

Thank you for reading.

VS Code project: mspm0_stepper_ramp_drv8711_20261015_2.zip
(check this post for the expected VS Code workspace settings: MSPM0 project with VS Code, CMake and GCC - part 6: empty "template" project 
)

TI DRV8711 driver on GitHub

previous post:  MSPM0 project with VS Code, CMake and GCC - part 7c: stepper motor control with S-shaped ramps 
part of the EasyL1105 series. 
all posts

  • Sign in to reply
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2026 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube