2013年12月27日 星期五

Optimal program and debug trace

 
程式的執行速度和所佔用的記憶体空間這兩個是決定系統中的效率。
 
其中ROM/RAM 及處理器的頻率有必要的關連性。
 
在嵌入式系統中,程式的執行速度比程式所佔用的記憶体空間顯得更重要。
 
1. 這是因為嵌入式系統是針對某一特定應用所開發的,而且大多平台可定址的範圍也同於PC;但在處理器速度上卻有很大的差距。
 
2. 而且,程式的memory size是比較好控制的因素,而程式執行中佔用多少處理器時間,則比較難量測的。
 
所以,我們可以將程式中犠牲某一特定的儲存容量來換取程式執行速度。
 
其中以查表法為例,(這個不止在一般的嵌入式系統中,這也用於在晶片設計上,FPGA),用於數學函數的處理(正弦、餘強表及對數等)
 
A.查表法
如何在4-bits的數值求有幾個位元為 ' 1 '.
int getnumber(unsigned int a)
{
    int i, num = 0;
    unsigned int temp = a & (0x0f);
 
    for(i = 0; i < 4; i++)
        if((temp >> 1) & 0x1)
        {
            num++;
        }
 
    return num;
}

 


const int table[16] ={0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4};
int getnumber(unsigned int a)
{
    return table[a];
}

 

B.迴圈

迴圈的執行的次數,是C中最常遇到的也同樣是可以來提高效率的地方。

 

像這個範例,

1.條件變數最佳化:


void change_list_value()
{
    int i;
    POSITION pos;
    CPtrList* plist;
    plist = get_start(pos);
 
    for(i = 0; i < get_count() ; i++)
    {
        plist = get_next(pos);
        set_val(plist);
    }
 
    return 0;
}

這個中,每次get_count()並在裡面得到下一個位址並再去做設定的動作,所以呼叫了三次的函式這對於嵌入式的呼叫時會去對暫存器做暫存。

 


void change_list_value()
{
    int i,count;
    POSITION pos;
    CPtrList* plist;
    plist = get_start(pos);
    count = get_count();
    for(i = 0; i < count ; i++)
    {
        plist = get_next(pos);
        set_val(plist);
    }
 
    return 0;
}

若改變函數中的呼叫流程,這樣可以減少呼叫次數。

"在迴圈運算中,對於迴圈條件,可以使用臨時變數"

 

2.迴圈展開最佳化:


void change_list_value()
{
    int i, count, total;
    POSITION pos;
    CPtrList* plist;
    plist = get_start(pos);
    count = get_count();
 
    for(i = 0; i < count ; i++)
    {
        plist = get_next(pos);
        total += set_val(plist);
    }
 
    return total;
}

而若每次迴圈內容的各種運算所佔的百分比,若要減少次數則要增加迴圈中運算則可能造成程式設計問題。

因此可以修正為,


void change_list_value()
{
    int i, count, total;
    POSITION pos;
    CPtrList* plist;
    plist = get_start(pos);
    count = get_count();
 
    for(i = 0; i < count+2 ; i++)
    {
        plist = get_next(pos);
        total += set_val(plist);
 
        plist = get_next(pos);
        total += set_val(plist);
    }
    //處理最後的
    if(i < count )
    {
        plist = get_next(pos);
        total += set_val(plist);
    }
    return total;
}

 

C. 小數點運算:

    在應用程式中,不僅需要整數及邏輯運算,也要浮點運算。像是float、double(實數)等來表示小數點。

若在不支援浮點運算的平台中使用了double,在compiler會哹叫一些滇算法來處理來代取。

 

"C語言中,int、long、short表示整數(整數),而float、double而浮點數(實數)。

 

而其中,並不是整數及小數的差別,而是' 小數點是否根據需要移動"

 

EX:

      對於一個2位數的十進位數字,可以表示0~99個數數值,也可表示為0.0 ~ 9.9這帶有小點的100個實數以及 0.01 ~0.99。這完全取決程式者認為小數點在什麼位置。 如果直接使用浮點數,對系統浪費很大的。

 

     所以可在某些場合中可以使用 " 定點數" 來代表 "浮點數"。

 

利用定點數表示浮點數的本質是使用整數型資料代替浮點數,進行定點的小數點運算。 從理論上,定點小數點和整型數的記憶體格式是一樣的。

 

整型數與浮點數的區別在於整型數表示資料範圍比較小,實際上,整數型的資料只需要加上知道小數點位置就可以表示小數點。

 

Q16格式的資料,小數點在16bits上。 例如 :一個32 bits,若以hex 表示成0x52C00。

而以Q16格式則為

0x 0005 | 2C00。

十進位== 0x 5.2C == 5 x2^0 + 2x 2^-4+12 x 2^-16 =5.171875

 

所以,可以用Q格式來表示浮點數。來節省資源浪費,只是用定點數表示浮點數的缺點表示數的範圍變小。(但需要記往小數點位置)。

 

但到底是否需要使用定點數表示或是直接用浮點數,需要看運算內容 ,如下:

 

EX:

求 3個浮點數並以 它所佔的權重求其總數。

 

a           90.24      32.6%

b           75.45      41.3%

c           80.36      21.1%

 


float  getvalue(float a, float b, float c)
{
    float sum = 0.326 * a + 0.413 * b + 0.261 * c;
    return sum;
}

 

但這樣的運算是不需要用到浮點運算,可將其權重轉成整數(乘上1000倍)

 

p.s : 不/可重入函數;


void swap1(int *i,int *j)
{
    int temp;
    temp= *i;
    *i=*j;
    *j=temp;
}
 
int temp;
void swap2(int *i,int *j)
{
    temp= *i;
    *i=*j;
    *j=temp;
}

swap 1為可重入,即可被中斷,因為其temp是被存在stack中。

而swap 2則為global所以可能被其的改變。

 

 

D.程式的除錯和巨集使用技巧

 

1. 列印檔、函數和程式列:

    它所使用的是各編輯器的巨集。

如下:


#define APP_ERROR_HANDLER(ERR_CODE)                         \
    do                                                      \
    {                                                       \
        app_error_handler((ERR_CODE), __LINE__, (uint8_t*) __FILE__);  \
    } while (0)

其中__FILE__、__LINE__。利用這些來得到除錯資訊。而且這些是compiler自己產生而不是變數定義。


2.# : 字串化運算子.

在gcc 的preprocesss中,可以使用"#"將當前內容轉換成字串。

 


#define dprint (expr) printf("<main>%s=%d \n",#expr,expr);
 
char a = "1";
 
dprint(3 / 4);
dprint(a);
dprint(123);
//------------------------
 
<main>3 / 4 = 0;
<main>a     = 321300;
<main>123   = 123;
 

它的優點是可以用統一的方法列印運算式的內容,所以程式中可以方便直觀地看到轉成成字串之後的運算式。


#define dprint (expr) printf("<main>%s=%d \n",#expr,expr);
#define dprintc (expr) printf("<main>%s=%c \n",#expr,expr);
#define dprintd (expr) printf("<main>%s=%f \n",#expr,expr);

3. ## :連結運算子.

在gcc 的preprocessor中,它將實作字元串連的運算。


#define test(x) test## x
 
void test1(int a)
{
    printf("test 1 integer:%d\n",a);
}
 
void test2(char* a)
{
    printf("test 2 string:%s\n",a);
}
 
void main(void)
{
    test(1)(100);
    test(2)("abc");
}
//--------------
test 1 integer:100
test 2 string:abc

因為是preprocess所以是在做代取字串而已,

test(1)(100):先test(1) 對應macro

 

#define test(x) test## x , 變成test1。

另一個使用範例為:

#define DPRINT(fmt,args...) printf(fmt,##args)

使用DPRINT代替printf使用。而且preprocess中將二個參數以##連結。

而其中##表示連結可變的參數列表;fmt則為其格式。

即因為在macro中想要其參數(可變參數)傳給代取的字串。

所以不能明確地指定其那個參數對映,故以##做連結。

--------------------------

最後,我們要將其上面的#及## 整合在一起。做出除錯巨集:

如下:



