Important changes to forums and questions
All forums and questions are now archived. To start a new conversation or read the latest updates go to forums.mbed.com.
Pin19 analogIn consistently noisier than p20/p18 analogin pins
After looking at your code ..
#include "mbed.h" DigitalOut myled(LED1); //analog inputs AnalogIn ain_v1(p19); AnalogIn ain_v2(p20); DigitalOut ref(p18); DigitalOut led1(LED1); DigitalOut led2(LED2); DigitalOut led3(LED3); unsigned short p1_cur[BUF_SIZE]; // sample buffer unsigned short p2_cur[BUF_SIZE]; // sample buffer unsigned char ind_write; // queue write index unsigned char ind_read; // queue read index unsigned int t_local; void get_readings() { //add nothing to the ISR unless it's strictly required. p1_cur[ind_write] = ain_v1.read_u16()>>4; //bottom 4 bits are 0 p2_cur[ind_write] = ain_v2.read_u16()>>4; // bottom 4 bits are 0 // Update the write index if (ind_write==BUF_SIZE-1) { ind_write = 0; } else { ind_write++; } } int main() { reset variables ind_write = 0; set queue index to 0. ind_read = 0; int samp_cnt=0; t_local = 0; ref = 0; set pin to 0 to see if it helps with noise Setup timer interrupts for samping the ADC channels flipper2.attach_us(&get_readings, 1000000/SAMP_RATE); the function to be attached and the interval in us spin in a main loop. flipper will interrupt it to call flip while(1) { if (samp_cnt>(SAMP_RATE>>2)) { blink an led led2 = 0; } else if (samp_cnt<SAMP_RATE) { led2 = 1; } else { samp_cnt = 0; } samp_cnt++; if (ind_read != ind_write) { new data, send it out over serial. // If you're going to apply some math to the raw samples, it should be done here serial.printf("%i,%i,%i\r\n", t_local,p1_cur[ind_read],p2_cur[ind_read]); t_local++; // increment local time (just a monotonically increasing sample counter that will overflow Update the read index if (ind_read==BUF_SIZE-1) { ind_read = 0; } else { ind_read++; } } } } }
Correct me if I am wrong,
you are only reading 2 ADC Channels,
I belive that the reason is because Pin 20, has a significant amount of time to settle (charge internal capacitors), in comparison to Pin 19.
there are a few possable compromises/solutions.
Best: External ADC Chip, one for each channel, or one with 2/4/8 seperate ADC blocks (none spring to mind)
compromise 1: Interleaving, sample each ADC alternatly,
who++; if (who && 1) { // Sample ADC 0 } else { // Sample ADC 1 }
or you could allow a short 'Charging' delay for each channel ..
{ read.An1(); wait_us (10); result = read.An1(); }
or alturnatly, what I used to do for PIC's ADC (not quite the same ..
{ // Result_Previous = ReadADC(); // select MUX .. for next conversion }
I am taking an educated guess, that most of your nois is related to the actual switching of the multiplexer,
and not fully charding the sample cap.
Hope this was informative.
Ceri
We have found that pin19 in analogin sense mode (sampling at 25 Hz) is significantly noisier than pin20 and pin18 in analogin sense mode. We've tested this on on 2 mbed-M3 devices.
mbed code:
Virtual serial port over USB Serial serial(USBTX, USBRX);
interrupt driven timer Ticker flipper; Ticker flipper2;
analog inputs AnalogIn ain_v1(p19); AnalogIn ain_v2(p20);
DigitalOut ref(p18);
DigitalOut led1(LED1); DigitalOut led2(LED2); DigitalOut led3(LED3);
unsigned short p1_cur[BUF_SIZE]; sample buffer unsigned short p2_cur[BUF_SIZE]; sample buffer unsigned char ind_write; queue write index unsigned char ind_read; queue read index
unsigned int t_local;
void get_readings() {
add nothing to the ISR unless it's strictly required. p1_cur[ind_write] = ain_v1.read_u16()>>4; bottom 4 bits are 0 p2_cur[ind_write] = ain_v2.read_u16()>>4; bottom 4 bits are 0
Update the write index if (ind_write==BUF_SIZE-1){ ind_write = 0; } else { ind_write++; } }
int main() {
reset variables
ind_write = 0; set queue index to 0. ind_read = 0;
int samp_cnt=0;
t_local = 0;
ref = 0; set pin to 0 to see if it helps with noise
Setup timer interrupts for samping the ADC channels flipper2.attach_us(&get_readings, 1000000/SAMP_RATE); the function to be attached and the interval in us
spin in a main loop. flipper will interrupt it to call flip while(1) {
if (samp_cnt>(SAMP_RATE>>2)){ blink an led led2 = 0; } else if (samp_cnt<SAMP_RATE){ led2 = 1; } else { samp_cnt = 0; } samp_cnt++;
if (ind_read != ind_write){ new data, send it out over serial.
If you're going to apply some math to the raw samples, it should be done here
serial.printf("%i,%i,%i\r\n", t_local,p1_cur[ind_read],p2_cur[ind_read]); t_local++; increment local time (just a monotonically increasing sample counter that will overflow Update the read index if (ind_read==BUF_SIZE-1){ ind_read = 0; } else { ind_read++; } }
} }
matlab code for noise sampling on pins:
ser_prt = serial('COM11','BaudRate',9600,'Terminator','CR/LF');
fopen(ser_prt);
of = fopen('data.txt','w');
cnt = 0;
samp_rate = 25; % Hz buff_length = 30; % seconds
databuf = zeros(3,samp_rate*buff_length);
while cnt < 1000 tline = fgetl(ser_prt); cnt = cnt+1;
delim_loc = strfind(tline,',');
if isempty(delim_loc) tlocal = tline(1:delim_loc(1)-1); v1 = tline(delim_loc(1)+1:delim_loc(2)-1); v2 = tline(delim_loc(2)+1:end); fprintf(of,'%s,%s,%s\n\r',tlocal,v1,v2);
databuf(:,1:end-1)=databuf(:,2:end); databuf(:,end)=[str2double(tlocal),str2double(v1),str2double(v2)]; end
if mod(cnt,samp_rate) plot((databuf(1,:)-databuf(1,end))/samp_rate,databuf(2,:),(databuf(1,:)-databuf(1,end))/samp_rate,databuf(3,:)) fprintf('cnt %i\n',cnt) end
end
fclose(of);
fclose(ser_prt); delete(ser_prt); clear ser_prt;
X = fft(databuf(2,:)); Y = fft(databuf(3,:));
f = linspace(0,25,length(X));
figure(1) semilogy(f(f<25/2),abs(X(f<25/2)),f(f<25/2),abs(Y(f<25/2)))
figure(2) plot((databuf(1,:)-databuf(1,end))/samp_rate,databuf(2,:),(databuf(1,:)-databuf(1,end))/samp_rate,databuf(3,:))