EVAL-AD593x Mbed Project.

Dependencies:   platform_drivers

main.cpp

Committer:
ssmith73
Date:
2019-10-29
Revision:
4:953fb3148f25
Parent:
1:bd8aea0d51e0

File content as of revision 4:953fb3148f25:

/*************************************************************************//**
 *   @file   main.cpp
 *   @brief  Main application code for AD5686 firmware example program
 *   @author ssmith (sean.smith@analog.com)
******************************************************************************
* Copyright (c) 2019 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/products 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.
* 
* 20180927-7CBSD SLA
*****************************************************************************/

#include <mbed.h>
#include <ctype.h>
#include "app_config.h"

#define NOT_USED 0
//Lower this value if storage becomes a problem
#define MAX_FREQ_INCREMENTS 511
#define TEMP_LIMIT_MIN -40
#define TEMP_LIMIT_MAX 125 


static void print_title(void);
static void getMenuSelect(uint8_t *menuSelect);
static void print_prompt();
static uint8_t read_temperature();
static uint8_t set_system_clock();
static uint8_t set_vrange_and_pga_gain();
static int32_t configure_system();
static uint8_t calculate_gain_factor();
static uint8_t guide();
static uint8_t impedance_sweep();

typedef struct ad5933_config_data {
	float 	start_freq;
	uint8_t pga_gain;
	float 	output_voltage_range;
	int32_t start_frequency;
	int32_t frequency_increment;
	int32_t number_increments;
	int32_t number_settling_cycles;
}ad5933_config_data;

ad5933_config_data config_data;

static double gain_factor = 0;
static double temperature;


/******************************************************************************/
/************************** Variables Declarations ****************************/
/******************************************************************************/

/**
	The following definitions are a requirement for the platform_driver
	Pin are changed if required in the app_config.h file
 ***/
mbed::SPI spi(SPI_MOSI, SPI_MISO, SPI_SCK, SPI_CS);
mbed::I2C i2c(I2C_SDA, I2C_SCL);
PinName slave_selects[MAX_SLAVE_SELECTS];

i2c_init_param i2c_params =
{
	GENERIC_I2C,				// i2c type
    0,							// i2c id
	100000,						// i2c max speed (hz)
	AD5933_ADDRESS << 1,		// i2c slave address //A0 tied high
};


ad5933_init_param init_params = {
	i2c_params,					// I2C parameters 
	AD5933_INTERNAL_SYS_CLK,	//current_sys_clk frequency (16MHz)
	AD5933_CONTROL_INT_SYSCLK,	//current_clock_source
	AD5933_RANGE_1000mVpp,		//current_gain
	AD5933_GAIN_X1,				//current_range
	AD5933_15_CYCLES,			//current_settling
};

ad5933_dev *device;
int32_t connected = -1;
Serial pc(USBTX, USBRX, 115200);


int main()
{
	uint8_t menu_select = 0;
	print_title();
	connected = ad5933_init(&device, init_params);


	//Do a quick check to ensure basic connectivity is ok
	temperature  = ad5933_get_temperature(device);
	if (temperature >= TEMP_LIMIT_MIN && temperature <= TEMP_LIMIT_MAX) {
		pc.printf("\nTemperature: %f, AD5933 initialisation successful!\n",temperature);
	}
	else {
		pc.printf("AD5933 initialisation reported a bad temperature - recommend debug :\n");
	}

	while (connected == SUCCESS) {
		print_prompt();
		getMenuSelect(&menu_select);
		config_data.start_freq = 10000;

		if (menu_select > 12)
			print_prompt();
		else switch (menu_select)
			{
			case 0: 
				guide();
				wait(2); 
				break;

			case 1:
				read_temperature();
				break;
			case 2:
				configure_system();
				break;
			case 3:
				calculate_gain_factor();
				break;
			case 4:
				impedance_sweep();
				break;

			default:
				pc.printf("Invalid option: Ignored.");
				break;
			}

			wait(0.1);
		}

		return 0;
}

//! Prints the title block
void print_title()
{
	pc.printf("*****************************************************************\n");
	pc.printf("* AD5933 Demonstration Program -- (mbed 1.0)                    *\n");
	pc.printf("*                                                               *\n");
	pc.printf("* This program demonstrates communication with the AD5933       *\n");
	pc.printf("*                                                               *\n");
	pc.printf("* 1 MSPS, 12-Bit Impedance Converter, Network analyser          *\n");
	pc.printf("*                                                               *\n");
	pc.printf("* Set the baud rate to 115200 select the newline terminator.    *\n");
	pc.printf("*****************************************************************\n");
}

void print_prompt()
{
	pc.printf("\n\n\rCommand Summary:\n\n");
	pc.printf("  0  -Software Guide\n");
	pc.printf("  1  -Read temperature\n");
	pc.printf("  2  -Configure voltage-range, PGA-Gain and sweep parameters\n");
	pc.printf("  3  -Calculate Gain-Factor\n");
	pc.printf("  4  -Do an impedance sweep\n");
	pc.printf("\n\rMake a selection...\n");

}


static void getMenuSelect(uint8_t *menuSelect) {
	pc.scanf("%d", (int *)menuSelect);
}

