You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							310 lines
						
					
					
						
							9.3 KiB
						
					
					
				
			
		
		
	
	
							310 lines
						
					
					
						
							9.3 KiB
						
					
					
				| #include <SPI.h>
 | |
| #include "TMC2130Stepper.h"
 | |
| #include "TMC2130Stepper_MACROS.h"
 | |
| 
 | |
| TMC2130Stepper::TMC2130Stepper(uint8_t pinEN, uint8_t pinDIR, uint8_t pinStep, uint8_t pinCS) {
 | |
| 	_started = false;
 | |
| 
 | |
| 	this->_pinEN = pinEN;
 | |
| 	this->_pinDIR = pinDIR;
 | |
| 	this->_pinSTEP = pinStep;
 | |
| 	this->_pinCS = pinCS;
 | |
| 
 | |
| 	begin();
 | |
| }
 | |
| 
 | |
| void TMC2130Stepper::begin() {
 | |
| #ifdef TMC2130DEBUG
 | |
| 	Serial.println("TMC2130 Stepper driver library");
 | |
| 	Serial.print("Enable pin: ");
 | |
| 	Serial.println(_pinEN);
 | |
| 	Serial.print("Direction pin: ");
 | |
| 	Serial.println(_pinDIR);
 | |
| 	Serial.print("Step pin: ");
 | |
| 	Serial.println(_pinSTEP);
 | |
| 	Serial.print("Chip select pin: ");
 | |
| 	Serial.println(_pinCS);
 | |
| #endif
 | |
| 	//set pins
 | |
| 	pinMode(_pinEN, OUTPUT);
 | |
| 	pinMode(_pinDIR, OUTPUT);
 | |
| 	pinMode(_pinSTEP, OUTPUT);
 | |
| 	pinMode(_pinCS, OUTPUT);
 | |
| 	digitalWrite(_pinEN, HIGH); //deactivate driver (LOW active)
 | |
| 	digitalWrite(_pinDIR, LOW); //LOW or HIGH
 | |
| 	digitalWrite(_pinSTEP, LOW);
 | |
| 	digitalWrite(_pinCS, HIGH);
 | |
| /*
 | |
| 	pinMode(MOSI, OUTPUT);
 | |
| 	pinMode(MISO, INPUT);
 | |
| 	pinMode(SCK, OUTPUT);
 | |
| 	digitalWrite(MOSI, LOW);
 | |
| 	digitalWrite(MISO, HIGH);
 | |
| 	digitalWrite(SCK, LOW);
 | |
| 
 | |
| 	SPI.begin();
 | |
| */
 | |
| 	GCONF(GCONF_sr);
 | |
| 	CHOPCONF(CHOPCONF_sr);
 | |
| 	COOLCONF(COOLCONF_sr);
 | |
| 	PWMCONF(PWMCONF_sr);
 | |
| 	IHOLD_IRUN(IHOLD_IRUN_sr);
 | |
| 
 | |
| 	toff(8); //off_time(8);
 | |
| 	tbl(1); //blank_time(24);
 | |
| 
 | |
| 	_started = true;
 | |
| }
 | |
| 
 | |
| //uint32_t TMC2130Stepper::send2130(uint8_t addressByte, uint32_t *config, uint32_t value, uint32_t mask) {
 | |
