Library for MAX14871 Shield, MAXREFDES89#
Dependents: MAXREFDES89_MAX14871_Shield_Demo MAXREFDES89_Test_Program Line_Following_Bot Line_Following_Bot_Pololu
max14871_shield.cpp
- Committer:
- j3
- Date:
- 2016-05-13
- Revision:
- 6:dc06cc75c1c8
- Parent:
- 5:a206f6505109
- Child:
- 7:c0bee1397f3e
File content as of revision 6:dc06cc75c1c8:
/******************************************************************//** * @file max14871_shield.cpp * Copyright (C) 2015 Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Except as contained in this notice, the name of Maxim Integrated * Products, Inc. shall not be used except as stated in the Maxim Integrated * Products, Inc. Branding Policy. * * The mere transfer of this software does not imply any licenses * of trade secrets, proprietary technology, copyrights, patents, * trademarks, maskwork rights, or any other form of intellectual * property whatsoever. Maxim Integrated Products, Inc. retains all * ownership rights. **********************************************************************/ #include "max14871_shield.h" #define MIN_PERIOD (0.00002f) //50KHz //Motor Driver control inputs #define MD_EN (0x01) #define MD_DIR (0x02) #define MD_MODE0 (0x04) #define MD_MODE1 (0x08) #define MAX_VREF (2.0f) //GPIO Expander Default Configurations #define MAX7300_ALL_OUTPUTS (0x55) #define MAX7300_ALL_INPUTS (0xFF) #define MAX7300_OUTPUT_DEFAULT (0xBB) //********************************************************************* Max14871_Shield::Max14871_Shield(I2C *i2c_bus, bool default_config): _p_i2c(i2c_bus) { _i2c_owner = false; if(default_config) { _p_io_expander = new Max7300(_p_i2c, Max7300::MAX7300_I2C_ADRS0); _p_digi_pot1 = new Max5387(_p_i2c, Max5387::MAX5387_I2C_ADRS0); _p_digi_pot2 = new Max5387(_p_i2c, Max5387::MAX5387_I2C_ADRS1); _p_pwm1 = new PwmOut(D4); _p_pwm2 = new PwmOut(D5); _p_pwm3 = new PwmOut(D9); _p_pwm4 = new PwmOut(D10); } else { _p_io_expander = new Max7300(_p_i2c, Max7300::MAX7300_I2C_ADRS1); _p_digi_pot1 = new Max5387(_p_i2c, Max5387::MAX5387_I2C_ADRS2); _p_digi_pot2 = new Max5387(_p_i2c, Max5387::MAX5387_I2C_ADRS3); _p_pwm1 = new PwmOut(D3); _p_pwm2 = new PwmOut(D6); _p_pwm3 = new PwmOut(D8); _p_pwm4 = new PwmOut(D11); } init_board(); } //********************************************************************* Max14871_Shield::Max14871_Shield(PinName sda, PinName scl, bool default_config) { _p_i2c = new I2C(sda, scl); _i2c_owner = true; if(default_config) { _p_io_expander = new Max7300(_p_i2c, Max7300::MAX7300_I2C_ADRS0); _p_digi_pot1 = new Max5387(_p_i2c, Max5387::MAX5387_I2C_ADRS0); _p_digi_pot2 = new Max5387(_p_i2c, Max5387::MAX5387_I2C_ADRS1); _p_pwm1 = new PwmOut(D4); _p_pwm2 = new PwmOut(D5); _p_pwm3 = new PwmOut(D9); _p_pwm4 = new PwmOut(D10); } else { _p_io_expander = new Max7300(_p_i2c, Max7300::MAX7300_I2C_ADRS1); _p_digi_pot1 = new Max5387(_p_i2c, Max5387::MAX5387_I2C_ADRS2); _p_digi_pot2 = new Max5387(_p_i2c, Max5387::MAX5387_I2C_ADRS3); _p_pwm1 = new PwmOut(D3); _p_pwm2 = new PwmOut(D6); _p_pwm3 = new PwmOut(D8); _p_pwm4 = new PwmOut(D11); } init_board(); } //********************************************************************* Max14871_Shield::~Max14871_Shield() { if(_i2c_owner) { delete _p_i2c; } delete _p_io_expander; delete _p_digi_pot1; delete _p_digi_pot2; delete _p_pwm1; delete _p_pwm2; delete _p_pwm3; delete _p_pwm4; } //********************************************************************* int16_t Max14871_Shield::set_operating_mode(max14871_motor_driver_t md, max14871_operating_mode_t mode) { int16_t result = 0; int16_t port_data; Max7300::max7300_port_number_t low_port; //determine the low port of an 8 bit register to read/write if(md < MD3) { low_port = Max7300::MAX7300_PORT_04; } else { low_port = Max7300::MAX7300_PORT_12; } //get current state of outputs port_data = _p_io_expander->read_8_ports(low_port); switch(mode) { //if(md % 2) for following cases, modify control bits //of odd motor driver case COAST: if(md % 2) { port_data |= MD_EN; } else { port_data |= (MD_EN << 4); } set_pwm_duty_cycle(md, 0.0f); break; case BRAKE: if(md % 2) { port_data &= ~MD_EN; } else { port_data &= ~(MD_EN << 4); } set_pwm_duty_cycle(md, 0.0f); break; case REVERSE: if(md % 2) { port_data &= ~(MD_EN + MD_DIR); } else { port_data &= ~((MD_EN + MD_DIR) << 4); } break; case FORWARD: if(md % 2) { port_data &= ~MD_EN; port_data |= MD_DIR; } else { port_data &= ~(MD_EN << 4); port_data |= (MD_DIR << 4); } break; default: result = -1; break; } if(!result) { //write data back to port result = _p_io_expander->write_8_ports(low_port, (uint8_t) port_data); if(!result) { _motor_data_array[(md - 1)].op_mode = mode; } } return result; } //********************************************************************* int16_t Max14871_Shield::set_current_regulation_mode(max14871_motor_driver_t md, max14871_current_regulation_mode_t mode, float vref) { int16_t result = 0; int16_t port_data; uint8_t local_vref = 0; Max7300::max7300_port_number_t low_port; Max5387 *p_digi_pot; if(vref > MAX_VREF) { vref = MAX_VREF; } local_vref = ((uint8_t) ((vref * 255.0f) / 3.3f)); //determine the low port of an 8 bit register to read/write //and digipot associated with motor driver if(md < MD3) { low_port = Max7300::MAX7300_PORT_04; p_digi_pot = _p_digi_pot1; } else { low_port = Max7300::MAX7300_PORT_12; p_digi_pot = _p_digi_pot2; } //get current state of outputs port_data = _p_io_expander->read_8_ports(low_port); switch(mode) { case RIPPLE_25_INTERNAL_REF: if(md % 2) { port_data &= ~MD_MODE0; port_data |= MD_MODE1; p_digi_pot->write_ch_A(0); } else { port_data &= ~(MD_MODE0 << 4); port_data |= (MD_MODE1 << 4); p_digi_pot->write_ch_B(0); } break; case RIPPLE_25_EXTERNAL_REF: if(md % 2) { port_data &= ~MD_MODE0; port_data |= MD_MODE1; p_digi_pot->write_ch_A(local_vref); } else { port_data &= ~(MD_MODE0 << 4); port_data |= (MD_MODE1 << 4); p_digi_pot->write_ch_B(local_vref); } break; case TCOFF_FAST_INTERNAL_REF: if(md % 2) { port_data |= (MD_MODE1 + MD_MODE0); p_digi_pot->write_ch_A(0); } else { port_data |= ((MD_MODE1 + MD_MODE0) << 4); p_digi_pot->write_ch_B(0); } break; case TCOFF_SLOW_INTERNAL_REF: if(md % 2) { port_data |= MD_MODE0; port_data &= ~MD_MODE1; p_digi_pot->write_ch_A(0); } else { port_data |= (MD_MODE0 << 4); port_data &= ~(MD_MODE1 << 4); p_digi_pot->write_ch_B(0); } break; case TCOFF_FAST_EXTERNAL_REF: if(md % 2) { port_data |= (MD_MODE1 + MD_MODE0); p_digi_pot->write_ch_A(local_vref); } else { port_data |= ((MD_MODE1 + MD_MODE0) << 4); p_digi_pot->write_ch_B(local_vref); } break; case TCOFF_SLOW_EXTERNAL_REF: if(md % 2) { port_data |= MD_MODE0; port_data &= ~MD_MODE1; p_digi_pot->write_ch_A(local_vref); } else { port_data |= (MD_MODE0 << 4); port_data &= ~(MD_MODE1 << 4); p_digi_pot->write_ch_B(local_vref); } break; default: result = -1; break; } if(!result) { //write data back to port result = _p_io_expander->write_8_ports(low_port, (uint8_t) port_data); if(!result) { _motor_data_array[(md - 1)].i_reg_mode = mode; _motor_data_array[(md - 1)].v_ref = vref; } } return result; } //********************************************************************* int16_t Max14871_Shield::set_pwm_channel(max14871_motor_driver_t md, PinName ch) { int16_t result = 0; float pwm_duty_cycle; float pwm_period; if((ch != D3) && (ch != D4) && (ch != D5) && (ch != D6) && (ch != D8) && (ch != D9) && (ch != D10) && (ch != D11)) { result = -1; } else { switch(md) { case MD1: if((ch != D3) && (ch != D4)) { result = -1; } else { pwm_duty_cycle = get_pwm_duty_cycle(md); pwm_period = get_pwm_period(md); _p_pwm1->pulsewidth_us(0); delete _p_pwm1; _p_pwm1 = new PwmOut(ch); set_pwm_period(md, pwm_period); set_pwm_duty_cycle(md, pwm_duty_cycle); } break; case MD2: if((ch != D5) && (ch != D6)) { result = -1; } else { pwm_duty_cycle = get_pwm_duty_cycle(md); pwm_period = get_pwm_period(md); _p_pwm2->pulsewidth_us(0); delete _p_pwm2; _p_pwm2 = new PwmOut(ch); set_pwm_period(md, pwm_period); set_pwm_duty_cycle(md, pwm_duty_cycle); } break; case MD3: if((ch != D8) && (ch != D9)) { result = -1; } else { pwm_duty_cycle = get_pwm_duty_cycle(md); pwm_period = get_pwm_period(md); _p_pwm3->pulsewidth_us(0); delete _p_pwm3; _p_pwm3 = new PwmOut(ch); set_pwm_period(md, pwm_period); set_pwm_duty_cycle(md, pwm_duty_cycle); } break; case MD4: if((ch != D10) && (ch != D11)) { result = -1; } else { pwm_duty_cycle = get_pwm_duty_cycle(md); pwm_period = get_pwm_period(md); _p_pwm4->pulsewidth_us(0); delete _p_pwm4; _p_pwm4 = new PwmOut(ch); set_pwm_period(md, pwm_period); set_pwm_duty_cycle(md, pwm_duty_cycle); } break; default: result = -1; break; } } return result; } //********************************************************************* int16_t Max14871_Shield::set_pwm_period(max14871_motor_driver_t md, float period) { int16_t result = 0; if(period < MIN_PERIOD) { result = -1; } else { switch(md) { case MD1: _p_pwm1->period(period); _motor_data_array[(md - 1)].period = period; break; case MD2: _p_pwm2->period(period); _motor_data_array[(md - 1)].period = period; break; case MD3: _p_pwm3->period(period); _motor_data_array[(md - 1)].period = period; break; case MD4: _p_pwm4->period(period); _motor_data_array[(md - 1)].period = period; break; default: result = -1; break; } } return result; } //********************************************************************* int16_t Max14871_Shield::set_pwm_duty_cycle(max14871_motor_driver_t md, float duty_cycle) { int16_t result = 0; switch(md) { case MD1: _p_pwm1->write(duty_cycle); _motor_data_array[(md - 1)].duty_cycle = duty_cycle; break; case MD2: _p_pwm2->write(duty_cycle); _motor_data_array[(md - 1)].duty_cycle = duty_cycle; break; case MD3: _p_pwm3->write(duty_cycle); _motor_data_array[(md - 1)].duty_cycle = duty_cycle; break; case MD4: _p_pwm4->write(duty_cycle); _motor_data_array[(md - 1)].duty_cycle = duty_cycle; break; default: result = -1; break; } return result; } //********************************************************************* Max14871_Shield::max14871_operating_mode_t Max14871_Shield::get_operating_mode(max14871_motor_driver_t md) { return(_motor_data_array[(md - 1)].op_mode); } //********************************************************************* Max14871_Shield::max14871_current_regulation_mode_t Max14871_Shield::get_current_regulation_mode(max14871_motor_driver_t md) { return(_motor_data_array[(md - 1)].i_reg_mode); } //********************************************************************* float Max14871_Shield::get_pwm_duty_cycle(max14871_motor_driver_t md) { return(_motor_data_array[(md - 1)].duty_cycle); } //********************************************************************* float Max14871_Shield::get_pwm_period(max14871_motor_driver_t md) { return(_motor_data_array[(md - 1)].period); } //********************************************************************* float Max14871_Shield::get_external_voltage_ref(max14871_motor_driver_t md) { return(_motor_data_array[(md - 1)].v_ref); } //********************************************************************* void Max14871_Shield::init_board(void) { //configure these ports as outputs _p_io_expander->config_4_ports(Max7300::MAX7300_PORT_04, MAX7300_ALL_OUTPUTS); _p_io_expander->config_4_ports(Max7300::MAX7300_PORT_08, MAX7300_ALL_OUTPUTS); _p_io_expander->config_4_ports(Max7300::MAX7300_PORT_12, MAX7300_ALL_OUTPUTS); _p_io_expander->config_4_ports(Max7300::MAX7300_PORT_16, MAX7300_ALL_OUTPUTS); //Set /EN and DIR pin of all motor drivers and set mode pin //of all motor drivers to 0.75V _p_io_expander->write_8_ports(Max7300::MAX7300_PORT_04, MAX7300_OUTPUT_DEFAULT); _p_io_expander->write_8_ports(Max7300::MAX7300_PORT_12, MAX7300_OUTPUT_DEFAULT); //configure these ports as inputs w/pull-up, _p_io_expander->config_4_ports(Max7300::MAX7300_PORT_20, MAX7300_ALL_INPUTS); _p_io_expander->config_4_ports(Max7300::MAX7300_PORT_24, MAX7300_ALL_INPUTS); _p_io_expander->config_4_ports(Max7300::MAX7300_PORT_28, MAX7300_ALL_INPUTS); //config port 31 as output for interrupt _p_io_expander->config_port(Max7300::MAX7300_PORT_31, Max7300::MAX7300_PORT_OUTPUT); _p_io_expander->enable_transition_detection(); _p_io_expander->enable_ports(); //set Vref pin of all motor drivers to 0V, //internal vref used for current regulation _p_digi_pot1->write_ch_AB(0); _p_digi_pot2->write_ch_AB(0); //set switching frequency of all motor drivers to 50KHz _p_pwm1->period(MIN_PERIOD); _p_pwm2->period(MIN_PERIOD); _p_pwm3->period(MIN_PERIOD); _p_pwm4->period(MIN_PERIOD); //init motor data to defaults for(uint8_t idx = 0; idx < 4; idx++) { _motor_data_array[idx].op_mode = COAST; _motor_data_array[idx].i_reg_mode = RIPPLE_25_INTERNAL_REF; _motor_data_array[idx].duty_cycle = 0.0f; _motor_data_array[idx].period = MIN_PERIOD; _motor_data_array[idx].v_ref = 0.0f; } }