Categories: Firmware Guide-PIC18

MG995 Servo Motor interfacing with PIC18F4550

A servo motor is a rotary actuator that allows precise control of the angular position. Along with the positive and negative terminals, servo motor also has a control terminal which is used to control the angular position of the servo motor. The control signal sends through the control terminal is a PWM signal which generally has a frequency of 50 Hz. The angular position of the motor is dependent on the duty cycle of the PWM signal. Here we will use the PCA9685 to generate the required PWM signal to operate the servo motor to a required angular position between 0 and 180 degrees. It allows simultaneous operation up to 16 motors, given a high current source voltage is supplied.

MG995 Servo Motor

MG995 is a high-speed standard servo motor which uses PWM signals to control its angular position. Its functions are similar to the commonly used SG90 servo motor. It is sturdier as it uses metallic gears, compared to the SG90 which uses plastic components. It has an operating voltage range of 4.8 V to 7.2 V and has an operating speed of 0.2 s per 60 degrees.

Although the MG995 claims to have an angular range of only 120 degrees, practically it can cover an angular range of about 180 degrees without reaching its angular limit. A 50 Hz PWM signal is generally used to operate the MG995 and the angular position of the servo motor depends on the duty cycle of the PWM control signal. It uses a position sensor to continuously sense the current position, compares it to the required position specified by the PWM signal and makes an angular displacement if required.

PCA9685

PCA9685 is a 16 channel LED controller device that provides PWM signal as its output. It can be used to operate RBGA LEDs at a required brightness by varying the duty cycle of the PWM signal. The phase and the period of the PWM signal could also be varied. Each of the output channels has its own 12 bit ON count and 12 bit OFF count registers to control the phase shift and duty cycle. A prescale value is used to configure the time period of the PWM signal. To load these registers I2C communication is used with the help of PIC18F4550. A detailed description of PCA9685 interfacing can be found in our previous chapter Interfacing of PCA9685 with PIC18F4550.

Here we will only be discussing the registers relevant to our topic.

Control Register

The control register is used to store the address of the register to be configured. It is loaded after the slave acknowledges a communication request by the master. The control register acts as a pointer and is automatically incremented after accessing the register if the AutoIncrement (AI) bit is enabled. The auto-increment, upon power-up, is disabled by default.

Mode 1

The Mode 1 register can be accessed at the location 0x00.


AI:- Bit used to enable or disable auto increment of the Control register
SLEEP:- When enabled will switch to low power mode with oscillator turned off
ALLCALL:- Enable or disable response to I2C-bus ALL CALL address

LED on and led off registers

Each of the 16 PWM outputs has a corresponding 12 bit ON count value and a 12 bit OFF count value. The 8 LSB bits of the ON count is stored in the LEDn_ON_L register and the 4 MSB bits at LEDn_ON_H[3:0]. The LEDn_ON_H[4] is used as always ON bit which will ignore the ON count and OFF count and keep the output always ON. Similarly, the 8 LSB bits of the OFF count is stored in the LEDn_OFF_L register and the 4 MSB bits at LEDn_OFF_H[3:0], with the LEDn_OFF_H[4] bit as the always OFF bit. The LED ON and OFF registers occupy address location from 06h to 15h.

The LEDn_ON and LEDn_OFF count can vary from 0 to 4095 and must never be programmed with the same value. This count value is compared with a counter variable, incremented at a particular time period, to get the corresponding PWM signal.

Pre_scale register

The value stored in PRE_SCALE register is used to pre-scale the clock output before using it to increment the counter value. The pre-scale value along with the clock frequency decides the time period of the PWM signal. For a required update rate, the pre_scale value can be calculated as

