2013年12月23日 星期一

MCU可裁切式IO才是主流

並不是使用ST系列的MCU習慣了,而是每次想換總是差了一點功能。
各家CM4F其基本結構差不多,常用週邊也是差不多。
但是ST系列有些特性是比別家的好,自然就用得多。

1.  Pin腳高度相容
    使得在設計上,可以做Cost Down及Function Up方便得多。

2.  豐富週邊
    許多內建週邊,就算不用,pin腳也可用做其他用途。
    內建未用週邊,在未來性上,使工程師安心,也會使工程師開始想如何來利用。

3.  平衡性
    許多公司都有做到可外接SDRAM等功能。但整體配合性以ST較為平衡。
    這可能和週邊豐富性是正相關,在使用及調度上方便許多。
   
但豐富也可能引入其他副效應,就商業行為而言,先吸引使用者才是第一重點。   

2013年11月13日 星期三

HEX轉成BMP檔

也是J-Link取得的HEX資料,轉成影像格式,用來檢查資料。

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <windows.h>

#define  SIZE                (0x1000000)
#define  WIDTH                (672)
#define  WIDTH_ALIG            ((-(WIDTH))&0x3)
#define  HEIGHT                (6144)
#define  BMP_OFFSET         0x436
#define  BMP_SIZE           ((WIDTH+WIDTH_ALIG)*HEIGHT+BMP_OFFSET)

unsigned char data[SIZE];
unsigned char image[BMP_SIZE];
FILE *src;
FILE *dest;

unsigned int  *p_color;
unsigned char *p_data;
unsigned char *p_src;
BITMAPFILEHEADER    *p_FileHeader;
BITMAPINFOHEADER    *p_InfoHeader;
// unsigned char d0,d1;

unsigned char B2bin(unsigned char *x)
{
    int t;
    int i;
    unsigned short r;

    r = 0;
    for ( i=0; i<2; i++ )
    {
        if ( *x <= '9' )
        {
            t = (*x-'0');
        }
        else
        {
            t = (*x-'A'+0xA);
        }
        r = (r<<4) + t;
        x++;
    }
    return r;
}

unsigned short W2bin(unsigned char *x)
{
    int t;
    int i;
    unsigned int r;

    r = 0;
    for ( i=0; i<4; i++ )
    {
        if ( *x <= '9' )
        {
            t = (*x-'0');
        }
        else
        {
            t = (*x-'A'+0xA);
        }
        r = (r<<4) + t;
        x++;
    }
    return r;
}

void main(void)
{
    int  i,j,n;
    char temp[80];
    int  byte_count;
    unsigned short address;
    int  record_type;
    int  flag;
    unsigned int img_address;

    p_FileHeader = (BITMAPFILEHEADER*)&image[0];
    p_InfoHeader = (BITMAPINFOHEADER*)&image[0xE];
    p_color    = (unsigned int *)&image[0x36];
    p_data     = &image[BMP_OFFSET];

    p_FileHeader->bfType = 'B' | ('M'<<8);
    p_FileHeader->bfSize = WIDTH*HEIGHT+BMP_OFFSET;
    p_FileHeader->bfOffBits = BMP_OFFSET;

    p_InfoHeader->biSize   = 40;
    p_InfoHeader->biWidth  = WIDTH;
    p_InfoHeader->biHeight = HEIGHT;
    p_InfoHeader->biPlanes = 1;
    p_InfoHeader->biBitCount = 8;
    p_InfoHeader->biCompression = 0;
    p_InfoHeader->biSizeImage = (WIDTH+WIDTH_ALIG)*HEIGHT;
    p_InfoHeader->biXPelsPerMeter = 0;
    p_InfoHeader->biYPelsPerMeter = 0;
    p_InfoHeader->biClrUsed = 0;
    p_InfoHeader->biClrImportant = 0;

    for (i=0; i<0x100; i++)
    {
        p_color[i] = (i<<16) | (i<<8) | i;    // set gray pattern
    }

    src = fopen("memory.hex", "rb");
    fread(data,1,SIZE,src);
    fclose(src);
    p_src = &data[0];
    temp[0] = 0;
    flag = 1;
    while ( flag )
    {
        sscanf(p_src,"%s",temp);
        n = strlen(temp);
        if ( n == 0 )
        {
            break;
        }
//        printf("%s\n",temp);
        if (':' != temp[0]) continue;
        byte_count = B2bin(&temp[1]);
        address    = W2bin(&temp[3]);
        record_type= B2bin(&temp[7]);
        switch ( record_type )
        {
        case 0:  // data record
            for( j=0; j<byte_count; j++ )
            {
                p_data[img_address+address+j] = B2bin(&temp[9+j*2]);
            }
            break;
        case 1:  // end
            flag = 0;
            break;
        case 4:  // relocate
            img_address = ((W2bin(&temp[9]) & 0xfff)<<16);
            break;
        default:
            break;
        }
        // reset var.
        p_src += (n+2);
        temp[0] = 0;
    }

    dest = fopen("CIS.bmp", "wb");
    fwrite(image, 1, BMP_SIZE, dest);
    fclose(dest);
}

