fix PWM usage

This commit is contained in:
Nikolay Khabarov
2017-05-20 15:05:00 +03:00
parent 78804a438a
commit 3b73d7dcc4
3 changed files with 35 additions and 29 deletions

View File

@@ -33,13 +33,10 @@ So having Raspberry Pi connected this way, there is no need to configure
pin map for project.
# Hardware
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.
Currently, this project supports Raspberry Pi 1-3. Tested with RPI2 and RPI3.
But there 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._
3.5 mm jack(PWM module), so do not use it. HDMI audio works._
# Usage
Just clone this repo and run `./pycnc` from repo root. It will start in

View File

@@ -93,7 +93,7 @@ class DMAGPIO(DMAProto):
otherwise memory will be unlocked and it could be overwritten by
operating system.
"""
super(DMAGPIO, self).__init__(31 * 1024 * 1024, 5)
super(DMAGPIO, self).__init__(30 * 1024 * 1024, 4)
self.__current_address = 0
# get helpers registers, this class uses PWM module to create precise
@@ -133,7 +133,7 @@ class DMAGPIO(DMAProto):
next1 = next2 - self._DMA_CONTROL_BLOCK_SIZE
source1 = next1 - 8 # last 8 bytes are padding, use it to store data
length2 = 16 * length_us
length2 = length_us << 4 # * 16
source3 = next3 - 8
data = (
@@ -158,7 +158,7 @@ class DMAGPIO(DMAProto):
raise MemoryError("Out of allocated memory.")
next1 = self._physmem.get_bus_address() + next_cb
source = next1 - 8 # last 8 bytes are padding, use it to store data
length = 16 * delay_us
length = delay_us << 4 # * 16
data = (
self._delay_info, source, self._delay_destination, length,
self._delay_stride, next1, 0, 0
@@ -180,11 +180,13 @@ class DMAGPIO(DMAProto):
"""
# configure PWM hardware module which will clocks DMA
self._pwm.write_int(PWM_CTL, 0)
self._clock.write_int(CM_CNTL, CM_PASSWORD | CM_SRC_PLLD) # disable
while (self._clock.read_int(CM_CNTL) & (1 << 7)) != 0:
self._clock.write_int(CM_PWM_CNTL, CM_PASSWORD | CM_SRC_PLLD) # disable
while (self._clock.read_int(CM_PWM_CNTL) & CM_CNTL_BUSY) != 0:
time.sleep(0.00001) # 10 us, wait until BUSY bit is clear
self._clock.write_int(CM_DIV, CM_PASSWORD | CM_DIV_VALUE(50)) # 10MHz
self._clock.write_int(CM_CNTL, CM_PASSWORD | CM_SRC_PLLD | CM_ENABLE)
self._clock.write_int(CM_PWM_DIV, CM_PASSWORD | CM_DIV_VALUE(5)) # 100MHz
self._clock.write_int(CM_PWM_CNTL, CM_PASSWORD | CM_SRC_PLLD |
CM_CNTL_ENABLE)
self._pwm.write_int(PWM_RNG1, 100)
self._pwm.write_int(PWM_DMAC, PWM_DMAC_ENAB
| PWM_DMAC_PANIC(15) | PWM_DMAC_DREQ(15))
@@ -350,7 +352,7 @@ def main():
print("now " + hex(a))
del cma
dg = DMAGPIO()
dg.add_pulse(1 << pin, 100000)
dg.add_pulse(1 << pin, 200000)
dg.add_delay(600000)
dg.run(True)
print("dmagpio is started")

View File

@@ -39,6 +39,8 @@ PHYSICAL_GPIO_BUS = 0x7E000000 + GPIO_REGISTER_BASE
# registers and values for DMA
DMA_BASE = 0x007000
DMA_CS = 0x00
DMA_CONBLK_AD = 0x04
DMA_TI_NO_WIDE_BURSTS = 1 << 26
DMA_TI_SRC_INC = 1 << 8
DMA_TI_DEST_INC = 1 << 4
@@ -79,16 +81,20 @@ def DMA_CS_PANIC_PRIORITY(x):
# hardware PWM controller registers
PWM_BASE = 0x0020C000
PHYSICAL_PWM_BUS = 0x7E000000 + PWM_BASE
PWM_CTL= 0x00
PWM_DMAC = 0x08
PWM_RNG1 = 0x10
PWM_RNG2 = 0x20
PWM_FIFO = 0x18
PWM_CTL_MODE1 = 1 << 1
PWM_CTL_MODE2 = 1 << 9
PWM_CTL_PWEN1 = 1 << 0
PWM_CTL_PWEN2 = 1 << 8
PWM_CTL_CLRF = 1 << 6
PWM_CTL_USEF1 = 1 << 5
PWM_CTL_USEF2 = 1 << 13
PWM_DMAC_ENAB = 1 << 31
PHYSICAL_PWM_BUS = 0x7E000000 + PWM_BASE
def PWM_DMAC_PANIC(x):
return x << 8
@@ -98,10 +104,13 @@ def PWM_DMAC_DREQ(x):
# clock manager module
CM_BASE = 0x00101000
CM_CNTL = 40
CM_DIV = 41
CM_PCM_CNTL = 0x98
CM_PCM_DIV = 0x9C
CM_PWM_CNTL = 0xA0
CM_PWM_DIV = 0xA4
CM_PASSWORD = 0x5A << 24
CM_ENABLE = 1 << 4
CM_CNTL_ENABLE = 1 << 4
CM_CNTL_BUSY = 1 << 7
CM_SRC_OSC = 1 # 19.2 MHz
CM_SRC_PLLC = 5 # 1000 MHz
CM_SRC_PLLD = 6 # 500 MHz
@@ -218,26 +227,24 @@ class DMAProto(object):
""" 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())
self._dma.write_int(address + DMA_CS, DMA_CS_END)
self._dma.write_int(address + DMA_CONBLK_AD, self._physmem.get_bus_address())
cs = DMA_CS_PRIORITY(7) | DMA_CS_PANIC_PRIORITY(7) | DMA_CS_DISDEBUG
self._dma.write_int(address, cs)
self._dma.write_int(address + DMA_CS, cs)
cs |= DMA_CS_ACTIVE
self._dma.write_int(address, cs)
self._dma.write_int(address + DMA_CS, cs)
def _stop_dma(self):
""" Stop DMA
"""
address = 0x100 * self._DMA_CHANNEL
cs = self._dma.read_int(address)
cs = self._dma.read_int(address + DMA_CS)
cs |= DMA_CS_ABORT
self._dma.write_int(address, cs)
self._dma.write_int(address + DMA_CS, cs)
cs &= ~DMA_CS_ACTIVE
self._dma.write_int(address, cs)
self._dma.write_int(address + DMA_CS, cs)
cs |= DMA_CS_RESET
self._dma.write_int(address, cs)
self._dma.write_int(address + DMA_CS, cs)
def is_active(self):
""" Check if DMA is working. Method can check if single sequence
@@ -245,7 +252,7 @@ class DMAProto(object):
:return: boolean value
"""
address = 0x100 * self._DMA_CHANNEL
cs = self._dma.read_int(address)
cs = self._dma.read_int(address + DMA_CS)
if cs & DMA_CS_ACTIVE == DMA_CS_ACTIVE:
return True
return False