Shop OBEX P1 Docs P2 Docs Learn Events
P2 ROM SERIAL ROUTINES - ROM version — Parallax Forums

P2 ROM SERIAL ROUTINES - ROM version

pic18f2550pic18f2550 Posts: 392
edited 2022-01-03 20:31 in Propeller 2

Hello,

does anyone know how I can query the Rx status if a character is ready to be fetched?

And how do I fetch a single character.

Both functions must not block the process.

The code is from the Z80 emulator.

'+-----------------------------------------------------------------------------+
  _bitper       = (_clkfreq / _baudx) << 16 + 7          ' xxx baud, 8 bits
  _txmode       = %0000_0000_000_0000000000000_01_11110_0 'async tx mode, output enabled for smart output
  _rxmode       = %0000_0000_000_0000000000000_00_11111_0 'async rx mode, input  enabled for smart input
'+-----------------------------------------------------------------------------+
  rx_pin        =       63                      'pin serial receiver
  tx_pin        =       62                      'pin serial transmitter
'+-----------------------------------------------------------------------------+

'+============[ COG VARIABLES $1E0-$1EF - ROM MONITOR]=========================+
'+-------[ LMM parameters, etc ]-----------------------------------------------+
  lmm_x         = $1e0          ' parameter passed to/from LMM routine (typically a value)
  lmm_f         = $1e1          ' parameter passed to      LMM routine (function options; returns unchanged)
  lmm_p         = $1e2          ' parameter passed to/from LMM routine (typically a hub/cog ptr/addr)
  lmm_p2        = $1e3          ' parameter passed to/from LMM routine (typically a 2nd hub/cog address)
  lmm_c         = $1e4          ' parameter passed to/from LMM routine (typically a count)
'+-------[ LMM additional workareas ]------------------------------------------+
  lmm_w         = $1e5          ' workarea (never saved - short term use between calls, except _HubTx)
  lmm_tx        = $1e6          ' _HubTx
  lmm_hx        = $1e7          ' _HubHex/_HubString
  lmm_hx2       = $1e8          ' _HubHex
  lmm_hc        = $1e9          '   "
  lmm_lx        = $1ea          ' _HubList
  lmm_lf        = $1eb          '   "
  lmm_lp        = $1ec          '   "
  lmm_lp2       = $1ed          '   "
  lmm_lc        = $1ee          '   "
  lmm_bufad     = $1ef          ' _HubRxString
'+-------[ ASCII equates ]-----------------------------------------------------+
  _CLS_         = $0C
  _BS_          = $08
  _LF_          = $0A
  _CR_          = $0D
  _TAQOZ_       = $1B           ' <esc>   goto TAQOZ
'+-------[ LMM DEBUGGER - CALL Modes...(not all modes supported) ]-------------+
  _MODE         = $F << 5                       ' mode bits defining the call b8..b5 (b4..b0 are modifier options)
  _SHIFT        = 5                             ' shr # to extract mode bits
  _HEX_         = 2 << 5                        ' hex...
    _REV_               = 1 << 4                '   - reverse byte order
    _SP                 = 1 << 3                '   - space between hex output pairs
   '_DIGITS             = 7..0 where 8->0       '   - no. of digits to display
  _LIST         = 3 << 5                        ' LIST memory line (1/4 longs) from cog/hub
    _ADDR2              = 1 << 4                ' 1= use lmm_p2 as to-address
    _LONG_              = 1 << 1                ' 1=display longs xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
  _TXSTRING     = 4 << 5                        ' tx string (nul terminated) from hub
  _RXSTRING     = 5 << 5                        ' rx string
    _ECHO_              = 1 << 4                '    - echo char
    _PROMPT             = 1 << 3                '    - prompt (lmm_x)
    _ADDR               = 1 << 2                '    - addr of string buffer supplied
    _NOLF               = 1 << 1                '    - strip <lf>
  _MONITOR      = 7 << 5                        ' goto rom monitor
'+-------[ P2 ROM SERIAL ROUTINES (HUBEXEC) - ROM version ]--------------------+
  _SerialInit      = $fcab8     ' Serial Initialise     (lmm_x & lmm_bufad must be set first)
  _hubTxCR         = $fcae4     ' Sends <cr><lf>        (overwrites lmm_x)
  _hubTxRev        = $fcaec     ' Sends lmm_x with bytes reversed
  _hubTx           = $fcaf0     ' Sends lmm_x           (can be up to 4 bytes)
  _hubHexRev       = $fcb24     ' Sends lmm_x with bytes reversed as Hex char(s) as defined in lmm_f
  _hubHex8         = $fcb28     ' Sends lmm_x as Hex char(s) after setting lmm_f as 8 hex chars
  _hubHex          = $fcb2c     ' Sends lmm_x as Hex char(s) as defined in lmm_f
  _hubTxStrVer     = $fcb9c     ' Sends $0 terminated string at lmm_p address after setting lmm_p=##_str_vers
  _hubTxString     = $fcba4     '\ Sends $0 terminated string at lmm_p address
  _hubTxStr        = $fcba4     '/ Sends $0 terminated string at lmm_p address
  _hubListA2H      = $fcbc4     ' List/Dump line(s) from lmm_p address to lmm_p2 address after setting lmm_f=#_LIST+_ADDR2
  _hubList         = $fcbc8     ' List/Dump line(s) from lmm_p address to lmm_p2 address according to lmm_f
  _hubRx           = $fcb10     ' Recv char into lmm_x
  _hubRxStrMon     = $fccc4     ' Recv string into lmm_bufad address after setting prompt=lmm_x=#"*" & params=lmm_f=#_RXSTRING+_ECHO_+_PROMPT
  _hubRxString     = $fcccc     ' Recv string into lmm_p/lmm_bufad address according to params in lmm_f
  _hubMonitor      = $fcd78     ' Calls the Monitor; uses lmm_bufad as the input buffer address
  _RdLongCogHub    = $fcf34     ' read cog/lut/hub long from lmm_p address into lmm_x, then lmm_p++
  _str_vers        = $fd014     ' locn of hub string, $0 terminated
'+-------[ HUB ADDRESSES ]-----------------------------------------------------+
  _HUB_ROM         = $FC000         ' ROM $FC000
  _HUB_SERBUF      = $FC000         '[80]  Serial receive buffer (overwrites ROM Booter)
  _HUB_SERSIZE     = 80             '      Serial receive buffer size
'+-----------------------------------------------------------------------------+

'+-------[ Start Serial for P2xxxx ]-------------------------------------------+
              mov       lmm_bufad,        ##_HUB_SERBUF  ' locn of hub buffer for serial routine
              mov       lmm_x,            ##_BITPER      ' sets serial baud
              call      #\_SerialInit                    ' initialise serial
'+-----------------------------------------------------------------------------+
              waitx     ##_STARTUP_DELAY                 ' delay to get terminal running
'+-----------------------------------------------------------------------------+

'+-----------------------------------------------------------------------------+
TX_DATA
              mov     lmm_x, Tx_Data
              call    #\_hubTx
              ret
'+-----------------------------------------------------------------------------+
RX_STATUS
              call      #\_hubRxStat?????
              mov     Rx_Stat, lmm_x
              ret
'+-----------------------------------------------------------------------------+
RX_DATA
            call      #\_hubRx
            mov     Rx_Data, lmm_x
            ret
'+-----------------------------------------------------------------------------+

:smile:
Smartpinn is easier with single characters.

