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.
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 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;
}
}
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
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
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
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
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