Skip to content

Instantly share code, notes, and snippets.

@ataffanel ataffanel/bootloader_512_7800.bin Secret
Last active Jan 14, 2018

Embed
What would you like to do?
Program nRF24LU1 bootloader using Raspberrypi GPIO as SPI programmer
#!/usr/bin/env python3
# Write a bootloader from page 60 (address 0x7800) and write the jump
# instruction page 0
# This script should work on any Raspberry pi running a recent version of
# rasbian. After the Crazyradio is connected to the raspberry pi expansion
# port just run the script with
# "python3 write_bootloader_raspi.py <bootloader.bin>"
# Script setup. Use this as a documentation to cable the Crazyradio or modify
# if you want to cable it differently.
# Name Pin on raspi Pin on Crazyradio
#-------------------------------------------
GND = 6 # 9
RESET = 3 # 3
PROG = 5 # 2
SCK = 7 # 4
MOSI = 8 # 6
MISO = 10 # 8
CS = 12 # 10
import RPi.GPIO as GPIO
import time
import sys
CS_ENABLE = GPIO.LOW
CS_DISABLE = GPIO.HIGH
# SPI commands
WREN = 0x06
WRDIS = 0x04
ERASE_PAGE = 0x52
PROGRAM = 0x02
READ = 0x03
def init_gpios():
GPIO.setmode(GPIO.BOARD)
GPIO.setup(RESET, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(PROG, GPIO.OUT, initial=GPIO.HIGH)
def check_connection():
# If reset is connected, it will be pulled up
return GPIO.input(RESET) != 0
def reset_in_prog():
GPIO.output(RESET, GPIO.LOW)
GPIO.output(PROG, GPIO.HIGH)
time.sleep(0.1)
GPIO.output(RESET, GPIO.HIGH)
time.sleep(0.1)
def reset_in_fw():
GPIO.output(RESET, GPIO.LOW)
GPIO.output(PROG, GPIO.LOW)
time.sleep(0.1)
GPIO.output(RESET, GPIO.HIGH)
time.sleep(0.1)
def spi_oe(enable):
if enable:
GPIO.setup([SCK, MOSI], GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(CS, GPIO.OUT, initial=CS_DISABLE)
GPIO.setup(MISO, GPIO.IN)
else:
GPIO.setup([SCK, MOSI, CS], GPIO.IN)
def set_cs(value):
GPIO.output(CS, value)
time.sleep(0.1)
def spi_transfer(dataout):
datain = 0
GPIO.output(SCK, GPIO.LOW)
for i in range(8):
b = GPIO.LOW
if dataout & 0x0080 != 0:
b = GPIO.HIGH
GPIO.output(MOSI, b)
dataout = dataout << 1
time.sleep(0.001)
b = GPIO.input(MISO)
GPIO.output(SCK, GPIO.HIGH)
datain = datain << 1
if b != GPIO.LOW:
datain = datain | 0x01
time.sleep(0.001)
GPIO.output(SCK, GPIO.LOW)
return datain
def erase_page(page_number):
assert(page_number >= 0 and page_number < 64)
set_cs(CS_ENABLE)
spi_transfer(WREN)
set_cs(CS_DISABLE)
set_cs(CS_ENABLE)
spi_transfer(ERASE_PAGE)
spi_transfer(page_number)
set_cs(CS_DISABLE)
time.sleep(0.1)
def program_page(page_number, data):
assert(page_number >= 0 and page_number < 64)
assert(len(data) <= 512)
start_address = page_number * 512
# Write page 256 bytes at a time
for address in range(start_address, start_address + len(data), 256):
set_cs(CS_ENABLE)
spi_transfer(WREN)
set_cs(CS_DISABLE)
set_cs(CS_ENABLE)
spi_transfer(PROGRAM)
# Address
spi_transfer(address >> 8)
spi_transfer(address &0x0FF)
# Write data
for _ in range(min(len(data),256)):
spi_transfer(data[0])
data = data[1:]
set_cs(CS_DISABLE)
# Wait for data to be written
time.sleep(1)
def verify_page(page_number, data):
assert(page_number >= 0 and page_number < 64)
assert(len(data) <= 512)
verification_ok = True
start_address = page_number * 512
set_cs(CS_ENABLE)
spi_transfer(READ)
spi_transfer(start_address >> 8)
spi_transfer(start_address & 0x0FF)
for d in data:
verification_ok &= spi_transfer(0x00) == d
set_cs(CS_DISABLE)
return verification_ok
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: {} <bootloader_bin_file.bin>".format(sys.argv[0]))
sys.exit(1)
with open(sys.argv[1], 'rb') as fd:
bootloader = fd.read()
n_pages = int((len(bootloader)-1) / 512) + 1
init_gpios()
reset_in_prog()
spi_oe(True)
print("Erasing page 0...")
erase_page(0)
print("Writing 'JL 0x7800' instruction on page 0...")
program_page(0, [0x02, 0x78, 0x00])
for page in range(60, 60 + n_pages):
file_page = page - 60
print("Erasing page {}...".format(page))
erase_page(page)
print("Writing bootloader on page {} ...".format(page))
program_page(page, bootloader[file_page*512:(file_page+1)*512])
print("Verifying page 0...")
if verify_page(0, [0x02, 0x78, 0x00]):
print("OK!")
else:
print("Failed!")
for page in range(60, 60 + n_pages):
file_page = page - 60
print("Verifying page {}...".format(page))
if verify_page(page, bootloader[file_page*512:(file_page+1)*512]):
print("OK!")
else:
print("Failed!")
spi_oe(False)
reset_in_fw()
GPIO.cleanup()
print("Bootloader programmed. Disconnect the PROG wire, reconnect Crazyradio")
print("and the bootloader should start!")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.