Nisarg Sheth / ADMX2001

ADMX2001.cpp

Committer:
nsheth
Date:
2021-10-07
Revision:
5:b9608e6cc24b
Parent:
4:eb7a23c25751
Child:
6:7d8f30b3bc57

File content as of revision 5:b9608e6cc24b:

/******************************************************************************
 Copyright (c) 2020 - 2021  Analog Devices Inc. All Rights Reserved.
 This software is proprietary & confidential to Analog Devices, Inc.
 and its licensors.
******************************************************************************/
/**
 * @file     admx200x.c
 * @brief    This file contains admx200x APIs for sdpk1 host
 * @addtogroup SDPK1
 * @{
 */
/*=============  I N C L U D E S   =============*/
#include "ADMX2001.h"
#include "ADMX2001_commands.h"
#include "message.h"
#include <stdlib.h>
#include <string.h>

static uint32_t SwapEndian(uint32_t *pData);
/** milli second delay**/
static void Admx200xDelay(uint32_t msec);

/**
 * Swaps endian of a 32 bit number
 * @param data  - 32 bit number
 * @return
 */
uint32_t SwapEndian(uint32_t *pData)
{
    uint8_t *pDataU8 = (uint8_t *)pData;

    return (uint32_t)pDataU8[0] << 24 | (uint32_t)pDataU8[1] << 16 |
           (uint32_t)pDataU8[2] << 8 | (uint32_t)pDataU8[3];
}

/**
 * @brief Initializes the ADMX200X.
 *
 * @param pDevice     - The device structure.
 * @param pSpiDesc    - Pointer to spi device
 * @return Returns 0 for success or negative error code.
 */
int32_t Admx200xInit(Admx200xDev *pDevice, spi_desc *pSpiDesc)
{
    int32_t ret = 0;

    pDevice->pSpiDesc = pSpiDesc;

    return ret;
}

/**
 * Wrapper fro delay
 * @param msecs  - delay in milliseconds
 */
void Admx200xDelay(uint32_t msecs)
{
    mdelay(msecs);
}

/**
 * @brief Create a command payload in buffer with inputs.
 *
 * @param pCmdId - Command ID.
 * @param pAddr - Sub commands addresses.
 * @param pData - Data to wildcat.
 * @param pBuffer - Data to wildcat.
 *
 * @return Returns 0 for success or negative error code.
 */
int32_t Admx200xCreateCmdPayload(uint8_t *pCmdId, uint16_t *pAddr,
                                 uint32_t *pData, uint8_t *pBuffer)
{
    int32_t ret = 0;
    //DEBUG_MSG("cmd:%d,addr:%d, data: 0x%x\n\r", *pCmdId, *pAddr, *pData);
    pBuffer[0] = pCmdId[0];
    pBuffer[1] = ((uint8_t *)pAddr)[1];
    pBuffer[2] = ((uint8_t *)pAddr)[0];
    pBuffer[3] = ((uint8_t *)pData)[3];
    pBuffer[4] = ((uint8_t *)pData)[2];
    pBuffer[5] = ((uint8_t *)pData)[1];
    pBuffer[6] = ((uint8_t *)pData)[0];

    return ret;
}

/**
 * @brief Parse the payload to get cmdID, addr and data.

 * @param[in] pBuffer - Data from wildcat.
 * @param[out] pCmdId  - Pointer to store Command ID.
 * @param[out]  pAddr   - Pointer to store addresses.
 * @param[out]  pData   -  Pointer to store Data
 *
 * @return Returns 0 for success or negative error code.
 */
int32_t Admx200xParseCmdPayload(uint8_t *pBuffer, uint8_t *pCmdId,
                                uint16_t *pAddr, uint32_t *pData)
{
    int32_t ret = 0;

    *pCmdId = pBuffer[0];
    *pAddr = ((uint16_t)pBuffer[1] << 8) | ((uint16_t)pBuffer[2]);

    *pData = SwapEndian((uint32_t *)&pBuffer[3]);

    return ret;
}

