viiv
Posts: 4
Joined: Thu Sep 13, 2012 7:23 pm

need help using timer

Thu Sep 13, 2012 7:47 pm

I am not sure where I am going wrong, or how to debug it, but it is not doing what I want (or anything?). I'm just trying to make a function that waits a specific amount of time

Code: Select all

#r0 is user delay input
.globl delay

delay:
input .req r0
systemTimer .req r1

ldr systemTimer,=0x7E003000

#load current counter time, offset by 0x4
ldr r4,[systemTimer,#0x4]
ldrd r2,r3,[r4]

#offset current time capture by user requested delay
add r2,input

#store time in timer0 comparison register, offset by 0xC
ldr r4,[systemTimer,#0xC]
str r2,[r4]

#check control register for hit at bit 0
timerLoop:
ldr r4,[systemTimer]
and r4,r4,#1
bne timerLoop

#clear control reg
push {r5}
ldr r5,=0
str r5,[systemTimer]
pop {r5}

.unreq input
.unreq systemTimer

#return
mov pc,lr

BrianW
Posts: 83
Joined: Sun Jul 29, 2012 9:03 pm

Re: need help using timer

Thu Sep 13, 2012 10:27 pm

viiv wrote:

Code: Select all

#check control register for hit at bit 0
timerLoop:
ldr r4,[systemTimer]
and r4,r4,#1
bne timerLoop
Hi,

The "and" will need to be "ands" (ie, AND and update the processor flags) as you want to act on the result of it.

This could be why your code isn't working - if the Z flag is already set at the start of the routine, the CPU will run straight through timerLoop. If not, it'll loop endlessly.

viiv
Posts: 4
Joined: Thu Sep 13, 2012 7:23 pm

Re: need help using timer

Fri Sep 14, 2012 1:56 am

thanks! Now I don't get how the timer can only be compared with 32 bits. My loop seems to take minutes what should take seconds (guessing I have to wait for it to loop around)

badut
Posts: 20
Joined: Tue Sep 11, 2012 12:49 pm

Re: need help using timer

Fri Sep 14, 2012 5:39 am

There's a good example of how to implement a "wait" function in OK04 of the Baking Pi tutorials.
See this thread: http://www.raspberrypi.org/phpBB3/viewt ... 72&t=17057
Alex's wait function is listed in the first post on that thread.
I've thrown in my own version of a wait function in the last post.
Both work ok for me.

dmj
Posts: 2
Joined: Thu Mar 29, 2012 9:23 pm

Re: need help using timer

Fri Sep 14, 2012 9:46 am

viiv wrote:I am not sure where I am going wrong, or how to debug it, but it is not doing what I want (or anything?). I'm just trying to make a function that waits a specific amount of time

Code: Select all

#r0 is user delay input
.globl delay

delay:
input .req r0
systemTimer .req r1

ldr systemTimer,=0x7E003000

#load current counter time, offset by 0x4
ldr r4,[systemTimer,#0x4]
ldrd r2,r3,[r4]

#offset current time capture by user requested delay
add r2,input

#store time in timer0 comparison register, offset by 0xC
ldr r4,[systemTimer,#0xC]
str r2,[r4]

#check control register for hit at bit 0
timerLoop:
ldr r4,[systemTimer]
and r4,r4,#1
bne timerLoop

#clear control reg
push {r5}
ldr r5,=0
str r5,[systemTimer]
pop {r5}

.unreq input
.unreq systemTimer

#return
mov pc,lr
I note that you are using 0x7E003000 as the base address for the timer. Although I haven't used it myself, reading of other posts (dwelch67 et al) suggests that the GPIO addresses in ARM I/O space commence at 0x20000000 and not 0x7E000000 which is apparently in GPU I/O space. So your timer base address should be 0x20003000.

viiv
Posts: 4
Joined: Thu Sep 13, 2012 7:23 pm

Re: need help using timer

Sat Sep 15, 2012 2:55 pm

dmj wrote: I note that you are using 0x7E003000 as the base address for the timer. Although I haven't used it myself, reading of other posts (dwelch67 et al) suggests that the GPIO addresses in ARM I/O space commence at 0x20000000 and not 0x7E000000 which is apparently in GPU I/O space. So your timer base address should be 0x20003000.
yeah, I had fixed that, but since I can't edit the OP I just left it.

I've been reading the ARM Instruction Set notes, and fixed up some parts of my code. But without being able to step through my code and see whats going on in the registers its really hard to figure out what is going wrong. I'm flying blind! :cry:

Maybe I can assume that the control register does flip the bit, but only for the interrupt controller. And after the interrupt controller reads it, the bit resets, so by the time I read it its clear again? (although interrupts are/should be disabled on reset...)

badut wrote:There's a good example of how to implement a "wait" function in OK04 of the Baking Pi tutorials.
Yeah, thats what I was working on before I jumped into this rabbit hole. So much for going on to lesson 5, I'm too deep now... :lol:

dwelch67
Posts: 1004
Joined: Sat May 26, 2012 5:32 pm

Re: need help using timer

Sat Sep 15, 2012 3:34 pm

This code jumped out at me as confusing:

Code: Select all

systemTimer .req r1

ldr systemTimer,=0x20003000

#load current counter time, offset by 0x4
ldr r4,[systemTimer,#0x4]
ldrd r2,r3,[r4]
First off the interesting/strange syntax for ldrd. But then more investigation. I changed the 0x7e to 0x20 btw.

Looking at what is generated:

Code: Select all

00000000 <.text>:
   0:	e59f1004 	ldr	r1, [pc, #4]	; c <.text+0xc>
   4:	e5914004 	ldr	r4, [r1, #4]
   8:	e1c420d0 	ldrd	r2, [r4]
   c:	20003000 	andcs	r3, r0, r0
so loading r1=0x20003000 is fine, no problems there.

the next instruction ldr r4,[r1,#4] what this is is r4 = memory[0x20003004], so r4 now contains the
lower 32 bits of the free running counter.

So now you are using the counter as an address into memory. That can be dangerous, unaligned accesses, etc.

I didnt know you could use syntax like that either, you have to use an even/odd with the odd register being even+1, so you really only need to specify one register. I can see the two register thing as a mental reminder that two registers are modified.

I am thinking that this is closer to what you were wanting

Code: Select all

ldr r1,=0x20003000
ldrd r2,[r1,#4]
And what that does is

Code: Select all

r1 = 0x20003000
r3:r2 = memory[r1+0x04] = memory[0x20003004]
The theme has been repeated

Code: Select all

#store time in timer0 comparison register, offset by 0xC
ldr r4,[systemTimer,#0xC]
str r2,[r4]
Correct me if I am wrong, but I think what you want is this:

Code: Select all

#store time in timer0 comparison register, offset by 0xC
str r2,[systemTimer,#0xC]
Now I dont think the ldrd r2,[r1,#4] is going to do what I assume you are trying to do, an atomic read of two separate peripheral registers. Even on a 64 AXI bus this should result in two separate bus transfers. Even if it had been a 64 bit aligned pair of registers and if it is a 64 bit AXI bus you would see a single AXI transfer, but that doesnt mean the peripheral hardware is going to implement the read of those two registers in an atomic manner. If it were a single AXI transfer the peripheral simply has to return all the data when it completes the transfer it can take as many cycles as it wants to return that data.

Sometimes you see 64 bit timers split like this that when reading one of the registers the other latches until you read it, allowing you to take your time to read the two. You just have to read them in the right order. Please help me but I dont see the documentation indicating that.

This appears worthy of a research project. Looking at more of your code I dont see that you are using r3, so not sure why the ldrd is used when ldr will satisfy what you are trying to do.

Another way you could have implemented your code, but with the arm instruction set there is no need to is:

Code: Select all

#store time in timer0 comparison register, offset by 0xC
add r4,systemTimer,#0xC
str r2,[r4]
The ldr/str instructions allow for somewhere around 8 to 12 bits of immediate offset to be added to the base, I would have to go to the arm docs to confirm how much. Certainly for this timer where you only need to offset from 0x00 to 0x18 you only need to set the base address and use [base,#imm_offset] addressing to reach any of the registers.

David

viiv
Posts: 4
Joined: Thu Sep 13, 2012 7:23 pm

Re: need help using timer

Sat Sep 15, 2012 4:05 pm

thanks for the reply.

Yeah, I had removed ldrd. I had copied that from the "Baking Pi" tutorial, but realized I just needed the lower 32.

And omg I am an idiot. My loop needed a branch if zero is set not cleared!!!! SMH!!!

final working code for reference:

Code: Select all

#r0 is user delay input
.globl delay

delay:
input .req r0
systemTimer .req r1

ldr systemTimer,=0x20003000

#load current lower 32-bit counter time, offset by 0x4
ldr r2,[systemTimer,#0x4]

#add to current time capture the user requested delay
add r2,r2,input

#store time in timer0 comparison register, offset by 0xC
str r2,[systemTimer,#0xC]

#clear control reg
ldr r3,[systemTimer]
orr r3,r4,#0xF
str r3,[systemTimer]

#check control register for hit at bit 0
timerLoop:
ldr r3,[systemTimer]
ands r3,r3,#1
beq timerLoop

.unreq input
.unreq systemTimer

#return
mov pc,lr
**walks away in shame** :oops:

Return to “Bare metal, Assembly language”