HEX轉成文字檔

J-Link取得資料,在PC上存成HEX格式。
寫了小程式轉成資料,可以用於Excel上看。

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <windows.h>

#define  SIZE                (0x1000000)
#define  MEM_SIZE            (0x10000)

unsigned char data[SIZE];
unsigned char image[MEM_SIZE];
FILE *src;
FILE *dest;

unsigned char *p_data;
unsigned char *p_src;

unsigned char B2bin(unsigned char *x)
{
    int t;
    int i;
    unsigned short r;

    r = 0;
    for ( i=0; i<2; i++ )
    {
        if ( *x <= '9' )
        {
            t = (*x-'0');
        }
        else
        {
            t = (*x-'A'+0xA);
        }
        r = (r<<4) + t;
        x++;
    }
    return r;
}

unsigned short W2bin(unsigned char *x)
{
    int t;
    int i;
    unsigned int r;

    r = 0;
    for ( i=0; i<4; i++ )
    {
        if ( *x <= '9' )
        {
            t = (*x-'0');
        }
        else
        {
            t = (*x-'A'+0xA);
        }
        r = (r<<4) + t;
        x++;
    }
    return r;
}

void main(void)
{
    int  i,j,n;
    char temp[80];
    int  byte_count;
    unsigned short address;
    int  record_type;
    int  flag;
    unsigned int img_address;
    int  first_address_flag = 0;
    unsigned int first_address;
    unsigned short *w_data;

    p_data     = &image[0];
    src = fopen("memory.hex", "rb");
    fread(data,1,SIZE,src);
    fclose(src);
    p_src = &data[0];
    temp[0] = 0;
    flag = 1;
    while ( flag )
    {
        sscanf(p_src,"%s",temp);
        n = strlen(temp);
        if ( n == 0 )
        {
            break;
        }
//        printf("%s\n",temp);
        if (':' != temp[0]) continue;
        byte_count = B2bin(&temp[1]);
        address    = W2bin(&temp[3]);
        record_type= B2bin(&temp[7]);
        switch ( record_type )
        {
        case 0:  // data record
            if(! first_address_flag )
            {
                first_address = img_address + address;
                first_address_flag = 1;
            }
            for( j=0; j<byte_count; j++ )
            {
                p_data[img_address+address+j-first_address] = B2bin(&temp[9+j*2]);
            }
            break;
        case 1:  // end
            flag = 0;
            break;
        case 4:  // relocate
            img_address = ((W2bin(&temp[9]))<<16);
            break;
        default:
            break;
        }
        // reset var.
        p_src += (n+2);
        temp[0] = 0;
    }
    dest = fopen("audio.csv", "w");
    w_data = (unsigned short *) &image[0];
    for( i=0; i<MEM_SIZE/2; i++)
    {
        if(*w_data == 0 ) break;
        fprintf(dest,"%d\n",*w_data);
        w_data++;
    }
//    fwrite(image, 1, MEM_SIZE, dest);
    fclose(dest);
}

2013年11月6日 星期三

Cortex M系列開始進入Tick-Tock時代

Intel的Tick-Tock策略是成就CPU帝國的重要推手。
沒想到Cortex-M也開始進入這樣的時代。

在今年(2013)年Cortex-M4進入火熱競爭的狀況下,在推展上很快進入價格戰。
也就是功能性推展(Tick)戰正在進行中。但Cost Down(Tock)也已經展開。
可是面對硬體價格低,功能卻不斷增加,但應用推展卻是緩慢的狀況下。
各廠商開始意識到,客戶是無法一口氣能夠控制複雜功能MCU。
韌體開始元件化,而硬體設定簡單化成為目前推展上的重點。

整合開發工具的方便性將會拉開Cortex-M系列和其他MCU開發上的差距。
也就是使用Cortex-M系列的工程師在圖型化界面拉一拉,就可以設定好MCU的工作模式。
反觀傳統MCU還在工程師一行行寫程式的狀況下,產能會逐漸拉開。

MCU功能多樣化,韌體元件化,程式資源的豐富性,PC資源連接。等等加速拉開Cortex M和傳統MCU之間的距離。
價格成為最後的底線,只要Cortex-M壓到多低,傳統MCU就只能更低。
而學MCU不是一二年可以成的,若是學傳統MCU只能在NT10元以下的MCU市場寫程式,可想而知薪水也高不起來。

Tick-Tock的出現,時代轉變。MCU的下一步?
還在觀察!

2013年10月6日 星期日

舊文章搬過來了。

