Turning on an LED using Assembly on raspbianOS (Raspberry Pi 3 Model B)

59 Views Asked by At

I'm trying to light an LED connected to GPIO pin 12 using Assembly, I have a coursework where I have to implement the game of MasterMind using C and Assembly, so I've been trying to light up an LED using Assembly

.section .init
.globl _start
_start:
ldr r0,=0x3F200000 // Base adress from GPIO
 
// Set the GPIO pin 12 as output
mov r1,#1
lsl r1,#6
str r1,[r0,#0x4] // 0x3F200004 is the GPSEL1 Register, where you can choose the function for the pin
 
// Prepare the number used for turning the LED off and on
mov r1,#1
lsl r1,#12
 
// Main loop, loops all the letters (bl means branch with saving the current physical adress in the link register (lr) so you can jump back to it)
loop$:
 bl morseS
 bl morseO
 bl morseS
b loop$
 
morseS:
 mov r6,lr // Move the lr adress to r6 so you dont override it (would be better if implemented with stack)
 bl dotBlink
 bl dotBlink
 bl dotBlink
 bl delayMedium
 mov lr,r6 // Move the adress back into the link register
 bx lr
 
morseO:
 mov r6,lr
 bl dashBlink
 bl dashBlink
 bl dashBlink
 bl delayMedium
 mov lr,r6
 bx lr
 
dotBlink:
 mov r7,lr
 str r1,[r0,#0x1C] // This turns the led on (According to the BCM2835 documentation the Register found at 0x3F20001C is GPSET0, so you can turn on the GPIO Pin 12 there
 bl delayShort
 str r1,[r0,#0x28] // This is GPCLR0, so used for turning the pin off again
 bl delayShort
 mov lr,r7
 bx lr
 
dashBlink:
 mov r7,lr
 str r1,[r0,#0x1C]
 bl delayLong
 str r1,[r0,#0x28]
 bl delayShort
 mov lr,r7
 bx lr
 
delayShort: 
 ldr r4,=0x3f003004 // Address for the timer of the Raspberry Pi
 ldr r4,[r4] // Load the value from the timer
 ldr r5,=0x30D40 // 200'000 micro seconds in hexadecimal
 delayLoop1$:
  ldr r3,=0x3F003004 
  ldr r3,[r3] // Load new timer value
  sub r3,r3,r4 // Save time passed since the beginning of subroutine in r3
  cmp r3,r5 // Compare 
  blt delayLoop1$ // If difference is smaller than 200ms go to the delay loop again
 bx lr // If time has passed return from function
 
delayMedium:
 ldr r4,=0x3f003004
 ldr r4,[r4]
 ldr r5,=0x61A80
 delayLoop3$:
  ldr r3,=0x3F003004
  ldr r3,[r3]
  sub r3,r3,r4
  cmp r3,r5
  blt delayLoop3$
 bx lr
 
delayLong:
 ldr r4,=0x3f003004
 ldr r4,[r4]
 ldr r5,=0x927C0
 delayLoop2$:
  ldr r3,=0x3F003004
  ldr r3,[r3]
  sub r3,r3,r4
  cmp r3,r5
  blt delayLoop2$
 bx lr

This is the code I have, I think it seems fine and I tried compiling it using

as -o testled.o testled.s
ld -o testled testled.o
sudo ./testled

and it gives a segmentation error, can someone please help me with this?

1

There are 1 best solutions below

5
Timothy Baldwin On

This program is written to run without an operating system with direct access to physical address space but you are running it on Linux which configures virtual memory.

Under Linux the physical address is in the file /dev/mem, and specifically the gpio registers are also in /dev/gpiomem. To use these files open them then you can obtain a virtual address using the mmap system call.

For example in C:

fd = open("/dev/mem", O_SYNC | O_RDWR)
gpiobase = mmap(0, 4096 PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0x3F200000);

However I would expect attempting to access the timer like that will result in chaos as the operating system will be using the timer.

Linux also provides a high level interface to the gpio using files in /sys/class/gpio.