PCA9629 a stepper motor controller class library

Dependents:   PCA9629_Hello

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers PCA9629.cpp Source File

PCA9629.cpp

00001 /** PCA9629 library
00002  *
00003  *  @author  Akifumi (Tedd) OKANO, NXP Semiconductors
00004  *  @version 1.1
00005  *  @date    23-Jul-2012
00006  *
00007  *  revision history
00008  *      version 1.0 (24-Apr-2011) : Initial version
00009  *      version 1.1 (23-Jul-2012) : API modification
00010  *                                  Correction for comments
00011  *
00012  *  Released under the MIT License: http://mbed.org/license/mit
00013  *
00014  *  An operation sample of PCU9629 stepper motor controller.
00015  *  The mbed accesses the PCU9629 registers through I2C.
00016  *
00017  *  About PCA9629:
00018  *    http://www.nxp.com/products/interface_and_connectivity/i2c/i2c_bus_controller_and_bridge_ics/PCA9629PW.html
00019  */
00020 
00021 #include    "mbed.h"
00022 #include    "PCA9629.h"
00023 
00024 #define     STEP_RESOLUTION     333333      //  1/(3e-6) = 333333
00025 
00026 char *reg_name[] = {
00027     "MODE", "SUBADR1", "SUBADR2", "SUBADR3", "ALLCALLADR", "WDTC", "WDMOD", "IP",
00028     "INTSTAT", "OP", "IOC", "MSK", "CLRINT", "INTMODE1", "INTMODE2", "INT_ACT_SETUP",
00029     "INT_MRT_SETUP", "INT_ES_SETUP", "SETMODE", "PHCNTL", "SROTNL", "SROTNH",
00030     "CWPWL", "CWPWH", "CCWPWL", "CCWPWH",
00031     "CWSCOUNTL", "CWSCOUNTH", "CCWSCOUNTL", "CCWSCOUNTH",
00032     "CWRCOUNTL", "CWRCOUNTH", "CCWRCOUNTL", "CCWRCOUNTH",
00033     "EXTRASTEPS0", "EXTRASTEPS1", "RAMPX", "LOOPDLY", "MCNTL"
00034 };
00035 
00036 PCA9629::PCA9629(
00037     PinName I2C_sda,
00038     PinName I2C_scl,
00039     short   steps_per_rotation,
00040     char    I2C_address
00041 ) : i2c( I2C_sda, I2C_scl ), i2c_addr( I2C_address ) {
00042 
00043     i2c.frequency( 400 * 1000 );
00044     software_reset();
00045     init_registers();
00046 }
00047 
00048 void PCA9629::software_reset( void ) {
00049     char    v   = 0x06;
00050     
00051     i2c.write( 0x00, &v, 1 );
00052     wait_ms( 1 );
00053 }
00054 
00055 void PCA9629::init_registers( void ) {
00056     char    init_array[] = { 0x80,                                                //  register access start address (0x00) with incremental access flag (MSB)
00057                              0x30, 0xE2, 0xE4, 0xE6, 0xE0, 0x02, 0x10,             //  for registers MODE - WDCNTL (0x00 - 0x06
00058                              0x00, 0x00,                                           //  for registers IP and INTSTAT (0x07, 0x08)
00059                              0x07, 0x0F, 0x00, 0x0F, 0x0F, 0x00, 0x03, 0x02, 0x01, //  for registers OP - INT_AUTO_CLR (0x09 - 0x11)
00060                              0x00, 0x00, 0x30, 0x00, 0x82, 0x66, 0x82, 0x06,       //  for registers SETMODE - CCWPWH (0x12 - 0x19)
00061                              0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,       //  for registers CWSCOUNTL - CCWRCOUNTH (0x1A - 0x21)
00062                              0x00, 0x00,                                           //  for registers EXTRASTEPS0 and EXTRASTEPS1 (0x22, 0x23)
00063                              0x00, 0x00, 0x00                                      //  for registers RMPCNTL - MCNTL (0x24 - 0x26)
00064                            };
00065 
00066     set_all_registers( init_array, sizeof( init_array ) );
00067 }
00068 
00069 void PCA9629::set_all_registers( char *a, char size ) {
00070     int     error_code;
00071 
00072     error_code  = i2c.write( i2c_addr, a, size );
00073 
00074     if ( error_code )
00075         error( "error @ initializing PCA9629" );
00076 }
00077 
00078 void PCA9629::write( RegisterName register_name, char value ) {
00079     int     error_code;
00080     char    cmd[ 2 ];
00081 
00082     cmd[ 0 ]    = register_name;
00083     cmd[ 1 ]    = value;
00084 
00085     error_code  = i2c.write( i2c_addr, cmd, 2 );
00086 
00087     if ( error_code )
00088         error( "PCA9629 writing failed\r\n" );
00089 }
00090 
00091 void PCA9629::write( RegisterNameFor16bitAccess register_name, short value ) {
00092     int     error_code;
00093     char    cmd[ 3 ];
00094 
00095     cmd[ 0 ]    = register_name;
00096     cmd[ 1 ]    = value & 0xFF;
00097     cmd[ 2 ]    = value >> 8;
00098 
00099     error_code  = i2c.write( i2c_addr, cmd, 3 );
00100 
00101     if ( error_code )
00102         error( "PCA9629 writing failed\r\n" );
00103 }
00104 
00105 char PCA9629::read( RegisterName register_name ) {
00106     int     error_code;
00107     char    cmd;
00108     char    data;
00109 
00110     cmd = register_name;
00111 
00112     error_code  = i2c.write( i2c_addr, &cmd, 1, false );
00113 
00114     if ( error_code )
00115         error( "PCA9629 reading (command phase) failed\r\n" );
00116 
00117     error_code  = i2c.read( i2c_addr, &data, 1 );
00118 
00119     if ( error_code )
00120         error( "PCA9629 reading (data phase) failed\r\n" );
00121 
00122     return ( data );
00123 }
00124 
00125 short PCA9629::read( RegisterNameFor16bitAccess register_name ) {
00126     int     error_code;
00127     char    cmd;
00128     char    data[ 2 ];
00129 
00130     cmd = register_name;
00131 
00132     error_code  = i2c.write( i2c_addr, &cmd, 1, false );
00133 
00134     if ( error_code )
00135         error( "PCA9629 reading (command phase) failed\r\n" );
00136 
00137     error_code  = i2c.read( i2c_addr, data, 2 );
00138 
00139     if ( error_code )
00140         error( "PCA9629 reading (data phase) failed\r\n" );
00141 
00142     return ( data[ 1 ] << 8 | data[ 0 ] );
00143 }
00144 
00145 void PCA9629::start( Direction dir ) {
00146     write( MCNTL, 0xA8 | dir );
00147 }
00148 
00149 void PCA9629::stop( void ) {
00150     write( MCNTL, 0x00 );
00151 }
00152 
00153 
00154 short PCA9629::pps( Direction dir, PrescalerRange prescaler, int pps ) {
00155     int     step_pulse_width;
00156 
00157     step_pulse_width    = STEP_RESOLUTION / ((1 << prescaler) * pps);
00158 
00159     if ( step_pulse_width & 0xE000 ) {  //error( "pps setting: out of range" );
00160         step_pulse_width    = 0x1FFF;
00161         printf( "the pps forced in to the range that user specified.. %fpps\r\n", (float)STEP_RESOLUTION / ((float)0x1FFF * (float)(1 << prescaler)) );
00162     }
00163     if ( !step_pulse_width ) {  //error( "pps setting: out of range" );
00164         step_pulse_width    = 0x1;
00165         printf( "the pps forced in to the range that user specified.. %fpps\r\n", (float)STEP_RESOLUTION / (float)(1 << prescaler) );
00166     }
00167 
00168     step_pulse_width    |= (prescaler << 13);
00169 
00170     write( (dir == CW) ? CW__STEP_WIDTH : CCW_STEP_WIDTH, step_pulse_width );
00171 
00172     return ( step_pulse_width );
00173 }
00174 
00175 short PCA9629::pps( Direction dir, float pulse_per_second ) {
00176     char    p       = 0;
00177     char    ratio;
00178 
00179     ratio   = (char)(40.6901 / pulse_per_second);
00180 
00181     p   = (ratio & 0x01) ? 1 : p;
00182     p   = (ratio & 0x02) ? 2 : p;
00183     p   = (ratio & 0x04) ? 3 : p;
00184     p   = (ratio & 0x08) ? 4 : p;
00185     p   = (ratio & 0x10) ? 5 : p;
00186     p   = (ratio & 0x20) ? 6 : p;
00187     p   = (ratio & 0x40) ? 7 : p;
00188 
00189     return ( pps( dir, (PrescalerRange)p, (int)pulse_per_second ) );
00190 }
00191 
00192 void PCA9629::rotations( Direction dir, int rotation_count ) {
00193     write( (dir == CW) ? CW__ROTATION_COUNT : CCW_ROTATION_COUNT, rotation_count );
00194 }
00195 
00196 void PCA9629::steps( Direction dir, int step_count ) {
00197     write( (dir == CW) ? CW__STEP_COUNT : CCW_STEP_COUNT, step_count );
00198 }
00199 
00200 void PCA9629::rotations_and_steps( Direction dir, int rotation_count, int step_count ) {
00201     rotations( dir, rotation_count );
00202     steps( dir, step_count );
00203 }
00204 
00205 void PCA9629::register_dump( void ) {
00206     char    data[ 0x27 ];
00207     char    cmd = 0x80;
00208     int     i;
00209     int     j;
00210 
00211     i2c.write( i2c_addr, &cmd, 1 );
00212     i2c.read( i2c_addr, data, sizeof( data ) );
00213 
00214     printf( "PCA9629 register dump\r\n" );
00215 
00216     for ( i = 0, j = 0x14; i <= 0x12; i++, j++ )
00217         printf( "  %-13s (0x%02X): 0x%02X    %-13s (0x%02X): 0x%02X\r\n", reg_name[ i ], i, data[ i ], reg_name[ j ], j, data[ j ] );
00218 
00219     printf( "  %-13s (0x%02X): 0x%02X\r\n", reg_name[ 0x13 ], 0x13, data[ 0x13 ] );
00220 }
00221 
00222 
00223 void PCA9629::speed_change( unsigned short pw ) {
00224     char    cmd0[]   = { PCA9629::MCNTL, 0x00};                         //  data for stop the motor
00225     char    cmd1[]   = { PCA9629::CW__STEP_WIDTH, pw & 0xFF, pw >> 8 }; //  data for rewrite pulse width
00226     char    cmd2[]   = { PCA9629::MCNTL, 0xB4};   //  start             //  data for start again
00227     wait_us(10);
00228 
00229     i2c.write( i2c_addr, cmd0, sizeof( cmd0 ), true );  //  stop the motor
00230     wait_us(50);
00231     i2c.write( i2c_addr, cmd1, sizeof( cmd1 ), true );  //  rewrite pulse width
00232     i2c.write( i2c_addr, cmd2, sizeof( cmd2 ), false ); //  start again
00233 }
00234 
00235 
00236