mirror of
https://github.com/sinseman44/PyCNC.git
synced 2026-07-16 08:37:09 +00:00
spindle implementation
This commit is contained in:
@@ -20,19 +20,23 @@ G0, G1, G4, G20, G21, G28, G90, G91, G92, M2, M3, M5, M30
|
|||||||
Commands can be easily added, see [gmachine.py](./cnc/gmachine.py) file.
|
Commands can be easily added, see [gmachine.py](./cnc/gmachine.py) file.
|
||||||
|
|
||||||
# Config
|
# Config
|
||||||
All config is stored in [config.py](./cnc/config.py) and contains hardware
|
All configs are stored in [config.py](./cnc/config.py) and contain hardware
|
||||||
properties, limitations and pin names for hardware control.
|
properties, limitations and pin names for hardware control.
|
||||||
Raspberry Pi implementation should be connected to A4988, DRV8825 or any other
|
Raspberry Pi implementation should be connected to A4988, DRV8825 or any other
|
||||||
stepper motor controllers with DIR and STEP pin inputs.
|
stepper motor drivers with DIR and STEP pin inputs.
|
||||||
Default config is created for Raspberry Pi 2-3 and this wiring diagram:
|
Default config is created for Raspberry Pi 2-3 and this wiring diagram:
|
||||||

|

