diff --git a/Remora-RT1052-cpp/.cproject b/Remora-RT1052-cpp/.cproject index 743cd34..8b6a711 100644 --- a/Remora-RT1052-cpp/.cproject +++ b/Remora-RT1052-cpp/.cproject @@ -800,7 +800,7 @@ SDK_2.x_MIMXRT1052xxxxB evkbimxrt1050_lwip_ping_bm - 2.14.0 + 24.12.00 driver.mdio-enet.MIMXRT1052;driver.phy-device-ksz8081.MIMXRT1052;platform.drivers.cache_armv7_m7.MIMXRT1052;middleware.lwip.contrib.ping.MIMXRT1052;middleware.lwip.enet_ethernetif.MIMXRT1052;middleware.lwip.MIMXRT1052;driver.phy-common.MIMXRT1052;platform.drivers.enet.MIMXRT1052;platform.drivers.clock.MIMXRT1052;platform.drivers.common.MIMXRT1052;device.MIMXRT1052_CMSIS.MIMXRT1052;utility.debug_console.MIMXRT1052;component.lpuart_adapter.MIMXRT1052;component.serial_manager.MIMXRT1052;component.lists.MIMXRT1052;component.serial_manager_uart.MIMXRT1052;platform.drivers.lpuart.MIMXRT1052;device.MIMXRT1052_startup.MIMXRT1052;platform.drivers.iomuxc.MIMXRT1052;platform.utilities.assert.MIMXRT1052;platform.drivers.igpio.MIMXRT1052;platform.drivers.xip_device.MIMXRT1052;platform.drivers.xip_board.evkbimxrt1050.MIMXRT1052;component.silicon_id.MIMXRT1052;driver.mdio-common.MIMXRT1052;CMSIS_Include_core_cm.MIMXRT1052;platform.utilities.misc_utilities.MIMXRT1052;device.MIMXRT1052_system.MIMXRT1052;evkbimxrt1050_lwip_ping_bm; evkbimxrt1050 MIMXRT1052CVL5B @@ -808,28 +808,28 @@ core0_MIMXRT1052xxxxB - <?xml version="1.0" encoding="UTF-8"?> -<TargetConfig> -<Properties property_3="NXP" property_4="MIMXRT1052xxxxB" property_count="5" version="100300"/> -<infoList vendor="NXP"> -<info chip="MIMXRT1052xxxxB" name="MIMXRT1052xxxxB"> -<chip> -<name>MIMXRT1052xxxxB</name> -<family>MIMXRT1050</family> -<vendor>NXP</vendor> -<memory can_program="true" id="Flash" is_ro="true" size="0" type="Flash"/> -<memory id="RAM" size="512" type="RAM"/> -<memoryInstance derived_from="Flash" driver="MIMXRT1050_SFDP_QSPI.cfx" edited="true" id="BOARD_FLASH" location="0x60000000" size="0x400000"/> -<memoryInstance derived_from="RAM" edited="true" id="SRAM_DTC" location="0x20000000" size="0x20000"/> -<memoryInstance derived_from="RAM" edited="true" id="SRAM_ITC" location="0x0" size="0x20000"/> -<memoryInstance derived_from="RAM" edited="true" id="SRAM_OC" location="0x20200000" size="0x40000"/> -</chip> -<processor> -<name gcc_name="cortex-m7">Cortex-M7</name> -<family>Cortex-M</family> -</processor> -</info> -</infoList> + <?xml version="1.0" encoding="UTF-8"?> +<TargetConfig> +<Properties property_3="NXP" property_4="MIMXRT1052xxxxB" property_count="5" version="100300"/> +<infoList vendor="NXP"> +<info chip="MIMXRT1052xxxxB" name="MIMXRT1052xxxxB"> +<chip> +<name>MIMXRT1052xxxxB</name> +<family>MIMXRT1050</family> +<vendor>NXP</vendor> +<memory can_program="true" id="Flash" is_ro="true" size="0" type="Flash"/> +<memory id="RAM" size="512" type="RAM"/> +<memoryInstance derived_from="Flash" driver="MIMXRT1050_SFDP_QSPI.cfx" edited="true" id="BOARD_FLASH" location="0x60000000" size="0x400000"/> +<memoryInstance derived_from="RAM" edited="true" id="SRAM_DTC" location="0x20000000" size="0x20000"/> +<memoryInstance derived_from="RAM" edited="true" id="SRAM_ITC" location="0x0" size="0x20000"/> +<memoryInstance derived_from="RAM" edited="true" id="SRAM_OC" location="0x20200000" size="0x40000"/> +</chip> +<processor> +<name gcc_name="cortex-m7">Cortex-M7</name> +<family>Cortex-M</family> +</processor> +</info> +</infoList> </TargetConfig> diff --git a/Remora-RT1052-cpp/.settings/language.settings.xml b/Remora-RT1052-cpp/.settings/language.settings.xml index a9749f5..4104cc9 100644 --- a/Remora-RT1052-cpp/.settings/language.settings.xml +++ b/Remora-RT1052-cpp/.settings/language.settings.xml @@ -4,7 +4,7 @@ - + @@ -15,7 +15,7 @@ - + diff --git a/Remora-RT1052-cpp/source/modules/pwmgen/pwmgen.cpp b/Remora-RT1052-cpp/source/modules/pwmgen/pwmgen.cpp new file mode 100644 index 0000000..cc7f20d --- /dev/null +++ b/Remora-RT1052-cpp/source/modules/pwmgen/pwmgen.cpp @@ -0,0 +1,294 @@ +#include "pwmgen.h" + +void muxPinsTimer(const char* PwmPin, const char* DirPin) +{ + +} + +void createPwmGen(void) +{ + const char* comment = module["Comment"]; + printf("\n%s\n", comment); + + uint8_t joint = module["Joint Number"]; + uint8_t pwmNumber = module["PWM No"]; + uint16_t pwmFreqHz = module["PWM Frequency"]; + uint8_t minDutyCycle = module["Min Duty Cycle"]; + uint8_t maxDutyCycle = module["Max Duty Cycle"]; + + // configure pointers to data source and feedback location + ptrJointFreqCmd[joint] = &rxData.jointFreqCmd[joint]; + ptrJointEnable = &rxData.jointEnable; + + // create the pwm generator, register it in the thread + Module* pwmgen = new PwmGen(joint, pwmNumber, pwmFreqHz, minDutyCycle, maxDutyCycle,*ptrJointFreqCmd[joint], *ptrJointEnable); + baseThread->registerModule(pwmgen); +} + +PwmGen::PwmGen(uint8_t jointNumber, uint8_t pwm, uint16_t pwmFreqHz, uint8_t minDutyCycle, uint8_t maxDutyCycle, volatile int32_t &ptrFrequencyCommand, volatile uint8_t &ptrJointEnable) : + jointNumber(jointNumber), + pwm(pwm), + pwmFreqHz(pwmFreqHz), + ptrFrequencyCommand(&ptrFrequencyCommand), + ptrJointEnable(&ptrJointEnable) +{ + + /* validate duty cycle limits, both limits must be between + 0 and 100 (inclusive) and max must be greater then min */ + this->minDutyCycle = minDutyCycle; + this->maxDutyCycle = maxDutyCycle; + + if (maxDutyCycle > 100) { + this->maxDutyCycle = 100; + } + if (minDutyCycle > maxDutyCycle) { + this->minDutyCycle = maxDutyCycle; + this->maxDutyCycle = maxDutyCycle; + } + if (minDutyCycle < 0.0) { + this->minDutyCycle = 0.0; + } + if (maxDutyCycle < minDutyCycle) { + this->maxDutyCycle = minDutyCycle; + this->minDutyCycle = minDutyCycle; + } + + this->srcClock_Hz = (CLOCK_GetFreq(kCLOCK_IpgClk) / QTMR_CLOCK_SOURCE_DIVIDER); + this->mask = 1 << this->jointNumber; + this->isEnabled = false; + + switch(this->pwm) + { + case 1: + //PWM1 Module + + //MUX the PWM pin + IOMUXC_SetPinMux( IOMUXC_GPIO_AD_B1_01_TMR3_TIMER1, 0U); + IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_01_TMR3_TIMER1, 0x10B0U); + + //Set Timer Channel + channel = kQTMR_Channel_1; + + //Create the DIR pin + this->dirPin = new Pin("P1_22", OUTPUT); + break; + case 2: + //PWM2 Module + + //MUX the PWM pin + IOMUXC_SetPinMux( IOMUXC_GPIO_AD_B1_02_TMR3_TIMER2, 0U); + IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_02_TMR3_TIMER2, 0x10B0U); + + //Set Timer Channel + channel = kQTMR_Channel_2; + + //Create the DIR pin + this->dirPin = new Pin("P1_25", OUTPUT); + break; + case 3: + //PWM3 Module + + //MUX the PWM pin + IOMUXC_SetPinMux( IOMUXC_GPIO_AD_B1_00_TMR3_TIMER0, 0U); + IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_00_TMR3_TIMER0, 0x10B0U); + + //Set Timer Channel + channel = kQTMR_Channel_0; + + //Create the DIR pin + this->dirPin = new Pin("P1_23", OUTPUT); + break; + case 4: + //PWM4 Module + + //MUX the PWM pin + IOMUXC_SetPinMux( IOMUXC_GPIO_AD_B1_03_TMR3_TIMER3, 0U); + IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_03_TMR3_TIMER3, 0x10B0U); + + //Set Timer Channel + channel = kQTMR_Channel_3; + + //Create the DIR pin + this->dirPin = new Pin("P1_20", OUTPUT); + break; + default: + break; + } + + //Set the Timer Configuration + qtmr_config_t qtmrConfig; + QTMR_GetDefaultConfig(&qtmrConfig); + qtmrConfig.primarySource = QTMR_PRIMARY_SOURCE; + QTMR_Init(QTMR_BASEADDR, channel, &qtmrConfig); + + printf("PWMGEN%d for JOINT%d, Created!!!!\n", this->pwm, this->jointNumber); + printf("PWM Frequency: %d\n", this->pwmFreqHz); + printf("Min Duty Cycle: %d\n", this->minDutyCycle); + printf("Max Duty Cycle: %d\n", this->maxDutyCycle); + printf("Source Clock: %lu\n", this->srcClock_Hz); + printf("-------------------------------------\n"); + +} + +void PwmGen::update() +{ + // Use the standard Module interface to run makePulses() + + this->makePulses(); +} + +void PwmGen::updatePost() +{ + this->stopPulses(); +} + +void PwmGen::slowUpdate() +{ + return; +} + +void PwmGen::makePulses() +{ + + double tmpDC = 0.0; + + this->isEnabled = ((*(this->ptrJointEnable) & this->mask) != 0); + + if (this->isEnabled == true) + { + + if(this->frequencyCommand != *(this->ptrFrequencyCommand)) + { + + this->frequencyCommand = *(this->ptrFrequencyCommand); + + //Convert the frequency command to a duty cycle + tmpDC = this->frequencyCommand; + + /* limit the duty cycle */ + if (tmpDC >= 0.0) { + if (tmpDC > this->maxDutyCycle) { + tmpDC = this->maxDutyCycle; + } else if (tmpDC < this->minDutyCycle) { + tmpDC = this->minDutyCycle; + } + this->direction = false; + this->dutyCycle = tmpDC; + } else { + if (tmpDC < -this->maxDutyCycle) { + tmpDC = -this->maxDutyCycle; + } else if (tmpDC > -this->minDutyCycle) { + tmpDC = -this->minDutyCycle; + } + this->direction = true; + this->dutyCycle = -tmpDC; + } + + // stop the timer so we can force an output state if needed + QTMR_StopTimer(QTMR_BASEADDR, this->channel); + + // manage the Quad Timer inability to handle 0 and 100% conditions + if (this->dutyCycle == 0.0) + { + // use the FORCE and VAL registers to output 0 + + this->base->CHANNEL[this->channel].SCTRL = (TMR_SCTRL_FORCE_MASK | TMR_SCTRL_OEN_MASK | TMR_SCTRL_VAL(0)); + } + else if (this->dutyCycle == 100.0) + { + // use the FORCE and VAL registers to output 1 + this->base->CHANNEL[this->channel].SCTRL = (TMR_SCTRL_FORCE_MASK | TMR_SCTRL_OEN_MASK | TMR_SCTRL_VAL(1)); + } + else + { + /* Set OFLAG pin for output mode and force out a low on the pin */ + base->CHANNEL[this->channel].SCTRL |= (TMR_SCTRL_FORCE_MASK | TMR_SCTRL_OEN_MASK); + + /* Counter values to generate a PWM signal */ + this->periodCount = srcClock_Hz / pwmFreqHz; + this->highCount = (uint32_t) ((float)periodCount * (100-this->dutyCycle)) / 100; + this->lowCount = this->periodCount - this->highCount; + + if (this->highCount > 0U) + { + this->highCount -= 1U; + } + if (this->lowCount > 0U) + { + this->lowCount -= 1U; + } + + /* Setup the compare registers for PWM output */ + this->base->CHANNEL[this->channel].COMP1 = (uint16_t)this->lowCount; + this->base->CHANNEL[this->channel].COMP2 = (uint16_t)this->highCount; + + /* Setup the pre-load registers for PWM output */ + this->base->CHANNEL[this->channel].CMPLD1 = (uint16_t)this->lowCount; + this->base->CHANNEL[this->channel].CMPLD2 = (uint16_t)this->highCount; + + this->reg = base->CHANNEL[this->channel].CSCTRL; + /* Setup the compare load control for COMP1 and COMP2. + * Load COMP1 when CSCTRL[TCF2] is asserted, load COMP2 when CSCTRL[TCF1] is asserted + */ + this->reg &= (uint16_t)(~(TMR_CSCTRL_CL1_MASK | TMR_CSCTRL_CL2_MASK)); + this->reg |= (TMR_CSCTRL_CL1(kQTMR_LoadOnComp2) | TMR_CSCTRL_CL2(kQTMR_LoadOnComp1)); + this->base->CHANNEL[this->channel].CSCTRL = reg; + + if (this->outputPolarity) + { + /* Invert the polarity */ + this->base->CHANNEL[this->channel].SCTRL |= TMR_SCTRL_OPS_MASK; + } + else + { + /* True polarity, no inversion */ + this->base->CHANNEL[this->channel].SCTRL &= ~(uint16_t)TMR_SCTRL_OPS_MASK; + } + + this->reg =this-> base->CHANNEL[this->channel].CTRL; + this->reg &= ~(uint16_t)TMR_CTRL_OUTMODE_MASK; + /* Count until compare value is reached and re-initialize the counter, toggle OFLAG output + * using alternating compare register + */ + this->reg |= (TMR_CTRL_LENGTH_MASK | TMR_CTRL_OUTMODE(kQTMR_ToggleOnAltCompareReg)); + this->base->CHANNEL[this->channel].CTRL = this->reg; + + this->dirPin->set(this->direction); + + // restart the timer + QTMR_StartTimer(QTMR_BASEADDR, this->channel, kQTMR_PriSrcRiseEdge); + } + } + + } + else + { + this->stopPulses(); + } + + + return; + +} + + +void PwmGen::stopPulses() +{ + this->dutyCycle = 0.0; + // stop the timer so we can force an output state if needed + QTMR_StopTimer(QTMR_BASEADDR, this->channel); + + // use the FORCE and VAL registers to output 0 + this->base->CHANNEL[this->channel].SCTRL = (TMR_SCTRL_FORCE_MASK | TMR_SCTRL_OEN_MASK | TMR_SCTRL_VAL(0)); + + this->dirPin->set(false); + + return; +} + + +void PwmGen::setEnabled(bool state) +{ + this->isEnabled = state; +} + diff --git a/Remora-RT1052-cpp/source/modules/pwmgen/pwmgen.h b/Remora-RT1052-cpp/source/modules/pwmgen/pwmgen.h new file mode 100644 index 0000000..0f9fa1e --- /dev/null +++ b/Remora-RT1052-cpp/source/modules/pwmgen/pwmgen.h @@ -0,0 +1,72 @@ +#ifndef PWMGEN_H +#define PWMGEN_H + +#include +#include +#include + +#include "fsl_iomuxc.h" +#include "fsl_qtmr.h" + +#include "../module.h" +#include "../../drivers/pin/pin.h" + +#include "extern.h" + +#define QTMR_BASEADDR TMR3 +#define QTMR_PRIMARY_SOURCE (kQTMR_ClockDivide_2) +#define QTMR_CLOCK_SOURCE_DIVIDER (2U) + +void createPwmGen(void); + +class PwmGen : public Module +{ +private: + + int mask; + + uint8_t jointNumber; // LinuxCNC joint number + uint8_t pwm; // PWM number + uint16_t pwmFreqHz; // PWM frequency + uint8_t minDutyCycle; // min duty cycle + uint8_t maxDutyCycle; // max duty cycle + + volatile int32_t *ptrFrequencyCommand; // pointer to the data source where to get the frequency command + volatile int32_t *ptrFeedback; // pointer where to put the feedback + volatile uint8_t *ptrJointEnable; + + uint32_t pwmMask; // PWM pin location in DR_TOGGLE register + uint32_t dirMask; // Direction pin location in DR_TOGGLE register + + bool isEnabled; // flag to enable the PWM generator + + int32_t frequencyCommand; // the joint frequency command generated by LinuxCNC + float dutyCycle; // current duty cycle + bool direction; // current direction + int32_t period; // period of the PWM signal + + TMR_Type *base = QTMR_BASEADDR; // Timer base address + qtmr_channel_selection_t channel; // Timer channel + + bool outputPolarity; // Timer output polarity + uint32_t srcClock_Hz; // Timer source clock + + uint32_t periodCount; // Timer period count + uint32_t highCount; // Timer high count + uint32_t lowCount; // Timer low count + uint16_t reg; // Timer register + +public: + PwmGen(uint8_t, uint8_t, uint16_t, uint8_t, uint8_t, volatile int32_t&, volatile uint8_t&); // constructor + + Pin *dirPin; // class object member - Pin object + + virtual void update(void); // Module default interface + virtual void updatePost(void); + virtual void slowUpdate(void); + void makePulses(); + void stopPulses(); + void setEnabled(bool); +}; + +#endif diff --git a/Remora-RT1052-cpp/source/remora-rt1052.cpp b/Remora-RT1052-cpp/source/remora-rt1052.cpp index 050f95d..76cfe67 100644 --- a/Remora-RT1052-cpp/source/remora-rt1052.cpp +++ b/Remora-RT1052-cpp/source/remora-rt1052.cpp @@ -64,6 +64,7 @@ along with this program; If not, see . #include "modules/DMAstepgen/DMAstepgen.h" #include "modules/encoder/encoder.h" #include "modules/qdc/qdc.h" +#include "modules/pwmgen/pwmgen.h" #include "modules/comms/RemoraComms.h" #include "modules/pwm/spindlePwm.h" #include "modules/stepgen/stepgen.h" @@ -460,6 +461,10 @@ void loadModules(void) createQdc(); hasQDC = true; } + else if (!strcmp(type,"PwmGen")) + { + createPwmGen(); + } } else if (!strcmp(thread,"Servo")) {