Continuous ADC-capture over UART (Atmega328P/Atmega2560)

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

Hello,

My goal is to measure RC-receivers RSSI pin with atmega328p and send the Received signal strenght to computer using UART with the help of FT232.

The signal what I am measuring looks like this:

RSSI FROM RECEIVER

 

Signal always stays up about 500us and then drops to 0.7V for a while, but only after that I am interested of the signal level, becaus that is varying by the signal strenght.

 

EDIT: Signal is up when Rx is off. The Rx is turned on little earlier than Tx, so the 0.7 level is the noise level. Then the Tx is turned on and the connection is so good that the level goes to zero, but if there is very bad connection the level will be closer to noise level. That is the simple explaining to the behavior, but it is lot more comlicated.

 

So I want to measure samples from the last period of signal and do some calculation for them, but my problem is how to trigger the ADC or should I use continous mode.

I was thinking could I put my signal also to Input Capture pin and with auto trigger start the adc when there is rising edge and then store only the data after 1ms-> 1.4ms.

 

Thank you in advance for your tips!

 

 

Last Edited: Thu. Jun 21, 2018 - 11:49 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sound like a rather bizarre way to give RSSI?!

 

surprise

 

Are you sure you're looking in the right/best place?

 

maenpaa wrote:
only after that I am interested of the signal level, because that is varying by the signal strength

So how, exactly, does it "vary by the signal strength" ?

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

It might help to know what radio your using!

Jim

Mission: Improving the readiness of hams world wide : flinthillsradioinc.com

Interests: Ham Radio, Solar power, futures & currency trading - whats yours?

 

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

also a link to any documentation you have.

 

eg, how do you know that this is the RSSI signal ?

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

is it a AM or FM signal?

Is it RSSI out from a radio chip ? (number please)

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

I am using Turnigy Hobby King 2.4Ghz 4Ch V2 Tx and  9X 2.4GHz 8Ch V2 Rx which both uses AMICCOM A7105 chip. I have measured the RSSI straight from the RSSI pin from the RX A7105 Chip (Pin 1 as the datasheet says).

 

 

Last Edited: Thu. Jun 21, 2018 - 06:58 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You will need to low pass filter the signal, the modulation give some noise to the signal.

 

Add:

Or is this two radio's that make a communication, where you just listen?

 

on 2.4GHz there is all kind of noise your radio will see so perhaps make a ring buffer there always sample and when you receive a correct packet then look in the buffer to see how good the signal was.   

Last Edited: Wed. May 23, 2018 - 02:32 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

looking at the DS link provided, it chip has a digital RSSI value available, why not use it?

The RSSI pin is intended to be connected to the AGC cap to provide a filtered AGC voltage to the IF stage in the RX, it's not meant to be used as an RSSI output.

The chip has an internal ADC to read the RSSI at the proper time and provide a digital value.

 

 

Jim

 

Mission: Improving the readiness of hams world wide : flinthillsradioinc.com

Interests: Ham Radio, Solar power, futures & currency trading - whats yours?

 

Last Edited: Wed. May 23, 2018 - 06:58 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you for your replies.

I have do some more measurement and it is even compicated signal that I thought. The radio is frequency hopping and the frame I have took picture is just one frame and there is 16 frames which can be little bit different.

My best measurement way at this far is the average minumum value that is about 30mV when very close, 40mV when 10m away and 400mV when 100m away and when the Tx is out of the range the signal changes totally.

There are two main types of frames and I have to figure out why they are like that.

 

Also to the digital RSSI value, it would be useful but it is hard to get out from the A7105 chip.

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

Also to the digital RSSI value, it would be useful but it is hard to get out from the A7105 chip.

Not any harder than sending and receiving data, and certainly easier than burning CPU cycles doing signal processing. Show us the code/library you're using and we'll help out.

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

Can't help wondering if BER is a much more important indicator of (digital) signal condition than signal strength? (certainly is in other digital radio systems such as satellite TV reception). I'll bet the chip has registers for bit error rate too.

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

Hello and thank you for your solutions!

 

