ADC Sampling Rate Limit

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

Hi everybody

To get 7kHz sound signal I programmed an ATmega8 by the below code. However, I get max 150 Hz in the LabVIEW. How could I increase the sampling rate?

I will be appreciated for any tip. The code:

$regfile = "m8def.dat"
$crystal = 24000000
$hwstack = 40
$swstack = 16
$framesize = 32
$baud = 128000
Config Adc = Single , Prescaler = 4 , Reference = Avcc
Start Adc

Dim A As Word

  Do
  A = Getadc(0)

   Print A
  Loop
End

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

If my eyesight is working you are running that mega8 at X1. 5 the designed maximum speed??

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

jahana wrote:
I get max 150 Hz in the LabVIEW. How could I increase the sampling rate?

So is your question actually about the ATmega8 - or is it about LabVIEW ?

 

This is not the place for LabVIEW support ...

 

http://www.ni.com/en-gb/shop/labview.html

 

http://www.ni.com/en-gb/support.html

 

http://www.ni.com/en-gb/community.html

 

EDIT

 

For details about the ATmega8, see the datasheethttp://www.atmel.com/Images/Atmel-2486-8-bit-AVR-microcontroller-ATmega8_L_datasheet.pdf

Last Edited: Fri. Sep 29, 2017 - 06:18 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:
So is your question actually about the ATmega8 - or is it about LabVIEW ?

Well, as pointed out there certainly are Mega8 considerations.

 

But my quick answer is "neither" -- the bottleneck has to do with polling conversions in that flavour of BASIC?

 

At that high UART bit rate there certainly would be more than 150 "messages" per second.  But I don't know how efficient "Print" is, or how many characters in a message.  If e.g. 4 bytes plus CR, that would be ~50 bits.  So ~2500 messages/second.

 

I'll guess that "Single" is single-conversion, polled, on the selected channel.  Does "Prescaler" of 4 mean clk/4, or the combination of ADPS bits?  If /4, that would be a 6MHz ADC clock.  If the ADPS combination that would be /16, 1.5MHz ADC clock -- way out of recommended range.

 

=================

With the recommended 200kHz ADC clock, one can get about 10000 samples per second.  Does OP need to sample at 7.5kHz, or sample a signal of that frequency?  If the latter, then oversampling is needed.

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

Thank you for helpful comment.

I have tried different adc clocks in range of 50 kHz to 200kHz with different crystals and buads. As you pointed prescaler means clk/4. This is the adc clk. However, I can't get more than 300 samples per second. Can single conversion be the point?

Best Regards

 

 

 

Last Edited: Sat. Sep 30, 2017 - 06:17 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jahana wrote:
 I can't get more than 300 samples per second. 

Again, is that because the AVR itself won't go any faster - or is it a limitation of LabVIEW and/or the way you're using it.

 

theusch wrote:
With the recommended 200kHz ADC clock, one can get about 10000 samples per second

So it certainly shouldn't be the AVR ...

 

Also, you didn't answer:

theusch wrote:
Does OP need to sample at 7.5kHz, or sample a signal of that frequency?  

 

("OP" = Original Poster - that's you!)

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

Sorry I am new to forum: "("OP" = Original Poster - that's you!)​". I did not notice. Thanks you very much. I want to record a sound with max 7 KHz then I need 14KSps. But with many trials on crystal, buad, prescaler (clk/1 to 128), and considering the ADC clock in range 50KHz to 200 KHz, I could not get sample higher than 300 Sps witch results in recording max a 150 Hz signal. I am not insisting that my LabVIEW works correctly but I asked LabVIEW experts to help and they confirmed my VI. Therefore I am here to ask if there is a fault in my AVR code. Thank You All in advance.

Last Edited: Sat. Sep 30, 2017 - 11:22 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jahana wrote:
 I asked LabVIEW experts to help and they confirmed my VI.

So what, exactly, did they "confirm" ?

 

EDIT

 

 

jahana wrote:
I could not get sample higher that 300 Sps
 

But theusch wrote:
With the recommended 200kHz ADC clock, one can get about 10000 samples per second
 

So you must be missing something!

 

Have you studied the AVR datasheet to check the capabilities of the ADC ?

Last Edited: Sat. Sep 30, 2017 - 11:09 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jahana wrote:

...

$crystal = 24000000
...
$baud = 128000
Config Adc = Single , Prescaler = 4 , Reference = Avcc
...

 

 

I'm not sure I believe any of these numbers.

 

1) As Cliff pointed out in #2, a 24MHz crystal is well outside the operating range of the chip

 

2) With those numbers the actual baud rate will not be 128,000. Depending on if Bascom rounds the divisor up or down it'll either be 125,000, an error of -2.5%, or 136,363, an error of +6.5%

 

3) The OP states they've tried various crystals, but we haven't seen anything to show they are running on anything other than the internal RC 1MHz unit.

 

4) If they really are running at 24MHz then the ADC, with a /4 prescaler, is horribly over-clocked. Who knows what it will do.

 

 

'This forum helps those who help themselves.'

 

pragmatic  adjective dealing with things sensibly and realistically in a way that is based on practical rather than theoretical consideration.

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

Thanks to Brian Fairchild and Cliff.

I know that the MAX crystal for this chip is 16MHz.

Also, by changing the fuse bits I have activated the external crystal.

In fact the posted Bascom code was my last try.

I am sure that your comments are reasonable and Awneil's comment on LabVIEW makes me doubtful on VI.

I would like to know if it is the fault of USB to UART chip? (I use a CP210x, Silicon Lab)

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

jahana wrote:
I know that the MAX crystal for this chip is 16MHz.

So why did you write

$crystal = 24000000

??

 

I would like to know if it is the fault of USB to UART chip? (I use a CP210x, Silicon Lab)

Pretty unlikely - but you could easily test that yourself by just sending some test pattern ...

 

 

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

Brian Fairchild wrote:
 With those numbers the actual baud rate will not be 128,000.

And 128000 is a pretty weird baud rate anyhow!!

 

surprise

 

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

What a Buad rate is suitable?

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

Standard baud rates include 9600, 19200, 115200

 

Higher rates following on from them are 230400, 460800, 921600

 

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

Not at home this weekend, or I might post some code...

 

How familiar are you with Bascom?

 

Have you used interrupts?

 

To do this project I think I would:

 

Set up a timer to generate an interrupt at 7.5 K interrupts / second.

Inside the interrupt:

Print the current ADC reading

Trigger the next ADC reading

 

Run the ADC in single sample mode, where you trigger it for each reading required.

 

Look in the Bascom help for samples of setting up a buffered, interrupt driven, USART.

This only takes one or two lines of code.

 

Look in the data sheet in the USART section for low baud rate error baud rates for various clock frequencies.

You want to use a baud rate with an error under 2%.

 

With the above approach you will get samples at a known data rate, (7.5 K S/Sec).

The ISR will transmit the data without holding up the data collection.

 

JC 

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

I'm making some assumptions here but presumably getAdc() returns 0..1023. Also I guess "Print A" sends this over UART with a terminating line feed. So worst case one reading sends 5 characters. Again assume 10 bits to send a character. So you may be looking at 50 bits for a sample. You want 7000 samples per second so you need to transmit at 50 * 7000 = 350,000 bits per second. And all this assumes very little overhead for getting the samples and converting / sending them.
.
It might be a better idea to add some buffering secondary storage to the AVR, record the whole sample there then transmit later at below real-time.
.
Getting 7K sampling over UART is quite a challenge otherwise.
.
It would help a lot if you can send it as binary (so just 2 bytes per sample) than 5 bytes+
.
(of course not all samples are going to be 4 ASCII digits - but you have to program defensively for "worst case")
.
Oh and maybe I've misunderstood getAdc() and Print A.

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

DocJC wrote:

Inside the interrupt:

