InetrfaceProducts NXP / PCA9629A

Dependents:   PCA9629A_Hello

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers PCA9629A.cpp Source File

PCA9629A.cpp

00001 /** A sample code for PCA9629A
00002  *
00003  *  @author  Akifumi (Tedd) OKANO, NXP Semiconductors
00004  *  @version 1.1
00005  *  @date    12-Sep-2012
00006  *
00007  *  revision history (PCA9629A)
00008  *      version 0.1 (05-Jun-2013) : PCA9629"A" initial version
00009  *      version 0.2 (05-Jun-2013) : register name fix, register description added
00010  *      version 1.0 (23-Apr-2014) : unnecessary parameter for constructor has been removed
00011  *      version 1.1 (12-Sep-2014) : constructor variation added. ramp parameter API added
00012  *
00013  *  Released under the Apache 2 license License
00014  *
00015  *  An operation sample of PCU9629A stepper motor controller.
00016  *  The mbed accesses the PCU9629A registers through I2C.
00017  *
00018  *  About PCA9629A:
00019  *    http://www.nxp.com/products/interface_and_connectivity/i2c/i2c_bus_controller_and_bridge_ics/PCA9629APW.html
00020  */
00021 
00022 #include    "mbed.h"
00023 #include    "PCA9629A.h"
00024 
00025 #define     STEP_RESOLUTION     333333      //  1/(3e-6) = 333333
00026 
00027 char *reg_name[] = {
00028     "MODE", "WDTOI", "WDCNTL", "IO_CFG",
00029     "INTMODE", "MSK", "INTSTAT", "IP", "INT_MTR_ACT", "EXTRASTEPS0", "EXTRASTEPS1",
00030     "OP_CFG",  "OP_STAT_PHS",
00031     "RUCNTL", "RDCNTL",
00032     "PMA", "LOOPDLY_CW", "LOOPDLY_CCW",
00033     "CWSCOUNTL", "CWSCOUNTH", "CCWSCOUNTL", "CCWSCOUNTH",
00034     "CWPWL", "CWPWH", "CCWPWL", "CCWPWH",
00035     "MCNTL",
00036     "SUBADR1", "SUBADR2", "SUBADR3", "ALLCALLADR",
00037     "STEPCOUNT0", "STEPCOUNT1", "STEPCOUNT2", "STEPCOUNT3"
00038 };
00039 
00040 PCA9629A::PCA9629A(
00041     PinName I2C_sda,
00042     PinName I2C_scl,
00043     char    I2C_address
00044 ) : i2c_p( new I2C( I2C_sda, I2C_scl ) ), i2c( *i2c_p ), i2c_addr( I2C_address )
00045 {
00046     i2c.frequency( I2C_SCL_FREQUENCY );
00047     init_registers();
00048 }
00049 
00050 PCA9629A::PCA9629A(
00051     I2C     &i2c_,
00052     char    I2C_address
00053 ) : i2c_p( NULL ), i2c( i2c_ ), i2c_addr( I2C_address )
00054 {
00055     init_registers();
00056 }
00057 
00058 PCA9629A::~PCA9629A()
00059 {
00060     if ( NULL != i2c_p )
00061         delete  i2c_p;
00062 }
00063 
00064 void PCA9629A::software_reset( void )
00065 {
00066     char    v   = 0x06;
00067 
00068     i2c.write( 0x00, &v, 1 );
00069     wait_ms( 1 );
00070 }
00071 
00072 void PCA9629A::init_registers( void )
00073 {
00074     char    init_array[] = { 0x80,                                           //  register access start address (0x00) with incremental access flag (MSB)
00075                              0x20, 0x0A, 0x00, 0x03, 0x13, 0x1C,             //  for registers MODE - MSK (0x00 - 0x07
00076                              0x00, 0x00, 0x68, 0x00, 0x00,                   //  for registers INTSTAT - EXTRASTEPS1 (0x06, 0xA)
00077                              0x10, 0x80,                                     //  for registers OP_CFG_PHS and OP_STAT_TO (0x0B - 0xC)
00078                              0x09, 0x09, 0x01, 0x7D, 0x7D,                   //  for registers RUCNTL - LOOPDLY_CCW (0xD- 0x10)
00079                              0xFF, 0x01, 0xFF, 0x01, 0x05, 0x0D, 0x05, 0x0D, //  for registers CWSCOUNTL - MCNTL (0x12 - 0x1A)
00080                              0x20,                                           //  for register MCNTL (0x1A)
00081                              0xE2, 0xE4, 0xE6, 0xE0                          //  for registers SUBADR1 - ALLCALLADR (0x1B - 0x1E)
00082                            };
00083 
00084     set_all_registers( init_array, sizeof( init_array ) );
00085 }
00086 
00087 void PCA9629A::set_all_registers( char *a, char size )
00088 {
00089     int     error_code;
00090 
00091     error_code  = i2c.write( i2c_addr, a, size );
00092 
00093     if ( error_code )
00094         error( "error @ initializing PCA9629A" );
00095 }
00096 
00097 void PCA9629A::write( RegisterName register_name, char value )
00098 {
00099     int     error_code;
00100     char    cmd[ 2 ];
00101 
00102     cmd[ 0 ]    = register_name;
00103     cmd[ 1 ]    = value;
00104 
00105     error_code  = i2c.write( i2c_addr, cmd, 2 );
00106 
00107     if ( error_code )
00108         error( "PCA9629A writing failed\r\n" );
00109 }
00110 
00111 void PCA9629A::write( RegisterNameFor16bitAccess register_name, short value )
00112 {
00113     int     error_code;
00114     char    cmd[ 3 ];
00115 
00116     cmd[ 0 ]    = register_name;
00117     cmd[ 1 ]    = value & 0xFF;
00118     cmd[ 2 ]    = value >> 8;
00119 
00120     error_code  = i2c.write( i2c_addr, cmd, 3 );
00121 
00122     if ( error_code )
00123         error( "PCA9629A writing failed\r\n" );
00124 }
00125 
00126 char PCA9629A::read( RegisterName register_name )
00127 {
00128     int     error_code;
00129     char    cmd;
00130     char    data;
00131 
00132     cmd = register_name;
00133 
00134     error_code  = i2c.write( i2c_addr, &cmd, 1, false );
00135 
00136     if ( error_code )
00137         error( "PCA9629A reading (command phase) failed\r\n" );
00138 
00139     error_code  = i2c.read( i2c_addr, &data, 1 );
00140 
00141     if ( error_code )
00142         error( "PCA9629A reading (data phase) failed\r\n" );
00143 
00144     return ( data );
00145 }
00146 
00147 short PCA9629A::read( RegisterNameFor16bitAccess register_name )
00148 {
00149     int     error_code;
00150     char    cmd;
00151     char    data[ 2 ];
00152 
00153     cmd = register_name;
00154 
00155     error_code  = i2c.write( i2c_addr, &cmd, 1, false );
00156 
00157     if ( error_code )
00158         error( "PCA9629A reading (command phase) failed\r\n" );
00159 
00160     error_code  = i2c.read( i2c_addr, data, 2 );
00161 
00162     if ( error_code )
00163         error( "PCA9629A reading (data phase) failed\r\n" );
00164 
00165     return ( data[ 1 ] << 8 | data[ 0 ] );
00166 }
00167 
00168 long PCA9629A::read( RegisterNameFor32bitAccess register_name )
00169 {
00170     int     error_code;
00171     char    cmd;
00172     char    data[ 4 ];
00173 
00174     cmd = register_name | 0x80;
00175 
00176     error_code  = i2c.write( i2c_addr, &cmd, 1, false );
00177 
00178     if ( error_code )
00179         error( "PCA9629A reading (command phase) failed\r\n" );
00180 
00181     error_code  = i2c.read( i2c_addr, data, 4 );
00182 
00183     if ( error_code )
00184         error( "PCA9629A reading (data phase) failed\r\n" );
00185 
00186     printf( "0x %02X %02X %02X %02X\r\n", data[3], data[2], data[1], data[0] );
00187 
00188     return ( data[ 3 ] << 24 | data[ 2 ] << 16 | data[ 1 ] << 8 | data[ 0 ] );
00189 }
00190 
00191 void PCA9629A::start( Direction dir )
00192 {
00193     write( MCNTL, 0xC0 | dir );
00194 }
00195 
00196 void PCA9629A::stop( void )
00197 {
00198     write( MCNTL, 0xA0 );
00199 }
00200 
00201 
00202 short PCA9629A::pps( Direction dir, PrescalerRange prescaler, int pps )
00203 {
00204     int     step_pulse_width;
00205 
00206     step_pulse_width    = STEP_RESOLUTION / ((1 << prescaler) * pps);
00207 
00208     if ( step_pulse_width & 0xE000 ) {  //error( "pps setting: out of range" );
00209         step_pulse_width    = 0x1FFF;
00210         printf( "the pps forced in to the range that user specified.. %fpps\r\n", (float)STEP_RESOLUTION / ((float)0x1FFF * (float)(1 << prescaler)) );
00211     }
00212     if ( !step_pulse_width ) {  //error( "pps setting: out of range" );
00213         step_pulse_width    = 0x1;
00214         printf( "the pps forced in to the range that user specified.. %fpps\r\n", (float)STEP_RESOLUTION / (float)(1 << prescaler) );
00215     }
00216 
00217     step_pulse_width    |= (prescaler << 13);
00218 
00219     write( (dir == CW) ? CW__STEP_WIDTH : CCW_STEP_WIDTH, step_pulse_width );
00220 
00221     return ( step_pulse_width );
00222 }
00223 
00224 short PCA9629A::pps( Direction dir, float pulse_per_second )
00225 {
00226     char    p       = 0;
00227     char    ratio;
00228 
00229     ratio   = (char)(40.6901 / pulse_per_second);
00230 
00231     p   = (ratio & 0x01) ? 1 : p;
00232     p   = (ratio & 0x02) ? 2 : p;
00233     p   = (ratio & 0x04) ? 3 : p;
00234     p   = (ratio & 0x08) ? 4 : p;
00235     p   = (ratio & 0x10) ? 5 : p;
00236     p   = (ratio & 0x20) ? 6 : p;
00237     p   = (ratio & 0x40) ? 7 : p;
00238 
00239     return ( pps( dir, (PrescalerRange)p, (int)pulse_per_second ) );
00240 }
00241 
00242 void PCA9629A::steps( Direction dir, int step_count )
00243 {
00244     write( (dir == CW) ? CW__STEP_COUNT : CCW_STEP_COUNT, step_count );
00245 }
00246 
00247 void PCA9629A::ramp_up( char rate )
00248 {
00249     write( RUCNTL, rate ? (0x30 | (rate -1)) : 0x00 );
00250 }
00251 
00252 void PCA9629A::ramp_down( char rate )
00253 {
00254     write( RDCNTL, rate ? (0x30 | (rate -1)) : 0x00 );
00255 }
00256 
00257 void PCA9629A::register_dump( void )
00258 {
00259     char    data[ 0x23 ];
00260     char    cmd = 0x80;
00261     int     i;
00262     int     j;
00263 
00264     i2c.write( i2c_addr, &cmd, 1 );
00265     i2c.read( i2c_addr, data, sizeof( data ) );
00266 
00267     printf( "PCA9629A register dump\r\n" );
00268 
00269     for ( i = 0, j = 0x14; i <= 0x12; i++, j++ )
00270         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 ] );
00271 
00272     printf( "  %-13s (0x%02X): 0x%02X\r\n", reg_name[ 0x13 ], 0x13, data[ 0x13 ] );
00273 }
00274 
00275 
00276 void PCA9629A::speed_change( unsigned short pw )
00277 {
00278 #ifdef MBED_PCA9629
00279     //  this is for PCA9629(non-A version)
00280     char    cmd0[]   = { PCA9629A::MCNTL, 0x00};                         //  data for stop the motor
00281     char    cmd1[]   = { PCA9629A::CW__STEP_WIDTH, pw & 0xFF, pw >> 8 }; //  data for rewrite pulse width
00282     char    cmd2[]   = { PCA9629A::MCNTL, 0xB4};   //  start             //  data for start again
00283     wait_us(10);
00284 
00285     i2c.write( i2c_addr, cmd0, sizeof( cmd0 ), true );  //  stop the motor
00286     wait_us(50);
00287     i2c.write( i2c_addr, cmd1, sizeof( cmd1 ), true );  //  rewrite pulse width
00288     i2c.write( i2c_addr, cmd2, sizeof( cmd2 ), false ); //  start again
00289 #else
00290     char    cmd1[]   = { PCA9629A::CW__STEP_WIDTH, pw & 0xFF, pw >> 8 }; //  data for rewrite pulse width
00291 
00292     i2c.write( i2c_addr, cmd1, sizeof( cmd1 ), true );  //  rewrite pulse width
00293 #endif
00294 }