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-EXP430FR5994: MSP-EXP430FR5994

Part Number: MSP-EXP430FR5994
Other Parts Discussed in Thread: MSP430FR5994, MSP430WARE

Hello dear community!

I'm trying to manage the SPI communication between the MSP430FR5994 and ADE7878 energy metering IC from Analog Devices. Everything works good while i'm testing my code on the LaunchPad . I connect the SIMO and SOMI wires together and i can see the data i'm sending on the logic analyzer and store the received data into my variables. The problem beginns when i'm interfacing the IC. I'm able to write to the registers, i can see the correct data on the logic analyzer and measure the changes on my evaluation board. When i try to preform the read operation, i can see the IC returning the correct data on the SOMI line.  My problem is that i'm reading the wrong data from UCB1RXBUF, its almost always 0xFF. Sometimes when i read 1byte registers, i receive the correct value. I would be very thankful if someone could give me a hint how to manage this issue.

Thanks in advance!

Illya


    #include <msp430.h>
    #include <string.h>

    #define DUMMY                      0x00
    #define CONFIG2                   0xEC01
    #define STATUS1                    0xE503
    #define RUN                            0xE228
    #define LAST_OP                   0xE7FD
    #define LAST_ADDR             0xE6FE
    #define LAST_RWDATA_8    0xE7FC
    #define LAST_RWDATA_16  0xE6FF
    #define LAST_RWDATA_32  0xE5FF
    #define PGA                             0xE60F
    #define COMPMODE              0xE60E
    #define WTHR1                       0x43AB
    #define WTHR0                       0x43AA
    #define VLEVEL                       0x43B3
    #define IARMS_LRIP              0xE531
    #define VARMS_LRIP             0xE531

    void send (unsigned int addr, char nr_bytes, unsigned long tx_data);
    unsigned volatile char byte1, byte2, byte3, byte4;

    void read (unsigned int addr, char nr_bytes);
    volatile unsigned char  rx1, rx2, rx3, rx4;

    unsigned char SPI_8(unsigned char TXdata);
    unsigned volatile char TXdata;
    unsigned volatile char RXdata;

    void SPI_enable(void);
    void SPI_disable(void);

    void init(void);

    volatile int counter1=0;
    volatile int counter2 = 0;

    int main(void)
    {


    WDTCTL = WDTPW | WDTHOLD;                         // Stop watchdog timer


    P5SEL1 &= ~(BIT0 | BIT1 | BIT2);                  // USCI_B1 SCLK, MOSI, and MISO pin
    P5SEL0 |= (BIT0 | BIT1 | BIT2);                      // USCI_B1 SCLK, MOSI, and MISO pin
    P6DIR  |= BIT3;                                                 // P6.3 OUT Csn

    P3DIR  &=  ~BIT7;                                          // CF3_HSCLK_EXT
    P3DIR  &=  ~BIT6;                                          // CF2_HREADY_EXT
    P3DIR  &=  ~BIT5;                                          // CF1_EXT
    P4DIR  |=   BIT1;                                             // P4.1 PM0
    P4DIR  |=   BIT2;                                             // P4.2 PM1
    P4OUT  |=   BIT1;                                            // P4.1 PM0 HIGH
    P4OUT  &=  ~BIT2;                                         // P4.2 PM1 LOW
    P4DIR  &=  ~BIT3;                                          // P4.3 IRQ0B
    P2DIR  &=  ~BIT5;                                          // P2.5 IRQ1B
    P8DIR  |=   BIT3;                                             // P8.3 RESB_CTRL  not sold

    PM5CTL0 &= ~LOCKLPM5;                         //Disable the GPIO power-on default high-impedance mode to activate previously configured port settings


    UCB1CTLW0 = UCSWRST;                                                         // **Put state machine in reset**
    UCB1CTLW0 |= UCMST | UCSYNC |UCCKPL | UCMSB;      // MASTER|Synchronous mode|inactive state-high|MSB first
    UCB1CTLW0 &= ~UCCKPH;                                                       // Data changed on first UCLK, captured on following ???

    UCB1CTLW0 |= UCSSEL__ACLK;                                             // ACLK
    UCB1BRW = 0x04;                                                                        // /2
    //UCB1MCTLW = 0;                                                                        // No modulation
    UCB1CTLW0 &= ~UCSWRST;                                                    // **Initialize USCI state machine**
    UCB1IE |= UCRXIE;                                                                       // Enable receive interrupt
    UCB1IE |= UCTXIE;                                                                        // Enable transmit interrupt
  

  //************************************************************************************************************//

    init();

    read(STATUS1,       4 );    
    read(COMPMODE, 2 );  
    read(RUN,               2 );
    read(WTHR1,          4 );
    read(WTHR0,          4 );
    read(PGA,                2 );
    read(VLEVEL,          4);


}

unsigned char SPI_8(unsigned char TXdata)
{
    while(UCB1STATW & UCBUSY);      
    UCB1TXBUF = TXdata;

    while(UCB1STATW & UCBUSY);      
    RXdata = UCB1RXBUF;
    return (RXdata);
}

void send (unsigned int addr, char nr_bytes, unsigned long tx_data)
{
    unsigned char reg1, reg2;
    reg1 = (addr >> 8)&0xFF;
    reg2 = addr & 0xFF ;

    switch(nr_bytes)
    {
        case 1:
        byte1 = tx_data & 0xFF;


        SPI_enable();
        SPI_8(0x00);
        SPI_8(reg1);
        SPI_8(reg2);
        SPI_8(byte1);
        SPI_disable();

        break;

        case 2:
        byte1 = (tx_data >> 8)&0xFF;
        byte2 = tx_data & 0xFF;
        SPI_enable();
        SPI_8(0x00);
        SPI_8(reg1);
        SPI_8(reg2);
        SPI_8(byte1);
        SPI_8(byte2);
        SPI_disable();
        break;

        case 3:
        byte1 = (tx_data >> 16)&0xFF;
        byte2 = (tx_data >> 8 )&0xFF;
        byte3 = tx_data & 0xFF;
        SPI_enable();
        SPI_8(0x00);
        SPI_8(reg1);
        SPI_8(reg2);
        SPI_8(byte1);
        SPI_8(byte2);
        SPI_8(byte3);
        SPI_disable();
        break;

        case 4:
        byte1 = (tx_data >> 24)&0xFF;
        byte2 = (tx_data >> 16)&0xFF;
        byte3 = (tx_data >> 8)&0xFF;
        byte4 = tx_data & 0xFF;
        SPI_enable();
        SPI_8(0x00);
        SPI_8(reg1);
        SPI_8(reg2);
        SPI_8(byte1);
        SPI_8(byte2);
        SPI_8(byte3);
        SPI_8(byte4);
        SPI_disable();
        break;

        default:
        break;
    }

}
void read (unsigned int addr, char nr_bytes)
{
    unsigned char reg1, reg2;
    reg1 = (addr >> 8)&0xFF;
    reg2 = addr & 0xFF ;

    switch(nr_bytes)
    {
        case 1:
        SPI_enable();
        SPI_8(0x01);
        SPI_8(reg1);
        SPI_8(reg2);
        rx1 = SPI_8(DUMMY);
        SPI_disable();
        break;

        case 2:
        SPI_enable();
        SPI_8(0x01);
        SPI_8(reg1);
        SPI_8(reg2);
        rx1 = SPI_8(DUMMY);
        rx2 = SPI_8(DUMMY);
        SPI_disable();
        break;

        case 3:
        SPI_enable();
        SPI_8(0x01);
        SPI_8(reg1);
        SPI_8(reg2);
        rx1 = SPI_8(DUMMY);
        rx2 = SPI_8(DUMMY);
        rx3 = SPI_8(DUMMY);
        SPI_disable();
        break;

        case 4:
        SPI_enable();
        SPI_8(0x01);
        SPI_8(reg1);
        SPI_8(reg2);
        rx1 = SPI_8(DUMMY);
        rx2 = SPI_8(DUMMY);
        rx3 = SPI_8(DUMMY);
        rx4 = SPI_8(DUMMY);
        SPI_disable();
        break;

        default:
        break;
    }

}

void SPI_enable(void)
{
    P6OUT &= ~BIT3;
}

void SPI_disable(void)
{
    P6OUT  |=  BIT3;
}

