ADC and internal RAM

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

Hi Freaks,

I am using an Atmega48 ADC to collect some samples of a sine wave. I am trying to save samples in the M48 RAM (512 bytes). I am using an array of 256 bytes to store each 8 bit value and when all 256 bytes have been saved, I am transmitting the RAM contents through UART.

Here is my code:


#include 
#include 
#include 
#include 

#define USART_BAUDRATE 115200
#define BAUD_PRESCALE (((14746000/ (USART_BAUDRATE * 16UL))) - 1) //value to load into UBRR

volatile unsigned char ADC_Buffer[256];
volatile unsigned char i,j;
volatile unsigned char flag;

void USART0_init()
{


   UCSR0B |= (1 << RXEN0) | (1 << TXEN0); // Turn on the transmission and reception circuitry
   UCSR0C |= (1 << UCSZ01) | (1 << UCSZ00); //Set to 8 bit no parity, 1 stop bit
   UBRR0L = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register
   UBRR0H = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register
}

void USART_putchar(unsigned char c)
   {

     while ((UCSR0A & (1 << UDRE0)) == 0) {};
   
     UDR0 = c;

}

void ADC_init()

  {
     ADCSRA |= (1 << ADPS2) | (1 << ADPS0) | (1 << ADATE);
	 //using /32 prescalar
     ADMUX = (1 << REFS0) | (1 << MUX2) | (1 << MUX0) | (1 << ADLAR); // Set ADC reference to AVCC,select channel 5
   //using all 10 bit of ADC; so do not left justify the ADC value
     DIDR0 = (1 << ADC5D); //turn off the digital driver
    ADCSRA |= (1 << ADEN);  // Enable ADC
    ADCSRA |= (1 << ADIE);  // Enable ADC Interrupt
   sei();   // Enable Global Interrupts
    ADCSRA |= (1 << ADSC);  // Start A2D Conversions
  }

void timer_init()
  {

   TCCR1B |= (1 << WGM12);
   TIMSK1  |= (1 << OCIE1A);

   sei();

   OCR1A = 2000;

   TCCR1B |= (1 << CS12) | (0 << CS11) | (0 << CS10);

  }

ISR(TIMER1_COMPA_vect)
 {

   PORTD ^= (1 <<PORTD7);
                  
 }

ISR(ADC_vect)
  {
                            
              if(i<256)
                 {
                     ADC_Buffer[i] = ADCH;
		     i++;
		 }
		else
		 {
					    
		   flag = 1;
		}

  }
int main (void)
    {   

      DDRC = 0x0F;
      DDRD = 0xC0;
      USART0_init();
      ADC_init();
      timer_init();
   
            for(;;)
              {
                
          
                 ADCSRA |= (1 << ADSC);
                 if(flag==1)
                  {
                   for(j=0;j<256;j++)
		     {
						                             USART_putchar(ADC_Buffer[j]);
			}
                    }
               }
     } 

I am not getting anything in my capture file from the hyperterminal. What may be missing?

Thanks.

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

