ADC trouble MC9S08QG8

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

ADC trouble MC9S08QG8

3,018 Views
Tarania
Contributor I

Hi there, Im a junior who is doing a project where i am doing some uP work with the MC9S08QG8 and anaccelerometer. For the first part of the project, the accelerometer must be displayed on the 8 bits of PortB. The rest of my class is using assembly and i am using C so i cant get much help. I am having trouble getting the A/D to work right and was wondering if someone could give me some help.

 

Here is my code:

 

#include <hidef.h> /* for EnableInterrupts macro */
#include <MC9S08QG8.h> /* include peripheral declarations */

/*define outputs*/
#define out1 PTBD_PTBD0
#define out2 PTBD_PTBD1
#define out3 PTBD_PTBD2
#define out4 PTBD_PTBD3
#define out5 PTBD_PTBD4
#define out6 PTBD_PTBD5
#define out7 PTBD_PTBD6
#define out8 PTBD_PTBD7


void main(void) {
EnableInterrupts; /* enable interrupts */

PTADD = 0x00; //initialize as input

PTBDD = 0xff; // make port b output
PTBPE = 0xff; //Pullups on output

for(;:smileywink: {
 
__RESET_WATCHDOG(); /* kicks the dog */

 
ADCSC1_ADCO = 1; // enable continuous conversion
ADCCFG_MODE = 0x00; // 8 bit mode
ADCSC1_ADCH = 0x00;       // set channel 00 = PTA0 with Acc
  while(ADCSC2_ADACT);
  while(!ADCSC1_COCO);      // ADC conversion complete?
 
PTBD = ADCRL; // output 8bit ADC to Port B

 
 } /* loop forever */
}

 

 

Thanks for your help

Labels (1)
0 Kudos
13 Replies

716 Views
Tarania
Contributor I

Thanks very much for your posts, I got the ADC working. I just have a couple more questions. I have to sample two channels each at a frequency of 2KHz. I tryed setting the ICS but had trouble understand what to do. Also, i need to switch between these two channels, so is there a was to make a time delay between the channel samples so that i get 2KHz on each channel? Should I be using continuous conversion or not? i tryed doing one channel without continuous cenversion and it seemed to be sampling at a rate of approximatly 1Hz. 

 

Thanks so much for your help.

0 Kudos

716 Views
bigmac
Specialist III

Hello,

 

For sampling two channels, you will need to use single conversion mode. To accurately time the samples, you would need to generate a timer interrupt every 500 microseconds, and do the ADC conversions within the ISR code.  You would probably use the TPM module for this purpose, setup for software only output compare mode.  When the timer interrupt occurs, simply initiate a conversion for each channel in succession.

 

// Global variables:

volatile byte result0, result1, flag;

 

Then incorporate the following code within the tmer ISR function -

 

  ADCSC1 = 0;            // Commence new conversion Ch0

  while (!ADCSC1_COCO);  // ADC conversion complete?
  result0 = ADCRL;

  ADCSC1 = 1;            // Commence new conversion Ch1

  while (!ADCSC1_COCO);  // ADC conversion complete?
  result1 = ADCRL;

  flag = 1;              // Flag new results to main()
 

Regards,

Mac

 

0 Kudos

716 Views
Tarania
Contributor I

Thanks again bigmac, you have been very helpful! Sorry if i sound like a noob, this is my first project with an mpu. Where you typed,

 

// Global variables:

volatile byte result0, result1, flag;

 

will these store all 8 bits of the result? 

 

Also, im not sure how to set up the TPM to be 500uS from the datasheet. I understand that once the 500uS is complete you sample both channels, im just not sure how to set up the 500uS delay. Also, What is the purpose of the ISR code, cant i jusy have that time interupt every 500uS then sample both channels?

 

THanks again! 

 

 

0 Kudos

716 Views
peg
Senior Contributor IV

Hi again,

 

It really depends on what you are trying to achieve and what else you need to be doing.

Do you need an exact sample rate or just maintain a minimum rate?

Do you have other interrupts enabled?

You may need to set the timer up at double the rate and sample alternate channels at each timeout to avoid blocking in the ISR for both each time.

If the rate is not critical you could just do all of this in the main loop. I would suggest doing it this way first anyway, get it working then transfer the appropriate section into a timer ISR.

It may also be appropriate to simply generate a flag in the ISR that is picked up in the main loop and the channel switching and wait for result done in the main loop.

It all depends on your application.

 

0 Kudos

716 Views
Tarania
Contributor I

Thanks for the reply,

 

What i am trying to do is sample two signals one in AD0 and the other on AD1. Each signal needs to be sampled at 2KHz. What i would like to do is sample AD0 wait 500uS, sample AD1 wait 500uS sample AD0 ...repeat. I dont have any other interupts enabled. I am jut not sure how to write the code to do this. It does not have the be exactly 2KHz sampling just near that. 

 

Thanks for your reply

0 Kudos

716 Views
BV_BV
Contributor III

Tarania wrote:

Thanks for the reply,

 

What i am trying to do is sample two signals one in AD0 and the other on AD1. Each signal needs to be sampled at 2KHz. What i would like to do is sample AD0 wait 500uS, sample AD1 wait 500uS sample AD0 ...repeat. I dont have any other interupts enabled. I am jut not sure how to write the code to do this. It does not have the be exactly 2KHz sampling just near that. 

 

Thanks for your reply


 

Ok, but see that you sample AD0 at 1kHz rate, and AD1 at 1kHz rate. 

This is not what you want, you want 2kHz for both AD0 and AD1.

 

You say:

AD0 (500us) AD1 (500us) AD0 (500us) AD1 (500us) AD0 (500us) AD1 (500us) so on.........

 

You want:

AD0 AD1 (500us) AD0 AD1 (500us) AD0 AD1 (500us) so on.........

0 Kudos

716 Views
peg
Senior Contributor IV

Hi,

 

Need to know your clock setup/BUSCLK rate to do this as TPM or code delays will be dependant on this.

 

Forgot one of you questions before - why do you think that the result etc would not hold all 8 bits?

 

You could get something going right now by just placing bigmac's ISR code into your main loop and insert a for loop delay before both of the channel select lines. Add a line to toggle an output after each delay so you can confirm the sample frequency.

 

 

0 Kudos

716 Views
Tarania
Contributor I

Thanks,

 I dont have anything specific setup for the clock, i think its just the normal 16MHz, Ill attach my updated code so you can see exactly what i have. But what you are saying about toggling an output makes perfect sense. Eventually we are going to have to do this with serial communication but for this part of the project we are being required to do parallel. Thanks again.

 

#include <hidef.h>                 /* for EnableInterrupts macro */
#include <MC9S08QG8.h>       /* include peripheral declarations */

 


void main(void) {
EnableInterrupts;                 /* enable interrupts */


PTBDD = 0xff;                     // make port b output

 

ADCSC1_ADCO = 1;                 // enable continuous conversion
ADCCFG_MODE = 0x00;                 // 8 bit mode

for(;:smileywink: {
 
__RESET_WATCHDOG();         

 

         ADCSC1_ADCH = 0x00;           // set channel PTA0

         while(!ADCSC1_COCO);          // ADC conversion complete?
          PTBD = ADCRL;             // output 8bit ADC to Port B
        
        //delay??
    
        ADCSC1_ADCH = 0x01;        // set channel PTA1

        while(!ADCSC1_COCO);          // ADC conversion complete?
        PTBD = ADCRL;             // output 8bit ADC to Port B

 

       //delay??

 } /* loop forever */
}

 

 

0 Kudos

716 Views
peg
Senior Contributor IV

Hi,

 

You don't want continuous conversion mode, changing channels initiates a new conversion.

Use say 

for (i=0, i< big_number, i++);

as your delay.

set up another pin on another port as output and set it after one delay and reset it after the other.

adjust big_number until you get the correct sample rate.

 

0 Kudos

716 Views
Tarania
Contributor I

OK thanks! The only thing is, when i had continuous conversion mode disabled, it was only sampling at around 1Hz or so, i didn't measure it, but it was slow. How do i change this, i should be setting the sampling rate with the for loop delay right? so it should be running through that code at 16MHz correct?

 

0 Kudos

716 Views
peg
Senior Contributor IV

Hi,

 

Just go for it! it won't blow up.

Don't know why it would be so slow.

The code will run at approx 8MHz and yes, you will be determining the sample rate by the delay time plus the conversion time plus a few cycles for the code.

It may be that you need to put a /2 divisor on the clock to bring the ADC into spec. This is done in the ADCCFG register. Not sure what actually happens when you run out of spec.

Put an LED on the test outpu, if it is really 1Hz you will see the flash, otherwise you have a test point to measure the frequency. Even a multimeter will show you that it is running (should get something like half rail).

 

0 Kudos

716 Views
peg
Senior Contributor IV

Hello and welcome to the fora, Tarania,

 

I don't really see a problem which would stop this code from working, how ever I would offer the following pointers:

Pullups only work on pins set as inputs.

Setting continuous conversion, 8-bit mode and channel selection should be done in the initialisation and not in the main loop. You would set the channel in the main loop if you were changing channels though.

There is no need to poll for ADACT.

In fact there is even no need to poll for COCO. simply reading ADCRL will give you the latest result. Of course you may want to wait for the first COCO outside the loop so the first read is true data.

 

Also if this is the only code you are using, do you even know that it is running? Maybe set and reset another output to test the code is actually running.

 

0 Kudos

716 Views
bigmac
Specialist III

Hello, and welcome to the forum.

 

If you wish to use continuous conversion mode, the ADCSC1 register should be written only once, perhaps within the initialisation, to start the first conversion. If you write to this register when a new conversion has already started, that conversion will be aborted.  I wonder if this is the problem that you are observing?  The initialisation code should also set the ADCCFG register, as well as the pin control register APCTL1, both prior to starting the conversions.

 

The main loop might contain the following code for continuous conversion mode -

 

for ( ; ; ) {
  __RESET_WATCHDOG();
  while (!ADCSC1_COCO);  // ADC conversion complete?
  PTBD = ADCRL;          // output 8bit ADC to Port B
  ...
}

 

However, for polling operation I might generally choose not to use continuous conversion, but to explicitly start each new reading following processing of the previous reading.  The ADCCFG and APCTL1 registers would still need to be setup during during initialisation.

 

 for ( ; ; ) {
  __RESET_WATCHDOG();

  ADCSC1 = 0;            // Commence new conversion Ch0

  while (!ADCSC1_COCO);  // ADC conversion complete?
  PTBD = ADCRL;          // output 8bit ADC to Port B
  ...
}

 

Since each write to the ADCSC1 register will start a new reading (and abort the previous one) it is good practice to simultaneously write all bits of the register, rather than set or clear individual bits.

 

Finally, note that it is pointless to enable pullups on a dedicated output port. 

 

Regards,

Mac

 

0 Kudos