Skip to content

Flashing firmware on DaVinci media processors

mefistotelis edited this page Jun 5, 2021 · 73 revisions

Table of Contents

Overview
Flashing via serial port
  Flashing u-boot by serial port
  Flashing kernel
  Flashing encrypted partition
  Flashing Root Filesystem
  Fix FPV restricted to 8 fps

Overview

Several DJI products use DM3xx family DaVinci media processors from Texas Instruments. Since the NAND memory chips which DJI uses to store their firmware can often stop working or lose data after several months without powering on, there is sometimes a need to re-flash part of the firmware, or even replace the chip and re-flash all partitions of the firmware. This page will explain the procedure.

Replacing whole NAND chip

When going the chip replacement route, you may first check whether some data can be still salvaged from the board. There are some files on the NAND which are unique to every drone, and can't be completely recovered when lost. Read the info on 8 fps issue for details.

Flashing via serial port

It is possible to boot the chip into a mode which allows programming it via serial port. Since the board requires 3.3V serial interface, you will need USB to TTL converter (aka FTDI adapter) which supports this voltage.

Connect your 3.3V TTL converter to service pads. While this depends on markings of specific TTL converter, usually RX should be connected to TX and vice versa. Don't worry about connecting RX and TX incorrectly, switching them will not damage anything, it just won't work. The pad names depend on the board you have:

If your TTL converter has a 5V power output, you may also choose to power your board from it, completely disconnecting it from aircraft. Be careful with that - connecting power from the drone and from TTL at the same time may overheat and damage some of the components. If you want to work on your board disconnected, connect power to a service pad marked 5V. The board will draw up to 700mA of current (over 1000 mA if it also contains Ambarella) - connecting it to low-power USB will cause random resets and transmission errors.

Flashing u-boot by serial port

If after tapping to the serial interface, you see no message, or booting does not get to loading kernel, then you should re-flash u-boot images. When u-boot is good, it will display the message Loading from nand0, offset 0x??????.

To re-flash u-boot, you should boot the chip into a mode which allows programming it via serial port.

To switch the boot mode, short the Boot Select service pad to 3.3V. Marking of Boot Select pad depends on board:

After the pad is connected, use TI utilities on connected PC to flash your new image:

sfh_DM36x -nandflash -v -p "COM21" ubl1.img u-boot.img

If you typed the correct port name, and service pads are shorted properly, you should see Target: BOOTME message. You have to press Ctrl+C to get back to a prompt, and then run the command again. The second time it will work, resulting in message Operation completed successfully.. Example for full log from the flashing:

-----------------------------------------------------
   TI Serial Flasher Host Program for DM36x
   (C) 2009, Texas Instruments, Inc.
-----------------------------------------------------

Flashing NAND with ubl1.img and u-boot.img.

Attempting to connect to device com21...

Waiting for the DM36x...
        Target:  BOOTME
BOOTME commmand received. Returning ACK and header...
ACK command sent. Waiting for BEGIN command...
        Target:   BEGIN
BEGIN commmand received. Sending CRC table...
                           CRC table sent....
Waiting for DONE...
        Target:    DONE
DONE received.  Sending the UBL...
                              UBL sent....
        Target:    DONE
DONE received.  UBL was accepted.
UBL transmitted successfully.

Waiting for SFT on the DM36x...
        Target: Starting UART Boot...
        Target: BOOTUBL
BOOTUBL commmand received. Returning CMD and command...
CMD value sent.  Waiting for DONE...
        Target:    DONE
DONE received. Command was accepted.
Sending the UBL image
Waiting for SENDIMG sequence...
        Target: SENDIMG
SENDIMG received. Returning ACK and header for image data...
ACK command sent. Waiting for BEGIN command...
        Target:   BEGIN
BEGIN commmand received.
                           Image data sent...
Waiting for DONE...
        Target:    DONE
DONE received.  All bytes of image data received...
        Target: Writing UBL to NAND flash
        Target: Unprotecting blocks 0x00000001 through 0x00000018.
        Target: Number of blocks needed for header and data: 0x0x00000001
        Target: Attempting to start in block number 0x0x00000001.
        Target: Erasing block 0x00000001 through 0x00000001.
        Target: Writing header and image data to Block 0x00000001, Page 0x00000000
