ช่วยดู code stm32 ติดต่อ ADE7763 energy meter มีปัญหา

Started by tha, July 17, 2013, 02:47:41 PM

Previous topic - Next topic

tha

ผมกำลังทำโปรเจ็คใช้ stm32 ติดต่ออ่านค่าจาก ADE7763 energy meter กำลังเพิ่งเริ่มเขียนโปรแกรมติดต่อให้อ่านค่า register VRMS, IRMS, AENERGY โดยโหลดของ ADE7763 เป็นหลอดไฟ 100w แต่ค่าที่ได้ไม่ตรงกับค่าที่ควรจะเป็น ลองอ่านเขียนกับ register อื่นก็อ่านค่าได้ไม่ตรงกับค่าที่เป็น default ซึ่งการติดต่อระหว่าง stm32 กับ ADE7763 เป็นแบบ SPI ผมก็เช็คดู timing diagram ของการ write และ read ของ ADE7763 แล้วเขียนโปรแกรมดู ซึ่งผมว่าปัญหาน่าจะมาจากการที่ผมเขียนโปรแกรมไม่ถูกต้อง ท่านใดพอจะช่วยตรวจเช็ค code ให้ผมหน่อยได้ไหมครับ
http://www.analog.com/en/analog-to-digital-converters/energy-measurement/ade7763/products/product.html

รูป board



/******************** (C) COPYRIGHT 2008 STMicroelectronics ********************
* File Name          : main.c
* Author             : MCD Application Team
* Version            : V2.0.1
* Date               : 06/13/2008
* Description        : Main program body
********************************************************************************
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*******************************************************************************/
/* Private define ------------------------------------------------------------*/


/* Includes ------------------------------------------------------------------*/
#include "stm32f10x_lib.h"
#include <stdio.h>
//#include <math.h>
#include "platform_config.h"
#include "GLCD5110.H"

/* Private typedef -----------------------------------------------------------*/

#define SPI_FLAG_RXNE           SPI_I2S_FLAG_RXNE
#define SPI_FLAG_TXE            SPI_I2S_FLAG_TXE
//#define SPI_FLAG_CRCERR                    ((u16)0x0010)
//#define SPI_FLAG_MODF                      ((u16)0x0020)
#define SPI_FLAG_OVR            SPI_I2S_FLAG_OVR
#define SPI_FLAG_BSY            SPI_I2S_FLAG_BSY
//----------------------------------------------
#define SPI_GetFlagStatus       SPI_I2S_GetFlagStatus
#define SPI_SendData            SPI_I2S_SendData
#define SPI_ReceiveData         SPI_I2S_ReceiveData

#define  CS_H()    GPIO_WriteBit(GPIOB,GPIO_Pin_12,Bit_SET)
#define  CS_L() GPIO_WriteBit(GPIOB,GPIO_Pin_12,Bit_RESET)

#define  WAVEFORM       0x01
#define  AENERGY       0x02
#define  VAENERGY     0x05
#define  MODE             0x09
#define  IRQEN             0x0A
#define  IRMS              0x16
#define  VRMS             0x17
#define  LINECYC         0x1C
#define  SAGCYC         0x1E

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
//GPIO_InitTypeDef GPIO_InitStructure;
ErrorStatus HSEStartUpStatus;
static vu32 TimingDelay;

char str[20];                          // Keep string convert

s32 AE = 0, W =0;
u32 VA =0, I =0, V =0;
u16 M;
u8 b;

/* Private function prototypes -----------------------------------------------*/
void RCC_Configuration(void);
void NVIC_Configuration(void);
void SPI_Configuration(void);
void GPIO_Configuration(void);
void delay(void);

//void DelayuS(vu32 nCount); // 1uS Delay
void DelayuS(vu32 nTime); // 1uS Delay
void TimingDelay_Decrement(void);

u8 SPI_Send_Byte(u8);
u8 SPI_RD_Reg(u8);
u16 SPI_RD_Reg16(u8);
u32 SPI_RD_Reg24(u8);
void SPI_WR_Reg8(u8, u8);
void SPI_WR_Reg16(u8, u16 );

/* Private functions ---------------------------------------------------------*/
/** read out parameters cal_param from BMP085 memory
   \return result of communication routines
*/

