Delays on PIC32MZ post

How to make millisecond and microsecond delays

Ever wanted to make an LED toggle on and off every second? It's the dream of every hobbyist, especially when we're dealing with the PIC32MZ. A sign of success, that things are working and clock speeds are right. Unfortunately, the XC32 compiler doesn't give us a delay function to call. A quick google of "PIC32 millisecond timer" brings back countless results relating to other PIC devices, not PIC32, and people saying we should be using Harmony. There are also plenty of results relating to using the Timer peripherals and the calculations look complex and really aren't what we want for this simple task. Oh, and "read the data sheet" of course.

Instead, let's do it the easy way. There's a built-in timer in every PIC32 called the Core Timer. It doesn't need to be set up and it is always running. It runs at half the system frequency, so if you're running at 200Mhz, it'll update at 100Mhz. First, let's add a define for how fast we've set the fuses to.

#define SYS_FREQ 200000000 // Running at 200MHz

This value will be useful for many calculations we'll need to do later. OK, so now how do we use the Core Timer? Well, first we need to calculate how long we need to wait.

<TL;DR>

In our example, the core timer updates at 100Mhz. Let's say we want to wait for 500 microseconds. First, let's calculate how many clock ticks that is. One clock tick takes 1 / 100,000,000 seconds, which is 0.000001 seconds, which is 0.01 microseconds. So this means that for every 100 clock ticks 1 microsecond has passed. So, for 500 microseconds we need to wait 500 * 100 = 50,000 clock ticks.

</TL;DR>

Still with me? Good :) Let's put that knowledge to use and make a microsecond delay function:

void delay_us(unsigned int us)
{
    // Convert microseconds us into how many clock ticks it will take
    us *= SYS_FREQ / 1000000 / 2; // Core Timer updates every 2 ticks

    _CP0_SET_COUNT(0); // Set Core Timer count to 0

    while (us > _CP0_GET_COUNT()); // Wait until Core Timer count reaches the number we calculated earlier
}

First we calculate how many clock ticks we need to wait. Then we set the Core Timer counter to 0 by calling

CP0_SET_COUNT(0)

<TL;DR>

CP0_SET_COUNT(value) is a built-in way to set the Core Timer's value. For the fancy pantses among us, yes, you can use:

_mtc0(9, 0, 0); // Register 9 is the Count register, set it to 0

But it comes down to the same thing, so take your pick.

</TL;DR>

Then we just need to wait until the Core Timer counter reaches the value we set and the delay will be done. Simple! Let's use that to make a millisecond delay now.

void delay_ms(int ms)
{
    delay_us(ms * 1000);
}

Is that cheating? Maybe? Off by a few clock cycles? Probably. As the audience for this blog is going to be tiny (or non-existent) anyway I don't think it matters :) Oh, one more thing. The Core Timer is a 32-bit number, which means it can only count to 4 billion before it'll wrap back around to 0. So don't use delay_ms() for hundreds of seconds. At least up to 20 seconds should be fine. Now let's make that LED dance!

while (1)
{
    LATAINV = 1 << 0; // Toggle LAT A bit 0
    delay_ms(1000); // Delay 1 second
}

LATAINV is an easy way to toggle bits on Port A and requires no work on our part. Hope the TL;DR tags help :)

Here's the code

Categories: pic32

Tags: code