This project serves to highlight the features of Maxim feather board based on Max32620 MCU with PMU MAX77650 and battery measurement fuel gauge IC MAX17055. At the end of this work it will be clear why this little feather board is the perfect replacement for robotic projects that are originally conceived to be powered by small batteries such AA or 9V cells, by taking advantage of the integrated Li-Ion compatible charger and fuel gauge, power consumption telemetry can be tracked and optimized. The processing power of the MAX32620 is also an advantage compared to other commercially boards.
About.The core of the project is the MAX32620FTHR board from Maxim, the idea is to use this board to replace an existing robotic car based on arduino core. The Robotic car for the project is the well known project SMARS, by default the project uses among other things a 9V battery and Arduino Uno board which are replaced here by the feather board from Maxim.
Maxim Feather for Robot.The SMARS project have all the 3D models to print out the robot. The project specifies a 9V battery, battery clip and Arduino Uno compatible board among other things. Those are going to be replaced by Maxim feather board and Li-Po battery. For this project a Motor shield based on L298P IC called Fundomoto was used, thou there are many other options available that will work too. I will describe here connections from feather board to this specific shield.
The lack of documentation for this shield was taking carefully to avoid any damage to the feather board, i.e. connecting a 5V signal or power rail to an I/O pin.
I found this blog very useful to decipher how to connect the motor shield board to the feather board. The basic pins numbering for a basic robot setup are described in the following table.
If you are not familiar with L298P I recommend read the datasheet specifications and some description like this or this. This particular shield as explained here is unable to do dynamic break mode, since the PWM signal is routed to the EN pins. For this case this is not a problem as there is a lot of friction and actually the robot don't speed at all.
The motor signal are input to the shield and so there is no problem to use the connections directly from feather board. The echo and trigger pins are signal output and input from ultrasonic sensors, an explanation of this type of sensors can be found here. Basically the sensor return a pulse whose duration is proportional to the distance of object in line of sight.
A low cost bidirectional level translator board is used for this case, thou it might be only needed for the input echo signal, I have also wired the trigger pin thorough it.
The Maxim compatible Feather board MAX32620FTHR was mounted on an arduino proto shield such as this.
Below is a picture showing how it looks the setup of the Maxim feather mounted on the generic proto shield.
Apart from the fact that the feather board uses a powerful Cortex M4 processor that is Arduino IDE compatible, one of the coolest thing this board allows is to have a 1 Cell Li Ion or Li-Po battery, this allows the replacement of the 9V battery but it also needs some considerations.
The DC motors used for this robot are rated at 6V for 150 RPM, which means we cannot only rely on the feather board for complete functioning. The Fundumoto shield can work with external power by using the two terminal blocks at the upper right, it can also works by powering from the arduino header but the voltage is not enough higher for operation since L298P supply voltage needs to be 2.5V higher than VIH (high voltage level at input pin), which at minimum is 2.3V, as stated in page 3 of datasheet.
The only option is to step up the battery voltage, which at the end is the most reasonable and convenient way.
For this purpose we use the XL6009 regulator to step up from the Li-Po battery voltage.
A module as the one shown in above image has the convenient size of less than the volume of a 9V battery, making it fit perfectly on the battery compartment of the SMARS robot without modifications. We have only cut the battery holder clips because those helps to keeps the little motors in place.
The black PLA parts you see on above picture has sort of hook to keep the 9V in place, I remove them using a set of pliers since I need the surface flat for the Li-Po battery. I am using a 2000 mAh Li-Po battery that fits almost perfectly on the robot, thou I sand the inner a little bit to easy insertion and removal.
In order to allow safe operation of the device I decide to enable the step up dc-dc converter only when the battery is not charging. One of the reason is because the motors can consume considerable current under certain torque/load conditions, which might be higher than the 300mA of the charging current from MAX77650 IC. When powering the feather from USB, the device behavior is to normally start the programmed firmware. One approach is to allow the max32620 to control the load switch at start up, but a safe approach is to control the load switch automatically, that is leaving the USB VBUS voltage controls it.
As you can see in the above circuit diagram, the battery positive terminal is connected to the input of the load switch NTGD1100L device. The Ground reference is not actually taken from the battery because we want to track the battery charge state using the Fuel Cell IC.
If you examine the MAX32620FTHR schematics you will notice that the GND battery terminal is actually connected to system ground reference thru a 0.05 Ohm resistor which is used to measure the current drained from the battery using the MAX17055 Fuel gauge, because of this we need to use the GND pins of the board and not the battery terminal labeled GND.
There a couple of arduino libraries for MAX17055, I have tested the one from AwotG github user that you can find here, my experience is that it partially works, it implements basic register reading and writing, thou it does not implement the procedure outlined in the software implementation guide. You still might want to check the user manual and the datasheet for details.
After playing around I notice the library uses a variable to set the sense resistor value, which is suppose you can modify during initialization by calling the function
sensor.setResistSensor(0.05);
This never work for me after a few attempts, so I device to hardcode the value in library MAX17055.h file, such as
float resistSensor = 0.05; //default internal resist sensor
The
library was a good starting point but in order to follow the software implementation guide I include a lot of code. If you open the guide you can see that certain conditions require different steps.
Under the sketch code I included a function called initSensor which is suppose to do steps 1 thru 4 explained on the guide.
Several functions have been included to accomplish those steps, for example step 1 where Check for POR is performed, a function called getStatusPOR is included in the library, but the flow execution is written in the sketch. Similar case for the function that checks the Data Not Ready Flag or DNR, called DataNotReady.
The sketch code looks like the following
boolean initSensor() {
if (sensor.getStatusPOR() == 0) {
float capacity = sensor.getReportedCapacity();
Serial.print("Capacity of plugged in battery is: ");
Serial.print(capacity, 4);
Serial.println(" mAH \n\n");
float SOC = sensor.getSOC();
Serial.print("State of Charge value is: %");
Serial.println(SOC, 4);
Serial.println("\n\n");
return true;
} else {
while (sensor.DataNotReady()) {
delay(10); // do not continue until FSTAT.DNR == 0
}
sensor.EzConfig(2000, 300 * 0.15);
sensor.clearPORbit();
if (sensor.getStatusPOR() == 1) {
return false;
}
return true;
}
}
The step 3 on the guide is contained in the public library function EzConfig. Specifically I follow the 3.1 step instructions, the EZ config (no INI file). The function is
void MAX17055::EzConfig(uint16_t capacity, float current){
uint16_t HibCFGVal = readReg16Bit(HibCFG);
writeReg16Bit(0x60, 0x90); // Exit Hibernate Mode Step 1
writeReg16Bit(0xBA, 0x0); // Exit Hibernate Mode Step 2
writeReg16Bit(0x60, 0x0); // Exit Hibernate Mode Step 3
writeReg16Bit(DesignCap, capacity); // Write DesignCap
writeReg16Bit(dQAcc, capacity/32); // Write dQAcc
setTerminationCurrent(current); // Write IChgTerm
uint16_t VEmptyVal = (0x14A << 7) | (0x61);
// 3.3V - 330 * 10mV and 3.88V - 97 * 40mV
writeReg16Bit(VEmpty, VEmptyVal); // Write VEmpty
// since charge voltage is 4.2V
writeReg16Bit(dPAcc, 1379); // hardwire this to test
setModelCfgRegister(0x8000);
while(getModelCfgRegister()&0x8000){
delay(10);
}
writeReg16Bit(HibCFG, HibCFGVal);
}
Another missing function of original library was one to set the charge termination current register, that is, IChgTerm (address 0x1E), otherwise the default value of 250mA will rule, in our case it's too much, the MAX77650 specifies termination current as percentage of Fast Charge current such as 15%, 10%, 5%.
Since our battery is 2000 mAh and the recommended charging current is between 100mA and 500mA for longer battery life, I have decide to set the Fast Charge Current value to 300 mA. For this reason the function setTerminationCurrent was added to the library, the function writes to register 0x1E, the code:
void MAX17055::setTerminationCurrent(float curLimit){
curLimit = curLimit / current_multiplier_mV;
writeReg16Bit(IChgTerm, curLimit);
}
where the register address is contained in a enum in definition file such as
enum regAddr
{
Status = 0x00,
VCell = 0x09,
AvgVCell = 0x19,
Current = 0x0A,
AvgCurrent = 0x0B,
RepSOC = 0x06,
RepCap = 0x05,
TimeToEmpty = 0x11,
DesignCap = 0x18,
IChgTerm = 0x1E,
PowerReg = 0xB1,
AvePowerReg = 0xB3,
FullCapRep = 0x10,
ModelCfg = 0xDB,
FStatReg = 0x3D,
HibCFG = 0xBA,
dQAcc = 0x45,
dPAcc = 0x46,
VEmpty = 0x3A,
};
On arduino IDE setup function the max17055 is initialized by initSensor function in a loop as required per step 4.2
while (!initSensor()) {
Serial.println("Problem Init MAX17055 - attempting ");
delay(1000);
}
It's worth to mention that the MAX32620FTHR uses I2C2 serial port for the MAX77650 and MAX17055 device. Next section talks about the arduino library for MAX77650, solely to say here is the fact that it is already developed for the feather board and that is the reason the Wire2 is already initialized.
Nonetheless the author of MAX17055 uses Wire port, that is, I2C0 port, the library need to adjust for our case by changing the low level I2C functions such as
// Private Methods
void MAX17055::writeReg16Bit(uint8_t reg, uint16_t value)
{
//Write order is LSB first, and then MSB. Refer to AN635
if(MAX17055_I2C_port == 0){
Wire.beginTransmission(I2CAddress);
Wire.write(reg);
Wire.write( value & 0xFF); // value low byte
Wire.write((value >> 8) & 0xFF); // value high byte
uint8_t last_status = Wire.endTransmission();
}
if(MAX17055_I2C_port == 2){
Wire2.beginTransmission(I2CAddress);
Wire2.write(reg);
Wire2.write( value & 0xFF); // value low byte
Wire2.write((value >> 8) & 0xFF); // value high byte
uint8_t last_status = Wire2.endTransmission();
}
}
uint16_t MAX17055::readReg16Bit(uint8_t reg)
{
uint16_t value = 0;
if(MAX17055_I2C_port == 0){
Wire.beginTransmission(I2CAddress);
Wire.write(reg);
uint8_t last_status = Wire.endTransmission(false);
Wire.requestFrom(I2CAddress, (uint8_t) 2);
value = Wire.read();
value |= (uint16_t)Wire.read() << 8; // value low byte
}
if(MAX17055_I2C_port == 2){
Wire2.beginTransmission(I2CAddress);
Wire2.write(reg);
uint8_t last_status = Wire2.endTransmission(false);
Wire2.requestFrom(I2CAddress, (uint8_t) 2);
value = Wire2.read();
value |= (uint16_t)Wire2.read() << 8; // value low byte
}
return value;
}
This way a compatibility can be maintained, just by changing a define in header file
#define MAX17055_I2C_port 2
The code was tested with the 2000 mAh Li-Polymer battery. A log of the result during charge and discharge is attached (discharge test.txt). For some reason the battery capacity goes higher than DesignCap Value of 2000mAh, which might happen during initial adjustment, but the discharge test ends with a 0% capacity before the 3.3V value of VEmpty is reached.
I am investigation the issue. Nonetheless the charge current measurement works very well, a negative value indicates a discharge, which is around 500mA for the robot car with 90% Duty Cycle PWM. Notice the 293 mA charge current. The current drawn by the Feather board itself without any optimization of arduino sketch is around 9 mA, which conforms the MAX77650 is delivering the configured value of 300mA.
System Shutdown.Another feature implemented here thanks to the Maxim Feather board is the system shutdown, this allow a controlled shutdown by using the same nEN pin, which is the Power push button on the feather board which is wired onto the proto shield for safe and easy access.
This feature don't need further hardware modifications but rather some firmware code that detects when user press the power button. The MAX77650 device is capable of generating an interrupt upon this event. The device also has an input pin named Power Hold (PWR_HLD) that should be keep high during operation, otherwise a shutdown sequence is initiated. Reading the nEN interrupt and making the corresponding output low level does the trick.
An open source arduino library for MAX77650 is used. Tou you might need to read the user manual for this device as well as the datasheet. The snippet code for system shutdown need first to detect interrupts by attaching the IRQ pin of MAX77650 to an interrupt in arduino code.
//MAX77650 Interrupt wiring
pinMode(MAX77650_IRQpin, INPUT_PULLUP);
attachInterrupt(MAX77650_IRQpin, MAX77650_IRQ, FALLING);
void MAX77650_IRQ(void) {
interrupt = true;
}
The MAX77650_IRQ function set a variable that is read every 50 ms in arduino loop, afterwards a check_IRQ_src function is called to detect the given interrupt source, below is a partial code of interest here
void check_IRQ_src(void){
byte INT_GLBL = MAX77650_getINT_GLBL();
if (((INT_GLBL) >> 2) & 0b00000001) {
nEN_Int = true;
Serial.println("nEN Falling Interrupt");
}
}
As you can see upon detecting a falling edge of nEN pin voltage, a new variable named nEN_Int is set, which is read in main loop to finally take the appropiate action, in this case, initiate a controlled system shutdown.
... in main loop
if(nEN_Int) {
PowerOff();
while(1);
}
... the function
void PowerOff(){
// stop motors
analogWrite(LEFT_MOTOR_PWM, 0); // 0% Duty Cycle
analogWrite(RIGHT_MOTOR_PWM, 0);
Serial.println("shuting down");
delay(500);
digitalWrite(MAX77650_PHLD, LOW); //set output to LOW to shutdown
}
Debug Serial Port.I have some problems to make it work the debug serial port located on the 10 pin JTAG connector in conjunction with the MAX32625PICO board, thou I receive something (always 2Eh chars), it was not working properly. The reason is perhaps the PICO board firmware. Rather to dedicate time to fix it, I tested the Feather board using my JTAG 20 pin to 10 pin adapter, after verifying the debug port was working I include a 10 pin connector on the Proto Shield as shown below.
The 10 pin connector should be tied there before the Feather board is inserted since the remaining space make it not possible as it was my willing to make it easier to remove for DAPLink programming. The final Top view assembly of the exposed connector.
Debug_TX pin was connected to PIN 1 or arduino D1, DEBUG_RX is on D0. This is to emulate Arduino Uno pinout.
The ultimate goal for this modification apart from the obvious intention to have access to the debug console, is because the Fundumoto shield has a header for a Bluetooth stick such as the HC-05, which can easily be used as a BT to serial adapter and then do some Telemetry.
Time for a short demo.The Pit Stop shows how it can be turn Off by pressing the power button.
Improvements.The power management load switch to turn on/off the motor shield when the USB voltage is present works OK but when the USB is not present the battery energize the Fundomoto shield, which it's not desirable. Right now it works to protect against charging the battery and having an alternate path of discharge or even accidental motor turn off, which might exceed the VSYS output limit.
A good solution is also not very friendly right now because of the prototyping board is somehow messy and the lack of some components, thou I will present the proposed solution.
One solution is to use the following diagram:
The Load switch and step-up sourcing our load should be familiar. The NOR gate allow us to have the following state table
The idea is to use a GPIO from the CPU connected to a Pull Up resistor, this way we can have a "high" voltage when the device (the MAX77650) is OFF, because the Pull Up resistor will be tied to VBAT rail.
One problem here is that the MAX32620 I/O lines are not tolerant to VBAT levels. One nice option would have been to use the MAX77650 GPIO, unfortunately the Feather board don't expose the GPIO to a header pin, thou not all is lost since it has a resistor pad connected to it, wire wrap cable can do the job for tests.
Conclusions.This projects shows that using the MAX32620FTHR is an improvement for a robotic system such as SMARS project. The robot new features make it easier to use and powerful to advance robotic applications.
Comments