Forums » Software Development »
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.)