亚洲精品一二区_国产黄色片网站_99久久久成人国产精品_蜜臀网_国产精品一区二区三区免费_成人av中文字幕_91精品国产欧美一区二区成人

當前位置:首頁 > 嵌入式培訓 > 嵌入式學習 > 講師博文 > 基于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號

回到頂部

主站蜘蛛池模板: 国产视频高清 | 欧美影院网站视频观看 | 精品午夜一区二区三区在线观看 | 日韩免费看片 | 久久免费观看国产99精品 | 久久精品这里只有精品 | 性久久久久久久久波多野结衣 | 免费香蕉依人在线视频久 | 狂野欧美性猛交xxxx乱大交 | 国产精品嫩草影院午夜 | 日本xxx在线观看 | 草护士| 欧洲一区二区三区 | jizzjizzjizz亚洲日本 | 国产蜜臀 | 亚洲视频区 | 免费福利资源站在线视频 | 欧美成人网在线综合视频 | 国产一级真人毛爱做毛片 | 久久99热这里只有精品 | 久久青草免费91线频观看不卡 | 日本在线亚州精品视频在线 | 99re热视频在线 | 天天摸天天做天天爽天天弄 | 日本一区二区三区久久久 | 国产成人精品三级91在线影院 | 韩国三级hd中文字幕一男多女 | 欧美网站黄 | 成人午夜性影院视频 | 精品亚洲午夜久久久久 | 99国产精品久久久久久久... | 国产一卡2卡3卡4卡公司科普 | 日本免费视屏 | 欧美性猛交xxx乱大交 | 美女色18片黄黄色 | 亚洲欧美一区二区久久香蕉 | 国产韩国在线 | 麻豆视频播放 | 国产一卡2卡3卡4卡网站免费 | 国产高清视频 | 人人插人 |