I am developing a synchronous communication application that uses an external clock signal and a shared transmit and receive line.
The external clock signal can change between 400 kHz and 12 MHz. I am using an FRDM-K64 and set to 120MHz to capture the clock signal as an external interrupt but it seems that the response speed of the K64 is slower than the clock signal.
To test it, I have an application that negates the value of a GPIO pin every time it detects a falling edge in the clock signal and a very important phase shift is seen. When the clock signal operates at 2 MHz the signal generated by the GPIO is unstable and varies between 0.3 MHz and 1 MHz, apparently it does not detect all the edges.
When the external clock signal operates at 400 kHz, the application works correctly and the change in the GPIO signal is synchronized on each falling edge of the clock signal.
I suspect the problem is in the clock setting in the FRDM-K64, the falling edge detection and the GPIO switching are slower than the external clock signal. Can you help me set the FRDM-K64 clock so that the GPIOs run at the highest possible frequency using processor expert?
I think you have a situation that is more challenging than it initially appears.
Maybe you could share your IRQ Handler and base code (please not the entire project) but I suspect that there is too much code overhead for you to be able to process the incoming data bits at higher speeds.
To explain what I mean, consider that on a 120MHz processor, a 12MHz signal has only 10 clock cycles to do the processing. A 3MHz signal has only 40 clock cycles to do the processing.
I use, as a rule of thumb, that a simple C statement with local variables in an Cortex M4 requires four clock cycles (and takes up 4 words or 12 bytes). When you are reading/writing IO registers, this at least doubles. If you are calling a method, it is at least tripled (assuming no parameters). I haven't tried to develop a model for IRQ Handler entry and return but I think it would be safe to say each would require 20 cycles or more.
So, while I can see 300-400kHz working where you have a few hundred clock cycles working between bits, your going to have issues has higher datarates.
I'm sure that you can increase your responsiveness by continuously polling the incoming clock bit but even then, at top speed, you're going to have some challenges and that seems like a waste of a K64 that you want to do more with to have it spend it's time in a polling loop.
I think the only way you're going to get full speed out of this application is to use external logic for this function to allow 8 bit (or whatever the data word size is) communication with the K64 - either put together a couple of parallel to shift registers with a counter and some logic or design a PLD for the task.
Sorry, this probably isn't the answer you were hoping for,
Hello myke, thank you very much for your answer, I really thought it was a much easier problem to solve.
According to what you say if the external clock operates at 12MHz it only has 10 clock cycles that are not enough to detect the event and move a GPIO on this board, this is the reason why cycles are lost.
In the test project what I want is to follow the external clock signal synchronously by moving a GPIO with each falling edge.
For the IRQ, I added an external interrupt and configured it to detect falling edges from the processor expert by assigning the interrupt the highest priority.
And this is the only thing I do in interruption
void E_CLK_OnInterrupt (void)
I can limit the external clock signal to not exceed 3.4MHz, that is a help although probably not enough.
Please tell me if there is any way to fix it with the FRDM-K64F?
If not, please recommend a similar low-cost development platform that can respond to the external 3.4MHz clock signal.
Thank you very much for your help
I just deleted a fairly long reply explaining what you can do to try and reduce the software overhead of the IRQ and RXTX_NegVal method. To net it out, even doing some unnatural things in your coding, you probably won't get acceptable/reliable operation at anything above 500kHz. To be honest, I don't think it's possible to handle anything approaching 3Mbps software data transfers with the i.MX RT @mjbcswitzerland suggested.
It sounds like you have some control over the operation of the communications and I'm hoping that you can send/receive data in chunks that are multiples of 8 bits. If you can, then I suggest that you use a DSPI port on the K64 with SIN and SOUT tied together (with a 1k resistor between them to minimize the chance for bus contention) with the SOUT pin output control keeping SOUT in a high impedance state until you are transmitting. I believe DSPI can run to a maximum of 15Mbps (I'm running it at 10Mbps without any issues).
Sorry I don't have a better answer,
What exactly does the content of the interrupt do?
The K64 also support DMA triggers on inputs (also on inputs that are configured as peripherals) and so can be used to copy input states to other outputs without any CPU overhead. Would that be suitable?
Otherwise an i.MX RT 1010 (used to cost $10 but now about $35) will run at 500MHz in RAM without wait states and give much increased performance, as long as you don't need the Ethernet of the K64: https://www.utasker.com/iMX/RT1010.html
[uTasker project developer for Kinetis and i.MX RT]
Contact me by personal message or on the uTasker web site to discuss professional training, solutions to problems or rapid product development requirements
For professionals searching for faster, problem-free Kinetis and i.MX RT 10xx developments the uTasker project holds the key: https://www.utasker.com/kinetis/FRDM-K64F.html
Thank you very much for your answer.
In the test application what I do in the interrupt is negate the value of a GPIO.
The production application reads a binary file from SD memory and sends it bit by bit in sync with the falling edges of the clock signal. I do the reading from the file outside of the interrupt. Within the interrupt, what I will do is set the GPIO low or high depending on the bit to send.
I do not know the i.MX RT 1010, if it can run at 500MHz it can be an interesting option. I'm going to buy one and I'm going to try it.
If the i.MX RT 1010 were not enough, is there another option that can operate at more than 500MHz?
Isn't what you need to do just to send out data in SPI slave mode?
1 - Enable SPI slave mode (SCLK on the clock input and MISO on the data out pin)
2 - Read a block from the SD card content to a RAM buffer
3 - Set up an SPI DMA transfer from the buffer to SPI
4 - Read next block from the SD card to a second RAM buffer
5 - Set up the next SPI DMA transfer from the next buffer to SPI
- repeat 2..5 until complete content sent
Like this you can achieve 25Mb/s with little CPU overhead with only one interrupt pro block no critical reaction time to be respected.
what I am doing if it is a communication but it does not operate by SPI. Communication is bidirectional and is done with two pins: an external clock pin (CLK) and a transmit and receive pin (RXTX).
What I need is to synchronize with the clock signal and be prepared to transmit or receive on the same pin (RXTX).
I initially considered the SPI option, but it would need MOSI and MISO to operate on the same pin (RXTX) without interfering. In other words, the RXTX pin must be an output and behave as MISO at the time of transmission, but that same pin must be an input and behave as MOSI at the time of reception. Any ideas how to solve this using SPI?
Thank you very much for your help
Can I ask that the first thing you do is lose the "MISO"/"MOSI" terminology and stick with the "SOUT"/"SIN" labels used on the chip. I know it was part of the original specification and continues in Arduino but it can be confusing - especially in this instance.
The simplest way of doing it is to start with the SIN pin connected directly to the controller's IO pin and then add the SOUT pin through a current limiting resistor (I would start with 1k):
That's it - when the controller is sending instructions, anything output on SOUT is overridden and when the controller is receiving data, SOUT becomes the dominant driver.
You may need to play with the resistor value depending on your controller IO drive capabilities.
Regardless, a very simple and fast way to use a single wire with an input and output pin. Easy peasy.
The SOUT pin can also be configured as open drain output. If there is a decent pull-up on the (connected) SIN line it will allow high speed bi-directional SPI - send 0xff when receiving.
As Myke has explained, the GPIOs are not capable of keeping up with the speeds that you need and using interrupts to handle such thing will be limited to very low MHz and, more practically - if the processor needs to do anything else too - to a few hundred kHz at most.
The K64 GPIOs are also not fast ones since they are on the processor bus and not connected to the core.
There are i.MX RT parts with tightly coupled GPIO capability [see https://youtu.be/nLInUIboLR0], where the difference in speed is 7 but again even here the interrupt overhead would be very high and a HW based solution is the only one that makes real engineering sense.