總算搬成功了。文章有搬過來。
另一個隨意窩的也好了。不過那邊的不會主動去更新。
還是留一個連結:
通通都是半路出家

2013年10月3日 星期四

32位元MCU軟體的改變



8位元MCU最大的問題在ADC/DAC超過8位元後,取值及計算效能會下降。因為每筆資料皆需多次ALU計算。
16位元MCU則無此問題。它的問題是遇到32位元MCU
8位元MCU多半沒有IP付費,應是說沒有利潤去買,不如自己做。
理論上16位元也是如此,但16位元自認為價格應高於8位元,價格不願低。
然後,32位元MCU突然在三年內劇降,直接壓縮了市場,價格直逼8位元。
16位元變成沒有空間。比價格比省電,不如8位元,比效能不如32位元。
再來是32位元不僅是核心快,週邊多到爆。幾乎和PDA接近。

更恐怖的是軟體,不用修改下,以前DOS程式近乎直接移。
這種軟體方便性不是8位元/16位元可以做到的。
PC程式及資料相通,程式開發快且功能多。
32位元MCUMCU是一場革命。
是一場軟體工程師對嵌入式系統主導設計的使用習慣變革。
大部分硬體信號可以由MCU內部軟硬體結構出來。
ADC/DAC精密度提高,使得濾波器可以使用軟體來做。
Flash容量一下子到1MB以上,多到可以做磁碟機來用。
一但檔案系統出現,連資料庫都可以放進去。
8/16位元要做,程式有得大改。
且大部分PC上的軟體多以作業系統下做主。
移到8/16位元會是大工程。
32位元因有RTOS,所以問題小很多。
RTOS也有8/16位元,但因效能及RAM空間不足,安裝後不會有好表現。

MCU市場因使用慣性,不會馬上變化。
不過一但原先16位元可以用的應用,32位元會以優勢周邊攻入。
可能會有巨大資料儲存器,無線通信功能等等。

所以說像是PDA
也可以說MCU正在PDA化,且價格不變。
MCU工程師也要進化為PDA工程師,不然就會變成傳統工程師,不再有價值。
這波革命是新的,軟體工程師正在工業化,變成勞工。若不升級,難保工程師之名。

2013年9月21日 星期六

2013年8月29日 星期四

ProtoThreads於VS2010下編譯問題

過了許久才動作。先將ProtoThreads編起來。
在VS2010下竟然編不出來。
錯誤訊息是說將巨集的東西做變數是不行的。
奇怪了,不是只有取用行號。
發出錯誤的是debugger。

查了一下,要將Debug Information Format設定從/ZI改為/Zi
這個應是除錯用外部資料,可能是有干涉。
總算動起來了。

不過使用行號嵌入巨集應是可以做的。只是少人用。
另外一個C/C++先進功能,將Label做為變數值這個功能在VS2010也是不支援。
手上已有二支程式需要使用Label做為變數值的程式了。
分別用於Coroutine及動態編譯。
但二者皆有函式域限定問題。不過VS2010連這個功能都沒有也不用試了。
寫程式這麼久,開始出現程式寫得出來,編譯器編不出來的狀況。

真的不能限定使用單一語言,編不出來是Compiler的問題,不是人的問題。
程式創作也不應被語言限定。只要CPU可以執行,就一定可以寫得出來。

2013年8月8日 星期四

Protothreads結合簡單多工之構想

簡單多工在閱讀上有Task及Function不易分別的問題。這個部分用Protothreads來補強。
因為Protothreads功能限定在單一函式內。
所以Task在程式結構上會分成二部分。
一個是狀態及時間控制,此部分以Protothreads為主要描述。
另外的是資料處理,基本上這部分還是沒有改變。
工作元仍採用動態加入,主要是要限定反應時間。

一度還想用Protothreads為主結構,但發現有限制。
所以仍以簡單多工為主要結構,這樣在簡單多工上產生出來的動作行為仍可以使用。

這樣的程式結構和FPGA上寫法相似,程式分為狀態控制及資料處理。
這種調整,應可以使程式在有作業系統及無作業系統下看起來更為相似。

2013年7月9日 星期二

簡單多工將移轉到Protothreads

簡單多工的效率不錯,但一直有一個問題:可讀性。
並不是不可以讀,而是和PC上寫程式的風格有差異。

Bee很早就知道有Coroutine可以用,但已知的Coroutine只有在FreeRTOS上。
今天找到了Protothreads正是符合需求。

比對簡單多工,只是短時間性延時的實現使用Protothreads做出來,就可以完全取代。
再來就是情境上的使用差異,在實際使用後才能寫出來。

2013年7月6日 星期六

MCU應用面的改變

今年MCU大廠合併一堆是前所未有的局面。ARM可以說近乎統一新MCU市場。

CPU核心是沒得好玩了,所以重心應轉到其他領域才是。