| void TMC2130Stepper::send2130(uint8_t addressByte, uint32_t *config) {
 | |
| 	//uint8_t s;
 | |
| 	SPI.begin();
 | |
| 	SPI.beginTransaction(SPISettings(16000000/8, MSBFIRST, SPI_MODE3));
 | |
| 	digitalWrite(_pinCS, LOW);
 | |
| 
 | |
| 	status_response = SPI.transfer(addressByte & 0xFF); // s = 
 | |
| 	#ifdef TMC2130DEBUG
 | |
| 		Serial.println("## Received parameters:");
 | |
| 		Serial.print("## Address byte: ");
 | |
| 		Serial.println(addressByte, HEX);
 | |
| 		Serial.print("## Config: ");
 | |
| 		Serial.println(*config, BIN);
 | |
| 		Serial.print("## status_response: ");
 | |
| 		Serial.println(status_response, BIN);
 | |
| 	#endif
 | |
| 
 | |
| 	if (addressByte >> 7) { // Check if WRITE command
 | |
| 		//*config &= ~mask; // Clear bits being set
 | |
| 		//*config |= (value & mask); // Set new values
 | |
| 		SPI.transfer((*config >> 24) & 0xFF);
 | |
| 		SPI.transfer((*config >> 16) & 0xFF);
 | |
| 		SPI.transfer((*config >>  8) & 0xFF);
 | |
| 		SPI.transfer(*config & 0xFF);
 | |
| 		#ifdef TMC2130DEBUG
 | |
| 			Serial.println("## WRITE cmd");
 | |
| 			Serial.println("##########################");
 | |
| 		#endif
 | |
| 	} else { // READ command
 | |
| 		SPI.transfer16(0x0000); // Clear SPI
 | |
| 		SPI.transfer16(0x0000);
 | |
| 		digitalWrite(_pinCS, HIGH);
 | |
| 		digitalWrite(_pinCS, LOW);
 | |
| 
 | |
| 		SPI.transfer(addressByte & 0xFF); // Send the address byte again
 | |
| 		*config  = SPI.transfer(0x00);
 | |
| 		*config <<= 8;
 | |
| 		*config |= SPI.transfer(0x00);
 | |
| 		*config <<= 8;
 | |
| 		*config |= SPI.transfer(0x00);
 | |
| 		*config <<= 8;
 | |
| 		*config |= SPI.transfer(0x00);
 | |
| 		#ifdef TMC2130DEBUG
 | |
| 			Serial.println("## READ cmd");
 | |
| 			Serial.print("## Received config: ");
 | |
| 			Serial.println(*config, BIN);
 | |
| 			Serial.println("##########################");
 | |
| 		#endif
 | |
| 	}
 | |
| 
 | |
| 	digitalWrite(_pinCS, HIGH);
 | |
| 	SPI.endTransaction();
 | |
| 
 | |
| 	//return s;
 | |
| }
 | |
| 
 | |
| bool TMC2130Stepper::checkOT() {
 | |
| 	uint32_t response = DRV_STATUS();
 | |
| 	if (response & OTPW_bm) {
 | |
| 		flag_otpw = 1;
 | |
| 		return true; // bit 26 for overtemperature warning flag
 | |
| 	}
 | |
| 	return false;
 | |
| }
 | |
| 
 | |
| bool TMC2130Stepper::getOTPW() { return flag_otpw; }
 | |
| 
 | |
| void TMC2130Stepper::clear_otpw() {	flag_otpw = 0; }
 | |
| 
 | |
| bool TMC2130Stepper::isEnabled() { return !digitalRead(_pinEN) && toff(); }
 | |
| 
 | |
| ///////////////////////////////////////////////////////////////////////////////////////
 | |
| // R+C: GSTAT
 | |
| void 	TMC2130Stepper::GSTAT(uint8_t input){
 | |
| 	GSTAT_sr = input;
 | |
| 	WRITE_REG(GSTAT);
 | |
| }
 | |
| uint8_t TMC2130Stepper::GSTAT()			 	{ READ_REG_R(GSTAT); 		}
 | |
| bool 	TMC2130Stepper::reset()				{ GET_BYTE(GSTAT, RESET);	}
 | |
| bool 	TMC2130Stepper::drv_err()			{ GET_BYTE(GSTAT, DRV_ERR);	}
 | |
| bool 	TMC2130Stepper::uv_cp()				{ GET_BYTE(GSTAT, UV_CP);	}
 | |
| ///////////////////////////////////////////////////////////////////////////////////////
 | |
| // R: IOIN
 | |
| uint32_t 	TMC2130Stepper::IOIN() 			{ READ_REG_R(IOIN); 				}
 | |
| bool 		TMC2130Stepper::step()			{ GET_BYTE_R(IOIN, STEP);			}
 | |
| bool 		TMC2130Stepper::dir()			{ GET_BYTE_R(IOIN, DIR);			}
 | |
| bool 		TMC2130Stepper::dcen_cfg4()		{ GET_BYTE_R(IOIN, DCEN_CFG4);		}
 | |
| bool 		TMC2130Stepper::dcin_cfg5()		{ GET_BYTE_R(IOIN, DCIN_CFG5);		}
 | |
| bool 		TMC2130Stepper::drv_enn_cfg6()	{ GET_BYTE_R(IOIN, DRV_ENN_CFG6);	}
 | |
| bool 		TMC2130Stepper::dco()			{ GET_BYTE_R(IOIN, DCO);			}
 | |
| uint8_t 	TMC2130Stepper::version() 		{ GET_BYTE_R(IOIN, VERSION);		}
 | |
| ///////////////////////////////////////////////////////////////////////////////////////
 | |
