Shop OBEX P1 Docs P2 Docs Learn Events
InfraRed, Is my SPIN wrong or should I use PASM — Parallax Forums

InfraRed, Is my SPIN wrong or should I use PASM

paulleicesterpaulleicester Posts: 12
edited 2011-10-01 13:50 in Propeller 1
Heya all, First post here but have been working with the prop a couple of weeks now and I hope it would not be considered for me to be rude to have my first post as a question.

I have no experience with ASM or PASM so I felt more comfortable attempting this task in SPIN.

I am working on my own IR protocol for a little project, I want to learn InfraRed and Making my own protocol is my preference. I am currently using Manchester Code @ 38Khz. I have 2 boards, one for sending and one for receiving.

Full credit to Bob Belleville for his very useful files related to IR.

I am having some difficulty with timing. I am modulating 600ns On 600ns Off for a 1 and the opposite way for a zero. The accuracy I am getting is not terrible on the reciever end.. about 1/3 packets make it through 25 bits, but this level of accuracy I am not comfertable with. After tweaking here and there I have come to figure that it must be the timing on either board.

I shall paste here both sides and I would most welcome suggestions. Please be aware variables are not well explained as this code is experimental at this stage.

Transmit Code Sample:
  us := clkfreq/1_000_000
  outa[0]~~
  dira[1]~
  Freq(0, 0, 38_000)
  repeat
    if ina[1]
      repeat a from 1 to 5
        repeat index from 1 to 23
          t := lookup(index: 1,1,1,0,1,0,1,0,1,0,0,1,1,0,0,1,1,1,0,0,1,1,1)
          if t == 0
            outa[0]~~
            waitcnt(600*us + cnt)                 
            outa[0]~
            waitcnt(600*us + cnt)
          elseif t == 1
            outa[0]~
            waitcnt(600*us + cnt)                 
            outa[0]~~
            waitcnt(600*us + cnt)  
        waitcnt(clkfreq/64 + cnt)  
Receive code sample:
  us := clkfreq/1_000_000
  r := 0
  c := 0
  lst := 0
  tm := 0
  term.start(12)

  dira[irpin]~                      'input on p0 (0 clear)
  repeat
    if ina[irpin]                   'adjust for a different pin
      if c => 1
        term.out("0")
        c := c + 1
        if c == 10
          c := 0
          term.out("E") 
    else
      term.out("1")
      if c == 0
        waitcnt(300*us + cnt)
      c := 1
    if c => 1
      waitcnt(1200*us + cnt)
    else
      waitcnt(300*us + cnt)  
if the IR Pin is Low, becomes a 1 there for wait 300ms to get into the centre of that carrier, then check every 1200ns what the pins state is to produce 1s and 0's. I find that I usually get good accuracy up until about the 17th bit, but some times I also have inaccuracy's before that.

Here are my recent results:

Should be
11101010100110011100111000000000

Results:
11101010100110011100111000000000E
1110101010011001110011000000000E
1110101010011001110011000000000E
1110101010011001110011000000000E
111010101001100111001000000000E

Many thanks for having a look and sorry if ive bored you totaly :)

