Dear Sir,
/***************************************************************************//**
* @file ADAS1000.c
* @brief Implementation of ADAS1000 Driver.
* @author ACozma (andrei.cozma@analog.com)
********************************************************************************
* Copyright 2012(c) Analog Devices, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* - Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* - The use of this software may or may not infringe the patent rights
* of one or more patent holders. This license does not release you
* from the requirement that you obtain separate licenses from these
* patent holders to use this software.
* - Use of the software either in source or binary form, must be run
* on or directly connected to an Analog Devices Inc. component.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
********************************************************************************
* SVN Revision: 570
*******************************************************************************/
/*****************************************************************************/
/***************************** Include Files *********************************/
/*****************************************************************************/
#include "ADAS1000.h"
#include "Communication.h"
/*****************************************************************************/
/************************ Variables Definitions ******************************/
/*****************************************************************************/
static unsigned long frameSize = 0; //ADAS1000 frame size in bytes
static unsigned long frameRate = 0; //ADAS1000 frame rate
static unsigned long inactiveWordsNo = 0; //number of inactive words in a frame
/***************************************************************************//**
* @brief Initializes the SPI communication with ADAS1000 and checks if the
* device is present by reading its ID. If the ID read is ok the ADAS1000
* is configured with the spefified frame rate and all the words in a
* frame are activated.
*
* @param rate - ADAS1000 frame rate.
*
* @return status - Result of the initialization procedure.
* Example: 1 - if initialization was successful;
* 0 - if initialization was unsuccessful.
*******************************************************************************/
unsigned char ADAS1000_Init(unsigned long rate)
{
unsigned long minSpiFreq = 0;
unsigned long revId = 0;
//store the selected frame rate
frameRate = rate;
// Compute the SPI clock frequency.
switch(frameRate)
{
case ADAS1000_16KHZ_FRAME_RATE:
minSpiFreq = ADAS1000_16KHZ_FRAME_RATE *
ADAS1000_16KHZ_WORD_SIZE *
ADAS1000_16KHZ_FRAME_SIZE;
break;
case ADAS1000_128KHZ_FRAME_RATE:
minSpiFreq = ADAS1000_128KHZ_FRAME_RATE *
ADAS1000_128KHZ_WORD_SIZE *
ADAS1000_128KHZ_FRAME_SIZE;
break;
case ADAS1000_31_25HZ_FRAME_RATE:
minSpiFreq = (ADAS1000_31_25HZ_FRAME_RATE *
ADAS1000_31_25HZ_WORD_SIZE *
ADAS1000_31_25HZ_FRAME_SIZE) / 100;
break;
default: // ADAS1000_2KHZ__FRAME_RATE
minSpiFreq = ADAS1000_2KHZ_FRAME_RATE *
ADAS1000_2KHZ_WORD_SIZE *
ADAS1000_2KHZ_FRAME_SIZE;
break;
}
// Initialize the SPI controller.
// The SPI frequency must be greater or equal to minSpiFreq.
if(!SPI_Init(0, minSpiFreq, 1, 1))
{
return 0;
}
// Reset the ADAS1000.
ADAS1000_SoftwareReset();
// Activate all the channels
inactiveWordsNo = 0;
ADAS1000_SetInactiveFrameWords(0);
//Set the frame rate
ADAS1000_SetFrameRate(frameRate);
return 1;
}
/***************************************************************************//**
* @brief Reads the value of the selected register
*
* @param regAddress - The address of the register to read.
* @param regVal - Pointer to a variable where to store the read data.
*
* @return None.
*******************************************************************************/
void ADAS1000_GetRegisterValue(unsigned char regAddress,
unsigned long* regVal)
{
unsigned char readCmd[4] = {0, 0, 0, 0};
unsigned char readData[4] = {0, 0, 0, 0};
// Select the register (For register reads, data is shifted out
// during the next word).
readCmd[0] = regAddress; // Register address.
SPI_Write(readCmd, 4);
// Read the data from the device.
SPI_Read(readData, 4);
*regVal = ((unsigned long)readData[1] << 16) +
((unsigned long)readData[2] << 8) +
((unsigned long)readData[3] << 0);
}
/***************************************************************************//**
* @brief Writes a value to the selected register
*
* @param regAddress - The address of the register to write to.
* @param regValue - The value to write to the register.
*
* @return None.
*******************************************************************************/
void ADAS1000_SetRegisterValue(unsigned char regAddress,
unsigned long regVal)
{
unsigned char writeCmd[4] = {0, 0, 0, 0};
writeCmd[0] = 0x80 + regAddress; // Write bit and register address.
writeCmd[1] = (unsigned char)((regVal & 0xFF0000) >> 16);
writeCmd[2] = (unsigned char)((regVal & 0x00FF00) >> 8);
writeCmd[3] = (unsigned char)((regVal & 0x0000FF) >> 0);
SPI_Write(writeCmd, 4);
}
/***************************************************************************//**
* @brief Resets the ADAS1000 part.
*
* @return None.
*******************************************************************************/
void ADAS1000_SoftwareReset(void)
{
// Clear all registers to their reset value.
ADAS1000_SetRegisterValue(ADAS1000_ECGCTL, ADAS1000_ECGCTL_SWRST);
// The software reset requires a NOP command to complete the reset.
ADAS1000_SetRegisterValue(ADAS1000_NOP, 0);
}
/***************************************************************************//**
* @brief Selects which words are not included in a data frame.
*
* @param channelsMask - Specifies the words to be excluded from the data
* frame using a bitwise or of the corresponding bits
* from the Frame Control Register.
*
* @return None.
*******************************************************************************/
void ADAS1000_SetInactiveFrameWords(unsigned long wordsMask)
{
unsigned long frmCtrlRegVal = 0;
unsigned char i = 0;
// Read the current value of the Frame Control Register
ADAS1000_GetRegisterValue(ADAS1000_FRMCTL, &frmCtrlRegVal);
//set the inactive channles
frmCtrlRegVal &= ~ADAS1000_FRMCTL_WORD_MASK;
frmCtrlRegVal |= wordsMask;
// Write the new value to the Frame Coontrol register.
ADAS1000_SetRegisterValue(ADAS1000_FRMCTL, frmCtrlRegVal);
//compute the number of inactive words
inactiveWordsNo = 0;
for(i = 0; i < 32; i++)
{
if(wordsMask & 0x00000001ul)
{
inactiveWordsNo++;
}
wordsMask >>= 1;
}
//compute the new frame size
switch(frameRate)
{
case ADAS1000_16KHZ_FRAME_RATE:
frameSize = (ADAS1000_16KHZ_WORD_SIZE / 8) *
(ADAS1000_16KHZ_FRAME_SIZE - inactiveWordsNo);
break;
case ADAS1000_128KHZ_FRAME_RATE:
frameSize = (ADAS1000_128KHZ_WORD_SIZE / 8) *
(ADAS1000_128KHZ_FRAME_SIZE - inactiveWordsNo);
break;
case ADAS1000_31_25HZ_FRAME_RATE:
frameSize = ((ADAS1000_31_25HZ_WORD_SIZE / 8) *
(ADAS1000_31_25HZ_FRAME_SIZE - inactiveWordsNo)) / 100;
break;
default: // ADAS1000_2KHZ__FRAME_RATE
frameSize = (ADAS1000_2KHZ_WORD_SIZE / 8) *
(ADAS1000_2KHZ_FRAME_SIZE - inactiveWordsNo);
break;
}
}
/***************************************************************************//**
* @brief Sets the frame rate.
*
* @param rate - ADAS1000 frame rate.
*
* @return None.
*******************************************************************************/
void ADAS1000_SetFrameRate(unsigned long rate)
{
unsigned long frmCtrlRegVal = 0;
// Store the selected frame rate
frameRate = rate;
// Read the current value of the Frame Control Register
ADAS1000_GetRegisterValue(ADAS1000_FRMCTL, &frmCtrlRegVal);
frmCtrlRegVal &= ~ADAS1000_FRMCTL_FRMRATE_MASK;
// Compute the new frame size and update the Frame Control Register value
switch(frameRate)
{
case ADAS1000_16KHZ_FRAME_RATE:
frameSize = (ADAS1000_16KHZ_WORD_SIZE / 8) *
(ADAS1000_16KHZ_FRAME_SIZE - inactiveWordsNo);
frmCtrlRegVal |= ADAS1000_FRMCTL_FRMRATE_16KHZ;
break;
case ADAS1000_128KHZ_FRAME_RATE:
frameSize = (ADAS1000_128KHZ_WORD_SIZE / 8) *
(ADAS1000_128KHZ_FRAME_SIZE - inactiveWordsNo);
frmCtrlRegVal |= ADAS1000_FRMCTL_FRMRATE_128KHZ;
break;
case ADAS1000_31_25HZ_FRAME_RATE:
frameSize = ((ADAS1000_31_25HZ_WORD_SIZE / 8) *
(ADAS1000_31_25HZ_FRAME_SIZE - inactiveWordsNo)) / 100;
frmCtrlRegVal |= ADAS1000_FRMCTL_FRMRATE_31_25HZ;
break;
default: // ADAS1000_2KHZ__FRAME_RATE
frameSize = (ADAS1000_2KHZ_WORD_SIZE / 8) *
(ADAS1000_2KHZ_FRAME_SIZE - inactiveWordsNo);
frmCtrlRegVal |= ADAS1000_FRMCTL_FRMRATE_2KHZ;
break;
}
// Write the new Frame control Register value
ADAS1000_SetRegisterValue(ADAS1000_FRMCTL, frmCtrlRegVal);
}
/***************************************************************************//**
* @brief Reads the specified number of frames.
*
* @param pDataBuffer - Buffer to store the read data.
* @param frameCnt - Number of frames to read.
* @param startRead - Set to 1 if a the frames read sequence must be started.
* @param stopRead - Set to 1 if a the frames read sequence must be sopped
* when exiting the function.
* @param waitForReady - Set to 1 if the function must wait for the READY bit
* to be set in the header.
* @param readyRepeat - Set to 1 if the device was configured to repeat the
* header until the READY bit is set.
*
* @return None.
*******************************************************************************/
void ADAS1000_ReadData(unsigned char* pDataBuffer, unsigned long frameCnt,
unsigned char startRead, unsigned char stopRead,
unsigned char waitForReady, unsigned char readyRepeat)
{
unsigned char readCmd[4] = {0, 0, 0, 0};
unsigned long ready = 0;
// If the read sequence must be started send a FRAMES command.
if(startRead)
{
readCmd[0] = ADAS1000_FRAMES; // Register address.
SPI_Write(readCmd, 4);
}
// Read the number of requested frames.
while(frameCnt)
{
// If waiting for the READY bit to be set read the header until the bit is set, otherwise just read the entire frame.
if(waitForReady)
{
ready = 1;
while(ready == 1)
{
//if the header is repeated until the READY bit is set read only the header, otherwise read the entire frame
if(readyRepeat)
{
SPI_Read(pDataBuffer, 4);
ready = *pDataBuffer & 0x40;
if(ready == 0)
{
SPI_Read(pDataBuffer + 4, frameSize - 4);
pDataBuffer += frameSize;
frameCnt--;
}
}
else
{
SPI_Read(pDataBuffer, frameSize);
ready = *pDataBuffer & 0x40;
if(ready == 0)
{
pDataBuffer += frameSize;
frameCnt--;
}
}
}
}
else
{
SPI_Read(pDataBuffer, frameSize);
pDataBuffer += frameSize;
frameCnt--;
}
}
// If the frames read sequence must be stopped read a register to stop the frames read.
if(stopRead)
{
ADAS1000_GetRegisterValue(ADAS1000_FRMCTL, &ready);
}
}
/***************************************************************************//**
* @brief Computes the CRC for a frame.
*
* @param pBuf - Buffer holding the frame data.
*
* @return Returns the CRC value for the given frame.
*******************************************************************************/
unsigned long ADAS1000_ComputeFrameCrc(unsigned char *pBuf)
{
unsigned char i = 0;
unsigned long crc = 0xFFFFFFFFul;
unsigned long poly = 0;
unsigned char bitCnt = 0;
unsigned long frmSize = 0;
// Select the CRC poly and word size based on the frame rate.
if(frameRate == ADAS1000_128KHZ_FRAME_RATE)
{
poly = CRC_POLY_128KHZ;
bitCnt = 16;
}
else
{
poly = CRC_POLY_2KHZ_16KHZ;
bitCnt = 24;
}
frmSize = frameSize;
// Compute the CRC.
while(frmSize--)
{
crc ^= (((unsigned long)*pBuf++) << (bitCnt - 8));
for(i = 0; i < 8; i++)
{
if(crc & (1ul << (bitCnt - 1)))
crc = (crc << 1) ^ poly;
else
crc <<= 1;
}
}
return crc;
}