Browse Source

wip: split up from tmp433 branch

Luke Dashjr 12 years ago
parent
commit
edbd112e84
8 changed files with 456 additions and 19 deletions
  1. 2 1
      Makefile.am
  2. 43 7
      driver-bitfury.c
  3. 109 10
      driver-metabank.c
  4. 2 0
      libbitfury.h
  5. 4 0
      spidevc.c
  6. 1 1
      tm_i2c.c
  7. 6 0
      tm_i2c.h
  8. 289 0
      tm_i2cm.c

+ 2 - 1
Makefile.am

@@ -264,7 +264,8 @@ bfgminer_SOURCES += driver-bfsb.c
 endif
 
 if HAS_METABANK
-bfgminer_SOURCES += driver-metabank.c tm_i2c.h tm_i2c.c
+bfgminer_SOURCES += driver-metabank.c tm_i2c.h tm_i2cm.c
+#bfgminer_SOURCES += driver-metabank.c tm_i2c.h tm_i2c.c
 endif
 
 if HAS_LITTLEFURY

+ 43 - 7
driver-bitfury.c

@@ -430,6 +430,8 @@ void bitfury_do_io(struct thr_info * const master_thr)
 		
 		inp = rxbuf[j];
 		
+		if (proc->deven == DEV_DISABLED) continue;
+		
 		if (unlikely(bitfury->desync_counter == 99))
 		{
 			bitfury_init_oldbuf(proc, inp);
@@ -449,9 +451,11 @@ void bitfury_do_io(struct thr_info * const master_thr)
 			inc_hw_errors2(thr, NULL, NULL);
 			if (unlikely(++bitfury->desync_counter >= 4))
 			{
-				applog(LOG_WARNING, "%"PRIpreprv": Previous nonce mismatch (4th try), recalibrating",
-				       proc->proc_repr);
+				if (bitfury->strange_counter > 50) proc->deven = DEV_DISABLED;
+				applog(LOG_WARNING, "%"PRIpreprv": Previous nonce mismatch (4th try), recalibrating %d",
+				       proc->proc_repr, bitfury->strange_counter);
 				bitfury_init_oldbuf(proc, inp);
+				bitfury->strange_counter++;
 				continue;
 			}
 			applog(LOG_DEBUG, "%"PRIpreprv": Previous nonce mismatch, ignoring response",
@@ -497,15 +501,15 @@ void bitfury_do_io(struct thr_info * const master_thr)
 				struct timeval d_time;
 				
 				timersub(&(tv_now), &(bitfury->timer1), &d_time);
-				period = timeval_to_us(&d_time) * 1000ULL;
-				ns = (double)period / (double)(cycles);
-				bitfury->mhz = 1.0 / ns * 65.0 * 1000.0;
+				period = timeval_to_us(&d_time);
+				ns = (double)(cycles) / (double)period * 65.0;
+				if (ns < 350) bitfury->mhz = ns;
 				
 				if (bitfury->mhz_best)
 				{
-					if (bitfury->mhz < bitfury->mhz_best / 2)
+					if (bitfury->mhz < bitfury->mhz_best / 3)
 					{
-						applog(LOG_INFO, "%"PRIpreprv": Frequency drop over 50%% detected, reinitialising",
+						applog(LOG_INFO, "%"PRIpreprv": Frequency drop over 33%% detected, reinitialising",
 						       proc->proc_repr);
 						bitfury->force_reinit = true;
 					}
@@ -527,8 +531,10 @@ void bitfury_do_io(struct thr_info * const master_thr)
 		
 		if (tvp_stat->tv_sec == 0 && tvp_stat->tv_usec == 0) {
 			copy_time(tvp_stat, &tv_now);
+			copy_time(&bitfury->tv_stat_long, &tv_now);
 		}
 		
+#ifndef USE_METABANK2
 		if (c->osc6_max)
 		{
 			if (timer_elapsed(tvp_stat, &tv_now) >= 60)
@@ -568,6 +574,7 @@ void bitfury_do_io(struct thr_info * const master_thr)
 				}
 			}
 		}
+#endif
 		
 		if (n)
 		{
@@ -610,6 +617,33 @@ void bitfury_do_io(struct thr_info * const master_thr)
 			bitfury->active = (bitfury->active + n) % 0x10;
 		}
 		
+#ifdef USE_METABANK2
+		if (timer_elapsed(tvp_stat, &tv_now) >= 10)
+		{
+			if (j == 0) {
+				struct bitfury_device *tbitfury;
+				int str_count = 0;
+				for (int k = 0; k < n_chips; ++k) {
+					tbitfury = procs[k]->device_data;
+					str_count += tbitfury->strange_counter;
+				}
+				applog(LOG_WARNING, "stranges=%d", str_count);
+			}
+			if (bitfury->strange_counter > 10 && bitfury->osc6_bits == c->osc6_min)
+				bitfury->osc6_bits -= 4;
+			if (bitfury->strange_counter > 3 && bitfury->osc6_bits > c->osc6_min)
+				bitfury_send_freq(bitfury->spi, bitfury->slot, bitfury->fasync, --bitfury->osc6_bits);
+			bitfury->strange_counter = 0;
+			copy_time(tvp_stat, &tv_now);
+		}
+		tvp_stat = &bitfury->tv_stat_long;
+		if (timer_elapsed(tvp_stat, &tv_now) >= 900)
+		{
+			if (bitfury->osc6_bits < c->osc6_max && (proc->total_mhashes / total_secs) < 2800)
+				bitfury_send_freq(bitfury->spi, bitfury->slot, bitfury->fasync, ++bitfury->osc6_bits);
+			copy_time(tvp_stat, &tv_now);
+		}
+#endif
 		memcpy(&oldbuf[0], &newbuf[n], 4 * (0x10 - n));
 		memcpy(&oldbuf[0x10 - n], &newbuf[0], 4 * n);
 		bitfury->oldjob = newjob;
@@ -625,8 +659,10 @@ out:
 			bitfury->mhz_best = 0;
 			bitfury->force_reinit = false;
 		}
+#ifndef USE_METABANK2
 		if (timer_elapsed(tvp_stat, &tv_now) >= 60)
 			copy_time(tvp_stat, &tv_now);
+#endif
 	}
 	
 	timer_set_delay_from_now(&master_thr->tv_poll, 10000);