[...] - above 2 messages will show for a sequence ob blocks
        Target: Erasing block 0x00000018 through 0x00000018.
        Target: Writing header and image data to Block 0x00000018, Page 0x00000000
        Target: Protecting the entire NAND flash.
        Target:    DONE
Sending the Application image
Waiting for SENDIMG sequence...
        Target: SENDIMG
SENDIMG received. Returning ACK and header for image data...
ACK command sent. Waiting for BEGIN command...
        Target:   BEGIN
BEGIN commmand received.
                           Image data sent...
Waiting for DONE...
        Target:    DONE
DONE received.  All bytes of image data received...
        Target: Writing APP to NAND flash
        Target: Unprotecting blocks 0x00000019 through 0x00000032.
        Target: Number of blocks needed for header and data: 0x0x00000003
        Target: Attempting to start in block number 0x0x00000019.
        Target: Erasing block 0x00000019 through 0x0000001B.
        Target: Writing header and image data to Block 0x00000019, Page 0x00000000
[...] - above 2 messages will show for a sequence ob blocks
        Target: Erasing block 0x0000002E through 0x00000030.
        Target: Writing header and image data to Block 0x0000002E, Page 0x00000000
        Target: Protecting the entire NAND flash.
        Target:    DONE
        Target:    DONE
Operation completed successfully.

You will need the unencrypted images of TI DaVinci Linux and the U-boot bootloader to do the flashing - files ubl1.img and u-boot.img. Depending on the board you're fixing, these are stored in appropriate modules within firmware update:

Download the correct firmware package, and extract it with the tools provided within dji-firmware-tools repository.

For more sources of information, you can look at the description of the flashing procedure for Lightbridge for some details. There is also a P3X-specific tutorial for Gimbal Top board, created by SunsetCatcher; you should be able to find links to his ph3pns.zip archive on PhantomPilots.

TI Serial Flashing tool

This method is based on Serial Boot and Flash Loading Utility provided by Texas Instruments. See "Obtaining the software" and "Versions for Other Devices" chapters of that page to download a version for the correct processor series.

Flashing kernel

If at the serial interface you see kernel boot error, or Recovery Kernel is booted, or kernel stops booting - you should reflash the kernel image. For example, this is how booting Recovery Kernel looks like:

U-Boot Product Vesion : DJI-DEC-Uboot-1.0-rc0(2015-11-02)
U-Boot 2010.12-rc2-svn3214-Dji (Nov 02 2015 - 19:39:56)
Cores: ARM 486 MHz
DDR:   360 MHz
I2C:   ready
DRAM:  128 MiB
NAND:  128 MiB
Bad block table found at page 65472, version 0x01
Bad block table found at page 65408, version 0x01
*** Warning - bad CRC, using default environment
.
Net:   Ethernet PHY: GENERIC @ 0xff
DaVinci-EMAC
Press ESC to abort autoboot in 1 seconds
.
Loading from nand0, offset 0x4a0000
** Unknown image type
Wrong Image Format for bootm command
ERROR: can't get kernel image!
.
Loading from nand0, offset 0x900000
   Image Name:   Linux-2.6.32.17-davinci1
   Created:      2015-02-12   3:09:59 UTC
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    3665856 Bytes = 3.5 MiB
   Load Address: 80008000
   Entry Point:  80008000
## Booting kernel from Legacy Image at 80700000 ...
   Image Name:   Linux-2.6.32.17-davinci1
   Created:      2015-02-12   3:09:59 UTC
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    3665856 Bytes = 3.5 MiB
   Load Address: 80008000
   Entry Point:  80008000
   Loading Kernel Image ... OK
OK
.
Starting kernel ...
.
[    0.000000] Kernel Product Vesion : DJI-GRC-Kernel-1.0-rc8(2014-11-21)
[    0.000000] Linux version 2.6.32.17-davinci1 (u@dji) (gcc version 4.3.3 (Sourcery G++ Lite 2009q1-203) ) #1 PREEMPT Thu Feb 12 11:09:57 HKT 2015
[    0.000000] CPU: ARM926EJ-S [41069265] revision 5 (ARMv5TEJ), cr=00053177
...