問題是應往那一個方向?

Bee提出一點看法,接下來會極端化。

1. 省電:
  保持小型系統,和8位元搶市場。

2. PC化
  要和PC相連接,擴張使用廣度。或是和手機及平板電腦相連接。
  問題是連接後會以何種方式呈現?
  以USB PnP的功能來說,一定要會產生新裝備,但Bee不認為新裝置的PID來得及加入。
  另一個是使用以前熟悉的界面。像是HID或Mass Storage等裝置,如此一來就不用安裝Driver這樣麻煩的事。
  個人覺得檔案系統是一個最容易呈現的界面。

新元素加入,再來就是市場變化。等著看時代改變了。


2013年5月24日 星期五

X86式微,已經回不來了

Bee最近換了手機,終於開始使用智慧手機了。
一看規格:四核心、2GB RAM及16GB儲存空間。
這規格超過七年前Bee的第一台筆電。
而最近Bee也有點想買NB,只是換手機先。
但低價NB,就i3,i5核心,沒有一台可以使用到16GB的記憶體,只能到8GB。
那NB除了硬碟容量大,64位元CPU外已沒有什麼特性了。以手機前進的速度,4GB記憶體很快會出現。
RAM的容量根本不是優勢。
NB規格上前進的速度,遠不及手機。
只有軟體環境差異,但Bee認為這點撐不了太久。
因為6502轉成X86也是一二年內就翻過來。
DOS被Win95取代也是。
NB被手機取代應該也是很快。

以SD卡做為MCU磁碟機

外部串列式儲存單元選用考量:
1.界面速度
2.單位儲存價格
3.和PC做資料交換

使用USB是一個不錯的選擇,但不是每一種MCU有USB界面。
使用UART是最普遍,但串列儲存元件未支援。
使用I2C則是慢了點。
使用SPI是不錯的選擇,但和PC又無法直通。

用了數種儲存單元後終於出現讓Bee滿意的答案=SD卡。
在界面速度上,速度算不錯。可以使用SDIO的高速模式,也可以用SPI界面,和大部分MCU連接。
在容量單位價格上,可說是非常低。
可以直接拿到PC上讀取,讀卡機容易取得。
若是MCU程式空間小到放不下FAT檔案系統,那也可以全碟讀出,再用PC軟體去分析。
不過已有Open Source解決FAT的問題,就是用FatFs,故就算是8051也是可以使用。

MCU有了大型儲存單元,再加上FAT檔案系統,可做的事就好像變多了。
從前沒有空間做大型資料計算處理,也變得可行。有機會在檔案上做儲存及暫存再轉出結果。
MCU可以做的事就如同DOS時代的PC。
其實環境還真的差不多。
DOS時代的記憶體為640KB,磁碟不到1GB。
現在MCU其RAM大約給64KB,SD卡有4GB。但另有程式空間512KB。
只要控制住RAM的使用量,真的就和DOS環境差不多了。


2013年5月23日 星期四

STM32完整C函式庫支援之可能性

IAR未實現函式列表:

作業系統相關
<stdlib>
abort()
exit()
system()

<signal.h>
raise()
signal()

時間
<time.h>
clock()
time()

檔案系統
<stdio.h>
open()
close()
lseek()
read()
write()
rename()
remove()

若是MCU有支援就可以做其他相關函式的動作。
以STM32來說,有RTC安裝時,可以將time()函式補齊。
若是有檔案系統,例如使用FatFs,也可以補齊。
但作業系統相關的是基於命令列模式,MCU可能沒有人機界面的狀況,仍不會支援。

推論:
DOS時代的程式,差不多可以不用修改就可以移植。


2013年5月22日 星期三

如何產生任意大小的磁碟影像

在使用FatFs就是為了MCU和PC之間可以做檔案交換。
也是Bee第一次在MCU上使用到64位元整數變數。
這種變數數值太大想都沒想過。但遇到檔案系統位址索引就非用不可。

FatFs可以在PC上進行模擬,會產生一個Ram Disk。
不過這個Ram Disk沒有和真實世界相通。
是可以載入SD卡影像檔,但抓取費時。

本想用其他Ram Disk的影像檔來用。結果沒想到Windows有內建。
就在控制台->系統管理工具->電腦管理->磁碟管理
可以在硬碟上產生一個新的碟。
設定上要使用固定大小,不然無法對應真實磁碟。
可以格式化,放入檔案。操作完畢後中斷連接。
再來就可以用檔案讀入的方式Copy進Ram中,給FatFs做為Disk影像用。


2013年5月12日 星期日

從CPU公司併購看科技之發展

Bee一向後知後覺:


Intel賣掉ARM核心一年後才知。


MIPSImagination Technologies併購半年才知。


這二件事時代不同,看似無關,卻是電腦科技的重要分叉路。


