色偷偷偷亚洲综合网另类,亚洲欧美另类在线观看,欧美午夜激情在线,久久久精品一区

當前位置:首頁 > 嵌入式培訓 > 嵌入式學習 > 講師博文 > 基于S5PC100裸機程序之SPI(下)

基于S5PC100裸機程序之SPI(下) 時間:2014-08-02      來源:未知

3 SPI接口應用示例

這里將介紹一種通過SPI通信的Flash,該芯片是M24PXX,如圖5所示為該芯片的原理圖,每根接線的意義已經清楚地標識出來了。


圖5 M25PXX原理圖

這一款芯片內部集成了12條指令,包括了通用的讀、寫、配置等命令,還有一個內置的狀態寄存器,可以通過該寄存器獲取芯片當前狀態。

如表7所示為M5DPXX芯片指令集。

表7 M25PXX芯片指令集

 Instrucion  Description  One-byle Instruction Code  Address Bytes  Dummy Bytes  Date Bytes  
 WREN  寫使能  0000 0110  06h  0  0  0
 WRDI  寫禁止  0000 0100  04h  0  0  0
 RDID  讀取ID  1001 1111  9Fh  0  0  1 to 3
 RDSR  讀狀態寄存器  0000 0101  05h  0  0  1 to ∞
 WRSR  寫狀態寄存器  0000 0001  01h  0  0  1
 READ  字節數據讀取  0000 0011  03h  3  0  1 to ∞
 FAST_READ  高速的字節讀取  0000 1011  0Bh  3  1  1 to ∞
 PP  頁編程  0000 0010  02h  3  0  1 to 256
 SE  扇區擦除  1101 1000  D8h  3  0  0
 BE  塊擦除  1100 0111  C7h  0  0  0
 DP  深度擦除  1011 1001  B9h  0  0  0
 RES  從睡眠模式喚醒以及讀出電特性  1010 1011  ABh  0  3  1 to ∞
 喚醒  0  0  0      

有了上文的知識做鋪墊,現在我們先來看一下SPI控制器的基本編程模型:

(1)設置時鐘源并配置分頻值等參數。

(2)軟復位后,并設置SPI配置寄存器(SPI CONFIGURATION REGISTER)。

(3)設置模式寄存器。

(4)設置從機選擇寄存器。

(5)收發數據。

根據以上信息,這里分成若干模塊來逐一實現。

1.相關寄存器結構體定義及宏定義。

/*SPI總線控制器寄存器定義*/
        typedef struct {
               unsigned int CHCFG;
               unsigned int CLKCFG;
               unsigned int MODECFG;
               unsigned int SLAVESEL;
               unsigned int INTEN;
               unsigned int STATUS;
               unsigned int TXDATA;
               unsigned int RXDATA; 
               unsigned int PACKETCNT;
               unsigned int PENDINGCLR;
               unsigned int SWAPCFG;
               unsigned int FBCLK;
        }spi;
        #define SPI0 ( * (volatile spi *)0XEC300000 )
        /* Flash opcodes. */
        #define    OPCODE_WREN        0x06 /*寫使能*/
        #define    OPCODE_WRDA        0x04 /*寫禁止*/
        #define    OPCODE_RDSR        0x05 /*讀狀態寄存器*/
        #define    OPCODE_WRSR        0x01 /*寫狀態寄存器*/
        #define    OPCODE_NORM_READ   0x03 /*低頻率的數據讀取*/
        #define    OPCODE_FAST_READ   0x0b /*高頻率的數據讀取*/
        #define    OPCODE_PP          0x02 /*頁編程*/
        #define    OPCODE_BE_4K       0x20 /* Erase 4KiB block */
        #define    OPCODE_BE_32K      0x52 /* Erase 32KiB block */
        #define    OPCODE_CHIP_ERASE  0xc7 /*擦除整塊芯片*/
        #define    OPCODE_SE          0xd8 /*扇區擦除*/
        #define    OPCODE_RDID        0x9f /*讀ID */
        /*狀態寄存器*/
        #define    SR_WIP             1        /*寫狀態中*/
        #define    SR_WEL               2            /*寫保護鎖*/

2.延時函數,使能芯片及禁用芯片的實現如下。

void delay(int times)
        {
                volatile int i,j;
                for (j = 0; j < times; j++){
                      for (i = 0; i < 100000; i++);
                      i = i + 1;
                }
        }
        void disable_chip(void)
        { 
                /* disable chip*/
                SPI0.SLAVESEL |= 0x1;
                delay(1);
        }
        void enable_chip(void)
        { 
                /* enable chip*/
                SPI0.SLAVESEL &= ~0x1;
                delay(1);
        }

3.軟件復位的代碼如下

void soft_reset(void)
        {
                SPI0.CHCFG |= 0x1 << 5;    
                delay(1);
                SPI0.CHCFG &= ~(0x1 << 5);
        }

4.接收(字節讀)的實現。

在實現讀字節功能的時候,第一次發送讀指令后,緊接著芯片就會回送數據,這時芯片會自動累加地址,因此需要人為控制所讀數據的范圍,讀時序如圖6所示。


圖6 讀時序

void receive(unsigned char *buf, int len)
        {
                int i;
                SPI0.CHCFG &= ~0x1; // disable Tx  
                SPI0.CHCFG |= 0x1 << 1; // enable Rx    
                delay(1);
                for (i = 0; i < len; i++){
                      buf[i] = SPI0.RXDATA;
                       //S5PC100 SPI支持在FiFo為空時,讀緩存產生SPI時鐘,否則需要發送數據產生時鐘 
                      delay(1);
                }
                SPI0.CHCFG &= ~(0x1 << 1);
        }

