Mirror with some correction

Dependencies:   mbed FastIO FastPWM USBDevice

Committer:
arnoz
Date:
Fri Oct 01 08:19:46 2021 +0000
Revision:
116:7a67265d7c19
Parent:
100:1ff35c07217c
- Correct information regarding your last merge

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mjr 100:1ff35c07217c 1 // This class is not currently used - it's been replaced by IRTransmitter
mjr 100:1ff35c07217c 2 // and NewPwm.
mjr 100:1ff35c07217c 3 #if 0
mjr 100:1ff35c07217c 4
mjr 77:0b96f6867312 5 // IRPwmOut - KL25Z ONLY
mjr 77:0b96f6867312 6 //
mjr 77:0b96f6867312 7 // This is a lightweight reimplementation of PwmOut for KL25Z only.
mjr 77:0b96f6867312 8 // It's basically a bare-metal version of the parts of PwmOut we
mjr 77:0b96f6867312 9 // need. There are two main differences from the base class:
mjr 77:0b96f6867312 10 //
mjr 77:0b96f6867312 11 // - Since we're KL25Z only, we can be less abstract about the
mjr 77:0b96f6867312 12 // hardware register interface, allowing us to store fewer
mjr 77:0b96f6867312 13 // internal pointers. This makes our memory footprint smaller.
mjr 77:0b96f6867312 14 //
mjr 77:0b96f6867312 15 // - We allow for higher precision in setting the PWM period for
mjr 77:0b96f6867312 16 // short cycles, by setting the TPM pre-scaler to 1 and using
mjr 77:0b96f6867312 17 // fractional microsecond counts. The KL25Z native clock rate
mjr 77:0b96f6867312 18 // is 48MHz, which translates to 20ns ticks - meaning we can get
mjr 77:0b96f6867312 19 // .02us precision in our PWM periods. The base mbed library
mjr 77:0b96f6867312 20 // sets the pre-scaler to 64, allowing only 1.33us precision.
mjr 77:0b96f6867312 21 // The reason it does this is the tradeoff of precision against
mjr 77:0b96f6867312 22 // maximum cycle length. The KL25Z TPM has a 16-bit counter,
mjr 77:0b96f6867312 23 // so the longest cycle is 65536 * one clock. With pre-scaling
mjr 77:0b96f6867312 24 // at 1, this is a maximum 1.365ms cycle, whereas it's 87ms with
mjr 77:0b96f6867312 25 // the pre-scaler at the mbed setting of 64. That's a good
mjr 77:0b96f6867312 26 // default for most applications; for our purposes, though,
mjr 77:0b96f6867312 27 // we're always working with cycles in the 35kHz to 40kHz range,
mjr 77:0b96f6867312 28 // so our cycles are all sub-millisecond.
mjr 77:0b96f6867312 29
mjr 77:0b96f6867312 30 #ifndef _IRPWMOUT_H_
mjr 77:0b96f6867312 31 #define _IRPWMOUT_H_
mjr 77:0b96f6867312 32
mjr 77:0b96f6867312 33 #include <mbed.h>
mjr 77:0b96f6867312 34 #include <pinmap.h>
mjr 77:0b96f6867312 35 #include <PeripheralPins.h>
mjr 77:0b96f6867312 36 #include <clk_freqs.h>
mjr 77:0b96f6867312 37
mjr 77:0b96f6867312 38 class IRPwmOut
mjr 77:0b96f6867312 39 {
mjr 77:0b96f6867312 40 public:
mjr 77:0b96f6867312 41 IRPwmOut(PinName pin)
mjr 77:0b96f6867312 42 {
mjr 77:0b96f6867312 43 // determine the channel
mjr 77:0b96f6867312 44 PWMName pwm = (PWMName)pinmap_peripheral(pin, PinMap_PWM);
mjr 77:0b96f6867312 45 MBED_ASSERT(pwm != (PWMName)NC);
mjr 77:0b96f6867312 46 unsigned int port = (unsigned int)pin >> PORT_SHIFT;
mjr 77:0b96f6867312 47 unsigned int tpm_n = (pwm >> TPM_SHIFT);
mjr 77:0b96f6867312 48 this->ch_n = (pwm & 0xFF);
mjr 77:0b96f6867312 49
mjr 77:0b96f6867312 50 // get the system clock rate
mjr 77:0b96f6867312 51 if (mcgpllfll_frequency()) {
mjr 77:0b96f6867312 52 SIM->SOPT2 |= SIM_SOPT2_TPMSRC(1); // Clock source: MCGFLLCLK or MCGPLLCLK
mjr 77:0b96f6867312 53 pwm_clock = mcgpllfll_frequency() / 1000000.0f;
mjr 77:0b96f6867312 54 } else {
mjr 77:0b96f6867312 55 SIM->SOPT2 |= SIM_SOPT2_TPMSRC(2); // Clock source: ExtOsc
mjr 77:0b96f6867312 56 pwm_clock = extosc_frequency() / 1000000.0f;
mjr 77:0b96f6867312 57 }
mjr 77:0b96f6867312 58
mjr 77:0b96f6867312 59 // enable the clock gate on the port (PTx) and TPM module
mjr 77:0b96f6867312 60 SIM->SCGC5 |= 1 << (SIM_SCGC5_PORTA_SHIFT + port);
mjr 77:0b96f6867312 61 SIM->SCGC6 |= 1 << (SIM_SCGC6_TPM0_SHIFT + tpm_n);
mjr 77:0b96f6867312 62
mjr 77:0b96f6867312 63 // fix the pre-scaler at divide-by-1 for maximum precision
mjr 77:0b96f6867312 64 const uint32_t clkdiv = 0;
mjr 77:0b96f6867312 65
mjr 77:0b96f6867312 66 // set up the TPM registers: counter enabled, pre-scaler as set above,
mjr 77:0b96f6867312 67 // no interrupts, high 'true', edge aligned
mjr 77:0b96f6867312 68 tpm = (TPM_Type *)(TPM0_BASE + 0x1000 * tpm_n);
mjr 77:0b96f6867312 69 tpm->SC = TPM_SC_CMOD(1) | TPM_SC_PS(clkdiv);
mjr 77:0b96f6867312 70 tpm->CONTROLS[ch_n].CnSC = (TPM_CnSC_MSB_MASK | TPM_CnSC_ELSB_MASK);
mjr 77:0b96f6867312 71
mjr 77:0b96f6867312 72 // clear the count register to turn off the output
mjr 77:0b96f6867312 73 tpm->CNT = 0;
mjr 77:0b96f6867312 74
mjr 77:0b96f6867312 75 // default to 1ms period
mjr 77:0b96f6867312 76 period_us(1000.0f);
mjr 100:1ff35c07217c 77 //printf("IRPwmOut, SC=%08lx, CnSC=%08lx\r\n", tpm->SC, tpm->CONTROLS[ch_n].CnSC);
mjr 77:0b96f6867312 78
mjr 77:0b96f6867312 79 // wire the pinout
mjr 77:0b96f6867312 80 pinmap_pinout(pin, PinMap_PWM);
mjr 77:0b96f6867312 81 }
mjr 77:0b96f6867312 82
mjr 77:0b96f6867312 83 float read()
mjr 77:0b96f6867312 84 {
mjr 77:0b96f6867312 85 float v = float(tpm->CONTROLS[ch_n].CnV)/float(tpm->MOD + 1);
mjr 77:0b96f6867312 86 return v > 1.0f ? 1.0f : v;
mjr 77:0b96f6867312 87 }
mjr 77:0b96f6867312 88
mjr 77:0b96f6867312 89 void write(float val)
mjr 77:0b96f6867312 90 {
mjr 77:0b96f6867312 91 // do the glitch-free write
mjr 77:0b96f6867312 92 glitchFreeWrite(val);
mjr 77:0b96f6867312 93
mjr 77:0b96f6867312 94 // Reset the counter. This is a workaround for a hardware problem
mjr 77:0b96f6867312 95 // on the KL25Z, namely that the CnV register can only be written
mjr 77:0b96f6867312 96 // once per PWM cycle. Any subsequent attempt to write it in the
mjr 77:0b96f6867312 97 // same cycle will be lost. Resetting the counter forces the end
mjr 77:0b96f6867312 98 // of the cycle and makes the register writable again. This isn't
mjr 77:0b96f6867312 99 // an ideal workaround because it causes visible brightness glitching
mjr 77:0b96f6867312 100 // if the caller writes new values repeatedly, such as when fading
mjr 77:0b96f6867312 101 // lights in or out.
mjr 77:0b96f6867312 102 tpm->CNT = 0;
mjr 77:0b96f6867312 103 }
mjr 77:0b96f6867312 104
mjr 77:0b96f6867312 105 // Write a new value without forcing the current PWM cycle to end.
mjr 77:0b96f6867312 106 // This results in glitch-free writing during fades or other series
mjr 77:0b96f6867312 107 // of rapid writes, BUT with the giant caveat that the caller MUST NOT
mjr 77:0b96f6867312 108 // write another value before the current PWM cycle ends. Doing so
mjr 77:0b96f6867312 109 // will cause the later write to be lost. Callers using this must
mjr 77:0b96f6867312 110 // take care, using mechanisms of their own, to limit writes to once
mjr 77:0b96f6867312 111 // per PWM cycle.
mjr 77:0b96f6867312 112 void glitchFreeWrite(float val)
mjr 77:0b96f6867312 113 {
mjr 77:0b96f6867312 114 // limit to 0..1 range
mjr 77:0b96f6867312 115 val = (val < 0.0f ? 0.0f : val > 1.0f ? 1.0f : val);
mjr 77:0b96f6867312 116
mjr 77:0b96f6867312 117 // Write the duty cycle register. The argument value is a duty
mjr 77:0b96f6867312 118 // cycle on a normalized 0..1 scale; for the hardware, we need to
mjr 77:0b96f6867312 119 // renormalize to the 0..MOD scale, where MOD is the cycle length
mjr 77:0b96f6867312 120 // in clock counts.
mjr 77:0b96f6867312 121 tpm->CONTROLS[ch_n].CnV = (uint32_t)((float)(tpm->MOD + 1) * val);
mjr 77:0b96f6867312 122 }
mjr 77:0b96f6867312 123
mjr 77:0b96f6867312 124 void period_us(float us)
mjr 77:0b96f6867312 125 {
mjr 100:1ff35c07217c 126 // if (tpm->SC == (TPM_SC_CMOD(1) | TPM_SC_PS(0))
mjr 100:1ff35c07217c 127 // && tpm->CONTROLS[ch_n].CnSC == (TPM_CnSC_MSB_MASK | TPM_CnSC_ELSB_MASK))
mjr 100:1ff35c07217c 128 // printf("period_us ok\r\n");
mjr 100:1ff35c07217c 129 // else
mjr 100:1ff35c07217c 130 // printf("period_us regs changed??? %08lx, %08lx\r\n", tpm->SC, tpm->CONTROLS[ch_n].CnSC);
mjr 77:0b96f6867312 131
mjr 77:0b96f6867312 132 float dc = read();
mjr 77:0b96f6867312 133 tpm->MOD = (uint32_t)(pwm_clock * (float)us) - 1;
mjr 77:0b96f6867312 134 write(dc);
mjr 77:0b96f6867312 135 }
mjr 77:0b96f6867312 136
mjr 77:0b96f6867312 137 protected:
mjr 77:0b96f6867312 138 // hardware register base, and TPM channel number we're on
mjr 77:0b96f6867312 139 TPM_Type *tpm;
mjr 77:0b96f6867312 140 uint8_t ch_n;
mjr 77:0b96f6867312 141
mjr 77:0b96f6867312 142 // global clock rate - store statically
mjr 77:0b96f6867312 143 static float pwm_clock;
mjr 77:0b96f6867312 144 };
mjr 77:0b96f6867312 145
mjr 77:0b96f6867312 146 #endif
mjr 100:1ff35c07217c 147
mjr 100:1ff35c07217c 148 #endif /* 0 */