void init(void)
{
    SPI_enable();       
    SPI_disable();
    SPI_enable();
    SPI_disable();
    SPI_enable();
    SPI_disable();

    for(counter1 = 0 ; counter1 < 10; counter1 ++)
    {
        send(CONFIG2, 1, 0x00000000);
    }

    send(STATUS1,       4, 0x00208000); 
    send(COMPMODE, 2, 0x000000FF);   
    send(RUN,               2, 0x00000001);
    send(WTHR1,          4, 0x00000001);
    send(WTHR0,          4, 0x00FF6A6B);
    send(PGA,                2, 0x00000000);
    send(VLEVEL,         4, 0x000A9B4A);

}




  • Hello Illya,

    If I understand your description, everything works with a launchpad, but when you connect the launchpad to ADE7858 you don't read the correct data? When you are not connected to the ADE7858, how are you able to read correct data? What are you reading data from?

    It sounds like an issue with the clock phase.
    Have you tried UCB1CTLW0 |=UCCKPH; ?
  • Hello Dennis, thanks a lot for your message!

    My launchpad is connected to the ADE7878 evaluation board, i have my logic analyzer connected in parallel  so i can see the data i'm sending from the MSP and the respond of the ADE7878. Thank you for your hint about the clock phase, i've checked it again and i think that its correct. Below is a short outtake from the datasheet:

    " A read operation using the SPI interface is initiated when the master sets the SS pin low...The master sends data on the MOSI line starting with the first high to low transition of SCLK. The SPI of the ADE7878A samples the data on the low to high transitions of SCLK...After the ADE7878A receive the last bit of the register address on a low to high transition of SCLK, it begins to transmit the register contents on the MISO line when the next SCLK high to low transition occurs; the master samples the data on a low to high SCLK transition. After the master receives the last bit, it sets the SS and SCLK lines high, and the communication ends.

    I see on my logic analyzer that the energymeter responds correctly, for example i perform a read operation on the 32bit register that represents the measured RMS Voltage and if i convert the obtained hex value i'm getting the voltage that i apply on the ADE7878 (8.3V). Below is the screenshot of the logic analyzer:

    And that's what i'm getting in my variable scope:

    Instead of getting 0x00 / 0x01 / 0x89 / 0x99 (is what i see in Logic Analyzer), i'm reading 0x00 / 0x01 / 0xFF / 0xFF.  I assume that i have some mistakes in my code. Since the writing part is functioning, i assume that the read function is not correct. My idea was to create a function SPI_8 that sends one byte and in the next step it saves the value of the RX buffer in the RXdata variable. Then i save this value in one of the global variables rx1...rx4. I've tried to perform the read operation over the ISR but since i'm new to embedded programming I'm not getting it working correctly. I would be very thankfull if you could look over it and tell me if something is wrong. Thanks a lot for your support and have a great weekend! (p.s. i will be able to reply on tuesday first)

    Below are the main parts of my code:

    #include <msp430.h>
    #define CONFIG2  0xEC01
    #define DUMMY     0x00

        void read (unsigned int addr, char nr_bytes);
        volatile unsigned char  rx1, rx2, rx3, rx4;                   //Global variables to store the RX buffer values

        unsigned char SPI_8(unsigned char TXdata);
        unsigned volatile char TXdata;                                  //Transmited byte
        unsigned volatile char RXdata;                                 //Received     byte

        void SPI_enable(void);
        void SPI_disable(void);


        int main(void)
        {

        WDTCTL = WDTPW | WDTHOLD;                                              // Stop watchdog timer


        P5SEL1 &= ~(BIT0 | BIT1 | BIT2);                                                // USCI_B1 SCLK, MOSI, and MISO pin
        P5SEL0 |= (BIT0 | BIT1 | BIT2);                                                    // USCI_B1 SCLK, MOSI, and MISO pin
        P6DIR  |= BIT3;                                                                               // P6.3 OUT Csn

        PM5CTL0 &= ~LOCKLPM5;                                                         //Disable the GPIO power-on default high-impedance mode to activate previously configured port settings
       
        UCB1CTLW0 = UCSWRST;                                                         // **Put state machine in reset**
        UCB1CTLW0 |= UCMST | UCSYNC |UCCKPL | UCMSB;      // MASTER|Synchronous mode|inactive state-high|MSB first
        UCB1CTLW0 &= ~UCCKPH;                                                      // Data changed on first UCLK, captured on following

        UCB1CTLW0 |= UCSSEL__ACLK;                                             // ACLK
        UCB1BRW = 0x02;                                                                        // /2
        UCB1CTLW0 &= ~UCSWRST;                                                    // **Initialize USCI state machine**
        UCB1IE |= UCRXIE;                                                                       // Enable receive interrupt
        UCB1IE |= UCTXIE;                                                                        // Enable transmit interrupt

    while(1);
    {
    read(CONFIG2, 1)
    }

    }

    void SPI_enable(void)
    {
        P6OUT &= ~BIT3;
    }

    void SPI_disable(void)
    {
        P6OUT  |=  BIT3;
    }

    unsigned char SPI_8(unsigned char TXdata)
    {
        while(UCB1STATW & UCBUSY);           
        UCB1TXBUF = TXdata;
       
        while(UCB1STATW & UCBUSY);         
        RXdata = UCB1RXBUF;
        return (RXdata);

    void read (unsigned int addr, char nr_bytes)
    {
        unsigned char reg1, reg2;
        reg1 = (addr >> 8)&0xFF;
        reg2 = addr & 0xFF ;

        switch(nr_bytes)
        {
            case 1:
            SPI_enable();
            SPI_8(0x01);
            SPI_8(reg1);
            SPI_8(reg2);
            rx1 = SPI_8(DUMMY);
            SPI_disable();
            break;

            case 2:
            SPI_enable();
            SPI_8(0x01);
            SPI_8(reg1);
            SPI_8(reg2);
            rx1 = SPI_8(DUMMY);
            rx2 = SPI_8(DUMMY);
            SPI_disable();
            break;

            case 3:
            SPI_enable();
            SPI_8(0x01);
            SPI_8(reg1);
            SPI_8(reg2);
            rx1 = SPI_8(DUMMY);
            rx2 = SPI_8(DUMMY);
            rx3 = SPI_8(DUMMY);
            SPI_disable();
            break;

            case 4:
            SPI_enable();
            SPI_8(0x01);
            SPI_8(reg1);
            SPI_8(reg2);
            rx1 = SPI_8(DUMMY);
            rx2 = SPI_8(DUMMY);
            rx3 = SPI_8(DUMMY);
            rx4 = SPI_8(DUMMY);
            SPI_disable();
            break;

            default:
            break;
        }

  • Hi Illya,

    I copied your code and programmed an MSP430FR5994 launchpad.

    I modified a couple of lines in your main loop:

       while(1)

       {

           read(CONFIG2, 4);

           _delay_cycles(1000);

       }

    The master writes the 3 bytes (0x01 and addrs 0xE5E1), followed by 4 dummy bytes.

    I then programmed a second MSP430FR5994 launchpad with SPI slave code that always responds with 7 bytes {0x00, 0x01, 0x02, 0x03, 0x04, 0x05,0x06} ( one for each byte received).

    Here is what I see on the SPI pins:

    I then checked the 4 bytes received in your code and it shows it captured them correctly.

  • Hello Dennis,

    thanks a lot for taking your time and helping me!

    I can't figure out the reason of the problem by now. I know that i can send data to the IC an that i'm reading the correct respond from the IC on the SOMI pin of my MSP on my logic analyzer. For some reason i still can't store the data from the RX buffer into a variable. Perhaps a interrupt based solution would work better? I'm trying to modify the example code from msp430ware but by now without any success. Could you please tell me what am i doing wrong? I'm trying to send 4 bytes and read the RX buffer at the end of the transition. Thanks a lot, i appreciate your help!

    Illya

        #include <msp430.h>
        volatile unsigned char RXData = 0;
        volatile unsigned char TXData;
        void SPI_8(unsigned char TXData);
        volatile unsigned char rx1;
        int main(void)
        {

        WDTCTL = WDTPW | WDTHOLD;                         // Stop watchdog timer


        P5SEL1 &= ~(BIT0 | BIT1 | BIT2);                     // USCI_B1 SCLK, MOSI, and MISO pin
        P5SEL0 |= (BIT0 | BIT1 | BIT2);                         // USCI_B1 SCLK, MOSI, and MISO pin
        P6DIR  |= BIT3;                                                    // P6.3 OUT Csn
        PM5CTL0 &= ~LOCKLPM5;                              //Disable the GPIO power-on default high-impedance mode to activate previously configured port settings

        UCB0CTLW0 = UCSWRST;                                                         // **Put state machine in reset**
        UCB0CTLW0 |= UCMST | UCSYNC |UCCKPL | UCMSB;      // MASTER|Synchronous mode|inactive state-high|MSB first
        UCB0CTLW0 &= ~UCCKPH;                                                       // Data changed on first UCLK, captured on following ???

        UCB0CTLW0 |= UCSSEL__ACLK;                                            // ACLK
        UCB0BRW = 0x02;                                                                        // /2
        UCB0CTLW0 &= ~UCSWRST;                                                    // **Initialize USCI state machine**

        UCB0IE |= UCTXIE;
        __bis_SR_register(GIE);

        while(1)
        {
            UCB1IE |= UCTXIE;
            TXData = 0x01;
            TXData = 0xEC;
            TXData = 0x01;
            TXData = 0x00;
            rx1 = RXData;
        }
        }



    #pragma vector=EUSCI_B1_VECTOR
    __interrupt void USCI_B1_ISR(void)
    {
        switch(__even_in_range(UCB1IV, USCI_SPI_UCTXIFG))
        {
            case USCI_NONE: break;

            case USCI_SPI_UCRXIFG:
                RXData = UCB1RXBUF;
                UCB1IFG &= ~UCRXIFG;
                break;

            case USCI_SPI_UCTXIFG:
                UCB1TXBUF = TXData;
                UCB1IE &= ~UCTXIE;
                break;
            default: break;
        }
    }    

  • Hi Illya,

    Before attempting this with interrupts, let's try a "loop-back" setup:

    Short the SOMI and MISO pins coming from the MSP430.

    Modify your code in the switch statement so you send out 4 payload bytes 0x01, 0x02, 0x03, 0x04.
    case 4:
    SPI_enable();
    SPI_8(0x01);
    SPI_8(reg1);
    SPI_8(reg2);
    rx1 = SPI_8(0x01);
    rx2 = SPI_8(0x02);
    rx3 = SPI_8(0x03);
    rx4 = SPI_8(0x04);
    SPI_disable();
    break;

    Set a break point just after the call (you can use a _no_operation() to set the break point on)
    read(CONFIG2, 4);
    _no_operation();

    After the call, examine your rx1, rx2, rx3, rx4. You should see the values you transmitted.
    I tried this and it works for me.
  • Hello Dennis!

    thank you for your reply! I've tried it before and it is working for me aswell. Thats why i'm wondering why i can't read the data from the IC, but i can receive the data while shorting MOSI and MISO. The data that is coming from IC looks very good on the scope - no noise, good timing, good voltage level.

    Kind regards

    Illya

  • Ok,

    It's possible that the rise/fall time of the data may be affected by additional capacitance on the connections between the MSP and the sensor. When you tie the SOMI and SIMO together, the lines are very short. The logic analyzer can decode the data because it's input thresholds may be different compared to the MSP430. Try reducing the clock rate by a factor or 2 or 4 and see if that makes the difference.
  • Hello Dennis,

    i've connected the MISO pin straight to the IC output and i've tried different ACLK dividers form 1 to 32. The MSP reads the data correctly if its 0x00 only, sometimes it reads the second byte correctly that differs from 0x00. In any case are the last 2 bytes always 0xFF.

    Kind regards

    Illya

  • Hello Dennis,

    i've written the same programm in Arduino and it works fine on the same setup, so i assume that i'm doing something wrong with my code. 

    Best regards

    Illya

  • Hi Illya,

    Ok. I'm curious why I was able to make your code work on my launchpad.

    Did you still need help to get this working on the MSP430FR5994 platform or are you going to move on?
  • Hello Dennis,

    i'm curious as well. When i test my code on the launchpad it works just fine (when i short MOSI and MISO) but as soon as i connect my board to the IC i get troubles. I've managed to write a new code based on the ISR. And again, i'm able to send the data, i'm getting the respond from the ADE7878 and i can't store that values.

    I need help to get it working on this platform, arduino was just a quick possibility to check if it is working properly. I simply need the program the can send and receive one byte.

    Kind regards

    Illya

  • Hello Dennis,

    i've found the problem and it's not due to the code. The metering IC is galvanically isolated from the MSP, if i connect the microcontroller directly to the ic, everything works fine. Now i'm trying to understand the reason for this behaviour. Do you have any ideas? Thanks a lot for your help!

    Kind regards

    Illya

  • Interesting...

    By what means is the galvanic isolation provided?
  • Hello Dennis,

    the isolation is provided by :

    4x - Analog Devices/ADuM3401CRWZ

    1x - Analog Devices/ADuM1250ARZ

    they separate all microcontroller IOs from the ADE7878

    Kind regards

    Illya

  • Hi Illya,

    I reviewed the Analog devices datasheet looking for some electrical spec violation (rise/fall, propagation time, clock rate, etc) but didn't see anything obvious. The thing that is really perplexing is your logic probe capture showing the correct data on the I2C bus ( I assume captured on the MSP430 side of the isolators). The only other thing you might try, if you have an oscilloscope, is to scope the SDA and SCL lines on the MSP430 side and look very closely at the rise and fall of the SCL and see that the SDA data coming from the isolator is stable and the correct logic level on the edge the I2C reads the bit. I say this because the logic probe may skew that data timing because of its thresholds when It detects a '1' or '0'.

    Other than that, I don't know what to tell you. Perhaps someone else in the community can offer some suggestions.
  • Hello Dennis, 

    thaks a lot for your help and the time you have spent for it. I will try to replace the Isolators to different ones and see if it will make any changes.

    Best regards 

    Illya

**Attention** This is a public forum