DC Motor Control

Building a DC Motor Control System with STM32: My Journey So Far

Hey everyone! I'm excited to share the journey of my personal project: building a DC motor control system using an STM32 microcontroller. This project has been a good learning experience. You can check out the code and project details on my GitHub Repository.

Here’s a look at my progress and the problems I've tackled along the way.

Early Steps: Encoder Integration and Quadrature Decoding

My first major task involved getting the encoder working to accurately measure motor position and speed.

  • Encoder Testing: I started by powering the encoder with the STM32 and observing the phase difference between Channel A and Channel B while spinning the motor. This was crucial for understanding how to decode the encoder signals.
  • Quadrature Decoding: The goal was to efficiently count encoder ticks. I configured a GPIO pin as an interrupt and used its weak callback function to compare pin states, allowing me to increment/decrement motorPosition.
  • Calculating Degrees: To convert raw encoder counts to degrees, I calibrated by rotating the shaft one full rotation to get the Pulses Per Revolution (PPR) for Channel A (using 2X decoding since the interrupt is triggered on rising and falling edge). The formula used is encoder_cnts_deg = (motorPosition / PPR) * 360.
  • Velocity Measurement: For velocity, I'm using a constant time method. I configured TIM4 with an ARR of 10 and a Prescaler of 8400 to generate a 1ms timer period for encoder velocity. The HAL_TIM_PeriodElapsedCallback function now computes motorVelocity based on the change in motorPosition over time.

Controlling the Motor: PWM Implementation

Getting the motor to spin required precise PWM control.

  • PWM Setup: I worked on taking PWM as output from the STM32 and verified the output from the timer pin on an oscilloscope.
  • Dynamic Duty Cycle: A key feature is setting the duty cycle via a user interface. My STM32 code receives 4 bytes of data via UART2 from the C# code. A callback function then combines these into a 32-bit unsigned number, which is set to the timer's CCR3 register to update the PWM duty cycle.

Communication: STM32 to User Interface

Seamless communication between the STM32 and a PC-based User Interface was essential for control and feedback.

  • UART Setup: I focused on establishing robust UART communication between the STM32 and the C# PC.
  • Challenges with UART: I encountered a problem where I couldn't use the same UART port to generate interrupts and also read serial data within a while loop simultaneously. This required some rethinking of the communication strategy.
  • User Interface Buffer Management: On the C# side, it's crucial to clear the buffer every time data is read to prevent data from stacking up and causing issues.
  • User Interface Enhancements: I developed a simple GUI in C# to provide users with all the project's features. I also removed MessageBox calls from the code to resolve random UI hangs, improving the user experience.

Current Sensing: Measuring Motor Current

Integrating a current sensor (INA219) has been the most recent and challenging phase for measuring the current flowing when a motor is connected to the microcontroller using an H-bridge.

  • Datasheet Deep Dive: I spent considerable time going through the INA219 datasheet to understand how to configure the chip and measure current.
  • Configuration: The default address of the chip with A0 and A1 not soldered is 0x40. I calculated the current_lsb and the calibration register value, then wrote a basic function to initialize the current sensor.
  • Reading Values: I've implemented functions for reading raw ADC counts and current in mA.
  • Current Sensor Troubleshooting: This part has presented significant hurdles:
    • Unexpected Readings: When the battery is off, I'm still reading 26625 as the raw ADC value, which is wrong (it should be closer to 0 as the shunt voltage should be 0V).
    • I2C Communication Failures: I've been troubleshooting issues where the basic HAL_I2C_Mem_Read function returns a failure, indicating there is perhaps a sensor wiring problem or the sensor just doesn't work. I've also adjusted compiler settings, changed code, and removed volatile keywords to manage warnings, but the core issue persists. I'll be trying new breadboards soon to rule out hardware defects.

Next Steps

My immediate focus is to resolve the current sensor issues, as accurate current measurement is vital for this project. Once that's stable, I'll continue refining the control algorithms and user interface.

Stay tuned for more updates on this exciting project! Your feedback and insights are always welcome.

---

Comments