Author Topic: PIC detecting start bit with NEC IR protocol  (Read 1156 times)

0 Members and 1 Guest are viewing this topic.

Offline GreyAreaTopic starter

  • Contributor
  • Posts: 39
  • Country: gb
PIC detecting start bit with NEC IR protocol
« on: January 02, 2018, 09:20:44 pm »
As an excercise I'm trying to write some code which uses a timing based method to detect the start bit of the NEC IR protcol.

The approach I have taken is to detect the pin going low and count how many chunks (counts) of 50us delays happens before the pin goes high again.

To detect the desired 9ms low pulse (before the 4.5ms space) I'm throwing out counts <8ms or >10ms

Heres the code snippet (the bottom half of the function is trimmed):

Code: [Select]
short read_data(void)
{
    unsigned uint8_t count, i;
   
    count = 0;
    // Check 9ms pulse (remote control sends logic high, pin goes low).
    while((RB4 == 0) && (count < 200))
    {
        count++;
        __delay_us(50);
    }
    // Is initial low pulse <8ms or >10ms?
    if( (count > 199) || (count < 160))
        return 0;   // Exit, not NEC protocol.

When I placed a breakpoint at the if statement, I noticed that the value for count was way out, it was 92 instead of approx 180 as it should be.  I was using a 1Mhz clock at the time.  I changed the clock speed to 8Mhz and noticed I captured a different result (163).  This allowed the code to pass the check but was stlll approx 1ms out.

I then did some testing and tried every clock speed the PIC (PIC16F87) could run at and recorded the results:

Code: [Select]
_XTAL_FREQ OSCON speed count
--------------------------------------------------------------
31250 0x00000000 31.25 Khz 5
125000 0b00010000 125 Khz 20
250000 0b00100000 250 Khz 35
500000 0b00110000 500 Khz 60
1000000 0b01000000 1 Mhz 92
2000000 0b01010000 2 Mhz 121
4000000 0b01100000 4 Mhz 146
8000000 0b01110000 8 Mhz 163

I was under the impression that the _XTAL_FREQ macro would adjust __delay_us() call but it does seem like the error is coming from some kind of timing issue.

For more precision I tried changing the "chunk" size to 10us and the boundaries to >800 <1000, centering on a value of 900 but at 8Mhz I got a result of 485 [EDIT: I changed the uint8_t to uint16_t to cope with the higher number].  The IR demodulator is behaving correctly as the attached trace shows.  I'm a bit stumped now and any ideas would be welcome.


« Last Edit: January 02, 2018, 09:25:00 pm by GreyArea »
 

Offline hexreader

  • Frequent Contributor
  • **
  • Posts: 262
  • Country: england
Re: PIC detecting start bit with NEC IR protocol
« Reply #1 on: January 02, 2018, 10:05:03 pm »
The while loop and other instructions within the loop require about 12 machine cycles to acheive (if I estimated correctly)

With 1 MHz crystal, each machine cycle takes 4uS, so your full loop takes about twice as long as you think.

Higher crystal frequencies mean that the loop overhead becomes less significant and the 50uS delay becomes the main timing factor.

If you can spare a timer, then this is a better way to time the IR signal, as it is less dependant on instruction time.

Your way is perfectly OK, but you need to factor in instruction execution time (possibly by reducing __delay_us() parameter to compensate.)
 
« Last Edit: January 02, 2018, 10:17:51 pm by hexreader »
 

Offline GreyAreaTopic starter

  • Contributor
  • Posts: 39
  • Country: gb
Re: PIC detecting start bit with NEC IR protocol
« Reply #2 on: January 02, 2018, 10:45:26 pm »
Thanks, I think I was getting closer - by using the stopwatch in the simulator I'd worked out that with no __delay_us() call it took 18us to loop back to count++; (according to the MPLABX stopwatch).  This doesn't seem to translate directly to the hardware though, I tried the following formula:

8ms / 18us = 444.44
9ms / 18us = 500.
10ms / 18us = 555.55

This overflowed so I set a really high value and found that the loop breaks out at 1023.  So using 9ms / 1023 = 8.8us that's a full 10us off the simulator stopwatch compared to actual hardware.

Oh well, knowing the loop time is 8.8us seems good enough to move on, but as you say - a timer does seem a better way to implement this.

Thanks a lot, Matt
« Last Edit: January 02, 2018, 10:48:32 pm by GreyArea »
 

Offline mikerj

  • Super Contributor
  • ***
  • Posts: 3240
  • Country: gb
Re: PIC detecting start bit with NEC IR protocol
« Reply #3 on: January 02, 2018, 10:49:39 pm »
You could make this work a little better by subtracting the loop overhead from your delay e.g. at 4MHz 12 instructions will take 12us, so set the delay to 50-12=38us.

You can also reduce the loop overhead by decrementing a counter and testing for zero, since this can be done in a single machine instruction.  Incrementing and testing if a target value has been reached requires a subtraction operation and then a test of the ALU flags, so takes multiple instructions.

However hexreader is quite correct, this is a pretty nasty way to do loop timing unless there is no other choice.  Your PIC contains a useful set of timers and a compare/capture unit which is perfect for doing this sort of job, and requires zero CPU overhead whilst the incoming bit period is being measured.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf