專注電子技術(shù)學(xué)習(xí)與研究
當(dāng)前位置:單片機教程網(wǎng) >> MCU設(shè)計實例 >> 瀏覽文章

無線射頻芯片CC1100e的編程

作者:xuchen   來源:xuchen的blog   點擊數(shù):  更新時間:2014年05月28日   【字體:
CC1100e通過SPI方式與MSP430進行通信的。首先需要明白讀寫寄存器的過程:寫寄存器時,先寫寄存器的地址,然后寫數(shù)據(jù),這樣數(shù)據(jù)就到了所要寫的寄存器當(dāng)中了。同樣,讀寄存器時,先讀寄存器的地址,由于同步通訊,相應(yīng)寄存器中的數(shù)據(jù)在讀寄存器地址的下個周期就自動讀出。

SPI接口上進行所有事務(wù)均以一個報頭字節(jié)作為開始:BIT7~BIT0,在SPI總線上傳輸數(shù)據(jù)期間,CSN引腳必須保持低電平。

寄存器的配置:
CC1100 寄存器地址是0~0x3F,也就是BIT0~BIT5
CC1100 讀寫控制是BIT7,BIT7 為1 時,為讀對應(yīng)的寄存器,BIT7 為0 時,為寫相應(yīng)的寄存器。
BIT6 是突發(fā)訪問控制位,BIT6 為1 為突發(fā)訪問,BIT6為0 為單字節(jié)訪問。
其中,SPI地址為0x00~0x2E之間的為配置寄存器,對于配置寄存器均能進行讀取和寫入操作。讀取還是寫入操作由上述的BIT7控制。寫入寄存器時,每當(dāng)一個報頭字節(jié)或數(shù)據(jù)字節(jié)通過MOSI引腳發(fā)送時 狀態(tài)字節(jié)便會通過MISO 引腳完成發(fā)送。當(dāng)讀取寄存器時,每當(dāng)一個報頭字節(jié)通過MOSI引腳發(fā)送時狀態(tài)字節(jié)便會通過MISO引腳完成發(fā)送。通過設(shè)置報頭字節(jié)的突發(fā)位BIT6可以高效的存取帶連續(xù)地址的寄存器。地址位BIT5~BIT0在內(nèi)部地址計數(shù)器內(nèi)設(shè)置起始地址,每增加一個新的字節(jié)(8個時鐘脈沖),計數(shù)器便增加1.突發(fā)存取可以是一次讀取也可以是一次寫入,但必須通過設(shè)置CSN為高電平來進行終止。
例如:配置IOCFG2寄存器,其地址0x00,我們突發(fā)訪問寫的話寫先數(shù)據(jù)0x40,再連續(xù)寫數(shù)據(jù)就可以了;如果單字節(jié)讀這個寄存器,先寫數(shù)據(jù)0x80,再讀一下就可讀出其值了。

命令濾波(指令選通脈沖):
通過尋址一條指令選通脈沖寄存器,啟動內(nèi)部序列。即cc1100 只要寫一下對應(yīng)的寄存器的地址,不用寫數(shù)據(jù),它就內(nèi)部自動執(zhí)行相應(yīng)的指令,比如重啟芯片,設(shè)置為發(fā)送模式等等,共有14 個濾波指令,地址從0x30~0x3D。
而濾波指令的狀態(tài)寄存器是可讀不可寫的,也就是0x30~0x3D 的地址加上0xC0,比如寫數(shù)據(jù)0xF4,就可以讀到相應(yīng)RSSI (0x34)狀態(tài)寄存器里面的值。

