用FPGA搭建一个STM32内核?
1.必要的基礎知識
為了更快的完成在FPGA上實現ARM Cortex-M3軟核,一些必要的基礎知識還是要有的!
FPGA開發基礎知識,如FPGA開發流程,設計、綜合、布局、布線、約束、下載
Xilinx Vivado開發環境使用基礎,如BlockDesign設計方式,管腳分配,Bit流文件生成與下載
ARM Cortex-M3內核的使用基礎,如STM32、MM32、GD32、CH32等微控制器的開發。
Keil-MDK開發環境的使用基礎,基本的工程建立、編譯、下載流程。
如果以上知識都具備,那么,恭喜你!可以在2小時內完成ARM Cortex-M3軟核在FPGA上的實現。
2.Cortex-M3 FPGA IP核下載
首先,我們需要從ARM官網上獲取ARM Cortex-M3 FPGA軟核IP包。
下載地址如下:
https://silver.arm.com/browse/AT426
文件名稱:Cortex-M3 DesignStart FPGA-Xilinx edition(r0p1-00rel0)
文件大小:7.52MB
MD5SUM:cd67536c29023429cde47130d51b6f49
官網下載需要先注冊賬號,如果下載速度很慢,可以在公眾號后臺回復:220318,獲取下載鏈接,復制到瀏覽器下載。
ARM官網壓縮包解壓之后,共有4個文件夾:
壓縮包內容各個文件夾存放的內容:
docs
存放ARM Cortex-M3處理器參考手冊、DesignStart FPGA版本使用說明、基于Arty-A7開發板的頂層BlockDesign框圖等文件。
hardware
存放基于Digilent Arty-A7開發板的Vivado工程,頂層BlockDesign文件,管腳約束文件,Testbench文件等。
software
存放Keil-MDK工程,SPI Flash的編程算法文件等。
vivado
包括DesignStart Cortex-M3 Xilinx FPGA版本的IP核文件,其中Arm_ipi_repository文件夾就是內核源文件了,IP文件內容已經加密,沒有可讀性。
IP核源碼3.硬件準備
為了完成DS CM3在FPGA上的搭建,我們至少需要以下硬件:
一塊Artix-7?開發板,用于構建Cortex-M3軟核SoC,我使用的是正點原子達芬奇Pro開發板,FPGA型號為XC7A100T。
Xilinx FPGA下載器,用于下載軟核Bit流到FPGA,如Platform Usb Cable,JTAG-HS2/HS3等。
ARM Cortex-M?3調試器,用于調試ARM核程序下載和調試,如JlinkV9,Jlink-OB等。
官方的DS CM3 IP核是基于Digilent的Arty-A7開發板,FPGA型號為XC7A35T/100T,Vivado版本為v2019.1,如果你手頭正好有這塊開發板,那么可以直接使用官方提供的示例工程。
Digilent Arty-A7開發板:
arty-a7開發板正點原子達芬奇Pro開發板:
正點原子達芬奇Pro開發板4.軟件準備
Xilinx Vivado開發環境,官方建議版本為2018.2以上,我使用的是2018.3版本
Keil MDK開發環境,如5.33版本
DS_CM3的Keil器件包
從Keil官網上下載DesignStart Cortex-M3所專用的器件支持包,下載鏈接如下:
https://keilpack.azureedge.net/pack/Keil.V2M-MPS2_DSx_BSP.1.1.0.pack
5.Cortex-M3軟核搭建
準備好以上軟硬件,就可以開始Cortex-M3軟核的搭建了。
首先,新建一個文件夾,命名為cortex_m3_on_xc7a100t,用于存放本次示例所有的工程文件,并新建以下幾個文件夾:
目錄結構每個文件夾的功能:
bd文件夾
用來存放BlockDesign設計
cm3_core文件夾
用來存放的是ARM Cortex-M3內核IP核文件,
doc文件夾
用來存放設計文檔
flash文件夾
用來存放生成的bit和mcs文件
rtl文件夾
用來存放用戶設計的verilog源文件
xdc文件夾
用來存放管腳、時序約束文件
其中cm3_core文件夾,需要將官方壓縮文件文件中的Arm_ipi_repository文件夾復制過來,路徑為AT426-BU-98000-r0p1-00rel0\vivado\Arm_ipi_repository
以上文件夾準備好之后,就可以開始新建工程了。
5.1 新建Vivado工程
打開Vivado 2018.3,打開工程創建向導,輸入工程名稱,工程的存放路徑為之前我們新建的文件夾。
新建工程選擇FPGA芯片的完整型號:XC7A100TFGG484。
選擇芯片型號最終創建完成之后的工程目錄
Vivado工程目錄5.2 添加IP核搜索路徑
為了能在BlockDesign中搜索到ARM Cortex-M3處理器IP核,我們需要把ARM 軟核IP所在的路徑添加到搜索路徑。
添加到搜索路徑5.3 創建BlockDesign設計
為了方便后續使用圖形化的方式連接各IP核,我們采用BlockDesign圖形化的設計方式,這樣可以快速的搭建出一顆定制化的軟核處理器。
新建BlockDesign,命名為cm3_core,保存到最初創建的bd文件夾中。
在畫布中添加Cortex-M3處理器核:
添加ARM核雙擊Cortex-M3 IP核進行一些基本配置,我們不需要Trace功能,選擇No Trace,使用SWD接口調試,禁用JTAG端口:
配置ARM核指令空間和數據空間大小,這里設置成64KB,都不進行初始化。
ITCM核DTCM配置5.4 添加一些必要的IP核
時鐘PLL
用于提供給內核、總線、外設時鐘,這里我們配置成50MHz單端輸入,PLL輸出配置成50MHz,如果時鐘頻率設置更高,綜合后會提示WNS,TNS時序不滿足,可能會影響系統的正常運行。
處理器復位IP
用于提供內核、外設、互聯組件所需要的復位信號,不需要進行定制,保持默認設置。
總線互聯IP
Cortex-M3內核為AHB總線,而且內部已經轉換成了AXI3總線,而Xilinx官方提供的GPIO/UART等外設IP核是AXI4-Lite總線,所以需要添加一個總線互聯矩陣,用于將不同協議進行轉換,從機數量配置為1,主機數量配置為2,連接到處理器的SYS總線。
基本邏輯門IP
Cortex-M3內核需要低電平復位,而復位IP輸出為高電平復位,需要在中間插入一個非門來進行轉換。
常量IP
本次軟核搭建不涉及中斷部分,所以IRQ和NMI都給定常量0即可,如果需要將中斷接入處理器,可以通過Concat核將多個中斷源合并成一個連接到IRQ。
將以上IP添加到BlockDesign畫布中,并按照下圖進行連接:
原理圖連接從官方手冊中可以知道,ARM提供的軟核IP中已經包括了ITCM和DTCM存儲器,所以我們無需添加外部的BRAM來作為程序和數據的存儲區。
Cortex-M3內核結構內核中提供ITCM和DTCM都是基于RAM實現,這也就意味著后續我們使用Keil下載程序只是下載到RAM中,掉電數據會丟失。
至此,ARM Cortex-M3處理器內核就搭建完成了,下面來添加GPIO和UART外設。
5.5 添加GPIO和UART外設
一些常用的單片機,如STM32,芯片內部的TIM、UART、SPI、CAN等外設一般是固定數量的,而我們使用FPGA來搭建ARM軟核SoC就比較靈活了,如果你不需要SPI,那就不用添加SPI外設,需要10個UART就添加10個UART,外設配置比較靈活,當然這些外設都是基于FPGA邏輯資源實現的,實際添加的數量會受限于FPGA芯片的邏輯資源大小。
下面以添加一組AXI GPIO和一組AXI UART為例,介紹如何使用ARM軟核來控制這兩個外設。
Xilinx官方提供的AXI GPIO外設具有以下特性:
內部有兩個通道,通道1和通道2,每個通道最多支持32個管腳
每個管腳可以配置成輸入或輸出模式
每個管腳可以設置復位初值
支持中斷輸出
提供的AXI UART外設有以下特性:
全雙工
支持5-8位數據位
支持奇偶校驗
可配置波特率110-230400
這里我們將GPIO配置成雙通道,通道1為輸出模式,低4位用于連接LED,通道2為輸入模式,低4位用于連接按鍵。
GPIO配置UART配置成115200波特率,8位數據位,無奇偶校驗。
UART配置配置完成之后,將它們連接的到互聯IP的主機接口上:
原理圖連接這兩組IP的時鐘可以和處理器使用同樣的時鐘,復位可以使用復位IP輸出的外設復位信號。
關于AXI GPIO和AXI UART的詳細使用,可以查看官方文檔:
pg144-axi-gpio.pdf
https://www.xilinx.com/support/documentation/ip_documentation/axi_gpio/v2_0/pg144-axi-gpio.pdf
pg142-axi-uartlite.pdf
https://www.xilinx.com/support/documentation/ip_documentation/axi_uartlite/v2_0/pg142-axi-uartlite.pdf
5.6 SWD接口的引出
官方的DesignStart IP核資料中,除了Cortex-M3處理器,還有一個DAP-Link調試核,如果使用DAP-Link調試器需要添加這個IP核。
DAP-Link這里我們不使用DAP-Link調試器,而是使用Jlink SWD模式。SWD模式一共需要兩根線,一個是SWCLK時鐘信號,一個是SWDIO雙向數據信號,處理器提供了3個管腳:SWDI,SWDO和SWDOEN,我們還需要實現一個雙向端口模塊。
基于IOBUF原語實現的雙向端口模塊,內容如下:
module?swdio_tri_buffer(//Inputsinput?swd_o,input?swd_oe,//Outputsoutput?swd_i,//Inoutsinout?swd_io );IOBUF?swd_iobuf_inst(.O(swd_i),.I(swd_o),.IO(swd_io),.T(!swd_oe) );endmodule將它添加到我們的設計中。
SWD接口連接最終的BlockDesign設計如下圖所示:
原理圖連接5.7 分配外設基地址
添加完外設IP之后,我們還需要對外設進行基地址和空間分配,在地址編輯框,右鍵選擇自動分配。
基地址分配分配完成之后,使用設計驗證(Validate Design)功能,可以檢查當前BlockDesign設計連接的合法性。
驗證設計5.8 生成Wrapper并例化到頂層
為了方便后續添加自定義的FPGA邏輯模塊,我們將Cortex-M3軟核處理器作為一個處理器例化到頂層設計中。
在BlockDesign源文件上右鍵,先選擇Generate Output Products,耐心等待生成完成之后,選擇Create HDL Wrapper。
生成Wrapper之后就會生成一個_wrapper的verilog文件。
新建頂層文件top_hdl.v并保存到rtl文件夾,將_wrapper例化到頂層。
module?top_hdl(//Inputsinput?clk,input?rst_n,input?swclk,input?uart_rxd,input?[3:0]?sw,//Outputsoutput?[3:0]?led,output?uart_txd,//Inoutsinout?swdio );cm3_core_wrapper?cm3_core_wrapper_ut0(//Inputs.cm3_clk(clk),.cm3_resetn(rst_n),.cm3_gpio_in_tri_i(sw[3:0]),.cm3_swclk(swclk),.cm3_uart_rxd(uart_rxd),//Outputs.cm3_gpio_out_tri_o(led[3:0]),.cm3_uart_txd(uart_txd),//Inouts.cm3_swdio(swdio) );endmodule???//top_hdl?end5.9 管腳分配
綜合(Synthesis)完成之后,使用Vivado的圖形化工具進行管腳分配,尤其注意要將SWDIO和SWDCLK引出到排針管腳上,方便后續使用外接的Jlink調試器進行ARM程序下載。
分配管腳或者直接新建XDC文件,使用約束語句進行管腳分配。
部分約束語句:
set_property?PACKAGE_PIN?R4?[get_ports?clk] set_property?PACKAGE_PIN?V13?[get_ports?swclk] set_property?PACKAGE_PIN?V14?[get_ports?swdio] set_property?PACKAGE_PIN?E14?[get_ports?uart_rxd] set_property?PACKAGE_PIN?D17?[get_ports?uart_txd] set_property?PACKAGE_PIN?U7?[get_ports?rst_n] set_property?PACKAGE_PIN?V9?[get_ports?{led[3]}] set_property?PACKAGE_PIN?Y8?[get_ports?{led[2]}] set_property?PACKAGE_PIN?Y7?[get_ports?{led[1]}] set_property?PACKAGE_PIN?W7?[get_ports?{led[0]}] set_property?PACKAGE_PIN?T4?[get_ports?{key[3]}] set_property?PACKAGE_PIN?T3?[get_ports?{key[2]}] set_property?PACKAGE_PIN?R6?[get_ports?{key[1]}] set_property?PACKAGE_PIN?T6?[get_ports?{key[0]}]如果你的板子和我的(正點原子達芬奇Pro)一樣,那么可以直接使用以上管腳約束。
如果你分配的時鐘管腳不是FPGA的全局時鐘管腳,需要添加BUFG原語進行緩沖。
5.10 Bit流文件生成和下載
我的板子使用的是QSPI Flash,為了提高下載和啟動速度,在生成Bit流時,配置生成選項:數據壓縮、50M讀取速度,4位數據線。
生成Bit流配置或者直接使用XDC語句進行約束:
set_property?BITSTREAM.GENERAL.COMPRESS?TRUE?[current_design] set_property?BITSTREAM.CONFIG.CONFIGRATE?50?[current_design] set_property?CONFIG_VOLTAGE?3.3?[current_design] set_property?CFGBVS?VCCO?[current_design] set_property?BITSTREAM.CONFIG.SPI_BUSWIDTH?4?[current_design]以上約束不是必須的,只是為了提高下載和配置速度。
耐心等待工程綜合完成,生成Bit流文件,綜合的速度和處理器主頻、核心數有關。
和常規的FPGA下載方式一樣,將生成的軟核Bit文件通過Xilinx下載器下載到FPGA內部,先不要固化到外部SPI Flash 。
手頭沒有Xilinx下載器的,可以參考之前的文章,自己做一個JTAG-HS2下載器!
開源、低成本的Xilinx FPGA下載器
5.11 Jlink連接測試
下載完成之后,現在FPGA內部運行的就是一顆基于ARM Cortex-M3的軟核處理器了,使用Jlink等調試工具可以連接到芯片。
將Jlink調試器的SWCLK和SWDIO連接到我們分配的管腳V13和V14上。
手頭沒有Jlink的,也可以參考之前的文章,自己做一個Jlink-OB!
手把手教你制作Jlink-OB調試器
使用Keil開發DesignStart Cortex-M3軟核的程序,需要先安裝一個DesignStart專用的器件包。
下載地址如下:
https://keilpack.azureedge.net/pack/Keil.V2M-MPS2_DSx_BSP.1.1.0.pack
打開一個STM32 Keil工程,器件修改為剛剛安裝的ARM DS_CM3,在Option->Debug-Setting界面中選擇SWD方式,第一次連接會提示需要選擇一個器件,這里選擇Cortex-M3:
選擇器件型號如果以上配置均正確,就能看到已經連接到的ARM Cortex-M3核心。如果沒有,說明FPGA工程配置有錯誤,需要確認是否和以上配置流程一致。
連接到ARM核心至此,ARM Cortex-M3軟核基本搭建完成,接下來我們使用Keil來編寫ARM核的程序,實現GPIO和UART的控制。
6.Cortex-M3軟核程序設計
和常規的ARM Cortex-M3內核單片機開發流程類似,使用Keil新建工程,源文件,根據外設使用手冊,讀寫指定的寄存器實現GPIO的控制,UART數據寫入,編譯下載,調試。
在之前創建的cortex_m3_on_xc7a100t文件夾下,新建mdk_prj文件夾,用于保存Keil-MDK的工程,并新建以下3個文件夾:
application????????//用戶源文件 object????????????//編譯生成的文件 project????????????//Keil的工程文件6.1 新建Keil工程
打開Keil-MDK,選擇Project->New Project,新建一個工程,命名為ds_cm3_prj,保存到project目錄下。
Keil工程目錄器件型號選擇我們新安裝的ARM Cortex-M3 DS_CM3內核。
選擇器件型號組件管理界面中,添加CMSIS內核文件和Startup啟動文件:
添加內核文件并按照如下結構組織文件:
文件結構6.2 設置RAM和ROM地址
在工程選項中設置片上ITCM的起始地址0x0、大小64K,片上DTCM起始地址0x20000000、大小64K:
RAM地址配置起始地址來源于使用手冊中圖4-1系統內存地址映射,可以看到其中ITCM和DTCM的起始地址:
ITCM和DTCM起始地址大小是我們在Cortex-M3內核配置中設置的大小:
ITCM和DTCM大小設置完成之后,新建main.c文件,輸入以下內容,編譯工程,應該無錯誤輸出。
#include?"DS_CM3.h" #include?"system_DS_CM3.h"int?main(void) {while(1){} }6.3 GPIO輸入輸出控制
通過查看AXI GPIO的使用手冊,通道1的數據寄存器偏移地址為0,通道2的數據寄存器偏移地址為0x08,根據Vivado中的連接,LED連接到通道1,按鍵連接到通道2上,所以只需要對這兩個寄存器地址進行讀寫,就可以實現LED的控制和撥碼開關狀態的讀取。
AXI GPIO寄存器定義在Vivado地址分配界面,可以看到GPIO和UART的基地址分別為:0x4000_0000和0x4060_0000。
外設基地址LEL控制和撥碼開關讀取:
*(volatile?uint32_t?*)?(0x40000000+0x0)?=?0x0f;????//GPIO通道1低4位寫1 *(volatile?uint32_t?*)?(0x40000000+0x0)?=?0x00;????//GPIO通道1低4位寫0uint32_t?sw?=?0; sw?=?*(uint32_t?*)?(0x40000000+0x08);????//獲取GPIO通道2的32位輸入狀態6.4 串口數據發送和接收
向串口發送FIFO寫入一字節數據:
while((*(volatile?uint32_t?*)(0x40600000?+?0x08))?&?0x08?!=?0x08);????//等待發送FIFO不滿 *(volatile?uint32_t?*)?(0x40600000+0x04)?=?0x41;????//向串口發送FIFO寫入字符'A'=0x41從串口接收一字節數據:
uint8_t?dat?=?0; if((*(volatile?uint32_t?*)(0x40600000?+?0x08))?&?0x01?==?1)????//串口接收FIFO中有數據dat?=?(*(volatile?uint32_t?*)(0x40600000?+?0x00));????????//從接收FIFO中讀取1字節數據。關于AXI GPIO和AXI UART寄存器的詳細說明,可以查看官方文檔:
pg144-axi-gpio.pdf
https://www.xilinx.com/support/documentation/ip_documentation/axi_gpio/v2_0/pg144-axi-gpio.pdf
pg142-axi-uartlite.pdf
https://www.xilinx.com/support/documentation/ip_documentation/axi_uartlite/v2_0/pg142-axi-uartlite.pdf
6.5 延時函數實現
為了讓LED的變化,可以被人眼所看到,需要使用延時函數對亮滅進行延時。
使用系統滴答定時器實現一個延時函數:
volatile?uint32_t?cnt?=?0;????//volatile類型void?SysTick_Handler(void) {cnt++; }void?delay_ms(uint32_t?t) {cnt?=?0;while(cnt-t>0); }為了讓延時函數準確延時,我們還需要更改工程中的系統時鐘頻率,和FPGA中配置的內核時鐘保持一致。
系統時鐘完成的main.c文件內容:
#include?"DS_CM3.h" #include?"system_DS_CM3.h" //C庫 #include?<stdarg.h> #include?<string.h> #include?<stdio.h>#define?BASEADDR_LED?????0x40000000 #define?BASEADDR_UART?????0x40600000 #define?CHANNEL_LED?????1 #define?CHANNEL_SW???????2#define?XGPIO_CHAN_OFFSET?8 #define?XGpio_WriteReg(BaseAddress,?RegOffset,?Data)???Xil_Out32((BaseAddress)?+?(RegOffset),?(uint32_t)(Data)) #define?XGpio_ReadReg(BaseAddress,?RegOffset)?????????????XGpio_In32((BaseAddress)?+?(RegOffset))#define?XUL_TX_FIFO_OFFSET???????????4?????/*?transmit?FIFO,?write?only?*/ #define?XUL_STATUS_REG_OFFSET????????8?????/*?status?register,?read?only?*/ #define?XUL_SR_TX_FIFO_FULL??????????0x08??/*?transmit?FIFO?full?*/#define?XUartLite_GetStatusReg(BaseAddress)??????????XUartLite_ReadReg((BaseAddress),?XUL_STATUS_REG_OFFSET) #define?XUartLite_ReadReg(BaseAddress,?RegOffset)???XGpio_In32((BaseAddress)?+?(RegOffset))#define?XUartLite_IsTransmitFull(BaseAddress)?\((XUartLite_GetStatusReg((BaseAddress))?&?XUL_SR_TX_FIFO_FULL)?==?\XUL_SR_TX_FIFO_FULL)#define?XUartLite_WriteReg(BaseAddress,?RegOffset,?Data)??Xil_Out32((BaseAddress)?+?(RegOffset),?(uint32_t)(Data))volatile?uint32_t?cnt?=?0;void?SysTick_Handler(void) {cnt++; }void?delay_ms(uint32_t?t) {cnt?=?0;while(cnt-t>0); }uint32_t?XGpio_In32(uint32_t?Addr) {return?*(volatile?uint32_t?*)?Addr; }void?Xil_Out32(uint32_t?Addr,?uint32_t?Value) {volatile?uint32_t?*LocalAddr?=?(volatile?uint32_t?*)Addr;*LocalAddr?=?Value; }uint32_t?XGpio_DiscreteRead(uint32_t?Addr,?uint8_t?Channel) {return?XGpio_ReadReg(Addr,?(Channel-1)*XGPIO_CHAN_OFFSET); }void?XGpio_DiscreteWrite(uint32_t?Addr,?uint8_t?Channel,?uint32_t?Data) {XGpio_WriteReg(Addr,?(Channel-1)*XGPIO_CHAN_OFFSET,?Data); }void?XUartLite_SendByte(uint32_t?BaseAddress,?uint8_t?Data) {while?(XUartLite_IsTransmitFull(BaseAddress));XUartLite_WriteReg(BaseAddress,?XUL_TX_FIFO_OFFSET,?Data); }void?cm3_print(const?char?*ptr) {while?(*ptr?!=?(char)0)?{XUartLite_SendByte(BASEADDR_UART,?*ptr);ptr++;} }void?MyUartPrintf(char?*fmt,...) {unsigned?char?UsartPrintfBuf[296];va_list?ap;unsigned?char?*pStr?=?UsartPrintfBuf;va_start(ap,?fmt);vsnprintf((char?*)UsartPrintfBuf,?sizeof(UsartPrintfBuf),?(const?char?*)fmt,?ap);??????????????????????va_end(ap);while(*pStr?!=?0){XUartLite_SendByte(BASEADDR_UART,?*pStr);pStr++;} }void?led_blink(void) {XGpio_DiscreteWrite(BASEADDR_LED,?CHANNEL_LED,?0);delay_ms(500);XGpio_DiscreteWrite(BASEADDR_LED,?CHANNEL_LED,?0xf);delay_ms(500); }int?main(void) {uint32_t?sw?=?0;SystemCoreClockUpdate();SysTick_Config(SystemCoreClock/1000);cm3_print("Hello?DesignStart?ARM?Cortex-M3?on?FPGA?Xilnx?Artix-7?XC7A100T?\r\n");MyUartPrintf("SystemCoreClock?=?%ld\r\n",?SystemCoreClock);while(1){led_blink();sw?=?XGpio_DiscreteRead(BASEADDR_LED,?CHANNEL_SW);MyUartPrintf("key?state?=?%d-%d-%d-%d\r\n",?sw>>3,?sw>>2&1,?sw>>1&1,?sw&1);} }實現的功能是,4顆LED每100ms閃爍一次,同時串口輸出此時撥碼開關的實時狀態。
編譯無誤后,就可以進行程序下載了。
6.6 Flash編程算法生成
使用Jlink下載程序需要指定Flash編程算法,但是Keil自帶的算法中并沒有我們所需要的:
下載算法所以我們需要定制一份Flash編程算法,打開Keil安裝目錄下的\ARM\Flash文件夾,將_Template文件夾復制出一份,并命名為DS_CM3,
復制模板打開其中的Keil工程:
下載算法這個工程可以自己設置要編程的Flash起始地址、大小,擦除大小等。
FlashDev.c文件填入以下內容,和我們之前ITCM的配置保持一致,起始地址0x0,大小64K:
#include?"..\FlashOS.H"????????//?FlashOS?Structuresstruct?FlashDevice?const?FlashDevice??=??{FLASH_DRV_VERS,?????????????//?Driver?Version,?do?not?modify!"MyCM3onFPGA",??????????????//?Device?Name?ONCHIP,?????????????????????//?Device?Type0x00000000,?????????????????//?Device?Start?Address0x00010000,?????????????????//?修改為64KB1024,???????????????????????//?Programming?Page?Size0,??????????????????????????//?Reserved,?must?be?00xFF,???????????????????????//?Initial?Content?of?Erased?Memory100,????????????????????????//?Program?Page?Timeout?100?mSec3000,???????????????????????//?Erase?Sector?Timeout?3000?mSec//?Specify?Size?and?Address?of?Sectors0x010000,?0x000000,?????????//?只有一個扇區,起始地址為0SECTOR_END };FlashPrg.c文件,實現一些存儲區擦除的函數:
#include?"..\FlashOS.H"????????//?FlashOS?Structures #include?"string.h"int?Init?(unsigned?long?adr,?unsigned?long?clk,?unsigned?long?fnc)?{return?(0);??????????????????????????????????//?Finished?without?Errors }int?UnInit?(unsigned?long?fnc)?{return?(0);??????????????????????????????????//?Finished?without?Errors }int?EraseChip?(void)?{memset((unsigned?char?*)0,?0,?0x10000);return?(0);??????????????????????????????????//?Finished?without?Errors }int?EraseSector?(unsigned?long?adr)?{memset((unsigned?char?*)adr,?0,?1024);return?(0);??????????????????????????????????//?Finished?without?Errors }int?ProgramPage?(unsigned?long?adr,?unsigned?long?sz,?unsigned?char?*buf)?{memcpy((unsigned?char?*)adr,?buf,?sz);return?(0);??????????????????????????????????//?Finished?without?Errors }編譯無誤后,會在工程目錄下生成一個FLM文件。新生成的下載算法將它復制到上一級目錄:
新生成的下載算法6.7 編譯下載運行
再打開我們的ARM核Keil工程,添加DS_CM3 Flash編程算法:
添加Flash編程算法點擊下載按鈕,把ARM程序下載到ARM核:
可以看到LED每500ms閃爍一次,串口數據每1s輸出一次,同時按下按鍵,串口輸出按鍵的狀態。
和其他ARM內核芯片一樣,也是支持在線調試的:
43由于ARM程序是下載到Cortex-M3軟核內的RAM存儲區,所以掉電后程序會丟失。如何將程序下載到片外的SPI Flash中,我還沒有成功實現。
-END-
往期推薦:點擊圖片即可跳轉閱讀
嵌入式與單片機之間的關系是什么?
考研還是工作?看完這個給你答案!
拆解飛機黑匣子,看看內部構造、PCB及芯片
19年三本畢業,做了三年的嵌入式軟件。
我是張巧龍,一名教電子的大學老師,歡迎關注!
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的用FPGA搭建一个STM32内核?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用HMAC-SHA1签名方法详解
- 下一篇: 几个贼有意思的电路