PWM on MC68H908JB

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

PWM on MC68H908JB

1,162 Views
champion_7891
Contributor I

Hi!

 

I am really new to freescale uControllers and I have been trying for a while to get a working pwm from JB8 controller but to no avail. following is my code:

 

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

 

void main(void) {

  EnableInterrupts; /* enable interrupts */
  /* include your code here */
  TSC=(TSC&0xCF)|0x30;
  TMODH=0x00;
  TMODL=0x7F;
  TCH0H=0x00;
  TCH0L=0x7F;
  TSC0=TSC0|0x1A;
  TSC=TSC|0x20;
  while(1);

  for(;:smileywink: {
    __RESET_WATCHDOG(); /* feeds the dog */
  } /* loop forever */
  /* please make sure that you never leave main */
}

 

please help me as this is not working even though i followed all the steps in the datsheet

Labels (1)
Tags (1)
0 Kudos
10 Replies

812 Views
bigmac
Specialist III

Hello,

 

You have set the TCH0 register to a value equal to the TMOD register setting.  The outcome of this has a degree of uncertainty - I suspect you will get almost 100 percent duty, with a very narrow low going pulse.

 

The final write to TSC actually stops the module, and this is why there is no action to be seen.

 

Here is the TPM initialisation code that I would try, assuming an initial 50 percent duty:

TSC  = 0x20;    // Prescale 1, TIM disabled

TMOD = 0x007F;

TCH0 = 0x0040;  // 50 percent duty

TSC0 = 0x1A;    // Unbuffered PWM, clear O/P on compare

TSC_TSTOP = 0;  // Enable TIM counter

 

Note that, interrupts are not necessary provided the duty remains constant.  However, should you wish to change the duty without any glitches, this will need to be done within a TIM channel ISR, immediately after the current output pulse has gone low.  The ISR code would obtain the new duty value from a global variable, update the TCH0 register, and disable further interrupts.  The interrupt flag would also be cleared.

 

A final comment - while not relevant to the current issue, it is usually a good coding practice to globally enable interrupts after the various peripherals have been initialised.

 

Regards,

Mac

 

0 Kudos

812 Views
champion_7891
Contributor I

Hey man thanks a lot!

 

A couple of questions:

1. polling (while(1); ) after the code you have given indeed gives a 50% duty cycle pwm...removing polling generates a periodic, exponential decaying to zero, waveform...could you explain that.

2. Ok, i measured the time period to be 42.64 x10^-6 s i.e. the pulse is high for half that time ie 21.32 us. Theoretically, I would have been able to find the high time as TCH0*T, where for me T=1/3MHz, and TCH0 was set as 0x0040...i.e. 64....i find the value to be 21.3us for high time...which is negligibly different from what I actually obtain...what I dont get is that to get 100% duty cycle then I would have to set TCH0 to 128....however, TCH0 can hold upto 65535...so, how is this related to duty cycle I mean from my understanding, duty cycle is the value set in TCH0 divided by the maximum value that TCH0 can hold?

3. TMOD, the pulse width...where do I see it practically? How is it different from duty cycle?

4. my intentions are to finally generate a 50Hz sine wave using a sine lookup table, with a JL16...but again since I am new, I have started with JB8...could you please explain how i will call an interrupt function (and use TIM channel registers as you stated above), to do so...I have actually done this on AVR ATMEGA16, but  the addition of channel registers, and actually going about calling an interrupt function in JB8, has left me at loss.

 

Thanks!

0 Kudos

812 Views
champion_7891
Contributor I

elaborating on point 4 above:

I wrote the following code:

 

#include <hidef.h> /* for EnableInterrupts macro */
#include "derivative.h" /* include peripheral declarations */
static unsigned char sample_number=0;
static unsigned char sine_table[64]={32,33,35,36,38,39,40,42,43,45,46,47,49,50,51,52,53,54,55,56,57,58,59,60,60,61,61,62,62,62,62,62,62,62,62,62,62,62,61,61,60,60,59,58,57,56,55,54,53,52,51,50,49,47,46,45,43,42,40,39,38,36,35,33};

interrupt void TimerTOF(void);
void main(void) {


  TSC  = 0x20;    // Prescale 1, TIM disabled

  TMOD = 0x0040; //64

  TCH0 = 0x0020;  // 50 percent duty

  TSC0 = 0x1A;    // Unbuffered PWM, clear O/P on compare

  TSC_TSTOP = 0;  // Enable TIM counter
 
  EnableInterrupts;
  while(1);
 
}

interrupt void TimerTOF (void)
{
  TCH0=sine_table[sample_number];
  sample_number++;
 
  if (sample_number>=64){
    sample_number=0;
  }
}

 

Now:

a. I have used a 64 value sine table pre generated.

b. Running the code as it is causes nothing but a 50% duty cycle pwm.

c. calling the TimerTOF function just before the poll (while(1); ) and after EnableInterrupts causes a memory error: Link Error: L1102: Out of allocation space in segment RAM at address 0x140;

d. declaring the sine_table as const and then doing c causes the link error to disappear. however, the generated wave is not changing in duty cycle according to the sine lookup table. Infact, a contsant duty cycle of <10% is obtained.

0 Kudos

812 Views
bigmac
Specialist III

Hello,

 

  1. The sine table requires to be located in flash as a constant array.
  2. I do not see where you are clearing the interrupt flag.  The ISR will immediately be re-entered.
  3. You are using the wrong interrupt.  You will need to use the TIM channel interrupt to avoid output glitches due to timing conflicts between overflow and output compare events.
  4. If the COP timer is enabled, you are not clearing this timer within the while loop, so a COP reset would eventually occur.  I might suggest that you utilise the standard main() framework, as provided by the new project wizzard.  I seem to recall that using

while (1) {  }    // this generates a compiler warning message

for ( ; ; ) {  }  // does not generate a warning message

 

Once the other problems are fixed, the output frequency should be about 721 Hz, with a 3 MHz bus frequency (3000000 / 65 / 64).  If there are N phase increments per output cycle (the table size), the output frequency is given by:
Fout = Fbus / (TMOD +1) / N

 

With the same bus frequency, to achieve a fixed output frequency of 50 Hz suggests that N = 240, TMOD = 249 would be a suitable combination.  The sine table values should be restricted between the limits 1 and 248.

 

Regards,

Mac

 

0 Kudos

812 Views
champion_7891
Contributor I

Hello!

 

Thanks again. i would appreciate it immensely if you could provide some code about the interrupts. I have been honestly trying for hours but can't get them to work. 

0 Kudos

812 Views
bigmac
Specialist III

Hello,

 

You might try the following code for the TIM Channel 0 ISR:

 

interrupt 4 void ISR_TIM_Ch0( void){  TCH0 = sine_table[sample_number];  sample_number++;  if (sample_number >= 64){    sample_number = 0;  }  TSC0_CH0F = 0;    // Clear flag}

 The register TSC0 should be initialised to a value of 0x5A.

 

With the previous small TMOD value, this ISR would need to complete in substantially less than 65 bus cycles, but this may not actually be feasible.  So there may still be problems due to missed interrupts.  If this is so, you could try increasing the prescale setting while you are experimenting with the small TMOD values.

 

The number of bus cycles required by ISR, or other code, can be ascertained using full chip simulation.  But there will be some additional fixed overheads for ISR entry (vector fetch process) and ISR exit (RTI return).

 

Regards,

Mac

 

0 Kudos

812 Views
champion_7891
Contributor I

Hello!

 

Thanks a lot bigmac. I have a problem, however:

 

The sine wave that is generated has a few kinks, one just after the peak, and a couple maybe maybe a tenth a cycle before the peak. These kinks are basically a localized fall in amplitude. Now, I have tried various sine tables, with 64, 128, and 256 values, but these kinks always appear in the same place. Any idea why?

0 Kudos

812 Views
bigmac
Specialist III

Hello,

 

What sort of low pass filter do you have at the timer output?  Does this have active components that could be subject to overload and distortion?  Also check the TIM output waveform to see whether there are any glitches, i.e. the duty does not smoothly increase and decrease over the output cycle.  This is probably best checked with 64 state table.

 

I assume that the highest value in each table does not exceed TMOD-1, and a table value of zero is not used.

 

Regards,

Mac

 

0 Kudos

812 Views
champion_7891
Contributor I

I am using an RC filter with a 100nF Myler Capacitor and a 10k resistor. There are no active components. Actually, there are glitches in the PWM waveform. I'll check back later to tell you exactly where they are but I can tell you that duty cycle decreases to almost 0 where it shoud not. About the table value, I used it both ways (i.e. with 0 and without), but the effect was the same. And yes, max value does not exceed TMOD.

0 Kudos

812 Views
bigmac
Specialist III

Hello,

 

I was actually suggesting to avoid both values zero and TMOD within your table.

 

With a TMOD setting of 63 decimal, and a minimum channel value of 1, the minimum duty will be 1/64.  For a higher TMOD values, the minimum duty would be proportionally smaller.  This is to achieve maximum output voltage swing about a mean value corresponding with 50 percent duty.

 

When using the 64 entry table, did you increase the TIM prescale factor, as I previously suggested?  Maybe select a division ratio of 4.  This will then allow nearly 256 bus cycles to process the ISR function.  With the former prescale division of 1, there would be somewhat less than 64 bus cycles available, which may not be enough time.  There will be less time available between interrupts as the duty decreases, and a little more time as the duty increases (affected by the difference between two adjacent table entries).

 

Perhaps you should also recheck your sine table calculations to see whether any significant arithmetic errors have crept in.

 

Regards,

Mac

0 Kudos