Need help to find out timebase ADC->UART ATMega64

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

Hi there!

I hope the subject is clear enough? Well, here is my problem. I use an ATMega 64 to do three major jobs on a PCB:

  • generate a clock for a switched capacitor filter (LTC1067) with the Timer1
  • convert the analog output behind the RMS-To-DC converter behind the filter through ADC0 to digital values
  • convert the values to ASCII and send them to an UART to a PC with a terminal program running and logging the results at 57,6kbit/s
The ATMega64 runs at 16MHz external clock. The program works fine, it filters ripple control signals from the main line and sends the ASCII values to an UART. BUT I don't know, how my time base is scaled. Here are some thoughts but I think they are not 100% right because the result I calculate with the pocket calculator is too far away from what it should be.
  • ADC runs at 125 kHz, so one cycle is 8us long. One conversion in free running mode takes 13 cycles, so 13 x 8us equals to 104us. In theory I should receive one result in my ring buffer every 104 us.
  • UART transmits at the speed of 57600 baud, that means 57600 bits per second which is 7200 bytes per second. My results in ASCII are 2-3 bytes long (one or two digits plus a CR) so in the worst case there are 2400 transmissions of ASCII value pairs every second which takes almost 417us per transmission.
  • that means I lose around every 4th ADC value because the UART is too slow to read the RingBuffer before it gets overwritten?
Here is the code to this program: Free running ADC

I tried to solve the problem in getting a defined amount of ADC samples. I thought I'd set up another Timer (Timer0) and trigger the ADC through Timer0. I tried to trigger every 200us, every 400us and even every 500 us.

  • every 200us seemed to look o.k. but the time base I calculated later did not match either. I assumed I trigger the ADC every 200us, on conversion takes 13,5 cylces in auto trigger mode. At 125kHz ADC clock this would be 108us. So I assumed I'd have one value every 200us. But this was not correct, I had less values. Maybe the INT to ASCII conversion and the UART takes too long?
  • every 400 or even 500 us I received "0" in between my values in my RingBuffer so I think the ADC was going on too slow?
Here is the code for the Timer0 triggered ADC attempt: Timer triggered ADC

I hope that someone can clear my mind up and help me how to get the correct timebase. I appreciate any help.

Josef

Attachment(s): 

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

Ok, a few notes:

lostchild wrote:
  • ADC runs at 125 kHz, so one cycle is 8us long. One conversion in free running mode takes 13 cycles, so 13 x 8us equals to 104us. In theory I should receive one result in my ring buffer every 104 us.
  • UART transmits at the speed of 57600 baud, that means 57600 bits per second which is 7200 bytes per second. My results in ASCII are 2-3 bytes long (one or two digits plus a CR) so in the worst case there are 2400 transmissions of ASCII value pairs every second which takes almost 417us per transmission.
  • that means I lose around every 4th ADC value because the UART is too slow to read the RingBuffer before it gets overwritten?

57600 baud = 5760 bytes/s (you forgot start and stop bit).

If ADC conversation takes 104µs and transmitting the value takes 417µs, then you don't lose about every 4th ADC, but you lose 3 of 4 conversations (only every 4th result is transmitted).

In your code you use the UDRE interrupt and then you send multiple characters inside this interrupt with polling. Not a good idea in my opinion.

The ring buffer for the conversation results doesn't make much sense with your current concept. If you have a producer with a fixed rate at one end and a consumer with a fixed rate at the other end, the buffer will always be empty or always be full, depending on which end has the higher rate.

Stefan Ernst

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

Just to note that if your ADC produces faster than your PC (limited by baud rate can consume) you might want to consider averaging every 4 readings (or whatever the difference in rates are).

To speed up the PC link you might also want to consider not converting to ASCII. Say you are transmitting 10bits as 2 bytes, if you convert this to ASCII if could be over 999 so using 4 bytes. You might therefore double the rate (of course some ASCII readings might only be 1 or 2 characters too)

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

Thank you for your replies!

I worked on the program and re-wrote it a bit. I deleted the ring buffer part and followed clawsons advice to collect a few samples and put the sum to the UART. I did not average them on the Atmel, that job can do the PC much faster... All I need is a known time base which should be as fast as possible of course. The signal I would like to measure is approx. 150ms long. I did not really know how to send the ADC result to the UART. I tried to send it like:

  uart_puts(sum & 0x0ff); //low byte
  uart_puts(sum >>8);     //high byte

where sum is an uint16_t value. The terminal program running on the PC did not show numbers of course but weird characters so it is not ASCII what the Atmel transmits - sure. I'm not that experienced in programming - is it possible to read the values somehow on the PC through the UART even if the characters are NOT ASCII and convert them to ASCII on the PC?

I now tried to solve it in converting the number to binary digits and add 48 to them (convert them to ASCII) and send them to the UART. But I still do not know if the timebase is now 104us*5 (13 ADC cycles multiplied by number of values summed up). How can I make sure how long my program needs to run? I suppose not at all due to the interrupts I use and the compiler in between?!

Thank you very much for your support. I am looking forward to your replies.

Josef

EDIT: I put in toggle pins into my code and watched them with an oscilloscope. This way I found out how long my routines run. I got rid of any unnecessary stuff (like the blinking LED...) and summed up 4 values before I transmit them to the UART (now with 115200 baud) and it works now. I got a fixed timebase of 4x104us. Thank you very much for your help!

Josef

Attachment(s):