Forum Rule: Always post complete source code & details to reproduce any issue!
Page 1 of 2 1 2 LastLast
Results 1 to 25 of 43

Thread: Teensy 3.2 UART0 Receive Lockup after first Write in RS485 circuit

  1. #1
    Member BradleyC's Avatar
    Join Date
    Mar 2018
    Location
    Houston Area
    Posts
    27

    Teensy 3.2 UART0 Receive Lockup after first Write in RS485 circuit

    This is an RS485 half-duplex application where I am trying to reverse engineer existing behavior in a multi-zone home AC system.

    The Teensy is connected to a working home AC system and is able to correctly receive and to transmit functioning command and response frames.

    However, it cannot receive anything after it has transmitted (used Serial1.write()) even just one byte! (Serial1.available() always returns 0 until the MCU is rebooted.)

    I cannot figure out why after trying many things (register dumps) and studying both the NXP reference and the device driver files, so I am posting this to seek help.

    Thank you in advance for any specific or general guidance.

    This is very frustrating because it should work but it doesn't.

    I think I must be missing some important detail regarding half-duplex protocol/hardware. I hope it's that simple.

    Note: I have also used polling in the loop() for reading packets but this example uses serialEvent1() to do the read of bytes. The receive lockup occurs in either mode of reception immediately after the Serial1.write() function is called.


    Code:
    // Teensy 2.0 has the LED on pin 11
    // Teensy++ 2.0 has the LED on pin 6
    // Teensy 3.x / Teensy LC have the LED on pin 13
    // For thermostat testing I have added an LED on unused pin 2 with a 1K OHM resistor to ground.
    const int ledPin = 2;
    
    uint32_t  frameCount = 0;
    uint8_t byteCount = 0;
    
    #define MAX483CTL 9             // Pin 9 controls MAX483 direction. LOW enables Reception, HIGH, transmission
    // the setup() method runs once, when the sketch starts
    void setup() {
      // initialize the digital pin as an output.
      pinMode(ledPin, OUTPUT);
      digitalWrite(ledPin, LOW);  
      Serial.begin(115200);
      delay(1000);
    
      // the HVAC controls RS-485 subsystem runs at 19200, 8N1.  
      Serial1.begin( 19200 );
      Serial1.transmitterEnable( MAX483CTL ); // Pin 9 controls MAX483 direction. LOW enables Reception, HIGH, transmission
     
      delay(1000);
      Serial.println("\r\nsetup() complete"); 
    }
    
    
    // the loop() method runs over and over again,
    // as long as the board has power
    
    void loop() {
      static uint32_t norcvdata = 0;
      static bool sent = false;
      
      digitalWrite(ledPin, sent ? LOW : HIGH ); // show when the reset packet has been sent.
    
      if ( 0 == Serial1.available() && !sent ) {
        if ((byteCount == 8) && (frameCount == 25)) {
          // after receiving all of the 25th frame, and while the bus is quiescent
          // transmit one reset unit command to thermostat number 04 (study)
          sendReset();    
          sent=true;  // do this only once because there is no reception after this and byteCount remains 8, and frameCount remains 50!                     
        }
      }
    }
    
    void sendReset( void ) {
      // after receiving all of the 50th frame, and while the bus is quiescent
      // transmit one reset unit command to thermostat number 04 (study)
      Serial1.write(0xFF);  // 
      Serial1.write(0x04);  // dst = Study
      Serial1.write(0x06);  // src = prototype (this node)
      Serial1.write(0x6E);  // cnd = reset unit (reboot the Study thermostat)
      Serial1.write(0x00);  // pad frame to 8 bytes
      Serial1.write(0x00);  // pad frame to 8 bytes  
      Serial1.write(0x00);  // pad frame to 8 bytes
      Serial1.write(0x00);  // pad frame to 8 bytes
    
      Serial.println("\r\n>>> FF 04 06 6E 00 00 00 00 ");
    }
    // serialEvent1() is a call-back that is called when receive char interrupt occurs. 
    // I'm not sure if it is invoked at interrupt level but it is called even before
    // the loop begins
    
    // Print each received byte on the monitor output
    // Do so in a way that lists each 8 byte Frame, beginning with the
    // 0xFF StartOfFrame byte, on a separate line.
    
    void serialEvent1( void ) {
      int dataByte;
      
      int bytesAvailable = Serial1.available(); // with the AC controls running,  the value 4 is always returned here.
      
      if (bytesAvailable > 0 ) { 
        
        while( bytesAvailable-- ) {
          dataByte = Serial1.read();
          if (-1 == dataByte ) {
            Serial.println("Fault");
            return;
          } else {
            // No error
            if (0xFF == (uint8_t)dataByte) {
              byteCount = 1;
              Serial.println();
              Serial.print(++frameCount);
              Serial.print(": FF ");       
              return;
            } else {
              byteCount++;
            }
            if (0 ==(0xF0 & (uint8_t)dataByte)) {
              Serial.print("0");        
            }
            Serial.print((uint8_t)dataByte, HEX);
            Serial.print(" ");
          }
        }
    
      } else {
        // Not really sure why this should be here or if it should be here but saw
        // it suggested in the Teensy forum.
        Serial1.flush(); // wait for outstanding transmits to complete.
      }
    
      
    }

    Hardware: Teensy 3.2, MAX483 transceiver.
    Software: Arduino 1.85, Teensyduino 1.41
    Development System: Windows 7 64 bit SP 1

    Supplemental Attachments

    • A photo of the scope display showing the input signals to the teensy module. The green trace is USART0 Rx Pin with 5V amplitude because the MAX483 is powered by 5.0V. The white trace is the A side, non-inverted signal, (pin 6 of the MAX483) of the RS485 bus. I assume these look normal but this is my first RS485 engineering experience. This trace of one frame appears the same before and after the send of the reset frame (using 4 Serial1.write() calls). So I believe the failure is inside the code within the Teensy, not the circuitry outside.
    • A hand-drawn Visio schematic of my Teensy 3.2 RS485 subsystem circuitry.
    • For context, a schematic of the home AC system showing controller and multiple thermostats.
    • A screen capture of the serial monitor output of the sketch showing 25 good frames received from the RS485 network but none after the transmit from the teensy.
    Attached Thumbnails Attached Thumbnails Click image for larger version. 

