Hi all, RF12 module is a bit tricky on Netduino+ 1st brood. On NDP2 works like a charm.
I'm going to post a class to control the module but bear in mind that NDP1 is a bit too slow to interact with the module as good as Arduino does. For my case is fully functional but if anybody finds any issue, please let me know. In case you need assistance for wiring write down a line.
using System;using Microsoft.SPOT;using Microsoft.SPOT.Hardware;using SecretLabs.NETMF.Hardware.NetduinoPlus;using System.Threading;namespace RFM12BLib{ public class RFM12B { private SPI _spiPort; private InterruptPort interrupt; //private OutputPort _led; private TransceiveStates rxstate; private byte nodeID; private byte networkID; public delegate void BdEventHandler(uint from, uint channel, uint value); public BdEventHandler OnCommand; public RFM12B(Cpu.Pin spiSelectPin, byte ID, byte netID) { GRP = netID; SPI.SPI_module spi = SecretLabs.NETMF.Hardware.NetduinoPlus.SPI_Devices.SPI1; _spiPort = new SPI(new SPI.Configuration(spiSelectPin, false, 0, 0, false, true, 2000, spi)); interrupt = new InterruptPort(Pins.GPIO_PIN_D9, true, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeLow); InitModule(ID, RF12_433MHZ, netID, 0x07, 0x3F, 0x07); Debug.Print("SETUP"); } private void InitModule(byte ID, ushort freqBand, byte networkid, ushort txPower, ushort airKbps, ushort lowVoltageThreshold) { nodeID = ID; networkID = networkid; RFXX_WRT_CMD(0x0000); // intitial SPI transfer added to avoid power-up problem RFXX_WRT_CMD(RF_SLEEP_MODE); // DC (disable clk pin), enable lbd // wait until RFM12B is out of power-up reset, this takes several *seconds* RFXX_WRT_CMD(RF_TXREG_WRITE); // in case we're still in OOK mode while (!interrupt.Read()) RFXX_WRT_CMD(0x0000); //CONFIGURATION RFXX_WRT_CMD(0x80D3);//EL,EF,433band,10.0pF //FREQUENCY SETTINGS RFXX_WRT_CMD(0xA640); // Frequency is exactly 434/868/915MHz (whatever freqBand is) //DATA RATE RFXX_WRT_CMD(0xC647);//0xC647 = 4.8kbps , 8F = 2.4 RFXX_WRT_CMD(0x90A2); // VDI,FAST,134kHz,0dBm,-91dBm RFXX_WRT_CMD(0xC2AC); // AL,!ml,DIG,DQD4 if (networkID != 0) { //RFXX_WRT_CMD(0xCA81); // FIFO8,2-SYNC,!ff,DR RFXX_WRT_CMD(0xCA83); // FIFO8,2-SYNC,!ff,DR RFXX_WRT_CMD((ushort)(0xCE00 | networkID)); // SYNC=2DXX; } else { RFXX_WRT_CMD(0xCA8B); // FIFO8,1-SYNC,!ff,DR RFXX_WRT_CMD(0xCE2D); // SYNC=2D; } RFXX_WRT_CMD(0xC483); // @PWR,NO RSTRIC,!st,!fi,OE,EN RFXX_WRT_CMD((ushort)(0x9850 | (txPower > 7 ? 7 : txPower))); // !mp,90kHz,MAX OUT //last byte=power level: 0=highest, 7=lowest RFXX_WRT_CMD(0xCC77); // OB1,OB0, LPX,!ddy,DDIT,BW0 RFXX_WRT_CMD(0xE000); // NOT USE RFXX_WRT_CMD(0xC800); // NOT USE RFXX_WRT_CMD(0xC043); // Clock output (1.66MHz), Low Voltage threshold (2.55V) interrupt.OnInterrupt += new NativeEventHandler(_interruptPort_OnInterrupt); interrupt.EnableInterrupt(); SetReceiving(); RFXX_WRT_CMD(0x0000); } byte[] data = new byte[20]; public void _interruptPort_OnInterrupt(uint data1, uint data2, DateTime time) { RFXX_WRT_CMD(0x0000); //RECEIVING if (rxstate == TransceiveStates.TXRECV) { GRP = (byte)RF12_RECV(); if (GRP == 0 || GRP == 1) { if (GRP == 0) // NULL GRP { while (interrupt.Read()) ; RFXX_WRT_CMD(0x0000); HDR1 = (byte)RF12_RECV(); } else { HDR1 = GRP; } byte destId = (byte)(HDR1 & 0x7F); if (destId == 1) { while (interrupt.Read()) ; RFXX_WRT_CMD(0x0000); HDR2 = (byte)RF12_RECV(); while (interrupt.Read()) ; RFXX_WRT_CMD(0x0000); LEN = (byte)RF12_RECV(); bool ctl = ((HDR2 >> 5) & 0x04) != 0; bool dst = ((HDR2 >> 5) & 0x02) != 0; bool ack = (HDR2 & 0x80) != 0; for (int b = 0; b < 20; b++) { if (b < LEN) { while (interrupt.Read()) ; RFXX_WRT_CMD(0x0000); data[b] = (byte)RF12_RECV(); } else { data[b] = 0; } } try { Debug.Print("INT |" + ToHex(new byte[] { GRP }) + " | " + ToHex(new byte[] { HDR1 }) + " | " + ToHex(new byte[] { HDR2 }) + " | " + ToHex(new byte[] { LEN }) + " | " + (ack ? "ACK" : " NO ACK ") + " | " + new string(System.Text.Encoding.UTF8.GetChars(data)) ); } catch (Exception) { Debug.Print("Invalid data"); } } } else { Debug.Print("G: " + ToHex(new byte[] { GRP })); } idleMode(); SetReceiving(); interrupt.ClearInterrupt(); } } private void SendAck() { SendTo(SRC_ID, new byte[]{}, false, true); } public void SendToNoAck(byte toNodeID, byte[] data) { SendTo(toNodeID, data, false, false); } public void SendTo(byte toNodeID, byte[] data) { SendTo(toNodeID, data, true, false); } private void SendTo(byte toNodeID, byte[] data, bool requestACK, bool sendAck) { if (rxstate != TransceiveStates.TXIDLE) { idleMode(); Thread.Sleep(500); } HDR1 = (byte)(toNodeID | (sendAck ? RF12_HDR_ACKCTLMASK : 0)); HDR2 = (byte)(nodeID | (requestACK ? RF12_HDR_ACKCTLMASK : 0)); LEN = (byte)(data.Length + 1); rxstate = TransceiveStates.TXSEND; RFXX_WRT_CMD(RF_XMITTER_ON); sendit(requestACK, data); idleMode(); SetReceiving(); } private void sendit(bool requestACK, byte[] data) { //SENDING rf12_crc = crc16_update(0xFFFF, networkID); rf12_crc = crc16_update(rf12_crc, HDR1); rf12_crc = crc16_update(rf12_crc, HDR2); foreach (byte b in data) rf12_crc = crc16_update(rf12_crc, b); while (interrupt.Read()) ; RFXX_WRT_CMD(0x0000); RF12_SEND(0xAA); while (interrupt.Read()) ; RFXX_WRT_CMD(0x0000); RF12_SEND(0xAA); while (interrupt.Read()) ; RFXX_WRT_CMD(0x0000); RF12_SEND(0xAA); while (interrupt.Read()) ; RFXX_WRT_CMD(0x0000); RF12_SEND(0x2D); while (interrupt.Read()) ; RFXX_WRT_CMD(0x0000); RF12_SEND(networkID); while (interrupt.Read()) ; RFXX_WRT_CMD(0x0000); RF12_SEND(HDR1); while (interrupt.Read()) ; RFXX_WRT_CMD(0x0000); RF12_SEND(HDR2); while (interrupt.Read()) ; RFXX_WRT_CMD(0x0000); RF12_SEND(LEN); if (LEN > 0) { foreach (byte b in data) { while (interrupt.Read()) ; RFXX_WRT_CMD(0x0000); RF12_SEND(b); } } while (interrupt.Read()) ; RFXX_WRT_CMD(0x0000); RF12_SEND((byte)(rf12_crc >> 8)); while (interrupt.Read()) ; RFXX_WRT_CMD(0x0000); RF12_SEND((byte)rf12_crc); while (interrupt.Read()) ; RFXX_WRT_CMD(0x0000); RF12_SEND(0xAA); while (interrupt.Read()) ; RFXX_WRT_CMD(0x0000); RF12_SEND(0xAA); /* Debug.Print("SENT " + ToHex(new byte[] { 0xAA }) + " | " + ToHex(new byte[] { 0xAA }) + " | " + ToHex(new byte[] { 0xAA }) + " | " + ToHex(new byte[] { 0x2D }) + " | " + ToHex(new byte[] { networkID }) + " | " + ToHex(new byte[] { HDR1 }) + " | " + ToHex(new byte[] { HDR2 }) + " | " + ToHex(new byte[] { LEN }) + " | " + new string(System.Text.Encoding.UTF8.GetChars(DATA)) + " | " + ToHex(new byte[] { (byte)rf12_crc }) + " | " + ToHex(new byte[] { (byte)(rf12_crc >> 8) }) + " | " + ToHex(new byte[] { 0xAA }) + " | " + ToHex(new byte[] { 0xAA }) + " | "); */ } public void idleMode() { RFXX_WRT_CMD(RF_IDLE_MODE); rxstate = TransceiveStates.TXIDLE; } public void SetReceiving() { rf12_crc = 0xFFFF; if (rxstate != TransceiveStates.TXRECV) { RFXX_WRT_CMD(RF_RECEIVER_ON); rxstate = TransceiveStates.TXRECV; } } /* private void resetFIFO() { RFXX_WRT_CMD(0xCA81); RFXX_WRT_CMD(0xCA83); } */ private ushort SPI_WRITE_READ(ushort cmd) { ushort[] readBuffer = new ushort[1]; _spiPort.WriteRead(new ushort[] { cmd }, readBuffer); return readBuffer[0]; } private void SPI_WIRTE(ushort cmd) { _spiPort.Write(new ushort[] { cmd }); } ushort[] _readBuf = new ushort[1]; ushort[] _writeBuf = new ushort[1]; private ushort RFXX_WRT_CMD(ushort cmd) { _writeBuf[0] = cmd; _spiPort.WriteRead(_writeBuf, _readBuf); return (_readBuf[0]); } private ushort RF12_RECV() { ushort FIFO_data; //RFXX_WRT_CMD(0x0000); FIFO_data = RFXX_WRT_CMD(0xB000); return (ushort)(FIFO_data & 0x00FF); } private void RF12_SEND(byte data) { RFXX_WRT_CMD((ushort)(RF_TXREG_WRITE | data)); } private enum TransceiveStates { TXIDLE, TXRECV, TXSEND }; private enum SleepModes { SLEEP_MODE_IDLE = 0, SLEEP_MODE_PWR_DOWN = 1, SLEEP_MODE_PWR_SAVE = 2, SLEEP_MODE_ADC = 3, SLEEP_MODE_STANDBY = 4, SLEEP_MODE_EXT_STANDBY = 5 } private byte GRP = 0x01; private byte HDR1; private byte HDR2; private byte LEN; private byte SRC_ID { get { return (byte)(HDR2 & RF12_HDR_IDMASK); } } private byte DST_ID { get { return (byte)(HDR1 & RF12_HDR_IDMASK); } } private ushort crc16_update(ushort crc, byte data) { int i; crc = (ushort)(crc ^ ((ushort)data << 8)); for (i = 0; i < 8; i++) { if ((crc & 0x8000) == 0x8000) crc = (ushort)((crc << 1) ^ 0x1021); else crc <<= 1; } return crc; } private bool CRCPass() { return rf12_crc == 0; } private const ushort RF_SLEEP_MODE = 0x8205; private const ushort RF_TXREG_WRITE = 0xB800; private const ushort RF12_433MHZ = 0x01; private const ushort RF_IDLE_MODE = 0x820D; private const ushort RF_RX_FIFO_READ = 0xB000; private const ushort RF_WAKEUP_TIMER = 0xE000; private const ushort RF_WAKEUP_MODE = 0x8207; private const ushort RF_RSSI_BIT = 0x0100; private const ushort RF_RECEIVER_ON = 0x82DD; private const ushort RF_XMITTER_ON = 0x823D; private const byte RF12_HDR_ACKCTLMASK = 0x80; private const byte RF12_HDR_IDMASK = 0x7F; private ushort rf12_crc; private string _Alpha = "0123456789ABCDEF"; private string ToHex(byte[] Blob) { int Len = Blob.Length; char[] res = new char[Len * 2]; for (int i = 0; i < Blob.Length; i++) { byte r = (byte)(Blob[i] % 16); byte v = (byte)((byte)(Blob[i] - r) / 16); res[(i + 1) * 2 - 1] = _Alpha[r]; res[(i + 1) * 2 - 2] = _Alpha[v]; } return new string(res); } }}