5.發送(寫頁面)的實現。

在發出寫指令后,要緊跟著發出第一個數據要存放的地址,這個時候再順序寫入數據,和讀的時候一樣,芯片會自動累加地址,芯片的頁面為256Bytes,寫時序如圖7所示。


圖7 寫時序

關鍵代碼如下。

void transfer(unsigned char *data, int len)
        {
                int i;
                SPI0.CHCFG &= ~(0x1 << 1);
                SPI0.CHCFG = SPI0.CHCFG | 0x1; // enable Tx and disable Rx
                delay(1);
                for (i = 0; i < len; i++){
                        SPI0.TXDATA = data[i];
                        while( !(SPI0.STATUS & (0x1 << 21)) );
                        delay(1);
                }
        SPI0.CHCFG &= ~0x1; 
        }

6.擦除芯片相關操作如下。

這塊芯片提供了兩種擦除方式,第一種是分扇區來進行擦除,重點在于選好指定的地址,然后進行擦除,結合如圖8所示的時序圖。


圖8 擦除扇區時序圖

第二種是整片芯片擦除,如圖9所示為整片芯片的擦除時的時序情況。


圖9 整片芯片擦除時序圖

關鍵代碼如下。

/*擦除扇區*/
        void erase_sector(int addr)
        {
                unsigned char buf[4];
                buf[0] = OPCODE_SE;
                buf[1] = addr >> 16;
                buf[2] = addr >> 8;
                buf[3] = addr;
                enable_chip();
                transfer(buf, 4);
                disable_chip();
        }
        /*擦除芯片*/
        void erase_chip()
        {
                unsigned char buf[4];
                buf[0] = OPCODE_CHIP_ERASE;
                enable_chip();
                transfer(buf, 1);
                disable_chip();
        }

7.解析狀態。

判斷芯片工作是否結束,如圖10所示為狀態寄存器讀時序。


圖10 狀態寄存器讀時序

關鍵代碼如下。

void wait_till_write_finished()
        {
                unsigned char buf[1]; 
                enable_chip();
                buf[0] = OPCODE_RDSR;
                transfer(buf, 1); 
                while(1) {
                      receive(buf, 1);
                      if(buf[0] & SR_WIP) {
                              //   printf( "Write is still in progress\n" );
                      }
                      else {
                           printf( "Write is finished.\n" );
                           break;
                      }
                }
                disable_chip();
        }

8.讀芯片ID。

讀ID時序如圖11所示。


圖11 讀ID時序

關鍵代碼如下。

void read_ID(void)
        { 
                unsigned char buf[3];
                int i;
                buf[0] = OPCODE_RDID;
                soft_reset();
                enable_chip();
                transfer(buf, 1);
                receive(buf, 3);
                disable_chip();
                printf("MI = %x\tMT = %x\tMC = %x\t\n", buf[0], buf[1], buf[2]);
        }

9.主程序

int main()
        {
                unsigned char buf[10] = "home\n";
                unsigned char data[10] = "morning\n";
                uart0_init();
                printf("aaaaa \n");
                cfg_gpio();       //配置SPI IO功能 
                set_clk();        //使能SPI控制器的時鐘 
                cfg_spi0();       //配置SPI0控制器 
                while(1)
                {
                      read_ID();               //讀出SPI Flash的ID號 
                      write_spi(buf, 4, 0);  //向目標芯片0地址寫入4個字節數據 
                      read_spi(data, 4, 0);  //從目標芯片0地址讀出4個字節數據 
                      printf("read from spi :%s", data);
                }
                return 0;
        }

上一篇:關于管道使用規則的總結

下一篇:sscanf函數的用法

熱點文章推薦
華清學員就業榜單
高薪學員經驗分享
熱點新聞推薦
前臺專線:010-82525158 企業培訓洽談專線:010-82525379 院校合作洽談專線:010-82525379 Copyright © 2004-2022 北京華清遠見科技集團有限公司 版權所有 ,京ICP備16055225號-5京公海網安備11010802025203號

回到頂部

色偷偷偷亚洲综合网另类,亚洲欧美另类在线观看,欧美午夜激情在线,久久久精品一区
主站蜘蛛池模板: 国产一区二区三区在线| 亚洲毛片在线观看.| 亚洲精品综合精品自拍| 免费91麻豆精品国产自产在线观看| 午夜精品免费视频| 亚洲精品电影网站| 国模吧一区二区| 日韩av一卡二卡| 性欧美办公室18xxxxhd| 国产午夜精品理论片a级探花| 欧美日韩在线视频首页| 96精品久久久久中文字幕| 欧美成人国产va精品日本一级| 国产精品扒开腿做| 久久精品视频在线| 国产精品私拍pans大尺度在线| 久久天天躁狠狠躁夜夜躁 | 免费不卡在线观看av| 国产精品jvid在线观看蜜臀| 日韩性xxxx爱| 成人国产在线激情| 国产综合在线看| 中文字幕亚洲无线码a| 国产精品一香蕉国产线看观看| 久久天天躁狠狠躁夜夜躁2014| 国产日韩在线观看av| 好吊成人免视频| 亚洲香蕉成人av网站在线观看| 国产mv久久久| 久久99久久99精品中文字幕| 亚洲第一视频网| 青青久久av北条麻妃海外网| 久久久国产一区二区三区| 亚洲国产精品成人一区二区| 奇米成人av国产一区二区三区| 欧美大奶子在线| 亚洲亚裔videos黑人hd| 国产在线拍偷自揄拍精品| 性色av一区二区三区在线观看 | 欧美性猛交xxxx免费看久久久| 亚洲男人天堂手机在线|