+ 109 - 10
driver-metabank.c

@@ -22,6 +22,7 @@
  * THE SOFTWARE.
  */
 
+//#define USE_METABANK2
 #include "config.h"
 
 #include <stdbool.h>
@@ -32,6 +33,15 @@
 #include "spidevc.h"
 #include "tm_i2c.h"
 
+static int renew_voltage = 1;
+static struct timeval mb_stat[32];
+
+typedef struct {
+	double temp;
+	double vc;
+} slots_stat_struct;
+static slots_stat_struct slots[32] = { { .temp = 0, } };
+
 BFG_REGISTER_DRIVER(metabank_drv)
 
 static
@@ -81,6 +91,7 @@ int metabank_autodetect()
 	
 	for (i = 0; i < 32; i++) {
 		slot_on[i] = 0;
+		timer_set_now(&mb_stat[i]);
 	}
 	for (i = 0; i < 32; i++) {
 		int slot_detected = tm_i2c_detect(i) != -1;
@@ -120,17 +131,27 @@ int metabank_autodetect()
 					.drv = &metabank_drv,
 					.procs = chip_n,
 					.device_data = devicelist,
-					.cutofftemp = 50,
+					.cutofftemp = 80,
 				};
 				add_cgpu_slave(cgpu, prev_cgpu);
 				
+#ifdef USE_METABANK2
+				// ### Set all vltage to 0.835V ###
+				applog(LOG_INFO, "Set voltage!");
+				applog(LOG_WARNING, "Slot[%02d]: %.3f V  %.1f C", i,
+					tm_i2c_set_voltage_abs(i, 0.835), tm_i2c_gettemp(i));
+#endif
+				
 				proc_count += chip_n;
 				if (!proc1)
 					proc1 = cgpu;
 				prev_cgpu = cgpu;
 			}
 			else
+			{
+				slot_on[i] = 0;
 				free(port);
+			}
 		}
 	}
 	
@@ -159,9 +180,15 @@ bool metabank_init(struct thr_info *thr)
 		proc->device_data = bitfury;
 		bitfury->spi->cgpu = proc;
 		bitfury_init_chip(proc);
+#ifndef USE_METABANK2
 		bitfury->osc6_bits = 53;
 		bitfury_send_reinit(bitfury->spi, bitfury->slot, bitfury->fasync, bitfury->osc6_bits);
 		bitfury_init_freq_stat(&bitfury->chip_stat, 52, 56);