BER would be also good but I will be staying RSSI for now. The chip is very small and I was not able to solder straight to the chips legs anything so even that restrict my actions. Luckily the RSSI pin was soldered to the capasitor where I managed solder the wire. I have done much more measurement and got some new information about the behavior of Tx and Rx and the RSSI signal.

 

I desided to use continous mode ADC and send the raw data straight  to computer and then do the calculating by computer.

 

Last Edited: Thu. Jun 21, 2018 - 07:03 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello
Now I have got the program working. Now it is continous saving ADC values to 'ringbuffer' and when matlab calls values, it stops the ADC saving and sends the buffer to matlab.
After send is ready it continue saving data to buffer, but I need to wait until the buffer goes one round before I can call new values. Another option would be reading and saving data at the same time to the buffer, but I havent thought how it would work.
My code is based on Benn Thomsen Continuous ADC Capture code. My problem is that I am using atmega328P so I can have only 1024 bytes ringbuffer and for my apllication I have to use smallest sample rate, so I can get enough long sample in one buffer.

I think i will by Arduino Mega board so I can use larger ringbuffer and so on higher sample rate.

 

 

There is my AVR code if you are interested: (Badly commented)

/*
 * Hobbyking_buffer.c
 *
 * Created: 29.5.2018 14.42.03
 * Author: Miikka Mäenpää
 */ 

#include <avr/io.h>
#include <stdint.h>
#include <avr/interrupt.h>

#define F_CPU 16000000UL
#define BAUDRATE 38400
#define BAUD_PRESCALER (((F_CPU / (BAUDRATE * 16UL))) - 1)
#define BUFFER_SIZE 1024
#define FALSE 0
#define TRUE 1

volatile uint16_t bufferIndex=0;
uint16_t i=0;
volatile uint8_t data[BUFFER_SIZE];
volatile uint8_t data_in = FALSE;

void adc_init(void);
void USART_init(void);
void USART_send( unsigned char data);
void Button_init(void);

int main(void){

	DDRB = (1 << PB0);
	PORTB |=  (1 << PB0);		//Turn off LED
	//PORTB &= ~(1 << PB0);		//Turn on LED
	//PORTB ^=  (1 << PB0);		//Change LED

	USART_init();
	adc_init();
	Button_init();
	sei();

	while(1){
		if (data_in)
		{	cli();
			USART_send((uint8_t)(bufferIndex >> 8));
			USART_send((uint8_t)(bufferIndex));

			for (i = 0; i < BUFFER_SIZE; i++)
			{
				USART_send(data[i]);
			}

			data_in = FALSE;

			sei();
		}

	}
}

ISR(ADC_vect){

	data[bufferIndex++] = ADCH;

	if (bufferIndex == BUFFER_SIZE)
	{
		bufferIndex = 0;
		PORTB ^=  (1 << PB0);		//Change LED

	}

}

ISR(USART_RX_vect)
{
	data_in = UDR0;
}

//Turn ADC on/off with external button
ISR(INT0_vect) {

	if (ADCSRA  & (1 << ADEN)) //if ADC on
	{
		ADCSRA &= ~(1 << ADEN); //Turn off ADC
		PORTB |=  (1 << PB0);	//Turn off LED
	}
	else
	{
		ADCSRA |= (1 << ADEN) | (1 << ADSC); //Turn on ADC
	}

}

void adc_init(void){

	//ADC prescaler = 128 -> ADC Clock =  125kHz
	ADCSRA = ((1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0));

	//Voltage reference to AREF (2.5V?), Left adjust result
	ADMUX = (1 << REFS0) | (1 << ADLAR);

	DIDR0 = 0xFF; //Disable digital input registers A0-7

	//Free runnig mode (13 ADC clock cycles per conversion -> ADC SPS 9.615k
	ADCSRB &= ~((1 << ADTS2) | (1 << ADTS1) | (1 << ADTS0));

	//Turn on ADC, Enable interrupts, enable autotrigger
	ADCSRA |= (1 << ADEN) | (1 << ADIE) | (1 << ADATE);
	ADCSRA |= (1 << ADSC); //start conversion
}