/**
 * @brief Waits till done bit is set in the status
 *
 * @param pDevice  - The handler of the instance of the driver.
 * @param timeout  - Count representing the number of polls to be done until the
 *                  function returns if no new data is available.
 * @param reqStatus - The status to be checked is passed via this argument.
 * @param pStatReg  - Get the status word in pStatReg.
 *
 * @return Returns 0 for success or negative error code.
 */
int32_t Admx200xWaitForStatus(Admx200xDev *pDevice, uint32_t timeout,
                              uint32_t reqStatus, uint32_t *pStatReg)
{
    int32_t status = ADMX_STATUS_SUCCESS;
    int8_t done = 0;
    uint8_t cmdId = CMD_STATUS_READ;

    if (pDevice != NULL)
    {
        while (!done && --timeout)
        {

            status = Admx200xReadData(pDevice, cmdId, pStatReg);

            if (status == 0)
            {
                /* Check the DONE bit in the Status Register */
                if (((*pStatReg) & reqStatus) == reqStatus)
                {
                    done = 1;
                    if (*pStatReg & ADMX200X_STATUS_ERROR_BITM)
                    {
                        status = *pStatReg & ADMX200X_STATUS_CODE_BITM;
                        if (status & ADMX_STATUS_LOG_ZERO_ERROR)
                        {
                            ERROR_MSG("sweep_start/sweep_end cannot be zero "
                                      "for logarithmic sweep");
                            status &= (~ADMX_STATUS_LOG_ZERO_ERROR);
                        }
                        if (status & ADMX_STATUS_LOG_SIGN_ERROR)
                        {
                            ERROR_MSG("sweep_start and sweep_end need to have "
                                      "the same sign "
                                      "for logarithmic sweep");
                            status &= (~ADMX_STATUS_LOG_SIGN_ERROR);
                        }
                        if (status & ADMX_STATUS_VOLT_ADC_ERROR)
                        {
                            ERROR_MSG("Voltage ADC Saturated\n");
                            status &= (~ADMX_STATUS_VOLT_ADC_ERROR);
                        }
                        if (status & ADMX_STATUS_CURR_ADC_ERROR)
                        {
                            ERROR_MSG("Current ADC Saturated\n");
                            status &= (~ADMX_STATUS_CURR_ADC_ERROR);
                        }
                        if (status & ADMX_STATUS_FIFO_ERROR)
                        {
                            ERROR_MSG(
                                "FIFO either Overflowed or Underflowed\n");
                            status &= (~ADMX_STATUS_FIFO_ERROR);
                        }
                        if (status & ADMX_STATUS_COUNT_EXCEEDED)
                        {
                            ERROR_MSG("Sweep count exceeded maximum value");
                            status &= (~ADMX_STATUS_COUNT_EXCEEDED);
                        }
                    }
                }
            }
        }

        if (!timeout)
        {
            status = ADMX_STATUS_TIMEOUT;
        }
    }
    else
    {
        status = ADMX_STATUS_FAILED;
    }
    return status;
}

/**
 * @brief Sends teh command to ADMX200x and wait till done bit is set
 * @param pDevice  - Device Handle
 * @param pCmdId   - The command ID
 * @param pAddr    - Address
 * @param pData    - Data
 * @param pStatReg - Status register info
 * @return Returns 0 for success or negative error code.
 */
