• AVR Freaks

Helpful ReplyHot!Reading 32 bit data through SPI using dsPIC33FJ series controller

Author
vijayakumar.sargunam
Starting Member
  • Total Posts : 40
  • Reward points : 0
  • Joined: 2012/10/12 22:59:47
  • Location: 0
  • Status: offline
2021/03/05 21:43:57 (permalink)
0

Reading 32 bit data through SPI using dsPIC33FJ series controller

I am interfacing energy meter IC (ATM90E32AS) with dsPIC33F series controller. I tried to read the power value from the energy meter IC. As per the data sheet power registers are 32 bits wide. There are 2 registers (MSB and LSB) each for all three phases for power measurement. I tried the following code to get the power value from IC but i am unsuccessful. Correct me if i done any thing wrong in the code. i read the phase B power value in the following code.
 
int PmB_read()
{
    CS=0;
    SPI2BUF=SBUF=0x80B2;
    while(SPI2STATbits.SPITBF==1){}
    SPI2BUF=0x0;
    
    while(SPI2STATbits.SPITBF==1){}
    delay();
    
    CS=1;
    HiByte = SPI2BUF;
    return HiByte;
}

int PmBLSB_read()
{
    CS=0;
    SPI2BUF=SBUF=0x80C2;
    while(SPI2STATbits.SPITBF==1){}
    SPI2BUF=0x0;
    while(SPI2STATbits.SPITBF==1){}
    delay();
    CS=1;
    LoByte = SPI2BUF;
    TPmB = (HiByte << 16)| LoByte;
    Total = TPmB * 0.00032;
    return Total;
}

[/code]
#1
GlennP
Super Member
  • Total Posts : 873
  • Reward points : 0
  • Joined: 2009/03/29 15:04:55
  • Location: El Paso County, CO, USA
  • Status: offline
Re: Reading 32 bit data through SPI using dsPIC33FJ series controller 2021/03/05 22:25:49 (permalink)
0
The information supplied is not sufficient for anyone to aid you.
 
You must show all configuration for the SPIx peripheral.
 
Also, you don't share HiByte and LoByte declarations.  If they are indeed bytes, then you cannot combine them as shown and get 32 bits.
#2
vijayakumar.sargunam
Starting Member
  • Total Posts : 40
  • Reward points : 0
  • Joined: 2012/10/12 22:59:47
  • Location: 0
  • Status: offline
Re: Reading 32 bit data through SPI using dsPIC33FJ series controller 2021/03/05 22:58:59 (permalink)
0
Hi Glenn,
 
             Thanks for your reply with this thread i included the code for SPI for interfacing with energy meter IC.
 
unsigned int Vr,Vy,Vb,Ir,Iy,Ib,In,kWH,SPICONValue,SPISTATValue,meter_read,meter_read1,dummy;
unsigned int spival[], Pa, Pb, Pc, PL_H, PL_L, acc, en, check,check_1, ff, SBUF, SBUF_2;
char read;
unsigned int ppp,qqq,rrr,LoByte,PmBLSB;
unsigned long PmA,PmB,PmC,PmT,HiByte,Total,TPmB;


void init_SPI()
{
 SPICONValue = ENABLE_SCK_PIN & FRAME_ENABLE_OFF & FRAME_SYNC_OUTPUT & ENABLE_SDO_PIN
 & SPI_MODE16_ON & SPI_SMP_OFF & SPI_CKE_OFF & SLAVE_ENABLE_OFF &
 CLK_POL_ACTIVE_HIGH & MASTER_ENABLE_ON & SEC_PRESCAL_1_1 &
 PRI_PRESCAL_64_1;
 SPISTATValue = SPI_ENABLE & SPI_IDLE_CON & SPI_RX_OVFLOW_CLR;
 SPI2CON1=SPICONValue;
 SPI2STAT=SPISTATValue;
 IEC2bits.SPI2IE=1;
}

