freerunning ADC without conversion interrupt, failing

Go To Last Post
20 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi!

Intending to make a zero-crossing detect for 50Hz, to use with TRIAC triggering. My true to my habits, have my jurasic oscilloscope at the wrong location, so I try to see if

the circuit works out, by testing sampling when supposed trigger puls. Setup is a negative puls to INT0, should initiate sampling for timespan around a period, well that was the think.

 

Now the INT0 trigger seem to work, connecting the AC reficted for halfperiod "buns", makes the "+" printout come in abundance, seemingly  triggerd at crossing, and stops when removing AC.

 

But the main code, which I thought would hang on ADSC bit, never releases, no "#" coming. What have I gotten wrong, any thinking ?


#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#define LED        PB0
#define LED_PORT   PORTB
#define LED_DDR    DDRB  

uint8_t  volatile sampling;
uint16_t  volatile count;
uint8_t  store[300];

#include "uart_main.h"

char CR=13; char LF=10;
char outstring[10];

uint16_t baud=103;      // 4800 vid 8Mhz clock

int main(){
    uint16_t i;

   LED_DDR   |= ( 1 << LED  );  

   USART_Init(baud);            /* Set up transmitt UART */
   USART_Init_rcv();            /* set up UART reception with interrupt */ 

// -- init ADC

    ADMUX   = ( 1 << REFS0 )|( 1 << ADLAR )|( 1 << MUX2 )|( 1 << MUX0 );  // 0101 to MUX3:0
    ADCSRA  = (1 << ADPS2)|(1 << ADPS1)|(1 << ADPS0)|(1 << ADFR);          // 111 to ADPS2:0

// -- init INT0 for triggering on down-flank (to zero)

    GICR   |= 1<<INT0;       // enable INT0 interrupt
    MCUCR  |= 1<<ISC01;      // falling, ISC00 =0 default

    i=0;

    LED_PORT  |= ( 1 << LED  );
    USART_Trsm_string("** hello zero cross trigg **") ;

     ADCSRA |=(1<<ADEN); 

     sei();   // I-bit SREG set, general interrupt enable

     while(1) {

         sampling = 0;

         while ( !sampling || (ADCSRA&(1<<ADSC)) );   // live wait
    USART_Trsm_string("##");

         ADCSRA |= (1<<ADSC);    //re start

         // count each 10, then store
         if(! (count%10 == 0) ) continue;

         store[i] = ADCH; i++;
 //        itoa(ADCH,outstring,10); USART_Trsm_string(outstring ) ;
         count++;

         if (i > 30) {
            // 130 ADCs should be around 20ms, ie on 50Hz cycle, output

            ADCSRA &=~(1<<ADEN);    // stop ADC for a while

            for (i=0; i<=30; i++) {
                // print
               itoa(store[i],outstring,10); USART_Trsm_string(outstring ) ;
               USART_Transmit(CR); USART_Transmit(LF);
            }
            i=0;
            ADCSRA |=(1<<ADEN);
         }
     }
}

ISR( INT0_vect ) {     // interrupt
    USART_Trsm_string("++");
     ADCSRA |= (1<<ADSC);    // start AD  -- ger OMSTART/reset
     sampling = 1;
     count = 0;    // kommer ställa till det vid halva period
     return;
}

ISR( BADISR_vect ) {     // interrupt
     while(1) {
         _delay_ms(50);
         LED_PORT   ^= ( 1 << LED  );
     }
}

The LED for bad interrupt never lights up.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Please show your circuit---that is the starting point for success

Watch out for high voltage---use isolation

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

gechxx wrote:

         while ( !sampling || (ADCSRA&(1<<ADSC)) );   // live wait

But in "Free running" mode you set the ADSC and then (unlike one-shot) it does not return to 0 but remains at 1 forever.

 

It's ironic because we often see code like:

uint16_t ADC_read() {
    ADCSRA |= (1 << ADSC);
    while (!(ADCSRA & (1 << ADIF)));
    ADCSRA |= (1 << ADIF);
    return ADC;
}

where a user starts the conversion with ADSC but then waits for indication of completion with ADIF but this means that they then need to clear ADIF (by writing 1) so it's ready to use next time. So we habitually suggest making it "simpler" with:

uint16_t ADC_read() {
    ADCSRA |= (1 << ADSC);
    while (ADCSRA & (1 << ADSC));
    return ADC;
}

