Current Sensing
TL;DR A current carrying wire produces a magnetic field. By measuring the strength of the magnetic field with a Hall Effect sensor we get an electrical signal (PWM) corresponding to the current in the wire. This signal can be "read" in software to calculate the current flowing from the battery box. In future, the problems we experienced can be mitigated by upgrading hardware and planning/standardizing the pinout more carefully.
Overview
The goal of current sensing is to monitor the current coming from the battery box, this is a good indication of how depleted the batteries are. This information is important for Plutus to monitor and maintain the health of the batteries.
Hall Effect Sensors
A Hall Effect Sensor has been used in both MSX and MSXI to monitor the current leaving the battery box. This type of sensor works by changing its voltage output in response to a magnetic field (B) making it a type of transducer. A current carrying wire will produce an electric field according to Ampere's Law (ignoring Maxwell's correction)
or in differential form
Where B is the magnetic field produced by a current-carrying wire, l is the length of the current-carrying wire in the vicinity of the sensor, μ0 is the magnetic permeability of free space and J is the current density flowing through a cross section S of the wire. Note the differential form states that the curl of the magnetic field is equal to the current density times the magnetic permeability of free space.
In essence, this means that since a Hall Effect sensor can read the strength of the magnetic field and convert it into a voltage by assuming values for l and S by restricting the wire gauge and choosing the length over which the sensor reads. This is translated to a pulse width modulated signal (see next section) to produce a duty-cycle which we can read in software this duty-cycle is then mapped to a current using a function provided by the sensor manufacturer.
More on Hall Effect Sensors and how they actually work:
Pulse Width Modulation (PWM)
A pulse width modulated signal or (PWM) is a method of relaying an analog result through a digitally readable signal. This is achieved by generating a square wave of alternating high/ON (typically 3.3 or 5 V) and low/OFF (0 V) signals. This essentially simulates an average voltage between the high and low value corresponding to the value of the effective analog signal. The portion of a wavelength (λ) that is spent at an ON or high state is the pulse width and the percentage of "active time" per wavelength is the duty-cycle. For example; a signal that is in the high state only 1/4 of the time is said to have a duty-cycle of 25% which for a 5 V high value would result in an average voltage of 1.25 V. The frequency (f) of the incoming signal is the inverse of the period (T) which is equivalent to wavelength for a time varying signal.
Mathematically, speaking the duty-cycle can be expressed as
Where D is the duty-cycle.
The average voltage of the signal can be expressed as
Where y is the signal strength.
Additional Readings:
Software
For MSX the duty-cycle was calculated instantaneously, this was improved in MSXI by using a time-averaged duty-cycle to reduce noise and improve accuracy. The duty-cycle was determined by using rising and falling edge detection, essentially this means that the chosen I/O pin(s) is/are monitoring the signal and alerts the software through an interrupt vector whenever the signal switches from low to high (rising) or high to low (falling). This vector triggers code to read the internal clock time of the signal change to a pair of ring buffers one for rising and one falling. By computing the duration between two rising events we can determine the period of a cycle. By computing the duration between the first rising and next falling event the active time can be determined. Dividing the active time by the period we can determine the duty cycle. By averaging these results we can get a good idea of the average duty cycle for a short period, this is then mapped to the current value using the manufacturer's function. In MSX these values were not averaged and as a result, the accuracy was lower.
Reflections and Improvements
The major difficulty experienced in implementing current sensing in MSXI was an internal timing issue. Specifically, the interrupt vectors to trigger the rising and falling behavior were not always interleaving as rising, falling, rising, falling. Instead one of the events would often skip leading to the two ring buffers falling out of sync yielding completely unexpected duty-cycles and by extension, current values. This issue plagued the initial implementation for weeks while we sought to understand the issue; it was particularly bad above 100 Hz and the sensor we were using operated at 125 Hz. It didn't help that the Timer A module we used in prototyping on the MSP430F5529 launchpad had different behavior than the Timer B module that was connected on the Plutus board. Going forward it would be ideal to use the same modules for both prototyping and real-boards. In this case, it was a hardware limitation of the launchpad and original design of Plutus.
A more specific, issue that would have helped with the conflicting interrupt vectors would have been to have had the rising and falling I/O pins in the same interrupt vector bank. The way Timer B was designed, pin 0 registered on a different vector than pins 1-7. The rising and falling pins assigned in hardware were pins 0 and 1 resulting in having to rely on multiple vectors to call on the same methods and the vector for pin 0 had priority over pin 1 likely causing most of the sync issues.
Another note to reflect on is the difficulty with doing numeric division for the duty-cycle calculation without proper hardware support. The MSP430 series of microcontrollers did not have good support for floating point mathematics so integer math was needed which was less than ideal and resulted in using some weird units such as cA (centiamps) due to the native register/integer size of the MSP430 series controllers. Similarly, the interrupt vector speed issue could have been resolved with a faster CPU speed so upgrading the hardware is recommended.
Other suggested improvements include using an external clock crystal for the system to help with timing issues and to consider using a Hall Effect Sensor with a better pin interface (the solder joints often broke and were hard to repair on the model used in MSXI).