Print the current ADC reading

You have to be very careful about "printing" from inside an ISR!

 

In fact, you don't do the actual printing in the ISR - you just pop data into a buffer, to be printed later.

 

buffered, interrupt driven, USART

is the essential thing for this to work.

 

But you still have to take into account that sending characters through a UART takes a relatively "long" time in microcontroller terms - so you will need to use a high enough baud rate that your buffer does not overflow ...

 

EDIT

 

Cliff's simultaneous post has put some numbers on my "sending characters through a UART takes a relatively 'long' time" and "you will need to use a high enough baud rate that your buffer does not overflow"

 

Last Edited: Sat. Sep 30, 2017 - 01:33 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I posed quite a few little questions with my earlier rough analysis.  OP answered few if any.  What speed is the AVR actually running at?  What is the actual baud rate?  How many characters in each "packet"?

 

Unless as the OP you start answering the basic questions, there is no way to determine "maximum" rate.  If indeed using a typical 9600bps then character line time is about 1ms for each.  So for

a four-byte or five-byte packet your observed rates seem to match.

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

Lee,

I was just looking at #1 rather than the whole thread (not easy using mobile) but #1 says (rather curiously) 128,000 baud rather than 9600.

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

You have to be very careful about "printing" from inside an ISR!

Absolutely, which is why I suggested configuring Bascom's ring buffered, ISR driven, USART driver ( s ).

Then the "Print" instruction just stuffs the buffer.

 

And yes, Cliff's understanding of the instructions is correct.

 

JC 

Last Edited: Sat. Sep 30, 2017 - 02:11 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JC,
.
Then does Bascom have something a bit "lower level" than "Print A" to just send the 16 bit samples in binary?
.
I'm making another assumption that LabVIEW can be configured to accept either little or big endian binary data.

Last Edited: Sat. Sep 30, 2017 - 02:18 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
I was just looking at #1 rather than the whole thread (not easy using mobile) but #1 says (rather curiously) 128,000 baud rather than 9600.

But that doesn't really fit with the "evidence".  As further posts go on, that combination seems ridiculous.  As mentioned in #9, the AVR could well be running at 1MHz.

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

Then does Bascom have something a bit "lower level" than "Print A" to just send the 16 bit samples in binary?

Not at home... or on my main computer, so from memory:

 

GetADC(), after configured, triggers a single ADC reading and returns a Word, (unsigned 16 bit value).

This is a blocking function that awaits the data before continuing.

 

If one configures the ISR driven ring buffer for the USART, which can be done independently for either / both TxData or RxData, then the generic "Print Variable" is smart enough to just stuff the buffer.

A trailing ";" should suppress a trailing CRLF, which would significantly lessen the overhead. 

 

One can also use "PrintBin variable", to print the raw data, again with or without a trailing ";".

 

If one wants to get to a lower level, one can insert ASM code within the Basic code, (or intermix them to some extent).

 

I suspect that the OP needs to get the basic sample and stuff buffer working, which shouldn't be overly complex, rather than try to bit-bang directly too much.

 

That said, one could certainly write their own ring buffer and USART driver, and skinny down the push/pop ISR overhead, or run that within the Main Loop, and just use a Timer/Counter in ISR CTC mode for a uniform sampling data collection, and process the data upload without interrupts.

 

Also easy to manually trigger the ADC, (via writing to the ADC register directly), and move on, then obviously grab the data on the next pass, which would significantly improve overall throughput, (data collection AND data upload).

 

Lots of options, but not enough good info from the OP.

 

JC

 

Last Edited: Sat. Sep 30, 2017 - 06:06 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I see that can not provide enough info, because here I understood that I should study more to understand your comments and questions. In fact different technical points are in your comments but I have only very basic knowledge on ADC and micro. I am so sorrysad. Excuse me for taking your time with a hurried question. I have to read your comments and the datasheet more carefully to understand the points.

Thank you all very much.

Best Regards

Ali

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

 