void __attribute__ ((__interrupt__)) _SPI2Interrupt(void)
{ppp++;
 IFS2bits.SPI2IF=0;
 SPI2STATbits.SPIROV = 0;
 if(SPI2STATbits.SPIRBF==1)
  {qqq++;
  meter_read1++;
  if (meter_read1>1)
   {rrr++;
   

/* */
    if (SBUF==0x80D9)
     Vr=(SPI2BUF)/100;
    if (SBUF==0x80DA)
     Vy=(SPI2BUF)/100;
    if (SBUF==0x80DB)
     Vb=(SPI2BUF)/100;
    if (SBUF==0x80B2)
                                        PmB=SPI2BUF;
                                if (SBUF==0x80C2)
                                        PmBLSB=SPI2BUF;

    meter_read1=0;
   }
  else
   dummy=SPI2BUF;
  }
}
void m_read()
{
if (meter_read==0)
 Vr_read();
else if (meter_read==1)
 Vy_read();
else if (meter_read==2)
 Vb_read();
else if (meter_read==3)
    PmB_read();
else if (meter_read==4)
    PmBLSB_read();
}

void Vr_read()
 {
 CS=0;
 SPI2BUF=SBUF=0x80D9;
 while(SPI2STATbits.SPITBF==1){}
 SPI2BUF=0x0;
 while(SPI2STATbits.SPITBF==1){}
 delay_rx();
 CS=1;
 }
void Vy_read()
 {
 CS=0;
 SPI2BUF=SBUF=0x80DA;
 while(SPI2STATbits.SPITBF==1){}
 SPI2BUF=0x0;
 while(SPI2STATbits.SPITBF==1){}
 delay_rx();
 CS=1;
 }

void Vb_read()
 {
 CS=0;
 SPI2BUF=SBUF=0x80DB;
 while(SPI2STATbits.SPITBF==1){}
 SPI2BUF=0x0;
 while(SPI2STATbits.SPITBF==1){}
 delay_rx();
 CS=1;
 }

int PmB_read()
{
    CS=0;
    SPI2BUF=SBUF=0x80B2;
 while(SPI2STATbits.SPITBF==1){}
 SPI2BUF=0x0;
    
    while(SPI2STATbits.SPITBF==1){}
 delay_rx();
    
 CS=1;
    HiByte = SPI2BUF;
    return HiByte;
}

int PmBLSB_read()
{
    CS=0;
    SPI2BUF=SBUF=0x80C2;
 while(SPI2STATbits.SPITBF==1){}
 SPI2BUF=0x0;
    while(SPI2STATbits.SPITBF==1){}
 delay_rx();
    CS=1;
    LoByte = SPI2BUF;
    TPmB = (HiByte << 16)| LoByte;
    Total = TPmB * 0.00032;
    return Total;
}

void acc_write()
 {
 CS=0;
 SPI2BUF=0x007F;
 while(SPI2STATbits.SPITBF==1){}
 SPI2BUF=0x55AA;
 while(SPI2STATbits.SPITBF==1){}
 delay_rx();
 CS=1;
 }

void en_write()
 {
 CS=0;
 SPI2BUF=0x0000;
 while(SPI2STATbits.SPITBF==1){}
 //SPI2BUF=0xFF;
        SPI2BUF=0x01;
 while(SPI2STATbits.SPITBF==1){}
 delay_rx();
 CS=1;
 }
int main()
{

init_SPI();



CS=1;


acc_write();
en_write();


while(1)
{

if (read==1)
{
m_read();
meter_read++;
if (meter_read>5)
 meter_read=0;
read=0;
}
      

__asm__ ("CLRWDT");
}
}





 
 
#3
vijayakumar.sargunam
Starting Member
  • Total Posts : 40
  • Reward points : 0
  • Joined: 2012/10/12 22:59:47
  • Location: 0
  • Status: offline
Re: Reading 32 bit data through SPI using dsPIC33FJ series controller 2021/03/05 23:10:53 (permalink)
0
Hi Glenn,
 
             Thanks for your reply with this thread i included the code for SPI for interfacing with energy meter IC.
 
unsigned int Vr,Vy,Vb,Ir,Iy,Ib,In,kWH,SPICONValue,SPISTATValue,meter_read,meter_read1,dummy;
unsigned int spival[], Pa, Pb, Pc, PL_H, PL_L, acc, en, check,check_1, ff, SBUF, SBUF_2;
char read;
unsigned int ppp,qqq,rrr,LoByte,PmBLSB;
unsigned long PmA,PmB,PmC,PmT,HiByte,Total,TPmB;


