摘要
使用esp-idf工具鏈編譯彙編程式實現在riscv架構的esp32c3點燈.
Abstract
Compiling an assembly program using the esp-idf toolchain to blink an LED on the RISC-V based ESP32-C3.
原理簡介
esp32c3的riscv架構
[https://www.bilibili.com/read/cv21025938/]
[https://smist08.wordpress.com/tag/assembly-language/]
[https://www.elektor.com/risc-v-assembly-language-programming-using-esp32-c3-and-qemu-e-book]
[https://github.com/bigmagic123/esp32c3_bare_metal]
[https://esp32.com/viewtopic.php?t=27734]
[https://github.com/TimSchulzRC/ESP32C3_Assembly_blink]
Focusing on the CPU resource, Espressif states that the ESP32-C3 device supports the RV32IMC ISA. Therefore, the following base and extensions are supported:
• I - Base Integer Instruction Set, 32-bit
• M - Standard Extension for Integer Multiplication and Division
• C - Standard Extension for Compressed Instructions
專注於CPU資源,Espressif公司給出了ESP32-C3裝置支援RV32IMC指令集架構。因此,ESP32-C3支援RV32IMC ISA,即以下基礎和擴充套件:
• I - 32位基本整數指令集
• M - 整數乘法和除法的標準擴充套件
• C - 壓縮指令的標準擴充套件
(來源:Warren Gay - RISC-V Assembly Language Programming. Using ESP32-C3 and QEMU-Elektor International Media (2022)(Z-Lib.io))
esp32c3時脈頻率
- ESP32-C3 只支援 40MHz 晶振(精度為 ± 10 p p m ),匹配電容 C15 和 C17 的取值需要經過測試之後再行確定。
- 每個ESP32定時器都是使用APB時鐘(一般是80MHz)作為基礎時鐘。
- 該定時器使用APB_CLK 時鐘源(通常為80 MHz),時脈頻率偏差小於±10 ppm,時間解析度為1 μs。
執行二進位制的一般過程
編譯->連結->執行,這裡使用匯編程式碼,但是還是需要使用esp-idf工具鏈進行編譯以生成正確的app.bin(blink.bin)檔案.
esp-idf生成的二進位制檔案
- bootloader.bin : 載入程式
- partition.bin : 分割槽地址
- blink.bin : 應用程式(反編譯生成的blink.dump.s和源程式main.s不一致)
實現
git clone https://github.com/TimSchulzRC/ESP32C3_Assembly_blink.git
cd ESP32C3_Assembly_blink
- 修改彙編程式指向正確的io口
main/main.s
.data
LED_PIN: .word 12 # 定義一個名為LED_PIN的變數,值為12,通常代表LED所連線的GPIO編號
C3_GPIO: .word 0x60004000 # 定義一個名為C3_GPIO的變數,值為0x60004000,通常這是GPIO暫存器的基址
.text
.global app_main # 宣告app_main函式為全域性可見
app_main: # app_main函式開始
lw a0, C3_GPIO # 將C3_GPIO的值載入到暫存器a0,即GPIO暫存器的基址
lw a1, LED_PIN # 將LED_PIN的值載入到暫存器a1,即LED的GPIO編號
# Aktiviere den Output
li t0, 1 # 將立即數1載入到暫存器t0
sll t0, t0, a1 # 將t0左移a1位,構建出LED對應的位掩碼
sw t0, 32(a0) # 將位掩碼寫入到GPIO輸出使能暫存器,使能LED對應的GPIO輸出
toggle_led: # toggle_led標籤,用於切換LED狀態
# Schalte LED an oder aus
lw t4, 4(a0) # 從GPIO輸出暫存器載入當前狀態到t4
xor t4, t4, t0 # 透過異或操作切換LED對應的位狀態
sw t4, 4(a0) # 將新的狀態寫回GPIO輸出暫存器,切換LED
li t5, 0 # 將立即數0載入到暫存器t5,用於計數
li t6, 10000000 # 將立即數10000000載入到暫存器t6,作為延遲計數
loop: # loop標籤,用於建立延遲
addi t5, t5, 1 # 將t5加1
blt t5, t6, loop # 如果t5小於t6,則跳轉到loop,繼續延遲
j toggle_led # 跳轉到toggle_led,切換LED狀態
- 編譯
docker pull espressif/idf:release-v4.4
alias esp-idf='docker run --rm --privileged -v $PWD:/project -w /project -it espressif/idf:release-v4.4 bash -c'
esp-idf "cd /project && idf.py build"
- 燒錄
esptool.py --chip auto --port /dev/cu.wchusbserial56910187941 -b 460800 --before=default_reset --after=hard_reset write_flash --flash_mode dio --flash_freq 80m 0x0 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/blink.bin
- (可選)反編譯
/Applications/riscv-gnu-toolchain/xpack-riscv-none-elf-gcc-14.2.0-1/bin/riscv-none-elf-objdump -d build/blink.elf > build/blink.dump.s
cat build/blink.dump.s
效果
io12的燈閃爍 |
---|
聯絡方式
如果對本文有疑問或者提出建議可評論區留言或者傳送郵件到2557877116@qq.com.