#include "usbscope.h" #define SCOPE50_HWRAMSIZE 3072 /* 0xC00 */ #define SCOPE50_SWRAMSIZE 3000 #define SCOPE50_POINTER_READ 0 #define SCOPE50_POINTER_WRITE 1 #undef DEBUG struct channel_info { unsigned char upper; /* upper nibble of reg 0x0 */ float raw_offset; float o2dac_scale; int trig_offset; /*int ris_min; int ris_max;*/ } cinfo[MAXFD]; unsigned pretrigger; unsigned startwdp; int use_ris; float corr_gain = 1.06; /* independent of channel */ int baseclk; /* 10, 12(.5), 25, or 50 - in MHz */ unsigned char baseclk_ix; /* 3, 2, 1, 0 acc. to baseclk */ unsigned static char clamp(int val) { if(val < 0) return 0; else if(val > 255) return 255; else return val; } /* Doplnit RIS */ int scope50_acquisition_start(int fd) { if(use_ris) { unsigned char seq[] = { 0x20, cinfo[fd].upper | 0xC, 0x16, 0, 0x17, 0, 0x27, 0, 0x28, 0, 0x20, cinfo[fd].upper | 0x0, 0x20, cinfo[fd].upper | 0x1, /* Run*/ 0x20, cinfo[fd].upper | 0x3}; /* Arm */ return writeregmulti(fd, seq, countof(seq)); } else { unsigned char seq[] = { 0x20, cinfo[fd].upper | 0x8, 0x16, (unsigned char)(pretrigger & 0xFF), 0x17, (unsigned char)(pretrigger >> 8), 0x27, (unsigned char)(startwdp & 0xFF), 0x28, (unsigned char)(startwdp >> 8), 0x20, cinfo[fd].upper | 0xC, 0x20, cinfo[fd].upper | 0xF, 0x20, (cinfo[fd].upper | 0xF) & 0xDF, 0x20, cinfo[fd].upper | 0xF}; return writeregmulti(fd, seq, countof(seq)); } } int scope50_set_ris_mode(int fd, int state) { use_ris = state; return changereg(fd, 0x10, ~0x06, state?0x02:0); } int scope50_set_trig_master(int fd, int state) { if(state) cinfo[fd].upper |= 0x40; else cinfo[fd].upper &= ~0x40; return writereg(fd, 0x0, cinfo[fd].upper); } int scope50_get_ris_data(int fd, unsigned char *ret) { return readreg(fd, 0x11, ret); } int scope50_set_pretrig_depth(int samples) { //if(pct >= 0) pretrigger = (unsigned)(pct * SCOPE50_SWRAMSIZE); if(samples >= 0 && samples < SCOPE50_HWRAMSIZE-10) pretrigger = samples; else return 0; startwdp = SCOPE50_HWRAMSIZE - 10 - pretrigger; return 1; } int scope50_set_trigger_delay(int fd, unsigned val) { return writeregdouble(fd, 0x12, val); } int scope50_set_cal_source(int fd, int state) { return changereg(fd, 0xA, (unsigned char)~0x80, state?0x80:0); } /* Base ADC clock = 10, 12.5, 25, or 50 MHz * 10 MHz (only!) can be divided by the decimation ratios: * 1, 2, 4, 10, 20, 40, ..., 400000 * => min sample interval = 20 ns (50 MHz) * max sample interval = 40 ms (10 MHz : 4E5) */ int scope50_set_base_adc_clk(int fd, int clk) { baseclk = clk; switch(clk) { case 10: baseclk_ix = 3; break; case 12: baseclk_ix = 2; break; case 25: baseclk_ix = 1; break; default: baseclk_ix = 0; } //printf("clk %i -> %i\n", clk, baseclk_ix); return changereg(fd, 0xC, ~0x3, baseclk_ix); } int scope50_set_decimation_ratio(int fd, int dr) { unsigned char code = 0; while(dr >= 10) { dr /= 10; code += 4; } if(dr == 2) code += 1; else if(dr != 1) code += 2; //printf("dec %i -> %i\n", dr, code); return changereg(fd, 0xC, 0x3, code << 2); } /* Allowed values: 25, 50, 100, 250, ..., 1E7, 1.25E7, 2.5E7, 5E7 */ int scope50_set_sample_frequency(int fd, int freq, int *real) { int clk, dec, pow10; if(freq < 25) freq = 25; if(freq > 5E7) freq = 5E7; if(freq > 1E7) { dec = 1; freq /= 1E6; if(freq < 11) clk = 10; else if(freq < 20) clk = 12; else if(freq < 40) clk = 25; else clk = 50; } else { clk = 10; dec = 1E7 / freq; } for(pow10 = 1; dec >= 10; ) { pow10 *= 10; dec /= 10; } if(dec > 2) dec = 4; dec *= pow10; if(real) *real = clk * 1E6 / dec; if(!scope50_set_base_adc_clk(fd, clk)) return 0; if(!scope50_set_decimation_ratio(fd, dec)) return 0; return 1; } /* code parameter is optional */ int scope50_set_offset(int fd, float pct, unsigned char *code) { unsigned char tmp; tmp = clamp(cinfo[fd].raw_offset + 0x80*(pct/100)*cinfo[fd].o2dac_scale); if(code) *code = tmp; if(!writereg(fd, 0x3, 1)) return 0; if(!writereg(fd, 0x4, tmp)) return 0; return delaycycle(fd, 6); } int scope50_set_trig_thresh(int fd, float pct) { unsigned char tmp; tmp = clamp(cinfo[fd].trig_offset + 73*(pct/100)); if(!writereg(fd, 0x3, 2)) return 0; return writereg(fd, 0x4, tmp); } int scope50_set_run(int fd, int state) { return changereg(fd, 0x0, ~0x1, state?0x1:0); } int scope50_set_arm(int fd, int state) { return changereg(fd, 0x0, ~0x2, state?0x2:0); } int scope50_set_adc_clk(int fd, int state) { return changereg(fd, 0x0, ~0x4, state?0x4:0); } int scope50_set_ctr_clk(int fd, int state) { return changereg(fd, 0x0, ~0x8, state?0x8:0); } int scope50_get_acquisition_state(int fd, int *state) { unsigned char res; if(!readreg(fd, 0x0, &res)) return 0; *state = res & 0x1; return 1; } int scope50_acquisition_end(int fd) { return writereg(fd, 0x0, cinfo[fd].upper & 0xF0); } int scope50_set_trig_type(int fd, int type) { return changereg(fd, 0x1, ~0x3, type); } int scope50_set_norm_trig(int fd, int state) { if(state) { if(!changereg(fd, 0x0, ~0x30, 0x30)) return 0; cinfo[fd].upper |= 0x30; scope50_set_pretrig_depth(-1); /* Use current value */ } else { if(!changereg(fd, 0x0, ~0x30, 0x20)) return 0; cinfo[fd].upper &= ~0x30; cinfo[fd].upper |= 0x20; if(!scope50_set_trigger_delay(fd, 0)) return 0; scope50_set_pretrig_depth(0); /* No pre-trig */ } return 1; } int scope50_setup_front_end(int fd, int range, int coupl, int ris) { unsigned char reg; if(!readreg(fd, 0x2, ®)) return 0; if(ris) reg |= 0x20; else { reg &= 0x80; switch(coupl) { case SCOPE50_COUPLING_AC: reg |= 0x10; break; case SCOPE50_COUPLING_DC: reg |= 0x18; break; case SCOPE50_COUPLING_GND: reg &= 0xE0; range = SCOPE50_RANGE_300V; } reg |= 1 << range; } if(!writereg(fd, 0x2, reg & 0xF8)) return 0; /* Without amps */ if(!delaycycle(fd, 5)) return 0; if(!writereg(fd, 0x2, reg)) return 0; if(!delaycycle(fd, 5)) return 0; return 1; } int scope50_set_ptr(int fd, int ptr, unsigned val) { return writeregdouble(fd, ptr?0x7:0x5, val); } int scope50_get_ptr(int fd, int ptr, unsigned *ret) { int i; unsigned char a, b, c; for(i = 0; i < 100; i++) { if(!readreg(fd, ptr?0x8:0x6, &a)) return 0; if(!readreg(fd, ptr?0x7:0x5, &b)) return 0; if(!readreg(fd, ptr?0x8:0x6, &c)) return 0; if(a == c) break; /* The pointer is changing */ } if(i == 100) *ret = 0; else *ret = ((((int)c)<<8)+b) & 0x7FFF; return 1; } int scope50_get_halt_ptr(int fd, unsigned *ret) { return readregdouble(fd, 0x14, ret); } int scope50_get_trig_ptr(int fd, unsigned *ret) { int r = readregdouble(fd, 0x18, ret); *ret &= 0x7FFF; return r; } int scope50_get_triggered_status(int fd, int *ret) { unsigned char res; if(!readreg(fd, 0x9, &res)) return 0; *ret = (res & 2) ? 1 : 0; return 1; } int scope50_get_samples_since_trigger(int fd, unsigned *ret) { unsigned a, b; int res; *ret = 0; if(!scope50_get_triggered_status(fd, &res)) return 0; if(res) return 1; if(!scope50_get_ptr(fd, SCOPE50_POINTER_WRITE, &a)) return 0; if(!scope50_get_trig_ptr(fd, &b)) return 0; if(a < startwdp && a > 10) return 1; *ret = (int)a - b; if(*ret < 0) *ret += SCOPE50_HWRAMSIZE; if(*ret) (*ret)--; return 1; } int scope50_get_buffer_blocks(int fd, float *data, int nblocks) { unsigned wdp; int i; unsigned char fld[512]; if(!writereg(fd, 0xF, 0)) return 0; /* Read 512 B */ if(!scope50_get_halt_ptr(fd, &wdp)) return 0; if(!scope50_set_ptr(fd, SCOPE50_POINTER_READ, (wdp+1)%SCOPE50_HWRAMSIZE)) return 0; while(nblocks--) { if(!readregmulti(fd, 0xB, 512, fld)) return 0; for(i = 0; i < 512; i++) { *data = ((int)fld[i] - 0x80) * corr_gain; data++; } } return 1; } int scope50_get_buffer_blocks_raw(int fd, unsigned char *data, int nblocks) { unsigned wdp; int i; if(!writereg(fd, 0xF, 0)) return 0; /* Read 512 B */ if(!scope50_get_halt_ptr(fd, &wdp)) return 0; if(!scope50_set_ptr(fd, SCOPE50_POINTER_READ, (wdp+1)%SCOPE50_HWRAMSIZE)) return 0; for(i = 0; i < nblocks; i++) if(!readregmulti(fd, 0xB, 512, data + i*512)) return 0; return 1; } /* buffer blocks multi, incr, RIS */ int scope50_calibrate_offset(int fd) { unsigned char o1, o2; float a1, a2; unsigned char buf[100]; int i; unsigned char seq[] = { 0x20, cinfo[fd].upper | 0x8, 0x2F, 50, 0x25, 0, 0x26, 0, 0x27, 0, 0x28, 0, 0x20, cinfo[fd].upper | 0xC, 0x20, cinfo[fd].upper | 0xD, 0x20, cinfo[fd].upper | 0xD, 0x20, cinfo[fd].upper | 0x0}; if(!scope50_setup_front_end(fd, 0, SCOPE50_COUPLING_GND, 0)) return 0; if(!scope50_set_norm_trig(fd, 0)) return 0; if(!scope50_set_base_adc_clk(fd, 50)) return 0; cinfo[fd].raw_offset = 0x80; /* Assumption */ cinfo[fd].o2dac_scale = 0.5; if(!scope50_set_offset(fd, 50, &o1)) return 0; if(!delaycycle(fd, 50)) return 0; if(!writeregmulti(fd, seq, countof(seq))) return 0; if(!readregmulti(fd, 0xB, 100, buf)) return 0; for(i = 0, a1 = 0; i < 100; i++) a1 += buf[i] - 0x80; a1 /= 100.0; #ifdef DEBUG printf("o1 = %i\na1 = %f\n", o1, a1); #endif if(!scope50_set_offset(fd, -50, &o2)) return 0; if(!delaycycle(fd, 50)) return 0; if(!writeregmulti(fd, seq, countof(seq))) return 0; if(!readregmulti(fd, 0xB, 100, buf)) return 0; for(i = 0, a2 = 0; i < 100; i++) a2 += buf[i] - 0x80; a2 /= 100.0; #ifdef DEBUG printf("o2 = %i\na2 = %f\n", o2, a2); #endif /*Original algorithm: cinfo[fd].o2dac_scale = (o1-o2) / (a1-a2); cinfo[fd].raw_offset = o2 - a2*cinfo[fd].o2dac_scale; cinfo[fd].o2dac_scale /= 1.09;*/ /* New algorithm: */ cinfo[fd].o2dac_scale = (o1-o2)/(a1-a2); cinfo[fd].raw_offset = (int)(1.1/2.-(o1*a2-o2*a1)/(a1-a2)); #ifdef DEBUG printf("%f\n%f\n", cinfo[fd].o2dac_scale, cinfo[fd].raw_offset); #endif return 1; } int scope50_calibrate_trig(int fd) { unsigned char code, res; if(!scope50_set_offset(fd, 0, NULL)) return 0; if(!scope50_setup_front_end(fd, 0, SCOPE50_COUPLING_GND, 0)) return 0; cinfo[fd].trig_offset = 0x80; for(code = 100; code <= 156; code++) { if(!writereg(fd, 0x3, 2)) return 0; if(!writereg(fd, 0x4, code)) return 0; if(!delaycycle(fd, 1)) return 0; if(!readreg(fd, 0x9, &res)) return 0; if(!(res & 0x4)) { cinfo[fd].trig_offset = code; break; } } return 1; } /*int scope50_calibrate_ris(int fd) { int data[SCOPE50_HWRAMSIZE]; int min, max; int i; unsigned char res; unsigned char seq[] = { 0x20, cinfo[fd].upper | 0xC, 0x27, 0, 0x28, 0, 0x20, cinfo[fd].upper | 0x0, 0x20, cinfo[fd].upper | 0x3, 0x30, 3, 0x80}; if(!scope50_set_ris_mode(fd, 1)) return 0; if(!scope50_set_trig_master(fd, 1)) return 0; for(i = 0; i < 100; i++) { if(!writeregmulti(fd, seq, countof(seq))) return 0; if(!readreg(fd, 0x11, &res)) return 0; data[i] = (int)res - 0x80; } max = -128; min = 127; for(i = 0; i < 100; i++) { if(data[i] < 127 && data[i] > max) max = data[i]; if(data[i] > -127 && data[i] < min) min = data[i]; } cinfo[fd].ris_min = 0.75*min; cinfo[fd].ris_max = 0.75*max; if(!writereg(fd, 0x10, 0)) return 0; if(!scope50_set_trig_master(fd, 0)) return 0; return 1; }*/ int scope50_init_scope(int fd, int master, float *raw, float *scale, int *trig) { cinfo[fd].upper = master?0x80:0; if(!writereg(fd, 0x0, cinfo[fd].upper)) return 0; if(!scope50_set_base_adc_clk(fd, 50)) return 0; if(!scope50_set_decimation_ratio(fd, 1)) return 0; /*cinfo[fd].ris_max = 127; cinfo[fd].ris_min = -128; if(!scope50_calibrate_ris(fd)) return 0;*/ if(raw == NULL || scale == NULL || trig == NULL || (*raw == 0 && *scale == 0 && *trig == 0)) { if(!scope50_calibrate_offset(fd)) return 0; if(!scope50_calibrate_trig(fd)) return 0; } else { cinfo[fd].raw_offset = *raw; cinfo[fd].o2dac_scale = *scale; cinfo[fd].trig_offset = *trig; } if(raw != NULL || scale != NULL || trig != NULL) { *raw = cinfo[fd].raw_offset; *scale = cinfo[fd].o2dac_scale; *trig = cinfo[fd].trig_offset; } if(!writereg(fd, 0x1, 0x20)) return 0; if(!writereg(fd, 0x1, 0x24)) return 0; if(!writereg(fd, 0x1, 0x04)) return 0; if(!writereg(fd, 0x1, 0x24)) return 0; if(!scope50_set_norm_trig(fd, 0)) return 0; if(!scope50_set_trig_type(fd, SCOPE50_TRIG_TYPE_EDGE_UP)) return 0; if(!usbtm_set_led_mode(fd, USBTM_LED_MODE_NORMAL)) return 0; if(!scope50_setup_front_end(fd, SCOPE50_RANGE_3V, SCOPE50_COUPLING_DC, 0)) return 0; if(!scope50_set_offset(fd, 0, NULL)) return 0; if(!scope50_set_trig_thresh(fd, 0)) return 0; use_ris = 0; return 1; }