and for "one-shot" this works because the first line sets ADSC then the next line uses ADSC not ADIF to watch for completion of conversion (on the basis that ADSC goes back from 1 to 0 at completion).

 

HOWEVER the free-running mode is not like this. When you set up to do free-run and then you finally set ADSC to start things the whole process starts and ADSC then never goes back to 0. So you cannot sit in a while() loop watching for it doing the 1->0 transition because it won't. This is the one occasion where you must use ADIF to signal completion. Then, like before, (if not using ISR) you must manually clear ADIF (by writing 1) so it's ready for use the next time around the loop.

 

But why even bother anyway? Part of the reason for free running is that you can just "dip in" at any time and read ADC or ADCH (ADLAR). Sure it might still have the same value as last time because it's not actually been updated with a new conversion result - but why does it matter? It's continuous. It's just a "snapshot" of what the input is doing just now. If you do put in code to actually wait for ADIF then you will simply be spacing out your sample points so they are 66us (or whatever the conversion time period is) apart.

Last Edited: Fri. Jan 14, 2022 - 10:08 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

HOWEVER the free-running mode is not like this. When you set up to do free-run and then you finally set ADSC to start things the whole process starts and ADSC then never goes back to 0.

Ah this, is what I had thought. The spec for m8 is not clear on this point. However I found an AN for tiny that actually states that IT GOES TO ZERO when conversion is ready. (possibly I did missread that for being for free-running, will go back and check). And yes, should have started with saying, havnt used freerunning before.

 

But why even bother anyway? Part of the reason for free running is that you can just "dip in" at any time and read ADC or ADCH (ADLAR). Sure it might still have the same value as last time because it's not actually been updated with a new conversion result - but why does it matter? It's continuous. It's just a "snapshot" of what the input is doing just now. If you do put in code to actually wait for ADIF then you will simply be spacing out your sample points so they are 66us (or whatever the conversion time period is) apart.

Ah again, thanks. Think this is the key for approach to free-running, that I had missed. I thought the "prescale" bit would supply a sampling rate.  (i HAD got that waiting for intterupt when not using interrupt was kind of wrong :).

 

candies; will be back with a circuit sketch, and yes Im safe so far, working 12V AC

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sketch included

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Actually, then, the term "freerunning" is more semantically significant and accurate, than one would expect  as used to todays more "inventive" terminology.  :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


easier if it's in the post - where we can see it:

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Right (tried but it got blown up so big... so I attached). Well the 12V is a bit sloppy, it is 12 before diode bridge, so its 6V times formfactor (1,4 like).  Did consider going for

mains to get sharper dips, but I think this can do, if delay from trigger on negative slope is determined (hence the sampling). Then the 4,0 in wave sketch is changed in actual to 4,7 since

the only zener I had in range. It does seem to tick on INT0 sofar.

Last Edited: Fri. Jan 14, 2022 - 12:03 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

gechxx wrote:
it got blown up so big

resize before posting wink

 

also crop

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Well, your schematic needs some work, but at least it shows you are using a transformer between the line, to get 12V, correct?

 

DO NOT make a direct connection between the AC line & AVR...use a transformer or optocoupler (or both).  An optocoupler is safer, in that it is rated for a high breakdown (like 3000 or 5000V)....whereas a cheapo transformer might breakdown (lose its isolation) at 300v, or some low value.

 

4.7V is no good for a 12V zero crossing--you would be NOWHERE near zero degrees.  However, the 4.7 is just a clamp, you are turning on a transistor (at 0.7V), plus some  20k/40k divider...so that is better, but still 4 or 5 degrees late....good enough for now.

However, the wave is not a sinewave like you see in math class---it is a jaggedly rotten looking thing...draw one after you have had your hand run over by a Mac truck.

All those shakes means you will get lots of interrupt, not just one interrupt.

At this very low freq (50Hz), you can easily start out with polling the pin---you will get very good timing.  

 

If you want to use IRQ, add some signal hysteresis.  Or you can cheat and:

When the AC IRQ happens, shut off the AC IRQ & turn on a timer IRQ (say for 5ms)