void init_SPI()
{
 SPICONValue = ENABLE_SCK_PIN & FRAME_ENABLE_OFF & FRAME_SYNC_OUTPUT & ENABLE_SDO_PIN
 & SPI_MODE16_ON & SPI_SMP_OFF & SPI_CKE_OFF & SLAVE_ENABLE_OFF &
 CLK_POL_ACTIVE_HIGH & MASTER_ENABLE_ON & SEC_PRESCAL_1_1 &
 PRI_PRESCAL_64_1;
 SPISTATValue = SPI_ENABLE & SPI_IDLE_CON & SPI_RX_OVFLOW_CLR;
 SPI2CON1=SPICONValue;
 SPI2STAT=SPISTATValue;
 IEC2bits.SPI2IE=1;
}

void __attribute__ ((__interrupt__)) _SPI2Interrupt(void)
{ppp++;
 IFS2bits.SPI2IF=0;
 SPI2STATbits.SPIROV = 0;
 if(SPI2STATbits.SPIRBF==1)
  {qqq++;
  meter_read1++;
  if (meter_read1>1)
   {rrr++;
   

/* */
    if (SBUF==0x80D9)
     Vr=(SPI2BUF)/100;
    if (SBUF==0x80DA)
     Vy=(SPI2BUF)/100;
    if (SBUF==0x80DB)
     Vb=(SPI2BUF)/100;
    if (SBUF==0x80B2)
                                        PmB=SPI2BUF;
                                if (SBUF==0x80C2)
                                        PmBLSB=SPI2BUF;

    meter_read1=0;
   }
  else
   dummy=SPI2BUF;
  }
}
void m_read()
{
if (meter_read==0)
 Vr_read();
else if (meter_read==1)
 Vy_read();
else if (meter_read==2)
 Vb_read();
else if (meter_read==3)
    PmB_read();
else if (meter_read==4)
    PmBLSB_read();
}

void Vr_read()
 {
 CS=0;
 SPI2BUF=SBUF=0x80D9;
 while(SPI2STATbits.SPITBF==1){}
 SPI2BUF=0x0;
 while(SPI2STATbits.SPITBF==1){}
 delay_rx();
 CS=1;
 }
void Vy_read()
 {
 CS=0;
 SPI2BUF=SBUF=0x80DA;
 while(SPI2STATbits.SPITBF==1){}
 SPI2BUF=0x0;
 while(SPI2STATbits.SPITBF==1){}
 delay_rx();
 CS=1;
 }

void Vb_read()
 {
 CS=0;
 SPI2BUF=SBUF=0x80DB;
 while(SPI2STATbits.SPITBF==1){}
 SPI2BUF=0x0;
 while(SPI2STATbits.SPITBF==1){}
 delay_rx();
 CS=1;
 }

int PmB_read()
{
    CS=0;
    SPI2BUF=SBUF=0x80B2;
 while(SPI2STATbits.SPITBF==1){}
 SPI2BUF=0x0;
    
    while(SPI2STATbits.SPITBF==1){}
 delay_rx();
    
 CS=1;
    HiByte = SPI2BUF;
    return HiByte;
}

int PmBLSB_read()
{
    CS=0;
    SPI2BUF=SBUF=0x80C2;
 while(SPI2STATbits.SPITBF==1){}
 SPI2BUF=0x0;
    while(SPI2STATbits.SPITBF==1){}
 delay_rx();
    CS=1;
    LoByte = SPI2BUF;
    TPmB = (HiByte << 16)| LoByte;
    Total = TPmB * 0.00032;
    return Total;
}

void acc_write()
 {
 CS=0;
 SPI2BUF=0x007F;
 while(SPI2STATbits.SPITBF==1){}
 SPI2BUF=0x55AA;
 while(SPI2STATbits.SPITBF==1){}
 delay_rx();
 CS=1;
 }

void en_write()
 {
 CS=0;
 SPI2BUF=0x0000;
 while(SPI2STATbits.SPITBF==1){}
 //SPI2BUF=0xFF;
        SPI2BUF=0x01;
 while(SPI2STATbits.SPITBF==1){}
 delay_rx();
 CS=1;
 }
int main()
{

init_SPI();



CS=1;


acc_write();
en_write();


while(1)
{

if (read==1)
{
m_read();
meter_read++;
if (meter_read>5)
 meter_read=0;
read=0;
}
      

__asm__ ("CLRWDT");
}
}


#4
GlennP
Super Member
  • Total Posts : 873
  • Reward points : 0
  • Joined: 2009/03/29 15:04:55
  • Location: El Paso County, CO, USA
  • Status: offline
