This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP-TS430PZ100E: UART (RS-485) using SN75176B Differential Transceiver doesn't work

Part Number: MSP-TS430PZ100E
Other Parts Discussed in Thread: MSP430F5528

Hi!

I'm using MSP-TS430PZ100E (MSP450FR6047) and SN5176B differential transceiver to communicate with PC through RS485/USB converter. 

I've never used SN5176B before. Or more accurately, I have no experience of using UART for RS485 interface. The only successful experience of using UART was communication with TTL with TDS7200EVEM  (MSP430F5528).

I had to use UCA2 (P5.0 - TXD, P5.1 - RXD, P5.2 - RE/DE) because UCA0 and UCA1 are either already being used for JTAG or too far from the breadboard. The schematic is as below;

I used TI's sample code of "msp430fr60x7_euscia0_uart_01.c" after modifying them as below;

 

#include <msp430.h>

 

int main(void)

{

   WDTCTL = WDTPW | WDTHOLD;               // Stop Watchdog

 

   // Configure GPIO

   P5SEL0 &= ~(BIT0 | BIT1);

   P5SEL1 |= BIT0 | BIT1;                 // USCI_A0 UART operation

 

   P5DIR |= BIT2; // P5.2 -> DE, ~RE, output

           P5OUT   &= ~ BIT2;       //

 

   // Disable the GPIO power-on default high-impedance mode to activate

   // previously configured port settings

   PM5CTL0 &= ~LOCKLPM5;

 

   // Startup clock system with max DCO setting ~8MHz

   CSCTL0_H = CSKEY_H;                     // Unlock CS registers

   CSCTL1 = DCOFSEL_3 | DCORSEL;           // Set DCO to 8MHz

   CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK;

   CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1;   // Set all dividers

   CSCTL0_H = 0;                           // Lock CS registers

 

   // Configure USCI_A0 for UART mode

   UCA2CTLW0 = UCSWRST;                   // Put eUSCI in reset

   UCA2CTLW0 |= UCSSEL__SMCLK;             // CLK = SMCLK

   // Baud Rate calculation

   // 8000000/(16*9600) = 52.083

   // Fractional portion = 0.083

   // User's Guide Table 24-4: UCBRSx = 0x04

   // UCBRFx = int ( (52.083-52)*16) = 1

   UCA2BRW = 52;                           // 8000000/16/9600

   UCA2MCTLW |= UCOS16 | UCBRF_1 | 0x4900;

   UCA2CTLW0 &= ~UCSWRST;                 // Initialize eUSCI

   UCA2IE |= UCRXIE;                       // Enable USCI_A0 RX interrupt

 

   __bis_SR_register(LPM3_bits + GIE);     // Enter LPM3, interrupts enabled

   __no_operation();                       // For debugger

}

 

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)

#pragma vector=EUSCI_A2_VECTOR

__interrupt void USCI_A2_ISR(void)

#elif defined(__GNUC__)

void __attribute__ ((interrupt(EUSCI_A2_VECTOR))) USCI_A2_ISR (void)

#else

#error Compiler not supported!

#endif

{

   switch(__even_in_range(UCA2IV, USCI_UART_UCTXCPTIFG))

   {

       case USCI_NONE: break;

       case USCI_UART_UCRXIFG:

           while(!(UCA2IFG&UCTXIFG));

           UCA2TXBUF = UCA2RXBUF;

           __no_operation();

           break;

       case USCI_UART_UCTXIFG: break;

       case USCI_UART_UCSTTIFG: break;

       case USCI_UART_UCTXCPTIFG: break;

       default: break;

   }

}

As below, I checked whether the TXD port is giving output by continuously sending a character using oscilloscope and confirmed that it's giving output.

while(1)

   {

//       if( i>0)

       {

 

           i--;

           P1OUT ^= (BIT0|BIT1);                     // Toggle LED

 

           __delay_cycles(100000);

           __delay_cycles(100000);

           __delay_cycles(100000);

           __delay_cycles(100000);

           __delay_cycles(100000);

                   __delay_cycles(100000);

                   __delay_cycles(100000);

                   __delay_cycles(100000);

                   __delay_cycles(100000);

       }

       if(bBUT_MENU)

           {

               Show("Button Menu pressed.");

           }

       else

       {

           Show("MaxiFlo Heat Meter");

       }

 

       UCA2TXBUF = 'A';

       UCA2TXBUF = 'b';

//       __bis_SR_register(LPM4_bits | GIE); // Enter LPM4 w/interrupt

         __no_operation();                   // For debugger

 

   }

