MC68HC908JK1  - Timer Interface Module Problems

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

MC68HC908JK1  - Timer Interface Module Problems

3,290 Views
mauricio2346
Contributor II

Hi:
i'm in trouble with the configuration of the TIM module of MC68HC908JK1 microcontroller.   i wwant to use it as an PWM output to trigger a led in a IR reflective sensor.  it seems that the sintaxis is good, but it doesn't work!!!!! 

this is the program (section of the TIM configuration):

unsigned int Frecuencia=40;
unsigned int Dureza=4;
unsigned int Modulo;
unsigned int Duty;


void Emisor(void){
Modulo=2500/Frecuencia;
Duty=Dureza*Modulo/100;
TSC_TSTOP=1;
TSC_TRST=1;
TMOD=Modulo;
TCH0=Duty;
TSC0_MS0A=1;
TSC0_ELS0B=1;
TSC0_TOV0=1;
TSC_TRST=0;
TSC_TSTOP=0;
}

Thanks!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Added part number to subject.



Message Edited by NLFSJ on 2007-08-12 11:46 PM
Labels (1)
0 Kudos
13 Replies

715 Views
JimB
Contributor I

Hello Mac,

 

Thank you very much for your reply.

 

In my application I happen to know that TMOD is less than 256, and originally chose 16-bit arithmetic for speed and because it was sufficient - and left a warning comment for myself that hopefully I would spot if I changed TMOD. I suppose my use of "TMOD" rather than "(word)TMODL" shows a lack of commitment!

 

I don't think I've had any strange results with the actual value - only that the two TCH1 byte-writes occur in the wrong order, which (unsurprisingly given the earlier result) also happens if I take your code snippet but do the cast before the shift: it seems to be torn between the knowledge that the expression really would fit in a byte but that it must be padded out to a word, and in so doing forgets that TCH1 is supposed to be written high byte first.

 

I'll take a fresh look at my application to see if there is any reason for not using a dword. I suppose if I do make the assumption that TMODH is zero, it would be logical to leave TCH1H alone (having once set it to zero) and just write TCH1L each time. Something for me to think about.

 

Thanks,

Jim

 

0 Kudos

715 Views
bigmac
Specialist III

Hello Jim,

 

I did some further tests with the value of TMOD limited, as you described.  I also checked the HCS08, in addition to the HC908, to see if there were any differences.

 

For the HC908, the following code was tested:

 

   word c;
   volatile byte scratch_byte = 0x40;

   TMOD = 0x00F0;

 

   // Case 1:
   c = TMODL * scratch_byte / 256;
   TCH1 = c;

 

   // Case 2:
   TCH1 = TMODL * scratch_byte / 256;

 

The compiler generated the following code to write to TCH1.

Case 1: 

      STX  0x29  ; High byte first

      STA  0x2A

 

Case 2:

      STHX 0x29  ; This should also be OK
 

The equivalent code for the HCS08:

 

   volatile word scratch_byte = 0x40;
   word c;

   TPM1MOD = 0x00F0;

   // Case 1:

   c = TPM1MODL * scratch_byte / 256;
   TPM1C1V = c;

    // Case 2:

   TPM1C1V = TPM1MODL * scratch_byte / 256;

 

The compiler generated the following code to write to TPM1C1V.

Case 1: 

   STHX 0x29  ; OK

 

Case 2:

   STA  0x2A  ; Low byte first - OK for HCS08

   CLR  0x29  ; High byte
 

In all the above cases, the expected result of the calculation was obtained.

 

Regards,

Mac

0 Kudos

715 Views
JimB
Contributor I

Hello Mac,

 

Thank you very much for your continued efforts - naturally I tried out your code and had a play around to see what happened. Case 2 was a match, but case 1 also did an STHX for "c" in a __SHORT_SEG (MOV X+,0x29 etc otherwise), but in any case TCH1 was written correctly.

 

