为什么 I2C_read_Register-Function 只适用于某些寄存器,而不适用于所有寄存器?

问题描述 投票:0回答:0

我目前正在尝试开发脉搏血氧仪。为此,我使用 MAX30102 传感器和 NXP LPC1768 微控制器。

通信通过 I2C 运行。

我的问题是MAX30102的2个寄存器的内容总是0x00。但是,当我读取其他寄存器时,它们具有匹配的内容。我现在的猜测是 I2C-read_register() 函数有问题。

关于此的一些背景信息: MAX30102 有一个用于存储数据的 FIFO。为了在这个 FIFO 缓冲区中存储和读取,有一个 FIFO 写指针(指向 MAX30102 写入下一个样本的位置)和一个 FIFO 读指针(指向处理器从 FIFO 获取下一个样本的位置)。

现在我想通过 I2C 读取 FIFO Read Pointer 和 FIFO Write Pointer。 通过 I2C 读取 MAX30102 的其他寄存器工作正常!例如。 Die Temp Integer Register,或 FIFO Config Register(我之前在其中写入数据)。 但只要我读取 FIFO 读指针和 FIFO 写指针寄存器,我就会得到值 0x00。 代码如下:

i2c.h:

`/****************************************************************************
 *   $Id:: i2c.h 5865 2010-12-08 21:42:21Z usb00423                         $
 *   Project: NXP LPC17xx I2C example
 *
 *   Description:
 *     This file contains I2C code header definition.
 *
 ****************************************************************************
 * Software that is described herein is for illustrative purposes only
 * which provides customers with programming information regarding the
 * products. This software is supplied "AS IS" without any warranties.
 * NXP Semiconductors assumes no responsibility or liability for the
 * use of the software, conveys no license or title under any patent,
 * copyright, or mask work right to the product. NXP Semiconductors
 * reserves the right to make changes in the software without
 * notification. NXP Semiconductors also make no representation or
 * warranty that such application will be suitable for the specified
 * use without further testing or modification.
****************************************************************************/

#ifndef __I2C_H 
#define __I2C_H

#include <stdint.h>
#include "LPC17xx.h"

#define FAST_MODE_PLUS      0

#define I2C_PORT_NUM        3
#define BUFSIZE             64  
#define MAX_TIMEOUT         0x00FFFFFF

static LPC_I2C_TypeDef (* const LPC_I2C[I2C_PORT_NUM]) = { LPC_I2C0, LPC_I2C1, LPC_I2C2 };  

#define I2CMASTER           0x01
#define I2CSLAVE            0x02

#define PCF8594_ADDR        0xA0
#define READ_WRITE          0x01

#define MAX30102_WR_ADDR 0xAE
#define MAX30102_RD_ADDR 0xAF

#define RD_BIT              0x01

#define I2C_IDLE              0
#define I2C_STARTED           1
#define I2C_RESTARTED         2
#define I2C_REPEATED_START    3
#define DATA_ACK              4
#define DATA_NACK             5
#define I2C_BUSY              6
#define I2C_NO_DATA           7
#define I2C_NACK_ON_ADDRESS   8
#define I2C_NACK_ON_DATA      9
#define I2C_ARBITRATION_LOST  10
#define I2C_TIME_OUT          11
#define I2C_OK                12

#define I2CONSET_I2EN       (0x1<<6)  /* I2C Control Set Register */
#define I2CONSET_AA         (0x1<<2)
#define I2CONSET_SI         (0x1<<3)
#define I2CONSET_STO        (0x1<<4)
#define I2CONSET_STA        (0x1<<5)

#define I2CONCLR_AAC        (0x1<<2)  /* I2C Control clear Register */
#define I2CONCLR_SIC        (0x1<<3)
#define I2CONCLR_STAC       (0x1<<5)
#define I2CONCLR_I2ENC      (0x1<<6)

#define I2DAT_I2C           0x00000000  /* I2C Data Reg */
#define I2ADR_I2C           0x00000000  /* I2C Slave Address Reg */
#define I2SCLH_SCLH         0x00000080  /* I2C SCL Duty Cycle High Reg */
#define I2SCLL_SCLL         0x00000080  /* I2C SCL Duty Cycle Low Reg */
#define I2SCLH_HS_SCLH      0x00000008  /* Fast Plus I2C SCL Duty Cycle High Reg */
#define I2SCLL_HS_SCLL      0x00000008  /* Fast Plus I2C SCL Duty Cycle Low Reg */



extern void I2C0_IRQHandler( void );
extern void I2C1_IRQHandler( void );
extern void I2C2_IRQHandler( void );
extern void I2C0Init( void );
extern void I2C1Init( void );
extern void I2C2Init( void );
extern uint32_t I2CStart( uint32_t portNum );
extern uint32_t I2CStop( uint32_t portNum );
extern uint32_t I2CEngine( uint32_t portNum );


#endif /* end __I2C_H */`

i2c.c

~~~ 
/****************************************************************************
$Id:: i2c.c 5865 2010-12-08 21:42:21Z usb00423                         $
Project: NXP LPC17xx I2C example

Description:This file contains I2C code example which include I2C initialization, I2C interrupt handler, and APIs for I2C access.Software that is described herein is for illustrative purposes only which provides customers with programming information regarding the products. This software is supplied "AS IS" without any warranties. NXP Semiconductors assumes no responsibility or liability for the use of the software, conveys no license or title under any patent, copyright, or mask work right to the product. NXP Semiconductors reserves the right to  take changes in the software without notification. NXP Semiconductors also make no representation or warranty that such application will be suitable for the specified use without further testing or modification.
****************************************************************************/  
#include "type.h"
#include "lpc17xx.h"
#include "i2c.h"

volatile uint32_t I2CMasterState[I2C_PORT_NUM] = {I2C_IDLE,I2C_IDLE,I2C_IDLE};volatile uint32_t timeout[I2C_PORT_NUM] = {0, 0, 0};
volatile uint8_t I2CMasterBuffer[I2C_PORT_NUM][BUFSIZE];
volatile uint8_t I2CSlaveBuffer[I2C_PORT_NUM][BUFSIZE];
volatile uint32_t I2CCount[I2C_PORT_NUM] = {0, 0, 0};
volatile uint32_t I2CReadLength[I2C_PORT_NUM];
volatile uint32_t I2CWriteLength[I2C_PORT_NUM];
volatile uint32_t RdIndex0 = 0, RdIndex1 = 0, RdIndex2 = 0;
volatile uint32_t WrIndex0 = 0, WrIndex1 = 0, WrIndex2 = 0;

void I2C0_IRQHandler(void)
{   
uint8_t StatValue;

timeout[0] = 0;
/* this handler deals with master read and master write only */

StatValue = LPC_I2C0->I2STAT;

switch ( StatValue ){
case 0x08:          /* A Start condition is issued. */
WrIndex0 = 0;LPC_I2C0->I2DAT = I2CMasterBuffer[0][WrIndex0++];
LPC_I2C0->I2CONCLR = (I2CONCLR_SIC | I2CONCLR_STAC);
break;

case 0x10:          /* A repeated started is issued */
RdIndex0 = 0;
/* Send SLA with R bit set, */
LPC_I2C0->I2DAT = I2CMasterBuffer[0][WrIndex0++];
LPC_I2C0->I2CONCLR = (I2CONCLR_SIC | I2CONCLR_STAC);
break;

case 0x18:          /* Regardless, it's a ACK */
if ( I2CWriteLength[0] == 1 )
{
  LPC_I2C0->I2CONSET = I2CONSET_STO;      /* Set Stop flag */
  I2CMasterState[0] = I2C_NO_DATA;
}
else
{
  LPC_I2C0->I2DAT = I2CMasterBuffer[0][WrIndex0++];
}
LPC_I2C0->I2CONCLR = I2CONCLR_SIC;
break;

case 0x28:  /* Data byte has been transmitted, regardless ACK or NACK */
if ( WrIndex0 < I2CWriteLength[0] )
{   
  LPC_I2C0->I2DAT = I2CMasterBuffer[0][WrIndex0++]; /* this should be the last one */
}
else
{
  if ( I2CReadLength[0] != 0 )
  {
    LPC_I2C0->I2CONSET = I2CONSET_STA;  /* Set Repeated-start flag */
  }
  else
  {
    LPC_I2C0->I2CONSET = I2CONSET_STO;      /* Set Stop flag */
    I2CMasterState[0] = I2C_OK;
  }
}
LPC_I2C0->I2CONCLR = I2CONCLR_SIC;
break;

case 0x30:
LPC_I2C0->I2CONSET = I2CONSET_STO;      /* Set Stop flag */
I2CMasterState[0] = I2C_NACK_ON_DATA;
LPC_I2C0->I2CONCLR = I2CONCLR_SIC;
break;

case 0x40:  /* Master Receive, SLA_R has been sent */
if ( (RdIndex0 + 1) < I2CReadLength[0] )
{
  /* Will go to State 0x50 */
  LPC_I2C0->I2CONSET = I2CONSET_AA; /* assert ACK after data is received */
}
else
{
  /* Will go to State 0x58 */
  LPC_I2C0->I2CONCLR = I2CONCLR_AAC;    /* assert NACK after data is received */
}
LPC_I2C0->I2CONCLR = I2CONCLR_SIC;
break;

case 0x50:  /* Data byte has been received, regardless following ACK or NACK */
I2CSlaveBuffer[0][RdIndex0++] = LPC_I2C0->I2DAT;
if ( (RdIndex0 + 1) < I2CReadLength[0] )
{   
  LPC_I2C0->I2CONSET = I2CONSET_AA; /* assert ACK after data is received */
}
else
{
  LPC_I2C0->I2CONCLR = I2CONCLR_AAC;    /* assert NACK on last byte */
}
LPC_I2C0->I2CONCLR = I2CONCLR_SIC;
break;

case 0x58:
I2CSlaveBuffer[0][RdIndex0++] = LPC_I2C0->I2DAT;
I2CMasterState[0] = I2C_OK;
LPC_I2C0->I2CONSET = I2CONSET_STO;  /* Set Stop flag */ 
LPC_I2C0->I2CONCLR = I2CONCLR_SIC;  /* Clear SI flag */
break;

case 0x20:      /* regardless, it's a NACK */
case 0x48:
LPC_I2C0->I2CONSET = I2CONSET_STO;      /* Set Stop flag */
I2CMasterState[0] = I2C_NACK_ON_ADDRESS;
LPC_I2C0->I2CONCLR = I2CONCLR_SIC;
break;

case 0x38:      /* Arbitration lost, in this example, we don't
                deal with multiple master situation */
default:
I2CMasterState[0] = I2C_ARBITRATION_LOST;
LPC_I2C0->I2CONCLR = I2CONCLR_SIC;  
break;
}
return;
}

