hardware watchdog

This commit is contained in:
Nikolay Khabarov
2017-07-23 03:10:27 +03:00
parent c09fd31457
commit 978f5f71d8
8 changed files with 126 additions and 8 deletions
+2
View File
@@ -6,6 +6,7 @@ from cnc.pulses import *
from cnc.coordinates import *
from cnc.heater import *
from cnc.enums import *
from cnc.watchdog import *
class GMachineException(Exception):
@@ -35,6 +36,7 @@ class GMachine(object):
self._heaters = dict()
self.reset()
hal.init()
self.watchdog = HardwareWatchdog()
def release(self):
""" Free all resources.
+10
View File
@@ -86,6 +86,14 @@
# """ De-initialise hal, stop any hardware.
# """
# do_something()
#
#
# def watchdog_feed():
# """ Feed hardware watchdog. This method should be called at least
# once in 15 seconds. Also, this method can do no operation in hal
# implementation and there will not be emergency stop for heaters.
# """
# do_something()
# check which module to import
@@ -121,3 +129,5 @@ if 'join' not in locals():
raise NotImplementedError("hal.join() not implemented")
if 'deinit' not in locals():
raise NotImplementedError("hal.deinit() not implemented")
if 'watchdog_feed' not in locals():
raise NotImplementedError("hal.watchdog_feed() not implemented")
+9
View File
@@ -10,6 +10,7 @@ US_IN_SECONDS = 1000000
gpio = rpgpio.GPIO()
dma = rpgpio.DMAGPIO()
pwm = rpgpio.DMAPWM()
watchdog = rpgpio.DMAWatchdog()
STEP_PIN_MASK_X = 1 << STEPPER_STEP_PIN_X
STEP_PIN_MASK_Y = 1 << STEPPER_STEP_PIN_Y
@@ -41,6 +42,7 @@ def init():
gpio.clear(EXTRUDER_HEATER_PIN)
gpio.clear(BED_HEATER_PIN)
gpio.clear(STEPPERS_ENABLE_PIN)
watchdog.start()
def spindle_control(percent):
@@ -328,3 +330,10 @@ def deinit():
gpio.clear(FAN_PIN)
gpio.clear(EXTRUDER_HEATER_PIN)
gpio.clear(BED_HEATER_PIN)
watchdog.stop()
def watchdog_feed():
""" Feed hardware watchdog.
"""
watchdog.feed()
+56 -2
View File
@@ -82,6 +82,7 @@ class GPIO(object):
# clock for delay). So, do not create two or more instances of DMAGPIO.
class DMAGPIO(DMAProto):
_DMA_CONTROL_BLOCK_SIZE = 32
_DMA_CHANNEL = 4
def __init__(self):
""" Create object which control GPIO pins via DMA(Direct Memory
@@ -93,7 +94,7 @@ class DMAGPIO(DMAProto):
otherwise memory will be unlocked and it could be overwritten by
operating system.
"""
super(DMAGPIO, self).__init__(30 * 1024 * 1024, 4)
super(DMAGPIO, self).__init__(30 * 1024 * 1024, self._DMA_CHANNEL)
self.__current_address = 0
# get helpers registers, this class uses PWM module to create precise
@@ -259,6 +260,7 @@ class DMAPWM(DMAProto):
_DMA_CONTROL_BLOCK_SIZE = 32
_DMA_DATA_OFFSET = 24
_TOTAL_NUMBER_OF_BLOCKS = 256
_DMA_CHANNEL = 14
def __init__(self):
""" Initialise PWM. PWM has 8 bit resolution and fixed frequency
@@ -273,7 +275,8 @@ class DMAPWM(DMAProto):
Cycles in info field of control blocks.
"""
super(DMAPWM, self).__init__(self._TOTAL_NUMBER_OF_BLOCKS
* self._DMA_CONTROL_BLOCK_SIZE, 14)
* self._DMA_CONTROL_BLOCK_SIZE,
self._DMA_CHANNEL)
self._clear_pins = dict()
# first control block always set pins
self.__add_control_block(0, GPIO_SET_OFFSET)
@@ -356,6 +359,57 @@ class DMAPWM(DMAProto):
assert len(self._clear_pins) == 0
class DMAWatchdog(DMAProto):
_DMA_CONTROL_BLOCK_SIZE = 32
_DMA_CHANNEL = 13
_DMA_BLOCKS = 2047
def __init__(self):
""" Initialize hardware watchdog timer.
"""
super(DMAWatchdog, self).__init__(self._DMA_CONTROL_BLOCK_SIZE
* (self._DMA_BLOCKS + 1),
self._DMA_CHANNEL)
def start(self):
""" Arm watchdog for ~15 seconds. If watchdog wasn't fed in 15 seconds,
GPIO pins 0-29 will be switched to input to prevent any output from
them.
"""
data = ()
ba = self._phys_memory.get_bus_address()
# first blocks is just a delay
for _ in range(0, self._DMA_BLOCKS):
data += (
DMA_TI_NO_WIDE_BURSTS | DMA_DEST_IGNORE | DMA_TI_WAIT_RESP
| DMA_TI_WAITS(31),
ba + 24, ba + 28, 65535,
0, ba + self._DMA_CONTROL_BLOCK_SIZE, 0, 0
)
ba += self._DMA_CONTROL_BLOCK_SIZE
# The last block writes zero(switch to input state) in GPIO's FSEL
# register in normal operating, should never be called, until watchdog
# timeout is reached.
data += (
DMA_TI_NO_WIDE_BURSTS | DMA_TI_WAIT_RESP | DMA_TI_DEST_INC,
ba + 24, PHYSICAL_GPIO_BUS + GPIO_FSEL_OFFSET, 12,
0, 0, 0, 0
)
self._phys_memory.write(0, str(len(data)) + "I", data)
super(DMAWatchdog, self)._run_dma()
def stop(self):
""" Disarm watchdog.
"""
super(DMAWatchdog, self)._stop_dma()
def feed(self):
""" Feed watchdog, restart waiting loop from the very beginning.
"""
self._dma.write_int(self._DMA_CHANNEL_ADDRESS + DMA_NEXTCONBK,
self._phys_memory.get_bus_address())
# for testing purpose
def main():
pin = 21
+2
View File
@@ -45,6 +45,7 @@ PHYSICAL_GPIO_BUS = 0x7E000000 + GPIO_REGISTER_BASE
DMA_BASE = 0x007000
DMA_CS = 0x00
DMA_CONBLK_AD = 0x04
DMA_NEXTCONBK = 0x1C
DMA_TI_NO_WIDE_BURSTS = 1 << 26
DMA_TI_SRC_INC = 1 << 8
DMA_TI_DEST_INC = 1 << 4
@@ -62,6 +63,7 @@ DMA_CS_ACTIVE = 1 << 0
DMA_TI_PER_MAP_PWM = 5
DMA_TI_PER_MAP_PCM = 2
DMA_TI_PER_MAP = (lambda x: x << 16)
DMA_TI_WAITS = (lambda x: x << 21)
DMA_TI_TXFR_LEN_YLENGTH = (lambda y: (y & 0x3fff) << 16)
DMA_TI_TXFR_LEN_XLENGTH = (lambda x: x & 0xffff)
DMA_TI_STRIDE_D_STRIDE = (lambda x: (x & 0xffff) << 16)
+6
View File
@@ -196,3 +196,9 @@ def deinit():
""" De-initialise.
"""
logging.info("hal deinit()")
def watchdog_feed():
""" Feed hardware watchdog.
"""
pass
+25
View File
@@ -0,0 +1,25 @@
import threading
import time
from cnc import hal
class HardwareWatchdog(threading.Thread):
def __init__(self):
""" Run feed loop for hardware watchdog.
"""
super(HardwareWatchdog, self).__init__()
self.setDaemon(True)
self.start()
def run(self):
while True:
hal.watchdog_feed()
time.sleep(3)
# for test purpose
if __name__ == "__main__":
hal.init()
hal.fan_control(True)
print("Fan is on, it should turn off automatically in ~15 seconds."
"\nExiting...")