I've been trying everything I can think of to get quadrature decoding to work with my FRDM-K64F board, running KDS 2.0, KSDK 1.1, MQX, and a combination of PEx and bare metal code.
I started by using the fsl_ftm component with the following settings:
With these settings, FTM2_CNT is always 0.
I have confirmed that the encoder works because I have my scope hooked up to PTB18 and PTB19 and can see the signals there.
I then found another post here on the forum that outlined the bare metal configuration. So I changed my task code to configure FTM2 (perhaps it can't be done in a task?), and the results are the same. Here is the code I used. Note that I only modified registers where the already-set value by PEx looked reasonable.
void qd_task( task_param_t initial_data)
{
static uint16_t counter = 0;
uint32_t sim_scgc6 = SIM_SCGC6;
uint32_t ftm2_mode = FTM2_MODE;
FTM2_CONF |= FTM_CONF_BDMMODE(3);
uint32_t ftm2_conf = FTM2_CONF;
FTM2_MOD = 4095;
uint32_t ftm2_mod = FTM2_MOD;
uint32_t ftm2_cntin = FTM2_CNTIN;
uint32_t ftm2_qdctrl = FTM2_QDCTRL;
FTM2_SC |= 0x08; // use system clock
uint32_t ftm2_sc = FTM2_SC;
while(1) {
if( FTM2_CNT != counter) {
counter = FTM2_CNT;
}
}
}
After running up to the while loop, here are the register values:
sim_scgc6 uint32_t 0x64000001
ftm2_mode uint32_t 0x5
ftm2_conf uint32_t 0xc0
ftm2_mod uint32_t 0x0
ftm2_cntin uint32_t 0x0
ftm2_qdctrl uint32_t 0xcd
ftm2_sc uint32_t 0x9
Can anyone suggest something for me to try to debug this further?
Original Attachment has been moved to: qd_pex_mqx.zip
已解决! 转到解答。
Ok, so I think I have it figured out. At least to the point where I'll be able to make some more progress. My original theory about why FMT2_CNT wasn't getting updated was correct, and it all came down to FMT2_MOD. If it's 0, the counter isn't going to increment. Although that does make sense, it would be nice to see this in a note in the reference manual because it'll probably help out some people.
But perhaps more importantly, I feel like it would have been nice to make the updating process of FMT2_MOD a little more clear. I followed the flowchart and set the registers as indicated, but could never get the register to update.
In the end, I used the following method, which was so obvious and easy, yet it took me at least two days of banging my head against the wall to realize how it could be done. And as far as I could tell, the manual doesn't offer this option in a note. It's definitely implied, but sometimes just telling the user something directly is a nice thing to do. :smileyhappy:
The solution is to simple disable FMT before setting FMTx_MOD. That's it.
Here's all you have to do:
Now you'll be able to see FMT2_CNT change when you spin the encoder.
I still have to go back through my code and determine what PEx does for me, and what I have to explicitly change myself. In addition, I need to write an ISR to handle the counter rollover conditions.
Hi Dave408,
So, I have encountered the same issue and thanks to your post, I narrowed in on MOD=0 as well.
I did however find a way to use the PEx to fix it. There is a function called "FTM_DRV_CounterStart" that needs to be called prior to starting the quad encoder. This function will preset the MOD. But, it can only be done while the decode is not running (i.e. FTM_DRV_QuadDecodeStart has not yet been called or you stopped the decoder with FTM_DRV_QuadDecodeStop).
Step 1: Remove the auto initialization of the encoder
Step 2: Manually initialize the encode.
<code>
//in main.c -> main()
.....
PE_low_level_init();
/*** End of Processor Expert internal initialization. ***/
FTM_DRV_CounterStart(Encoder_IDX, kCounting_FTM_UP, 0x0, 0xffff, false);
FTM_DRV_QuadDecodeStart(Encoder_IDX, &Encoder_QdConfig0, &Encoder_QdConfig0, kFtmQuadCountAndDir);
.....
</code>
-Ry
So I'm in the same position now as you were before finding this solution, where I have set up Processor Expert to enable FTM2 for quadrature mode but the counter does not increment or decrement as I turn the encoder.
I've gone and added your code suggestions to my initialization procedure (I am also using FTM2 on the K64), and I can verify that FTM2_MOD is successfully written to and has the value 0xFFFF, yet the counter still doesn't update. I'm sure there is a step that I'm missing but I'm not sure that your posted code contains the complete solution.
Did you ultimately not use the Processor Expert code for initialization and do everything through baremetal? If so, would you be willing to share some of that code? Alternatively, if you did keep the PEx settings, could you explain further what the actual issue is?
Any help is very much appreciated, thanks!
Sorry for the late response, Kris! Are you using KDS 2.0 or KDS 3.0? I don't know how much of a difference it makes, but I am currently using 3.0 and my post above isn't entirely accurate.
I am using the PE configuration along with the bare metal "pre configuration" shown in my previous post.
To be honest, I'm not sure what the "External clock pin" setting is used for, yet. I think it works either way, but my current project (3.0 based) actually has it enabled. My KDS 2.0 project had it disabled. More importantly though, in the initialization tab of the Component Inspector, did you enable QD initialization and also check the "Install interrupts" checkbox? When using MQX, you *always* have to check that box so MQX can properly handle interrupts in the driver code.
Thanks Dave, I am using KDS 3.0 with KSDK 1.2. I agree that a clocking issue does seem like a possible culprit, though I'm not able to select the "External clock pin" setting in the PEx FTM block as that pin is already defined by the clock_manager to set up "System oscillator 0" to 120 MHz from a 12 MHz external crystal.
My assumption is that this same system clock should be available to the FTM blocks by default, but it's entirely possible that this needs to be set elsewhere. I mean, we are explicitly setting the clock source with the line "FTM2_SC |= 0x08; //enable FMT with system clock)," so who knows.
When you say "pre configuration" do you mean that you are running your configuration settings before the Processor Expert init code happens? I'm currently doing it after... Will keep trying things.
I meant before the OS starts running, so I put all of the code I showed here right after PE_low_level_init(). The clocking shouldn't be the problem since, as you have said, it is explicitly set. Are you able to post your project here?
Ok, so I think I have it figured out. At least to the point where I'll be able to make some more progress. My original theory about why FMT2_CNT wasn't getting updated was correct, and it all came down to FMT2_MOD. If it's 0, the counter isn't going to increment. Although that does make sense, it would be nice to see this in a note in the reference manual because it'll probably help out some people.
But perhaps more importantly, I feel like it would have been nice to make the updating process of FMT2_MOD a little more clear. I followed the flowchart and set the registers as indicated, but could never get the register to update.
In the end, I used the following method, which was so obvious and easy, yet it took me at least two days of banging my head against the wall to realize how it could be done. And as far as I could tell, the manual doesn't offer this option in a note. It's definitely implied, but sometimes just telling the user something directly is a nice thing to do. :smileyhappy:
The solution is to simple disable FMT before setting FMTx_MOD. That's it.
Here's all you have to do:
Now you'll be able to see FMT2_CNT change when you spin the encoder.
I still have to go back through my code and determine what PEx does for me, and what I have to explicitly change myself. In addition, I need to write an ISR to handle the counter rollover conditions.
Sorry I didn't catch your query in time to be of any help! These register-order things can get mighty tricky....
If it helps, I have attached my full, current driver file. Contains a fair bit of stuff that works with my larger context, but I think the ISRs might help you. They include 'index edge capture' as well -- for my linear encoders, one-edge is sufficient.
You mention MQX -- I recommend you do NOT allow MQX to intercept this IRQ. For both the 'rollover' and 'index edge' interrupt functions, you have NO protection from 'multiple hits', of which you 'might miss some', except for 'raw speed'. I also place this interrupt at a higher priority than ANY other IRQs to insure response-time. I have the 'nagging worry' that halting right at an index or rollover step could 'bounce' at ANY rate the electronics allow, and we have a limit to how fast we can 'keep up'. To mitigate this potential A LITTLE, I preset my FTM counter (PRESUMED physical 'zero' point from power-up or 'zero' operation) at one-half of full-count.
Hi Earl, no worries, I just kept fighting through the reference manual and eventually had that revelation regarding disabling of the FTM before setting FTMx_MOD. That ended up being the easiest solution for me that actually worked.
Thank you for attaching your project. After I test my proof-of-concept code on another Kinetis part (K22 this time), I'll take a stab at using the ISR to handle rollover. I don't need the index pulse (yet), but I expect your code to be extremely helpful. And thank you for your advice regarding ISRs and the RTOS. :smileyhappy:
Dave
I would check out this (concerning the MOD register):
Writes to it are saved to an intermediate register and only transferred to the MOD register when an update trigger becomes true.
Regards
Mark
Before I left the office, I read that MOD updates depend upon CLKS, so I next will check into the MCG_C1 register to see what the value is at the time I try to update. That will determine the method in which I update MOD. There is a nice large flowchart that explains it. Sure is a lot more complicated than I would have expected. :smileyhappy:
Dave
In such cases I would expect a missing clock (as comparison: if one writes a pin to its UART MUX state but it stays at value '0' it gives the impressions that the MUX is not operating. But if the UART has a programmable clock that hasn't been set it does this - once the clock is configired/enabled/selected the pin then moves to its expected '1' level).
Another thing to look at is the compatibiity setting in the FlexTimer. The default is to work in backward compatibility mode - with TPM (which is a sub-set of FlexTimer) and the extended functions are only operational when this compatibility mode is disabled (or the advanced mode enabled).
Regards
Mark
Thanks for the suggestions, Mark. You could be right, but according to the registers I have looked at so far, everything looks right, so perhaps I missed one. To summarize what I had posted earlier (and adding a couple of other registers), this is the breakdown:
sim_scgc6 uint32_t 0x64000001 (RTC access and interrupts enabled, FTM2 clock gate control enabled, flash memory clock gate control enabled)
ftm2_mode uint32_t 0x5 (channel events occured on channel 2 & 0)
ftm2_conf uint32_t 0xc0 (BDM mode 3 - strange since PEx is set to mode 0)
ftm2_synconf uint32_t 0x1fb4 (need to read up on this, this indicates that hardware triggers are used for some reason, but I had those checkboxes unchecked in PEx)
syncmode _Bool 0x1
mcg_c1 uint8_t 0x6 (FLL uses slow internal reference clock, MCGIRCLK active)
ftm2_mod uint32_t 0x0 (this is what I *think* needs to be set to a non-zero value for ftm2_cnt to increment)
ftm2_cntin uint32_t 0x0
ftm2_qdctrl uint32_t 0xcd (phase A filter enable, phase B filter enable, count and direction encoding mode, counting direction is increasing, quadrature decoder mode enable)
ftm2_sc uint32_t 0x9 (system clock, divide by 2)