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.
Dependencies: platform_drivers
Diff: app/iio_ad7606.c
- Revision:
- 3:83b3133f544a
- Parent:
- 1:819ac9aa5667
- Child:
- 6:75e922b3859a
--- a/app/iio_ad7606.c Mon Oct 05 09:39:06 2020 +0000
+++ b/app/iio_ad7606.c Fri Oct 16 21:37:35 2020 +0530
@@ -45,15 +45,41 @@
/* ADC data to Voltage conversion scale factor for IIO client */
#define DEFAULT_SCALE ((DEFAULT_CHN_RANGE / ADC_MAX_COUNT_BIPOLAR) * 1000)
-/* LSB Threshold to entry into open wire detection as per datasheet */
-#define OPEN_DETECT_ENTRY_THRESHOLD 350
+/* LSB Threshold to entry into open circuit detection as per datasheet */
+#define MANUAL_OPEN_DETECT_ENTRY_TRHLD 350
+
+/* Manual open circuit detect LSB threshold @50K Rpd as per datasheet */
+#define MANUAL_OPEN_DETECT_THRESHOLD_RPD50K 20
+
+/* Number of consecutive conversions (N) in manual open circuit detection */
+#define MANUAL_OPEN_DETECT_CONV_CNTS 10
-/* Open detect LSB threshold @50K Rpd as per datasheet */
-#define OPEN_DETECT_THRESHOLD_RPD50K 15
+/* LSB Threshold b/w consecutive N conversions */
+#define MANUAL_OPEN_DETECT_CONV_TRSHLD 10
+
+/* Number of common mode conversions in manual open circuit detect */
+#define MANUAL_OPEN_DETECT_CM_CNV_CNT 3
+
+/* Max number of queue counts for auto mode open circuit detection */
+#define AUTO_OPEN_DETECT_QUEUE_MAX_CNT 128
+#define AUTO_OPEN_DETECT_QUEUE_EXTRA_CONV_CNT 15
/* Maximum ADC calibration gain value */
#define ADC_CALIBRATION_GAIN_MAX 64.0
+#if defined(DEV_AD7606C_18)
+#define OFFSET_REG_RESOLUTION 4
+#else
+#define OFFSET_REG_RESOLUTION 1
+#endif
+
+/* Default sampling frequency for AD7606 (in SPS) to define IIO client timeout period.
+ * Note: The actual sampling frequncy is much higher (~30KSPS per channel), however the
+ * data transmission back to IIO client is limited by the serial (UART) link, which
+ * can provide max transmission rate of ~3-4KSPS. Hence sampling frequency is set to 1Khz
+ * for safer side */
+#define AD7606_DEFLT_SAMPLING_FREQEUNCY (1000)
+
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
@@ -98,8 +124,8 @@
"8 (+/-10.0V SE)", "9 (+/-10.0V SE)", "10 (+/-10.0V SE)", "11 (+/-10.0V SE)",
#elif defined(DEV_AD7606C_18) || defined(DEV_AD7606C_16)
"0 (+/-2.5V SE)", "1 (+/-5.0V SE)", "2 (+/-6.25V SE)", "3 (+/-10.0V SE)",
- "4 (+/-12.5V SE)", "5 (+5.0V SE)", "6 (+10.0V SE)", "7 (+12.5V SE)",
- "8 (+/-5.0V DE)", "9 (+/-10.0V DE)", "10 (+/-12.5V DE)", "11 (+/-20.0V DE)"
+ "4 (+/-12.5V SE)", "5 (0 to 5V SE)", "6 (0 to 10V SE)", "7 (0 to 12.5V SE)",
+ "8 (+/-5.0V Diff)", "9 (+/-10.0V Diff)", "10 (+/-12.5V Diff)", "11 (+/-20.0V Diff)"
#elif defined(DEV_AD7609)
"0 (+/-10.0V SE)", "1 (+/-20.0V SE)"
#else
@@ -171,6 +197,17 @@
/* Flag to trigger new background conversion and capture when READBUFF command is issued */
static bool adc_background_data_capture_started = false;
+/* Gain calibration status */
+static bool gain_calibration_done = false;
+
+/* Open circuit mode detection flags */
+static bool open_circuit_detection_done = false;
+static bool open_circuit_detection_error = false;
+static bool open_circuit_detect_read_done = false;
+
+/* Sampling frequency of device */
+static uint16_t sampling_frequency = AD7606_DEFLT_SAMPLING_FREQEUNCY;
+
/******************************************************************************/
/************************ Functions Prototypes ********************************/
/******************************************************************************/
@@ -217,6 +254,37 @@
/*!
+ * @brief Getter/Setter for the sampling frequency attribute value
+ * @param device- pointer to IIO device structure
+ * @param buf- pointer to buffer holding attribute value
+ * @param len- length of buffer string data
+ * @param channel- pointer to IIO channel structure
+ * @return Number of characters read/written
+ * @Note This attribute is used to define the timeout period in IIO
+ * client during data capture.
+ * Timeout = (number of requested samples * (1/sampling frequency)) + 1sec
+ * e.g. if sampling frequency = 1KSPS and requested samples = 400
+ * Timeout = (400 * 0.001) + 1 = 1.4sec
+ */
+ssize_t get_sampling_frequency(void *device,
+ char *buf,
+ size_t len,
+ const struct iio_ch_info *channel)
+{
+ return (ssize_t) sprintf(buf, "%d", sampling_frequency);
+}
+
+ssize_t set_sampling_frequency(void *device,
+ char *buf,
+ size_t len,
+ const struct iio_ch_info *channel)
+{
+ /* NA- Can't set sampling frequency value */
+ return len;
+}
+
+
+/*!
* @brief Getter/Setter for the raw attribute value
* @param device- pointer to IIO device structure
* @param buf- pointer to buffer holding attribute value
@@ -1057,70 +1125,114 @@
/*!
- * @brief Getter/Setter for the channel open wire detect manual attribute value
+ * @brief Getter/Setter for the channel open circuit detect manual attribute value
* @param device- pointer to IIO device structure
* @param buf- pointer to buffer holding attribute value
* @param len- length of buffer string data
* @param channel- pointer to IIO channel structure
* @return Number of characters read/written
*/
-ssize_t get_chn_open_wire_detect_manual(void *device,
- char *buf,
- size_t len,
- const struct iio_ch_info *channel)
+ssize_t get_chn_open_circuit_detect_manual(void *device,
+ char *buf,
+ size_t len,
+ const struct iio_ch_info *channel)
{
- static volatile int32_t data[2];
- uint8_t open_detect_flag = false;
- int32_t rw_status = FAILURE;
+ int32_t prev_adc_code, curr_adc_code;
+ bool open_detect_flag = false;
+ bool open_detect_done = false;
+ uint8_t cnt;
- /* Read the ADC on selected channel (before open wire detection start) */
- data[0] = single_data_read(device,
- channel->ch_num - 1,
- attr_polarity_val[channel->ch_num - 1]);
+ /* Enter into manual open circuit detection mode */
+ do {
+ if (ad7606_spi_reg_write(device, AD7606_REG_OPEN_DETECT_QUEUE, 1) == SUCCESS) {
+ /* Read the ADC on selected chnnel (first reading post open circuit detection start) */
+ prev_adc_code = single_data_read(device,
+ channel->ch_num - 1,
+ attr_polarity_val[channel->ch_num - 1]);
- /* Enter into manual open wire detect mode */
- if (ad7606_spi_reg_write(device, AD7606_REG_OPEN_DETECT_QUEUE, 1) == SUCCESS) {
- /* Set common mode high (enabling open wire detect on selected channel) */
- if (ad7606_spi_reg_write(device, AD7606_REG_OPEN_DETECT_ENABLE,
- (1 << ((channel->ch_num) - 1))) == SUCCESS) {
- /* Read the ADC on selected chnnel (post open wire detection) */
- data[1] = single_data_read(device, channel->ch_num - 1,
- attr_polarity_val[channel->ch_num - 1]);
+ /* Perform N conversions and monitor the code delta */
+ for (cnt = 0; cnt < MANUAL_OPEN_DETECT_CONV_CNTS; cnt++) {
+ /* Check if code is within 350LSB (nearest ZS code) */
+ if (prev_adc_code >= 0 && prev_adc_code < MANUAL_OPEN_DETECT_ENTRY_TRHLD) {
+ /* Perform next conversion and read the result */
+ curr_adc_code = single_data_read(device,
+ channel->ch_num - 1,
+ attr_polarity_val[channel->ch_num - 1]);
- /* Check for up shift in common mode output voltage */
- if ((data[1] - data[0]) > OPEN_DETECT_THRESHOLD_RPD50K) {
- /* Set common mode low (disabling open wire detect on channels) */
- if (ad7606_spi_reg_write(device,
- AD7606_REG_OPEN_DETECT_ENABLE,
- 0) == SUCCESS) {
-
- /* Let channel settle down */
- mdelay(1);
+ /* Check if delta b/w current and previus reading is within 10 LSB code */
+ if (abs(curr_adc_code - prev_adc_code) > MANUAL_OPEN_DETECT_CONV_TRSHLD) {
+ open_detect_done = true;
+ break;
+ }
- /* Read the ADC output after open wire detection */
- data[1] = single_data_read(device,
- channel->ch_num - 1,
- attr_polarity_val[channel->ch_num - 1]);
-
- /* Check if code returns back to original (with some threshold) */
- if (abs(data[1] - data[0]) <= OPEN_DETECT_THRESHOLD_RPD50K) {
- open_detect_flag = true;
- }
+ /* Get the previous code */
+ prev_adc_code = curr_adc_code;
+ } else {
+ open_detect_done = true;
+ break;
}
}
- rw_status = SUCCESS;
+ /* Break if open circuit detection aborted (in case above conditions not met) */
+ if (open_detect_done)
+ break;
+
+ /* Set common mode high (enabling open circuit detect on selected channel) */
+ if (ad7606_spi_reg_write(device,
+ AD7606_REG_OPEN_DETECT_ENABLE,
+ (1 << ((channel->ch_num) - 1))) == SUCCESS) {
+
+ /* Perform next conversions (~2-3) and read the result (with common mode set high) */
+ for (cnt = 0; cnt < MANUAL_OPEN_DETECT_CM_CNV_CNT; cnt++) {
+ udelay(100);
+ curr_adc_code = single_data_read(device,
+ channel->ch_num - 1,
+ attr_polarity_val[channel->ch_num - 1]);
+ }
+
+ /* Check if delta b/w common mode high code and previous N conversion code is > threshold */
+ if ((curr_adc_code - prev_adc_code) < MANUAL_OPEN_DETECT_THRESHOLD_RPD50K) {
+ open_detect_done = true;
+ break;
+ }
+ } else {
+ return -EINVAL;
+ }
+
+ /* Break if open circuit detection aborted (in case above conditions not met) */
+ if (open_detect_done)
+ break;
+
+ /* Set common mode low (disabling open circuit detect on channel) */
+ if (ad7606_spi_reg_write(device,
+ AD7606_REG_OPEN_DETECT_ENABLE,
+ 0) == SUCCESS) {
+ /* Perform next conversion and read the result (with common mode set low) */
+ curr_adc_code = single_data_read(device,
+ channel->ch_num - 1,
+ attr_polarity_val[channel->ch_num - 1]);
+
+ /* Check if delta b/w common mode low code and previous N conversion code is < threshold */
+ if (abs(curr_adc_code - prev_adc_code) < MANUAL_OPEN_DETECT_THRESHOLD_RPD50K) {
+ open_detect_flag = true;
+ open_detect_done = true;
+ }
+ } else {
+ return -EINVAL;
+ }
+ } else {
+ return -EINVAL;
}
- }
+ } while (0);
/* Disable open detect mode */
(void)ad7606_spi_reg_write(device, AD7606_REG_OPEN_DETECT_QUEUE, 0);
- if (rw_status == SUCCESS) {
+ if (open_detect_done) {
if (open_detect_flag) {
- strcpy(buf, "Open Wire Detected");
+ strcpy(buf, "Open Circuit Detected");
} else {
- strcpy(buf, "Open Wire Not Detected");
+ strcpy(buf, "Open Circuit Not Detected");
}
return len;
@@ -1129,105 +1241,126 @@
return -EINVAL;
}
-ssize_t set_chn_open_wire_detect_manual(void *device,
- char *buf,
- size_t len,
- const struct iio_ch_info *channel)
+ssize_t set_chn_open_circuit_detect_manual(void *device,
+ char *buf,
+ size_t len,
+ const struct iio_ch_info *channel)
{
- // NA- Can't set open wire detect
+ // NA- Can't set open circuit detect
return - EINVAL;
}
/*!
- * @brief Getter/Setter for the channel open wire detect auto attribute value
+ * @brief Getter/Setter for the channel open circuit detect auto attribute value
* @param device- pointer to IIO device structure
* @param buf- pointer to buffer holding attribute value
* @param len- length of buffer string data
* @param channel- pointer to IIO channel structure
* @return Number of characters read/written
*/
-ssize_t get_chn_open_wire_detect_auto(void *device,
- char *buf,
- size_t len,
- const struct iio_ch_info *channel)
+ssize_t get_chn_open_circuit_detect_auto(void *device,
+ char *buf,
+ size_t len,
+ const struct iio_ch_info *channel)
{
- uint8_t open_detect_flag = false;
- int32_t rw_status = FAILURE;
- uint8_t conv_cnts;
+ if (open_circuit_detect_read_done) {
+ open_circuit_detect_read_done = false;
+
+ if (open_circuit_detection_error) {
+ strcpy(buf, "Error!!");
+ }
- if (open_detect_queue_cnts[channel->ch_num-1] <= 1) {
- strcpy(buf, "Err: OPEN_DETECT_QUEUE Invalid");
+ if (open_circuit_detection_done) {
+ strcpy(buf, "Open Circuit Detected");
+ } else {
+ strcpy(buf, "Open Circuit Not Detected");
+ }
+
return len;
}
- /* Enter into auto open detect mode */
- if (ad7606_spi_reg_write(device, AD7606_REG_OPEN_DETECT_QUEUE,
- open_detect_queue_cnts[channel->ch_num-1]) == SUCCESS) {
- /* Enable open wire detection on selected channel */
- if (ad7606_spi_reg_write(device, AD7606_REG_OPEN_DETECT_ENABLE,
- (1 << ((channel->ch_num) - 1))) == SUCCESS) {
- /* Monitor the open detect flag for max N (open detect queue count) conversions.
- * Note: In ideal scenario, the open detect flash should be monitored continuously while
- * background N conversions are in progress */
- for (conv_cnts = 0; conv_cnts < open_detect_queue_cnts[channel->ch_num - 1];
- conv_cnts++) {
- if (ad7606_convst(device) == SUCCESS) {
- udelay(100);
+ return (ssize_t)sprintf(buf, "OPEN_DETECT_QUEUE: %d",
+ open_detect_queue_cnts[channel->ch_num - 1]);
+}
+
+ssize_t set_chn_open_circuit_detect_auto(void *device,
+ char *buf,
+ size_t len,
+ const struct iio_ch_info *channel)
+{
+ uint8_t data;
+ uint8_t open_detect_flag = false;
+ int32_t rw_status = FAILURE;
+ uint16_t conv_cnts;
+
+ (void)sscanf(buf, "%d", &data);
+ open_circuit_detection_error = false;
+
+ if ((data > 1 && data <= AUTO_OPEN_DETECT_QUEUE_MAX_CNT) && (buf[0] >= '0'
+ && buf[0] <= '9')) {
+ open_detect_queue_cnts[channel->ch_num - 1] = data;
- /* Monitor the open detect flag */
- if (ad7606_spi_reg_read(device,
- AD7606_REG_OPEN_DETECTED,
- &open_detect_flag) == SUCCESS) {
- open_detect_flag >>= (channel->ch_num - 1);
- open_detect_flag &= 0x1;
+ /* Enter into open circuit auto open detect mode */
+ if (ad7606_spi_reg_write(device,
+ AD7606_REG_OPEN_DETECT_QUEUE,
+ open_detect_queue_cnts[channel->ch_num - 1]) == SUCCESS) {
+ /* Enable open circuit detection on selected channel */
+ if (ad7606_spi_reg_write(device,
+ AD7606_REG_OPEN_DETECT_ENABLE,
+ (1 << ((channel->ch_num) - 1))) == SUCCESS) {
+ /* Monitor the open detect flag for max N+15 (open detect queue count) conversions.
+ * Note: In ideal scenario, the open detect flash should be monitored continuously while
+ * background N conversions are in progress */
+ for (conv_cnts = 0;
+ conv_cnts < (open_detect_queue_cnts[channel->ch_num - 1] +
+ AUTO_OPEN_DETECT_QUEUE_EXTRA_CONV_CNT);
+ conv_cnts++) {
+ if (ad7606_convst(device) == SUCCESS) {
+ udelay(100);
- rw_status = SUCCESS;
- if (open_detect_flag) {
+ /* Monitor the open detect flag */
+ if (ad7606_spi_reg_read(device,
+ AD7606_REG_OPEN_DETECTED,
+ &open_detect_flag) == SUCCESS) {
+ open_detect_flag >>= (channel->ch_num - 1);
+ open_detect_flag &= 0x1;
+
+ rw_status = SUCCESS;
+ if (open_detect_flag) {
+ break;
+ }
+ } else {
+ rw_status = FAILURE;
break;
}
} else {
rw_status = FAILURE;
break;
}
- } else {
- rw_status = FAILURE;
- break;
}
}
}
+
+ /* Disable open detect mode and clear open detect flag */
+ (void)ad7606_spi_reg_write(device, AD7606_REG_OPEN_DETECT_QUEUE, 0);
+ (void)ad7606_spi_reg_write(device, AD7606_REG_OPEN_DETECTED, 0xFF);
+
+ open_detect_queue_cnts[channel->ch_num - 1] = 0;
+
+ if (rw_status == SUCCESS) {
+ if (open_detect_flag) {
+ open_circuit_detection_done = true;
+ } else {
+ open_circuit_detection_done = false;
+ }
+
+ open_circuit_detect_read_done = true;
+ return len;
+ }
}
- /* Disable open detect mode */
- (void)ad7606_spi_reg_write(device, AD7606_REG_OPEN_DETECT_QUEUE, 0);
-
- if (rw_status == SUCCESS) {
- if (open_detect_flag) {
- strcpy(buf, "Open Wire Detected");
- } else {
- strcpy(buf, "Open Wire Not Detected");
- }
-
- return len;
- }
-
- return -EINVAL;
-}
-
-ssize_t set_chn_open_wire_detect_auto(void *device,
- char *buf,
- size_t len,
- const struct iio_ch_info *channel)
-{
- uint8_t data;
-
- (void)sscanf(buf, "%d", &data);
-
- if (data > 1) {
- open_detect_queue_cnts[channel->ch_num - 1] = data;
- return len;
- }
-
+ open_circuit_detection_error = true;
return -EINVAL;
}
@@ -1268,7 +1401,7 @@
attr_scale_val[channel->ch_num - 1]);
/* Calculate the channel offset and write it to offset register */
- chn_offset = -(adc_voltage / lsb_voltage);
+ chn_offset = -(adc_voltage / lsb_voltage / OFFSET_REG_RESOLUTION);
if (ad7606_set_ch_offset(device, channel->ch_num - 1,
chn_offset) == SUCCESS) {
@@ -1283,7 +1416,7 @@
size_t len,
const struct iio_ch_info *channel)
{
- // NA- Can't set open wire detect
+ // NA- Can't set open circuit detect
return - EINVAL;
}
@@ -1301,15 +1434,22 @@
size_t len,
const struct iio_ch_info *channel)
{
- uint8_t chn_gain;
-
- /* Perform the gain calibration */
- chn_gain = gain_calibration_reg_val[channel->ch_num - 1];
+ uint8_t read_val;
- if (ad7606_set_ch_gain(device,
- channel->ch_num - 1,
- chn_gain) == SUCCESS) {
- return sprintf(buf, "Calibration Done (Rfilter=%d K)", chn_gain);
+ if (gain_calibration_done) {
+ /* Get calibration status for previous gain value write event */
+ gain_calibration_done = false;
+ return sprintf(buf, "Calibration Done (Rfilter=%d K)",
+ gain_calibration_reg_val[channel->ch_num - 1]);
+ }
+
+ /* Return gain value when normal read event is triggered */
+ if (ad7606_spi_reg_read(device,
+ AD7606_REG_GAIN_CH(channel->ch_num - 1),
+ &read_val) == SUCCESS) {
+ gain_calibration_reg_val[channel->ch_num - 1] = (read_val & AD7606_GAIN_MSK);
+ return sprintf(buf, "Rfilter= %d K",
+ gain_calibration_reg_val[channel->ch_num - 1]);
}
return -EINVAL;
@@ -1322,12 +1462,21 @@
{
float data;
- (void)sscanf(buf, "%f", &data);
+ if (buf[0] >= '0' && buf[0] <= '9') {
+ (void)sscanf(buf, "%f", &data);
+
+ if (data >= 0 && data < ADC_CALIBRATION_GAIN_MAX) {
+ /* Get the nearest value of unsigned integer */
+ gain_calibration_reg_val[channel->ch_num - 1] = (uint8_t)(round(data));
- if (data < ADC_CALIBRATION_GAIN_MAX) {
- /* Get the nearest value of unsigned integer */
- gain_calibration_reg_val[channel->ch_num - 1] = (uint8_t)(round(data));
- return len;
+ /* Perform the gain calibration by writing gain value into gain register */
+ if (ad7606_set_ch_gain(device,
+ channel->ch_num - 1,
+ gain_calibration_reg_val[channel->ch_num - 1]) == SUCCESS) {
+ gain_calibration_done = true;
+ return len;
+ }
+ }
}
return -EINVAL;