Shop OBEX P1 Docs P2 Docs Learn Events
Creating a multi port serial object - Page 2 — Parallax Forums

Creating a multi port serial object

2

Comments

  • Cluso99Cluso99 Posts: 18,066

    @DiverBob

    My multiport driver is now working on P2. You can have up to 8 fullduplexports or 16 of any receive and/or transmit pins/ports.



  • I’ve been watching your progress with great interest and looking over your approach to the coding. I’ve learned a few things and it’s given me some ideas for parts of my code that I wasn’t sure how to proceed. My Version has been one of slow progress, lots of notes and code tidbits written down on paper. Plan is to start putting it all on the computer and see how it comes out. I have a bit of a different approach to doing multi-ports, at this time I’d just want to see if I can finish it up as working code.

  • DiverBobDiverBob Posts: 1,091
    edited 2021-01-29 04:27

    I've been glued to my computer translating several pages of notes finally into code. I've run into a problem that I've been unable to figure out how to code for a while now.

    I added a note in the DAT pasm section where I'm stuck on the rx_serial section. I've hit a mental block on what I need to do to get the head value from the serdata array and then write it back again. Thanks for any help!

    rx_serial       testp     rxd                           wc      ' anything waiting on smartpin?
        if_nc       ret
    
                    rdpin     t3, rxd                               ' read new byte
                    shr       t3, #24                               ' align lsb
    
                    mov       t2, #BUF_SIZE                         ' get port offset for rxbuf
                    mul       t2, #portctr                          ' t2 is rxbuf offset for current port
                    mov       t1, p_rxbuf[t2]                       ' t1 := @rxbuf at current port buffer area
    
                    mov       t4, #RXHEAD_OFFSET                    ' get offset to rxhead
                    add       t4, p_port                            ' add offset to port data location
    
    ' ------------ getting stuck here on how to get rxhead value and then write it back to rxhead ???????
    
                    rdlong    t2, ptra[4]                           ' t2 := rxhead
                    add       t1, t2
                    wrbyte    t3, t1                                ' rxbuf[rxhead] := t3
                    incmod    t2, #(BUF_SIZE-1)                     ' update head index
        _ret_       wrlong    t2, ptra[5]                           ' write head index back to hub
    
    
    
    • This is based on the jm_fullduplexserial.spin2 object, I have edited everything above the area I got stuck on, the rest of the code is original coding I am using as a guide
    • interesting how the new CODE block colors the entry
  • With a fresh day I went back and saw some mistakes I made and corrected the rx_serial routine enough that the code at least compiles. Tomorrow I’ll start fresh on the tx_serial routine.

    I’m still a bit hazy on a concept that I haven’t seen an example to study yet. In this code I set up an array. I’ve got a pointer to the first element in the array and offsets defined as constants. What is the right way to increment a pointer to a specific item? I thought using MOV and ADD was the right way but that those work on the data the address is pointing at. Is there a command for incrementing an address a specific amount?

  • Cluso99Cluso99 Posts: 18,066

    There are two ways I can think of....

    1. Use the head and tail where they are offsets into the bufer, initially beginning with 0. An INCMOD can be used to add and wrap-around. You will need to know the size (maximum before returning to 0 for head and tail indexes). A good example is JonnyMac's jm_fullduplexserial.
    2. Use hub address pointers, where both head and tail start with the first buffer address. When they are incremented, a compare with the last+1 hub buffer address is done and if so, the address is reset to the first address. An example is my mpx_multiportserial.

    As you've probably seen, it's tricky to ensure you get it right. Both the above examples have both spin and pasm examples.

  • Thanks for the information! At first I didn’t really understand your answer but as I was writing out my response the light started to come on, at least for item #1.

    1. INCMOD as I understand how it works is that it increments the data value specified by D. So if the D field is actually an address this increments to the next address. I was looking at INCMOD just for incrementing a data value (1,2,3,4, etc), didn’t think about the D Value could be an address also.

    I see that in the DAT section you can do a block copy using SETQ followed by the number of longs to copy minus 1. Then the data in the ptra register points to the first entry in that block. So using ADD ptra, #1 increments the ptra data (which is an address) by 1 so the D field holds the new address value.

    It is legal syntax to write things like ptra[x] and return the data from that address. But when I tried something like p_array[x] in pasm I get a compiler error. Is ptra a special case or is it more likely that I don’t have a proper address value for p_array?

    Item 2 I need to study more.

  • Cluso99Cluso99 Posts: 18,066

    Yes, PRTA and PTRB are special for using the indexed values ptrx[..]. Also, these only apply to rdxxxx and wrxxxx instructions. See Chip’s documentation.

  • New question!

    Ptra uses the hub address to point to variables linked via cogint. I can use rdxxx in pasm to copy the data at the hub address ptra is pointing at to a pasm variable. So how do I get the new cog address of the pasm variable?

  • Cluso99Cluso99 Posts: 18,066

    Not sure what you're asking Bob.

    You've read into a register variable using rdlong xxx,ptra[n] so now it's in a register named xxx or whatever you called it.

  • @Cluso99 said:
    Not sure what you're asking Bob.
    You've read into a register variable using rdlong xxx,ptra[n] so now it's in a register named xxx or whatever you called it.

    I’m probably not explaining myself well or not using the right terminology.
    After I copy a variable value from hub memory into cog memory into a register named xxx, how do I then determine the cog memory address for that register? In Spin2 I can use ‘ptr := @variablename’ to get the address of a variable. How do you do the same thing in pasm?

  • AribaAriba Posts: 2,682
    edited 2021-02-02 15:28

    #xxx gives you the cogram address of the register xxx
    if you want to copy some longs from hubmemory to cogmemory:

            mov     pb,#0               'buffer index
    .loop   altd    pb,#buffer          'modify destination of rdlong: pb+bufferaddr
            rdlong  0-0,ptra++          'copy long
            incmod  pb,#8      wc       'next cog addr, wrap inside 8
      if_nc jmp     #.loop
    
    buffer  long    0[8]                '8 longs in cogram initialized with 0
    
    

    for such a direct copy there is a more efficient way with setq, but this is only
    an example to show how you access hub and cog memory.

    Andy

  • Thank you for the example. I didn’t know that # could return the cog address, I’ll go back and reread the P2 docs again, must have missed or more likely misunderstood the information.

  • I've got a starting framework for a multi-port serial object that I want to share. Please look it over and see if the code is actually doing what my notes say it is supposed to be doing! I am including the most relevant portions of the code at this time. This is all based on JonnyMac's jm_fullduplexserial object. I still have to add the code for rx_serial and tx_serial in pasm but figuring out the data framework and how to access it inside of pasm has been a learning experience.

    This is the initial variable setup. At this point I am restricting it to a max of 8 open ports but by changing the MAX_PORT value you could open a lot more.

    con
      BUF_SIZE       = 64                                             ' size of rx and tx buffers
      MAX_PORT       = 8                                              ' set to number of ports to be used (1-8)
      STRUCT_SIZE    = 9                                              ' # array elements used
      RX_OFFSET      = 0
      TX_OFFSET      = 1
      RXHUB_OFFSET   = 2
      TXHUB_OFFSET   = 3
      RXHEAD_OFFSET  = 4
      RXTAIL_OFFSET  = 5
      TXHEAD_OFFSET  = 6
      TXTAIL_OFFSET  = 7
      TXDELAY_OFFSET = 8
    
    var
      long  cog                                                     ' cog flag/id
    
      long  num_ports                                               ' total number of open ports (0-7)
      long  serialdata[STRUCT_SIZE * MAX_PORT]                      ' array for serial variables
    
      byte  rxbuf[BUF_SIZE * MAX_PORT]                              ' buffers - set MAX_PORT to actual open ports
      byte  txbuf[BUF_SIZE * MAX_PORT]
    

    addport is run for each port to be opened. It adds data into serialdata array and sets up the smartpins.
    The routine returns the assigned port number.

    pub addport(rxpin, txpin, mode, baud) : result | baudcfg, spmode, rxt, txt, tdelay
    '' add additional ports - call before start. miniumum 1 port required
    '' load serialdata array and setup smartpins
    '' does not check for port duplication
    '' run addport at least once before calling start method
    '' returns port id (0 to MAX_PORT-1), -1 on error
    '' -- rxpin... receive pin (-1 if not used)
    '' -- txpin... transmit pin (-1 if not used)
    '' -- mode.... %0xx1 = invert rx
    ''             %0x1x = invert tx
    ''             %01xx = open-drain/open-source tx
    
      if (rxpin == txpin)                                            ' pins must be unique
        return -1
      '' check if pin used by any other ports
    
      if (num_ports > MAX_PORT-1)                                    ' port in range
        return -1                                                    ' error, initializing too many ports
        abort
      else
        return num_ports                                             ' return port number (0-7), -1 if error
    
      baudcfg := muldiv64(clkfreq, $1_0000, baud) & $FFFFFC00        ' set bit timing
      baudcfg |= (8-1)                                               ' set bits (8)
    
      rxt := (num_ports * STRUCT_SIZE) + RX_OFFSET                   ' calculate offset
      longmove(serialdata[rxt], rxpin, 1)                            ' save pin in array
    
      if (serialdata[rxt] >= 0)                                      ' configure rx pin if used
        spmode := P_ASYNC_RX
        if (mode.[0])
          spmode |= P_INVERT_IN
        pinstart(serialdata[rxt], spmode, baudcfg, 0)
    
      txt := (num_ports * STRUCT_SIZE) + TX_OFFSET
      longmove(serialdata[txt], txpin, 1)
    
      if (serialdata[txt] >= 0)                                      ' configure tx pin if used
        spmode := P_ASYNC_TX | P_OE
        case mode.[2..1]
          %01 : spmode |= P_INVERT_OUTPUT
          %10 : spmode |= P_HIGH_FLOAT                               ' requires external pull-up
          %11 : spmode |= P_INVERT_OUTPUT | P_LOW_FLOAT              ' requires external pull-down
        pinstart(serialdata[txt], spmode, baudcfg, 0)
    
      serialdata[(num_ports * STRUCT_SIZE) + RXHUB_OFFSET] := @rxbuf[num_ports * BUF_SIZE]    ' ptr to rx and tx hub buffer address
      serialdata[(num_ports * STRUCT_SIZE) + TXHUB_OFFSET] := @txbuf[num_ports * BUF_SIZE]
    
      tdelay := (num_ports * STRUCT_SIZE) + TXDELAY_OFFSET
      serialdata[tdelay] := clkfreq / baud * 11                      ' tix to transmit one byte
    
      num_ports++                                                    ' increment port counter
    
    pub start() : result
    '' Start new cog
      stop()
    
      cog := coginit(COGEXEC_NEW, @uart_mgr, @num_ports) + 1         ' start uart manager cog
    
      return cog
    

    Here is the PASM code. The idea is to read the port values from the serialdata array for each port in turn ,
    copy the port data to variables and then act on the values.

    dat { smart pin uart/buffer manager }
    
                    org
    uart_mgr
                    ' read hub variables into cog, get # of open ports
                    ' and structure size to determine size of serialdata array
                    ' to copy to cog ram
                    rdlong    portnum, ptra                       ' get # of open ports
                    add       ptra, #4
                    mov       t1, #STRUCT_SIZE                      ' get number of longs to read from hub serdata array
                    mul       t1, portnum                           ' STRUCT_SIZE * #ports is size of serdata array
                    setq      t1 -1                                 ' block copy serdata to cog
                    rdlong    t2, ptra                              ' read first item in array
                    mov       p_buf, #t2                            ' get address for array start
    
                    ' loop through each port one at a time to get rx, tx, baud,
                    ' p_rxbuf, and p_txbuf
    uart_main       mov       portctr, #0                           ' set portctr to 0
                                                                    ' portctr loops through each open port
    .loop           mov       t1, #STRUCT_SIZE                      ' get port data in serdata array
                    mul       t1, #portctr                          ' t1 has offset value in p_buf for p_port
                    mov       p_port, #p_buf                        ' put array start point into p_port
                    add       p_port, #t1                           ' add offset to get p_port address at start of port
    
                    ' get offsets for array values
                    mov       p_offset, #p_port                     ' copy port data start address to offset
                    add       p_offset, #RX_OFFSET                  ' add rx pin offset
                    mov       rxd, p_offset                         ' put rx pin in rxd
    
                    mov       p_offset, #p_port                     ' copy data block start location to offset
                    add       p_offset, #TX_OFFSET                  ' add offset to point to tx pin
                    mov       txd, p_offset                         ' put tx pin in txd
    
                    mov       p_offset, #p_port                     ' copy data block start location to offset
                    add       p_offset, #RXHUB_OFFSET               ' add offset to point to rxbuf
                    mov       p_rxbuf, p_offset                     ' hub ram location in p_rxbuf for rxbuf
    
                    mov       p_offset, #p_port                     ' copy data block start location to offset
                    add       p_offset, #TXHUB_OFFSET               ' add offset to point to txbuf
                    mov       p_rxbuf, p_offset                     ' hub ram location in p_txbuf for txbuf
    
                    ' check if data available at smartpins. If data
                    ' available, jump to rx_serial or tx_serial
                    testb     rxd,  #31                     wc      ' rx pin in use? -test for -1 when no pin saved
        if_nc       call      #rx_serial
    
                    testb     txd, #31                      wc      ' tx in use? -test for -1
        if_nc       call      #tx_serial
    
                    ' increment counter to next port. if portctr >
                    ' open ports, reset portctr to 0 and loop
                    incmod    portctr, #portnum             wz      ' check if portctr = open ports
        if_nz       call      #.loop                                ' repeat loop for each open port
    
                    jmp       #uart_main
    
    rx_serial       'next area to work on 
    tx_serial       
    
    ' --------------------------------------------------------------------------------------------------
    portnum         long      1                                     ' total # ports
    p_buf           long      1                                     ' ptr to cog serialdata array
    
    p_port          res       1                                     ' ptr to specific port in serdata array
    p_offset        res       1                                     ' offset pointer
    p_rxbuf         res       1                                     ' pointer to rxbuf
    p_txbuf         res       1                                     ' pointer to txbuf
    
    portctr         res       1                                     ' loop counter
    rxd             res       1                                     ' rx pin
    txd             res       1                                     ' tx pin
    t1              res       1                                     ' work vars
    t2              res       1
    t3              res       1
    t4              res       1                                     '
    
    
  • The previous entry got so slow I wasn’t able to add any additional comments. The code isn’t complete but I wanted see if some of our p2pasm experts could look it over and see if the coding is correct for what I am trying to accomplish. I put in a lot of notes to help myself as I was attempting to increment through cog ram to access values in the serial data array.
    My wife is telling me to get off the computer and get dinner out so I’ll leave now!

  • Cluso99Cluso99 Posts: 18,066

    Just had a quick look, nothing detailed.

    You haven't allocated enough space for t2 when you doe the setq block read.
    Didn't have time to check the calcs but you seem to be doing a lot of manipulation of the register addresses instead of the contents. Not sure if this is correct. I have always found to let the code do a dry run and outputting data and address dumps to the serial. Chips debug should be good for this.

  • Yeh, lots of manipulation of register addresses in there! The idea is that p_buf points to the first item in an array. Each port has 9 entries in the array, arranged one after another. So using p_buf address as the entry point to the array the first port is the first 9 addresses, the next port is the following 9 addresses and so on. The p_port points to the address of the first entry of a specific port and the p_offset then gets the value from that address offset.
    Good point about t2, I need to define a variable big enough to hold the entire array which can be up to 72 longs (9 elements X 8 ports). Is there a way to dynamically set the variable size in case I’m dealing with less than 8 ports?
    I really should run this through Pnut and use Chip’s debug to see if my assumptions are right. I mostly use the Prop Tool and have been hoping that Jeff gets then debug version out soon (according to last nights meeting we should see it pretty soon).

  • After a lot of false steps from trying to figure out pasm, I finally did what I should have done a while back. I opened my code in Pnut and started using the DEBUG commands to see what was really happening inside the registers. With this additional information many things that I had been making assumptions on have become much clearer. The ability to easily make changes on the fly and see the results has made a huge difference in helping make sense of these commands and how they interact with each other. I’m still a long way from finishing up my version of a multi-port serial object but today was the first time I felt I was making some real progress.
    Now I just hope Parallax gets the Debug working in the Propellor Tool soon!

  • jrullanjrullan Posts: 159
    edited 2021-02-09 05:30

    @DiverBob said:
    ...I opened my code in Pnut and started using the DEBUG commands ... I just hope Parallax gets the Debug working in the Propellor Tool soon!

    While we wait for Debug on Prop Tool (it's supposed to be coming very soon according to some posts I've seen), you might want to check Flexprop since it already implements the basic debug commands. I have been using it for exactly this reason as a complement to Prop Tool since Pnut is too barebones for me (no syntax highlighting, weird scrolling and tab spacing).

  • I didn’t realize FlexProp had Debug added to itself. I had used it a while back when I was trying out C programming (because C had Sin, Cosine, and Tan available in the math module) and signed up to be a Patreon since I liked what I saw. Time to revisit the program.
    Had some interesting times yesterday with Pnut. Opened my test Spin2 program and all my edits were gone. Realized that I accidentally had the same program open in the Prop Tool so all my saves were not actually saved. So I had to start from scratch again. Unfortunately I ran into an issue where I added another debug entry and it won’t come up on the terminal. All the earlier debug lines show up still but anything new doesn’t. I thought the docs say you can have up to 256 debug lines (I have around 10 debug statements) so not sure why this is happening. I got distracted after my Firefox on the Win10 computer refused to open any Parallax forum or the developer docs so I shut everything down for the day in frustration. Ready to give it another go today and hopefully everything will start working again.

  • DiverBobDiverBob Posts: 1,091
    edited 2021-02-11 22:52

    It took a while but finally got my windows 10 computer to play nice again. Unfortunately I'm still not understanding something basic in pasm coding, mainly copying variables from Hub to Cog.

    con
      ' serial specific constants
      BUF_SIZE       = 64                                            ' size of rx and tx buffers
      MAX_PORT       = 2                                             ' set to number of ports to be used (1-8)
    
    var
      long  cog                                                      ' cog flag/id
      long  num_ports                                                ' total number of open ports (0-7)
      long  rxdata[MAX_PORT]                                       ' rx pin array
      long  txdata[MAX_PORT]                                       ' tx pin array
      long  rxhub[MAX_PORT]                                        '
      long  txhub[MAX_PORT]                                        '
      long  rxhead[MAX_PORT]
      long  rxtail[MAX_PORT]
      long  txhead[MAX_PORT]
      long  txtail[MAX_PORT]
      long  txdelay[MAX_PORT]
    
      byte  rxbuf[BUF_SIZE * MAX_PORT]                               ' buffers - set MAX_PORT to actual open ports
      byte  txbuf[BUF_SIZE * MAX_PORT]
    
      byte  pbuf[80]                                                 ' padded strings
    
    pub main()| t
      ' used during testing for setup only
      t := addport(5, 6, %0000, BR_TERM)                ' 1st open port
      t := addport(21, 22, %0000, BR_TERM)              ' 2nd open port
      debug(udec(rxdata[0]))
      debug(udec(rxdata[1]))
      debug(udec(txdata[0]))
      debug(udec(txdata[1]))
      debug(udec(rxhub[0]))
      debug(udec(rxhub[1]))
      start()
    
    pub addport(rxpin, txpin, mode, baud) : result | baudcfg, spmode, tdelay
    '' add additional ports - call before start. miniumum 1 port required
    '' load serialdata array and setup smartpins
    '' does not check for port duplication
    '' run addport at least once before calling start method
    '' returns port id (0 to MAX_PORT-1), -1 on error
    '' -- rxpin... receive pin (-1 if not used)
    '' -- txpin... transmit pin (-1 if not used)
    '' -- mode.... %0xx1 = invert rx
    ''             %0x1x = invert tx
    ''             %01xx = open-drain/open-source tx
    
      if (rxpin == txpin)                                            ' pins must be unique
        result := -1
      '' check if pin used by any other ports
    
      if num_ports > (MAX_PORT-1)                                    ' port in range
        result := -1                                                 ' error, initializing too many ports
        abort
      else
        result := num_ports                                          ' return port number (0-7), -1 if error
    
      txdelay[num_ports] := clkfreq / baud * 11                      ' tix to transmit one byte
    
      baudcfg := muldiv64(clkfreq, $1_0000, baud) & $FFFFFC00        ' set bit timing
      baudcfg |= (8-1)                                               ' set bits (8)
    
      rxdata[num_ports] := rxpin                                     ' save rx pin
    
      if rxdata[num_ports] >= 0                                      ' configure rx pin if used
        spmode := P_ASYNC_RX
        if (mode.[0])
          spmode |= P_INVERT_IN
        pinstart(rxpin, spmode, baudcfg, 0)
    
      txdata[num_ports] := txpin                                     ' save tx pin
    
      if txdata[num_ports] >= 0                                      ' configure tx pin if used
        spmode := P_ASYNC_TX | P_OE
        case mode.[2..1]
          %01 : spmode |= P_INVERT_OUTPUT
          %10 : spmode |= P_HIGH_FLOAT                               ' requires external pull-up
          %11 : spmode |= P_INVERT_OUTPUT | P_LOW_FLOAT              ' requires external pull-down
        pinstart(txpin, spmode, baudcfg, 0)
    
      rxhub[num_ports] := @rxbuf[num_ports * BUF_SIZE]               ' ptr to hub buffer address
      txhub[num_ports] := @txbuf[num_ports * BUF_SIZE]
    
      num_ports++                                                    ' increment port counter
    
    

    Above is my setup in spin, the AddPort function works correctly and in this example puts rxdata[0] = 5, rxdata[1] = 21, txdata[0] = 6, txdata[1] = 22, and so on. Debug shows the values stored correctly.

    dat { smart pin uart/buffer manager }
    
                    org
    uart_mgr
                    ' read hub arrays into cog, get # of open ports
                    ' to copy to cog ram
                    rdlong    portnum, ptra++                         ' get # of open ports
    '       debug(udec(portnum))
                    mov       t1, #MAX_PORT                         ' get number of longs to read
                    mul       t1, #4                                ' multiply by 4 seperate arrays to copy
    '       debug(udec(t1))
                    setq      t1 -1                                 ' block copy serdata to cog
                    rdlong    rxbuff, ptra 
            debug(udec_long(rxbuff))                            
    uart_main       ' loop through each port one at a time to get rx, tx
                                                             ' portctr loops through each open port
            mov       portctr, #0                            ' set portctr to 0
                    debug(udec(portctr))                            ' portctr loops through each open port             ----no debug statements show up in the terminal window starting here
    
    .loop           ' get offsets for array values
            alts      portnum, #rxbuff
                    mov       rxd, 0                                ' copy data block start location to offset
                    debug(udec(rxd))                            ' portctr loops through each open port
    
                    mov       t1, txbuff                            ' copy start address
                    add       t1, #portnum                          ' add in offset
                    mov       txd, t1                               ' copy data block start location to offset
    
                    ' check if data available at smartpins. If data
                    ' available, jump to rx_serial or tx_serial
                    testb     rxd,  #31                     wc      ' rx pin in use? -test for -1 when no pin saved
        if_nc       call      #rx_serial
    
                    testb     txd, #31                      wc      ' tx in use? -test for -1
        if_nc       call      #tx_serial
    
                    ' increment counter to next port. if portctr >
                    ' open ports, reset portctr to 0 and loop
                    incmod    portctr, #portnum             wz      ' check if portctr = open ports
        if_nz       call      #.loop                                ' repeat loop for each open port
    
                    jmp       #uart_main
    '----------------------------------------------- no changes to original pasm code past here yet ----------------------------------
    rx_serial       testp     rxd                           wc      ' anything waiting on smartpin?
        if_nc       ret
    
                    rdpin     t3, rxd                               ' read new byte from smartpin
                    shr       t3, #24                               ' align lsb
                    mov       offset, p_rxbuf
                    add       offset, #portnum
                    mov       t1, offset                            ' t1 := @rxbuff[portnum]
                                                                     ' t2 := rxhead
        _ret_       wrlong    t2, offset                          ' write rxhead index back to hub
    
    tx_serial       rdpin     t1, txd                       wc      ' check busy flag
        if_c        ret                                             '  abort if busy
    
                    rdlong    t1, ptra[7]                           ' t1 = txhead
                    rdlong    t2, ptra[8]                           ' t2 = txtail
                    cmp       t1, t2                        wz      ' byte(s) to tx?
        if_e        ret
    
                    mov       t1, p_txbuf                           ' start of tx buffer
                    add       t1, t2                                ' add tail index
                    rdbyte    t3, t1                                ' t3 := txbuf[txtail]
                    wypin     t3, txd                               ' load into sp uart
                    incmod    t2, #(BUF_SIZE-1)                     ' update tail index
        _ret_       wrlong    t2, ptra[8]                           ' write tail index back to hub
    
    ' --------------------------------------------------------------------------------------------------
    
    portnum         long      1                                     ' total # ports
    rxbuff          long      0[2]                                  ' rx pin array
    txbuff          long      0[2]                                  ' tx pin array
    p_rxbuf         long      0[2]                                  ' ptr to rxhub
    p_txbuf         long      0[2]                                  ' ptr to txhub
    
    portctr         res       1                                     ' loop counter
    rxd             res       1                                     ' rx pin
    txd             res       1                                     ' tx pin
    offset          res       1
    t1              res       1                                     ' work vars
    t2              res       1
    t3              res       1
    t4              res       1                                     '
    

    The pasm section is based on the JonnyMac fullduplexserial code. At the beginning the rdlong reads in the correct portnum value. That is used to calculate the number of longs for the block copy using setq.
    However the debug to read the first value in rxbuff I thought would be '5' (from rxdata[0]) is showing as 772_538_522 instead. Either I'm not using debug correctly or I missed something on the block copy to the cog.
    Another thing that happens is that although the code compiles without error, the debug statements past reading the debug for rxbuff show up in the debug terminal window. I was using the debug output to work my way through the pasm code and got to this stopping point and not sure how to proceed.

  • AribaAriba Posts: 2,682

    I have not checked the whole code but some things have caught my eyes.

            mov       t1, #MAX_PORT          ' get number of longs to read
            mul       t1, #4                 ' multiply by 4 seperate arrays to copy
            setq      t1 -1                  ' block copy serdata to cog
            rdlong    rxbuff, ptra 
    
    

    That does not work and is overcomplicated. You would need a sub t1,#1 instead of t1 -1 (this accesses the variable before t1), but because MAX_PORT is a constant anyway, you can just write:

            setq      #MAX_PORT*4-1          ' block copy serdata to cog
            rdlong    rxbuff, ptra 
    
    

    You also use #portnum later in the code, while portnum is a register you load at begin. You want the register value and not the address of portnum, so use it without the #.

    Another problem, I see: You read the spin variables only once at begin, but some of them will change (the heads and tails), so you need to read them again in the loop.

    Andy

  • Thanks for looking at my code and your comments, I’ll try your suggestion out as soon as I get back on the computer.
    I haven’t gotten down to making any changes to the part on the heads and tails part yet, I’ve just been modifying JonnyMac’s code as I go along. I have been having difficulties just getting the spin variables to read into pasm properly. I’ve been mostly working on the loop that checks the smart pins for a rx or tx byte. I’ll be hitting up the rx and tx sections once I know the beginning is working right.

  • @Ariba said:

            mov       t1, #MAX_PORT          ' get number of longs to read
            mul       t1, #4                 ' multiply by 4 seperate arrays to copy
            setq      t1 -1                  ' block copy serdata to cog
            rdlong    rxbuff, ptra 
    

    That does not work and is overcomplicated. You would need a sub t1,#1 instead of t1 -1 (this accesses the variable before t1), but because MAX_PORT is a constant anyway, you can just write:

            setq      #MAX_PORT*4-1          ' block copy serdata to cog
            rdlong    rxbuff, ptra 
    
    

    I tried out your suggestion and it works. I didn’t think about simplifying the code and put it all on one line with setq. Additionally the debug is also working past where it was stopping before.
    The initial loop that cycles through the ports appears to work correctly so tomorrow I’ll start work on the rx_serial and tx_serial portions of the code.

  • Got a lot done today and finished up coding the RX and TX portions of pasm. Started testing the program as a whole and its obvious I have some mistakes in the pasm to figure out. Using debug it appears that the line incmod portctr, portnum wz isn't set up correctly as portctr should be cycling between 0 and the number of open ports-1, debug shows it cycling up indefinitely (not sure how to pause debug to troubleshoot this yet, need to review the debug docs again). When rx_serial and tx_serial sections are disabled the loop operates correctly. Not sure what is causing this to happen. Once portctr is out of the expected range of course that blows up the rest of the code.
    Comments and suggestions are welcome!

  • AribaAriba Posts: 2,682

    After the line incmod portctr, portnum wz you have a call #.loop instead of a jmp #.loop.
    I normally use the carry flag to detect the wrap around of incmod, but Zero flag should also work.

    Andy

  • Thanks for looking over the code. Why is it better to use jump vs call in this instance?

  • @Ariba said:
    After the line incmod portctr, portnum wz you have a call #.loop instead of a jmp #.loop.
    I normally use the carry flag to detect the wrap around of incmod, but Zero flag should also work.

    Andy

    I changed the call to jmp and used the carry flag also. I figured out the portctr issue, I was subtracting 1 from the portnum each time it looped through the first section. I didn't catch it because I put some stops in the code which masked that problem.
    Testing the tx_serial loop by transmitting numbers 1 through 99. The smartpin (pin 6), debug isn't showing the expected value (some very large value constantly changing). I don't see any output on pin 6 per the logic analyzer. It appears to be in the tx_serial code but I'm can't figure it out even with lots of debug statements.

  • I woke up with some new ideas on parts I got stuck on last night, tried them out and got at least partial success today; the uart_mgr, uart_main, and tx_serial sections of pasm appear to be working now. I believe the last pasm loop, rx_serial, is also working but haven't figured out how to fully test that yet. I'm getting the expected values using debug so far.
    I have tested at up to baud 115200 so far with no issues. The logic analyzer JonnyMac recommended is great for seeing the output. Once I'm sure the rx_serial is working then I'll start adding ports and see how many and fast I can go.
    Any suggestions for improvements or how to test the receive code is welcome!

  • After reviewing the other 2 multiport objects I wanted to incorporate some ideas I got from looking over the code. In my version all the buffers are tied to the object and you only have to add how ever many ports using AddPort() before you start the cog. I ended up breaking just about every part of the code so it was a good test of the new Prop Tool debugging capabilities to figure out what was going on. I managed to get things more or less running, the transmit and receive sections are running but the transmitter is no longer outputting the expected values (logic analyzer is not picking up any output) although I can see the values coming into the code via debugging. The same goes for the receive section, it appears to be wanting to store incoming data in the right locations but I'm not getting the expected values.
    After spending several hours on this today and not progressing, anyone good at P2 PASM willing to take a look and see where I'm going wrong? I appreciate any help!

    Bob

  • Duane DegnDuane Degn Posts: 10,588
    edited 2021-02-17 23:23

    I'd be glad to look at your code but I think it would be helpful to also have the parent object you're using for testing. An archive from the top object would be great.
    Edit: If the test code is the same as you used in post #1 then never mind. I'll use your earlier test code. Sorry, I should have check for earlier test code first.

Sign In or Register to comment.