[MC9S12C128] Can't assign counter value to an unsigned integer correctly?!

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

[MC9S12C128] Can't assign counter value to an unsigned integer correctly?!

2,442 Views
mehmedean
Contributor I

Hi,

 

We have a magnetic encoder that measures angle... We use PACNT counter to measure the pulse width. The values are between 0 and 20000. After each angle reading, we want to store the value of PACNT into an unsigned integer. But something is wrong... The value of the variable is just around 30 whereas PACNT is around 4900. We see 4900 in the memory but when we try to copy it into the variable (D register), we encounter this problem. Can you help me?

 

Regards,

 

Mehmedean

Labels (1)
0 Kudos
6 Replies

594 Views
pgo
Senior Contributor V

Dear Mehmedean,

 

I can't explain the symptom you are describing.  The dissassembly of your code looks correct in terms of reading the PACNT register.

 

However there a couple of things that may be leading to problems.

 

You appear to be clearing the  PAIF flag manually as well as automatically using the FFC option.  This can cause problems (or at least confuse me!)

 

The PACNT should be cleared immediately after reading - not before the flag clearing.  I think the way your code is set up it would be possible for incomplete counts since the delay through your SCI code could be quite long  and overlap the next period measurement.   Essentially you would get a random value depending on the timing of when you clear the register before the end of capture time.

 

Alternativley just omit clearing the flag and wait for it to be set twice in the busy-wait loop.  Save the PACNT value from the 1st edge and use subtraction to determine the change in count.  The second measurement would be guaranteed to be complete.  Better still - have an interrupt handler save the difference value in a glabal var  instead.

 

You enable PA interrupts.  What does you PA interrupt handler do anyway?

 

One last comment - Personally, I would use the IC hardware instead.

 

bye


 

0 Kudos

594 Views
mehmedean
Contributor I
I'm a newbie, so could you provide me some codes or pseudocodes about your suggestions? Your 10 minutes would save my days (but i have nothing to give you in turn, except a 'thank you very much')... I don't know how to use an interrupt handler in this example... But if you show me the way, i suppose i can figure it out. I don't know how to read the register as soon as the register sees the falling edge, or the code get out of the while... Thanx in advance.
0 Kudos

594 Views
pgo
Senior Contributor V

Dear mehmedean,

 

Can you describe the device you are trying to interface to?

 

 

Some example code using input capture - This routine measures duty cycle and period.  It should be adaptable to your requirements (if I understand what you are trying to do correctly).

 

 

#include <hidef.h>      /* common defines and macros */
#include <mc9s12c32.h>     /* derivative information */
#pragma LINK_INFO DERIVATIVE "mc9s12c32"
#include <stdio.h>
#include "LCD.h"

typedef unsigned char U8;
typedef unsigned int  U16;

/*
**  Information for M68HC11 Timer
*/
#define PR210      (0x04)       /* Prescale value for TSCR2 reg */
#define PRESCALE   (1<<PR210)   /* Actual division factor (1,2,4,..,128) */

/* TIOS, TIE & TFLG1 masks */
#define IC3 (0x08)

/* TCTL4 masks */
#define IC3EDGE    (0xC0)
#define IC3RISING  (0x40)
#define IC3FALLING (0x80)

int highTime, period; /* globals updated by IC3 routine */

interrupt VectorNumber_Vtimch3
void IC3Handler(void) {
/*
** Handler for IC3 interrupts.
** This handler alternates between looking for rising and
** falling edges of IC3. From these events it
** calculates the high time and period of the waveform in
** the global variables highTime and period.
** Note that highTime and period are updated on the same
** rising edge interrupt so that they are always a
** consistent pair of values.
** This falls in a heap if the waveform is too fast or slow!!
*/
static int risingEdge;  /* times of last edges */
static int fallingEdge;

  if ((TCTL4 & IC3EDGE) == IC3RISING) {
    /* handling int for IC3 rising edge */
    /* calculate period & high time */
    highTime   = fallingEdge - risingEdge;
    period     = TC3 - risingEdge;
    risingEdge = TC3; /* save time of edge for next time */
    /* set for next falling edge on IC3 */
    TCTL4 &= ~IC3EDGE;
    TCTL4 |=  IC3FALLING;
    }
  else {
    /* handling int for IC3 falling edge */
    fallingEdge = TC3; /* save time of edge */
    /* set for next rising edge on IC3 */
    TCTL4 &= ~IC3EDGE;
    TCTL4 |=  IC3RISING;
    }
   
  TFLG1  = IC3; /* clear pending IC3 int */
} /* IC3Handler(void) */

void q8_1(void) {
  char lineBuff[100];
  EnableInterrupts;
  initLCD();

  /* Set timer prescale value */
  TSCR2  = PR210;

  /* Enable timer, stop in freeze or wait mode */
  TSCR1 = TSCR1_TEN_MASK|TSCR1_TSWAI_MASK|TSCR1_TSFRZ_MASK;
 
  TIOS  &= ~IC3; /* set ECT3 as IC3 */
 
  /* set for next rising edge on IC3 */
  TCTL4 &= ~IC3EDGE;
  TCTL4 |=  IC3RISING;

  TFLG1  = IC3; /* clear pending IC3 int */
  TIE   |= IC3; /* enable IC3 int */

  for( ; ; ) { /* continuous loop updating the display */
    int lHighTime, lPeriod;

    /* enter critical region */   
    DisableInterrupts;

    /* make local copy of globals
    ** - minimises time that ints are off
    ** This is important since the division and putsLCD()
    ** are verrrrry SLOW and we don't want to miss edges.
    ** We disable ints as we need a consistent pair of
    ** values from highTime and period without any ints
    ** between.
    */
    lHighTime = highTime;
    lPeriod   = period;

    /* leave critical region */
    EnableInterrupts;

    (void)sprintf( lineBuff,
                   "Duty Cycle =%3d%%", (int)((100UL*lHighTime)/lPeriod) );
    gotoXY(0,0);
    putsLCD( lineBuff );

    } /* for(..) */
} /* main() */

 

bye

 

0 Kudos

594 Views
kef
Specialist I
It seems compiler is optimizing store to angle variable. Try making your angle variable static, either use keyword or move angle out of main {}-block.
0 Kudos

594 Views
mehmedean
Contributor I

both didn't work...

 

the counter should start counting when a rising edge comes and should stop when a falling edge comes. Should it stop until the next rising edge? Or does the value resetted when a falling edge comes or does it stay the same until the next rising edge?

 

Do you have any other suggestions to measure the pulsewidth?

0 Kudos

594 Views
mehmedean
Contributor I

Is there any possibility that the problem arises from wrong assignment? Should I merge PACNT(hi) and PACNT(lo) after direct reading from the memory? I tried the code below, but it is not correct...

 

0x0062 - Address of PACNT(hi)
0x0063 - Address of PACNT(lo)

 

instead of "angle = PACNT;", I used "angle = ((*(int *)(0x0062)) * 256) + (*(int *)(0x0063));"...

0 Kudos