Triple Timer Counter Examples

Example functions for using the Zynq’s TTC in ARM Assembly

@ Addresses
.equ TTC0_BASE, 	0xF8001000	@ ttc0 clock control reg
.equ TTC0_CLKCTL_OFF,	0x0
.equ TTC0_CNTCTL_OFF,	0xC		@ ttc0 count 1 control
.equ TTC0_ITVL_OFF,	0x24		@ ttc0 interval 1 reg
.equ TTC0_IER_OFF,	0x60		@ ttc0 IER (interrupt enable)
.equ TTC0_ISR_OFF,	0x54		@ ttc0 ISR (interrupt status)

@ Constants used to setup timer
.equ div_mask,	0xFFFFFFE1 	@ mask to clear only bits 4:1
.equ cnt_dis_rst, 0x11		@ settings to disable and reset counter
.equ cnt_en_itvl, 0x22		@ settings to enable counter in interval mode
.equ intvl_int_en, 0x1		@ settings to enable interrupt signal so it can be read

@ configures TTC0 to use prescale and pclk
@ sets div_value to 0 (div pclk by 2)
	ldr r1, =(TTC0_BASE+TTC0_CLKCTL_OFF)	@ load address of clock control reg
	mov r0, #1
	str r0, [r1]
	bx lr

@ sets the clock divider for
@ takes r0 as 4-bit prescale value
@ sets bits 4:1 in the TTC clock control register
	ldr r2, =TTC0_BASE
	ldr r1, [r2] 		@ get current conf
	ldr r3, =div_mask	@ load mask
	and r1, r3, r1 		@ mask out div bits
	and r0, r0, #0xF	@ mask out all but 4 LSB
	lsl r0,r0, #1		@ shift left one (align div bits)
	orr r1,r0, r1		@ combine r0,r1
	str r1, [r2]		@ write new conf
	bx lr

@ NOTE: The above two code segments illustrate how individual
@ bit fields in control registers can be set without inadvertently
@ changing bits in neighboring fields. In this project, you can set
@ the seven bits in the CLK_CNTRL register to "0010011" to enable prescale,
@ set a prescale divide constant of 9, and select the positive edge of the PC
@ clock as the clock source. The code below does this in a simplified fashion.
	ldr r1, =TTC0_BASE	@ load TTC0 base register address into R1
	mov r0, #0b0010011	@ r0 <- bit settings to divide PC clock by 2^10
	str r0, [r1]		@ store bits into TTC0 base register
	bx lr

@ resets and disables TTC0 counter 1
@ the counter must be reenabled manually
	ldr r1, =(TTC0_BASE + TTC0_CNTCTL_OFF)
	mov r0, #cnt_dis_rst	@ assert reset
	str r0,[r1]		@ store constant
	bx lr

@ sets TTC0 counter 1 as enabled in interval mode
	ldr r1, =(TTC0_BASE + TTC0_CNTCTL_OFF)
	mov r0, #cnt_en_itvl	@ enable interval mode
	str r0, [r1]
	bx lr

@ takes in interval value (16-bit) as parameter
@ in r0, writes to itvl register
	ldr r1,=(TTC0_BASE+TTC0_ITVL_OFF)
	str r0, [r1]	@ store value
	bx lr

@ enables ttc0 interval interrupts
@ no parameter
	ldr r1, =(TTC0_BASE+TTC0_IER_OFF)
	mov r0, #intvl_int_en
	str r0, [r1]
	bx lr

The code above provides relevant functions to using the triple timer counter. A brief description of each function is given below.

ttc0_clk_conf configures the clock register for ttc0 counter 1. It sets it up to use the peripheral clock, as well as divide the clock value (initially by 2).

ttc0_set_div uses the parameter in r0 as the divider value. It sets the divider bits in the clock control register without touching the other configuration bits.

ttc0_reset disables the counter and resets the count value.

ttc0_en_itvl enables the counter and configures it for interval mode.

ttc0_set_itvl sets the interval for the counter, using a passed parameter in r0 (the value the counter reaches before setting the interval flag in the ISR)

ttc0_en_itvl_int enables the interval interrupt for ttc0. This will allow the flag in the ttc0 ISR to be set.

When the interval interrupt is enabled, the interval flag will set every time the counter reaches the value in the interval register. When this flag is set and then read, the flag will clear and the count will reset.