Comments

  • frank freedmanfrank freedman Posts: 1,983
    edited 2011-09-29 15:33
    Everyone on this forum started off at question #1. (Well at least most including myself) I now have a couple of months on the device and still learning. I have bypassed most spin for now as my pet project can not run that slow. At a glance, I am wondering if spin can provide the timing you are looking for and if so, the other part of the equation using spin is the hub access times for the spin tokens. Possibly the access times may be behind the instabilities. But those are under-educated guesses on my part for which I will be fully set straight I am sure by the more knowledgeable and therefore will also be monitoring this thread as well. Time for me to learn more.

    Frank
  • JonnyMacJonnyMac Posts: 9,203
    edited 2011-09-29 16:11
    You may be running into some overhead issues with Spin on one side and not the other.

    I have always used PASM for my IR work and, believe me, Assembly is not my first language. PASM, however, is quite friendly and you may find it comfortable to work with. I've attached my Sony RX and TX code so you can see my approach and, perhaps, adapt the protocol to suit your needs.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-09-29 16:19
    You're dealing with some heavy overhead in your transmit timing loop, which will mess up your timing. Here's how I would change it (if you insist on using lookup -- shifting would be better):
      delay := clkfreq * 6 / 10_000
      ...
      repeat
        if ina[1]
          time := cnt + delay
          repeat 5
            repeat index from 1 to 23
              t := !lookup(index: 1,1,1,0,1,0,1,0,1,0,0,1,1,0,0,1,1,1,0,0,1,1,1)
              waitcnt(time += delay)
              outa[0] := t
              !t
              waitcnt(time += delay)
              outa[0] := t
    

    -Phil
  • paulleicesterpaulleicester Posts: 12
    edited 2011-09-30 00:24
    Thank you very much for your replies...

    I shall take a look at your attached files JonnyMac and hopefully that should give me some clues

    As to lookup I dont need to use it, Shifting bits would be fine, if only I could work out how to read the first bit of a byte/word/long then I could shift along. (Generaly pretty new to low level stuff)

    Its all a learning process, but its all very very fun :)

    Cheers

    Paul
  • JonnyMacJonnyMac Posts: 9,203
    edited 2011-09-30 10:13
    Just for fun, have a look at this -- it may help. While they ~ and ~~ are cute, they're not as fast as just setting the bit value (hence I don't use the operators for setting/clearing a single bit). The lookup table has been replaced (per Phil's suggestion) and the logic removes the if-then construct which may keep the speed consistent through the loop.
    us := clkfreq/1_000_000
      outa[0] := 1
      dira[1] := 0
      Freq(0_ 0_ 38_000)
      repeat
        if ina[1]
          repeat a from 1 to 5
            irout := %1_1_1_0_1_0_1_0_1_0_0_1_1_0_0_1_1_1_0_0_1_1_1 << (32-23)
         
            repeat index from 1 to 23
              t := (irout <-= 1) & 1                        ' get bit (1072 clock ticks, 13.4 us)
    
              outa[0] := !t
              waitcnt(600*us + cnt)  
              outa[0] := t
              waitcnt(580*us + cnt)                         ' account for overhead
    
            waitcnt(clkfreq/64 + cnt)
    
  • paulleicesterpaulleicester Posts: 12
    edited 2011-09-30 10:57
    Thank you to Jonny and Phil for the code samples,

    I have tried them both and I am now condident that the IR side is working as well as it can within spin.

    The receiver is another story how ever.. with my existing code my results where as follows:

    With the lookup:
    1110110101100111100111000000000E
    1101010101110011101000000000E
    1110110101100111100111000000000E
    10010101011100111011000000000E
    1001010100110011101000000000E

    and Without
    11100101011100111001000000000E
    11010101011000111001000000000E
    11110101011100111001000000000E
    11010101011100111000000000E
    111101010110001110011000000000E

    As you can see, the raw data is apparent but the movement of 1's and 0's indicate some serious flaws and overheads in the reciever part, Some things I think that could help though, Sending a character to the terminal must have some overhead attached that will mess up the whole thing. every overhead will be magnified the closer to the least significant bit that I get. It also seems (looking at both code samples) that using IF for flow control has adverse affects also. This has given me some food for thought on how to improve my code. Many thanks :D

    Paul
  • JonnyMacJonnyMac Posts: 9,203
    edited 2011-09-30 11:34
    How are you detecting going from line idle (no IR) to the start of the packet?
  • paulleicesterpaulleicester Posts: 12
    edited 2011-09-30 11:53
    Currently I just wait for the pin to go low.
  • JonnyMacJonnyMac Posts: 9,203
    edited 2011-09-30 13:07
    Attempting to write the output while sampling is probably another bottleneck. Why not capture the code and then print it? Here's an idea.
    dira[irpin] := 0                         ' input on p0 (0 clear)
    
      irwork := 1                              ' 1st bit always 1
      repeat while (ina[irpin])                ' wait for start of packet (always 1 low-high)
    
      waitcnt(900 * us + cnt)                  ' skip 1st bit
    
      t := cnt
      repeat 22
        waitcnt(t += (1200 * us))              ' wait for next bit
        irwork := (irwork << 1) | ina[irpin]   ' sample
    

    Note that this assumes the first bit of the packet will always be "1" (low then high on output). The 900us delay at the beginning aligns the sample window to the 3/4 point in the bit cycle which is where the bit value is held. After capturing the code use the .bin() method to display.
  • paulleicesterpaulleicester Posts: 12
    edited 2011-09-30 15:45
    Wow, that was a great help, using your code I am now getting consistancy for the first 5 (sometimes 10) packets, after that and sometimes things go strange, But I think thats the transmit side as im getting a clear left shift of 2 bits in the results, I am not fussed about that at all as im pretty sure I can fix that.

    I implemented your suggestion like so
      dira[irpin] := 0                         ' input on p0 (0 clear)
      irwork := 1
      repeat                              ' 1st bit always 1
        repeat while (ina[irpin])                ' wait for start of packet (always 1 low-high)
        waitcnt(900 * us + cnt)                  ' skip 1st bit
        t := cnt
        repeat 22
         waitcnt(t += (1200 * us))              ' wait for next bit
         irwork := (irwork << 1) | ina[irpin]   ' sample
        term.bin(irwork, 23)
        term.out("E")
        irwork := 1
        dira[irpin] := 0     'Making sure pin is clear
    
    The first 5 packets always read like so...
    11101001011001100010011E

    Although they should be
    11101010100110011100111

    How ever just having that consistancy is a much better improvement, If I had not have already had a few beers then I would actualy take a closer look as to see if im reading the bit ahead or behind where the bits of opposite of what they should be. Many Thanks :D
  • paulleicesterpaulleicester Posts: 12
    edited 2011-10-01 13:50
    Thank you very much to everyone here that has helped me.. IR is now working 100% My code is as follows using suggestions here and tweaking them

    Transmit
    PUB start | us, t, irout, l
      us := clkfreq/1_000_000
      outa[0]~~
      dira[1]~
      Freq(0, 0, 38_000)
      repeat
        if ina[1]
          repeat 3
            l := cnt
            irout := %1_1_1_0_1_0_1_0_1_0_0_1_1_0_0_1_1_1_0_0_1_1_1 << (32-23)
            repeat 23
              t := (irout <-= 1) & 1                        ' get bit (1072 clock ticks, 13.4 us) This no longer causes delay later because we are storing the cnt
              outa[0] := !t
              waitcnt(l += (600 * us))  
              outa[0] := t
              waitcnt(l += (600 * us))
            outa[0] := 1 ' Pin must now be set high to drop the carrier
            waitcnt(l += (3000 * us)) 'wait for 3000 Micro seconds
    

    Receive
    PUB start | us, irwork, t
      us := clkfreq/1_000_000
      'start the tv terminal
      term.start(12)
      dira[irpin] := 0                         ' input on p0 (0 clear)
      irwork := 1
      repeat                              ' 1st bit always 1
        repeat while (ina[irpin])                ' wait for start of packet (always 1 low-high)
        t := cnt 
        waitcnt(t += (900 * us)) 
        repeat 22
          waitcnt(t += (1200 * us))              ' wait for next bit
          irwork := (irwork << 1) | ina[irpin]   ' sample
        term.bin(irwork, 23)
        term.out("E")
        irwork := 1
    
Sign In or Register to comment.