Ugh... That Coding Part

The No Coding Option 

This part doesn't bother me. It's one of the reasons I started on the project in the first place. But, there's no getting around it, the amount of development environment setup that goes into just getting started is exhausting and a little annoying. Coming from a mostly software development world (which already requires a bit of setup), this seemed even more excessive. So I went looking for an easy to use and minimal development option (on my side) to simply get the treadmill belt length into the application. With this small step, a precompiled application can be used by anyone with the NRF52840 Dongle and IR Sensor and wouldn't have to worry about the entire software development piece. Of course, you'd still have to connect the hardware, acquire the SoftDevice, and program the SoftDevice and application to the dongle. But those steps are actually quite short compared to getting started with the development environment. So my though process went something like this:
  1. A mobile app with a configuration parameter for the belt length. The app then sends the configuration to the application, you know, like any of the other real hardware development companies do. Well, this part seemed to me like an entire project itself, so I passed on it... for now.
  2. The NRF52840 contains User Information Configuration Registers (UICR). That sounded a lot like what I needed. A non-volatile register to hold user information, for example, belt length. Reading from the UICRs looked very straight forward in code. The only missing piece I needed was a easy way to write to a UICR from an external tool. So my next step was to start searching for an example of how to do this. And, as it turned out, writing the value is possible with the NRF command line tools. However, the next issue was that the value could only be written once, otherwise the entire flash needed to be erased and rewritten. So I looked for another way.
  3. The Intel Hex file format is relatively straight forward and pretty well documented. So the first thing I did was search for my belt length, 3162 in decimal... 0x0C5A in hexadecimal... 5A0C in little endian... and it was there. So I'll dig a little deeper into this approach.

Modifying the Treadmill SDM Application Hex File

I left off saying that the belt length number was found in the hex file, so my first thought was to change the number, reprogram the NRF52840 Dongle, and see what happens. So I changed it to 0x03E8, or 1000mm. But it turns out its about one byte more complicated than that... a checksum byte. Fortunately, it's an easy checksum to calculate and a few lines of code later the checksum was being updated.

So now with a binary that was modified to by changing 0x0C5A to 0x03E8, I programmed it onto a spare NRF52840 Dongle I have using NRF Connect. Then I fired up SimulANT+ and ran the SDM Display to observe how the change affected the transmitted values. This is where the results met up with the tiny voice in the back of my head telling me that compiler optimizations should have made this not work. And that was the case, at least partially. The distance being added was not 1 meter, rather 3.162m (actually the closest approximation to 1/16 of a meter), but the pace reported was using 1m as the belt length, not 3.162m.

See, the way the code is written the BELT_LENGTH constant is used in two places. It gets added directly to the SDM distance attribute and it is used to calculate the SDM instantaneous speed. 

In the first use, the entire distance calculation is known at the time the code is being compiled. That is, all three pieces in the calculation are constants and the compiler is able to do something called constant folding to combine the three numbers into one.  So what was once code that looked something like:
distance += 3162 / 1000 * 16;
Now got simplified into:
distance += 51;

However, when it comes to the pace calculation, there is a variable component, that is, the time between the last and current interrupt. Because of this variable piece, the calculation
pace = 3162 / time * 256;
can't be simplified ahead of time by the compiler, because the time variable changes each time the calculation is performed. This causes the number 3162 to be left in the code as an immediate value for this calculation and is the reason that only the pace was affected when 3162 was changed to 1000.

Fortunately, you can trick the compiler out of using constant folding by using the volatile keyword in C. This keyword pretty much tells the compiler that even though its analysis might not see changes made to a variable, it's possible that something external to the could change its value. Because of this the compiler can't use some of its nifty optimizations on the variable. By changing the line:
#define BELT_LENGTH 3162 /* millimeters */
to
static const volatile uint32_t BELT_LENGTH = 3162; /* millimeters */
the belt length will by 3162 for both of the calculations.
After making this change, I once again replaced 0x0C5A with 0x03E8 and tested it out. This time, both the distance and pace values were correctly using one meter as the belt size. Success. The only small issue I can see with this approach is that because the compiler is unable to precalculate the distance to add the application has to do a few more operations each time the interrupt triggers than it would have otherwise.

That's a lot of words to say...

I precompiled a version of the code with a belt length that can be externally replaced. I also wrote a Python script that take belt length in millimeters as a parameter and outputs a new hex file using the provided belt length instead of 3162. Run the script with your desired belt length:
python BeltLengthReplacer.py 1000
and you should end up with treadmill_sdm_s212_beltlength_1000mm.hex sitting next to treadmill_sdm_s212.hex and treadmill_sdm_s212_RBL.hex. This can be programmed the NRF52840 Dongle along with the S212 SoftDevice and should work exactly the same as compiling the code. Just note that I haven't really tested this beyond some quick examination, so it's possible there will be issues.

Comments

  1. Hi, I am wondering if you ever got around to doing anything with cadence on your tracker. I am thinking of copying your project, but would like to try to incorporate a cadence sensor on the treadmill as well, possibly by mounting an accelerometer with a magnet.

    ReplyDelete
    Replies
    1. No, sorry, I never got back around to making things work with the accelerometer. I looked at the sensors I had sitting here earlier in the year and thought about coding it up but I really don't look at or use the cadence information in my training so I had no motive to make it work.

      It can definitely be done, though. The foot steps definitely showed up in the accelerometer data when I was testing.

      Delete

Post a Comment