Name:	RS485 RCV Signals.jpg 
Views:	17 
Size:	142.4 KB 
ID:	14776   Click image for larger version. 

Name:	lockup screencap.PNG 
Views:	9 
Size:	39.4 KB 
ID:	14777  

    Attached Files Attached Files
    Last edited by BradleyC; 09-22-2018 at 11:42 PM. Reason: Add a screen capture of the sketch output.

  2. #2
    Member crees's Avatar
    Join Date
    Dec 2016
    Location
    Utah
    Posts
    98
    Take rs485 out and use another serial device (another teensy or arduino) and simulate it. Does it do the same thing? Tried another teensy? Use different teensy pins for the rs485 en pins?

  3. #3
    Senior Member
    Join Date
    May 2017
    Posts
    148
    I question why you disable the MAX receiver when you transmit. The RX line to the teensy is going to float and perhaps cause framing errors. For a quick test you could try a pullup resistor on the RX line to see if this is an issue. If you left the MAX receiver enabled when transmitting, you could receive your transmitted frame and make sure it went ok without any collisions.

  4. #4
    Member BradleyC's Avatar
    Join Date
    Mar 2018
    Location
    Houston Area
    Posts
    27
    Quote Originally Posted by crees View Post
    Take rs485 out and use another serial device (another teensy or arduino) and simulate it. Does it do the same thing? Tried another teensy? Use different teensy pins for the rs485 en pins?
    Thanks for the ideas. I had not considered eliminating the rs485 because that's a core requirement of the sketch/module. Half duplex is what the existing system uses and I'm building a thermostat to plug in place of the existing design. (I can't change the main AC controller at this time.)

    I also did use a different teensy with a different physical implementation of the external circuit components and observed the same lockup on receive after the first transmit with that hardware implementation. That's one of the reasons I focused on stripping the user interface and temp sensor code out of the application down to just the serial comms on the rs485 bus.

    Thanks again for the response and ideas.

  5. #5
    Member BradleyC's Avatar
    Join Date
    Mar 2018
    Location
    Houston Area
    Posts
    27
    The reason reception is disabled during transmission is because this is a half-duplex system. This circuitry (connecting pins 2 and 3 to the digital direction signal) is, I believe, the standard way to use the transceiver in a half-duplex application. If successful, this design is going into an existing system to upgrade an old thermostat design with 8bit PIC and 2x16 character display). The existing software protocol in this system has a controller that continually polls the 8 (maximum) thermostats which (if the zone is present in the house) respond with a packet. When the home owner interacts with the thermostat in a zone, by pressing buttons, that thermostat will generate (insert) a message on the wires which will be intended for the central controller. The screen dump shows 25 frames of this traffic -- until the device under test sends (inserts during quiet time) its 8 byte command to one of the thermostats. (This command was handled and I observed that thermostat reboot).

    The protocol is not a good design. Collisions can occur easily and recovery is clumsy. (try and try again kind of thing.) The original source code is gone and these thermostats are being built from hex files. Since I cannot change the code in the controller without more work than possible (I'm doing this pro-bono, part time) - I have to live with the collision behavior for now (until I could redesign a new controller and fix the half-duplex protocol to be more robust). I

  6. #6
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,696
    Can you use the scope or even just a voltmeter to monitor pin 9? Would really help to know whether pin is remaining high (telling the transceiver not to receive) while in the locked-up condition, or if it's returning low after those 8 bytes are done transmitting and whether the transceiver chip is again delivering incoming signals to the RX pin.

  7. #7
    Member BradleyC's Avatar
    Join Date
    Mar 2018
    Location
    Houston Area
    Posts
    27
    Quote Originally Posted by PaulStoffregen View Post
    Can you use the scope or even just a voltmeter to monitor pin 9? Would really help to know whether pin is remaining high (telling the transceiver not to receive) while in the locked-up condition, or if it's returning low after those 8 bytes are done transmitting and whether the transceiver chip is again delivering incoming signals to the RX pin.
    Hi Paul, This is one of the first tests I did. In that test, PIN 9 returned low after the last call to Serial1.write(). It was done with my real application, not this stripped down one.

    However, I can and willbuild a slightly different sketch today that continually sends frames. (Unfortunately, because reception is not working, the sketch can't wait for an 'idle' space betwene frames as it does now so it might not actually work in the real world ). But with this sketch, doing repeated Serial1.writes(), I can capture a trace as I did before, where one channel connected to the Rx input pin (on the Teensy side of the MAX483) and the other channel (I only have 2 probes) is connected to PIN 9.

    By the way, in previous instrumented code, using a register dump routine, I captured Status and Control register contents before and after the write and saw nothing out of the ordinary.

    I had expected to see error register bits such as framing errors or something that might trigger a lockup of the dma or maybe a simple coding error on my part due to my ignorance of the Arduino Sketch application model.

    I do so miss JTAG debugging but I don't miss having to do all the work that you have done for us! I can never thank you and PJRC enough for saving many months of work.

    Without it I could not afford to do this pro-bono work to help my friend who has a wonderful AC design but whose company has fallen on hard times.

  8. #8
    Member BradleyC's Avatar
    Join Date
    Mar 2018
    Location
    Houston Area
    Posts
    27

    Sketch modified to capture Pin 9 trace

    Paul,

    This is a follow-up to my response about pin 9.

    Below is a modified sketch that receives and prints frames as before but also sends the reset frame periodically without regard for bus activity (will cause collisions).
    I ran this connected to the home AC system and observed similar behavior -- Teensy receives and prints frames to the monitor until it sends its first frame.
    While connected to the home AC system, I observe the target thermostat reset in response to the successfully transmitted frame (unless there was a collision with other traffic garbling the frame. As I explained this protocol is crude and I can't change the other nodes)

    I decided to increase the frequency of the reset command to make it easier to capture the traces on the scope but not wanting to disrupt my AC function too much, I disconnected the Teensy MAX483 from the home network. I thought this doesn't matter for the scope tests because we are only wanting to look at the signals on the Teensy before, during and after it is transmitting, and not really do any functional communication.

    I did that and this is the code below. I also captured 2 scope traces. One shows Tx and Pin 9 (Tx and Pin 9.jpg), and the other shows the output of the MAX483 pin A with Pin 9 (A and Pin 9.jpg).
    I also have a screen shot (rs485BG capture.PNG) of the monitor output of this sketch. With the MAX483 disconnected from the network, and the pins just 'floating in air', I was expecting NO bytes at all on the input (receive) side. And that's what happens -- until after the first transmit. Then after every transmit, ONE byte of 00 is received. One and only one. So this is a 'spurious' receive byte synthesized by the hardware from switching or something inside the MCU (or perhaps the USART driver which I doubt.)

    Perhaps this spurious input byte is a clue to my problem.

    I hope the scope traces help.

    Thank you for looking at this.


    Code:
    // Teensy 2.0 has the LED on pin 11
    // Teensy++ 2.0 has the LED on pin 6
    // Teensy 3.x / Teensy LC have the LED on pin 13
    // For thermostat testing I have added an LED on unused pin 2 with a 1K OHM resistor to ground.
    const int ledPin = 2;
    
    uint32_t  frameCount = 0;
    uint8_t byteCount = 0;
    
    #define MAX483CTL 9             // Pin 9 controls MAX483 direction. LOW enables Reception, HIGH, transmission
    // the setup() method runs once, when the sketch starts
    void setup() {
      // initialize the digital pin as an output.
      pinMode(ledPin, OUTPUT);
      digitalWrite(ledPin, LOW);  
      Serial.begin(115200);
      delay(1000);
    
      // the HVAC controls RS-485 subsystem runs at 19200, 8N1.  
      Serial1.begin( 19200 );
      Serial1.transmitterEnable( MAX483CTL ); // Pin 9 controls MAX483 direction. LOW enables Reception, HIGH, transmission
     
      delay(1000);
      Serial.println("\r\nsetup() rs485B complete"); 
    }
    
    
    // the loop() method runs over and over again,
    // as long as the board has power
    
    void loop() {
    
      static uint32_t timeNow = 0;
      static uint32_t timeFuture = 0;
      if (0 == timeNow ) {
        timeNow = millis();
        timeFuture = timeNow + 2000;  // five seconds in the future
        digitalWrite(ledPin, LOW );
      }
      
      if (timeNow > 0 ) {
        if (timeFuture < millis()) {
          timeNow = 0;
          digitalWrite(ledPin, HIGH);
          sendReset();  // this can and will collide with other frames -- randomly.
        }
      }
      
    }
    
    void sendReset( void ) {
      // after receiving all of the 50th frame, and while the bus is quiescent
      // transmit one reset unit command to thermostat number 04 (study)
      Serial1.write(0xFF);  // 
      Serial1.write(0x04);  // dst = Study
      Serial1.write(0x06);  // src = prototype (this node)
      Serial1.write(0x6E);  // cnd = reset unit (reboot the Study thermostat)
      Serial1.write(0x00);  // pad frame to 8 bytes
      Serial1.write(0x00);  // pad frame to 8 bytes  
      Serial1.write(0x00);  // pad frame to 8 bytes
      Serial1.write(0x00);  // pad frame to 8 bytes
    
      Serial.print("\r\n>>> FF 04 06 6E 00 00 00 00 ");Serial.println(millis());
    }
    // serialEvent1() is a call-back that is called when receive char interrupt occurs. 
    // I'm not sure if it is invoked at interrupt level but it is called even before
    // the loop begins
    
    // Print each received byte on the monitor output
    // Do so in a way that lists each 8 byte Frame, beginning with the
    // 0xFF StartOfFrame byte, on a separate line.
    
    void serialEvent1( void ) {
      int dataByte;
      
      int bytesAvailable = Serial1.available(); // with the AC controls running,  the value 4 is always returned here.
      
      if (bytesAvailable > 0 ) { 
        Serial1.flush();  // wait for any outstanding bytes to be sent.
        while( bytesAvailable-- ) {
          dataByte = Serial1.read();
          if (-1 == dataByte ) {
            Serial.println("Fault");
            return;
          } else {
            // No error
            if (0xFF == (uint8_t)dataByte) {
              byteCount = 1;
              Serial.print(millis());Serial.println();
              Serial.print(++frameCount);
              Serial.print(": FF ");       
              return;
            } else {
              byteCount++;
            }
            if (0 ==(0xF0 & (uint8_t)dataByte)) {
              Serial.print("0");        
            }
            Serial.print((uint8_t)dataByte, HEX);
            Serial.print(" ");
          }
        }
      }
    
      
    }
    Attached Thumbnails Attached Thumbnails Click image for larger version. 

Name:	A and Pin 9.jpg 
Views:	12 
Size:	197.5 KB 
ID:	14791   Click image for larger version. 

Name:	Tx and Pin 9.jpg 
Views:	9 
Size:	204.2 KB 
ID:	14792  

    Click image for larger version. 

Name:	rs485B capture.PNG 
Views:	12 
Size:	30.4 KB 
ID:	14793  

  9. #9
    Senior Member
    Join Date
    May 2017
    Posts
    148
    In reviewing, one thing I find strange is that in your scope trace in Post #1, the RX line idles low. In most instances of using UARTS that I am familiar with, the RX line idles high. But I never worked with multidrop systems so perhaps they can be different.

    Since it is a receiver issue, it would be interesting to see what the RX line looks like before, during and after you send the first packet when all units are connected. You could sync your scope with pin 9 going high and capture that.

  10. #10
    Member BradleyC's Avatar
    Join Date
    Mar 2018
    Location
    Houston Area
    Posts
    27
    Quote Originally Posted by rcarr View Post
    In reviewing, one thing I find strange is that in your scope trace in Post #1, the RX line idles low. In most instances of using UARTS that I am familiar with, the RX line idles high. But I never worked with multidrop systems so perhaps they can be different.

    Since it is a receiver issue, it would be interesting to see what the RX line looks like before, during and after you send the first packet when all units are connected. You could sync your scope with pin 9 going high and capture that.
    This is the first time I've worked with RS485 and half duplex on UARTS so I've been learning and obviously have more to learn.

    I also have a lot more to learn about using the scope properly so i'll try to do what you suggest.

    This old (20+ years) hand-me-down scope is really nice (4 channels but i got it with only 2 probes). Hopefully I can do the test you outline with only 2 probes.

    I find it hard for me to explain how the 00 byte shows up on the receive FIFO only after the transmit FIFO is used when there is no sender -- maybe this is coming from the MAX483 somehow even though the 483 A/B are disconnected (floating in air) on this last sketch. I'm not EE. Just software/firmware and always had HW experts working around me to ask for help when something like this showed up. Now I'm basically on my own - except for all the great help on this forum! Thanks for your time and help by the way!

  11. #11
    Member
    Join Date
    Aug 2013
    Location
    Ohio
    Posts
    83
    Rcarr's observation about the idle state of leads to a question about UART handling at a register level: I have not looked at the Teensyduino driver layer recently, but there's a possibility that after the first transmit, the receiver enters an error state (possibly framing error if there's an unexpected signal inversion).

    Once in the error state, the UART becomes recalcitrant and may not receive until the error is cleared. There's a bit of a register access procedure (read the "S1" register, then read the "D" register) to clear the error state, whereupon the receiver can receive again.

    The behavior of the UART_FE framing error is documented in the reference manual (Chapter 47, "Universal Asynchronous Receiver/Transmitter") this way:

    FE is set when a logic 0 is accepted as the stop bit. FE does not set in the case of an overrun or while the
    LIN break detect feature is enabled (S2[LBKDE] = 1). FE inhibits further data reception until it is cleared.
    To clear FE, read S1 with FE set and then read D.
    Make sure the UART's receive inversion state matches the signal and be prepared to recover from errors resulting from collisions.

  12. #12
    Member BradleyC's Avatar
    Join Date
    Mar 2018
    Location
    Houston Area
    Posts
    27
    Quote Originally Posted by LenSamuelson View Post
    Rcarr's observation about the idle state of leads to a question about UART handling at a register level: I have not looked at the Teensyduino driver layer recently, but there's a possibility that after the first transmit, the receiver enters an error state (possibly framing error if there's an unexpected signal inversion).

    Once in the error state, the UART becomes recalcitrant and may not receive until the error is cleared. There's a bit of a register access procedure (read the "S1" register, then read the "D" register) to clear the error state, whereupon the receiver can receive again.

    The behavior of the UART_FE framing error is documented in the reference manual (Chapter 47, "Universal Asynchronous Receiver/Transmitter") this way:



    Make sure the UART's receive inversion state matches the signal and be prepared to recover from errors resulting from collisions.
    Thank you so much for these details. It helps me focus my attention in the right place in the haystack (manual). I looked for FE and other errors in the registers following the failure and did not notice them but I'll look again more carefully.

  13. #13
    Member BradleyC's Avatar
    Join Date
    Mar 2018
    Location
    Houston Area
    Posts
    27

    Do you think I have created the wrong circuit?

    With the post from Len fresh in my mind, I started a web search for "+Kinetis +K20 +USART +RS485 +Errata" hoping to find something useful.

    I found this: https://www.nxp.com/docs/en/supporti...T-Training.pdf.

    On slide 12 is a diagram for using the Kinetis UART in an RS485 circuit that -- instead of connecting RE and DE to a direction digital pin of the Teensy, I should connect the UART's RTS pin to RE and DE and "RTS should be configured for TXRTS mode and active high polarity."

    Click image for larger version. 

Name:	NXP RS485 Slide.PNG 
Views:	15 
Size:	68.8 KB 
ID:	14809

    So ... now I'm wondering if the fact I'm using the Serial1.transmitenable() instead of the way Kinetis training indicates can explain the misbheavior.

    Maybe the behavior I'm seeing is not a bug - it's a 'feature' because I just am using the wrong teensy pin to control the transceiver!

    Unless -- the magic Paul has written in the driver to implement transmitenable() is mapping the digital pin to the USART0 RTS functional pin. Then I'm still stuck.

    (I have tried reading the driver but I'm not a C++ expert and have had more difficulty seeing what the code is really doing at the MCU register level. I can't even find the code that starts up the MCU out of reset -- the typical 'board support package' code that I'm used to modifying and / or writing myself in non-arduino context.)


    Paul S., can you comment about this RTS configuration detail vs. the use of transmitenable? Are they one and the same?

  14. #14
    Senior Member
    Join Date
    May 2017
    Posts
    148
    I think your hardware has probably two design issues that lead to it being nondeterministic. And issues like 'it works until you transmit' and receiving an unexpected 0 are the type of flaky errors one observes in such a system. One of those is what I tried to communicate before. When you transmit, the RX signal to the UART goes tristate. Floating inputs are not good in logic systems. A 4.7k pullup to 3.3 or 5 volts would ensure a known logic level.

    The 2nd is the fact that RX idles low leads me to believe your system does not have Failsafe bias resisters as discussed in this document.

    https://www.maximintegrated.com/en/a...dex.mvp/id/763

    Notice how they stress the need to keep the RX line high when nothing is driving the bus.

  15. #15
    Member BradleyC's Avatar
    Join Date
    Mar 2018
    Location
    Houston Area
    Posts
    27
    Quote Originally Posted by rcarr View Post
    I think your hardware has probably two design issues that lead to it being nondeterministic. And issues like 'it works until you transmit' and receiving an unexpected 0 are the type of flaky errors one observes in such a system. One of those is what I tried to communicate before. When you transmit, the RX signal to the UART goes tristate. Floating inputs are not good in logic systems. A 4.7k pullup to 3.3 or 5 volts would ensure a known logic level.

    The 2nd is the fact that RX idles low leads me to believe your system does not have Failsafe bias resisters as discussed in this document.

    https://www.maximintegrated.com/en/a...dex.mvp/id/763

    Notice how they stress the need to keep the RX line high when nothing is driving the bus.
    Thanks so much for the additional details, you're very generous with sharing your knowledge here -- As I wrote, I'm not an EE and the circuit I used is cloned (save for the MCU) from the existing thermostat design. All it uses is a termination resistor at each thermostat.

    I've read the app note twice and you are right -- my design does not have Failsafe bias resistors.

    I note that it says to use a pull-up on the non-inverting line (A) and a pull-down on the inverting line (B).

    The app note also describes using Failsafe resistors on the 'receiver end of the transmission line'.

    My follow-up question to you is this: Since every node in this system is a 'receiver' -- then may I interpret this directive to be inclusive -- in that it means "if the node will receive, then use failsafe resistors to prevent 'undefined receiver output'? I think the answer is yes but in my ignorance I do not want to make assumptions!

    I should say the failure seems pretty is deterministic -- the failure always occurs and it occurs the same way each time. But that doesn't mean the design is right -- it's not working so something (probably more than one something) is different. Also, the packets received are reliable -- this Teensy based design reliably receives every transmitted packet successfully from the controller and 6 other thermostats in the network. Also, every transmitted packet (so far) has been correctly processed (received) by the targeted nodes. (The central controller in repeated tests and the thermostat in the study in the other set of repeated tests).

    The unexpected single byte reception seems to be triggered by the use of the transmit line (switching the MAX483 transceiver to transmit mode) -- and NEVER occurs when the sketch stays in receive mode. I am suspecting this may be the evidence of the need for Failsafe biasing that you discuss.

    I guess that the design I'm copying, using the same MAX483 transceivers, has been fortunate not to have problems like I see with the teensy. (or perhaps it does have the problems but the code which I have not seen contains adequate workarounds).

    One last follow-up question. You say the idle state of the Rx line (input to the Teensy, output from the Transceiver) should not be low.

    I can buy that as a fact but am curious as to why it works so reliably until a transmit is used. Do you have any hypothesis?

    I observed days worth (thousands) of successful frames received and processed in my tests before I turned on the code to try to transmit.

    This is deterministic and reproducible with my second prototype containing a different teensy 3.2 but using the same circuit.

  16. #16
    Senior Member
    Join Date
    May 2017
    Posts
    148
    I am kind of learning multidrop as we go. My understanding is that the failsafe bias resistors would only be on one node at one end of the network. If you have a star configuration then they perhaps would be at the center. The ap note mentions some newer drivers/receivers that do not need the resistors. I didn't look at the specification of those, but that may be a good option that would not interfere with the existing design. Wikipedia has some discussion of the resistors:
    https://en.wikipedia.org/wiki/RS-485

    I think you should scope the RX line as I mentioned. My hypothesis is that the RX line idles high until you transmit and then starts to idle low. The only way to prove if true or false would be to take a look. The other part of the theory is that there is a framing error which does not clear for some reason as previously mentioned. The missing pullup on RX could also cause the same thing. When you transmit and the RX line floats it could: 1) be seen as a low and cause a framing error. 2) be seen as a high and all ok. 3) it could oscillate as it picks up noise.

  17. #17
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,696
    Quote Originally Posted by BradleyC View Post
    Paul S., can you comment about this RTS configuration detail vs. the use of transmitenable? Are they one and the same?
    No, they're not the same. Teensyduino implements it in software, allowing any digital pin.

  18. #18
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,696
    Quote Originally Posted by BradleyC View Post
    With the MAX483 disconnected from the network, and the pins just 'floating in air', I was expecting NO bytes at all on the input (receive) side. And that's what happens -- until after the first transmit. Then after every transmit, ONE byte of 00 is received. One and only one. So this is a 'spurious' receive byte synthesized by the hardware from switching or something inside the MCU (or perhaps the USART driver which I doubt.)
    I'd like to try running this test, maybe later tonight or tomorrow.

    As I understand, all I need for this test is a Teensy 3.2 and a MAX483 chip, and a 10K resistor between the A & B pins. Only 3 signals (pins 0, 1, 9) plus GND & 5V are needed between the MAX483 and Teensy. Is that right? Do I need to connect any other hardware or do anything else before I run that code here?

    In my draw of transceiver chips, I have MAX487, ST485 and ST3485. Looks like I don't actually have MAX483. Hopefully a MAX487 will be close enough?

  19. #19
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,696
    Here's my first attempt. I wired it up with the MAX487.

    Click image for larger version. 

Name:	DSC_0223_web.jpg 
Views:	7 
Size:	155.6 KB 
ID:	14811

    Here's what I get in the serial monitor when I run the code from msg #8.

    Click image for larger version. 

Name:	sc.png 
Views:	17 
Size:	33.9 KB 
ID:	14812

  20. #20
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,696
    Looks like I forgot the 10K resistor, in my first quick attempt. Indeed it does make quite a difference.

    I added the resistor, and connected my scope to those 3 signals and to the A signal (pin 6 of the MAX487).

    Click image for larger version. 

Name:	DSC_0224_web.jpg 
Views:	17 
Size:	178.0 KB 
ID:	14815

    With the 10K resistor, here's what I see in the serial monitor.

    Click image for larger version. 

Name:	sc.png 
Views:	17 
Size:	37.2 KB 
ID:	14816

    Here's what my scope sees:

    Click image for larger version. 

Name:	file.png 
Views:	27 
Size:	42.6 KB 
ID:	14817

  21. #21
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,696
    If I remove the 10K resistor, those extra zero receive bytes disappear (same result as msg #19).

    Here's how it looks on my scope.

    Click image for larger version. 

Name:	file.png 
Views:	9 
Size:	42.0 KB 
ID:	14818

    The interesting thing here is the yellow trace (voltage arriving at Teensy's RX1 pin) is going from ~3.3 volts to about 2 volts when the DE+RE pins are driven high.

  22. #22
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,696
    For this application, I'd recommend adding three 4.7K resistors.

    Resistor #1: RS485 signal A to +5V
    Resistor #2: RS485 signal B to GND
    Resistor #3: RO (RX1) to +5V

    The first 2 keep the RS485 signals in a proper idle state when they're not driven. Here's a page with more detail and a schematic.

    https://electronics.stackexchange.co...-bidirectional

    The 3rd resistor helps keep the RO signal from the MAX483 / MAX487 at a valid logic high when the receiver is turned off.

    Here's how the reset looks on my scope.

    Click image for larger version. 

Name:	file.png 
Views:	18 
Size:	41.5 KB 
ID:	14819

    Here's the 4.7K resistors connected on my breadboard.

    Click image for larger version. 

Name:	DSC_0225_zoomin.JPG 
Views:	20 
Size:	99.8 KB 
ID:	14820

  23. #23
    Member BradleyC's Avatar
    Join Date
    Mar 2018
    Location
    Houston Area
    Posts
    27
    Quote Originally Posted by rcarr View Post
    I am kind of learning multidrop as we go. My understanding is that the failsafe bias resistors would only be on one node at one end of the network. If you have a star configuration then they perhaps would be at the center. The ap note mentions some newer drivers/receivers that do not need the resistors. I didn't look at the specification of those, but that may be a good option that would not interfere with the existing design. Wikipedia has some discussion of the resistors:
    https://en.wikipedia.org/wiki/RS-485

    I think you should scope the RX line as I mentioned. My hypothesis is that the RX line idles high until you transmit and then starts to idle low. The only way to prove if true or false would be to take a look. The other part of the theory is that there is a framing error which does not clear for some reason as previously mentioned. The missing pullup on RX could also cause the same thing. When you transmit and the RX line floats it could: 1) be seen as a low and cause a framing error. 2) be seen as a high and all ok. 3) it could oscillate as it picks up noise.
    I'm going to try to do the scope tests as you suggest and will share them. Here is the circuit of the existing thermostat whose UI (16x2 char + 3 button) hardware I'm trying to replace with a TFT Touchscreen from Adafruit. Click image for larger version. 

Name:	TSTAT SCHEMATIC Copy.jpg 
Views:	10 
Size:	107.2 KB 
ID:	14822 Since I am not an EE or electrical technician, and need backwards electrical compatibility with the node at the center of the star (the controller), which uses the MAX483, I chose to use the MAX483 here too. I have been in the attic and looked at the controller. It turns out not to have a termination resistor between the A-B terminals - neither does it have Failsafe resistors pulling A up and B down. All I can say is it's been working for decades. I think the business owner's main problem with the design is that the software protocol for the 9 node, half-duplex multi-master system does nothing to avoid collisions when two nodes transmit at the same time - it accepts them and just does retransmits with a node-address specific back-off timer. I can't criticize the design -- it works and my replacement doesn't -- not yet anyway.

    I will append the screenshots of the traces. I recall that before and after the transmit, the idle Rx is at ground -- I haven't measured Rx level during the transmit as I assumed (bad me) that it didn't matter because the MAX483 tristated its output and the Teensy probably tristated its input. But .... i know about assumptions ... they're full of blind-spots.

  24. #24
    Member BradleyC's Avatar
    Join Date
    Mar 2018
    Location
    Houston Area
    Posts
    27
    Quote Originally Posted by PaulStoffregen View Post
    No, they're not the same. Teensyduino implements it in software, allowing any digital pin.
    Thanks for that clarification. I would prefer to use a design with Teensy that you advocate rather than changing to the one some unnamed NXP presenter put into a training slide!

    So I will stick with transmitenable() and just work to fix the circuit I'm using. I have not read your responses below yet -- but it seems you ran some tests and have good results and advice so I'm going to go do that now and make appropriate changes and retest. THANK YOU SO VERY MUCH.

  25. #25
    Member BradleyC's Avatar
    Join Date
    Mar 2018
    Location
    Houston Area
    Posts
    27
    Quote Originally Posted by PaulStoffregen View Post
    Here's my first attempt. I wired it up with the MAX487.

    Click image for larger version. 

Name:	DSC_0223_web.jpg 
Views:	7 
Size:	155.6 KB 
ID:	14811

    Here's what I get in the serial monitor when I run the code from msg #8.

    Click image for larger version. 

Name:	sc.png 
Views:	17 
Size:	33.9 KB 
ID:	14812
    Interesting that you don't get the spurious nul bytes after the 2nd transmit. Due to some difference between the 483 and 487 perhaps?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •