2015年10月24日 星期六

Banana Pi 初體驗:使用ubuntu進行簡易安裝

所需準備
1. Banana Pi Bpi-M1
2. Mirco USB 電源
3. 讀卡機 & SD 卡 8G 以上
4. HDMI 轉 VGA 線(非必要: 因為我的螢幕只有 VGA)

5. image 使用最簡易安裝的 Raspbian For BananaPi



Linux 下的安裝 
主要有 3 個步驟:
     1. 分割 SD 卡空間 (使用 fdisk )
     2. 格式化 SD 卡(使用 mkfs)
     3. 複製 Image 檔至 SD 卡 (使用 dd 指令)


- 分割 SD 卡空間

step1: 
             進入 root fdisk -l 可查到 SD 卡裝置號與分割區(通常為/dev/sdbx)
             如下圖分割區為/dev/sdb1

step2: 
             將 sdb1 卸載 --> umount  /dev/sdb1
step3: 

             使用 fdisk 對 SD 卡裝置執行分割配置進入配置介面後按"m"可以查看所
             有的 fdisk 動作指令
"p"可以列出 SD 卡的整個分割表
step4: 
             接著按下'' d ''刪除掉指定的 partition(/dev/sdb1)若有多個 partition 想
             一次全部刪除可以按''o''

 
step5:
             加入新的 partition
總共分割 2 個 partition
             partition-1(存放 boot 與 uImage): /dev/sdb1
size 設為 30MB
             partition-2(存放 file system): /dev/sdb2 , size = 減掉 sdb1 的剩餘空間

            按下''n''加入第一個 partition
                  - 輸入 p (主分割區) 後按 Enter
                  - 輸入 1(partition 編號) 後按 Enter
                  - 直接按 Enter (起使位置使用預設值所以才按 Enter)
                  - 輸入+30M 後按 Enter

            同樣按下''n''加入第二個 partition
                 - 輸入 p (主分割區) 後按 Enter
                 - 輸入 2(partition 編號) 後按 Enter
                 - 使用預設值 --> 直接按 Enter
                 - 使用預設值 --> 直接按 Enter



step6: 

            按下''w''保存分割表並離開 fdisk 操作介面

- 格式化 SD 卡

step1 : 
             格式化 /dev/sdb1格式為 vfat
             ---> mkfs  -t vfat /dev/sdb1


step2 : 

             格式化 /dev/sdb2格式為 ext4
             ---> mkfs  -t ext4 /dev/sdb2



- 複製 Image 檔至 SD 卡

使用 dd 指令 : 
bs (block size)   if (輸入檔)  of (輸出檔 )
dd bs=4M if=/home/jinyo/banana_Pi/Raspbian_For_BananaPi_v1412.img
of=/dev/sdb

要等一段時間才會複製完畢

上電開機安裝成功

之後發現做出來的檔案系統只有 4G,但我的 SD 卡明明就有 16G 的空間,查了一
下發現需要擴充 file system 空間
,步驟如下:
1. 進入 banana pi
,打開終端機(user/passwd 預設都是 bananapi)
2. 下 sudo raspi-config
,會進入 config 畫面,選則 Expand Filesystem 然後一鍵
按到底,最後再重新開機


3. 使用 df -h 指令查看已變成 16G 的空間


2015年9月29日 星期二

資料結構: 堆疊應用與後序轉換


以前在大四升碩0的時後,因為太菜了,所以被老板要求寫這些資料結構程式當作練功,資料結構在研究所考試時是必考的,所以我以為我還算熟 , 但要實作程式出來又是另一回事了,可見在大學時真的背太多了 最近整裡硬碟資料找到當初寫的code,所以在此做一下紀錄

主要是參考 Horowitz 資料結構聖經版 
http://www.amazon.com/Fundamentals-Data-Structures-Ellis-Horowitz/dp/0929306406

 這個中序轉後序程式可分為三個部份:
    1.  運算元(A-Z ,0-9)與運算子( + - * / )的分離
               -   使用isalnum()可以將數字/字母與符號分離
    2.  堆疊的操作
               -   push()  &  pop()
    3.  後序轉換演算法
               -  在於比較運算子的優先權:左右括號  >  乘除  >加減


#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>

#define STACK_SIZE 50

#define ADD_SUB   1       /* 代表 加減  */
#define MULT_DIV  2   /* 代表 乘除 */
#define LEFT      3             /* 代表左括號 */
#define RIGHT     4            /* 代表右括號 */

char stack[STACK_SIZE];       /* 堆疊陣列 */
int top=-1;                  /* 堆疊頂端指標 */ 
int priority[STACK_SIZE];        /*優先權堆疊 */


void push(char s,int number){
   if(top>=STACK_SIZE-1){
      printf("堆疊滿了");
   }
   else{
     top++;
     stack[top]=s;
     priority[top]=number;
   }
}

void pop(){
    if (top==-1){
      printf("堆疊已空\n");
    }
    else{
  /*不要印出  '('*/
       if( priority[top ]!=LEFT){
    printf("%c",stack[top]);
       }
       top--;
    }
} 
/* 運算子處理 */
void Operator(char ch,int number) {

  if(top==-1&&number!=RIGHT) /* 若堆疊為空 直接push */
      push(ch,number);
  else{
        switch(number){          
             /* 若輸入為 ')' 從堆疊頂端依序pop直到出現'('  */
           case RIGHT:
                for(priority[top];priority[top]!=LEFT;pop()) ;
                    pop();//把最後的 '(' pop 但不印出 
                break;                       
            /* 若輸入為 '('  直接 PUSH  */
           case LEFT:
                push(ch,number);
                break;    
            /* 若輸入是 '+' '-' '*' '/' */
           case ADD_SUB:
           case MULT_DIV:
                if( priority[top]==LEFT||priority[top]<number){
                   push(ch,number);
                }
                else{
                     /* 若堆疊內優先權 大於number  */
                    while((priority[top]>=number)&&priority[top]!=LEFT)
                           pop();  /* 先POP 堆疊內再PUSH number  */ 
                    push(ch,number);
                }   
                break;
            /*當字串已scan完 堆疊不為空 pop 剩下的運算子*/           
            case 0:  
       while(top!=-1) 
                      pop();
                 break;
        }        
    }  
}      
int main(void){
    
    char *IndString;
    char buf[STACK_SIZE];
    int i=0;
    int error_OP = 0;
    printf("請輸入中序 :");
    IndString=gets(buf);//中序輸入
    printf("\n");
    printf("後序為:");

   /*若不等於結束字元*/ 
   while(*(IndString+i)!='\0' & !error_OP) {

       /*數字和字母是運算元所以直接印出 */
      if(isalnum(*(IndString+i))) {    
               printf("%c",*(IndString+i));
      }
      else if(ispunct(*(IndString+i))) {     //若不是數字 空白 字母  則為真 
       
             switch(*(IndString+i)){
                case '+':
                             Operator(*(IndString+i),ADD_SUB);                       
                             break;
                case '-':   
                             Operator(*(IndString+i),ADD_SUB);                       
                             break;         
             
                case '*':
                             Operator(*(IndString+i),MULT_DIV);
                             break;
                case '/':
                             Operator(*(IndString+i),MULT_DIV);
                             break;
                case '(':
                             Operator(*(IndString+i),LEFT);
                             break; 
                case ')':
                            Operator(*(IndString+i),RIGHT);
                            break;  
                default:
                            printf(" error Operator\n");
                            error_OP = 1;
       break;
            }   
       }     
     i++; 
   } 

   Operator('\0',0);//字串scan結束 
   puts("\n------------------------------------\n");
   return 0;
}

ps:  程式裡有使用到gets,通常建議改成fgets使用,不過懶得改了
執行結果:





2015年9月25日 星期五

在Uboot下遇到的DMA快取一致性問題



關於DMA快取一致性(Cache coherency)的問題以前只在書上看過,但沒想到真的讓我遇到了。事情是這樣的,我原本的目的是想在u-boot下做一些memory的測試,所以在U-boot裡加入了DMA功能,並且做成了一個u-boot Command

首先講一下DMA是什麼:
DMA的基本原理就是不需經過CPU進行memory讀寫操作,而是由DMA控制器來負責,可以把DMA想像成另一顆只負責處理memory存取的processor,當需要將一大塊memory區塊搬到另一目的位址時,使用DMA會有很好的效果,許多周邊裝置都會使用到DMA,例如GPU或網卡等。

