Experiments with custom firmware for E.ZICLEAN CUBE robot vacuum cleaner.
Build experimental firmware images based on stm32f1xx-hal:
$ cargo build --bins --release
Build examples based on stm32f1xx-hal:
$ cargo build --examples --release
Build examples based on stm32ral:
$ cargo build --features ral --no-default-features --examples
Write example firmware to flash using cargo-embed subcommand:
$ cargo embed --example example-hal-battery-charging flash
There 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:
$ openocd -f tools/openocd-stlink.cfg -c 'flash_img target/thumbv7m-none-eabi/release/examples/example-hal-battery-charging'
The following commands restores original e.ziclean firmware:
$ openocd -f tools/openocd-stlink.cfg -c 'factory ()'
Currently 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.
Attach to RTT channels for the running firmware example:
$ cargo embed --example example-hal-battery-charging
Attach OpenOCD to the target using ST-Link probe:
$ openocd -f tools/openocd-stlink.cfg -c 'attach ()'
Now attach to OpenOCD command console, configure RTT, check available RTT debug channels, and start OpenOCD RTT server for selected channel:
$ telnet localhost 4444
> rtt setup 0x20000000 0x2000 "SEGGER RTT"
> rtt start
rtt: Searching for control block 'SEGGER RTT'
rtt: Control block found at 0x20000000
> rtt channels
Channels: up=1, down=0
Up-channels:
0: Terminal 1024 0
Down-channels:
> rtt server start 9000 0
Listening on port 9000 for rtt connections
accepting 'rtt' connection on tcp/9000
Finally connect to OpenOCD RTT server to view RTT log stream:
$ nc localhost 9000
Default project runner is gdb. So OpenOCD gdb server can be used to run and debug firmware examples.
Attach OpenOCD to the target using ST-Link probe:
$ openocd -f tools/openocd-stlink.cfg -c 'attach ()'
Run selected firmware example. By default gdb will be used in conjunction with OpenOCD GDB server:
$ cargo run --example example-hal-battery-charging
...
Loading section .vector_table, size 0x130 lma 0x8000000
Loading section .text, size 0x9244 lma 0x8000130
Loading section .rodata, size 0x1710 lma 0x8009374
Start address 0x08007f62, load size 43652
Transfer rate: 17 KB/sec, 8730 bytes/write.
halted: PC: 0x08007f64
halted: PC: 0x08007f66
510 __pre_init();
(gdb) cont
Continuing.
...
Note that now OpenOCD command console can be opened and RTT logging can be configured.
Creation of several basic work scenarios have been automated using cargo-make subcommand:
- Start tmux debug environment with jlink:
$ cargo make debug-stlink
- Start tmux debug environment with jlink:
$ cargo make debug-jlink
- Restore original factory firmware:
$ cargo make factory
- Microcontroller STM32f101VBT6
- Accelerometer KXCJ9
- 3 operational amplifiers LM324
- Quad buffer/line driver 74HC125D
- Display driver TM1668
- One-channel touch sensor AT42QT1010
- 4-serial-cell Li-Ion rechargeable batteries controlled by S-8254A battery protection IC
- Accelerometer and display
- GPIO for SCL/SDA/INT and DIO/STB/CLK respectively
- note that devices connected to GPIO rather than to h/w I2C and SPI blocks, so GPIO bitbang is used
- IR front/bottom sensors
- GPIO to enable/disable IR LEDs
- ADC to read IR diode voltage
- Brush/pump motors
- PWM to control rotation speed
- ADC to control current consumption
- Wheel motors
- PWM to control rotation speed
- GPIO to control direction
- ADC to control current consumption
- Battery management circuit
- PWM to charge battery
- GPIO to detect battery presence
- ADC to control battery voltage and charging current
- SWD debug port
- 5 front infrared obstacle sensors
- 3 bottom infrared floor sensors
- infrared remote control: protocol and commands
- dock station infrared beacons: protocol and commands
- sensor button
- display
- beeper
- accelerometer
- 2 brush motors
- pump motor
- 2 wheel motors, their direction control and encoders
- charger connector and presence detection
- dock station connector and presence detection
- battery presence detection
- battery voltage control circuit
- battery current control circuit
- brush motors current control circuit
- pump motor current control circuit
- wheel motors current control circuit
- battery charging circuit
VDD (75) | TMS/SWD (72) | GND | TDI (77) | NTRST (90) |
---|---|---|---|---|
TX (68) | RX (69) | TDO/TRACESWO (89) | TCK/SWCLK (76) | NRST (14) |
Pin | Configuration | Mapping | Function |
---|---|---|---|
PA0 | analog input | ADC_IN0 | NC ??? |
PA1 | analog input | ADC_IN1 | battery voltage control |
PA2 | analog input | ADC_IN2 | battery charging current control |
PA3 | analog input | ADC_IN3 | NC ??? |
PA4 | analog input | ADC_IN4 | IR diode of the left-center front sensor |
PA5 | analog input | ADC_IN5 | Connected to op-amp U5 (LM324): seems to be a current control circuitry of left wheel motor |
PA6 | analog input | ADC_IN6 | IR diode of the center-center front sensor |
PA7 | analog input | ADC_IN7 | IR diode of the central floor sensor |
PA8 | floating input | ||
PA9 | floating input | J31 (TX) | |
PA10 | floating input | J31 (RX) | |
PA11 | general purpose output (50MHz) push-pull | TM1668 STB | |
PA12 | floating input | ||
PA13 | input with pull-up/pull-down | J31 (SWDIO) | |
PA14 | input with pull-up/pull-down | J31 (SWCLK) | |
PA15 | general purpose output (50MHz) push-pull | J31 (TDI) |
Pin | Configuration | Mapping | Function |
---|---|---|---|
PB0 | analog input | ADC_IN8 | IR diode of the right-right front sensor |
PB1 | analog input | ADC_IN9 | IR diode of the right floor sensor |
PB2 | general purpose output (50MHz) push-pull | KXCJ9 SDA | |
PB3 | floating input | TDO/TRACESWO pin on J31 | |
PB4 | alternate function output (50MHz) push-pull | TIM3_CH1 | pump motor: must remap AFIO/SWJ_CFG since default configuration of PB4 is NJTRST |
PB5 | alternate function output (50MHz) push-pull | TIM3_CH2 | all 3 brushes |
PB6 | alternate function output (50MHz) push-pull | TIM4_CH1 | left wheel reverse speed (TIM4/PWM via 74HC125D 2A) |
PB7 | alternate function output (50MHz) push-pull | TIM4_CH2 | left wheel forward speed (TIM4/PWM via 74HC125D 1A) |
PB8 | alternate function output (50MHz) push-pull | TIM4_CH3 | right wheel forward speed (TIM4/PWM via 74HC125D 4A) |
PB9 | alternate function output (50MHz) push-pull | TIM4_CH4 | right wheel reverse speed (TIM4/PWM via 74HC125D 3A) |
PB10 | alternate function output (50MHz) push-pull | TIM2_CH3 | PWM for battery charging |
PB11 | general purpose output (50MHz) open-drain | right wheel reverse control | |
PB12 | general purpose output (50MHz) push-pull | SPI2_NSS for U12 (non-populated) | |
PB13 | general purpose output (50MHz) push-pull | SPI2_SCK for U12 (non-populated) | |
PB14 | general purpose output (50MHz) push-pull | SPI2_MISO for U12 (non-populated) | |
PB15 | floating input | SPI2_MOSI for U12 (non-populated) |
Pin | Configuration | Mapping | Function |
---|---|---|---|
PC0 | analog input | ADC_IN10 | IR diode of the left-left front sensor |
PC1 | analog input | ADC_IN11 | IR diode of the left floor sensor |
PC2 | analog input | ADC_IN12 | Current control for brush motors |
PC3 | analog input | ADC_IN13 | Current control for air pump motor |
PC4 | analog input | ADC_IN14 | Connected to op-amp U6 (LM324): seems to be a current control circuitry of right wheel motor |
PC5 | analog input | ADC_IN15 | IR diode of the right-center front sensor |
PC6 | floating input | ||
PC7 | general purpose output (50MHz) push-pull | IR LEDs of all 5 front IR obstacle sensors | |
PC8 | general purpose output (50MHz) push-pull | TM1668 CLK | |
PC9 .. PC10 | floating input | ||
PC11 | floating input | RC IR: left diode | |
PC12 | floating input | IR diode in left motor optical incremental encoder | |
PC13 .. PC15 | floating input |
Pin | Configuration | Mapping | Function |
---|---|---|---|
PD0 | floating input | ||
PD1 | floating input | sensor button: AT42QT1010 output | |
PD2 | general purpose output (50MHz) open-drain | left wheel forward control | |
PD3 | floating input | ||
PD4 | general purpose output (50MHz) push-pull | ||
PD5 | general purpose output (50MHz) open-drain | left wheel reverse control | |
PD6 .. PD8 | floating input | ||
PD9 | general purpose output (50MHz) push-pull | IR LEDs of all 3 bottom IR floor sensors | |
PD10 | floating input | ||
PD11 | floating input | RC IR: front diode | |
PD12 | floating input | ||
PD13 | general purpose output (50MHz) open-drain | IR LEDs in optical incremental encoders for both main motors, active low | |
PD14 | general purpose output (50MHz) push-pull | TM1668 DIO | |
PD15 | floating input | RC IR: top diode |
Pin | Configuration | Mapping | Function |
---|---|---|---|
PE0 | general purpose output (50MHz) push-pull | Beeper | |
PE1 .. PE3 | floating input | NC ??? | |
PE4 | floating input | charge connector detection | |
PE5 | floating input | charge dock station detection | |
PE6 | floating input | battery presence detection | |
PE7 | general purpose output (50MHz) push-pull | KXCJ9 SCL | |
PE8 | floating input | IR diode in right motor optical incremental encoder | |
PE9 | floating input | KXCJ9 INT | |
PE10 | floating input | RC IR: right diode | |
PE11 | floating input | NC ??? | |
PE12 | general purpose output (50MHz) open-drain | Enable power for IR RC left/front/right diodes (via R22 and Q7) | |
PE13 | floating input | NC ??? | |
PE14 | general purpose output (50MHz) open-drain | right wheel forward control | |
PE15 | general purpose output (50MHz) push-pull | NC ??? |
From PCB investigation, it looks like SR-latch circuit is used for direction control to protect H-bridges for main motors.
Right motor direction is controlled by PE14 and PB11:
PE14 | PB11 | Direction |
---|---|---|
0 | 0 | stop |
1 | 0 | reverse |
0 | 1 | forward |
1 | 1 | stop |
Left motor direction is controlled by PD2 and PD5:
PD2 | PD5 | Direction |
---|---|---|
0 | 0 | stop |
1 | 0 | reverse |
0 | 1 | forward |
1 | 1 | stop |
From PCB investigation, schematics looks as follows:
From PCB investigation, schematics looks as follows:
From PCB investigation, schematics looks as follows:
Schematics: TODO
Function | GPIO | EXTI line | EXTI interrupt | Comments |
---|---|---|---|---|
KXCJ9 INT | PE9 | EXTI9 | EXTI9_5 | |
TOP IR RC diode | PD15 | EXTI15 | EXTI15_10 | |
Left IR RC diode | PC11 | EXTI11 | EXTI15_10 | Only one Px11 GPIO pin can be selected for EXTI11 line |
Front IR RC diode | PD11 | EXTI11 | EXTI15_10 | Only one Px11 GPIO pin can be selected for EXTI11 line |
Right IR RC diode | PE10 | EXTI10 | EXTI15_10 | |
Button | PD1 | EXTI1 | EXTI1 | |
Left wheel encoder | PC12 | EXTI12 | EXTI15_10 | |
Right wheel encoder | PE8 | EXTI8 | EXTI9_5 | |
Charger detect | PE4 | EXTI4 | EXTI4 | |
Dock detect | PE5 | EXTI5 | EXTI9_5 | |
Battery detect | PE6 | EXTI6 | EXTI9_5 |
Note 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.
Logic analyzer capture of IR RC Edge button demodulated signal looks as follows:
Capture in csv format is attached. 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:
Function | Name | Code | Comments |
---|---|---|---|
Button | ON/OFF | 0x1d | |
Button | SCHED | 0x4d | |
Button | TIME | 0x2d | |
Button | UP | 0x3d | |
Button | DOWN | 0x6d | |
Button | LEFT | 0x5d | |
Button | RIGHT | 0x7d | |
Button | EDGE | 0x5d | same as LEFT |
Button | DOCK | 0x1d | same as ON/OFF |
Button | SPOT | 0x6d | same as DOWN |
Button | CLEAN | 0x3d | same as UP |
If 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:
Dock station sends beacons continuously, approximately ~32 msec between consequent beacons. Here is a capture of demodulated signal:
Dock uses the same protocol similar to 1-wire as IR RC device. Beacon code depends from viewing angle:
- 5 front infrared obstacle sensors
- 3 bottom infrared floor sensors
- infrared remote control
- dock station infrared beacons: protocol and commands
- sensor button
- display
- beeper
- KXCJ9 accelerometer
- 2 brush motors
- pump motor
- 2 wheel motors, their speed and encoders
- 2 wheel motors, their encoders
- charger connector presence detection
- dock station connector presence detection
- battery presence detection
- battery voltage control circuit
- battery current control circuit
- brush motors current control circuit
- pump motor current control circuit
- wheel motors current control circuit
- battery charging circuit
TODO