一、蜂鳴器學習
?
代碼實現:
二、BSP工程管理及Makefile
1、BSP工程管理
利用BSP工程管理,使文檔顯示不雜亂;
????????將這些文件分為4類,并保存到4個不同的文件夾里。
????????首先在新的工程文件夾里創建一個之后我們編寫的類似led驅動,clk驅動等等外設驅動程序都放在這文件夾里面,創建名為bsp
?再創建project文件夾,存放 start.s和 main.c 文件,也就是應用文件;
?? 一個imx6ull文件夾,用來保存NXP的相關庫cc.h、fsl_common.h、fsl_iomuxch和 MCIMX6Y2.h 這四個文件;
最后再創建一個obj文件夾,用來存放編譯生成的.o?文件。
2、Makefile?
target = ledcross_compiler = arm-linux-gnueabihf-cc = $(cross_compiler)gcc
ld = $(cross_compiler)ld
objcopy = $(cross_compiler)objcopy
objdump = $(cross_compiler)objdumpincdirs = bsp imx6ull #所有包含頭文件的文件夾
srcdirs = bsp project #所有包含源文件的文件夾include = $(patsubst %, -I%, $(incdirs)) #處理了頭文件之后生成了$(incdirs),然后在生成的每個文件前面加-I
#I是include,-Idsp意思是使用的頭文件去dsp文件夾找cfiles = $(foreach dir, $(srcdirs), $(wildcard $(dir)/*.c)) #將所有源文件中的.c找出來,但是得到的結果帶目錄。eg:文件名/main.c
sfiles = $(foreach dir, $(srcdirs), $(wildcard $(dir)/*.S)) #將所有源文件中的.s找出來,但是得到的結果帶目錄。eg:文件名/main.Scfilenodir = $(notdir $(cfiles)) #去掉了目錄名,得到的是main.c
sfilenodir = $(notdir $(sfiles))#去掉了目錄名,得到的是main.Scobjs = $(patsubst %, obj/%, $(cfilenodir:.c=.o)) #編譯之后生成的結果是main.o,(.c)需要放入obj的目錄中去,obj/表示放在obj這個目錄中去
sobjs = $(patsubst %, obj/%, $(sfilenodir:.S=.o)) #編譯之后生成的結果是main.o,(.S)需要放入obj的目錄中去,obj/表示放在obj這個目錄中去objs = $(cobjs) $(sobjs) #將.c生成的obj和.S生成的obj放在一起VPATH = $(srcdirs) #表示如果找源文件找不到的話,就去srcdirs中去查找;$(target).bin : $(objs)$(ld) -Timx6ull.lds -o$(target).elf $^$(objcopy) -O binary -S -g $(target).elf $@$(objdump) -D $(target).elf > $(target).dis$(sobjs) : obj/%.o : %.S #.S生成sobj@mkdir -p obj #如果沒有obj文件,創建obj目錄,@符號表示,創建的過程中沒有回顯,,-p表示如果這個目錄已存在,則不報錯$(cc) -Wall -nostdlib -c $(include) -o $@ $<$(cobjs) : obj/%.o : %.c #.c生成cobj@mkdir -p obj #如果沒有obj文件,創建obj目錄,@符號表示,創建的過程中沒有回顯,,-p表示如果這個目錄已存在,則不報錯$(cc) -Wall -nostdlib -c $(include) -o $@ $<.PHONY : clean
clean:rm -rf $(objs) $(target).elf $(target).bin $(target).dis
三、 按鍵練習
代碼實現:
#include"key.h"
#include"MCIMX6Y2.h"
#include"fsl_iomuxc.h"
#include "core_ca7.h"
#include "gpio.h"
void init_key(void)
{IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18,0);IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_UART1_CTS_B,0x10F0);GPIO_Pin_Config_t t = {.direction = GPIO_Direction_In};gpio_pin_config(GPIO1,18,&t);GPIO1->ICR2 |= (3 << 18);GPIO1->IMR |= (1 << 18);GIC_SetPriority(GPIO1_Combined_16_31_IRQn,1);GIC_EnableIRQ(GPIO1_Combined_16_31_IRQn);}int key_pressed(void)
{return((GPIO1->DR & (1 << 18)) == 0) ? 1 : 0;}
四、中斷
4.1 GIC控制器(通用中斷控制器)
?VFIQ/VIRQ中V指虛擬化的;
????????GIC 接收眾多的外部中斷,然后對其進行處理,最終就只通過四個信號報給 ARM 內核,這四個信號的含義分別為: VFIQ:虛擬快速 FIQ。 VIRQ:虛擬 IRQ。 FIQ:快速中斷 IRQ。 IRQ:中斷 IRQ。
作用:
- 作用是中斷優先級排序;
- 中斷屏蔽的控制;
GIC控制器(v2版本)最多處理8個內核;最多有1020個中斷源:
SGI ?(軟件中斷):( 0 - 15 ),,軟件中斷,由軟件觸發引起的中斷,通過向寄存器GICD_SGIR
寫入數據來觸發,系統會使用 SGI 中斷來完成多核之間的通信。
PPIs(私有中斷):(16 - 31), GIC 是支持多核的,每個核肯定有自己獨有的中斷。這些獨有的中斷肯定是要指定的核心處理,因此這些中斷就叫做私有中斷;
SPI(共享中斷):(32-1019), (注意!不是 SPI 總線那個中斷),這類中斷泛指所有的外設中斷;如定時器、外部中斷、串口中斷等。
? ? ? ? 實際用到的只有(32-159)128個,這128是imx6ull所支持的
? ? ? ? PS:GIC也可以屏蔽不需要的中斷
? ? ? ? ? ? ? ? V2版本的GIC不在ARM內部,V3、V4版本的是64位
4.2?異常向量表
????????異常向量表重映射是指在處理器發生異常時,通過改變異常向量表的物理地址與邏輯地址之間的映射關系
????????目的:確保系統能夠正確響應和處理異常。
????????各模式下的sp只能在進入對應模式后 才能設置,這是因為每種模式的sp都是分離的。 這里分別設置irq、sys、svc模式下的大小都為2MB。
異常狀態返回地址偏移量:當異常狀態發生以后,返回地址和lr中保留的地址偏移量
4.3 協處理器
????????協處理器:用于減輕系統微處理器特定處理任務的芯片;
? ? ? ? cortex A7 共16個協處理器,CP0~CP15
4.3.1 mcr指令與mrc指令?
用mcr與mrc來訪問協處理器;
mcr寫入協處理器;
mrc讀取協處理器;
協處理器編號p0-p15;
讀取出來的寄存器內容:
SCTLR寄存器:
eg:mrc p15, 0, r0, c0, c0, 0(mrc指令讀取MIDR(主ID)寄存器,讀出來的結果放入了寄存器R0中)
? ? CPSR分為I位(bit[7](0不屏蔽? 1屏蔽))、F位(bit[6] 0不屏蔽 1屏蔽)
CPS指令
????????這里的 effect 分為倆個bit[7](IE使能 cpsie(0)、ID失能cpsid(1)),使用了effect的話就不能省略iflags,i位指irq,f位指frq
PS:在匯編中調main.c中的函數時,要先保護現場
獲取中斷號,并記錄?
GPIOx_ICR? ? ? ? //設置中斷寄存器?
GPIOx_IMR? ? ? ? //設置中斷屏蔽寄存器 ,若為1,開中斷
GPIOx_ISR? ? ? ? //設置中斷標記寄存器 ,若為1,則說明該位產生中斷,但要手動清零
4.4? 搶占優先級
????????Cortex——A7 有32個搶占優先級(誰數小,誰的優先級就高)
????????1 1111 ---> 32個
????????0(組優先級) xxxx(子優先級)
五、提高代碼的耦合性
gpio.c
#include "gpio.h"void gpio_pin_config(GPIO_Type *base, int pin, GPIO_Pin_Config_t *config) //初始化函數,GPIo引腳的配置, // 參數分別是GPIO_Type類型的base,將GPIO的組號傳入 參數2:引腳號 參數3:初始化引腳 {if(config->direction == GPIO_Direction_Out) //判斷 將相關寄存器,方向配置為輸出{base->GDIR |= (1 << pin);if(config->defalut_value != 0) //該引腳的默認值為高電平{ base->DR |= (1 << pin); }else // 該引腳的默認應該配置為低電平{base->DR &= ~(1 << pin); }}else //需要將該引腳配置為低電平{base->GDIR &= ~(1 << pin);} }void gpio_write(GPIO_Type *base, int pin, int value) //寫入函數,參數分別是:參數1:參數分別是GPIO_Type類型的base,將GPIO的組號傳入 // 參數2:引腳 參數3:需要寫入的值 {if(value) //判斷寫入的值是不是1,如果是1的話,則在其DR寫入1;{base->DR |= (1 << pin); //在輸入得引腳寫入1}else // 如果不是,則進行指定位清0{base->DR &= ~(1 << pin); //在輸入得引腳寫入0} }int gpio_read(GPIO_Type *base, int pin) // 讀函數,參數分別是GPIO_Type類型的base,第二個參數:引腳 {return (base->DR & (1 << pin)) != 0; }
gpio.h
#ifndef _GPIO_H_ #define _GPIO_H_ #include "MCIMX6Y2.h" typedef enum {GPIO_Direction_Out,GPIO_Direction_In }GPIO_Direction_t; //枚舉的方法列舉GPIO兩種狀態,輸入或者輸出的方向typedef struct {GPIO_Direction_t direction; // 引腳的工作方式,列:輸入或者輸出int defalut_value; // 初始化引腳后,該引腳的默認值是高電平還是低電平 }GPIO_Pin_Config_t; // 初始化引腳extern void gpio_pin_config(GPIO_Type *base, int pin, GPIO_Pin_Config_t *config); extern void gpio_write(GPIO_Type *base, int pin, int value); extern int gpio_read(GPIO_Type *base, int pin);#endif