[SOLVED] Is there a way to load a program directly into SRAM using USB OTG?

Writing an applcation to SDcard each time I want to test code I write is pretty troublesome and wears SDcard out. I wonder if there’s a way to upload and execute my code directly in SRAM? I thought that maybe rkdeveloptool could be of use for this, but I’m not sure about it or how to use it for the purpose.

Any advice will be highly appreciated. Thanks in advance.

Yes, rkdeveloptool is exactly what’s needed.

rkdeveloptool db file.bin

And uploaded binary gets executed.

In case anyone is interested, here’s a quick-and-dirty python3 script to pack an application for rkdeveloptool (I believe it is pretty self-explanatory):

from datetime import datetime
date = datetime.now()

def rc4(data):
    K = [0x7C,0x4E,0x03,0x04,0x55,0x05,0x09,0x07,0x2D,0x2C,0x7B,0x38,0x17,0x0D,0x17,0x11]
    C = []

    S = [i for i in range(256)]
    l = len(K)
    j = 0
    for i in range(256):
        j = (j + S[i] + K[i % l]) % 256
        S[i], S[j] = S[j], S[i]

    i = 0
    j = 0
    for b in data:
        i = (i + 1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        C.append(b ^ S[(S[i] + S[j]) % 256])
    return bytearray(C)

def crc32(data):
    crc = 0
    for b in data:
        crc = crc ^ (b << 24)
        for i in range(8):
            if crc & 0x80000000:
                crc = (crc << 1) ^ 0x04c10db7
                crc = crc << 1
            crc = crc & 0xffffffff
    return crc

data = bytearray()
with open('app.bin', 'rb') as f:

BYTE = 1
WORD = 4

hdr = {
    'signature': (WORD, 0x544f4f42),    # 'BOOT'
    'size': (HWORD, 32),
    'version': (HWORD, 0x0100),         # 1.0
    'reserved': (WORD, 0),
    'magic': (HWORD, 0x0103),
    'year': (HWORD, date.year),
    'month': (BYTE, date.month),
    'day': (BYTE, date.day),
    'hour': (BYTE, date.hour),
    'minute': (BYTE, date.minute),
    'second': (BYTE, date.second),
    'model': (WORD, 0x33333038),
    'file_descriptor_type': (BYTE, 1),
    'file_descriptor_offset': (WORD, 32),
    'file_descriptor_length': (BYTE, 57),
    'padding': (1, 0),

    # file descriptor
    'descriptor_length': (BYTE, 57),
    'file_type': (WORD, 1),
    'file_name': (40, 0x007000700061),  # 'app' (UCS2 string)
    'file_offset': (WORD, 89),
    'file_size': (WORD, len(data)),
    'unknown': (WORD, 0)

out = bytearray()
for key in hdr.keys():
    out.extend(hdr[key][1].to_bytes(hdr[key][0], 'little'))
out.extend(crc32(out).to_bytes(WORD, 'little'))

with open('loader.bin', 'wb') as f:

Application must start with RK33 signature.
Below is a simple test application which turns on the Blue LED on ROCK Pi S board:

.cpu cortex-a35
.global _start


GPIO0_BASEADDR = 0xff220000


.section .text
.word 0x33334b52


        mrs x9, mpidr_el1
        tst x9, 0b11
        b.eq . + 0x0c
        b.al . - 0x04
        movz x9, :abs_g1:GPIO0_BASEADDR
        mov w10, ROCKPIS_BLUE_LED
        str w10, [x9, GPIO_SWPORTA_DDR]
        str w10, [x9, GPIO_SWPORTA_DR]
        b.al .
# build
$ aarch64-linux-gnu-as -o /tmp/app.o app.asm
$ aarch64-linux-gnu-ld -o /tmp/app /tmp/app.o
$ aarch64-linux-gnu-objcopy -S -O binary /tmp/app app.bin

# pack
$ python3 pack.py

# upload
$ timeout 2 rkdeveloptool db loader.bin

timeout is to kill rkdeveloptool because it will wait forever for response from the board (which will never come – usbplug is missing and cannot respond)



regarding python script, isn’t same doing mkimage (mkimage -T rkimage)?

would you mind to put it to github/gitlab, if you don’t already have it there?

i’m working on rockpi s and 4 openocd configs.
for now i’ve modified uboot env to enable jtag on rockpi 4.

i have on todo list to make bin file for rkdeveloptool to run directly in sram to avoid messing with emmc/sd.
i would like to reference source inspiration for that :slight_smile:

Could be. I don’t know. I’m not very familiar with u-boot and its accompanying tools.

this is for what?

This is a required signature “RK33”, for BootROM code to “recognize” the binary as valid. Actually, I didn’t check if BootROM validates it or not, but program seems to start executing at offset 4. At least Rockchip ddrbin module always include it and it starts first on load.

Played a bit with different setups. Looks like the signature actually doesn’t matter. If it exists, then it’s fine. If not, it’s fine, too.

are you verifying that using jtag? (on rockpis)

i’m trying something similar with rockpi4, instead of switching leds, i’m trying to switch gpio pins for swd/jtag. but not successfully jlink returns same response like before upload

last four lines changed:

movz x9, #:abs_g1:GRF_GPIO4_ADDR
movz w10, #:abs_g1:GRF_GPIO4_MASKANDVALUE
str w10, [x9]
b.al .

difference between a35 based chips from rockchip is that they have jtag on gpio pins enabled by default, while a53 based chips not.

i’m just thinking whether problem is not, that cortex-m (which also can be considered as core executing bootrom content and hence bringing up a53 up) sits on different pins.

Looks like you load only the upped 16 bits. I’d expect smth like

movz w10, :abs_g0_nc:GRF_GPIO4_MASKANDVALUE
movk w10, :abs_g1:GRF_GPIO4_MASKANDVALUE

ofc, unless value is 0x0000

No, I yet move in the dark. Reading code disassembly and trying. For now, on my ROCK Pi S, apart from GPIO, I managed to successfully configure UARTs and implemented serial console. basically, that’s how I debug – just send values of registers and memory locations which interest me over the serial :slight_smile:

1 Like

i had it, but was not sure regarding copying words/halfwords, before compilation i just found some llvm test which had this in and replaced :confused:

consider me assembly noob :slight_smile:

Improved packer script a little bit and added ddrbin for DRAM init.

  • ddrbin starts in SRAM, initializes DRAM and UART, returns back to BootROM
  • BootROM loads target application appbin into DRAM at address 0 and gives it control.


import datetime
import struct
import sys

def rc4(data):
    K = [0x7C,0x4E,0x03,0x04,0x55,0x05,0x09,0x07,0x2D,0x2C,0x7B,0x38,0x17,0x0D,0x17,0x11]
    C = []

    S = [i for i in range(256)]
    l = len(K)
    j = 0
    for i in range(256):
        j = (j + S[i] + K[i % l]) % 256
        S[i], S[j] = S[j], S[i]

    i = 0
    j = 0
    for b in data:
        i = (i + 1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        C.append(b ^ S[(S[i] + S[j]) % 256])
    return bytearray(C)

def crc32(data):
    crc = 0
    for b in data:
        crc = crc ^ (b << 24)
        for i in range(8):
            if crc & 0x80000000:
                crc = (crc << 1) ^ 0x04c10db7
                crc = crc << 1
    return crc & 0xffffffff

hdr_size = struct.calcsize(hdr_fmt)

fte_fmt = '<BL40sLLL'
fte_size = struct.calcsize(fte_fmt)

with open(sys.argv[1], 'rb') as f:
    ddrbin = f.read()

with open(sys.argv[2], 'rb') as f:
    appbin = f.read()

now = datetime.datetime.now()

hdr = struct.pack(
    hdr_fmt + fte_fmt[1:] + fte_fmt[1:],

    # rkboot header
    0x544f4f42,     # signature ('BOOT')
    hdr_size,       # size of header
    0x0100,         # version (1.0)
    0,              # reserved
    0x0103,         # magic
    now.year,       # year
    now.month,      # month
    now.day,        # day
    now.hour,       # hour
    now.minute,     # minute
    now.second,     # second
    0x33333038,     # SoC model ('3308')

    # file table entry descriptors
    1, hdr_size, fte_size,
    1, hdr_size + fte_size, fte_size,

    # file table entries
    fte_size,                                   # entry size
    1,                                          # file type
    bytearray('ddr.bin'.encode('utf-16-le')),   # file name (UTF-16)
    hdr_size + fte_size * 2,                    # file offset
    len(ddrbin),                                # file size
    0,                                          # ???

    fte_size,                                   # entry size
    1,                                          # file type
    bytearray('app.bin'.encode('utf-16-le')),   # file name (UTF-16)
    hdr_size + fte_size * 2 + len(ddrbin),      # file offset
    len(appbin),                                # file size

out = bytearray(hdr)
out.extend(crc32(out).to_bytes(4, 'little'))
with open(sys.argv[3], 'wb') as f:
python3 pack.py rk3308_ddr_589MHz_uart0_m0_v1.26.bin target_app.bin out.bin

Note: Maybe will need to change the way included files are encrypted by the script. This is because files included in the original Rockchip loader are encrypted this way:

  • each file is encrypted separately
  • out of the first two files, only the first 64K are encrypted. That is, if file1 size is 32K, then only the first 32K of file 2 are encrypted. The rest goes plain.
    Anyway, I don’t need this now. Will update when need to (if required). But just keep this in mind.

great news.

thanks your upper/lower bits note i managed to switch jtag pins on rockpi4, connected to debug port and halted/resumed running core in EL3 level.

i would like to know, if is possible to use ahb connected to debug port for communication with usb, to close uploading of file without halting the core.

replying to myself - no it is not possible, core must be halted.

1 Like