Library for MAX14871 Shield, MAXREFDES89#

Dependencies:   MAX5387 MAX7300

Dependents:   MAXREFDES89_MAX14871_Shield_Demo MAXREFDES89_Test_Program Line_Following_Bot Line_Following_Bot_Pololu

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers max14871_shield.cpp Source File

max14871_shield.cpp

Go to the documentation of this file.
00001 /******************************************************************//**
00002 * @file max14871_shield.cpp
00003 * Copyright (C) 2015 Maxim Integrated Products, Inc., All Rights Reserved.
00004 *
00005 * Permission is hereby granted, free of charge, to any person obtaining a
00006 * copy of this software and associated documentation files (the "Software"),
00007 * to deal in the Software without restriction, including without limitation
00008 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
00009 * and/or sell copies of the Software, and to permit persons to whom the
00010 * Software is furnished to do so, subject to the following conditions:
00011 *
00012 * The above copyright notice and this permission notice shall be included
00013 * in all copies or substantial portions of the Software.
00014 *
00015 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00016 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00017 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00018 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
00019 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00020 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00021 * OTHER DEALINGS IN THE SOFTWARE.
00022 *
00023 * Except as contained in this notice, the name of Maxim Integrated
00024 * Products, Inc. shall not be used except as stated in the Maxim Integrated
00025 * Products, Inc. Branding Policy.
00026 *
00027 * The mere transfer of this software does not imply any licenses
00028 * of trade secrets, proprietary technology, copyrights, patents,
00029 * trademarks, maskwork rights, or any other form of intellectual
00030 * property whatsoever. Maxim Integrated Products, Inc. retains all
00031 * ownership rights.
00032 **********************************************************************/
00033 
00034 
00035 #include "max14871_shield.h"
00036 
00037 #define MIN_PERIOD (0.00002f) //50KHz
00038 
00039 //Motor Driver control inputs
00040 #define MD_EN    (0x01)
00041 #define MD_DIR   (0x02)
00042 #define MD_MODE0 (0x04)
00043 #define MD_MODE1 (0x08)
00044 
00045 #define MAX_VREF (2.0f)
00046 
00047 //GPIO Expander Default Configurations
00048 #define MAX7300_ALL_OUTPUTS    (0x55)
00049 #define MAX7300_ALL_INPUTS     (0xFF)
00050 #define MAX7300_OUTPUT_DEFAULT (0xBB)
00051 
00052 
00053 //*********************************************************************
00054 Max14871_Shield::Max14871_Shield(I2C *i2c_bus, bool default_config): _p_i2c(i2c_bus)
00055 {
00056     _i2c_owner = false;
00057     
00058     if(default_config)
00059     {
00060         _p_io_expander = new Max7300(_p_i2c, Max7300::MAX7300_I2C_ADRS0);
00061         _p_digi_pot1 = new Max5387(_p_i2c, Max5387::MAX5387_I2C_ADRS0);
00062         _p_digi_pot2 = new Max5387(_p_i2c, Max5387::MAX5387_I2C_ADRS1);
00063         
00064         _p_pwm1 = new PwmOut(D4);
00065         _p_pwm2 = new PwmOut(D5);
00066         _p_pwm3 = new PwmOut(D9);
00067         _p_pwm4 = new PwmOut(D10);
00068     }
00069     else
00070     {
00071         _p_io_expander = new Max7300(_p_i2c, Max7300::MAX7300_I2C_ADRS1);
00072         _p_digi_pot1 = new Max5387(_p_i2c, Max5387::MAX5387_I2C_ADRS2);
00073         _p_digi_pot2 = new Max5387(_p_i2c, Max5387::MAX5387_I2C_ADRS3);
00074         
00075         _p_pwm1 = new PwmOut(D3);
00076         _p_pwm2 = new PwmOut(D6);
00077         _p_pwm3 = new PwmOut(D8);
00078         _p_pwm4 = new PwmOut(D11);
00079     }
00080     
00081     init_board();
00082 }
00083 
00084 
00085 //*********************************************************************
00086 Max14871_Shield::Max14871_Shield(PinName sda, PinName scl, bool default_config)
00087 {
00088      _p_i2c = new I2C(sda, scl);
00089     _i2c_owner = true;
00090     
00091     if(default_config)
00092     {
00093         _p_io_expander = new Max7300(_p_i2c, Max7300::MAX7300_I2C_ADRS0);
00094         _p_digi_pot1 = new Max5387(_p_i2c, Max5387::MAX5387_I2C_ADRS0);
00095         _p_digi_pot2 = new Max5387(_p_i2c, Max5387::MAX5387_I2C_ADRS1);
00096         
00097         _p_pwm1 = new PwmOut(D4);
00098         _p_pwm2 = new PwmOut(D5);
00099         _p_pwm3 = new PwmOut(D9);
00100         _p_pwm4 = new PwmOut(D10);
00101     }
00102     else
00103     {
00104         _p_io_expander = new Max7300(_p_i2c, Max7300::MAX7300_I2C_ADRS1);
00105         _p_digi_pot1 = new Max5387(_p_i2c, Max5387::MAX5387_I2C_ADRS2);
00106         _p_digi_pot2 = new Max5387(_p_i2c, Max5387::MAX5387_I2C_ADRS3);
00107         
00108         _p_pwm1 = new PwmOut(D3);
00109         _p_pwm2 = new PwmOut(D6);
00110         _p_pwm3 = new PwmOut(D8);
00111         _p_pwm4 = new PwmOut(D11);
00112     }
00113     
00114     init_board();
00115 }
00116 
00117 
00118 //*********************************************************************
00119 Max14871_Shield::~Max14871_Shield()
00120 {
00121     if(_i2c_owner) 
00122     {
00123         delete _p_i2c;
00124     }
00125     
00126     delete _p_io_expander;
00127     delete _p_digi_pot1;
00128     delete _p_digi_pot2;
00129     delete _p_pwm1;
00130     delete _p_pwm2;
00131     delete _p_pwm3;
00132     delete _p_pwm4;
00133 }
00134 
00135 
00136 //*********************************************************************
00137 int16_t Max14871_Shield::set_operating_mode(max14871_motor_driver_t md, 
00138                                             max14871_operating_mode_t mode)
00139 {
00140     int16_t result = 0;
00141     int16_t port_data;
00142     
00143     Max7300::max7300_port_number_t low_port;
00144     
00145     //determine the low port of an 8 bit register to read/write 
00146     if(md < MD3)
00147     {
00148         low_port = Max7300::MAX7300_PORT_04;
00149     }
00150     else
00151     {
00152         low_port = Max7300::MAX7300_PORT_12;
00153     }
00154     
00155     //get current state of outputs
00156     port_data = _p_io_expander->read_8_ports(low_port);
00157 
00158     switch(mode)
00159     {
00160         //if(md % 2) for following cases, modify control bits
00161         //of odd motor driver
00162 
00163         case COAST:
00164             if(md % 2)
00165             {
00166                 port_data |= MD_EN;
00167             }
00168             else
00169             {
00170                 port_data |= (MD_EN << 4);
00171             }
00172         break;
00173         
00174         case BRAKE:
00175             if(md % 2)
00176             {
00177                 port_data &= ~MD_EN;
00178             }
00179             else
00180             {
00181                 port_data &= ~(MD_EN << 4);
00182             }
00183             
00184             set_pwm_duty_cycle(md, 0.0f);
00185         break;
00186         
00187         case REVERSE:
00188             if(md % 2)
00189             {
00190                 port_data &= ~(MD_EN + MD_DIR);
00191             }
00192             else
00193             {
00194                 port_data &= ~((MD_EN + MD_DIR) << 4);
00195             }
00196         break;
00197         
00198         case FORWARD:
00199             if(md % 2)
00200             {
00201                 port_data &= ~MD_EN;
00202                 port_data |= MD_DIR;
00203             }
00204             else
00205             {
00206                 port_data &= ~(MD_EN << 4);
00207                 port_data |= (MD_DIR << 4);
00208             } 
00209         break;
00210         
00211         default:
00212             result = -1;
00213         break;
00214     }
00215     
00216     if(!result)
00217     {
00218         //write data back to port
00219         result = _p_io_expander->write_8_ports(low_port, (uint8_t) port_data);
00220         
00221         if(!result)
00222         {
00223             _motor_data_array[(md - 1)].op_mode = mode;
00224         }
00225     }
00226 
00227     return result;
00228 }
00229 
00230 
00231 //*********************************************************************
00232 int16_t Max14871_Shield::set_current_regulation_mode (max14871_motor_driver_t md, 
00233                                                      max14871_current_regulation_mode_t mode,
00234                                                      float vref)
00235 {
00236     int16_t result = 0;
00237     int16_t port_data;
00238     uint8_t local_vref = 0;
00239     
00240     Max7300::max7300_port_number_t low_port;
00241     Max5387 *p_digi_pot;
00242     
00243     if(vref > MAX_VREF)
00244     {
00245         vref = MAX_VREF;
00246     }
00247     local_vref = ((uint8_t) ((vref * 255.0f) / 3.3f));
00248     
00249     //determine the low port of an 8 bit register to read/write 
00250     //and digipot associated with motor driver
00251     if(md < MD3)
00252     {
00253         low_port = Max7300::MAX7300_PORT_04;
00254         p_digi_pot = _p_digi_pot1;
00255     }
00256     else
00257     {
00258         low_port = Max7300::MAX7300_PORT_12;
00259         p_digi_pot = _p_digi_pot2;
00260     }
00261     
00262     //get current state of outputs
00263     port_data = _p_io_expander->read_8_ports(low_port);
00264         
00265     switch(mode)
00266     {
00267         case RIPPLE_25_INTERNAL_REF:
00268             if(md % 2)
00269             {
00270                 port_data &= ~MD_MODE0;
00271                 port_data |= MD_MODE1;
00272                 p_digi_pot->write_ch_A(0);
00273             }
00274             else
00275             {
00276                 port_data &= ~(MD_MODE0 << 4);
00277                 port_data |= (MD_MODE1 << 4);
00278                 p_digi_pot->write_ch_B(0);
00279             }
00280         break;
00281         
00282         case RIPPLE_25_EXTERNAL_REF:
00283             if(md % 2)
00284             {
00285                 port_data &= ~MD_MODE0;
00286                 port_data |= MD_MODE1;
00287                 p_digi_pot->write_ch_A(local_vref);
00288             }
00289             else
00290             {
00291                 port_data &= ~(MD_MODE0 << 4);
00292                 port_data |= (MD_MODE1 << 4);
00293                 p_digi_pot->write_ch_B(local_vref);
00294             }
00295         break;
00296         
00297         case TCOFF_FAST_INTERNAL_REF:
00298             if(md % 2)
00299             {
00300                 port_data |= (MD_MODE1 + MD_MODE0);
00301                 p_digi_pot->write_ch_A(0);
00302             }
00303             else
00304             {
00305                 port_data |= ((MD_MODE1 + MD_MODE0) << 4);
00306                 p_digi_pot->write_ch_B(0);
00307             }
00308         break;
00309         
00310         case TCOFF_SLOW_INTERNAL_REF:
00311             if(md % 2)
00312             {
00313                 port_data |= MD_MODE0;
00314                 port_data &= ~MD_MODE1;
00315                 p_digi_pot->write_ch_A(0);
00316             }
00317             else
00318             {
00319                 port_data |= (MD_MODE0 << 4);
00320                 port_data &= ~(MD_MODE1 << 4);
00321                 p_digi_pot->write_ch_B(0);
00322             }
00323         break;
00324         
00325         case TCOFF_FAST_EXTERNAL_REF:
00326             if(md % 2)
00327             {
00328                 port_data |= (MD_MODE1 + MD_MODE0);
00329                 p_digi_pot->write_ch_A(local_vref);
00330             }
00331             else
00332             {
00333                 port_data |= ((MD_MODE1 + MD_MODE0) << 4);
00334                 p_digi_pot->write_ch_B(local_vref);
00335             }
00336         break;
00337         
00338         case TCOFF_SLOW_EXTERNAL_REF:
00339             if(md % 2)
00340             {
00341                 port_data |= MD_MODE0;
00342                 port_data &= ~MD_MODE1;
00343                 p_digi_pot->write_ch_A(local_vref);
00344             }
00345             else
00346             {
00347                 port_data |= (MD_MODE0 << 4);
00348                 port_data &= ~(MD_MODE1 << 4);
00349                 p_digi_pot->write_ch_B(local_vref);
00350             }
00351         break;
00352         
00353         default:
00354             result = -1;
00355         break;
00356     }
00357     
00358     if(!result)
00359     {
00360         //write data back to port
00361         result = _p_io_expander->write_8_ports(low_port, (uint8_t) port_data);
00362         
00363         if(!result)
00364         {
00365             _motor_data_array[(md - 1)].i_reg_mode = mode;
00366             _motor_data_array[(md - 1)].v_ref = vref;
00367         }
00368     }
00369     
00370     return result;
00371 }
00372 
00373 
00374 //*********************************************************************
00375 int16_t Max14871_Shield::set_pwm_channel(max14871_motor_driver_t md, PinName ch)
00376 {
00377     
00378     int16_t result = 0;
00379     float pwm_duty_cycle;
00380     float pwm_period;
00381     
00382     
00383     if((ch != D3) && (ch != D4) && (ch != D5) && (ch != D6) &&
00384        (ch != D8) && (ch != D9) && (ch != D10) && (ch != D11))
00385     {
00386         result = -1;
00387     }
00388     else
00389     {        
00390         switch(md)
00391         {
00392             case MD1:
00393                 if((ch != D3) && (ch != D4))
00394                 {
00395                     result = -1;
00396                 }
00397                 else
00398                 {
00399                     pwm_duty_cycle = get_pwm_duty_cycle(md);
00400                     pwm_period = get_pwm_period(md);
00401                     
00402                     _p_pwm1->pulsewidth_us(0);
00403                     
00404                     delete _p_pwm1;
00405                     _p_pwm1 = new PwmOut(ch);
00406                     
00407                     set_pwm_period(md, pwm_period);
00408                     set_pwm_duty_cycle(md, pwm_duty_cycle);
00409                 }
00410             break;
00411             
00412             case MD2:
00413                 if((ch != D5) && (ch != D6))
00414                 {
00415                     result = -1;
00416                 }
00417                 else
00418                 {
00419                     pwm_duty_cycle = get_pwm_duty_cycle(md);
00420                     pwm_period = get_pwm_period(md);
00421                     
00422                     _p_pwm2->pulsewidth_us(0);
00423                     
00424                     delete _p_pwm2;
00425                     _p_pwm2 = new PwmOut(ch);
00426                     
00427                     set_pwm_period(md, pwm_period);
00428                     set_pwm_duty_cycle(md, pwm_duty_cycle);
00429                 }
00430             break;
00431             
00432             case MD3:
00433                 if((ch != D8) && (ch != D9))
00434                 {
00435                     result = -1;
00436                 }
00437                 else
00438                 {
00439                     pwm_duty_cycle = get_pwm_duty_cycle(md);
00440                     pwm_period = get_pwm_period(md);
00441                     
00442                     _p_pwm3->pulsewidth_us(0);
00443                     
00444                     delete _p_pwm3;
00445                     _p_pwm3 = new PwmOut(ch);
00446                     
00447                     set_pwm_period(md, pwm_period);
00448                     set_pwm_duty_cycle(md, pwm_duty_cycle);
00449                 }
00450             break;
00451             
00452             case MD4:
00453                 if((ch != D10) && (ch != D11))
00454                 {
00455                     result = -1;
00456                 }
00457                 else
00458                 {
00459                     pwm_duty_cycle = get_pwm_duty_cycle(md);
00460                     pwm_period = get_pwm_period(md);
00461                     
00462                     _p_pwm4->pulsewidth_us(0);
00463                     
00464                     delete _p_pwm4;
00465                     _p_pwm4 = new PwmOut(ch);
00466                     
00467                     set_pwm_period(md, pwm_period);
00468                     set_pwm_duty_cycle(md, pwm_duty_cycle);
00469                 }
00470             break;
00471             
00472             default:
00473                 result = -1;
00474             break;
00475         }
00476     }
00477     
00478     return result;
00479 }
00480 
00481 
00482 //*********************************************************************
00483 int16_t Max14871_Shield::set_pwm_period(max14871_motor_driver_t md, float period)
00484 {
00485     int16_t result = 0;
00486     
00487     if(period < MIN_PERIOD)
00488     {
00489         result = -1;
00490     }
00491     else
00492     {
00493         switch(md)
00494         {
00495             case MD1:
00496                 _p_pwm1->period(period);
00497                 _motor_data_array[(md - 1)].period = period;
00498             break;
00499             
00500             case MD2:
00501                 _p_pwm2->period(period);
00502                 _motor_data_array[(md - 1)].period = period;
00503             break;
00504             
00505             case MD3:
00506                 _p_pwm3->period(period);
00507                 _motor_data_array[(md - 1)].period = period;
00508             break;
00509             
00510             case MD4:
00511                 _p_pwm4->period(period);
00512                 _motor_data_array[(md - 1)].period = period;
00513             break;
00514             
00515             default:
00516                 result = -1;
00517             break;
00518         }
00519     }
00520     
00521     return result;
00522 }
00523 
00524 
00525 //*********************************************************************
00526 int16_t Max14871_Shield::set_pwm_duty_cycle(max14871_motor_driver_t md, float duty_cycle)
00527 {
00528     int16_t result = 0;
00529     
00530     switch(md)
00531     {
00532         case MD1:
00533             _p_pwm1->write(duty_cycle);
00534             _motor_data_array[(md - 1)].duty_cycle = duty_cycle;
00535         break;
00536         
00537         case MD2:
00538             _p_pwm2->write(duty_cycle);
00539             _motor_data_array[(md - 1)].duty_cycle = duty_cycle;
00540         break;
00541         
00542         case MD3:
00543             _p_pwm3->write(duty_cycle);
00544             _motor_data_array[(md - 1)].duty_cycle = duty_cycle;
00545         break;
00546         
00547         case MD4:
00548             _p_pwm4->write(duty_cycle);
00549             _motor_data_array[(md - 1)].duty_cycle = duty_cycle;
00550         break;
00551         
00552         default:
00553             result = -1;
00554         break;
00555     }
00556     
00557     return result;
00558 }
00559 
00560 
00561 //*********************************************************************
00562 Max14871_Shield::max14871_operating_mode_t Max14871_Shield::get_operating_mode(max14871_motor_driver_t md)
00563 {
00564     return(_motor_data_array[(md - 1)].op_mode);
00565 }
00566 
00567 
00568 //*********************************************************************
00569 Max14871_Shield::max14871_current_regulation_mode_t Max14871_Shield::get_current_regulation_mode(max14871_motor_driver_t md)
00570 {
00571     return(_motor_data_array[(md - 1)].i_reg_mode);
00572 }
00573 
00574 
00575 //*********************************************************************
00576 float Max14871_Shield::get_pwm_duty_cycle(max14871_motor_driver_t md)
00577 {
00578     return(_motor_data_array[(md - 1)].duty_cycle);
00579 }
00580 
00581 
00582 //*********************************************************************
00583 float Max14871_Shield::get_pwm_period(max14871_motor_driver_t md)
00584 {
00585     return(_motor_data_array[(md - 1)].period);
00586 }
00587 
00588 
00589 //*********************************************************************
00590 float Max14871_Shield::get_external_voltage_ref(max14871_motor_driver_t md)
00591 {
00592     return(_motor_data_array[(md - 1)].v_ref);
00593 }
00594       
00595 
00596 //*********************************************************************
00597 void Max14871_Shield::init_board(void)
00598 {
00599     //configure these ports as outputs
00600     _p_io_expander->config_4_ports(Max7300::MAX7300_PORT_04, MAX7300_ALL_OUTPUTS);
00601     _p_io_expander->config_4_ports(Max7300::MAX7300_PORT_08, MAX7300_ALL_OUTPUTS);
00602     _p_io_expander->config_4_ports(Max7300::MAX7300_PORT_12, MAX7300_ALL_OUTPUTS);
00603     _p_io_expander->config_4_ports(Max7300::MAX7300_PORT_16, MAX7300_ALL_OUTPUTS);
00604     
00605     //Set /EN and DIR pin of all motor drivers and set mode pin 
00606     //of all motor drivers to 0.75V
00607     _p_io_expander->write_8_ports(Max7300::MAX7300_PORT_04, MAX7300_OUTPUT_DEFAULT);
00608     _p_io_expander->write_8_ports(Max7300::MAX7300_PORT_12, MAX7300_OUTPUT_DEFAULT);
00609     
00610     //configure these ports as inputs w/pull-up, 
00611     _p_io_expander->config_4_ports(Max7300::MAX7300_PORT_20, MAX7300_ALL_INPUTS);
00612     _p_io_expander->config_4_ports(Max7300::MAX7300_PORT_24, MAX7300_ALL_INPUTS);
00613     _p_io_expander->config_4_ports(Max7300::MAX7300_PORT_28, MAX7300_ALL_INPUTS);
00614     
00615     //config port 31 as output for interrupt
00616     _p_io_expander->config_port(Max7300::MAX7300_PORT_31, Max7300::MAX7300_PORT_OUTPUT);
00617     
00618     _p_io_expander->enable_transition_detection();
00619     _p_io_expander->enable_ports();
00620     
00621     //set Vref pin of all motor drivers to 0V, 
00622     //internal vref used for current regulation
00623     _p_digi_pot1->write_ch_AB(0);
00624     _p_digi_pot2->write_ch_AB(0);
00625     
00626     //set switching frequency of all motor drivers to 50KHz
00627     _p_pwm1->period(MIN_PERIOD);  
00628     _p_pwm2->period(MIN_PERIOD);
00629     _p_pwm3->period(MIN_PERIOD);
00630     _p_pwm4->period(MIN_PERIOD);
00631     
00632     //init motor data to defaults
00633     for(uint8_t idx = 0; idx < 4; idx++)
00634     {
00635         _motor_data_array[idx].op_mode = COAST;
00636         _motor_data_array[idx].i_reg_mode = RIPPLE_25_INTERNAL_REF;
00637         _motor_data_array[idx].duty_cycle = 0.0f;
00638         _motor_data_array[idx].period = MIN_PERIOD;
00639         _motor_data_array[idx].v_ref = 0.0f;
00640     }
00641 }