You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

381 lines
17 KiB

  1. < [Flashing guide](flashing.md) | [Index](../README.md) | [Sponsoring](sponsoring.md) >
  2. # Technical details
  3. In this section, you can find some of the information that was gathered during the reverse
  4. engineering of the Bedside Lamp 2 hardware.
  5. Table of contents:
  6. * [High level overview](#high-level-overview)
  7. * [ESP32 pinout](#esp32-pinout)
  8. * [Front panel](#front-panel)
  9. * [Build requirements](#build-requirements)
  10. * [Original firmware](#original-firmware)
  11. ## High level overview
  12. No documentation is complete without some ASCII art schematics.
  13. ```
  14. RX/TX/GND for
  15. 12V power supply flashing and logs
  16. | |
  17. v | Front panel
  18. +---------------+ +---------------+ .---.
  19. | Power supply |---- 3.3V -.----->| ESP-WROOM-32D |<- I2C ->| O | -- color
  20. +---------------+ \ | single core | | | button
  21. | \ | 4 MB flash |<- IRQ --| | |
  22. 12V \ +---------------+ | | |
  23. | `-------|------------------->| | | -- slider
  24. v | | | |
  25. +---------------+ | | | |
  26. | RGB and white |<---- RGBW + master ---+ | | power
  27. | LED circuitry | PWM on/off | O | -- button
  28. +---------------+ `---`
  29. ```
  30. The LED circuitry provides two light modes:
  31. * Colored RGB light;
  32. * Warm to cool white light.
  33. The front panel of the device contains a two touch buttons (power on/off and color selection) and a
  34. touch slider (for setting the brightness level). This panel is lit when the device is turned on. The
  35. light behind the slider will represent the actual brightness setting of the device.
  36. ## ESP32 pinout
  37. In the following image, you can find the pinout as used for the ESP32:
  38. <img src="../images/hardware/ESP32_pinout.jpg" width="600">
  39. Here's an overview of all exposed pins of the chip, starting at the GND + 3.3V pins, and going
  40. anti-clockwise. The table shows not only the functions of the pins that are actually in use by the
  41. lamp's circuitry, but also the pins that are not in use and their possible use.
  42. | PIN | GPIO# | Function | Description | Possible use |
  43. |------|--------|-----------|--------------------------------|--------------|
  44. | GND | | Ground | Connected to ground | - |
  45. | 3.3V | | Power | Power supply input | - |
  46. | 9 | | Reset | Can be pulled to GND to reset | - |
  47. | 5 | GPIO36 | - | | IN |
  48. | 8 | GPIO39 | - | | IN |
  49. | 10 | GPIO34 | - | | IN |
  50. | 11 | GPIO35 | - | | IN |
  51. | 12 | GPIO32 | - | | IN/OUT |
  52. | 13 | GPIO33 | LEDs | LEDs, master switch 1 | - |
  53. | 14 | GPIO25 | ??? | 10k pull up, unknown function | IN/OUT (1) |
  54. | 15 | GPIO26 | - | | IN/OUT |
  55. | 16 | GPIO27 | - | | IN/OUT |
  56. | 17 | GPIO14 | LEDs | LEDs, green PWM channel | - |
  57. | 18 | GPIO12 | LEDs | LEDs, white PWM channel | - |
  58. | GND | | Ground | Connected to ground | - |
  59. | 20 | GPIO13 | LEDs | LEDs, red PWM channel | - |
  60. | 28 | GPIO9 | SPI | SPI flash memory | - |
  61. | 29 | GPIO10 | SPI | SPI flash memory | - |
  62. | 30 | GPIO11 | SPI | SPI flash memory | - |
  63. | 31 | GPIO6 | SPI | SPI flash memory | - |
  64. | 32 | GPIO7 | SPI | SPI flash memory | - |
  65. | 33 | GPIO8 | SPI | SPI flash memory | - |
  66. | 21 | GPIO15 | - | | IN/OUT (2) |
  67. | 22 | GPIO2 | - | Debug pad, no function | IN/OUT (3) |
  68. | 23 | GPIO0 | Boot mode | Pull to GND for flashing mode | - |
  69. | 24 | GPIO4 | LEDs | LEDs, master switch 2 | - |
  70. | 25 | GPIO16 | Front pnl | Front panel interrupt | - |
  71. | 27 | GPIO17 | EEPROM | EEPROM I2C SDA (4) | - |
  72. | 34 | GPIO5 | LEDs | LEDs, blue PWM channel | - |
  73. | 35 | GPIO18 | EEPROM | EEPROM I2C CLK (4) | - |
  74. | 38 | GPIO19 | Front pnl | Front panel I2C SCL | - |
  75. | N/C | | | | |
  76. | 42 | GPIO21 | Front pnl | Front panel I2C SDA | - |
  77. | 40 | GPIO3 | Serial | Debug pad, RX (flashing, logs) | - |
  78. | 41 | GPIO1 | Serial | Debug pad, TX (flashing, logs) | - |
  79. | 39 | GPIO22 | - | | IN/OUT |
  80. | 36 | GPIO23 | - | | IN/OUT |
  81. | GND | | Ground | Connected to ground | - |
  82. 1. GPIO25 is connected to a 10k pull up resistor. This suggests that it might have some function in
  83. the lamp, but I have not found that function yet. If you find the actual use for this pin, or
  84. find that you can indeed repurpose it, then please let me know.
  85. 1. Beware that GPIO15 outputs a PWM signal at boot. This might make the pin less useful for your use
  86. case.
  87. 1. Often, GPIO2 is used for an on-board LED. Here, it is only connected to the debug pad. The pin is
  88. usable for I/O (I tested it), which is great because of the easy access of the debug pad. GPIO2
  89. might only be used for testing purposes in the original firmware.
  90. 1. The connected IC, using I2C address 0x10, looks a lot like an EEPROM, but this has yet to be
  91. confirmed. It uses a decicated I2C bus, separate from the I2C bus of the front panel.
  92. [This picture](../images/hardware/IC_on_I2C_GPIO1718.jpg) shows the IC.
  93. For more information on the use of pins on the ESP32 chip, please check out
  94. this [ESP32 pinout reference information](https://randomnerdtutorials.com/esp32-pinout-reference-gpios/).
  95. ## Front panel
  96. <img src="../images/hardware/front_panel.jpg" width="150">
  97. The front panel is a stand-alone component, with its own control chip (KungFu KF8TS2716).
  98. Communication between the ESP32 and the front panel is done using:
  99. - **An I2C bus**
  100. - the front panel is the I2C slave, the ESP32 is the I2C master
  101. (pardon the standard terminology, I am aware of the controversy)
  102. - the front panel device ID is 0x2C
  103. - SDA is connected to ESP32 pin GPIO21
  104. - SCL is connected to ESP32 pin GPIO19
  105. - **An interrupt data line to signal the ESP32 about new events**
  106. - this line is connected to ESP32 pin GPIO16
  107. - the default state is HIGH
  108. - line is pulled LOW for at least 6 ms when a new event is available
  109. Commands can be written to and data can be read from the front panel component using I2C. The I2C
  110. protocol is fairly simple. All read and write operations uses 6 bytes of data. No register selection
  111. is done before reading or writing.
  112. The interrupt data line is used by the front panel, to signal the ESP32 that a new button or slider
  113. event is available. Further details on this can be found below.
  114. **Connection to the main board**
  115. The front panel is connected to the main board using a flat cable. The picture below shows the
  116. connector on the main board, including the functions of the cable pins:
  117. <img src="../images/hardware/front_panel_flat_cable_connection.jpg" width="400">
  118. **Writing commands to the front panel**
  119. Commands can be written to the front panel at any time.
  120. The commands that are used by the original firmware are these:
  121. | Command | Byte sequence to send |
  122. |-----------------|-----------------------|
  123. | TURN PANEL ON | 02 03 5E 00 64 00 00 |
  124. | TURN PANEL OFF | 02 03 0C 00 64 00 00 |
  125. | SET LEVEL 1 | 02 03 5E 00 64 00 00 |
  126. | SET LEVEL 2 | 02 03 5F 00 64 00 00 |
  127. | SET LEVEL 3 | 02 03 5F 80 64 00 00 |
  128. | SET LEVEL 4 | 02 03 5F C0 64 00 00 |
  129. | SET LEVEL 5 | 02 03 5F E0 64 00 00 |
  130. | SET LEVEL 6 | 02 03 5F F0 64 00 00 |
  131. | SET LEVEL 7 | 02 03 5F F8 64 00 00 |
  132. | SET LEVEL 8 | 02 03 5F FC 64 00 00 |
  133. | SET LEVEL 9 | 02 03 5F FE 64 00 00 |
  134. | SET LEVEL 10 | 02 03 5F FF 64 00 00 |
  135. | READY FOR EVENT | 01 00 00 00 00 00 01 |
  136. *Note: The `READY FOR EVENT` command is only used when a new event is provided by the front panel.
  137. Information about this command can be found in the next section.*
  138. Further experimentation has uncovered that the LEDs of the front panel can be controlled
  139. individually. The original firmware does not use this feature, but I built support for it
  140. into the custom firmware, because it opens up some nice possibilities.
  141. How this works, is that the general format of the "set LEDs" command is: `02 03 XX XX 64 00 00`.
  142. The LEDs to enable are specified using the `XX XX` part. This is a 16 bit value, which can be
  143. constructed by bitwise OR-ing the following LED bit values:
  144. | LED to enable | Bit pattern |
  145. |---------------|-------------------|
  146. | POWER | 01001100 00000000 |
  147. | COLOR | 00011100 00000000 |
  148. | LED 1 | 00001110 00000000 |
  149. | LED 2 | 00001101 00000000 |
  150. | LED 3 | 00001100 10000000 |
  151. | LED 4 | 00001100 01000000 |
  152. | LED 5 | 00001100 00100000 |
  153. | LED 6 | 00001100 00010000 |
  154. | LED 7 | 00001100 00001000 |
  155. | LED 8 | 00001100 00000100 |
  156. | LED 9 | 00001100 00000010 |
  157. | LED 10 | 00001100 00000001 |
  158. LED 1 is the one closest to the power button.
  159. LED 10 is the one closest to the color button.
  160. **Reading events from the front panel**
  161. The types of events that can occur can be summarized as:
  162. - Touch or release the power button
  163. - Touch or release the color button
  164. - Touch or release the slider at a certain level
  165. Because the front panel is an I2C slave device, it cannot contact the ESP32 via I2C. Only an I2C
  166. master device can initiate communication. Therefore, when the front panel has a new event available,
  167. it will pull down the interrupt line for a short period of time, to signal the ESP32 about this new
  168. event.
  169. *Note that the ESP32 needs to poll the interrupt line at least at 667 Hz to be able to trustworthy
  170. detect the 6 ms signal. Unfortunately, the interrupt line does not wait for the ESP32 to respond to
  171. its signalling. The best way to handle signals from this line, is to use an actual interrupt
  172. handler.*
  173. After detecting this signal, the ESP32 must first write the "READY FOR EVENT" command (`01 00 00 00
  174. 00 00 01`) via I2C to the front panel.
  175. After the front panel has ACK'ed this command, the ESP32 can read 6 bytes, which will represent the
  176. event that occurred.
  177. Here's the mapping for the events and their corresponding byte sequences:
  178. | | Touch event | Release event |
  179. |-----------------|----------------------|----------------------|
  180. | POWER BUTTON | 04 04 01 00 01 01 03 | 04 04 01 00 01 02 04 |
  181. | COLOR BUTTON | 04 04 01 00 02 01 04 | 04 04 01 00 02 02 05 |
  182. | SLIDER LEVEL 1 | 04 04 01 00 03 16 1A | 04 04 01 00 04 16 1B |
  183. | SLIDER LEVEL 2 | 04 04 01 00 03 15 19 | 04 04 01 00 04 15 1A |
  184. | SLIDER LEVEL 3 | 04 04 01 00 03 14 18 | 04 04 01 00 04 14 19 |
  185. | SLIDER LEVEL 4 | 04 04 01 00 03 13 17 | 04 04 01 00 04 13 18 |
  186. | SLIDER LEVEL 5 | 04 04 01 00 03 12 16 | 04 04 01 00 04 12 17 |
  187. | SLIDER LEVEL 6 | 04 04 01 00 03 11 15 | 04 04 01 00 04 11 16 |
  188. | SLIDER LEVEL 7 | 04 04 01 00 03 10 14 | 04 04 01 00 04 10 15 |
  189. | SLIDER LEVEL 8 | 04 04 01 00 03 0F 13 | 04 04 01 00 04 0F 14 |
  190. | SLIDER LEVEL 9 | 04 04 01 00 03 0E 12 | 04 04 01 00 04 0E 13 |
  191. | SLIDER LEVEL 10 | 04 04 01 00 03 0D 11 | 04 04 01 00 04 0D 12 |
  192. | SLIDER LEVEL 11 | 04 04 01 00 03 0C 10 | 04 04 01 00 04 0C 11 |
  193. | SLIDER LEVEL 12 | 04 04 01 00 03 0B 0F | 04 04 01 00 04 0B 10 |
  194. | SLIDER LEVEL 13 | 04 04 01 00 03 0A 0E | 04 04 01 00 04 0A 0F |
  195. | SLIDER LEVEL 14 | 04 04 01 00 03 09 0D | 04 04 01 00 04 09 0E |
  196. | SLIDER LEVEL 15 | 04 04 01 00 03 08 0C | 04 04 01 00 04 08 0D |
  197. | SLIDER LEVEL 16 | 04 04 01 00 03 07 0B | 04 04 01 00 04 07 0C |
  198. | SLIDER LEVEL 17 | 04 04 01 00 03 06 0A | 04 04 01 00 04 06 0B |
  199. | SLIDER LEVEL 18 | 04 04 01 00 03 05 09 | 04 04 01 00 04 05 0A |
  200. | SLIDER LEVEL 19 | 04 04 01 00 03 04 08 | 04 04 01 00 04 04 09 |
  201. | SLIDER LEVEL 20 | 04 04 01 00 03 03 07 | 04 04 01 00 04 03 08 |
  202. | SLIDER LEVEL 21 | 04 04 01 00 03 02 06 | 04 04 01 00 04 02 07 |
  203. | SLIDER LEVEL 22 | 04 04 01 00 03 01 05 | 04 04 01 00 04 01 06 |
  204. **Behavior when more events come in than can be handled**
  205. The front panel does not queue events. When a new event occurs, before the previous event has be
  206. read by the ESP32, the new event will replace the old event and a new signal is sent over the
  207. interrupt line.
  208. The ESP32 can read the last event multiple times. It will not be cleared by the front panel after
  209. reading it.
  210. ## Build requirements
  211. The ESP-WROOM-32D that is used for this lamp (and for various other Xiaomi devices), contains a
  212. single core CPU, even though the data sheet for ESP-WROOM-32D specifies a dual core CPU. Therefore,
  213. when flashing the device with a generic ESP32 build, you will end up with the following boot error:
  214. ```
  215. E (459) cpu_start: Running on single core chip, but application is built with dual core support.
  216. E (459) cpu_start: Please enable CONFIG_FREERTOS_UNICORE option in menuconfig.
  217. ```
  218. Another issue with a lot of these devices, is that the MAC address that is burnt into EFUSE does not
  219. match the CRC checksum that is also burnt into EFUSE. Using a generic ESP32 build, you will end up
  220. with the boot error:
  221. ```
  222. Base MAC address from BLK0 of EFUSE CRC error
  223. ```
  224. For these reasons, you must build the firmware using a taylored version of arduino-esp32.
  225. You can make use of the version [created by @pauln](https://github.com/pauln/arduino-esp32)
  226. or the version [created by @mmakaay](https://github.com/mmakaay/arduino-esp32-unicore-no-mac-crc).
  227. To make use of one of these in an ESPHome build, you'll have to provide a platform package
  228. definition for the PlatformIO build. Here's an example configuration that will work for these Xiaomi
  229. devices:
  230. ```yaml
  231. esphome:
  232. name: my_device_name
  233. platform: ESP32
  234. board: esp32doit-devkit-v1
  235. platformio_options:
  236. platform: espressif32@3.2.0
  237. platform_packages: |-
  238. framework-arduinoespressif32 @ https://github.com/mmakaay/arduino-esp32-unicore-no-mac-crc
  239. ```
  240. If you want to build your own platform package, then you can checkout
  241. the build scripts [by @mmakaay here](https://github.com/mmakaay/arduino-esp32-unicore-no-mac-crc-builder).
  242. ## Original firmware
  243. Below, I have gathered some of the interesting boot messages from the original firmware. These
  244. messages are logged via the serial interface.
  245. **SPI Flash memory:**
  246. ```
  247. boot: SPI Flash RID : 0xB20B4
  248. boot: SPI Flash MF : 0xB4
  249. boot: SPI Flash ID : 0x200B
  250. boot: SPI Speed : 40MHz
  251. boot: SPI Mode : DIO
  252. boot: SPI Flash Size : 4MB
  253. ```
  254. **Partition table:**
  255. ```
  256. boot: Partition Table:
  257. boot: ## Label Usage Type ST Offset Length
  258. boot: 0 nvs WiFi data 01 02 00009000 00004000
  259. boot: 1 otadata OTA data 01 00 0000d000 00002000
  260. boot: 2 phy_init RF data 01 01 0000f000 00001000
  261. boot: 3 miio_fw1 OTA app 00 10 00010000 001e0000
  262. boot: 4 miio_fw2 OTA app 00 11 001f0000 001e0000
  263. boot: 5 test test app 00 20 003d0000 00013000
  264. boot: 6 mfi_p Unknown data 01 82 003e3000 00001000
  265. boot: 7 factory_nvs WiFi data 01 02 003e4000 00004000
  266. boot: 8 coredump Unknown data 01 03 003e8000 00010000
  267. boot: 9 minvs Unknown data 01 fe 003f8000 00004000
  268. boot: End of partition table
  269. ```
  270. **MIIO initialization:**
  271. ```
  272. _| _| _|_|_| _|_|_| _|_|
  273. _|_| _|_| _| _| _| _|
  274. _| _| _| _| _| _| _|
  275. _| _| _| _| _| _|
  276. _| _| _|_|_| _|_|_| _|_|
  277. 08:00:00.200 [I] did=332985470 hostname=MiBedsideLamp2-7651
  278. JENKINS BUILD NUMBER: N/A
  279. BUILD TIME: Sep 5 2019,07:12:39
  280. BUILT BY: N/A
  281. MIIO APP VER: 2.0.6_0030
  282. Setup ID: 95XJ
  283. Getting setup info from factory NVS
  284. MIIO MCU VER:
  285. MIIO DID: *********
  286. MIIO WIFI MAC: ************
  287. MIIO MODEL: yeelink.light.bslamp2
  288. ARCH TYPE: esp32,0x0000a601
  289. ARCH VER: d178b9b
  290. ```
  291. **Network initialized:**
  292. ```
  293. [20:27:05]08:00:04.180 [I] miio_net: Wifi station connected
  294. [20:27:05]Registering HomeKit web handlers
  295. [20:27:05]Announcing _hap._tcp mDNS service
  296. ```
  297. **Phoning home to the Mijia cloud:**
  298. ```
  299. ots: httpdns resolve start failed, -12 (ots_cloud_host_update,850)
  300. otu: Opened.
  301. ots: de.ots.io.mi.com resolved to 3.126.247.75.
  302. ots: ots connect 3.126.247.75::443...
  303. tls: connect to server Mijia Cloud, domain is 3.126.247.75, port is 443.
  304. tls: timeout[100]! mbedtls_ssl_handshake returned -0x6800 (d0_tls_open,369)
  305. tls: timeout[200]! mbedtls_ssl_handshake returned -0x6800 (d0_tls_open,369)
  306. tls: timeout[300]! mbedtls_ssl_handshake returned -0x6800 (d0_tls_open,369)
  307. tls: timeout[400]! mbedtls_ssl_handshake returned -0x6800 (d0_tls_open,369)
  308. ots: Connected.
  309. ```
  310. < [Flashing guide](flashing.md) | [Index](../README.md) | [Sponsoring](sponsoring.md) >