int32_t Admx200xSendCmd(Admx200xDev *pDevice, uint8_t *pCmdId, uint16_t *pAddr,
                        uint32_t *pData, uint32_t *pStatReg)
{

    int32_t status = ADMX_STATUS_SUCCESS;
    uint8_t cmdPayload[ADMX200X_CMD_LENGTH];

    Admx200xCreateCmdPayload(pCmdId, pAddr, pData, &cmdPayload[0]);

    status = spi_write_and_read(pDevice->pSpiDesc, &cmdPayload[0],
                                ADMX200X_CMD_LENGTH);
    Admx200xDelay(100);
    // printf("CMD :%02x ADDR: %04x DATA: %08x\n\r",*pCmdId, *pAddr, *pData);
    if (!status)
    {
        /** Wait for status done = 1,Warn/error/command result = 0 from result
         */
        status = Admx200xWaitForStatus(pDevice, SPI_TIMEOUT,
                                       ADMX200X_STATUS_DONE_BITM, pStatReg);

        // printf("Stat Reg: %08x\n\r", *pStatReg);
        if (status == ADMX_STATUS_SUCCESS)
        {
            status = *pStatReg & ADMX200X_STATUS_CODE_BITM;
        }
    }
    if (status == ADMX_STATUS_TIMEOUT)
    {
        ERROR_MSG("SPI interface timed out : Not responding");
    }
    return status;
}

/**
 * @brief Read result register from the WILDCAT
 * @param pDevice  - Device Handle
 * @param cmdId   - This determines where the data is read from - result
 *                  register, status register or Fifo
 * @param pResult - The data in the result register
 * @return Returns 0 for success or negative error code.
 */
int32_t Admx200xReadData(Admx200xDev *pDevice, uint8_t cmdId, uint32_t *pResult)
{
    int32_t ret = ADMX_STATUS_SUCCESS;
    uint8_t cmdTemp;
    uint16_t addrTemp;
    uint16_t addr;
    uint32_t data;
    uint8_t cmdPayload[ADMX200X_CMD_LENGTH];

    /*FIXME: Insert checks here. Not all command IDs are accepted here */
    addr = 0;
    data = 0;

    Admx200xCreateCmdPayload(&cmdId, &addr, &data, &cmdPayload[0]);

    /* Send command and Read response from the slave */
    ret = spi_write_and_read(pDevice->pSpiDesc, &cmdPayload[0],
                             ADMX200X_CMD_LENGTH);
    Admx200xDelay(100);
    Admx200xParseCmdPayload(&cmdPayload[0], &cmdTemp, &addrTemp, pResult);

    return ret;
}

/**
 * @brief Read array of datatype doube from the fifo of the WILDCAT
 * @param pDevice  - Device Handle
 * @param pFifo - Double array that stores the data
 * @param pCount - Stores the number of double values stored in the pFifo array
 */
int32_t Admx200xReadFifo(Admx200xDev *pDevice, double *pFifo, int32_t *pCount)
{
    int32_t status = ADMX_STATUS_SUCCESS;
    int32_t i;
    uint32_t *pData = (uint32_t *)pFifo;
    uint8_t cmdId = CMD_STATUS_READ;
    uint32_t statusReg;
    int32_t numDoublesInFifo;

    status = Admx200xReadData(pDevice, cmdId, &statusReg);

    /* Fifo depth in doubles */
    numDoublesInFifo = (statusReg & ADMX200X_STATUS_FIFO_DEPTH_BITM) >> 17;

    if (numDoublesInFifo < *pCount)
    {
        *pCount = numDoublesInFifo;
    }

    for (i = 0; i < *pCount; i++)
    {
        /* Read a double  -- Split it into two reads for redability*/
        Admx200xReadData(pDevice, CMD_FIFO_READ, &pData[2 * i]);
        Admx200xReadData(pDevice, CMD_FIFO_READ, &pData[2 * i + 1]);
    }
    return status;
}

/**
 * @brief Clears the Admx2001 SPI FIFO & errors
 *
 * @param pDevice - Device Handle
 * @return Returns 0 for success or error code.
 */
int32_t Admx200xClearSPI(Admx200xDev *pDevice)
{
    int32_t status = ADMX_STATUS_SUCCESS;
    uint8_t cmdID;
    uint16_t addr = 0;
    uint32_t statReg = 0;
    uint32_t data = 0;

    cmdID = CMD_CLEAR_ERROR;
    status = Admx200xSendCmd(pDevice, &cmdID, &addr, &data, &statReg);

    return status;
}

/**
 * @}
 */