-
文章寫的很直覺,一看就能懂,入門好文
-
樓主不用vim用啥 emacs?sublime atom?純屬好奇
-
freebsder 发表于 2015-5-8 20:53
主要用在服务器,如果做桌面和嵌入式还是不太方便。
想折腾看手册是最好的入门资料
服务器啊..那暂时还不会用到
一直在用的服务器也是Ubuntu的
看来机会不多
-
cool
-
freebsder 发表于 2015-5-8 20:00
freebsd + debian 党飘过
很想玩玩freeBSD,名气太大了
-
freebsder 发表于 2015-5-4 21:11
呵呵,只以我个人经历来说,建议你不要管“不少人”怎么怎么希望,自己按照结构性的,系统性的学习,基础性的学习,某一天这些乱七八糟的“技术”对你来说就是纸老虎了。
對,我大概一年半前就意識到這個問題了
其實道理很簡單,越容易上手的越難學到真東西,也越沒競爭力
-
本帖最后由 john0517 于 2015-5-4 16:49 编辑
freebsder 发表于 2015-5-4 09:38
一般有info manual或help就可以,这种产品性的东西,说明书最靠谱。
ps:
最好整理一下,你的链接我这边是被墙了。
完全贊同你!說明書是最嚴謹也是最完善的開發指南
但是,你也知道,不少人都希望有不用思考的完全教學指南:)
我會抽空整理~
國內現在封了github、hackpad很無奈
-
本帖最后由 john0517 于 2015-5-4 00:12 编辑
freebsder 发表于 2015-5-3 13:15
确实用gcc的人很少,其时就算能用IAR,MDK等命令行工具做工程的人就不多,何况gcc。
除了版面格式太伤眼,期待更多交流和分享
关于版面格式,因为从Hackpad直接贴过来的缘故,没有用心去整理,实在是抱歉!!!
此处补上hackpad地址:https://embedded2015.hackpad.com/Week-7-8--ID8HJ3uW0MO
IAR,MDK的命令行工具我也是第一次听说@@
可能跟教学的资源太少有关吧
-
感慨一句,可能gnu toolchain不少人都不熟,其實我也才入門不久
以前都是用MDK IDE,覺得好用,但毫無疑問用的盜版,這些行爲屬於灰色的
使用GNU toolchain不僅僅是因爲免費,更是因爲它的強大
GNU/linux名字是怎麼得來的無需贅言
將來繼續做Embedded system,基本也離不開linux系統
那麼在linux上,GNU software就是王道
(MS剛剛宣佈全新的visual studio code將支持linux,不過目前也還只是編輯器而已)
-
本帖最后由 john0517 于 2015-5-4 00:11 编辑
——————————————END——————————————
-
本帖最后由 john0517 于 2015-5-4 00:10 编辑
06-Preemptive
在context_switch.s中對systick_handler定義了一樣的行爲,當systick exception觸發時,也會將進程切換到kernel mode
一直沒找到delay()和systick有什麼直接聯繫,恍然大悟:當一個task在運行時,由於發生了systick exception,就會切換到kernel mode然後運行下一個task,這樣就如同preemptive
-
本帖最后由 john0517 于 2015-5-4 00:10 编辑
05-TimerInterrupt
首先看啓動文件,多了pendsv和systick的定義,關於Cortex-M3設備的異常類型再複習一下
void __attribute__((interrupt)) systick_handler(void)
The compiler generates function entry and exit sequences suitable for use in an interrupt handler when this attribute is present. With Epiphany targets it may also generate a special section with code to initialize the interrupt vector table.(https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html)
-
本帖最后由 john0517 于 2015-5-4 00:10 编辑
04-Multitasking
https://hackpad-attachments.imgix.net/hackpad.com_ID8HJ3uW0MO_p.313849_1430069883929_undefined?fit=max&w=882
(先猜測main裏有個while循環,裏面來回activate task1和task2,而在task1和2中print完後便調用syscall回到kernel(main)
diff context_switch.S ../03-ContextSwitch-2/context_switch.S ,發現:
svc_handler中的msr psr, ip變成了msr psr_nzcvq, ip
nzcv爲psr的四個標誌位,只是q是什麼@@
從ARM® 和 Thumb®-2 指令集中找到nzcvq爲PSR[31:27]的標誌位,由此再google從KEIL網站得到解釋
詫異爲何在ARM官網看到的第27位保留了,仔細看才發現是cortex-m0的手冊
找到cortex-m3的通用寄存器手冊果然找到了nzcvq
另外在activate中,在切換到process stask後多一條isb指令:
Instruction Synchronization Barrier flushes the pipeline in the processor, so that all instructions following the ISB are fetched from cache or memory, after the instruction has been completed. It ensures that the effects of context altering operations, such as changing the ASID, or completed TLB maintenance operations, or branch predictor maintenance operations, as well as all changes to the CP15 registers, executed before the ISB instruction are visible to the instructions fetched after the ISB.
In addition, the ISB instruction ensures that any branches that appear in program order after it are always written into the branch prediction logic with the context that is visible after the ISB instruction. This is required to ensure correct execution of the instruction stream.
重頭戲果然在os.c,並且代碼的設計比我一開始預測的要有規劃性一些,具體分析如下:
首先宏定義了三個地址:
#define HANDLER_MSP 0xFFFFFFF1
#define THREAD_MSP 0xFFFFFFF9
#define THREAD_PSP 0xFFFFFFFD
https://hackpad-attachments.imgix.net/hackpad.com_ID8HJ3uW0MO_p.313849_1430104560643_undefined?fit=max&w=882
接着是新建一個task:
unsigned int *create_task(unsigned int *stack, void (*start)(void))
{
static int first = 1;
stack += STACK_SIZE - 32; /* End of stack, minus what we are about to push */
if (first) {
stack[8] = (unsigned int) start;
first = 0;
} else {
stack[8] = (unsigned int) THREAD_PSP;
stack[15] = (unsigned int) start;
stack[16] = (unsigned int) 0x01000000; /* PSR Thumb bit */
}
stack = activate(stack);
return stack;
}
而在main函數中,對應的調用是:
unsigned int user_stacks[TASK_LIMIT][STACK_SIZE]; //定義了程式stack的數量(2個)和大小(256*4bytes)
unsigned int *usertasks[TASK_LIMIT]; //定義了用戶程式的數量(2個)
usertasks[0]=create_task(user_stack[0],&task_func); //將之前定義的stack和function地址傳給create_task配置
usertasks[0]=create_task(user_stack[0],&task_func);
當使用create_task函數第一次進行初始化時,在create_task中對task的stack進行了配置,並且因爲是第一次設定,將stack[8]存放了task_func的地址,然後進入到task_func中echo"task1 Created"&"return"後調用syscall回到了main函數。
當第二次呼叫create_task時,comment也有說明,因爲activate是從exception中返回,故將lr保存爲THREAD_PSP,而此時的func從stack[15]開始
爲何緊接着的stack[16]就要設epsr爲0x01000000?爲何processor可以認出這條指令是設置espr的?
-
本帖最后由 john0517 于 2015-5-4 00:09 编辑
03-ContextSwitch-2
startup.c中多了一些聲明:
void nmi_handler(void) __attribute((weak, alias("default_handler")));
void hardfault_handler(void) __attribute((weak, alias("default_handler")));
void memmanage_handler(void) __attribute((weak, alias("default_handler")));
void busfault_handler(void) __attribute((weak, alias("default_handler")));
void usagefault_handler(void) __attribute((weak, alias("default_handler")));
void svc_handler(void) __attribute((weak, alias("default_handler")));
alias ("target")The alias attribute causes the declaration to be emitted as an alias for another symbol, which must be specified. For instance,
void __f () { /* Do something. */; }
void f () __attribute__ ((weak, alias ("__f")));
defines ‘f’ to be a weak alias for ‘__f’. In C++, the mangled name for the target must be used. It is an error if ‘__f’ is not defined in the same translation unit.
Not all target machines support this attribute.
所以*_handler全部alias到了default_handler上,而default_handler目前爲一個死循環:
void default_handler(void)
{
while (1);
}
syscall的定義:
syscall:
svc 0
nop
bx lr
關於svc 0,http://reverseengineering.stackexchange.com/questions/4217/arm-shellcode-for-linux-svc-0-vs-svc-1 這個鏈接裏的回答很好
在context_switch.S中定義了svc_handler函數,聯想到startup.c中的weak alias,可以理解weak alias的意思就是編譯器假如在文件中找到了某個函數的定義就會編譯,假如沒有找到就會將其alias到指定的weak alias函數。
svc_handler:
/* save user state */
mrs r0, psp
stmdb r0!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}
/* load kernel state */
pop {r4, r5, r6, r7, r8, r9, r10, r11, ip, lr}
msr psr, ip
bx lr
關於stmdb,stm代表存儲更多寄存器,db代表在獲取前將地址減小。所以就是r0地址會增加9*4bytes,然後將{}中的9個寄存器從左至右從最低位置開始存放
https://hackpad-attachments.imgix.net/hackpad.com_ID8HJ3uW0MO_p.313849_1430066464820_undefined?fit=max&w=882
程序run可見當usertask觸發syscall後會保存其狀態,然後切回main函數輸出兩個print_str,然後回到usertask後會繼續接着上一次的執行到的地方繼續執行,再輸出兩句話,然後回到main函數,也是接着上次執行後的地方繼續執行。這驗證了之前代碼裏關於user state和kernel state的save和load動作。
-
本帖最后由 john0517 于 2015-5-4 00:06 编辑
02-ContextSwitch-1
在startup.c中定義了nmi_handler和hardfault_handler,地址在reset_handler之後,什麼時候會觸發他們呢?
msp的值爲_estack=RAM的初始位置加上RAM的寬度,即0x20000000+40k,這樣意味這stack的爲40K大小,這個大小的stack感覺足夠寬裕!
接着看os.c裏的main函數:
int main(void)
{
/* Initialization of process stack.
* r4, r5, r6, r7, r8, r9, r10, r11, lr */
unsigned int usertask_stack[256];
unsigned int *usertask_stack_start = usertask_stack + 256 - 16;
usertask_stack_start[8] = (unsigned int) &usertask;
usart_init();
print_str("OS Starting...\n");
activate(usertask_stack_start);
// while (1); /* We can't exit, there is nowhere to go */
return 0;
}
cortex-m系列處理器core registers
首先定義額usertask的堆棧大小256*4byte=1k,然後定義一個指針*usertask_stack_start指向usertask堆棧加256-16的距離,而usertask的地址從usertask_stack_start棧底-8才開始,這中間多出了24byte。
我想這應該是call stack的概念,爲了後門調用usertask函數的argument、return address、saved ebp%等留下空間(24byte應該是6個空格)
contex_swtich.s中.syntax unified:Cortex-m3爲了兼容thumb指令和thumb2指令,使這兩種指令可以使用統一的格式,引入了一種叫做“UAL”的語法機制。簡單說來就是程序員不用關心自己使用的是thumb還是thumb2指令,而是統一使用32位thumb2指令的語法格式書寫。具體的機器指令是16位還是32位由編譯器來決定。.syntax unified的作用就是制定使用這一功能,具體可以參考《cortex-m3權威指南》。
接着這段代碼:
/* save kernel state */
mrs ip, psr
push {r4, r5, r6, r7, r8, r9, r10, r11, ip, lr}
/* switch to process stack */
msr psp, r0
mov r0, #3
msr control, r0
/* load user state */
pop {r4, r5, r6, r7, r8, r9, r10, r11, lr}
/* jump to user task */
bx lr
MRS:Move to ARM register from system coprocessor register. MRS Rn, coproc_register中Rn is the ARM destination register, and Rn must not be PC.System coprocessor register應該是那些special registers,其中包含psr(Program status register)。MSR反之。
將main函數(kernel)的狀態存入堆棧後,將r0數據存入程序狀態寄存器(此時r0應該存放了usertask_stack_start地址),然後設定control寄存器爲0b11:
https://hackpad-attachments.imgix.net/hackpad.com_ID8HJ3uW0MO_p.313849_1430036986509_undefined?fit=max&w=882
所以現在stack pointer是PSP,而PSP中存放的是usertask_stack_start地址,至於Thread mode是Unprivileged。
最後把usertask_stack中的寄存器值拿出來,就可以跳轉到user state了
-
本帖最后由 john0517 于 2015-5-4 00:05 编辑
01-HelloWorld
此實驗和00相比在ld上作了更多文章。00-HelloWorld的ld文件僅配置了Flash和.text section,而01中則多配置了RAM,將運行時不會更改的.text、.rodata、放入.text section中,.data放入.data section中
AT(_sidata)的_sidata表示了.data載入RAM後的VMA。因爲data section會從flash搬移到SRAM中,因此它的LMA和VMA會不同。連結器腳本的一個重要作用,就是管理個別section的LMA和VMA,並在必要的情況下,把有關資訊提供給程式程式碼使用。
/* Copy the data segment initializers from flash to SRAM */
uint32_t *idata_begin = &_sidata;
uint32_t *data_begin = &_sdata;
uint32_t *data_end = &_edata;
while (data_begin < data_end) *data_begin++ = *idata_begin++;
由startup.c中的這段代碼可知,_sidata中存放的是LMA!
-
本帖最后由 john0517 于 2015-5-4 00:05 编辑
MINI-ARM-OS
注1:这个操作系统是课程老师为了课程而开发的,后续还有发展在这里不赘述,源代码请上Github搜索mini-arm-os
注2:以下实验均在qemu模拟器上执行,等我有空再实际搬到STM32F429Discovery上
00-HelloWorld
先make然後make qemu後出現hello world,然後輸入arm-none-eabi-objdump -D hello.elf查看executable and linkable文件
https://hackpad-attachments.imgix.net/hackpad.com_ID8HJ3uW0MO_p.313849_1429980714152_undefined?fit=max&w=882
https://hackpad-attachments.imgix.net/hackpad.com_ID8HJ3uW0MO_p.313849_1429980820624_undefined?fit=max&w=882
這裏值得注意的是,在M3上電取出MSP後,會取出PC的值,圖中可見是0x000000ad。但實際上reset_handler地址是從000000ac開始的。這是因爲:
當一個例外處理程式(exception handler)的位址在LSB設定為1,代表該例外處理程式運作於Thumb模式(Thumb mode),對ARM Cortex-M3來說,這是必要的,因為該處理器核心只支援Thumb-2指令集,而不支援ARM模式(也稱ARM code或ARM state)。
所以http://wiki.csie.ncku.edu.tw/embedded/Lab42 的截圖裏,reset_handler是從0x000000ad是實際編譯器在不同機器下編譯出來的不同?
搭配hello.ld和startup.c一起看終於有種恍然大悟的感覺。.text section最前面的位置就是isr_vector,然後再是其他.text文件。當m3從Flash開始讀入數據時,首先就是isr_vector的內容,而isr_vector中首先給MSP地址賦0,然後是reset_handler,而reset_handler指向Main函數,這樣就導入我們寫的主函數了
-
本帖最后由 john0517 于 2015-5-4 00:04 编辑
STM32F429驗證 Lab3(SYSTICK精確定時)
RM裏居然沒有systic,此處查看Programming Manual
https://hackpad-attachments.imgix.net/hackpad.com_ID8HJ3uW0MO_p.313849_1429875210206_undefined?fit=max&w=882
自己又給自己上了一課,白白耗費了幾個小時,以後困了真不如先睡飽再寫...:(2個問題如下)
#define STK_BASE (*((volatile unsigned long*)(0xE000E010)))
#define STK_CRTL (*((volatile unsigned long*)(STK_BASE)))
...
解決完問題才想到gdb,假如直接用gdb來debug應該會很快
使用systic定時,時間計算:
採用HSE時鐘源(F429板子上已焊有8MHz晶振),通過AHB PRESC時不分頻,經過System Timer的bus時8分頻,這樣到達system timer的頻率就是1Mhz,每一個tick就是1us
然後STK_LOAD設爲1000000,STK_VAL設爲0,這樣count完一次就是1000000*1us=1s
實際現象請看:
-
本帖最后由 john0517 于 2015-5-4 00:03 编辑
STM32F429驗證 Lab2
依照文檔將
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 2048k
SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 112k
編譯運行正常,現象和lab1相同
-
本帖最后由 john0517 于 2015-5-4 00:02 编辑
STM32F429驗證 Lab1
ld文件中,.text : {}的.text與:中間必須有空格
參考環境搭設文件:https://stm32f429.hackpad.com/NOTE-WbiooOfkaoR
STM32F429的schematics在此文檔裏:
http://www.st.com/st-web-ui/static/active/cn/resource/technical/document/user_manual/DM00093903.pdf
LED部分的電路圖如下
https://hackpad-attachments.imgix.net/hackpad.com_ID8HJ3uW0MO_p.313849_1429541779433_undefined?fit=max&w=882
Discovery所用的STM32F429ZIT6:
Datasheet: http://www.st.com/st-web-ui/static/active/cn/resource/technical/document/datasheet/DM00071990.pdf
Reference Manual:http://www.st.com/st-web-ui/static/active/cn/resource/technical/document/reference_manual/DM00031020.pdf
STM32F429ZIT6的Flash Memory也是從0x0800 0000開始, SRAM從0x2000 0000開始, 不過注意到不同是F429的SRAM分成了112KB、16KB、64KB,Google了一下也沒看到爲什麼要這麼分,好奇
關於時鐘源:
https://hackpad-attachments.imgix.net/hackpad.com_ID8HJ3uW0MO_p.313849_1429543146612_undefined?fit=max&w=882
https://hackpad-attachments.imgix.net/hackpad.com_ID8HJ3uW0MO_p.313849_1429543251791_undefined?fit=max&w=882
關於GPIO:
port13 14,output push-pull,high speed
https://hackpad-attachments.imgix.net/hackpad.com_ID8HJ3uW0MO_p.313849_1429543371126_undefined?fit=max&w=882
https://hackpad-attachments.imgix.net/hackpad.com_ID8HJ3uW0MO_p.313849_1429543536769_undefined?fit=max&w=882
https://hackpad-attachments.imgix.net/hackpad.com_ID8HJ3uW0MO_p.313849_1429543623068_undefined?fit=max&w=882
https://hackpad-attachments.imgix.net/hackpad.com_ID8HJ3uW0MO_p.313849_1429543661753_undefined?fit=max&w=882
https://hackpad-attachments.imgix.net/hackpad.com_ID8HJ3uW0MO_p.313849_1429543959961_undefined?fit=max&w=882
make時提示:gcc: warning: ‘-mcpu=’ is deprecated; use ‘-mtune=’ or ‘-march=’ instead
根據https://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html 更換成-mtune=cortex-m4
照貓畫虎,學着https://github.com/jserv/stm32f429-demos.git 中的Makefile的openocd加進了自己的Makefile裏(但是爲什麼要這麼設置其實不是太懂,只能大概猜出一些),僅供參考:
CROSS_COMPILE ?= arm-none-eabi-
.PHONY: all
all: blink.bin
blink.o: blink.c
$(CROSS_COMPILE)gcc -mtune=cortex-m4 -mthumb -nostartfiles -c blink.c -o blink.o
blink.out: blink.o simple.ld
$(CROSS_COMPILE)ld -T simple.ld -o blink.out blink.o
blink.bin: blink.out
$(CROSS_COMPILE)objcopy -j .text -O binary blink.out blink.bin
flash: $(blink.bin)
openocd \
-f interface/stlink-v2.cfg \
-f target/stm32f4x.cfg \
-c "init" \
-c "reset init" \
-c "flash probe 0" \
-c "flash info 0" \
-c "flash write_image erase blink.bin 0x8000000" \
-c "reset run" -c shutdown || \
st-flash write blink.bin 0x8000000
clean:
rm -f *.o *.out *.bin
接着make flash,可見LED3和LED4間隔閃爍,如下:
OpenOCD的輸出在:https://github.com/luckyjoou/stm32f429Discovery-Lab/blob/master/blink_v1/log