Skip to content
Permalink
Browse files

boards: intel_s1000_crb: Image download scripts

Python scripts to download a zephyr binary image (zephyr.bin) to
Intel S1000 from a linux host.
The linux host's SPI master and GPIOs shall be connected to the
corresponding SPI slave and I/Os respectively.

Signed-off-by: Sathish Kuttan <sathish.k.kuttan@intel.com>
  • Loading branch information...
sathishkuttan authored and nashif committed May 21, 2019
1 parent d714f64 commit 8075de7b94162e91ca584a1511a2937c84937329
@@ -0,0 +1,124 @@
#!/usr/bin/env python3
#
# Copyright (c) 2019 Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0
#
# Author: Sathish Kuttan <sathish.k.kuttan@intel.com>

# This file defines device class that contains functions to
# setup/cconfigure SPI master device and GPIO pins required
# to communicate with the target.
# Member functions are provided to send and receive messages
# over the SPI bus

import yaml
import time
import periphery
import sys
import os

class Device:
"""
Device class containing the interface methods for communicating
with the target using SPI bus and GPIOs
"""
def __init__(self):
"""
Read config file and determine the SPI device, speed, mode
GPIO pin assignments, etc.
Initialize data structures accordingly.
"""
config_file = os.path.dirname(__file__)
config_file += '/config.yml'
with open(config_file, 'r') as ymlfile:
config = yaml.safe_load(ymlfile)
self.name = config['general']['name']
self.spi_device = config['spi']['device']
self.spi_speed = config['spi']['max_speed']
self.spi_mode = None
self.gpio_reset = config['gpio']['reset']
self.gpio_wake = config['gpio']['wake']
self.gpio_irq = config['gpio']['irq']
self.spi = None
self.reset_pin = None
self.wake_pin = None
self.irq_pin = None

def print_config(self):
"""
Print configuration information that was read from config file
"""
print('%s Device on %s' %(self.name, self.spi_device))
print('Max SPI Frequency: %2.1f MHz' % self.spi_speed)
print('Reset GPIO: %d' % self.gpio_reset)
print('Wake GPIO : %d' % self.gpio_wake)
print('IRQ GPIO : %d' % self.gpio_irq)

def configure_device(self, spi_mode, order, bits):
"""
Configure the SPI device and GPIOs for communication with target
"""
self.reset_pin = periphery.GPIO(self.gpio_reset, 'out')
self.wake_pin = periphery.GPIO(self.gpio_wake, 'out')
self.irq_pin = periphery.GPIO(self.gpio_irq, 'in')
self.spi = periphery.SPI(self.spi_device, spi_mode,
self.spi_speed * 1e6)
self.spi.bit_order = order
self.spi.bits_per_word = bits
print('Configured SPI %s for %s.' % (self.spi_device, self.name))
print('Configured GPIO %d for %s Reset.' % (self.gpio_reset, self.name))
print('Configured GPIO %d for %s Wake.' % (self.gpio_wake, self.name))
print('Configured GPIO %d for %s IRQ.' % (self.gpio_irq, self.name))

def check_device_ready(self):
"""
Check whether the target is ready to accept a command as follows:
Wait a minimum time and check whether IRQ is asserted by the target
If IRQ is not asserted, wait maximum time and check again.
Device is ready if IRQ is asserted
"""
min_wait = 0.001 # 1 ms
max_wait = 0.1 # 100 ms
time.sleep(min_wait)
ready = self.irq_pin.read()
if ready == False:
time.sleep(max_wait)
ready = self.irq_pin.read()
if ready == False:
print('Error: Device not ready', file=sys.stderr)
return ready

def reset_device(self):
"""
Assert the GPIO and deassert after a short duration to reset
the target.
"""
print('Resetting %s ...' % self.name)
self.reset_pin.write(False)
time.sleep(0.1)
self.reset_pin.write(True)
self.check_device_ready()

def send_receive(self, data, wait = True):
"""
Transmit and receive full duplex data over SPI
If requested to wait, wait for device to become ready
before return.
"""
rx_data = self.spi.transfer(data)
if wait == True:
self.check_device_ready()
return rx_data