#define DEBUG_OUT1(fmt,args...) \
{ \
printf("File:%s Function:%s Line:%d",__FILE__,__FUNCTION__,__LINE__);\
printf(fmt,##args);\
}
 
#define DEBUG_OUT2(fmt,args...) \
{ \
printf("File:%s Function:%s Line:%d"fmt,__FILE__,__FUNCTION__,__LINE__,##args);\
}
 
 

















而其使用的方式:



int a=100;
int b=200;
char *s= "string";
DEBUG_OUT("a= %d;b =%d \n",a,b);
DEBUG_OUT("%s",s);
//DEBUG_OUT(s);error
//------------------
File:main.c Function:main Line:155 a=100;b=200
File:main.c Function:main Line:156 s= string


===================


對除錯程式碼進行分級審查


在定義除錯的巨集,在工程大時,可能會導致其輸出訊息過多。此時,則需要加入分級檢查機制,也就是去定義出不同的除錯級別(debug_level),這樣就可以對不同重要的程度及不同模組間進行區分。


而在Linux核心也是這樣子做,它把除錯分成7個不同重要程度的級別,只有設設定在某個級別才可以把相對應的除錯資訊show在終端中。



void show_debug()
{
    int level;
    if(level == XXX_MODULE)
    {
#define DEBUG_OUT2(fmt,args...) \
            printf("File:%s Function:%s Line:%d"fmt,__FILE__,__FUNCTION__,__LINE__,##args)
 
    }
    else
        ....
}
 
#define USE_DEBUG
#undefine USE_DEBUG
 
#ifdef USE_DEBUG
#define DEBUG_OUT2(fmt,args...) \
            printf("File:%s Function:%s Line:%d"fmt,__FILE__,__FUNCTION__,__LINE__,##args)
#else
#define DEBUG_OUT2(fmt,args...)
#endif
 
#define USE_DEBUG 1
#if USE_DEBUG ==1
#define DEBUG_OUT2(fmt,args...) \
            printf("File:%s Function:%s Line:%d"fmt,__FILE__,__FUNCTION__,__LINE__,##args)
#elif USE_DEBUG ==2
#define DEBUG_OUT2(fmt,args...)
#endif

2013年12月21日 星期六

建立嵌入式系統-1

我一直在想不論是誰,經過一小小段時間的磨練。好像都可以成為韌體工程師。

比如我目前所在的,怎麼連一個碰都沒碰過的,經過2~3月就可以handle一個案子了。

 

若是如此,那本科的到底差在那裡了。

我想除了,

上手的時間外,以過去經驗來學習新東西及解決問題能力外。

個人覺得還在個更為重要的"正確的開發方法"。

"若只是時間的問題;那還有什麼價值的"

因為時間才是重點。

但雖然我知道,卻不知如何去做起。只能不斷不斷地亂吸收有的沒的資訊。

這本"建立嵌入式系統-傑出軟體的設計模式"

是一本相當不錯的書我想就從這開始吧。

裡面的內容有系統架構、硬體(測試及處理錯誤)、輪出及輪入與計時器、動作流程(排程、事件、中斷)、週邊通訊、更新程式、

功耗、數學(嵌入式)

--------------------------------------------------------------------------------------------------------

就像是解數學(在設計時也應該把它現象具現化數值化),問題、變數及條件。

Q.

開關去抖動(Deboucing switch)

var.

其持續時間的長短(取決於使用的開關)

需考慮程式寫法,可能會有多個。

limit.

反應時間.

 

1.問題分析

按鍵debouce,我們都知道的東西。但我們只知加上個delay time去判斷有效否? 沒有詳細去觀察它。

它正確名稱為" 跳動數位按鈕訊號,bouncy digital button signal",而不論是採用poll or interrupt對這個都會

產生反應,而系統對 開關抖動(switch bouncing)的原因來自機械或電子效應。

image

可以見到其中有3個不確定的狀態 都是在上/下邊緣時的雜訊,這些就是抖動bounce現象。

而要去除這些則需要比反應取樣,並出現連續一致的就系統按鈕狀態已經改變。

2.條件(需求)

以一般的打字來算,平均一分鐘120字(每字5個字元)。即一分鐘按600次,故10 time/s=100ms。

而系統必須在一半的時間內判斷按下按鍵,所以是50mS。

加上其所使用的按鍵的datasheet,對於按下/放開的時間(設12.5 ms 內),則可以知以10mS(低於反應時間)

約有5次的sample來判判。

3.變數

由持續時間的長短,:

    The current raw reading of the I/O line(raw data)
    A counter to determine how long the raw reading has been consistent (counter)
    The debounced button value used by the rest of the code (debounce button)

ps.因程式簡化,新增一個changed變數。

read button:
if raw reading same as debounced button value,
    reset the counter //counter set number,no change,long press
else
    decrement the counter
if the counter is zero,
    set debounced button value to raw reading
    set changed to true
    reset the counter
    
main loop:
if time to read button,
    read button
if button changed and button is no longer pressed
    set button changed to false
    set the delay period (reset or halve it)
if time to toggle the LED,
    toggle LED
repeat



 


另一個例子是:


使用計時器


現在有一個要求是,每按下按鈕時改變LED閃爍的速度(6.5,8.5 and 10Hz)。


background:


其中 要求來關關LED,需以需要時間的"精確度"。


而系統中精確度來自輸入時脈(clock)的" 正確性" 及" 準確性"。


計時器的組成:


image


image



其中,Prescale register(預先倍率暫存器)是相當重要的一點,


將時脈值除以特定數字,讓計時器以較慢的速度增加。


問題:


現在有一個要求是,每按下按鈕時改變LED閃爍的速度(6.5,8.5 and 10Hz)。


條件(需求):


6.5,8.5 and 10Hz。容許誤差範圍。


其各timer register的設定範圍。(8bit/16bit)


變數:


main clock souce and how much? (4MHz)


各timer的register設定。(prescale register(預先倍率),time counter(輸入頻率),compare register(比對) and action register(動作))


 


由以上可以得到。


timerFrequency = clockIn/(prescaler * compareReg)


在已知clock In,只需改prescaler 及compareReg來得到其timerFrequency


 


其中,以10Hz閃爍(on/off)所以需要20Hz來on or off動作。


A.若不使用prescale (set =1)則 其compareReg = 4M/(20)=2x 10^5(超過compareReg大小255)


B.而prescale (1023,10bits),可以先求prescaler * compareReg的總數再找各別的,所以


    prescaler * compareReg= 4M/20,


    prescaler(8bit) * compareReg(10bit)=200,000, compareReg set 200, prescaler set 1000


另一個8.5Hz,若以相同的話?


    prescaler * compareReg = 4M/17 = 235294.1


    set prescaler = 923, compareReg =


因為沒法整除,所以必須將誤差代入(以最好計算)


error = 100*(goal frequency – actual)/goal


所以要以疊代計算。


image


          |                         |


          |                        \/


          | <--------------  set new prescaler


        


image



 


Pulse Width Modulation (PWM)


若有一個新增一個按鈕來控制亮度。


image

2013年12月17日 星期二

嵌入-1-迴圈緩衝區

最近,有同事在處理IR訊號的擷取及處理。有聽到對於緩衝區的部份,所以整理一下這部份的內容:

 

迴圈緩衝區

image

在某些DSP系統中,可以支援迴圈緩衝區的硬體,向其中放置資料時,不需考慮是否緩衝區填滿。而一般的嵌入式系統中並無這種的硬体機制。

可以簡單的推導,若要實現則必須在每次的都在迴圈中判斷緩衝區是否放滿了。

但會付出一些代價,而且在某些時候影響很大。(取樣處理問題)

以下,是以另一方式處理:

#define BUFFERSIZE 256
int x[BUFFERSIZE];//static ,stack and heap
 
unsigned int k; //mask 00001111
unsigned int i; //acc  xxxxxxxx =k只取i後n bit
 
while(1)
{
     k=i&;(BUFFERSIZE-1);
     x[k]=Imput();
     ........
     i++;
}


從程式中可見,x[]是程式用來做緩衝區的使用。而於是全域且非初始化(BSS)段。


 


在程式中,i用來做累加的作用。而k做為緩衝區陣例的下標。


因此,k應在0~BUFFERSIZE –1的範圍內。而每次變數i累加後再與k做 "&"來得其緩衝區的下標k。


image


k= i & (BUFFERSIZE-1);


使其k只取i後的n位元的資料。


使其緩衝區的大小必須為2的整數次冪,來使得可用位元"&及"來罩掉。(i大於256時,k得0)


 


由於上述程式不需要使用if 判斷,可以節省幾道程式。但在這一區塊中它所佔的比重還是很大。特別在程式需要指定時間內完成的及 執行頻率比較高的。


------------------------------------------------


在看了如何處理loop buffer後,應該要配合週邊裝置做結合才行。


剛好也找到一些資料,加以整理。


--------------------------------------------------


資料驅動系統(data-driven system),目標是取得資料加以處理,再對結果作動作週而復始。


所以它不存在事件(event),只有持續地增加等待系統處理的資烞。


所以系統處理應比產生的速度快。


"系統主要的特性在於資料量與產生速度"


任何重新啓動和錯誤會讓系統處理落後,能不能優雅地失敗對這類的系統十分重要,如果有錯誤會造成系統處理落後,系統


是否要跳過部份資料追上最新內容? 或是應該改為某種簡化過的處理等待系統恢復? 跳過部份會造成什麼後果?


 


環型緩衝區:


實作data -driven system中主要以環型緩衝區的策略(FIFO, First In First Out)。


生產者以某個速度將資料放入環型緩衝區,消費者以相同的平均速率取出資料,消費者可以一次取出大量資料,但生產者放入時只能一個個放入(也可相反),並讓處理器在資料達到演算法所需大小後進一步處理。


image


其中變數有:


使用的長度、下一個寫入位置(write or start)及下一讀取位置(read or end)。


在write = = read ==> empty or full?


解決方式有:


A. 設定當write 在落後read 一個位置時就表示滿了. read =0 , write 7 , Full


B.多一個變數,write +1 ; read –1 ,full var = buffer lenght –1, Empty var= 0.


 


而在data driver system中,大多其中一個必為中斷(生產或消費); 另一者則非中斷。所以為了讓生產及消費者使用的獨立,


必須要在"讀取及寫入指標"的更新是 單元操作(atomically)才能使用環型緩衝區不被中斷。


但在指標到緩衝區時會折回,這時以一般方使(餘數 %, if判斷)會使得無法使用 單元操作(atomically)。


 


可以將其環型緩衝區大小設為 2的次方大小。



struct sCircularBuffer {
tElement *buf; // block of memory
uint16_t size; // must be a power of two
uint16_t read; // holds current read position: 0 to (size-1) 
uint16_t write; // holds current write position: 0 to (size-1)
};
uint16_t CBLengthData(struct sCircularBuffer *cb) 
{
/* **********
|-----|----------|-------|
write read
*/
int32_t length = cb->;write - cb->read;
if (length >; 0) return length;
/*
bbbbbb aaaaaaaa 
|-----|----------|-------|
read write
*/
return (cb->;size – cb->write) + /* aaaa */
(cb->;read); /* bbbbb */
}
 
uint16_t CBLengthData(struct sCircularBuffer *cb) 
{
return ((cb->;write – cb->read) & (cb->size - 1));
}
其中需將其read /write設為

(cb->write – cb->read) & (cb->size - 1)
= ( 5 – 6 ) & ( 8 - 1)
= ( -1 ) & ( 7 )
= ( 1111 1111 ) & ( 0000 0111 )
= 0000 0111 = 7



enum eError CBWrite(struct sCircularBuffer *cb, tElement data)
{
if (CBLengthData(cb) == (cb->;size-1)) { return eErrorBufferFull;}
cb->;buf[cb->write] = data;
cb->;write = (cb->write + 1) & (cb->size - 1); // must be atomic 
}
 
enum eError CBRead(struct sCircularBuffer *cb, tElement *data)
{
if (CBLengthData(cb) == 0) { return eErrorBufferEmpty;}
*data = cb->;buf[cb->read];
cb->;read = (cb->read + 1) & ( cb->size - 1); 
}

而在setting "write/read"在不同系統32/16/8 bits. 通常只有16bits一定是單元操作其它的則需去確定。


 


在build Ring-FIFO後,使用者可以read其資料並加以複制memcpy並釋放free。


但這也會造成其浪費,若要將資料保留在原處並只有處理後才是真正釋放free時,則需新增一個 “Free”


image


image



enum eError CBFree(struct sCircularBuffer *cb)
{
if (CBLengthReadData(cb) == 0) { return eErrorBufferEmpty;}
cb->;free = (cb->free + 1) & (cb->size-1); 
}

 


---------------------------


image


To implement a system like that, you'd need to add one more pointer to the system
called processed. As the pointers move independently of on another, adding another is
fairly straightforward. The code is nearly the same as we added for CBReador CBWrite.
Don't forget to add a new length function(s) too.

 


硬体:buffer


檢查碼:


 


p.s:其它有


stack,BSS and heap

2013年12月8日 星期日

有線~無線楖論(4)

有線~無線楖論的最後,才要提我的主要目的

即無線網路系統中的內容。

以下是我從整理出的內容:http://www.techbang.com/posts/15863-introduction-to-network-infrastructure-5-80211-and-80211a?page=1

 

無線網路的規格定義在IEEE 802.11(有線則是802.3)。

定義:

IEEE 802.11定義了運作頻率設定在2.4GHz。會選擇這個頻率是因為2.4GHz屬於ISM(Industrial, Scientific and Medical radio band,工業、科學以及醫療無線頻段),

 

資料表示 : 格雷碼

格雷碼(gray code)

十進位數字轉為二進位時,0、1、2、3、4、5、6、7、8、9分別會轉換成0000、0001、0010、0011、0100、0101、 0110、0111、1000、1001。但在通訊世界裡則是採用格雷碼,所以0∼9會被轉換為0000、0001、0011、0010、0110、 0111、0101、0100、1100、1101,由於各組之間只有變換1個位元,可以降低傳輸時出錯的機會。

(假設以二進制為0的值做為格雷碼的0)
G:格雷碼 B:二進制碼
G(N) = (B(n)/2) XOR B(n)

 

展頻

data link layer:

802.11在媒體層(data link,定義出其CRC這種檢查及Frame大小)的部分採用CSMA/CA(Carrier Sense Multiple Access with Collision Avoidance)(**RTS/CTS(Request To Send/Clear To Send)。

physical layer :

展頻(Spread Spectrum)的概念,展頻就是把1組資料量較少的資訊,加以放大並放在1組資料量較多的資訊上,好比把1MB的資料,增肥到10MB的大小,但內部包含的實際資訊卻跟1MB沒有兩樣。這麼做當然對於傳輸速度是有害的,但在無線網路的環境中,有些事比起傳輸量來說更需要克服。

展頻有許多好處,第一就是對抗雜訊,由於生活環境中充滿許多電磁波,甚至是地球或是外太空也都會來尬一角。舉個簡單例子,展頻之後使用 11111111代表原始的1、00000000代表原始的0,如果今天好死不死11111111被干擾成10111110,也可以辨識出這其實是代表 1。第二就是可以用來隱藏或是加密訊號,通常我們想要傳輸的資料只占據一個相當小頻寬的基頻訊號,利用展頻技術把基頻延伸到大範圍的頻帶上,讓傳輸能量降低成與背景值差不多,避免引起他人注意;此外把這個把原始信號與加密信號經過一翻計算後傳送出去,只有擁有加密信號的人能夠解出原始訊號,其他人看到就只是一些無意義的資料。

而且展頻之後,可同時容許多人在同一頻率中進行通訊,大家的頻寬都是相等的,這就是所謂的CDMA(Code Division Multiple Access,分碼多重存取)。

CDMA

雖然CDMA沒有使用在802.11之中,但由於CDMA的原理相當神奇又有趣,容筆者在此先說明一下。想要使用CDMA,則此網路中的每個節點都必須要有1組編碼,而大家的編碼必須兩兩呈現正交的性質,內積值必須為零。假設現在有2組節點,A的編碼為[1、1]、B為[1、-1],兩者經計算後的內積值為零,符合正交的要求。如果今天A要傳送1,則經過CDMA編碼後變成[1、1];如果要A要傳送0,則是取補數[-1、-1],B的原理也是一樣。

如果今天A點傳送1[1、1]、B傳送0[-1、1],兩者在空氣介質中向量合變成[0、2];某C點想要解出[0、2]的資訊,便把[0、2]和 A[1、1]、B[1、-1]作內積,得出2和-2。在大於零等於1、小於零等於0、等於零沒發射訊號的原則下,得知A發出了1、B發出了0。

 

FHSS

802.11在2.4GHz傳輸頻率中定義的展頻方式有2種,一種是FHSS(Frequency-Hopping  Spread  Spectrum,跳頻展頻),另一種則為DSSS(Direct-Sequence Spread Spectrum,直接序列展頻)。

FHSS跳頻機制,FHSS需要一段較大的頻寬,再將這個頻寬切割成許多較小的頻寬,就可以在這些不同的小頻寬之間不斷切換傳輸,就是FHSS的跳頻機制。在802.11中,使用FHSS展頻使用2.4∼2.4835GHz頻帶,將其以1MHz的方式切出頻道,每個頻道的停留時間為19TU(Time Unit、1TU=1024μs)。事實上使用頻率範圍、切割的頻道數、各頻道駐留時間以各國規定為準,像是美國FCC聯邦通訊委員會就制定出75個以上的頻道數和最大駐留時間為390TU。

image

DSSS

DSSS直接序列展頻顧名思義,直接將欲傳輸的0或是1代換成1串序列碼傳送出去,實際代換的方式為域傳送的資料位元值與虛擬雜訊碼進行XOR運算,而虛擬雜訊碼在此使用巴克碼(Barker code)。

image

調變(modulation)

想要傳遞的資料經過展頻之後,接下來便是要如何把資料放在載波(carrier)上,而把1010111110111011010101⋯⋯這類的二元碼變成實際在介質中傳播,就稱為調變(modulation),無線網路就是變為電磁波傳送,光纖則是以光來傳送

調變大致上可分為2種,分別為類比調變和數位調變。類比調變的例子就是收音機的調幅(AM)或是調頻(FM),波形雖然有振幅或是頻率上的變化,但波形是連續的,不會發生這個時間點為波谷底點,下個時間點突然變成波峰頂點。而數位調變就會發生這種情形,比較像是由一段段的波形組合起來。若以道路來比喻,類比調變像是連續彎道山路,數位調變則比較像都市裡的十字路口。

image

 

GFSK

因應FHSS和DSSS不同的特性,其調變的方式也不相同。FHSS採用GPSK(Gaussian frequency-Shift Keying,高斯頻率偏移調變、高斯頻移鍵控),GFSK是FSK加上高斯濾波器組成,高斯濾波器的功用在於平滑化訊號,因此GFSK的本質還是 FSK。

FSK的調變方式相當簡單,選定一載波頻率Fc,再選定一差值頻率Fd,如果今天想要傳送1,就傳送Fc+Fd的頻率,想要傳送0,就傳送Fc-Fd的頻率即可。FHSS展頻再加上2GFSK(2種頻率變化的GFSK)可帶來1Mbps的頻寬。

如果需要2Mbps的頻寬,則是改採4GFSK,由於有4種頻率變化,可對應22種資料00、01、11、10,所以每次傳輸時由1bit改為2bit,頻寬直接翻倍。

DPSK

另外一種DSSS所搭配的調變方式為DPSK(Differential Phase-Shift Keying,相位差調變、差分相移鍵控),屬於PSK的1個分支。PSK在傳輸訊號的時候,使用的頻率、振福是相等的,差別在於相位的不同,藉由相位的不同代表不同的資訊。

所謂DPSK的D就是相差、差異的意思,所以是藉由目前波形相位減去上次相位之後的角度差異作為判斷的依據。1個完整的sin波形從 0開始,到波峰時的相位角為90度,下降到0的相位角為180度,波谷的相位角則為270度。

在802.11中使用的DPSK有2種,分別為DBPSK和DQPSK,其中B代表Binary(雙)、Q代表Quadrature(正交),DBPSK利用2種相位差表示,DQPSK利用4種相位差表示,這兩種調變正好可提供1Mbps和2Mbps的傳輸速率。

但由於使用編碼速率11M symble/sec的關係,加上DPSK調變,傳輸能量會在選定的頻率±11MHz的地方以|Sin(x)|函數的方式出現,共佔去22MHz的頻寬。這在使用11個頻道(2.412∼2.462GHz,以5MHz劃分)的國家地區使用時,僅有3個不相互干擾的頻道(頻道1、6、11)。

image

image

有線~無線楖論(3)

上篇是關於有線在embeddend system的module。而在要回到無線時,首先要談到有線的較底層的。
網路底層的訊框傳送法則,從有線的談到無線,差異及相同之處。
TCP/IP網路模型的第一層或是OSI網路模型的第二層,了解訊框實際上在有線和無線網路上傳輸的策略。
image
在Data Link Layer主要是CRC檢查及定義基本的一個訊息框(Frame)。

 

802.3

在 有線 中,網路採用802.3
OSI網路架構屬於L2資料鏈結層的CSMA(Carrier Sense Multiple Access,載波偵測多重存取)載波偵測多重存取網路通訊協定,定義在IEEE 802.3當中。
IEEE 802.3使用了一種稱為CSMA的技術作為核心,因為在較為早期的網路,線材作為匯流排看待,任何連上此網路匯流排的電腦都可以在其上傳輸資料,避免大家同時傳輸資料造成錯誤,而此規則就是CSMA。
CSMA載波偵測多重存取的規則就像其名稱一樣,為了避免在其它電腦傳輸資料時造成干擾,當某台電腦想要傳輸時,會先監聽傳輸媒介是否正在使用,如果沒有其它電腦正在傳輸,代表線路目前是空閒狀態可立即使用;如果監聽的結果是線路正在使用,則持續保持監聽狀態,直到線路空閒,這就是 CS(Carrier Sense)的由來。
當某部電腦正在傳送資料時,則所有位於匯流排上的電腦都會接收到這份資料,電腦處理與否的關鍵在於傳送訊框表頭所包含的MAC(Media Access Control)位址是否跟自己相符,如果兩者一致就接收下來進行後續的處理,不同就表示這份資料不是給我的,不進行處理。。
CSMA/CD
CD(Collision Detection)變成CSMA/CD,對於碰撞的發生進行偵測並處理,提高線路傳輸效率。

在Ethernet中,最大的架設環境下,距離最遠的兩端點訊號時間差可達232  bit傳輸時間,也就是說,當A電腦發送231bit之後,與A最遠的B電腦若已傳輸1bit,下個傳輸1bit的時間就會偵測到A電腦送來的訊號,才會偵測到碰撞發生,停止傳輸。而傳輸32  bit長度的jam signal是為了讓A電腦更容易辨識,過短的jam signal無法保證A電腦得知碰撞發生。
Ethernet訊框最短長度64  Byte也是因為232 bit的傳輸時間差而設計出來的,因為當A電腦發送之後,最遠的B電腦需要經過232  bit傳輸時間後才可收到訊號;若是碰撞發生,回傳給A電腦的碰撞訊號也要232  bit的傳輸時間,一來一往之下就是464  bit(58  Byte),為了確保A電腦佔據網路夠久的時間偵測B電腦傳來的碰撞訊號,以及電腦單位經常使用2的次方影響,就制訂出了64Byte這個最短訊框長度。
image 除了CSMA/CD外其它相關的還有:
1.隨機時間
如何 在碰撞,隨機時間二元指數後退演算法」(binary exponential backoff algorithm)
我們假設第幾次發生碰撞為n(n≦16,如果n>16,會放棄傳送訊框,並向網路架構的上一層報錯),t為n和10取最小值,r為一個倍數,r的值在0≦r<2t(n、t、r皆為包含0的正整數)。
2.CSMA監聽/發送策略
Ethernet採用1-persistent(1-堅持法),相對的還有O-persistent(O-堅持法),在這兩者中間尚有P- persistent(P-堅持法)和non-persistent(非持續法)。
3.時槽(time slot)
時槽定義為在最大網路佈建的情況下,最短的訊框從網路中最遠的2點來回1次所需要的時間,會受到網路速度(傳輸頻率)和最短訊框的大小所影響。網路速度越快、時槽越短;訊框越小、時槽越短。
 
而它的缺點在於其CSMA/CD上,當匯流排上的裝置多時其碰撞增多很多。
所以才發展出Switch出來,盡量避免了碰撞產生,以及由同軸電纜到雙絞線(半雙工 /全雙工)。
4.流量控制:
back pressure(半雙工) :
CSMA/CD的半雙工傳輸模式下,如果接收端裝置效能不足,無法快速處理傳送端送來的訊框,想要請傳送端降低傳送速率,但半雙工模式無法同時進行雙向傳輸,沒有辦法告知對方我快吐了。此時有2種作法,第一種就是直接在網路上造成訊框碰撞,對方偵測到之後就會進入碰撞之後的處理演算法,而這演算法本身就有降低傳輸速率的功效。第二種就是由接收端直接發出傳輸訊框,另一端就會以為線路上有其它電腦要傳輸。
 
全雙工:(沒有用CSMA/CD)
進步到全雙工傳輸之後,由於傳送和接收分別在獨立的線組上執行,CSMA/CD被拋棄,根本就不會產生碰撞;於是可以直接告訴對方我快滿了,請降低傳輸速度避免訊框遺失。
 

無線使用CSMA/CA

但在無線網路中,CSMA還活得好好的,因為使用空間作為介質傳遞訊號,很難限定訊號只在特定範圍內傳播。無線環境還有個相當特殊的「隱藏節點」狀況,如下圖所示。
由於無線訊號會根據傳輸距離而逐漸遞減,A、B點和基地台的距離都要在雙方的無線訊號涵蓋區之內才可進行通訊,但A、B點卻因距離問題都不在對方的訊號範圍內,無法得知對方的存在,如果同時發送訊號給基地台,基地台部分必會發生碰撞。由於無法相當有效的偵測碰撞的存在,無線傳輸無法使用CSMA/CD,而是盡量避免碰撞的發生,使用CSMA/CA(Carrier Sense Multiple Access with Collision Avoidance)。

image
在無線網路傳輸標準802.11之中,還有個選用功能能夠避免碰撞的發生,就是啟用RTS/CTS(Request To Send/Clear To Send)。
在裝置傳送無線訊號之前,會先向基地台傳送RTS訊號,請求傳輸許可,若基地台感測到目前空間無裝置使用,便會發送CTS訊號給裝置,告知其准許傳輸。如果同時有多個裝置同時向基地台發送RTS,則基地台只會給其中1台CTS訊號允許傳輸,便不會造成訊框碰撞
以上所述在無線訊號的範疇裡屬於DCF(Distributed Coordination Function,分散式協調功能),需要傳送方自行去搶傳送資源,應此又稱為競爭式服務。另外一種是由AP負責輪詢各台裝置,唯有被問到的裝置才能傳輸資訊,為PCF(Point Coordination Function,集中式協調功能),屬於非競爭式服務

http://www.techbang.com/posts/15880-4-introduction-to-network-architecture-networks-underlying-frame-relay-rule?page=3
















有線~無線楖論(2)

在前篇中 有線~無線楖論(1)中對於網路模式TCP/IP的介紹,

 

接下來是對於有線通訊在 embeddend system的

 

So Many Ways of Communicating,其中最重要的是where does the clock come from?

image

其中對於我所使用的embeddend system中,最重要的是前三層的(physical, data link and network)

簡單的話就是 。並以I2C為例

physical: 電氣特性, 其幾條線其工作電壓是多少

data link :而是CRC檢查及定義出多少bit資料為一個封包(frame)

networ: 定義IP, 即其裝置的位址,address.

 

其中physical

中可分為Serial 及parall and synchronous/asynchronous , half/full duxplex

serial 串列即指一個time slace只能傳一個單位的資料:

parall 並列即指其可傳多於1個單位的資料.

而

synchronous: 同步則指的是二端必須同時做傳送動作(同步),即使有一端是沒有資料也要傳。

                   suart(use-are) synchronous receiver/transmitter,常見的有SPI

asynchrouous: 即二端是不需要同步動作的,而是以各自講好的機制(bit rate) protcol動作。

asynchronous receiver/transmitter

half duxplex :而其線材, 若只有一條線做為transfer and recevice則為半雙工。像是I2C(SDA)

full duxplex :其recevice and transfer各有一個時,則為全雙工, SPI.(SOMI, SIMO), RS232

image

對於I2C而言:

1.clock generate:

    is generate from master, which is exlicit. and because clock generater by master so it is not precise.

2. it have 3 wires(scl,sda,gnd) ,and it connect all peripherals ,so it control complex.

3. it is asynchronous . the master and slave only one wire to transfer data.

4. half duplex , only one sda.

5. there  address. and to select the via chip.

6. 3.4M bits/sec

7.

 

data link:

一個傳送單位frame 或 檢查CRC。

NetWork :

IP , system address.

 

I2C drivers invariably include a state machine to deal with the complexity of switching
the direction of the bus between the master transmitting and the slave transmitting.
The master starts communication by sending a 7-bit address and whether it wants to
read from or write to the slave. The slave with that address then sends an acknowledgement (ACK). Next, the master sends a command to (or reads from) the slave and
the interaction proceeds. When the communication is complete, the master sends a
stop bit.

 

p.s: 上次有同事,因為datasheet沒寫明是I2C或SPI or other的通訊介面。自己認為是I2C 等porting後,才發現不會動。

可見這些的重要性。

有線~無線楖論(1)

 

前日,在量測產品的Radio Testing(FCC)時覺得自己完全不了解wireless的基礎。也剛好看一個系列在介紹網路系統。

這也正好很網路的觀點來看wirelss的一些名詞內容(module,CSMA/CD,PSK,OFDM,FHSS.ie..)

 

而從有線到 無線,都是我們日常會碰到的通訊介面。 有線的串列USB 、無線wireless (2.4G,Sub 1G, 802.11 and Bluetooth)

然而這二者的差別及相同處?

 

1.base OSI and TCP/IP module

一直以來,對於這二個modele我一直聽到。但這二者到底有什麼差別及用途,都不太清楚明確。

其實有前'後及實作'理論上的差別。

image

TCP/IP :

從名稱就知是一開始就就用的。而就實作上也是以"此"為主。

其各layer 的定義如下:以internet為主

Link Layer : RJ45 ,

位於整個網路架構的最底層,負責制定資料傳輸的「實體」規格

Internet Layer : IP ,

網路層能夠提供實體介面網路卡1個邏輯上的位置,也就是我們常聽到的IP位址,此IP位址是唯一的(或至少在同層級的網路中是如此),所以資訊才能夠傳輸到正確的目的地。此層會將資料的目的地和來源地寫入,如同我們在信件上填入收件人和寄件者。

除了賦予每個網路介面卡邏輯IP位址外,IP還定義了資料封包該如何繞送的規則,如同郵局有各地區的小據點,也有大型的轉運站,藉由這些規則,選擇較佳的傳送路徑,將東西正確傳遞

Transport Layer:

資料經過了應用層之後,下一層便是傳輸層,此層對應用層傳送過來的資料進行處理,建立2台電腦之間可靠的傳輸。在此層常見的2種協定為TCP與UDP,絕大多數應用層協定都會選擇TCP,因為TCP提供一連串偵錯、重送、資料順序、流量控管等實作,確保2台電腦之間的連線正常

Application Layer :

HTTP,應用層的協定非常多,像是網頁HTTP、郵件POP3、檔案FTP

 

而在OSI中

,則是從通訊介面理論上的module,共有7個layer而各layer都可對映到TCP/IP的各別的layer

而且在 網路的設備也都用這個來區分,像是Hub 是L1 , switch L2 and router is L3。

因為它是以通訊理論上來區分,所以它也可以對所有的通訊介面分類(I2C,USB,SPI,UART),有些會取消或合併。

從上圖中,可以看到相對於TCP/IP module中有些是沒有的 Link Layer(TCP/IP) 合併physical and data lin Layer(OSI).

或是TCP/IP中的application layer 合併到 session , presentation and application(OSI)。

而在OSI module中,有

1.physical :同TCP/IP ,link layer

定義實際在媒介上的傳輸標準,大多直接拿取其它相關組織的規格直接使用,如IEEE電機電子工程師協會制定的一系列802標準

2.data link :

決定何時資料可由實體傳輸媒介發送,也包含錯誤偵測機制

3.network:

邏輯定址、繞送、傳輸路徑選擇,維護2端點之間的連線。基本上就是IP協定所執行的工作。

4.Transport :

確保會議層與網路層之間傳遞的資料沒有遺失、重複,還有錯誤復原以及流量控管等功能。

5.session:

負責交談如何開始、控制、結束。就像是有個會議主持人負責招集,制定開會流程,開會完後宣布散會。

6.presenation:

定義與轉換資料格式,如ASCII和EDCBIC文字編碼的轉換,我們才能夠在不同的電腦上看到相同的資訊,加解密動作也由OSI指定在此層中處理。

7.application:

提供應用程式與其它主機上程式溝通的介面,也提供使用者應用程式存取網路上資源服務

 

http://www.techbang.com/posts/15859-network-architecture-2-arpanet-history-and-introduction-to-mac-ip-dns-concepts-review?page=5&related_post=true