|
||||||
So having Raspberry Pi connected this was, there is no need to configure
|
So having Raspberry Pi connected this way, there is no need to configure
|
||||||
pin map for project.
|
pin map for project.
|
||||||
_Note: spindle control is not implemented yet_
|
|
||||||
|
|
||||||
# Hardware
|
# Hardware
|
||||||
Currently, this project supports Raspberry Pi 1-3. Tested with RPI2. But there
|
Currently, this project supports Raspberry Pi 1-3. Tested with RPI2. But there
|
||||||
is a way to add new boards. See [hal.py](./cnc/hal.py) file.
|
is a way to add new boards. See [hal.py](./cnc/hal.py) file.
|
||||||
|
_Note: Current Raspberry Pi implementation uses the same resources as on board
|
||||||
|
GPU(memory). So video output will not work with this project. Use ssh
|
||||||
|
connection to board. And do not connect HDMI cable, otherwise project would not
|
||||||
|
run. Probably, increasing of GPU dedicated memory(at least to 64 MB) could solve
|
||||||
|
it and allow to work project and GPU together, but it was never tested._
|
||||||
|
|
||||||
# Usage
|
# Usage
|
||||||
Just clone this repo and run `./pycnc` from repo root. It will start in
|
Just clone this repo and run `./pycnc` from repo root. It will start in
|
||||||
|
|||||||
+3
-1
@@ -34,8 +34,9 @@ class GMachine(object):
|
|||||||
def release(self):
|
def release(self):
|
||||||
""" Return machine to original position and free all resources.
|
""" Return machine to original position and free all resources.
|
||||||
"""
|
"""
|
||||||
|
self._spindle(0)
|
||||||
self.home()
|
self.home()
|
||||||
hal.join()
|
hal.deinit()
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
""" Reinitialize all program configurable thing.
|
""" Reinitialize all program configurable thing.
|
||||||
@@ -48,6 +49,7 @@ class GMachine(object):
|
|||||||
self._absoluteCoordinates = True
|
self._absoluteCoordinates = True
|
||||||
|
|
||||||
def _spindle(self, spindle_speed):
|
def _spindle(self, spindle_speed):
|
||||||
|
hal.join()
|
||||||
hal.spindle_control(100.0 * spindle_speed / SPINDLE_MAX_RPM)
|
hal.spindle_control(100.0 * spindle_speed / SPINDLE_MAX_RPM)
|
||||||
|
|
||||||
def _move(self, delta, velocity):
|
def _move(self, delta, velocity):
|
||||||
|
|||||||
@@ -29,6 +29,11 @@
|
|||||||
# """ Wait till motors work.
|
# """ Wait till motors work.
|
||||||
# """
|
# """
|
||||||
# do_something()
|
# do_something()
|
||||||
|
#
|
||||||
|
# def deinit():
|
||||||
|
# """ De-initialise hal, stop any hardware.
|
||||||
|
# """
|
||||||
|
# do_something()
|
||||||
|
|
||||||
|
|
||||||
# check which module to import
|
# check which module to import
|
||||||
@@ -48,4 +53,6 @@ if 'move_linear' not in locals():
|
|||||||
raise NotImplementedError("hal.move_linear() not implemented")
|
raise NotImplementedError("hal.move_linear() not implemented")
|
||||||
if 'join' not in locals():
|
if 'join' not in locals():
|
||||||
raise NotImplementedError("hal.join() not implemented")
|
raise NotImplementedError("hal.join() not implemented")
|
||||||
|
if 'deinit' not in locals():
|
||||||
|
raise NotImplementedError("hal.deinit() not implemented")
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ US_IN_SECONDS = 1000000
|
|||||||
|
|
||||||
gpio = rpgpio.GPIO()
|
gpio = rpgpio.GPIO()
|
||||||
dma = rpgpio.DMAGPIO()
|
dma = rpgpio.DMAGPIO()
|
||||||
|
pwm = rpgpio.DMAPWM()
|
||||||
|
|
||||||
STEP_PIN_MASK_X = 1 << STEPPER_STEP_PIN_X
|
STEP_PIN_MASK_X = 1 << STEPPER_STEP_PIN_X
|
||||||
STEP_PIN_MASK_Y = 1 << STEPPER_STEP_PIN_Y
|
STEP_PIN_MASK_Y = 1 << STEPPER_STEP_PIN_Y
|
||||||
@@ -40,6 +41,8 @@ def init():
|
|||||||
gpio.init(ENDSTOP_PIN_X, rpgpio.GPIO.MODE_INPUT_PULLUP)
|
gpio.init(ENDSTOP_PIN_X, rpgpio.GPIO.MODE_INPUT_PULLUP)
|
||||||
gpio.init(ENDSTOP_PIN_X, rpgpio.GPIO.MODE_INPUT_PULLUP)
|
gpio.init(ENDSTOP_PIN_X, rpgpio.GPIO.MODE_INPUT_PULLUP)
|
||||||
gpio.init(ENDSTOP_PIN_X, rpgpio.GPIO.MODE_INPUT_PULLUP)
|
gpio.init(ENDSTOP_PIN_X, rpgpio.GPIO.MODE_INPUT_PULLUP)
|
||||||
|
gpio.init(SPINDLE_PWM_PIN, rpgpio.GPIO.MODE_OUTPUT)
|
||||||
|
gpio.clear(SPINDLE_PWM_PIN)
|
||||||
|
|
||||||
# calibration
|
# calibration
|
||||||
gpio.set(STEPPER_DIR_PIN_X)
|
gpio.set(STEPPER_DIR_PIN_X)
|
||||||
@@ -71,10 +74,13 @@ def init():
|
|||||||
|
|
||||||
def spindle_control(percent):
|
def spindle_control(percent):
|
||||||
""" Spindle control implementation.
|
""" Spindle control implementation.
|
||||||
:param percent: Spindle speed in percent.
|
:param percent: Spindle speed in percent. If 0, stop the spindle.
|
||||||
"""
|
"""
|
||||||
# TODO spindle control.
|
logging.info("spindle control: {}%".format(percent))
|
||||||
logging.info("TODO spindle control: {}%".format(percent))
|
if percent > 0:
|
||||||
|
pwm.add_pin(SPINDLE_PWM_PIN, percent)
|
||||||
|
else:
|
||||||
|
pwm.remove_pin(SPINDLE_PWM_PIN)
|
||||||
|
|
||||||
|
|
||||||
def move_linear(delta, velocity):
|
def move_linear(delta, velocity):
|
||||||
@@ -147,6 +153,14 @@ def move_linear(delta, velocity):
|
|||||||
def join():
|
def join():
|
||||||
""" Wait till motors work.
|
""" Wait till motors work.
|
||||||
"""
|
"""
|
||||||
|
logging.info("hal join()")
|
||||||
# wait till dma works
|
# wait till dma works
|
||||||
while dma.is_active():
|
while dma.is_active():
|
||||||
time.sleep(0.01)
|
time.sleep(0.01)
|
||||||
|
|
||||||
|
|
||||||
|
def deinit():
|
||||||
|
""" De-initialize hardware.
|
||||||
|
"""
|
||||||
|
join()
|
||||||
|
pwm.remove_all()
|
||||||
|
|||||||
+127
-39
@@ -78,10 +78,12 @@ class GPIO(object):
|
|||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
class DMAGPIO(object):
|
# When DMAGPIO is an active with two channels simultaneously, delay time shifts
|
||||||
|
# a little bit, because all DMA channels query the same PWM(which is used as
|
||||||
|
# clock for delay). So, do not create two or more instances of DMAGPIO.
|
||||||
|
class DMAGPIO(DMAProto):
|
||||||
_DMA_CONTROL_BLOCK_SIZE = 32
|
_DMA_CONTROL_BLOCK_SIZE = 32
|
||||||
_DMA_CHANNEL = 5
|
_DMA_CHANNEL = 5
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
""" Create object which control GPIO pins via DMA(Direct Memory
|
""" Create object which control GPIO pins via DMA(Direct Memory
|
||||||
Access).
|
Access).
|
||||||
@@ -92,12 +94,11 @@ class DMAGPIO(object):
|
|||||||
otherwise memory will be unlocked and it could be overwritten by
|
otherwise memory will be unlocked and it could be overwritten by
|
||||||
operating system.
|
operating system.
|
||||||
"""
|
"""
|
||||||
# allocate buffer for control blocks, always 32 MB
|
super(DMAGPIO, self).__init__(31 * 1024 * 1024)
|
||||||
self._physmem = CMAPhysicalMemory(32 * 1024 * 1024)
|
|
||||||
self.__current_address = 0
|
self.__current_address = 0
|
||||||
|
|
||||||
# prepare dma registers memory map
|
# get helpers registers, this class uses PWM module to create precise
|
||||||
self._dma = PhysicalMemory(PERI_BASE + DMA_BASE)
|
# delays
|
||||||
self._pwm = PhysicalMemory(PERI_BASE + PWM_BASE)
|
self._pwm = PhysicalMemory(PERI_BASE + PWM_BASE)
|
||||||
self._clock = PhysicalMemory(PERI_BASE + CM_BASE)
|
self._clock = PhysicalMemory(PERI_BASE + CM_BASE)
|
||||||
|
|
||||||
@@ -119,7 +120,10 @@ class DMAGPIO(object):
|
|||||||
|
|
||||||
def add_pulse(self, pins_mask, length_us):
|
def add_pulse(self, pins_mask, length_us):
|
||||||
""" Add single pulse at the current position.
|
""" Add single pulse at the current position.
|
||||||
:param pins_mask: bitwise mask of GPIO pins to trigger. Only for first 32 pins.
|
Note: GPIO pins are not initialized in this method and should be
|
||||||
|
initialized in advance before running.
|
||||||
|
:param pins_mask: bitwise mask of GPIO pins to trigger. Only for
|
||||||
|
first 32 pins.
|
||||||
:param length_us: length in us.
|
:param length_us: length in us.
|
||||||
"""
|
"""
|
||||||
next_cb = self.__current_address + 3 * self._DMA_CONTROL_BLOCK_SIZE
|
next_cb = self.__current_address + 3 * self._DMA_CONTROL_BLOCK_SIZE
|
||||||
@@ -187,16 +191,7 @@ class DMAGPIO(object):
|
|||||||
| PWM_DMAC_PANIC(15) | PWM_DMAC_DREQ(15))
|
| PWM_DMAC_PANIC(15) | PWM_DMAC_DREQ(15))
|
||||||
self._pwm.write_int(PWM_CTL, PWM_CTL_CLRF)
|
self._pwm.write_int(PWM_CTL, PWM_CTL_CLRF)
|
||||||
self._pwm.write_int(PWM_CTL, PWM_CTL_USEF1 | PWM_CTL_PWEN1)
|
self._pwm.write_int(PWM_CTL, PWM_CTL_USEF1 | PWM_CTL_PWEN1)
|
||||||
# configure DMA
|
super(DMAGPIO, self)._run_dma()
|
||||||
addr = 0x100 * self._DMA_CHANNEL
|
|
||||||
cs = self._dma.read_int(addr)
|
|
||||||
cs |= DMA_CS_END
|
|
||||||
self._dma.write_int(addr, cs)
|
|
||||||
self._dma.write_int(addr + 4, self._physmem.get_bus_address())
|
|
||||||
cs = DMA_CS_PRIORITY(7) | DMA_CS_PANIC_PRIORITY(7) | DMA_CS_DISDEBUG
|
|
||||||
self._dma.write_int(addr, cs)
|
|
||||||
cs |= DMA_CS_ACTIVE
|
|
||||||
self._dma.write_int(addr, cs)
|
|
||||||
|
|
||||||
def run(self, loop=False):
|
def run(self, loop=False):
|
||||||
""" Run DMA module and start sending specified pulses.
|
""" Run DMA module and start sending specified pulses.
|
||||||
@@ -217,32 +212,115 @@ class DMAGPIO(object):
|
|||||||
""" Stop any DMA activities.
|
""" Stop any DMA activities.
|
||||||
"""
|
"""
|
||||||
self._pwm.write_int(PWM_CTL, 0)
|
self._pwm.write_int(PWM_CTL, 0)
|
||||||
addr = 0x100 * self._DMA_CHANNEL
|
super(DMAGPIO, self)._stop_dma()
|
||||||
cs = self._dma.read_int(addr)
|
|
||||||
cs |= DMA_CS_ABORT
|
|
||||||
self._dma.write_int(addr, cs)
|
|
||||||
cs &= ~DMA_CS_ACTIVE
|
|
||||||
self._dma.write_int(addr, cs)
|
|
||||||
cs |= DMA_CS_RESET
|
|
||||||
self._dma.write_int(addr, cs)
|
|
||||||
|
|
||||||
def is_active(self):
|
|
||||||
""" Check if DMA is working. Method can check if single sent sequence
|
|
||||||
still active.
|
|
||||||
:return: boolean value
|
|
||||||
"""
|
|
||||||
addr = 0x100 * self._DMA_CHANNEL
|
|
||||||
cs = self._dma.read_int(addr)
|
|
||||||
if cs & DMA_CS_ACTIVE == DMA_CS_ACTIVE:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
""" Remove any specified pulses.
|
""" Remove any specified pulses. Doesn't affect currently running
|
||||||
|
sequence.
|
||||||
"""
|
"""
|
||||||
self.__current_address = 0
|
self.__current_address = 0
|
||||||
|
|
||||||
|
|
||||||
|
class DMAPWM(DMAProto):
|
||||||
|
_DMA_CHANNEL = 14
|
||||||
|
_DMA_CONTROL_BLOCK_SIZE = 32
|
||||||
|
_DMA_DATA_OFFSET = 24
|
||||||
|
_TOTAL_NUMBER_OF_BLOCKS = 256
|
||||||
|
def __init__(self):
|
||||||
|
""" Initialise PWM. PWM has 8 bit resolution and fixed frequency
|
||||||
|
(~11.5 KHz and may flow). Though duty cycle is quite precise and
|
||||||
|
it uses the minimum amount of system resources (just one lite DMA
|
||||||
|
channel without any anything else).
|
||||||
|
That's why such PWM is best to use with collector motors, heaters
|
||||||
|
and other non sensitive hardware.
|
||||||
|
Implementation is super simple and uses lite DMA channel.
|
||||||
|
Overall frequency depends on number of blocks.
|
||||||
|
To adjust frequency, just write more byte per operation, use Wait
|
||||||
|
Cycles in info field of control blocks.
|
||||||
|
"""
|
||||||
|
super(DMAPWM, self).__init__(self._TOTAL_NUMBER_OF_BLOCKS
|
||||||
|
* self._DMA_CONTROL_BLOCK_SIZE)
|
||||||
|
self._clear_pins = dict()
|
||||||
|
# first control block always set pins
|
||||||
|
self.__add_control_block(0, GPIO_SET_OFFSET)
|
||||||
|
# fill control blocks
|
||||||
|
for i in range(1, self._TOTAL_NUMBER_OF_BLOCKS):
|
||||||
|
self.__add_control_block(i * self._DMA_CONTROL_BLOCK_SIZE,
|
||||||
|
GPIO_CLEAR_OFFSET)
|
||||||
|
# loop
|
||||||
|
self._physmem.write_int((self._TOTAL_NUMBER_OF_BLOCKS - 1)
|
||||||
|
* self._DMA_CONTROL_BLOCK_SIZE + 20,
|
||||||
|
self._physmem.get_bus_address())
|
||||||
|
self._gpio = PhysicalMemory(PERI_BASE + GPIO_REGISTER_BASE)
|
||||||
|
|
||||||
|
def __add_control_block(self, address, offset):
|
||||||
|
ba = self._physmem.get_bus_address() + address
|
||||||
|
data = (
|
||||||
|
DMA_TI_NO_WIDE_BURSTS | DMA_TI_WAIT_RESP
|
||||||
|
| DMA_TI_DEST_INC | DMA_TI_SRC_INC, # info
|
||||||
|
ba + self._DMA_DATA_OFFSET, # source, last 8 bytes are padding, use it to store data
|
||||||
|
PHYSICAL_GPIO_BUS + offset, # destination
|
||||||
|
4, # length
|
||||||
|
0, # stride
|
||||||
|
ba + self._DMA_CONTROL_BLOCK_SIZE, # next control block
|
||||||
|
0, # padding, uses as data storage
|
||||||
|
0 # padding
|
||||||
|
)
|
||||||
|
self._physmem.write(address, data)
|
||||||
|
|
||||||
|
def add_pin(self, pin, duty_cycle):
|
||||||
|
""" Add pin to PMW with specified duty cycle.
|
||||||
|
:param pin: pin number to add.
|
||||||
|
:param duty_cycle: duty cycle 0..100 which represent percents.
|
||||||
|
"""
|
||||||
|
assert 0 <= duty_cycle <= 100
|
||||||
|
self.remove_pin(pin)
|
||||||
|
block_number = int(duty_cycle * self._TOTAL_NUMBER_OF_BLOCKS
|
||||||
|
/ 100.0)
|
||||||
|
if block_number == 0:
|
||||||
|
self._gpio.write_int(GPIO_CLEAR_OFFSET, 1 << pin)
|
||||||
|
elif block_number == self._TOTAL_NUMBER_OF_BLOCKS:
|
||||||
|
self._gpio.write_int(GPIO_SET_OFFSET, 1 << pin)
|
||||||
|
self._clear_pins[pin] = self._DMA_DATA_OFFSET
|
||||||
|
else:
|
||||||
|
value = self._physmem.read_int(self._DMA_DATA_OFFSET)
|
||||||
|
value |= 1 << pin
|
||||||
|
self._physmem.write_int(self._DMA_DATA_OFFSET, value)
|
||||||
|
clear_address = block_number * self._DMA_CONTROL_BLOCK_SIZE \
|
||||||
|
+ self._DMA_DATA_OFFSET
|
||||||
|
value = self._physmem.read_int(clear_address)
|
||||||
|
value |= 1 << pin
|
||||||
|
self._physmem.write_int(clear_address, value)
|
||||||
|
self._clear_pins[pin] = clear_address
|
||||||
|
if not self.is_active():
|
||||||
|
super(DMAPWM, self)._run_dma()
|
||||||
|
|
||||||
|
def remove_pin(self, pin):
|
||||||
|
""" Remove pin from PWM
|
||||||
|
:param pin: pin number to remove.
|
||||||
|
"""
|
||||||
|
assert 0 <= pin < 32
|
||||||
|
if pin in self._clear_pins.keys():
|
||||||
|
address = self._clear_pins[pin]
|
||||||
|
value = self._physmem.read_int(address)
|
||||||
|
value &= ~(1 << pin)
|
||||||
|
self._physmem.write_int(address, value)
|
||||||
|
value = self._physmem.read_int(self._DMA_DATA_OFFSET)
|
||||||
|
value &= ~(1 << pin)
|
||||||
|
self._physmem.write_int(self._DMA_DATA_OFFSET, value)
|
||||||
|
del self._clear_pins[pin]
|
||||||
|
self._gpio.write_int(GPIO_CLEAR_OFFSET, 1 << pin)
|
||||||
|
if len(self._clear_pins) == 0 and self.is_active():
|
||||||
|
super(DMAPWM, self)._stop_dma()
|
||||||
|
|
||||||
|
def remove_all(self):
|
||||||
|
""" Remove all pins from PWM and stop it.
|
||||||
|
"""
|
||||||
|
pins_list = self._clear_pins.keys()
|
||||||
|
for pin in pins_list:
|
||||||
|
self.remove_pin(pin)
|
||||||
|
assert len(self._clear_pins) == 0
|
||||||
|
|
||||||
# for testing purpose
|
# for testing purpose
|
||||||
def main():
|
def main():
|
||||||
pin = 21
|
pin = 21
|
||||||
@@ -272,8 +350,8 @@ def main():
|
|||||||
print("now " + hex(a))
|
print("now " + hex(a))
|
||||||
del cma
|
del cma
|
||||||
dg = DMAGPIO()
|
dg = DMAGPIO()
|
||||||
dg.add_pulse(1 << pin, 4000)
|
dg.add_pulse(1 << pin, 100000)
|
||||||
dg.add_delay(12000)
|
dg.add_delay(600000)
|
||||||
dg.run(True)
|
dg.run(True)
|
||||||
print("dmagpio is started")
|
print("dmagpio is started")
|
||||||
try:
|
try:
|
||||||
@@ -284,6 +362,16 @@ def main():
|
|||||||
dg.stop()
|
dg.stop()
|
||||||
g.clear(pin)
|
g.clear(pin)
|
||||||
print("dma stopped")
|
print("dma stopped")
|
||||||
|
pwm = DMAPWM()
|
||||||
|
pwm.add_pin(pin, 20)
|
||||||
|
print("pwm is started")
|
||||||
|
try:
|
||||||
|
print("press enter to stop...")
|
||||||
|
sys.stdin.readline()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
pass
|
||||||
|
pwm.remove_pin(pin)
|
||||||
|
print("pwm stopped")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|||||||
@@ -175,6 +175,8 @@ class CMAPhysicalMemory(PhysicalMemory):
|
|||||||
atexit.register(self.free)
|
atexit.register(self.free)
|
||||||
|
|
||||||
def free(self):
|
def free(self):
|
||||||
|
"""Release and free allocated memory
|
||||||
|
"""
|
||||||
self._send_data(0x3000e, [self._handle]) # unlock memory
|
self._send_data(0x3000e, [self._handle]) # unlock memory
|
||||||
self._send_data(0x3000f, [self._handle]) # free memory
|
self._send_data(0x3000f, [self._handle]) # free memory
|
||||||
self._close_dev(self._vcio_fd)
|
self._close_dev(self._vcio_fd)
|
||||||
@@ -196,3 +198,50 @@ class CMAPhysicalMemory(PhysicalMemory):
|
|||||||
|
|
||||||
def get_phys_address(self):
|
def get_phys_address(self):
|
||||||
return self._busmem & ~0xc0000000
|
return self._busmem & ~0xc0000000
|
||||||
|
|
||||||
|
|
||||||
|
class DMAProto(object):
|
||||||
|
def __init__(self, memory_size):
|
||||||
|
""" This class provides basic access to DMA and creates buffer for
|
||||||
|
control blocks.
|
||||||
|
"""
|
||||||
|
# allocate buffer for control blocks
|
||||||
|
self._physmem = CMAPhysicalMemory(memory_size)
|
||||||
|
# prepare dma registers memory map
|
||||||
|
self._dma = PhysicalMemory(PERI_BASE + DMA_BASE)
|
||||||
|
|
||||||
|
def _run_dma(self):
|
||||||
|
""" Run DMA module from created buffer.
|
||||||
|
"""
|
||||||
|
address = 0x100 * self._DMA_CHANNEL
|
||||||
|
cs = self._dma.read_int(address)
|
||||||
|
cs |= DMA_CS_END
|
||||||
|
self._dma.write_int(address, cs)
|
||||||
|
self._dma.write_int(address + 4, self._physmem.get_bus_address())
|
||||||
|
cs = DMA_CS_PRIORITY(7) | DMA_CS_PANIC_PRIORITY(7) | DMA_CS_DISDEBUG
|
||||||
|
self._dma.write_int(address, cs)
|
||||||
|
cs |= DMA_CS_ACTIVE
|
||||||
|
self._dma.write_int(address, cs)
|
||||||
|
|
||||||
|
def _stop_dma(self):
|
||||||
|
""" Stop DMA
|
||||||
|
"""
|
||||||
|
address = 0x100 * self._DMA_CHANNEL
|
||||||
|
cs = self._dma.read_int(address)
|
||||||
|
cs |= DMA_CS_ABORT
|
||||||
|
self._dma.write_int(address, cs)
|
||||||
|
cs &= ~DMA_CS_ACTIVE
|
||||||
|
self._dma.write_int(address, cs)
|
||||||
|
cs |= DMA_CS_RESET
|
||||||
|
self._dma.write_int(address, cs)
|
||||||
|
|
||||||
|
def is_active(self):
|
||||||
|
""" Check if DMA is working. Method can check if single sequence
|
||||||
|
still active or cycle sequence is working.
|
||||||
|
:return: boolean value
|
||||||
|
"""
|
||||||
|
address = 0x100 * self._DMA_CHANNEL
|
||||||
|
cs = self._dma.read_int(address)
|
||||||
|
if cs & DMA_CS_ACTIVE == DMA_CS_ACTIVE:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|||||||
@@ -89,3 +89,9 @@ def join():
|
|||||||
""" Wait till motors work.
|
""" Wait till motors work.
|
||||||
"""
|
"""
|
||||||
logging.info("hal join()")
|
logging.info("hal join()")
|
||||||
|
|
||||||
|
|
||||||
|
def deinit():
|
||||||
|
""" De-initialise.
|
||||||
|
"""
|
||||||
|
logging.info("hal deinit()")
|
||||||
|
|||||||
Reference in New Issue
Block a user