Hello Forum,
I have developed a system to program microcontrollers wirelessly using the nRF24L01 module. I include the Bascom files below.
The way it works:
Micro #1 - Base
- mega328 with LCD and nRF24L01 module
- file UART.nrf24l01.BL.Base.1.bas is compiled and loaded into mega328 using ISP programmer (or for the sophisticated user use the Bascom UART Bootloader).
- UART connected to computer with Bascom
- Bascom configured with Programmer as MCS Loader with COM Port pointing to UART on mega328.
Micro #2 - Remote
- mega644p (in my case) with UART to second computer (or second COM Port) with nRF24L01 module
- file BL.Remote.M644P.nRF24L01.UART.1.bas is compiled and loaded into Bootloader area with ISP Programmer
- FuseBits: BOOTSZ=7800 and BOOTRST set.
Usage:
1. Micro #2 should be showing title and countdown on UART.
2. Micro #1 should be displaying "WaitPC?" on LCD.
3. From Bascom, select and compile the target *.bas file to transfer to Micro #2.
4. Push F4. File should be transferred from the Bascom PC to Micro #1, then wirelessly transmitted to micro#2 and finally be programmed into micro#2 by the wireless bootloader receiver.
Enjoy. Please post any improvements
Ennio M
[PS: special thanks to Evert Dekker for the inspiration and for preparing AN#151.]
[PS1: I had previously developed a similar system using the Microchip MRF24J40MA module. It is IEEE 802.15 compliant with AES-128 security-enabled communication with 64-bit addressing. If anyone is interested in this for commercial, industrial or military applications, please let me know.]
[code:1:36deabc27d]'===UART.nrf24l01.BL.Base.1.bas==========================================
'Bootloader Base - Ver 1.0
'328 Board w/nRF24L01
'Nov 15/13
'
'Thanks to Evert Dekker for the inspiration and BASCOM AN#151
'=============================================
$regfile = "m328def.dat"
$crystal = 8000000
$baud = 38400
$hwstack = 80 ' default use 32 for the hardware stack
$swstack = 40 ' default use 10 for the SW stack
$framesize = 80 ' default use 40 for the frame space
$loadersize = $1000
'==========================================
'Overall AtMega Config
'==========================================
Config Portb.2 = Output
Set Portb.2
Config Spi = Hard , Interrupt = Off , Data Order = Msb , Master = Yes , Polarity = Low , Phase = 0 , Clockrate = 4 , Noss = 1
Spiinit
'============================================
'nRF24L01+ Nordic Semiconductor
'============================================
Const Dev_id = 1 'Address LSB of BASE device
Nrfce Alias Portc.0
Config Nrfce = Output
Nrfce = 1
Nrfcs Alias Portc.1
Config Nrfcs = Output
Nrfcs = 1
nrfint Alias Pinc.2
Config Nrfint = Input
Declare Sub R_register(byval Command As Byte , Byval Start_b As Byte , Byval Num_b As Byte)
Declare Sub W_register(byval Start_b As Byte , Byval Num_b As Byte)
Declare Sub Nrf24l01init()
Declare Function Transmit(byval Tx As Byte , Byval Pl_w As Byte) As Byte
Declare Function Receive() As Byte
'SPI(nRF24L01) commands
Const Write_reg = &H20 'Define Write Command To Register
Const Rd_rx_pload = &H61 'Define Rx Payload Register Address
Const Wr_tx_pload = &HA0 'Define Tx Payload Register Address
Const Flush_tx = &HE1 'Define Flush Tx Register Command
Const Flush_rx = &HE2 'Define Flush Rx Register Command
'Registers
Const Config_nrf = &H00
Const Status = &H07
Const Fifo_stat = &H17
Const Tx_addr = &H10
Const Rx_addr_p0 = &H0A
Const R_rx_pl_wid = &B01100000
'VALUES
Const Nrfwait = 5 'This can be optimized.
'CAUTION:
'The nRF24L01 module has a 3-level Receive FIFO
'and a 3-level Transmit FIFO. If TX is too fast, the data
'may go into a level other than the first and this Bootloader
'will not work.
Const V_irq_reset = &B01110000
Const V_set_tx = &B00001010 'PRX=1(RX_device), PWR_UP=1, CRC 2bytes, Enable CRC
Const V_set_rx = &B00001011 'Make sure this matches DATA lines
'&B00001111
' ^ Module function as 0=TX, 1=RX
' ^ 0=Power Down, 1=Up
' ^ CRC type 0=1 byte, 1=2 byte
' ^ Enable CRC
' x^^^ Three sources of interrupts 0=enabled
'====================================================
'RAM dBase Array
'====================================================
'This RAM array assumes a 4-byte address for each nRF24L01
'The indeces (IDX) below need to be changed if using 3 or 5 byte address
'and the array will need re-mapping
'
' 2 1 4 1 4 1 1 1 32
'1 2 34567 89012 3 4 5 6789012345 6789012345 6789012345 67 8
'T R TAd RAd PW IrCm|-------- Payload ----------------|
Const Payload_idx = 32 + 16
Const T_idx = 1
Const Tadr_idx = 3
Const Radr_idx = 8
Const Pw_idx = 13
Const Irq_idx = 14
Const Pl_cmd_idx = 15
Const Pl_idx = 16
Dim Payload(payload_idx) As Byte 'Main RAM space where Vars and Payload are OVERLAYED
Dim Tb As Byte At Payload(t_idx) Overlay , Rb As Byte At Payload(t_idx) + 1 Overlay
Dim Tx_addr_lsb As Byte At Payload(tadr_idx) + 1 Overlay , P0_addr_lsb As Byte At Payload(radr_idx) + 1 Overlay
Dim Pw As Byte At Payload(pw_idx) Overlay , Irq_stat As Byte At Payload(irq_idx) Overlay
Dim Reg_name As String * 12 , Reg_addr As Byte
Tb = Tadr_idx
Payload(tb + 4) = &H12
Payload(tb + 3) = &H34
Payload(tb + 2) = &H00
Payload(tadr_idx) = Write_reg + Tx_addr
Rb = Radr_idx
Payload(rb + 4) = &H12
Payload(rb + 3) = &H34
Payload(rb + 2) = &H00
Payload(radr_idx ) = Write_reg + Rx_addr_p0
'============================================
'Scratchpad
'============================================
Dim I As Byte , J As Byte , K As Byte , W As Word
'==========================================
'MCS Bootloader Interface
'==========================================
Const Nak = &H15
Const Ack = &H06
Const Can = &H18
Const Eeprom_transfer = $3ff
Dim Bstatus As Byte , Bblock As Byte , Bblocklocal As Byte
Dim Bcsum1 As Byte , Bcsum2 As Byte , Buf(128) As Byte , Csum As Byte
Dim Bkind As Byte , Bstarted As Byte , Nrfdevid As Byte
Dim I1 As Byte
Dim Ss As String * 20
'=========================================
'LCD Interface
'=========================================
Config Lcdpin = Pin , Rs = Portb.1 , E = Portb.2 , Db4 = Portd.4 , Db5 = Portd.5 , Db6 = Portd.6 , Db7 = Portd.7
Config Lcd = 16 * 2
Cls
Cursor Off
'============================================
'Config Interrupts
'============================================
Config Int0 = Falling
On Int0 Do0
Enable Int0
Portd.2 = 1
Config Int1 = Falling
On Int1 Do1
Enable Int1
Portd.3 = 1
Dim Pbs As Byte
'============================================
'Base
'============================================
Dim Page As Word , Kk As Byte
Dim Blockidx As Byte , Spmsize As Byte
Dim Mv(32) As Byte At Payload(pl_idx) Overlay
'============================================
'Initialize components
'============================================
Lcd "Base 328"
Spmsize = 32
Call Nrf24l01init()
'============================================
' Main
'============================================
$timeout = 800000
Enable Interrupts
Readeeprom Nrfdevid , Eeprom_transfer
I = Nrfdevid 'Changed by PushButtons 'Default
I = 15 'Forced in this DEMO
Kk = 0
Do
Pbs = 0
Waitms 200
Select Case Pbs
Case 1
If I > 1 Then Decr I
Kk = 0
Case 2
If I < 50 Then Incr I
Kk = 0
End Select
Locate 2 , 1 : Lcd "DevID " ; I ; " "
Incr Kk
Loop Until Pbs = 3 Or Kk = 30
If Nrfdevid <> I Then
Writeeeprom I , Eeprom_transfer
Nrfdevid = I
End If
Do 'complete program loop
Locate 1 , 1 : Lcd "DevID " ; Nrfdevid ; " "
Locate 2 , 1 : Lcd "WaitPC? "
Do
Bkind = Waitkey() 'wait for the loader to send a byte
If Pbs = 1 Then Goto _reset
If Pbs = 3 Then Goto $3c00
Loop Until Bkind = 123 Or Bkind = 124 'Flash Or Eeprom
Print Chr(bkind);
If Bkind = 123 Then Ss = "Flash " Else Ss = "EEPROM "
Locate 1 , 1 : Lcd Ss
Do
Bstatus = Waitkey()
Loop Until Bstatus = 0
Locate 2 , 1 : Lcd "Wait " ; Nrfdevid ; " "
Page = 0
Disable Interrupts
If Nrfdevid <> 15 Then 'prepare and reset remote mrf
Mv(1) = 15
Do
Kk = Transmit(nrfdevid , 2)
Loop Until Kk = 1
'=================================================================================================
Wait 2 'this allows running main program to exit and start bootloader
End If
Config Watchdog = 8192
Start Watchdog
Mv(1) = Bkind : Kk = Transmit(nrfdevid , 2)
Reset Watchdog
Bitwait Nrfint , Reset
Kk = Receive()
Stop Watchdog
Blockidx = Mv(1)
If Blockidx <> Bkind Then
Locate 2 , 1 : Lcd "nRFTxErr"
Wait 8
Goto _reset
End If
Locate 1 , 1 : Lcd "Send " ; Nrfdevid ; " "
Do
Bstarted = 0 'not started yet
Csum = 0 'checksum is 0 when we start
Print Chr(nak); 'first time send a nack
Do
Bstatus = Waitkey() 'wait for status byte
Select Case Bstatus
Case 0 :
Bkind = 255 : Exit Do 'normal exit
Case 1: 'start of heading, PC is ready to send
Incr Bblocklocal 'increase local block count
Csum = 1 'checksum is 1
Bblock = Waitkey() : Csum = Csum + Bblock 'get block
Bcsum1 = Waitkey() : Csum = Csum + Bcsum1 'get checksum first byte
For J = 1 To 128 'get 128 bytes
Buf(j) = Waitkey() : Csum = Csum + Buf(j)
Next
Bcsum2 = Waitkey() 'get second checksum byte
If Bblocklocal = Bblock Then 'are the blocks the same?
If Bcsum2 = Csum Then 'is the checksum the same?
For J = 0 To 3 'yes send data
K = Spmsize * J : For I1 = 1 To Spmsize : I = K + I1 : Mv(i1) = Buf(i) : Next
Kk = Transmit(nrfdevid , 33)
Next J
Mv(1) = 1 : Kk = Transmit(nrfdevid , 2)
Incr Page : W = Page / 2
Locate 2 , 1 : Lcd "Page " ; W ; " "
Print Chr(ack); 'acknowledge
Else 'no match so send nak
Print Chr(nak);
End If
Else
Print Chr(nak); 'blocks do not match
End If
Case 4:
Mv(1) = 255 : Kk = Transmit(nrfdevid , 2) 'end of transmission , file is transmitted
Print Chr(ack); 'send ack and ready
Bkind = 255
Case &H18: 'PC aborts transmission
Locate 2 , 1 : Lcd "PC ABORT"
Wait 8
Goto _reset 'Exit Do no valid data
Case Else
Locate 2 , 1 : Lcd "Unknown?"
Wait 8
Goto _reset 'Exit Do no valid data
End Select
Loop
Loop Until Bkind = 255
Locate 1 , 1 : Lcd "Complete"
Locate 2 , 1 : Lcd "DevID " ; Nrfdevid
Wait 8
Goto _reset
Loop
End
'=========================================
'Subroutines
'=========================================
Sub Nrf24l01init()
Nrfce = 0
Restore Nrf_registers_init
Do
Read Reg_name : Read Reg_addr : Read Rb
If Reg_addr = 255 Then Exit Do
Tb = Write_reg + Reg_addr
Call W_register(t_idx , 2)
Loop
P0_addr_lsb = Dev_id : Call W_register(radr_idx , 5) 'Put this device 4-byte address in Pipe 0 for RX
Tb = Flush_tx : Call W_register(t_idx , 1) 'Flush TX_fifo buffer
Tb = Flush_rx : Call W_register(t_idx , 1) 'Flush RX_fifo buffer
Nrfce = 1
End Sub
Function Transmit(byval Tx As Byte , Byval Pl_w As Byte) As Byte
Nrfce = 0 'set CE LO to set up registers
Tb = Write_reg + Config_nrf : Rb = V_set_tx 'Set to TX
Call W_register(t_idx , 2)
Tb = Flush_tx 'Flush the TX_fifo buffer
Call W_register(t_idx , 1)
Tb = Write_reg + Status : Rb = V_irq_reset 'Reset the IRQ bits
Call W_register(t_idx , 2)
Tx_addr_lsb = Tx : Call W_register(tadr_idx , 5) 'LSB of Target Put 4-bytes TARGET address in TX
P0_addr_lsb = Tx : Call W_register(radr_idx , 5) 'LSB of Target Put same 4-byte address in Pipe 0 for ACK
Payload(pl_cmd_idx) = Wr_tx_pload 'Put bytes in the TX pload buffer
Call W_register(pl_cmd_idx , Pl_w)
Nrfce = 1 : Waitus 100 : Nrfce = 0 : W = 0 'Set CE for a short time to transmit the fifo buffer
Bitwait Nrfint , Reset
Call R_register(status , Irq_idx , 1) 'save TX status bit overlayed into IRQ_Stat
Tb = Write_reg + Status : Rb = V_irq_reset 'Reset the IRQ bits
Call W_register(t_idx , 2)
P0_addr_lsb = Dev_id 'LSB of this device
Call W_register(radr_idx , 5) 'Put this device 4-byte address BACK in Pipe 0 for RX
Tb = Write_reg + Config_nrf : Rb = V_set_rx 'Set to RX
Call W_register(t_idx , 2)
Nrfce = 1 'set to RX
Waitms Nrfwait
Transmit = Irq_stat.5
End Function 'set CE HIGH to turn on Device Receive
Function Receive() As Byte
Call R_register(r_rx_pl_wid , Pw_idx , 1)
Call R_register(status , Irq_idx , 1) 'save Receive interrupt overlayed into IRQ_Stat
If Pw <= 32 And Pw > 0 And Irq_stat.6 = 1 Then Call R_register(rd_rx_pload , Pl_idx , Pw) Else Irq_stat = 0 'Read bytes RX to buffer overlayed in MV array
Nrfce = 0 'set CE Low to read registers
Tb = Flush_rx 'Flush the rX_fifo buffer
Call W_register(t_idx , 1)
Tb = Write_reg + Status : Rb = V_irq_reset 'Reset interrupts
Call W_register(t_idx , 2)
Nrfce = 1 'set CE HIGH for Receive
Receive = Irq_stat.6
End Function
Sub W_register(byval Start_b As Byte , Byval Num_b As Byte)
Reset Nrfcs
Spiout Payload(start_b) , Num_b
Set Nrfcs
End Sub
Sub R_register(byval Command As Byte , Byval Start_b As Byte , Byval Num_b As Byte)
Reset Nrfcs
Spiout Command , 1
Spiin payload(start_b) , Num_b
Set Nrfcs
End Sub
'=============================
'nRF24L01+ Register addresses
'=============================
'Registers:
'Data "CONFIG_nRF " , &H00 , 1
'Data "EN_AA " , &H01 , 1
'Data "EN_RXADDR " , &H02 , 1
'Data "SETUP_AW " , &H03 , 1
'Data "SETUP_RETR " , &H04 , 1
'Data "RF_CH " , &H05 , 1
'Data "RF_SETUP " , &H06 , 1
'Data "STATUS " , &H07 , 1
'Data "OBSERVE_TX " , &H08 , 1
'Data "RcdPowerD " , &H09 , 1
'Data "RX_ADDR_P0 " , &H0A , 4
'Data "RX_ADDR_P1 " , &H0B , 4
'Data "RX_ADDR_P2 " , &H0C , 1
'Data "RX_ADDR_P3 " , &H0D , 1
'Data "RX_ADDR_P4 " , &H0E , 1
'Data "RX_ADDR_P5 " , &H0F , 1
'Data "TX_ADDR " , &H10 , 4
'Data "RX_PW_P0 " , &H11 , 1
'Data "RX_PW_P1 " , &H12 , 1
'Data "RX_PW_P2 " , &H13 , 1
'Data "RX_PW_P3 " , &H14 , 1
'Data "RX_PW_P4 " , &H15 , 1
'Data "RX_PW_P5 " , &H16 , 1
'Data "FIFO_STAT " , &H17 , 1
'Data "DYN_PD " , &H1C , 1
'Data "Features " , &H1D , 1
'Data "End " , &HFF , 0
Nrf_registers_init:
Data "CONFIG_nRF " , &H00 , &B00001011 'PRX=1(RX_device), PWR_UP=1, CRC 2bytes, Enable CRC
'&B00001111
' ^ Module function as 0=TX, 1=RX
' ^ 0=Power Down, 1=Up
' ^ CRC type 0=1 byte, 1=2 byte
' ^ Enable CRC
' x^^^ Three sources of interrupts 0=enabled
Data "EN_AA " , &H01 , &B00000001 'Enable auto ACK for pipe0
Data "EN_RXADDR " , &H02 , &B00111111 'Enable RX address for pipe0
Data "SETUP_AW " , &H03 , &B00000010 'number of address bytes
'&B00000010
' ^^ 01=3, 10=4, 11=5
Data "SETUP_RETR " , &H04 , &B11111111 'TX Retry wait; Num Retries
'&B00110011
' ^^ Num retries=3
' ^^ TX retry wait=1000 uS
Data "RF_CH " , &H05 , 27 'Set RF channel; range is 0-125
'2.400 - 2.525 GHz in 1 MHz increments
'FIND A FREQUENCY WITH THE LEAST INTERFERENCE
Data "RF_SETUP " , &H06 , &B00100111 'Output power 0dbm, datarate 2Mbps and LNA gain on
'&B00000000
' ^ LNA Gain on=1
' ^^ Power in TX 00=-18 dBm, -> 11=0 dBm
' ^ ^ Speed 00=1 MBPS, 01=2 MBPS, 10=250KBPS
Data "STATUS " , &H07 , &B01110000 'Reset IRQ vector
Data "DYN_Payld " , &H1C , &B00000001 'Dynamic payload pipe 0 &B00000001
Data "Features " , &H1D , &B00000100 'Enable Dynamic Payload length &B00000100
Data "End " , &HFF , 0
'=========================================
'PushButton Interrupts
'=========================================
Do0:
Pbs.0 = 1
Return
Do1:
Pbs.1 = 1
Return
[/code:1:36deabc27d]
And ...........
[code:1:36deabc27d]
'=====BL.Remote.M644P.nRF24L01.UART.1.bas====================================
'Bootloader Remote 644p
'Nov 15, 2013
'Revised:
'
'Thanks to Evert Dekker for the inspiration and BASCOM AN#151
'=============================================
$regfile = "m644pdef.dat"
$crystal = 8000000
$baud = 38400
$hwstack = 80 ' default use 32 for the hardware stack
$swstack = 64 ' default use 10 for the SW stack
$framesize = 64 ' default use 40 for the frame space
$version 1 , 0 , 2
'==========================================
'Bootloader Config
'==========================================
Disable Interrupts 'we do not use ints
$loader = $7800
Const Bootloader_start = $7800
' Bootloader Hex $LOADERSIZE
' 8000 none 10000
' 7E00 FC00 $400
' 7C00 F800 $800
' 7800 F000 $1000
' 7000 E000 $2000
Const Maxwordbit = 7 'Z7 is maximum bit '
Const Maxword =(2 ^ Maxwordbit) * 2 '128
Const Maxwordshift = Maxwordbit + 1
'==========================================
'AtMega SPI Config
'==========================================
Config Portb.4 = Output
Set Portb.4
Config Spi = Hard , Interrupt = Off , Data Order = Msb , Master = Yes , Polarity = Low , Phase = 0 , Clockrate = 4 , Noss = 1
Spiinit
'============================================
'nRF24L01+ Nordic Semiconductor
'============================================
Const Dev_id = 15 'Address LSB of this TARGET device
Nrfce Alias Portb.3
Config Nrfce = Output
Nrfce = 1
Nrfcs Alias Portb.0
Config Nrfcs = Output
Nrfcs = 1
Nrfint Alias Pinb.1
Config Nrfint = Input
Declare Sub R_register(byval Command As Byte , Byval Start_b As Byte , Byval Num_b As Byte)
Declare Sub W_register(byval Start_b As Byte , Byval Num_b As Byte)
Declare Sub Nrf24l01init()
Declare Function Transmit(byval Tx As Byte , Byval Pl_w As Byte) As Byte
Declare Function Receive() As Byte
'SPI(nRF24L01) commands
Const Write_reg = &H20
Const Rd_rx_pload = &H61
Const Wr_tx_pload = &HA0
Const Flush_tx = &HE1
Const Flush_rx = &HE2
'Registers
Const Config_nrf = &H00
Const Status = &H07
Const Fifo_stat = &H17
Const Tx_addr = &H10
Const Rx_addr_p0 = &H0A
Const R_rx_pl_wid = &B01100000
'VALUES
Const Nrfwait = 5 'Not Optimized
'CAUTION:
'The nRF24L01 module has a 3-level Receive FIFO
'and a 3-level Transmit FIFO. If TX is too fast, the data
'may go into a level other than the first and this Bootloader
'will not work.
Const V_irq_reset = &B01110000
Const V_set_tx = &B00001010
Const V_set_rx = &B00001011 'PRX=1(RX_device), PWR_UP=1, CRC 2bytes, Enable CRC
'&B00001111
' ^ Module function as 0=TX, 1=RX
' ^ 0=Power Down, 1=Up
' ^ CRC type 0=1 byte, 1=2 byte
' ^ Enable CRC
' x^^^ Three sources of interrupts 0=enabled
'====================================================
'RAM dBase Array
'====================================================
'This RAM array assumes a 4-byte address for each nRF24L01
'The indeces (IDX) below need to be changed if using 3 or 5 byte address
'and the array will need re-mapping
'
' 2 1 4 1 4 1 1 1 32
'1 2 34567 89012 3 4 5 6789012345 6789012345 6789012345 67 8
'T R TAd RAd PW IrCm|-------- Payload ----------------|
Const Payload_idx = 32 + 16
Const T_idx = 1
Const Tadr_idx = 3
Const Radr_idx = 8
Const Pw_idx = 13
Const Irq_idx = 14
Const Pl_cmd_idx = 15
Const Pl_idx = 16
Dim Payload(payload_idx) As Byte 'Main RAM space where Vars and Payload are OVERLAYED
Dim Tb As Byte At Payload(t_idx) Overlay , Rb As Byte At Payload(t_idx) + 1 Overlay
Dim Tx_addr_lsb As Byte At Payload(tadr_idx) + 1 Overlay , P0_addr_lsb As Byte At Payload(radr_idx) + 1 Overlay
Dim Pw As Byte At Payload(pw_idx) Overlay , Irq_stat As Byte At Payload(irq_idx) Overlay
Dim Reg_name As String * 12 , Reg_addr As Byte , Reg_vals As Byte
Tb = Tadr_idx
Payload(tb + 4) = &H12 ')
Payload(tb + 3) = &H34 ') Same MSB bytes
Payload(tb + 2) = &H00 ')
Payload(tadr_idx) = Write_reg + Tx_addr
Rb = Radr_idx
Payload(rb + 4) = &H12 ')
Payload(rb + 3) = &H34 ') Same MSB bytes
Payload(rb + 2) = &H00 ')
Payload(radr_idx ) = Write_reg + Rx_addr_p0
'============================================
'Scratchpad
'============================================
Dim I As Byte , J As Byte , K As Byte , Jj As Byte , W As Word , Kk As Byte
'============================================
'User defined
'============================================
Dim Mv(32) As Byte At Payload(pl_idx) Overlay
Dim Blockidx As Byte , Spmsize As Byte , Buf(128) As Byte
Dim Z As Long 'this is the Z pointer word
Dim Vl As Byte , Vh As Byte ' these bytes are used for the data values
Dim Wrd As Word , Page As Word 'these vars contain the page and word address
Dim Bkind As Byte , Spmcrval As Byte
'============================================
'Initialize components
'============================================
Call Nrf24l01init()
'============================================
' Main
'============================================
Spmsize = 32
Print : Print : Print "BL M644p Addr LSB:15 Ver:" ; Version(2)
Print "BL Start-" ;
I = 9
Do
J = 250
Print I;
Do
Decr J
Waitms 4
Loop Until Nrfint = 0 Or J = 0
If Nrfint = 0 Then
Kk = Receive()
Blockidx = Mv(1)
End If
If I = 0 Then Goto _reset 'goto the normal reset vector at address 0
Decr I
Loop Until Blockidx = 123 Or Blockidx = 124
Waitms Nrfwait
Bkind = Mv(1) : Kk = Transmit(1 , 2) 'send back mv(1) = 123 or 124
Page = 0 : Wrd = 0
Print : Print "Page:" ; Page ; ".";
Do
For I = 0 To 3
Bitwait Nrfint , Reset
Kk = Receive()
If I = 0 And Mv(1) = 255 Then
Blockidx = 255 : Exit Do
End If
J = Spmsize * I : For Jj = 1 To Spmsize : K = J + Jj : Buf(k) = Mv(jj) : Next
Next
Bitwait Nrfint , Reset
Kk = Receive() : Blockidx = Mv(1)
If Blockidx = 1 Then Gosub Writepage
If Blockidx = 255 Then Exit Do
Loop
Print : Print "Exit"
If Bkind = 123 Then
If Blockidx = 255 Or Wrd > 0 Then 'if there was something left in the page
Wrd = 0 'Z pointer needs wrd to be 0
Spmcrval = 5 : Gosub Do_spm 'write page
Spmcrval = 17 : Gosub Do_spm ' re-enable page
End If
End If
Goto _reset
End
'=============================================
'nRF24L01+ Subroutines
'=============================================
Sub Nrf24l01init()
Nrfce = 0 'Low to Write
Restore Nrf_registers_init
Do
Read Reg_name : Read Reg_addr : Read Rb
If Reg_addr = 255 Then Exit Do
Tb = Write_reg + Reg_addr : Call W_register(t_idx , 2)
Loop
P0_addr_lsb = Dev_id : Call W_register(radr_idx , 5) 'Put this device 4-byte address in Pipe 0 for RX
Tb = Flush_tx : Call W_register(t_idx , 1) 'Flush TX_fifo buffer
Tb = Flush_rx : Call W_register(t_idx , 1) 'Flush RX_fifo buffer
Nrfce = 1
End Sub
Function Transmit(byval Tx As Byte , Byval Pl_w As Byte) As Byte
Nrfce = 0 'set CE LO to write registers
Tb = Write_reg + Config_nrf : Rb = V_set_tx 'Set to TX
Call W_register(t_idx , 2)
Tb = Flush_tx : Call W_register(t_idx , 1) 'Flush the TX_fifo buffer
Tb = Write_reg + Status : Rb = V_irq_reset 'Reset the IRQ bits
Call W_register(t_idx , 2)
Tx_addr_lsb = Tx : Call W_register(tadr_idx , 5) 'LSB of Target Put 4-bytes TARGET address in TX
P0_addr_lsb = Tx : Call W_register(radr_idx , 5) 'LSB of Target Put same 4-byte address in Pipe 0 for ACK
Payload(pl_cmd_idx) = Wr_tx_pload 'Put bytes in the TX pload buffer
Call W_register(Pl_cmd_idx , Pl_w)
Nrfce = 1 : Waitus 200 : Nrfce = 0 : W = 0 'Set CE for a short moment to transmit the fifo buffer
Bitwait Nrfint , Reset
Call R_register(status , Irq_idx , 1) 'save TX status bit overlayed into IRQ_Stat
Tb = Write_reg + Status : Rb = V_irq_reset 'Reset the IRQ bits
Call W_register(t_idx , 2)
P0_addr_lsb = Dev_id : Call W_register(radr_idx , 5) 'LSB of this device Put this device 4-byte address BACK in RX Pipe 0
Tb = Write_reg + Config_nrf : Rb = V_set_rx 'Set to RX
Call W_register(t_idx , 2)
Nrfce = 1
Transmit = Irq_stat.5
End Function 'set CE HIGH to turn on Device Receive
Function Receive() As Byte
Call R_register(r_rx_pl_wid , Pw_idx , 1)
Call R_register(status , Irq_idx , 1) 'save Receive interrupt overlayed into IRQ_Stat
If Pw <= 32 And Pw > 0 And Irq_stat.6 = 1 Then Call R_register(rd_rx_pload , Pl_idx , Pw) Else Irq_stat = 0 'Read bytes RX to buffer overlayed in MV array
Nrfce = 0 'set CE Low to read registers
Tb = Flush_rx : Call W_register(t_idx , 1) 'Flush the rX_fifo buffer
Tb = Write_reg + Status : Rb = V_irq_reset 'Reset interrupts
Call W_register(t_idx , 2)
Nrfce = 1 'set CE HIGH for Receive
Receive = Irq_stat.6
End Function
Sub W_register(byval Start_b As Byte , Byval Num_b As Byte)
Reset Nrfcs
Spiout Payload(start_b) , Num_b
Set Nrfcs
End Sub
Sub R_register(byval Command As Byte , Byval Start_b As Byte , Byval Num_b As Byte)
Reset Nrfcs
Spiout Command , 1
Spiin payload(start_b) , Num_b
Set Nrfcs
End Sub
'=============================
'nRF24L01+ Register addresses
'=============================
'Registers:
'Data "CONFIG_nRF " , &H00 , 1
'Data "EN_AA " , &H01 , 1
'Data "EN_RXADDR " , &H02 , 1
'Data "SETUP_AW " , &H03 , 1
'Data "SETUP_RETR " , &H04 , 1
'Data "RF_CH " , &H05 , 1
'Data "RF_SETUP " , &H06 , 1
'Data "STATUS " , &H07 , 1
'Data "OBSERVE_TX " , &H08 , 1
'Data "RcdPowerD " , &H09 , 1
'Data "RX_ADDR_P0 " , &H0A , 4
'Data "RX_ADDR_P1 " , &H0B , 4
'Data "RX_ADDR_P2 " , &H0C , 1
'Data "RX_ADDR_P3 " , &H0D , 1
'Data "RX_ADDR_P4 " , &H0E , 1
'Data "RX_ADDR_P5 " , &H0F , 1
'Data "TX_ADDR " , &H10 , 4
'Data "RX_PW_P0 " , &H11 , 1
'Data "RX_PW_P1 " , &H12 , 1
'Data "RX_PW_P2 " , &H13 , 1
'Data "RX_PW_P3 " , &H14 , 1
'Data "RX_PW_P4 " , &H15 , 1
'Data "RX_PW_P5 " , &H16 , 1
'Data "FIFO_STAT " , &H17 , 1
'Data "DYN_PD " , &H1C , 1
'Data "Features " , &H1D , 1
'Data "End " , &HFF , 0
Nrf_registers_init:
Data "CONFIG_nRF " , &H00 , &B00001011 'PRX=1(RX_device), PWR_UP=1, CRC 2bytes, Enable CRC
'&B00001111
' ^ Module function as 0=TX, 1=RX
' ^ 0=Power Down, 1=Up
' ^ CRC type 0=1 byte, 1=2 byte
' ^ Enable CRC
' x^^^ Three sources of interrupts 0=enabled
Data "EN_AA " , &H01 , &B00000001 'Enable auto ACK for pipe0
Data "EN_RXADDR " , &H02 , &B00111111 'Enable RX address for pipe0
Data "SETUP_AW " , &H03 , &B00000010 'number of address bytes
'&B00000010
' ^^ 01=3, 10=4, 11=5
Data "SETUP_RETR " , &H04 , &B11111111 'TX Retry wait; Num Retries
'&B00110011
' ^^ Num retries=3
' ^^ TX retry wait=1000 uS
Data "RF_CH " , &H05 , 27 'Set RF channel; range is 0-125
'2.400 - 2.525 GHz in 1 MHz increments
'FIND A FREQUENCY WITH THE LEAST INTERFERENCE
Data "RF_SETUP " , &H06 , &B00100111 'Output power 0dbm, datarate 2Mbps and LNA gain on
'&B00000000
' ^ LNA Gain on=1
' ^^ Power in TX 00=-18 dBm, -> 11=0 dBm
' ^ ^ Speed 00=1 MBPS, 01=2 MBPS, 10=250KBPS
' 76543210
Data "STATUS " , &H07 , &B01110000 'Reset IRQ vector
Data "DYN_Payld " , &H1C , &B00000001 'Dynamic payload pipe 0 &B00000001
Data "Features " , &H1D , &B00000100 'Enable Dynamic Payload length &B00000100
Data "End " , &HFF , 0
Writepage:
If Bkind = 123 Then
If Wrd = 0 Then
Spmcrval = 3 : Gosub Do_spm ' erase the first page
Spmcrval = 17 : Gosub Do_spm ' re-enable page
End If
For J = 1 To 128 Step 2 'we write 2 bytes into a page
Vl = Buf(j) : Vh = Buf(j + 1) 'get Low and High bytes
lds r0, {vl} 'store them into r0 and r1 registers
lds r1, {vh}
Spmcrval = 1 : Gosub Do_spm 'write value into page at word address
Wrd = Wrd + 2 ' word address increases with 2 because LS bit of Z is not used
If Wrd = Maxword Then ' page is full
Wrd = 0 'Z pointer needs wrd to be 0
Spmcrval = 5 : Gosub Do_spm 'write page
Spmcrval = 17 : Gosub Do_spm ' re-enable page
Page = Page + 1 : Print Page ; "."; 'next page
End If
Next
Else 'eeprom
For J = 1 To 128
Writeeeprom Buf(j) , Wrd
Wrd = Wrd + 1
Next
End If
Return
Do_spm:
Bitwait Spmcsr.0 , Reset ' check for previous SPM complete
Bitwait Eecr.1 , Reset 'wait for eeprom
Z = Page 'make equal to page
Shift Z , Left , Maxwordshift 'shift to proper place
Z = Z + Wrd 'add word
lds r30,{Z}
lds r31,{Z+1}
#if _romsize > 65536
lds r24,{Z+2}
sts rampz,r24 ' we need to set rampz also for the M128
#endif
Spmcsr = Spmcrval 'assign register
spm 'this is an asm instruction
nop
nop
Return[/code:1:36deabc27d][code:1:36deabc27d][/code:1:36deabc27d]
↧