AnsweredAssumed Answered

LPC804 maximum MRT frequency?

Question asked by Martin Fierz on Nov 29, 2019
Latest reply on Dec 4, 2019 by jeremyzhou

I am trying to use an LPC804 to read a PWM input and at the same time generate a defined output pattern on 4 GPIO outputs to drive an H-bridge. 

 

The PWM input is 20kHz fixed, and I need to find its duty cycle.

 

The output pattern I need to generate on the GPIOs somewhere around 22kHz but I need to track a resonance frequency, so it is variable. The output pattern has 3 different states for the pins, and they should last about 25,3,21 and 3 microseconds each (roughly, changing a bit depending on total frequency). 

 

I wanted to do this by using the multi-rate timer (MRT) for the output and the standard counter timer (CTIMER) to demodulate the input PWM. I wanted to use one channel of the MRT in repeat mode to make the ~22kHz frequency, and then use a second channel of the MRT in one-shot mode to count down the number of microseconds necessary. The code is pretty straightforward; I pasted it below - and it also kind of works - only when I use short time intervals such as ...

 

LPC_MRT->Channel[1].INTVAL = ForceLoad | (3*15);     // 3*15 counts should be 3 us

 

...the interrupt comes far too late - instead of generating an interrupt after 3us it takes about 10us to make the interrupt (measured with a scope). 

 

I then went on to just toggle a single GPIO with the MRT, with a single channel of the MRT, with repeat mode. That works fine up until values of 150 (giving me a 100kHz timer), but values smaller than 150 seem to have no effect - it remains a 100kHz timer. So I am guessing that the MRT for some reason is unable to go faster than this, and values <150 written to the register are somehow rounded up to 150? However, nothing like this is written in the documentation. 

 

My questions are: 

(1) is there really a 100kHz limit on the MRT, and if yes why isn't it documented?

(2) does anyone see a way to achieve my objective of demodulating a PWM while at the same time generating a fast output waveform on 4 GPIOs with the LPC804? The CTIMER seems to be useful to generate PWM but since I think I need to use it to demodulate the input PWM I feel stuck?!

 

best regards

  Martin

 

 

 

FWIW the code:

 

setup: 

LPC_MRT->Channel[0].CTRL = (MRT_Repeat<<MRT_MODE) | (1<<MRT_INTEN);
LPC_MRT->Channel[1].CTRL = (MRT_OneShot<<MRT_MODE) | (1<<MRT_INTEN);
NVIC_EnableIRQ(MRT_IRQn);

LPC_MRT->Channel[0].INTVAL = 750; 

 

With the 15MHz Clock, the value of 750 counter would correspond to 20 kHz. 

 

interrupt service routine:

void MRT_IRQHandler(void) {
   static int count = 0; 

   if (LPC_MRT->IRQ_FLAG & (1<<GFLAG0)) {
      chan = 0;

      count = 0; 

   }
   else
      count++;

 

 


// Clear the interrupt flags
LPC_MRT->Channel[0].STAT = 1<<MRT_INTFLAG;
LPC_MRT->Channel[1].STAT = 1<<MRT_INTFLAG;

switch(count) {

   case 0:       // main ~22kHz timer has triggered
   LPC_GPIO_PORT->SET[0] = ((1<<DRV1_PIN) | (1<<DRV4_PIN));
   LPC_GPIO_PORT->CLR[0] = ((1<<DRV2_PIN) | (1<<DRV3_PIN));

   LPC_MRT->Channel[1].INTVAL = ForceLoad | (25*15);     // 25*15 counts should be 25 us

   break; 

   

   case 1: 
   LPC_GPIO_PORT->SET[0] = ((1<<DRV2_PIN) | (1<<DRV4_PIN));
   LPC_GPIO_PORT->CLR[0] = ((1<<DRV1_PIN) | (1<<DRV3_PIN));

   LPC_MRT->Channel[1].INTVAL = ForceLoad | (3*15);     // 3*15 counts should be 3 us

   break; 

 

   case 2: 
   LPC_GPIO_PORT->SET[0] = ((1<<DRV2_PIN) | (1<<DRV3_PIN));
   LPC_GPIO_PORT->CLR[0] = ((1<<DRV1_PIN) | (1<<DRV4_PIN));

 

   LPC_MRT->Channel[1].INTVAL = ForceLoad | (21*15);     // 21*15 counts should be 21 us

   break; 

 

   case 3: 

   LPC_GPIO_PORT->SET[0] = ((1<<DRV2_PIN) | (1<<DRV4_PIN));
   LPC_GPIO_PORT->CLR[0] = ((1<<DRV1_PIN) | (1<<DRV3_PIN));

   // no need to load a value to MRT channel 1 as channel 0 will trigger next

}

Outcomes