Individální projekty MPOA

Mikroprocesory s architekturou ARM

Uživatelské nástroje

Nástroje pro tento web


2015:p2p-rfm12b

Toto je starší verze dokumentu!


Point-to-point spoj s RFM12B

Zadání

Pomocí dvojice transceiverů RFM12B připojených ke kitům FRDM-KL25Z realizujte experimentální rádiový spoj v pásmu 868MHz. Vytvořte firmware pro testování spojení - měření chybovosti, rychlosti přenosu, RTT apod. Proveďte měření základních parametrů v závislosti na vzdálenosti modulů.

Hardware

RFM12B

Jedná se o univerzální poloduplexní transceiver pracující v ISM pásmu. Nosný kmitočet lze nastavit do pásem 433 MHz, 868 MHz a 915 MHz. Komunikační rychlost by dle katalogového listu měla dosahovat rychlosti až 115,2 kb/s při použití digitálního filtru a až 256 kb/s při použití analogového filtru. Modul ke komunikaci využívá FSK modulaci, přičemž kmitočtový zdvih lze nastavovat v rozmezí 15 kHz – 240 KHz. Maximální výstupní výkon při použití antény se vstupní impedancí 50 Ω je 5 dBm a lze jej snižovat s krokem 2,5 dB až na hodnotu -12,5 dBm. Modul je vybaven SPI rozhraním, který slouží k jeho řízení a k přenosu dat z/do připojeného kontroléru.

FRDM KL25Z

Řešení

Vývojové prostředí.

Původním záměrem bylo řešit projekt pomocí online vývojového prostředí mbed.org, protože jsou zde k dispozici knihovny pro použitý modul. Bohužel ani s jednou ze dvou testovaných knihoven se mi nepodařilo zprovoznit ani základní komunikaci. Důvod nefunkčnosti zřejmě nebyl v knihovnách, protože obě byly relativně dost používané, ale někde v mém kódu, chybu se však nepodařilo najít. Proto jsem přistoupil k použití vývojového prostředí Kinetis Design Studio s rozšířením Procesor Expert. Pro projekt jsem vytvořil vlastní knihovnu funkcí, sestavenou dle katalogového listu RFM12B. Některé funkce pak byly částečně inspirovány knihovnou dostupnou na mbed.org.

Inicializace procesoru

Pro inicializaci procesoru byl využit program Processor Expert, který je integrován ve vývojovém prostředí Kinetis Design Studio. Pomocí tohoto programu byly inicializovány vstupní a výstupní pinu procesoru, UART pro komunikaci s PC, časovač pro měření RTT, rychlost procesoru. Dále byla z PE do projektu vložena komponenta WAIT realizující blokující zpoždění.

SPI

Pro komunikaci bylo s modulem bylo implementováno softwarové SPI rozhraní, protože s využitím hardwarového SPI se nepodařilo komunikaci zprovoznit. Softwarová implementace SPI je zřejmá z následujícího zdrojového kódu:

uint16_t sendCMD(uint16_t cmd)
{
    uint16_t reply=0;	// slaves answer 
    uint8_t i=0;
    SCK_ClrVal();		// SCK=SPI clock
    nSEL_ClrVal();		//nSEL=SPI chip select
 
    for(i=0;i<16;i++)
    {
 
      if(cmd&0x8000)
      {
    	  SDI_SetVal();	//SDI=SPI MOSI
      }
      else
      {
    	  SDI_ClrVal();
      }
      //WAIT1_Waitns(10);
      SCK_SetVal();
      //WAIT1_Waitns(50);
      reply<<=1;
      if(SDO_GetVal())	//SDO=SPI MISO
      {
        reply|=0x0001;
      }
      SCK_ClrVal();
      cmd<<=1;
    }
    SCK_ClrVal();
    nSEL_SetVal();
    return(reply);
}

Nevýhodou softwarového SPI je to, že i při maximální možné rychlosti použitého procesoru dosahuje jeho komunikační rychlosti pouze 250 kb/s.

Inicializace modulu.