static uint8_t read_temperature()
{
	temperature = ad5933_get_temperature(device);

	pc.printf("Current temperature:%.3f C", temperature);
	return SUCCESS;
}

static uint8_t set_system_clock()
{
	pc.printf("  Select Internal (1) or external clock (2): ");

	int input = 0;
	pc.scanf("%d", &input);
	if (isdigit(input) == 0 && (input == 1 || input == 2))
	{
		input == 1 ? pc.printf("\n  You selected Internal clock source\n") :
			pc.printf("  You selected external Source clock source\n");
	}
	else
	{
		pc.printf("Invalid entry\n");
		wait(2);
		return FAILURE;
	}

	if (input == 2)
	{
		
		pc.printf("  Enter external clock frequency in Hz ");
		pc.scanf("%d", &input);
		if (isdigit(input) == 0  && input > 0 && input < 20000000)
		{
			pc.printf("  External clk-source frequency set to %d \n", input);
		}
		else
		{
			pc.printf("Invalid entry\n");
			wait(2);
			return FAILURE;
		}
	}

	ad5933_set_system_clk(device,
		input == 1 ? AD5933_CONTROL_INT_SYSCLK : 
									AD5933_CONTROL_EXT_SYSCLK,
		input);

	return 0;
}

static uint8_t set_vrange_and_pga_gain()
{
	int input;
	uint8_t v_range = AD5933_RANGE_1000mVpp;

	pc.printf("  Select output voltage range:\n");
	pc.printf("    0: 2Vpp typical:\n");
	pc.printf("    1: 200mVpp typical:\n");
	pc.printf("    2: 400mVpp typical:\n");
	pc.printf("    3: 1Vpp typical:\n");


	pc.scanf("%d", &input);
	if (input >= 0 && input < 4)
	{
		switch (input)
		{
		case AD5933_RANGE_2000mVpp: { 
				pc.printf("  Selected 2V pp typical.\n");
				break;
			}
		case AD5933_RANGE_200mVpp: { 
				pc.printf("  Selected 200mV pp typical.\n");
				break;
			}
		case AD5933_RANGE_400mVpp: { 
				pc.printf("  Selected 400mV pp typical.\n");
				break;
			}
		case AD5933_RANGE_1000mVpp: { 
				pc.printf("  Selected 1V pp typical.\n");
				break;
			}
		}
		v_range = input;
	}
	else
	{
		pc.printf("Invalid entry\n");
		wait(2);
		return FAILURE;
	}

	pc.printf("\n  Select PGA Gain (0=X5, 1=X1)\n");
	pc.scanf("%d", &input);
	if (input >= 0 && input < 2)
	{
		config_data.pga_gain = input;
		config_data.output_voltage_range = v_range;

		pc.printf("PGA gain set to : ");
		input == AD5933_GAIN_X5 ? printf("X5\n\n") : printf("X1\n\n");
		ad5933_set_range_and_gain(device, 
			config_data.output_voltage_range,
			config_data.pga_gain);
	}
	else
	{
		pc.printf("Invalid entry: write aborted\n");
		wait(2);
		return FAILURE;
	}
		

	return SUCCESS;
}

static int32_t configure_system()
{

	pc.printf("Configure the impedance meter\n\n");
	set_vrange_and_pga_gain();
	set_system_clock();

	int start_freq;
	int freq_inc;
	int num_increments;
	int num_settling_cycles;
	int multiplier = AD5933_SETTLING_X1;

	pc.printf("\n  Enter start-frequency as a decimal number: ");
	if (pc.scanf("%d", &start_freq) == 1)
	{
		if (start_freq <= 0)
		{
			pc.printf("  Invalid entry, write aborted: \n");
			return FAILURE;
		}
	}


	pc.printf("\n  Enter frequency-increment as a decimal number: ");
	pc.scanf("%d", &freq_inc);
	if (isdigit(freq_inc) != 0  || freq_inc <= 0)
	{
		pc.printf("  Invalid entry, write aborted: \n");
		return FAILURE;
	}

	pc.printf("\n  Enter the number of increments as a decimal number: ");
	pc.printf("\n  Number of increments must be less than %d\n", MAX_FREQ_INCREMENTS);
	pc.scanf("%d", &num_increments);
	if (isdigit(num_increments) != 0  || num_increments > MAX_FREQ_INCREMENTS)
	{
		pc.printf("  Invalid entry, write aborted: \n");
		return FAILURE;
	}

	pc.printf("Enter the number of settling-time cycles before ADC is triggered.\n");
	pc.scanf("%d", &num_settling_cycles);
	if (num_settling_cycles > AD5933_MAX_SETTLING_CYCLES )
	{
		pc.printf("  Invalid entry, write aborted: \n");
		return FAILURE;
	}

	pc.printf("Set the settling time multiplier (X1=0, X2=1, X4=2).\n");
	pc.scanf("%d", &multiplier);
	if (multiplier > 2)
	{
		pc.printf("  Invalid entry, write aborted: \n");
		return FAILURE;
	}
	else
	{   //adjust X4 option to match memory map
		if (multiplier == 2) 
			multiplier = AD5933_SETTLING_X4;
	}

	pc.printf("\n    Setting start frequency to %d\n\r", (unsigned int)start_freq);
	pc.printf("    Setting frequency increment to %d\n\r", (unsigned int)freq_inc);
	pc.printf("    Setting the number of increments to %d\n\r", (unsigned int)num_increments);
	pc.printf("    Setting the number of settling-cycles to %d\n\r", (unsigned int)num_settling_cycles);
	pc.printf("    The multiplier for the settling-cycles %d\n\r", (unsigned int)multiplier+1);

	//update device state
	config_data.start_freq = start_freq;
	config_data.frequency_increment = freq_inc;
	config_data.number_increments = num_increments;
	config_data.number_settling_cycles = num_settling_cycles;

	ad5933_set_settling_time(device,multiplier,num_settling_cycles);
	ad5933_set_range_and_gain(device, device->current_range, device->current_gain);
	ad5933_config_sweep(device, start_freq, freq_inc, num_increments);

	return SUCCESS;

}

