Sat
Mar 14

ci20: Enabling the timer

This is part 4 of an ongoing series (part 1part 2part 3) about writing bare-metal code for the CI20 Creator. The last post talked about the RAM available to the CI20: 1 gigabyte of DDR, which requires initialisation, and 16 kilobytes of SRAM, which can be used by a bootloader to initialise the DDR.

Before we get to DDR, we need to give the bootloader some way to keep track of time intervals. The proximate requirement is the DDR controller requires a 200 microsecond delay, and without a timer of some sort we have no way of knowing how long that is — but timers are generally useful things to have around in any case. The JZ4780 CPU has lots of timers available to it, so the simplest thing to do is just to enable one of them.

You can check out the repository for this code:

$ git clone https://github.com/nfd/ci20-os
$ cd ci20-os
$ git checkout tags/ostimer

There are a few changes from last time, but the only really functionally relevant one is that there are two new files, timer.c and timer.h, which set up the “OS Timer” in the JZ4780 SOC. Initialisation of this timer is very straightforward, as can be seen in os_timer_init():
  • Set the frequency of count, which is some fraction of one of the available clocks — we use the 48MHz EXTCLK which doesn’t require any additional set-up, and then divide it by 16 to give us a timer which increments 3 million times a second.
  • Clear the counter value (not required, just neat);
  • Set the clock source (EXTCLK); and
  • Start the timer running.
Compile and run the code as before:

$ make bootloader.bin
$ python3 usbloader.py bootloader.bin

And you should see a message printed to the serial port once a second.

This timer isn’t using any interrupts, because we haven’t yet written any way to handle them. This means that the delay function, usleep(), simply polls the timer register in a tight loop. This is of course very bad practise generally, but it’s just about okay for run-at-boot initialisation code and short time intervals.