+#else
+		bitfury->osc6_bits = 56;
+		bitfury_send_reinit(bitfury->spi, bitfury->slot, bitfury->fasync, bitfury->osc6_bits);
+		bitfury_init_freq_stat(&bitfury->chip_stat, 54, 56);
+#endif
 		
 		if (proc->proc_id == proc->procs - 1)
 			free(devicelist);
@@ -180,16 +207,87 @@ static void metabank_shutdown(struct thr_info *thr)
 
 static bool metabank_get_stats(struct cgpu_info *cgpu)
 {
-	struct bitfury_device * const bitfury = cgpu->device_data;
+	struct bitfury_device *bitfury = cgpu->device_data;
 	float t;
-
-	t = tm_i2c_gettemp(bitfury->slot) * 0.1;
-
-	if (t < -27) //Sometimes tm_i2c_gettemp() returns strange result, ignoring it.
-		return false;
-
-	cgpu->temp = t;
-
+	struct timeval now;
+	struct cgpu_info *proc, *cproc;
+	unsigned slot = bitfury->slot;
+	slots_stat_struct *stat = &slots[bitfury->slot];
+	
+	timer_set_now(&now);
+	if (timer_elapsed(&mb_stat[slot], &now) >= 10)
+	{
+		copy_time(&mb_stat[slot], &now);
+		slot = bitfury->slot;
+		t = tm_i2c_gettemp(slot);
+		if (t < -27 || t > 250) //Sometimes tm_i2c_gettemp() returns strange result, ignoring it.
+			return false;
+		cgpu->temp = t;
+		
+#ifndef USE_METABANK2
+		bitfury->volt = tm_i2c_getcore0(slot);
+		stat->temp = t;
+		stat->vc = bitfury->volt;
+#else
+		if (t > 75) // Drop Down voltage
+		{
+			tm_i2c_set_vid(slot, 0);
+			applog(LOG_WARNING, "-----=====!!!!! Slot %u set low voltage !!!!!=====-----", slot);
+		}
+		bitfury->volt = (slot & 1) ? tm_i2c_getcore1(slot) : tm_i2c_getcore0(slot);
+		stat->temp = t;
+		stat->vc = bitfury->volt;
+		
+		if (stat->vc < 0.8 && !renew_voltage && t > 0 && t < 50 && timer_elapsed(&bitfury->tv_stat_long, &now) < 60) { // No overheat return voltage
+			renew_voltage = 1;
+			applog(LOG_WARNING, "Restore voltage after overheat");
+			proc = cgpu->device;
+			slot = 99;
+			while(proc) {
+				bitfury = (struct bitfury_device *) proc->device_data;
+				if (bitfury->slot != slot) {
+					slot = bitfury->slot;
+					applog(LOG_WARNING, "%s slot[%02d]: %.3f V  %.1f C",
+						proc->dev_repr, slot, tm_i2c_set_voltage_abs(slot, 0.835), tm_i2c_gettemp(slot));
+				}
+				proc = proc->next_proc;
+			}
+		}
+		
+		if (renew_voltage && timer_elapsed(&bitfury->tv_stat_long, &now) > 660) { // set new voltage after 15 min
+			int count = 0;
+			double mhz;
+			applog(LOG_WARNING, "Set new voltage!");
+			proc = cgpu->device;
+			while(proc) {
+				cproc = proc;
+				mhz = 0;
+				count = proc->procs;
+				for(int i = 0; i < cproc->procs; i++) {
+					bitfury = (struct bitfury_device *) proc->device_data;
+					if (bitfury->mhz > 150)
+						mhz += bitfury->mhz;
+					else
+						count--;
+					proc = proc->next_proc;
+				}
+				mhz /= (double)count;
+				if (mhz < 220) {
+					applog(LOG_WARNING, "Dev : %s slot[%u]=(%.0f, %d) new voltage: %.3f V\t%.1f C",
+						cproc->dev_repr, bitfury->slot, mhz, count, tm_i2c_set_voltage_abs(bitfury->slot, 0.91), tm_i2c_gettemp(bitfury->slot));
+				} else {
+					applog(LOG_WARNING, "Dev : %s slot[%u]=(%.0f, %d) no changes",
+						cproc->dev_repr, bitfury->slot, mhz, count);
+				}
+			};
+			renew_voltage = 0;
+		}
+#endif
+	} else {
+		cgpu->temp = stat->temp;
+		bitfury->volt = stat->vc;
+	}
+	
 	return true;
 }
 
