experiment.c 36.5 KiB
Newer Older
Michael DM Dryden's avatar
 
Michael DM Dryden committed
void swv_experiment(uint16_t start, uint16_t stop, uint16_t step, uint16_t pulse_height, uint16_t frequency, uint8_t scans){
Michael DM Dryden's avatar
 
Michael DM Dryden committed
	 * @param start Start voltage in dac units.
	 * @param stop Stop voltage in dac units.
	 * @param step Step voltage in dac units.
	 * @param pulse_height Pulse amplitude in dac units.
	 * @param scans Number of scans (0 for single direction mode)
	tc_enable(&EXP_TC0_1);
	tc_enable(&EXP_TC0_0);
	
	frequency *= 2; //compensate for half-period triggers
	
	//calculate time to ADC trigger
	period = ceil((1/(double)frequency)*F_CPU);
	uint32_t adc_period = ceil(((1/(double)frequency)-(double)(sample_delay_ms_100div/1e5))*F_CPU);
	set_timer_period(period, &EXP_TC0_1);
	set_timer_period(adc_period, &EXP_TC0_0);
		EXP_TC0_1.CNT = 0;
		EXP_TC0_0.CNT = 0;
Michael DM Dryden's avatar
 
Michael DM Dryden committed
		if (_swv_singledir(start, stop, pulse_height, step, direction))
			goto aborting; //function will return non-zero if abort called over USB
		if (scans > 0){ //non-cyclic mode skips out after one direction
			EXP_TC0_1.CNT = 0;
			EXP_TC0_0.CNT = 0;
Michael DM Dryden's avatar
 
Michael DM Dryden committed
			if (_swv_singledir(stop, start, pulse_height, step, !direction)) //swap start and stop and invert direction for second half of scan
		printf("S\n"); //signal end of scan
		
	} while (scans-- > 1); //will underflow after comparison for scans = 0 , but shouldn't matter 
	
	printf("D\n"); //signal end of experiment
		tc_write_clock_source(&EXP_TC0_1, TC_CLKSEL_OFF_gc);
		tc_disable(&EXP_TC0_1);
		EXP_TC0_1.CNT = 0;
		tc_write_clock_source(&EXP_TC0_0, TC_CLKSEL_OFF_gc);
		tc_disable(&EXP_TC0_0);
		EXP_TC0_0.CNT = 0;
		ads1255_standby();
	
		return;
}