Please help me!!!

  • Part Number: MSP-TS430PZ100E

    Hi!

    I'm using MSP-TS430PZ100E (MSP450FR6047) and SN5176B differential transceiver to communicate with PC through RS485/USB converter. 

    I've never used SN5176B before. Or more accurately, I have no experience of using UART for RS485 interface. The only successful experience of using UART was communication with TTL with TDS7200EVEM  (MSP430F5528).

    I had to use UCA2 (P5.0 - TXD, P5.1 - RXD, P5.2 - RE/DE) because UCA0 and UCA1 are either already being used for JTAG or too far from the breadboard. The schematic is as below; (There's a 120-ohm resistor across A and B though not shown here)

    I used TI's sample code of "msp430fr60x7_euscia0_uart_01.c" after modifying them as below;

     

    #include <msp430.h>

     

    int main(void)

    {

       WDTCTL = WDTPW | WDTHOLD;               // Stop Watchdog

     

       // Configure GPIO

       P5SEL0 &= ~(BIT0 | BIT1);

       P5SEL1 |= BIT0 | BIT1;                 // USCI_A0 UART operation

     

       P5DIR |= BIT2; // P5.2 -> DE, ~RE, output

               P5OUT   &= ~ BIT2;       //

     

       // Disable the GPIO power-on default high-impedance mode to activate

       // previously configured port settings

       PM5CTL0 &= ~LOCKLPM5;

     

       // Startup clock system with max DCO setting ~8MHz

       CSCTL0_H = CSKEY_H;                     // Unlock CS registers

       CSCTL1 = DCOFSEL_3 | DCORSEL;           // Set DCO to 8MHz

       CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK;

       CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1;   // Set all dividers

       CSCTL0_H = 0;                           // Lock CS registers

     

       // Configure USCI_A0 for UART mode

       UCA2CTLW0 = UCSWRST;                   // Put eUSCI in reset

       UCA2CTLW0 |= UCSSEL__SMCLK;             // CLK = SMCLK

       // Baud Rate calculation

       // 8000000/(16*9600) = 52.083

       // Fractional portion = 0.083

       // User's Guide Table 24-4: UCBRSx = 0x04

       // UCBRFx = int ( (52.083-52)*16) = 1

       UCA2BRW = 52;                           // 8000000/16/9600

       UCA2MCTLW |= UCOS16 | UCBRF_1 | 0x4900;

       UCA2CTLW0 &= ~UCSWRST;                 // Initialize eUSCI

       UCA2IE |= UCRXIE;                       // Enable USCI_A0 RX interrupt

     

       __bis_SR_register(LPM3_bits + GIE);     // Enter LPM3, interrupts enabled

       __no_operation();                       // For debugger

    }

     

    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)

    #pragma vector=EUSCI_A2_VECTOR

    __interrupt void USCI_A2_ISR(void)

    #elif defined(__GNUC__)

    void __attribute__ ((interrupt(EUSCI_A2_VECTOR))) USCI_A2_ISR (void)

    #else

    #error Compiler not supported!

    #endif

    {

       switch(__even_in_range(UCA2IV, USCI_UART_UCTXCPTIFG))

       {

           case USCI_NONE: break;

           case USCI_UART_UCRXIFG:

               while(!(UCA2IFG&UCTXIFG));

               UCA2TXBUF = UCA2RXBUF;

               __no_operation();

               break;

           case USCI_UART_UCTXIFG: break;

           case USCI_UART_UCSTTIFG: break;

           case USCI_UART_UCTXCPTIFG: break;

           default: break;

       }

    }

    As below, I checked whether the TXD port is giving output by continuously sending a character using oscilloscope and confirmed that it's giving output.

    while(1)

       {

    //       if( i>0)

           {

     

               i--;

               P1OUT ^= (BIT0|BIT1);                     // Toggle LED

     

               __delay_cycles(100000);

               __delay_cycles(100000);

               __delay_cycles(100000);

               __delay_cycles(100000);

               __delay_cycles(100000);

                       __delay_cycles(100000);

                       __delay_cycles(100000);

                       __delay_cycles(100000);

                       __delay_cycles(100000);

           }

           if(bBUT_MENU)

               {

                   Show("Button Menu pressed.");

               }

           else

           {

               Show("MaxiFlo Heat Meter");

           }

     

           UCA2TXBUF = 'A';

           UCA2TXBUF = 'b';

    //       __bis_SR_register(LPM4_bits | GIE); // Enter LPM4 w/interrupt

             __no_operation();                   // For debugger

     

       }

    Please help me!!!

  • I don't see your termination.

    What does the scope say?

  • Mr. Barkley;

    Thank you for your coming forward.

    There's 120 ohm resistor across A and B though I didn't show it in the picture. Is this the right answer?

    The scope probe was taking measurement directly off P5.0/UCA2TXD. The wave form is consistent.

    Sukho

  • That was the correct answer.

    Do you get any differential signal out of the unit?

    Can you give a clear description of the problem?

  • First off I recommend that you read "The Art and Science of RS-485" from the July 1999 issue of Circuit Cellar. (Google usually turns up a copy.)

    Second, the enable inputs of the 75176 tristate the outputs which means that when the receiver is disabled, the RX input of the UART is floating. You must use a pullup there for reliable operation.

    Third, as the article above shows, termination is more than just a 120 Ohm resistor.

  • But a 120 ohm resistor should work fine for as first cut, it just won't be failsafe.

    To the OP: Make sure you are driving *RE and DE correctly.

  • There's a slight change of the situation. I somehow started receiving the signals from the device. I don't know what happened. I send "M', "a', 'x', 'i', 'f'', 'l', 'o' and receive it at my PC TeraTerm, though I had to insert long delays at the beginning and in-between the characters. Otherwise, I receive only part of the message.

    I didn't set anything with regards, to DE/RE.

    But the device is not receiving anything sent from PC. The ISR never seems to be triggered.

    Here's the complete code.

    #include <msp430.h>

     

    int main(void)

    {

       WDTCTL = WDTPW | WDTHOLD;               // Stop Watchdog

     

      // Configure GPIO

       P5SEL0 &= ~(BIT0 | BIT1);

       P5SEL1 |= BIT0 | BIT1;                 // USCI_A0 UART operation

     

       // Disable the GPIO power-on default high-impedance mode to activate

       // previously configured port settings

       PM5CTL0 &= ~LOCKLPM5;

     

       // Startup clock system with max DCO setting ~8MHz

       CSCTL0_H = CSKEY_H;                     // Unlock CS registers

       CSCTL1 = DCOFSEL_3 | DCORSEL;           // Set DCO to 8MHz

       CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK;

       CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1;   // Set all dividers

       CSCTL0_H = 0;                           // Lock CS registers

     

       // Configure USCI_A0 for UART mode

       UCA2CTLW0 = UCSWRST;                   // Put eUSCI in reset

       UCA2CTLW0 |= UCSSEL__SMCLK;             // CLK = SMCLK

       // Baud Rate calculation

       // 8000000/(16*9600) = 52.083

       // Fractional portion = 0.083

       // User's Guide Table 24-4: UCBRSx = 0x04

       // UCBRFx = int ( (52.083-52)*16) = 1

       UCA2BRW = 52;                           // 8000000/16/9600

       UCA2MCTLW |= UCOS16 | UCBRF_1 | 0x4900;

       UCA2CTLW0 &= ~UCSWRST;                 // Initialize eUSCI

       UCA2IE |= UCRXIE;                       // Enable USCI_A0 RX interrupt

     

       __delay_cycles(100000);

       __delay_cycles(100000);

       __delay_cycles(100000);

     

       UCA2TXBUF='M';

       __delay_cycles(100000);

       UCA2TXBUF='a';

       __delay_cycles(100000);

       UCA2TXBUF='x';

       __delay_cycles(100000);

       UCA2TXBUF='i';

       __delay_cycles(100000);

       UCA2TXBUF='F';

       __delay_cycles(100000);

       UCA2TXBUF='l';

       __delay_cycles(100000);

       UCA2TXBUF='o';

     

       __bis_SR_register(LPM3_bits + GIE);     // Enter LPM3, interrupts enabled

       __no_operation();                       // For debugger

    }

     

    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)

    #pragma vector=EUSCI_A2_VECTOR

    __interrupt void USCI_A2_ISR(void)

    #elif defined(__GNUC__)

    void __attribute__ ((interrupt(EUSCI_A2_VECTOR))) USCI_A2_ISR (void)

    #else

    #error Compiler not supported!

    #endif

    {

       switch(__even_in_range(UCA2IV, USCI_UART_UCTXCPTIFG))

       {

           case USCI_NONE: break;

           case USCI_UART_UCRXIFG:

               while(!(UCA2IFG&UCTXIFG));

               UCA2TXBUF = UCA2RXBUF;

               __no_operation();

               break;

           case USCI_UART_UCTXIFG: break;

           case USCI_UART_UCSTTIFG: break;

           case USCI_UART_UCTXCPTIFG: break;

           default: break;

       }

    }

    Please let me know how to receive the data from PC. And I don't know how to use P5REN and DE/RE.

    I downloaded the "The Art and Science of RS-485" and am reading it now. But I don't think I'm skilled enough to absorb the necessary information in it. But I'll read it till the end.

  • "I didn't set anything with regards, to *DE/RE."

    There is why you cannot receive.  When transmitting *DE/RE (which are connected together) must be low to activate the transmitter and disable the receiver. When receiving, you have to set it high to activate the receiver and disable the transmitter.

    Do you really want to send and receive on the same data lines? I think it is a *much* better plan to run 2 sets of RS485, one to transmit and one to receive so can do both at the same time. Now you have to coordinate who is talking and listening so you don't try to have the MCU and PC sending data at the same time.

  • Hi. Mr. Barkley;

    That was it. 

    The TI sample code doesn't do anything about *DE/RE. Why do they provide such "USELESS SAMPLE CODE"? It's a serious trap for a young player like me.

    Any ways, I added this before transmit;

       P5DIR |=BIT2;

       P5OUT |=BIT2;

    After transmit;

     P5OUT &=~BIT2;

    Then after receiving and echoing back to PC;

       P5OUT |=BIT2;

    It's working now. Thank you.

    But I see another problems now. 

    They are

    1. If I don't insert long delays of '__delay_cycles(20000);' , only part of the bytes are received or much worse no data is received at all. Here, the example code fails me again.

    2. The last byte is not sent or doesn't appear to exist. For example

         if I send 'M', 'a', 'x', 'i', 'F', 'l' and 'o', I only receive "MaxiFl". The last byte 'o' doesn't come through.

        if  the PC sends just one byte, the device raises the Receive Interrupt and ISR is executed (like turning an LED on/off.). But no byte is echoed back to PC.

    Please help me one more time. Or do you think it's better to start a new question thread?

    __delay_cycles(20000);

  • The reason TI does nothing with the *DE/RE line is that the example is for the UART, and TI has no idea what hardware is attached. Most folks don't need it since they have full duplex. I, for one, will never need it since I will never try to send and receive over the same lines.

    Given that you share the 422 lines for RX and TX, you can't really echo a character, since you have no idea if another character is coming down the line. You really need some way to arbitrate the RS422 bus. Generally, it is done as a Master/Slave and one device (the slave) only responds when the master asks it to.

  • RS-485 is by definition half-duplex. It's most widely used industrial standard. 

    I understand that it's a must to have Master/Slave scheme in such networks and I have no qualm about that.

    But "Given that you share the 422 lines for RX and TX, you can't really echo a character, since you have no idea if another character is coming down the line." doesn't reflect the fact the "data received" interrupt was triggered. The receiver part received the data, and only after that shall it raise the interrupt. At least that's how I understand it. I'm not arguing with you. I'm just trying to understand what's there to know between the lines of your statement.

    I guess the delay part must have something to do with baud rate. I'll dig more into it.

  • Right, you receive the character and get the interrupt, but you cannot echo the character unless you know that the PC is not sending another character following the one you just received.

**Attention** This is a public forum