I'm working on a module for the RFM70 transceiver. I've ported the supplied sample code in to Swordfish as a module. All seems OK, the code explorer shows all consts, variables and subs and if I set an option that would normally be set externally, the module compiles.
However, when I try and include it in my main program things go wrong. In the code explorer, if I expand the module it only lists the includes for that module, no consts, vars or subs. If I try and call a sub I get a 'Identifier not found' error.
Any idea what I should be looking for to spot what is causing this? The code was ported from C so I've checked for 0x, ; and {} brackets where they shouldn't be and there aren't any. What else might be wrong?
Modules not being recognised in a main program
Moderators: David Barker, Jerry Messina
-
- Posts: 113
- Joined: Mon Jan 11, 2010 10:39 pm
- Location: Chesterfield
-
- Posts: 113
- Joined: Mon Jan 11, 2010 10:39 pm
- Location: Chesterfield
Some of the code is a bit messy, I've tried to do it quickly so I can test the module work as expected.
Code: Select all
Module RFM70
#option RFM70_CSN = PORTB.4 // Chip Select (active low) pin
#option RFM70_CE = PORTB.0 // Chip Enable pin
#option RFM70_IRQ = PORTB.5 // IRQ pin
#if IsOption(RFM70_SPI1)
Include "SPI.bas"
Dim RFM70_RW As SPI.RWByte
Dim RFM70SPI_WriteByte As SPI.WriteByte
Dim RFM70SPI_SetAsMaster As SPI.SetAsMaster
Dim RFM70SPI_Enabled As SPI.Enabled
Dim RFM70SPI_SetClock As SPI.SetClock
#elseif IsOption(RFM70_SPI2)
Include "SPI2.bas"
Dim RFM70_RW As SPI2.RWByte
Dim RFM70SPI_WriteByte As SPI2.WriteByte
Dim RFM70SPI_SetAsMaster As SPI2.SetAsMaster
Dim RFM70SPI_Enabled As SPI2.Enabled
Dim RFM70SPI_SetClock As SPI2.SetClock
#elseif IsOption(RFM70_SSPI)
Include "SSPI.bas"
Dim RFM70_RW As SSPI.RWByte
Dim RFM70SPI_WriteByte As SSPI.WriteByte
Dim RFM70SPI_Init As SSPI.Initialize
Dim RFM70SPI_SetClock As SSPI.SetClock
#else
#error "SPI port not defined for display. Set #option true for either RFM70_SPI1, RFM70_SPI2 or RFM70_SSPI."
#endif
#option RFM70_SPI_CLOCK = spiOscDiv16 // Clock rate for SPI. See SPI module for options. Not used with software SPI module.
#option RFM70_MAX_PACKET_LEN = 32
// Bring the options in to the module
Const R_PACKET_LEN = RFM70_MAX_PACKET_LEN
Const R_CLOCK = RFM70_SPI_CLOCK
Include "system.bas"
Dim
R_CSN As RFM70_CSN.RFM70_CSN@, // Data/Command pin
R_CE As RFM70_CE.RFM70_CE@, // Reset pin
R_IRQ As RFM70_IRQ.RFM70_IRQ@ // Chip select pin
//************************FSK COMMAND and REGISTER****************************************//
// SPI(RFM70) commands
Const READ_REG = $00 // Define read command to register
Const WRITE_REG = $20 // Define write command to register
Const RD_RX_PLOAD = $61 // Define RX payload register address
Const WR_TX_PLOAD = $A0 // Define TX payload register address
Const FLUSH_TX = $E1 // Define flush TX register command
Const FLUSH_RX = $E2 // Define flush RX register command
Const REUSE_TX_PL = $E3 // Define reuse TX payload register command
Const W_TX_PAYLOAD_NOACK_CMD = $b0
Const W_ACK_PAYLOAD_CMD = $a8
Const ACTIVATE_CMD = $50
Const R_RX_PL_WID_CMD = $60
Const NOP_NOP = $FF // Define No Operation, might be used to read status register
// SPI(RFM70) registers(addresses)
Const ConfigR = $00 // 'Config' register address
Const EN_AA = $01 // 'Enable Auto Acknowledgment' register address
Const EN_RXADDR = $02 // 'Enabled RX addresses' register address
Const SETUP_AW = $03 // 'Setup address width' register address
Const SETUP_RETR = $04 // 'Setup Auto. Retrans' register address
Const RF_CH = $05 // 'RF channel' register address
Const RF_SETUP = $06 // 'RF setup' register address
Const STATUS = $07 // 'Status' register address
Const OBSERVE_TX = $08 // 'Observe TX' register address
Const CD = $09 // 'Carrier Detect' register address
Const RX_ADDR_P0 = $0A // 'RX address pipe0' register address
Const RX_ADDR_P1 = $0B // 'RX address pipe1' register address
Const RX_ADDR_P2 = $0C // 'RX address pipe2' register address
Const RX_ADDR_P3 = $0D // 'RX address pipe3' register address
Const RX_ADDR_P4 = $0E // 'RX address pipe4' register address
Const RX_ADDR_P5 = $0F // 'RX address pipe5' register address
Const TX_ADDR = $10 // 'TX address' register address
Const RX_PW_P0 = $11 // 'RX payload width, pipe0' register address
Const RX_PW_P1 = $12 // 'RX payload width, pipe1' register address
Const RX_PW_P2 = $13 // 'RX payload width, pipe2' register address
Const RX_PW_P3 = $14 // 'RX payload width, pipe3' register address
Const RX_PW_P4 = $15 // 'RX payload width, pipe4' register address
Const RX_PW_P5 = $16 // 'RX payload width, pipe5' register address
Const FIFO_STATUS = $17 // 'FIFO Status Register' register address
Const DYNPD = $1C // Dynamic payload enable register address
Const FEATURE = $1D // Feature register address
Const PAYLOAD_WIDTH = $1f // 'payload length of 256 bytes modes register address
//interrupt status
Const STATUS_RX_DR = $40
Const STATUS_TX_DS = $20
Const STATUS_MAX_RT = $10
Const STATUS_TX_FULL = $01
//FIFO_STATUS
Const FIFO_STATUS_TX_REUSE = $40
Const FIFO_STATUS_TX_FULL = $20
Const FIFO_STATUS_TX_EMPTY = $10
Const FIFO_STATUS_RX_FULL = $02
Const FIFO_STATUS_RX_EMPTY = $01
Dim op_status As Byte
// Bank1 register initialization value
// To translate from the datasheet, please write random gibberish to the registers in Bank 1 otherwise the module won't work....
Const Bank1_Reg0_13() As LongWord = (
$E2014B40,
$00004BC0,
$028CFCD0,
$41390099,
$0B869Ef9,
$A67F0624,
$00000000,
$00000000,
$00000000,
$00000000,
$00000000,
$00000000,
$00127300,
$36B48000 )
Const Bank1_Reg14() As Byte = ( $41, $20, $08, $04, $81, $20, $CF, $F7, $FE, $FF, $FF )
// Bank0 register initialization value
// Refer to datasheet for options for these registers. Only bytes defined here, anything more unusual defined separately
// Re-do these as defines eventually so they can be changed in main code
Const B0_CONFIG = $4E // $00- Transmit mode so mask off RX interrupt. Enable CRC with 2 bytes, Power up and PTX mode
Const B0_EN_AA = $3F // $01- Enable auto acknowledgement on all data pipes
Const B0_EN_RXADDR = $03 // $02- Enable RX Addresses, enable data pipes 0 and 1 only
Const B0_SETUP_AW = $03 // $03- RX/TX address field width 5byte
Const B0_SETUP_RETR = $3F // $04- auto retransmission dalay (1000us),auto retransmission count(15)
Const B0_RF_CH = $42 // $05- Set frequency channel. Can be 0 to 83 (decimal). Sets offset from 2.4GHz in MHz
Const B0_RF_SETUP = $37 // $06- air data rate-1M,out power 5dbm,setup LNA gain to high
Const B0_STATUS = $70 // $07- Status Register. Many bits are read only. $70 clears all interrupts
// $08 - OBSERVE_TX - Read Only
// $09 - CD - Read Only
// $0A - RX_ADDR_P0 - Defined and written elsewhere
// $0B - RX_ADDR_P1 - Defined and written elsewhere
Const B0_RX_ADDR_P2 = $c3 // $0C - Pipe 2 address (LSB only, MSBs shared with Pipe 1) These four addresses can be changed to suit
Const B0_RX_ADDR_P3 = $c4 // $0D - Pipe 3 address LSB
Const B0_RX_ADDR_P4 = $c5 // $0E - Pipe 4 address LSB
Const B0_RX_ADDR_P5 = $c6 // $0F - Pipe 5 address LSB
// $10 - TX_ADDR - write elsewhere and set to RX_ADDR_0
Const B0_RX_PW_P0 = $0E // $11 - Pipe 0 width. Unit setup commands received here. 10 byte header then data. To be defined later. (E = 14)
Const B0_RX_PW_P1 = $06 // $12 - Pipe 1 width. Stores temperature in ASCII format xxx.y<null>
Const B0_RX_PW_P2 = $01 // $13 - Pipe 2 width. Stores an error code - single byte.
Const B0_RX_PW_P3 = $20 // $14 - Pipe 3 width.
Const B0_RX_PW_P4 = $20 // $15 - Pipe 4 width.
Const B0_RX_PW_P5 = $20 // $16 - Pipe 5 width.
// $17 - Fifo status - read only
// $18 - No register
// $19 - No register
// $1A - No register
// $1B - No register
Const B0_DYNPD = $00 // $1C - DYNamic PayloaD length. Bits 5>0 set high to enable for pipes 5>0, clear to set fixed payload length.
Const B0_FEATURE = $03 // $1D - Feature register. Bit 2 enables Dynamic Payload Length, Bit 1 enables payload with ACK, Bit 0 enables W_TX_PAYLOA_NOACK command
Const RX0_Address() As Byte = ($34, $43, $10, $10, $01) // Receive address data pipe 0
Const RX1_Address() As Byte = ($39, $38, $37, $36, $c2) // Receive address data pipe 1
///////////////////////////////////////////////////////////////////////////////
// SPI access //
///////////////////////////////////////////////////////////////////////////////
// Uses Swordfish SPI library plus added RWByte command
// Write a value to a register
Sub RFM70_Write_Reg(pReg As Byte, pData As Byte)
R_CSN = 0 // CSN low to init SPI
op_status = RFM70_RW(pReg) // Select the register
RFM70_RW(pData) // Write data to it
R_CSN = 1 // Pull CSN high to end access
End Sub
// Read the contents of a register
Function RFM70_Read_Reg(pReg As Byte) As Byte
Dim value As Byte
R_CSN = 0
op_status = RFM70_RW(pReg) // Select register to read from
value = RFM70_RW(0) // read value
R_CSN = 1
result = value // return it
End Function
// Read a FIFO in to a memory buffer
Sub RFM70_Read_Buf(pReg As Byte, ByRef pBuf() As Byte, length As Byte)
Dim stat, byte_ctr As Byte
R_CSN = 0
stat = RFM70_RW(pReg)
For byte_ctr = 0 To length-1
pBuf(byte_ctr) = RFM70_RW(0)
Next
R_CSN = 1
End Sub
Sub RFM70_Write_Buf(pReg As Byte, ByRef pBuf() As Byte, length As Byte)
Dim byte_ctr As Byte
R_CSN = 0
op_status = RFM70_RW(pReg) // Select register to write to
For byte_ctr = 0 To length-1 // Loop though buffer
RFM70_RW(pBuf(byte_ctr)) // Writing bytes to RFM70 in turn
Next
R_CSN = 1
End Sub
Sub RFM70_Write_Buf(pReg As Byte, ByRefConst pBuf() As Byte, length As Byte)
Dim byte_ctr As Byte
R_CSN = 0
op_status = RFM70_RW(pReg) // Select register to write to
For byte_ctr = 0 To length-1 // Loop though buffer
RFM70_RW(pBuf(byte_ctr)) // Writing bytes to RFM70 in turn
Next
R_CSN = 1
End Sub
Sub RFM70_To_RXMode()
Dim value As Byte
RFM70_Write_Reg(FLUSH_RX,0) // Flush RX buffers
value = RFM70_Read_Reg(STATUS) // Read status register
RFM70_Write_Reg(WRITE_REG Or STATUS, value) // Clear interrupt flags
R_CE = 0 // Can only manipulate registers in a standby mode so disable chip
value = RFM70_Read_Reg(ConfigR) // Read CONFIG register contents
value = value Or 1 // Set bit 1
RFM70_Write_Reg(WRITE_REG Or ConfigR, value) // Write register contents back with PRIM_RX set
R_CE = 1 // Re-enable chip
End Sub
Sub RFM70_To_TXMode()
Dim value As Byte
RFM70_Write_Reg(FLUSH_TX,0) // Flush TX buffers
R_CE = 0 // Can only manipulate registers in standby modes so disable chip
value = RFM70_Read_Reg(ConfigR) // Read CONFIG register value
value = value And $FE // Clear bit 0
RFM70_Write_Reg(WRITE_REG Or ConfigR, value) // Clear PRIM_RX bit to set to transmit mode. Other settings unchanged
R_CE = 1
End Sub
// Switch between register banks. Call with 0 for Bank 0, 1 for Bank 1
Sub RFM70_SwitchCFG(_cfg As Byte)
Dim tmp As Byte
tmp = RFM70_Read_Reg(7)
tmp = tmp And $80 // Mask of all but bit 7 to find which bank is currently selected
tmp = tmp >> 7 // Move MSB to LSB
If tmp <> _cfg Then RFM70_Write_Reg(ACTIVATE_CMD,$53) EndIf // If bank called for is not selected then issue the 'swap bank' command
End Sub
Sub RFM70_SetChannelNum(ch As Byte)
RFM70_Write_Reg( WRITE_REG Or 5, ch)
End Sub
///////////////////////////////////////////////////////////////////////////////
// RFM70 initialization //
///////////////////////////////////////////////////////////////////////////////
Sub RFM70_Init()
Dim i,j,tmp As Byte
Dim WriteArr(4) As Byte
DelayMS(200) // Calls for a min. 50ms delay. No idea why, not documented.
// *** Write bank 0 registers ***
RFM70_SwitchCFG(0) // Select bank 0
RFM70_Write_Reg( WRITE_REG Or ConfigR, B0_CONFIG )
RFM70_Write_Reg( WRITE_REG Or EN_AA, B0_EN_AA )
RFM70_Write_Reg( WRITE_REG Or EN_RXADDR, B0_EN_RXADDR )
RFM70_Write_Reg( WRITE_REG Or SETUP_AW, B0_SETUP_AW )
RFM70_Write_Reg( WRITE_REG Or SETUP_RETR, B0_SETUP_RETR )
RFM70_Write_Reg( WRITE_REG Or RF_CH, B0_RF_CH )
RFM70_Write_Reg( WRITE_REG Or RF_SETUP, B0_RF_SETUP )
RFM70_Write_Reg( WRITE_REG Or STATUS, B0_STATUS )
RFM70_Write_Buf( WRITE_REG Or RX_ADDR_P0, RX0_Address, 5 )
RFM70_Write_Buf( WRITE_REG Or RX_ADDR_P1, RX1_Address, 5 )
RFM70_Write_Reg( WRITE_REG Or RX_ADDR_P2, B0_RX_ADDR_P2 )
RFM70_Write_Reg( WRITE_REG Or RX_ADDR_P3, B0_RX_ADDR_P3 )
RFM70_Write_Reg( WRITE_REG Or RX_ADDR_P4, B0_RX_ADDR_P4 )
RFM70_Write_Reg( WRITE_REG Or RX_ADDR_P5, B0_RX_ADDR_P5 )
RFM70_Write_Buf( WRITE_REG Or TX_ADDR, RX0_Address, 5 ) // Set TX address to R0 address to allow auto ack.
RFM70_Write_Reg( WRITE_REG Or RX_PW_P0, B0_RX_PW_P0 )
RFM70_Write_Reg( WRITE_REG Or RX_PW_P1, B0_RX_PW_P1 )
RFM70_Write_Reg( WRITE_REG Or RX_PW_P2, B0_RX_PW_P2 )
RFM70_Write_Reg( WRITE_REG Or RX_PW_P3, B0_RX_PW_P3 )
RFM70_Write_Reg( WRITE_REG Or RX_PW_P4, B0_RX_PW_P4 )
RFM70_Write_Reg( WRITE_REG Or RX_PW_P5, B0_RX_PW_P5 )
i = RFM70_Read_Reg(29) // Read feature register.
If i = 0 Then RFM70_Write_Reg(ACTIVATE_CMD, $73) EndIf // i > 0 shows chip is already active, if no then send activate command
RFM70_Write_Reg( WRITE_REG Or FEATURE, B0_FEATURE )
RFM70_Write_Reg( WRITE_REG Or DYNPD, B0_DYNPD )
// *** Write Bank 1 registers ***
RFM70_SwitchCFG(1)
For i = 0 To 8
WriteArr(0) = Bank1_Reg0_13(i).byte0 // Long word > byte array, LSByte first
WriteArr(1) = Bank1_Reg0_13(i).byte1
WriteArr(2) = Bank1_Reg0_13(i).byte2
WriteArr(3) = Bank1_Reg0_13(i).byte3
RFM70_Write_Buf( WRITE_REG Or i, WriteArr, 4 )
Next
For i = 9 To 13
WriteArr(0) = Bank1_Reg0_13(i).byte3 // Long word > byte array, MSByte first
WriteArr(1) = Bank1_Reg0_13(i).byte2
WriteArr(2) = Bank1_Reg0_13(i).byte1
WriteArr(3) = Bank1_Reg0_13(i).byte0
RFM70_Write_Buf( WRITE_REG Or i, WriteArr, 4 )
Next
RFM70_Write_Buf( WRITE_REG Or 14, Bank1_Reg14, 11)
i = 4
WriteArr(0) = Bank1_Reg0_13(i).byte0
WriteArr(1) = Bank1_Reg0_13(i).byte1
WriteArr(2) = Bank1_Reg0_13(i).byte2
WriteArr(3) = Bank1_Reg0_13(i).byte3
WriteArr(0) = WriteArr(0) Or $06
RFM70_Write_Buf( WRITE_REG Or 4, WriteArr, 4)
WriteArr(0) = WriteArr(0) And $F9
RFM70_Write_Buf( WRITE_REG Or 4, WriteArr, 4)
DelayMS(50)
RFM70_SwitchCFG(0)
RFM70_To_RXMode
End Sub
-
- Posts: 113
- Joined: Mon Jan 11, 2010 10:39 pm
- Location: Chesterfield
Oh, and I should mention I've added a RW_Byte command to the SPI modules which simply returns the SSP Buffer register after writing a byte. My understanding of the SSP module is that data is clocked in as it is being clocked out so it reads and writes at the same time.
I would suspect there is no reason I couldn't just modify the Write_Byte command to return this value instead - I believe that function returns are ignored if not used?
I would suspect there is no reason I couldn't just modify the Write_Byte command to return this value instead - I believe that function returns are ignored if not used?
-
- Posts: 113
- Joined: Mon Jan 11, 2010 10:39 pm
- Location: Chesterfield