If both primary and recovery kernel is corrupted, the booting will end at U-Boot command line:

Loading from nand0, offset 0x4a0000
** Unknown image type
Wrong Image Format for bootm command
ERROR: can't get kernel image!

Loading from nand0, offset 0x900000
** Unknown image type
Wrong Image Format for bootm command
ERROR: can't get kernel image!
Dji-Pro #

Note that u-boot tries to load primary kernel after message Loading from nand0, offset 0x4a0000, and recovery kernel is tried only if primary failed, with message Loading from nand0, offset 0x900000. The offsets at which kernel images are located inside NAND, depend on memory map used within specific product - see pages about your module (m0800/m1300/m1301) for proper memory map. There are some products which do not have recovery kernel, and there is only one kernel. For these platforms, u-boot will only show one message about Loading from nand0.

Usually you will want to flash the primary kernel, uImage. For most boards, you can get it from firmware update (see chapter about flashing bootloader for firmware module marking). For specific boards:

If your Recovery Kernel is also damaged, you may also flash the special recovery image uImage_recovery. It is not a part of firmware update, so you need to find a proper image:

It might be better to use the primary kernel image to flash both copies of kernel. The Recovery Kernel is different only because it is never updated automatically by DJI firmware updates - it stays as it was when going out of factory. This means the Recovery Kernel is just a very old version of the ordinary kernel.

Preparations

To reflash the kernel, you need to press the ESC key just when your board gets power, so that you end up in u-boot console. Next press Enter to get rid of any additional ESC stokes left in input buffer:

Press ESC to abort autoboot in 1 seconds
Dji-Pro #
Unknown command '' - try 'help'
Dji-Pro # 

Now, you need to load a new kernel image to DRAM, and from there, flash it to NAND memory.

Let's start by cleaning a portion of DRAM which we will use:

Dji-Pro # mw.b 0x80008000 0xFF 0x460000

Next we need to put our kernel image into that location. There are two ways:

Loading kernel via serial using ModemY

The transfer over serial is very slow and cumbersome. It requires compatible terminal client. On Windows, you can use ExtraPuTTY. On Linux, Minicom can support it.

First, initiate the transfer on DaVinci side:

Dji-Pro # loady 0x80008000 115200
## Ready for binary (ymodem) download to 0x80008000 at 115200 bps...

Then, use proper function in your terminal to select the target file. The transfer will last some time - for 4MB kernel, it should take around 13 minutes. After it finishes, you will see:

xyzModem - CRC mode, 1(SOH)/3971(STX)/0(CAN) packets, 4 retries
## Total Size      = 0x003e09c0 = 4065728 Bytes
Dji-Pro #

Loading kernel via USB stick

This is the method I'd suggest. It is fast and reliable, especially for boards which by design have USB connector linked to the DaVinci chip. On some boards, the USB output comes from Ambarella - in such case, using the DaVinci USB requires manually soldering a female USB connector to proper pins. The method was tested with 2GB sd-card formatted to FAT32 and inserted into USB Card Reader. Some USB sticks were not detected by the DM3xx USB controller - it is best to try a few of them.

If your board does not have USB connector to DaVinci, you'll have to solder it:

  • for Gimbal top board, use two pins (pin1 and pin2) of the connector which goes to OFDM for USB D+ and D-. The power pin of your female USB connector should go to 5V supply, and ground pin to a ground associated to the 5V supply you used. Pin map using standard USB wire colors:
wire color solder point
Vbus red 5V service pad
GND black GND service pad
D+ green Gimbal-to-OFDM ribbon cable pin1
D- white Gimbal-to-OFDM ribbon cable pin2

In some of the gimbal boards, USB is controlled by GPIO pin of the DM3xx chip; if usb start shows no information about USB device connected, then it may be required to switch the proper GPIO pin by software. It is not fully known how to do this, or which of GPIO pins is used. If USB just doesn't want to work on your board, use serial transfer instead.

  • for other boards, find the proper place where DM36x USB output is

Copy the kernel image on your USB stick, and put it into USB slot of your board. Then, execute the following:

Dji-Pro # usb start
Dji-Pro # usb storage