/*******************************************************************************
* Function Name  : main
* Description    : Main program.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
int main(void)
{

#ifdef DEBUG
  debug();
#endif

  /* System Clocks Configuration **********************************************/
  RCC_Configuration();   

  /* NVIC Configuration *******************************************************/
  NVIC_Configuration();

/* I/O init */
  GPIO_Configuration();

SPI_Configuration();

/* SysTick end of count event each 1ms with input clock equal to 9MHz (HCLK/8, default) */
  SysTick_SetReload(9);

  /* Enable SysTick interrupt */
  SysTick_ITConfig(ENABLE);

lcdString(1,1,"Energy Meter  "); // Set message on line 1
  lcdUpdate();  // Display message
DelayuS(100000);

//SPI_WR_Reg16(MODE, 12);
SPI_WR_Reg8(SAGCYC, 7);
DelayuS(20000);

while(1)
{
     
       /*AE = SPI_RD_Reg(AENERGY);
           sprintf(str,"AE : %d  ", AE);
           lcdString(1,2,str); // Set message on line 4
           lcdUpdate();  // Display message
      DelayuS(20000);
       VA = SPI_RD_Reg(VAENERGY);
           sprintf(str,"VA : %d  ", VA);
           lcdString(1,3,str); // Set message on line 4
           lcdUpdate();  // Display message
      DelayuS(20000); 
       I = SPI_RD_Reg24(IRMS);
           sprintf(str,"I : %d  ", I);
           lcdString(1,4,str); // Set message on line 4
           lcdUpdate();  // Display message
      DelayuS(20000);  */
      /*V = SPI_RD_Reg(VRMS);
           sprintf(str,"V : %d  ", V);
           lcdString(1,5,str); // Set message on line 4
           lcdUpdate();  // Display message
       DelayuS(20000);
       W = SPI_RD_Reg(WAVEFORM);
           sprintf(str,"AE : %d  ", W);
           lcdString(1,6,str); // Set message on line 4
           lcdUpdate();  // Display message  */
b = SPI_RD_Reg(IRQEN);
sprintf(str,"IRQEN : %d  ", b);
           lcdString(1,3,str); // Set message on line 4
           lcdUpdate();  // Display message
DelayuS(20000);
b = SPI_RD_Reg(SAGCYC);
sprintf(str,"SAG : %d  ", b);
           lcdString(1,4,str); // Set message on line 4
           lcdUpdate();  // Display message
DelayuS(20000);
  M = SPI_RD_Reg16(LINECYC);
           sprintf(str,"LINE : %d  ", M);
           lcdString(1,5,str); // Set message on line 4
           lcdUpdate();  // Display message
DelayuS(20000);
M = SPI_RD_Reg16(MODE);
           sprintf(str,"MODE : %d  ", M);
           lcdString(1,6,str); // Set message on line 4
           lcdUpdate();  // Display message

      DelayuS(200000);
}
}

/*******************************************************************************
* Function Name  : RCC_Configuration
* Description    : Configures the different system clocks.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void RCC_Configuration(void)
{   
  /* RCC system reset(for debug purpose) */
  RCC_DeInit();

  /* Enable HSE */
  RCC_HSEConfig(RCC_HSE_ON);

  /* Wait till HSE is ready */
  HSEStartUpStatus = RCC_WaitForHSEStartUp();

  if(HSEStartUpStatus == SUCCESS)
  {
    /* Enable Prefetch Buffer */
    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

    /* Flash 2 wait state */
    FLASH_SetLatency(FLASH_Latency_2);

    /* HCLK = SYSCLK */
    RCC_HCLKConfig(RCC_SYSCLK_Div1);
 
    /* PCLK2 = HCLK */
    RCC_PCLK2Config(RCC_HCLK_Div1);

    /* PCLK1 = HCLK/2 */
    RCC_PCLK1Config(RCC_HCLK_Div2);

    /* PLLCLK = 8MHz * 9 = 72 MHz */
    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);

    /* Enable PLL */
    RCC_PLLCmd(ENABLE);

    /* Wait till PLL is ready */
    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
    {
    }

    /* Select PLL as system clock source */
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

    /* Wait till PLL is used as system clock source */
    while(RCC_GetSYSCLKSource() != 0x08)
    {
    }
  }
}

