Baud rate and ADC sampling frequency

Go To Last Post
65 posts / 0 new

Pages

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

Ok I tried sending the raw ADC value and I cannot seem to capture a 1kHz sine wave. I am sending a printf("#d",ADC); statement. I can comfortably capture a 100Hz sine wave. Following are the various combinations I have tried:

Prescalar  Crystal  Baud rate  I/p freq.  Works?
64           7.3278M   230400     100 Hz     Yes
64           7.3278M   230400     1kHz       No
64           9.216M    115200     100Hz      Yes
64           9.216M    115200     1kHz       No

I am using a prescalar of 64 so that I am still within the 200kHz limitation of the ADC. (9.216M/64/13 = 11.076Ksps). Could this be the MAX232? The crystal does not seem to make a difference. I seem to be hitting a wall at 1 kHz (and I want to try and go up to 10kHz)

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

Anybody?

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

Which AVR is this? One approach would be to forget trying to use the (slow) UART while actually sampling but sample to a RAM buffer then, later, at leisure, transmit these samples to the PC. To draw your graph it's not as if you really need more than a few hundred samples - if that.

If continuing with your current plan you may want to profile printf() in the simulator but it alone could be eating hundreds or even thousands of cycles on each invocation. This is why I'd just send the raw binary and forget printf() all together. Just literally:

 UART_sendchar(ADCL);
 UART_sendchar(ADCH);

then, as I suggested previously, do all your processing at the Gigahungry PC end.

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

Thanks for the idea, Cliff.

All I need is to transmit 9 bits/sample. (my values are < 512)

I tried itoa to convert the entire 16 bit ADC value to a string and sent it to the hyperterminal, and at 1kHz, 9.216MHz and 115200, I got an aliased sine wave.Again works fine at 100Hz.

I also tried to send ADCL and ADCH separately but all I got was smiley faces and other ASCII characters on my hyperterminal. I am using the standard sendchar function which is defined as follows:

void UART_sendchar(unsigned char c)
{
while ((UCSR0A & (1 << UDRE0)) == 0) {}; 
UDR = c;
}

I also tried converting the unsigned char c to an unsigned int c and still got the same ASCII characters on my hyperterminal.

How can I convert the ASCII characters I get on my hyperterminal into decimals? Is there an easier way or do I have to write a script (say in Bray's terminal program)?

Another question: Does the 200kHz sampling limitation hold before or after the 13 cycles/ conversion has been taken into account?

Are there any other AVR's that do not have this 200 ksps limitation?

Appreciate your patience on this.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
int addat[1000];
//------------------------
void acquire(void){
int n;

  for(n=0; n<1000; n++)}
    addat[n]=readadchan(5);
  }
}

//----------------------
void dump(void){
char i,j;
int *p;

  p=addat;
  for(j=0; j<50; j++){
    for(i=0; i<20; i++){
      printf("pct 3x ",*p++);
    }
    crlf();
  }
  crlf(); 
}

//------------------
while(1){
  acquire();
  dump();
}

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
int addat[1000]; 

2,000 bytes - not all AVRs could cope with a sample buffer so big.

Quote:

I also tried to send ADCL and ADCH separately but all I got was smiley faces and other ASCII characters on my hyperterminal.