@@ -215,6 +313,7 @@ static struct api_data *metabank_api_extra_device_status(struct cgpu_info *cgpu)
 
 	vc0 = tm_i2c_getcore0(bitfury->slot);
 	vc1 = tm_i2c_getcore1(bitfury->slot);
+	bitfury->volt = (bitfury->slot & 1) ? vc1 : vc0;
 
 	root = api_add_volts(root, "Slot VC0", &vc0, true);
 	root = api_add_volts(root, "Slot VC1", &vc1, true);

+ 2 - 0
libbitfury.h

@@ -43,6 +43,7 @@ struct bitfury_device {
 	struct freq_stat chip_stat;
 	struct timeval timer1;
 	struct timeval tv_stat;
+	struct timeval tv_stat_long;
 	unsigned int counter1, counter2;
 	double mhz;
 	int mhz_last;
@@ -54,6 +55,7 @@ struct bitfury_device {
 	int desync_counter;
 	int sample_hwe;
 	int sample_tot;
+	double volt;
 };
 
 extern void work_to_bitfury_payload(struct bitfury_payload *, struct work *);

+ 4 - 0
spidevc.c

@@ -116,7 +116,11 @@ bool sys_spi_txrx(struct spi_port *port)
 	struct spi_ioc_transfer tr[16];
 
 	memset(&tr,0,sizeof(tr));
+#ifdef HAS_METABANK2
+	mode = 0; bits = 8; speed = 1000000;
+#else
 	mode = 0; bits = 8; speed = 4000000;
+#endif
 	if (port->speed)
 		speed = port->speed;
 

+ 1 - 1
tm_i2c.c

@@ -38,7 +38,7 @@ static int tm_i2c_fd;
 
 float tm_i2c_Data2Temp(unsigned int ans) {
 	float t = ans;
-	return (t / 1023.0 * 3.3 * 2-2.73) * 100.0;
+	return (t / 1023.0 * 3.3 - 2.73) * 100.0;
 }
 
 float tm_i2c_Data2Core(unsigned int ans) {

+ 6 - 0
tm_i2c.h

@@ -10,6 +10,10 @@
 #define TM_SET_MODE     0x21
 #define TM_SET_RED      0x22
 #define TM_SET_GREEN    0x23
+#define TM_SET_OE0      0x24
+#define TM_SET_OE1      0x25
+#define TM_SET_CORE0    0x26
+#define TM_SET_CORE1    0x27
 
 #define TM_GET_PORTB    0x30
 #define TM_SET_PORTB    0x31
@@ -40,4 +44,6 @@ void tm_i2c_set_oe(unsigned char slot);
 void tm_i2c_clear_oe(unsigned char slot);
 int tm_i2c_detect(unsigned char slot);
 unsigned char tm_i2c_slot2addr(unsigned char slot);
+double tm_i2c_set_voltage_abs(unsigned char slot2, double voltage);
+unsigned int tm_i2c_set_vid(unsigned char slot, unsigned char vid);
 

+ 289 - 0
tm_i2cm.c

@@ -0,0 +1,289 @@
+/*
+ * Copyright 2013 gluk <glukolog@mail.ru>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#ifdef NEED_LINUX_I2C_H
+#include <linux/i2c.h>
+#endif
+#include <linux/i2c-dev.h>
+
+#include "logging.h"
+#include "tm_i2c.h"
+#include <sys/mman.h>
+
+#define TM_TRIES	3
+
+static int tm_i2c_fd;
+
+unsigned leds = 0xFF;
+
+static volatile unsigned *gpiom;
+
+#define INP_GPIO(g) *(gpiom+((g)/10)) &= ~(7<<(((g)%10)*3))
+#define OUT_GPIO(g) *(gpiom+((g)/10)) |=  (1<<(((g)%10)*3))
+#define GPIO_SET *(gpiom+7)
+#define GPIO_CLR *(gpiom+10)
+
+unsigned char slotI2C(unsigned char slot) {
+#ifdef USE_METABANK2
+	unsigned char x = (slot >> 1);
+
+	if (x == 6) return 4;
+	if (x == 4) return 6;
+	return x;
+#else
+	return slot;
+#endif
+}
+
+float tm_i2c_Data2Temp(unsigned int ans) {
+	float t = ans;
+	return (t / 1023.0 * 3.3 * 2.0 - 2.73) * 100.0;
+}
+
+float tm_i2c_Data2Core(unsigned int ans) {
+	float t = ans;
+	return t / 1023.0 * 3.3;
+}
+
+int tm_i2c_init() {
+	int i;
+	int fd;
+
+	fd = open("/dev/mem",O_RDWR|O_SYNC);
+//	if (fd < 0) { perror("/dev/mem trouble"); return (1); }
+	if (fd < 0) return (1);
+	gpiom = mmap(0,4096,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0x20200000);
+	if (gpiom == MAP_FAILED) { perror("gpio mmap trouble"); return(1); }
+	close(fd);
+
+	for(i = 0; i < 4 ; i++) {
+		INP_GPIO(i + 22); OUT_GPIO(i + 22);
+		GPIO_CLR = 1 << (i + 22);
+	}
+	INP_GPIO(27); OUT_GPIO(27);
+	INP_GPIO(17); OUT_GPIO(17);
+	INP_GPIO(18); OUT_GPIO(18);
+
+	GPIO_CLR = 1 << 27;
+	usleep(1000);
+	GPIO_SET = 1 << 27;
+
+	if ((tm_i2c_fd = open("/dev/i2c-1", O_RDWR)) < 0)
+		return 1;
+	else
+		return 0;
+}
+
+void leds_push() {
+	int i;
+	
+	for (i = 0; i < 16; ++i)
+	{
+		if (leds & (1 << i))
+			GPIO_SET = 1 << 17;
+		else
+			GPIO_CLR = 1 << 17;
+		GPIO_SET = 1 << 18;
+		usleep(10);
+		GPIO_CLR = 1 << 18;
+	}
+}
+
+void leds_set(unsigned char b) {
+	leds &= ~(1 << b);
+	leds_push();
+}
+
+void leds_clr(unsigned char b) {
+	leds |= (1 << b);
+	leds_push();
+}
+
+void tm_i2c_close() {
+	close(tm_i2c_fd);
+}
+
+unsigned int tm_i2c_req(int fd, unsigned char addr, unsigned char cmd, unsigned int data) {
+	int i;
+	unsigned char buf[16];
+	struct i2c_msg msg;
+	tm_struct *tm = (tm_struct *) buf;
+	struct i2c_rdwr_ioctl_data msg_rdwr;
+	unsigned int ret;
+
+	//applog(LOG_DEBUG, "fd: %d, REQ from %02X cmd: %02X", fd, addr, cmd);
+
+	tm->cmd = cmd;
+	tm->data_lsb = data & 0xFF;
+	tm->data_msb = (data & 0xFF00) >> 8;
+
+	/* Write CMD */
+	msg.addr = addr;
+	msg.flags = 0;
+	msg.len = 3;
+	msg.buf = (void*)tm;
+	msg_rdwr.msgs = &msg;
+	msg_rdwr.nmsgs = 1;
+	if ((i = ioctl(fd, I2C_RDWR, &msg_rdwr)) < 0) {
+		//perror("ioctl error");
+		return -1;
+	}
+
+	/* Read result */
+	msg.addr = addr;
+	msg.flags = I2C_M_RD;
+	msg.len = 3;
+	msg.buf = (void*)tm;
+	msg_rdwr.msgs = &msg;
+	msg_rdwr.nmsgs = 1;
+	if ((i = ioctl(fd, I2C_RDWR, &msg_rdwr)) < 0) {
+		//perror("ioctl error");
+		return -1;
+	}
+
+	//hexdump(buf, 10);
+	ret = (tm->data_msb << 8) + tm->data_lsb;
+	//printf("REQ from %02X, cmd: %02X, res: %04X\n", addr, cmd, ret);
+	if (tm->cmd == cmd) return ret;
+	return 0;
+}
+
+int tm_i2c_detect(unsigned char slot) {
+	if (slot < 0 || slot > 31) return 0;
+	leds_set(slot >> 1);
+	//return tm_i2c_req(tm_i2c_fd, (TM_ADDR >> 1) + (slot >> 1), TM_GET_CORE0, 0);
+	return 1;
+}
+
+float tm_i2c_getcore0(unsigned char slot) {
+	int t = 0;
+	float v;
+	if (slot < 0 || slot > 31) return 0;
+	do {
+		usleep(10000);
+		v = tm_i2c_Data2Core(tm_i2c_req(tm_i2c_fd, (TM_ADDR >> 1) + slotI2C(slot), TM_GET_CORE0, 0));
+		t++;
+	} while(t <= TM_TRIES && (v == 0 || v > 3.3));
+	if (v == 0 || v > 3.3) v = -1;
+	return v;
+}
+
+float tm_i2c_getcore1(unsigned char slot) {
+	int t = 0;
+	float v;
+	if (slot < 0 || slot > 31) return 0;
+	do {
+		usleep(10000);
+		v = tm_i2c_Data2Core(tm_i2c_req(tm_i2c_fd, (TM_ADDR >> 1) + slotI2C(slot), TM_GET_CORE1, 0));
+		t++;
+	} while(t <= TM_TRIES && (v == 0 || v > 3.3));
+	if (v == 0 || v > 3.3) v = -1;
+	return v;
+}
+
+float tm_i2c_gettemp(unsigned char slot) {
+	if (slot < 0 || slot > 31) return 0;
+	return tm_i2c_Data2Temp(tm_i2c_req(tm_i2c_fd, (TM_ADDR >> 1) + slotI2C(slot), TM_GET_TEMP, 0));
+}
+void tm_i2c_set_oe(unsigned char slot) {
+	int i;
+
+	if (slot < 0 || slot > 15) return;
+	for(i = 0 ; i < 4 ; i++) {
+		if (slot & (1 << i)) GPIO_SET = 1 << (i + 22);
+		else GPIO_CLR = 1 << (i + 22);
+	}
+	GPIO_CLR = 1 << 27;
+	leds ^= (1 << slot);
+	leds_push();
+}
+
+void tm_i2c_clear_oe(unsigned char slot) {
+	if (slot < 0 || slot > 31) return;
+	GPIO_SET = 1 << 27;
+}
+
+unsigned char tm_i2c_slot2addr(unsigned char slot) {
+	if (slot < 0 || slot > 31) return 0;
+	return ((TM_ADDR >> 1) + slotI2C(slot));
+}
+
+#ifdef USE_METABANK2
+double tm_i2c_set_voltage_abs(unsigned char slot2, double voltage) {
+	int vid = 0, core_id;
+	double prev = 0.0, current = 0.0;
+	float (*get_core)(unsigned char);
+	unsigned char slot = slotI2C(slot2);
+	double eps = 0.01, eps_max=0.02;
+
+	if ((slot2 & 1)) {
+		core_id = TM_SET_CORE1;
+		get_core = &tm_i2c_getcore1;
+	} else {
+		core_id = TM_SET_CORE0;
+		get_core = &tm_i2c_getcore0;
+	}
+	if (get_core(slot2) <= 0) return -1;
+
+	do {
+		prev = current;
+		tm_i2c_req(tm_i2c_fd, (TM_ADDR >> 1) + slot, core_id, vid);
+		usleep(100000);
+		current = get_core(slot2);
+		vid++;
+		usleep(1000);
+	} while (current <= voltage && vid < 16);
+	if (current - voltage <= eps) return current;
+	if (current - voltage > eps_max || current - voltage > voltage - prev) {
+		int tr = 0;
+		double volt_chk;
+		//set low
+		vid -= 2;
+		do {
+			tm_i2c_req(tm_i2c_fd, (TM_ADDR >> 1) + slot, core_id, vid);
+			usleep(100000);
+			volt_chk = get_core(slot2);
+			tr++;
+		} while(volt_chk > current && tr < TM_TRIES);
+	}
+	usleep(100000);
+	return get_core(slot2);
+}
+
+unsigned int tm_i2c_set_vid(unsigned char slot, unsigned char vid) {
+	int tr = 0;
+	unsigned int res;
+
+	if (slot < 0 || slot > 31) return -1;
+	do {
+		res = tm_i2c_req(tm_i2c_fd, (TM_ADDR >> 1) + slotI2C(slot), (slot & 1) ? TM_SET_CORE1 : TM_SET_CORE0, vid);
+		tr++;
+	} while(tr < TM_TRIES && res < 0);
+	return res;
+}
+#endif