Programming GPIO pins via mapped memory

Tagged: 

This topic contains 4 replies, has 2 voices, and was last updated by  garysims 2 years, 7 months ago.

Viewing 5 posts - 1 through 5 (of 5 total)
  • Author
    Posts
  • #31982

    garysims
    Member

    Hi,

    I am working on porting wiringX (a modular GPIO library) to the CI20. I have a version working with sysfs, however I would like to try and get a version working that uses mapped memory, mainly because all the other supported boards including the Raspberry Pi and the HummingBoard have such an implementation.

    I have written the code but it isn’t working and I wonder if I could just verify what I am doing with someone:

    To get access to the registers first I open a memory map for 0x1001000 like this:

    gpio = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_BASE);

    Where BLOCK_SIZE is 4096 and GPIO_BASE is 0x10010000. fd comes from a previous call to open /dev/mem.

    Then to set PD28/GPIO1/physical pin 7 to OUTPUT I use this code:

    // p is the port number (0,1,2,3,4,5)
    // o is the pin offset (0-31) inside the port
    // n is the absolute number of a pin (0-127), regardless of the port
    unsigned int p, o, n;
    n = 124; // Port D, offset 28
    p = (n) / 32;
    o = (n) % 32;

    *(gpio+(0x18 + (p)*0x100)) = (1 < < (o)); // INTC
    *(gpio+(0x24 + (p)*0x100)) = (1 < < (o)); // MASKS
    *(gpio+(0x38 + (p)*0x100)) = (1 < < (o)); // PAT1C
    *(gpio+(0x48 + (p)*0x100)) = (1 < < (o)); // PAT0CThen to set the pin HIGH I use:*(gpio + (0x44 + (p)*0x100)) = (1 < < o); // PAT0SBut it doesn’t work.Can anyone spot any problems with this approach?Thanks,Gary

    #39495

    ZubairLK
    Member

    Hi,

    I’m guessing you are using sudo while running this?

    PF15 is SYS_POWER_IND which is linked with USB 5V and the LED.

    I’ve attached a code snippet that blinks the on board LED (you loose USB power btw)

    You could check the values in this vs what you generate..

    Hope this helps
    ZubairLK

    #include
    #include
    #include
    #include
    #include
    #include
    #include

    #define GPIO_BASE 0x10010000

    #if !defined(PAGE_SIZE)
    #define PAGE_SIZE 0x1000
    #define PAGE_MASK (PAGE_SIZE - 1)
    #endif

    #define EXIT_FAILURE 1
    #define MAP_FAILED (void *) -1

    #define PROT (PROT_READ|PROT_WRITE)
    #define FLAGS MAP_SHARED

    #define ERRORS
    { printf(errmsg, __LINE__, __FILE__, errno, strerror(errno));
    exit(EXIT_FAILURE);
    }

    static const char errmsg[]="Error at line %d, file %s (%d) [%s]n";
    static int mem_fd;
    static volatile unsigned char * map_base;

    void SetGPIOVal (unsigned int, unsigned int);

    /* Set the required GPIO output pins */
    void SetGPIOVal (unsigned int gpio_offset, unsigned int gpio_val)
    {
    unsigned int *gpio_reg;
    gpio_reg = (unsigned int *)(map_base + ((gpio_offset) & PAGE_MASK));
    *gpio_reg = gpio_val;
    gpio_reg = (unsigned int *)(map_base + ((gpio_offset)));
    *gpio_reg = gpio_val;
    }

    int unmap_fd;

    int main (void)
    {
    int i;
    off_t addr;
    const char mapfile[]="/dev/mem";

    /* Set up the virtual memory map to the GPIO base address */
    mem_fd = open(mapfile,O_SYNC|O_RDWR);
    if (mem_fd < 0) {
    printf("nCould not open memory");
    ERRORS;
    }

    /* set up the GPIO access */
    addr = GPIO_BASE & ~PAGE_MASK;
    if((map_base = (volatile unsigned char*)mmap(0,
    PAGE_SIZE,
    PROT,
    FLAGS,
    mem_fd,
    addr)) == MAP_FAILED )
    {
    (void)close(mem_fd);
    printf("Mem map failed: virt=%p, phys=%pn",map_base, addr);
    ERRORS;
    }

    printf("Mem map successful: virt=%p, phys=%pn",map_base, addr);

    /* Toggle the GPIO value */
    SetGPIOVal (0x544, 0x8000);
    usleep(2000);
    SetGPIOVal(0x548, 0x8000);
    usleep(2000);
    SetGPIOVal (0x544, 0x8000);

    /* Close the GPIO memory map */
    if ((unmap_fd = munmap(map_base, PAGE_SIZE)) == -1)
    {
    printf("Unmap failedn");
    ERRORS;
    }

    (void)close(mem_fd);

    return 0;

    }

    #39496

    garysims
    Member

    Hi,

    Thanks, that is very useful. It looks very similar to what I am doing… But I notice that in SetGPIOVal you do two writes of the gpio_val, one with the PAGE_MASK and one without… Why?

    gpio_reg = (unsigned int *)(map_base + ((gpio_offset) & PAGE_MASK));
    *gpio_reg = gpio_val;
    gpio_reg = (unsigned int *)(map_base + ((gpio_offset)));
    *gpio_reg = gpio_val;

    Thanks,

    Gary

    #39497

    garysims
    Member

    Hi,

    The good news is that I took your program and altered it a little to control the GPIO I am interetsed in:

    // Set direction as output
    SetGPIOVal (0x318, (1 << 28));
    SetGPIOVal (0x324, (1 << 28));
    SetGPIOVal (0x34, (1 << 28));
    SetGPIOVal (0x348, (1 << 28));

    SetGPIOVal (0x344, (1 << 28));
    sleep(1);
    SetGPIOVal (0x348, (1 << 28));
    sleep(1);
    SetGPIOVal (0x344, (1 << 28));
    sleep(1);
    SetGPIOVal (0x348, (1 << 28));

    And it works… so there is clearly a problem with my implementation, but at least now I know what I am trying will actually work!!!

    Many, many thanks!

    Gary
    PS. I removed the first write to gpio_reg with the PAGE_MASK and it still works so I don’t think that is needed.

    #39498

    garysims
    Member

    As a final follow up, the problem with my original code was two fold:

    First, the pointer used to accessing the physical memory needed to be unsigned char * and not gpio = uint32_t *.

    Second, I needed an explicit cast to unsigned int * when writing to the GPIO registers, i.e:

    * (unsigned int *)(gpio+(0x48 + (p)*0x100)) = (1 < < (o)); // PAT0C

    Thanks.

Viewing 5 posts - 1 through 5 (of 5 total)
The forum ‘Creator Platforms’ is closed to new topics and replies.