Quantcast
Channel: Raspberry Pi Forums
Viewing all articles
Browse latest Browse all 4907

Interfacing (DSI, CSI, I2C, etc.) • PWM phase offsets not working on RP1

$
0
0
Hi all!

I'm working on a project on a Raspberry PI 5 where I need two synchronised PWM's operating with a phase shift. (Software PWM does not cut it for this application I'm afraid.)
My problem is that I cannot get the phase offset working.
In lack of other API's capable of performing this, I've resorted to using mmap to set the registers directly.

Reading the datasheet for RP1, I'm guessing that phase should be respected and pre-loaded in the counter when the PWM channel is enabled, but it's not perfectly clear. Is there anything specific I might have forgotten that need to be setup to get phase offset working?

This is my procedure for configuring the PWMs:

Code:

    # setup IO    write((4,0), IO_BANK0_REG(Gpio.GPIO14, IoBankRegister.CTRL), 0) # function a0 for GPIO 14    write((4,0), IO_BANK0_REG(Gpio.GPIO15, IoBankRegister.CTRL), 0) # function a0 for GPIO 15    write((7,7), PADS_BANK0_REG(Gpio.GPIO14), 0)                    # output enable GPIO 14    write((7,7), PADS_BANK0_REG(Gpio.GPIO15), 0)                    # output enable GPIO 15    write((5,4), PADS_BANK0_REG(Gpio.GPIO14), 3)                    # output drive 12 mA    write((5,4), PADS_BANK0_REG(Gpio.GPIO15), 3)    # setup PWM    write((31,0), PWM_CH_REG(PwmChannel.CH3, PwmChannelRegister.RANGE), 200000) # range    write((31,0), PWM_CH_REG(PwmChannel.CH4, PwmChannelRegister.RANGE), 200000)    write((31,0), PWM_CH_REG(PwmChannel.CH3, PwmChannelRegister.DUTY), 50000)   # 25% duty    write((31,0), PWM_CH_REG(PwmChannel.CH4, PwmChannelRegister.DUTY), 50000)    write((31,0), PWM_CH_REG(PwmChannel.CH3, PwmChannelRegister.PHASE), 0)      # phase has no effect?    write((31,0), PWM_CH_REG(PwmChannel.CH4, PwmChannelRegister.PHASE), 50000)    write((2,0), PWM_CH_REG(PwmChannel.CH3, PwmChannelRegister.CTRL), 1)        # trailing edge    write((2,0), PWM_CH_REG(PwmChannel.CH4, PwmChannelRegister.CTRL), 1)    write((3,0), PWM_GLOBAL_REG(PwmRegister.GLOBAL_CTRL), 0b1100)               # enable PWM channel 2 & 3    write((31,31), PWM_GLOBAL_REG(PwmRegister.GLOBAL_CTRL), 1)                  # apply config
And here's the complete runnable test application (that need sudo):

Code:

from enum import Enumimport mmapimport osimport sysclass Gpio(Enum):    GPIO12 = 12    GPIO13 = 13    GPIO14 = 14    GPIO15 = 15class PwmChannel(Enum):    CH1 = 0    CH2 = 1    CH3 = 2    CH4 = 3class PwmChannelRegister(Enum):    CTRL = 0    RANGE = 1    PHASE = 2    DUTY = 3class PwmRegister(Enum):    GLOBAL_CTRL = 0    FIFO_CTRL = 1    COMMON_RANGE = 2    COMMON_DUTY = 3    DUTY_FIFO = 4class IoBankRegister(Enum):    STATUS = 0    CTRL = 1FILENAME = "/sys/bus/pci/devices/0000:01:00.0/resource1"PWM0_OFFSET = 0x98000IO_BANK0_OFFSET = 0xd0000IO_BANK0_PADS_OFFSET = 0xf0000REGISTER_SIZE = 4  # in bytesRegister = intBits = tuple[int, int]def PWM_GLOBAL_REG(reg: PwmRegister) -> Register:    return PWM0_OFFSET + reg.value * REGISTER_SIZEdef PWM_CH_REG(channel: PwmChannel, reg: PwmChannelRegister) -> Register:    return PWM0_OFFSET + 0x14 + channel.value * 0x10 + reg.value * REGISTER_SIZEdef IO_BANK0_REG(gpio: Gpio, reg: IoBankRegister) -> Register:    return IO_BANK0_OFFSET + gpio.value * 0x8 + reg.value * REGISTER_SIZEdef PADS_BANK0_REG(gpio: Gpio) -> Register:    return IO_BANK0_PADS_OFFSET + gpio.value * REGISTER_SIZE + REGISTER_SIZEdef create_mask(bits: Bits) -> tuple[int, int]:    bh, bl = bits    mask = ((1 << (bh - bl + 1)) - 1) << bl    inv_mask = ~mask & 0xFFFFFFFF    return (mask, inv_mask)fd = os.open("/sys/bus/pci/devices/0000:01:00.0/resource1", flags=os.O_RDWR | os.O_SYNC)with mmap.mmap(fd, length=0x400000, access=mmap.PROT_WRITE) as mm:    os.close(fd)    def write(bits: Bits, reg: Register, value: int) -> None:        _, bl = bits        mask, inv_mask = create_mask(bits)        old_value = int.from_bytes(mm[reg:reg+4], sys.byteorder)        new_value: int = old_value & inv_mask | (value << bl) & mask        mm[reg:reg+4] = new_value.to_bytes(4, sys.byteorder)    # setup IO    write((4,0), IO_BANK0_REG(Gpio.GPIO14, IoBankRegister.CTRL), 0) # function a0 for GPIO 14    write((4,0), IO_BANK0_REG(Gpio.GPIO15, IoBankRegister.CTRL), 0) # function a0 for GPIO 15    write((7,7), PADS_BANK0_REG(Gpio.GPIO14), 0)                    # output enable GPIO 14    write((7,7), PADS_BANK0_REG(Gpio.GPIO15), 0)                    # output enable GPIO 15    write((5,4), PADS_BANK0_REG(Gpio.GPIO14), 3)                    # output drive 12 mA    write((5,4), PADS_BANK0_REG(Gpio.GPIO15), 3)    # setup PWM    write((31,0), PWM_CH_REG(PwmChannel.CH3, PwmChannelRegister.RANGE), 200000) # range    write((31,0), PWM_CH_REG(PwmChannel.CH4, PwmChannelRegister.RANGE), 200000)    write((31,0), PWM_CH_REG(PwmChannel.CH3, PwmChannelRegister.DUTY), 50000)   # 25% duty    write((31,0), PWM_CH_REG(PwmChannel.CH4, PwmChannelRegister.DUTY), 50000)    write((31,0), PWM_CH_REG(PwmChannel.CH3, PwmChannelRegister.PHASE), 0)      # phase has no effect?    write((31,0), PWM_CH_REG(PwmChannel.CH4, PwmChannelRegister.PHASE), 50000)    write((2,0), PWM_CH_REG(PwmChannel.CH3, PwmChannelRegister.CTRL), 1)        # trailing edge    write((2,0), PWM_CH_REG(PwmChannel.CH4, PwmChannelRegister.CTRL), 1)    write((3,0), PWM_GLOBAL_REG(PwmRegister.GLOBAL_CTRL), 0b1100)               # enable PWM channel 2 & 3    write((31,31), PWM_GLOBAL_REG(PwmRegister.GLOBAL_CTRL), 1)                  # apply config

Statistics: Posted by Micke — Wed Jul 31, 2024 12:00 pm



Viewing all articles
Browse latest Browse all 4907

Trending Articles