⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cs5523.c

📁 AVR平台下的CanOpen协议桟源码包括应用
💻 C
字号:
/* ------------------------------------------------------------------------
File   : cs5523.c

Descr  : Functions for operating a CRYSTAL CS5523 (CS5524) 4-chan 16-bit
         (24-bit) ADC with SPI serial interface.

History: 01JUN.00; Henk B&B; Start of development, based on routines for
                             a CS5525 ADC.
	 22SEP.00; Henk B&B; In cs5523_write_csr() assume Depth Pointer
	                     is by default set to 1 (which is the case
			     if a first call is made to it for a write to
			     a depth of 8 (to be done by the ADC init routine).
	 29NOV.00; Henk B&B; BUG FIX: in cs5523_reset() used Timer2 twice
	                     at the same time, in a timeout and for reading
			     out the CS5523 registers, resulting in a faulty
			     timeout causing a hang situation (e.g. when
			     CS5523 not present).
	 06AUG.01; Henk B&B; Replaced 2 functions by macros.
--------------------------------------------------------------------------- */

#include "general.h"
#include "adc.h"
#include "cs5523.h"
#include "timer103.h"

extern BYTE AdcOptoDelay;

/* ------------------------------------------------------------------------ */

void cs5523_read_reg( BYTE reg, BYTE ain, BYTE *regdata )
{
  /* Make sure to address a valid register */
  reg  &= CS23_CMD_REG_SELECT_MASK;
  ain <<= CS23_CMD_PHYSCHAN_SELECT_SHIFT;
  ain  &= CS23_CMD_PHYSCHAN_SELECT_MASK;

  /* Write the 'read register' command */
  cs5523_select_register_cmd( CS23_CMD_READ | reg | ain );

  /* Read 24 bits (3 bytes) of data, MSB first */

  /* Store Most Significant Byte in highest byte */
  regdata += 2;
  *regdata = cs5523_read_byte();
  --regdata;
  *regdata = cs5523_read_byte();
  --regdata;
  *regdata = cs5523_read_byte();
}

/* ------------------------------------------------------------------------ */

void cs5523_write_reg( BYTE reg, BYTE ain, BYTE *regdata )
{
  /* Make sure to address a valid register */
  reg  &= CS23_CMD_REG_SELECT_MASK;
  ain <<= CS23_CMD_PHYSCHAN_SELECT_SHIFT;
  ain  &= CS23_CMD_PHYSCHAN_SELECT_MASK;

  /* Write the 'write register' command */
  cs5523_select_register_cmd( CS23_CMD_WRITE | reg | ain );

  /* Write 24 bits (3 bytes) of data, MSB first */

  /* Get Most Significant Byte in highest byte */
  regdata += 2;
  cs5523_write_byte( *regdata );
  --regdata;
  cs5523_write_byte( *regdata );
  --regdata;
  cs5523_write_byte( *regdata );
}

/* ------------------------------------------------------------------------ */

void cs5523_read_csr( BYTE *csrdata )
{
  /* Read all 4 Channel-Setup Registers (data for 8 Logical Channels)
     without changing other Configuration Register settings;
     use 2 bytes per Logical Channel (so need 16 for 8 LCs) */
  BYTE config[3];
  BYTE lc;

  /* Read the current Configuration Register setting */
  cs5523_read_reg( CS23_CMD_CONFIG_REG, 0, config );

  /* Set the Depth Pointer to 7 (8 Logical Channel settings to read) */
  config[1] |= (7 << CS23_CNF_CSR_DEPTH_SHIFT);

  /* Write the Configuration Register setting */
  cs5523_write_reg( CS23_CMD_CONFIG_REG, 0, config );

  /* Now write the 'read CSR register' command */
  cs5523_select_register_cmd( CS23_CMD_READ | CS23_CMD_CHAN_SETUP_REG );

  /* Read 4*24=96 bits of data, MSB first, in chunks of 4 and 8 bits,
     each chunk stored in 1 byte, stored LSB first */
  for( lc=0; lc<8; ++lc )
    {
      csrdata[lc*2+1] = cs5523_read_nibble(); /* A1,A0,NU,CS1 */
      csrdata[lc*2]   = cs5523_read_byte();   /* the lower 8 bits */
    }

  /* Reset the Depth Pointer to 1 */
  config[1] &= ~CS23_CNF_CSR_DEPTH_MASK;
  config[1] |= (1 << CS23_CNF_CSR_DEPTH_SHIFT);

  /* Write the Configuration Register setting */
  cs5523_write_reg( CS23_CMD_CONFIG_REG, 0, config );
}

