Understanding of arm bare metal lighting led volatile

1. Initialization process

Initialize clock

Set the multiplexed IO port of GPIO

Set the electrical properties of GPIO

Initialize GPIO

2. Understanding volatile initialization registers in C language

#define CCM_CCGR0 *((volatile unsigned int *)0x020C4068)

Understanding of volatile

The volatile keyword has the following uses:

(1) Used for synchronization, because the same thing may have multiple copies in different storage media. In some cases

In this case, the values in these copies will be different, which is not allowed, so simply use volatile to make it only

There is one copy and no other copies, so no out-of-sync problems will occur.

(2) Prevent the compiler from optimizing and removing certain statements. For example, I saw a register in arm that was very strange.

When an interrupt comes, the corresponding position is 1, and you cannot clear 0 by writing 0 to this bit. Writing 1 to this bit is 1.

Yes clear interrupt (clear to 0)

// Assume 0x560012300 is the register address
#define INTPAND *(volatile unsigned int *)0x560012300

INTPAND = INTPAND; // clear interrupt

If the compiler sees INTPAND = INTPAND; this seemingly useless operation, if not

volatile means that the compiler will most likely remove INTPAND = INTPAND; which is actually useful.

West, but was optimized away by the compiler as useless.

(3) When the address is an io port, reading and writing this address cannot cache it. This is relatively

This is only available if there is cache in some embedded systems. For example, when writing this io port, if there is no such

Volatile, probably due to compiler optimization, will first write the value to a buffer. At a certain time,

Then write to the io port, so that the data cannot be written to the io port in time. With the volatile description,

It will no longer go through cache and write buffer, but will write directly to the io port, thereby avoiding reading and writing

Latency of io port. What is Cache? – Zhihu (zhihu.com)

3. C language version LED process

1. Write the startup file start.s

.global_start
 
 _start:
      @ Set the processor to enter SVC mode
      mrs r0, cpsr //Read cpsr to r0
      bic r0, r0, #0x1f //BIC Rd, Rn, #immed Rd = Rn & amp; (~#immed) 0x1f 1 1111
      orr r0, r0, #0x13 //Use SVC mode ORR Rd, Rn, #immed Rd = Rn | #immed 0x13 1 0011
      msr cpsr, r0 //Write r0 to cpsr

     @ Set sp pointer
     ldr sp, = 0x80200000
     b main //Jump to c language to main function

2.Write the main.h file

#ifndef _MAIN_H
#define _MAIN_H

//All clock register addresses
#define CCM_CCGR0 *((volatile unsigned int *)0x020C4068)
#define CCM_CCGR1 *((volatile unsigned int *)0x020C406C)
#define CCM_CCGR2 *((volatile unsigned int *)0x020C4070)
#define CCM_CCGR3 *((volatile unsigned int *)0x020C4074)
#define CCM_CCGR4 *((volatile unsigned int *)0x020C4078)
#define CCM_CCGR5 *((volatile unsigned int *)0x020C407C)
#define CCM_CCGR6 *((volatile unsigned int *)0x020C4080)


//Set the multiplexed IO port address
#define SW_MUX_GPIO1_IO03 *((volatile unsigned int *)0x020E0068)
#define SW_PAD_GPIO1_IO03 *((volatile unsigned int *)0x020E02F4)

//GPIO related register address
#define GPIO1_DR *((volatile unsigned int *)0x0209C000)
#define GPIO1_GDIR *((volatile unsigned int *)0x0209C004)
#define GPIO1_PSR *((volatile unsigned int *)0x0209C008)
#define GPIO1_ICR1 *((volatile unsigned int *)0x0209C00C)
#define GPIO1_ICR2 *((volatile unsigned int *)0x0209C00C)
#define GPIO1_IMR *((volatile unsigned int *)0x0209C00C)
#define GPIO1_ISR *((volatile unsigned int *)0x0209C00C)
#define GPIO1_EDGE_SEL *((volatile unsigned int *)0x0209C00C)


#endif // !_MAIN_H

3. Write the main.c file

#include "main.h"

// Enable peripheral clock
void clk_enable(void)
{
    CCM_CCGR0 = 0xFFFFFFFF;
    CCM_CCGR1 = 0xFFFFFFFF;
    CCM_CCGR2 = 0xFFFFFFFF;
    CCM_CCGR3 = 0xFFFFFFFF;
    CCM_CCGR4 = 0xFFFFFFFF;
    CCM_CCGR5 = 0xFFFFFFFF;
    CCM_CCGR6 = 0xFFFFFFFF;
}

//Initialize LED
void led_init(void)
{
    //Reuse IO port
    SW_MUX_GPIO1_IO03 = 0x5;
    //Set the electrical properties of the IO port
    SW_PAD_GPIO1_IO03 = 0x10B0;


    //GPIO initialization
    GPIO1_GDIR = 0x08; //Set as output
    GPIO1_DR = 0x0; //Set to turn on the light
    
}
// short delay
void delay_short(volatile unsigned int n)
{
    while(n--){}
}

// One time is about 1ms, main frequency is 396MHZ
// n represents the delay time
void delay(volatile unsigned int n)
{
    while(n--)
    {
        delay_short(0x7FF);
    }
}

// turn on led
void led_on(void)
{
    GPIO1_DR & amp;= ~(1<<3); // clear bit3 to 0 1000 inverse 0111
}
// turn off led
void led_off(void)
{
    GPIO1_DR |= (1<<3); // clear bit3 to 0 1000 inverse 0111
}

int main(void)
{
    // enable clock
    clk_enable();
    //Initialize led
    led_init();

    while (1)
    {
        led_on();
        delay(500);

        led_off();
        delay(500);
    }
    return 0;
    //Initialize led
    // flash led light
}

4.Write makefile

makefile

# Dependency files are placed in front, linked and compiled in front, start.o is placed in front of main.o
# You can view the compiled execution sequence in the disassembly .s file
objs = start.o main.o


led.bin : $(objs)
arm-linux-gnueabihf-ld -Ttext 0x87800000 $^ -o led.elf
arm-linux-gnueabihf-objcopy -O binary -S led.elf $@
arm-linux-gnueabihf-objdump -D -m arm led.elf > led.dis

# -Wall means to display all warnings during compilation
# nostdlib means not linking system standard startup files and library files
# -O indicates optimization level

%.o : %.c
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o $@ $<

%.o : %.S
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o $@ $<

clean:
rm -rf *.o led.bin led.elf led.dis


The above does not use the link file

arm-linux-gnueabihf-ld -Ttext 0x87800000 $^ -o led.elf

-Ttext 0x87800000 specifies the first link address

Use the link file as follows

SECTIONS{
. = 0X87800000;
.text:
{
start.o
main.o
*(.text)
}
    .rodata ALIGN(4) : {*(.rodata*)}
    .data ALIGN(4) : { *(.data) }
__bss_start = .;
.bss ALIGN(4) : { *(.bss) *(COMMON) }
__bss_end = .;
}

The compilation part is changed to use the link file

 arm-linux-gnueabihf-ld -Timx6u.lds $^ -o led.elf
var code = "c01da795-9bfb-4168-89ef-6424a65cb617"