This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

UARTE in semi-duplex mode

Hi all,

I would like to have a semi-duplex communication link over one pin (+GND). The nRF will act as a pure slave device which responds to, and acknowledges, commands from a "master".Thus:

1. I set UARTE in RX mode.  PSEL.RXD is set to the (shared) pin.

2. A command is successfully received from the master.

3.  PSEL.RXD = 0xffffffff, PSEL.TXD s set to the (shared) pin.

4. A reply is successfully sent to the master.

5. Back to 1

The problem is that this only works two times. Then I get an "overrun" error. I've tried "EVERYTHING" to prevent this from happening; delays in various places, different sequences of pin role swithing (when the UARTE module is disabled) and trying to run  STOPRX (according to the 35.4 UARTE-Reception section of the device datasheet) in order to properly empty the RX buffer.

Any ideas ? Please help !

Cheers

Eric

Parents
  • Hi 

    In the past I have had success implementing 'one wire UART' implementations like this by connecting the TX and RX pins together externally, then you don't have to do any complicated configuration of the driver to go from TX to RX and vice versa. 

    The only drawback of this method is that any data you send will also be received (you get external loopback essentially), so you will need to take this into account when sending data. 

    Also, for more complicated UART implementations I would recommend using the nrf_libuarte driver, as it is a more robust and feature rich UART implementation that is designed to make full use of the UARTE peripheral and its EasyDMA features. 

    Best regards
    Torbjørn

  • Hi Torbjörn,

    Thanks for your input. As I explained to "hmolesworth" I would very much like to be able to solve this with one I/O pin only. For the same reason I have not considered the nrf_libuarte driver as this most certainly does not support semi-duplex operation. Besides, I would not call my use case a "complicated" scenario which requires an advanced driver.

    What bugs me is that you'd think that by switching the UARTE module off (as required when switching role on the I/O pin) you would automatically put it in its reset condition. Guess not ... 

    An why does the "RX flush" procedure need to be so complicated ???

    \Eric

  • Hey Eric, just to clarify I didn't mean use a separate pin for the Rx data, just a separate pin to "park" Rx in a input-high-via-pull-up state while transmitting on Tx. Any input pin will do even if used for something else as long as you can avoid things happening during that Rx interval. For example you might try the 32kHz crystal output drive pin P0.1; I haven't tried this yet but considered it for a similar issue a while ago. It all hinges whether the pull-up is applied to the pin-side or input buffer-side of the input FET switch.

    Ok I just looked at the crystal pins as that might be a special case as it doesn't seem to work, but other pins look ok, eg SDA just avoid I2C transfers during Tx activity while Rx is parked

    It works!!

     // Park Rx pin somewhere safe with a known '1' input level
     NRF_UARTE0->PSEL.RXD = PIN_I2C_SCL;
    
    // Transmit some data, be sure last tx byte has cleared the pin
    
     if (mTxDone)
     {
       // Revert Parked Rx pin here or in interrupt (not both)
       NRF_UARTE0->PSEL.RXD = PIN_UART_RX;
       mTxDone = false;
     }

    To be sure the last byte has cleared the Tx pin before turning on Rx again:

    case APP_UART_TX_EMPTY: // Event UART has completed transmission of all available data in the TX FIFO
      // Revert Parked Rx pin
      NRF_UARTE0->PSEL.RXD = PIN_UART_RX;
    or set a flag:
      mTxDone = true;
      break;

Reply
  • Hey Eric, just to clarify I didn't mean use a separate pin for the Rx data, just a separate pin to "park" Rx in a input-high-via-pull-up state while transmitting on Tx. Any input pin will do even if used for something else as long as you can avoid things happening during that Rx interval. For example you might try the 32kHz crystal output drive pin P0.1; I haven't tried this yet but considered it for a similar issue a while ago. It all hinges whether the pull-up is applied to the pin-side or input buffer-side of the input FET switch.

    Ok I just looked at the crystal pins as that might be a special case as it doesn't seem to work, but other pins look ok, eg SDA just avoid I2C transfers during Tx activity while Rx is parked

    It works!!

     // Park Rx pin somewhere safe with a known '1' input level
     NRF_UARTE0->PSEL.RXD = PIN_I2C_SCL;
    
    // Transmit some data, be sure last tx byte has cleared the pin
    
     if (mTxDone)
     {
       // Revert Parked Rx pin here or in interrupt (not both)
       NRF_UARTE0->PSEL.RXD = PIN_UART_RX;
       mTxDone = false;
     }

    To be sure the last byte has cleared the Tx pin before turning on Rx again:

    case APP_UART_TX_EMPTY: // Event UART has completed transmission of all available data in the TX FIFO
      // Revert Parked Rx pin
      NRF_UARTE0->PSEL.RXD = PIN_UART_RX;
    or set a flag:
      mTxDone = true;
      break;

Children
  • Hi,

    Great to hear that you got it working. Unfortunately I cannot replicate your success ... yet. May I ask for some additional details:

    1. What is your initial set-up; baudrate etc. ? Do you assign NRF_UARTE0->PSEL.TXD  to the same pin at start-up or not until you have "parked" PSEL.RXD ? 

    2. Do you do the "flush RX" operation before you go into TX mode ? If yes, how does your sequence look like ?

    3. Do you set NRF_UARTE0->ENABLE = 0 before the pin swap ? (and enable it before starting to transmit) ?

    4. Have you tried the RX-TX -RX cycle a number of consecutive times without any problems ?

    The devil is in the details ...

    \Eric

  • Hello again,

    Never mind my last post. I got it working now ! As usual, when you have something that does not make any sense, there is more than one error; indeed the "parking" issue you highlighted but also another, really stupid, high level bug that also prevented multiple transactions.

    In any way; you made my day. Thanks a lot !!!

  • Good news indeed! I don't turn off the uart enable, by the way, although the datasheet says to do so before changing pins, but then the datasheet says don't share any pins between peripherals but I've never seen an issue with sharing input-function pins. Difficult to see how input-side loading might be an issue, but maybe that's the concern; I suspect it's a general rule to stop multiple peripherals driving the same output pin.

Related