/* ------------------------------------------------------------------------ */

void cs5523_write_csr( BYTE no_of_csr, BYTE *csrdata )
{
  /* Write 1 to 4 Channel-Setup Registers (data for up to 8 Logical Channels)
     without changing other Configuration Register settings;
     use 2 bytes per Logical Channel (so need 16 for 8 LCs) */
  BYTE config[3];
  BYTE no_of_lc, lc;

  if( no_of_csr > 4 )  no_of_csr = 4;
  if( no_of_csr == 0 ) no_of_csr = 1;

  no_of_lc = no_of_csr * 2;

  /* Assume everything is already properly set for writing 1 CSR... */
  if( no_of_csr > 1 )
    {
      /* Read the current Configuration Register setting */
      cs5523_read_reg( CS23_CMD_CONFIG_REG, 0, config );

      /* Set the Depth Pointer */
      config[1] &= ~CS23_CNF_CSR_DEPTH_MASK;
      config[1] |= ((no_of_lc-1) << CS23_CNF_CSR_DEPTH_SHIFT);

      /* Write the Configuration Register setting */
      cs5523_write_reg( CS23_CMD_CONFIG_REG, 0, config );
    }

  /* Now write the 'write CSR register' command */
  cs5523_select_register_cmd( CS23_CMD_WRITE | CS23_CMD_CHAN_SETUP_REG );

  /* Write up to 4*24=96 bits of data, MSB first, in chunks of 4 and 8 bits,
     each chunk stored in 1 byte, stored LSB first */
  for( lc=0; lc<no_of_lc; ++lc )
    {
      cs5523_write_nibble( csrdata[lc*2+1] ); /* A1,A0,NU,CS1 */
      cs5523_write_byte( csrdata[lc*2] );     /* the lower 8 bits */
    }

  /* Assume everything was properly set for writing 1 CSR... */
  if( no_of_csr > 1 )
    {
      /* Reset the Depth Pointer to 1 */
      config[1] &= ~CS23_CNF_CSR_DEPTH_MASK;
      config[1] |= (1 << CS23_CNF_CSR_DEPTH_SHIFT);

      /* Write the Configuration Register setting */
      cs5523_write_reg( CS23_CMD_CONFIG_REG, 0, config );
    }
}

/* ------------------------------------------------------------------------ */

BOOL cs5523_read_adc( BYTE log_chan, BYTE *conversion_data )
{
  /* Make sure to use a valid Logical Channel */
  log_chan = (log_chan << CS23_CMD_LOGCHAN_SELECT_SHIFT) &
             CS23_CMD_LOGCHAN_SELECT_MASK;

  /* Initiate the conversion */
  cs5523_start_conversion_cmd( CS23_CMD_NORMAL_CONVERSION | log_chan );

  /* Wait for SDO to go low flagging the conversion is done,
     but use a timeout (ca. 600 ms, sufficient at 1.88 Hz wordrate) */
  //if( cs5523_await_sdo_low( 60 ) )
  if( cs5523_await_sdo_low( 120 ) ) // Make that 1200 ms...
    {
      /* Generate 8 SCLKs to clear the SDO flag */
      cs5523_write_byte( 0 );

      /* Read 24 bits (3 bytes) of conversion data */
      conversion_data[2] = cs5523_read_byte();
      conversion_data[1] = cs5523_read_byte();
      conversion_data[0] = cs5523_read_byte();
      return TRUE;
    }
  else
    {
      /* Time out ! Meaning there was a time-out on conversion-done... */
      conversion_data[2] = 0xFF;
      conversion_data[1] = 0xFF;
      conversion_data[0] = 0xFE;
      return FALSE;
    }
}

/* ------------------------------------------------------------------------ */

