Shop OBEX P1 Docs P2 Docs Learn Events
Propeller to Propeller comunication — Parallax Forums

Propeller to Propeller comunication

Dear All,

Another week, another discussion of me not understanding how to make my Activity Boards to work as intended.

I want to make two Propellers, embedded in their respective Activity Boards, communicate to each other, i.e. exchange at a rate of 50-500 KHz, one long variable.

Specifically, I am using the modified code attached below (microphone_to_headphone_2_cogs.spin), that uses one cog to do A/D conversion, stores the result in a long in the hub and there it can be taken by another cog , D/A converted and output to the jack. I would like now two split the process between two Propellers: one does A/D, stores the audio signal as a long in the hub, the signal is then sent to another Propeller to D/A converted and output again.

I am trying to figure out how I can correctly address the serial communication between Propellers.

My first thought was to use the PropBus object (https://github.com/parallaxinc/propeller/tree/master/libraries/community/p1/All/PropBus, Single wire multi-propeller comm link), with a one wire configuration with 100k pull up resistances as the author of the object suggests (attached also the two objects I am loading to the two different Propeller Activity Boards to try to make it work, RT is the mic Propeller and BC the headphone one), but I can't make it work and do not get any results.

Has anyone any experience with communication between Propellers? Can someone suggest me the best serial communication to make it work and point me to some objects that can be used to make two Propellers communicate with each other, or shed some light on why I can't make the PropBus work and how to make use of it correctly?

I don't need much complication, just to send the long variable in full at the rate of 50-500kHz.

Domenico

Comments

  • Christof Eb.Christof Eb. Posts: 1,131
    edited 2023-09-29 04:41

    Hi,
    Can't you just split the long into 4 bytes and send them over serial? No bus, just one line plus gnd.
    Edit perhaps 2 bytes are sufficient?!
    Christof

  • I did give some thought about it, splitting my "long signal_hub" in another variable "byte serial[4]", something like:

    serial[0]:=byte[@signal_hub][0]
    ...
    serial[3]:=byte[@signal_hub][3]

    but then which object/serial communication do you suggest to use to send them over to the other propeller? And once they are there how would I put them together? I looked in the manual but could not really find a method to paste for bytes in a long, I am a really new when it comes to spin.

    Domenico

  • Since you're not doing full-duplex you could use unrolled (high-speed) serial drivers on either end.

    Transmit your long

      serial.tx(signalOut.byte[0])
      serial.tx(signalOut.byte[1])
      serial.tx(signalOut.byte[2])
      serial.tx(signalOut.byte[3])
    

    Receive on the other side:

      signalIn.byte[0] := serial.rx
      signalIn.byte[1] := serial.rx
      signalIn.byte[2] := serial.rx
      signalIn.byte[3] := serial.rx
    

    Easy-peasy, lemon-squeezey

  • Hi> @domeniv97 said:

    I don't need much complication, just to send the long variable in full at the rate of 50-500kHz.

    Domenico

    Hi, once again,
    do you really need to transfer a long=32bits? - The reason I ask, is that the ADC of P1 has about 11bits signal to noise ratio. This means, that there is no advantage to transfer more than 12bits of audio data. If you send 16bits instead of 32, you can still use 4 bits for other information.

    If the project is about transmission of speech, than about 7 bits will be enough to have it be clearly understandable. As the important frequencies for speech are less than 2kHz, a sample frequency of perhaps 6kHz will sufficient for speech. So for speech, one byte at a rate of 6000 Bytes/sec will be sufficient, without complicated encoding methods. You only have to make sure that the scale of 7 bits are really used by the modulation amplitude, which can be achieved by an hardware audio compressor or also in software.

    So it might be possible to reduce the data rate from "1long per 50kHz...500kHz" = 200.000..2000.000Bytes/s to something like 6.000Bytes/s. Which will make the transmission and also the processing very much more easy. Often such considerations decide, whether a project is feasible or not. I have heavy doubts, that it is possible to process 4*50kBytes/sec using SPIN.

    Some other thoughts: If you have to do audio processing, than speed is very important. This means that interpreted SPIN will often have to be combined with assembler, which means, that you have to learn 2 languages. So it might be well worth to have a look at the compiled languages for P1. The downside of the compiled languages are, that they need much more code space, which is rather restricted. (Myself I do like to use Tachyon (Taqoz) Forth for the Propellers as Forth is the best compromise between speed and code density and makes experimenting fun. I know, that Forth is often seen as weird, so perhaps you will not fall in love with it.... :-) )

    About the access of bytes as part of longs in SPIN. The manual for P1 is really good:
    https://www.parallax.com/package/propeller-manual/

    Good luck, Christof

  • AribaAriba Posts: 2,685

    Yes Spin on the Propeller 1 is quite slow. It's better to do anything in PASM, especially with your project, you have enough free time in the ADC and DAC cogs to do also the communication in the same cog.

    The simplest is Async Serial, this needs just one data transmit/receive pin, without a clock pin, and without a sample rate sync pin.
    Async Serial just adds a start- and a stopbit to allow to detect the begin of a dataword, the databits are sent with a fixed bitrate which bith the transmitter and the receiver need to know.

    Here are two PASM subroutines for sending and receiving data-words up to 30 bits (start and stopbits have also to fit in the same 32bit register).
    It defaults to 13 bits data size. Baudrate is 4 Mbit/s, so transmitting one sample takes 3.75 us - good for sample rates up to 250 kHz.

    '-------------------------
    ' ASYNC transmitter
    con
      TX_BITS  = 15     'startbit(High) + 13 databits + stopbit(Low)  max 30 databits
      TX_PIN   = 8
    
    dat
     ...
    asyncTx      shl     txd, #1               'data in txd, add startbit (High)
                 or      txd, #1
                 mov     tbits, #TX_BITS       'startbit + n databits + stopbit (Low)
    :loop        shr     txd, #1  wc           'shift out, LSB first
                 muxc    OUTA, txmask          'to TX pin
                 nop                           'some delay
                 nop
                 djnz    tbits, #:loop         'next bit    4+4+4+4+4 = 20 cy = 4 Mbits/s @80Mhz sysclk
    asyncTx_ret  ret
    
    txd          long    0                     'data to transmit
    tbits        long    0
    txmask       long    1 << TX_PIN
    
    
    '-------------------------
    ' ASYNC receiver
    con
      RX_BITS  = 15
      RX_PIN   = 9
    
    dat
     ...
    asyncRx      mov     rbits, #RX_BITS
    :wait        test    rxmask, INA  wz      'wait for startbit (High)
      if_z       jmp     #:wait               '8..11 cy delay (~= middle of startbit)
    :loop        test    rxmsk, INA  wc       'read bits in
                 rcr     rxd, #1              'shift in (to bit31 downwards)
                 nop
                 nop
                 djnz    rbits, #:loop        '20 cy loop
                 shr     rxd, #32-RX_BITS+1   'right align rxd
    asyncRx_ret  ret
    
    rxd          long    0                    'received data
    rbits        long    0
    rxmask       long    1 << RX_PIN
    

    In your ADC and DAC cog, you don't need to communicate with the Spin variables, this makes it simpler:

    The ADC cog defines the sample rate depending on the chosen bit size. On every ADC loop there is plenty of time to also send the data with AsncTx subroutine:

    adc_entry     
                mov       dira,adc_dira                   'make pins 8 (ADC) and 0 (DAC) outputs
                movs      ctra,#ADCIN                     'POS W/FEEDBACK mode for CTRA
                movd      ctra,#ADCFB
                movi      ctra,#%01001_000
                mov       frqa,#1
                mov       adc_cnt,cnt                     'prepare for WAITCNT loop
                add       adc_cnt,adc_cycles
    :adc_loop   waitcnt   adc_cnt,adc_cycles              'wait for samle periode
                call      #adc
                mov       txd,pcm_sample
                call      #asyncTx                        'send adc data each sample periode
                jmp       #:adc_loop
    
    adc         mov       pcm_sample,phsa                 'capture PHSA and get difference
                sub       pcm_sample,pcm_old
                add       pcm_old,pcm_sample
    adc_ret     ret
    
    asyncTx     see above
    

    The DAC cog needs to synchronize to the received data anyway for receiving, so this also gives also the sample rate:

    dac_entry     
                mov       dira,dac_dira                   'make pins 8 (ADC) and 0 (DAC) outputs
                movs      ctrb,#DAC_L                     'DUTY DIFFERENTIAL mode for CTRB
                movd      ctrb,#DAC_R
                movi      ctrb,#%00111_000
    :dac_loop   call      #asyncRx                        'receive sample (synchronized to transmitters sample rate)
                mov       dac_sample,rxd
                call      #dac
                jmp       #:dac_loop
    
    dac
                shl       dac_sample,#32-bits             'justify sample and output to FRQB
                mov       frqb,dac_sample
    dac_ret ret
    
    asyncRX     see above
    

    For sure this is not a working code, only snippets, and all is untested...

    Andy

  • @JonnyMac said:
    Since you're not doing full-duplex you could use unrolled (high-speed) serial drivers on either end.

    Transmit your long

      serial.tx(signalOut.byte[0])
      serial.tx(signalOut.byte[1])
      serial.tx(signalOut.byte[2])
      serial.tx(signalOut.byte[3])
    

    Receive on the other side:

      signalIn.byte[0] := serial.rx
      signalIn.byte[1] := serial.rx
      signalIn.byte[2] := serial.rx
      signalIn.byte[3] := serial.rx
    

    Thanks, I fairly understand the snippets and the code that you sent, but can't assure myself on how it functions: like this it seems to me that I will have to synchronize the two chips so that when signalOut.byte[0] goes out, the other chip expects to receive it and thus is waiting with a SignalIn.byte[0] inside a repeat or something of that sort, and the same for signalOut.byte[1], SignalIn.byte[1] and so forth, am I understanding it wrong? Because otherwise I can encounter the risk of bytes being read more than once or missed.

    Domenico

  • @Ariba said:
    Yes Spin on the Propeller 1 is quite slow. It's better to do anything in PASM, especially with your project, you have enough free time in the ADC and DAC cogs to do also the communication in the same cog.

    The simplest is Async Serial, this needs just one data transmit/receive pin, without a clock pin, and without a sample rate sync pin.
    Async Serial just adds a start- and a stopbit to allow to detect the begin of a dataword, the databits are sent with a fixed bitrate which bith the transmitter and the receiver need to know.

    Here are two PASM subroutines for sending and receiving data-words up to 30 bits (start and stopbits have also to fit in the same 32bit register).
    It defaults to 13 bits data size. Baudrate is 4 Mbit/s, so transmitting one sample takes 3.75 us - good for sample rates up to 250 kHz.
    For sure this is not a working code, only snippets, and all is untested...

    Andy

    Thanks as always Andy, I will have a look at the PASM and try to modify the code according to your routines and suggestions! I hope like this it will work well.

    I had some worries on touching the ADC and DAC routines because, I do not clearly understand how the bits saving in the counter worked, since it seemed that the ADC counter mode saves them in the last n bits of the counter while the DAC wants them in the first n bits.

  • @"Christof Eb." said:
    Hi> @domeniv97 said:

    I don't need much complication, just to send the long variable in full at the rate of 50-500kHz.

    Domenico

    Hi, once again,
    do you really need to transfer a long=32bits? - The reason I ask, is that the ADC of P1 has about 11bits signal to noise ratio. This means, that there is no advantage to transfer more than 12bits of audio data. If you send 16bits instead of 32, you can still use 4 bits for other information.

    If the project is about transmission of speech, than about 7 bits will be enough to have it be clearly understandable. As the important frequencies for speech are less than 2kHz, a sample frequency of perhaps 6kHz will sufficient for speech. So for speech, one byte at a rate of 6000 Bytes/sec will be sufficient, without complicated encoding methods. You only have to make sure that the scale of 7 bits are really used by the modulation amplitude, which can be achieved by an hardware audio compressor or also in software.

    So it might be possible to reduce the data rate from "1long per 50kHz...500kHz" = 200.000..2000.000Bytes/s to something like 6.000Bytes/s. Which will make the transmission and also the processing very much more easy. Often such considerations decide, whether a project is feasible or not. I have heavy doubts, that it is possible to process 4*50kBytes/sec using SPIN.

    Some other thoughts: If you have to do audio processing, than speed is very important. This means that interpreted SPIN will often have to be combined with assembler, which means, that you have to learn 2 languages. So it might be well worth to have a look at the compiled languages for P1. The downside of the compiled languages are, that they need much more code space, which is rather restricted. (Myself I do like to use Tachyon (Taqoz) Forth for the Propellers as Forth is the best compromise between speed and code density and makes experimenting fun. I know, that Forth is often seen as weird, so perhaps you will not fall in love with it.... :-) )

    About the access of bytes as part of longs in SPIN. The manual for P1 is really good:
    https://www.parallax.com/package/propeller-manual/

    Good luck, Christof

    Thanks, I will try to familiarize more with the bitrates and the byte addressing, I was using byte[@address][index], but it is clear that I am far from familiar with propeller programming. In my defense: I am a major in physics and recently switched in computer science so I have a mostly numerical-methods centric approach to programming and miss out a lot of important knowledge.

    Domenico

  • RaymanRayman Posts: 14,130

    Somewhere here in the forum is a fancy one pin communications code. But, in the end I just used serial, like fullduplex serial with both pins the same.

    Key is to make one Prop master so that others only speak when spoken to…

    Then, can share bus with many props.
    Also, good to have resistive loading at at least one prop to reduce noise.

    This way was able to talk between boxes with coax cable connection…

Sign In or Register to comment.