CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

18F2550 ADC Sampling Rate
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
hops-cc



Joined: 06 Mar 2012
Posts: 6

View user's profile Send private message

18F2550 ADC Sampling Rate
PostPosted: Tue Mar 06, 2012 7:50 am     Reply with quote

Hi everyone,

I'm new here. I made an ADC circuit with 18F2550. I need to take samples from an ECG signal. Maksimum frequency of ECG signal is about 45 Hz. My pic doesn't take sample fastly so i lost some signals when i see them on MATLAB software. When i apply sinus 10 Hz to ADC it shown on matlab like triangle signal. I want to write a loop to take samples from ECG signals fast enough. Maximum freq = 45 hz so from nyquist criteration i need to make sampling at least 45*2 = 90 hz. That means sampling period must be at least 1/95 sn = 10,5 ms.

So far so good. But now i dont know to configure the ADC time to adjust these values and is there anyone knows the maximum sampling rate can be archived by 18F2550 ?? Whats the maximum frequency ??

SIMPLY, I WANT TO LEARN HOW TO ADJUST THE TIME BETWEEN THE SAMPLES.


Here's my configuration codes. Thanks

Code:
#include <18F2550.h>
#device ADC=10
#fuses HSPLL,USBDIV,PLL5,PUT,CPUDIV1,VREGEN,NOWDT,NOPROTECT,NOLVP,NODEBUG,NOMCLR
#use delay(clock=48000000)
     
static unsigned int16 ADC1 = 0;
static unsigned int16 ADC2 = 0;
static unsigned int16 i=0;

void user_init(void)
{
   set_tris_a(0x03);                    //RA0,RA1 input
   set_tris_b(0xFF);
   setup_adc_ports(AN0_TO_AN1);
   setup_adc(ADC_CLOCK_INTERNAL);
}

unsigned int16 ADC_read(byte channel)
{
   unsigned int16 value=0;
   set_adc_channel(channel);
   delay_us(20);
   value = read_adc();
   return value;
}
temtronic



Joined: 01 Jul 2010
Posts: 9225
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Tue Mar 06, 2012 8:12 am     Reply with quote

first problem

simply put...you have to read the PIC datasheet. Everything you need to know is there.Nice thing about PICs..they're all very similar. Learn something once and you can apply to most PICs !!

1)
A 5 volt PIC ADC ONLY accepts input of zero to just less than +5 volts. NO negative voltages are allowed!! You'll need an ac/dc convertor for that.

Sinus (sine wave ?) values will only be read on the +ve phase. -ve hase will be zeros.

2) You do not need to use the set_tris_..... statements. Let the compiler do it for you, automatically.

3) Read the ADC section of the manual.There's a chart on the adc 'clock + speed' and almost always you NEVER want to use 'adc_clock_internal'.

4) CCS supplies lots of example programs in the 'examples' folder. You will find several that use the ADC and display data.

5) The PIC will easily sample at 90 Hz !!!
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

ECG to MATLAB
PostPosted: Tue Mar 06, 2012 8:56 am     Reply with quote

You can use a PIC for negative voltages. You bias the analogue input to somewhere in it's common mode range.

From what you're saying, there should not be any problem with either sampling frequency or resolution.

However, from your code I can't see how you're getting the data from the PIC to MATLAB. There's something wrong/missing if you can't get a PIC to take enough samples to give a reasonable sine wave at 10Hz? What are you not telling us?

Nyquist is fine for the ultimate boundary, But I suspect you would be disappointed with what you got at the Nyquist limit. What you really need is at least an order of magnitude better than that. Again no problem for most PICs.

NB. Code is more readable in the code box.

Mike
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Tue Mar 06, 2012 9:31 am     Reply with quote

Quote:

from an ECG signal

these are TINY mv level signals at best
and hard to resolve
without SERIOUS analog processing -

as is - you have NO signal that you can resolve on even a 12Bit A/D pic
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