Intel賣掉ARM核心,Bee當時認為是不合理的事,ARM核是發展PDA的核心,Intel擺明要失去PDA市場。過了幾年,結果更慘,PDA和手機完全合體後,ARM處理器已經成為主流CPU之一。


至於MIPS被併,則可以見得,GPU的重要性已經和CPU不相上下。


 


那就電腦科技來說,路又是如何走的。


CPU一開始因需求計算力,在達到有效需求的運算力之前,其他功能皆不是重點。Intel在計算力的推展符合需求,造就了帝國企業。


CPU發展到64位元時,就出現了應用需求減緩,正代表已達到基本需求運算力。再來就會有其他問題出現,此時PDA興起,代表能量效率的需求,ARM因此發展成霸主。就目前來看,x86指令解碼電路至少是ARM的三倍,長期下去x86絶非對手。


GPU公司併購CPU公司,代表CPU已無新公司生存空間,也代表GPU已開始和CPU平起平坐。


GPU是如何和CPU能平起平坐,一般人應是無法理解。其實在生物上已經發現相同的問題,解法也是一樣,同時使用。


生物解決自然界問題,和科技是相同的。應是說工程問題相同,只是解決材料不同。在生物從單一感測細胞進展到多重感測細胞,最終發展出視覺細胞,就開始遇到計算問題。邏輯運算和影像運算無法使用同一種單元來做,應說是同是腦細胞,但二者所需的連結結構不同,無法同時存在。於是大腦就分成二個腦,一個做為邏輯運算而另一個做為影像運算。發展了上億年,二個大腦還是沒有因為是那一個重要,而有特別去發展。有的是同時變大。


電腦科技已經開始走入邏輯運算和影像運算並行發展的年代,但因影像運算較為後起,所以市場空間尚未佔足,還有可以成長的空間。而CPU核心設計的市場則是過了高原期,接下來的發展會比以前慢得多。不信的人,您可以看看,若是您買了一台新PC(NB)您說得出CPU多了什麼功能嗎?就是因為連CPU公司也說不出來,才會多了一堆型號(就這裏多一點,那裏少一點),完全沒有創新的內容。就算有創新,也不是客戶關心的內容。



2013年4月23日 星期二

FatFs使用修改

FatFs可以動作:讀取檔案、寫出檔案皆有執行。


但寫出檔案的日期有問題,因為沒有RTC故無時間資料。


時間資料可以給一個固定值,但固定值由人來填寫不太有利。


利用C語言中的__TIME____DATE__來做為時間常數。


__TIME__的格式為”hh:mm:ss”


是固定的ASCII碼,所以轉成數值無問題。


__DATE__的格式為”Mmm dd yy”


dd yy也是ASCII也無問題。


Mmm為三個英文字,要轉成1~12變得很麻煩。


三個英文字要分成12個月,只要判定後二字就可以分。


只好寫一個switch case去做12個月字母去分類。


最後將__TIME____DATE__const字串去存。


設定有最佳化的Compiler設定後,可以看到反組譯的結果為:


   \                     get_fattime:


   \   00000000   0x....             LDR.N    R0,??DataTable7_4  ;; 0x42938746


   \   00000002   0x4770             BX       LR               ;; return


結果只有二個指令,只回傳定值。


寫了近90行程式,只會編成二個指令,就是4Byte


測試寫入檔案的時間是對的,會是編譯的時間。


程式碼:


#define DC(t,a,b)   (((a)<<8)+(b))
unsigned char const Date[] = __DATE__;
unsigned char const Time[] = __TIME__;