void USART_init(void){

	UBRR0 = BAUD_PRESCALER;
	UCSR0C = ((0<<USBS0)|(1 << UCSZ01)|(1<<UCSZ00)); // Set frame format
	UCSR0B |= (1 << RXCIE0) | (1 << RXEN0) | (1 << TXEN0); // Enable receiver, transmitter and interrupt
}

void USART_send( unsigned char data)
{

	while(!(UCSR0A & (1<<UDRE0)));

	UDR0 = data;
}

void Button_init(void) {

	DDRD &= ~(1 << PD2);
	PORTD = (1 << PD2);

	EICRA = (1 << ISC01);	//Falling edge
	EIMSK = (1 << INT0);	//Enable INT0
}

  and MATLAB functions and code:

function [s] = Serial_Init(N)
instrreset

port = 'COM3';
s=serial(port,'BaudRate', 38400,'InputBufferSize',2*N);
fopen(s);
function Serial_close(s)
fclose(s);
instrfind
function [ voltage , buffer_index ] = Serial_READ(s,N)
fwrite(s,1)
data = fread(s,N+1,'uint8');
buffer_index = data(1);
voltage=data(2:end)*2.5/256;
end
clear all
clc
X=4;

V = zeros(X,1024);
V2 = zeros(X,1024);
N=1024;
Fs = 9.6154e3;
time = (0:N-1)./Fs;
s = Serial_Init(N);
pause(1)
buffer_index = zeros(X,1);
tic

for n = 1:X
    [V(n,:),buffer_index(n)] = Serial_READ(s,N);
    pause(0.200)
end
toc

for n =1:X
    V2(n,:) = V(n,[buffer_index(n)+1:end 1:buffer_index(n)]);
end

for n = 1:X
    figure(n)
    plot(time,V2(n,:),'-o')
    ax = gca;
    ax.XAxis.Exponent = -3;
    axis([0 1023/Fs 0 2.25])
    grid on
    xlabel('Time (ms)')
    ylabel('Amplitude')
end

Serial_close(s)

 

Last Edited: Thu. Jun 21, 2018 - 06:50 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

don't wire a pushbutton to an external interrupt! Maybe you've found out already that the button doesn't always work as expected. Pushbuttons bounce and give multiple interrupts per press. 

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

Yes that's true Kartman, but the push button is rarely used in this project (I did it for fun, just so I can turn it off when I go to lunch laugh), so it does not matter much (And I can always check from the led is the ADC on or off. 

 

What does matter is when the buffer goes round, there is some strange happening, maybe few measures skipped. But I think I will consentrate on prosessing the data until I get my Ardruino Mega board.

 

By the way, I am using external VREF for ADC and I did it with voltage divider from the USB VCC with two 1Kohm resistor to get 2.5V. Is there a better way you suggest or is it "good enough"?

 

EDIT: I didnt wait enough time in matlab so the buffer didnt have time to go around.

Last Edited: Thu. May 31, 2018 - 11:59 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello,

Today I got my arduino Mega board and burnt my code there. (can be seen few post earlier)

I noticed mega has 4 USART so I had to rename ISR(USART_RX_vect) -> ISR(USART0_RX_vect), but I think other names should be the same.

My USART connection was not working and the ADC Didn't work.
 

Code should start continous ADC and ISR function saves the value to buffer and everytime buffer gets full, led will change state and ADC strats from the beginning of the buffer.

ISR(USART0_RX_vect) stores sata and if the data is 1 the buffer is send to USART

But I figured out with the led that code will never enter the ISR(ADC_vect) or ISR(USART0_RX_vect)?
 

 

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

maenpaa wrote:
but I think other names should be the same.
I would not have thought a port from 328 to 2560 is as simple as changing the name of one ISR vect ! There's quite a lot different between those two chips so you need to look at every bit of every register of every peripheral you are using and find any change in behaviour and amend accordingly.

 

This is one of the many ways Arduino is "better" than plain C. It hides all the differences in "cores" so as long as you only call hardware adaption functions in the core it just works (and that can even involve a move from AVR to ARM!). as soon as you start hitting the silicon directly then when you move from one device to another you have to "port" any changes.

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

Yeah you are rght clawson that it is not so easy and It would have been easier to write whole thing new by arduino code, but I am not familiar with it so I tried plain C.

I have browsed the datasheets and there are many differences, but the basics and the names are pretty much the same. 2560 has little bit more possibilities in ADC but it has all the same register than 328, and pretty much same with the UART.
My biggest concern is, why any of my interrupts wont work frown

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

"pretty much" the same is not good enough!

 

They need to be either exactly the same, or you have to do all the work to take care of all the differences.

 

My biggest concern is, why any of my interrupts wont work

Because you have missed something!

 

As ever, the best approach is probably to take it little-by-little, getting one small part to work at each step - rather than trying to port the entire thing in one go.

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If all the interrupts don't work it hints at a couple of possibilities (which might actually be the same thing):

 

1) the code path that holds the sei() is not being executed

 

2) a while() loop is holding execution infinitely somewhere

 

As I say (1) may simply be a consequence of (2)

 

Don't suppose you have access to an ICE?

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

Should the interrupt vector in dependies be the same as in datasheet?
Datasheet says ADC is vector 30 but in dependies is said #define ADC_vect            _VECTOR(29)

 

Datasheets first vector is reset vector, what is not in dependies, so every vector number is missmatched.

 

EDIT: I guess no because 328P has also different numbers

Last Edited: Wed. Jun 13, 2018 - 10:32 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

maenpaa wrote:
Should the interrupt vector in dependies be the same as in datasheet? Datasheet says ADC is vector 30 but in dependies is said #define ADC_vect _VECTOR(29) Datasheets first vector is reset vector, what is not in dependies, so every vector number is missmatched.
GCC headers choose 1-based, datasheet chooses 2 based (they are actually 1 based but they count "reset" as number 1). Doesn't really matter because the _VECTOR(n) is effectively "hidden". You refer to things like "INT0_vect" and only behind the scenes is this temporarily interrupted as _VECTOR(1)

 

The key thing is that the C compiler headers match this:

 

http://svn.savannah.gnu.org/view...

 

which has:

50 	        .section .vectors,"ax",@progbits
51 	        .global __vectors
52 	        .func   __vectors
53 	__vectors:
54 	        XJMP    __init
55 	        vector  __vector_1
56 	        vector  __vector_2
57 	        vector  __vector_3
etc.

 

Last Edited: Wed. Jun 13, 2018 - 12:09 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I kind of understood what you were saying clawson but I dont honestly know where my C-compilers headers are indecision I havent really explored enogh how the code actually is compiled and transformed and burned into chip surprise. I dont either have ICE

 

I have been testing simple codes for mega2560 and I figured out that once the interrupt should occur, the code jumps to start of main and continues until sei(); and jumps again into start.

Last Edited: Wed. Jun 20, 2018 - 09:40 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Until I get the interrupts working, I was wondering is it possible to continuously send ADC data to computer if my ADC samplerate is ~10k SPS. (I managed to do it by stopping the ADC for the time UART sends data, but afterwards I would be much better to transmit continous data)

 

I was going to use ring buffer to store the ADC data and send it to computer and I did some calculations if the samplerate would be 10k SPS and one sample is 8 bits and then there is 1 start and 1 stop bit so the frame is 10 bits. So the buffer to work I would need 10*10k = 100k Baud rate? and is that achievable easily?

 

(Arduino Mega R3 (atmega2560 (16MHz external clock) and atmega16U2 handling the UART) -> Matlab2017b(Lenovo T470p, Win 10))

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

maenpaa wrote:
I have been testing simple codes for mega2560 and I figured out that once the interrupt should occur, the code jumps to start of main and continues
Almost certainly "catch all" described on this page in the manual:

 

https://www.nongnu.org/avr-libc/...

 

That is you have enabled some interrupt for which you have not provided an ISR() so it goes to "bad interrupt" which does a JMP 0 and restarts the AVR. This will happen as soon as you sei() and as soon as the interrupting event then occurs.

 

maenpaa wrote:
data to computer if my ADC samplerate is ~10k SPS.

If you send binary then it is 2 bytes for a reading (I assume 10 bit not 8 bit?). Each byte takes 11 bits with 8N1 framing so you need to send 22,000bps so any baud rate above that should allow you to do this.