.syntax unified @ Use the unified syntax
.thumb @ Use the Thumb instruction set
.global leds_blink
.global delay_loop
.global leds_init
.global main
.equ rcc_reg, 0x40023800 // adresa registru RCC
.equ rcc_ahb1enr_offset, 0x30 // offset registru AHB1ENR
.equ rcc_gpiob_en, 0x0002 // bit pro povoleni hodin pro GPIOB
.equ rcc_gpioa_en, 0x0001 // bit pro povoleni hodin pro GPIOB
.equ gpio_a, 0x40020000 // adresa registru GPIOA
.equ gpio_b, 0x40020400 // adresa registru GPIOA
// .equ gpio_c, 0x40020800 // adresa registru GPIOB
.equ gpio_moder_offset, 0x00 // offset adresy registru MODER
.equ gpio_otyper_offset, 0x04 // offset adresy registru OTYPER
.equ gpio_odr_offset, 0x14 // offset adresy registru ODR
.equ gpioa_odr_init, (0 << 5) // inicializacni hodnota pro registr ODR (turn off upper 4 leds)
// Initialization values for moder, odr, otyper
.equ gpioa_moder_leds, (0x01 << (2 * 5)) | (0x01 << (2 * 6)) | (0x01 << (2 * 7))
.equ gpiob_moder_leds, (0x01 << (2 * 6))
.equ gpioa_odr_leds, (0x7 << 5)
.equ gpiob_odr_leds, (0x1 << 6)
.equ gpioa_otyper_leds, (0x3 << 6) // The first one should not be open-drain.
.equ gpiob_otyper_leds, gpiob_odr_leds
.equ gpioa_leds_count, 3 // How many leds correspond to first gpio - gpioa
.equ gpioa_leds_lsb_pos, 5 // What is the position of leds lsb in gpioa
.equ gpiob_leds_lsb_pos, 6 // What is the position of led lsb in gpiob
.equ last_led_position, (0x1 << 3) // Four LEDs total
.equ init_led_position, (0x3 << 0) // The inital value for the shift value (1 means off)
.equ mask_led_position, 0xF // The mask for all leds (4 leds total)
.equ count_1ms, 7999 // pocet opakovani na 1 ms
.equ delay, 500 // zpozdeni 500 ms
.section .data
shift_value:
.word
.section .text
.thumb_func
leds_init:
push {R0-R3};
// Enable GPIOA in RCC->AHB1ENR
ldr R0, =rcc_reg;
ldr R1, =rcc_ahb1enr_offset;
ldr R2, [R0, R1];
ldr R3, =rcc_gpioa_en;
orr R2, R3 ;
ldr R3, =rcc_gpiob_en;
orr R2, R3;
str R2, [R0, R1];
ldr R0, =gpio_a;
ldr R1, =gpio_moder_offset;
ldr R2, =gpioa_moder_leds;
ldr R3, [R0, R1] ;
orr R3, R2
str R3, [R0, R1];
ldr R0, =gpio_b;
ldr R1, =gpio_moder_offset;
ldr R2, =gpiob_moder_leds;
ldr R3, [R0, R1] ;
orr R3, R2
str R3, [R0, R1];
// Output open-drain
ldr R0, =gpio_a;
ldr R1, =gpio_otyper_offset;
ldr R2, =gpioa_otyper_leds;
str R2, [R0, R1];
ldr R0, =gpio_b;
ldr R1, =gpio_otyper_offset;
ldr R2, =gpiob_otyper_leds;
str R2, [R0, R1];
pop {R0-R3};
bx lr;
.thumb_func
shift:
push {R0-R1}
ldr R0, =shift_value
ldr R1, [R0]
// Shift right by one
lsrs R1, R1, #1
// Skip next section if no carry
bcc shift_next
// Set last bit, as one has just disappeared
ldr R0, =last_led_position
orr R1, R0
shift_next:
ldr R0, =shift_value
str R1, [R0]
bx lr
.thumb_func
write_leds:
push {R0-R4}
// GPIOA first
// Load the shift value, to R1
ldr R0, =shift_value
ldr R2, [R0] // R2 contains the shift position
// Load gpioa leds lsb position
ldr R0, =gpioa_leds_lsb_pos
// Shift the shift value to led positions
lsl R2, R2, R0
// Mask the value with gpioa_odr_leds
ldr R0, =gpioa_odr_leds
and R2, R0
ldr R0, =gpio_a
ldr R1, =gpio_odr_offset
// Store the shift value in R2.
// NOTE: Ideally, it should only set the few
// bits, but it does not matter since other
// bits are always zero in this program.
str R2, [R0, R1]
// GPIOB second
// Load the shift value, to R1
ldr R0, =shift_value
ldr R2, [R0] // R2 contains the shift position
// Shift right by number of leds in gpioa
ldr R0, =gpioa_leds_count
lsr R2, R2, R0
// Shift the shift value to led positions
ldr R0, =gpiob_leds_lsb_pos
lsl R2, R2, R0
// Mask the value with gpiob_odr_leds
ldr R0, =gpiob_odr_leds
and R2, R0
ldr R0, =gpio_b
ldr R1, =gpio_odr_offset
// Store the shift value in R2.
// NOTE: Ideally, it should only set the few
// bits, but it does not matter since other
// bits are always zero in this program.
str R2, [R0, R1]
pop {R0-R4}
bx lr
.thumb_func
delay_loop:
push {R0-R1};
ldr R1, =delay
// Load counter for 1ms delay
.thumb_func
load_1ms:
ldr R0, =count_1ms
.thumb_func
count_loop:
// Loop through the counter to 1 ms
subs R0, #1
bne count_loop
// Loop through the number of ms (delay value)
subs R1, #1
bne load_1ms
pop {R0-R1};
bx lr;
.thumb_func
main:
bl leds_init;
ldr R0, =shift_value
ldr R1, =init_led_position
str R1, [R0]
main_loop:
bl shift;
bl write_leds;
bl delay_loop;
b main_loop;