Re: Reading 32 bit data through SPI using dsPIC33FJ series controller 2021/03/05 23:37:39 (permalink)
0
That's better, but I suggest you don't call "unsigned int" variables LoByte and HiByte.  It confuses reader and may confuse you someday.
 
Also, it appears ppp, qqq, and rrr are counters of some kind.  Using descriptive names help there too. ff is declared but I could not find a reference when searching visually.
 
The sequence of tests of "meter_read" would be easier to read if you use a switch/case statement construct.  But I guess the counter would be better being replaced by a sequence of function invocations but can't tell quickly.
 
The various Vx_read routines seems like you could parameterize them into a single routine providing the write value (e.g. 0x80DB) as a parameter.  Similarly for the PmX_read functions.  When you have fewer lines of code it's easier for you and reviewers (and it makes compiling and loading faster).
 
Don't introduce variables (especially globals) when they are not needed.  For instance:
SPISTATValue = SPI_ENABLE & SPI_IDLE_CON & SPI_RX_OVFLOW_CLR;
...
SPI2STAT=SPISTATValue;

 
is more complex and longer than:
SPI2STAT = SPI_ENABLE & SPI_IDLE_CON & SPI_RX_OVFLOW_CLR;

 
The main program has a while loop that executes forever.  But only the first pass does anything due to the "if (read==1) test.
 
Calculating (for instance) the various Vx-es, you perform integer divisions by 100.  Is that appropriate?  Any fraction will be lost.
 
What is the use of the '1' variants?  meter_read vs. meter_read1 for instance.  Surely you can make more self-documenting names.
 
Use a consistent style for naming.  You use underbars (meter_read), case (LoByte), suffexes (1), ... .
 
Also use consistent indenting to make the code easier to read.  Fifteen minutes cleaning up stuff that seems trivial will go a long way to make the program understandable.
 
Finally, what does "I am unsuccessful" mean?  Does the program hang?  Do you have Endian problems?  Are the results incorrect?
#5
ric
Super Member
  • Total Posts : 30244
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: offline
Re: Reading 32 bit data through SPI using dsPIC33FJ series controller 2021/03/06 00:13:29 (permalink)
0
I can't see any code for delay_rx()
Is it waiting for SPIRBF to go high?
 

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#6
vijayakumar.sargunam
Starting Member
  • Total Posts : 40
  • Reward points : 0
  • Joined: 2012/10/12 22:59:47
  • Location: 0
  • Status: offline
Re: Reading 32 bit data through SPI using dsPIC33FJ series controller 2021/03/06 00:26:27 (permalink)
0
Hi Glenn thank you will implement as you suggested. I actually read the voltage and current value i got voltage value as 231V and current value as 21A. but when i read the power value (only MSB) i got the value as 195. As per the basic power calculation it should be 231 x 21 (VxI) the value will be 4851. but i am getting only 195. I have doubt over what iam getting is correct or not?. And also as per the data sheet the power registers are 32-bits wide. But as per my program i think i am reading only 16 bits of data in MSB (PmeanA).  Plz correct me if i am wrong. And suggest me what changes to be made in the code to correct it.

Attached Image(s)

#7
vijayakumar.sargunam
Starting Member
  • Total Posts : 40
  • Reward points : 0
  • Joined: 2012/10/12 22:59:47
  • Location: 0
  • Status: offline
Re: Reading 32 bit data through SPI using dsPIC33FJ series controller 2021/03/06 00:32:22 (permalink)
0
Hi ric,
           This is my delay routine. Yes it is waiting for SPIRBF to go high.
 
void delay_rx()
 {
  int i;
  for(i=0;i<200;i++);
 }

       
 
post edited by vijayakumar.sargunam - 2021/03/06 00:34:52
#8
ric
Super Member
  • Total Posts : 30244
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: offline
Re: Reading 32 bit data through SPI using dsPIC33FJ series controller 2021/03/06 00:41:09 (permalink)
0
vijayakumar.sargunam
Hi ric,
           This is my delay routine.

That is a bad way to implement a delay.
If you don't qualify the variable as "volatile", the compiler is free to totally optimise the whole delay away.
That is why XC8 comes with built in delay macros to give precise delays.

Yes it is waiting for SPIRBF to go high.

