It’s been almost three weeks since my last post and some further progress has been made. I’ve upgraded the microcontroller and can now control the gain of the second amplifier stage in software. But let’s look at the changes in some more detail.
New microcontroller: PIC32MX250
I mentioned last time that I was running out of code space, i.e. flash memory on the PIC32MC220. That particular model has only 32k of flash and I’m using the free version of the XC32 compiler. That free version only performs limited amounts of optimization and therefore produces rather large and slow code compared to the standard and professional version. But the other two are rather costly (around USD 500 and 1000, respectively) and are not really an option here. And at least so far I’ve always had all the speed I needed so the only issue was flash memory.
So the straight forward solution was to upgrade the microcontroller to an otherwise identical model with more memory. The 250 I’m using now has four times more of both flash (now 128k) and ram (now 32k). I unsoldered the old chip using a hot air gun and soldered in a PIC32MX250 in its place. Now we have all the flash we need to continue our journey.
Getting I2C to work
My design uses a dual op amp for the necessary amplification of the received signal. The first stage is ground-referenced and uses a simple resistive divider to set the gain (currently set at 11).
The second stage is biased to 1.65V (i.e. half way between ground and 3.3 volts) and has its gain controlled by a I2C digipot. The idea is to have the PIC control the digipot so it can adjust the gain as needed to compensate for any effect that might change the amplitude of the received signal.
So in order to control our digipot we first need to get the I2C interface working on the PIC. There are two (identical) I2C peripherals on the PIC32MX2xx and this design uses one of them (#2) exclusively to communicate to the digipot. The other one (#1) is then available to interface to the outside world.
I’ve written a set of simple functions to use the I2C interface. So far I’ve only implemented master transmit mode since that’s the only thing we need here.
- void app_i2c_internal_init(void);
- bool app_i2c_internal_write(uint8_t address, uint8_t *data, uint8_t length);
- void app_i2c_internal_writeDigipot(uint8_t value);
The functions are entirely non-blocking so they can be called from within the interrupt service routines that do the measurement.
Fixing a design bug
Unfortunately, I made a mistake in the schematic when I referenced the feedback loop of the second op amp stage to ground instead of the mentioned 1.65 volts. Now let’s look at what that did to the signal. First, below is the signal with the digipot at 0 (of 256). The gain is set to one and all is well.
But at a setting of 64, some clipping starts to occur as shown below.
With the gain turned up to 4 with a digipot setting of 192 things get really uggly with a completely unrecognizable output signal.
I was extremely lucky that the correct signal was available right next to the pin where I needed it so all I had to do was to cut the ground connection with a carving knife and to connect the correct signal using a tiny bit of wire. The change is hardly visible on the photo below. Can you spot it? It’s almost at the center of the photo at pin 5 (bottom right) of the small 8-pin IC. It now connects to the 10k resistor at the bottom instead of the ground plane on its right.
Controlling the gain in software
With that error fixed we can now set the gain as we please. Here some examples. Yellow is the (unamplified) input signal whereas green is the output of the (fixed) first amplifier stage. The purple signal is calculated as the difference between the DAC+ and DAC- signals. Those two signals is what we feed into the PIC to be measured.
With the gain at 1 (digipot at 0) we get a about 2.6 volts peak-peak. A bit little but sufficient.
This is probably about what we want. Digipot at 50 resulting in a peak-peak amplitude of a bit above 3 volts.
Needless to say that we can jerk the gain up far more than that if we want. Below is an example where a gain of 4 results in a seriously clipped signal.
Now let’s look a a situation where such a high gain might actually be useful. In the example below I’ve lowered the input voltage to only 5 volts. As a result the received signal is only 90mV in amplitude instead of the 220mV seen above. That’s easily compensated with a bit of help from our digipot. With a setting of 170 we get a nice, clean 3 volt output signal.
Calculating the necessary gain
For the examples above I’ve explicitly set the gain in the code. But what we really want is to have the software calculate and set the necessary gain automatically.
So I’ve implemented a simple algorithm to do so. I set some target value for the peak-to-peak amplitude of the signal measured by the DAC. Knowing the amplitude and digipot setting of the last measurement I calculate the optimal gain and digipot setting for the next measurement.
Above is the signal without this automatic gain setting in place (gain=1). As you can see, the peak-to-peak amplitudes vary quite a bit between transducer pairs. So the gain calculations, too, work on a transducer pair basis. Each direction gets its own setting to compensate for different transducer sensitivities.
Below is a screenshot of the result. Notice how now all transducer pairs have identical (and somewhat larger) amplitudes.
That’s it for today. Click here for my next post.