狀態(tài)字節(jié):
狀態(tài)字節(jié)包含一些關(guān)鍵的狀態(tài)信號,當(dāng)通過SPI接口發(fā)送報頭字節(jié)、數(shù)據(jù)字節(jié)或指令選通脈沖時,CC1100e的狀態(tài)字節(jié)通過MISO引腳發(fā)送。狀態(tài)字節(jié)的最后四位(3:0)FIFO_BYTES_AVAILABLE,進行讀取操作時,報頭字節(jié)的BIT7設(shè)置為1,F(xiàn)IFO_BYTES_AVAILABLE域包含了可從FIFO讀取的字節(jié)數(shù)。進行寫操作時,F(xiàn)IFO_BYTES_AVAILABLE字段包含了可寫至TX FIFO的字節(jié)數(shù)。當(dāng)FIFO_BYTES_AVAILABLE=15時,表示15或更多的字節(jié)為可用字節(jié)。

FIFO存。
關(guān)于FIFO的訪問,其分為TX FIFO和RX FIFO。64字節(jié)的TX FIFO和64字節(jié)的RX FIFO均通過0x3F地址進行存取。對其既可以通過單字節(jié)訪問也可以通過突發(fā)訪問。當(dāng)讀寫控制位BIT7為1時訪問的是RX FIFO,BIT7是0時訪問的TX FIFO。這樣得到下列報頭字節(jié):0x3F為單字節(jié)訪問TX FIFO,0xBF為單字節(jié)訪問RX FIFO,0x7F為突發(fā)訪問TX FIFO,0xFF為突發(fā)訪問 RX FIFO。
當(dāng)對TX FIFO進行寫入操作時,每個數(shù)據(jù)字節(jié)的狀態(tài)字節(jié)均在MISO上輸出。該狀態(tài)字節(jié)用于檢測TX FIFO寫數(shù)據(jù)時的下溢。狀態(tài)字節(jié)包含將其寫入TX FIFO過程以前自由的字節(jié)數(shù),當(dāng)可寫入TX FIFO的最后一個字節(jié)在MOSI上發(fā)送時,與此同時在MISO引腳上接收到的狀態(tài)字節(jié)將表明TXFIFO中存在一個自由字節(jié)。TX FIFO可能會由于寫入一條SFTX指令選通脈沖而被刷新,同樣,一條SFRX指令選通脈沖也會刷新RX FIFO。

PTABLE存。
0x3E地址用于存取PATABLE,用來設(shè)置發(fā)射功率的。接收到此地址之后,SPI要求有高達8個數(shù)據(jù)字節(jié)。PATABLE是一個8字節(jié)表,其定義了PA控制設(shè)置。讀寫還是通過讀寫控制位BIT7控制,突發(fā)訪問還是單字節(jié)訪問還是通過突發(fā)位BIT6來控制。內(nèi)部有個計數(shù)器用來控制對該表的存取,每讀取或?qū)懭朐摫碇幸粋字節(jié),計數(shù)器就自動加1,當(dāng)計數(shù)到7時會自動從0開始計數(shù).當(dāng)設(shè)置Csn為高電平時,內(nèi)部計數(shù)器會變?yōu)?.如果向PTABLE寫入一個字節(jié),并且要讀取該值,那么在讀取存取以前必須將CSN設(shè)置為高電平,以將計數(shù)器重新設(shè)置為0.

數(shù)據(jù)包格式:
由cc1100的datasheet可以知道,其數(shù)據(jù)包是由前導(dǎo)碼、同步字節(jié)、可選的數(shù)據(jù)包長度、可選的目標(biāo)地址、數(shù)據(jù)區(qū)以及兩個字節(jié)的CRC校驗碼。前導(dǎo)碼的最小長度可以通過MDMCFG1.NUM_PREAMBLE的值進行編程。當(dāng)開啟TX模式時,調(diào)制器將開始發(fā)送前導(dǎo)碼。當(dāng)編程的前導(dǎo)字節(jié)數(shù)被發(fā)送完畢后,調(diào)制器將開始發(fā)送同步字節(jié),然后發(fā)送來自TX FIFO的數(shù)據(jù)。若TXFIFO為空,調(diào)制器將繼續(xù)發(fā)送前導(dǎo)碼,知道第一個字節(jié)被寫入TX FIFO為止,調(diào)制器隨后發(fā)送同步字,然后發(fā)送數(shù)據(jù)字節(jié)。
同步字是設(shè)置于SYNC1和SYNC0兩個寄存器中的2字節(jié)值。在可變數(shù)據(jù)包長度模式下,通過同步字后面的第一個字節(jié)來配置數(shù)據(jù)包長度。數(shù)據(jù)包長度被定義為有效負載數(shù)據(jù),但不包括長度字節(jié)和可選CRC。PKTLEN寄存器用于設(shè)置RX模式中允許的最大數(shù)據(jù)包長度。任何長度字節(jié)值大于PKTLEN的接收數(shù)據(jù)包將被丟棄。

接收模式下的數(shù)據(jù)包濾波:
CC1100e支持三種不同類型的濾波:地址濾波、最大長度濾波和CRC濾波。
地址濾波:設(shè)置PKTCTRL1.ADR_CHK為0以外的任何值均可開啟數(shù)據(jù)包的地址濾波器。radio將目標(biāo)地址字節(jié)與ADDR寄存器中地址,以及PKTCTRL1.ADR_CHK=10時的0x00廣播地址或者PKTCTRL1.ADR_CHK=11時的0x00和0xff廣播地址進行比較。如果接收的地址匹配一個有效地址,則接收該數(shù)據(jù)包,并將其寫入RX FIFO,如果地址匹配失敗,則丟棄該數(shù)據(jù)包,并重新啟動接收模式。
最大長度濾波:在可變數(shù)據(jù)包長度模式下,PKTLEN.PACKET_LENGTH寄存器的值用來設(shè)置最大允許數(shù)據(jù)包長度,當(dāng)接收字節(jié)值比這個值大,則數(shù)據(jù)包被丟棄,并且重新啟動接收模式。
CRC濾波:(不懂,不寫

發(fā)送模式下的數(shù)據(jù)包處理:
必須要將即將發(fā)送的有效數(shù)據(jù)長度寫入TX FIFO中,開啟可變數(shù)據(jù)包長度以后,長度字節(jié)必須最先被寫入。長度字節(jié)具有一個與數(shù)據(jù)包有效負載相當(dāng)?shù)闹。如果接收機端開啟了地址識別,則寫入TX FIFO的第二個字節(jié)必須為地址字節(jié)。如果開啟了固定數(shù)據(jù)包長度,則寫入TX FIFO的第一個字節(jié)應(yīng)為地址字節(jié)。
調(diào)制器會首先發(fā)送編程的前導(dǎo)字節(jié)數(shù),如果TX FIFO中的數(shù)據(jù)可用,則調(diào)制器會發(fā)送兩個字節(jié)同步字,之后是TX FIFO 中的有效負載。如果開啟了CRC,則在所有取自TXFIFO的數(shù)據(jù)上計算驗和,并在有效負載之后以兩個額外字節(jié)發(fā)送該結(jié)果。如果TXFIFO在發(fā)送完全部數(shù)據(jù)包以前變?yōu)榭,那么該無線電設(shè)備將進入TXFIFO_UNDERFLOW狀態(tài)。退出該狀態(tài)的唯一方法是發(fā)出一個SFTX選通脈沖。

接收模式下的數(shù)據(jù)包處理:
在接收模式下,解調(diào)器和數(shù)據(jù)包處理器將會搜索一個有效的前導(dǎo)和同步字。如果找到,解調(diào)器就獲得了位和字節(jié)同步機制,并將接收第一個有效負載字節(jié)。當(dāng)可變數(shù)據(jù)包長度模式開啟時,則第一個字節(jié)為長度字節(jié)。數(shù)據(jù)包處理器把這個值作為數(shù)據(jù)包長度存儲,并接收該長度字節(jié)線束數(shù)目的字節(jié)。

