Jon Freeman / Mbed 2 deprecated Brushless_STM3_ESC_2019_10

Dependencies:   mbed BufferedSerial Servo PCT2075 FastPWM

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers 24LC64_eeprom.cpp Source File

24LC64_eeprom.cpp

00001 #include "mbed.h"
00002 #include "STM3_ESC.h"
00003 #include "BufferedSerial.h"
00004 extern  BufferedSerial pc;
00005 extern  error_handling_Jan_2019     ESC_Error    ;         //  Provides array usable to store error codes.
00006     //  Code for 24LC64 8k x 8 bit eeprom
00007     //  Code based on earlier work using memory FM24W256, also at i2c address 0xa0;
00008 
00009 const int   addr_rd = 0xa1;  //  set bit 0 for read, clear bit 0 for write 24LC64
00010 const int   addr_wr = 0xa0;  //  set bit 0 for read, clear bit 0 for write 24LC64
00011 const int   ACK     = 1;
00012 /*struct  optpar  {
00013     int     min, max, de_fault;  //  min, max, default
00014     const char * txt;     //  description
00015 }   ;
00016 */
00017 struct  optpar option_list[] = {
00018     {0, 1, 1,     "MotorA direction [0 or 1]"},       //  MOTADIR
00019     {0, 1, 0,     "MotorB direction [0 or 1]"},       //  MOTBDIR
00020     {4, 8, 8,     "MotorA poles 4 or 6 or 8"},      //  MOTAPOLES
00021     {4, 8, 8,     "MotorB poles 4 or 6 or 8"},      //  MOTBPOLES
00022     {1, 4, 1,     "MotorA 0R05 shunt Rs 1 to 4"},        //  ISHUNTB
00023     {1, 4, 1,     "MotorB 0R05 shunt Rs 1 to 4"},        //  ISHUNTB
00024     {10, 50, 20,  "POT_REGBRAKE_RANGE percentage 10 to 50"},     //  POT_REGBRAKE_RANGE
00025     {0, 1, 0,     "Servo1 out 0 = Disabled, 1= Output enabled"},        //  SVO1
00026     {0, 1, 0,     "Servo2 out 0 = Disabled, 1= Output enabled"},        //  SVO2
00027     {0, 2, 0,     "RC Input1 0 = Not used, 1= Uni_dir, 2= Bi_dir"},     //  RCIN1
00028     {0, 2, 0,     "RC Input2 0 = Not used, 1= Uni_dir, 2= Bi_dir"},     //  RCIN2
00029     {2, 6, 2,     "Command source 2= COM2 (Touch Screen), 3= Pot, 4= RCIn1, 5= RCIn2, 6=RCin_both"},     //  COMM_SRC
00030     {'1', '9', '0',     "Alternative ID ascii '1' to '9'"}, //  BOARD_ID    defaults to '0' before eerom setup for first time
00031     {10, 250, 60,       "Top speed MPH, range 1.0 to 25.0"},    //  New Jan 2019 TOP_SPEED
00032     {50, 253, 98,       "Wheel diameter mm"},   //  New 01/06/2018
00033     {10, 253, 27,       "Motor pinion"},   //  New 01/06/2018
00034     {50, 253, 85,       "Wheel gear"},   //  New 01/06/2018     ** NOTE this and above two used to calculate RPM to MPH **
00035     {0, 255, 12,     "RC in 1 trim"},    //  New Dec 2019 RCI1_TRIM read as 2's complement (-128 to +127), user enters -128 to +127
00036     {0, 255, 12,     "RC in 2 trim"},    //  New Dec 2019 RCI2_TRIM read as 2's complement (-128 to +127), user enters -128 to +127
00037     {10, 50, 20,     "RCIN_REGBRAKE_RANGE stick range percent 10 to 50"},     //  RCIN_REGBRAKE_RANGE
00038     {10, 90, 50,     "RCIN_STICK_ATTACK rate percent 10 to 90"},     //  RCIN_STICK_ATTACK
00039     {0, 1, 0,     "RCIN1 direction swap 0 normal, 1 reverse"},     //  RCIN1REVERSE
00040     {0, 1, 0,     "RCIN2 direction swap 0 normal, 1 reverse"},     //  RCIN2REVERSE
00041     {11, 63, 48,    "Nominal system voltage, used to calculate current scaling"},    //   NOM_SYSTEM_VOLTS
00042     {5, 91, 90,    "Brake Effectiveness percentage"},
00043     {1, 5, 1,       "Baud rate, [1=9k6, 2=19k2, 3=38k4, 4=78k6, 5=115k2] = "},   //  BAUD 1=9k6, 2=19k2, 3=38k4, 4=78k6, 5=115k2
00044     {0, 100, 0,     "Future 11"},
00045     {0, 100, 0,     "Future 12"},
00046     {0, 100, 0,     "Future 13"},
00047     {0, 100, 0,     "Future 14"},
00048     {0, 100, 0,     "Future 15"},
00049     {0, 100, 0,     "Future 16"},
00050 }   ;
00051 
00052 const   int    numof_eeprom_options    = sizeof(option_list) / sizeof (struct optpar);
00053 
00054 
00055 
00056 
00057 /*
00058 class   eeprom_settings {
00059     I2C i2c;
00060     uint32_t    errors;
00061     uint32_t    i2c_device_count;
00062     uint32_t    i2c_device_list[12];    //  max 12 i2c devices
00063     char        settings    [36];
00064     double      rpm2mphdbl, user_brake_rangedbl, Vnomdbl;
00065     bool        rd_24LC64  (uint32_t start_addr, char * dest, uint32_t length)    ;
00066     bool        wr_24LC64  (uint32_t start_addr, char * dest, uint32_t length)    ;
00067     bool        set_24LC64_internal_address (int    start_addr) ;
00068     bool        ack_poll    ()  ;
00069   public:
00070     eeprom_settings (PinName sda, PinName scl); //  Constructor
00071     bool        do_we_have_i2c  (uint32_t x)    ;
00072     char        rd  (uint32_t)  ;           //  Read one setup char value from private buffer 'settings'
00073     bool        wr  (char, uint32_t)  ;     //  Write one setup char value to private buffer 'settings'
00074     bool        save    ()  ;               //  Write 'settings' buffer to EEPROM
00075     bool        set_defaults    ();         //  Put default settings into EEPROM and local buffer
00076     uint32_t    errs    ()  ;               //  Return errors
00077     const char *      t   (uint32_t);
00078     int         min (uint32_t)   ;
00079     int         max (uint32_t)   ;
00080     int         def (uint32_t)   ;
00081     bool        in_range   (char val, uint32_t p)  ;
00082     void        edit   (double * dbl, uint32_t numof_dbls)    ;
00083     double      user_brake_range ()  ;
00084     double      top_speed ()  ;
00085     double      rpm2mph ()  ;
00086     double      rpm2mph (double)  ;
00087 }   ;
00088 */
00089 
00090 uint32_t    eeprom_settings::baud    ()  {
00091     const   uint32_t    brates[] = {0, 9600, 19200, 38400, 76800, 11520};
00092     return  brates[settings[BAUD]];
00093 }
00094 
00095 double      eeprom_settings::top_speed ()  {
00096     return  top_speeddbl;
00097 }
00098 
00099 double  eeprom_settings::brake_effectiveness    ()  {
00100     return  brake_eff;
00101 }
00102 
00103 double  eeprom_settings::user_brake_range    ()  {
00104     return  user_brake_rangedbl;
00105 }
00106 
00107 double  eeprom_settings::Vnom    ()  {
00108     return  Vnomdbl;
00109 }
00110 
00111 double  eeprom_settings::rpm2mph    ()  {
00112     return  rpm2mphdbl;
00113 }
00114 
00115 double  eeprom_settings::rpm2mph    (double rpm)  {
00116     return  rpm2mphdbl * rpm;
00117 }
00118 
00119 void    eeprom_settings::edit   (double * dbl, uint32_t numof_dbls)    {
00120 extern  void    set_RCIN_offsets    ()  ;
00121     const char* labs[3] = {"Disabled","Uni_directional","Bi_directional"};
00122     char    temps[MAX_CLI_PARAMS+1];  //  max num of parameters entered from pc terminal
00123     uint32_t i;
00124     double  user_scratch;
00125     double  topspeed;   //  New Jan 2019 - set max loco speed
00126     pc.printf   ("\r\nus - User Settings data in EEPROM\r\nSyntax 'us' with no parameters lists current state.\r\n");
00127     if  (numof_dbls > 0)  {           //  If more than 0 parameters supplied
00128         if  (numof_dbls > MAX_CLI_PARAMS)
00129             numof_dbls = MAX_CLI_PARAMS;
00130         for (i = 0; i < numof_dbls; i++)
00131             temps[i] = (char)dbl[i];          //  recast doubles to char
00132         while   (MAX_CLI_PARAMS > i)
00133             temps[i++] = 0;
00134         i = temps[0];
00135         switch  (i) {   //  First number read from user response after "mode"
00136             case    11:      //  MotorA_dir [0 or 1], MotorB_dir [0 or 1]
00137                 wr(temps[1], MOTADIR);
00138                 wr(temps[2], MOTBDIR);
00139                 break;
00140             case    12:      //  MotorA_poles [4,6,8], MotorB_poles [4,6,8]
00141                 if  (temps[1] == 4 || temps[1] == 6 || temps[1] == 8)
00142                     wr(temps[1], MOTAPOLES);
00143                 if  (temps[2] == 4 || temps[2] == 6 || temps[2] == 8)
00144                     wr(temps[2], MOTBPOLES);
00145                 break;
00146             case    13:      //  MotorA_ current sense resistors [1 to 4], MotorB_ current sense resistors [1 to 4]
00147                 wr(temps[1], ISHUNTA);     //  Corrected since published
00148                 wr(temps[2], ISHUNTB);
00149                 break;
00150             case    14:
00151                 wr(temps[1], BRAKE_EFFECTIVENESS);
00152                 break;
00153             case    15:
00154                 pc.printf   ("POT_REGBRAKE_RANGE value entered = %d\r\n", temps[1]);
00155                 if  (!in_range(temps[1], POT_REGBRAKE_RANGE))
00156                     temps[1] = def(POT_REGBRAKE_RANGE);
00157                 wr    (temps[1], POT_REGBRAKE_RANGE);
00158                 break;
00159             case    16:      //  2 Servo1 [0 or 1], Servo2 [0 or 1]
00160                 wr(temps[1], SVO1);
00161                 wr(temps[2], SVO2);
00162                 break;
00163             case    17:      //  3 RCIn1 [0 or 1], RCIn2 [0 or 1]
00164                 wr(temps[1], RCIN1);
00165                 wr(temps[2], RCIN2);
00166                 break;
00167             case    18:
00168                 wr(temps[1], RCIN1REVERSE);
00169                 break;
00170             case    19:
00171                 wr(temps[1], RCIN2REVERSE);
00172                 break;
00173 /*            case    33:      //  Not shown in menu, just to test stuff searching for strtod bug, to be deleted later
00174                 pc.printf   ("Testing to fix strtod bug, ");
00175                 i = 0;
00176                 while   (numof_dbls--)
00177                     pc.printf   ("%.3f, ", dbl[i++]);
00178                 pc.printf   ("TheEnd\r\n");
00179                 break;*/
00180             case    21:      //  3 RCIn1 trim [-128 to +127]
00181             case    22:      //  3 RCIn2 trim [-128 to +127]
00182                 user_scratch = dbl[1];
00183                 if  (user_scratch > 127.0)  user_scratch = 127.0;
00184                 if  (user_scratch < -128.0) user_scratch = -128.0;
00185                 wr    (((signed char) user_scratch), i == 21 ? RCI1_TRIM : RCI2_TRIM);
00186                 set_RCIN_offsets    ()  ;
00187                 break;
00188             case    23:     //  RCIN_REGBRAKE_RANGE
00189                 wr    (temps[1], RCIN_REGBRAKE_RANGE);
00190                 break;
00191             case    24:      //  RCIN_STICK_ATTACK
00192                 wr    (temps[1], RCIN_STICK_ATTACK);
00193                 break;
00194             case    25:      //  4 Board ID '0' to '9'
00195                 if  (temps[1] <= 9)    //  pointless to compare unsigned integer with zero
00196                     wr('0' | temps[1], BOARD_ID);
00197                 break;
00198             case    26:      //  TOP_SPEED
00199                 topspeed = dbl[1];
00200                 if  (topspeed > 25.0)   topspeed = 25.0;
00201                 if  (topspeed < 1.0)    topspeed = 1.0;
00202                 wr((char)(topspeed * 10.0), TOP_SPEED);
00203                 break;
00204             case    27:      //  5 Wheel dia mm, Motor pinion teeth, Wheel gear teeth
00205                 wr(temps[1], WHEELDIA);
00206                 wr(temps[2], MOTPIN);
00207                 wr(temps[3], WHEELGEAR);
00208                 break;
00209             case    28:      //    {2, 5, 2, "Command source 2= COM2 (Touch Screen), 3= Pot, 4= RC Input1, 5= RC Input2, 6=RC1+2 Robot"},
00210                 if  (temps[1] > 1 && temps[1] <= 6)
00211                     wr(temps[1], COMM_SRC);
00212                 break;
00213             case    29: //  Nominal System Voltage
00214                 wr    (temps[1], NOM_SYSTEM_VOLTS);
00215                 break;
00216             case    83: //  set to defaults
00217                 set_defaults   ();
00218                 break;
00219             case    30: //  BAUD
00220                 wr  (temps[1], BAUD);
00221                 break;
00222 /*            case    9:      //  9 Save settings
00223                 save   ();
00224                 pc.printf   ("Saving settings to EEPROM\r\n");
00225                 break;*/
00226             default:
00227                 pc.printf   ("Not found - user setting %d\r\n", i);
00228                 i = 0;
00229                 break;
00230         }       //  endof   switch
00231         if  (i) {
00232             save    ();
00233             pc.printf   ("Saving settings to EEPROM\r\n");
00234         }
00235     }           //  endof   //  If more than 0 parameters supplied
00236     else    {   //  command was just "mode" on its own
00237         pc.printf   ("No Changes\r\n");
00238     }
00239     pc.printf   ("us 11\t%s = %d, %s = %d\r\n", t(MOTADIR), settings[MOTADIR], t(MOTBDIR), settings[MOTBDIR]);
00240     pc.printf   ("us 12\t%s = %d, %s = %d\r\n", t(MOTAPOLES), settings[MOTAPOLES], t(MOTBPOLES), settings[MOTBPOLES]);
00241     pc.printf   ("us 13\tNumof motor current shunt resistors [%d to %d], MotorA = %d, MotorB = %d\r\n", min(ISHUNTA), max(ISHUNTA), settings[ISHUNTA], settings[ISHUNTB]);
00242     pc.printf   ("us 14\t%s [min %d, max %d] = %d\r\n", t(BRAKE_EFFECTIVENESS), min(BRAKE_EFFECTIVENESS), max(BRAKE_EFFECTIVENESS), settings[BRAKE_EFFECTIVENESS]);
00243     pc.printf   ("us 15\t%s[%d to %d] = %d\r\n", t(POT_REGBRAKE_RANGE), min(POT_REGBRAKE_RANGE), max(POT_REGBRAKE_RANGE), settings[POT_REGBRAKE_RANGE]);
00244     pc.printf   ("us 16\tServo1 [0 or 1] = %d %s, Servo2 [0 or 1] = %d %s\r\n", settings[SVO1], settings[SVO1] == 0 ? "Disabled":"Enabled", settings[SVO2], settings[SVO2] == 0 ? "Disabled":"Enabled");
00245     pc.printf   ("us 17\tRCIn1 [0 disable, 1 Uni_dir, 2 Bi_dir] = %d, %s\r\n\tRCIn2 [0 disable, 1 Uni_dir, 2 Bi_dir] = %d, %s\r\n", settings[RCIN1], labs[settings[RCIN1]], settings[RCIN2], labs[rd(RCIN2)]);
00246     pc.printf   ("us 18\t%s RCIN1 = %d, %s\r\n", t(RCIN1REVERSE), settings[RCIN1REVERSE], settings[RCIN1REVERSE] == 0 ? "NORMAL":"REVERSE");
00247     pc.printf   ("us 19\t%s RCIN2 = %d, %s\r\n", t(RCIN2REVERSE), settings[RCIN2REVERSE], settings[RCIN2REVERSE] == 0 ? "NORMAL":"REVERSE");
00248     pc.printf   ("us 21\tRCIn1 two's comp trim, [-128 to +127] = %d\r\n", (signed char) settings[RCI1_TRIM]);
00249     pc.printf   ("us 22\tRCIn2 two's comp trim, [-128 to +127] = %d\r\n", (signed char) settings[RCI2_TRIM]);
00250     pc.printf   ("us 23\tRCIn Regen braking uses this pcntage of movement range, [%d to %d] = %d\r\n",min(RCIN_REGBRAKE_RANGE), max(RCIN_REGBRAKE_RANGE), settings[RCIN_REGBRAKE_RANGE]);
00251     pc.printf   ("us 24\tRCIn Stick move Attack rate, [%d to %d] = %d\r\n",min(RCIN_STICK_ATTACK), max(RCIN_STICK_ATTACK), settings[RCIN_STICK_ATTACK]);
00252     pc.printf   ("us 25\tBoard ID ['0' to '9'] = '%c'\r\n", settings[BOARD_ID]);
00253     pc.printf   ("us 26\t%s = %.1f\r\n", t(TOP_SPEED), double(settings[TOP_SPEED]) / 10.0);
00254 //                  WHEELDIA, MOTPIN, WHEELGEAR, used in converting RPM to MPH
00255     pc.printf   ("us 27\t%s = %d, %s = %d, %s = %d\r\n", t(WHEELDIA), settings[WHEELDIA], t(MOTPIN), settings[MOTPIN], t(WHEELGEAR), settings[WHEELGEAR]);
00256     pc.printf   ("us 28\tCommand Src [%d] - 2=COM2 (Touch Screen), 3=Pot, 4=RC In1, 5=RC In2, 6=RC1+2\r\n", settings[COMM_SRC]);
00257     pc.printf   ("us 29\t%s = %d\r\n", t(NOM_SYSTEM_VOLTS), settings[NOM_SYSTEM_VOLTS]);
00258     pc.printf   ("us 30\t%s %d\r\n", t(BAUD), settings[BAUD]);
00259     pc.printf   ("us 83\tSet to defaults\r\n");
00260 //    pc.printf   ("us 9\tSave settings\r\r\n");
00261 }
00262 
00263 bool    eeprom_settings::in_range   (char val, uint32_t p)  {
00264     if  ((val >= option_list[p].min) && (val <= option_list[p].max))
00265         return  true;
00266     return  false;
00267 }
00268 uint32_t    eeprom_settings::min (uint32_t i)    {
00269     if  (i >= numof_eeprom_options)
00270         i = numof_eeprom_options - 1;
00271     return  option_list[i].min;
00272 }
00273 uint32_t    eeprom_settings::max (uint32_t i)    {
00274     if  (i >= numof_eeprom_options)
00275         i = numof_eeprom_options - 1;
00276     return  option_list[i].max;
00277 }
00278 uint32_t    eeprom_settings::def (uint32_t i)    {
00279     if  (i >= numof_eeprom_options)
00280         i = numof_eeprom_options - 1;
00281     return  option_list[i].de_fault;
00282 }
00283 
00284 const char *  eeprom_settings::t  (uint32_t    i)  {
00285     if  (i >= numof_eeprom_options)
00286         i = numof_eeprom_options - 1;
00287     return  option_list[i].txt;
00288 }
00289 
00290 bool        eeprom_settings::set_defaults    () {         //  Put default settings into EEPROM and local buffer
00291     for (int i = 0; i < numof_eeprom_options; i++)
00292         settings[i] = option_list[i].de_fault;       //  Load defaults and 'Save Settings'
00293     return  save    ();
00294 }
00295 
00296 uint32_t    eeprom_settings::errs   ()  {
00297     return  errors;
00298 }
00299 
00300 bool    eeprom_settings::do_we_have_i2c  (uint32_t x)    {
00301     for (int i = 0; i < i2c_device_count; i++)  {
00302         if  (i2c_device_list[i] == x)
00303             return  true;
00304     }
00305     return  false;
00306 }
00307 
00308 //  Use :   eeprom_settings (SDA_PIN, SCL_PIN);
00309 eeprom_settings::eeprom_settings    (PinName sda, PinName scl) : i2c(sda, scl)  //  Constructor
00310 {
00311     errors = i2c_device_count = 0;
00312     for (int i = 0; i < 36; i++)
00313         settings[i] = 0;
00314     for (int i = 0; i < MAX_I2C_DEVICES; i++)
00315         i2c_device_list[i] = 0;
00316     i2c.frequency(400000);      //  Speed 400000 max.
00317     int q;
00318     for (int i = 0; i < 255; i += 2)    {   //  Search for devices at all possible i2c addresses
00319         i2c.start();
00320         q = i2c.write(i);   //  may return error code 2 when no start issued
00321         switch  (q) {
00322             case    ACK:
00323                 i2c_device_list[i2c_device_count++] = i;
00324                 if  (i2c_device_count >= MAX_I2C_DEVICES)   {
00325                     i = 300;    //  break out
00326                     pc.printf   ("Too many i2c devices %d\r\n", i2c_device_count);
00327                 }
00328             case    2:      //  Device not seen at this address
00329             break;
00330             default:
00331                 pc.printf   ("Unknown error %d from i2c.write while looking for i2c devices\r\n", q);
00332                 errors |= 512;
00333             break;
00334         }
00335     }
00336     i2c.stop();
00337     if  (errors || !do_we_have_i2c(0xa0))    {
00338         pc.printf   ("Error - EEPROM not seen %d\r\n", errors);
00339         errors |= 0xa0;
00340         ESC_Error.set   (FAULT_EEPROM, errors);                      //  Set FAULT_EEPROM bits if 24LC64 problem
00341     }
00342     else    {   //  Found 24LC64 memory on I2C. Attempt to load settings from EEPROM
00343         errors = 0;
00344         if  (!rd_24LC64   (0, settings, 32))
00345             ESC_Error.set   (FAULT_EEPROM, 2);                      //  Set FAULT_EEPROM bit 1 if 24LC64 problem
00346         for (int i = 0; i < numof_eeprom_options; i++) {
00347             if  ((settings[i] < option_list[i].min) || (settings[i] > option_list[i].max))  {
00348                 pc.printf   ("EEROM error with %s\r\n", option_list[i].txt);
00349                 settings[i] = option_list[i].de_fault;       //  Load default for faulty entry
00350                 errors++;
00351             }
00352         }
00353     }
00354     ESC_Error.set   (FAULT_EEPROM, errors);  //  sets nothing if 0
00355 //    if  (errors > 1) {    ??why > 1 ?
00356     if  (errors > 0) {
00357 //        pc.printf   ("Bad settings found at startup. Restoring defaults\r\n");
00358 //        for (int i = 0; i < numof_eeprom_options2; i++)
00359 //            settings[i] = option_list[i].de_fault;       //  Load defaults and 'Save Settings'
00360         if  (!wr_24LC64  (0, settings, 32))         //  Save settings
00361             pc.printf   ("Error saving EEPROM in user_settings19\r\n");
00362     }
00363     rpm2mphdbl = 60.0                                                          //  to Motor Revs per hour;
00364               * ((double)settings[MOTPIN] / (double)settings[WHEELGEAR])  //  Wheel revs per hour
00365               * PI * ((double)settings[WHEELDIA] / 1000.0)                  //  metres per hour
00366               * 39.37 / (1760.0 * 36.0);                                      //  miles per hour
00367     update_dbls ();
00368 //    else    //  0 or 1 error max found
00369 //        pc.printf   ("At startup, settings errors = %d\r\n", errors);
00370 }       //  endof constructor
00371     
00372 void    eeprom_settings::update_dbls ()  {
00373     user_brake_rangedbl = (double)settings[POT_REGBRAKE_RANGE] / 100.0;
00374     Vnomdbl = (double)settings[NOM_SYSTEM_VOLTS];
00375     brake_eff = (double)settings[BRAKE_EFFECTIVENESS] / 100.0;
00376     top_speeddbl = (double)settings[TOP_SPEED] / 10.0;
00377 }
00378 
00379 bool    eeprom_settings::ack_poll    ()  {   //  wait short while for any previous memory operation to complete
00380     const int poll_tries    = 40;
00381     int poll_count = 0;
00382     bool    i2cfree = false;
00383     while   (poll_count++ < poll_tries && !i2cfree)  {
00384         i2c.start   ();
00385         if  (i2c.write(addr_wr) == ACK)
00386             i2cfree = true;
00387         else
00388             wait_us   (1000);   //  June 2020 changed from wait_ms as now deprecated
00389     }
00390     return  i2cfree;
00391 }
00392 
00393 bool    eeprom_settings::set_24LC64_internal_address (int    start_addr)   {
00394     if  (!ack_poll())
00395     {
00396         pc.printf   ("Err in set_24LC64_internal_address, no ACK writing device address byte\r\n");
00397         i2c.stop();
00398         return  false;
00399     }
00400     int err = 0;
00401     if  (i2c.write(start_addr >> 8)   != ACK) err++;
00402     if  (i2c.write(start_addr & 0xff) != ACK) err++;
00403     if  (err)   {
00404         pc.printf   ("In set_24LC64_internal_address, Believe Device present, failed in writing 2 mem addr bytes %d\r\n", err);
00405         i2c.stop();
00406         return  false;
00407     }
00408     return  true;
00409 }
00410 
00411 bool eeprom_settings::rd_24LC64  (uint32_t start_addr, char * dest, uint32_t length)   {
00412     int acknak = ACK;
00413     if(length < 1)
00414         return false;
00415     if  (!set_24LC64_internal_address   (start_addr))   {
00416         pc.printf   ("In rd_24LC64, failed to set_ramaddr\r\n");
00417         return  false;
00418     }
00419     i2c.start();
00420     if  (i2c.write(addr_rd) != ACK) {
00421         pc.printf   ("Errors in rd_24LC64 sending addr_rd\r\n");
00422         return  false;
00423     }
00424     while(length--) {
00425         if(length == 0)
00426             acknak = 0;
00427         *dest++ = i2c.read(acknak);
00428     }
00429     i2c.stop();
00430     return  true;
00431 }
00432 
00433 bool    eeprom_settings::wr_24LC64  (uint32_t start_addr, char * source, uint32_t length)   {
00434     int err = 0;
00435     if(length < 1 || length > 32)   {
00436         pc.printf   ("Length out of range %d in wr_24LC64\r\n", length);
00437         return  false;
00438     }
00439     ack_poll    ();
00440     if  (!set_24LC64_internal_address   (start_addr))   {
00441         pc.printf   ("In wr_24LC64, Believe Device present, failed in writing 2 mem addr bytes %d\r\n", err);
00442         return  false;
00443     }
00444     while(length--)
00445         err += ACK - i2c.write(*source++);
00446     i2c.stop();
00447     if  (err)   {
00448         pc.printf   ("in wr_24LC64, device thought good, mem addr write worked, failed writing string\r\n");
00449         return  false;
00450     }
00451 //    pc.printf   ("In wr_24LC64 No Errors Found!\r\n");
00452     return  true;
00453 }
00454 
00455 char    eeprom_settings::rd  (uint32_t i)  {           //  Read one setup char value from private buffer 'settings'
00456     if  (i > 31)    {
00457         pc.printf   ("ERROR Attempt to read setting %d\r\n", i);
00458         return  0;
00459     }
00460     return  settings[i];
00461 }
00462 
00463 /*
00464 bool    eeprom_settings::in_range   (char val, uint32_t p)  {
00465     if  ((val >= option_list[p].min) && (val <= option_list[p].max))
00466         return  true;
00467     return  false;
00468 }
00469 */
00470 bool    eeprom_settings::wr  (char val, uint32_t p)  {           //  Write one setup char value to private buffer 'settings'
00471     if  (p > 31)
00472         return  false;
00473     if  ((val >= min(p)) && (val <= max(p)))    {
00474         settings[p] = val;
00475         return  true;
00476     }
00477     settings[p] = def(p);
00478 //    pc.printf   ("Wrong in wr, %s\r\n", t(p));
00479     return  false;
00480 }
00481 
00482 bool    eeprom_settings::save    ()  {               //  Write 'settings' buffer to EEPROM
00483     update_dbls ();
00484     return  wr_24LC64   (0, settings, 32);
00485 }
00486