I am using the MQX 4.1 on a custom board derived from the TWR-K70. I need to interface to the Dallas Semiconductor iButton which requires timing resolutions down to 1uS. Therefore, I need to write a delay routine with 1uS resolutions. And these routines cannot be preempted by MQX or any other interrupts. How can I create a timing delay routine with this resolution that prevents any preemption in order to preserve these strict timing requirements of the Dallas Semiconductor iButton? Thanks.
There is a way to communicate over a 1-wire bus using Kinetis devices without blocking/disabling any interrupts (especially OS related) and have the timing completely controlled by the microcontroller peripherals such as the TPM and the DMA. Since I have no K70 setup available I tested this idea on a KL26 FRDM board and a DS1820 1-wire temperature sensor. Yet, I believe you should have no problems to port this implementation in your system.
Kinetis devices with ports without open drain control can emulate this functionality by allocating a GPIO pin with an external pull-up that will act as a 1-wire bus. This pin will have to be preconfigured to drive low level when being an output (GPO) pin. When switched to an input pin (GPI), the external pull-up will allow the slave to drive the bus level. In case no slave is there the bus would go high.
This implementation of the 1-wire bus needs a timer (TPM) with 4 channels. They will be labeled as OUT_FE, OUT_RE, IN_FE, and IN_RE corresponding to output/input falling/rising edges.
The OUT_FE channel will trigger a DMA request that will make the 1-wire bus pin output (therefore low level); similar to this the OUT_RE channel will trigger a DMA transfer that will make the 1-wire bus pin input (and with the external pull-up’s help high).
This timer stops on overflow. Effectively the software has to prepare falling and rising edge matching values for each and every bit transmitted. Once enabled timer generates 1 bit of data and stops. The match values have to be updated by software before the timer is enabled again.
To read a byte of data from the slave the master (i.e. the Kinetis micro) prepares to send all 1s (0xFF). Two additional channels in the TPM are used to record the falling and rising edges capture timing. By subtracting these two timestamps and comparing the result with the 13-15 us threshold (as per the 1-wire read spec) the code can extract slave’s data bit as 0 or 1.
The reset pulse routine used in this demo so that the master can synchronize with the 1-wire slave can’t actually detect slave’s presence pulse. It is there just to generate a 480 us negative pulse and complete the whole process in 960 us. It is up to the application to perform a full-blown CRC check on the slave data and eliminate situations when there is no slave present.
This demo feeds a 48 MHz into the TPM. It is important to make sure the TPM does not overflow for 1 ms (i.e. the reset/presence pulse routine) so the TPM prescaler should be used accordingly. In my case I set the prescaler to divide by 2 so a count of 21 did match timer running for 1 us.
Ideally the OUT_FE and OUT_RE related DMA channels should have the highest priority in the system so that the output waveform would be as similar to the ideal as possible.
On the input end you get the best results if both the IN_FE and IN_RE TPM channel pins are used (they must be connected to the 1-wire bus). If only one capture pin is available in your system, it will be used as the IN_RE. In such case when extracting the slave bit data your code should subtract the OUT_FE match value from the IN_RE captured timestamp to extract the slave data bit content.
The important thing about this implementation is that while it is software driven (since it is the software that makes the timer run for one period) the waveform timing is fully controlled by the timer hardware – there is no need for disabling (any) interrupts. Between two bit transmissions the bus is kept in the idle state (the 1-wire pin is configured as input) so it can stay there indefinitely. This can help an OS based application visit the 1-wire routine when possible and drive the write and read process in a way not affecting the other tasks.
Let me know if I can provide more info.
P.S. here is the test scope screenshot
You can call __disable_interrupt() then start a timer for 1uS and then call __enable_interrupt().
You can find an example showing how to get 1uS interrupts with a PIT in MQX4.1.