BOOL cs5523_calibrate( BYTE calib_type, BYTE adc_config )
{
  /* Perform the requested calibration on all 4 physical channels */

  BYTE ain;
  BYTE csr_data[4];

  /* Dummy data for LC 2... */
  csr_data[2] = 0;
  csr_data[3] = 0;

  /* Always use 15 Hz calibration wordrate */
  adc_config &= ~CS23_CSR_WORDRATE_MASK;
  adc_config |= (CS23_WORDRATE_15 << CS23_CSR_WORDRATE_SHIFT);

  for( ain=0; ain<4; ++ain )
    {
      /* Set physical channel, wordrate and gain in LC 1:
         wordrate and gain (and measurement mode) are in 'adc_config' ! */
      csr_data[0]  = adc_config |
	             ((ain << CS23_CSR_PHYSCHAN_SEL_LO_SHIFT) &
		      CS23_CSR_PHYSCHAN_SEL_LO_MASK);
      csr_data[1]  = ((ain >> CS23_CSR_PHYSCHAN_SEL_HI_SHIFT) &
		      CS23_CSR_PHYSCHAN_SEL_HI_MASK);

      /* Write to one CSR (LCs 1 and 2) */
      cs5523_write_csr( 1, csr_data );

      /* Perform the requested calibration using LC 1 */
      cs5523_start_conversion_cmd( calib_type |
				   (0 << CS23_CMD_LOGCHAN_SELECT_SHIFT) );

      /* Busy-wait for calibration-ready or time-out */
      //if( !cs5523_await_sdo_low( 60 ) )
      if( !cs5523_await_sdo_low( 120 ) ) // Make that 1200 ms...
	{
	  /* Time out ! */
	  return FALSE;
	}

      /* Calibration done ! */

      /* Generate 8 SCLKs to clear the SDO flag:
	 ! not needed after calibration (says CRYSTAL) ! */
      /*cs5523_write_byte( 0 );*/
    }

  return TRUE;
}

/* ------------------------------------------------------------------------ */

BOOL cs5523_reset( BYTE *err_id )
{
  /* Initiate a converter reset and
     and check for default contents of Configuration, Offset and Gain
     Registers, which should be:
     config  = 0x000040 (CS23_CNF_RESET_VALID),
     offset  = 0x000000,
     gain    = 0x400000,
     (setups = 0x000000)
     and Configuration Register should contain 0x000000 after the first read
  */

  BYTE config[3];
  BOOL reset_valid;
  BYTE ain;
  BYTE ms50_cnt;

  *err_id = 0;

  /* Write 'reset system' command to the Configuration Register
     by setting the RS-bit */
  config[0] = CS23_CNF_RESET_SYSTEM;
  config[1] = 0;
  config[2] = 0;
  cs5523_write_reg( CS23_CMD_CONFIG_REG, 0, config ); 

  /* Read Configuration Register until RV-bit is set,
     or time-out (ca. 400 ms) */
  ms50_cnt    = 0;
  reset_valid = FALSE;
  while( !reset_valid && ms50_cnt < 8 )
    {
      /* Pause for 50 ms */
      timer0_set_timeout_10ms( ADC_ELMB, 5 );
      while( !timer0_timeout(ADC_ELMB) );
      ++ms50_cnt;

      /* Read Configuration Register */
      cs5523_read_reg( CS23_CMD_CONFIG_REG, 0, config );

      /* RV-bit set ? */
      if( config[0] & CS23_CNF_RESET_VALID )
	{
	  reset_valid = TRUE;
	  /* RV-bit is set, reset the RS-bit */
	  config[0] = 0;
	  config[1] = 0;
	  config[2] = 0;
	  cs5523_write_reg( CS23_CMD_CONFIG_REG, 0, config );
	}
      else reset_valid = FALSE;
    }

  if( reset_valid )
    {
      /* Read Configuration Register once more to reset the RV-bit */
      cs5523_read_reg( CS23_CMD_CONFIG_REG, 0, config );

      /* RV-bit reset ? */
      cs5523_read_reg( CS23_CMD_CONFIG_REG, 0, config );
      if( config[0] != 0x00 )
	{
	  *err_id |= CS23_ERR_RV_NOT_RESET;
	  return FALSE;
	}
    }
  else
    {
      /* Time out ! */
      *err_id |= CS23_ERR_RV_TIMEOUT;
      return FALSE;
    }

  /* Check Offset Registers, should contain 0x000000 */
  for( ain=0; ain<4; ++ain )
    {
      cs5523_read_reg( CS23_CMD_OFFSET_REG, ain, config );
      if( config[0] != 0x00 || config[1] != 0x00 || config[2] != 0x00 )
	{
	  *err_id |= CS23_ERR_OFFSET;
	  return FALSE;
	}
    }

  /* Check Gain Registers, should contain 0x400000 */
  for( ain=0; ain<4; ++ain )
    {
      cs5523_read_reg( CS23_CMD_GAIN_REG, ain, config );
      if( config[0] != 0x00 || config[1] != 0x00 || config[2] != 0x40 )
	{
	  *err_id |= CS23_ERR_GAIN;
	  return FALSE;
	}
    }

  return TRUE;
}

