Modules not being recognised in a main program

Coding and general discussion relating to the compiler

Moderators: David Barker, Jerry Messina

Post Reply
blackcattech
Posts: 113
Joined: Mon Jan 11, 2010 10:39 pm
Location: Chesterfield

Modules not being recognised in a main program

Post by blackcattech » Wed Sep 04, 2013 11:10 am

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?

blackcattech
Posts: 113
Joined: Mon Jan 11, 2010 10:39 pm
Location: Chesterfield

Post by blackcattech » Wed Sep 04, 2013 11:11 am

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

blackcattech
Posts: 113
Joined: Mon Jan 11, 2010 10:39 pm
Location: Chesterfield

Post by blackcattech » Wed Sep 04, 2013 11:13 am

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?

richardb
Posts: 310
Joined: Tue Oct 03, 2006 8:54 pm

Post by richardb » Wed Sep 04, 2013 11:19 am

Unless I misunderstand you,
you need to declare the required parts as public.

have a look at another module.
Hmmm..

blackcattech
Posts: 113
Joined: Mon Jan 11, 2010 10:39 pm
Location: Chesterfield

Post by blackcattech » Wed Sep 04, 2013 11:22 am

In the words of Homer Simpson, 'D'oh!'

Thanks. I knew it would be something really stupid I was doing wrong...

Post Reply