STM32 Development

Tags: #<Tag:0x00007f13e6d0acb8> #<Tag:0x00007f13e698fe30>

(Paul) #123

I have now added tar6 to the repo, for now it’s still following the released tar numbering rather than the version so this is tag 0.0.6 and here’s the latest v5 to v6 diff ( The “fix_math” branch will be deleted.

emonTxshield Demo 1.2
Patch PA0 through to PB14 for V!!!
CPU temp: 30C, Vdda: 3306mV
CPU temp: 30C, Vdda: 3304mV
1: Vrms: 1149.54, Irms: 87.93, Papp: 101076.28, Preal: 1993.98, PF: 0.020
2: Vrms: 1149.54, Irms: 87.93, Papp: 101076.28, Preal: 1993.98, PF: 0.020
3: Vrms: 1149.54, Irms: 87.93, Papp: 101075.99, Preal: 2178.61, PF: 0.022
0: Vrms: 1149.54, Irms: 8.00, Papp: 9193.34, Preal: -24.47, PF: -0.003
CPU temp: 30C, Vdda: 3302mV
0: Vrms: 1150.45, Irms: 8.10, Papp: 9320.32, Preal: -22.06, PF: -0.002
1: Vrms: 1150.45, Irms: 87.93, Papp: 101156.23, Preal: 2318.72, PF: 0.023
2: Vrms: 1150.45, Irms: 87.93, Papp: 101156.23, Preal: 2318.72, PF: 0.023
3: Vrms: 1150.44, Irms: 87.93, Papp: 101155.78, Preal: 2486.08, PF: 0.025
CPU temp: 30C, Vdda: 3304mV
0: Vrms: 1149.99, Irms: 8.29, Papp: 9537.43, Preal: -30.59, PF: -0.003
1: Vrms: 1149.99, Irms: 87.92, Papp: 101112.29, Preal: 1306.02, PF: 0.013
2: Vrms: 1149.99, Irms: 87.93, Papp: 101115.56, Preal: 1306.02, PF: 0.013
3: Vrms: 1149.98, Irms: 87.93, Papp: 101115.11, Preal: 1453.20, PF: 0.014

(Paul Reed) #124

@pb66 - would it be worth adding a line in the git readme about users updating line 319 of emonTxshield.ioc to the correct local url, after cloning?


(Paul) #125

TBH Paul, I’m not sure at the moment. I haven’t even looked at that aspect of things myself yet so I’m not really able to advise others or document it yet. Currently it’s just for download and use. the cubeMX isn’t mentioned anywhere in the repo as yet.

Even pulling in updates via git needs explaining as the local build folder’s changes block the pull. you need to use make clean before git pull.

I may make a little script that wraps some commands up together eg update = echo warning && make clean && git pull. that could include a “personalize” function that searches and replaces strings like that with your own.

(Paul Reed) #126

In fact, just looked further into this and it appears that regardless if you migrate or simply load the ioc file into CubeMX, the line in the file emonTxshield.ioc;


is automatically removed, and replaced with

ProjectManager.FirmwarePackage=STM32Cube FW_F3 V1.9.0

which does not include a local path.

I assume this is one of the changes made between dBC’s CubeMX version 4.24.0, and the current version 4.25.0 which we are using, so no changes are necessary - it’s taken care of by CubeMX!


(dBC) #127

Yes, exactly that. Everything is in A/D units all the way through, and then at the last minute you can convert them to real world units based on resistor dividers, shunts, calibration constants etc. I tend to favour that approach because that’s how it all works in the energy IC world. Who cares about actual Volts, Amps and Watts, you can do that conversion on the final dial display. And if your meter is performing well, you’ll only need to calibrate Volts and Amps, and you’ll get Power for free.

There are some disadvantages to that approach, like is 75.xx a big number or not?.. if it were already in Amps you’d know but your brain eventually adjusts. Anyway, that’s just a personal preference, it ultimately shouldn’t make any difference to the answer where you convert them to real world units, so use whichever you prefer. Your Irms of 75.50 means 75.50/4096 * 3.3V = 60.8mV, so quite small, and smaller than the noise on your unterminated inputs. To work back from that to Amps going into you kettle, you’d need to do the CT/shunt maths. If you’re up for doing that, I’d be kinda’ interested to know what answer you get, because I think you’re the first to wrap the CT around a real load.

To give you a rough idea of scale, I’m feeding all my inputs (V + 4*I) this sine wave:

and you can see it’s close to full-scale deflection (Vpeak of 3.29V and Vmin of 27mV). That gives these readings:

CPU temp: 38C, Vdda: 3304mV                                                                                  
0: Vrms: 1394.68, Irms: 1394.44, Papp: 1944800.12, Preal: 1944781.12, PF: 1.000                              
1: Vrms: 1394.68, Irms: 1394.28, Papp: 1944575.00, Preal: 1944561.38, PF: 1.000                              
2: Vrms: 1394.68, Irms: 1394.11, Papp: 1944338.12, Preal: 1944327.38, PF: 1.000                              
3: Vrms: 1394.69, Irms: 1394.26, Papp: 1944573.38, Preal: 1944549.25, PF: 1.000     

BTW, if you look in power.c you’ll see I indicate clipping by changing the “:” to a “>” just after the channel number, like this:

CPU temp: 38C, Vdda: 3304mV                                                                                  
0> Vrms: 1394.38, Irms: 1394.16, Papp: 1943993.12, Preal: 1943957.25, PF: 1.000                              
1> Vrms: 1394.38, Irms: 1394.02, Papp: 1943788.00, Preal: 1943759.12, PF: 1.000                              
2> Vrms: 1394.38, Irms: 1393.90, Papp: 1943633.00, Preal: 1943600.50, PF: 1.000                              
3> Vrms: 1394.40, Irms: 1394.05, Papp: 1943860.00, Preal: 1943847.12, PF: 1.000   

Well, possible clipping. It does that if it sees just a single reading of 4095 during that 10 second integration. If it’s just kissing 3.3V than 4095 would be a valid reading so “possible clipping” is probably more accurate than “clipping”. The chances are if you’re hitting 4095 then it’s probably wanting to tell you 4096 on some readings, but can’t.

Yes, that would be my guess. You can see in my numbers above, where I’m bypassing any sensors and feeding a signal straight into the inputs, I get a PF of 1.000. You could try using the ADC-lag feature to calibrate that away. The first thing you want to do is move the two sine waves well away from each other, so that the numbers are bigger. I use 60° when calibrating my energy IC, because I need meaningful Real and Reactive numbers (I use arc-tan rather than arc-cos) to calculate the phase error. But as Robert suggested above, you could use 90° in this case. Then the Preal number being spat out would actually be Preactive and since your dealing with a resistive load, it should be 0.

You do that by editing the call to start_ADC():

  start_ADCs(5000);                 // start ADC with x usec lag

A cycle is 20,000 usecs, so 5000 usecs is 1/4 of a cycle, or 90°. Here’s what I get when I do that with my full-scale deflection sinewave from above:

CPU temp: 39C, Vdda: 3302mV                                                                                  
0: Vrms: 1393.60, Irms: 1393.86, Papp: 1942492.25, Preal: -2365.41, PF: -0.001                               
1: Vrms: 1393.60, Irms: 1393.73, Papp: 1942301.50, Preal: -2353.97, PF: -0.001                               
2: Vrms: 1393.60, Irms: 1393.77, Papp: 1942366.88, Preal: -2371.13, PF: -0.001                               
3: Vrms: 1393.59, Irms: 1393.72, Papp: 1942268.38, Preal: -2350.05, PF: -0.001   

Not quite 0, but close compared to Papp (remember we’re dealing with full-scale deflections here). So to work out my phase error (which ideally would be 0 given I’ve got no magnetics involved) I do an arccos (2365/1942492) which is 89.93°. You can ignore signs in all this. I’m aiming for 90° because I’ve turned my purely resistive load into a purely reactive load. So somewhere I’ve got a 0.07° phase error. My guess at the source of that would be that the signal generator’s idea of 50Hz is slightly different from the F303’s idea of 50Hz.

So if you do all that, you’ll get a pretty good estimate of what your net phase error is (i.e. VT + CT combined). Let’s say it comes out at 2°, you can then turn that back into a usec value: 2/360 * 20000 = 111 usecs (or possibly -111 usecs since we’ve ignored sign in all this) and use that in your call to start_DACs() and you should get much closer to a PF of 1. If it makes it worse, you need to change the sign… i.e. 111 Vs -111.

If you do manage to nail it, you’ll then get a feel for how sensitive it all is to a whole bunch of things including:
. line frequency changes
. V changes
. I changes.

These were all the things I planned playing with when my shield arrives, but feel free to start without me if you’re up for it.

(Robert Wall) #128

And if you keep to A/D units all the way to the final display, there’s no need for user calibration at the head end.

(dBC) #129

Yet another reason for me to upgrade then! Somehow tools upgrades always manages to stay a few notches below the top of my to-do list… probably because too many times the rewards didn’t outweigh the dramas. But I will upgrade… I promise ;-).

