I'm looking to add the ability to capture wave forms to an ATmega 328 based product and I've been unable to find details on how responsive the ATmega 328 is when doing A/D conversions. The code is being prototyped on an Arduino, but will be migrated to custom board when done.
My plan is to have a total period (typically 16 to 20 milliseconds, based on local AC line frequency) and sample a single pin on the order of 50 to 100 times during that interval. Can the ATmega 328 reliably perform that many conversions successively? The minimum interval per conversion is 16ms / 100 = 160us.
I can add a code example if anyone has to see code, but right now I'm more concerned about the minimum period between multiple successive A/D conversions.
The easiest way would be to write a Arduino script and do some timing benchmarks for yourself.
The other way - doing this by spec - requires some more input for each involved level.
On the lowest level is the ATmega328 chip. The docs on the ADC part says:
By default, the successive approximation circuitry requires an input clock frequency between 50 kHz and 200 kHz to get maximum resolution. If a lower resolution than 10 bits is needed, the input clock frequency to the ADC can be higher than 200 kHz to get a higher sample rate.
Assuming a 16 MHz clock for the ATMega the only available prescaler value for the ADC clock is 128 which is 125kHz for 10 bit resolution. You could use the prescaler value 64 (250kHz) if you can get away with 8 bit resolution.
Next: The doc says:
A normal conversion takes 13 ADC clock cycles. The first conversion after the ADC is switched on (ADEN in ADCSRA is set) takes 25 ADC clock cycles in order to initialize the analog circuitry.
So taking the 125kHz ADC clock this would mean ~9600Hz sample rate in "single conversion" mode. This is 104µs per sample. These are the Arduino defaults.
Compared to your requirement of 160µs this seems good.
BUT: So far only the conversion alone have been considered. You have to transfer the data somewhere. ALSO the Arduino analogRead() function has some overhead as you can see in the file wiring_analog.c in the Arduino dist.
This overhead might be to much - you have to test it for yourself.
On the other hand: Nobody forces you to use the Arduino analogRead function. Some available choices:
you can ditch the overhead of analogRead and/or
you can reconfigure the ADC to your needs (8 bit only, higher ADC clock) and/or
you can use "advanced" modes like continuous sampling ("freerunning mode"9 of the ADC or
you can use even interrupts to trigger the conversions.
Of course all of these choices heavily depend on your knowledge and time budget. :-)
Related
I am using two microcontrollers for a project, I want to measure execution time for some code with the help of internal timer of both microcontrollers. But One microcontroller's timer count till 32 bit value and second microcontroller's timer can count till 16bit value then it restart. I know that execution time of code is more than 16 bit value. could you suggest me any solution for this problem. (Turning ON and OFF GPIO pin doesn't provide useful results)
You should be able to measure execution time using either type of timer, assuming that execution time is less than days or hours. The real problem is how to configure the timer to meet your needs. How you configure the timer will control the precision or granularity of the measurement, as well as the maximum interval that can be measured.
The general approach will be thus:
Identify required precision and estimate the longest interval to be measured
Given the precision, determine the timer clock prescaler or divider that will meet your precision requirements. For example, if the clock speed is 50 MHz, and you need microsecond precision, then select a prescaler such that (Prescaler) / (Clock speed) ~ 1 microsecond. A spreadsheet helps with this. For this case, a divider value of 64 gives us about 1.28 microseconds per timer increment.
Determine if your timer register is large enough. For a 16-bit timer, you can measure (1.28 microseconds) * (2^16 - 1) = 0.084 seconds, or about a tenth of a second. If the thing you are measuring takes longer than this, you will need to rethink your precision requirements.
You should by now have identified the key parameters to configuring the timer, keeping in mind the limitations. If you update your answer with more specifics, such as the microcontrollers you plan to use and what you're trying to measure, I can be more specific.
I've got an Arduino with an ATmega328 processor. It can be operated at 3.3V which nets a clock signal frequency of about 12 MHz respectively 16 Mhz at 5V.
I connected an IMU to the Arduino which runs an AHRS algorithm turning accelerometer, gyroscope and magnetometer data into orientation data.
What does the higher frequency of 16 MHz actually mean in this context?
Will the AHRS be calculated faster so I get a lower latency? Can I poll the sensors more often? I want a deeper understanding of what I'm doing here.
Higher frequency means more clock cycles per second which means more operations are done during the same duration of time. This means AHRS runs faster and you will achieve a lower latency and if you are repeatedly reading values from the IMU, you will be able to poll more often.
I have a PIC24 based system equipped with a 24 bit, 8 channels ADC (google MCP3914 Evaluation Board for more details...).
I have got the board to sample all of the 8 channels, store the data in a 512x8 buffer and transmit the data to PC using a USB module when the buffer is full (it's is done by different interrupts).
The only problem is that when the MCU is transmitting data (UART transmission interrupt has higher priority than the ADC reading interrupt) the ADC is not sampling data hence there will be data loss (sample rate is around 500 samples/sec).
Is there any way to prevent this data loss? maybe some multitasking?
Simply transmit the information to the UART register without using interrupts but by polling the bit TXIF
while (PIR1.TXIF == 0);
TXREG = "the data you want to send";
The same applies to the ADC conversion : if you were using interruptions to start / stop a conversion, simply poll the required bits (ADON) and thats it.
The TX bits and AD bits may vary depending on your PIC.
That prevents the MCU to enter an interrupt service routine and loose 3-4 samples.
In PIC24 an interrupt can be assigned one of the 8 priorities. Take a look at the corresponding section in the "Family Reference Manual" -> http://ww1.microchip.com/downloads/en/DeviceDoc/70000600d.pdf
Alternatively you can use DMA channels which are very handy. You can configure your ADC to use the DMA, and thus sampling and feeding the buffer won't use any CPU Time, same goes for UART I beleive.
http://ww1.microchip.com/downloads/en/DeviceDoc/39742A.pdf
http://esca.atomki.hu/PIC24/code_examples/docs/manuallyCreated/Appendix_H_ADC_with_DMA.pdf
I know this sounds a bit funny :). But I am trying to eliminate possibilities:
On the Arduino Uno I have attached an interrupt triggered on HIGH to a routine which only increments a volatile defined long counter. This counter is displayed on an LCD screen.
If I connect a pulse generator with a frequency of 1 Hz at TTL levels, I would expect the counter to increase with about 1 per second. However this is not the case.
As the frequency is 1 Hz (duty cycle 50%) could it be possible that once the counter is incremented the IRS is exited (and clears the interrupt flag) BUT: the INT0 level is still HIGH so the ISR would be called again? At 1 Hz 50% duty, the HIGH would stay for 500 ms and at 16 mHz...
The processor at the heart of any Arduino has two different kinds of interrupts: “external”, and “pin change”. There are only two external interrupt pins on the ATmega168/328 (ie, in the Arduino Uno/Nano/Duemilanove), INT0 and INT1, and they are mapped to Arduino pins 2 and 3. These interrupts can be set to trigger on RISING or FALLING signal edges, or on low level. The triggers are interpreted by hardware, and the interrupt is very fast. The Arduino Mega has a few more external interrupt pins available.
So as commented: It triggers on an edge!
See more details on the Arduino Playground web page.
Two electrical reasons can explain why interrupt does not function as you need.
1- The pulse generator output and MCU input can have an impedance mismatch, which can cause ringing on the waveform edges. For example, if your function generator has a 50 ohm output capable of generating high frequencies you might see a problem driving a high impedance input like the Arduino at low frequency.
The name "pulse generator" makes me think this is a 50 ohm out device intended to make very short pulses with sharp edges. In such a case, you add a terminating resistor at the destination (load) to match the impedance of the source (pulse generator). For a 50 ohm output, 47 ohm would be close enough. If the output is 100 kohm, then place a matching resistor at the Arduino.
2- Just the opposite, the generator waveform edges may be so slow that the voltage passes through TTL 0 to 1 transition multiple times. If you have noise on your signal input, a slow edge could be causing multiple triggers. For example, if you are picking up some 60 Hz ripple from a power supply and grounding issues, your square wave edges won't be as square as you think.
In such cases hysteresis is a solution. There are many ways to de-glitch (debounce) in code. There is no answer that is right for all problems. A simple example would be that the ISR you require that the input reads high twice in a row for the edge to be accepted.
I am a CS guy getting started with Arduino. This is probably a very basic electronics question but from going over the arduino tutorials everything is connected to the arduino with a resistor.
Well since i am following the tutorials i know what type of resistor i should use but what i do not know is why i should use one? and What type of resistor to pick i am to do something which is not covered in a tutorial.
The resistor simply serves to limit the current into or out of a pin in case something goes awry. If your AVR decides to output high on a pin that something else wants low (or vice-versa), large, damaging currents can occur if not limited by some resistance. The current limit for AVRs is about 20 milliamps, and given that the voltages are usually 5V, something larger than 250 ohms "would work".
To give a margin of safety, 1-10k is a great choice; for digital signals it seldom matters unless you're into very high-speed applications (beyond the AVRs capability anyways). For analog inputs, a similar resistor would also be advisable, as the amount of current the ADC takes to sample is negligible when your resistor is in the few kilo-ohm range.
The underlying principle that you want to learn is Ohm's Law, which describes the relationship between voltage, resistance, and current in a circuit.
Resistors are used to
limit current,
devide voltage
protect against over voltage
pull-up, pull down
current to voltage conversion
etc ...
1) limit output current, the absolute max current per IO is 40mA, a typical LED works on ±2V 20mA.
the resistance value can by calculated by (5V - 2V)/(0.02A)=150Ω usually a 220Ω resistor is used, because: it consumes less power, there doesn't flow 20 milliamps, and there is no notable difference in emitted light.
2) if you have a analog voltage that variates between 0 and 10 Volts, you 'll need a voltage divider of 1/2. pick by example z2 10k and calculate z1 by 10k*(Vin,max/5V -1). take a value of resistance higher than the original calculated. and recalculate the new Vout.
3) place a resistor of 10k in series between the analog input of the arduino and the 'to measure voltage'
3) if you have to measure a analog current, you place a resistor to ground and the analog input, calculate the resistor by Z=5V/amps.
4) if you connect a button to the arduino, you 'll need to place a pull up or a pull down resistor. if you 're not using a resistor, the input is floating and can take any value (high or low). or you can enable the internal weak pull up. by pinMode(xx,INPUT); digitalWrite(xx,HIGH);. and disabeling by digitalWrite(xx,LOW); by default the pull-up is disabled.