diff --git a/examples/pwm_demo/pwm_demo.ino b/examples/pwm_demo/pwm_demo.ino new file mode 100644 index 00000000..2992ee66 --- /dev/null +++ b/examples/pwm_demo/pwm_demo.ino @@ -0,0 +1,78 @@ +#include + + +void setup() { + int dc = 100; + //Serial for debug output + Serial.begin(9600); + while(!Serial); + + //LED + pinMode(LED1, OUTPUT); + + //power supply voltage should be available before tle94112.begin() is called + delay(100); + //enable tle94112 + tle94112.begin(); + + /* + //update motor speed + //three different frequencies are shown on oscilloscope + tle94112.configPWM(tle94112.TLE_PWM1, tle94112.TLE_FREQ80HZ, dc); + tle94112.configPWM(tle94112.TLE_PWM2, tle94112.TLE_FREQ100HZ, dc); + tle94112.configPWM(tle94112.TLE_PWM3, tle94112.TLE_FREQ200HZ, dc); + */ + + //halfbridges for outputting HIGH or PWM + tle94112.configHB(tle94112.TLE_HB1, tle94112.TLE_HIGH, tle94112.TLE_PWM1); + tle94112.configHB(tle94112.TLE_HB2, tle94112.TLE_HIGH, tle94112.TLE_PWM2); + tle94112.configHB(tle94112.TLE_HB3, tle94112.TLE_HIGH, tle94112.TLE_PWM3); + tle94112.configHB(tle94112.TLE_HB4, tle94112.TLE_HIGH, tle94112.TLE_NOPWM); + + //halfbridges outputting LOW + tle94112.configHB(tle94112.TLE_HB5, tle94112.TLE_LOW, tle94112.TLE_NOPWM); + tle94112.configHB(tle94112.TLE_HB6, tle94112.TLE_LOW, tle94112.TLE_NOPWM); + tle94112.configHB(tle94112.TLE_HB7, tle94112.TLE_LOW, tle94112.TLE_NOPWM); + tle94112.configHB(tle94112.TLE_HB8, tle94112.TLE_LOW, tle94112.TLE_NOPWM); + + //halfbridges floating / inactive + tle94112.configHB(tle94112.TLE_HB9, tle94112.TLE_FLOATING, tle94112.TLE_NOPWM); + tle94112.configHB(tle94112.TLE_HB10, tle94112.TLE_FLOATING, tle94112.TLE_NOPWM); + tle94112.configHB(tle94112.TLE_HB11, tle94112.TLE_FLOATING, tle94112.TLE_NOPWM); + tle94112.configHB(tle94112.TLE_HB12, tle94112.TLE_FLOATING, tle94112.TLE_NOPWM); +} + +//duty cycle +int dc = 100; + +void loop() { + + //update dutycycle to show animation on oscilloscope + dc = (dc + 8) % 255; + + //update motor speed + //three different frequencies are shown on oscilloscope + tle94112.configPWM(tle94112.TLE_PWM1, tle94112.TLE_FREQ80HZ, dc); + tle94112.configPWM(tle94112.TLE_PWM2, tle94112.TLE_FREQ100HZ, dc); + tle94112.configPWM(tle94112.TLE_PWM3, tle94112.TLE_FREQ200HZ, dc); + + + //print diagnosis information + int diagnosis = tle94112.getSysDiagnosis(); + if(diagnosis==tle94112.TLE_STATUS_OK) + { + Serial.println("Status: OK"); + } + else + { + Serial.print("Status: Error! "); + Serial.println(diagnosis); + tle94112.clearErrors(); + } + + //let LED blink to show that program is still running + delay(200); + digitalWrite(LED1, HIGH); + delay(200); + digitalWrite(LED1, LOW); +} \ No newline at end of file diff --git a/examples/speedControl/speedControl.ino b/examples/speedControl/speedControl.ino new file mode 100644 index 00000000..c0766263 --- /dev/null +++ b/examples/speedControl/speedControl.ino @@ -0,0 +1,37 @@ +#include + +#define pinDir 5 +#define pinSpeed A1 +//connect motor between halfbridge 1 and halfbridge 2 + + +void setup() { + //power supply voltage should be available before tle94112.begin() is called + delay(100); + //enable tle94112 + tle94112.begin(); + + pinMode(pinDir, INPUT); + pinMode(pinSpeed, INPUT); +} + + +void loop() { + //get desired direction from digital pin + int dir = digitalRead(pinDir); + if(dir == HIGH) + { + tle94112.configHB(tle94112.TLE_HB1, tle94112.TLE_HIGH, tle94112.TLE_PWM1); + tle94112.configHB(tle94112.TLE_HB2, tle94112.TLE_LOW, tle94112.TLE_NOPWM); + } + else + { + tle94112.configHB(tle94112.TLE_HB1, tle94112.TLE_LOW, tle94112.TLE_NOPWM); + tle94112.configHB(tle94112.TLE_HB2, tle94112.TLE_HIGH, tle94112.TLE_PWM1); + } + + //get desired motor speed from analog input + int dc = analogRead(pinSpeed) >> 2; + //update motor speed + tle94112.configPWM(tle94112.TLE_PWM1, tle94112.TLE_FREQ80HZ, dc); +} \ No newline at end of file diff --git a/keywords.txt b/keywords.txt new file mode 100644 index 00000000..bf7f7cea --- /dev/null +++ b/keywords.txt @@ -0,0 +1,76 @@ +####################################### +# Syntax Coloring Map For TLE94112 +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +Tle94112 KEYWORD1 + + + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +end KEYWORD2 +configHB KEYWORD2 +configPWM KEYWORD2 +getSysDiagnosis KEYWORD2 +getHBOverCurrent KEYWORD2 +getHBOpenLoad KEYWORD2 +clearErrors KEYWORD2 + + + +####################################### +# Instances (KEYWORD2) +####################################### + +tle94112 KEYWORD2 +tle94112_2 KEYWORD2 + + + +####################################### +# Constants (LITERAL1) +####################################### + +TLE_HB1 LITERAL1 +TLE_HB2 LITERAL1 +TLE_HB3 LITERAL1 +TLE_HB4 LITERAL1 +TLE_HB5 LITERAL1 +TLE_HB6 LITERAL1 +TLE_HB7 LITERAL1 +TLE_HB8 LITERAL1 +TLE_HB9 LITERAL1 +TLE_HB10 LITERAL1 +TLE_HB11 LITERAL1 +TLE_HB12 LITERAL1 + +TLE_NOPWM LITERAL1 +TLE_PWM1 LITERAL1 +TLE_PWM2 LITERAL1 +TLE_PWM3 LITERAL1 + +TLE_FLOATING LITERAL1 +TLE_LOW LITERAL1 +TLE_HIGH LITERAL1 + +TLE_FREQOFF LITERAL1 +TLE_FREQ80HZ LITERAL1 +TLE_FREQ100HZ LITERAL1 +TLE_FREQ200HZ LITERAL1 + +TLE_SPI_ERROR LITERAL1 +TLE_LOAD_ERROR LITERAL1 +TLE_UNDER_VOLTAGE LITERAL1 +TLE_OVER_VOLTAGE LITERAL1 +TLE_POWER_ON_RESET LITERAL1 +TLE_TEMP_SHUTDOWN LITERAL1 +TLE_TEMP_WARNING LITERAL1 + +TLE_STATUS_OK LITERAL1 \ No newline at end of file diff --git a/library.properties b/library.properties new file mode 100644 index 00000000..720a44b6 --- /dev/null +++ b/library.properties @@ -0,0 +1,9 @@ +name=TLE94112 +version=0.1.0 +author=Infineon Technologies +maintainer=Infineon Technologies +sentence=This library provides an interface for Infineon's DC Motor Control Shield with TLE94112EL +paragraph=This shield provides 12 half-bridges which can drive up to 6 indipendent (+5 cascaded) bidirectional motors consuming up to 0.9 Ampere each +category=Device Control +url=https://www.infineon.com/dgdl/Infineon-DC_Motor_Control_Shield_with_TLE94112EL_UserManual-UM-v01_00-EN.pdf?fileId=5546d46259d9a4bf015a4755351304ac +architectures=* diff --git a/src/TLE94112.cpp b/src/TLE94112.cpp new file mode 100644 index 00000000..e38576c1 --- /dev/null +++ b/src/TLE94112.cpp @@ -0,0 +1,227 @@ +/* + * Arduino library to control Infineon's DC Motor Control Shield with TLE94112 + * + * The shield contains twelve independent halfbridges, + * so it can drive up to 6 indipendent (+5 cascaded) bidirectional DC motor(s). + * Each halfbridge provides a high-Voltage (nominal 5.5-18 V) tristate output, + * which is also capable of PWM with 3 different frequencies. + * + * Have a look at the datasheet for more information. + */ + +/*! \file TLE94112.cpp + * \brief This file defines functions and predefined instances from TLE94112.h + */ + +#include "TLE94112.h" +#include "./util/tle94112_conf.h" + +//SPI address commands +#define TLE94112_CMD_WRITE 0x80; +#define TLE94112_CMD_CLEAR 0x80; +//standard pin assignment +#define TLE94112_PIN_CS1 10 +#define TLE94112_PIN_CS2 12 +#define TLE94112_PIN_EN 8 +#define TLE94112_CS_RISETIME 2 + +#define TLE94112_STATUS_INV_MASK (Tle94112::TLE_POWER_ON_RESET) + +//predefined instances +Tle94112 tle94112(&SPI, TLE94112_PIN_CS1, TLE94112_PIN_EN); +Tle94112 tle94112_2(&SPI, TLE94112_PIN_CS2, TLE94112_PIN_EN); + + +Tle94112::Tle94112(void) +{ + Tle94112(&SPI, TLE94112_PIN_CS1, TLE94112_PIN_EN); +} + +Tle94112::Tle94112(SPIClass *bus, uint8_t cs, uint8_t en) +{ + mEnabled = FALSE; + mBus = bus; + mCsPin = cs; + mEnPin = en; +} + +void Tle94112::begin(void) +{ + mEnabled = TRUE; + mBus->begin(); + mBus->setBitOrder(LSBFIRST); + mBus->setClockDivider(SPI_CLOCK_DIV16); + mBus->setDataMode(SPI_MODE1); + pinMode(mEnPin, OUTPUT); + pinMode(mCsPin, OUTPUT); + digitalWrite(mCsPin, HIGH); + digitalWrite(mEnPin, HIGH); + init(); +} + +void Tle94112::end(void) +{ + mEnabled = FALSE; + digitalWrite(mCsPin, HIGH); + digitalWrite(mEnPin, LOW); +} + +void Tle94112::configHB(HalfBridge hb, HBState state, PWMChannel pwm) +{ + configHB(hb, state, pwm, 0); +} + +void Tle94112::configHB(HalfBridge hb, HBState state, PWMChannel pwm, uint8_t activeFW) +{ + if(mEnabled == TRUE) + { + configHB(static_cast(hb), + static_cast(state), + static_cast(pwm), + activeFW ); + } +} + +void Tle94112::configHB(uint8_t hb, uint8_t state, uint8_t pwm, uint8_t activeFW) +{ + uint8_t reg = mHalfBridges[hb].stateReg; + uint8_t mask = mHalfBridges[hb].stateMask; + uint8_t shift = mHalfBridges[hb].stateShift; + writeReg(reg, mask, shift, state); + + reg = mHalfBridges[hb].pwmReg; + mask = mHalfBridges[hb].pwmMask; + shift = mHalfBridges[hb].pwmShift; + writeReg(reg, mask, shift, pwm); + + reg = mHalfBridges[hb].fwReg; + mask = mHalfBridges[hb].fwMask; + shift = mHalfBridges[hb].fwShift; + writeReg(reg, mask, shift, pwm); +} + +void Tle94112::configPWM(PWMChannel pwm, PWMFreq freq, uint8_t dutyCycle) +{ + if(mEnabled == TRUE) + { + configPWM(static_cast(pwm), + static_cast(freq), + dutyCycle ); + } +} + +void Tle94112::configPWM(uint8_t pwm, uint8_t freq, uint8_t dutyCycle) +{ + uint8_t reg = mPwmChannels[pwm].freqReg; + uint8_t mask = mPwmChannels[pwm].freqMask; + uint8_t shift = mPwmChannels[pwm].freqShift; + writeReg(reg, mask, shift, freq); + + reg = mPwmChannels[pwm].dcReg; + mask = mPwmChannels[pwm].dcMask; + shift = mPwmChannels[pwm].dcShift; + writeReg(reg, mask, shift, dutyCycle); +} + +uint8_t Tle94112::getSysDiagnosis() +{ + uint8_t ret = readStatusReg(SYS_DIAG1); + return ret^TLE94112_STATUS_INV_MASK; +} + +uint8_t Tle94112::getSysDiagnosis(DiagFlag mask) +{ + return getSysDiagnosis(static_cast(mask)); +} + +uint8_t Tle94112::getSysDiagnosis(uint8_t mask) +{ + uint8_t ret = readStatusReg(SYS_DIAG1, mask, 0); + return ret^(TLE94112_STATUS_INV_MASK&mask); +} + +uint8_t Tle94112::getHBOverCurrent(HalfBridge hb) +{ + return getHBOverCurrent(static_cast(hb)); +} + +uint8_t Tle94112::getHBOverCurrent(uint8_t hb) +{ + uint8_t reg = mHalfBridges[hb].ocReg; + uint8_t mask = mHalfBridges[hb].ocMask; + uint8_t shift = mHalfBridges[hb].ocShift; + return readStatusReg(reg, mask, shift); +} + +uint8_t Tle94112::getHBOpenLoad(HalfBridge hb) +{ + return getHBOpenLoad(static_cast(hb)); +} + +uint8_t Tle94112::getHBOpenLoad(uint8_t hb) +{ + uint8_t reg = mHalfBridges[hb].olReg; + uint8_t mask = mHalfBridges[hb].olMask; + uint8_t shift = mHalfBridges[hb].olShift; + return readStatusReg(reg, mask, shift); +} + +void Tle94112::clearErrors() +{ + clearStatusReg(SYS_DIAG1); + clearStatusReg(OP_ERROR_1_STAT); + clearStatusReg(OP_ERROR_2_STAT); + clearStatusReg(OP_ERROR_3_STAT); + clearStatusReg(OP_ERROR_4_STAT); + clearStatusReg(OP_ERROR_5_STAT); + clearStatusReg(OP_ERROR_6_STAT); +} + +void Tle94112::writeReg(uint8_t reg, uint8_t mask, uint8_t shift, uint8_t data) +{ + uint8_t address = mCtrlRegAddresses[reg]; + uint8_t toWrite = mCtrlRegData[reg] & (~mask); + toWrite |= (data << shift) & mask; + mCtrlRegData[reg] = toWrite; + + address = address | TLE94112_CMD_WRITE; + digitalWrite(mCsPin, LOW); + uint8_t byte0 = mBus->transfer(address); + uint8_t byte1 = mBus->transfer(toWrite); + digitalWrite(mCsPin, HIGH); + delay(TLE94112_CS_RISETIME); +} + +uint8_t Tle94112::readStatusReg(uint8_t reg) +{ + //read the whole register + return readStatusReg(reg, 0xFF, 0); +} + +uint8_t Tle94112::readStatusReg(uint8_t reg, uint8_t mask, uint8_t shift) +{ + uint8_t address = mStatusRegAddresses[reg]; + + digitalWrite(mCsPin, LOW); + uint8_t byte0 = SPI.transfer(address); + uint8_t received = SPI.transfer(0xFF); //send dummy byte while receiving + digitalWrite(mCsPin, HIGH); + delay(TLE94112_CS_RISETIME); + + received = (received & mask) >> shift; + + return received; +} + +void Tle94112::clearStatusReg(uint8_t reg) +{ + uint8_t address = mStatusRegAddresses[reg]; + + address = address | TLE94112_CMD_CLEAR; + digitalWrite(mCsPin, LOW); + uint8_t byte0 = mBus->transfer(address); + uint8_t byte1 = mBus->transfer(0); //clear register by writing 0x00 + digitalWrite(mCsPin, HIGH); + delay(TLE94112_CS_RISETIME); +} + diff --git a/src/TLE94112.h b/src/TLE94112.h new file mode 100644 index 00000000..15c7e34c --- /dev/null +++ b/src/TLE94112.h @@ -0,0 +1,350 @@ +/* + * Arduino library to control Infineon's DC Motor Control Shield with TLE94112 + * + * The shield contains twelve independent halfbridges, + * so it can drive up to 6 indipendent (+5 cascaded) bidirectional DC motor(s). + * Each halfbridge provides a high-Voltage (nominal 5.5-18 V) tristate output, + * which is also capable of PWM with 3 different frequencies. + * + * Have a look at the datasheet for more information. + */ + +/*! \file TLE94112.h + * \brief This file has to be included in projects that use Infineon's DC Motor Control Shield with TLE94112 + */ + +#ifndef TLE94112_H +#define TLE94112_H + +#include "Arduino.h" +#include "SPI.h" +#include "./util/tle94112_conf.h" + + +/*! \brief the number of halfbridges on a TLE94112 + * + * \see mHalfBridges + * \see HalfBridge + */ +#define TLE94112_NUM_HB 12 + +/*! \brief the number of pwm modes for a halfbridge (including no pwm) + * + * \see mPwmChannels + * \see PWMChannel + */ +#define TLE94112_NUM_PWM 4 + +/*! \brief the number of control registers in a TLE94112 + * + * \see CtrlRegisters + * \see mCtrlRegAddresses + * \see mCtrlRegData + */ +#define TLE94112_NUM_CTRL_REGS 12 + +/*! \brief the number of status registers in a TLE94112 + * + * \see StatusRegisters + * \see mStatusRegAddresses + * \see mStatusRegData + */ +#define TLE94112_NUM_STATUS_REGS 7 + + +//! \brief Class that represents a TLE94112 +class Tle94112 +{ + public: + //! \brief enum for the halfbridges on a TLE94112 + enum HalfBridge + { + TLE_HB1 = 0, TLE_HB2, TLE_HB3, TLE_HB4, TLE_HB5, TLE_HB6, + TLE_HB7, TLE_HB8, TLE_HB9, TLE_HB10, TLE_HB11, TLE_HB12 + }; + + //! \brief enum for the PWM channels of a halfbridge on TLE94112 + enum PWMChannel + { + TLE_NOPWM = 0, TLE_PWM1, TLE_PWM2, TLE_PWM3 + }; + + //! \brief enum for the output states of a halfbridge + enum HBState + { + TLE_FLOATING = 0b00, TLE_LOW = 0b01, TLE_HIGH = 0b10 + }; + + //! \brief enum for the frequencies of a PWM channel + enum PWMFreq + { + TLE_FREQOFF = 0b00, TLE_FREQ80HZ, TLE_FREQ100HZ, TLE_FREQ200HZ + }; + + //! \brief enum for the flags in the register SYS_DIAG1 + enum DiagFlag + { + TLE_SPI_ERROR = 0x80, + TLE_LOAD_ERROR = 0x40, + TLE_UNDER_VOLTAGE = 0x20, + TLE_OVER_VOLTAGE = 0x10, + TLE_POWER_ON_RESET = 0x08, + TLE_TEMP_SHUTDOWN = 0x04, + TLE_TEMP_WARNING = 0x02 + }; + //! \brief Reference value of Status Register + static const uint8_t TLE_STATUS_OK = 0U; + + //! \brief standard constructor with default pin assignment + Tle94112(); + + /*! \brief constructor with individual pin assignment + * + * \param bus a pointer to an SPIClass object + * \param cs pin number of the CS pin + * \param en pin number of the ENABLE pin + */ + Tle94112(SPIClass *bus, uint8_t cs, uint8_t en); + + //! \brief enables and initializes the TLE94112 + void begin(void); + + //! \brief deactivates all outputs and disables the TLE94112 + void end(void); + + /*! \brief sets the output state and the PWM channel for a halfbridge (only for passive freewheeling) + * + * \param hb halfbridge which will be configured + * \param state sets the output voltage to high, low or floating + * \param pwm selects a PWM channel for PWM output + * + * \see HalfBridge + * \see HBState + * \see PWMChannel + */ + void configHB(HalfBridge hb, HBState state, PWMChannel pwm); + + /*! \brief sets the output state and the PWM channel for a halfbridge (allows active freewheeling) + * + * \param hb halfbridge which will be configured + * \param state sets the output voltage to high, low or floating + * \param pwm selects a PWM channel for PWM output + * \param activeFW 1 for active freewheeling + * 0 for passive freewheeling (default) + * + * \see HalfBridge + * \see HBState + * \see PWMChannel + */ + void configHB(HalfBridge hb, HBState state, PWMChannel pwm, uint8_t activeFW); + + /*! \brief sets the frequency and duty cycle for a PWM channel + * + * \param pwm PWM channel which will be configured + * \param freq selects the PWM output frequency + * \param dutyCycle a value from 0 to 255 which sets the dutyCycle + * + * \see PWMChannel + * \see PWMFreq + */ + void configPWM(PWMChannel pwm, PWMFreq freq, uint8_t dutyCycle); + + /*! \brief returns a diagnosis value for error detection + * + * \return 0 if everything is ok + * non-zero value if errors occurred + */ + uint8_t getSysDiagnosis(); + + /*! \brief shows if errors of a specific type have occurred + * + * \param mask mask to filter for a specific flag + * + * \return 0 if everything is ok + * non-zero value on error condition + * + * \see DiagFlag + */ + uint8_t getSysDiagnosis(DiagFlag mask); + + /*! \brief shows if errors of a specific type have occurred + * + * \param mask mask to filter for one or more specific flags + * this can be a disjunction of DiagFlag values + * + * \return 0 if everything is ok + * non-zero value on error condition + * + * \see DiagFlag + */ + uint8_t getSysDiagnosis(uint8_t mask); + + /*! \brief gets the overcurrent error flag bit for a specific halfbridge + * + * \param halfbridge halfbridge thats overcurrent flag will be returned + * + * \return 1 if there HalfBridge was shut down because of an overcurrent + * 0 otherwise + */ + uint8_t getHBOverCurrent(HalfBridge hb); + + /*! \brief gets the openload error flag bit for a specific halfbridge + * + * \param halfbridge halfbridge thats openload flag will be returned + * + * \return 1 if there HalfBridge detected an open load + * 0 otherwise + */ + uint8_t getHBOpenLoad(HalfBridge hb); + + //! \brief clears all clearable error flags + void clearErrors(); + + private: + //! \brief enum for the control registers in a TLE94112 + enum CtrlRegisters + { + HB_ACT_1_CTRL = 0, + HB_ACT_2_CTRL, + HB_ACT_3_CTRL, + HB_MODE_1_CTRL, + HB_MODE_2_CTRL, + HB_MODE_3_CTRL, + PWM_CH_FREQ_CTRL, + PWM1_DC_CTRL, + PWM2_DC_CTRL, + PWM3_DC_CTRL, + FW_OL_CTRL, + FW_CTRL + }; + + //! \brief enum for the control registers in a TLE94112 + enum StatusRegisters + { + SYS_DIAG1 = 0, + OP_ERROR_1_STAT, + OP_ERROR_2_STAT, + OP_ERROR_3_STAT, + OP_ERROR_4_STAT, + OP_ERROR_5_STAT, + OP_ERROR_6_STAT + }; + + //! \brief indicates if TLE94112LE is enabled + uint8_t mEnabled; + //! \brief pointer to the SPIClass object representing the bus + SPIClass *mBus; + //! \brief pin number of the CS pin + uint8_t mCsPin; + //! \brief pin number on the EN pin + uint8_t mEnPin; + //! \brief array of register locations for halfbridges + HalfBridge_t mHalfBridges[TLE94112_NUM_HB]; + //! \brief array of register locations for PWM channels + PWMchannel_t mPwmChannels[TLE94112_NUM_PWM]; + //! \brief mapping array for control register addresses + uint8_t mCtrlRegAddresses[TLE94112_NUM_CTRL_REGS]; + //! \brief mirror array for control register data + uint8_t mCtrlRegData[TLE94112_NUM_CTRL_REGS]; + //! \brief mapping array for status register addresses + uint8_t mStatusRegAddresses[TLE94112_NUM_STATUS_REGS]; + + //! \brief initializes this object, automatically called by begin() + void init(void); + + /*! \brief sets the output state and the PWM channel for a halfbridge + * automatically called by the public version of configHB + * + * \param hb halfbridge which will be configured + * \param state sets the output voltage to high, low or floating + * \param pwm selects a PWM channel for PWM output + * \param activeFW 1 for active freewheeling + * 0 for passive freewheeling (default) + */ + void configHB(uint8_t hb, uint8_t state, uint8_t pwm, uint8_t activeFW); + + /*! \brief sets the frequency and duty cycle for a PWM channel + automatically called by the public version of configPWM + * + * \param pwm PWM channel which will be configured + * \param freq selects the PWM output frequency + * \param dutyCycle a value from 0 to 255 which sets the dutyCycle + */ + void configPWM(uint8_t pwm, uint8_t freq, uint8_t dutyCycle); + + /*! \brief gets the overcurrent error flag bit for a specific halfbridge + * automatically called by the public version of getHBOverCurrent + * + * \param halfbridge halfbridge thats overcurrent flag will be returned + * + * \return 1 if there HalfBridge was shut down because of an overcurrent + * 0 otherwise + */ + uint8_t getHBOverCurrent(uint8_t hb); + + /*! \brief gets the openload error flag bit for a specific halfbridge + * automatically called by the public version of getHBOpenLoad + * + * \param halfbridge halfbridge thats openload flag will be returned + * + * \return 1 if there HalfBridge detected an open load + * 0 otherwise + */ + uint8_t getHBOpenLoad(uint8_t hb); + + /*! \brief writes data bits to a control register of the TLE94112 + * + * \param reg control register number(mapping array index / CtrlRegisters constant) of the register + * \param mask mask for the bits that have to be written + * \param shift data will be shifted left by this amount before masking. This is for the bit alignment of data + * \param data the data byte that has to be written. It will be shifted and masked before + * + * \see CtrlRegisters + * \see TLE94112_NUM_CTRL_REGS + * \see mCtrlRegAddresses + * \see mCtrlRegData + */ + void writeReg(uint8_t reg, uint8_t mask, uint8_t shift, uint8_t data); + + /*! \brief reads one byte from a status register of the TLE94112 + * + * \param reg status register number(mapping array index / StatusRegisters constant) of the register + * + * \return data byte that has been read + * + * \see StatusRegisters + * \see TLE94112_NUM_STATUS_REGS + * \see mStatusRegAddresses + */ + uint8_t readStatusReg(uint8_t reg); + + /*! \brief reads some bits from a status register of the TLE94112 + * + * \param reg status register number(mapping array index / StatusRegisters constant) of the register + * \param mask mask for the bits that have to be read + * \param shift data will be shifted right by this amount after masking. This is for the bit alignment of data + * + * \return data bits that have been read (after masking and shifting) + * + * \see StatusRegisters + * \see TLE94112_NUM_STATUS_REGS + * \see mStatusRegAddresses + */ + uint8_t readStatusReg(uint8_t reg, uint8_t mask, uint8_t shift); + + /*! \brief clears a status register by writing 0x00 to it + * + * \param reg status register number(mapping array index / StatusRegisters constant) of the register + * + * \see StatusRegisters + * \see TLE94112_NUM_STATUS_REGS + * \see mStatusRegAddresses + */ + void clearStatusReg(uint8_t reg); +}; + +//predefined instances +extern Tle94112 tle94112; +extern Tle94112 tle94112_2; + +#endif \ No newline at end of file diff --git a/src/util/tle94112_conf.cpp b/src/util/tle94112_conf.cpp new file mode 100644 index 00000000..c2b08d12 --- /dev/null +++ b/src/util/tle94112_conf.cpp @@ -0,0 +1,77 @@ +/* + * Arduino library to control Infineon's DC Motor Control Shield with TLE94112 + * + * The shield contains twelve independent halfbridges, + * so it can drive up to 6 indipendent (+5 cascaded) bidirectional DC motor(s). + * Each halfbridge provides a high-Voltage (nominal 5.5-18 V) tristate output, + * which is also capable of PWM with 3 different frequencies. + * + * Have a look at the datasheet for more information. + */ + +/*! \file TLE94112_conf.cpp + * \brief This file contains the initialization of a TLE94112 with all its magic numbers + */ + +#include "tle94112_conf.h" +#include "TLE94112.h" + + +void Tle94112::init(void) +{ + //initial control register configuration + mCtrlRegAddresses[static_cast(Tle94112::HB_ACT_1_CTRL)] = 0x03; + mCtrlRegData[HB_ACT_1_CTRL] = 0; + mCtrlRegAddresses[HB_ACT_2_CTRL] = 0x43; + mCtrlRegData[HB_ACT_2_CTRL] = 0; + mCtrlRegAddresses[HB_ACT_3_CTRL] = 0x23; + mCtrlRegData[HB_ACT_3_CTRL] = 0; + mCtrlRegAddresses[HB_MODE_1_CTRL] = 0x63; + mCtrlRegData[HB_MODE_1_CTRL] = 0; + mCtrlRegAddresses[HB_MODE_2_CTRL] = 0x13; + mCtrlRegData[HB_MODE_2_CTRL] = 0; + mCtrlRegAddresses[HB_MODE_3_CTRL] = 0x53; + mCtrlRegData[HB_MODE_3_CTRL] = 0; + mCtrlRegAddresses[PWM_CH_FREQ_CTRL] = 0x33; + mCtrlRegData[PWM_CH_FREQ_CTRL] = 0; + mCtrlRegAddresses[PWM1_DC_CTRL] = 0x73; + mCtrlRegData[PWM1_DC_CTRL] = 0; + mCtrlRegAddresses[PWM2_DC_CTRL] = 0x0B; + mCtrlRegData[PWM2_DC_CTRL] = 0; + mCtrlRegAddresses[PWM3_DC_CTRL] = 0x4B; + mCtrlRegData[PWM3_DC_CTRL] = 0; + mCtrlRegAddresses[FW_OL_CTRL] = 0x2B; + mCtrlRegData[FW_OL_CTRL] = 0; + mCtrlRegAddresses[FW_CTRL] = 0x6B; + mCtrlRegData[FW_CTRL] = 0; + + //status register configuration + mStatusRegAddresses[SYS_DIAG1] = 0x1B; + mStatusRegAddresses[OP_ERROR_1_STAT] = 0x5B; + mStatusRegAddresses[OP_ERROR_2_STAT] = 0x3B; + mStatusRegAddresses[OP_ERROR_3_STAT] = 0x7B; + mStatusRegAddresses[OP_ERROR_4_STAT] = 0x07; + mStatusRegAddresses[OP_ERROR_5_STAT] = 0x47; + mStatusRegAddresses[OP_ERROR_6_STAT] = 0x27; + + //bit masking for all halfbridges + mHalfBridges[TLE_HB1] = { HB_ACT_1_CTRL, 0x03, 0, HB_MODE_1_CTRL, 0x03, 0, FW_OL_CTRL, 0x04, 2, OP_ERROR_1_STAT, 0x03, 0, OP_ERROR_4_STAT, 0x03, 0 }; + mHalfBridges[TLE_HB2] = { HB_ACT_1_CTRL, 0x0C, 2, HB_MODE_1_CTRL, 0x0C, 2, FW_OL_CTRL, 0x08, 3, OP_ERROR_1_STAT, 0x0C, 2, OP_ERROR_4_STAT, 0x0C, 2 }; + mHalfBridges[TLE_HB3] = { HB_ACT_1_CTRL, 0x30, 4, HB_MODE_1_CTRL, 0x30, 4, FW_OL_CTRL, 0x10, 4, OP_ERROR_1_STAT, 0x30, 4, OP_ERROR_4_STAT, 0x30, 4 }; + mHalfBridges[TLE_HB4] = { HB_ACT_1_CTRL, 0xC0, 6, HB_MODE_1_CTRL, 0xC0, 6, FW_OL_CTRL, 0x20, 5, OP_ERROR_1_STAT, 0xC0, 6, OP_ERROR_4_STAT, 0xC0, 6 }; + mHalfBridges[TLE_HB5] = { HB_ACT_2_CTRL, 0x03, 0, HB_MODE_2_CTRL, 0x03, 0, FW_OL_CTRL, 0x40, 6, OP_ERROR_2_STAT, 0x03, 0, OP_ERROR_5_STAT, 0x03, 0 }; + mHalfBridges[TLE_HB6] = { HB_ACT_2_CTRL, 0x0C, 2, HB_MODE_2_CTRL, 0x0C, 2, FW_OL_CTRL, 0x80, 7, OP_ERROR_2_STAT, 0x0C, 2, OP_ERROR_5_STAT, 0x0C, 2 }; + mHalfBridges[TLE_HB7] = { HB_ACT_2_CTRL, 0x30, 4, HB_MODE_2_CTRL, 0x30, 4, FW_CTRL, 0x01, 0, OP_ERROR_2_STAT, 0x30, 4, OP_ERROR_5_STAT, 0x30, 4 }; + mHalfBridges[TLE_HB8] = { HB_ACT_2_CTRL, 0xC0, 6, HB_MODE_2_CTRL, 0xC0, 6, FW_CTRL, 0x02, 1, OP_ERROR_2_STAT, 0xC0, 6, OP_ERROR_5_STAT, 0xC0, 6 }; + mHalfBridges[TLE_HB9] = { HB_ACT_3_CTRL, 0x03, 0, HB_MODE_3_CTRL, 0x03, 0, FW_CTRL, 0x04, 2, OP_ERROR_3_STAT, 0x03, 0, OP_ERROR_6_STAT, 0x03, 0 }; + mHalfBridges[TLE_HB10] = { HB_ACT_3_CTRL, 0x0C, 2, HB_MODE_3_CTRL, 0x0C, 2, FW_CTRL, 0x08, 3, OP_ERROR_3_STAT, 0x0C, 2, OP_ERROR_6_STAT, 0x0C, 2 }; + mHalfBridges[TLE_HB11] = { HB_ACT_3_CTRL, 0x30, 4, HB_MODE_3_CTRL, 0x30, 4, FW_CTRL, 0x10, 4, OP_ERROR_3_STAT, 0x30, 4, OP_ERROR_6_STAT, 0x30, 4 }; + mHalfBridges[TLE_HB12] = { HB_ACT_3_CTRL, 0xC0, 6, HB_MODE_3_CTRL, 0xC0, 6, FW_CTRL, 0x20, 5, OP_ERROR_3_STAT, 0xC0, 6, OP_ERROR_6_STAT, 0xC0, 6 }; + + //bit masking for all pwm channels + mPwmChannels[TLE_NOPWM] = { PWM_CH_FREQ_CTRL, 0x00, 0, 0, 0x00, 0}; //dummy channel for NOPWM + mPwmChannels[TLE_PWM1] = { PWM_CH_FREQ_CTRL, 0x03, 0, PWM1_DC_CTRL, 0xFF, 0}; + mPwmChannels[TLE_PWM2] = { PWM_CH_FREQ_CTRL, 0x0C, 2, PWM2_DC_CTRL, 0xFF, 0}; + mPwmChannels[TLE_PWM3] = { PWM_CH_FREQ_CTRL, 0x30, 4, PWM3_DC_CTRL, 0xFF, 0}; + +} \ No newline at end of file diff --git a/src/util/tle94112_conf.h b/src/util/tle94112_conf.h new file mode 100644 index 00000000..990d1483 --- /dev/null +++ b/src/util/tle94112_conf.h @@ -0,0 +1,54 @@ +/* + * Arduino library to control Infineon's DC Motor Control Shield with TLE94112 + * + * The shield contains twelve independent halfbridges, + * so it can drive up to 6 indipendent (+5 cascaded) bidirectional DC motor(s). + * Each halfbridge provides a high-Voltage (nominal 5.5-18 V) tristate output, + * which is also capable of PWM with 3 different frequencies. + * + * Have a look at the datasheet for more information. + */ + +/*! \file TLE94112_conf.h + * \brief This file is automatically included + */ + + +#ifndef TLE94112_CONF_H +#define TLE94112_CONF_H + +#include "Arduino.h" + +//! \brief struct containing register locations for a single halfbridge +typedef struct +{ + uint8_t stateReg; + uint8_t stateMask; + uint8_t stateShift; + uint8_t pwmReg; + uint8_t pwmMask; + uint8_t pwmShift; + uint8_t fwReg; + uint8_t fwMask; + uint8_t fwShift; + uint8_t ocReg; + uint8_t ocMask; + uint8_t ocShift; + uint8_t olReg; + uint8_t olMask; + uint8_t olShift; +} HalfBridge_t; + +//! \brief struct containing register locations for a single PWM channel +typedef struct +{ + uint8_t freqReg; + uint8_t freqMask; + uint8_t freqShift; + uint8_t dcReg; + uint8_t dcMask; + uint8_t dcShift; +} PWMchannel_t; + + +#endif \ No newline at end of file