Actually, I need to stay in sync with other folks I’m collaborating with on non OEM projects, so I’ve got a few dimensions to this… and I’d prefer not to end up running multiple versions.

(dBC) #130

If I take my line frequency down to 49Hz, my measured phase error goes up to 1.74°, at a more reasonable 49.8Hz it’s 0.29°.

(Paul) #131

Interesting stuff, I will try to do some more tests tomorrow if i have the time, it’s getting pretty late now.

I do need to get my head around the phase errors and correcting them so it would be helpful if do experiment.

(dBC) #132

The maths is definitely the preferred approach, but if you don’t fancy that you can always just go hunting for the right correction. Keep changing the value passed to start_ADCs() until PF comes back close to 1. You can even do it programatically since you can call start_ADCs() as much as you like.

Actually, you could even do the maths programatically. On the press of the Blue button, put in an absolute shift of 90°, get the next 10 second result back, do the arccos to calculate the phase error, turn that back into a usec delay, call start_ADCs() with that and display the result. Provided you only ever pressed the Blue button while it was hooked up to a resistive load, it could self-calibrate the phase error to that load. I wouldn’t want to attempt coding that without a shield to test against, so I’ll code that up when mine arrives, if nobody else has by then.

(Paul) #133

Since it’s a 33R burden and 2000:1 CT, I make it (60.8mV) 0.0608/33*2000 = 3.6848 Amps. Which sounds both right as the kettle is 900w and familiar as I have used this kettle for testing in the past.