Did you expect otherwise? It's BINARY not ASCII. I'm suggesting you collect the binary (because it crosses the comms channel quicker) then later post process it into ASCII (if that's what you want) or feed it into your graphing app as raw binary. In Hyperterminal use the Capture facility to have the "smiley faces" written to a file which is now a .bin file with 2 bytes per sample. Then fopen(,"rb") this file in the program that wants to process the data.

Or go with what Bob showed to sample quickly then send slowly.

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

Thanks Bob and Cliff.

I tried to send raw data to my hyperterminal and converted it from ASCII to decimal. I am using 7.3728MHz, 115200 baud and capturing a 10KHz sine wave.

Attached is the file I am getting. It seems like it is working. I am sending ADCL first, then ADCH. It looks like the positive half of the cycle is getting inverted to a negative. the puchar() function accepts unsigned chars.

Is this a problem? I tried to change the function so it accepts signed chars but I got no output on my hyperterminal. I can of course multiply by -1 to get the right wave, but I wanted to understand the reason for this.

Also the raw data converted decimal samples are delimited by a 1 and occasionally a 10 between them. The 10 seems to be very close to a zero crossing.

What does the 1 represent? Could this be my converter?

 1 241 1 242 1 240 1 10 239 1 236 1 237 1 231 1 228 1 223 1 220 1 218 1 216 1 215 1 214 1 215 1 216 1 218 1 222 1 224 1 228 1 230 1 235 1 238 1 239 1 241 1 241 1 241 1 240 1 237 1 236 1 232 1 231 1 225 1 223 1 219 1 217 1 215 1 217 1 214 1 216 1 217 1 221 1 223 1 10 227 1 230 1 234 1 236 1 239 1 241 1 241 1 241 1 240 1 238 1 237 1 233 1 231 1 226 1 224 1 220 1 218 1 216 1 215 1 214 1 215 1 216 1 220 1 221 1 226 1 228 1 232

Attachment(s): 

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

Quote:

What does the 1 represent?

Post the AVR code.

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

Here is the code:

#include 
#include 
#include 
#include 

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

//volatile unsigned int a;
//volatile unsigned int b;
volatile unsigned char flag;

//static int UART_putchar(char c, FILE *stream);

//static FILE mystdout = FDEV_SETUP_STREAM(UART_putchar, NULL, _FDEV_SETUP_WRITE);

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
//   stdout = &mystdout; //Required for printf init

}


/*static int UART_putchar(char c, FILE *stream)
{
    if (c == '\n') UART_putchar('\r', stream);
  
    while ((UCSR0A & (1 << UDRE0)) == 0) {}; // Do nothing until UDR is ready for more data to be written to it

    UDR0 = c;
    
    return 0;
}*/


  void USART_putchar(unsigned char c)
   {

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

}

/*void USART_putstring(char *s)
{
    while (*s)
        USART_putchar(*s++);
}*/


void ADC_init() 

  {
     ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADATE); 
     ADMUX = (1 << REFS0) | (1 << MUX2) | (1 << MUX0); // 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)
  {
 						         flag = 1;

  }
int main (void)
    {   
	   DDRC = 0x0F;
	   DDRD = 0xC0; 
           USART0_init();
	   ADC_init(); 
	   timer_init();
    
            for(;;)
              {
			  	  
			  
                 ADCSRA |= (1 << ADSC); 
                 if(flag==1)
		    {
                         //itoa(ADC, string, 2); 
                          //USART_putstring(string);
                          USART_putchar(ADCL);
                          USART_putchar(ADCH);
						                               //printf("#d\n",ADC);

		          flag = 0;
                     }
               }
     }

Could the 1 be ADCH? The ADCL is always < 256 which makes sense for an 8 bit value. I also noticed that all my values are half of what they should be. Do I need to send the 9 bit value as one value instead of two? I guess the other option is to change my reference so that it is less than (1/2)VCC so that I need only ADCL?

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

I'm sorry but THAT program did not produce that data:

 1 241 1 242 1 240 1 10 239 1 236 1 237 1 231 1 228 1 223 1 220 1 218 1 216 1 215 1 214 1 215 1 216 1 218 1 222 1 224 1 228 1 230 1 235 1 238 1 239 1 241 1 241 1 241 1 240 1 237 1 236 1 232 1 231 1 225 1 223 1 219 1 217 1 215 1 217 1 214 1 ...

Can we either see the right program or the right data. I have half a suspicion that this data has been "post processed" in some way to represent it in ASCII. Don't do that - as an attachment post the raw .bin file that was written to the disk from HyperTerminal.

Even if there hadn't been some kind of "hidden" binary to ASCII conversion then assuming ADCL then ADCH order the '1's would not be in the L position.

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

Sorry about that,Cliff. Yes you are right, I did use a ASCII to decimal conversion website to post process the data.Attached is the raw data captured from the hyperterminal. This raw data is with the program I posted below. Also attached is a screen snapshot of the tool I am using to convert the raw data into ASCII characters.

Here is the link to the converter:

[url]
http://cs.carleton.edu/faculty/a...
[/url]

Here is an excerpt of the raw data. I am trying to attach it but the attach is not working.


ññòññïîêèäâÞÝÚØ×Ö×ØÚÜÞâäèêíðñòòñðîìéçãáÝ
ÚÚÙ×××ÙÚÞßãæéíîññòñðïíëçæáÞÜÙØ×××ØÚÜßáåé
ëðïññññðïìêæâàÜÚØÙÖ××ØÛÞàãçêìïðññññîíêæä
âßÛÚ××××ÙØÜàâæèìíðñòññðîêéçãßÝÚÙ××××ÙÜÝá
ãçéíîðñòñðîíèçãáÞÜÙÙ×××ÙÚßßãæéëîïññññïíì
èèâàÝÚØ××××ÚÚßàäæêìïðñòñòïìêååàßÛÚ×Ø×ÖØÛ
ÜßâçèëíðòñòñïîëéåãßÝÚØ×Ö×ØÙÜÝâäèêíððòòñð
îìéäãáÝÚÚÙÖ××ÙÛÝàãæéíïññòñðïìèçåáÝÜÙØØÖ×
ÙÚÜßáåéëíðòòòñïîëéåáßÜÚØ×ÖÖØÙÜÝáåçëìïðñò
ññîíêåäáÝÚÙ××××ÙØÝáãèéìîðññòððíêèäâÞÝØØ×
ÖÖØÚÞßãæéëîïñóòòðíìèæâàÝÛÚÙ×ÖØÚÛßáåçëìïð
òòòñïìëçåáÞÛÚØ××ÙÙÜÝàãæèìîðñòòñïîëêåäßÝÚ
Ø×××ÙÚÝÞâäèêîïñòòññîêéèãáÝÛÙØ××ÙÙÛÞàäæêì
ïññòòñðìëççáßÝÚØ××ØØÛÜàâæèìîðòòòòðîëëåäß
ÜÚØ×××ØÙÜÞáäçëíññòòòñîíêèäàÞÛÙØ×Ø×ÙÚÞàãè
éíîñòòòñðíìèäâßÝÙÚ×××ØÚÛßãåêëîïñòòóðïìéæ
äàÝÜÙØ××ØÙÛàáæçëíïðòòòñïìêçåâÞÛÚØ××ÙÙÜÝà

edit: looks like it worked. File is attached.

Attachment(s): 

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

OK, here's my view of that data - I just loaded the ".txt" file into a binary editor. So the sample data you really have there is:

0x1DF, 0x1E0, 0x1E2, 0x1E6, 0x1E8, 0x1EC, 0x1EE, 0x1F2, etc.

To read your data the psuedo code would be:

FILE * fin;
uint8_t lobyte, hibyte;
uint16_t dataword;

fin = fopen("raw_data.txt", "rb");
while (!feof(fin)) {
  lobyte = fgetc(fin);
  hibyte = fgetc(fin);
  dataword = (hibyte<<8) + lobyte;
  // use 'dataword'...
}

Attachment(s): 

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

Thanks again, Cliff.

Ok I ran the raw data with the C code and attached is the waveform I got (for one cycle).

Here is some thinking out loud calculations:

I have 28 samples/cycle. I am using 115200 bps. Since I am sending 9 bits/sample that is 1.125 bytes/sample. So (115200/1.125/28) gives me 3.657kHz. The input is 10kHz. I am using 7372800 Hz as my clock and a divide by 64 as the prescalar. So assuming 13 cycles/conversion I get my ADC sampling rate as 8.861ksps which is too low. (for Nyquist)

So if I use /16 as my prescalar, I get 7372800/16 = 460800 ksps and with 13 cycles/conversion, I will get 35.4ksps.

How stringent is the requirement that the sampling rate should be between 50-200 ksps for the ADC? Is that before or after the 13 cycles/conversion factor?

Attachment(s): 

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

Quote:

How stringent is the requirement that the sampling rate should be between 50-200 ksps for the ADC?

No one really seems to be able to give an accurate answer to that question. It's clear you trade bits of accuracy against conversion speed but exactly what accuracy you can expect for 460kHz is unknown.

But there's something suspicious in your calculations I think. Across the UART channel you are NOT sending either 9 or 10 bits per sample even when using binary. You are sending two bytes, 16 bits to convey 8/9 bits of info with 7 bits wasted. Hence the reason every second byte is only 0x01 or 0x00.

You have two options - drop the accuracy and use ADLAR and take 8 bit samples and send one UART byte per reading. Or you can consider packing the bits. Let's assume 10 bits per reading then (breaking the bits into groups of 8) you could pack and send as:

11111111 11222222 22223333 33333344 44444444

So you pack four 10 bit readings into 5 bytes that are transmitted. This will require some extra packet construction/deconstruction code though to get this benefit.

Pages