DrPinball
Posts: 57
Joined: Fri May 04, 2012 6:44 pm

Using GPIO Clocks

Fri Sep 21, 2012 10:35 am

Hi

I wanted to try and get a 1MHz clock out of the GPIOs so started looking at using the GPIO Clocks - see section 6.3 of the BCM2835 Peripherals doc.

I'm not having much luck getting it going and wondered if anyone else had tried.

I'm trying to set GPIO 4 to ALT0 function which should be GPCLK0. I'm then writing to the CM_GP0CTL and CM_GP0DIV registers to set it up.

Code is as follows:

Code: Select all

.section .init
.globl _start
_start:

b main

.section .text

/*---------------------*/
/* Function: heartbeat */
/*---------------------*/
heartbeat:

/* Store the return address */
push {lr}

/* Flash GPIO 16 */
mov r0, #16
mov r1, #0
bl SetGpio

ldr r0, =125000
bl Wait

mov r0, #16
mov r1, #1
bl SetGpio

ldr r0, =500000
bl Wait

/* Return */
pop {pc}

/*----------------*/
/* Function: main */
/*----------------*/
main:

/*
* Set the stack point to 0x8000.
*/
mov sp,#0x8000

/* Setup GPIO 16 as output for debug purposes */
mov r0, #16
mov r1, #1
bl SetGpioFunction

/* Setup GPIO 4 as ALT0 function i.e. GPCLK0 */
mov r0, #4
mov r1, #4 /* ALT0 */
bl SetGpioFunction

/* Get the clock base address */
ldr r1, =0x02101070

/* Set the clock register */
/* PASSWD	- 5A */
/* MASH		- 0 (Integer division) */
/* SRC		- 6 (PLLD per) */
ldr r0, =0x5A000006
str r0, [r1, #0x00]

/* Set the clock divider - 200Mhz PLL divided by 200 = 1MHz */
ldr r0, =0x5A0C8000
str r0, [r1, #0x04]

/* Enable the clock */
/* PASSWD	- 5A 		*/
/* MASH		- 0 (Integer division) */
/* ENAB		- 1 		*/
/* SRC		- 6 (PLLD per) 	*/
ldr r0, =0x5A000016
str r0, [r1, #0x00]

Loop$:

/* Flash 'OK' */
bl heartbeat

b Loop$
The above code uses the gpio.s and systemTimer.s modules from BakingPi lesson 5.

I'm using a logic analyser to check the output of GPIO 4 but nothing is coming out.

Any ideas? Many thanks, David.

Z3r0
Posts: 23
Joined: Wed Sep 05, 2012 7:42 pm

Re: Using GPIO Clocks

Sat Sep 22, 2012 9:14 am

When i was playing with gpio clocks i was able to get it working only with oscillator source, none of PLL was working for me (1 = oscillator) also test first without any dividers, i was able to get only around 2Mhz in my early tests from gpio clock with oscillator source.

also look into https://github.com/raspberrypi/firmware ... -interface
There are several clocks configurable via mailbox messages and for instance pwm clock is not active by default, could be same with PLL's

DrPinball
Posts: 57
Joined: Fri May 04, 2012 6:44 pm

Re: Using GPIO Clocks

Sat Sep 22, 2012 3:43 pm

Thanks, I'll give it a try and report back.

DrPinball
Posts: 57
Joined: Fri May 04, 2012 6:44 pm

Re: Using GPIO Clocks

Mon Sep 24, 2012 1:44 pm

Okay, I got a clock going on GPIO 4, however...

Only Clock Source = 1 and 6 seem to work and I needed to set a divisor - leaving at all zeros was no good. Code is as follows:

Code: Select all

.section .init
.globl _start
_start:

b main

.section .text

/*----------------*/
/* Function: main */
/*----------------*/
main:

/*
* Set the stack point to 0x8000.
*/
mov sp,#0x8000

/* Setup GPIO 16 as output for debug purposes */
mov r0, #16
mov r1, #1
bl SetGpioFunction

/* Setup GPIO 4 as ALT0 function i.e. GPCLK0 */
mov r0, #4
mov r1, #4
bl SetGpioFunction

/* Set the clock divider */
/* PASSWD 	- 5A  */
/* DIVI		- 016 */
/* DIVF		- 000 */
ldr r0, =0x5A016000
ldr r1, =0x20101070
str r0, [r1, #0x04]

/* Set the clock register */
/* PASSWD	- 5A */
/* MASH		- 0 (Integer division) */
/* SRC		- 1 (Oscillator) */
ldr r0, =0x5A000001
ldr r1, =0x20101070
str r0, [r1, #0x00]

/* Enable the clock */
/* PASSWD	- 5A */
/* MASH		- 0 (Integer division) */
/* ENAB		- 1 (Start) */
/* SRC		- 1 (Oscillator) */
ldr r0, =0x5A000011
ldr r1, =0x20101070
str r0, [r1, #0x00]

Loop$:

b Loop$
This may be of use if you can also set an interrupt on the GPIO line and then set the other GPIOs in tandem to create a useful communication with an external device.
The actual frequency didn't seem to stable i.e. I got 1MHz and then 850KHz with the same code!

DrPinball
Posts: 57
Joined: Fri May 04, 2012 6:44 pm

Re: Using GPIO Clocks

Mon Sep 24, 2012 2:11 pm

Sorry, to get 1MHz you need to have a DIVI of 0x14 not 0x16 as I put in the code, so the following is correct:

Code: Select all

/* Set the clock divider */
/* PASSWD 	- 5A  */
/* DIVI		- 014 */
/* DIVF		- 000 */
ldr r0, =0x5A014000
ldr r1, =0x20101070
str r0, [r1, #0x04]

guzunty
Posts: 276
Joined: Mon Jan 14, 2013 10:13 am

Re: Using GPIO Clocks

Mon Jan 14, 2013 10:28 am

Here is some C to do a similar job:

https://github.com/Guzunty/Pi/blob/mast ... c/gz_clk.c
Guzunty: A fully programmable peripheral you build yourself! https://github.com/Guzunty/Pi/wiki

krydab
Posts: 19
Joined: Fri Jan 04, 2013 8:33 pm

Re: Using GPIO Clocks

Tue Jan 15, 2013 11:57 am

I've checked the C code using clock. It's working correctly, but I really don't know why. I thought, according to the datasheet of BCM2835 peripherals (pages 107, 108), you should add 0x70 instead of 0x1C and 0x74 instead of 0x1D. Can you explain me how do you know it? Also assembly code in that topic, as I understand, order to write on register 0x20101074 value 0x5A016000 etc. I did it my way but it wasn't working, but your code works perfectly.

guzunty
Posts: 276
Joined: Mon Jan 14, 2013 10:13 am

Re: Using GPIO Clocks

Tue Jan 15, 2013 9:21 pm

Hi krydab,

So glad you found my code useful :-)

I'll look it over and try to remember the process I followed when making it.

From memory, I can say:
- I did not follow the assembler above when creating the 'C' code, I have no reason to believe it's wrong, I just based mine on other fragments of code I had already seen elsewhere before seeing this thread (plus what was in the micro controller user guide). Message to Broadcom: The manual could be a lot better. The content is fine, but I found there were no indexes or sections built into the pdf which makes navigating it more difficult than it needs to be.
- I did have to persevere through some trial and error, but I have found this to be the case with other micro controllers in the past.
- I did not at any time encounter any issues with the busy bit not being set as reported in some other forum posts. This may have contributed to the trouble you were having, since I think it is quite important to wait on it.
- As posted by Dr. Pinball above, only two of the possible clock sources seem to work (sources 1 and 6).

I will review the code and revisit the manual and then I'll try to address your other questions regarding the offsets I used. It may be that some examples are using a memory mapped image of the registers and I am not (or vice versa).
Guzunty: A fully programmable peripheral you build yourself! https://github.com/Guzunty/Pi/wiki

guzunty
Posts: 276
Joined: Mon Jan 14, 2013 10:13 am

Re: Using GPIO Clocks

Tue Jan 15, 2013 10:21 pm

Q: What do you get if you multiply 0x1C by 4?
A: 0x70

and that is the explanation.

bcm2385_clk is defined as a uint32_t, which is 4 bytes, so the offset needs to be 0x1C (for 0x70 bytes) and 0x1D (0x74 bytes) respectively.

hth

best,

G.
Guzunty: A fully programmable peripheral you build yourself! https://github.com/Guzunty/Pi/wiki

krydab
Posts: 19
Joined: Fri Jan 04, 2013 8:33 pm

Re: Using GPIO Clocks

Wed Jan 16, 2013 4:17 pm

Ok, I got it. It's based on pointer's arithmetic. Thank you for explanation.

AndyPi
Posts: 83
Joined: Wed Feb 22, 2012 10:24 pm
Location: Gloucestershire,UK

Re: Using GPIO Clocks

Fri Feb 08, 2013 3:42 pm

I am puzzled by the general purpose clock dividers. The documentation arm2835 peripherals section 6.3 indicates that the fractional part of the clock divider is a 12 bit value ie bits (11-0) in CM_GP0DIV, but that the specified fractions denominator is 1024 ie 10 bit value.


It seems by inspecting the code that in order to get a frequency of 103.3 MHz from the PLLD clock (@500MHz) we need a divider of 4.8403. According to the documentation example we need to set the integer divider to 4 and the fractional divider to int(0.84*1024) = 860. and so the command should read 0x5A00435C ie DIVI = 0x004 DIVF = 0x35C.

What the code seems to use is 5A 004 D72. Which if the documentation is correct and only bits 9-0 are used would result in a divider of 4.361 which would give a frequency of 114.65 MHz. BUT it doesn't it produces 103.3 MHz.

This only makes sense if the DIVF is denominated by 4096 and not 1024.

Is this correct and the documentation hopelessly wrong, or is my analysis just wrong ?

help required

regards

Andy

Return to “Bare metal, Assembly language”