Where?
None of the code you have shown tests that bit.
If you correctly check that bit, you should not need a time based delay at all.,
 

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#9
GlennP
Super Member
  • Total Posts : 873
  • Reward points : 0
  • Joined: 2009/03/29 15:04:55
  • Location: El Paso County, CO, USA
  • Status: offline
Re: Reading 32 bit data through SPI using dsPIC33FJ series controller 2021/03/06 00:45:36 (permalink) ☄ Helpfulby vijayakumar.sargunam 2021/03/06 01:41:44
0
The value of 195 * 65536 * 0.00032 is about 4089.  So if you include the LO 16 bits it could be as high as 4110 (=196*65536*0.00032).  This could be correct, depending on the power factor.
 
Post the code after you get it cleaned up and it will be easier for us to understand.
#10
GlennP
Super Member
  • Total Posts : 873
  • Reward points : 0
  • Joined: 2009/03/29 15:04:55
  • Location: El Paso County, CO, USA
  • Status: offline
Re: Reading 32 bit data through SPI using dsPIC33FJ series controller 2021/03/06 00:54:08 (permalink)
0
I think the test is in the loop immediately before delay is called (at least in one place - hence the reason to consolidate all the SPI sequences) - thus making the delay (working or not) of no important consequence.
 
And since the bit is tested (at least in many places), there is no reason to enable interrupts or write an interrupt handler.
#11
ric
Super Member
  • Total Posts : 30244
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: offline
Re: Reading 32 bit data through SPI using dsPIC33FJ series controller 2021/03/06 01:07:30 (permalink)
0
SPIRBF is NOT tested in the transfer routines posted here.
There is a test for it in an interrupt service, but that is irrelevant. This code is disabling CS without a check for SPIRBF. It doesn't make sense to have an interrupt service elsewhere to read the data.
 

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#12
GlennP
Super Member
  • Total Posts : 873
  • Reward points : 0
  • Joined: 2009/03/29 15:04:55
  • Location: El Paso County, CO, USA
  • Status: offline
Re: Reading 32 bit data through SPI using dsPIC33FJ series controller 2021/03/06 01:23:33 (permalink)
0
ricSPIRBF is NOT tested in the transfer routines posted here.  ...



What was I thinking, disagreeing with Mr. ric.
 
I misread and thought SPITBF.  My bad.
 
GP
#13
vijayakumar.sargunam
Starting Member
  • Total Posts : 40
  • Reward points : 0
  • Joined: 2012/10/12 22:59:47
  • Location: 0
  • Status: offline
Re: Reading 32 bit data through SPI using dsPIC33FJ series controller 2021/03/06 01:51:38 (permalink)
0
Hi Glenn,
          I took another reading and i got voltage value as 232V ad current 20 A and power value as 185. And as per the general power calculation VxI it should be 4600 approx. but by the formula it will comes around 3900 (186 * 65536 * 0.00032) including LSB. The difference is around 700. Is it ok?
#14
ric
Super Member
  • Total Posts : 30244
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: offline
Re: Reading 32 bit data through SPI using dsPIC33FJ series controller 2021/03/06 04:02:41 (permalink)
0
vijayakumar.sargunam
And as per the general power calculation VxI it should be 4600 approx.

Power is only VxI if voltage and current are "in phase", i.e. if the power factor is "1".
That will only happen with a purely resistive load. What is your load?
 

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#15
vijayakumar.sargunam
Starting Member
  • Total Posts : 40
  • Reward points : 0
  • Joined: 2012/10/12 22:59:47
  • Location: 0
  • Status: offline
Re: Reading 32 bit data through SPI using dsPIC33FJ series controller 2021/03/08 03:42:04 (permalink)
0
Hi ric,
        my load is purely resistive.
#16
GlennP
Super Member
  • Total Posts : 873
  • Reward points : 0
  • Joined: 2009/03/29 15:04:55
  • Location: El Paso County, CO, USA
  • Status: offline
Re: Reading 32 bit data through SPI using dsPIC33FJ series controller 2021/03/09 14:19:41 (permalink)
0
vijayakumar.sargunam
... my load is purely resistive.



If your load is purely resistive (Power Factor = 1.0), then those measurements are too far off.
 
When you've finished the cleanup of the code, post it for further help.
#17
Jump to:
© 2021 APG vNext Commercial Version 4.5