prescale_value = round( clock_rate/(4096 * update_rate ) – 1

PRE_SCALE register is hardware limited to have a minimum value of 3 (03h) and a maximum value of 255 (FFh). Thus using the 25MHz internal oscillator, the maximum value of update_rate is 1526 Hz (prescale_value=0x03h) and the minimum value of update_rate is 24 Hz (prescale_value=0xFFh). By default, the PRE_SCALE register is loaded with the value 30 (0x1Eh) giving us an update_rate of 200 Hz with the 25MHz internal oscillator.

For operating the MG995 servo motor, we need a 50 Hz PWM signal. Using the 25 MHz internal oscillators, for a 50 Hz frequency, the prescale_value calculated as 121 (Decimal) or 0x79 (Hex).

Programming PWM Signal

The PWM signal output is programmed by loading appropriate ON count and OFF count values for each output pin. The PCA9685 has an internal counter value, incremented at a particular update rate, counting from 0 to 4095. The counter value is constantly compared with the ON count and the OFF count to generate the PWM signal. The PWM signal is turned HIGH when the counter value equal to ON coun. And it is turned LOW when the counter value equal to OFF count. Thus the ON count will account for the phase shift and the difference between OFF count and ON count will decide the duty cycle of the PWM signal.

For our purpose of operation servo motor, the initial delay or phase shift is not required. So the ON count is always loaded with the value zero.

The angular position of the servo motor depends on the duty cycle of the PWM signal. The duty cycle required to obtain a particular angle is different for different models of servo motors. The OFF count has to be loaded with a calculated value to provide the required angular position of the servo motor. The mapping of the OFF count to the required degree between 0 and 180 can be done with the formula

OFF_Count =(( Max-Min ) * ( Degree/180 ))+Min

Here Min and Max are the count values corresponding to the angular position 0 and 180 respectively for a particular model of the servo motor. It can be found by trial and error method or from its datasheet if specified.

For MG995, by trial and error method, the Min value was found as 96 (Decimal) and the Max value as 470 (Decimal).

Waveform

Interfacing with PIC18F4550

To program the PCA9685 chip with PIC18F4550, we will use functions implementing the I2C communication. Before setting the count registers, we need to configure the PCA9685 by enabling the output (OE=0) and configuring the Mode 1 register. Also to change the PWM frequency to 50 Hz, we need to load the corresponding prescale value to PRE_SCALE register. Enable SLEEP bit in Mode 1 register to turn off the internal oscillator for loading prescale value

To that end, we need to apply a LOW voltage at OE pin and give a start signal followed by the slave address and mode of operation. After receiving the acknowledgment from the PCA9685, the Mode 1 register is configured to turn off the internal oscillator and the prescale value is loaded to the PRE_SCALE register. The internal oscillator is then enabled by loading the Mode 1 register with an appropriate value. The communication is ended with a Stop signal.

Firmware Example :

#define i2c_freq 100000UL
#define _XTAL_FREQ 20000000UL

unsigned int pca_addr;                  //Global variable to store slave address

void pca_servo_init(unsigned int addr)
{
    pca_addr=addr;                      //Assigning global variable with slave address
    
    TRISBbits.TRISB2=0;
    PORTBbits.RB2=0;                    //Enabling PCA9685 with OE=0
    
    i2c_init(i2c_freq);                 //Initializing I2C communication at 100KHz
    i2c_start();                        //Start signal
    i2c_write(pca_addr);                //Specifying slave address in write mode
    i2c_write(0x00);                    //Control register set to address of Mode 1 register
    i2c_write(0x10);                    //Mode 1 configured to enable sleep
    i2c_restart();                      //Start new operation
    i2c_write(pca_addr);                //Specifying slave address in write mode
    i2c_write(0xFE);                    //Control register set to address of PRE_SCALE register
    i2c_write(0x79);                    //Loading prescale value for 50 Hz PWM Signal
    i2c_restart();                      //Start new operation
    i2c_write(pca_addr);                //Specifying slave address in write mode
    i2c_write(0x00);                    //Control register set to address of Mode 1 register
    i2c_write(0x21);                    //Mode 1 configured with AI=1, ALLCALL=1 and SLEEP disabled
    i2c_stop();                         //Stop signal
}

To configure the PWM signal from the output pin LEDn of PCA9685 to the servo motor, we need to load the ON count and the OFF count. The ON count is loaded with value 0 and the OFF count should be calculated for the required angular position of the servo motor.

A start signal is provided followed by the slave address in write mode. After receiving the acknowledgment, the Control register is loaded with the address of LEDn_ON_L register. The LEDn_ON_L, LEDn_ON_H, LEDn_OFF_L and LEDn_OFF_H registers are sequentially loaded with an appropriate value according to the required ON count and OFF count. Therefore a Stop signal is also provided to end the communication.

Firmware Example :

void pca_servo(unsigned int pin, unsigned int deg)
{
    unsigned int min, max, count;
    min = 96;                                                   //Calibrated value for 0 Degree
    max = 470;                                                  //Calibrated value for 180 Degree
    
    if(pin > 15)                                                //Checking if pin entered is invalid
        return;
    if(deg > 180)                                               //Limiting maximum value of degrees to 180
        deg = 180;
    
    count = (unsigned int)(((max-min)*(float)deg/180)+min);     //Mapping count value for required angle
        
    i2c_init(i2c_freq);                                         //Initializing I2C communication at 100KHz
    i2c_start();                                                //Start signal
    i2c_write(pca_addr);                                        //Specifying slave address in write mode
    i2c_write((pin*4)+6);                                       //Control register set to address PINn_ON_L
    i2c_write(0x00);                                            //Writing 8 LSB bits of ON count
    i2c_write(0x00);                                            //Writing 4 MSB bits of ON count
    i2c_write(count&0xFF);                                      //Writing 8 LSB bits of OFF count
    i2c_write((count&0xF00)>>8);                                //Writing 4 MSB bits of OFF count
    i2c_stop();                                                 //Stop signal
}

Circuit Diagram

Here all the address pins of PCA9685 are grounded. TheMG995 servo motor can be connected to male pins of the output channel of the development board. An external high current voltage is recommended for operating the higher number of servo motors or more powerful servo motors

Share