The second command isn't really needed, but it will show you your USB device, so that you know it is functioning. Now, start the loading process:

Dji-Pro # fatload usb 0 0x80008000 uImage

On success, you should see something like:

reading uImage
.
4065728 bytes read
Dji-Pro #

Flashing the kernel from DRAM

Be careful, you are now going to make changes to your NAND memory. Do not lose or add any zeros in the offsets. Select one of the following chapters, based on memory map used in your device. DaVinci modules in most products use the typical memory map.

Flashing the kernel from DRAM on typical NAND memory map

To write Primary Kernel, execute the following commands:

Dji-Pro # nand erase 0x04a0000 0x460000
Dji-Pro # nand write 0x80008000 0x04a0000 0x460000

In case you are writing Recovery Kernel, run the commands below instead:

Dji-Pro # nand erase 0x0900000 0x460000
Dji-Pro # nand write 0x80008000 0x0900000 0x460000

You can write the same kernel image over the two locations. But if the recovery kernel works, there is no reason to overwrite it.

Flashing the kernel from DRAM on FC200

The first use of DM36x by Dji, FC200 camera from P2V, has a bit different memory map and requires different addresses; kernel is also compressed there, and therefore smaller:

Dji-Pro # nand erase 0x0680000 0x300000
Dji-Pro # nand write 0x80008000 0x0680000 0x300000

In case you are writing Recovery Kernel, run the commands below instead:

Dji-Pro # nand erase 0x0980000 0x300000
Dji-Pro # nand write 0x80008000 0x0980000 0x300000

You can write the same kernel image over the two locations. But if the recovery kernel works, there is no reason to overwrite it.

Flashing the kernel from DRAM on RC001

The memory map within Inspire 2 RC has a different layout; kernel is usually smaller, but there is no reason not to rewrite the whole partition:

Dji-Pro # nand erase 0x0580000 0x400000
Dji-Pro # nand write 0x80008000 0x0580000 0x400000

There is no recovery kernel partition for this product, so that is all.

Flashing encrypted partition

If the encrypted partition gets damaged, Linux will stop booting - kernel module responsible for encryption will freeze. In such case, the system freezes soon after the message:

encrypt device:at88 found

If this happens, you may want to reflash this partition. It is not a part of firmware update, so you need to find a proper image:

Note: this partition is different for every specific board instance; do not reflash it unless you are having issues you know are related to it! Some products (P2 series, Inspire RC001) do not have that partition at all.

The procedure is almost the same as for flashing kernel, so it will not be explained in detail. Commands:

mw.b 0x80008000 0xFF 0xa0000
usb start
usb storage
fatload usb 0 0x80008000 dm365_secret.bin
nand erase 0x0d60000 0xa0000
nand write 0x80008000 0x0d60000 0xa0000

Flashing Root Filesystem

The Ubi File System is able to correct its errors and mark would-be bad sectors in advance, so it is unusual for it to get corrupted. It is also the hardest component to recover. Do not flash the UbiFS unless error messages explicitly say it is damaged!

The UbiFS partitions cannot be just written by nand write as all the others, because it contains EC blocks supported by NAND hardware. Writing them this way would make them possible to read only once, after that EC block would be damaged.

While u-boot has UbiFS support, it is unfinished in the old version provided in firmwares. Do not use it - it will damage your UbiFS even further.

The only viable option is to flash the new UbiFS image from Linux. To run Linux independently of the UbiFS Root Filesystem, we will need another root - Recovery Root Filesystem. It needs to be as small as possible, but still have all the tools required to work with UBI partitions. You can get it here.

Getting a Root Filesystem image

You will need a valid UbiFS Root Filesystem image, the one we want to recover. It is not a part of firmware update, so you need to find one:

Keep the image handy - we will need it after we'll manage to boot Linux.

Flashing Recovery Root Filesystem

Since we have no unused space on the disk to fit our partition, we will have to temporarily sacrifice something else. For most boards, the best candidate is our primary kernel - it will be easy to recover it later, and it is far from encrypted partition which we don't want to accidentally overwrite.

If you don't understand the commands, or want to use serial instead of USB, read flashing kernel section.

Flashing Recovery Root Filesystem on typical NAND memory map

We will now overwrite the primary kernel with our Recovery Root Filesystem.

