Shop Learn
Using FullDuplexSerial to receive data via USB — Parallax Forums

Using FullDuplexSerial to receive data via USB

ZachSZachS Posts: 27
edited 2021-06-25 13:42 in Propeller 1

Hi everyone,

I'm trying to write a program for the P1 that will allow the P1 to receive serial data via the USB port from a python program being run on the connected computer. The purpose is to broaden the functionality of automated testing that is typically done with a python program using pyserial. So I'm essentially trying to get the P1 to act like a bit whacker/banger. I'm currently using FullDuplexSerial but am having some trouble with it.

The code I'm using is below. I'll keep researching/experimenting, but if anyone has suggestions, I'd appreciate it.

Thanks,

Zach

CON

    _clkmode = xtal1 + pll16x
    _xinfreq = 5_000_000

    RST          = 15         'OLED pins
    DC           = 16
    CS           = 17
    CLK_oled     = 18
    DIN          = 19

    clk_enc      = 28         'Encoder pins
    dt           = 29
    btn          = 11


    LED0         = 3          'pins
    LED1         = 4
    LED2         = 5
    LED3         = 6
    LED4         = 7
    LED5         = 8
    LED6         = 9
    LED7         = 10

    Rx           = 31        'Serial pins
    Tx           = 30

    LE           = 2         'latch pin

    CLK_FREQ = (_clkmode >> 6) * _xinfreq
    MS_001   = CLK_FREQ / 1_000

    'USB is on COM3

OBJ

  serial        : "FullDuplexSerial"

VAR

  long  Data
  long  DataX

PUB Main

  serial.Start(Rx, Tx, %0000, 9600)

  repeat
    Data := serial.Rx
    ifnot DataX == Data
      outa[LED0] := (Data & %00000001)
      outa[LED1] := (Data & %00000010) >> 1
      outa[LED2] := (Data & %00000100) >> 2
      outa[LED3] := (Data & %00001000) >> 3
      outa[LED4] := (Data & %00010000) >> 4
      outa[LED5] := (Data & %00100000) >> 5
      outa[LED6] := (Data & %01000000) >> 6
      outa[LED7] := (Data & %10000000) >> 7

   DataX := Data

Comments

  • JonnyMacJonnyMac Posts: 7,649
    edited 2021-06-25 15:11

    The problem is not with FDS. I used FDS on a Propeller board that was communicating with the PC via PySerial for a TV commercial several years ago. It worked fine.

  • Zach,

    Grabbing raw data seems simple at first, But due to the litany of problems I have encountered over the years and different systems, I always use a simple protocol that avoids bytes that various systems and serial implementations can choke on.

    It goes like this:

    Command to prop:
    :FF
    Where the colon lets my propeller program know there is real data in the string, Then the data in hex. It can be any length, as you seem to be using single bytes, I used two hex chars for 1 byte. Then followed by 13, (Return) so you can receive it like a string (Which it is...) Then convert the hex to a raw byte.

    I use a similar protocol for data in the other direction as well..

    Python can easily convert the data to/from hex, and I ripped off the hex converter from Parallax Serial Terminal for the propeller end.

    This has the advantage that if you use a serial terminal (Parallax Serial Terminal perhaps) to debug, it is easy to see what is happening.

  • @JonnyMac ,

    Thanks. My suspicion was that it was more likely an issue on my end (likely oversimplifying as @R Bagget is suggesting) as opposed to FullDuplexSerial. The python program I'm using I know works using a Bit Whacker from sparkfun. So I'm trying to use that same program to send that information (in this case binary 9) to the prop instead of the Bit Whacker and have the prop light up the LEDs that would correspond to that binary 9. Then the next step would be to tie those lines going to the LEDs to lines going to an RF component to drive its state. In this case, I'm loading the Spin program to EEPROM and then running the python program in the command prompt. The python program gets about as far as checking to make sure the com port is open ( the same com port that the prop is using) which it recognizes as being open, but then the python program seems to get stuck on the the section that configures the serial pins as outputs. I'm not sure if at this point there is some conflict between my python code and spin code that is holding things up. Any thoughts?

    @R Baggett,

    Thank you for that tip. That's also a good idea to take a look at how Parallax Serial Terminal handles that information. Could you send me an example so I can see what you're talking about in Spin?

    Thank you both,

    Zach

  • AribaAriba Posts: 2,494

    You need to set the LED pins to output first. This id done with the DIRA[] array.

    If the LEDs are contiguous like in your case, you can just write the whole byte to the pin group, no need to check the bits separatly:

    PUB Main
    
      serial.Start(Rx, Tx, %0000, 9600)
      dira[LED7..LED0] := %11111111
    
      repeat
        Data := serial.Rx
        ifnot DataX == Data
          outa[LED7..LED0] := Data
    
       DataX := Data
    

    Andy

  • Good morning @Ariba ,

    Thank you for pointing that out. I realized later that afternoon that there were a few small things like that I was missing. I fixed those but am still not getting the data coming over the serial port. My current code is posted below. I don't think it's an issue with my spin code. In using RxCheck from FDS, it's throwing a -1 and lighting the appropriate LED's to signal that there is no data coming through. So I'm now thinking that there may be an issue with my python code. The python code that I'm using to try and transfer the serial data works well with the JSB Bit Whacker (DEV-00762 from SparkFun), but I understand that they're using different chips that likely have different properties. I've tried a few other python code combinations to successfully transfer the data, but with no luck. I know this may not be kosher, but does anyone have a python code example that successfully transfers data over the serial port to the propeller?

    CON
    
        _clkmode = xtal1 + pll16x
        _xinfreq = 5_000_000
    
        RST          = 15         'OLED pins
        DC           = 16
        CS           = 17
        CLK_oled     = 18
        DIN          = 19
    
        clk_enc      = 28         'Encoder pins
        dt           = 29
        btn          = 11
    
    
        LED0         = 3          'pins
        LED1         = 4
        LED2         = 5
        LED3         = 6
        LED4         = 7
        LED5         = 8
        LED6         = 9
        LED7         = 10
    
        RxP           = 31        'Serial pins
        TxP           = 30
    
        LE           = 2         'latch pin
    
        CLK_FREQ = (_clkmode >> 6) * _xinfreq
        MS_001   = CLK_FREQ / 1_000
    
        'USB is on COM3
    
    OBJ
    
      serial        : "FullDuplexSerial"
      OLED          : "OLED_AsmFast v0.5 Driver"
      enk           : "jm_encoder_1x"
      sn            : "Simple_Numbers"
      misc          : "Misc_Methods"
      sserial       : "Simple_Serial"
    VAR
    
      long  Data
      long  DataX
      long  Decimal
    
    
    PUB Main
    
      OLED.Init(CS,DC,DIN,CLK_oled,RST)
      enk.Start(clk_enc, dt, btn, true, 1, 0, 127)
      serial.Start(RxP, TxP, %0000, 9600)
      sserial.init(31, 30, 9600)
      dira[LED7..LED0]~~
    
      OLED.AutoUpdateOff
      OLED.clearDisplay
    
      OLED.write1x6String(String("Bit"),3,15,0,OLED#Yellow,OLED#BLACK)
      OLED.write1x6String(String("Whack"),5,0,32,OLED#Yellow,OLED#BLACK)
      'misc.wait_for_state(btn, 0, 50)
      OLED.clearDisplay
      'misc.delay(100)
    
      repeat
        Data := serial.RxCheck
        Decimal := sn.decf(Data, 5)
        ifnot DataX == Data
          OLED.write1x6String(Decimal,5,0,0,OLED#Yellow,OLED#BLACK)
          outa[LED0] := (Data & %00000001)
          outa[LED1] := (Data & %00000010) >> 1
          outa[LED2] := (Data & %00000100) >> 2
          outa[LED3] := (Data & %00001000) >> 3
          outa[LED4] := (Data & %00010000) >> 4
          outa[LED5] := (Data & %00100000) >> 5
          outa[LED6] := (Data & %01000000) >> 6
          outa[LED7] := (Data & %10000000) >> 7
    
       DataX := Data
    

    Thanks,

    Zach

  • Hi everyone,

    I figured out what the issue was.

    Thank you for all of the help!

    Zach

  • JonnyMacJonnyMac Posts: 7,649

    You should probably share the solution so that others can learn from it.

  • Morning everyone,

    Below is the code that ended up working for me to turn the P1 into a bit whacker that is sent the necessary data by a python program using the USB serial com port. The code is very much adapted from the parser code used in the program prop_serial_slave_010.spin, which is used in chapter 10 of "Programming and Customizing the Multicore Propeller Microcontroller" book from Parallax (highly recommended for anyone that wants a thorough introduction into spin and the P1 chip). It took me some time to fully understand and appreciate what the parser program was doing, but once I did, I was able to adapt it into the program so that the spin program could properly receive and parse the string being sent by the python program for the data within the string. Once parsed, each character (separated by a comma/space) is assigned a token value. Then a specific character can be taken out of the received string using its assigned token value (which is a string). To then use the program as a bit whacker, that token needs to be converted to a decimal value (done using the StrToDec(stringptr) method) and then "separated out" so that the binary representation of the decimal value in question is outputted using the eight LED's and attached wires that go to the mythical connected part to change its state.

    Best,

    Zach

     CON
    
        _clkmode = xtal1 + pll16x
        _xinfreq = 5_000_000
        _stack   = 128                    ' accomodate display memory and stack
    
        CLK_FREQ = (_clkmode >> 6) * _xinfreq
        MS_001   = CLK_FREQ / 1_000
        CLOCKS_PER_MICROSECOND = _xinfreq / 1_000_000  ' used for delay function
    
        RST          = 11         'OLED pins
        DC           = 12
        CS           = 13
        CLK_oled     = 14
        DIN          = 15
    
        {{
        V            = 16         VGA pins
        H            = 17
        B1           = 18
        B0           = 19
        G1           = 20
        G0           = 21
        R1           = 22
        R0           = 23
        }}
    
        clk_enc      = 28         'Encoder pins
        dt           = 29
        btn          = 25
    
    
        LED0         = 3          'pins
        LED1         = 4
        LED2         = 5
        LED3         = 6
        LED4         = 7
        LED5         = 8
        LED6         = 9
        LED7         = 10
    
        RxP           = 31        'Serial pins
        TxP           = 30
    
        LE           = 2         'latch pin
    
        ' ASCII codes for ease of parser development
        ASCII_A       = 65
        ASCII_B       = 66
        ASCII_C       = 67
        ASCII_D       = 68
        ASCII_E       = 69
        ASCII_F       = 70
        ASCII_G       = 71
        ASCII_H       = 72
        ASCII_O       = 79
        ASCII_P       = 80
        ASCII_Z       = 90
        ASCII_0       = 48
        ASCII_9       = 57
        ASCII_BS     = 127 ' backspace
        ASCII_LF     = $0A ' line feed
        ASCII_CR     = $0D ' carriage return
        ASCII_ESC    = $1B ' escape
        ASCII_HEX    = $24 ' $ for hex
        ASCII_BIN    = $25 ' % for binary
        ASCII_LB     = $5B ' [
        ASCII_SEMI   = $3B ' ;
        ASCII_EQUALS = $3D ' =
        ASCII_PERIOD = $2E ' .
        ASCII_COMMA  = $2C ' ,
        ASCII_SHARP  = $23 ' #
        ASCII_NULL   = $00 ' null character
        ASCII_SPACE  = $20 ' space
        ASCII_COLON  = $3A ' Colon
    
        ' null pointer, null character
        NULL         = 0
    
    
    OBJ
    
      serial        : "FullDuplexserial_drv_012.spin"
      OLED          : "OLED_AsmFast v0.5 Driver"
      enk           : "jm_encoder_1x"
      sn            : "Simple_Numbers"
      misc          : "Misc_Methods"
    
    VAR
    
      long  Data
      long  DataX
      long  DataS
      long  Decimal
    
      long cogon, cog     ' ids for cogs
    
      byte input_buff[80]  ' storage for input buffer
      long input_buff_index  ' index into current position of command buffer
    
      byte tok_buff[80]    ' storage for token buffer during processing
      byte prompt[32]      ' storage for user prompt
      long tok_buff_index  ' index into current position of tokenbuffer
      long token_ptr       ' used to point to output token from tokenizer
      long tokens[ 16 ]    ' array of pointers to parsed tokens ready for processing
      long num_tokens      ' number of tokens in token array
    
      long cmd_token       ' a single command token
    
      long cmd_data_ptr    ' ptr to command token
      long cmd_parse_index ' index of command token in array
    
      long arg1, arg2, arg3, arg4 ' general parameters used during parameter extraction
    
      ' state vars for strtok_r function, basically static locals that we must define
      long strtok_string_ptr
      long strtok_string_index
      long strtok_string_length
      long Baud             ' Default 9600
    
    PUB Main | ch
    
      OLED.Init(CS,DC,DIN,CLK_oled,RST)
      enk.Start(clk_enc, dt, btn, true, 1, 0, 127)
      serial.Start(RxP, TxP, %0000, 9600)
    
      dira[LED7..LED0]~~
    
      OLED.AutoUpdateOff
      OLED.clearDisplay
    
    
    
      OLED.write1x6String(String("Bit"),3,15,0,OLED#Yellow,OLED#BLACK)
      OLED.write1x6String(String("Whack"),5,0,32,OLED#Yellow,OLED#BLACK)
    
      input_buff_index := -1
    
      repeat
    
        ' attempt to retrieve character from serial terminal
        ch := serial.rxcheck
    
        ' character ready in receive buffer?
        if (ch <> -1)
          ' process character, test for carriage return, or basic EDITing characters like back space
          case ch
    
            ASCII_LF, ASCII_CR: ' return
    
    
    
              ' print the buffer
              if (input_buff_index > -1)
                ' at this point we have the command buffer, so we can parse it
                ' copy it
                bytemove( @tok_buff, @input_buff, ++input_buff_index )
    
                ' null terminate it
                tok_buff[ input_buff_index ] := 0
                tok_buff_index := input_buff_index
    
                ' reset buffer
                input_buff_index := -1
    
                ' tokenize input string
                num_tokens := 0
    
                ' start the tokenization of the string (this function mimics the C strtok_r function more or less
                strtok_r(@tok_buff, string(","), @token_ptr)
    
                ' continue tokenization process now that first token has been found
                repeat while (token_ptr <> NULL)
                  ' upcase the token before insertion
                  StrUpper( token_ptr )
    
                  ' insert token into token array
                  tokens[ num_tokens++ ] := token_ptr
    
    
                  ' get next token
                  strtok_r( NULL, string(","), @token_ptr)
    
               ' end repeat tokenization...
    
                ' // end if buffer valid
    
                ' // Now process command in large if, elseif, else chain
                ' each "if" attempts to process a different command, if no
                ' command is found then user typed it wrong or its not supported
                ' and an error is emmited. Each command passes parameters to the COG
                ' running the specific driver being requested; NTSC, VGA, etc.
                ' the full functionality of each driver is NOT exposed, only a subset to
                ' illustrate the idea of use the Prop as a slave processor controlled by a
                ' serial communications stream in ASCII...
                {{
                First process "local" client commands for terminal. These include
                requests to the terminal such as clear the screen, help, etc.
                The remaining commands are "remote commands" that are processed and
                then issued to the "worker" cores running the respective drivers for
                video, vga, audio, etc.
                }}
                ' clear the terminal screen command
                if ( strcomp( tokens[0], string("C") ) )
                    serial.txstringnl( string("OK"))
                    OLED.clearDisplay
                    OLED.write1x6String(string("OK"),2,15,0,OLED#Yellow,OLED#BLACK)
    
    
                elseif ( strcomp( tokens[0], string("O") ))
                    serial.txstringnl( string("OK"))
                    DataS := ( tokens[2] )
                    Data := StrToDec(DataS)
                    Decimal := sn.decf(Data, 5)
                    ifnot DataX == Data
                      OLED.write1x6String(Decimal,5,0,0,OLED#Yellow,OLED#BLACK)
                      outa[LED0] := (Data & %00000001)
                      outa[LED1] := (Data & %00000010) >> 1
                      outa[LED2] := (Data & %00000100) >> 2
                      outa[LED3] := (Data & %00001000) >> 3
                      outa[LED4] := (Data & %00010000) >> 4
                      outa[LED5] := (Data & %00100000) >> 5
                      outa[LED6] := (Data & %01000000) >> 6
                      outa[LED7] := (Data & %10000000) >> 7
    
    
    
    
    
              ' print prompt
             serial.txstring( @prompt )
    
            ' editing commands, for now just backspace, later you could add more advanced terminal based editing
            ' but the trick is to keep the buffer on the client side sync'ed with the terminal's display!
           ASCII_BS:      ' backspace
              ' insert null
               if (input_buff_index => 0)
                input_buff[ input_buff_index-- ] := ASCII_NULL
    
                ' echo character
                serial.tx( ch )
    
           other:
              ' insert character into command buffer for processing
              input_buff[ ++input_buff_index ] := ch
    
              ' echo character to terminal (terminal must be in non ECHO mode, otherwise you will see input 2x!)
              'serial.tx( ch )
    
        DataX := Data
    
    
    
    
    
    
    
    
    '//////////////////////////////////////////////////////////////////////////////
    'FUNCTIONS SECTION ////////////////////////////////////////////////////////////
    '//////////////////////////////////////////////////////////////////////////////
    PUB StrToDec(stringptr) : value | char, index, multiply
    
        '' Converts a zero terminated string representation of a decimal number to a value
    
        value := index := 0
        repeat until ((char := byte[stringptr][index++]) == 0)
           if char => "0" and char =< "9"
              value := value * 10 + (char - "0")
        if byte[stringptr] == "-"
           value := - value
    
    
    PUB HexToDec(n)
    ' converts hex digit to decimal
      if ( (n => "0") and (n =< "9") )
        return (n - ASCII_0)
      elseif ( (n => "A") and (n =< "F") )
        return (n - "A" + 10)
      else
        return ( 0 )
    
    ' /////////////////////////////////////////////////////////////////////////////
    
    PUB atoi2(string_ptr) | index, sum, ch
    ' this function tries to convert the string to a number, supports binary %, hex $, decimal (default)
    ' Eg. %001010110, $EF, 25
    
      ' initialize vars
      index := 0
      sum   := 0
    
      ' try to determine number base
      if (byte [string_ptr][index] == ASCII_HEX)
        repeat while ( (ch := byte [string_ptr][index]) <> 0)
          sum := (sum << 4) + HexToDec( ToUpper(ch) )
          index++
    
        return(sum)
      ' // end if hex number
      elseif (byte [string_ptr][index] == ASCII_BIN)
        repeat while ( (ch := byte [ string_ptr ][index]) <> 0)
          sum := (sum << 1) + (ch - ASCII_0)
          index++
    
        return(sum)
      ' // end if binary number
      else
        ' must be in default base 10, assume that
        repeat while ( (ch := byte [ string_ptr ][index]) <> 0)
          sum := (sum * 10) + (ch - ASCII_0)
          index++
    
        return(sum)
    
      ' else, have no idea of number format!
      return(0)
    
    ' /////////////////////////////////////////////////////////////////////////////
    
    PUB strtok_r(string_ptr, delimeters_ptr, token_ptr2)
    {{
    ' this function mimics the functionality of the C library strtok_r(...) function
    ' the function is first called with a pointer to string that the caller wants
    ' tokenized in string_ptr, then during remaining calls string_ptr is sell to NULL
    ' as the string is tokenized. Other than that, the 1st and remaining calls always
    ' require delimeters_ptr to point to a string with single character delimeters that
    ' the caller wants to be used to seperate token, eg. ",:" would use comma, colon and
    ' white space (always included), finally as tokens are located NULLs are placed at the
    ' terminus of each token and token_ptr2 is pointed to the head of the token string
    
    Example:
    
    1st Call:
    string_ptr -> "This is a test 10,20"
    delimeters_ptr -> ","
    
    token_ptr2 -> "This"
    string_ptr -> "ThisNULLis a test 10,20"
    
    2nd Call:
    string_ptr -> NULL
    delimeters_ptr -> ","
    
    token_ptr2 -> "is"
    string_ptr -> "ThisNULLisNULLa test 10,20"
    
    3rd Call:
    string_ptr -> NULL
    delimeters_ptr -> ","
    
    token_ptr2 -> "a"
    string_ptr -> "ThisNULLisNULLaNULLtest 10,20"
    
    4th Call:
    string_ptr -> NULL
    delimeters_ptr -> ","
    
    token_ptr2 -> "test"
    string_ptr -> "ThisNULLisNULLaNULLtestNULL10,20"
    
    5th Call:
    string_ptr -> NULL
    delimeters_ptr -> ","
    
    token_ptr2 -> "10"
    string_ptr -> "ThisNULLisNULLaNULLtestNULL10NULL20"
    
    6th Call:
    string_ptr -> NULL
    delimeters_ptr -> ","
    
    token_ptr2 -> "20"
    string_ptr -> "ThisNULLisNULLaNULLtestNULL10NULL20NULL"
    
    7th Call:
    string_ptr -> NULL
    delimeters_ptr -> ","
    
    token_ptr2 -> NULL
    string_ptr -> "ThisNULLisNULLaNULLtestNULL10NULL20NULL"
    }}
    
      ' test if this is first call
      if (string_ptr <> NULL)
        ' initialize tokenizer
        strtok_string_ptr := string_ptr
        strtok_string_length := strsize ( strtok_string_ptr )
    
      ' else nth call, continue using global string, do not re-init it
    
      ' initialize index into string to head
      strtok_string_index := 0
    
      ' consume white space and delimeters
      repeat while ( (IsSpace(byte[strtok_string_ptr][strtok_string_index]) <> -1) or (IsInSet( byte[strtok_string_ptr][strtok_string_index], delimeters_ptr ) <> -1) )
        strtok_string_index++
        strtok_string_length--
    
      ' has string been consumed?
      if (strtok_string_length =< 0)
        ' we are done, return NULL to pointers ,exit
        long [ token_ptr2 ] := 0
        return( 0 )
    
      ' adjust strtok_string_ptr to point to head of token
      strtok_string_ptr += strtok_string_index
    
      ' reset strtok_string_index to 0
      strtok_string_index := 0
    
      ' consume alpha num
      repeat while ( (IsInSet( byte[strtok_string_ptr][strtok_string_index], delimeters_ptr ) == -1) and ((IsAlpha(byte[strtok_string_ptr][strtok_string_index]) <> -1) or (IsDigit(byte[strtok_string_ptr][strtok_string_index]) <> -1) or (IsPunc(byte[strtok_string_ptr][strtok_string_index]) <> -1)) )
        strtok_string_index++
        strtok_string_length--
    
      ' at this point we have the token, ready to return
    
      ' NULL terminate
      byte[strtok_string_ptr][strtok_string_index] := 0
    
      ' write pointer out to input ptr
      long [ token_ptr2 ] := strtok_string_ptr
    
      ' save strtok_string_ptr
      string_ptr := strtok_string_ptr
    
      ' now adjust strok_string_ptr AFTER the token, so that on next call its ready to read next token (if there is one)
      strtok_string_ptr    += (strtok_string_index+1)
      strtok_string_length--
    
      ' return address of string token
      return( string_ptr )
    
    ' /////////////////////////////////////////////////////////////////////////////
    
    PUB StrUpper(string_ptr)
    ' upcases a string
      if (string_ptr <> NULL)
        repeat while (byte[ string_ptr ] <> NULL)
          byte[ string_ptr ] :=  ToUpper( byte[ string_ptr ] )
          string_ptr++
    
      ' return string
      return (string_ptr)
    
    ' /////////////////////////////////////////////////////////////////////////////
    
    PUB ToUpper(ch)
    ' returns the uppercase of the sent character
    if (ch => $61 and ch =< $7A)
      return(ch-32)
    else
      return(ch)
    
    ' /////////////////////////////////////////////////////////////////////////////
    
    PUB IsInSet(ch, set_string)
    ' tests if sent character is in string
    
    repeat while (byte[set_string][0] <> NULL)
      if (ch == byte[set_string++][0])
        'serial.txstring(string ("found!") )
        return( ch )
    
    'serial.txstring(string ("not found!") )
    ' not found
    return( -1 )
    
    ' /////////////////////////////////////////////////////////////////////////////
    
    PUB IsSpace(ch)
    ' tests if sent character is white space, cr, lf, space, tab
    if (ch == ASCII_SPACE)
      return (ch)
    else
      return(-1)
    
    ' /////////////////////////////////////////////////////////////////////////////
    
    PUB IsDigit(ch)
    ' tests if sent character is a number 0..9, returns integer 0..9
    if (ch => ASCII_0 and ch =< ASCII_9)
      return (ch-ASCII_0)
    else
      return(-1)
    
    ' /////////////////////////////////////////////////////////////////////////////
    
    PUB IsAlpha(ch)
    ' tests if sent character is a number a...zA...Z
    ch := ToUpper(ch)
    
    if ( (ch => ASCII_A) and (ch =< ASCII_Z))
      return (ch)
    else
      return(-1)
    
    ' /////////////////////////////////////////////////////////////////////////////
    
    PUB IsPunc(ch)
    ' tests if sent character is a punctuation symbol !@#$%^&*()--+={}[]|\;:'",<.>/?
    ch := ToUpper(ch)
    
    if (  ((ch => 33) and (ch =< 47)) or  ((ch => 58) and (ch =< 64)) or ((ch => 91) and (ch =< 96)) or ((ch =>123) and (ch =< 126))  )
      return (ch)
    else
      return(-1)
    
    '//////////////////////////////////////////////////////////////////////////////
    
    PUB Delay( time_us )
    ' delays time sent in microseconds
      waitcnt ( CNT + time_us * CLOCKS_PER_MICROSECOND )
    
      ' return current count after delay
      return( CNT )
    
  • I do have a question about the sharing of the serial com port.

    My steps for running the above program are: load the program into EEPROM, start the python program in Windows command prompt, and then increment the python program forward. When the python program gets to its ser.open() function though it causes a restart event for the P1. I'm pretty sure that this is related to FDS, but does anyone know of a way around that restart event?

    Thanks,

    Zach

  • msrobotsmsrobots Posts: 3,419

    well - old problem. That is the way P1 handles programming.

    Opening/closing a port in windows toggles DTR and resets the prop.
    Putting something into a USB port on the computer re-enumerates the USB devices and toggles DTR and resets the Prop.
    Even sending serial data from the P1 to the USB chip without having anything connected to the USB chip fires up the USB chip and resets the Prop.

    The only solution I know of is to physically cut the trace between the USB chip and the propeller reset and put a jumper there to enable/disable reset on the P1.

    Sadly

    Mike

  • This all sounds incredibly complicated. On the P2, from the PC, I think you can just write a forth command and the P2 Taqoz interpreter will respond to it. And Taqoz can write to the terminal, and presumably Python can read it as a string.
    Of course I have not yet done this, I am sure it will be more difficult than I expect. The devil is in the details.
    Chris

  • msrobotsmsrobots Posts: 3,419

    It has nothing to do with taqoz or python. It is just the way programming the propeller is done.

    Most of Parallax p1 or p2 boards have build in USB chips hardwired to the reset of the propellers and will reset when windows opens or closes a serial port.

    It is by design. The only exception currently is the EDGE board, it does not have build in USB and you can use a prop plug with a small 3 pin header in between leaving the connection to reset disconnected.

    Else it will hit you.

    Mike

  • Thank you for the comments on the USB port/chip and reset relationship. I'll keep that in mind for the future.

    Zach

  • The easiest (but not ideal) solution is to put a pull-up resistor on the Prop's TX pin. That will keep the USB chip powered parasitically whenever the Prop is powered, thus avoiding the resets when the program raises the TX pin.

    -Phil

  • WOW.

    And I foolishly thought that if the board has a usb plug on it, just plug in and go.
    Thank you guys.
    Chris

  • From the Eval Board Rev C Document:

    USB RES is on the dip switch, which enables the user to disconnect the USB reset (DTR) signal from the Propeller RESn pin.

    I think that means that I can connect with a usb cable to the upper right of the eval board, and it will not reboot every time. Is that correct?

  • msrobotsmsrobots Posts: 3,419

    yes.

    And on Rev C you can also use the small adapter board and the WiFi module when that switch is off.

    Mike

Sign In or Register to comment.