I eventually figured out why the code looked so different (the apparently non-optimised division (tired!) and the correct write-order): casting to a word optimised the division, and in case 1 the code worked as one would expect, however in case 2 the write-order problem came back.

 

I guess this is a fairly unlikely scenario - if I'd chosen to code properly for either a 16-bit TMOD/TCH1 or an 8-bit one everything would have been fine.

 

I've not yet done anything for HCS08 - I'm hoping to jump straight to its succesor!

 

Thanks again,

Jim

0 Kudos

715 Views
peg
Senior Contributor IV
Hi mauricio,
 
This basically looks correct. However this older device does not have the HLL friendly "write either byte first" latches on the TMOD and TCHx double registers.
They need to be written high byte first in each case. You need to check what your resultant code is doing and perhaps do this more specifically in your C code.
 
0 Kudos

715 Views
bigmac
Specialist III
Hello Mauricio and Peg,
 
It would appear that the compiler is sufficiently smart to generate code that writes high byte first.  This would seem to apply whether the variables Modulo and Duty are global or local.
 
Actually, in this case, I would tend to write all bits simultaneously to both TSC0 and TSC registers, since there is no apparent reason to set the bits individually.
 
TMOD = Modulo;
TCNT = Duty;
TSC0 = 0x1A;  /* Unbuffered PWM mode */
TSC = 0x00;   /* Start timer with pre-scale = 1 */
 
Are you monitoring the output pin with an oscilloscope to determine that it is not working?  Do you have a transistor driver for the LED?  The output pin of the MCU probably won't have sufficient drive capability for a reflective sensor device.
 
If you are actually monitoring at the output of the IR detector, does this provide internal filtering for a specific carrier (PWM) frequency?  If so, you would probably need to trim the internal oscillator of the MCU.  Keep in mind that each PWM output cycle will consist of (TMOD+1) bus cycles.  With a modulo value of only 62, the accuracy of the PWM frequency will be limited.
 
Regards,
Mac
 
0 Kudos

715 Views
peg
Senior Contributor IV
Hi Mac,
 
I am not sure if the compiler is "smart" or this is just how it does it. On a straight assignment and with the one compiler (Codewarrior I presume you tested) you could perhaps rely on it.
Given that I don't believe that the compiler is aware of the exact derivative that it is compiling for, I still don't think you can rely on this always. If the compiler does this always under all optimisations for every location it would be missing out sometimes.
Perhaps the "Guru" could shed some light on this.
When Freescale removed the restriction they made the point that it was to help compatability with HLL's.
 
Also to the OP, you are resetting the RST bit in TSC, this is unnecessary. (meant to mention this before).
 
0 Kudos

715 Views
CompilerGuru
NXP Employee
NXP Employee
The compiler was changed to generate that order,here's the release note entry:


out of compler release notes:
RELEASE NOTES CHC08 V5.0.18...List of new Features- Changed access order to objects declared with 'volatile', typically IO registers:  volatile unsigned int TCNT;  TCNT = 0x1234;  gives now code that accesses the low address byte first:  LDA   #52  LDX   #18  STX   TCNT  STA   TCNT:1  previous compiler versions accessed all objects high address byte first.....

Note that the current compiler version is V5.0.24, so that was changed quite some time ago.

Daniel

0 Kudos

715 Views
JimB
Contributor I

I thought I remembered that the compiler was supposed to take care of it, but I've just had problems with it: 

 

TCH1 = TMOD * scratch_byte >> 8;

 