static uint8_t calculate_gain_factor()
{

	double calibration_impedance;

	pc.printf("\n\nCalculate the gain-factor (see datasheet for information)\n");
	pc.printf("Calcualted gain-factor will be stored for impedance measurements and\n");
	pc.printf("displayed on the terminal screen.\n");
	pc.printf("Ensure that the system has been configured before\n");
	pc.printf("calculating the gain factor\n");
              
	ad5933_config_sweep(device,
		config_data.start_freq, 
		config_data.frequency_increment,
		config_data.number_increments);

    // Do standby, init-start freq, start the sweep, and wait for valid data
	ad5933_start_sweep(device);
   
	pc.printf("\nEnter calibration resistance in Ohms: ");
	pc.scanf("%le", &calibration_impedance);


	pc.printf("Calculating gain factor\n\r");

	gain_factor = ad5933_calculate_gain_factor(device,
		calibration_impedance,
		AD5933_FUNCTION_REPEAT_FREQ);
	pc.printf("\n\r    Calculated gain factor %e\n\r", gain_factor);
	
	
	return SUCCESS;
}	




static uint8_t guide()
{

	pc.printf("\n\rAD5933-Demo quick-start guide: \n\n");
	pc.printf("This program can be used both as a demo of the AD5933 impedance \n");
	pc.printf("measurement system and as a starting point for developing a \n");
	pc.printf("more advanced program for prototyping. This program is not \n");
	pc.printf("provided as production-quality code, but as a helpful starting point.\n\n");

	pc.printf("As a quick start, the following steps can be implemented to ensure\n");
	pc.printf("firmware is communcating with the board and measurements taking place.\n\n");
    
	pc.printf("Firstly - use menu option 1 to read the on-chip temperature.\n");
	pc.printf("If a realistic temperature comes back - you are good to go :)\n\n");
    
	pc.printf("Step 1\tConnect a 200k Resistor across the SMA terminals of the PMOD 1A\n");
	pc.printf("Step 2\tSelect the 100k feedback resistor by pulling the SEL pin high\n");
	pc.printf("Step 2\tConfigure the impedance system with Menu Option 2\n");
	pc.printf("Step 3\tCalculate the gain factor with menu-item 3\n");
	pc.printf("Step 3\tReplace the 200k impedance across the SMA terminals with a \n");
	pc.printf("different 'unknown' impedance (300K perhaps)\n");
	pc.printf("Step 4\tRun the impedance measurement with menu-item 4\n");
	pc.printf("\tresults are dispayed on the terminal\n");
    
	return SUCCESS;
}



static uint8_t impedance_sweep() {

	ad5933_result results;

	pc.printf("\nPerform a sweep to calculate an unknown impedance (see datasheet for information)\n");
	pc.printf("System should have been previously configured (Menu Option 2)\n");
	pc.printf("Impedance will be caculated and results shown.\n\r");

	int32_t status = FAILURE;
	double impedance;
	float frequency = config_data.start_freq;

	
	ad5933_config_sweep(device,
		config_data.start_freq, 
		config_data.frequency_increment,
		config_data.number_increments);

	/*
		> program frequency sweep parameters into relevant registerS
		> place the ad5933 into standby mode.
		> start frequency register
		> number of increments register
	*/
	ad5933_start_sweep(device);
	pc.printf("\n  FREQUENCY MAGNITUDE   PHASE	IMPEDANCE\n");

	do {

		//Fill up the results struct with data
		results = ad5933_calculate_impedance(device,
			gain_factor,
			AD5933_FUNCTION_INC_FREQ);

		impedance =  1 / (results.magnitude * gain_factor);

		pc.printf("  %.2f,", frequency);
		pc.printf("  %.2f", results.magnitude);
		pc.printf("  %.2f", results.phase);
		pc.printf("  %.2f\n", impedance);
			
		frequency += config_data.frequency_increment;

		//poll the status register to check if frequency sweep is complete.
		status = ad5933_get_register_value(device, AD5933_REG_STATUS, 1);
		
	} while ((status & AD5933_STAT_SWEEP_DONE) == 0);

	return status;
}