Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of Babyseat_NewFirmware_copy_sean by
Diff: src/adisense1000.cpp
- Revision:
- 2:625a45555a85
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/adisense1000.cpp Fri Aug 25 11:17:37 2017 +0000
@@ -0,0 +1,633 @@
+/*!
+ ******************************************************************************
+ * @file: adisense1000.cpp
+ * @brief:
+ *-----------------------------------------------------------------------------
+ *
+Copyright (c) 2017 Emutex Ltd. / 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.
+ - Modified versions of the software must be conspicuously marked as such.
+ - This software is licensed solely and exclusively for use with processors
+ manufactured by or for Analog Devices, Inc.
+ - This software may not be combined or merged with other code in any manner
+ that would cause the software to become subject to terms and conditions
+ which differ from those listed here.
+ - 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.
+
+THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. AND CONTRIBUTORS "AS IS" AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
+TITLE, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+NO EVENT SHALL ANALOG DEVICES, INC. OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, DAMAGES ARISING OUT OF CLAIMS OF INTELLECTUAL
+PROPERTY RIGHTS INFRINGEMENT; 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.
+ *
+ *****************************************************************************/
+/******************************************************************************/
+/* Include Files */
+/******************************************************************************/
+
+#include "mbed.h"
+#include "inc/spi_nucleo.h"
+#include "inc/gpio_nucleo.h"
+#include "inc/adisense1000.h"
+
+#define BIT(n) (1 << (n))
+#define BIT_MASK(len) (BIT(len)-1)
+
+#define MAX_RCV_BYTES (100)
+#define MAX_REG_SIZE (4)
+
+#define GET_SAMPLE_TIMEOUT (1)
+
+extern Serial pc;
+Timer readTimeout;
+
+uint8_t rcvBuff[MAX_RCV_BYTES] = {0};
+uint8_t txdBuff[MAX_REG_SIZE] = {0};
+
+/*
+ For v0.1 we pass this into ADISense1000_HostGpioOpen but it is not being used.
+ This is because the os dependant wrapper for the nucleo is using classes which
+ are hardcoded globally. We should probally wrap the os layer in a c wrapper
+ so these c++ functions are hidden from the user
+ */
+gpioSettings gpioConfig[HOST_GPIO_COUNT] =
+{
+ {D2, OUTPUT, HIGH},
+ {D3, INPUT, LOW},
+ {D4, INPUT, LOW},
+ {D5, INPUT, LOW}
+};
+
+/* Same as mentioned for gpioConfig applies here */
+spiSettings spiConfigure;
+
+/*!
+ * @brief Init SPI and GPIO for ADISense1000.
+ *
+ * @param[in] void
+ *
+ * @return Status
+ * - #ADI_SENSE_SUCCESS Call completed successfully.
+ * - #ADI_SENSE_FAILURE If GPIO open failed.
+ * - #ADI_SENSE_FAILURE If SPI open failed.
+ *
+ * @details Configure GPIO for ADISense1000 module and open
+ * SPI communications to ADISense1000 module.
+ */
+ADI_SENSE_RESULT ADISense1000_Open(void)
+{
+ if (ADISense1000_HostGpioOpen(gpioConfig) != ADI_SENSE_SUCCESS)
+ {
+ return ADI_SENSE_FAILURE;
+ }
+
+ if (ADISense1000_HostSpiOpen(spiConfigure) != ADI_SENSE_SUCCESS)
+ {
+ return ADI_SENSE_FAILURE;
+ }
+
+ return ADI_SENSE_SUCCESS;
+}
+
+
+/*!
+ * @brief Get the product ID for Module
+ *
+ * @param[in]
+ * @param[out] pProductID : Pointer to uint16_t for Product ID.
+ *
+ * @return Status
+ * - #ADI_SENSE_SUCCESS Call completed successfully.
+ * - #ADI_SENSE_FAILURE If receive product ID fails.
+ *
+ * @details Read the product ID for ADISense1000 module.
+ *
+ */
+ADI_SENSE_RESULT ADISense1000_GetID(uint16_t *pProductID)
+{
+ ADI_SENSE_RESULT eRet;
+ uint8_t id_l, id_h;
+
+ eRet = ADISense1000_RegRead(regMap[SPI_PRODUCT_ID_L].addr,
+ regMap[SPI_PRODUCT_ID_L].size,
+ rcvBuff);
+ if (eRet != ADI_SENSE_SUCCESS)
+ {
+ return eRet;
+ }
+
+ id_l = rcvBuff[0];
+
+ eRet = ADISense1000_RegRead(regMap[SPI_PRODUCT_ID_H].addr,
+ regMap[SPI_PRODUCT_ID_H].size,
+ rcvBuff);
+ if (eRet != ADI_SENSE_SUCCESS)
+ {
+ return eRet;
+ }
+
+ id_h = rcvBuff[0];
+ *pProductID = ((id_h << 8)&0xff00)|id_l;
+
+ return ADI_SENSE_SUCCESS;
+}
+
+/*!
+ * @brief Basic configuration of module for V0.1
+ *
+ * @param[in] void
+ * @param[out]
+ *
+ * @return Status
+ * - #ADI_SENSE_SUCCESS Call completed successfully.
+ * - #ADI_SENSE_FAILURE If write module config fails.
+ *
+ * @details Basic function to set a fixed configuration.
+ */
+ADI_SENSE_RESULT ADISense1000_ConfigureModule(void)
+{
+ ADI_SENSE_RESULT eRet;
+ ADI_CORE_Mode_t modeReg;
+
+ modeReg.Conversion_Mode = CORE_MODE_SINGLECYCLE;
+ modeReg.Drdy_Mode = CORE_MODE_DRDY_PER_CYCLE;
+
+ eRet = ADISense1000_RegWrite(regMap[CORE_MODE].addr,
+ regMap[CORE_MODE].size,
+ (uint8_t*)&modeReg);
+
+ if (eRet != ADI_SENSE_SUCCESS)
+ {
+ return eRet;
+ }
+
+ return ADI_SENSE_SUCCESS;
+}
+
+/*!
+ * @brief Get general status of ADISense1000 module.
+ *
+ * @param[in]
+ * @param[out] pStatus : Pointer to CORE Status struct.
+ *
+ * @return Status
+ * - #ADI_SENSE_SUCCESS Call completed successfully.
+ * - #ADI_SENSE_FAILURE If status register read fails.
+ *
+ * @details Read the general status register for the ADISense1000
+ * module. Indicates Error, Alert conditions, data ready
+ * and command running.
+ *
+ */
+ADI_SENSE_RESULT ADISense1000_GetStatus(ADI_CORE_Status_t *pStatus)
+{
+ ADI_SENSE_RESULT eRet;
+
+ pStatus->VALUE8 = 0;
+ eRet = ADISense1000_RegRead(regMap[CORE_STATUS].addr,
+ regMap[CORE_STATUS].size,
+ rcvBuff);
+ if (eRet != ADI_SENSE_SUCCESS)
+ {
+ return eRet;
+ }
+
+ pStatus->VALUE8 = rcvBuff[0];
+
+ return ADI_SENSE_SUCCESS;
+}
+
+/*!
+ * @brief Get a list of channels with alerts.
+ *
+ * @param[in]
+ * @param[out] pStatus : List of Channel detailed alerts.
+ *
+ * @return Status
+ * - #ADI_SENSE_SUCCESS Call completed successfully.
+ * - #ADI_SENSE_FAILURE If request for channel alerts fails.
+ *
+ * @details Read the channel alert register. If channel alert register
+ * indicates alert on a channel, process the channel detailed
+ * alert register.
+ */
+ADI_SENSE_RESULT ADISense1000_GetChannelAlert(ADI_Channel_Alert_t pAlerts)
+{
+ ADI_SENSE_RESULT eRet;
+ uint8_t i;
+ uint8_t chAlertReg;
+ uint16_t n;
+
+ memset(pAlerts, 0, sizeof(ADI_Channel_Alert_t));
+
+ eRet = ADISense1000_RegRead(regMap[CORE_CHANNEL_ALERT_STATUS].addr,
+ regMap[CORE_CHANNEL_ALERT_STATUS].size,
+ rcvBuff);
+ if (eRet != ADI_SENSE_SUCCESS)
+ {
+ return eRet;
+ }
+
+ n = ((rcvBuff[1] << 8)&0xff00) | rcvBuff[0];
+ for (i=0; i<ADI_SENSE_NUM_CHANNELS; i++)
+ {
+ if ((n >> i)&0x1)
+ {
+ chAlertReg = baseAlertReg[i];
+ eRet = ADISense1000_RegRead(regMap[chAlertReg].addr,
+ regMap[chAlertReg].size,
+ rcvBuff);
+ if (eRet != ADI_SENSE_SUCCESS)
+ {
+ return eRet;
+ }
+
+ pAlerts[i].VALUE8 = rcvBuff[0];
+ }
+
+ }
+
+ return ADI_SENSE_SUCCESS;
+}
+
+/*!
+ * @brief Send a configuration to one channel.
+ *
+ * @param[in] ADI_Channel_ID_t : Channel Identifier.
+ * @param[in] ADI_Channel_Config_t : Pointer to channel config data.
+ * @param[out]
+ * @return Status
+ * - #ADI_SENSE_SUCCESS Call completed successfully.
+ * - #ADI_SENSE_FAILURE If set channel config fails.
+ *
+ * @details Sends the entire configuration to the select channel during a
+ * single transfer.
+ */
+ADI_SENSE_RESULT ADISense1000_ConfigureChannel(ADI_Channel_ID_t eChannel,
+ ADI_Channel_Config_t *pConfig)
+{
+ ADI_SENSE_RESULT eRet;
+ uint8_t chBaseReg;
+
+ chBaseReg = baseReg[eChannel];
+ eRet = ADISense1000_RegWrite(regMap[chBaseReg].addr,
+ sizeof(ADI_Channel_Config_t),
+ (uint8_t*)pConfig);
+
+ if (eRet != ADI_SENSE_SUCCESS)
+ {
+ return eRet;
+ }
+
+ return ADI_SENSE_SUCCESS;
+}
+
+/*!
+ * @brief Start a measurement cycle.
+ *
+ * @param[in] ADI_CORE_Command_Special_Command : Conversion result format.
+ * @param[out]
+ *
+ * @return Status
+ * - #ADI_SENSE_SUCCESS Call completed successfully.
+ * - #ADI_SENSE_FAILURE
+ *
+ * @details Sends the latch config command. Configuration for channels in
+ * conversion cycle should be completed before this function.
+ * Channel enabled bit should be set before this function.
+ * Starts a conversion and configures the format of the sample.
+ *
+ */
+ADI_SENSE_RESULT ADISense1000_StartMeasurement(
+ ADI_CORE_Command_Special_Command cmd)
+{
+ ADI_SENSE_RESULT eRet;
+ ADI_CORE_Command_t command;
+ ADI_CORE_Status_t *statusreg = (ADI_CORE_Status_t *)rcvBuff;
+
+ /* Send the latch command */
+ command.Special_Command = CORE_COMMAND_LATCH_CONFIG;
+ eRet = ADISense1000_RegWrite(regMap[CORE_COMMAND].addr,
+ regMap[CORE_COMMAND].size,
+ (uint8_t*)&command);
+ if (eRet != ADI_SENSE_SUCCESS)
+ {
+ return eRet;
+ }
+
+ /* Wait for command to finish */
+ statusreg->Cmd_Running = true;
+ while (statusreg->Cmd_Running)
+ {
+ wait_ms(10);
+ eRet = ADISense1000_RegRead(regMap[CORE_STATUS].addr,
+ regMap[CORE_STATUS].size,
+ rcvBuff);
+ if (eRet != ADI_SENSE_SUCCESS)
+ {
+ return eRet;
+ }
+ }
+
+ /* Send the user command */
+ command.Special_Command = cmd;
+ eRet = ADISense1000_RegWrite(regMap[CORE_COMMAND].addr,
+ regMap[CORE_COMMAND].size,
+ (uint8_t*)&command);
+
+ if (eRet != ADI_SENSE_SUCCESS)
+ {
+ return eRet;
+ }
+
+
+ /* Wait for command to finish */
+ statusreg->Cmd_Running = true;
+ while (statusreg->Cmd_Running)
+ {
+ wait_ms(10);
+ eRet = ADISense1000_RegRead(regMap[CORE_STATUS].addr,
+ regMap[CORE_STATUS].size,
+ rcvBuff);
+ if (eRet != ADI_SENSE_SUCCESS)
+ {
+ return eRet;
+ }
+ }
+
+ return ADI_SENSE_SUCCESS;
+}
+
+/*!
+ * @brief Stop measurement on selected channel.
+ *
+ * @param[in] ADI_Channel_ID_t : Channel identifier.
+ * @param[out]
+ *
+ * @return Status
+ * - #ADI_SENSE_SUCCESS Call completed successfully.
+ * - #ADI_SENSE_FAILURE
+ *
+ * @details Un-sets the channel enable bit in the selected channel
+ * count register. Retains the cycle count in the channel
+ * count register.
+ *
+ */
+ADI_SENSE_RESULT ADISense1000_StopMeasurement(ADI_Channel_ID_t eChannel)
+{
+ ADI_SENSE_RESULT eRet;
+ uint8_t setValue;
+ uint8_t chBaseReg;
+ ADI_CORE_Command_t command;
+ ADI_CORE_Status_t *statusreg = (ADI_CORE_Status_t *)rcvBuff;
+
+ /* Read back the count register to store the cycle count for this
+ * channel.
+ */
+ chBaseReg = baseReg[eChannel];
+ eRet = ADISense1000_RegRead(regMap[chBaseReg].addr,
+ regMap[chBaseReg].size, rcvBuff);
+ if (eRet != ADI_SENSE_SUCCESS)
+ {
+ return eRet;
+ }
+
+ /* Zero the enable bit of the count register */
+ setValue = rcvBuff[0] & 0x7f;
+ eRet = ADISense1000_RegWrite(regMap[chBaseReg].addr,
+ regMap[chBaseReg].size,
+ &setValue);
+ if (eRet != ADI_SENSE_SUCCESS)
+ {
+ return eRet;
+ }
+
+ /* Send the latch command */
+ command.Special_Command = CORE_COMMAND_LATCH_CONFIG;
+ eRet = ADISense1000_RegWrite(regMap[CORE_COMMAND].addr,
+ regMap[CORE_COMMAND].size,
+ (uint8_t*)&command);
+ if (eRet != ADI_SENSE_SUCCESS)
+ {
+ return eRet;
+ }
+
+ /* Wait for command to finish */
+ statusreg->Cmd_Running = true;
+ while (statusreg->Cmd_Running)
+ {
+ wait_ms(10);
+ eRet = ADISense1000_RegRead(regMap[CORE_STATUS].addr,
+ regMap[CORE_STATUS].size,
+ rcvBuff);
+ if (eRet != ADI_SENSE_SUCCESS)
+ {
+ return eRet;
+ }
+ }
+
+ return ADI_SENSE_SUCCESS;
+}
+
+/*!
+ * @brief Get input status of data ready gpio
+ *
+ * @param[in] void
+ * @param[out]
+ *
+ * @return Status
+ * - #bool State of the data ready pin.
+ *
+ *
+ */
+bool ADISense1000_SampleReady(void)
+{
+ bool bDrdy=false;
+
+ ADISense1000_HostGpioGet(HOST_READY, &bDrdy);
+ return bDrdy;
+}
+
+/*!
+ * @brief Request sample for a selected channel.
+ *
+ * @param[in] ADI_Channel_ID_t : Channel identifier.
+ * @param[out] uint32_t : Pointer to raw ADC sample for channel.
+ * @param[out] float : Pointer to linearised ADC sample for channel.
+ * @param[out] uint8_t : Pointer to channel status.
+ *
+ * @return Status
+ * - #ADI_SENSE_SUCCESS Call completed successfully.
+ * - #ADI_SENSE_FAILURE
+ *
+ * @details Reads Data FIFO until a sample for the requested channel is
+ * received.
+ *
+ */
+ADI_SENSE_RESULT ADISense1000_GetData(uint32_t *pRaw, float *pSample,
+ uint8_t *pStatus)
+{
+ ADI_SENSE_RESULT eRet;
+ ADI_CORE_Data_FIFO_t *pChSample = (ADI_CORE_Data_FIFO_t *)rcvBuff;
+ bool bTimeOut = false;
+ uint32_t timeNow;
+ uint32_t runTime;
+
+ /* Read Data FIFO buffer until sample for channel is read */
+ readTimeout.reset();
+ readTimeout.start();
+ timeNow = readTimeout.read();
+ do {
+ eRet = ADISense1000_RegRead(regMap[CORE_DATA_FIFO].addr,
+ regMap[CORE_DATA_FIFO].size,
+ rcvBuff);
+ runTime = (readTimeout.read() - timeNow);
+ if (runTime > GET_SAMPLE_TIMEOUT)
+ {
+ bTimeOut = true;
+ }
+ wait_ms(10);
+ }
+ while ((pChSample->Ch_Valid != 1) && eRet == ADI_SENSE_SUCCESS &&
+ !(bTimeOut));
+
+ readTimeout.stop();
+
+ if (eRet != ADI_SENSE_SUCCESS)
+ {
+ pChSample->Raw_Sample = 0;
+ pChSample->Sensor_Result = 0;
+ *pRaw = pChSample->Raw_Sample;
+ *pSample = pChSample->Sensor_Result;
+ *pStatus = (pChSample->Channel_ID)|((pChSample->Ch_Error << 4))|
+ ((pChSample->Ch_Alert << 5))|((pChSample->Ch_Raw << 6))|
+ ((pChSample->Ch_Valid << 7));
+
+ return eRet;
+ }
+
+ if (bTimeOut == true)
+ {
+ pChSample->Raw_Sample = 0;
+ pChSample->Sensor_Result = 0;
+ *pRaw = pChSample->Raw_Sample;
+ *pSample = pChSample->Sensor_Result;
+ *pStatus = (pChSample->Channel_ID)|((pChSample->Ch_Error << 4))|
+ ((pChSample->Ch_Alert << 5))|((pChSample->Ch_Raw << 6))|
+ ((pChSample->Ch_Valid << 7));
+
+ return ADI_SENSE_NO_DATA;
+ }
+
+ *pRaw = pChSample->Raw_Sample;
+ *pSample = pChSample->Sensor_Result;
+ *pStatus = (pChSample->Channel_ID)|((pChSample->Ch_Error << 4))|
+ ((pChSample->Ch_Alert << 5))|((pChSample->Ch_Raw << 6))|
+ ((pChSample->Ch_Valid << 7));
+
+ return ADI_SENSE_SUCCESS;
+}
+
+/*!
+ * @brief Get register value from ADISense1000 Module
+ *
+ * @param[in] uint16_t : Register Identifier
+ * @param[out] uint32_t : Pointer to the register value.
+ *
+ * @return Status
+ * - #ADI_SENSE_SUCCESS Call completed successfully.
+ * - #ADI_SENSE_FAILURE
+ * - #ADI_SENSE_INVALID_OPERATION Invalid register identifier.
+ *
+ * @details Will return the value for any of the ADISense modules
+ * 1 byte to 4 byte size. Data FIFO register is not available to
+ * this function.
+ */
+ADI_SENSE_RESULT ADISense1000_GetRegister(uint16_t reg, uint32_t *pRegValue)
+{
+ ADI_SENSE_RESULT eRet;
+ uint8_t i;
+ uint32_t n;
+
+ if (regMap[reg].rw == WRITE_ONLY || reg > REGISTER_MAP_COUNT
+ || regMap[reg].size > 4)
+ {
+ return ADI_SENSE_INVALID_OPERATION;
+ }
+
+ eRet = ADISense1000_RegRead(regMap[reg].addr, regMap[reg].size, rcvBuff);
+
+ if(eRet != ADI_SENSE_SUCCESS)
+ {
+ return eRet;
+ }
+
+ n=0;
+ for (i=0; i<regMap[reg].size; i++)
+ {
+ n = n | (rcvBuff[i] << (i*8));
+ }
+
+ *pRegValue = n & BIT_MASK((regMap[reg].size*8));
+
+ return ADI_SENSE_SUCCESS;
+}
+
+
+/*!
+ * @brief Set register value to ADISense1000 Module
+ *
+ * @param[in] uint16_t : Register Identifier.
+ * @param[in] uint32_t : Value to write to register.
+ *
+ * @return Status
+ * - #ADI_SENSE_SUCCESS Call completed successfully.
+ * - #ADI_SENSE_FAILURE
+ * - #ADI_SENSE_INVALID_OPERATION Invalid register identifier.
+ *
+ * @details Will write a value to any of the writable ADISense modules
+ * regiters from 1 byte to 4 byte size.
+ *
+ */
+ADI_SENSE_RESULT ADISense1000_SetRegister(uint16_t reg, uint32_t regValue)
+{
+ ADI_SENSE_RESULT eRet;
+
+ if (regMap[reg].rw == READ_ONLY || reg > REGISTER_MAP_COUNT
+ || regMap[reg].size > 4)
+ {
+ return ADI_SENSE_INVALID_OPERATION;
+ }
+
+ eRet = ADISense1000_RegWrite(regMap[reg].addr, regMap[reg].size,
+ (uint8_t*)(®Value));
+
+ if(eRet != ADI_SENSE_SUCCESS)
+ {
+ return eRet;
+ }
+
+ return ADI_SENSE_SUCCESS;
+}
+
