We have upgraded the community system as part of the upgrade a password reset is required for all users before login in.

[Omega2] Hardware PWM problem



  • Hi everyone.
    I have some problem with hardware PWM on Omega2. I'm trying to start PWM using registers.
    The problem is - no signal on GPIO18 pin. I'm trying to get 1Hz signal.
    Here is my code:

    #ifndef _FCNTL_H
    #include <fcntl.h>
    #endif

    #ifndef _STDIO_H
    #include <stdio.h>
    #endif

    #ifndef _ERRNO_H
    #include <errno.h>
    #endif

    #ifndef _STDINT_H
    #include <stdint.h>
    #endif

    #ifndef _STDLIB_H
    #include <stdlib.h>
    #endif

    #ifndef _SYS_MMAN_H
    #include <sys/mman.h>
    #endif

    #ifndef _UNISTD_H
    #include <unistd.h>
    #endif

    // Registers base
    #define REGISTER_BASE 0x10000000u

    // GPIO1_MODE register offset
    #define GPIO1_MODE 0x60u
    #define PWM_ENABLE 0x5000u
    #define PWM0_CON 0x5010u

    // GPIO18 output setting bits
    #define PWM0_MODE0 28
    #define PWM0_MODE1 29

    // PWM0 enable bit
    #define PWM0_EN 0

    // Clock select bit
    #define CLKSEL 3

    #define OLD_PWM_MODE 15

    // High level period register offset
    #define PWM0_HDURATION 0x5014u

    // Low level period register offset
    #define PWM0_LDURATION 0x5018u

    // PWM Enable status register offset
    #define PWM_EN_STATUS 0x520Cu

    // Logic levels
    #define LOW 0
    #define HIGH 1

    // Registers map pointer
    volatile uint32_t *uiBaseAddress;

    // Set or clear bit in register
    void vSetBitInRegister(uint16_t offset,uint8_t bit, uint8_t wartosc)
    {
    if (wartosc==0)
    {
    *(uiBaseAddress+(offset/4))&=~(1<<bit);
    }
    else
    {
    *(uiBaseAddress+(offset/4))|=(1<<bit);
    }
    }

    // Display register
    void vViewRegister(uint16_t offset, char *sRegisterName)
    {
    // Zrzut rejestru
    int i = 0;
    printf("\n%s register view:\n",sRegisterName);
    for (i=31; i>=0; i--)
    {
    printf("+---");
    }
    printf("+\n");
    for (i=31; i>=0; i--)
    {
    printf("|%02u ",i+1);
    }
    printf("|\n");
    for (i=31; i>=0; i--)
    {
    printf("+---");
    }
    printf("\n");
    for (i=31; i>=0; i--)
    {

    	if ((*(uiBaseAddress+(offset/4)))&(1<<i)) printf("| 1 "); else printf("| 0 ");
    
    }
    
    printf("|\n");
    for (i=31; i>=0; i--)
    {
    	printf("+---");
    }
    
    printf("+\n");
    

    }

    int main(int argc, char* argv[])
    {
    // Memory map descriptor
    int iMap;

    // Opening device /dev/mem for mapping and exit when it fails
    if ((iMap = open ("/dev/mem", O_RDWR | O_SYNC) ) < 0) 
    {
    	printf("OPEN Error");
    	return EXIT_FAILURE;
    }
    
    
    // Mapping MT7688 registers
    uiBaseAddress = (uint32_t *) mmap(0, 65536, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, iMap,
                                          REGISTER_BASE);
    
    // Close device descriptor
    close(iMap);
    
    // Exit when map fails
    if (uiBaseAddress == MAP_FAILED) 
    {
    	printf("MMAP Error");
    	return EXIT_FAILURE;
    }
    
    
    // Display GPIO1_MODE register before operation
    vViewRegister(GPIO1_MODE,"GPIO1_MODE");
    
    // Setting GPIO18 as PWM0 output
    vSetBitInRegister(GPIO1_MODE,PWM0_MODE0,LOW);
    vSetBitInRegister(GPIO1_MODE,PWM0_MODE1,LOW);
    
    // Display GPIO1_MODE register after opreation
    vViewRegister(0x60,"GPIO1_MODE");
    
    
    
    vViewRegister(PWM_ENABLE,"PWM_ENABLE");
    vSetBitInRegister(PWM_ENABLE,PWM0_EN,HIGH); // Enable PWM0
    vViewRegister(PWM_ENABLE,"PWM_ENABLE");
    
    vViewRegister(PWM0_CON,"PWM0_CON");
    vSetBitInRegister(PWM0_CON,CLKSEL,LOW);	// 100kHz clock
    vSetBitInRegister(PWM0_CON,OLD_PWM_MODE,LOW);	// Old PWM Mode
    vViewRegister(PWM0_CON,"PWM0_CON");
    
    vViewRegister(PWM0_HDURATION,"PWM0_HDURATION");
    *(uiBaseAddress+PWM0_HDURATION/4) = 0xC351;	// 0,5s high level duration
    vViewRegister(PWM0_HDURATION,"PWM0_HDURATION");
    
    vViewRegister(PWM0_LDURATION,"PWM0_LDURATION");
    *(uiBaseAddress+PWM0_LDURATION/4) = 0xC351;	// 0,5s high level duration
    vViewRegister(PWM0_LDURATION,"PWM0_LDURATION");
    
    // Display PWM Enable status register	
    vViewRegister(PWM_EN_STATUS,"PWM_EN_STATUS");
    
    return EXIT_SUCCESS;
    

    }



  • @Krzysztof-Skiba

    I had a similar problem with GPIO18/19 a while back, altough not with the regular Onion firmware but my own LEDE build.

    Anyway, there's a global mode to use this pins as digital GPIO/PWM etc. or as ethernet port. If this is set to ethernet mode (they call it AGPIO), then GPIO18 does not work as GPIO or PWM no matter what the gpio mux settings are.

    So you might want to have a look at that topic here.

    Maybe my experiments from a while ago with the PWM using the devmem command could be of interest for you. In the meantime, these experiments turned into a working kernel driver using the PWM to generate WS28xx LED timing.



  • Thanks for fast reply.
    The problem was "send data register" for pattern. I didn't wrote any value to this register. I have 1Hz signal on GPIO18 pin but I still don't know how to increase resolution of signal regulation. I have 1/64s (for 64 bits pattern) - it is 15,625ms. I need 10ms resolution for AC 50Hz group power regulation. I'll try to do it by regulating high and low signal duration.



  • You need to set the clock prescaler (CLKDIV Bits 0..2 in PWM0_CON 0x10005010, see datasheet) and the main clock selector (40MHz or 100kHz, Bit 0 in PWM0_CON) to get a suitable base clock speed for your application.

    If you only need a signal with defined high and low time, and not a complicated sequence, you could just put a 0x01 into SEND0/1, set the STOP_BITPOS (in PWM0_CON) to 2 and then regulate the signal with PWM_HDURATION / PWM_LDURATION (and maybe PWM_GDURATION).



  • I did this:
    PWM0_SEND_DATA0 <- 0xAAAAAAAA (1010101010101....)
    PWM0_SEND_DATA1 <- 0xAAAAAAAA (1010101010101....)

    Clock 100kHz/2 - 50kHz

    And for 1% duty (for example):
    PWM0_HDURATION <- 500
    PWM0_LDURATION <- 50000-PWM0_HDURATION

    It works. I have exactly 10ms step regulation.
    My rectification column power regulator is much closer šŸ™‚ Thanx!


Log in to reply
 

Looks like your connection to Community was lost, please wait while we try to reconnect.