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:
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)
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.
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?
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.
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?
#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?
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.
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.
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?
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.
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:
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)
- Log in or register to post comments
TopAnybody?
- Log in or register to post comments
TopWhich 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:
then, as I suggested previously, do all your processing at the Gigahungry PC end.
- Log in or register to post comments
TopThanks 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:
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.
- Log in or register to post comments
TopImagecraft compiler user
- Log in or register to post comments
Top2,000 bytes - not all AVRs could cope with a sample buffer so big.
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.
- Log in or register to post comments
TopThanks 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?
Attachment(s):
- Log in or register to post comments
TopPost the AVR code.
- Log in or register to post comments
TopHere is the code:
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?
- Log in or register to post comments
TopI'm sorry but THAT program did not produce that data:
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.
- Log in or register to post comments
TopSorry 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):
- Log in or register to post comments
TopOK, 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:
Attachment(s):
- Log in or register to post comments
TopThanks 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):
- Log in or register to post comments
TopNo 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:
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.
- Log in or register to post comments
TopPages