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"