uint32_t I2CStart( uint32_t portNum )
{
  uint32_t retVal = FALSE;
 
  timeout[portNum] = 0;
  /*--- Issue a start condition ---*/
  LPC_I2C[portNum]->I2CONSET = I2CONSET_STA;    /* Set Start flag */
    
  /*--- Wait until START transmitted ---*/
  while( 1 )
  {
    if ( I2CMasterState[portNum] == I2C_STARTED )
    {
      retVal = TRUE;
      break;    
    }
    if ( timeout[portNum] >= MAX_TIMEOUT )
    {
      retVal = FALSE;
      break;
    }
    timeout[portNum]++;
  }
  return( retVal );
}

uint32_t I2CStop( uint32_t portNum )
{
  LPC_I2C[portNum]->I2CONSET = I2CONSET_STO;      /* Set Stop flag */ 
  LPC_I2C[portNum]->I2CONCLR = I2CONCLR_SIC;  /* Clear SI flag */ 
            
  /*--- Wait for STOP detected ---*/
  while( LPC_I2C[portNum]->I2CONSET & I2CONSET_STO );
  return TRUE;
}

oid I2C0Init( void ) 
{
  LPC_SC->PCONP |= (1 << 7);

  /* set PIO0.27 and PIO0.28 to I2C0 SDA and SCL */
  /* function to 01 on both SDA and SCL. */
  LPC_PINCON->PINSEL1 &= ~((0x03<<22)|(0x03<<24));
  LPC_PINCON->PINSEL1 |= ((0x01<<22)|(0x01<<24));   
 
  /*--- Clear flags ---*/
  LPC_I2C0->I2CONCLR = I2CONCLR_AAC | I2CONCLR_SIC | I2CONCLR_STAC | I2CONCLR_I2ENC;    

  /*--- Reset registers ---*/
  /*--- Reset registers ---*/
#if FAST_MODE_PLUS
  LPC_PINCON->I2CPADCFG |= ((0x1<<0)|(0x1<<2));
  LPC_I2C0->I2SCLL   = I2SCLL_HS_SCLL;
  LPC_I2C0->I2SCLH   = I2SCLH_HS_SCLH;
#else
  LPC_PINCON->I2CPADCFG &= ~((0x1<<0)|(0x1<<2));
  /*LPC_I2C0->I2SCLL   = I2SCLL_SCLL;
  LPC_I2C0->I2SCLH   = I2SCLH_SCLH;*/
    LPC_I2C0->I2SCLL   = 0x20;
  LPC_I2C0->I2SCLH   = 0x1F;
#endif

  /* Install interrupt handler */
  NVIC_EnableIRQ(I2C0_IRQn);

  LPC_I2C0->I2CONSET = I2CONSET_I2EN;
  return;
}


uint32_t I2CEngine( uint32_t portNum ) 
{
  /*--- Issue a start condition ---*/
  LPC_I2C[portNum]->I2CONSET = I2CONSET_STA;    /* Set Start flag */

  I2CMasterState[portNum] = I2C_BUSY;   

  while ( I2CMasterState[portNum] == I2C_BUSY )
  {
    if ( timeout[portNum] >= MAX_TIMEOUT )
    {
      I2CMasterState[portNum] = I2C_TIME_OUT;
      break;
    }
    timeout[portNum]++;
  }
  LPC_I2C[portNum]->I2CONCLR = I2CONCLR_STAC;

  return ( I2CMasterState[portNum] );
}

max30102.h