(or even TCH1 = TMOD >> 8:smileywink:

 

Compiler seems to get them the wrong way round - apparently because it knows the high byte is 0.

 

Is this right?

 

Jim

0 Kudos

715 Views
bigmac
Specialist III

Hello Jim,

 

The operation TMOD * scratch_byte seems to be problematic.  We are multiplying a 16-bit value with an 8-bit value, with the possible result of unsigned long value.  The result always seems to be zero.

 

I obtained the expected result with the following code -

 

   dword c;

 

   c = TMOD;
   c *= scratch_byte;
   TCH1 = (word)(c >> 8);

 

The cast was required to eliminate a "possible loss of data" warning.  Yet the following expression gave a zero result for c, and casts did not seem to help.

 

   c = TMOD * scratch_byte;

 

Regards,

Mac

0 Kudos

715 Views
mauricio2346
Contributor II
Hi.
No Bigmac, i have already solve the problem.  it was only a little change on the variable's values.  you idea is great, less code, i'll try it!!

already i'm programming and i have a question:

can i declare a global variable that works in the main program and the libraries at the same time?

i have a library (MOTORAPI.c and MOTORAPI.h) that controls a pair of dc motors with the codes to the h bridges.  in MOTORAPI.h i wrote this:

signed char Estado;

void Atras (void){
    Estado=-1;
    PTB_PTB3=1;
    PTD_PTD2=0;
}
   
void Adelante(void){
    Estado=1;
    PTB_PTB3=0;
    PTD_PTD2=1;
}

Estado controls two bumpers (both conected to IRQ pin).  while the program is running, i want to control if the aplication moves forward or backward with Estado. in the main program i wrote this:

void interrupt 2 Init_IRQ_Isr(void){
INTSCR_ACK1=1;
if(Estado==1){
Parar();
Centro();
Delayms(500);
Atras();
Izquierda();
Delayms(800);
Parar();
Delayms(500);
Adelante();
}

i want to use Estado to control the movement of the aplication (robot).  can i???

Regards..
mauricio2346
0 Kudos

715 Views
bigmac
Specialist III
Hello Mauricio,
 
If the global variable Estado is defined in the main program, you can use it from within the library file, but for visibility of the variable you will also need to declare it within the second file.
 
extern signed char;
 
This could be placed directly in the library file prior to first use, or alternatively within a header file included in the library file.
 
A further comment about your ISR code -
It could be problematic to include lengthy delays within the ISR function (and is a bad programming practice).  This will prevent any background tasks, and any other ISRs, from executing for the for the duration of the delayed ISR.  It is better to exit the ISR function as quickly as possible, and to provide the delays as a background task within the main loop.  You might use a global variable to provide communication between the ISR and the background task.
 
For example,
 
/* Global variable definition */
unsigned char int_flag = 0;
 
Within main loop:
 
if (int_flag) {
  Delayms(500);
  Atras();
  Izquierda();
  Delayms(800);
  Parar();
  Delayms(500);
  Adelante();
  int_flag = 0;  /* Clear flag */
}
 
Modified ISR code:
 
void interrupt 2 Init_IRQ_Isr(void){
  INTSCR_ACK1 = 1;
  if (!int_flag) {    /* Execute following only if flag is clear */
    if (Estado == 1) {
      int_flag = 1;   /* Set flag */
      Parar();        /* Assumed to be quick functions */
      Centro();
    }
  }
}
 
Regards,
Mac
 
0 Kudos

715 Views
mauricio2346
Contributor II
ajajaja!! i forgot to say that the IR Emitter uses a transistor in saturation mode between the MCU and LED.  it works fine.


Regards...
mauricio2346
0 Kudos

715 Views
mauricio2346
Contributor II
Hi.
yeah, it seems to be correct.  after i wrote my last message, i found a little thing that maybe was the problem: the "Frecuencia" and "Duty" values. i couldn't understand why this values worked in other program with other microcontroller (mc68hc908gp32) with the same aplication: "38Khz Infrared receiver".  changing that values just a little and poof..... it worked!!! 
i understand that this device is a "fossil", but sometimes the older, the better, (the cheaper), jajajaja.  sometimes i think that i should keep a couple of this devices, in  5 years i'll be rich selling them..
Now my problem is bigger: i have a couple of discrete H bridges and i can't find the problem... they don't work!!!

Thank you so much...!!!


Message Edited by mauricio2346 on 2007-08-12 05:09 AM
0 Kudos