By any chance has anyone got the analogWriteFrequencySlow function running on the Teensy 4.0?
By any chance has anyone got the analogWriteFrequencySlow function running on the Teensy 4.0?
This is an old T_3.1 thread - if an example problem on T_4.0 shows up it would be good to start a new thread perhaps.
More context please? Not seeing a analogWriteFrequencySlow() so it wasn't added to the Teensy CORES.
Does the analogWriteFrequency() not work on T_4.0 at 2Khz?
Quite some time ago I merged a contribution which I believe was originally named analogWriteFrequencySlow. But it was merged into normal analogWriteFrequency, rather than adding a new function name. If you request a frequency on Teensy 3.x which is too low to be generated by the timer+prescalers from F_BUS, then it switches the timer to using a much slower clock. This is only possible because the FTM timers have an option to use a slower clock.
So far, I am not aware of anyone managing to use an alternate clock for PWM on Teensy 4. It may be possible. Here's the info from the reference manual.
Normally we run with mux input 0, which is 150 MHz. With only an 8 bit prescaler and 16 bit counters, we just can't reach very slow PWM frequency because we can only divide 150 MHz by 2^24.
The AUX_CLK (input 2) might be possible, but it would require dedicating submodule0 to act as a prescaler. My understanding is it could only apply to the pins controlled by the other 3 submodules of each FlexPWM, and doing so would make the PWM unusable on the pins controlled by that first submodule.
EXT_CLK (input 1) looks much more promising. It appears to be connected to XBAR output 34 for FlexPWM1 and XBAR output 48 for the other 3 FlexPWM timers. So perhaps we could dedicate one of the unused QuadTimers to generate a relatively slow clock, like 100 kHz and route its through the XBAR to the EXT_CLK inputs.
Of course this would only work on the PWM pins controlled by FlexPWM timers. The QuadTimer controlled pins would need some other approach. But the QuadTimer prescaler has more bits, so maybe not such an issue with those pins.
Re: slow PWM with GPT
I think you can run the T4 GPT timer at low PWM frequency. The compare register is 32 bits so you should be able to get below 1 hz. I think you can only do 50% duty and the output pin is different for T4.0 (GPT2 compare3, pin 16) vs T4.1 (GPT2 compare1, pin 41). here is a T4.1 GPT PWM example
if you want to go real slow, you can select the 32khz clock for the GPT timer.Code://teensy 4.1 GPT PWM pin 41 AD_B1_05 PWM GPT2 compare1 ALT8 #define TICKS 24000 void setup() { //initialise general hardware Serial.begin(115200); //setup serial port // CCM_CSCMR1 &= ~CCM_CSCMR1_PERCLK_CLK_SEL; // turn off 24mhz mode CCM_CCGR0 |= CCM_CCGR0_GPT2_BUS(CCM_CCGR_ON) ; // enable GPT2 module //configure GPT2 for test GPT2_CR = 0; //clear the control register, FRR = 0 means restart after Compare GPT2_SR = 0x3F; //clear all prior status GPT2_PR = 0; //prescale register set divide by 1 GPT2_CR |= GPT_CR_CLKSRC(1); //clock selection #1 24 mhz crystal GPT2_CR |= GPT_CR_ENMOD; //reset count to zero before enabling GPT2_CR |= GPT_CR_OM1(1); // toggle mode compare1 GPT2_OCR1 = TICKS - 1; //Compare1 value 1khz GPT2_CR |= GPT_CR_EN; //enable GPT2 //configure T41 pin 41 as Compare1 output IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_05 = 8; } void loop() { }
Restart mode (FRR = 0) only works on compare channel 1.
Last edited by manitou; 07-30-2021 at 01:08 AM.
Re: slow PWM
As Paul noted, one can use EXT_CLK via XBAR to flexpwm timers to get a slower clock. Here is a proof-of-concept sketch using quad-timer to provide a 10khz clock via XBAR to flexpwm timer. Hook scope to pin 8 (PWM output pin).
EDIT: use QTIMER4/0 since not used by T4*Code:// QTIMER4 timer 0 xbar 36 to EXT_CLK flexpwm via XBAR 34 // pin 8 FLEXPWM1_A3 XBAR1_OUT34 #define MMASK (1<<3) // module mask 3 for PWM1_A3 #define PRREG(x) Serial.print(#x" 0x"); Serial.println(x,HEX) void flexpwm_init(int scale) { // flexpwm pin 8 external clock FLEXPWM1_OUTEN |= FLEXPWM_OUTEN_PWMA_EN(MMASK); //A3 IOMUXC_SW_MUX_CTL_PAD_GPIO_B1_00 = 6 ; // ALT6 FLEXPWM1_FCTRL0 |= FLEXPWM_FCTRL0_FLVL(MMASK); // clear FLEXPWM1_FSTS0 = FLEXPWM_FSTS0_FFLAG(MMASK); // clear FLEXPWM1_MCTRL |= FLEXPWM_MCTRL_CLDOK(MMASK); FLEXPWM1_SM3CTRL2 = FLEXPWM_SMCTRL2_INDEP | FLEXPWM_SMCTRL2_CLK_SEL(1); // ext clk FLEXPWM1_SM3CTRL = FLEXPWM_SMCTRL_FULL | FLEXPWM_SMCTRL_PRSC(0); FLEXPWM1_SM3INIT = 0; FLEXPWM1_SM3VAL0 = 0; FLEXPWM1_SM3VAL1 = scale - 1; // period ticks FLEXPWM1_SM3VAL2 = 0; FLEXPWM1_SM3VAL3 = scale / 2; FLEXPWM1_SM3VAL4 = 0; FLEXPWM1_SM3VAL5 = 0; FLEXPWM1_MCTRL |= FLEXPWM_MCTRL_LDOK(MMASK) | FLEXPWM_MCTRL_RUN(MMASK); } void xbar_connect(unsigned int input, unsigned int output) { if (input >= 88) return; if (output >= 132) return; volatile uint16_t *xbar = &XBARA1_SEL0 + (output / 2); uint16_t val = *xbar; if (!(output & 1)) { val = (val & 0xFF00) | input; } else { val = (val & 0x00FF) | (input << 8); } *xbar = val; } void xbar_init() { CCM_CCGR2 |= CCM_CCGR2_XBAR1(CCM_CCGR_ON); //turn clock on for xbara1 xbar_connect(XBARA1_IN_QTIMER4_TIMER0, XBARA1_OUT_FLEXPWM1_EXT_CLK); // 36,34 } void qtmr40_init(int hz) { int cnt, pcs = 0; cnt = 150000000 / hz; while (cnt > 65536) { pcs++; hz *= 2; cnt = 150000000 / hz; } CCM_CCGR6 |= CCM_CCGR6_QTIMER4(CCM_CCGR_ON); // enable qtmr4 TMR4_CTRL0 = 0; // stop TMR4_SCTRL0 = TMR_SCTRL_OPS | TMR_SCTRL_OEN ; TMR4_LOAD0 = 0; // start val after compare TMR4_COMP10 = cnt - 1; // count up to this val, interrupt, and start again TMR4_CMPLD10 = cnt - 1; TMR4_CTRL0 = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8 + pcs) | TMR_CTRL_LENGTH | TMR_CTRL_OUTMODE(4) ; // prescale } void setup() { Serial.begin(9600); delay(1000); xbar_init(); flexpwm_init(10); //divisor qtmr40_init(10000); // 10 khz } void loop() { }
https://github.com/manitou48/teensy4...r/qtmrxpwm.ino
Last edited by manitou; 01-06-2021 at 09:50 AM. Reason: use QTIMER4/0
I'm also interested in this being included for the T4.x hopefully in Teensyduino 1.54.
Has anyone found a way to make this work for teensy 4.x? Seems like it will be a while before we can order teensy 3's...
Could you not use a frequency divider chip?
That way the 4.x can generate a higher frequency which is divided down by the external chip.
You can try this Teensy_Slow_PWM library, designed for very low (sub-Hz) up to 500Hz ISR-based PWM.