Perhaps a short summary of ADC timing limits are in order. Using a Mega328 as a prototype:

 

1. The AVR 10-bit ADCs are guaranteed to produce the spec sheet behavior ONLY if the ADC is clocked between 50KHz and 200KHz.

 

2. The maximum sample rate for 10-bit resolution is 15K samples per second.

 

3. A conversion takes 14.5 clocks for a normal repeating externally triggered conversion, 15.5 clocks if it is auto-triggered.

 

4. The actual sample rate is determined by a combination of the ADC clock rate and the rate at which triggers occur. If the non-auto trigger rate is slower than one conversion time, then the conversion rate is the trigger rate.

 

What is this trigger? Usually, it is generated from an internal timer, though it CAN be driven by an external interrupt or other events. It can also be automatic, in which a new conversion is triggered by the completion of the previous conversion.

 

Thus, your report of maximum 150 samples per second is being set by something OTHER than the ADC. It COULD be how it is initialized or it could be the rate at which the ADC is triggered.

 

Your rate MAY be limited by the rate at which you can transmit sample messages. Lets consider 19.2Kbaud (one of the standard baud rates) as a starting example. That number is the number of bits per second that convey the data. A standard 8-bit byte really takes 10 bits (start bit, one stop bit, no parity, 8 data bits), so that baud rate gets you 1.92K bytes (characters) per second. If one message has 5 characters, then your maximum throughput is 1.92K/5 = 384 messages per second. To get 7K messages per second, you would need a minimum of (7k messages per second) * (5 characters per message) * (10 bits per character) = 350K baud. 500Kbaud should be achievable at F_CPU = 16MHz. IF you were to use only 2 characters per message, your required baud rate drops to 2/5 of the numbers referenced, above.

 

BUT, now it gets a bit dicey. The best ADC performance happens if you don't have other things running while the ADC is converting. Thus, you would LIKE to convert and wait to complete, then send and wait to complete, then convert and wait to complete, then send ... . Doing it this way means that the maximum conversion rate is set by the sum of the message time and the conversion time. So, with a minimum conversion time of 66.7 microseconds and a message time of 1/(500Kbaud//10/5) = 100us, the fastest that you would be able to do a full convert/send cycle is 167us. That translates into 6.0K! If you use 2, 3, or 4 characters per message, you could do it with a CPU clock of 16MHz. 

 

It is not clear to me how LabView fits into all this. It should compile your program and download it to run on the MCU. It should limit things only if it does not allow you to use the proper ADC settings and the needed baud rates.

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

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

jahana wrote:

I know that the MAX crystal for this chip is 16MHz.

Also, by changing the fuse bits I have activated the external crystal.

 

The internal and external frequency from a crystal or internal osc. should be 16MHz MAX, there is no internal crystal.

You might possibly get away with running the chip at 20MHz but at 24MHz it could be running just enough to be unstable.

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

Haven't heard from Jahana, the OP, in a while.

 

Anyway, I thought I'd try this today and see what happens.

Given that the OP gave it a shot, here is a working example.

 

This program runs on an Arduino Nano with its own USB-to-USART bridge chip to actually send the data to the PC via USB.

The Nano has a Mega328P micro and runs on a 16 MHz Xtal.

 

I used Timer/Counter #0, (8-Bit), in CTC mode to generate an interrupt at 6944.4 interrupts per second.

This is < 1 % error from the OP's desired 7 KHz sample rate.

One could test other ADC pre-scaler and TOP combinations, or investigate using the 16-bit Timer/Counter

if one wanted to reduce the error a bit further.

 

The work of the program is done within the ISR.

The ISR fires, reads the last ADC value, triggers the next ADC Sampling, and stuffs the ADC value into the print buffer.

The USART is using a ring buffered, ISR driven print buffer, (set up with one instruction, easy!).

The baud rate is set to 250000 which gives adequate time to transmit the two bytes of data for each ADC reading.

 

The data is not compressed, and is not wrapped within a packet.

 

The O'scope upper channel shows the ISR which does the real work of the program.

The ISR is firing at 6.94 KHz instead of the exact 7 KHz the OP mentioned.

The pin to monitor the ISR is set and reset as the first and last lines within the ISR.

Therefore the duration of the pulse shows the duration of the ISR routine.

In reality the ISR push and pop instructions precede and follow the pin set and reset, so that adds a couple of uSec's on each side of the pulse.

 

The lower O'scope tracing is the USART's TxData pin, at 250000 baud.

 

The ADC reading is obtained, then the actual data is changed to an ASCII "C" in order to allow one to watch the data on a PC terminal emulator program.

The USART is sending the C then the upper byte of 0's.

The USART then goes Idel, (high), before the next ISR firing.

 

The code mentions a few extra LEDs and a push button switch, obviously not needed, but they were part of the setup...

One can use a Bascom statement to configure the Timer/Counter for CTC interrupt mode, but I prefer to do it myself.

In that way I know exactly how it is being configured.

 

I also elected to manually trigger the ADC in single shot mode, as I think the Bascom single shot instruction awaits the ADC returning the value.

In this case that isn't desired.

 

Sorry for all of the "Magic Numbers" in the set up, but at least they are documented in the comments!

 

JC

 

 

 

'File Name:  Nano ADC to USART Test V1.bas
'JEC  Bascom   Oct 2, 2017

'This is a quickie test project for a Forum question regarding sampling ADC
'at 7 KHz and uploading the data via the USART.

'This uses an Arduino Nano board, Mega328P @ 16 MHz, 5V system
'This Nano has a USART to USB bridge chip: CP2102.

'Nano Hardware:
'USB Bridge is on PortD.0, RxD
'USB Bridge is on PortD.1, TxD
'On PCB LED is on PortB.5  LED
'
'Extra hardware on the breadboard at the moment, not needed:
'PortD.3    LED   Hi = On
'PortD.4    LED   Hi = On
'PortD.5    LED   Hi = On
'
'PortD.6    PB Switch   Needs Internal Pull Up Resistor enabled.
'PB Switch normally reads high, is low when pressed.

'Note:  ARef pin has a cap to ground, it is NOT connected to any
'voltage reference.
'The ADC is configured to use the Vcc rail, set up internally.

'V1   Oct. 2, 2017  Works
'Set up T/C for 7 KHz ISR
'Set up ADC for 10bit data to a Word variable
'Set up ring buffered, interrupt driven, USART TxData driver

'Note well:
'The functionality of this program is really entirely within the
'ISR.  Main Loop flashes an LED for fun.

'Method:
'Isr Fires At 7 Khz.
'Inside ISR read the LAST ADC reading and stuff it in USART TxData buffer
'Trigger the next ADC reading to take the next reading
'There is NO Packetization of the data.
'There is NO data compression.
'Data synchronization at the PC end is left as an exercise for the user
'Note:  After reading the ADC data, this program changes the ADC data value
'to a "C" to allow it to be seen on a terminal emulator program on a PC.

'Note:  With the USART running with a Baud Rate of 250000 one has time to send
'the TWO data bytes to the PC in the interval between the ISR firings.
'The 10 Bit data is send as a Word, (two 8-bit Bytes).
'No data compression is used.
'One might fit in a third Byte, (just barely, didn't calc or test this).


'-----------------------------------------------------------------------------------------

$regfile = "m328pdef.dat"                                   'Micro used
$crystal = 16000000                                         'Micro's Clock Frequency

$hwstack = 64                                               'Hardware Stack
$swstack = 64                                               'Software Stack
$framesize = 64                                             'Frame Space
'$baud = 57600                                               'Set Baud Rate
$baud = 250000                                              'Set Baud Rate

   'Configure the Port's Pins for Input or Output mode.
   Config Portb.5 = Output                                  'LED
   Config Portd.3 = Output                                  'LED
   Config Portd.4 = Output                                  'LED
   Config Portd.5 = Output                                  'LED
   Config Portd.6 = Input                                   'User Push Button Switch

   'Type Word is 16 Bit unsigned
   'ADC Value is 10 Bit data, Right justified.

   Dim Regval As Byte                                       'Register Value for manual config
   Dim X As Byte                                            'Loop counter
   Dim Ttcnt As Word                                        'TicTock ISR Counter

   Dim Adcval As Word                                       'ADC Data Value, Word
   Dim Pbsw1 As Byte                                        'PB Switch #1's value

   Led0 Alias Portb.5                                       'LED on Nano PCB
   Led1 Alias Portd.3                                       'Led, Red
   Led2 Alias Portd.4                                       'Led, Yellow
   Led3 Alias Portd.5                                       'Led, Green
   Pbs1 Alias Pind.6                                        'PB Switch, Pressed = Low

'...............................................................................
   'Setup Timer/Counter #0 for Interrupts:
   'Bascom can configure the Timer/Counter for generating interrupts.
   'I prefer to do it myself, then I know the specific details of how it
   'has been configured.

   'This will configure the M328P Timer/Counter #0, (8-bit), for an interrupt
   'rate of APPROXIMATELY 7 KHz.
   'One can, of course, look at using other T/C prescaler settings, or a 16 bit
   'T/C and see if the error in the 7KHz rate can be reduced.
   'This example, however, demonstrates the concept and the 7 KHz sampling rate
   'is actually at 6944.4 Hz, for < 1% sampling rate error.

   'Configure M328P Timer/Counter #0,(8-Bit), for APPROX 7 KHz ISR rate:
   'CTC Mode, Clear Timer On Compare Mode
   'Enable TC0 in Power Reduction Register.
   'Do not enable any hardware output pins.
   'uC Clock = 16 MHz
   'Prescale = /64    16MHz/64 = 250,000 clock into the TC0 module.
   '250k / 7000 = 35.714, so round this up to 36
   'This means if the T/C counts to 36 it will generate an interrupt at ~ 7 KHz.
   'Set the T/C TOP value to 35, as the T/C roll over from TOP to zero also
   'counts as one count.

   'Using Output Compare A for this.
   'Must write 0 to PRR Bit 5 to Enable TC0.  Leave other bits alone.

   'First Turn On the Timer/Counter0 Module.
   'Read the Power Reduction Register, set the PRTim0 bit to 0 to Enable it.
   'Then write it back.  This does NOT alter any other module's activity.
   'Bitwise AND with 1101 1111   All bits unchanged, except Bit 5 = 0.
   Regval = Prr                                             'Read in current Power Reduction Register Values
   Regval = Regval And &B11011111                           'Force Bit 5 = 0
   Prr = Regval                                             'Save new value

   'Now set up the Timer/Counter#0 Control Registers for CTC Mode,
   'PreScale Div by 64:
   'No output on hardware pins.
   Tccr0a = &B00000010                                      'Timer/Counter Control Register A
   Tccr0b = &B00000011                                      'Timer/Counter Control Register B

   'Now set the TOP value for the A Output Compare Register.
   'I want this to be 35 dec  for a count of 36 dec.
   Ocr0a = 35                                               'TOP for CTC count of 36d, ~ 7KHz

  ' Ocr0a = 249                                              'TOP for CTC count of 250, 1 KHz ISR

   'Now Set The Interrupt Mask:  Enable Output Compare A Match Interrupt
   Timsk1 = &B00000010                                      'Timer/Counter1 Interrupt Mask Register

   'Now Enable the Interrupt and define the ISR handler:   Output Compare 0 A
   Enable Compare0a
   On Oc0a Heartbeat
