Shop OBEX P1 Docs P2 Docs Learn Events
Array and cognew — Parallax Forums

Array and cognew

J LudwigJ Ludwig Posts: 19
edited 2012-01-16 21:12 in Propeller 1
Hi,
I have an object that reads the data from a GM ALDL link and displays the desired values on a TV screen. It works well and I can display at least 10 different parameters from the ECU (engine control unit) in real time. My next step is to put the method that gathers the data into a new cog to run continuously. The code that works follows, I have eliminated all but one display value for clarity:
{The purpose of this object is to acquire data continuously from the Engine Control Unit in one cog and display the results with another cog}


CON
  _clkmode = xtal1 + pll16x                             'Standard clock mode * crystal frequency = 80 MHz
  _xinfreq = 5_000_000

VAR
  long  request[5]
  long  data[67]
    
OBJ
  ser      : "FullDuplexSerialPlus"
  term     : "tv_text"
  
PUB Main | i, r, tmp, throt

  request[0] := $F4
  request[1] := $57
  request[2] := $01
  request[3] := $00
  request[4] := $B4
  
  ser.start(7, 6, %0000, 8192)                       'Start ALDL communications with FullDuplexSerial
  term.start(12)                                     'Start TV Terminal
  waitcnt(clkfreq + cnt)                             'Give methods chance to start
  term.str(@title)                                   'Print Title on TV screen
                                   
  repeat
    ser.rxflush                                      'Clear receive buffer
    repeat i from 0 to 4                             'Send command string to ECU
      ser.tx(request[i])
    repeat r from 0 to 66                            'Fill array
      data[r]:= ser.rx
  
    term.str(string($A,1,$B,1,$0D))                  'Set display position 
    tmp := data[49]                                  'Word 49 is raw throttle position
    throt := tmp                                     'No conversion, display raw count
    term.str(String("TPS "))                         'Print label
    term.str(string($A,10,$B,2))                     'Set display location to column 10
    term.dec(throt)                                  'Print value
    term.str(String("  "))                           'Put a couple blank spaces after the value is displayed
    term.str(String($0D))                            'Newline

DAT
title    byte    "ALDL MONITOR",13,13,0     


When I run the following code, I get only one sample after reset. I have had my scope connected to the TX out of the prop and see only one request come through, with the previous code I get continuous data.
{The purpose of this object is to acquire data continuously from the Engine Control Unit in one cog and display the results with another cog}


CON
   _clkmode = xtal1 + pll16x                         'Standard clock mode * crystal frequency = 80 MHz
   _xinfreq = 5_000_000

VAR

  long  stack[16]                                    'Stack space for new cog 
  long  data[67]                                     'Space for data array
    
OBJ
  ser      : "FullDuplexSerialPlus"
  term     : "tv_text"
   
PUB Main | d, tmp, throt

  ser.start(7, 6, %0000, 8192)                       'Start ALDL communications with FullDuplexSerial
  term.start(12)                                     'Start TV Terminal
  waitcnt(clkfreq + cnt)                             'Give methods chance to start
  term.str(@title)                                   'Print Title on TV screen

  cognew(GetData(@data), @stack)                     'Continuously get ECU data       

  repeat
    term.str(string($A,1,$B,1,$0D))                  'Set display position 
    tmp := data[49]                                  'Word 22 is raw coolant temp
    throt := tmp                                     'No conversion, display raw count
    term.str(String("TPS "))                         'Print label
    term.str(string($A,10,$B,2))                     'Set display location
    term.dec(throt)                                  'Print value
    term.str(String("  "))                           'Put a couple blank spaces after the value is displayed
    term.str(String($0D))                            'Newline


PUB GetData (dataAddr) | i, r, request[5]

  request[0] := $F4
  request[1] := $57
  request[2] := $01
  request[3] := $00
  request[4] := $B4

  repeat
    ser.rxflush
    repeat i from 0 to 4                             'Send command string to ECU
      ser.tx(request[i])
    repeat r from 0 to 66                            'Fill array
      long[dataAddr][r]:= ser.rx

DAT
title    byte    "ALDL MONITOR",13,13,0 

I suspect a problem with variables, any tips will be appreciated.
Thanks,
JL