~~~
#ifndef __MAX30102_HPP#define __MAX30102_HPP

//Status 
#define FIFO_WR_PTR 0x04 
#define OVF_CNTR_REG 0x05 
#define FIFO_RD_PTR 0x06 
#define FIFO_DATA_REG 0x07

//Configuration Registers 
#define FIFO_CONFIG_REG 0x08 
#define MODE_CONFIG_REG 0x09 
#define SPO2_CONFIG_REG 0x0A 
#define LED_PULSE_AMPL_1    0x0C 
#define LED_PULSE_AMPL_2    0x0D 
#define MULTI_LED_CONTR_REG_1 0x11 
#define MULTI_LED_CONTR_REG_2 0x12

//MAX30102 I2C Address 
#define MAX30102_WR_ADDR 0xAE 
#define MAX30102_RD_ADDR 0xAF

#define PORT_USED   0

#include <stdbool.h>
#include <stdint.h> 
#include <string.h> 
#include "i2c.h"

bool max30102_init(uint8_t Mode); 
bool max30102_read_reg(uint8_t reg_addr, uint8_t *data); 
bool max30102_write_reg(uint8_t reg_addr, uint8_t data);

bool getReadPointer(uint8_t *data); 
bool getWritePointer(uint8_t *data);

typedef struct Sensor_Readings { 
uint32_t red[4]; 
uint32_t IR[4]; 
unsigned char head; 
unsigned char tail; 
}readings_struct;           //Buffer für Daten von dem Sensor

#endif //__MAX30102_HPP `

max30102.c

~~~
include <stdbool.h>
#include <stdint.h>
#include "MAX30102.h"
extern volatile uint8_t I2CMasterBuffer[I2C_PORT_NUM][BUFSIZE];
extern volatile uint8_t I2CSlaveBuffer[I2C_PORT_NUM][BUFSIZE];
extern volatile uint32_t I2CReadLength[I2C_PORT_NUM];
extern volatile uint32_t I2CWriteLength[I2C_PORT_NUM];
volatile uint8_t MAX30102_Mode;
readings_struct readings;

bool max30102_init(uint8_t Mode)
{
    ...
}

bool max30102_read_reg(uint8_t reg_addr, uint8_t *data)
{
  uint8_t i = 0;
  //clear Buffer
  for (i = 0; i < BUFSIZE; i++ )
  {
        I2CMasterBuffer[PORT_USED][i] = 0;
  }

/* Write SLA(W), address, SLA(R), and read one byte back. */
I2CWriteLength[PORT_USED] = 2;
I2CReadLength[PORT_USED] = 1;                                           
I2CMasterBuffer[PORT_USED][0] = MAX30102_WR_ADDR;
I2CMasterBuffer[PORT_USED][1] = reg_addr;       /* address */
I2CMasterBuffer[PORT_USED][2] = MAX30102_RD_ADDR;

if(I2CEngine(PORT_USED) != I2C_OK)
    return false;

*data = I2CSlaveBuffer[PORT_USED][0];

return true;
}

bool max30102_write_reg(uint8_t reg_addr, uint8_t data)
{
uint8_t i = 0;
uint32_t j =0;
//clear Buffer
for (i = 0; i < BUFSIZE; i++ )
{
    I2CMasterBuffer[PORT_USED][i] = 0;
}

I2CWriteLength[PORT_USED] = 3;
I2CReadLength[PORT_USED] = 0;
I2CMasterBuffer[PORT_USED][0] = MAX30102_WR_ADDR;
I2CMasterBuffer[PORT_USED][1] = reg_addr;       /* address */
I2CMasterBuffer[PORT_USED][2] = data;               /* Data0 */

if(I2CEngine(PORT_USED) != I2C_OK)
    return false;

return true;
}

bool getReadPointer(uint8_t *data) {
if(!max30102_read_reg(FIFO_RD_PTR, data))
    return false;

return true;
}

bool getWritePointer(uint8_t *data) {
if(!max30102_read_reg(FIFO_WR_PTR, data))
    return false;

return true;
}

对不起,代码太多了,但我无法更好地缩小代码中应该有错误的地方。

当我使用 max301022_read_reg() 读取寄存器时,它起作用了。

例如max30102_init()中,通过max30102_write_reg()配置值为0xF0的FIFO_CONFIG_REGISTER。当我通过 max30102_read_reg() 读取这个寄存器时,我在数据中得到值 0xF0。

但是当我读取寄存器 FIFO 写指针(getWritePointer())或 FIFO 读指针(getReadPointer())时,我总是得到值 0x00。

我也已经怀疑传感器可能坏了,并提出了一个问题:meaning-of-the-part-id-max30102-pulse-oximeter

希望有人能帮助我:)

c embedded microcontroller i2c nxp-microcontroller
© www.soinside.com 2019 - 2024. All rights reserved.