'...............................................................................

   'ADC Module Setup:
   'Configure the M328P ADC for Single Conversion Mode
   '10 Bit resolution
   'There are 8 Analog Inputs on PortA.
   'Use the Multiplexer to set the desired input Pin.
   'Config for Vref = Internal connection to the Vcc, (5V) rail.
   'Config for ADC0 as the input source.
   'Config for Single conversion, without using ADC interrupts.
   'Manually start conversion by setting Bit 6 in ADCSRA register.
   'Ignore first conversion result.

   'First Turn On the ADC Module in the Power Reduction Register,
   'In PRR Bit 0 = 0 to Enable the ADC module
   'Read the Power Reduction Register, set the PRADC bit to 0 to Enable it.
   'Then write it back.  This does NOT alter any other module's activity.
   'Bitwise AND with 1111 1110   All bits unchanged, except Bit 0 = 0.
   Regval = Prr                                             'Read in current Power Reduction Register Values
   Regval = Regval And &B11111110                           'Force Bit 0 = 0
   Prr = Regval                                             'Save new value

   'ADC: Vref = Vcc internally selected, R just data, ADC Ch 0
   Admux = &B01000000

   'Trigger the first ADC Read to set up the ADC hardware:
   'Enable ADC, No Interrupts, Pre-Scale = 128, (ADC Clock = 125 kHz)
   Adcsra = &B11000111

'............................................................................
   'Setup USART:
   'Config the HW USART for interrupt driven ring buffered output
   'Serialout = serialout0 = The first USART.
   'Default N,8,1 is used if Config isn't used.
   Config Serialout = Buffered , Size = 128

'............................................................................


'............................................................................
Premain:
   'Turn on PB Switch's Internal Pull Up Resistor:
   Portd.6 = 1                                              'Turn On Pull Up Resistor


   'Flash an LED on Startup:
   For X = 1 To 10
      Set Led0
      Waitms 50
      Reset Led0
      Waitms 50
   Next X


   'Now Enable Global Interrupts:
   Enable Interrupts                                        'Global Enable Interrupts

Main:
   'Program's real work is done within the ISR.
   'This Main Loop just flashes an LED for kicks.
   'Flash an LED about 1 Hz (Without ISR)

   'LED's Off
   Reset Led1
   Reset Led2
   Reset Led3

   Do
      'Flash an LED, NOT ISR driven
      Set Led2
      Waitms 100
      Reset Led2
      Waitms 900

   Loop


Heartbeat:
   'Timer/Counter #0 ISR:
   'This ISR fires at APPROX 7 KHZ rate.
   '  Set an I/O Pin for O'scope monitoring
   '  Read in Last ADC conversion
   '  Trigger the next ADC conversion
   '  Stuff ADC reading into the USART Transmit Buffer
   '  Flash an LED at 1 / Sec
   '  Push Button Switch Debounce can be added, also...
   '  Clear the O'scope Pin

   'TickTock counter  TTCnt

   'Set PortD.3 I/O Pin to watch ISR fire on O'Scope.
   'This is LED 1, so it will also glow dimly.
   Set Led1                                                 'Pin High

   'Process ADC Data:
   'Read in the current ADC reading
   'Trigger the Next ADC reading
   'Then stuff the ADC data into the USART's Transmit buffer

   'Automatically read in ADCL, then ADCH, put in ADCVal variable:
   Adcval = Adc                                             'Get ADC data

   'Trigger the next ADC Reading
   'Enable ADC, No Interrupts, Pre-Scale = 128, (ADC Clock = 125 kHz)

   '**********************************
   '  Change the ADC Data to an ASCII Character to
   '  see it on the "C's data terminal program
   '**********************************

   Adcval = 67                                              '"C"  Fake Data
   Adcsra = &B11000111

   Printbin Adcval                                          'Upload the ADC data

   'Flash an LED once per second
   Ttcnt = Ttcnt + 1                                        'Incr
   If Ttcnt < 100 Then
      Set Led0                                              'LED On
   Else
      Reset Led0                                            'LED Off
   End If

   If Ttcnt > 999 Then
      Ttcnt = 0                                             'Rollover
   End If


   Reset Led1                                               'Clear O'scope marker

   Return


   End