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"))
{