AnsweredAssumed Answered

Undocumented behavior of HCS12 ECT compare 7

Question asked by Daniel Lundin on Mar 24, 2016
Latest reply on Mar 30, 2016 by Daniel Lundin

I'm looking for an explanation of how the output compare 7 feature of the HCS12 ECT timer is supposed to work. There is apparently some undocumented behavior for this timer, or at least I can't find any description explaining the below behavior it in the manual.

 

What I want to do, is to sync numerous timer outputs to go high at the same time, but to pull them low individually, based on their individual timer settings.

 

According to the manual, the OC7 timer will upon successful output compare on timer 7 set the pins selected through mask register OC7M to the value specified in OC7D. So far so good. This works well, upon OC7 interrupt, all pins are pulled high like I want.

 

What's not documented though, is that some sort of automatic trick is also pulling said pins specified through OC7M low, when their individual timers elapse. This overwrites the behavior specified in TCTL1.

 

Simplified example code that uses only channel 0 and channel 7:

 

//setup HPRIO = 0xE0; // CH7 interrupt high prio TSCR1 = TEN; TSCR2 = clk_div TIOS = IOS0 | IOS7; TCTL1 = 0x00; // timers disconnected from output logic TCTL2 = 0x00; // timers disconnected from output logic OC7M = 0x00;  OC7D = 0x01; // pull channel 1 high upon OC7 TC7 = TCNT + pwm_period; TIE = C7I; // enable timer interrupts on ch7 ...

 

void compare7_interrupt(void) {   uint16_t tc7;    __asm BSET TFLG1, $FF                          // clear all interrupt flags   tc7 = TC7;    if(duty == 0)   {     OC7M &= ~0x1;                                // disable ch7 output compare for this pin   }   else   {     OC7M |= 0x01;                           // enable ch7 output compare for this pin     TC0 = tc7 + duty;               // set output compare based on duty cycle   }    TC7 = tc7 + pwm_period; }

Through some undocumented feature of OC7, this apparently gives me a PWM on channel 0 based on the specified duty cycle. I can't find any documentation stating what causes the pin to get pulled low.

 

I don't want this behavior, because I need to trigger individual interrupts for each channel, where I read an ADC and then pull the pin low manually. The system is something very common, namely a PID regulator where the PWM generated by the timers is regulated by ADC reads. The ADC must read a current when the timer pin is still high.

 

So I thought, ok I will simply disable OC7M from inside the OC7 interrupt, when the pin should already have been pulled high, and then re-enable it from the individual interrupt, to give a PWM. To my surpise, doing this causes the PWM signal to get inverted! The pin is now pulled low upon OC7 compare and high upon the individual interrupt. Despite the value of OC7D which is 1. None of this makes any sense to me. I find nothing about it in the erratas. (Specific device is HCS12C32)

 

Example to reproduce this behavior:

 

void compare7_interrupt(void) {   uint16_t tc7;    __asm BSET TFLG1, $FF                          // clear all interrupt flags   tc7 = TC7;    OC7M = 0x00;    if(duty == 0)   {     TIE &= ~0x01;   }   else   {     TC0 = tc7 + duty;               // set output compare based on duty cycle     TIE |= 0x01;   }    TC7 = tc7 + pwm_period; }  void compare0_interrupt (void) {               __asm BSET TFLG1, C0F   OC7M |= 0x01; }

Outcomes