固件中的數(shù)據(jù)包處理:
在固件中執(zhí)行數(shù)據(jù)包導(dǎo)向無線協(xié)議時,MSP430需要知道一個數(shù)據(jù)包何時被接收到、何時被發(fā)送出去。當(dāng)數(shù)據(jù)包長度大于64字節(jié)時,需要在RX模式下讀取RX FIFO,需要在TX模式下重填TXFIFO。
中斷驅(qū)動法:當(dāng)通過設(shè)置IOCFGx.GDOx_CFG=0x06接收到或發(fā)送出去一個同步字或接收到發(fā)送出去一個完整的數(shù)據(jù)包時,在RX和TX模式下均可使用GDO引腳來實現(xiàn)中斷。
SPI輪詢:可以某個給定速率對PKTSTATUS寄存器輪詢,以獲取GDO2和GDO0當(dāng)前值的相關(guān)信息?梢阅硞給定速率對RXBYTES和TXBYTES寄存器輪詢,以獲取RXFIFO和TXFIFO中所含字節(jié)數(shù)的相關(guān)信息。另外,在SPI總線上每發(fā)送一個報頭字節(jié)、數(shù)據(jù)字節(jié)或指令選通脈沖時,可從MISO線路上返回的芯片狀態(tài)字節(jié)讀取到RXFIFO和TXFIFO中所含的字節(jié)數(shù)。


具體編程時必須注意一下事項:
1、拉低CSN引腳電平時,在開始傳輸報頭字節(jié)以前,msp430必須等待SISO引腳變?yōu)榈碗娖綖橹,表明?nèi)部穩(wěn)定。
2、每當(dāng)一個字節(jié)通過SI引腳寫入到寄存器時,狀態(tài)字節(jié)將被送到MISO引腳
3、狀態(tài)字節(jié)的最后4位用來表示FIFO的可用字節(jié),其最大值是15,此時表示15或更多的字節(jié)是可以使用的。
4、只有radio處于XOSC空閑,并且數(shù)字中心的能量開啟,其他模塊處于功率降低狀態(tài),這時候頻率和信道配置才能被更新。(不是很理解)
5、寄存器的突發(fā)訪問時,內(nèi)部計數(shù)器會自動設(shè)置起始地址,每增加一個字節(jié),地址會自動加1,無論讀寫操作,必須通過拉高Csn終止操作。
6、關(guān)于命令濾波,其實是單字節(jié)指令,通過指令對寄存器的選址,內(nèi)部功能做出相應(yīng)的啟動或關(guān)閉。不像對其他寄存器一樣必須先寫地址后寫數(shù)據(jù)。
7、當(dāng)radio進入休眠狀態(tài)時,兩個FIFO都被刷新為空。
8、一般所有的濾波命令會立即執(zhí)行,只有休眠濾波命令SPWD不會立即執(zhí)行,它會延遲到Csn為高電平時執(zhí)行。




部分程序如下:
//SPI讀取和發(fā)送函數(shù)
unsigned int SpiTxRxByte(unsigned data)
{
 unsigned char i,temp;
 temp=0;
 SCK_0;
 for(i=0;i<8;i++)
  {
   if(data&0x80)
     {
      MOSI_1; 
     }
   else
    {
     MOSI_0;
    }
   data<<=1;
   SCK_1;
   temp<<=1;
   if(MISO)temp++;
   SCK_0;
  }
 teturn temp;
}

//重啟芯片函數(shù)
void RESET_CC1100(void)
{
 CSN_0;
 while(MISO);
 SpiTxRxByte(SRES);
 while(MISO);
 CSN_1;
}

//上電重啟芯片函數(shù)
void POWER_UP_RESET_CC1100(void)
{
CSN_1;
delayus(1);
CSN_0;
delayus(1);
CSN_1;
delayus(41);
ESET_CC1100();
}

//單字節(jié)寫寄存器函數(shù)
void SpiWriteReg(unsigned char addr,unchar int value)
{
 CSN_0;
 while(MISO);
 SpiTxRxByte(addr); //寫入地址
 SpiTxRxByte(value);//寫入配置
 CSN_1;
}

