diff --git a/DSTAT-temp/src/ads1255.c b/DSTAT-temp/src/ads1255.c index aea4c44e881cb89f261e451ef5e0c4fa34be451a..3c92ba9575914de99e5dd029af3e26e198884aa6 100644 --- a/DSTAT-temp/src/ads1255.c +++ b/DSTAT-temp/src/ads1255.c @@ -9,6 +9,7 @@ #include <ads1255.h> uint8_t buffer_iter = 0; +uint16_t sample_delay_ms_100div = 0; struct usart_spi_device spi_device_conf = { .id = IOPORT_CREATE_PIN(PORTE, 4) @@ -82,6 +83,64 @@ void ads1255_setup(uint8_t buff, uint8_t rate, uint8_t pga){ #if BOARD_VER_MAJOR == 1 && BOARD_VER_MINOR == 2 uint8_t command_buffer[6] = {0x50,0x03,buff,0x08,pga,rate}; // write reg 0, write 4 registers, analog buffer, MUX AIN0-AINCOM, pga, rate #endif + + //Stores propagation delay of current ADC sample rate in sample_delay_ms_100div in .01 ms + + switch (rate) + { + case ADS_DR_2_5: + sample_delay_ms_100div = 40022; + break; + case ADS_DR_5: + sample_delay_ms_100div = 20022; + break; + case ADS_DR_10: + sample_delay_ms_100div = 10022; + break; + case ADS_DR_15: + sample_delay_ms_100div = 6688; + break; + case ADS_DR_25: + sample_delay_ms_100div = 4022; + break; + case ADS_DR_30: + sample_delay_ms_100div = 3355; + break; + case ADS_DR_50: + sample_delay_ms_100div = 2022; + break; + case ADS_DR_60: + sample_delay_ms_100div = 1688; + break; + case ADS_DR_100: + sample_delay_ms_100div = 1022; + break; + case ADS_DR_500: + sample_delay_ms_100div = 222; + break; + case ADS_DR_1000: + sample_delay_ms_100div = 122; + break; + case ADS_DR_2000: + sample_delay_ms_100div = 72; + break; + case ADS_DR_3750: + sample_delay_ms_100div = 48; + break; + case ADS_DR_7500: + sample_delay_ms_100div = 35; + break; + case ADS_DR_15000: + sample_delay_ms_100div = 29; + break; + case ADS_DR_30000: + sample_delay_ms_100div = 25; + break; + default: + printf("#ERR: Invalid ADC data rate specified.\n\r"); + break; + } + usart_spi_select_device(&USARTE1, &spi_device_conf); usart_spi_transmit(&USARTE1, ADS_SDATAC); @@ -226,6 +285,45 @@ int32_t ads1255_read_fast24(void){ usart_clear_tx_complete(&USARTE1); usart_spi_deselect_device(&USARTE1, &spi_device_conf); + if (input_buffer.uint[2] > 0x7F) + input_buffer.uint[3] = 0xFF; + else + input_buffer.uint[3] = 0x0; + + cpu_irq_restore(flags); + return input_buffer.int32; +} + +int32_t ads1255_read_single24(void){ + + union{ + uint8_t uint[4]; + int32_t int32; + } input_buffer; + + input_buffer.int32 = 0; + + irqflags_t flags; + flags = cpu_irq_save(); + + usart_spi_select_device(&USARTE1, &spi_device_conf); + usart_spi_transmit(&USARTE1, ADS_RDATA); + delay_us(6.5); + + for (int i = 2; i >= 0; --i){ + while (usart_data_register_is_empty(&USARTE1) == false) + ; + usart_put(&USARTE1, CONFIG_USART_SPI_DUMMY); + while (usart_rx_is_complete(&USARTE1) == false) + ; + input_buffer.uint[i] = usart_get(&USARTE1); + } + + while (!usart_tx_is_complete(&USARTE1)) + ; + usart_clear_tx_complete(&USARTE1); + usart_spi_deselect_device(&USARTE1, &spi_device_conf); + if (input_buffer.uint[2] > 0x7F) input_buffer.uint[3] = 0xFF; else diff --git a/DSTAT-temp/src/ads1255.h b/DSTAT-temp/src/ads1255.h index f01d2d59895fd6a926af2332ffccf87d10a40f56..3b4cbe088b37f906a953e3e09af12ea496bf8ed8 100644 --- a/DSTAT-temp/src/ads1255.h +++ b/DSTAT-temp/src/ads1255.h @@ -62,12 +62,15 @@ #define ADS_MUX_VOLT 0x08 #define ADS_MUX_POT 0x18 +extern uint16_t sample_delay_ms_100div; + void ads1255_sync(void); void ads1255_init_pins(void); void ads1255_init_module(void); int16_t ads1255_read_fast(void); int16_t ads1255_read_fast_single(void); int32_t ads1255_read_fast24(void); +int32_t ads1255_read_single24(void); void ads1255_reg_read(uint8_t address); void ads1255_reset(void); void ads1255_setup(uint8_t buff, uint8_t rate, uint8_t pga); diff --git a/DSTAT-temp/src/config/conf_usart_spi.h b/DSTAT-temp/src/config/conf_usart_spi.h index b5360e4bebd36bb7f96271ee6d93506f7db1ffdd..a7593371de5af5d20c914ebdef32c19cb044591f 100644 --- a/DSTAT-temp/src/config/conf_usart_spi.h +++ b/DSTAT-temp/src/config/conf_usart_spi.h @@ -43,5 +43,6 @@ #ifndef CONF_USART_SPI_H_INCLUDED #define CONF_USART_SPI_H_INCLUDED +#define CONFIG_USART_SPI_DUMMY 0xFE #endif /* CONF_USART_SPI_H_INCLUDED */ diff --git a/DSTAT-temp/src/experiment.c b/DSTAT-temp/src/experiment.c index 12648828539378ae0c2a6222bd8d940f9a8c1448..87344442801786deecc5afadfcfb587a9740595f 100644 --- a/DSTAT-temp/src/experiment.c +++ b/DSTAT-temp/src/experiment.c @@ -75,6 +75,54 @@ void send_data_int32(int32_t data){ udi_cdc_putc(((unsigned char *)(&data))[3]); } +uint16_t set_timer_period(uint32_t period, volatile void *tc) +{ + /** + * Sets a suitable timer source and sets period for a 16-bit timer + * + * @param period 32-bit period in CPU cycles + * @param *tc pointer to timer to set + * @return divider used. + */ + uint16_t temp_div = ceil((double)period/65536); + uint16_t divider = 0; + + if (temp_div == 1) + tc_write_clock_source(tc, TC_CLKSEL_DIV1_gc); + else if (temp_div == 2){ + tc_write_clock_source(tc, TC_CLKSEL_DIV2_gc); + divider = 2; + } + else if (temp_div <= 4){ + tc_write_clock_source(tc, TC_CLKSEL_DIV4_gc); + divider = 4; + } + else if (temp_div <= 8){ + tc_write_clock_source(tc,TC_CLKSEL_DIV8_gc); + divider = 8; + } + else if (temp_div <= 64){ + tc_write_clock_source(tc,TC_CLKSEL_DIV64_gc); + divider = 64; + } + else if (temp_div <= 256){ + tc_write_clock_source(tc,TC_CLKSEL_DIV256_gc); + divider = 256; + } + else if (temp_div <= 1024){ + tc_write_clock_source(tc,TC_CLKSEL_DIV1024_gc); + divider = 1024; + } + else{ + printf("#Frequency/ADC rate is too low\n\r"); + return 0; + } + + period /= divider; + tc_write_period(tc, (uint16_t)period); + return divider; +} + void pot_init(void){ /** * Initializes AVR port directions and levels @@ -753,7 +801,6 @@ void swv_experiment(int16_t start, int16_t stop, uint16_t step, uint16_t pulse_h 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)); - uint16_t dacindex = dacindex_start; uint32_t period; if (start < stop) @@ -762,68 +809,31 @@ void swv_experiment(int16_t start, int16_t stop, uint16_t step, uint16_t pulse_h direction = 0; tc_enable(&TCF0); + tc_enable(&TCC0); frequency *= 2; //compensate for half-period triggers //calculate time to ADC trigger period = ceil((1/(double)frequency)*F_CPU); - uint16_t temp_div = ceil((double)period/65536); - - if (temp_div == 1) - tc_write_clock_source(&TCF0,TC_CLKSEL_DIV1_gc); - else if (temp_div == 2){ - tc_write_clock_source(&TCF0,TC_CLKSEL_DIV2_gc); - period /= 2; - } - else if (temp_div <= 4){ - tc_write_clock_source(&TCF0,TC_CLKSEL_DIV4_gc); - period /= 4; - } - else if (temp_div <= 8){ - tc_write_clock_source(&TCF0,TC_CLKSEL_DIV8_gc); - period /= 8; - } - else if (temp_div <= 64){ - tc_write_clock_source(&TCF0,TC_CLKSEL_DIV64_gc); - period /= 64; - } - else if (temp_div <= 256){ - tc_write_clock_source(&TCF0,TC_CLKSEL_DIV256_gc); - period /= 256; - } - else if (temp_div <= 1024){ - tc_write_clock_source(&TCF0,TC_CLKSEL_DIV1024_gc); - period /= 1024; - } - else{ - printf("#Frequency/ADC rate is too low\n\r"); - return; - } - - tc_write_period(&TCF0, (uint16_t)period); - - if (direction == 1) - max5443_set_voltage1(dacindex+dacindex_pulse_height); - else - max5443_set_voltage1(dacindex-dacindex_pulse_height); + uint32_t adc_period = ceil(((1/(double)frequency)-(double)(sample_delay_ms_100div/1e5))*F_CPU); + set_timer_period(period, &TCF0); + set_timer_period(adc_period, &TCC0); ads1255_wakeup(); - ads1255_rdatac(); - ads1255_sync(); + ads1255_standby(); volt_exp_start(); do{ TCF0.CNT = 0; - while (!tc_is_overflow(&TCF0)); - ads1255_wakeup(); //synchronize ADC - TCF0.CNT = 0; + TCC0.CNT = 0; if (_swv_singledir(dacindex_start, dacindex_stop, dacindex_pulse_height, dacindex_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 TCF0.CNT = 0; + TCC0.CNT = 0; if (_swv_singledir(dacindex_stop, dacindex_start, dacindex_pulse_height, dacindex_step, !direction)) //swap start and stop and invert direction for second half of scan goto aborting; } @@ -839,6 +849,9 @@ void swv_experiment(int16_t start, int16_t stop, uint16_t step, uint16_t pulse_h tc_write_clock_source(&TCF0, TC_CLKSEL_OFF_gc); tc_disable(&TCF0); TCF0.CNT = 0; + tc_write_clock_source(&TCC0, TC_CLKSEL_OFF_gc); + tc_disable(&TCC0); + TCC0.CNT = 0; ads1255_standby(); return; @@ -865,34 +878,45 @@ uint8_t _swv_singledir (uint16_t dacindex, uint16_t dacindex_stop, uint16_t daci while ((dacindex <= dacindex_stop && direction == 1) || (dacindex >= dacindex_stop && direction == 0)){ tc_clear_overflow(&TCF0); + tc_clear_overflow(&TCC0); - while (!tc_is_overflow(&TCF0)){ //convert continuously until tc overflow - datum is last collected point - while (ioport_pin_is_low(IOPORT_CREATE_PIN(PORTD, 5))); //wait for next valid datum - while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTD, 5))); - forward = ads1255_read_fast24(); + while (!tc_is_overflow(&TCC0)){ //ADC tc overflow 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_overflow(&TCF0)); //wait for end of half-cycle + TCC0.CNT = 0; + if (direction == 1) //switch voltage to other half of cycle max5443_set_voltage1(dacindex-dacindex_pulse_height); else max5443_set_voltage1(dacindex+dacindex_pulse_height); tc_clear_overflow(&TCF0); //reset timer OVF + tc_clear_overflow(&TCC0); - while (!tc_is_overflow(&TCF0)){ //wait for tc overflow - while (ioport_pin_is_low(IOPORT_CREATE_PIN(PORTD, 5))); //wait for next valid datum - while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTD, 5))); - reverse = ads1255_read_fast24(); - - if (udi_cdc_is_rx_ready()){ + while (!tc_is_overflow(&TCC0)){ //ADC tc overflow + if (udi_cdc_is_rx_ready()){ //check for abort signal over USB if (getchar() == 'a') - return 1; + return 1; } } + + ads1255_wakeup(); + while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTD, 5))); + reverse = ads1255_read_single24(); + ads1255_standby(); + + while (!tc_is_overflow(&TCF0)); //wait for end of half-cycle + TCC0.CNT = 0; lastindex = dacindex; @@ -935,7 +959,6 @@ void dpv_experiment(int16_t start, int16_t stop, uint16_t step, uint16_t pulse_h 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)); - uint16_t dacindex = dacindex_start; uint32_t cpu_period; uint32_t cpu_width; @@ -945,59 +968,28 @@ void dpv_experiment(int16_t start, int16_t stop, uint16_t step, uint16_t pulse_h direction = 0; tc_enable(&TCF0); + tc_enable(&TCC0); //calculate time to ADC trigger cpu_period = ceil((double)pulse_period*1e-3*F_CPU); - uint16_t temp_div = ceil((double)cpu_period/65536); + 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, &TCF0); + uint16_t adc_divider = set_timer_period(adc_period, &TCC0); - if (temp_div == 1) - tc_write_clock_source(&TCF0,TC_CLKSEL_DIV1_gc); - else if (temp_div == 2) - tc_write_clock_source(&TCF0,TC_CLKSEL_DIV2_gc); - else if (temp_div <= 4){ - tc_write_clock_source(&TCF0,TC_CLKSEL_DIV4_gc); - temp_div = 4; - } - else if (temp_div <= 8){ - tc_write_clock_source(&TCF0,TC_CLKSEL_DIV8_gc); - temp_div = 8; - } - else if (temp_div <= 64){ - tc_write_clock_source(&TCF0,TC_CLKSEL_DIV64_gc); - temp_div = 64; - } - else if (temp_div <= 256){ - tc_write_clock_source(&TCF0,TC_CLKSEL_DIV256_gc); - temp_div = 256; - } - else if (temp_div <= 1024){ - tc_write_clock_source(&TCF0,TC_CLKSEL_DIV1024_gc); - temp_div = 1024; - } - else{ - printf("#Frequency/ADC rate is too low\n\r"); - return; - } - - tc_write_period(&TCF0, (uint16_t)(cpu_period/temp_div)); cpu_width = (double)pulse_width*1e-3*F_CPU; - tc_write_cc(&TCF0, TC_CCA, (uint16_t)(cpu_width/temp_div)); + uint32_t adc_width = ceil((((double)pulse_width*1e-3)-(double)(sample_delay_ms_100div/1e5))*F_CPU); + tc_write_cc(&TCF0, TC_CCA, (uint16_t)(cpu_width/divider)); tc_enable_cc_channels(&TCF0, TC_CCAEN); - - if (direction == 1) - max5443_set_voltage1(dacindex+dacindex_pulse_height); - else - max5443_set_voltage1(dacindex-dacindex_pulse_height); + tc_write_cc(&TCC0, TC_CCA, (uint16_t)(adc_width/adc_divider)); + tc_enable_cc_channels(&TCC0, TC_CCAEN); ads1255_wakeup(); - ads1255_rdatac(); - ads1255_sync(); + ads1255_standby(); + volt_exp_start(); TCF0.CNT = 0; - while (!tc_is_overflow(&TCF0)); - ads1255_wakeup(); //synchronize ADC - TCF0.CNT = 0; + TCC0.CNT = 0; if (_dpv_singledir(dacindex_start, dacindex_stop, dacindex_pulse_height, dacindex_step, direction)) goto aborting; //function will return non-zero if abort called over USB @@ -1008,7 +1000,10 @@ void dpv_experiment(int16_t start, int16_t stop, uint16_t step, uint16_t pulse_h volt_exp_stop(); tc_write_clock_source(&TCF0, TC_CLKSEL_OFF_gc); tc_disable(&TCF0); + tc_write_clock_source(&TCC0, TC_CLKSEL_OFF_gc); + tc_disable(&TCC0); TCF0.CNT = 0; + TCC0.CNT = 0; ads1255_standby(); return; @@ -1036,31 +1031,41 @@ uint8_t _dpv_singledir (uint16_t dacindex, uint16_t dacindex_stop, uint16_t daci while ((dacindex <= dacindex_stop && direction == 1) || (dacindex >= dacindex_stop && direction == 0)){ tc_clear_overflow(&TCF0); tc_clear_cc_interrupt(&TCF0, TC_CCA); + tc_clear_overflow(&TCC0); + tc_clear_cc_interrupt(&TCC0, TC_CCA); - while (!tc_is_cc_interrupt(&TCF0, TC_CCA)){ //convert continuously until tc CCA match - datum is last collected point - while (ioport_pin_is_low(IOPORT_CREATE_PIN(PORTD, 5))); //wait for next valid datum - while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTD, 5))); - forward = ads1255_read_fast24(); + while (!tc_is_cc_interrupt(&TCC0, 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(&TCF0, TC_CCA)); //wait for end of half-cycle + //switch voltage to baseline max5443_set_voltage1(dacindex); - while (!tc_is_overflow(&TCF0)){ //wait for tc overflow - while (ioport_pin_is_low(IOPORT_CREATE_PIN(PORTD, 5))); //wait for next valid datum - while (ioport_pin_is_high(IOPORT_CREATE_PIN(PORTD, 5))); - reverse = ads1255_read_fast24(); - + while (!tc_is_overflow(&TCC0)){ //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(&TCF0)); //wait for end of half-cycle + TCC0.CNT = 0; // Resync ADC TC + lastindex = dacindex; //increment dacindex diff --git a/DSTAT-temp/src/experiment.h b/DSTAT-temp/src/experiment.h index 4d270407b4b530f8dda9ddbdbed926e7ff89602e..8b1ab536fe44ad9f463583f0c3f33f49d8889cf9 100644 --- a/DSTAT-temp/src/experiment.h +++ b/DSTAT-temp/src/experiment.h @@ -77,6 +77,7 @@ extern uint8_t autogain_enable; void send_data_uint16(uint16_t data); void send_data_int32(int32_t data); +uint16_t set_timer_period(uint32_t period, volatile void *tc); void pot_init(void); void pot_set_gain(void); void volt_exp_start(void); diff --git a/DSTAT1.atsuo b/DSTAT1.atsuo index 27e605a947380e8b305f257e7b61f155ff94837d..c409dd7e0b88439dfd9d1cdd2b17f4b8fcedb73f 100644 Binary files a/DSTAT1.atsuo and b/DSTAT1.atsuo differ