Need some help with ADC on mega644

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

Mega644 14.75456 Oscillator Serial Baud 230,400

Communication flawless

I wrote a c# program using OpenTK to receive and chart the data

 

I am now testing the input but not having luck with the ADC0

Here is the ADC setup and Clock0 settings

 

	// ADC initialization
	// ADC Clock frequency: 115.200 kHz
	// ADC Voltage Reference: AREF pin
	// ADC Auto Trigger Source: Timer0 Overflow
	// Digital input buffers on ADC0: On, ADC1: Off, ADC2: Off, ADC3: Off
	// ADC4: Off, ADC5: Off, ADC6: Off, ADC7: Off
	DIDR0=(1<<ADC7D) | (1<<ADC6D) | (1<<ADC5D) | (1<<ADC4D) | (1<<ADC3D) | (1<<ADC2D) | (1<<ADC1D) | (0<<ADC0D);
	ADMUX=ADC_VREF_TYPE;
	ADCSRA=(1<<ADEN) | (0<<ADSC) | (1<<ADATE) | (0<<ADIF) | (0<<ADIE) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
	ADCSRB=(1<<ADTS2) | (0<<ADTS1) | (0<<ADTS0);
	// Timer/Counter 0 initialization
	// Clock source: System Clock
	// Clock value: 1843.200 kHz
	// Mode: Normal top=0xFF
	// OC0A output: Disconnected
	// OC0B output: Disconnected
	// Timer Period: 0.13889 ms
	TCCR0A=(0<<COM0A1) | (0<<COM0A0) | (0<<COM0B1) | (0<<COM0B0) | (0<<WGM01) | (0<<WGM00);
	TCCR0B=(0<<WGM02) | (0<<CS02) | (1<<CS01) | (0<<CS00);
	TCNT0=0x48;
	OCR0A=0x00;
	OCR0B=0x00;

 

I'm confused if the ADC is running or if I need to set the ADSC to one to start it running, datasheet says in free running mode to do this.

When ADSC is default code vision settings for timer 0 overflow I only read zero

When I set ADSC high I only read 255 in ADCL and 3 in ADCH

 

I am also not sure if I just read them or wait for the ADSC to clear before reading them.

On the mega48 I was doing single conversions that worked, never tried the overflow timer method.

 

Reading in this loop

 

	while (1)
	{
	  byteReceived = ADCL;
	  highbyte = ADCH;
	  putchar(byteReceived);
	}

ADC(0) pin 40 on the mega644 verified testing voltage 4.89V to VCC and 0V to ground, adc reads 1023 either way.

AVCC also VCC voltage at 4.89V

 

Must be something simple I am not doing.

 

 

 

 

 

 

 

Attachment(s): 

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

well, first of all you have the DIDR definition the wrong way around. all the IO lines do not have digital input except the ADC0 line...... See datasheet, as it is very clear.

Did the ADC in single conversion mode work on the Mega644? You have a working uart so can spit out lots of info as to what is happening where. that could make things easy.

 

In addition, I would read the adc as "uint16_t AdcVal = ADC;"  then the compiler can handle the right order into what the data should be retrieved.

 

First focus on getting the ADC to work at all ( I understand that it is not working at all) so forget about everything else, init the adc and then in a while loop, start a conversion, wait for it to finish, spit out the result to the ADC, wait 500ms and do it all again

When that works you can then start fiddling around witht he rest of the stuff you want. add the timer as in: disable ADC and have the timer overflow spit out a character every 500ms. then when that works you can have the timer start the ADC conversion and all you need to do then is wiat for its completion. As such gradualy extending the functionality as at this point it can be a lot fo things wrong ( besides the 2 I already mentions as they triggered me right away.)

 

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

 

Yes just tested single conversion and it is working on that, just testing now with overflow

 

Not working with overflow

 

Output on scope using this code

	while (1)
	{

     TCNT0 =1;
	 while(TCNT0 != 0)
	 {
	 }
	 putchar(0);
	}

So timer period .13889ms is right.

 

Attachment(s): 

Last Edited: Thu. Oct 10, 2019 - 07:20 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Codevision has a Wizard that can configure your USART comms, ADC, Timers, ...

 

Use it.

 

But it is also sensible to put your brain into gear as well.

 

You can always ZIP up your project and attach the ZIP.

And then ask specific questions.

 

David.

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

 

Normally if I would choose to do it, I would put all the initialization setting in one function, say adc_init:

int8_t adc_init();

I dont see whhere are you enabling the clock for ADC register, the is i.e. PRADC "Power reduction ADC" Page 44 in date sheet:

 

" Bit 0 - PRADC: Power Reduction ADCWriting a logic one to this bit shuts down the ADC. The ADC must be disabled before shut down.The analog comparator cannot use the ADC input MUX when the ADC is shut down. "

 

so if you want you can choose setting for this bit:

PRR &= ~(0 << PRADC);

set the following bits for ADMUX:

 

ADMUX = (0x00 << REFS0)   //internal ref
	        | (0 << ADLAR)    //left adjust results
	        | (0x00 << MUX0);  //depending on your settings

afterwards, you need to set the regsiter ADCSRA "ADC CTRL & STATUS REGISTER", check page 234 from the datasheet:

 

 

 

so, try to configure the bits of this register and to enable the ADC and the interrupt:

 

ADCSRA = (1 << ADEN)        //enable ADC
	         | (0 << ADATE)     //enable auto-trigger "depends on your settings
	         | (1 << ADIE)      //enable ADC interrupt
	         | (0x01 << ADPS0); // check the note below

now, pay special attention to page 236 from datasheet:

 

So you have to define which ADPS(0,1,2).....hence the comment in the code up. Last, enable the Counter/Timer overflow:

 

ADCSRB = (0x04 << ADTS0)    //timer counter 0, see below
             | (0 << ACME);      // no need to use analog comparator multiplexer

check page 251 from datasheet:

 

now put all the setting together in one function:

 

int8_t ADC_0_init()
{

	/* Enable clock to write ADC registers */
	PRR &= ~(0 << PRADC);

	ADMUX = (0x00 << REFS0)
	        | (0 << ADLAR)
	        | (0x00 << MUX0); //pin 0

	ADCSRA = (1 << ADEN)
	         | (0 << ADATE)
	         | (1 << ADIE)
	         | (0x01 << ADPS0);
	ADCSRB = (0x04 << ADTS0)    // Timer/Counter0 Overflow
	         | (0 << ACME);      

	return 0;
}

ofcurse, before using the ADC you need to define Clock for ADC, check the datasheet. this is always related to your main clock.

 

regards,

Moe

 

Last Edited: Thu. Oct 10, 2019 - 09:14 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The CV Wizard will provide the initialisation and an ADC_read() function.

CV provides example projects that show how to use the ADC.

 

Of course you can always write your own low level functions and ignore all the CodeVision libraries.

 

Any project can be designed from Bottom-Up or Top-Down.

I would advise that Top-Down is more productive.  i.e. start with proven library code

 

The AVR is pretty simple.    Writing directly to registers from the datasheet is practical and efficient.  i.e. Bottom-Up approach

You will just end up with the same solutions as the library(s).

A commercial Compiler like CV do not show their library source code.     But Atmel / Microchip Application Notes do provide public source code that you can use with GCC,  IAR, ImageCraft, Codevision, ...

 

David.

 

Last Edited: Thu. Oct 10, 2019 - 09:47 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I did use Code Vision , that code I posted is directly from codevisions auto generated code with no changes.

When I get home I will go over the whole thing again.

 

I forgot there was a Read function generated, I do use the read and write USART interrupts.

I just assumed the generated code set things up and no other code was necessary

but to wait for a completion and read the values low byte first then high byte.

 

well, first of all you have the DIDR definition the wrong way around. all the IO lines do not have digital input except the ADC0 line...... See datasheet, as it is very clear.

 

Codevision setup generated code

There are check boxes to select unused (at least i thought so may be wrong) 

with the adc0 pin in the DIDR set to 0 the adc does work when not in auto overflow of timer mode.

Have to re read the code generation wizard , just pointing out what errors in understanding I had when i generated the gode over a week ago

Its the first time i used codevision to generate code in 14 years (used codevision in 2000 - 2005 exclusively and have been out of this for that many years so just trying to find my way here.

 

 

Last Edited: Thu. Oct 10, 2019 - 04:16 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
	  byteReceived = ADCL;
	  highbyte = ADCH;
	  putchar(byteReceived);

since when has putchar() offered binary to ASCII conversion??

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

Hmmm its a uint8_t bytereceived

Initially I ran tests sending from my C# program a byte and transmitting the byte back at 250400 baud

and it had no errors. Perhaps I am missing something but on my scope when I send a value 0..255 the

serial output is spot on. So I am confused by the question.

 

My C# program (on my windows 10 computer) outputs the received VALUE .tostring() so it outputs integers from 0 to 255 in ascii to the console.

 

Last Edited: Thu. Oct 10, 2019 - 04:31 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You can send whatever you like on the Serial Terminal.    But either end might mangle it.

 

Which is why you tend to write human readable text between foreign systems instead of raw binary values.

 

Yes,   interrupt driven Serial at 230400 baud is wise.

You can afford to use the poll-driven adc_read() function.

 

But you can equally well use interrupts for the ADC.

 

I don't know any humans that can read at 230400 baud.    High speeds are only worthwhile for machines.   And if you use machines you can compress data,  use packets,  error recovery, ...

 

David.

Last Edited: Thu. Oct 10, 2019 - 04:47 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I will be sending about 3000 bytes per second 

for now I am sending the maximum I think 23,040 bytes (2 bits for stop and start i think)

 

The data is displayed on the screen using OpenTK 

 

Just connected last night to the 14MHZ oscillator reading the ADC with full 10 bit speed

here is the output, (the screen runs at 60 frames per second and is set to display 10,000 points across a 1200 point window

so of course many points get translated to the same horizontal pixel but vertically show up if different values.)

 

Just thought I may try increasing the speed on adc to maximum to see if i can read 14MHZ on or off and put out a square wave.

I guess this is a dyi oscilloscope or logic probe I guess.

 

I will see if I can get this thread marked solution tonight.

 

I will for timebase reasons set it up for interrupt adc readings as that will make more sense than polling for the output.

 

 

 

 

  

Attachment(s): 

Last Edited: Thu. Oct 10, 2019 - 05:39 PM