To load the Recovery Root FS, insert USB stick with the partition image, boot to u-boot Console and execute:

mw.b 0x82000000 0xFF 0x400000
usb start
usb storage
fatload usb 0 0x82000000 dm365_recovery_rootfs.bin

That will place the Recovery Root FS image in DRAM (you may also do the same using serial transfer). Next, you want to flash it, sacrificing primary kernel:

nand erase 0x04a0000 0x400000
nand write 0x82000000 0x04a0000 0x400000

That's it - now we should be able to boot. Read Booting to Linux chapter below.

Flashing Recovery Root Filesystem on FC200

For FC200 camera from P2V, with its specific memory map, flashing Recovery Root Filesystem will overwrite both kernels. We will have to deal with that.

To load the Recovery Root FS, insert USB stick with the partition image, boot to u-boot Console and execute:

mw.b 0x82000000 0xFF 0x400000
usb start
usb storage
fatload usb 0 0x82000000 dm365_recovery_rootfs.bin

That will place the Recovery Root FS image in DRAM (you may also do the same using serial transfer). Next, you want to flash it, sacrificing both kernels:

nand erase 0x0680000 0x400000
nand write 0x82000000 0x0680000 0x400000

Now you have no valid kernel on the NAND. So to boot Linux, you need to write a third kernel somewhere further, I'd suggest just after the Recovery Root FS, at 0x0a80000. To load and flash the kernel, execute:

fatload usb 0 0x80008000 uImage
nand erase 0x0a80000 0x300000
nand write 0x80008000 0x0a80000 0x300000

For more info on these commands, see chapter on Flashing kernel.

After the kernel is flashed, we should be able to boot. Read Booting to Linux chapter below.

Flashing Recovery Root Filesystem on RC001

If you are fixing Inspire 2 RC board, there is no recovery kernel - only primary. But the place for kernel is large enough to store Recovery Root FS, and we also have the logo partition which is empty, so there is a way to fit both the kernel and the Recovery Root FS on the NAND:

  • flash Recovery Root FS into Kernel partition
  • flash the kernel into U-boot logo partition

To load the Recovery Root FS, insert USB stick with the partition image, boot to u-boot Console and execute:

mw.b 0x82000000 0xFF 0x400000
usb start
usb storage
fatload usb 0 0x82000000 dm365_recovery_rootfs.bin

That will place the Recovery Root FS image in DRAM (you may also do the same using serial transfer). Next, you want to flash it, sacrificing the kernel:

nand erase 0x0580000 0x400000
nand write 0x82000000 0x0580000 0x400000

Now you have no valid kernel on the NAND. So to boot Linux, you need to overwrite U-boot logo at 0x0280000. To load and flash the kernel, execute:

fatload usb 0 0x80008000 uImage
nand erase 0x0280000 0x300000
nand write 0x80008000 0x0280000 0x300000

For more info on these commands, see chapter on Flashing kernel.

After the kernel is flashed, we should be able to boot. Read Booting to Linux chapter below.

Booting to Linux with Recovery Root FS

Now we are able to boot our Recovery Kernel, pointing it to our Primary Kernel partition for Root Filesystem location. But if started normally, the u-boot would set the kernel parameters so that they point to original Root Filesystem. We need to land in U-boot console, and there change the Root Filesystem location in kernel parameters before starting the kernel.

Booting with Recovery Root FS on typical NAND memory map

To start recovery kernel with rootfs placed on primary kernel partition, boot to u-boot Console and execute:

env set bootargs 'console=ttyS0,115200n8 rw dm365_imp.oper_mode=0 video=davincifb:vid0=0,10K:vid1=0,10K:osd0=1920x1080X16,8100K mem=96MB davinci_enc_mngr.ch0_output=COMPOSITE loglevel=8 davinci_enc_mngr.ch0_mode=pal root=/dev/mtdblock1 rootfstype=cramfs ip=off lpj=1077248'
nboot 80700000 0 900000
bootm 80700000

Booting with Recovery Root FS on FC200

To start your third kernel with rootfs placed on primary kernel partition, boot to u-boot Console and execute:

env set bootargs 'console=ttyS0,115200n8 rw dm365_imp.oper_mode=0 video=davincifb:vid0=OFF:vid1=OFF:osd0=480x272x16,4050K mem=96MB davinci_enc_mngr.ch0_output=LCD davinci_enc_mngr.ch0_mode=480x272 loglevel=8 root=/dev/mtdblock2 rootfstype=cramfs ip=192.168.1.10:192.168.1.5:192.168.2.2:255.255.255.0::eth0:off'
nboot 80700000 0 a80000
bootm 80700000

Booting with Recovery Root FS on RC001

To start your kernel from U-boot logo partiton with rootfs placed on kernel partition, boot to u-boot Console and execute:

env set bootargs 'console=ttyO0,115200n8 rw mem=128M rw notifyk.vpssm3_sva=0xbffd0000 ddr_mem=512M vram=32M lpj=2998272 loglevel=8 root=/dev/mtdblock3 rootfstype=cramfs ip=192.168.1.10:192.168.1.5:192.168.2.2:255.255.255.0::eth0:off'
dcache on
nand read.os 0x80007fc0 0x00280000 0x300000
dcache off
bootm 0x80007fc0

The actual Root Filesystem flash operation

When the Linux is started with different rootfs, you can format the UbiFS partition with new image. The commands below assume that UbiFS partition is visible as mtd2 - make sure it is the case before executing the commands:

cd /tmp; mkdir sdcard
mount /dev/sda sdcard
ubiformat /dev/mtd2 --sub-page-size=512 --vid-hdr-offset=2048 -f sdcard/dm365_root_ubifs.ubi

If you do not have USB connector to read the image from, you can use ramdisk (/tmp) to temporarily store an image transferred by serial. In such case, use lrz tool available in the Recovery Root Filesystem to receive binary ymodem transmission.

To check whether the filesystem is functional, try:

ubiattach -m 2 --vid-hdr-offset=2048

If this resulted in details on file system blocks and no error information, UbiFS is restored! Now, booting from Recovery Kernel should work without using our Recovery Root Filesystem. Restart the board; since the Primary Kernel does not contain a valid Kernel, u-boot will boot Recovery kernel automatically.

If the Linux system boots properly, we can restore the Primary Kernel to finish the process. Follow the instructions above to do that.

Fix FPV restricted to 8 fps

When Encrypted Partition or Root Filesystem are re-flashed, the First Person View Video on Mobile Device will come back but only at 8 frames per second. This chapter will focus on explaining and providing a fix for this issue.

Modules m0100 (Ambarella App), m0800 (DaVinci Processor) and m0400 (Gimbal Controller) share access to ATSHA204 chip, which provides safe storage for a cryptographic key. Using that chip, these modules can encrypt data in a way which is hard to break - because there is no way to extract key from ATSHA204. They do not use the key from ATSHA204 directly - instead, it is used to store another key within persistent storage of each of the modules, and they are stored in encrypted form.

In case of DaVinci Media Processor, there are two copies stored - one as the entire Encrypted Partition, and second as /etc/key.bin within the Root Filesystem. If these were damaged, they're not easy to recover.

The encryption capability is used at startup, to verify whether all modules share the same key. If that verification fails, DaVinci processor will continuously re-try encryption pairing, forever. Since encryption is computationally expensive, that will degrade FPV video to 8 fps.

As a side note - if that same verification fails in Ambarella App, the module will enter AuthorityLevel=0 mode. In this mode, it will ignore most commands. If your Ambarella works, but refuses to start recording or to take a photo - this might be the cause.

To fix the issue when the encryption keys were damaged, the best approach is to mod the firmware so that it will ignore encryption fail at startup. In case of DaVinci, encode_usb binary needs to be modified and copied back to the Root Filesystem. In case of Ambarella App, the sys partition needs to be modified. Modifications can be performed using *_hardcoder.py scripts from this repository. Some details are provided within these scripts.

Why we can't just pair these chips again, you ask? The factory pairing DUML command can be easily triggered on the gimbal, but it won't be able to update key within ATSHA204 chip - it was irreversibly sealed during first pairing. So to do the pairing again, you'd have to replace that chip. Without replacing it, the only way is to workaround the issue by fixing encode_usb.

Clone this wiki locally