DWORD get_fattime (void)
{
    BYTE rtcYear , rtcMon , rtcMday, rtcHour, rtcMin, rtcSec;
    DWORD time;

#ifdef USE_FS_RTC
    RTC_TimeTypeDef   RTC_TimeStructure;
    RTC_DateTypeDef   RTC_DateStructure;
    /* Get info from RTC here */
    RTC_GetTime(RTC_Format_BIN, &RTC_TimeStructure);

    rtcSec    =  RTC_TimeStructure.RTC_Seconds;
    rtcMin    =  RTC_TimeStructure.RTC_Minutes;
    rtcHour   =  RTC_TimeStructure.RTC_Hours;

    RTC_GetDate(RTC_Format_BIN, &RTC_DateStructure);

    rtcYear =  RTC_DateStructure.RTC_Year;
    rtcMon =  RTC_DateStructure.RTC_Month;
    rtcMday =  RTC_DateStructure.RTC_Date;
#else
    rtcSec    =  ((Time[6]-'0')*10+(Time[7]-'0'));
    rtcMin    =  ((Time[3]-'0')*10+(Time[4]-'0'));
    rtcHour   =  ((Time[0]-'0')*10+(Time[1]-'0'));
    rtcYear   =  ((Date[9]-'0')*10+(Date[10]-'0')+20);


    rtcMday   =  (Date[4]==' ')? (Date[5]-'0'): ((Date[4]-'0')*10+(Date[5]-'0'));
    switch ((Date[1]<<8)+Date[2])
    {
    case DC('J','a','n') :
        rtcMon = 1;
        break;
    case DC('F','e','b') :
        rtcMon = 2;
        break;
    case DC('M','a','r') :
        rtcMon = 3;
        break;
    case DC('A','p','r') :
        rtcMon = 4;
        break;
    case DC('M','a','y') :
        rtcMon = 5;
        break;
    case DC('J','u','n') :
        rtcMon = 6;
        break;
    case DC('J','u','l') :
        rtcMon = 7;
        break;
    case DC('A','u','g') :
        rtcMon = 8;
        break;
    case DC('S','e','p') :
        rtcMon = 9;
        break;
    case DC('O','c','t') :
        rtcMon = 10;
        break;
    case DC('N','o','v') :
        rtcMon = 11;
        break;
    case DC('D','e','c') :
        rtcMon = 12;
        break;
    default :
        rtcMon = 1;
        break;
    }
#endif
    /* Pack date and time into a DWORD variable */
    time =      (((DWORD)rtcYear) << 25)
             | ((DWORD)rtcMon << 21)
             | ((DWORD)rtcMday << 16)
             | (WORD)(rtcHour << 11)
             | (WORD)(rtcMin << 5)
             | (WORD)(rtcSec >> 1);
    return time;
}







2013年3月19日 星期二

CPU市場鐵律:量變引發質變

之前看了對於ARM及X86之爭的評論。有一句話我非常認同:量變引發質變。
意思是當某種型式CPU在市場上佔有數量優勢時,就會形成絶對性優勢。
這和CPU本身品質無關,只因硬體相容性可以讓軟體好好發展。
而要佔有數量,價格不用說一定要夠低,另一種是開放性,非獨家生產。
PC市場因壟斷較看不出來,但MCU卻是很明顯。
8051是8位元MCU的霸主,因為大家都可以做硬體。
16位元來不及有霸主就直接進入32位元MCU時代。
而32位元MCU的霸主正在形成。
硬體統一完畢,再來會變成軟體開始統一。
結果也會有類似的現象,會有統一的軟體架構出現。
又走"量變引發質變"這條路,軟體架構的品質不是重點,而是使用量。

不管軟硬體,使用者習慣才是主導,而市場往使用者多的方向走。


2013年3月16日 星期六

Cortex M4推展不如預期

雖然各廠商將推展主力移往CM4,但在推展上並不是如此順利。
主因是,要浮點運算做什麼?
往8位元MCU轉來的工程師,對於能在32位元上開發程式已是很開心,要玩的一堆,還沒有意識到浮點運算要如何用,那又何必多花錢。
而從PC轉來的工程師對於CM4的執行效能根本看不上眼,去玩Cortex-A8還比較實在,因為Cortex-A8也不貴。
這樣的局面造成CM4不上不下的樣子。
還有各廠商自行發展的32位元處理器,其實Bee也不太看好。

現在市場已經轉成由軟體來主導,要換MCU談何容易。連軟體工具都要換新,那來那個時間。
至少CM3還可以降為CM0或升級為CM4,光是這樣就可以吃很久,那還有機會看別的MCU。
萬一有什麼大的應用,轉到Cortex-A8也是不差的選擇。

MCU現在只是一個骨架系統,再來需求會轉往拼裝系統的速度。
再來就要看工程師如何快速拼裝系統,拼裝快硬體價格低才是重點。


2013年3月14日 星期四

簡單多工於Cortex-M3上最佳化

原程式:


void main(void)


{


    InitSystem();


    INIT_DEVICE();


    while (1)


    {


        switch (Task_State[FuncID])


        {


        case TASK_RUNNING :


            TaskFunc[FuncID]();


            break;


        case TASK_SKIP :


            if ( Task_Delay_Count[FuncID] )


            {


                Task_Delay_Count[FuncID]--;


                if (! Task_Delay_Count[FuncID]) WakeUp(FuncID);


            }


            break;


        default:


            break;


        }


        if ( ++FuncID >= TASK_NUM ) FuncID = 0;


    }


}


 


新程式:


void main(void)


{


    InitSystem();


    INIT_DEVICE();


    while (1)


    {


        register unsigned int   temp_id;


        register unsigned int   temp_delay;


 


        temp_id = FuncID;


        switch (Task_State[temp_id])


        {


        case TASK_RUNNING :


            TaskFunc[temp_id]();


            break;


        case TASK_SKIP :


            temp_delay = Task_Delay_Count[temp_id];


            if ( temp_delay )


            {


                temp_delay--;


                Task_Delay_Count[temp_id] = temp_delay;


                if (! temp_delay) WakeUp(temp_id);


            }


            break;


        default:


            break;


        }


        if ( ++temp_id >= TASK_NUM ) temp_id = 0;


        FuncID = temp_id;


    }


}


