PCA9629 a stepper motor controller class library
Class library for PCA9629.
A sample program available on http://mbed.org/users/nxp_ip/code/PCA9629_Hello/
Diff: PCA9629.cpp
- Revision:
- 4:9a80b6d63005
- Child:
- 5:aff87a1c8bd6
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PCA9629.cpp Fri Feb 03 04:03:34 2012 +0000 @@ -0,0 +1,198 @@ +/** A sample code for PCA9629 + * + * @author Tedd OKANO, NXP Semiconductors + * @version 1.0 + * @date 03-Feb-2011 + * + * Released under the MIT License: http://mbed.org/license/mit + * + * An operation sample of PCU9629 stepper motor controller. + * The mbed accesses the PCU9629 registers through I2C. + */ + +#include "mbed.h" +#include "PCA9629.h" + +#define STEP_RESOLUTION 333333 // 1/(3e-6) = 333333 + +char *reg_name[] = { + "MODE", "SUBADR1", "SUBADR2", "SUBADR3", "ALLCALLADR", "WDTC", "WDMOD", "IP", + "INTSTAT", "OP", "IOC", "MSK", "CLRINT", "INTMODE1", "INTMODE2", "INT_ACT_SETUP", + "INT_MRT_SETUP", "INT_ES_SETUP", "SETMODE", "PHCNTL", "SROTNL", "SROTNH", + "CWPWL", "CWPWH", "CCWPWL", "CCWPWH", + "CWSCOUNTL", "CWSCOUNTH", "CCWSCOUNTL", "CCWSCOUNTH", + "CWRCOUNTL", "CWRCOUNTH", "CCWRCOUNTL", "CCWRCOUNTH", + "EXTRASTEPS0", "EXTRASTEPS1", "RAMPX", "LOOPDLY", "MCNTL" +}; + +PCA9629::PCA9629( + PinName I2C_sda, + PinName I2C_scl, + char I2C_address +) : i2c( I2C_sda, I2C_scl ), i2c_addr( I2C_address ) { + + i2c.frequency( 400 * 1000 ); + init_registers(); +} + +void PCA9629::init_registers( void ) { + char init_array[] = { 0x80, // register access start address (0x00) with incremental access flag (MSB) + 0x30, 0xE2, 0xE4, 0xE6, 0xE0, 0x02, 0x10, // for registers MODE - WDCNTL (0x00 - 0x06 + 0x00, 0x00, // for registers IP and INTSTAT (0x07, 0x08) + 0x07, 0x0F, 0x00, 0x0F, 0x0F, 0x00, 0x03, 0x02, 0x01, // for registers OP - INT_AUTO_CLR (0x09 - 0x11) + 0x00, 0x00, 0x30, 0x00, 0x82, 0x66, 0x82, 0x06, // for registers SETMODE - CCWPWH (0x12 - 0x19) + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, // for registers CWSCOUNTL - CCWRCOUNTH (0x1A - 0x21) + 0x00, 0x00, // for registers EXTRASTEPS0 and EXTRASTEPS1 (0x22, 0x23) + 0x00, 0x00, 0x00 // for registers RMPCNTL - MCNTL (0x24 - 0x26) + }; + + set_all_registers( init_array, sizeof( init_array ) ); +} + +void PCA9629::set_all_registers( char *a, char size ) +{ + int error_code; + + error_code = i2c.write( i2c_addr, a, size ); + + if ( error_code ) + error( "error @ initializing PCA9629" ); +} + +void PCA9629::write( RegisterName register_name, char value ) { + int error_code; + char cmd[ 2 ]; + + cmd[ 0 ] = register_name; + cmd[ 1 ] = value; + + error_code = i2c.write( i2c_addr, cmd, 2 ); + + if ( error_code ) + error( "PCA9629 writing failed\r\n" ); +} + +void PCA9629::write( Register16bits register_name, short value ) { + int error_code; + char cmd[ 3 ]; + + cmd[ 0 ] = register_name; + cmd[ 1 ] = value & 0xFF; + cmd[ 2 ] = value >> 8; + + error_code = i2c.write( i2c_addr, cmd, 3 ); + + if ( error_code ) + error( "PCA9629 writing failed\r\n" ); +} + +char PCA9629::read( RegisterName register_name ) { + int error_code; + char cmd; + char data; + + cmd = register_name; + + error_code = i2c.write( i2c_addr, &cmd, 1, false ); + + if ( error_code ) + error( "PCA9629 reading (command phase) failed\r\n" ); + + error_code = i2c.read( i2c_addr, &data, 1 ); + + if ( error_code ) + error( "PCA9629 reading (data phase) failed\r\n" ); + + return ( data ); +} + +short PCA9629::read( Register16bits register_name ) { + int error_code; + char cmd; + char data[ 2 ]; + + cmd = register_name; + + error_code = i2c.write( i2c_addr, &cmd, 1, false ); + + if ( error_code ) + error( "PCA9629 reading (command phase) failed\r\n" ); + + error_code = i2c.read( i2c_addr, data, 2 ); + + if ( error_code ) + error( "PCA9629 reading (data phase) failed\r\n" ); + + return ( data[ 1 ] << 8 | data[ 0 ] ); +} + +void PCA9629::start( Direction dir ) { + write( MCNTL, 0xA8 | dir ); +} + +void PCA9629::stop( void ) { + write( MCNTL, 0x00 ); +} + +short PCA9629::pps( Direction dir, PrescalerRange prescaler, int pps ) { + int step_pulse_width; + + step_pulse_width = STEP_RESOLUTION / ((1 << prescaler) * pps); + + if ( step_pulse_width & 0xE000 ) { //error( "pps setting: out of range" ); + step_pulse_width = 0x1FFF; + printf( "the pps forced in to the range that user specified.. %fpps\r\n", (float)STEP_RESOLUTION / ((float)0x1FFF * (float)(1 << prescaler)) ); + } + if ( !step_pulse_width ) { //error( "pps setting: out of range" ); + step_pulse_width = 0x1; + printf( "the pps forced in to the range that user specified.. %fpps\r\n", (float)STEP_RESOLUTION / (float)(1 << prescaler) ); + } + + step_pulse_width |= (prescaler << 13); + + write( (dir == CW) ? CWPW_ : CCWPW_, step_pulse_width ); + + return ( step_pulse_width ); +} + +void PCA9629::rotations( Direction dir, int rotations ) { + write( (dir == CW) ? CWRCOUNT_ : CCWRCOUNT_, rotations ); +} + +void PCA9629::steps( Direction dir, int steps ) { + write( (dir == CW) ? CWSCOUNT_ : CCWSCOUNT_, steps ); +} + + +void PCA9629::register_dump( void ) { + char data[ 0x27 ]; + char cmd = 0x80; + int i; + int j; + + i2c.write( i2c_addr, &cmd, 1 ); + i2c.read( i2c_addr, data, sizeof( data ) ); + + printf( "PCA9629 register dump\r\n" ); + + for ( i = 0, j = 0x14; i <= 0x12; i++, j++ ) + 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 ] ); + + printf( " %-13s (0x%02X): 0x%02X\r\n", reg_name[ 0x13 ], 0x13, data[ 0x13 ] ); +} + + +void PCA9629::speed_change( unsigned short pw ) { + char cmd0[] = { PCA9629::MCNTL, 0x00}; // data for stop the motor + char cmd1[] = { PCA9629::CW__STEP_WIDTH, pw & 0xFF, pw >> 8 }; // data for rewrite pulse width + char cmd2[] = { PCA9629::MCNTL, 0xB4}; // start // data for start again + wait_us(10); + + i2c.write( i2c_addr, cmd0, sizeof( cmd0 ), true ); // stop the motor + wait_us(50); + i2c.write( i2c_addr, cmd1, sizeof( cmd1 ), true ); // rewrite pulse width + i2c.write( i2c_addr, cmd2, sizeof( cmd2 ), false ); // start again +} + + +