Jak již bylo zmíněno výše, k nastavování modulu slouží 14 registrů. Na začátku vykonávání programu jsou do nastavovacích registrů zapsány výchozí hodnoty, z nichž některé lze později měnit prostřednictvím konzole v PC. Výchozí nastavení transceiverů: Kmitočet nosné: 868,3 MHz Bitová rychlost: 4,78 kb/s Mód: přijímač Kmitočtový zdvih: 90 kHz Přerušení: 16 přijatých bitů Datový filtr: digitální Výstupní výkon: 5 dBm

Funkce pro inicializaci modulu:

void init(void)
{
 
	  sendCMD(0x80E7); 		// Config. Setting Cmd:  f=868MHz, Tx reg. EN, Rx FIFO EN,XTAL Cload 12pF
	  sendCMD(0x82D9); 		// Power Management Cmd: rcvr EN,BB EN,TX dis,synth EN,osc EN,low-batt DIS,wake-up DIS,CLK out DIS,
	  sendCMD(0xA67C);		// Freq. Setting Cmd:fc= 860,3MHz
	  sendCMD(0xC688);		// Data Rate Cmd: BR=4,79 kbps
	  sendCMD(0x96A0);		// VDI out - SLOW,BB=134kHz,LNA gain=0dBm,RSSI= -103dBm
	  sendCMD(0xC2AC);		// CR auto mode, digital filter, DQD=6
	  sendCMD(0xCAF1);		// nIRQ goes low after 16 received bits, 2 synchro bytes
	  sendCMD(0xCED4);		// synchro pattern Byte0 =0xD4
	  sendCMD(0xC483); 		// keep f ofset,not range limit,enable AFC calc and reg.
	  sendCMD(0x9850); 		// f deviation = 90kHz, max TX power
	  sendCMD(0xCC77);		// CLKout not used, phase noise =-102 dBc/Hz
	  sendCMD(0xE000);		// no effect - wake-up timer is disable 
	  sendCMD(0xC800);		// no effect wake-up time is set to zero
	  sendCMD(0xC000);		// no effect low batt detec is off, CLK out not used
}

Odesílání dat

K zápisu do registru vysílače slouží speciální příkaz 0xB800 kde první dva nibbly (B8h)slouží k identifikaci příkazu a do druhých dvou se vkládají data. Před odesláním dat do modulu je vždy nutné počkat než se uvolní vysílací registr, což je indikováno úrovní na pinu nIRQ.

void send(unsigned char data)
{
  while(nIRQ_GetVal()){}        //waiting for previously TX over
  sendCMD(0xB800|data);
}

Při odesílání paketu dat je nutné na začátku odeslat preambuli se synchonizačními byty a na konci 3 prázdné bity.

void sendDATA(unsigned char *data, unsigned char size)
{
    uint8_t i;
    unsigned char send1[size];
    FIFO_rst();				//reset prijimaci pametu RF modulu
 
    RFmode(TX);				//nastaveni RF modulu do vysilaciho modu
    WAIT1_Waitns(200);
    sendCMD(0x0000);
    send(0xAA);				//preambule
    send(0xAA);
    send(0xAA);
    send(0x2D);
    send(0xD4);				//synchro
 
    for(i=0;i<size;i++)			//send data
    {
      send(*data);
      data++;
    }
    send(0x00);
    send(0x00);
    send(0xAA);				//dummy bytes
    send(0xAA);
    send(0xAA);
 
    RFmode(RX);				//set to RX mode
    WAIT1_Waitns(200);
}

Před začátkem vysílání je samozřejmě nutné přepnout modul do vysílacího módu a po skončení zpět do režimu přijímače. K tomu slouží funkce void RFmode(bool mode);.

void RFmode(bool mode)
{
	if(mode)
	{
		sendCMD(0x8239);
		sendCMD(0x0000);
	}
	else
	{
		sendCMD(0x82D9);
		sendCMD(0x0000);
	}
}

Čtení přijatých dat

Přijetí dat je signalizováno nízkou úrovní na pinu nIRQ. V režimu přijímače je tedy v nekonečné smyčce testován stav tohoto pinu a v případě nízké úrovně je volána funkce void readDATA1(unsigned char data[]); nebo funkce void readDATA(unsigned char FIFO_data[],unsigned char size);. První zmíněná funkce může přijímat libovolně dlouhé pakety, ty však musejí být dvěma znaky ‘’\n’’. Druhá funkce pak přijme paket definované délky, přičemž není vyžadován ukončovací znak.

void readDATA1(unsigned char data[])
{
	  uint8_t i=0;
  	  do
      {
  		 data[i++]=Rx_FIFO();
      }
      while(!((data[i-1]=='\n')||(data[i-2]=='\n')));
      LED_G_PutVal(!LED_G_GetVal());
      FIFO_rst();
      sprintf(data,data);
}
 
void readDATA(unsigned char data[],unsigned char size)
{
  uint8_t i=0;
            for(i=0;i<size;i++)
            {
  		      data[i]=Rx_FIFO();
            }
            LED_G_PutVal(!LED_G_GetVal());
            FIFO_rst();
  sprintf(data,data);
}

Obě funkce pro příjem paketů volají funkci pro čtení jednotlivých bytů Rx_FIFO().

unsigned char Rx_FIFO(void)
{
   unsigned int data_rx, x=100;			//x - number of tests for RX data
   while(x--)						
   {
 
      if((sendCMD(0x0000) & 0x8000))	    	//is byte valid?				
     {
       data_rx =sendCMD(0xB000);			//read the RX byte
       return (data_rx & 0x00FF);		//mask and return		
     }
   }
   return 0;      					//no data
}

Po přijetí datového paketu je nutné resetovat synchronizaci FIFO paměti:

void FIFO_rst(void)
{
	sendCMD(0xCA81);
	sendCMD(0xCA83);
	sendCMD(0x0000);
} 

Měření RTT

Pro měření RTT byl využit 16 – bitový hardwarový časovač. Samotné měření je realizováno tak, že jeden z transceiveru se nastaví tak, že ihned po přijetí paketu dat jej odešle zpět (funkce resender();). Druhý transceiver, který měří RTT vynuluje hodnotu časovače a odešle paket. Jakmile zachytí vrácený paket, je odečtena hodnota časovače a z ní je vypočtena hodnota RTT v milisekundách, pokud se paket nevrátí do 150 ms, je paket považován za ztracený a do konzole je vypsána zpráva RTT>75 ms (funkce RTTmeasure()).

void resender(void)
{
	unsigned char data[128];
 
	while(flags==resend)
	{
		if(!nIRQ_GetVal())
		{
			readDATA(data,64);
			sendDATA(data,64);
		}
	}
}
void RTTmeasure(void)
{
	unsigned char data[128];
	unsigned char RXdata[128];
	sprintf(data,"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz123456789[]\n");
	uint16_t len;
	uint16_t m;
	bool x=1;
	unsigned char c;
	FC1_Reset();
	sendDATA(data,64);
	while(x)
	{
		if(!nIRQ_GetVal())
		{
			readDATA(RXdata,64);
			x=0;
		}
		FC1_GetCounterValue(&m);
		if(m>56250)
		{
			sprintf(data,"RTT > 75 ms\n\n");
			(UART_SendBlock(data,strlen(data),&len));
			x=0;
			return;
		}
	}
	FC1_GetCounterValue(&m);
	while(UART_SendBlock(data,64,&len)!=ERR_OK){}
	float ms=((float)m)/750;			//timer freq is 375 kHz
	m=(ms);
	ms-=m;
	uint16_t n=round(ms*1000);
	sprintf(data,"RTT = %d.%03d ms\n\n",m,n);
	(UART_SendBlock(data,strlen(data),&len));
	return;
}

Měření BER