因核心程式執行未檢討有無可以改善空間,因此段程式決定各工作間的掃描率,若是可以改善將增加工作效率。


分析原本的程式,發現有多一些記憶體存取動作。


於是將記憶體動作簡化,中間使用暫存器的方式應可以加速。


先將FuncID這個變數用暫存器變數取出,編出來的程式少了一個指令。


又將Task_Delay_Count[]也用暫存器變數,有少一點組合語言指令。


主要廻圈原需要16個指令,現在只剩下12個指令,少了四個指令。


16個指令需要23Clock執行時間,現在12個指令只要19Clock執行時間。


用示波器實測,Skip 1000次需時5.02ms,原先為6.80ms,確實加速執行時間。


 


不過Cortex M3用暫存器變數直接使用int會比shortchar來得有效率。中間會少了正負號擴張指令,所以速度會更快。


 


2013年3月6日 星期三

Cortex-M4開啟新MCU戰場

CM3因為ST已是獨大,所以各廠商就將重心移往CM4


直到最近TI推展CM4時,才發現價格已經壓到US$3以下。


有浮點運算器的MCU是這樣的價格,等於ADC/DAC不用什麼錢。


其他可以用於浮點運算的應用可以普及。


這樣的轉變,離上次Bee認為32位元MCU變革,只過了剛好一年。


32位元浮點運算,已不是8位元MCU可以做的事。


再下來會大量使用的演算法如:


矩陣運算、傅利葉轉換等等,都會變成非常容易達成。


這樣子MCU程式和PC程式之間差異就更小了。


看來只剩作業系統相容度的問題了。


另一個是使用浮點運算時,可能有效能不足需稍長的時間。


使用作業系統將長時間運算程式做為低優先權的運算,這樣的應用會增多。


RTOSCM4的出現將會推展的更快。



2013年2月21日 星期四

STM32系列開始支援SDRAM

ST網站改版,出現了新的型號STM32F429/439,支援TFT及SDRAM。

顯然是要做影像處理的。

再不出Bee都開始考慮轉廠商了。

不過只有網頁型號,沒有多少資料。

這樣Bee就再等數月再看看了。

2013年2月10日 星期日

從PC看MCU發展

PC也是從8位元一路走到64位元。從使用狀況可以推得MCU使用變革。


 


最早的PC是從8位元的6502開始,當時資源少,組合語言當道。


 


再來進入808616位元PCC語言開始使用。DOS是最早的作業系統,基本上是單工的時代。資料用電腦處理開始流行。


 


到了80386,多工作業系統開始使用。PC進入多元發展,主因是32位元已具有處理絶大部分資料的能力。


 


再來64位元時代開始,一開始還不知要如何用,因為作業系統不支援,應用程式無法發展。可是一但開始支援,大型資料程式就開始發展。


 


 


對應於MCU


 


8位元MCU是基本型,以目前來看,價格可能是生存唯一的方法。在這個前題下,只能算是可程式化的智慧型裝置。


 


16位元MCU就是可以處理資料的基本型,有一段時間大約是DSP的領域。基本應用也是單工來得多。


 


32位元MCU成熟型。同PC一樣,多工的需求來了,也就是RTOS引入各家爭鳴的時代。如同Windows 3.1OS2的時代一樣。在這個時代要不要使用多工作業系統也引發工程師之間的爭議。但時代的需求是擋不住的。


目前就是處在32位元MCU大量出現的時代。


 


64位元MCU,應是大量資料處理才會有應用。就觀察何時會開始。


 


 


MCUPC介面不同,只能由資料的使用量來推估使用領域的變化。



MCU程式設計技巧:示波器的使用

有使用到ADC功能時,示波器是不可缺少的儀器。


Bee確實看過許多MCU工程師不會用,原因是由軟體轉來的工程師。


不幸的是,信號處理不是單純的軟體。一定要能看到信號才能寫合適的程式。


所以MCU工程師,示波器還是學會如何操作會好些。


 


除了一般看信號外,好一點的數位示波器可以儲存波型資料由EXCEL來抓取使用。


Bee在一個案例中,就是用數位示波器上所抓取來的資料在EXCEL中就設計出用來取出所要的信號的方法。連程式都還沒有寫就先找出方法,是可以強化程式適應力。


 


ADC程式設計有一項難處,就是RAM少,不可能將數秒的資料皆存下來,反應快的系統連要使用通信傳輸出來都會是困難。


所以使用數位示波器這一類的外部記錄器將變得很重要。


只要MCU提供一個啟動信號讓數位示波器開始啟動抓取資料,然後儲存下來做分析用,就算是沒有多少RAMMCU也不用特別去做儲存。再以數位示波器的資料去設計出對應方法就行了。



