I'm working on a regenerative-braking project with a DC motor. My Beaglebone Black drives a small DC Motor using a TB6612FNG motor driver from Sparkfun (datasheet):
Everything runs fine except that sometimes when I'm driving the motor back and forth and I try to read an ADC channel, my program hangs (can't even Ctrl-Z) and two minutes later I get a kernel module stack trace from the kernel's dmesg
:
[ 840.290177] INFO: task drive_motor:656 blocked for more than 120 seconds.
[ 840.297231] Tainted: G O 4.1.12-bone-rt-r16 #3
[ 840.312263] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
[ 840.322102] drive_motor D c065b9b7 0 656 606 0x00000001
[ 840.328856] [<c065b9b7>] (__schedule) from [<c065bc11>] (schedule+0x35/0x90)
[ 840.340345] [<c065bc11>] (schedule) from [<bf86416f>] (am335x_tsc_se_set_once+0x8e/0xcc [ti_am335x_tscadc])
[ 840.352180] [<bf86416f>] (am335x_tsc_se_set_once [ti_am335x_tscadc]) from [<bf8873bb>] (tiadc_read_raw+0x86/0x118 [ti_am335x_adc])
[ 840.365891] [<bf8873bb>] (tiadc_read_raw [ti_am335x_adc]) from [<bf86fa4b>] (iio_read_channel_info+0x52/0x54 [industrialio])
[ 840.379287] [<bf86fa4b>] (iio_read_channel_info [industrialio]) from [<c041c3eb>] (dev_attr_show+0x13/0x34)
[ 840.391418] [<c041c3eb>] (dev_attr_show) from [<c0173907>] (sysfs_kf_seq_show+0x63/0xb0)
[ 840.401550] [<c0173907>] (sysfs_kf_seq_show) from [<c013d4c3>] (seq_read+0x157/0x300)
[ 840.411700] [<c013d4c3>] (seq_read) from [<c0124c2d>] (__vfs_read+0x19/0x88)
[ 840.420677] [<c0124c2d>] (__vfs_read) from [<c01251c1>] (vfs_read+0x55/0xf4)
[ 840.429580] [<c01251c1>] (vfs_read) from [<c01258cd>] (SyS_read+0x31/0x6c)
[ 840.438240] [<c01258cd>] (SyS_read) from [<c000e821>] (ret_fast_syscall+0x1/0x4c)
I can reproduce the problem by running a program that drives the motor at 100% duty cycle and reverses the direction every second, and reads the ADC:
set pwm to 100%
while true:
read ADC
switch direction of motor
sleep for 1 second
(My actual code is pure C and uses this C code underneath the Adafruit BBIO Python library to read the ADCs and also uses Saad Ahmad's PWM kernel module.)
The motor's coil resistance is 2.5 Ohms and I'm driving it with a 6V battery, so the stall current is 2.4A, which seems to be (somewhat) within the specs of the motor driver.
The program does not hang if I remove the call to read the ADC, and it does not hang if I disconnect the battery.
Significantly, it does not hang if I drive the motor at a low duty cycle (like 20%) instead of a high duty cycle (like 80% - 100%). This suggests that the motor currents are somehow working their way into the Beaglebone and screwing up the ADCs.
The program hangs regardless of whether I connect analog ground (AGND) to the Beaglebone's system ground (GND) (the pink line in the picture). When they are disconnected, my DMM's "max" function measures a 70mV spike between them when the motor changes direction.
As the picture shows, the battery's negative terminal is connected to "GND" on the right side of the motor driver. The program hangs in this configuration. Additionally, the program also hangs if I connect the right-hand side motor driver "GND" to its left-hand "GND". My sense is that these should remain disconnected because of the large currents through the battery.
There is a 0.1 uF capacitor across the motor terminals. My crappy LCR meter says the motor's inductance is 1 mH. I have not placed any other capacitors in the circuit.
I've enjoyed these very informative posts from Phil Frost, SunnyBoyNY and supercat.
My guess is that the sudden changes in motor direction cause current spikes to exceed the 3A limit stated in the driver datasheet, overwhelming the motor driver's ability to isolate the Beaglebone side from the motor side, and letting current leak into the Beaglebone and screw up some voltage that the ADCs depend on.
I'd really appreciate the community's thoughts on this.
- Is this a reasonable conclusion?
- Is the motor driver supposed to isolate the motor side from the Beaglebone side?
- Is there a more appropriate motor driver I should be using?