Měření bitové chybovosti je realizováno pomocí odeslání známe sekvence dat (jeden 64 bytový paket). Po přijetí paketu je paket bit po bitu porovnán s očekávanou sekvencí. V případě chyby je inkrementována příslušná proměnná. BER je pak poměr mezi počtem chyb a celkovým počtem bitů.

float BER(unsigned char *ref, unsigned char *data, uint8_t size)
{
	uint16_t i,err=0;
	unsigned char x;
 
	for(i=0;i<size;i++)
	{
		x=*ref^*data;
		while(x)
		{
			if(x&1) {err++;}
			x=x>>1;
		}
		ref++;
		data++;
	}
	return ((float)err)/((float)(size*8));
}

Nastavování parametrů přenosu dat

Pro nastavování parametrů modulu RFM12B bylo vytvořeno jednoduché menu, které se v PC zobrazuje a ovládá pomocí konzole. V menu lze nastavit rychlost přenosu dat a výstupní výkon vysílače. Dále lze nastavit příslušný transceiver do módu resender, který slouží pro měření RTT pomocí druhého transceiveru. Z konzole lze také odeslat příkaz pro změření RTT nebo prosté odeslání datového paketu, na základě čehož lze změřit BER. Poslední možností v menu je periodické odesílání paketu, to slouží pro testování spoje.

void menu(void)
{
	unsigned char vypis[]={"\n\nMENU\nSend test packet(t)\nSend test packet 200x (n)\nSet data rate (d) \nSet TX power (p)\nSet frequency deviation (f)\nSet as resender (r)\nRTT measure (a)\n\r"};
	uint16_t len;
	erase();
 
	UART_SendBlock(vypis,strlen(vypis),&len);
}
 
 
void dataRATEmenu(void)
{
	erase();
	uint16_t len;
	unsigned char vypis[256];
	sprintf(vypis,"\nSet data rate\n\n  5.4 kbps (1) \n 10.1 kbps (2) \n 20.3 kbps (3) \n 31.3 kbps (4) \n 49.3 kbps (5) \n 68.9 kbps (6) \n 86.2 kbps (7) \n114.9 kbps (8)\n");
    UART_SendBlock(vypis,strlen(vypis),&len);
}
 
void powerMenu(void)
{
	erase();
	uint16_t len;
	unsigned char vypis[256];
	sprintf(vypis,"\nSet data rate\n\n  5 dBm (1) \n 2.5 dBm (2) \n 0 dBm (3) \n -2.5 dBm (4) \n -5 dBm (5) \n -7.5 dBm (6) \n -10 dBm (7) \n-12.5 dbm (8)\n");
    UART_SendBlock(vypis,strlen(vypis),&len);
}
 
void deviationMenu(void)
{
	erase();
	uint16_t len;
	unsigned char vypis[256];
	sprintf(vypis,"\nSet frequency deviation\n\n  15 kHz (0) \n 30 kHz (1) \n 45 kHz (2) \n 60 kHz (3) \n 75 kHz (4) \n 90 kHz (5) \n105 kHz (6) \n120 kHz (7)\n135 kHz (8)\n150 kHz (9)\n165 kHz (A)\n180 kHz (B)\n195 kHz (C)\n210 kHz (D)\n225 kHz (E)\n240 kHz (F)\n");
    UART_SendBlock(vypis,strlen(vypis),&len);
}
 
void erase(void)
{
	  uint16_t len;
	  uint8_t i,j;
	  int8_t k,l;;
	  unsigned char block[128];
  	   i=(uint16_t)(DR);
  	   j=((DR-i)*10);
  	   k=((int8_t)(TXpower));
  	   l=abs(((TXpower-k)*10));
	  sprintf(block,"\e[2J\e[H ***Experimentalni radiovy spoj v pasmu 868 MHz***\n\nfc=868.3 MHz\ndelta f=%d\nData rate =%d.%1d [kbps]\nTX power =%d.%1d\n",fdev,i,j,k,l);
	  UART_SendBlock(block,strlen(block),&len);
}
2015/p2p-rfm12b.1453059661.txt.gz · Poslední úprava: 2016/01/17 20:41 autor: Petr Prachař