MCU程式設計技巧:LA的使用

LA:邏輯分析儀


現在低價位USB LA已經很便宜了。


只要是寫MCU通信,都應會使用LA


雖然Bee也看過有軟體人寫通信記錄器,但LA除了解通信格式外,另一個是有時間記錄。


有了時間記錄,才知道反應時間是否合理。


 


這個技巧並不是新的,在專業LA就有出現。


但因時代不同,已是人人可以容易取得的工具。


有了新的觀察工具,程式開發就方便多了。



MCU程式設計技巧:中斷及FIFO的使用

能否有效使用中斷,將是MCU程式是否進入專業領域的關鍵。並不是會使用就可以了,而是能否了解工作的時效性並做工作切割。


這也是Bee將中斷及FIFO放在一起的原因。


 


在一個具有回授性系統上做PID控制。


因為回授控制具有時間敏感度,故不允許時間上的失誤。


其做法是將命令生成做成FIFO,只要FIFO有空間,就填入新的命令。而中斷則只要負責PID回授的計算方程式,以確保用最短時間內做出反應。


 


類似的工作也出現在通信上面。


應用層程式總是希望通信可以將整個句子一次輸出。但MCU的世界並不是這樣,通信每出一個字都是要花時間的。可以的做法也是使用FIFO,將整個句子用FIFO存起來,再利用中斷接續中間的工作。


 


能有效的將工作切割、控制好中斷的時效性,那MCU程式設計就開始進入專業等級。



MCU程式設計技巧:Delay的使用

在有作業系統的系統上,Delay不是問題,只要呼叫對的函式就對了。


程式也很好寫,樣子大概就是以下程式:


 


void Task(void)


{


        for(;;)


        {


                delay(1);


                // do something


        }


}


只要控制delay的參數,就可以控制執行頻率。


 


 


但在無作業系統的MCU上,這可是嚴重的問題。Bee也以如何處理這個問題來看工程師的MCU程式設計的專業程度。


在許多入門書可以看到delay是這樣寫的:


void delay(unsigned int n)


{


        while(n--);


}


若是這樣用,就是MCU新鮮人。


因為做為產品,不會只有一項功能,老闆隨時都會加功能,一但功能修改,就會調不完。


有一個變形方法解決在不同MCU上執行的效率差,就是利用Watch Dog計時器去取代delay()中的參數。利用檢查參數值做為時間計數。


另一個問題是:一但在執行delay()其他工作就停擺。


這樣做出來的產品,往往有一個問題,只會做單工,不會處理多重工作。產品特性很挑時序,只能在對的時間送入對的信號,使產品不具適應性。


 


 


專業一點的作法,會使用一個Timer做為計時器去改變變數的值,做為計時的檢知。


int delay=DELAY_TIME;


void main(void)


{


        while(1)


        {


                if(delay == 0)


                {


                        // do something


                        delay=DELAY_TIME;


                }


        }


}


 


void Timer_Interrupt(void)


{


        if(delay) delay--;


}


這樣做的效果不錯,只是程式有點不太好寫。但可以使不同工作之間較不相互干擾。不過每次加入新的計時器,又要去改寫中斷程式。


這樣做其產品對於多重工作具有近似的反應時間,唯一的問題是工程師要負擔中斷及其他資源管理,也就是無法多人一起開發程式。另外閱讀性稍差,交接需要多花時間去追蹤變數功能。



MCU程式設計技巧:除錯器之使用

JTAG的使用


這是基本技巧,但看到有人不用就寫了MCU數年,還真是驚訝。


雖然在具回授性系統上並不是很好用,但在程式邏輯除錯還是很好用。


不用的結果,就是找不到人可以教。


Bee待過二家公司,都是使用無JTAGICE的系統,人員訓練皆難以進行。


主因是程式技術也是由除錯來的,沒有好的觀察器,又如何知高階程式是如何運作。


另外一個問題是,程式發展久了,往往有些特異,就是程式如何運作連設計者也不知,是硬試出來的,更不用說下一個交接者要如何看懂了。


這種特異程式多了,系統往往有怪毛病,造成產品評價不好,也無人可解。


 


Simulator的使用


這是好的工具才會有的。但因為可用的地方不多,大部分人玩了一下大概不會再玩。


其實會使用還是可以好好使用。


Bee就用在Boot Loader的開發上。


Simulator是無法模擬在現實電路板上的狀況。


但可以自由載入記憶體資料為其特性,也就是可以裝載大量資料,然後看它如何運作。


Bee就用在Boot Loader載入應用程式的二進制資料,看它的通信寫入是否正常。


因為Boot Loader也不會開太多裝置,所以只用Simulator就寫玩大半。


而且用Simulator也可以將自己的機器碼抓下來,正好做測試用資料。