//突發(fā)訪問方式寫寄存器函數(shù)
void SpiWriteBurstReg(unsigned int addr,unsigned int *buffer,unsigned int count)
{
 unsigned int i,temp;
 temp=addr|0x40;//將突發(fā)訪問位置1
 CSN_0;
 while(MISO);
 SpiTxRxByte(temp);
 for(i=0;i<count;i++)
   {
    SpiTxRxByte(buffer[i]);
   }
 CSN_1;
}

//寫命令濾波函數(shù)
void SpiStrobe(unsigned int strobe)
{
 CSN_0;
 while(MISO);
 SpiTxRxByte(strobe);
 CSN_1;
}

//單字節(jié)讀寄存器函數(shù)
unsigned int SpiReadReg(unsigned int addr)
{
 unsigned int temp,value;
 temp=addr|0x80;
 CSN_0;
 while(MISO);
 SpiTxRxByte(temp);
 value=SpiTxRxByte(0);
 CSN_1;
 return value;
}

//突發(fā)訪問讀寄存器函數(shù)
void SpiReadBurstReg(unsigned int addr,unsigned int *buffer,unsigned int count)
{
 unsigned int i,temp;
 temp=addr|0xc0;
 CSN_0;
 while(MISO);
 SpiTxRxByte(temp);
 for(i=0;i<count;i++)
  {
   buffer[i]=SpiTxRxByte(0);
  }
CSN_1;
}

//讀寄存器狀態(tài)函數(shù)
unsigned int SpiReadStatus(unsigned int addr)
{
 unsigned int value,temp;
 temp=addr|0xc0;
 CSN_0;
 while(MISO);
 SpiTxRxByte(temp);
 value=SpiTxRxByte(0);
 CSN_1;
 return value;
}

//
//
//CC1100發(fā)送一組數(shù)據(jù)的函數(shù)
void RFSpiSendPacket(unsigned int *txbuffer,unsigned int size)
{
 SpiWriteReg(TXFIFO,size);//是否和下句沖突?
 SpiWriteBurstReg(TXFIFO,txbuffer,size);//寫入要發(fā)送的數(shù)據(jù)
 SpiStrobe(STX);//進入發(fā)送模式發(fā)送數(shù)據(jù)
 //wait for GDO0 to be set--->sync transmitted
 while(!(GDO0));
//wait for GDO0 to be cleared--->end of packet
 while(GDO0);
 SpiStrobe(SFTX);//沖洗 TXFIFO
}

//
//
//
//CC1100接收一組數(shù)據(jù)
unsigned int RFReceivePacket(unsigned int *rxbuffer,unsigned int *length)
{
 unsigned int status[2];
 unsigned int packetlength;
 unsigned int i=(*length)*4;
 SpiStrobe(SRX);//進入接收狀態(tài)
 delayus(2);
 while(GDO0)
  {
    delayus(2);
    --i;
   if(i<1)
   return 0;
  }
if((SpiReadStatus(RXBYTES)&0x7F))//如果接的字節(jié)數(shù)不為0
  {
   packetlength=SpiReadReg(RXFIFO);//讀出第一個字節(jié),此字節(jié)為該幀數(shù)據(jù)長度
   if(packetlength<=*length)
       {
        SpiReadBurstReg(RXFIFO,rxbuffer,packetlength);//讀出所有接收到的數(shù)據(jù)
        *length=packetlength;
        SpiReadBurstReg(RXFIFO,status,2);//讀出CRC校驗位
        SpiStrobe(SFRX);//清洗接收緩沖區(qū)
        return(status[1]&0x80);//如果校驗成功 返回接收成功
       }
   else
       {
        *length=packetlength;
        SpiStrobe(SFRX);//清洗接收緩沖區(qū)
        return 0;
       }
 
 else
  return 0;
}
關(guān)閉窗口

相關(guān)文章