Skip to content

Instantly share code, notes, and snippets.

@pranav083
Created June 11, 2019 16:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pranav083/9b58550f5ccf293eadde907ca43eb8ba to your computer and use it in GitHub Desktop.
Save pranav083/9b58550f5ccf293eadde907ca43eb8ba to your computer and use it in GitHub Desktop.
gpio out
.origin 0
.entrypoint START
// the number of times we blink the LED
#define NUMBER_OF_BLINKS 10
// this is the address of the BBB GPIO Bank1 Register. We set bits in special locations in offsets
// here to put a GPIO high or low. It so happens that the BBB USR LED3 is tied to the 24th bit.
// Note GPIO's still have to be enabled in the PINMUX if you want to see the signal on the
// BBB P8 and P9 Headers. The USR LED3 is usually mux'ed in by default so it is a good one to
// use as an example.
#define GPIO_BANK1 0x4804c000
// set up a value that has a 1 in bit 24. We will later use this to toggle the state of LED3
#define GPIO1_LED3BIT 1<<13
// at this offset various GPIOs are associated with a bit position. Writing a 32 bit value to
// this offset enables them (sets them high) if there is a 1 in a corresponding bit. A zero
// in a bit position here is ignored - it does NOT turn the associated GPIO off.
#define GPIO_SETDATAOUT 0x194
#define GPIO_DATAOUT 0x13c
// you may think that you turn off (set low) a GPIO by writing a 0 somewhere. After all, you set it
// high with a 1 so why not set it low with a 0. That is NOT the way it works.
// We set a GPIO low by writing to this offset. In the 32 bit value we write, if a bit is 1 the
// GPIO goes low. If a bit is 0 it is ignored. Thus we can write the same value (GPIO1_LED3BIT
// in this example) to two different registers in order to turn it on and then off again.
#define GPIO_CLEARDATAOUT 0x190
// this defines a memory location inside the PRU's address space which we can use to enable
// the PRU to see the BBB's memory as if it were the PRU's memory (and other things too).
#define REGISTER_PRUCFG 0x00026000
// this label is where the code execution starts
START:
// Enable the OCP master port, this is what allows the PRU to read/write to the
// BBB's main memory (rather than the PRU's own memory). The BBB main memory
// will be mapped into the PRU address space and you can use it in the PRU as
// if it belonged to the PRU. Note that the code below will only permit the
// PRU to access BBB memory addresses above 0x0008_0000 unless you go to a bit
// of extra trouble. This is because below 0x0008_0000 you are hitting the
// PRU's own memory regions. See the PRM page 19 Section 3.1.1
MOV r3, REGISTER_PRUCFG // mov the address of the PRUs CFG register into R3
LBBO r0, r3, 4, 4 // use R3 to get the contents of the PRUCFG register into R0
CLR r0, r0, 4 // Clear bit 4. This will enable the OCP master port
// see the PRM page 272 section 10.1.2
SBBO r0, r3, 4, 4 // write the modified contents back out
MOV R2, GPIO1_LED3BIT
MOV R3, GPIO_BANK1+GPIO_DATAOUT
SBBO R2,R3, 0, 4
MOV r31.b0, 0x20|1
MOV r0, NUMBER_OF_BLINKS // this is the number of times we wish to blink
// there are three loops in this code. The outermost loop defined by the BLINK
// label executes once for each on/off cycle of the LED. L1 and L2 are half second
// delay loops
BLINK: MOV R1, 50000000 // set up for a half second delay
// perform a half second delay
L1: SUB R1, R1, 1 // subtract 1 from R1
QBNE L1, R1, 0 // is R1 == 0? if no, then goto L1
// now we turn the LED3 on
MOV R2, GPIO1_LED3BIT // reload R2 with the USR3 LEDs enable/disable bit
MOV R3, GPIO_BANK1+GPIO_SETDATAOUT // load the address to we wish to set. Note that the
// operation GPIO_BANK1+GPIO_SETDATAOUT is performed
// by the assembler at compile time and the resulting
// constant value is used. The addition is NOT done
// at runtime by the PRU!
SBBO R2, R3, 0, 4 // write the contents of R2 out to the memory address
// contained in R3. Use no offset from that address
// and copy all 4 bytes of R2
// perform a half second delay. Note the delay works because of the determinate nature
// of the execution times of PRU instructions. Instructions that do not reference data
// RAM take 5ns. We have two instructions in our loop (the SUB and the QBNE). If you do the
// math on that you find that a value of 50000000 gives you a half second delay. Of course
// we are ignoring the time taken by all the other instructions because the small amount of
// time they take does not add much error. One can conceive of applications where one might
// have to take note of such things and compensate.
MOV R1, 50000000 // set up for a half second delay
L2: SUB R1, R1, 1 // subtract 1 from R1
QBNE L2, R1, 0 // is R1 == 0? if no, then goto L2
// now we turn the LED3 off again
MOV R2, GPIO1_LED3BIT // reload R2 with the USR3 LEDs enable/disable bit
MOV R3, GPIO_BANK1+GPIO_CLEARDATAOUT// load the address we wish to write to. Note that every
// bit that is a 1 will turn off the associated GPIO
// we do NOT write a 0 to turn it off. 0's are simply ignored.
SBBO R2, R3, 0, 4 // write the contents of R2 out to the memory address
// contained in R3. Use no offset from that address
// and copy all 4 bytes of R2
// the bottom of the BLINK loop. Note that R0 contains the number of remaining blinks. It
// is UP TO YOU to remember that and not use R0 for something else in the code above. There
// is no safety net in assembler :-)
SUB R0, R0, 1
QBNE BLINK, R0, 0
// if we get here we have blinked the led as many times as we need to.
HALT // stop the PRU
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment