{"id":15720267,"url":"https://github.com/geomatsi/e.ziclean-cube","last_synced_at":"2025-07-26T16:42:03.017Z","repository":{"id":142017012,"uuid":"168220525","full_name":"geomatsi/e.ziclean-cube","owner":"geomatsi","description":"Experiments with custom firmware for e.ziclean cube robot vacuum cleaner","archived":false,"fork":false,"pushed_at":"2021-03-28T19:06:16.000Z","size":2391,"stargazers_count":8,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-01T06:02:39.274Z","etag":null,"topics":["rust","rust-embedded","stm32","vacuum-cleaner"],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/geomatsi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-01-29T20:07:27.000Z","updated_at":"2022-12-15T09:13:41.000Z","dependencies_parsed_at":"2023-07-07T07:45:22.363Z","dependency_job_id":null,"html_url":"https://github.com/geomatsi/e.ziclean-cube","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geomatsi%2Fe.ziclean-cube","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geomatsi%2Fe.ziclean-cube/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geomatsi%2Fe.ziclean-cube/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geomatsi%2Fe.ziclean-cube/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/geomatsi","download_url":"https://codeload.github.com/geomatsi/e.ziclean-cube/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253862732,"owners_count":21975583,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["rust","rust-embedded","stm32","vacuum-cleaner"],"created_at":"2024-10-03T21:58:09.557Z","updated_at":"2025-05-13T02:47:21.877Z","avatar_url":"https://github.com/geomatsi.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Rust](https://github.com/geomatsi/e.ziclean-cube/workflows/Rust/badge.svg?branch=master)\n\n# Summary\nExperiments with custom firmware for [E.ZICLEAN CUBE](https://www.e-zicom.com/aspirateur-robot-eziclean-cube.html) robot vacuum cleaner.\n\n# Quick start guide\n## Build\n### Build firmware\nBuild experimental firmware images based on [stm32f1xx-hal](https://crates.io/crates/stm32f1xx-hal):\n```bash\n$ cargo build --bins --release\n```\n\n### Build stm32hal examples\nBuild examples based on [stm32f1xx-hal](https://crates.io/crates/stm32f1xx-hal):\n```bash\n$ cargo build --examples --release\n```\n\n### Build stm32ral examples\nBuild examples based on [stm32ral](https://crates.io/crates/stm32ral):\n```bash\n$ cargo build --features ral --no-default-features --examples\n```\n\n## Flash\n### Flash using cargo-embed\nWrite example firmware to flash using cargo-embed subcommand:\n```bash\n$ cargo embed  --example example-hal-battery-charging flash\n```\n\n### Flash using OpenOCD\nThere are two OpenOCD configuration scripts in tools directory: for ST-Link and Segger JLink. Those scripts include several pre-defined helper functions. The following command explains how to use OpenOCD to write firmware example to flash using ST-Link:\n```bash\n$ openocd -f tools/openocd-stlink.cfg -c 'flash_img target/thumbv7m-none-eabi/release/examples/example-hal-battery-charging'\n```\n\n### Restore original e.ziclean firmware\nThe following commands restores original e.ziclean firmware:\n```bash\n$ openocd -f tools/openocd-stlink.cfg -c 'factory ()'\n```\n\n## Debug\nCurrently RTT is used for logging purposes. All the logging code based on semi-hosting and ITM has been replaced by RTT. It is possible to view RTT logs using both cargo-embed and OpenOCD. Using cargo-embed is easier, but OpenOCD can do both RTT view and GDB debug at the same time.\n\n### View RTT using cargo-embed\nAttach to RTT channels for the running firmware example:\n```bash\n$ cargo embed  --example example-hal-battery-charging\n```\n\n### View RTT using OpenOCD\nAttach OpenOCD to the target using ST-Link probe:\n```bash\n$ openocd -f tools/openocd-stlink.cfg -c 'attach ()'\n```\nNow attach to OpenOCD command console, configure RTT, check available RTT debug channels, and start OpenOCD RTT server for selected channel:\n```bash\n$ telnet localhost 4444\n\u003e rtt setup 0x20000000 0x2000 \"SEGGER RTT\"\n\u003e rtt start\nrtt: Searching for control block 'SEGGER RTT'\nrtt: Control block found at 0x20000000\n\u003e rtt channels\nChannels: up=1, down=0\nUp-channels:\n0: Terminal 1024 0\nDown-channels:\n\u003e rtt server  start 9000 0\nListening on port 9000 for rtt connections\naccepting 'rtt' connection on tcp/9000\n```\nFinally connect to OpenOCD RTT server to view RTT log stream:\n```bash\n$ nc localhost 9000\n```\n\n### Debug using OpenOCD\nDefault project runner is gdb. So OpenOCD gdb server can be used to run and debug firmware examples.\n\nAttach OpenOCD to the target using ST-Link probe:\n```bash\n$ openocd -f tools/openocd-stlink.cfg -c 'attach ()'\n```\n\nRun selected firmware example. By default gdb will be used in conjunction with OpenOCD GDB server:\n```bash\n$ cargo run  --example example-hal-battery-charging\n  ...\nLoading section .vector_table, size 0x130 lma 0x8000000\nLoading section .text, size 0x9244 lma 0x8000130\nLoading section .rodata, size 0x1710 lma 0x8009374\nStart address 0x08007f62, load size 43652\nTransfer rate: 17 KB/sec, 8730 bytes/write.\nhalted: PC: 0x08007f64\nhalted: PC: 0x08007f66\n510\t    __pre_init();\n(gdb) cont\nContinuing.\n   ...\n\n```\n\nNote that now OpenOCD command console can be opened and RTT logging can be configured.\n\n## Misc tools\n### Helpers based on cargo-make\nCreation of several basic work scenarios have been automated using cargo-make subcommand:\n\n* Start tmux debug environment with jlink:\n```bash\n$ cargo make debug-stlink\n```\n* Start tmux debug environment with jlink:\n```bash\n$ cargo make debug-jlink\n```\n* Restore original factory firmware:\n```bash\n$ cargo make factory\n```\n\n# Hardware\n## Board\n![alt text](pics/board-p1.jpg)\n\n### Components\n* Microcontroller STM32f101VBT6\n* Accelerometer KXCJ9\n* 3 operational amplifiers LM324\n* Quad buffer/line driver 74HC125D\n* Display driver TM1668\n* One-channel touch sensor AT42QT1010\n* 4-serial-cell Li-Ion rechargeable batteries controlled by S-8254A battery protection IC\n\n### Hardware diagram\n![alt text](pics/hw-diagram.png)\n\n#### Notes\n* Accelerometer and display\n  * GPIO for SCL/SDA/INT and DIO/STB/CLK respectively\n  * note that devices connected to GPIO rather than to h/w I2C and SPI blocks, so GPIO bitbang is used\n* IR front/bottom sensors\n  * GPIO to enable/disable IR LEDs\n  * ADC to read IR diode voltage\n* Brush/pump motors\n  * PWM to control rotation speed\n  * ADC to control [current consumption](#current-control-for-dc-motors)\n* Wheel motors\n  * PWM to control rotation speed\n  * GPIO to control [direction](#wheel-motors-control)\n  * ADC to control current consumption\n* Battery management circuit\n  * PWM to charge battery\n  * GPIO to detect battery presence\n  * ADC to control [battery voltage](#battery-voltage-control) and [charging current](#charger-control)\n  \n### Hardware investigation status\n- [x] SWD debug port\n- [x] 5 front infrared obstacle sensors\n- [x] 3 bottom infrared floor sensors\n- [x] infrared remote control: protocol and commands\n- [x] dock station infrared beacons: protocol and commands\n- [x] sensor button\n- [x] display\n- [x] beeper\n- [x] accelerometer\n- [x] 2 brush motors\n- [x] pump motor\n- [x] 2 wheel motors, their direction control and encoders\n- [x] charger connector and presence detection\n- [x] dock station connector and presence detection\n- [x] battery presence detection\n- [x] battery voltage control circuit\n- [x] battery current control circuit\n- [x] brush motors current control circuit\n- [x] pump motor current control circuit\n- [ ] wheel motors current control circuit\n- [ ] battery charging circuit\n\n### Connector pinout\n| VDD (75) | TMS/SWD (72) | GND | TDI (77) | NTRST (90)|\n|-|-|-|-|-|\n|__TX (68)__| __RX (69)__ | __TDO/TRACESWO (89)__ | __TCK/SWCLK (76)__ | __NRST (14)__|\n\n### Runtime pin configuration\n\n#### GPIOA\n\n| Pin | Configuration | Mapping | Function |\n|-|-|-|-|\n| PA0 | analog input | ADC_IN0 | NC ??? |\n| PA1 | analog input | ADC_IN1 | battery [voltage](#battery-voltage-control) control |\n| PA2 | analog input | ADC_IN2 | battery [charging current](#charger-control) control |\n| PA3 | analog input | ADC_IN3 | NC ??? |\n| PA4 | analog input | ADC_IN4 | IR diode of the left-center front sensor |\n| PA5 | analog input | ADC_IN5 | Connected to op-amp U5 (LM324): seems to be a [current control](#current-control-for-wheel-motors) circuitry of left wheel motor|\n| PA6 | analog input | ADC_IN6 | IR diode of the center-center front sensor |\n| PA7 | analog input | ADC_IN7 | IR diode of the central floor sensor |\n| PA8 | floating input | | |\n| PA9 | floating input | | J31 (TX) |\n| PA10 | floating input | | J31 (RX) |\n| PA11 | general purpose output (50MHz) push-pull | | TM1668 STB |\n| PA12 | floating input | | |\n| PA13 | input with pull-up/pull-down | | J31 (SWDIO) |\n| PA14 | input with pull-up/pull-down | | J31 (SWCLK) |\n| PA15 | general purpose output (50MHz) push-pull | | J31 (TDI) |\n\n#### GPIOB\n\n| Pin | Configuration | Mapping | Function |\n|-|-|-|-|\n| PB0 | analog input | ADC_IN8 | IR diode of the right-right front sensor |\n| PB1 | analog input | ADC_IN9 | IR diode of the right floor sensor |\n| PB2 | general purpose output (50MHz) push-pull | | KXCJ9 SDA |\n| PB3 | floating input | | TDO/TRACESWO pin on J31 |\n| PB4 | alternate function output (50MHz) push-pull | TIM3_CH1 | pump motor: must remap AFIO/SWJ_CFG since default configuration of PB4 is NJTRST |\n| PB5 | alternate function output (50MHz) push-pull | TIM3_CH2 | all 3 brushes |\n| PB6 | alternate function output (50MHz) push-pull | TIM4_CH1 | left wheel reverse speed (TIM4/PWM via 74HC125D 2A) |\n| PB7 | alternate function output (50MHz) push-pull | TIM4_CH2 | left wheel forward speed (TIM4/PWM via 74HC125D 1A) |\n| PB8 | alternate function output (50MHz) push-pull | TIM4_CH3 | right wheel forward speed (TIM4/PWM via 74HC125D 4A) |\n| PB9 | alternate function output (50MHz) push-pull | TIM4_CH4 | right wheel reverse speed (TIM4/PWM via 74HC125D 3A) |\n| PB10 | alternate function output (50MHz) push-pull | TIM2_CH3 | PWM for [battery charging](#charger-control) |\n| PB11 | general purpose output (50MHz) open-drain | | right wheel reverse [control](#wheel-motors-control) |\n| PB12 | general purpose output (50MHz) push-pull | | SPI2_NSS for U12 (non-populated) |\n| PB13 | general purpose output (50MHz) push-pull | | SPI2_SCK for U12 (non-populated) |\n| PB14 | general purpose output (50MHz) push-pull | | SPI2_MISO for U12 (non-populated) |\n| PB15 | floating input | | SPI2_MOSI for U12 (non-populated) |\n\n#### GPIOC\n\n| Pin | Configuration | Mapping | Function |\n|-|-|-|-|\n| PC0 | analog input | ADC_IN10 | IR diode of the left-left front sensor |\n| PC1 | analog input | ADC_IN11 | IR diode of the left floor sensor |\n| PC2 | analog input | ADC_IN12 | [Current control](#current-control-for-dc-motors) for brush motors|\n| PC3 | analog input | ADC_IN13 | [Current control](#current-control-for-dc-motors) for air pump motor|\n| PC4 | analog input | ADC_IN14 | Connected to op-amp U6 (LM324): seems to be a [current control](#current-control-for-wheel-motors) circuitry of right wheel motor|\n| PC5 | analog input | ADC_IN15 | IR diode of the right-center front sensor |\n| PC6 | floating input | | |\n| PC7 | general purpose output (50MHz) push-pull | | IR LEDs of all 5 front IR obstacle sensors |\n| PC8 | general purpose output (50MHz) push-pull | | TM1668 CLK |\n| PC9 .. PC10 | floating input | | |\n| PC11 | floating input | | RC IR: left diode |\n| PC12 | floating input | | IR diode in left motor optical incremental encoder |\n| PC13 .. PC15 | floating input | | |\n\n#### GPIOD\n\n| Pin | Configuration | Mapping | Function |\n|-|-|-|-|\n| PD0 | floating input | | |\n| PD1 | floating input | | sensor button: AT42QT1010 output |\n| PD2 | general purpose output (50MHz) open-drain | | left wheel forward [control](#wheel-motors-control) |\n| PD3 | floating input | | |\n| PD4 | general purpose output (50MHz) push-pull | | |\n| PD5 | general purpose output (50MHz) open-drain | | left wheel reverse [control](#wheel-motors-control) |\n| PD6 .. PD8 | floating input | | |\n| PD9 | general purpose output (50MHz) push-pull | | IR LEDs of all 3 bottom IR floor sensors |\n| PD10 | floating input | | |\n| PD11 | floating input | | RC IR: front diode |\n| PD12 | floating input | | |\n| PD13 | general purpose output (50MHz) open-drain | | IR LEDs in optical incremental encoders for both main motors, active low |\n| PD14 | general purpose output (50MHz) push-pull | | TM1668 DIO |\n| PD15 | floating input | | RC IR: top diode |\n\n#### GPIOE\n\n| Pin | Configuration | Mapping | Function |\n|-|-|-|-|\n| PE0 | general purpose output (50MHz) push-pull | | Beeper |\n| PE1 .. PE3 | floating input | | NC ??? |\n| PE4 | floating input | | [charge connector](#charger-control) detection |\n| PE5 | floating input | | [charge dock station](#charger-control) detection |\n| PE6 | floating input | | [battery presence](#charger-control) detection |\n| PE7 | general purpose output (50MHz) push-pull | | KXCJ9 SCL |\n| PE8 | floating input | | IR diode in right motor optical incremental encoder |\n| PE9 | floating input | | KXCJ9 INT |\n| PE10 | floating input | | RC IR: right diode |\n| PE11 | floating input | | NC ??? |\n| PE12 | general purpose output (50MHz) open-drain | | Enable power for IR RC left/front/right diodes (via R22 and Q7) |\n| PE13 | floating input | | NC ??? |\n| PE14 | general purpose output (50MHz) open-drain | | right wheel forward [control](#wheel-motors-control) |\n| PE15 | general purpose output (50MHz) push-pull | | NC ??? |\n\n### [Wheel motors control](#wheel-motors-control)\nFrom PCB investigation, it looks like SR-latch circuit is used for direction control to protect H-bridges for main motors.\n\nRight motor direction is controlled by PE14 and PB11:\n\n| PE14 | PB11 | Direction |\n|-|-|-|\n|  0   |   0  |  stop |\n|  1   |   0  |  reverse |\n|  0   |   1  |  forward |\n|  1   |   1  |  stop |\n\nLeft motor direction is controlled by PD2 and PD5:\n\n| PD2  | PD5  | Direction |\n|-|-|-|\n|  0   |   0  |  stop |\n|  1   |   0  |  reverse |\n|  0   |   1  |  forward |\n|  1   |   1  |  stop |\n\n### [Current control circuit for brush/pump motors](#current-control-for-dc-motors)\nFrom PCB investigation, schematics looks as follows:\n![alt text](pics/dc-motor-current-control.jpg)\n\n### [Battery voltage control circuit](#battery-voltage-control)\nFrom PCB investigation, schematics looks as follows:\n![alt text](pics/battery-voltage.jpg)\n\n### [Battery charger circuit](#charger-control)\nFrom PCB investigation, schematics looks as follows:\n![alt text](pics/battery-charger.jpg)\n\n### [Current control for wheel motors](#current-control-for-wheel-motors)\nSchematics: TODO\n\n### Input GPIO pins and EXTI lines budget\n| Function | GPIO | EXTI line | EXTI interrupt | Comments |\n|-|-|-|-|-|\n| KXCJ9 INT | PE9 | EXTI9 | EXTI9_5 ||\n| TOP IR RC diode | PD15 | EXTI15 | EXTI15_10 ||\n| Left IR RC diode | PC11 | EXTI11 | EXTI15_10 | Only one Px11 GPIO pin can be selected for EXTI11 line |\n| Front IR RC diode | PD11 | EXTI11 | EXTI15_10 | Only one Px11 GPIO pin can be selected for EXTI11 line |\n| Right IR RC diode | PE10 | EXTI10 | EXTI15_10 | |\n| Button | PD1 | EXTI1 | EXTI1 | |\n| Left wheel encoder | PC12 | EXTI12 | EXTI15_10 | |\n| Right wheel encoder | PE8 | EXTI8 | EXTI9_5 | |\n| Charger detect | PE4 | EXTI4 | EXTI4 | |\n| Dock detect | PE5 | EXTI5 | EXTI9_5 | |\n| Battery detect | PE6 | EXTI6 | EXTI9_5 | |\n\nNote that left and front IR remote control diodes are connected to PC11 and PD11 respectively. As a result, both these GPIO lines are attached to the same EXTI11 line and only one of them can be selected as EXTI source.\n\n### IR controls\n#### Remote Control commands\nLogic analyzer capture of IR RC _Edge_ button demodulated signal looks as follows:\n![alt text](pics/ir-rc-capture.jpg)\n\nCapture in csv format is [attached](dumps/ir-rc-capture.csv). This capture does not look like any of the common IR RC protocols, e.g. NEC, RC5, RC6. In fact, it looks like 1-wire protocol w/o initial reset/response phase. Following 1-wire conventions, consider short low level pulse as '1' and long low level pulse as '0'. As a result, the following table of key codes is obtained:\n\n| Function | Name | Code | Comments |\n|-|-|-|-|\n| Button | _ON/OFF_ | 0x1d | |\n| Button | _SCHED_ | 0x4d | |\n| Button | _TIME_ | 0x2d | |\n| Button | _UP_  | 0x3d | |\n| Button | _DOWN_ | 0x6d | |\n| Button | _LEFT_ | 0x5d | |\n| Button | _RIGHT_ | 0x7d | |\n| Button | _EDGE_ | 0x5d | same as _LEFT_ |\n| Button | _DOCK_ | 0x1d | same as _ON/OFF_ |\n| Button | _SPOT_ | 0x6d | same as _DOWN_ |\n| Button | _CLEAN_ | 0x3d | same as _UP_ |\n\nIf button on IR RC device is pressed and not released, then IR RC command is sent continuously, approximately 10-12 msec between two consequent transmissions. Here is a capture of demodulated signal: \n![alt_text](pics/ir-rc-continuous-command-capture.png)\n\n#### Dock station beacons\nDock station sends beacons continuously, approximately ~32 msec between consequent beacons. Here is a capture of demodulated signal:\n![alt_text](pics/ir-rc-dock-beacons-capture.png)\n\nDock uses the same protocol similar to 1-wire  as IR RC device. Beacon code depends from viewing angle:\n![alt_text](pics/ir-rc-dock-codes.png)\n\n\n# Firmware\n## Status of firmware building blocks\n- [x] [5 front infrared obstacle sensors](examples/hal/example-hal-adc-sensors.rs)\n- [x] [3 bottom infrared floor sensors](examples/hal/example-hal-adc-sensors.rs)\n- [x] [infrared remote control](examples/hal/example-hal-ir-rc-test4.rs)\n- [x] [dock station infrared beacons: protocol and commands](examples/hal/example-hal-ir-rc-test4.rs)\n- [x] [sensor button](examples/hal/example-hal-sensor-button.rs)\n- [x] [display](examples/hal/example-hal-i2c-disp-test2.rs)\n- [x] [beeper](examples/ral/example-ral-beep.rs)\n- [x] [KXCJ9 accelerometer](examples/hal/example-hal-i2c-acc-test2.rs)\n- [x] [2 brush motors](examples/hal/example-hal-pwm-brushes.rs)\n- [x] [pump motor](examples/hal/example-hal-pwm-brushes.rs)\n- [x] [2 wheel motors, their speed and encoders](examples/hal/example-hal-pwm-wheels.rs)\n- [x] [2 wheel motors, their encoders](examples/hal/example-hal-wheel-encoders.rs)\n- [x] [charger connector presence detection](examples/hal/example-hal-pwr.rs)\n- [x] [dock station connector presence detection](examples/hal/example-hal-pwr.rs)\n- [x] [battery presence detection](examples/hal/example-hal-pwr.rs)\n- [x] [battery voltage control circuit](examples/hal/example-hal-pwr.rs)\n- [x] [battery current control circuit](examples/hal/example-hal-pwr.rs)\n- [ ] brush motors current control circuit\n- [ ] pump motor current control circuit\n- [ ] wheel motors current control circuit\n- [ ] battery charging circuit\n\n## Firmware diagram\nTODO\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgeomatsi%2Fe.ziclean-cube","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgeomatsi%2Fe.ziclean-cube","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgeomatsi%2Fe.ziclean-cube/lists"}