Hi all,
I am Using kinetis K26 uc
For my application i am using FTM0 Channel 0 and Channel 1 for Beep soung generation.
I need to Generate different frequency PWM signals on both channels Simultaneously. is that FTM module support for this?
thanks and Regards,
Sujin
Solved! Go to Solution.
Hi
The FTM0_C0V and FTM0_C1V can be used to generate different duty cycle PWM signals.
The Channel 0 and Channel 1 share the same FTM0_MOD register, so you can't generate different frequency PWM signals on both channels Simultaneously.
Please try to use different FTM modules.
Best Regards,
Robin
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hi
The FTM0_C0V and FTM0_C1V can be used to generate different duty cycle PWM signals.
The Channel 0 and Channel 1 share the same FTM0_MOD register, so you can't generate different frequency PWM signals on both channels Simultaneously.
Please try to use different FTM modules.
Best Regards,
Robin
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
thank you
I got your point
so let me ask you one thing, we can't able to generate different frequencies on different channels of FTM_0 Module then what is the use of multiple channels in same FTM module.
I think It can only useful to generate PWM signals for motor applications
Thanks and Regards,
Sujin Vincent
If the 'overall rate' of FTM-generated edges you need is 'tolerable' (say less than 100K/s overall) then you can always go the 'timer banged sequence generation' route. That is, like 'bit banged I/O' firmware sets each edge, BUT in the case of 'timer-banged' generation the timer-hardware precisely places each edge for you, AND your firmware only has to respond to the high-priority interrupt that the 'latest edge time has been consumed' to set up the NEXT edge event, then return to 'normal' work. It is easiest if you let the base FTM counter free-run (MOD FFFF), then just use 16-bit unsigned math to calculate from each 'previous edge' to 'next edge' based on the next timing requirement. This is used 'all the time' to 'fake' another UART TX (RX too, but that is a little harder) but certainly can be used to make ANY firmware-calculatable sequence.
I couldn't get you
are you telling we can generate different frequencies?
Absolutely!!! ---well, within reason! I haven't had occasion to run this kind of process on Kinetis yet, but have done so 'many times' on S08, and the timer-peripheral is (for better or worse) 'very similar'.
Firstly, you run the FTM's channels in 'output compare' mode, table 45-3 in K26 RM, '01 01' -- for this generation, 'toggle output' is probably sufficient here; for other waveform generation you may want to force 'one' or 'zero' on the next time-compare.
Let's say you run FTM at 10MHz, with MOD of course at 0xFFFF (152.6Hz overflow rate) --- said FTM frequency is a tradeoff between frequency-resolution and lowest-possible frequency being >= 1/2 overflow rate. And let's further posit that you want (at this time) to make 2400Hz and 2800Hz. That makes for 4800 edges and 5600 edges, otherwise defined then as 2083 'counts' between edges for 2400.4Hz, 1786 for 2799.5Hz. So then you have (in-psuedo-code) an ISR like this:
FTM0_IRQHandler()
{
if(channel 0 interrupt)
clear interrupt; ////FTM0_C0SC &= ~FTM_CnSC_CHF_MASK;
FTM0_C0V = FTM0_C0V+2083;
if(channel 1 interrupt)
clear interrupt;
FTM0_C1V = FTM0_C1V+1786;
}
Your time-counts would surely be 'pre-calculated unsigned-16bit variables' somewhere, not the shown constants, but that is the idea. It MIGHT be faster to have a uint16_t static-var that keeps the running-timer-count for each channel, like FTM_ch0_next_count += Freq0_count; then just write that to FTM0_C0V, as the process to fetch the peripheral-register is slower than RAM-access (but causes a second global-address-load-instruction and two back-to-back write-ops, so maybe NOT faster??? Interesting...).
This interrupt MUST be allowed to be serviced faster than your lowest half-period, else the 'time for the next event' will already have 'passed' when you get here, meaning this 'simple math' will delay the next edge one whole FTM overflow. This is easiest to achieve if said FTM channel is the highest-level interrupt, and never disabled. See also my priority-comments in:
https://community.nxp.com/message/872684?commentID=872684#comment-872684
As for overhead, we might guess this IRQ to take a microsecond or so, so for our combined 10,400 edges/s we take ~1% of the CPU for these two examples.
FWIW, this is an S08 interrupt-handler for full timer-banged-UART-waveform generation (of a fixed-size 8-byte message):
#define BAUDRATE (1000000/38400) //uS per bit, assume 8MHz Busclk and /8 prescale
/* TPMC0SC: CH1F=0,CH1IE=1,MS0B=0,MS0A=1,ELS0B=1,ELS0A=1,??=0,??=0--to set a 'one' */
#define MARK 0xD8 ////SC values for INVERTED UART waveform (mark=0V, space=Vdd)
#define SPACE 0xDC
static uint8_t serbyte; //Byte currently going out serial stream
static uint8_t ser_bit_cnt; //Bit count within said byte
static uint8_t ser_byte_cnt; //Count within total stream
enum SIOState {SIO_Idle, SIO_SendStrt, SIO_SendByte,
SIO_SendStop, SIO_WaitIdle} SIO_State=SIO_Idle;
ISR (Tim1_OutComp)
{
(void)TPMC1SC;
/* TPMC0SC: CH0F=0 */
clrReg8Bits(TPMC1SC, 0x80); /* Reset compare interrupt request flag */
if( SIO_State != SIO_Idle )
{
setReg16(TPMC1V, TPMC1V+BAUDRATE); /* 'Default' Compare 1 value for next bit */
if( SIO_State == SIO_SendByte )
{
if( (serbyte & 0x01) == 0x01 ) //Set up for next bit
setReg8(TPMC1SC, MARK);
else
setReg8(TPMC1SC, SPACE);
serbyte >>= 1;
ser_bit_cnt--;
if( ser_bit_cnt == 0 )
{
SIO_State = SIO_SendStop;
setReg8(TPMC1SC, MARK);
}
}else if( SIO_State == SIO_SendStop )
{
if( ser_byte_cnt != 8 )
{
SIO_State = SIO_SendByte;
setReg8(TPMC1SC, SPACE);
ser_byte_cnt++;
serbyte = ValidData[ser_byte_cnt];
ser_bit_cnt = 9;
}else
{
SIO_State = SIO_WaitIdle;
setReg16(TPMC1V, TPMCNT+1000); //Wait 1ms from now for 'Idle'
}
}else if( SIO_State == SIO_WaitIdle )
{
if( ser_byte_cnt != 8 )
SIO_State = SIO_SendStop; //Start up bit stream next bit time
else
{
SIO_State = SIO_Idle;
KBISC_KBIE = 1; //Start looking for input edges
PTAD_PTAD4 = 0; //Re-enable debug port serial
}
}
}else
{
setReg16(TPMC1V, TPMCNT+127); //Wait another while of 'nothing'
}
}
Did this 'timer-banged' process get you the waveforms you needed?