void GPIO_Configuration(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
   
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

/* Configure SPI2 pins: SCK, MISO and MOSI */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOB, &GPIO_InitStructure);

// SPI ship select  CS
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOB, &GPIO_InitStructure);

}

void SPI_Configuration(void)
{
  SPI_InitTypeDef  SPI_InitStructure;

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
 
  /* SPI2 configuration */
  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;//SPI_CPOL_High=ģʽ3£¬Ê±ÖÓ¿ÕÏÐΪ¸ß //SPI_CPOL_Low=ģʽ0£¬Ê±ÖÓ¿ÕÏÐΪµÍ
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;//SPI_CPHA_2Edge;//SPI_CPHA_1Edge, SPI_CPHA_2Edge;
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;//SPI_NSS_Soft;//SPI_NSS_Hard
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;//SPI_BaudRatePrescaler_2=18M;//SPI_BaudRatePrescaler_4=9MHz
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//Êý¾Ý´Ó¸ßλ¿ªÊ¼·¢ËÍ
  SPI_InitStructure.SPI_CRCPolynomial = 7;
 
  SPI_Init(SPI2, &SPI_InitStructure);
  /* Enable SPI2  */
  SPI_Cmd(SPI2, ENABLE);   
}

/*******************************************************************************
* Function Name  : SPI_FLASH_SendByte
* Description    : Sends a byte through the SPI interface and return the byte
*                  received from the SPI bus.
* Input          : byte : byte to send.
* Output         : None
* Return         : The value of the received byte.
*******************************************************************************/
u8 SPI_Send_Byte(u8 dat)
{
  /* Loop while DR register in not emplty */
  while(SPI_GetFlagStatus(SPI2, SPI_FLAG_TXE) == RESET);

  /* Send byte through the SPI2 peripheral */
  SPI_SendData(SPI2, dat);

  /* Wait to receive a byte */
  while(SPI_GetFlagStatus(SPI2, SPI_FLAG_RXNE) == RESET);

  /* Return the byte read from the SPI bus */
  return SPI_ReceiveData(SPI2);
}

/*******************************************************************************
* Function Name  : Serial Read 24 bits Command
* Description    : 
*                 
* Input          : byte : byte to send.
* Output         : None
* Return         : The value of the received byte.
*******************************************************************************/
u8 SPI_RD_Reg(u8 reg)
{
u8 valve;
CS_L();                // CS low, initialize SPI communication...
SPI_Send_Byte(reg);            // Select register to read from..
DelayuS(5);
valve= SPI_Send_Byte(0);    // ..then read registervalue
CS_H();                // CS high, terminate SPI communication

return(valve);        // return register value
}

u16 SPI_RD_Reg16(u8 reg)
{
u16 valve;
u16 valve1;
CS_L();                // CS low, initialize SPI communication...
SPI_Send_Byte(reg);            // Select register to read from..
DelayuS(5);
valve= SPI_Send_Byte(0);    // ..then read registervalue
valve1 = valve<<8;
valve = SPI_Send_Byte(0);    // ..then read registervalue
valve1 +=valve;
CS_H();                // CS high, terminate SPI communication

return(valve1);        // return register value
}

u32 SPI_RD_Reg24(u8 reg)
{
u32 reg_val;

CS_L();                // CS low, initialize SPI communication...
SPI_Send_Byte(reg);            // Select register to read from..
DelayuS(4);
reg_val = SPI_Send_Byte(0)<<16;    // ..then read registervalue
reg_val += SPI_Send_Byte(0)<<8;    // ..then read registervalue
reg_val += SPI_Send_Byte(0);    // ..then read registervalue
CS_H();                // CS high, terminate SPI communication

return(reg_val);        // return register value
}

void SPI_WR_Reg8(u8 reg, u8 value)
{
CS_L();                   // CSN low, init SPI transaction
SPI_Send_Byte(reg |0x80);// select register
DelayuS(4);
SPI_Send_Byte(value);             // ..and write value to it..
CS_H();                   // CSN high again
}

void SPI_WR_Reg16(u8 reg, u16 value)
{
CS_L();                   // CSN low, init SPI transaction
SPI_Send_Byte(reg |0x80);// select register
DelayuS(4);
SPI_Send_Byte(value>>8);             // ..and write value to it..
DelayuS(4);
SPI_Send_Byte(value);             // ..and write value to it..
CS_H();                   // CSN high again
}


/*******************************************************************************
* Function Name  : NVIC_Configuration
* Description    : Configures Vector Table base location.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void NVIC_Configuration(void)
{
//NVIC_InitTypeDef NVIC_InitStructure;

#ifdef  VECT_TAB_RAM 
  /* Set the Vector Table base location at 0x20000000 */
  NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else  /* VECT_TAB_FLASH  */
  /* Set the Vector Table base location at 0x08000000 */
  NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   
#endif

// 2 bits for Preemption Priority and 2 bits for Sub Priority
   //NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

/*NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQChannel;
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
   NVIC_Init(&NVIC_InitStructure);

NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel;
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
   NVIC_Init(&NVIC_InitStructure); */

  // Set SysTick interrupt vector Preemption Priority to 1
   //NVIC_SystemHandlerPriorityConfig(SystemHandler_SysTick, 1, 0);
}

/*******************************************************************************
* Function Name  : Delay
* Description    : Inserts a delay time.
* Input          : nCount: specifies the delay time length.
* Output         : None
* Return         : None
*******************************************************************************/
/*void DelayuS(vu32 nCount)

  while (nCount--);
} */

/*******************************************************************************
* Function Name  : Delay
* Description    : Inserts a delay time.
* Input          : nTime: specifies the delay time length, in milliseconds.
* Output         : None
* Return         : None
*******************************************************************************/
void DelayuS(u32 nTime)
{
  /* Enable the SysTick Counter */
  SysTick_CounterCmd(SysTick_Counter_Enable);
 
  TimingDelay = nTime;

  while(TimingDelay != 0);

  /* Disable SysTick Counter */
  SysTick_CounterCmd(SysTick_Counter_Disable);
  /* Clear SysTick Counter */
  SysTick_CounterCmd(SysTick_Counter_Clear);
}

/*******************************************************************************
* Function Name  : TimingDelay_Decrement
* Description    : Decrements the TimingDelay variable.
* Input          : None
* Output         : TimingDelay
* Return         : None
*******************************************************************************/
void TimingDelay_Decrement(void)
{
  if (TimingDelay != 0x00)
  {
    TimingDelay--;
  }
}

#ifdef  DEBUG
/*******************************************************************************
* Function Name  : assert_failed
* Description    : Reports the name of the source file and the source line number
*                  where the assert_param error has occurred.
* Input          : - file: pointer to the source file name
*                  - line: assert_param error line source number
* Output         : None
* Return         : None
*******************************************************************************/
void assert_failed(u8* file, u32 line)
{
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

  /* Infinite loop */
  while (1)
  {
  }
}
#endif

/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/


wlasoi

อาการแบบนี้ เหมือนกับว่าสื่อสารกันได้แต่อ่านค่าผิด .. สันณิษฐานเบื้องต้น .. ดูก่อนว่า SPI ที่ใช้ในการเชื่อมต่อ Mode เดียวกันหรือไม่ .. SPI มี 4 mode ครับ .. ตั้งฝั่ง MCU ให้ตรงกับฝั่ง Device

tha

data sheet บอกว่า
"Data Output for the Serial Interface. Data is shifted out at this pin upon the rising edge of SCLK.
DIN Data Input for the Serial Interface. Data is shifted in at this pin upon the falling edge of SCLK."
ก็ลองสลับ CPOL กับ CPHA ไปทุก mode แล้ว mode นี้ดีที่สุด ดู timing diagram ประกอบแล้วด้วย ก็ยังไม่ได้อีกครับ


tha

ทำได้แล้วครับ ผมเปลี่ยนไปใช้ IO ทำเป็น serial interface ซึ่งทำให้ตรงกับ timing diagram ของ ADE7763 สามารถอ่านค่าจาก register ต่างๆออกมาได้ ขั้นต่อไปคงจะยากหน่อย เพราะต้อง set ค่า parameter ต่างๆ ให้มันอ่านค่าได้ใกล้เคียงกับค่าจริง ขอบคุณครับที่ช่วยกันดู