As for the PF adjustment that will have to wait for another day, I’m being pestered for work I should have done already, so aside from a few minutes here and there, I’m tied up with less exciting stuff right now.

(dBC) #134

Thanks for doing the CT maths… glad to hear it’s in the right ballpark.

When you do come up for air, that reading suggests a net phase error of about 5.7° (arccos 0.995), which would correspond to passing 318 to start_ADCs(), not sure whether it would be 318 or -318 though.

(Paul) #135

If you could point out where that would need editing (sorry I’m being lazy) I might be able to at least get that reflashed before my next brew and give you the numbers back.

(dBC) #136

The call to start_ADCs() is in main.c just after where it prints out the banner:

 snprintf(log_buffer, sizeof(log_buffer),
	   "\nemonTxshield Demo 1.2\n");
  snprintf(log_buffer, sizeof(log_buffer),
	   "Patch PA0 through to PB14 for V!!!\n");

  start_ADCs(0);                 // start ADC with x usec lag

(Paul) #137

How easy it is to get sucked into doing multiple tests to confirm what you get first time.

starting point at 0 adjustment was

0: Vrms: 1138.36, Irms: 74.97, Papp: 85346.75, Preal: 84903.35, PF: 0.995

So I edited to 316 first and that very little change, but at 0.996 I wondered if we could do better so first I tried -316 to be sure it was the right sign/direction. Since the neg value had such a big swing I tried larger edits first and then narrowed it because they were all way out, but it didn’t get any better.


0: Vrms: 1142.20, Irms: 75.28, Papp: 85984.51, Preal: 85605.85, PF: 0.996

@316 again

0: Vrms: 1145.18, Irms: 75.47, Papp: 86422.79, Preal: 86048.12, PF: 0.996


0: Vrms: 1150.39, Irms: 75.90, Papp: 87309.00, Preal: 85899.79, PF: 0.984