Comments

  • kuronekokuroneko Posts: 3,623
    edited 2012-01-16 16:24
    You have quite a lot of local variables (which live on the stack) and only 16 longs total (which is also used for method calls). Just raise the stack size (32 or 64) and go from there. Once it's working you can always shrink it again later.

    That said, why do you use a long array (data[]) for storing bytes (ser.rx)?

    You should also store your command array as DAT byte sequence, e.g.
    DAT
    request byte    $F4, $57, $01, $00, $B4
    
  • J LudwigJ Ludwig Posts: 19
    edited 2012-01-16 18:01
    kuroneko,
    Thanks, I changed my longs to bytes and the working code still worked. Next I tried storing my command array as a DAT byte sequence and it no longer worked. Is there an error in my code that deals with data transfer?

    (In the code that uses another cog I tried sizing my stack up to 255 longs and still no success.)
      repeat
        ser.rxflush                                      'Clear receive buffer
        repeat i from 0 to 4                             'Send command string to ECU
          ser.tx(@request[i])
        repeat r from 0 to 66                            'Fill array
          data[r]:= ser.rx
      
        term.str(string($A,1,$B,1,$0D))                  'Set display position 
        tmp := data[49]                                  'Word 49 is raw throttle position
        throt := tmp                                     'No conversion, display raw count
        term.str(String("TPS "))                         'Print label
        term.str(string($A,10,$B,2))                     'Set display location to column 10
        term.dec(throt)                                  'Print value
        term.str(String("  "))                           'Put a couple blank spaces after the value is displayed
        term.str(String($0D))                            'Newline
    
    DAT
    title    byte    "ALDL MONITOR",13,13,0     
    request  byte    $F4,$57,$01,$00,$B4 
    

    Thanks,
    JL
  • kuronekokuroneko Posts: 3,623
    edited 2012-01-16 18:14
      repeat
        ser.rxflush                                      'Clear receive buffer
        repeat i from 0 to 4                             'Send command string to ECU
          ser.tx([COLOR="red"]@[/COLOR]request[i])
        repeat r from 0 to 66                            'Fill array
          data[r]:= ser.rx
      
        term.str(string($A,1,$B,1,$0D))                  'Set display position 
        tmp := data[49]                                  'Word 49 is raw throttle position
        throt := tmp                                     'No conversion, display raw count
        term.str(String("TPS "))                         'Print label
        term.str(string($A,10,$B,2))                     'Set display location to column 10
        term.dec(throt)                                  'Print value
        term.str(String("  "))                           'Put a couple blank spaces after the value is displayed
        term.str(String($0D))                            'Newline
    
    DAT
    title    byte    "ALDL MONITOR",13,13,0     
    request  byte    $F4,$57,$01,$00,$B4 
    
    Just get rid of the @ symbol here. request is a DAT array (as opposed to VAR). Adressing is the same, i.e. first element is request[0].

    I have a look at the cognew issue.
  • kuronekokuroneko Posts: 3,623
    edited 2012-01-16 18:50
    Odd, there is nothing obvious wrong. I faked an ECU which just receives the 5 command bytes and sends them back for all 67 results. The data is written to PST instead of TV. Subsequently also used VGA and it just works.
    CON
       _clkmode = xtal1 + pll16x                         'Standard clock mode * crystal frequency = 80 MHz
       _xinfreq = 5_000_000
    
    VAR
      long  stack[32]                                    'Stack space for new cog
      byte  data[67]                                     'Space for data array
        
    OBJ
      ser: "FullDuplexSerial"
      dbg: "FullDuplexSerial"
       
    PUB Main
    
      [COLOR="orange"]cognew(ecu_method, @ecu_stack)[/COLOR]                     'Fake ECU
    
      ser.start(7, 6, %0000, 8192)                       'Start ALDL communications with FullDuplexSerial
      dbg.start(31, 30, %0000, 115200)                   'Start debug Terminal
      waitcnt(clkfreq*3 + cnt)                           'Give methods chance to start
      dbg.tx(0)                                          'Clear screen
    
      cognew(GetData(@data), @stack)                     'Continuously get ECU data       
    
      repeat
        dbg.str(string("TPS "))                          'Print label
        dbg.hex(data[49], 2)                             'Print value
        dbg.tx(1)
        waitcnt(clkfreq/10 + cnt)
    
    PRI GetData(dataAddr) | i
    
      repeat
        ser.rxflush
        repeat i from 0 to 4                             'Send command string to ECU
          ser.tx(request[i])
        repeat i from 0 to 66                            'Fill array
          byte[dataAddr][i]:= ser.rx
    
    DAT
    
    title   byte    "ALDL MONITOR",13,13,0
    request byte    $F4, $57, $01, $00, $B4
    
    [COLOR="orange"]VAR
      long  ecu_stack[32]
      byte  cmds[5]
      
    OBJ
      ecu: "FullDuplexSerial"
    
    PRI ecu_method | i
    
      ecu.start(6, 7, %0000, 8192)
      repeat
        repeat i from 0 to 4
          cmds[i] := ecu.rx
        repeat i from 0 to 66
          ecu.tx(cmds[frqa // 5])
        frqa++
        waitcnt(clkfreq + cnt)
    [/COLOR]
    DAT
    
    Could it be that the ECU needs some time to recover before it can take the next command sequence? In your no-extra-cog example you have debug output between receiving all data and sending a new command sequence. For the extra-cog example this delay doesn't exist (command sequence is sent immediately).
  • J LudwigJ Ludwig Posts: 19
    edited 2012-01-16 19:10
    kuroneko,
    Thanks, I have changed longs to bytes and put the request array in DAT. The working code is still working but much cleaner in the VAR department.

    My attempts at running the data acquistion in a new cog result in the same - it replies once with the correct value then it appears (viewing Tx with a scope) to quit sending requests.
    JL

    My cleaned up code trying to start new cog:
    {The purpost of this object is to acquire data continuously from the Engine Control Unit in one cog and display the results with another cog}
    
    
    CON
       _clkmode = xtal1 + pll16x                         'Standard clock mode * crystal frequency = 80 MHz
       _xinfreq = 5_000_000
    
    VAR
      long  stack[255]                                    'Stack space for new cog 
      byte  data[67]                                     'Space for data array
        
    OBJ
      ser      : "FullDuplexSerialPlus"
      term     : "tv_text"
       
    PUB Main | tmp, throt
    
      ser.start(7, 6, %0000, 8192)                       'Start ALDL communications with FullDuplexSerial
      term.start(12)                                     'Start TV Terminal
      waitcnt(clkfreq + cnt)                             'Give methods chance to start
      term.str(@title)                                   'Print Title on TV screen
    
      cognew(GetData(@data), @stack)                     'Continuously get ECU data       
    
      repeat
        term.str(string($A,1,$B,1,$0D))                  'Set display position 
        tmp := data[49]                                  'Word 22 is raw coolant temp
        throt := tmp                                     'No conversion, display raw count
        term.str(String("TPS "))                         'Print label
        term.str(string($A,10,$B,2))                     'Set display location
        term.dec(throt)                                  'Print value
        term.str(String("  "))                           'Put a couple blank spaces after the value is displayed
        term.str(String($0D))                            'Newline
    
    
    PUB GetData (dataAddr) | i, r
    
      repeat
        ser.rxflush
        repeat i from 0 to 4                             'Send command string to ECU
          ser.tx(request[i])
        repeat r from 0 to 66                            'Fill array
          byte[dataAddr][r]:= ser.rx
    
    DAT
    title    byte    "ALDL MONITOR",13,13,0     
    request  byte    $F4,$57,$01,$00,$B4
    
  • kuronekokuroneko Posts: 3,623
    edited 2012-01-16 19:25
    J Ludwig wrote: »
    My attempts at running the data acquistion in a new cog result in the same - it replies once with the correct value then it appears (viewing Tx with a scope) to quit sending requests.
    Can you add some debug code which indicates where exactly in the ECU loop it gets stuck? E.g. use a global variable which is displayed in the main loop. IDs are:
    1. before rxflush
    2. before command sequence is sent
    3. before receive loop is entered
    4. maybe also indicate how often it goes around the loop
    The code structure as such is OK. Now I'm trying to figure out if it's a timing issue (see last comment in post #5).
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2012-01-16 19:40
    Shouldn't ser.start be called from the cog that uses that object (i.e. GetData), or does it matter?

    -Phil
  • kuronekokuroneko Posts: 3,623
    edited 2012-01-16 19:43
    Shouldn't ser.start be called from the cog that uses that object (i.e. GetData), or does it matter?
    It's FDS[+] which is fine. IIRC only Simple_Serial has this issue. Besides, it works for me with a fake ECU.
  • J LudwigJ Ludwig Posts: 19
    edited 2012-01-16 19:56
    kuroneko,
    It WAS a timing issue, I put a 10 millisecond delay at the end of the repeat loop and now it works. I will try shorter values until I find the optimum time.
    Thank you very much for all your tips. I can move on with the project, my next step will be to add some floating point code to display some two-byte parameters that are in milliseconds, and other non-integer scaling formulas.
    JL
  • J LudwigJ Ludwig Posts: 19
    edited 2012-01-16 20:09
    Phil,
    Thanks, I missed seeing your reply earlier. The code works as it is now with calling ser.start from the Main method. I will try that though, it makes good sense.

    BTW, Thanks for your altimeter object. I added a quadrature encoder so that I could adjust the barometric pressure from a local setting. (there's an iPhone app called AeroWeather that you can program for favorite locations) I put the breadboard on the seat of my airplane and with the local (Troutdale, OR) altimeter setting it was right on with my airport at Camas. As soon as I was up to speed, it read a little higher due to lower cabin pressure but that error was pretty consistent all the way up to 9500 feet!

    JL
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2012-01-16 21:12
    Hey JL,

    I'm glad to hear the altimeter object worked out for you and that it's proven good to nearly 10K feet!

    -Phil
Sign In or Register to comment.