accessory:power_supply_battery:m1s_ups

UPS Kit for M1S

The UPS(Uninterrupted Power Supply) device is designed specifically for the ODROID-M1S.
It is equipped with a 18650 rechargeable Li-Ion battery holder, charger control IC and a 5Volt Boost DCDC.
There is a small MCU on the board which measures the battery level and communicate with the ODROID-M1S board via USB interface.

When the AC power source is removed, the UPS keeps supplying the power to the ODROID-M1S boards with the battery.

The M1S-UPS has a USB serial port(ttyACM) to communicate with so that it can trigger the shutdown process by sending a low battery warning.
It will significantly reduce the risk of data loss by a sudden power outage.
When the AC power source becomes available again, the UPS will supply power to the ODROID-M1S again and trigger a power-on event automatically.



If you have 30~40mm PCB spacers and M3 screws, you can mount the UPS on the ODROID-M1S cases.


* The battery is not included in the product package, so you have to buy a PROTECTED 18650 Li-Ion rechargeable battery in your local market and install it.
The length of the 18650 Li-Ion battery with a built-in protection circuit is close to 68mm, which is about 3mm longer than the unprotected bare cell battery length of 65mm.


  • Since the retail market in many countries, including South Korea, does not allow the sale of unprotected lithium-ion rechargeable batteries, we designed it to use batteries that include a protection circuit.
  • For safety reasons, when purchasing batteries, please choose a reputable battery cell manufacturer if possible. As far as we know that Panasonic, LG, Samsung, and CATL are famous.


Due to the Li-Ion chemical characteristics, the battery voltage level might go higher slightly when the load is very light.

Specification

Power Input
Recommended power supply DC 4.8V ~ 5.3V with 3Amp output
Charger
Charging Time 5 ~ 9 hours
Battery Charging Current 500mA Max.
Power Ouput
DC Output Current 3A Max.
DC Output Voltage 5.2 V
Recommended Battery
Type Protected Li-Ion 18650 cylindrical cell
Capacity Any of 2300~3600 mAh
Nominal Voltage 3.7 V
Estimated ODROID-M1S running time (500mA @ 5V) About 3~4 hours with a fully charged battery



The product package contains only the UPS board and cables.
You must purchase a protection circuit included 18650 lithium-ion battery separately.


H/W Block Diagram


MCU Firmware Flow Chart

Documents

Schematic:

Datasheet CH552DS1:ch552ds1.pdf
Datasheet TC4056A:tc4056a_c84051.pdf
Datasheet TLV70245DBVR:texas-instruments-tlv70245dbvr.pdf
Datasheet TPS61088RHLR:texas-instruments-tps61088rhlr.pdf

PCB Layout(DWG):ups4m1s_rev1.0_230818_mech.zip
PCB Pattern(PNG):m1s_ups_board.zip

State indicators(LED)



Battery Level Indicator(LED)
(Charging, FULL / Discharging)
Battery Display Level LV4 LV3 LV2 LV1
LV4 (3950mV) ON / BLINK ON ON ON
LV3 (3750 mV) OFF ON / BLINK ON ON
LV2 (3650 mV) OFF OFF ON / BLINK ON
LV1 (3550 mV) OFF OFF OFF ON / BLINK
LV0 (3400 mV) OFF OFF OFF OFF
Battery Level Indicator(LED)
(M1S_UPS Power OFF state)
Battery Display Level LV4 LV3 LV2 LV1
LV4 (3950mV) BLINK BLINK BLINK BLINK
LV3 (3750 mV) OFF BLINK BLINK BLINK
LV2 (3650 mV) OFF OFF BLINK BLINK
LV1 (3550 mV) OFF OFF OFF BLINK
LV0 (3400 mV) OFF OFF OFF OFF
Charger state
Charger State Indicator(LED)
Charger State CHRG FULL
Error : Battery Remove 1 0
Charging 0 1
Full Charged 1 0
Discharging 1 1

How to connect the UPS to ODROID-M1S

14-pin cable colors are produced randomly. The 14 PIN Header (J3) of the M1S board and the 14 PIN header(J1) of the UPS board must be connected 1:1 (1 Pin → 1 Pin).

Required Ubuntu packages
root@odroid:~# apt install wget unzip
Check UPS MCU interface connection
# check ttyUSB Device
root@odroid:~# lsusb | grep 1209:c550
Bus 001 Device 062: ID 1209:c550 Generic CH55xduino

# find the ch55xduino device node
root@odroid:~# echo "ch55xduino dev node =" `find $(grep -l "PRODUCT=$(printf "%x/%x" "0x1209" "0xc550")" \
                                        /sys/bus/usb/devices/[0-9]*:*/uevent | sed 's,uevent$,,') \
                                        /dev/null -name dev -o -name dev_id  | sed 's,[^/]*$,uevent,' |
                                        xargs sed -n -e s,DEVNAME=,/dev/,p -e s,INTERFACE=,,p`

ch55xduino dev node = /dev/ttyACM0

# Request battery avr voltage (auto repeat 1 sec)
root@odroid:~# echo "@V1#" > /dev/ttyACM0
root@odroid:~# cat /dev/ttyACM0
@V3950#
@V3951#
@V3952#
^C
# disable auto repeat
root@odroid:~# echo "@V0#" > /dev/ttyACM0
Install UPS control service

service.zip

# Create folder
root@odroid:~# mkdir m1s_ups
root@odroid:~# cd m1s_ups

# Download M1S_UPS control service package
root@odroid:~/m1s_ups# wget https://wiki.odroid.com/_media/en/m1s_ups/service.zip
root@odroid:~/m1s_ups# unzip ./service.zip
root@odroid:~/m1s_ups# chmod 777 -R ./service
root@odroid:~/m1s_ups# cd service

# Grant execution permission to the UPS control script.
root@odroid:~/m1s_ups/service# chmod a+x ./check_ups.sh

# Install M1S_UPS Control service
root@odroid:~/m1s_ups/service# ./install_service.sh

service m1s_ups active -> inactive
Removed /etc/systemd/system/multi-user.target.wants/m1s_ups.service.
Created symlink /etc/systemd/system/multi-user.target.wants/m1s_ups.service → /etc/systemd/system/m1s_ups.service.
● m1s_ups.service
     Loaded: loaded (/etc/systemd/system/m1s_ups.service; enabled; vendor preset: enabled)
     Active: active (running) since Mon 2023-12-18 03:56:33 UTC; 26ms ago
    Process: 12952 ExecStartPre=/bin/sleep 1 (code=exited, status=0/SUCCESS)
   Main PID: 12953 (bash)
     CGroup: /system.slice/m1s_ups.service
             ├─12953 /bin/bash ./check_ups.sh > /dev/null 2>&1
             ├─12957 /bin/bash ./check_ups.sh > /dev/null 2>&1
             ├─12958 /bin/bash ./check_ups.sh > /dev/null 2>&1
             ├─12959 sed s,[^/]*$,uevent,
             ├─12960 /bin/bash ./check_ups.sh > /dev/null 2>&1
             ├─12961 xargs sed -n -e s,DEVNAME=,/dev/,p -e s,INTERFACE=,,p
             ├─12962 grep -l PRODUCT=1209/c550 /sys/bus/usb/devices/1-0:1.0/uevent /sys/bus/usb/devices/2-0:1.0/uevent /s>
             └─12963 sed s,uevent$,,

Dec 18 03:56:32 server systemd[1]: Starting m1s_ups.service...
Dec 18 03:56:33 server systemd[1]: Started m1s_ups.service.
Dec 18 03:56:33 server systemd[1]: /etc/systemd/system/m1s_ups.service:9: Assignment outside of section. Ignoring.
Dec 18 03:56:33 server systemd[1]: /etc/systemd/system/m1s_ups.service:11: Assignment outside of section. Ignoring.


# check ups status
root@server:~/m1s_ups/service# tail -f /var/log/syslog
Dec 18 05:10:47 server bash[7648]: ------------------------------------------------------------
Dec 18 05:10:47 server bash[7648]: Found ttyACM(CH55xduino) device. Node name = /dev/ttyACM0
Dec 18 05:10:47 server bash[7648]: ------------------------------------------------------------
Dec 18 05:10:49 server bash[7648]: ------------------------------------------------------------
Dec 18 05:10:53 server bash[7648]: Mon Dec 18 05:10:53 UTC 2023, Firmware Ver V0-6
Dec 18 05:10:53 server bash[7648]: UPS Battery Status (Discharging...)
Dec 18 05:10:53 server bash[7648]: UPS Battery Volt : 4143 mV
Dec 18 05:10:53 server bash[7648]: SYSTEM Power OFF : UPS Battery Volt is lower then 3550 mV
Dec 18 05:10:53 server bash[7648]: ------------------------------------------------------------
Dec 18 05:10:53 server bash[7648]: ------------------------------------------------------------
Dec 18 05:10:57 server bash[7648]: Mon Dec 18 05:10:57 UTC 2023, Firmware Ver V0-6
Dec 18 05:10:57 server bash[7648]: UPS Battery Status (Discharging...)
Dec 18 05:10:57 server bash[7648]: UPS Battery Volt : 4140 mV
Dec 18 05:10:57 server bash[7648]: SYSTEM Power OFF : UPS Battery Volt is lower then 3550 mV
Dec 18 05:10:57 server bash[7648]: ------------------------------------------------------------
^C

root@server:~/m1s_ups/service#
UPS control script (check_ups.sh) in service.zip file
#!/bin/bash
 
#/*---------------------------------------------------------------------------*/
#/*---------------------------------------------------------------------------*/
#
#
# Script configuration start (/root/m1s_ups/check_ups.sh)
#
#
#/*---------------------------------------------------------------------------*/
#/* Battery level definition value for UPS system */
#/*---------------------------------------------------------------------------*/
BATTERY_LEVEL_FULL="4300"
 
#/* Battery level define (1 ~ 9) */
BATTERY_LEVEL_3550mV="3550"
BATTERY_LEVEL_3600mV="3600"
BATTERY_LEVEL_3650mV="3650"
BATTERY_LEVEL_3700mV="3700"
BATTERY_LEVEL_3750mV="3750"
BATTERY_LEVEL_3800mV="3800"
BATTERY_LEVEL_3850mV="3850"
BATTERY_LEVEL_3900mV="3900"
BATTERY_LEVEL_3950mV="3950"
 
BATTERY_LEVEL_0mV="0"
 
#/*---------------------------------------------------------------------------*/
#/* Set battery level for system power off */
#/* BATERRY_LEVEL_FULL : Power off when battery discharge condition detected. */
#/* BATERRY_LEVEL_0mV  : Maintains power until the battery is fully discharged. */
#/*---------------------------------------------------------------------------*/
# CONFIG_POWEROFF_BATTERY_LEVEL=${BATTERY_LEVEL_FULL}
CONFIG_POWEROFF_BATTERY_LEVEL=${BATTERY_LEVEL_3550mV}
 
#/*---------------------------------------------------------------------------*/
#/* Set battery level for system power on */
#/* Power on when battery charge condition detected.(default) */
# BATTERY_LEVEL_0mV : Detect charging status.(default)
#/*---------------------------------------------------------------------------*/
CONFIG_POWERON_BATTERY_LEVEL=${BATTERY_LEVEL_0mV}
# CONFIG_POWERON_BATTERY_LEVEL=${BATTERY_LEVEL_3550mV}
 
#/*---------------------------------------------------------------------------*/
#/* Set watchdog reset time */
# 0     : Disable.(default)
# 1 ~ 9 : Watchdog reset time(sec) : Warnning
#
# WARNING: The watchdog reset value must be greater than the script execution time.
#
# The script takes about 4-5 seconds to run once.
#
#/*---------------------------------------------------------------------------*/
CONFIG_WATCHDOG_RESET_TIME=""
 
#/*---------------------------------------------------------------------------*/
#
#
# Script configuration end
#
#
#/*---------------------------------------------------------------------------*/
#/*---------------------------------------------------------------------------*/
 
#/*---------------------------------------------------------------------------*/
#/* Define CH55xduino ttyACM VID/PID (1209:c550) */
#/*---------------------------------------------------------------------------*/
VID_CH55xduino="1209"
PID_CH55xduino="C550"
 
#/*---------------------------------------------------------------------------*/
#/* Define tmp file */
#/*---------------------------------------------------------------------------*/
UPS_TTY_NODE=""
UPS_TTY_DATA="/tmp/ttyUPS.dat"
 
#/*---------------------------------------------------------------------------*/
#/* battery log filename (default disable) */
#/* eg) UPS_TTY_LOG="/tmp/ttyUPS.log" */
#/*---------------------------------------------------------------------------*/
UPS_TTY_LOG=""
 
#/*---------------------------------------------------------------------------*/
#/* Script start time and date */
#/*---------------------------------------------------------------------------*/
CURRENT_TIME=$(date)
 
#/*---------------------------------------------------------------------------*/
#/* UPS Command List */
#/*---------------------------------------------------------------------------*/
# Send command to read battery volt to UPS.
UPS_CMD_BATTERY_VOLT="@V0#"
 
# Send command to read battery level to UPS.
# LED 1 : BATTERY DISPLAY LEVEL 1 (3550 mV > Battery voltage)
# LED 2 : BATTERY DISPLAY LEVEL 2 (3650 mV > Battery voltage)
# LED 3 : BATTERY DISPLAY LEVEL 3 (3750 mV > Battery voltage)
# LED 4 : BATTERY DISPLAY LEVEL 4 (3900 mV > Battery voltage)
UPS_CMD_BATTERY_LEVEL="@L0#"
 
# Send command to read charger status to UPS.
UPS_CMD_CHARGER_STATUS="@C0#"
 
# Send command to ups off to UPS.
UPS_CMD_POWEROFF="@P0#"
 
# Send command to firmware version to UPS.
UPS_CMD_FIRMWARE_VER="@F0#"
 
# Send command to power on level to UPS.
# *     : Detect charging status.(default)
# 0 ~ 4 : BATTERY LEVEL
UPS_CMD_POWERON="@O0#"
 
# Send command to watchdog reset time to UPS.
# *     : Disable.(default)
# 1 ~ 9 : Watchdog reset time
UPS_CMD_WATCHDOG="@W0#"
 
#/*---------------------------------------------------------------------------*/
#/* for communication with ups */
#/*---------------------------------------------------------------------------*/
UPS_CMD_STR=""
 
#/*---------------------------------------------------------------------------*/
#/* UPS system data */
#/*---------------------------------------------------------------------------*/
UPS_BATTERY_VOLT="0"
UPS_STATUS_CHRG="0"
UPS_STATUS_FULL="0"
UPS_FIRMWARE_VER="0"
 
#/*---------------------------------------------------------------------------*/
#/*---------------------------------------------------------------------------*/
#/* Kill previously running processes(dead process). */
#/*---------------------------------------------------------------------------*/
function kill_dead_process {
	PID=""
	PID=`ps -eaf | grep ${UPS_TTY_NODE} | grep -v grep | awk '{print $2}'`
	if [ -n "$PID" ]; then
		echo "------------------------------------------------------------"
		echo "Killing $PID"
		kill -9 $PID
		echo "------------------------------------------------------------"
	fi
}
 
#/*---------------------------------------------------------------------------*/
#/* find ttyNode name : VID_CH55xduino(1209):PID_CH55xduino(c550)
#/*---------------------------------------------------------------------------*/
function find_tty_node {
	UPS_TTY_NODE=`find $(grep -l "PRODUCT=$(printf "%x/%x" "0x${VID_CH55xduino}" "0x${PID_CH55xduino}")" \
					/sys/bus/usb/devices/[0-9]*:*/uevent | sed 's,uevent$,,') \
					/dev/null -name dev -o -name dev_id  | sed 's,[^/]*$,uevent,' |
					xargs sed -n -e s,DEVNAME=,/dev/,p -e s,INTERFACE=,,p`
 
}
 
#/*---------------------------------------------------------------------------*/
#/* Send control commands to the UPS via the UPS_CMD_STR variable.
#/*---------------------------------------------------------------------------*/
function ups_cmd_send {
	# ttyACM response data wait settings.
	cat ${UPS_TTY_NODE} > ${UPS_TTY_DATA} &
	sleep 1
 
	# Get PID (cat command) to kill background process
	PID=""
	PID=$!
 
	#/* Send command string to UPS */
	echo -ne ${UPS_CMD_STR} > ${UPS_TTY_NODE}
	sleep 1
 
	#/* Update data */
	case ${UPS_CMD_STR} in
		${UPS_CMD_BATTERY_VOLT})
			# Update battery volt data.
			UPS_BATTERY_VOLT=`cut -c 3-6 < ${UPS_TTY_DATA}`
			;;
		${UPS_CMD_BATTERY_LEVEL})
			# Update charger status data.
			UPS_BATTERY_LV4=`cut -c 3 < ${UPS_TTY_DATA}`
			UPS_BATTERY_LV3=`cut -c 4 < ${UPS_TTY_DATA}`
			UPS_BATTERY_LV2=`cut -c 5 < ${UPS_TTY_DATA}`
			UPS_BATTERY_LV1=`cut -c 6 < ${UPS_TTY_DATA}`
			;;
		${UPS_CMD_CHARGER_STATUS})
			# Update charger status data.
			UPS_STATUS_CHRG=`cut -c 6 < ${UPS_TTY_DATA}`
			UPS_STATUS_FULL=`cut -c 4 < ${UPS_TTY_DATA}`
			;;
		${UPS_CMD_FIRMWARE_VER})
			# Update battery volt data.
			UPS_FIRMWARE_VER=`cut -c 3-6 < ${UPS_TTY_DATA}`
			;;
		* )
			;;
	esac
 
	# Kill background process(cat cmd)
	if [ -n "$PID" ]; then
		kill $PID
	fi
}
 
#/*---------------------------------------------------------------------------*/
# UPS system staus check.
#/*---------------------------------------------------------------------------*/
function check_ups_status {
	#/* UPS Status : Error...(Battery Removed) */
	if [ ${UPS_STATUS_CHRG} -eq "0" -a ${UPS_STATUS_FULL} -eq "0" ]; then
		echo "------------------------------------------------------------"
		echo "ERROR: Battery Removed. force power off..."
		echo "------------------------------------------------------------"
		system_poweroff
		return
	fi
 
	#/* UPS Status : Discharging... */
	if [ ${UPS_STATUS_CHRG} -eq "1" -a ${UPS_STATUS_FULL} -eq "1" ]; then
		echo "UPS Battery Status (Discharging...)"
 
		#/* UPS Battery Status : Low Battery */
		if [ ${UPS_BATTERY_VOLT} -lt ${CONFIG_POWEROFF_BATTERY_LEVEL} ]; then
			if [ ${CONFIG_POWEROFF_BATTERY_LEVEL} -eq ${BATTERY_LEVEL_FULL} ]; then
				#/* Power off after Detecting UPS battery discharge. */
				echo "------------------------------------------------------------"
				echo "Detected UPS battery discharge."
				echo "------------------------------------------------------------"
			else
				echo "------------------------------------------------------------"
				echo "UPS Battery Volt : ${UPS_BATTERY_VOLT} mV"
				echo "UPS Battery Volt is lower then ${CONFIG_POWEROFF_BATTERY_LEVEL} mV"
				echo "------------------------------------------------------------"
			fi
			system_poweroff
		fi
	else
		if [ ${UPS_STATUS_CHRG} -eq "0" ]; then
			echo "UPS Battery Status (Charging...)"
		else
			echo "UPS Battery Status (Full Charged..)"
		fi
 
	fi
 
	echo "UPS Battery Volt : ${UPS_BATTERY_VOLT} mV"
 
	if [ ${CONFIG_POWEROFF_BATTERY_LEVEL} -eq ${BATTERY_LEVEL_FULL} ]; then
		echo "SYSTEM Power OFF : Detecting UPS battery discharge."
	else
		echo "SYSTEM Power OFF : UPS Battery Volt is lower then ${CONFIG_POWEROFF_BATTERY_LEVEL} mV"
	fi
}
 
#/*---------------------------------------------------------------------------*/
# Send command to ups off to UPS.
#/*---------------------------------------------------------------------------*/
function system_poweroff {
	UPS_CMD_STR=${UPS_CMD_POWEROFF}
	ups_cmd_send
 
	echo "------------------------------------------------------------"
	echo "run poweroff command..."
	echo "------------------------------------------------------------"
	if [ -n "${UPS_TTY_LOG}" ]; then
		echo "${CURRENT_TIME}, POWEROFF" >> ${UPS_TTY_LOG}
		echo "-------------------------" >> ${UPS_TTY_LOG}
	fi
	poweroff
	exit 0
}
 
#/*---------------------------------------------------------------------------*/
#/* Set watchdog reset time */
# 0     : Disable.(default)
# 1 ~ 9 : Watchdog reset time(sec) : Warnning
#
# WARNING: The watchdog reset value must be greater than the script execution time.
#
# The script takes about 4-5 seconds to run once.
#
#/*---------------------------------------------------------------------------*/
function watchdog_reset {
	if [ ${CONFIG_WATCHDOG_RESET_TIME} -gt "9" -o ${CONFIG_WATCHDOG_RESET_TIME} -lt "0"]
	then
		echo "CONFIG_WATCHDOG_RESET_TIME=${CONFIG_WATCHDOG_RESET_TIME} value error."
		echo "WATCHDOG Disable"
		CONFIG_WATCHDOG_RESET_TIME="0"
	fi
 
	UPS_CMD_WATCHDOG="@W${CONFIG_WATCHDOG_RESET_TIME}#"
	UPS_CMD_STR=${UPS_CMD_WATCHDOG}
	ups_cmd_send
}
 
#/*---------------------------------------------------------------------------*/
#/* Set battery level for system power on */
#/* Power on when battery charge condition detected.(default) */
# 0     : Detect charging status.(default)
# 1 ~ 9 : BATTERY LEVEL
#/*---------------------------------------------------------------------------*/
function ups_poweron_setup {
	#/* Update data */
	case ${CONFIG_POWERON_BATTERY_LEVEL} in
		${BATTERY_LEVEL_3550mV})
			POWERON_BATTERY_LEVEL="1"
			;;
		${BATTERY_LEVEL_3600mV})
			POWERON_BATTERY_LEVEL="2"
			;;
		${BATTERY_LEVEL_3650mV})
			POWERON_BATTERY_LEVEL="3"
			;;
		${BATTERY_LEVEL_3700mV})
			POWERON_BATTERY_LEVEL="4"
			;;
		${BATTERY_LEVEL_3750mV})
			POWERON_BATTERY_LEVEL="5"
			;;
		${BATTERY_LEVEL_3800mV})
			POWERON_BATTERY_LEVEL="6"
			;;
		${BATTERY_LEVEL_3850mV})
			POWERON_BATTERY_LEVEL="7"
			;;
		${BATTERY_LEVEL_3900mV})
			POWERON_BATTERY_LEVEL="8"
			;;
		${BATTERY_LEVEL_3950mV})
			POWERON_BATTERY_LEVEL="9"
			;;
		* )
			POWERON_BATTERY_LEVEL="0"
			;;
	esac
 
	if [ ${POWERON_BATTERY_LEVEL} -eq "0" ]
	then
		echo "Power on when battery charge condition detected.(default)"
	fi
 
	UPS_CMD_POWERON="@O${POWERON_BATTERY_LEVEL}#"
	UPS_CMD_STR=${UPS_CMD_POWERON}
	ups_cmd_send
}
 
#/*---------------------------------------------------------------------------*/
#/* UPS node check */
#/*---------------------------------------------------------------------------*/
function check_ups_node {
	if [ -z "${UPS_TTY_NODE}" ]; then
		echo "------------------------------------------------------------"
		echo "Disconnect ups tty node (${UPS_TTY_NODE})."
		echo "------------------------------------------------------------"
		exit 1
	fi
}
 
#/*---------------------------------------------------------------------------*/
#/*---------------------------------------------------------------------------*/
#/* START Script */
#/*---------------------------------------------------------------------------*/
#/* find CH55xduino ttyACM node (1209:c550) */
#/*---------------------------------------------------------------------------*/
find_tty_node
 
#/*---------------------------------------------------------------------------*/
#/* Script exit handling when node not found. */
#/*---------------------------------------------------------------------------*/
if [ -z "${UPS_TTY_NODE}" ]; then
	echo "------------------------------------------------------------"
	echo "Can't found ttyACM(CH55xduino) device. (1209:c550)"
	echo "------------------------------------------------------------"
	exit 1
else
	echo "------------------------------------------------------------"
	echo "Found ttyACM(CH55xduino) device. Node name = ${UPS_TTY_NODE}"
	echo "------------------------------------------------------------"
fi
 
#/*---------------------------------------------------------------------------*/
#/* Log status display */
#/*---------------------------------------------------------------------------*/
if [ -n "${UPS_TTY_LOG}" ]; then
	echo "------------------------------------------------------------"
	echo "Log Enable (${UPS_TTY_LOG})"
	echo "------------------------------------------------------------"
	echo "------------------------" >> ${UPS_TTY_LOG}
	echo "${CURRENT_TIME}, POWERON" >> ${UPS_TTY_LOG}
fi
 
#/*---------------------------------------------------------------------------*/
#/* Kill previously running processes(dead process). */
#/*---------------------------------------------------------------------------*/
kill_dead_process
 
#/*---------------------------------------------------------------------------*/
#/* ttyACM Baudrate setup */
#/*---------------------------------------------------------------------------*/
stty -F ${UPS_TTY_NODE} 9600 raw -echo
 
#/*---------------------------------------------------------------------------*/
#/* Set battery level for system power on */
#/*---------------------------------------------------------------------------*/
if [ -n "${CONFIG_UPS_ON_BATTERY_LEVEL}" ]; then
	ups_poweron_setup
fi
 
#/*---------------------------------------------------------------------------*/
#/* Main Loop (The script takes about 4-5 seconds to run once.) */
#/*---------------------------------------------------------------------------*/
UPS_CMD_STR=${UPS_CMD_FIRMWARE_VER}
ups_cmd_send
 
while true
do
	echo "------------------------------------------------------------"
	# check ups node
	check_ups_node
 
	# Send command to read battery volt to UPS.
	UPS_CMD_STR=${UPS_CMD_BATTERY_VOLT}
	ups_cmd_send
 
	UPS_CMD_STR=${UPS_CMD_CHARGER_STATUS}
	ups_cmd_send
 
	#/* current date, time */
	CURRENT_TIME=$(date)
 
	#/* Display UPS Status */
	echo "${CURRENT_TIME}, Firmware Ver ${UPS_FIRMWARE_VER}"
	check_ups_status
 
	#/* Battery Log save */
	if [ -n "${UPS_TTY_LOG}" ]; then
		echo "${CURRENT_TIME}, ${UPS_BATTERY_VOLT}" >> ${UPS_TTY_LOG}
	fi
 
	#/* Watchdog control */
	if [ -n "${CONFIG_WATCHDOG_RESET_TIME}" ]; then
		watchdog_reset
	fi
 
	echo "------------------------------------------------------------"
done
 
#/*---------------------------------------------------------------------------*/
#/*---------------------------------------------------------------------------*/

How to modify the script according to your usage scenario.

Default Scenario
  • When power is supplied to the M1S_UPS, the M1S_UPS supplies power to the ODROID-M1S.
  • When a power failure occurs, the control script issues a poweroff command to ODROID-M1S and sends a power off event to M1S_UPS.
  • When M1S_UPS receives power off event from ODROID-M1S, M1S UPS enters sleep mode.
  • When the power comes back on after a power outage, the M1S_UPS wakes up from sleep mode and supplies power to the ODROID-M1S.
Scenario1
  • When the board is turned off when the battery voltage drops below battery level 2 (3650mV).

You can set the battery voltage at which the board turns off via the “CONFIG_POWEROFF_BATTERY_LEVEL=” variable in the M1S_UPS Control script.

#/*---------------------------------------------------------------------------*/
#/* Set battery level for system power off */
#/* BATERRY_LEVEL_FULL : Power off when battery discharge condition detected. */
#/*---------------------------------------------------------------------------*/
# CONFIG_POWEROFF_BATTERY_LEVEL=${BATTERY_LEVEL_FULL}
CONFIG_POWEROFF_BATTERY_LEVEL=${BATTERY_LEVEL_3650mV}
Scenario2
  • If you want the board to turn on only when the battery voltage is higher than battery level 2 (3650mV) when the power comes back on after a power outage.

You can set the battery voltage at which the board turns on via the “CONFIG_POWERON_BATTERY_LEVEL=” variable in the M1S_UPS Control script.

#/*---------------------------------------------------------------------------*/
#/* Set battery level for system power on */
#/* BATTERY_LEVEL_0mV : Power on when battery charge condition detected. */
#/*---------------------------------------------------------------------------*/
# CONFIG_POWERON_BATTERY_LEVEL=${BATTERY_LEVEL_0mV}
CONFIG_POWERON_BATTERY_LEVEL=${BATTERY_LEVEL_3650mV}
Scenario3
  • If you need to use Watchdog for system stability.

You can monitor the operation of the board via the “CONFIG_UPS_WATCHDOG_TIME=” variable in the M1S_UPS control script.

#/*---------------------------------------------------------------------------*/
#/* Set watchdog reset time */
# 0     : Disable.(default)
# 1 ~ 9 : Watchdog reset time(sec) : Warnning
#
# WARNING: The watchdog reset value must be greater than the script execution time.
#
# The script takes about 4-5 seconds to run once.
#
#/*---------------------------------------------------------------------------*/
CONFIG_UPS_WATCHDOG_TIME=""

Warning :
If the watchdog reset value is not greater than the script execution time, the system reboots.

Log enable
  • If you want to record ups battery log

The log file creation location can be set through the “UPS_TTY_LOG=” variable in the M1S_UPS control script.

#/*---------------------------------------------------------------------------*/
#/* battery log filename (default disable) */
#/* eg) UPS_TTY_LOG="/tmp/ttyUPS.log" */
#/*---------------------------------------------------------------------------*/
UPS_TTY_LOG=""

Firmware Releases

Release v0.6 : 2023-12-13 m1s_ups_fw rev 0.6

  • Problems that occurred in F/W v0.5 have been resolved. (Infinite boot-loop problem until the battery is completely discharged )
  • Added a new feature of showing the firmware version in the log

Release v0.5 : 2023-11-22 {F/W has been deleted(2023-12-12) due to serious issues. Infinite booting problem until the battery is completely discharged }

  • Fixed an issue where auto power-on would not work on power-up again if the battery was completely discharged.
  • Boot voltage setting changed from 3300mV to 3500mV to prevent malfunction (Power on/off loop occurs at boot voltage (3300 mV) and forced power off voltage (3300 mV)).

Release v0.4 : 2023-09-04 m1s_ups_fw rev 0.4

  • Fixed battery voltage condition value to force system power off.
    • 3400mV → 3300mV
  • Fixed an issue where the power would turn off after firmware update.

How to update UPS firmware

Required Ubuntu packages
root@odroid:~/m1s_ups# apt install wget unzip vim usbutils minicom
Firmware download and flash into the MCU on the UPS board
# Firmware download
root@odroid:~/m1s_ups# wget https://wiki.odroid.com/_media/en/m1s_ups/rev0.6_hex.zip
root@odroid:~/m1s_ups# unzip rev0.6_hex.zip
root@odroid:~/m1s_ups# cd rev0.6_hex
root@odroid:~/m1s_ups/rev0.6_hex# chmod 777 *
root@odroid:~/m1s_ups/rev0.6_hex# ./fw_update.sh ups_fw.ino.hex
/root/m1s_ups/rev0.6_hex/vnproch55x
------------------------------------------------------------
Stop m1s_ups service for f/w update.
------------------------------------------------------------
------------------------------------------------------------
Found ttyACM(CH55xduino) device. Node name = /dev/ttyACM0
------------------------------------------------------------
------------------------------------------------------------------
CH55x Programmer by Deqing
Updated on: 2023/04/22
------------------------------------------------------------------
usbRertySeconds 2
Load file as hex
   Loaded 12575 bytes between: 0000 to 316E
No CH55x USB Found, retry...
No CH55x USB Found, retry...
No CH55x USB Found, retry...
No CH55x USB Found, retry...
No CH55x USB Found, retry...
No CH55x USB Found, retry...
No CH55x USB Found, retry...
DeviceVersion of CH55x: 2.50 
MCU ID: 52 11
Found Device CH552
Bootloader: 2.5.0
ID: 79 2F 09 BD
XOR Mask: 6E 6E 6E 6E 6E 6E 6E C0 
Write 12655 bytes from bin file.
..................................................
Write complete!!!
Verify chip
..................................................
Verify complete!!!
------------------------------------------------------------------
************************************************************

Update Firmware Version = V0-6

************************************************************
------------------------------------------------------------
Restart m1s_ups service.
------------------------------------------------------------
root@odroid:~/m1s_ups/rev0.6_hex#

# check ups log
root@odroid:~/m1s_ups/rev0.6_hex# tail -f /var/log/syslog

Dec 13 08:21:42 server bash[1738]: ------------------------------------------------------------
Dec 13 08:21:42 server bash[1738]: Found ttyACM(CH55xduino) device. Node name = /dev/ttyACM0
Dec 13 08:21:42 server bash[1738]: ------------------------------------------------------------
Dec 13 08:21:44 server bash[1738]: ------------------------------------------------------------
Dec 13 08:21:48 server bash[1738]: Wed Dec 13 08:21:48 UTC 2023, Firmware Ver V0-6
Dec 13 08:21:48 server bash[1738]: UPS Battery Status (Charging...)
Dec 13 08:21:48 server bash[1738]: UPS Battery Volt : 3741 mV
Dec 13 08:21:48 server bash[1738]: SYSTEM Power OFF : UPS Battery Volt is lower then 3550 mV
Dec 13 08:21:48 server bash[1738]: ------------------------------------------------------------
Dec 13 08:21:48 server bash[1738]: ------------------------------------------------------------
Dec 13 08:21:53 server bash[1738]: Wed Dec 13 08:21:53 UTC 2023, Firmware Ver V0-6
Dec 13 08:21:53 server bash[1738]: UPS Battery Status (Charging...)
Dec 13 08:21:53 server bash[1738]: UPS Battery Volt : 3741 mV
Dec 13 08:21:53 server bash[1738]: SYSTEM Power OFF : UPS Battery Volt is lower then 3550 mV
Dec 13 08:21:53 server bash[1738]: ------------------------------------------------------------
Firmware update script within the firmware {release_ver}.zip file.
#!/bin/bash
 
#/*---------------------------------------------------------------------------*/
#/* Define CH55xduino ttyACM VID/PID (1209:c550) */
#/*---------------------------------------------------------------------------*/
VID_CH55xduino="1209"
PID_CH55xduino="C550"
 
# FW_UPDATE_TOOL="/bin/vnproch55x"
TOOL_PATH=`pwd`
FW_UPDATE_TOOL="${TOOL_PATH}/vnproch55x"
 
echo ${FW_UPDATE_TOOL}
UPS_TTY_NODE=""
 
#/*---------------------------------------------------------------------------*/
#/* find ttyNode name : VID_CH55xduino(1209):PID_CH55xduino(c550)
#/*---------------------------------------------------------------------------*/
function find_tty_node {
    UPS_TTY_NODE=`find $(grep -l "PRODUCT=$(printf "%x/%x" "0x${VID_CH55xduino}" "0x${PID_CH55xduino}")" \
                    /sys/bus/usb/devices/[0-9]*:*/uevent | sed 's,uevent$,,') \
                    /dev/null -name dev -o -name dev_id  | sed 's,[^/]*$,uevent,' |
                    xargs sed -n -e s,DEVNAME=,/dev/,p -e s,INTERFACE=,,p`
 
}
 
#/*---------------------------------------------------------------------------*/
#/*---------------------------------------------------------------------------*/
#/* START Script */
#/*---------------------------------------------------------------------------*/
#/*---------------------------------------------------------------------------*/
#/* update hex file check */
#/*---------------------------------------------------------------------------*/
if [ -z "$1" ]; then
    echo "------------------------------------------------------------"
    echo "Useage : ./fw_update.sh {update hex file}"
    echo "------------------------------------------------------------"
        exit 1
elif [ ! -e "$1" ]; then
    echo "------------------------------------------------------------"
    echo "File not found ($1)."
    echo "------------------------------------------------------------"
        exit 1
fi
 
#/*---------------------------------------------------------------------------*/
#/* update tool check */
#/*---------------------------------------------------------------------------*/
if [ -z "${FW_UPDATE_TOOL}" ]; then
    echo "------------------------------------------------------------"
    echo "Can't found f/w update tool. ${FW_UPDATE_TOOL}"
    echo "------------------------------------------------------------"
    exit 1
fi
 
#/*---------------------------------------------------------------------------*/
#/* find CH55xduino ttyACM node (1209:c550) */
#/*---------------------------------------------------------------------------*/
find_tty_node
 
#/*---------------------------------------------------------------------------*/
#/* Script exit handling when node not found. */
#/*---------------------------------------------------------------------------*/
if [ -z "${UPS_TTY_NODE}" ]; then
    echo "------------------------------------------------------------"
    echo "Can't found ttyACM(CH55xduino) device. (1209:c550)"
    echo "------------------------------------------------------------"
    exit 1
else
    echo "------------------------------------------------------------"
    echo "Stop m1s_ups service for f/w update."
    echo "------------------------------------------------------------"
    service m1s_ups stop
 
    echo "------------------------------------------------------------"
    echo "Found ttyACM(CH55xduino) device. Node name = ${UPS_TTY_NODE}"
    echo "------------------------------------------------------------"
    #/*---------------------------------------------------------------------------*/
    #/* ttyACM F/W update mode setup */
    #/*---------------------------------------------------------------------------*/
    stty -F ${UPS_TTY_NODE} 1200 raw -echo
 
    #/*---------------------------------------------------------------------------*/
    #/* UPS f/w update */
    #/*---------------------------------------------------------------------------*/
    ${FW_UPDATE_TOOL} -r 2 $1
fi
 
sleep 1
 
PID=""
UPS_FIRMWARE_VER=""
UPS_TTY_DATA="/tmp/ups.dat"
 
stty -F ${UPS_TTY_NODE} 9600 raw -echo
 
sleep 1
 
# ttyACM response data wait settings.
cat ${UPS_TTY_NODE} > ${UPS_TTY_DATA} &
sleep 1
 
# Get PID (cat command) to kill background process
PID=""
PID=$!
 
#/* Send command string to UPS */
echo -ne "@F0#" > ${UPS_TTY_NODE}
sleep 1
 
UPS_FIRMWARE_VER=`cut -c 3-6 < ${UPS_TTY_DATA}`
 
# Kill background process(cat cmd)
if [ -n "$PID" ]; then
    kill $PID
fi
 
echo "************************************************************"
echo ""
echo "Update Firmware Version = ${UPS_FIRMWARE_VER}"
echo ""
echo "************************************************************"
 
echo "------------------------------------------------------------"
echo "Restart m1s_ups service."
echo "------------------------------------------------------------"
systemctl restart m1s_ups
 
#/*---------------------------------------------------------------------------*/
#/*---------------------------------------------------------------------------*/

Battery discharge graph by Load (@500mA, @2A)

If your ODROID-M1S System takes 2A, the M1S_UPS can supply the power to your system around 9~10 minutes at least.(Battery level@3550mV)
It seems to be fine to shutdown the system safely.
When the battery level is below 3300mV, the ODROID-M1S will be forced shut down by the “RESET” and “PWRBTN” gpios on the m1s_ups board.

Picture of the board temperature when charging the battery.

m1s_ups_500ma_charge_temp.jpg m1s_ups_2a_charge_temp.jpg
@500mA load with battery charging. @2A load with battery charging.

Warning :
The UPS board generates a lot of heat when charging, so be careful not to touch the board.

UPS Serial Protocol

ODROID-M1S → M1S_UPS (Request)
START
(1 Byte)
CMD
(1 Byte)
DATA
(1 Byte)
END
(1 Byte)
Description
@ L 0 ~ 9 # Battery Level 1 ~ 9 : Automatically report data every (1 ~ 9) second.
* : Report once and disable automatic reporting. (default)
V Battery Voltage(Avr)
C Charger State
W Watchdog Setup 1 ~ 9 : Watchdog enable & watchdog time reset (sec)
* : Watchdog disable (default)
O Power On Battery level Set the battery level when restarting after a power outage. (default : Turns on when power input is detected.)
Cal Power On Battery Value = 3500mV + (set value) * 50mV
0 : 3400 mV (default)
1 : 3550 mV
2 : 3600 mV

9 : 3950 mV
P x Power Off Event Notify m1s_ups that poweroff command has been executed. (m1s_ups enters Power OFF state)
F x Firmware Version Request the current F/W version.
R 1 / 0 (DEBUG) RESET GPIO Control 1 : Set High, 0 : Set Low
* : Setting is ignored.
B 1 / 0 (DEBUG) PWRBT GPIO Control
X x (DEBUG) UPS Watchdog reset Stop UPS firmware for UPS Watchdog reset.
T x (DEBUG) Battery Level LED Test Execute firmware for LED test.
M1S_UPS → ODROID-M1S (Response)
START
(1 Byte)
CMD
(1 Byte)
DATA (4 Bytes) END
(1 Byte)
Description
MSB LSB
@ L 1 / 0
(LV4)
1 / 0
(LV3)
1 / 0
(LV2)
1 / 0
(LV1)
# Battery Level Battery level indicator(LED) state
V 0 ~ 9999 Battery Voltage(Avr) 1-minute moving average battery value.
C F 1 / 0 C 1 / 0 Charger State Charger state indicator(LED)
F (FULL LED State), C (CHRG LED State)
FULL = 0., CHRG = 0 : Error condition (Battery remove)
FULL = 1., CHRG = 0 : Charging
FULL = 0., CHRG = 1 : Full charged
FULL = 1., CHRG = 1 : Discharging
W 0 ~ 9999 Watchdog Setup Displays the set watchdog setting value.
O 0 ~ 9999 Power On Battery level Displays the set power-on voltage value after power outage.
P - O F F Power Off Event
F V 1 / 9 - 1 / 9 Firmware Version F/W version. (Version 0.1 = V0-1)
R 1 / 0 (DEBUG) RESET GPIO Control 1 : GPIO Status High
0 : GPIO Status Low
B 1 / 0 (DEBUG) PWRBTN GPIO Control
When a “@V0#” command is requested from ODROID-M1S to M1S_UPS through the ttyACM port,
M1S_UPS responds with a “@V3700#” command to ODROID-M1S through the ttyACM port.

How to Build the firmware source code and Download

Required Ubuntu packages
root@odroid:~/m1s_ups# apt install wget unzip git vim libusb-1.0-0-dev build-essential usbutils curl minicom
Permission for Linux

By default, Linux will not expose enough permission for Arduino to upload the code with the USB bootloader.
Copy 99-ch55xbl.rules in this repo to /etc/udev/rules.d/ and restart your computer.
Otherwise, the upload tool may not find the bootloader device.

arduino-cli install and environment setup
root@odroid:~# mkdir cli
root@odroid:~/cli# cd cli
root@odroid:~/cli# curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh
root@odroid:~/cli# cp ./bin/arduino-cli /bin/
root@odroid:~/cli# arduino-cli config init
Add the ch55xduino board package url to the arduino-cli config file
root@odroid:~/cli# vi ~/.arduino15/arduino-cli.yaml

additional_urls:
    - https://raw.githubusercontent.com/DeqingSun/ch55xduino/ch55xduino/package_ch55xduino_mcs51_index.json
Download and copy the ch55xduino board package index file to the ~/.arduino-cli directory
root@odroid:~/cli# wget https://raw.githubusercontent.com/DeqingSun/ch55xduino/ch55xduino/package_ch55xduino_mcs51_index.json
root@odroid:~/cli# cp ./package_ch55xduino_mcs51_index.json ~/.arduino15
Install the ch55xduino core and board package library
root@odroid:~/cli# arduino-cli core install arduino:avr CH55xDuino:mcs51
Download the source code file and unzip the compressed file
# download source code
root@odroid:~/m1s_ups# wget https://wiki.odroid.com/_media/en/m1s_ups/ups_fw.zip
root@odroid:~/m1s_ups# unzip ./ups_fw.zip
root@odroid:~/m1s_ups# chmod 777 -R ./ups_fw
Source code compile and firmware update
# compile only
root@odroid:~/m1s_ups# arduino-cli compile -b CH55xDuino:mcs51:ch552 ups_fw
# compile and firmware update
root@odroid:~/m1s_ups# arduino-cli compile -b CH55xDuino:mcs51:ch552 ups_fw -u -p /dev/ttyACM0
# firmware update only
root@odroid:~/m1s_ups# arduino-cli upload -b CH55xDuino:mcs51:ch552 -i ups_fw.hex -p /dev/ttyACM0
The compiled firmware hex file can be found in the /tmp/arduino/sketches/***/
  • accessory/power_supply_battery/m1s_ups.txt
  • Last modified: 2024/02/06 15:13
  • by charles.park