Library for MAX14871 Shield, MAXREFDES89#
Dependents: MAXREFDES89_MAX14871_Shield_Demo MAXREFDES89_Test_Program Line_Following_Bot Line_Following_Bot_Pololu
max14871_shield.cpp
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 }
Generated on Thu Jul 14 2022 04:04:30 by 1.7.2