uint8_t _swv_singledir (uint16_t dacindex, uint16_t dacindex_stop, uint16_t dacindex_pulse_height, uint16_t dacindex_step, uint8_t direction){
	/**
	 * Internal function that performs a single direction sweep for SWV
	 *
	 * @param dacindex Starting voltage as dac index
	 * @param dacindex_stop Stop voltage in dac index.
	 * @param dacindex_step Step voltage in dac index.
	 * @param dacindex_pulse_height Pulse amplitude in dac index.
	 * @param direction Scan direction - 1 for up, 0 for down.
	 */
	int32_t forward = 0;
	int32_t reverse = 0;
	uint16_t lastindex = 0;
	
	if (direction == 1)
		max5443_set_voltage1(dacindex+dacindex_pulse_height);
	else
		max5443_set_voltage1(dacindex-dacindex_pulse_height);
	
	while ((dacindex <= dacindex_stop && direction == 1) || (dacindex >= dacindex_stop && direction == 0)){
		tc_clear_overflow(&EXP_TC0_1);
		tc_clear_overflow(&EXP_TC0_0);
		while (!tc_is_overflow(&EXP_TC0_0)){ //ADC tc overflow
			if (udi_cdc_is_rx_ready()){ //check for abort signal over USB
		
		ads1255_wakeup();
		while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTD, 5)));
		forward = ads1255_read_single24();
		ads1255_standby();
		
		while (!tc_is_overflow(&EXP_TC0_1)); //wait for end of half-cycle
		EXP_TC0_0.CNT = 0;
		if (direction == 1) //switch voltage to other half of cycle
			max5443_set_voltage1(dacindex-dacindex_pulse_height);
			max5443_set_voltage1(dacindex+dacindex_pulse_height);
		tc_clear_overflow(&EXP_TC0_1); //reset timer OVF
		tc_clear_overflow(&EXP_TC0_0);
		while (!tc_is_overflow(&EXP_TC0_0)){ //ADC tc overflow
			if (udi_cdc_is_rx_ready()){ //check for abort signal over USB
		
		ads1255_wakeup();
		while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTD, 5)));
		reverse = ads1255_read_single24();
		ads1255_standby();
		
		while (!tc_is_overflow(&EXP_TC0_1)); //wait for end of half-cycle
		EXP_TC0_0.CNT = 0;
			
		lastindex = dacindex;
			
		//increment dacindex
		if (direction == 1){
			dacindex += dacindex_step;
			max5443_set_voltage1(dacindex+dacindex_pulse_height);
		else{
			dacindex -= dacindex_step;
			max5443_set_voltage1(dacindex-dacindex_pulse_height);
		}
			
		//data output
		struct
		{
			uint16_t lastindex;
			int32_t forward;
			int32_t	reverse;
		} data;
		
		data.lastindex = lastindex;
		data.forward = forward;
		data.reverse = reverse;
		
Michael DM Dryden's avatar
 
Michael DM Dryden committed
void dpv_experiment(uint16_t start, uint16_t stop, uint16_t step, uint16_t pulse_height, uint16_t pulse_period, uint16_t pulse_width){
Michael DM Dryden's avatar
 
Michael DM Dryden committed
	 * @param start Start voltage in dac units.
	 * @param stop Stop voltage in dac units.
	 * @param step Step voltage in dac units.
	 * @param pulse_height Pulse amplitude in dac units.
	 * @param pulse_period Pulse period in ms.
	 * @param pulse_width Pulse width in ms.
	 */

	uint8_t direction;
Michael DM Dryden's avatar
 
Michael DM Dryden committed
//	uint16_t dacindex_start = ceil((start)*(65536/(double)3000))+32768;
//	uint16_t dacindex_stop = ceil(stop*(65536/(double)3000))+32768;
//	uint16_t dacindex_step = ceil(step*(65536/(double)3000));
//	uint16_t dacindex_pulse_height = ceil(pulse_height*(65536/(double)3000));
	uint32_t cpu_period;
	uint32_t cpu_width;
	
	if (start < stop)
		direction = 1;
	else
		direction = 0;
	
	tc_enable(&EXP_TC0_1);
	tc_enable(&EXP_TC0_0);
	
	//calculate time to ADC trigger
	cpu_period = ceil((double)pulse_period*1e-3*F_CPU);
	uint32_t adc_period = ceil((((double)pulse_period*1e-3)-(double)(sample_delay_ms_100div/1e5))*F_CPU);
	uint16_t divider = set_timer_period(cpu_period, &EXP_TC0_1);
	uint16_t adc_divider = set_timer_period(adc_period, &EXP_TC0_0);
	uint32_t adc_width = ceil((((double)pulse_width*1e-3)-(double)(sample_delay_ms_100div/1e5))*F_CPU);
	tc_write_cc(&EXP_TC0_1, TC_CCA, (uint16_t)(cpu_width/divider));
	tc_enable_cc_channels(&EXP_TC0_1, TC_CCAEN);
	tc_write_cc(&EXP_TC0_0, TC_CCA, (uint16_t)(adc_width/adc_divider));
	tc_enable_cc_channels(&EXP_TC0_0, TC_CCAEN);
	volt_exp_start();
	EXP_TC0_1.CNT = 0;
	EXP_TC0_0.CNT = 0;
Michael DM Dryden's avatar
 
Michael DM Dryden committed
	if (_dpv_singledir(start, stop, pulse_height, step, direction))
		goto aborting; //function will return non-zero if abort called over USB
	
	printf("D\n"); //signal end of experiment
		tc_write_clock_source(&EXP_TC0_1, TC_CLKSEL_OFF_gc);
		tc_disable(&EXP_TC0_1);
		tc_write_clock_source(&EXP_TC0_0, TC_CLKSEL_OFF_gc);
		tc_disable(&EXP_TC0_0);
		EXP_TC0_1.CNT = 0;
		EXP_TC0_0.CNT = 0;
		ads1255_standby();
	
		return;
}

uint8_t _dpv_singledir (uint16_t dacindex, uint16_t dacindex_stop, uint16_t dacindex_pulse_height, uint16_t dacindex_step, uint8_t direction){
	/**
	 * Internal function that performs a single direction sweep for DPV
	 *
	 * @param dacindex Starting voltage as dac index
	 * @param dacindex_stop Stop voltage in dac index.
	 * @param dacindex_step Step voltage in dac index.
	 * @param dacindex_pulse_height Pulse amplitude in dac index.
	 * @param direction Scan direction - 1 for up, 0 for down.
	 */
	int32_t forward = 0;
	int32_t reverse = 0;
	uint16_t lastindex = 0;
	
	if (direction == 1)
		max5443_set_voltage1(dacindex+dacindex_pulse_height);
	else
		max5443_set_voltage1(dacindex-dacindex_pulse_height);
	
	while ((dacindex <= dacindex_stop && direction == 1) || (dacindex >= dacindex_stop && direction == 0)){
		tc_clear_overflow(&EXP_TC0_1);
		tc_clear_cc_interrupt(&EXP_TC0_1, TC_CCA);
		tc_clear_overflow(&EXP_TC0_0);
		tc_clear_cc_interrupt(&EXP_TC0_0, TC_CCA);
		while (!tc_is_cc_interrupt(&EXP_TC0_0, TC_CCA)){ //wait until ADC TC CCA match
			if (udi_cdc_is_rx_ready()){ //check for abort signal over USB
				if (getchar() == 'a')
					return 1;
			}
		}
		
		ads1255_wakeup();
		while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTD, 5)));
		forward = ads1255_read_single24();
		ads1255_standby();
		
		while (!tc_is_cc_interrupt(&EXP_TC0_1, TC_CCA)); //wait for end of half-cycle
		//switch voltage to baseline
		max5443_set_voltage1(dacindex);
				
		while (!tc_is_overflow(&EXP_TC0_0)){ //wait for ADC TC overflow
			if (udi_cdc_is_rx_ready()){
				if (getchar() == 'a')
					return 1;
			}
		}
		
		ads1255_wakeup();
		while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTD, 5)));
		reverse = ads1255_read_single24();
		ads1255_standby();
		
		while (!tc_is_overflow(&EXP_TC0_1)); //wait for end of half-cycle
		EXP_TC0_0.CNT = 0; // Resync ADC TC
		lastindex = dacindex;
			
		//increment dacindex
		if (direction == 1){
			dacindex += dacindex_step;
			max5443_set_voltage1(dacindex+dacindex_pulse_height);
		}
		
		else{
			dacindex -= dacindex_step;
			max5443_set_voltage1(dacindex-dacindex_pulse_height);
		}
			
		//data output
		struct
		{
			uint16_t lastindex;
			int32_t forward;
			int32_t	reverse;
		} data;
		
		data.lastindex = lastindex;
		data.forward = forward;
		data.reverse = reverse;
		
ISR(PORTD_INT0_vect){
	if (portd_int0_callback) {
		portd_int0_callback();
	}