def send_bulk(self, data):
"""
Send a byte stream of data without checking for device readiness.
"""
self.spi.transfer(data)

def close(self):
"""
Close the device handle
"""
self.spi.close()
@@ -0,0 +1,133 @@
#!/usr/bin/env python3
#
# Copyright (c) 2019 Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0
#
# Author: Sathish Kuttan <sathish.k.kuttan@intel.com>

# This script is the top level script that an user can invoke to
# download a Zephyr application binary from a Linux host connected
# over SPI to Intel Sue Creek S1000 target during development.

import os
import sys
import hashlib
import device
import messenger

sue_creek = device.Device()
msg = messenger.Message()

def check_arguments():
"""
Check whether file name is provided.
If not print usage instruction and exit.
"""
if len(sys.argv) != 2:
print('Usage: python3 %s <zephyr.bin>' % sys.argv[0])
sys.exit()
return sys.argv[1]

def calc_firmware_sha(file):
"""
Open firmware image file and calculate file size
Pad file size to a multiple of 64 bytes
Caculate SHA256 hash of the padded contents
"""
with open(file, 'rb') as firmware:
firmware.seek(0, 2)
size = firmware.tell()

# pad firmware to round upto 64 byte boundary
padding = (size % 64)
if padding != 0:
padding = (64 - padding)
size += padding

firmware.seek(0, 0)
sha256 = hashlib.sha256()
for block in iter(lambda: firmware.read(4096), b""):
sha256.update(block)
firmware.close()

if padding != 0:
sha256.update(b'\0' * padding)
print('Firmware (%s): %d bytes, will be padded to %d bytes.'
% (os.path.basename(file), size - padding, size))
else:
print('Firmware file size: %d bytes.' % size)
print('SHA: ' + sha256.hexdigest())
return (size, padding, sha256.digest())

def setup_device():
"""
Configure SPI master device
Reset target and send initialization commands
"""
sue_creek.configure_device(spi_mode = 3, order = 'msb', bits = 8)
sue_creek.reset_device()

command = msg.create_memwrite_cmd((0x71d14, 0, 0x71d24, 0,
0x304628, 0xd, 0x71fd0, 0x3))
response = sue_creek.send_receive(command)
msg.print_response(response)

def load_firmware(file, size, padding, sha):
"""
Send command to load firmware
Transfer binary file contents including padding
"""
command = msg.create_loadfw_cmd(size, sha)
response = sue_creek.send_receive(command)
msg.print_response(response)

with open(file, 'rb') as firmware:
firmware.seek(0, 0)
block_size = msg.get_bulk_message_size()
transferred = 0
for block in iter(lambda: firmware.read(block_size), b""):
if len(block) < block_size:
block += b'\0' * padding
bulk_msg = msg.create_bulk_message(block)
sue_creek.send_bulk(bulk_msg)
transferred += len(bulk_msg)
sys.stdout.write('\r%d of %d bytes transferred to %s.'
% (transferred, size, sue_creek.name))
print('')
firmware.close()

sue_creek.check_device_ready()

command = msg.create_null_cmd()
response = sue_creek.send_receive(command)
msg.print_response(response)

def execute_firmware():
"""
Send command to start execution
"""
command = msg.create_memwrite_cmd((0x71d10, 0, 0x71d20, 0))
response = sue_creek.send_receive(command)
msg.print_response(response)

command = msg.create_execfw_cmd()
response = sue_creek.send_receive(command, wait = False)
msg.print_response(response)

def main():
"""
Check arguments to ensure binary file is provided.
Calculate SHA of the binary image
Setup the SPI master device and GPIOs on the host
Download Firmware
"""
file = check_arguments()
(size, padding, sha) = calc_firmware_sha(file)
setup_device()
load_firmware(file, size, padding, sha)
execute_firmware()
sue_creek.close()

if __name__ == '__main__':
main()

0 comments on commit 8075de7

Please sign in to comment.
You can’t perform that action at this time.