| // W: TPOWERDOWN
 | |
| uint32_t TMC2130Stepper::TPOWERDOWN() { return TPOWERDOWN_sr; }
 | |
| void TMC2130Stepper::TPOWERDOWN(uint32_t input) {
 | |
| 	TPOWERDOWN_sr = input;
 | |
| 	WRITE_REG(TPOWERDOWN);
 | |
| }
 | |
| ///////////////////////////////////////////////////////////////////////////////////////
 | |
| // R: TSTEP
 | |
| uint32_t TMC2130Stepper::TSTEP() { READ_REG_R(TSTEP); }
 | |
| ///////////////////////////////////////////////////////////////////////////////////////
 | |
| // W: TPWMTHRS
 | |
| uint32_t TMC2130Stepper::TPWMTHRS() { return TPWMTHRS_sr; }
 | |
| void TMC2130Stepper::TPWMTHRS(uint32_t input) {
 | |
| 	TPWMTHRS_sr = input;
 | |
| 	WRITE_REG(TPWMTHRS);
 | |
| }
 | |
| ///////////////////////////////////////////////////////////////////////////////////////
 | |
| // W: TCOOLTHRS
 | |
| uint32_t TMC2130Stepper::TCOOLTHRS() { return TCOOLTHRS_sr; }
 | |
| void TMC2130Stepper::TCOOLTHRS(uint32_t input) {
 | |
| 	TCOOLTHRS_sr = input;
 | |
| 	WRITE_REG(TCOOLTHRS);
 | |
| }
 | |
| ///////////////////////////////////////////////////////////////////////////////////////
 | |
| // W: THIGH
 | |
| uint32_t TMC2130Stepper::THIGH() { return THIGH_sr; }
 | |
| void TMC2130Stepper::THIGH(uint32_t input) {
 | |
| 	THIGH_sr = input;
 | |
| 	WRITE_REG(THIGH);
 | |
| }
 | |
| ///////////////////////////////////////////////////////////////////////////////////////
 | |
| // RW: XDIRECT
 | |
| uint32_t TMC2130Stepper::XDIRECT() { READ_REG(XDIRECT); }
 | |
| void TMC2130Stepper::XDIRECT(uint32_t input) {
 | |
| 	XDIRECT_sr = input;
 | |
| 	WRITE_REG(XDIRECT);
 | |
| }
 | |
| void TMC2130Stepper::coil_A(int16_t B) 	{ MOD_REG(XDIRECT, COIL_A); 	}
 | |
| void TMC2130Stepper::coil_B(int16_t B) 	{ MOD_REG(XDIRECT, COIL_B); 	}
 | |
| int16_t TMC2130Stepper::coil_A() 		{ GET_BYTE_R(XDIRECT, COIL_A); 	}
 | |
| int16_t TMC2130Stepper::coil_B() 		{ GET_BYTE_R(XDIRECT, COIL_A); 	}
 | |
| ///////////////////////////////////////////////////////////////////////////////////////
 | |
| // W: VDCMIN
 | |
| uint32_t TMC2130Stepper::VDCMIN() { return VDCMIN_sr; }
 | |
| void TMC2130Stepper::VDCMIN(uint32_t input) {
 | |
| 	VDCMIN_sr = input;
 | |
| 	WRITE_REG(VDCMIN);
 | |
| }
 | |
| ///////////////////////////////////////////////////////////////////////////////////////
 | |
| // R: PWM_SCALE
 | |
| uint8_t TMC2130Stepper::PWM_SCALE() { READ_REG_R(PWM_SCALE); }
 | |
| ///////////////////////////////////////////////////////////////////////////////////////
 | |
| // W: ENCM_CTRL
 | |
| uint8_t TMC2130Stepper::ENCM_CTRL() { return ENCM_CTRL_sr; }
 | |
| void TMC2130Stepper::ENCM_CTRL(uint8_t input) {
 | |
| 	ENCM_CTRL_sr = input;
 | |
| 	WRITE_REG(ENCM_CTRL);
 | |
| }
 | |
| void TMC2130Stepper::inv(bool B)		{ MOD_REG(ENCM_CTRL, INV);		}
 | |
| void TMC2130Stepper::maxspeed(bool B)	{ MOD_REG(ENCM_CTRL, MAXSPEED); }
 | |
| bool TMC2130Stepper::inv() 				{ GET_BYTE(ENCM_CTRL, INV); 	}
 | |
| bool TMC2130Stepper::maxspeed() 		{ GET_BYTE(ENCM_CTRL, MAXSPEED);}
 | |
| ///////////////////////////////////////////////////////////////////////////////////////
 | |
| // R: LOST_STEPS
 | |
| uint32_t TMC2130Stepper::LOST_STEPS() { READ_REG_R(LOST_STEPS); }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  *	Helper functions
 | |
|  */
 | |
| 
 | |
| 
 | |
| /*	
 | |
| 	Requested current = mA = I_rms/1000
 | |
| 	Equation for current:
 | |
| 	I_rms = (CS+1)/32 * V_fs/(R_sense+0.02ohm) * 1/sqrt(2)
 | |
| 	Solve for CS ->
 | |
| 	CS = 32*sqrt(2)*I_rms*(R_sense+0.02)/V_fs - 1
 | |
| 	
 | |
| 	Example:
 | |
| 	vsense = 0b0 -> V_fs = 0.325V
 | |
| 	mA = 1640mA = I_rms/1000 = 1.64A
 | |
| 	R_sense = 0.10 Ohm
 | |
| 	->
 | |
| 	CS = 32*sqrt(2)*1.64*(0.10+0.02)/0.325 - 1 = 26.4
 | |
| 	CS = 26
 | |
| */	
 | |
| void TMC2130Stepper::rms_current(uint16_t mA, float multiplier, float RS) {
 | |
| 	Rsense = RS;
 | |
| 	uint8_t CS = 32.0*1.41421*mA/1000.0*(Rsense+0.02)/0.325 - 1;
 | |
| 	// If Current Scale is too low, turn on high sensitivity R_sense and calculate again
 | |
| 	if (CS < 16) {
 | |
| 		vsense(true);
 | |
| 		CS = 32.0*1.41421*mA/1000.0*(Rsense+0.02)/0.180 - 1;
 | |
| 	} else if(vsense()) { // If CS >= 16, turn off high_sense_r if it's currently ON
 | |
| 		vsense(false);
 | |
| 	}
 | |
| 	irun(CS);
 | |
| 	ihold(CS*multiplier);
 | |
| 	val_mA = mA;
 | |
| }
 | |
| 
 | |
| uint16_t TMC2130Stepper::rms_current() {
 | |
| 	return (float)(irun()+1)/32.0 * (vsense()?0.180:0.325)/(Rsense+0.02) / 1.41421 * 1000;
 | |
| }
 | |
| 
 | |
| void TMC2130Stepper::setCurrent(uint16_t mA, float R, float multiplier) { rms_current(mA, multiplier, R); }
 | |
| uint16_t TMC2130Stepper::getCurrent() {	return val_mA; }
 | |
| 
 | |
| void TMC2130Stepper::SilentStepStick2130(uint16_t current) { rms_current(current); }
 | |
| 
 | |
| void TMC2130Stepper::microsteps(uint16_t ms) {
 | |
| 	switch(ms) {
 | |
| 		case 256: mres(0); break;
 | |
| 		case 128: mres(1); break;
 | |
| 		case  64: mres(2); break;
 | |
| 		case  32: mres(3); break;
 | |
| 		case  16: mres(4); break;
 | |
| 		case   8: mres(5); break;
 | |
| 		case   4: mres(6); break;
 | |
| 		case   2: mres(7); break;
 | |
| 		case   0: mres(8); break;
 | |
| 		default: break;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| uint16_t TMC2130Stepper::microsteps() {
 | |
| 	switch(mres()) {
 | |
| 		case 0: return 256;
 | |
| 		case 1: return 128;
 | |
| 		case 2: return  64;
 | |
| 		case 3: return  32;
 | |
| 		case 4: return  16;
 | |
| 		case 5: return   8;
 | |
| 		case 6: return   4;
 | |
| 		case 7: return   2;
 | |
| 		case 8: return   0;
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| void TMC2130Stepper::sg_current_decrease(uint8_t value) {
 | |
| 	switch(value) {
 | |
| 		case 32: sedn(0b00); break;
 | |
| 		case  8: sedn(0b01); break;
 | |
| 		case  2: sedn(0b10); break;
 | |
| 		case  1: sedn(0b11); break;
 | |
| 	}
 | |
| }
 | |
| uint8_t TMC2130Stepper::sg_current_decrease() {
 | |
| 	switch(sedn()) {
 | |
| 		case 0b00: return 32;
 | |
| 		case 0b01: return  8;
 | |
| 		case 0b10: return  2;
 | |
| 		case 0b11: return  1;
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 |