EmonLib CM on a ATmega32U4 MCU

Hi to All,

As described in my post Multichannel Home Electricity Monitoring System I succeeded to run EmonLibCM on Olimex AVR-T32U4 board (Arduino Leonardo compatible) using all 12 ADC inputs as single ended and everything works fine. Later on I have made some steps to investigate usage of HWCT-5A/5mA current sensor. All this is described in Multichannel_Home_Electricity_Monitoring_System.pdf and on the Olimex forum tread.

Next step in my plan was to test using of differential inputs on ATmega32U4 MCU. As expected selection of corresponding inputs/gain combination works fine but the result is wrong as amplitude. Because of added by me ability to capture and print ADC raw data I see that the problem comes at switching between single ended and differential channels. Probably the problem comes from the need of more time like described in ATmega32U4 datasheet:

Special care should be taken when changing differential channels. Once a differential channel has been selected, the stage may take as much as 125μs to stabilize to the new value. Thus conversions should not be started within the first 125μs after selecting a new differential channel. Alternatively, conversion results obtained within this period should be discarded.

One possible solution is to double first differential input and discard the first sample. I tested this by scanning only differential channels and it works fine. Doubling first differential input is possible because the channels sequence used by me is to scan first single ended inputs and then differential once.

Is there another solution of this problem?

Thanks in advance

[I created a new Topic because this isn’t specifically about emonLibCM, but a quite different version thereof.]

I’m afraid I still don’t have the time to look in detail at your problem, so there’s little I can do to help at the present time.

However, what I would ask is, why is it necessary to switch between single-ended and differential? What is at about your hardware that makes it necessary to have both?

Thanks Robert for you prompt replay.

I would like to use all available inputs. The single ended inputs are 12 (1 for voltage and 11 for currents). If I can use both single ended and differential inputs I will have 15 inputs (6 single ended and 9 differential). On the other hand differential inputs are noise immune and with gain control small currents can be measured with better precision.

BTW I tested the idea to double first differential channel in the sequence and it works fine. This is the easier way and I will make later on changes in calculations for differential channels and probably everything will be fine. I will post new results when ready.

Thanks again


The first observation about doubling the first differential channel in the sequence was wrong. It works but not as expected. Further investigation uncover that not all figures are exact. My findings are shown on the following picture

and also on updated version of the file Multichannel_Home_Electricity_Monitoring_System.pdf.

Probably the problem is in timing and phase calculations but it is difficult for me to understand whole library logic so any help will be welcome.

Other encountered problems are impossibility to use differential pair ADC0/1 together with other combinations and lack of gain 1x for some of the differential pairs. Using 13 instead of 14 current sensor is not big issue. The gain problem was solved with using of lower burden resistor and gain 10x, 40x and 200x. Gain 200x is maybe unreliable but later tests will show.

Thanks in advance

Hi to All

I have probably find the problem. It comes when differential inputs sampling is added. In ATmega32U4 datasheet is written that the conversion takes 13 clocks for single ended input conversion but 14 for differential. On the other hand there is additional time for synchronization up to 3 clock cycles. All these details and the fact that in used by me sequence the scanned inputs are 6 single ended and 8 differential probably effective ADCDuration should be something different from 104us (@13 clocks) and 112us (@13 clocks) . That is why I investigate firmware behavior for different integer values of ADCDuration. The measured mains frequency vs ADCDuration value is shown on the following picture:

As a result if ADCDuration = 117 is chosen the measured figures become like expected:

{ Va: 225.23, Hz: 49.796, Sp: 1,
  Ia: [ 64.327, 16.052, 16.050, 16.058, 16.056, 16.084, 16.084, 16.080, 16.079, 16.097, 16.087, 16.081, 16.079 ],
  PF: [ 0.9974, 0.9956, 0.9955, 0.9954, 0.9952, 0.9972, 0.9972, 0.9973, 0.9973, 0.9973, 0.9973, 0.9973, 0.9973 ],
  Wr: [  14451,   3599,   3599,   3600,   3599,   3612,   3612,   3612,   3612,   3616,   3614,   3612,   3612 ],
  Wa: [  14488,   3615,   3615,   3617,   3616,   3623,   3622,   3622,   3621,   3626,   3623,   3622,   3621 ],
  Wh: [    177,     44,     44,     44,     44,     44,     44,     44,     44,     44,     44,     44,     44 ],

Is that solves the problem with wrong calculated figures in a right way?


Is the ADC “free running” - meaning it generates an interrupt and it is in the Interrupt Service Routine that you do the first step in the calculations, for example calculate the instantaneous power and accumulate it, and current² and voltage², like emonLibCM?

If that is the case, you must allow time for the rest of the program - the part that calculates the rms values and sends the data to wherever you need it - to operate, in between the time it takes inside the ISR. So you might find that you must slow the sampling time to allow for the main program loop to run - because of course it stops each time a sample is available, then continues when the ISR has finished.

A p.f. > 1.0 cannot directly be caused by the ADC period, it can only come from wrong values of apparent power and real power. The reason those are wrong is what you are looking for, and missing some calculations could easily be the cause. So could the interpolation calculations to time-shift the voltage so that the voltage sample appears to coincide with the current sample. If the voltage sample is amplified in that calculation, real power can be bigger than apparent power; which physically is impossible.

Thanks Robert,

I am using latest version of emonLibCM from the forum with very small changes in global variables and EmonLibCM_interrupt() like:

  if ((ADC_MuxSeq[next] & (1 << MUX5))) ADCSRB |= (1 << MUX5);
  else ADCSRB &= ~(1 << MUX5);
  ADMUX = ADCRef + (ADC_MuxSeq[next] & 0x1f); // set up the next-but-one conversion
//  ADMUX = ADCRef + ADC_Sequence[next];      // set up the next-but-one conversion
    if (!channel_doubled && (doubled_channel == sample_index)) {  // above printout
//    if (!channel_doubled && (doubled_channel == next)) {        // below printout
    channel_doubled = true;
  } else {
    channel_doubled = false;

  if ((ADC_MuxSeq[sample_index] & 0xc0) > 0) { // calculation for differential channels 
    if (rawSample < 511) rawSample = 512 - rawSample;
    else rawSample = 512 - rawSample + 1023;

That is why all calculations are the same and for now gain is compensated by the burden resistor used. The changed global variables looks like:

// in case of s + d connections
static const int max_no_of_channels = 13; // Maximum number of Current (I) channels used to create arrays
int no_of_channels = 13;  // Number of Current (I) channels used by 'for' loops
byte doubled_channel = 6;
// <-- Sensor types: CT01 - SCT013, CT02-14 - HWCT-5A; Connection: s - single ended, d - differential
// <--                                           |        single ended inpits            |>DOUBLE<             diferential inputs                    !!!!!|
// <-- Sensor number                                VT  CT01s  CT02s  CT03s  CT04s  CT05s   CT06d  CT07d  CT08d  CT09d   CT10d  CT11d  CT12d  CT13d   CT14d
// <-- The analogue ports sequence               adc13  adc12  adc11  adc10  adc09  adc08  adc7/1 adc6/1 adc5/1 adc4/1  adc7/0 adc6/0 adc5/0 adc4/0  adc1/0
static byte ADC_MuxSeq[max_no_of_channels+1] = {  0x25,  0x24,  0x23,  0x22,  0x21,  0x20,   0x6f,  0x6e,  0x6d,  0x6c,   0x6b,  0x6a,  0x69,  0x68}; //,   0x49};
double currentCal[max_no_of_channels] =        {        90.04, 21.20, 21.20, 21.20, 21.20,  21.20, 21.20, 21.20, 21.20,  21.20, 21.20, 21.20, 21.20}; //,  21.20};
double  phaseCal_CT[max_no_of_channels] =      {        -40.2, -40.2, -40.2, -40.2, -40.2,  -40.2, -40.2, -40.2, -40.2, -40.2,  -40.2, -40.2, -40.2}; //, -40.2}; 
long wh_CT[max_no_of_channels] =               {            0,     0,     0,     0,     0,      0,     0,     0,     0,     0,      0,     0,     0}; //,     0};

Before adding the deferential inputs in scanning sequence everything was like expected and the problem comes after using mixed channel sequence.

I am sure that the timings needed to make calculations inside interrupt routine is changed a little and cannot influence over the calculated results.

So my question is about the way of solving the problem changing ADCDuration value.


It can. You need to find out what happens when an interrupt happens before the previous one has been dealt with. If there’s not enough time left for the main program to do all it needs to, anything can happen - most likely data will be overwritten and lost.

For sure and may be you are right. I try some quick tests with commenting some of code I added in EmonLibCM_interrupt() and behavior is changed. Definitely it is unbelievable that the time it takes the interrupt routine in the original emonLibCM code to finish all the calculations is so critically close to the time it takes to convert sample. If so added by me a few calculations can make the mess in the interrupt timing.

Unfortunately, currently used clk/128 ADC frequency is the lowest possible so is there other way to enlarge the sampling time?

The timing in the original ATMega 328P:

This was an emonPi with only 2 current inputs.

Without reading the data sheet, I cannot say. And I really don’t have time to do that for you - sorry.

OK thanks, probably this is the source of the problem so it will take some time to investigate it deeply. I will notify you when ready. Thanks again for the time you spend for me.

BTW I have just measure the time of added by me code: 3us

Have a nice weekend.

Hi Robert,

I have done more tests with mixed (6x VT/CT single ended and 8x CT deferentially connected) sensor sequence. You can see the modifications and oscillogram of the timings from the modified emonLibCM library (Version 2.2.2 15/9/2022).

As can be seen, the additional code takes 3us. It is also seen the part of the scan sequence with the last single ended input (conversion time 104us) and the first differential one (conversion time 112us). The times at current readings left for the main loop are 42us and 50us instead of 62us and there is no any side effects from that. The time distribution in the interrupt routine is quite similar to that from the original emonLibCM library. It can also be seen doubling and discarding of calculations for the first differential input. There is no observation for overlapping of ADC interrupts at all. These facts suggest that the additional code is not the cause for the wrong calculations as shown on the next picture.

The problem with wrongly calculated figures is solved if ADCDuration value is set to 117us instead of 104us or 112us (derived empirically). It is also empirically derived (but not logically explained) that for the right functioning the code for doubling the first differential input scan have to use following condition: (!channel_doubled && (doubled_channel == sample_index)). It can also be seen in the oscillogram (but not logically explained) that the first 112us conversion interval (coming from differentially connected CT) is from regular interrupt routine execution while the second one is from skipped interrupt processing.

More details can be found on the updated version of the file Multichannel_Home_Electricity_Monitoring_System.pdf.

I will try to investigate deeply how ADCDuration value influence over measured and calculated values of electrical quantities.

BTW I have tested ADC triggering from a timer with larger periods (120-250us). The problem with wrong calculation was still present but interrupt processing was not stable at all.

Best regards

Hi to All,

I have given another try of using timer for ADC triggering but setting now fast PWM mode with auto-reload for timer 1. This way ADC triggering is granted stability of the period by the hardware so scenario is quite similar to ADC auto-triggering. Trying with different periods (120, 128, …, 148us) gives the same result as in ADC auto-triggering case. For having exact calculating values ADCDuration has to be larger than the triggering period. For example ADCDuration should be set to 128 for triggering period 120us.

I did not exact assessment but my feeling is that ratio (ADCDuration / triggering period) is as closer to 1 as (mains period in us / (triggering period * (max_no_of_channels + 2 ))) is closer to integer. In second expression +2 is because 1 sample is doubled.

Unfortunately, I did not found the reason for wrong calculations in case of using mixed (single ended and differential) ADC inputs in the scan set until now.

My question is: it there any reason for not using empirically settled ADCDuration value in case of using mixed (single ended and differential) ADC inputs in the scan set?

Best regards

Hi to All,

While the problem with mixed (single ended and differential) ADC inputs in a common scan set still exists, a test bench for the MEM system was developed:

Both MEM system and its test bench consists of the following components:

The result is possibility to test and calibrate at 50Hz or 60Hz of the both voltage (up to 250Vac) and current (up to 100Aac) sensors. Total consumption of the test bench do not exceed 3W and it works on a battery completely autonomous and isolated from the mains. All signals including phase differences can be monitored by oscilloscope and multimeters.

More details can be found on the updated version of the file Multichannel_Home_Electricity_Monitoring_System.pdf .

Best regards

Hi to All,

MEM system test bench was tested and works fine with 2x batteries (3.7V and 14.8V), 2x adapters (5V and 12V or 24V) and single adapter (5V/1.5A + 12V/1.5A). It simulates 50Hz sinusoidal voltage up to 250Vac and currents up to 16/64Aac while the total power consumption is only 4.5W ([email protected]).

Special attention was paid to the common ground to prevent the influence of the high starting current of the audio amplifier on the MCU. The main 12V supply and the common GND are connected to the DC-DC convertor and the audio amplifier boards. Voltage and current measurement device is also connected between the power supply and the other boards. The common GND of the DC-DC convertor and the audio amplifier boards is connected to the MCU board together with its output sinusoidal signal. Only the 5V of the power supply is connected to the MCU board while the common GND is taken via the DC-DC convertor and the audio amplifier boards.

In final varian when complete independence is not a must scenario with single adapter is used and more tests with MEM system (simple variant with single ended inputs only) was done. Assessment of the waveforms quality was made in the beggining.

The total voltage and current deviations are in the interval from 1% to 1.6% while the generator’s one (modulated PWM) is 0.08%. The relatively big dispersion of the signals is mainly caused by the discretization.

Later on the individual and the averaged waveforms of the voltage and the currents for both SCT013 100A 50mA and HWCT-5A/5mA sensors were measured and proceed off-line.

In addition to the waveform graphs calculated total RMS values and their deviations are shown. As it can be seen the latest version of the test bench grants extremely stable values for both the voltage and the currents (0.016% and less). Without matter that waveform deviations from sinusoidal form are relatively big (up to 17% at given individual points) the total deviations of the voltage and the currents are less than 1.15%. The deviations were calculated for both the waveforms (DEVi = Xi / Si – 1 in % where X is the real signal and S is the sinusoidal one) and the total values (DEV = CF / √2 – 1 in % where the crest factor is CF = Xpeak / Xrms ignoring the DC component of the signals).

All details around this project can be found in the regularly updated file Multichannel_Home_Electricity_Monitoring_System.pdf .

Best regards

1 Like