那麼何謂DMA快取一致性(Cache coherency)?
維基如是說 :

粗略地畫一下簡圖
以下是我的環境:
Platform: Arm arch , TI DM81xx
DMA: TI EDMA control
u-boot:
來源位址: 0x84000000
目標位址: 0xA0000000 (要被DMA寫入的位址)


一開始在來源位址: 0x84000000 寫入4k大小的 pattern value ( 0x55 )

再來執行DMACopy動作

接著使用md 指令:
   可以看到從目標位址: 0xA0000000開始確實有寫入了4K大小的pattern
   DMA正常動作


但之後要寫入另一個pattern(0x33)並執行DMA Copy發現目標位址的值沒有改變,試了很多次都一樣



將目標位址全部印出之後才發現只有後半段有更新到,這時才發覺可能是快取的問題。


解決方法: 

    1. 下U-boot指令, d-cache off 可以將資料快取(Data cache)整個關掉,
         但這個方法會讓CPU的讀寫速度變得很慢
    2. 在每次要執行DMA存取前先將快取給清除掉,Uboot裡有提供flush_dcache_all
        這個函式可以把資料快取(Data cache)清除 

2015年9月16日 星期三

Arm linux下 QRcode library安裝使用

所需套件

1. qrencode -->  qrencode-3.2.0.tar.gz
下載
http://pkgs.fedoraproject.org/repo/pkgs/qrencode/qrencode-3.2.0.tar.gz/

2. libpng --> libpng-1.6.12.tar.gz
下載
http://pkgs.fedoraproject.org/repo/pkgs/libpng/libpng-1.6.12.tar.gz/297388a6746a65a2127ecdeb1c6e5c82/


Step 1: 安裝 libpng

    $:  tar zxvf libpng-1.6.12.tar.gz ;

    $:  cd libpng-1.6.12

    $:  ./configure --prefix=/usr/local/Jinyo_linpng(安裝路徑) \

        --host =arm-linux(主機架構) \

        CC= arm-arago-linux-gnueabi-gcc(gcc 路徑) \

        LD= arm-arago-linux-gnueabi-ld( ld 路徑) ;

    $:  make ; make install ;



Step 2: 安裝 qrencode
    $:  tar zxvf qrencode-3.2.0.tar.gz  ;
    $:  cd qrencode-3.2.0 ;
    $:  ./configure PKG_CONFIG_PATH= \
         $PKG_CONFIG_PATH:/usr/local/Jinyo_linpng/lib/pkgconfig \
         --host= arm-linux --prefix=/usr/local/jinyo_qrencode --enable-static \
         CC= arm-arago-linux-gnueabi-gcc \
         LD= arm-arago-linux-gnueabi-ld ;
    $:   make ; make install ;

Step 3: ADD project
   安裝完成後就可以將qrencode.h 和 libqrencode.a 加入自己的project來使用
   $: cp /usr/local/jinyo_qrencode/include/qrencode.h   / your project/include/
   $: cp /usr/local/jinyo_qrencode/lib/libqrencode.a     / your project/lib/

   主要是呼叫這個API
   QRcode_encodeString("www.xxx.com", 1, QR_ECLEVEL_L, QR_MODE_8,0) ;
   原形如下
QRcode *QRcode_encodeString( const char *string,
                                    int version,
                                    QRecLevel level,
                                    QRencodeMode hint,
                                    int casesensitive   ) {

    return QRcode_encodeStringReal( string,
                                    version, 
                                    level, 
                                    0, 
                                    hint,
                                    casesensitive  );

}

   string:     輸入字串,ex:www.xxx.com
   version:  版本號
   level:      錯誤更正碼(Error correction)的等級,共4級
                 參考wiki
                  https://en.wikipedia.org/wiki/QR_code#Error_correction
              

  hint:           ??不太清楚
  casesensitive:   輸入字串是否要分大小寫 --> 0:忽略  1:要分大小寫

完整的sample-code主要參考這一篇
 http://stackoverflow.com/questions/21400254/how-to-draw-a-qr-code-with-qt-in-native-c-c