The AC IRQ is now blocked for a while (spurious sig then can't get in)

When the timer IRQ happens, use it to turn the AC IRQ back on.

This gets rid of (blocks) spurious, but might react (respond) to an early incorrect noise spike (blocking the upcoming good signal).

 

ADD A capacitor across the 40K---will clean spiky noise up, and barely have any ill effect of delay. Try a 0.01 uF cap, even 0.1uF will be less than 1ms delay (but 1 ms is somewhat a lot for a 20 ms  period)

Note while 0.01uF smooths the shaky wave, the extra slowness might cause more detection responses as it sloooowly crosses the threshold.  So a bit of a trade off.  Try it and see.  You generally want to cross thresholds fast...but fast response means  fast noise spikes get through too.

 

Draw your schematics IN PENCIL, or draw them using solder (as Bob Pease favored)

 

 

 

 

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

solder seem more firm  :)

will get hold and dust off my osc any day now so Ill be able to see little better, and thanks a lot all, will test some more and possibly will sort throu. Be back.

(or Ill just cheat and go for a polling scheme....)

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

gechxx wrote:

it got blown up so big

 

resize before posting wink

 

OT:  With my W7/Firefox setup (platform probably unrelated)  I've found that the forum post resize doesn't always want to work with a large photo.  I've also found that if I post the large photo anyway being patient, then edit and resize, it will work OK. YMMV

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

I just resize pictures in good old MS Paint before posting (I do this to other people's pictures when making attachments visible too).

 

I usually think W=1024 is a "good size" and let the H sort itself out (while maintaining aspect ratio)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, and thanks. I was into Paint, unsuccessfully . (used GIMP to reduce size from 1M+ to 125k..., but format in some way made it blow up)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:

Well, your schematic needs some work, but at least it shows you are using a transformer between the line, to get 12V, correct?

 

DO NOT make a direct connection between the AC line & AVR...use a transformer or optocoupler (or both).

 

OMG, can we please stop treating people as if they were children? (Unless they come out with being electronic rookies, of course) Naturally it is always preferable to avoid direct connections to the mains, but if there is a good reason to it, and the designer knows their way around and how to take proper precautions then there is nothing wrong with it. In the US, connecting a mains plug into the wall socket is more dangerous, as it is handled by clueless people and children, seems nobody finds it wrong to have the most dangerous mains plug standard in the world.

 

avrcandies wrote:

Draw your schematics IN PENCIL.

 

So now we really got into kindergarten ... sad

 

One bit of advice that may really help here has not been forthcoming. I think it is a bad idea to rectify the voltage, and detect the zero-crossing with the rectified signal. This is potentially unreliable, because the power line is messy (as was pointed out before), and if some of the interference on the power line causes it to cross the zero very fast, then the period where the rectified signal stays near zero becomes extremely short. You may also want to filter a bit, doing that to the rectified signal completely prevents it from reaching zero, and smoothes the voltage such that detection of the voltage minimum does not deliver an accurate zero detection anymore.

 

A potentially simpler and more reliable version, that doesn't need much filtering, does not rectify, as follows. Bias one of the transformer output lines with a voltage divider to roughly 2.5V (assuming 5V power supply for MCU), and feed it into one of the inputs of a comparator. Have a series (current limiting) resistor at the other transformer output line, before you feed them through two anti-parallel diodes (limiting the voltage) to the other transformer line. Connect the junction between the current limiting resistor and the diodes to the other input of the comparator. The comparator output gives you a nice zero-detect signal, that you can connect to an MCU interrupt line. No ADConversion necessary. Remember comparators usually have open-drain outputs, so'll need to activate the port pin's pullup.

 

Some AVRs have a comparator built in that is exactly meant for this kind of purpose, it can generate an interrupt of course. This way, you won't need any external active components. On the other hand, using an external comparator allows choosing one that has extended input voltage range beyond the rails, in which case you might not need the voltage limiting components (the diodes, and hence neither the current limiting resistor). Just connect the transformer outputs to the comparator inputs, but you will still need the biasing divider.

 

Whatever you choose, including your own design, keep in mind that the connecting electronics introduces a fixed delay. For switching large main currents you may need to measure it and take into account. Note that filtering makes that worse!

Cheers  Peter

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

perot wrote:
OMG, can we please stop treating people as if they were children?
Well you say that but we see a lot of posts here from people interfacing to 220V and seemingly not having much idea what they are up to (BTW I do NOT mean OP in this thread). I often wonder if we should have a blanket ban on helping people working with mains voltage in case someone was told to do something here and through mis-interpretation or whatever they ended up killing themselves - who would be held liable?

 

So, no, personally I don't think it hurts to point out the potentially very serious risks of connecting open circuits to lethal voltages. Far too often I've seen threads here where it's clear the person experimenting doesn't even know what an "isolation barrier" is !

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


You can also try this one:

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
I usually think W=1024 is a "good size"

I used 800 in #7

 

and let the H sort itself out (while maintaining aspect ratio)

indeed. 

 

theusch wrote:
I've found that the forum post resize doesn't always want to work with a large photo

I think it probably would work, eventually - but it does take an exceedingly long time

 

frown

 

Also, I think it's previously been noted that it doesn't actually scale the file size?

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Fri. Jan 14, 2022 - 07:03 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks a lot Perot !  Will see if I get my head around your proposal. Actually I could have done some more research from the beginning. And one mignt note that the initial question was

actually about ADC reading, for a hipshot test, which possibly was a bit too lazy to figure, and instead ask this emminent and benevolent forum. And now I have got very much good input and a set of solutions :)

