Reverse-engineering of some rechargeable disposable vapes that include a small color TFT LCD (Raz TN9000/Kraze HD7K/etc.).
Further updates can be found at https://github.com/ginbot86/ColorLCDVape-RE
Some disposable vapes on the market include accoutrements like a color LCD screen and USB-C rechargeability, yet are single-use throwaway devices; this makes such devices quite ecologically harmful. On the other hand, this opens up opportunities for hardware salvage by hobbyists/engineers, reusing the vape as-is by refilling it with fresh vape juice and resetting the internal meter, or even customization by editing the onboard images.
The specific vape being researched in this project comes by various names, but the one that was researched specifically was called the Kraze HD7K. However, this vape has also been seen under the "RAZ" brand name, like the RAZ TN9000.
Disposable vapes generally use Li-ion batteries without any protection circuitry. Short circuits could dissipate uncontrolled amounts of power, causing personal injury and/or property damage. Any work done on these vapes is done at your own risk.
It has been determined that there are multiple circuit revisions of these vapes, which may have incompatibilities that could result in device damage if versions are mismatched. Verify connections and firmware compatibility before proceeding with any modifications.
Additionally, vape juice/"e-liquid" can contain high concentrations of nicotine, which is absorbed through skin. Handling of the vape's internals should be done with gloves until the internal parts are cleaned of juice and/or residue.
Other people's work on these vapes include, but are not limited to:
Work done in the aforementioned repositories may or may not be based on work done in this project; it is meant to link similar projects in the hopes that more community efforts can be undertaken on these vapes.
The vape uses the following hardware:
The vape uses an 80x160 resolution 0.96-inch IPS LCD, with a 13-pin 0.7mm-pitch flat-flex (FPC) cable that is soldered to the vape mainboard. It connects via 4-wire SPI (data, clock, data/command, chip select), and appears to use the ST7735S controller. It even uses the same pinout for commercially available displays, like the Smart Prototyping #102106.
Pin | Name | Function |
---|---|---|
1 | TP0/NC | Unused |
2 | TP1/NC | Unused |
3 | SDIN | SPI data to LCD |
4 | SCLK | SPI clock |
5 | RS | Logic low = command, high = data |
6 | /RST | Reset (active-low) |
7 | /CS | Chip select (active-low) |
8 | GND | Power supply/signal ground |
9 | NC | Not connected |
10 | VDD | Power supply (3.3V) |
11 | LEDK | LED backlight cathode |
12 | LEDA | LED backlight anode |
13 | GND | Power supply/signal ground |
There are two forms of Flash memory on the vape: internal Flash on the microcontroller, and 1 megabyte (8 megabits) of external SPI NOR Flash. The former contains the firmware, while the latter contains all the images that are displayed on the LCD, as well as the total time that the vape heating coil was in use; this counter is used to derive the number of "bars" displayed on the vape juice meter. Analysis of the LCD data bus (see the .dsl logic capture using DreamSourceLab DSView) suggests that the microcontroller uses DMA (Direct Memory Access) to stream image data from the external Flash into the LCD, as data transfers occur as contiguous 4096-byte chunks, corresponding to a single NOR Flash page. Analysis of the microcontroller's memory indicates that the DMA memory buffer lies in RAM addresses 0x2000022C-0x2000062B.
All images are stored on the external Flash as raw RGB565 16-bit bitmaps (i.e. each pixel takes up 2 bytes of data). Conversion tools, such as ImageConverter565 from Rinky-Dink Electronics' UTFT library, can be used to convert image formats like JPEG/PNG into a raw binary file that can be patched into the external Flash at the corresponding offset. There is no metadata stored with the raw images, so the image dimensions must be manually supplied, as shown in the table below.
Index (#) | Offset (Hex) | Length (Hex) | Frame H (px) | Frame V (px) | Category | Unused? | Seq (#) | Notes |
---|---|---|---|---|---|---|---|---|
0 | 0 | 6400 | 80 | 160 | Background | 0 | ||
1 | 6400 | 2880 | 72 | 72 | Battery Icon | 0 | ||
2 | 8C80 | 2880 | 72 | 72 | Battery Icon | 1 | ||
3 | B500 | 2880 | 72 | 72 | Battery Icon | 2 | ||
4 | DD80 | 2880 | 72 | 72 | Battery Icon | 3 | ||
5 | 10600 | 2880 | 72 | 72 | Battery Icon | 4 | ||
6 | 12E80 | 2880 | 72 | 72 | Battery Icon | 5 | ||
7 | 15700 | 2880 | 72 | 72 | Battery Icon | 6 | ||
8 | 17F80 | 2880 | 72 | 72 | Battery Icon | 7 | ||
9 | 1A800 | 2880 | 72 | 72 | Battery Icon | 8 | ||
10 | 1D080 | 2880 | 72 | 72 | Battery Icon | 9 | ||
11 | 1F900 | 2880 | 72 | 72 | Battery Icon | 10 | ||
12 | 22180 | 2880 | 72 | 72 | Juice Icon | 0 | ||
13 | 24A00 | 2880 | 72 | 72 | Juice Icon | 1 | ||
14 | 27280 | 2880 | 72 | 72 | Juice Icon | 2 | ||
15 | 29B00 | 2880 | 72 | 72 | Juice Icon | 3 | ||
16 | 2C380 | 2880 | 72 | 72 | Juice Icon | 4 | ||
17 | 2EC00 | 2880 | 72 | 72 | Juice Icon | 5 | ||
18 | 31480 | 2880 | 72 | 72 | Juice Icon | 6 | ||
19 | 33D00 | 6400 | 80 | 160 | Vaping Animation | 0 | ||
20 | 3A100 | 6400 | 80 | 160 | Vaping Animation | 1 | ||
21 | 40500 | 6400 | 80 | 160 | Vaping Animation | 2 | ||
22 | 46900 | 6400 | 80 | 160 | Vaping Animation | 3 | ||
23 | 4CD00 | 6400 | 80 | 160 | Vaping Animation | 4 | ||
24 | 53100 | 6400 | 80 | 160 | Vaping Animation | 5 | ||
25 | 59500 | 6400 | 80 | 160 | Vaping Animation | 6 | ||
26 | 5F900 | 6400 | 80 | 160 | Vaping Animation | 7 | ||
27 | 65D00 | 6400 | 80 | 160 | Vaping Animation | 8 | ||
28 | 6C100 | 6400 | 80 | 160 | Vaping Animation | 9 | ||
29 | 72500 | 6400 | 80 | 160 | Vaping Animation | 10 | ||
30 | 78900 | 6400 | 80 | 160 | Vaping Animation | 11 | ||
31 | 7ED00 | 6400 | 80 | 160 | Vaping Animation | 12 | ||
32 | 85100 | 6400 | 80 | 160 | Vaping Animation | 13 | ||
33 | 8B500 | 6400 | 80 | 160 | Vaping Animation | 14 | ||
34 | 91900 | 6400 | 80 | 160 | Vaping Animation | 15 | ||
35 | 97D00 | 6400 | 80 | 160 | Plugin Background 1 | Unused | 16 | 1 |
36 | 9E100 | 17CA | 35 | 87 | Logo Wipe | Unused | 0 | 1 |
37 | 9F8CA | 17CA | 35 | 87 | Logo Wipe | Unused | 1 | 1 |
38 | A1094 | 17CA | 35 | 87 | Logo Wipe | Unused | 2 | 1 |
39 | A285E | 17CA | 35 | 87 | Logo Wipe | Unused | 3 | 1 |
40 | A4028 | 17CA | 35 | 87 | Logo Wipe | Unused | 4 | 1 |
41 | A57F2 | 17CA | 35 | 87 | Logo Wipe | Unused | 5 | 1 |
42 | A6FBC | 17CA | 35 | 87 | Logo Wipe | Unused | 6 | 1 |
43 | A8786 | 17CA | 35 | 87 | Logo Wipe | Unused | 7 | 1 |
44 | A9F50 | 17CA | 35 | 87 | Logo Wipe | Unused | 8 | 1 |
45 | AB71A | 17CA | 35 | 87 | Logo Wipe | Unused | 9 | 1 |
46 | ACEE4 | 17CA | 35 | 87 | Logo Wipe | Unused | 10 | 1 |
47 | AE6AE | 17CA | 35 | 87 | Logo Wipe | Unused | 11 | 1 |
48 | AFE78 | 17CA | 35 | 87 | Logo Wipe | Unused | 12 | 1 |
49 | B1642 | 17CA | 35 | 87 | Logo Wipe | Unused | 13 | 1 |
50 | B2E0C | 17CA | 35 | 87 | Logo Wipe | Unused | 14 | 1 |
51 | B45D6 | 17CA | 35 | 87 | Logo Wipe | Unused | 15 | 1 |
52 | B5DA0 | 17CA | 35 | 87 | Logo Wipe | Unused | 16 | 1 |
53 | B756A | 17CA | 35 | 87 | Logo Wipe | Unused | 17 | 1 |
54 | B8D34 | 17CA | 35 | 87 | Logo Wipe | Unused | 18 | 1 |
55 | BA4FE | 17CA | 35 | 87 | Logo Wipe | Unused | 19 | 1 |
56 | BBCC8 | 17CA | 35 | 87 | Logo Wipe | Unused | 20 | 1 |
57 | BD492 | 17CA | 35 | 87 | Logo Wipe | Unused | 21 | 1 |
58 | BEC5C | 17CA | 35 | 87 | Logo Wipe | Unused | 22 | 1 |
59 | C0426 | 17CA | 35 | 87 | Logo Wipe | Unused | 23 | 1 |
60 | C1BF0 | 17CA | 35 | 87 | Logo Wipe | Unused | 24 | 1 |
61 | C33BA | 17CA | 35 | 87 | Logo Wipe | Unused | 25 | 1 |
62 | C4B84 | 17CA | 35 | 87 | Logo Wipe | Unused | 26 | 1 |
63 | C634E | 17CA | 35 | 87 | Logo Wipe | Unused | 27 | 1 |
64 | C7B18 | 17CA | 35 | 87 | Logo Wipe | Unused | 28 | 1 |
65 | C92E2 | 6400 | 80 | 160 | Plugin Background 2 | Unused | 0 | 1 |
66 | CF6E2 | F80 | 31 | 64 | Battery Bars Animation | Unused | 0 | 1 |
67 | D0662 | F80 | 31 | 64 | Battery Bars Animation | Unused | 1 | 1 |
68 | D15E2 | F80 | 31 | 64 | Battery Bars Animation | Unused | 2 | 1 |
69 | D2562 | F80 | 31 | 64 | Battery Bars Animation | Unused | 3 | 1 |
70 | D34E2 | F80 | 31 | 64 | Battery Bars Animation | Unused | 4 | 1 |
71 | D4462 | F80 | 31 | 64 | Battery Bars Animation | Unused | 5 | 1 |
72 | D53E2 | 6400 | 80 | 160 | Plugin Background 3 | 0 | ||
73 | DB7E2 | E9A | 21 | 89 | Charger Logo Wipe | 0 | ||
74 | DC67C | E9A | 21 | 89 | Charger Logo Wipe | 1 | ||
75 | DD516 | E9A | 21 | 89 | Charger Logo Wipe | 2 | ||
76 | DE3B0 | E9A | 21 | 89 | Charger Logo Wipe | 3 | ||
77 | DF24A | E9A | 21 | 89 | Charger Logo Wipe | 4 | ||
78 | E00E4 | E9A | 21 | 89 | Charger Logo Wipe | 5 | ||
79 | E0F7E | E9A | 21 | 89 | Charger Logo Wipe | 6 | ||
80 | E1E18 | E9A | 21 | 89 | Charger Logo Wipe | 7 | ||
81 | E2CB2 | E9A | 21 | 89 | Charger Logo Wipe | 8 | ||
82 | E3B4C | E9A | 21 | 89 | Charger Logo Wipe | 9 | ||
83 | E49E6 | E9A | 21 | 89 | Charger Logo Wipe | 10 | ||
84 | E5880 | E9A | 21 | 89 | Charger Logo Wipe | 11 | ||
85 | E671A | E9A | 21 | 89 | Charger Logo Wipe | 12 | ||
86 | E75B4 | E9A | 21 | 89 | Charger Logo Wipe | 13 | ||
87 | E844E | E9A | 21 | 89 | Charger Logo Wipe | 14 | ||
88 | E92E8 | E9A | 21 | 89 | Charger Logo Wipe | 15 | ||
89 | EA182 | E9A | 21 | 89 | Charger Logo Wipe | 16 | ||
90 | EB01C | E9A | 21 | 89 | Charger Logo Wipe | 17 | ||
91 | EBEB6 | E9A | 21 | 89 | Charger Logo Wipe | 18 | ||
92 | ECD50 | E9A | 21 | 89 | Charger Logo Wipe | 19 | ||
93 | EDBEA | E9A | 21 | 89 | Charger Logo Wipe | 20 | ||
94 | EEA84 | E9A | 21 | 89 | Charger Logo Wipe | 21 | ||
95 | EF91E | E9A | 21 | 89 | Charger Logo Wipe | 22 | ||
96 | F07B8 | E9A | 21 | 89 | Charger Logo Wipe | 23 | ||
97 | F1652 | E9A | 21 | 89 | Charger Logo Wipe | 24 | ||
98 | F24EC | E9A | 21 | 89 | Charger Logo Wipe | 25 | ||
99 | F3386 | E9A | 21 | 89 | Charger Logo Wipe | 26 | ||
100 | F4220 | E9A | 21 | 89 | Charger Logo Wipe | 27 | ||
101 | F50BA | E9A | 21 | 89 | Charger Logo Wipe | 28 | ||
102 | F5F54 | E9A | 21 | 89 | Charger Logo Wipe | 29 | ||
103 | F6DEE | E9A | 21 | 89 | Charger Logo Wipe | 30 | ||
104 | F8000 | 4 | N/A | N/A | Total Vape Time x0.01s (LSB->MSB) | N/A | 2 | |
105 | F8004 | 1 | N/A | N/A | Vape In Use Flag (0xBB) | N/A | 3 |
Two Python scripts have been included to aid in splitting and reassembling the Flash dump into/from the individual images stored in the SPI Flash: split-flashdump.py
and assemble-flashdump.py
. The tools currently do not perform format conversion (getting ChatGPT to help me this far was already a long process), but go a long way in aiding creation of custom "theme" packs. Unused resources can be removed from the repacked Flash dump by keeping them out of the directory containing the files to be reassembled; those unused regions will stay as 0xFF/erased bytes.
The repacker, assemble-flashdump.py
, expects the input filenames to be of a specific format, as it uses the hexadecimal-encoded offset to determine where to insert each piece into the 1MB Flash dump file (see split_map.csv or the included example theme, described below in Custom Theme Packs):
{index}_{offset}_{width}x{height}_{category}_{sequence}.bin
19_33d00_80x160_vapeanim-0.bin
To convert PNG or JPEG images, use the previously-mentioned UTFT library's ImgConv.exe
tool:
ImgConv.exe *.png /r
ImgConv.exe *.jpg /r
ren *.raw *.bin
Note: ensure the pictures to be converted into .bin format are the correct dimensions BEFORE converting them!
As a proof of concept, a finished Windows 95-style theme pack is included; it implements all resources for the battery and juice indicators, charging animation (only plugin background 3 and charger logo wipe, as that is the only used animation set with the tested firmware), and vaping animation (an aspect-ratio correct capture of the 3D Pipes screensaver). All that is needed is access to the SPI Flash and a means of reprogramming it. Room for extension of this concept could be through a cheap SWD USB dongle, connected through the USB-C port, and some software that uploads a small reprogramming tool into the microcontroller's RAM, potentially eliminating the need to desolder the Flash chip.
A blank/editable template has also been included. All frames are implemented with frame numbers for animations.
All of this customization is possible without touching the microcontroller's firmware!
As described in External Flash Memory Layout, notes 2 and 3 above, filling external Flash locations 0xF8000-0xF8004 with 0xFF will reset the juice meter to full, permitting reuse of the vape once the reservoir is refilled. The microcontroller itself then needs to be reset by pulling the nRST pin to ground, or by power cycling it by disconnecting and reconnecting the battery; this will likely have already happened if one is desoldering and resoldering the external Flash for reprogramming/patching.
The microcontroller uses the industry standard Serial Wire Debug (SWD) debug/programming interface for reading/writing its firmware and/or its internal SRAM memory. The SWD interface is exposed through the vape's USB-C charging port. The SWDIO/SWCLK lines are connected to the CC pins behind the normal 5.1k Rd pulldown resistors, as the connector is normally power-only.
The firmware on the microcontroller is not readout-protected, so further research into the firmware via decompilation is a possible avenue. It may be possible to use this debug interface to interact with the external Flash, but this has not been researched yet.
Some of the vape mainboards that were tested, had RX/TX test pads on the backside of the board. This has not yet been researched, as to how this port interacts with the firmware, and/or if it can be used to update the external Flash contents.
The vape is made up of two PCBs, joined together with a 9-pin 0.15mm-pitch right-angle male pin header:
Pin 1 is denoted by a square pad on the power board, and a corresponding pad on the logic board's underside (opposite side of the microcontroller, SPI Flash and LCD). WARNING: The pin 1 markings may be opposite of each other between the two boards!
Power Board Pin | Logic Board Pin | Name | Function |
---|---|---|---|
1 | 9 | VBAT | Battery positive (+) on power board |
2 | 8 | VBUS | +5V from USB-C port on power board with SMD fuse, "B" marking |
3 | 7 | GND | Power/signal ground |
4 | 6 | COIL_DRV | Heater control signal from MCU on logic board (active-high) |
5 | 5 | PUFF_DET | Puff detection signal from power board vape controller (note 1) |
6 | 4 | CC2/SWCLK | USB-C Rd pulldown 2 / SWD debug interface clock to MCU on logic board |
7 | 3 | CC1/SWDIO | USB-C Rd pulldown 1 / SWD debug interface data to MCU on logic board |
8 | 2 | VDD | 3V supply from LDO regulator on logic board to vape controller |
9 | 1 | COIL_DET? | Heater coil detection to MCU on logic board (see note 2) |
The N32G01 series of microcontrollers are advertised in the datasheet as having onboard Flash encryption and secure boot support, but this feature (thankfully) is not used on the vape(s) tested so far (namely the Kraze HD7K).
Not much work has gone into reverse-engineering the firmware itself, but a flash dump was able to be obtained with the use of a Segger J-Link and its corresponding J-Mem software, accessed through the SWD debug/programming port. Like many Arm-based MCUs, the Flash is located at 0x08000000 but is also mirrored at 0x00000000. A dump of the firmware was taken from addresses 0x08000000-0x0800FFFF (64k), and a cursory glance at the firmware dump shows that only approximately 50% of the Flash space was actually used (addresses from just before 0x8000 through 0xFFFF were all 0xFF bytes, indicating erased/unprogrammed memory). No human-readable strings appear to be present in the firmware dump.
A "secret" version number is displayed on-screen if the USB-C power is rapidly turned on and off (but seems to occur inconsistently). When attempted with a Kraze HD7K, the screen turns black, and the text "GV-K23 0904V1" is displayed in red across two lines of text for a couple seconds; it appears to be rendered with a monospaced version of the 12-point-size "System" font from Windows. This hints to an internal product name of "GV-K" and the firmware being revision 1, dated September 4, 2023. Coincidentally, near the end of the used Flash address space is a block of bytes filled with 0x00, and 0xE8E4, which looks suspiciously like black and red-orange pixel data. Further analysis of the raw data from this region confirms that the version number is stored as a raw bitmap and not rendered from a text string (explained below).
Inside the firmware Flash dump, at addresses 0x7066-0x7E75, appears to be a bitmap version of the aforementioned version number. It appears to be only 60x30 pixels in size, but there are 0x00 padding bytes around this bitmap that do not align to 120-byte boundaries (60 pixels), making determining the "true" image size difficult without decompiling the firmware and finding the function that triggers the version screen.
All trademarks are the property of their respective owners.