Project

General

Profile

Pinmux changes back on its own

Added by Andrew Bean over 8 years ago

I'm trying to set up PINMUX5 at address 0x01C14134 to have EPWM1A on the output. It seems to take on the desired value momentarily, but the value subsequently changes back after only a brief moment. The following is the code that I'm using:

#include <stdio.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>

int main (void)
{
    /* Get access to physical memory */
    int mem_fd = open("/dev/mem", O_RDWR|O_SYNC);
    if (mem_fd < 0) {
        printf("Failed to open /dev/mem (%s)\n", strerror(errno));
        return -1;
    }
    printf("Setup EPWM1A Pinmux\r\n");
    unsigned long Address = 0x1c14134;
    void * AddrMap;
    void * regMap;
    unsigned long PageSize = 0x1000;
    unsigned long AddrPage;
    AddrPage = Address & (~(PageSize-1));
    AddrMap = mmap(0, PageSize, PROT_WRITE | PROT_READ, MAP_SHARED, mem_fd, AddrPage);
    regMap = AddrMap + (Address & (PageSize-1));
    printf("Register = 0x%X before change\n",*(unsigned int *)regMap);
    // read, modify, write
    unsigned int temp = *(unsigned int *)regMap;
    temp = temp & 0xFFFFFFF0;
    temp = temp | 0x00000002;
    *(unsigned int *)regMap = temp;
    printf("Register = 0x%X after change\n",*(unsigned int *)regMap);
    usleep(1);
    printf("Register = 0x%X after usleep()\n",*(unsigned int *)regMap);
    munmap(AddrMap,PageSize);
    close(mem_fd);
    return(0);
}

The program output I get is the following:

Setup EPWM1A Pinmux
Register = 0x118118 before change
Register = 0x118112 after change
Register = 0x118118 after usleep()

Does anyone have any insight into why this is happening and how to make the pinmux keep the desired setting?


Replies (10)

RE: Pinmux changes back on its own - Added by Jonathan Cormier over 8 years ago

Strange, the only time the pinmux should get modified is during u-boot initialization and during kernel boot. Otherwise there isn't anything in linux that should be modifying the pinmux. Unless you need to dynamically change the pinmux I'd recommend setting it in the kernel to what you need it to be.

RE: Pinmux changes back on its own - Added by Andrew Bean over 8 years ago

I've played around with it a bit more, and it seems the issues does not have to do specifically with PINMUX registers. It seems that all writes through memory mapped /dev/mem are failing to actually take effect, i.e., the register is not reverting but rather is just not being changed. This also explains why my attempts at setting up the PWM had failed. Reads are successful for the most part, except immediately after attempting to write through the memory mapped /dev/mem. Also, it turns out that the usleep(1) didn't matter. Just the printf() is enough for the value to 'revert'. I was able to work around this by using the PRU to make the desired writes.

Could it be that I accidentally configured the kernel strangely when I verified that the PRUs are enabled? Can you think of any other reason why writes to /dev/mem would not work, while reads do work?

RE: Pinmux changes back on its own - Added by Jonathan Cormier over 8 years ago

Do you have the same problem using the devmem utilty? It also uses the /dev/mem interface. If it works perhaps you can use strace to see what its doing differently.

strace devmem 0x01C14134 0x118112

RE: Pinmux changes back on its own - Added by Andrew Bean over 8 years ago

It looks like devmem is missing from the version of busybox (v1.19.4) included with the 2014-01-13 root file system image, which I'm currently using. Is it straightforward to update busybox? I looked through the source for the most recent busybox, and the included devmem seems to ultimately do the same thing as the code above ( open(/dev/mem) then mmap() with all the same options).

RE: Pinmux changes back on its own - Added by Jonathan Cormier over 8 years ago

You can download the latest busybox and cross compile it. Should be something like below assuming you've set the toolchain in the path and the --host matches your toolchain. The busybox executable can be copied to the home directory and used from there like ./busybox devmem or you could try to replace the existing busybox. I usually use the default busybox config when building myself to get the majority of the useful tools.

./configure --host=arm-angstrom-linux-gnueabi
make

RE: Pinmux changes back on its own - Added by Jonathan Cormier over 8 years ago

One difference with the busybox code is they seem to be taking pains to make sure their mmap is page aligned.

https://git.busybox.net/busybox/tree/miscutils/devmem.c#n80

target & ~(off_t)(page_size - 1)

RE: Pinmux changes back on its own - Added by Andrew Bean over 8 years ago

I was able to compile busybox (after making an empty syncfs() function in sync.c as a quick workaround), and here's what I get:

root@mityomapl138:~# ./busybox devmem 0x1c14134
0x00118112
root@mityomapl138:~# ./busybox devmem 0x1c14134 32 0x118118
root@mityomapl138:~# ./busybox devmem 0x1c14134
0x00118112

In my code included above, I actually do the same page alignment calculation as devmem.

Could it be the way that I set up my module? I got the linux source as descibed here and used the Jan 2014 board support package to make a root file system and update the board, plus the new kernel with PRU enabled and kernel modules. I'm using the L138 with the development kit.

Does the write to memory with devmem work correctly for you (or someone else with similar setup)?

RE: Pinmux changes back on its own - Added by Jonathan Cormier over 8 years ago

I can confirm that doesn't appear to work.

root@mityomapl138:~# devmem 0x1c14134
0x11110118
root@mityomapl138:~# devmem 0x1c14134 32 0x118118
root@mityomapl138:~# devmem 0x1c14134
0x11110118

RE: Pinmux changes back on its own - Added by Jonathan Cormier over 8 years ago

Found this post for the 335x which mentions that the pinmux registers are protected. Its likely this is also true for the L138.
https://groups.google.com/forum/#!topic/beagleboard/D8hU7LddIu0

RE: Pinmux changes back on its own - Added by Andrew Bean over 8 years ago

Hi Jonathan, thanks for looking into this. The L138 technical reference manual does show many of the SYSCFG registers being modifiable only in a privileged mode, including PINMUX registers. I tried reading and writing to PRU internal general purpose registers (0x01C37400 - 0x01C3747C, not protected) using busybox devmem, and this does work.

The linked page mentions "Neither mmaped C code nor the PRUSS can write these registers." Nevertheless, I have successfully been able to use the PRUSS to configure the PINMUX registers on the fly for both EPWM1A and PRU input/output. (The L138 technical reference manual additionally mentions protection of the SYSCFG registers through KICK registers, but this is only in earlier versions of the silicon than the chip included on the module.)

    (1-10/10)
    Go to top
    Add picture from clipboard (Maximum size: 1 GB)