/* ------------------------------------------------------------------------ */

void cs5523_serial_init( void )
{
  /* Perform the serial port initialization sequence:
     at least 15 command bytes 0xFF, then one byte 0xFE */
  BYTE i;
  for( i=0; i<15; ++i ) cs5523_write_byte( 0xFF );
  cs5523_write_byte( 0xFE );
}

/* ------------------------------------------------------------------------ */

BOOL cs5523_await_sdo_low( BYTE ms10_cnt )
{
  /* Wait for about ms10_cnt * 10 ms
     (e.g. for about 2200 ms maximum... (ca. 4 conversions @ 1.88 Hz)) */

  timer0_set_timeout_10ms( ADC_ELMB, ms10_cnt );

  /* Busy-wait for conversion-ready or time-out */
  while( !(ADC_SDO_LOW() || timer0_timeout(ADC_ELMB)) );

  return( ADC_SDO_LOW() );
}

/* ------------------------------------------------------------------------ */

BYTE cs5523_read_nibble( void )
{
  BYTE i, b;

  b = 0;

  /* Clock the data in from the CS5523, MSB first */
  for( i=0; i<4; ++i )
    {
      b <<= 1;
      ADC_SET_SCLK();
      //timer2_delay_mus( CS23_ELMB_SIGNAL_RISETIME );
      timer2_delay_mus( AdcOptoDelay );
      if( ADC_SDO_HIGH() ) ++b;
      ADC_CLEAR_SCLK();
      //timer2_delay_mus( CS23_ELMB_SIGNAL_FALLTIME );
      timer2_delay_mus( AdcOptoDelay );
    }

  return b;
}

/* ------------------------------------------------------------------------ */

void cs5523_write_nibble( BYTE byt )
{
  BYTE i, b;

  b = byt;

  /* Clock the data out to the CS5523, MSB first */
  for( i=0; i<4; ++i )
    {
      if( b & 0x08 ) ADC_SET_SDI();
      else ADC_CLEAR_SDI();
      //timer2_delay_mus( CS23_ELMB_SIGNAL_FALLTIME );
      timer2_delay_mus( AdcOptoDelay );
      ADC_SET_SCLK();
      //timer2_delay_mus( CS23_ELMB_SIGNAL_RISETIME );
      timer2_delay_mus( AdcOptoDelay );
      ADC_CLEAR_SCLK();
      b <<= 1;
    }
}

/* ------------------------------------------------------------------------ */

BYTE cs5523_read_byte( void )
{
  BYTE i, b;

  b = 0;

  /* Clock the data in from the CS5523, MSB first */
  for( i=0; i<8; ++i )
    {
      b <<= 1;
      ADC_SET_SCLK();
      //timer2_delay_mus( CS23_ELMB_SIGNAL_RISETIME );
      timer2_delay_mus( AdcOptoDelay );
      if( ADC_SDO_HIGH() ) ++b;
      ADC_CLEAR_SCLK();
      //timer2_delay_mus( CS23_ELMB_SIGNAL_FALLTIME );
      timer2_delay_mus( AdcOptoDelay );
    }

  return b;
}

/* ------------------------------------------------------------------------ */

void cs5523_write_byte( BYTE byt )
{
  BYTE i, b;

  b = byt;

  /* Clock the data out to the CS5523, MSB first */
  for( i=0; i<8; ++i )
    {
      if( b & 0x80 ) ADC_SET_SDI();
      else ADC_CLEAR_SDI();
      //timer2_delay_mus( CS23_ELMB_SIGNAL_FALLTIME );
      timer2_delay_mus( AdcOptoDelay );
      ADC_SET_SCLK();
      //timer2_delay_mus( CS23_ELMB_SIGNAL_RISETIME );
      timer2_delay_mus( AdcOptoDelay );
      ADC_CLEAR_SCLK();
      b <<= 1;
    }

  /* Set SDI to one when not writing:
     switches off opto-coupler, reduces power consumption */
  ADC_SET_SDI();

  //timer2_delay_mus( CS23_ELMB_SIGNAL_FALLTIME );
  timer2_delay_mus( AdcOptoDelay );
}

/* ------------------------------------------------------------------------ */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -