#include "./drv8316.h" void DRV8316Driver3PWM::init(SPIClass* _spi) { DRV8316Driver::init(_spi); setRegistersLocked(false); delayMicroseconds(1); DRV8316Driver::setPWMMode(DRV8316_PWMMode::PWM3_Mode); BLDCDriver3PWM::init(); }; void DRV8316Driver6PWM::init(SPIClass* _spi) { DRV8316Driver::init(_spi); setRegistersLocked(false); delayMicroseconds(1); DRV8316Driver::setPWMMode(DRV8316_PWMMode::PWM6_Mode); // default mode is 6-PWM BLDCDriver6PWM::init(); }; /* * SPI setup: * * capture on falling, propagate on rising = * MSB first * * 16 bit words * outgoing: R/W:1 addr:6 parity:1 data:8 * incoming: status:8 data:8 * * on reads, incoming data is content of register being read * on writes, incomnig data is content of register being written * * */ void handleInterrupt() { } void DRV8316Driver::init(SPIClass* _spi) { // TODO make SPI speed configurable spi = _spi; settings = SPISettings(1000000, MSBFIRST, SPI_MODE1); //setup pins pinMode(cs, OUTPUT); digitalWrite(cs, HIGH); // switch off //SPI has an internal SPI-device counter, it is possible to call "begin()" from different devices spi->begin(); if (_isset(nFault)) { pinMode(nFault, INPUT); // TODO add interrupt handler on the nFault pin if configured // add configuration for how to handle faults... idea: interrupt handler calls a callback, depending on the type of fault // consider what would be a useful configuration in practice? What do we want to do on a fault, e.g. over-temperature for example? //attachInterrupt(digitalPinToInterrupt(nFault), handleInterrupt, PinStatus::FALLING); } }; bool DRV8316Driver::getParity(uint16_t data) { //PARITY = XNOR(CMD, A5..A0, D7..D0) uint8_t par = 0; for (int i=0;i<16;i++) { if (((data)>>i) & 0x0001) par+=1; } return (par&0x01)==0x01; // even number of bits means true } uint16_t DRV8316Driver::readSPI(uint8_t addr) { digitalWrite(cs, 0); spi->beginTransaction(settings); uint16_t data = (((addr<<1) | 0x80)<<8)|0x0000; if (getParity(data)) data |= 0x0100; uint16_t result = spi->transfer16(data); spi->endTransaction(); digitalWrite(cs, 1); // Serial.print("SPI Read Result: "); // Serial.print(data, HEX); // Serial.print(" -> "); // Serial.println(result, HEX); return result; } uint16_t DRV8316Driver::writeSPI(uint8_t addr, uint8_t value) { digitalWrite(cs, 0); spi->beginTransaction(settings); uint16_t data = ((addr<<1)<<8)|value; if (getParity(data)) data |= 0x0100; uint16_t result = spi->transfer16(data); spi->endTransaction(); digitalWrite(cs, 1); // Serial.print("SPI Write Result: "); // Serial.print(data, HEX); // Serial.print(" -> "); // Serial.println(result, HEX); return result; } DRV8316Status DRV8316Driver::getStatus() { IC_Status data; Status__1 data1; Status__2 data2; uint16_t result = readSPI(IC_Status_ADDR); data.reg = (result & 0x00FF); delayMicroseconds(1); // delay at least 400ns between operations result = readSPI(Status__1_ADDR); data1.reg = (result & 0x00FF); delayMicroseconds(1); // delay at least 400ns between operations result = readSPI(Status__2_ADDR); data2.reg = (result & 0x00FF); return DRV8316Status(data, data1, data2); } void DRV8316Driver::clearFault() { uint16_t result = readSPI(Control__2_ADDR); Control__2 data; data.reg = (result & 0x00FF); data.CLR_FLT |= 1; delayMicroseconds(1); // delay at least 400ns between operations result = writeSPI(Control__2_ADDR, data.reg); }; bool DRV8316Driver::isRegistersLocked(){ uint16_t result = readSPI(Control__1_ADDR); Control__1 data; data.reg = (result & 0x00FF); return data.REG_LOCK==REG_LOCK_LOCK; } void DRV8316Driver::setRegistersLocked(bool lock){ uint16_t result = readSPI(Control__1_ADDR); Control__1 data; data.reg = (result & 0x00FF); data.REG_LOCK = lock?REG_LOCK_LOCK:REG_LOCK_UNLOCK; delayMicroseconds(1); // delay at least 400ns between operations result = writeSPI(Control__1_ADDR, data.reg); } DRV8316_PWMMode DRV8316Driver::getPWMMode() { uint16_t result = readSPI(Control__2_ADDR); Control__2 data; data.reg = (result & 0x00FF); return (DRV8316_PWMMode)data.PWM_MODE; }; void DRV8316Driver::setPWMMode(DRV8316_PWMMode pwmMode){ uint16_t result = readSPI(Control__2_ADDR); Control__2 data; data.reg = (result & 0x00FF); data.PWM_MODE = pwmMode; delayMicroseconds(1); // delay at least 400ns between operations result = writeSPI(Control__2_ADDR, data.reg); }; DRV8316_Slew DRV8316Driver::getSlew() { uint16_t result = readSPI(Control__2_ADDR); Control__2 data; data.reg = (result & 0x00FF); return (DRV8316_Slew)data.SLEW; }; void DRV8316Driver::setSlew(DRV8316_Slew slewRate) { uint16_t result = readSPI(Control__2_ADDR); Control__2 data; data.reg = (result & 0x00FF); data.SLEW = slewRate; delayMicroseconds(1); // delay at least 400ns between operations result = writeSPI(Control__2_ADDR, data.reg); }; DRV8316_SDOMode DRV8316Driver::getSDOMode() { uint16_t result = readSPI(Control__2_ADDR); Control__2 data; data.reg = (result & 0x00FF); return (DRV8316_SDOMode)data.SDO_MODE; }; void DRV8316Driver::setSDOMode(DRV8316_SDOMode sdoMode) { uint16_t result = readSPI(Control__2_ADDR); Control__2 data; data.reg = (result & 0x00FF); data.SDO_MODE = sdoMode; delayMicroseconds(1); // delay at least 400ns between operations result = writeSPI(Control__2_ADDR, data.reg); }; bool DRV8316Driver::isOvertemperatureReporting(){ uint16_t result = readSPI(Control__3_ADDR); Control__3 data; data.reg = (result & 0x00FF); return data.OTW_REP==OTW_REP_ENABLE; }; void DRV8316Driver::setOvertemperatureReporting(bool reportFault){ uint16_t result = readSPI(Control__3_ADDR); Control__3 data; data.reg = (result & 0x00FF); data.OTW_REP = reportFault?OTW_REP_ENABLE:OTW_REP_DISABLE; delayMicroseconds(1); // delay at least 400ns between operations result = writeSPI(Control__3_ADDR, data.reg); }; bool DRV8316Driver::isSPIFaultReporting(){ uint16_t result = readSPI(Control__3_ADDR); Control__3 data; data.reg = (result & 0x00FF); return data.SPI_FLT_REP==SPI_FLT_REP_ENABLE; } void DRV8316Driver::setSPIFaultReporting(bool reportFault){ uint16_t result = readSPI(Control__3_ADDR); Control__3 data; data.reg = (result & 0x00FF); data.SPI_FLT_REP = reportFault?SPI_FLT_REP_ENABLE:SPI_FLT_REP_DISABLE; delayMicroseconds(1); // delay at least 400ns between operations result = writeSPI(Control__3_ADDR, data.reg); } bool DRV8316Driver::isOvervoltageProtection(){ uint16_t result = readSPI(Control__3_ADDR); Control__3 data; data.reg = (result & 0x00FF); return data.OVP_EN==OVP_EN_ENABLE; }; void DRV8316Driver::setOvervoltageProtection(bool enabled){ uint16_t result = readSPI(Control__3_ADDR); Control__3 data; data.reg = (result & 0x00FF); data.OVP_EN = enabled?OVP_EN_ENABLE:OVP_EN_DISABLE; delayMicroseconds(1); // delay at least 400ns between operations result = writeSPI(Control__3_ADDR, data.reg); }; DRV8316_OVP DRV8316Driver::getOvervoltageLevel(){ uint16_t result = readSPI(Control__3_ADDR); Control__3 data; data.reg = (result & 0x00FF); return (DRV8316_OVP)data.OVP_SEL; }; void DRV8316Driver::setOvervoltageLevel(DRV8316_OVP voltage){ uint16_t result = readSPI(Control__3_ADDR); Control__3 data; data.reg = (result & 0x00FF); data.OVP_SEL = voltage; delayMicroseconds(1); // delay at least 400ns between operations result = writeSPI(Control__3_ADDR, data.reg); }; DRV8316_PWM100DUTY DRV8316Driver::getPWM100Frequency(){ uint16_t result = readSPI(Control__3_ADDR); Control__3 data; data.reg = (result & 0x00FF); return (DRV8316_PWM100DUTY)data.PWM_100_DUTY_SEL; }; void DRV8316Driver::setPWM100Frequency(DRV8316_PWM100DUTY freq){ uint16_t result = readSPI(Control__3_ADDR); Control__3 data; data.reg = (result & 0x00FF); data.PWM_100_DUTY_SEL = freq; delayMicroseconds(1); // delay at least 400ns between operations result = writeSPI(Control__3_ADDR, data.reg); }; DRV8316_OCPMode DRV8316Driver::getOCPMode(){ uint16_t result = readSPI(Control__4_ADDR); Control__4 data; data.reg = (result & 0x00FF); return (DRV8316_OCPMode)data.OCP_MODE; }; void DRV8316Driver::setOCPMode(DRV8316_OCPMode ocpMode){ uint16_t result = readSPI(Control__4_ADDR); Control__4 data; data.reg = (result & 0x00FF); data.OCP_MODE = ocpMode; delayMicroseconds(1); // delay at least 400ns between operations result = writeSPI(Control__4_ADDR, data.reg); }; DRV8316_OCPLevel DRV8316Driver::getOCPLevel(){ uint16_t result = readSPI(Control__4_ADDR); Control__4 data; data.reg = (result & 0x00FF); return (DRV8316_OCPLevel)data.OCP_LVL; }; void DRV8316Driver::setOCPLevel(DRV8316_OCPLevel amps){ uint16_t result = readSPI(Control__4_ADDR); Control__4 data; data.reg = (result & 0x00FF); data.OCP_LVL = amps; delayMicroseconds(1); // delay at least 400ns between operations result = writeSPI(Control__4_ADDR, data.reg); }; DRV8316_OCPRetry DRV8316Driver::getOCPRetryTime(){ uint16_t result = readSPI(Control__4_ADDR); Control__4 data; data.reg = (result & 0x00FF); return (DRV8316_OCPRetry)data.OCP_RETRY; }; void DRV8316Driver::setOCPRetryTime(DRV8316_OCPRetry ms){ uint16_t result = readSPI(Control__4_ADDR); Control__4 data; data.reg = (result & 0x00FF); data.OCP_RETRY = ms; delayMicroseconds(1); // delay at least 400ns between operations result = writeSPI(Control__4_ADDR, data.reg); }; DRV8316_OCPDeglitch DRV8316Driver::getOCPDeglitchTime(){ uint16_t result = readSPI(Control__4_ADDR); Control__4 data; data.reg = (result & 0x00FF); return (DRV8316_OCPDeglitch)data.OCP_DEG; }; void DRV8316Driver::setOCPDeglitchTime(DRV8316_OCPDeglitch ms){ uint16_t result = readSPI(Control__4_ADDR); Control__4 data; data.reg = (result & 0x00FF); data.OCP_DEG = ms; delayMicroseconds(1); // delay at least 400ns between operations result = writeSPI(Control__4_ADDR, data.reg); }; bool DRV8316Driver::isOCPClearInPWMCycleChange(){ uint16_t result = readSPI(Control__4_ADDR); Control__4 data; data.reg = (result & 0x00FF); return data.OCP_CBC==OCP_CBC_ENABLE; }; void DRV8316Driver::setOCPClearInPWMCycleChange(bool enable){ uint16_t result = readSPI(Control__4_ADDR); Control__4 data; data.reg = (result & 0x00FF); data.OCP_CBC = enable?OCP_CBC_ENABLE:OCP_CBC_DISABLE; delayMicroseconds(1); // delay at least 400ns between operations result = writeSPI(Control__4_ADDR, data.reg); }; bool DRV8316Driver::isDriverOffEnabled(){ uint16_t result = readSPI(Control__4_ADDR); Control__4 data; data.reg = (result & 0x00FF); return data.DRV_OFF==DRV_OFF_ENABLE; }; void DRV8316Driver::setDriverOffEnabled(bool enabled){ uint16_t result = readSPI(Control__4_ADDR); Control__4 data; data.reg = (result & 0x00FF); data.DRV_OFF = enabled?DRV_OFF_ENABLE:DRV_OFF_DISABLE; delayMicroseconds(1); // delay at least 400ns between operations result = writeSPI(Control__4_ADDR, data.reg); }; DRV8316_CSAGain DRV8316Driver::getCurrentSenseGain(){ uint16_t result = readSPI(Control__5_ADDR); Control__5 data; data.reg = (result & 0x00FF); return (DRV8316_CSAGain)data.CSA_GAIN; }; void DRV8316Driver::setCurrentSenseGain(DRV8316_CSAGain gain){ uint16_t result = readSPI(Control__5_ADDR); Control__5 data; data.reg = (result & 0x00FF); data.CSA_GAIN = gain; delayMicroseconds(1); // delay at least 400ns between operations result = writeSPI(Control__5_ADDR, data.reg); }; bool DRV8316Driver::isActiveSynchronousRectificationEnabled(){ uint16_t result = readSPI(Control__5_ADDR); Control__5 data; data.reg = (result & 0x00FF); return data.EN_ASR==EN_ASR_ENABLE; }; void DRV8316Driver::setActiveSynchronousRectificationEnabled(bool enabled){ uint16_t result = readSPI(Control__5_ADDR); Control__5 data; data.reg = (result & 0x00FF); data.EN_ASR = enabled?EN_ASR_ENABLE:EN_ASR_DISABLE; delayMicroseconds(1); // delay at least 400ns between operations result = writeSPI(Control__5_ADDR, data.reg); }; bool DRV8316Driver::isActiveAsynchronousRectificationEnabled(){ uint16_t result = readSPI(Control__5_ADDR); Control__5 data; data.reg = (result & 0x00FF); return data.EN_AAR==EN_AAR_ENABLE; }; void DRV8316Driver::setActiveAsynchronousRectificationEnabled(bool enabled){ uint16_t result = readSPI(Control__5_ADDR); Control__5 data; data.reg = (result & 0x00FF); data.EN_AAR = enabled?EN_AAR_ENABLE:EN_AAR_DISABLE; delayMicroseconds(1); // delay at least 400ns between operations result = writeSPI(Control__5_ADDR, data.reg); }; DRV8316_Recirculation DRV8316Driver::getRecirculationMode(){ uint16_t result = readSPI(Control__5_ADDR); Control__5 data; data.reg = (result & 0x00FF); return (DRV8316_Recirculation)data.ILIM_RECIR; }; void DRV8316Driver::setRecirculationMode(DRV8316_Recirculation recirculationMode){ uint16_t result = readSPI(Control__5_ADDR); Control__5 data; data.reg = (result & 0x00FF); data.ILIM_RECIR = recirculationMode; delayMicroseconds(1); // delay at least 400ns between operations result = writeSPI(Control__5_ADDR, data.reg); }; bool DRV8316Driver::isBuckEnabled(){ uint16_t result = readSPI(Control__6_ADDR); Control__6 data; data.reg = (result & 0x00FF); return data.BUCK_DIS==BUCK_DIS_BUCK_ENABLE; }; void DRV8316Driver::setBuckEnabled(bool enabled){ uint16_t result = readSPI(Control__6_ADDR); Control__6 data; data.reg = (result & 0x00FF); data.BUCK_DIS = enabled?BUCK_DIS_BUCK_ENABLE:BUCK_DIS_BUCK_DISABLE; delayMicroseconds(1); // delay at least 400ns between operations result = writeSPI(Control__6_ADDR, data.reg); }; DRV8316_BuckVoltage DRV8316Driver::getBuckVoltage(){ uint16_t result = readSPI(Control__6_ADDR); Control__6 data; data.reg = (result & 0x00FF); return (DRV8316_BuckVoltage)data.BUCK_SEL; }; void DRV8316Driver::setBuckVoltage(DRV8316_BuckVoltage volts){ uint16_t result = readSPI(Control__6_ADDR); Control__6 data; data.reg = (result & 0x00FF); data.BUCK_SEL = volts; delayMicroseconds(1); // delay at least 400ns between operations result = writeSPI(Control__6_ADDR, data.reg); }; DRV8316_BuckCurrentLimit DRV8316Driver::getBuckCurrentLimit(){ uint16_t result = readSPI(Control__6_ADDR); Control__6 data; data.reg = (result & 0x00FF); return (DRV8316_BuckCurrentLimit)data.BUCK_CL; }; void DRV8316Driver::setBuckCurrentLimit(DRV8316_BuckCurrentLimit mamps){ uint16_t result = readSPI(Control__6_ADDR); Control__6 data; data.reg = (result & 0x00FF); data.BUCK_CL = mamps; delayMicroseconds(1); // delay at least 400ns between operations result = writeSPI(Control__6_ADDR, data.reg); }; bool DRV8316Driver::isBuckPowerSequencingEnabled(){ uint16_t result = readSPI(Control__6_ADDR); Control__6 data; data.reg = (result & 0x00FF); return data.BUCK_PS_DIS==BUCK_PS_DIS_ENABLE; }; void DRV8316Driver::setBuckPowerSequencingEnabled(bool enabled){ uint16_t result = readSPI(Control__6_ADDR); Control__6 data; data.reg = (result & 0x00FF); data.BUCK_PS_DIS = enabled?BUCK_PS_DIS_ENABLE:BUCK_PS_DIS_DISABLE; delayMicroseconds(1); // delay at least 400ns between operations result = writeSPI(Control__6_ADDR, data.reg); }; DRV8316_DelayTarget DRV8316Driver::getDelayTarget(){ uint16_t result = readSPI(Control__10_ADDR); Control__10 data; data.reg = (result & 0x00FF); return (DRV8316_DelayTarget)data.DLY_TARGET; }; void DRV8316Driver::setDelayTarget(DRV8316_DelayTarget us){ uint16_t result = readSPI(Control__10_ADDR); Control__10 data; data.reg = (result & 0x00FF); data.DLY_TARGET = us; delayMicroseconds(1); // delay at least 400ns between operations result = writeSPI(Control__10_ADDR, data.reg); }; bool DRV8316Driver::isDelayCompensationEnabled(){ uint16_t result = readSPI(Control__10_ADDR); Control__10 data; data.reg = (result & 0x00FF); return data.DLYCMP_EN==DLYCMP_EN_ENABLE; }; void DRV8316Driver::setDelayCompensationEnabled(bool enabled){ uint16_t result = readSPI(Control__10_ADDR); Control__10 data; data.reg = (result & 0x00FF); data.DLYCMP_EN = enabled?DLYCMP_EN_ENABLE:DLYCMP_EN_DISABLE; delayMicroseconds(1); // delay at least 400ns between operations result = writeSPI(Control__10_ADDR, data.reg); };