RF12 Driver
NOTE: This is not a complete work. I believe an SPIreadWrite method needs to be used to shift in the bytes at the same time as it is shifting out. I’m new to the spin language. But this is what i came up with. Feel free to comment suggestions
CON { .:RF12B wireless tranciever driver V1.0:. .:Written by Bill Heaster:. .:TheCreator at ApexLogic D0t net .:Adapted from JeeLabs Arduino RF12Driver;. } #0, TXIDLE, TXRECV, TXSEND, TXFULL 'Frequency Constants F433 = 0 F868 = 1 F915 = 2 'RF12 Bits RF_RECEIVER_ON = $82DD RF_XMITTER_ON = $823D RF_IDLE_MODE = $820D RF_SLEEP_MODE = $8205 RF_WAKEUP_MODE = $8207 RF_TXREG_WRITE = $B800 RF_RX_FIFO_READ= $B000 RF_WAKEUP_TIMER= $E000 'max buffer size MAXPACKET = 128 'Status Bits RF_LBD_BIT = $0400 RF_RSSI_BIT = $0100 'Node ID stuff NODE_BAND = $C0 NODE_ACKANY = $20 NODE_ID = $1F OBJ Debug : "SimpleDebug" VAR 'Pins , state flags, stacks, and buffers long SDI, SDO, CP, SS, nIRQ, ID, MHZ long intStack[32] long rxfill, rxstate, packetSize byte rf12Buff[MAXPACKET] long in , out, pos, temp, temp2 byte cog byte hdr[3] long count byte tempCheck, checksum, low, high PUB Start(DIpin, DOpin, Cpin, SSpin, nIRQpin, NodeIDarg, MHZarg) Debug.start(115200) Debug.str(STRING("Debug Started")) Debug.newline 'Assign global variables with the methods argument SDI :=DIpin SDO := DOpin CP := Cpin SS := SSpin nIRQ := nIRQpin ID := NodeIDarg MHZ := MHZarg 'Set pin direction of slave select pin, set it to high dira[SS]~~ dira[SDI]~~ dira[SDO]~ dira[CP]~~ dira[nIRQ]~ outa[SS]~~ 'When the interupt pin on the rf12 is pulled low clear it with a fake status read command 'repeat until(ina[nIRQ] == 1) WriteCommand($0000) 'What is our Mhz if(MHZ == F433) WriteCommand($80D8) 'Set registers, 433mhz, 12.5pf WriteCommand($A4B0) 'Set Frequency Center if(MHZ == F868) WriteCommand($80E8) WriteCommand($A640) if(MHZ == F915) WriteCommand($80F8) WriteCommand($A7D0) WriteCommand(RF_IDLE_MODE) 'disable Clock , Enable LBD WriteCommand($C606) '49.2kb/s data rate WriteCommand($94A0) 'fast VDI, -103Dbm, !gain, 134khz BaseBand WriteCommand($C2AC) 'DigitalFilter, clock auto lock WriteCommand($CA8B) 'FIFO8, 1-sync, !ff, DR WriteCommand($C483) 'AFC WriteCommand($9850) '90khz, !MP, !OP WriteCommand($CC77) 'PLL WriteCommand($E000) 'not using low duty cycle WriteCommand($C800) ' not using wakeup timer WriteCommand($C000) '1.0mhz, 2.2v rxState := TXIDLE Debug.str(STRING("txidle")) Debug.newline 'Setup a new COG to handle interrupts cog := cognew(RX(nIRQ), @intStack) return cog PUB Stop if(cog) cogstop(cog~-1) PRI WriteCommand(cmd) | ltemp Debug.hex(cmd,4) Debug.newline outa[CP]~ outa[SS]~ repeat ltemp from 17 to 0 if(cmd & $8000) write1 else write0 cmd<=1 outa[CP]~ outa[SS]~~ PUB canSend if(rxstate==TXRECV & rxfill ==0) WriteCommand(RF_IDLE_MODE) rxstate := TXIDLE return 1 if(rxstate == TXIDLE) return 1 PUB RX(iPin) dira[iPin]~ repeat while(ina[iPin]==0 & rxstate == TXRECV) rf12Buff[rxfill] := ReadFIFO checksum += rf12Buff[rxfill] rxfill++ if(rxfill>=MAXPACKET+5) checksum &= $0FF WriteCommand(RF_IDLE_MODE) rxstate := TXFULL PUB checkData Debug.str(STRING("CheckData")) Debug.newline 'If the buffer is full if(rxstate == TXFULL) if(packetSize > MAXPACKET) checksum := -1 'Send bad crc if the packet length is invalid if(rf12Buff[--rxfill] <> checksum) checksum := -1 'if the packets destination was to this node, or a broadcast packet if((rf12Buff[0] == ID | rf12Buff[0]==31)& checksum > -1) 'return 1 to let us know that we need to parse the buffer return 1 if(rxstate == TXIDLE) recvStart return 0 PRI recvStart rxfill := packetSize := 0 checksum := 0 rxstate := TXRECV WriteCommand(RF_RECEIVER_ON) PUB ReadPacket(myBuffer) | myCount myCount:=0 repeat myCount from 0 to rxfill myBuffer[myCount] := rf12Buff[myCount] bytefill(@rf12Buff, 0, MAXPACKET) WriteCommand(RF_IDLE_MODE) rxstate := TXIDLE return myCount PUB WritePacket(dst, buffer, size, ack) | tempTime bytefill(@rf12Buff, 0,MAXPACKET) packetSize := size checksum := 0 'Assemble the packet into a buffer then send it 'Assemble Header...Destination [0], this node ID[1], 1 for ack 0 for no ack [2] rf12Buff[0] := dst rf12Buff[1] := ID if(ack) rf12Buff[2] := 1 else rf12Buff[2] := 0 count:= 0 repeat count from 0 to size checksum := checksum + buffer[count] rf12Buff[count+3] :=buffer[count] checksum &= $0FF rxstate := TXSEND WriteCommand(RF_XMITTER_ON) tempTime := cnt waitcnt(100_000 + tempTime) 'send preamble WriteByte($AA) WriteByte($AA) WriteByte($AA) 'send sync word WriteByte($D4) count:= 0 repeat count from 0 to size+3 WriteByte(rf12Buff[count]) WriteByte(checksum) WriteByte($AA) WriteCommand(RF_IDLE_MODE) rxstate := TXIDLE PRI Write1 | tempTime tempTime := cnt outa[CP]~ waitcnt(10_000 + tempTime) outa[SDI]~~ tempTime := cnt waitcnt(100_000 + tempTime) outa[CP]~~ tempTime:= cnt waitcnt(10_000 + tempTime) PRI Write0 | tempTime tempTime := cnt outa[CP]~ waitcnt(10_000 + tempTime) outa[SDI]~ tempTime := cnt waitcnt(100_000 + tempTime) outa[CP]~~ tempTime := cnt waitcnt(10_000 + tempTime) PRI WriteByte(outByte) | RGIT, tempOut RGIT := 0 tempOut := RF_TXREG_WRITE | outByte repeat while RGIT == 0 outa[CP]~ outa[SS]~ outa[SDI]~ outa[CP]~~ if(ina[SDO]) RGIT :=1 else RGIT := 0 outa[CP]~ outa[SDI]~~ outa[SS]~~ if(RGIT) WriteCommand(tempOut) PRI ReadFIFO | myResult, tempTime 'set clock and chip select outa[CP]~ outa[SS]~ 'Skip status bytes repeat 17 outa[CP]~~ tempTime := cnt waitcnt(tempTime + 1_000_000) outa[CP]~ tempTime := cnt waitcnt(tempTime + 1_000_000) myResult := 0 repeat 9 myResult <<= 1 if(ina[SDO]) myResult |= 1 outa[CP]~~ tempTime := cnt waitcnt(tempTime + 1_000_000) outa[CP]~ tempTime := cnt waitcnt(tempTime + 1_000_000) outa[SS]~~ return myResult {~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~} {Test stuff below here} {~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~} PUB getStatus | statByte, TempTime statByte := 0 WriteCommand($0000) repeat 17 outa[CP]~~ tempTime := cnt waitcnt(tempTime + 1_000_000) if(ina[SDO] == 1) statByte |=1 outa[CP]~ tempTime := cnt waitcnt(tempTime + 1_000_000) statByte <<=1
CON { .:RF12B wireless tranciever driver V1.0:. .:Written by Bill Heaster:. .:TheCreator at ApexLogic D0t net .:Adapted from JeeLabs Arduino RF12Driver;. } #0, TXIDLE, TXRECV, TXSEND, TXFULL #0, PRE1, PRE2, PRE3, SYNC, HEADER1, HEADER2, HEADER3, SDATA, POST 'Frequency Constants F433 = 0 F868 = 1 F915 = 2 'RF12 Bits RF_RECEIVER_ON = $82DD RF_XMITTER_ON = $823D RF_IDLE_MODE = $820D RF_TXREG_WRITE = $B800 RF_RX_FIFO_READ= $B000 RF_WAKEUP_TIMER= $E000 'max buffer size MAXPACKET = 128 'Status Bits RF_LBD_BIT = $0400 RF_RSSI_BIT = $0100 'Node ID stuff NODE_BAND = $C0 NODE_ACKANY = $20 NODE_ID = $1F OBJ Debug : "SimpleDebug" SPI : "SPI_ASM" VAR 'Pins , state flags, stacks, and buffers long SDI, SDO, CP, SS, nIRQ, ID, MHZ long intStack[128] long rxfill, rxstate, packetSize byte rf12Buff[MAXPACKET] byte rf12hdr[2] long in , out, temp, temp2 byte cog, pos long count byte tempCheck, checksum, low, high long packetState PUB Start(DIpin, DOpin, Cpin, SSpin, nIRQpin, NodeIDarg, MHZarg) SPI.start(1,0) 'Debug.start(115200) 'Debug.str(STRING("Debug Started")) 'Debug.newline 'Assign global variables with the methods argument SDI :=DIpin SDO := DOpin CP := Cpin SS := SSpin nIRQ := nIRQpin ID := NodeIDarg MHZ := MHZarg 'Set pin direction of slave select pin, set it to high dira[SS]~~ dira[SDI]~~ dira[SDO]~ dira[CP]~~ dira[nIRQ]~ outa[SS]~~ 'When the interupt pin on the rf12 is pulled low clear it with a fake status read command repeat while(ina[nIRQ] == 0) WriteCommand($0000) 'What is our Mhz if(MHZ == F433) WriteCommand($80D8) 'Set registers, 433mhz, 12.5pf WriteCommand($A4B0) 'Set Frequency Center if(MHZ == F868) WriteCommand($80E8) WriteCommand($A640) if(MHZ == F915) WriteCommand($80F8) WriteCommand($A7D0) WriteCommand(RF_IDLE_MODE) 'disable Clock , Enable LBD WriteCommand($C606) '49.2kb/s data rate WriteCommand($94A0) 'fast VDI, -103Dbm, !gain, 134khz BaseBand WriteCommand($C2AC) 'DigitalFilter, clock auto lock WriteCommand($CA8B) 'FIFO8, 1-sync, !ff, DR WriteCommand($C483) 'AFC WriteCommand($9850) '90khz, !MP, !OP WriteCommand($CC77) 'PLL WriteCommand($E000) 'not using low duty cycle WriteCommand($C800) ' not using wakeup timer WriteCommand($C000) '1.0mhz, 2.2v rxstate := TXIDLE 'Setup a new COG to handle interrupts stop cog := cognew(handleInt(nIRQ), @intStack) return cog PUB Stop if(cog) cogstop(cog~-1) PRI WriteCommand(cmd) | myHigh, myLow ' Debug.hex(cmd,4) ' Debug.newline outa[SS]~ myLow := cmd & $FF myHigh := cmd >>8 SPI.SHIFTOUT(SDI, CP, SPI#MSBFIRST, 8, myHigh) SPI.SHIFTOUT(SDI, CP, SPI#MSBFIRST, 8, myLow) outa[SS]~~ PUB canSend if(rxstate==TXRECV & rxfill ==0) WriteCommand(RF_IDLE_MODE) rxstate := TXIDLE return 1 if(rxstate == TXIDLE) return 1 else return 0 PUB handleInt(iPin) dira[iPin]~ if(rxstate == TXRECV) SPI.SHIFTOUT(SDI,CP,SPI#MSBFIRST, 8, RF_RX_FIFO_READ) SPI.SHIFTIN(SDO,CP,SPI#MSBPRE, 8) rf12Buff[rxfill] := in checksum += rf12Buff[rxfill] rxfill++ if(rxfill>=MAXPACKET+5) checksum &= $0FF WriteCommand(RF_IDLE_MODE) rxstate := TXFULL if(rxstate==TXSEND & packetState==SDATA) if(pos <= packetSize) txByte(rf12Buff[pos++]) else packetState++ if(rxstate == TXSEND) case packetState PRE1: txByte($AA) packetState++ PRE2: txByte($AA) packetState++ PRE3: txByte($AA) packetState++ SYNC : txByte($D4) pos := 0 packetState++ HEADER1: txByte(rf12hdr[0]) packetState++ HEADER2: txByte(rf12hdr[1]) packetState++ HEADER3: txByte(rf12hdr[2]) packetState++ POST : txByte(checksum) txByte($AA) WriteCommand(RF_IDLE_MODE) rxstate := TXIDLE OTHER : txByte($AA) PUB checkData 'If the buffer is full if(rxstate == TXFULL) if(packetSize > MAXPACKET) checksum := -1 'Send bad crc if the packet length is invalid 'if the packets destination was to this node, or a broadcast packet 'if(( rf12Buff[0] == ID | rf12Buff[0]==31)& checksum > -1) 'return 1 to let us know that we need to parse the buffer return 1 if(rxstate == TXIDLE) recvStart return 0 PRI recvStart rxfill := packetSize := 0 checksum := 0 rxstate := TXRECV WriteCommand(RF_RECEIVER_ON) PUB txByte(myByte) | RGIT RGIT := 0 outa[SS]~ repeat while !RGIT if(ina[SDO]) RGIT := 1 SPI.SHIFTOUT(SDI, CP, SPI#MSBFIRST, 8, RF_TXREG_WRITE) SPI.SHIFTOUT(SDI, CP, SPI#MSBFIRST, 8, myByte) else RGIT := 0 outa[SS]~~ PUB ReadPacket(myBuffer) | myCount bytemove(@myBuffer, @rf12Buff, MAXPACKET) WriteCommand(RF_IDLE_MODE) rxstate := TXIDLE return myCount PUB WritePacket(dst, buffer, size, ack) | tempTime bytefill(@rf12Buff, 0,MAXPACKET) packetSize := size checksum := 0 'Assemble the packet into a buffer 'Assemble Header...Destination [0], this node ID[1], 1 for ack 0 for no ack [2] rf12hdr[0] := dst rf12hdr[1] := ID if(ack) rf12hdr[2] := 1 else rf12hdr[2] := 0 bytemove(@rf12Buff, @buffer, size) repeat count from 0 to size checksum += rf12buff[count] checksum &= $0FF rxstate := TXSEND packetState := PRE1 WriteCommand(RF_XMITTER_ON) PUB checkStatus | outByte outa[SS]~ outByte := SPI.SHIFTIN(SDO, CP, SPI#MSBPRE,8) outa[SS]~~ return outByte
This is a different version using SPI_ASM object.