Comments

  • Hello,

    I would like to ask again if there is a way to determine whether a new character was received or their number.

    CP/M often asks the status and I don't want to block the whole system.

    Thank you.

  • kwinnkwinn Posts: 8,697

    @pic18f2550 said:
    Hello,

    I would like to ask again if there is a way to determine whether a new character was received or their number.

    CP/M often asks the status and I don't want to block the whole system.

    Thank you.

    I would think that the RX_STATUS code below that is near the end of the code you posted would do that. Not 100% sure of that since the code it calls is not listed here.
    '+-----------------------------------------------------------------------------+
    RX_STATUS
    call #_hubRxStat?????
    mov Rx_Stat, lmm_x
    ret

  • No, the routine is only a guess, as _hubRxStat is not defined in the constants.

  • Cluso99Cluso99 Posts: 18,069

    Sorry i am away and on my iphone.

    I created a thread about using the P2 ROM Serial routines. IIRC there is a routine that does a rxline that places any received chars into a buffer.

  • pik33pik33 Posts: 2,350
    edited 2021-12-30 08:26

    Yesterday I wrote something for my RPi Zero based contraption. A P2 uses a serial port to receive messages from it via a serial port. This is done without any ROM procedures, instead I read the pin status to determine if the serial port received a byte. Then I put this byte into a circular buffer. Without this buffer there were missed bytes as they can arrive faster than the main program process them.

    Maybe something from this code can help. It opens 2 serial ports, one for a RPi (keyboard/mouse interface), one for MIDI and then receicves and processes this data.

    https://github.com/pik33/P2-retromachine/blob/main/Propeller/retrocog.spin2

    ' A retromachine cog
    ' The purpose: to read/send and process data from RPi and Midi Shield
    ' v. 0.01 pik33@o2.pl
    '
    
    con
    _clkfreq=320_000_000
    
    rxpin=32
    txpin=33
    midiin=29
    midiout=30
    baudrate=1920000
    mbaudrate=31250
    
    var
    
    long kbdfront,kbdtail
    long mousefront,mousetail
    long midifront,miditail
    
    long kbdbuf[32]
    
    long mousebuf[128]
    
    long midibuf[32]
    
    long serialstack[36]
    
    
    
    pub dummy()
    
    repeat
    'this is the object and not a program
    
    pub start :cog
    
    cog:=cogspin(16,serialcog(),@serialstack)
    return cog
    
    pub serialcog()| rr, mrr, b, mb, midireport, kbmreport
    
    'start serial and midi
    
    serial_start(rxpin, txpin, baudrate)
    serial_start(midiin,midiout,mbaudrate)
    
    mb:=(-1)
    b:=(-1)
    
    mousefront:=0
    mousetail:=0
    kbdfront:=0
    kbdtail:=0
    midifront:=0
    miditail:=0
    long[$30]:=0
    long[$34]:=0
    long[$38]:=0
    
    repeat
    
      repeat 
        rr:=rxcheck(rxpin)
        mrr:=rxcheck(midiin)
    
      until rr>=0 || mrr>=0  
    
    
    ' midi. Must be >= $80 for a command
    '$80-$8F - 3 bytes note off. note, velocity
    '$90-$9F - 3 bytes note on, note, velocity
    '$A0-$AF - 3 bytes poly aftertouch. note, value
    '$B0-$BF - 3 bytes control change, controller-value, 
    '$C0-$CF - 2 bytes program change
    '$D0-$DF - 2 bytes mono aftertouch
    '$E0-$EF - 3 bytes pitch bend, $2000 - center
    '$F0-$FF - 1 byte
    
    
    
      if ((mrr>=$80) && (mrr<=$BF)) || ((mrr>=$E0) && (mrr<=$EF)) 
        mb:=2
        midireport:=mrr<<24
    
      if (mrr>=$C0) && (mrr<=$DF)
        mb:=1
        midireport:=mrr<<24
    
      if (mrr>=$F0) 'TODO: do something with SYSEX, now a workaround for Novation Impulse
        mb:=4
        midireport:=mrr<<24  
    
      if (mrr<$80) && (mb>0)
    
        mb--
        if mb<3
          midireport+=mrr<<(mb<<3)
    
      if mb==0
    
        if midifront<>((miditail-1) //32)
          midibuf[midifront]:=midireport
          midifront+=1
          midifront:=midifront // 32
        mb:=(-1)
    
    'Keyboard and mouse
    
      if (rr>=$80) && (rr<>$FF)
        b:=3
        kbmreport:=rr<<24
    
      if (rr<$80) && (b>0)
        b--
        kbmreport+=rr<<(b<<3)  
    
      if (rr==$FF)
        b:=0   
    
      if b==0  
    
        if (kbmreport +>= $80000000) && (kbmreport +< $87000000)  'mouse
          if mousefront<>((mousetail-1) //128)
            mousebuf[mousefront]:=kbmreport
            mousefront+=1
            mousefront:=mousefront // 128
        b:=(-1)
    
        if (kbmreport +>= $87000000) && (kbmreport +< $8a000000)  'keyboard
          if kbdfront<>((kbdtail-1) //32)
            kbdbuf[kbdfront]:=kbmreport
            kbdfront+=1
            kbdfront:=kbdfront // 32
        b:=(-1)
    
    
      if long[$30]==0
        if kbdfront<>kbdtail
          long[$30]:=kbdbuf[kbdtail]
          kbdtail++
          kbdtail:= kbdtail // 32
    
      if long[$34]==0
        if mousefront<>mousetail
          long[$34]:=mousebuf[mousetail]
          mousetail++
          mousetail:= mousetail // 128
    
    
      if long[$38]==0
        if midifront<>miditail
          long[$38]:=midibuf[miditail]
          miditail++
          miditail:= miditail // 32
    
    
    ''---------------------- Serial functions from jm_serial.spin2, modified
    
    pub serial_start(rxpin, txpin, baud) | bitmode
    
    bitmode := muldiv64(clkfreq, $1_0000, baud) & $FFFFFC00       ' set bit timing
    bitmode |= 7                                                  ' set bits (8)
    pinstart(rxpin,P_HIGH_15K|P_ASYNC_RX,bitmode,0)
    pinstart(txpin,P_ASYNC_TX|P_OE,bitmode,0)
    pinhigh(rxpin)
    
    pub rxcheck(pin) : rxbyte | check
    
    '' Check for serial input
    '' -- returns -1 if nothing available
    
      rxbyte := -1
      check := pinr(pin)
      if (check)
        rxbyte := rdpin(pin) >> 24
    
    pub tx(pin,b)
    
    '' Emit byte
    
      wypin(pin, b)
      txflush(pin)
    
    pub txflush(pin) | check
    
    '' Wait until last byte has finished
    
      repeat
        check := pinr(pin)
      while (check == 0)
    
  • Pic33, that looks good.
    I just have to see how I do it with PASM.

    I will leave the (lmm) part in for debugging.

    I will use a new interface for the console in/out of the CP/M bios.

  • pik33pik33 Posts: 2,350

    I added today the standard serial pin p63 as 4th input source to the code (and removed a bug) - I wanted to do this in PASM first, but the spin is fast enough. Maybe this code will be rewritten in Pasm as I want more input sources to receive data (I want to connect analog and digital joystick to the P2)

  • pic18f2550pic18f2550 Posts: 392
    edited 2022-01-03 10:48

    I pulled out the important part and this is what comes out:

    ''==============================================================================
    '' Echo
    ''==============================================================================
    CON
      _clkfreq = 256_000_000
    
      srxpin=32
      stxpin=31
      sbaudrate=1000000
    
    pub start()| srr
      serial_start(srxpin,stxpin,sbaudrate)
      repeat
        if srr>=rxcheck(srxpin)
          tx(stxpin,srr)
    
    PRI serial_start(rxpin, txpin, baud) | bitmode
      bitmode := muldiv64(clkfreq, $1_0000, baud) & $FFFFFC00 '' set bit timing
      bitmode |= 7                                            '' set bits (8)
      pinstart(rxpin,P_HIGH_15K|P_ASYNC_RX,bitmode,0)
      pinstart(txpin,P_ASYNC_TX|P_OE,bitmode,0)
      pinhigh(rxpin)                                          ''activate
    
    PRI rxcheck(pin) : rxbyte '' Check for serial input, returns -1 if nothing available
      rxbyte := -1
      if pinr(pin)
        rxbyte := rdpin(pin) >> 24
    
    PRI tx(pin,b) '' Send a byte and Wait until last byte has finished
      wypin(pin, b)
      repeat
      while (pinr(pin) == 0)
    

    Now I still have to test it and convert it into PASM.

  • pic18f2550pic18f2550 Posts: 392
    edited 2022-01-03 16:31
    {{
      %0000_0000_000_0000000000000_00_11110_0               P_ASYNC_TX              Asynchronous serial transmit
      %0000_0000_000_0000000000000_01_00000_0               P_OE                    Enable output in smart pin mode
    
      %0000_0000_000_0000000000000_00_11111_0               P_ASYNC_RX              Asynchronous serial receive
      %0000_0000_000_0000000010000_00_00000_0               P_HIGH_15K              Drive high 15k
    }}
    
    CON
      _clkfreq = 256_000_000
    
    CON
      TX_PIN          = 31                                                          '' P31 serial input
      RX_PIN          = 32                                                          '' P32 serial out
      txmode        = P_ASYNC_TX | P_OE                                             '' async tx mode
      rxmode        = P_ASYNC_RX | P_HIGH_15K                                       '' async rx mode
      sclk          = ( _clkfreq / 1_000_000 )                                      '' bit rate 1MBit
      bitper        = (( sclk << 16 ) & $FFFFFC00 ) + ( 32 - 1 )                    '' bit rate & bits
    
    DAT
                  org       0
                  asmclk
    
                  wrpin     ##rxmode, #RX_PIN                                       '' Smart Pin async receive mode
                  wxpin     ##bitper, #RX_PIN                                       '' receive period for 8 bits
                  dirh      #RX_PIN                                                 '' enable Smart Pin rcvr
    
                  wrpin     ##txmode, #TX_PIN                                       '' Smart Pin async transmit mode
                  wxpin     ##bitper, #TX_PIN                                       '' transmit period for 32 bits
                  dirh      #TX_PIN                                                 '' enable Smart Pin tx
                  nop
    
    .next
    .rcvr '' wait for data
                  testp     #RX_PIN               wc                                '' test flag
            if_nc jmp       #.rcvr                                                  '' no flag, no data
                  rdpin     data_1, #RX_PIN                                         '' RX
    
    .tcvr '' wait for ready
                  testp     #TX_PIN               wc                                '' test flag
            if_c  jmp       #.tcvr                                                  '' is flag, no ready
                  wypin     data_1, #TX_PIN                                         '' TX
    
                  jmp       #.next                                                  
    
    data_1        long 0                                                            '' data saved here
    

    I hope I have the TX status query right.
    I don't have a P2 at hand, so it's all theory.

  • pik33pik33 Posts: 2,350

    Remember to enable output for TX (the or P_OE bit in spin, there is a particular bit# to set)

    The input pin (RX) is normally floating. If the signal source is on the same board, it is OK, but if there is a long cable between the source and P2, trash happens. This is why there is this P_HIGH_15K and pinhigh in my code. This enables 15k pullup which magically removed these interferences.

  • pic33,
    i have adjusted the code in #10 a little.

    Thanks

  • Sending and receiving works.

    I want to check whether the smart pin has sent the old byte before sending.
    But that doesn't work somehow.
    I don't want to wait after each byte until the byte has been sent.

  • :smile:

    .tcvr '' wait for ready
                  rdpin     tmp,#TX_PIN               wc                                '' test flag
            if_c  jmp       #.tcvr                                                  '' is flag, no ready
                  wypin     data_1, #TX_PIN                                         '' TX
    
    
Sign In or Register to comment.