--
For more options, visit http://beagleboard.org/discuss
---
You received this message because you are subscribed to the Google Groups "BeagleBoard" group.
To unsubscribe from this group and stop receiving emails from it, send an email to beagleboard...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
#ifdef __arm__inline int32_t get_position_fast() { return *((int32_t *) virt_addr); } ///< not really clean but performing
#include <stdio.h>#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <fcntl.h>#include <sys/mman.h>
#define MAP_SIZE 4096UL#define MAP_MASK (MAP_SIZE - 1)#define EQEP0_BASE 0x48300180#define EQEP1_BASE 0x48302180#define EQEP2_BASE 0x48304180
int main(){ int fd; volatile unsigned long *virt_addr; volatile unsigned long *map_base; unsigned long read_result; int i; for(i=0;i<10000;i++){ unsigned long target=EQEP2_BASE; //O_SYNC makes the memory uncacheable if ((fd = open("/dev/mem", O_RDWR | O_SYNC))==-1) { printf("Could not open memory\n"); return 0; } //printf("opened /dev/mem \n"); //EQEP0_BASE&~MAP_MASK truncates the last 12 bits of the target address map_base=(ulong*)mmap(0, 4096, PROT_READ|PROT_WRITE,MAP_SHARED,fd, target&~MAP_MASK); if(map_base == (void *) -1) { printf("Unable to mmap eqep\n"); exit(-1); } //add the last 12 bits (0x180 for eqep) back onto to the address //also add 0x5C to offset to hardware revision code virt_addr = map_base + (target & MAP_MASK)+0x5C; read_result = *((unsigned long *) virt_addr); printf("\rValue at addr: 0x%lX (%p): 0x%lX ", map_base, virt_addr, read_result); close(fd); usleep(10000); } close(fd); return 0;}Thank you Guiseppe. I had tried an failed in the past to use mmap, but I see your solution to the error I had before is to mmap starting at the base address of the PWM peripheral instead of just at eQEP with (target&~MAP_MASK). Since ~MAP_MASK is 0xFFFFFFFFF000, the mmap starts at address 0x48300000 instead of 0x48300180 (for eqep0). Then you seem to be getting back to the base eQEP position register by adding target&MAP_MASK (0x180) back onto the virt_addr. Why the mmap function call fails without using the MAP_MASK is not entirely clear to me, but I won't worry about it.While my mmap errors are gone, I'm still only ever reading 0x83 when accessing the position value pointed to by virt-addr. If I try to access other parts of the eqep module I only get 0. For example the eqep hardware revision code which is at offset 0x5C according to the AM335xx reference manual returns 0 but should contain a value.
--
Cheers, John! Your suggestion of 0xFA300180 matches the MMU translations and places it in the linux-arm map range: vmalloc : 0xf0000000 - 0xff000000. This address does return values at both the base and the hardware revision offset, but not correct ones :-/A little more stumbling on the internet turned up the below example of mmapping the GPIO peripheral at GPIO1_START_ADDR 0x4804C000 which matches exactly to the address in page 159 of the AM335x Technical Reference Manual.
#include <stdio.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#define QPOSCNT 0x0000
#define EQEP0_BASE 0x48300180
#define QREVID 0x005C
int main(){
int fd;
volatile unsigned long *map_base;
unsigned long target=EQEP0_BASE;
long eqep0_pos, revid;
struct timeval tv1, tv2;
unsigned long map_size = getpagesize();
unsigned long map_mask = map_size-1;
//O_SYNC makes the memory uncacheable
if ((fd = open("/dev/mem", O_RDWR | O_SYNC))==-1) {
printf("Could not open /dev/mem\n");
return 0;
}
printf("opened /dev/mem\n");
//&~map_mask truncates the address to the base of the 4K Page
map_base=(uint8_t*)mmap(0, map_size, PROT_READ|PROT_WRITE,MAP_SHARED,fd, target&~map_mask);
if(map_base == (void *) -1) {
printf("Unable to mmap eqep\n");
exit(-1);
}
//&map_mask adds the position within the page to the address, this is 0x180 for eEQP0
unsigned long* eqep0_addr = (uint8_t *)map_base + (target&map_mask);
//time a read-loop to assess speed
int num_reads = 1000000;
int i;
gettimeofday(&tv1,NULL);
for(i=0;i<num_reads;i++){
eqep0_pos = *((uint8_t *)eqep0_addr + QPOSCNT);
}
gettimeofday(&tv2,NULL);
revid = *(uint32_t *)((uint8_t *)eqep0_addr+QREVID);
//find difference between start and end time
unsigned long dt_micros = (1000000 * tv2.tv_sec + tv2.tv_usec)-(1000000 * tv1.tv_sec + tv1.tv_usec);
float time_per_read = (float)dt_micros/num_reads;
printf("last position %ld\n", eqep0_pos);
printf("micros per read %f\n", time_per_read);
printf("pagesize %d\n", getpagesize());
printf("map_base 0x%lX\n",map_base);
printf("(uint8_t *)map_base 0x%lX\n", (uint8_t *)map_base);
printf("target&map_mask 0x%lX\n",target&map_mask);
printf("revid 0x%lX (should read 44D31103)\n",revid);
close(fd);
return 0;
}opened /dev/mem
last position 71
micros per read 0.389692
pagesize 4096
map_base 0xB6FF1000
(uint8_t *)map_base 0xB6FF1000
target&map_mask 0x180
revid 0x44D31103 (should read 44D31103)// Write the decoder control settings*(unsigned short*)(pwm_map_base[0]+EQEP_OFFSET+QDECCTL) = 0;// set maximum position to two's compliment of -1, aka UINT_MAX*(unsigned long*)(pwm_map_base[0]+EQEP_OFFSET+QPOSMAX)=-1;// Enable interrupt*(uint16_t*)(pwm_map_base[0]+EQEP_OFFSET+QEINT) = UTOF;// set unit period register*(unsigned long*)(pwm_map_base[0]+EQEP_OFFSET+QUPRD)=0x5F5E100;// enable counter in control register*(unsigned short*)(pwm_map_base[0]+EQEP_OFFSET+QEPCTL) = PHEN|IEL0|SWI|UTE|QCLM;SYSCONFIG 0xC
CLKCONFIG 0x111
QEPCTL0 0x9E
QDECCTL0 0x0
QEINT0 0x800
QUPRD0 0x5F5E100
QPOSMAX0 0xFFFFFFFF
QEPSTS0 0xA0
eqep0: -174 eqep1: 544 e^Cp2: 0 // Enable the clock to the eQEP unit
status = pwmss_submodule_state_change(pdev->dev.parent, PWMSS_EQEPCLK_EN);
*(unsigned long*)(pwm_map_base[0]+PWMSS_CLKCONFIG) = PWMSS_EQEPCLK_EN;
CLKCONFIG 0x111 = 000100010001
fragment@0 { target = <&am33xx_pinmux>; __overlay__ { pinctrl_eqep0: pinctrl_eqep0_pins { pinctrl-single,pins = < 0x1A8 0x21 /* P9_41 = GPIO3_20 = EQEP0_index, MODE1 */ 0x1AC 0x21 /* P9_25 = GPIO3_21 = EQEP0_strobe, MODE1 */ 0x1A0 0x31 /* P9_42 = GPIO3_18 = EQEP0A_in, MODE1 */ 0x1A4 0x31 /* P9_27 = GPIO3_19 = EQEP0B_in, MODE1 */ >; }; }; }; fragment@1 { target = <&epwmss0>; __overlay__ { status = "okay"; }; };
fragment@2 { target = <&eqep0>; __overlay__ { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_eqep0>; count_mode = <0>; /* 0 - Quadrature mode, normal 90 phase offset cha & chb. 1 - Direction mode. cha input = clock, chb input = direction */ swap_inputs = <0>; /* Are channel A and channel B swapped? (0 - no, 1 - yes) */ invert_qa = <1>; /* Should we invert the channel A input? */ invert_qb = <1>; /* Should we invert the channel B input? I invert these because my encoder outputs drive transistors that pull down the pins */ invert_qi = <0>; /* Should we invert the index input? */ invert_qs = <0>; /* Should we invert the strobe input? */ status = "okay"; }; };
[ 523.086537] bone-capemgr bone_capemgr.9: slot #10: dtbo 'bone_eqep0-00A0.dtbo' loaded; converting to live tree[ 523.090030] of_resolve: Could not find symbol 'eqep0'[ 523.095581] bone-capemgr bone_capemgr.9: slot #10: Failed to resolve tree
fragment@2 {
target = <&ocp>;
__overlay__ {
test_helper: helper {
compatible = "bone-pinmux-helper";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart5>;
status = "okay";
};
};
};
I don't believe that actually will change the I/O configuration. For the pin ctrl entry to be adopted, it needs to be used by some driver. Turns out there is a "pinmux helper" device. Check out this blog post: http://hipstercircuits.com/enable-serialuarttty-on-beaglebone-black/. More specifically, this section:fragment@2 {
target = <&ocp>;
__overlay__ {
test_helper: helper {
compatible = "bone-pinmux-helper";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart5>;
status = "okay";
};
};
};
- Nathaniel
diff --git a/cape-universal-00A0.dts b/cape-universal-00A0.dts
index ad5b388..bc6c005 100755
--- a/cape-universal-00A0.dts
+++ b/cape-universal-00A0.dts
@@ -602,7 +602,7 @@
P9_27_gpio_pd_pin: pinmux_P9_27_gpio_pd_pin {
pinctrl-single,pins = <0x1a4 0x27>; }; /* Mode 7, Pull-Down, RxActive */
P9_27_qep_pin: pinmux_P9_27_qep_pin {
- pinctrl-single,pins = <0x1a4 0x21>; }; /* Mode 1, Pull-Down, RxActive */
+ pinctrl-single,pins = <0x1a4 0x31>; }; /* Mode 1, Pull-Up, RxActive */
P9_27_pruout_pin: pinmux_P9_27_pruout_pin {
pinctrl-single,pins = <0x1a4 0x25>; }; /* Mode 5, Pull-Down, RxActive */
P9_27_pruin_pin: pinmux_P9_27_pruin_pin {
@@ -752,7 +752,7 @@
P9_92_gpio_pd_pin: pinmux_P9_92_gpio_pd_pin {
pinctrl-single,pins = <0x1a0 0x27>; }; /* Mode 7, Pull-Down, RxActive */
P9_92_qep_pin: pinmux_P9_92_qep_pin {
- pinctrl-single,pins = <0x1a0 0x21>; }; /* Mode 1, Pull-Down, RxActive */
+ pinctrl-single,pins = <0x1a0 0x31>; }; /* Mode 1, Pull-Up, RxActive */
P9_92_pruout_pin: pinmux_P9_92_pruout_pin {
pinctrl-single,pins = <0x1a0 0x25>; }; /* Mode 5, Pull-Down, RxActive */
P9_92_pruin_pin: pinmux_P9_92_pruin_pin {
@@ -1727,4 +1727,24 @@
};
};
+
+ /************************/
+ /* eQEP */
+ /************************/
+
+ fragment@41 {
+ target = <&eqep0>;
+ __overlay__ {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <>;
+
+ count_mode = <0>; /* 0 - Quadrature mode, normal 90 phase offset cha & chb. 1 - Direction mode. cha input = clock, chb input = direction */
+ swap_inputs = <0>; /* Are channel A and channel B swapped? (0 - no, 1 - yes) */
+ invert_qa = <1>; /* Should we invert the channel A input? */
+ invert_qb = <1>; /* Should we invert the channel B input? I invert these because my encoder outputs drive transistors that pull down the pins */
+ invert_qi = <0>; /* Should we invert the index input? */
+ invert_qs = <0>; /* Should we invert the strobe input? */
+ };
+ };
}; 0x038 0x24 /* P8_16 = GPIO2_12 = EQEP2_index, MODE4 */ 0x03C 0x24 /* P8_15 = GPIO2_13 = EQEP2_strobe, MODE4 */
0x030 0x34 /* P8_12 = GPIO2_10 = EQEP2A_in, MODE4 */
0x034 0x34 /* P8_11 = GPIO2_11 = EQEP2B_in, MODE4 */