0: Vrms: 1146.39, Irms: 75.77, Papp: 86857.98, Preal: 86314.27, PF: 0.994


0: Vrms: 1141.72, Irms: 75.35, Papp: 86027.18, Preal: 85206.70, PF: 0.990


0: Vrms: 1140.63, Irms: 75.40, Papp: 86000.88, Preal: 85316.49, PF: 0.992


0: Vrms: 1135.41, Irms: 75.09, Papp: 85253.09, Preal: 84608.67, PF: 0.992


0: Vrms: 1139.24, Irms: 75.25, Papp: 85723.21, Preal: 85247.46, PF: 0.994


0: Vrms: 1139.77, Irms: 75.28, Papp: 85798.78, Preal: 85212.43, PF: 0.993

I used the one result that appeared most frequently in the run of serial output for each test, but there were only 4-6 blocks ever printed so not a big data set to draw too many conclusions from. Also as this is done at 3.6 Amps, it is well inside the erroneous first 5% of the 100A CT’s range.

when they are put in numerical order of adjustment the results make even less sense unless the “300” line is discarded.

setting PF
-316 0.984
200 0.995
250 0.994
300 0.992
316 0.996
316 0.996
350 0.993
400 0.992
500 0.990

I did use make clean between compiles and reset the device before each test. I have not checked voltage or frequency at any point so changes in either might have altered the phase error at the VT I guess. Having just said that, looking back at the Vrms (adc counts) recorded for that “300 setting” is 1135.41 and it’s the lowest voltage reading of the batch, but not by a lot.

Perhaps the voltage swing (and frequency?) have an even bigger impact than suspected? or more likely it’s out of the CT’s more accurate range.

Any way, back to work I go :-:smirk:

(ian) #138


I am following this thread with great interest and I think I understand roughly how it all works. Am I correct that if I made the correct shield with 6 CT connections and 3 AC monitor connections and suitable firmware I could monitor a UK three phase installation that also has three phase PV?

Could an EmonESP be serially connected to post the results to an emoncms Rpi ?



(Paul) #139

The example isn’t quite at that stage yet.

The values that are printed are unitless, they are currently just adc steps not volts, amps or watts etc. The output is not in esp format either. It is still very basic, but yes you could take what @dBC has started and run with it, complete it for you own use, but no it’s far from a finished sketch, it’s just early tinkering.

(ian) #140

Hi Paul

I just wanted to confirm my understanding of the number of suitable analogue ports that are available. I am thinking of getting a prototype PCB made with as many ADC connections as possible connected to CT sockets and AC monitoring sockets grouped in the most sensible way which for 3 phase I assume to be 2 CTs to 1 AC in the case of both 3 phase grid and 3 phase PV. I am still trying to understand the tutorial posted by @dBC.

STM32 Nucleo 64 dev pcb
(Paul) #141

That’s something we have been debating and trying to work out ourselves.

There are 22 ADC channels on the 64pin F303 fitted to the Nucleo board, we are aiming for perhaps 15 or 18 CT’s and 3 AC (VT’s) but getting them arranged so that the sampling is done in a synchronized and simultaneous way to avoid adding any further phase error is the trickier part.

Trying to get all 18 + 3 adc channels where we want may not be possible on the 64pin F303 as it is using every adc channel (one will most likely get used for the midrail opamp), the 144 pin version has 40 adc channels, so it may get considered so that it’s easier to implement and there are spares for bespoke applications and future development, not an easy decision because we don’t want to be wasteful, it’s not much more money and the extra channels and IO might give the processor something to keep it busy since sampling 21/22 channels, much faster than we have done before, looks like it might be a breeze for it.

I too would like a PCB with plenty of CT sockets so that I could test the various potential arrangements, so if you do get some made, please keep me in mind :slight_smile:

(ian) #142

I assume you mean the NUCLEO-F303ZE. Its only £14.66 from Farnell which is only about £6.60 more than I paid for the 64 pin. In the scheme of things that’s insignificant. Will the code be the same for both boards?

Any one else have any thoughts on which board to choose? I doubt it will make much difference to the prototype PCB cost which ever one is chosen. But equally I guess there is no point in creating a divided effort.