As to as:  if they were children

No problem with me. Forums are intrinsically difficult in determining the level of participants. And as clawson points out, one has sometimes serious doubts about any level. Actually my own level can be a bit bumpy ;)

 

Again thanks all.

 

Ed: Note not not ...

Last Edited: Fri. Jan 14, 2022 - 08:11 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi, so, the validity of zerocrossing is not tested on the real thing, but there is at least indication that approach could

possibly work, the "mid zero" is quite constantly on 96, sometimes going for 97... the code a little modified give below

 

 

#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#define LED        PB0
#define LED_PORT   PORTB
#define LED_DDR    DDRB  

uint8_t  volatile sampling;
uint16_t  volatile count;
uint8_t  store[300];

#include "uart_main.h"

char CR=13; char LF=10;
char outstring[10];

uint16_t baud=103;      // 4800 vid 8Mhz clock

int main(){
    uint16_t i;

   LED_DDR   |= ( 1 << LED  );  

   USART_Init(baud);            /* Set up transmitt UART */
   USART_Init_rcv();            /* set up UART reception with interrupt */ 

// -- init ADC

    ADMUX   = ( 1 << REFS0 )|( 1 << ADLAR )|( 1 << MUX2 )|( 1 << MUX0 );  // 0101 to MUX3:0
    ADCSRA  = (0 << ADPS2)|(1 << ADPS1)|(1 << ADPS0)|(1 << ADFR);          // 111 to ADPS2:0

// -- init INT0 for triggering on down-flank (to zero)

    GICR   |= 1<<INT0;       // enable INT0 interrupt
    MCUCR  |= 1<<ISC01;      // falling, ISC00 =0 default

    i=0;

    LED_PORT  |= ( 1 << LED  );
    USART_Trsm_string("** hello zero cross trigg **") ;

     ADCSRA |=(1<<ADEN); 

     ADCSRA |= (1<<ADSC);    // start AD  

     while(1){

       sampling = 0;
       i=0;

       sei();   // I-bit SREG set, general interrupt enable

       while ( !sampling ) ;   // live wait

       while(1) {

          // trigg (hopefully at/near zero-cross
          // sampel a period ... intended

          cli();   // we dont want another interrupt for some time
          GICR   &= ~(1<<INT0);       // disable INT0 interrupt   

          _delay_us(100);    // whole period 20ms then 100samples, at .1 is half wave
          store[i] = ADCH;
          i++;

          if(i == 100) break;

      }  // ** end sample loop

      i=0;

      for (i=0; i<100; i++) {
         // print
         itoa(i,outstring,10); USART_Trsm_string(outstring ) ;
         if(i<10)USART_Trsm_string(" " );if(i<100)USART_Trsm_string(" " ) ; // pad for left adjust strait
         USART_Trsm_string(": " ) ;
         itoa(store[i],outstring,10); USART_Trsm_string(outstring ) ;
         USART_Transmit(CR); USART_Transmit(LF);
      }
      i=0;

      sei();  // we run another round

      while( UART_IN == 0 ); 

      GICR   |= 1<<INT0;       // enable INT0 interrupt

  }

}

ISR( INT0_vect ) {     // interrupt

     sampling = 1;
     return;
}

ISR( BADISR_vect ) {     // interrupt
     while(1) {
         _delay_ms(50);
         LED_PORT   ^= ( 1 << LED  );
     }
}

(the UART_IN is set when there is input from uart, reset when fetching that input, so not fetching releases free run)

 

ed: the circuit is as in the previous pen-cad :)

Last Edited: Sun. Jan 16, 2022 - 12:51 PM