From 3b73d7dcc4d8f7f99a36f6d81046342704604aef Mon Sep 17 00:00:00 2001 From: Nikolay Khabarov <2xl@mail.ru> Date: Sat, 20 May 2017 15:05:00 +0300 Subject: [PATCH] fix PWM usage --- README.md | 9 +++---- cnc/hal_raspberry/rpgpio.py | 18 +++++++------- cnc/hal_raspberry/rpgpio_private.py | 37 +++++++++++++++++------------ 3 files changed, 35 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index c9eb96b..e222b26 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/cnc/hal_raspberry/rpgpio.py b/cnc/hal_raspberry/rpgpio.py index b6956f1..6490746 100755 --- a/cnc/hal_raspberry/rpgpio.py +++ b/cnc/hal_raspberry/rpgpio.py @@ -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") diff --git a/cnc/hal_raspberry/rpgpio_private.py b/cnc/hal_raspberry/rpgpio_private.py index 3f194dc..4089c43 100644 --- a/cnc/hal_raspberry/rpgpio_private.py +++ b/cnc/hal_raspberry/rpgpio_private.py @@ -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