void SPI_Send ( u8 data)
{
u8 j,data_in;
   
    data_in = data;
    for ( j = 0; j <8; j++ )
    {
      GPIO_WriteBit(GPIOC,GPIO_Pin_8,Bit_SET);
         if ((data_in & 0x80)!=0)
         {
            GPIO_WriteBit(GPIOC,GPIO_Pin_10,Bit_SET);
         }
         else
         {
            GPIO_WriteBit(GPIOC,GPIO_Pin_10,Bit_RESET);
         }
data_in=data_in<<1;
   GPIO_WriteBit(GPIOC,GPIO_Pin_8,Bit_RESET);
   }
}

u8 SPI_Receive (void)
{
u8 j,data_in=0;
   
    for ( j = 0; j <8; j++ )
    {
      GPIO_WriteBit(GPIOC,GPIO_Pin_8,Bit_SET);
  data_in=data_in<<1;
          if(GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_9) == Bit_SET)
            {
               data_in +=1;
            }
         else
           {
              data_in +=0;
           }
   
    GPIO_WriteBit(GPIOC,GPIO_Pin_8,Bit_RESET);
    }
return(data_in);
}

wlasoi

 ;D  mode ผิดจริงๆ แหละ  ถ้ามีเวลาก็ แก้ SPI จะได้ศึกษาไปในตัวด้วย ครับ .. จะดีกว่า shift-bit ธรรมดา

tha

เขาเขียนไว้ว่า SPI -compatible serial interface ไม่ได้บอกว่าเป็น mode ไหนครับ อ่านคู่มือและดู timing diagram แล้ว DIN กับ DOUT ก็เป็นคนละ mode กัน
-DIN, data is shifted into the ADE7763 at the DIN logic input upon the falling edge of SCLK. ส่วน CPHA(Clock Phase) ดูจาก timing Diagram แล้วก็ทำงานที่ขอบขาที่สอง
-DOUT, data is shifted out of the ADE7763 at DOUT logic output upon a rising edge of SCLK. ส่วน CPHA(clock phase) ดูจาก timing diagram แล้วจะทำงานที่ขอบขาแรกครับ
ผมก็ลองเปลี่ยน CPOL(clock polarity) กับ CPHA(clock phase) ไปครบทั้ง 4 mode แล้วก็ไม่ได้ครับ ลองเปลี่ยน IN กับ OUT คนละ mode กันก็ไม่ได้อีก ไม่รู้มันจะเกี่ยวกับไฟของ stm32 เป็น 3.3v ส่วน ADE7763 เป็น 5v หรือเปล่าก็ไม่ทราบ แต่ขา port ผมก็ใช้ขาที่่เป็น 5v terelance แล้ว แต่พอผมเปลี่ยนวิธีมาใช้ serial interface แบบ bit shifted แล้ว ก็สามารถทำงานได้ปกติเลยครับ 
ก็ไม่รู้ว่าที่ data sheet บอกว่า SPI -compatible serial interface มันคือ mode ไหนก็ไม่รู้เหมือนกันครับท่าน wlasoi แต่ยังไงก็ได้แล้วครับแบบ bit shifted ก็ไม่มีปัญหาอะไร ปัญหาต่อไปคือจะทำยังไง calibrate มันเพราะไม่มี volt source, current source มาจ่ายไฟเพื่อ calibrate หรือ kwh meter มาวัดค่าเปรียบเทียบครับ

wlasoi

Volt ไม่เท่าไหร่ หา Variac ปรับได้ ...  แต่ current source .. สิเป็นปัญหา  ;D

tha

เดี๋ยวจะใช้หลอดใส้ 100w , w=vi, i = 100w/230v = 0.43478 A  , ทางด้าน secondary ของ CT ratio 1:1000 = 0.43478A/1000*20ohm = 8.695mV
ส่วน volt 230v ลดทอนสัญญานลง 230v*1k/(820k+820K+1k) = 140mV ต้องแปลงค่ากันอีกมากเลย อ่าน data sheet ไปรอบหนึ่งชักจะลืมแล้ว  >:(