Perhaps pre-load your array (don't worry about ADC) and make sure the "Hello world" transmission is working OK.

(From the description of "not getting any" it doesn't give us much to go on.)

Then move back from there--load dummy data in the ADC ISR.

Note that i will >>always<< be less than 256. ;) (and this could be the hangup...)

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: 0

You got me! I read the comment that says you are using 10 bit mode and I thought Aha! 256 bytes will only hold 128 10 bit samples. But I guess that misleading comments arent what is causing the program to not work....

Imagecraft compiler user

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

Quote:

I read the comment that says you are using 10 bit mode ...

... which was a lie just to trip us up. But I'm too sharp to fall for that old gag, Bob.

Lee

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: 0

Ah, the old un-maintained comment trick! One of the few ways a software engineer can earn a (dis-)honest buck nowadays. Oh, all right.. There's the confusing indentation trick also.

I eagerly await the common discovery of the Preview button. :roll:

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Sorry about the confusing comments.
I tried some more and here is what I have:

#include 
#include 
#include 
#include 
#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((3680000/ (USART_BAUDRATE * 16UL))) - 1) //value to load into UBRR

volatile unsigned char ADC_Buffer[20];
volatile unsigned char i,j;
volatile unsigned char flag;

void USART0_init()
{


   UCSR0B |= (1 << RXEN0) | (1 << TXEN0); // Turn on the transmission and reception circuitry
   UCSR0C |= (1 << UCSZ01) | (1 << UCSZ00); //Set to 8 bit no parity, 1 stop bit
   UBRR0L = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register
   UBRR0H = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register

}


void USART_putchar(unsigned char c)
   {

     while ((UCSR0A & (1 << UDRE0)) == 0) {};
   
     UDR0 = c;

}


void ADC_init()

  {
     ADCSRA |= (1 << ADPS1) | (1 << ADATE);
	 //using /4 prescalar
     ADMUX = (1 << REFS0) | (1 << MUX2) | (1 << MUX0) | (1 << ADLAR); // Set ADC reference to AVCC,select channel 5
	 //Use only 8 bits of ADC (ADCH)
     DIDR0 = (1 << ADC5D); //turn off the digital driver
    ADCSRA |= (1 << ADEN);  // Enable ADC
    ADCSRA |= (1 << ADIE);  // Enable ADC Interrupt
   sei();   // Enable Global Interrupts
    ADCSRA |= (1 << ADSC);  // Start A2D Conversions
  }

void timer_init()
  {

   TCCR1B |= (1 << WGM12);
   TIMSK1  |= (1 << OCIE1A);

   sei();

   OCR1A = 2000;

   TCCR1B |= (1 << CS12) | (0 << CS11) | (0 << CS10);

  }

ISR(TIMER1_COMPA_vect)
 {

   PORTD ^= (1 <<PORTD2);//Blink portD2
                  
 }



ISR(ADC_vect)
  {
     for(i=0;i<20;i++) //collect 20 samples
	{
					              ADC_Buffer[i] = ADCH; //tried ADC_Buffer[i] = 'H' and it worked
	   ADCSRA |= (1 << ADSC);
	 }
                if(i == 20) //if finished set flag= 1 to send samples to hyperterminal
		   {
		     flag = 1;
//Do I need a disable ADC here?
                    }
 
  }
int main (void)
    {    

	  DDRC = 0x0F;
          DDRD = 0xFF;
          USART0_init();
          ADC_init();
          timer_init();
	     
            for(;;)
             {      
                        
                 if(flag==1)
                    {
 							                for(j=0;j<20;j++)
							                USART_putchar(ADC_Buffer[j]);
                         
                         flag = 0;

						  

                    }
              }
     } 

On my hyperterminal I am getting a continuous display of 8 bit (hex) sample values. I tried doing ADC_buffer[i] = 'H' and the hyperterminal showed me a continuous display of 'H'.

How can I just see only the 20 samples that I have stored in RAM? Do I have to disable the ADC in the if loop in the ISR? Or do I need a switch input and then display the 20 sample values in the ISR for the switch?

I am not able to distinguish if these samples are the RAM stored samples or real time captures.

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

Do you not find this:

ISR(ADC_vect) 
  { 
     for(i=0;i<20;i++) //collect 20 samples 
   { 
                             ADC_Buffer[i] = ADCH; //tried ADC_Buffer[i] = 'H' and it worked 
      ADCSRA |= (1 << ADSC); 
    } 
                if(i == 20) //if finished set flag= 1 to send samples to hyperterminal 
         { 
           flag = 1; 
//Do I need a disable ADC here? 
                    } 
  
  }

very difficult to follow with your indentation all over the place? After cleaning it up it looks like this:

ISR(ADC_vect) { 
    for(i=0;i<20;i++) //collect 20 samples 
    { 
        ADC_Buffer[i] = ADCH; //tried ADC_Buffer[i] = 'H' and it worked 
        ADCSRA |= (1 << ADSC); 
    } 
    if (i == 20) //if finished set flag= 1 to send samples to hyperterminal 
    { 
        flag = 1; 
        //Do I need a disable ADC here? 
    } 
}

So now we can actually read it how exactly do you think this is going to work then? Your ADC_init() ends by setting ADSC to start the very first conversion. When it completes ADIF becomes set and execution vectors to this ISR routine - then what do YOU think happens next?

Whizzing round a for() loop twenty times, setting ADSC each time does NOT make 20 readings. If you wanted to do something like this then you'd have to wait for ADSC to return to 0 each time but this would be very bad news in an ISR - they should be fleet of foot - in and out - bada boom.

You then have a test of i==20, now why would you do that? As the for() loop has no possibility of early exit how could it possibly complete without this condition being true.

What I *think* you had in mind was something like:

ISR(ADC_vect) { 
    static sample_count = 0;
    ADC_Buffer[sample_count] = ADCH;
    ADCSRA |= (1 << ADSC); 
    sample_count++;
    if (sample_count == 20) //if finished set flag= 1 to send samples to hyperterminal 
    { 
        sample_count = 0;
        flag = 1; 
    } 
}

but I wasn't clear if you wanted to only ever take 20 readings then shut everything down (in which case do clear ADEN in the sample_count==20 block too) or do you want to repeatedly take 20 readings, send them, take another 20, send them and so on...?

Cliff

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

Hmm I did indent my code and used the preview and it looked good.
I tried the code you mentioned.My main looks like this:


int main (void)
    {    

      DDRC = 0x0F;
      DDRD = 0xFF;
      USART0_init();
      ADC_init();
      timer_init();

         for(;;)
           {               
             if(flag==1){
            for(j=0;j<20;j++)
							    USART_putchar(ADC_Buffer[j]);


               flag = 0;

                    }
              }
     } 

I see continuous data on the hyperterminal. It does not stop. I did add the ADEN disable in the ISR but the hyperterminal still gives a running display of data. How can I have the hyperterminal display only the 20 values and stop?

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

I don't see how that's possible. Once ADEN is switched off the ADC interrupt can no longer occur, so 'flag' cannot be set so the if(flag==1) bock in main() cannot execute any longer once the last 20 have been output and 'flag' changed back to 0.

I have a suspicion that to get the behaviour you describe that the AVR may continually be resetting and restarting the program. Either because the WDTON fuse is enabled or because a rogue IE bit is set with no handling ISR()

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

Ok it worked. I was using ADCSRA |= (1 << ADEN); instead of ADCSRA &= ~(1 << ADEN);