一、需求概述
如何擺脫ST官方燒錄器的束縛,編寫一個Linux驅動,完成ARM-A9 Soc對STM8固件的升級燒錄?
二、目標步驟:
1.準備好一個編譯好的固件(bin格式文件);
2.平臺Soc激活STM8的SWIM模塊;
3.平臺Soc通過SWIM單線向STM8的Flash中燒錄固件。
三、A9 Soc 通過SWIM模塊完成STM8的固件燒錄
1. 管腳連接示意圖:
/********************************************************
* A9 Soc STM8
* -------------------- --------------------
* (PD26) gpio |--->>---| rst(硬復位管腳)
* (PD27) gpio |<------>| swim
* -------------------- --------------------
*******************************************************/
1
2
3
4
5
6
7
2. 代碼示例(包含Linux驅動和應用程序)
點擊跳轉GitHub - 代碼示例SWIM
3. 重難點
ARM Soc內部PWM完成對納秒級別時間段的定時
ARM Soc普通gpio電平跳變時毛刺的消除和時間的縮短
ARM Soc普通gpio對納秒級別的反饋輸入的檢測
STM8的SWIM功能和工作方式
STM8的Flash的訪問
四、STM8相關介紹
1. STM8的調試模塊SWIM
1) STM8調試系統組成部分有哪些?
主要兩大模塊:
序號 模塊 釋義
1. SWIM(serial wire interface module) 單線接口模塊(劃重點)。
SWIM 的接口是一個基於異步、強灌電流(8mA)、開漏、雙向通信的單線接口。
2. DM(debug module)
2)STM8調試系統存在的意義何在?
STM8調試系統接口,允許被調試或編程工具通過單線連接,進行雙向通信;該調試接口提供對STM8的RAM和外圍設備的非侵入性讀/寫訪問。
3)調試系統的結構框圖長啥樣?
如圖:
4)SWIM都有哪些功能?論SWIM的工作模式
注意:
在STM8上電覆位時,SWIM自動進入OFF模式,STM8內部低速RC時鐘自動啓動,並強制保持打開。
只要SWIM處於OFF模式,SWIM仍然可以檢測激活序列,無論是復位期間還是程序運行期間;
工作模式 概述
OFF模式 該模式下,SWIM管腳不能當作IO口,等待進入激活序列或者切換到IO模式
I/O模式 可置位MCR寄存器的IOM位來進入該模式。當作IO腳後,無法使用內部的調試器來使用系統調試功能
Active模式下 在OFF模式下,通過特定序列激活進入該模式。
SWIM的激活流程圖:
SWIM激活序列
激活序列起於高電平,終於高電平。
兩組脈衝
4個頻率爲1KHz的脈衝
4個頻率爲2KHz的脈衝
注意:
經過實驗,使用750Hz和1.5Khz脈衝組合序列也可完成SWIM的激活,但儘量使用官方文檔提供的脈衝序列組合激活SWIM。
5)如何激活SWIM?SWIM激活步驟(如圖:SWIM激活時序圖)
序號 任務
0. 拉低stm8的rst管腳,//>mdelay(10)
(1). 拉低stm8的swim管腳,至少16us,//mdelay(1)
(2). A9 Soc向stm8灌輸swim激活序列
(3). A9 Soc開始監測swim管腳的輸入
(4). A9 Soc等待stm8的swim的16us的低電平同步信號(swim檢測到激活序列後,進入Active模式,內部高速時鐘開啓)(128*HSI = 16us)
(5). A9 Soc拉高STM8的swim管腳 //>300ns
(6). A9 Soc向STM8的0x7f80地址(SWIM_SCR寄存器)寫0xa0的數據;
1.設置位5,使能整個內存空間和SRST命令可以訪問。
2.設置位7,屏蔽內部復位源
//寫後最好間隔一會兒//10ms
(7). A9 Soc拉高STM8復位管腳,至少等待1ms來讓STM8裝載其配置參數 //>1ms
(8). 一旦設備穩定一切正常,STM8的cpu將進入“第8階段”:
1. STM8將被暫停,HSI爲16MHz(更精確的HSI詳見具體產品手冊)
2. SWIM時鐘爲HSI/2=8MHz
3. SWIM被激活,其通信方式進入“低速位格式”
SWIM激活時序圖
6)其他Soc如何同STM8的SWIM模塊進行通信?swim位格式 - 低速位格式
22個HSI振盪週期表示1bit數據
數據0/1的表示 低速位格式表達(SWIM模塊對應解碼規則)
數據0 20個0脈衝後接着2個1脈衝(連續的0脈衝大於等於9個)
數據1 2個0脈衝後接着20個1脈衝(連續的0脈衝小於等於8個)
2. 如何訪問STM8的Flash
暫停CPU
Flash關閉寫保護、解鎖
然後以頁的形式,按地址進行讀寫訪問
1)STM8的內部Flash簡介
一頁64bytes
最大128頁
Flash解鎖(使用"選項字"來控制,類似於控制命令)
2) STM8的Flash的WOTF(write-on-the-fly)
略,詳見附附件手冊和代碼實現;
static int swim_send_unit(unsigned char data, unsigned char len){
signed char i=0, j=0, retry=1, cnt=0;
unsigned char p=0, m=0;
#define SWIM_SEND_CHECK_TIMEOUT 300
for(retry=1; retry>0; retry--){
swim_set_output_high();
swim_send_bit(0);
p = 0;
for (i=len-1; i>=0; --i){
m = (data >> i) & 1;
swim_send_bit(m);
p += m;
}
swim_send_bit(p&1); // parity bit
swim_set_input(); //check ack
for(cnt=0; cnt<SWIM_SEND_CHECK_TIMEOUT; cnt++){
if(!swim_get_input_val())
break;
}
if(cnt>SWIM_SEND_CHECK_TIMEOUT){
j++;
printk(KERN_ALERT "St8 Bug: No ack.try again...\n");
if(j > 3){
swim_set_output_high();
return -1;
}else
continue;
}
time_ndelay(1000); //125*8ns
if(swim_get_input_val())break;
time_ndelay(1750);
}
swim_set_output_high();
return (retry<=0);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#define SWIM_CMD_LEN 3
#define SWIM_CMD_SRST 0x00
#define SWIM_CMD_ROTF 0x01
#define SWIM_CMD_WOTF 0x02
static int swim_write_buf(unsigned int addr, char* buf, unsigned int n){
unsigned int i = 0;
if(swim_send_unit(SWIM_CMD_WOTF, SWIM_CMD_LEN))return -1;
if(swim_send_unit(n, 8))return -2; //N
if(swim_send_unit(0, 8))return -3; //@E
if(swim_send_unit((addr>>8)&0xff, 8))return -4; //@H
if(swim_send_unit(addr&0xff, 8))return -5; //@L
for(i=0; i<n; i++){
#if 0
if(!(i%8))
printk(KERN_ALERT "addr(%#x-%#x):|%#x %#x %#x %#x %#x %#x %#x %#x|\n", addr+i, addr+i+7, buf[i], buf[i+1], buf[i+2], buf[i+3], buf[i+4], buf[i+5], buf[i+6], buf[i+7]);
#endif
if(swim_send_unit(buf[i], 8))break;
}
if(i<n)return -6;
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
3)向STM8的Flash中寫入固件的步驟:
假設
STM8的固件大小爲size(單位爲bytes)
固件大小換算爲頁爲:pageCnt = size/64 + (((size%64) > 0)?1:0);
序號 讀寄存器 寫寄存器 值(讀/寫) 目的
1. 0x7f99 0x08 DM_CSR2寄存器,暫停cpu
2. 0x5062 0x56 FLASH_PUKR寄存器,關閉寫保護
mdelay(1) 延時
3. 0x5062 0xae FLASH_PUKR寄存器,解鎖Flash
mdelay(10) 延時
4. 0x505b 0x01 FLASH_CR2寄存器,啓用標準塊編程操作(自動第一次擦除)
5. 0x505c 0xfe FLASH_NCR2寄存器,僅啓動塊編程操作
6. 0x8000+n*64 fileBufPointer + n *64 指定位置按塊寫數據
7. 延遲10ms, 等待該頁數據完全刷入Flash
4)按頁寫Flash示例
for(int i=0; i<pageCnt; i++){
if(write_byte(0x505b, 0x01))return -4;
if(write_byte(0x505c, 0xfe))return -5;
if(write_buf(0x8000+i*64, buf+i*64, 64))return -6;
mdelay(10);
}
1
2
3
4
5
6
五、注意點和問題總結
1) 問題1 - 電源問題
問題情景:
STM8復位時使用Soc的pin復位時,系統重啓;示波器顯示swim的電壓波動偏幅大;
問題分析和解決:
可能是電容放電太快,波動了系統的電源穩定性。調整了一些外圍硬件,問題解決。
2) 問題2 - 標準pinctrl子系統並不好用
問題情景:
使用sunxi封裝好的pinctrl子系統操作gpio管腳,管腳上電平跳變的耗時在50us左右,pinctrl操作會影響入口時序的準確性,因爲STM8的SWIM對激活時序要求還是挺嚴格的,
在使用pinctr的時候很容易出現瞬低毛刺(可能其內部同時操作一系列相關寄存器時,波及了管腳的電平輸出,可見Allwinner在硬件的設計上有一些問題),如圖(在拉高rst和swim的時候,很明顯分別出現了瞬低毛刺):
(圖中上邊爲RST,下邊爲SWIM信號線的信號)
問題分析和解決:
操作了過多的相關寄存器,我們可以自己封裝控制GPIO的接口,儘量減少對不必要寄存器的控制,以減少Soc硬件出錯的機率,以減少操作過多寄存器所消耗的時間
3)問題3 - 示波器精度和ST的STM的SWIM入口激活序列
激活序列的時鐘組合之間的要精確,pin相關寄存器的控制耗時也要算進去。
帶寬和採樣率比較低的示波器,不要高級示波器採集的波形更準確利於開發,如圖:
泰克示波器(100M帶寬和1G的採樣率)截獲的激活時序(8個脈衝)和激活後16us的低電平應答(局部放大後顯示得不精確)
Tek的示波器在抓波形的時候縮放太大的時候會抓不到有用的高速脈衝,如縮放爲每格25ms就抓不到本來應該存在的stm8的應答脈衝(20us高電平過後的,約爲16us的低電平纔是應答)。
安捷倫(300MHz帶寬和2G的採樣率)示波器截獲的激活時序(8個脈衝)和激活後16us的低電平應答(局部放大後也很精確)
我還能說什麼,一分價錢一分貨,還好手頭有兩種示波器,硬件設備夠硬才能搞開發。
4)問題4 - 權威
問題情景:
大部分人在遇到問題且一時半會解決不了的時候都會抓狂,項目組其他人鼓動你嘗試各種突發奇想。
問題分析和解決
對於別人的意見要思考推敲,不可一票否定別人寶貴建議和意見也不能過於依賴相信同事的個人見解;要依據權威的官方的協議,冷靜思考,結合實際情況和大家的經驗來調試。
5) 問題5 - 系統已用資源的重複使用
問題情景:
使用Soc上的timer0結合spin_lock_irq使用,鎖定Soc定時的時間時和linux系統衝突:(系統出現如下信息)
[ 1032.550012] INFO: rcu_bh detected stalls on CPUs/tasks: { 3} (detected by 0, t=6020 jiffies)
[ 1032.559958] INFO: Stall ended before state dump start
[ 1038.960011] INFO: rcu_preempt detected stalls on CPUs/tasks: { 3} (detected by 0, t=6021 jiffies)
[ 1038.970001] INFO: Stall ended before state dump start
[ 1227.650009] INFO: rcu_bh detected stalls on CPUs/tasks:
[ 1227.656042] INFO: Stall ended before state dump start
[ 1227.660007] INFO: rcu_preempt detected stalls on CPUs/tasks: { 3} (detected by 0, t=24890 jiffies)
[ 1227.660020] INFO: Stall ended before state dump start
[ 1407.850025] INFO: rcu_bh detected stalls on CPUs/tasks: { 3} (detected by 5, t=43550 jiffies)
[ 1407.860012] INFO: Stall ended before state dump start
[ 1407.860012] INFO: rcu_preempt detected stalls on CPUs/tasks: { 3} (detected by 5, t=42910 jiffies)
[ 1407.860012] INFO: Stall ended before state dump start
[ 1588.080030] INFO: rcu_bh detected stalls on CPUs/tasks: { 3} (detected by 4, t=61573 jiffies)
[ 1588.090019] INFO: Stall ended before state dump start
[ 1588.090019] INFO: rcu_preempt detected stalls on CPUs/tasks: { 3} (detected by 4, t=60933 jiffies)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
問題分析和解決:
timer已經被系統佔用,改用pwm的脈衝來精確計時,達到軟件精確延時(納秒級延時)的目的。
6) 問題6 - STM8的固件的UART通信訪問時間問題:
問題情景:
stm8的次命令7執行後需要延時1s後才能響應
問題分析和解決:
這個指令執行時會消耗時間,因爲需要操作交換機芯片並等待操作完成,詳見STM8固件源碼
六、附件
文件
1. EN-STM8_SWIM_Communication_Protocol_And_Debug_Module
2. STM8S_Flash_and_Control_System
3. STM8S_Series_Registers
4. STM8SAnd8AProgrammingManual3.4
七、注意:
不足之處還望指正,多多留言
如需轉載,請註明出處,謝謝~
————————————————
版權聲明:本文爲CSDN博主「LadiesMan929」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/u010014090/article/details/88852347