ECG signals
PostPosted: Tue Mar 06, 2012 3:20 pm     Reply with quote

I remember now. Long time ago, I met early versions of ECGs. There were issues with, OPAs saturating for tens of seconds, and isolating the victim / test-subject from the lethal possibilities of mains connected displays.

On that note:-

Is you ECG signal already suitably processed?
Is it effectively ac or dc coupled?

Mike
hops-cc



Joined: 06 Mar 2012
Posts: 6

View user's profile Send private message

PostPosted: Fri Mar 09, 2012 8:52 am     Reply with quote

Hi guys,

I know ECG signal magnitude is about milivolts. But i use amplifier, gain controller and DC adder to adjust it between 0-5 V. I have no problem with hardware and i already took samples of eCG signals in matlab. But, the points is that, my codes don't work fast as it should be. I can't sampling fast enough. I see the problem when i apply 10 Hz sinusoidal (Dont say that,you cant apply negative voltages because it's DC added voltage. that's not the point). signals becomes triangle. That means sampling frequency isn't fast enough. I'm new on CCS programming. I tried to write a loop that takes 64 samples (64 because i will send this char on USB pipe,1024 recommended but i couldn't made it yet). Can you help me with the codes. I just want to make sampling at least above 90 hz (i prefer 200-400 hz). Take those samples to a array and send them on USB pipe. I this method, I'm sure i will not be failed. The below codes takes only one sample and after send it to matlab. This so slow i think. So i want to take samples as much as possible at one time instead of doing one by one. And after send them at one time. Then make an signal processing on matlab with that array.

Code:

#include <18F2550.h>
#device ADC=10
#fuses HSPLL,USBDIV,PLL5,PUT,CPUDIV1,VREGEN,NOWDT,NOPROTECT,NOLVP,NODEBUG,NOMCLR
#use delay(clock=48000000)

#define USB_HID_DEVICE     FALSE             
#define USB_EP1_TX_ENABLE  USB_ENABLE_BULK   
#define USB_EP1_RX_ENABLE  USB_ENABLE_BULK   
#define USB_EP1_TX_SIZE    64
#define USB_EP1_RX_SIZE    64   
#include <pic18_usb.h>     
#include <USB_Konfigurasyon.h>           
#include <usb.c>         
#define UcNokta1       1

static unsigned int16 ADC_deger1 = 0;
   
void user_init(void)
{
   set_tris_a(0x03);   
   set_tris_b(0x00);
   setup_adc_ports(AN0);
   setup_adc(ADC_CLOCK_INTERNAL);
}
 
unsigned int16 ADC_Oku(byte kanal)
{
   unsigned int16 olcum=0;
   set_adc_channel(kanal);
   delay_us(20);
   olcum = read_adc();
   return olcum;
}

void main(void)
{
   byte sayac=0;
   byte gelen_paket[64];               
   byte gond_paket[64];             
  user_init();                     
   usb_init();                     
   usb_task();                     
   usb_wait_for_enumeration();         
   if(usb_enumerated())

      for (;;)
   {
      while(usb_enumerated())
      {
                     
                           [b]ADC_deger1=ADC_Oku(0);   //Here's where i want to write a loop that takes 64 samples.
                           gond_paket[1] = (byte) ADC_deger1;
                           gond_paket[2] = (byte)(ADC_deger1>>8);
                           sayac = 0x02;[/b]
             
                                       
         if(sayac!=0)
         {
         usb_put_packet(UcNokta1, gond_paket, sayac, USB_DTS_TOGGLE);
         sayac = 0;

         }
      }

   }
}


Last edited by hops-cc on Fri Mar 09, 2012 9:22 am; edited 1 time in total
Ttelmah



Joined: 11 Mar 2010
Posts: 19504

View user's profile Send private message

PostPosted: Fri Mar 09, 2012 9:20 am     Reply with quote

Have a look at this thread:
<http://www.ccsinfo.com/forum/viewtopic.php?t=47494>

Send the samples to USB, instead of serial, and you should be starting in the right direction.

Best Wishes
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Fri Mar 09, 2012 9:54 am     Reply with quote

here is a trick i use all the time when trying to take a lot of samples on different PIC channels.

every time you take a reading, and BEFORE formatting and sending the data - set the NEXT channel you will be reading - instead of just before you read it.

Also keep in mind that the nyquist frequency is only the outer limit for getting ANY data - not a sampling rate that preserves the WFM AT ALL well
when you are after waveform accuracy.

20X or even 100X that rate is where i would set my sights - and in the case of a 10 hz WFM - i'd be targetting 500 samples /sec to have a decent reconstruction of the signal. BTDT with biophysical waveforms that are much faster than 10hz. Then again i use an external parallel 16 bit ADC and exploit 230400 baud to get rid of the data in hex ........
Ttelmah



Joined: 11 Mar 2010
Posts: 19504

View user's profile Send private message

PostPosted: Fri Mar 09, 2012 10:14 am     Reply with quote

Actually you can do even better than this!....

As soon as the ADC starts actually converting, the voltage source is disconnected from the multiplexer. So you can do this:

Code:

read_adc(ADC_START_ONLY);
set_adc_channel(next_channel);
while (!adc_done()) ;
val=read_adc(ADC_READ_ONLY);


and the 'new' channel will be connected to the ADC input as soon as the conversion finishes!. A good few cycles earlier than if you wait till after you have read!.

A 'little known' feature that can be useful if you are trying to really optimise the timing.

Best Wishes
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Fri Mar 09, 2012 3:29 pm     Reply with quote

glad i posted that method of mine.

Now I want to be TTELMAH when i grow up , or at least his 65 YO adopted
student.

Very Happy Very Happy
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

Sampling Rate
PostPosted: Fri Mar 09, 2012 5:14 pm     Reply with quote

How do you KNOW that your problem is with the PIC?

Performing 5,000 conversions per second should be well within range of a lowly '877 & 3.6864MHz crystal. That's 10bit conversion and two characters per @ 115,200baud. If you don't like sending data as binary, you should be able to get hex and a CR(or a comma) to go at 2.5k/s.

Is it possible, the problem lies at the PC end, not the PIC?

Mike
temtronic



Joined: 01 Jul 2010
Posts: 9225
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sat Mar 10, 2012 6:38 am     Reply with quote

I think Mike's right. as I KNOW I can get 1 megabaud serial communcations with an 18F4550 using the internal UART tied to a TTL<-->USB dongle. Even 'direct' to the USB I/F of the PIC, I get 1 megabaud with the CDC 'driver'.Data is formatted as CSV,stored into a file by realterm, to autoload into Excel.

A quick test...
You should try 'regular' rs232 serial to the PC ( bypassing ALL the PIC USB stuff). Just simply read 64 samples,store in buffer, transmit buffer data, pause a bit, do it again.On the PC side , use a terminal program to display data.

Getting USB on the PC may be your headache as we don't know what application you're using.
hops-cc



Joined: 06 Mar 2012
Posts: 6

View user's profile Send private message

PostPosted: Sat Mar 10, 2012 4:18 pm     Reply with quote

Hi everyone,

Thanks for all the advice. This project is my final project in my engineering faculty so I have to complete this task with USB and use MATLAB for signal processing. I will write a MATLAB GUI for see the signals and other purposes.

So, now I made a calculation, I need maximum 2 seconds of measurement each time. I chose my sampling frequency of 500 Hz, so I will acquire approximately 1000 samples at each measurement. I will write the measurement on a char and send them by isochronous USB transfer (1024 packet at one time). My second problem is to adjust the Sampling interval. I don't know how to. TAD values and Fosc values confused me.

Now i can only transfer 256 packets with BULK or INTERRUPT TRANSFER. But i want to switch to isochronous transfer. I couldn't find location that i will modify on the codes for isochronous transfer. Here's all my codes that show what i tried to do.

Code:

#include <18F2550.h>
#device ADC=10
#fuses HSPLL,USBDIV,PLL5,PUT,CPUDIV1,VREGEN,NOWDT,NOPROTECT,NOLVP,NODEBUG,NOMCLR
#use delay(clock=20000000)

#define USB_HID_DEVICE     FALSE
#define USB_EP1_TX_ENABLE  USB_ENABLE_BULK    //Uçnokta1'de Yığın transferi aktif
#define USB_EP1_RX_ENABLE  USB_ENABLE_BULK   
#define USB_EP1_TX_SIZE    1000                 //Uçnokta1 için maksimum alınacak ve gonderilecek
#define USB_EP1_RX_SIZE    2                 //veri boyutu (64 byte)
#include <pic18_usb.h>     
#include <USB_Konfigurasyon.h>                //USB konfigurasyon bilgileri bu dosyadadır.
#include <usb.c>         
#define UcNokta1       1
#define Komut          gelen_paket[0]


static unsigned int16 ADC_deger1 = 0;   
void user_init(void)
{
   set_tris_a(0x01);                    //RA0 giriş
   set_tris_b(0x00);
   output_b(0);
   setup_adc_ports(AN0);
   setup_adc(ADC_CLOCK_INTERNAL);
   
 }
unsigned int16 ADC_Oku(byte kanal)
{
   unsigned int16 olcum=0;
   set_adc_channel(kanal);
   delay_us(10);
   olcum = read_adc();
   return olcum;
}
void main(void)
{
   unsigned int16 sayac=0;
   unsigned int16 gond_paket[1000];
   byte gelen_paket[2] ;            //gelen paket
   
 
   user_init();
   usb_init();                     
   usb_task();
   usb_wait_for_enumeration();         //Cihaz, hazır olana kadar bekle
   if(usb_enumerated())
   output_high(Pin_A2);                //USB bağlantısı kurulduysa LED'i yak.
 
      while(usb_enumerated())
      {

                           unsigned int16 i;
                           for (i=1;i<=500;++i)  // Here should be a loop that takes 1000 samples during 2 seconds with 500Hz sampling frequency.
                           {
                           ADC_deger1=ADC_Oku(0);
                           gond_paket[(2*i)-1] = (byte) ADC_deger1;
                           gond_paket[(2*i)] = (byte)(ADC_deger1>>8);
                           delay_us( ); // I Don't know the delay ? what it should be for 500 Hz sampling rate ?
                           }
                         
                           sayac = 1000;
             

         if(sayac!=0)
         {
         usb_put_packet(UcNokta1, gond_paket, sayac, USB_DTS_TOGGLE);
         sayac = 0;
         Komut = 0;
         }

      }
   }
}
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Sat Mar 10, 2012 5:28 pm     Reply with quote

Create a 2ms interrupt. Use that to control the ADC timing. That way you'll not miss any data. The ADC could continue whilst sending data out.

A problem I see with 1000 samples is you're close to running out of RAM. Do you really need 10bit ADC? With 8bit ADC you will only need half the RAM. (Unless you do some sort of data packing.)

Mike
hops-cc



Joined: 06 Mar 2012
Posts: 6

View user's profile Send private message

PostPosted: Sat Mar 10, 2012 5:34 pm     Reply with quote

Mike Walne wrote:
Create a 2ms interrupt. Use that to control the ADC timing. That way you'll not miss any data. The ADC could continue whilst sending data out.

A problem I see with 1000 samples is you're close to running out of RAM. Do you really need 10bit ADC? With 8bit ADC you will only need half the RAM. (Unless you do some sort of data packing.)

Mike


First, for now I only can copy paste from other codes. I'm new on CCS programming. But I will try that advice about interrupt. I don't know why interrupt is used and when used. I will search it. Second thing that is PIC can make ADC conversion to 8 bit instead of 10 bit ?

I guess it modified from # device ADC=10 code. Can you help me with that interrupt codes ? please.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group